Skip to content

Commit

Permalink
feat(#3059): Replace time selection bar with menu
Browse files Browse the repository at this point in the history
  • Loading branch information
dominikriemer committed Jul 25, 2024
1 parent 3b261b0 commit 7075d02
Show file tree
Hide file tree
Showing 34 changed files with 984 additions and 425 deletions.
40 changes: 37 additions & 3 deletions ui/cypress/support/utils/datalake/DataLakeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { FileManagementUtils } from '../FileManagementUtils';
import { ConnectUtils } from '../connect/ConnectUtils';
import { ConnectBtns } from '../connect/ConnectBtns';
import { AdapterBuilder } from '../../builder/AdapterBuilder';
import { differenceInMonths } from 'date-fns';

export class DataLakeUtils {
public static goToDatalake() {
Expand Down Expand Up @@ -349,16 +350,49 @@ export class DataLakeUtils {
}

public static selectTimeRange(from: Date, to: Date) {
DataLakeUtils.setTimeInput('time-range-from', from);
DataLakeUtils.setTimeInput('time-range-to', to);
DataLakeUtils.openTimeSelectorMenu();
const monthsBack = Math.abs(differenceInMonths(from, new Date()));
DataLakeUtils.navigateCalendar('previous', monthsBack);
DataLakeUtils.selectDay(from.getDay());

const monthsForward = Math.abs(differenceInMonths(from, to));
DataLakeUtils.navigateCalendar('next', monthsForward);

DataLakeUtils.selectDay(to.getDay());

DataLakeUtils.setTimeInput('time-selector-start-time', from);
DataLakeUtils.setTimeInput('time-selector-end-time', to);
DataLakeUtils.applyCustomTimeSelection();
}

public static navigateCalendar(direction: string, numberOfMonths: number) {
for (let i = 0; i < numberOfMonths; i++) {
cy.get(`button.mat-calendar-${direction}-button`).click();
}
}

public static selectDay(day: number) {
cy.get(
`button:has(span.mat-calendar-body-cell-content:contains("${day}"))`,
)
.first()
.click();
}

public static openTimeSelectorMenu() {
cy.dataCy('time-selector-menu').click();
}

public static applyCustomTimeSelection() {
cy.dataCy('apply-custom-time').click();
}

public static setTimeInput(field: string, date: Date) {
cy.dataCy(field).type(DataLakeUtils.makeTimeString(date));
}

public static makeTimeString(date: Date) {
return date.toISOString().slice(0, 16);
return date.toTimeString().slice(0, 5);
}

public static getFutureDate() {
Expand Down
160 changes: 88 additions & 72 deletions ui/cypress/tests/datalake/timeRangeSelectors.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,29 @@
*/

import { DataLakeUtils } from '../../support/utils/datalake/DataLakeUtils';
import {
subDays,
subHours,
subMinutes,
subMonths,
subWeeks,
subYears,
} from 'date-fns';

describe('Test Time Range Selectors in Data Explorer', () => {
const periods = [
{ selector: '15_min', offset: 15 },
{ selector: '1_hour', offset: 60 },
{ selector: '1_day', offset: 1440 },
{ selector: '1_week', offset: 10080 },
{ selector: '1_month', offset: 43200 },
{ selector: '1_year', offset: 525600 },
{ selector: 1, start: (now: Date) => subMinutes(now, 15) },
{ selector: 2, start: (now: Date) => subHours(now, 1) },
{ selector: 4, start: (now: Date) => subDays(now, 1) },
{ selector: 6, start: (now: Date) => subWeeks(now, 1) },
{ selector: 8, start: (now: Date) => subMonths(now, 1) },
{ selector: 10, start: (now: Date) => subYears(now, 1) },
];

const dateAttribute = 'ng-reflect-date';
const timeRangeFrom = 'time-range-from';
const timeRangeTo = 'time-range-to';
const timeRangeFrom = 'time-selector-start-time';
const timeRangeTo = 'time-selector-end-time';
const dateRangeFrom = 'time-selector-start-date';
const dateRangeTo = 'time-selector-end-date';

before('Setup Tests', () => {
cy.initStreamPipesTest();
Expand All @@ -42,74 +51,59 @@ describe('Test Time Range Selectors in Data Explorer', () => {
it('Perform Test', () => {
periods.forEach(period => {
cy.log('Testing period: ' + period.selector);
DataLakeUtils.openTimeSelectorMenu();
// Choosing time period and saving initial start and end dates
cy.dataCy(period.selector).click();
cy.dataCy(timeRangeTo)
.invoke('attr', dateAttribute)
.then(initialEndDateString => {
cy.dataCy(timeRangeFrom)
.invoke('attr', dateAttribute)
.then(initialStartDateString => {
const initialStartDate = parseDate(
initialStartDateString,
);
const initialEndDate =
parseDate(initialEndDateString);

cy.wrap(initialStartDate).should(
'deep.eq',
getExpectedStartDate(
initialEndDate,
period.offset,
),
);
// Updating time range to previous one and checking start and end dates
cy.dataCy('decrease-time-button').click({
force: true,
});
cy.dataCy(timeRangeTo)
.invoke('attr', dateAttribute)
.then(updatedEndDateString => {
cy.dataCy(timeRangeFrom)
.invoke('attr', dateAttribute)
.then(updatedStartDateString => {
const updatedStartDate = parseDate(
updatedStartDateString,
);
const updatedEndDate =
parseDate(updatedEndDateString);
cy.dataCy(`time-selector-quick-${period.selector}`).click();
const expectedEndDate = new Date();
DataLakeUtils.openTimeSelectorMenu();
// check if dates can differ from the selected dates
const expectedStartDate = getExpectedStartDate(
expectedEndDate,
period.start,
);
cy.dataCy(dateRangeFrom).should(
'have.text',
getLocalizedDateString(expectedStartDate),
);
cy.dataCy(dateRangeTo).should(
'have.text',
getLocalizedDateString(expectedEndDate),
);

cy.wrap(updatedStartDate).should(
'deep.eq',
getExpectedStartDate(
updatedEndDate,
period.offset,
),
);
cy.wrap(updatedEndDate).should(
'deep.eq',
initialStartDate,
);
});
});
// Updating time range to the next one and comparing start and end dates with initial values
cy.dataCy('increase-time-button').click({
force: true,
});
cy.dataCy(timeRangeFrom)
.invoke('attr', dateAttribute)
.should('eq', initialStartDateString);
cy.dataCy(timeRangeTo)
.invoke('attr', dateAttribute)
.should('eq', initialEndDateString);
});
cy.dataCy(timeRangeFrom)
.invoke('val')
.then(actualTime => {
const expectedDate =
getLocalizedTimeString(expectedStartDate);
expect(
isTimeWithinTolerance(
actualTime as string,
expectedDate,
3,
),
).to.be.true;
});
cy.dataCy(timeRangeTo)
.invoke('val')
.then(actualTime => {
const expectedDate =
getLocalizedTimeString(expectedEndDate);
expect(
isTimeWithinTolerance(
actualTime as string,
expectedDate,
3,
),
).to.be.true;
});

DataLakeUtils.applyCustomTimeSelection();
});
});
});

function getExpectedStartDate(endDate: Date, offset: number): Date {
const startDate = new Date(endDate.getTime() - offset * 60000);
function getExpectedStartDate(endDate: Date, startFn: (Date) => Date): Date {
const startDate = startFn(endDate);
startDate.setMinutes(
startDate.getMinutes() + getTimezoneDifference(endDate, startDate),
);
Expand All @@ -120,6 +114,28 @@ function getTimezoneDifference(endDate: Date, startDate: Date): number {
return endDate.getTimezoneOffset() - startDate.getTimezoneOffset();
}

function parseDate(dateString: string): Date {
return new Date(Date.parse(dateString));
function getLocalizedDateString(date: Date) {
return date.toLocaleDateString();
}

function getLocalizedTimeString(date: Date) {
return date.toLocaleTimeString();
}

function parseTimeStringToSeconds(timeString: string) {
const [hours, minutes, seconds] = timeString.split(':').map(Number);
return hours * 3600 + minutes * 60 + seconds || 0;
}

function isTimeWithinTolerance(
actualTimeString: string,
expectedTimeString: string,
toleranceInSeconds: number,
) {
const actualTimeInSeconds = parseTimeStringToSeconds(actualTimeString);
const expectedTimeInSeconds = parseTimeStringToSeconds(expectedTimeString);
return (
Math.abs(actualTimeInSeconds - expectedTimeInSeconds) <=
toleranceInSeconds
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ export class DataViewDataExplorerService {
return this.sharedDatalakeRestService.getDashboards(this.dashboardUrl);
}

getDashboard(dashboardId: string): Observable<Dashboard> {
return this.http.get(`${this.dashboardUrl}/${dashboardId}`);
}

updateDashboard(dashboard: Dashboard): Observable<Dashboard> {
return this.sharedDatalakeRestService.updateDashboard(
this.dashboardUrl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,37 @@ export interface TimeSettings {
startTime: number;
endTime: number;
dynamicSelection: 15 | 60 | 1440 | 10080 | 43800 | 525600 | -1;
timeSelectionId?: TimeSelectionId;
}

export interface TimeString {
startDate: string;
startTime: string;
endDate: string;
endTime: string;
}

export enum TimeSelectionId {
CUSTOM,
LAST_15_MINUTES,
LAST_HOUR,
CURRENT_HOUR,
LAST_DAY,
CURRENT_DAY,
LAST_WEEK,
CURRENT_WEEK,
LAST_MONTH,
CURRENT_MONTH,
LAST_YEAR,
CURRENT_YEAR,
}

export interface QuickTimeSelection {
label: string;
timeSelectionId: TimeSelectionId;
startTime: (now: Date) => Date;
endTime: (now: Date) => Date;
addDividerAfter?: boolean;
}

export class DateRange {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@
fxLayout="row"
>
<sp-time-range-selector
*ngIf="editMode || timeRangeVisible"
*ngIf="(editMode || timeRangeVisible) && globalTimeEnabled"
(dateRangeEmitter)="updateDateRangeEmitter.emit($event)"
[dateRange]="timeSettings"
[timeSettings]="timeSettings"
>
</sp-time-range-selector>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ export class DataExplorerDashboardToolbarComponent {
@Input()
timeSettings: TimeSettings;

@Input()
globalTimeEnabled = true;

@Output()
viewModeChange: EventEmitter<string> = new EventEmitter<string>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@
<h5>{{ dataView.baseAppearanceConfig.widgetTitle }}</h5>
<div fxLayout="row" fxLayoutGap="15px" class="data-view-preview-info">
<span fxLayoutAlign="start center"
><i class="material-icons color-primary">insert_chart</i></span
><mat-icon color="primary">insert_chart</mat-icon></span
>
<span fxFlex fxLayoutAlign="start center">{{
widgetTypeLabel
}}</span>
</div>
<div fxLayout="row" fxLayoutGap="15px" class="data-view-preview-info">
<span fxLayoutAlign="start center"
><i class="material-icons">folder</i></span
><mat-icon color="primary">folder</mat-icon></span
>
<span fxFlex fxLayoutAlign="start center">{{
dataView.dataConfig.sourceConfigs[0].measureName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
>
<div nav fxFlex="100" class="ml-10">
<sp-data-explorer-dashboard-toolbar
[globalTimeEnabled]="
dashboard.dashboardGeneralSettings.globalTimeEnabled
"
[editMode]="editMode"
[(viewMode)]="viewMode"
[hasDataExplorerDeletePrivileges]="hasDataExplorerDeletePrivileges"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,8 @@ export class DataExplorerDashboardPanelComponent implements OnInit, OnDestroy {
}

getDashboard(dashboardId: string, startTime: number, endTime: number) {
this.dataViewService.getDataViews().subscribe(data => {
this.dashboard = data.filter(
dashboard => dashboard.elementId === dashboardId,
)[0];
this.dataViewService.getDashboard(dashboardId).subscribe(dashboard => {
this.dashboard = dashboard;
this.breadcrumbService.updateBreadcrumb(
this.breadcrumbService.makeRoute(
[SpDataExplorerRoutes.BASE],
Expand All @@ -192,6 +190,13 @@ export class DataExplorerDashboardPanelComponent implements OnInit, OnDestroy {
this.viewMode =
this.dashboard.dashboardGeneralSettings.defaultViewMode ||
'grid';
if (
this.dashboard.dashboardGeneralSettings.globalTimeEnabled ===
undefined
) {
this.dashboard.dashboardGeneralSettings.globalTimeEnabled =
true;
}
this.timeSettings =
startTime && endTime
? this.overrideTime(+startTime, +endTime)
Expand Down
Loading

0 comments on commit 7075d02

Please sign in to comment.