Skip to content

Commit 0acc996

Browse files
authored
Add support for view initial state (collapsed or hidden) (microsoft#102002)
Fixes microsoft#101283
1 parent 27e8b9d commit 0acc996

4 files changed

Lines changed: 42 additions & 5 deletions

File tree

extensions/npm/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@
5656
{
5757
"id": "npm",
5858
"name": "%view.name%",
59-
"when": "npm:showScriptExplorer || config.npm.enableScriptExplorer",
60-
"icon": "images/code.svg"
59+
"when": "npm:showScriptExplorer",
60+
"icon": "images/code.svg",
61+
"visibility": "hidden"
6162
}
6263
]
6364
},

src/vs/workbench/api/browser/viewsExtensionPoint.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,19 @@ interface IUserFriendlyViewDescriptor {
8383

8484
icon?: string;
8585
contextualTitle?: string;
86+
visibility?: string;
8687

8788
// From 'remoteViewDescriptor' type
8889
group?: string;
8990
remoteName?: string | string[];
9091
}
9192

93+
enum InitialVisibility {
94+
Visible = 'visible',
95+
Hidden = 'hidden',
96+
Collapsed = 'collapsed'
97+
}
98+
9299
const viewDescriptor: IJSONSchema = {
93100
type: 'object',
94101
properties: {
@@ -112,6 +119,20 @@ const viewDescriptor: IJSONSchema = {
112119
description: localize('vscode.extension.contributes.view.contextualTitle', "Human-readable context for when the view is moved out of its original location. By default, the view's container name will be used. Will be shown"),
113120
type: 'string'
114121
},
122+
visibility: {
123+
description: localize('vscode.extension.contributes.view.initialState', "Initial state of the view when the extension is first installed. Once the user has changed the view state by collapsing, moving, or hiding the view, the initial state will not be used again."),
124+
type: 'string',
125+
enum: [
126+
'visible',
127+
'hidden',
128+
'collapsed'
129+
],
130+
enumDescriptions: [
131+
localize('vscode.extension.contributes.view.initialState.visible', "The default initial state for view. The view will be expanded. This may have different behavior when the view container that the view is in is built in."),
132+
localize('vscode.extension.contributes.view.initialState.hidden', "The view will not be shown in the view container, but will be discoverable through the views menu and other view entry points and can be un-hidden by the user."),
133+
localize('vscode.extension.contributes.view.initialState.collapsed', "The view will show in the view container, but will be collapsed.")
134+
]
135+
}
115136
}
116137
};
117138

@@ -419,6 +440,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
419440
: undefined;
420441

421442
const icon = item.icon ? resources.joinPath(extension.description.extensionLocation, item.icon) : undefined;
443+
const initialVisibility = this.convertInitialVisibility(item.visibility);
422444
const viewDescriptor = <ICustomViewDescriptor>{
423445
id: item.id,
424446
name: item.name,
@@ -429,12 +451,13 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
429451
canToggleVisibility: true,
430452
canMoveView: true,
431453
treeView: this.instantiationService.createInstance(CustomTreeView, item.id, item.name),
432-
collapsed: this.showCollapsed(container),
454+
collapsed: this.showCollapsed(container) || initialVisibility === InitialVisibility.Collapsed,
433455
order: order,
434456
extensionId: extension.description.identifier,
435457
originalContainerId: entry.key,
436458
group: item.group,
437-
remoteAuthority: item.remoteName || (<any>item).remoteAuthority // TODO@roblou - delete after remote extensions are updated
459+
remoteAuthority: item.remoteName || (<any>item).remoteAuthority, // TODO@roblou - delete after remote extensions are updated
460+
hideByDefault: initialVisibility === InitialVisibility.Hidden
438461
};
439462

440463
viewIds.add(viewDescriptor.id);
@@ -463,6 +486,13 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
463486
}
464487
}
465488

489+
private convertInitialVisibility(value: any): InitialVisibility | undefined {
490+
if (Object.values(InitialVisibility).includes(value)) {
491+
return value;
492+
}
493+
return undefined;
494+
}
495+
466496
private isValidViewDescriptors(viewDescriptors: IUserFriendlyViewDescriptor[], collector: ExtensionMessageCollector): boolean {
467497
if (!Array.isArray(viewDescriptors)) {
468498
collector.error(localize('requirearray', "views must be an array"));
@@ -490,6 +520,10 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
490520
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'contextualTitle'));
491521
return false;
492522
}
523+
if (descriptor.visibility && !this.convertInitialVisibility(descriptor.visibility)) {
524+
collector.error(localize('optenum', "property `{0}` can be omitted or must be one of {1}", 'visibility', Object.values(InitialVisibility).join(', ')));
525+
return false;
526+
}
493527
}
494528

495529
return true;

src/vs/workbench/browser/parts/views/viewPaneContainer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,8 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
982982
this.updateViewHeaders();
983983
}
984984
});
985+
986+
this._register(this.viewContainerModel.onDidChangeActiveViewDescriptors(() => this._onTitleAreaUpdate.fire()));
985987
}
986988

987989
getTitle(): string {

src/vs/workbench/browser/viewlet.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export abstract class Viewlet extends PaneComposite implements IViewlet {
4545
@IConfigurationService protected configurationService: IConfigurationService
4646
) {
4747
super(id, viewPaneContainer, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
48-
this._register(Event.any(viewPaneContainer.onDidAddViews, viewPaneContainer.onDidRemoveViews)(() => {
48+
this._register(Event.any(viewPaneContainer.onDidAddViews, viewPaneContainer.onDidRemoveViews, viewPaneContainer.onTitleAreaUpdate)(() => {
4949
// Update title area since there is no better way to update secondary actions
5050
this.updateTitleArea();
5151
}));

0 commit comments

Comments
 (0)