mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-31 17:38:48 +00:00
[AAE-16303] Handle nested property data source in data table (#8895)
This commit is contained in:
@@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { DataColumn, FormFieldModel, FormFieldTypes, FormModel, LogService } from '@alfresco/adf-core';
|
import { DataColumn, FormFieldModel, FormFieldTypes, FormModel, LogService, VariableConfig } from '@alfresco/adf-core';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { DataTableWidgetComponent } from './data-table.widget';
|
import { DataTableWidgetComponent } from './data-table.widget';
|
||||||
import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module';
|
import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module';
|
||||||
@@ -32,7 +32,9 @@ import {
|
|||||||
mockJsonProcessVariables,
|
mockJsonProcessVariables,
|
||||||
mockSchemaDefinition,
|
mockSchemaDefinition,
|
||||||
mockJsonResponseEuropeCountriesData,
|
mockJsonResponseEuropeCountriesData,
|
||||||
mockJsonResponseFormVariable
|
mockJsonResponseFormVariable,
|
||||||
|
mockJsonNestedResponseFormVariable,
|
||||||
|
mockJsonNestedResponseEuropeCountriesData
|
||||||
} from '../../../mocks/data-table-widget.mock';
|
} from '../../../mocks/data-table-widget.mock';
|
||||||
|
|
||||||
describe('DataTableWidgetComponent', () => {
|
describe('DataTableWidgetComponent', () => {
|
||||||
@@ -45,7 +47,7 @@ describe('DataTableWidgetComponent', () => {
|
|||||||
const errorIcon: string = 'error_outline';
|
const errorIcon: string = 'error_outline';
|
||||||
|
|
||||||
const getDataVariable = (
|
const getDataVariable = (
|
||||||
variableName: string,
|
variableConfig: VariableConfig,
|
||||||
schemaDefinition: DataColumn[],
|
schemaDefinition: DataColumn[],
|
||||||
processVariables?: TaskVariableCloud[],
|
processVariables?: TaskVariableCloud[],
|
||||||
variables?: TaskVariableCloud[]
|
variables?: TaskVariableCloud[]
|
||||||
@@ -56,11 +58,19 @@ describe('DataTableWidgetComponent', () => {
|
|||||||
type: FormFieldTypes.DATA_TABLE,
|
type: FormFieldTypes.DATA_TABLE,
|
||||||
optionType: 'variable',
|
optionType: 'variable',
|
||||||
schemaDefinition,
|
schemaDefinition,
|
||||||
variableConfig: {
|
variableConfig
|
||||||
variableName
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const mockVariableConfig: VariableConfig = {
|
||||||
|
variableName: 'json-form-variable'
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkDataTableErrorMessage = () => {
|
||||||
|
const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-data-table-widget-failed-message'));
|
||||||
|
|
||||||
|
expect(failedErrorMsgElement.nativeElement.textContent.trim()).toBe(errorIcon.concat('FORM.FIELD.DATA_TABLE_LOAD_FAILED'));
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -101,7 +111,7 @@ describe('DataTableWidgetComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should properly initialize column schema', () => {
|
it('should properly initialize column schema', () => {
|
||||||
widget.field = getDataVariable('json-form-variable', mockSchemaDefinition, [], mockJsonFormVariable);
|
widget.field = getDataVariable(mockVariableConfig, mockSchemaDefinition, [], mockJsonFormVariable);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
widget.dataSource.getColumns().forEach((column, index) =>
|
widget.dataSource.getColumns().forEach((column, index) =>
|
||||||
@@ -110,7 +120,7 @@ describe('DataTableWidgetComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should properly initialize data source with priority on the field value if process and form variables are provided', () => {
|
it('should properly initialize data source with priority on the field value if process and form variables are provided', () => {
|
||||||
widget.field = getDataVariable('json-form-variable', mockSchemaDefinition, mockJsonProcessVariables, mockJsonFormVariable);
|
widget.field = getDataVariable(mockVariableConfig, mockSchemaDefinition, mockJsonProcessVariables, mockJsonFormVariable);
|
||||||
widget.field.value = mockAmericaCountriesData;
|
widget.field.value = mockAmericaCountriesData;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
@@ -121,7 +131,7 @@ describe('DataTableWidgetComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should properly initialize data source based on field value', () => {
|
it('should properly initialize data source based on field value', () => {
|
||||||
widget.field = getDataVariable('json-form-variable', mockSchemaDefinition, [], []);
|
widget.field = getDataVariable(mockVariableConfig, mockSchemaDefinition, [], []);
|
||||||
widget.field.value = mockAmericaCountriesData;
|
widget.field.value = mockAmericaCountriesData;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
@@ -131,8 +141,8 @@ describe('DataTableWidgetComponent', () => {
|
|||||||
expect(widget.dataSource.getRows()).toEqual(expectedData.getRows());
|
expect(widget.dataSource.getRows()).toEqual(expectedData.getRows());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should properly initialize json response data source based on field value', () => {
|
it('should properly initialize default json response data source based on field value if path is NOT provided', () => {
|
||||||
widget.field = getDataVariable('json-form-variable', mockSchemaDefinition, [], []);
|
widget.field = getDataVariable(mockVariableConfig, mockSchemaDefinition, [], []);
|
||||||
widget.field.value = mockJsonResponseEuropeCountriesData;
|
widget.field.value = mockJsonResponseEuropeCountriesData;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
@@ -142,8 +152,29 @@ describe('DataTableWidgetComponent', () => {
|
|||||||
expect(widget.dataSource.getRows()).toEqual(expectedData.getRows());
|
expect(widget.dataSource.getRows()).toEqual(expectedData.getRows());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should properly initialize json response data source based on variable', () => {
|
it('should properly initialize default json response data source based on variable if path is NOT provided', () => {
|
||||||
widget.field = getDataVariable('json-form-variable', mockSchemaDefinition, [], mockJsonResponseFormVariable);
|
widget.field = getDataVariable(mockVariableConfig, mockSchemaDefinition, [], mockJsonResponseFormVariable);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const expectedData = new WidgetDataTableAdapter(mockEuropeCountriesData, mockSchemaDefinition);
|
||||||
|
expectedData.getRows().forEach(row => row.cssClass = '');
|
||||||
|
|
||||||
|
expect(widget.dataSource.getRows()).toEqual(expectedData.getRows());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should properly initialize json response data source based on field value if path is provided', () => {
|
||||||
|
widget.field = getDataVariable({ ...mockVariableConfig, optionsPath: 'response.my-data' }, mockSchemaDefinition, [], []);
|
||||||
|
widget.field.value = mockJsonNestedResponseEuropeCountriesData;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const expectedData = new WidgetDataTableAdapter(mockEuropeCountriesData, mockSchemaDefinition);
|
||||||
|
expectedData.getRows().forEach(row => row.cssClass = '');
|
||||||
|
|
||||||
|
expect(widget.dataSource.getRows()).toEqual(expectedData.getRows());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should properly initialize json response data source based on variable if path is provided', () => {
|
||||||
|
widget.field = getDataVariable({ ...mockVariableConfig, optionsPath: 'response.my-data' }, mockSchemaDefinition, [], mockJsonNestedResponseFormVariable);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const expectedData = new WidgetDataTableAdapter(mockEuropeCountriesData, mockSchemaDefinition);
|
const expectedData = new WidgetDataTableAdapter(mockEuropeCountriesData, mockSchemaDefinition);
|
||||||
@@ -153,7 +184,7 @@ describe('DataTableWidgetComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should properly initialize data source based on form variable', () => {
|
it('should properly initialize data source based on form variable', () => {
|
||||||
widget.field = getDataVariable('json-form-variable', mockSchemaDefinition, [], mockJsonFormVariable);
|
widget.field = getDataVariable(mockVariableConfig, mockSchemaDefinition, [], mockJsonFormVariable);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const expectedData = new WidgetDataTableAdapter(mockEuropeCountriesData, mockSchemaDefinition);
|
const expectedData = new WidgetDataTableAdapter(mockEuropeCountriesData, mockSchemaDefinition);
|
||||||
@@ -163,7 +194,7 @@ describe('DataTableWidgetComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should properly initialize data source based on process variable', () => {
|
it('should properly initialize data source based on process variable', () => {
|
||||||
widget.field = getDataVariable('json-variable', mockSchemaDefinition, mockJsonProcessVariables);
|
widget.field = getDataVariable({ variableName: 'json-variable' }, mockSchemaDefinition, mockJsonProcessVariables);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const expectedData = new WidgetDataTableAdapter(mockEuropeCountriesData, mockSchemaDefinition);
|
const expectedData = new WidgetDataTableAdapter(mockEuropeCountriesData, mockSchemaDefinition);
|
||||||
@@ -173,7 +204,7 @@ describe('DataTableWidgetComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT display error if form is in preview state', () => {
|
it('should NOT display error if form is in preview state', () => {
|
||||||
widget.field = getDataVariable('json-form-variable', mockSchemaDefinition, [], mockJsonFormVariableWithIncorrectData);
|
widget.field = getDataVariable(mockVariableConfig, mockSchemaDefinition, [], mockJsonFormVariableWithIncorrectData);
|
||||||
spyOn(formCloudService, 'getPreviewState').and.returnValue(true);
|
spyOn(formCloudService, 'getPreviewState').and.returnValue(true);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
@@ -185,7 +216,7 @@ describe('DataTableWidgetComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT display data table with data source if form is in preview state', () => {
|
it('should NOT display data table with data source if form is in preview state', () => {
|
||||||
widget.field = getDataVariable('json-form-variable', mockSchemaDefinition, [], mockJsonFormVariable);
|
widget.field = getDataVariable(mockVariableConfig, mockSchemaDefinition, [], mockJsonFormVariable);
|
||||||
spyOn(formCloudService, 'getPreviewState').and.returnValue(true);
|
spyOn(formCloudService, 'getPreviewState').and.returnValue(true);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
@@ -196,36 +227,48 @@ describe('DataTableWidgetComponent', () => {
|
|||||||
expect(dataTable).toBeNull();
|
expect(dataTable).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to display and log error if data source is not linked to every column', () => {
|
it('should display and log error if data source is not linked to every column', () => {
|
||||||
widget.field = getDataVariable('json-form-variable', mockSchemaDefinition, [], mockJsonFormVariableWithIncorrectData);
|
widget.field = getDataVariable(mockVariableConfig, mockSchemaDefinition, [], mockJsonFormVariableWithIncorrectData);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-data-table-widget-failed-message'));
|
checkDataTableErrorMessage();
|
||||||
|
|
||||||
expect(failedErrorMsgElement.nativeElement.textContent.trim()).toBe(errorIcon.concat('FORM.FIELD.DATA_TABLE_LOAD_FAILED'));
|
|
||||||
expect(logServiceSpy).toHaveBeenCalledWith('Data source has corrupted model or structure');
|
expect(logServiceSpy).toHaveBeenCalledWith('Data source has corrupted model or structure');
|
||||||
expect(widget.dataSource.getRows()).toEqual([]);
|
expect(widget.dataSource.getRows()).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to display and log error if data source has invalid column structure', () => {
|
it('should display and log error if data source has invalid column structure', () => {
|
||||||
widget.field = getDataVariable('json-form-variable', mockInvalidSchemaDefinition, [], mockJsonFormVariableWithIncorrectData);
|
widget.field = getDataVariable(mockVariableConfig, mockInvalidSchemaDefinition, [], mockJsonFormVariableWithIncorrectData);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-data-table-widget-failed-message'));
|
checkDataTableErrorMessage();
|
||||||
|
|
||||||
expect(failedErrorMsgElement.nativeElement.textContent.trim()).toBe(errorIcon.concat('FORM.FIELD.DATA_TABLE_LOAD_FAILED'));
|
|
||||||
expect(logServiceSpy).toHaveBeenCalledWith('Data source has corrupted model or structure');
|
expect(logServiceSpy).toHaveBeenCalledWith('Data source has corrupted model or structure');
|
||||||
expect(widget.dataSource.getRows()).toEqual([]);
|
expect(widget.dataSource.getRows()).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to display and log error if data source is not found', () => {
|
it('should display and log error if data source is not found', () => {
|
||||||
widget.field = getDataVariable('not-found-data-source', mockSchemaDefinition, [], mockJsonFormVariableWithIncorrectData);
|
widget.field = getDataVariable({ variableName: 'not-found-data-source' }, mockSchemaDefinition, [], mockJsonFormVariableWithIncorrectData);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-data-table-widget-failed-message'));
|
checkDataTableErrorMessage();
|
||||||
|
expect(logServiceSpy).toHaveBeenCalledWith('Data source not found or it is not an array');
|
||||||
|
expect(widget.dataSource).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
expect(failedErrorMsgElement.nativeElement.textContent.trim()).toBe(errorIcon.concat('FORM.FIELD.DATA_TABLE_LOAD_FAILED'));
|
it('should display and log error if path is incorrect', () => {
|
||||||
expect(logServiceSpy).toHaveBeenCalledWith('Data source not found');
|
widget.field = getDataVariable({ ...mockVariableConfig, optionsPath: 'wrong.path' }, mockSchemaDefinition, mockJsonNestedResponseFormVariable, []);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
checkDataTableErrorMessage();
|
||||||
|
expect(logServiceSpy).toHaveBeenCalledWith('Data source not found or it is not an array');
|
||||||
|
expect(widget.dataSource).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display and log error if provided data by path is not an array', () => {
|
||||||
|
widget.field = getDataVariable({ ...mockVariableConfig, optionsPath: 'response.no-array' }, mockSchemaDefinition, mockJsonNestedResponseFormVariable, []);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
checkDataTableErrorMessage();
|
||||||
|
expect(logServiceSpy).toHaveBeenCalledWith('Data source not found or it is not an array');
|
||||||
expect(widget.dataSource).toBeUndefined();
|
expect(widget.dataSource).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -90,7 +90,7 @@ export class DataTableWidgetComponent extends WidgetComponent implements OnInit
|
|||||||
}
|
}
|
||||||
|
|
||||||
private initDataTable(): void {
|
private initDataTable(): void {
|
||||||
if (this.rowsData) {
|
if (this.rowsData?.length) {
|
||||||
this.dataSource = new WidgetDataTableAdapter(this.rowsData, this.columnsSchema);
|
this.dataSource = new WidgetDataTableAdapter(this.rowsData, this.columnsSchema);
|
||||||
|
|
||||||
if (this.dataSource.isDataSourceValid()) {
|
if (this.dataSource.isDataSourceValid()) {
|
||||||
@@ -99,16 +99,18 @@ export class DataTableWidgetComponent extends WidgetComponent implements OnInit
|
|||||||
this.handleError('Data source has corrupted model or structure');
|
this.handleError('Data source has corrupted model or structure');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.handleError('Data source not found');
|
this.handleError('Data source not found or it is not an array');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getRowsData(): void {
|
private getRowsData(): void {
|
||||||
|
const optionsPath = this.field?.variableConfig?.optionsPath ?? this.defaultResponseProperty;
|
||||||
const fieldValue = this.field?.value;
|
const fieldValue = this.field?.value;
|
||||||
const rowsData = fieldValue ? fieldValue : this.getDataFromVariable();
|
const rowsData = fieldValue || this.getDataFromVariable();
|
||||||
|
|
||||||
if (rowsData) {
|
if (rowsData) {
|
||||||
this.rowsData = rowsData[this.defaultResponseProperty] || rowsData as DataRow[];
|
const dataFromPath = this.getOptionsFromPath(rowsData, optionsPath);
|
||||||
|
this.rowsData = dataFromPath?.length ? dataFromPath : rowsData as DataRow[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,6 +124,23 @@ export class DataTableWidgetComponent extends WidgetComponent implements OnInit
|
|||||||
return processVariableDropdownOptions ?? formVariableDropdownOptions;
|
return processVariableDropdownOptions ?? formVariableDropdownOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getOptionsFromPath(data: any, path: string): DataRow[] {
|
||||||
|
const properties = path.split('.');
|
||||||
|
const currentProperty = properties.shift();
|
||||||
|
|
||||||
|
if (!data.hasOwnProperty(currentProperty)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const nestedData = data[currentProperty];
|
||||||
|
|
||||||
|
if (Array.isArray(nestedData)) {
|
||||||
|
return nestedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getOptionsFromPath(nestedData, properties.join('.'));
|
||||||
|
}
|
||||||
|
|
||||||
private getVariableValueByName(variables: TaskVariableCloud[], variableName: string): any {
|
private getVariableValueByName(variables: TaskVariableCloud[], variableName: string): any {
|
||||||
return variables?.find((variable: TaskVariableCloud) => variable?.name === `variables.${variableName}` || variable?.name === variableName)?.value;
|
return variables?.find((variable: TaskVariableCloud) => variable?.name === `variables.${variableName}` || variable?.name === variableName)?.value;
|
||||||
}
|
}
|
||||||
|
@@ -85,20 +85,21 @@ export const mockEuropeCountriesData = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const mockJsonResponseEuropeCountriesData = {
|
export const mockJsonResponseEuropeCountriesData = {
|
||||||
data: [
|
data: mockEuropeCountriesData
|
||||||
{
|
};
|
||||||
id: 'PL',
|
|
||||||
name: 'Poland'
|
export const mockJsonNestedResponseEuropeCountriesData = {
|
||||||
},
|
response: {
|
||||||
{
|
empty: [],
|
||||||
id: 'IT',
|
'my-data': mockEuropeCountriesData,
|
||||||
name: 'Italy'
|
data: [
|
||||||
},
|
{
|
||||||
{
|
id: 'HR',
|
||||||
id: 'UK',
|
name: 'Croatia'
|
||||||
name: 'United Kingdom'
|
}
|
||||||
}
|
],
|
||||||
]
|
'no-array': {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mockAmericaCountriesData = [
|
export const mockAmericaCountriesData = [
|
||||||
@@ -137,6 +138,10 @@ export const mockJsonResponseFormVariable = [
|
|||||||
new TaskVariableCloud({ name: 'json-form-variable', value: mockJsonResponseEuropeCountriesData, type: 'json', id: 'fake-id-1' })
|
new TaskVariableCloud({ name: 'json-form-variable', value: mockJsonResponseEuropeCountriesData, type: 'json', id: 'fake-id-1' })
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const mockJsonNestedResponseFormVariable = [
|
||||||
|
new TaskVariableCloud({ name: 'json-form-variable', value: mockJsonNestedResponseEuropeCountriesData, type: 'json', id: 'fake-id-1' })
|
||||||
|
];
|
||||||
|
|
||||||
export const mockJsonProcessVariables = [
|
export const mockJsonProcessVariables = [
|
||||||
new TaskVariableCloud({ name: 'variables.json-variable', value: mockEuropeCountriesData, type: 'json', id: 'fake-id-1' }),
|
new TaskVariableCloud({ name: 'variables.json-variable', value: mockEuropeCountriesData, type: 'json', id: 'fake-id-1' }),
|
||||||
new TaskVariableCloud({ name: 'variables.different-variable', value: 'fake-value', type: 'json', id: 'fake-id-2' })
|
new TaskVariableCloud({ name: 'variables.different-variable', value: 'fake-value', type: 'json', id: 'fake-id-2' })
|
||||||
|
Reference in New Issue
Block a user