mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ACA-3000][ACA-2999] FE - Provide way to show ContextMenu on Task/Process list (#5596)
* [ACA-3000] FE - Provide way to show ContextMenu on Task list * * Updated docs * * Added unit tests to the recent changes
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
[selectionMode]="selectionMode"
|
||||
[multiselect]="multiselect"
|
||||
[resolverFn]="resolverFn"
|
||||
[contextMenu]="showContextMenu"
|
||||
(showRowContextMenu)="onShowRowContextMenu($event)"
|
||||
(rowClick)="onRowClick($event)"
|
||||
(row-keyup)="onRowKeyUp($event)">
|
||||
<adf-loading-content-template>
|
||||
|
@@ -15,14 +15,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, SimpleChange, ViewChild } from '@angular/core';
|
||||
import { Component, SimpleChange, ViewChild, OnInit, Output, EventEmitter } from '@angular/core';
|
||||
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
import { of, throwError } from 'rxjs';
|
||||
import { of, throwError, Subject } from 'rxjs';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { ProcessInstanceListComponent } from './process-list.component';
|
||||
import {
|
||||
AppConfigService, setupTestBed, CoreModule, DataTableModule, DataRow, DataColumn,
|
||||
DataRowEvent, ObjectDataRow, ObjectDataTableAdapter
|
||||
DataRowEvent, ObjectDataRow, ObjectDataTableAdapter, DataCellEvent
|
||||
} from '@alfresco/adf-core';
|
||||
import { fakeProcessInstance, fakeProcessInstancesWithNoName, fakeProcessInstancesEmpty, fakeProcessCustomSchema } from '../../mock';
|
||||
import { ProcessService } from '../services/process.service';
|
||||
@@ -527,3 +527,115 @@ describe('Process List: Custom EmptyTemplateComponent', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<adf-process-instance-list
|
||||
[appId]="appId"
|
||||
[showContextMenu]="true"
|
||||
(showRowContextMenu)="onShowRowContextMenu($event)"
|
||||
#processlistComponentInstance>
|
||||
<data-columns>
|
||||
<data-column key="name" title="ADF_PROCESS_LIST.PROPERTIES.NAME" class="adf-full-width adf-name-column"></data-column>
|
||||
<data-column key="created" title="ADF_PROCESS_LIST.PROPERTIES.END_DATE" class="adf-hidden"></data-column>
|
||||
<data-column key="startedBy" title="ADF_PROCESS_LIST.PROPERTIES.CREATED" class="adf-desktop-only dw-dt-col-3 adf-ellipsis-cell">
|
||||
<ng-template let-entry="$implicit">
|
||||
<div>{{entry.row.obj.startedBy | fullName}}</div>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</data-columns>
|
||||
</adf-process-instance-list>`
|
||||
})
|
||||
|
||||
class ProcessListContextMenuComponent implements OnInit {
|
||||
|
||||
appId: number;
|
||||
@Output()
|
||||
contextAction = new EventEmitter<any>();
|
||||
private performAction$ = new Subject<any>();
|
||||
|
||||
ngOnInit() {
|
||||
this.performContextActions();
|
||||
}
|
||||
|
||||
onShowRowContextMenu(event: DataCellEvent) {
|
||||
event.value.actions = [
|
||||
{
|
||||
data: event.value.row['obj'],
|
||||
model:
|
||||
{
|
||||
key: 'processDetails',
|
||||
icon: 'open',
|
||||
title: 'View Process Details',
|
||||
visible: true
|
||||
},
|
||||
subject: this.performAction$
|
||||
},
|
||||
{
|
||||
data: event.value.row['obj'],
|
||||
model:
|
||||
{
|
||||
key: 'cancel',
|
||||
icon: 'open',
|
||||
title: 'Cancel Process',
|
||||
visible: true
|
||||
},
|
||||
subject: this.performAction$
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
performContextActions() {
|
||||
this.performAction$
|
||||
.subscribe((action: any) => {
|
||||
this.contextAction.emit(action.data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
describe('ProcessListContextMenuComponent', () => {
|
||||
let fixture: ComponentFixture<ProcessListContextMenuComponent>;
|
||||
let customComponent: ProcessListContextMenuComponent;
|
||||
let processService: ProcessService;
|
||||
let element: HTMLElement;
|
||||
|
||||
setupTestBed({
|
||||
imports: [CoreModule.forRoot()],
|
||||
declarations: [ProcessInstanceListComponent, ProcessListContextMenuComponent],
|
||||
providers: [ProcessService]
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProcessListContextMenuComponent);
|
||||
customComponent = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
processService = TestBed.get(ProcessService);
|
||||
customComponent.appId = 12345;
|
||||
spyOn(processService, 'getProcesses').and.returnValue(of(fakeProcessInstance));
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
const event = new KeyboardEvent('keydown', {
|
||||
bubbles : true, cancelable : true, key : 'Escape'
|
||||
});
|
||||
document.querySelector('.cdk-overlay-backdrop').dispatchEvent(event);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('Should be able to show context menu on process list', async () => {
|
||||
const contextMenu = element.querySelector(`[data-automation-id="text_${fakeProcessInstance.data[0].name}"]`);
|
||||
const contextActionSpy = spyOn(customComponent.contextAction, 'emit').and.callThrough();
|
||||
contextMenu.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true }));
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const contextActions = document.querySelectorAll('.mat-menu-item');
|
||||
|
||||
expect(contextActions.length).toBe(2);
|
||||
expect(contextActions[0]['disabled']).toBe(false, 'View Process Details action not enabled');
|
||||
expect(contextActions[1]['disabled']).toBe(false, 'Cancel Process action not enabled');
|
||||
contextActions[0].dispatchEvent(new Event('click'));
|
||||
fixture.detectChanges();
|
||||
expect(contextActionSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@@ -27,7 +27,8 @@ import {
|
||||
PaginatedComponent,
|
||||
PaginationComponent,
|
||||
PaginationModel,
|
||||
UserPreferencesService
|
||||
UserPreferencesService,
|
||||
DataCellEvent
|
||||
} from '@alfresco/adf-core';
|
||||
import {
|
||||
AfterContentInit,
|
||||
@@ -110,6 +111,14 @@ export class ProcessInstanceListComponent extends DataTableSchema implements OnC
|
||||
@Input()
|
||||
selectFirstRow: boolean = true;
|
||||
|
||||
/** Toggles custom context menu for the component. */
|
||||
@Input()
|
||||
showContextMenu: boolean = false;
|
||||
|
||||
/** Emitted before the context menu is displayed for a row. */
|
||||
@Output()
|
||||
showRowContextMenu = new EventEmitter<DataCellEvent>();
|
||||
|
||||
/**
|
||||
* Resolver function is used to show dynamic complex column objects
|
||||
* see the docs to learn how to configure a resolverFn.
|
||||
@@ -284,6 +293,10 @@ export class ProcessInstanceListComponent extends DataTableSchema implements OnC
|
||||
}
|
||||
}
|
||||
|
||||
onShowRowContextMenu(event: DataCellEvent) {
|
||||
this.showRowContextMenu.emit(event);
|
||||
}
|
||||
|
||||
private createRequestNode(): ProcessFilterParamRepresentationModel {
|
||||
return new ProcessFilterParamRepresentationModel({
|
||||
appDefinitionId: this.appId,
|
||||
|
@@ -8,6 +8,8 @@
|
||||
[loading]="isLoading"
|
||||
[multiselect]="multiselect"
|
||||
[selectionMode]="selectionMode"
|
||||
[contextMenu]="showContextMenu"
|
||||
(showRowContextMenu)="onShowRowContextMenu($event)"
|
||||
(row-select)="onRowSelect($event)"
|
||||
(row-unselect)="onRowUnselect($event)"
|
||||
(rowClick)="onRowClick($event)"
|
||||
|
@@ -15,16 +15,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, SimpleChange, ViewChild } from '@angular/core';
|
||||
import { Component, SimpleChange, ViewChild, OnInit, Output, EventEmitter } from '@angular/core';
|
||||
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { AppConfigService, setupTestBed, CoreModule, DataTableModule, DataRowEvent, ObjectDataRow } from '@alfresco/adf-core';
|
||||
import { AppConfigService, setupTestBed, CoreModule, DataTableModule, DataRowEvent, ObjectDataRow, DataCellEvent } from '@alfresco/adf-core';
|
||||
import { TaskListService } from '../services/tasklist.service';
|
||||
import { TaskListComponent } from './task-list.component';
|
||||
import { ProcessTestingModule } from '../../testing/process.testing.module';
|
||||
import { fakeGlobalTask, fakeCustomSchema, fakeEmptyTask, paginatedTask } from '../../mock';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { of } from 'rxjs';
|
||||
import { of, Subject } from 'rxjs';
|
||||
import { TaskListModule } from '../task-list.module';
|
||||
|
||||
declare let jasmine: any;
|
||||
@@ -807,3 +807,112 @@ describe('Task List: Custom EmptyTemplateComponent', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<adf-tasklist
|
||||
[showContextMenu]="true"
|
||||
(showRowContextMenu)="onShowRowContextMenu($event)"
|
||||
#taskList>
|
||||
<data-columns>
|
||||
<data-column key="name" title="ADF_TASK_LIST.PROPERTIES.NAME" class="full-width name-column"></data-column>
|
||||
<data-column key="created" title="ADF_TASK_LIST.PROPERTIES.CREATED" class="hidden"></data-column>
|
||||
<data-column key="startedBy" title="ADF_TASK_LIST.PROPERTIES.CREATED" class="desktop-only dw-dt-col-3 ellipsis-cell">
|
||||
<ng-template let-entry="$implicit">
|
||||
<div>{{entry.row?.obj?.startedBy | fullName}}</div>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</data-columns>
|
||||
</adf-tasklist>`
|
||||
})
|
||||
|
||||
class TaskListContextMenuComponent implements OnInit {
|
||||
|
||||
@Output()
|
||||
contextAction = new EventEmitter<any>();
|
||||
private performAction$ = new Subject<any>();
|
||||
|
||||
ngOnInit() {
|
||||
this.performContextActions();
|
||||
}
|
||||
|
||||
onShowRowContextMenu(event: DataCellEvent) {
|
||||
event.value.actions = [
|
||||
{
|
||||
data: event.value.row['obj'],
|
||||
model:
|
||||
{
|
||||
key: 'taskDetails',
|
||||
icon: 'open',
|
||||
title: 'View Task Details',
|
||||
visible: true
|
||||
},
|
||||
subject: this.performAction$
|
||||
},
|
||||
{
|
||||
data: event.value.row['obj'],
|
||||
model:
|
||||
{
|
||||
key: 'cancel',
|
||||
icon: 'open',
|
||||
title: 'Cancel Process',
|
||||
visible: true
|
||||
},
|
||||
subject: this.performAction$
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
performContextActions() {
|
||||
this.performAction$
|
||||
.subscribe((action: any) => {
|
||||
this.contextAction.emit(action.data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
describe('TaskListContextMenuComponent', () => {
|
||||
let fixture: ComponentFixture<TaskListContextMenuComponent>;
|
||||
let customComponent: TaskListContextMenuComponent;
|
||||
let taskListService: TaskListService;
|
||||
let element: HTMLElement;
|
||||
|
||||
setupTestBed({
|
||||
imports: [CoreModule.forRoot()],
|
||||
declarations: [TaskListComponent, TaskListContextMenuComponent],
|
||||
providers: [TaskListService]
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(TaskListContextMenuComponent);
|
||||
customComponent = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
taskListService = TestBed.get(TaskListService);
|
||||
spyOn(taskListService, 'findTasksByState').and.returnValues(of(fakeGlobalTask));
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
const event = new KeyboardEvent('keydown', {
|
||||
bubbles : true, cancelable : true, key : 'Escape'
|
||||
});
|
||||
document.querySelector('.cdk-overlay-backdrop').dispatchEvent(event);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('Should be able to show context menu on task list', async () => {
|
||||
const contextMenu = element.querySelector(`[data-automation-id="text_${fakeGlobalTask.data[0].name}"]`);
|
||||
const contextActionSpy = spyOn(customComponent.contextAction, 'emit').and.callThrough();
|
||||
contextMenu.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true }));
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const contextActions = document.querySelectorAll('.mat-menu-item');
|
||||
|
||||
expect(contextActions.length).toBe(2);
|
||||
expect(contextActions[0]['disabled']).toBe(false, 'View Task Details action not enabled');
|
||||
expect(contextActions[1]['disabled']).toBe(false, 'Cancel Task action not enabled');
|
||||
contextActions[0].dispatchEvent(new Event('click'));
|
||||
fixture.detectChanges();
|
||||
expect(contextActionSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@@ -18,7 +18,7 @@
|
||||
import {
|
||||
DataRowEvent, DataTableAdapter, DataTableSchema, CustomEmptyContentTemplateDirective, CustomLoadingContentTemplateDirective,
|
||||
AppConfigService, PaginationComponent, PaginatedComponent,
|
||||
UserPreferencesService, UserPreferenceValues, PaginationModel } from '@alfresco/adf-core';
|
||||
UserPreferencesService, UserPreferenceValues, PaginationModel, DataCellEvent } from '@alfresco/adf-core';
|
||||
import {
|
||||
AfterContentInit, Component, ContentChild, EventEmitter,
|
||||
Input, OnChanges, Output, SimpleChanges, OnDestroy, OnInit } from '@angular/core';
|
||||
@@ -123,6 +123,14 @@ export class TaskListComponent extends DataTableSchema implements OnChanges, Aft
|
||||
@Input()
|
||||
start: number;
|
||||
|
||||
/** Toggles custom context menu for the component. */
|
||||
@Input()
|
||||
showContextMenu: boolean = false;
|
||||
|
||||
/** Emitted before the context menu is displayed for a row. */
|
||||
@Output()
|
||||
showRowContextMenu = new EventEmitter<DataCellEvent>();
|
||||
|
||||
/** Emitted when a task in the list is clicked */
|
||||
@Output()
|
||||
rowClick = new EventEmitter<string>();
|
||||
@@ -356,6 +364,10 @@ export class TaskListComponent extends DataTableSchema implements OnChanges, Aft
|
||||
}
|
||||
}
|
||||
|
||||
onShowRowContextMenu(event: DataCellEvent) {
|
||||
this.showRowContextMenu.emit(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize name field
|
||||
* @param instances
|
||||
|
Reference in New Issue
Block a user