diff --git a/extensions/agent/package.json b/extensions/agent/package.json index 685a29fdf3..96d85eaea4 100644 --- a/extensions/agent/package.json +++ b/extensions/agent/package.json @@ -2,7 +2,7 @@ "name": "agent", "displayName": "SQL Server Agent", "description": "Manage and troubleshoot SQL Server Agent jobs", - "version": "0.48.0", + "version": "0.49.0", "publisher": "Microsoft", "preview": true, "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt", diff --git a/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts b/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts index 9e8d7aabba..ba8e79da8e 100644 --- a/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts +++ b/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts @@ -22,7 +22,7 @@ export interface CommandEventArgs { export class HeaderFilter { - public onFilterApplied = new Slick.Event<{ grid: Slick.Grid, column: IExtendedColumn}>(); + public onFilterApplied = new Slick.Event(); public onCommand = new Slick.Event>(); private grid!: Slick.Grid; @@ -331,7 +331,7 @@ export class HeaderFilter { private handleApply(e: JQuery.Event, columnDef: Slick.Column) { this.hideMenu(); - this.onFilterApplied.notify({ grid: this.grid, column: columnDef }, e, self); + this.onFilterApplied.notify({ 'grid': this.grid, 'column': columnDef }, e, self); e.preventDefault(); e.stopPropagation(); } diff --git a/src/sql/workbench/contrib/jobManagement/browser/jobsView.component.ts b/src/sql/workbench/contrib/jobManagement/browser/jobsView.component.ts index d1faa4f2fa..cc8ae5e182 100644 --- a/src/sql/workbench/contrib/jobManagement/browser/jobsView.component.ts +++ b/src/sql/workbench/contrib/jobManagement/browser/jobsView.component.ts @@ -79,12 +79,12 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe private _jobCacheObject: JobCacheObject; private rowDetail: RowDetailView; - private filterPlugin: HeaderFilter; - private dataView: Slick.Data.DataView; + private filterPlugin: any; + private dataView: any; public _isCloud: boolean; - private filterStylingMap: { [columnName: string]: IItem[]; } = {}; + private filterStylingMap: { [columnName: string]: [any]; } = {}; private filterStack = ['start']; - private filterValueMap: { [columnName: string]: { filterValues: string[], filteredItems: IItem[] } } = {}; + private filterValueMap: { [columnName: string]: string[]; } = {}; private sortingStylingMap: { [columnName: string]: any; } = {}; public jobs: azdata.AgentJobInfo[]; @@ -157,7 +157,7 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe column.rerenderOnResize = true; return column; }); - let options = >{ + let options = >{ syncColumnCellResize: true, enableColumnReorder: false, rowHeight: ROW_HEIGHT, @@ -181,7 +181,7 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe }); this.rowDetail = rowDetail; columns.unshift(this.rowDetail.getColumnDefinition()); - let filterPlugin = new HeaderFilter(); + let filterPlugin = new HeaderFilter<{ inlineFilters: false }>(); this._register(attachButtonStyler(filterPlugin, this._themeService)); this.filterPlugin = filterPlugin; jQuery(this._gridEl.nativeElement).empty(); @@ -254,7 +254,6 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe this._table.grid.resetActiveCell(); let filterValues = args.column.filterValues; if (filterValues) { - let currentFilteredItems = this.dataView.getFilteredItems(); if (filterValues.length === 0) { // if an associated styling exists with the current filters if (this.filterStylingMap[args.column.name]) { @@ -271,8 +270,9 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe delete this.filterValueMap[args.column.name]; } // apply the previous filter styling - let previousFilteredItems = this.filterValueMap[this.filterStack[this.filterStack.length - 1]].filteredItems; - if (previousFilteredItems === currentFilteredItems) { + 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]); @@ -280,13 +280,14 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe } else { // style it all over again let seenJobs = 0; - for (let i = 0; i < currentFilteredItems.length; i++) { + 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 @@ -296,6 +297,7 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe seenJobs++; } this.dataView.refresh(); + this.filterValueMap[args.column.name].push(this.dataView.getFilteredItems()); this._table.grid.resetActiveCell(); } if (this.filterStack.length === 0) { @@ -310,11 +312,12 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe // current filter if (filterValues.find(x => x === item[args.column.field])) { // check all previous filters - if (this.isItemFiltered(item)) { + 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 @@ -326,7 +329,11 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe } } this.dataView.refresh(); - this.filterValueMap[args.column.name] = { filterValues: filterValues, filteredItems: this.dataView.getFilteredItems() }; + 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._table.grid.resetActiveCell(); } @@ -382,7 +389,7 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe // cache the dataview for future use this._jobCacheObject.dataView = this.dataView; - this.filterValueMap['start'] = { filterValues: [], filteredItems: this.dataView.getItems() }; + this.filterValueMap['start'] = [[], this.dataView.getItems()]; this.loadJobHistories().catch(onUnexpectedError); } @@ -552,13 +559,12 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe return [failing, nonFailing]; } - /** - * Returns true if the item matches all filters currently applied - */ - private isItemFiltered(item: IItem): boolean { + private checkPreviousFilters(item): boolean { for (let column in this.filterValueMap) { - if (column !== 'start' && this.filterValueMap[column]) { - if (!this.filterValueMap[column].filterValues.includes(item[JobManagementUtilities.convertColNameToField(column)])) { + if (column !== 'start' && this.filterValueMap[column][0].length > 0) { + let temp = this.filterValueMap[column][0] as unknown; + let arr = temp as []; + if (!arr.find(x => x === item[JobManagementUtilities.convertColNameToField(column)])) { return false; } } diff --git a/src/sql/workbench/contrib/jobManagement/browser/notebooksView.component.ts b/src/sql/workbench/contrib/jobManagement/browser/notebooksView.component.ts index e4dad64814..21f48a7043 100644 --- a/src/sql/workbench/contrib/jobManagement/browser/notebooksView.component.ts +++ b/src/sql/workbench/contrib/jobManagement/browser/notebooksView.component.ts @@ -78,12 +78,12 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit, private _notebookCacheObject: NotebookCacheObject; private rowDetail: RowDetailView; - private filterPlugin: HeaderFilter; - private dataView: Slick.Data.DataView; + private filterPlugin: any; + private dataView: any; public _isCloud: boolean; - private filterStylingMap: { [columnName: string]: IItem[]; } = {}; + private filterStylingMap: { [columnName: string]: [any]; } = {}; private filterStack = ['start']; - private filterValueMap: { [columnName: string]: { filterValues: string[], filteredItems: IItem[] } } = {}; + private filterValueMap: { [columnName: string]: string[]; } = {}; private sortingStylingMap: { [columnName: string]: any; } = {}; public notebooks: azdata.AgentNotebookInfo[]; @@ -156,7 +156,7 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit, column.rerenderOnResize = true; return column; }); - let options = >{ + let options = >{ syncColumnCellResize: true, enableColumnReorder: false, rowHeight: ROW_HEIGHT, @@ -180,7 +180,7 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit, }); this.rowDetail = rowDetail; columns.unshift(this.rowDetail.getColumnDefinition()); - let filterPlugin = new HeaderFilter(); + let filterPlugin = new HeaderFilter<{ inlineFilters: false }>(); this._register(attachButtonStyler(filterPlugin, this._themeService)); this.filterPlugin = filterPlugin; jQuery(this._gridEl.nativeElement).empty(); @@ -260,7 +260,6 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit, this._table.grid.resetActiveCell(); let filterValues = args.column.filterValues; if (filterValues) { - let currentFilteredItems = this.dataView.getFilteredItems(); if (filterValues.length === 0) { // if an associated styling exists with the current filters if (this.filterStylingMap[args.column.name]) { @@ -277,8 +276,9 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit, delete this.filterValueMap[args.column.name]; } // apply the previous filter styling - let previousFilteredItems = this.filterValueMap[this.filterStack[this.filterStack.length - 1]].filteredItems; - if (previousFilteredItems === currentFilteredItems) { + 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]); @@ -286,7 +286,7 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit, } else { // style it all over again let seenJobs = 0; - for (let i = 0; i < currentFilteredItems.length; i++) { + for (let i = 0; i < currentItems.length; i++) { this._table.grid.removeCellCssStyles('error-row' + i.toString()); this._table.grid.removeCellCssStyles('notebook-error-row' + i.toString()); let item = this.dataView.getFilteredItems()[i]; @@ -294,6 +294,7 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit, 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 @@ -303,6 +304,7 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit, seenJobs++; } this.dataView.refresh(); + this.filterValueMap[args.column.name].push(this.dataView.getFilteredItems()); this._table.grid.resetActiveCell(); } if (this.filterStack.length === 0) { @@ -318,11 +320,12 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit, // current filter if (!!filterValues.find(x => x === item[args.column.field])) { // check all previous filters - if (this.isItemFiltered(item)) { + if (this.checkPreviousFilters(item)) { if (item.lastRunOutcome === 'Failed') { this.addToStyleHash(seenNotebooks, 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 @@ -334,7 +337,11 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit, } } this.dataView.refresh(); - this.filterValueMap[args.column.name] = { filterValues: filterValues, filteredItems: this.dataView.getFilteredItems() }; + 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._table.grid.resetActiveCell(); } @@ -407,7 +414,7 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit, // cache the dataview for future use this._notebookCacheObject.dataView = this.dataView; - this.filterValueMap['start'] = { filterValues: [], filteredItems: this.dataView.getItems() }; + this.filterValueMap['start'] = [[], this.dataView.getItems()]; this.loadJobHistories().catch(onUnexpectedError); } @@ -601,13 +608,12 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit, return [failing, nonFailing]; } - /** - * Returns true if the item matches all filters currently applied - */ - private isItemFiltered(item: IItem): boolean { + private checkPreviousFilters(item): boolean { for (let column in this.filterValueMap) { - if (column !== 'start' && this.filterValueMap[column]) { - if (!this.filterValueMap[column].filterValues.includes(item[JobManagementUtilities.convertColNameToField(column)])) { + if (column !== 'start' && this.filterValueMap[column][0].length > 0) { + let temp = this.filterValueMap[column][0] as unknown; + let arr = temp as []; + if (!arr.find(x => x === item[JobManagementUtilities.convertColNameToField(column)])) { return false; } } diff --git a/src/sql/workbench/services/jobManagement/browser/jobManagementUtilities.ts b/src/sql/workbench/services/jobManagement/browser/jobManagementUtilities.ts index 8af474f9f2..1240b9eb89 100644 --- a/src/sql/workbench/services/jobManagement/browser/jobManagementUtilities.ts +++ b/src/sql/workbench/services/jobManagement/browser/jobManagementUtilities.ts @@ -40,16 +40,28 @@ export class JobManagementUtilities { return bool ? nls.localize('agentUtilities.yes', "Yes") : nls.localize('agentUtilities.no', "No"); } - public static convertToNextRun(date: string) { - return date.includes('1/1/0001') ? nls.localize('agentUtilities.notScheduled', "Not Scheduled") : date; + public static convertToNextRun(date: string): string { + if (date.includes('1/1/0001')) { + return nls.localize('agentUtilities.notScheduled', "Not Scheduled"); + } else { + return date; + } } - public static convertToLastRun(date: string) { - return date.includes('1/1/0001') ? nls.localize('agentUtilities.neverRun', "Never Run") : date; + public static convertToLastRun(date: string): string { + if (date.includes('1/1/0001')) { + return nls.localize('agentUtilities.neverRun', "Never Run"); + } else { + return date; + } } public static setRunnable(icon: HTMLElement, index: number) { - icon.classList.remove('non-runnable'); + let temp = icon.className as unknown; + let classNameArr = temp as []; + if (classNameArr.find(x => x === 'non-runnable')) { + icon.className = icon.className.slice(0, index); + } } public static getActionIconClassName(startIcon: HTMLElement, stopIcon: HTMLElement, executionStatus: number) { diff --git a/src/typings/slickgrid.d.ts b/src/typings/slickgrid.d.ts index 87f1a0aac9..69f5111da3 100644 --- a/src/typings/slickgrid.d.ts +++ b/src/typings/slickgrid.d.ts @@ -1584,7 +1584,6 @@ declare namespace Slick { public setPagingOptions(args: PagingOptions): void; public getPagingInfo(): PagingOptions; public getItems(): T[]; - public getFilteredItems(): T[]; // manually adding this type - it's present in the definition but not the typings file from DefinitelyTyped public setItems(data: T[], objectIdProperty?: string): void; public setFilter(filterFn: (item: T, args: any) => boolean): void; // todo: typeof(args) public sort(comparer: Function, ascending: boolean): void; // todo: typeof(comparer), should be the same callback as Array.sort