Fix dropdown error & editor database dropdown validation (#14946)

* Fix dropdown error & editor database dropdown validation

* Set initial values

* Update comment

* hygiene

* remove unused

* Fix tests
This commit is contained in:
Charles Gagnon
2021-04-01 14:52:55 -07:00
committed by GitHub
parent a00ffa0469
commit ce6ea8af41
4 changed files with 49 additions and 46 deletions

View File

@@ -13,7 +13,6 @@ import { IMessage, MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { IListStyles, List } from 'vs/base/browser/ui/list/listWidget'; import { IListStyles, List } from 'vs/base/browser/ui/list/listWidget';
import { Color } from 'vs/base/common/color'; import { Color } from 'vs/base/common/color';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event'; import { Emitter, Event } from 'vs/base/common/event';
import { KeyCode } from 'vs/base/common/keyCodes'; import { KeyCode } from 'vs/base/common/keyCodes';
import { Disposable } from 'vs/base/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle';
@@ -221,7 +220,7 @@ export class Dropdown extends Disposable implements IListVirtualDelegate<string>
})); }));
this._input.onDidChange(e => { this._input.onDidChange(e => {
if (this._dataSource.values?.length > 0) { if (this._dataSource.values.length > 0) {
this._dataSource.filter = e; this._dataSource.filter = e;
if (this._isDropDownVisible) { if (this._isDropDownVisible) {
this._updateDropDownList(); this._updateDropDownList();
@@ -297,25 +296,21 @@ export class Dropdown extends Disposable implements IListVirtualDelegate<string>
} }
private _updateDropDownList(): void { private _updateDropDownList(): void {
try { this._selectList.splice(0, this._selectList.length, this._dataSource.filteredValues.map(v => { return { text: v }; }));
this._selectList.splice(0, this._selectList.length, this._dataSource.filteredValues.map(v => { return { text: v }; }));
} catch (e) {
onUnexpectedError(e);
}
let width = this._inputContainer.clientWidth; let width = this._inputContainer.clientWidth;
if (this._dataSource && this._dataSource.filteredValues) {
const longestOption = this._dataSource.filteredValues.reduce((previous, current) => {
return previous.length > current.length ? previous : current;
}, '');
this._widthControlElement.innerText = longestOption;
const inputContainerWidth = DOM.getContentWidth(this._inputContainer); // Find the longest option in the list and set our width to that (max 500px)
const longestOptionWidth = DOM.getTotalWidth(this._widthControlElement); const longestOption = this._dataSource.filteredValues.reduce((previous, current) => {
width = clamp(longestOptionWidth, inputContainerWidth, 500); return previous.length > current.length ? previous : current;
} }, '');
this._widthControlElement.innerText = longestOption;
const height = Math.min((this._dataSource.filteredValues?.length ?? 0) * this.getHeight(), this._options.maxHeight ?? 500); const inputContainerWidth = DOM.getContentWidth(this._inputContainer);
const longestOptionWidth = DOM.getTotalWidth(this._widthControlElement);
width = clamp(longestOptionWidth, inputContainerWidth, 500);
const height = Math.min(this._dataSource.filteredValues.length * this.getHeight(), this._options.maxHeight ?? 500);
this._selectListContainer.style.width = `${width}px`; this._selectListContainer.style.width = `${width}px`;
this._selectListContainer.style.height = `${height}px`; this._selectListContainer.style.height = `${height}px`;
this._selectList.layout(height, width); this._selectList.layout(height, width);
@@ -361,7 +356,7 @@ export class Dropdown extends Disposable implements IListVirtualDelegate<string>
} }
private _inputValidator(value: string): IMessage | null { private _inputValidator(value: string): IMessage | null {
if (!this._input.hasFocus() && !this._selectList.isDOMFocused() && this._dataSource.values && !this._dataSource.values.some(i => i === value)) { if (!this._input.hasFocus() && this._input.isEnabled() && !this._selectList.isDOMFocused() && !this._dataSource.values.some(i => i === value)) {
if (this._options.strictSelection && this._options.errorMessage) { if (this._options.strictSelection && this._options.errorMessage) {
return { return {
content: this._options.errorMessage, content: this._options.errorMessage,

View File

@@ -42,9 +42,9 @@ export class DropdownListRenderer implements IListRenderer<IDropdownListItem, ID
} }
export class DropdownDataSource { export class DropdownDataSource {
values: string[]; public values: string[] = [];
filter: string | undefined; public filter: string | undefined = undefined;
public get filteredValues(): string[] { public get filteredValues(): string[] {
if (this.filter) { if (this.filter) {

View File

@@ -44,6 +44,7 @@ import { ConnectionProfile } from 'sql/platform/connection/common/connectionProf
import { IQueryManagementService } from 'sql/workbench/services/query/common/queryManagement'; import { IQueryManagementService } from 'sql/workbench/services/query/common/queryManagement';
import { ILogService } from 'vs/platform/log/common/log'; import { ILogService } from 'vs/platform/log/common/log';
import { IRange } from 'vs/editor/common/core/range'; import { IRange } from 'vs/editor/common/core/range';
import { onUnexpectedError } from 'vs/base/common/errors';
/** /**
* Action class that query-based Actions will extend. This base class automatically handles activating and * Action class that query-based Actions will extend. This base class automatically handles activating and
@@ -761,48 +762,54 @@ export class ListDatabasesActionItem extends Disposable implements IActionViewIt
} }
private onDropdownFocus(): void { private onDropdownFocus(): void {
this.getDatabaseNames().then(databaseNames => {
this._dropdown.values = databaseNames;
}).catch(onUnexpectedError);
}
/**
* Fetches the list of database names from the current editor connection
* @returns The list of database names
*/
private async getDatabaseNames(): Promise<string[]> {
if (!this._editor.input) { if (!this._editor.input) {
this.logService.error('editor input was null'); this.logService.error('editor input was null');
return; return [];
} }
let uri = this._editor.input.uri; let uri = this._editor.input.uri;
if (!uri) { if (!uri) {
return; return [];
} }
try {
this.connectionManagementService.listDatabases(uri) const result = await this.connectionManagementService.listDatabases(uri);
.then(result => { return result.databaseNames;
if (result && result.databaseNames) { } catch (err) {
this._dropdown.values = result.databaseNames; this.logService.error(`Error loading database names for query editor `, err);
} }
}); return [];
} }
private updateConnection(databaseName: string) { private updateConnection(databaseName: string): void {
this._isConnected = true; this._isConnected = true;
this._currentDatabaseName = databaseName; this._currentDatabaseName = databaseName;
if (this._isInAccessibilityMode) { if (this._isInAccessibilityMode) {
this._databaseSelectBox.enable(); this.getDatabaseNames()
if (!this._editor.input) { .then(databaseNames => {
this.logService.error('editor input was null'); this._databaseSelectBox.setOptions(databaseNames);
return;
}
let uri = this._editor.input.uri;
if (!uri) {
return;
}
this.connectionManagementService.listDatabases(uri)
.then(result => {
if (result && result.databaseNames) {
this._databaseSelectBox.setOptions(result.databaseNames);
}
this._databaseSelectBox.selectWithOptionName(databaseName); this._databaseSelectBox.selectWithOptionName(databaseName);
}); }).catch(onUnexpectedError);
} else { } else {
this._dropdown.enabled = true; // Set the value immediately to the initial database so the user can see that, and then
// populate the list with just that value to avoid displaying an error while we load
// the full list of databases
this._dropdown.value = databaseName; this._dropdown.value = databaseName;
this._dropdown.values = [databaseName];
this._dropdown.enabled = true;
this.getDatabaseNames().then(databaseNames => {
this._dropdown.values = databaseNames;
}).catch(onUnexpectedError);
} }
} }

View File

@@ -68,6 +68,7 @@ suite('SQL QueryAction Tests', () => {
queryModelService.setup(q => q.onRunQueryComplete).returns(() => Event.None); queryModelService.setup(q => q.onRunQueryComplete).returns(() => Event.None);
connectionManagementService = TypeMoq.Mock.ofType<TestConnectionManagementService>(TestConnectionManagementService); connectionManagementService = TypeMoq.Mock.ofType<TestConnectionManagementService>(TestConnectionManagementService);
connectionManagementService.setup(q => q.onDisconnect).returns(() => Event.None); connectionManagementService.setup(q => q.onDisconnect).returns(() => Event.None);
connectionManagementService.setup(q => q.listDatabases(TypeMoq.It.isAny())).returns(() => Promise.resolve({ databaseNames: ['master', 'msdb', 'model'] }));
const workbenchinstantiationService = workbenchInstantiationService(); const workbenchinstantiationService = workbenchInstantiationService();
const accessor = workbenchinstantiationService.createInstance(ServiceAccessor); const accessor = workbenchinstantiationService.createInstance(ServiceAccessor);
const service = accessor.untitledTextEditorService; const service = accessor.untitledTextEditorService;