diff --git a/demo-shell/src/app/components/app-layout/cloud/cloud-layout.component.ts b/demo-shell/src/app/components/app-layout/cloud/cloud-layout.component.ts index 6ecdbd403c..59f0b1bc02 100644 --- a/demo-shell/src/app/components/app-layout/cloud/cloud-layout.component.ts +++ b/demo-shell/src/app/components/app-layout/cloud/cloud-layout.component.ts @@ -46,12 +46,7 @@ export class CloudLayoutComponent implements OnInit { } onProcessFilterSelected(filter) { - const queryParams = { - status: filter.query.state, - filterName: filter.name, - sort: filter.query.sort, - order: filter.query.order - }; - this.router.navigate([`/cloud/${this.applicationName}/processes/`], { queryParams: queryParams }); + const currentFilter = Object.assign({}, filter); + this.router.navigate([`/cloud/${this.applicationName}/processes/`], { queryParams: currentFilter }); } } diff --git a/demo-shell/src/app/components/app-layout/cloud/processes-cloud-demo.component.html b/demo-shell/src/app/components/app-layout/cloud/processes-cloud-demo.component.html index e4dd1a318e..4fa568e229 100644 --- a/demo-shell/src/app/components/app-layout/cloud/processes-cloud-demo.component.html +++ b/demo-shell/src/app/components/app-layout/cloud/processes-cloud-demo.component.html @@ -1,57 +1,15 @@
- - - - - {{filterName | translate}} - - - {{ 'PROCESS_LIST_CLOUD_DEMO.CUSTOMIZE_FILTERS' | translate}} - - -
- - - - ALL - - - RUNNING - - - COMPLETED - - - - - - Select a column - - {{column.label}} - - - - - - Select a direction - - ASC - - - DESC - - - -
- -
-
-
+ + +
diff --git a/demo-shell/src/app/components/app-layout/cloud/processes-cloud-demo.component.ts b/demo-shell/src/app/components/app-layout/cloud/processes-cloud-demo.component.ts index 7169781d8f..2e3f074fb9 100644 --- a/demo-shell/src/app/components/app-layout/cloud/processes-cloud-demo.component.ts +++ b/demo-shell/src/app/components/app-layout/cloud/processes-cloud-demo.component.ts @@ -16,9 +16,15 @@ */ import { Component, ViewChild, OnInit } from '@angular/core'; -import { ProcessListCloudComponent } from '@alfresco/adf-process-services-cloud'; +import { + ProcessListCloudComponent, + ProcessFilterCloudModel, + EditProcessFilterCloudComponent, + ProcessListCloudSortingModel, + ProcessFiltersCloudComponent +} from '@alfresco/adf-process-services-cloud'; + import { ActivatedRoute } from '@angular/router'; -import { FormControl } from '@angular/forms'; import { UserPreferencesService } from '@alfresco/adf-core'; @Component({ @@ -30,27 +36,17 @@ export class ProcessesCloudDemoComponent implements OnInit { @ViewChild('processCloud') processCloud: ProcessListCloudComponent; - sortFormControl: FormControl; - sortDirectionFormControl: FormControl; + @ViewChild('processFiltersCloud') + processFiltersCloud: ProcessFiltersCloudComponent; applicationName: string = ''; - isFilterLoaded: boolean; + isFilterLoaded: boolean; - status: string = ''; - filterName: string; filterId: string = ''; - sort: string = ''; sortArray: any = []; - sortField: string; - sortDirection: string; selectedRow: any; - columns = [ - {key: 'id', label: 'ID'}, - {key: 'name', label: 'NAME'}, - {key: 'status', label: 'STATUS'}, - {key: 'startDate', label: 'START DATE'} - ]; + editedFilter: ProcessFilterCloudModel; constructor(private route: ActivatedRoute, private userPreference: UserPreferencesService) { @@ -62,43 +58,11 @@ export class ProcessesCloudDemoComponent implements OnInit { this.applicationName = params.applicationName; }); - this.sortFormControl = new FormControl(''); - - this.sortFormControl.valueChanges.subscribe( - (sortValue) => { - this.sort = sortValue; - - this.sortArray = [{ - orderBy: this.sort, - direction: this.sortDirection - }]; - } - ); - this.sortDirectionFormControl = new FormControl(''); - - this.sortDirectionFormControl.valueChanges.subscribe( - (sortDirectionValue) => { - this.sortDirection = sortDirectionValue; - - this.sortArray = [{ - orderBy: this.sort, - direction: this.sortDirection - }]; - } - ); - - this.route.queryParams - .subscribe((params) => { - if (params.filterName) { - this.status = params.status ? params.status : ''; - this.sort = params.sort; - this.sortDirection = params.order; - this.filterName = params.filterName; - this.isFilterLoaded = true; - this.sortDirectionFormControl.setValue(this.sortDirection); - this.sortFormControl.setValue(this.sort); - } - }); + this.route.queryParams.subscribe((params) => { + this.isFilterLoaded = true; + this.onFilterChange(params); + this.filterId = params.id; + }); } onChangePageSize(event) { @@ -108,4 +72,33 @@ export class ProcessesCloudDemoComponent implements OnInit { onRowClick($event) { this.selectedRow = $event; } + + onFilterChange(query: any) { + this.editedFilter = Object.assign({}, query); + this.sortArray = [new ProcessListCloudSortingModel({ orderBy: this.editedFilter.sort, direction: this.editedFilter.order })]; + } + + onEditActions(event: any) { + if (event.actionType === EditProcessFilterCloudComponent.ACTION_SAVE) { + this.save(event.id); + } else if (event.actionType === EditProcessFilterCloudComponent.ACTION_SAVE_AS) { + this.saveAs(event.id); + } else if (event.actionType === EditProcessFilterCloudComponent.ACTION_DELETE) { + this.deleteFilter(); + } + } + + saveAs(filterId) { + this.processFiltersCloud.filterParam = {id : filterId}; + this.processFiltersCloud.getFilters(this.applicationName); + } + + save(filterId) { + this.processFiltersCloud.filterParam = {id : filterId}; + this.processFiltersCloud.getFilters(this.applicationName); + } + + deleteFilter() { + this.processFiltersCloud.getFilters(this.applicationName); + } } diff --git a/docs/docassets/images/edit-process-filter-cloud.component.png b/docs/docassets/images/edit-process-filter-cloud.component.png new file mode 100644 index 0000000000..969570e8c6 Binary files /dev/null and b/docs/docassets/images/edit-process-filter-cloud.component.png differ diff --git a/docs/process-services-cloud/edit-process-filter-cloud.component.md b/docs/process-services-cloud/edit-process-filter-cloud.component.md new file mode 100644 index 0000000000..ffcf75e384 --- /dev/null +++ b/docs/process-services-cloud/edit-process-filter-cloud.component.md @@ -0,0 +1,50 @@ +--- +Title: Edit Process Filter Cloud component +Added: v3.0.0 +Status: Active +Last reviewed: 2018-20-11 +--- + +# [Edit Process Filter Cloud component](../../lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/edit-process-filter-cloud.component.ts "Defined in edit-process-filter-cloud.component.ts") + +Shows Process Filter Details. + +## Basic Usage + +```html + + +``` + +## Class members + +### Properties + +| Name | Type | Default value | Description | +| ---- | ---- | ------------- | ----------- | +| appName | `string` | | The name of the application. | +| id | `string` | | Id of the process filter. | + +### Events + +| Name | Type | Description | +| ---- | ---- | ----------- | +| action | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessFilterActionType`](../../lib/process-services-cloud/src/lib/process-cloud/models/process-filter-cloud.model.ts)`>` | Emitted when an filter action occurs i.e Save, SaveAs, Delete. | +| filterChange | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessFilterCloudModel`](../../lib/process-services-cloud/src/lib/process-cloud/models/process-filter-cloud.model.ts)`>` | Emitted when an process instance filter property changes. | + +## Details + +### Editing APS2 process filter + +Use the process filter id property to edit process filter properties: + +```html + + +``` + +![edit-process-filter-cloud](../docassets/images/edit-process-filter-cloud.component.png) diff --git a/docs/process-services-cloud/process-filters-cloud.component.md b/docs/process-services-cloud/process-filters-cloud.component.md index 9d8d05ca18..eee06978ab 100644 --- a/docs/process-services-cloud/process-filters-cloud.component.md +++ b/docs/process-services-cloud/process-filters-cloud.component.md @@ -24,13 +24,32 @@ Lists all available process filters and allows to select a filter. | Name | Type | Default value | Description | | ---- | ---- | ------------- | ----------- | | appName | `string` | | (required) The application name | -| filterParam | [`ProcessFilterParamModel`](../../lib/process-services-cloud/src/lib/process-cloud/models/process-filter-cloud.model.ts) | | (optional) The filter to be selected by default | +| filterParam | `ProcessFilterCloudModel` | | (optional) The filter to be selected by default | | showIcons | `boolean` | false | (optional) The flag hides/shows icon against each filter | ### Events | Name | Type | Description | | ---- | ---- | ----------- | -| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when any error occurs while loading the filters | -| filterClick | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessFilterRepresentationModel`](../../lib/process-services-cloud/src/lib/process-cloud/models/process-filter-cloud.model.ts)`>` | Emitted when a filter is selected/clicked | -| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when filters are loaded successfully | +| filterClick | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessFilterCloudModel`](../../lib/process-services-cloud/src/lib/process-cloud/models/process-filter-cloud.model.ts)`>` | Emitted when a filter is selected/clicked. | +| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when filters are loaded successfully. | +| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when any error occurs while loading the filters. | + +### Details + +The `filterParam` input can be used to select a filter as mentioned below. + +```html + + +``` + +A filter can be selected by using any of the `ProcessFilterCloudModel` property. + +| Name | Type | Description | +| ---- | ---- | ----------- | +| id | string | The id of the filter | +| name | string | The name of the filter | +| key | string | The key of the filter | +| index | string | The zero-based position of the filter in the array | diff --git a/lib/process-services-cloud/src/lib/i18n/en.json b/lib/process-services-cloud/src/lib/i18n/en.json index f999d220c9..249e9bfc32 100644 --- a/lib/process-services-cloud/src/lib/i18n/en.json +++ b/lib/process-services-cloud/src/lib/i18n/en.json @@ -80,5 +80,28 @@ "SAVE": "SAVE", "CANCEL": "CANCEL" } + }, + "ADF_CLOUD_EDIT_PROCESS_FILTER": { + "TITLE": "Customize your filter", + "STATUS": "Select a status", + "ASSIGNMENT": "ASSIGNMENT", + "COLUMN": "Select a column", + "DIRECTION": "Select a direction", + "TOOL_TIP": { + "SAVE": "Save filter", + "SAVE_AS": "Save filter as", + "DELETE": "Delete filter" + }, + "LABEL": { + "STATUS": "Status", + "ASSIGNMENT": "Assignment", + "COLUMN": "Column", + "DIRECTION": "Direction" + }, + "DIALOG": { + "TITLE": "Save filter as", + "SAVE": "SAVE", + "CANCEL": "CANCEL" + } } } diff --git a/lib/process-services-cloud/src/lib/process-cloud/models/process-filter-cloud.model.ts b/lib/process-services-cloud/src/lib/process-cloud/models/process-filter-cloud.model.ts index ebc37e1b73..2e77410b4e 100644 --- a/lib/process-services-cloud/src/lib/process-cloud/models/process-filter-cloud.model.ts +++ b/lib/process-services-cloud/src/lib/process-cloud/models/process-filter-cloud.model.ts @@ -14,31 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export class ProcessQueryModel { - processDefinitionId: string; - appName: string; - state: string; - sort: string; - assignment: string; - order: string; - constructor(obj?: any) { - if (obj) { - this.appName = obj.appName || null; - this.processDefinitionId = obj.processDefinitionId || null; - this.state = obj.state || null; - this.sort = obj.sort || null; - this.assignment = obj.assignment || null; - this.order = obj.order || null; - } - } -} -export class ProcessFilterRepresentationModel { +export class ProcessFilterCloudModel { id: string; name: string; key: string; icon: string; - query: ProcessQueryModel; + index: number; + processDefinitionId: string; + appName: string; + state: string; + sort: string; + order: string; constructor(obj?: any) { if (obj) { @@ -46,26 +33,17 @@ export class ProcessFilterRepresentationModel { this.name = obj.name || null; this.key = obj.key || null; this.icon = obj.icon || null; - this.query = new ProcessQueryModel(obj.query); - } - } - - hasFilter() { - return !!this.query; - } -} - -export class ProcessFilterParamModel { - id: string; - name: string; - key: string; - index: number; - constructor(obj?: any) { - if (obj) { - this.id = obj.id || null; - this.name = obj.name || null; - this.key = obj.key || null; this.index = obj.index || null; + this.appName = obj.appName || null; + this.processDefinitionId = obj.processDefinitionId || null; + this.state = obj.state || null; + this.sort = obj.sort || null; + this.order = obj.order || null; } } } + +export interface ProcessFilterActionType { + actionType: string; + id: string; +} diff --git a/lib/process-services-cloud/src/lib/process-cloud/process-cloud.module.ts b/lib/process-services-cloud/src/lib/process-cloud/process-cloud.module.ts index f5290f353f..529809b395 100644 --- a/lib/process-services-cloud/src/lib/process-cloud/process-cloud.module.ts +++ b/lib/process-services-cloud/src/lib/process-cloud/process-cloud.module.ts @@ -17,14 +17,20 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { FlexLayoutModule } from '@angular/flex-layout'; import { ProcessFiltersCloudComponent } from './process-filters-cloud/process-filters-cloud.component'; import { MaterialModule } from '../material.module'; import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; import { TranslateLoaderService, LogService, StorageService } from '@alfresco/adf-core'; import { ProcessFilterCloudService } from './services/process-filter-cloud.service'; import { HttpClientModule } from '@angular/common/http'; +import { EditProcessFilterCloudComponent } from './process-filters-cloud/edit-process-filter-cloud.component'; +import { ProcessFilterDialogCloudComponent } from './process-filters-cloud/process-filter-dialog-cloud.component'; @NgModule({ imports: [ + FormsModule, + ReactiveFormsModule, HttpClientModule, CommonModule, TranslateModule.forRoot({ @@ -33,11 +39,12 @@ import { HttpClientModule } from '@angular/common/http'; useClass: TranslateLoaderService } }), + FlexLayoutModule, MaterialModule ], - declarations: [ProcessFiltersCloudComponent], - - exports: [ProcessFiltersCloudComponent], + declarations: [ProcessFiltersCloudComponent, EditProcessFilterCloudComponent, ProcessFilterDialogCloudComponent], + exports: [ProcessFiltersCloudComponent, EditProcessFilterCloudComponent, ProcessFilterDialogCloudComponent], + entryComponents: [ProcessFilterDialogCloudComponent], providers: [ProcessFilterCloudService, LogService, StorageService] }) export class ProcessCloudModule { } diff --git a/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/edit-process-filter-cloud.component.html b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/edit-process-filter-cloud.component.html new file mode 100644 index 0000000000..c4e428795e --- /dev/null +++ b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/edit-process-filter-cloud.component.html @@ -0,0 +1,60 @@ + + + + {{processFilter.name | translate}} + + {{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.TITLE' | translate}} + + +
+
+ + + + {{ state.label }} + + + + + + + + + + + + + {{ column.label }} + + + + + + + {{ direction }} + + + +
+ + + +
+
+
+
+
diff --git a/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/edit-process-filter-cloud.component.scss b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/edit-process-filter-cloud.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/edit-process-filter-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/edit-process-filter-cloud.component.spec.ts new file mode 100644 index 0000000000..bb580f45c4 --- /dev/null +++ b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/edit-process-filter-cloud.component.spec.ts @@ -0,0 +1,317 @@ +/*! + * @license + * Copyright 2016 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 { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { SimpleChange } from '@angular/core'; +import { By } from '@angular/platform-browser'; + +import { setupTestBed } from '@alfresco/adf-core'; +import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module'; +import { MatDialog } from '@angular/material'; +import { of } from 'rxjs'; +import { ProcessFilterDialogCloudComponent } from './process-filter-dialog-cloud.component'; +import { EditProcessFilterCloudComponent } from './edit-process-filter-cloud.component'; +import { ProcessCloudModule } from '../process-cloud.module'; +import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model'; +import { ProcessFilterCloudService } from '../services/process-filter-cloud.service'; + +describe('EditProcessFilterCloudComponent', () => { + let component: EditProcessFilterCloudComponent; + let service: ProcessFilterCloudService; + let fixture: ComponentFixture; + let dialog: MatDialog; + + let fakeFilter = new ProcessFilterCloudModel({ + name: 'FakeRunningProcess', + icon: 'adjust', + id: 10, + state: 'RUNNING', + appName: 'app-name', + processDefinitionId: 'process-def-id', + assignment: 'fake-involved', + order: 'ASC', + sort: 'id' + }); + + setupTestBed({ + imports: [ProcessServiceCloudTestingModule, ProcessCloudModule], + providers: [MatDialog] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(EditProcessFilterCloudComponent); + component = fixture.componentInstance; + service = TestBed.get(ProcessFilterCloudService); + dialog = TestBed.get(MatDialog); + spyOn(dialog, 'open').and.returnValue({ afterClosed() { return of({ + action: ProcessFilterDialogCloudComponent.ACTION_SAVE, + icon: 'icon', + name: 'fake-name' + }); }}); + spyOn(service, 'getProcessFilterById').and.returnValue(fakeFilter); + }); + + it('should create EditProcessFilterCloudComponent', () => { + expect(component instanceof EditProcessFilterCloudComponent).toBeTruthy(); + }); + + it('should fetch process instance filter by id', async(() => { + let change = new SimpleChange(undefined, '10', true); + component.ngOnChanges({ 'id': change }); + fixture.detectChanges(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(component.processFilter.name).toEqual('FakeRunningProcess'); + expect(component.processFilter.icon).toEqual('adjust'); + expect(component.processFilter.state).toEqual('RUNNING'); + expect(component.processFilter.order).toEqual('ASC'); + expect(component.processFilter.sort).toEqual('id'); + }); + })); + + it('should display filter name as title', () => { + let change = new SimpleChange(undefined, '10', true); + component.ngOnChanges({ 'id': change }); + fixture.detectChanges(); + fixture.detectChanges(); + const title = fixture.debugElement.nativeElement.querySelector('#adf-edit-process-filter-title-id'); + const subTitle = fixture.debugElement.nativeElement.querySelector('#adf-edit-process-filter-sub-title-id'); + expect(title).toBeDefined(); + expect(subTitle).toBeDefined(); + expect(title.innerText).toEqual('FakeRunningProcess'); + expect(subTitle.innerText).toEqual('ADF_CLOUD_EDIT_PROCESS_FILTER.TITLE'); + }); + + describe('EditProcessFilter form', () => { + + beforeEach(() => { + let change = new SimpleChange(undefined, '10', true); + component.ngOnChanges({ 'id': change }); + fixture.detectChanges(); + }); + + it('should define editProcessFilter form', () => { + expect(component.editProcessFilterForm).toBeDefined(); + }); + + it('should create editProcessFilter form', async(() => { + fixture.detectChanges(); + fixture.whenStable().then(() => { + const stateController = component.editProcessFilterForm.get('state'); + const sortController = component.editProcessFilterForm.get('sort'); + const orderController = component.editProcessFilterForm.get('order'); + expect(component.editProcessFilterForm).toBeDefined(); + expect(stateController).toBeDefined(); + expect(sortController).toBeDefined(); + expect(orderController).toBeDefined(); + + expect(stateController.value).toBe('RUNNING'); + expect(sortController.value).toBe('id'); + expect(orderController.value).toBe('ASC'); + }); + })); + + it('should disable save button if the process filter is not changed', async(() => { + let expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); + expansionPanel.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + let saveButton = fixture.debugElement.nativeElement.querySelector('#adf-save-id'); + expect(saveButton.disabled).toBe(true); + }); + })); + + it('should disable saveAs button if the process filter is not changed', async(() => { + let expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); + expansionPanel.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + let saveButton = fixture.debugElement.nativeElement.querySelector('#adf-save-as-id'); + expect(saveButton.disabled).toBe(true); + }); + })); + + it('should enable delete button by default', async(() => { + let expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); + expansionPanel.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + let deleteButton = fixture.debugElement.nativeElement.querySelector('#adf-delete-id'); + expect(deleteButton.disabled).toBe(false); + }); + })); + + it('should display current process filter details', async(() => { + let expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); + expansionPanel.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + let stateElement = fixture.debugElement.nativeElement.querySelector('#adf-process-filter-state-id'); + let sortElement = fixture.debugElement.nativeElement.querySelector('#adf-process-filter-sort-id'); + let orderElement = fixture.debugElement.nativeElement.querySelector('#adf-process-filter-order-id'); + expect(stateElement).toBeDefined(); + expect(sortElement).toBeDefined(); + expect(orderElement).toBeDefined(); + expect(stateElement.innerText.trim()).toBe('ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.STATUS'); + expect(sortElement.innerText.trim()).toBe('ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.COLUMN'); + expect(orderElement.innerText.trim()).toBe('ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DIRECTION'); + }); + })); + + it('should enable save button if the process filter is changed', async(() => { + let expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); + expansionPanel.click(); + const stateElement = fixture.debugElement.query(By.css('#adf-process-filter-state-id .mat-select-trigger')).nativeElement; + stateElement.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + const saveButton = fixture.debugElement.nativeElement.querySelector('#adf-save-id'); + const options = fixture.debugElement.queryAll(By.css('.mat-option-text')); + options[2].nativeElement.click(); + fixture.detectChanges(); + expect(saveButton.disabled).toBe(false); + }); + })); + + it('should display state drop down', async(() => { + fixture.detectChanges(); + let expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); + expansionPanel.click(); + const stateElement = fixture.debugElement.query(By.css('#adf-process-filter-state-id .mat-select-trigger')).nativeElement; + stateElement.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + const statusOptions = fixture.debugElement.queryAll(By.css('.mat-option-text')); + expect(statusOptions.length).toEqual(3); + }); + })); + + it('should display sort drop down', async(() => { + fixture.detectChanges(); + let expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); + expansionPanel.click(); + const sortElement = fixture.debugElement.query(By.css('#adf-process-filter-sort-id .mat-select-trigger')).nativeElement; + sortElement.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + const sortOptions = fixture.debugElement.queryAll(By.css('.mat-option-text')); + expect(sortOptions.length).toEqual(4); + }); + })); + + it('should display order drop down', async(() => { + fixture.detectChanges(); + let expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); + expansionPanel.click(); + const orderElement = fixture.debugElement.query(By.css('#adf-process-filter-order-id .mat-select-trigger')).nativeElement; + orderElement.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + const orderOptions = fixture.debugElement.queryAll(By.css('.mat-option-text')); + expect(orderOptions.length).toEqual(2); + }); + })); + }); + + describe('edit filter actions', () => { + + beforeEach(() => { + let change = new SimpleChange(undefined, '10', true); + component.ngOnChanges({ 'id': change }); + }); + + it('should emit save event and save the filter on click save button', async(() => { + const saveFilterSpy = spyOn(service, 'updateFilter').and.returnValue(fakeFilter); + let saveSpy: jasmine.Spy = spyOn(component.action, 'emit'); + fixture.detectChanges(); + let expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); + expansionPanel.click(); + const stateElement = fixture.debugElement.query(By.css('#adf-process-filter-state-id .mat-select-trigger')).nativeElement; + stateElement.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + const saveButton = fixture.debugElement.nativeElement.querySelector('#adf-save-id'); + const stateOptions = fixture.debugElement.queryAll(By.css('.mat-option-text')); + stateOptions[2].nativeElement.click(); + fixture.detectChanges(); + saveButton.click(); + fixture.detectChanges(); + expect(saveFilterSpy).toHaveBeenCalled(); + expect(saveSpy).toHaveBeenCalled(); + }); + })); + + it('should emit delete event and delete the filter on click of delete button', async(() => { + const deleteFilterSpy = spyOn(service, 'deleteFilter').and.callThrough(); + let deleteSpy: jasmine.Spy = spyOn(component.action, 'emit'); + fixture.detectChanges(); + let expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); + expansionPanel.click(); + const stateElement = fixture.debugElement.query(By.css('#adf-process-filter-state-id .mat-select-trigger')).nativeElement; + stateElement.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + let deleteButton = fixture.debugElement.nativeElement.querySelector('#adf-delete-id'); + deleteButton.click(); + fixture.detectChanges(); + expect(deleteFilterSpy).toHaveBeenCalled(); + expect(deleteSpy).toHaveBeenCalled(); + }); + })); + + it('should emit saveAs event and add filter on click of saveAs button', async(() => { + const saveAsFilterSpy = spyOn(service, 'addFilter').and.callThrough(); + let saveAsSpy: jasmine.Spy = spyOn(component.action, 'emit'); + fixture.detectChanges(); + let expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); + expansionPanel.click(); + const stateElement = fixture.debugElement.query(By.css('#adf-process-filter-state-id .mat-select-trigger')).nativeElement; + stateElement.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + const saveButton = fixture.debugElement.nativeElement.querySelector('#adf-save-as-id'); + const stateOptions = fixture.debugElement.queryAll(By.css('.mat-option-text')); + stateOptions[2].nativeElement.click(); + fixture.detectChanges(); + saveButton.click(); + fixture.detectChanges(); + expect(saveAsFilterSpy).toHaveBeenCalled(); + expect(saveAsSpy).toHaveBeenCalled(); + expect(dialog.open).toHaveBeenCalled(); + }); + })); + + it('should able to open save dialog on click of saveAs button', async(() => { + fixture.detectChanges(); + let expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); + expansionPanel.click(); + const stateElement = fixture.debugElement.query(By.css('#adf-process-filter-state-id .mat-select-trigger')).nativeElement; + stateElement.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + const saveButton = fixture.debugElement.nativeElement.querySelector('#adf-save-as-id'); + const stateOptions = fixture.debugElement.queryAll(By.css('.mat-option-text')); + stateOptions[2].nativeElement.click(); + fixture.detectChanges(); + saveButton.click(); + fixture.detectChanges(); + expect(dialog.open).toHaveBeenCalled(); + }); + })); + }); +}); diff --git a/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/edit-process-filter-cloud.component.ts b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/edit-process-filter-cloud.component.ts new file mode 100644 index 0000000000..e5c1156d3b --- /dev/null +++ b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/edit-process-filter-cloud.component.ts @@ -0,0 +1,189 @@ +/*! + * @license + * Copyright 2016 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 { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core'; +import { FormGroup, FormBuilder } from '@angular/forms'; +import { ProcessFilterCloudModel, ProcessFilterActionType } from '../models/process-filter-cloud.model'; +import { TranslationService } from '@alfresco/adf-core'; +import { ProcessFilterCloudService } from '../services/process-filter-cloud.service'; +import { ProcessFilterDialogCloudComponent } from './process-filter-dialog-cloud.component'; +import { MatDialog } from '@angular/material'; + +@Component({ + selector: 'adf-cloud-edit-process-filter', + templateUrl: './edit-process-filter-cloud.component.html', + styleUrls: ['./edit-process-filter-cloud.component.scss'] +}) +export class EditProcessFilterCloudComponent implements OnChanges { + + public static ACTION_SAVE = 'SAVE'; + public static ACTION_SAVE_AS = 'SAVE_AS'; + public static ACTION_DELETE = 'DELETE'; + + /** The name of the application. */ + @Input() + appName: string; + + /** Id of the process instance filter. */ + @Input() + id: string; + + /** Emitted when an process instance filter property changes. */ + @Output() + filterChange: EventEmitter = new EventEmitter(); + + /** Emitted when an filter action occurs i.e Save, SaveAs, Delete. */ + @Output() + action: EventEmitter = new EventEmitter(); + + processFilter: ProcessFilterCloudModel; + changedProcessFilter: ProcessFilterCloudModel; + + columns = [ + {key: 'id', label: 'ID'}, + {key: 'name', label: 'NAME'}, + {key: 'status', label: 'STATUS'}, + {key: 'startDate', label: 'START DATE'} + ]; + + status = [ + {label: 'ALL', value: ''}, + {label: 'RUNNING', value: 'RUNNING'}, + {label: 'COMPLETED', value: 'COMPLETED'} + ]; + + directions = ['ASC', 'DESC']; + formHasBeenChanged = false; + editProcessFilterForm: FormGroup; + + constructor( + private formBuilder: FormBuilder, + public dialog: MatDialog, + private translateService: TranslationService, + private processFilterCloudService: ProcessFilterCloudService) {} + + ngOnChanges(changes: SimpleChanges) { + const id = changes['id']; + if (id && id.currentValue !== id.previousValue) { + this.retrieveProcessFilter(); + this.buildForm(); + } + } + + /** + * Build process filter edit form + */ + buildForm() { + this.formHasBeenChanged = false; + this.editProcessFilterForm = this.formBuilder.group({ + state: this.processFilter.state ? this.processFilter.state : '', + sort: this.processFilter.sort, + order: this.processFilter.order, + processDefinitionId: this.processFilter.processDefinitionId, + appName: this.processFilter.appName + }); + this.onFilterChange(); + } + + /** + * Return process instance filter by application name and filter id + */ + retrieveProcessFilter() { + this.processFilter = this.processFilterCloudService.getProcessFilterById(this.appName, this.id); + } + + /** + * Check process instance filter changes + */ + onFilterChange() { + this.editProcessFilterForm.valueChanges.subscribe((formValues: ProcessFilterCloudModel) => { + this.changedProcessFilter = new ProcessFilterCloudModel(Object.assign({}, this.processFilter, formValues)); + this.formHasBeenChanged = !this.compareFilters(this.changedProcessFilter, this.processFilter); + this.filterChange.emit(this.changedProcessFilter); + }); + } + + /** + * Return true if both filters are same + * @param editedQuery, @param currentQuery + */ + compareFilters(editedQuery: ProcessFilterCloudModel, currentQuery: ProcessFilterCloudModel): boolean { + return JSON.stringify(editedQuery).toLowerCase() === JSON.stringify(currentQuery).toLowerCase(); + } + + /** + * Save a process instance filter + */ + onSave() { + this.processFilterCloudService.updateFilter(this.changedProcessFilter); + this.action.emit({actionType: EditProcessFilterCloudComponent.ACTION_SAVE, id: this.changedProcessFilter.id}); + } + + /** + * Delete a process instance filter + */ + onDelete() { + this.processFilterCloudService.deleteFilter(this.processFilter); + this.action.emit({actionType: EditProcessFilterCloudComponent.ACTION_DELETE, id: this.processFilter.id}); + } + + /** + * Save As a process instance filter + */ + onSaveAs() { + const dialogRef = this.dialog.open(ProcessFilterDialogCloudComponent, { + data: { + name: this.translateService.instant(this.processFilter.name) + }, + height: 'auto', + minWidth: '30%' + }); + dialogRef.afterClosed().subscribe( (result) => { + if (result && result.action === ProcessFilterDialogCloudComponent.ACTION_SAVE) { + const filterId = Math.random().toString(36).substr(2, 9); + const filterKey = this.getSanitizeFilterName(result.name); + const newFilter = { + name: result.name, + icon: result.icon, + id: filterId, + key: 'custom-' + filterKey + }; + const filter = Object.assign({}, this.changedProcessFilter, newFilter); + this.processFilterCloudService.addFilter(filter); + this.action.emit({actionType: EditProcessFilterCloudComponent.ACTION_SAVE_AS, id: filter.id}); + } + }); + } + + /** + * Return filter name + * @param filterName + */ + getSanitizeFilterName(filterName: string): string { + const nameWithHyphen = this.replaceSpaceWithHyphen(filterName.trim()); + return nameWithHyphen.toLowerCase(); + } + + /** + * Return name with hyphen + * @param name + */ + replaceSpaceWithHyphen(name: string): string { + const regExt = new RegExp(' ', 'g'); + return name.replace(regExt, '-'); + } +} diff --git a/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filter-dialog-cloud.component.html b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filter-dialog-cloud.component.html new file mode 100644 index 0000000000..f47f9688bc --- /dev/null +++ b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filter-dialog-cloud.component.html @@ -0,0 +1,22 @@ +
+ + {{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.DIALOG.TITLE' | translate}} + + + +
+ + + +
+
+ + + + +
+
diff --git a/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filter-dialog-cloud.component.scss b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filter-dialog-cloud.component.scss new file mode 100644 index 0000000000..48e59d0a11 --- /dev/null +++ b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filter-dialog-cloud.component.scss @@ -0,0 +1,9 @@ +.adf-process-filter-dialog .mat-card { + padding: 0; + box-shadow: none; +} + +.adf-process-filter-dialog .mat-card-content { + padding: 0; + box-shadow: none; +} diff --git a/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filter-dialog-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filter-dialog-cloud.component.spec.ts new file mode 100644 index 0000000000..3f7d3a49a4 --- /dev/null +++ b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filter-dialog-cloud.component.spec.ts @@ -0,0 +1,136 @@ +/*! + * @license + * Copyright 2016 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 { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; +import { ProcessFilterDialogCloudComponent } from './process-filter-dialog-cloud.component'; +import { setupTestBed } from '@alfresco/adf-core'; +import { ProcessServiceCloudTestingModule } from './../../testing/process-service-cloud.testing.module'; +import { ProcessCloudModule } from '../process-cloud.module'; + +describe('ProcessFilterDialogCloudComponent', () => { + let component: ProcessFilterDialogCloudComponent; + let fixture: ComponentFixture; + + const mockDialogRef = { + close: jasmine.createSpy('close'), + open: jasmine.createSpy('open') + }; + + const mockDialogData = { + data: {name: 'Mock-Title'} + }; + + setupTestBed({ + imports: [ProcessServiceCloudTestingModule, ProcessCloudModule], + providers: [ + { provide: MatDialogRef, useValue: mockDialogRef }, + { provide: MAT_DIALOG_DATA, useValue: mockDialogData } + ] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ProcessFilterDialogCloudComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create ProcessFilterDialogCloudComponent', () => { + expect(component instanceof ProcessFilterDialogCloudComponent).toBeTruthy(); + }); + + it('should get data from MAT_DIALOG_DATA as an input to the dialog', () => { + fixture.detectChanges(); + const mockData = component.data; + fixture.detectChanges(); + expect(mockData).toEqual(mockDialogData); + expect(mockData.data.name).toEqual('Mock-Title'); + }); + + it('should display title', () => { + fixture.detectChanges(); + let titleElement = fixture.debugElement.nativeElement.querySelector( + '#adf-process-filter-dialog-title' + ); + expect(titleElement.textContent).toEqual(' ADF_CLOUD_EDIT_PROCESS_FILTER.DIALOG.TITLE '); + }); + + it('should enable save button if form is valid', async(() => { + fixture.detectChanges(); + let saveButton = fixture.debugElement.nativeElement.querySelector( + '#adf-save-button-id' + ); + const inputElement = fixture.debugElement.nativeElement.querySelector( + '#adf-filter-name-id' + ); + inputElement.value = 'My custom Name'; + inputElement.dispatchEvent(new Event('input')); + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(saveButton).toBeDefined(); + expect(saveButton.disabled).toBeFalsy(); + }); + })); + + it('should disable save button if form is not valid', async(() => { + fixture.detectChanges(); + const inputElement = fixture.debugElement.nativeElement.querySelector( + '#adf-filter-name-id' + ); + inputElement.value = ''; + inputElement.dispatchEvent(new Event('input')); + fixture.whenStable().then(() => { + let saveButton = fixture.debugElement.nativeElement.querySelector( + '#adf-save-button-id' + ); + fixture.detectChanges(); + expect(saveButton).toBeDefined(); + expect(saveButton.disabled).toBe(true); + }); + })); + + it('should able to close dialog on click of save button if form is valid', async(() => { + fixture.detectChanges(); + const inputElement = fixture.debugElement.nativeElement.querySelector( + '#adf-filter-name-id' + ); + inputElement.value = 'My custom Name'; + inputElement.dispatchEvent(new Event('input')); + fixture.whenStable().then(() => { + let saveButton = fixture.debugElement.nativeElement.querySelector( + '#adf-save-button-id' + ); + fixture.detectChanges(); + saveButton.click(); + expect(saveButton).toBeDefined(); + expect(saveButton.disabled).toBeFalsy(); + expect(component.dialogRef.close).toHaveBeenCalled(); + }); + })); + + it('should able close dialog on click of cancel button', () => { + component.data = { data: { name: '' } }; + let cancelButton = fixture.debugElement.nativeElement.querySelector( + '#adf-cancel-button-id' + ); + fixture.detectChanges(); + cancelButton.click(); + expect(cancelButton).toBeDefined(); + expect(cancelButton.disabled).toBeFalsy(); + expect(component.dialogRef.close).toHaveBeenCalled(); + }); +}); diff --git a/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filter-dialog-cloud.component.ts b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filter-dialog-cloud.component.ts new file mode 100644 index 0000000000..7e341222a4 --- /dev/null +++ b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filter-dialog-cloud.component.ts @@ -0,0 +1,66 @@ +/*! + * @license + * Copyright 2016 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 { Component, Inject } from '@angular/core'; +import { OnInit } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; +import { FormBuilder, FormGroup, AbstractControl, Validators } from '@angular/forms'; + +@Component({ + selector: 'adf-cloud-process-filter-dialog-cloud', + templateUrl: './process-filter-dialog-cloud.component.html', + styleUrls: ['./process-filter-dialog-cloud.component.scss'] +}) +export class ProcessFilterDialogCloudComponent implements OnInit { + + public static ACTION_SAVE = 'SAVE'; + defaultIcon = 'inbox'; + + filterForm: FormGroup; + + constructor( + private fb: FormBuilder, + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data) { + } + + ngOnInit() { + this.filterForm = this.fb.group({ + name: [this.data.name, Validators.required] + }); + } + + onSaveClick() { + this.dialogRef.close({ + action: ProcessFilterDialogCloudComponent.ACTION_SAVE, + icon: this.defaultIcon, + name: this.nameController.value + }); + } + + onCancelClick() { + this.dialogRef.close(); + } + + get nameController(): AbstractControl { + return this.filterForm.get('name'); + } + + isValid(): boolean { + return this.filterForm.valid; + } +} diff --git a/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.spec.ts index 8b554c86f3..806886f7d9 100644 --- a/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.spec.ts @@ -19,7 +19,7 @@ import { SimpleChange } from '@angular/core'; import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { setupTestBed } from '@alfresco/adf-core'; import { from, Observable } from 'rxjs'; -import { ProcessFilterRepresentationModel, ProcessFilterParamModel } from '../models/process-filter-cloud.model'; +import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model'; import { ProcessFilterCloudService } from '../services/process-filter-cloud.service'; import { ProcessFiltersCloudComponent } from './process-filters-cloud.component'; import { By } from '@angular/platform-browser'; @@ -31,24 +31,24 @@ describe('ProcessFiltersCloudComponent', () => { let processFilterService: ProcessFilterCloudService; let fakeGlobalFilter = [ - new ProcessFilterRepresentationModel({ + new ProcessFilterCloudModel({ name: 'FakeAllProcesses', icon: 'adjust', id: '10', - query: {state: ''} + state: '' }), - new ProcessFilterRepresentationModel({ + new ProcessFilterCloudModel({ name: 'FakeRunningProcesses', icon: 'inbox', id: '11', - query: {state: 'RUNNING'} + state: 'RUNNING' }), - new ProcessFilterRepresentationModel({ + new ProcessFilterCloudModel({ name: 'FakeCompletedProcesses', key: 'completed-processes', icon: 'done', id: '12', - query: {state: 'COMPLETED'} + state: 'COMPLETED' }) ]; @@ -205,7 +205,7 @@ describe('ProcessFiltersCloudComponent', () => { it('should select the filter based on the input by name param', (done) => { spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); - component.filterParam = new ProcessFilterParamModel({ name: 'FakeRunningProcesses' }); + component.filterParam = new ProcessFilterCloudModel({ name: 'FakeRunningProcesses' }); const appName = 'my-app-1'; let change = new SimpleChange(null, appName, true); @@ -224,7 +224,7 @@ describe('ProcessFiltersCloudComponent', () => { it('should select the filter based on the input by key param', (done) => { spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); - component.filterParam = new ProcessFilterParamModel({ key: 'completed-processes' }); + component.filterParam = new ProcessFilterCloudModel({ key: 'completed-processes' }); const appName = 'my-app-1'; let change = new SimpleChange(null, appName, true); @@ -244,7 +244,7 @@ describe('ProcessFiltersCloudComponent', () => { it('should select the default filter if filter input does not exist', (done) => { spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); - component.filterParam = new ProcessFilterParamModel({ name: 'UnexistableFilter' }); + component.filterParam = new ProcessFilterCloudModel({ name: 'UnexistableFilter' }); const appName = 'my-app-1'; let change = new SimpleChange(null, appName, true); @@ -265,7 +265,7 @@ describe('ProcessFiltersCloudComponent', () => { it('should select the filter based on the input by index param', (done) => { spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); - component.filterParam = new ProcessFilterParamModel({ index: 2 }); + component.filterParam = new ProcessFilterCloudModel({ index: 2 }); const appName = 'my-app-1'; let change = new SimpleChange(null, appName, true); @@ -285,7 +285,7 @@ describe('ProcessFiltersCloudComponent', () => { it('should select the filter based on the input by id param', (done) => { spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); - component.filterParam = new ProcessFilterParamModel({ id: '12' }); + component.filterParam = new ProcessFilterCloudModel({ id: '12' }); const appName = 'my-app-1'; let change = new SimpleChange(null, appName, true); @@ -304,7 +304,7 @@ describe('ProcessFiltersCloudComponent', () => { it('should emit an event when a filter is selected', (done) => { spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); - component.filterParam = new ProcessFilterParamModel({ id: '10' }); + component.filterParam = new ProcessFilterCloudModel({ id: '10' }); const appName = 'my-app-1'; let change = new SimpleChange(null, appName, true); @@ -369,7 +369,7 @@ describe('ProcessFiltersCloudComponent', () => { component.filters = fakeGlobalFilter; expect(component.currentFilter).toBeUndefined(); - component.selectFilter( {id: filter.id}); + component.selectFilter( {id: filter.id}); expect(component.getCurrentFilter()).toBe(filter); }); }); diff --git a/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.ts b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.ts index 79ce89fbd1..db12faa723 100644 --- a/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/process-cloud/process-filters-cloud/process-filters-cloud.component.ts @@ -18,7 +18,7 @@ import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { Observable } from 'rxjs'; import { ProcessFilterCloudService } from '../services/process-filter-cloud.service'; -import { ProcessFilterRepresentationModel, ProcessFilterParamModel } from '../models/process-filter-cloud.model'; +import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model'; import { TranslationService } from '@alfresco/adf-core'; @Component({ selector: 'adf-cloud-process-filters', @@ -33,7 +33,7 @@ export class ProcessFiltersCloudComponent implements OnChanges { /** (optional) The filter to be selected by default */ @Input() - filterParam: ProcessFilterParamModel; + filterParam: ProcessFilterCloudModel; /** (optional) The flag hides/shows icon against each filter */ @Input() @@ -41,7 +41,7 @@ export class ProcessFiltersCloudComponent implements OnChanges { /** Emitted when a filter is selected/clicked */ @Output() - filterClick: EventEmitter = new EventEmitter(); + filterClick: EventEmitter = new EventEmitter(); /** Emitted when filters are loaded successfully */ @Output() @@ -51,11 +51,11 @@ export class ProcessFiltersCloudComponent implements OnChanges { @Output() error: EventEmitter = new EventEmitter(); - filters$: Observable; + filters$: Observable; - currentFilter: ProcessFilterRepresentationModel; + currentFilter: ProcessFilterCloudModel; - filters: ProcessFilterRepresentationModel [] = []; + filters: ProcessFilterCloudModel [] = []; constructor( private processFilterCloudService: ProcessFilterCloudService, @@ -78,7 +78,7 @@ export class ProcessFiltersCloudComponent implements OnChanges { this.filters$ = this.processFilterCloudService.getProcessFilters(appName); this.filters$.subscribe( - (res: ProcessFilterRepresentationModel[]) => { + (res: ProcessFilterCloudModel[]) => { if (res.length === 0) { this.createFilters(appName); } else { @@ -101,7 +101,7 @@ export class ProcessFiltersCloudComponent implements OnChanges { this.filters$ = this.processFilterCloudService.createDefaultFilters(appName); this.filters$.subscribe( - (resDefault: ProcessFilterRepresentationModel[]) => { + (resDefault: ProcessFilterCloudModel[]) => { this.resetFilter(); this.filters = resDefault; }, @@ -114,7 +114,7 @@ export class ProcessFiltersCloudComponent implements OnChanges { /** * Pass the selected filter as next */ - public selectFilter(filterParam: ProcessFilterParamModel) { + public selectFilter(filterParam: ProcessFilterCloudModel) { if (filterParam) { this.currentFilter = this.filters.find((filter, index) => { return filterParam.id === filter.id || @@ -141,7 +141,7 @@ export class ProcessFiltersCloudComponent implements OnChanges { /** * Select and emit the given filter */ - public selectFilterAndEmit(newFilter: ProcessFilterParamModel) { + public selectFilterAndEmit(newFilter: ProcessFilterCloudModel) { this.selectFilter(newFilter); this.filterClick.emit(this.currentFilter); } @@ -150,7 +150,7 @@ export class ProcessFiltersCloudComponent implements OnChanges { * Select filter with the id */ public selectFilterById(id: string) { - this.selectFilterAndEmit( {id: id}); + this.selectFilterAndEmit( {id: id}); } /** @@ -165,7 +165,7 @@ export class ProcessFiltersCloudComponent implements OnChanges { /** * Return the current process */ - getCurrentFilter(): ProcessFilterRepresentationModel { + getCurrentFilter(): ProcessFilterCloudModel { return this.currentFilter; } diff --git a/lib/process-services-cloud/src/lib/process-cloud/public-api.ts b/lib/process-services-cloud/src/lib/process-cloud/public-api.ts index 2438eb04b6..8b9d0f3b25 100644 --- a/lib/process-services-cloud/src/lib/process-cloud/public-api.ts +++ b/lib/process-services-cloud/src/lib/process-cloud/public-api.ts @@ -16,5 +16,7 @@ */ export * from './process-filters-cloud/process-filters-cloud.component'; +export * from './process-filters-cloud/edit-process-filter-cloud.component'; export * from './models/process-filter-cloud.model'; +export * from './services/process-filter-cloud.service'; export * from './process-cloud.module'; diff --git a/lib/process-services-cloud/src/lib/process-cloud/services/process-filter-cloud.service.ts b/lib/process-services-cloud/src/lib/process-cloud/services/process-filter-cloud.service.ts index d56f916ea2..d6d4ad5738 100644 --- a/lib/process-services-cloud/src/lib/process-cloud/services/process-filter-cloud.service.ts +++ b/lib/process-services-cloud/src/lib/process-cloud/services/process-filter-cloud.service.ts @@ -18,7 +18,7 @@ import { StorageService } from '@alfresco/adf-core'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { ProcessFilterRepresentationModel, ProcessQueryModel } from '../models/process-filter-cloud.model'; +import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model'; @Injectable() export class ProcessFilterCloudService { @@ -31,7 +31,7 @@ export class ProcessFilterCloudService { * @param appName Name of the target app * @returns Observable of default filters just created */ - public createDefaultFilters(appName: string): Observable { + public createDefaultFilters(appName: string): Observable { const allProcessesFilter = this.getAllProcessesFilter(appName); this.addFilter(allProcessesFilter); const runningProcessesFilter = this.getRunningProcessesFilter(appName); @@ -47,7 +47,7 @@ export class ProcessFilterCloudService { * @param appName Name of the target app * @returns Observable of process filter details */ - getProcessFilters(appName: string): Observable { + getProcessFilters(appName: string): Observable { let key = 'process-filters-' + appName; const filters = JSON.parse(this.storage.getItem(key) || '[]'); return new Observable(function(observer) { @@ -56,36 +56,73 @@ export class ProcessFilterCloudService { }); } + /** + * Get process instance filter for given filter id + * @param appName Name of the target app + * @param id Id of the target process instance filter + * @returns Details of process filter + */ + getProcessFilterById(appName: string, id: string): ProcessFilterCloudModel { + const key = 'process-filters-' + appName; + let filters = []; + filters = JSON.parse(this.storage.getItem(key)) || []; + return filters.filter((filterTmp: ProcessFilterCloudModel) => id === filterTmp.id)[0]; + } + /** * Adds a new process instance filter * @param filter The new filter to add * @returns Details of process filter just added */ - addFilter(filter: ProcessFilterRepresentationModel) { - const key = 'process-filters-' + filter.query.appName; + addFilter(filter: ProcessFilterCloudModel) { + const key = 'process-filters-' + filter.appName; const storedFilters = JSON.parse(this.storage.getItem(key) || '[]'); storedFilters.push(filter); this.storage.setItem(key, JSON.stringify(storedFilters)); } + /** + * Update process instance filter + * @param filter The new filter to update + */ + updateFilter(filter: ProcessFilterCloudModel) { + const key = 'process-filters-' + filter.appName; + if (key) { + let filters = JSON.parse(this.storage.getItem(key) || '[]'); + let itemIndex = filters.findIndex((flt: ProcessFilterCloudModel) => flt.id === filter.id); + filters[itemIndex] = filter; + this.storage.setItem(key, JSON.stringify(filters)); + } + } + + /** + * Delete process instance filter + * @param filter The new filter to delete + */ + deleteFilter(filter: ProcessFilterCloudModel) { + const key = 'process-filters-' + filter.appName; + if (key) { + let filters = JSON.parse(this.storage.getItem(key) || '[]'); + filters = filters.filter((item) => item.id !== filter.id); + this.storage.setItem(key, JSON.stringify(filters)); + } + } + /** * Creates and returns a filter for "All" Process instances. * @param appName Name of the target app * @returns The newly created filter */ - getAllProcessesFilter(appName: string): ProcessFilterRepresentationModel { - return new ProcessFilterRepresentationModel({ + getAllProcessesFilter(appName: string): ProcessFilterCloudModel { + return new ProcessFilterCloudModel({ name: 'ADF_CLOUD_PROCESS_FILTERS.ALL_PROCESSES', key: 'all-processes', icon: 'adjust', - query: new ProcessQueryModel( - { - appName: appName, - sort: 'startDate', - order: 'DESC' - } - ) + appName: appName, + sort: 'startDate', + state: '', + order: 'DESC' }); } @@ -94,19 +131,15 @@ export class ProcessFilterCloudService { * @param appName Name of the target app * @returns The newly created filter */ - getRunningProcessesFilter(appName: string): ProcessFilterRepresentationModel { - return new ProcessFilterRepresentationModel({ + getRunningProcessesFilter(appName: string): ProcessFilterCloudModel { + return new ProcessFilterCloudModel({ name: 'ADF_CLOUD_PROCESS_FILTERS.RUNNING_PROCESSES', icon: 'inbox', key: 'running-processes', - query: new ProcessQueryModel( - { - appName: appName, - sort: 'startDate', - state: 'RUNNING', - order: 'DESC' - } - ) + appName: appName, + sort: 'startDate', + state: 'RUNNING', + order: 'DESC' }); } @@ -115,19 +148,15 @@ export class ProcessFilterCloudService { * @param appName Name of the target app * @returns The newly created filter */ - getCompletedProcessesFilter(appName: string): ProcessFilterRepresentationModel { - return new ProcessFilterRepresentationModel({ + getCompletedProcessesFilter(appName: string): ProcessFilterCloudModel { + return new ProcessFilterCloudModel({ name: 'ADF_CLOUD_PROCESS_FILTERS.COMPLETED_PROCESSES', icon: 'done', key: 'completed-processes', - query: new ProcessQueryModel( - { - appName: appName, - sort: 'startDate', - state: 'COMPLETED', - order: 'DESC' - } - ) + appName: appName, + sort: 'startDate', + state: 'COMPLETED', + order: 'DESC' }); } } diff --git a/lib/process-services-cloud/src/public-api.ts b/lib/process-services-cloud/src/public-api.ts index f263daaedc..31c7381a59 100644 --- a/lib/process-services-cloud/src/public-api.ts +++ b/lib/process-services-cloud/src/public-api.ts @@ -19,5 +19,6 @@ export * from './lib/process-services-cloud.module'; export * from './lib/app-list-cloud/public-api'; export * from './lib/task-list-cloud/public-api'; export * from './lib/task-cloud/public-api'; +export * from './lib/process-cloud/public-api'; export * from './lib/process-list-cloud/public_api'; export * from './lib/start-task-cloud/public-api';