mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[AAE-7856] Show variables in table
This commit is contained in:
@@ -21,6 +21,7 @@ Defines column properties for DataTable, Tasklist, Document List and other compo
|
||||
- [Column Template](#column-template)
|
||||
- [Styling Techniques](#styling-techniques)
|
||||
- [Using the copyContent option](#using-the-copycontent-option)
|
||||
- [Exapmple of column customData](#example-of-column-customData)
|
||||
- [See also](#see-also)
|
||||
|
||||
## Basic Usage
|
||||
@@ -52,6 +53,7 @@ Defines column properties for DataTable, Tasklist, Document List and other compo
|
||||
| formatTooltip | `Function` | | Custom tooltip formatter function. |
|
||||
| key | `string` | | Data source key. Can be either a column/property key like `title` or a property path like `createdBy.name`. |
|
||||
| sortable | `boolean` | true | Toggles ability to sort by this column, for example by clicking the column header. |
|
||||
| customData | `Generic` | any | Any feature specific data |
|
||||
| draggable | `boolean` | false | Toggles drag and drop for header column. |
|
||||
| isHidden | `boolean` | false | Hides columns |
|
||||
| sortingKey | `string` | | When using server side sorting the column used by the api call where the sorting will be performed |
|
||||
@@ -351,6 +353,35 @@ HTML `<data-column>` element example:
|
||||
</adf-tasklist>
|
||||
```
|
||||
|
||||
### Example of column customData
|
||||
|
||||
If you would like to pass any custom data related to your specific feature, you can use customData
|
||||
|
||||
HTML `<data-column>` element example:
|
||||
|
||||
```html
|
||||
<data-column [customData]="MyCustomData" key="id" title="Id"></data-column>
|
||||
```
|
||||
|
||||
You can use generic type for `DataColumn` in order to get intellisense working e.g.
|
||||
|
||||
```ts
|
||||
const dataColumn: DataColumn<{ shouldPerformActionIfDisplayed: boolean }> = {
|
||||
...
|
||||
customData: { shouldPerformActionIfDisplayed: true }
|
||||
}
|
||||
|
||||
// We should get proper types
|
||||
consol.log(dataColumn.customData.shouldPerformActionIfDisplayed);
|
||||
|
||||
// Now we can use this data in our feature e.g.
|
||||
const shouldPerformAction = this.columns
|
||||
.filter(column => column.isHidden)
|
||||
.some(column => column.customData?.shouldPerformActionIfDisplayed === true);
|
||||
|
||||
if (shouldPerformAction) { /* action */}
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [Document list component](../../content-services/components/document-list.component.md)
|
||||
|
@@ -70,6 +70,10 @@ export class ShareDataTableAdapter implements DataTableAdapter {
|
||||
this.allowDropFiles = allowDropFiles;
|
||||
}
|
||||
|
||||
getColumnType(_row: DataRow, col: DataColumn): string {
|
||||
return col.type;
|
||||
}
|
||||
|
||||
getRows(): Array<DataRow> {
|
||||
return this.rows;
|
||||
}
|
||||
|
@@ -34,6 +34,10 @@ export class DataColumnComponent implements OnInit {
|
||||
@Input()
|
||||
key: string;
|
||||
|
||||
/** You can specify any custom data which can be used by any specific feature */
|
||||
@Input()
|
||||
customData: any;
|
||||
|
||||
/** Value type for the column. Possible settings are 'text', 'image',
|
||||
* 'date', 'fileSize', 'location', and 'json'.
|
||||
*/
|
||||
@@ -52,6 +56,10 @@ export class DataColumnComponent implements OnInit {
|
||||
@Input()
|
||||
draggable: boolean = false;
|
||||
|
||||
/* Hide column */
|
||||
@Input()
|
||||
isHidden: boolean = false;
|
||||
|
||||
/** Display title of the column, typically used for column headers. You can use the
|
||||
* i18n resource key to get it translated automatically.
|
||||
*/
|
||||
|
@@ -24,10 +24,11 @@
|
||||
[placeholder]='"ADF-DATATABLE.COLUMNS_SELECTOR.SEARCH" | translate'>
|
||||
</div>
|
||||
|
||||
<div class="adf-columns-selector-list-container">
|
||||
<ng-container *ngFor="let column of columnItems">
|
||||
<div
|
||||
*ngIf="(column.title | translate | filterString:searchQuery) as translatedTitle"
|
||||
class="adf-columns-selector-list-item-container">
|
||||
class="adf-columns-selector-list-item">
|
||||
<mat-checkbox
|
||||
color="primary"
|
||||
class="adf-columns-selector-column-checkbox"
|
||||
@@ -38,6 +39,7 @@
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<mat-divider class="adf-columns-selector-divider"></mat-divider>
|
||||
|
||||
|
@@ -25,7 +25,13 @@ $adf-columns-selector-space: 12px;
|
||||
font-size: var(--theme-body-1-font-size);
|
||||
}
|
||||
|
||||
&-list-item-container {
|
||||
&-list-container {
|
||||
max-height: 350px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
&-list-item {
|
||||
margin-top: 10px;
|
||||
|
||||
&:hover {
|
||||
|
@@ -194,7 +194,7 @@
|
||||
[adf-context-menu-enabled]="contextMenu"
|
||||
adf-drop-zone dropTarget="cell" [dropColumn]="col" [dropRow]="row">
|
||||
<div *ngIf="!col.template" class="adf-datatable-cell-container">
|
||||
<ng-container [ngSwitch]="col.type">
|
||||
<ng-container [ngSwitch]="data.getColumnType(row, col)">
|
||||
<div *ngSwitchCase="'image'" class="adf-cell-value">
|
||||
<mat-icon *ngIf="isIconValue(row, col); else no_iconvalue">{{ asIconValue(row, col) }}
|
||||
</mat-icon>
|
||||
|
@@ -29,7 +29,7 @@ export interface DataColumnTypes {
|
||||
|
||||
export type DataColumnType = keyof DataColumnTypes;
|
||||
|
||||
export interface DataColumn {
|
||||
export interface DataColumn<T = unknown> {
|
||||
id?: string;
|
||||
key: string;
|
||||
type: DataColumnType;
|
||||
@@ -47,4 +47,5 @@ export interface DataColumn {
|
||||
header?: TemplateRef<any>;
|
||||
draggable?: boolean;
|
||||
isHidden?: boolean;
|
||||
customData?: T;
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ import { ObjectDataColumn } from './object-datacolumn.model';
|
||||
|
||||
@Directive()
|
||||
// eslint-disable-next-line @angular-eslint/directive-class-suffix
|
||||
export abstract class DataTableSchema {
|
||||
export abstract class DataTableSchema<T = unknown> {
|
||||
|
||||
@ContentChild(DataColumnListComponent)
|
||||
columnList: DataColumnListComponent;
|
||||
@@ -33,7 +33,7 @@ export abstract class DataTableSchema {
|
||||
@Input()
|
||||
presetColumn: string;
|
||||
|
||||
columns: any;
|
||||
columns: DataColumn<T>[];
|
||||
|
||||
protected columnsOrder: string[] | undefined;
|
||||
protected columnsOrderedByKey: string = 'id';
|
||||
@@ -91,7 +91,7 @@ export abstract class DataTableSchema {
|
||||
return customSchemaColumns;
|
||||
}
|
||||
|
||||
public getSchemaFromHtml(columnList: DataColumnListComponent): any {
|
||||
public getSchemaFromHtml(columnList: DataColumnListComponent): DataColumn[] {
|
||||
let schema = [];
|
||||
if (columnList && columnList.columns && columnList.columns.length > 0) {
|
||||
schema = columnList.columns.map((c) => c as DataColumn);
|
||||
|
@@ -29,6 +29,7 @@ export interface DataTableAdapter {
|
||||
getColumns(): Array<DataColumn>;
|
||||
setColumns(columns: Array<DataColumn>): void;
|
||||
getValue(row: DataRow, col: DataColumn, resolverFn?: (_row: DataRow, _col: DataColumn) => any): any;
|
||||
getColumnType(row: DataRow, col: DataColumn): string;
|
||||
getSorting(): DataSorting;
|
||||
setSorting(sorting: DataSorting): void;
|
||||
sort(key?: string, direction?: string): void;
|
||||
|
@@ -19,7 +19,7 @@ import { TemplateRef } from '@angular/core';
|
||||
import { DataColumn, DataColumnType } from './data-column.model';
|
||||
|
||||
// Simple implementation of the DataColumn interface.
|
||||
export class ObjectDataColumn implements DataColumn {
|
||||
export class ObjectDataColumn<T = unknown> implements DataColumn<T> {
|
||||
id?: string;
|
||||
key: string;
|
||||
type: DataColumnType;
|
||||
@@ -35,6 +35,7 @@ export class ObjectDataColumn implements DataColumn {
|
||||
header?: TemplateRef<any>;
|
||||
draggable: boolean;
|
||||
isHidden: boolean;
|
||||
customData?: T;
|
||||
|
||||
constructor(input: any) {
|
||||
this.id = input.id ?? '';
|
||||
@@ -52,5 +53,6 @@ export class ObjectDataColumn implements DataColumn {
|
||||
this.header = input.header;
|
||||
this.draggable = input.draggable ?? false;
|
||||
this.isHidden = input.isHidden ?? false;
|
||||
this.customData = input.customData;
|
||||
}
|
||||
}
|
||||
|
@@ -77,6 +77,10 @@ export class ObjectDataTableAdapter implements DataTableAdapter {
|
||||
this.rowsChanged = new Subject<Array<DataRow>>();
|
||||
}
|
||||
|
||||
getColumnType(_row: DataRow, col: DataColumn): string {
|
||||
return col.type;
|
||||
}
|
||||
|
||||
getRows(): Array<DataRow> {
|
||||
return this._rows;
|
||||
}
|
||||
|
22
lib/core/mock/data-column.mock.ts
Normal file
22
lib/core/mock/data-column.mock.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { DataColumn } from '../datatable/data/data-column.model';
|
||||
|
||||
export const getDataColumnMock = <T = unknown>(column: Partial<DataColumn<T>> = {}): DataColumn<T> => ({
|
||||
id: 'columnId',
|
||||
key: 'key',
|
||||
type: 'text',
|
||||
format: 'format',
|
||||
sortable: false,
|
||||
title: 'title',
|
||||
srTitle: 'srTitle',
|
||||
cssClass: 'cssClass',
|
||||
template: undefined,
|
||||
copyContent: false,
|
||||
editable: false,
|
||||
focus: false,
|
||||
sortingKey: 'sortingKey',
|
||||
header: undefined,
|
||||
draggable: false,
|
||||
isHidden: false,
|
||||
customData: undefined,
|
||||
...column
|
||||
});
|
@@ -41,3 +41,4 @@ export * from './identity-group.mock';
|
||||
export * from './identity-user.mock';
|
||||
export * from './identity-group.service.mock';
|
||||
export * from './identity-user.service.mock';
|
||||
export * from './data-column.mock';
|
||||
|
@@ -0,0 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow
|
||||
export enum ColumnDataType {
|
||||
processVariableColumn = 'process-variable-column'
|
||||
}
|
@@ -15,6 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ProcessVariableDefinition } from './variable-definition';
|
||||
|
||||
export class ProcessDefinitionCloud {
|
||||
id: string;
|
||||
appName: string;
|
||||
@@ -25,6 +27,7 @@ export class ProcessDefinitionCloud {
|
||||
name: string;
|
||||
category: string;
|
||||
description: string;
|
||||
variableDefinitions?: ProcessVariableDefinition[];
|
||||
|
||||
constructor(obj?: any) {
|
||||
this.id = obj && obj.id || null;
|
||||
@@ -36,5 +39,6 @@ export class ProcessDefinitionCloud {
|
||||
this.appVersion = obj && obj.appVersion || 0;
|
||||
this.category = obj && obj?.category || '';
|
||||
this.description = obj && obj?.description || '';
|
||||
this.variableDefinitions = obj?.variableDefinitions ?? [];
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,33 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export interface ProcessInstanceVariable {
|
||||
id: number;
|
||||
variableDefinitionId: string;
|
||||
value: string;
|
||||
appName: string;
|
||||
createTime: string;
|
||||
lastUpdatedTime: string;
|
||||
markedAsDeleted: boolean;
|
||||
name: string;
|
||||
processInstanceId: string;
|
||||
serviceFullName: string;
|
||||
serviceName: string;
|
||||
serviceVersion: string;
|
||||
taskVariable: boolean;
|
||||
type: string;
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export interface ProcessVariableDefinition {
|
||||
id: string;
|
||||
name: string;
|
||||
type: string;
|
||||
required: boolean;
|
||||
display: boolean;
|
||||
displayName?: string;
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
<adf-datatable #dataTable
|
||||
[rows]="rows"
|
||||
[columns]="columns"
|
||||
[data]="dataAdapter"
|
||||
[stickyHeader]="stickyHeader"
|
||||
[loading]="isLoading"
|
||||
[sorting]="formattedSorting"
|
||||
|
@@ -22,6 +22,7 @@ import {
|
||||
ColumnsSelectorComponent,
|
||||
DataColumn,
|
||||
DataRowEvent,
|
||||
getDataColumnMock,
|
||||
ObjectDataRow,
|
||||
setupTestBed
|
||||
} from '@alfresco/adf-core';
|
||||
@@ -33,6 +34,10 @@ import { shareReplay, skip } from 'rxjs/operators';
|
||||
import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ProcessListCloudSortingModel } from '../models/process-list-sorting.model';
|
||||
import { PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN } from '../../../services/cloud-token.service';
|
||||
import { LocalPreferenceCloudService } from '../../../services/local-preference-cloud.service';
|
||||
import { ProcessListCloudPreferences } from '../models/process-cloud-preferences';
|
||||
import { ColumnDataType } from '../../../models/column-data-type.model';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
@@ -71,6 +76,9 @@ describe('ProcessListCloudComponent', () => {
|
||||
let fixture: ComponentFixture<ProcessListCloudComponent>;
|
||||
let appConfig: AppConfigService;
|
||||
let processListCloudService: ProcessListCloudService;
|
||||
let preferencesService: LocalPreferenceCloudService;
|
||||
const fakeCustomSchemaName = 'fakeCustomSchema';
|
||||
const schemaWithVariable = 'schemaWithVariableId';
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
@@ -82,12 +90,13 @@ describe('ProcessListCloudComponent', () => {
|
||||
beforeEach(() => {
|
||||
appConfig = TestBed.inject(AppConfigService);
|
||||
processListCloudService = TestBed.inject(ProcessListCloudService);
|
||||
preferencesService = TestBed.inject<LocalPreferenceCloudService>(PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN);
|
||||
fixture = TestBed.createComponent(ProcessListCloudComponent);
|
||||
component = fixture.componentInstance;
|
||||
appConfig.config = Object.assign(appConfig.config, {
|
||||
'adf-cloud-process-list': {
|
||||
presets: {
|
||||
fakeCustomSchema: [
|
||||
[fakeCustomSchemaName]: [
|
||||
{
|
||||
key: 'fakeName',
|
||||
type: 'text',
|
||||
@@ -100,6 +109,16 @@ describe('ProcessListCloudComponent', () => {
|
||||
title: 'ADF_CLOUD_TASK_LIST.PROPERTIES.TASK_FAKE',
|
||||
sortable: true
|
||||
}
|
||||
],
|
||||
[schemaWithVariable]: [
|
||||
getDataColumnMock(),
|
||||
getDataColumnMock({
|
||||
id: 'variableColumnId',
|
||||
customData: {
|
||||
assignedVariableDefinitionIds: ['variableDefinitionId'],
|
||||
columnType: ColumnDataType.processVariableColumn
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -108,11 +127,12 @@ describe('ProcessListCloudComponent', () => {
|
||||
component.isColumnSchemaCreated$ = of(true).pipe(shareReplay(1));
|
||||
});
|
||||
|
||||
afterEach(() => fixture.destroy());
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
it('should use the default schemaColumn', () => {
|
||||
appConfig.config = Object.assign(appConfig.config, { 'adf-cloud-process-list': processListSchemaMock });
|
||||
component.ngAfterContentInit();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.columns).toBeDefined();
|
||||
@@ -164,6 +184,7 @@ describe('ProcessListCloudComponent', () => {
|
||||
it('should the payload contain the appVersion if it is defined', () => {
|
||||
spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList));
|
||||
component.appVersion = 1;
|
||||
component.ngAfterContentInit();
|
||||
component.reload();
|
||||
|
||||
expect(component.requestNode.appVersion).toEqual('1');
|
||||
@@ -172,6 +193,7 @@ describe('ProcessListCloudComponent', () => {
|
||||
it('should the payload contain all the app versions joined by a comma separator', () => {
|
||||
spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList));
|
||||
component.appVersion = [1, 2, 3];
|
||||
component.ngAfterContentInit();
|
||||
component.reload();
|
||||
|
||||
expect(component.requestNode.appVersion).toEqual('1,2,3');
|
||||
@@ -180,20 +202,21 @@ describe('ProcessListCloudComponent', () => {
|
||||
it('should the payload NOT contain any app version when appVersion does not have a value', () => {
|
||||
spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList));
|
||||
component.appVersion = undefined;
|
||||
component.ngAfterContentInit();
|
||||
component.reload();
|
||||
|
||||
expect(component.requestNode.appVersion).toEqual('');
|
||||
});
|
||||
|
||||
it('should use the custom schemaColumn from app.config.json', () => {
|
||||
component.presetColumn = 'fakeCustomSchema';
|
||||
component.presetColumn = fakeCustomSchemaName;
|
||||
component.ngAfterContentInit();
|
||||
fixture.detectChanges();
|
||||
expect(component.columns).toEqual(fakeCustomSchema);
|
||||
});
|
||||
|
||||
it('should fetch custom schemaColumn when the input presetColumn is defined', () => {
|
||||
component.presetColumn = 'fakeCustomSchema';
|
||||
component.presetColumn = fakeCustomSchemaName;
|
||||
fixture.detectChanges();
|
||||
expect(component.columns).toBeDefined();
|
||||
expect(component.columns.length).toEqual(2);
|
||||
@@ -223,6 +246,7 @@ describe('ProcessListCloudComponent', () => {
|
||||
done();
|
||||
});
|
||||
component.appName = appName.currentValue;
|
||||
component.ngAfterContentInit();
|
||||
component.ngOnChanges({ appName });
|
||||
fixture.detectChanges();
|
||||
});
|
||||
@@ -244,6 +268,7 @@ describe('ProcessListCloudComponent', () => {
|
||||
spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList));
|
||||
|
||||
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
|
||||
component.ngAfterContentInit();
|
||||
component.ngOnChanges({ appName });
|
||||
|
||||
fixture.detectChanges();
|
||||
@@ -285,6 +310,41 @@ describe('ProcessListCloudComponent', () => {
|
||||
expect(displayedColumns.length).toBe(2, 'only column with isHidden set to false and action column should be shown');
|
||||
});
|
||||
|
||||
it('should NOT request process variable if columns for process variables are not displayed', () => {
|
||||
spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList));
|
||||
spyOn(preferencesService, 'getPreferences').and.returnValue(of({
|
||||
list: {
|
||||
entries: []
|
||||
}
|
||||
}));
|
||||
|
||||
component.ngAfterContentInit();
|
||||
component.reload();
|
||||
|
||||
expect(component.requestNode.variableDefinitions).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should request process variable if column for process variable is displayed', () => {
|
||||
component.presetColumn = schemaWithVariable;
|
||||
|
||||
spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList));
|
||||
spyOn(preferencesService, 'getPreferences').and.returnValue(of({
|
||||
list: {
|
||||
entries: [{
|
||||
entry: {
|
||||
key: ProcessListCloudPreferences.columnsVisibility,
|
||||
value: '{"variableColumnId":true, "2":true}'
|
||||
}
|
||||
}]
|
||||
}
|
||||
}));
|
||||
|
||||
component.ngAfterContentInit();
|
||||
component.reload();
|
||||
|
||||
expect(component.requestNode.variableDefinitions).toEqual(['variableDefinitionId']);
|
||||
});
|
||||
|
||||
it('should reload tasks when reload() is called', (done) => {
|
||||
component.appName = 'fake';
|
||||
spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList));
|
||||
|
@@ -21,14 +21,17 @@ import { DataTableSchema, PaginatedComponent,
|
||||
UserPreferencesService, PaginationModel,
|
||||
UserPreferenceValues, DataRowEvent, CustomLoadingContentTemplateDirective, DataCellEvent, DataRowActionEvent, DataTableComponent, DataColumn } from '@alfresco/adf-core';
|
||||
import { ProcessListCloudService } from '../services/process-list-cloud.service';
|
||||
import { BehaviorSubject, combineLatest } from 'rxjs';
|
||||
import { BehaviorSubject, of } 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';
|
||||
import { map, take } from 'rxjs/operators';
|
||||
import { map, switchMap, take, tap } from 'rxjs/operators';
|
||||
import { PreferenceCloudServiceInterface } from '../../../services/preference-cloud.interface';
|
||||
import { PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN } from '../../../services/cloud-token.service';
|
||||
import { ProcessListCloudPreferences } from '../models/process-cloud-preferences';
|
||||
import { ColumnDataType } from '../../../models/column-data-type.model';
|
||||
import { ProcessListDatatableAdapter } from '../datatable/process-list-datatable-adapter';
|
||||
import { ProcessListDataColumnCustomData } from '../models/data-column-custom-data';
|
||||
|
||||
const PRESET_KEY = 'adf-cloud-process-list.presets';
|
||||
|
||||
@@ -38,7 +41,7 @@ const PRESET_KEY = 'adf-cloud-process-list.presets';
|
||||
styleUrls: ['./process-list-cloud.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class ProcessListCloudComponent extends DataTableSchema implements OnChanges, AfterContentInit, PaginatedComponent {
|
||||
export class ProcessListCloudComponent extends DataTableSchema<ProcessListDataColumnCustomData> implements OnChanges, AfterContentInit, PaginatedComponent {
|
||||
@ViewChild(DataTableComponent)
|
||||
dataTable: DataTableComponent;
|
||||
|
||||
@@ -201,6 +204,7 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan
|
||||
rows: any[] = [];
|
||||
formattedSorting: any[];
|
||||
requestNode: ProcessQueryCloudRequestModel;
|
||||
dataAdapter: ProcessListDatatableAdapter;
|
||||
|
||||
private defaultSorting = { key: 'startDate', direction: 'desc' };
|
||||
|
||||
@@ -231,7 +235,7 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan
|
||||
|
||||
return {
|
||||
columnsOrder: columnsOrder ? JSON.parse(columnsOrder.entry.value) : undefined,
|
||||
columnsVisibility: columnsVisibility ? JSON.parse(columnsVisibility.entry.value) : undefined
|
||||
columnsVisibility: columnsVisibility ? JSON.parse(columnsVisibility.entry.value) : this.columnsVisibility
|
||||
};
|
||||
}))
|
||||
)
|
||||
@@ -262,24 +266,29 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan
|
||||
}
|
||||
|
||||
reload() {
|
||||
this.requestNode = this.createRequestNode();
|
||||
if (this.requestNode.appName || this.requestNode.appName === '') {
|
||||
this.load(this.requestNode);
|
||||
if (this.appName || this.appName === '') {
|
||||
this.load();
|
||||
} else {
|
||||
this.rows = [];
|
||||
}
|
||||
}
|
||||
|
||||
private load(requestNode: ProcessQueryCloudRequestModel) {
|
||||
private load() {
|
||||
this.isLoading = true;
|
||||
|
||||
combineLatest([
|
||||
this.processListCloudService.getProcessByRequest(requestNode),
|
||||
this.isColumnSchemaCreated$
|
||||
]).pipe(
|
||||
take(1)
|
||||
).subscribe(([processes]) => {
|
||||
this.rows = processes.list.entries;
|
||||
this.isColumnSchemaCreated$.pipe(
|
||||
take(1),
|
||||
switchMap(() => of(this.createRequestNode())),
|
||||
tap((requestNode) => this.requestNode = requestNode),
|
||||
switchMap((requestNode) => this.processListCloudService.getProcessByRequest(requestNode))
|
||||
).subscribe((processes) => {
|
||||
this.rows = this.processListCloudService.createRowsViewModel(
|
||||
processes.list.entries,
|
||||
this.columns
|
||||
);
|
||||
|
||||
this.dataAdapter = new ProcessListDatatableAdapter(this.rows, this.columns);
|
||||
|
||||
this.success.emit(processes);
|
||||
this.isLoading = false;
|
||||
this.pagination.next(processes.list.pagination);
|
||||
@@ -359,6 +368,7 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan
|
||||
}, {});
|
||||
|
||||
this.createColumns();
|
||||
this.reload();
|
||||
|
||||
if (this.appName) {
|
||||
this.cloudPreferenceService.updatePreference(
|
||||
@@ -427,8 +437,10 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan
|
||||
suspendedFrom: this.suspendedFrom,
|
||||
suspendedTo: this.suspendedTo,
|
||||
completedDate: this.completedDate,
|
||||
sorting: this.sorting
|
||||
sorting: this.sorting,
|
||||
variableDefinitions: this.getRequestNodeVariableIds()
|
||||
};
|
||||
|
||||
return new ProcessQueryCloudRequestModel(requestNode);
|
||||
}
|
||||
|
||||
@@ -454,4 +466,16 @@ export class ProcessListCloudComponent extends DataTableSchema implements OnChan
|
||||
isValidSorting(sorting: ProcessListCloudSortingModel[]) {
|
||||
return sorting.length && sorting[0].orderBy && sorting[0].direction;
|
||||
}
|
||||
|
||||
private getRequestNodeVariableIds(): string[] | undefined {
|
||||
const displayedVariableColumns = this.columns
|
||||
.filter(column =>
|
||||
column.customData?.columnType === ColumnDataType.processVariableColumn &&
|
||||
column.isHidden !== true
|
||||
)
|
||||
.map(column => column.customData.assignedVariableDefinitionIds)
|
||||
.reduce((allIds, ids) => [...ids, ...allIds], []);
|
||||
|
||||
return displayedVariableColumns.length ? displayedVariableColumns : undefined;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,53 @@
|
||||
/*!
|
||||
* @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 { DataColumn, DataRow, getDataColumnMock } from '@alfresco/adf-core';
|
||||
import { ColumnDataType } from '../../../models/column-data-type.model';
|
||||
import { getProcessInstanceVariableMock } from '../mock/process-instance-variable.mock';
|
||||
import { ProcessListDataColumnCustomData } from '../models/data-column-custom-data';
|
||||
import { ProcessInstanceCloudListViewModel } from '../models/perocess-instance-cloud-view.model';
|
||||
import { ProcessListDatatableAdapter } from './process-list-datatable-adapter';
|
||||
|
||||
describe('ProcessListDatatableAdapter', () => {
|
||||
it('should get proepr type for column', () => {
|
||||
const viewModel: ProcessInstanceCloudListViewModel = {
|
||||
id: '1',
|
||||
variablesMap: {
|
||||
columnDisplayName1: getProcessInstanceVariableMock({ type: 'number' })
|
||||
}
|
||||
};
|
||||
|
||||
const row: DataRow = {
|
||||
getValue: () => {},
|
||||
hasValue: () => true,
|
||||
isSelected: false,
|
||||
obj: viewModel
|
||||
};
|
||||
|
||||
const column: DataColumn<ProcessListDataColumnCustomData> = getDataColumnMock({
|
||||
title: 'columnDisplayName1',
|
||||
customData: {
|
||||
assignedVariableDefinitionIds: ['1'],
|
||||
columnType: ColumnDataType.processVariableColumn
|
||||
}
|
||||
});
|
||||
|
||||
const adapter = new ProcessListDatatableAdapter([], []);
|
||||
|
||||
expect(adapter.getColumnType(row, column)).toBe('number');
|
||||
});
|
||||
});
|
@@ -0,0 +1,23 @@
|
||||
import { DataColumn, DataRow, ObjectDataTableAdapter } from '@alfresco/adf-core';
|
||||
import { ProcessListDataColumnCustomData } from '../models/data-column-custom-data';
|
||||
import { ColumnDataType } from '../../../models/column-data-type.model';
|
||||
import { ProcessInstanceCloudListViewModel } from '../models/perocess-instance-cloud-view.model';
|
||||
|
||||
export class ProcessListDatatableAdapter extends ObjectDataTableAdapter {
|
||||
constructor(
|
||||
data: ProcessInstanceCloudListViewModel[],
|
||||
schema: DataColumn<ProcessListDataColumnCustomData>[]
|
||||
) {
|
||||
super(data, schema);
|
||||
}
|
||||
|
||||
getColumnType(row: DataRow, col: DataColumn<ProcessListDataColumnCustomData>): string {
|
||||
if (col.customData?.columnType === ColumnDataType.processVariableColumn) {
|
||||
const variableDisplayName = col.title;
|
||||
const columnType = row.obj.variablesMap?.[variableDisplayName]?.type;
|
||||
return columnType ?? 'text';
|
||||
}
|
||||
|
||||
return super.getColumnType(row, col);
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
import { ProcessInstanceVariable } from '../../../models/process-instance-variable.model';
|
||||
|
||||
export const getProcessInstanceVariableMock = (variable: Partial<ProcessInstanceVariable> = {}): ProcessInstanceVariable => ({
|
||||
id: 1,
|
||||
variableDefinitionId: 'variableDefinitionId',
|
||||
value: 'value',
|
||||
appName: 'appName',
|
||||
createTime: 'createTime',
|
||||
lastUpdatedTime: 'lastUpdatedTime',
|
||||
markedAsDeleted: false,
|
||||
name: 'name',
|
||||
processInstanceId: 'processInstanceId',
|
||||
serviceFullName: 'serviceFullName',
|
||||
serviceName: 'serviceName',
|
||||
serviceVersion: 'serviceVersion',
|
||||
taskVariable: false,
|
||||
type: 'text',
|
||||
...variable
|
||||
});
|
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
import { ObjectDataColumn } from '@alfresco/adf-core';
|
||||
import { ProcessListDataColumnCustomData } from '../models/data-column-custom-data';
|
||||
|
||||
export const fakeProcessCloudList = {
|
||||
list: {
|
||||
@@ -34,7 +35,8 @@ export const fakeProcessCloudList = {
|
||||
status: 'RUNNING',
|
||||
lastModified: 1540381146276,
|
||||
lastModifiedTo: null,
|
||||
lastModifiedFrom: null
|
||||
lastModifiedFrom: null,
|
||||
variables: [{ id: 'variableId', value: 'variableValue'}]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -84,13 +86,13 @@ export const fakeProcessCloudList = {
|
||||
|
||||
export const fakeCustomSchema =
|
||||
[
|
||||
new ObjectDataColumn({
|
||||
new ObjectDataColumn<ProcessListDataColumnCustomData>({
|
||||
key: 'fakeName',
|
||||
type: 'text',
|
||||
title: 'ADF_CLOUD_TASK_LIST.PROPERTIES.FAKE',
|
||||
sortable: true
|
||||
}),
|
||||
new ObjectDataColumn({
|
||||
new ObjectDataColumn<ProcessListDataColumnCustomData>({
|
||||
key: 'fakeTaskName',
|
||||
type: 'text',
|
||||
title: 'ADF_CLOUD_TASK_LIST.PROPERTIES.TASK_FAKE',
|
||||
|
@@ -0,0 +1,4 @@
|
||||
export interface ProcessListDataColumnCustomData {
|
||||
assignedVariableDefinitionIds: string[];
|
||||
columnType: string;
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
/*!
|
||||
* @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 { ProcessInstanceVariable } from '../../../models/process-instance-variable.model';
|
||||
import { ProcessInstanceCloud } from '../../start-process/models/process-instance-cloud.model';
|
||||
|
||||
export interface ProcessInstanceCloudListViewModel extends ProcessInstanceCloud {
|
||||
variablesMap?: {
|
||||
[variableDisplayName: string]: ProcessInstanceVariable;
|
||||
};
|
||||
}
|
@@ -42,6 +42,8 @@ export class ProcessQueryCloudRequestModel {
|
||||
maxItems: number;
|
||||
skipCount: number;
|
||||
sorting?: ProcessListCloudSortingModel[];
|
||||
variableDefinitions?: string[];
|
||||
|
||||
constructor(obj?: any) {
|
||||
if (obj) {
|
||||
this.appName = obj.appName;
|
||||
@@ -68,6 +70,7 @@ export class ProcessQueryCloudRequestModel {
|
||||
this.maxItems = obj.maxItems;
|
||||
this.skipCount = obj.skipCount;
|
||||
this.sorting = obj.sorting;
|
||||
this.variableDefinitions = obj.variableDefinitions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -15,10 +15,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { fakeAsync, TestBed } from '@angular/core/testing';
|
||||
import { setupTestBed, AlfrescoApiService } from '@alfresco/adf-core';
|
||||
import { setupTestBed, AlfrescoApiService, getDataColumnMock } from '@alfresco/adf-core';
|
||||
import { ProcessListCloudService } from './process-list-cloud.service';
|
||||
import { ProcessQueryCloudRequestModel } from '../models/process-cloud-query-request.model';
|
||||
import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module';
|
||||
import { ProcessInstanceVariable } from '../../../models/process-instance-variable.model';
|
||||
import { ProcessInstanceCloudListViewModel } from '../models/perocess-instance-cloud-view.model';
|
||||
import { ProcessInstanceCloud } from '../../public-api';
|
||||
import { getProcessInstanceVariableMock } from '../mock/process-instance-variable.mock';
|
||||
import { ProcessListDataColumnCustomData } from '../models/data-column-custom-data';
|
||||
import { ColumnDataType } from '../../../models/column-data-type.model';
|
||||
|
||||
describe('ProcessListCloudService', () => {
|
||||
let service: ProcessListCloudService;
|
||||
@@ -98,4 +104,35 @@ describe('ProcessListCloudService', () => {
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should map to view model', () => {
|
||||
const processInstanceVariable: ProcessInstanceVariable = getProcessInstanceVariableMock({
|
||||
variableDefinitionId: '5c75b259-dc59-11ec-aa89-fed162b97957'
|
||||
});
|
||||
|
||||
const columnTitle = 'columnTitle';
|
||||
const column = getDataColumnMock<ProcessListDataColumnCustomData>({
|
||||
title: columnTitle,
|
||||
customData: {
|
||||
assignedVariableDefinitionIds: ['5c75b259-dc59-11ec-aa89-fed162b97957'],
|
||||
columnType: ColumnDataType.processVariableColumn
|
||||
}
|
||||
});
|
||||
|
||||
const processInstance: ProcessInstanceCloud = {
|
||||
id: 'id',
|
||||
variables: [processInstanceVariable]
|
||||
};
|
||||
|
||||
const expectedViewModel: ProcessInstanceCloudListViewModel = {
|
||||
...processInstance,
|
||||
variablesMap: {
|
||||
[columnTitle]: processInstanceVariable
|
||||
}
|
||||
};
|
||||
|
||||
const viewModel = service.createRowsViewModel([processInstance], [column]);
|
||||
|
||||
expect(viewModel).toEqual([expectedViewModel]);
|
||||
});
|
||||
});
|
||||
|
@@ -15,12 +15,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AlfrescoApiService, AppConfigService, LogService } from '@alfresco/adf-core';
|
||||
import { AlfrescoApiService, AppConfigService, DataColumn, DataColumnType, LogService } from '@alfresco/adf-core';
|
||||
import { ProcessQueryCloudRequestModel } from '../models/process-cloud-query-request.model';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { ProcessListCloudSortingModel } from '../models/process-list-sorting.model';
|
||||
import { BaseCloudService } from '../../../services/base-cloud.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { ProcessInstanceCloudListViewModel } from '../models/perocess-instance-cloud-view.model';
|
||||
import { ProcessInstanceCloud } from '../../start-process/models/process-instance-cloud.model';
|
||||
import { ProcessListDataColumnCustomData } from '../models/data-column-custom-data';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ProcessListCloudService extends BaseCloudService {
|
||||
@@ -62,6 +65,51 @@ export class ProcessListCloudService extends BaseCloudService {
|
||||
}
|
||||
}
|
||||
|
||||
createRowsViewModel(
|
||||
processes: ProcessInstanceCloud[] = [],
|
||||
columnsSchema: DataColumn<ProcessListDataColumnCustomData>[]
|
||||
): ProcessInstanceCloudListViewModel[] {
|
||||
const columnsByVariableId = columnsSchema
|
||||
.filter(column => !!column.customData)
|
||||
.reduce<{ [variableId: string]: string }>((columnsByVariable, column) => {
|
||||
const columnTitle = column.title;
|
||||
const variableIds = column.customData.assignedVariableDefinitionIds;
|
||||
|
||||
variableIds.forEach((variableId) => {
|
||||
columnsByVariable[variableId] = columnTitle;
|
||||
});
|
||||
return columnsByVariable;
|
||||
|
||||
}, {});
|
||||
|
||||
const rowsViewModel = processes.map((process) => {
|
||||
if (!process.variables?.length) {
|
||||
return process;
|
||||
}
|
||||
|
||||
const variablesMap = (process.variables ?? []).reduce((variableAccumulator, variable) => {
|
||||
const processVariableDefinitionId = variable.variableDefinitionId;
|
||||
|
||||
const column = columnsByVariableId[processVariableDefinitionId];
|
||||
if (column) {
|
||||
variableAccumulator[column] = {
|
||||
...variable,
|
||||
type: this.mapProcessVariableTypes(variable.type)
|
||||
};
|
||||
}
|
||||
|
||||
return variableAccumulator;
|
||||
}, {});
|
||||
|
||||
return {
|
||||
...process,
|
||||
variablesMap
|
||||
};
|
||||
});
|
||||
|
||||
return rowsViewModel;
|
||||
}
|
||||
|
||||
protected isPropertyValueValid(requestNode: any, property: string): boolean {
|
||||
return requestNode[property] !== '' && requestNode[property] !== null && requestNode[property] !== undefined;
|
||||
}
|
||||
@@ -73,7 +121,7 @@ export class ProcessListCloudService extends BaseCloudService {
|
||||
if (requestNode.hasOwnProperty(property) &&
|
||||
!this.isExcludedField(property) &&
|
||||
this.isPropertyValueValid(requestNode, property)) {
|
||||
queryParam[property] = requestNode[property];
|
||||
queryParam[property] = this.getQueryParamValueFromRequestNode(requestNode, property as keyof ProcessQueryCloudRequestModel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +132,17 @@ export class ProcessListCloudService extends BaseCloudService {
|
||||
return queryParam;
|
||||
}
|
||||
|
||||
private getQueryParamValueFromRequestNode(
|
||||
requestNode: ProcessQueryCloudRequestModel,
|
||||
property: keyof ProcessQueryCloudRequestModel
|
||||
) {
|
||||
if (property === 'variableDefinitions' && requestNode[property]?.length > 0) {
|
||||
return `${requestNode[property].map(variableId => variableId).join(',')}`;
|
||||
}
|
||||
|
||||
return requestNode[property];
|
||||
}
|
||||
|
||||
protected buildFilterForAllStatus(): string[] {
|
||||
return ['RUNNING', 'SUSPENDED', 'CANCELLED', 'COMPLETED'];
|
||||
}
|
||||
@@ -105,4 +164,18 @@ export class ProcessListCloudService extends BaseCloudService {
|
||||
}
|
||||
return encodeURI(finalSorting);
|
||||
}
|
||||
|
||||
private mapProcessVariableTypes(variableType: string): DataColumnType {
|
||||
switch (variableType) {
|
||||
case 'boolean':
|
||||
case 'integer':
|
||||
case 'string':
|
||||
return 'text';
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
return 'date';
|
||||
default:
|
||||
return 'text';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ProcessInstanceVariable } from '../../../models/process-instance-variable.model';
|
||||
export interface ProcessInstanceCloud {
|
||||
appName?: string;
|
||||
id?: string;
|
||||
@@ -28,4 +29,5 @@ export interface ProcessInstanceCloud {
|
||||
processDefinitionId?: string;
|
||||
processDefinitionKey?: string;
|
||||
processDefinitionName?: string;
|
||||
variables?: ProcessInstanceVariable[];
|
||||
}
|
||||
|
@@ -42,11 +42,11 @@ export class StartProcessCloudService extends BaseCloudService {
|
||||
* @param appName Name of the target app
|
||||
* @returns Array of process definitions
|
||||
*/
|
||||
getProcessDefinitions(appName: string): Observable<ProcessDefinitionCloud[]> {
|
||||
getProcessDefinitions(appName: string, queryParams?: { include: 'variables' }): Observable<ProcessDefinitionCloud[]> {
|
||||
if (appName || appName === '') {
|
||||
const url = `${this.getBasePath(appName)}/rb/v1/process-definitions`;
|
||||
|
||||
return this.get(url).pipe(
|
||||
return this.get(url, queryParams).pipe(
|
||||
map((res: any) => res.list.entries.map((processDefs) => new ProcessDefinitionCloud(processDefs.entry)))
|
||||
);
|
||||
} else {
|
||||
|
@@ -32,3 +32,5 @@ export * from './lib/models/application-version.model';
|
||||
export * from './lib/models/engine-event-cloud.model';
|
||||
export * from './lib/models/filter-cloud-model';
|
||||
export * from './lib/models/task-list-sorting.model';
|
||||
export * from './lib/models/column-data-type.model';
|
||||
export * from './lib/models/process-instance-variable.model';
|
||||
|
Reference in New Issue
Block a user