[ADF-3799] Process Filter definition in a component APS2 (#4048)

* * Generated EditProcessFilterComponent by cli
* Added MatExpansionModule

* * Added translation keys related to the editProcessFilterComponent
* Updated editProcessFilterComponent

* * Refactored EditProcessFilter component
* Created delete , save and saveAs  filter methods in the service
* Generated ProcessDialog component
* Exported process-cloud
* Added Unit tests to the EditProcessFilter

* * Added unit tests to the processFIlterDialog component* Refactored process-list-cloud-demo component

* * Added editProcessFilter documentaion.

* * Unified process filter cloud models

* * Used new process-filter-cloud model

* * Updated documentation

* * Updated demo component

* * Updated editProcessFilter unit tests

* * After rebase* Fixed missing documentation

* * Fixed conflicts
* Rebased with dev branch

* Fix import
This commit is contained in:
siva kumar
2018-12-11 20:31:12 +05:30
committed by Maurizio Vitale
parent 1d94d90716
commit 242884db20
22 changed files with 1071 additions and 217 deletions

View File

@@ -46,12 +46,7 @@ export class CloudLayoutComponent implements OnInit {
} }
onProcessFilterSelected(filter) { onProcessFilterSelected(filter) {
const queryParams = { const currentFilter = Object.assign({}, filter);
status: filter.query.state, this.router.navigate([`/cloud/${this.applicationName}/processes/`], { queryParams: currentFilter });
filterName: filter.name,
sort: filter.query.sort,
order: filter.query.order
};
this.router.navigate([`/cloud/${this.applicationName}/processes/`], { queryParams: queryParams });
} }
} }

View File

@@ -1,57 +1,15 @@
<div fxLayout="column" fxFill fxLayoutGap="2px"> <div fxLayout="column" fxFill fxLayoutGap="2px">
<mat-accordion> <adf-cloud-edit-process-filter
<mat-expansion-panel> [appName]="applicationName"
<mat-expansion-panel-header> [id]="filterId"
<mat-panel-title> (filterChange)="onFilterChange($event)"
{{filterName | translate}} (action)="onEditActions($event)">
</mat-panel-title> </adf-cloud-edit-process-filter>
<mat-panel-description> <div fxLayout="column" fxFlex fxLayoutAlign="space-between" *ngIf="editedFilter">
{{ 'PROCESS_LIST_CLOUD_DEMO.CUSTOMIZE_FILTERS' | translate}}
</mat-panel-description>
</mat-expansion-panel-header>
<div fxLayout="row" fxLayoutGap="10px">
<mat-form-field>
<mat-select placeholder="Status" [(ngModel)]="status">
<mat-option value="">
ALL
</mat-option>
<mat-option value="RUNNING">
RUNNING
</mat-option>
<mat-option value="COMPLETED">
COMPLETED
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-select [formControl]="sortFormControl">
<mat-option [value]="''">Select a column</mat-option>
<mat-option *ngFor="let column of columns" [value]="column.key">
{{column.label}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-select [formControl]="sortDirectionFormControl">
<mat-option [value]="''">Select a direction</mat-option>
<mat-option value="ASC">
ASC
</mat-option>
<mat-option value="DESC">
DESC
</mat-option>
</mat-select>
</mat-form-field>
</div>
</mat-expansion-panel>
</mat-accordion>
<div fxLayout="column" fxFlex fxLayoutAlign="space-between">
<adf-cloud-process-list fxFlex class="adf-cloud-layout-overflow" <adf-cloud-process-list fxFlex class="adf-cloud-layout-overflow"
[applicationName]="applicationName" [applicationName]="editedFilter.appName"
[status]="status" [status]="editedFilter.state"
[sorting]="sortArray" [sorting]="sortArray"
[id]="filterId"
(rowClick)="onRowClick($event)" (rowClick)="onRowClick($event)"
#processCloud> #processCloud>
<data-columns> <data-columns>

View File

@@ -16,9 +16,15 @@
*/ */
import { Component, ViewChild, OnInit } from '@angular/core'; 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 { ActivatedRoute } from '@angular/router';
import { FormControl } from '@angular/forms';
import { UserPreferencesService } from '@alfresco/adf-core'; import { UserPreferencesService } from '@alfresco/adf-core';
@Component({ @Component({
@@ -30,27 +36,17 @@ export class ProcessesCloudDemoComponent implements OnInit {
@ViewChild('processCloud') @ViewChild('processCloud')
processCloud: ProcessListCloudComponent; processCloud: ProcessListCloudComponent;
sortFormControl: FormControl; @ViewChild('processFiltersCloud')
sortDirectionFormControl: FormControl; processFiltersCloud: ProcessFiltersCloudComponent;
applicationName: string = ''; applicationName: string = '';
isFilterLoaded: boolean; isFilterLoaded: boolean;
status: string = '';
filterName: string;
filterId: string = ''; filterId: string = '';
sort: string = '';
sortArray: any = []; sortArray: any = [];
sortField: string;
sortDirection: string;
selectedRow: any; selectedRow: any;
columns = [ editedFilter: ProcessFilterCloudModel;
{key: 'id', label: 'ID'},
{key: 'name', label: 'NAME'},
{key: 'status', label: 'STATUS'},
{key: 'startDate', label: 'START DATE'}
];
constructor(private route: ActivatedRoute, constructor(private route: ActivatedRoute,
private userPreference: UserPreferencesService) { private userPreference: UserPreferencesService) {
@@ -62,43 +58,11 @@ export class ProcessesCloudDemoComponent implements OnInit {
this.applicationName = params.applicationName; this.applicationName = params.applicationName;
}); });
this.sortFormControl = new FormControl(''); this.route.queryParams.subscribe((params) => {
this.isFilterLoaded = true;
this.sortFormControl.valueChanges.subscribe( this.onFilterChange(params);
(sortValue) => { this.filterId = params.id;
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);
}
});
} }
onChangePageSize(event) { onChangePageSize(event) {
@@ -108,4 +72,33 @@ export class ProcessesCloudDemoComponent implements OnInit {
onRowClick($event) { onRowClick($event) {
this.selectedRow = $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 = <any> {id : filterId};
this.processFiltersCloud.getFilters(this.applicationName);
}
save(filterId) {
this.processFiltersCloud.filterParam = <any> {id : filterId};
this.processFiltersCloud.getFilters(this.applicationName);
}
deleteFilter() {
this.processFiltersCloud.getFilters(this.applicationName);
}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -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
<adf-cloud-edit-process-filter
[id]="processFilterId"
[appName]="applicationName">
</adf-cloud-edit-process-filter>
```
## 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
<adf-cloud-edit-process-filter
[id]="processFilterId"
[appName]="applicationName">
</adf-cloud-edit-process-filter>
```
![edit-process-filter-cloud](../docassets/images/edit-process-filter-cloud.component.png)

View File

@@ -24,13 +24,32 @@ Lists all available process filters and allows to select a filter.
| Name | Type | Default value | Description | | Name | Type | Default value | Description |
| ---- | ---- | ------------- | ----------- | | ---- | ---- | ------------- | ----------- |
| appName | `string` | | (required) The application name | | 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 | | showIcons | `boolean` | false | (optional) The flag hides/shows icon against each filter |
### Events ### Events
| Name | Type | Description | | Name | Type | Description |
| ---- | ---- | ----------- | | ---- | ---- | ----------- |
| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when any error occurs while loading the filters | | 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. |
| 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)`<any>` | Emitted when filters are loaded successfully. |
| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when filters are loaded successfully | | error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when any error occurs while loading the filters. |
### Details
The `filterParam` input can be used to select a filter as mentioned below.
```html
<adf-cloud-process-filters
[filterParam]="{name:'Running Processes'}">
</adf-cloud-process-filters>
```
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 |

View File

@@ -80,5 +80,28 @@
"SAVE": "SAVE", "SAVE": "SAVE",
"CANCEL": "CANCEL" "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"
}
} }
} }

View File

@@ -14,31 +14,18 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
export class ProcessQueryModel {
processDefinitionId: string;
appName: string;
state: string;
sort: string;
assignment: string;
order: string;
constructor(obj?: any) { export class ProcessFilterCloudModel {
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 {
id: string; id: string;
name: string; name: string;
key: string; key: string;
icon: string; icon: string;
query: ProcessQueryModel; index: number;
processDefinitionId: string;
appName: string;
state: string;
sort: string;
order: string;
constructor(obj?: any) { constructor(obj?: any) {
if (obj) { if (obj) {
@@ -46,26 +33,17 @@ export class ProcessFilterRepresentationModel {
this.name = obj.name || null; this.name = obj.name || null;
this.key = obj.key || null; this.key = obj.key || null;
this.icon = obj.icon || 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.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;
}

View File

@@ -17,14 +17,20 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; 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 { ProcessFiltersCloudComponent } from './process-filters-cloud/process-filters-cloud.component';
import { MaterialModule } from '../material.module'; import { MaterialModule } from '../material.module';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateLoaderService, LogService, StorageService } from '@alfresco/adf-core'; import { TranslateLoaderService, LogService, StorageService } from '@alfresco/adf-core';
import { ProcessFilterCloudService } from './services/process-filter-cloud.service'; import { ProcessFilterCloudService } from './services/process-filter-cloud.service';
import { HttpClientModule } from '@angular/common/http'; 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({ @NgModule({
imports: [ imports: [
FormsModule,
ReactiveFormsModule,
HttpClientModule, HttpClientModule,
CommonModule, CommonModule,
TranslateModule.forRoot({ TranslateModule.forRoot({
@@ -33,11 +39,12 @@ import { HttpClientModule } from '@angular/common/http';
useClass: TranslateLoaderService useClass: TranslateLoaderService
} }
}), }),
FlexLayoutModule,
MaterialModule MaterialModule
], ],
declarations: [ProcessFiltersCloudComponent], declarations: [ProcessFiltersCloudComponent, EditProcessFilterCloudComponent, ProcessFilterDialogCloudComponent],
exports: [ProcessFiltersCloudComponent, EditProcessFilterCloudComponent, ProcessFilterDialogCloudComponent],
exports: [ProcessFiltersCloudComponent], entryComponents: [ProcessFilterDialogCloudComponent],
providers: [ProcessFilterCloudService, LogService, StorageService] providers: [ProcessFilterCloudService, LogService, StorageService]
}) })
export class ProcessCloudModule { } export class ProcessCloudModule { }

View File

@@ -0,0 +1,60 @@
<mat-accordion>
<mat-expansion-panel>
<mat-expansion-panel-header id="adf-edit-process-filter-expansion-header">
<mat-panel-title id="adf-edit-process-filter-title-id">{{processFilter.name | translate}}</mat-panel-title>
<mat-panel-description id="adf-edit-process-filter-sub-title-id">
{{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.TITLE' | translate}}
</mat-panel-description>
</mat-expansion-panel-header>
<form [formGroup]="editProcessFilterForm">
<div fxLayout="row" fxLayout.xs="column" fxLayoutAlign="space-between center" fxLayoutGap="10px">
<mat-form-field [floatLabel]="'auto'" fxFlex>
<mat-select placeholder="{{'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.STATUS' | translate}}" formControlName="state" id="adf-process-filter-state-id">
<mat-option *ngFor="let state of status" [value]="state.value">
{{ state.label }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="false" [floatLabel]="'auto'" fxFlex>
<input matInput
formControlName="appName"
type="text"
id="adf-process-filter-appname-id"
placeholder="{{'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.APP_NAME' | translate}}"/>
</mat-form-field>
<mat-form-field *ngIf="false" [floatLabel]="'auto'" fxFlex>
<input matInput
formControlName="processDefinitionId"
type="text"
id="adf-process-filter-process-definition-id"
placeholder="{{'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.PROCESS_DEF_ID' | translate}}"/>
</mat-form-field>
<mat-form-field [floatLabel]="'auto'" fxFlex>
<mat-select placeholder="{{'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.COLUMN' | translate}}" formControlName="sort" id="adf-process-filter-sort-id">
<mat-option *ngFor="let column of columns" [value]="column.key">
{{ column.label }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field [floatLabel]="'auto'" fxFlex>
<mat-select placeholder="{{'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.DIRECTION' | translate}}" formControlName="order" id="adf-process-filter-order-id">
<mat-option *ngFor="let direction of directions" [value]="direction">
{{ direction }}
</mat-option>
</mat-select>
</mat-form-field>
<div>
<button mat-icon-button matTooltip="{{'ADF_CLOUD_EDIT_PROCESS_FILTER.TOOL_TIP.SAVE' | translate}}" [disabled]="!formHasBeenChanged" id="adf-save-id" (click)="onSave()">
<mat-icon>save</mat-icon>
</button>
<button mat-icon-button matTooltip="{{'ADF_CLOUD_EDIT_PROCESS_FILTER.TOOL_TIP.SAVE_AS' | translate}}" [disabled]="!formHasBeenChanged" id="adf-save-as-id" (click)="onSaveAs()">
<mat-icon>unarchive</mat-icon>
</button>
<button mat-icon-button matTooltip="{{'ADF_CLOUD_EDIT_PROCESS_FILTER.TOOL_TIP.DELETE' | translate}}" id="adf-delete-id" (click)="onDelete()">
<mat-icon>delete</mat-icon>
</button>
</div>
</div>
</form>
</mat-expansion-panel>
</mat-accordion>

View File

@@ -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<EditProcessFilterCloudComponent>;
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();
});
}));
});
});

View File

@@ -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<ProcessFilterCloudModel> = new EventEmitter();
/** Emitted when an filter action occurs i.e Save, SaveAs, Delete. */
@Output()
action: EventEmitter<ProcessFilterActionType> = 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, '-');
}
}

View File

@@ -0,0 +1,22 @@
<div class="adf-process-filter-dialog">
<span mat-dialog-title id="adf-process-filter-dialog-title">
{{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.DIALOG.TITLE' | translate}}
</span>
<mat-card>
<mat-card-content>
<form [formGroup]="filterForm">
<mat-form-field fxFlex [floatLabel]="'auto'">
<input matInput placeholder="Filter name" formControlName="name" id="adf-filter-name-id">
</mat-form-field>
</form>
</mat-card-content>
<mat-card-actions fxLayout="row" fxLayoutAlign="end end">
<button mat-button (click)="onSaveClick()" id="adf-save-button-id" [disabled]="!isValid()">
{{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.DIALOG.SAVE' | translate}}
</button>
<button mat-button (click)="onCancelClick()" id="adf-cancel-button-id">
{{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.DIALOG.CANCEL' | translate}}
</button>
</mat-card-actions>
</mat-card>
</div>

View File

@@ -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;
}

View File

@@ -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<ProcessFilterDialogCloudComponent>;
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();
});
});

View File

@@ -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<ProcessFilterDialogCloudComponent>,
@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;
}
}

View File

@@ -19,7 +19,7 @@ import { SimpleChange } from '@angular/core';
import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { setupTestBed } from '@alfresco/adf-core'; import { setupTestBed } from '@alfresco/adf-core';
import { from, Observable } from 'rxjs'; 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 { ProcessFilterCloudService } from '../services/process-filter-cloud.service';
import { ProcessFiltersCloudComponent } from './process-filters-cloud.component'; import { ProcessFiltersCloudComponent } from './process-filters-cloud.component';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
@@ -31,24 +31,24 @@ describe('ProcessFiltersCloudComponent', () => {
let processFilterService: ProcessFilterCloudService; let processFilterService: ProcessFilterCloudService;
let fakeGlobalFilter = [ let fakeGlobalFilter = [
new ProcessFilterRepresentationModel({ new ProcessFilterCloudModel({
name: 'FakeAllProcesses', name: 'FakeAllProcesses',
icon: 'adjust', icon: 'adjust',
id: '10', id: '10',
query: {state: ''} state: ''
}), }),
new ProcessFilterRepresentationModel({ new ProcessFilterCloudModel({
name: 'FakeRunningProcesses', name: 'FakeRunningProcesses',
icon: 'inbox', icon: 'inbox',
id: '11', id: '11',
query: {state: 'RUNNING'} state: 'RUNNING'
}), }),
new ProcessFilterRepresentationModel({ new ProcessFilterCloudModel({
name: 'FakeCompletedProcesses', name: 'FakeCompletedProcesses',
key: 'completed-processes', key: 'completed-processes',
icon: 'done', icon: 'done',
id: '12', 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) => { it('should select the filter based on the input by name param', (done) => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new ProcessFilterParamModel({ name: 'FakeRunningProcesses' }); component.filterParam = new ProcessFilterCloudModel({ name: 'FakeRunningProcesses' });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); 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) => { it('should select the filter based on the input by key param', (done) => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); 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'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); 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) => { it('should select the default filter if filter input does not exist', (done) => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new ProcessFilterParamModel({ name: 'UnexistableFilter' }); component.filterParam = new ProcessFilterCloudModel({ name: 'UnexistableFilter' });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); 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) => { it('should select the filter based on the input by index param', (done) => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new ProcessFilterParamModel({ index: 2 }); component.filterParam = new ProcessFilterCloudModel({ index: 2 });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); 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) => { it('should select the filter based on the input by id param', (done) => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new ProcessFilterParamModel({ id: '12' }); component.filterParam = new ProcessFilterCloudModel({ id: '12' });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); let change = new SimpleChange(null, appName, true);
@@ -304,7 +304,7 @@ describe('ProcessFiltersCloudComponent', () => {
it('should emit an event when a filter is selected', (done) => { it('should emit an event when a filter is selected', (done) => {
spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable); spyOn(processFilterService, 'getProcessFilters').and.returnValue(fakeGlobalFilterObservable);
component.filterParam = new ProcessFilterParamModel({ id: '10' }); component.filterParam = new ProcessFilterCloudModel({ id: '10' });
const appName = 'my-app-1'; const appName = 'my-app-1';
let change = new SimpleChange(null, appName, true); let change = new SimpleChange(null, appName, true);
@@ -369,7 +369,7 @@ describe('ProcessFiltersCloudComponent', () => {
component.filters = fakeGlobalFilter; component.filters = fakeGlobalFilter;
expect(component.currentFilter).toBeUndefined(); expect(component.currentFilter).toBeUndefined();
component.selectFilter(<ProcessFilterParamModel> {id: filter.id}); component.selectFilter(<ProcessFilterCloudModel> {id: filter.id});
expect(component.getCurrentFilter()).toBe(filter); expect(component.getCurrentFilter()).toBe(filter);
}); });
}); });

View File

@@ -18,7 +18,7 @@
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { ProcessFilterCloudService } from '../services/process-filter-cloud.service'; 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'; import { TranslationService } from '@alfresco/adf-core';
@Component({ @Component({
selector: 'adf-cloud-process-filters', selector: 'adf-cloud-process-filters',
@@ -33,7 +33,7 @@ export class ProcessFiltersCloudComponent implements OnChanges {
/** (optional) The filter to be selected by default */ /** (optional) The filter to be selected by default */
@Input() @Input()
filterParam: ProcessFilterParamModel; filterParam: ProcessFilterCloudModel;
/** (optional) The flag hides/shows icon against each filter */ /** (optional) The flag hides/shows icon against each filter */
@Input() @Input()
@@ -41,7 +41,7 @@ export class ProcessFiltersCloudComponent implements OnChanges {
/** Emitted when a filter is selected/clicked */ /** Emitted when a filter is selected/clicked */
@Output() @Output()
filterClick: EventEmitter<ProcessFilterRepresentationModel> = new EventEmitter<ProcessFilterRepresentationModel>(); filterClick: EventEmitter<ProcessFilterCloudModel> = new EventEmitter<ProcessFilterCloudModel>();
/** Emitted when filters are loaded successfully */ /** Emitted when filters are loaded successfully */
@Output() @Output()
@@ -51,11 +51,11 @@ export class ProcessFiltersCloudComponent implements OnChanges {
@Output() @Output()
error: EventEmitter<any> = new EventEmitter<any>(); error: EventEmitter<any> = new EventEmitter<any>();
filters$: Observable<ProcessFilterRepresentationModel[]>; filters$: Observable<ProcessFilterCloudModel[]>;
currentFilter: ProcessFilterRepresentationModel; currentFilter: ProcessFilterCloudModel;
filters: ProcessFilterRepresentationModel [] = []; filters: ProcessFilterCloudModel [] = [];
constructor( constructor(
private processFilterCloudService: ProcessFilterCloudService, private processFilterCloudService: ProcessFilterCloudService,
@@ -78,7 +78,7 @@ export class ProcessFiltersCloudComponent implements OnChanges {
this.filters$ = this.processFilterCloudService.getProcessFilters(appName); this.filters$ = this.processFilterCloudService.getProcessFilters(appName);
this.filters$.subscribe( this.filters$.subscribe(
(res: ProcessFilterRepresentationModel[]) => { (res: ProcessFilterCloudModel[]) => {
if (res.length === 0) { if (res.length === 0) {
this.createFilters(appName); this.createFilters(appName);
} else { } else {
@@ -101,7 +101,7 @@ export class ProcessFiltersCloudComponent implements OnChanges {
this.filters$ = this.processFilterCloudService.createDefaultFilters(appName); this.filters$ = this.processFilterCloudService.createDefaultFilters(appName);
this.filters$.subscribe( this.filters$.subscribe(
(resDefault: ProcessFilterRepresentationModel[]) => { (resDefault: ProcessFilterCloudModel[]) => {
this.resetFilter(); this.resetFilter();
this.filters = resDefault; this.filters = resDefault;
}, },
@@ -114,7 +114,7 @@ export class ProcessFiltersCloudComponent implements OnChanges {
/** /**
* Pass the selected filter as next * Pass the selected filter as next
*/ */
public selectFilter(filterParam: ProcessFilterParamModel) { public selectFilter(filterParam: ProcessFilterCloudModel) {
if (filterParam) { if (filterParam) {
this.currentFilter = this.filters.find((filter, index) => { this.currentFilter = this.filters.find((filter, index) => {
return filterParam.id === filter.id || return filterParam.id === filter.id ||
@@ -141,7 +141,7 @@ export class ProcessFiltersCloudComponent implements OnChanges {
/** /**
* Select and emit the given filter * Select and emit the given filter
*/ */
public selectFilterAndEmit(newFilter: ProcessFilterParamModel) { public selectFilterAndEmit(newFilter: ProcessFilterCloudModel) {
this.selectFilter(newFilter); this.selectFilter(newFilter);
this.filterClick.emit(this.currentFilter); this.filterClick.emit(this.currentFilter);
} }
@@ -150,7 +150,7 @@ export class ProcessFiltersCloudComponent implements OnChanges {
* Select filter with the id * Select filter with the id
*/ */
public selectFilterById(id: string) { public selectFilterById(id: string) {
this.selectFilterAndEmit(<ProcessFilterParamModel> {id: id}); this.selectFilterAndEmit(<ProcessFilterCloudModel> {id: id});
} }
/** /**
@@ -165,7 +165,7 @@ export class ProcessFiltersCloudComponent implements OnChanges {
/** /**
* Return the current process * Return the current process
*/ */
getCurrentFilter(): ProcessFilterRepresentationModel { getCurrentFilter(): ProcessFilterCloudModel {
return this.currentFilter; return this.currentFilter;
} }

View File

@@ -16,5 +16,7 @@
*/ */
export * from './process-filters-cloud/process-filters-cloud.component'; 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 './models/process-filter-cloud.model';
export * from './services/process-filter-cloud.service';
export * from './process-cloud.module'; export * from './process-cloud.module';

View File

@@ -18,7 +18,7 @@
import { StorageService } from '@alfresco/adf-core'; import { StorageService } from '@alfresco/adf-core';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { ProcessFilterRepresentationModel, ProcessQueryModel } from '../models/process-filter-cloud.model'; import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model';
@Injectable() @Injectable()
export class ProcessFilterCloudService { export class ProcessFilterCloudService {
@@ -31,7 +31,7 @@ export class ProcessFilterCloudService {
* @param appName Name of the target app * @param appName Name of the target app
* @returns Observable of default filters just created * @returns Observable of default filters just created
*/ */
public createDefaultFilters(appName: string): Observable<ProcessFilterRepresentationModel[]> { public createDefaultFilters(appName: string): Observable<ProcessFilterCloudModel[]> {
const allProcessesFilter = this.getAllProcessesFilter(appName); const allProcessesFilter = this.getAllProcessesFilter(appName);
this.addFilter(allProcessesFilter); this.addFilter(allProcessesFilter);
const runningProcessesFilter = this.getRunningProcessesFilter(appName); const runningProcessesFilter = this.getRunningProcessesFilter(appName);
@@ -47,7 +47,7 @@ export class ProcessFilterCloudService {
* @param appName Name of the target app * @param appName Name of the target app
* @returns Observable of process filter details * @returns Observable of process filter details
*/ */
getProcessFilters(appName: string): Observable<ProcessFilterRepresentationModel[]> { getProcessFilters(appName: string): Observable<ProcessFilterCloudModel[]> {
let key = 'process-filters-' + appName; let key = 'process-filters-' + appName;
const filters = JSON.parse(this.storage.getItem(key) || '[]'); const filters = JSON.parse(this.storage.getItem(key) || '[]');
return new Observable(function(observer) { 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 * Adds a new process instance filter
* @param filter The new filter to add * @param filter The new filter to add
* @returns Details of process filter just added * @returns Details of process filter just added
*/ */
addFilter(filter: ProcessFilterRepresentationModel) { addFilter(filter: ProcessFilterCloudModel) {
const key = 'process-filters-' + filter.query.appName; const key = 'process-filters-' + filter.appName;
const storedFilters = JSON.parse(this.storage.getItem(key) || '[]'); const storedFilters = JSON.parse(this.storage.getItem(key) || '[]');
storedFilters.push(filter); storedFilters.push(filter);
this.storage.setItem(key, JSON.stringify(storedFilters)); 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. * Creates and returns a filter for "All" Process instances.
* @param appName Name of the target app * @param appName Name of the target app
* @returns The newly created filter * @returns The newly created filter
*/ */
getAllProcessesFilter(appName: string): ProcessFilterRepresentationModel { getAllProcessesFilter(appName: string): ProcessFilterCloudModel {
return new ProcessFilterRepresentationModel({ return new ProcessFilterCloudModel({
name: 'ADF_CLOUD_PROCESS_FILTERS.ALL_PROCESSES', name: 'ADF_CLOUD_PROCESS_FILTERS.ALL_PROCESSES',
key: 'all-processes', key: 'all-processes',
icon: 'adjust', icon: 'adjust',
query: new ProcessQueryModel( appName: appName,
{ sort: 'startDate',
appName: appName, state: '',
sort: 'startDate', order: 'DESC'
order: 'DESC'
}
)
}); });
} }
@@ -94,19 +131,15 @@ export class ProcessFilterCloudService {
* @param appName Name of the target app * @param appName Name of the target app
* @returns The newly created filter * @returns The newly created filter
*/ */
getRunningProcessesFilter(appName: string): ProcessFilterRepresentationModel { getRunningProcessesFilter(appName: string): ProcessFilterCloudModel {
return new ProcessFilterRepresentationModel({ return new ProcessFilterCloudModel({
name: 'ADF_CLOUD_PROCESS_FILTERS.RUNNING_PROCESSES', name: 'ADF_CLOUD_PROCESS_FILTERS.RUNNING_PROCESSES',
icon: 'inbox', icon: 'inbox',
key: 'running-processes', key: 'running-processes',
query: new ProcessQueryModel( appName: appName,
{ sort: 'startDate',
appName: appName, state: 'RUNNING',
sort: 'startDate', order: 'DESC'
state: 'RUNNING',
order: 'DESC'
}
)
}); });
} }
@@ -115,19 +148,15 @@ export class ProcessFilterCloudService {
* @param appName Name of the target app * @param appName Name of the target app
* @returns The newly created filter * @returns The newly created filter
*/ */
getCompletedProcessesFilter(appName: string): ProcessFilterRepresentationModel { getCompletedProcessesFilter(appName: string): ProcessFilterCloudModel {
return new ProcessFilterRepresentationModel({ return new ProcessFilterCloudModel({
name: 'ADF_CLOUD_PROCESS_FILTERS.COMPLETED_PROCESSES', name: 'ADF_CLOUD_PROCESS_FILTERS.COMPLETED_PROCESSES',
icon: 'done', icon: 'done',
key: 'completed-processes', key: 'completed-processes',
query: new ProcessQueryModel( appName: appName,
{ sort: 'startDate',
appName: appName, state: 'COMPLETED',
sort: 'startDate', order: 'DESC'
state: 'COMPLETED',
order: 'DESC'
}
)
}); });
} }
} }

View File

@@ -19,5 +19,6 @@ export * from './lib/process-services-cloud.module';
export * from './lib/app-list-cloud/public-api'; export * from './lib/app-list-cloud/public-api';
export * from './lib/task-list-cloud/public-api'; export * from './lib/task-list-cloud/public-api';
export * from './lib/task-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/process-list-cloud/public_api';
export * from './lib/start-task-cloud/public-api'; export * from './lib/start-task-cloud/public-api';