Skip to content

Commit

Permalink
show auto update checkbox in editor (microsoft#199066)
Browse files Browse the repository at this point in the history
microsoft#194188 show auto update checkbox in editor
  • Loading branch information
sandy081 authored Nov 25, 2023
1 parent 7c342a3 commit 578ad35
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 44 deletions.
13 changes: 13 additions & 0 deletions src/vs/base/browser/ui/toggle/toggle.css
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@
background-size: 16px !important;
}

.monaco-action-bar .checkbox-action-item {
display: flex;
align-items: center;
}

.monaco-action-bar .checkbox-action-item > .monaco-custom-toggle.monaco-checkbox {
margin-right: 4px;
}

.monaco-action-bar .checkbox-action-item > .checkbox-label {
font-size: 12px;
}

/* hide check when unchecked */
.monaco-custom-toggle.monaco-checkbox:not(.checked)::before {
visibility: hidden;
Expand Down
102 changes: 100 additions & 2 deletions src/vs/base/browser/ui/toggle/toggle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ThemeIcon } from 'vs/base/common/themables';
import { Emitter, Event } from 'vs/base/common/event';
import { KeyCode } from 'vs/base/common/keyCodes';
import 'vs/css!./toggle';
import { isActiveElement } from 'vs/base/browser/dom';
import { isActiveElement, $, addDisposableListener, EventType } from 'vs/base/browser/dom';

export interface IToggleOpts extends IToggleStyles {
readonly actionClassName?: string;
Expand Down Expand Up @@ -219,6 +219,10 @@ export class Toggle extends Widget {
}

export class Checkbox extends Widget {

private readonly _onChange = this._register(new Emitter<boolean>());
readonly onChange: Event<boolean /* via keyboard */> = this._onChange.event;

private checkbox: Toggle;
private styles: ICheckboxStyles;

Expand All @@ -235,7 +239,10 @@ export class Checkbox extends Widget {

this.applyStyles();

this._register(this.checkbox.onChange(() => this.applyStyles()));
this._register(this.checkbox.onChange(keyboard => {
this.applyStyles();
this._onChange.fire(keyboard);
}));
}

get checked(): boolean {
Expand All @@ -256,9 +263,100 @@ export class Checkbox extends Widget {
return isActiveElement(this.domNode);
}

enable(): void {
this.checkbox.enable();
}

disable(): void {
this.checkbox.disable();
}

protected applyStyles(): void {
this.domNode.style.color = this.styles.checkboxForeground || '';
this.domNode.style.backgroundColor = this.styles.checkboxBackground || '';
this.domNode.style.borderColor = this.styles.checkboxBorder || '';
}
}

export interface ICheckboxActionViewItemOptions extends IActionViewItemOptions {
checkboxStyles: ICheckboxStyles;
}

export class CheckboxActionViewItem extends BaseActionViewItem {

protected readonly toggle: Checkbox;
private cssClass?: string;

constructor(context: any, action: IAction, options: ICheckboxActionViewItemOptions) {
super(context, action, options);

this.toggle = this._register(new Checkbox(this._action.label, !!this._action.checked, options.checkboxStyles));
this._register(this.toggle.onChange(() => this.onChange()));
}

override render(container: HTMLElement): void {
this.element = container;
this.element.classList.add('checkbox-action-item');
this.element.appendChild(this.toggle.domNode);
if ((<IActionViewItemOptions>this.options).label && this._action.label) {
const label = this.element.appendChild($('span.checkbox-label', undefined, this._action.label));
this._register(addDisposableListener(label, EventType.CLICK, (e: MouseEvent) => {
this.toggle.checked = !this.toggle.checked;
e.stopPropagation();
e.preventDefault();
this.onChange();
}));
}

this.updateEnabled();
this.updateClass();
this.updateChecked();
}

private onChange(): void {
this._action.checked = !!this.toggle && this.toggle.checked;
this.actionRunner.run(this._action, this._context);
}

protected override updateEnabled(): void {
if (this.isEnabled()) {
this.toggle.enable();
} else {
this.toggle.disable();
}
if (this.action.enabled) {
this.element?.classList.remove('disabled');
} else {
this.element?.classList.add('disabled');
}
}

protected override updateChecked(): void {
this.toggle.checked = !!this._action.checked;
}

protected override updateClass(): void {
if (this.cssClass) {
this.toggle.domNode.classList.remove(...this.cssClass.split(' '));
}
this.cssClass = this.getClass();
if (this.cssClass) {
this.toggle.domNode.classList.add(...this.cssClass.split(' '));
}
}

override focus(): void {
this.toggle.domNode.tabIndex = 0;
this.toggle.focus();
}

override blur(): void {
this.toggle.domNode.tabIndex = -1;
this.toggle.domNode.blur();
}

override setFocusable(focusable: boolean): void {
this.toggle.domNode.tabIndex = focusable ? 0 : -1;
}

}
10 changes: 7 additions & 3 deletions src/vs/workbench/contrib/extensions/browser/extensionEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { CheckboxActionViewItem } from 'vs/base/browser/ui/toggle/toggle';
import { Action, IAction } from 'vs/base/common/actions';
import * as arrays from 'vs/base/common/arrays';
import { Cache, CacheResult } from 'vs/base/common/cache';
Expand Down Expand Up @@ -46,7 +47,7 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { defaultKeybindingLabelStyles } from 'vs/platform/theme/browser/defaultStyles';
import { defaultCheckboxStyles, defaultKeybindingLabelStyles } from 'vs/platform/theme/browser/defaultStyles';
import { buttonForeground, buttonHoverBackground, editorBackground, textLinkActiveForeground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
import { IColorTheme, ICssStyleCollector, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
Expand All @@ -72,7 +73,6 @@ import {
SetLanguageAction,
SetProductIconThemeAction,
ToggleAutoUpdateForExtensionAction,
ToggleAutoUpdatesForPublisherAction,
SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction,
ToggleSyncExtensionAction,
UninstallAction,
Expand Down Expand Up @@ -345,7 +345,7 @@ export class ExtensionEditor extends EditorPane {
this.instantiationService.createInstance(ReloadAction),
this.instantiationService.createInstance(ExtensionStatusLabelAction),
this.instantiationService.createInstance(ActionWithDropDownAction, 'extensions.updateActions', '',
[[this.instantiationService.createInstance(UpdateAction, true)], [this.instantiationService.createInstance(ToggleAutoUpdateForExtensionAction), this.instantiationService.createInstance(ToggleAutoUpdatesForPublisherAction)]]),
[[this.instantiationService.createInstance(UpdateAction, true)], [this.instantiationService.createInstance(ToggleAutoUpdateForExtensionAction, true, [true, 'onlyEnabledExtensions'])]]),
this.instantiationService.createInstance(SetColorThemeAction),
this.instantiationService.createInstance(SetFileIconThemeAction),
this.instantiationService.createInstance(SetProductIconThemeAction),
Expand All @@ -369,6 +369,7 @@ export class ExtensionEditor extends EditorPane {
this.instantiationService.createInstance(SwitchToPreReleaseVersionAction, false),
this.instantiationService.createInstance(SwitchToReleasedVersionAction, false),
this.instantiationService.createInstance(ToggleSyncExtensionAction),
this.instantiationService.createInstance(ToggleAutoUpdateForExtensionAction, false, ['onlySelectedExtensions']),
new ExtensionEditorManageExtensionAction(this.scopedContextKeyService || this.contextKeyService, this.instantiationService),
];

Expand All @@ -382,6 +383,9 @@ export class ExtensionEditor extends EditorPane {
if (action instanceof ActionWithDropDownAction) {
return new ExtensionActionWithDropdownActionViewItem(action, { icon: true, label: true, menuActionsOrProvider: { getActions: () => action.menuActions }, menuActionClassNames: (action.class || '').split(' ') }, this.contextMenuService);
}
if (action instanceof ToggleAutoUpdateForExtensionAction) {
return new CheckboxActionViewItem(undefined, action, { icon: true, label: true, checkboxStyles: defaultCheckboxStyles });
}
return undefined;
},
focusOnlyEnabledItems: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1335,14 +1335,14 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
id: MenuId.ExtensionContext,
group: UPDATE_ACTIONS_GROUP,
order: 1,
when: ContextKeyExpr.and(ContextKeyExpr.equals('extensionStatus', 'installed'), ContextKeyExpr.not('isBuiltinExtension'), ContextKeyExpr.equals(`config.${AutoUpdateConfigurationKey}`, 'onlySelectedExtensions'),)
when: ContextKeyExpr.and(ContextKeyExpr.not('inExtensionEditor'), ContextKeyExpr.equals('extensionStatus', 'installed'), ContextKeyExpr.not('isBuiltinExtension'), ContextKeyExpr.equals(`config.${AutoUpdateConfigurationKey}`, 'onlySelectedExtensions'),)
},
run: async (accessor: ServicesAccessor, id: string) => {
const instantiationService = accessor.get(IInstantiationService);
const extensionWorkbenchService = accessor.get(IExtensionsWorkbenchService);
const extension = extensionWorkbenchService.local.find(e => areSameExtensions(e.identifier, { id }));
if (extension) {
const action = instantiationService.createInstance(ToggleAutoUpdateForExtensionAction);
const action = instantiationService.createInstance(ToggleAutoUpdateForExtensionAction, false, []);
action.extension = extension;
return action.run();
}
Expand Down
55 changes: 29 additions & 26 deletions src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Emitter, Event } from 'vs/base/common/event';
import * as json from 'vs/base/common/json';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { disposeIfDisposable } from 'vs/base/common/lifecycle';
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewPaneContainer, IExtensionContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID, THEME_ACTIONS_GROUP, INSTALL_ACTIONS_GROUP, UPDATE_ACTIONS_GROUP } from 'vs/workbench/contrib/extensions/common/extensions';
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewPaneContainer, IExtensionContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID, THEME_ACTIONS_GROUP, INSTALL_ACTIONS_GROUP, UPDATE_ACTIONS_GROUP, AutoUpdateConfigurationKey, AutoUpdateConfigurationValue } from 'vs/workbench/contrib/extensions/common/extensions';
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate';
import { IGalleryExtension, IExtensionGalleryService, ILocalExtension, InstallOptions, InstallOperation, TargetPlatformToString, ExtensionManagementErrorCode } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
Expand Down Expand Up @@ -826,30 +826,48 @@ export class UpdateAction extends AbstractUpdateAction {
}
}

export class ToggleAutoUpdateForExtensionAction extends AbstractUpdateAction {
export class ToggleAutoUpdateForExtensionAction extends ExtensionAction {

static readonly ID = 'workbench.extensions.action.toggleAutoUpdateForExtension';
static readonly LABEL = localize('enableAutoUpdateLabel', "Auto Update");

private static readonly EnabledClass = `${ExtensionAction.EXTENSION_ACTION_CLASS} auto-update`;
private static readonly DisabledClass = `${ToggleAutoUpdateForExtensionAction.EnabledClass} hide`;

constructor(
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService
private readonly enableWhenOutdated: boolean,
private readonly enableWhenAutoUpdateValue: AutoUpdateConfigurationValue[],
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
@IConfigurationService configurationService: IConfigurationService,

) {
super(ToggleAutoUpdateForExtensionAction.ID, ToggleAutoUpdateForExtensionAction.LABEL, extensionsWorkbenchService);
super(ToggleAutoUpdateForExtensionAction.ID, ToggleAutoUpdateForExtensionAction.LABEL, ToggleAutoUpdateForExtensionAction.DisabledClass);
this._register(configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(AutoUpdateConfigurationKey)) {
this.update();
}
}));
this.update();
}

override update() {
this.enabled = false;
this.class = ToggleAutoUpdateForExtensionAction.DisabledClass;
if (!this.extension) {
return;
}
if (this.extension.isBuiltin) {
return;
}
if (!this.extensionsWorkbenchService.isAutoUpdateEnabled()) {
if (this.enableWhenOutdated && !this.extension.outdated) {
return;
}
super.update();
this._checked = this.extensionsWorkbenchService.isAutoUpdateEnabledFor(this.extension);
if (!this.enableWhenAutoUpdateValue.includes(this.extensionsWorkbenchService.getAutoUpdateValue())) {
return;
}
this.enabled = true;
this.class = ToggleAutoUpdateForExtensionAction.EnabledClass;
this.checked = this.extensionsWorkbenchService.isAutoUpdateEnabledFor(this.extension);
}

override async run(): Promise<any> {
Expand All @@ -868,7 +886,7 @@ export class ToggleAutoUpdateForExtensionAction extends AbstractUpdateAction {
}
}

export class ToggleAutoUpdatesForPublisherAction extends AbstractUpdateAction {
export class ToggleAutoUpdatesForPublisherAction extends ExtensionAction {

static readonly ID = 'workbench.extensions.action.toggleAutoUpdatesForPublisher';
static readonly LABEL = localize('toggleAutoUpdatesForPublisherLabel', "Auto Update (Publisher)");
Expand All @@ -878,27 +896,12 @@ export class ToggleAutoUpdatesForPublisherAction extends AbstractUpdateAction {
}

constructor(
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService
) {
super(ToggleAutoUpdatesForPublisherAction.ID, ToggleAutoUpdatesForPublisherAction.LABEL, extensionsWorkbenchService);
super(ToggleAutoUpdatesForPublisherAction.ID, ToggleAutoUpdatesForPublisherAction.LABEL);
}

override update() {
if (!this.extension) {
return;
}
if (this.extension.isBuiltin) {
this.enabled = false;
return;
}
if (this.extensionsWorkbenchService.getAutoUpdateValue() !== 'onlySelectedExtensions') {
this.enabled = false;
return;
}
super.update();
this._checked = this.extensionsWorkbenchService.isAutoUpdateEnabledFor(this.extension.publisher);
this.label = ToggleAutoUpdatesForPublisherAction.getLabel(this.extension);
}
override update() { }

override async run(): Promise<any> {
if (!this.extension) {
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/contrib/extensions/browser/extensionsList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
import { Event } from 'vs/base/common/event';
import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
import { ManageExtensionAction, ReloadAction, ExtensionStatusLabelAction, RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtensionAction, SetLanguageAction, ClearLanguageAction, UpdateAction, ToggleAutoUpdateForExtensionAction, ToggleAutoUpdatesForPublisherAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { ManageExtensionAction, ReloadAction, ExtensionStatusLabelAction, RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtensionAction, SetLanguageAction, ClearLanguageAction, UpdateAction, ToggleAutoUpdateForExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, ExtensionPackCountWidget as ExtensionPackBadgeWidget, SyncIgnoredWidget, ExtensionHoverWidget, ExtensionActivationStatusWidget, PreReleaseBookmarkWidget, extensionVerifiedPublisherIconColor, VerifiedPublisherWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
import { IExtensionService, toExtension } from 'vs/workbench/services/extensions/common/extensions';
Expand Down Expand Up @@ -119,7 +119,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
this.instantiationService.createInstance(MigrateDeprecatedExtensionAction, true),
this.instantiationService.createInstance(ReloadAction),
this.instantiationService.createInstance(ActionWithDropDownAction, 'extensions.updateActions', '',
[[this.instantiationService.createInstance(UpdateAction, false)], [this.instantiationService.createInstance(ToggleAutoUpdateForExtensionAction), this.instantiationService.createInstance(ToggleAutoUpdatesForPublisherAction)]]),
[[this.instantiationService.createInstance(UpdateAction, false)], [this.instantiationService.createInstance(ToggleAutoUpdateForExtensionAction, true, [true, 'onlyEnabledExtensions'])]]),
this.instantiationService.createInstance(InstallDropdownAction),
this.instantiationService.createInstance(InstallingLabelAction),
this.instantiationService.createInstance(SetLanguageAction),
Expand Down
Loading

0 comments on commit 578ad35

Please sign in to comment.