[AAE-9200] - Be able to customise task/process list and header date f… (#7711)

* [AAE-9200] - Be able to customise task/process list and header date formats

* Update json schema

* Revert schema changes

* Update task and process name translation values

* move task/process header date formats inside header config

* Add documentation

* Update documentation

* Use a fixed timezone for unit tests of core and cloud

* Fix e2e due to column rename

* More e2e fixes due to column rename, remove test covered by unit test
This commit is contained in:
Ardit Domi 2022-07-19 15:46:31 +02:00 committed by GitHub
parent 46926ed818
commit fa587510bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 171 additions and 54 deletions

View File

@ -847,6 +847,16 @@ here is the sample resolver which merge the users property and status and it wil
![](../../docassets/images/custom-data-table-resolver.png) ![](../../docassets/images/custom-data-table-resolver.png)
# Tooltip
You can define the tooltip format for cells of type date using a configuration in `app.config.json`:
```json
"dateValues": {
"defaultTooltipDateFormat": "medium"
}
```
## See also ## See also
- [Data column component](data-column.component.md) - [Data column component](data-column.component.md)

View File

@ -50,6 +50,14 @@ However, you can also choose which properties to show using a configuration in `
With this configuration, only the four listed properties will be shown. With this configuration, only the four listed properties will be shown.
You can also define the date format of the date properties using a configuration in `app.config.json`:
```json
"adf-cloud-process-header": {
"defaultDateFormat": "full"
}
```
## See also ## See also
- [Process header cloud service](../../process-services-cloud/services/process-header-cloud.service.md) - [Process header cloud service](../../process-services-cloud/services/process-header-cloud.service.md)

View File

@ -58,3 +58,11 @@ However, you can also choose which properties to show using a configuration in `
``` ```
With this configuration, only the four listed properties will be shown. With this configuration, only the four listed properties will be shown.
You can also define the date format of the date properties using a configuration in `app.config.json`:
```json
"adf-cloud-task-header": {
"defaultDateFormat": "full"
}
```

View File

@ -23,11 +23,11 @@ export class ProcessDetailsCloudDemoPage {
dataTable: DataTableComponentPage = new DataTableComponentPage(); dataTable: DataTableComponentPage = new DataTableComponentPage();
async checkTaskIsDisplayed(taskName: string): Promise<void> { async checkTaskIsDisplayed(taskName: string): Promise<void> {
await this.dataTable.checkContentIsDisplayed('Name', taskName); await this.dataTable.checkContentIsDisplayed('Task Name', taskName);
} }
async selectProcessTaskByName(taskName: string): Promise<void> { async selectProcessTaskByName(taskName: string): Promise<void> {
await this.dataTable.selectRow('Name', taskName); await this.dataTable.selectRow('Task Name', taskName);
} }
async checkListedSelectedProcessInstance(processInstanceId: string): Promise<void> { async checkListedSelectedProcessInstance(processInstanceId: string): Promise<void> {

View File

@ -156,11 +156,11 @@ describe('Process list cloud', () => {
await setFilter({ sort: 'Name' }); await setFilter({ sort: 'Name' });
await setFilter({ order: SORT_DIRECTION.ASC }); await setFilter({ order: SORT_DIRECTION.ASC });
await expect(await processList.getDataTable().checkListIsSorted(SORT_DIRECTION.ASC, 'Name')).toBe(true); await expect(await processList.getDataTable().checkListIsSorted(SORT_DIRECTION.ASC, 'Process Name')).toBe(true);
await setFilter({ order: SORT_DIRECTION.DESC}); await setFilter({ order: SORT_DIRECTION.DESC});
await expect(await processList.getDataTable().checkListIsSorted(SORT_DIRECTION.DESC, 'Name')).toBe(true); await expect(await processList.getDataTable().checkListIsSorted(SORT_DIRECTION.DESC, 'Process Name')).toBe(true);
}); });
it('[C291783] Should display processes ordered by id when Id is selected from sort dropdown', async () => { it('[C291783] Should display processes ordered by id when Id is selected from sort dropdown', async () => {

View File

@ -266,7 +266,7 @@ describe('Start Task Form', () => {
await processList.getDataTable().waitTillContentLoaded(); await processList.getDataTable().waitTillContentLoaded();
await processList.checkContentIsDisplayedByName(startEventFormProcess); await processList.checkContentIsDisplayedByName(startEventFormProcess);
await processList.getDataTable().selectRow('Name', startEventFormProcess); await processList.getDataTable().selectRow('Process Name', startEventFormProcess);
await browser.actions().sendKeys(protractor.Key.ENTER).perform(); await browser.actions().sendKeys(protractor.Key.ENTER).perform();
await processDetailsCloudDemoPage.checkTaskIsDisplayed('StartEventFormTask'); await processDetailsCloudDemoPage.checkTaskIsDisplayed('StartEventFormTask');

View File

@ -20,7 +20,6 @@ import { createApiService,
AppListCloudPage, AppListCloudPage,
GroupIdentityService, GroupIdentityService,
IdentityService, IdentityService,
LocalStorageUtil,
LoginPage, LoginPage,
StringUtil, StringUtil,
TaskHeaderCloudPage, TaskHeaderCloudPage,
@ -68,7 +67,6 @@ describe('Task Header cloud component', () => {
let subTask: any; let subTask: any;
let subTaskCreatedDate: string; let subTaskCreatedDate: string;
let completedEndDate: string; let completedEndDate: string;
let defaultDate: string;
let groupInfo: any; let groupInfo: any;
let testUser: any; let testUser: any;
let unclaimedTask: any; let unclaimedTask: any;
@ -76,7 +74,6 @@ describe('Task Header cloud component', () => {
const description = 'descriptionTask'; const description = 'descriptionTask';
const formatDate = 'MMM D, YYYY'; const formatDate = 'MMM D, YYYY';
const dateTimeFormat = 'MMM D, Y, H:mm'; const dateTimeFormat = 'MMM D, Y, H:mm';
const defaultFormat = 'M/D/YY';
const createCompletedTask = async function () { const createCompletedTask = async function () {
const completedTaskId = await tasksService.createStandaloneTask(completedTaskName, const completedTaskId = await tasksService.createStandaloneTask(completedTaskName,
@ -117,7 +114,6 @@ describe('Task Header cloud component', () => {
completedCreatedDate = moment(completedTask.entry.createdDate).format(formatDate); completedCreatedDate = moment(completedTask.entry.createdDate).format(formatDate);
dueDate = moment(completedTask.entry.dueDate).format(dateTimeFormat); dueDate = moment(completedTask.entry.dueDate).format(dateTimeFormat);
completedEndDate = moment(completedTask.entry.endDate).format(formatDate); completedEndDate = moment(completedTask.entry.endDate).format(formatDate);
defaultDate = moment(completedTask.entry.createdDate).format(defaultFormat);
subTask = await createSubTask(createdTaskId); subTask = await createSubTask(createdTaskId);
subTaskCreatedDate = moment(subTask.entry.createdDate).format(formatDate); subTaskCreatedDate = moment(subTask.entry.createdDate).format(formatDate);
@ -241,29 +237,4 @@ describe('Task Header cloud component', () => {
await peopleCloudComponentPage.searchAssignee('modeler'); await peopleCloudComponentPage.searchAssignee('modeler');
await peopleCloudComponentPage.checkNoResultsFoundError(); await peopleCloudComponentPage.checkNoResultsFoundError();
}); });
describe('Default Date format', () => {
beforeEach(async () => {
await LocalStorageUtil.setConfigField('dateValues', '{' +
'"defaultDateFormat": "shortDate",' +
'"defaultDateTimeFormat": "M/d/yy, h:mm a",' +
'"defaultLocale": "uk"' +
'}');
await navigationBarPage.navigateToProcessServicesCloudPage();
await appListCloudComponent.checkApsContainer();
await appListCloudComponent.goToApp(simpleApp);
});
it('[C311280] Should pick up the default date format from the app configuration', async () => {
await taskFilter.clickTaskFilter('completed-tasks');
await taskList.getDataTable().waitTillContentLoaded();
await taskList.checkContentIsDisplayedByName(completedTaskName);
await taskList.selectRow(completedTaskName);
await tasksCloudDemoPage.waitTillContentLoaded();
await taskHeaderCloudPage.checkTaskPropertyListIsDisplayed();
await expect(await taskHeaderCloudPage.getCreated()).toEqual(defaultDate);
});
});
}); });

View File

@ -142,10 +142,10 @@ describe('Edit task filters and task list properties', () => {
await editTaskFilter.setSortFilterDropDown('name'); await editTaskFilter.setSortFilterDropDown('name');
await editTaskFilter.setOrderFilterDropDown(SORT_ORDER.ASC); await editTaskFilter.setOrderFilterDropDown(SORT_ORDER.ASC);
await expect(await taskList.getDataTable().checkListIsSorted(SORT_ORDER.ASC, 'Name')).toBe(true); await expect(await taskList.getDataTable().checkListIsSorted(SORT_ORDER.ASC, 'Task Name')).toBe(true);
await editTaskFilter.setOrderFilterDropDown(SORT_ORDER.DESC); await editTaskFilter.setOrderFilterDropDown(SORT_ORDER.DESC);
await expect(await taskList.getDataTable().checkListIsSorted(SORT_ORDER.DESC, 'Name')).toBe(true); await expect(await taskList.getDataTable().checkListIsSorted(SORT_ORDER.DESC, 'Task Name')).toBe(true);
}); });
it('[C290156] Should display tasks ordered by id when Id is selected from sort dropdown', async () => { it('[C290156] Should display tasks ordered by id when Id is selected from sort dropdown', async () => {

View File

@ -0,0 +1,73 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { UserPreferencesService } from '../../../services';
import { AppConfigService } from '../../../app-config';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CoreTestingModule } from '../../../testing';
import { DateCellComponent } from './date-cell.component';
describe('DateCellComponent', () => {
let appConfigService: AppConfigService;
let userPreferencesService: UserPreferencesService;
let fixture: ComponentFixture<DateCellComponent>;
let component: DateCellComponent;
let getLocaleSpy: jasmine.Spy;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
CoreTestingModule
],
declarations: [DateCellComponent]
});
appConfigService = TestBed.inject(AppConfigService);
userPreferencesService = TestBed.inject(UserPreferencesService);
getLocaleSpy = spyOn(userPreferencesService, 'select').and.callThrough();
appConfigService.config = {
dateValues: {
defaultDateFormat: 'mediumDate',
defaultTooltipDateFormat: 'medium'
}
};
fixture = TestBed.createComponent(DateCellComponent);
component = fixture.componentInstance;
});
it('should read locale from user preferences service', () => {
expect(getLocaleSpy).toHaveBeenCalledWith('locale');
expect(component.currentLocale).toEqual('en');
});
it('should read date format values from app config service', () => {
expect(component.format).toEqual('mediumDate');
expect(component.tooltipDateFormat).toEqual('medium');
});
it('should date values be formatted based on the formats defined in the app config', () => {
component.value$.next('2022-07-14T11:50:45.973+0000');
component.tooltip = '2022-07-14T11:50:45.973+0000';
fixture.detectChanges();
const dateCellValue = fixture.nativeElement.querySelector('.adf-datatable-cell-value');
const tooltipValue = dateCellValue.attributes['title'].value;
expect(dateCellValue.textContent.trim()).toEqual('Jul 14, 2022');
expect(dateCellValue.attributes['aria-label'].value).toEqual('Jul 14, 2022');
expect(tooltipValue).toEqual('Jul 14, 2022, 11:50:45 AM');
});
});

View File

@ -41,8 +41,7 @@ import { takeUntil } from 'rxjs/operators';
<ng-template #standard_date> <ng-template #standard_date>
<span <span
class="adf-datatable-cell-value" class="adf-datatable-cell-value"
title="{{ tooltip | adfLocalizedDate: format }}" title="{{ tooltip | adfLocalizedDate: tooltipDateFormat }}"
class="adf-datatable-cell-value"
[attr.aria-label]="value$ | async | adfLocalizedDate: format"> [attr.aria-label]="value$ | async | adfLocalizedDate: format">
{{ value$ | async | adfLocalizedDate: format }} {{ value$ | async | adfLocalizedDate: format }}
</span> </span>
@ -57,6 +56,7 @@ export class DateCellComponent extends DataTableCellComponent {
currentLocale: string; currentLocale: string;
dateFormat: string; dateFormat: string;
tooltipDateFormat: string;
get format(): string { get format(): string {
if (this.column) { if (this.column) {
@ -73,6 +73,7 @@ export class DateCellComponent extends DataTableCellComponent {
super(alfrescoApiService); super(alfrescoApiService);
this.dateFormat = appConfig.get('dateValues.defaultDateFormat', DateCellComponent.DATE_FORMAT); this.dateFormat = appConfig.get('dateValues.defaultDateFormat', DateCellComponent.DATE_FORMAT);
this.tooltipDateFormat = appConfig.get('dateValues.defaultTooltipDateFormat', DateCellComponent.DATE_FORMAT);
if (userPreferenceService) { if (userPreferenceService) {
userPreferenceService userPreferenceService
.select(UserPreferenceValues.Locale) .select(UserPreferenceValues.Locale)

View File

@ -102,4 +102,5 @@ module.exports = function (config) {
browsers: ['Chrome'], browsers: ['Chrome'],
singleRun: false singleRun: false
}); });
process.env.TZ = 'UTC';
}; };

View File

@ -84,4 +84,5 @@ module.exports = function (config) {
browsers: ['Chrome'], browsers: ['Chrome'],
singleRun: false singleRun: false
}); });
process.env.TZ = 'UTC';
}; };

View File

@ -6,7 +6,7 @@
"NONE": "No process instance filter selected." "NONE": "No process instance filter selected."
}, },
"PROPERTIES": { "PROPERTIES": {
"NAME": "Name", "NAME": "Process Name",
"CREATED": "Created", "CREATED": "Created",
"STATUS": "Status", "STATUS": "Status",
"START_DATE": "Start Date", "START_DATE": "Start Date",
@ -83,7 +83,7 @@
} }
}, },
"PROPERTIES": { "PROPERTIES": {
"NAME": "Name", "NAME": "Task Name",
"ASSIGNEE": "Assignee", "ASSIGNEE": "Assignee",
"ID": "Id", "ID": "Id",
"STATUS": "Status", "STATUS": "Status",

View File

@ -34,7 +34,7 @@ export const processInstancePlaceholdersCloudMock: ProcessInstanceCloud = {
businessKey: '', businessKey: '',
id: '00fcc4ab-4290-11e9-b133-0a586460016a', id: '00fcc4ab-4290-11e9-b133-0a586460016a',
initiator: 'devopsuser', initiator: 'devopsuser',
lastModified: new Date(1552152187081), lastModified: new Date(2022, 1, 1, 1, 30, 40),
name: '', name: '',
parentId: '', parentId: '',
startDate: new Date(1552152187080), startDate: new Date(1552152187080),

View File

@ -206,4 +206,28 @@ describe('ProcessHeaderCloudComponent', () => {
expect(propertyList[1].nativeElement.textContent).toContain('ADF_CLOUD_PROCESS_HEADER.PROPERTIES.NAME'); expect(propertyList[1].nativeElement.textContent).toContain('ADF_CLOUD_PROCESS_HEADER.PROPERTIES.NAME');
}); });
}); });
describe('Date values format', () => {
beforeEach(() => {
appConfigService.config = {
'adf-cloud-process-header': {
defaultDateFormat: 'full'
}
};
component.ngOnInit();
component.ngOnChanges();
});
it('should format the dates based on app config format configuration', async () => {
fixture.detectChanges();
await fixture.whenStable();
const startedDateElement = fixture.debugElement.query(By.css('[data-automation-id="header-startDate"] .adf-property-value'));
const lastModifiedElement = fixture.debugElement.query(By.css('[data-automation-id="header-lastModified"] .adf-property-value'));
expect(component.dateFormat).toEqual('full');
expect(startedDateElement.nativeElement.innerText.trim()).toBe('Saturday, March 9, 2019 at 5:23:07 PM GMT+00:00');
expect(lastModifiedElement.nativeElement.innerText.trim()).toBe('Saturday, March 9, 2019 at 5:23:07 PM GMT+00:00');
});
});
}); });

View File

@ -55,7 +55,7 @@ export class ProcessHeaderCloudComponent implements OnChanges, OnInit, OnDestroy
} }
ngOnInit() { ngOnInit() {
this.dateFormat = this.appConfig.get('dateValues.defaultDateFormat'); this.dateFormat = this.appConfig.get('adf-cloud-process-header.defaultDateFormat');
this.dateLocale = this.appConfig.get('dateValues.defaultDateLocale'); this.dateLocale = this.appConfig.get('dateValues.defaultDateLocale');
this.processCloudService.dataChangesDetected this.processCloudService.dataChangesDetected

View File

@ -31,7 +31,6 @@ import {
taskDetailsWithParentTaskIdMock, taskDetailsWithParentTaskIdMock,
createdTaskDetailsCloudMock createdTaskDetailsCloudMock
} from '../mocks/task-details-cloud.mock'; } from '../mocks/task-details-cloud.mock';
import moment from 'moment-es6';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
@ -67,9 +66,14 @@ describe('TaskHeaderCloudComponent', () => {
}); });
beforeEach(() => { beforeEach(() => {
appConfigService = TestBed.inject(AppConfigService);
appConfigService.config = {
'adf-cloud-task-header': {
defaultDateFormat: 'full'
}
};
fixture = TestBed.createComponent(TaskHeaderCloudComponent); fixture = TestBed.createComponent(TaskHeaderCloudComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
appConfigService = TestBed.inject(AppConfigService);
taskCloudService = TestBed.inject(TaskCloudService); taskCloudService = TestBed.inject(TaskCloudService);
alfrescoApiService = TestBed.inject(AlfrescoApiService); alfrescoApiService = TestBed.inject(AlfrescoApiService);
component.appName = 'mock-app-name'; component.appName = 'mock-app-name';
@ -103,7 +107,7 @@ describe('TaskHeaderCloudComponent', () => {
expect(taskTitle).toBeTruthy(); expect(taskTitle).toBeTruthy();
}); });
it('should fectch task details when appName and taskId defined', async () => { it('should fetch task details when appName and taskId defined', async () => {
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable(); await fixture.whenStable();
expect(getTaskByIdSpy).toHaveBeenCalled(); expect(getTaskByIdSpy).toHaveBeenCalled();
@ -149,7 +153,7 @@ describe('TaskHeaderCloudComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
const valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-dueDate"] .adf-property-value')); const valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-dueDate"] .adf-property-value'));
expect(valueEl.nativeElement.innerText.trim()).toBe(moment(assignedTaskDetailsCloudMock.dueDate, 'x').format('MMM D, Y, H:mm')); expect(valueEl.nativeElement.innerText.trim()).toBe('Monday, December 17, 2018 at 12:00:55 PM GMT+00:00');
}); });
it('should display process instance id', async () => { it('should display process instance id', async () => {
@ -501,7 +505,13 @@ describe('TaskHeaderCloudComponent', () => {
describe('Config properties', () => { describe('Config properties', () => {
it('should show only the properties from the configuration file', async () => { it('should show only the properties from the configuration file', async () => {
spyOn(appConfigService, 'get').and.returnValue(['assignee', 'status']); appConfigService.config = {
'adf-cloud-task-header': {
presets: {
properties: ['assignee', 'status']
}
}
};
component.ngOnChanges(); component.ngOnChanges();
fixture.detectChanges(); fixture.detectChanges();
const propertyList = fixture.debugElement.queryAll(By.css('.adf-property-list .adf-property')); const propertyList = fixture.debugElement.queryAll(By.css('.adf-property-list .adf-property'));
@ -527,6 +537,18 @@ describe('TaskHeaderCloudComponent', () => {
expect(propertyList[0].nativeElement.textContent).toContain('ADF_CLOUD_TASK_HEADER.PROPERTIES.ASSIGNEE'); expect(propertyList[0].nativeElement.textContent).toContain('ADF_CLOUD_TASK_HEADER.PROPERTIES.ASSIGNEE');
expect(propertyList[1].nativeElement.textContent).toContain('ADF_CLOUD_TASK_HEADER.PROPERTIES.STATUS'); expect(propertyList[1].nativeElement.textContent).toContain('ADF_CLOUD_TASK_HEADER.PROPERTIES.STATUS');
}); });
it('should format the dates based on app config format configuration', async () => {
component.ngOnInit();
component.ngOnChanges();
fixture.detectChanges();
await fixture.whenStable();
const createdDateElement = fixture.debugElement.query(By.css('[data-automation-id="header-created"] .adf-property-value'));
expect(component.dateFormat).toEqual('full');
expect(createdDateElement.nativeElement.innerText.trim()).toBe('Monday, December 17, 2018 at 12:00:55 PM GMT+00:00');
});
}); });
describe('Task errors', () => { describe('Task errors', () => {

View File

@ -74,7 +74,6 @@ export class TaskHeaderCloudComponent implements OnInit, OnDestroy, OnChanges {
inEdit: boolean = false; inEdit: boolean = false;
parentTaskName: string; parentTaskName: string;
dateFormat: string; dateFormat: string;
dateTimeFormat: string;
dateLocale: string; dateLocale: string;
displayDateClearAction = false; displayDateClearAction = false;
isLoading = true; isLoading = true;
@ -88,9 +87,8 @@ export class TaskHeaderCloudComponent implements OnInit, OnDestroy, OnChanges {
private appConfig: AppConfigService, private appConfig: AppConfigService,
private cardViewUpdateService: CardViewUpdateService private cardViewUpdateService: CardViewUpdateService
) { ) {
this.dateFormat = this.appConfig.get('dateValues.defaultDateFormat'); this.dateFormat = this.appConfig.get('adf-cloud-task-header.defaultDateFormat');
this.dateLocale = this.appConfig.get('dateValues.defaultDateLocale'); this.dateLocale = this.appConfig.get('dateValues.defaultDateLocale');
this.dateTimeFormat = this.appConfig.get('dateValue.defaultDateTimeFormat');
} }
ngOnInit() { ngOnInit() {
@ -178,7 +176,7 @@ export class TaskHeaderCloudComponent implements OnInit, OnDestroy, OnChanges {
key: 'dueDate', key: 'dueDate',
default: this.translationService.instant('ADF_CLOUD_TASK_HEADER.PROPERTIES.DUE_DATE_DEFAULT'), default: this.translationService.instant('ADF_CLOUD_TASK_HEADER.PROPERTIES.DUE_DATE_DEFAULT'),
editable: true, editable: true,
format: this.dateTimeFormat, format: this.dateFormat,
locale: this.dateLocale locale: this.dateLocale
} }
), ),

View File

@ -49,7 +49,7 @@ export const assignedTaskDetailsCloudMock: TaskDetailsCloudModel = {
name: 'This is a new task', name: 'This is a new task',
description: 'This is the description ', description: 'This is the description ',
createdDate: new Date(1545048055900), createdDate: new Date(1545048055900),
dueDate: new Date(), dueDate: new Date(1545048055900),
claimedDate: null, claimedDate: null,
priority: 1, priority: 1,
category: null, category: null,

View File

@ -25,7 +25,7 @@ export class ProcessListCloudComponentPage {
columns = { columns = {
id: 'Id', id: 'Id',
name: 'Name', name: 'Process Name',
processDefinitionName: 'Process Definition Name' processDefinitionName: 'Process Definition Name'
}; };

View File

@ -23,7 +23,7 @@ import { DataTableColumnSelector } from '../../core/pages/data-table/columns-sel
const column = { const column = {
id: 'Id', id: 'Id',
name: 'Name', name: 'Task Name',
processInstanceId: 'ProcessInstanceId', processInstanceId: 'ProcessInstanceId',
processDefinitionId: 'ProcessDefinitionId', processDefinitionId: 'ProcessDefinitionId',
assignee: 'Assignee', assignee: 'Assignee',