diff --git a/demo-shell/src/app/components/cloud/processes-cloud-demo.component.html b/demo-shell/src/app/components/cloud/processes-cloud-demo.component.html index acb24cf12e..3876f194d9 100644 --- a/demo-shell/src/app/components/cloud/processes-cloud-demo.component.html +++ b/demo-shell/src/app/components/cloud/processes-cloud-demo.component.html @@ -13,6 +13,7 @@ fxFlex class="app-cloud-layout-overflow" [appName]="editedFilter.appName" + [appVersion]="editedFilter.appVersion" [initiator]="getInitiatorValue()" [processDefinitionId]="editedFilter.processDefinitionId" [processDefinitionName]="editedFilter.processDefinitionName" diff --git a/docs/process-services-cloud/components/process-list-cloud.component.md b/docs/process-services-cloud/components/process-list-cloud.component.md index e859743e74..d70e547a7a 100644 --- a/docs/process-services-cloud/components/process-list-cloud.component.md +++ b/docs/process-services-cloud/components/process-list-cloud.component.md @@ -52,7 +52,7 @@ when the process list is empty: | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | actionsPosition | `string` | "right" | Position of the actions dropdown menu. Can be "left" or "right". | | appName | `string` | "" | The name of the application. | -| appVersion | `number` | | The release version of the application. | +| appVersion | `number | number[]` | | The release version of the application. | | businessKey | `string` | "" | Filter the processes to display only the ones with this businessKey value. | | completedDate | `string` | "" | Filter the processes. Display only process with completedDate equal to the supplied date. | | completedFrom | `string` | "" | Filter the processes. Display only process with completedFrom equal to the supplied date. | diff --git a/lib/process-services-cloud/src/lib/app/services/apps-process-cloud.service.ts b/lib/process-services-cloud/src/lib/app/services/apps-process-cloud.service.ts index 7429816856..8fba07ee3c 100644 --- a/lib/process-services-cloud/src/lib/app/services/apps-process-cloud.service.ts +++ b/lib/process-services-cloud/src/lib/app/services/apps-process-cloud.service.ts @@ -31,7 +31,6 @@ export class AppsProcessCloudService { private apiService: AlfrescoApiService, private logService: LogService, private appConfigService: AppConfigService) { - this.loadApps(); } diff --git a/lib/process-services-cloud/src/lib/i18n/en.json b/lib/process-services-cloud/src/lib/i18n/en.json index 75126bd9cb..1f35ce8df9 100644 --- a/lib/process-services-cloud/src/lib/i18n/en.json +++ b/lib/process-services-cloud/src/lib/i18n/en.json @@ -214,7 +214,7 @@ "LAST_MODIFIED_DATE_FORM": "LastModifiedFrom", "LAST_MODIFIED_TO": "LastModifiedTo", "PROCESS_NAME": "Process Name", - "APP_VERSION": "AppReleaseVersion", + "APP_VERSION": "AppVersion", "STARTED_DATE": "Started Date", "STARTED_BY": "Started by", "COMPLETED_DATE": "Completed Date", diff --git a/lib/process-services-cloud/src/lib/models/application-version.model.ts b/lib/process-services-cloud/src/lib/models/application-version.model.ts new file mode 100644 index 0000000000..37025f33f8 --- /dev/null +++ b/lib/process-services-cloud/src/lib/models/application-version.model.ts @@ -0,0 +1,34 @@ +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Pagination } from '@alfresco/js-api'; + +export class ApplicationVersionModel { + entry: { + id: string; + name: string; + version: string; + }; + +} + +export class ApplicationVersionResponseModel { + list: { + entries: ApplicationVersionModel[]; + pagination: Pagination; + }; +} diff --git a/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.html b/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.html index 1fb770baa3..9f53e3fd14 100644 --- a/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.html +++ b/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.html @@ -34,6 +34,17 @@ + + + + {{ propertyOption.label | translate }} + + + { let component: EditProcessFilterCloudComponent; @@ -531,6 +532,49 @@ describe('EditProcessFilterCloudComponent', () => { }); })); + it('should fetch appVersionMultiple options when appVersionMultiple filter property is set', async () => { + const mockAppVersion1: ApplicationVersionModel = { + entry: { + id: 'mock-version-1-id', + name: 'mock-version-1-name', + version: '1' + } + }; + + const mockAppVersion2: ApplicationVersionModel = { + entry: { + id: 'mock-version-2-id', + name: 'mock-version-2-name', + version: '2' + } + }; + + const applicationVersionsSpy = spyOn(processService, 'getApplicationVersions').and.returnValue(of([mockAppVersion1, mockAppVersion2])); + fixture.detectChanges(); + + component.filterProperties = ['appVersionMultiple']; + fixture.detectChanges(); + + const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true); + component.ngOnChanges({ 'id': processFilterIdChange }); + fixture.detectChanges(); + + const controller = component.editProcessFilterForm.get('appVersionMultiple'); + const appVersionMultiple = fixture.debugElement.nativeElement.querySelector('[data-automation-id="adf-cloud-edit-process-property-appVersionMultiple"]'); + appVersionMultiple.click(); + + fixture.detectChanges(); + await fixture.whenStable(); + + const appVersionOptions = fixture.debugElement.queryAll(By.css('.mat-option-text')); + + expect(applicationVersionsSpy).toHaveBeenCalled(); + expect(controller).toBeDefined(); + expect(appVersionOptions.length).toEqual(2); + expect(appVersionOptions[0].nativeElement.innerText).toEqual('1'); + expect(appVersionOptions[1].nativeElement.innerText).toEqual('2'); + }); + it('should fetch process definitions when processDefinitionName filter property is set', async(() => { const processSpy = spyOn(processService, 'getProcessDefinitions').and.returnValue(of([{ id: 'fake-id', name: 'fake-name' }])); fixture.detectChanges(); diff --git a/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.ts b/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.ts index 9fc46eac05..abda341720 100644 --- a/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.ts @@ -30,6 +30,7 @@ import { ProcessFilterCloudService } from '../services/process-filter-cloud.serv import { ProcessFilterDialogCloudComponent } from './process-filter-dialog-cloud.component'; import { ProcessCloudService } from '../../services/process-cloud.service'; import { DateCloudFilterType, DateRangeFilter } from '../../../models/date-cloud-filter.model'; +import { ApplicationVersionModel } from '../../../models/application-version.model'; @Component({ selector: 'adf-cloud-edit-process-filter', @@ -114,6 +115,7 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes processFilterProperties: ProcessFilterProperties[] = []; processFilterActions: ProcessFilterAction[] = []; toggleFilterActions: boolean = false; + appVersionOptions: ProcessFilterOptions[]; private onDestroy$ = new Subject(); isLoading: boolean = false; @@ -219,6 +221,10 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes this.processDefinitionNames = []; this.getProcessDefinitions(); } + if (this.checkForProperty('appVersionMultiple')) { + this.appVersionOptions = []; + this.getAppVersionOptions(); + } const defaultProperties = this.createProcessFilterProperties(this.processFilter); let filteredProperties = defaultProperties.filter((filterProperty) => this.isValidProperty(this.filterProperties, filterProperty.key)); if (!this.hasSortProperty()) { @@ -265,6 +271,16 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes return defaultSortProperties.filter((sortProperty) => this.isValidProperty(this.sortProperties, sortProperty.key)); } + getAppVersionOptions() { + this.processCloudService.getApplicationVersions(this.appName) + .pipe(takeUntil(this.onDestroy$)) + .subscribe((appVersions: ApplicationVersionModel[]) => { + appVersions.forEach(appVersion => { + this.appVersionOptions.push({ label: appVersion.entry.version, value: appVersion.entry.version }); + }); + }); + } + checkMandatorySortProperties() { if (this.sortProperties === undefined || this.sortProperties.length === 0) { this.sortProperties = EditProcessFilterCloudComponent.DEFAULT_SORT_PROPERTIES; @@ -619,6 +635,13 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes key: 'appVersion', value: currentProcessFilter.appVersion }, + { + label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.APP_VERSION', + type: 'multi-select', + key: 'appVersionMultiple', + value: currentProcessFilter.appVersion, + options: this.appVersionOptions + }, { label: 'ADF_CLOUD_EDIT_PROCESS_FILTER.LABEL.PROCESS_INS_ID', type: 'text', diff --git a/lib/process-services-cloud/src/lib/process/process-filters/models/process-filter-cloud.model.ts b/lib/process-services-cloud/src/lib/process/process-filters/models/process-filter-cloud.model.ts index bf09533416..9245aafc4b 100644 --- a/lib/process-services-cloud/src/lib/process/process-filters/models/process-filter-cloud.model.ts +++ b/lib/process-services-cloud/src/lib/process/process-filters/models/process-filter-cloud.model.ts @@ -29,7 +29,7 @@ export class ProcessFilterCloudModel { icon: string; index: number; appName: string; - appVersion?: number; + appVersion?: number | number[]; processName: string; processInstanceId: string; initiator: IdentityUserModel[]; @@ -60,7 +60,7 @@ export class ProcessFilterCloudModel { this.icon = obj.icon || null; this.index = obj.index || null; this.appName = obj.appName || obj.appName === '' ? obj.appName : null; - this.appVersion = obj.appVersion || null; + this.appVersion = obj.appVersion ? obj.appVersion : (obj.appVersionMultiple instanceof Array ? obj.appVersionMultiple : null); this.processInstanceId = obj.processInstanceId || null; this.processName = obj.processName || null; this.initiator = obj.initiator || null; diff --git a/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.spec.ts index 30deb28b78..59788ad368 100644 --- a/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.spec.ts @@ -157,6 +157,30 @@ describe('ProcessListCloudComponent', () => { expect(component.rows.length).toEqual(3); }); + it('should the payload contain the appVersion if it is defined', () => { + spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList)); + component.appVersion = 1; + component.reload(); + + expect(component.requestNode.appVersion).toEqual('1'); + }); + + it('should the payload contain all the app versions joined by a comma separator', () => { + spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList)); + component.appVersion = [1, 2, 3]; + component.reload(); + + expect(component.requestNode.appVersion).toEqual('1,2,3'); + }); + + it('should the payload NOT contain any app version when appVersion does not have a value', () => { + spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList)); + component.appVersion = undefined; + component.reload(); + + expect(component.requestNode.appVersion).toEqual(''); + }); + it('should use the custom schemaColumn from app.config.json', () => { component.presetColumn = 'fakeCustomSchema'; component.ngAfterContentInit(); diff --git a/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.ts b/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.ts index f2dd082302..86b1b023ab 100644 --- a/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.ts @@ -47,9 +47,9 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan @Input() appName: string = ''; - /** The release version of the application. */ + /** The version of the application. */ @Input() - appVersion: number; + appVersion: number | number[]; /** Name of the initiator of the process. */ @Input() @@ -325,7 +325,7 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan private createRequestNode(): ProcessQueryCloudRequestModel { const requestNode = { appName: this.appName, - appVersion: this.appVersion, + appVersion: this.getAppVersions(), maxItems: this.size, skipCount: this.skipCount, initiator: this.initiator, @@ -348,6 +348,10 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan return new ProcessQueryCloudRequestModel(requestNode); } + getAppVersions(): string { + return this.appVersion instanceof Array ? this.appVersion.join(',') : (this.appVersion ? String(this.appVersion) : ''); + } + setSorting(sortDetail) { const sorting = sortDetail ? { orderBy: sortDetail.key.replace(ProcessListCloudComponent.ENTRY_PREFIX, ''), diff --git a/lib/process-services-cloud/src/lib/process/process-list/models/process-cloud-query-request.model.ts b/lib/process-services-cloud/src/lib/process/process-list/models/process-cloud-query-request.model.ts index 68193c70e6..521b831ff5 100644 --- a/lib/process-services-cloud/src/lib/process/process-list/models/process-cloud-query-request.model.ts +++ b/lib/process-services-cloud/src/lib/process/process-list/models/process-cloud-query-request.model.ts @@ -19,7 +19,7 @@ import { ProcessListCloudSortingModel } from './process-list-sorting.model'; export class ProcessQueryCloudRequestModel { appName: string; - appVersion?: number; + appVersion?: number | string; initiator?: null; id?: string; name?: string; diff --git a/lib/process-services-cloud/src/lib/process/services/process-cloud.service.ts b/lib/process-services-cloud/src/lib/process/services/process-cloud.service.ts index 214dd742fe..9686058262 100644 --- a/lib/process-services-cloud/src/lib/process/services/process-cloud.service.ts +++ b/lib/process-services-cloud/src/lib/process/services/process-cloud.service.ts @@ -18,10 +18,11 @@ import { AlfrescoApiService, LogService, AppConfigService } from '@alfresco/adf-core'; import { Injectable } from '@angular/core'; import { Observable, Subject, throwError } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { catchError, map } from 'rxjs/operators'; import { ProcessInstanceCloud } from '../start-process/models/process-instance-cloud.model'; import { BaseCloudService } from '../../services/base-cloud.service'; import { ProcessDefinitionCloud } from '../../models/process-definition-cloud.model'; +import { ApplicationVersionModel, ApplicationVersionResponseModel } from '../../models/application-version.model'; @Injectable({ providedIn: 'root' @@ -78,6 +79,27 @@ export class ProcessCloudService extends BaseCloudService { } } + /** + * Gets the application versions associated with an app. + * @param appName Name of the target app + * @returns Array of Application Version Models + */ + getApplicationVersions(appName: string): Observable { + if (appName) { + const url = `${this.getBasePath(appName)}/query/v1/applications`; + + return this.get(url).pipe( + map((appEntities: ApplicationVersionResponseModel) => { + return appEntities.list.entries; + }), + catchError((err) => this.handleError(err)) + ); + } else { + this.logService.error('AppName is mandatory for querying the versions of an application'); + return throwError('AppName not configured'); + } + } + /** * Cancels a process. * @param appName Name of the app @@ -98,4 +120,9 @@ export class ProcessCloudService extends BaseCloudService { return throwError('App name and process id not configured'); } } + + private handleError(error?: any) { + this.logService.error(error); + return throwError(error || 'Server error'); + } } diff --git a/lib/process-services-cloud/src/public-api.ts b/lib/process-services-cloud/src/public-api.ts index f5333d4af7..684e20185b 100644 --- a/lib/process-services-cloud/src/public-api.ts +++ b/lib/process-services-cloud/src/public-api.ts @@ -28,3 +28,4 @@ export * from './lib/pipes/process-name-cloud.pipe'; export * from './lib/pipes/process-services-cloud-pipe.module'; export * from './lib/models/process-definition-cloud.model'; export * from './lib/models/date-cloud-filter.model'; +export * from './lib/models/application-version.model';