mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-20 18:46:56 -05:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
088cac030f | ||
|
|
ef29871b62 | ||
|
|
a2a87f8d2b | ||
|
|
83c01c6bcb | ||
|
|
c1d850804c | ||
|
|
6590d5f58a | ||
|
|
bd3c293f94 | ||
|
|
a225925bc4 | ||
|
|
ab39f1f44f | ||
|
|
8d89364d72 | ||
|
|
af2bc859d1 | ||
|
|
8e72fdaa52 | ||
|
|
e9661f90d0 | ||
|
|
30b111034d | ||
|
|
df18359309 | ||
|
|
03857e0afd | ||
|
|
17db0b7d09 | ||
|
|
eaf1e08752 | ||
|
|
d39ceffa94 | ||
|
|
406b171c66 | ||
|
|
6d89b9e203 | ||
|
|
733bb69d25 | ||
|
|
4609694141 | ||
|
|
3be0c5130a | ||
|
|
e50b512580 | ||
|
|
eb62d054de | ||
|
|
e870a309c0 | ||
|
|
3afd3b0ff3 | ||
|
|
e3a2ed95d4 | ||
|
|
20c4f085c8 | ||
|
|
02af7e9299 | ||
|
|
0ae9b36d93 | ||
|
|
2bbb2842e5 |
@@ -658,7 +658,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.1.7",
|
||||
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.1.8.2",
|
||||
"opener": "^1.4.3",
|
||||
"service-downloader": "github:anthonydresser/service-downloader#0.1.2",
|
||||
"vscode-extension-telemetry": "^0.0.15"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
|
||||
"version": "1.4.0-alpha.35",
|
||||
"version": "1.4.0-alpha.45",
|
||||
"downloadFileNames": {
|
||||
"Windows_86": "win-x86-netcoreapp2.1.zip",
|
||||
"Windows_64": "win-x64-netcoreapp2.1.zip",
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
'use strict';
|
||||
|
||||
import { NotificationType, RequestType } from 'vscode-languageclient';
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
import { ITelemetryEventProperties, ITelemetryEventMeasures } from './telemetry';
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
// ------------------------------- < Telemetry Sent Event > ------------------------------------
|
||||
|
||||
@@ -31,50 +30,207 @@ export class TelemetryParams {
|
||||
|
||||
// ------------------------------- </ Telemetry Sent Event > ----------------------------------
|
||||
|
||||
|
||||
// Job Management types
|
||||
// ------------------------------- < Agent Management > ------------------------------------
|
||||
// Job management parameters
|
||||
export interface AgentJobsParams {
|
||||
ownerUri: string;
|
||||
jobId: string;
|
||||
}
|
||||
|
||||
export interface AgentJobsResult {
|
||||
succeeded: boolean;
|
||||
errorMessage: string;
|
||||
jobs: sqlops.AgentJobInfo[];
|
||||
}
|
||||
|
||||
export interface AgentJobHistoryParams {
|
||||
ownerUri: string;
|
||||
jobId: string;
|
||||
}
|
||||
|
||||
export interface AgentJobHistoryResult {
|
||||
succeeded: boolean;
|
||||
errorMessage: string;
|
||||
jobs: sqlops.AgentJobHistoryInfo[];
|
||||
}
|
||||
|
||||
export interface AgentJobActionParams {
|
||||
ownerUri: string;
|
||||
jobName: string;
|
||||
action: string;
|
||||
}
|
||||
|
||||
export interface AgentJobActionResult {
|
||||
succeeded: boolean;
|
||||
errorMessage: string;
|
||||
export interface CreateAgentJobParams {
|
||||
ownerUri: string;
|
||||
job: sqlops.AgentJobInfo;
|
||||
}
|
||||
|
||||
export interface UpdateAgentJobParams {
|
||||
ownerUri: string;
|
||||
originalJobName: string;
|
||||
job: sqlops.AgentJobInfo;
|
||||
}
|
||||
|
||||
export interface DeleteAgentJobParams {
|
||||
ownerUri: string;
|
||||
job: sqlops.AgentJobInfo;
|
||||
}
|
||||
|
||||
// Job Step management parameters
|
||||
export interface CreateAgentJobStepParams {
|
||||
ownerUri: string;
|
||||
step: sqlops.AgentJobStepInfo;
|
||||
}
|
||||
|
||||
export interface UpdateAgentJobStepParams {
|
||||
ownerUri: string;
|
||||
originalJobStepName: string;
|
||||
step: sqlops.AgentJobStepInfo;
|
||||
}
|
||||
|
||||
export interface DeleteAgentJobStepParams {
|
||||
ownerUri: string;
|
||||
step: sqlops.AgentJobStepInfo;
|
||||
}
|
||||
|
||||
// Alert management parameters
|
||||
export interface AgentAlertsParams {
|
||||
ownerUri: string;
|
||||
}
|
||||
|
||||
export interface CreateAgentAlertParams {
|
||||
ownerUri: string;
|
||||
alert: sqlops.AgentAlertInfo;
|
||||
}
|
||||
|
||||
export interface UpdateAgentAlertParams {
|
||||
ownerUri: string;
|
||||
originalAlertName: string;
|
||||
alert: sqlops.AgentAlertInfo;
|
||||
}
|
||||
|
||||
export interface DeleteAgentAlertParams {
|
||||
ownerUri: string;
|
||||
alert: sqlops.AgentAlertInfo;
|
||||
}
|
||||
|
||||
// Operator management parameters
|
||||
export interface AgentOperatorsParams {
|
||||
ownerUri: string;
|
||||
}
|
||||
|
||||
export interface CreateAgentOperatorParams {
|
||||
ownerUri: string;
|
||||
operator: sqlops.AgentOperatorInfo;
|
||||
}
|
||||
|
||||
export interface UpdateAgentOperatorParams {
|
||||
ownerUri: string;
|
||||
originalOperatorName: string;
|
||||
operator: sqlops.AgentOperatorInfo;
|
||||
}
|
||||
|
||||
export interface DeleteAgentOperatorParams {
|
||||
ownerUri: string;
|
||||
operator: sqlops.AgentOperatorInfo;
|
||||
}
|
||||
|
||||
// Proxy management parameters
|
||||
export interface AgentProxiesParams {
|
||||
ownerUri: string;
|
||||
}
|
||||
|
||||
export interface CreateAgentProxyParams {
|
||||
ownerUri: string;
|
||||
proxy: sqlops.AgentProxyInfo;
|
||||
}
|
||||
|
||||
export interface UpdateAgentProxyParams {
|
||||
ownerUri: string;
|
||||
originalProxyName: string;
|
||||
proxy: sqlops.AgentProxyInfo;
|
||||
}
|
||||
|
||||
export interface DeleteAgentProxyParams {
|
||||
ownerUri: string;
|
||||
proxy: sqlops.AgentProxyInfo;
|
||||
}
|
||||
|
||||
// Agent Job management requests
|
||||
export namespace AgentJobsRequest {
|
||||
export const type = new RequestType<AgentJobsParams, AgentJobsResult, void, void>('agent/jobs');
|
||||
export const type = new RequestType<AgentJobsParams, sqlops.AgentJobsResult, void, void>('agent/jobs');
|
||||
}
|
||||
|
||||
export namespace AgentJobHistoryRequest {
|
||||
export const type = new RequestType<AgentJobHistoryParams, AgentJobHistoryResult, void, void>('agent/jobhistory');
|
||||
export const type = new RequestType<AgentJobHistoryParams, sqlops.AgentJobHistoryResult, void, void>('agent/jobhistory');
|
||||
}
|
||||
|
||||
|
||||
export namespace AgentJobActionRequest {
|
||||
export const type = new RequestType<AgentJobActionParams, AgentJobActionResult, void, void>('agent/jobaction');
|
||||
export const type = new RequestType<AgentJobActionParams, sqlops.ResultStatus, void, void>('agent/jobaction');
|
||||
}
|
||||
|
||||
export namespace CreateAgentJobRequest {
|
||||
export const type = new RequestType<CreateAgentJobParams, sqlops.CreateAgentJobResult, void, void>('agent/createjob');
|
||||
}
|
||||
|
||||
export namespace UpdateAgentJobRequest {
|
||||
export const type = new RequestType<UpdateAgentJobParams, sqlops.UpdateAgentJobResult, void, void>('agent/updatejob');
|
||||
}
|
||||
|
||||
export namespace DeleteAgentJobRequest {
|
||||
export const type = new RequestType<DeleteAgentJobParams, sqlops.ResultStatus, void, void>('agent/deletejob');
|
||||
}
|
||||
|
||||
// Job Step requests
|
||||
export namespace CreateAgentJobStepRequest {
|
||||
export const type = new RequestType<CreateAgentJobStepParams, sqlops.CreateAgentJobStepResult, void, void>('agent/createjobstep');
|
||||
}
|
||||
|
||||
export namespace UpdateAgentJobStepRequest {
|
||||
export const type = new RequestType<UpdateAgentJobStepParams, sqlops.UpdateAgentJobStepResult, void, void>('agent/updatejobstep');
|
||||
}
|
||||
|
||||
export namespace DeleteAgentJobStepRequest {
|
||||
export const type = new RequestType<DeleteAgentJobStepParams, sqlops.ResultStatus, void, void>('agent/deletejobstep');
|
||||
}
|
||||
|
||||
// Alerts requests
|
||||
export namespace AgentAlertsRequest {
|
||||
export const type = new RequestType<CreateAgentAlertParams, sqlops.AgentAlertsResult, void, void>('agent/alerts');
|
||||
}
|
||||
|
||||
export namespace CreateAgentAlertRequest {
|
||||
export const type = new RequestType<CreateAgentAlertParams, sqlops.CreateAgentAlertResult, void, void>('agent/createalert');
|
||||
}
|
||||
|
||||
export namespace UpdateAgentAlertRequest {
|
||||
export const type = new RequestType<UpdateAgentAlertParams, sqlops.UpdateAgentAlertResult, void, void>('agent/updatealert');
|
||||
}
|
||||
|
||||
export namespace DeleteAgentAlertRequest {
|
||||
export const type = new RequestType<DeleteAgentAlertParams, sqlops.ResultStatus, void, void>('agent/deletealert');
|
||||
}
|
||||
|
||||
// Operators requests
|
||||
export namespace AgentOperatorsRequest {
|
||||
export const type = new RequestType<CreateAgentOperatorParams, sqlops.AgentOperatorsResult, void, void>('agent/operators');
|
||||
}
|
||||
|
||||
export namespace CreateAgentOperatorRequest {
|
||||
export const type = new RequestType<CreateAgentOperatorParams, sqlops.CreateAgentOperatorResult, void, void>('agent/createoperator');
|
||||
}
|
||||
|
||||
export namespace UpdateAgentOperatorRequest {
|
||||
export const type = new RequestType<UpdateAgentOperatorParams, sqlops.UpdateAgentOperatorResult, void, void>('agent/updateoperator');
|
||||
}
|
||||
|
||||
export namespace DeleteAgentOperatorRequest {
|
||||
export const type = new RequestType<DeleteAgentOperatorParams, sqlops.ResultStatus, void, void>('agent/deleteoperator');
|
||||
}
|
||||
|
||||
// Proxies requests
|
||||
export namespace AgentProxiesRequest {
|
||||
export const type = new RequestType<CreateAgentProxyParams, sqlops.AgentProxiesResult, void, void>('agent/proxies');
|
||||
}
|
||||
|
||||
export namespace CreateAgentProxyRequest {
|
||||
export const type = new RequestType<CreateAgentProxyParams, sqlops.CreateAgentProxyResult, void, void>('agent/createproxy');
|
||||
}
|
||||
|
||||
export namespace UpdateAgentProxyRequest {
|
||||
export const type = new RequestType<UpdateAgentProxyParams, sqlops.UpdateAgentProxyResult, void, void>('agent/updateproxy');
|
||||
}
|
||||
|
||||
export namespace DeleteAgentProxyRequest {
|
||||
export const type = new RequestType<DeleteAgentProxyParams, sqlops.ResultStatus, void, void>('agent/deleteproxy');
|
||||
}
|
||||
|
||||
// ------------------------------- < Agent Management > ------------------------------------
|
||||
|
||||
@@ -6,13 +6,12 @@
|
||||
|
||||
import { SqlOpsDataClient, SqlOpsFeature } from 'dataprotocol-client';
|
||||
import { ClientCapabilities, StaticFeature, RPCMessageType, ServerCapabilities } from 'vscode-languageclient';
|
||||
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
|
||||
import { Disposable } from 'vscode';
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
import { Telemetry } from './telemetry';
|
||||
import * as contracts from './contracts';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as Utils from './utils';
|
||||
import { TelemetryNotification, AgentJobsRequest, AgentJobActionRequest, AgentJobHistoryRequest, AgentJobsParams, AgentJobHistoryParams, AgentJobActionParams } from './contracts';
|
||||
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
|
||||
|
||||
export class TelemetryFeature implements StaticFeature {
|
||||
|
||||
@@ -23,7 +22,7 @@ export class TelemetryFeature implements StaticFeature {
|
||||
}
|
||||
|
||||
initialize(): void {
|
||||
this._client.onNotification(TelemetryNotification.type, e => {
|
||||
this._client.onNotification(contracts.TelemetryNotification.type, e => {
|
||||
Telemetry.sendTelemetryEvent(e.params.eventName, e.params.properties, e.params.measures);
|
||||
});
|
||||
}
|
||||
@@ -31,9 +30,9 @@ export class TelemetryFeature implements StaticFeature {
|
||||
|
||||
export class AgentServicesFeature extends SqlOpsFeature<undefined> {
|
||||
private static readonly messagesTypes: RPCMessageType[] = [
|
||||
AgentJobsRequest.type,
|
||||
AgentJobHistoryRequest.type,
|
||||
AgentJobActionRequest.type
|
||||
contracts.AgentJobsRequest.type,
|
||||
contracts.AgentJobHistoryRequest.type,
|
||||
contracts.AgentJobActionRequest.type
|
||||
];
|
||||
|
||||
constructor(client: SqlOpsDataClient) {
|
||||
@@ -55,35 +54,312 @@ export class AgentServicesFeature extends SqlOpsFeature<undefined> {
|
||||
protected registerProvider(options: undefined): Disposable {
|
||||
const client = this._client;
|
||||
|
||||
// Job management methods
|
||||
let getJobs = (ownerUri: string): Thenable<sqlops.AgentJobsResult> => {
|
||||
let params: AgentJobsParams = { ownerUri: ownerUri, jobId: null };
|
||||
return client.sendRequest(AgentJobsRequest.type, params).then(
|
||||
let params: contracts.AgentJobsParams = { ownerUri: ownerUri, jobId: null };
|
||||
return client.sendRequest(contracts.AgentJobsRequest.type, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(AgentJobsRequest.type, e);
|
||||
client.logFailedRequest(contracts.AgentJobsRequest.type, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let getJobHistory = (connectionUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult> => {
|
||||
let params: AgentJobHistoryParams = { ownerUri: connectionUri, jobId: jobID };
|
||||
let getJobHistory = (ownerUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult> => {
|
||||
let params: contracts.AgentJobHistoryParams = { ownerUri: ownerUri, jobId: jobID };
|
||||
|
||||
return client.sendRequest(AgentJobHistoryRequest.type, params).then(
|
||||
return client.sendRequest(contracts.AgentJobHistoryRequest.type, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(AgentJobHistoryRequest.type, e);
|
||||
client.logFailedRequest(contracts.AgentJobHistoryRequest.type, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let jobAction = (connectionUri: string, jobName: string, action: string): Thenable<sqlops.AgentJobActionResult> => {
|
||||
let params: AgentJobActionParams = { ownerUri: connectionUri, jobName: jobName, action: action };
|
||||
return client.sendRequest(AgentJobActionRequest.type, params).then(
|
||||
let jobAction = (ownerUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus> => {
|
||||
let params: contracts.AgentJobActionParams = { ownerUri: ownerUri, jobName: jobName, action: action };
|
||||
return client.sendRequest(contracts.AgentJobActionRequest.type, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(AgentJobActionRequest.type, e);
|
||||
client.logFailedRequest(contracts.AgentJobActionRequest.type, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let createJob = (ownerUri: string, jobInfo: sqlops.AgentJobInfo): Thenable<sqlops.CreateAgentJobResult> => {
|
||||
let params: contracts.CreateAgentJobParams = {
|
||||
ownerUri: ownerUri,
|
||||
job: jobInfo
|
||||
};
|
||||
let requestType = contracts.CreateAgentJobRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let updateJob = (ownerUri: string, originalJobName: string, jobInfo: sqlops.AgentJobInfo): Thenable<sqlops.UpdateAgentJobResult> => {
|
||||
let params: contracts.UpdateAgentJobParams = {
|
||||
ownerUri: ownerUri,
|
||||
originalJobName: originalJobName,
|
||||
job: jobInfo
|
||||
};
|
||||
let requestType = contracts.UpdateAgentJobRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let deleteJob = (ownerUri: string, jobInfo: sqlops.AgentJobInfo): Thenable<sqlops.ResultStatus> => {
|
||||
let params: contracts.DeleteAgentJobParams = {
|
||||
ownerUri: ownerUri,
|
||||
job: jobInfo
|
||||
};
|
||||
let requestType = contracts.DeleteAgentJobRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// Job Step management methods
|
||||
let createJobStep = (ownerUri: string, stepInfo: sqlops.AgentJobStepInfo): Thenable<sqlops.CreateAgentJobStepResult> => {
|
||||
let params: contracts.CreateAgentJobStepParams = {
|
||||
ownerUri: ownerUri,
|
||||
step: stepInfo
|
||||
};
|
||||
let requestType = contracts.CreateAgentJobStepRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let updateJobStep = (ownerUri: string, originalJobStepName: string, stepInfo: sqlops.AgentJobStepInfo): Thenable<sqlops.UpdateAgentJobStepResult> => {
|
||||
let params: contracts.UpdateAgentJobStepParams = {
|
||||
ownerUri: ownerUri,
|
||||
originalJobStepName: originalJobStepName,
|
||||
step: stepInfo
|
||||
};
|
||||
let requestType = contracts.UpdateAgentJobStepRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let deleteJobStep = (ownerUri: string, stepInfo: sqlops.AgentJobStepInfo): Thenable<sqlops.ResultStatus> => {
|
||||
let params: contracts.DeleteAgentJobStepParams = {
|
||||
ownerUri: ownerUri,
|
||||
step: stepInfo
|
||||
};
|
||||
let requestType = contracts.DeleteAgentJobStepRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// Alert management methods
|
||||
let getAlerts = (ownerUri: string): Thenable<sqlops.AgentAlertsResult> => {
|
||||
let params: contracts.AgentAlertsParams = {
|
||||
ownerUri: ownerUri
|
||||
};
|
||||
let requestType = contracts.AgentAlertsRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let createAlert = (ownerUri: string, alertInfo: sqlops.AgentAlertInfo): Thenable<sqlops.CreateAgentAlertResult> => {
|
||||
let params: contracts.CreateAgentAlertParams = {
|
||||
ownerUri: ownerUri,
|
||||
alert: alertInfo
|
||||
};
|
||||
let requestType = contracts.CreateAgentAlertRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let updateAlert = (ownerUri: string, originalAlertName: string, alertInfo: sqlops.AgentAlertInfo): Thenable<sqlops.UpdateAgentAlertResult> => {
|
||||
let params: contracts.UpdateAgentAlertParams = {
|
||||
ownerUri: ownerUri,
|
||||
originalAlertName: originalAlertName,
|
||||
alert: alertInfo
|
||||
};
|
||||
let requestType = contracts.UpdateAgentAlertRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let deleteAlert = (ownerUri: string, alertInfo: sqlops.AgentAlertInfo): Thenable<sqlops.ResultStatus> => {
|
||||
let params: contracts.DeleteAgentAlertParams = {
|
||||
ownerUri: ownerUri,
|
||||
alert: alertInfo
|
||||
};
|
||||
let requestType = contracts.DeleteAgentAlertRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// Operator management methods
|
||||
let getOperators = (ownerUri: string): Thenable<sqlops.AgentOperatorsResult> => {
|
||||
let params: contracts.AgentOperatorsParams = {
|
||||
ownerUri: ownerUri
|
||||
};
|
||||
let requestType = contracts.AgentOperatorsRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let createOperator = (ownerUri: string, operatorInfo: sqlops.AgentOperatorInfo): Thenable<sqlops.CreateAgentOperatorResult> => {
|
||||
let params: contracts.CreateAgentOperatorParams = {
|
||||
ownerUri: ownerUri,
|
||||
operator: operatorInfo
|
||||
};
|
||||
let requestType = contracts.CreateAgentOperatorRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let updateOperator = (ownerUri: string, originalOperatorName: string, operatorInfo: sqlops.AgentOperatorInfo): Thenable<sqlops.UpdateAgentOperatorResult> => {
|
||||
let params: contracts.UpdateAgentOperatorParams = {
|
||||
ownerUri: ownerUri,
|
||||
originalOperatorName: originalOperatorName,
|
||||
operator: operatorInfo
|
||||
};
|
||||
let requestType = contracts.UpdateAgentOperatorRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let deleteOperator = (ownerUri: string, operatorInfo: sqlops.AgentOperatorInfo): Thenable<sqlops.ResultStatus> => {
|
||||
let params: contracts.DeleteAgentOperatorParams = {
|
||||
ownerUri: ownerUri,
|
||||
operator: operatorInfo
|
||||
};
|
||||
let requestType = contracts.DeleteAgentOperatorRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// Proxy management methods
|
||||
let getProxies = (ownerUri: string): Thenable<sqlops.AgentProxiesResult> => {
|
||||
let params: contracts.AgentProxiesParams = {
|
||||
ownerUri: ownerUri
|
||||
};
|
||||
let requestType = contracts.AgentProxiesRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let createProxy = (ownerUri: string, proxyInfo: sqlops.AgentProxyInfo): Thenable<sqlops.CreateAgentOperatorResult> => {
|
||||
let params: contracts.CreateAgentProxyParams = {
|
||||
ownerUri: ownerUri,
|
||||
proxy: proxyInfo
|
||||
};
|
||||
let requestType = contracts.CreateAgentProxyRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let updateProxy = (ownerUri: string, originalProxyName: string, proxyInfo: sqlops.AgentProxyInfo): Thenable<sqlops.UpdateAgentOperatorResult> => {
|
||||
let params: contracts.UpdateAgentProxyParams = {
|
||||
ownerUri: ownerUri,
|
||||
originalProxyName: originalProxyName,
|
||||
proxy: proxyInfo
|
||||
};
|
||||
let requestType = contracts.UpdateAgentProxyRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let deleteProxy = (ownerUri: string, proxyInfo: sqlops.AgentProxyInfo): Thenable<sqlops.ResultStatus> => {
|
||||
let params: contracts.DeleteAgentProxyParams = {
|
||||
ownerUri: ownerUri,
|
||||
proxy: proxyInfo
|
||||
};
|
||||
let requestType = contracts.DeleteAgentProxyRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
@@ -93,7 +369,25 @@ export class AgentServicesFeature extends SqlOpsFeature<undefined> {
|
||||
providerId: client.providerId,
|
||||
getJobs,
|
||||
getJobHistory,
|
||||
jobAction
|
||||
jobAction,
|
||||
createJob,
|
||||
updateJob,
|
||||
deleteJob,
|
||||
createJobStep,
|
||||
updateJobStep,
|
||||
deleteJobStep,
|
||||
getAlerts,
|
||||
createAlert,
|
||||
updateAlert,
|
||||
deleteAlert,
|
||||
getOperators,
|
||||
createOperator,
|
||||
updateOperator,
|
||||
deleteOperator,
|
||||
getProxies,
|
||||
createProxy,
|
||||
updateProxy,
|
||||
deleteProxy
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,396 +1,396 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
agent-base@4, agent-base@^4.1.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.0.tgz#9838b5c3392b962bad031e6a4c5e1024abec45ce"
|
||||
dependencies:
|
||||
es6-promisify "^5.0.0"
|
||||
|
||||
applicationinsights@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.1.tgz#53446b830fe8d5d619eee2a278b31d3d25030927"
|
||||
dependencies:
|
||||
diagnostic-channel "0.2.0"
|
||||
diagnostic-channel-publishers "0.2.1"
|
||||
zone.js "0.7.6"
|
||||
|
||||
base64-js@0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978"
|
||||
|
||||
bl@^1.0.0:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c"
|
||||
dependencies:
|
||||
readable-stream "^2.3.5"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
buffer-crc32@~0.2.3:
|
||||
version "0.2.13"
|
||||
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
||||
|
||||
buffer@^3.0.1:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-3.6.0.tgz#a72c936f77b96bf52f5f7e7b467180628551defb"
|
||||
dependencies:
|
||||
base64-js "0.0.8"
|
||||
ieee754 "^1.1.4"
|
||||
isarray "^1.0.0"
|
||||
|
||||
commander@~2.8.1:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4"
|
||||
dependencies:
|
||||
graceful-readlink ">= 1.0.0"
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
|
||||
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#0.1.7":
|
||||
version "0.1.7"
|
||||
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/d50285b03d0d5073c086362c5c96afb279320607"
|
||||
dependencies:
|
||||
vscode-languageclient "3.5.0"
|
||||
|
||||
debug@3.1.0, debug@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1"
|
||||
dependencies:
|
||||
file-type "^5.2.0"
|
||||
is-stream "^1.1.0"
|
||||
tar-stream "^1.5.2"
|
||||
|
||||
decompress-tarbz2@^4.0.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b"
|
||||
dependencies:
|
||||
decompress-tar "^4.1.0"
|
||||
file-type "^6.1.0"
|
||||
is-stream "^1.1.0"
|
||||
seek-bzip "^1.0.5"
|
||||
unbzip2-stream "^1.0.9"
|
||||
|
||||
decompress-targz@^4.0.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee"
|
||||
dependencies:
|
||||
decompress-tar "^4.1.1"
|
||||
file-type "^5.2.0"
|
||||
is-stream "^1.1.0"
|
||||
|
||||
decompress-unzip@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69"
|
||||
dependencies:
|
||||
file-type "^3.8.0"
|
||||
get-stream "^2.2.0"
|
||||
pify "^2.3.0"
|
||||
yauzl "^2.4.2"
|
||||
|
||||
decompress@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.0.tgz#7aedd85427e5a92dacfe55674a7c505e96d01f9d"
|
||||
dependencies:
|
||||
decompress-tar "^4.0.0"
|
||||
decompress-tarbz2 "^4.0.0"
|
||||
decompress-targz "^4.0.0"
|
||||
decompress-unzip "^4.0.1"
|
||||
graceful-fs "^4.1.10"
|
||||
make-dir "^1.0.0"
|
||||
pify "^2.3.0"
|
||||
strip-dirs "^2.0.0"
|
||||
|
||||
diagnostic-channel-publishers@0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3"
|
||||
|
||||
diagnostic-channel@0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17"
|
||||
dependencies:
|
||||
semver "^5.3.0"
|
||||
|
||||
end-of-stream@^1.0.0:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
|
||||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
es6-promise@^4.0.3:
|
||||
version "4.2.4"
|
||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29"
|
||||
|
||||
es6-promisify@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
|
||||
dependencies:
|
||||
es6-promise "^4.0.3"
|
||||
|
||||
eventemitter2@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-5.0.1.tgz#6197a095d5fb6b57e8942f6fd7eaad63a09c9452"
|
||||
|
||||
fd-slicer@~1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65"
|
||||
dependencies:
|
||||
pend "~1.2.0"
|
||||
|
||||
file-type@^3.8.0:
|
||||
version "3.9.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9"
|
||||
|
||||
file-type@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6"
|
||||
|
||||
file-type@^6.1.0:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919"
|
||||
|
||||
get-stream@^2.2.0:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de"
|
||||
dependencies:
|
||||
object-assign "^4.0.1"
|
||||
pinkie-promise "^2.0.0"
|
||||
|
||||
graceful-fs@^4.1.10:
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
|
||||
|
||||
"graceful-readlink@>= 1.0.0":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
||||
|
||||
http-proxy-agent@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
|
||||
dependencies:
|
||||
agent-base "4"
|
||||
debug "3.1.0"
|
||||
|
||||
https-proxy-agent@^2.1.1:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.0.tgz#7fbba856be8cd677986f42ebd3664f6317257887"
|
||||
dependencies:
|
||||
agent-base "^4.1.0"
|
||||
debug "^3.1.0"
|
||||
|
||||
ieee754@^1.1.4:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.11.tgz#c16384ffe00f5b7835824e67b6f2bd44a5229455"
|
||||
|
||||
inherits@~2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
|
||||
is-natural-number@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8"
|
||||
|
||||
is-stream@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
|
||||
isarray@^1.0.0, isarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
|
||||
make-dir@^1.0.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b"
|
||||
dependencies:
|
||||
pify "^3.0.0"
|
||||
|
||||
minimist@0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
||||
|
||||
mkdirp@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||
dependencies:
|
||||
minimist "0.0.8"
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
|
||||
object-assign@^4.0.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
|
||||
once@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
opener@^1.4.3:
|
||||
version "1.4.3"
|
||||
resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8"
|
||||
|
||||
os-tmpdir@~1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
||||
|
||||
pend@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||
|
||||
pify@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
||||
|
||||
pify@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
|
||||
|
||||
pinkie-promise@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
|
||||
dependencies:
|
||||
pinkie "^2.0.0"
|
||||
|
||||
pinkie@^2.0.0:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
|
||||
|
||||
readable-stream@^2.0.0, readable-stream@^2.3.5:
|
||||
version "2.3.5"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.5.tgz#b4f85003a938cbb6ecbce2a124fb1012bd1a838d"
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.3"
|
||||
isarray "~1.0.0"
|
||||
process-nextick-args "~2.0.0"
|
||||
safe-buffer "~5.1.1"
|
||||
string_decoder "~1.0.3"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
|
||||
|
||||
seek-bzip@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc"
|
||||
dependencies:
|
||||
commander "~2.8.1"
|
||||
|
||||
semver@^5.3.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
||||
|
||||
"service-downloader@github:anthonydresser/service-downloader#0.1.2":
|
||||
version "0.1.2"
|
||||
resolved "https://codeload.github.com/anthonydresser/service-downloader/tar.gz/2aa9b336b6442e17e24693ddc907030575539798"
|
||||
dependencies:
|
||||
decompress "^4.2.0"
|
||||
eventemitter2 "^5.0.1"
|
||||
http-proxy-agent "^2.0.0"
|
||||
https-proxy-agent "^2.1.1"
|
||||
mkdirp "^0.5.1"
|
||||
tmp "^0.0.33"
|
||||
|
||||
string_decoder@~1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab"
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
strip-dirs@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5"
|
||||
dependencies:
|
||||
is-natural-number "^4.0.1"
|
||||
|
||||
tar-stream@^1.5.2:
|
||||
version "1.5.5"
|
||||
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.5.5.tgz#5cad84779f45c83b1f2508d96b09d88c7218af55"
|
||||
dependencies:
|
||||
bl "^1.0.0"
|
||||
end-of-stream "^1.0.0"
|
||||
readable-stream "^2.0.0"
|
||||
xtend "^4.0.0"
|
||||
|
||||
through@^2.3.6:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||
|
||||
tmp@^0.0.33:
|
||||
version "0.0.33"
|
||||
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
|
||||
dependencies:
|
||||
os-tmpdir "~1.0.2"
|
||||
|
||||
unbzip2-stream@^1.0.9:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz#73a033a567bbbde59654b193c44d48a7e4f43c47"
|
||||
dependencies:
|
||||
buffer "^3.0.1"
|
||||
through "^2.3.6"
|
||||
|
||||
util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
|
||||
vscode-extension-telemetry@^0.0.15:
|
||||
version "0.0.15"
|
||||
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.15.tgz#685c32f3b67e8fb85ba689c1d7f88ff90ff87856"
|
||||
dependencies:
|
||||
applicationinsights "1.0.1"
|
||||
|
||||
vscode-jsonrpc@3.5.0, vscode-jsonrpc@^3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0.tgz#87239d9e166b2d7352245b8a813597804c1d63aa"
|
||||
|
||||
vscode-languageclient@3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-3.5.0.tgz#36d02cc186a8365a4467719a290fb200a9ae490a"
|
||||
dependencies:
|
||||
vscode-languageserver-protocol "^3.5.0"
|
||||
|
||||
vscode-languageserver-protocol@3.5.0, vscode-languageserver-protocol@^3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0.tgz#067c5cbe27709795398d119692c97ebba1452209"
|
||||
dependencies:
|
||||
vscode-jsonrpc "^3.5.0"
|
||||
vscode-languageserver-types "^3.5.0"
|
||||
|
||||
vscode-languageserver-types@3.5.0, vscode-languageserver-types@^3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz#e48d79962f0b8e02de955e3f524908e2b19c0374"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
|
||||
xtend@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
||||
|
||||
yauzl@^2.4.2:
|
||||
version "2.9.1"
|
||||
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.1.tgz#a81981ea70a57946133883f029c5821a89359a7f"
|
||||
dependencies:
|
||||
buffer-crc32 "~0.2.3"
|
||||
fd-slicer "~1.0.1"
|
||||
|
||||
zone.js@0.7.6:
|
||||
version "0.7.6"
|
||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009"
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
agent-base@4, agent-base@^4.1.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.0.tgz#9838b5c3392b962bad031e6a4c5e1024abec45ce"
|
||||
dependencies:
|
||||
es6-promisify "^5.0.0"
|
||||
|
||||
applicationinsights@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.1.tgz#53446b830fe8d5d619eee2a278b31d3d25030927"
|
||||
dependencies:
|
||||
diagnostic-channel "0.2.0"
|
||||
diagnostic-channel-publishers "0.2.1"
|
||||
zone.js "0.7.6"
|
||||
|
||||
base64-js@0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978"
|
||||
|
||||
bl@^1.0.0:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c"
|
||||
dependencies:
|
||||
readable-stream "^2.3.5"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
buffer-crc32@~0.2.3:
|
||||
version "0.2.13"
|
||||
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
||||
|
||||
buffer@^3.0.1:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-3.6.0.tgz#a72c936f77b96bf52f5f7e7b467180628551defb"
|
||||
dependencies:
|
||||
base64-js "0.0.8"
|
||||
ieee754 "^1.1.4"
|
||||
isarray "^1.0.0"
|
||||
|
||||
commander@~2.8.1:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4"
|
||||
dependencies:
|
||||
graceful-readlink ">= 1.0.0"
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
|
||||
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#0.1.7":
|
||||
version "0.1.7"
|
||||
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/d50285b03d0d5073c086362c5c96afb279320607"
|
||||
dependencies:
|
||||
vscode-languageclient "3.5.0"
|
||||
|
||||
debug@3.1.0, debug@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1"
|
||||
dependencies:
|
||||
file-type "^5.2.0"
|
||||
is-stream "^1.1.0"
|
||||
tar-stream "^1.5.2"
|
||||
|
||||
decompress-tarbz2@^4.0.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b"
|
||||
dependencies:
|
||||
decompress-tar "^4.1.0"
|
||||
file-type "^6.1.0"
|
||||
is-stream "^1.1.0"
|
||||
seek-bzip "^1.0.5"
|
||||
unbzip2-stream "^1.0.9"
|
||||
|
||||
decompress-targz@^4.0.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee"
|
||||
dependencies:
|
||||
decompress-tar "^4.1.1"
|
||||
file-type "^5.2.0"
|
||||
is-stream "^1.1.0"
|
||||
|
||||
decompress-unzip@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69"
|
||||
dependencies:
|
||||
file-type "^3.8.0"
|
||||
get-stream "^2.2.0"
|
||||
pify "^2.3.0"
|
||||
yauzl "^2.4.2"
|
||||
|
||||
decompress@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.0.tgz#7aedd85427e5a92dacfe55674a7c505e96d01f9d"
|
||||
dependencies:
|
||||
decompress-tar "^4.0.0"
|
||||
decompress-tarbz2 "^4.0.0"
|
||||
decompress-targz "^4.0.0"
|
||||
decompress-unzip "^4.0.1"
|
||||
graceful-fs "^4.1.10"
|
||||
make-dir "^1.0.0"
|
||||
pify "^2.3.0"
|
||||
strip-dirs "^2.0.0"
|
||||
|
||||
diagnostic-channel-publishers@0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3"
|
||||
|
||||
diagnostic-channel@0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17"
|
||||
dependencies:
|
||||
semver "^5.3.0"
|
||||
|
||||
end-of-stream@^1.0.0:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
|
||||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
es6-promise@^4.0.3:
|
||||
version "4.2.4"
|
||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29"
|
||||
|
||||
es6-promisify@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
|
||||
dependencies:
|
||||
es6-promise "^4.0.3"
|
||||
|
||||
eventemitter2@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-5.0.1.tgz#6197a095d5fb6b57e8942f6fd7eaad63a09c9452"
|
||||
|
||||
fd-slicer@~1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65"
|
||||
dependencies:
|
||||
pend "~1.2.0"
|
||||
|
||||
file-type@^3.8.0:
|
||||
version "3.9.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9"
|
||||
|
||||
file-type@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6"
|
||||
|
||||
file-type@^6.1.0:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919"
|
||||
|
||||
get-stream@^2.2.0:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de"
|
||||
dependencies:
|
||||
object-assign "^4.0.1"
|
||||
pinkie-promise "^2.0.0"
|
||||
|
||||
graceful-fs@^4.1.10:
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
|
||||
|
||||
"graceful-readlink@>= 1.0.0":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
||||
|
||||
http-proxy-agent@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
|
||||
dependencies:
|
||||
agent-base "4"
|
||||
debug "3.1.0"
|
||||
|
||||
https-proxy-agent@^2.1.1:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.0.tgz#7fbba856be8cd677986f42ebd3664f6317257887"
|
||||
dependencies:
|
||||
agent-base "^4.1.0"
|
||||
debug "^3.1.0"
|
||||
|
||||
ieee754@^1.1.4:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.11.tgz#c16384ffe00f5b7835824e67b6f2bd44a5229455"
|
||||
|
||||
inherits@~2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
|
||||
is-natural-number@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8"
|
||||
|
||||
is-stream@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
|
||||
isarray@^1.0.0, isarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
|
||||
make-dir@^1.0.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b"
|
||||
dependencies:
|
||||
pify "^3.0.0"
|
||||
|
||||
minimist@0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
||||
|
||||
mkdirp@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||
dependencies:
|
||||
minimist "0.0.8"
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
|
||||
object-assign@^4.0.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
|
||||
once@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
opener@^1.4.3:
|
||||
version "1.4.3"
|
||||
resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8"
|
||||
|
||||
os-tmpdir@~1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
||||
|
||||
pend@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||
|
||||
pify@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
||||
|
||||
pify@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
|
||||
|
||||
pinkie-promise@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
|
||||
dependencies:
|
||||
pinkie "^2.0.0"
|
||||
|
||||
pinkie@^2.0.0:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
|
||||
|
||||
readable-stream@^2.0.0, readable-stream@^2.3.5:
|
||||
version "2.3.5"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.5.tgz#b4f85003a938cbb6ecbce2a124fb1012bd1a838d"
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.3"
|
||||
isarray "~1.0.0"
|
||||
process-nextick-args "~2.0.0"
|
||||
safe-buffer "~5.1.1"
|
||||
string_decoder "~1.0.3"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
|
||||
|
||||
seek-bzip@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc"
|
||||
dependencies:
|
||||
commander "~2.8.1"
|
||||
|
||||
semver@^5.3.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
||||
|
||||
"service-downloader@github:anthonydresser/service-downloader#0.1.2":
|
||||
version "0.1.2"
|
||||
resolved "https://codeload.github.com/anthonydresser/service-downloader/tar.gz/2aa9b336b6442e17e24693ddc907030575539798"
|
||||
dependencies:
|
||||
decompress "^4.2.0"
|
||||
eventemitter2 "^5.0.1"
|
||||
http-proxy-agent "^2.0.0"
|
||||
https-proxy-agent "^2.1.1"
|
||||
mkdirp "^0.5.1"
|
||||
tmp "^0.0.33"
|
||||
|
||||
string_decoder@~1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab"
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
strip-dirs@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5"
|
||||
dependencies:
|
||||
is-natural-number "^4.0.1"
|
||||
|
||||
tar-stream@^1.5.2:
|
||||
version "1.5.5"
|
||||
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.5.5.tgz#5cad84779f45c83b1f2508d96b09d88c7218af55"
|
||||
dependencies:
|
||||
bl "^1.0.0"
|
||||
end-of-stream "^1.0.0"
|
||||
readable-stream "^2.0.0"
|
||||
xtend "^4.0.0"
|
||||
|
||||
through@^2.3.6:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||
|
||||
tmp@^0.0.33:
|
||||
version "0.0.33"
|
||||
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
|
||||
dependencies:
|
||||
os-tmpdir "~1.0.2"
|
||||
|
||||
unbzip2-stream@^1.0.9:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz#73a033a567bbbde59654b193c44d48a7e4f43c47"
|
||||
dependencies:
|
||||
buffer "^3.0.1"
|
||||
through "^2.3.6"
|
||||
|
||||
util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
|
||||
vscode-extension-telemetry@^0.0.15:
|
||||
version "0.0.15"
|
||||
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.15.tgz#685c32f3b67e8fb85ba689c1d7f88ff90ff87856"
|
||||
dependencies:
|
||||
applicationinsights "1.0.1"
|
||||
|
||||
vscode-jsonrpc@3.5.0, vscode-jsonrpc@^3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0.tgz#87239d9e166b2d7352245b8a813597804c1d63aa"
|
||||
|
||||
vscode-languageclient@3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-3.5.0.tgz#36d02cc186a8365a4467719a290fb200a9ae490a"
|
||||
dependencies:
|
||||
vscode-languageserver-protocol "^3.5.0"
|
||||
|
||||
vscode-languageserver-protocol@3.5.0, vscode-languageserver-protocol@^3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0.tgz#067c5cbe27709795398d119692c97ebba1452209"
|
||||
dependencies:
|
||||
vscode-jsonrpc "^3.5.0"
|
||||
vscode-languageserver-types "^3.5.0"
|
||||
|
||||
vscode-languageserver-types@3.5.0, vscode-languageserver-types@^3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz#e48d79962f0b8e02de955e3f524908e2b19c0374"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
|
||||
xtend@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
||||
|
||||
yauzl@^2.4.2:
|
||||
version "2.9.1"
|
||||
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.1.tgz#a81981ea70a57946133883f029c5821a89359a7f"
|
||||
dependencies:
|
||||
buffer-crc32 "~0.2.3"
|
||||
fd-slicer "~1.0.1"
|
||||
|
||||
zone.js@0.7.6:
|
||||
version "0.7.6"
|
||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sqlops",
|
||||
"version": "0.30.4",
|
||||
"version": "0.30.5",
|
||||
"distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
@@ -60,7 +60,7 @@
|
||||
"reflect-metadata": "^0.1.8",
|
||||
"rxjs": "5.4.0",
|
||||
"semver": "4.3.6",
|
||||
"slickgrid": "github:anthonydresser/SlickGrid#2.3.17",
|
||||
"slickgrid": "github:anthonydresser/SlickGrid#2.3.16",
|
||||
"spdlog": "0.6.0",
|
||||
"sudo-prompt": "^8.0.0",
|
||||
"svg.js": "^2.2.5",
|
||||
|
||||
@@ -82,7 +82,8 @@ export default class MainController implements vscode.Disposable {
|
||||
tab1.registerContent(async (view) => {
|
||||
let inputBox = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
//width: 300
|
||||
multiline: true,
|
||||
height: 100
|
||||
}).component();
|
||||
let inputBoxWrapper = view.modelBuilder.loadingComponent().withItem(inputBox).component();
|
||||
inputBoxWrapper.loading = false;
|
||||
@@ -171,12 +172,67 @@ export default class MainController implements vscode.Disposable {
|
||||
inputBox.value = radioButton.value;
|
||||
groupModel1.enabled = false;
|
||||
});
|
||||
let table = view.modelBuilder.table().withProperties({
|
||||
data: [
|
||||
['1', '2', '2'],
|
||||
['4', '5', '6'],
|
||||
['7', '8', '9']
|
||||
], columns: ['c1', 'c2', 'c3'],
|
||||
height: 250,
|
||||
selectedRows: [0]
|
||||
}).component();
|
||||
table.onRowSelected(e => {
|
||||
// TODO:
|
||||
});
|
||||
let listBox = view.modelBuilder.listBox().withProperties({
|
||||
values: ['1', '2', '3'],
|
||||
selectedRow: 2
|
||||
}).component();
|
||||
|
||||
let declarativeTable = view.modelBuilder.declarativeTable()
|
||||
.withProperties({
|
||||
columns: [{
|
||||
displayName: 'Column 1',
|
||||
valueType: sqlops.DeclarativeDataType.string,
|
||||
width: '20px',
|
||||
isReadOnly: true
|
||||
}, {
|
||||
displayName: 'Column 2',
|
||||
valueType: sqlops.DeclarativeDataType.string,
|
||||
width: '100px',
|
||||
isReadOnly: false
|
||||
}, {
|
||||
displayName: 'Column 3',
|
||||
valueType: sqlops.DeclarativeDataType.boolean,
|
||||
width: '20px',
|
||||
isReadOnly: false
|
||||
}, {
|
||||
displayName: 'Column 4',
|
||||
valueType: sqlops.DeclarativeDataType.category,
|
||||
isReadOnly: false,
|
||||
width: '120px',
|
||||
categoryValues: [
|
||||
{ name: 'options1', displayName: 'option 1' },
|
||||
{ name: 'options2', displayName: 'option 2' }
|
||||
]
|
||||
}
|
||||
],
|
||||
data: [
|
||||
['Data00', 'Data01', false, 'options2'],
|
||||
['Data10', 'Data11', true, 'options1']
|
||||
]
|
||||
}).component();
|
||||
|
||||
declarativeTable.onDataChanged(e => {
|
||||
inputBox2.value = e.row.toString() + ' ' + e.column.toString() + ' ' + e.value.toString();
|
||||
inputBox3.value = declarativeTable.data[e.row][e.column];
|
||||
});
|
||||
|
||||
let flexRadioButtonsModel = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'column',
|
||||
alignItems: 'left',
|
||||
height: 50
|
||||
height: 150
|
||||
}).withItems([
|
||||
radioButton, groupModel1, radioButton2]
|
||||
, { flex: '1 1 50%' }).component();
|
||||
@@ -200,6 +256,15 @@ export default class MainController implements vscode.Disposable {
|
||||
}, {
|
||||
component: flexRadioButtonsModel,
|
||||
title: 'Options'
|
||||
}, {
|
||||
component: declarativeTable,
|
||||
title: 'Declarative Table'
|
||||
}, {
|
||||
component: table,
|
||||
title: 'Table'
|
||||
}, {
|
||||
component: listBox,
|
||||
title: 'List Box'
|
||||
}], {
|
||||
horizontal: false,
|
||||
componentWidth: 400
|
||||
@@ -322,7 +387,7 @@ export default class MainController implements vscode.Disposable {
|
||||
height: '100%'
|
||||
});
|
||||
|
||||
let templateValues = {url: 'http://whoisactive.com/docs/'};
|
||||
let templateValues = { url: 'http://whoisactive.com/docs/' };
|
||||
Utils.renderTemplateHtml(path.join(__dirname, '..'), 'templateTab.html', templateValues)
|
||||
.then(html => {
|
||||
webview.html = html;
|
||||
|
||||
@@ -20,9 +20,9 @@ import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
<ng-template ngFor let-item let-first="first" let-last="last" [ngForOf]="menuItems">
|
||||
<span style="padding: 5px; display: flex; align-items: center">
|
||||
<span *ngIf="item.icon" class="icon" style="display: inline-block; margin-right: 5px" [ngClass]="item.icon"></span>
|
||||
<span *ngIf="first" style="font-weight: 200">{{item.label}}</span>
|
||||
<span *ngIf="first">{{item.label}}</span>
|
||||
<span *ngIf="last" style="">{{item.label}}</span>
|
||||
<a class="router-link" *ngIf="!last && !first" (click)="route(item.routerLink)" style=" font-weight: 200" >{{item.label}}</a>
|
||||
<a class="router-link" *ngIf="!last && !first" (click)="route(item.routerLink)" >{{item.label}}</a>
|
||||
</span>
|
||||
<span *ngIf="!last" class="icon chevron-right"></span>
|
||||
</ng-template>
|
||||
|
||||
@@ -33,4 +33,12 @@ export class Button extends vsButton {
|
||||
public set title(value: string) {
|
||||
this.$el.title(value);
|
||||
}
|
||||
|
||||
public setHeight(value: string) {
|
||||
this.$el.style('height', value);
|
||||
}
|
||||
|
||||
public setWidth(value: string) {
|
||||
this.$el.style('width', value);
|
||||
}
|
||||
}
|
||||
@@ -132,7 +132,7 @@ export class Dropdown extends Disposable {
|
||||
ariaLabel: this._options.ariaLabel
|
||||
});
|
||||
|
||||
this._register(DOM.addDisposableListener(this._input.inputElement, DOM.EventType.FOCUS, () => {
|
||||
this._register(DOM.addDisposableListener(this._input.inputElement, DOM.EventType.CLICK, () => {
|
||||
this._showList();
|
||||
}));
|
||||
|
||||
@@ -145,8 +145,12 @@ export class Dropdown extends Disposable {
|
||||
this._register(DOM.addStandardDisposableListener(this._input.inputElement, DOM.EventType.KEY_DOWN, (e: StandardKeyboardEvent) => {
|
||||
switch (e.keyCode) {
|
||||
case KeyCode.Enter:
|
||||
if (this._input.validate()) {
|
||||
this._onValueChange.fire(this._input.value);
|
||||
if (this._contextView.isVisible()) {
|
||||
if (this._input.validate()) {
|
||||
this._onValueChange.fire(this._input.value);
|
||||
}
|
||||
} else {
|
||||
this._showList();
|
||||
}
|
||||
e.stopPropagation();
|
||||
break;
|
||||
@@ -192,6 +196,11 @@ export class Dropdown extends Disposable {
|
||||
this._contextView.hide();
|
||||
});
|
||||
|
||||
this._controller.onDropdownEscape(() => {
|
||||
this._input.focus();
|
||||
this._contextView.hide();
|
||||
});
|
||||
|
||||
this._input.onDidChange(e => {
|
||||
if (this._dataSource.options) {
|
||||
this._filter.filterString = e;
|
||||
@@ -231,17 +240,19 @@ export class Dropdown extends Disposable {
|
||||
}
|
||||
|
||||
private _layoutTree(): void {
|
||||
let filteredLength = this._dataSource.options.reduce((p, i) => {
|
||||
if (this._filter.isVisible(undefined, i)) {
|
||||
return p + 1;
|
||||
} else {
|
||||
return p;
|
||||
}
|
||||
}, 0);
|
||||
let height = filteredLength * this._renderer.getHeight(undefined, undefined) > this._options.maxHeight ? this._options.maxHeight : filteredLength * this._renderer.getHeight(undefined, undefined);
|
||||
this.$treeContainer.style('height', height + 'px').style('width', DOM.getContentWidth(this.$input.getHTMLElement()) - 2 + 'px');
|
||||
this._tree.layout(parseInt(this.$treeContainer.style('height')));
|
||||
this._tree.refresh();
|
||||
if (this._dataSource && this._dataSource.options && this._dataSource.options.length > 0) {
|
||||
let filteredLength = this._dataSource.options.reduce((p, i) => {
|
||||
if (this._filter.isVisible(undefined, i)) {
|
||||
return p + 1;
|
||||
} else {
|
||||
return p;
|
||||
}
|
||||
}, 0);
|
||||
let height = filteredLength * this._renderer.getHeight(undefined, undefined) > this._options.maxHeight ? this._options.maxHeight : filteredLength * this._renderer.getHeight(undefined, undefined);
|
||||
this.$treeContainer.style('height', height + 'px').style('width', DOM.getContentWidth(this.$input.getHTMLElement()) - 2 + 'px');
|
||||
this._tree.layout(parseInt(this.$treeContainer.style('height')));
|
||||
this._tree.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public set values(vals: string[]) {
|
||||
|
||||
@@ -101,10 +101,19 @@ export class DropdownController extends TreeDefaults.DefaultController {
|
||||
private _onSelectionChange = new Emitter<Resource>();
|
||||
public readonly onSelectionChange: Event<Resource> = this._onSelectionChange.event;
|
||||
|
||||
private _onDropdownEscape = new Emitter<void>();
|
||||
public readonly onDropdownEscape: Event<void> = this._onDropdownEscape.event;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected onEscape(tree: tree.ITree, event: IKeyboardEvent): boolean {
|
||||
let response = super.onEscape(tree, event);
|
||||
this._onDropdownEscape.fire();
|
||||
return response;
|
||||
}
|
||||
|
||||
protected onLeftClick(tree: tree.ITree, element: any, eventish: TreeDefaults.ICancelableEvent, origin: string): boolean {
|
||||
let response = super.onLeftClick(tree, element, eventish, origin);
|
||||
if (response) {
|
||||
|
||||
@@ -30,6 +30,7 @@ export class InputBox extends AngularDisposable implements OnInit, OnChanges {
|
||||
@Input() type: string;
|
||||
@Input() placeholder: string;
|
||||
@Input() ariaLabel: string;
|
||||
@Input() value: string;
|
||||
|
||||
@Output() onDidChange = new EventEmitter<string | number>();
|
||||
|
||||
@@ -49,6 +50,9 @@ export class InputBox extends AngularDisposable implements OnInit, OnChanges {
|
||||
placeholder: this.placeholder,
|
||||
ariaLabel: this.ariaLabel
|
||||
});
|
||||
if (this.value) {
|
||||
this._inputbox.value = this.value;
|
||||
}
|
||||
this._inputbox.onDidChange(e => {
|
||||
switch (this.type) {
|
||||
case 'number':
|
||||
|
||||
@@ -32,6 +32,7 @@ export class InputBox extends vsInputBox {
|
||||
private _onLoseFocus = this._register(new Emitter<OnLoseFocusParams>());
|
||||
public onLoseFocus: Event<OnLoseFocusParams> = this._onLoseFocus.event;
|
||||
|
||||
private _isTextAreaInput: boolean;
|
||||
|
||||
constructor(container: HTMLElement, contextViewProvider: IContextViewProvider, options?: IInputOptions) {
|
||||
super(container, contextViewProvider, options);
|
||||
@@ -48,6 +49,10 @@ export class InputBox extends vsInputBox {
|
||||
self._onLoseFocus.fire({ value: self.value, hasChanged: self._lastLoseFocusValue !== self.value });
|
||||
self._lastLoseFocusValue = self.value;
|
||||
});
|
||||
|
||||
if (options && options.type === 'textarea') {
|
||||
this._isTextAreaInput = true;
|
||||
}
|
||||
}
|
||||
|
||||
public style(styles: IInputBoxStyles): void {
|
||||
@@ -67,6 +72,20 @@ export class InputBox extends vsInputBox {
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
public set rows(value: number) {
|
||||
this.inputElement.setAttribute('rows', value.toString());
|
||||
}
|
||||
|
||||
public set columns(value: number) {
|
||||
this.inputElement.setAttribute('cols', value.toString());
|
||||
}
|
||||
|
||||
public layout(): void {
|
||||
if (!this._isTextAreaInput) {
|
||||
super.layout();
|
||||
}
|
||||
}
|
||||
|
||||
public disable(): void {
|
||||
super.disable();
|
||||
this.inputBackground = this.disabledInputBackground;
|
||||
@@ -75,6 +94,12 @@ export class InputBox extends vsInputBox {
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
public setHeight(value: string) {
|
||||
if (this._isTextAreaInput) {
|
||||
this.inputElement.style.height = value;
|
||||
}
|
||||
}
|
||||
|
||||
public isEnabled(): boolean {
|
||||
return !this.inputElement.hasAttribute('disabled');
|
||||
}
|
||||
|
||||
@@ -115,8 +115,7 @@ export class SelectBox extends vsSelectBox {
|
||||
}
|
||||
|
||||
public enable(): void {
|
||||
//@SQLTODO
|
||||
//this.selectElement.disabled = false;
|
||||
this.selectElement.disabled = false;
|
||||
this.selectBackground = this.enabledSelectBackground;
|
||||
this.selectForeground = this.enabledSelectForeground;
|
||||
this.selectBorder = this.enabledSelectBorder;
|
||||
@@ -124,8 +123,7 @@ export class SelectBox extends vsSelectBox {
|
||||
}
|
||||
|
||||
public disable(): void {
|
||||
//@SQLTODO
|
||||
//this.selectElement.disabled = true;
|
||||
this.selectElement.disabled = true;
|
||||
this.selectBackground = this.disabledSelectBackground;
|
||||
this.selectForeground = this.disabledSelectForeground;
|
||||
this.selectBorder = this.disabledSelectBorder;
|
||||
|
||||
1
src/sql/base/browser/ui/table/media/down-inverse.svg
Normal file
1
src/sql/base/browser/ui/table/media/down-inverse.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#2d2d30;}.icon-canvas-transparent{opacity:0;}.icon-vs-bg{fill:#c5c5c5;}</style></defs><title>CollapseChevronDown_md_16x</title><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/><path class="icon-vs-out" d="M15.444,6.061,8,13.5.556,6.061,3.03,3.586,8,8.556l4.97-4.97Z" style="display: none;"/><path class="icon-vs-bg" d="M14.03,6.061,8,12.091,1.97,6.061,3.03,5,8,9.97,12.97,5Z"/></svg>
|
||||
|
After Width: | Height: | Size: 507 B |
1
src/sql/base/browser/ui/table/media/down.svg
Normal file
1
src/sql/base/browser/ui/table/media/down.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-vs-bg{fill:#424242;}</style></defs><title>CollapseChevronDown_md_16x</title><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/><path class="icon-vs-out" d="M15.444,6.061,8,13.5.556,6.061,3.03,3.586,8,8.556l4.97-4.97Z" style="display: none;"/><path class="icon-vs-bg" d="M14.03,6.061,8,12.091,1.97,6.061,3.03,5,8,9.97,12.97,5Z"/></svg>
|
||||
|
After Width: | Height: | Size: 507 B |
1
src/sql/base/browser/ui/table/media/filter.svg
Normal file
1
src/sql/base/browser/ui/table/media/filter.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{font-size:12px;font-family:FullMDL2Assets, Full MDL2 Assets;}</style></defs><title>filter_16x16</title><text class="cls-1" transform="translate(0 12)"> </text><path d="M0,1.53H16V3.24l-6,6v6.27H6V9.22l-6-6ZM15,2.82V2.53H1v.29l6,6v5.69H9V8.8Z"/></svg>
|
||||
|
After Width: | Height: | Size: 363 B |
1
src/sql/base/browser/ui/table/media/filter_inverse.svg
Normal file
1
src/sql/base/browser/ui/table/media/filter_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{font-size:12px;font-family:FullMDL2Assets, Full MDL2 Assets;}.cls-1,.cls-2{fill:#fff;}</style></defs><title>filter_inverse_16x16</title><text class="cls-1" transform="translate(0.03 12.1)"> </text><path class="cls-2" d="M.05,1.63H16V3.33l-6,6v6.27H6V9.31l-6-6ZM15,2.91V2.62H1v.29l6,6v5.69H9V8.89Z"/></svg>
|
||||
|
After Width: | Height: | Size: 418 B |
@@ -31,4 +31,117 @@
|
||||
height: 5px;
|
||||
margin-left: 4px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.slick-header-menubutton {
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
bottom: 0;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 0;
|
||||
width: 18px;
|
||||
background-image: url('down.svg');
|
||||
}
|
||||
|
||||
.vs-dark .slick-header-menubutton {
|
||||
background-image: url('down-inverse.svg');
|
||||
}
|
||||
|
||||
.slick-header-menubutton.filtered {
|
||||
background-image: url('filter.svg');
|
||||
}
|
||||
|
||||
.vs-dark .slick-header-menubutton.filtered {
|
||||
background-image: url('filter_inverse.svg');
|
||||
}
|
||||
|
||||
.slick-header-menu {
|
||||
background: none repeat scroll 0 0 white;
|
||||
border: 1px solid #BFBDBD;
|
||||
min-width: 175px;
|
||||
padding: 4px;
|
||||
z-index: 100000;
|
||||
cursor: default;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.vs-dark .slick-header-menu {
|
||||
background: none repeat scroll 0 0 #333333;
|
||||
}
|
||||
|
||||
.slick-header-menu a.monaco-button.monaco-text-button {
|
||||
width: 60px;
|
||||
margin: 6px 6px 6px 6px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.slick-header-menu .filter
|
||||
{
|
||||
border: 1px solid #BFBDBD;
|
||||
font-size: 8pt;
|
||||
height: 400px;
|
||||
margin-top: 6px;
|
||||
overflow: scroll;
|
||||
padding: 4px;
|
||||
white-space: nowrap;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.slick-header-menuitem
|
||||
{
|
||||
border: 1px solid transparent;
|
||||
padding: 2px 4px;
|
||||
cursor: pointer;
|
||||
list-style: none outside none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.slick-header-menuicon
|
||||
{
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
margin-right: 4px;
|
||||
vertical-align: middle;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.slick-header-menuicon.ascending {
|
||||
background: url('sort-asc.gif');
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.slick-header-menuicon.descending {
|
||||
background: url('sort-desc.gif');
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.slick-header-menucontent {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.slick-header-menuitem:hover {
|
||||
border-color: #BFBDBD;
|
||||
}
|
||||
|
||||
.header-overlay, .cell-overlay, .selection-cell-overlay {
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.vs-dark .slick-header-menu > input.input {
|
||||
color: #4a4a4a;
|
||||
}
|
||||
353
src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts
Normal file
353
src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts
Normal file
@@ -0,0 +1,353 @@
|
||||
// Adopted and converted to typescript from https://github.com/danny-sg/slickgrid-spreadsheet-plugins/blob/master/ext.headerfilter.js
|
||||
// heavily modified
|
||||
import 'vs/css!sql/base/browser/ui/table/media/table';
|
||||
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { SlickGrid } from 'angular2-slickgrid';
|
||||
import { Button } from '../../button/button';
|
||||
import { attachButtonStyler } from 'sql/common/theme/styler';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
|
||||
export class HeaderFilter {
|
||||
|
||||
public onFilterApplied = new Slick.Event();
|
||||
public onCommand = new Slick.Event();
|
||||
|
||||
private grid;
|
||||
private handler = new Slick.EventHandler();
|
||||
private defaults = {
|
||||
filterImage: 'src/sql/media/icons/filter.svg',
|
||||
sortAscImage: 'sort-asc.gif',
|
||||
sortDescImage: 'sort-desc.gif'
|
||||
};
|
||||
|
||||
private $menu;
|
||||
private options: any;
|
||||
private okButton: Button;
|
||||
private clearButton: Button;
|
||||
private cancelButton: Button;
|
||||
private workingFilters: any;
|
||||
private columnDef: any;
|
||||
|
||||
constructor(options: any, private _themeService: IThemeService) {
|
||||
this.options = mixin(options, this.defaults, false);
|
||||
}
|
||||
|
||||
public init(grid: Slick.Grid<any>): void {
|
||||
this.grid = grid;
|
||||
this.handler.subscribe(this.grid.onHeaderCellRendered, (e, args) => this.handleHeaderCellRendered(e , args))
|
||||
.subscribe(this.grid.onBeforeHeaderCellDestroy, (e, args) => this.handleBeforeHeaderCellDestroy(e, args))
|
||||
.subscribe(this.grid.onClick, (e) => this.handleBodyMouseDown)
|
||||
.subscribe(this.grid.onColumnsResized, () => this.columnsResized());
|
||||
|
||||
this.grid.setColumns(this.grid.getColumns());
|
||||
|
||||
$(document.body).bind('mousedown', this.handleBodyMouseDown);
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
this.handler.unsubscribeAll();
|
||||
$(document.body).unbind('mousedown', this.handleBodyMouseDown);
|
||||
}
|
||||
|
||||
private handleBodyMouseDown = (e) => {
|
||||
if (this.$menu && this.$menu[0] !== e.target && !$.contains(this.$menu[0], e.target)) {
|
||||
this.hideMenu();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
private hideMenu() {
|
||||
if (this.$menu) {
|
||||
this.$menu.remove();
|
||||
this.$menu = null;
|
||||
}
|
||||
}
|
||||
|
||||
private handleHeaderCellRendered(e, args) {
|
||||
let column = args.column;
|
||||
if (column.id === '_detail_selector') {
|
||||
return;
|
||||
}
|
||||
let $el = $('<div></div>')
|
||||
.addClass('slick-header-menubutton')
|
||||
.data('column', column);
|
||||
|
||||
$el.bind('click', (e) => this.showFilter(e)).appendTo(args.node);
|
||||
}
|
||||
|
||||
private handleBeforeHeaderCellDestroy(e, args) {
|
||||
$(args.node)
|
||||
.find('.slick-header-menubutton')
|
||||
.remove();
|
||||
}
|
||||
|
||||
private addMenuItem(menu, columnDef, title, command, image) {
|
||||
let $item = $('<div class="slick-header-menuitem">')
|
||||
.data('command', command)
|
||||
.data('column', columnDef)
|
||||
.bind('click', (e) => this.handleMenuItemClick(e, command, columnDef))
|
||||
.appendTo(menu);
|
||||
|
||||
let $icon = $('<div class="slick-header-menuicon">')
|
||||
.appendTo($item);
|
||||
|
||||
if (title === 'Sort Ascending') {
|
||||
$icon.get(0).className += ' ascending';
|
||||
} else if (title === 'Sort Descending') {
|
||||
$icon.get(0).className += ' descending';
|
||||
}
|
||||
|
||||
$('<span class="slick-header-menucontent">')
|
||||
.text(title)
|
||||
.appendTo($item);
|
||||
}
|
||||
|
||||
private addMenuInput(menu, columnDef) {
|
||||
const self = this;
|
||||
$('<input class="input" placeholder="Search" style="margin-top: 5px; width: 206px">')
|
||||
.data('column', columnDef)
|
||||
.bind('keyup', (e) => {
|
||||
let filterVals = this.getFilterValuesByInput($(e.target));
|
||||
self.updateFilterInputs(menu, columnDef, filterVals);
|
||||
})
|
||||
.appendTo(menu);
|
||||
}
|
||||
|
||||
private updateFilterInputs(menu, columnDef, filterItems) {
|
||||
let filterOptions = '<label><input type="checkbox" value="-1" />(Select All)</label>';
|
||||
columnDef.filterValues = columnDef.filterValues || [];
|
||||
|
||||
// WorkingFilters is a copy of the filters to enable apply/cancel behaviour
|
||||
this.workingFilters = columnDef.filterValues.slice(0);
|
||||
|
||||
for (let i = 0; i < filterItems.length; i++) {
|
||||
let filtered = _.contains(this.workingFilters, filterItems[i]);
|
||||
|
||||
filterOptions += '<label><input type="checkbox" value="' + i + '"'
|
||||
+ (filtered ? ' checked="checked"' : '')
|
||||
+ '/>' + filterItems[i] + '</label>';
|
||||
}
|
||||
let $filter = menu.find('.filter');
|
||||
$filter.empty().append($(filterOptions));
|
||||
|
||||
$(':checkbox', $filter).bind('click', (e) => {
|
||||
this.workingFilters = this.changeWorkingFilter(filterItems, this.workingFilters, $(e.target));
|
||||
});
|
||||
}
|
||||
|
||||
private showFilter(e) {
|
||||
let $menuButton = $(e.target);
|
||||
this.columnDef = $menuButton.data('column');
|
||||
|
||||
this.columnDef.filterValues = this.columnDef.filterValues || [];
|
||||
|
||||
// WorkingFilters is a copy of the filters to enable apply/cancel behaviour
|
||||
this.workingFilters = this.columnDef.filterValues.slice(0);
|
||||
|
||||
let filterItems;
|
||||
|
||||
if (this.workingFilters.length === 0) {
|
||||
// Filter based all available values
|
||||
filterItems = this.getFilterValues(this.grid.getData(), this.columnDef);
|
||||
}
|
||||
else {
|
||||
// Filter based on current dataView subset
|
||||
filterItems = this.getAllFilterValues(this.grid.getData().getItems(), this.columnDef);
|
||||
}
|
||||
|
||||
if (!this.$menu) {
|
||||
this.$menu = $('<div class="slick-header-menu">').appendTo(document.body);
|
||||
}
|
||||
|
||||
this.$menu.empty();
|
||||
|
||||
this.addMenuItem(this.$menu, this.columnDef, 'Sort Ascending', 'sort-asc', this.options.sortAscImage);
|
||||
this.addMenuItem(this.$menu, this.columnDef, 'Sort Descending', 'sort-desc', this.options.sortDescImage);
|
||||
this.addMenuInput(this.$menu, this.columnDef);
|
||||
|
||||
let filterOptions = '<label><input type="checkbox" value="-1" />(Select All)</label>';
|
||||
|
||||
for (let i = 0; i < filterItems.length; i++) {
|
||||
let filtered = _.contains(this.workingFilters, filterItems[i]);
|
||||
if (filterItems[i] && filterItems[i].indexOf('Error:') < 0) {
|
||||
filterOptions += '<label><input type="checkbox" value="' + i + '"'
|
||||
+ (filtered ? ' checked="checked"' : '')
|
||||
+ '/>' + filterItems[i] + '</label>';
|
||||
}
|
||||
}
|
||||
let $filter = $('<div class="filter">')
|
||||
.append($(filterOptions))
|
||||
.appendTo(this.$menu);
|
||||
|
||||
this.okButton = new Button(this.$menu.get(0));
|
||||
this.okButton.label = 'OK';
|
||||
this.okButton.title = 'OK';
|
||||
this.okButton.element.id = 'filter-ok-button';
|
||||
let okElement = $('#filter-ok-button');
|
||||
okElement.bind('click', (ev) => {
|
||||
this.columnDef.filterValues = this.workingFilters.splice(0);
|
||||
this.setButtonImage($menuButton, this.columnDef.filterValues.length > 0);
|
||||
this.handleApply(ev, this.columnDef);
|
||||
});
|
||||
|
||||
this.clearButton = new Button(this.$menu.get(0));
|
||||
this.clearButton.label = 'Clear';
|
||||
this.clearButton.title = 'Clear';
|
||||
this.clearButton.element.id = 'filter-clear-button';
|
||||
let clearElement = $('#filter-clear-button');
|
||||
clearElement.bind('click', (ev) => {
|
||||
this.columnDef.filterValues.length = 0;
|
||||
this.setButtonImage($menuButton, false);
|
||||
this.handleApply(ev, this.columnDef);
|
||||
});
|
||||
|
||||
this.cancelButton = new Button(this.$menu.get(0));
|
||||
this.cancelButton.label = 'Cancel';
|
||||
this.cancelButton.title = 'Cancel';
|
||||
this.cancelButton.element.id = 'filter-cancel-button';
|
||||
let cancelElement = $('#filter-cancel-button');
|
||||
cancelElement.bind('click', () => this.hideMenu());
|
||||
attachButtonStyler(this.okButton, this._themeService);
|
||||
attachButtonStyler(this.clearButton, this._themeService);
|
||||
attachButtonStyler(this.cancelButton, this._themeService);
|
||||
|
||||
$(':checkbox', $filter).bind('click', (e) => {
|
||||
this.workingFilters = this.changeWorkingFilter(filterItems, this.workingFilters, $(e.target));
|
||||
});
|
||||
|
||||
let offset = $(e.target).offset();
|
||||
let left = offset.left - this.$menu.width() + $(e.target).width() - 8;
|
||||
|
||||
let menutop = offset.top + $(e.target).height();
|
||||
|
||||
if (menutop + offset.top > $(window).height()) {
|
||||
menutop -= (this.$menu.height() + $(e.target).height() + 8);
|
||||
}
|
||||
this.$menu.css('top', menutop)
|
||||
.css('left', (left > 0 ? left : 0));
|
||||
}
|
||||
|
||||
private columnsResized() {
|
||||
this.hideMenu();
|
||||
}
|
||||
|
||||
private changeWorkingFilter(filterItems, workingFilters, $checkbox) {
|
||||
let value = $checkbox.val();
|
||||
let $filter = $checkbox.parent().parent();
|
||||
|
||||
if ($checkbox.val() < 0) {
|
||||
// Select All
|
||||
if ($checkbox.prop('checked')) {
|
||||
$(':checkbox', $filter).prop('checked', true);
|
||||
workingFilters = filterItems.slice(0);
|
||||
} else {
|
||||
$(':checkbox', $filter).prop('checked', false);
|
||||
workingFilters.length = 0;
|
||||
}
|
||||
} else {
|
||||
let index = _.indexOf(workingFilters, filterItems[value]);
|
||||
|
||||
if ($checkbox.prop('checked') && index < 0) {
|
||||
workingFilters.push(filterItems[value]);
|
||||
let nextRow = filterItems[(parseInt(value)+1).toString()];
|
||||
if (nextRow && nextRow.indexOf('Error:') >= 0) {
|
||||
workingFilters.push(nextRow);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (index > -1) {
|
||||
workingFilters.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return workingFilters;
|
||||
}
|
||||
|
||||
private setButtonImage($el, filtered) {
|
||||
let element: HTMLElement = $el.get(0);
|
||||
if (filtered) {
|
||||
element.className += ' filtered';
|
||||
} else {
|
||||
let classList = element.classList;
|
||||
if (classList.contains('filtered')) {
|
||||
classList.remove('filtered');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private handleApply(e, columnDef) {
|
||||
this.hideMenu();
|
||||
|
||||
this.onFilterApplied.notify({ 'grid': this.grid, 'column': columnDef }, e, self);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
private getFilterValues(dataView, column) {
|
||||
let seen = [];
|
||||
for (let i = 0; i < dataView.getLength() ; i++) {
|
||||
let value = dataView.getItem(i)[column.field];
|
||||
|
||||
if (!_.contains(seen, value)) {
|
||||
seen.push(value);
|
||||
}
|
||||
}
|
||||
return seen;
|
||||
}
|
||||
|
||||
private getFilterValuesByInput($input) {
|
||||
let column = $input.data('column'),
|
||||
filter = $input.val(),
|
||||
dataView = this.grid.getData(),
|
||||
seen = [];
|
||||
|
||||
for (let i = 0; i < dataView.getLength() ; i++) {
|
||||
let value = dataView.getItem(i)[column.field];
|
||||
|
||||
if (filter.length > 0) {
|
||||
let itemValue = !value ? '' : value;
|
||||
let lowercaseFilter = filter.toString().toLowerCase();
|
||||
let lowercaseVal = itemValue.toString().toLowerCase();
|
||||
if (!_.contains(seen, value) && lowercaseVal.indexOf(lowercaseFilter) > -1) {
|
||||
seen.push(value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!_.contains(seen, value)) {
|
||||
seen.push(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _.sortBy(seen, (v) => { return v; });
|
||||
}
|
||||
|
||||
private getAllFilterValues(data, column) {
|
||||
let seen = [];
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let value = data[i][column.field];
|
||||
|
||||
if (!_.contains(seen, value)) {
|
||||
seen.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
return _.sortBy(seen, (v) => { return v; });
|
||||
}
|
||||
|
||||
private handleMenuItemClick(e, command, columnDef) {
|
||||
this.hideMenu();
|
||||
|
||||
this.onCommand.notify({
|
||||
'grid': this.grid,
|
||||
'column': columnDef,
|
||||
'command': command
|
||||
}, e, self);
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
@@ -277,8 +277,8 @@ export class RowDetailView {
|
||||
item._isPadding = false;
|
||||
item._parent = parent;
|
||||
item._offset = offset;
|
||||
item.jobId = parent.jobId;
|
||||
item.name = parent.message ? parent.message : nls.localize('rowDetailView.loadError','Loading Error...');
|
||||
parent._child = item;
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ export interface IFindPosition {
|
||||
row: number;
|
||||
}
|
||||
|
||||
function defaultSort<T>(args: Slick.OnSortEventArgs<T>, data: Array<T>): Array<T> {
|
||||
export function defaultSort<T>(args: Slick.OnSortEventArgs<T>, data: Array<T>): Array<T> {
|
||||
let field = args.sortCol.field;
|
||||
let sign = args.sortAsc ? 1 : -1;
|
||||
return data.sort((a, b) => (a[field] === b[field] ? 0 : (a[field] > b[field] ? 1 : -1)) * sign);
|
||||
|
||||
10
src/sql/base/browser/ui/table/utils.ts
Normal file
10
src/sql/base/browser/ui/table/utils.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.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export function defaultFormatter<T>(valueProperty: keyof T): Slick.Formatter<T> {
|
||||
return (row: number, cell: number, value: any, columnDef: Slick.Column<T>, dataContext: Slick.SlickData): string => {
|
||||
return value[valueProperty];
|
||||
};
|
||||
}
|
||||
@@ -72,6 +72,7 @@ export function attachInputBoxStyler(widget: IThemable, themeService: IThemeServ
|
||||
export function attachSelectBoxStyler(widget: IThemable, themeService: IThemeService, style?:
|
||||
{
|
||||
selectBackground?: cr.ColorIdentifier,
|
||||
selectListBackground?: cr.ColorIdentifier,
|
||||
selectForeground?: cr.ColorIdentifier,
|
||||
selectBorder?: cr.ColorIdentifier,
|
||||
disabledSelectBackground?: cr.ColorIdentifier,
|
||||
@@ -81,10 +82,17 @@ export function attachSelectBoxStyler(widget: IThemable, themeService: IThemeSer
|
||||
inputValidationWarningBorder?: cr.ColorIdentifier,
|
||||
inputValidationWarningBackground?: cr.ColorIdentifier,
|
||||
inputValidationErrorBorder?: cr.ColorIdentifier,
|
||||
inputValidationErrorBackground?: cr.ColorIdentifier
|
||||
inputValidationErrorBackground?: cr.ColorIdentifier,
|
||||
focusBorder?: cr.ColorIdentifier,
|
||||
listFocusBackground?: cr.ColorIdentifier,
|
||||
listFocusForeground?: cr.ColorIdentifier,
|
||||
listFocusOutline?: cr.ColorIdentifier,
|
||||
listHoverBackground?: cr.ColorIdentifier,
|
||||
listHoverForeground?: cr.ColorIdentifier
|
||||
}): IDisposable {
|
||||
return attachStyler(themeService, {
|
||||
selectBackground: (style && style.selectBackground) || cr.selectBackground,
|
||||
selectListBackground: (style && style.selectListBackground) || cr.selectListBackground,
|
||||
selectForeground: (style && style.selectForeground) || cr.selectForeground,
|
||||
selectBorder: (style && style.selectBorder) || cr.selectBorder,
|
||||
disabledSelectBackground: (style && style.disabledSelectBackground) || sqlcolors.disabledInputBackground,
|
||||
@@ -94,7 +102,14 @@ export function attachSelectBoxStyler(widget: IThemable, themeService: IThemeSer
|
||||
inputValidationWarningBorder: (style && style.inputValidationWarningBorder) || cr.inputValidationWarningBorder,
|
||||
inputValidationWarningBackground: (style && style.inputValidationWarningBackground) || cr.inputValidationWarningBackground,
|
||||
inputValidationErrorBorder: (style && style.inputValidationErrorBorder) || cr.inputValidationErrorBorder,
|
||||
inputValidationErrorBackground: (style && style.inputValidationErrorBackground) || cr.inputValidationErrorBackground
|
||||
inputValidationErrorBackground: (style && style.inputValidationErrorBackground) || cr.inputValidationErrorBackground,
|
||||
focusBorder: (style && style.focusBorder) || cr.focusBorder,
|
||||
listFocusBackground: (style && style.listFocusBackground) || cr.listFocusBackground,
|
||||
listFocusForeground: (style && style.listFocusForeground) || cr.listFocusForeground,
|
||||
listFocusOutline: (style && style.listFocusOutline) || cr.activeContrastBorder,
|
||||
listHoverBackground: (style && style.listHoverBackground) || cr.listHoverBackground,
|
||||
listHoverForeground: (style && style.listHoverForeground) || cr.listHoverForeground,
|
||||
listHoverOutline: (style && style.listFocusOutline) || cr.activeContrastBorder
|
||||
}, widget);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@ import { Component, Inject, forwardRef, ViewChild, ElementRef, ViewChildren, Que
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface, SingleConnectionManagementService } 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';
|
||||
import { IPropertiesConfig } from 'sql/parts/dashboard/pages/serverDashboardPage.contribution';
|
||||
import { PanelComponent } from 'sql/base/browser/ui/panel/panel.component';
|
||||
import { IDashboardRegistry, Extensions as DashboardExtensions, IDashboardTab } from 'sql/platform/dashboard/common/dashboardRegistry';
|
||||
@@ -27,13 +25,8 @@ import { AngularDisposable } from 'sql/base/common/lifecycle';
|
||||
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as nls from 'vs/nls';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { addDisposableListener, getContentHeight, EventType } from 'vs/base/browser/dom';
|
||||
import { IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import * as colors from 'vs/platform/theme/common/colorRegistry';
|
||||
import * as themeColors from 'vs/workbench/common/theme';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
|
||||
@@ -7,11 +7,7 @@ import 'vs/css!./controlHostContent';
|
||||
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';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
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';
|
||||
|
||||
@@ -52,11 +52,16 @@ import { DashboardControlHostContainer } from 'sql/parts/dashboard/containers/da
|
||||
import { JobsViewComponent } from 'sql/parts/jobManagement/views/jobsView.component';
|
||||
import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.component';
|
||||
import { JobHistoryComponent } from 'sql/parts/jobManagement/views/jobHistory.component';
|
||||
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox.component';
|
||||
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox.component';
|
||||
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox.component';
|
||||
|
||||
let baseComponents = [DashboardHomeContainer, DashboardComponent, DashboardWidgetWrapper, DashboardWebviewContainer,
|
||||
DashboardWidgetContainer, DashboardGridContainer, DashboardErrorContainer, DashboardNavSection, ModelViewContent, WebviewContent, WidgetContent,
|
||||
ComponentHostDirective, BreadcrumbComponent, ControlHostContent, DashboardControlHostContainer,
|
||||
JobsViewComponent, AgentViewComponent, JobHistoryComponent, JobStepsViewComponent, DashboardModelViewContainer, ModelComponentWrapper];
|
||||
JobsViewComponent, AgentViewComponent, JobHistoryComponent, JobStepsViewComponent, DashboardModelViewContainer, ModelComponentWrapper, Checkbox,
|
||||
SelectBox,
|
||||
InputBox,];
|
||||
|
||||
/* Panel */
|
||||
import { PanelModule } from 'sql/base/browser/ui/panel/panel.module';
|
||||
|
||||
@@ -29,7 +29,6 @@ export class DatabaseDashboardPage extends DashboardPage implements OnInit {
|
||||
background_color: colors.editorBackground,
|
||||
border: 'none',
|
||||
fontSize: '14px',
|
||||
fontWeight: '200',
|
||||
padding: '5px 0 0 0',
|
||||
provider: undefined,
|
||||
edition: undefined
|
||||
|
||||
@@ -29,7 +29,6 @@ export class ServerDashboardPage extends DashboardPage implements OnInit {
|
||||
background_color: colors.editorBackground,
|
||||
border: 'none',
|
||||
fontSize: '14px',
|
||||
fontWeight: '200',
|
||||
padding: '5px 0 0 0',
|
||||
provider: undefined,
|
||||
edition: undefined
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<span #child style="white-space : nowrap; width: fit-content">
|
||||
<ng-template ngFor let-item [ngForOf]="properties">
|
||||
<span style="margin-left: 10px; display: inline-block;">
|
||||
<div style="font-size: 11px; font-weight: lighter">{{item.displayName}}</div>
|
||||
<div style="font-size: 11px;">{{item.displayName}}</div>
|
||||
<div>{{item.value}}</div>
|
||||
</span>
|
||||
</ng-template>
|
||||
|
||||
@@ -86,7 +86,7 @@ export class TasksWidget extends DashboardWidget implements IDashboardWidget, On
|
||||
}).filter(i => !!i);
|
||||
}
|
||||
|
||||
this._tasks = tasks.map(i => MenuRegistry.getCommand(i));
|
||||
this._tasks = tasks.map(i => MenuRegistry.getCommand(i)).filter(v => !!v);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
@@ -21,7 +21,7 @@ import { IEditDataComponentParams } from 'sql/services/bootstrap/bootstrapParams
|
||||
import { GridParentComponent } from 'sql/parts/grid/views/gridParentComponent';
|
||||
import { EditDataGridActionProvider } from 'sql/parts/grid/views/editData/editDataGridActions';
|
||||
import { error } from 'sql/base/common/log';
|
||||
import { clone } from 'sql/base/common/objects';
|
||||
import { clone, mixin } from 'sql/base/common/objects';
|
||||
import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService';
|
||||
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
||||
|
||||
@@ -195,7 +195,11 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
||||
let gridData: IGridDataRow[] = result.subset.map(row => {
|
||||
self.idMapping[rowIndex] = row.id;
|
||||
rowIndex++;
|
||||
return { values: row.cells, row: row.id };
|
||||
return {
|
||||
values: row.cells.map(c => {
|
||||
return mixin({ ariaLabel: c.displayValue }, c);
|
||||
}), row: row.id
|
||||
};
|
||||
});
|
||||
|
||||
// Append a NULL row to the end of gridData
|
||||
@@ -210,23 +214,21 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
||||
onDeleteRow(): (index: number) => void {
|
||||
const self = this;
|
||||
return (index: number): void => {
|
||||
self.dataService.deleteRow(index)
|
||||
.then(() => self.dataService.commitEdit())
|
||||
.then(() => self.removeRow(index));
|
||||
// If the user is deleting a new row that hasn't been committed yet then use the revert code
|
||||
if (self.newRowVisible && index === self.dataSet.dataRows.getLength() - 2) {
|
||||
self.revertCurrentRow();
|
||||
} else {
|
||||
self.dataService.deleteRow(index)
|
||||
.then(() => self.dataService.commitEdit())
|
||||
.then(() => self.removeRow(index));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
onRevertRow(): (index: number) => void {
|
||||
onRevertRow(): () => void {
|
||||
const self = this;
|
||||
return (index: number): void => {
|
||||
// Force focus to the first cell (completing any active edit operation)
|
||||
self.focusCell(index, 0, false);
|
||||
this.currentEditCellValue = null;
|
||||
// Perform a revert row operation
|
||||
self.dataService.revertRow(index)
|
||||
.then(() => {
|
||||
self.refreshResultsets();
|
||||
});
|
||||
return (): void => {
|
||||
self.revertCurrentRow();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -275,24 +277,27 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
||||
}
|
||||
|
||||
if (this.currentCell.row !== row) {
|
||||
// We're changing row, commit the changes
|
||||
cellSelectTasks = cellSelectTasks.then(() => {
|
||||
return self.dataService.commitEdit()
|
||||
.then(
|
||||
result => {
|
||||
// If we're currently adding a new row, only commit it if it has changes or the user is trying to add another new row
|
||||
if (this.newRowVisible && this.currentCell.row === this.dataSet.dataRows.getLength() - 2 && !this.isNullRow(row) && this.currentEditCellValue === null) {
|
||||
cellSelectTasks = cellSelectTasks.then(() => {
|
||||
return this.revertCurrentRow().then(() => this.focusCell(row, column));
|
||||
});
|
||||
} else {
|
||||
// We're changing row, commit the changes
|
||||
cellSelectTasks = cellSelectTasks.then(() => {
|
||||
return self.dataService.commitEdit().then(result => {
|
||||
// Committing was successful, clean the grid
|
||||
self.setGridClean();
|
||||
self.rowIdMappings = {};
|
||||
self.newRowVisible = false;
|
||||
return Promise.resolve();
|
||||
},
|
||||
error => {
|
||||
}, error => {
|
||||
// Committing failed, jump back to the last selected cell
|
||||
self.focusCell(self.currentCell.row, self.currentCell.column);
|
||||
return Promise.reject(null);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isNullRow(row) && !this.removingNewRow) {
|
||||
@@ -428,7 +433,18 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
||||
// If the esc key was pressed while in a create session
|
||||
let currentNewRowIndex = this.dataSet.totalRows - 2;
|
||||
|
||||
if (e.keyCode === KeyCode.Escape && this.newRowVisible && this.currentCell.row === currentNewRowIndex) {
|
||||
if (e.keyCode === KeyCode.Escape) {
|
||||
this.revertCurrentRow();
|
||||
handled = true;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
// Private Helper Functions ////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private async revertCurrentRow(): Promise<void> {
|
||||
let currentNewRowIndex = this.dataSet.totalRows - 2;
|
||||
if (this.newRowVisible && this.currentCell.row === currentNewRowIndex) {
|
||||
// revert our last new row
|
||||
this.removingNewRow = true;
|
||||
|
||||
@@ -437,17 +453,21 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
||||
this.removeRow(currentNewRowIndex);
|
||||
this.newRowVisible = false;
|
||||
});
|
||||
handled = true;
|
||||
} else if (e.keyCode === KeyCode.Escape) {
|
||||
this.currentEditCellValue = null;
|
||||
this.onRevertRow()(this.currentCell.row);
|
||||
handled = true;
|
||||
} else {
|
||||
try {
|
||||
// Perform a revert row operation
|
||||
if (this.currentCell) {
|
||||
await this.dataService.revertRow(this.currentCell.row);
|
||||
}
|
||||
} finally {
|
||||
// The operation may fail if there were no changes sent to the service to revert,
|
||||
// so clear any existing client-side edit and refresh the table regardless
|
||||
this.currentEditCellValue = null;
|
||||
this.refreshResultsets();
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
// Private Helper Functions ////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Checks if input row is our NULL new row
|
||||
private isNullRow(row: number): boolean {
|
||||
// Null row is always at index (totalRows - 1)
|
||||
@@ -535,9 +555,11 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
||||
// refresh results view
|
||||
this.onScroll(0);
|
||||
|
||||
// Set focus to the row index column of the removed row
|
||||
// Set focus to the row index column of the removed row if the current selection is in the removed row
|
||||
setTimeout(() => {
|
||||
this.focusCell(row, 0);
|
||||
if (this.currentCell.row === row) {
|
||||
this.focusCell(row, 0);
|
||||
}
|
||||
this.removingNewRow = false;
|
||||
}, this.scrollTimeOutTime);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export class EditDataGridActionProvider extends GridActionProvider {
|
||||
dataService: DataService,
|
||||
selectAllCallback: (index: number) => void,
|
||||
private _deleteRowCallback: (index: number) => void,
|
||||
private _revertRowCallback: (index: number) => void,
|
||||
private _revertRowCallback: () => void,
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super(dataService, selectAllCallback, instantiationService);
|
||||
@@ -56,18 +56,18 @@ export class DeleteRowAction extends Action {
|
||||
|
||||
export class RevertRowAction extends Action {
|
||||
public static ID = 'grid.revertRow';
|
||||
public static LABEL = localize('revertRow', 'Revert Row');
|
||||
public static LABEL = localize('revertRow', 'Revert Current Row');
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
private callback: (index: number) => void
|
||||
private callback: () => void
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(gridInfo: IGridInfo): TPromise<boolean> {
|
||||
this.callback(gridInfo.rowIndex);
|
||||
this.callback();
|
||||
return TPromise.as(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import { GridActionProvider } from 'sql/parts/grid/views/gridActions';
|
||||
import { IQueryComponentParams } from 'sql/services/bootstrap/bootstrapParams';
|
||||
import { error } from 'sql/base/common/log';
|
||||
import { TabChild } from 'sql/base/browser/ui/panel/tab.component';
|
||||
import { clone } from 'sql/base/common/objects';
|
||||
import { clone, mixin } from 'sql/base/common/objects';
|
||||
import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService';
|
||||
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
@@ -301,7 +301,9 @@ export class QueryComponent extends GridParentComponent implements OnInit, OnDes
|
||||
for (let row = 0; row < rows.rows.length; row++) {
|
||||
// Push row values onto end of gridData for slickgrid
|
||||
gridData.push({
|
||||
values: rows.rows[row]
|
||||
values: rows.rows[row].map(c => {
|
||||
return mixin({ ariaLabel: c.displayValue }, c);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -168,13 +168,16 @@ export class InsightsDialogView extends Modal {
|
||||
|
||||
this._splitView = new SplitView(container);
|
||||
|
||||
const itemsHeaderTitle = nls.localize("insights.dialog.items", "Items");
|
||||
const itemsDetailHeaderTitle = nls.localize("insights.dialog.itemDetails", "Item Details");
|
||||
|
||||
this._topTableData = new TableDataView();
|
||||
this._bottomTableData = new TableDataView();
|
||||
let topTableView = new TableCollapsibleView(nls.localize("insights.dialog.items", "Items"), { sizing: ViewSizing.Flexible, ariaHeaderLabel: 'title' }, this._topTableData, this._topColumns, { forceFitColumns: true });
|
||||
let topTableView = new TableCollapsibleView(itemsHeaderTitle, { sizing: ViewSizing.Flexible, ariaHeaderLabel: itemsHeaderTitle }, this._topTableData, this._topColumns, { forceFitColumns: true });
|
||||
this._topTable = topTableView.table;
|
||||
topTableView.addContainerClass('insights');
|
||||
this._topTable.setSelectionModel(new RowSelectionModel<ListResource>());
|
||||
let bottomTableView = new TableCollapsibleView(nls.localize("insights.dialog.itemDetails", "Item Details"), { sizing: ViewSizing.Flexible, ariaHeaderLabel: 'title' }, this._bottomTableData, this._bottomColumns, { forceFitColumns: true });
|
||||
let bottomTableView = new TableCollapsibleView(itemsDetailHeaderTitle, { sizing: ViewSizing.Flexible, ariaHeaderLabel: itemsDetailHeaderTitle }, this._bottomTableData, this._bottomColumns, { forceFitColumns: true });
|
||||
this._bottomTable = bottomTableView.table;
|
||||
this._bottomTable.setSelectionModel(new RowSelectionModel<ListResource>());
|
||||
|
||||
|
||||
@@ -82,7 +82,6 @@ export class AgentViewComponent {
|
||||
|
||||
public set jobId(value: string) {
|
||||
this._jobId = value;
|
||||
this._cd.detectChanges();
|
||||
}
|
||||
|
||||
public set showHistory(value: boolean) {
|
||||
@@ -92,7 +91,6 @@ export class AgentViewComponent {
|
||||
|
||||
public set agentJobInfo(value: AgentJobInfo) {
|
||||
this._agentJobInfo = value;
|
||||
this._cd.detectChanges();
|
||||
}
|
||||
|
||||
public set refresh(value: boolean) {
|
||||
@@ -104,6 +102,10 @@ export class AgentViewComponent {
|
||||
this._expanded.set(jobId, errorMessage);
|
||||
}
|
||||
|
||||
public set expanded(value: Map<string, string>) {
|
||||
this._expanded = value;
|
||||
}
|
||||
|
||||
public layout() {
|
||||
this._panel.layout();
|
||||
}
|
||||
|
||||
@@ -92,4 +92,58 @@ export class AgentJobUtilities {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public static convertDurationToSeconds(duration: string): number {
|
||||
let split = duration.split(':');
|
||||
let seconds = (+split[0]) * 60 * 60 + (+split[1]) * 60 + (+split[2]);
|
||||
return seconds;
|
||||
}
|
||||
|
||||
public static convertColFieldToName(colField: string) {
|
||||
switch(colField) {
|
||||
case('name'):
|
||||
return 'Name';
|
||||
case('lastRun'):
|
||||
return 'Last Run';
|
||||
case('nextRun'):
|
||||
return 'Next Run';
|
||||
case('enabled'):
|
||||
return 'Enabled';
|
||||
case('status'):
|
||||
return 'Status';
|
||||
case('category'):
|
||||
return 'Category';
|
||||
case('runnable'):
|
||||
return 'Runnable';
|
||||
case('schedule'):
|
||||
return 'Schedule';
|
||||
case('lastRunOutcome'):
|
||||
return 'Last Run Outcome';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public static convertColNameToField(columnName: string) {
|
||||
switch(columnName) {
|
||||
case('Name'):
|
||||
return 'name';
|
||||
case('Last Run'):
|
||||
return 'lastRun';
|
||||
case('Next Run'):
|
||||
return 'nextRun';
|
||||
case('Enabled'):
|
||||
return 'enabled';
|
||||
case('Status'):
|
||||
return 'status';
|
||||
case('Category'):
|
||||
return 'category';
|
||||
case('Runnable'):
|
||||
return 'runnable';
|
||||
case('Schedule'):
|
||||
return 'schedule';
|
||||
case('Last Run Outcome'):
|
||||
return 'lastRunOutcome';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ export interface IJobManagementService {
|
||||
|
||||
getJobHistory(connectionUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult>;
|
||||
|
||||
jobAction(connectionUri: string, jobName: string, action: string): Thenable<sqlops.AgentJobActionResult>;
|
||||
jobAction(connectionUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus>;
|
||||
|
||||
addToCache(server: string, cache: JobCacheObject);
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ export class JobManagementService implements IJobManagementService {
|
||||
});
|
||||
}
|
||||
|
||||
public jobAction(connectionUri: string, jobName: string, action: string): Thenable<sqlops.AgentJobActionResult> {
|
||||
public jobAction(connectionUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus> {
|
||||
return this._runAction(connectionUri, (runner) => {
|
||||
return runner.jobAction(connectionUri, jobName, action);
|
||||
});
|
||||
@@ -82,6 +82,7 @@ export class JobCacheObject {
|
||||
private _jobHistories: { [jobId: string]: sqlops.AgentJobHistoryInfo[]; } = {};
|
||||
private _prevJobID: string;
|
||||
private _serverName: string;
|
||||
private _dataView: Slick.Data.DataView<any>;
|
||||
|
||||
/* Getters */
|
||||
public get jobs(): sqlops.AgentJobInfo[] {
|
||||
@@ -104,6 +105,10 @@ export class JobCacheObject {
|
||||
return this._serverName;
|
||||
}
|
||||
|
||||
public get dataView(): Slick.Data.DataView<any> {
|
||||
return this._dataView;
|
||||
}
|
||||
|
||||
/* Setters */
|
||||
public set jobs(value: sqlops.AgentJobInfo[]) {
|
||||
this._jobs = value;
|
||||
@@ -125,4 +130,7 @@ export class JobCacheObject {
|
||||
this._serverName = value;
|
||||
}
|
||||
|
||||
}
|
||||
public set dataView(value: Slick.Data.DataView<any>) {
|
||||
this._dataView = value;
|
||||
}
|
||||
}
|
||||
@@ -49,12 +49,12 @@ jobhistory-component {
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
.vs-dark #jobsDiv .slick-cell {
|
||||
background:#333333 !important;
|
||||
.vs-dark #jobsDiv jobsview-component .jobview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
|
||||
background:#333333;
|
||||
}
|
||||
|
||||
#jobsDiv .slick-cell {
|
||||
background: white !important;
|
||||
#jobsDiv jobsview-component .jobview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
|
||||
background: white;
|
||||
border-right: transparent !important;
|
||||
border-left: transparent !important;
|
||||
line-height: 33px !important;
|
||||
@@ -205,4 +205,37 @@ agentview-component .jobview-grid .grid-canvas > .ui-widget-content.slick-row.od
|
||||
#jobsDiv jobsview-component .jobview-grid .slick-cell.l1.r1.error-row td.jobview-jobnameindicatorfailure {
|
||||
width: 0;
|
||||
background: none;
|
||||
}
|
||||
|
||||
#jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
#jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell,
|
||||
#jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row> .slick-cell.hovered {
|
||||
background: #dcdcdc !important;
|
||||
}
|
||||
|
||||
.vs-dark #jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
.vs-dark #jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row > .slick-cell.hovered,
|
||||
.vs-dark #jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell {
|
||||
background: #444444 !important;
|
||||
}
|
||||
|
||||
table.jobprevruns div.bar1, table.jobprevruns div.bar2, table.jobprevruns div.bar3,
|
||||
table.jobprevruns div.bar4, table.jobprevruns div.bar5 {
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
.jobview-grid .slick-cell.l10.r10 {
|
||||
text-align: center;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
table.jobprevruns {
|
||||
margin: auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
table.jobprevruns > tbody {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
@@ -7,31 +7,22 @@ import 'vs/css!./jobHistory';
|
||||
import 'vs/css!sql/media/icons/common-icons';
|
||||
import { OnInit, OnChanges, Component, Inject, Input, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, ChangeDetectionStrategy, Injectable } from '@angular/core';
|
||||
import { AgentJobHistoryInfo, AgentJobInfo } from 'sqlops';
|
||||
|
||||
import { Taskbar, ITaskbarContent } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||
import { RunJobAction, StopJobAction } from 'sql/parts/jobManagement/views/jobHistoryActions';
|
||||
import { JobCacheObject } from 'sql/parts/jobManagement/common/jobManagementService';
|
||||
import { AgentJobUtilities } from '../common/agentJobUtilities';
|
||||
import { PanelComponent } from 'sql/base/browser/ui/panel/panel.component';
|
||||
import { IJobManagementService } from '../common/interfaces';
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.component';
|
||||
import { JobHistoryController, JobHistoryDataSource,
|
||||
JobHistoryRenderer, JobHistoryFilter, JobHistoryModel, JobHistoryRow } from 'sql/parts/jobManagement/views/jobHistoryTree';
|
||||
import { JobStepsViewComponent } from 'sql/parts/jobManagement/views/jobStepsView.component';
|
||||
import { JobStepsViewRow } from './jobStepsViewTree';
|
||||
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { ITreeOptions } from 'vs/base/parts/tree/browser/tree';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
|
||||
@@ -301,7 +292,4 @@ export class JobHistoryComponent extends Disposable implements OnInit {
|
||||
this._showSteps = value;
|
||||
this._cd.detectChanges();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -245,6 +245,3 @@ jobhistory-component > .actionbar-container .monaco-action-bar > ul.actions-cont
|
||||
border-top: 3px solid #444444;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -8,9 +8,7 @@ import { Action } from 'vs/base/common/actions';
|
||||
import * as nls from 'vs/nls';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { BaseActionContext } from '../../../workbench/common/actions';
|
||||
import { JobHistoryComponent } from 'sql/parts/jobManagement/views/jobHistory.component';
|
||||
import { JobManagementService } from '../common/jobManagementService';
|
||||
import { IJobManagementService } from '../common/interfaces';
|
||||
|
||||
export enum JobHistoryActions {
|
||||
@@ -33,7 +31,7 @@ export class RunJobAction extends Action {
|
||||
let ownerUri = context.ownerUri;
|
||||
return new TPromise<boolean>((resolve, reject) => {
|
||||
this.jobManagementService.jobAction(ownerUri, jobName, JobHistoryActions.Run).then(result => {
|
||||
if (result.succeeded) {
|
||||
if (result.success) {
|
||||
var startMsg = nls.localize('jobSuccessfullyStarted', ': The job was successfully started.');
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Info,
|
||||
@@ -68,7 +66,7 @@ export class StopJobAction extends Action {
|
||||
let ownerUri = context.ownerUri;
|
||||
return new TPromise<boolean>((resolve, reject) => {
|
||||
this.jobManagementService.jobAction(ownerUri, jobName, JobHistoryActions.Stop).then(result => {
|
||||
if (result.succeeded) {
|
||||
if (result.success) {
|
||||
var stopMsg = nls.localize('jobSuccessfullyStopped', ': The job was successfully stopped.');
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Info,
|
||||
|
||||
@@ -3,33 +3,18 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
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/services/common/commonServiceInterface.service';
|
||||
import {
|
||||
NewQueryAction, ScriptSelectAction, EditDataAction, ScriptCreateAction, ScriptExecuteAction, ScriptAlterAction,
|
||||
BackupAction, ManageActionContext, BaseActionContext, ManageAction, RestoreAction
|
||||
} from 'sql/workbench/common/actions';
|
||||
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 * as tree from 'vs/base/parts/tree/browser/tree';
|
||||
import * as TreeDefaults from 'vs/base/parts/tree/browser/treeDefaults';
|
||||
import { Promise, TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { OEAction } from 'sql/parts/objectExplorer/viewlet/objectExplorerActions';
|
||||
import { $ } from 'vs/base/browser/builder';
|
||||
import { AgentJobHistoryInfo } from 'sqlops';
|
||||
import { Agent } from 'vs/base/node/request';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { JobHistoryComponent } from './jobHistory.component';
|
||||
|
||||
export class JobHistoryRow {
|
||||
runDate: string;
|
||||
|
||||
@@ -6,22 +6,14 @@
|
||||
import 'vs/css!./jobStepsView';
|
||||
|
||||
import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, Injectable, AfterContentChecked } from '@angular/core';
|
||||
|
||||
import { AgentJobHistoryInfo } from 'sqlops';
|
||||
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
|
||||
import { IJobManagementService } from '../common/interfaces';
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { JobStepsViewController, JobStepsViewDataSource, JobStepsViewFilter,
|
||||
JobStepsViewRenderer, JobStepsViewRow, JobStepsViewModel} from 'sql/parts/jobManagement/views/jobStepsViewTree';
|
||||
JobStepsViewRenderer, JobStepsViewModel} from 'sql/parts/jobManagement/views/jobStepsViewTree';
|
||||
import { JobHistoryComponent } from 'sql/parts/jobManagement/views/jobHistory.component';
|
||||
|
||||
export const JOBSTEPSVIEW_SELECTOR: string = 'jobstepsview-component';
|
||||
|
||||
@@ -3,29 +3,17 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
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/services/common/commonServiceInterface.service';
|
||||
import {
|
||||
NewQueryAction, ScriptSelectAction, EditDataAction, ScriptCreateAction, ScriptExecuteAction, ScriptAlterAction,
|
||||
BackupAction, ManageActionContext, BaseActionContext, ManageAction, RestoreAction
|
||||
} from 'sql/workbench/common/actions';
|
||||
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 * as tree from 'vs/base/parts/tree/browser/tree';
|
||||
import * as TreeDefaults from 'vs/base/parts/tree/browser/treeDefaults';
|
||||
import { Promise, TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { OEAction } from 'sql/parts/objectExplorer/viewlet/objectExplorerActions';
|
||||
import { AgentJobHistoryInfo } from 'sqlops';
|
||||
import { Agent } from 'vs/base/node/request';
|
||||
import { AgentJobUtilities } from 'sql/parts/jobManagement/common/agentJobUtilities';
|
||||
|
||||
export class JobStepsViewRow {
|
||||
|
||||
@@ -10,26 +10,26 @@ import 'vs/css!sql/parts/grid/media/slick.grid';
|
||||
import 'vs/css!sql/parts/grid/media/slickGrid';
|
||||
import 'vs/css!../common/media/jobs';
|
||||
import 'vs/css!sql/media/icons/common-icons';
|
||||
import 'vs/css!sql/base/browser/ui/table/media/table';
|
||||
|
||||
import { Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, AfterContentChecked } from '@angular/core';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
|
||||
import { Table } from 'sql/base/browser/ui/table/table';
|
||||
import { AgentViewComponent } from '../agent/agentView.component';
|
||||
import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.component';
|
||||
import { RowDetailView } from 'sql/base/browser/ui/table/plugins/rowdetailview';
|
||||
import { JobCacheObject } from 'sql/parts/jobManagement/common/jobManagementService';
|
||||
import { AgentJobUtilities } from '../common/agentJobUtilities';
|
||||
import { AgentJobUtilities } from 'sql/parts/jobManagement/common/agentJobUtilities';
|
||||
import { HeaderFilter } from 'sql/base/browser/ui/table/plugins/headerFilter.plugin';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { IJobManagementService } from '../common/interfaces';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { TabChild } from 'sql/base/browser/ui/panel/tab.component';
|
||||
|
||||
|
||||
export const JOBSVIEW_SELECTOR: string = 'jobsview-component';
|
||||
export const ROW_HEIGHT: number = 45;
|
||||
|
||||
@Component({
|
||||
selector: JOBSVIEW_SELECTOR,
|
||||
@@ -44,23 +44,35 @@ export class JobsViewComponent implements AfterContentChecked {
|
||||
private _disposables = new Array<vscode.Disposable>();
|
||||
|
||||
private columns: Array<Slick.Column<any>> = [
|
||||
{ name: nls.localize('jobColumns.name', 'Name'), field: 'name', formatter: this.renderName, width: 200, id: 'name' },
|
||||
{ name: nls.localize('jobColumns.lastRun', 'Last Run'), field: 'lastRun', width: 150, id: 'lastRun' },
|
||||
{ name: nls.localize('jobColumns.nextRun', 'Next Run'), field: 'nextRun', width: 150, id: 'nextRun' },
|
||||
{ name: nls.localize('jobColumns.enabled', 'Enabled'), field: 'enabled', width: 70, id: 'enabled' },
|
||||
{ name: nls.localize('jobColumns.status', 'Status'), field: 'currentExecutionStatus', width: 60, id: 'currentExecutionStatus' },
|
||||
{ name: nls.localize('jobColumns.category', 'Category'), field: 'category', width: 150, id: 'category' },
|
||||
{ name: nls.localize('jobColumns.runnable', 'Runnable'), field: 'runnable', width: 50, id: 'runnable' },
|
||||
{ name: nls.localize('jobColumns.schedule', 'Schedule'), field: 'hasSchedule', width: 50, id: 'hasSchedule' },
|
||||
{ name: nls.localize('jobColumns.lastRunOutcome', 'Last Run Outcome'), field: 'lastRunOutcome', width: 150, id: 'lastRunOutcome' },
|
||||
{ name: nls.localize('jobColumns.name','Name'), field: 'name', formatter: (row, cell, value, columnDef, dataContext) => this.renderName(row, cell, value, columnDef, dataContext), width: 200 , id: 'name' },
|
||||
{ name: nls.localize('jobColumns.lastRun','Last Run'), field: 'lastRun', width: 120, id: 'lastRun' },
|
||||
{ name: nls.localize('jobColumns.nextRun','Next Run'), field: 'nextRun', width: 120, id: 'nextRun' },
|
||||
{ name: nls.localize('jobColumns.enabled','Enabled'), field: 'enabled', width: 50, id: 'enabled' },
|
||||
{ name: nls.localize('jobColumns.status','Status'), field: 'currentExecutionStatus', width: 60, id: 'currentExecutionStatus' },
|
||||
{ name: nls.localize('jobColumns.category','Category'), field: 'category', width: 120, id: 'category' },
|
||||
{ name: nls.localize('jobColumns.runnable','Runnable'), field: 'runnable', width: 70, id: 'runnable' },
|
||||
{ name: nls.localize('jobColumns.schedule','Schedule'), field: 'hasSchedule', width: 60, id: 'hasSchedule' },
|
||||
{ name: nls.localize('jobColumns.lastRunOutcome', 'Last Run Outcome'), field: 'lastRunOutcome', width: 120, id: 'lastRunOutcome' },
|
||||
{ name: nls.localize('jobColumns.previousRuns', 'Previous Runs'), formatter: this.renderChartsPostHistory, field: 'previousRuns', width: 80, id: 'previousRuns'}
|
||||
];
|
||||
|
||||
|
||||
private options: Slick.GridOptions<any> = {
|
||||
syncColumnCellResize: true,
|
||||
enableColumnReorder: false,
|
||||
rowHeight: 45,
|
||||
enableCellNavigation: true,
|
||||
editable: true
|
||||
};
|
||||
|
||||
private rowDetail: RowDetailView;
|
||||
private dataView: Slick.Data.DataView<any>;
|
||||
private filterPlugin: any;
|
||||
private dataView: any;
|
||||
|
||||
@ViewChild('jobsgrid') _gridEl: ElementRef;
|
||||
private isVisible: boolean = false;
|
||||
private isInitialized: boolean = false;
|
||||
private isRefreshing: boolean = false;
|
||||
private _table: Table<any>;
|
||||
public jobs: sqlops.AgentJobInfo[];
|
||||
public jobHistories: { [jobId: string]: sqlops.AgentJobHistoryInfo[]; } = Object.create(null);
|
||||
@@ -68,13 +80,18 @@ export class JobsViewComponent implements AfterContentChecked {
|
||||
private _isCloud: boolean;
|
||||
private _showProgressWheel: boolean;
|
||||
private _tabHeight: number;
|
||||
private filterStylingMap: { [columnName: string]: [any] ;} = {};
|
||||
private filterStack = ['start'];
|
||||
private filterValueMap: { [columnName: string]: string[] ;} = {};
|
||||
private sortingStylingMap: { [columnName: string]: any; } = {};
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private _dashboardService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef,
|
||||
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
|
||||
@Inject(forwardRef(() => AgentViewComponent)) private _agentViewComponent: AgentViewComponent,
|
||||
@Inject(IJobManagementService) private _jobManagementService: IJobManagementService
|
||||
@Inject(IJobManagementService) private _jobManagementService: IJobManagementService,
|
||||
@Inject(IThemeService) private _themeService: IThemeService
|
||||
) {
|
||||
let jobCacheObjectMap = this._jobManagementService.jobCacheObjectMap;
|
||||
this._serverName = _dashboardService.connectionManagementService.connectionInfo.connectionProfile.serverName;
|
||||
@@ -111,10 +128,14 @@ export class JobsViewComponent implements AfterContentChecked {
|
||||
} else if (this.isVisible === true && this._agentViewComponent.refresh === true) {
|
||||
this._showProgressWheel = true;
|
||||
this.onFirstVisible(false);
|
||||
this.isRefreshing = true;
|
||||
this._agentViewComponent.refresh = false;
|
||||
} else if (this.isVisible === true && this._agentViewComponent.refresh === false) {
|
||||
this._showProgressWheel = true;
|
||||
this.onFirstVisible(true);
|
||||
if (!this.isRefreshing) {
|
||||
this._showProgressWheel = true;
|
||||
this.onFirstVisible(true);
|
||||
}
|
||||
this.isRefreshing = false;
|
||||
} else if (this.isVisible === true && this._gridEl.nativeElement.offsetParent === null) {
|
||||
this.isVisible = false;
|
||||
}
|
||||
@@ -129,7 +150,7 @@ export class JobsViewComponent implements AfterContentChecked {
|
||||
let options = <Slick.GridOptions<any>>{
|
||||
syncColumnCellResize: true,
|
||||
enableColumnReorder: false,
|
||||
rowHeight: 45,
|
||||
rowHeight: ROW_HEIGHT,
|
||||
enableCellNavigation: true,
|
||||
forceFitColumns: true
|
||||
};
|
||||
@@ -147,9 +168,11 @@ export class JobsViewComponent implements AfterContentChecked {
|
||||
panelRows: 1
|
||||
});
|
||||
this.rowDetail = rowDetail;
|
||||
|
||||
columns.unshift(this.rowDetail.getColumnDefinition());
|
||||
this._table = new Table(this._gridEl.nativeElement, undefined, columns, options);
|
||||
let filterPlugin = new HeaderFilter({}, this._themeService);
|
||||
this.filterPlugin = filterPlugin;
|
||||
$(this._gridEl.nativeElement).empty();
|
||||
this._table = new Table(this._gridEl.nativeElement, undefined, columns, this.options);
|
||||
this._table.grid.setData(this.dataView, true);
|
||||
this._table.grid.onClick.subscribe((e, args) => {
|
||||
let job = self.getJob(args);
|
||||
@@ -158,7 +181,7 @@ export class JobsViewComponent implements AfterContentChecked {
|
||||
self._agentViewComponent.showHistory = true;
|
||||
});
|
||||
if (cached && this._agentViewComponent.refresh !== true) {
|
||||
this.onJobsAvailable(this._jobCacheObject.jobs);
|
||||
this.onJobsAvailable(null);
|
||||
} else {
|
||||
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
|
||||
this._jobManagementService.getJobs(ownerUri).then((result) => {
|
||||
@@ -172,50 +195,137 @@ export class JobsViewComponent implements AfterContentChecked {
|
||||
}
|
||||
|
||||
private onJobsAvailable(jobs: sqlops.AgentJobInfo[]) {
|
||||
let jobViews = jobs.map((job) => {
|
||||
return {
|
||||
id: job.jobId,
|
||||
jobId: job.jobId,
|
||||
name: job.name,
|
||||
lastRun: AgentJobUtilities.convertToLastRun(job.lastRun),
|
||||
nextRun: AgentJobUtilities.convertToNextRun(job.nextRun),
|
||||
enabled: AgentJobUtilities.convertToResponse(job.enabled),
|
||||
currentExecutionStatus: AgentJobUtilities.convertToExecutionStatusString(job.currentExecutionStatus),
|
||||
category: job.category,
|
||||
runnable: AgentJobUtilities.convertToResponse(job.runnable),
|
||||
hasSchedule: AgentJobUtilities.convertToResponse(job.hasSchedule),
|
||||
lastRunOutcome: AgentJobUtilities.convertToStatusString(job.lastRunOutcome)
|
||||
};
|
||||
});
|
||||
let jobViews: any;
|
||||
let start: boolean = true;
|
||||
if (!jobs) {
|
||||
let dataView = this._jobCacheObject.dataView;
|
||||
jobViews = dataView.getItems();
|
||||
start = false;
|
||||
} else {
|
||||
jobViews = jobs.map((job) => {
|
||||
return {
|
||||
id: job.jobId,
|
||||
jobId: job.jobId,
|
||||
name: job.name,
|
||||
lastRun: AgentJobUtilities.convertToLastRun(job.lastRun),
|
||||
nextRun: AgentJobUtilities.convertToNextRun(job.nextRun),
|
||||
enabled: AgentJobUtilities.convertToResponse(job.enabled),
|
||||
currentExecutionStatus: AgentJobUtilities.convertToExecutionStatusString(job.currentExecutionStatus),
|
||||
category: job.category,
|
||||
runnable: AgentJobUtilities.convertToResponse(job.runnable),
|
||||
hasSchedule: AgentJobUtilities.convertToResponse(job.hasSchedule),
|
||||
lastRunOutcome: AgentJobUtilities.convertToStatusString(job.lastRunOutcome)
|
||||
};
|
||||
});
|
||||
}
|
||||
this._table.registerPlugin(<any>this.rowDetail);
|
||||
this.filterPlugin.onFilterApplied.subscribe((e, args) => {
|
||||
this.dataView.refresh();
|
||||
this._table.grid.resetActiveCell();
|
||||
let filterValues = args.column.filterValues;
|
||||
if (filterValues) {
|
||||
if (filterValues.length === 0) {
|
||||
// if an associated styling exists with the current filters
|
||||
if (this.filterStylingMap[args.column.name]) {
|
||||
let filterLength = this.filterStylingMap[args.column.name].length;
|
||||
// then remove the filtered styling
|
||||
for (let i = 0; i < filterLength; i++) {
|
||||
let lastAppliedStyle = this.filterStylingMap[args.column.name].pop();
|
||||
this._table.grid.removeCellCssStyles(lastAppliedStyle[0]);
|
||||
}
|
||||
delete this.filterStylingMap[args.column.name];
|
||||
let index = this.filterStack.indexOf(args.column.name, 0);
|
||||
if (index > -1) {
|
||||
this.filterStack.splice(index, 1);
|
||||
delete this.filterValueMap[args.column.name];
|
||||
}
|
||||
// apply the previous filter styling
|
||||
let currentItems = this.dataView.getFilteredItems();
|
||||
let styledItems = this.filterValueMap[this.filterStack[this.filterStack.length-1]][1];
|
||||
if (styledItems === currentItems) {
|
||||
let lastColStyle = this.filterStylingMap[this.filterStack[this.filterStack.length-1]];
|
||||
for (let i = 0; i < lastColStyle.length; i++) {
|
||||
this._table.grid.setCellCssStyles(lastColStyle[i][0], lastColStyle[i][1]);
|
||||
}
|
||||
} else {
|
||||
// style it all over again
|
||||
let seenJobs = 0;
|
||||
for (let i = 0; i < currentItems.length; i++) {
|
||||
this._table.grid.removeCellCssStyles('error-row'+i.toString());
|
||||
let item = this.dataView.getFilteredItems()[i];
|
||||
if (item.lastRunOutcome === 'Failed') {
|
||||
this.addToStyleHash(seenJobs, false, this.filterStylingMap, args.column.name);
|
||||
if (this.filterStack.indexOf(args.column.name) < 0) {
|
||||
this.filterStack.push(args.column.name);
|
||||
this.filterValueMap[args.column.name] = [filterValues];
|
||||
}
|
||||
// one expansion for the row and one for
|
||||
// the error detail
|
||||
seenJobs ++;
|
||||
i++;
|
||||
}
|
||||
seenJobs++;
|
||||
}
|
||||
this.dataView.refresh();
|
||||
this.filterValueMap[args.column.name].push(this.dataView.getFilteredItems());
|
||||
this._table.grid.resetActiveCell();
|
||||
}
|
||||
if (this.filterStack.length === 0) {
|
||||
this.filterStack = ['start'];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let seenJobs = 0;
|
||||
for (let i = 0; i < this.jobs.length; i++) {
|
||||
this._table.grid.removeCellCssStyles('error-row'+i.toString());
|
||||
let item = this.dataView.getItemByIdx(i);
|
||||
// current filter
|
||||
if (_.contains(filterValues, item[args.column.field])) {
|
||||
// check all previous filters
|
||||
if (this.checkPreviousFilters(item)) {
|
||||
if (item.lastRunOutcome === 'Failed') {
|
||||
this.addToStyleHash(seenJobs, false, this.filterStylingMap, args.column.name);
|
||||
if (this.filterStack.indexOf(args.column.name) < 0) {
|
||||
this.filterStack.push(args.column.name);
|
||||
this.filterValueMap[args.column.name] = [filterValues];
|
||||
}
|
||||
// one expansion for the row and one for
|
||||
// the error detail
|
||||
seenJobs ++;
|
||||
i++;
|
||||
}
|
||||
seenJobs++;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.dataView.refresh();
|
||||
if (this.filterValueMap[args.column.name]) {
|
||||
this.filterValueMap[args.column.name].push(this.dataView.getFilteredItems());
|
||||
} else {
|
||||
this.filterValueMap[args.column.name] = this.dataView.getFilteredItems();
|
||||
}
|
||||
|
||||
this.rowDetail.onBeforeRowDetailToggle.subscribe(function (e, args) {
|
||||
this._table.grid.resetActiveCell();
|
||||
}
|
||||
} else {
|
||||
this.expandJobs(false);
|
||||
}
|
||||
});
|
||||
this.rowDetail.onAfterRowDetailToggle.subscribe(function (e, args) {
|
||||
});
|
||||
this.rowDetail.onAsyncEndUpdate.subscribe(function (e, args) {
|
||||
this.filterPlugin.onCommand.subscribe((e, args: any) => {
|
||||
this.columnSort(args.column.name, args.command === 'sort-asc');
|
||||
});
|
||||
this._table.registerPlugin(<HeaderFilter>this.filterPlugin);
|
||||
|
||||
this.dataView.beginUpdate();
|
||||
this.dataView.setItems(jobViews);
|
||||
this.dataView.setFilter((item) => this.filter(item));
|
||||
|
||||
this.dataView.endUpdate();
|
||||
this._table.autosizeColumns();
|
||||
this._table.resizeCanvas();
|
||||
let expandedJobs = this._agentViewComponent.expanded;
|
||||
let expansions = 0;
|
||||
for (let i = 0; i < jobs.length; i++) {
|
||||
let job = jobs[i];
|
||||
if (job.lastRunOutcome === 0 && !expandedJobs.get(job.jobId)) {
|
||||
this.expandJobRowDetails(i + expandedJobs.size);
|
||||
this.addToStyleHash(i + expandedJobs.size);
|
||||
this._agentViewComponent.setExpanded(job.jobId, 'Loading Error...');
|
||||
} else if (job.lastRunOutcome === 0 && expandedJobs.get(job.jobId)) {
|
||||
this.expandJobRowDetails(i + expansions);
|
||||
this.addToStyleHash(i + expansions);
|
||||
expansions++;
|
||||
}
|
||||
}
|
||||
|
||||
this.expandJobs(start);
|
||||
// tooltip for job name
|
||||
$('.jobview-jobnamerow').hover(e => {
|
||||
let currentTarget = e.currentTarget;
|
||||
currentTarget.title = currentTarget.innerText;
|
||||
@@ -244,7 +354,56 @@ export class JobsViewComponent implements AfterContentChecked {
|
||||
$('#jobsDiv .jobview-grid .slick-cell.l1.r1 .jobview-jobnametext').css('width', `${nameWidth - 10}px`);
|
||||
// adjust error message when resized
|
||||
$('#jobsDiv .jobview-grid .slick-cell.l1.r1.error-row .jobview-jobnametext').css('width', '100%');
|
||||
|
||||
// generate job charts again
|
||||
self.jobs.forEach(job => {
|
||||
let jobId = job.jobId;
|
||||
let jobHistories = self._jobCacheObject.getJobHistory(job.jobId);
|
||||
let previousRuns = jobHistories.slice(jobHistories.length-5, jobHistories.length);
|
||||
self.createJobChart(job.jobId, previousRuns);
|
||||
});
|
||||
});
|
||||
$('#jobsDiv .jobview-grid .monaco-table .slick-viewport .grid-canvas .ui-widget-content.slick-row').hover((e) => {
|
||||
// highlight the error row as well if a failing job row is hovered
|
||||
if (e.currentTarget.children.item(0).classList.contains('job-with-error')) {
|
||||
let target = $(e.currentTarget);
|
||||
let targetChildren = $(e.currentTarget.children);
|
||||
let siblings = target.nextAll().toArray();
|
||||
let top = parseInt(target.css('top'), 10);
|
||||
for (let i = 0; i < siblings.length; i++) {
|
||||
let sibling = siblings[i];
|
||||
let siblingTop = parseInt($(sibling).css('top'), 10);
|
||||
if (siblingTop === top + ROW_HEIGHT) {
|
||||
$(sibling.children).addClass('hovered');
|
||||
sibling.onmouseenter = (e) => {
|
||||
targetChildren.addClass('hovered');
|
||||
};
|
||||
sibling.onmouseleave = (e) => {
|
||||
targetChildren.removeClass('hovered');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, (e) => {
|
||||
// switch back to original background
|
||||
if (e.currentTarget.children.item(0).classList.contains('job-with-error')) {
|
||||
let target = $(e.currentTarget);
|
||||
let siblings = target.nextAll().toArray();
|
||||
let top = parseInt(target.css('top'), 10);
|
||||
for (let i = 0; i < siblings.length; i++) {
|
||||
let sibling = siblings[i];
|
||||
let siblingTop = parseInt($(sibling).css('top'), 10);
|
||||
if (siblingTop === top + ROW_HEIGHT) {
|
||||
$(sibling.children).removeClass('hovered');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// cache the dataview for future use
|
||||
this._jobCacheObject.dataView = this.dataView;
|
||||
this.filterValueMap['start'] = [[], this.dataView.getItems()];
|
||||
this.loadJobHistories();
|
||||
}
|
||||
|
||||
@@ -261,20 +420,34 @@ export class JobsViewComponent implements AfterContentChecked {
|
||||
'category': errorClass,
|
||||
'runnable': errorClass,
|
||||
'hasSchedule': errorClass,
|
||||
'lastRunOutcome': errorClass
|
||||
'lastRunOutcome': errorClass,
|
||||
'previousRuns': errorClass
|
||||
};
|
||||
return hash;
|
||||
}
|
||||
|
||||
private addToStyleHash(row: number) {
|
||||
let hash: {
|
||||
private addToStyleHash(row: number, start: boolean, map: any, columnName: string) {
|
||||
let hash : {
|
||||
[index: number]: {
|
||||
[id: string]: string;
|
||||
}
|
||||
} = {};
|
||||
hash = this.setRowWithErrorClass(hash, row, 'job-with-error');
|
||||
hash = this.setRowWithErrorClass(hash, row + 1, 'error-row');
|
||||
this._table.grid.setCellCssStyles('error-row' + row.toString(), hash);
|
||||
hash = this.setRowWithErrorClass(hash, row+1, 'error-row');
|
||||
if (start) {
|
||||
if (map['start']) {
|
||||
map['start'].push(['error-row'+row.toString(), hash]);
|
||||
} else {
|
||||
map['start'] = [['error-row'+row.toString(), hash]];
|
||||
}
|
||||
} else {
|
||||
if (map[columnName]) {
|
||||
map[columnName].push(['error-row'+row.toString(), hash]);
|
||||
} else {
|
||||
map[columnName] = [['error-row'+row.toString(), hash]];
|
||||
}
|
||||
}
|
||||
this._table.grid.setCellCssStyles('error-row'+row.toString(), hash);
|
||||
}
|
||||
|
||||
private renderName(row, cell, value, columnDef, dataContext) {
|
||||
@@ -303,6 +476,17 @@ export class JobsViewComponent implements AfterContentChecked {
|
||||
'</tr></table>';
|
||||
}
|
||||
|
||||
private renderChartsPostHistory(row, cell, value, columnDef, dataContext) {
|
||||
return `<table class="jobprevruns" id="${dataContext.id}">
|
||||
<tr>
|
||||
<td><div class="bar1"></div></td>
|
||||
<td><div class="bar2"></div></td>
|
||||
<td><div class="bar3"></div></td>
|
||||
<td><div class="bar4"></div></td>
|
||||
</tr>
|
||||
</table>`;
|
||||
}
|
||||
|
||||
private expandJobRowDetails(rowIdx: number, message?: string): void {
|
||||
let item = this.dataView.getItemByIdx(rowIdx);
|
||||
item.message = this._agentViewComponent.expanded.get(item.jobId);
|
||||
@@ -336,6 +520,17 @@ export class JobsViewComponent implements AfterContentChecked {
|
||||
return [failing, nonFailing];
|
||||
}
|
||||
|
||||
private checkPreviousFilters(item): boolean {
|
||||
for (let column in this.filterValueMap) {
|
||||
if (column !== 'start' && this.filterValueMap[column][0].length > 0) {
|
||||
if (!_.contains(this.filterValueMap[column][0], item[AgentJobUtilities.convertColNameToField(column)])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private isErrorRow(cell: HTMLElement) {
|
||||
return cell.classList.contains('error-row');
|
||||
}
|
||||
@@ -361,11 +556,14 @@ export class JobsViewComponent implements AfterContentChecked {
|
||||
if (result && result.jobs) {
|
||||
self.jobHistories[job.jobId] = result.jobs;
|
||||
self._jobCacheObject.setJobHistory(job.jobId, result.jobs);
|
||||
let jobHistories = self._jobCacheObject.getJobHistory(job.jobId);
|
||||
let previousRuns = jobHistories.slice(jobHistories.length-5, jobHistories.length);
|
||||
self.createJobChart(job.jobId, previousRuns);
|
||||
if (self._agentViewComponent.expanded.has(job.jobId)) {
|
||||
let jobHistory = self._jobCacheObject.getJobHistory(job.jobId)[result.jobs.length - 1];
|
||||
let lastJobHistory = jobHistories[result.jobs.length-1];
|
||||
let item = self.dataView.getItemById(job.jobId + '.error');
|
||||
let noStepsMessage = nls.localize('jobsView.noSteps', 'No Steps available for this job.');
|
||||
let errorMessage = jobHistory ? jobHistory.message : noStepsMessage;
|
||||
let errorMessage = lastJobHistory ? lastJobHistory.message: noStepsMessage;
|
||||
item['name'] = nls.localize('jobsView.error', 'Error: ') + errorMessage;
|
||||
self._agentViewComponent.setExpanded(job.jobId, item['name']);
|
||||
self.dataView.updateItem(job.jobId + '.error', item);
|
||||
@@ -374,4 +572,216 @@ export class JobsViewComponent implements AfterContentChecked {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private createJobChart(jobId: string, jobHistories: sqlops.AgentJobHistoryInfo[]): void {
|
||||
let chartHeights = this.getChartHeights(jobHistories);
|
||||
for (let i = 0; i < jobHistories.length; i++) {
|
||||
let runGraph = $(`table#${jobId}.jobprevruns > tbody > tr > td > div.bar${i+1}`);
|
||||
if (jobHistories && jobHistories.length > 0) {
|
||||
runGraph.css('height', chartHeights[i]);
|
||||
let bgColor = jobHistories[i].runStatus === 0 ? 'red' : 'green';
|
||||
runGraph.css('background', bgColor);
|
||||
runGraph.hover((e) => {
|
||||
let currentTarget = e.currentTarget;
|
||||
currentTarget.title = jobHistories[i].runDuration;
|
||||
});
|
||||
} else {
|
||||
runGraph.css('height', '5px');
|
||||
runGraph.css('background', 'red');
|
||||
runGraph.hover((e) => {
|
||||
let currentTarget = e.currentTarget;
|
||||
currentTarget.title = 'Job not run.';
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// chart height normalization logic
|
||||
private getChartHeights(jobHistories: sqlops.AgentJobHistoryInfo[]): string[] {
|
||||
if (!jobHistories || jobHistories.length === 0) {
|
||||
return ['5px','5px','5px','5px','5px'];
|
||||
}
|
||||
let maxDuration: number = 0;
|
||||
jobHistories.forEach(history => {
|
||||
let historyDuration = AgentJobUtilities.convertDurationToSeconds(history.runDuration) ;
|
||||
if (historyDuration > maxDuration) {
|
||||
maxDuration = historyDuration;
|
||||
}
|
||||
});
|
||||
maxDuration = maxDuration === 0 ? 1 : maxDuration;
|
||||
let maxBarHeight: number = 24;
|
||||
let chartHeights = [];
|
||||
for (let i = 0; i < jobHistories.length; i++) {
|
||||
let duration = jobHistories[i].runDuration;
|
||||
let chartHeight = (maxBarHeight * AgentJobUtilities.convertDurationToSeconds(duration))/maxDuration;
|
||||
chartHeights.push(`${chartHeight}px`);
|
||||
}
|
||||
return chartHeights;
|
||||
}
|
||||
|
||||
private expandJobs(start: boolean): void {
|
||||
if (start) {
|
||||
this._agentViewComponent.expanded = new Map<string, string>();
|
||||
}
|
||||
let expandedJobs = this._agentViewComponent.expanded;
|
||||
let expansions = 0;
|
||||
for (let i = 0; i < this.jobs.length; i++){
|
||||
let job = this.jobs[i];
|
||||
if (job.lastRunOutcome === 0 && !expandedJobs.get(job.jobId)) {
|
||||
this.expandJobRowDetails(i+expandedJobs.size);
|
||||
this.addToStyleHash(i+expandedJobs.size, start, this.filterStylingMap, undefined);
|
||||
this._agentViewComponent.setExpanded(job.jobId, 'Loading Error...');
|
||||
} else if (job.lastRunOutcome === 0 && expandedJobs.get(job.jobId)) {
|
||||
this.addToStyleHash(i+expansions, start, this.filterStylingMap, undefined);
|
||||
expansions++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private filter(item: any) {
|
||||
let columns = this._table.grid.getColumns();
|
||||
let value = true;
|
||||
for (let i = 0; i < columns.length; i++) {
|
||||
let col: any = columns[i];
|
||||
let filterValues = col.filterValues;
|
||||
if (filterValues && filterValues.length > 0) {
|
||||
if (item._parent) {
|
||||
value = value && _.contains(filterValues, item._parent[col.field]);
|
||||
} else {
|
||||
value = value && _.contains(filterValues, item[col.field]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private columnSort(column: string, isAscending: boolean) {
|
||||
let items = this.dataView.getItems();
|
||||
// get error items here and remove them
|
||||
let jobItems = items.filter(x => x._parent === undefined);
|
||||
let errorItems = items.filter(x => x._parent !== undefined);
|
||||
this.sortingStylingMap[column] = items;
|
||||
switch(column) {
|
||||
case('Name'): {
|
||||
this.dataView.setItems(jobItems);
|
||||
// sort the actual jobs
|
||||
this.dataView.sort((item1, item2) => {
|
||||
return item1.name.localeCompare(item2.name);
|
||||
}, isAscending);
|
||||
break;
|
||||
}
|
||||
case('Last Run'): {
|
||||
this.dataView.setItems(jobItems);
|
||||
// sort the actual jobs
|
||||
this.dataView.sort((item1, item2) => this.dateCompare(item1, item2, true), isAscending);
|
||||
break;
|
||||
}
|
||||
case ('Next Run') : {
|
||||
this.dataView.setItems(jobItems);
|
||||
// sort the actual jobs
|
||||
this.dataView.sort((item1, item2) => this.dateCompare(item1, item2, false), isAscending);
|
||||
break;
|
||||
}
|
||||
case ('Enabled'): {
|
||||
this.dataView.setItems(jobItems);
|
||||
// sort the actual jobs
|
||||
this.dataView.sort((item1, item2) => {
|
||||
return item1.enabled.localeCompare(item2.enabled);
|
||||
}, isAscending);
|
||||
break;
|
||||
}
|
||||
case ('Status'): {
|
||||
this.dataView.setItems(jobItems);
|
||||
// sort the actual jobs
|
||||
this.dataView.sort((item1, item2) => {
|
||||
return item1.currentExecutionStatus.localeCompare(item2.currentExecutionStatus);
|
||||
}, isAscending);
|
||||
break;
|
||||
}
|
||||
case ('Category'): {
|
||||
this.dataView.setItems(jobItems);
|
||||
// sort the actual jobs
|
||||
this.dataView.sort((item1, item2) => {
|
||||
return item1.category.localeCompare(item2.category);
|
||||
}, isAscending);
|
||||
break;
|
||||
}
|
||||
case ('Runnable'): {
|
||||
this.dataView.setItems(jobItems);
|
||||
// sort the actual jobs
|
||||
this.dataView.sort((item1, item2) => {
|
||||
return item1.runnable.localeCompare(item2.runnable);
|
||||
}, isAscending);
|
||||
break;
|
||||
}
|
||||
case ('Schedule'): {
|
||||
this.dataView.setItems(jobItems);
|
||||
// sort the actual jobs
|
||||
this.dataView.sort((item1, item2) => {
|
||||
return item1.hasSchedule.localeCompare(item2.hasSchedule);
|
||||
}, isAscending);
|
||||
break;
|
||||
}
|
||||
case ('Last Run Outcome'): {
|
||||
this.dataView.setItems(jobItems);
|
||||
// sort the actual jobs
|
||||
this.dataView.sort((item1, item2) => {
|
||||
return item1.lastRunOutcome.localeCompare(item2.lastRunOutcome);
|
||||
}, isAscending);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// insert the errors back again
|
||||
let jobItemsLength = jobItems.length;
|
||||
for (let i = 0; i < jobItemsLength; i++) {
|
||||
let item = jobItems[i];
|
||||
if (item._child) {
|
||||
let child = errorItems.find(error => error === item._child);
|
||||
jobItems.splice(i+1, 0, child);
|
||||
jobItemsLength++;
|
||||
}
|
||||
}
|
||||
this.dataView.setItems(jobItems);
|
||||
// remove old style
|
||||
if (this.filterStylingMap[column]) {
|
||||
let filterLength = this.filterStylingMap[column].length;
|
||||
for (let i = 0; i < filterLength; i++) {
|
||||
let lastAppliedStyle = this.filterStylingMap[column].pop();
|
||||
this._table.grid.removeCellCssStyles(lastAppliedStyle[0]);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < this.jobs.length; i++) {
|
||||
this._table.grid.removeCellCssStyles('error-row'+i.toString());
|
||||
}
|
||||
}
|
||||
// add new style to the items back again
|
||||
items = this.filterStack.length > 1 ? this.dataView.getFilteredItems() : this.dataView.getItems();
|
||||
for (let i = 0; i < items.length; i ++) {
|
||||
let item = items[i];
|
||||
if (item.lastRunOutcome === 'Failed') {
|
||||
this.addToStyleHash(i, false, this.sortingStylingMap, column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private dateCompare(item1: any, item2: any, lastRun: boolean): number {
|
||||
let exceptionString = lastRun ? 'Never Run' : 'Not Scheduled';
|
||||
if (item2.lastRun === exceptionString && item1.lastRun !== exceptionString) {
|
||||
return -1;
|
||||
} else if (item1.lastRun === exceptionString && item2.lastRun !== exceptionString) {
|
||||
return 1;
|
||||
} else if (item1.lastRun === exceptionString && item2.lastRun === exceptionString) {
|
||||
return 0;
|
||||
} else {
|
||||
let date1 = new Date(item1.lastRun);
|
||||
let date2 = new Date(item2.lastRun);
|
||||
if (date1 > date2) {
|
||||
return 1;
|
||||
} else if (date1 === date2) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } fro
|
||||
import { attachButtonStyler } from 'sql/common/theme/styler';
|
||||
import { Button } from 'sql/base/browser/ui/button/button';
|
||||
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { SIDE_BAR_BACKGROUND, SIDE_BAR_TITLE_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||
import URI from 'vs/base/common/uri';
|
||||
@@ -55,13 +55,11 @@ export default class ButtonComponent extends ComponentBase implements IComponent
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
if (this._inputContainer) {
|
||||
|
||||
|
||||
this._button = new Button(this._inputContainer.nativeElement);
|
||||
|
||||
this._register(this._button);
|
||||
this._register(attachButtonStyler(this._button, this.themeService, {
|
||||
buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND
|
||||
buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND, buttonForeground: SIDE_BAR_TITLE_FOREGROUND
|
||||
}));
|
||||
this._register(this._button.onDidClick(e => {
|
||||
this._onEventEmitter.fire({
|
||||
@@ -94,6 +92,12 @@ export default class ButtonComponent extends ComponentBase implements IComponent
|
||||
super.setProperties(properties);
|
||||
this._button.enabled = this.enabled;
|
||||
this._button.label = this.label;
|
||||
if (this.width) {
|
||||
this._button.setWidth(this.width.toString());
|
||||
}
|
||||
if (this.height) {
|
||||
this._button.setWidth(this.height.toString());
|
||||
}
|
||||
this.updateIcon();
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ export default class CheckBoxComponent extends ComponentBase implements ICompone
|
||||
|
||||
this._register(this._input);
|
||||
this._register(this._input.onChange(e => {
|
||||
this.value = this._input.checked;
|
||||
this.checked = this._input.checked;
|
||||
this._onEventEmitter.fire({
|
||||
eventType: ComponentEventType.onDidChange,
|
||||
args: e
|
||||
@@ -88,10 +88,10 @@ export default class CheckBoxComponent extends ComponentBase implements ICompone
|
||||
// CSS-bound properties
|
||||
|
||||
public get checked(): boolean {
|
||||
return this.getPropertyOrDefault<sqlops.CheckBoxProperties, boolean>((props) => props.value, false);
|
||||
return this.getPropertyOrDefault<sqlops.CheckBoxProperties, boolean>((props) => props.checked, false);
|
||||
}
|
||||
|
||||
public set value(newValue: boolean) {
|
||||
public set checked(newValue: boolean) {
|
||||
this.setPropertyFromUI<sqlops.CheckBoxProperties, boolean>((properties, value) => { properties.checked = value; }, newValue);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import * as types from 'vs/base/common/types';
|
||||
|
||||
import { IComponent, IComponentDescriptor, IModelStore, IComponentEventArgs, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||
import { FlexLayout, FlexItemLayout } from 'sqlops';
|
||||
import * as sqlops from 'sqlops';
|
||||
import { ComponentHostDirective } from 'sql/parts/dashboard/common/componentHost.directive';
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
@@ -112,6 +112,51 @@ export abstract class ComponentBase extends Disposable implements IComponent, On
|
||||
this.setProperties(properties);
|
||||
}
|
||||
|
||||
public get height(): number | string {
|
||||
return this.getPropertyOrDefault<sqlops.ComponentProperties, number | string>((props) => props.height, undefined);
|
||||
}
|
||||
|
||||
public set height(newValue: number | string) {
|
||||
this.setPropertyFromUI<sqlops.ComponentProperties, number | string>((props, value) => props.height = value, newValue);
|
||||
}
|
||||
|
||||
public get width(): number | string {
|
||||
return this.getPropertyOrDefault<sqlops.ComponentProperties, number | string>((props) => props.width, undefined);
|
||||
}
|
||||
|
||||
public set width(newValue: number | string) {
|
||||
this.setPropertyFromUI<sqlops.ComponentProperties, number | string>((props, value) => props.width = value, newValue);
|
||||
}
|
||||
|
||||
protected convertSizeToNumber(size: number | string): number {
|
||||
if (size && typeof (size) === 'string') {
|
||||
if (size.toLowerCase().endsWith('px')) {
|
||||
return +size.replace('px', '');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return +size;
|
||||
}
|
||||
|
||||
protected getWidth(): string {
|
||||
return this.width ? this.convertSize(this.width) : '';
|
||||
}
|
||||
|
||||
protected getHeight(): string {
|
||||
return this.height ? this.convertSize(this.height) : '';
|
||||
}
|
||||
|
||||
protected convertSize(size: number | string): string {
|
||||
if (types.isUndefinedOrNull(size)) {
|
||||
return '100%';
|
||||
}
|
||||
let convertedSize: string = size ? size.toString() : '100%';
|
||||
if (!convertedSize.toLowerCase().endsWith('px') && !convertedSize.toLowerCase().endsWith('%')) {
|
||||
convertedSize = convertedSize + 'px';
|
||||
}
|
||||
return convertedSize;
|
||||
}
|
||||
|
||||
public get valid(): boolean {
|
||||
return this._valid;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import GroupContainer from './groupContainer.component';
|
||||
import CardComponent from './card.component';
|
||||
import InputBoxComponent from './inputbox.component';
|
||||
import DropDownComponent from './dropdown.component';
|
||||
import DeclarativeTableComponent from './declarativeTable.component';
|
||||
import ListBoxComponent from './listbox.component';
|
||||
import ButtonComponent from './button.component';
|
||||
import CheckBoxComponent from './checkbox.component';
|
||||
import RadioButtonComponent from './radioButton.component';
|
||||
@@ -41,6 +43,12 @@ registerComponentType(INPUTBOX_COMPONENT, ModelComponentTypes.InputBox, InputBox
|
||||
export const DROPDOWN_COMPONENT = 'dropdown-component';
|
||||
registerComponentType(DROPDOWN_COMPONENT, ModelComponentTypes.DropDown, DropDownComponent);
|
||||
|
||||
export const DECLARATIVETABLE_COMPONENT = 'declarativeTable-component';
|
||||
registerComponentType(DECLARATIVETABLE_COMPONENT, ModelComponentTypes.DeclarativeTable, DeclarativeTableComponent);
|
||||
|
||||
export const LISTBOX_COMPONENT = 'lisbox-component';
|
||||
registerComponentType(LISTBOX_COMPONENT, ModelComponentTypes.ListBox, ListBoxComponent);
|
||||
|
||||
export const BUTTON_COMPONENT = 'button-component';
|
||||
registerComponentType(BUTTON_COMPONENT, ModelComponentTypes.Button, ButtonComponent);
|
||||
|
||||
|
||||
194
src/sql/parts/modelComponents/declarativeTable.component.ts
Normal file
194
src/sql/parts/modelComponents/declarativeTable.component.ts
Normal file
@@ -0,0 +1,194 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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!./declarativeTable';
|
||||
import {
|
||||
Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver,
|
||||
ViewChild, ViewChildren, ElementRef, Injector, OnDestroy, QueryList, AfterViewInit
|
||||
} from '@angular/core';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
import { ComponentBase } from 'sql/parts/modelComponents/componentBase';
|
||||
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox.component';
|
||||
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox.component';
|
||||
import { ISelectData } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox.component';
|
||||
import * as nls from 'vs/nls';
|
||||
|
||||
export enum DeclarativeDataType {
|
||||
string = 'string',
|
||||
category = 'category',
|
||||
boolean = 'boolean'
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'modelview-declarativeTable',
|
||||
template: `
|
||||
<table role=grid aria-labelledby="ID_REF" #container *ngIf="columns" class="declarative-table">
|
||||
<ng-container *ngFor="let column of columns;let h = index">
|
||||
<th class="declarative-table-header" tabindex="-1" role="button" aria-sort="none">{{column.displayName}}</th>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="data">
|
||||
<ng-container *ngFor="let row of data;let r = index">
|
||||
<tr class="declarative-table-row">
|
||||
<ng-container *ngFor="let cellData of row;let c = index">
|
||||
<td class="declarative-table-cell" tabindex="-1" role="button" [style.width]="getColumnWidth(c)">
|
||||
<checkbox *ngIf="isCheckBox(c)" label="" (onChange)="onCheckBoxChanged($event,r,c)" [enabled]="isControlEnabled(c)" [checked]="isChecked(r,c)"></checkbox>
|
||||
<select-box *ngIf="isSelectBox(c)" [options]="GetOptions(c)" (onDidSelect)="onSelectBoxChanged($event,r,c)" [selectedOption]="GetSelectedOptionDisplayName(r,c)"></select-box>
|
||||
<input-box *ngIf="isInputBox(c)" [value]="cellData" (onDidChange)="onInputBoxChanged($event,r,c)"></input-box>
|
||||
<ng-container *ngIf="isLabel(c)" >{{cellData}}</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
</tr>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</table>
|
||||
`
|
||||
})
|
||||
export default class DeclarativeTableComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit {
|
||||
@Input() descriptor: IComponentDescriptor;
|
||||
@Input() modelStore: IModelStore;
|
||||
|
||||
@ViewChild('container', { read: ElementRef }) private _tableContainer: ElementRef;
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
|
||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
||||
@Inject(IContextViewService) private contextViewService: IContextViewService
|
||||
) {
|
||||
super(changeRef);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.baseInit();
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
}
|
||||
|
||||
public validate(): Thenable<boolean> {
|
||||
return super.validate().then(valid => {
|
||||
return valid;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.baseDestroy();
|
||||
}
|
||||
|
||||
private isCheckBox(cell: number): boolean {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
return column.valueType === DeclarativeDataType.boolean;
|
||||
}
|
||||
|
||||
private isControlEnabled(cell: number): boolean {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
return !column.isReadOnly;
|
||||
}
|
||||
|
||||
private isLabel(cell: number): boolean {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
return column.isReadOnly && column.valueType === DeclarativeDataType.string;
|
||||
}
|
||||
|
||||
private isChecked(row: number, cell: number): boolean {
|
||||
let cellData = this.data[row][cell];
|
||||
return cellData;
|
||||
}
|
||||
|
||||
private onInputBoxChanged(e: string, row: number, cell: number): void {
|
||||
this.onCellDataChanged(e, row, cell);
|
||||
}
|
||||
|
||||
private onCheckBoxChanged(e: boolean, row: number, cell: number): void {
|
||||
this.onCellDataChanged(e, row, cell);
|
||||
}
|
||||
|
||||
private onSelectBoxChanged(e: ISelectData, row: number, cell: number): void {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
if (column.categoryValues) {
|
||||
this.onCellDataChanged(column.categoryValues[e.index].name, row, cell);
|
||||
}
|
||||
}
|
||||
|
||||
private onCellDataChanged(newValue: any, row: number, cell: number): void {
|
||||
this.data[row][cell] = newValue;
|
||||
this.data = this.data;
|
||||
let newCellData : sqlops.TableCell = {
|
||||
row: row,
|
||||
column: cell,
|
||||
value: newValue
|
||||
};
|
||||
this._onEventEmitter.fire({
|
||||
eventType: ComponentEventType.onDidChange,
|
||||
args: newCellData
|
||||
});
|
||||
}
|
||||
|
||||
private isSelectBox(cell: number): boolean {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
return column.valueType === DeclarativeDataType.category;
|
||||
}
|
||||
|
||||
private isInputBox(cell: number): boolean {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
return column.valueType === DeclarativeDataType.string && !column.isReadOnly;
|
||||
}
|
||||
|
||||
private getColumnWidth(cell: number): string {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
return this.convertSize(column.width);
|
||||
}
|
||||
|
||||
private GetOptions(cell: number): string[] {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
return column.categoryValues ? column.categoryValues.map(x => x.displayName) : [];
|
||||
}
|
||||
|
||||
private GetSelectedOptionDisplayName(row: number, cell: number): string {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
let cellData = this.data[row][cell];
|
||||
if (cellData && column.categoryValues) {
|
||||
let category = column.categoryValues.find(v => v.name === cellData);
|
||||
return category.displayName;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
public setLayout(layout: any): void {
|
||||
// TODO allow configuring the look and feel
|
||||
this.layout();
|
||||
}
|
||||
|
||||
public setProperties(properties: { [key: string]: any; }): void {
|
||||
super.setProperties(properties);
|
||||
}
|
||||
|
||||
public get data(): any[][] {
|
||||
return this.getPropertyOrDefault<sqlops.DeclarativeTableProperties, any[]>((props) => props.data, []);
|
||||
}
|
||||
|
||||
public set data(newValue: any[][]) {
|
||||
this.setPropertyFromUI<sqlops.DeclarativeTableProperties, any[][]>((props, value) => props.data = value, newValue);
|
||||
}
|
||||
|
||||
public get columns(): sqlops.DeclarativeTableColumn[] {
|
||||
return this.getPropertyOrDefault<sqlops.DeclarativeTableProperties, sqlops.DeclarativeTableColumn[]>((props) => props.columns, []);
|
||||
}
|
||||
|
||||
public set columns(newValue: sqlops.DeclarativeTableColumn[]) {
|
||||
this.setPropertyFromUI<sqlops.DeclarativeTableProperties, sqlops.DeclarativeTableColumn[]>((props, value) => props.columns = value, newValue);
|
||||
}
|
||||
}
|
||||
41
src/sql/parts/modelComponents/declarativeTable.css
Normal file
41
src/sql/parts/modelComponents/declarativeTable.css
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
.declarative-table {
|
||||
padding: 5px 30px 0px 30px;
|
||||
box-sizing: border-box;
|
||||
width:100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.declarative-table-row {
|
||||
}
|
||||
|
||||
.declarative-table-header {
|
||||
padding: 5px;
|
||||
border: 1px solid gray;
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
|
||||
.vs-dark .declarative-table-header {
|
||||
padding: 5px;
|
||||
border: 1px solid gray;
|
||||
background-color: #333334;
|
||||
}
|
||||
|
||||
.hc-black .declarative-table-header {
|
||||
padding: 5px;
|
||||
border: 1px solid gray;
|
||||
background-color: #333334;
|
||||
}
|
||||
|
||||
.declarative-table-cell {
|
||||
padding: 5px;
|
||||
border: 1px solid gray;
|
||||
}
|
||||
|
||||
[role="gridcell"]:focus,
|
||||
[role="gridcell"] *:focus,
|
||||
[role="grid"] [tabindex="0"]:focus {
|
||||
outline: #005a9c;
|
||||
outline-style: dotted;
|
||||
outline-width: 3px;
|
||||
}
|
||||
@@ -15,7 +15,8 @@ import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } fro
|
||||
import { Dropdown, IDropdownOptions } from 'sql/base/browser/ui/editableDropdown/dropdown';
|
||||
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { attachEditableDropdownStyler , attachSelectBoxStyler} from 'sql/common/theme/styler';
|
||||
import { attachEditableDropdownStyler } from 'sql/common/theme/styler';
|
||||
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
|
||||
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
@@ -26,7 +27,7 @@ import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||
selector: 'modelview-dropdown',
|
||||
template: `
|
||||
|
||||
<div>
|
||||
<div [style.width]="getWidth()">
|
||||
<div [style.display]="getEditableDisplay()" #editableDropDown style="width: 100%;"></div>
|
||||
<div [style.display]="getNotEditableDisplay()" #dropDown style="width: 100%;"></div>
|
||||
</div>
|
||||
@@ -68,7 +69,7 @@ export default class DropDownComponent extends ComponentBase implements ICompone
|
||||
this._register(attachEditableDropdownStyler(this._editableDropdown, this.themeService));
|
||||
this._register(this._editableDropdown.onValueChange(e => {
|
||||
if (this.editable) {
|
||||
this.value = this._editableDropdown.value;
|
||||
this.setSelectedValue(this._editableDropdown.value);
|
||||
this._onEventEmitter.fire({
|
||||
eventType: ComponentEventType.onDidChange,
|
||||
args: e
|
||||
@@ -77,14 +78,14 @@ export default class DropDownComponent extends ComponentBase implements ICompone
|
||||
}));
|
||||
}
|
||||
if (this._dropDownContainer) {
|
||||
this._selectBox = new SelectBox(this.values || [], this.value, this.contextViewService, this._dropDownContainer.nativeElement);
|
||||
this._selectBox = new SelectBox(this.getValues(), this.getSelectedValue(), this.contextViewService, this._dropDownContainer.nativeElement);
|
||||
this._selectBox.render(this._dropDownContainer.nativeElement);
|
||||
this._register(this._selectBox);
|
||||
|
||||
this._register(attachSelectBoxStyler(this._selectBox, this.themeService));
|
||||
this._register(this._selectBox.onDidSelect(e => {
|
||||
if (!this.editable) {
|
||||
this.value = this._selectBox.value;
|
||||
this.setSelectedValue(this._selectBox.value);
|
||||
this._onEventEmitter.fire({
|
||||
eventType: ComponentEventType.onDidChange,
|
||||
args: e
|
||||
@@ -112,14 +113,14 @@ export default class DropDownComponent extends ComponentBase implements ICompone
|
||||
public setProperties(properties: { [key: string]: any; }): void {
|
||||
super.setProperties(properties);
|
||||
if (this.editable) {
|
||||
this._editableDropdown.values = this.values ? this.values : [];
|
||||
this._editableDropdown.values = this.getValues();
|
||||
if (this.value) {
|
||||
this._editableDropdown.value = this.value;
|
||||
this._editableDropdown.value = this.getSelectedValue();
|
||||
}
|
||||
this._editableDropdown.enabled = this.enabled;
|
||||
} else {
|
||||
this._selectBox.setOptions(this.values || []);
|
||||
this._selectBox.selectWithOptionName(this.value);
|
||||
this._selectBox.setOptions(this.getValues());
|
||||
this._selectBox.selectWithOptionName(this.getSelectedValue());
|
||||
if (this.enabled) {
|
||||
this._selectBox.enable();
|
||||
} else {
|
||||
@@ -128,6 +129,39 @@ export default class DropDownComponent extends ComponentBase implements ICompone
|
||||
}
|
||||
}
|
||||
|
||||
private getValues(): string[] {
|
||||
if (this.values && this.values.length > 0) {
|
||||
if (!this.valuesHaveDisplayName()) {
|
||||
return this.values as string[];
|
||||
} else {
|
||||
return (<sqlops.CategoryValue[]>this.values).map(v => v.displayName);
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
private valuesHaveDisplayName(): boolean {
|
||||
return typeof (this.values[0]) !== 'string';
|
||||
}
|
||||
|
||||
private getSelectedValue(): string {
|
||||
if (this.values && this.valuesHaveDisplayName()) {
|
||||
let valueCategory = (<sqlops.CategoryValue[]>this.values).find(v => v.name === this.value);
|
||||
return valueCategory && valueCategory.displayName;
|
||||
} else {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
private setSelectedValue(newValue: string): void {
|
||||
if (this.values && this.valuesHaveDisplayName()) {
|
||||
let valueCategory = (<sqlops.CategoryValue[]>this.values).find(v => v.displayName === newValue);
|
||||
this.value = valueCategory && valueCategory.name;
|
||||
} else {
|
||||
this.value = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
// CSS-bound properties
|
||||
|
||||
private get value(): string {
|
||||
@@ -138,11 +172,11 @@ export default class DropDownComponent extends ComponentBase implements ICompone
|
||||
return this.getPropertyOrDefault<sqlops.DropDownProperties, boolean>((props) => props.editable, false);
|
||||
}
|
||||
|
||||
public getEditableDisplay() : string {
|
||||
public getEditableDisplay(): string {
|
||||
return this.editable ? '' : 'none';
|
||||
}
|
||||
|
||||
public getNotEditableDisplay() : string {
|
||||
public getNotEditableDisplay(): string {
|
||||
return !this.editable ? '' : 'none';
|
||||
}
|
||||
|
||||
@@ -150,12 +184,12 @@ export default class DropDownComponent extends ComponentBase implements ICompone
|
||||
this.setPropertyFromUI<sqlops.DropDownProperties, string>(this.setValueProperties, newValue);
|
||||
}
|
||||
|
||||
private get values(): string[] {
|
||||
return this.getPropertyOrDefault<sqlops.DropDownProperties, string[]>((props) => props.values, undefined);
|
||||
private get values(): string[] | sqlops.CategoryValue[] {
|
||||
return this.getPropertyOrDefault<sqlops.DropDownProperties, string[] | sqlops.CategoryValue[]>((props) => props.values, undefined);
|
||||
}
|
||||
|
||||
private set values(newValue: string[]) {
|
||||
this.setPropertyFromUI<sqlops.DropDownProperties, string[]>(this.setValuesProperties, newValue);
|
||||
private set values(newValue: string[] | sqlops.CategoryValue[]) {
|
||||
this.setPropertyFromUI<sqlops.DropDownProperties, string[] | sqlops.CategoryValue[]>(this.setValuesProperties, newValue);
|
||||
}
|
||||
|
||||
private setValueProperties(properties: sqlops.DropDownProperties, value: string): void {
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import 'vs/css!./flexContainer';
|
||||
|
||||
import { Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver,
|
||||
import {
|
||||
Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver,
|
||||
ViewChild, ViewChildren, ElementRef, Injector, OnDestroy, QueryList,
|
||||
} from '@angular/core';
|
||||
|
||||
@@ -18,13 +19,13 @@ import { ModelComponentWrapper } from 'sql/parts/modelComponents/modelComponentW
|
||||
import types = require('vs/base/common/types');
|
||||
|
||||
class FlexItem {
|
||||
constructor(public descriptor: IComponentDescriptor, public config: FlexItemLayout) {}
|
||||
constructor(public descriptor: IComponentDescriptor, public config: FlexItemLayout) { }
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<div *ngIf="items" class="flexContainer" [style.flexFlow]="flexFlow" [style.justifyContent]="justifyContent"
|
||||
[style.alignItems]="alignItems" [style.alignContent]="alignContent" [style.height]="height">
|
||||
[style.alignItems]="alignItems" [style.alignContent]="alignContent" [style.height]="height" [style.width]="width">
|
||||
<div *ngFor="let item of items" [style.flex]="getItemFlex(item)" [style.order]="getItemOrder(item)" >
|
||||
<model-component-wrapper [descriptor]="item.descriptor" [modelStore]="modelStore">
|
||||
</model-component-wrapper>
|
||||
@@ -40,6 +41,7 @@ export default class FlexContainer extends ContainerBase<FlexItemLayout> impleme
|
||||
private _alignItems: string;
|
||||
private _alignContent: string;
|
||||
private _height: string;
|
||||
private _width: string;
|
||||
|
||||
constructor(@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) {
|
||||
super(changeRef);
|
||||
@@ -58,18 +60,14 @@ export default class FlexContainer extends ContainerBase<FlexItemLayout> impleme
|
||||
|
||||
/// IComponent implementation
|
||||
|
||||
public setLayout (layout: FlexLayout): void {
|
||||
public setLayout(layout: FlexLayout): void {
|
||||
this._flexFlow = layout.flexFlow ? layout.flexFlow : '';
|
||||
this._justifyContent = layout.justifyContent ? layout.justifyContent : '';
|
||||
this._alignItems = layout.alignItems ? layout.alignItems : '';
|
||||
this._alignContent = layout.alignContent ? layout.alignContent : '';
|
||||
if (types.isUndefinedOrNull(layout.height)) {
|
||||
this._height = '';
|
||||
} else if (types.isNumber(layout.height)) {
|
||||
this._height = layout.height + 'px';
|
||||
} else {
|
||||
this._height = layout.height;
|
||||
}
|
||||
this._height = this.convertSize(layout.height);
|
||||
this._width = this.convertSize(layout.width);
|
||||
|
||||
this.layout();
|
||||
}
|
||||
|
||||
@@ -90,6 +88,10 @@ export default class FlexContainer extends ContainerBase<FlexItemLayout> impleme
|
||||
return this._height;
|
||||
}
|
||||
|
||||
public get width(): string {
|
||||
return this._width;
|
||||
}
|
||||
|
||||
public get alignContent(): string {
|
||||
return this._alignContent;
|
||||
}
|
||||
|
||||
@@ -35,10 +35,10 @@ class FormItem {
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<div #container *ngIf="items" class="form-table" [style.width]="getFormWidth()">
|
||||
<div #container *ngIf="items" class="form-table" [style.width]="getFormWidth()" [style.height]="getFormHeight()">
|
||||
<ng-container *ngFor="let item of items">
|
||||
<div class="form-row" >
|
||||
<ng-container *ngIf="isFormComponent(item)">
|
||||
<div class="form-row" *ngIf="isFormComponent(item)">
|
||||
|
||||
<ng-container *ngIf="isHorizontal(item)">
|
||||
<div class="form-cell">{{getItemTitle(item)}}</div>
|
||||
<div class="form-cell">
|
||||
@@ -69,7 +69,6 @@ class FormItem {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
@@ -113,7 +112,11 @@ export default class FormContainer extends ContainerBase<FormItemLayout> impleme
|
||||
}
|
||||
|
||||
private getFormWidth(): string {
|
||||
return this._formLayout && this._formLayout.width ? +this._formLayout.width + 'px' : '100%';
|
||||
return this.convertSize(this._formLayout && this._formLayout.width);
|
||||
}
|
||||
|
||||
private getFormHeight(): string {
|
||||
return this.convertSize(this._formLayout && this._formLayout.height);
|
||||
}
|
||||
|
||||
private getComponentWidth(item: FormItem): string {
|
||||
|
||||
@@ -20,19 +20,23 @@ import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/work
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import * as nls from 'vs/nls';
|
||||
import { TextAreaInput } from 'vs/editor/browser/controller/textAreaInput';
|
||||
|
||||
@Component({
|
||||
selector: 'modelview-inputBox',
|
||||
template: `
|
||||
<div #input style="width: 100%"></div>
|
||||
<div [style.display]="getInputBoxDisplay()" #input style="width: 100%"></div>
|
||||
<div [style.display]="getTextAreaDisplay()" #textarea style="width: 100%"></div>
|
||||
`
|
||||
})
|
||||
export default class InputBoxComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit {
|
||||
@Input() descriptor: IComponentDescriptor;
|
||||
@Input() modelStore: IModelStore;
|
||||
private _input: InputBox;
|
||||
private _textAreaInput: InputBox;
|
||||
|
||||
@ViewChild('input', { read: ElementRef }) private _inputContainer: ElementRef;
|
||||
@ViewChild('textarea', { read: ElementRef }) private _textareaContainer: ElementRef;
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
|
||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
||||
@@ -43,47 +47,71 @@ export default class InputBoxComponent extends ComponentBase implements ICompone
|
||||
|
||||
ngOnInit(): void {
|
||||
this.baseInit();
|
||||
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
if (this._inputContainer) {
|
||||
let inputOptions: IInputOptions = {
|
||||
placeholder: '',
|
||||
ariaLabel: '',
|
||||
validationOptions: {
|
||||
validation: () => {
|
||||
if (this.valid) {
|
||||
return undefined;
|
||||
} else {
|
||||
return {
|
||||
content: this._input.inputElement.validationMessage || nls.localize('invalidValueError', 'Invalid value'),
|
||||
type: MessageType.ERROR
|
||||
};
|
||||
}
|
||||
let inputOptions: IInputOptions = {
|
||||
placeholder: '',
|
||||
ariaLabel: '',
|
||||
validationOptions: {
|
||||
validation: () => {
|
||||
if (this.valid) {
|
||||
return undefined;
|
||||
} else {
|
||||
return {
|
||||
content: this.inputElement.inputElement.validationMessage || nls.localize('invalidValueError', 'Invalid value'),
|
||||
type: MessageType.ERROR
|
||||
};
|
||||
}
|
||||
},
|
||||
useDefaultValidation: true
|
||||
};
|
||||
|
||||
}
|
||||
},
|
||||
useDefaultValidation: true
|
||||
};
|
||||
if (this._inputContainer) {
|
||||
this._input = new InputBox(this._inputContainer.nativeElement, this.contextViewService, inputOptions);
|
||||
this._validations.push(() => !this._input.inputElement.validationMessage);
|
||||
this.registerInput(this._input, () => !this.multiline);
|
||||
|
||||
this._register(this._input);
|
||||
this._register(attachInputBoxStyler(this._input, this.themeService));
|
||||
this._register(this._input.onDidChange(e => {
|
||||
this.value = this._input.value;
|
||||
this._onEventEmitter.fire({
|
||||
eventType: ComponentEventType.onDidChange,
|
||||
args: e
|
||||
});
|
||||
}
|
||||
if (this._textareaContainer) {
|
||||
let textAreaInputOptions = Object.assign({}, inputOptions, { flexibleHeight: true, type: 'textarea' });
|
||||
this._textAreaInput = new InputBox(this._textareaContainer.nativeElement, this.contextViewService, textAreaInputOptions);
|
||||
this.registerInput(this._textAreaInput, () => this.multiline);
|
||||
}
|
||||
}
|
||||
|
||||
private get inputElement(): InputBox {
|
||||
return this.multiline ? this._textAreaInput : this._input;
|
||||
}
|
||||
|
||||
private registerInput(input: InputBox, checkOption: () => boolean): void {
|
||||
if (input) {
|
||||
this._validations.push(() => !input.inputElement.validationMessage);
|
||||
|
||||
this._register(input);
|
||||
this._register(attachInputBoxStyler(input, this.themeService));
|
||||
this._register(input.onDidChange(e => {
|
||||
if (checkOption()) {
|
||||
this.value = input.value;
|
||||
this._onEventEmitter.fire({
|
||||
eventType: ComponentEventType.onDidChange,
|
||||
args: e
|
||||
});
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public getInputBoxDisplay(): string {
|
||||
return !this.multiline ? '' : 'none';
|
||||
}
|
||||
|
||||
public getTextAreaDisplay(): string {
|
||||
return this.multiline ? '' : 'none';
|
||||
}
|
||||
|
||||
public validate(): Thenable<boolean> {
|
||||
return super.validate().then(valid => {
|
||||
this._input.validate();
|
||||
this.inputElement.validate();
|
||||
return valid;
|
||||
});
|
||||
}
|
||||
@@ -96,6 +124,16 @@ export default class InputBoxComponent extends ComponentBase implements ICompone
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
this.layoutInputBox();
|
||||
}
|
||||
|
||||
private layoutInputBox(): void {
|
||||
if (this.width) {
|
||||
this.inputElement.width = this.convertSizeToNumber(this.width);
|
||||
}
|
||||
if (this.height) {
|
||||
this.inputElement.setHeight(this.convertSize(this.height));
|
||||
}
|
||||
}
|
||||
|
||||
public setLayout(layout: any): void {
|
||||
@@ -105,21 +143,41 @@ export default class InputBoxComponent extends ComponentBase implements ICompone
|
||||
|
||||
public setProperties(properties: { [key: string]: any; }): void {
|
||||
super.setProperties(properties);
|
||||
this._input.inputElement.type = this.inputType;
|
||||
if (this.inputType === 'number') {
|
||||
this._input.inputElement.step = 'any';
|
||||
}
|
||||
this._input.value = this.value;
|
||||
this._input.setAriaLabel(this.ariaLabel);
|
||||
this._input.setPlaceHolder(this.placeHolder);
|
||||
this._input.setEnabled(this.enabled);
|
||||
if (this.width) {
|
||||
this._input.width = this.width;
|
||||
}
|
||||
this._input.inputElement.required = this.required;
|
||||
this.setInputProperties(this.inputElement);
|
||||
this.validate();
|
||||
}
|
||||
|
||||
private setInputProperties(input: InputBox): void {
|
||||
if (!this.multiline) {
|
||||
input.inputElement.type = this.inputType;
|
||||
if (this.inputType === 'number') {
|
||||
input.inputElement.step = 'any';
|
||||
if (this.min) {
|
||||
input.inputElement.min = this.min.toString();
|
||||
}
|
||||
if (this.max) {
|
||||
input.inputElement.max = this.max.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
input.value = this.value;
|
||||
input.setAriaLabel(this.ariaLabel);
|
||||
input.setPlaceHolder(this.placeHolder);
|
||||
input.setEnabled(this.enabled);
|
||||
this.layoutInputBox();
|
||||
if (this.multiline) {
|
||||
if (this.rows) {
|
||||
this.inputElement.rows = this.rows;
|
||||
}
|
||||
if (this.columns) {
|
||||
this.inputElement.columns = this.columns;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
input.inputElement.required = this.required;
|
||||
}
|
||||
|
||||
// CSS-bound properties
|
||||
|
||||
public get value(): string {
|
||||
@@ -146,20 +204,36 @@ export default class InputBoxComponent extends ComponentBase implements ICompone
|
||||
this.setPropertyFromUI<sqlops.InputBoxProperties, string>((props, value) => props.placeHolder = value, newValue);
|
||||
}
|
||||
|
||||
public get height(): number {
|
||||
return this.getPropertyOrDefault<sqlops.InputBoxProperties, number>((props) => props.height, undefined);
|
||||
public set columns(newValue: number) {
|
||||
this.setPropertyFromUI<sqlops.InputBoxProperties, number>((props, value) => props.columns = value, newValue);
|
||||
}
|
||||
|
||||
public set height(newValue: number) {
|
||||
this.setPropertyFromUI<sqlops.InputBoxProperties, number>((props, value) => props.height = value, newValue);
|
||||
public get rows(): number {
|
||||
return this.getPropertyOrDefault<sqlops.InputBoxProperties, number>((props) => props.rows, undefined);
|
||||
}
|
||||
|
||||
public get width(): number {
|
||||
return this.getPropertyOrDefault<sqlops.InputBoxProperties, number>((props) => props.width, undefined);
|
||||
public get columns(): number {
|
||||
return this.getPropertyOrDefault<sqlops.InputBoxProperties, number>((props) => props.columns, undefined);
|
||||
}
|
||||
|
||||
public set width(newValue: number) {
|
||||
this.setPropertyFromUI<sqlops.InputBoxProperties, number>((props, value) => props.width = value, newValue);
|
||||
public set rows(newValue: number) {
|
||||
this.setPropertyFromUI<sqlops.InputBoxProperties, number>((props, value) => props.rows = value, newValue);
|
||||
}
|
||||
|
||||
public get min(): number {
|
||||
return this.getPropertyOrDefault<sqlops.InputBoxProperties, number>((props) => props.min, undefined);
|
||||
}
|
||||
|
||||
public set min(newValue: number) {
|
||||
this.setPropertyFromUI<sqlops.InputBoxProperties, number>((props, value) => props.min = value, newValue);
|
||||
}
|
||||
|
||||
public get max(): number {
|
||||
return this.getPropertyOrDefault<sqlops.InputBoxProperties, number>((props) => props.max, undefined);
|
||||
}
|
||||
|
||||
public set max(newValue: number) {
|
||||
this.setPropertyFromUI<sqlops.InputBoxProperties, number>((props, value) => props.max = value, newValue);
|
||||
}
|
||||
|
||||
public get inputType(): string {
|
||||
@@ -170,6 +244,14 @@ export default class InputBoxComponent extends ComponentBase implements ICompone
|
||||
this.setPropertyFromUI<sqlops.InputBoxProperties, string>((props, value) => props.inputType = value, newValue);
|
||||
}
|
||||
|
||||
public get multiline(): boolean {
|
||||
return this.getPropertyOrDefault<sqlops.InputBoxProperties, boolean>((props) => props.multiline, false);
|
||||
}
|
||||
|
||||
public set multiline(newValue: boolean) {
|
||||
this.setPropertyFromUI<sqlops.InputBoxProperties, boolean>((props, value) => props.multiline = value, newValue);
|
||||
}
|
||||
|
||||
public get required(): boolean {
|
||||
return this.getPropertyOrDefault<sqlops.InputBoxProperties, boolean>((props) => props.required, false);
|
||||
}
|
||||
|
||||
112
src/sql/parts/modelComponents/listbox.component.ts
Normal file
112
src/sql/parts/modelComponents/listbox.component.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import {
|
||||
Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver,
|
||||
ViewChild, ViewChildren, ElementRef, Injector, OnDestroy, QueryList, AfterViewInit
|
||||
} from '@angular/core';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
import { ComponentBase } from 'sql/parts/modelComponents/componentBase';
|
||||
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||
|
||||
import { ListBox } from 'sql/base/browser/ui/listBox/listBox';
|
||||
import { attachListBoxStyler } from 'sql/common/theme/styler';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
|
||||
@Component({
|
||||
selector: 'modelview-listBox',
|
||||
template: `
|
||||
<div #input style="width: 100%"></div>
|
||||
`
|
||||
})
|
||||
export default class ListBoxComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit {
|
||||
@Input() descriptor: IComponentDescriptor;
|
||||
@Input() modelStore: IModelStore;
|
||||
private _input: ListBox;
|
||||
|
||||
@ViewChild('input', { read: ElementRef }) private _inputContainer: ElementRef;
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
|
||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
||||
@Inject(IContextViewService) private contextViewService: IContextViewService,
|
||||
@Inject(IClipboardService) private clipboardService: IClipboardService
|
||||
) {
|
||||
super(changeRef);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.baseInit();
|
||||
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
if (this._inputContainer) {
|
||||
this._input = new ListBox([], undefined, this.contextViewService, this.clipboardService);
|
||||
this._input.render(this._inputContainer.nativeElement);
|
||||
|
||||
this._register(this._input);
|
||||
this._register(attachListBoxStyler(this._input, this.themeService));
|
||||
this._register(this._input.onDidSelect(e => {
|
||||
this.selectedRow = e.index;
|
||||
this._onEventEmitter.fire({
|
||||
eventType: ComponentEventType.onSelectedRowChanged,
|
||||
args: e
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public validate(): Thenable<boolean> {
|
||||
return super.validate().then(valid => {
|
||||
return valid;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.baseDestroy();
|
||||
}
|
||||
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
public setLayout(layout: any): void {
|
||||
// TODO allow configuring the look and feel
|
||||
this.layout();
|
||||
}
|
||||
|
||||
public setProperties(properties: { [key: string]: any; }): void {
|
||||
super.setProperties(properties);
|
||||
this._input.setOptions(this.values, this.selectedRow);
|
||||
|
||||
this.validate();
|
||||
}
|
||||
|
||||
// CSS-bound properties
|
||||
|
||||
private get values(): string[] {
|
||||
return this.getPropertyOrDefault<sqlops.ListBoxProperties, string[]>((props) => props.values, undefined);
|
||||
}
|
||||
|
||||
private set values(newValue: string[]) {
|
||||
this.setPropertyFromUI<sqlops.ListBoxProperties, string[]>((props, value) => props.values = value, newValue);
|
||||
}
|
||||
|
||||
private get selectedRow(): number {
|
||||
return this.getPropertyOrDefault<sqlops.ListBoxProperties, number>((props) => props.selectedRow, undefined);
|
||||
}
|
||||
|
||||
private set selectedRow(newValue: number) {
|
||||
this.setPropertyFromUI<sqlops.ListBoxProperties, number>((props, value) => props.selectedRow = value, newValue);
|
||||
}
|
||||
}
|
||||
@@ -25,10 +25,18 @@ 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 { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import * as nls from 'vs/nls';
|
||||
|
||||
const componentRegistry = <IComponentRegistry>Registry.as(Extensions.ComponentContribution);
|
||||
|
||||
export interface ModelComponentParams extends IBootstrapParams {
|
||||
|
||||
onLayoutRequested: Event<string>;
|
||||
modelViewId: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'model-component-wrapper',
|
||||
template: `
|
||||
@@ -46,6 +54,7 @@ export class ModelComponentWrapper extends AngularDisposable implements OnInit {
|
||||
}
|
||||
|
||||
private _componentInstance: IComponent;
|
||||
private _modelViewId: string;
|
||||
|
||||
@ViewChild(ComponentHostDirective) componentHost: ComponentHostDirective;
|
||||
|
||||
@@ -54,9 +63,18 @@ export class ModelComponentWrapper extends AngularDisposable implements OnInit {
|
||||
@Inject(forwardRef(() => ElementRef)) private _ref: ElementRef,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeref: ChangeDetectorRef,
|
||||
@Inject(forwardRef(() => Injector)) private _injector: Injector,
|
||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService
|
||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
||||
@Inject(IBootstrapParams) private _params: ModelComponentParams
|
||||
) {
|
||||
super();
|
||||
if (_params && _params.onLayoutRequested) {
|
||||
this._modelViewId = _params.modelViewId;
|
||||
_params.onLayoutRequested(modelViewId => {
|
||||
if (modelViewId === this._modelViewId) {
|
||||
this.layout();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
@@ -62,6 +62,7 @@ export class ModelViewContent extends ViewBase implements OnInit, IModelView {
|
||||
}
|
||||
|
||||
public layout(): void {
|
||||
this.changeRef.detectChanges();
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
|
||||
@@ -127,13 +127,19 @@ export default class TableComponent extends ComponentBase implements IComponent,
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._table.layout(new Dimension(
|
||||
this.width ? this.width : getContentWidth(this._inputContainer.nativeElement),
|
||||
this.height ? this.height : getContentHeight(this._inputContainer.nativeElement)));
|
||||
this.layoutTable();
|
||||
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
private layoutTable(): void {
|
||||
let width: number = this.convertSizeToNumber(this.width);
|
||||
let height: number = this.convertSizeToNumber(this.height);
|
||||
this._table.layout(new Dimension(
|
||||
width && width > 0 ? width : getContentWidth(this._inputContainer.nativeElement),
|
||||
height && height > 0 ? height : getContentHeight(this._inputContainer.nativeElement)));
|
||||
}
|
||||
|
||||
public setLayout(): void {
|
||||
// TODO allow configuring the look and feel
|
||||
this.layout();
|
||||
@@ -149,10 +155,8 @@ export default class TableComponent extends ComponentBase implements IComponent,
|
||||
if (this.selectedRows) {
|
||||
this._table.setSelectedRows(this.selectedRows);
|
||||
}
|
||||
this._table.layout(new Dimension(
|
||||
this.width ? this.width : getContentWidth(this._inputContainer.nativeElement),
|
||||
this.height ? this.height : getContentHeight(this._inputContainer.nativeElement)));
|
||||
|
||||
this.layoutTable();
|
||||
this.validate();
|
||||
}
|
||||
|
||||
@@ -181,20 +185,4 @@ export default class TableComponent extends ComponentBase implements IComponent,
|
||||
public set selectedRows(newValue: number[]) {
|
||||
this.setPropertyFromUI<sqlops.TableComponentProperties, number[]>((props, value) => props.selectedRows = value, newValue);
|
||||
}
|
||||
|
||||
public get height(): number {
|
||||
return this.getPropertyOrDefault<sqlops.TableComponentProperties, number>((props) => props.height, undefined);
|
||||
}
|
||||
|
||||
public set height(newValue: number) {
|
||||
this.setPropertyFromUI<sqlops.TableComponentProperties, number>((props, value) => props.height = value, newValue);
|
||||
}
|
||||
|
||||
public get width(): number {
|
||||
return this.getPropertyOrDefault<sqlops.TableComponentProperties, number>((props) => props.width, undefined);
|
||||
}
|
||||
|
||||
public set width(newValue: number) {
|
||||
this.setPropertyFromUI<sqlops.TableComponentProperties, number>((props, value) => props.width = value, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ export abstract class ViewBase extends AngularDisposable implements IModelView {
|
||||
abstract serverInfo: sqlops.ServerInfo;
|
||||
private _onEventEmitter = new Emitter<any>();
|
||||
|
||||
|
||||
initializeModel(rootComponent: IComponentShape, validationCallback: (componentId: string) => Thenable<boolean>): void {
|
||||
let descriptor = this.defineComponent(rootComponent);
|
||||
this.rootDescriptor = descriptor;
|
||||
@@ -50,6 +49,10 @@ export abstract class ViewBase extends AngularDisposable implements IModelView {
|
||||
}
|
||||
|
||||
private defineComponent(component: IComponentShape): IComponentDescriptor {
|
||||
let existingDescriptor = this.modelStore.getComponentDescriptor(component.id);
|
||||
if (existingDescriptor) {
|
||||
return existingDescriptor;
|
||||
}
|
||||
let typeId = componentRegistry.getIdForTypeMapping(component.type);
|
||||
if (!typeId) {
|
||||
// failure case
|
||||
|
||||
@@ -92,33 +92,6 @@ const profilerSessionTemplateSchema: IJSONSchema = {
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'TSQL'
|
||||
},
|
||||
{
|
||||
name: 'Blank'
|
||||
},
|
||||
{
|
||||
name: 'SP_Counts'
|
||||
},
|
||||
{
|
||||
name: 'TQL_Duration'
|
||||
},
|
||||
{
|
||||
name: 'TSQL_Grouped'
|
||||
},
|
||||
{
|
||||
name: 'TSQL_Locks'
|
||||
},
|
||||
{
|
||||
name: 'TSQL_Replay'
|
||||
},
|
||||
{
|
||||
name: 'TSQL_SPs'
|
||||
},
|
||||
{
|
||||
name: 'Tuning'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -57,7 +57,7 @@ export class ProfilerConnect extends Action {
|
||||
public set connected(value: boolean) {
|
||||
this._connected = value;
|
||||
this._setClass(value ? 'disconnect' : 'connect');
|
||||
this._setLabel(value ? nls.localize('profilerAction.disconnect', 'Disconnected') : nls.localize('profilerAction.connect', "Connect"));
|
||||
this._setLabel(value ? nls.localize('profilerAction.disconnect', 'Disconnect') : nls.localize('profilerAction.connect', "Connect"));
|
||||
}
|
||||
|
||||
public get connected(): boolean {
|
||||
@@ -78,17 +78,19 @@ export class ProfilerStart extends Action {
|
||||
|
||||
public run(input: ProfilerInput): TPromise<boolean> {
|
||||
this.enabled = false;
|
||||
input.data.clear();
|
||||
return TPromise.wrap(this._profilerService.startSession(input.id).then(() => {
|
||||
input.state.change({ isRunning: true, isStopped: false, isPaused: false });
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ProfilerPause extends Action {
|
||||
public static ID = 'profiler.pause';
|
||||
public static LABEL = nls.localize('pause', "Pause");
|
||||
public static LABEL = nls.localize('profiler.capture', "Pause Capture");
|
||||
|
||||
private _paused: boolean = false;
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@@ -98,12 +100,22 @@ export class ProfilerPause extends Action {
|
||||
}
|
||||
|
||||
public run(input: ProfilerInput): TPromise<boolean> {
|
||||
this.enabled = false;
|
||||
return TPromise.wrap(this._profilerService.pauseSession(input.id).then(() => {
|
||||
input.state.change({ isPaused: true, isStopped: false, isRunning: false });
|
||||
this.paused = !this._paused;
|
||||
input.state.change({ isPaused: this.paused, isStopped: false, isRunning: !this.paused });
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
|
||||
public set paused(value: boolean) {
|
||||
this._paused = value;
|
||||
this._setClass(value ? 'start' : 'stop');
|
||||
this._setLabel(value ? nls.localize('profilerAction.resumeCapture', "Resume Capture") : nls.localize('profilerAction.pauseCapture', "Pause Capture"));
|
||||
}
|
||||
|
||||
public get paused(): boolean {
|
||||
return this._paused;
|
||||
}
|
||||
}
|
||||
|
||||
export class ProfilerStop extends Action {
|
||||
|
||||
@@ -202,15 +202,15 @@ export class ProfilerEditor extends BaseEditor {
|
||||
this._register(attachSelectBoxStyler(this._sessionTemplateSelector, this.themeService));
|
||||
|
||||
this._actionBar.setContent([
|
||||
{ action: this._startAction },
|
||||
{ action: this._pauseAction },
|
||||
{ action: this._stopAction },
|
||||
{ action: this._connectAction },
|
||||
{ element: Taskbar.createTaskbarSeparator() },
|
||||
{ action: this._autoscrollAction },
|
||||
{ action: this._instantiationService.createInstance(Actions.ProfilerClear, Actions.ProfilerClear.ID, Actions.ProfilerClear.LABEL) },
|
||||
{ action: this._startAction },
|
||||
{ action: this._stopAction },
|
||||
{ element: dropdownContainer },
|
||||
{ action: this._instantiationService.createInstance(Actions.ProfilerEditColumns, Actions.ProfilerEditColumns.ID, Actions.ProfilerEditColumns.LABEL) }
|
||||
{ element: Taskbar.createTaskbarSeparator() },
|
||||
{ action: this._pauseAction },
|
||||
{ action: this._autoscrollAction },
|
||||
{ action: this._instantiationService.createInstance(Actions.ProfilerClear, Actions.ProfilerClear.ID, Actions.ProfilerClear.LABEL) }
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -228,7 +228,9 @@ export class ProfilerEditor extends BaseEditor {
|
||||
if (data) {
|
||||
this._modelService.updateModel(this._editorModel, data['TextData']);
|
||||
this._detailTableData.clear();
|
||||
this._detailTableData.push(Object.keys(data).map(key => {
|
||||
this._detailTableData.push(Object.keys(data).filter(key => {
|
||||
return data[key] !== ' ';
|
||||
}).map(key => {
|
||||
return {
|
||||
label: key,
|
||||
value: data[key]
|
||||
@@ -397,16 +399,14 @@ export class ProfilerEditor extends BaseEditor {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.isRunning) {
|
||||
this._startAction.enabled = !this.input.state.isRunning;
|
||||
if (e.isPaused){
|
||||
this._pauseAction.paused = this.input.state.isPaused;
|
||||
}
|
||||
|
||||
if (e.isStopped || e.isRunning) {
|
||||
this._stopAction.enabled = !this.input.state.isStopped && this.input.state.isRunning;
|
||||
}
|
||||
|
||||
if (e.isPaused || e.isRunning) {
|
||||
this._pauseAction.enabled = !this.input.state.isPaused && this.input.state.isRunning;
|
||||
this._startAction.enabled = !this.input.state.isRunning && !this.input.state.isPaused;
|
||||
this._stopAction.enabled = !this.input.state.isStopped && (this.input.state.isRunning || this.input.state.isPaused);
|
||||
this._pauseAction.enabled = !this.input.state.isStopped && (this.input.state.isRunning || this.input.state.isPaused);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,6 @@ export class ProfilerInput extends EditorInput implements IProfilerSession {
|
||||
let data = {};
|
||||
data['EventClass'] = e.name;
|
||||
data['StartTime'] = e.timestamp;
|
||||
data['EndTime'] = e.timestamp;
|
||||
const columns = [
|
||||
'TextData',
|
||||
'ApplicationName',
|
||||
@@ -156,12 +155,14 @@ export class ProfilerInput extends EditorInput implements IProfilerSession {
|
||||
columnNameMap['cpu_time'] = 'CPU';
|
||||
columnNameMap['duration'] = 'Duration';
|
||||
columnNameMap['logical_reads'] = 'Reads';
|
||||
columnNameMap['event_sequence'] = 'EventSequence';
|
||||
columnNameMap['client_pid'] = 'ClientProcessID';
|
||||
columnNameMap['writes'] = 'Writes';
|
||||
|
||||
for (let idx = 0; idx < columns.length; ++idx) {
|
||||
let columnName = columns[idx];
|
||||
data[columnName] = '';
|
||||
}
|
||||
|
||||
// Using ' ' instead of '' fixed the error where clicking through events
|
||||
// with empty text fields causes future text panes to be highlighted.
|
||||
// This is a temporary fix, and should be changed before the July release
|
||||
data['TextData'] = ' ';
|
||||
for (let key in e.values) {
|
||||
let columnName = columnNameMap[key];
|
||||
if (columnName) {
|
||||
|
||||
@@ -19,6 +19,9 @@ import { ComponentHostDirective } from 'sql/parts/dashboard/common/componentHost
|
||||
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox.component';
|
||||
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox.component';
|
||||
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox.component';
|
||||
|
||||
/* Model-backed components */
|
||||
let extensionComponents = Registry.as<IComponentRegistry>(Extensions.ComponentContribution).getAllCtors();
|
||||
@@ -26,6 +29,9 @@ let extensionComponents = Registry.as<IComponentRegistry>(Extensions.ComponentCo
|
||||
export const DialogModule = (params, selector: string): any => {
|
||||
@NgModule({
|
||||
declarations: [
|
||||
Checkbox,
|
||||
SelectBox,
|
||||
InputBox,
|
||||
DialogContainer,
|
||||
ModelViewContent,
|
||||
ModelComponentWrapper,
|
||||
|
||||
@@ -15,6 +15,7 @@ import { ComponentEventType } from '../../parts/modelComponents/interfaces';
|
||||
export interface DialogComponentParams extends IBootstrapParams {
|
||||
modelViewId: string;
|
||||
validityChangedCallback: (valid: boolean) => void;
|
||||
onLayoutRequested: Event<string>;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@@ -35,6 +36,11 @@ export class DialogContainer implements AfterContentInit {
|
||||
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
|
||||
@Inject(IBootstrapParams) private _params: DialogComponentParams) {
|
||||
this.modelViewId = this._params.modelViewId;
|
||||
this._params.onLayoutRequested(e => {
|
||||
if (this.modelViewId === e) {
|
||||
this.layout();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterContentInit(): void {
|
||||
|
||||
@@ -21,6 +21,7 @@ import { Builder } from 'vs/base/browser/builder';
|
||||
import { IThemable } from 'vs/platform/theme/common/styler';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
export class DialogPane extends Disposable implements IThemable {
|
||||
private _tabbedPanel: TabbedPanel;
|
||||
@@ -34,6 +35,9 @@ export class DialogPane extends Disposable implements IThemable {
|
||||
private _tabBar: HTMLElement;
|
||||
private _tabs: HTMLElement[];
|
||||
private _tabContent: HTMLElement[];
|
||||
private _selectedTabIndex: number = 0; //TODO: can be an option
|
||||
private _onTabChange = new Emitter<string>();
|
||||
private _selectedTabContent: string;
|
||||
|
||||
constructor(
|
||||
private _title: string,
|
||||
@@ -55,10 +59,16 @@ export class DialogPane extends Disposable implements IThemable {
|
||||
} else {
|
||||
this._tabbedPanel = new TabbedPanel(this._body);
|
||||
this._content.forEach((tab, tabIndex) => {
|
||||
if (this._selectedTabIndex === tabIndex) {
|
||||
this._selectedTabContent = tab.content;
|
||||
}
|
||||
let tabContainer = document.createElement('div');
|
||||
tabContainer.style.display = 'none';
|
||||
this._body.appendChild(tabContainer);
|
||||
this.initializeModelViewContainer(tabContainer, tab.content, tab);
|
||||
this._tabbedPanel.onTabChange(e => {
|
||||
this._onTabChange.fire(tab.content);
|
||||
});
|
||||
this._tabbedPanel.pushTab({
|
||||
title: tab.title,
|
||||
identifier: 'dialogPane.' + this._title + '.' + tabIndex,
|
||||
@@ -70,7 +80,7 @@ export class DialogPane extends Disposable implements IThemable {
|
||||
container.appendChild(tabContainer);
|
||||
tabContainer.style.display = 'block';
|
||||
},
|
||||
layout: (dimension) => { }
|
||||
layout: (dimension) => { this.getTabDimension(); }
|
||||
} as IPanelView
|
||||
} as IPanelTab);
|
||||
});
|
||||
@@ -80,9 +90,14 @@ export class DialogPane extends Disposable implements IThemable {
|
||||
return this._body;
|
||||
}
|
||||
|
||||
private getTabDimension(): DOM.Dimension {
|
||||
return new DOM.Dimension(DOM.getContentWidth(this._body), DOM.getContentHeight(this._body))
|
||||
}
|
||||
|
||||
public layout(): void {
|
||||
if (this._tabbedPanel) {
|
||||
this._tabbedPanel.layout(new DOM.Dimension(DOM.getContentWidth(this._body), DOM.getContentHeight(this._body)));
|
||||
this._onTabChange.fire(this._selectedTabContent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,10 +116,13 @@ export class DialogPane extends Disposable implements IThemable {
|
||||
if (tab) {
|
||||
tab.notifyValidityChanged(valid);
|
||||
}
|
||||
}
|
||||
},
|
||||
onLayoutRequested: this._onTabChange.event
|
||||
} as DialogComponentParams,
|
||||
undefined,
|
||||
(moduleRef) => this._moduleRefs.push(moduleRef));
|
||||
(moduleRef) => {
|
||||
return this._moduleRefs.push(moduleRef);
|
||||
});
|
||||
}
|
||||
|
||||
public show(): void {
|
||||
|
||||
@@ -139,6 +139,7 @@ export class Wizard {
|
||||
public readonly onPageAdded = this._pageAddedEmitter.event;
|
||||
private _pageRemovedEmitter = new Emitter<WizardPage>();
|
||||
public readonly onPageRemoved = this._pageRemovedEmitter.event;
|
||||
private _navigationValidator: (pageChangeInfo: sqlops.window.modelviewdialog.WizardPageChangeInfo) => boolean | Thenable<boolean>;
|
||||
|
||||
constructor(public title: string) { }
|
||||
|
||||
@@ -191,4 +192,19 @@ export class Wizard {
|
||||
this.pages.splice(index, 1);
|
||||
this._pageRemovedEmitter.fire(removedPage);
|
||||
}
|
||||
|
||||
public registerNavigationValidator(validator: (pageChangeInfo: sqlops.window.modelviewdialog.WizardPageChangeInfo) => boolean | Thenable<boolean>): void {
|
||||
this._navigationValidator = validator;
|
||||
}
|
||||
|
||||
public validateNavigation(newPage: number): Thenable<boolean> {
|
||||
if (this._navigationValidator) {
|
||||
return Promise.resolve(this._navigationValidator({
|
||||
lastPage: this._currentPage,
|
||||
newPage: newPage
|
||||
}));
|
||||
} else {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,4 +29,4 @@
|
||||
|
||||
.footer-button.dialogModal-hidden {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
@@ -106,12 +106,12 @@ export class WizardModal extends Modal {
|
||||
});
|
||||
this._wizard.onPageAdded(page => {
|
||||
this.registerPage(page);
|
||||
this.showPage(this.getCurrentPage());
|
||||
this.showPage(this.getCurrentPage(), false);
|
||||
});
|
||||
this._wizard.onPageRemoved(page => {
|
||||
let dialogPane = this._dialogPanes.get(page);
|
||||
this._dialogPanes.delete(page);
|
||||
this.showPage(this.getCurrentPage());
|
||||
this.showPage(this.getCurrentPage(), false);
|
||||
dialogPane.dispose();
|
||||
});
|
||||
}
|
||||
@@ -123,10 +123,13 @@ export class WizardModal extends Modal {
|
||||
page.onUpdate(() => this.setButtonsForPage(this._wizard.currentPage));
|
||||
}
|
||||
|
||||
private showPage(index: number): void {
|
||||
private async showPage(index: number, validate: boolean = true): Promise<void> {
|
||||
let pageToShow = this._wizard.pages[index];
|
||||
if (!pageToShow) {
|
||||
this.done();
|
||||
this.done(validate);
|
||||
return;
|
||||
}
|
||||
if (validate && !await this._wizard.validateNavigation(index)) {
|
||||
return;
|
||||
}
|
||||
this._dialogPanes.forEach((dialogPane, page) => {
|
||||
@@ -163,12 +166,15 @@ export class WizardModal extends Modal {
|
||||
}
|
||||
|
||||
public open(): void {
|
||||
this.showPage(0);
|
||||
this.showPage(0, false);
|
||||
this.show();
|
||||
}
|
||||
|
||||
public done(): void {
|
||||
public async done(validate: boolean = true): Promise<void> {
|
||||
if (this._wizard.doneButton.enabled) {
|
||||
if (validate && !await this._wizard.validateNavigation(undefined)) {
|
||||
return;
|
||||
}
|
||||
this._onDone.fire();
|
||||
this.dispose();
|
||||
this.hide();
|
||||
|
||||
201
src/sql/sqlops.d.ts
vendored
201
src/sql/sqlops.d.ts
vendored
@@ -1025,22 +1025,33 @@ declare module 'sqlops' {
|
||||
getDatabaseInfo(connectionUri: string): Thenable<DatabaseInfo>;
|
||||
}
|
||||
|
||||
// Agent Services interfaces
|
||||
export interface AgentJobsResult {
|
||||
succeeded: boolean;
|
||||
errorMessage: string;
|
||||
jobs: AgentJobInfo[];
|
||||
// Agent Services types
|
||||
export enum WeekDays {
|
||||
sunday = 1,
|
||||
monday = 2,
|
||||
tuesday = 4,
|
||||
wednesday = 8,
|
||||
thursday = 16,
|
||||
friday = 32,
|
||||
weekDays = 62,
|
||||
saturday = 64,
|
||||
weekEnds = 65,
|
||||
everyDay = 127
|
||||
}
|
||||
|
||||
export interface AgentJobHistoryResult {
|
||||
succeeded: boolean;
|
||||
errorMessage: string;
|
||||
jobs: AgentJobHistoryInfo[];
|
||||
export enum NotifyMethods {
|
||||
none = 0,
|
||||
notifyEmail = 1,
|
||||
pager = 2,
|
||||
netSend = 4,
|
||||
notifyAll = 7
|
||||
}
|
||||
|
||||
export interface AgentJobActionResult {
|
||||
succeeded: boolean;
|
||||
errorMessage: string;
|
||||
export enum AlertType {
|
||||
sqlServerEvent = 1,
|
||||
sqlServerPerformanceCondition = 2,
|
||||
nonSqlServerEvent = 3,
|
||||
wmiEvent = 4
|
||||
}
|
||||
|
||||
export interface AgentJobInfo {
|
||||
@@ -1061,7 +1072,8 @@ declare module 'sqlops' {
|
||||
jobId: string;
|
||||
}
|
||||
|
||||
export interface AgentJobStep {
|
||||
export interface AgentJobStepInfo {
|
||||
jobId: string;
|
||||
stepId: string;
|
||||
stepName: string;
|
||||
message: string;
|
||||
@@ -1086,13 +1098,168 @@ declare module 'sqlops' {
|
||||
operatorPaged: string;
|
||||
retriesAttempted: string;
|
||||
server: string;
|
||||
steps: AgentJobStep[];
|
||||
steps: AgentJobStepInfo[];
|
||||
}
|
||||
|
||||
export interface AgentProxyInfo {
|
||||
id: number;
|
||||
accountName: string;
|
||||
description: string;
|
||||
credentialName: string;
|
||||
credentialIdentity: string;
|
||||
credentialId: number;
|
||||
isEnabled: boolean;
|
||||
}
|
||||
|
||||
export interface AgentAlertInfo {
|
||||
id: number;
|
||||
delayBetweenResponses: number;
|
||||
eventDescriptionKeyword: string;
|
||||
eventSource: string;
|
||||
hasNotification: number;
|
||||
includeEventDescription: NotifyMethods;
|
||||
isEnabled: boolean;
|
||||
jobId: string;
|
||||
jobName: string;
|
||||
lastOccurrenceDate: string;
|
||||
lastResponseDate: string;
|
||||
messageId: number;
|
||||
notificationMessage: string;
|
||||
occurrenceCount: number;
|
||||
performanceCondition: string;
|
||||
severity: number;
|
||||
databaseName: string;
|
||||
countResetDate: string;
|
||||
categoryName: string;
|
||||
alertType: AlertType;
|
||||
wmiEventNamespace: string;
|
||||
wmiEventQuery: string;
|
||||
}
|
||||
|
||||
export interface AgentOperatorInfo {
|
||||
name: string;
|
||||
id: number;
|
||||
emailAddress: string;
|
||||
enabled: boolean;
|
||||
lastEmailDate: string;
|
||||
lastNetSendDate: string;
|
||||
lastPagerDate: string;
|
||||
pagerAddress: string;
|
||||
categoryName: string;
|
||||
pagerDays: WeekDays;
|
||||
saturdayPagerEndTime: string;
|
||||
saturdayPagerStartTime: string;
|
||||
sundayPagerEndTime: string;
|
||||
sundayPagerStartTime: string;
|
||||
netSendAddress: string;
|
||||
weekdayPagerStartTime: string;
|
||||
weekdayPagerEndTime: string;
|
||||
}
|
||||
|
||||
export interface ResultStatus {
|
||||
success: boolean;
|
||||
errorMessage: string;
|
||||
}
|
||||
|
||||
export interface AgentJobsResult extends ResultStatus {
|
||||
jobs: AgentJobInfo[];
|
||||
}
|
||||
|
||||
export interface AgentJobHistoryResult extends ResultStatus {
|
||||
jobs: AgentJobHistoryInfo[];
|
||||
}
|
||||
|
||||
export interface CreateAgentJobResult extends ResultStatus {
|
||||
job: AgentJobInfo;
|
||||
}
|
||||
|
||||
export interface UpdateAgentJobResult extends ResultStatus {
|
||||
job: AgentJobInfo;
|
||||
}
|
||||
|
||||
export interface CreateAgentJobStepResult extends ResultStatus {
|
||||
step: AgentJobStepInfo;
|
||||
}
|
||||
|
||||
export interface UpdateAgentJobStepResult extends ResultStatus {
|
||||
step: AgentJobStepInfo;
|
||||
}
|
||||
|
||||
export interface CreateAgentProxyResult extends ResultStatus {
|
||||
step: AgentJobStepInfo;
|
||||
}
|
||||
|
||||
export interface UpdateAgentProxyResult extends ResultStatus {
|
||||
step: AgentJobStepInfo;
|
||||
}
|
||||
|
||||
export interface AgentAlertsResult extends ResultStatus {
|
||||
alerts: AgentAlertInfo[];
|
||||
}
|
||||
|
||||
export interface CreateAgentAlertResult extends ResultStatus {
|
||||
alert: AgentJobStepInfo;
|
||||
}
|
||||
|
||||
export interface UpdateAgentAlertResult extends ResultStatus {
|
||||
alert: AgentJobStepInfo;
|
||||
}
|
||||
|
||||
export interface AgentOperatorsResult extends ResultStatus {
|
||||
operators: AgentOperatorInfo[];
|
||||
}
|
||||
|
||||
export interface CreateAgentOperatorResult extends ResultStatus {
|
||||
operator: AgentOperatorInfo;
|
||||
}
|
||||
|
||||
export interface UpdateAgentOperatorResult extends ResultStatus {
|
||||
operator: AgentOperatorInfo;
|
||||
}
|
||||
|
||||
export interface AgentProxiesResult extends ResultStatus {
|
||||
operators: AgentOperatorInfo[];
|
||||
}
|
||||
|
||||
export interface CreateAgentProxyResult extends ResultStatus {
|
||||
operator: AgentOperatorInfo;
|
||||
}
|
||||
|
||||
export interface UpdateAgentProxyResult extends ResultStatus {
|
||||
operator: AgentOperatorInfo;
|
||||
}
|
||||
|
||||
export interface AgentServicesProvider extends DataProvider {
|
||||
getJobs(connectionUri: string): Thenable<AgentJobsResult>;
|
||||
getJobHistory(connectionUri: string, jobId: string): Thenable<AgentJobHistoryResult>;
|
||||
jobAction(connectionUri: string, jobName: string, action: string): Thenable<AgentJobActionResult>;
|
||||
// Job management methods
|
||||
getJobs(ownerUri: string): Thenable<AgentJobsResult>;
|
||||
getJobHistory(ownerUri: string, jobId: string): Thenable<AgentJobHistoryResult>;
|
||||
jobAction(ownerUri: string, jobName: string, action: string): Thenable<ResultStatus>;
|
||||
createJob(ownerUri: string, jobInfo: AgentJobInfo): Thenable<CreateAgentJobResult>;
|
||||
updateJob(ownerUri: string, originalJobName: string, jobInfo: AgentJobInfo): Thenable<UpdateAgentJobResult>;
|
||||
deleteJob(ownerUri: string, jobInfo: AgentJobInfo): Thenable<ResultStatus>;
|
||||
|
||||
// Job Step management methods
|
||||
createJobStep(ownerUri: string, jobInfo: AgentJobStepInfo): Thenable<CreateAgentJobStepResult>;
|
||||
updateJobStep(ownerUri: string, originalJobStepName: string, jobInfo: AgentJobStepInfo): Thenable<UpdateAgentJobStepResult>;
|
||||
deleteJobStep(ownerUri: string, jobInfo: AgentJobStepInfo): Thenable<ResultStatus>;
|
||||
|
||||
// Alert management methods
|
||||
getAlerts(ownerUri: string): Thenable<AgentAlertsResult>;
|
||||
createAlert(ownerUri: string, alertInfo: AgentAlertInfo): Thenable<CreateAgentAlertResult>;
|
||||
updateAlert(ownerUri: string, originalAlertName: string, alertInfo: AgentAlertInfo): Thenable<UpdateAgentAlertResult>;
|
||||
deleteAlert(ownerUri: string, alertInfo: AgentAlertInfo): Thenable<ResultStatus>;
|
||||
|
||||
// Operator management methods
|
||||
getOperators(ownerUri: string): Thenable<AgentOperatorsResult>;
|
||||
createOperator(ownerUri: string, operatorInfo: AgentOperatorInfo): Thenable<CreateAgentOperatorResult>;
|
||||
updateOperator(ownerUri: string, originalOperatorName: string, operatorInfo: AgentOperatorInfo): Thenable<UpdateAgentOperatorResult>;
|
||||
deleteOperator(ownerUri: string, operatorInfo: AgentOperatorInfo): Thenable<ResultStatus>;
|
||||
|
||||
// Proxy management methods
|
||||
getProxies(ownerUri: string): Thenable<AgentProxiesResult>;
|
||||
createProxy(ownerUri: string, proxyInfo: AgentProxyInfo): Thenable<CreateAgentOperatorResult>;
|
||||
updateProxy(ownerUri: string, originalProxyName: string, proxyInfo: AgentProxyInfo): Thenable<UpdateAgentOperatorResult>;
|
||||
deleteProxy(ownerUri: string, proxyInfo: AgentProxyInfo): Thenable<ResultStatus>;
|
||||
}
|
||||
|
||||
// Task service interfaces ----------------------------------------------------------------------------
|
||||
|
||||
94
src/sql/sqlops.proposed.d.ts
vendored
94
src/sql/sqlops.proposed.d.ts
vendored
@@ -26,7 +26,9 @@ declare module 'sqlops' {
|
||||
text(): ComponentBuilder<TextComponent>;
|
||||
button(): ComponentBuilder<ButtonComponent>;
|
||||
dropDown(): ComponentBuilder<DropDownComponent>;
|
||||
listBox(): ComponentBuilder<ListBoxComponent>;
|
||||
table(): ComponentBuilder<TableComponent>;
|
||||
declarativeTable(): ComponentBuilder<DeclarativeTableComponent>;
|
||||
dashboardWidget(widgetId: string): ComponentBuilder<DashboardWidgetComponent>;
|
||||
dashboardWebview(webviewId: string): ComponentBuilder<DashboardWebviewComponent>;
|
||||
formContainer(): FormBuilder;
|
||||
@@ -104,11 +106,11 @@ declare module 'sqlops' {
|
||||
/**
|
||||
* Sends any updated properties of the component to the UI
|
||||
*
|
||||
* @returns {Thenable<boolean>} Thenable that completes once the update
|
||||
* @returns {Thenable<void>} Thenable that completes once the update
|
||||
* has been applied in the UI
|
||||
* @memberof Component
|
||||
*/
|
||||
updateProperties(properties: { [key: string]: any }): Thenable<boolean>;
|
||||
updateProperties(properties: { [key: string]: any }): Thenable<void>;
|
||||
|
||||
enabled: boolean;
|
||||
/**
|
||||
@@ -205,7 +207,15 @@ declare module 'sqlops' {
|
||||
*/
|
||||
alignContent?: string;
|
||||
|
||||
/**
|
||||
* Container Height
|
||||
*/
|
||||
height?: number | string;
|
||||
|
||||
/**
|
||||
* Container Width
|
||||
*/
|
||||
width?: number | string;
|
||||
}
|
||||
|
||||
export interface FlexItemLayout {
|
||||
@@ -226,7 +236,8 @@ declare module 'sqlops' {
|
||||
}
|
||||
|
||||
export interface FormLayout {
|
||||
width?: number;
|
||||
width?: number | string;
|
||||
height?: number | string;
|
||||
}
|
||||
|
||||
export interface GroupLayout {
|
||||
@@ -292,21 +303,29 @@ declare module 'sqlops' {
|
||||
|
||||
export type InputBoxInputType = 'color' | 'date' | 'datetime-local' | 'email' | 'month' | 'number' | 'password' | 'range' | 'search' | 'text' | 'time' | 'url' | 'week';
|
||||
|
||||
export interface InputBoxProperties {
|
||||
export interface ComponentProperties {
|
||||
height: number | string;
|
||||
width: number | string;
|
||||
}
|
||||
|
||||
export interface InputBoxProperties extends ComponentProperties {
|
||||
value?: string;
|
||||
ariaLabel?: string;
|
||||
placeHolder?: string;
|
||||
height: number;
|
||||
width: number;
|
||||
inputType?: InputBoxInputType;
|
||||
required?: boolean;
|
||||
multiline?: boolean;
|
||||
rows?: number;
|
||||
columns?: number;
|
||||
min?: number;
|
||||
max?: number;
|
||||
}
|
||||
|
||||
export interface TableColumn {
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface TableComponentProperties {
|
||||
export interface TableComponentProperties extends ComponentProperties {
|
||||
data: any[][];
|
||||
columns: string[] | TableColumn[];
|
||||
selectedRows?: number[];
|
||||
@@ -317,6 +336,12 @@ declare module 'sqlops' {
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export enum DeclarativeDataType {
|
||||
string = 'string',
|
||||
category = 'category',
|
||||
boolean = 'boolean'
|
||||
}
|
||||
|
||||
export interface RadioButtonProperties {
|
||||
name?: string;
|
||||
label?: string;
|
||||
@@ -328,18 +353,37 @@ declare module 'sqlops' {
|
||||
value?: string;
|
||||
}
|
||||
|
||||
export interface DropDownProperties {
|
||||
export interface DropDownProperties extends ComponentProperties {
|
||||
value?: string;
|
||||
values?: string[];
|
||||
values?: string[] | CategoryValue[];
|
||||
editable?: boolean;
|
||||
}
|
||||
|
||||
export interface DeclarativeTableColumn {
|
||||
displayName: string;
|
||||
categoryValues: CategoryValue[];
|
||||
valueType: DeclarativeDataType;
|
||||
isReadOnly: boolean;
|
||||
width: number | string;
|
||||
}
|
||||
|
||||
export interface DeclarativeTableProperties {
|
||||
data: any[][];
|
||||
columns: DeclarativeTableColumn[];
|
||||
}
|
||||
|
||||
export interface ListBoxProperties {
|
||||
selectedRow?: number;
|
||||
values?: string[];
|
||||
|
||||
}
|
||||
|
||||
export interface WebViewProperties {
|
||||
message?: any;
|
||||
html?: string;
|
||||
}
|
||||
|
||||
export interface ButtonProperties {
|
||||
export interface ButtonProperties extends ComponentProperties {
|
||||
label?: string;
|
||||
iconPath?: string | vscode.Uri | { light: string | vscode.Uri; dark: string | vscode.Uri };
|
||||
}
|
||||
@@ -375,10 +419,26 @@ declare module 'sqlops' {
|
||||
|
||||
export interface DropDownComponent extends Component, DropDownProperties {
|
||||
value: string;
|
||||
values: string[];
|
||||
values: string[] | CategoryValue[];
|
||||
onValueChanged: vscode.Event<any>;
|
||||
}
|
||||
|
||||
export interface TableCell {
|
||||
row: number;
|
||||
column: number;
|
||||
value: any;
|
||||
}
|
||||
|
||||
export interface DeclarativeTableComponent extends Component, DeclarativeTableProperties {
|
||||
onDataChanged: vscode.Event<any>;
|
||||
}
|
||||
|
||||
export interface ListBoxComponent extends Component, ListBoxProperties {
|
||||
selectedRow?: number;
|
||||
values: string[];
|
||||
onRowSelected: vscode.Event<any>;
|
||||
}
|
||||
|
||||
export interface TableComponent extends Component, TableComponentProperties {
|
||||
onRowSelected: vscode.Event<any>;
|
||||
}
|
||||
@@ -609,7 +669,7 @@ declare module 'sqlops' {
|
||||
lastPage: number,
|
||||
|
||||
/**
|
||||
* The new page number
|
||||
* The new page number or undefined if the user is closing the wizard
|
||||
*/
|
||||
newPage: number
|
||||
}
|
||||
@@ -722,6 +782,16 @@ declare module 'sqlops' {
|
||||
* Close the wizard. Does nothing if the wizard is not open.
|
||||
*/
|
||||
close(): Thenable<void>;
|
||||
|
||||
/**
|
||||
* Register a callback that will be called when the user tries to navigate by
|
||||
* changing pages or clicking done. Only one callback can be registered at once, so
|
||||
* each registration call will clear the previous registration.
|
||||
* @param validator The callback that gets executed when the user tries to
|
||||
* navigate. Return true to allow the navigation to proceed, or false to
|
||||
* cancel it.
|
||||
*/
|
||||
registerNavigationValidator(validator: (pageChangeInfo: WizardPageChangeInfo) => boolean | Thenable<boolean>): void;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,12 +63,45 @@ export enum ScriptOperation {
|
||||
Alter = 6
|
||||
}
|
||||
|
||||
export enum WeekDays
|
||||
{
|
||||
sunday = 1,
|
||||
monday = 2,
|
||||
tuesday = 4,
|
||||
wednesday = 8,
|
||||
thursday = 16,
|
||||
friday = 32,
|
||||
weekDays = 62,
|
||||
saturday = 64,
|
||||
weekEnds = 65,
|
||||
everyDay = 127
|
||||
}
|
||||
|
||||
export enum NotifyMethods
|
||||
{
|
||||
none = 0,
|
||||
notifyEmail = 1,
|
||||
pager = 2,
|
||||
netSend = 4,
|
||||
notifyAll = 7
|
||||
}
|
||||
|
||||
export enum AlertType
|
||||
{
|
||||
sqlServerEvent = 1,
|
||||
sqlServerPerformanceCondition = 2,
|
||||
nonSqlServerEvent = 3,
|
||||
wmiEvent = 4
|
||||
}
|
||||
|
||||
export enum ModelComponentTypes {
|
||||
NavContainer,
|
||||
FlexContainer,
|
||||
Card,
|
||||
InputBox,
|
||||
DropDown,
|
||||
DeclarativeTable,
|
||||
ListBox,
|
||||
Button,
|
||||
CheckBox,
|
||||
RadioButton,
|
||||
@@ -185,3 +218,9 @@ export enum DataProviderType {
|
||||
AgentServicesProvider = 'AgentServicesProvider',
|
||||
CapabilitiesProvider = 'CapabilitiesProvider'
|
||||
}
|
||||
|
||||
export enum DeclarativeDataType {
|
||||
string = 'string',
|
||||
category = 'category',
|
||||
boolean = 'boolean'
|
||||
}
|
||||
@@ -503,6 +503,14 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
|
||||
return this._resolveProvider<sqlops.ProfilerProvider>(handle).stopSession(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause a profiler session
|
||||
*/
|
||||
public $pauseSession(handle: number, sessionId: string): Thenable<boolean> {
|
||||
return this._resolveProvider<sqlops.ProfilerProvider>(handle).pauseSession(sessionId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Profiler session events available notification
|
||||
*/
|
||||
@@ -532,7 +540,7 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
|
||||
/**
|
||||
* Run an action on a job
|
||||
*/
|
||||
public $jobAction(handle: number, ownerUri: string, jobName: string, action: string): Thenable<sqlops.AgentJobActionResult> {
|
||||
public $jobAction(handle: number, ownerUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus> {
|
||||
return this._resolveProvider<sqlops.AgentServicesProvider>(handle).jobAction(ownerUri, jobName, action);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +116,13 @@ class ModelBuilderImpl implements sqlops.ModelBuilder {
|
||||
return builder;
|
||||
}
|
||||
|
||||
listBox(): sqlops.ComponentBuilder<sqlops.ListBoxComponent> {
|
||||
let id = this.getNextComponentId();
|
||||
let builder: ComponentBuilderImpl<sqlops.ListBoxComponent> = this.getComponentBuilder(new ListBoxWrapper(this._proxy, this._handle, id), id);
|
||||
this._componentBuilders.set(id, builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
table(): sqlops.ComponentBuilder<sqlops.TableComponent> {
|
||||
let id = this.getNextComponentId();
|
||||
let builder: ComponentBuilderImpl<sqlops.TableComponent> = this.getComponentBuilder(new TableComponentWrapper(this._proxy, this._handle, id), id);
|
||||
@@ -123,6 +130,13 @@ class ModelBuilderImpl implements sqlops.ModelBuilder {
|
||||
return builder;
|
||||
}
|
||||
|
||||
declarativeTable(): sqlops.ComponentBuilder<sqlops.DeclarativeTableComponent> {
|
||||
let id = this.getNextComponentId();
|
||||
let builder: ComponentBuilderImpl<sqlops.DeclarativeTableComponent> = this.getComponentBuilder(new DeclarativeTableWrapper(this._proxy, this._handle, id), id);
|
||||
this._componentBuilders.set(id, builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
dashboardWidget(widgetId: string): sqlops.ComponentBuilder<sqlops.DashboardWidgetComponent> {
|
||||
let id = this.getNextComponentId();
|
||||
let builder = this.getComponentBuilder<sqlops.DashboardWidgetComponent>(new ComponentWrapper(this._proxy, this._handle, ModelComponentTypes.DashboardWidget, id), id);
|
||||
@@ -328,7 +342,6 @@ class InternalItemConfig {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ComponentWrapper implements sqlops.Component {
|
||||
public properties: { [key: string]: any } = {};
|
||||
public layout: any;
|
||||
@@ -371,6 +384,22 @@ class ComponentWrapper implements sqlops.Component {
|
||||
this.setProperty('enabled', value);
|
||||
}
|
||||
|
||||
public get height(): number | string {
|
||||
return this.properties['height'];
|
||||
}
|
||||
|
||||
public set height(v: number | string) {
|
||||
this.setProperty('height', v);
|
||||
}
|
||||
|
||||
public get width(): number | string {
|
||||
return this.properties['width'];
|
||||
}
|
||||
|
||||
public set width(v: number | string) {
|
||||
this.setProperty('width', v);
|
||||
}
|
||||
|
||||
public toComponentShape(): IComponentShape {
|
||||
return <IComponentShape>{
|
||||
id: this.id,
|
||||
@@ -406,12 +435,13 @@ class ComponentWrapper implements sqlops.Component {
|
||||
return this._proxy.$setLayout(this._handle, this.id, layout);
|
||||
}
|
||||
|
||||
public updateProperties(): Thenable<boolean> {
|
||||
public updateProperties(properties: { [key: string]: any }): Thenable<void> {
|
||||
this.properties = Object.assign(this.properties, properties);
|
||||
return this.notifyPropertyChanged();
|
||||
}
|
||||
|
||||
protected notifyPropertyChanged(): Thenable<boolean> {
|
||||
return this._proxy.$setProperties(this._handle, this._id, this.properties).then(() => true);
|
||||
protected notifyPropertyChanged(): Thenable<void> {
|
||||
return this._proxy.$setProperties(this._handle, this._id, this.properties);
|
||||
}
|
||||
|
||||
public registerEvent(): Thenable<boolean> {
|
||||
@@ -421,9 +451,9 @@ class ComponentWrapper implements sqlops.Component {
|
||||
public onEvent(eventArgs: IComponentEventArgs) {
|
||||
if (eventArgs && eventArgs.eventType === ComponentEventType.PropertiesChanged) {
|
||||
this.properties = eventArgs.args;
|
||||
}
|
||||
else if (eventArgs && eventArgs.eventType === ComponentEventType.validityChanged) {
|
||||
} else if (eventArgs && eventArgs.eventType === ComponentEventType.validityChanged) {
|
||||
this._valid = eventArgs.args;
|
||||
this._onValidityChangedEmitter.fire(this._valid);
|
||||
} else if (eventArgs) {
|
||||
let emitter = this._emitterMap.get(eventArgs.eventType);
|
||||
if (emitter) {
|
||||
@@ -432,13 +462,13 @@ class ComponentWrapper implements sqlops.Component {
|
||||
}
|
||||
}
|
||||
|
||||
protected async setProperty(key: string, value: any): Promise<boolean> {
|
||||
protected async setProperty(key: string, value: any): Promise<void> {
|
||||
if (!this.properties[key] || this.properties[key] !== value) {
|
||||
// Only notify the front end if a value has been updated
|
||||
this.properties[key] = value;
|
||||
return this.notifyPropertyChanged();
|
||||
}
|
||||
return Promise.resolve(true);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
private handleError(err: Error): void {
|
||||
@@ -538,18 +568,39 @@ class InputBoxWrapper extends ComponentWrapper implements sqlops.InputBoxCompone
|
||||
this.setProperty('placeHolder', v);
|
||||
}
|
||||
|
||||
public get height(): number {
|
||||
return this.properties['height'];
|
||||
public get rows(): number {
|
||||
return this.properties['rows'];
|
||||
}
|
||||
public set height(v: number) {
|
||||
this.setProperty('height', v);
|
||||
public set rows(v: number) {
|
||||
this.setProperty('rows', v);
|
||||
}
|
||||
|
||||
public get width(): number {
|
||||
return this.properties['width'];
|
||||
public get min(): number {
|
||||
return this.properties['min'];
|
||||
}
|
||||
public set width(v: number) {
|
||||
this.setProperty('width', v);
|
||||
public set min(v: number) {
|
||||
this.setProperty('min', v);
|
||||
}
|
||||
|
||||
public get max(): number {
|
||||
return this.properties['max'];
|
||||
}
|
||||
public set max(v: number) {
|
||||
this.setProperty('max', v);
|
||||
}
|
||||
|
||||
public get columns(): number {
|
||||
return this.properties['columns'];
|
||||
}
|
||||
public set columns(v: number) {
|
||||
this.setProperty('columns', v);
|
||||
}
|
||||
|
||||
public get multiline(): boolean {
|
||||
return this.properties['multiline'];
|
||||
}
|
||||
public set multiline(v: boolean) {
|
||||
this.setProperty('multiline', v);
|
||||
}
|
||||
|
||||
public get inputType(): sqlops.InputBoxInputType {
|
||||
@@ -727,10 +778,10 @@ class DropDownWrapper extends ComponentWrapper implements sqlops.DropDownCompone
|
||||
this.setProperty('value', v);
|
||||
}
|
||||
|
||||
public get values(): string[] {
|
||||
public get values(): string[] | sqlops.CategoryValue[] {
|
||||
return this.properties['values'];
|
||||
}
|
||||
public set values(v: string[]) {
|
||||
public set values(v: string[] | sqlops.CategoryValue[]) {
|
||||
this.setProperty('values', v);
|
||||
}
|
||||
|
||||
@@ -747,6 +798,63 @@ class DropDownWrapper extends ComponentWrapper implements sqlops.DropDownCompone
|
||||
}
|
||||
}
|
||||
|
||||
class DeclarativeTableWrapper extends ComponentWrapper implements sqlops.DeclarativeTableComponent {
|
||||
|
||||
constructor(proxy: MainThreadModelViewShape, handle: number, id: string) {
|
||||
super(proxy, handle, ModelComponentTypes.DeclarativeTable, id);
|
||||
this.properties = {};
|
||||
this._emitterMap.set(ComponentEventType.onDidChange, new Emitter<any>());
|
||||
}
|
||||
|
||||
public get data(): any[][] {
|
||||
return this.properties['data'];
|
||||
}
|
||||
public set data(v: any[][]) {
|
||||
this.setProperty('data', v);
|
||||
}
|
||||
|
||||
public get columns(): sqlops.DeclarativeTableColumn[] {
|
||||
return this.properties['columns'];
|
||||
}
|
||||
|
||||
public set columns(v: sqlops.DeclarativeTableColumn[]) {
|
||||
this.setProperty('columns', v);
|
||||
}
|
||||
|
||||
public get onDataChanged(): vscode.Event<any> {
|
||||
let emitter = this._emitterMap.get(ComponentEventType.onDidChange);
|
||||
return emitter && emitter.event;
|
||||
}
|
||||
}
|
||||
|
||||
class ListBoxWrapper extends ComponentWrapper implements sqlops.ListBoxComponent {
|
||||
|
||||
constructor(proxy: MainThreadModelViewShape, handle: number, id: string) {
|
||||
super(proxy, handle, ModelComponentTypes.ListBox, id);
|
||||
this.properties = {};
|
||||
this._emitterMap.set(ComponentEventType.onSelectedRowChanged, new Emitter<any>());
|
||||
}
|
||||
|
||||
public get selectedRow(): number {
|
||||
return this.properties['selectedRow'];
|
||||
}
|
||||
public set selectedRow(v: number) {
|
||||
this.setProperty('selectedRow', v);
|
||||
}
|
||||
|
||||
public get values(): string[] {
|
||||
return this.properties['values'];
|
||||
}
|
||||
public set values(v: string[]) {
|
||||
this.setProperty('values', v);
|
||||
}
|
||||
|
||||
public get onRowSelected(): vscode.Event<any> {
|
||||
let emitter = this._emitterMap.get(ComponentEventType.onSelectedRowChanged);
|
||||
return emitter && emitter.event;
|
||||
}
|
||||
}
|
||||
|
||||
class ButtonWrapper extends ComponentWrapper implements sqlops.ButtonComponent {
|
||||
|
||||
constructor(proxy: MainThreadModelViewShape, handle: number, id: string) {
|
||||
|
||||
@@ -217,6 +217,7 @@ class WizardImpl implements sqlops.window.modelviewdialog.Wizard {
|
||||
public customButtons: sqlops.window.modelviewdialog.Button[];
|
||||
private _pageChangedEmitter = new Emitter<sqlops.window.modelviewdialog.WizardPageChangeInfo>();
|
||||
public readonly onPageChanged = this._pageChangedEmitter.event;
|
||||
private _navigationValidator: (info: sqlops.window.modelviewdialog.WizardPageChangeInfo) => boolean | Thenable<boolean>;
|
||||
|
||||
constructor(public title: string, private _extHostModelViewDialog: ExtHostModelViewDialog) {
|
||||
this.doneButton = this._extHostModelViewDialog.createButton(DONE_LABEL);
|
||||
@@ -225,6 +226,7 @@ class WizardImpl implements sqlops.window.modelviewdialog.Wizard {
|
||||
this.nextButton = this._extHostModelViewDialog.createButton(NEXT_LABEL);
|
||||
this.backButton = this._extHostModelViewDialog.createButton(PREVIOUS_LABEL);
|
||||
this._extHostModelViewDialog.registerWizardPageInfoChangedCallback(this, info => this.handlePageInfoChanged(info));
|
||||
this._currentPage = 0;
|
||||
this.onPageChanged(info => this._currentPage = info.newPage);
|
||||
}
|
||||
|
||||
@@ -254,6 +256,18 @@ class WizardImpl implements sqlops.window.modelviewdialog.Wizard {
|
||||
return this._extHostModelViewDialog.closeWizard(this);
|
||||
}
|
||||
|
||||
public registerNavigationValidator(validator: (pageChangeInfo: sqlops.window.modelviewdialog.WizardPageChangeInfo) => boolean | Thenable<boolean>): void {
|
||||
this._navigationValidator = validator;
|
||||
}
|
||||
|
||||
public validateNavigation(info: sqlops.window.modelviewdialog.WizardPageChangeInfo): Thenable<boolean> {
|
||||
if (this._navigationValidator) {
|
||||
return Promise.resolve(this._navigationValidator(info));
|
||||
} else {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
|
||||
private handlePageInfoChanged(info: WizardPageEventInfo): void {
|
||||
this._currentPage = info.pageChangeInfo.newPage;
|
||||
if (info.eventType === WizardPageInfoEventType.PageAddedOrRemoved) {
|
||||
@@ -335,6 +349,11 @@ export class ExtHostModelViewDialog implements ExtHostModelViewDialogShape {
|
||||
}
|
||||
}
|
||||
|
||||
public $validateNavigation(handle: number, info: sqlops.window.modelviewdialog.WizardPageChangeInfo): Thenable<boolean> {
|
||||
let wizard = this._objectsByHandle.get(handle) as WizardImpl;
|
||||
return wizard.validateNavigation(info);
|
||||
}
|
||||
|
||||
public openDialog(dialog: sqlops.window.modelviewdialog.Dialog): void {
|
||||
let handle = this.getHandle(dialog);
|
||||
this.updateDialogContent(dialog);
|
||||
|
||||
@@ -296,7 +296,7 @@ export class MainThreadDataProtocol implements MainThreadDataProtocolShape {
|
||||
return self._proxy.$stopSession(handle, sessionId);
|
||||
},
|
||||
pauseSession(sessionId: string): Thenable<boolean> {
|
||||
return TPromise.as(true);
|
||||
return self._proxy.$pauseSession(handle, sessionId);
|
||||
},
|
||||
connectSession(sessionId: string): Thenable<boolean> {
|
||||
return TPromise.as(true);
|
||||
@@ -339,7 +339,7 @@ export class MainThreadDataProtocol implements MainThreadDataProtocolShape {
|
||||
getJobHistory(connectionUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult> {
|
||||
return self._proxy.$getJobHistory(handle, connectionUri, jobID);
|
||||
},
|
||||
jobAction(connectionUri: string, jobName: string, action: string): Thenable<sqlops.AgentJobActionResult> {
|
||||
jobAction(connectionUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus> {
|
||||
return self._proxy.$jobAction(handle, connectionUri, jobName, action);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -157,6 +157,7 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape
|
||||
wizard.onPageChanged(info => this._proxy.$onWizardPageChanged(handle, info));
|
||||
wizard.onPageAdded(() => this.handleWizardPageAddedOrRemoved(handle));
|
||||
wizard.onPageRemoved(() => this.handleWizardPageAddedOrRemoved(handle));
|
||||
wizard.registerNavigationValidator(info => this.validateNavigation(handle, info));
|
||||
this._wizards.set(handle, wizard);
|
||||
}
|
||||
|
||||
@@ -254,4 +255,8 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape
|
||||
let wizard = this._wizards.get(handle);
|
||||
this._proxy.$updateWizardPageInfo(handle, wizard.pages.map(page => this._wizardPageHandles.get(page)), wizard.currentPage);
|
||||
}
|
||||
|
||||
private validateNavigation(handle: number, info: sqlops.window.modelviewdialog.WizardPageChangeInfo): Thenable<boolean> {
|
||||
return this._proxy.$validateNavigation(handle, info);
|
||||
}
|
||||
}
|
||||
@@ -369,6 +369,7 @@ export function createApiFactory(
|
||||
serialization,
|
||||
dataprotocol,
|
||||
DataProviderType: sqlExtHostTypes.DataProviderType,
|
||||
DeclarativeDataType: sqlExtHostTypes.DeclarativeDataType,
|
||||
ServiceOptionType: sqlExtHostTypes.ServiceOptionType,
|
||||
ConnectionOptionSpecialType: sqlExtHostTypes.ConnectionOptionSpecialType,
|
||||
EditRowState: sqlExtHostTypes.EditRowState,
|
||||
@@ -376,6 +377,9 @@ export function createApiFactory(
|
||||
TaskStatus: sqlExtHostTypes.TaskStatus,
|
||||
TaskExecutionMode: sqlExtHostTypes.TaskExecutionMode,
|
||||
ScriptOperation: sqlExtHostTypes.ScriptOperation,
|
||||
WeekDays: sqlExtHostTypes.WeekDays,
|
||||
NotifyMethods: sqlExtHostTypes.NotifyMethods,
|
||||
AlertType: sqlExtHostTypes.AlertType,
|
||||
window,
|
||||
tasks,
|
||||
dashboard,
|
||||
|
||||
@@ -313,6 +313,11 @@ export abstract class ExtHostDataProtocolShape {
|
||||
*/
|
||||
$stopSession(handle: number, sessionId: string): Thenable<boolean> { throw ni(); }
|
||||
|
||||
/**
|
||||
* Pause a profiler session
|
||||
*/
|
||||
$pauseSession(handle: number, sessionId: string): Thenable<boolean> { throw ni(); }
|
||||
|
||||
|
||||
/**
|
||||
* Get Agent Job list
|
||||
@@ -327,7 +332,7 @@ export abstract class ExtHostDataProtocolShape {
|
||||
/**
|
||||
* Run an action on a Job
|
||||
*/
|
||||
$jobAction(handle: number, ownerUri: string, jobName: string, action: string): Thenable<sqlops.AgentJobActionResult> { throw ni(); }
|
||||
$jobAction(handle: number, ownerUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus> { throw ni(); }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -556,6 +561,7 @@ export interface ExtHostModelViewDialogShape {
|
||||
$onPanelValidityChanged(handle: number, valid: boolean): void;
|
||||
$onWizardPageChanged(handle: number, info: sqlops.window.modelviewdialog.WizardPageChangeInfo): void;
|
||||
$updateWizardPageInfo(handle: number, pageHandles: number[], currentPageIndex: number): void;
|
||||
$validateNavigation(handle: number, info: sqlops.window.modelviewdialog.WizardPageChangeInfo): Thenable<boolean>;
|
||||
}
|
||||
|
||||
export interface MainThreadModelViewDialogShape extends IDisposable {
|
||||
|
||||
@@ -118,4 +118,14 @@ suite('ExtHostModelView Validation Tests', () => {
|
||||
});
|
||||
assert.equal(inputBox.valid, true, 'Input box did not update validity to true based on the validityChanged event');
|
||||
});
|
||||
|
||||
test('Main thread validityChanged events cause component to fire validity changed events', () => {
|
||||
let validityFromEvent: boolean = undefined;
|
||||
inputBox.onValidityChanged(valid => validityFromEvent = valid);
|
||||
extHostModelView.$handleEvent(handle, inputBox.id, {
|
||||
eventType: ComponentEventType.validityChanged,
|
||||
args: false
|
||||
});
|
||||
assert.equal(validityFromEvent, false, 'Main thread validityChanged event did not cause component to fire its own event');
|
||||
});
|
||||
});
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as assert from 'assert';
|
||||
import { Mock, It, Times } from 'typemoq';
|
||||
import { ExtHostModelViewDialog } from 'sql/workbench/api/node/extHostModelViewDialog';
|
||||
@@ -263,4 +264,30 @@ suite('ExtHostModelViewDialog Tests', () => {
|
||||
extHostModelViewDialog.$onPanelValidityChanged(pageHandle, false);
|
||||
assert.equal(page.valid, false);
|
||||
});
|
||||
|
||||
test('Main thread can execute wizard navigation validation', () => {
|
||||
// Set up the main thread mock to record the wizard handle
|
||||
let wizardHandle: number;
|
||||
mockProxy.setup(x => x.$setWizardDetails(It.isAny(), It.isAny())).callback((handle, details) => wizardHandle = handle);
|
||||
|
||||
// Create the wizard and add a validation that records that it has been called
|
||||
let wizard = extHostModelViewDialog.createWizard('wizard_1');
|
||||
extHostModelViewDialog.updateWizard(wizard);
|
||||
let validationInfo: sqlops.window.modelviewdialog.WizardPageChangeInfo;
|
||||
wizard.registerNavigationValidator(info => {
|
||||
validationInfo = info;
|
||||
return true;
|
||||
});
|
||||
|
||||
// If I call the validation from the main thread then it should run and record the correct page change info
|
||||
let lastPage = 0;
|
||||
let newPage = 1;
|
||||
extHostModelViewDialog.$validateNavigation(wizardHandle, {
|
||||
lastPage: lastPage,
|
||||
newPage: newPage
|
||||
});
|
||||
assert.notEqual(validationInfo, undefined);
|
||||
assert.equal(validationInfo.lastPage, lastPage);
|
||||
assert.equal(validationInfo.newPage, newPage);
|
||||
});
|
||||
});
|
||||
@@ -59,7 +59,8 @@ suite('MainThreadModelViewDialog Tests', () => {
|
||||
$onButtonClick: handle => undefined,
|
||||
$onPanelValidityChanged: (handle, valid) => undefined,
|
||||
$onWizardPageChanged: (handle, info) => undefined,
|
||||
$updateWizardPageInfo: (wizardHandle, pageHandles, currentPageIndex) => undefined
|
||||
$updateWizardPageInfo: (wizardHandle, pageHandles, currentPageIndex) => undefined,
|
||||
$validateNavigation: (handle, info) => undefined
|
||||
});
|
||||
let extHostContext = <IExtHostContext>{
|
||||
getProxy: proxyType => mockExtHostModelViewDialog.object
|
||||
@@ -316,4 +317,15 @@ suite('MainThreadModelViewDialog Tests', () => {
|
||||
It.is(pageHandles => pageHandles.length === 1 && pageHandles[0] === page2Handle),
|
||||
It.is(currentPage => currentPage === 0)), Times.once());
|
||||
});
|
||||
|
||||
test('Creating a wizard adds a navigation validation that calls the extension host', () => {
|
||||
mockExtHostModelViewDialog.setup(x => x.$validateNavigation(It.isAny(), It.isAny()));
|
||||
|
||||
// If I call validateNavigation on the wizard that gets created
|
||||
let wizard: Wizard = (mainThreadModelViewDialog as any).getWizard(wizardHandle);
|
||||
wizard.validateNavigation(1);
|
||||
|
||||
// Then the call gets forwarded to the extension host
|
||||
mockExtHostModelViewDialog.verify(x => x.$validateNavigation(It.is(handle => handle === wizardHandle), It.is(info => info.newPage === 1)), Times.once());
|
||||
});
|
||||
});
|
||||
@@ -248,7 +248,8 @@ export class ContextView {
|
||||
this.$view.hide();
|
||||
}
|
||||
|
||||
private isVisible(): boolean {
|
||||
// {{SQL CARBON EDIT}}
|
||||
public isVisible(): boolean {
|
||||
return !!this.delegate;
|
||||
}
|
||||
|
||||
|
||||
@@ -364,7 +364,11 @@ export class InputBox extends Widget {
|
||||
};
|
||||
}
|
||||
|
||||
if (!errorMsg) {
|
||||
if (errorMsg) {
|
||||
this.inputElement.setAttribute('aria-invalid', 'true');
|
||||
this.showMessage(errorMsg);
|
||||
}
|
||||
else if (this.inputElement.hasAttribute('aria-invalid')) {
|
||||
this.inputElement.removeAttribute('aria-invalid');
|
||||
this.hideMessage();
|
||||
}
|
||||
|
||||
@@ -541,21 +541,22 @@ export class SelectBoxList implements ISelectBoxDelegate, IDelegate<ISelectOptio
|
||||
|
||||
this.selectList.setFocus([this.selected]);
|
||||
this.selectList.reveal(this.selectList.getFocus()[0]);
|
||||
|
||||
// {{SQL CARBON EDIT}} - Update the selection before firing the handler instead of after
|
||||
// Reset Selection Handler
|
||||
this._currentSelection = -1;
|
||||
this.hideSelectDropDown(true);
|
||||
|
||||
this._onDidSelect.fire({
|
||||
index: this.selectElement.selectedIndex,
|
||||
selected: this.selectElement.title
|
||||
});
|
||||
|
||||
// Reset Selection Handler
|
||||
this._currentSelection = -1;
|
||||
this.hideSelectDropDown(true);
|
||||
}
|
||||
dom.EventHelper.stop(e);
|
||||
}
|
||||
|
||||
// List Exit - passive - hide drop-down, fire onDidSelect
|
||||
private onListBlur(): void {
|
||||
|
||||
if (this._currentSelection >= 0) {
|
||||
this.select(this._currentSelection);
|
||||
}
|
||||
|
||||
@@ -771,7 +771,8 @@ export class IssueReporter extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
const queryStringPrefix = product.reportIssueUrl.indexOf('?') === -1 ? '?' : '&';
|
||||
// {{SQL CARBON EDIT}}
|
||||
const queryStringPrefix = repositoryUrl.indexOf('?') === -1 ? '?' : '&';
|
||||
return `${repositoryUrl}${queryStringPrefix}title=${encodeURIComponent(issueTitle)}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,9 @@ export interface ITemplateData {
|
||||
element: HTMLElement;
|
||||
icon: HTMLImageElement;
|
||||
name: HTMLElement;
|
||||
installCount: HTMLElement;
|
||||
ratings: HTMLElement;
|
||||
// {{SQL CARBON EDIT}}
|
||||
//installCount: HTMLElement;
|
||||
//ratings: HTMLElement;
|
||||
author: HTMLElement;
|
||||
description: HTMLElement;
|
||||
extension: IExtension;
|
||||
@@ -103,16 +104,19 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
||||
const reloadAction = this.instantiationService.createInstance(ReloadAction);
|
||||
const manageAction = this.instantiationService.createInstance(ManageExtensionAction);
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
actionbar.push([updateAction, reloadAction, installAction, disabledStatusAction, maliciousStatusAction, manageAction], actionOptions);
|
||||
const disposables = [versionWidget, installCountWidget, ratingsWidget, maliciousStatusAction, disabledStatusAction, updateAction, reloadAction, manageAction, actionbar, bookmarkStyler];
|
||||
const disposables = [versionWidget, /*installCountWidget, ratingsWidget*/, maliciousStatusAction, disabledStatusAction, updateAction, reloadAction, manageAction, actionbar, bookmarkStyler];
|
||||
|
||||
return {
|
||||
root, element, icon, name, installCount, ratings, author, description, disposables,
|
||||
// {{SQL CARBON EDIT}}
|
||||
root, element, icon, name, /*installCount, ratings,*/ author, description, disposables,
|
||||
extensionDisposables: [],
|
||||
set extension(extension: IExtension) {
|
||||
versionWidget.extension = extension;
|
||||
installCountWidget.extension = extension;
|
||||
ratingsWidget.extension = extension;
|
||||
// {{SQL CARBON EDIT}}
|
||||
//installCountWidget.extension = extension;
|
||||
//ratingsWidget.extension = extension;
|
||||
maliciousStatusAction.extension = extension;
|
||||
disabledStatusAction.extension = extension;
|
||||
installAction.extension = extension;
|
||||
@@ -132,8 +136,8 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
||||
data.name.textContent = '';
|
||||
data.author.textContent = '';
|
||||
data.description.textContent = '';
|
||||
data.installCount.style.display = 'none';
|
||||
data.ratings.style.display = 'none';
|
||||
//data.installCount.style.display = 'none';
|
||||
//data.ratings.style.display = 'none';
|
||||
data.extension = null;
|
||||
}
|
||||
|
||||
@@ -173,8 +177,9 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
||||
data.name.textContent = extension.displayName;
|
||||
data.author.textContent = extension.publisherDisplayName;
|
||||
data.description.textContent = extension.description;
|
||||
data.installCount.style.display = '';
|
||||
data.ratings.style.display = '';
|
||||
// {{SQL CARBON EDIT}}
|
||||
//data.installCount.style.display = '';
|
||||
//data.ratings.style.display = '';
|
||||
data.extension = extension;
|
||||
}
|
||||
|
||||
|
||||
@@ -327,19 +327,22 @@ export class ExtensionEditor extends BaseEditor {
|
||||
.done(viewlet => viewlet.search(`publisher:"${extension.publisherDisplayName}"`));
|
||||
});
|
||||
|
||||
if (extension.licenseUrl) {
|
||||
this.license.onclick = finalHandler(() => window.open(extension.licenseUrl));
|
||||
this.license.style.display = 'initial';
|
||||
} else {
|
||||
this.license.onclick = null;
|
||||
this.license.style.display = 'none';
|
||||
}
|
||||
|
||||
} else {
|
||||
this.name.onclick = null;
|
||||
this.rating.onclick = null;
|
||||
this.publisher.onclick = null;
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
if (extension.licenseUrl) {
|
||||
this.license.onclick = finalHandler(() => window.open(extension.licenseUrl));
|
||||
this.license.style.display = 'initial';
|
||||
} else {
|
||||
this.license.onclick = null;
|
||||
this.license.style.display = 'none';
|
||||
}
|
||||
|
||||
if (extension.repository) {
|
||||
this.repository.onclick = finalHandler(() => window.open(extension.repository));
|
||||
this.repository.style.display = 'initial';
|
||||
|
||||
@@ -5889,9 +5889,9 @@ slice-ansi@0.0.4:
|
||||
version "0.0.4"
|
||||
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
|
||||
|
||||
"slickgrid@github:anthonydresser/SlickGrid#2.3.17":
|
||||
version "2.3.17"
|
||||
resolved "https://codeload.github.com/anthonydresser/SlickGrid/tar.gz/8def7636409c51a10890209f90083bb2c3092b3b"
|
||||
"slickgrid@github:anthonydresser/SlickGrid#2.3.16":
|
||||
version "2.3.16"
|
||||
resolved "https://codeload.github.com/anthonydresser/SlickGrid/tar.gz/0cdbb91ca4f24e296e156b704dab51ea9e1cf3ac"
|
||||
dependencies:
|
||||
jquery ">=1.8.0"
|
||||
jquery-ui ">=1.8.0"
|
||||
|
||||
Reference in New Issue
Block a user