[ADF-4828] [ProcessListCloudComponent] Add action and context menu. (#5009)

* * Demo on list com

* [ADF-4828] [ADF] [ProcessListCloudComponent] Add action and context menu.

* Exposed action and context menu.
* Provided a way to in the demo shell to test action menu.
* Added required transaltion on demo shell.

* * Added doc

* * Fixed comments.
This commit is contained in:
siva kumar
2019-08-23 19:21:40 +05:30
committed by Maurizio Vitale
parent 8c159babe0
commit 8c00919db0
12 changed files with 366 additions and 10 deletions

View File

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

View File

@@ -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)">
</adf-cloud-process-list>
@@ -35,10 +41,28 @@
(prevPage)="resetSelectedRows()">
</adf-pagination>
<div *ngIf="testingMode">
Selected rows:
<div *ngIf="multiselect">
{{ 'SETTINGS_CLOUD.SELECTED_ROWS' | translate }}:
<ul>
<li *ngFor="let row of selectedRows">{{ row.id }}</li>
</ul>
</div>
<div *ngIf="actionMenu">
<span>{{ 'SETTINGS_CLOUD.ACTION.ACTION_MENU' | translate }}:</span>
<br>
<div *ngIf="selectedAction">
<span>{{ 'SETTINGS_CLOUD.ACTION.PROCESS_ID' | translate }}: {{ selectedAction.id }}</span><br>
<span>{{ 'SETTINGS_CLOUD.ACTION.ACTION_TYPE' | translate }}: {{ selectedAction.actionType }}</span>
</div>
</div>
<div *ngIf="contextMenu">
<span>{{ 'SETTINGS_CLOUD.ACTION.CONTEX_MENU' | translate }}:</span>
<br>
<div *ngIf="selectedContextAction">
<span>{{ 'SETTINGS_CLOUD.ACTION.PROCESS_ID' | translate }}: {{ selectedContextAction.id }}</span><br>
<span>{{ 'SETTINGS_CLOUD.ACTION.ACTION_TYPE' | translate }}: {{ selectedContextAction.actionType }}</span>
</div>
</div>
</div>
</div>
</div>

View File

@@ -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<any>();
private onDestroy$ = new Subject<boolean>();
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};
}
}

View File

@@ -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<FilterSettings>({index: 0});

View File

@@ -2,6 +2,12 @@
<mat-slide-toggle [color]="'primary'" [checked]="multiselect" (change)="toggleMultiselect()" data-automation-id="multiSelection">
{{ 'SETTINGS_CLOUD.MULTISELECTION' | translate }}
</mat-slide-toggle>
<mat-slide-toggle [color]="'primary'" [checked]="actionMenu" (change)="toggleActionMenu()" data-automation-id="actionmenu">
{{ 'SETTINGS_CLOUD.ACTION.ACTION_MENU' | translate }}
</mat-slide-toggle>
<mat-slide-toggle [color]="'primary'" [checked]="contextMenu" (change)="toggleContextMenu()" data-automation-id="contextmenu">
{{ 'SETTINGS_CLOUD.ACTION.CONTEX_MENU' | translate }}
</mat-slide-toggle>
<mat-slide-toggle [color]="'primary'" [checked]="testingMode" (change)="toggleTestingMode()" data-automation-id="testingMode">
{{ 'SETTINGS_CLOUD.TESTING_MODE' | translate }}
</mat-slide-toggle>
@@ -21,4 +27,45 @@
</mat-option>
</mat-select>
</mat-form-field>
<mat-card *ngIf="actionMenu || contextMenu">
<mat-card-header>
<mat-card-title>{{ 'SETTINGS_CLOUD.ACTION.ACTION_TITLE' | translate }}</mat-card-title>
</mat-card-header>
<mat-card-content>
<form [formGroup]="actionMenuForm" fxLayout="row" fxLayoutAlign="space-around center" fxLayoutGap="20px">
<mat-form-field fxFlex="23%">
<input matInput formControlName="key" placeholder="{{ 'SETTINGS_CLOUD.ACTION.KEY' | translate }}">
</mat-form-field>
<mat-form-field fxFlex="23%">
<input matInput formControlName="title" placeholder="{{ 'SETTINGS_CLOUD.ACTION.TITLE' | translate }}">
</mat-form-field>
<mat-form-field fxFlex="23%">
<input matInput formControlName="icon" placeholder="{{ 'SETTINGS_CLOUD.ACTION.ICON' | translate }}"I>
</mat-form-field>
<mat-checkbox formControlName="visible">
{{ 'SETTINGS_CLOUD.ACTION.ACTION_VISIBLE' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="disable">
{{ 'SETTINGS_CLOUD.ACTION.ACTION_DISABLE' | translate }}
</mat-checkbox>
<button mat-raised-button (click)="addAction()">
{{ 'SETTINGS_CLOUD.ACTION.ADD_BUTTON' | translate }}
</button>
</form>
<div *ngIf="actions.length > 0">
<mat-chip-list #chipList>
<mat-chip *ngFor="let action of actions" [removable]="true">
{{action.title}}
<mat-icon
matChipRemove
(click)="removeAction(action)">
cancel
</mat-icon>
</mat-chip>
</mat-chip-list>
</div>
</mat-card-content>
</mat-card>
</div>

View File

@@ -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<boolean>();
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(<ActionMenuModel> 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,

View File

@@ -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]

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -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)`<string>` | Emitted when a row in the process list is clicked. |
| rowsSelected | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any[]>` | Emitted when rows are selected/unselected. |
| success | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | 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
<adf-cloud-process-list
[contextMenu]="true"
(showRowContextMenu)="onShowRowContextMenu($event)">
</adf-cloud-process-list>
```
Event properties:
```ts
value: {
row: DataRow,
col: DataColumn,
actions: []
}
```
Handler example:
```ts
onShowRowContextMenu(event: DataCellEvent) {
event.value.actions = [
{ title: 'Hello Context Action' },
{ ... }
]
}
```
![](../../docassets/images/context-menu-on-process-list.png)
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
<adf-cloud-process-list
[actions]="true"
(showRowActionsMenu)="onShowRowActionsMenu($event)"
(executeRowAction)="onExecuteRowAction($event)">
</adf-cloud-process-list>
```
```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}`);
}
```
![](../../docassets/images/action-menu-on-process-list.png)
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)

View File

@@ -1,9 +1,16 @@
<adf-datatable #dataTable
[rows]="rows"
[columns]="columns"
[stickyHeader]="stickyHeader"
[loading]="isLoading"
[selectionMode]="selectionMode"
[multiselect]="multiselect"
[actions]="showActions"
[actionsPosition]="actionsPosition"
[contextMenu]="showContextMenu"
(showRowActionsMenu)="onShowRowActionsMenu($event)"
(showRowContextMenu)="onShowRowContextMenu($event)"
(executeRowAction)="onExecuteRowAction($event)"
(rowClick)="onRowClick($event)"
(row-select)="onRowSelect($event)"
(row-unselect)="onRowUnselect($event)"

View File

@@ -19,12 +19,13 @@ import { Component, ViewEncapsulation, OnChanges, AfterContentInit, ContentChild
import { DataTableSchema, PaginatedComponent,
CustomEmptyContentTemplateDirective, AppConfigService,
UserPreferencesService, PaginationModel,
UserPreferenceValues, DataRowEvent, CustomLoadingContentTemplateDirective } from '@alfresco/adf-core';
UserPreferenceValues, DataRowEvent, CustomLoadingContentTemplateDirective, DataCellEvent, DataRowActionEvent } from '@alfresco/adf-core';
import { ProcessListCloudService } from '../services/process-list-cloud.service';
import { BehaviorSubject } from 'rxjs';
import { processCloudPresetsDefaultModel } from '../models/process-cloud-preset.model';
import { ProcessQueryCloudRequestModel } from '../models/process-cloud-query-request.model';
import { ProcessListCloudSortingModel } from '../models/process-list-sorting.model';
@Component({
selector: 'adf-cloud-process-list',
templateUrl: './process-list-cloud.component.html',
@@ -100,6 +101,22 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan
@Input()
sorting: ProcessListCloudSortingModel[];
/** Toggles the data actions column. */
@Input()
showActions: boolean = false;
/** Position of the actions dropdown menu. Can be "left" or "right". */
@Input()
actionsPosition: string = 'right'; // left|right
/** Toggles the sticky header mode. */
@Input()
stickyHeader: boolean = false;
/** Toggles custom context menu for the component. */
@Input()
showContextMenu: boolean = false;
/** Emitted when a row in the process list is clicked. */
@Output()
rowClick: EventEmitter<string> = new EventEmitter<string>();
@@ -108,6 +125,18 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan
@Output()
rowsSelected: EventEmitter<any[]> = new EventEmitter<any[]>();
/** Emitted before the context menu is displayed for a row. */
@Output()
showRowContextMenu = new EventEmitter<DataCellEvent>();
/** Emitted before the actions menu is displayed for a row. */
@Output()
showRowActionsMenu = new EventEmitter<DataCellEvent>();
/** Emitted when the user executes a row action. */
@Output()
executeRowAction = new EventEmitter<DataRowActionEvent>();
/** Emitted when an error occurs while loading the list of process instances from the server. */
@Output()
error: EventEmitter<any> = new EventEmitter<any>();
@@ -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,