diff --git a/docs/process-services-cloud/components/task-list-cloud.component.md b/docs/process-services-cloud/components/task-list-cloud.component.md index ce77f58538..c591ff2c01 100644 --- a/docs/process-services-cloud/components/task-list-cloud.component.md +++ b/docs/process-services-cloud/components/task-list-cloud.component.md @@ -49,43 +49,45 @@ when the task list is empty: ### Properties -| Name | Type | Default value | Description | -| ---- | ---- | ------------- | ----------- | -| actionsPosition | `string` | "right" | Position of the actions dropdown menu. Can be "left" or "right". | -| appName | `string` | "" | The name of the application. | -| assignee | `string` | "" | The assignee of the process. Possible values are: "assignee" (the current user is the assignee), "candidate" (the current user is a task candidate", "group_x" (the task is assigned to a group where the current user is a member, no value (the current user is involved). | -| createdDate | `string` | "" | Filter the tasks. Display only tasks created on the supplied date. | -| dueDate | `string` | "" | Filter the tasks. Display only tasks with dueDate equal to the supplied date. | -| id | `string` | "" | Filter the tasks. Display only tasks with id equal to the supplied value. | -| lastModifiedFrom | `string` | "" | Filter the tasks. Display only tasks with lastModifiedFrom equal to the supplied date. | -| lastModifiedTo | `string` | "" | Filter the tasks. Display only tasks with lastModifiedTo equal to the supplied date. | -| multiselect | `boolean` | false | Toggles multiple row selection, rendering a checkbox at the beginning of each row. | -| name | `string` | "" | Filter the tasks. Display only tasks with the supplied name. | -| owner | `string` | "" | Filter the tasks. Display only tasks with owner equal to the supplied value. | -| parentTaskId | `string` | "" | Filter the tasks. Display only tasks with parentTaskId equal to the supplied value. | -| presetColumn | `string` | | Custom preset column schema in JSON format. | -| priority | `number` | | Filter the tasks. Display only tasks with priority equal to the supplied value. | -| processDefinitionId | `string` | "" | Filter the tasks. Display only tasks with processDefinitionId equal to the supplied value. | -| processInstanceId | `string` | "" | Filter the tasks. Display only tasks with processInstanceId equal to the supplied value. | -| selectionMode | `string` | "single" | Row selection mode. Can be none, `single` or `multiple`. For `multiple` mode, you can use the Cmd (macOS) or Ctrl (Win) modifier key to toggle selection for multiple rows. | -| showActions | `boolean` | false | Toggles the data actions column. | -| showContextMenu | `boolean` | false | Toggles custom context menu for the component. | -| sorting | [`TaskListCloudSortingModel`](../../../lib/process-services-cloud/src/lib/task/task-list/models/task-list-sorting.model.ts)`[]` | | Specifies how the table should be sorted. The parameters are for BE sorting. | -| standalone | `boolean` | false | Filter the tasks. Display only the tasks that belong to a process in case is false or tasks that doesn't belong to a process in case of true. | -| status | `string` | "" | Filter the tasks. Display only tasks with status equal to the supplied value. | -| stickyHeader | `boolean` | false | Toggles the sticky header mode. | +| Name | Type | Default value | Description | +| ------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| actionsPosition | `string` | "right" | Position of the actions dropdown menu. Can be "left" or "right". | +| appName | `string` | "" | The name of the application. | +| assignee | `string` | "" | The assignee of the process. Possible values are: "assignee" (the current user is the assignee), "candidate" (the current user is a task candidate", "group_x" (the task is assigned to a group where the current user is a member, no value (the current user is involved). | +| createdDate | `string` | "" | Filter the tasks. Display only tasks created on the supplied date. | +| dueDate | `string` | "" | Filter the tasks. Display only tasks with dueDate equal to the supplied date. | +| dueDateFrom | `string` | "" | Filter the tasks. Display only tasks with dueDate greater or equal than the supplied date. | +| dueDateTo | `string` | "" | Filter the tasks. Display only tasks with dueDate less or equal to the supplied date. | +| id | `string` | "" | Filter the tasks. Display only tasks with id equal to the supplied value. | +| lastModifiedFrom | `string` | "" | Filter the tasks. Display only tasks with lastModifiedFrom equal to the supplied date. | +| lastModifiedTo | `string` | "" | Filter the tasks. Display only tasks with lastModifiedTo equal to the supplied date. | +| multiselect | `boolean` | false | Toggles multiple row selection, rendering a checkbox at the beginning of each row. | +| name | `string` | "" | Filter the tasks. Display only tasks with the supplied name. | +| owner | `string` | "" | Filter the tasks. Display only tasks with owner equal to the supplied value. | +| parentTaskId | `string` | "" | Filter the tasks. Display only tasks with parentTaskId equal to the supplied value. | +| presetColumn | `string` | | Custom preset column schema in JSON format. | +| priority | `number` | | Filter the tasks. Display only tasks with priority equal to the supplied value. | +| processDefinitionId | `string` | "" | Filter the tasks. Display only tasks with processDefinitionId equal to the supplied value. | +| processInstanceId | `string` | "" | Filter the tasks. Display only tasks with processInstanceId equal to the supplied value. | +| selectionMode | `string` | "single" | Row selection mode. Can be none, `single` or `multiple`. For `multiple` mode, you can use the Cmd (macOS) or Ctrl (Win) modifier key to toggle selection for multiple rows. | +| showActions | `boolean` | false | Toggles the data actions column. | +| showContextMenu | `boolean` | false | Toggles custom context menu for the component. | +| sorting | [`TaskListCloudSortingModel`](../../../lib/process-services-cloud/src/lib/task/task-list/models/task-list-sorting.model.ts)`[]` | | Specifies how the table should be sorted. The parameters are for BE sorting. | +| standalone | `boolean` | false | Filter the tasks. Display only the tasks that belong to a process in case is false or tasks that doesn't belong to a process in case of true. | +| status | `string` | "" | Filter the tasks. Display only tasks with status equal to the supplied value. | +| stickyHeader | `boolean` | false | Toggles the sticky header mode. | ### Events -| Name | Type | Description | -| ---- | ---- | ----------- | -| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when an error occurs. | -| executeRowAction | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`DataRowActionEvent`](../../../lib/core/datatable/components/data-row-action.event.ts)`>` | Emitted when the user executes a row action. | -| rowClick | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when a task in the list is clicked | -| rowsSelected | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when rows are selected/unselected | -| showRowActionsMenu | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`DataCellEvent`](../../../lib/core/datatable/components/data-cell.event.ts)`>` | Emitted before the actions menu is displayed for a row. | -| showRowContextMenu | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`DataCellEvent`](../../../lib/core/datatable/components/data-cell.event.ts)`>` | Emitted before the context menu is displayed for a row. | -| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when the task list is loaded | +| Name | Type | Description | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | +| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when an error occurs. | +| executeRowAction | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`DataRowActionEvent`](../../../lib/core/datatable/components/data-row-action.event.ts)`>` | Emitted when the user executes a row action. | +| rowClick | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when a task in the list is clicked | +| rowsSelected | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when rows are selected/unselected | +| showRowActionsMenu | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`DataCellEvent`](../../../lib/core/datatable/components/data-cell.event.ts)`>` | Emitted before the actions menu is displayed for a row. | +| showRowContextMenu | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`DataCellEvent`](../../../lib/core/datatable/components/data-cell.event.ts)`>` | Emitted before the context menu is displayed for a row. | +| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when the task list is loaded | ## Details diff --git a/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.component.html b/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.component.html index 9334d5561d..1bc4515b49 100644 --- a/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.component.html +++ b/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.component.html @@ -1,10 +1,10 @@ - + {{ propertyOption.label | translate }} @@ -14,13 +14,13 @@ {{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE_TITLE' | translate }} - - + + - {{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.ERROR.INDALID_START_DATE' | translate }} - {{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.ERROR.INDALID_END_DATE' | translate }} + {{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.ERROR.INDALID_START_DATE' | translate }} + {{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.ERROR.INDALID_END_DATE' | translate }} diff --git a/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.component.spec.ts b/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.component.spec.ts index 239c834289..fb6eab65a5 100644 --- a/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.component.spec.ts +++ b/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.component.spec.ts @@ -16,18 +16,20 @@ */ import { DateRangeFilterComponent } from './date-range-filter.component'; -import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { setupTestBed } from 'core'; import { TranslateModule } from '@ngx-translate/core'; import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module'; import { By } from '@angular/platform-browser'; -import { ProcessDateFilterType } from '../../process/process-filters/models/process-filter-cloud.model'; import { MatSelectChange } from '@angular/material/select'; +import { DateCloudFilterType } from '../../models/date-cloud-filter.model'; +import { DateRangeFilterService } from './date-range-filter.service'; import moment from 'moment-es6'; describe('DateRangeFilterComponent', () => { let component: DateRangeFilterComponent; let fixture: ComponentFixture; + let service: DateRangeFilterService; setupTestBed({ imports: [ @@ -39,6 +41,7 @@ describe('DateRangeFilterComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(DateRangeFilterComponent); component = fixture.componentInstance; + service = TestBed.inject(DateRangeFilterService); component.processFilterProperty = { key: 'createdDate', @@ -54,8 +57,8 @@ describe('DateRangeFilterComponent', () => { fixture.destroy(); }); - it('should setDate on option change', async(() => { - spyOn(component, 'setDate'); + it('should get on option change', async () => { + spyOn(service, 'getDateRange'); const stateElement = fixture.debugElement.nativeElement.querySelector('[data-automation-id="adf-cloud-edit-process-property-createdDate"] .mat-select-trigger'); stateElement.click(); fixture.detectChanges(); @@ -63,61 +66,13 @@ describe('DateRangeFilterComponent', () => { const options = fixture.debugElement.queryAll(By.css('.mat-option-text')); options[2].nativeElement.click(); fixture.detectChanges(); - fixture.whenStable().then(() => { - expect(component.setDate).toHaveBeenCalled(); - }); - })); - - it('should emit today range', () => { - spyOn(component.dateChanged, 'emit'); - const value = { value: ProcessDateFilterType.today }; - component.onSelectionChange(value); - const expectedDate = { - startDate: moment().startOf('day').toDate(), - endDate: moment().endOf('day').toDate() - }; - expect(component.dateChanged.emit).toHaveBeenCalledWith(expectedDate); + await fixture.whenStable(); + expect(service.getDateRange).toHaveBeenCalled(); }); - it('should emit month range', () => { + it('should reset date range when no_date type is selected', () => { spyOn(component.dateChanged, 'emit'); - const value = { value: ProcessDateFilterType.month }; - component.onSelectionChange(value); - const expectedDate = { - startDate: moment().startOf('month').toDate(), - endDate: moment().endOf('month').toDate() - }; - expect(component.dateChanged.emit).toHaveBeenCalledWith(expectedDate); - }); - - it('should emit year range', () => { - spyOn(component.dateChanged, 'emit'); - const value = { value: ProcessDateFilterType.year }; - component.onSelectionChange(value); - const expectedDate = { - startDate: moment().startOf('year').toDate(), - endDate: moment().endOf('year').toDate() - }; - expect(component.dateChanged.emit).toHaveBeenCalledWith(expectedDate); - }); - - it('should emit quarter range', () => { - spyOn(component.dateChanged, 'emit'); - const value = { value: ProcessDateFilterType.quarter }; - component.onSelectionChange(value); - const currentDate = new Date(); - const quarter = Math.floor((currentDate.getMonth() / 3)); - const firstDate = new Date(currentDate.getFullYear(), quarter * 3, 1); - const expectedDate = { - startDate: firstDate, - endDate: new Date(firstDate.getFullYear(), firstDate.getMonth() + 3, 0) - }; - expect(component.dateChanged.emit).toHaveBeenCalledWith(expectedDate); - }); - - it('should reset date range when no type is selected', () => { - spyOn(component.dateChanged, 'emit'); - const value = { value: null }; + const value = { value: DateCloudFilterType.NO_DATE }; component.onSelectionChange(value); const expectedDate = { startDate: null, @@ -126,8 +81,36 @@ describe('DateRangeFilterComponent', () => { expect(component.dateChanged.emit).toHaveBeenCalledWith(expectedDate); }); + it('should emit date range when any type is selected', () => { + spyOn(component.dateChanged, 'emit'); + const value = { value: DateCloudFilterType.TOMORROW }; + component.onSelectionChange(value); + const expectedDate = { + startDate: moment().endOf('day').toDate(), + endDate: moment().add(1, 'days').startOf('day').toDate() + }; + expect(component.dateChanged.emit).toHaveBeenCalledWith(expectedDate); + }); + + it('should not emit any date change events when range type is selected', () => { + spyOn(component.dateChanged, 'emit'); + const value = { value: DateCloudFilterType.RANGE }; + component.onSelectionChange(value); + expect(component.dateChanged.emit).not.toHaveBeenCalled(); + }); + + it('should emit custom date range on date picker closed', () => { + spyOn(component.dateChanged, 'emit'); + component.onDateRangeClosed(); + 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 = { value: ProcessDateFilterType.range }; + const value = { value: DateCloudFilterType.RANGE }; component.onSelectionChange(value); fixture.detectChanges(); await fixture.whenStable(); diff --git a/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.component.ts b/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.component.ts index 7e8e8911b7..f08ffd82f8 100644 --- a/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.component.ts +++ b/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.component.ts @@ -17,9 +17,19 @@ import { Component, Input, EventEmitter, Output } from '@angular/core'; import { MatSelectChange } from '@angular/material/select'; -import moment from 'moment-es6'; -import { ProcessFilterProperties, DateRangeFilter, ProcessDateFilterType } 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 { DateRangeFilterService } from './date-range-filter.service'; +import { DateRangeFilter, DateCloudFilterType } from '../../models/date-cloud-filter.model'; + +const DEFAULT_DATE_RANGE_OPTIONS = [ + DateCloudFilterType.TODAY, + DateCloudFilterType.WEEK, + DateCloudFilterType.MONTH, + DateCloudFilterType.QUARTER, + DateCloudFilterType.YEAR, + DateCloudFilterType.RANGE +]; @Component({ selector: 'adf-cloud-date-range-filter', @@ -31,128 +41,88 @@ import { FormGroup, FormControl } from '@angular/forms'; @Input() processFilterProperty: ProcessFilterProperties; + @Input() + options: DateCloudFilterType[] = DEFAULT_DATE_RANGE_OPTIONS; + @Output() dateChanged = new EventEmitter(); - type: ProcessDateFilterType; - currentDate = new Date(); - dateRange: DateRangeFilter = { - startDate: null, - endDate: null - }; - + type: DateCloudFilterType; + filteredProperties: ProcessFilterOptions[] = []; dateRangeForm = new FormGroup({ - start: new FormControl(), - end: new FormControl() + from: new FormControl(), + to: new FormControl() }); - options = [ - { - key: ProcessDateFilterType.today, - label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE.TODAY' - }, - { - key: ProcessDateFilterType.week, - label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE.WEEK' - }, - { - key: ProcessDateFilterType.month, - label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE.MONTH' - }, - { - key: ProcessDateFilterType.quarter, - label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE.QUARTER' - }, - { - key: ProcessDateFilterType.year, - label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE.YEAR' - }, - { - key: ProcessDateFilterType.range, - label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE.RANGE' - } - ]; + constructor(private dateRangeFilterService: DateRangeFilterService) {} + + ngOnInit() { + const defaultProperties = this.createDefaultDateOptions(); + this.filteredProperties = defaultProperties.filter((filterProperty: ProcessFilterOptions) => this.isValidProperty(this.options, filterProperty)); + } onSelectionChange(option: MatSelectChange) { this.type = option.value; - this.setDate(); - this.dateChanged.emit(this.dateRange); - } - - setDate() { - switch (this.type) { - case ProcessDateFilterType.today: - this.setTodayDateRange(); - break; - case ProcessDateFilterType.week: - this.setCurrentWeekRange(); - break; - case ProcessDateFilterType.month: - this.setCurrentMonthDateRange(); - break; - case ProcessDateFilterType.quarter: - this.setQuarterDateRange(); - break; - case ProcessDateFilterType.year: - this.setCurrentYearDateRange(); - break; - default: this.resetDateRange(); + const dateRange = this.dateRangeFilterService.getDateRange(this.type); + if (!this.isDateRangeType()) { + this.dateChanged.emit(dateRange); } } isDateRangeType(): boolean { - return this.type === ProcessDateFilterType.range; + return this.type === DateCloudFilterType.RANGE; } onDateRangeClosed() { - this.dateRange = { - startDate: this.dateRangeForm.controls.start.value, - endDate: this.dateRangeForm.controls.end.value + const dateRange = { + startDate: this.dateRangeForm.controls.from.value, + endDate: this.dateRangeForm.controls.to.value }; - this.dateChanged.emit(this.dateRange); + this.dateChanged.emit(dateRange); } - private resetDateRange() { - this.dateRange = { - startDate: null, - endDate: null - }; + private isValidProperty(filterProperties: string[], filterProperty: any): boolean { + return filterProperties ? filterProperties.indexOf(filterProperty.value) >= 0 : true; } - private setCurrentYearDateRange() { - this.dateRange = { - startDate: moment().startOf('year').toDate(), - endDate: moment().endOf('year').toDate() - }; - } - - private setTodayDateRange() { - this.dateRange = { - startDate: moment().startOf('day').toDate(), - endDate: moment().endOf('day').toDate() - }; - } - - private setCurrentWeekRange() { - this.dateRange = { - startDate: moment().startOf('week').toDate(), - endDate: moment().endOf('week').toDate() - }; - } - - private setCurrentMonthDateRange() { - this.dateRange = { - startDate: moment().startOf('month').toDate(), - endDate: moment().endOf('month').toDate() - }; - } - - private setQuarterDateRange() { - const quarter = Math.floor((this.currentDate.getMonth() / 3)); - const firstDate = new Date(this.currentDate.getFullYear(), quarter * 3, 1); - this.dateRange = { - startDate: firstDate, - endDate: new Date(firstDate.getFullYear(), firstDate.getMonth() + 3, 0) - }; + private createDefaultDateOptions(): ProcessFilterOptions[] { + return [ + { + value: DateCloudFilterType.NO_DATE, + label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE.NO_DATE' + }, + { + value: DateCloudFilterType.TODAY, + label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE.TODAY' + }, + { + value: DateCloudFilterType.TOMORROW, + label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE.TOMORROW' + }, + { + value: DateCloudFilterType.NEXT_7_DAYS, + label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE.NEXT_7_DAYS' + }, + { + value: DateCloudFilterType.WEEK, + label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE.WEEK' + }, + { + value: DateCloudFilterType.MONTH, + label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE.MONTH' + }, + { + value: DateCloudFilterType.QUARTER, + label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE.QUARTER' + }, + { + value: DateCloudFilterType.YEAR, + label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE.YEAR' + }, + { + value: DateCloudFilterType.RANGE, + label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DATE_RANGE.RANGE' + } + ]; } } diff --git a/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.service.spec.ts b/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.service.spec.ts new file mode 100644 index 0000000000..a1ccaf391f --- /dev/null +++ b/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.service.spec.ts @@ -0,0 +1,93 @@ +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TestBed } from '@angular/core/testing'; +import { DateRangeFilterService } from './date-range-filter.service'; +import { DateCloudFilterType } from '../../models/date-cloud-filter.model'; +import moment from 'moment-es6'; + +describe('Date Range Filter service', () => { + + let service: DateRangeFilterService; + + beforeEach(() => { + service = TestBed.inject(DateRangeFilterService); + }); + + it('should return today range', () => { + const expectedDate = { + startDate: moment().startOf('day').toDate(), + endDate: moment().endOf('day').toDate() + }; + expect(service.getDateRange(DateCloudFilterType.TODAY)).toEqual(expectedDate); + }); + + it('should return month range', () => { + const expectedDate = { + startDate: moment().startOf('month').toDate(), + endDate: moment().endOf('month').toDate() + }; + expect(service.getDateRange(DateCloudFilterType.MONTH)).toEqual(expectedDate); + }); + + it('should return year range', () => { + const expectedDate = { + startDate: moment().startOf('year').toDate(), + endDate: moment().endOf('year').toDate() + }; + expect(service.getDateRange(DateCloudFilterType.YEAR)).toEqual(expectedDate); + }); + + it('should return quarter range', () => { + const currentDate = new Date(); + const quarter = Math.floor((currentDate.getMonth() / 3)); + const firstDate = new Date(currentDate.getFullYear(), quarter * 3, 1); + const expectedDate = { + startDate: firstDate, + endDate: new Date(firstDate.getFullYear(), firstDate.getMonth() + 3, 0) + }; + expect(service.getDateRange(DateCloudFilterType.QUARTER)).toEqual(expectedDate); + }); + + it('should reset date range when no_date type is selected', () => { + const expectedDate = { + startDate: null, + endDate: null + }; + expect(service.getDateRange(DateCloudFilterType.NO_DATE)).toEqual(expectedDate); + }); + + it('should return tomorow range', () => { + const expectedDate = { + startDate: moment().endOf('day').toDate(), + endDate: moment().add(1, 'days').startOf('day').toDate() + }; + expect(service.getDateRange(DateCloudFilterType.TOMORROW)).toEqual(expectedDate); + }); + + it('should return next 7 days range', () => { + const expectedDate = { + startDate: moment().startOf('day').toDate(), + endDate: moment().add(7, 'days').endOf('day').toDate() + }; + 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')); + }); +}); diff --git a/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.service.ts b/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.service.ts new file mode 100644 index 0000000000..d25feded19 --- /dev/null +++ b/lib/process-services-cloud/src/lib/common/date-range-filter/date-range-filter.service.ts @@ -0,0 +1,101 @@ +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import moment from 'moment-es6'; +import { DateRangeFilter, DateCloudFilterType } from '../../models/date-cloud-filter.model'; + +@Injectable({ + providedIn: 'root' +}) +export class DateRangeFilterService { + + currentDate = new Date(); + + getDateRange(type: DateCloudFilterType): DateRangeFilter { + switch (type) { + case DateCloudFilterType.TODAY: return this.getTodayDateRange(); + case DateCloudFilterType.TOMORROW: return this.getTomorrowDateRange(); + case DateCloudFilterType.NEXT_7_DAYS: return this.getNext7DaysDateRange(); + case DateCloudFilterType.WEEK: return this.getCurrentWeekRange(); + 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'); + } + } + + private resetDateRange(): DateRangeFilter { + return { + startDate: null, + endDate: null + }; + } + + private getNext7DaysDateRange(): DateRangeFilter { + return { + startDate: moment().startOf('day').toDate(), + endDate: moment().add(7, 'days').endOf('day').toDate() + }; + } + + private getTomorrowDateRange(): DateRangeFilter { + return { + startDate: moment().endOf('day').toDate(), + endDate: moment().add(1, 'days').startOf('day').toDate() + }; + } + + private getCurrentYearDateRange(): DateRangeFilter { + return { + startDate: moment().startOf('year').toDate(), + endDate: moment().endOf('year').toDate() + }; + } + + private getTodayDateRange(): DateRangeFilter { + return { + startDate: moment().startOf('day').toDate(), + endDate: moment().endOf('day').toDate() + }; + } + + private getCurrentWeekRange(): DateRangeFilter { + return { + startDate: moment().startOf('week').toDate(), + endDate: moment().endOf('week').toDate() + }; + } + + private getCurrentMonthDateRange(): DateRangeFilter { + return { + startDate: moment().startOf('month').toDate(), + endDate: moment().endOf('month').toDate() + }; + } + + private getQuarterDateRange(): DateRangeFilter { + const quarter = Math.floor((this.currentDate.getMonth() / 3)); + const firstDate = new Date(this.currentDate.getFullYear(), quarter * 3, 1); + return { + startDate: firstDate, + endDate: new Date(firstDate.getFullYear(), firstDate.getMonth() + 3, 0) + }; + } +} diff --git a/lib/process-services-cloud/src/lib/common/process-common.module.ts b/lib/process-services-cloud/src/lib/common/process-common.module.ts index c1d95ec3d1..959878a3b8 100644 --- a/lib/process-services-cloud/src/lib/common/process-common.module.ts +++ b/lib/process-services-cloud/src/lib/common/process-common.module.ts @@ -20,6 +20,7 @@ import { CoreModule } from '@alfresco/adf-core'; import { DateRangeFilterComponent } from './date-range-filter/date-range-filter.component'; import { MaterialModule } from '../material.module'; import { CommonModule } from '@angular/common'; +import { DateRangeFilterService } from './date-range-filter/date-range-filter.service'; @NgModule({ declarations: [ DateRangeFilterComponent ], @@ -30,6 +31,9 @@ import { CommonModule } from '@angular/common'; ], exports: [ DateRangeFilterComponent + ], + providers: [ + DateRangeFilterService ] }) export class ProcessCommonModule {} diff --git a/lib/process-services-cloud/src/lib/i18n/en.json b/lib/process-services-cloud/src/lib/i18n/en.json index 30b2f2ebcb..a609375fed 100644 --- a/lib/process-services-cloud/src/lib/i18n/en.json +++ b/lib/process-services-cloud/src/lib/i18n/en.json @@ -168,7 +168,10 @@ "APP_VERSION": "AppReleaseVersion", "CREATED_DATE": "Created Date", "DATE_RANGE": { + "NO_DATE": "NO_DATE", "TODAY": "today", + "TOMORROW": "tomorow", + "NEXT_7_DAYS": "Next 7 Days", "WEEK": "this week", "MONTH": "this month", "QUARTER": "this quarter", @@ -182,7 +185,8 @@ "ERROR": { "DATE": "Date format DD/MM/YYYY", "INDALID_START_DATE": "Invalid start date", - "INDALID_END_DATE": "Invalid end date" + "INDALID_END_DATE": "Invalid end date", + "INVALID_DATE_FILTER": "Date filter option is not supported" }, "TOOL_TIP": { "SAVE": "Save filter", diff --git a/lib/process-services-cloud/src/lib/models/date-cloud-filter.model.ts b/lib/process-services-cloud/src/lib/models/date-cloud-filter.model.ts new file mode 100644 index 0000000000..b682c0ded3 --- /dev/null +++ b/lib/process-services-cloud/src/lib/models/date-cloud-filter.model.ts @@ -0,0 +1,33 @@ +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export enum DateCloudFilterType { + NO_DATE = 'NO_DATE', + TODAY = 'TODAY', + TOMORROW = 'TOMORROW', + NEXT_7_DAYS = 'NEXT_7_DAYS', + WEEK = 'WEEK', + MONTH = 'MONTH', + QUARTER = 'QUARTER', + YEAR = 'YEAR', + RANGE = 'RANGE' +} + +export interface DateRangeFilter { + startDate: Date; + endDate: Date; +} diff --git a/lib/process-services-cloud/src/lib/process/process-filters/models/process-filter-cloud.model.ts b/lib/process-services-cloud/src/lib/process/process-filters/models/process-filter-cloud.model.ts index d3bf7e2581..af7cfa20d9 100644 --- a/lib/process-services-cloud/src/lib/process/process-filters/models/process-filter-cloud.model.ts +++ b/lib/process-services-cloud/src/lib/process/process-filters/models/process-filter-cloud.model.ts @@ -99,17 +99,3 @@ export class ProcessFilterProperties { } } } - -export enum ProcessDateFilterType { - today = 'today', - week = 'week', - month = 'month', - quarter = 'quarter', - year = 'year', - range = 'range' -} - -export interface DateRangeFilter { - startDate: Date; - endDate: Date; -} diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filter-cloud.component.html b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filter-cloud.component.html index 4e0ddb0fc9..050cff08f9 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filter-cloud.component.html +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filter-cloud.component.html @@ -59,14 +59,19 @@ -
- - {{taskFilterProperty.label | translate}} - +
+ + {{taskFilterProperty.label | translate}} +
+ +
diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filter-cloud.component.scss b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filter-cloud.component.scss index 8bf1426c27..31070d7058 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filter-cloud.component.scss +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filter-cloud.component.scss @@ -6,6 +6,7 @@ font-size: 16px; padding-top: 10px; text-align: center; + flex: 1 23%; } .adf-edit-task-filter-date-error-container { @@ -35,6 +36,10 @@ } } + .adf-edit-task-filter-dateRange mat-grid-list { + width: 450px; + } + .adf { &-cloud-edit-task-filter-loading-margin { margin-left: calc((100% - 100px) / 2); diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filter-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filter-cloud.component.ts index f452f74596..56422076c2 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filter-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filter-cloud.component.ts @@ -30,6 +30,7 @@ import { TaskFilterDialogCloudComponent } from './task-filter-dialog-cloud.compo import { TranslationService, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core'; import { AppsProcessCloudService } from '../../../app/services/apps-process-cloud.service'; import { ApplicationInstanceModel } from '../../../app/models/application-instance.model'; +import { DateCloudFilterType, DateRangeFilter } from '../../../models/date-cloud-filter.model'; @Component({ selector: 'adf-cloud-edit-task-filter', @@ -163,7 +164,14 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges, OnDestro getFormControlsConfig(taskFilterProperties: TaskFilterProperties[]): any { const properties = taskFilterProperties.map((property: TaskFilterProperties) => { - return { [property.key]: property.value }; + if (!property.rangeKeys) { + return { [property.key]: property.value }; + } else { + return { + [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)), {}); } @@ -317,6 +325,15 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges, OnDestro } } + onDateRangeFilterChanged(dateRange: DateRangeFilter, property: TaskFilterProperties) { + this.editTaskFilterForm.get(property.rangeKeys.from).setValue( + dateRange.startDate ? dateRange.startDate.toISOString() : null + ); + this.editTaskFilterForm.get(property.rangeKeys.to).setValue( + dateRange.endDate ? dateRange.endDate.toISOString() : null + ); + } + hasError(property: TaskFilterProperties): boolean { return this.getPropertyController(property).errors && this.getPropertyController(property).errors.invalid; } @@ -443,6 +460,10 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges, OnDestro return property.type === 'date'; } + isDateRangeType(property: TaskFilterProperties): boolean { + return property.type === 'date-range'; + } + isSelectType(property: TaskFilterProperties): boolean { return property.type === 'select'; } @@ -588,12 +609,6 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges, OnDestro key: 'createdDate', value: '' }), - new TaskFilterProperties({ - label: 'ADF_CLOUD_EDIT_TASK_FILTER.LABEL.DUE_DATE', - type: 'date', - key: 'dueDate', - value: '' - }), new TaskFilterProperties({ label: 'ADF_CLOUD_EDIT_TASK_FILTER.LABEL.SORT', type: 'select', @@ -613,6 +628,19 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges, OnDestro type: 'checkbox', key: 'standalone', value: currentTaskFilter.standalone || false + }), + new TaskFilterProperties({ + label: 'ADF_CLOUD_EDIT_TASK_FILTER.LABEL.DUE_DATE', + type: 'date-range', + key: 'dueDate', + rangeKeys: { from: 'dueDateFrom', to: 'dueDateTo'}, + value: currentTaskFilter.dueDate || false, + dateFilterOptions: [ + DateCloudFilterType.NO_DATE, + DateCloudFilterType.TOMORROW, + DateCloudFilterType.NEXT_7_DAYS, + DateCloudFilterType.RANGE + ] }) ]; } diff --git a/lib/process-services-cloud/src/lib/task/task-filters/models/filter-cloud.model.ts b/lib/process-services-cloud/src/lib/task/task-filters/models/filter-cloud.model.ts index 0f708ae224..ae24bdbe0a 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/models/filter-cloud.model.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/models/filter-cloud.model.ts @@ -15,6 +15,8 @@ * limitations under the License. */ +import { DateCloudFilterType } from '../../../models/date-cloud-filter.model'; + export class TaskFilterCloudModel { id: string; name: string; @@ -31,6 +33,8 @@ export class TaskFilterCloudModel { processInstanceId: string; createdDate: Date; dueDate: Date; + dueDateFrom: string; + dueDateTo: string; taskName: string; taskId: string; parentTaskId: string; @@ -56,6 +60,8 @@ export class TaskFilterCloudModel { this.processInstanceId = obj.processInstanceId || null; this.createdDate = obj.createdDate || null; this.dueDate = obj.dueDate || null; + this.dueDateFrom = obj.dueDateFrom || null; + this.dueDateTo = obj.dueDateTo || null; this.taskName = obj.taskName || null; this.taskId = obj.taskId || null; this.parentTaskId = obj.parentTaskId || null; @@ -104,12 +110,19 @@ export interface FilterOptions { value?: string; } +export interface RangeKeys { + from: string; + to: string; +} + export class TaskFilterProperties { label: string; type: string; value: any; key: string; + rangeKeys?: RangeKeys; options: FilterOptions[]; + dateFilterOptions?: DateCloudFilterType[]; constructor(obj?: any) { if (obj) { @@ -117,7 +130,9 @@ export class TaskFilterProperties { this.type = obj.type || null; this.value = obj.value || ''; this.key = obj.key || null; + this.rangeKeys = obj.rangeKeys || null; this.options = obj.options || null; + this.dateFilterOptions = obj.dateFilterOptions || null; } } } diff --git a/lib/process-services-cloud/src/lib/task/task-filters/task-filters-cloud.module.ts b/lib/process-services-cloud/src/lib/task/task-filters/task-filters-cloud.module.ts index db7841be7f..0e2d07313e 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/task-filters-cloud.module.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/task-filters-cloud.module.ts @@ -27,6 +27,7 @@ import { EditTaskFilterCloudComponent } from './components/edit-task-filter-clou import { TaskFilterDialogCloudComponent } from './components/task-filter-dialog-cloud.component'; import { AppListCloudModule } from './../../app/app-list-cloud.module'; import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core'; +import { ProcessCommonModule } from '../../common/process-common.module'; @NgModule({ imports: [ @@ -37,7 +38,8 @@ import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core'; FlexLayoutModule, MaterialModule, AppListCloudModule, - CoreModule + CoreModule, + ProcessCommonModule ], declarations: [TaskFiltersCloudComponent, EditTaskFilterCloudComponent, TaskFilterDialogCloudComponent], exports: [TaskFiltersCloudComponent, EditTaskFilterCloudComponent], diff --git a/lib/process-services-cloud/src/lib/task/task-list/components/task-list-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-list/components/task-list-cloud.component.ts index 27802eb186..81b0f738dc 100644 --- a/lib/process-services-cloud/src/lib/task/task-list/components/task-list-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-list/components/task-list-cloud.component.ts @@ -70,6 +70,14 @@ export class TaskListCloudComponent extends DataTableSchema implements OnChanges @Input() lastModifiedTo: string = ''; + /** Filter the tasks. Display only tasks with dueDate greater or equal than the supplied date. */ + @Input() + dueDateFrom: string = ''; + + /** Filter the tasks. Display only tasks with dueDate less or equal to the supplied date. */ + @Input() + dueDateTo: string = ''; + /** Filter the tasks. Display only tasks with id equal to the supplied value. */ @Input() id: string = ''; @@ -344,6 +352,8 @@ export class TaskListCloudComponent extends DataTableSchema implements OnChanges priority: this.priority, lastModifiedFrom: this.lastModifiedFrom, lastModifiedTo: this.lastModifiedTo, + dueDateFrom: this.dueDateFrom, + dueDateTo: this.dueDateTo, status: this.status, dueDate: this.dueDate, createdDate: this.createdDate, diff --git a/lib/process-services-cloud/src/lib/task/task-list/models/filter-cloud-model.ts b/lib/process-services-cloud/src/lib/task/task-list/models/filter-cloud-model.ts index 0ed6adaef8..6484259266 100644 --- a/lib/process-services-cloud/src/lib/task/task-list/models/filter-cloud-model.ts +++ b/lib/process-services-cloud/src/lib/task/task-list/models/filter-cloud-model.ts @@ -27,6 +27,8 @@ export class TaskQueryCloudRequestModel { dueDate?: null; lastModifiedFrom?: null; lastModifiedTo?: null; + dueDateFrom?: null; + dueDateTo?: null; id?: string; name?: string; owner?: string; @@ -51,6 +53,8 @@ export class TaskQueryCloudRequestModel { this.dueDate = obj.dueDate; this.lastModifiedFrom = obj.lastModifiedFrom; this.lastModifiedTo = obj.lastModifiedTo; + this.dueDateFrom = obj.dueDateFrom; + this.dueDateTo = obj.dueDateTo; this.id = obj.id; this.name = obj.name; this.owner = obj.owner;