mirror of
https://github.com/Microsoft/vscode
synced 2024-10-05 19:02:54 +00:00
profiles editor: incorporate feedback (#214490)
This commit is contained in:
parent
6e4ace33dd
commit
dfedd9ba12
|
@ -768,7 +768,7 @@ export class ExtensionsScanner extends Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
private async scanLocalExtension(location: URI, type: ExtensionType, profileLocation?: URI): Promise<ILocalExtension> {
|
||||
async scanLocalExtension(location: URI, type: ExtensionType, profileLocation?: URI): Promise<ILocalExtension> {
|
||||
try {
|
||||
if (profileLocation) {
|
||||
const scannedExtensions = await this.extensionsScannerService.scanUserExtensions({ profileLocation });
|
||||
|
@ -921,13 +921,9 @@ class InstallExtensionInProfileTask extends AbstractExtensionTask<ILocalExtensio
|
|||
this.identifier = this.extensionKey.identifier;
|
||||
}
|
||||
|
||||
private async getExistingExtension(): Promise<ILocalExtension | undefined> {
|
||||
const installed = await this.extensionsScanner.scanExtensions(null, this.options.profileLocation, this.options.productVersion);
|
||||
return installed.find(i => areSameExtensions(i.identifier, this.identifier));
|
||||
}
|
||||
|
||||
protected async doRun(token: CancellationToken): Promise<ILocalExtension> {
|
||||
const existingExtension = await this.getExistingExtension();
|
||||
const installed = await this.extensionsScanner.scanExtensions(ExtensionType.User, this.options.profileLocation, this.options.productVersion);
|
||||
const existingExtension = installed.find(i => areSameExtensions(i.identifier, this.identifier));
|
||||
if (existingExtension) {
|
||||
this._operation = InstallOperation.Update;
|
||||
}
|
||||
|
@ -1018,7 +1014,7 @@ class InstallExtensionInProfileTask extends AbstractExtensionTask<ILocalExtensio
|
|||
throw toExtensionManagementError(error, ExtensionManagementErrorCode.AddToProfile);
|
||||
}
|
||||
|
||||
const result = await this.getExistingExtension();
|
||||
const result = await this.extensionsScanner.scanLocalExtension(local.location, ExtensionType.User, this.options.profileLocation);
|
||||
if (!result) {
|
||||
throw new ExtensionManagementError('Cannot find the installed extension', ExtensionManagementErrorCode.InstalledExtensionNotFound);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,11 @@
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.profiles-editor .monaco-split-view2 > .sash-container,
|
||||
.profiles-editor .monaco-split-view2.separator-border.horizontal > .monaco-scrollable-element > .split-view-container > .split-view-view:not(:first-child)::before {
|
||||
top: 55px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container {
|
||||
padding: 0px 20px;
|
||||
height: 100%;
|
||||
|
@ -42,8 +47,20 @@
|
|||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.profiles-editor .monaco-list-row .profile-tree-item-actions-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.profiles-editor .monaco-list-row.focused .profile-tree-item-actions-container,
|
||||
.profiles-editor .monaco-list-row.selected .profile-tree-item-actions-container,
|
||||
.profiles-editor .monaco-list-row:hover .profile-tree-item-actions-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.profiles-editor .sidebar-container .profiles-list {
|
||||
margin-top: 10px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.profiles-editor .sidebar-container .profiles-list .profile-list-item {
|
||||
|
@ -68,6 +85,11 @@
|
|||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.profiles-editor .sidebar-container .profiles-list .profile-list-item .profile-tree-item-actions-container {
|
||||
justify-content: flex-end;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.profiles-editor .hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
@ -82,18 +104,18 @@
|
|||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: large;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-title-container .codicon {
|
||||
cursor: pointer;
|
||||
font-size: large;
|
||||
padding: 6px;
|
||||
padding: 4px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-title-container .monaco-inputbox {
|
||||
width: 330px;
|
||||
width: 340px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-header .profile-button-container {
|
||||
|
@ -102,25 +124,15 @@
|
|||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-header .profile-button-container .monaco-button {
|
||||
margin-right: 4px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-header .profile-actions-container {
|
||||
display: flex;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-header .profile-actions-container .actions-container {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-header .profile-actions-container .actions-container .codicon {
|
||||
font-size: 18px;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-header .profile-actions-container .profile-button-container {
|
||||
margin-left:6px;
|
||||
margin-right: 6px;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
|
@ -129,6 +141,10 @@
|
|||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-header .profile-actions-container .actions-container .action-label {
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-body {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
@ -142,15 +158,15 @@
|
|||
|
||||
.profiles-editor .contents-container .profile-select-container > .monaco-select-box {
|
||||
cursor: pointer;
|
||||
line-height: 17px;
|
||||
padding: 2px 23px 2px 8px;
|
||||
line-height: 18px;
|
||||
padding: 0px 23px 0px 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-copy-from-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0px 0px 20px 28px;
|
||||
margin: 0px 0px 20px 36px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-copy-from-container > .profile-copy-from-label {
|
||||
|
@ -166,35 +182,60 @@
|
|||
.profiles-editor .contents-container .profile-use-as-default-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 25px 20px 20px 28px;
|
||||
margin: 0px 20px 15px 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-use-as-default-container .profile-use-as-default-label {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-contents-container {
|
||||
margin: 0px 0px 10px 20px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-content-tree-header,
|
||||
.profiles-editor .contents-container .profile-content-tree {
|
||||
margin-left: 6px;
|
||||
max-width: 450px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-content-tree-header {
|
||||
display: flex;
|
||||
height: 24px;
|
||||
align-items: center;
|
||||
margin-bottom: 2px;
|
||||
background-color: var(--vscode-keybindingTable-headerBackground);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-tree-item-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-tree-item-container > .profile-resource-type-label {
|
||||
.profiles-editor .contents-container .profile-content-tree-header :first-child {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-tree-item-container > .profile-resource-type-label,
|
||||
.profiles-editor .contents-container .profile-tree-item-container.new-profile-resource-type-container > .profile-resource-type-label-container {
|
||||
width: 170px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-content-tree-header > .inherit-label,
|
||||
.profiles-editor .contents-container .profile-tree-item-container > .inherit-container {
|
||||
width: 130px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-tree-item-container > .inherit-container > .inherit-label {
|
||||
/* font-size: 0.9em; */
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-tree-item-container.new-profile-resource-type-container > .profile-resource-type-label-container {
|
||||
width: 170px;
|
||||
.profiles-editor .contents-container .profile-content-tree-header > .actions-label {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-tree-item-container.new-profile-resource-type-container > .profile-select-container {
|
||||
|
@ -206,3 +247,11 @@
|
|||
font-size: 0.9em;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-tree-item-container.profile-resource-child-container > .monaco-icon-label {
|
||||
width: 295px;
|
||||
}
|
||||
|
||||
.profiles-editor .contents-container .profile-tree-item-container .profile-tree-item-actions-container {
|
||||
justify-content: center;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ import { IHostService } from 'vs/workbench/services/host/browser/host';
|
|||
|
||||
type IProfileTemplateQuickPickItem = IQuickPickItem & IProfileTemplateInfo;
|
||||
|
||||
export const OpenProfileMenu = new MenuId('OpenProfile');
|
||||
|
||||
export class UserDataProfilesWorkbenchContribution extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
static readonly ID = 'workbench.contrib.userDataProfiles';
|
||||
|
@ -100,6 +102,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
|
|||
this._register(this.registerManageProfilesAction());
|
||||
this._register(this.registerSwitchProfileAction());
|
||||
|
||||
this.registerOpenProfileSubMenu();
|
||||
this.registerProfilesActions();
|
||||
this._register(this.userDataProfilesService.onDidChangeProfiles(() => this.registerProfilesActions()));
|
||||
|
||||
|
@ -137,15 +140,23 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
|
|||
});
|
||||
}
|
||||
|
||||
private registerOpenProfileSubMenu(): void {
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
|
||||
title: localize('open profile', "Open Profile"),
|
||||
submenu: OpenProfileMenu,
|
||||
group: '2_open',
|
||||
order: 4,
|
||||
when: HAS_PROFILES_CONTEXT,
|
||||
});
|
||||
}
|
||||
|
||||
private readonly profilesDisposable = this._register(new MutableDisposable<DisposableStore>());
|
||||
private registerProfilesActions(): void {
|
||||
this.profilesDisposable.value = new DisposableStore();
|
||||
for (const profile of this.userDataProfilesService.profiles) {
|
||||
if (!profile.isTransient) {
|
||||
this.profilesDisposable.value.add(this.registerProfileEntryAction(profile));
|
||||
if (!profile.isDefault) {
|
||||
this.profilesDisposable.value.add(this.registerNewWindowAction(profile));
|
||||
}
|
||||
this.profilesDisposable.value.add(this.registerNewWindowAction(profile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -189,19 +200,19 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
|
|||
}
|
||||
|
||||
private registerNewWindowAction(profile: IUserDataProfile): IDisposable {
|
||||
return registerAction2(class NewWindowAction extends Action2 {
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
const id = `workbench.action.openProfile.${profile.name.toLowerCase().replace('/\s+/', '_')}`;
|
||||
|
||||
disposables.add(registerAction2(class NewWindowAction extends Action2 {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: `workbench.action.${profile.name.toLowerCase().replace('/\s+/', '_')}.newWindow`,
|
||||
title: {
|
||||
...localize2('newWindow', "New {0} Window", profile.name),
|
||||
},
|
||||
f1: true,
|
||||
id,
|
||||
title: localize2('openShort', "{0}", profile.name),
|
||||
menu: {
|
||||
id: MenuId.MenubarFileMenu,
|
||||
group: '1_new',
|
||||
order: 4
|
||||
id: OpenProfileMenu,
|
||||
when: HAS_PROFILES_CONTEXT
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -210,7 +221,18 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
|
|||
const hostService = accessor.get(IHostService);
|
||||
return hostService.openWindow({ remoteAuthority: null, forceProfile: profile.name });
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
disposables.add(MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
command: {
|
||||
id,
|
||||
category: PROFILES_CATEGORY,
|
||||
title: localize2('open', "Open {0} Profile", profile.name),
|
||||
precondition: HAS_PROFILES_CONTEXT
|
||||
},
|
||||
}));
|
||||
|
||||
return disposables;
|
||||
}
|
||||
|
||||
private registerSwitchProfileAction(): IDisposable {
|
||||
|
@ -247,15 +269,12 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
|
|||
private readonly currentprofileActionsDisposable = this._register(new MutableDisposable<DisposableStore>());
|
||||
private registerCurrentProfilesActions(): void {
|
||||
this.currentprofileActionsDisposable.value = new DisposableStore();
|
||||
this.currentprofileActionsDisposable.value.add(this.registerEditCurrentProfileAction());
|
||||
this.currentprofileActionsDisposable.value.add(this.registerShowCurrentProfileContentsAction());
|
||||
this.currentprofileActionsDisposable.value.add(this.registerExportCurrentProfileAction());
|
||||
this.currentprofileActionsDisposable.value.add(this.registerImportProfileAction());
|
||||
}
|
||||
|
||||
private registerManageProfilesAction(): IDisposable {
|
||||
const disposables = new DisposableStore();
|
||||
const precondition = ContextKeyExpr.equals('config.workbench.experimental.enableNewProfilesUI', true);
|
||||
disposables.add(registerAction2(class ManageProfilesAction extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
|
@ -265,23 +284,15 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
|
|||
mnemonicTitle: localize({ key: 'miOpenProfiles', comment: ['&& denotes a mnemonic'] }, "&&Profiles"),
|
||||
},
|
||||
menu: [
|
||||
{
|
||||
id: ProfilesMenu,
|
||||
group: '2_manage_current',
|
||||
when: precondition,
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
id: MenuId.GlobalActivity,
|
||||
group: '2_configuration',
|
||||
order: 1,
|
||||
when: ContextKeyExpr.and(HAS_PROFILES_CONTEXT.negate(), precondition),
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
id: MenuId.MenubarPreferencesMenu,
|
||||
group: '2_configuration',
|
||||
order: 1,
|
||||
when: ContextKeyExpr.and(HAS_PROFILES_CONTEXT.negate(), precondition),
|
||||
order: 1
|
||||
},
|
||||
]
|
||||
});
|
||||
|
@ -297,66 +308,12 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
|
|||
id: 'workbench.profiles.actions.manageProfiles',
|
||||
category: Categories.Preferences,
|
||||
title: localize2('open profiles', "Open Profiles (UI)"),
|
||||
precondition: precondition,
|
||||
},
|
||||
}));
|
||||
|
||||
return disposables;
|
||||
}
|
||||
|
||||
|
||||
private registerEditCurrentProfileAction(): IDisposable {
|
||||
const that = this;
|
||||
return registerAction2(class RenameCurrentProfileAction extends Action2 {
|
||||
constructor() {
|
||||
const precondition = ContextKeyExpr.and(ContextKeyExpr.notEquals(CURRENT_PROFILE_CONTEXT.key, that.userDataProfilesService.defaultProfile.id), IS_CURRENT_PROFILE_TRANSIENT_CONTEXT.toNegated());
|
||||
super({
|
||||
id: `workbench.profiles.actions.editCurrentProfile`,
|
||||
title: localize2('edit profile', "Edit Profile..."),
|
||||
precondition: precondition,
|
||||
f1: true,
|
||||
menu: [
|
||||
{
|
||||
id: ProfilesMenu,
|
||||
group: '2_manage_current',
|
||||
when: ContextKeyExpr.and(precondition, ContextKeyExpr.notEquals('config.workbench.experimental.enableNewProfilesUI', true)),
|
||||
order: 2
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
run() {
|
||||
return that.userDataProfileImportExportService.editProfile(that.userDataProfileService.currentProfile);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private registerShowCurrentProfileContentsAction(): IDisposable {
|
||||
const id = 'workbench.profiles.actions.showProfileContents';
|
||||
return registerAction2(class ShowProfileContentsAction extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id,
|
||||
title: localize2('show profile contents', "Show Profile Contents"),
|
||||
category: PROFILES_CATEGORY,
|
||||
menu: [
|
||||
{
|
||||
id: ProfilesMenu,
|
||||
group: '2_manage_current',
|
||||
order: 3,
|
||||
when: ContextKeyExpr.notEquals('config.workbench.experimental.enableNewProfilesUI', true)
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor) {
|
||||
const userDataProfileImportExportService = accessor.get(IUserDataProfileImportExportService);
|
||||
return userDataProfileImportExportService.showProfileContents();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private registerExportCurrentProfileAction(): IDisposable {
|
||||
const that = this;
|
||||
const disposables = new DisposableStore();
|
||||
|
@ -365,34 +322,22 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
|
|||
constructor() {
|
||||
super({
|
||||
id,
|
||||
title: localize2('export profile', "Export Profile..."),
|
||||
title: localize2('export profile', "Export Profile ({0})...", that.userDataProfileService.currentProfile.name),
|
||||
category: PROFILES_CATEGORY,
|
||||
precondition: IS_PROFILE_EXPORT_IN_PROGRESS_CONTEXT.toNegated(),
|
||||
menu: [
|
||||
{
|
||||
id: ProfilesMenu,
|
||||
group: '4_import_export_profiles',
|
||||
order: 1,
|
||||
when: ContextKeyExpr.notEquals('config.workbench.experimental.enableNewProfilesUI', true),
|
||||
}, {
|
||||
id: MenuId.CommandPalette
|
||||
}
|
||||
]
|
||||
f1: true,
|
||||
menu: {
|
||||
id: MenuId.MenubarShare
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor) {
|
||||
const userDataProfileImportExportService = accessor.get(IUserDataProfileImportExportService);
|
||||
return userDataProfileImportExportService.exportProfile();
|
||||
const editorGroupsService = accessor.get(IEditorGroupsService);
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
return editorGroupsService.activeGroup.openEditor(new UserDataProfilesEditorInput(instantiationService));
|
||||
}
|
||||
}));
|
||||
disposables.add(MenuRegistry.appendMenuItem(MenuId.MenubarShare, {
|
||||
command: {
|
||||
id,
|
||||
title: localize2('export profile in share', "Export Profile ({0})...", that.userDataProfileService.currentProfile.name),
|
||||
precondition: PROFILES_ENABLEMENT_CONTEXT,
|
||||
},
|
||||
}));
|
||||
return disposables;
|
||||
}
|
||||
|
||||
|
@ -407,17 +352,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
|
|||
title: localize2('import profile', "Import Profile..."),
|
||||
category: PROFILES_CATEGORY,
|
||||
precondition: IS_PROFILE_IMPORT_IN_PROGRESS_CONTEXT.toNegated(),
|
||||
menu: [
|
||||
{
|
||||
id: ProfilesMenu,
|
||||
group: '4_import_export_profiles',
|
||||
when: ContextKeyExpr.and(PROFILES_ENABLEMENT_CONTEXT, ContextKeyExpr.notEquals('config.workbench.experimental.enableNewProfilesUI', true)),
|
||||
order: 2
|
||||
}, {
|
||||
id: MenuId.CommandPalette,
|
||||
when: PROFILES_ENABLEMENT_CONTEXT,
|
||||
}
|
||||
]
|
||||
f1: true,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -519,7 +454,6 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
|
|||
}
|
||||
|
||||
private registerCreateProfileAction(): void {
|
||||
const that = this;
|
||||
this._register(registerAction2(class CreateProfileAction extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
|
@ -528,19 +462,13 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
|
|||
category: PROFILES_CATEGORY,
|
||||
precondition: PROFILES_ENABLEMENT_CONTEXT,
|
||||
f1: true,
|
||||
menu: [
|
||||
{
|
||||
id: ProfilesMenu,
|
||||
group: '3_manage_profiles',
|
||||
when: ContextKeyExpr.and(PROFILES_ENABLEMENT_CONTEXT, ContextKeyExpr.notEquals('config.workbench.experimental.enableNewProfilesUI', true)),
|
||||
order: 1
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor) {
|
||||
return that.userDataProfileImportExportService.createProfile();
|
||||
const editorGroupsService = accessor.get(IEditorGroupsService);
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
return editorGroupsService.activeGroup.openEditor(new UserDataProfilesEditorInput(instantiationService));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -554,14 +482,6 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
|
|||
category: PROFILES_CATEGORY,
|
||||
f1: true,
|
||||
precondition: ContextKeyExpr.and(PROFILES_ENABLEMENT_CONTEXT, HAS_PROFILES_CONTEXT),
|
||||
menu: [
|
||||
{
|
||||
id: ProfilesMenu,
|
||||
group: '3_manage_profiles',
|
||||
when: ContextKeyExpr.and(PROFILES_ENABLEMENT_CONTEXT, ContextKeyExpr.notEquals('config.workbench.experimental.enableNewProfilesUI', true)),
|
||||
order: 2
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ export class UserDataProfilesEditor extends EditorPane implements IUserDataProfi
|
|||
layout: (width, _, height) => {
|
||||
sidebarView.style.width = `${width}px`;
|
||||
if (height && this.profilesList) {
|
||||
const listHeight = height - 40 /* new profile button */ - 10 /* padding */;
|
||||
const listHeight = height - 40 /* new profile button */ - 15 /* marginTop */;
|
||||
this.profilesList.getHTMLElement().style.height = `${listHeight}px`;
|
||||
this.profilesList.layout(listHeight, width);
|
||||
}
|
||||
|
@ -136,9 +136,6 @@ export class UserDataProfilesEditor extends EditorPane implements IUserDataProfi
|
|||
}
|
||||
}, Sizing.Distribute, undefined, true);
|
||||
|
||||
const borderColor = this.theme.getColor(profilesSashBorder)!;
|
||||
this.splitView.style({ separatorBorder: borderColor });
|
||||
|
||||
this.registerListeners();
|
||||
|
||||
this.userDataProfileManagementService.getBuiltinProfileTemplates().then(templates => {
|
||||
|
@ -147,6 +144,11 @@ export class UserDataProfilesEditor extends EditorPane implements IUserDataProfi
|
|||
});
|
||||
}
|
||||
|
||||
override updateStyles(): void {
|
||||
const borderColor = this.theme.getColor(profilesSashBorder)!;
|
||||
this.splitView?.style({ separatorBorder: borderColor });
|
||||
}
|
||||
|
||||
private renderSidebar(parent: HTMLElement): void {
|
||||
// render New Profile Button
|
||||
this.renderNewProfileButton(append(parent, $('.new-profile-button')));
|
||||
|
@ -188,10 +190,7 @@ export class UserDataProfilesEditor extends EditorPane implements IUserDataProfi
|
|||
getActions: () => {
|
||||
const actions: IAction[] = [];
|
||||
if (this.templates.length) {
|
||||
actions.push(new SubmenuAction('from.template', localize('from template', "From Template"),
|
||||
this.templates.map(template => new Action(`template:${template.url}`, template.name, undefined, true, async () => {
|
||||
this.createNewProfile(URI.parse(template.url));
|
||||
}))));
|
||||
actions.push(new SubmenuAction('from.template', localize('from template', "From Template"), this.getCreateFromTemplateActions()));
|
||||
actions.push(new Separator());
|
||||
}
|
||||
actions.push(new Action('importProfile', localize('importProfile', "Import Profile..."), undefined, true, () => this.importProfile()));
|
||||
|
@ -203,10 +202,16 @@ export class UserDataProfilesEditor extends EditorPane implements IUserDataProfi
|
|||
supportIcons: true,
|
||||
...defaultButtonStyles
|
||||
}));
|
||||
button.label = `$(add) ${localize('newProfile', "New Profile")}`;
|
||||
button.label = localize('newProfile', "New Profile");
|
||||
this._register(button.onDidClick(e => this.createNewProfile()));
|
||||
}
|
||||
|
||||
private getCreateFromTemplateActions(): IAction[] {
|
||||
return this.templates.map(template => new Action(`template:${template.url}`, template.name, undefined, true, async () => {
|
||||
this.createNewProfile(URI.parse(template.url));
|
||||
}));
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
if (this.profilesList) {
|
||||
this._register(this.profilesList.onDidChangeSelection(e => {
|
||||
|
@ -215,19 +220,43 @@ export class UserDataProfilesEditor extends EditorPane implements IUserDataProfi
|
|||
this.profileWidget?.render(element);
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this.profilesList.onContextMenu(e => {
|
||||
const actions: IAction[] = [];
|
||||
if (!e.element) {
|
||||
actions.push(...this.getTreeContextMenuActions());
|
||||
}
|
||||
if (e.element instanceof AbstractUserDataProfileElement) {
|
||||
actions.push(...e.element.contextMenuActions);
|
||||
}
|
||||
if (actions.length) {
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => e.anchor,
|
||||
getActions: () => e.element instanceof AbstractUserDataProfileElement ? e.element.contextMenuActions.slice(0) : [],
|
||||
getActions: () => actions,
|
||||
getActionsContext: () => e.element
|
||||
});
|
||||
}
|
||||
}));
|
||||
this._register(this.profilesList.onMouseDblClick(e => {
|
||||
if (!e.element) {
|
||||
this.createNewProfile();
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private getTreeContextMenuActions(): IAction[] {
|
||||
const actions: IAction[] = [];
|
||||
actions.push(new Action('newProfile', localize('newProfile', "New Profile"), undefined, true, () => this.createNewProfile()));
|
||||
const templateActions = this.getCreateFromTemplateActions();
|
||||
if (templateActions.length) {
|
||||
actions.push(new SubmenuAction('from.template', localize('new from template', "New Profile From Template"), templateActions));
|
||||
}
|
||||
actions.push(new Separator());
|
||||
actions.push(new Action('importProfile', localize('importProfile', "Import Profile..."), undefined, true, () => this.importProfile()));
|
||||
return actions;
|
||||
}
|
||||
|
||||
private async importProfile(): Promise<void> {
|
||||
const disposables = new DisposableStore();
|
||||
const quickPick = disposables.add(this.quickInputService.createQuickPick());
|
||||
|
@ -338,12 +367,14 @@ interface IProfileElementTemplateData {
|
|||
readonly icon: HTMLElement;
|
||||
readonly label: HTMLElement;
|
||||
readonly description: HTMLElement;
|
||||
readonly actionBar: WorkbenchToolBar;
|
||||
readonly disposables: DisposableStore;
|
||||
readonly elementDisposables: DisposableStore;
|
||||
}
|
||||
|
||||
class ProfileElementDelegate implements IListVirtualDelegate<AbstractUserDataProfileElement> {
|
||||
getHeight(element: AbstractUserDataProfileElement) {
|
||||
return 30;
|
||||
return 22;
|
||||
}
|
||||
getTemplateId() { return 'profileListElement'; }
|
||||
}
|
||||
|
@ -352,24 +383,42 @@ class ProfileElementRenderer implements IListRenderer<AbstractUserDataProfileEle
|
|||
|
||||
readonly templateId = 'profileListElement';
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
) { }
|
||||
|
||||
renderTemplate(container: HTMLElement): IProfileElementTemplateData {
|
||||
|
||||
const disposables = new DisposableStore();
|
||||
const elementDisposables = new DisposableStore();
|
||||
|
||||
container.classList.add('profile-list-item');
|
||||
const icon = append(container, $('.profile-list-item-icon'));
|
||||
const label = append(container, $('.profile-list-item-label'));
|
||||
const description = append(container, $('.profile-list-item-description'));
|
||||
append(description, $(`span${ThemeIcon.asCSSSelector(Codicon.check)}`));
|
||||
append(description, $('span', undefined, localize('activeProfile', "Active")));
|
||||
return { label, icon, description, disposables: new DisposableStore() };
|
||||
append(description, $('span', undefined, localize('activeProfile', "In use")));
|
||||
|
||||
const actionsContainer = append(container, $('.profile-tree-item-actions-container'));
|
||||
const actionBar = disposables.add(this.instantiationService.createInstance(WorkbenchToolBar,
|
||||
actionsContainer,
|
||||
{
|
||||
hoverDelegate: disposables.add(createInstantHoverDelegate()),
|
||||
highlightToggledItems: true
|
||||
}
|
||||
));
|
||||
|
||||
return { label, icon, description, actionBar, disposables, elementDisposables };
|
||||
}
|
||||
|
||||
renderElement(element: AbstractUserDataProfileElement, index: number, templateData: IProfileElementTemplateData, height: number | undefined) {
|
||||
templateData.disposables.clear();
|
||||
templateData.elementDisposables.clear();
|
||||
templateData.label.textContent = element.name;
|
||||
templateData.label.classList.toggle('new-profile', element instanceof NewProfileElement);
|
||||
templateData.icon.className = ThemeIcon.asClassName(element.icon ? ThemeIcon.fromId(element.icon) : DEFAULT_ICON);
|
||||
templateData.description.classList.toggle('hide', !element.active);
|
||||
if (element.onDidChange) {
|
||||
templateData.disposables.add(element.onDidChange(e => {
|
||||
templateData.elementDisposables.add(element.onDidChange(e => {
|
||||
if (e.name) {
|
||||
templateData.label.textContent = element.name;
|
||||
}
|
||||
|
@ -385,10 +434,16 @@ class ProfileElementRenderer implements IListRenderer<AbstractUserDataProfileEle
|
|||
}
|
||||
}));
|
||||
}
|
||||
templateData.actionBar.setActions(element.titleActions[0] ?? []);
|
||||
}
|
||||
|
||||
disposeElement(element: AbstractUserDataProfileElement, index: number, templateData: IProfileElementTemplateData, height: number | undefined): void {
|
||||
templateData.elementDisposables.clear();
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IProfileElementTemplateData): void {
|
||||
templateData.disposables.dispose();
|
||||
templateData.elementDisposables.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -405,6 +460,7 @@ class ProfileWidget extends Disposable {
|
|||
private readonly copyFromSelectBox: SelectBox;
|
||||
private copyFromOptions: (ISelectOptionItem & { id?: string; source?: IUserDataProfile | URI })[] = [];
|
||||
|
||||
private readonly contentsTreeHeader: HTMLElement;
|
||||
private readonly resourcesTree: WorkbenchAsyncDataTree<AbstractUserDataProfileElement, ProfileResourceTreeElement>;
|
||||
|
||||
private _templates: IProfileTemplateInfo[] = [];
|
||||
|
@ -471,6 +527,7 @@ class ProfileWidget extends Disposable {
|
|||
}));
|
||||
|
||||
const actionsContainer = append(header, $('.profile-actions-container'));
|
||||
this.buttonContainer = append(actionsContainer, $('.profile-button-container'));
|
||||
this.toolbar = this._register(instantiationService.createInstance(WorkbenchToolBar,
|
||||
actionsContainer,
|
||||
{
|
||||
|
@ -478,7 +535,6 @@ class ProfileWidget extends Disposable {
|
|||
highlightToggledItems: true
|
||||
}
|
||||
));
|
||||
this.buttonContainer = append(actionsContainer, $('.profile-button-container'));
|
||||
|
||||
const body = append(parent, $('.profile-body'));
|
||||
|
||||
|
@ -497,7 +553,7 @@ class ProfileWidget extends Disposable {
|
|||
this.copyFromSelectBox.render(append(this.copyFromContainer, $('.profile-select-container')));
|
||||
|
||||
this.useAsDefaultProfileContainer = append(body, $('.profile-use-as-default-container'));
|
||||
const useAsDefaultProfileTitle = localize('enable for new windows', "Enable this profile for new windows");
|
||||
const useAsDefaultProfileTitle = localize('enable for new windows', "Use this profile for new windows");
|
||||
this.useAsDefaultProfileCheckbox = this._register(new Checkbox(useAsDefaultProfileTitle, false, defaultCheckboxStyles));
|
||||
append(this.useAsDefaultProfileContainer, this.useAsDefaultProfileCheckbox.domNode);
|
||||
const useAsDefaultProfileLabel = append(this.useAsDefaultProfileContainer, $('.profile-use-as-default-label', undefined, useAsDefaultProfileTitle));
|
||||
|
@ -512,6 +568,12 @@ class ProfileWidget extends Disposable {
|
|||
}
|
||||
}));
|
||||
|
||||
this.contentsTreeHeader = append(body, $('.profile-content-tree-header'));
|
||||
append(this.contentsTreeHeader,
|
||||
$(''),
|
||||
$('.inherit-label', undefined, localize('default profile', "Use Default Profile")),
|
||||
$('.actions-label', undefined, localize('actions', "Actions")),
|
||||
);
|
||||
const delegate = new ProfileResourceTreeElementDelegate();
|
||||
this.resourcesTree = this._register(this.instantiationService.createInstance(WorkbenchAsyncDataTree<AbstractUserDataProfileElement, ProfileResourceTreeElement>,
|
||||
'ProfileEditor-ResourcesTree',
|
||||
|
@ -551,7 +613,7 @@ class ProfileWidget extends Disposable {
|
|||
expandOnlyOnTwistieClick: true,
|
||||
renderIndentGuides: RenderIndentGuides.None,
|
||||
enableStickyScroll: false,
|
||||
openOnSingleClick: false
|
||||
openOnSingleClick: false,
|
||||
}));
|
||||
this._register(this.resourcesTree.onDidOpen(async (e) => {
|
||||
if (!e.browserEvent) {
|
||||
|
@ -625,19 +687,7 @@ class ProfileWidget extends Disposable {
|
|||
}
|
||||
|
||||
private renderSelectBox(): void {
|
||||
const separator = { text: '\u2500\u2500\u2500\u2500\u2500\u2500', isDisabled: true };
|
||||
this.copyFromOptions.push({ text: localize('empty profile', "None") });
|
||||
if (this._templates.length) {
|
||||
this.copyFromOptions.push({ ...separator, decoratorRight: localize('from templates', "Profile Templates") });
|
||||
for (const template of this._templates) {
|
||||
this.copyFromOptions.push({ text: template.name, id: template.url, source: URI.parse(template.url) });
|
||||
}
|
||||
}
|
||||
this.copyFromOptions.push({ ...separator, decoratorRight: localize('from existing profiles', "Existing Profiles") });
|
||||
for (const profile of this.userDataProfilesService.profiles) {
|
||||
this.copyFromOptions.push({ text: profile.name, id: profile.id, source: profile });
|
||||
}
|
||||
this.copyFromSelectBox.setOptions(this.copyFromOptions);
|
||||
this.copyFromSelectBox.setOptions(this.getCopyFromOptions());
|
||||
this._register(this.copyFromSelectBox.onDidSelect(option => {
|
||||
if (this._profileElement.value?.element instanceof NewProfileElement) {
|
||||
this._profileElement.value.element.copyFrom = this.copyFromOptions[option.index].source;
|
||||
|
@ -662,7 +712,7 @@ class ProfileWidget extends Disposable {
|
|||
|
||||
this.resourcesTree.setInput(profileElement);
|
||||
disposables.add(profileElement.onDidChange(e => {
|
||||
if (e.flags || e.copyFrom || e.copyFlags) {
|
||||
if (e.flags || e.copyFrom || e.copyFlags || e.disabled) {
|
||||
const viewState = this.resourcesTree.getViewState();
|
||||
this.resourcesTree.setInput(profileElement, {
|
||||
...viewState,
|
||||
|
@ -671,49 +721,54 @@ class ProfileWidget extends Disposable {
|
|||
}
|
||||
}));
|
||||
|
||||
if (profileElement.primaryAction || profileElement.secondaryAction) {
|
||||
const [primaryTitleButtons, secondatyTitleButtons] = profileElement.titleButtons;
|
||||
if (primaryTitleButtons?.length || secondatyTitleButtons?.length) {
|
||||
this.buttonContainer.classList.remove('hide');
|
||||
|
||||
if (profileElement.primaryAction) {
|
||||
const button = disposables.add(new Button(this.buttonContainer, {
|
||||
...defaultButtonStyles
|
||||
}));
|
||||
button.label = profileElement.primaryAction.label;
|
||||
button.enabled = profileElement.primaryAction.enabled;
|
||||
disposables.add(button.onDidClick(() => this.editorProgressService.showWhile(profileElement.primaryAction!.run())));
|
||||
disposables.add(profileElement.primaryAction.onDidChange((e) => {
|
||||
if (!isUndefined(e.enabled)) {
|
||||
button.enabled = profileElement.primaryAction!.enabled;
|
||||
}
|
||||
}));
|
||||
disposables.add(profileElement.onDidChange(e => {
|
||||
if (e.message) {
|
||||
button.setTitle(profileElement.message ?? profileElement.primaryAction!.label);
|
||||
button.element.classList.toggle('error', !!profileElement.message);
|
||||
}
|
||||
}));
|
||||
if (primaryTitleButtons?.length) {
|
||||
for (const action of primaryTitleButtons) {
|
||||
const button = disposables.add(new Button(this.buttonContainer, {
|
||||
...defaultButtonStyles
|
||||
}));
|
||||
button.label = action.label;
|
||||
button.enabled = action.enabled;
|
||||
disposables.add(button.onDidClick(() => this.editorProgressService.showWhile(action.run())));
|
||||
disposables.add(action.onDidChange((e) => {
|
||||
if (!isUndefined(e.enabled)) {
|
||||
button.enabled = action.enabled;
|
||||
}
|
||||
}));
|
||||
disposables.add(profileElement.onDidChange(e => {
|
||||
if (e.message) {
|
||||
button.setTitle(profileElement.message ?? action.label);
|
||||
button.element.classList.toggle('error', !!profileElement.message);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if (profileElement.secondaryAction) {
|
||||
const button = disposables.add(new Button(this.buttonContainer, {
|
||||
...defaultButtonStyles,
|
||||
secondary: true
|
||||
}));
|
||||
button.label = profileElement.secondaryAction.label;
|
||||
button.enabled = profileElement.secondaryAction.enabled;
|
||||
disposables.add(button.onDidClick(() => this.editorProgressService.showWhile(profileElement.secondaryAction!.run())));
|
||||
disposables.add(profileElement.secondaryAction.onDidChange((e) => {
|
||||
if (!isUndefined(e.enabled)) {
|
||||
button.enabled = profileElement.secondaryAction!.enabled;
|
||||
}
|
||||
}));
|
||||
if (secondatyTitleButtons?.length) {
|
||||
for (const action of secondatyTitleButtons) {
|
||||
const button = disposables.add(new Button(this.buttonContainer, {
|
||||
...defaultButtonStyles,
|
||||
secondary: true
|
||||
}));
|
||||
button.label = action.label;
|
||||
button.enabled = action.enabled;
|
||||
disposables.add(button.onDidClick(() => this.editorProgressService.showWhile(action.run())));
|
||||
disposables.add(action.onDidChange((e) => {
|
||||
if (!isUndefined(e.enabled)) {
|
||||
button.enabled = action.enabled;
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
this.buttonContainer.classList.add('hide');
|
||||
}
|
||||
|
||||
this.toolbar.setActions(profileElement.titleActions[0].slice(0), profileElement.titleActions[1].slice(0));
|
||||
this.toolbar.setActions([], profileElement.titleActions[1].slice(0));
|
||||
|
||||
if (profileElement instanceof NewProfileElement) {
|
||||
this.nameInput.focus();
|
||||
|
@ -735,8 +790,10 @@ class ProfileWidget extends Disposable {
|
|||
this.iconElement.className = ThemeIcon.asClassName(ThemeIcon.fromId(DEFAULT_ICON.id));
|
||||
}
|
||||
if (profileElement instanceof NewProfileElement) {
|
||||
this.contentsTreeHeader.classList.add('hide');
|
||||
this.useAsDefaultProfileContainer.classList.add('hide');
|
||||
this.copyFromContainer.classList.remove('hide');
|
||||
this.copyFromOptions = this.getCopyFromOptions();
|
||||
const id = profileElement.copyFrom instanceof URI ? profileElement.copyFrom.toString() : profileElement.copyFrom?.id;
|
||||
const index = id
|
||||
? this.copyFromOptions.findIndex(option => option.id === id)
|
||||
|
@ -750,11 +807,29 @@ class ProfileWidget extends Disposable {
|
|||
this.copyFromSelectBox.setEnabled(false);
|
||||
}
|
||||
} else if (profileElement instanceof UserDataProfileElement) {
|
||||
this.contentsTreeHeader.classList.toggle('hide', profileElement.profile.isDefault);
|
||||
this.useAsDefaultProfileContainer.classList.remove('hide');
|
||||
this.useAsDefaultProfileCheckbox.checked = profileElement.isNewWindowProfile;
|
||||
this.copyFromContainer.classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
private getCopyFromOptions(): (ISelectOptionItem & { id?: string; source?: IUserDataProfile | URI })[] {
|
||||
const separator = { text: '\u2500\u2500\u2500\u2500\u2500\u2500', isDisabled: true };
|
||||
const copyFromOptions: (ISelectOptionItem & { id?: string; source?: IUserDataProfile | URI })[] = [];
|
||||
copyFromOptions.push({ text: localize('empty profile', "None") });
|
||||
if (this._templates.length) {
|
||||
copyFromOptions.push({ ...separator, decoratorRight: localize('from templates', "Profile Templates") });
|
||||
for (const template of this._templates) {
|
||||
copyFromOptions.push({ text: template.name, id: template.url, source: URI.parse(template.url) });
|
||||
}
|
||||
}
|
||||
copyFromOptions.push({ ...separator, decoratorRight: localize('from existing profiles', "Existing Profiles") });
|
||||
for (const profile of this.userDataProfilesService.profiles) {
|
||||
copyFromOptions.push({ text: profile.name, id: profile.id, source: profile });
|
||||
}
|
||||
return copyFromOptions;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -774,7 +849,7 @@ class ProfileResourceTreeElementDelegate implements IListVirtualDelegate<Profile
|
|||
return ExistingProfileResourceTreeRenderer.TEMPLATE_ID;
|
||||
}
|
||||
getHeight(element: ProfileResourceTreeElement) {
|
||||
return 30;
|
||||
return 22;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -793,13 +868,17 @@ class ProfileResourceTreeDataSource implements IAsyncDataSource<AbstractUserData
|
|||
return false;
|
||||
}
|
||||
if (element.root instanceof NewProfileElement) {
|
||||
if (element.root.getFlag((<IProfileResourceTypeElement>element.element).resourceType)) {
|
||||
const resourceType = (<IProfileResourceTypeElement>element.element).resourceType;
|
||||
if (element.root.getFlag(resourceType)) {
|
||||
return true;
|
||||
}
|
||||
if (!element.root.hasResource(resourceType)) {
|
||||
return false;
|
||||
}
|
||||
if (element.root.copyFrom === undefined) {
|
||||
return false;
|
||||
}
|
||||
if (!element.root.getCopyFlag((<IProfileResourceTypeElement>element.element).resourceType)) {
|
||||
if (!element.root.getCopyFlag(resourceType)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -829,6 +908,7 @@ class ProfileResourceTreeDataSource implements IAsyncDataSource<AbstractUserData
|
|||
interface IProfileResourceTemplateData {
|
||||
readonly disposables: DisposableStore;
|
||||
readonly elementDisposables: DisposableStore;
|
||||
readonly actionBar: WorkbenchToolBar;
|
||||
}
|
||||
|
||||
interface IExistingProfileResourceTemplateData extends IProfileResourceTemplateData {
|
||||
|
@ -882,6 +962,12 @@ class ExistingProfileResourceTreeRenderer extends AbstractProfileResourceTreeRen
|
|||
|
||||
readonly templateId = ExistingProfileResourceTreeRenderer.TEMPLATE_ID;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
renderTemplate(parent: HTMLElement): IExistingProfileResourceTemplateData {
|
||||
const disposables = new DisposableStore();
|
||||
const container = append(parent, $('.profile-tree-item-container.existing-profile-resource-type-container'));
|
||||
|
@ -890,8 +976,17 @@ class ExistingProfileResourceTreeRenderer extends AbstractProfileResourceTreeRen
|
|||
const inheritContainer = append(container, $('.inherit-container'));
|
||||
const checkbox = disposables.add(new Checkbox('', false, defaultCheckboxStyles));
|
||||
append(inheritContainer, checkbox.domNode);
|
||||
append(inheritContainer, $('.inherit-label', undefined, localize('default profile', "Use Default Profile")));
|
||||
return { checkbox, label, inheritContainer, disposables, elementDisposables: disposables.add(new DisposableStore()) };
|
||||
|
||||
const actionsContainer = append(container, $('.profile-tree-item-actions-container'));
|
||||
const actionBar = disposables.add(this.instantiationService.createInstance(WorkbenchToolBar,
|
||||
actionsContainer,
|
||||
{
|
||||
hoverDelegate: disposables.add(createInstantHoverDelegate()),
|
||||
highlightToggledItems: true
|
||||
}
|
||||
));
|
||||
|
||||
return { checkbox, label, inheritContainer, actionBar, disposables, elementDisposables: disposables.add(new DisposableStore()) };
|
||||
}
|
||||
|
||||
renderElement({ element: profileResourceTreeElement }: ITreeNode<ProfileResourceTreeElement, void>, index: number, templateData: IExistingProfileResourceTemplateData, height: number | undefined): void {
|
||||
|
@ -906,12 +1001,14 @@ class ExistingProfileResourceTreeRenderer extends AbstractProfileResourceTreeRen
|
|||
|
||||
templateData.label.textContent = this.getResourceTypeTitle(element.resourceType);
|
||||
if (root instanceof UserDataProfileElement && root.profile.isDefault) {
|
||||
templateData.inheritContainer.classList.add('hide');
|
||||
templateData.checkbox.domNode.classList.add('hide');
|
||||
} else {
|
||||
templateData.inheritContainer.classList.remove('hide');
|
||||
templateData.checkbox.domNode.classList.remove('hide');
|
||||
templateData.checkbox.checked = root.getFlag(element.resourceType);
|
||||
templateData.elementDisposables.add(templateData.checkbox.onChange(() => root.setFlag(element.resourceType, templateData.checkbox.checked)));
|
||||
}
|
||||
|
||||
templateData.actionBar.setActions(element.action ? [element.action] : []);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -946,7 +1043,16 @@ class NewProfileResourceTreeRenderer extends AbstractProfileResourceTreeRenderer
|
|||
const selectContainer = append(container, $('.profile-select-container'));
|
||||
selectBox.render(selectContainer);
|
||||
|
||||
return { label, selectContainer, selectBox, disposables, elementDisposables: disposables.add(new DisposableStore()) };
|
||||
const actionsContainer = append(container, $('.profile-tree-item-actions-container'));
|
||||
const actionBar = disposables.add(this.instantiationService.createInstance(WorkbenchToolBar,
|
||||
actionsContainer,
|
||||
{
|
||||
hoverDelegate: disposables.add(createInstantHoverDelegate()),
|
||||
highlightToggledItems: true
|
||||
}
|
||||
));
|
||||
|
||||
return { label, selectContainer, selectBox, actionBar, disposables, elementDisposables: disposables.add(new DisposableStore()) };
|
||||
}
|
||||
|
||||
renderElement({ element: profileResourceTreeElement }: ITreeNode<ProfileResourceTreeElement, void>, index: number, templateData: INewProfileResourceTemplateData, height: number | undefined): void {
|
||||
|
@ -959,10 +1065,11 @@ class NewProfileResourceTreeRenderer extends AbstractProfileResourceTreeRenderer
|
|||
throw new Error('Invalid profile resource element');
|
||||
}
|
||||
templateData.label.textContent = this.getResourceTypeTitle(element.resourceType);
|
||||
if (root.copyFrom) {
|
||||
if (root.copyFrom && root.hasResource(element.resourceType)) {
|
||||
const copyFromName = root.getCopyFromName();
|
||||
templateData.selectBox.setOptions([
|
||||
{ text: localize('empty', "Empty") },
|
||||
{ text: localize('copy', "Copy") },
|
||||
{ text: copyFromName ? localize('copy from', "Copy ({0})", copyFromName) : localize('copy', "Copy") },
|
||||
{ text: localize('default', "Use Default Profile") }
|
||||
]);
|
||||
templateData.selectBox.select(root.getCopyFlag(element.resourceType) ? 1 : root.getFlag(element.resourceType) ? 2 : 0);
|
||||
|
@ -981,6 +1088,7 @@ class NewProfileResourceTreeRenderer extends AbstractProfileResourceTreeRenderer
|
|||
}));
|
||||
}
|
||||
templateData.selectBox.setEnabled(!root.disabled);
|
||||
templateData.actionBar.setActions(element.action ? [element.action] : []);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -993,7 +1101,7 @@ class ProfileResourceChildTreeItemRenderer extends AbstractProfileResourceTreeRe
|
|||
private readonly hoverDelegate: IHoverDelegate;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
) {
|
||||
super();
|
||||
this.labels = instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER);
|
||||
|
@ -1006,7 +1114,17 @@ class ProfileResourceChildTreeItemRenderer extends AbstractProfileResourceTreeRe
|
|||
const checkbox = disposables.add(new Checkbox('', false, defaultCheckboxStyles));
|
||||
append(container, checkbox.domNode);
|
||||
const resourceLabel = disposables.add(this.labels.create(container, { hoverDelegate: this.hoverDelegate }));
|
||||
return { checkbox, resourceLabel, disposables, elementDisposables: disposables.add(new DisposableStore()) };
|
||||
|
||||
const actionsContainer = append(container, $('.profile-tree-item-actions-container'));
|
||||
const actionBar = disposables.add(this.instantiationService.createInstance(WorkbenchToolBar,
|
||||
actionsContainer,
|
||||
{
|
||||
hoverDelegate: disposables.add(createInstantHoverDelegate()),
|
||||
highlightToggledItems: true
|
||||
}
|
||||
));
|
||||
|
||||
return { checkbox, resourceLabel, actionBar, disposables, elementDisposables: disposables.add(new DisposableStore()) };
|
||||
}
|
||||
|
||||
renderElement({ element: profileResourceTreeElement }: ITreeNode<ProfileResourceTreeElement, void>, index: number, templateData: IProfileResourceChildTreeItemTemplateData, height: number | undefined): void {
|
||||
|
@ -1038,6 +1156,7 @@ class ProfileResourceChildTreeItemRenderer extends AbstractProfileResourceTreeRe
|
|||
icon: element.icon,
|
||||
hideIcon: !element.resource && !element.icon,
|
||||
});
|
||||
templateData.actionBar.setActions(element.action ? [element.action] : []);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
|||
import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { CancelablePromise, createCancelablePromise, RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { ITreeItemCheckboxState } from 'vs/workbench/common/views';
|
||||
|
@ -197,17 +197,22 @@ export abstract class AbstractUserDataProfileElement extends Disposable {
|
|||
ProfileResourceType.Snippets,
|
||||
ProfileResourceType.Extensions
|
||||
];
|
||||
return resourceTypes.map<IProfileResourceTypeElement>(resourceType => ({
|
||||
handle: resourceType,
|
||||
checkbox: undefined,
|
||||
resourceType,
|
||||
action: resourceType === ProfileResourceType.Settings
|
||||
|| resourceType === ProfileResourceType.Keybindings
|
||||
|| resourceType === ProfileResourceType.Tasks
|
||||
? new Action('_open', '', undefined, true, async () => {
|
||||
const children = await this.getChildren(resourceType);
|
||||
children[0]?.action?.run();
|
||||
}) : undefined
|
||||
return Promise.all(resourceTypes.map<Promise<IProfileResourceTypeElement>>(async r => {
|
||||
const children = (r === ProfileResourceType.Settings
|
||||
|| r === ProfileResourceType.Keybindings
|
||||
|| r === ProfileResourceType.Tasks) ? await this.getChildrenForResourceType(r) : [];
|
||||
return {
|
||||
handle: r,
|
||||
checkbox: undefined,
|
||||
resourceType: r,
|
||||
action: children.length
|
||||
? new Action('_open',
|
||||
localize('open', "Open to the Side"),
|
||||
ThemeIcon.asClassName(Codicon.goToFile),
|
||||
true,
|
||||
() => children[0]?.action?.run())
|
||||
: undefined
|
||||
};
|
||||
}));
|
||||
}
|
||||
return this.getChildrenForResourceType(resourceType);
|
||||
|
@ -247,7 +252,7 @@ export abstract class AbstractUserDataProfileElement extends Disposable {
|
|||
label: child.label?.label ?? '',
|
||||
resource: URI.revive(child.resourceUri),
|
||||
icon: child.themeIcon,
|
||||
action: new Action('_openChild', '', undefined, true, async () => {
|
||||
action: new Action('_openChild', localize('open', "Open to the Side"), ThemeIcon.asClassName(Codicon.goToFile), true, async () => {
|
||||
if (child.parent.type === ProfileResourceType.Extensions) {
|
||||
await this.commandService.executeCommand('extension.open', child.handle, undefined, true, undefined, true);
|
||||
} else if (child.resourceUri) {
|
||||
|
@ -298,8 +303,7 @@ export abstract class AbstractUserDataProfileElement extends Disposable {
|
|||
});
|
||||
}
|
||||
|
||||
abstract readonly primaryAction?: Action;
|
||||
abstract readonly secondaryAction?: Action;
|
||||
abstract readonly titleButtons: [Action[], Action[]];
|
||||
abstract readonly titleActions: [IAction[], IAction[]];
|
||||
abstract readonly contextMenuActions: IAction[];
|
||||
|
||||
|
@ -310,11 +314,9 @@ export class UserDataProfileElement extends AbstractUserDataProfileElement {
|
|||
|
||||
get profile(): IUserDataProfile { return this._profile; }
|
||||
|
||||
readonly primaryAction = undefined;
|
||||
readonly secondaryAction = undefined;
|
||||
|
||||
constructor(
|
||||
private _profile: IUserDataProfile,
|
||||
readonly titleButtons: [Action[], Action[]],
|
||||
readonly titleActions: [IAction[], IAction[]],
|
||||
readonly contextMenuActions: IAction[],
|
||||
@IUserDataProfileService private readonly userDataProfileService: IUserDataProfileService,
|
||||
|
@ -388,11 +390,13 @@ const USER_DATA_PROFILE_TEMPLATE_PREVIEW_SCHEME = 'userdataprofiletemplateprevie
|
|||
|
||||
export class NewProfileElement extends AbstractUserDataProfileElement {
|
||||
|
||||
private templatePromise: CancelablePromise<void> | undefined;
|
||||
private template: IUserDataProfileTemplate | null = null;
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
copyFrom: URI | IUserDataProfile | undefined,
|
||||
readonly primaryAction: Action,
|
||||
readonly secondaryAction: Action,
|
||||
readonly titleButtons: [Action[], Action[]],
|
||||
readonly titleActions: [IAction[], IAction[]],
|
||||
readonly contextMenuActions: Action[],
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
|
@ -414,6 +418,7 @@ export class NewProfileElement extends AbstractUserDataProfileElement {
|
|||
);
|
||||
this._copyFrom = copyFrom;
|
||||
this._copyFlags = this.getCopyFlagsFrom(copyFrom);
|
||||
this.initialize();
|
||||
this._register(this.fileService.registerProvider(USER_DATA_PROFILE_TEMPLATE_PREVIEW_SCHEME, this._register(new InMemoryFileSystemProvider())));
|
||||
}
|
||||
|
||||
|
@ -425,6 +430,11 @@ export class NewProfileElement extends AbstractUserDataProfileElement {
|
|||
this._onDidChange.fire({ copyFrom: true });
|
||||
this.flags = undefined;
|
||||
this.copyFlags = this.getCopyFlagsFrom(copyFrom);
|
||||
if (copyFrom instanceof URI) {
|
||||
this.templatePromise?.cancel();
|
||||
this.templatePromise = undefined;
|
||||
}
|
||||
this.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -456,6 +466,76 @@ export class NewProfileElement extends AbstractUserDataProfileElement {
|
|||
} : undefined;
|
||||
}
|
||||
|
||||
private async initialize(): Promise<void> {
|
||||
this.disabled = true;
|
||||
try {
|
||||
if (this.copyFrom instanceof URI) {
|
||||
await this.resolveTemplate(this.copyFrom);
|
||||
if (this.template) {
|
||||
this.name = this.template.name ?? '';
|
||||
this.icon = this.template.icon;
|
||||
this.setCopyFlag(ProfileResourceType.Settings, !!this.template.settings);
|
||||
this.setCopyFlag(ProfileResourceType.Keybindings, !!this.template.keybindings);
|
||||
this.setCopyFlag(ProfileResourceType.Tasks, !!this.template.tasks);
|
||||
this.setCopyFlag(ProfileResourceType.Snippets, !!this.template.snippets);
|
||||
this.setCopyFlag(ProfileResourceType.Extensions, !!this.template.extensions);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isUserDataProfile(this.copyFrom)) {
|
||||
this.name = `${this.copyFrom.name} (Copy)`;
|
||||
this.icon = this.copyFrom.icon;
|
||||
this.setCopyFlag(ProfileResourceType.Settings, true);
|
||||
this.setCopyFlag(ProfileResourceType.Keybindings, true);
|
||||
this.setCopyFlag(ProfileResourceType.Tasks, true);
|
||||
this.setCopyFlag(ProfileResourceType.Snippets, true);
|
||||
this.setCopyFlag(ProfileResourceType.Extensions, true);
|
||||
return;
|
||||
}
|
||||
|
||||
this.name = localize('untitled', "Untitled");
|
||||
this.icon = undefined;
|
||||
this.setCopyFlag(ProfileResourceType.Settings, false);
|
||||
this.setCopyFlag(ProfileResourceType.Keybindings, false);
|
||||
this.setCopyFlag(ProfileResourceType.Tasks, false);
|
||||
this.setCopyFlag(ProfileResourceType.Snippets, false);
|
||||
this.setCopyFlag(ProfileResourceType.Extensions, false);
|
||||
} finally {
|
||||
this.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async resolveTemplate(uri: URI): Promise<void> {
|
||||
if (!this.templatePromise) {
|
||||
this.templatePromise = createCancelablePromise(async token => {
|
||||
const template = await this.userDataProfileImportExportService.resolveProfileTemplate(uri);
|
||||
if (!token.isCancellationRequested) {
|
||||
this.template = template;
|
||||
}
|
||||
});
|
||||
}
|
||||
return this.templatePromise;
|
||||
}
|
||||
|
||||
hasResource(resourceType: ProfileResourceType): boolean {
|
||||
if (this.template) {
|
||||
switch (resourceType) {
|
||||
case ProfileResourceType.Settings:
|
||||
return !!this.template.settings;
|
||||
case ProfileResourceType.Keybindings:
|
||||
return !!this.template.keybindings;
|
||||
case ProfileResourceType.Snippets:
|
||||
return !!this.template.snippets;
|
||||
case ProfileResourceType.Tasks:
|
||||
return !!this.template.tasks;
|
||||
case ProfileResourceType.Extensions:
|
||||
return !!this.template.extensions;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
getCopyFlag(key: ProfileResourceType): boolean {
|
||||
return this.copyFlags?.[key] ?? false;
|
||||
}
|
||||
|
@ -466,6 +546,16 @@ export class NewProfileElement extends AbstractUserDataProfileElement {
|
|||
this.copyFlags = flags;
|
||||
}
|
||||
|
||||
getCopyFromName(): string | undefined {
|
||||
if (isUserDataProfile(this.copyFrom)) {
|
||||
return this.copyFrom.name;
|
||||
}
|
||||
if (this.template) {
|
||||
return this.template.name;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected override async getChildrenForResourceType(resourceType: ProfileResourceType): Promise<IProfileChildElement[]> {
|
||||
if (this.getFlag(resourceType)) {
|
||||
return this.getChildrenFromProfile(this.userDataProfilesService.defaultProfile, resourceType);
|
||||
|
@ -474,11 +564,11 @@ export class NewProfileElement extends AbstractUserDataProfileElement {
|
|||
return [];
|
||||
}
|
||||
if (this.copyFrom instanceof URI) {
|
||||
const template = await this.userDataProfileImportExportService.resolveProfileTemplate(this.copyFrom);
|
||||
if (!template) {
|
||||
await this.resolveTemplate(this.copyFrom);
|
||||
if (!this.template) {
|
||||
return [];
|
||||
}
|
||||
return this.getChildrenFromProfileTemplate(template, resourceType);
|
||||
return this.getChildrenFromProfileTemplate(this.template, resourceType);
|
||||
}
|
||||
if (this.copyFrom) {
|
||||
return this.getChildrenFromProfile(this.copyFrom, resourceType);
|
||||
|
@ -614,54 +704,92 @@ export class UserDataProfilesEditorModel extends EditorModel {
|
|||
private createProfileElement(profile: IUserDataProfile): [UserDataProfileElement, DisposableStore] {
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
const activateAction = disposables.add(new Action('userDataProfile.activate', localize('active', "Active"), ThemeIcon.asClassName(Codicon.check), true, () => this.userDataProfileManagementService.switchProfile(profile)));
|
||||
activateAction.checked = this.userDataProfileService.currentProfile.id === profile.id;
|
||||
disposables.add(this.userDataProfileService.onDidChangeCurrentProfile(() => activateAction.checked = this.userDataProfileService.currentProfile.id === profile.id));
|
||||
const copyFromProfileAction = disposables.add(new Action('userDataProfile.copyFromProfile', localize('copyFromProfile', "Save As..."), ThemeIcon.asClassName(Codicon.copy), true, () => this.createNewProfile(profile)));
|
||||
const exportAction = disposables.add(new Action('userDataProfile.export', localize('export', "Export..."), ThemeIcon.asClassName(Codicon.export), true, () => this.exportProfile(profile)));
|
||||
const deleteAction = disposables.add(new Action('userDataProfile.delete', localize('delete', "Delete"), ThemeIcon.asClassName(Codicon.trash), true, () => this.removeProfile(profile)));
|
||||
const newWindowAction = disposables.add(new Action('userDataProfile.newWindow', localize('new window', "New {0} Window", profile.name), ThemeIcon.asClassName(Codicon.emptyWindow), true, () => this.openWindow(profile)));
|
||||
const useAsNewWindowProfileAction = disposables.add(new Action('userDataProfile.useAsNewWindowProfile', localize('use as new window', "Enable for New Windows", profile.name), undefined, true, () => profileElement.toggleNewWindowProfile()));
|
||||
const activateAction = disposables.add(new Action(
|
||||
'userDataProfile.activate',
|
||||
localize('active', "Use for Current Window"),
|
||||
ThemeIcon.asClassName(Codicon.check),
|
||||
true,
|
||||
() => this.userDataProfileManagementService.switchProfile(profile)
|
||||
));
|
||||
|
||||
const copyFromProfileAction = disposables.add(new Action(
|
||||
'userDataProfile.copyFromProfile',
|
||||
localize('copyFromProfile', "Duplicate..."),
|
||||
ThemeIcon.asClassName(Codicon.copy),
|
||||
true, () => this.createNewProfile(profile)
|
||||
));
|
||||
|
||||
const exportAction = disposables.add(new Action(
|
||||
'userDataProfile.export',
|
||||
localize('export', "Export..."),
|
||||
ThemeIcon.asClassName(Codicon.export),
|
||||
true,
|
||||
() => this.exportProfile(profile)
|
||||
));
|
||||
|
||||
const deleteAction = disposables.add(new Action(
|
||||
'userDataProfile.delete',
|
||||
localize('delete', "Delete"),
|
||||
ThemeIcon.asClassName(Codicon.trash),
|
||||
true,
|
||||
() => this.removeProfile(profile)
|
||||
));
|
||||
|
||||
const newWindowAction = disposables.add(new Action(
|
||||
'userDataProfile.newWindow',
|
||||
localize('open new window', "Open"),
|
||||
ThemeIcon.asClassName(Codicon.emptyWindow),
|
||||
true,
|
||||
() => this.openWindow(profile)
|
||||
));
|
||||
|
||||
const useAsNewWindowProfileAction = disposables.add(new Action(
|
||||
'userDataProfile.useAsNewWindowProfile',
|
||||
localize('use as new window', "Use for New Windows", profile.name),
|
||||
undefined,
|
||||
true,
|
||||
() => profileElement.toggleNewWindowProfile()
|
||||
));
|
||||
|
||||
const titlePrimaryActions: IAction[] = [];
|
||||
titlePrimaryActions.push(copyFromProfileAction);
|
||||
titlePrimaryActions.push(exportAction);
|
||||
if (!profile.isDefault) {
|
||||
titlePrimaryActions.push(deleteAction);
|
||||
}
|
||||
|
||||
titlePrimaryActions.push(newWindowAction);
|
||||
const titleSecondaryActions: IAction[] = [];
|
||||
titleSecondaryActions.push(copyFromProfileAction);
|
||||
titleSecondaryActions.push(exportAction);
|
||||
if (!profile.isDefault) {
|
||||
titleSecondaryActions.push(new Separator());
|
||||
titleSecondaryActions.push(deleteAction);
|
||||
}
|
||||
|
||||
const secondaryActions: IAction[] = [];
|
||||
secondaryActions.push(activateAction);
|
||||
secondaryActions.push(useAsNewWindowProfileAction);
|
||||
secondaryActions.push(new Separator());
|
||||
secondaryActions.push(newWindowAction);
|
||||
secondaryActions.push(new Separator());
|
||||
secondaryActions.push(copyFromProfileAction);
|
||||
secondaryActions.push(exportAction);
|
||||
if (!profile.isDefault) {
|
||||
secondaryActions.push(new Separator());
|
||||
secondaryActions.push(deleteAction);
|
||||
}
|
||||
|
||||
const profileElement = disposables.add(this.instantiationService.createInstance(UserDataProfileElement,
|
||||
profile,
|
||||
[[newWindowAction], []],
|
||||
[titlePrimaryActions, titleSecondaryActions],
|
||||
secondaryActions,
|
||||
));
|
||||
|
||||
useAsNewWindowProfileAction.checked = profileElement.isNewWindowProfile;
|
||||
useAsNewWindowProfileAction.label = profileElement.isNewWindowProfile ? localize('donot use as new window', "Disable for New Windows") : localize('use as new window', "Enable for New Windows");
|
||||
activateAction.checked = this.userDataProfileService.currentProfile.id === profile.id;
|
||||
disposables.add(this.userDataProfileService.onDidChangeCurrentProfile(() =>
|
||||
activateAction.checked = this.userDataProfileService.currentProfile.id === profile.id));
|
||||
|
||||
useAsNewWindowProfileAction.checked = profileElement.isNewWindowProfile;
|
||||
disposables.add(profileElement.onDidChange(e => {
|
||||
if (e.name) {
|
||||
newWindowAction.label = localize('new window', "New {0} Window", profileElement.name);
|
||||
}
|
||||
if (e.newWindowProfile) {
|
||||
useAsNewWindowProfileAction.checked = profileElement.isNewWindowProfile;
|
||||
useAsNewWindowProfileAction.label = profileElement.isNewWindowProfile ? localize('donot use as new window', "Disable for New Windows") : localize('use as new window', "Enable for New Windows");
|
||||
}
|
||||
}));
|
||||
|
||||
return [profileElement, disposables];
|
||||
}
|
||||
|
||||
|
@ -686,7 +814,7 @@ export class UserDataProfilesEditorModel extends EditorModel {
|
|||
));
|
||||
const previewProfileAction = disposables.add(new Action(
|
||||
'userDataProfile.preview',
|
||||
localize('preview', "Open Preview"),
|
||||
localize('preview', "Preview"),
|
||||
ThemeIcon.asClassName(Codicon.openPreview),
|
||||
true,
|
||||
() => this.previewNewProfile(cancellationTokenSource.token)
|
||||
|
@ -694,11 +822,8 @@ export class UserDataProfilesEditorModel extends EditorModel {
|
|||
this.newProfileElement = disposables.add(this.instantiationService.createInstance(NewProfileElement,
|
||||
localize('untitled', "Untitled"),
|
||||
copyFrom,
|
||||
createAction,
|
||||
cancelAction,
|
||||
[[
|
||||
previewProfileAction
|
||||
], []],
|
||||
[[createAction], [previewProfileAction, cancelAction]],
|
||||
[[cancelAction], []],
|
||||
[],
|
||||
));
|
||||
disposables.add(this.newProfileElement.onDidChange(e => {
|
||||
|
|
|
@ -53,6 +53,8 @@ export interface IUserDataProfileManagementService {
|
|||
}
|
||||
|
||||
export interface IUserDataProfileTemplate {
|
||||
readonly name: string;
|
||||
readonly icon?: string;
|
||||
readonly settings?: string;
|
||||
readonly keybindings?: string;
|
||||
readonly tasks?: string;
|
||||
|
|
Loading…
Reference in a new issue