diff --git a/demo-shell/resources/i18n/en.json b/demo-shell/resources/i18n/en.json
index 9fb603b5f9..6f13ce31f6 100644
--- a/demo-shell/resources/i18n/en.json
+++ b/demo-shell/resources/i18n/en.json
@@ -320,7 +320,21 @@
"MULTISELECTION": "Multiselection",
"TESTING_MODE": "Testing Mode",
"SELECTION_MODE": "Selection Mode",
+ "SELECTED_ROWS": "Selected rows",
"TASK_DETAILS_REDIRECTION": "Display task details on task click",
- "PROCESS_DETAILS_REDIRECTION": "Display process details on process click"
+ "PROCESS_DETAILS_REDIRECTION": "Display process details on process click",
+ "ACTION": {
+ "ACTION_TITLE": "Add Action",
+ "ACTION_MENU": "Action Menu",
+ "CONTEX_MENU": "Context Menu",
+ "ACTION_VISIBLE": "Visible",
+ "ACTION_DISABLE": "Disable",
+ "ADD_BUTTON": "Add",
+ "KEY": "Key",
+ "TITLE": "Title",
+ "ICON": "Icon",
+ "PROCESS_ID": "ProcessInstanceId",
+ "ACTION_TYPE": "Action Type"
+ }
}
}
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 af3a0ec943..70dfb611ac 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
@@ -24,7 +24,13 @@
[lastModifiedTo]="editedFilter.lastModifiedTo"
[sorting]="sortArray"
[selectionMode]="selectionMode"
+ [stickyHeader]="true"
+ [showActions]="actionMenu"
+ [showContextMenu]="contextMenu"
[multiselect]="multiselect"
+ (showRowActionsMenu)="onShowRowActionsMenu($event)"
+ (showRowContextMenu)="onShowRowContextMenu($event)"
+ (executeRowAction)="onExecuteRowAction($event)"
(rowClick)="onRowClick($event)"
(rowsSelected)="onRowsSelected($event)">
@@ -35,10 +41,28 @@
(prevPage)="resetSelectedRows()">
- Selected rows:
-
+
+ {{ 'SETTINGS_CLOUD.SELECTED_ROWS' | translate }}:
+
+
+
+
{{ 'SETTINGS_CLOUD.ACTION.ACTION_MENU' | translate }}:
+
+
+ {{ 'SETTINGS_CLOUD.ACTION.PROCESS_ID' | translate }}: {{ selectedAction.id }}
+ {{ 'SETTINGS_CLOUD.ACTION.ACTION_TYPE' | translate }}: {{ selectedAction.actionType }}
+
+
+
+
{{ 'SETTINGS_CLOUD.ACTION.CONTEX_MENU' | translate }}:
+
+
+ {{ 'SETTINGS_CLOUD.ACTION.PROCESS_ID' | translate }}: {{ selectedContextAction.id }}
+ {{ 'SETTINGS_CLOUD.ACTION.ACTION_TYPE' | translate }}: {{ selectedContextAction.actionType }}
+
+
diff --git a/demo-shell/src/app/components/cloud/processes-cloud-demo.component.ts b/demo-shell/src/app/components/cloud/processes-cloud-demo.component.ts
index 40455ff8c2..87f77c13bc 100644
--- a/demo-shell/src/app/components/cloud/processes-cloud-demo.component.ts
+++ b/demo-shell/src/app/components/cloud/processes-cloud-demo.component.ts
@@ -24,7 +24,7 @@ import {
} from '@alfresco/adf-process-services-cloud';
import { ActivatedRoute, Router } from '@angular/router';
-import { UserPreferencesService, AppConfigService } from '@alfresco/adf-core';
+import { UserPreferencesService, AppConfigService, DataCellEvent } from '@alfresco/adf-core';
import { CloudLayoutService, CloudServiceSettings } from './services/cloud-layout.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@@ -55,11 +55,17 @@ export class ProcessesCloudDemoComponent implements OnInit, OnDestroy {
selectionMode: string;
selectedRows: string[] = [];
testingMode: boolean;
+ actionMenu: boolean;
+ contextMenu: boolean;
+ actions: any[] = [];
+ selectedAction: { id: number, name: string, actionType: string};
+ selectedContextAction: { id: number, name: string, actionType: string};
processFilterProperties: any = { filterProperties: [], sortProperties: [], actions: [] };
processDetailsRedirection: boolean;
editedFilter: ProcessFilterCloudModel;
+ private performAction$ = new Subject();
private onDestroy$ = new Subject();
constructor(
@@ -89,6 +95,7 @@ export class ProcessesCloudDemoComponent implements OnInit, OnDestroy {
this.cloudLayoutService.settings$
.pipe(takeUntil(this.onDestroy$))
.subscribe(settings => this.setCurrentSettings(settings));
+ this.performContextActions();
}
ngOnDestroy() {
@@ -102,6 +109,9 @@ export class ProcessesCloudDemoComponent implements OnInit, OnDestroy {
this.testingMode = settings.testingMode;
this.selectionMode = settings.selectionMode;
this.processDetailsRedirection = settings.processDetailsRedirection;
+ this.actionMenu = settings.actionMenu;
+ this.contextMenu = settings.contextMenu;
+ this.actions = settings.actions;
}
}
@@ -140,4 +150,41 @@ export class ProcessesCloudDemoComponent implements OnInit, OnDestroy {
this.resetSelectedRows();
this.selectedRows = nodes.map((node) => node.obj.entry);
}
+
+ onShowRowActionsMenu(event: DataCellEvent) {
+ event.value.actions = this.actions;
+ }
+
+ onShowRowContextMenu(event: DataCellEvent) {
+ event.value.actions = this.actions.map((action) => {
+ return {
+ data: event.value.row['obj'],
+ model: action,
+ subject: this.performAction$
+
+ };
+ });
+ }
+
+ onExecuteRowAction(row: any) {
+ const value = row.value.row['obj'].entry;
+ const action = row.value.action;
+ this.selectedAction = {id: value.id, name: value.name, actionType: action.title};
+ }
+
+ performContextActions() {
+ this.performAction$
+ .pipe(takeUntil(this.onDestroy$))
+ .subscribe((action: any) => {
+ if (action) {
+ this.onExecuteContextAction(action);
+ }
+ });
+ }
+
+ onExecuteContextAction(contextAction: any) {
+ const value = contextAction.data.entry;
+ const action = contextAction.model;
+ this.selectedContextAction = {id: value.id, name: value.name, actionType: action.title};
+ }
}
diff --git a/demo-shell/src/app/components/cloud/services/cloud-layout.service.ts b/demo-shell/src/app/components/cloud/services/cloud-layout.service.ts
index d3041063d3..4e86e2aa5a 100644
--- a/demo-shell/src/app/components/cloud/services/cloud-layout.service.ts
+++ b/demo-shell/src/app/components/cloud/services/cloud-layout.service.ts
@@ -20,10 +20,13 @@ import { BehaviorSubject } from 'rxjs';
export interface CloudServiceSettings {
multiselect: boolean;
+ actionMenu: boolean;
+ contextMenu: boolean;
testingMode: boolean;
taskDetailsRedirection: boolean;
processDetailsRedirection: boolean;
selectionMode: string;
+ actions: any[];
}
export interface FilterSettings {
@@ -32,6 +35,17 @@ export interface FilterSettings {
key?: string;
}
+export class ActionMenuModel {
+ constructor(
+ public key: string,
+ public icon: string,
+ public title: string,
+ public visible?: boolean,
+ public disable?: boolean
+ ) { }
+
+}
+
@Injectable({
providedIn: 'root'
})
@@ -39,10 +53,13 @@ export class CloudLayoutService {
private settings: CloudServiceSettings = {
multiselect: false,
+ actionMenu: false,
+ contextMenu: false,
testingMode: false,
taskDetailsRedirection: true,
processDetailsRedirection: true,
- selectionMode: 'single'
+ selectionMode: 'single',
+ actions: []
};
taskFilter$ = new BehaviorSubject({index: 0});
diff --git a/demo-shell/src/app/components/cloud/shared/cloud-settings.component.html b/demo-shell/src/app/components/cloud/shared/cloud-settings.component.html
index 62d8ded230..5c385dcbdd 100644
--- a/demo-shell/src/app/components/cloud/shared/cloud-settings.component.html
+++ b/demo-shell/src/app/components/cloud/shared/cloud-settings.component.html
@@ -2,6 +2,12 @@
{{ 'SETTINGS_CLOUD.MULTISELECTION' | translate }}
+
+ {{ 'SETTINGS_CLOUD.ACTION.ACTION_MENU' | translate }}
+
+
+ {{ 'SETTINGS_CLOUD.ACTION.CONTEX_MENU' | translate }}
+
{{ 'SETTINGS_CLOUD.TESTING_MODE' | translate }}
@@ -21,4 +27,45 @@
+
+
+ {{ 'SETTINGS_CLOUD.ACTION.ACTION_TITLE' | translate }}
+
+
+
+ 0">
+
+
+ {{action.title}}
+
+ cancel
+
+
+
+
+
+
diff --git a/demo-shell/src/app/components/cloud/shared/cloud-settings.component.ts b/demo-shell/src/app/components/cloud/shared/cloud-settings.component.ts
index d21e308386..b9ca5fec4e 100644
--- a/demo-shell/src/app/components/cloud/shared/cloud-settings.component.ts
+++ b/demo-shell/src/app/components/cloud/shared/cloud-settings.component.ts
@@ -16,9 +16,10 @@
*/
import { Component, OnInit, OnDestroy } from '@angular/core';
-import { CloudLayoutService } from '../services/cloud-layout.service';
+import { CloudLayoutService, ActionMenuModel } from '../services/cloud-layout.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
+import { FormGroup, FormControl } from '@angular/forms';
@Component({
selector: 'app-cloud-settings',
@@ -29,6 +30,9 @@ export class CloudSettingsComponent implements OnInit, OnDestroy {
private onDestroy$ = new Subject();
multiselect: boolean;
+ actionMenu: boolean;
+ contextMenu: boolean;
+ actions: ActionMenuModel[] = [];
selectionMode: string;
testingMode: boolean;
taskDetailsRedirection: boolean;
@@ -40,6 +44,14 @@ export class CloudSettingsComponent implements OnInit, OnDestroy {
{ value: 'multiple', title: 'Multiple' }
];
+ actionMenuForm = new FormGroup({
+ key: new FormControl(''),
+ title: new FormControl(''),
+ icon: new FormControl(''),
+ visible: new FormControl(true),
+ disable: new FormControl(false)
+ });
+
constructor(private cloudLayoutService: CloudLayoutService) { }
ngOnInit() {
@@ -57,6 +69,9 @@ export class CloudSettingsComponent implements OnInit, OnDestroy {
setCurrentSettings(settings) {
if (settings) {
this.multiselect = settings.multiselect;
+ this.actionMenu = this.actionMenu;
+ this.contextMenu = this.contextMenu;
+ this.actions = this.actions;
this.testingMode = settings.testingMode;
this.selectionMode = settings.selectionMode;
this.taskDetailsRedirection = settings.taskDetailsRedirection;
@@ -88,9 +103,35 @@ export class CloudSettingsComponent implements OnInit, OnDestroy {
this.setSetting();
}
+ toggleActionMenu() {
+ this.actionMenu = !this.actionMenu;
+ this.setSetting();
+ }
+
+ toggleContextMenu() {
+ this.contextMenu = !this.contextMenu;
+ this.setSetting();
+ }
+
+ addAction() {
+ this.actions.push( this.actionMenuForm.value);
+ this.actionMenuForm.get('key').reset();
+ this.actionMenuForm.get('title').reset();
+ this.actionMenuForm.get('icon').reset();
+ this.setSetting();
+ }
+
+ removeAction(removedAction: ActionMenuModel) {
+ this.actions = this.actions.filter((action: ActionMenuModel) => action.key !== removedAction.key);
+ this.setSetting();
+ }
+
setSetting() {
this.cloudLayoutService.setCurrentSettings({
multiselect: this.multiselect,
+ actionMenu: this.actionMenu,
+ contextMenu: this.contextMenu,
+ actions: this.actions,
testingMode: this.testingMode,
selectionMode: this.selectionMode,
taskDetailsRedirection: this.taskDetailsRedirection,
diff --git a/demo-shell/src/app/components/cloud/shared/cloud.shared.module.ts b/demo-shell/src/app/components/cloud/shared/cloud.shared.module.ts
index a67fc6e948..7a72006f9d 100644
--- a/demo-shell/src/app/components/cloud/shared/cloud.shared.module.ts
+++ b/demo-shell/src/app/components/cloud/shared/cloud.shared.module.ts
@@ -20,6 +20,7 @@ import { CommonModule } from '@angular/common';
import { CloudSettingsComponent } from './cloud-settings.component';
import { MatDialogModule, MatInputModule, MatSelectModule, MatSlideToggleModule } from '@angular/material';
import { CoreModule } from '@alfresco/adf-core';
+import { FlexLayoutModule } from '@angular/flex-layout';
@NgModule({
imports: [
@@ -28,7 +29,8 @@ import { CoreModule } from '@alfresco/adf-core';
MatDialogModule,
MatInputModule,
MatSelectModule,
- MatSlideToggleModule
+ MatSlideToggleModule,
+ FlexLayoutModule
],
declarations: [ CloudSettingsComponent ],
exports: [ CommonModule, CloudSettingsComponent]
diff --git a/docs/docassets/images/action-menu-on-process-list.png b/docs/docassets/images/action-menu-on-process-list.png
new file mode 100644
index 0000000000..bf16ea6b6a
Binary files /dev/null and b/docs/docassets/images/action-menu-on-process-list.png differ
diff --git a/docs/docassets/images/context-menu-on-process-list.png b/docs/docassets/images/context-menu-on-process-list.png
new file mode 100644
index 0000000000..2ea60e48a3
Binary files /dev/null and b/docs/docassets/images/context-menu-on-process-list.png differ
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 5b12220bed..1f7ad0b23c 100644
--- a/docs/process-services-cloud/components/process-list-cloud.component.md
+++ b/docs/process-services-cloud/components/process-list-cloud.component.md
@@ -51,6 +51,9 @@ when the process list is empty:
| Name | Type | Default value | Description |
| ---- | ---- | ------------- | ----------- |
| appName | `string` | | The name of the application. |
+| actions | `boolean` | false | Toggles the data actions column. |
+| actionsPosition | `string` | "right" | Position of the actions dropdown menu. Can be "left" or "right". |
+| contextMenu | `boolean` | false | Toggles custom context menu for the component. |
| businessKey | `string` | "" | Filter the processes to display only the ones with this businessKey value. |
| id | `string` | "" | Filter the processes to display only the ones with this ID. |
| initiator | `string` | "" | Name of the initiator of the process. |
@@ -73,6 +76,9 @@ when the process list is empty:
| rowClick | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when a row in the process list is clicked. |
| rowsSelected | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when rows are selected/unselected. |
| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`` | Emitted when the list of process instances has been loaded successfully from the server. |
+| executeRowAction | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`DataRowActionEvent`](../../../lib/core/datatable/components/datatable/data-row-action.event.ts)`>` | Emitted when the user executes a row action. |
+| showRowActionsMenu | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`DataCellEvent`](../../../lib/core/datatable/components/datatable/data-cell.event.ts)`>` | Emitted before the actions menu is displayed for a row. |
+| showRowContextMenu | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`DataCellEvent`](../../../lib/core/datatable/components/datatable/data-cell.event.ts)`>` | Emitted before the context menu is displayed for a row. |
## Details
@@ -192,6 +198,116 @@ The configuration related to the pagination can be changed from the `app.config.
},
```
+#### showRowContextMenu event
+
+Emitted before the context menu is displayed for a row.
+
+Note that the ProcessListCloud itself does not populate the context menu with items.
+You can provide all necessary content via the handler.
+
+```html
+
+
+```
+
+Event properties:
+
+```ts
+value: {
+ row: DataRow,
+ col: DataColumn,
+ actions: []
+}
+```
+
+Handler example:
+
+```ts
+onShowRowContextMenu(event: DataCellEvent) {
+ event.value.actions = [
+ { title: 'Hello Context Action' },
+ { ... }
+ ]
+}
+```
+
+
+This event is cancellable. You can use `event.preventDefault()` to prevent the default behavior.
+
+The ProcessListCloud will automatically render the supplied menu items.
+
+See the [ContextMenu](https://www.npmjs.com/package/ng2-alfresco-core)
+documentation for more details on the format and behavior of context actions.
+
+#### showRowActionsMenu event
+
+Emitted before the actions menu is displayed for a row.
+Requires the `actions` property to be set to `true`.
+
+Event properties:
+
+```ts
+value: {
+ row: DataRow,
+ action: any
+}
+```
+
+Note that the ProcessListCloud itself does not populate the action menu with items.
+You can provide all necessary content via the handler.
+
+This event is cancellable. You can use `event.preventDefault()` to prevent the default behavior.
+
+#### executeRowAction event
+
+Emitted when the user executes a row action.
+
+This usually accompanies a `showRowActionsMenu` event.
+The ProcessListCloud itself does not execute actions but provides support for external
+integration. If actions are provided using the `showRowActionsMenu` event
+then `executeRowAction` will be automatically executed when the user clicks a
+corresponding menu item.
+
+```html
+
+
+```
+
+```ts
+import { DataCellEvent, DataRowActionEvent } from '@alfresco/adf-core';
+
+onShowRowActionsMenu(event: DataCellEvent) {
+ let myAction = {
+ title: 'Hello Action'
+ // your custom metadata needed for onExecuteRowAction
+ };
+ event.value.actions = [
+ myAction
+ ];
+}
+
+onExecuteRowAction(event: DataRowActionEvent) {
+ let args = event.value;
+ console.log(args.row);
+ console.log(args.action);
+ window.alert(`My custom action: ${args.action.title}`);
+}
+```
+
+
+
+You can use any payloads for row actions. The only requirement for the objects is that they
+must have a `title` property.
+
+When an action is selected in the dropdown menu, the ProcessListCloud invokes the `executeRowAction` event.
+Use this to handle the response, inspect the action payload (and all custom properties defined
+earlier), and perform the corresponding actions.
+
## See also
- [Data column component](../../core/components/data-column.component.md)
diff --git a/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.html b/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.html
index ab135609ab..70a8338452 100644
--- a/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.html
+++ b/lib/process-services-cloud/src/lib/process/process-list/components/process-list-cloud.component.html
@@ -1,9 +1,16 @@
= new EventEmitter();
@@ -108,6 +125,18 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan
@Output()
rowsSelected: EventEmitter = new EventEmitter();
+ /** Emitted before the context menu is displayed for a row. */
+ @Output()
+ showRowContextMenu = new EventEmitter();
+
+ /** Emitted before the actions menu is displayed for a row. */
+ @Output()
+ showRowActionsMenu = new EventEmitter();
+
+ /** Emitted when the user executes a row action. */
+ @Output()
+ executeRowAction = new EventEmitter();
+
/** Emitted when an error occurs while loading the list of process instances from the server. */
@Output()
error: EventEmitter = new EventEmitter();
@@ -223,6 +252,18 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan
}
}
+ onShowRowActionsMenu(event: DataCellEvent) {
+ this.showRowActionsMenu.emit(event);
+ }
+
+ onShowRowContextMenu(event: DataCellEvent) {
+ this.showRowContextMenu.emit(event);
+ }
+
+ onExecuteRowAction(row: DataRowActionEvent) {
+ this.executeRowAction.emit(row);
+ }
+
private createRequestNode(): ProcessQueryCloudRequestModel {
const requestNode = {
appName: this.appName,