More feedback (#187934)

* #156144 More feedback

* 💄

* add telemetry
This commit is contained in:
Sandeep Somavarapu
2023-07-14 17:50:20 +02:00
committed by GitHub
parent c780d0dfef
commit 6bff31c75f
5 changed files with 204 additions and 227 deletions
@@ -1326,7 +1326,6 @@ export class QuickInputController extends Disposable {
rightActionBar.domNode.classList.add('quick-input-right-action-bar');
const headerContainer = dom.append(container, $('.quick-input-header'));
const description1 = dom.append(container, $('.quick-input-description'));
const checkAll = <HTMLInputElement>dom.append(headerContainer, $('input.quick-input-check-all'));
checkAll.type = 'checkbox';
@@ -1379,6 +1378,8 @@ export class QuickInputController extends Disposable {
const widget = dom.append(container, $('.quick-input-html-widget'));
widget.tabIndex = -1;
const description1 = dom.append(container, $('.quick-input-description'));
const listId = this.idPrefix + 'list';
const list = this._register(new QuickInputList(container, listId, this.options));
inputBox.setAttribute('aria-controls', listId);
@@ -0,0 +1,28 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.profile-type-widget {
display: flex;
margin: 0px 6px 8px 11px;
align-items: center;
justify-content: space-between;
font-size: 12px;
}
.profile-type-widget>.profile-type-select-container {
overflow: hidden;
padding-left: 10px;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
.profile-type-widget>.profile-type-select-container>.monaco-select-box {
cursor: pointer;
line-height: 17px;
padding: 2px 23px 2px 8px;
border-radius: 2px;
}
@@ -3,20 +3,19 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/userDataProfileCreateWidget';
import { Disposable, DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { isWeb } from 'vs/base/common/platform';
import { Event } from 'vs/base/common/event';
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { localize } from 'vs/nls';
import { Action2, IMenuService, ISubmenuItem, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IUserDataProfile, IUserDataProfilesService, ProfileResourceType, UseDefaultProfileFlags } from 'vs/platform/userDataProfile/common/userDataProfile';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { RenameProfileAction } from 'vs/workbench/contrib/userDataProfile/browser/userDataProfileActions';
import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { CURRENT_PROFILE_CONTEXT, HAS_PROFILES_CONTEXT, IS_CURRENT_PROFILE_TRANSIENT_CONTEXT, IS_PROFILE_IMPORT_IN_PROGRESS_CONTEXT, IUserDataProfileImportExportService, IUserDataProfileManagementService, IUserDataProfileService, PROFILES_CATEGORY, PROFILE_FILTER, IS_PROFILE_EXPORT_IN_PROGRESS_CONTEXT, ProfilesMenu, PROFILES_ENABLEMENT_CONTEXT, PROFILES_TITLE } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
import { IQuickInputService, IQuickPickItem, QuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { URI } from 'vs/base/common/uri';
@@ -31,32 +30,18 @@ import { IRequestService, asJson } from 'vs/platform/request/common/request';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ILogService } from 'vs/platform/log/common/log';
import Severity from 'vs/base/common/severity';
const CREATE_EMPTY_PROFILE_ACTION_ID = 'workbench.profiles.actions.createEmptyProfile';
const CREATE_EMPTY_PROFILE_ACTION_TITLE = {
value: localize('create empty profile', "Create an Empty Profile..."),
original: 'Create an Empty Profile...'
};
const CREATE_FROM_CURRENT_PROFILE_ACTION_ID = 'workbench.profiles.actions.createFromCurrentProfile';
const CREATE_FROM_CURRENT_PROFILE_ACTION_TITLE = {
value: localize('save profile as', "Save Current Profile As..."),
original: 'Save Current Profile As...'
};
const CREATE_NEW_PROFILE_ACTION_ID = 'workbench.profiles.actions.createNewProfile';
const CREATE_NEW_PROFILE_ACTION_TITLE = {
value: localize('create new profile', "Create New Profile..."),
original: 'Create New Profile...'
};
import { $, append } from 'vs/base/browser/dom';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ISelectOptionItem, SelectBox } from 'vs/base/browser/ui/selectBox/selectBox';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { defaultSelectBoxStyles } from 'vs/platform/theme/browser/defaultStyles';
import { isString } from 'vs/base/common/types';
interface IProfileTemplateInfo {
readonly name: string;
readonly url: string;
}
type IProfileTemplateQuickPickItem = IQuickPickItem & IProfileTemplateInfo;
export class UserDataProfilesWorkbenchContribution extends Disposable implements IWorkbenchContribution {
private readonly currentProfileContext: IContextKey<string>;
@@ -77,6 +62,8 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
@ILifecycleService private readonly lifecycleService: ILifecycleService,
@IProductService private readonly productService: IProductService,
@IRequestService private readonly requestService: IRequestService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IContextViewService private readonly contextViewService: IContextViewService,
@ILogService private readonly logService: ILogService,
) {
super();
@@ -115,9 +102,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
this.registerCurrentProfilesActions();
this._register(Event.any(this.userDataProfileService.onDidChangeCurrentProfile, this.userDataProfileService.onDidUpdateCurrentProfile)(() => this.registerCurrentProfilesActions()));
this.registerCreateEmptyProfileAction();
this.registerCreateFromCurrentProfileAction();
this.registerCreateNewProfileAction();
this.registerCreateProfileAction();
this.registerDeleteProfileAction();
@@ -214,21 +199,21 @@ 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.registerRenameCurrentProfileAction());
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 registerRenameCurrentProfileAction(): IDisposable {
private registerEditCurrentProfileAction(): IDisposable {
const that = this;
return registerAction2(class RenameCurrentProfileAction extends Action2 {
constructor() {
super({
id: `workbench.profiles.actions.renameCurrentProfile`,
id: `workbench.profiles.actions.editCurrentProfile`,
title: {
value: localize('rename profile', "Rename..."),
original: `Rename...`
value: localize('edit profile', "Edit..."),
original: `Edit...`
},
menu: [
{
@@ -240,8 +225,8 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
]
});
}
async run(accessor: ServicesAccessor) {
accessor.get(ICommandService).executeCommand(RenameProfileAction.ID, that.userDataProfileService.currentProfile);
run() {
return that.saveProfile(that.userDataProfileService.currentProfile);
}
});
}
@@ -413,8 +398,11 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
this._register(registerAction2(class CreateFromCurrentProfileAction extends Action2 {
constructor() {
super({
id: CREATE_FROM_CURRENT_PROFILE_ACTION_ID,
title: CREATE_FROM_CURRENT_PROFILE_ACTION_TITLE,
id: 'workbench.profiles.actions.createFromCurrentProfile',
title: {
value: localize('save profile as', "Save Current Profile As..."),
original: 'Save Current Profile As...'
},
category: PROFILES_CATEGORY,
f1: true,
precondition: PROFILES_ENABLEMENT_CONTEXT
@@ -422,86 +410,35 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
}
run(accessor: ServicesAccessor) {
return that.createFromCurrentProfile();
return that.saveProfile(undefined, that.userDataProfileService.currentProfile);
}
}));
}
private registerCreateNewProfileAction(): void {
const that = this;
this._register(registerAction2(class CreateFromCurrentProfileAction extends Action2 {
constructor() {
super({
id: CREATE_NEW_PROFILE_ACTION_ID,
title: CREATE_NEW_PROFILE_ACTION_TITLE,
category: PROFILES_CATEGORY,
f1: true,
precondition: PROFILES_ENABLEMENT_CONTEXT
});
}
private async saveProfile(profile: IUserDataProfile): Promise<void>;
private async saveProfile(profile?: IUserDataProfile, source?: IUserDataProfile | string): Promise<void>;
private async saveProfile(profile?: IUserDataProfile, source?: IUserDataProfile | string): Promise<void> {
run() {
return that.createNewProfile();
}
}));
}
type CreateProfileInfoClassification = {
owner: 'sandy081';
comment: 'Report when profile is about to be created';
};
this.telemetryService.publicLog2<{}, CreateProfileInfoClassification>('userDataProfile.startCreate');
private registerCreateEmptyProfileAction(): void {
const that = this;
this._register(registerAction2(class CreateEmptyProfileAction extends Action2 {
constructor() {
super({
id: CREATE_EMPTY_PROFILE_ACTION_ID,
title: CREATE_EMPTY_PROFILE_ACTION_TITLE,
category: PROFILES_CATEGORY,
f1: true,
precondition: PROFILES_ENABLEMENT_CONTEXT
});
}
const disposables = new DisposableStore();
const title = profile ? localize('save profile', "Edit Profile...") : localize('create new profle', "Create New Profile...");
run(accessor: ServicesAccessor) {
return that.createEmptyProfile();
}
}));
}
private async createEmptyProfile(): Promise<void> {
const name = await this.getNameForProfile(localize('create empty profile', "Create an Empty Profile..."));
if (!name) {
return;
}
try {
await this.userDataProfileManagementService.createAndEnterProfile(name, undefined);
} catch (error) {
this.notificationService.error(error);
}
}
private async createFromCurrentProfile(): Promise<void> {
const name = await this.getNameForProfile(localize('create from current profle', "Create from Current Profile..."));
if (!name) {
return;
}
try {
await this.userDataProfileImportExportService.SaveCurrentProfileAs(name);
} catch (error) {
this.notificationService.error(error);
}
}
private async createNewProfile(): Promise<void> {
const title = localize('create new profle', "Create New Profile...");
const settings: IQuickPickItem = { id: ProfileResourceType.Settings, label: localize('settings', "Settings"), picked: true };
const keybindings: IQuickPickItem = { id: ProfileResourceType.Keybindings, label: localize('keybindings', "Keyboard Shortcuts"), picked: true };
const snippets: IQuickPickItem = { id: ProfileResourceType.Snippets, label: localize('snippets', "User Snippets"), picked: true };
const tasks: IQuickPickItem = { id: ProfileResourceType.Tasks, label: localize('tasks', "User Tasks"), picked: true };
const extensions: IQuickPickItem = { id: ProfileResourceType.Extensions, label: localize('extensions', "Extensions"), picked: true };
const settings: IQuickPickItem & { id: ProfileResourceType } = { id: ProfileResourceType.Settings, label: localize('settings', "Settings"), picked: profile?.useDefaultFlags?.settings };
const keybindings: IQuickPickItem & { id: ProfileResourceType } = { id: ProfileResourceType.Keybindings, label: localize('keybindings', "Keyboard Shortcuts"), picked: profile?.useDefaultFlags?.keybindings };
const snippets: IQuickPickItem & { id: ProfileResourceType } = { id: ProfileResourceType.Snippets, label: localize('snippets', "User Snippets"), picked: profile?.useDefaultFlags?.snippets };
const tasks: IQuickPickItem & { id: ProfileResourceType } = { id: ProfileResourceType.Tasks, label: localize('tasks', "User Tasks"), picked: profile?.useDefaultFlags?.tasks };
const extensions: IQuickPickItem & { id: ProfileResourceType } = { id: ProfileResourceType.Extensions, label: localize('extensions', "Extensions"), picked: profile?.useDefaultFlags?.extensions };
const resources = [settings, keybindings, snippets, tasks, extensions];
const quickPick = this.quickInputService.createQuickPick();
quickPick.title = title;
quickPick.placeholder = localize('name placeholder', "Name the new profile");
quickPick.placeholder = localize('name placeholder', "Profile name");
quickPick.value = profile?.name ?? '';
quickPick.canSelectMany = true;
quickPick.matchOnDescription = false;
quickPick.matchOnDetail = false;
@@ -512,42 +449,109 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
quickPick.customButton = true;
quickPick.hideCheckAll = true;
quickPick.ignoreFocusOut = true;
quickPick.customLabel = localize('create', "Create Profile");
quickPick.description = localize('customise the profile', "Choose what to configure in the profile. Unselected items are shared from the default profile.");
quickPick.items = resources;
quickPick.selectedItems = resources.filter(item => item.picked);
quickPick.customLabel = profile ? localize('save', "Save") : localize('create', "Create");
quickPick.description = localize('customise the profile', "Select configurations to share from the Default profile:");
quickPick.items = [...resources];
const updateSelection = () => {
quickPick.selectedItems = resources.filter(item => item.picked);
};
updateSelection();
const validate = () => {
if (!profile && this.userDataProfilesService.profiles.some(p => p.name === quickPick.value)) {
quickPick.validationMessage = localize('profileExists', "Profile with name {0} already exists.", quickPick.value);
quickPick.severity = Severity.Error;
return;
}
if (resources.every(resource => resource.picked)) {
quickPick.validationMessage = localize('cannot share all', "Cannot share all configurations from the Default Profile.");
quickPick.severity = Severity.Error;
return;
}
quickPick.severity = Severity.Ignore;
quickPick.validationMessage = undefined;
};
const disposables = new DisposableStore();
disposables.add(quickPick.onDidChangeSelection(items => {
for (const resource of resources) {
resource.picked = items.includes(resource);
}
validate();
}));
disposables.add(quickPick.onDidChangeValue(value => {
if (this.userDataProfilesService.profiles.some(p => p.name === value)) {
quickPick.validationMessage = localize('profileExists', "Profile with name {0} already exists.", value);
quickPick.severity = Severity.Error;
} else {
quickPick.severity = Severity.Ignore;
quickPick.validationMessage = undefined;
}
}));
disposables.add(quickPick.onDidChangeValue(validate));
let result: { name: string; items: ReadonlyArray<IQuickPickItem> } | undefined;
disposables.add(quickPick.onDidCustom(async () => {
disposables.add(Event.any(quickPick.onDidCustom, quickPick.onDidAccept)(() => {
if (!quickPick.value) {
quickPick.validationMessage = localize('name required', "Provide a name for the new profile");
quickPick.severity = Severity.Error;
}
if (quickPick.validationMessage) {
return;
}
if (resources.some(resource => quickPick.selectedItems.includes(resource))) {
result = { name: quickPick.value, items: quickPick.selectedItems };
quickPick.hide();
}
result = { name: quickPick.value, items: quickPick.selectedItems };
quickPick.hide();
quickPick.severity = Severity.Ignore;
quickPick.validationMessage = undefined;
}));
if (!profile) {
const domNode = $('.profile-type-widget');
append(domNode, $('.profile-type-create-label', undefined, localize('create from', "Copy from:")));
const separator = { text: '\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500', isDisabled: true };
const profileOptions: (ISelectOptionItem & { id?: string; source?: IUserDataProfile | string })[] = [];
profileOptions.push({ text: localize('empty profile', "None") });
const templates = await this.getProfileTemplatesFromProduct();
if (templates.length) {
profileOptions.push({ ...separator, decoratorRight: localize('from templates', "Profile Templates") });
for (const template of templates) {
profileOptions.push({ text: template.name, id: template.url, source: template.url });
}
}
profileOptions.push({ ...separator, decoratorRight: localize('from existing profiles', "Existing Profiles") });
for (const profile of this.userDataProfilesService.profiles) {
profileOptions.push({ text: profile.name, id: profile.id, source: profile });
}
const findOptionIndex = () => {
const index = profileOptions.findIndex(option => {
if (isString(source)) {
return option.id === source;
} else if (source) {
return option.id === source.id;
}
return false;
});
return index > -1 ? index : 0;
};
const selectBox = disposables.add(this.instantiationService.createInstance(SelectBox, profileOptions, findOptionIndex(), this.contextViewService, defaultSelectBoxStyles, { useCustomDrawn: true }));
selectBox.render(append(domNode, $('.profile-type-select-container')));
quickPick.widget = domNode;
const updateOptions = () => {
const index = findOptionIndex();
if (index <= 0) {
return;
}
const option = profileOptions[index];
if (!isString(option.source)) {
for (const resource of resources) {
resource.picked = option.source?.useDefaultFlags?.[resource.id];
}
updateSelection();
}
};
updateOptions();
disposables.add(selectBox.onDidSelect(({ index }) => {
source = profileOptions[index].source;
updateOptions();
}));
}
quickPick.show();
await new Promise<void>((c, e) => {
@@ -558,37 +562,36 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
});
if (!result) {
this.telemetryService.publicLog2<{}, CreateProfileInfoClassification>('userDataProfile.cancelCreate');
return;
}
const { name, items } = result;
this.telemetryService.publicLog2<{}, CreateProfileInfoClassification>('userDataProfile.successCreate');
try {
const useDefaultFlags: UseDefaultProfileFlags | undefined = items.length !== resources.length ? {
settings: !items.includes(settings),
keybindings: !items.includes(keybindings),
snippets: !items.includes(snippets),
tasks: !items.includes(tasks),
extensions: !items.includes(extensions)
const useDefaultFlags: UseDefaultProfileFlags | undefined = result.items.length ? {
settings: result.items.includes(settings),
keybindings: result.items.includes(keybindings),
snippets: result.items.includes(snippets),
tasks: result.items.includes(tasks),
extensions: result.items.includes(extensions)
} : undefined;
await this.userDataProfileManagementService.createAndEnterProfile(name, { useDefaultFlags });
if (profile) {
await this.userDataProfileManagementService.updateProfile(profile, { name: result.name, useDefaultFlags });
} else {
if (isString(source)) {
await this.userDataProfileImportExportService.importProfile(URI.parse(source), { mode: 'apply', name: result.name, useDefaultFlags });
} else if (source) {
await this.userDataProfileImportExportService.createFromProfile(source, result.name, { useDefaultFlags });
} else {
await this.userDataProfileManagementService.createAndEnterProfile(result.name, { useDefaultFlags });
}
}
} catch (error) {
this.notificationService.error(error);
}
}
private async getNameForProfile(title: string): Promise<string | undefined> {
return this.quickInputService.input({
placeHolder: localize('name', "Profile name"),
title,
validateInput: async (value: string) => {
if (this.userDataProfilesService.profiles.some(p => p.name === value)) {
return localize('profileExists', "Profile with name {0} already exists.", value);
}
return undefined;
}
});
}
private registerCreateProfileAction(): void {
const that = this;
this._register(registerAction2(class CreateProfileAction extends Action2 {
@@ -601,6 +604,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
},
category: PROFILES_CATEGORY,
precondition: PROFILES_ENABLEMENT_CONTEXT,
f1: true,
menu: [
{
id: ProfilesMenu,
@@ -613,52 +617,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
}
async run(accessor: ServicesAccessor) {
const quickInputService = accessor.get(IQuickInputService);
const commandService = accessor.get(ICommandService);
const userDataProfileImportExportService = accessor.get(IUserDataProfileImportExportService);
const quickPickItems: QuickPickItem[] = [{
id: CREATE_EMPTY_PROFILE_ACTION_ID,
label: localize('empty profile', "Empty Profile..."),
}, {
id: CREATE_NEW_PROFILE_ACTION_ID,
label: localize('new profile', "New Profile..."),
}, {
type: 'separator',
}, {
id: CREATE_FROM_CURRENT_PROFILE_ACTION_ID,
label: localize('using current', "Save Current Profile As..."),
}];
const profileTemplateQuickPickItems = await that.getProfileTemplatesQuickPickItems();
if (profileTemplateQuickPickItems.length) {
quickPickItems.push({
type: 'separator',
label: localize('templates', "Profile Templates")
}, ...profileTemplateQuickPickItems);
}
const pick = await quickInputService.pick(quickPickItems,
{
hideInput: true,
canPickMany: false,
title: localize('create profile title', "Create Profile...")
});
if (pick) {
if (pick.id) {
return commandService.executeCommand(pick.id);
}
if ((<IProfileTemplateQuickPickItem>pick).url) {
type ProfileCreationFromTemplateActionClassification = {
owner: 'sandy081';
comment: 'Report profile creation from template action';
profileName: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Name of the profile created from template' };
};
type ProfileCreationFromTemplateActionEvent = {
profileName: string;
};
that.telemetryService.publicLog2<ProfileCreationFromTemplateActionEvent, ProfileCreationFromTemplateActionClassification>('profileCreationAction:builtinTemplate', { profileName: (<IProfileTemplateQuickPickItem>pick).name });
const uri = URI.parse((<IProfileTemplateQuickPickItem>pick).url);
return userDataProfileImportExportService.importProfile(uri, { mode: 'apply' });
}
}
return that.saveProfile();
}
}));
}
@@ -736,18 +695,6 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
}));
}
private async getProfileTemplatesQuickPickItems(): Promise<IProfileTemplateQuickPickItem[]> {
const quickPickItems: IProfileTemplateQuickPickItem[] = [];
const profileTemplates = await this.getProfileTemplatesFromProduct();
for (const template of profileTemplates) {
quickPickItems.push({
label: template.name,
...template
});
}
return quickPickItems;
}
private async getProfileTemplatesFromProduct(): Promise<IProfileTemplateInfo[]> {
if (this.productService.profileTemplatesUrl) {
try {
@@ -18,7 +18,7 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile
import { IFileService } from 'vs/platform/files/common/files';
import { URI } from 'vs/base/common/uri';
import { Extensions, ITreeItem, ITreeViewDataProvider, ITreeViewDescriptor, IViewContainersRegistry, IViewDescriptorService, IViewsRegistry, IViewsService, TreeItemCollapsibleState, ViewContainer, ViewContainerLocation } from 'vs/workbench/common/views';
import { IUserDataProfile, IUserDataProfilesService, ProfileResourceType, toUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile';
import { IUserDataProfile, IUserDataProfileOptions, IUserDataProfilesService, ProfileResourceType, toUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile';
import { ContextKeyExpr, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { Registry } from 'vs/platform/registry/common/platform';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
@@ -209,11 +209,11 @@ export class UserDataProfileImportExportService extends Disposable implements IU
return;
}
if (mode === 'preview') {
await this.previewProfile(profileTemplate);
await this.previewProfile(profileTemplate, options);
} else if (mode === 'apply') {
await this.createAndSwitch(profileTemplate, false, true, localize('create profile', "Create Profile"));
await this.createAndSwitch(profileTemplate, false, true, options, localize('create profile', "Create Profile"));
} else if (mode === 'both') {
await this.importAndPreviewProfile(uri, profileTemplate);
await this.importAndPreviewProfile(uri, profileTemplate, options);
}
} finally {
disposables.dispose();
@@ -249,11 +249,11 @@ export class UserDataProfileImportExportService extends Disposable implements IU
}
}
async SaveCurrentProfileAs(name: string): Promise<void> {
const userDataProfilesExportState = this.instantiationService.createInstance(UserDataProfileExportState, this.userDataProfileService.currentProfile);
async createFromProfile(profile: IUserDataProfile, name: string, options?: IUserDataProfileOptions): Promise<void> {
const userDataProfilesExportState = this.instantiationService.createInstance(UserDataProfileExportState, profile);
try {
const profileTemplate = await userDataProfilesExportState.getProfileTemplate(name, undefined);
await this.createAndSwitch(profileTemplate, false, true, localize('save profile as', "Save Profile As"));
await this.createAndSwitch(profileTemplate, false, true, options, localize('create profile', "Create Profile"));
} finally {
userDataProfilesExportState.dispose();
}
@@ -269,7 +269,7 @@ export class UserDataProfileImportExportService extends Disposable implements IU
sticky: true,
}, async progress => {
const reportProgress = (message: string) => progress.report({ message: localize('troubleshoot profile progress', "Setting up Troubleshoot Profile: {0}", message) });
const profile = await this.createProfile(profileTemplate, true, false, reportProgress);
const profile = await this.createProfile(profileTemplate, true, false, { useDefaultFlags: this.userDataProfileService.currentProfile.useDefaultFlags }, reportProgress);
if (profile) {
reportProgress(localize('progress extensions', "Applying Extensions..."));
await this.instantiationService.createInstance(ExtensionsResource).copy(this.userDataProfileService.currentProfile, profile, true);
@@ -362,21 +362,21 @@ export class UserDataProfileImportExportService extends Disposable implements IU
return profileTemplate;
}
private async importAndPreviewProfile(uri: URI, profileTemplate: IUserDataProfileTemplate): Promise<void> {
private async importAndPreviewProfile(uri: URI, profileTemplate: IUserDataProfileTemplate, options: IUserDataProfileOptions | undefined): Promise<void> {
const disposables = new DisposableStore();
try {
const userDataProfileImportState = disposables.add(this.instantiationService.createInstance(UserDataProfileImportState, profileTemplate));
profileTemplate = await userDataProfileImportState.getProfileTemplateToImport();
const importedProfile = await this.createAndSwitch(profileTemplate, true, false, localize('preview profile', "Preview Profile"));
const importedProfile = await this.createAndSwitch(profileTemplate, true, false, options, localize('preview profile', "Preview Profile"));
if (!importedProfile) {
return;
}
const barrier = new Barrier();
const importAction = this.getCreateAction(barrier, userDataProfileImportState);
const importAction = this.getCreateAction(barrier, userDataProfileImportState, options);
const primaryAction = isWeb
? new Action('importInDesktop', localize('import in desktop', "Create Profile in {0}", this.productService.nameLong), undefined, true, async () => this.openerService.open(uri, { openExternal: true }))
: importAction;
@@ -435,15 +435,15 @@ export class UserDataProfileImportExportService extends Disposable implements IU
}
}
private async previewProfile(profileTemplate: IUserDataProfileTemplate): Promise<void> {
private async previewProfile(profileTemplate: IUserDataProfileTemplate, options: IUserDataProfileOptions | undefined): Promise<void> {
const disposables = new DisposableStore();
try {
const userDataProfileImportState = disposables.add(this.instantiationService.createInstance(UserDataProfileImportState, profileTemplate));
if (userDataProfileImportState.isEmpty()) {
await this.createAndSwitch(profileTemplate, false, true, localize('create profile', "Create Profile"));
await this.createAndSwitch(profileTemplate, false, true, options, localize('create profile', "Create Profile"));
} else {
const barrier = new Barrier();
const importAction = this.getCreateAction(barrier, userDataProfileImportState);
const importAction = this.getCreateAction(barrier, userDataProfileImportState, options);
await this.showProfilePreviewView(IMPORT_PROFILE_PREVIEW_VIEW, profileTemplate.name, importAction, new BarrierAction(barrier, new Action('cancel', localize('cancel', "Cancel")), this.notificationService), false, userDataProfileImportState);
await barrier.wait();
await this.hideProfilePreviewView(IMPORT_PROFILE_PREVIEW_VIEW);
@@ -453,16 +453,16 @@ export class UserDataProfileImportExportService extends Disposable implements IU
}
}
private getCreateAction(barrier: Barrier, userDataProfileImportState: UserDataProfileImportState): IAction {
private getCreateAction(barrier: Barrier, userDataProfileImportState: UserDataProfileImportState, options: IUserDataProfileOptions | undefined): IAction {
const importAction = new BarrierAction(barrier, new Action('title', localize('import', "Create Profile"), undefined, true, async () => {
importAction.enabled = false;
const profileTemplate = await userDataProfileImportState.getProfileTemplateToImport();
return this.createAndSwitch(profileTemplate, false, true, localize('create profile', "Create Profile"));
return this.createAndSwitch(profileTemplate, false, true, options, localize('create profile', "Create Profile"));
}), this.notificationService);
return importAction;
}
private async createAndSwitch(profileTemplate: IUserDataProfileTemplate, temporaryProfile: boolean, extensions: boolean, title: string): Promise<IUserDataProfile | undefined> {
private async createAndSwitch(profileTemplate: IUserDataProfileTemplate, temporaryProfile: boolean, extensions: boolean, options: IUserDataProfileOptions | undefined, title: string): Promise<IUserDataProfile | undefined> {
return this.progressService.withProgress({
location: ProgressLocation.Notification,
delay: 500,
@@ -471,7 +471,7 @@ export class UserDataProfileImportExportService extends Disposable implements IU
title = `${title} (${profileTemplate.name})`;
progress.report({ message: title });
const reportProgress = (message: string) => progress.report({ message: `${title}: ${message}` });
const profile = await this.createProfile(profileTemplate, temporaryProfile, extensions, reportProgress);
const profile = await this.createProfile(profileTemplate, temporaryProfile, extensions, options, reportProgress);
if (profile) {
reportProgress(localize('switching profile', "Switching Profile..."));
await this.userDataProfileManagementService.switchProfile(profile);
@@ -480,8 +480,8 @@ export class UserDataProfileImportExportService extends Disposable implements IU
});
}
private async createProfile(profileTemplate: IUserDataProfileTemplate, temporaryProfile: boolean, extensions: boolean, progress: (message: string) => void): Promise<IUserDataProfile | undefined> {
const profile = await this.getProfileToImport(profileTemplate, temporaryProfile);
private async createProfile(profileTemplate: IUserDataProfileTemplate, temporaryProfile: boolean, extensions: boolean, options: IUserDataProfileOptions | undefined, progress: (message: string) => void): Promise<IUserDataProfile | undefined> {
const profile = await this.getProfileToImport(profileTemplate, temporaryProfile, options);
if (!profile) {
return undefined;
}
@@ -569,12 +569,12 @@ export class UserDataProfileImportExportService extends Disposable implements IU
return result?.id;
}
private async getProfileToImport(profileTemplate: IUserDataProfileTemplate, temp: boolean): Promise<IUserDataProfile | undefined> {
private async getProfileToImport(profileTemplate: IUserDataProfileTemplate, temp: boolean, options: IUserDataProfileOptions | undefined): Promise<IUserDataProfile | undefined> {
const profileName = profileTemplate.name;
const profile = this.userDataProfilesService.profiles.find(p => p.name === profileName);
if (profile) {
if (temp) {
return this.userDataProfilesService.createNamedProfile(`${profileName} ${this.getProfileNameIndex(profileName)}`, { shortName: profileTemplate.shortName, transient: temp });
return this.userDataProfilesService.createNamedProfile(`${profileName} ${this.getProfileNameIndex(profileName)}`, { ...options, shortName: profileTemplate.shortName, transient: temp });
}
enum ImportProfileChoice {
@@ -625,7 +625,7 @@ export class UserDataProfileImportExportService extends Disposable implements IU
}
return this.userDataProfilesService.createNamedProfile(name);
} else {
return this.userDataProfilesService.createNamedProfile(profileName, { shortName: profileTemplate.shortName, transient: temp });
return this.userDataProfilesService.createNamedProfile(profileName, { ...options, shortName: profileTemplate.shortName, transient: temp });
}
}
@@ -73,7 +73,8 @@ export function toUserDataProfileUri(path: string, productService: IProductServi
});
}
export interface IProfileImportOptions {
export interface IProfileImportOptions extends IUserDataProfileOptions {
readonly name?: string;
readonly mode?: 'preview' | 'apply' | 'both';
}
@@ -87,7 +88,7 @@ export interface IUserDataProfileImportExportService {
exportProfile(): Promise<void>;
importProfile(uri: URI, options?: IProfileImportOptions): Promise<void>;
showProfileContents(): Promise<void>;
SaveCurrentProfileAs(name: string): Promise<void>;
createFromProfile(profile: IUserDataProfile, name: string, options?: IUserDataProfileOptions): Promise<void>;
createTroubleshootProfile(): Promise<void>;
setProfile(profile: IUserDataProfileTemplate): Promise<void>;
}