table designer validation support (#18438)

* table designer validation

* vbump sts
This commit is contained in:
Alan Ren
2022-02-17 13:07:19 -08:00
committed by GitHub
parent e66192cbfd
commit 28ab7372d2
11 changed files with 186 additions and 72 deletions

View File

@@ -1,6 +1,6 @@
{ {
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
"version": "3.0.0-release.204", "version": "3.0.0-release.206",
"downloadFileNames": { "downloadFileNames": {
"Windows_86": "win-x86-net6.0.zip", "Windows_86": "win-x86-net6.0.zip",
"Windows_64": "win-x64-net6.0.zip", "Windows_64": "win-x64-net6.0.zip",

View File

@@ -1425,7 +1425,7 @@ declare module 'azdata' {
/** /**
* Error messages of current state, and the property the caused the error. * Error messages of current state, and the property the caused the error.
*/ */
errors?: { message: string, property?: DesignerEditPath }[]; errors?: { message: string, propertyPath?: DesignerEditPath }[];
} }
/** /**

View File

@@ -120,8 +120,8 @@ export class TabbedPanel extends Disposable {
this._styleElement.remove(); this._styleElement.remove();
} }
public contains(tab: IPanelTab): boolean { public contains(tabId: string): boolean {
return this._tabMap.has(tab.identifier); return this._tabMap.has(tabId);
} }
public pushTab(tab: IPanelTab, index?: number, destroyTabBody?: boolean): PanelTabIdentifier { public pushTab(tab: IPanelTab, index?: number, destroyTabBody?: boolean): PanelTabIdentifier {

View File

@@ -6,7 +6,7 @@
import { import {
DesignerComponentInput, DesignerEditType, DesignerTab, DesignerEdit, DesignerEditPath, DesignerViewModel, DesignerDataPropertyInfo, DesignerComponentInput, DesignerEditType, DesignerTab, DesignerEdit, DesignerEditPath, DesignerViewModel, DesignerDataPropertyInfo,
DesignerTableComponentRowData, DesignerTableProperties, InputBoxProperties, DropDownProperties, CheckBoxProperties, DesignerTableComponentRowData, DesignerTableProperties, InputBoxProperties, DropDownProperties, CheckBoxProperties,
DesignerEditProcessedEventArgs, DesignerStateChangedEventArgs, DesignerAction, DesignerUIState, DesignerTextEditor, ScriptProperty, DesignerRootObjectPath DesignerEditProcessedEventArgs, DesignerStateChangedEventArgs, DesignerAction, DesignerUIState, ScriptProperty, DesignerRootObjectPath
} }
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';
@@ -34,9 +34,10 @@ import { Color } from 'vs/base/common/color';
import { LoadingSpinner } from 'sql/base/browser/ui/loadingSpinner/loadingSpinner'; import { LoadingSpinner } from 'sql/base/browser/ui/loadingSpinner/loadingSpinner';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { DesignerScriptEditor } from 'sql/workbench/browser/designer/designerScriptEditor';
import { INotificationService } from 'vs/platform/notification/common/notification'; import { INotificationService } from 'vs/platform/notification/common/notification';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { DesignerMessagesTabPanelView } from 'sql/workbench/browser/designer/designerMessagesTabPanelView';
import { DesignerScriptEditorTabPanelView } from 'sql/workbench/browser/designer/designerScriptEditorTabPanelView';
export interface IDesignerStyle { export interface IDesignerStyle {
tabbedPanelStyles?: ITabbedPanelStyles; tabbedPanelStyles?: ITabbedPanelStyles;
@@ -56,6 +57,8 @@ export type SetComponentValueFunc = (definition: DesignerDataPropertyInfo, compo
const TableRowHeight = 25; const TableRowHeight = 25;
const TableHeaderRowHeight = 28; const TableHeaderRowHeight = 28;
const ScriptTabId = 'scripts';
const MessagesTabId = 'messages';
type DesignerUIArea = 'PropertiesView' | 'ScriptView' | 'TopContentView' | 'TabsView'; type DesignerUIArea = 'PropertiesView' | 'ScriptView' | 'TopContentView' | 'TabsView';
@@ -67,7 +70,8 @@ export class Designer extends Disposable implements IThemable {
private _editorContainer: HTMLElement; private _editorContainer: HTMLElement;
private _horizontalSplitView: SplitView; private _horizontalSplitView: SplitView;
private _verticalSplitView: SplitView; private _verticalSplitView: SplitView;
private _tabbedPanel: TabbedPanel; private _contentTabbedPanel: TabbedPanel;
private _scriptTabbedPannel: TabbedPanel;
private _contentContainer: HTMLElement; private _contentContainer: HTMLElement;
private _topContentContainer: HTMLElement; private _topContentContainer: HTMLElement;
private _propertiesPaneContainer: HTMLElement; private _propertiesPaneContainer: HTMLElement;
@@ -81,7 +85,8 @@ export class Designer extends Disposable implements IThemable {
private _inputDisposable: DisposableStore; private _inputDisposable: DisposableStore;
private _loadingTimeoutHandle: any; private _loadingTimeoutHandle: any;
private _groupHeaders: HTMLElement[] = []; private _groupHeaders: HTMLElement[] = [];
private _textEditor: DesignerTextEditor; private _messagesView: DesignerMessagesTabPanelView;
private _scriptEditorView: DesignerScriptEditorTabPanelView;
constructor(private readonly _container: HTMLElement, constructor(private readonly _container: HTMLElement,
@IInstantiationService private readonly _instantiationService: IInstantiationService, @IInstantiationService private readonly _instantiationService: IInstantiationService,
@@ -119,7 +124,7 @@ export class Designer extends Disposable implements IThemable {
this._propertiesPaneContainer = DOM.$('.properties-container'); this._propertiesPaneContainer = DOM.$('.properties-container');
this._verticalSplitView = new SplitView(this._verticalSplitViewContainer, { orientation: Orientation.VERTICAL }); this._verticalSplitView = new SplitView(this._verticalSplitViewContainer, { orientation: Orientation.VERTICAL });
this._horizontalSplitView = new SplitView(this._horizontalSplitViewContainer, { orientation: Orientation.HORIZONTAL }); this._horizontalSplitView = new SplitView(this._horizontalSplitViewContainer, { orientation: Orientation.HORIZONTAL });
this._tabbedPanel = new TabbedPanel(this._tabbedPanelContainer); this._contentTabbedPanel = new TabbedPanel(this._tabbedPanelContainer);
this._container.appendChild(this._verticalSplitViewContainer); this._container.appendChild(this._verticalSplitViewContainer);
this._contentContainer.appendChild(this._topContentContainer); this._contentContainer.appendChild(this._topContentContainer);
this._contentContainer.appendChild(this._tabbedPanelContainer); this._contentContainer.appendChild(this._tabbedPanelContainer);
@@ -132,11 +137,18 @@ export class Designer extends Disposable implements IThemable {
maximumSize: Number.POSITIVE_INFINITY, maximumSize: Number.POSITIVE_INFINITY,
onDidChange: Event.None onDidChange: Event.None
}, Sizing.Distribute); }, Sizing.Distribute);
this._textEditor = this._instantiationService.createInstance(DesignerScriptEditor, this._editorContainer); this._scriptTabbedPannel = new TabbedPanel(this._editorContainer);
this._messagesView = new DesignerMessagesTabPanelView();
this._scriptEditorView = new DesignerScriptEditorTabPanelView(this._instantiationService);
this._scriptTabbedPannel.pushTab({
title: localize('designer.scriptTabTitle', "Scripts"),
identifier: ScriptTabId,
view: this._scriptEditorView
});
this._verticalSplitView.addView({ this._verticalSplitView.addView({
element: this._editorContainer, element: this._editorContainer,
layout: size => { layout: size => {
this._textEditor.layout(new DOM.Dimension(this._editorContainer.clientWidth, size)); this._scriptTabbedPannel.layout(new DOM.Dimension(this._editorContainer.clientWidth, size - this._scriptTabbedPannel.headersize));
}, },
minimumSize: 100, minimumSize: 100,
maximumSize: Number.POSITIVE_INFINITY, maximumSize: Number.POSITIVE_INFINITY,
@@ -163,6 +175,7 @@ export class Designer extends Disposable implements IThemable {
onDidChange: Event.None onDidChange: Event.None
}, Sizing.Distribute); }, Sizing.Distribute);
this._propertiesPane = new DesignerPropertiesPane(this._propertiesPaneContainer, (container, components, parentPath) => { this._propertiesPane = new DesignerPropertiesPane(this._propertiesPaneContainer, (container, components, parentPath) => {
return this.createComponents(container, components, this._propertiesPane.componentMap, this._propertiesPane.groupHeaders, parentPath, 'PropertiesView'); return this.createComponents(container, components, this._propertiesPane.componentMap, this._propertiesPane.groupHeaders, parentPath, 'PropertiesView');
}, (definition, component, viewModel) => { }, (definition, component, viewModel) => {
@@ -244,7 +257,7 @@ export class Designer extends Disposable implements IThemable {
this._buttons = []; this._buttons = [];
this._componentMap.clear(); this._componentMap.clear();
DOM.clearNode(this._topContentContainer); DOM.clearNode(this._topContentContainer);
this._tabbedPanel.clearTabs(); this._contentTabbedPanel.clearTabs();
this._propertiesPane.clear(); this._propertiesPane.clear();
this._inputDisposable?.dispose(); this._inputDisposable?.dispose();
this._groupHeaders = []; this._groupHeaders = [];
@@ -287,7 +300,7 @@ export class Designer extends Disposable implements IThemable {
this.createComponents(this._topContentContainer, view.components, this._componentMap, this._groupHeaders, DesignerRootObjectPath, 'TopContentView'); this.createComponents(this._topContentContainer, view.components, this._componentMap, this._groupHeaders, DesignerRootObjectPath, 'TopContentView');
} }
view.tabs.forEach(tab => { view.tabs.forEach(tab => {
this._tabbedPanel.pushTab(this.createTabView(tab)); this._contentTabbedPanel.pushTab(this.createTabView(tab));
}); });
this.layoutTabbedPanel(); this.layoutTabbedPanel();
this.updateComponentValues(); this.updateComponentValues();
@@ -297,8 +310,6 @@ export class Designer extends Disposable implements IThemable {
private handleEditProcessedEvent(args: DesignerEditProcessedEventArgs): void { private handleEditProcessedEvent(args: DesignerEditProcessedEventArgs): void {
const edit = args.edit; const edit = args.edit;
const result = args.result;
if (result.isValid) {
this._supressEditProcessing = true; this._supressEditProcessing = true;
try { try {
this.updateComponentValues(); this.updateComponentValues();
@@ -330,9 +341,6 @@ export class Designer extends Disposable implements IThemable {
this._notificationService.error(err); this._notificationService.error(err);
} }
this._supressEditProcessing = false; this._supressEditProcessing = false;
} else {
this._notificationService.error(result.errors.map(e => e.message));
}
} }
private handleInputStateChangedEvent(args: DesignerStateChangedEventArgs): void { private handleInputStateChangedEvent(args: DesignerStateChangedEventArgs): void {
@@ -378,7 +386,7 @@ export class Designer extends Disposable implements IThemable {
} }
private layoutTabbedPanel() { private layoutTabbedPanel() {
this._tabbedPanel.layout(new DOM.Dimension(this._tabbedPanelContainer.clientWidth, this._tabbedPanelContainer.clientHeight)); this._contentTabbedPanel.layout(new DOM.Dimension(this._tabbedPanelContainer.clientWidth, this._tabbedPanelContainer.clientHeight));
} }
private layoutPropertiesPane() { private layoutPropertiesPane() {
@@ -431,16 +439,36 @@ export class Designer extends Disposable implements IThemable {
} }
private updateComponentValues(): void { private updateComponentValues(): void {
this.updateMessagesTab();
const viewModel = this._input.viewModel; const viewModel = this._input.viewModel;
const scriptProperty = viewModel[ScriptProperty] as InputBoxProperties; const scriptProperty = viewModel[ScriptProperty] as InputBoxProperties;
if (scriptProperty) { if (scriptProperty) {
this._textEditor.content = scriptProperty.value || ''; this._scriptEditorView.content = scriptProperty.value || '';
} }
this._componentMap.forEach((value) => { this._componentMap.forEach((value) => {
this.setComponentValue(value.defintion, value.component, viewModel); this.setComponentValue(value.defintion, value.component, viewModel);
}); });
} }
private updateMessagesTab(): void {
if (!this._input) {
return;
}
if (this._scriptTabbedPannel.contains(MessagesTabId)) {
this._scriptTabbedPannel.removeTab(MessagesTabId);
}
if (this._input.validationErrors === undefined || this._input.validationErrors.length === 0) {
return;
}
this._scriptTabbedPannel.pushTab({
title: localize('designer.messagesTabTitle', "Errors ({0})", this._input.validationErrors.length),
identifier: MessagesTabId,
view: this._messagesView
});
this._scriptTabbedPannel.showTab(MessagesTabId);
this._messagesView.updateMessages(this._input.validationErrors);
}
private handleEdit(edit: DesignerEdit): void { private handleEdit(edit: DesignerEdit): void {
if (this._supressEditProcessing) { if (this._supressEditProcessing) {
return; return;
@@ -791,13 +819,13 @@ export class Designer extends Disposable implements IThemable {
private getUIState(): DesignerUIState { private getUIState(): DesignerUIState {
return { return {
activeTabId: this._tabbedPanel.activeTabId activeTabId: this._contentTabbedPanel.activeTabId
}; };
} }
private restoreUIState(): void { private restoreUIState(): void {
if (this._input.designerUIState) { if (this._input.designerUIState) {
this._tabbedPanel.showTab(this._input.designerUIState.activeTabId); this._contentTabbedPanel.showTab(this._input.designerUIState.activeTabId);
} }
} }
} }

View File

@@ -0,0 +1,30 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IPanelView } from 'sql/base/browser/ui/panel/panel';
import { Disposable } from 'vs/base/common/lifecycle';
import * as DOM from 'vs/base/browser/dom';
import { DesignerValidationError } from 'sql/workbench/browser/designer/interfaces';
export class DesignerMessagesTabPanelView extends Disposable implements IPanelView {
private _container: HTMLElement;
render(container: HTMLElement): void {
this._container = container.appendChild(DOM.$('.messages-container'));
}
layout(dimension: DOM.Dimension): void {
}
updateMessages(errors: DesignerValidationError[]) {
if (this._container) {
DOM.clearNode(this._container);
errors?.forEach(error => {
const messageItem = this._container.appendChild(DOM.$('.message-item.codicon.error'));
messageItem.innerText = error.message;
});
}
}
}

View File

@@ -84,9 +84,6 @@ export class DesignerScriptEditor extends BaseTextEditor implements DesignerText
options.renderIndentGuides = false; options.renderIndentGuides = false;
options.rulers = []; options.rulers = [];
options.glyphMargin = true; options.glyphMargin = true;
options.minimap = {
enabled: true
};
} }
return options; return options;
} }

View File

@@ -0,0 +1,32 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IPanelView } from 'sql/base/browser/ui/panel/panel';
import { Disposable } from 'vs/base/common/lifecycle';
import * as DOM from 'vs/base/browser/dom';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { DesignerScriptEditor } from 'sql/workbench/browser/designer/designerScriptEditor';
export class DesignerScriptEditorTabPanelView extends Disposable implements IPanelView {
private _textEditor: DesignerScriptEditor;
constructor(private _instantiationService: IInstantiationService) {
super();
}
render(container: HTMLElement): void {
this._textEditor = this._instantiationService.createInstance(DesignerScriptEditor, container);
}
layout(dimension: DOM.Dimension): void {
this._textEditor.layout(dimension);
}
set content(content: string) {
if (this._textEditor) {
this._textEditor.content = content;
}
}
}

View File

@@ -43,6 +43,11 @@ export interface DesignerComponentInput {
*/ */
readonly viewModel: DesignerViewModel; readonly viewModel: DesignerViewModel;
/**
* Gets the validation errors.
*/
readonly validationErrors: DesignerValidationError[] | undefined;
/** /**
* Start initilizing the designer input object. * Start initilizing the designer input object.
*/ */
@@ -210,9 +215,11 @@ export interface DesignerEdit {
export type DesignerEditPath = (string | number)[]; export type DesignerEditPath = (string | number)[];
export const DesignerRootObjectPath: DesignerEditPath = []; export const DesignerRootObjectPath: DesignerEditPath = [];
export type DesignerValidationError = { message: string, property?: DesignerEditPath };
export interface DesignerEditResult { export interface DesignerEditResult {
isValid: boolean; isValid: boolean;
errors?: { message: string, property?: DesignerEditPath }[]; errors?: DesignerValidationError[];
} }
export interface DesignerTextEditor { export interface DesignerTextEditor {

View File

@@ -29,6 +29,20 @@
height: 100%; height: 100%;
} }
.designer-component .messages-container {
overflow: scroll;
height: 100%;
width: 100%;
}
.designer-component .messages-container .message-item {
padding: 0px 5px 0px 25px;
background-position: 5px center;
background-size: 16px 16px;
user-select: text;
line-height: 25px;
}
.designer-component .tabbed-panel-container { .designer-component .tabbed-panel-container {
flex: 1 1 auto; flex: 1 1 auto;
overflow: hidden; overflow: hidden;

View File

@@ -257,27 +257,27 @@ export class QueryResultsView extends Disposable {
} }
})); }));
if (this.input?.state.visibleTabs.has(this.chartTab.identifier) && !this._panelView.contains(this.chartTab)) { if (this.input?.state.visibleTabs.has(this.chartTab.identifier) && !this._panelView.contains(this.chartTab.identifier)) {
this._panelView.pushTab(this.chartTab); this._panelView.pushTab(this.chartTab);
} else if (!this.input?.state.visibleTabs.has(this.chartTab.identifier) && this._panelView.contains(this.chartTab)) { } else if (!this.input?.state.visibleTabs.has(this.chartTab.identifier) && this._panelView.contains(this.chartTab.identifier)) {
this._panelView.removeTab(this.chartTab.identifier); this._panelView.removeTab(this.chartTab.identifier);
} }
if (this.input?.state.visibleTabs.has(this.qp2Tab.identifier) && !this._panelView.contains(this.qp2Tab)) { if (this.input?.state.visibleTabs.has(this.qp2Tab.identifier) && !this._panelView.contains(this.qp2Tab.identifier)) {
this._panelView.pushTab(this.qp2Tab); this._panelView.pushTab(this.qp2Tab);
} else if (!this.input?.state.visibleTabs.has(this.qp2Tab.identifier) && this._panelView.contains(this.qp2Tab)) { } else if (!this.input?.state.visibleTabs.has(this.qp2Tab.identifier) && this._panelView.contains(this.qp2Tab.identifier)) {
this._panelView.removeTab(this.qp2Tab.identifier); this._panelView.removeTab(this.qp2Tab.identifier);
} }
if (this.input?.state.visibleTabs.has(this.topOperationsTab.identifier) && !this._panelView.contains(this.topOperationsTab)) { if (this.input?.state.visibleTabs.has(this.topOperationsTab.identifier) && !this._panelView.contains(this.topOperationsTab.identifier)) {
this._panelView.pushTab(this.topOperationsTab); this._panelView.pushTab(this.topOperationsTab);
} else if (!this.input?.state.visibleTabs.has(this.topOperationsTab.identifier) && this._panelView.contains(this.topOperationsTab)) { } else if (!this.input?.state.visibleTabs.has(this.topOperationsTab.identifier) && this._panelView.contains(this.topOperationsTab.identifier)) {
this._panelView.removeTab(this.topOperationsTab.identifier); this._panelView.removeTab(this.topOperationsTab.identifier);
} }
// restore query model view tabs // restore query model view tabs
this.dynamicModelViewTabs.forEach(tab => { this.dynamicModelViewTabs.forEach(tab => {
if (this._panelView.contains(tab)) { if (this._panelView.contains(tab.identifier)) {
this._panelView.removeTab(tab.identifier); this._panelView.removeTab(tab.identifier);
} }
}); });
@@ -291,7 +291,7 @@ export class QueryResultsView extends Disposable {
let tab = this._register(new QueryModelViewTab(parts[1], this.instantiationService)); let tab = this._register(new QueryModelViewTab(parts[1], this.instantiationService));
tab.view.componentId = parts[2]; tab.view.componentId = parts[2];
this.dynamicModelViewTabs.push(tab); this.dynamicModelViewTabs.push(tab);
if (!this._panelView.contains(tab)) { if (!this._panelView.contains(tab.identifier)) {
this._panelView.pushTab(tab, undefined, true); this._panelView.pushTab(tab, undefined, true);
} }
} }
@@ -381,7 +381,7 @@ export class QueryResultsView extends Disposable {
public chartData(dataId: { resultId: number, batchId: number }): void { public chartData(dataId: { resultId: number, batchId: number }): void {
this.input?.state.visibleTabs.add(this.chartTab.identifier); this.input?.state.visibleTabs.add(this.chartTab.identifier);
if (!this._panelView.contains(this.chartTab)) { if (!this._panelView.contains(this.chartTab.identifier)) {
this._panelView.pushTab(this.chartTab); this._panelView.pushTab(this.chartTab);
} }
@@ -390,19 +390,19 @@ export class QueryResultsView extends Disposable {
} }
public hideChart() { public hideChart() {
if (this._panelView.contains(this.chartTab)) { if (this._panelView.contains(this.chartTab.identifier)) {
this._panelView.removeTab(this.chartTab.identifier); this._panelView.removeTab(this.chartTab.identifier);
} }
} }
public hideResults() { public hideResults() {
if (this._panelView.contains(this.resultsTab)) { if (this._panelView.contains(this.resultsTab.identifier)) {
this._panelView.removeTab(this.resultsTab.identifier); this._panelView.removeTab(this.resultsTab.identifier);
} }
} }
public showResults() { public showResults() {
if (!this._panelView.contains(this.resultsTab)) { if (!this._panelView.contains(this.resultsTab.identifier)) {
this._panelView.pushTab(this.resultsTab, 0); this._panelView.pushTab(this.resultsTab, 0);
} }
this._panelView.showTab(this.resultsTab.identifier); this._panelView.showTab(this.resultsTab.identifier);
@@ -410,16 +410,16 @@ export class QueryResultsView extends Disposable {
public showTopOperations(xml: string) { public showTopOperations(xml: string) {
this.input?.state.visibleTabs.add(this.topOperationsTab.identifier); this.input?.state.visibleTabs.add(this.topOperationsTab.identifier);
if (!this._panelView.contains(this.topOperationsTab)) { if (!this._panelView.contains(this.topOperationsTab.identifier)) {
this._panelView.pushTab(this.topOperationsTab); this._panelView.pushTab(this.topOperationsTab);
} }
this.topOperationsTab.view.showPlan(xml); this.topOperationsTab.view.showPlan(xml);
} }
public showPlan2() { public showPlan2() {
if (!this._panelView.contains(this.qp2Tab)) { if (!this._panelView.contains(this.qp2Tab.identifier)) {
this.input?.state.visibleTabs.add(this.qp2Tab.identifier); this.input?.state.visibleTabs.add(this.qp2Tab.identifier);
if (!this._panelView.contains(this.qp2Tab)) { if (!this._panelView.contains(this.qp2Tab.identifier)) {
this._panelView.pushTab(this.qp2Tab); this._panelView.pushTab(this.qp2Tab);
} }
this._panelView.showTab(this.qp2Tab.identifier); this._panelView.showTab(this.qp2Tab.identifier);
@@ -427,13 +427,13 @@ export class QueryResultsView extends Disposable {
} }
public hideTopOperations() { public hideTopOperations() {
if (this._panelView.contains(this.topOperationsTab)) { if (this._panelView.contains(this.topOperationsTab.identifier)) {
this._panelView.removeTab(this.topOperationsTab.identifier); this._panelView.removeTab(this.topOperationsTab.identifier);
} }
} }
public hidePlan2() { public hidePlan2() {
if (this._panelView.contains(this.qp2Tab)) { if (this._panelView.contains(this.qp2Tab.identifier)) {
this.qp2Tab.clear(); this.qp2Tab.clear();
this.input.state.queryPlan2State.clearQueryPlan2State(); this.input.state.queryPlan2State.clearQueryPlan2State();
this._panelView.removeTab(this.qp2Tab.identifier); this._panelView.removeTab(this.qp2Tab.identifier);
@@ -442,7 +442,7 @@ export class QueryResultsView extends Disposable {
public hideDynamicViewModelTabs() { public hideDynamicViewModelTabs() {
this.dynamicModelViewTabs.forEach(tab => { this.dynamicModelViewTabs.forEach(tab => {
if (this._panelView.contains(tab)) { if (this._panelView.contains(tab.identifier)) {
this._panelView.removeTab(tab.identifier); this._panelView.removeTab(tab.identifier);
} }
}); });
@@ -462,7 +462,7 @@ export class QueryResultsView extends Disposable {
this.dynamicModelViewTabs.push(tab); this.dynamicModelViewTabs.push(tab);
this.input?.state.visibleTabs.add('querymodelview;' + title + ';' + componentId); this.input?.state.visibleTabs.add('querymodelview;' + title + ';' + componentId);
if (!this._panelView.contains(tab)) { if (!this._panelView.contains(tab.identifier)) {
this._panelView.pushTab(tab, undefined, true); this._panelView.pushTab(tab, undefined, true);
} }

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import { DesignerViewModel, DesignerEdit, DesignerComponentInput, DesignerView, DesignerTab, DesignerDataPropertyInfo, DropDownProperties, DesignerTableProperties, DesignerEditProcessedEventArgs, DesignerAction, DesignerStateChangedEventArgs, DesignerEditPath } from 'sql/workbench/browser/designer/interfaces'; import { DesignerViewModel, DesignerEdit, DesignerComponentInput, DesignerView, DesignerTab, DesignerDataPropertyInfo, DropDownProperties, DesignerTableProperties, DesignerEditProcessedEventArgs, DesignerAction, DesignerStateChangedEventArgs, DesignerEditPath, DesignerValidationError } from 'sql/workbench/browser/designer/interfaces';
import { TableDesignerProvider } from 'sql/workbench/services/tableDesigner/common/interface'; import { TableDesignerProvider } from 'sql/workbench/services/tableDesigner/common/interface';
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
import { designers } from 'sql/workbench/api/common/sqlExtHostTypes'; import { designers } from 'sql/workbench/api/common/sqlExtHostTypes';
@@ -22,6 +22,7 @@ const ErrorDialogTitle: string = localize('tableDesigner.ErrorDialogTitle', "Tab
export class TableDesignerComponentInput implements DesignerComponentInput { export class TableDesignerComponentInput implements DesignerComponentInput {
private _viewModel: DesignerViewModel; private _viewModel: DesignerViewModel;
private _validationErrors?: DesignerValidationError[];
private _view: DesignerView; private _view: DesignerView;
private _valid: boolean = true; private _valid: boolean = true;
private _dirty: boolean = false; private _dirty: boolean = false;
@@ -75,6 +76,10 @@ export class TableDesignerComponentInput implements DesignerComponentInput {
return this._viewModel; return this._viewModel;
} }
get validationErrors(): DesignerValidationError[] | undefined {
return this._validationErrors;
}
processEdit(edit: DesignerEdit): void { processEdit(edit: DesignerEdit): void {
const telemetryInfo = this.createTelemetryInfo(); const telemetryInfo = this.createTelemetryInfo();
telemetryInfo.tableObjectType = this.getObjectTypeFromPath(edit.path); telemetryInfo.tableObjectType = this.getObjectTypeFromPath(edit.path);
@@ -85,6 +90,7 @@ export class TableDesignerComponentInput implements DesignerComponentInput {
this._provider.processTableEdit(this.tableInfo, edit).then( this._provider.processTableEdit(this.tableInfo, edit).then(
result => { result => {
this._viewModel = result.viewModel; this._viewModel = result.viewModel;
this._validationErrors = result.errors;
this.updateState(result.isValid, !equals(this._viewModel, this._originalViewModel), undefined); this.updateState(result.isValid, !equals(this._viewModel, this._originalViewModel), undefined);
this._onEditProcessed.fire({ this._onEditProcessed.fire({