mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
table designer bug fixes (#18701)
* table designer bug fixes * pr comments * fix debounce issue
This commit is contained in:
@@ -10,12 +10,16 @@ import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview
|
|||||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||||
import * as DOM from 'vs/base/browser/dom';
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
import { Dropdown } from 'sql/base/browser/ui/editableDropdown/browser/dropdown';
|
import { Dropdown } from 'sql/base/browser/ui/editableDropdown/browser/dropdown';
|
||||||
|
import { debounce } from 'vs/base/common/decorators';
|
||||||
|
import { Event } from 'vs/base/common/event';
|
||||||
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
|
||||||
export interface ITableCellEditorOptions {
|
export interface ITableCellEditorOptions {
|
||||||
valueGetter?: (item: Slick.SlickData, column: Slick.Column<Slick.SlickData>) => string,
|
valueGetter?: (item: Slick.SlickData, column: Slick.Column<Slick.SlickData>) => string,
|
||||||
valueSetter?: (context: any, row: number, item: Slick.SlickData, column: Slick.Column<Slick.SlickData>, value: string) => void,
|
valueSetter?: (context: any, row: number, item: Slick.SlickData, column: Slick.Column<Slick.SlickData>, value: string) => void,
|
||||||
optionsGetter?: (item: Slick.SlickData, column: Slick.Column<Slick.SlickData>) => string[],
|
optionsGetter?: (item: Slick.SlickData, column: Slick.Column<Slick.SlickData>) => string[],
|
||||||
editorStyler: (component: InputBox | SelectBox | Dropdown) => void
|
editorStyler: (component: InputBox | SelectBox | Dropdown) => void,
|
||||||
|
onStyleChange: Event<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TableCellEditorFactory {
|
export class TableCellEditorFactory {
|
||||||
@@ -32,18 +36,20 @@ export class TableCellEditorFactory {
|
|||||||
optionsGetter: options.optionsGetter ?? function (item, column) {
|
optionsGetter: options.optionsGetter ?? function (item, column) {
|
||||||
return [];
|
return [];
|
||||||
},
|
},
|
||||||
editorStyler: options.editorStyler
|
editorStyler: options.editorStyler,
|
||||||
|
onStyleChange: options.onStyleChange
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTextEditorClass(context: any, inputType: 'text' | 'number' = 'text'): any {
|
public getTextEditorClass(context: any, inputType: 'text' | 'number' = 'text'): any {
|
||||||
const self = this;
|
const self = this;
|
||||||
class TextEditor {
|
class TextEditor extends Disposable {
|
||||||
private _originalValue: string;
|
private _originalValue: string;
|
||||||
private _input: InputBox;
|
private _input: InputBox;
|
||||||
private _keyCaptureList: number[];
|
private _keyCaptureList: number[];
|
||||||
|
|
||||||
constructor(private _args: Slick.Editors.EditorOptions<Slick.SlickData>) {
|
constructor(private _args: Slick.Editors.EditorOptions<Slick.SlickData>) {
|
||||||
|
super();
|
||||||
this.init();
|
this.init();
|
||||||
const keycodesToCapture = [KeyCode.Home, KeyCode.End, KeyCode.UpArrow, KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow];
|
const keycodesToCapture = [KeyCode.Home, KeyCode.End, KeyCode.UpArrow, KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow];
|
||||||
this._keyCaptureList = keycodesToCapture.map(keycode => getCodeForKeyCode(keycode));
|
this._keyCaptureList = keycodesToCapture.map(keycode => getCodeForKeyCode(keycode));
|
||||||
@@ -63,10 +69,26 @@ export class TableCellEditorFactory {
|
|||||||
self._options.editorStyler(this._input);
|
self._options.editorStyler(this._input);
|
||||||
this._input.element.style.height = '100%';
|
this._input.element.style.height = '100%';
|
||||||
this._input.focus();
|
this._input.focus();
|
||||||
|
this._input.onDidChange(async () => {
|
||||||
|
await this.commitEdit();
|
||||||
|
});
|
||||||
|
this._register(this._input);
|
||||||
|
this._register(self._options.onStyleChange(() => {
|
||||||
|
self._options.editorStyler(this._input);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@debounce(200)
|
||||||
|
private async commitEdit(): Promise<void> {
|
||||||
|
if (this.isValueChanged()) {
|
||||||
|
const item = this._args.grid.getDataItem(this._args.grid.getActiveCell().row);
|
||||||
|
await this.applyValue(item, this._input.value);
|
||||||
|
this._originalValue = this._input.value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy(): void {
|
public destroy(): void {
|
||||||
this._input.dispose();
|
this.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public focus(): void {
|
public focus(): void {
|
||||||
@@ -84,8 +106,7 @@ export class TableCellEditorFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public isValueChanged(): boolean {
|
public isValueChanged(): boolean {
|
||||||
return this._input.value !== this._originalValue.toString();
|
return this._input.value !== this._originalValue;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public serializeValue(): any {
|
public serializeValue(): any {
|
||||||
@@ -104,13 +125,13 @@ export class TableCellEditorFactory {
|
|||||||
|
|
||||||
public getDropdownEditorClass(context: any, defaultOptions: string[], isEditable?: boolean): any {
|
public getDropdownEditorClass(context: any, defaultOptions: string[], isEditable?: boolean): any {
|
||||||
const self = this;
|
const self = this;
|
||||||
class TextEditor {
|
class DropdownEditor extends Disposable {
|
||||||
private _originalValue: string;
|
private _originalValue: string;
|
||||||
private _selectBox: SelectBox;
|
private _component: SelectBox | Dropdown;
|
||||||
private _dropdown: Dropdown;
|
|
||||||
private _keyCaptureList: number[];
|
private _keyCaptureList: number[];
|
||||||
|
|
||||||
constructor(private _args: Slick.Editors.EditorOptions<Slick.SlickData>) {
|
constructor(private _args: Slick.Editors.EditorOptions<Slick.SlickData>) {
|
||||||
|
super();
|
||||||
this.init();
|
this.init();
|
||||||
const keycodesToCapture = [KeyCode.Home, KeyCode.End, KeyCode.UpArrow, KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow];
|
const keycodesToCapture = [KeyCode.Home, KeyCode.End, KeyCode.UpArrow, KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow];
|
||||||
this._keyCaptureList = keycodesToCapture.map(keycode => getCodeForKeyCode(keycode));
|
this._keyCaptureList = keycodesToCapture.map(keycode => getCodeForKeyCode(keycode));
|
||||||
@@ -126,37 +147,43 @@ export class TableCellEditorFactory {
|
|||||||
public init(): void {
|
public init(): void {
|
||||||
const container = DOM.$('');
|
const container = DOM.$('');
|
||||||
this._args.container.appendChild(container);
|
this._args.container.appendChild(container);
|
||||||
|
container.style.height = '100%';
|
||||||
|
container.style.width = '100%';
|
||||||
if (isEditable) {
|
if (isEditable) {
|
||||||
this._dropdown = new Dropdown(container, self._contextViewProvider);
|
this._component = new Dropdown(container, self._contextViewProvider);
|
||||||
container.style.height = '100%';
|
this._component.onValueChange(async () => {
|
||||||
container.style.width = '100%';
|
await this.commitEdit();
|
||||||
self._options.editorStyler(this._dropdown);
|
});
|
||||||
this._dropdown.focus();
|
|
||||||
} else {
|
} else {
|
||||||
this._selectBox = new SelectBox([], undefined, self._contextViewProvider);
|
this._component = new SelectBox([], undefined, self._contextViewProvider);
|
||||||
container.style.height = '100%';
|
this._component.render(container);
|
||||||
container.style.width = '100%';
|
this._component.selectElem.style.height = '100%';
|
||||||
this._selectBox.render(container);
|
this._component.onDidSelect(async () => {
|
||||||
this._selectBox.selectElem.style.height = '100%';
|
await this.commitEdit();
|
||||||
self._options.editorStyler(this._selectBox);
|
});
|
||||||
this._selectBox.focus();
|
}
|
||||||
|
self._options.editorStyler(this._component);
|
||||||
|
this._component.focus();
|
||||||
|
this._register(this._component);
|
||||||
|
this._register(self._options.onStyleChange(() => {
|
||||||
|
self._options.editorStyler(this._component);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async commitEdit(): Promise<void> {
|
||||||
|
if (this.isValueChanged()) {
|
||||||
|
const item = this._args.grid.getDataItem(this._args.grid.getActiveCell().row);
|
||||||
|
await this.applyValue(item, this._component.value);
|
||||||
|
this._originalValue = this._component.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy(): void {
|
public destroy(): void {
|
||||||
if (isEditable) {
|
this.dispose();
|
||||||
this._dropdown.dispose();
|
|
||||||
} else {
|
|
||||||
this._selectBox.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public focus(): void {
|
public focus(): void {
|
||||||
if (isEditable) {
|
this._component.focus();
|
||||||
this._dropdown.focus();
|
|
||||||
} else {
|
|
||||||
this._selectBox.focus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public loadValue(item: Slick.SlickData): void {
|
public loadValue(item: Slick.SlickData): void {
|
||||||
@@ -164,12 +191,12 @@ export class TableCellEditorFactory {
|
|||||||
const options = self._options.optionsGetter(item, this._args.column) ?? defaultOptions;
|
const options = self._options.optionsGetter(item, this._args.column) ?? defaultOptions;
|
||||||
const idx = options?.indexOf(this._originalValue);
|
const idx = options?.indexOf(this._originalValue);
|
||||||
if (idx > -1) {
|
if (idx > -1) {
|
||||||
if (isEditable) {
|
if (this._component instanceof Dropdown) {
|
||||||
this._dropdown.values = options;
|
this._component.values = options;
|
||||||
this._dropdown.value = options[idx];
|
this._component.value = options[idx];
|
||||||
} else {
|
} else {
|
||||||
this._selectBox.setOptions(options);
|
this._component.setOptions(options);
|
||||||
this._selectBox.select(idx);
|
this._component.select(idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,19 +207,11 @@ export class TableCellEditorFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public isValueChanged(): boolean {
|
public isValueChanged(): boolean {
|
||||||
if (isEditable) {
|
return this._component.value !== this._originalValue;
|
||||||
return this._dropdown.value !== this._originalValue.toString();
|
|
||||||
} else {
|
|
||||||
return this._selectBox.value !== this._originalValue.toString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public serializeValue(): any {
|
public serializeValue(): any {
|
||||||
if (isEditable) {
|
return this._component.value;
|
||||||
return this._dropdown.value;
|
|
||||||
} else {
|
|
||||||
return this._selectBox.value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public validate(): Slick.ValidateResults {
|
public validate(): Slick.ValidateResults {
|
||||||
@@ -202,6 +221,6 @@ export class TableCellEditorFactory {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return TextEditor;
|
return DropdownEditor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
from 'sql/workbench/browser/designer/interfaces';
|
from 'sql/workbench/browser/designer/interfaces';
|
||||||
import { IPanelTab, ITabbedPanelStyles, TabbedPanel } from 'sql/base/browser/ui/panel/panel';
|
import { IPanelTab, ITabbedPanelStyles, TabbedPanel } from 'sql/base/browser/ui/panel/panel';
|
||||||
import * as DOM from 'vs/base/browser/dom';
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
import { Orientation, Sizing, SplitView } from 'vs/base/browser/ui/splitview/splitview';
|
import { Orientation, Sizing, SplitView } from 'vs/base/browser/ui/splitview/splitview';
|
||||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
import { IInputBoxStyles, InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
|
import { IInputBoxStyles, InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
|
||||||
@@ -45,6 +45,7 @@ import { alert } from 'vs/base/browser/ui/aria/aria';
|
|||||||
import { layoutDesignerTable, TableHeaderRowHeight, TableRowHeight } from 'sql/workbench/browser/designer/designerTableUtil';
|
import { layoutDesignerTable, TableHeaderRowHeight, TableRowHeight } from 'sql/workbench/browser/designer/designerTableUtil';
|
||||||
import { Dropdown, IDropdownStyles } from 'sql/base/browser/ui/editableDropdown/browser/dropdown';
|
import { Dropdown, IDropdownStyles } from 'sql/base/browser/ui/editableDropdown/browser/dropdown';
|
||||||
import { IListStyles } from 'vs/base/browser/ui/list/listWidget';
|
import { IListStyles } from 'vs/base/browser/ui/list/listWidget';
|
||||||
|
import { debounce } from 'vs/base/common/decorators';
|
||||||
|
|
||||||
export interface IDesignerStyle {
|
export interface IDesignerStyle {
|
||||||
tabbedPanelStyles?: ITabbedPanelStyles;
|
tabbedPanelStyles?: ITabbedPanelStyles;
|
||||||
@@ -96,6 +97,7 @@ export class Designer extends Disposable implements IThemable {
|
|||||||
private _groupHeaders: HTMLElement[] = [];
|
private _groupHeaders: HTMLElement[] = [];
|
||||||
private _messagesView: DesignerMessagesTabPanelView;
|
private _messagesView: DesignerMessagesTabPanelView;
|
||||||
private _scriptEditorView: DesignerScriptEditorTabPanelView;
|
private _scriptEditorView: DesignerScriptEditorTabPanelView;
|
||||||
|
private _onStyleChangeEventEmitter = new Emitter<void>();
|
||||||
|
|
||||||
constructor(private readonly _container: HTMLElement,
|
constructor(private readonly _container: HTMLElement,
|
||||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||||
@@ -122,7 +124,8 @@ export class Designer extends Disposable implements IThemable {
|
|||||||
},
|
},
|
||||||
editorStyler: (component) => {
|
editorStyler: (component) => {
|
||||||
this.styleComponent(component);
|
this.styleComponent(component);
|
||||||
}
|
},
|
||||||
|
onStyleChange: this._onStyleChangeEventEmitter.event
|
||||||
}, this._contextViewProvider
|
}, this._contextViewProvider
|
||||||
);
|
);
|
||||||
this._loadingSpinner = new LoadingSpinner(this._container, { showText: true, fullSize: true });
|
this._loadingSpinner = new LoadingSpinner(this._container, { showText: true, fullSize: true });
|
||||||
@@ -254,6 +257,7 @@ export class Designer extends Disposable implements IThemable {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this._propertiesPane.descriptionElement.style.borderColor = styles.paneSeparator.toString();
|
this._propertiesPane.descriptionElement.style.borderColor = styles.paneSeparator.toString();
|
||||||
|
this._onStyleChangeEventEmitter.fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
public layout(dimension: DOM.Dimension) {
|
public layout(dimension: DOM.Dimension) {
|
||||||
@@ -718,9 +722,11 @@ export class Designer extends Disposable implements IThemable {
|
|||||||
ariaLabel: inputProperties.title,
|
ariaLabel: inputProperties.title,
|
||||||
type: inputProperties.inputType,
|
type: inputProperties.inputType,
|
||||||
});
|
});
|
||||||
input.onLoseFocus((args) => {
|
input.onDidChange(() => {
|
||||||
if (args.hasChanged) {
|
// The supress edit processing check is done in the handleEdit method, but since we have debounce operation on input box we
|
||||||
this.handleEdit({ type: DesignerEditType.Update, path: propertyPath, value: args.value, source: view });
|
// have to do it here to avoid treating system originated value setting operation as user edits.
|
||||||
|
if (!this._supressEditProcessing) {
|
||||||
|
this.handleInputBoxEdit({ type: DesignerEditType.Update, path: propertyPath, value: input.value, source: view });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
input.onInputFocus(() => {
|
input.onInputFocus(() => {
|
||||||
@@ -937,6 +943,11 @@ export class Designer extends Disposable implements IThemable {
|
|||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@debounce(200)
|
||||||
|
private handleInputBoxEdit(edit: DesignerEdit) {
|
||||||
|
this.handleEdit(edit);
|
||||||
|
}
|
||||||
|
|
||||||
private startLoading(message: string, timeout: number): void {
|
private startLoading(message: string, timeout: number): void {
|
||||||
this._loadingTimeoutHandle = setTimeout(() => {
|
this._loadingTimeoutHandle = setTimeout(() => {
|
||||||
this._loadingSpinner.loadingMessage = message;
|
this._loadingSpinner.loadingMessage = message;
|
||||||
|
|||||||
Reference in New Issue
Block a user