mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-12 17:04:57 +00:00
[ADF-3543] Start Process Component for APS 2 (#4105)
* [ADF-3543] Start Process Component for APS 2 * [ADF-3543] Fix e2e tests * [ADF-3543] Process filter data automation id with process key * [ADF-3543] Fix Process Services e2e tests * [ADF-3543] Fix Search e2e tests * [ADF-3543] Fix Search e2e tests
This commit is contained in:
parent
dd25467a98
commit
2acd1b4e26
@ -74,6 +74,7 @@ import { StartTaskCloudDemoComponent } from './components/app-layout/cloud/start
|
|||||||
import { CloudBreadcrumbsComponent } from './components/app-layout/cloud/cloud-breadcrumb-component';
|
import { CloudBreadcrumbsComponent } from './components/app-layout/cloud/cloud-breadcrumb-component';
|
||||||
import { TasksCloudDemoComponent } from './components/app-layout/cloud/tasks-cloud-demo.component';
|
import { TasksCloudDemoComponent } from './components/app-layout/cloud/tasks-cloud-demo.component';
|
||||||
import { CloudFiltersDemoComponent } from './components/app-layout/cloud/cloud-filters-demo.component';
|
import { CloudFiltersDemoComponent } from './components/app-layout/cloud/cloud-filters-demo.component';
|
||||||
|
import { StartProcessCloudDemoComponent } from './components/app-layout/cloud/start-process-cloud-demo.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -130,6 +131,7 @@ import { CloudFiltersDemoComponent } from './components/app-layout/cloud/cloud-f
|
|||||||
ProcessesCloudDemoComponent,
|
ProcessesCloudDemoComponent,
|
||||||
TaskDetailsCloudDemoComponent,
|
TaskDetailsCloudDemoComponent,
|
||||||
StartTaskCloudDemoComponent,
|
StartTaskCloudDemoComponent,
|
||||||
|
StartProcessCloudDemoComponent,
|
||||||
CloudBreadcrumbsComponent,
|
CloudBreadcrumbsComponent,
|
||||||
CloudFiltersDemoComponent
|
CloudFiltersDemoComponent
|
||||||
],
|
],
|
||||||
|
@ -29,10 +29,8 @@ import { FormNodeViewerComponent } from './components/process-service/form-node-
|
|||||||
import { AppsViewComponent } from './components/process-service/apps-view.component';
|
import { AppsViewComponent } from './components/process-service/apps-view.component';
|
||||||
import { SearchResultComponent } from './components/search/search-result.component';
|
import { SearchResultComponent } from './components/search/search-result.component';
|
||||||
import { SearchExtendedComponent } from './components/search/search-extended.component';
|
import { SearchExtendedComponent } from './components/search/search-extended.component';
|
||||||
|
|
||||||
import { FilesComponent } from './components/files/files.component';
|
import { FilesComponent } from './components/files/files.component';
|
||||||
import { FormComponent } from './components/form/form.component';
|
import { FormComponent } from './components/form/form.component';
|
||||||
|
|
||||||
import { FormListComponent } from './components/form/form-list.component';
|
import { FormListComponent } from './components/form/form-list.component';
|
||||||
import { OverlayViewerComponent } from './components/overlay-viewer/overlay-viewer.component';
|
import { OverlayViewerComponent } from './components/overlay-viewer/overlay-viewer.component';
|
||||||
import { SharedLinkViewComponent } from './components/shared-link-view/shared-link-view.component';
|
import { SharedLinkViewComponent } from './components/shared-link-view/shared-link-view.component';
|
||||||
@ -47,6 +45,7 @@ import { TaskDetailsCloudDemoComponent } from './components/app-layout/cloud/tas
|
|||||||
import { AppsCloudDemoComponent } from './components/app-layout/cloud/apps-cloud-demo.component';
|
import { AppsCloudDemoComponent } from './components/app-layout/cloud/apps-cloud-demo.component';
|
||||||
import { TasksCloudDemoComponent } from './components/app-layout/cloud/tasks-cloud-demo.component';
|
import { TasksCloudDemoComponent } from './components/app-layout/cloud/tasks-cloud-demo.component';
|
||||||
import { StartTaskCloudDemoComponent } from './components/app-layout/cloud/start-task-cloud-demo.component';
|
import { StartTaskCloudDemoComponent } from './components/app-layout/cloud/start-task-cloud-demo.component';
|
||||||
|
import { StartProcessCloudDemoComponent } from './components/app-layout/cloud/start-process-cloud-demo.component';
|
||||||
|
|
||||||
export const appRoutes: Routes = [
|
export const appRoutes: Routes = [
|
||||||
{ path: 'login', component: LoginComponent },
|
{ path: 'login', component: LoginComponent },
|
||||||
@ -167,6 +166,10 @@ export const appRoutes: Routes = [
|
|||||||
path: 'start-task',
|
path: 'start-task',
|
||||||
component: StartTaskCloudDemoComponent
|
component: StartTaskCloudDemoComponent
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'start-process',
|
||||||
|
component: StartProcessCloudDemoComponent
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'task-details/:taskId',
|
path: 'task-details/:taskId',
|
||||||
component: TaskDetailsCloudDemoComponent
|
component: TaskDetailsCloudDemoComponent
|
||||||
|
@ -9,13 +9,19 @@
|
|||||||
<ng-template>
|
<ng-template>
|
||||||
<adf-sidebar-action-menu [expanded]="true" [width]="205"
|
<adf-sidebar-action-menu [expanded]="true" [width]="205"
|
||||||
title="{{'ADF_SIDEBAR_ACTION_MENU.BUTTON.CREATE' | translate}}">
|
title="{{'ADF_SIDEBAR_ACTION_MENU.BUTTON.CREATE' | translate}}">
|
||||||
<mat-icon sidebar-menu-title-icon>arrow_drop_down</mat-icon>
|
<mat-icon sidebar-menu-title-icon>arrow_drop_down</mat-icon>
|
||||||
<div sidebar-menu-options>
|
<div sidebar-menu-options>
|
||||||
<button mat-menu-item data-automation-id="btn-start-task" (click)="onStartTask()">
|
<button mat-menu-item data-automation-id="btn-start-task" (click)="onStartTask()">
|
||||||
<mat-icon>assessment</mat-icon>
|
<mat-icon>assessment</mat-icon>
|
||||||
<span>{{'ADF_SIDEBAR_ACTION_MENU.BUTTON.NEW_TASK' | translate}}</span>
|
<span>{{'ADF_SIDEBAR_ACTION_MENU.BUTTON.NEW_TASK' | translate}}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div sidebar-menu-options>
|
||||||
|
<button mat-menu-item data-automation-id="btn-start-process" (click)="onStartProcess()">
|
||||||
|
<mat-icon>assessment</mat-icon>
|
||||||
|
<span>{{'ADF_SIDEBAR_ACTION_MENU.BUTTON.NEW_PROCESS' | translate}}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</adf-sidebar-action-menu>
|
</adf-sidebar-action-menu>
|
||||||
<app-cloud-filters-demo [appName]="applicationName"></app-cloud-filters-demo>
|
<app-cloud-filters-demo [appName]="applicationName"></app-cloud-filters-demo>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -39,4 +39,8 @@ export class CloudLayoutComponent implements OnInit {
|
|||||||
onStartTask() {
|
onStartTask() {
|
||||||
this.router.navigate([`/cloud/${this.applicationName}/start-task/`]);
|
this.router.navigate([`/cloud/${this.applicationName}/start-task/`]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onStartProcess() {
|
||||||
|
this.router.navigate([`/cloud/${this.applicationName}/start-process/`]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
<adf-cloud-start-process
|
||||||
|
[appName]="applicationName"
|
||||||
|
[name]="processName"
|
||||||
|
(error)="openSnackMessage($event)"
|
||||||
|
(success)="onStartProcessSuccess()"
|
||||||
|
(cancel)="onCancelStartProcess()">
|
||||||
|
</adf-cloud-start-process>
|
@ -0,0 +1,61 @@
|
|||||||
|
/*!
|
||||||
|
* @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, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { NotificationService, AppConfigService } from '@alfresco/adf-core';
|
||||||
|
import { CloudLayoutService } from './services/cloud-layout.service';
|
||||||
|
@Component({
|
||||||
|
templateUrl: './start-process-cloud-demo.component.html',
|
||||||
|
styleUrls: ['./start-process-cloud-demo.component.scss']
|
||||||
|
})
|
||||||
|
export class StartProcessCloudDemoComponent implements OnInit {
|
||||||
|
|
||||||
|
applicationName;
|
||||||
|
processName: string;
|
||||||
|
|
||||||
|
constructor(private appConfig: AppConfigService,
|
||||||
|
private cloudLayoutService: CloudLayoutService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private notificationService: NotificationService,
|
||||||
|
private router: Router) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.route.parent.params.subscribe((params) => {
|
||||||
|
this.applicationName = params.applicationName;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.processName = this.appConfig.get<string>('adf-start-process.name');
|
||||||
|
}
|
||||||
|
|
||||||
|
onStartProcessSuccess() {
|
||||||
|
this.router.navigate([`/cloud/${this.applicationName}`]);
|
||||||
|
this.cloudLayoutService.setCurrentProcessFilterParam({ key: 'running-processes' });
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelStartProcess() {
|
||||||
|
this.router.navigate([`/cloud/${this.applicationName}`]);
|
||||||
|
}
|
||||||
|
|
||||||
|
openSnackMessage(event: any) {
|
||||||
|
this.notificationService.openSnackMessage(
|
||||||
|
event.response.body.message,
|
||||||
|
4000
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
49
docs/process-services-cloud/start-process-cloud.component.md
Executable file
49
docs/process-services-cloud/start-process-cloud.component.md
Executable file
@ -0,0 +1,49 @@
|
|||||||
|
# Start Process Cloud Component
|
||||||
|
|
||||||
|
Starts a process.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Basic Usage
|
||||||
|
|
||||||
|
```html
|
||||||
|
<adf-cloud-start-process
|
||||||
|
[appName]="YOUR_APP_NAME">
|
||||||
|
</adf-cloud-start-process>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Class members
|
||||||
|
|
||||||
|
### Properties
|
||||||
|
|
||||||
|
| Name | Type | Default value | Description |
|
||||||
|
| ---- | ---- | ------------- | ----------- |
|
||||||
|
| appName | `string` | | Limit the list of processes that can be started to those contained in the specified app. |
|
||||||
|
| name | `string` | "" | (optional) Name to assign to the current process. |
|
||||||
|
| processDefinitionName | `string` | | (optional) Definition name of the process to start. |
|
||||||
|
| showSelectProcessDropdown | `boolean` | true | (optional) Hide or show the process selection dropdown. |
|
||||||
|
| variables | `Map<string, any>[]` | | (optional) Variables in the input to the process. |
|
||||||
|
|
||||||
|
### Events
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ---- | ----------- |
|
||||||
|
| cancel | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessInstanceCloud`](../../lib/process-services-cloud/src/lib/process-cloud/models/process-instance-cloud.model.ts)`>` | Emitted when the process is canceled. |
|
||||||
|
| error | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessInstanceCloud`](../../lib/process-services-cloud/src/lib/process-cloud/models/process-instance-cloud.model.ts)`>` | Emitted when an error occurs. |
|
||||||
|
| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ProcessInstanceCloud`](../../lib/process-services-cloud/src/lib/process-cloud/models/process-instance-cloud.model.ts)`>` | Emitted when the process starts. |
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
### Starting a process with a default name and a pre-selected process definition name
|
||||||
|
|
||||||
|
```html
|
||||||
|
<adf-cloud-start-process
|
||||||
|
[appId]="YOUR_APP_ID"
|
||||||
|
[name]="PROCESS_NAME"
|
||||||
|
[processDefinitionName]="PROCESS_DEFINITION_NAME">
|
||||||
|
</adf-cloud-start-process>
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use the `processDefinitionName` property to select which process will be selected by default on the dropdown (when there is more than one process to choose from). Use the `name` property to set the name shown on the dropdown item.
|
||||||
|
|
||||||
|
If the app contains only one process definition, this process definition will be selected by default
|
@ -24,9 +24,9 @@ import { element, by } from 'protractor';
|
|||||||
|
|
||||||
export class ProcessCloudDemoPage {
|
export class ProcessCloudDemoPage {
|
||||||
|
|
||||||
allProcesses = element(by.css('span[data-automation-id="ADF_CLOUD_PROCESS_FILTERS.ALL_PROCESSES_filter"]'));
|
allProcesses = element(by.css('span[data-automation-id="all-processes_filter"]'));
|
||||||
runningProcesses = element(by.css('span[data-automation-id="ADF_CLOUD_PROCESS_FILTERS.RUNNING_PROCESSES_filter"]'));
|
runningProcesses = element(by.css('span[data-automation-id="running-processes_filter"]'));
|
||||||
completedProcesses = element(by.css('span[data-automation-id="ADF_CLOUD_PROCESS_FILTERS.COMPLETED_PROCESSES_filter"]'));
|
completedProcesses = element(by.css('span[data-automation-id="completed-processes_filter"]'));
|
||||||
activeFilter = element(by.css("mat-list-item[class*='active'] span"));
|
activeFilter = element(by.css("mat-list-item[class*='active'] span"));
|
||||||
processFilters = element(by.css("mat-expansion-panel[data-automation-id='Process Filters']"));
|
processFilters = element(by.css("mat-expansion-panel[data-automation-id='Process Filters']"));
|
||||||
|
|
||||||
|
@ -62,10 +62,6 @@ export class DatePickerPage {
|
|||||||
return `${('0' + date.getDate()).slice(-2)}-${this.months[date.getMonth()]}-${date.getFullYear().toString().substr(-2)}`;
|
return `${('0' + date.getDate()).slice(-2)}-${this.months[date.getMonth()]}-${date.getFullYear().toString().substr(-2)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
convertDateToNewFormat(date) { // Format : mm-dd-yy
|
|
||||||
return `${date.getMonth() + 1}-${('0' + date.getDate()).slice(-2)}-${date.getFullYear().toString().substr(-2)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
selectTodayDate() {
|
selectTodayDate() {
|
||||||
this.checkDatePickerIsDisplayed();
|
this.checkDatePickerIsDisplayed();
|
||||||
let todayDate = element(by.css('.mat-calendar-body-today'));
|
let todayDate = element(by.css('.mat-calendar-body-today'));
|
||||||
|
@ -29,6 +29,7 @@ import TestConfig = require('../../test.config');
|
|||||||
|
|
||||||
import AlfrescoApi = require('alfresco-js-api-node');
|
import AlfrescoApi = require('alfresco-js-api-node');
|
||||||
import { browser } from 'protractor';
|
import { browser } from 'protractor';
|
||||||
|
import moment from 'moment-es6';
|
||||||
|
|
||||||
describe('Search Date Range Filter', () => {
|
describe('Search Date Range Filter', () => {
|
||||||
|
|
||||||
@ -199,6 +200,7 @@ describe('Search Date Range Filter', () => {
|
|||||||
describe('configuration change', () => {
|
describe('configuration change', () => {
|
||||||
|
|
||||||
let jsonFile;
|
let jsonFile;
|
||||||
|
let dateFormat = 'MM-DD-YY';
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
let searchConfiguration = new SearchConfiguration();
|
let searchConfiguration = new SearchConfiguration();
|
||||||
@ -206,7 +208,7 @@ describe('Search Date Range Filter', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('[C277117] Should be able to change date format', () => {
|
it('[C277117] Should be able to change date format', () => {
|
||||||
jsonFile.categories[4].component.settings.dateFormat = 'MM-DD-YY';
|
jsonFile.categories[4].component.settings.dateFormat = dateFormat;
|
||||||
|
|
||||||
navigationBar.clickConfigEditorButton();
|
navigationBar.clickConfigEditorButton();
|
||||||
configEditor.clickSearchConfiguration();
|
configEditor.clickSearchConfiguration();
|
||||||
@ -221,7 +223,7 @@ describe('Search Date Range Filter', () => {
|
|||||||
dateRangeFilter.checkFromFieldIsDisplayed()
|
dateRangeFilter.checkFromFieldIsDisplayed()
|
||||||
.openFromDatePicker();
|
.openFromDatePicker();
|
||||||
|
|
||||||
let todayDate = datePicker.convertDateToNewFormat(new Date());
|
let todayDate = moment().format(dateFormat);
|
||||||
datePicker.selectTodayDate();
|
datePicker.selectTodayDate();
|
||||||
|
|
||||||
browser.controlFlow().execute(async () => {
|
browser.controlFlow().execute(async () => {
|
||||||
|
@ -2,18 +2,40 @@
|
|||||||
"ADF_CLOUD_PROCESS_LIST": {
|
"ADF_CLOUD_PROCESS_LIST": {
|
||||||
"MESSAGES": {
|
"MESSAGES": {
|
||||||
"TITLE": "No Processes Found",
|
"TITLE": "No Processes Found",
|
||||||
"SUBTITLE":"Create a new process that you want to easily find later",
|
"SUBTITLE": "Create a new process that you want to easily find later",
|
||||||
"NONE": "No process instance filter selected."
|
"NONE": "No process instance filter selected."
|
||||||
},
|
},
|
||||||
"PROPERTIES": {
|
"PROPERTIES": {
|
||||||
"NAME": "Name",
|
"NAME": "Name",
|
||||||
"CREATED": "Created"
|
"CREATED": "Created"
|
||||||
|
},
|
||||||
|
"ADF_CLOUD_START_PROCESS": {
|
||||||
|
"BUTTON": "Start Process",
|
||||||
|
"NO_PROCESS_DEFINITIONS": "You can't start a process as there are no process definitions available",
|
||||||
|
"FORM": {
|
||||||
|
"TITLE": "Start Process",
|
||||||
|
"LABEL": {
|
||||||
|
"TYPE": "Select Process",
|
||||||
|
"NAME": "Process Name"
|
||||||
|
},
|
||||||
|
"TYPE_PLACEHOLDER": "Choose one...",
|
||||||
|
"ACTION": {
|
||||||
|
"START": "Start Process",
|
||||||
|
"CANCEL": "Cancel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ERROR": {
|
||||||
|
"LOAD_PROCESS_DEFS": "Couldn't load process definitions, check you have access.",
|
||||||
|
"START": "Couldn't start new process instance, check you have access.",
|
||||||
|
"PROCESS_NAME_REQUIRED": "Process Name is required",
|
||||||
|
"PROCESS_DEFINITION_REQUIRED": "Process Definition is required"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ADF_CLOUD_TASK_LIST": {
|
"ADF_CLOUD_TASK_LIST": {
|
||||||
"APPS": {
|
"APPS": {
|
||||||
"TITLE": "No Applications Found",
|
"TITLE": "No Applications Found",
|
||||||
"SUBTITLE":"Create a new application that you want to easily find later"
|
"SUBTITLE": "Create a new application that you want to easily find later"
|
||||||
},
|
},
|
||||||
"START_TASK": {
|
"START_TASK": {
|
||||||
"FORM": {
|
"FORM": {
|
||||||
@ -40,7 +62,7 @@
|
|||||||
"LIST": {
|
"LIST": {
|
||||||
"MESSAGES": {
|
"MESSAGES": {
|
||||||
"TITLE": "No Tasks Found",
|
"TITLE": "No Tasks Found",
|
||||||
"SUBTITLE":"Create a new task that you want to easily find later",
|
"SUBTITLE": "Create a new task that you want to easily find later",
|
||||||
"NONE": "No task lists found"
|
"NONE": "No task lists found"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,15 +18,13 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { TRANSLATION_PROVIDER } from '@alfresco/adf-core';
|
import { TRANSLATION_PROVIDER } from '@alfresco/adf-core';
|
||||||
import { AppListCloudModule } from './app/app-list-cloud.module';
|
import { AppListCloudModule } from './app/app-list-cloud.module';
|
||||||
import { ProcessListCloudModule } from './process/process-list/process-list-cloud.module';
|
|
||||||
import { ProcessFiltersCloudModule } from './process/process-filters/process-filters-cloud.module';
|
|
||||||
import { TaskCloudModule } from './task/task-cloud.module';
|
import { TaskCloudModule } from './task/task-cloud.module';
|
||||||
|
import { ProcessCloudModule } from './process/process-cloud.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
AppListCloudModule,
|
AppListCloudModule,
|
||||||
ProcessListCloudModule,
|
ProcessCloudModule,
|
||||||
ProcessFiltersCloudModule,
|
|
||||||
TaskCloudModule
|
TaskCloudModule
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
@ -41,8 +39,7 @@ import { TaskCloudModule } from './task/task-cloud.module';
|
|||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
AppListCloudModule,
|
AppListCloudModule,
|
||||||
ProcessListCloudModule,
|
ProcessCloudModule,
|
||||||
ProcessFiltersCloudModule,
|
|
||||||
TaskCloudModule
|
TaskCloudModule
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@ -18,15 +18,18 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { ProcessFiltersCloudModule } from './process-filters/process-filters-cloud.module';
|
import { ProcessFiltersCloudModule } from './process-filters/process-filters-cloud.module';
|
||||||
import { ProcessListCloudModule } from './process-list/process-list-cloud.module';
|
import { ProcessListCloudModule } from './process-list/process-list-cloud.module';
|
||||||
|
import { StartProcessCloudModule } from './start-process/start-process-cloud.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
ProcessFiltersCloudModule,
|
ProcessFiltersCloudModule,
|
||||||
ProcessListCloudModule
|
ProcessListCloudModule,
|
||||||
|
StartProcessCloudModule
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
ProcessFiltersCloudModule,
|
ProcessFiltersCloudModule,
|
||||||
ProcessListCloudModule
|
ProcessListCloudModule,
|
||||||
|
StartProcessCloudModule
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class ProcessCloudModule { }
|
export class ProcessCloudModule { }
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
class="adf-filters__entry" [class.adf-active]="currentFilter === filter">
|
class="adf-filters__entry" [class.adf-active]="currentFilter === filter">
|
||||||
<mat-icon *ngIf="showIcons && filter.icon" matListIcon class="adf-filters__entry-icon">{{filter.icon}}
|
<mat-icon *ngIf="showIcons && filter.icon" matListIcon class="adf-filters__entry-icon">{{filter.icon}}
|
||||||
</mat-icon>
|
</mat-icon>
|
||||||
<span matLine [attr.data-automation-id]="filter.name + '_filter'">{{filter.name | translate}}</span>
|
<span matLine [attr.data-automation-id]="filter.key + '_filter'">{{filter.name | translate}}</span>
|
||||||
</mat-list-item>
|
</mat-list-item>
|
||||||
</mat-list>
|
</mat-list>
|
||||||
<ng-template #loading>
|
<ng-template #loading>
|
||||||
|
@ -40,6 +40,7 @@ describe('ProcessFiltersCloudComponent', () => {
|
|||||||
}),
|
}),
|
||||||
new ProcessFilterCloudModel({
|
new ProcessFilterCloudModel({
|
||||||
name: 'FakeRunningProcesses',
|
name: 'FakeRunningProcesses',
|
||||||
|
key: 'FakeRunningProcesses',
|
||||||
icon: 'inbox',
|
icon: 'inbox',
|
||||||
id: '11',
|
id: '11',
|
||||||
state: 'RUNNING'
|
state: 'RUNNING'
|
||||||
|
@ -17,4 +17,6 @@
|
|||||||
|
|
||||||
export * from './process-list/public-api';
|
export * from './process-list/public-api';
|
||||||
export * from './process-filters/public-api';
|
export * from './process-filters/public-api';
|
||||||
|
export * from './start-process/public-api';
|
||||||
|
|
||||||
export * from './process-cloud.module';
|
export * from './process-cloud.module';
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
<mat-card class="adf-start-process">
|
||||||
|
|
||||||
|
<mat-card-title>{{'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.TITLE' | translate}}
|
||||||
|
</mat-card-title>
|
||||||
|
|
||||||
|
<mat-card-content *ngIf="!isProcessDefinitionsEmpty(); else emptyProcessDefinitionsList">
|
||||||
|
<mat-card-subtitle id="error-message" *ngIf="errorMessageId">
|
||||||
|
{{ errorMessageId | translate }}
|
||||||
|
</mat-card-subtitle>
|
||||||
|
|
||||||
|
<form [formGroup]="processForm">
|
||||||
|
<mat-form-field class="adf-process-input-container">
|
||||||
|
<mat-label>{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.LABEL.NAME' | translate }}</mat-label>
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
formControlName="processInstanceName"
|
||||||
|
id="processName">
|
||||||
|
<mat-error *ngIf="processInstanceName.hasError('required')">
|
||||||
|
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.PROCESS_NAME_REQUIRED' | translate }}
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="adf-process-input-container">
|
||||||
|
<mat-label>{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.LABEL.TYPE' | translate }}</mat-label>
|
||||||
|
<input
|
||||||
|
#inputAutocomplete
|
||||||
|
matInput
|
||||||
|
formControlName="processDefinition"
|
||||||
|
[matAutocomplete]="auto"
|
||||||
|
id="processDefinitionName">
|
||||||
|
<div class="adf-process-input-autocomplete">
|
||||||
|
<mat-autocomplete #auto="matAutocomplete" id="processDefinitionOptions" [displayWith]="displayProcessNameOnDropdown">
|
||||||
|
<mat-option *ngFor="let processDef of filteredProcesses" [value]="processDef.name">
|
||||||
|
{{ processDef.name }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-autocomplete>
|
||||||
|
<button id="adf-select-process-dropdown" *ngIf="showSelectProcessDropdown" mat-icon-button (click)="displayDropdown($event)">
|
||||||
|
<mat-icon>arrow_drop_down</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<mat-error *ngIf="processDefinition.hasError('required')">
|
||||||
|
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.PROCESS_DEFINITION_REQUIRED' | translate }}
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-card-content>
|
||||||
|
|
||||||
|
<ng-template #emptyProcessDefinitionsList>
|
||||||
|
<mat-card-content>
|
||||||
|
<mat-card-subtitle class="error-message" id="no-process-message">
|
||||||
|
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.NO_PROCESS_DEFINITIONS' | translate | uppercase}}
|
||||||
|
</mat-card-subtitle>
|
||||||
|
</mat-card-content>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<mat-card-actions>
|
||||||
|
<button mat-button (click)="cancelStartProcess()" id="cancel_process">
|
||||||
|
{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.ACTION.CANCEL' | translate | uppercase}}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
color="primary"
|
||||||
|
mat-button
|
||||||
|
[disabled]="!processForm.valid || isLoading"
|
||||||
|
(click)="startProcess()"
|
||||||
|
data-automation-id="btn-start"
|
||||||
|
id="button-start" class="btn-start">
|
||||||
|
{{'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.ACTION.START' | translate | uppercase}}
|
||||||
|
</button>
|
||||||
|
</mat-card-actions>
|
||||||
|
</mat-card>
|
@ -0,0 +1,56 @@
|
|||||||
|
.adf {
|
||||||
|
&-start-process {
|
||||||
|
width: 66%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
.mat-select-trigger {
|
||||||
|
font-size: 14px !important;
|
||||||
|
}
|
||||||
|
mat-form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
mat-select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px 0 0;
|
||||||
|
}
|
||||||
|
mat-card-actions {
|
||||||
|
text-align: right;
|
||||||
|
.mat-button {
|
||||||
|
text-transform: uppercase !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-process-input-container {
|
||||||
|
mat-form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-process-input-autocomplete {
|
||||||
|
display: flex;
|
||||||
|
button {
|
||||||
|
position: absolute;
|
||||||
|
right: -14px;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-start-form-container {
|
||||||
|
.mat-card {
|
||||||
|
box-shadow: none !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-start-form-actions {
|
||||||
|
text-align: right !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.adf-start-process {
|
||||||
|
width: 90%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,380 @@
|
|||||||
|
/*!
|
||||||
|
* @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 { SimpleChange } from '@angular/core';
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { setupTestBed } from '@alfresco/adf-core';
|
||||||
|
import { of, throwError } from 'rxjs';
|
||||||
|
import { StartProcessCloudService } from '../services/start-process-cloud.service';
|
||||||
|
|
||||||
|
import { StartProcessCloudComponent } from './start-process-cloud.component';
|
||||||
|
import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module';
|
||||||
|
import { ProcessCloudModule } from '../../process-cloud.module';
|
||||||
|
import { fakeProcessDefinitions, fakeProcessInstance, fakeProcessPayload } from '../mock/start-process.component.mock';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
describe('StartProcessCloudComponent', () => {
|
||||||
|
|
||||||
|
let component: StartProcessCloudComponent;
|
||||||
|
let fixture: ComponentFixture<StartProcessCloudComponent>;
|
||||||
|
let processService: StartProcessCloudService;
|
||||||
|
let getDefinitionsSpy: jasmine.Spy;
|
||||||
|
let startProcessSpy: jasmine.Spy;
|
||||||
|
|
||||||
|
setupTestBed({
|
||||||
|
imports: [
|
||||||
|
ProcessServiceCloudTestingModule,
|
||||||
|
ProcessCloudModule
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
processService = TestBed.get(StartProcessCloudService);
|
||||||
|
fixture = TestBed.createComponent(StartProcessCloudComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
|
||||||
|
getDefinitionsSpy = spyOn(processService, 'getProcessDefinitions').and.returnValue(of(fakeProcessDefinitions));
|
||||||
|
startProcessSpy = spyOn(processService, 'startProcess').and.returnValue(of(fakeProcessInstance));
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fixture.destroy();
|
||||||
|
TestBed.resetTestingModule();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create instance of StartProcessInstanceComponent', () => {
|
||||||
|
expect(fixture.componentInstance instanceof StartProcessCloudComponent).toBe(true, 'should create StartProcessInstanceComponent');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('first step', () => {
|
||||||
|
|
||||||
|
describe('without start form', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
component.name = 'My new process';
|
||||||
|
component.appName = 'myApp';
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should enable start button when name and process filled out', async(() => {
|
||||||
|
spyOn(component, 'loadProcessDefinitions').and.callThrough();
|
||||||
|
component.processDefinitionList = fakeProcessDefinitions;
|
||||||
|
component.processForm.controls['processInstanceName'].setValue('My Process 1');
|
||||||
|
component.processForm.controls['processDefinition'].setValue('NewProcess 1');
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let startBtn = fixture.nativeElement.querySelector('#button-start');
|
||||||
|
expect(startBtn.disabled).toBe(false);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should have start button disabled when name not filled out', async(() => {
|
||||||
|
spyOn(component, 'loadProcessDefinitions').and.callThrough();
|
||||||
|
component.processForm.controls['processInstanceName'].setValue('');
|
||||||
|
component.processForm.controls['processDefinition'].setValue(fakeProcessInstance.name);
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let startBtn = fixture.nativeElement.querySelector('#button-start');
|
||||||
|
expect(startBtn.disabled).toBe(true);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should have start button disabled when no process is selected', async(() => {
|
||||||
|
component.processPayloadCloud.processDefinitionKey = null;
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let startBtn = fixture.nativeElement.querySelector('#button-start');
|
||||||
|
expect(startBtn.disabled).toBe(true);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('process definitions list', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.name = 'My new process';
|
||||||
|
component.appName = 'myApp';
|
||||||
|
fixture.detectChanges();
|
||||||
|
let change = new SimpleChange(null, 'MyApp', true);
|
||||||
|
component.ngOnChanges({ 'appName': change });
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call service to fetch process definitions with appId', () => {
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(getDefinitionsSpy).toHaveBeenCalledWith('myApp');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display the correct number of processes in the select list', () => {
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let selectElement = fixture.nativeElement.querySelector('mat-select');
|
||||||
|
expect(selectElement.children.length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display the option def details', () => {
|
||||||
|
component.processDefinitionList = fakeProcessDefinitions;
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let selectElement = fixture.nativeElement.querySelector('mat-select > .mat-select-trigger');
|
||||||
|
let optionElement = fixture.nativeElement.querySelectorAll('mat-option');
|
||||||
|
selectElement.click();
|
||||||
|
expect(selectElement).not.toBeNull();
|
||||||
|
expect(selectElement).toBeDefined();
|
||||||
|
expect(optionElement).not.toBeNull();
|
||||||
|
expect(optionElement).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should indicate an error to the user if process defs cannot be loaded', async(() => {
|
||||||
|
getDefinitionsSpy = getDefinitionsSpy.and.returnValue(throwError({}));
|
||||||
|
let change = new SimpleChange('myApp', 'myApp1', true);
|
||||||
|
component.ngOnChanges({ appName: change });
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let errorEl = fixture.nativeElement.querySelector('#error-message');
|
||||||
|
expect(errorEl.innerText.trim()).toBe('ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.LOAD_PROCESS_DEFS');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should show no process available message when no process definition is loaded', async(() => {
|
||||||
|
getDefinitionsSpy = getDefinitionsSpy.and.returnValue(of([]));
|
||||||
|
let change = new SimpleChange('myApp', 'myApp1', true);
|
||||||
|
component.ngOnChanges({ appName: change });
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
const noProcessElement = fixture.nativeElement.querySelector('#no-process-message');
|
||||||
|
expect(noProcessElement).not.toBeNull('Expected no available process message to be present');
|
||||||
|
expect(noProcessElement.innerText.trim()).toBe('ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.NO_PROCESS_DEFINITIONS');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should select processDefinition based on processDefinition input', async(() => {
|
||||||
|
getDefinitionsSpy = getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
|
component.processForm.controls['processInstanceName'].setValue('NewProcess 1');
|
||||||
|
component.processForm.controls['processDefinition'].setValue('NewProcess 1');
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(component.processPayloadCloud.processDefinitionKey).toBe(JSON.parse(JSON.stringify(fakeProcessDefinitions[0])).name);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should select automatically the processDefinition if the app contain only one', async(() => {
|
||||||
|
getDefinitionsSpy = getDefinitionsSpy.and.returnValue(of([fakeProcessDefinitions[0]]));
|
||||||
|
let change = new SimpleChange('myApp', 'myApp1', true);
|
||||||
|
component.ngOnChanges({ appName: change });
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(component.processForm.controls['processDefinition'].value).toBe(JSON.parse(JSON.stringify(fakeProcessDefinitions[0])).name);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should not select automatically any processDefinition if the app contain multiple process and does not have any processDefinition as input', async(() => {
|
||||||
|
getDefinitionsSpy = getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
|
component.appName = 'myApp';
|
||||||
|
component.ngOnChanges({});
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(component.processPayloadCloud.processInstanceName).toBeNull();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('dropdown', () => {
|
||||||
|
|
||||||
|
it('should hide the process dropdown button if showSelectProcessDropdown is false', async(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
getDefinitionsSpy = getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
|
component.appName = 'myApp';
|
||||||
|
component.showSelectProcessDropdown = false;
|
||||||
|
component.ngOnChanges({});
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let selectElement = fixture.nativeElement.querySelector('button#adf-select-process-dropdown');
|
||||||
|
expect(selectElement).toBeNull();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should show the process dropdown button if showSelectProcessDropdown is false', async(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
getDefinitionsSpy = getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
|
component.appName = 'myApp';
|
||||||
|
component.processDefinitionName = 'NewProcess 2';
|
||||||
|
component.showSelectProcessDropdown = true;
|
||||||
|
component.ngOnChanges({});
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let selectElement = fixture.nativeElement.querySelector('button#adf-select-process-dropdown');
|
||||||
|
expect(selectElement).not.toBeNull();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should show the process dropdown button by default', async(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
getDefinitionsSpy = getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
|
component.appName = 'myApp';
|
||||||
|
component.processDefinitionName = 'NewProcess 2';
|
||||||
|
component.ngOnChanges({});
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let selectElement = fixture.nativeElement.querySelector('button#adf-select-process-dropdown');
|
||||||
|
expect(selectElement).not.toBeNull();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('input changes', () => {
|
||||||
|
|
||||||
|
let change = new SimpleChange('myApp', 'myApp1', true);
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
component.appName = 'myApp';
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
getDefinitionsSpy.calls.reset();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should reload processes when appId input changed', async(() => {
|
||||||
|
component.ngOnChanges({ appName: change });
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(getDefinitionsSpy).toHaveBeenCalledWith('myApp1');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should get current processDef', () => {
|
||||||
|
component.ngOnChanges({ appName: change });
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(getDefinitionsSpy).toHaveBeenCalled();
|
||||||
|
expect(component.processDefinitionList).toBe(fakeProcessDefinitions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('start process', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
component.name = 'NewProcess 1';
|
||||||
|
component.appName = 'myApp';
|
||||||
|
component.ngOnChanges({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call service to start process if required fields provided', async(() => {
|
||||||
|
component.processPayloadCloud = fakeProcessPayload;
|
||||||
|
component.startProcess();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(startProcessSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should avoid calling service to start process if required fields NOT provided', async(() => {
|
||||||
|
component.processForm.controls['processInstanceName'].setValue('');
|
||||||
|
component.processForm.controls['processDefinition'].setValue('');
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let startProcessButton = fixture.debugElement.query(By.css('[data-automation-id="btn-start"]'));
|
||||||
|
expect(startProcessButton.nativeElement.disabled).toBeTruthy();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should call service to start process with the correct parameters', async(() => {
|
||||||
|
component.processPayloadCloud = fakeProcessPayload;
|
||||||
|
component.startProcess();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(startProcessSpy).toHaveBeenCalledWith('myApp', fakeProcessPayload);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should call service to start process with the variables setted', async(() => {
|
||||||
|
let inputProcessVariable: Map<string, object>[] = [];
|
||||||
|
inputProcessVariable['name'] = {value: 'Josh'};
|
||||||
|
|
||||||
|
component.variables = inputProcessVariable;
|
||||||
|
component.processPayloadCloud = fakeProcessPayload;
|
||||||
|
|
||||||
|
component.startProcess();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(component.processPayloadCloud.variables).toBe(inputProcessVariable);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should output start event when process started successfully', async(() => {
|
||||||
|
let emitSpy = spyOn(component.success, 'emit');
|
||||||
|
component.processPayloadCloud = fakeProcessPayload;
|
||||||
|
component.startProcess();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(emitSpy).toHaveBeenCalledWith(fakeProcessInstance);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should throw error event when process cannot be started', async(() => {
|
||||||
|
let errorSpy = spyOn(component.error, 'emit');
|
||||||
|
let error = { message: 'My error' };
|
||||||
|
startProcessSpy = startProcessSpy.and.returnValue(throwError(error));
|
||||||
|
component.processPayloadCloud = fakeProcessPayload;
|
||||||
|
component.startProcess();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(errorSpy).toHaveBeenCalledWith(error);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should indicate an error to the user if process cannot be started', async(() => {
|
||||||
|
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
|
let change = new SimpleChange('myApp', 'myApp1', true);
|
||||||
|
component.ngOnChanges({ appName: change });
|
||||||
|
startProcessSpy = startProcessSpy.and.returnValue(throwError({}));
|
||||||
|
component.startProcess();
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let errorEl = fixture.nativeElement.querySelector('#error-message');
|
||||||
|
expect(errorEl.innerText.trim()).toBe('ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.START');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should emit start event when start select a process and add a name', (done) => {
|
||||||
|
let disposableStart = component.success.subscribe(() => {
|
||||||
|
disposableStart.unsubscribe();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
component.processPayloadCloud = fakeProcessPayload;
|
||||||
|
component.name = 'NewProcess 1';
|
||||||
|
component.startProcess();
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should able to start the process when the required fields are filled up', (done) => {
|
||||||
|
component.processForm.controls['processInstanceName'].setValue('My Process 1');
|
||||||
|
component.processForm.controls['processDefinition'].setValue('NewProcess 1');
|
||||||
|
|
||||||
|
let disposableStart = component.success.subscribe(() => {
|
||||||
|
disposableStart.unsubscribe();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
component.startProcess();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,237 @@
|
|||||||
|
/*!
|
||||||
|
* @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, EventEmitter, Input, OnChanges, OnInit,
|
||||||
|
Output, SimpleChanges, ViewChild, ViewEncapsulation
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import { ProcessInstanceCloud } from '../models/process-instance-cloud.model';
|
||||||
|
import { StartProcessCloudService } from '../services/start-process-cloud.service';
|
||||||
|
import { FormControl, Validators, FormGroup, AbstractControl, FormBuilder, ValidatorFn } from '@angular/forms';
|
||||||
|
import { MatAutocompleteTrigger } from '@angular/material';
|
||||||
|
import { ProcessPayloadCloud } from '../models/process-payload-cloud.model';
|
||||||
|
import { debounceTime } from 'rxjs/operators';
|
||||||
|
import { ProcessDefinitionCloud } from '../models/process-definition-cloud.model';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-cloud-start-process',
|
||||||
|
templateUrl: './start-process-cloud.component.html',
|
||||||
|
styleUrls: ['./start-process-cloud.component.scss'],
|
||||||
|
encapsulation: ViewEncapsulation.None
|
||||||
|
})
|
||||||
|
export class StartProcessCloudComponent implements OnChanges, OnInit {
|
||||||
|
|
||||||
|
@ViewChild(MatAutocompleteTrigger)
|
||||||
|
inputAutocomplete: MatAutocompleteTrigger;
|
||||||
|
|
||||||
|
/** (required) Name of the app. */
|
||||||
|
@Input()
|
||||||
|
appName: string;
|
||||||
|
|
||||||
|
/** Name of the process. */
|
||||||
|
@Input()
|
||||||
|
name: string = '';
|
||||||
|
|
||||||
|
/** Name of the process definition. */
|
||||||
|
@Input()
|
||||||
|
processDefinitionName: string;
|
||||||
|
|
||||||
|
/** Variables to attach to the payload */
|
||||||
|
@Input()
|
||||||
|
variables: Map<string, object>[];
|
||||||
|
|
||||||
|
/** This flag displays/hides the process dropdown list */
|
||||||
|
@Input()
|
||||||
|
showSelectProcessDropdown: boolean = true;
|
||||||
|
|
||||||
|
/** Emitted when the starting process is successfully created. */
|
||||||
|
@Output()
|
||||||
|
success: EventEmitter<ProcessInstanceCloud> = new EventEmitter<ProcessInstanceCloud>();
|
||||||
|
|
||||||
|
/** Emitted when the starting process is cancelled */
|
||||||
|
@Output()
|
||||||
|
cancel: EventEmitter<ProcessInstanceCloud> = new EventEmitter<ProcessInstanceCloud>();
|
||||||
|
|
||||||
|
/** Emitted when an error occurs. */
|
||||||
|
@Output()
|
||||||
|
error: EventEmitter<ProcessInstanceCloud> = new EventEmitter<ProcessInstanceCloud>();
|
||||||
|
|
||||||
|
processDefinitionList: ProcessDefinitionCloud[] = [];
|
||||||
|
errorMessageId: string = '';
|
||||||
|
processForm: FormGroup;
|
||||||
|
processPayloadCloud = new ProcessPayloadCloud();
|
||||||
|
filteredProcesses: ProcessDefinitionCloud[] = [];
|
||||||
|
isLoading = false;
|
||||||
|
|
||||||
|
constructor(private startProcessCloudService: StartProcessCloudService,
|
||||||
|
private formBuilder: FormBuilder) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.processForm = this.formBuilder.group({
|
||||||
|
processInstanceName: new FormControl(this.name, Validators.required),
|
||||||
|
processDefinition: new FormControl('', [Validators.required, this.processDefinitionNameValidator()])
|
||||||
|
});
|
||||||
|
|
||||||
|
this.processDefinition.valueChanges
|
||||||
|
.pipe(debounceTime(300))
|
||||||
|
.subscribe((processDefinitionName) => {
|
||||||
|
this.processPayloadCloud.processDefinitionKey = null;
|
||||||
|
if (this.processDefinition.valid) {
|
||||||
|
this.setProcessDefinitionOnForm(processDefinitionName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
|
if (changes['appName'] && changes['appName'].currentValue !== changes['appName'].previousValue) {
|
||||||
|
this.appName = changes['appName'].currentValue;
|
||||||
|
this.loadProcessDefinitions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setProcessDefinitionOnForm(processDefinitionName: string) {
|
||||||
|
this.filteredProcesses = this.getProcessDefinitionList(processDefinitionName);
|
||||||
|
const selectedProcess = this.getProcessIfExists(processDefinitionName);
|
||||||
|
this.processPayloadCloud.processDefinitionKey = selectedProcess.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getProcessDefinitionList(processDefinitionName: string): ProcessDefinitionCloud[] {
|
||||||
|
return this.processDefinitionList.filter((option) => option.name.toLowerCase().includes(processDefinitionName.toLowerCase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private getProcessIfExists(processDefinitionName: string): ProcessDefinitionCloud {
|
||||||
|
let matchedProcess = this.processDefinitionList.find((option) => option.name.toLowerCase() === processDefinitionName.toLowerCase());
|
||||||
|
if (!matchedProcess) {
|
||||||
|
matchedProcess = new ProcessDefinitionCloud();
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchedProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getProcessDefinitionByName(processDefinitionName: string): ProcessDefinitionCloud {
|
||||||
|
const matchedProcess = processDefinitionName ? this.getProcessIfExists(processDefinitionName) : this.processDefinitionList[0];
|
||||||
|
return matchedProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
private selectDefaultProcessDefinition() {
|
||||||
|
let selectedProcess = this.getProcessDefinitionByName(this.processDefinitionName);
|
||||||
|
if (selectedProcess) {
|
||||||
|
this.processForm.controls['processDefinition'].setValue(selectedProcess.name);
|
||||||
|
this.processPayloadCloud.processDefinitionKey = selectedProcess.key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public loadProcessDefinitions() {
|
||||||
|
this.resetErrorMessage();
|
||||||
|
|
||||||
|
this.startProcessCloudService.getProcessDefinitions(this.appName).subscribe(
|
||||||
|
(processDefinitionRepresentations: ProcessDefinitionCloud[]) => {
|
||||||
|
this.processDefinitionList = processDefinitionRepresentations;
|
||||||
|
if (processDefinitionRepresentations.length > 0) {
|
||||||
|
this.selectDefaultProcessDefinition();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
this.errorMessageId = 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.LOAD_PROCESS_DEFS';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
isProcessDefinitionsEmpty(): boolean {
|
||||||
|
return this.processDefinitionList.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
startProcess() {
|
||||||
|
this.isLoading = true;
|
||||||
|
|
||||||
|
this.processPayloadCloud.processInstanceName = this.processInstanceName.value;
|
||||||
|
this.processPayloadCloud.payloadType = 'StartProcessPayload';
|
||||||
|
if (this.variables) {
|
||||||
|
this.processPayloadCloud.variables = this.variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.startProcessCloudService.startProcess(this.appName, this.processPayloadCloud).subscribe(
|
||||||
|
(res) => {
|
||||||
|
this.success.emit(res);
|
||||||
|
this.isLoading = false;
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
this.errorMessageId = 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.START';
|
||||||
|
this.error.emit(err);
|
||||||
|
this.isLoading = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelStartProcess() {
|
||||||
|
this.cancel.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private resetErrorMessage() {
|
||||||
|
this.errorMessageId = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
private resetProcessDefinitionList() {
|
||||||
|
this.processForm.controls['processDefinition'].setValue('');
|
||||||
|
this.filteredProcesses = this.processDefinitionList;
|
||||||
|
}
|
||||||
|
|
||||||
|
displayProcessNameOnDropdown(process: any) {
|
||||||
|
if (process) {
|
||||||
|
let processName = process;
|
||||||
|
if (typeof process !== 'string') {
|
||||||
|
processName = process.name;
|
||||||
|
}
|
||||||
|
return processName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
displayDropdown(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
if (!this.inputAutocomplete.panelOpen) {
|
||||||
|
this.resetProcessDefinitionList();
|
||||||
|
this.inputAutocomplete.openPanel();
|
||||||
|
} else {
|
||||||
|
this.inputAutocomplete.closePanel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processDefinitionNameValidator(): ValidatorFn {
|
||||||
|
return (control: AbstractControl): { [key: string]: any } | null => {
|
||||||
|
const processDefinitionFieldValue = control.value;
|
||||||
|
let processDefinitionNameError = false;
|
||||||
|
|
||||||
|
if (processDefinitionFieldValue) {
|
||||||
|
const processDefinition = this.getProcessIfExists(processDefinitionFieldValue);
|
||||||
|
if (!processDefinition.key) {
|
||||||
|
processDefinitionNameError = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return processDefinitionNameError ? { 'invalid name': true } : null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get processInstanceName(): AbstractControl {
|
||||||
|
return this.processForm.get('processInstanceName');
|
||||||
|
}
|
||||||
|
|
||||||
|
get processDefinition(): AbstractControl {
|
||||||
|
return this.processForm.get('processDefinition');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
/*!
|
||||||
|
* @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 { ProcessInstanceCloud } from '../models/process-instance-cloud.model';
|
||||||
|
import { ProcessPayloadCloud } from '../models/process-payload-cloud.model';
|
||||||
|
import { ProcessDefinitionCloud } from '../models/process-definition-cloud.model';
|
||||||
|
|
||||||
|
export let fakeProcessInstance = new ProcessInstanceCloud({
|
||||||
|
appName: 'simple-app',
|
||||||
|
appVersion: '',
|
||||||
|
serviceName: 'simple-app-rb',
|
||||||
|
serviceFullName: 'simple-app-rb',
|
||||||
|
serviceType: 'runtime-bundle',
|
||||||
|
serviceVersion: '',
|
||||||
|
id: 'd0b30377-dc5a-11e8-ae24-0a58646001fa',
|
||||||
|
name: 'My Process Name',
|
||||||
|
startDate: '2018-10-30T15:45:24.136+0000',
|
||||||
|
initiator: 'usermock',
|
||||||
|
status: 'RUNNING',
|
||||||
|
processDefinitionId: 'BasicProcess:1:d05062f1-c6fb-11e8-ae24-0a58646001fa',
|
||||||
|
processDefinitionKey: 'BasicProcess'
|
||||||
|
});
|
||||||
|
|
||||||
|
export let fakeProcessDefinitions: ProcessDefinitionCloud[] = [
|
||||||
|
new ProcessDefinitionCloud({
|
||||||
|
appName: 'myApp',
|
||||||
|
appVersion: 0,
|
||||||
|
id: 'NewProcess:1',
|
||||||
|
key: 'NewProcess 1',
|
||||||
|
name: 'NewProcess 1',
|
||||||
|
serviceFullName: 'myApp-rb',
|
||||||
|
serviceName: 'myApp-rb',
|
||||||
|
serviceType: 'runtime-bundle',
|
||||||
|
serviceVersion: null
|
||||||
|
}),
|
||||||
|
new ProcessDefinitionCloud({
|
||||||
|
appName: 'myApp',
|
||||||
|
appVersion: 0,
|
||||||
|
id: 'NewProcess:2',
|
||||||
|
key: 'NewProcess 2',
|
||||||
|
name: 'NewProcess 2',
|
||||||
|
serviceFullName: 'myApp-rb',
|
||||||
|
serviceName: 'myApp-rb',
|
||||||
|
serviceType: 'runtime-bundle',
|
||||||
|
serviceVersion: null
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
export let fakeProcessPayload = new ProcessPayloadCloud({
|
||||||
|
processDefinitionKey: 'NewProcess:1',
|
||||||
|
processInstanceName: 'NewProcess 1',
|
||||||
|
payloadType: 'string'
|
||||||
|
});
|
@ -0,0 +1,42 @@
|
|||||||
|
/*!
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class ProcessDefinitionCloud {
|
||||||
|
id: string;
|
||||||
|
appName: string;
|
||||||
|
key: string;
|
||||||
|
appVersion: number;
|
||||||
|
version: number;
|
||||||
|
name: string;
|
||||||
|
serviceFullName: string;
|
||||||
|
serviceName: string;
|
||||||
|
serviceType: string;
|
||||||
|
serviceVersion: string;
|
||||||
|
|
||||||
|
constructor(obj?: any) {
|
||||||
|
this.id = obj && obj.id || null;
|
||||||
|
this.name = obj && obj.name || null;
|
||||||
|
this.appName = obj && obj.appName || null;
|
||||||
|
this.key = obj && obj.key || null;
|
||||||
|
this.version = obj && obj.version || 0;
|
||||||
|
this.appVersion = obj && obj.appVersion || 0;
|
||||||
|
this.serviceFullName = obj && obj.serviceFullName || null;
|
||||||
|
this.serviceType = obj && obj.serviceType || null;
|
||||||
|
this.serviceName = obj && obj.serviceName || null;
|
||||||
|
this.serviceVersion = obj && obj.serviceVersion || null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/*!
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class ProcessInstanceCloud {
|
||||||
|
appName: string;
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
startDate: Date;
|
||||||
|
initiator: string;
|
||||||
|
status: string;
|
||||||
|
processDefinitionId: string;
|
||||||
|
processDefinitionKey: string;
|
||||||
|
|
||||||
|
constructor(obj?: any) {
|
||||||
|
this.appName = obj && obj.appName || null;
|
||||||
|
this.id = obj && obj.id || null;
|
||||||
|
this.name = obj && obj.name || null;
|
||||||
|
this.startDate = obj && obj.startDate || null;
|
||||||
|
this.initiator = obj && obj.initiator || null;
|
||||||
|
this.status = obj && obj.status || null;
|
||||||
|
this.processDefinitionId = obj && obj.processDefinitionId || null;
|
||||||
|
this.processDefinitionKey = obj && obj.processDefinitionKey || null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*!
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class ProcessPayloadCloud {
|
||||||
|
processDefinitionKey: string;
|
||||||
|
processInstanceName: string;
|
||||||
|
businessKey: string;
|
||||||
|
variables: Map<string, object>[];
|
||||||
|
payloadType: string;
|
||||||
|
|
||||||
|
constructor(obj?: any) {
|
||||||
|
this.processDefinitionKey = obj && obj.processDefinitionKey ? obj.processDefinitionKey : null;
|
||||||
|
this.processInstanceName = obj && obj.processInstanceName ? obj.processInstanceName : null;
|
||||||
|
this.businessKey = obj && obj.businessKey ? obj.businessKey : null;
|
||||||
|
this.variables = obj && obj.variables ? obj.variables : null;
|
||||||
|
this.payloadType = obj && obj.valueUrl ? obj.payloadType : null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/*!
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './components/start-process-cloud.component';
|
||||||
|
|
||||||
|
export * from './models/process-definition-cloud.model';
|
||||||
|
export * from './models/process-instance-cloud.model';
|
||||||
|
export * from './models/process-payload-cloud.model';
|
||||||
|
|
||||||
|
export * from './services/start-process-cloud.service';
|
||||||
|
export * from './start-process-cloud.module';
|
@ -0,0 +1,111 @@
|
|||||||
|
/*!
|
||||||
|
* @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 { TestBed } from '@angular/core/testing';
|
||||||
|
import { setupTestBed } from '@alfresco/adf-core';
|
||||||
|
import { of, throwError } from 'rxjs';
|
||||||
|
import {
|
||||||
|
AlfrescoApiService,
|
||||||
|
AppConfigService,
|
||||||
|
LogService,
|
||||||
|
StorageService
|
||||||
|
} from '@alfresco/adf-core';
|
||||||
|
import { StartProcessCloudService } from './start-process-cloud.service';
|
||||||
|
import { fakeProcessPayload } from '../mock/start-process.component.mock';
|
||||||
|
import { ProcessInstanceCloud } from '../models/process-instance-cloud.model';
|
||||||
|
import { HttpErrorResponse } from '@angular/common/http';
|
||||||
|
import { ProcessDefinitionCloud } from '../models/process-definition-cloud.model';
|
||||||
|
import { ProcessCloudModule } from '../../process-cloud.module';
|
||||||
|
|
||||||
|
describe('StartTaskCloudService', () => {
|
||||||
|
|
||||||
|
let service: StartProcessCloudService;
|
||||||
|
|
||||||
|
setupTestBed({
|
||||||
|
imports: [ProcessCloudModule],
|
||||||
|
providers: [StartProcessCloudService, AlfrescoApiService, AppConfigService, LogService, StorageService]
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
service = TestBed.get(StartProcessCloudService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to create a new process', (done) => {
|
||||||
|
spyOn(service, 'startProcess').and.returnValue(of({ id: 'fake-id', name: 'fake-name' }));
|
||||||
|
service.startProcess('appName1', fakeProcessPayload)
|
||||||
|
.subscribe(
|
||||||
|
(res: ProcessInstanceCloud) => {
|
||||||
|
expect(res).toBeDefined();
|
||||||
|
expect(res.id).toEqual('fake-id');
|
||||||
|
expect(res.name).toEqual('fake-name');
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should not be able to create a process if error occurred', () => {
|
||||||
|
const errorResponse = new HttpErrorResponse({
|
||||||
|
error: 'Mock Error',
|
||||||
|
status: 404, statusText: 'Not Found'
|
||||||
|
});
|
||||||
|
|
||||||
|
spyOn(service, 'startProcess').and.returnValue(throwError(errorResponse));
|
||||||
|
service.startProcess('appName1', fakeProcessPayload)
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
|
fail('expected an error, not applications');
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
expect(error.status).toEqual(404);
|
||||||
|
expect(error.statusText).toEqual('Not Found');
|
||||||
|
expect(error.error).toEqual('Mock Error');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to get all the process definitions', (done) => {
|
||||||
|
spyOn(service, 'getProcessDefinitions').and.returnValue(of([{ id: 'fake-id', name: 'fake-name' }]));
|
||||||
|
service.getProcessDefinitions('appName1')
|
||||||
|
.subscribe(
|
||||||
|
(res: ProcessDefinitionCloud[]) => {
|
||||||
|
expect(res).toBeDefined();
|
||||||
|
expect(res[0].id).toEqual('fake-id');
|
||||||
|
expect(res[0].name).toEqual('fake-name');
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not be able to get all the process definitions if error occurred', () => {
|
||||||
|
const errorResponse = new HttpErrorResponse({
|
||||||
|
error: 'Mock Error',
|
||||||
|
status: 404, statusText: 'Not Found'
|
||||||
|
});
|
||||||
|
spyOn(service, 'getProcessDefinitions').and.returnValue(throwError(errorResponse));
|
||||||
|
service.getProcessDefinitions('appName1')
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
|
fail('expected an error, not applications');
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
expect(error.status).toEqual(404);
|
||||||
|
expect(error.statusText).toEqual('Not Found');
|
||||||
|
expect(error.error).toEqual('Mock Error');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,99 @@
|
|||||||
|
/*!
|
||||||
|
* @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 { AlfrescoApiService, AppConfigService, LogService } from '@alfresco/adf-core';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Observable, from, throwError } from 'rxjs';
|
||||||
|
import { map, catchError } from 'rxjs/operators';
|
||||||
|
import { ProcessInstanceCloud } from '../models/process-instance-cloud.model';
|
||||||
|
import { ProcessPayloadCloud } from '../models/process-payload-cloud.model';
|
||||||
|
import { ProcessDefinitionCloud } from '../models/process-definition-cloud.model';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class StartProcessCloudService {
|
||||||
|
|
||||||
|
contextRoot: string;
|
||||||
|
contentTypes = ['application/json'];
|
||||||
|
accepts = ['application/json'];
|
||||||
|
returnType = Object;
|
||||||
|
|
||||||
|
constructor(private alfrescoApiService: AlfrescoApiService,
|
||||||
|
private appConfigService: AppConfigService,
|
||||||
|
private logService: LogService) {
|
||||||
|
this.contextRoot = this.appConfigService.get('bpmHost', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets process definitions associated with an app.
|
||||||
|
* @param appId ID of a target app
|
||||||
|
* @returns Array of process definitions
|
||||||
|
*/
|
||||||
|
getProcessDefinitions(appName: string): Observable<ProcessDefinitionCloud[]> {
|
||||||
|
|
||||||
|
if (appName) {
|
||||||
|
let queryUrl = `${this.contextRoot}/${appName}-rb/v1/process-definitions`;
|
||||||
|
|
||||||
|
return from(this.alfrescoApiService.getInstance()
|
||||||
|
.oauth2Auth.callCustomApi(queryUrl, 'GET',
|
||||||
|
null, null, null,
|
||||||
|
null, null, null,
|
||||||
|
this.contentTypes, this.accepts,
|
||||||
|
this.returnType, null, null)
|
||||||
|
).pipe(
|
||||||
|
map((res: any) => {
|
||||||
|
return res.list.entries.map((processDefs) => new ProcessDefinitionCloud(processDefs.entry));
|
||||||
|
}),
|
||||||
|
catchError((err) => this.handleProcessError(err))
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.logService.error('AppName is mandatory for querying task');
|
||||||
|
return throwError('AppName not configured');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a process based on a process definition, name, form values or variables.
|
||||||
|
* @param appName name of the Application
|
||||||
|
* @param processDefinitionId Process definition ID
|
||||||
|
* @param name Process name
|
||||||
|
* @param outcome Process outcome
|
||||||
|
* @param startFormValues Values for the start form
|
||||||
|
* @param variables Array of process instance variables
|
||||||
|
* @returns Details of the process instance just started
|
||||||
|
*/
|
||||||
|
startProcess(appName: string, requestPayload: ProcessPayloadCloud): Observable<ProcessInstanceCloud> {
|
||||||
|
|
||||||
|
let queryUrl = `${this.contextRoot}/${appName}-rb/v1/process-instances`;
|
||||||
|
|
||||||
|
return from(this.alfrescoApiService.getInstance()
|
||||||
|
.oauth2Auth.callCustomApi(queryUrl, 'POST',
|
||||||
|
null, null, null,
|
||||||
|
null, requestPayload, null,
|
||||||
|
this.contentTypes, this.accepts,
|
||||||
|
this.returnType, null, null)
|
||||||
|
).pipe(
|
||||||
|
map((processInstance) => new ProcessInstanceCloud(processInstance)),
|
||||||
|
catchError((err) => this.handleProcessError(err))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleProcessError(error: any) {
|
||||||
|
return throwError(error || 'Server error');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*!
|
||||||
|
* @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 { StartProcessCloudModule } from './start-process-cloud.module';
|
||||||
|
|
||||||
|
describe('ProcessCloudModule', () => {
|
||||||
|
let startProcessCloudModule: StartProcessCloudModule;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
startProcessCloudModule = new StartProcessCloudModule();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create an instance', () => {
|
||||||
|
expect(startProcessCloudModule).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,51 @@
|
|||||||
|
/*!
|
||||||
|
* @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 { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||||
|
import { MaterialModule } from '../../material.module';
|
||||||
|
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
|
||||||
|
import { TranslateLoaderService } from '@alfresco/adf-core';
|
||||||
|
import { StartProcessCloudComponent } from './components/start-process-cloud.component';
|
||||||
|
import { StartProcessCloudService } from './services/start-process-cloud.service';
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
FormsModule,
|
||||||
|
CommonModule,
|
||||||
|
TranslateModule.forRoot({
|
||||||
|
loader: {
|
||||||
|
provide: TranslateLoader,
|
||||||
|
useClass: TranslateLoaderService
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
MaterialModule,
|
||||||
|
FlexLayoutModule,
|
||||||
|
ReactiveFormsModule
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
StartProcessCloudComponent
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
StartProcessCloudComponent
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
StartProcessCloudService
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class StartProcessCloudModule { }
|
Loading…
x
Reference in New Issue
Block a user