From c7d769510dfe88e4b41964c295a9de4bc7fbe0c7 Mon Sep 17 00:00:00 2001 From: Tomasz Gnyp <49343696+tomgny@users.noreply.github.com> Date: Fri, 26 Aug 2022 13:53:06 +0200 Subject: [PATCH] [AAE-9186] Filter tasks by assignee (#7784) * [AAE-9186] Filter tasks by assignee * add status filter enum * remove useless case * remove useless unit test * improve task assignment filter unit tests * remove useless imports * rebase * fix lint * run the copydist only for affected * Build always cli and testing to use local * Add back test and cli Co-authored-by: Maurizio Vitale --- angular.json | 32 +- .../src/lib/i18n/en.json | 4 +- ...base-edit-task-filter-cloud.component.html | 13 +- .../base-edit-task-filter-cloud.component.ts | 45 ++- .../edit-task-filter-cloud.component.spec.ts | 334 +++++++----------- .../edit-task-filter-cloud.component.ts | 22 +- .../task-assignment-filter.component.html | 33 +- .../task-assignment-filter.component.scss | 4 +- .../task-assignment-filter.component.spec.ts | 193 ++++++++-- .../task-assignment-filter.component.ts | 108 ++++-- .../mock/edit-task-filter-cloud.mock.ts | 86 +++++ .../mock/task-filters-cloud.mock.ts | 13 +- .../task-filters/models/filter-cloud.model.ts | 17 +- scripts/build/build-all-lib.sh | 2 +- scripts/build/build-cli.sh | 6 +- scripts/build/build-core.sh | 3 +- scripts/build/build-testing.sh | 5 +- 17 files changed, 598 insertions(+), 322 deletions(-) create mode 100644 lib/process-services-cloud/src/lib/task/task-filters/mock/edit-task-filter-cloud.mock.ts diff --git a/angular.json b/angular.json index d61cd7da1a1..e018b6a6094 100644 --- a/angular.json +++ b/angular.json @@ -306,7 +306,7 @@ "tsConfig": "lib/core/tsconfig.lib.json", "project": "lib/core/ng-package.json" }, - "dependsOn": ["license", "^build"], + "dependsOn": ["^build", "license"], "configurations": { "production": { "project": "lib/core/ng-package.json", @@ -412,6 +412,16 @@ } ] } + }, + "pretheme": { + "executor": "nx:run-commands", + "options": { + "commands": [ + { + "command": "$(npm bin)/webpack -- --config ./lib/config/webpack.style.js --progress --profile --bail && rm ./dist/libs/core/lib/prebuilt-themes/*.js" + } + ] + } } } }, @@ -833,6 +843,16 @@ "lib/testing/**/*.html" ] } + }, + "copydist": { + "executor": "nx:run-commands", + "options": { + "commands": [ + { + "command": "rm -rf ./node_modules/@alfresco/adf-testing/ && mkdir -p ./node_modules/@alfresco/adf-testing/ && cp -R ./dist/libs/testing/* ./node_modules/@alfresco/adf-testing/" + } + ] + } } } }, @@ -863,6 +883,16 @@ "lib/cli/**/*.html" ] } + }, + "copydist": { + "executor": "nx:run-commands", + "options": { + "commands": [ + { + "command": "cp -R ./lib/cli/dist dist/libs/cli/ && rm -rf ./node_modules/@alfresco/adf-cli/ && mkdir -p ./node_modules/@alfresco/adf-cli/ && cp -R ./dist/libs/cli/* ./node_modules/@alfresco/adf-cli/" + } + ] + } } } }, diff --git a/lib/process-services-cloud/src/lib/i18n/en.json b/lib/process-services-cloud/src/lib/i18n/en.json index a2bf4703ced..4bb1dff9340 100644 --- a/lib/process-services-cloud/src/lib/i18n/en.json +++ b/lib/process-services-cloud/src/lib/i18n/en.json @@ -381,9 +381,11 @@ "ADF_CLOUD_FORM_COMPONENT": { "RETRIEVE_METADATA": "Autofill Form" }, - "ADF_CLOUD_TASK_ASSIGNEMNT_FILTER": { + "ADF_CLOUD_TASK_ASSIGNMENT_FILTER": { + "ASSIGNED_TO": "Assigned to", "ASSIGNED_TO_ME": "Assigned to me", "UNASSIGNED": "Unassigned", + "NONE": "None", "LIST_OF_CANDIDATE_GROUPS": "List of candidate groups", "ASSIGNEE": "Assignee", "ASSIGNMENT_TYPE": "Assignment type" diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/base-edit-task-filter-cloud.component.html b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/base-edit-task-filter-cloud.component.html index e487b554ad5..9a990dc473d 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/base-edit-task-filter-cloud.component.html +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/base-edit-task-filter-cloud.component.html @@ -28,7 +28,7 @@
-
+
+ [attr.data-automation-id]="'adf-cloud-edit-task-property-' + taskFilterProperty.key" + (selectionChange)="onStatusChange($event)"> @@ -109,9 +110,13 @@ + [status]="selectedStatus" + [appName]="appName" + (assignedUsersChange)="onAssignedUsersChange($event)" + (assignedGroupsChange)="onAssignedGroupsChange($event)" + (assignmentTypeChange)="onAssignmentTypeChange($event)"> +
diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/base-edit-task-filter-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/base-edit-task-filter-cloud.component.ts index d73fc6cfcc7..c232d89b5ff 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/base-edit-task-filter-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/base-edit-task-filter-cloud.component.ts @@ -16,7 +16,7 @@ */ import { OnChanges, SimpleChanges, OnInit, OnDestroy, Directive, Input, Output, EventEmitter } from '@angular/core'; -import { FilterOptions, TaskFilterAction, TaskFilterProperties } from '../../models/filter-cloud.model'; +import { AssignmentType, FilterOptions, TaskFilterAction, TaskFilterProperties, TaskStatusFilter } from '../../models/filter-cloud.model'; import { TaskCloudService } from './../../../services/task-cloud.service'; import { AppsProcessCloudService } from './../../../../app/services/apps-process-cloud.service'; import { DateCloudFilterType, DateRangeFilter } from '../../../../models/date-cloud-filter.model'; @@ -30,6 +30,7 @@ import { TaskFilterDialogCloudComponent } from '../task-filter-dialog/task-filte import { MatDialog } from '@angular/material/dialog'; import { IdentityUserModel } from '../../../../people/models/identity-user.model'; import { IdentityGroupModel } from '../../../../group/models/identity-group.model'; +import { MatSelectChange } from '@angular/material/select'; /* eslint-disable @typescript-eslint/naming-convention */ @@ -106,6 +107,7 @@ export abstract class BaseEditTaskFilterCloudComponent implements OnInit, OnC taskFilterProperties: TaskFilterProperties[] = []; taskFilterActions: TaskFilterAction[] = []; toggleFilterActions: boolean = false; + selectedStatus: TaskStatusFilter; sortDirections: DropdownOption[] = [ { value: 'ASC', label: 'ADF_CLOUD_TASK_FILTERS.DIRECTION.ASCENDING' }, { value: 'DESC', label: 'ADF_CLOUD_TASK_FILTERS.DIRECTION.DESCENDING' } @@ -305,16 +307,49 @@ export abstract class BaseEditTaskFilterCloudComponent implements OnInit, OnC this.getPropertyController(userProperty).setValue(selectedUsers); } - onAssignedChange(assignedValue: IdentityUserModel) { - this.editTaskFilterForm.get('candidateGroups').setValue([]); - this.editTaskFilterForm.get('assignee').setValue(assignedValue?.username); + onAssignedUsersChange(assignedUsers: IdentityUserModel[]) { + this.editTaskFilterForm.get('candidateGroups').setValue(undefined); + this.editTaskFilterForm.get('assignedUsers').setValue(assignedUsers); } onAssignedGroupsChange(groups: IdentityGroupModel[]) { - this.editTaskFilterForm.get('assignee').setValue(null); + this.editTaskFilterForm.get('assignedUsers').setValue(undefined); this.editTaskFilterForm.get('candidateGroups').setValue(groups); } + onAssignmentTypeChange(assignmentType: AssignmentType) { + switch (assignmentType) { + case AssignmentType.UNASSIGNED: + this.editTaskFilterForm.get('status').setValue(TaskStatusFilter.CREATED); + this.resetAssignmentTypeValues(); + break; + case AssignmentType.NONE: + this.editTaskFilterForm.get('status').setValue(TaskStatusFilter.ALL); + this.resetAssignmentTypeValues(); + break; + case AssignmentType.ASSIGNED_TO: + case AssignmentType.CANDIDATE_GROUPS: + this.editTaskFilterForm.get('status').setValue(TaskStatusFilter.ASSIGNED); + this.resetAssignmentTypeValues(); + break; + default: + this.editTaskFilterForm.get('status').setValue(TaskStatusFilter.ASSIGNED); + } + } + + onStatusChange(status: MatSelectChange) { + if (status.value === TaskStatusFilter.CREATED) { + this.resetAssignmentTypeValues(); + } + + this.selectedStatus = status.value; + } + + private resetAssignmentTypeValues() { + this.editTaskFilterForm.get('assignedUsers').setValue(undefined); + this.editTaskFilterForm.get('candidateGroups').setValue(undefined); + } + hasError(property: TaskFilterProperties): boolean { const controller = this.getPropertyController(property); return controller.errors && controller.errors.invalid; diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-task-filter-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-task-filter-cloud.component.spec.ts index 38da69682a2..bd78c1ab625 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-task-filter-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-task-filter-cloud.component.spec.ts @@ -16,7 +16,6 @@ */ import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing'; -import { SimpleChange } from '@angular/core'; import { By } from '@angular/platform-browser'; import { AlfrescoApiService, setupTestBed } from '@alfresco/adf-core'; @@ -37,11 +36,22 @@ import { AbstractControl } from '@angular/forms'; import moment from 'moment'; import { TranslateModule } from '@ngx-translate/core'; import { DateCloudFilterType } from '../../../../models/date-cloud-filter.model'; -import { TaskFilterCloudModel } from '../../models/filter-cloud.model'; +import { AssignmentType, TaskFilterCloudModel, TaskStatusFilter } from '../../models/filter-cloud.model'; import { PeopleCloudModule } from '../../../../people/people-cloud.module'; import { ProcessDefinitionCloud } from '../../../../models/process-definition-cloud.model'; import { MatIconTestingModule } from '@angular/material/icon/testing'; -import { IdentityUserModel } from '../../../../people/models/identity-user.model'; +import { + mockAlfrescoApi, + mockCompletedDateFilter, + mockCreatedDateFilter, + mockDateFilterFromTo, + mockDateFilterStartEnd, + mockDefaultTaskFilter, + mockDueDateFilter, + mockTaskFilterIdChange +} from '../../mock/edit-task-filter-cloud.mock'; +import { mockFoodUsers } from '../../../../people/mock/people-cloud.mock'; +import { mockFoodGroups } from '../../../../group/mock/group-cloud.mock'; describe('EditTaskFilterCloudComponent', () => { let component: EditTaskFilterCloudComponent; @@ -54,14 +64,6 @@ describe('EditTaskFilterCloudComponent', () => { let getRunningApplicationsSpy: jasmine.Spy; let taskService: TaskCloudService; - const mock: any = { - oauth2Auth: { - callCustomApi: () => Promise.resolve(fakeApplicationInstance) - }, - isEcmLoggedIn: () => false, - reply: jasmine.createSpy('reply') - }; - setupTestBed({ imports: [ TranslateModule.forRoot(), @@ -91,7 +93,7 @@ describe('EditTaskFilterCloudComponent', () => { name: 'fake-name' }) } as any); - spyOn(alfrescoApiService, 'getInstance').and.returnValue(mock); + spyOn(alfrescoApiService, 'getInstance').and.returnValue(mockAlfrescoApi); getTaskFilterSpy = spyOn(service, 'getTaskFilterById').and.returnValue(of(fakeFilter)); getRunningApplicationsSpy = spyOn(appsService, 'getDeployedApplicationsByStatus').and.returnValue(of(fakeApplicationInstance)); fixture.detectChanges(); @@ -100,14 +102,13 @@ describe('EditTaskFilterCloudComponent', () => { afterEach(() => fixture.destroy()); it('should fetch task filter by taskId', () => { - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); fixture.whenStable().then(() => { expect(getTaskFilterSpy).toHaveBeenCalled(); expect(component.taskFilter.name).toEqual('FakeInvolvedTasks'); expect(component.taskFilter.icon).toEqual('adjust'); - expect(component.taskFilter.status).toEqual('CREATED'); + expect(component.taskFilter.status).toEqual(TaskStatusFilter.CREATED); expect(component.taskFilter.order).toEqual('ASC'); expect(component.taskFilter.sort).toEqual('id'); }); @@ -118,8 +119,7 @@ describe('EditTaskFilterCloudComponent', () => { fixture.detectChanges(); component.filterProperties = ['processDefinitionName']; fixture.detectChanges(); - const taskFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); const controller = component.editTaskFilterForm.get('processDefinitionName'); @@ -131,8 +131,7 @@ describe('EditTaskFilterCloudComponent', () => { }); it('should display filter name as title', async () => { - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); await fixture.whenStable(); @@ -144,9 +143,8 @@ describe('EditTaskFilterCloudComponent', () => { }); it('should not display filter name if showFilterName is false', async () => { - const taskFilterIdChange = new SimpleChange(null, 'mock-task-filter-id', true); component.showTaskFilterName = false; - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); await fixture.whenStable(); @@ -156,8 +154,7 @@ describe('EditTaskFilterCloudComponent', () => { }); it('should not display mat-spinner if isloading set to false', async () => { - const taskFilterIdChange = new SimpleChange(null, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); await fixture.whenStable(); @@ -173,8 +170,7 @@ describe('EditTaskFilterCloudComponent', () => { it('should display mat-spinner if isloading set to true', async () => { component.isLoading = true; - const taskFilterIdChange = new SimpleChange(null, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); await fixture.whenStable(); @@ -186,8 +182,7 @@ describe('EditTaskFilterCloudComponent', () => { describe('EditTaskFilter form', () => { beforeEach(() => { - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); }); @@ -201,7 +196,7 @@ describe('EditTaskFilterCloudComponent', () => { const assigneeController = component.editTaskFilterForm.get('assignee'); expect(component.editTaskFilterForm).toBeDefined(); expect(assigneeController).toBeDefined(); - expect(stateController.value).toBe('CREATED'); + expect(stateController.value).toBe(TaskStatusFilter.CREATED); expect(sortController.value).toBe('id'); expect(orderController.value).toBe('ASC'); expect(assigneeController.value).toBe('fake-involved'); @@ -209,18 +204,9 @@ describe('EditTaskFilterCloudComponent', () => { describe('Save & Delete buttons', () => { it('should disable save and delete button for default task filters', async () => { - getTaskFilterSpy.and.returnValue(of({ - name: 'ADF_CLOUD_TASK_FILTERS.MY_TASKS', - id: 'filter-id', - key: 'all-fake-task', - icon: 'adjust', - sort: 'startDate', - status: 'ALL', - order: 'DESC' - })); - - const taskFilterIdChange = new SimpleChange(null, 'filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + getTaskFilterSpy.and.returnValue(of(mockDefaultTaskFilter)); + + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); component.toggleFilterActions = true; @@ -237,8 +223,7 @@ describe('EditTaskFilterCloudComponent', () => { }); it('should enable delete button for custom task filters', async () => { - const taskFilterIdChange = new SimpleChange(null, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); component.toggleFilterActions = true; @@ -255,8 +240,7 @@ describe('EditTaskFilterCloudComponent', () => { }); it('should enable save button if the filter is changed for custom task filters', (done) => { - const taskFilterIdChange = new SimpleChange(null, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); component.toggleFilterActions = true; @@ -296,18 +280,8 @@ describe('EditTaskFilterCloudComponent', () => { describe('SaveAs button', () => { it('should disable saveAs button if the process filter is not changed for default filter', async () => { - getTaskFilterSpy.and.returnValue(of({ - name: 'ADF_CLOUD_TASK_FILTERS.MY_TASKS', - id: 'filter-id', - key: 'all-fake-task', - icon: 'adjust', - sort: 'startDate', - status: 'ALL', - order: 'DESC' - })); - - const taskFilterIdChange = new SimpleChange(null, 'filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + getTaskFilterSpy.and.returnValue(of(mockDefaultTaskFilter)); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); component.toggleFilterActions = true; @@ -334,18 +308,9 @@ describe('EditTaskFilterCloudComponent', () => { }); it('should enable saveAs button if the filter values are changed for default filter', (done) => { - getTaskFilterSpy.and.returnValue(of({ - name: 'ADF_CLOUD_TASK_FILTERS.MY_TASKS', - id: 'filter-id', - key: 'all-fake-task', - icon: 'adjust', - sort: 'startDate', - status: 'ALL', - order: 'DESC' - })); - - const taskFilterIdChange = new SimpleChange(null, 'filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + getTaskFilterSpy.and.returnValue(of(mockDefaultTaskFilter)); + + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); component.toggleFilterActions = true; @@ -467,11 +432,10 @@ describe('EditTaskFilterCloudComponent', () => { }); it('should able to build a editTaskFilter form with default properties if input is empty', async () => { - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); component.filterProperties = []; fixture.detectChanges(); - const stateController = component.editTaskFilterForm.get('status'); + const statusController = component.editTaskFilterForm.get('status'); const sortController = component.editTaskFilterForm.get('sort'); const orderController = component.editTaskFilterForm.get('order'); @@ -479,7 +443,7 @@ describe('EditTaskFilterCloudComponent', () => { expect(component.taskFilterProperties.length).toBe(4); expect(component.editTaskFilterForm).toBeDefined(); - expect(stateController.value).toBe('CREATED'); + expect(statusController.value).toBe(TaskStatusFilter.CREATED); expect(sortController.value).toBe('id'); expect(orderController.value).toBe('ASC'); }); @@ -487,8 +451,7 @@ describe('EditTaskFilterCloudComponent', () => { it('should able to fetch running applications when appName property defined in the input', async () => { component.filterProperties = ['appName', 'processInstanceId', 'priority']; fixture.detectChanges(); - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); const appController = component.editTaskFilterForm.get('appName'); fixture.detectChanges(); @@ -502,8 +465,7 @@ describe('EditTaskFilterCloudComponent', () => { it('should fetch data in completedBy filter', async () => { component.filterProperties = ['appName', 'processInstanceId', 'priority', 'completedBy']; fixture.detectChanges(); - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); const appController = component.editTaskFilterForm.get('completedBy'); fixture.detectChanges(); @@ -519,8 +481,7 @@ describe('EditTaskFilterCloudComponent', () => { it('should show completedBy filter', async () => { component.filterProperties = ['appName', 'processInstanceId', 'priority', 'completedBy']; fixture.detectChanges(); - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); await fixture.whenStable(); @@ -532,22 +493,13 @@ describe('EditTaskFilterCloudComponent', () => { it('should update form on completed by user is updated', (done) => { component.appName = 'fake'; component.filterProperties = ['appName', 'processInstanceId', 'priority', 'completedBy']; - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); - const mockUser: IdentityUserModel[] = [{ - id: 'id', - username: 'test', - firstName: 'first-name', - lastName: 'last-name', - email: 'email@fake.com' - }]; - const startedDateTypeControl: AbstractControl = component.editTaskFilterForm.get('completedBy'); startedDateTypeControl.setValue('hruser'); - component.onChangedUser(mockUser, { + component.onChangedUser(mockFoodUsers, { key: 'completedBy', label: '', type: 'people', @@ -557,7 +509,7 @@ describe('EditTaskFilterCloudComponent', () => { fixture.detectChanges(); component.filterChange.subscribe(() => { - expect(component.changedTaskFilter.completedBy).toEqual(mockUser[0]); + expect(component.changedTaskFilter.completedBy).toEqual(mockFoodUsers[0]); done(); }); component.onFilterChange(); @@ -566,20 +518,15 @@ describe('EditTaskFilterCloudComponent', () => { 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 }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); const startedDateTypeControl: AbstractControl = component.editTaskFilterForm.get('dueDateType'); startedDateTypeControl.setValue(DateCloudFilterType.TODAY); - const dateFilter = { - startFrom: moment().startOf('day').toISOString(true), - startTo: moment().endOf('day').toISOString(true) - }; component.filterChange.subscribe(() => { - expect(component.changedTaskFilter.dueDateFrom).toEqual(dateFilter.startFrom); - expect(component.changedTaskFilter.dueDateTo).toEqual(dateFilter.startTo); + expect(component.changedTaskFilter.dueDateFrom).toEqual(mockDateFilterFromTo.startFrom); + expect(component.changedTaskFilter.dueDateTo).toEqual(mockDateFilterFromTo.startTo); done(); }); component.onFilterChange(); @@ -588,8 +535,7 @@ describe('EditTaskFilterCloudComponent', () => { it('should have correct options on dueDate filters', () => { component.appName = 'fake'; component.filterProperties = ['appName', 'processInstanceId', 'priority', 'dueDateRange']; - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); const stateElement = fixture.debugElement.nativeElement.querySelector('[data-automation-id="adf-cloud-edit-process-property-dueDateRange"] .mat-select-trigger'); @@ -607,34 +553,18 @@ describe('EditTaskFilterCloudComponent', () => { 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 }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); - const dateFilter = { - startDate: moment().startOf('day').toISOString(true), - endDate: moment().endOf('day').toISOString(true) - }; - 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' - } - }); + component.onDateRangeFilterChanged(mockDateFilterStartEnd, mockDueDateFilter); fixture.detectChanges(); component.filterChange.subscribe(() => { - expect(component.changedTaskFilter.dueDateFrom).toEqual(dateFilter.startDate); - expect(component.changedTaskFilter.dueDateTo).toEqual(dateFilter.endDate); + expect(component.changedTaskFilter.dueDateFrom).toEqual(mockDateFilterStartEnd.startDate); + expect(component.changedTaskFilter.dueDateTo).toEqual(mockDateFilterStartEnd.endDate); expect(component.changedTaskFilter.dueDateType).toEqual(DateCloudFilterType.RANGE); done(); }); @@ -644,20 +574,15 @@ describe('EditTaskFilterCloudComponent', () => { it('should set the correct completed 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 }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); const startedDateTypeControl: AbstractControl = component.editTaskFilterForm.get('completedDateType'); startedDateTypeControl.setValue(DateCloudFilterType.TODAY); - const dateFilter = { - startFrom: moment().startOf('day').toISOString(true), - startTo: moment().endOf('day').toISOString(true) - }; component.filterChange.subscribe(() => { - expect(component.changedTaskFilter.completedFrom).toEqual(dateFilter.startFrom); - expect(component.changedTaskFilter.completedTo).toEqual(dateFilter.startTo); + expect(component.changedTaskFilter.completedFrom).toEqual(mockDateFilterFromTo.startFrom); + expect(component.changedTaskFilter.completedTo).toEqual(mockDateFilterFromTo.startTo); done(); }); component.onFilterChange(); @@ -666,34 +591,18 @@ describe('EditTaskFilterCloudComponent', () => { it('should update form on date range when completed 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 }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); - const dateFilter = { - startDate: moment().startOf('day').toISOString(true), - endDate: moment().endOf('day').toISOString(true) - }; - const startedDateTypeControl: AbstractControl = component.editTaskFilterForm.get('completedDateType'); startedDateTypeControl.setValue(DateCloudFilterType.RANGE); - component.onDateRangeFilterChanged(dateFilter, { - key: 'completedDateType', - label: '', - type: 'date-range', - value: '', - attributes: { - dateType: 'completedDateType', - from: '_completedFrom', - to: '_completedTo' - } - }); + component.onDateRangeFilterChanged(mockDateFilterStartEnd, mockCompletedDateFilter); fixture.detectChanges(); component.filterChange.subscribe(() => { - expect(component.changedTaskFilter.completedFrom).toEqual(dateFilter.startDate); - expect(component.changedTaskFilter.completedTo).toEqual(dateFilter.endDate); + expect(component.changedTaskFilter.completedFrom).toEqual(mockDateFilterStartEnd.startDate); + expect(component.changedTaskFilter.completedTo).toEqual(mockDateFilterStartEnd.endDate); done(); }); component.onFilterChange(); @@ -702,20 +611,15 @@ describe('EditTaskFilterCloudComponent', () => { it('should set the correct created date range when date range option is changed', (done) => { component.appName = 'fake'; component.filterProperties = ['appName', 'processInstanceId', 'priority', 'createdDateRange']; - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); const startedDateTypeControl: AbstractControl = component.editTaskFilterForm.get('createdDateType'); startedDateTypeControl.setValue(DateCloudFilterType.TODAY); - const dateFilter = { - startDate: moment().startOf('day').toISOString(true), - endDate: moment().endOf('day').toISOString(true) - }; component.filterChange.subscribe(() => { - expect(component.changedTaskFilter.createdFrom).toEqual(dateFilter.startDate); - expect(component.changedTaskFilter.createdTo).toEqual(dateFilter.endDate); + expect(component.changedTaskFilter.createdFrom).toEqual(mockDateFilterStartEnd.startDate); + expect(component.changedTaskFilter.createdTo).toEqual(mockDateFilterStartEnd.endDate); done(); }); @@ -725,23 +629,21 @@ describe('EditTaskFilterCloudComponent', () => { it('should show the task assignment filter', () => { component.appName = 'fake'; component.filterProperties = ['assignment']; - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); const assignmentComponent = fixture.debugElement.nativeElement.querySelector('adf-cloud-task-assignment-filter'); expect(assignmentComponent).toBeTruthy(); }); it('should filter by user assignment', (done) => { - const identityUserMock = { firstName: 'fake-identity-first-name', username: 'username', lastName: 'fake-identity-last-name', email: 'fakeIdentity@email.com' }; component.appName = 'fake'; component.filterProperties = ['assignment']; - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); - component.onAssignedChange(identityUserMock); + component.ngOnChanges({ id: mockTaskFilterIdChange }); + component.onAssignedUsersChange(mockFoodUsers); component.filterChange.subscribe(() => { - expect(component.changedTaskFilter.assignee).toEqual(identityUserMock.username); + expect(component.changedTaskFilter.assignedUsers).toEqual(mockFoodUsers); + expect(component.changedTaskFilter.candidateGroups).toBeNull(); done(); }); component.onFilterChange(); @@ -750,34 +652,18 @@ describe('EditTaskFilterCloudComponent', () => { it('should update form on date range when createdDate value is updated', (done) => { component.appName = 'fake'; component.filterProperties = ['appName', 'processInstanceId', 'priority', 'createdDateRange']; - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); - const dateFilter = { - startDate: moment().startOf('day').toISOString(true), - endDate: moment().endOf('day').toISOString(true) - }; - const startedDateTypeControl: AbstractControl = component.editTaskFilterForm.get('createdDateType'); startedDateTypeControl.setValue(DateCloudFilterType.RANGE); - component.onDateRangeFilterChanged(dateFilter, { - key: 'createdDateType', - label: '', - type: 'date-range', - value: '', - attributes: { - dateType: 'createdDateType', - from: '_createdFrom', - to: '_createdTo' - } - }); + component.onDateRangeFilterChanged(mockDateFilterStartEnd, mockCreatedDateFilter); fixture.detectChanges(); component.filterChange.subscribe(() => { - expect(component.changedTaskFilter.createdFrom).toEqual(dateFilter.startDate); - expect(component.changedTaskFilter.createdTo).toEqual(dateFilter.endDate); + expect(component.changedTaskFilter.createdFrom).toEqual(mockDateFilterStartEnd.startDate); + expect(component.changedTaskFilter.createdTo).toEqual(mockDateFilterStartEnd.endDate); done(); }); @@ -785,19 +671,60 @@ describe('EditTaskFilterCloudComponent', () => { }); it('should filter by candidateGroups assignment', (done) => { - const identityGroupsMock = [ - { name: 'group1'}, - { name: 'group2'} - ]; component.appName = 'fake'; component.filterProperties = ['assignment']; - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); - component.onAssignedGroupsChange(identityGroupsMock); + component.onAssignedGroupsChange(mockFoodGroups); + + component.filterChange.subscribe(() => { + expect(component.changedTaskFilter.candidateGroups).toEqual(mockFoodGroups); + expect(component.changedTaskFilter.assignedUsers).toBeNull(); + done(); + }); + component.onFilterChange(); + }); + }); + + describe('assignment type change', () => { + + beforeEach(() => { + component.appName = 'fake'; + component.filterProperties = ['assignment', 'status']; + component.ngOnChanges({ id: mockTaskFilterIdChange }); + }); + + it('should UNASSIGNED assignment type set status to CREATED', (done) => { + component.onAssignmentTypeChange(AssignmentType.UNASSIGNED); + + component.filterChange.subscribe(() => { + expect(component.changedTaskFilter.status).toEqual(TaskStatusFilter.CREATED); + expect(component.changedTaskFilter.candidateGroups).toBeNull(); + expect(component.changedTaskFilter.candidateGroups).toBeNull(); + done(); + }); + component.onFilterChange(); + }); + + it('should NONE assignment type set status to ALL', (done) => { + component.onAssignmentTypeChange(AssignmentType.NONE); + + component.filterChange.subscribe(() => { + expect(component.changedTaskFilter.status).toEqual(null); + expect(component.changedTaskFilter.candidateGroups).toBeNull(); + expect(component.changedTaskFilter.candidateGroups).toBeNull(); + done(); + }); + component.onFilterChange(); + }); + + it('should ASSIGNED_TO status set assignment type to ASSIGNED', (done) => { + component.onAssignmentTypeChange(AssignmentType.ASSIGNED_TO); component.filterChange.subscribe(() => { - expect(component.changedTaskFilter.candidateGroups).toEqual(identityGroupsMock); + expect(component.changedTaskFilter.status).toEqual(TaskStatusFilter.ASSIGNED); + expect(component.changedTaskFilter.candidateGroups).toBeNull(); + expect(component.changedTaskFilter.candidateGroups).toBeNull(); done(); }); component.onFilterChange(); @@ -807,8 +734,7 @@ describe('EditTaskFilterCloudComponent', () => { describe('sort properties', () => { it('should display default sort properties', async () => { - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); expansionPanel.click(); @@ -833,9 +759,10 @@ describe('EditTaskFilterCloudComponent', () => { priority: '12' })); fixture.detectChanges(); - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); + const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); expansionPanel.click(); fixture.detectChanges(); @@ -853,8 +780,7 @@ describe('EditTaskFilterCloudComponent', () => { }); it('should display default sort properties if input is empty', async () => { - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); component.sortProperties = []; fixture.detectChanges(); @@ -878,8 +804,7 @@ describe('EditTaskFilterCloudComponent', () => { it('should display default filter actions', async () => { component.toggleFilterActions = true; - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); expansionPanel.click(); @@ -900,9 +825,10 @@ describe('EditTaskFilterCloudComponent', () => { it('should display filter actions when input actions are specified', async () => { component.actions = ['save']; fixture.detectChanges(); - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); + component.toggleFilterActions = true; fixture.detectChanges(); const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); @@ -924,8 +850,7 @@ describe('EditTaskFilterCloudComponent', () => { it('should set the correct lastModifiedTo date', (done) => { component.appName = 'fake'; component.filterProperties = ['appName', 'processInstanceId', 'priority', 'lastModified']; - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); const lastModifiedToControl: AbstractControl = component.editTaskFilterForm.get('lastModifiedTo'); @@ -950,8 +875,7 @@ describe('EditTaskFilterCloudComponent', () => { describe('edit filter actions', () => { beforeEach(() => { - const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); - component.ngOnChanges({ id: taskFilterIdChange }); + component.ngOnChanges({ id: mockTaskFilterIdChange }); fixture.detectChanges(); spyOn(component.action, 'emit').and.callThrough(); }); diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-task-filter-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-task-filter-cloud.component.ts index c19d655a92a..077612ed16a 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-task-filter-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-task-filter-cloud.component.ts @@ -23,7 +23,7 @@ import { takeUntil, map } from 'rxjs/operators'; import { Observable } from 'rxjs'; import moment, { Moment } from 'moment'; -import { TaskFilterCloudModel, TaskFilterProperties, TaskFilterAction } from '../../models/filter-cloud.model'; +import { TaskFilterCloudModel, TaskFilterProperties, TaskFilterAction, TaskStatusFilter } from '../../models/filter-cloud.model'; import { TaskFilterCloudService } from '../../services/task-filter-cloud.service'; import { TranslationService, UserPreferencesService } from '@alfresco/adf-core'; import { AppsProcessCloudService } from '../../../../app/services/apps-process-cloud.service'; @@ -142,19 +142,18 @@ export class EditTaskFilterCloudComponent extends BaseEditTaskFilterCloudCompone private getStatusOptions(): DropdownOption[] { return [ - { value: '', label: 'ADF_CLOUD_TASK_FILTERS.STATUS.ALL' }, - { value: 'CREATED', label: 'ADF_CLOUD_TASK_FILTERS.STATUS.CREATED' }, - { value: 'ASSIGNED', label: 'ADF_CLOUD_TASK_FILTERS.STATUS.ASSIGNED' }, - { value: 'SUSPENDED', label: 'ADF_CLOUD_TASK_FILTERS.STATUS.SUSPENDED' }, - { value: 'CANCELLED', label: 'ADF_CLOUD_TASK_FILTERS.STATUS.CANCELLED' }, - { value: 'COMPLETED', label: 'ADF_CLOUD_TASK_FILTERS.STATUS.COMPLETED' } + { value: TaskStatusFilter.ALL, label: 'ADF_CLOUD_TASK_FILTERS.STATUS.ALL' }, + { value: TaskStatusFilter.CREATED, label: 'ADF_CLOUD_TASK_FILTERS.STATUS.CREATED' }, + { value: TaskStatusFilter.ASSIGNED, label: 'ADF_CLOUD_TASK_FILTERS.STATUS.ASSIGNED' }, + { value: TaskStatusFilter.SUSPENDED, label: 'ADF_CLOUD_TASK_FILTERS.STATUS.SUSPENDED' }, + { value: TaskStatusFilter.CANCELLED, label: 'ADF_CLOUD_TASK_FILTERS.STATUS.CANCELLED' }, + { value: TaskStatusFilter.COMPLETED, label: 'ADF_CLOUD_TASK_FILTERS.STATUS.COMPLETED' } ]; } createTaskFilterProperties(): TaskFilterProperties[] { const statusOptions = this.getStatusOptions(); const sortProperties = this.createSortProperties; - return [ { label: 'ADF_CLOUD_EDIT_TASK_FILTER.LABEL.APP_NAME', @@ -303,11 +302,12 @@ export class EditTaskFilterCloudComponent extends BaseEditTaskFilterCloudCompone label: 'ADF_CLOUD_EDIT_TASK_FILTER.LABEL.ASSIGNMENT', type: 'assignment', key: 'assignment', - attributes: { assignee: 'assignee', candidateGroups: 'candidateGroups'}, + attributes: { assignedUsers: 'assignedUsers', candidateGroups: 'candidateGroups'}, value: { - assignee: this.taskFilter.assignee || null, + assignedUsers: this.taskFilter.assignedUsers || [], candidateGroups: this.taskFilter.candidateGroups || [] - } + }, + selectionMode: 'multiple' } ]; } diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.html b/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.html index 031e5c7efb8..67ee26e820d 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.html +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.html @@ -1,20 +1,35 @@ -
+
- {{ 'ADF_CLOUD_TASK_ASSIGNEMNT_FILTER.ASSIGNED_TO_ME' | translate }} - {{ 'ADF_CLOUD_TASK_ASSIGNEMNT_FILTER.UNASSIGNED' | translate }} - {{ 'ADF_CLOUD_TASK_ASSIGNEMNT_FILTER.LIST_OF_CANDIDATE_GROUPS' | translate }} + [attr.data-automation-id]="'adf-task-assignment-filter-select'" + (selectionChange)="onAssignmentTypeChange($event)"> + + {{ assignmentType.label | translate }} + - + [mode]="taskFilterProperty.selectionMode" + [title]="'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.CANDIDATE_GROUP'" + (changedGroups)="onChangedGroups($event)"> + + + +
diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.scss b/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.scss index dd9ef56c93b..60a39d7795e 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.scss +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.scss @@ -1,5 +1,6 @@ .adf-cloud-assignment-container { - align-items: center; + display: flex; + flex-wrap: wrap; mat-form-field { width: 100%; @@ -11,7 +12,6 @@ } .adf-group-cloud-filter { - margin-left: 15px; flex: 1; width: 100%; } diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.spec.ts index 9f3804c5512..99f4ca785d8 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.spec.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.spec.ts @@ -21,19 +21,32 @@ import { TranslateModule } from '@ngx-translate/core'; import { TaskAssignmentFilterCloudComponent } from './task-assignment-filter.component'; import { GroupCloudModule } from '../../../../group/group-cloud.module'; import { TaskFiltersCloudModule } from '../../task-filters-cloud.module'; -import { AssignmentType } from '../../models/filter-cloud.model'; +import { AssignmentType, TaskStatusFilter } from '../../models/filter-cloud.model'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { IdentityUserService } from '../../../../people/services/identity-user.service'; +import { By } from '@angular/platform-browser'; +import { DebugElement, SimpleChange } from '@angular/core'; +import { mockFoodUsers } from '../../../../people/mock/people-cloud.mock'; +import { mockFoodGroups } from '../../../../group/mock/group-cloud.mock'; -describe('EditTaskFilterCloudComponent', () => { +describe('TaskAssignmentFilterComponent', () => { let component: TaskAssignmentFilterCloudComponent; let fixture: ComponentFixture; let identityUserService: IdentityUserService; - const identityUserMock = { - firstName: 'fake-identity-first-name', - lastName: 'fake-identity-last-name', - email: 'fakeIdentity@email.com' - }; + + function selectAssignmentType(type: AssignmentType) { + const assignmentTypeChangeSpy = spyOn(component.assignmentTypeChange, 'emit'); + + const assignmentTypeSelect: DebugElement = fixture.debugElement.query(By.css(`[data-automation-id="adf-task-assignment-filter-select"]`)); + assignmentTypeSelect.nativeElement.click(); + fixture.detectChanges(); + + const assignmentOption: DebugElement = fixture.debugElement.query(By.css(`[data-automation-id="adf-task-assignment-filter-${type}"]`)); + assignmentOption.nativeElement.click(); + fixture.detectChanges(); + + expect(assignmentTypeChangeSpy).toHaveBeenCalledWith(type); + } setupTestBed({ imports: [ @@ -47,43 +60,147 @@ describe('EditTaskFilterCloudComponent', () => { ] }); - beforeEach(() => { - fixture = TestBed.createComponent(TaskAssignmentFilterCloudComponent); - component = fixture.componentInstance; - identityUserService = TestBed.inject(IdentityUserService); - component.taskFilterProperty = { - key: 'assignment', - label: 'mock-filter', - value: null, - type: 'dateRange', - attributes: null, - options: null - }; - fixture.detectChanges(); - }); + describe('inputs', () => { + beforeEach(() => { + fixture = TestBed.createComponent(TaskAssignmentFilterCloudComponent); + component = fixture.componentInstance; + identityUserService = TestBed.inject(IdentityUserService); + component.taskFilterProperty = { + key: 'assignment', + label: 'mock-filter', + value: {}, + type: 'assignment', + attributes: { assignedUsers: 'assignedUsers', candidateGroups: 'candidateGroups' } + }; + fixture.detectChanges(); + }); - afterEach(() => fixture.destroy()); + afterEach(() => fixture.destroy()); - it('should emit the current user info when assignment is the current user', () => { - spyOn(identityUserService, 'getCurrentUserInfo').and.returnValue(identityUserMock as any); - spyOn(component.assignedChange, 'emit'); - component.onAssignmentTypeChange(AssignmentType.CURRENT_USER); - fixture.detectChanges(); - expect(component.assignedChange.emit).toHaveBeenCalledWith(identityUserMock); + it('should display all available assignment types', () => { + const assignmentTypeSelect: DebugElement = fixture.debugElement.query(By.css(`[data-automation-id="adf-task-assignment-filter-select"]`)); + assignmentTypeSelect.nativeElement.click(); + fixture.detectChanges(); + + const assignmentTypeOptions: DebugElement[] = fixture.debugElement.queryAll(By.css('mat-option')); + + expect(assignmentTypeOptions.length).toEqual(5); + expect(assignmentTypeOptions[0].nativeElement.innerText).toEqual('ADF_CLOUD_TASK_ASSIGNMENT_FILTER.NONE'); + expect(assignmentTypeOptions[1].nativeElement.innerText).toEqual('ADF_CLOUD_TASK_ASSIGNMENT_FILTER.UNASSIGNED'); + expect(assignmentTypeOptions[2].nativeElement.innerText).toEqual('ADF_CLOUD_TASK_ASSIGNMENT_FILTER.ASSIGNED_TO'); + expect(assignmentTypeOptions[3].nativeElement.innerText).toEqual('ADF_CLOUD_TASK_ASSIGNMENT_FILTER.CURRENT_USER'); + expect(assignmentTypeOptions[4].nativeElement.innerText).toEqual('ADF_CLOUD_TASK_ASSIGNMENT_FILTER.CANDIDATE_GROUPS'); + }); + + it('should emit the current user info when assignment is the current user', () => { + spyOn(identityUserService, 'getCurrentUserInfo').and.returnValue(mockFoodUsers[0]); + spyOn(component.assignedUsersChange, 'emit'); + + selectAssignmentType(AssignmentType.CURRENT_USER); + + expect(component.assignedUsersChange.emit).toHaveBeenCalledWith([mockFoodUsers[0]]); + }); + + it('should show the CANDIDATE_GROUPS input', () => { + selectAssignmentType(AssignmentType.CANDIDATE_GROUPS); + + const candidateGroups = fixture.debugElement.query(By.css('[data-automation-id="adf-group-cloud-candidate-groups-filter"]')); + expect(component.candidateGroups.length).toEqual(0); + expect(candidateGroups).toBeTruthy(); + }); + + it('should show the ASSIGNED_TO input', () => { + selectAssignmentType(AssignmentType.ASSIGNED_TO); + + const candidateGroups = fixture.debugElement.query(By.css('[data-automation-id="adf-group-cloud-assigned-to-filter"]')); + expect(component.assignedUsers.length).toEqual(0); + expect(candidateGroups).toBeTruthy(); + }); + + it('should have floating labels when values are present', () => { + const inputLabelsNodes = document.querySelectorAll('mat-form-field'); + + inputLabelsNodes.forEach(labelNode => { + expect(labelNode.getAttribute('ng-reflect-float-label')).toBe('auto'); + }); + }); }); - it('should show the candidate groups', () => { - component.assignmentType = AssignmentType.CANDIDATE_GROUPS; - fixture.detectChanges(); - const candidateGroups = fixture.debugElement.nativeElement.querySelector('.adf-group-cloud-filter'); - expect(candidateGroups).toBeTruthy(); + describe('status input change', () => { + beforeEach(() => { + fixture = TestBed.createComponent(TaskAssignmentFilterCloudComponent); + component = fixture.componentInstance; + }); + + afterEach(() => fixture.destroy()); + + it('should CREATED status set assignment type to UNASSIGNED', () => { + const createdStatusChange = new SimpleChange(null, TaskStatusFilter.CREATED, true); + component.ngOnChanges({status: createdStatusChange}); + + expect(component.assignmentType).toEqual(AssignmentType.UNASSIGNED); + }); + + it('should ASSIGNED status set assignment type to ASSIGNED_TO', () => { + const createdStatusChange = new SimpleChange(null, TaskStatusFilter.ASSIGNED, true); + component.ngOnChanges({status: createdStatusChange}); + + expect(component.assignmentType).toEqual(AssignmentType.ASSIGNED_TO); + }); + + it('should ALL status set assignment type to NONE', () => { + const createdStatusChange = new SimpleChange(null, TaskStatusFilter.ALL, true); + component.ngOnChanges({status: createdStatusChange}); + + expect(component.assignmentType).toEqual(AssignmentType.NONE); + }); }); - it('should have floating labels when values are present', () => { - fixture.detectChanges(); - const inputLabelsNodes = document.querySelectorAll('mat-form-field'); - inputLabelsNodes.forEach(labelNode => { - expect(labelNode.getAttribute('ng-reflect-float-label')).toBe('auto'); + describe('set initial assignment type', () => { + beforeEach(() => { + fixture = TestBed.createComponent(TaskAssignmentFilterCloudComponent); + component = fixture.componentInstance; + }); + + afterEach(() => fixture.destroy()); + + it('should set assignment type to ASSIGNED_TO if initial assignedUsers exists', () => { + component.taskFilterProperty = { + key: 'assignment', + label: 'mock-filter', + value: { assignedUsers: mockFoodUsers }, + type: 'assignment', + attributes: { assignedUsers: 'assignedUsers', candidateGroups: 'candidateGroups'} + }; + fixture.detectChanges(); + + expect(component.assignmentType).toEqual(AssignmentType.ASSIGNED_TO); + }); + + it('should set assignment type to CANDIDATE_GROUPS if initial candidateGroups exists', () => { + component.taskFilterProperty = { + key: 'assignment', + label: 'mock-filter', + value: { candidateGroups: mockFoodGroups }, + type: 'assignment', + attributes: { assignedUsers: 'assignedUsers', candidateGroups: 'candidateGroups'} + }; + fixture.detectChanges(); + + expect(component.assignmentType).toEqual(AssignmentType.CANDIDATE_GROUPS); + }); + + it('should set assignment type to NONE if initial value is empty', () => { + component.taskFilterProperty = { + key: 'assignment', + label: 'mock-filter', + value: {}, + type: 'assignment', + attributes: { assignedUsers: 'assignedUsers', candidateGroups: 'candidateGroups'} + }; + fixture.detectChanges(); + + expect(component.assignmentType).toEqual(AssignmentType.NONE); }); }); }); diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.ts b/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.ts index 51a9867b117..a1015403c00 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/task-assignment-filter/task-assignment-filter.component.ts @@ -15,42 +15,54 @@ * limitations under the License. */ -import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core'; -import { UntypedFormControl } from '@angular/forms'; -import { AssignmentType, TaskFilterProperties } from '../../models/filter-cloud.model'; +import { Component, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges } from '@angular/core'; +import { MatSelectChange } from '@angular/material/select'; +import { AssignmentType, TaskFilterProperties, TaskStatusFilter } from '../../models/filter-cloud.model'; import { IdentityUserModel } from '../../../../people/models/identity-user.model'; import { IdentityUserService } from '../../../../people/services/identity-user.service'; import { IdentityGroupModel } from '../../../../group/models/identity-group.model'; +import { DropdownOption } from '../edit-task-filters/base-edit-task-filter-cloud.component'; +import { FormControl } from '@angular/forms'; @Component({ selector: 'adf-cloud-task-assignment-filter', templateUrl: './task-assignment-filter.component.html', styleUrls: ['./task-assignment-filter.component.scss'] }) -export class TaskAssignmentFilterCloudComponent implements OnInit { +export class TaskAssignmentFilterCloudComponent implements OnInit, OnChanges { @Input() appName: string; @Input() taskFilterProperty: TaskFilterProperties; - @Output() assignedChange = new EventEmitter(); + @Input() status: TaskStatusFilter; - @Output() assignedGroupChange = new EventEmitter(); + @Output() assignedUsersChange = new EventEmitter(); + + @Output() assignedGroupsChange = new EventEmitter(); + + @Output() assignmentTypeChange = new EventEmitter(); assignmentType: AssignmentType; + assignedUsers: IdentityUserModel[] = []; candidateGroups: IdentityGroupModel[] = []; - groupForm = new UntypedFormControl(''); - assignmentTypeList = { - unassigned: AssignmentType.UNASSIGNED, - currentUser: AssignmentType.CURRENT_USER, - candidateGroups: AssignmentType.CANDIDATE_GROUPS - }; + groupForm = new FormControl(''); + assignmentTypeOptions: DropdownOption[]; constructor(private identityUserService: IdentityUserService) {} + ngOnChanges(changes: SimpleChanges): void { + if (changes?.status?.currentValue !== changes?.status?.previousValue) { + this.changeAssignmentTypeByStatus(changes?.status?.currentValue); + } + } + ngOnInit() { + this.assignmentTypeOptions = this.getAssignmentTypeOptions(); + if (this.isFilterPropertyDefined()) { - this.setDefaultAssignedGroups(); + this.setInitialCandidateGroups(); + this.setInitialAssignedUsers(); this.setDefaultAssignmentType(); } } @@ -59,35 +71,73 @@ export class TaskAssignmentFilterCloudComponent implements OnInit { return this.assignmentType === AssignmentType.CANDIDATE_GROUPS; } - onAssignmentTypeChange(type: any) { + isAssignedToType(): boolean { + return this.assignmentType === AssignmentType.ASSIGNED_TO; + } + + onAssignmentTypeChange(assignmentChange: MatSelectChange) { this.candidateGroups = []; - if (type === AssignmentType.CURRENT_USER) { - this.assignedChange.emit(this.identityUserService.getCurrentUserInfo()); - } else if (type === AssignmentType.UNASSIGNED) { - this.assignedChange.emit(null); + this.assignedUsers = []; + + if (assignmentChange.value === AssignmentType.CURRENT_USER) { + this.assignedUsersChange.emit([this.identityUserService.getCurrentUserInfo()]); + } else if (assignmentChange.value === AssignmentType.NONE) { + this.assignedUsersChange.emit([]); } + + this.assignmentType = assignmentChange.value; + this.assignmentTypeChange.emit(this.assignmentType); } onChangedGroups(groups: IdentityGroupModel[]) { - this.assignedGroupChange.emit(groups); + this.assignedGroupsChange.emit(groups); } - private setDefaultAssignmentType() { - const assignmentAttr = this.taskFilterProperty.attributes['assignee']; - const assignee = this.taskFilterProperty.value[assignmentAttr]; + onChangedAssignedUsers(users: IdentityUserModel[]) { + this.assignedUsersChange.emit(users); + } + + private changeAssignmentTypeByStatus(status: TaskStatusFilter) { + switch (status) { + case TaskStatusFilter.CREATED: + this.assignmentType = AssignmentType.UNASSIGNED; + break; + case TaskStatusFilter.ASSIGNED: + this.assignmentType = AssignmentType.ASSIGNED_TO; + break; + default: + this.assignmentType = AssignmentType.NONE; + } + } - if (this.candidateGroups.length > 0) { + private getAssignmentTypeOptions(): DropdownOption[] { + return [ + { value: AssignmentType.NONE, label: `ADF_CLOUD_TASK_ASSIGNMENT_FILTER.${AssignmentType.NONE}` }, + { value: AssignmentType.UNASSIGNED, label: `ADF_CLOUD_TASK_ASSIGNMENT_FILTER.${AssignmentType.UNASSIGNED}` }, + { value: AssignmentType.ASSIGNED_TO, label: `ADF_CLOUD_TASK_ASSIGNMENT_FILTER.${AssignmentType.ASSIGNED_TO}` }, + { value: AssignmentType.CURRENT_USER, label: `ADF_CLOUD_TASK_ASSIGNMENT_FILTER.${AssignmentType.CURRENT_USER}` }, + { value: AssignmentType.CANDIDATE_GROUPS, label: `ADF_CLOUD_TASK_ASSIGNMENT_FILTER.${AssignmentType.CANDIDATE_GROUPS}` } + ]; + } + + private setDefaultAssignmentType() { + if (this.candidateGroups?.length) { this.assignmentType = AssignmentType.CANDIDATE_GROUPS; - } else if (assignee) { - this.assignmentType = AssignmentType.CURRENT_USER; + } else if (this.assignedUsers?.length) { + this.assignmentType = AssignmentType.ASSIGNED_TO; } else { - this.assignmentType = AssignmentType.UNASSIGNED; + this.assignmentType = AssignmentType.NONE; } } - private setDefaultAssignedGroups() { - const assignmentGroupsAttr = this.taskFilterProperty.attributes['candidateGroups']; - this.candidateGroups = this.taskFilterProperty.value[assignmentGroupsAttr]; + private setInitialCandidateGroups() { + const candidateGroupsAttr = this.taskFilterProperty.attributes['candidateGroups']; + this.candidateGroups = this.taskFilterProperty.value[candidateGroupsAttr]; + } + + private setInitialAssignedUsers() { + const assignedUsersAttr = this.taskFilterProperty.attributes['assignedUsers']; + this.assignedUsers = this.taskFilterProperty.value[assignedUsersAttr]; } private isFilterPropertyDefined(): boolean { diff --git a/lib/process-services-cloud/src/lib/task/task-filters/mock/edit-task-filter-cloud.mock.ts b/lib/process-services-cloud/src/lib/task/task-filters/mock/edit-task-filter-cloud.mock.ts new file mode 100644 index 00000000000..f1436ebd696 --- /dev/null +++ b/lib/process-services-cloud/src/lib/task/task-filters/mock/edit-task-filter-cloud.mock.ts @@ -0,0 +1,86 @@ +/*! + * @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 { SimpleChange } from '@angular/core'; +import moment from 'moment'; +import { fakeApplicationInstance } from '../../../app/mock/app-model.mock'; + +export const mockAlfrescoApi: any = { + oauth2Auth: { + callCustomApi: () => Promise.resolve(fakeApplicationInstance) + }, + isEcmLoggedIn: () => false, + reply: jasmine.createSpy('reply') +}; + +export const mockTaskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true); + +export const mockDefaultTaskFilter = { + name: 'ADF_CLOUD_TASK_FILTERS.MY_TASKS', + id: 'filter-id', + key: 'all-fake-task', + icon: 'adjust', + sort: 'startDate', + status: 'ALL', + order: 'DESC' +}; + +export const mockDateFilterFromTo = { + startFrom: moment().startOf('day').toISOString(true), + startTo: moment().endOf('day').toISOString(true) +}; + +export const mockDateFilterStartEnd = { + startDate: moment().startOf('day').toISOString(true), + endDate: moment().endOf('day').toISOString(true) +}; + +export const mockDueDateFilter = { + key: 'dueDateRange', + label: '', + type: 'date-range', + value: '', + attributes: { + dateType: 'dueDateType', + from: '_dueDateFrom', + to: '_dueDateTo' + } +}; + +export const mockCompletedDateFilter = { + key: 'completedDateType', + label: '', + type: 'date-range', + value: '', + attributes: { + dateType: 'completedDateType', + from: '_completedFrom', + to: '_completedTo' + } +}; + +export const mockCreatedDateFilter = { + key: 'createdDateType', + label: '', + type: 'date-range', + value: '', + attributes: { + dateType: 'createdDateType', + from: '_createdFrom', + to: '_createdTo' + } +}; diff --git a/lib/process-services-cloud/src/lib/task/task-filters/mock/task-filters-cloud.mock.ts b/lib/process-services-cloud/src/lib/task/task-filters/mock/task-filters-cloud.mock.ts index 6824aa33c16..e03099d5cd5 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/mock/task-filters-cloud.mock.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/mock/task-filters-cloud.mock.ts @@ -16,7 +16,7 @@ */ import { assignedTaskDetailsCloudMock } from '../../task-header/mocks/task-details-cloud.mock'; -import { TaskFilterCloudModel, ServiceTaskFilterCloudModel } from '../models/filter-cloud.model'; +import { TaskFilterCloudModel, ServiceTaskFilterCloudModel, AssignmentType, TaskStatusFilter } from '../models/filter-cloud.model'; export const fakeGlobalFilter: any[] = [ { @@ -75,10 +75,11 @@ export const fakeFilter = new TaskFilterCloudModel({ name: 'FakeInvolvedTasks', icon: 'adjust', id: 'mock-task-filter-id', - status: 'CREATED', + status: TaskStatusFilter.CREATED, appName: 'mock-app-name', processDefinitionId: 'process-def-id', assignee: 'fake-involved', + assignment: AssignmentType.NONE, order: 'ASC', sort: 'id', completedBy: { @@ -103,7 +104,7 @@ export const fakeAllTaskFilter = new TaskFilterCloudModel({ name: 'AllTasks', icon: 'adjust', id: 'mock-task-filter-id', - status: '', + status: TaskStatusFilter.ALL, appName: 'mock-app-name', processDefinitionId: 'process-def-id', assignee: 'fake-involved', @@ -296,7 +297,7 @@ export const defaultTaskFiltersMock = [ icon: 'adjust', appName: 'fakeAppName', sort: 'startDate', - status: 'CREATED', + status: TaskStatusFilter.CREATED, order: 'DESC' }, { @@ -306,7 +307,7 @@ export const defaultTaskFiltersMock = [ icon: 'adjust', appName: 'fakeAppName', sort: 'startDate', - status: 'ASSIGNED', + status: TaskStatusFilter.ASSIGNED, order: 'DESC' }, { @@ -316,7 +317,7 @@ export const defaultTaskFiltersMock = [ icon: 'adjust', appName: 'fakeAppName', sort: 'startDate', - status: 'COMPLETED', + status: TaskStatusFilter.COMPLETED, order: 'DESC' } ]; 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 684fb77ae20..6e59caf8b3a 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 @@ -32,9 +32,10 @@ export class TaskFilterCloudModel { icon: string; index: number; appName: string; - status: string; + status: TaskStatusFilter; sort: string; assignee: string; + assignedUsers: IdentityUserModel[]; candidateGroups: IdentityGroupModel[]; order: string; owner: string; @@ -77,6 +78,7 @@ export class TaskFilterCloudModel { this.status = obj.status || null; this.sort = obj.sort || null; this.assignee = obj.assignee || null; + this.assignedUsers = obj.assignedUsers || null; this.order = obj.order || null; this.owner = obj.owner || null; this.processDefinitionName = obj.processDefinitionName || null; @@ -234,7 +236,18 @@ export interface FilterOptions { export enum AssignmentType { CURRENT_USER = 'CURRENT_USER', UNASSIGNED = 'UNASSIGNED', - CANDIDATE_GROUPS = 'CANDIDATE_GROUPS' + NONE = 'NONE', + CANDIDATE_GROUPS = 'CANDIDATE_GROUPS', + ASSIGNED_TO = 'ASSIGNED_TO' +} + +export enum TaskStatusFilter { + ALL = '', + CREATED = 'CREATED', + ASSIGNED = 'ASSIGNED', + SUSPENDED = 'SUSPENDED', + CANCELLED = 'CANCELLED', + COMPLETED = 'COMPLETED' } export interface TaskFilterProperties { diff --git a/scripts/build/build-all-lib.sh b/scripts/build/build-all-lib.sh index 4f706ae7d49..a16a8e9d1c9 100755 --- a/scripts/build/build-all-lib.sh +++ b/scripts/build/build-all-lib.sh @@ -8,7 +8,7 @@ echo "====== Run lib =====" if [ "$CI" = "true" ]; then echo "Building libs for production with NX_FLAG $NX_CALCULATION_FLAGS" - NODE_OPTIONS="--max-old-space-size=8192" $(npm bin)/nx affected:build $NX_CALCULATION_FLAGS --prod --exclude=demoshell || exit 1 + NODE_OPTIONS="--max-old-space-size=8192" $(npm bin)/nx affected:build $NX_CALCULATION_FLAGS --prod --exclude="demoshell,cli,testing" || exit 1 else echo "Building libs for development with NX_FLAG $NX_CALCULATION_FLAGS" NODE_OPTIONS="--max-old-space-size=8192" $(npm bin)/nx affected:build $NX_CALCULATION_FLAGS --exclude=demoshell || exit 1 diff --git a/scripts/build/build-cli.sh b/scripts/build/build-cli.sh index 4e2c38ed307..0a2bd01c6e5 100755 --- a/scripts/build/build-cli.sh +++ b/scripts/build/build-cli.sh @@ -11,6 +11,6 @@ cp -R ./lib/cli/dist dist/libs/cli/ cp ./lib/cli/README.md dist/libs/cli/README.md echo "====== Cli Move to node_modules ======" -rm -rf ./node_modules/@alfresco/adf-cli/ && \ -mkdir -p ./node_modules/@alfresco/adf-cli/ && \ -cp -R ./dist/libs/cli/* ./node_modules/@alfresco/adf-cli/ +nx build cli +nx run cli:copydist + diff --git a/scripts/build/build-core.sh b/scripts/build/build-core.sh index cf8b130e2ba..f54f6e8b213 100755 --- a/scripts/build/build-core.sh +++ b/scripts/build/build-core.sh @@ -7,5 +7,4 @@ cd $DIR/../.. echo "====== Core ======" echo "====== Prebuilt Themes =====" -npm run webpack -- --config ./lib/config/webpack.style.js --progress --profile --bail -rm ./dist/libs/core/lib/prebuilt-themes/*.js +nx affected $NX_CALCULATION_FLAGS --target=pretheme diff --git a/scripts/build/build-testing.sh b/scripts/build/build-testing.sh index 1daef1e5337..1203568aa74 100755 --- a/scripts/build/build-testing.sh +++ b/scripts/build/build-testing.sh @@ -7,6 +7,5 @@ cd $DIR/../.. echo "====== Testing ======" echo "====== Move to node_modules ======" -rm -rf ./node_modules/@alfresco/adf-testing/ && \ -mkdir -p ./node_modules/@alfresco/adf-testing/ && \ -cp -R ./dist/libs/testing/* ./node_modules/@alfresco/adf-testing/ +nx build testing +nx run testing:copydist