mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-26 17:23:15 -05:00
Merge branch 'master' into feature/nativeNotebook
This commit is contained in:
@@ -5,8 +5,8 @@
|
||||
|
||||
import { IThemable } from 'vs/platform/theme/common/styler';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Dimension, EventType } from 'vs/base/browser/dom';
|
||||
import { $, Builder } from 'vs/base/browser/builder';
|
||||
import { Dimension, EventType, $, addDisposableListener } from 'vs/base/browser/dom';
|
||||
import { $ as quickBuilder } from 'vs/base/browser/builder';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IActionOptions, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
@@ -34,8 +34,8 @@ export interface IPanelTab {
|
||||
}
|
||||
|
||||
interface IInternalPanelTab extends IPanelTab {
|
||||
header: Builder;
|
||||
label: Builder;
|
||||
header: HTMLElement;
|
||||
label: HTMLElement;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
@@ -49,10 +49,10 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
private _tabMap = new Map<PanelTabIdentifier, IInternalPanelTab>();
|
||||
private _shownTab: PanelTabIdentifier;
|
||||
public readonly headersize = 35;
|
||||
private $header: Builder;
|
||||
private $tabList: Builder;
|
||||
private $body: Builder;
|
||||
private $parent: Builder;
|
||||
private header: HTMLElement;
|
||||
private tabList: HTMLElement;
|
||||
private body: HTMLElement;
|
||||
private parent: HTMLElement;
|
||||
private _actionbar: ActionBar;
|
||||
private _currentDimensions: Dimension;
|
||||
private _collapsed = false;
|
||||
@@ -65,26 +65,26 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
|
||||
constructor(private container: HTMLElement, private options: IPanelOptions = defaultOptions) {
|
||||
super();
|
||||
this.$parent = this._register($('.tabbedPanel'));
|
||||
this.$parent.appendTo(container);
|
||||
this.$header = $('.composite.title');
|
||||
this.$tabList = $('.tabList');
|
||||
this.$tabList.attr('role', 'tablist');
|
||||
this.$tabList.style('height', this.headersize + 'px');
|
||||
this.$header.append(this.$tabList);
|
||||
this.parent = $('.tabbedPanel');
|
||||
container.appendChild(this.parent);
|
||||
this.header = $('.composite.title');
|
||||
this.tabList = $('.tabList');
|
||||
this.tabList.setAttribute('role', 'tablist');
|
||||
this.tabList.style.height = this.headersize + 'px';
|
||||
this.header.appendChild(this.tabList);
|
||||
let actionbarcontainer = $('.title-actions');
|
||||
this._actionbar = new ActionBar(actionbarcontainer.getHTMLElement());
|
||||
this.$header.append(actionbarcontainer);
|
||||
this._actionbar = new ActionBar(actionbarcontainer);
|
||||
this.header.appendChild(actionbarcontainer);
|
||||
if (options.showHeaderWhenSingleView) {
|
||||
this._headerVisible = true;
|
||||
this.$parent.append(this.$header);
|
||||
this.parent.appendChild(this.header);
|
||||
} else {
|
||||
this._headerVisible = false;
|
||||
}
|
||||
this.$body = $('.tabBody');
|
||||
this.$body.attr('role', 'tabpanel');
|
||||
this.$body.attr('tabindex', '0');
|
||||
this.$parent.append(this.$body);
|
||||
this.body = $('.tabBody');
|
||||
this.body.setAttribute('role', 'tabpanel');
|
||||
this.body.setAttribute('tabindex', '0');
|
||||
this.parent.appendChild(this.body);
|
||||
}
|
||||
|
||||
public contains(tab: IPanelTab): boolean {
|
||||
@@ -99,7 +99,7 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
this.showTab(tab.identifier);
|
||||
}
|
||||
if (this._tabMap.size > 1 && !this._headerVisible) {
|
||||
this.$parent.append(this.$header, 0);
|
||||
this.parent.insertBefore(this.header, this.parent.firstChild);
|
||||
this._headerVisible = true;
|
||||
this.layout(this._currentDimensions);
|
||||
}
|
||||
@@ -116,30 +116,27 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
|
||||
private _createTab(tab: IInternalPanelTab): void {
|
||||
let tabHeaderElement = $('.tab-header');
|
||||
tabHeaderElement.attr('tabindex', '0');
|
||||
tabHeaderElement.attr('role', 'tab');
|
||||
tabHeaderElement.attr('aria-selected', 'false');
|
||||
tabHeaderElement.attr('aria-controls', tab.identifier);
|
||||
tabHeaderElement.setAttribute('tabindex', '0');
|
||||
tabHeaderElement.setAttribute('role', 'tab');
|
||||
tabHeaderElement.setAttribute('aria-selected', 'false');
|
||||
tabHeaderElement.setAttribute('aria-controls', tab.identifier);
|
||||
let tabElement = $('.tab');
|
||||
tabHeaderElement.append(tabElement);
|
||||
tabHeaderElement.appendChild(tabElement);
|
||||
let tabLabel = $('a.tabLabel');
|
||||
tabLabel.safeInnerHtml(tab.title);
|
||||
tabElement.append(tabLabel);
|
||||
tabHeaderElement.on(EventType.CLICK, e => this.showTab(tab.identifier));
|
||||
tabHeaderElement.on(EventType.KEY_DOWN, (e: KeyboardEvent) => {
|
||||
tabLabel.innerText = tab.title;
|
||||
tabElement.appendChild(tabLabel);
|
||||
addDisposableListener(tabHeaderElement, EventType.CLICK, e => this.showTab(tab.identifier));
|
||||
addDisposableListener(tabHeaderElement, EventType.KEY_DOWN, (e: KeyboardEvent) => {
|
||||
let event = new StandardKeyboardEvent(e);
|
||||
if (event.equals(KeyCode.Enter)) {
|
||||
this.showTab(tab.identifier);
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
});
|
||||
this.$tabList.append(tabHeaderElement);
|
||||
this.tabList.appendChild(tabHeaderElement);
|
||||
tab.header = tabHeaderElement;
|
||||
tab.label = tabLabel;
|
||||
tab.dispose = () => {
|
||||
tab.header.dispose();
|
||||
tab.label.dispose();
|
||||
};
|
||||
tab.dispose = () => { };
|
||||
this._register(tab);
|
||||
}
|
||||
|
||||
@@ -149,19 +146,20 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
}
|
||||
|
||||
if (this._shownTab) {
|
||||
this._tabMap.get(this._shownTab).label.removeClass('active');
|
||||
this._tabMap.get(this._shownTab).header.removeClass('active').attr('aria-selected', 'false');
|
||||
this._tabMap.get(this._shownTab).label.classList.remove('active');
|
||||
this._tabMap.get(this._shownTab).header.classList.remove('active');
|
||||
this._tabMap.get(this._shownTab).header.setAttribute('aria-selected', 'false');
|
||||
}
|
||||
|
||||
this._shownTab = id;
|
||||
this.tabHistory.push(id);
|
||||
this.$body.clearChildren();
|
||||
quickBuilder(this.body).empty();
|
||||
let tab = this._tabMap.get(this._shownTab);
|
||||
this.$body.attr('aria-labelledby', tab.identifier);
|
||||
tab.label.addClass('active');
|
||||
tab.header.addClass('active');
|
||||
tab.header.attr('aria-selected', 'true');
|
||||
tab.view.render(this.$body.getHTMLElement());
|
||||
this.body.setAttribute('aria-labelledby', tab.identifier);
|
||||
tab.label.classList.add('active');
|
||||
tab.header.classList.add('active');
|
||||
tab.header.setAttribute('aria-selected', 'true');
|
||||
tab.view.render(this.body);
|
||||
this._onTabChange.fire(id);
|
||||
if (this._currentDimensions) {
|
||||
this._layoutCurrentTab(new Dimension(this._currentDimensions.width, this._currentDimensions.height - this.headersize));
|
||||
@@ -170,11 +168,11 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
|
||||
public removeTab(tab: PanelTabIdentifier) {
|
||||
let actualTab = this._tabMap.get(tab);
|
||||
actualTab.header.destroy();
|
||||
quickBuilder(actualTab.header).destroy();
|
||||
if (actualTab.view.remove) {
|
||||
actualTab.view.remove();
|
||||
}
|
||||
this._tabMap.get(tab).header.destroy();
|
||||
quickBuilder(this._tabMap.get(tab).header).destroy();
|
||||
this._tabMap.delete(tab);
|
||||
if (this._shownTab === tab) {
|
||||
this._shownTab = undefined;
|
||||
@@ -192,7 +190,7 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
}
|
||||
|
||||
if (!this.options.showHeaderWhenSingleView && this._tabMap.size === 1 && this._headerVisible) {
|
||||
this.$header.offDOM();
|
||||
this.header.remove();
|
||||
this._headerVisible = false;
|
||||
this.layout(this._currentDimensions);
|
||||
}
|
||||
@@ -205,12 +203,12 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
public layout(dimension: Dimension): void {
|
||||
if (dimension) {
|
||||
this._currentDimensions = dimension;
|
||||
this.$parent.style('height', dimension.height + 'px');
|
||||
this.$parent.style('width', dimension.width + 'px');
|
||||
this.$header.style('width', dimension.width + 'px');
|
||||
this.$body.style('width', dimension.width + 'px');
|
||||
this.parent.style.height = dimension.height + 'px';
|
||||
this.parent.style.height = dimension.width + 'px';
|
||||
this.header.style.width = dimension.width + 'px';
|
||||
this.body.style.width = dimension.width + 'px';
|
||||
const bodyHeight = dimension.height - (this._headerVisible ? this.headersize : 0);
|
||||
this.$body.style('height', bodyHeight + 'px');
|
||||
this.body.style.height = bodyHeight + 'px';
|
||||
this._layoutCurrentTab(new Dimension(dimension.width, bodyHeight));
|
||||
}
|
||||
}
|
||||
@@ -232,9 +230,9 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
|
||||
this._collapsed = val === false ? false : true;
|
||||
if (this.collapsed) {
|
||||
this.$body.offDOM();
|
||||
this.body.remove();
|
||||
} else {
|
||||
this.$parent.append(this.$body);
|
||||
this.parent.appendChild(this.body);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -192,9 +192,9 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
||||
this.onBeforeAppendCell = (row: number, column: number): string => {
|
||||
let cellClass = undefined;
|
||||
if (this.isRowDirty(row) && column === 0) {
|
||||
cellClass = ' dirtyCell ';
|
||||
} else if (this.isCellDirty(row, column)) {
|
||||
cellClass = ' dirtyRowHeader ';
|
||||
} else if (this.isCellDirty(row, column)) {
|
||||
cellClass = ' dirtyCell ';
|
||||
}
|
||||
|
||||
return cellClass;
|
||||
@@ -279,8 +279,8 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
||||
let cellSelectTasks: Promise<void> = this.submitCurrentCellChange(
|
||||
(result: EditUpdateCellResult) => {
|
||||
// Cell update was successful, update the flags
|
||||
self.setCellDirtyState(row, self.currentCell.column, result.cell.isDirty);
|
||||
self.setRowDirtyState(row, result.isRowDirty);
|
||||
self.setCellDirtyState(self.currentCell.row, self.currentCell.column, result.cell.isDirty);
|
||||
self.setRowDirtyState(self.currentCell.row, result.isRowDirty);
|
||||
return Promise.resolve();
|
||||
},
|
||||
(error) => {
|
||||
@@ -474,10 +474,11 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
||||
//
|
||||
this.currentEditCellValue = undefined;
|
||||
this.dirtyCells = [];
|
||||
let row = this.currentCell.row;
|
||||
this.resetCurrentCell();
|
||||
|
||||
if (this.currentCell.row !== undefined) {
|
||||
this.dataSet.dataRows.resetWindowsAroundIndex(this.currentCell.row);
|
||||
if (row !== undefined) {
|
||||
this.dataSet.dataRows.resetWindowsAroundIndex(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -540,6 +541,9 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
||||
}
|
||||
} else {
|
||||
$(grid.getCellNode(row, column)).removeClass('dirtyCell');
|
||||
if (this.dirtyCells.indexOf(column) !== -1) {
|
||||
this.dirtyCells.splice(this.dirtyCells.indexOf(column), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ export interface IJobManagementService {
|
||||
fireOnDidChange(): void;
|
||||
|
||||
getJobs(connectionUri: string): Thenable<sqlops.AgentJobsResult>;
|
||||
getJobHistory(connectionUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult>;
|
||||
getJobHistory(connectionUri: string, jobID: string, jobName: string): Thenable<sqlops.AgentJobHistoryResult>;
|
||||
deleteJob(connectionUri: string, job: sqlops.AgentJobInfo): Thenable<sqlops.ResultStatus>;
|
||||
|
||||
deleteJobStep(connectionUri: string, step: sqlops.AgentJobStepInfo): Thenable<sqlops.ResultStatus>;
|
||||
|
||||
@@ -43,9 +43,9 @@ export class JobManagementService implements IJobManagementService {
|
||||
});
|
||||
}
|
||||
|
||||
public getJobHistory(connectionUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult> {
|
||||
public getJobHistory(connectionUri: string, jobID: string, jobName: string): Thenable<sqlops.AgentJobHistoryResult> {
|
||||
return this._runAction(connectionUri, (runner) => {
|
||||
return runner.getJobHistory(connectionUri, jobID);
|
||||
return runner.getJobHistory(connectionUri, jobID, jobName);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -142,6 +142,9 @@ export class JobCacheObject {
|
||||
_serviceBrand: any;
|
||||
private _jobs: sqlops.AgentJobInfo[] = [];
|
||||
private _jobHistories: { [jobID: string]: sqlops.AgentJobHistoryInfo[]; } = {};
|
||||
private _jobSteps: { [jobID: string]: sqlops.AgentJobStepInfo[]; } = {};
|
||||
private _jobAlerts: { [jobID: string]: sqlops.AgentAlertInfo[]; } = {};
|
||||
private _jobSchedules: { [jobID: string]: sqlops.AgentJobScheduleInfo[]; } = {};
|
||||
private _runCharts: { [jobID: string]: string[]; } = {};
|
||||
private _prevJobID: string;
|
||||
private _serverName: string;
|
||||
@@ -176,6 +179,18 @@ export class JobCacheObject {
|
||||
return this._runCharts[jobID];
|
||||
}
|
||||
|
||||
public getJobSteps(jobID: string): sqlops.AgentJobStepInfo[] {
|
||||
return this._jobSteps[jobID];
|
||||
}
|
||||
|
||||
public getJobAlerts(jobID: string): sqlops.AgentAlertInfo[] {
|
||||
return this._jobAlerts[jobID];
|
||||
}
|
||||
|
||||
public getJobSchedules(jobID: string): sqlops.AgentJobScheduleInfo[] {
|
||||
return this._jobSchedules[jobID];
|
||||
}
|
||||
|
||||
/* Setters */
|
||||
public set jobs(value: sqlops.AgentJobInfo[]) {
|
||||
this._jobs = value;
|
||||
@@ -204,4 +219,16 @@ export class JobCacheObject {
|
||||
public set dataView(value: Slick.Data.DataView<any>) {
|
||||
this._dataView = value;
|
||||
}
|
||||
|
||||
public setJobSteps(jobID: string, value: sqlops.AgentJobStepInfo[]) {
|
||||
this._jobSteps[jobID] = value;
|
||||
}
|
||||
|
||||
public setJobAlerts(jobID: string, value: sqlops.AgentAlertInfo[]) {
|
||||
this._jobAlerts[jobID] = value;
|
||||
}
|
||||
|
||||
public setJobSchedules(jobID: string, value: sqlops.AgentJobScheduleInfo[]) {
|
||||
this._jobSchedules[jobID] = value;
|
||||
}
|
||||
}
|
||||
@@ -150,16 +150,17 @@ export class JobHistoryComponent extends JobManagementView implements OnInit {
|
||||
private loadHistory() {
|
||||
const self = this;
|
||||
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
||||
this._jobManagementService.getJobHistory(ownerUri, this._agentViewComponent.jobId).then((result) => {
|
||||
if (result && result.jobs) {
|
||||
if (result.jobs.length > 0) {
|
||||
let jobName = this._agentViewComponent.agentJobInfo.name;
|
||||
this._jobManagementService.getJobHistory(ownerUri, this._agentViewComponent.jobId, jobName).then((result) => {
|
||||
if (result && result.histories) {
|
||||
if (result.histories.length > 0) {
|
||||
self._showPreviousRuns = true;
|
||||
self.buildHistoryTree(self, result.jobs);
|
||||
self.buildHistoryTree(self, result.histories);
|
||||
if (self._agentViewComponent.showHistory) {
|
||||
self._cd.detectChanges();
|
||||
}
|
||||
} else {
|
||||
self._jobCacheObject.setJobHistory(self._agentViewComponent.jobId, result.jobs);
|
||||
self._jobCacheObject.setJobHistory(self._agentViewComponent.jobId, result.histories);
|
||||
self._showPreviousRuns = false;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -53,6 +53,7 @@ export abstract class JobManagementView extends TabChild implements AfterContent
|
||||
if (!this.isInitialized) {
|
||||
this._showProgressWheel = true;
|
||||
this.onFirstVisible();
|
||||
this.layout();
|
||||
this.isInitialized = true;
|
||||
}
|
||||
} else if (this.isVisible === true && this._parentComponent.refresh === true) {
|
||||
|
||||
@@ -36,8 +36,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { IDashboardService } from 'sql/services/dashboard/common/dashboardService';
|
||||
import { escape } from 'sql/base/common/strings';
|
||||
import { IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { tableBackground, cellBackground, tableHoverBackground, jobsHeadingBackground, cellBorderColor } from 'sql/common/theme/colors';
|
||||
import { JobStepsViewRow } from 'sql/parts/jobManagement/views/jobStepsViewTree';
|
||||
import { tableBackground, cellBackground, cellBorderColor } from 'sql/common/theme/colors';
|
||||
|
||||
export const JOBSVIEW_SELECTOR: string = 'jobsview-component';
|
||||
export const ROW_HEIGHT: number = 45;
|
||||
@@ -87,7 +86,10 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
private sortingStylingMap: { [columnName: string]: any; } = {};
|
||||
|
||||
public jobs: sqlops.AgentJobInfo[];
|
||||
public jobHistories: { [jobId: string]: sqlops.AgentJobHistoryInfo[]; } = Object.create(null);
|
||||
private jobHistories: { [jobId: string]: sqlops.AgentJobHistoryInfo[]; } = Object.create(null);
|
||||
private jobSteps: { [jobId: string]: sqlops.AgentJobStepInfo[]; } = Object.create(null);
|
||||
private jobAlerts: { [jobId: string]: sqlops.AgentAlertInfo[]; } = Object.create(null);
|
||||
private jobSchedules: { [jobId: string]: sqlops.AgentJobScheduleInfo[]; } = Object.create(null);
|
||||
public contextAction = NewJobAction;
|
||||
|
||||
@ViewChild('jobsgrid') _gridEl: ElementRef;
|
||||
@@ -579,10 +581,14 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
private async curateJobHistory(jobs: sqlops.AgentJobInfo[], ownerUri: string) {
|
||||
const self = this;
|
||||
jobs.forEach(async (job) => {
|
||||
await this._jobManagementService.getJobHistory(ownerUri, job.jobId).then((result) => {
|
||||
if (result && result.jobs) {
|
||||
self.jobHistories[job.jobId] = result.jobs;
|
||||
self._jobCacheObject.setJobHistory(job.jobId, result.jobs);
|
||||
await this._jobManagementService.getJobHistory(ownerUri, job.jobId, job.name).then((result) => {
|
||||
if (result) {
|
||||
self.jobSteps[job.jobId] = result.steps ? result.steps : [];
|
||||
self.jobAlerts[job.jobId] = result.alerts ? result.alerts : [];
|
||||
self.jobSchedules[job.jobId] = result.schedules ? result.schedules : [];
|
||||
self.jobHistories[job.jobId] = result.histories ? result.histories : [];
|
||||
self._jobCacheObject.setJobSteps(job.jobId, self.jobSteps[job.jobId]);
|
||||
self._jobCacheObject.setJobHistory(job.jobId, self.jobHistories[job.jobId]);
|
||||
let jobHistories = self._jobCacheObject.getJobHistory(job.jobId);
|
||||
let previousRuns: sqlops.AgentJobHistoryInfo[];
|
||||
if (jobHistories.length >= 5) {
|
||||
@@ -592,7 +598,7 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
}
|
||||
self.createJobChart(job.jobId, previousRuns);
|
||||
if (self._agentViewComponent.expanded.has(job.jobId)) {
|
||||
let lastJobHistory = jobHistories[result.jobs.length - 1];
|
||||
let lastJobHistory = jobHistories[jobHistories.length - 1];
|
||||
let item = self.dataView.getItemById(job.jobId + '.error');
|
||||
let noStepsMessage = nls.localize('jobsView.noSteps', 'No Steps available for this job.');
|
||||
let errorMessage = lastJobHistory ? lastJobHistory.message : noStepsMessage;
|
||||
@@ -909,29 +915,22 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
jobId = data.getItem(rowIndex - 1).jobId;
|
||||
}
|
||||
}
|
||||
|
||||
let job: sqlops.AgentJobInfo[] = this.jobs.filter(job => {
|
||||
return job.jobId === jobId;
|
||||
});
|
||||
let jobHistories = this.jobHistories[jobId];
|
||||
let steps: sqlops.AgentJobStep[] = undefined;
|
||||
let schedules: sqlops.AgentJobScheduleInfo[] = undefined;
|
||||
let alerts: sqlops.AgentAlertInfo[] = undefined;
|
||||
|
||||
// add steps
|
||||
if (this.jobSteps && this.jobSteps[jobId]) {
|
||||
let steps = this.jobSteps[jobId];
|
||||
job[0].JobSteps = steps;
|
||||
}
|
||||
let jobHistories = this.jobHistories[job[0].jobId];
|
||||
let schedules: sqlops.AgentJobScheduleInfo[] = this.jobSchedules[job[0].jobId];
|
||||
let alerts: sqlops.AgentAlertInfo[] = this.jobAlerts[job[0].jobId];
|
||||
if (jobHistories && jobHistories[jobHistories.length-1]) {
|
||||
// add steps
|
||||
steps = jobHistories[jobHistories.length-1].steps;
|
||||
if (steps && steps.length > 0) {
|
||||
if (!job[0].JobSteps) {
|
||||
job[0].JobSteps = [];
|
||||
}
|
||||
if (job[0].JobSteps.length !== steps.length) {
|
||||
job[0].JobSteps = [];
|
||||
steps.forEach(step => {
|
||||
job[0].JobSteps.push(step.stepDetails);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// add schedules
|
||||
schedules = jobHistories[jobHistories.length-1].schedules;
|
||||
if (schedules && schedules.length > 0) {
|
||||
if (!job[0].JobSchedules) {
|
||||
job[0].JobSchedules = [];
|
||||
@@ -944,7 +943,6 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
}
|
||||
}
|
||||
// add alerts
|
||||
alerts = jobHistories[jobHistories.length-1].alerts;
|
||||
if (!job[0].Alerts) {
|
||||
job[0].Alerts = [];
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ export class ActiveConnectionsFilterAction extends Action {
|
||||
public static LABEL = localize('activeConnections', 'Show Active Connections');
|
||||
private static enabledClass = 'active-connections-action';
|
||||
private static disabledClass = 'icon server-page';
|
||||
private static clearAllLabel = localize('clearAll', 'Clear All');
|
||||
private static showAllConnectionsLabel = localize('showAllConnections', 'Show All Connections');
|
||||
private _isSet: boolean;
|
||||
public static readonly ACTIVE = 'active';
|
||||
public get isSet(): boolean {
|
||||
@@ -249,7 +249,7 @@ export class ActiveConnectionsFilterAction extends Action {
|
||||
// show active connections in the tree
|
||||
this.view.showFilteredTree(ActiveConnectionsFilterAction.ACTIVE);
|
||||
this.isSet = true;
|
||||
this.label = ActiveConnectionsFilterAction.clearAllLabel;
|
||||
this.label = ActiveConnectionsFilterAction.showAllConnectionsLabel;
|
||||
} else {
|
||||
// show full tree
|
||||
this.view.refreshTree();
|
||||
|
||||
@@ -76,7 +76,7 @@ class ResultsView implements IPanelView {
|
||||
this.panelViewlet.resizePanel(this.gridPanel, this.state.messagePanelSize);
|
||||
}
|
||||
this.panelViewlet.resizePanel(this.gridPanel, panelSize);
|
||||
})
|
||||
});
|
||||
// once the user changes the sash we should stop trying to resize the grid
|
||||
once(this.panelViewlet.onDidSashChange)(e => {
|
||||
this.needsGridResize = false;
|
||||
@@ -203,12 +203,14 @@ export class QueryResultsView {
|
||||
if (!this._panelView.contains(this.qpTab)) {
|
||||
this._panelView.pushTab(this.qpTab);
|
||||
}
|
||||
} else if (queryRunner.isQueryPlan) {
|
||||
let disp = queryRunner.onResultSet(() => {
|
||||
this.showPlan(queryRunner.planXml);
|
||||
disp.dispose();
|
||||
});
|
||||
}
|
||||
this.runnerDisposables.push(queryRunner.onQueryEnd(() => {
|
||||
if (queryRunner.isQueryPlan) {
|
||||
queryRunner.planXml.then(e => {
|
||||
this.showPlan(e);
|
||||
});
|
||||
}
|
||||
}));
|
||||
if (this.input.state.activeTab) {
|
||||
this._panelView.showTab(this.input.state.activeTab);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ResultSerializer } from 'sql/parts/query/common/resultSerializer';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { Deferred } from 'sql/base/common/promise';
|
||||
|
||||
export interface IEditSessionReadyEvent {
|
||||
ownerUri: string;
|
||||
@@ -69,11 +70,11 @@ export default class QueryRunner {
|
||||
private _hasCompleted: boolean = false;
|
||||
private _batchSets: sqlops.BatchSummary[] = [];
|
||||
private _eventEmitter = new EventEmitter();
|
||||
private _isQueryPlan: boolean;
|
||||
|
||||
private _isQueryPlan: boolean;
|
||||
public get isQueryPlan(): boolean { return this._isQueryPlan; }
|
||||
private _planXml: string;
|
||||
public get planXml(): string { return this._planXml; }
|
||||
private _planXml = new Deferred<string>();
|
||||
public get planXml(): Thenable<string> { return this._planXml.promise; }
|
||||
|
||||
private _onMessage = new Emitter<sqlops.IResultMessage>();
|
||||
private _debouncedMessage = debounceEvent<sqlops.IResultMessage, sqlops.IResultMessage[]>(this._onMessage.event, (l, e) => {
|
||||
@@ -342,7 +343,7 @@ export default class QueryRunner {
|
||||
}
|
||||
// handle getting queryPlanxml if we need too
|
||||
if (this.isQueryPlan) {
|
||||
this.getQueryRows(0, 1, 0, 0).then(e => this._planXml = e.resultSubset.rows[0][0].displayValue);
|
||||
this.getQueryRows(0, 1, 0, 0).then(e => this._planXml.resolve(e.resultSubset.rows[0][0].displayValue));
|
||||
}
|
||||
if (batchSet) {
|
||||
// Store the result set in the batch and emit that a result set has completed
|
||||
|
||||
19
src/sql/sqlops.d.ts
vendored
19
src/sql/sqlops.d.ts
vendored
@@ -1266,6 +1266,16 @@ declare module 'sqlops' {
|
||||
Last = 16
|
||||
}
|
||||
|
||||
export enum JobExecutionStatus {
|
||||
Executing = 1,
|
||||
WaitingForWorkerThread = 2,
|
||||
BetweenRetries = 3,
|
||||
Idle = 4,
|
||||
Suspended = 5,
|
||||
WaitingForStepToFinish = 6,
|
||||
PerformingCompletionAction = 7
|
||||
}
|
||||
|
||||
export interface AgentJobInfo {
|
||||
name: string;
|
||||
owner: string;
|
||||
@@ -1371,8 +1381,6 @@ declare module 'sqlops' {
|
||||
retriesAttempted: string;
|
||||
server: string;
|
||||
steps: AgentJobStep[];
|
||||
schedules: AgentJobScheduleInfo[];
|
||||
alerts: AgentAlertInfo[];
|
||||
}
|
||||
|
||||
export interface AgentProxyInfo {
|
||||
@@ -1441,7 +1449,10 @@ declare module 'sqlops' {
|
||||
}
|
||||
|
||||
export interface AgentJobHistoryResult extends ResultStatus {
|
||||
jobs: AgentJobHistoryInfo[];
|
||||
histories: AgentJobHistoryInfo[];
|
||||
steps: AgentJobStepInfo[];
|
||||
schedules: AgentJobScheduleInfo[];
|
||||
alerts: AgentAlertInfo[];
|
||||
}
|
||||
|
||||
export interface CreateAgentJobResult extends ResultStatus {
|
||||
@@ -1529,7 +1540,7 @@ declare module 'sqlops' {
|
||||
export interface AgentServicesProvider extends DataProvider {
|
||||
// Job management methods
|
||||
getJobs(ownerUri: string): Thenable<AgentJobsResult>;
|
||||
getJobHistory(ownerUri: string, jobId: string): Thenable<AgentJobHistoryResult>;
|
||||
getJobHistory(ownerUri: string, jobId: string, jobName: 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>;
|
||||
|
||||
@@ -95,6 +95,16 @@ export enum JobCompletionActionCondition {
|
||||
Always = 3
|
||||
}
|
||||
|
||||
export enum JobExecutionStatus {
|
||||
Executing = 1,
|
||||
WaitingForWorkerThread = 2,
|
||||
BetweenRetries = 3,
|
||||
Idle = 4,
|
||||
Suspended = 5,
|
||||
WaitingForStepToFinish = 6,
|
||||
PerformingCompletionAction = 7
|
||||
}
|
||||
|
||||
export enum AlertType {
|
||||
sqlServerEvent = 1,
|
||||
sqlServerPerformanceCondition = 2,
|
||||
|
||||
@@ -578,8 +578,8 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
|
||||
/**
|
||||
* Get a Agent Job's history
|
||||
*/
|
||||
public $getJobHistory(handle: number, ownerUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult> {
|
||||
return this._resolveProvider<sqlops.AgentServicesProvider>(handle).getJobHistory(ownerUri, jobID);
|
||||
public $getJobHistory(handle: number, ownerUri: string, jobID: string, jobName: string): Thenable<sqlops.AgentJobHistoryResult> {
|
||||
return this._resolveProvider<sqlops.AgentServicesProvider>(handle).getJobHistory(ownerUri, jobID, jobName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -350,8 +350,8 @@ export class MainThreadDataProtocol implements MainThreadDataProtocolShape {
|
||||
getJobs(connectionUri: string): Thenable<sqlops.AgentJobsResult> {
|
||||
return self._proxy.$getJobs(handle, connectionUri);
|
||||
},
|
||||
getJobHistory(connectionUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult> {
|
||||
return self._proxy.$getJobHistory(handle, connectionUri, jobID);
|
||||
getJobHistory(connectionUri: string, jobID: string, jobName: string): Thenable<sqlops.AgentJobHistoryResult> {
|
||||
return self._proxy.$getJobHistory(handle, connectionUri, jobID, jobName);
|
||||
},
|
||||
jobAction(connectionUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus> {
|
||||
return self._proxy.$jobAction(handle, connectionUri, jobName, action);
|
||||
|
||||
@@ -422,6 +422,7 @@ export function createApiFactory(
|
||||
WeekDays: sqlExtHostTypes.WeekDays,
|
||||
NotifyMethods: sqlExtHostTypes.NotifyMethods,
|
||||
JobCompletionActionCondition: sqlExtHostTypes.JobCompletionActionCondition,
|
||||
JobExecutionStatus: sqlExtHostTypes.JobExecutionStatus,
|
||||
AlertType: sqlExtHostTypes.AlertType,
|
||||
FrequencyTypes: sqlExtHostTypes.FrequencyTypes,
|
||||
FrequencySubDayTypes: sqlExtHostTypes.FrequencySubDayTypes,
|
||||
|
||||
@@ -358,7 +358,7 @@ export abstract class ExtHostDataProtocolShape {
|
||||
/**
|
||||
* Get a Agent Job's history
|
||||
*/
|
||||
$getJobHistory(handle: number, ownerUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult> { throw ni(); }
|
||||
$getJobHistory(handle: number, ownerUri: string, jobID: string, jobName: string): Thenable<sqlops.AgentJobHistoryResult> { throw ni(); }
|
||||
|
||||
/**
|
||||
* Run an action on a Job
|
||||
|
||||
Reference in New Issue
Block a user