Skip to content

Commit

Permalink
frontend: Implement executions list enhacements
Browse files Browse the repository at this point in the history
Executions list highlighting is in sync with duration
chart focus on event (execution).
Change label text on filter by period.
Added caret next to text from time period filter.
Implement synchronization between time period filter,
duration zoom, grid filters and grid sort criteria.
Whenever change occurs it is reflected on the other
components/charts and everything is sharable through URL.

Signed-off-by: Goran Kokinovski <[email protected]>
  • Loading branch information
gorankokin committed May 26, 2023
1 parent 460a133 commit cc3d46e
Show file tree
Hide file tree
Showing 51 changed files with 2,323 additions and 490 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ describe(
pathSegment: `/manage/data-jobs/${longLivedFailingJobFixture.team}/${longLivedFailingJobFixture.job_name}/executions`,
queryParams: {
sort: '{"startTime":-1}',
filter: `{"startTimeFormatted":"${filterValue}"}`
filter: `{"startTime":"${filterValue}"}`
}
});
});
Expand Down Expand Up @@ -803,7 +803,7 @@ describe(
pathSegment: `/manage/data-jobs/${longLivedFailingJobFixture.team}/${longLivedFailingJobFixture.job_name}/executions`,
queryParams: {
sort: '{"startTime":-1}',
filter: `{"endTimeFormatted":"${filterValue}"}`
filter: `{"endTime":"${filterValue}"}`
}
});
});
Expand Down Expand Up @@ -1799,7 +1799,8 @@ describe(
});
});

// !!! important tests order is very important, because generated url from 1st test is used in the second
// !!! important tests order is very important, because generated url from 1st test is used in the second test
// the second test cannot be run without previously running the first test
describe('DataGrid Filters and Sort to URL', () => {
// value is assigned at the end of the 1st test and used in the 2nd test
let navigationUrlWithFiltersAndSort = '';
Expand Down Expand Up @@ -1845,15 +1846,16 @@ describe(
}
});

// open type filter and select manual execution trigger and close
// open type filter and select manual execution then verify, then select scheduled trigger and close
dataJobExecutionsPage.openTypeFilter();
dataJobExecutionsPage.filterByType('manual');
dataJobExecutionsPage
.getDataGridExecTypeContainers('scheduled')
.should('have.length', 0);
dataJobExecutionsPage.filterByType('scheduled');
dataJobExecutionsPage.closeFilter();

// verify current URL has appended filters execution status: user_error, trigger type: manual, and sort by startTime descending
// verify current URL has appended filters execution status: user_error, trigger type: manual and scheduled, and sort by startTime descending
dataJobExecutionsPage
.getCurrentUrlNormalized({
includePathSegment: true,
Expand All @@ -1864,7 +1866,7 @@ describe(
pathSegment: `/manage/data-jobs/${longLivedFailingJobFixture.team}/${longLivedFailingJobFixture.job_name}/executions`,
queryParams: {
sort: '{"startTime":-1}',
filter: '{"status":"user_error","type":"manual"}'
filter: '{"status":"user_error","type":"manual,scheduled"}'
}
});

Expand All @@ -1890,7 +1892,7 @@ describe(
return foundCells.length;
})
.should('gt', 0);
// verify current URL has appended filters execution status: user_error, trigger type: manual, id: long_lived_job_name and sort by id ascending
// verify current URL has appended filters execution status: user_error, trigger type: manual and scheduled, id: long_lived_job_name and sort by id ascending
dataJobExecutionsPage
.getCurrentUrlNormalized({
includePathSegment: true,
Expand All @@ -1901,7 +1903,7 @@ describe(
pathSegment: `/manage/data-jobs/${longLivedFailingJobFixture.team}/${longLivedFailingJobFixture.job_name}/executions`,
queryParams: {
sort: '{"id":1}',
filter: `{"status":"user_error","type":"manual","id":"${longLivedFailingJobFixture.job_name}"}`
filter: `{"status":"user_error","type":"manual,scheduled","id":"${longLivedFailingJobFixture.job_name}"}`
}
});

Expand Down Expand Up @@ -1930,7 +1932,7 @@ describe(
})
.should('gt', 0);

// verify current URL has appended filters execution status: user_error, trigger type: manual, id: long_lived_job_name, startTimeFormatted: ${filterValue} and sort by id ascending
// verify current URL has appended filters execution status: user_error, trigger type: manual and scheduled, id: long_lived_job_name, startTime: ${filterValue} and sort by id ascending
dataJobExecutionsPage
.getCurrentUrlNormalized({
includePathSegment: true,
Expand All @@ -1941,7 +1943,7 @@ describe(
pathSegment: `/manage/data-jobs/${longLivedFailingJobFixture.team}/${longLivedFailingJobFixture.job_name}/executions`,
queryParams: {
sort: '{"id":1}',
filter: `{"status":"user_error","type":"manual","id":"${longLivedFailingJobFixture.job_name}","startTimeFormatted":"${filterValue}"}`
filter: `{"status":"user_error","type":"manual,scheduled","id":"${longLivedFailingJobFixture.job_name}","startTime":"${filterValue}"}`
}
});
});
Expand Down Expand Up @@ -1972,7 +1974,7 @@ describe(
})
.should('gt', 0);

// verify current URL has appended filters execution status: user_error, trigger type: manual, id: long_lived_job_name, startTimeFormatted: ${filterValue}, endTimeFormatted: ${filterValue} and sort by id ascending
// verify current URL has appended filters execution status: user_error, trigger type: manual and scheduled, id: long_lived_job_name, startTime: ${filterValue}, endTime: ${filterValue} and sort by id ascending
dataJobExecutionsPage
.getCurrentUrlNormalized({
includePathSegment: true,
Expand All @@ -1983,7 +1985,7 @@ describe(
pathSegment: `/manage/data-jobs/${longLivedFailingJobFixture.team}/${longLivedFailingJobFixture.job_name}/executions`,
queryParams: {
sort: '{"id":1}',
filter: `{"status":"user_error","type":"manual","id":"${longLivedFailingJobFixture.job_name}","startTimeFormatted":"${filterValue}","endTimeFormatted":"${filterValue}"}`
filter: `{"status":"user_error","type":"manual,scheduled","id":"${longLivedFailingJobFixture.job_name}","startTime":"${filterValue}","endTime":"${filterValue}"}`
}
});
});
Expand Down Expand Up @@ -2037,11 +2039,14 @@ describe(
.getDataGridExecTypeFilterCheckboxesStatuses()
.should('deep.equal', [
['manual', true],
['scheduled', false]
['scheduled', true]
]);
dataJobExecutionsPage
.getDataGridExecTypeContainers('manual')
.should('have.length.gte', 0);
dataJobExecutionsPage
.getDataGridExecTypeContainers('scheduled')
.should('have.length', 0);
.should('have.length.gte', 0);
dataJobExecutionsPage.closeFilter();

// verify sort by id ascending
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1495,7 +1495,6 @@ describe('FiltersSortManager', () => {
// Given
const filterValue1 = 'f1v,f11v';
const filterValue3 = 'f3v';
const filterValue4 = 'f4v,f44v,f444v';
const sortValue1 = 's1v';
const sortValue2 = '-1';
const sortValue3 = 's3v';
Expand Down Expand Up @@ -1744,8 +1743,6 @@ describe('FiltersSortManager', () => {
// Given
const filterValue1 = 'f1v,f11v';
const filterValue3 = 'f3v';
const filterValue4 = 'f4v,f44v,f444v';
const sortValue1 = 's1v';
const sortValue2 = '-1';
const sortValue3 = 's3v';
const sortValue4 = 's4v';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@ export class FiltersSortManager<
// debouncing for update URL, to avoid multiple updates when there are multiple serial near close update events
this._updateTimeoutRef = setTimeout(() => {
this._doUpdateBrowserUrl(strategy);

this._updateTimeoutRef = null;
}, this._debouncingTime);
}

Expand All @@ -355,6 +357,8 @@ export class FiltersSortManager<
cancelScheduledBrowserUrlUpdate(): void {
if (CollectionsUtil.isNumber(this._updateTimeoutRef)) {
clearTimeout(this._updateTimeoutRef);

this._updateTimeoutRef = null;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { Component, HostListener, Input } from '@angular/core';
import { Component, Input } from '@angular/core';

import { DataJobExecutionStatus } from '../../../../../model';

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* Copyright 2021-2023 VMware, Inc.
* SPDX-License-Identifier: Apache-2.0
*/

import { DatePipe } from '@angular/common';

import { TestBed } from '@angular/core/testing';

import { DATA_PIPELINES_DATE_TIME_FORMAT } from '../../../../../../../model';

import { GridDataJobExecution } from '../../../model';

import { ExecutionDefaultComparator } from './execution-default.comparator';

describe('ExecutionDefaultComparator', () => {
let datePipe: DatePipe;
let dataJobExecutions: GridDataJobExecution[];

beforeEach(() => {
TestBed.configureTestingModule({
providers: [DatePipe]
});

datePipe = TestBed.inject(DatePipe);

const aStartTime = new Date();
const aEndTime = new Date(aStartTime.getTime() + 100);
const bStartTime = new Date();
const bEndTime = new Date(bStartTime.getTime() + 110);

dataJobExecutions = [
{
id: 'aJob',
startTimeFormatted: datePipe.transform(aStartTime, DATA_PIPELINES_DATE_TIME_FORMAT),
startTime: aStartTime.toISOString(),
endTimeFormatted: datePipe.transform(aEndTime, DATA_PIPELINES_DATE_TIME_FORMAT),
endTime: aEndTime.toISOString(),
duration: '100',
jobVersion: 'version-10'
},
{
id: 'bJob',
startTimeFormatted: datePipe.transform(bStartTime, DATA_PIPELINES_DATE_TIME_FORMAT),
startTime: bStartTime.toISOString(),
endTimeFormatted: datePipe.transform(bEndTime, DATA_PIPELINES_DATE_TIME_FORMAT),
endTime: bEndTime.toISOString(),
duration: '110',
jobVersion: 'version-11'
}
];
});

describe('Properties::', () => {
describe('|direction|', () => {
it('should verify value', () => {
// Given
const instance = new ExecutionDefaultComparator('jobVersion', 'ASC');

// Then
expect(instance.property).toEqual('jobVersion');
expect(instance.direction).toEqual('ASC');
});
});
});

describe('Methods::', () => {
describe('|compare|', () => {
it('should verify will return -1 because of ascending sort', () => {
// Given
const instance = new ExecutionDefaultComparator('jobVersion', 'ASC');

// When
const res = instance.compare(dataJobExecutions[0], dataJobExecutions[1]);

// Then
expect(res).toEqual(-1);
});

it('should verify will return 1 because of ascending sort', () => {
// Given
const instance = new ExecutionDefaultComparator('endTime', 'ASC');

// When
const res = instance.compare(dataJobExecutions[1], dataJobExecutions[0]);

// Then
expect(res).toEqual(1);
});

it('should verify will return 1 because of descending sort', () => {
// Given
const instance = new ExecutionDefaultComparator('jobVersion', 'DESC');

// When
const res = instance.compare(dataJobExecutions[0], dataJobExecutions[1]);

// Then
expect(res).toEqual(1);
});

it('should verify will return -1 because of descending sort', () => {
// Given
const instance = new ExecutionDefaultComparator('endTime', 'DESC');

// When
const res = instance.compare(dataJobExecutions[1], dataJobExecutions[0]);

// Then
expect(res).toEqual(-1);
});

it('should verify will return 0 because of ascending sort', () => {
// Given
const instance = new ExecutionDefaultComparator('startTime', 'ASC');

// When
const res = instance.compare(dataJobExecutions[0], dataJobExecutions[1]);

// Then
expect(res).toEqual(-0);
});

it('should verify will return 0 because of descending sort', () => {
// Given
const instance = new ExecutionDefaultComparator('startTime', 'DESC');

// When
const res = instance.compare(dataJobExecutions[0], dataJobExecutions[1]);

// Then
expect(res).toEqual(0);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2021-2023 VMware, Inc.
* SPDX-License-Identifier: Apache-2.0
*/

import { get } from 'lodash';

import { Comparator } from '@versatiledatakit/shared';

import { GridDataJobExecution } from '../../../model/data-job-execution';

/**
* ** Execution default comparator.
*/
export class ExecutionDefaultComparator implements Comparator<GridDataJobExecution> {
/**
* ** Property path to value from GridDataJobExecution object.
*/
public readonly property: keyof GridDataJobExecution;

/**
* ** Sort direction.
*/
public readonly direction: 'ASC' | 'DESC';

/**
* ** Constructor.
*/
constructor(property: keyof GridDataJobExecution, direction: 'ASC' | 'DESC') {
this.property = property;
this.direction = direction;
}

/**
* @inheritDoc
*/
compare(exec1: GridDataJobExecution, exec2: GridDataJobExecution) {
const value1 = get<GridDataJobExecution, keyof GridDataJobExecution>(exec1, this.property);
const value2 = get<GridDataJobExecution, keyof GridDataJobExecution>(exec2, this.property);
const directionModifier = this.direction === 'DESC' ? 1 : -1;

return (value1 > value2 ? -1 : value2 > value1 ? 1 : 0) * directionModifier;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
* Copyright 2023 VMware, Inc.
* SPDX-License-Identifier: Apache-2.0
*/

export * from './execution-default.comparator';
Loading

0 comments on commit cc3d46e

Please sign in to comment.