Skip to content

Commit e8c4f47

Browse files
committed
Allow multiselect and multidelete in ports view
Fixes microsoft#121780
1 parent 04a3fb2 commit e8c4f47

File tree

1 file changed

+46
-18
lines changed

1 file changed

+46
-18
lines changed

src/vs/workbench/contrib/remote/browser/tunnelView.ts

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,8 @@ const TunnelPrivacyContextKey = new RawContextKey<TunnelPrivacy | undefined>('tu
665665
const TunnelViewFocusContextKey = new RawContextKey<boolean>('tunnelViewFocus', false, nls.localize('tunnel.focusContext', "Whether the Ports view has focus."));
666666
const TunnelViewSelectionKeyName = 'tunnelViewSelection';
667667
const TunnelViewSelectionContextKey = new RawContextKey<ITunnelItem | undefined>(TunnelViewSelectionKeyName, undefined, true);
668+
const TunnelViewMultiSelectionKeyName = 'tunnelViewMultiSelection';
669+
const TunnelViewMultiSelectionContextKey = new RawContextKey<ITunnelItem[] | undefined>(TunnelViewMultiSelectionKeyName, undefined, true);
668670
const PortChangableContextKey = new RawContextKey<boolean>('portChangable', false, true);
669671
const WebContextKey = new RawContextKey<boolean>('isWeb', isWeb, true);
670672

@@ -679,6 +681,7 @@ export class TunnelPanel extends ViewPane {
679681
private tunnelPrivacyContext: IContextKey<TunnelPrivacy | undefined>;
680682
private tunnelViewFocusContext: IContextKey<boolean>;
681683
private tunnelViewSelectionContext: IContextKey<ITunnelItem | undefined>;
684+
private tunnelViewMultiSelectionContext: IContextKey<ITunnelItem[] | undefined>;
682685
private portChangableContextKey: IContextKey<boolean>;
683686
private isEditing: boolean = false;
684687
private titleActions: IAction[] = [];
@@ -711,6 +714,7 @@ export class TunnelPanel extends ViewPane {
711714
this.tunnelPrivacyContext = TunnelPrivacyContextKey.bindTo(contextKeyService);
712715
this.tunnelViewFocusContext = TunnelViewFocusContextKey.bindTo(contextKeyService);
713716
this.tunnelViewSelectionContext = TunnelViewSelectionContextKey.bindTo(contextKeyService);
717+
this.tunnelViewMultiSelectionContext = TunnelViewMultiSelectionContextKey.bindTo(contextKeyService);
714718
this.portChangableContextKey = PortChangableContextKey.bindTo(contextKeyService);
715719

716720
const overlayContextKeyService = this._register(this.contextKeyService.createOverlay([['view', TunnelPanel.ID]]));
@@ -762,7 +766,7 @@ export class TunnelPanel extends ViewPane {
762766
return item.label;
763767
}
764768
},
765-
multipleSelectionSupport: false,
769+
multipleSelectionSupport: true,
766770
accessibilityProvider: {
767771
getAriaLabel: (item: ITunnelItem) => {
768772
if (item instanceof TunnelItem) {
@@ -783,6 +787,7 @@ export class TunnelPanel extends ViewPane {
783787
this._register(this.table.onContextMenu(e => this.onContextMenu(e, actionRunner)));
784788
this._register(this.table.onMouseDblClick(e => this.onMouseDblClick(e)));
785789
this._register(this.table.onDidChangeFocus(e => this.onFocusChanged(e)));
790+
this._register(this.table.onDidChangeSelection(e => this.onSelectionChanged(e)));
786791
this._register(this.table.onDidFocus(() => this.tunnelViewFocusContext.set(true)));
787792
this._register(this.table.onDidBlur(() => this.tunnelViewFocusContext.set(false)));
788793

@@ -879,6 +884,15 @@ export class TunnelPanel extends ViewPane {
879884
}
880885
}
881886

887+
private onSelectionChanged(event: ITableEvent<ITunnelItem>) {
888+
const elements = event.elements;
889+
if (elements.length > 1) {
890+
this.tunnelViewMultiSelectionContext.set(elements);
891+
} else {
892+
this.tunnelViewMultiSelectionContext.set(undefined);
893+
}
894+
}
895+
882896
private onContextMenu(event: ITableContextMenuEvent<ITunnelItem>, actionRunner: ActionRunner): void {
883897
if ((event.element !== undefined) && !(event.element instanceof TunnelItem)) {
884898
return;
@@ -1097,11 +1111,20 @@ namespace ClosePortAction {
10971111

10981112
export function inlineHandler(): ICommandHandler {
10991113
return async (accessor, arg) => {
1100-
const context = (arg !== undefined || arg instanceof TunnelItem) ? arg : accessor.get(IContextKeyService).getContextKeyValue(TunnelViewSelectionKeyName);
1101-
if (context instanceof TunnelItem) {
1102-
const remoteExplorerService = accessor.get(IRemoteExplorerService);
1103-
await remoteExplorerService.close({ host: context.remoteHost, port: context.remotePort });
1114+
const contextKeyService = accessor.get(IContextKeyService);
1115+
let ports = contextKeyService.getContextKeyValue<ITunnelItem[] | undefined>(TunnelViewMultiSelectionKeyName);
1116+
if (!ports) {
1117+
const context = (arg !== undefined || arg instanceof TunnelItem) ?
1118+
arg : contextKeyService.getContextKeyValue<ITunnelItem | undefined>(TunnelViewSelectionKeyName);
1119+
if (context) {
1120+
ports = [context];
1121+
}
1122+
}
1123+
if (!ports) {
1124+
return;
11041125
}
1126+
const remoteExplorerService = accessor.get(IRemoteExplorerService);
1127+
return Promise.all(ports.map(port => remoteExplorerService.close({ host: port.remoteHost, port: port.remotePort })));
11051128
};
11061129
}
11071130

@@ -1351,10 +1374,14 @@ namespace MakePortPrivateAction {
13511374

13521375
const tunnelViewCommandsWeightBonus = 10; // give our commands a little bit more weight over other default list/tree commands
13531376

1377+
const isForwardedExpr = TunnelTypeContextKey.isEqualTo(TunnelType.Forwarded);
1378+
const isForwardedOrDetectedExpr = ContextKeyExpr.or(isForwardedExpr, TunnelTypeContextKey.isEqualTo(TunnelType.Detected));
1379+
const isNotMultiSelectionExpr = TunnelViewMultiSelectionContextKey.isEqualTo(undefined);
1380+
13541381
KeybindingsRegistry.registerCommandAndKeybindingRule({
13551382
id: LabelTunnelAction.ID,
13561383
weight: KeybindingWeight.WorkbenchContrib + tunnelViewCommandsWeightBonus,
1357-
when: ContextKeyExpr.and(TunnelViewFocusContextKey, TunnelTypeContextKey.isEqualTo(TunnelType.Forwarded)),
1384+
when: ContextKeyExpr.and(TunnelViewFocusContextKey, isForwardedExpr, isNotMultiSelectionExpr),
13581385
primary: KeyCode.F2,
13591386
mac: {
13601387
primary: KeyCode.Enter
@@ -1382,7 +1409,7 @@ CommandsRegistry.registerCommand(OpenPortInBrowserCommandPaletteAction.ID, OpenP
13821409
KeybindingsRegistry.registerCommandAndKeybindingRule({
13831410
id: CopyAddressAction.INLINE_ID,
13841411
weight: KeybindingWeight.WorkbenchContrib + tunnelViewCommandsWeightBonus,
1385-
when: ContextKeyExpr.or(ContextKeyExpr.and(TunnelViewFocusContextKey, TunnelTypeContextKey.isEqualTo(TunnelType.Forwarded)), ContextKeyExpr.and(TunnelViewFocusContextKey, TunnelTypeContextKey.isEqualTo(TunnelType.Detected))),
1412+
when: ContextKeyExpr.and(TunnelViewFocusContextKey, isForwardedOrDetectedExpr, isNotMultiSelectionExpr),
13861413
primary: KeyMod.CtrlCmd | KeyCode.KEY_C,
13871414
handler: CopyAddressAction.inlineHandler()
13881415
});
@@ -1427,7 +1454,7 @@ MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
14271454
id: OpenPortInBrowserAction.ID,
14281455
title: OpenPortInBrowserAction.LABEL,
14291456
},
1430-
when: ContextKeyExpr.or(TunnelTypeContextKey.isEqualTo(TunnelType.Forwarded), TunnelTypeContextKey.isEqualTo(TunnelType.Detected))
1457+
when: ContextKeyExpr.and(isForwardedOrDetectedExpr, isNotMultiSelectionExpr)
14311458
}));
14321459
MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
14331460
group: '._open',
@@ -1438,7 +1465,8 @@ MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
14381465
},
14391466
when: ContextKeyExpr.and(
14401467
ContextKeyExpr.or(WebContextKey.negate(), TunnelPrivacyContextKey.isEqualTo(TunnelPrivacy.Public)),
1441-
ContextKeyExpr.or(TunnelTypeContextKey.isEqualTo(TunnelType.Forwarded), TunnelTypeContextKey.isEqualTo(TunnelType.Detected)))
1468+
isForwardedOrDetectedExpr,
1469+
isNotMultiSelectionExpr)
14421470
}));
14431471
// The group 0_manage is used by extensions, so try not to change it
14441472
MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
@@ -1449,7 +1477,7 @@ MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
14491477
title: LabelTunnelAction.LABEL,
14501478
icon: labelPortIcon
14511479
},
1452-
when: TunnelTypeContextKey.isEqualTo(TunnelType.Forwarded)
1480+
when: ContextKeyExpr.and(isForwardedExpr, isNotMultiSelectionExpr)
14531481
}));
14541482
MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
14551483
group: '2_localaddress',
@@ -1458,7 +1486,7 @@ MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
14581486
id: CopyAddressAction.INLINE_ID,
14591487
title: CopyAddressAction.INLINE_LABEL,
14601488
},
1461-
when: ContextKeyExpr.or(TunnelTypeContextKey.isEqualTo(TunnelType.Forwarded), TunnelTypeContextKey.isEqualTo(TunnelType.Detected))
1489+
when: ContextKeyExpr.and(isForwardedOrDetectedExpr, isNotMultiSelectionExpr)
14621490
}));
14631491
MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
14641492
group: '2_localaddress',
@@ -1467,7 +1495,7 @@ MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
14671495
id: ChangeLocalPortAction.ID,
14681496
title: ChangeLocalPortAction.LABEL,
14691497
},
1470-
when: ContextKeyExpr.and(TunnelTypeContextKey.isEqualTo(TunnelType.Forwarded), PortChangableContextKey)
1498+
when: ContextKeyExpr.and(isForwardedExpr, PortChangableContextKey, isNotMultiSelectionExpr)
14711499
}));
14721500
MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
14731501
group: '2_localaddress',
@@ -1476,7 +1504,7 @@ MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
14761504
id: MakePortPublicAction.ID,
14771505
title: MakePortPublicAction.LABEL,
14781506
},
1479-
when: TunnelPrivacyContextKey.isEqualTo(TunnelPrivacy.Private)
1507+
when: ContextKeyExpr.and(TunnelPrivacyContextKey.isEqualTo(TunnelPrivacy.Private), isNotMultiSelectionExpr)
14801508
}));
14811509
MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
14821510
group: '2_localaddress',
@@ -1485,7 +1513,7 @@ MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
14851513
id: MakePortPrivateAction.ID,
14861514
title: MakePortPrivateAction.LABEL,
14871515
},
1488-
when: TunnelPrivacyContextKey.isEqualTo(TunnelPrivacy.Public)
1516+
when: ContextKeyExpr.and(TunnelPrivacyContextKey.isEqualTo(TunnelPrivacy.Public), isNotMultiSelectionExpr)
14891517
}));
14901518
MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
14911519
group: '3_forward',
@@ -1524,7 +1552,7 @@ MenuRegistry.appendMenuItem(MenuId.TunnelPortInline, ({
15241552
title: LabelTunnelAction.LABEL,
15251553
icon: labelPortIcon
15261554
},
1527-
when: TunnelTypeContextKey.isEqualTo(TunnelType.Forwarded)
1555+
when: isForwardedExpr
15281556
}));
15291557
MenuRegistry.appendMenuItem(MenuId.TunnelPortInline, ({
15301558
group: '0_manage',
@@ -1544,7 +1572,7 @@ MenuRegistry.appendMenuItem(MenuId.TunnelLocalAddressInline, ({
15441572
title: CopyAddressAction.INLINE_LABEL,
15451573
icon: copyAddressIcon
15461574
},
1547-
when: ContextKeyExpr.or(TunnelTypeContextKey.isEqualTo(TunnelType.Forwarded), TunnelTypeContextKey.isEqualTo(TunnelType.Detected))
1575+
when: isForwardedOrDetectedExpr
15481576
}));
15491577
MenuRegistry.appendMenuItem(MenuId.TunnelLocalAddressInline, ({
15501578
order: 0,
@@ -1553,7 +1581,7 @@ MenuRegistry.appendMenuItem(MenuId.TunnelLocalAddressInline, ({
15531581
title: OpenPortInBrowserAction.LABEL,
15541582
icon: openBrowserIcon
15551583
},
1556-
when: ContextKeyExpr.or(TunnelTypeContextKey.isEqualTo(TunnelType.Forwarded), TunnelTypeContextKey.isEqualTo(TunnelType.Detected))
1584+
when: isForwardedOrDetectedExpr
15571585
}));
15581586
MenuRegistry.appendMenuItem(MenuId.TunnelLocalAddressInline, ({
15591587
order: 1,
@@ -1564,7 +1592,7 @@ MenuRegistry.appendMenuItem(MenuId.TunnelLocalAddressInline, ({
15641592
},
15651593
when: ContextKeyExpr.and(
15661594
ContextKeyExpr.or(WebContextKey.negate(), TunnelPrivacyContextKey.isEqualTo(TunnelPrivacy.Public)),
1567-
ContextKeyExpr.or(TunnelTypeContextKey.isEqualTo(TunnelType.Forwarded), TunnelTypeContextKey.isEqualTo(TunnelType.Detected)))
1595+
isForwardedOrDetectedExpr)
15681596
}));
15691597

15701598
export const portWithRunningProcessForeground = registerColor('ports.iconRunningProcessForeground', {

0 commit comments

Comments
 (0)