mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 11:01:37 -05:00
Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
619c816e7f | ||
|
|
3d6fb7a8fa | ||
|
|
891624c085 | ||
|
|
a7c4686980 | ||
|
|
93aa052856 | ||
|
|
61d05f6782 | ||
|
|
60ccae48f1 | ||
|
|
4b454581fd | ||
|
|
f0aadebd2c | ||
|
|
d3f0ac7954 | ||
|
|
134f76c17f | ||
|
|
b9c877a109 | ||
|
|
aa243a8aae | ||
|
|
e5c1c6f544 | ||
|
|
9e9f85079e | ||
|
|
ae8e2e1f89 | ||
|
|
b2c70e9301 | ||
|
|
e022f4a0d1 | ||
|
|
8bc32e6371 | ||
|
|
f739c47984 | ||
|
|
13fb9fdfd2 | ||
|
|
9a5f51bfbf | ||
|
|
06bab6a38c | ||
|
|
c35a14d8fd | ||
|
|
b914073147 | ||
|
|
04ae18143b | ||
|
|
efe8e81b6e | ||
|
|
c33ddfabf9 | ||
|
|
8ec5451e64 | ||
|
|
20853ddf7e | ||
|
|
091d4cb924 | ||
|
|
cd0210c88a | ||
|
|
ed10f984b6 | ||
|
|
087a6a0810 | ||
|
|
495b4ee7c2 | ||
|
|
7833c28b7a | ||
|
|
bbfb68b082 | ||
|
|
b32e7a777c | ||
|
|
a327889d05 | ||
|
|
5ac89e5a49 | ||
|
|
849653927a | ||
|
|
3545483fc1 | ||
|
|
e5a1896414 | ||
|
|
bec8e72688 | ||
|
|
86748e6d69 | ||
|
|
596f09f754 | ||
|
|
563e25f073 | ||
|
|
1800d0baaf | ||
|
|
2182658301 | ||
|
|
3990719054 | ||
|
|
071b510fba | ||
|
|
d2d2ade9f7 | ||
|
|
d97d2e5c91 | ||
|
|
a6ba44e435 | ||
|
|
4967e630fb | ||
|
|
2508464fde | ||
|
|
782623cba9 | ||
|
|
36045c5381 |
3
.vscode/launch.json
vendored
3
.vscode/launch.json
vendored
@@ -89,7 +89,8 @@
|
||||
"skipFiles": [
|
||||
"**/winjs*.js"
|
||||
],
|
||||
"webRoot": "${workspaceFolder}"
|
||||
"webRoot": "${workspaceFolder}",
|
||||
"timeout": 15000
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "agent",
|
||||
"displayName": "SQL Server Agent",
|
||||
"description": "Manage and troubleshoot SQL Server Agent jobs (early preview)",
|
||||
"version": "0.27.1",
|
||||
"version": "0.28.0",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"license": "https://raw.githubusercontent.com/Microsoft/sqlopsstudio/master/LICENSE.txt",
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
|
||||
"version": "1.4.0-alpha.18",
|
||||
"version": "1.4.0-alpha.23",
|
||||
"downloadFileNames": {
|
||||
"Windows_86": "win-x86-netcoreapp2.0.zip",
|
||||
"Windows_64": "win-x64-netcoreapp2.0.zip",
|
||||
"OSX": "osx-x64-netcoreapp2.0.tar.gz",
|
||||
"CentOS_7": "rhel-x64-netcoreapp2.0.tar.gz",
|
||||
"Debian_8": "rhel-x64-netcoreapp2.0.tar.gz",
|
||||
"Fedora_23": "rhel-x64-netcoreapp2.0.tar.gz",
|
||||
"OpenSUSE_13_2": "rhel-x64-netcoreapp2.0.tar.gz",
|
||||
"RHEL_7": "rhel-x64-netcoreapp2.0.tar.gz",
|
||||
"SLES_12_2": "rhel-x64-netcoreapp2.0.tar.gz",
|
||||
"Ubuntu_14": "rhel-x64-netcoreapp2.0.tar.gz",
|
||||
"Ubuntu_16": "rhel-x64-netcoreapp2.0.tar.gz"
|
||||
"Windows_86": "win-x86-netcoreapp2.1.zip",
|
||||
"Windows_64": "win-x64-netcoreapp2.1.zip",
|
||||
"OSX": "osx-x64-netcoreapp2.1.tar.gz",
|
||||
"CentOS_7": "rhel-x64-netcoreapp2.1.tar.gz",
|
||||
"Debian_8": "rhel-x64-netcoreapp2.1.tar.gz",
|
||||
"Fedora_23": "rhel-x64-netcoreapp2.1.tar.gz",
|
||||
"OpenSUSE_13_2": "rhel-x64-netcoreapp2.1.tar.gz",
|
||||
"RHEL_7": "rhel-x64-netcoreapp2.1.tar.gz",
|
||||
"SLES_12_2": "rhel-x64-netcoreapp2.1.tar.gz",
|
||||
"Ubuntu_14": "rhel-x64-netcoreapp2.1.tar.gz",
|
||||
"Ubuntu_16": "rhel-x64-netcoreapp2.1.tar.gz"
|
||||
},
|
||||
"installDirectory": "../sqltoolsservice/{#platform#}/{#version#}",
|
||||
"executableFiles": ["MicrosoftSqlToolsServiceLayer.exe", "MicrosoftSqlToolsServiceLayer"]
|
||||
|
||||
@@ -9,3 +9,5 @@ export const providerId = 'MSSQL';
|
||||
export const serviceCrashMessage = 'SQL Tools Service component exited unexpectedly. Please restart SQL Operations Studio.';
|
||||
export const serviceCrashButton = 'View Known Issues';
|
||||
export const serviceCrashLink = 'https://github.com/Microsoft/vscode-mssql/wiki/SqlToolsService-Known-Issues';
|
||||
export const configLogDebugInfo = 'logDebugInfo';
|
||||
export const extensionConfigSectionName = 'mssql';
|
||||
@@ -16,7 +16,7 @@ import { CredentialStore } from './credentialstore/credentialstore';
|
||||
import { AzureResourceProvider } from './resourceProvider/resourceProvider';
|
||||
import * as Utils from './utils';
|
||||
import { Telemetry, LanguageClientErrorHandler } from './telemetry';
|
||||
import { TelemetryFeature } from './features';
|
||||
import { TelemetryFeature, AgentServicesFeature } from './features';
|
||||
|
||||
const baseConfig = require('./config.json');
|
||||
const outputChannel = vscode.window.createOutputChannel(Constants.serviceName);
|
||||
@@ -47,15 +47,17 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
let clientOptions: ClientOptions = {
|
||||
documentSelector: ['sql'],
|
||||
synchronize: {
|
||||
configurationSection: 'mssql'
|
||||
configurationSection: Constants.extensionConfigSectionName
|
||||
},
|
||||
providerId: Constants.providerId,
|
||||
errorHandler: new LanguageClientErrorHandler(),
|
||||
features: [
|
||||
// we only want to add new features
|
||||
...SqlOpsDataClient.defaultFeatures,
|
||||
TelemetryFeature
|
||||
]
|
||||
TelemetryFeature,
|
||||
AgentServicesFeature
|
||||
],
|
||||
outputChannel: new CustomOutputChannel()
|
||||
};
|
||||
|
||||
const installationStart = Date.now();
|
||||
@@ -99,6 +101,13 @@ function generateServerOptions(executablePath: string): ServerOptions {
|
||||
launchArgs.push('--log-dir');
|
||||
let logFileLocation = path.join(Utils.getDefaultLogLocation(), 'mssql');
|
||||
launchArgs.push(logFileLocation);
|
||||
let config = vscode.workspace.getConfiguration(Constants.extensionConfigSectionName);
|
||||
if (config) {
|
||||
let logDebugInfo = config[Constants.configLogDebugInfo];
|
||||
if (logDebugInfo) {
|
||||
launchArgs.push('--enable-logging');
|
||||
}
|
||||
}
|
||||
|
||||
return { command: executablePath, args: launchArgs, transport: TransportKind.stdio };
|
||||
}
|
||||
@@ -138,3 +147,23 @@ function generateHandleServerProviderEvent() {
|
||||
// this method is called when your extension is deactivated
|
||||
export function deactivate(): void {
|
||||
}
|
||||
|
||||
class CustomOutputChannel implements vscode.OutputChannel {
|
||||
name: string;
|
||||
append(value: string): void {
|
||||
console.log(value);
|
||||
}
|
||||
appendLine(value: string): void {
|
||||
console.log(value);
|
||||
}
|
||||
clear(): void {
|
||||
}
|
||||
show(preserveFocus?: boolean): void;
|
||||
show(column?: vscode.ViewColumn, preserveFocus?: boolean): void;
|
||||
show(column?: any, preserveFocus?: any) {
|
||||
}
|
||||
hide(): void {
|
||||
}
|
||||
dispose(): void {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
// "button.disabledForeground": "#888888" ,
|
||||
|
||||
//Dropdown Control
|
||||
"dropdown.background": "#333333",
|
||||
"dropdown.background": "#212121",
|
||||
"dropdown.foreground": "#fffffe",
|
||||
"dropdown.border": "#888888",
|
||||
|
||||
@@ -56,12 +56,12 @@
|
||||
"tab.activeBackground": "#212121",
|
||||
"tab.activeForeground": "#ffffff",
|
||||
"tab.inactiveBackground": "#444444",
|
||||
"tab.inactiveForeground": "#888888",
|
||||
"tab.inactiveForeground": "#b6b6b6",
|
||||
"tab.border": "#3c3c3c",
|
||||
"panel.background": "#212121",
|
||||
"panel.border": "#515151",
|
||||
"panelTitle.activeForeground": "#ffffff",
|
||||
"panelTitle.inactiveForeground": "#888888"
|
||||
"panelTitle.inactiveForeground": "#888888"
|
||||
},
|
||||
"tokenColors": [
|
||||
{
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
// "button.disabledForeground": "#888888",
|
||||
|
||||
//Dropdown Control
|
||||
"dropdown.background": "#EAEAEA00",
|
||||
"dropdown.background": "#fffffe",
|
||||
"dropdown.foreground": "#4a4a4a",
|
||||
"dropdown.border": "#C8C8C8",
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"tab.activeBackground": "#FFFFFE",
|
||||
"tab.activeForeground": "#4A4A4A",
|
||||
"tab.inactiveBackground": "#f4f4f4",
|
||||
"tab.inactiveForeground": "#888888",
|
||||
"tab.inactiveForeground": "#707070",
|
||||
"tab.border": "#EAEAEA",
|
||||
"tab.unfocusedInactiveForeground": "#888888",
|
||||
"tab.unfocusedActiveForeground": "#212121",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sqlops",
|
||||
"version": "0.28.1",
|
||||
"version": "0.28.4",
|
||||
"distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
"darwinBundleIdentifier": "com.sqlopsstudio.oss",
|
||||
"reportIssueUrl": "https://github.com/Microsoft/sqlopsstudio/issues/new?labels=customer%20reported%20issue",
|
||||
"requestFeatureUrl": "https://github.com/Microsoft/sqlopsstudio/issues/new?labels=feature-request",
|
||||
"privacyStatementUrl": "https://privacy.microsoft.com/en-us/privacystatement",
|
||||
"telemetryOptOutUrl": "https://github.com/Microsoft/sqlopsstudio/wiki/How-to-Disable-Telemetry-Reporting",
|
||||
"urlProtocol": "sqlops",
|
||||
"enableTelemetry": true,
|
||||
"aiConfig": {
|
||||
|
||||
3
samples/sqlservices/.gitignore
vendored
Normal file
3
samples/sqlservices/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
*.vsix
|
||||
typings/sqlops.proposed.d.ts
|
||||
57
samples/sqlservices/.vscode/launch.json
vendored
Normal file
57
samples/sqlservices/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
// A launch configuration that launches the extension inside a new window
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
|
||||
// To debug the extension:
|
||||
// 1. please install the "SQL Operations Studio Debug" extension into VSCode
|
||||
// 2. Ensure sqlops is added to your path:
|
||||
// - open SQL Operations Studio
|
||||
// - run the command "Install 'sqlops' command in PATH"
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"name": "Debug in SqlOps install",
|
||||
"type": "sqlopsExtensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "sqlops",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"name": "Attach to Ops Studio",
|
||||
"protocol": "inspector",
|
||||
"port": 5870,
|
||||
"restart": true,
|
||||
"sourceMaps": true,
|
||||
"outFiles": [
|
||||
"${workspaceRoot}/out/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "",
|
||||
"timeout": 25000
|
||||
},
|
||||
{
|
||||
"name": "Debug in enlistment",
|
||||
"type": "sqlopsExtensionHost",
|
||||
"request": "launch",
|
||||
"windows": {
|
||||
"runtimeExecutable": "${workspaceFolder}/../../scripts/sql.bat"
|
||||
},
|
||||
"osx": {
|
||||
"runtimeExecutable": "${workspaceFolder}/../../scripts/sql.sh"
|
||||
},
|
||||
"linux": {
|
||||
"runtimeExecutable": "${workspaceFolder}/../../scripts/sql.sh"
|
||||
},
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"timeout": 20000
|
||||
}
|
||||
]
|
||||
}
|
||||
14
samples/sqlservices/.vscode/tasks.json
vendored
Normal file
14
samples/sqlservices/.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "gulp",
|
||||
"task": "build",
|
||||
"problemMatcher": [
|
||||
"$gulp-tsc"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
4
samples/sqlservices/.vscodeignore
Normal file
4
samples/sqlservices/.vscodeignore
Normal file
@@ -0,0 +1,4 @@
|
||||
.vscode/**
|
||||
.vscode-test/**
|
||||
.gitignore
|
||||
vsc-extension-quickstart.md
|
||||
1
samples/sqlservices/README.md
Normal file
1
samples/sqlservices/README.md
Normal file
@@ -0,0 +1 @@
|
||||
This is a sample extension that will show some basic model-backed UI scenarios. The long-term goal is to use SQL Service querying (e.g. see if Agent and other services are running) and visualize in interesting ways. Additional suggestions for improving this sample are welcome.
|
||||
14
samples/sqlservices/gulpfile.js
Normal file
14
samples/sqlservices/gulpfile.js
Normal file
@@ -0,0 +1,14 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// NOTE: These are es6 gulpfiles
|
||||
|
||||
// Basic build tasks
|
||||
require('./tasks/buildtasks');
|
||||
|
||||
// VSIX generation tasks
|
||||
require('./tasks/packagetasks');
|
||||
7118
samples/sqlservices/package-lock.json
generated
Normal file
7118
samples/sqlservices/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
81
samples/sqlservices/package.json
Normal file
81
samples/sqlservices/package.json
Normal file
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"name": "sqlservices",
|
||||
"displayName": "sqlservices",
|
||||
"description": "Lists SQL Server service status in the management dashboard for a server",
|
||||
"version": "0.0.1",
|
||||
"publisher": "demo",
|
||||
"engines": {
|
||||
"vscode": "^1.21.0",
|
||||
"sqlops": "*"
|
||||
},
|
||||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"*"
|
||||
],
|
||||
"main": "./out/src/extension",
|
||||
"contributes": {
|
||||
"dashboard.tabs": [
|
||||
{
|
||||
"id": "sqlservices.tab",
|
||||
"title": "sqlservices",
|
||||
"icon": {
|
||||
"light": "./out/src/media/insights.svg",
|
||||
"dark": "./out/src/media/insights_inverse.svg"
|
||||
},
|
||||
"description": "Shows available services running in the SQL Server instance",
|
||||
"container": {
|
||||
"nav-section": [
|
||||
{
|
||||
"id": "sqlservices",
|
||||
"title": "Services",
|
||||
"gridItemConfig": {
|
||||
"sizex": 2,
|
||||
"sizey": 1
|
||||
},
|
||||
"container": {
|
||||
"modelview-container": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "splitPanel",
|
||||
"title": "SplitPanel",
|
||||
"gridItemConfig": {
|
||||
"sizex": 2,
|
||||
"sizey": 1
|
||||
},
|
||||
"container": {
|
||||
"modelview-container": null
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp build",
|
||||
"compile": "gulp compile",
|
||||
"watch": "gulp watch",
|
||||
"typings": "gulp copytypings",
|
||||
"postinstall": "node ./node_modules/vscode/bin/install && node ./node_modules/sqlops/bin/install && gulp copytypings"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-nls": "^3.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^7.0.43",
|
||||
"child-process-promise": "^2.2.1",
|
||||
"del": "^3.0.0",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-color": "0.0.1",
|
||||
"gulp-sourcemaps": "^2.6.4",
|
||||
"gulp-tslint": "^6.0.2",
|
||||
"gulp-typescript": "^3.2.4",
|
||||
"sqlops": "github:anthonydresser/sqlops-extension-sqlops",
|
||||
"tslint": "^3.14.0",
|
||||
"typescript": "^2.6.1",
|
||||
"vscode": "^1.1.14"
|
||||
}
|
||||
}
|
||||
9
samples/sqlservices/sql/query.sql
Normal file
9
samples/sqlservices/sql/query.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
/*
|
||||
* This file should contain SQL code that returns a result set
|
||||
* To get started, build your own queries in SQL Operations Studio and click the
|
||||
* "View as Chart" button to get the correct chart format. Then choose "Create Insight"
|
||||
* and update the package.json with the JSON contents, and this file with the query
|
||||
* used to generate the chart.
|
||||
*/
|
||||
select 'My Label' as [Label], 1 as [Value]
|
||||
10
samples/sqlservices/src/constants.ts
Normal file
10
samples/sqlservices/src/constants.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// CONFIG VALUES ///////////////////////////////////////////////////////////
|
||||
export const extensionConfigSectionName = 'sqlservices';
|
||||
export const configLogDebugInfo = 'logDebugInfo';
|
||||
109
samples/sqlservices/src/controllers/mainController.ts
Normal file
109
samples/sqlservices/src/controllers/mainController.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as Utils from '../utils';
|
||||
import * as vscode from 'vscode';
|
||||
import SplitPropertiesPanel from './splitPropertiesPanel';
|
||||
|
||||
/**
|
||||
* The main controller class that initializes the extension
|
||||
*/
|
||||
export default class MainController implements vscode.Disposable {
|
||||
|
||||
constructor(protected context: vscode.ExtensionContext) {
|
||||
|
||||
}
|
||||
|
||||
// PUBLIC METHODS //////////////////////////////////////////////////////
|
||||
|
||||
public dispose(): void {
|
||||
this.deactivate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates the extension
|
||||
*/
|
||||
public deactivate(): void {
|
||||
Utils.logDebug('Main controller deactivated');
|
||||
}
|
||||
|
||||
public activate(): Promise<boolean> {
|
||||
this.registerSqlServicesModelView();
|
||||
this.registerSplitPanelModelView();
|
||||
|
||||
sqlops.tasks.registerTask('sqlservices.clickTask', (profile) => {
|
||||
vscode.window.showInformationMessage(`Clicked from profile ${profile.serverName}.${profile.databaseName}`);
|
||||
});
|
||||
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
private registerSqlServicesModelView(): void {
|
||||
sqlops.dashboard.registerModelViewProvider('sqlservices', async (view) => {
|
||||
let flexModel = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'row',
|
||||
alignItems: 'center'
|
||||
}).withItems([
|
||||
// 1st child panel with N cards
|
||||
view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
})
|
||||
.withItems([
|
||||
view.modelBuilder.card()
|
||||
.withProperties<sqlops.CardProperties>({
|
||||
label: 'label1',
|
||||
value: 'value1',
|
||||
actions: [{ label: 'action', taskId: 'sqlservices.clickTask' }]
|
||||
})
|
||||
.component()
|
||||
]).component(),
|
||||
// 2nd child panel with N cards
|
||||
view.modelBuilder.flexContainer()
|
||||
.withLayout({ flexFlow: 'column' })
|
||||
.withItems([
|
||||
view.modelBuilder.card()
|
||||
.withProperties<sqlops.CardProperties>({
|
||||
label: 'label2',
|
||||
value: 'value2',
|
||||
actions: [{ label: 'action', taskId: 'sqlservices.clickTask' }]
|
||||
})
|
||||
.component()
|
||||
]).component()
|
||||
], { flex: '1 1 50%' })
|
||||
.component();
|
||||
await view.initializeModel(flexModel);
|
||||
});
|
||||
}
|
||||
|
||||
private registerSplitPanelModelView(): void {
|
||||
sqlops.dashboard.registerModelViewProvider('splitPanel', async (view) => {
|
||||
let numPanels = 3;
|
||||
let splitPanel = new SplitPropertiesPanel(view, numPanels);
|
||||
await view.initializeModel(splitPanel.modelBase);
|
||||
|
||||
// Add a bunch of cards after an initial timeout
|
||||
setTimeout(async () => {
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
let panel = i % numPanels;
|
||||
let card = view.modelBuilder.card().component();
|
||||
card.label = `label${i.toString()}`;
|
||||
|
||||
splitPanel.addItem(card, panel);
|
||||
}
|
||||
|
||||
}, 0);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
43
samples/sqlservices/src/controllers/splitPropertiesPanel.ts
Normal file
43
samples/sqlservices/src/controllers/splitPropertiesPanel.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
/**
|
||||
* The main controller class that initializes the extension
|
||||
*/
|
||||
export default class SplitPropertiesPanel {
|
||||
private panels: sqlops.FlexContainer[];
|
||||
private _modelBase: sqlops.FlexContainer;
|
||||
constructor(view: sqlops.ModelView, numPanels: number) {
|
||||
this.panels = [];
|
||||
let ratio = Math.round(100 / numPanels);
|
||||
for (let i = 0; i < numPanels; i++) {
|
||||
this.panels.push(view.modelBuilder.flexContainer()
|
||||
.withLayout({ flexFlow: 'column' }).component());
|
||||
}
|
||||
this._modelBase = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'row'
|
||||
}).withItems(this.panels, {
|
||||
flex: `0 1 ${ratio}%`
|
||||
})
|
||||
.component();
|
||||
}
|
||||
|
||||
public get modelBase(): sqlops.Component {
|
||||
return this._modelBase;
|
||||
}
|
||||
|
||||
public addItem(item: sqlops.Component, panel: number): void {
|
||||
if (panel >= this.panels.length) {
|
||||
throw new Error(`Cannot add to panel ${panel} as only ${this.panels.length - 1} panels defined`);
|
||||
}
|
||||
this.panels[panel].addItem(item, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
37
samples/sqlservices/src/extension.ts
Normal file
37
samples/sqlservices/src/extension.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import MainController from './controllers/mainController';
|
||||
|
||||
let mainController: MainController;
|
||||
|
||||
export function activate(context: vscode.ExtensionContext): Promise<boolean> {
|
||||
let activations: Promise<boolean>[] = [];
|
||||
|
||||
// Start the main controller
|
||||
mainController = new MainController(context);
|
||||
context.subscriptions.push(mainController);
|
||||
activations.push(mainController.activate());
|
||||
|
||||
return Promise.all(activations)
|
||||
.then((results: boolean[]) => {
|
||||
for (let result of results) {
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
export function deactivate(): void {
|
||||
if (mainController) {
|
||||
mainController.deactivate();
|
||||
}
|
||||
}
|
||||
1
samples/sqlservices/src/media/insights.svg
Normal file
1
samples/sqlservices/src/media/insights.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#212121;}</style></defs><title>insights</title><path class="cls-1" d="M15,4V8H14V5.71L9.49,10.2l-2-2L2,13.71V14H15v1H1V1H2V12.29L7.49,6.8l2,2L13.28,5H11V4Z"/></svg>
|
||||
|
After Width: | Height: | Size: 282 B |
1
samples/sqlservices/src/media/insights_inverse.svg
Normal file
1
samples/sqlservices/src/media/insights_inverse.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>insights_inverse</title><path class="cls-1" d="M15,4V8H14V5.71L9.49,10.2l-2-2L2,13.71V14H15v1H1V1H2V12.29L7.49,6.8l2,2L13.28,5H11V4Z"/></svg>
|
||||
|
After Width: | Height: | Size: 287 B |
52
samples/sqlservices/src/utils.ts
Normal file
52
samples/sqlservices/src/utils.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as fs from 'fs-extra';
|
||||
import * as handlebars from 'handlebars';
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import * as Constants from './constants';
|
||||
import * as nls from 'vscode-nls';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
/**
|
||||
* Helper to log messages to the developer console if enabled
|
||||
* @param msg Message to log to the console
|
||||
*/
|
||||
export function logDebug(msg: any): void {
|
||||
let config = vscode.workspace.getConfiguration(Constants.extensionConfigSectionName);
|
||||
let logDebugInfo = config[Constants.configLogDebugInfo];
|
||||
if (logDebugInfo === true) {
|
||||
let currentTime = new Date().toLocaleTimeString();
|
||||
let outputMsg = '[' + currentTime + ']: ' + msg ? msg.toString() : '';
|
||||
console.log(outputMsg);
|
||||
}
|
||||
}
|
||||
|
||||
export function renderTemplateHtml(extensionPath: string, templateName: string, templateValues: object): Thenable<string> {
|
||||
let templatePath = path.join(extensionPath, 'resources', templateName);
|
||||
|
||||
// 1) Read the template from the disk
|
||||
// 2) Compile it as a handlebars template and render the HTML
|
||||
// 3) On failure, return a simple string as an error
|
||||
return fs.readFile(templatePath, 'utf-8')
|
||||
.then(templateText => {
|
||||
let template = handlebars.compile(templateText);
|
||||
return template(templateValues);
|
||||
})
|
||||
.then(
|
||||
undefined,
|
||||
error => {
|
||||
logDebug(error);
|
||||
return localize('errorLoadingTab', 'An error occurred while loading the tab');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
124
samples/sqlservices/tasks/buildtasks.js
Normal file
124
samples/sqlservices/tasks/buildtasks.js
Normal file
@@ -0,0 +1,124 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
"use strict";
|
||||
|
||||
let del = require('del');
|
||||
let gulp = require('gulp');
|
||||
let srcmap = require('gulp-sourcemaps');
|
||||
let tslint = require('gulp-tslint');
|
||||
let ts = require('gulp-typescript');
|
||||
let cproc = require('child_process');
|
||||
let os = require('os');
|
||||
|
||||
let config = require('./config');
|
||||
let tsProject = ts.createProject('tsconfig.json');
|
||||
|
||||
|
||||
// GULP TASKS //////////////////////////////////////////////////////////////
|
||||
gulp.task('clean', function(done) {
|
||||
return del('out', done);
|
||||
});
|
||||
|
||||
gulp.task('lint', () => {
|
||||
return gulp.src([
|
||||
config.paths.project.root + '/src/**/*.ts',
|
||||
config.paths.project.root + '/test/**/*.ts'
|
||||
])
|
||||
.pipe((tslint({
|
||||
formatter: "verbose"
|
||||
})))
|
||||
.pipe(tslint.report());
|
||||
});
|
||||
|
||||
gulp.task('compile:src', function(done) {
|
||||
gulp.src([
|
||||
config.paths.project.root + '/src/**/*.sql',
|
||||
config.paths.project.root + '/src/**/*.svg',
|
||||
config.paths.project.root + '/src/**/*.html'
|
||||
]).pipe(gulp.dest('out/src/'));
|
||||
|
||||
let srcFiles = [
|
||||
config.paths.project.root + '/src/**/*.ts',
|
||||
config.paths.project.root + '/src/**/*.js',
|
||||
config.paths.project.root + '/typings/**/*.ts'
|
||||
];
|
||||
|
||||
return gulp.src(srcFiles)
|
||||
.pipe(srcmap.init())
|
||||
.pipe(tsProject())
|
||||
.on('error', function() {
|
||||
if (process.env.BUILDMACHINE) {
|
||||
done('Extension Tests failed to build. See Above.');
|
||||
process.exit(1);
|
||||
}
|
||||
})
|
||||
.pipe(srcmap.write('.', {
|
||||
sourceRoot: function(file) {
|
||||
return file.cwd + '/src';
|
||||
}
|
||||
}))
|
||||
.pipe(gulp.dest('out/src/'));
|
||||
});
|
||||
|
||||
gulp.task('compile:test', function(done) {
|
||||
let srcFiles = [
|
||||
config.paths.project.root + '/test/**/*.ts',
|
||||
config.paths.project.root + '/typings/**/*.ts'
|
||||
];
|
||||
|
||||
return gulp.src(srcFiles)
|
||||
.pipe(srcmap.init())
|
||||
.pipe(tsProject())
|
||||
.on('error', function() {
|
||||
if(process.env.BUILDMACHINE) {
|
||||
done('Failed to compile test source, see above.');
|
||||
process.exit(1);
|
||||
}
|
||||
})
|
||||
.pipe(srcmap.write('.', {sourceRoot: function(file) { return file.cwd + '/test'; }}))
|
||||
.pipe(gulp.dest('out/test/'));
|
||||
});
|
||||
|
||||
// COMPOSED GULP TASKS /////////////////////////////////////////////////////
|
||||
gulp.task("compile", gulp.series("compile:src", "compile:test"));
|
||||
|
||||
gulp.task("build", gulp.series("clean", "lint", "compile"));
|
||||
|
||||
gulp.task("watch", function() {
|
||||
gulp.watch([config.paths.project.root + '/src/**/*',
|
||||
config.paths.project.root + '/test/**/*.ts'],
|
||||
gulp.series('build'));
|
||||
});
|
||||
|
||||
gulp.task('test', (done) => {
|
||||
let workspace = process.env['WORKSPACE'];
|
||||
if (!workspace) {
|
||||
workspace = process.cwd();
|
||||
}
|
||||
process.env.JUNIT_REPORT_PATH = workspace + '/test-reports/ext_xunit.xml';
|
||||
|
||||
let sqlopsPath = 'sqlops';
|
||||
if (process.env['SQLOPS_DEV']) {
|
||||
let suffix = os.platform === 'win32' ? 'bat' : 'sh';
|
||||
sqlopsPath = `${process.env['SQLOPS_DEV']}/scripts/sql-cli.${suffix}`;
|
||||
}
|
||||
console.log(`Using SQLOPS Path of ${sqlopsPath}`);
|
||||
|
||||
cproc.exec(`${sqlopsPath} --extensionDevelopmentPath="${workspace}" --extensionTestsPath="${workspace}/out/test" --verbose`, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.error(`exec error: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`stdout: ${stdout}`);
|
||||
console.log(`stderr: ${stderr}`);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('copytypings', function() {
|
||||
return gulp.src(config.paths.project.root + '/../../src/sql/sqlops.proposed.d.ts')
|
||||
.pipe(gulp.dest('typings/'));
|
||||
});
|
||||
24
samples/sqlservices/tasks/config.js
Normal file
24
samples/sqlservices/tasks/config.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
var path = require('path');
|
||||
|
||||
var projectRoot = path.resolve(path.dirname(__dirname));
|
||||
var srcRoot = path.resolve(projectRoot, 'src');
|
||||
var localization = path.resolve(projectRoot, 'localization');
|
||||
|
||||
var config = {
|
||||
paths: {
|
||||
project: {
|
||||
root: projectRoot,
|
||||
localization: localization
|
||||
},
|
||||
extension: {
|
||||
root: srcRoot
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
36
samples/sqlservices/tasks/packagetasks.js
Normal file
36
samples/sqlservices/tasks/packagetasks.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
let gulp = require('gulp');
|
||||
let exec = require('child-process-promise').exec;
|
||||
let color = require('gulp-color');
|
||||
|
||||
// CONSTANTS ///////////////////////////////////////////////////////////////
|
||||
let packageVals = require('../package');
|
||||
|
||||
// HELPER FUNCTIONS ////////////////////////////////////////////////////////
|
||||
|
||||
let buildPackage = function(packageName) {
|
||||
// Make sure there are
|
||||
if (!packageVals.repository) {
|
||||
return Promise.reject("Repository field is not defined in package.json");
|
||||
}
|
||||
|
||||
// Initialize the package command with program and command
|
||||
let vsceArgs = [];
|
||||
vsceArgs.push('./node_modules/vsce/out/vsce');
|
||||
vsceArgs.push('package'); // package command
|
||||
|
||||
// Add the package name
|
||||
vsceArgs.push('-o');
|
||||
vsceArgs.push(packageName);
|
||||
|
||||
// Put it all together and execute the command
|
||||
let command = vsceArgs.join(' ');
|
||||
console.log(command);
|
||||
return exec(command);
|
||||
};
|
||||
16
samples/sqlservices/tsconfig.json
Normal file
16
samples/sqlservices/tsconfig.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "ES6",
|
||||
"lib": [ "es6" ],
|
||||
"sourceMap": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"rootDir": "."
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
".vscode-test"
|
||||
]
|
||||
}
|
||||
123
samples/sqlservices/tslint.json
Normal file
123
samples/sqlservices/tslint.json
Normal file
@@ -0,0 +1,123 @@
|
||||
{
|
||||
"rules": {
|
||||
"align": [
|
||||
true,
|
||||
"parameters",
|
||||
"statements"
|
||||
],
|
||||
"ban": false,
|
||||
"class-name": true,
|
||||
"comment-format": [
|
||||
true,
|
||||
"check-space"
|
||||
],
|
||||
"curly": true,
|
||||
"eofline": true,
|
||||
"forin": true,
|
||||
"indent": [
|
||||
true,
|
||||
"tabs"
|
||||
],
|
||||
"interface-name": true,
|
||||
"jsdoc-format": true,
|
||||
"label-position": true,
|
||||
"label-undefined": true,
|
||||
"max-line-length": [
|
||||
true,
|
||||
160
|
||||
],
|
||||
"member-access": false,
|
||||
"member-ordering": false,
|
||||
"no-any": false,
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
"no-conditional-assignment": true,
|
||||
"no-consecutive-blank-lines": false,
|
||||
"no-console": [
|
||||
true,
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-construct": true,
|
||||
"no-constructor-vars": false,
|
||||
"no-debugger": true,
|
||||
"no-duplicate-key": true,
|
||||
"no-duplicate-variable": true,
|
||||
"no-empty": true,
|
||||
"no-eval": true,
|
||||
"no-inferrable-types": false,
|
||||
"no-internal-module": true,
|
||||
"no-null-keyword": true,
|
||||
"no-require-imports": false,
|
||||
"no-shadowed-variable": true,
|
||||
"no-string-literal": false,
|
||||
"no-switch-case-fall-through": false,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unreachable": true,
|
||||
"no-unused-expression": false,
|
||||
"no-unused-variable": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"no-var-requires": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
true,
|
||||
"check-open-brace",
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-finally",
|
||||
"check-whitespace"
|
||||
],
|
||||
"quotemark": [
|
||||
true,
|
||||
"single",
|
||||
"avoid-escape"
|
||||
],
|
||||
"radix": true,
|
||||
"semicolon": true,
|
||||
"switch-default": true,
|
||||
"trailing-comma": [
|
||||
true,
|
||||
{
|
||||
"multiline": "never",
|
||||
"singleline": "never"
|
||||
}
|
||||
],
|
||||
"triple-equals": [
|
||||
true,
|
||||
"allow-null-check"
|
||||
],
|
||||
"typedef": [
|
||||
true,
|
||||
"call-signature",
|
||||
"property-declaration"
|
||||
],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"use-strict": false,
|
||||
"variable-name": [
|
||||
true,
|
||||
"allow-leading-underscore",
|
||||
"ban-keywords"
|
||||
],
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
]
|
||||
}
|
||||
}
|
||||
3689
samples/sqlservices/yarn.lock
Normal file
3689
samples/sqlservices/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,7 @@ export interface ICheckboxOptions {
|
||||
enabled?: boolean;
|
||||
checked?: boolean;
|
||||
onChange?: (val: boolean) => void;
|
||||
ariaLabel?: string;
|
||||
}
|
||||
|
||||
export class Checkbox extends Widget {
|
||||
@@ -27,6 +28,10 @@ export class Checkbox extends Widget {
|
||||
this._el = document.createElement('input');
|
||||
this._el.type = 'checkbox';
|
||||
|
||||
if (opts.ariaLabel) {
|
||||
this._el.setAttribute('aria-label', opts.ariaLabel);
|
||||
}
|
||||
|
||||
this.onchange(this._el, e => {
|
||||
this._onChange.fire(this.checked);
|
||||
});
|
||||
|
||||
@@ -49,6 +49,10 @@ export interface IDropdownOptions extends IDropdownStyles {
|
||||
* Error Message to show if input is not part of the supplied list, only used if strictSelection = false
|
||||
*/
|
||||
errorMessage?: string;
|
||||
/**
|
||||
* Value to use as aria-label for the input box
|
||||
*/
|
||||
ariaLabel?: string;
|
||||
}
|
||||
|
||||
export interface IDropdownStyles {
|
||||
@@ -124,7 +128,8 @@ export class Dropdown extends Disposable {
|
||||
validation: v => this._inputValidator(v)
|
||||
},
|
||||
placeholder: this._options.placeholder,
|
||||
actions: [this._toggleAction]
|
||||
actions: [this._toggleAction],
|
||||
ariaLabel: this._options.ariaLabel
|
||||
});
|
||||
|
||||
this._register(DOM.addDisposableListener(this._input.inputElement, DOM.EventType.FOCUS, () => {
|
||||
|
||||
@@ -20,6 +20,7 @@ import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/cont
|
||||
import { Button } from 'sql/base/browser/ui/button/button';
|
||||
import * as TelemetryUtils from 'sql/common/telemetryUtilities';
|
||||
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
export const MODAL_SHOWING_KEY = 'modalShowing';
|
||||
export const MODAL_SHOWING_CONTEXT = new RawContextKey<Array<string>>(MODAL_SHOWING_KEY, []);
|
||||
@@ -155,6 +156,7 @@ export abstract class Modal extends Disposable implements IThemable {
|
||||
modalHeader.div({ class: 'modal-go-back' }, (cellContainer) => {
|
||||
this._backButton = new Button(cellContainer);
|
||||
this._backButton.icon = 'backButtonIcon';
|
||||
this._backButton.title = localize('modalBack', "Back");
|
||||
});
|
||||
}
|
||||
if (this._modalOptions.hasTitleIcon) {
|
||||
|
||||
@@ -43,7 +43,8 @@ export function createOptionElement(option: sqlops.ServiceOption, rowContainer:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ariaLabel: option.displayName
|
||||
});
|
||||
optionWidget.value = optionValue;
|
||||
inputElement = this.findElement(rowContainer, 'input');
|
||||
@@ -55,7 +56,8 @@ export function createOptionElement(option: sqlops.ServiceOption, rowContainer:
|
||||
optionWidget = new InputBox(rowContainer.getHTMLElement(), contextViewService, {
|
||||
validationOptions: {
|
||||
validation: (value: string) => (!value && option.isRequired) ? ({ type: MessageType.ERROR, content: option.displayName + missingErrorMessage }) : null
|
||||
}
|
||||
},
|
||||
ariaLabel: option.displayName
|
||||
});
|
||||
optionWidget.value = optionValue;
|
||||
if (option.valueType === ServiceOptionType.password) {
|
||||
|
||||
@@ -71,7 +71,7 @@ panel {
|
||||
}
|
||||
|
||||
.tabbedPanel .tabList .tab .tabLabel {
|
||||
opacity: 0.6;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.tabbedPanel .tabList .tab .tabLabel.icon {
|
||||
|
||||
@@ -49,7 +49,7 @@ let idPool = 0;
|
||||
|
||||
<div class="tabbedPanel fullsize" #tabbedPanel>
|
||||
<div *ngIf="!options.showTabsWhenOne ? _tabs.length !== 1 : true" class="composite title" #titleContainer>
|
||||
<div class="tabList" #tabList>
|
||||
<div class="tabList" #tabList role="tablist">
|
||||
<div *ngFor="let tab of _tabs">
|
||||
<tab-header [tab]="tab" [showIcon]="options.showIcon" (onSelectTab)='selectTab($event)' (onCloseTab)='closeTab($event)'> </tab-header>
|
||||
</div>
|
||||
@@ -182,7 +182,7 @@ export class PanelComponent extends Disposable implements AfterContentInit, OnIn
|
||||
if (input instanceof TabComponent) {
|
||||
tab = input;
|
||||
} else if (types.isNumber(input)) {
|
||||
tab = this._tabs[input];
|
||||
tab = this._tabs.toArray()[input];
|
||||
} else if (types.isString(input)) {
|
||||
tab = this._tabs.find(i => i.identifier === input);
|
||||
}
|
||||
@@ -226,6 +226,18 @@ export class PanelComponent extends Disposable implements AfterContentInit, OnIn
|
||||
return this._activeTab.identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select on the next tab
|
||||
*/
|
||||
public selectOnNextTab(): void {
|
||||
let activeIndex = this._tabs.toArray().findIndex(i => i === this._activeTab);
|
||||
let nextTabIndex = activeIndex + 1;
|
||||
if (nextTabIndex === this._tabs.length) {
|
||||
nextTabIndex = 0;
|
||||
}
|
||||
this.selectTab(nextTabIndex);
|
||||
}
|
||||
|
||||
private findAndRemoveTabFromMRU(tab: TabComponent): void {
|
||||
let mruIndex = this._mru.findIndex(i => i === tab);
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
this.$parent.appendTo(container);
|
||||
this.$header = $('.composite.title');
|
||||
this.$tabList = $('.tabList');
|
||||
this.$tabList.attr('role', 'tablist');
|
||||
this.$tabList.style('height', this.headersize + 'px');
|
||||
this.$header.append(this.$tabList);
|
||||
let actionbarcontainer = $('.title-actions');
|
||||
@@ -89,6 +90,9 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
private _createTab(tab: IInternalPanelTab): void {
|
||||
let tabHeaderElement = $('.tab-header');
|
||||
tabHeaderElement.attr('tabindex', '0');
|
||||
tabHeaderElement.attr('role', 'tab');
|
||||
tabHeaderElement.attr('aria-selected', 'false');
|
||||
tabHeaderElement.attr('aria-label', tab.title);
|
||||
let tabElement = $('.tab');
|
||||
tabHeaderElement.append(tabElement);
|
||||
let tabLabel = $('a.tabLabel');
|
||||
@@ -114,7 +118,7 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
|
||||
if (this._shownTab) {
|
||||
this._tabMap.get(this._shownTab).label.removeClass('active');
|
||||
this._tabMap.get(this._shownTab).header.removeClass('active');
|
||||
this._tabMap.get(this._shownTab).header.removeClass('active').attr('aria-selected', 'false');
|
||||
}
|
||||
|
||||
this._shownTab = id;
|
||||
@@ -122,6 +126,7 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
let tab = this._tabMap.get(this._shownTab);
|
||||
tab.label.addClass('active');
|
||||
tab.header.addClass('active');
|
||||
tab.header.attr('aria-selected', 'true');
|
||||
tab.view.render(this.$body.getHTMLElement());
|
||||
this._onTabChange.fire(id);
|
||||
if (this._currentDimensions) {
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
import 'vs/css!./media/panel';
|
||||
|
||||
import { registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
import { PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER } from 'vs/workbench/common/theme';
|
||||
import { TAB_ACTIVE_FOREGROUND, TAB_INACTIVE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER } from 'vs/workbench/common/theme';
|
||||
import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
|
||||
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
||||
|
||||
// Title Active
|
||||
const titleActive = theme.getColor(PANEL_ACTIVE_TITLE_FOREGROUND);
|
||||
const titleActive = theme.getColor(TAB_ACTIVE_FOREGROUND);
|
||||
const titleActiveBorder = theme.getColor(PANEL_ACTIVE_TITLE_BORDER);
|
||||
if (titleActive || titleActiveBorder) {
|
||||
collector.addRule(`
|
||||
@@ -28,7 +28,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
||||
}
|
||||
|
||||
// Title Inactive
|
||||
const titleInactive = theme.getColor(PANEL_INACTIVE_TITLE_FOREGROUND);
|
||||
const titleInactive = theme.getColor(TAB_INACTIVE_FOREGROUND);
|
||||
if (titleInactive) {
|
||||
collector.addRule(`
|
||||
.tabbedPanel > .title > .tabList .tab .tabLabel {
|
||||
|
||||
@@ -20,7 +20,7 @@ import { CloseTabAction } from './tabActions';
|
||||
selector: 'tab-header',
|
||||
template: `
|
||||
<div #actionHeader class="tab-header" style="flex: 0 0; flex-direction: row;" [class.active]="tab.active" tabindex="0" (keyup)="onKey($event)">
|
||||
<span class="tab" (click)="selectTab(tab)">
|
||||
<span class="tab" (click)="selectTab(tab)" role="tab" [attr.aria-selected]="tab.active" [attr.aria-label]="tab.title">
|
||||
<a class="tabLabel" [class.active]="tab.active" #tabLabel>
|
||||
</a>
|
||||
</span>
|
||||
|
||||
@@ -26,7 +26,7 @@ export class RowDetailView {
|
||||
this._options = mixin(options, this._defaults, false);
|
||||
}
|
||||
|
||||
public init(grid: any) {
|
||||
public init(grid: any): void {
|
||||
this._grid = grid;
|
||||
this._dataView = this._grid.getData();
|
||||
|
||||
@@ -61,17 +61,17 @@ export class RowDetailView {
|
||||
this._options = $.extend(true, {}, this._options, options);
|
||||
}
|
||||
|
||||
public handleClick(e: any, args: any) {
|
||||
public handleClick(e: any, args: any): void {
|
||||
// clicking on a row select checkbox
|
||||
if (this._options.useRowClick || this._grid.getColumns()[args.cell].id === this._options.columnId && $(e.target).hasClass("detailView-toggle")) {
|
||||
if (this._options.useRowClick || this._grid.getColumns()[args.cell].id === this._options.columnId && $(e.target).hasClass('detailView-toggle')) {
|
||||
// if editing, try to commit
|
||||
if (this._grid.getEditorLock().isActive() && !this._grid.getEditorLock().commitCurrentEdit()) {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
return;
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
var item = this._dataView.getItem(args.row);
|
||||
let item = this._dataView.getItem(args.row);
|
||||
|
||||
// trigger an event before toggling
|
||||
this.onBeforeRowDetailToggle.notify({
|
||||
@@ -100,36 +100,35 @@ export class RowDetailView {
|
||||
// If we scroll save detail views that go out of cache range
|
||||
public handleScroll(e, args) {
|
||||
|
||||
var range = this._grid.getRenderedRange();
|
||||
let range = this._grid.getRenderedRange();
|
||||
|
||||
var start = (range.top > 0 ? range.top : 0);
|
||||
var end = (range.bottom > this._dataView.getLength() ? range.bottom : this._dataView.getLength());
|
||||
let start: number = (range.top > 0 ? range.top : 0);
|
||||
let end: number = (range.bottom > this._dataView.getLength() ? range.bottom : this._dataView.getLength());
|
||||
if (end <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the item at the top of the view
|
||||
var topMostItem = this._dataView.getItemByIdx(start);
|
||||
let topMostItem = this._dataView.getItemByIdx(start);
|
||||
|
||||
// Check it is a parent item
|
||||
if (topMostItem._parent === undefined)
|
||||
{
|
||||
if (topMostItem._parent === undefined) {
|
||||
// This is a standard row as we have no parent.
|
||||
var nextItem = this._dataView.getItemByIdx(start + 1);
|
||||
if(nextItem !== undefined && nextItem._parent !== undefined)
|
||||
{
|
||||
let nextItem = this._dataView.getItemByIdx(start + 1);
|
||||
if (nextItem !== undefined && nextItem._parent !== undefined) {
|
||||
// This is likely the expanded Detail Row View
|
||||
// Check for safety
|
||||
if(nextItem._parent === topMostItem)
|
||||
{
|
||||
if (nextItem._parent === topMostItem) {
|
||||
this.saveDetailView(topMostItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the bottom most item that is likely to go off screen
|
||||
var bottomMostItem = this._dataView.getItemByIdx(end - 1);
|
||||
let bottomMostItem = this._dataView.getItemByIdx(end - 1);
|
||||
|
||||
// If we are a detailView and we are about to go out of cache view
|
||||
if(bottomMostItem._parent !== undefined)
|
||||
{
|
||||
if (bottomMostItem._parent !== undefined) {
|
||||
this.saveDetailView(bottomMostItem._parent);
|
||||
}
|
||||
}
|
||||
@@ -143,17 +142,17 @@ export class RowDetailView {
|
||||
|
||||
// Collapse all of the open items
|
||||
public collapseAll() {
|
||||
for (var i = this._expandedRows.length - 1; i >= 0; i--) {
|
||||
for (let i = this._expandedRows.length - 1; i >= 0; i--) {
|
||||
this.collapseItem(this._expandedRows[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Saves the current state of the detail view
|
||||
public saveDetailView(item) {
|
||||
var view = $('#innerDetailView_' + item.id);
|
||||
let view = $('#innerDetailView_' + item.id);
|
||||
if (view) {
|
||||
var html = $('#innerDetailView_' + item.id).html();
|
||||
if(html !== undefined) {
|
||||
let html = $('#innerDetailView_' + item.id).html();
|
||||
if (html !== undefined) {
|
||||
item._detailContent = html;
|
||||
}
|
||||
}
|
||||
@@ -230,7 +229,7 @@ export class RowDetailView {
|
||||
|
||||
args.itemDetail._detailViewLoaded = true;
|
||||
|
||||
var idxParent = this._dataView.getIdxById(args.itemDetail.id);
|
||||
let idxParent = this._dataView.getIdxById(args.itemDetail.id);
|
||||
this._dataView.updateItem(args.itemDetail.id, args.itemDetail);
|
||||
|
||||
// trigger an event once the post template is finished loading
|
||||
@@ -254,7 +253,7 @@ export class RowDetailView {
|
||||
//////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////
|
||||
public getPaddingItem(parent, offset) {
|
||||
var item: any = {};
|
||||
let item: any = {};
|
||||
|
||||
for (let prop in this._grid.getData()) {
|
||||
item[prop] = null;
|
||||
@@ -284,7 +283,7 @@ export class RowDetailView {
|
||||
item._height = (item._sizePadding * this._grid.getOptions().rowHeight);
|
||||
|
||||
let idxParent = this._dataView.getIdxById(item.id);
|
||||
for (var idx = 1; idx <= item._sizePadding; idx++) {
|
||||
for (let idx = 1; idx <= item._sizePadding; idx++) {
|
||||
this._dataView.insertItem(idxParent + idx, this.getPaddingItem(item, idx));
|
||||
}
|
||||
}
|
||||
@@ -307,12 +306,12 @@ export class RowDetailView {
|
||||
public detailSelectionFormatter(row, cell, value, columnDef, dataContext) {
|
||||
|
||||
if (dataContext._collapsed === undefined) {
|
||||
dataContext._collapsed = true,
|
||||
dataContext._sizePadding = 0, //the required number of pading rows
|
||||
dataContext._height = 0, //the actual height in pixels of the detail field
|
||||
dataContext._isPadding = false,
|
||||
dataContext._parent = undefined,
|
||||
dataContext._offset = 0
|
||||
dataContext._collapsed = true;
|
||||
dataContext._sizePadding = 0; //the required number of pading rows
|
||||
dataContext._height = 0; //the actual height in pixels of the detail field
|
||||
dataContext._isPadding = false;
|
||||
dataContext._parent = undefined;
|
||||
dataContext._offset = 0;
|
||||
}
|
||||
|
||||
if (dataContext._isPadding === true) {
|
||||
@@ -320,9 +319,9 @@ export class RowDetailView {
|
||||
} else if (dataContext._collapsed) {
|
||||
return '<div class=\'detailView-toggle expand\'></div>';
|
||||
} else {
|
||||
var html = [];
|
||||
var rowHeight = this._grid.getOptions().rowHeight;
|
||||
var bottomMargin = 5;
|
||||
let html = [];
|
||||
let rowHeight = this._grid.getOptions().rowHeight;
|
||||
let bottomMargin = 5;
|
||||
|
||||
//V313HAX:
|
||||
//putting in an extra closing div after the closing toggle div and ommiting a
|
||||
@@ -339,7 +338,7 @@ export class RowDetailView {
|
||||
html.push("style='height:", dataContext._height, "px;"); //set total height of padding
|
||||
html.push("top:", rowHeight, "px'>"); //shift detail below 1st row
|
||||
html.push("<div id='detailViewContainer_", dataContext.id, "' class='detail-container' style='max-height:" + (dataContext._height - rowHeight + bottomMargin) + "px'>"); //sub ctr for custom styling
|
||||
html.push("<div id='innerDetailView_" , dataContext.id , "'>" , dataContext._detailContent, "</div></div>");
|
||||
html.push("<div id='innerDetailView_", dataContext.id, "'>", dataContext._detailContent, "</div></div>");
|
||||
//&omit a final closing detail container </div> that would come next
|
||||
|
||||
return html.join('');
|
||||
@@ -351,33 +350,32 @@ export class RowDetailView {
|
||||
if (!item) return;
|
||||
|
||||
// Grad each of the dom items
|
||||
var mainContainer = document.getElementById('detailViewContainer_' + item.id);
|
||||
var cellItem = document.getElementById('cellDetailView_' + item.id);
|
||||
var inner = document.getElementById('innerDetailView_' + item.id);
|
||||
let mainContainer = document.getElementById('detailViewContainer_' + item.id);
|
||||
let cellItem = document.getElementById('cellDetailView_' + item.id);
|
||||
let inner = document.getElementById('innerDetailView_' + item.id);
|
||||
|
||||
if (!mainContainer || !cellItem || !inner) return;
|
||||
|
||||
for (var idx = 1; idx <= item._sizePadding; idx++) {
|
||||
for (let idx = 1; idx <= item._sizePadding; idx++) {
|
||||
this._dataView.deleteItem(item.id + "." + idx);
|
||||
}
|
||||
|
||||
var rowHeight = this._grid.getOptions().rowHeight; // height of a row
|
||||
var lineHeight = 13; //we know cuz we wrote the custom css innit ;)
|
||||
let rowHeight = this._grid.getOptions().rowHeight; // height of a row
|
||||
let lineHeight = 13; //we know cuz we wrote the custom css innit ;)
|
||||
|
||||
// Get the inner Item height as this will be the actual size
|
||||
var itemHeight = inner.clientHeight;
|
||||
let itemHeight = inner.clientHeight;
|
||||
|
||||
// Now work out how many rows
|
||||
var rowCount = Math.ceil(itemHeight / rowHeight) + 1;
|
||||
let rowCount = Math.ceil(itemHeight / rowHeight) + 1;
|
||||
|
||||
item._sizePadding = Math.ceil(((rowCount * 2) * lineHeight) / rowHeight);
|
||||
item._height = (item._sizePadding * rowHeight);
|
||||
|
||||
// If the padding is now more than the original minRowBuff we need to increase it
|
||||
if (this._grid.getOptions().minRowBuffer < item._sizePadding)
|
||||
{
|
||||
if (this._grid.getOptions().minRowBuffer < item._sizePadding) {
|
||||
// Update the minRowBuffer so that the view doesn't disappear when it's at top of screen + the original default 3
|
||||
this._grid.getOptions().minRowBuffer =item._sizePadding + 3;
|
||||
this._grid.getOptions().minRowBuffer = item._sizePadding + 3;
|
||||
}
|
||||
|
||||
mainContainer.setAttribute("style", "max-height: " + item._height + "px");
|
||||
@@ -386,7 +384,7 @@ export class RowDetailView {
|
||||
}
|
||||
|
||||
let idxParent = this._dataView.getIdxById(item.id);
|
||||
for (var idx = 1; idx <= item._sizePadding; idx++) {
|
||||
for (let idx = 1; idx <= item._sizePadding; idx++) {
|
||||
this._dataView.insertItem(idxParent + idx, this.getPaddingItem(item, idx));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import { mixin } from 'vs/base/common/objects';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Dimension } from 'vs/base/browser/builder';
|
||||
import { Orientation } from 'vs/base/browser/ui/splitview/splitview';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
|
||||
export interface ITableStyles extends IListStyles {
|
||||
tableHeaderBackground?: Color;
|
||||
@@ -27,18 +28,22 @@ function getDefaultOptions<T>(): Slick.GridOptions<T> {
|
||||
};
|
||||
}
|
||||
|
||||
export class Table<T extends Slick.SlickData> implements IThemable {
|
||||
export class Table<T extends Slick.SlickData> extends Widget implements IThemable {
|
||||
private styleElement: HTMLStyleElement;
|
||||
private idPrefix: string;
|
||||
|
||||
private _grid: Slick.Grid<T>;
|
||||
private _columns: Slick.Column<T>[];
|
||||
private _data: TableDataView<T>;
|
||||
private _styleElement: HTMLStyleElement;
|
||||
private _idPrefix: string;
|
||||
private _autoscroll: boolean;
|
||||
private _onRowCountChangeListener: IDisposable;
|
||||
private _container: HTMLElement;
|
||||
private _tableContainer: HTMLElement;
|
||||
|
||||
private _classChangeTimeout: number;
|
||||
|
||||
constructor(parent: HTMLElement, data?: Array<T> | TableDataView<T>, columns?: Slick.Column<T>[], options?: Slick.GridOptions<T>) {
|
||||
super();
|
||||
if (data instanceof TableDataView) {
|
||||
this._data = data;
|
||||
} else {
|
||||
@@ -55,13 +60,28 @@ export class Table<T extends Slick.SlickData> implements IThemable {
|
||||
|
||||
this._container = document.createElement('div');
|
||||
this._container.className = 'monaco-table';
|
||||
this._register(DOM.addDisposableListener(this._container, DOM.EventType.FOCUS, () => {
|
||||
clearTimeout(this._classChangeTimeout);
|
||||
this._classChangeTimeout = setTimeout(() => {
|
||||
DOM.addClass(this._container, 'focused');
|
||||
}, 100);
|
||||
}, true));
|
||||
|
||||
this._register(DOM.addDisposableListener(this._container, DOM.EventType.BLUR, () => {
|
||||
clearTimeout(this._classChangeTimeout);
|
||||
this._classChangeTimeout = setTimeout(() => {
|
||||
DOM.removeClass(this._container, 'focused');
|
||||
}, 100);
|
||||
}, true));
|
||||
|
||||
parent.appendChild(this._container);
|
||||
this._styleElement = DOM.createStyleSheet(this._container);
|
||||
this.styleElement = DOM.createStyleSheet(this._container);
|
||||
this._tableContainer = document.createElement('div');
|
||||
this._container.appendChild(this._tableContainer);
|
||||
this._styleElement = DOM.createStyleSheet(this._container);
|
||||
this.styleElement = DOM.createStyleSheet(this._container);
|
||||
this._grid = new Slick.Grid<T>(this._tableContainer, this._data, this._columns, newOptions);
|
||||
this._idPrefix = this._tableContainer.classList[0];
|
||||
this.idPrefix = this._tableContainer.classList[0];
|
||||
DOM.addClass(this._container, this.idPrefix);
|
||||
this._onRowCountChangeListener = this._data.onRowCountChange(() => this._handleRowCountChange());
|
||||
this._grid.onSort.subscribe((e, args) => {
|
||||
this._data.sort(args);
|
||||
@@ -200,78 +220,77 @@ export class Table<T extends Slick.SlickData> implements IThemable {
|
||||
const content: string[] = [];
|
||||
|
||||
if (styles.tableHeaderBackground) {
|
||||
content.push(`.monaco-table .${this._idPrefix} .slick-header .slick-header-column { background-color: ${styles.tableHeaderBackground}; }`);
|
||||
content.push(`.monaco-table .${this.idPrefix} .slick-header .slick-header-column { background-color: ${styles.tableHeaderBackground}; }`);
|
||||
}
|
||||
|
||||
if (styles.tableHeaderForeground) {
|
||||
content.push(`.monaco-table .${this._idPrefix} .slick-header .slick-header-column { color: ${styles.tableHeaderForeground}; }`);
|
||||
content.push(`.monaco-table .${this.idPrefix} .slick-header .slick-header-column { color: ${styles.tableHeaderForeground}; }`);
|
||||
}
|
||||
|
||||
if (styles.listFocusBackground) {
|
||||
content.push(`.monaco-table .${this._idPrefix} .slick-row .active { background-color: ${styles.listFocusBackground}; }`);
|
||||
content.push(`.monaco-table.${this.idPrefix}.focused .slick-row .active { background-color: ${styles.listFocusBackground}; }`);
|
||||
content.push(`.monaco-table.${this.idPrefix}.focused .slick-row .active:hover { background-color: ${styles.listFocusBackground}; }`); // overwrite :hover style in this case!
|
||||
}
|
||||
|
||||
if (styles.listFocusForeground) {
|
||||
content.push(`.monaco-table .${this._idPrefix} .slick-row .active { color: ${styles.listFocusForeground}; }`);
|
||||
content.push(`.monaco-table.${this.idPrefix}.focused .slick-row .active { color: ${styles.listFocusForeground}; }`);
|
||||
}
|
||||
|
||||
if (styles.listActiveSelectionBackground) {
|
||||
content.push(`.monaco-table .${this._idPrefix} .slick-row .selected { background-color: ${styles.listActiveSelectionBackground}; }`);
|
||||
content.push(`.monaco-table .${this._idPrefix} .slick-row .selected:hover { background-color: ${styles.listActiveSelectionBackground}; }`); // overwrite :hover style in this case!
|
||||
content.push(`.monaco-table.${this.idPrefix}.focused .slick-row .selected { background-color: ${styles.listActiveSelectionBackground}; }`);
|
||||
content.push(`.monaco-table.${this.idPrefix}.focused .slick-row .selected:hover { background-color: ${styles.listActiveSelectionBackground}; }`); // overwrite :hover style in this case!
|
||||
}
|
||||
|
||||
if (styles.listActiveSelectionForeground) {
|
||||
content.push(`.monaco-table .${this._idPrefix} .slick-row .selected { color: ${styles.listActiveSelectionForeground}; }`);
|
||||
content.push(`.monaco-table.${this.idPrefix}.focused .slick-row .selected { color: ${styles.listActiveSelectionForeground}; }`);
|
||||
}
|
||||
|
||||
if (styles.listFocusAndSelectionBackground) {
|
||||
content.push(`.monaco-table .${this._idPrefix} .slick-row .selected.active { background-color: ${styles.listFocusAndSelectionBackground}; }`);
|
||||
content.push(`.monaco-table.${this.idPrefix}.focused .slick-row .selected.active { background-color: ${styles.listFocusAndSelectionBackground}; }`);
|
||||
}
|
||||
|
||||
if (styles.listFocusAndSelectionForeground) {
|
||||
content.push(`.monaco-table .${this._idPrefix} .slick-row .selected.active { color: ${styles.listFocusAndSelectionForeground}; }`);
|
||||
content.push(`.monaco-table.${this.idPrefix}.focused .slick-row .selected.active { color: ${styles.listFocusAndSelectionForeground}; }`);
|
||||
}
|
||||
|
||||
/* Commented out andresse 8/17/2017; keeping for reference as we iterate on the table styling */
|
||||
// if (styles.listInactiveFocusBackground) {
|
||||
// content.push(`.monaco-table .${this._idPrefix} .slick-row.focused { background-color: ${styles.listInactiveFocusBackground}; }`);
|
||||
// content.push(`.monaco-table .${this._idPrefix} .slick-row.focused:hover { background-color: ${styles.listInactiveFocusBackground}; }`); // overwrite :hover style in this case!
|
||||
// }
|
||||
if (styles.listInactiveFocusBackground) {
|
||||
content.push(`.monaco-table.${this.idPrefix} .slick-row .selected.active { background-color: ${styles.listInactiveFocusBackground}; }`);
|
||||
content.push(`.monaco-table.${this.idPrefix} .slick-row .selected.active:hover { background-color: ${styles.listInactiveFocusBackground}; }`); // overwrite :hover style in this case!
|
||||
}
|
||||
|
||||
// if (styles.listInactiveSelectionBackground) {
|
||||
// content.push(`.monaco-table .${this._idPrefix} .slick-row .selected { background-color: ${styles.listInactiveSelectionBackground}; }`);
|
||||
// content.push(`.monaco-table .${this._idPrefix} .slick-row .selected:hover { background-color: ${styles.listInactiveSelectionBackground}; }`); // overwrite :hover style in this case!
|
||||
// }
|
||||
if (styles.listInactiveSelectionBackground) {
|
||||
content.push(`.monaco-table.${this.idPrefix} .slick-row .selected { background-color: ${styles.listInactiveSelectionBackground}; }`);
|
||||
content.push(`.monaco-table.${this.idPrefix} .slick-row .selected:hover { background-color: ${styles.listInactiveSelectionBackground}; }`); // overwrite :hover style in this case!
|
||||
}
|
||||
|
||||
// if (styles.listInactiveSelectionForeground) {
|
||||
// content.push(`.monaco-table .${this._idPrefix} .slick-row .selected { color: ${styles.listInactiveSelectionForeground}; }`);
|
||||
// }
|
||||
if (styles.listInactiveSelectionForeground) {
|
||||
content.push(`.monaco-table.${this.idPrefix} .slick-row .selected { color: ${styles.listInactiveSelectionForeground}; }`);
|
||||
}
|
||||
|
||||
if (styles.listHoverBackground) {
|
||||
content.push(`.monaco-table .${this._idPrefix} .slick-row:hover { background-color: ${styles.listHoverBackground}; }`);
|
||||
content.push(`.monaco-table.${this.idPrefix} .slick-row:hover { background-color: ${styles.listHoverBackground}; }`);
|
||||
}
|
||||
|
||||
if (styles.listHoverForeground) {
|
||||
content.push(`.monaco-table .${this._idPrefix} .slick-row:hover { color: ${styles.listHoverForeground}; }`);
|
||||
content.push(`.monaco-table.${this.idPrefix} .slick-row:hover { color: ${styles.listHoverForeground}; }`);
|
||||
}
|
||||
|
||||
if (styles.listSelectionOutline) {
|
||||
content.push(`.monaco-table .${this._idPrefix} .slick-row .selected { outline: 1px dotted ${styles.listSelectionOutline}; outline-offset: -1px; }`);
|
||||
content.push(`.monaco-table.${this.idPrefix} .slick-row .selected.active { outline: 1px dotted ${styles.listSelectionOutline}; outline-offset: -1px; }`);
|
||||
}
|
||||
|
||||
/* Commented out andresse 8/17/2017; keeping for reference as we iterate on the table styling */
|
||||
// if (styles.listFocusOutline) {
|
||||
// content.push(`.monaco-table .${this._idPrefix}:focus .slick-row.focused { outline: 1px solid ${styles.listFocusOutline}; outline-offset: -1px; }`);
|
||||
// }
|
||||
if (styles.listFocusOutline) {
|
||||
content.push(`.monaco-table.${this.idPrefix}.focused .slick-row .selected { outline: 1px solid ${styles.listFocusOutline}; outline-offset: -1px; }`);
|
||||
}
|
||||
|
||||
// if (styles.listInactiveFocusOutline) {
|
||||
// content.push(`.monaco-table .${this._idPrefix} .slick-row.focused { outline: 1px dotted ${styles.listInactiveFocusOutline}; outline-offset: -1px; }`);
|
||||
// }
|
||||
if (styles.listInactiveFocusOutline) {
|
||||
content.push(`.monaco-table.${this.idPrefix} .slick-row .selected .active { outline: 1px dotted ${styles.listInactiveFocusOutline}; outline-offset: -1px; }`);
|
||||
}
|
||||
|
||||
if (styles.listHoverOutline) {
|
||||
content.push(`.monaco-table .${this._idPrefix} .slick-row:hover { outline: 1px dashed ${styles.listHoverOutline}; outline-offset: -1px; }`);
|
||||
content.push(`.monaco-table.${this.idPrefix} .slick-row:hover { outline: 1px dashed ${styles.listHoverOutline}; outline-offset: -1px; }`);
|
||||
}
|
||||
|
||||
this._styleElement.innerHTML = content.join('\n');
|
||||
this.styleElement.innerHTML = content.join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,12 +153,18 @@ export class ActionBar extends ActionRunner implements IActionRunner {
|
||||
}
|
||||
|
||||
private updateFocusedItem(): void {
|
||||
let actionIndex = 0;
|
||||
for (let i = 0; i < this._actionsList.children.length; i++) {
|
||||
let elem = this._actionsList.children[i];
|
||||
|
||||
if (DOM.isAncestor(document.activeElement, elem)) {
|
||||
this._focusedItem = i;
|
||||
this._focusedItem = actionIndex;
|
||||
break;
|
||||
}
|
||||
|
||||
if (elem.classList.contains('action-item')) {
|
||||
actionIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,10 @@ import { registerColor, foreground } from 'vs/platform/theme/common/colorRegistr
|
||||
import { Color, RGBA } from 'vs/base/common/color';
|
||||
import * as nls from 'vs/nls';
|
||||
|
||||
export const tableHeaderBackground = registerColor('table.headerBackground', { dark: new Color(new RGBA(51, 51, 52)), light: new Color(new RGBA(245, 245, 245)), hc: null }, nls.localize('tableHeaderBackground', 'Table header background color'));
|
||||
export const tableHeaderForeground = registerColor('table.headerForeground', { dark: new Color(new RGBA(229, 229, 229)), light: new Color(new RGBA(16, 16, 16)), hc: null }, nls.localize('tableHeaderForeground', 'Table header foreground color'));
|
||||
export const tableHeaderBackground = registerColor('table.headerBackground', { dark: new Color(new RGBA(51, 51, 52)), light: new Color(new RGBA(245, 245, 245)), hc: '#333334' }, nls.localize('tableHeaderBackground', 'Table header background color'));
|
||||
export const tableHeaderForeground = registerColor('table.headerForeground', { dark: new Color(new RGBA(229, 229, 229)), light: new Color(new RGBA(16, 16, 16)), hc: '#e5e5e5' }, nls.localize('tableHeaderForeground', 'Table header foreground color'));
|
||||
export const disabledInputBackground = registerColor('input.disabled.background', { dark: '#444444', light: '#dcdcdc', hc: Color.black }, nls.localize('disabledInputBoxBackground', "Disabled Input box background."));
|
||||
export const disabledInputForeground = registerColor('input.disabled.foreground', { dark: '#888888', light: '#888888', hc: foreground }, nls.localize('disabledInputBoxForeground', "Disabled Input box foreground."));
|
||||
export const buttonFocusOutline = registerColor('button.focusOutline', { dark: '#eaeaea', light: '#666666', hc: null }, nls.localize('buttonFocusOutline', "Button outline color when focused."));
|
||||
export const buttonFocusOutline = registerColor('button.focusOutline', { dark: '#eaeaea', light: '#666666', hc: null }, nls.localize('buttonFocusOutline', "Button outline color when focused."));
|
||||
|
||||
export const listFocusAndSelectionBackground = registerColor('list.focusAndSelectionBackground', { dark: '#2c3295', light: '#2c3295', hc: null }, nls.localize('listFocusAndSelectionBackground', "List/Table background color for the selected and focus item when the list/table is active"));
|
||||
@@ -146,9 +146,9 @@ export function attachTableStyler(widget: IThemable, themeService: IThemeService
|
||||
return attachStyler(themeService, {
|
||||
listFocusBackground: (style && style.listFocusBackground) || cr.listFocusBackground,
|
||||
listFocusForeground: (style && style.listFocusForeground) || cr.listFocusForeground,
|
||||
listActiveSelectionBackground: (style && style.listActiveSelectionBackground) || cr.lighten(cr.listActiveSelectionBackground, 0.1),
|
||||
listActiveSelectionBackground: (style && style.listActiveSelectionBackground) || cr.listActiveSelectionBackground,
|
||||
listActiveSelectionForeground: (style && style.listActiveSelectionForeground) || cr.listActiveSelectionForeground,
|
||||
listFocusAndSelectionBackground: style && style.listFocusAndSelectionBackground || cr.listActiveSelectionBackground,
|
||||
listFocusAndSelectionBackground: style && style.listFocusAndSelectionBackground || sqlcolors.listFocusAndSelectionBackground,
|
||||
listFocusAndSelectionForeground: (style && style.listFocusAndSelectionForeground) || cr.listActiveSelectionForeground,
|
||||
listInactiveFocusBackground: (style && style.listInactiveFocusBackground),
|
||||
listInactiveSelectionBackground: (style && style.listInactiveSelectionBackground) || cr.listInactiveSelectionBackground,
|
||||
|
||||
@@ -104,7 +104,9 @@ export class AutoOAuthDialog extends Modal {
|
||||
});
|
||||
|
||||
inputContainer.div({ class: 'dialog-input' }, (inputCellContainer) => {
|
||||
inputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService);
|
||||
inputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService, {
|
||||
ariaLabel: label
|
||||
});
|
||||
});
|
||||
});
|
||||
return inputBox;
|
||||
|
||||
@@ -34,6 +34,11 @@ import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||
// in case that other non-Azure sign in is to be used
|
||||
const firewallHelpUri = 'https://aka.ms/sqlopsfirewallhelp';
|
||||
|
||||
const LocalizedStrings = {
|
||||
FROM: localize('from', 'From'),
|
||||
TO: localize('to', 'To')
|
||||
};
|
||||
|
||||
export class FirewallRuleDialog extends Modal {
|
||||
public viewModel: FirewallRuleViewModel;
|
||||
private _createButton: Button;
|
||||
@@ -140,19 +145,23 @@ export class FirewallRuleDialog extends Modal {
|
||||
subnetIPRangeSection = subnetIPRangeContainer.getHTMLElement();
|
||||
subnetIPRangeContainer.div({ 'class': 'dialog-input-section' }, (inputContainer) => {
|
||||
inputContainer.div({ 'class': 'dialog-label' }, (labelContainer) => {
|
||||
labelContainer.innerHtml(localize('from', 'From'));
|
||||
labelContainer.innerHtml(LocalizedStrings.FROM);
|
||||
});
|
||||
|
||||
inputContainer.div({ 'class': 'dialog-input' }, (inputCellContainer) => {
|
||||
this._fromRangeinputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService);
|
||||
this._fromRangeinputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService, {
|
||||
ariaLabel: LocalizedStrings.FROM
|
||||
});
|
||||
});
|
||||
|
||||
inputContainer.div({ 'class': 'dialog-label' }, (labelContainer) => {
|
||||
labelContainer.innerHtml(localize('to', 'To'));
|
||||
labelContainer.innerHtml(LocalizedStrings.TO);
|
||||
});
|
||||
|
||||
inputContainer.div({ 'class': 'dialog-input' }, (inputCellContainer) => {
|
||||
this._toRangeinputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService);
|
||||
this._toRangeinputBox = new InputBox(inputCellContainer.getHTMLElement(), this._contextViewService, {
|
||||
ariaLabel: LocalizedStrings.TO
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { DashboardEditor } from 'sql/parts/dashboard/dashboardEditor';
|
||||
import { DashboardInput } from 'sql/parts/dashboard/dashboardInput';
|
||||
import { AddServerGroupAction, AddServerAction } from 'sql/parts/registeredServer/viewlet/connectionTreeAction';
|
||||
import { AddServerGroupAction, AddServerAction } from 'sql/parts/objectExplorer/viewlet/connectionTreeAction';
|
||||
import { ClearRecentConnectionsAction } from 'sql/parts/connection/common/connectionActions';
|
||||
|
||||
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
|
||||
|
||||
@@ -12,58 +12,94 @@ import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
|
||||
import { INotificationService, INotificationActions } from 'vs/platform/notification/common/notification';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { IConfirmationService, IChoiceService, IConfirmation, IConfirmationResult, Choice } from 'vs/platform/dialogs/common/dialogs';
|
||||
|
||||
/**
|
||||
* Workbench action to clear the recent connnections list
|
||||
*/
|
||||
export class ClearRecentConnectionsAction extends Action {
|
||||
|
||||
public static ID = 'clearRecentConnectionsAction';
|
||||
public static LABEL = nls.localize('ClearRecentlyUsedLabel', 'Clear Recent Connections List');
|
||||
public static ID = 'clearRecentConnectionsAction';
|
||||
public static LABEL = nls.localize('ClearRecentlyUsedLabel', 'Clear Recent Connections List');
|
||||
public static ICON = 'search-action clear-search-results';
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||
@INotificationService private _notificationService: INotificationService,
|
||||
@IQuickOpenService private _quickOpenService: IQuickOpenService
|
||||
) {
|
||||
super(id, label);
|
||||
this.enabled = true;
|
||||
}
|
||||
private _onRecentConnectionsRemoved = new Emitter<void>();
|
||||
public onRecentConnectionsRemoved: Event<void> = this._onRecentConnectionsRemoved.event;
|
||||
|
||||
public run(): TPromise<void> {
|
||||
let self = this;
|
||||
return self.promptToClearRecentConnectionsList().then(result => {
|
||||
private _useConfirmationMessage = false;
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||
@INotificationService private _notificationService: INotificationService,
|
||||
@IQuickOpenService private _quickOpenService: IQuickOpenService,
|
||||
@IConfirmationService private _confirmationService: IConfirmationService,
|
||||
) {
|
||||
super(id, label, ClearRecentConnectionsAction.ICON);
|
||||
this.enabled = true;
|
||||
}
|
||||
|
||||
public set useConfirmationMessage(value: boolean) {
|
||||
this._useConfirmationMessage = value;
|
||||
}
|
||||
|
||||
public run(): TPromise<void> {
|
||||
if (this._useConfirmationMessage) {
|
||||
return this.promptConfirmationMessage().then(result => {
|
||||
if (result) {
|
||||
self._connectionManagementService.clearRecentConnectionsList();
|
||||
this._connectionManagementService.clearRecentConnectionsList();
|
||||
this._onRecentConnectionsRemoved.fire();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return this.promptQuickOpenService().then(result => {
|
||||
if (result) {
|
||||
this._connectionManagementService.clearRecentConnectionsList();
|
||||
|
||||
const actions: INotificationActions = { primary: [ ] };
|
||||
self._notificationService.notify({
|
||||
const actions: INotificationActions = { primary: [] };
|
||||
this._notificationService.notify({
|
||||
severity: Severity.Info,
|
||||
message: nls.localize('ClearedRecentConnections', 'Recent connections list cleared'),
|
||||
actions
|
||||
});
|
||||
this._onRecentConnectionsRemoved.fire();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private promptToClearRecentConnectionsList(): TPromise<boolean> {
|
||||
const self = this;
|
||||
return new TPromise<boolean>((resolve, reject) => {
|
||||
let choices: { key, value }[] = [
|
||||
{ key: nls.localize('connectionAction.yes', 'Yes'), value: true },
|
||||
{ key: nls.localize('connectionAction.no', 'No'), value: false }
|
||||
];
|
||||
|
||||
self._quickOpenService.pick(choices.map(x => x.key), { placeHolder: nls.localize('ClearRecentlyUsedLabel', 'Clear Recent Connections List'), ignoreFocusLost: true }).then((choice) => {
|
||||
let confirm = choices.find(x => x.key === choice);
|
||||
resolve(confirm && confirm.value);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private promptQuickOpenService(): TPromise<boolean> {
|
||||
const self = this;
|
||||
return new TPromise<boolean>((resolve, reject) => {
|
||||
let choices: { key, value }[] = [
|
||||
{ key: nls.localize('connectionAction.yes', 'Yes'), value: true },
|
||||
{ key: nls.localize('connectionAction.no', 'No'), value: false }
|
||||
];
|
||||
|
||||
self._quickOpenService.pick(choices.map(x => x.key), { placeHolder: nls.localize('ClearRecentlyUsedLabel', 'Clear Recent Connections List'), ignoreFocusLost: true }).then((choice) => {
|
||||
let confirm = choices.find(x => x.key === choice);
|
||||
resolve(confirm && confirm.value);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private promptConfirmationMessage(): TPromise<boolean> {
|
||||
let confirm: IConfirmation = {
|
||||
message: nls.localize('clearRecentConnectionMessage', 'Are you sure you want to delete all the connections from the list?'),
|
||||
primaryButton: nls.localize('connectionDialog.yes', 'Yes'),
|
||||
secondaryButton: nls.localize('connectionDialog.no', 'No'),
|
||||
type: 'question'
|
||||
};
|
||||
|
||||
return new TPromise<boolean>((resolve, reject) => {
|
||||
this._confirmationService.confirm(confirm).then((confirmed) => {
|
||||
resolve(confirmed);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to delete one recently used connection from the MRU
|
||||
*/
|
||||
|
||||
@@ -10,7 +10,7 @@ import { IEditorGroupService } from 'vs/workbench/services/group/common/groupSer
|
||||
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
|
||||
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
import { IObjectExplorerService } from 'sql/parts/registeredServer/common/objectExplorerService';
|
||||
import { IObjectExplorerService } from 'sql/parts/objectExplorer/common/objectExplorerService';
|
||||
import * as TaskUtilities from 'sql/workbench/common/taskUtilities';
|
||||
|
||||
// Connection status bar showing the current global connection
|
||||
|
||||
@@ -346,7 +346,10 @@ export class ConnectionDialogService implements IConnectionDialogService {
|
||||
this._connectionDialog.close();
|
||||
this._clipboardService.writeText('kinit\r');
|
||||
this._commandService.executeCommand('workbench.action.terminal.focus').then(resolve => {
|
||||
return this._commandService.executeCommand('workbench.action.terminal.paste');
|
||||
// setTimeout to allow for terminal Instance to load.
|
||||
setTimeout(() => {
|
||||
return this._commandService.executeCommand('workbench.action.terminal.paste');
|
||||
}, 10);
|
||||
}).then(resolve => null, reject => null);
|
||||
return null;
|
||||
}));
|
||||
|
||||
@@ -11,13 +11,14 @@ import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
import { Modal } from 'sql/base/browser/ui/modal/modal';
|
||||
import { IConnectionManagementService, INewConnectionParams } from 'sql/parts/connection/common/connectionManagement';
|
||||
import * as DialogHelper from 'sql/base/browser/ui/modal/dialogHelper';
|
||||
import { TreeCreationUtils } from 'sql/parts/registeredServer/viewlet/treeCreationUtils';
|
||||
import { TreeUpdateUtils } from 'sql/parts/registeredServer/viewlet/treeUpdateUtils';
|
||||
import { TreeCreationUtils } from 'sql/parts/objectExplorer/viewlet/treeCreationUtils';
|
||||
import { TreeUpdateUtils } from 'sql/parts/objectExplorer/viewlet/treeUpdateUtils';
|
||||
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
|
||||
import { TabbedPanel, PanelTabIdentifier } from 'sql/base/browser/ui/panel/panel';
|
||||
import { RecentConnectionTreeController, RecentConnectionActionsProvider } from 'sql/parts/connection/connectionDialog/recentConnectionTreeController';
|
||||
import { SavedConnectionTreeController } from 'sql/parts/connection/connectionDialog/savedConnectionTreeController';
|
||||
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||
import { ClearRecentConnectionsAction } from 'sql/parts/connection/common/connectionActions';
|
||||
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
@@ -32,11 +33,11 @@ import { localize } from 'vs/nls';
|
||||
import { ITree } from 'vs/base/parts/tree/browser/tree';
|
||||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConfirmationService, IChoiceService, IConfirmation, IConfirmationResult, Choice } from 'vs/platform/dialogs/common/dialogs';
|
||||
import * as styler from 'vs/platform/theme/common/styler';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { DialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogs';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
|
||||
export interface OnShowUIResponse {
|
||||
selectedProviderType: string;
|
||||
@@ -58,6 +59,7 @@ export class ConnectionDialogWidget extends Modal {
|
||||
private _savedConnectionTree: ITree;
|
||||
private $connectionUIContainer: Builder;
|
||||
private _databaseDropdownExpanded: boolean;
|
||||
private _actionbar: ActionBar;
|
||||
|
||||
private _panel: TabbedPanel;
|
||||
private _recentConnectionTabId: PanelTabIdentifier;
|
||||
@@ -90,7 +92,6 @@ export class ConnectionDialogWidget extends Modal {
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IContextMenuService private _contextMenuService: IContextMenuService,
|
||||
@IConfirmationService private _confirmationService: IConfirmationService,
|
||||
@IContextViewService private _contextViewService: IContextViewService
|
||||
) {
|
||||
super(localize('connection', 'Connection'), TelemetryKeys.Connection, _partService, telemetryService, contextKeyService, { hasSpinner: true, hasErrors: true });
|
||||
@@ -257,26 +258,6 @@ export class ConnectionDialogWidget extends Modal {
|
||||
this.hide();
|
||||
}
|
||||
|
||||
private clearRecentConnectionList(): TPromise<boolean> {
|
||||
|
||||
let confirm: IConfirmation = {
|
||||
message: localize('clearRecentConnectionMessage', 'Are you sure you want to delete all the connections from the list?'),
|
||||
primaryButton: localize('connectionDialog.yes', 'Yes'),
|
||||
secondaryButton: localize('connectionDialog.no', 'No'),
|
||||
type: 'question'
|
||||
};
|
||||
|
||||
return new TPromise<boolean>((resolve, reject) => {
|
||||
this._confirmationService.confirm(confirm).then((confirmed) => {
|
||||
if (confirmed) {
|
||||
this._connectionManagementService.clearRecentConnectionsList();
|
||||
this.open(false);
|
||||
}
|
||||
resolve(confirmed);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private createRecentConnectionList(): void {
|
||||
this._recentConnectionBuilder.div({ class: 'connection-recent-content' }, (recentConnectionContainer) => {
|
||||
let recentHistoryLabel = localize('recentHistory', 'Recent history');
|
||||
@@ -284,8 +265,12 @@ export class ConnectionDialogWidget extends Modal {
|
||||
container.div({ class: 'connection-history-label' }, (recentTitle) => {
|
||||
recentTitle.innerHtml(recentHistoryLabel);
|
||||
});
|
||||
container.div({ class: 'search-action clear-search-results' }, (clearSearchIcon) => {
|
||||
clearSearchIcon.on('click', () => this.clearRecentConnectionList());
|
||||
container.div({ class: 'connection-history-actions' }, (actionsContainer) => {
|
||||
this._actionbar = this._register(new ActionBar(actionsContainer, { animated: false }));
|
||||
let clearAction = this._instantiationService.createInstance(ClearRecentConnectionsAction, ClearRecentConnectionsAction.ID, ClearRecentConnectionsAction.LABEL);
|
||||
clearAction.useConfirmationMessage = true;
|
||||
clearAction.onRecentConnectionsRemoved(() => this.open(false));
|
||||
this._actionbar.push(clearAction, { icon: true, label: false });
|
||||
});
|
||||
});
|
||||
recentConnectionContainer.div({ class: 'server-explorer-viewlet' }, (divContainer: Builder) => {
|
||||
|
||||
@@ -128,6 +128,7 @@ export class ConnectionWidget {
|
||||
validationOptions: {
|
||||
validation: (value: string) => !value ? ({ type: MessageType.ERROR, content: serverNameOption.displayName + errorMessage }) : null
|
||||
},
|
||||
ariaLabel: serverNameOption.displayName
|
||||
});
|
||||
|
||||
if (this._optionsMaps[ConnectionOptionSpecialType.authType]) {
|
||||
@@ -141,12 +142,13 @@ export class ConnectionWidget {
|
||||
this._userNameInputBox = new InputBox(userNameBuilder.getHTMLElement(), this._contextViewService, {
|
||||
validationOptions: {
|
||||
validation: (value: string) => self.validateUsername(value, userNameOption.isRequired) ? ({ type: MessageType.ERROR, content: userNameOption.displayName + errorMessage }) : null
|
||||
}
|
||||
},
|
||||
ariaLabel: userNameOption.displayName
|
||||
});
|
||||
|
||||
let passwordOption = this._optionsMaps[ConnectionOptionSpecialType.password];
|
||||
let passwordBuilder = DialogHelper.appendRow(this._tableContainer, passwordOption.displayName, 'connection-label', 'connection-input');
|
||||
this._passwordInputBox = new InputBox(passwordBuilder.getHTMLElement(), this._contextViewService);
|
||||
this._passwordInputBox = new InputBox(passwordBuilder.getHTMLElement(), this._contextViewService, { ariaLabel: passwordOption.displayName });
|
||||
this._passwordInputBox.inputElement.type = 'password';
|
||||
this._password = '';
|
||||
|
||||
@@ -158,9 +160,10 @@ export class ConnectionWidget {
|
||||
|
||||
this._databaseNameInputBox = new Dropdown(databaseNameBuilder.getHTMLElement(), this._contextViewService, this._themeService, {
|
||||
values: [this._defaultDatabaseName, this._loadingDatabaseName],
|
||||
strictSelection : false,
|
||||
strictSelection: false,
|
||||
placeholder: this._defaultDatabaseName,
|
||||
maxHeight: 125
|
||||
maxHeight: 125,
|
||||
ariaLabel: databaseOption.displayName
|
||||
});
|
||||
|
||||
let serverGroupLabel = localize('serverGroup', 'Server group');
|
||||
@@ -204,7 +207,7 @@ export class ConnectionWidget {
|
||||
container.element('tr', {}, (rowContainer) => {
|
||||
rowContainer.element('td');
|
||||
rowContainer.element('td', { class: cellContainerClass }, (inputCellContainer) => {
|
||||
checkbox = new Checkbox(inputCellContainer.getHTMLElement(), { label, checked: isChecked });
|
||||
checkbox = new Checkbox(inputCellContainer.getHTMLElement(), { label, checked: isChecked, ariaLabel: label });
|
||||
});
|
||||
});
|
||||
return checkbox;
|
||||
@@ -343,6 +346,12 @@ export class ConnectionWidget {
|
||||
public focusOnOpen(): void {
|
||||
this._serverNameInputBox.focus();
|
||||
this.focusPasswordIfNeeded();
|
||||
this.clearValidationMessages();
|
||||
}
|
||||
|
||||
private clearValidationMessages(): void {
|
||||
this._serverNameInputBox.hideMessage();
|
||||
this._userNameInputBox.hideMessage();
|
||||
}
|
||||
|
||||
private getModelValue(value: string): string {
|
||||
|
||||
@@ -69,15 +69,21 @@
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.connection-dialog .connection-history-actions .action-label.icon {
|
||||
display: block;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
min-width: 20px;
|
||||
background-size: 16px;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.search-action.clear-search-results {
|
||||
background: url('clear-search-results.svg') center right no-repeat;
|
||||
width: 10%;
|
||||
cursor: pointer;
|
||||
background: url('clear-search-results.svg');
|
||||
}
|
||||
|
||||
.vs-dark .search-action.clear-search-results,
|
||||
.hc-black .search-action.clear-search-results {
|
||||
background: url('clear-search-results-dark.svg') center right no-repeat;
|
||||
width: 10%;
|
||||
cursor: pointer;
|
||||
background: url('clear-search-results-dark.svg');
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import Event from 'vs/base/common/event';
|
||||
|
||||
import { IAngularEventingService, AngularEventType, IAngularEvent } from 'sql/services/angularEventing/angularEventingService';
|
||||
import { INewDashboardTabDialogService } from 'sql/parts/dashboard/newDashboardTabDialog/interface';
|
||||
@@ -225,8 +226,19 @@ export class CollapseWidgetAction extends Action {
|
||||
}
|
||||
|
||||
private _toggleState(): void {
|
||||
this.collpasedState = !this.collpasedState;
|
||||
this._updateState(!this.collpasedState);
|
||||
}
|
||||
|
||||
private _updateState(collapsed: boolean): void {
|
||||
if (collapsed === this.collpasedState) {
|
||||
return;
|
||||
}
|
||||
this.collpasedState = collapsed;
|
||||
this._setClass(this.collpasedState ? CollapseWidgetAction.EXPAND_ICON : CollapseWidgetAction.COLLAPSE_ICON);
|
||||
this._setLabel(this.collpasedState ? CollapseWidgetAction.EXPAND_LABEL : CollapseWidgetAction.COLLPASE_LABEL);
|
||||
}
|
||||
|
||||
public set state(collapsed: boolean) {
|
||||
this._updateState(collapsed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboar
|
||||
import { WIDGETS_CONTAINER } from 'sql/parts/dashboard/containers/dashboardWidgetContainer.contribution';
|
||||
import { GRID_CONTAINER } from 'sql/parts/dashboard/containers/dashboardGridContainer.contribution';
|
||||
import { WEBVIEW_CONTAINER } from 'sql/parts/dashboard/containers/dashboardWebviewContainer.contribution';
|
||||
import { MODELVIEW_CONTAINER } from 'sql/parts/dashboard/containers/dashboardModelViewContainer.contribution';
|
||||
import { CONTROLHOST_CONTAINER } from 'sql/parts/dashboard/containers/dashboardControlHostContainer.contribution';
|
||||
import { NAV_SECTION } from 'sql/parts/dashboard/containers/dashboardNavSection.contribution';
|
||||
import { IDashboardContainerRegistry, Extensions as DashboardContainerExtensions, IDashboardContainer, registerContainerType } from 'sql/platform/dashboard/common/dashboardContainerRegistry';
|
||||
@@ -25,6 +26,7 @@ const containerTypes = [
|
||||
WIDGETS_CONTAINER,
|
||||
GRID_CONTAINER,
|
||||
WEBVIEW_CONTAINER,
|
||||
MODELVIEW_CONTAINER,
|
||||
CONTROLHOST_CONTAINER,
|
||||
NAV_SECTION
|
||||
];
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
</dashboard-webview-container>
|
||||
<dashboard-widget-container *ngIf="getContentType(tab) === 'widgets-container'" [tab]="tab">
|
||||
</dashboard-widget-container>
|
||||
<dashboard-modelview-container *ngIf="getContentType(tab) === 'modelview-container'" [tab]="tab">
|
||||
</dashboard-modelview-container>
|
||||
<dashboard-controlhost-container *ngIf="getContentType(tab) === 'controlhost-container'" [tab]="tab">
|
||||
</dashboard-controlhost-container>
|
||||
<dashboard-nav-section *ngIf="getContentType(tab) === 'nav-section'" [tab]="tab">
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'sql/parts/dashboard/common/dashboardPanelStyles';
|
||||
import { Component, Inject, forwardRef, ViewChild, ElementRef, ViewChildren, QueryList, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
||||
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { WidgetConfig, TabConfig, TabSettingConfig } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
import { Extensions, IInsightRegistry } from 'sql/platform/dashboard/common/insightRegistry';
|
||||
import { DashboardWidgetWrapper } from 'sql/parts/dashboard/contents/dashboardWidgetWrapper.component';
|
||||
@@ -85,13 +86,15 @@ export abstract class DashboardPage extends AngularDisposable {
|
||||
|
||||
protected abstract propertiesWidget: WidgetConfig;
|
||||
protected abstract get context(): string;
|
||||
protected dashboardService: DashboardServiceInterface;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) protected dashboardService: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) protected commonService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => ElementRef)) protected _el: ElementRef,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) protected _cd: ChangeDetectorRef
|
||||
) {
|
||||
super();
|
||||
this.dashboardService = commonService as DashboardServiceInterface;
|
||||
}
|
||||
|
||||
protected init() {
|
||||
|
||||
@@ -13,6 +13,10 @@ panel.dashboard-panel > .tabbedPanel > .title > .monaco-scrollable-element > .ta
|
||||
border-bottom: 0px solid;
|
||||
}
|
||||
|
||||
panel.dashboard-panel > .tabbedPanel .tabList .tab .tabLabel {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
panel.dashboard-panel > .tabbedPanel > .title > .title-actions,
|
||||
panel.dashboard-panel > .tabbedPanel > .title > .monaco-scrollable-element > .tabList .tab-header {
|
||||
box-sizing: border-box;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import 'vs/css!./dashboardControlHostContainer';
|
||||
|
||||
import { Component, forwardRef, Input, AfterContentInit, ViewChild } from '@angular/core';
|
||||
import { Component, forwardRef, Input, AfterContentInit, ViewChild, OnChanges } from '@angular/core';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { DashboardTab } from 'sql/parts/dashboard/common/interfaces';
|
||||
import { TabConfig } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
@@ -18,6 +18,7 @@ import { ControlHostContent } from 'sql/parts/dashboard/contents/controlHostCont
|
||||
</controlhost-content>
|
||||
`
|
||||
})
|
||||
|
||||
export class DashboardControlHostContainer extends DashboardTab implements AfterContentInit {
|
||||
@Input() private tab: TabConfig;
|
||||
|
||||
@@ -53,6 +54,6 @@ export class DashboardControlHostContainer extends DashboardTab implements After
|
||||
}
|
||||
|
||||
public refresh(): void {
|
||||
// no op
|
||||
this._hostContent.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ export class DashboardErrorContainer extends DashboardTab implements AfterViewIn
|
||||
|
||||
ngAfterViewInit() {
|
||||
let errorMessage = this._errorMessageContainer.nativeElement as HTMLElement;
|
||||
errorMessage.innerHTML = nls.localize('dashboardNavSection_loadTabError', 'The {0} has an invalid content. Please contact extension owner.', this.tab.title);
|
||||
errorMessage.innerHTML = nls.localize('dashboardNavSection_loadTabError', 'The "{0}" section has invalid content. Please contact extension owner.', this.tab.title);
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Component, Inject, Input, forwardRef, ViewChild, ElementRef, ViewChildr
|
||||
import { NgGridConfig, NgGrid, NgGridItem } from 'angular2-grid';
|
||||
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { TabConfig, WidgetConfig } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
import { DashboardWidgetWrapper } from 'sql/parts/dashboard/contents/dashboardWidgetWrapper.component';
|
||||
import { subscriptionToDisposable } from 'sql/base/common/lifecycle';
|
||||
@@ -153,7 +154,7 @@ export class DashboardGridContainer extends DashboardTab implements OnDestroy {
|
||||
@ViewChildren(DashboardWidgetWrapper) private _widgets: QueryList<DashboardWidgetWrapper>;
|
||||
@ViewChildren(WebviewContent) private _webViews: QueryList<WebviewContent>;
|
||||
constructor(
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) protected dashboardService: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) protected dashboardService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => ElementRef)) protected _el: ElementRef,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) protected _cd: ChangeDetectorRef
|
||||
) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import { DashboardWidgetContainer } from 'sql/parts/dashboard/containers/dashboa
|
||||
import { DashboardTab } from 'sql/parts/dashboard/common/interfaces';
|
||||
import { WidgetConfig } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { AngularEventType } from '../../../services/angularEventing/angularEventingService';
|
||||
import { DashboardWidgetWrapper } from 'sql/parts/dashboard/contents/dashboardWidgetWrapper.component';
|
||||
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
@@ -30,12 +31,15 @@ export class DashboardHomeContainer extends DashboardWidgetContainer {
|
||||
@Input() private properties: WidgetConfig;
|
||||
@ViewChild('propertiesClass') private _propertiesClass: DashboardWidgetWrapper;
|
||||
|
||||
private dashboardService: DashboardServiceInterface;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) _cd: ChangeDetectorRef,
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) protected dashboardService: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) protected commonService: CommonServiceInterface,
|
||||
|
||||
) {
|
||||
super(_cd);
|
||||
this.dashboardService = commonService as DashboardServiceInterface;
|
||||
}
|
||||
|
||||
ngAfterContentInit() {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import 'vs/css!./dashboardWebviewContainer';
|
||||
|
||||
import { Component, forwardRef, Input, AfterContentInit, ViewChild } from '@angular/core';
|
||||
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
|
||||
import { DashboardTab } from 'sql/parts/dashboard/common/interfaces';
|
||||
import { TabConfig } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
import { ModelViewContent } from 'sql/parts/modelComponents/modelViewContent.component';
|
||||
|
||||
@Component({
|
||||
selector: 'dashboard-modelview-container',
|
||||
providers: [{ provide: DashboardTab, useExisting: forwardRef(() => DashboardModelViewContainer) }],
|
||||
template: `
|
||||
<modelview-content [modelViewId]="tab.id">
|
||||
</modelview-content>
|
||||
`
|
||||
})
|
||||
export class DashboardModelViewContainer extends DashboardTab implements AfterContentInit {
|
||||
@Input() private tab: TabConfig;
|
||||
|
||||
private _onResize = new Emitter<void>();
|
||||
public readonly onResize: Event<void> = this._onResize.event;
|
||||
|
||||
@ViewChild(ModelViewContent) private _modelViewContent: ModelViewContent;
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
ngAfterContentInit(): void {
|
||||
this._register(this._modelViewContent.onResize(() => {
|
||||
this._onResize.fire();
|
||||
}));
|
||||
}
|
||||
|
||||
public layout(): void {
|
||||
this._modelViewContent.layout();
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return this.tab.id;
|
||||
}
|
||||
|
||||
public get editable(): boolean {
|
||||
return this.tab.editable;
|
||||
}
|
||||
|
||||
public refresh(): void {
|
||||
// no op
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import * as nls from 'vs/nls';
|
||||
|
||||
import { registerContainerType, registerNavSectionContainerType } from 'sql/platform/dashboard/common/dashboardContainerRegistry';
|
||||
|
||||
export const MODELVIEW_CONTAINER = 'modelview-container';
|
||||
|
||||
let modelviewSchema: IJSONSchema = {
|
||||
type: 'null',
|
||||
description: nls.localize('dashboard.container.modelview', "The model-backed view that will be displayed in this tab."),
|
||||
default: null
|
||||
};
|
||||
|
||||
registerContainerType(MODELVIEW_CONTAINER, modelviewSchema);
|
||||
registerNavSectionContainerType(MODELVIEW_CONTAINER, modelviewSchema);
|
||||
@@ -0,0 +1,10 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
dashboard-modelview-container {
|
||||
height: 100%;
|
||||
width : 100%;
|
||||
display: block;
|
||||
}
|
||||
@@ -11,6 +11,8 @@
|
||||
</dashboard-webview-container>
|
||||
<dashboard-widget-container *ngIf="getContentType(tab) === 'widgets-container'" [tab]="tab">
|
||||
</dashboard-widget-container>
|
||||
<dashboard-modelview-container *ngIf="getContentType(tab) === 'modelview-container'" [tab]="tab">
|
||||
</dashboard-modelview-container>
|
||||
<dashboard-grid-container *ngIf="getContentType(tab) === 'grid-container'" [tab]="tab">
|
||||
</dashboard-grid-container>
|
||||
<dashboard-error-container *ngIf="getContentType(tab) === 'error-container'" [tab]="tab">
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'vs/css!./dashboardNavSection';
|
||||
import { Component, Inject, Input, forwardRef, ViewChild, ElementRef, ViewChildren, QueryList, OnDestroy, ChangeDetectorRef, EventEmitter, OnChanges, AfterContentInit } from '@angular/core';
|
||||
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { WidgetConfig, TabConfig, NavSectionConfig } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
import { PanelComponent, IPanelOptions, NavigationBarLayout } from 'sql/base/browser/ui/panel/panel.component';
|
||||
import { TabComponent } from 'sql/base/browser/ui/panel/tab.component';
|
||||
@@ -53,7 +54,7 @@ export class DashboardNavSection extends DashboardTab implements OnDestroy, OnCh
|
||||
@ViewChildren(DashboardTab) private _tabs: QueryList<DashboardTab>;
|
||||
@ViewChild(PanelComponent) private _panel: PanelComponent;
|
||||
constructor(
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) protected dashboardService: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) protected dashboardService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) protected _cd: ChangeDetectorRef
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -5,5 +5,4 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
-->
|
||||
|
||||
<agentview-component *ngIf="(controlType) === 'agent'">
|
||||
</agentview-component>
|
||||
<agentview-component #agent *ngIf="(controlType) === 'agent'"></agentview-component>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import 'vs/css!./controlHostContent';
|
||||
|
||||
import { Component, forwardRef, Input, OnInit, Inject, ChangeDetectorRef, ElementRef } from '@angular/core';
|
||||
import { Component, forwardRef, Input, OnInit, Inject, ChangeDetectorRef, ElementRef, ViewChild } from '@angular/core';
|
||||
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { Parts } from 'vs/workbench/services/part/common/partService';
|
||||
@@ -13,15 +13,17 @@ import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { DashboardTab } from 'sql/parts/dashboard/common/interfaces';
|
||||
import { TabConfig } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { AgentViewComponent } from '../../jobManagement/agent/agentView.component';
|
||||
|
||||
@Component({
|
||||
templateUrl: decodeURI(require.toUrl('sql/parts/dashboard/contents/controlHostContent.component.html')),
|
||||
selector: 'controlhost-content'
|
||||
})
|
||||
export class ControlHostContent implements OnInit {
|
||||
export class ControlHostContent {
|
||||
@Input() private webviewId: string;
|
||||
|
||||
private _onResize = new Emitter<void>();
|
||||
@@ -32,16 +34,16 @@ export class ControlHostContent implements OnInit {
|
||||
private _onMessageDisposable: IDisposable;
|
||||
private _type: string;
|
||||
|
||||
/* Children components */
|
||||
@ViewChild('agent') private _agentViewComponent: AgentViewComponent;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) private _dashboardService: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private _dashboardService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
public layout(): void {
|
||||
}
|
||||
|
||||
@@ -73,4 +75,8 @@ export class ControlHostContent implements OnInit {
|
||||
public get controlType(): string {
|
||||
return this._type;
|
||||
}
|
||||
|
||||
public refresh() {
|
||||
this._agentViewComponent.refresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import { InsightsWidget } from 'sql/parts/dashboard/widgets/insights/insightsWid
|
||||
import { WebviewWidget } from 'sql/parts/dashboard/widgets/webview/webviewWidget.component';
|
||||
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
@@ -35,6 +36,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
const componentMap: { [x: string]: Type<IDashboardWidget> } = {
|
||||
'properties-widget': PropertiesWidgetComponent,
|
||||
@@ -52,6 +54,7 @@ export class DashboardWidgetWrapper extends AngularDisposable implements OnInit
|
||||
@Input() private _config: WidgetConfig;
|
||||
@Input() private collapsable = false;
|
||||
|
||||
private _collapseAction: CollapseWidgetAction;
|
||||
private _collapsed = false;
|
||||
|
||||
public get collapsed(): boolean {
|
||||
@@ -63,6 +66,7 @@ export class DashboardWidgetWrapper extends AngularDisposable implements OnInit
|
||||
return;
|
||||
}
|
||||
this._collapsed = val;
|
||||
this._collapseAction.state = val;
|
||||
this._changeref.detectChanges();
|
||||
if (!val) {
|
||||
this.loadWidget();
|
||||
@@ -85,7 +89,7 @@ export class DashboardWidgetWrapper extends AngularDisposable implements OnInit
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ComponentFactoryResolver)) private _componentFactoryResolver: ComponentFactoryResolver,
|
||||
@Inject(forwardRef(() => ElementRef)) private _ref: ElementRef,
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) private _bootstrap: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrap: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeref: ChangeDetectorRef,
|
||||
@Inject(forwardRef(() => Injector)) private _injector: Injector
|
||||
) {
|
||||
@@ -108,7 +112,8 @@ export class DashboardWidgetWrapper extends AngularDisposable implements OnInit
|
||||
this._actionbar = new ActionBar(this._actionbarRef.nativeElement);
|
||||
if (this._actions) {
|
||||
if (this.collapsable) {
|
||||
this._actionbar.push(this._bootstrap.instantiationService.createInstance(CollapseWidgetAction, this._bootstrap.getUnderlyingUri(), this.guid, this.collapsed), { icon: true, label: false });
|
||||
this._collapseAction = this._bootstrap.instantiationService.createInstance(CollapseWidgetAction, this._bootstrap.getUnderlyingUri(), this.guid, this.collapsed);
|
||||
this._actionbar.push(this._collapseAction, { icon: true, label: false });
|
||||
}
|
||||
this._actionbar.push(this._bootstrap.instantiationService.createInstance(ToggleMoreWidgetAction, this._actions, this._component.actionsContext), { icon: true, label: false });
|
||||
}
|
||||
@@ -116,13 +121,13 @@ export class DashboardWidgetWrapper extends AngularDisposable implements OnInit
|
||||
}
|
||||
|
||||
public refresh(): void {
|
||||
if (this._component && this._component.refresh) {
|
||||
if (!this.collapsed && this._component && this._component.refresh) {
|
||||
this._component.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public layout(): void {
|
||||
if (this._component && this._component.layout) {
|
||||
if (!this.collapsed && this._component && this._component.layout) {
|
||||
this._component.layout();
|
||||
}
|
||||
}
|
||||
@@ -163,7 +168,7 @@ export class DashboardWidgetWrapper extends AngularDisposable implements OnInit
|
||||
this._component = componentRef.instance;
|
||||
let actions = componentRef.instance.actions;
|
||||
if (componentRef.instance.refresh) {
|
||||
actions.push(new RefreshWidgetAction(componentRef.instance.refresh, componentRef.instance));
|
||||
actions.push(new RefreshWidgetAction(this.refresh, this));
|
||||
}
|
||||
if (actions !== undefined && actions.length > 0) {
|
||||
this._actions = actions;
|
||||
|
||||
@@ -16,7 +16,8 @@ import { memoize } from 'vs/base/common/decorators';
|
||||
import { DashboardTab } from 'sql/parts/dashboard/common/interfaces';
|
||||
import { TabConfig } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { IDashboardWebview } from 'sql/services/dashboardWebview/common/dashboardWebviewService';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { IDashboardWebview } from 'sql/services/dashboard/common/dashboardViewService';
|
||||
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
@@ -36,17 +37,19 @@ export class WebviewContent extends AngularDisposable implements OnInit, IDashbo
|
||||
private _onMessageDisposable: IDisposable;
|
||||
private _webview: Webview;
|
||||
private _html: string;
|
||||
private _dashboardService: DashboardServiceInterface;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) private _dashboardService: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private commonService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef
|
||||
) {
|
||||
super();
|
||||
this._dashboardService = commonService as DashboardServiceInterface;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this._dashboardService.dashboardWebviewService.registerWebview(this);
|
||||
this._dashboardService.dashboardViewService.registerWebview(this);
|
||||
this._createWebview();
|
||||
this._register(addDisposableListener(window, EventType.RESIZE, e => {
|
||||
this.layout();
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Component, Inject, Input, forwardRef, ViewChild, ViewChildren, QueryLis
|
||||
import { NgGridConfig, NgGrid, NgGridItem } from 'angular2-grid';
|
||||
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { WidgetConfig } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
import { DashboardWidgetWrapper } from 'sql/parts/dashboard/contents/dashboardWidgetWrapper.component';
|
||||
import { subscriptionToDisposable, AngularDisposable } from 'sql/base/common/lifecycle';
|
||||
@@ -111,11 +112,14 @@ export class WidgetContent extends AngularDisposable implements AfterViewInit {
|
||||
@ViewChildren(NgGridItem) private _items: QueryList<NgGridItem>;
|
||||
@ViewChild('scrollable', { read: ElementRef }) private _scrollable: ElementRef;
|
||||
@ViewChild('scrollContainer', { read: ElementRef }) private _scrollContainer: ElementRef;
|
||||
|
||||
protected dashboardService: DashboardServiceInterface;
|
||||
constructor(
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) protected dashboardService: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) protected commonService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) protected _cd: ChangeDetectorRef
|
||||
) {
|
||||
super();
|
||||
this.dashboardService = commonService as DashboardServiceInterface;
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, O
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { DashboardServiceInterface } from './services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
import * as Utils from 'sql/parts/connection/common/utils';
|
||||
import { RefreshWidgetAction, EditDashboardAction } from 'sql/parts/dashboard/common/actions';
|
||||
@@ -36,7 +37,7 @@ export class DashboardComponent extends AngularDisposable implements OnInit {
|
||||
private editDisposable: IDisposable;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) private _bootstrapService: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrapService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => Router)) private _router: Router,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef
|
||||
) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import { ChartsModule } from 'ng2-charts/ng2-charts';
|
||||
import CustomUrlSerializer from 'sql/common/urlSerializer';
|
||||
import { IBootstrapService, BOOTSTRAP_SERVICE_ID } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { Extensions, IInsightRegistry } from 'sql/platform/dashboard/common/insightRegistry';
|
||||
import { Extensions as ComponentExtensions, IComponentRegistry } from 'sql/platform/dashboard/common/modelComponentRegistry';
|
||||
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
|
||||
@@ -25,6 +26,7 @@ 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';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
|
||||
/* Directives */
|
||||
import { ComponentHostDirective } from 'sql/parts/dashboard/common/componentHost.directive';
|
||||
@@ -35,9 +37,12 @@ import { DashboardWidgetWrapper } from 'sql/parts/dashboard/contents/dashboardWi
|
||||
import { DashboardWidgetContainer } from 'sql/parts/dashboard/containers/dashboardWidgetContainer.component';
|
||||
import { DashboardGridContainer } from 'sql/parts/dashboard/containers/dashboardGridContainer.component';
|
||||
import { DashboardWebviewContainer } from 'sql/parts/dashboard/containers/dashboardWebviewContainer.component';
|
||||
import { DashboardModelViewContainer } from 'sql/parts/dashboard/containers/dashboardModelViewContainer.component';
|
||||
import { DashboardErrorContainer } from 'sql/parts/dashboard/containers/dashboardErrorContainer.component';
|
||||
import { DashboardNavSection } from 'sql/parts/dashboard/containers/dashboardNavSection.component';
|
||||
import { WidgetContent } from 'sql/parts/dashboard/contents/widgetContent.component';
|
||||
import { ModelViewContent } from 'sql/parts/modelComponents/modelViewContent.component';
|
||||
import { ModelComponentWrapper } from 'sql/parts/modelComponents/modelComponentWrapper.component';
|
||||
import { WebviewContent } from 'sql/parts/dashboard/contents/webviewContent.component';
|
||||
import { BreadcrumbComponent } from 'sql/base/browser/ui/breadcrumb/breadcrumb.component';
|
||||
import { IBreadcrumbService } from 'sql/base/browser/ui/breadcrumb/interfaces';
|
||||
@@ -49,9 +54,9 @@ import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.comp
|
||||
import { JobHistoryComponent } from 'sql/parts/jobManagement/views/jobHistory.component';
|
||||
|
||||
let baseComponents = [DashboardHomeContainer, DashboardComponent, DashboardWidgetWrapper, DashboardWebviewContainer,
|
||||
DashboardWidgetContainer, DashboardGridContainer, DashboardErrorContainer, DashboardNavSection, WebviewContent, WidgetContent,
|
||||
ComponentHostDirective, BreadcrumbComponent, ControlHostContent, DashboardControlHostContainer,
|
||||
JobsViewComponent, AgentViewComponent, JobHistoryComponent, JobStepsViewComponent];
|
||||
DashboardWidgetContainer, DashboardGridContainer, DashboardErrorContainer, DashboardNavSection, ModelViewContent, WebviewContent, WidgetContent,
|
||||
ComponentHostDirective, BreadcrumbComponent, ControlHostContent, DashboardControlHostContainer,
|
||||
JobsViewComponent, AgentViewComponent, JobHistoryComponent, JobStepsViewComponent, DashboardModelViewContainer, ModelComponentWrapper];
|
||||
|
||||
/* Panel */
|
||||
import { PanelModule } from 'sql/base/browser/ui/panel/panel.module';
|
||||
@@ -81,6 +86,9 @@ let widgetComponents = [
|
||||
/* Insights */
|
||||
let insightComponents = Registry.as<IInsightRegistry>(Extensions.InsightContribution).getAllCtors();
|
||||
|
||||
/* Model-backed components */
|
||||
let extensionComponents = Registry.as<IComponentRegistry>(ComponentExtensions.ComponentContribution).getAllCtors();
|
||||
|
||||
// Setup routes for various child components
|
||||
const appRoutes: Routes = [
|
||||
{ path: 'database-dashboard', component: DatabaseDashboardPage },
|
||||
@@ -99,13 +107,15 @@ const appRoutes: Routes = [
|
||||
...baseComponents,
|
||||
...pageComponents,
|
||||
...widgetComponents,
|
||||
...insightComponents
|
||||
...insightComponents,
|
||||
...extensionComponents
|
||||
],
|
||||
// also for widgets
|
||||
entryComponents: [
|
||||
DashboardComponent,
|
||||
...widgetComponents,
|
||||
...insightComponents
|
||||
...insightComponents,
|
||||
...extensionComponents
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
@@ -119,18 +129,19 @@ const appRoutes: Routes = [
|
||||
providers: [
|
||||
{ provide: APP_BASE_HREF, useValue: '/' },
|
||||
{ provide: IBreadcrumbService, useClass: BreadcrumbService },
|
||||
DashboardServiceInterface,
|
||||
{ provide: CommonServiceInterface, useClass: DashboardServiceInterface },
|
||||
{ provide: UrlSerializer, useClass: CustomUrlSerializer }
|
||||
]
|
||||
})
|
||||
export class DashboardModule {
|
||||
|
||||
private _bootstrap: DashboardServiceInterface;
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ComponentFactoryResolver)) private _resolver: ComponentFactoryResolver,
|
||||
@Inject(BOOTSTRAP_SERVICE_ID) private _bootstrapService: IBootstrapService,
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) private _bootstrap: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) bootstrap: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => Router)) private _router: Router
|
||||
) {
|
||||
this._bootstrap = bootstrap as DashboardServiceInterface;
|
||||
}
|
||||
|
||||
ngDoBootstrap(appRef: ApplicationRef) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import { IBootstrapService, BOOTSTRAP_SERVICE_ID } from 'sql/services/bootstrap/
|
||||
|
||||
import * as colors from 'vs/platform/theme/common/colorRegistry';
|
||||
import * as nls from 'vs/nls';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
|
||||
export class DatabaseDashboardPage extends DashboardPage implements OnInit {
|
||||
protected propertiesWidget: WidgetConfig = {
|
||||
@@ -35,7 +36,7 @@ export class DatabaseDashboardPage extends DashboardPage implements OnInit {
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => IBreadcrumbService)) private _breadcrumbService: IBreadcrumbService,
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) dashboardService: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) dashboardService: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) _cd: ChangeDetectorRef,
|
||||
@Inject(forwardRef(() => ElementRef)) el: ElementRef
|
||||
) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { BreadcrumbClass } from 'sql/parts/dashboard/services/breadcrumb.service
|
||||
import { IBreadcrumbService } from 'sql/base/browser/ui/breadcrumb/interfaces';
|
||||
import { WidgetConfig } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { IBootstrapService, BOOTSTRAP_SERVICE_ID } from 'sql/services/bootstrap/bootstrapService';
|
||||
|
||||
import * as colors from 'vs/platform/theme/common/colorRegistry';
|
||||
@@ -36,7 +37,7 @@ export class ServerDashboardPage extends DashboardPage implements OnInit {
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => IBreadcrumbService)) private breadcrumbService: IBreadcrumbService,
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) dashboardService: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) dashboardService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) _cd: ChangeDetectorRef,
|
||||
@Inject(forwardRef(() => ElementRef)) el: ElementRef
|
||||
) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Injectable, forwardRef, Inject, OnDestroy } from '@angular/core';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
|
||||
import { DashboardServiceInterface } from './dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { MenuItem, IBreadcrumbService } from 'sql/base/browser/ui/breadcrumb/interfaces';
|
||||
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
|
||||
|
||||
@@ -23,9 +24,11 @@ export class BreadcrumbService implements IBreadcrumbService {
|
||||
public breadcrumbItem: Subject<MenuItem[]>;
|
||||
private itemBreadcrums: MenuItem[];
|
||||
private _currentPage: BreadcrumbClass;
|
||||
private _bootstrap: DashboardServiceInterface;
|
||||
|
||||
constructor( @Inject(forwardRef(() => DashboardServiceInterface)) private _bootstrap: DashboardServiceInterface) {
|
||||
_bootstrap.onUpdatePage(() => {
|
||||
constructor( @Inject(forwardRef(() => CommonServiceInterface)) private commonService: CommonServiceInterface) {
|
||||
this._bootstrap = commonService as DashboardServiceInterface;
|
||||
this._bootstrap.onUpdatePage(() => {
|
||||
this.setBreadcrumbs(this._currentPage);
|
||||
});
|
||||
this.breadcrumbItem = new Subject<MenuItem[]>();
|
||||
|
||||
@@ -23,9 +23,11 @@ import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
import { AngularEventType, IAngularEvent, IAngularEventingService } from 'sql/services/angularEventing/angularEventingService';
|
||||
import { IDashboardTab } from 'sql/platform/dashboard/common/dashboardRegistry';
|
||||
import { TabSettingConfig } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
import { IDashboardWebviewService } from 'sql/services/dashboardWebview/common/dashboardWebviewService';
|
||||
import { IDashboardViewService } from 'sql/services/dashboard/common/dashboardViewService';
|
||||
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
||||
import { ConnectionContextkey } from 'sql/parts/connection/common/connectionContextKey';
|
||||
import { SingleConnectionMetadataService, SingleConnectionManagementService, SingleAdminService, SingleQueryManagementService, CommonServiceInterface }
|
||||
from 'sql/services/common/commonServiceInterface.service';
|
||||
|
||||
import { ProviderMetadata, DatabaseInfo, SimpleExecuteResult } from 'sqlops';
|
||||
|
||||
@@ -50,68 +52,6 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
|
||||
|
||||
const DASHBOARD_SETTINGS = 'dashboard';
|
||||
|
||||
/* Wrapper for a metadata service that contains the uri string to use on each request */
|
||||
export class SingleConnectionMetadataService {
|
||||
|
||||
constructor(
|
||||
private _metadataService: IMetadataService,
|
||||
private _uri: string
|
||||
) { }
|
||||
|
||||
get metadata(): Observable<ProviderMetadata> {
|
||||
return Observable.fromPromise(this._metadataService.getMetadata(this._uri));
|
||||
}
|
||||
|
||||
get databaseNames(): Observable<string[]> {
|
||||
return Observable.fromPromise(this._metadataService.getDatabaseNames(this._uri));
|
||||
}
|
||||
}
|
||||
|
||||
/* Wrapper for a connection service that contains the uri string to use on each request */
|
||||
export class SingleConnectionManagementService {
|
||||
|
||||
constructor(
|
||||
private _connectionService: IConnectionManagementService,
|
||||
private _uri: string,
|
||||
private _contextKey: ConnectionContextkey
|
||||
) { }
|
||||
|
||||
public changeDatabase(name: string): Thenable<boolean> {
|
||||
return this._connectionService.changeDatabase(this._uri, name).then(e => {
|
||||
// we need to update our context
|
||||
this._contextKey.set(this.connectionInfo.connectionProfile);
|
||||
return e;
|
||||
});
|
||||
}
|
||||
|
||||
public get connectionInfo(): ConnectionManagementInfo {
|
||||
return this._connectionService.getConnectionInfo(this._uri);
|
||||
}
|
||||
}
|
||||
|
||||
export class SingleAdminService {
|
||||
|
||||
constructor(
|
||||
private _adminService: IAdminService,
|
||||
private _uri: string
|
||||
) { }
|
||||
|
||||
public get databaseInfo(): Observable<DatabaseInfo> {
|
||||
return Observable.fromPromise(this._adminService.getDatabaseInfo(this._uri));
|
||||
}
|
||||
}
|
||||
|
||||
export class SingleQueryManagementService {
|
||||
constructor(
|
||||
private _queryManagementService: IQueryManagementService,
|
||||
private _uri: string
|
||||
) { }
|
||||
|
||||
public runQueryAndReturn(queryString: string): Thenable<SimpleExecuteResult> {
|
||||
return this._queryManagementService.runQueryAndReturn(this._uri, queryString);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Providers a interface between a dashboard interface and the rest of carbon.
|
||||
Stores the uri and unique selector of a dashboard instance and uses that
|
||||
@@ -120,35 +60,12 @@ export class SingleQueryManagementService {
|
||||
usage of a widget.
|
||||
*/
|
||||
@Injectable()
|
||||
export class DashboardServiceInterface extends AngularDisposable {
|
||||
private _uniqueSelector: string;
|
||||
private _uri: string;
|
||||
private _bootstrapParams: DashboardComponentParams;
|
||||
export class DashboardServiceInterface extends CommonServiceInterface {
|
||||
|
||||
/* Static Services */
|
||||
private _themeService = this._bootstrapService.themeService;
|
||||
private _contextMenuService = this._bootstrapService.contextMenuService;
|
||||
private _instantiationService = this._bootstrapService.instantiationService;
|
||||
private _configService = this._bootstrapService.configurationService;
|
||||
private _insightsDialogService = this._bootstrapService.insightsDialogService;
|
||||
private _contextViewService = this._bootstrapService.contextViewService;
|
||||
private _notificationService = this._bootstrapService.notificationService;
|
||||
private _workspaceContextService = this._bootstrapService.workspaceContextService;
|
||||
private _storageService = this._bootstrapService.storageService;
|
||||
private _capabilitiesService = this._bootstrapService.capabilitiesService;
|
||||
private _configurationEditingService = this._bootstrapService.configurationEditorService;
|
||||
private _commandService = this._bootstrapService.commandService;
|
||||
private _dashboardWebviewService = this._bootstrapService.dashboardWebviewService;
|
||||
private _partService = this._bootstrapService.partService;
|
||||
private _angularEventingService = this._bootstrapService.angularEventingService;
|
||||
private _environmentService = this._bootstrapService.environmentService;
|
||||
|
||||
/* Special Services */
|
||||
private _metadataService: SingleConnectionMetadataService;
|
||||
private _connectionManagementService: SingleConnectionManagementService;
|
||||
private _adminService: SingleAdminService;
|
||||
private _queryManagementService: SingleQueryManagementService;
|
||||
private _contextKeyService: IContextKeyService;
|
||||
private _dashboardViewService = this._bootstrapService.dashboardViewService;
|
||||
|
||||
|
||||
private _updatePage = new Emitter<void>();
|
||||
public readonly onUpdatePage: Event<void> = this._updatePage.event;
|
||||
@@ -168,91 +85,17 @@ export class DashboardServiceInterface extends AngularDisposable {
|
||||
private _dashboardContextKey = new RawContextKey<string>('dashboardContext', undefined);
|
||||
public dashboardContextKey: IContextKey<string>;
|
||||
|
||||
private _connectionContextKey: ConnectionContextkey;
|
||||
|
||||
private _numberOfPageNavigations = 0;
|
||||
|
||||
constructor(
|
||||
@Inject(BOOTSTRAP_SERVICE_ID) private _bootstrapService: IBootstrapService,
|
||||
@Inject(BOOTSTRAP_SERVICE_ID) bootstrapService: IBootstrapService,
|
||||
@Inject(forwardRef(() => Router)) private _router: Router,
|
||||
) {
|
||||
super();
|
||||
super(bootstrapService);
|
||||
}
|
||||
|
||||
public get notificationService(): INotificationService {
|
||||
return this._notificationService;
|
||||
}
|
||||
|
||||
public get configurationEditingService(): ConfigurationEditingService {
|
||||
return this._configurationEditingService;
|
||||
}
|
||||
|
||||
public get metadataService(): SingleConnectionMetadataService {
|
||||
return this._metadataService;
|
||||
}
|
||||
|
||||
public get connectionManagementService(): SingleConnectionManagementService {
|
||||
return this._connectionManagementService;
|
||||
}
|
||||
|
||||
public get commandService(): ICommandService {
|
||||
return this._commandService;
|
||||
}
|
||||
|
||||
public get themeService(): IWorkbenchThemeService {
|
||||
return this._themeService;
|
||||
}
|
||||
|
||||
public get contextMenuService(): IContextMenuService {
|
||||
return this._contextMenuService;
|
||||
}
|
||||
|
||||
public get instantiationService(): IInstantiationService {
|
||||
return this._instantiationService;
|
||||
}
|
||||
|
||||
public get dashboardWebviewService(): IDashboardWebviewService {
|
||||
return this._dashboardWebviewService;
|
||||
}
|
||||
|
||||
public get partService(): IPartService {
|
||||
return this._partService;
|
||||
}
|
||||
|
||||
public get contextKeyService(): IContextKeyService {
|
||||
return this._contextKeyService;
|
||||
}
|
||||
|
||||
public get adminService(): SingleAdminService {
|
||||
return this._adminService;
|
||||
}
|
||||
|
||||
public get queryManagementService(): SingleQueryManagementService {
|
||||
return this._queryManagementService;
|
||||
}
|
||||
|
||||
public get environmentService(): IEnvironmentService {
|
||||
return this._environmentService;
|
||||
}
|
||||
|
||||
public get contextViewService(): IContextViewService {
|
||||
return this._contextViewService;
|
||||
}
|
||||
|
||||
public get workspaceContextService(): IWorkspaceContextService {
|
||||
return this._workspaceContextService;
|
||||
}
|
||||
|
||||
public get storageService(): IStorageService {
|
||||
return this._storageService;
|
||||
}
|
||||
|
||||
public get capabilitiesService(): ICapabilitiesService {
|
||||
return this._capabilitiesService;
|
||||
}
|
||||
|
||||
public get angularEventingService(): IAngularEventingService {
|
||||
return this._angularEventingService;
|
||||
public get dashboardViewService(): IDashboardViewService {
|
||||
return this._dashboardViewService;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,7 +106,7 @@ export class DashboardServiceInterface extends AngularDisposable {
|
||||
this._getbootstrapParams();
|
||||
}
|
||||
|
||||
private _getbootstrapParams(): void {
|
||||
protected _getbootstrapParams(): void {
|
||||
this._bootstrapParams = this._bootstrapService.getBootstrapParams<DashboardComponentParams>(this._uniqueSelector);
|
||||
this._contextKeyService = this._bootstrapParams.scopedContextService;
|
||||
this._connectionContextKey = this._bootstrapParams.connectionContextKey;
|
||||
@@ -275,27 +118,11 @@ export class DashboardServiceInterface extends AngularDisposable {
|
||||
* Set the uri for this dashboard instance, should only be set once
|
||||
* Inits all the services that depend on knowing a uri
|
||||
*/
|
||||
private set uri(uri: string) {
|
||||
this._uri = uri;
|
||||
this._metadataService = new SingleConnectionMetadataService(this._bootstrapService.metadataService, this._uri);
|
||||
this._connectionManagementService = new SingleConnectionManagementService(this._bootstrapService.connectionManagementService, this._uri, this._connectionContextKey);
|
||||
this._adminService = new SingleAdminService(this._bootstrapService.adminService, this._uri);
|
||||
this._queryManagementService = new SingleQueryManagementService(this._bootstrapService.queryManagementService, this._uri);
|
||||
protected set uri(uri: string) {
|
||||
super.setUri(uri);
|
||||
this._register(toDisposableSubscription(this._bootstrapService.angularEventingService.onAngularEvent(this._uri, (event) => this.handleDashboardEvent(event))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying Uri for dashboard
|
||||
* In general don't use this, use specific services instances exposed publically
|
||||
*/
|
||||
public getUnderlyingUri(): string {
|
||||
return this._uri;
|
||||
}
|
||||
|
||||
public getOriginalConnectionProfile(): IConnectionProfile {
|
||||
return this._bootstrapParams.connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of page navigation
|
||||
*/
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Router } from '@angular/router';
|
||||
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
import { MetadataType } from 'sql/parts/connection/common/connectionManagement';
|
||||
import { SingleConnectionManagementService } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { SingleConnectionManagementService } from 'sql/services/common/commonServiceInterface.service';
|
||||
import {
|
||||
NewQueryAction, ScriptSelectAction, EditDataAction, ScriptCreateAction, ScriptExecuteAction, ScriptAlterAction,
|
||||
BackupAction, ManageActionContext, BaseActionContext, ManageAction, RestoreAction
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
|
||||
import { ConnectionManagementInfo } from 'sql/parts/connection/common/connectionManagementInfo';
|
||||
import * as Constants from 'sql/parts/connection/common/constants';
|
||||
import { OEAction } from 'sql/parts/objectExplorer/viewlet/objectExplorerActions';
|
||||
|
||||
import { ObjectMetadata } from 'sqlops';
|
||||
|
||||
@@ -27,7 +28,8 @@ import { IAction } from 'vs/base/common/actions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { $ } from 'vs/base/browser/dom';
|
||||
import { OEAction } from 'sql/parts/registeredServer/viewlet/objectExplorerActions';
|
||||
import { ExecuteCommandAction } from 'vs/platform/actions/common/actions';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
|
||||
export class ObjectMetadataWrapper implements ObjectMetadata {
|
||||
public metadataType: MetadataType;
|
||||
@@ -164,6 +166,19 @@ export class ExplorerController extends TreeDefaults.DefaultController {
|
||||
this._router.navigate(['database-dashboard']);
|
||||
});
|
||||
}
|
||||
|
||||
protected onEnter(tree: tree.ITree, event: IKeyboardEvent): boolean {
|
||||
let result = super.onEnter(tree, event);
|
||||
if (result) {
|
||||
const focus = tree.getFocus();
|
||||
if (focus && !(focus instanceof ObjectMetadataWrapper)) {
|
||||
this._connectionService.changeDatabase(focus.databaseName).then(result => {
|
||||
this._router.navigate(['database-dashboard']);
|
||||
});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export class ExplorerDataSource implements tree.IDataSource {
|
||||
@@ -371,14 +386,14 @@ function GetExplorerActions(element: TreeResource, instantiationService: IInstan
|
||||
actions.push(instantiationService.createInstance(ScriptAlterAction, ScriptAlterAction.ID, ScriptAlterAction.LABEL));
|
||||
}
|
||||
} else {
|
||||
actions.push(instantiationService.createInstance(OEAction, NewQueryAction.ID, NewQueryAction.LABEL));
|
||||
actions.push(instantiationService.createInstance(CustomExecuteCommandAction, NewQueryAction.ID, NewQueryAction.LABEL));
|
||||
|
||||
let action: IAction = instantiationService.createInstance(OEAction, RestoreAction.ID, RestoreAction.LABEL);
|
||||
let action: IAction = instantiationService.createInstance(CustomExecuteCommandAction, RestoreAction.ID, RestoreAction.LABEL);
|
||||
if (capabilitiesService.isFeatureAvailable(action, info)) {
|
||||
actions.push(action);
|
||||
}
|
||||
|
||||
action = instantiationService.createInstance(OEAction, BackupAction.ID, BackupAction.LABEL);
|
||||
action = instantiationService.createInstance(CustomExecuteCommandAction, BackupAction.ID, BackupAction.LABEL);
|
||||
if (capabilitiesService.isFeatureAvailable(action, info)) {
|
||||
actions.push(action);
|
||||
}
|
||||
@@ -391,3 +406,9 @@ function GetExplorerActions(element: TreeResource, instantiationService: IInstan
|
||||
|
||||
return TPromise.as(actions);
|
||||
}
|
||||
|
||||
class CustomExecuteCommandAction extends ExecuteCommandAction {
|
||||
run(context: ManageActionContext): TPromise<any> {
|
||||
return super.run(context.profile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Router } from '@angular/router';
|
||||
|
||||
import { DashboardWidget, IDashboardWidget, WidgetConfig, WIDGET_CONFIG } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { toDisposableSubscription } from 'sql/parts/common/rxjsUtils';
|
||||
import { ExplorerFilter, ExplorerRenderer, ExplorerDataSource, ExplorerController, ObjectMetadataWrapper, ExplorerModel } from './explorerTree';
|
||||
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
|
||||
@@ -49,7 +50,7 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
|
||||
@ViewChild('table') private _tableContainer: ElementRef;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) private _bootstrap: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrap: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => Router)) private _router: Router,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||
@Inject(WIDGET_CONFIG) protected _config: WidgetConfig,
|
||||
@@ -62,8 +63,11 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
|
||||
ngOnInit() {
|
||||
this._inited = true;
|
||||
|
||||
let placeholderLabel = this._config.context === 'database' ? nls.localize('seachObjects', 'Search by name of type (a:, t:, v:, f:, or sp:)') : nls.localize('searchDatabases', 'Search databases');
|
||||
|
||||
let inputOptions: IInputOptions = {
|
||||
placeholder: this._config.context === 'database' ? nls.localize('seachObjects', 'Search by name of type (a:, t:, v:, f:, or sp:)') : nls.localize('searchDatabases', 'Search databases')
|
||||
placeholder: placeholderLabel,
|
||||
ariaLabel: placeholderLabel
|
||||
};
|
||||
this._input = new InputBox(this._inputContainer.nativeElement, this._bootstrap.contextViewService, inputOptions);
|
||||
this._register(this._input.onDidChange(e => {
|
||||
|
||||
@@ -10,7 +10,7 @@ import * as TaskUtilities from 'sql/workbench/common/taskUtilities';
|
||||
import { RunQueryOnConnectionMode, IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
|
||||
import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService';
|
||||
import { InsightActionContext } from 'sql/workbench/common/actions';
|
||||
import { IObjectExplorerService } from 'sql/parts/registeredServer/common/objectExplorerService';
|
||||
import { IObjectExplorerService } from 'sql/parts/objectExplorer/common/objectExplorerService';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
export class RunInsightQueryAction extends Action {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { Observable } from 'rxjs/Observable';
|
||||
|
||||
import { DashboardWidget, IDashboardWidget, WIDGET_CONFIG, WidgetConfig } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { ComponentHostDirective } from 'sql/parts/dashboard/common/componentHost.directive';
|
||||
import { InsightAction, InsightActionContext } from 'sql/workbench/common/actions';
|
||||
import { toDisposableSubscription } from 'sql/parts/common/rxjsUtils';
|
||||
@@ -26,6 +27,7 @@ import * as pfs from 'vs/base/node/pfs';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IntervalTimer } from 'vs/base/common/async';
|
||||
|
||||
const insightRegistry = Registry.as<IInsightRegistry>(Extensions.InsightContribution);
|
||||
|
||||
@@ -51,13 +53,14 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget,
|
||||
|
||||
private _typeKey: string;
|
||||
private _init: boolean = false;
|
||||
private _intervalTimer: IntervalTimer;
|
||||
|
||||
public error: string;
|
||||
public lastUpdated: string;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ComponentFactoryResolver)) private _componentFactoryResolver: ComponentFactoryResolver,
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) private dashboardService: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private dashboardService: CommonServiceInterface,
|
||||
@Inject(WIDGET_CONFIG) protected _config: WidgetConfig,
|
||||
@Inject(forwardRef(() => ViewContainerRef)) private viewContainerRef: ViewContainerRef,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef
|
||||
@@ -75,6 +78,7 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget,
|
||||
result => {
|
||||
if (this._init) {
|
||||
this._updateChild(result);
|
||||
this.setupInterval();
|
||||
} else {
|
||||
this.queryObv = Observable.fromPromise(Promise.resolve<SimpleExecuteResult>(result));
|
||||
}
|
||||
@@ -99,6 +103,7 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget,
|
||||
this._register(toDisposableSubscription(this.queryObv.subscribe(
|
||||
result => {
|
||||
this._updateChild(result);
|
||||
this.setupInterval();
|
||||
},
|
||||
error => {
|
||||
this.showError(error);
|
||||
@@ -107,6 +112,14 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget,
|
||||
}
|
||||
}
|
||||
|
||||
private setupInterval(): void {
|
||||
if (this.insightConfig.autoRefreshInterval) {
|
||||
this._intervalTimer = new IntervalTimer();
|
||||
this._register(this._intervalTimer);
|
||||
this._intervalTimer.cancelAndSet(() => this.refresh(), this.insightConfig.autoRefreshInterval * 60 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
private showError(error: string): void {
|
||||
this.error = error;
|
||||
this._cd.detectChanges();
|
||||
@@ -151,6 +164,7 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget,
|
||||
this.lastUpdated = nls.localize('insights.lastUpdated', "Last Updated: {0} {1}", date.toLocaleTimeString(), date.toLocaleDateString());
|
||||
if (this._init) {
|
||||
this._updateChild(storedResult.results);
|
||||
this.setupInterval();
|
||||
this._cd.detectChanges();
|
||||
} else {
|
||||
this.queryObv = Observable.fromPromise(Promise.resolve<SimpleExecuteResult>(JSON.parse(storage)));
|
||||
@@ -187,21 +201,22 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget,
|
||||
}
|
||||
|
||||
private _updateChild(result: SimpleExecuteResult): void {
|
||||
this.componentHost.viewContainerRef.clear();
|
||||
|
||||
if (result.rowCount === 0) {
|
||||
this.showError(nls.localize('noResults', 'No results to show'));
|
||||
return;
|
||||
}
|
||||
|
||||
let componentFactory = this._componentFactoryResolver.resolveComponentFactory<IInsightsView>(insightRegistry.getCtorFromId(this._typeKey));
|
||||
this.componentHost.viewContainerRef.clear();
|
||||
|
||||
let componentRef = this.componentHost.viewContainerRef.createComponent(componentFactory);
|
||||
let componentInstance = componentRef.instance;
|
||||
componentInstance.data = { columns: result.columnInfo.map(item => item.columnName), rows: result.rows.map(row => row.map(item => item.displayValue)) };
|
||||
// check if the setter is defined
|
||||
if (componentInstance.setConfig) {
|
||||
componentInstance.setConfig(this.insightConfig.type[this._typeKey]);
|
||||
}
|
||||
componentInstance.data = { columns: result.columnInfo.map(item => item.columnName), rows: result.rows.map(row => row.map(item => item.displayValue)) };
|
||||
|
||||
if (componentInstance.init) {
|
||||
componentInstance.init();
|
||||
@@ -229,6 +244,10 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget,
|
||||
throw new Error('No query was specified for this insight');
|
||||
}
|
||||
|
||||
if (this.insightConfig.autoRefreshInterval && !types.isNumber(this.insightConfig.autoRefreshInterval)) {
|
||||
throw new Error('Auto Refresh Interval must be a number if specified');
|
||||
}
|
||||
|
||||
if (!types.isStringArray(this.insightConfig.query)
|
||||
&& !types.isString(this.insightConfig.query)
|
||||
&& !types.isString(this.insightConfig.queryFile)) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { join } from 'path';
|
||||
|
||||
import { registerDashboardWidget, registerNonCustomDashboardWidget } from 'sql/platform/dashboard/common/widgetRegistry';
|
||||
import { Extensions as InsightExtensions, IInsightRegistry } from 'sql/platform/dashboard/common/insightRegistry';
|
||||
import { IInsightsConfig } from './interfaces';
|
||||
import { IInsightsConfig, IInsightTypeContrib } from './interfaces';
|
||||
import { insightsContribution, insightsSchema } from 'sql/parts/dashboard/widgets/insights/insightsWidgetSchemas';
|
||||
|
||||
import { IExtensionPointUser, ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
@@ -14,10 +14,6 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
||||
|
||||
const insightRegistry = Registry.as<IInsightRegistry>(InsightExtensions.InsightContribution);
|
||||
|
||||
interface IInsightTypeContrib {
|
||||
id: string;
|
||||
contrib: IInsightsConfig;
|
||||
}
|
||||
|
||||
registerDashboardWidget('insights-widget', '', insightsSchema);
|
||||
|
||||
|
||||
@@ -32,6 +32,10 @@ export const insightsSchema: IJSONSchema = {
|
||||
type: 'string',
|
||||
description: nls.localize('insightQueryFileDescription', '[Optional] path to a file that contains a query. Use if "query" is not set')
|
||||
},
|
||||
autoRefreshInterval: {
|
||||
type: 'number',
|
||||
description: nls.localize('insightAutoRefreshIntervalDescription', '[Optional] Auto refresh interval in minutes, if not set, there will be no auto refresh')
|
||||
},
|
||||
details: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -93,15 +97,15 @@ export const insightsSchema: IJSONSchema = {
|
||||
},
|
||||
database: {
|
||||
type: 'string',
|
||||
description: nls.localize('actionDatabaseDescription', 'Target database for the action; can use the format "${columnName} to use a data driven column name.')
|
||||
description: nls.localize('actionDatabaseDescription', 'Target database for the action; can use the format "${columnName}" to use a data driven column name.')
|
||||
},
|
||||
server: {
|
||||
type: 'string',
|
||||
description: nls.localize('actionServerDescription', 'Target server for the action; can use the format "${columnName} to use a data driven column name.')
|
||||
description: nls.localize('actionServerDescription', 'Target server for the action; can use the format "${columnName}" to use a data driven column name.')
|
||||
},
|
||||
user: {
|
||||
type: 'string',
|
||||
description: nls.localize('actionUserDescription', 'Target user for the action; can use the format "${columnName} to use a data driven column name.')
|
||||
description: nls.localize('actionUserDescription', 'Target user for the action; can use the format "${columnName}" to use a data driven column name.')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,4 +56,9 @@ export interface IInsightsConfig {
|
||||
query?: string | Array<string>;
|
||||
queryFile?: string;
|
||||
details?: IInsightsConfigDetails;
|
||||
autoRefreshInterval?: number;
|
||||
}
|
||||
export interface IInsightTypeContrib {
|
||||
id: string;
|
||||
contrib: IInsightsConfig;
|
||||
}
|
||||
@@ -79,6 +79,7 @@ export interface IChartConfig {
|
||||
legendPosition?: LegendPosition;
|
||||
dataDirection?: DataDirection;
|
||||
columnsAsLabels?: boolean;
|
||||
showTopNData?: number;
|
||||
}
|
||||
|
||||
export const defaultChartConfig: IChartConfig = {
|
||||
@@ -90,7 +91,7 @@ export const defaultChartConfig: IChartConfig = {
|
||||
|
||||
@Component({
|
||||
template: ` <div style="display: block; width: 100%; height: 100%; position: relative">
|
||||
<canvas #canvas *ngIf="_isDataAvailable"
|
||||
<canvas #canvas *ngIf="_isDataAvailable && _hasInit"
|
||||
baseChart
|
||||
[datasets]="chartData"
|
||||
[labels]="labels"
|
||||
@@ -101,6 +102,7 @@ export const defaultChartConfig: IChartConfig = {
|
||||
})
|
||||
export abstract class ChartInsight extends Disposable implements IInsightsView {
|
||||
private _isDataAvailable: boolean = false;
|
||||
private _hasInit: boolean = false;
|
||||
private _options: any = {};
|
||||
|
||||
@ViewChild(BaseChartDirective) private _chart: BaseChartDirective;
|
||||
@@ -111,7 +113,6 @@ export abstract class ChartInsight extends Disposable implements IInsightsView {
|
||||
|
||||
protected abstract get chartType(): ChartType;
|
||||
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
|
||||
@@ -127,7 +128,7 @@ export abstract class ChartInsight extends Disposable implements IInsightsView {
|
||||
// This is because chart.js doesn't auto-update anything other than dataset when re-rendering so defaults are used
|
||||
// hence it's easier to not render until ready
|
||||
this.options = mixin(this.options, { maintainAspectRatio: false });
|
||||
this._isDataAvailable = true;
|
||||
this._hasInit = true;
|
||||
this._changeRef.detectChanges();
|
||||
TelemetryUtils.addTelemetry(this._bootstrapService.telemetryService, TelemetryKeys.ChartCreated, { type: this.chartType });
|
||||
}
|
||||
@@ -162,7 +163,9 @@ export abstract class ChartInsight extends Disposable implements IInsightsView {
|
||||
|
||||
public refresh() {
|
||||
// cheaper refresh but causes problems when change data for rerender
|
||||
this._chart.ngOnChanges({});
|
||||
if (this._chart) {
|
||||
this._chart.ngOnChanges({});
|
||||
}
|
||||
}
|
||||
|
||||
public getCanvasData(): string {
|
||||
@@ -177,11 +180,42 @@ export abstract class ChartInsight extends Disposable implements IInsightsView {
|
||||
// unmemoize chart data as the data needs to be recalced
|
||||
unmemoize(this, 'chartData');
|
||||
unmemoize(this, 'labels');
|
||||
this._data = data;
|
||||
this._data = this.filterToTopNData(data);
|
||||
if (isValidData(data)) {
|
||||
this._isDataAvailable = true;
|
||||
}
|
||||
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
private filterToTopNData(data: IInsightData): IInsightData {
|
||||
if (this._config.dataDirection === 'horizontal') {
|
||||
return {
|
||||
columns: this.getTopNData(data.columns),
|
||||
rows: data.rows.map((row) => {
|
||||
return this.getTopNData(row);
|
||||
})
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
columns: data.columns,
|
||||
rows: data.rows.slice(0, this._config.showTopNData)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private getTopNData(data: any[]): any[] {
|
||||
if (this._config.showTopNData) {
|
||||
if (this._config.dataDirection === 'horizontal' && this._config.labelFirstColumn) {
|
||||
return data.slice(0, this._config.showTopNData + 1);
|
||||
} else {
|
||||
return data.slice(0, this._config.showTopNData);
|
||||
}
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
protected clearMemoize(): void {
|
||||
// unmemoize getters since their result can be changed by a new config
|
||||
unmemoize(this, 'getChartData');
|
||||
@@ -226,14 +260,14 @@ export abstract class ChartInsight extends Disposable implements IInsightsView {
|
||||
data: this._data.rows.map(row => Number(row[i])),
|
||||
label: this._data.columns[i]
|
||||
};
|
||||
}).slice(1);
|
||||
});
|
||||
} else {
|
||||
return this._data.rows[0].map((row, i) => {
|
||||
return {
|
||||
data: this._data.rows.map(row => Number(row[i])),
|
||||
label: 'Series' + i
|
||||
};
|
||||
}).slice(1);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -245,7 +279,11 @@ export abstract class ChartInsight extends Disposable implements IInsightsView {
|
||||
@memoize
|
||||
public getLabels(): Array<string> {
|
||||
if (this._config.dataDirection === 'horizontal') {
|
||||
return this._data.columns;
|
||||
if (this._config.labelFirstColumn) {
|
||||
return this._data.columns.slice(1);
|
||||
} else {
|
||||
return this._data.columns;
|
||||
}
|
||||
} else {
|
||||
return this._data.rows.map(row => row[0]);
|
||||
}
|
||||
@@ -284,3 +322,19 @@ export abstract class ChartInsight extends Disposable implements IInsightsView {
|
||||
this.options = mixin(this.options, options);
|
||||
}
|
||||
}
|
||||
|
||||
function isValidData(data: IInsightData): boolean {
|
||||
if (types.isUndefinedOrNull(data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (types.isUndefinedOrNull(data.columns)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (types.isUndefinedOrNull(data.rows)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,10 @@ export const chartInsightSchema: IJSONSchema = {
|
||||
default: 'vertical',
|
||||
enum: ['vertical', 'horizontal'],
|
||||
enumDescriptions: ['When vertical, the first column is used to define the x-axis labels, with other columns expected to be numerical.', 'When horizontal, the column names are used as the x-axis labels.']
|
||||
},
|
||||
showTopNData: {
|
||||
type: 'number',
|
||||
description: nls.localize('showTopNData', 'If showTopNData is set, showing only top N data in the chart.')
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -12,7 +12,7 @@ import { chartInsightSchema } from 'sql/parts/dashboard/widgets/insights/views/c
|
||||
|
||||
import BarChart from './barChart.component';
|
||||
|
||||
export const properties: IJSONSchema = {
|
||||
const properties: IJSONSchema = {
|
||||
properties: {
|
||||
yAxisMin: {
|
||||
type: 'number',
|
||||
@@ -41,6 +41,6 @@ export const properties: IJSONSchema = {
|
||||
}
|
||||
};
|
||||
|
||||
const barSchema = mixin(clone(chartInsightSchema), properties) as IJSONSchema;
|
||||
export const barChartSchema = mixin(clone(chartInsightSchema), properties) as IJSONSchema;
|
||||
|
||||
registerInsight('bar', '', barSchema, BarChart);
|
||||
registerInsight('bar', '', barChartSchema, BarChart);
|
||||
|
||||
@@ -7,7 +7,7 @@ import { mixin } from 'vs/base/common/objects';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
|
||||
import { registerInsight } from 'sql/platform/dashboard/common/insightRegistry';
|
||||
import { properties as BarChartSchema } from 'sql/parts/dashboard/widgets/insights/views/charts/types/barChart.contribution';
|
||||
import { barChartSchema } from 'sql/parts/dashboard/widgets/insights/views/charts/types/barChart.contribution';
|
||||
|
||||
import HorizontalBarChart from './horizontalBarChart.component';
|
||||
|
||||
@@ -15,6 +15,6 @@ const properties: IJSONSchema = {
|
||||
|
||||
};
|
||||
|
||||
const horizontalBarSchema = mixin(clone(BarChartSchema), properties) as IJSONSchema;
|
||||
const horizontalBarSchema = mixin(clone(barChartSchema), properties) as IJSONSchema;
|
||||
|
||||
registerInsight('horizontalBar', '', horizontalBarSchema, HorizontalBarChart);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import * as nls from 'vs/nls';
|
||||
|
||||
import { registerInsight } from 'sql/platform/dashboard/common/insightRegistry';
|
||||
import { properties as BarChartSchema } from 'sql/parts/dashboard/widgets/insights/views/charts/types/barChart.contribution';
|
||||
import { barChartSchema } from 'sql/parts/dashboard/widgets/insights/views/charts/types/barChart.contribution';
|
||||
|
||||
import LineChart from './lineChart.component';
|
||||
|
||||
@@ -24,6 +24,6 @@ const properties: IJSONSchema = {
|
||||
}
|
||||
};
|
||||
|
||||
export const lineSchema = mixin(clone(BarChartSchema), properties) as IJSONSchema;
|
||||
export const lineSchema = mixin(clone(barChartSchema), properties) as IJSONSchema;
|
||||
|
||||
registerInsight('line', '', lineSchema, LineChart);
|
||||
|
||||
@@ -7,13 +7,13 @@ import { clone } from 'sql/base/common/objects';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
|
||||
import { registerInsight } from 'sql/platform/dashboard/common/insightRegistry';
|
||||
import { properties as BarChartSchema } from 'sql/parts/dashboard/widgets/insights/views/charts/types/barChart.contribution';
|
||||
import { barChartSchema } from 'sql/parts/dashboard/widgets/insights/views/charts/types/barChart.contribution';
|
||||
|
||||
import ScatterChart from './scatterChart.component';
|
||||
|
||||
const properties: IJSONSchema = {
|
||||
};
|
||||
|
||||
const scatterSchema = mixin(clone(BarChartSchema), properties) as IJSONSchema;
|
||||
const scatterSchema = mixin(clone(barChartSchema), properties) as IJSONSchema;
|
||||
|
||||
registerInsight('scatter', '', scatterSchema, ScatterChart);
|
||||
|
||||
@@ -7,13 +7,13 @@ import { clone } from 'sql/base/common/objects';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
|
||||
import { registerInsight } from 'sql/platform/dashboard/common/insightRegistry';
|
||||
import { properties as BarChartSchema } from 'sql/parts/dashboard/widgets/insights/views/charts/types/barChart.contribution';
|
||||
import { barChartSchema } from 'sql/parts/dashboard/widgets/insights/views/charts/types/barChart.contribution';
|
||||
|
||||
import TimeSeriesChart from './timeSeriesChart.component';
|
||||
|
||||
const properties: IJSONSchema = {
|
||||
};
|
||||
|
||||
const timeSeriesSchema = mixin(clone(BarChartSchema), properties) as IJSONSchema;
|
||||
const timeSeriesSchema = mixin(clone(barChartSchema), properties) as IJSONSchema;
|
||||
|
||||
registerInsight('timeSeries', '', timeSeriesSchema, TimeSeriesChart);
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Component, Inject, forwardRef, ChangeDetectorRef, OnInit, ElementRef, V
|
||||
|
||||
import { DashboardWidget, IDashboardWidget, WidgetConfig, WIDGET_CONFIG } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { ConnectionManagementInfo } from 'sql/parts/connection/common/connectionManagementInfo';
|
||||
import { toDisposableSubscription } from 'sql/parts/common/rxjsUtils';
|
||||
import { error } from 'sql/base/common/log';
|
||||
@@ -68,7 +69,7 @@ export class PropertiesWidgetComponent extends DashboardWidget implements IDashb
|
||||
@ViewChild('parent', { read: ElementRef }) private _parent: ElementRef;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) private _bootstrap: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrap: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
|
||||
@Inject(WIDGET_CONFIG) protected _config: WidgetConfig,
|
||||
|
||||
@@ -12,6 +12,7 @@ import { DomSanitizer } from '@angular/platform-browser';
|
||||
/* SQL imports */
|
||||
import { DashboardWidget, IDashboardWidget, WidgetConfig, WIDGET_CONFIG } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { TaskRegistry } from 'sql/platform/tasks/common/tasks';
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
import { BaseActionContext } from 'sql/workbench/common/actions';
|
||||
@@ -31,6 +32,8 @@ import * as DOM from 'vs/base/browser/dom';
|
||||
import { CommandsRegistry, ICommand } from 'vs/platform/commands/common/commands';
|
||||
import { MenuRegistry, ICommandAction } from 'vs/platform/actions/common/actions';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
|
||||
interface ITask {
|
||||
name: string;
|
||||
@@ -49,13 +52,14 @@ export class TasksWidget extends DashboardWidget implements IDashboardWidget, On
|
||||
private _profile: IConnectionProfile;
|
||||
private _scrollableElement: ScrollableElement;
|
||||
private $container: Builder;
|
||||
static readonly ICON_PATH_TO_CSS_RULES: Map<string /* path*/, string /* CSS rule */> = new Map<string, string>();
|
||||
|
||||
private _inited = false;
|
||||
|
||||
@ViewChild('container', { read: ElementRef }) private _container: ElementRef;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) private _bootstrap: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrap: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => DomSanitizer)) private _sanitizer: DomSanitizer,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeref: ChangeDetectorRef,
|
||||
@Inject(WIDGET_CONFIG) protected _config: WidgetConfig
|
||||
@@ -128,14 +132,22 @@ export class TasksWidget extends DashboardWidget implements IDashboardWidget, On
|
||||
let tile = $('div.task-tile').style('height', this._size + 'px').style('width', this._size + 'px');
|
||||
let innerTile = $('div');
|
||||
|
||||
// @SQLTODO - iconPath shouldn't be used as a CSS class
|
||||
if (action.iconPath && action.iconPath.dark) {
|
||||
let icon = $('span.icon').addClass(action.iconPath.dark);
|
||||
let iconClassName = TaskRegistry.getOrCreateTaskIconClassName(action);
|
||||
if (iconClassName) {
|
||||
let icon = $('span.icon').addClass(iconClassName);
|
||||
innerTile.append(icon);
|
||||
}
|
||||
innerTile.append(label);
|
||||
tile.append(innerTile);
|
||||
tile.attr('tabindex', '0');
|
||||
tile.on(DOM.EventType.CLICK, () => this.runTask(action));
|
||||
tile.on(DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => {
|
||||
let event = new StandardKeyboardEvent(e);
|
||||
if (event.equals(KeyCode.Enter)) {
|
||||
this.runTask(action);
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
});
|
||||
return tile.getHTMLElement();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,8 @@ import { memoize } from 'vs/base/common/decorators';
|
||||
|
||||
import { DashboardWidget, IDashboardWidget, WidgetConfig, WIDGET_CONFIG } from 'sql/parts/dashboard/common/dashboardWidget';
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { IDashboardWebview } from 'sql/services/dashboardWebview/common/dashboardWebviewService';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { IDashboardWebview } from 'sql/services/dashboard/common/dashboardViewService';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
@@ -35,19 +36,21 @@ export class WebviewWidget extends DashboardWidget implements IDashboardWidget,
|
||||
private _onMessage = new Emitter<string>();
|
||||
public readonly onMessage: Event<string> = this._onMessage.event;
|
||||
private _onMessageDisposable: IDisposable;
|
||||
private _dashboardService: DashboardServiceInterface;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => DashboardServiceInterface)) private _dashboardService: DashboardServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private commonService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||
@Inject(WIDGET_CONFIG) protected _config: WidgetConfig,
|
||||
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef
|
||||
) {
|
||||
super();
|
||||
this._id = (_config.widget[selector] as IWebviewWidgetConfig).id;
|
||||
this._dashboardService = commonService as DashboardServiceInterface;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this._dashboardService.dashboardWebviewService.registerWebview(this);
|
||||
this._dashboardService.dashboardViewService.registerWebview(this);
|
||||
this._createWebview();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,24 +8,24 @@
|
||||
<div class="angular-modal-body" style="display: flex; flex-direction: column;">
|
||||
<div class="angular-modal-body-content">
|
||||
<div class="dialog-label">
|
||||
{{backupNameLabel}}
|
||||
{{localizedStrings.BACKUP_NAME}}
|
||||
</div>
|
||||
<div class="input-divider" #backupsetName>
|
||||
</div>
|
||||
<div class="dialog-label">
|
||||
{{recoveryModelLabel}}
|
||||
{{localizedStrings.RECOVERY_MODEL}}
|
||||
</div>
|
||||
<div class="input-divider" #recoveryModelContainer>
|
||||
</div>
|
||||
<div class="dialog-label">
|
||||
{{backupTypeLabel}}
|
||||
{{localizedStrings.BACKUP_TYPE}}
|
||||
</div>
|
||||
<div class="input-divider" #backupTypeContainer>
|
||||
</div>
|
||||
<div class="input-divider check" #copyOnlyContainer>
|
||||
</div>
|
||||
<div class="dialog-label">
|
||||
{{backupDeviceLabel}}
|
||||
{{localizedStrings.BACKUP_DEVICE}}
|
||||
</div>
|
||||
<div class="backup-path-list">
|
||||
<div #pathContainer>
|
||||
@@ -47,11 +47,11 @@
|
||||
<div class="advanced-main-body" #advancedOptionBodyContainer>
|
||||
<!-- Compression -->
|
||||
<div class="dialog-label advanced-header">
|
||||
{{compressionLabel}}
|
||||
{{localizedStrings.COMPRESSION}}
|
||||
</div>
|
||||
<div class="indent">
|
||||
<div class="dialog-label">
|
||||
{{setBackupCompressionLabel}}
|
||||
{{localizedStrings.SET_BACKUP_COMPRESSION}}
|
||||
</div>
|
||||
<div class="dialog-label" #compressionContainer>
|
||||
</div>
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
<!-- Encryption -->
|
||||
<div class="dialog-label advanced-header">
|
||||
{{encryptionLabel}}
|
||||
{{localizedStrings.ENCRYPTION}}
|
||||
</div>
|
||||
<div class="indent">
|
||||
<div class="option check" #encryptCheckContainer>
|
||||
@@ -68,17 +68,17 @@
|
||||
<div class="icon warning">
|
||||
</div>
|
||||
<div class="warning-message">
|
||||
{{noEncryptorWarning}}
|
||||
{{localizedStrings.NO_ENCRYPTOR_WARNING}}
|
||||
</div>
|
||||
</div>
|
||||
<div #encryptContainer>
|
||||
<div class="dialog-label">
|
||||
{{algorithmLabel}}
|
||||
{{localizedStrings.ALGORITHM}}
|
||||
</div>
|
||||
<div class="dialog-label" #algorithmContainer>
|
||||
</div>
|
||||
<div class="dialog-label">
|
||||
{{certificateOrAsymmetricKeyLabel}}
|
||||
{{localizedStrings.CERTIFICATE_OR_ASYMMETRIC_KEY}}
|
||||
</div>
|
||||
<div class="dialog-label" #encryptorContainer>
|
||||
</div>
|
||||
@@ -86,33 +86,33 @@
|
||||
</div>
|
||||
|
||||
<!-- Overwrite media -->
|
||||
<div class="dialog-label advanced-header">
|
||||
{{mediaLabel}}
|
||||
<div id="media" class="dialog-label advanced-header">
|
||||
{{localizedStrings.MEDIA}}
|
||||
</div>
|
||||
<div class="radio-indent">
|
||||
<div role="radiogroup" aria-labelledby="media" class="radio-indent">
|
||||
<div class="option">
|
||||
<input type="radio" name=media-option value="no_format" [checked]="!isFormatChecked" (change)="onChangeMediaFormat()" [disabled]="isEncryptChecked">{{mediaOptionLabel}}
|
||||
<input role="radio" type="radio" name="media-option" value="no_format" [checked]="!isFormatChecked" (change)="onChangeMediaFormat()" [disabled]="isEncryptChecked" aria-labelledby="mediaOption"><span id="mediaOption">{{localizedStrings.MEDIA_OPTION}}</span>
|
||||
</div>
|
||||
<div style="margin-left:15px">
|
||||
<div role="radiogroup" aria-labelledby="mediaOption" style="margin-left:15px">
|
||||
<div class="option">
|
||||
<input type="radio" name=existing-media value="append" [(ngModel)]="selectedInitOption" [disabled]="isFormatChecked">{{existingMediaAppendLabel}}
|
||||
<input role="radio" type="radio" name="existing-media" value="append" [(ngModel)]="selectedInitOption" [disabled]="isFormatChecked" aria-labelledby="existingMediaAppend"><span id="existingMediaAppend">{{localizedStrings.EXISTING_MEDIA_APPEND}}</span>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" name=existing-media value="overwrite" [(ngModel)]="selectedInitOption" [disabled]="isFormatChecked">{{existingMediaOverwriteLabel}}
|
||||
<input role="radio" type="radio" name="existing-media" value="overwrite" [(ngModel)]="selectedInitOption" [disabled]="isFormatChecked" aria-labelledby="existingMediaOverwrite"><span id="existingMediaOverwrite">{{localizedStrings.EXISTING_MEDIA_OVERWRITE}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="option">
|
||||
<input type="radio" name=media-option value="format" [checked]="isFormatChecked" (change)="onChangeMediaFormat()">{{mediaOptionFormatLabel}}
|
||||
<input role="radio" type="radio" name="media-option" value="format" [checked]="isFormatChecked" (change)="onChangeMediaFormat()" aria-labelledby="mediaOptionFormat"><span id="mediaOptionFormat">{{localizedStrings.MEDIA_OPTION_FORMAT}}</span>
|
||||
</div>
|
||||
<div style="margin-left: 22px">
|
||||
<div class="dialog-label">
|
||||
{{newMediaSetNameLabel}}
|
||||
{{localizedStrings.NEW_MEDIA_SET_NAME}}
|
||||
</div>
|
||||
<div class="dialog-label" #mediaName>
|
||||
</div>
|
||||
<div class="dialog-label">
|
||||
{{newMediaSetDescriptionLabel}}
|
||||
{{localizedStrings.NEW_MEDIA_SET_DESCRIPTION}}
|
||||
</div>
|
||||
<div class="dialog-label" #mediaDescription>
|
||||
</div>
|
||||
@@ -120,21 +120,21 @@
|
||||
</div>
|
||||
|
||||
<!-- Transaction log -->
|
||||
<div class="dialog-label advanced-header">
|
||||
{{transactionLogLabel}}
|
||||
<div id="transactionLog" class="dialog-label advanced-header">
|
||||
{{localizedStrings.TRANSACTION_LOG}}
|
||||
</div>
|
||||
<div class="radio-indent">
|
||||
<div role="radiogroup" aria-labelledby="transactionLog" class="radio-indent">
|
||||
<div class="option">
|
||||
<input type="radio" name=t-log value="truncate" [checked]="isTruncateChecked" (change)="onChangeTlog()" [disabled]="disableTlog">Truncate the transaction log
|
||||
<input role="radio" type="radio" name="t-log" value="truncate" [checked]="isTruncateChecked" (change)="onChangeTlog()" [disabled]="disableTlog" aria-labelledby="truncateTransaction"><span id="truncateTransaction">{{localizedStrings.TRUNCATE_TRANSACTION_LOG}}</span>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" name=t-log value="taillog" [checked]="isTaillogChecked" (change)="onChangeTlog()" [disabled]="disableTlog">Backup the tail of the log
|
||||
<input role="radio" type="radio" name="t-log" value="taillog" [checked]="isTaillogChecked" (change)="onChangeTlog()" [disabled]="disableTlog" aria-labelledby="backupTail"><span id="backupTail">{{localizedStrings.BACKUP_TAIL}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reliability -->
|
||||
<div class="dialog-label advanced-header">
|
||||
{{reliabilityLabel}}
|
||||
{{localizedStrings.RELIABILITY}}
|
||||
</div>
|
||||
<div class="indent">
|
||||
<div class="option check" #checksumContainer>
|
||||
@@ -147,11 +147,11 @@
|
||||
|
||||
<!-- Backup expiration -->
|
||||
<div class="dialog-label advanced-header">
|
||||
{{expirationLabel}}
|
||||
{{localizedStrings.EXPIRATION}}
|
||||
</div>
|
||||
<div class="indent">
|
||||
<div class="dialog-label">
|
||||
{{setBackupRetainDaysLabel}}
|
||||
{{localizedStrings.SET_BACKUP_RETAIN_DAYS}}
|
||||
</div>
|
||||
<div class="dialog-label">
|
||||
<div #backupDaysContainer></div>
|
||||
|
||||
@@ -76,6 +76,38 @@ interface MssqlBackupInfo {
|
||||
encryptorName: string;
|
||||
}
|
||||
|
||||
const LocalizedStrings = {
|
||||
BACKUP_NAME: localize('backup.backupName', 'Backup name'),
|
||||
RECOVERY_MODEL: localize('backup.recoveryModel', 'Recovery model'),
|
||||
BACKUP_TYPE: localize('backup.backupType', 'Backup type'),
|
||||
BACKUP_DEVICE: localize('backup.backupDevice', 'Backup files'),
|
||||
ALGORITHM: localize('backup.algorithm', 'Algorithm'),
|
||||
CERTIFICATE_OR_ASYMMETRIC_KEY: localize('backup.certificateOrAsymmetricKey', 'Certificate or Asymmetric key'),
|
||||
MEDIA: localize('backup.media', 'Media'),
|
||||
MEDIA_OPTION: localize('backup.mediaOption', 'Backup to the existing media set'),
|
||||
MEDIA_OPTION_FORMAT: localize('backup.mediaOptionFormat', 'Backup to a new media set'),
|
||||
EXISTING_MEDIA_APPEND: localize('backup.existingMediaAppend', 'Append to the existing backup set'),
|
||||
EXISTING_MEDIA_OVERWRITE: localize('backup.existingMediaOverwrite', 'Overwrite all existing backup sets'),
|
||||
NEW_MEDIA_SET_NAME: localize('backup.newMediaSetName', 'New media set name'),
|
||||
NEW_MEDIA_SET_DESCRIPTION: localize('backup.newMediaSetDescription', 'New media set description'),
|
||||
CHECKSUM_CONTAINER: localize('backup.checksumContainer', 'Perform checksum before writing to media'),
|
||||
VERIFY_CONTAINER: localize('backup.verifyContainer', 'Verify backup when finished'),
|
||||
CONTINUE_ON_ERROR_CONTAINER: localize('backup.continueOnErrorContainer', 'Continue on error'),
|
||||
EXPIRATION: localize('backup.expiration', 'Expiration'),
|
||||
SET_BACKUP_RETAIN_DAYS: localize('backup.setBackupRetainDays', 'Set backup retain days'),
|
||||
COPY_ONLY: localize('backup.copyOnly', 'Copy-only backup'),
|
||||
ADVANCED_CONFIGURATION: localize('backup.advancedConfiguration', 'Advanced Configuration'),
|
||||
COMPRESSION: localize('backup.compression', 'Compression'),
|
||||
SET_BACKUP_COMPRESSION: localize('backup.setBackupCompression', 'Set backup compression'),
|
||||
ENCRYPTION: localize('backup.encryption', 'Encryption'),
|
||||
TRANSACTION_LOG: localize('backup.transactionLog', 'Transaction log'),
|
||||
TRUNCATE_TRANSACTION_LOG: localize('backup.truncateTransactionLog', 'Truncate the transaction log'),
|
||||
BACKUP_TAIL: localize('backup.backupTail', 'Backup the tail of the log'),
|
||||
RELIABILITY: localize('backup.reliability', 'Reliability'),
|
||||
MEDIA_NAME_REQUIRED_ERROR: localize('backup.mediaNameRequired', 'Media name is required'),
|
||||
NO_ENCRYPTOR_WARNING: localize('backup.noEncryptorWarning', "No certificate or asymmetric key is available")
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: BACKUP_SELECTOR,
|
||||
templateUrl: decodeURI(require.toUrl('sql/parts/disasterRecovery/backup/backup.component.html'))
|
||||
@@ -109,36 +141,7 @@ export class BackupComponent {
|
||||
@ViewChild('advancedOptionContainer', { read: ElementRef }) advancedOptionElement;
|
||||
@ViewChild('advancedOptionBodyContainer', { read: ElementRef }) advancedOptionBodyElement;
|
||||
|
||||
// tslint:disable:no-unused-variable
|
||||
private readonly backupNameLabel: string = localize('backup.backupName', 'Backup name');
|
||||
private readonly recoveryModelLabel: string = localize('backup.recoveryModel', 'Recovery model');
|
||||
private readonly backupTypeLabel: string = localize('backup.backupType', 'Backup type');
|
||||
private readonly backupDeviceLabel: string = localize('backup.backupDevice', 'Backup files');
|
||||
private readonly algorithmLabel: string = localize('backup.algorithm', 'Algorithm');
|
||||
private readonly certificateOrAsymmetricKeyLabel: string = localize('backup.certificateOrAsymmetricKey', 'Certificate or Asymmetric key');
|
||||
private readonly mediaLabel: string = localize('backup.media', 'Media');
|
||||
private readonly mediaOptionLabel: string = localize('backup.mediaOption', 'Backup to the existing media set');
|
||||
private readonly mediaOptionFormatLabel: string = localize('backup.mediaOptionFormat', 'Backup to a new media set');
|
||||
private readonly existingMediaAppendLabel: string = localize('backup.existingMediaAppend', 'Append to the existing backup set');
|
||||
private readonly existingMediaOverwriteLabel: string = localize('backup.existingMediaOverwrite', 'Overwrite all existing backup sets');
|
||||
private readonly newMediaSetNameLabel: string = localize('backup.newMediaSetName', 'New media set name');
|
||||
private readonly newMediaSetDescriptionLabel: string = localize('backup.newMediaSetDescription', 'New media set description');
|
||||
private readonly checksumContainerLabel: string = localize('backup.checksumContainer', 'Perform checksum before writing to media');
|
||||
private readonly verifyContainerLabel: string = localize('backup.verifyContainer', 'Verify backup when finished');
|
||||
private readonly continueOnErrorContainerLabel: string = localize('backup.continueOnErrorContainer', 'Continue on error');
|
||||
private readonly expirationLabel: string = localize('backup.expiration', 'Expiration');
|
||||
private readonly setBackupRetainDaysLabel: string = localize('backup.setBackupRetainDays', 'Set backup retain days');
|
||||
private readonly copyOnlyLabel: string = localize('backup.copyOnly', 'Copy-only backup');
|
||||
private readonly advancedConfigurationLabel: string = localize('backup.advancedConfiguration', 'Advanced Configuration');
|
||||
private readonly compressionLabel: string = localize('backup.compression', 'Compression');
|
||||
private readonly setBackupCompressionLabel: string = localize('backup.setBackupCompression', 'Set backup compression');
|
||||
private readonly encryptionLabel: string = localize('backup.encryption', 'Encryption');
|
||||
private readonly transactionLogLabel: string = localize('backup.transactionLog', 'Transaction log');
|
||||
private readonly reliabilityLabel: string = localize('backup.reliability', 'Reliability');
|
||||
private readonly mediaNameRequiredError: string = localize('backup.mediaNameRequired', 'Media name is required');
|
||||
private readonly noEncryptorWarning: string = localize('backup.noEncryptorWarning', "No certificate or asymmetric key is available");
|
||||
|
||||
// tslint:enable:no-unused-variable
|
||||
private localizedStrings = LocalizedStrings;
|
||||
|
||||
private _backupService: IBackupService;
|
||||
private _backupUiService: IBackupUiService;
|
||||
@@ -207,48 +210,58 @@ export class BackupComponent {
|
||||
let self = this;
|
||||
this.addFooterButtons();
|
||||
|
||||
this.recoveryBox = new InputBox(this.recoveryModelElement.nativeElement, this._bootstrapService.contextViewService, { placeholder: this.recoveryModel });
|
||||
this.recoveryBox = new InputBox(this.recoveryModelElement.nativeElement, this._bootstrapService.contextViewService, {
|
||||
placeholder: this.recoveryModel,
|
||||
ariaLabel: LocalizedStrings.RECOVERY_MODEL
|
||||
});
|
||||
// Set backup type
|
||||
this.backupTypeSelectBox = new SelectBox([], '', this._bootstrapService.contextViewService);
|
||||
this.backupTypeSelectBox.render(this.backupTypeElement.nativeElement);
|
||||
|
||||
// Set copy-only check box
|
||||
this.copyOnlyCheckBox = new Checkbox(this.copyOnlyElement.nativeElement, {
|
||||
label: this.copyOnlyLabel,
|
||||
label: LocalizedStrings.COPY_ONLY,
|
||||
checked: false,
|
||||
onChange: (viaKeyboard) => { }
|
||||
onChange: (viaKeyboard) => { },
|
||||
ariaLabel: LocalizedStrings.COPY_ONLY
|
||||
});
|
||||
|
||||
// Encryption checkbox
|
||||
this.encryptCheckBox = new Checkbox(this.encryptElement.nativeElement, {
|
||||
label: this.encryptionLabel,
|
||||
label: LocalizedStrings.ENCRYPTION,
|
||||
checked: false,
|
||||
onChange: (viaKeyboard) => self.onChangeEncrypt()
|
||||
onChange: (viaKeyboard) => self.onChangeEncrypt(),
|
||||
ariaLabel: LocalizedStrings.ENCRYPTION
|
||||
});
|
||||
|
||||
// Verify backup checkbox
|
||||
this.verifyCheckBox = new Checkbox(this.verifyElement.nativeElement, {
|
||||
label: this.verifyContainerLabel,
|
||||
label: LocalizedStrings.VERIFY_CONTAINER,
|
||||
checked: false,
|
||||
onChange: (viaKeyboard) => { }
|
||||
onChange: (viaKeyboard) => { },
|
||||
ariaLabel: LocalizedStrings.VERIFY_CONTAINER
|
||||
});
|
||||
|
||||
// Perform checksum checkbox
|
||||
this.checksumCheckBox = new Checkbox(this.checksumElement.nativeElement, {
|
||||
label: this.checksumContainerLabel,
|
||||
label: LocalizedStrings.CHECKSUM_CONTAINER,
|
||||
checked: false,
|
||||
onChange: (viaKeyboard) => { }
|
||||
onChange: (viaKeyboard) => { },
|
||||
ariaLabel: LocalizedStrings.CHECKSUM_CONTAINER
|
||||
});
|
||||
|
||||
// Continue on error checkbox
|
||||
this.continueOnErrorCheckBox = new Checkbox(this.continueOnErrorElement.nativeElement, {
|
||||
label: this.continueOnErrorContainerLabel,
|
||||
label: LocalizedStrings.CONTINUE_ON_ERROR_CONTAINER,
|
||||
checked: false,
|
||||
onChange: (viaKeyboard) => { }
|
||||
onChange: (viaKeyboard) => { },
|
||||
ariaLabel: LocalizedStrings.CONTINUE_ON_ERROR_CONTAINER
|
||||
});
|
||||
|
||||
// Set backup name
|
||||
this.backupNameBox = new InputBox(this.backupNameElement.nativeElement, this._bootstrapService.contextViewService);
|
||||
this.backupNameBox = new InputBox(this.backupNameElement.nativeElement, this._bootstrapService.contextViewService, {
|
||||
ariaLabel: LocalizedStrings.BACKUP_NAME
|
||||
});
|
||||
|
||||
// Set backup path list
|
||||
this.pathListBox = new ListBox([], '', this._bootstrapService.contextViewService, this._bootstrapService.clipboardService);
|
||||
@@ -278,11 +291,15 @@ export class BackupComponent {
|
||||
this._bootstrapService.contextViewService,
|
||||
{
|
||||
validationOptions: {
|
||||
validation: (value: string) => !value ? ({ type: MessageType.ERROR, content: this.mediaNameRequiredError }) : null
|
||||
}
|
||||
});
|
||||
validation: (value: string) => !value ? ({ type: MessageType.ERROR, content: LocalizedStrings.MEDIA_NAME_REQUIRED_ERROR }) : null
|
||||
},
|
||||
ariaLabel: LocalizedStrings.NEW_MEDIA_SET_NAME
|
||||
}
|
||||
);
|
||||
|
||||
this.mediaDescriptionBox = new InputBox(this.mediaDescriptionElement.nativeElement, this._bootstrapService.contextViewService);
|
||||
this.mediaDescriptionBox = new InputBox(this.mediaDescriptionElement.nativeElement, this._bootstrapService.contextViewService, {
|
||||
ariaLabel: LocalizedStrings.NEW_MEDIA_SET_DESCRIPTION
|
||||
});
|
||||
|
||||
// Set backup retain days
|
||||
let invalidInputMessage = localize('backupComponent.invalidInput', 'Invalid input. Value must be greater than or equal 0.');
|
||||
@@ -300,7 +317,8 @@ export class BackupComponent {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ariaLabel: LocalizedStrings.SET_BACKUP_RETAIN_DAYS
|
||||
});
|
||||
|
||||
// Disable elements
|
||||
@@ -316,7 +334,7 @@ export class BackupComponent {
|
||||
// Set category view for advanced options. This should be defined in ngAfterViewInit so that it correctly calculates the text height after data binding.
|
||||
var splitview = new SplitView(this.advancedOptionElement.nativeElement);
|
||||
var advancedBodySize = DOM.getTotalHeight(this.advancedOptionBodyElement.nativeElement);
|
||||
var categoryView = new CategoryView(this.advancedConfigurationLabel, this.advancedOptionBodyElement.nativeElement, true, advancedBodySize, this._advancedHeaderSize);
|
||||
var categoryView = new CategoryView(LocalizedStrings.ADVANCED_CONFIGURATION, this.advancedOptionBodyElement.nativeElement, true, advancedBodySize, this._advancedHeaderSize);
|
||||
splitview.addView(categoryView);
|
||||
splitview.layout(advancedBodySize + this._advancedHeaderSize);
|
||||
|
||||
@@ -584,7 +602,7 @@ export class BackupComponent {
|
||||
if (strings.isFalsyOrWhitespace(this.mediaNameBox.value)) {
|
||||
this.backupEnabled = false;
|
||||
this.backupButton.enabled = false;
|
||||
this.mediaNameBox.showMessage({ type: MessageType.ERROR, content: this.mediaNameRequiredError });
|
||||
this.mediaNameBox.showMessage({ type: MessageType.ERROR, content: LocalizedStrings.MEDIA_NAME_REQUIRED_ERROR });
|
||||
}
|
||||
} else {
|
||||
this.enableBackupButton();
|
||||
|
||||
@@ -145,23 +145,26 @@ export class BackupUiService implements IBackupUiService {
|
||||
|
||||
let backupOptions = this.getOptions(this._currentProvider);
|
||||
return new TPromise<void>(() => {
|
||||
let uri = this._connectionManagementService.getConnectionId(connection)
|
||||
+ ProviderConnectionInfo.idSeparator
|
||||
+ ConnectionUtils.ConnectionUriBackupIdAttributeName
|
||||
+ ProviderConnectionInfo.nameValueSeparator
|
||||
+ BackupUiService._connectionUniqueId;
|
||||
|
||||
this._connectionUri = uri;
|
||||
|
||||
BackupUiService._connectionUniqueId++;
|
||||
|
||||
// Create connection if needed
|
||||
if (!this._connectionManagementService.isConnected(uri)) {
|
||||
this._connectionManagementService.connect(connection, uri).then(() => {
|
||||
this._onShowBackupEvent.fire({ connection: connection, ownerUri: uri });
|
||||
});
|
||||
}
|
||||
|
||||
if (backupOptions) {
|
||||
(backupDialog as OptionsDialog).open(backupOptions, self._optionValues);
|
||||
} else {
|
||||
let uri = this._connectionManagementService.getConnectionId(connection)
|
||||
+ ProviderConnectionInfo.idSeparator
|
||||
+ ConnectionUtils.ConnectionUriBackupIdAttributeName
|
||||
+ ProviderConnectionInfo.nameValueSeparator
|
||||
+ BackupUiService._connectionUniqueId;
|
||||
|
||||
BackupUiService._connectionUniqueId++;
|
||||
|
||||
// Create connection if needed
|
||||
if (!this._connectionManagementService.isConnected(uri)) {
|
||||
this._connectionManagementService.connect(connection, uri).then(() => {
|
||||
this._onShowBackupEvent.fire({ connection: connection, ownerUri: uri });
|
||||
});
|
||||
}
|
||||
(backupDialog as BackupDialog).open(connection);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ import { MssqlRestoreInfo } from 'sql/parts/disasterRecovery/restore/mssqlRestor
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
import { ProviderConnectionInfo } from 'sql/parts/connection/common/providerConnectionInfo';
|
||||
import * as Utils from 'sql/parts/connection/common/utils';
|
||||
import { IObjectExplorerService } from 'sql/parts/registeredServer/common/objectExplorerService';
|
||||
import { IObjectExplorerService } from 'sql/parts/objectExplorer/common/objectExplorerService';
|
||||
import { ITaskService } from 'sql/parts/taskHistory/common/taskService';
|
||||
import { TaskStatus, TaskNode } from 'sql/parts/taskHistory/common/taskNode';
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user