mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Hide results tab when there are none (#5763)
* wip * add behavior around hiding results when there are none * fix strict null access
This commit is contained in:
@@ -13,6 +13,8 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
|||||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
|
import { isUndefinedOrNull } from 'vs/base/common/types';
|
||||||
|
import * as map from 'vs/base/common/map';
|
||||||
|
|
||||||
export interface ITabbedPanelStyles {
|
export interface ITabbedPanelStyles {
|
||||||
titleActiveForeground?: Color;
|
titleActiveForeground?: Color;
|
||||||
@@ -39,7 +41,8 @@ export interface IPanelTab {
|
|||||||
view: IPanelView;
|
view: IPanelView;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IInternalPanelTab extends IPanelTab {
|
interface IInternalPanelTab {
|
||||||
|
tab: IPanelTab;
|
||||||
header: HTMLElement;
|
header: HTMLElement;
|
||||||
disposables: IDisposable[];
|
disposables: IDisposable[];
|
||||||
label: HTMLElement;
|
label: HTMLElement;
|
||||||
@@ -108,11 +111,11 @@ export class TabbedPanel extends Disposable {
|
|||||||
return this._tabMap.has(tab.identifier);
|
return this._tabMap.has(tab.identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public pushTab(tab: IPanelTab): PanelTabIdentifier {
|
public pushTab(tab: IPanelTab, index?: number): PanelTabIdentifier {
|
||||||
let internalTab = tab as IInternalPanelTab;
|
let internalTab = { tab } as IInternalPanelTab;
|
||||||
internalTab.disposables = [];
|
internalTab.disposables = [];
|
||||||
this._tabMap.set(tab.identifier, internalTab);
|
this._tabMap.set(tab.identifier, internalTab);
|
||||||
this._createTab(internalTab);
|
this._createTab(internalTab, index);
|
||||||
if (!this._shownTabId) {
|
if (!this._shownTabId) {
|
||||||
this.showTab(tab.identifier);
|
this.showTab(tab.identifier);
|
||||||
}
|
}
|
||||||
@@ -132,26 +135,31 @@ export class TabbedPanel extends Disposable {
|
|||||||
this._actionbar.context = context;
|
this._actionbar.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _createTab(tab: IInternalPanelTab): void {
|
private _createTab(tab: IInternalPanelTab, index?: number): void {
|
||||||
let tabHeaderElement = DOM.$('.tab-header');
|
let tabHeaderElement = DOM.$('.tab-header');
|
||||||
tabHeaderElement.setAttribute('tabindex', '0');
|
tabHeaderElement.setAttribute('tabindex', '0');
|
||||||
tabHeaderElement.setAttribute('role', 'tab');
|
tabHeaderElement.setAttribute('role', 'tab');
|
||||||
tabHeaderElement.setAttribute('aria-selected', 'false');
|
tabHeaderElement.setAttribute('aria-selected', 'false');
|
||||||
tabHeaderElement.setAttribute('aria-controls', tab.identifier);
|
tabHeaderElement.setAttribute('aria-controls', tab.tab.identifier);
|
||||||
let tabElement = DOM.$('.tab');
|
let tabElement = DOM.$('.tab');
|
||||||
tabHeaderElement.appendChild(tabElement);
|
tabHeaderElement.appendChild(tabElement);
|
||||||
let tabLabel = DOM.$('a.tabLabel');
|
let tabLabel = DOM.$('a.tabLabel');
|
||||||
tabLabel.innerText = tab.title;
|
tabLabel.innerText = tab.tab.title;
|
||||||
tabElement.appendChild(tabLabel);
|
tabElement.appendChild(tabLabel);
|
||||||
tab.disposables.push(DOM.addDisposableListener(tabHeaderElement, DOM.EventType.CLICK, e => this.showTab(tab.identifier)));
|
tab.disposables.push(DOM.addDisposableListener(tabHeaderElement, DOM.EventType.CLICK, e => this.showTab(tab.tab.identifier)));
|
||||||
tab.disposables.push(DOM.addDisposableListener(tabHeaderElement, DOM.EventType.KEY_UP, (e: KeyboardEvent) => {
|
tab.disposables.push(DOM.addDisposableListener(tabHeaderElement, DOM.EventType.KEY_UP, (e: KeyboardEvent) => {
|
||||||
let event = new StandardKeyboardEvent(e);
|
let event = new StandardKeyboardEvent(e);
|
||||||
if (event.equals(KeyCode.Enter)) {
|
if (event.equals(KeyCode.Enter)) {
|
||||||
this.showTab(tab.identifier);
|
this.showTab(tab.tab.identifier);
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
this.tabList.appendChild(tabHeaderElement);
|
const insertBefore = !isUndefinedOrNull(index) ? this.tabList.children.item(index) : undefined;
|
||||||
|
if (insertBefore) {
|
||||||
|
this.tabList.insertBefore(tabHeaderElement, insertBefore);
|
||||||
|
} else {
|
||||||
|
this.tabList.append(tabHeaderElement);
|
||||||
|
}
|
||||||
tab.header = tabHeaderElement;
|
tab.header = tabHeaderElement;
|
||||||
tab.label = tabLabel;
|
tab.label = tabLabel;
|
||||||
}
|
}
|
||||||
@@ -178,10 +186,10 @@ export class TabbedPanel extends Disposable {
|
|||||||
tab.body = DOM.$('.tab-container');
|
tab.body = DOM.$('.tab-container');
|
||||||
tab.body.style.width = '100%';
|
tab.body.style.width = '100%';
|
||||||
tab.body.style.height = '100%';
|
tab.body.style.height = '100%';
|
||||||
tab.view.render(tab.body);
|
tab.tab.view.render(tab.body);
|
||||||
}
|
}
|
||||||
this.body.appendChild(tab.body);
|
this.body.appendChild(tab.body);
|
||||||
this.body.setAttribute('aria-labelledby', tab.identifier);
|
this.body.setAttribute('aria-labelledby', tab.tab.identifier);
|
||||||
DOM.addClass(tab.label, 'active');
|
DOM.addClass(tab.label, 'active');
|
||||||
DOM.addClass(tab.header, 'active');
|
DOM.addClass(tab.header, 'active');
|
||||||
tab.header.setAttribute('aria-selected', 'true');
|
tab.header.setAttribute('aria-selected', 'true');
|
||||||
@@ -197,8 +205,8 @@ export class TabbedPanel extends Disposable {
|
|||||||
if (!actualTab) {
|
if (!actualTab) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (actualTab.view && actualTab.view.remove) {
|
if (actualTab.tab.view && actualTab.tab.view.remove) {
|
||||||
actualTab.view.remove();
|
actualTab.tab.view.remove();
|
||||||
}
|
}
|
||||||
if (actualTab.header && actualTab.header.remove) {
|
if (actualTab.header && actualTab.header.remove) {
|
||||||
actualTab.header.remove();
|
actualTab.header.remove();
|
||||||
@@ -218,6 +226,9 @@ export class TabbedPanel extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!this._shownTabId && this._tabMap.size > 0) {
|
||||||
|
this.showTab(map.values(this._tabMap)[0].tab.identifier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.options.showHeaderWhenSingleView && this._tabMap.size === 1 && this._headerVisible) {
|
if (!this.options.showHeaderWhenSingleView && this._tabMap.size === 1 && this._headerVisible) {
|
||||||
@@ -302,7 +313,7 @@ export class TabbedPanel extends Disposable {
|
|||||||
if (tab) {
|
if (tab) {
|
||||||
tab.body.style.width = dimension.width + 'px';
|
tab.body.style.width = dimension.width + 'px';
|
||||||
tab.body.style.height = dimension.height + 'px';
|
tab.body.style.height = dimension.height + 'px';
|
||||||
tab.view.layout(dimension);
|
tab.tab.view.layout(dimension);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -311,7 +322,7 @@ export class TabbedPanel extends Disposable {
|
|||||||
if (this._shownTabId) {
|
if (this._shownTabId) {
|
||||||
const tab = this._tabMap.get(this._shownTabId);
|
const tab = this._tabMap.get(this._shownTabId);
|
||||||
if (tab) {
|
if (tab) {
|
||||||
tab.view.focus();
|
tab.tab.view.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ export class QueryResultsView extends Disposable {
|
|||||||
this.resultsTab = this._register(new ResultsTab(instantiationService));
|
this.resultsTab = this._register(new ResultsTab(instantiationService));
|
||||||
this.messagesTab = this._register(new MessagesTab(instantiationService));
|
this.messagesTab = this._register(new MessagesTab(instantiationService));
|
||||||
this.chartTab = this._register(new ChartTab(instantiationService));
|
this.chartTab = this._register(new ChartTab(instantiationService));
|
||||||
this._panelView = this._register(new TabbedPanel(container, { showHeaderWhenSingleView: false }));
|
this._panelView = this._register(new TabbedPanel(container, { showHeaderWhenSingleView: true }));
|
||||||
this._register(attachTabbedPanelStyler(this._panelView, themeService));
|
this._register(attachTabbedPanelStyler(this._panelView, themeService));
|
||||||
this.qpTab = this._register(new QueryPlanTab());
|
this.qpTab = this._register(new QueryPlanTab());
|
||||||
this.topOperationsTab = this._register(new TopOperationsTab(instantiationService));
|
this.topOperationsTab = this._register(new TopOperationsTab(instantiationService));
|
||||||
@@ -195,17 +195,40 @@ export class QueryResultsView extends Disposable {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private hasResults(runner: QueryRunner): boolean {
|
||||||
|
let hasResults = false;
|
||||||
|
for (const batch of runner.batchSets) {
|
||||||
|
if (batch.resultSetSummaries.length > 0) {
|
||||||
|
hasResults = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hasResults;
|
||||||
|
}
|
||||||
|
|
||||||
private setQueryRunner(runner: QueryRunner) {
|
private setQueryRunner(runner: QueryRunner) {
|
||||||
|
if (runner.hasCompleted && !this.hasResults(runner)) {
|
||||||
|
this.hideResults();
|
||||||
|
} else {
|
||||||
|
this.showResults();
|
||||||
|
}
|
||||||
this.resultsTab.queryRunner = runner;
|
this.resultsTab.queryRunner = runner;
|
||||||
this.messagesTab.queryRunner = runner;
|
this.messagesTab.queryRunner = runner;
|
||||||
this.chartTab.queryRunner = runner;
|
this.chartTab.queryRunner = runner;
|
||||||
this.runnerDisposables.push(runner.onQueryStart(e => {
|
this.runnerDisposables.push(runner.onQueryStart(e => {
|
||||||
|
this.showResults();
|
||||||
this.hideChart();
|
this.hideChart();
|
||||||
this.hidePlan();
|
this.hidePlan();
|
||||||
this.hideDynamicViewModelTabs();
|
this.hideDynamicViewModelTabs();
|
||||||
this.input.state.visibleTabs = new Set();
|
this.input.state.visibleTabs = new Set();
|
||||||
this.input.state.activeTab = this.resultsTab.identifier;
|
this.input.state.activeTab = this.resultsTab.identifier;
|
||||||
}));
|
}));
|
||||||
|
this.runnerDisposables.push(runner.onQueryEnd(() => {
|
||||||
|
if (!this.hasResults(runner)) {
|
||||||
|
this.hideResults();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
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)) {
|
||||||
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)) {
|
||||||
@@ -311,6 +334,19 @@ export class QueryResultsView extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public hideResults() {
|
||||||
|
if (this._panelView.contains(this.resultsTab)) {
|
||||||
|
this._panelView.removeTab(this.resultsTab.identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public showResults() {
|
||||||
|
if (!this._panelView.contains(this.resultsTab)) {
|
||||||
|
this._panelView.pushTab(this.resultsTab, 0);
|
||||||
|
}
|
||||||
|
this._panelView.showTab(this.resultsTab.identifier);
|
||||||
|
}
|
||||||
|
|
||||||
public showPlan(xml: string) {
|
public showPlan(xml: string) {
|
||||||
this.input.state.visibleTabs.add(this.qpTab.identifier);
|
this.input.state.visibleTabs.add(this.qpTab.identifier);
|
||||||
if (!this._panelView.contains(this.qpTab)) {
|
if (!this._panelView.contains(this.qpTab)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user