Skip to content

Commit

Permalink
FIO-8537: Fixing the filter processor to handle nested component data…
Browse files Browse the repository at this point in the history
… properly. (#117)

* FIO-8537: Fixing issues with the filter process to handle nested components properly.

* Adding the process tests to test for proper filtering of nested components.

* Removed a non-implemented test.

* Adding a new line.
  • Loading branch information
travist authored and lane-formio committed Jul 30, 2024
1 parent 22a14cd commit 4c38e2a
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 108 deletions.
71 changes: 14 additions & 57 deletions src/process/__tests__/process.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -831,29 +831,7 @@ describe('Process Tests', () => {
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
pathName: '/',
onLine: true,
headers: {
host: 'localhost:3000',
connection: 'keep-alive',
'content-length': '9020',
pragma: 'no-cache',
'cache-control': 'no-cache',
'sec-ch-ua':
'"Chromium";v="122", "Not(A:Brand";v="24", "Brave";v="122"',
accept: 'application/json',
'content-type': 'application/json',
'sec-ch-ua-mobile': '?0',
'user-agent':
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
'sec-ch-ua-platform': '"macOS"',
'sec-gpc': '1',
'accept-language': 'en-US,en',
origin: 'http://localhost:3000',
'sec-fetch-site': 'same-origin',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:3000/',
'accept-encoding': 'gzip, deflate, br',
},

},
data: {
number: 23,
Expand Down Expand Up @@ -969,40 +947,7 @@ describe('Process Tests', () => {
},
owner: '65ea3601c3792e416cabcb2a',
access: [],
metadata: {
timezone: 'America/Chicago',
offset: -360,
origin: 'http://localhost:3000',
referrer: '',
browserName: 'Netscape',
userAgent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
pathName: '/',
onLine: true,
headers: {
'accept-language': 'en-US,en',
'cache-control': 'no-cache',
connection: 'keep-alive',
origin: 'http://localhost:3000',
pragma: 'no-cache',
referer: 'http://localhost:3000/',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'sec-gpc': '1',
'user-agent':
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
accept: 'application/json',
'content-type': 'application/json',
'sec-ch-ua':
'"Chromium";v="122", "Not(A:Brand";v="24", "Brave";v="122"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"',
host: 'localhost:3000',
'accept-encoding': 'gzip, deflate, br',
'content-length': '18055',
},
},

_vnote: '',
state: 'submitted',
form: '65ea368b705068f84a93c87a',
Expand All @@ -1024,6 +969,8 @@ describe('Process Tests', () => {
submission.data = context.data;
context.processors = ProcessTargets.evaluator;
processSync(context);
console.log(context.scope.errors);

assert.equal(context.scope.errors.length, 0);
});
it('should remove submission data not in a nested form definition', async function () {
Expand Down Expand Up @@ -3253,9 +3200,14 @@ describe('Process Tests', () => {
form: {
data: {
textField: 'test',
invalidField: 'bad',
},

},
},
{
invalidDataGridField: 'wrong',
},
],
},
};
Expand All @@ -3274,7 +3226,12 @@ describe('Process Tests', () => {
processSync(context);
context.processors = ProcessTargets.evaluator;
processSync(context);
console.log(JSON.stringify(context.data, null, 2));

expect((context.scope as ValidationScope).errors).to.have.length(0);
expect(context.data).to.deep.equal({
editGrid: [{ form: { data: { textField: 'test' } } }],
});
});
it('Should not validate required component when it is not filled out', async () => {
const submission = {
Expand Down
6 changes: 3 additions & 3 deletions src/process/filter/__tests__/filter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ it('Should not filter empty array value for dataGrid component', async () => {
};
const context: any = generateProcessorContext(dataGridComp, data);
filterProcessSync(context);
expect(context.scope.filter).to.deep.equal({'dataGrid': {'compModelType': 'array', 'include': true}});
expect(context.scope.filter).to.deep.equal({'dataGrid': {'compModelType': 'array', 'include': true, value: []}});
});

it('Should not filter empty array value for editGrid component', async () => {
Expand All @@ -46,7 +46,7 @@ it('Should not filter empty array value for editGrid component', async () => {
};
const context: any = generateProcessorContext(editGridComp, data);
filterProcessSync(context);
expect(context.scope.filter).to.deep.equal({'editGrid': {'compModelType': 'array', 'include': true}});
expect(context.scope.filter).to.deep.equal({'editGrid': {'compModelType': 'array', 'include': true, value: []}});
});

it('Should not filter empty array value for datTable component', async () => {
Expand All @@ -69,5 +69,5 @@ it('Should not filter empty array value for datTable component', async () => {
};
const context: any = generateProcessorContext(dataTableComp, data);
filterProcessSync(context);
expect(context.scope.filter).to.deep.equal({'dataTable': {'compModelType': 'array', 'include': true}});
expect(context.scope.filter).to.deep.equal({'dataTable': {'compModelType': 'array', 'include': true, value: []}});
});
75 changes: 27 additions & 48 deletions src/process/filter/index.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
import {
FilterContext,
FilterScope,
ProcessorFn,
ProcessorFnSync,
ProcessorInfo,
} from 'types';
import set from 'lodash/fp/set';
import { Utils } from 'utils';
import { get } from 'lodash';
import { getComponentAbsolutePath } from 'utils/formUtil';
export const filterProcessSync: ProcessorFnSync<FilterScope> = (
context: FilterContext
) => {
import { FilterContext, FilterScope, ProcessorFn, ProcessorFnSync, ProcessorInfo } from "types";
import { set } from 'lodash';
import { Utils } from "utils";
import { get, isObject } from "lodash";
import { getComponentAbsolutePath } from "utils/formUtil";
export const filterProcessSync: ProcessorFnSync<FilterScope> = (context: FilterContext) => {
const { scope, component } = context;
let { value } = context;
const absolutePath = getComponentAbsolutePath(component);

if (!scope.filter) scope.filter = {};
if (value !== undefined) {
const modelType = Utils.getModelType(component);
Expand All @@ -24,22 +15,22 @@ export const filterProcessSync: ProcessorFnSync<FilterScope> = (
scope.filter[absolutePath] = {
compModelType: modelType,
include: true,
value: { data: {} },
value: { data: {} }
};
break;
case 'array':
scope.filter[absolutePath] = {
compModelType: modelType,
include: true,
value: []
};
break;
case 'object':
if (component.type !== 'container') {
scope.filter[absolutePath] = {
compModelType: modelType,
include: true,
};
}
scope.filter[absolutePath] = {
compModelType: modelType,
include: true,
value: (component.type === 'address') ? false : {}
};
break;
default:
scope.filter[absolutePath] = {
Expand All @@ -51,37 +42,25 @@ export const filterProcessSync: ProcessorFnSync<FilterScope> = (
}
};

export const filterProcess: ProcessorFn<FilterScope> = async (
context: FilterContext
) => {
export const filterProcess: ProcessorFn<FilterScope> = async (context: FilterContext) => {
return filterProcessSync(context);
};

export const filterPostProcess: ProcessorFnSync<FilterScope> = (
context: FilterContext
) => {
const { scope, component, submission } = context;
let filtered: Record<string, object> = {};
export const filterPostProcess: ProcessorFnSync<FilterScope> = (context: FilterContext) => {
const { scope, submission } = context;
const filtered = {};
for (const path in scope.filter) {
let value = get(submission?.data, path) as any;
const pathFilter = scope.filter[path];

if (pathFilter.compModelType === 'array') {
// special case for array, if it's empty, set it to empty array
if(value.length === 0) {
filtered[path] = []
}
continue;
} else if (pathFilter) {
// when it's a dataModel Object, don't set values directly on the data object, let child fields do that.
// it can have extra data on updates, so pass all other values except data
// standard lodash set function will mutate original value, using the functional version so it doesn't
if (pathFilter.compModelType === 'dataObject') {
const { data, ...rest } = value;
filtered = set(path, rest)(filtered);
} else {
filtered = set(path, value)(filtered);
if (scope.filter[path].include) {
let value = get(submission?.data, path);
if (scope.filter[path].value) {
if (isObject(value) && scope.filter[path].value?.data) {
value = { ...value, ...scope.filter[path].value };
}
else {
value = scope.filter[path].value;
}
}
set(filtered, path, value);
}
}
context.data = filtered;
Expand Down

0 comments on commit 4c38e2a

Please sign in to comment.