Skip to content

Commit ceafebd

Browse files
committed
scm viewlet inline actions
1 parent 7f8d9c9 commit ceafebd

9 files changed

Lines changed: 157 additions & 32 deletions

File tree

extensions/git/package.json

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,38 @@
3838
{
3939
"command": "git.stage",
4040
"title": "Stage",
41-
"category": "Git"
41+
"category": "Git",
42+
"icon": {
43+
"light": "resources/icons/light/stage.svg",
44+
"dark": "resources/icons/dark/stage.svg"
45+
}
4246
},
4347
{
4448
"command": "git.stage-all",
4549
"title": "Stage All",
46-
"category": "Git"
50+
"category": "Git",
51+
"icon": {
52+
"light": "resources/icons/light/stage.svg",
53+
"dark": "resources/icons/dark/stage.svg"
54+
}
4755
},
4856
{
4957
"command": "git.unstage",
5058
"title": "Unstage",
51-
"category": "Git"
59+
"category": "Git",
60+
"icon": {
61+
"light": "resources/icons/light/unstage.svg",
62+
"dark": "resources/icons/dark/unstage.svg"
63+
}
5264
},
5365
{
5466
"command": "git.unstage-all",
5567
"title": "Unstage All",
56-
"category": "Git"
68+
"category": "Git",
69+
"icon": {
70+
"light": "resources/icons/light/unstage.svg",
71+
"dark": "resources/icons/dark/unstage.svg"
72+
}
5773
}
5874
],
5975
"menus": {
@@ -63,24 +79,48 @@
6379
"group": "navigation"
6480
}
6581
],
82+
"scm/git/index/group": [
83+
{
84+
"command": "git.unstage-all",
85+
"group": "navigation"
86+
}
87+
],
6688
"scm/git/index/group/context": [
6789
{
6890
"command": "git.unstage-all",
6991
"group": "navigation"
7092
}
7193
],
94+
"scm/git/index/resource": [
95+
{
96+
"command": "git.unstage",
97+
"group": "navigation"
98+
}
99+
],
72100
"scm/git/index/resource/context": [
73101
{
74102
"command": "git.unstage",
75103
"group": "navigation"
76104
}
77105
],
106+
"scm/git/workingTree/group": [
107+
{
108+
"command": "git.stage-all",
109+
"group": "navigation"
110+
}
111+
],
78112
"scm/git/workingTree/group/context": [
79113
{
80114
"command": "git.stage-all",
81115
"group": "navigation"
82116
}
83117
],
118+
"scm/git/workingTree/resource": [
119+
{
120+
"command": "git.stage",
121+
"group": "navigation"
122+
}
123+
],
84124
"scm/git/workingTree/resource/context": [
85125
{
86126
"command": "git.stage",
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading

extensions/git/src/commands.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
'use strict';
77

8-
import { commands, Disposable } from 'vscode';
8+
import { commands, Disposable, SCMResourceGroup, SCMResource } from 'vscode';
99
import { Model } from './model';
1010
import { log } from './util';
1111

@@ -20,9 +20,29 @@ function openChange(...args: any[]): void {
2020
console.log('openChange', args);
2121
}
2222

23+
function stage(resource: SCMResource): void {
24+
log('stage', resource);
25+
}
26+
27+
function stageAll(resourceGroup: SCMResourceGroup): void {
28+
log('stage-all', resourceGroup);
29+
}
30+
31+
function unstage(resource: SCMResource): void {
32+
log('unstage', resource);
33+
}
34+
35+
function unstageAll(resourceGroup: SCMResourceGroup): void {
36+
log('unstage-all', resourceGroup);
37+
}
38+
2339
export function registerCommands(model: Model): Disposable {
2440
const disposables = [
2541
commands.registerCommand('git.refresh', refresh(model)),
42+
commands.registerCommand('git.stage', stage),
43+
commands.registerCommand('git.stage-all', stageAll),
44+
commands.registerCommand('git.unstage', unstage),
45+
commands.registerCommand('git.unstage-all', unstageAll),
2646
commands.registerCommand('git.open-change', openChange)
2747
];
2848

src/vs/workbench/parts/scm/browser/media/scmViewlet.css

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,41 @@
2929
font-size: 11px;
3030
font-weight: bold;
3131
text-transform: uppercase;
32+
overflow: hidden;
33+
text-overflow: ellipsis;
3234
}
3335

34-
.scm-viewlet .monaco-list-row > .resource-group > .count-badge {
36+
.scm-viewlet .monaco-list-row > .resource-group:hover > .count {
37+
display: none;
38+
}
39+
40+
.scm-viewlet .monaco-list-row > .resource-group:not(:hover) > .actions {
41+
display: none;
42+
}
43+
44+
.scm-viewlet .monaco-list-row > .resource {
45+
display: flex;
46+
}
47+
48+
.scm-viewlet .monaco-list-row > .resource > .name {
3549
flex: 1;
36-
font-size: 11px;
37-
font-weight: bold;
38-
text-transform: uppercase;
39-
cursor: default;
50+
overflow: hidden;
51+
}
52+
53+
.scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label {
54+
width: 100%;
55+
overflow: hidden;
56+
text-overflow: ellipsis;
57+
}
58+
59+
.scm-viewlet .monaco-list-row > .resource > .actions .action-label,
60+
.scm-viewlet .monaco-list-row > .resource-group > .actions .action-label {
61+
width: 16px;
62+
height: 100%;
63+
background-position: 50% 50%;
64+
background-repeat: no-repeat;
65+
}
66+
67+
.scm-viewlet .monaco-list-row > .resource:not(:hover) > .actions {
68+
display: none;
4069
}

src/vs/workbench/parts/scm/browser/scmMenus.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,23 +63,39 @@ export class SCMMenus implements IDisposable {
6363
return this.titleSecondaryActions;
6464
}
6565

66-
getResourceGroupActions(providerId: string, resourceGroupId: string): IAction[] {
67-
const menuId = new SCMMenuId(providerId, resourceGroupId, SCMMenuType.ResourceGroup, false);
66+
getResourceGroupActions(resourceGroupId: string): IAction[] {
67+
if (!this.scmService.activeProvider) {
68+
return [];
69+
}
70+
71+
const menuId = new SCMMenuId(this.scmService.activeProvider.id, resourceGroupId, SCMMenuType.ResourceGroup, false);
6872
return this.getActions(menuId);
6973
}
7074

71-
getResourceGroupContextActions(providerId: string, resourceGroupId: string): IAction[] {
72-
const menuId = new SCMMenuId(providerId, resourceGroupId, SCMMenuType.ResourceGroup, true);
75+
getResourceGroupContextActions(resourceGroupId: string): IAction[] {
76+
if (!this.scmService.activeProvider) {
77+
return [];
78+
}
79+
80+
const menuId = new SCMMenuId(this.scmService.activeProvider.id, resourceGroupId, SCMMenuType.ResourceGroup, true);
7381
return this.getActions(menuId);
7482
}
7583

76-
getResourceActions(providerId: string, resourceGroupId: string): IAction[] {
77-
const menuId = new SCMMenuId(providerId, resourceGroupId, SCMMenuType.Resource, false);
84+
getResourceActions(resourceGroupId: string): IAction[] {
85+
if (!this.scmService.activeProvider) {
86+
return [];
87+
}
88+
89+
const menuId = new SCMMenuId(this.scmService.activeProvider.id, resourceGroupId, SCMMenuType.Resource, false);
7890
return this.getActions(menuId);
7991
}
8092

81-
getResourceContextActions(providerId: string, resourceGroupId: string): IAction[] {
82-
const menuId = new SCMMenuId(providerId, resourceGroupId, SCMMenuType.Resource, true);
93+
getResourceContextActions(resourceGroupId: string): IAction[] {
94+
if (!this.scmService.activeProvider) {
95+
return [];
96+
}
97+
98+
const menuId = new SCMMenuId(this.scmService.activeProvider.id, resourceGroupId, SCMMenuType.Resource, true);
8399
return this.getActions(menuId);
84100
}
85101

src/vs/workbench/parts/scm/browser/scmViewlet.ts

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import { IMenuService } from 'vs/platform/actions/common/actions';
3434
import { IAction, IActionItem } from 'vs/base/common/actions';
3535
import { createActionItem } from 'vs/platform/actions/browser/menuItemActionItem';
3636
import { SCMMenus } from './scmMenus';
37+
import { ActionBar, IActionItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';
3738

3839
interface SearchInputEvent extends Event {
3940
target: HTMLInputElement;
@@ -43,25 +44,35 @@ interface SearchInputEvent extends Event {
4344
interface ResourceGroupTemplate {
4445
name: HTMLElement;
4546
count: CountBadge;
47+
actionBar: ActionBar;
4648
}
4749

4850
class ResourceGroupRenderer implements IRenderer<ISCMResourceGroup, ResourceGroupTemplate> {
4951

5052
static TEMPLATE_ID = 'resource group';
5153
get templateId(): string { return ResourceGroupRenderer.TEMPLATE_ID; }
5254

55+
constructor(
56+
private scmMenus: SCMMenus,
57+
private actionItemProvider: IActionItemProvider
58+
) { }
59+
5360
renderTemplate(container: HTMLElement): ResourceGroupTemplate {
5461
const element = append(container, $('.resource-group'));
5562
const name = append(element, $('.name'));
56-
const countContainer = append(element, $('div'));
63+
const countContainer = append(element, $('.count'));
5764
const count = new CountBadge(countContainer);
65+
const actionsContainer = append(element, $('.actions'));
66+
const actionBar = new ActionBar(actionsContainer, { actionItemProvider: this.actionItemProvider });
5867

59-
return { name, count };
68+
return { name, count, actionBar };
6069
}
6170

6271
renderElement(group: ISCMResourceGroup, index: number, template: ResourceGroupTemplate): void {
6372
template.name.textContent = group.label;
6473
template.count.setCount(group.resources.length);
74+
template.actionBar.clear();
75+
template.actionBar.push(this.scmMenus.getResourceGroupActions(group.id));
6576
}
6677

6778
disposeTemplate(template: ResourceGroupTemplate): void {
@@ -71,6 +82,7 @@ class ResourceGroupRenderer implements IRenderer<ISCMResourceGroup, ResourceGrou
7182

7283
interface ResourceTemplate {
7384
fileLabel: FileLabel;
85+
actionBar: ActionBar;
7486
}
7587

7688
class ResourceRenderer implements IRenderer<ISCMResource, ResourceTemplate> {
@@ -79,19 +91,27 @@ class ResourceRenderer implements IRenderer<ISCMResource, ResourceTemplate> {
7991
get templateId(): string { return ResourceRenderer.TEMPLATE_ID; }
8092

8193
constructor(
94+
private scmMenus: SCMMenus,
95+
private actionItemProvider: IActionItemProvider,
8296
@IInstantiationService private instantiationService: IInstantiationService
8397
) {
8498

8599
}
86100

87101
renderTemplate(container: HTMLElement): ResourceTemplate {
88-
const fileLabel = this.instantiationService.createInstance(FileLabel, container, void 0);
102+
const element = append(container, $('.resource'));
103+
const name = append(element, $('.name'));
104+
const fileLabel = this.instantiationService.createInstance(FileLabel, name, void 0);
105+
const actionsContainer = append(element, $('.actions'));
106+
const actionBar = new ActionBar(actionsContainer, { actionItemProvider: this.actionItemProvider });
89107

90-
return { fileLabel };
108+
return { fileLabel, actionBar };
91109
}
92110

93111
renderElement(resource: ISCMResource, index: number, template: ResourceTemplate): void {
94112
template.fileLabel.setFile(resource.uri);
113+
template.actionBar.clear();
114+
template.actionBar.push(this.scmMenus.getResourceActions(resource.resourceGroupId));
95115
}
96116

97117
disposeTemplate(template: ResourceTemplate): void {
@@ -176,9 +196,11 @@ export class SCMViewlet extends Viewlet {
176196
this.listContainer = append(root, $('.scm-status.show-file-icons'));
177197
const delegate = new Delegate();
178198

199+
const actionItemProvider = action => this.getActionItem(action);
200+
179201
this.list = new List(this.listContainer, delegate, [
180-
new ResourceGroupRenderer(),
181-
this.instantiationService.createInstance(ResourceRenderer)
202+
new ResourceGroupRenderer(this.menus, actionItemProvider),
203+
this.instantiationService.createInstance(ResourceRenderer, this.menus, actionItemProvider)
182204
]);
183205

184206
chain(this.list.onSelectionChange)
@@ -254,21 +276,15 @@ export class SCMViewlet extends Viewlet {
254276
}
255277

256278
private onListContextMenu(e: IListMouseEvent<ISCMResourceGroup | ISCMResource>): void {
257-
const provider = this.scmService.activeProvider;
258-
259-
if (!provider) {
260-
return;
261-
}
262-
263279
const element = e.element;
264280
let actions: IAction[];
265281

266282
if ((element as ISCMResource).uri) {
267283
const resource = element as ISCMResource;
268-
actions = this.menus.getResourceContextActions(provider.id, resource.resourceGroupId);
284+
actions = this.menus.getResourceContextActions(resource.resourceGroupId);
269285
} else {
270286
const resourceGroup = element as ISCMResourceGroup;
271-
actions = this.menus.getResourceGroupContextActions(provider.id, resourceGroup.id);
287+
actions = this.menus.getResourceGroupContextActions(resourceGroup.id);
272288
}
273289

274290
this.contextMenuService.showContextMenu({

0 commit comments

Comments
 (0)