in patched-vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts [318:734]
content: localize('invalidTrust', "You cannot trust individual folders within a repository.", path)
};
}
}
return null;
}
acceptEdit(item: ITrustedUriItem, uri: URI) {
const trustedFolders = this.workspaceTrustManagementService.getTrustedUris();
const index = trustedFolders.findIndex(u => this.uriService.extUri.isEqual(u, item.uri));
if (index >= trustedFolders.length || index === -1) {
trustedFolders.push(uri);
} else {
trustedFolders[index] = uri;
}
this.workspaceTrustManagementService.setTrustedUris(trustedFolders);
this._onDidAcceptEdit.fire(item);
}
rejectEdit(item: ITrustedUriItem) {
this._onDidRejectEdit.fire(item);
}
async delete(item: ITrustedUriItem) {
this.table.focusNext();
await this.workspaceTrustManagementService.setUrisTrust([item.uri], false);
if (this.table.getFocus().length === 0) {
this.table.focusLast();
}
this._onDelete.fire(item);
this.table.domFocus();
}
async edit(item: ITrustedUriItem, usePickerIfPossible?: boolean) {
const canUseOpenDialog = item.uri.scheme === Schemas.file ||
(
item.uri.scheme === this.currentWorkspaceUri.scheme &&
this.uriService.extUri.isEqualAuthority(this.currentWorkspaceUri.authority, item.uri.authority) &&
!isVirtualResource(item.uri)
);
if (canUseOpenDialog && usePickerIfPossible) {
const uri = await this.fileDialogService.showOpenDialog({
canSelectFiles: false,
canSelectFolders: true,
canSelectMany: false,
defaultUri: item.uri,
openLabel: localize('trustUri', "Trust Folder"),
title: localize('selectTrustedUri', "Select Folder To Trust")
});
if (uri) {
this.acceptEdit(item, uri[0]);
} else {
this.rejectEdit(item);
}
} else {
this.selectTrustedUriEntry(item);
this._onEdit.fire(item);
}
}
}
class TrustedUriTableVirtualDelegate implements ITableVirtualDelegate<ITrustedUriItem> {
static readonly HEADER_ROW_HEIGHT = 30;
static readonly ROW_HEIGHT = 24;
readonly headerRowHeight = TrustedUriTableVirtualDelegate.HEADER_ROW_HEIGHT;
getHeight(item: ITrustedUriItem) {
return TrustedUriTableVirtualDelegate.ROW_HEIGHT;
}
}
interface IActionsColumnTemplateData {
readonly actionBar: ActionBar;
}
class TrustedUriActionsColumnRenderer implements ITableRenderer<ITrustedUriItem, IActionsColumnTemplateData> {
static readonly TEMPLATE_ID = 'actions';
readonly templateId: string = TrustedUriActionsColumnRenderer.TEMPLATE_ID;
constructor(
private readonly table: WorkspaceTrustedUrisTable,
private readonly currentWorkspaceUri: URI,
@IUriIdentityService private readonly uriService: IUriIdentityService) { }
renderTemplate(container: HTMLElement): IActionsColumnTemplateData {
const element = container.appendChild($('.actions'));
const actionBar = new ActionBar(element);
return { actionBar };
}
renderElement(item: ITrustedUriItem, index: number, templateData: IActionsColumnTemplateData, height: number | undefined): void {
templateData.actionBar.clear();
const canUseOpenDialog = item.uri.scheme === Schemas.file ||
(
item.uri.scheme === this.currentWorkspaceUri.scheme &&
this.uriService.extUri.isEqualAuthority(this.currentWorkspaceUri.authority, item.uri.authority) &&
!isVirtualResource(item.uri)
);
const actions: IAction[] = [];
if (canUseOpenDialog) {
actions.push(this.createPickerAction(item));
}
actions.push(this.createEditAction(item));
actions.push(this.createDeleteAction(item));
templateData.actionBar.push(actions, { icon: true });
}
private createEditAction(item: ITrustedUriItem): IAction {
return {
label: '',
class: ThemeIcon.asClassName(editIcon),
enabled: true,
id: 'editTrustedUri',
tooltip: localize('editTrustedUri', "Edit Path"),
run: () => {
this.table.edit(item, false);
}
};
}
private createPickerAction(item: ITrustedUriItem): IAction {
return {
label: '',
class: ThemeIcon.asClassName(folderPickerIcon),
enabled: true,
id: 'pickerTrustedUri',
tooltip: localize('pickerTrustedUri', "Open File Picker"),
run: () => {
this.table.edit(item, true);
}
};
}
private createDeleteAction(item: ITrustedUriItem): IAction {
return {
label: '',
class: ThemeIcon.asClassName(removeIcon),
enabled: true,
id: 'deleteTrustedUri',
tooltip: localize('deleteTrustedUri', "Delete Path"),
run: async () => {
await this.table.delete(item);
}
};
}
disposeTemplate(templateData: IActionsColumnTemplateData): void {
templateData.actionBar.dispose();
}
}
interface ITrustedUriPathColumnTemplateData {
element: HTMLElement;
pathLabel: HTMLElement;
pathInput: InputBox;
renderDisposables: DisposableStore;
disposables: DisposableStore;
}
class TrustedUriPathColumnRenderer implements ITableRenderer<ITrustedUriItem, ITrustedUriPathColumnTemplateData> {
static readonly TEMPLATE_ID = 'path';
readonly templateId: string = TrustedUriPathColumnRenderer.TEMPLATE_ID;
private currentItem?: ITrustedUriItem;
constructor(
private readonly table: WorkspaceTrustedUrisTable,
@IContextViewService private readonly contextViewService: IContextViewService
) {
}
renderTemplate(container: HTMLElement): ITrustedUriPathColumnTemplateData {
const element = container.appendChild($('.path'));
const pathLabel = element.appendChild($('div.path-label'));
const pathInput = new InputBox(element, this.contextViewService, {
validationOptions: {
validation: value => this.table.validateUri(value, this.currentItem)
},
inputBoxStyles: defaultInputBoxStyles
});
const disposables = new DisposableStore();
const renderDisposables = disposables.add(new DisposableStore());
return {
element,
pathLabel,
pathInput,
disposables,
renderDisposables
};
}
renderElement(item: ITrustedUriItem, index: number, templateData: ITrustedUriPathColumnTemplateData, height: number | undefined): void {
templateData.renderDisposables.clear();
this.currentItem = item;
templateData.renderDisposables.add(this.table.onEdit(async (e) => {
if (item === e) {
templateData.element.classList.add('input-mode');
templateData.pathInput.focus();
templateData.pathInput.select();
templateData.element.parentElement!.style.paddingLeft = '0px';
}
}));
// stop double click action from re-rendering the element on the table #125052
templateData.renderDisposables.add(addDisposableListener(templateData.pathInput.element, EventType.DBLCLICK, e => {
EventHelper.stop(e);
}));
const hideInputBox = () => {
templateData.element.classList.remove('input-mode');
templateData.element.parentElement!.style.paddingLeft = '5px';
};
const accept = () => {
hideInputBox();
const pathToUse = templateData.pathInput.value;
const uri = hasDriveLetter(pathToUse) ? item.uri.with({ path: posix.sep + toSlashes(pathToUse) }) : item.uri.with({ path: pathToUse });
templateData.pathLabel.innerText = this.formatPath(uri);
if (uri) {
this.table.acceptEdit(item, uri);
}
};
const reject = () => {
hideInputBox();
templateData.pathInput.value = stringValue;
this.table.rejectEdit(item);
};
templateData.renderDisposables.add(addStandardDisposableListener(templateData.pathInput.inputElement, EventType.KEY_DOWN, e => {
let handled = false;
if (e.equals(KeyCode.Enter)) {
accept();
handled = true;
} else if (e.equals(KeyCode.Escape)) {
reject();
handled = true;
}
if (handled) {
e.preventDefault();
e.stopPropagation();
}
}));
templateData.renderDisposables.add((addDisposableListener(templateData.pathInput.inputElement, EventType.BLUR, () => {
reject();
})));
const stringValue = this.formatPath(item.uri);
templateData.pathInput.value = stringValue;
templateData.pathLabel.innerText = stringValue;
templateData.element.classList.toggle('current-workspace-parent', item.parentOfWorkspaceItem);
}
disposeTemplate(templateData: ITrustedUriPathColumnTemplateData): void {
templateData.disposables.dispose();
templateData.renderDisposables.dispose();
}
private formatPath(uri: URI): string {
if (uri.scheme === Schemas.file) {
return normalizeDriveLetter(uri.fsPath);
}
// If the path is not a file uri, but points to a windows remote, we should create windows fs path
// e.g. /c:/user/directory => C:\user\directory
if (uri.path.startsWith(posix.sep)) {
const pathWithoutLeadingSeparator = uri.path.substring(1);
const isWindowsPath = hasDriveLetter(pathWithoutLeadingSeparator, true);
if (isWindowsPath) {
return normalizeDriveLetter(win32.normalize(pathWithoutLeadingSeparator), true);
}
}
return uri.path;
}
}
interface ITrustedUriHostColumnTemplateData {
element: HTMLElement;
hostContainer: HTMLElement;
buttonBarContainer: HTMLElement;
disposables: DisposableStore;
renderDisposables: DisposableStore;
}
function getHostLabel(labelService: ILabelService, item: ITrustedUriItem): string {
return item.uri.authority ? labelService.getHostLabel(item.uri.scheme, item.uri.authority) : localize('localAuthority', "Local");
}
class TrustedUriHostColumnRenderer implements ITableRenderer<ITrustedUriItem, ITrustedUriHostColumnTemplateData> {
static readonly TEMPLATE_ID = 'host';
readonly templateId: string = TrustedUriHostColumnRenderer.TEMPLATE_ID;
constructor(
@ILabelService private readonly labelService: ILabelService,
) { }
renderTemplate(container: HTMLElement): ITrustedUriHostColumnTemplateData {
const disposables = new DisposableStore();
const renderDisposables = disposables.add(new DisposableStore());
const element = container.appendChild($('.host'));
const hostContainer = element.appendChild($('div.host-label'));
const buttonBarContainer = element.appendChild($('div.button-bar'));
return {
element,
hostContainer,
buttonBarContainer,
disposables,
renderDisposables
};
}
renderElement(item: ITrustedUriItem, index: number, templateData: ITrustedUriHostColumnTemplateData, height: number | undefined): void {
templateData.renderDisposables.clear();
templateData.renderDisposables.add({ dispose: () => { clearNode(templateData.buttonBarContainer); } });
templateData.hostContainer.innerText = getHostLabel(this.labelService, item);
templateData.element.classList.toggle('current-workspace-parent', item.parentOfWorkspaceItem);
templateData.hostContainer.style.display = '';
templateData.buttonBarContainer.style.display = 'none';
}
disposeTemplate(templateData: ITrustedUriHostColumnTemplateData): void {
templateData.disposables.dispose();
}
}
export class WorkspaceTrustEditor extends EditorPane {
static readonly ID: string = 'workbench.editor.workspaceTrust';
private rootElement!: HTMLElement;
// Header Section
private headerContainer!: HTMLElement;
private headerTitleContainer!: HTMLElement;
private headerTitleIcon!: HTMLElement;
private headerTitleText!: HTMLElement;
private headerDescription!: HTMLElement;
private bodyScrollBar!: DomScrollableElement;
// Affected Features Section
private affectedFeaturesContainer!: HTMLElement;
private trustedContainer!: HTMLElement;
private untrustedContainer!: HTMLElement;
// Settings Section
private configurationContainer!: HTMLElement;
private workspaceTrustedUrisTable!: WorkspaceTrustedUrisTable;
constructor(
group: IEditorGroup,
@ITelemetryService telemetryService: ITelemetryService,
@IThemeService themeService: IThemeService,
@IStorageService storageService: IStorageService,
@IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService,
@IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService,
@IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService,
@IWorkbenchConfigurationService private readonly configurationService: IWorkbenchConfigurationService,
@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService,
@IProductService private readonly productService: IProductService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
) { super(WorkspaceTrustEditor.ID, group, telemetryService, themeService, storageService); }
protected createEditor(parent: HTMLElement): void {
this.rootElement = append(parent, $('.workspace-trust-editor', { tabindex: '0' }));
this.createHeaderElement(this.rootElement);
const scrollableContent = $('.workspace-trust-editor-body');
this.bodyScrollBar = this._register(new DomScrollableElement(scrollableContent, {
horizontal: ScrollbarVisibility.Hidden,
vertical: ScrollbarVisibility.Auto,
}));
append(this.rootElement, this.bodyScrollBar.getDomNode());
this.createAffectedFeaturesElement(scrollableContent);
this.createConfigurationElement(scrollableContent);
this.rootElement.style.setProperty('--workspace-trust-selected-color', asCssVariable(buttonBackground));
this.rootElement.style.setProperty('--workspace-trust-unselected-color', asCssVariable(buttonSecondaryBackground));
this.rootElement.style.setProperty('--workspace-trust-check-color', asCssVariable(debugIconStartForeground));
this.rootElement.style.setProperty('--workspace-trust-x-color', asCssVariable(editorErrorForeground));
// Navigate page with keyboard
this._register(addDisposableListener(this.rootElement, EventType.KEY_DOWN, e => {
const event = new StandardKeyboardEvent(e);
if (event.equals(KeyCode.UpArrow) || event.equals(KeyCode.DownArrow)) {
const navOrder = [this.headerContainer, this.trustedContainer, this.untrustedContainer, this.configurationContainer];
const currentIndex = navOrder.findIndex(element => {