Merge pull request #288944 from microsoft/mrleemurray/glorious-reindeer-silver

Refactor debug checkboxes to custom toggle components
This commit is contained in:
Lee Murray
2026-01-19 18:51:15 +00:00
committed by GitHub
2 changed files with 56 additions and 39 deletions
@@ -5,12 +5,12 @@
import * as dom from '../../../../base/browser/dom.js';
import { IKeyboardEvent } from '../../../../base/browser/keyboardEvent.js';
import { Gesture } from '../../../../base/browser/touch.js';
import { ActionBar } from '../../../../base/browser/ui/actionbar/actionbar.js';
import { AriaRole } from '../../../../base/browser/ui/aria/aria.js';
import { getDefaultHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js';
import { IconLabel } from '../../../../base/browser/ui/iconLabel/iconLabel.js';
import { InputBox } from '../../../../base/browser/ui/inputbox/inputBox.js';
import { Checkbox, TriStateCheckbox } from '../../../../base/browser/ui/toggle/toggle.js';
import { IListVirtualDelegate } from '../../../../base/browser/ui/list/list.js';
import { IListAccessibilityProvider } from '../../../../base/browser/ui/list/listWidget.js';
import { Orientation } from '../../../../base/browser/ui/splitview/splitview.js';
@@ -46,7 +46,7 @@ import { WorkbenchCompressibleObjectTree } from '../../../../platform/list/brows
import { INotificationService } from '../../../../platform/notification/common/notification.js';
import { IOpenerService } from '../../../../platform/opener/common/opener.js';
import { IQuickInputService } from '../../../../platform/quickinput/common/quickInput.js';
import { defaultInputBoxStyles } from '../../../../platform/theme/browser/defaultStyles.js';
import { defaultCheckboxStyles, defaultInputBoxStyles } from '../../../../platform/theme/browser/defaultStyles.js';
import { IThemeService } from '../../../../platform/theme/common/themeService.js';
import { ViewAction, ViewPane } from '../../../browser/parts/views/viewPane.js';
import { IViewletViewOptions } from '../../../browser/parts/views/viewsViewlet.js';
@@ -64,11 +64,10 @@ import { hasKey } from '../../../../base/common/types.js';
const $ = dom.$;
function createCheckbox(disposables: DisposableStore): HTMLInputElement {
const checkbox = <HTMLInputElement>$('input');
checkbox.type = 'checkbox';
checkbox.tabIndex = -1;
disposables.add(Gesture.ignoreTarget(checkbox));
function createCheckbox(disposables: DisposableStore): Checkbox {
const checkbox = new Checkbox('', false, defaultCheckboxStyles);
checkbox.domNode.tabIndex = -1;
disposables.add(checkbox);
return checkbox;
}
@@ -621,7 +620,7 @@ class BreakpointsDelegate implements IListVirtualDelegate<BreakpointTreeElement>
interface IBaseBreakpointTemplateData {
breakpoint: HTMLElement;
name: HTMLElement;
checkbox: HTMLInputElement;
checkbox: Checkbox;
context: BreakpointItem;
actionBar: ActionBar;
templateDisposables: DisposableStore;
@@ -656,7 +655,7 @@ interface IInstructionBreakpointTemplateData extends IBaseBreakpointWithIconTemp
interface IFunctionBreakpointInputTemplateData {
inputBox: InputBox;
checkbox: HTMLInputElement;
checkbox: Checkbox;
icon: HTMLElement;
breakpoint: IFunctionBreakpoint;
templateDisposables: DisposableStore;
@@ -667,7 +666,7 @@ interface IFunctionBreakpointInputTemplateData {
interface IDataBreakpointInputTemplateData {
inputBox: InputBox;
checkbox: HTMLInputElement;
checkbox: Checkbox;
icon: HTMLElement;
breakpoint: IDataBreakpoint;
elementDisposables: DisposableStore;
@@ -678,7 +677,7 @@ interface IDataBreakpointInputTemplateData {
interface IExceptionBreakpointInputTemplateData {
inputBox: InputBox;
checkbox: HTMLInputElement;
checkbox: Checkbox;
currentBreakpoint?: IExceptionBreakpoint;
templateDisposables: DisposableStore;
elementDisposables: DisposableStore;
@@ -686,7 +685,7 @@ interface IExceptionBreakpointInputTemplateData {
interface IBreakpointsFolderTemplateData {
container: HTMLElement;
checkbox: HTMLInputElement;
checkbox: TriStateCheckbox;
name: HTMLElement;
actionBar: ActionBar;
context: BreakpointsFolderItem;
@@ -723,15 +722,18 @@ class BreakpointsFolderRenderer implements ICompressibleTreeRenderer<Breakpoints
container.classList.remove('breakpoint', 'breakpoint-folder');
}));
data.checkbox = createCheckbox(data.templateDisposables);
data.templateDisposables.add(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {
const enabled = data.checkbox.checked;
data.checkbox = new TriStateCheckbox('', false, defaultCheckboxStyles);
data.checkbox.domNode.tabIndex = -1;
data.templateDisposables.add(data.checkbox);
data.templateDisposables.add(data.checkbox.onChange(() => {
const checked = data.checkbox.checked;
const enabled = checked === 'mixed' ? true : checked;
for (const bp of data.context.breakpoints) {
this.debugService.enableOrDisableBreakpoints(enabled, bp);
}
}));
dom.append(data.container, data.checkbox);
dom.append(data.container, data.checkbox.domNode);
data.name = dom.append(data.container, $('span.name'));
dom.append(data.container, $('span.file-path'));
@@ -753,10 +755,8 @@ class BreakpointsFolderRenderer implements ICompressibleTreeRenderer<Breakpoints
// Set checkbox state
if (folderItem.indeterminate) {
data.checkbox.checked = false;
data.checkbox.indeterminate = true;
data.checkbox.checked = 'mixed';
} else {
data.checkbox.indeterminate = false;
data.checkbox.checked = folderItem.enabled;
}
@@ -790,10 +790,8 @@ class BreakpointsFolderRenderer implements ICompressibleTreeRenderer<Breakpoints
// Set checkbox state
if (folderItem.indeterminate) {
data.checkbox.checked = false;
data.checkbox.indeterminate = true;
data.checkbox.checked = 'mixed';
} else {
data.checkbox.indeterminate = false;
data.checkbox.checked = folderItem.enabled;
}
@@ -863,12 +861,12 @@ class BreakpointsRenderer implements ICompressibleTreeRenderer<IBreakpoint, void
data.icon = $('.icon');
data.checkbox = createCheckbox(data.templateDisposables);
data.templateDisposables.add(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {
data.templateDisposables.add(data.checkbox.onChange(() => {
this.debugService.enableOrDisableBreakpoints(!data.context.enabled, data.context);
}));
dom.append(data.breakpoint, data.icon);
dom.append(data.breakpoint, data.checkbox);
dom.append(data.breakpoint, data.checkbox.domNode);
data.name = dom.append(data.breakpoint, $('span.name'));
@@ -1001,11 +999,11 @@ class ExceptionBreakpointsRenderer implements ICompressibleTreeRenderer<IExcepti
data.breakpoint = dom.append(container, $('.breakpoint'));
data.checkbox = createCheckbox(data.templateDisposables);
data.templateDisposables.add(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {
data.templateDisposables.add(data.checkbox.onChange(() => {
this.debugService.enableOrDisableBreakpoints(!data.context.enabled, data.context);
}));
dom.append(data.breakpoint, data.checkbox);
dom.append(data.breakpoint, data.checkbox.domNode);
data.name = dom.append(data.breakpoint, $('span.name'));
data.condition = dom.append(data.breakpoint, $('span.condition'));
@@ -1096,12 +1094,12 @@ class FunctionBreakpointsRenderer implements ICompressibleTreeRenderer<FunctionB
data.icon = $('.icon');
data.checkbox = createCheckbox(data.templateDisposables);
data.templateDisposables.add(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {
data.templateDisposables.add(data.checkbox.onChange(() => {
this.debugService.enableOrDisableBreakpoints(!data.context.enabled, data.context);
}));
dom.append(data.breakpoint, data.icon);
dom.append(data.breakpoint, data.checkbox);
dom.append(data.breakpoint, data.checkbox.domNode);
data.name = dom.append(data.breakpoint, $('span.name'));
data.condition = dom.append(data.breakpoint, $('span.condition'));
@@ -1201,12 +1199,12 @@ class DataBreakpointsRenderer implements ICompressibleTreeRenderer<DataBreakpoin
data.icon = $('.icon');
data.checkbox = createCheckbox(data.templateDisposables);
data.templateDisposables.add(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {
data.templateDisposables.add(data.checkbox.onChange(() => {
this.debugService.enableOrDisableBreakpoints(!data.context.enabled, data.context);
}));
dom.append(data.breakpoint, data.icon);
dom.append(data.breakpoint, data.checkbox);
dom.append(data.breakpoint, data.checkbox.domNode);
data.name = dom.append(data.breakpoint, $('span.name'));
data.accessType = dom.append(data.breakpoint, $('span.access-type'));
@@ -1311,12 +1309,12 @@ class InstructionBreakpointsRenderer implements ICompressibleTreeRenderer<IInstr
data.icon = $('.icon');
data.checkbox = createCheckbox(data.templateDisposables);
data.templateDisposables.add(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {
data.templateDisposables.add(data.checkbox.onChange(() => {
this.debugService.enableOrDisableBreakpoints(!data.context.enabled, data.context);
}));
dom.append(data.breakpoint, data.icon);
dom.append(data.breakpoint, data.checkbox);
dom.append(data.breakpoint, data.checkbox.domNode);
data.name = dom.append(data.breakpoint, $('span.name'));
@@ -1400,7 +1398,7 @@ class FunctionBreakpointInputRenderer implements ICompressibleTreeRenderer<IFunc
template.checkbox = createCheckbox(toDispose);
dom.append(breakpoint, template.icon);
dom.append(breakpoint, template.checkbox);
dom.append(breakpoint, template.checkbox.domNode);
this.view.breakpointInputFocused.set(true);
const inputBoxContainer = dom.append(breakpoint, $('.inputBoxContainer'));
@@ -1468,7 +1466,7 @@ class FunctionBreakpointInputRenderer implements ICompressibleTreeRenderer<IFunc
data.icon.className = ThemeIcon.asClassName(icon);
data.elementDisposables.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), data.icon, message ? message : ''));
data.checkbox.checked = functionBreakpoint.enabled;
data.checkbox.disabled = true;
data.checkbox.disable();
data.inputBox.value = functionBreakpoint.name || '';
let placeholder = localize('functionBreakpointPlaceholder', "Function to break on");
@@ -1533,7 +1531,7 @@ class DataBreakpointInputRenderer implements ICompressibleTreeRenderer<IDataBrea
template.checkbox = createCheckbox(toDispose);
dom.append(breakpoint, template.icon);
dom.append(breakpoint, template.checkbox);
dom.append(breakpoint, template.checkbox.domNode);
this.view.breakpointInputFocused.set(true);
const inputBoxContainer = dom.append(breakpoint, $('.inputBoxContainer'));
@@ -1593,7 +1591,7 @@ class DataBreakpointInputRenderer implements ICompressibleTreeRenderer<IDataBrea
data.icon.className = ThemeIcon.asClassName(icon);
data.elementDisposables.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), data.icon, message ?? ''));
data.checkbox.checked = dataBreakpoint.enabled;
data.checkbox.disabled = true;
data.checkbox.disable();
data.inputBox.value = '';
let placeholder = '';
let ariaLabel = '';
@@ -1655,7 +1653,7 @@ class ExceptionBreakpointInputRenderer implements ICompressibleTreeRenderer<IExc
breakpoint.classList.add('exception');
const checkbox = createCheckbox(toDispose);
dom.append(breakpoint, checkbox);
dom.append(breakpoint, checkbox.domNode);
this.view.breakpointInputFocused.set(true);
const inputBoxContainer = dom.append(breakpoint, $('.inputBoxContainer'));
const inputBox = new InputBox(inputBoxContainer, this.contextViewService, {
@@ -1713,7 +1711,7 @@ class ExceptionBreakpointInputRenderer implements ICompressibleTreeRenderer<IExc
data.inputBox.setPlaceHolder(placeHolder);
data.currentBreakpoint = exceptionBreakpoint;
data.checkbox.checked = exceptionBreakpoint.enabled;
data.checkbox.disabled = true;
data.checkbox.disable();
data.inputBox.value = exceptionBreakpoint.condition || '';
setTimeout(() => {
data.inputBox.focus();
@@ -306,8 +306,27 @@
margin-left: 0;
}
.debug-pane .debug-breakpoints .breakpoint input {
.debug-pane .debug-breakpoints .breakpoint .monaco-custom-toggle {
flex-shrink: 0;
margin-left: 0;
margin-right: 4px;
}
.debug-pane .debug-breakpoints .breakpoint .monaco-custom-toggle.monaco-checkbox {
width: 18px;
min-width: 18px;
max-width: 18px;
height: 18px;
padding: 0;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.debug-pane .debug-breakpoints .breakpoint .monaco-custom-toggle.monaco-checkbox::before {
margin: 0;
}
.debug-pane .debug-breakpoints .breakpoint > .codicon {