diff --git a/src/sql/common/telemetryKeys.ts b/src/sql/common/telemetryKeys.ts index bae25446f0..44cc3896f3 100644 --- a/src/sql/common/telemetryKeys.ts +++ b/src/sql/common/telemetryKeys.ts @@ -23,6 +23,7 @@ export const RunQueryStatement = 'RunQueryStatement'; export const CancelQuery = 'CancelQuery'; export const NewQuery = 'NewQuery'; export const FirewallRuleRequested = 'FirewallRuleCreated'; +export const DashboardNavigated = 'DashboardNavigated'; // Telemetry Properties diff --git a/src/sql/parts/dashboard/common/dashboardTab.contribution.ts b/src/sql/parts/dashboard/common/dashboardTab.contribution.ts index 506cd9e7db..f43a6805b0 100644 --- a/src/sql/parts/dashboard/common/dashboardTab.contribution.ts +++ b/src/sql/parts/dashboard/common/dashboardTab.contribution.ts @@ -5,6 +5,7 @@ import { IExtensionPointUser, ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { localize } from 'vs/nls'; +import * as types from 'vs/base/common/types'; import { registerTab } from 'sql/platform/dashboard/common/dashboardRegistry'; import { generateContainerTypeSchemaProperties } from 'sql/platform/dashboard/common/dashboardContainerRegistry'; @@ -92,7 +93,11 @@ ExtensionsRegistry.registerExtensionPoint) { let { description, container, title, edition, provider, id, alwaysShow } = tab; - alwaysShow = alwaysShow || false; + + // If always show is not specified, set it to true by default. + if (!types.isBoolean(alwaysShow)) { + alwaysShow = true; + } let publisher = extension.description.publisher; if (!title) { extension.collector.error(localize('dashboardTab.contribution.noTitleError', 'No title specified for extension.')); diff --git a/src/sql/parts/dashboard/dashboard.module.ts b/src/sql/parts/dashboard/dashboard.module.ts index dc42c7f84e..4bcbbf66e3 100644 --- a/src/sql/parts/dashboard/dashboard.module.ts +++ b/src/sql/parts/dashboard/dashboard.module.ts @@ -6,7 +6,7 @@ import { Inject, NgModule, forwardRef, ApplicationRef, ComponentFactoryResolver } from '@angular/core'; import { CommonModule, APP_BASE_HREF } from '@angular/common'; import { BrowserModule } from '@angular/platform-browser'; -import { RouterModule, Routes, UrlSerializer } from '@angular/router'; +import { RouterModule, Routes, UrlSerializer, Router, NavigationEnd } from '@angular/router'; import { FormsModule } from '@angular/forms'; import { NgGridModule } from 'angular2-grid'; import { ChartsModule } from 'ng2-charts/ng2-charts'; @@ -17,6 +17,11 @@ import { Extensions, IInsightRegistry } from 'sql/platform/dashboard/common/insi import { Registry } from 'vs/platform/registry/common/platform'; +/* Telemetry */ +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import * as TelemetryUtils from 'sql/common/telemetryUtilities'; +import * as TelemetryKeys from 'sql/common/telemetryKeys'; + /* Services */ import { BreadcrumbService } from 'sql/parts/dashboard/services/breadcrumb.service'; import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service'; @@ -114,7 +119,8 @@ export class DashboardModule { constructor( @Inject(forwardRef(() => ComponentFactoryResolver)) private _resolver: ComponentFactoryResolver, @Inject(BOOTSTRAP_SERVICE_ID) private _bootstrapService: IBootstrapService, - @Inject(forwardRef(() => DashboardServiceInterface)) private _bootstrap: DashboardServiceInterface + @Inject(forwardRef(() => DashboardServiceInterface)) private _bootstrap: DashboardServiceInterface, + @Inject(forwardRef(() => Router)) private _router: Router ) { } @@ -124,5 +130,15 @@ export class DashboardModule { this._bootstrap.selector = uniqueSelector; (factory).factory.selector = uniqueSelector; appRef.bootstrap(factory); + + this._router.events.subscribe(e => { + if (e instanceof NavigationEnd) { + this._bootstrap.handlePageNavigation(); + TelemetryUtils.addTelemetry(this._bootstrapService.telemetryService, TelemetryKeys.DashboardNavigated, { + numberOfNavigations: this._bootstrap.getNumberOfPageNavigations(), + routeUrl: e.url + }); + } + }); } } diff --git a/src/sql/parts/dashboard/newDashboardTabDialog/media/newDashboardTabDialog.css b/src/sql/parts/dashboard/newDashboardTabDialog/media/newDashboardTabDialog.css index db911b0bbf..1e1cbdaf5f 100644 --- a/src/sql/parts/dashboard/newDashboardTabDialog/media/newDashboardTabDialog.css +++ b/src/sql/parts/dashboard/newDashboardTabDialog/media/newDashboardTabDialog.css @@ -63,3 +63,8 @@ opacity: .6; font-weight: 600; } + +.no-extensionTab-label { + font-size: 12px; + padding: 15px; +} \ No newline at end of file diff --git a/src/sql/parts/dashboard/newDashboardTabDialog/newDashboardTabDialog.ts b/src/sql/parts/dashboard/newDashboardTabDialog/newDashboardTabDialog.ts index 2dc1a75952..cd05c9b81e 100644 --- a/src/sql/parts/dashboard/newDashboardTabDialog/newDashboardTabDialog.ts +++ b/src/sql/parts/dashboard/newDashboardTabDialog/newDashboardTabDialog.ts @@ -101,6 +101,8 @@ export class NewDashboardTabDialog extends Modal { private _extensionList: List; private _extensionTabView: FixedListView; private _container: HTMLElement; + private _extensionViewContainer: HTMLElement; + private _noExtensionViewContainer: HTMLElement; private _viewModel: NewDashboardTabViewModel; @@ -154,10 +156,20 @@ export class NewDashboardTabDialog extends Modal { protected renderBody(container: HTMLElement) { this._container = container; - let viewBody = DOM.$('div.extension-view'); - DOM.append(container, viewBody); + this._extensionViewContainer = DOM.$('div.extension-view'); + DOM.append(container, this._extensionViewContainer); - // Create a fixed list view for the account provider + this.createExtensionList(this._extensionViewContainer); + this._noExtensionViewContainer = DOM.$('.no-extension-view'); + let noExtensionTitle = DOM.append(this._noExtensionViewContainer, DOM.$('.no-extensionTab-label')); + let noExtensionLabel = localize('newdashboardTabDialog.noExtensionLabel', 'No available feature tabs. Install extensions from the Extension Manager to get additional features.'); + noExtensionTitle.innerHTML = noExtensionLabel; + + DOM.append(container, this._noExtensionViewContainer); + } + + private createExtensionList(container: HTMLElement) { + // Create a fixed list view for the extensions let extensionTabViewContainer = DOM.$('.extensionTab-view'); let delegate = new ExtensionListDelegate(NewDashboardTabDialog.EXTENSIONLIST_HEIGHT); let extensionTabRenderer = new ExtensionListRenderer(); @@ -186,7 +198,7 @@ export class NewDashboardTabDialog extends Modal { } }); - this._extensionTabView.render(viewBody, Orientation.VERTICAL); + this._extensionTabView.render(container, Orientation.VERTICAL); this._register(attachListStyler(this._extensionList, this._themeService)); @@ -234,10 +246,14 @@ export class NewDashboardTabDialog extends Modal { this._extensionTabView.updateList(tabs); this.layout(); if (this._extensionList.length > 0) { + this._extensionViewContainer.hidden = false; + this._noExtensionViewContainer.hidden = true; this._extensionList.setSelection([0]); this._extensionList.domFocus(); this._addNewTabButton.enabled = true; } else { + this._extensionViewContainer.hidden = true; + this._noExtensionViewContainer.hidden = false; this._addNewTabButton.enabled = false; this._cancelButton.focus(); } diff --git a/src/sql/parts/dashboard/services/dashboardServiceInterface.service.ts b/src/sql/parts/dashboard/services/dashboardServiceInterface.service.ts index d23a00ed88..616eeda030 100644 --- a/src/sql/parts/dashboard/services/dashboardServiceInterface.service.ts +++ b/src/sql/parts/dashboard/services/dashboardServiceInterface.service.ts @@ -155,6 +155,8 @@ export class DashboardServiceInterface implements OnDestroy { private _onCloseTab = new Emitter(); public readonly onCloseTab: Event = this._onCloseTab.event; + private _numberOfPageNavigations: number; + constructor( @Inject(BOOTSTRAP_SERVICE_ID) private _bootstrapService: IBootstrapService, @Inject(forwardRef(() => Router)) private _router: Router, @@ -174,6 +176,7 @@ export class DashboardServiceInterface implements OnDestroy { this._dashboardWebviewService = this._bootstrapService.dashboardWebviewService; this._partService = this._bootstrapService.partService; this._angularEventingService = this._bootstrapService.angularEventingService; + this._numberOfPageNavigations = 0; } ngOnDestroy() { @@ -291,6 +294,20 @@ export class DashboardServiceInterface implements OnDestroy { return this._bootstrapParams.connection; } + /** + * Gets the number of page navigation + */ + public getNumberOfPageNavigations(): number { + return this._numberOfPageNavigations; + } + + /** + * Handle on page navigation + */ + public handlePageNavigation(): void { + this._numberOfPageNavigations++; + } + /** * Get settings for given string * @param type string of setting to get from dashboard settings; i.e dashboard.{type}