Skip to content

Commit

Permalink
[ACA-3692] - Add completed date/due date/started date filter (#6145)
Browse files Browse the repository at this point in the history
* add completedDate filter

* [ACA-3692] - Add completed date filter

* fix lint

* fix description

* fix lint

* preserve filters

* fix startDate/dueDate fitlers and add unit test

* revert app.config.json changes

* add support for completed date field in datatable

* fix unit tests

* fix date range unit test

Co-authored-by: Silviu Popa <p3701014@L3700101120.ness.com>
  • Loading branch information
SilviuCPopa and Silviu Popa committed Sep 24, 2020
1 parent b67b3b8 commit b5ae4eb
Show file tree
Hide file tree
Showing 18 changed files with 459 additions and 102 deletions.
Expand Up @@ -2,9 +2,10 @@
<mat-form-field [attr.data-automation-id]="processFilterProperty.key">
<mat-select
placeholder="{{ processFilterProperty.label | translate }}"
[value]="type"
(selectionChange)="onSelectionChange($event)"
[attr.data-automation-id]="'adf-cloud-edit-process-property-' + processFilterProperty.key">
<mat-option *ngFor="let propertyOption of filteredProperties" [value]="propertyOption.value" [attr.data-automation-id]="'adf-cloud-edit-process-property-options-' + processFilterProperty.value">
<mat-option *ngFor="let propertyOption of filteredProperties" [value]="propertyOption.value" [attr.data-automation-id]="'adf-cloud-edit-process-property-options-' + propertyOption.value.toString()">
{{ propertyOption.label | translate }}
</mat-option>
</mat-select>
Expand All @@ -19,8 +20,5 @@
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-date-range-picker #picker (closed)="onDateRangeClosed()"></mat-date-range-picker>

<mat-error *ngIf="dateRangeForm.controls.from.hasError('matStartDateInvalid')">{{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.ERROR.INDALID_START_DATE' | translate }}</mat-error>
<mat-error *ngIf="dateRangeForm.controls.to.hasError('matEndDateInvalid')">{{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.ERROR.INDALID_END_DATE' | translate }}</mat-error>
</mat-form-field>
</ng-container>
Expand Up @@ -59,6 +59,7 @@ describe('DateRangeFilterComponent', () => {

it('should get on option change', async () => {
spyOn(service, 'getDateRange');
spyOn(component.dateTypeChange, 'emit');
const stateElement = fixture.debugElement.nativeElement.querySelector('[data-automation-id="adf-cloud-edit-process-property-createdDate"] .mat-select-trigger');
stateElement.click();
fixture.detectChanges();
Expand All @@ -67,32 +68,27 @@ describe('DateRangeFilterComponent', () => {
options[2].nativeElement.click();
fixture.detectChanges();
await fixture.whenStable();
expect(service.getDateRange).toHaveBeenCalled();
expect(service.getDateRange).not.toHaveBeenCalled();
expect(component.dateTypeChange.emit).toHaveBeenCalled();
});

it('should reset date range when no_date type is selected', () => {
spyOn(component.dateChanged, 'emit');
const value = <MatSelectChange> { value: DateCloudFilterType.NO_DATE };
component.onSelectionChange(value);
const expectedDate = {
startDate: null,
endDate: null
};
expect(component.dateChanged.emit).toHaveBeenCalledWith(expectedDate);
expect(service.getDateRange(DateCloudFilterType.NO_DATE)).toEqual(expectedDate);
});

it('should emit date range when any type is selected', () => {
spyOn(component.dateChanged, 'emit');
const value = <MatSelectChange> { value: DateCloudFilterType.TOMORROW };
component.onSelectionChange(value);
it('should return correct date when any type is selected', () => {
const expectedDate = {
startDate: moment().endOf('day').toDate(),
endDate: moment().add(1, 'days').startOf('day').toDate()
};
expect(component.dateChanged.emit).toHaveBeenCalledWith(expectedDate);
expect(service.getDateRange(DateCloudFilterType.TOMORROW)).toEqual(expectedDate);
});

it('should not emit any date change events when range type is selected', () => {
it('should not emit any date change events when any type is selected', () => {
spyOn(component.dateChanged, 'emit');
const value = <MatSelectChange> { value: DateCloudFilterType.RANGE };
component.onSelectionChange(value);
Expand All @@ -105,10 +101,6 @@ describe('DateRangeFilterComponent', () => {
expect(component.dateChanged.emit).toHaveBeenCalled();
});

it('should throw error no supported type is selected', () => {
expect(function () { service.getDateRange(null); } ).toThrow(new Error('ADF_CLOUD_EDIT_PROCESS_FILTER.ERROR.INVALID_DATE_FILTER'));
});

it('should show date-range picker when type is range', async () => {
const value = <MatSelectChange> { value: DateCloudFilterType.RANGE };
component.onSelectionChange(value);
Expand All @@ -117,4 +109,29 @@ describe('DateRangeFilterComponent', () => {
const rangePickerElement = fixture.debugElement.nativeElement.querySelector('.adf-cloud-date-range-picker');
expect(rangePickerElement).not.toBeNull();
});

it('should preselect values if filterProperty has attribute', () => {
const mockFilterProperty = {
key: 'createdDate',
label: 'mock-filter',
value: {
createdDateType: DateCloudFilterType.RANGE,
_startFrom: new Date().toISOString(),
_startTo: new Date().toISOString()
},
type: 'dateRange',
options: null,
attributes: {
dateType: 'createdDateType',
from: '_startFrom',
to: '_startTo'
}
};
component.processFilterProperty = mockFilterProperty;
component.ngOnInit();
fixture.detectChanges();

expect(component.dateRangeForm.get('from').value).toEqual(moment(mockFilterProperty.value._startFrom));
expect(component.dateRangeForm.get('to').value).toEqual(moment(mockFilterProperty.value._startTo));
});
});
Expand Up @@ -19,18 +19,8 @@ import { Component, Input, EventEmitter, Output } from '@angular/core';
import { MatSelectChange } from '@angular/material/select';
import { ProcessFilterProperties, ProcessFilterOptions } from '../../process/process-filters/models/process-filter-cloud.model';
import { FormGroup, FormControl } from '@angular/forms';
import { DateRangeFilterService } from './date-range-filter.service';
import { DateRangeFilter, DateCloudFilterType } from '../../models/date-cloud-filter.model';

const DEFAULT_DATE_RANGE_OPTIONS = [
DateCloudFilterType.NO_DATE,
DateCloudFilterType.TODAY,
DateCloudFilterType.WEEK,
DateCloudFilterType.MONTH,
DateCloudFilterType.QUARTER,
DateCloudFilterType.YEAR,
DateCloudFilterType.RANGE
];
import moment from 'moment-es6';

@Component({
selector: 'adf-cloud-date-range-filter',
Expand All @@ -43,31 +33,33 @@ const DEFAULT_DATE_RANGE_OPTIONS = [
processFilterProperty: ProcessFilterProperties;

@Input()
options: DateCloudFilterType[] = DEFAULT_DATE_RANGE_OPTIONS;
options: DateCloudFilterType[];

@Output()
dateChanged = new EventEmitter<DateRangeFilter>();

@Output()
dateTypeChange = new EventEmitter<DateCloudFilterType>();

type: DateCloudFilterType;
filteredProperties: ProcessFilterOptions[] = [];
dateRangeForm = new FormGroup({
from: new FormControl(),
to: new FormControl()
});

constructor(private dateRangeFilterService: DateRangeFilterService) {}

ngOnInit() {
this.options = this.options ? this.options : this.createDefaultRangeOptions();
const defaultProperties = this.createDefaultDateOptions();
this.filteredProperties = defaultProperties.filter((filterProperty: ProcessFilterOptions) => this.isValidProperty(this.options, filterProperty));
if (this.hasPreselectedValues()) {
this.setPreselectedValues();
}
}

onSelectionChange(option: MatSelectChange) {
this.type = option.value;
const dateRange = this.dateRangeFilterService.getDateRange(this.type);
if (!this.isDateRangeType()) {
this.dateChanged.emit(dateRange);
}
this.dateTypeChange.emit(this.type);
}

isDateRangeType(): boolean {
Expand All @@ -82,10 +74,44 @@ const DEFAULT_DATE_RANGE_OPTIONS = [
this.dateChanged.emit(dateRange);
}

private hasPreselectedValues() {
return !!this.processFilterProperty?.attributes && !!this.processFilterProperty?.value;
}

private setPreselectedValues() {
const from = this.getFilterAttribute('from');
const to = this.getFilterAttribute('to');
const type = this.getFilterAttribute('dateType');

this.dateRangeForm.get('from').setValue(moment(this.getFilterValue(from)));
this.dateRangeForm.get('to').setValue(moment(this.getFilterValue(to)));
this.type = this.getFilterValue(type);
}

private getFilterAttribute(key: string): string {
return this.processFilterProperty.attributes[key];
}

private getFilterValue(attribute: string) {
return this.processFilterProperty.value[attribute];
}

private isValidProperty(filterProperties: string[], filterProperty: any): boolean {
return filterProperties ? filterProperties.indexOf(filterProperty.value) >= 0 : true;
}

private createDefaultRangeOptions(): DateCloudFilterType[] {
return [
DateCloudFilterType.NO_DATE,
DateCloudFilterType.TODAY,
DateCloudFilterType.WEEK,
DateCloudFilterType.MONTH,
DateCloudFilterType.QUARTER,
DateCloudFilterType.YEAR,
DateCloudFilterType.RANGE
];
}

private createDefaultDateOptions(): ProcessFilterOptions[] {
return [
{
Expand Down
Expand Up @@ -86,8 +86,4 @@ describe('Date Range Filter service', () => {
};
expect(service.getDateRange(DateCloudFilterType.NEXT_7_DAYS)).toEqual(expectedDate);
});

it('should throw error no supported type is selected', () => {
expect(function () { service.getDateRange(null); } ).toThrow(new Error('ADF_CLOUD_EDIT_PROCESS_FILTER.ERROR.INVALID_DATE_FILTER'));
});
});
Expand Up @@ -35,12 +35,14 @@ export class DateRangeFilterService {
case DateCloudFilterType.MONTH: return this.getCurrentMonthDateRange();
case DateCloudFilterType.QUARTER: return this.getQuarterDateRange();
case DateCloudFilterType.YEAR: return this.getCurrentYearDateRange();
case DateCloudFilterType.RANGE: return this.resetDateRange();
case DateCloudFilterType.NO_DATE: return this.resetDateRange();
default: throw new Error('ADF_CLOUD_EDIT_PROCESS_FILTER.ERROR.INVALID_DATE_FILTER');
default: return this.resetDateRange();
}
}

isDateRangeType(type: DateCloudFilterType) {
return type === DateCloudFilterType.RANGE;
}

private resetDateRange(): DateRangeFilter {
return {
startDate: null,
Expand Down
4 changes: 3 additions & 1 deletion lib/process-services-cloud/src/lib/i18n/en.json
Expand Up @@ -10,6 +10,7 @@
"CREATED": "Created",
"STATUS": "Status",
"START_DATE": "Start Date",
"COMPLETED_DATE": "Completed Date",
"ID": "Id",
"INITIATOR": "Initiator",
"APP_NAME": "Application Name",
Expand Down Expand Up @@ -167,7 +168,8 @@
"LAST_MODIFIED_TO": "LastModifiedTo",
"PROCESS_NAME": "Process Name",
"APP_VERSION": "AppReleaseVersion",
"CREATED_DATE": "Created Date",
"STARTED_DATE": "Started Date",
"COMPLETED_DATE": "Completed Date",
"DATE_RANGE": {
"NO_DATE": "No Date",
"TODAY": "Today",
Expand Down
Expand Up @@ -66,8 +66,11 @@
</div>
</div>
</mat-form-field>

<adf-cloud-date-range-filter *ngIf="isDateRangeType(processFilterProperty)"
[processFilterProperty]="processFilterProperty"
[options]="processFilterProperty.dateFilterOptions"
(dateTypeChange)="onDateTypeChange($event, processFilterProperty)"
(dateChanged)="onDateRangeFilterChanged($event, processFilterProperty)"></adf-cloud-date-range-filter>
</ng-container>
</div>
Expand Down
Expand Up @@ -37,6 +37,7 @@ import { PROCESS_FILTERS_SERVICE_TOKEN } from '../../../services/cloud-token.ser
import { LocalPreferenceCloudService } from '../../../services/local-preference-cloud.service';
import { TranslateModule } from '@ngx-translate/core';
import { ProcessCloudService } from '../../services/process-cloud.service';
import { DateCloudFilterType } from '../../../models/date-cloud-filter.model';

describe('EditProcessFilterCloudComponent', () => {
let component: EditProcessFilterCloudComponent;
Expand Down Expand Up @@ -443,6 +444,21 @@ describe('EditProcessFilterCloudComponent', () => {
});
}));

it('should get form attributes', async() => {
fixture.detectChanges();
component.filterProperties = ['appName', 'completedDateRange'];
fixture.detectChanges();
const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(component.editProcessFilterForm.get('_completedFrom')).toBeDefined();
expect(component.editProcessFilterForm.get('_completedTo')).toBeDefined();
expect(component.editProcessFilterForm.get('completedDateType')).toBeDefined();
});
});

it('should able to build a editProcessFilter form with default properties if input is empty', async(() => {
fixture.detectChanges();
component.filterProperties = [];
Expand Down Expand Up @@ -767,6 +783,64 @@ describe('EditProcessFilterCloudComponent', () => {
component.onFilterChange();
});

it('should set the correct started date range when date range option is changed', (done) => {
component.appName = 'fake';
component.filterProperties = ['appName', 'processInstanceId', 'priority', 'completedDateRange'];
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange });
fixture.detectChanges();

const startedDateTypeControl: AbstractControl = component.editProcessFilterForm.get('completedDateType');
startedDateTypeControl.setValue(DateCloudFilterType.TODAY);
const dateFilter = {
startFrom: moment().startOf('day').toDate(),
startTo: moment().endOf('day').toDate()
};

component.filterChange.subscribe(() => {
expect(component.changedProcessFilter.completedFrom).toEqual(dateFilter.startFrom.toISOString());
expect(component.changedProcessFilter.completedTo).toEqual(dateFilter.startTo.toISOString());
done();
});
component.onFilterChange();
});

it('should update form on date range value is updated', (done) => {
component.appName = 'fake';
component.filterProperties = ['appName', 'processInstanceId', 'priority', 'completedDateRange'];
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange });
fixture.detectChanges();

const dateFilter = {
startDate: moment().startOf('day').toDate(),
endDate: moment().endOf('day').toDate()
};

const startedDateTypeControl: AbstractControl = component.editProcessFilterForm.get('completedDateType');
startedDateTypeControl.setValue(DateCloudFilterType.RANGE);

component.onDateRangeFilterChanged(dateFilter, {
key: 'completedDateRange',
label: '',
type: 'date-range',
value: '',
attributes: {
dateType: 'completedDateType',
from: '_completedFrom',
to: '_completedTo'
}
});

fixture.detectChanges();
component.filterChange.subscribe(() => {
expect(component.changedProcessFilter.completedFrom).toEqual(dateFilter.startDate.toISOString());
expect(component.changedProcessFilter.completedTo).toEqual(dateFilter.endDate.toISOString());
done();
});
component.onFilterChange();
});

it('should call restore default filters service on deletion of last filter', (done) => {
component.toggleFilterActions = true;
const deleteFilterSpy = spyOn(service, 'deleteFilter').and.returnValue(of([]));
Expand Down

0 comments on commit b5ae4eb

Please sign in to comment.