Skip to content

Commit 1db9db3

Browse files
authored
SCM - add incoming/outgoing menu proposal (microsoft#202772)
1 parent 8d63804 commit 1db9db3

File tree

8 files changed

+104
-6
lines changed

8 files changed

+104
-6
lines changed

src/vs/platform/actions/common/actions.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ export class MenuId {
107107
static readonly OpenEditorsContextShare = new MenuId('OpenEditorsContextShare');
108108
static readonly ProblemsPanelContext = new MenuId('ProblemsPanelContext');
109109
static readonly SCMInputBox = new MenuId('SCMInputBox');
110+
static readonly SCMIncomingChanges = new MenuId('SCMIncomingChanges');
111+
static readonly SCMOutgoingChanges = new MenuId('SCMOutgoingChanges');
110112
static readonly SCMIncomingChangesAllChangesContext = new MenuId('SCMIncomingChangesAllChangesContext');
111113
static readonly SCMIncomingChangesHistoryItemContext = new MenuId('SCMIncomingChangesHistoryItemContext');
112114
static readonly SCMOutgoingChangesAllChangesContext = new MenuId('SCMOutgoingChangesAllChangesContext');

src/vs/workbench/contrib/scm/browser/media/scm.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@
255255

256256
.scm-view .monaco-list .monaco-list-row .resource-group > .actions,
257257
.scm-view .monaco-list .monaco-list-row .resource > .name > .monaco-icon-label > .actions,
258+
.scm-view .monaco-list .monaco-list-row .history-item-group > .actions,
258259
.scm-view .monaco-list .monaco-list-row .history-item > .actions {
259260
display: none;
260261
max-width: fit-content;
@@ -267,6 +268,9 @@
267268
.scm-view .monaco-list .monaco-list-row.selected .resource > .name > .monaco-icon-label > .actions,
268269
.scm-view .monaco-list .monaco-list-row.focused .resource > .name > .monaco-icon-label > .actions,
269270
.scm-view .monaco-list:not(.selection-multiple) .monaco-list-row .resource:hover > .actions,
271+
.scm-view .monaco-list .monaco-list-row:hover .history-item-group > .actions,
272+
.scm-view .monaco-list .monaco-list-row.selected .history-item-group > .actions,
273+
.scm-view .monaco-list .monaco-list-row.focused .history-item-group > .actions,
270274
.scm-view .monaco-list .monaco-list-row:hover .history-item > .actions,
271275
.scm-view .monaco-list .monaco-list-row.selected .history-item > .actions,
272276
.scm-view .monaco-list .monaco-list-row.focused .history-item > .actions {
@@ -288,6 +292,7 @@
288292
.scm-view.show-actions > .monaco-list .monaco-list-row .scm-input > .scm-editor > .actions,
289293
.scm-view.show-actions > .monaco-list .monaco-list-row .resource-group > .actions,
290294
.scm-view.show-actions > .monaco-list .monaco-list-row .resource > .name > .monaco-icon-label > .actions,
295+
.scm-view.show-actions > .monaco-list .monaco-list-row .history-item-group > .actions,
291296
.scm-view.show-actions > .monaco-list .monaco-list-row .history-item > .actions {
292297
display: block;
293298
}

src/vs/workbench/contrib/scm/browser/menus.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,21 @@ export class SCMHistoryProviderMenus implements ISCMHistoryProviderMenus, IDispo
258258
private readonly historyItemMenus = new Map<SCMHistoryItemTreeElement, IMenu>();
259259
private readonly disposables = new DisposableStore();
260260

261+
private _incomingHistoryItemGroupMenu: IMenu;
262+
get incomingHistoryItemGroupMenu(): IMenu { return this._incomingHistoryItemGroupMenu; }
263+
264+
private _outgoingHistoryItemGroupMenu: IMenu;
265+
get outgoingHistoryItemGroupMenu(): IMenu { return this._outgoingHistoryItemGroupMenu; }
266+
261267
constructor(
262268
@IContextKeyService private readonly contextKeyService: IContextKeyService,
263-
@IMenuService private readonly menuService: IMenuService) { }
269+
@IMenuService private readonly menuService: IMenuService) {
270+
this._incomingHistoryItemGroupMenu = this.menuService.createMenu(MenuId.SCMIncomingChanges, this.contextKeyService);
271+
this.disposables.add(this._incomingHistoryItemGroupMenu);
272+
273+
this._outgoingHistoryItemGroupMenu = this.menuService.createMenu(MenuId.SCMOutgoingChanges, this.contextKeyService);
274+
this.disposables.add(this._outgoingHistoryItemGroupMenu);
275+
}
264276

265277
getHistoryItemMenu(historyItem: SCMHistoryItemTreeElement): IMenu {
266278
return this.getOrCreateHistoryItemMenu(historyItem);

src/vs/workbench/contrib/scm/browser/scmViewPane.ts

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { MenuItemAction, IMenuService, registerAction2, MenuId, IAction2Options,
2424
import { IAction, ActionRunner, Action, Separator, IActionRunner } from 'vs/base/common/actions';
2525
import { ActionBar, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';
2626
import { IThemeService, IFileIconTheme } from 'vs/platform/theme/common/themeService';
27-
import { isSCMResource, isSCMResourceGroup, connectPrimaryMenuToInlineActionBar, isSCMRepository, isSCMInput, collectContextMenuActions, getActionViewItemProvider, isSCMActionButton, isSCMViewService, isSCMHistoryItemGroupTreeElement, isSCMHistoryItemTreeElement, isSCMHistoryItemChangeTreeElement, toDiffEditorArguments, isSCMResourceNode, isSCMHistoryItemChangeNode, isSCMViewSeparator } from './util';
27+
import { isSCMResource, isSCMResourceGroup, connectPrimaryMenuToInlineActionBar, isSCMRepository, isSCMInput, collectContextMenuActions, getActionViewItemProvider, isSCMActionButton, isSCMViewService, isSCMHistoryItemGroupTreeElement, isSCMHistoryItemTreeElement, isSCMHistoryItemChangeTreeElement, toDiffEditorArguments, isSCMResourceNode, isSCMHistoryItemChangeNode, isSCMViewSeparator, connectPrimaryMenu } from './util';
2828
import { WorkbenchCompressibleAsyncDataTree, IOpenEvent } from 'vs/platform/list/browser/listService';
2929
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
3030
import { disposableTimeout, Sequencer, ThrottledDelayer, Throttler } from 'vs/base/common/async';
@@ -761,18 +761,42 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IReso
761761
}
762762
}
763763

764+
765+
class HistoryItemGroupActionRunner extends ActionRunner {
766+
767+
protected override runAction(action: IAction, context: SCMHistoryItemGroupTreeElement): Promise<void> {
768+
if (!(action instanceof MenuItemAction)) {
769+
return super.runAction(action, context);
770+
}
771+
772+
return action.run(context.repository.provider, context.id);
773+
}
774+
}
775+
764776
interface HistoryItemGroupTemplate {
765777
readonly iconContainer: HTMLElement;
766778
readonly label: IconLabel;
779+
readonly toolBar: WorkbenchToolBar;
767780
readonly count: CountBadge;
768-
readonly disposables: IDisposable;
781+
readonly elementDisposables: DisposableStore;
782+
readonly templateDisposables: DisposableStore;
769783
}
770784

771785
class HistoryItemGroupRenderer implements ICompressibleTreeRenderer<SCMHistoryItemGroupTreeElement, void, HistoryItemGroupTemplate> {
772786

773787
static readonly TEMPLATE_ID = 'history-item-group';
774788
get templateId(): string { return HistoryItemGroupRenderer.TEMPLATE_ID; }
775789

790+
constructor(
791+
readonly actionRunner: ActionRunner,
792+
@IContextKeyService readonly contextKeyService: IContextKeyService,
793+
@IContextMenuService readonly contextMenuService: IContextMenuService,
794+
@IKeybindingService readonly keybindingService: IKeybindingService,
795+
@IMenuService readonly menuService: IMenuService,
796+
@ISCMViewService private readonly scmViewService: ISCMViewService,
797+
@ITelemetryService readonly telemetryService: ITelemetryService
798+
) { }
799+
776800
renderTemplate(container: HTMLElement) {
777801
// hack
778802
(container.parentElement!.parentElement!.querySelector('.monaco-tl-twistie')! as HTMLElement).classList.add('force-twistie');
@@ -782,10 +806,14 @@ class HistoryItemGroupRenderer implements ICompressibleTreeRenderer<SCMHistoryIt
782806
const label = new IconLabel(element, { supportIcons: true });
783807
const iconContainer = prepend(label.element, $('.icon-container'));
784808

809+
const templateDisposables = new DisposableStore();
810+
const toolBar = new WorkbenchToolBar(append(element, $('.actions')), { actionRunner: this.actionRunner, menuOptions: { shouldForwardArgs: true } }, this.menuService, this.contextKeyService, this.contextMenuService, this.keybindingService, this.telemetryService);
811+
templateDisposables.add(toolBar);
812+
785813
const countContainer = append(element, $('.count'));
786814
const count = new CountBadge(countContainer, {}, defaultCountBadgeStyles);
787815

788-
return { iconContainer, label, count, disposables: new DisposableStore() };
816+
return { iconContainer, label, toolBar, count, elementDisposables: new DisposableStore(), templateDisposables };
789817
}
790818

791819
renderElement(node: ITreeNode<SCMHistoryItemGroupTreeElement>, index: number, templateData: HistoryItemGroupTemplate, height: number | undefined): void {
@@ -798,13 +826,36 @@ class HistoryItemGroupRenderer implements ICompressibleTreeRenderer<SCMHistoryIt
798826

799827
templateData.label.setLabel(historyItemGroup.label, historyItemGroup.description, { title: historyItemGroup.ariaLabel });
800828
templateData.count.setCount(historyItemGroup.count ?? 0);
829+
830+
const repositoryMenus = this.scmViewService.menus.getRepositoryMenus(historyItemGroup.repository.provider);
831+
const historyProviderMenu = repositoryMenus.historyProviderMenu;
832+
833+
if (historyProviderMenu) {
834+
const menuId = historyItemGroup.direction === 'incoming' ? MenuId.SCMIncomingChanges : MenuId.SCMOutgoingChanges;
835+
const menu = historyItemGroup.direction === 'incoming' ? historyProviderMenu.incomingHistoryItemGroupMenu : historyProviderMenu.outgoingHistoryItemGroupMenu;
836+
837+
templateData.elementDisposables.add(connectPrimaryMenu(menu, (primary, secondary) => {
838+
templateData.toolBar.setActions(primary, secondary, [menuId]);
839+
}));
840+
841+
templateData.toolBar.context = historyItemGroup;
842+
} else {
843+
templateData.toolBar.setActions([], []);
844+
templateData.toolBar.context = undefined;
845+
}
801846
}
802847

803848
renderCompressedElements(node: ITreeNode<ICompressedTreeNode<SCMHistoryItemGroupTreeElement>, void>, index: number, templateData: HistoryItemGroupTemplate, height: number | undefined): void {
804849
throw new Error('Should never happen since node is incompressible');
805850
}
851+
852+
disposeElement(node: ITreeNode<SCMHistoryItemGroupTreeElement>, index: number, templateData: HistoryItemGroupTemplate, height: number | undefined): void {
853+
templateData.elementDisposables.clear();
854+
}
855+
806856
disposeTemplate(templateData: HistoryItemGroupTemplate): void {
807-
templateData.disposables.dispose();
857+
templateData.elementDisposables.dispose();
858+
templateData.templateDisposables.dispose();
808859
}
809860
}
810861

@@ -2709,6 +2760,10 @@ export class SCMViewPane extends ViewPane {
27092760
resourceActionRunner.onWillRun(() => this.tree.domFocus(), this, this.disposables);
27102761
this.disposables.add(resourceActionRunner);
27112762

2763+
const historyItemGroupActionRunner = new HistoryItemGroupActionRunner();
2764+
historyItemGroupActionRunner.onWillRun(() => this.tree.domFocus(), this, this.disposables);
2765+
this.disposables.add(historyItemGroupActionRunner);
2766+
27122767
const historyItemActionRunner = new HistoryItemActionRunner();
27132768
historyItemActionRunner.onWillRun(() => this.tree.domFocus(), this, this.disposables);
27142769
this.disposables.add(historyItemActionRunner);
@@ -2728,7 +2783,7 @@ export class SCMViewPane extends ViewPane {
27282783
this.instantiationService.createInstance(RepositoryRenderer, MenuId.SCMTitle, getActionViewItemProvider(this.instantiationService)),
27292784
this.instantiationService.createInstance(ResourceGroupRenderer, getActionViewItemProvider(this.instantiationService)),
27302785
this.instantiationService.createInstance(ResourceRenderer, () => this.viewMode, this.listLabels, getActionViewItemProvider(this.instantiationService), resourceActionRunner),
2731-
this.instantiationService.createInstance(HistoryItemGroupRenderer),
2786+
this.instantiationService.createInstance(HistoryItemGroupRenderer, historyItemGroupActionRunner),
27322787
this.instantiationService.createInstance(HistoryItemRenderer, historyItemActionRunner, getActionViewItemProvider(this.instantiationService)),
27332788
this.instantiationService.createInstance(HistoryItemChangeRenderer, () => this.viewMode, this.listLabels),
27342789
this.instantiationService.createInstance(SeparatorRenderer)

src/vs/workbench/contrib/scm/common/history.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import { IMenu } from 'vs/platform/actions/common/actions';
1010
import { ISCMRepository } from 'vs/workbench/contrib/scm/common/scm';
1111

1212
export interface ISCMHistoryProviderMenus {
13+
readonly incomingHistoryItemGroupMenu: IMenu;
14+
readonly outgoingHistoryItemGroupMenu: IMenu;
15+
1316
getHistoryItemMenu(historyItem: SCMHistoryItemTreeElement): IMenu;
1417
}
1518

src/vs/workbench/services/actions/common/menusExtensionPoint.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,18 @@ const apiMenus: IAPIMenu[] = [
150150
description: localize('menus.input', "The Source Control input box menu"),
151151
proposed: 'contribSourceControlInputBoxMenu'
152152
},
153+
{
154+
key: 'scm/incomingChanges',
155+
id: MenuId.SCMIncomingChanges,
156+
description: localize('menus.incomingChanges', "The Source Control incoming changes menu"),
157+
proposed: 'contribSourceControlHistoryItemGroupMenu'
158+
},
159+
{
160+
key: 'scm/outgoingChanges',
161+
id: MenuId.SCMOutgoingChanges,
162+
description: localize('menus.outgoingChanges', "The Source Control outgoing changes menu"),
163+
proposed: 'contribSourceControlHistoryItemGroupMenu'
164+
},
153165
{
154166
key: 'scm/incomingChanges/allChanges/context',
155167
id: MenuId.SCMIncomingChangesAllChangesContext,

src/vs/workbench/services/extensions/common/extensionsApiProposals.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export const allApiProposals = Object.freeze({
3232
contribNotebookStaticPreloads: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribNotebookStaticPreloads.d.ts',
3333
contribRemoteHelp: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribRemoteHelp.d.ts',
3434
contribShareMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribShareMenu.d.ts',
35+
contribSourceControlHistoryItemGroupMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribSourceControlHistoryItemGroupMenu.d.ts',
3536
contribSourceControlHistoryItemMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribSourceControlHistoryItemMenu.d.ts',
3637
contribSourceControlInputBoxMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribSourceControlInputBoxMenu.d.ts',
3738
contribStatusBarItems: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribStatusBarItems.d.ts',
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
// empty placeholder declaration for the `scm/incomingChanges`-menu contribution point
7+
// empty placeholder declaration for the `scm/outgoingChanges`-menu contribution point
8+
// https://github.com/microsoft/vscode/issues/201997

0 commit comments

Comments
 (0)