From 1f96c3452caed8359a2c568df2109e586dcd637c Mon Sep 17 00:00:00 2001 From: Tomasz Gnyp <49343696+tomgny@users.noreply.github.com> Date: Wed, 9 Aug 2023 01:31:39 +0200 Subject: [PATCH] [AAE-15815] Create Data Table widget (#8801) * [AAE-15815] Create Data Table widget * [AAE-15815] Add check for corectness of column schema * fix mock name typo * improve method name * fix testing module config --- .../widgets/core/form-field-types.ts | 1 + .../widgets/core/form-field.model.ts | 3 + lib/core/src/lib/i18n/en.json | 1 + .../cloud-form-rendering.service.ts | 4 +- .../data-table-adapter.widget.spec.ts | 76 +++++++ .../data-table/data-table-adapter.widget.ts | 62 ++++++ .../widgets/data-table/data-table.widget.html | 22 +++ .../widgets/data-table/data-table.widget.scss | 3 + .../data-table/data-table.widget.spec.ts | 186 ++++++++++++++++++ .../widgets/data-table/data-table.widget.ts | 128 ++++++++++++ .../lib/form/mocks/data-table-widget.mock.ts | 107 ++++++++++ 11 files changed, 592 insertions(+), 1 deletion(-) create mode 100644 lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table-adapter.widget.spec.ts create mode 100644 lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table-adapter.widget.ts create mode 100644 lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table.widget.html create mode 100644 lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table.widget.scss create mode 100644 lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table.widget.spec.ts create mode 100644 lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table.widget.ts create mode 100644 lib/process-services-cloud/src/lib/form/mocks/data-table-widget.mock.ts diff --git a/lib/core/src/lib/form/components/widgets/core/form-field-types.ts b/lib/core/src/lib/form/components/widgets/core/form-field-types.ts index 77161c1804..2af8a706c6 100644 --- a/lib/core/src/lib/form/components/widgets/core/form-field-types.ts +++ b/lib/core/src/lib/form/components/widgets/core/form-field-types.ts @@ -46,6 +46,7 @@ export class FormFieldTypes { static VIEWER: string = 'base-viewer'; static DISPLAY_RICH_TEXT: string = 'display-rich-text'; static JSON: string = 'json'; + static DATA_TABLE: string = 'data-table'; static READONLY_TYPES: string[] = [ FormFieldTypes.HYPERLINK, diff --git a/lib/core/src/lib/form/components/widgets/core/form-field.model.ts b/lib/core/src/lib/form/components/widgets/core/form-field.model.ts index 8488bd2757..25c496f1fe 100644 --- a/lib/core/src/lib/form/components/widgets/core/form-field.model.ts +++ b/lib/core/src/lib/form/components/widgets/core/form-field.model.ts @@ -28,6 +28,7 @@ import { FormFieldRule } from './form-field-rule'; import { ProcessFormModel } from './process-form-model.interface'; import { isNumberValue } from './form-field-utils'; import { VariableConfig } from './form-field-variable-options'; +import { DataColumn } from '../../../../datatable/data/data-column.model'; // Maps to FormFieldRepresentation export class FormFieldModel extends FormWidgetModel { @@ -83,6 +84,7 @@ export class FormFieldModel extends FormWidgetModel { groupsRestriction: string[]; leftLabels: boolean = false; variableConfig: VariableConfig; + schemaDefinition: DataColumn[]; // container model members numberOfColumns: number = 1; @@ -197,6 +199,7 @@ export class FormFieldModel extends FormWidgetModel { this.selectLoggedUser = json.selectLoggedUser; this.groupsRestriction = json.groupsRestriction?.groups; this.variableConfig = json.variableConfig; + this.schemaDefinition = json.schemaDefinition; if (json.placeholder && json.placeholder !== '' && json.placeholder !== 'null') { this.placeholder = json.placeholder; diff --git a/lib/core/src/lib/i18n/en.json b/lib/core/src/lib/i18n/en.json index dfb040f301..2da9563fd5 100644 --- a/lib/core/src/lib/i18n/en.json +++ b/lib/core/src/lib/i18n/en.json @@ -47,6 +47,7 @@ "REQUIRED": "This is a required field", "REST_API_FAILED": "The server `{{ hostname }}` is not reachable", "VARIABLE_DROPDOWN_OPTIONS_FAILED": "There was a problem loading dropdown elements. Please contact administrator.", + "DATA_TABLE_LOAD_FAILED": "There was a problem loading table elements. Please contact administrator.", "FILE_NAME": "File Name", "NO_FILE_ATTACHED": "No file attached", "VALIDATOR": { diff --git a/lib/process-services-cloud/src/lib/form/components/cloud-form-rendering.service.ts b/lib/process-services-cloud/src/lib/form/components/cloud-form-rendering.service.ts index d7f284f4e8..1d6a692953 100644 --- a/lib/process-services-cloud/src/lib/form/components/cloud-form-rendering.service.ts +++ b/lib/process-services-cloud/src/lib/form/components/cloud-form-rendering.service.ts @@ -26,6 +26,7 @@ import { PropertiesViewerWidgetComponent } from './widgets/properties-viewer/pro import { RadioButtonsCloudWidgetComponent } from './widgets/radio-buttons/radio-buttons-cloud.widget'; import { FileViewerWidgetComponent } from './widgets/file-viewer/file-viewer.widget'; import { DisplayRichTextWidgetComponent } from './widgets/display-rich-text/display-rich-text.widget'; +import { DataTableWidgetComponent } from './widgets/data-table/data-table.widget'; @Injectable({ providedIn: 'root' @@ -43,7 +44,8 @@ export class CloudFormRenderingService extends FormRenderingService { [FormFieldTypes.PROPERTIES_VIEWER]: () => PropertiesViewerWidgetComponent, [FormFieldTypes.RADIO_BUTTONS]: () => RadioButtonsCloudWidgetComponent, [FormFieldTypes.ALFRESCO_FILE_VIEWER]: () => FileViewerWidgetComponent, - [FormFieldTypes.DISPLAY_RICH_TEXT]: () => DisplayRichTextWidgetComponent + [FormFieldTypes.DISPLAY_RICH_TEXT]: () => DisplayRichTextWidgetComponent, + [FormFieldTypes.DATA_TABLE]: () => DataTableWidgetComponent }, true); } } diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table-adapter.widget.spec.ts b/lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table-adapter.widget.spec.ts new file mode 100644 index 0000000000..2572961f6a --- /dev/null +++ b/lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table-adapter.widget.spec.ts @@ -0,0 +1,76 @@ +/*! + * @license + * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * 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 { WidgetDataTableAdapter } from './data-table-adapter.widget'; +import { + mockCountriesData, + mockCountriesIncorrectData, + mockInvalidSchemaDefinition, + mockSchemaDefinition, + mockSchemaDefinitionWithDifferentTypes +} from '../../../mocks/data-table-widget.mock'; +import { ObjectDataRow } from '@alfresco/adf-core'; + +describe('WidgetDataTableAdapter', () => { + let widgetDataTableAdapter: WidgetDataTableAdapter; + + beforeEach(() => { + widgetDataTableAdapter = new WidgetDataTableAdapter(mockCountriesData, mockSchemaDefinition); + }); + + it('should set columns type to "text" during initialization', () => { + widgetDataTableAdapter = new WidgetDataTableAdapter(mockCountriesData, mockSchemaDefinitionWithDifferentTypes); + + widgetDataTableAdapter.getColumns().forEach(column => + expect(column.type).toBe('text') + ); + }); + + it('should return rows if all columns are linked to data', () => { + const rows = widgetDataTableAdapter.getRows(); + + expect(rows).toEqual([ + new ObjectDataRow({ id: 'IT', name: 'Italy' }), + new ObjectDataRow({ id: 'PL', name: 'Poland' }), + new ObjectDataRow({ id: 'UK', name: 'United Kingdom' }) + ]); + }); + + it('should return an empty array if not all columns are linked to data', () => { + widgetDataTableAdapter = new WidgetDataTableAdapter(mockCountriesIncorrectData, mockSchemaDefinition); + const rows = widgetDataTableAdapter.getRows(); + const isDataSourceValid = widgetDataTableAdapter.isDataSourceValid(); + + expect(rows).toEqual([]); + expect(isDataSourceValid).toBeFalse(); + }); + + it('should return an empty array if columns have invalid structure', () => { + widgetDataTableAdapter = new WidgetDataTableAdapter(mockCountriesData, mockInvalidSchemaDefinition); + const rows = widgetDataTableAdapter.getRows(); + const isDataSourceValid = widgetDataTableAdapter.isDataSourceValid(); + + expect(rows).toEqual([]); + expect(isDataSourceValid).toBeFalse(); + }); + + it('should return true for isDataSourceValid() if rows have data and valid columns schema', () => { + const isValid = widgetDataTableAdapter.isDataSourceValid(); + + expect(isValid).toBeTrue(); + }); +}); diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table-adapter.widget.ts b/lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table-adapter.widget.ts new file mode 100644 index 0000000000..f87a5af764 --- /dev/null +++ b/lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table-adapter.widget.ts @@ -0,0 +1,62 @@ +/*! + * @license + * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * 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 { + ObjectDataTableAdapter, + DataColumn, + DataRow +} from '@alfresco/adf-core'; + +export class WidgetDataTableAdapter extends ObjectDataTableAdapter { + + private rows: DataRow[]; + private columns: DataColumn[]; + + constructor(data?: any[], schema?: DataColumn[]) { + super(data, schema); + this.rows = super.getRows(); + this.columns = super.getColumns(); + + this.setColumnsTypeToText(); + } + + getRows(): DataRow[] { + if (this.isDataSourceValid()) { + return this.rows; + } + + return []; + } + + isDataSourceValid(): boolean { + return this.hasAllColumnsLinkedToData() && this.hasAllMandatoryColumnPropertiesHaveValues(); + } + + private hasAllMandatoryColumnPropertiesHaveValues(): boolean { + return this.columns.every(column => !!column.key); + } + + private hasAllColumnsLinkedToData(): boolean { + const availableColumnKeys: string[] = this.columns.map(column => column.key); + + return availableColumnKeys.every(columnKey => this.rows.some(row => Object.keys(row.obj).includes(columnKey))); + } + + private setColumnsTypeToText(): void { + super.setColumns(this.columns.map(column => ({ ...column, type: 'text' }))); + } +} diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table.widget.html b/lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table.widget.html new file mode 100644 index 0000000000..5671f24481 --- /dev/null +++ b/lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table.widget.html @@ -0,0 +1,22 @@ +
diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table.widget.scss b/lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table.widget.scss new file mode 100644 index 0000000000..e5f7fbd650 --- /dev/null +++ b/lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table.widget.scss @@ -0,0 +1,3 @@ +.adf-data-table-widget-failed-message { + margin: 10px; +} diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table.widget.spec.ts b/lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table.widget.spec.ts new file mode 100644 index 0000000000..166c0e24f7 --- /dev/null +++ b/lib/process-services-cloud/src/lib/form/components/widgets/data-table/data-table.widget.spec.ts @@ -0,0 +1,186 @@ +/*! + * @license + * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * 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 { ComponentFixture, TestBed } from '@angular/core/testing'; +import { DataColumn, FormFieldModel, FormFieldTypes, FormModel, LogService } from '@alfresco/adf-core'; +import { By } from '@angular/platform-browser'; +import { DataTableWidgetComponent } from './data-table.widget'; +import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module'; +import { TaskVariableCloud } from '../../../models/task-variable-cloud.model'; +import { FormCloudService } from '../../../services/form-cloud.service'; +import { WidgetDataTableAdapter } from './data-table-adapter.widget'; +import { + mockCountriesData, + mockInvalidSchemaDefinition, + mockJsonFormVariable, + mockJsonFormVariableWithIncorrectData, + mockJsonProcessVariables, + mockSchemaDefinition +} from '../../../mocks/data-table-widget.mock'; + +describe('DataTableWidgetComponent', () => { + let widget: DataTableWidgetComponent; + let fixture: ComponentFixture