[ACA-3692] - Add completed date/due date/started date filter (#6145)

* 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>
This commit is contained in:
Silviu Popa
2020-09-24 12:07:30 +03:00
committed by GitHub
parent b67b3b83b0
commit b5ae4ebff5
18 changed files with 459 additions and 102 deletions

View File

@@ -2,9 +2,10 @@
<mat-form-field [attr.data-automation-id]="processFilterProperty.key"> <mat-form-field [attr.data-automation-id]="processFilterProperty.key">
<mat-select <mat-select
placeholder="{{ processFilterProperty.label | translate }}" placeholder="{{ processFilterProperty.label | translate }}"
[value]="type"
(selectionChange)="onSelectionChange($event)" (selectionChange)="onSelectionChange($event)"
[attr.data-automation-id]="'adf-cloud-edit-process-property-' + processFilterProperty.key"> [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 }} {{ propertyOption.label | translate }}
</mat-option> </mat-option>
</mat-select> </mat-select>
@@ -19,8 +20,5 @@
</mat-date-range-input> </mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle> <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-date-range-picker #picker (closed)="onDateRangeClosed()"></mat-date-range-picker> <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> </mat-form-field>
</ng-container> </ng-container>

View File

@@ -59,6 +59,7 @@ describe('DateRangeFilterComponent', () => {
it('should get on option change', async () => { it('should get on option change', async () => {
spyOn(service, 'getDateRange'); 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'); const stateElement = fixture.debugElement.nativeElement.querySelector('[data-automation-id="adf-cloud-edit-process-property-createdDate"] .mat-select-trigger');
stateElement.click(); stateElement.click();
fixture.detectChanges(); fixture.detectChanges();
@@ -67,32 +68,27 @@ describe('DateRangeFilterComponent', () => {
options[2].nativeElement.click(); options[2].nativeElement.click();
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable(); 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', () => { 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 = { const expectedDate = {
startDate: null, startDate: null,
endDate: 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', () => { it('should return correct date when any type is selected', () => {
spyOn(component.dateChanged, 'emit');
const value = <MatSelectChange> { value: DateCloudFilterType.TOMORROW };
component.onSelectionChange(value);
const expectedDate = { const expectedDate = {
startDate: moment().endOf('day').toDate(), startDate: moment().endOf('day').toDate(),
endDate: moment().add(1, 'days').startOf('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'); spyOn(component.dateChanged, 'emit');
const value = <MatSelectChange> { value: DateCloudFilterType.RANGE }; const value = <MatSelectChange> { value: DateCloudFilterType.RANGE };
component.onSelectionChange(value); component.onSelectionChange(value);
@@ -105,10 +101,6 @@ describe('DateRangeFilterComponent', () => {
expect(component.dateChanged.emit).toHaveBeenCalled(); 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 () => { it('should show date-range picker when type is range', async () => {
const value = <MatSelectChange> { value: DateCloudFilterType.RANGE }; const value = <MatSelectChange> { value: DateCloudFilterType.RANGE };
component.onSelectionChange(value); component.onSelectionChange(value);
@@ -117,4 +109,29 @@ describe('DateRangeFilterComponent', () => {
const rangePickerElement = fixture.debugElement.nativeElement.querySelector('.adf-cloud-date-range-picker'); const rangePickerElement = fixture.debugElement.nativeElement.querySelector('.adf-cloud-date-range-picker');
expect(rangePickerElement).not.toBeNull(); 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));
});
}); });

View File

@@ -19,18 +19,8 @@ import { Component, Input, EventEmitter, Output } from '@angular/core';
import { MatSelectChange } from '@angular/material/select'; import { MatSelectChange } from '@angular/material/select';
import { ProcessFilterProperties, ProcessFilterOptions } from '../../process/process-filters/models/process-filter-cloud.model'; import { ProcessFilterProperties, ProcessFilterOptions } from '../../process/process-filters/models/process-filter-cloud.model';
import { FormGroup, FormControl } from '@angular/forms'; import { FormGroup, FormControl } from '@angular/forms';
import { DateRangeFilterService } from './date-range-filter.service';
import { DateRangeFilter, DateCloudFilterType } from '../../models/date-cloud-filter.model'; import { DateRangeFilter, DateCloudFilterType } from '../../models/date-cloud-filter.model';
import moment from 'moment-es6';
const DEFAULT_DATE_RANGE_OPTIONS = [
DateCloudFilterType.NO_DATE,
DateCloudFilterType.TODAY,
DateCloudFilterType.WEEK,
DateCloudFilterType.MONTH,
DateCloudFilterType.QUARTER,
DateCloudFilterType.YEAR,
DateCloudFilterType.RANGE
];
@Component({ @Component({
selector: 'adf-cloud-date-range-filter', selector: 'adf-cloud-date-range-filter',
@@ -43,11 +33,14 @@ const DEFAULT_DATE_RANGE_OPTIONS = [
processFilterProperty: ProcessFilterProperties; processFilterProperty: ProcessFilterProperties;
@Input() @Input()
options: DateCloudFilterType[] = DEFAULT_DATE_RANGE_OPTIONS; options: DateCloudFilterType[];
@Output() @Output()
dateChanged = new EventEmitter<DateRangeFilter>(); dateChanged = new EventEmitter<DateRangeFilter>();
@Output()
dateTypeChange = new EventEmitter<DateCloudFilterType>();
type: DateCloudFilterType; type: DateCloudFilterType;
filteredProperties: ProcessFilterOptions[] = []; filteredProperties: ProcessFilterOptions[] = [];
dateRangeForm = new FormGroup({ dateRangeForm = new FormGroup({
@@ -55,19 +48,18 @@ const DEFAULT_DATE_RANGE_OPTIONS = [
to: new FormControl() to: new FormControl()
}); });
constructor(private dateRangeFilterService: DateRangeFilterService) {}
ngOnInit() { ngOnInit() {
this.options = this.options ? this.options : this.createDefaultRangeOptions();
const defaultProperties = this.createDefaultDateOptions(); const defaultProperties = this.createDefaultDateOptions();
this.filteredProperties = defaultProperties.filter((filterProperty: ProcessFilterOptions) => this.isValidProperty(this.options, filterProperty)); this.filteredProperties = defaultProperties.filter((filterProperty: ProcessFilterOptions) => this.isValidProperty(this.options, filterProperty));
if (this.hasPreselectedValues()) {
this.setPreselectedValues();
}
} }
onSelectionChange(option: MatSelectChange) { onSelectionChange(option: MatSelectChange) {
this.type = option.value; this.type = option.value;
const dateRange = this.dateRangeFilterService.getDateRange(this.type); this.dateTypeChange.emit(this.type);
if (!this.isDateRangeType()) {
this.dateChanged.emit(dateRange);
}
} }
isDateRangeType(): boolean { isDateRangeType(): boolean {
@@ -82,10 +74,44 @@ const DEFAULT_DATE_RANGE_OPTIONS = [
this.dateChanged.emit(dateRange); 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 { private isValidProperty(filterProperties: string[], filterProperty: any): boolean {
return filterProperties ? filterProperties.indexOf(filterProperty.value) >= 0 : true; 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[] { private createDefaultDateOptions(): ProcessFilterOptions[] {
return [ return [
{ {

View File

@@ -86,8 +86,4 @@ describe('Date Range Filter service', () => {
}; };
expect(service.getDateRange(DateCloudFilterType.NEXT_7_DAYS)).toEqual(expectedDate); 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'));
});
}); });

View File

@@ -35,12 +35,14 @@ export class DateRangeFilterService {
case DateCloudFilterType.MONTH: return this.getCurrentMonthDateRange(); case DateCloudFilterType.MONTH: return this.getCurrentMonthDateRange();
case DateCloudFilterType.QUARTER: return this.getQuarterDateRange(); case DateCloudFilterType.QUARTER: return this.getQuarterDateRange();
case DateCloudFilterType.YEAR: return this.getCurrentYearDateRange(); case DateCloudFilterType.YEAR: return this.getCurrentYearDateRange();
case DateCloudFilterType.RANGE: return this.resetDateRange(); default: return this.resetDateRange();
case DateCloudFilterType.NO_DATE: return this.resetDateRange();
default: throw new Error('ADF_CLOUD_EDIT_PROCESS_FILTER.ERROR.INVALID_DATE_FILTER');
} }
} }
isDateRangeType(type: DateCloudFilterType) {
return type === DateCloudFilterType.RANGE;
}
private resetDateRange(): DateRangeFilter { private resetDateRange(): DateRangeFilter {
return { return {
startDate: null, startDate: null,

View File

@@ -10,6 +10,7 @@
"CREATED": "Created", "CREATED": "Created",
"STATUS": "Status", "STATUS": "Status",
"START_DATE": "Start Date", "START_DATE": "Start Date",
"COMPLETED_DATE": "Completed Date",
"ID": "Id", "ID": "Id",
"INITIATOR": "Initiator", "INITIATOR": "Initiator",
"APP_NAME": "Application Name", "APP_NAME": "Application Name",
@@ -167,7 +168,8 @@
"LAST_MODIFIED_TO": "LastModifiedTo", "LAST_MODIFIED_TO": "LastModifiedTo",
"PROCESS_NAME": "Process Name", "PROCESS_NAME": "Process Name",
"APP_VERSION": "AppReleaseVersion", "APP_VERSION": "AppReleaseVersion",
"CREATED_DATE": "Created Date", "STARTED_DATE": "Started Date",
"COMPLETED_DATE": "Completed Date",
"DATE_RANGE": { "DATE_RANGE": {
"NO_DATE": "No Date", "NO_DATE": "No Date",
"TODAY": "Today", "TODAY": "Today",

View File

@@ -66,8 +66,11 @@
</div> </div>
</div> </div>
</mat-form-field> </mat-form-field>
<adf-cloud-date-range-filter *ngIf="isDateRangeType(processFilterProperty)" <adf-cloud-date-range-filter *ngIf="isDateRangeType(processFilterProperty)"
[processFilterProperty]="processFilterProperty" [processFilterProperty]="processFilterProperty"
[options]="processFilterProperty.dateFilterOptions"
(dateTypeChange)="onDateTypeChange($event, processFilterProperty)"
(dateChanged)="onDateRangeFilterChanged($event, processFilterProperty)"></adf-cloud-date-range-filter> (dateChanged)="onDateRangeFilterChanged($event, processFilterProperty)"></adf-cloud-date-range-filter>
</ng-container> </ng-container>
</div> </div>

View File

@@ -37,6 +37,7 @@ import { PROCESS_FILTERS_SERVICE_TOKEN } from '../../../services/cloud-token.ser
import { LocalPreferenceCloudService } from '../../../services/local-preference-cloud.service'; import { LocalPreferenceCloudService } from '../../../services/local-preference-cloud.service';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { ProcessCloudService } from '../../services/process-cloud.service'; import { ProcessCloudService } from '../../services/process-cloud.service';
import { DateCloudFilterType } from '../../../models/date-cloud-filter.model';
describe('EditProcessFilterCloudComponent', () => { describe('EditProcessFilterCloudComponent', () => {
let component: EditProcessFilterCloudComponent; let component: EditProcessFilterCloudComponent;
@@ -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(() => { it('should able to build a editProcessFilter form with default properties if input is empty', async(() => {
fixture.detectChanges(); fixture.detectChanges();
component.filterProperties = []; component.filterProperties = [];
@@ -767,6 +783,64 @@ describe('EditProcessFilterCloudComponent', () => {
component.onFilterChange(); 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) => { it('should call restore default filters service on deletion of last filter', (done) => {
component.toggleFilterActions = true; component.toggleFilterActions = true;
const deleteFilterSpy = spyOn(service, 'deleteFilter').and.returnValue(of([])); const deleteFilterSpy = spyOn(service, 'deleteFilter').and.returnValue(of([]));

View File

@@ -32,7 +32,7 @@ import { ProcessFilterDialogCloudComponent } from './process-filter-dialog-cloud
import { ApplicationInstanceModel } from '../../../app/models/application-instance.model'; import { ApplicationInstanceModel } from '../../../app/models/application-instance.model';
import { ProcessCloudService } from '../../services/process-cloud.service'; import { ProcessCloudService } from '../../services/process-cloud.service';
import { ProcessDefinitionCloud } from '../../../models/process-definition-cloud.model'; import { ProcessDefinitionCloud } from '../../../models/process-definition-cloud.model';
import { DateRangeFilter } from '../../../models/date-cloud-filter.model'; import { DateCloudFilterType, DateRangeFilter } from '../../../models/date-cloud-filter.model';
@Component({ @Component({
selector: 'adf-cloud-edit-process-filter', selector: 'adf-cloud-edit-process-filter',
@@ -165,18 +165,22 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
getFormControlsConfig(processFilterProperties: ProcessFilterProperties[]): any { getFormControlsConfig(processFilterProperties: ProcessFilterProperties[]): any {
const properties = processFilterProperties.map((property: ProcessFilterProperties) => { const properties = processFilterProperties.map((property: ProcessFilterProperties) => {
if (!property.rangeKeys) { if (!!property.attributes) {
return { [property.key]: property.value }; return this.getAttributesControlConfig(property);
} else { } else {
return { return { [property.key]: property.value };
[property.rangeKeys.from]: property.value[property.rangeKeys.from],
[property.rangeKeys.to]: property.value[property.rangeKeys.to]
};
} }
}); });
return properties.reduce(((result, current) => Object.assign(result, current)), {}); return properties.reduce(((result, current) => Object.assign(result, current)), {});
} }
private getAttributesControlConfig(property: ProcessFilterProperties) {
return Object.values(property.attributes).reduce((result, key) => {
result[key] = property.value[key];
return result;
}, {});
}
/** /**
* Fetches process instance filter by application name and filter id and creates filter properties, build form * Fetches process instance filter by application name and filter id and creates filter properties, build form
*/ */
@@ -316,6 +320,19 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
} }
} }
onDateTypeChange(dateType: DateCloudFilterType, property: ProcessFilterProperties) {
this.editProcessFilterForm.get(property.attributes.dateType).setValue(dateType);
}
onDateRangeFilterChanged(dateRange: DateRangeFilter, property: ProcessFilterProperties) {
this.editProcessFilterForm.get(property.attributes?.from).setValue(
dateRange.startDate ? dateRange.startDate.toISOString() : null
);
this.editProcessFilterForm.get(property.attributes?.to).setValue(
dateRange.endDate ? dateRange.endDate.toISOString() : null
);
}
hasError(property: ProcessFilterProperties): boolean { hasError(property: ProcessFilterProperties): boolean {
return this.getPropertyController(property).errors && this.getPropertyController(property).errors.invalid; return this.getPropertyController(property).errors && this.getPropertyController(property).errors.invalid;
} }
@@ -455,15 +472,6 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
this.toggleFilterActions = false; this.toggleFilterActions = false;
} }
onDateRangeFilterChanged(dateRange: DateRangeFilter, property: ProcessFilterProperties) {
this.editProcessFilterForm.get(property.rangeKeys.from).setValue(
dateRange.startDate ? dateRange.startDate.toISOString() : null
);
this.editProcessFilterForm.get(property.rangeKeys.to).setValue(
dateRange.endDate ? dateRange.endDate.toISOString() : null
);
}
isDateType(property: ProcessFilterProperties): boolean { isDateType(property: ProcessFilterProperties): boolean {
return property.type === 'date'; return property.type === 'date';
} }
@@ -605,6 +613,11 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
key: 'processDefinitionId', key: 'processDefinitionId',
value: 'processDefinitionId' value: 'processDefinitionId'
}, },
{
label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.PROCESS_DEF_NAME',
key: 'processDefinitionName',
value: 'processDefinitionName'
},
{ {
label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.PROCESS_DEF_KEY', label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.PROCESS_DEF_KEY',
key: 'processDefinitionKey', key: 'processDefinitionKey',
@@ -697,13 +710,31 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
options: this.directions options: this.directions
}), }),
new ProcessFilterProperties({ new ProcessFilterProperties({
label: 'ADF_CLOUD_EDIT_TASK_FILTER.LABEL.START_DATE', label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.COMPLETED_DATE',
type: 'date',
key: 'completedDate',
value: currentProcessFilter.completedDate || false
}),
new ProcessFilterProperties({
label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.COMPLETED_DATE',
type: 'date-range', type: 'date-range',
key: 'startDateRange', key: 'completedDateRange',
rangeKeys: { from: 'startFrom', to: 'startTo'}, attributes: { dateType: 'completedDateType', from: '_completedFrom', to: '_completedTo'},
values: { value: {
from: currentProcessFilter.startFrom || null, completedDateType: currentProcessFilter.completedDateType || null,
to: currentProcessFilter.startTo || null _completedFrom: currentProcessFilter.completedFrom || null,
_completedTo: currentProcessFilter.completedTo || null
}
}),
new ProcessFilterProperties({
label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.STARTED_DATE',
type: 'date-range',
key: 'startedDateRange',
attributes: { dateType: 'startedDateType', from: '_startFrom', to: '_startTo'},
value: {
startedDateType: currentProcessFilter.startedDateType || null,
_startFrom: currentProcessFilter.startFrom || null,
_startTo: currentProcessFilter.startTo || null
} }
}) })
]; ];

View File

@@ -14,9 +14,13 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { DateCloudFilterType, RangeKeys } from '../../../models/date-cloud-filter.model'; import { DateCloudFilterType } from '../../../models/date-cloud-filter.model';
import { DateRangeFilterService } from '../../../common/date-range-filter/date-range-filter.service';
export class ProcessFilterCloudModel { export class ProcessFilterCloudModel {
private dateRangeFilterService = new DateRangeFilterService();
id: string; id: string;
name: string; name: string;
key: string; key: string;
@@ -37,8 +41,14 @@ export class ProcessFilterCloudModel {
lastModifiedTo: Date; lastModifiedTo: Date;
lastModifiedFrom: Date; lastModifiedFrom: Date;
startedDate: Date; startedDate: Date;
startFrom: Date; completedDateType: DateCloudFilterType;
startTo: Date; startedDateType: DateCloudFilterType;
completedDate: Date;
private _completedFrom: string;
private _completedTo: string;
private _startFrom: string;
private _startTo: string;
constructor(obj?: any) { constructor(obj?: any) {
if (obj) { if (obj) {
@@ -62,10 +72,71 @@ export class ProcessFilterCloudModel {
this.lastModifiedTo = obj.lastModifiedTo || null; this.lastModifiedTo = obj.lastModifiedTo || null;
this.lastModifiedFrom = obj.lastModifiedFrom || null; this.lastModifiedFrom = obj.lastModifiedFrom || null;
this.startedDate = obj.startedDate || null; this.startedDate = obj.startedDate || null;
this.startFrom = obj.startFrom || null; this.startFrom = obj._startFrom || null;
this.startTo = obj.startTo || null; this.startTo = obj._startTo || null;
this.completedDateType = obj.completedDateType || null;
this.startedDateType = obj.startedDateType || null;
this.completedFrom = obj._completedFrom || null;
this.completedTo = obj._completedTo || null;
this.completedDate = obj.completedDate || null;
} }
} }
set completedFrom(completedFrom: string) {
this._completedFrom = completedFrom;
}
set completedTo(completedTo: string) {
this._completedTo = completedTo;
}
get completedFrom() {
if (this.isDateRangeType(this.completedDateType)) {
return this._completedFrom;
}
return this.getStartDate(this.completedDateType);
}
get completedTo() {
if (this.isDateRangeType(this.completedDateType)) {
return this._completedTo;
}
return this.getEndDate(this.completedDateType);
}
set startFrom(startFrom: string) {
this._startFrom = startFrom;
}
set startTo(startTo: string) {
this._startTo = startTo;
}
get startFrom() {
if (this.isDateRangeType(this.startedDateType)) {
return this._startFrom;
}
return this.getStartDate(this.startedDateType);
}
get startTo() {
if (this.isDateRangeType(this.startedDateType)) {
return this._startTo;
}
return this.getEndDate(this.startedDateType);
}
private getStartDate(key: DateCloudFilterType) {
return this.dateRangeFilterService.getDateRange(key).startDate?.toISOString();
}
private getEndDate(key: DateCloudFilterType) {
return this.dateRangeFilterService.getDateRange(key).endDate?.toISOString();
}
private isDateRangeType(type: DateCloudFilterType) {
return !!this.dateRangeFilterService.isDateRangeType(type);
}
} }
export class ProcessFilterAction { export class ProcessFilterAction {
@@ -86,16 +157,16 @@ export class ProcessFilterAction {
export interface ProcessFilterOptions { export interface ProcessFilterOptions {
label?: string; label?: string;
value?: string; value?: string | object;
} }
export class ProcessFilterProperties { export class ProcessFilterProperties {
label: string; label: string;
type: string; type: string;
value: string; value: string | object;
key: string; key: string;
options: ProcessFilterOptions[]; attributes?: { [key: string]: string; };
rangeKeys?: RangeKeys; options?: ProcessFilterOptions[];
dateFilterOptions?: DateCloudFilterType[]; dateFilterOptions?: DateCloudFilterType[];
constructor(obj?: any) { constructor(obj?: any) {
@@ -104,15 +175,15 @@ export class ProcessFilterProperties {
this.type = obj.type || null; this.type = obj.type || null;
this.value = obj.value || ''; this.value = obj.value || '';
this.key = obj.key || null; this.key = obj.key || null;
this.attributes = obj.attributes || null;
this.options = obj.options || null; this.options = obj.options || null;
this.rangeKeys = obj.rangeKeys || null; this.dateFilterOptions = obj.dateFilterOptions || null;
this.dateFilterOptions = obj.dateFilterOptions || [];
} }
} }
} }
export interface ProcessSortFilterProperties { export interface ProcessSortFilterProperties {
label: string; label: string;
value: string; value: string | object;
key: string; key: string;
} }

View File

@@ -24,6 +24,7 @@ import { LocalPreferenceCloudService } from '../../../services/local-preference-
import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model'; import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model';
import { DateCloudFilterType } from 'process-services-cloud/src/lib/models/date-cloud-filter.model';
describe('ProcessFilterCloudService', () => { describe('ProcessFilterCloudService', () => {
let service: ProcessFilterCloudService; let service: ProcessFilterCloudService;
@@ -40,7 +41,7 @@ describe('ProcessFilterCloudService', () => {
email: 'fakeIdentity@email.com' email: 'fakeIdentity@email.com'
}; };
const fakeProcessFilter: ProcessFilterCloudModel = { const fakeProcessFilter: ProcessFilterCloudModel = new ProcessFilterCloudModel({
name: 'MOCK_PROCESS_NAME_1', name: 'MOCK_PROCESS_NAME_1',
id: '1', id: '1',
key: 'all-mock-process', key: 'all-mock-process',
@@ -59,10 +60,14 @@ describe('ProcessFilterCloudService', () => {
lastModified: null, lastModified: null,
lastModifiedTo: null, lastModifiedTo: null,
lastModifiedFrom: null, lastModifiedFrom: null,
completedDateType: DateCloudFilterType.NO_DATE,
startedDateType: DateCloudFilterType.NO_DATE,
_completedFrom: null,
_completedTo: null,
startedDate: null, startedDate: null,
startFrom: null, _startFrom: null,
startTo: null _startTo: null
}; });
const fakeProcessCloudFilterEntries = { const fakeProcessCloudFilterEntries = {
list: { list: {

View File

@@ -99,6 +99,18 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan
@Input() @Input()
startTo: string = ''; startTo: string = '';
/** Filter the processes. Display only process with completedFrom equal to the supplied date. */
@Input()
completedFrom: string = '';
/** Filter the processes. Display only process with completedTo equal to the supplied date. */
@Input()
completedTo: string = '';
/** Filter the processes. Display only process with completedDate equal to the supplied date. */
@Input()
completedDate: string = '';
/** /**
* Row selection mode. Can be "none", "single" or "multiple". * Row selection mode. Can be "none", "single" or "multiple".
* For multiple mode, you can use Cmd (macOS) or Ctrl (Win) modifier * For multiple mode, you can use Cmd (macOS) or Ctrl (Win) modifier
@@ -328,6 +340,9 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan
lastModifiedTo: this.lastModifiedTo, lastModifiedTo: this.lastModifiedTo,
startFrom: this.startFrom, startFrom: this.startFrom,
startTo: this.startTo, startTo: this.startTo,
completedFrom: this.completedFrom,
completedTo: this.completedTo,
completedDate: this.completedDate,
sorting: this.sorting sorting: this.sorting
}; };
return new ProcessQueryCloudRequestModel(requestNode); return new ProcessQueryCloudRequestModel(requestNode);

View File

@@ -34,6 +34,9 @@ export class ProcessQueryCloudRequestModel {
lastModifiedFrom?: string; lastModifiedFrom?: string;
startFrom?: string; startFrom?: string;
startTo?: string; startTo?: string;
completedFrom?: string;
completedTo?: string;
completedDate?: string;
maxItems: number; maxItems: number;
skipCount: number; skipCount: number;
sorting?: ProcessListCloudSortingModel[]; sorting?: ProcessListCloudSortingModel[];
@@ -55,6 +58,9 @@ export class ProcessQueryCloudRequestModel {
this.lastModifiedFrom = obj.lastModifiedFrom; this.lastModifiedFrom = obj.lastModifiedFrom;
this.startFrom = obj.startFrom; this.startFrom = obj.startFrom;
this.startTo = obj.startTo; this.startTo = obj.startTo;
this.completedFrom = obj.completedFrom;
this.completedTo = obj.completedTo;
this.completedDate = obj.completedDate;
this.maxItems = obj.maxItems; this.maxItems = obj.maxItems;
this.skipCount = obj.skipCount; this.skipCount = obj.skipCount;
this.sorting = obj.sorting; this.sorting = obj.sorting;

View File

@@ -71,6 +71,7 @@
<adf-cloud-date-range-filter *ngIf="isDateRangeType(taskFilterProperty)" <adf-cloud-date-range-filter *ngIf="isDateRangeType(taskFilterProperty)"
[processFilterProperty]="taskFilterProperty" [processFilterProperty]="taskFilterProperty"
[options]="taskFilterProperty.dateFilterOptions" [options]="taskFilterProperty.dateFilterOptions"
(dateTypeChange)="onDateTypeChange($event, taskFilterProperty)"
(dateChanged)="onDateRangeFilterChanged($event, taskFilterProperty)"></adf-cloud-date-range-filter> (dateChanged)="onDateRangeFilterChanged($event, taskFilterProperty)"></adf-cloud-date-range-filter>
</ng-container> </ng-container>
</div> </div>

View File

@@ -37,6 +37,7 @@ import { fakeFilter } from '../mock/task-filters-cloud.mock';
import { AbstractControl } from '@angular/forms'; import { AbstractControl } from '@angular/forms';
import moment from 'moment-es6'; import moment from 'moment-es6';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { DateCloudFilterType } from '../../../models/date-cloud-filter.model';
describe('EditTaskFilterCloudComponent', () => { describe('EditTaskFilterCloudComponent', () => {
let component: EditTaskFilterCloudComponent; let component: EditTaskFilterCloudComponent;
@@ -467,6 +468,64 @@ describe('EditTaskFilterCloudComponent', () => {
expect(appController.value).toBe('mock-app-name'); expect(appController.value).toBe('mock-app-name');
}); });
})); }));
it('should set the correct started date range when date range option is changed', (done) => {
component.appName = 'fake';
component.filterProperties = ['appName', 'processInstanceId', 'priority', 'dueDateRange'];
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange });
fixture.detectChanges();
const startedDateTypeControl: AbstractControl = component.editTaskFilterForm.get('dueDateType');
startedDateTypeControl.setValue(DateCloudFilterType.TODAY);
const dateFilter = {
startFrom: moment().startOf('day').toDate(),
startTo: moment().endOf('day').toDate()
};
component.filterChange.subscribe(() => {
expect(component.changedTaskFilter.dueDateFrom).toEqual(dateFilter.startFrom.toISOString());
expect(component.changedTaskFilter.dueDateTo).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', 'dueDateRange'];
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.editTaskFilterForm.get('dueDateType');
startedDateTypeControl.setValue(DateCloudFilterType.RANGE);
component.onDateRangeFilterChanged(dateFilter, {
key: 'dueDateRange',
label: '',
type: 'date-range',
value: '',
attributes: {
dateType: 'dueDateType',
from: '_dueDateFrom',
to: '_dueDateTo'
}
});
fixture.detectChanges();
component.filterChange.subscribe(() => {
expect(component.changedTaskFilter.dueDateFrom).toEqual(dateFilter.startDate.toISOString());
expect(component.changedTaskFilter.dueDateTo).toEqual(dateFilter.endDate.toISOString());
done();
});
component.onFilterChange();
});
}); });
describe('sort properties', () => { describe('sort properties', () => {

View File

@@ -170,18 +170,22 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges, OnDestro
getFormControlsConfig(taskFilterProperties: TaskFilterProperties[]): any { getFormControlsConfig(taskFilterProperties: TaskFilterProperties[]): any {
const properties = taskFilterProperties.map((property: TaskFilterProperties) => { const properties = taskFilterProperties.map((property: TaskFilterProperties) => {
if (!property.rangeKeys) { if (!!property.attributes) {
return { [property.key]: property.value }; return this.getAttributesControlConfig(property);
} else { } else {
return { return { [property.key]: property.value };
[property.rangeKeys.from]: property.value[property.rangeKeys.from],
[property.rangeKeys.to]: property.value[property.rangeKeys.to]
};
} }
}); });
return properties.reduce(((result, current) => Object.assign(result, current)), {}); return properties.reduce(((result, current) => Object.assign(result, current)), {});
} }
private getAttributesControlConfig(property: TaskFilterProperties) {
return Object.values(property.attributes).reduce((result, key) => {
result[key] = property.value[key];
return result;
}, {});
}
/** /**
* Check for edit task filter form changes * Check for edit task filter form changes
*/ */
@@ -335,11 +339,15 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges, OnDestro
} }
} }
onDateTypeChange(dateType: DateCloudFilterType, property: TaskFilterProperties) {
this.editTaskFilterForm.get(property.attributes.dateType).setValue(dateType);
}
onDateRangeFilterChanged(dateRange: DateRangeFilter, property: TaskFilterProperties) { onDateRangeFilterChanged(dateRange: DateRangeFilter, property: TaskFilterProperties) {
this.editTaskFilterForm.get(property.rangeKeys.from).setValue( this.editTaskFilterForm.get(property.attributes?.from).setValue(
dateRange.startDate ? dateRange.startDate.toISOString() : null dateRange.startDate ? dateRange.startDate.toISOString() : null
); );
this.editTaskFilterForm.get(property.rangeKeys.to).setValue( this.editTaskFilterForm.get(property.attributes?.to).setValue(
dateRange.endDate ? dateRange.endDate.toISOString() : null dateRange.endDate ? dateRange.endDate.toISOString() : null
); );
} }
@@ -669,8 +677,12 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges, OnDestro
label: 'ADF_CLOUD_EDIT_TASK_FILTER.LABEL.DUE_DATE', label: 'ADF_CLOUD_EDIT_TASK_FILTER.LABEL.DUE_DATE',
type: 'date-range', type: 'date-range',
key: 'dueDateRange', key: 'dueDateRange',
rangeKeys: { from: 'dueDateFrom', to: 'dueDateTo'}, attributes: { dateType: 'dueDateType', from: '_dueDateFrom', to: '_dueDateTo'},
value: currentTaskFilter.dueDate || false, value: {
dueDateType: currentTaskFilter.dueDateType || null,
_dueDateFrom: currentTaskFilter.dueDateFrom || null,
_dueDateTo: currentTaskFilter.dueDateTo || null
},
dateFilterOptions: [ dateFilterOptions: [
DateCloudFilterType.NO_DATE, DateCloudFilterType.NO_DATE,
DateCloudFilterType.TODAY, DateCloudFilterType.TODAY,

View File

@@ -15,7 +15,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { DateCloudFilterType, RangeKeys } from '../../../models/date-cloud-filter.model'; import { DateCloudFilterType } from '../../../models/date-cloud-filter.model';
import { DateRangeFilterService } from '../../../common/date-range-filter/date-range-filter.service';
export class TaskFilterCloudModel { export class TaskFilterCloudModel {
id: string; id: string;
@@ -33,9 +34,8 @@ export class TaskFilterCloudModel {
processDefinitionId: string; processDefinitionId: string;
processInstanceId: string; processInstanceId: string;
createdDate: Date; createdDate: Date;
dueDateType: DateCloudFilterType;
dueDate: Date; dueDate: Date;
dueDateFrom: string;
dueDateTo: string;
taskName: string; taskName: string;
taskId: string; taskId: string;
parentTaskId: string; parentTaskId: string;
@@ -44,6 +44,10 @@ export class TaskFilterCloudModel {
lastModifiedFrom: Date; lastModifiedFrom: Date;
lastModifiedTo: Date; lastModifiedTo: Date;
private _dueDateFrom: string;
private _dueDateTo: string;
private dateRangeFilterService = new DateRangeFilterService();
constructor(obj?: any) { constructor(obj?: any) {
if (obj) { if (obj) {
this.id = obj.id || Math.random().toString(36).substr(2, 9); this.id = obj.id || Math.random().toString(36).substr(2, 9);
@@ -61,9 +65,10 @@ export class TaskFilterCloudModel {
this.processDefinitionId = obj.processDefinitionId || null; this.processDefinitionId = obj.processDefinitionId || null;
this.processInstanceId = obj.processInstanceId || null; this.processInstanceId = obj.processInstanceId || null;
this.createdDate = obj.createdDate || null; this.createdDate = obj.createdDate || null;
this.dueDateType = obj.dueDateType || null;
this.dueDate = obj.dueDate || null; this.dueDate = obj.dueDate || null;
this.dueDateFrom = obj.dueDateFrom || null; this._dueDateFrom = obj._dueDateFrom || null;
this.dueDateTo = obj.dueDateTo || null; this._dueDateTo = obj._dueDateTo || null;
this.taskName = obj.taskName || null; this.taskName = obj.taskName || null;
this.taskId = obj.taskId || null; this.taskId = obj.taskId || null;
this.parentTaskId = obj.parentTaskId || null; this.parentTaskId = obj.parentTaskId || null;
@@ -73,6 +78,40 @@ export class TaskFilterCloudModel {
this.lastModifiedTo = obj.lastModifiedTo || null; this.lastModifiedTo = obj.lastModifiedTo || null;
} }
} }
set dueDateFrom(dueDateFrom: string) {
this._dueDateFrom = dueDateFrom;
}
set dueDateTo(dueDateTo: string) {
this._dueDateTo = dueDateTo;
}
get dueDateFrom() {
if (this.isDateRangeType(this.dueDateType)) {
return this._dueDateFrom;
}
return this.getStartDate(this.dueDateType);
}
get dueDateTo() {
if (this.isDateRangeType(this.dueDateType)) {
return this._dueDateTo;
}
return this.getEndDate(this.dueDateType);
}
private getStartDate(key: DateCloudFilterType) {
return this.dateRangeFilterService.getDateRange(key).startDate?.toISOString();
}
private getEndDate(key: DateCloudFilterType) {
return this.dateRangeFilterService.getDateRange(key).endDate?.toISOString();
}
private isDateRangeType(type: DateCloudFilterType) {
return !!this.dateRangeFilterService.isDateRangeType(type);
}
} }
export class FilterParamsModel { export class FilterParamsModel {
@@ -117,8 +156,8 @@ export class TaskFilterProperties {
type: string; type: string;
value: any; value: any;
key: string; key: string;
rangeKeys?: RangeKeys; attributes?: { [key: string]: string; };
options: FilterOptions[]; options?: FilterOptions[];
dateFilterOptions?: DateCloudFilterType[]; dateFilterOptions?: DateCloudFilterType[];
constructor(obj?: any) { constructor(obj?: any) {
@@ -127,7 +166,7 @@ export class TaskFilterProperties {
this.type = obj.type || null; this.type = obj.type || null;
this.value = obj.value || ''; this.value = obj.value || '';
this.key = obj.key || null; this.key = obj.key || null;
this.rangeKeys = obj.rangeKeys || null; this.attributes = obj.attributes || null;
this.options = obj.options || null; this.options = obj.options || null;
this.dateFilterOptions = obj.dateFilterOptions || null; this.dateFilterOptions = obj.dateFilterOptions || null;
} }

View File

@@ -3,7 +3,7 @@
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$DIR/../" cd "$DIR/../"
if grep "envalfresco" . -R --exclude-dir={node_modules,.history,.idea,scripts,dist,e2e-output} --exclude={.env,.env.*}; then if grep "envalfresco" . -R --exclude-dir={node_modules,.history,.idea,scripts,dist,e2e-output,.git} --exclude={.env,.env.*}; then
echo not permitted word echo not permitted word
exit 1 exit 1
fi fi