@truedat/df 7.12.5 → 7.12.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/package.json +4 -4
  2. package/src/components/DynamicFieldValue.js +1 -1
  3. package/src/components/DynamicFormViewer.js +4 -3
  4. package/src/components/DynamicFormWithTranslations.js +3 -3
  5. package/src/components/EditableDynamicFieldValue.js +1 -1
  6. package/src/components/FieldViewerValue.js +44 -3
  7. package/src/components/__tests__/FieldViewerValue.spec.js +10 -6
  8. package/src/components/__tests__/__snapshots__/FieldViewerValue.spec.js.snap +53 -0
  9. package/src/components/widgets/DynamicField.js +6 -62
  10. package/src/components/widgets/DynamicTableField.js +150 -0
  11. package/src/components/widgets/FieldByWidget.js +63 -0
  12. package/src/components/widgets/StandardDropdown.js +2 -2
  13. package/src/components/widgets/StringField.js +2 -1
  14. package/src/components/widgets/__tests__/DynamicField.spec.js +10 -1
  15. package/src/components/widgets/__tests__/DynamicTableField.spec.js +257 -0
  16. package/src/components/widgets/__tests__/__snapshots__/DynamicField.spec.js.snap +97 -0
  17. package/src/components/widgets/__tests__/__snapshots__/DynamicTableField.spec.js.snap +114 -0
  18. package/src/templates/components/templateForm/ActiveGroupForm.js +5 -16
  19. package/src/templates/components/templateForm/FieldDefinition.js +158 -0
  20. package/src/templates/components/templateForm/FieldForm.js +32 -135
  21. package/src/templates/components/templateForm/TableValuesForm.js +258 -0
  22. package/src/templates/components/templateForm/TemplateForm.js +43 -26
  23. package/src/templates/components/templateForm/ValuesConfiguration.js +67 -0
  24. package/src/templates/components/templateForm/ValuesField.js +60 -96
  25. package/src/templates/components/templateForm/ValuesListForm.js +1 -3
  26. package/src/templates/components/templateForm/__tests__/FieldDefinition.spec.js +227 -0
  27. package/src/templates/components/templateForm/__tests__/TableValuesForm.spec.js +215 -0
  28. package/src/templates/components/templateForm/__tests__/ValuesField.spec.js +28 -83
  29. package/src/templates/components/templateForm/__tests__/__snapshots__/ActiveGroupForm.spec.js.snap +17 -0
  30. package/src/templates/components/templateForm/__tests__/__snapshots__/FieldDefinition.spec.js.snap +443 -0
  31. package/src/templates/components/templateForm/__tests__/__snapshots__/FieldForm.spec.js.snap +51 -0
  32. package/src/templates/components/templateForm/__tests__/__snapshots__/TemplateForm.spec.js.snap +17 -0
  33. package/src/templates/components/templateForm/__tests__/__snapshots__/ValuesField.spec.js.snap +61 -387
  34. package/src/templates/components/templateForm/contentValidation.js +22 -3
  35. package/src/templates/components/templateForm/valueDefinitions.js +16 -2
  36. package/src/templates/components/templateForm/widgetDefinitions.js +28 -2
  37. package/src/templates/utils/__tests__/validateContent.spec.js +6 -6
  38. package/src/templates/utils/applyTemplate.js +72 -23
  39. package/src/templates/utils/filterValues.js +3 -3
  40. package/src/templates/utils/parseFieldOptions.js +73 -58
  41. package/src/templates/utils/parseGroups.js +47 -48
  42. package/src/templates/utils/validateContent.js +70 -25
@@ -1,6 +1,9 @@
1
1
  import _ from "lodash/fp";
2
+ import { useIntl } from "react-intl";
3
+
4
+ export const getCardinalityOptions = (widget) => {
5
+ const { formatMessage } = useIntl();
2
6
 
3
- export const getCardinalityOptions = (formatMessage) => (widget) => {
4
7
  const cardinalities = _.flow([
5
8
  _.find({ value: widget }),
6
9
  _.prop("cardinalities"),
@@ -12,7 +15,9 @@ export const getCardinalityOptions = (formatMessage) => (widget) => {
12
15
  }))(cardinalities);
13
16
  };
14
17
 
15
- export const getTypeOptions = (formatMessage) => (widget) => {
18
+ export const getTypeOptions = (widget) => {
19
+ const { formatMessage } = useIntl();
20
+
16
21
  const types = _.flow([_.find({ value: widget }), _.prop("types")])(WIDGETS);
17
22
  return _.map((type) => ({
18
23
  key: type,
@@ -111,6 +116,14 @@ export const WIDGETS = [
111
116
  cardinalities: ["*"],
112
117
  types: ["table"],
113
118
  },
119
+ {
120
+ key: "dynamic_table",
121
+ value: "dynamic_table",
122
+ text: "Dynamic Table",
123
+ icon: "table",
124
+ cardinalities: ["*"],
125
+ types: ["dynamic_table"],
126
+ },
114
127
  {
115
128
  key: "password",
116
129
  value: "password",
@@ -152,3 +165,16 @@ export const WIDGETS = [
152
165
  types: ["datetime"],
153
166
  },
154
167
  ];
168
+
169
+ export const defaultFieldDefinition = {
170
+ name: "new_field",
171
+ label: "New Field",
172
+ widget: "string",
173
+ cardinality: "?",
174
+ type: "string",
175
+ default: {
176
+ value: "",
177
+ origin: "default",
178
+ },
179
+ values: null,
180
+ };
@@ -62,7 +62,7 @@ const templateMultCondVisibility = {
62
62
  describe("utils: validateContent", () => {
63
63
  describe("validateRequired", () => {
64
64
  it("should return an empty array on valid content", () => {
65
- const content = { req: "foo" };
65
+ const content = { req: { value: "foo" } };
66
66
  const result = validateContent(template)(content);
67
67
  expect(result).toEqual([]);
68
68
  });
@@ -77,12 +77,12 @@ describe("utils: validateContent", () => {
77
77
  ]);
78
78
  });
79
79
  it("should return empty array on valid multiple field", () => {
80
- const content = { req: ["value"] };
80
+ const content = { req: { value: ["value"] } };
81
81
  const result = validateContent(templateMultiple)(content);
82
82
  expect(result).toEqual([]);
83
83
  });
84
84
  it("should return error on empty required multiple field", () => {
85
- const content = { req: [] };
85
+ const content = { req: { value: [] } };
86
86
  const result = validateContent(templateMultiple)(content);
87
87
  expect(result).toEqual([
88
88
  {
@@ -92,12 +92,12 @@ describe("utils: validateContent", () => {
92
92
  ]);
93
93
  });
94
94
  it("should return empty array on hidden required field", () => {
95
- const content = { depend: "no" };
95
+ const content = { depend: { value: "no" } };
96
96
  const result = validateContent(templateCondVisibility)(content);
97
97
  expect(result).toEqual([]);
98
98
  });
99
99
  it("should return error on conditionaly shown required field", () => {
100
- const content = { depend: "yes" };
100
+ const content = { depend: { value: "yes" } };
101
101
  const result = validateContent(templateCondVisibility)(content);
102
102
  expect(result).toEqual([
103
103
  {
@@ -107,7 +107,7 @@ describe("utils: validateContent", () => {
107
107
  ]);
108
108
  });
109
109
  it("should return error on multiple conditionaly shown required field", () => {
110
- const content = { depend: "maybe" };
110
+ const content = { depend: { value: "maybe" } };
111
111
  const result = validateContent(templateMultCondVisibility)(content);
112
112
  expect(result).toEqual([
113
113
  {
@@ -17,33 +17,82 @@ const isInformed = _.flow(
17
17
  (value) => !value
18
18
  );
19
19
 
20
+ const applyTableFields = (templateContent, content, domainId) => {
21
+ const tableFields = _.filter((field) => field.type === "dynamic_table")(templateContent);
22
+ return _.reduce((content, field) => {
23
+ const fieldName = field.name;
24
+ const contentValues = _.pathOr([], `${fieldName}.value`)(content)
25
+
26
+ if (!_.isEmpty(contentValues)) {
27
+ const tableColumns = field.values.table_columns;
28
+ const updatedContentValues = _.map((contentValue) => _.flow(
29
+ filterFields(tableColumns),
30
+ filterValues(tableColumns),
31
+ filterDepends(tableColumns),
32
+ filterSwitches(tableColumns),
33
+ (content) => filterDomains(tableColumns)(content, domainId),
34
+ (content) => applyDefaults(tableColumns)(content, domainId),
35
+ )(contentValue))(contentValues);
36
+
37
+ return _.set(`${fieldName}.value`, updatedContentValues)(content);
38
+ } else {
39
+ return content
40
+ }
41
+ }, content)(tableFields)
42
+ }
43
+
44
+ const applyTableFieldsWithoutDefaults = (templateContent, content, domainId) => {
45
+ const tableFields = _.filter((field) => field.type === "dynamic_table")(templateContent);
46
+ return _.reduce((content, field) => {
47
+ const fieldName = field.name;
48
+ const contentValues = _.pathOr([], `${fieldName}.value`)(content)
49
+
50
+ if (!_.isEmpty(contentValues)) {
51
+ const tableColumns = field.values.table_columns;
52
+ const updatedContentValues = _.map((contentValue) => _.flow(
53
+ filterFields(tableColumns),
54
+ filterValues(tableColumns),
55
+ filterDepends(tableColumns),
56
+ filterSwitches(tableColumns),
57
+ (content) => filterDomains(tableColumns)(content, domainId),
58
+ (content) => applyDefaults(tableColumns)(content, domainId),
59
+ )(contentValue))(contentValues);
60
+
61
+ return _.set(`${fieldName}.value`, updatedContentValues)(content);
62
+ } else {
63
+ return content
64
+ }
65
+ }, content)(tableFields)
66
+ }
20
67
  export const applyTemplate =
21
68
  (template) =>
22
- (content, domainId = null) => {
23
- const templateContent = flattenFields(template);
24
- return _.flow(
25
- filterFields(templateContent),
26
- filterValues(templateContent),
27
- filterDepends(templateContent),
28
- filterSwitches(templateContent),
29
- (content) => filterDomains(templateContent)(content, domainId),
30
- (content) => applyDefaults(templateContent)(content, domainId),
31
- _.pickBy((value) => isInformed(value.value))
32
- )(content);
33
- };
69
+ (content, domainId = null) => {
70
+ const templateContent = flattenFields(template);
71
+ return _.flow(
72
+ filterFields(templateContent),
73
+ filterValues(templateContent),
74
+ filterDepends(templateContent),
75
+ filterSwitches(templateContent),
76
+ (content) => filterDomains(templateContent)(content, domainId),
77
+ (content) => applyDefaults(templateContent)(content, domainId),
78
+ _.pickBy((value) => isInformed(value.value)),
79
+ (content) => applyTableFields(templateContent, content, domainId)
80
+ )(content);
81
+ };
34
82
 
35
83
  export const applyTemplateWithoutDefaults =
36
84
  (template) =>
37
- (content, domainId = null) => {
38
- const templateContent = flattenFields(template);
39
- return _.flow(
40
- filterFields(templateContent),
41
- filterValues(templateContent),
42
- filterDepends(templateContent),
43
- filterSwitches(templateContent),
44
- (content) => filterDomains(templateContent)(content, domainId),
45
- _.pickBy((value) => isInformed(value.value))
46
- )(content);
47
- };
85
+ (content, domainId = null) => {
86
+ const templateContent = flattenFields(template);
87
+ return _.flow(
88
+ filterFields(templateContent),
89
+ filterValues(templateContent),
90
+ filterDepends(templateContent),
91
+ filterSwitches(templateContent),
92
+ (content) => filterDomains(templateContent)(content, domainId),
93
+ _.pickBy((value) => isInformed(value.value)),
94
+ (content) => applyTableFieldsWithoutDefaults(templateContent, content, domainId)
95
+ )(content);
96
+ };
48
97
 
49
98
  export default applyTemplate;
@@ -34,9 +34,9 @@ export const filterValues = (templateContent) => {
34
34
  _.has(key)(vv)
35
35
  ? _.isArray(value.value)
36
36
  ? _.set(
37
- "value",
38
- _.filter((v) => _.includes(v)(_.prop(key)(vv)))(value.value)
39
- )(value)
37
+ "value",
38
+ _.filter((v) => _.includes(v)(_.prop(key)(vv)))(value.value)
39
+ )(value)
40
40
  : _.includes(value.value)(_.prop(key)(vv))
41
41
  ? value
42
42
  : { ...value, value: null }
@@ -7,66 +7,81 @@ const makeOptions = (formatMessage, label) =>
7
7
  text: formatMessage({ id: `fields.${label}.${v}`, defaultMessage: v }),
8
8
  }));
9
9
 
10
- export const parseFieldOptions =
11
- (formatMessage) => (content, selectedDomain) => (field) => {
12
- const value = _.prop(field?.name)(content);
13
- if (!field?.values) return { ...field, value };
10
+ const doParseFieldOptions = (formatMessage, content, selectedDomain, field) => {
11
+ const value = _.prop(field?.name)(content);
14
12
 
15
- const translateValues = _.flow(
16
- makeOptions(formatMessage, field?.label),
17
- _.sortBy(accentInsensitivePathOrder("text"))
18
- );
19
- const parseSwitch = (values) => {
20
- const switchOn = _.prop("switch.on")(values);
21
- const switchedValues = _.prop(`switch.values.${content[switchOn].value}`)(
22
- values
23
- );
24
- return translateValues(switchedValues);
13
+ if (!field?.values) return { ...field, value };
14
+ if (field?.type == "dynamic_table" && _.has("values.table_columns")(field)) {
15
+ const tableColumns = _.flow(
16
+ _.propOr([], "values.table_columns"),
17
+ _.map((field) =>
18
+ doParseFieldOptions(formatMessage, content, selectedDomain, field),
19
+ ),
20
+ )(field);
21
+ return {
22
+ ...field,
23
+ value,
24
+ values: { ...field?.values, table_columns: tableColumns },
25
25
  };
26
- const parseFixed = _.flow(_.get("fixed"), translateValues);
27
- const parseRoleUsers = _.flow(
28
- _.get("processed_users"),
29
- _.cond([
30
- [_.isArray, _.identity],
31
- [_.stubTrue, _.constant([])],
32
- ]),
33
- translateValues
26
+ }
27
+ const translateValues = _.flow(
28
+ makeOptions(formatMessage, field?.label),
29
+ _.sortBy(accentInsensitivePathOrder("text")),
30
+ );
31
+ const parseSwitch = (values) => {
32
+ const switchOn = _.prop("switch.on")(values);
33
+ const switchedValues = _.prop(`switch.values.${content[switchOn].value}`)(
34
+ values,
34
35
  );
35
- const parseRoleGroups = (values) =>
36
- _.concat(
37
- _.flow(
38
- _.get("processed_users"),
39
- _.map((name) => ({
40
- value: `user:${name}`,
41
- text: name,
42
- icon: "user",
43
- }))
44
- )(values),
45
- _.flow(
46
- _.get("processed_groups"),
47
- _.map((name) => ({
48
- value: `group:${name}`,
49
- text: name,
50
- icon: "group",
51
- }))
52
- )(values)
53
- );
54
- const parseDomain = _.flow(
55
- _.get("domain"),
56
- _.propOr([], _.toString(selectedDomain?.id)),
57
- translateValues
36
+ return translateValues(switchedValues);
37
+ };
38
+ const parseFixed = _.flow(_.get("fixed"), translateValues);
39
+ const parseRoleUsers = _.flow(
40
+ _.get("processed_users"),
41
+ _.cond([
42
+ [_.isArray, _.identity],
43
+ [_.stubTrue, _.constant([])],
44
+ ]),
45
+ translateValues,
46
+ );
47
+ const parseRoleGroups = (values) =>
48
+ _.concat(
49
+ _.flow(
50
+ _.get("processed_users"),
51
+ _.map((name) => ({
52
+ value: `user:${name}`,
53
+ text: name,
54
+ icon: "user",
55
+ })),
56
+ )(values),
57
+ _.flow(
58
+ _.get("processed_groups"),
59
+ _.map((name) => ({
60
+ value: `group:${name}`,
61
+ text: name,
62
+ icon: "group",
63
+ })),
64
+ )(values),
58
65
  );
66
+ const parseDomain = _.flow(
67
+ _.get("domain"),
68
+ _.propOr([], _.toString(selectedDomain?.id)),
69
+ translateValues,
70
+ );
59
71
 
60
- const parsedValues = _.flow(
61
- _.get("values"),
62
- _.cond([
63
- [_.has("switch"), parseSwitch],
64
- [_.has("fixed"), parseFixed],
65
- [_.has("fixed_tuple"), _.get("fixed_tuple")],
66
- [_.has("role_users"), parseRoleUsers],
67
- [_.has("role_groups"), parseRoleGroups],
68
- [_.has("domain"), parseDomain],
69
- ])
70
- )(field);
71
- return { ...field, value, parsedValues };
72
- };
72
+ const parsedValues = _.flow(
73
+ _.get("values"),
74
+ _.cond([
75
+ [_.has("switch"), parseSwitch],
76
+ [_.has("fixed"), parseFixed],
77
+ [_.has("fixed_tuple"), _.get("fixed_tuple")],
78
+ [_.has("role_users"), parseRoleUsers],
79
+ [_.has("role_groups"), parseRoleGroups],
80
+ [_.has("domain"), parseDomain],
81
+ ]),
82
+ )(field);
83
+ return { ...field, value, parsedValues };
84
+ };
85
+ export const parseFieldOptions =
86
+ (formatMessage) => (content, selectedDomain) => (field) =>
87
+ doParseFieldOptions(formatMessage, content, selectedDomain, field);
@@ -31,61 +31,60 @@ export const parseGroups =
31
31
  (hasDependentKeys(field) && checkDependency(field, content))) &&
32
32
  (!(field.values && "switch" in field.values) ||
33
33
  _.prop(`${_.prop("values.switch.on")(field)}.value`)(content) in
34
- _.prop("values.switch.values")(field))
34
+ _.prop("values.switch.values")(field)),
35
35
  ),
36
36
  _.map(parseFieldOptions(formatMessage)(content, selectedDomain)),
37
37
  _.map(enrichRequired(content)),
38
- _.map(enrichIsSecret(_.get("is_secret")(group)))
38
+ _.map(enrichIsSecret(_.get("is_secret")(group))),
39
39
  )(group);
40
40
  return { ...group, fields };
41
41
  }),
42
- _.filter(({ fields }) => _.negate(_.isEmpty)(fields))
42
+ _.filter(({ fields }) => _.negate(_.isEmpty)(fields)),
43
43
  )(template);
44
44
 
45
45
  export const parseGroupsWithLangs =
46
46
  (formatMessage) =>
47
- (template, i18nContent, fieldsToOmit, selectedDomain, requiredLangs = []) => {
48
- return _.flow(
49
- _.getOr([], "content"),
50
- _.map((group) => {
51
- const langs = _.flow(
52
- _.toPairs,
53
- _.map(([lang, langContent]) => {
54
- const fields = _.flow(
55
- _.get("fields"),
56
- _.reject((field) => _.includes(fieldsToOmit)(field?.name)),
57
- _.filter((field) => {
58
- return (
59
- (!("depends" in field) ||
60
- (hasDependentKeys(field) &&
61
- checkDependency(field, langContent))) &&
62
- (!(field.values && "switch" in field.values) ||
63
- _.prop(`${_.prop("values.switch.on")(field)}.value`)(
64
- langContent
65
- ) in _.prop("values.switch.values")(field))
66
- );
67
- }),
68
- _.map((field) => ({
69
- ...field,
70
- ...parseFieldOptions(formatMessage)(
71
- langContent,
72
- selectedDomain
73
- )(field),
74
- ...(requiredLangs.includes(lang)
75
- ? enrichRequired(langContent)(field)
76
- : { required: false }),
77
- ...enrichIsSecret(_.get("is_secret")(group))(field),
78
- }))
79
- )(group);
80
- return [lang, fields];
81
- }),
82
- _.fromPairs
83
- )(i18nContent);
84
- return {
85
- name: group.name,
86
- langs,
87
- };
88
- }),
89
- _.filter(({ langs }) => _.some((fields) => !_.isEmpty(fields))(langs))
90
- )(template);
91
- };
47
+ (template, i18nContent, fieldsToOmit, selectedDomain, requiredLangs = []) => {
48
+ return _.flow(
49
+ _.getOr([], "content"),
50
+ _.map((group) => {
51
+ const langs = _.flow(
52
+ _.toPairs,
53
+ _.map(([lang, langContent]) => {
54
+ const fields = _.flow(
55
+ _.get("fields"),
56
+ _.reject((field) => _.includes(fieldsToOmit)(field?.name)),
57
+ _.filter((field) => {
58
+ return (
59
+ (!("depends" in field) ||
60
+ (hasDependentKeys(field) &&
61
+ checkDependency(field, langContent))) &&
62
+ (!(field.values && "switch" in field.values) ||
63
+ _.prop(`${_.prop("values.switch.on")(field)}.value`)(
64
+ langContent,
65
+ ) in _.prop("values.switch.values")(field))
66
+ );
67
+ }),
68
+ _.map(
69
+ _.flow(
70
+ parseFieldOptions(formatMessage)(langContent, selectedDomain),
71
+ (field) => requiredLangs.includes(lang)
72
+ ? enrichRequired(langContent)(field)
73
+ : { ...field, required: false }
74
+ ,
75
+ enrichIsSecret(_.get("is_secret")(group)),
76
+ ),
77
+ ),
78
+ )(group);
79
+ return [lang, fields];
80
+ }),
81
+ _.fromPairs,
82
+ )(i18nContent);
83
+ return {
84
+ name: group.name,
85
+ langs,
86
+ };
87
+ }),
88
+ _.filter(({ langs }) => _.some((fields) => !_.isEmpty(fields))(langs)),
89
+ )(template);
90
+ };
@@ -3,42 +3,75 @@ import { flattenFields } from "./flattenFields";
3
3
 
4
4
  const fieldIsHiddenVerifier =
5
5
  (content) =>
6
- ({ depends }) => {
7
- if (!depends) return false;
8
- const { on, to_be } = depends;
9
- const dependentValue = content[on];
10
- return _.isArray(dependentValue)
11
- ? !_.some((d) => to_be.includes(d))(dependentValue)
12
- : !to_be.includes(dependentValue);
13
- };
6
+ ({ depends }) => {
7
+ if (!depends) return false;
8
+ const { on, to_be } = depends;
9
+ const dependentValue = content[on]?.value;
10
+ return _.isArray(dependentValue)
11
+ ? !_.some((d) => to_be.includes(d))(dependentValue)
12
+ : !to_be.includes(dependentValue);
13
+ };
14
14
 
15
- export const validateContent = (template) => (content) => {
15
+ const isTableRequired = (field, content) => {
16
+ if (field?.type === "dynamic_table" && _.has("values.table_columns")(field)) {
17
+ const rowValues = _.pathOr([], `${field?.name}.value`)(content);
18
+
19
+ if (_.isEmpty(rowValues)) return false;
20
+
21
+ return _.flow(
22
+ _.pathOr([], "values.table_columns"),
23
+ _.any((nestedField) => _.includes(nestedField?.cardinality)(["1", "+"])))
24
+ (field);
25
+ }
26
+
27
+ return false;
28
+ }
29
+
30
+ const validateTemplateContent = (schema, content) => {
16
31
  const fieldIsHidden = fieldIsHiddenVerifier(content);
17
- const templateContent = _.flow(
18
- flattenFields,
19
- _.reject(fieldIsHidden)
20
- )(template);
32
+ const templateContent = _.reject(fieldIsHidden)(schema);
21
33
  return _.flow(validateRequired(templateContent), _.head)([[], content]);
34
+ }
35
+
36
+ export const validateContent = (template) => (content) => {
37
+ const schema = flattenFields(template);
38
+ return validateTemplateContent(schema, content);
22
39
  };
23
40
 
24
- const isEmptyValue = (value) => !_.isNumber(value) && _.isEmpty(value);
41
+ const isEmptyValue = (value) => _.isNil(value) || (!_.isNumber(value) && _.isEmpty(value));
42
+
43
+ const isEmptyField = (field, content) => {
44
+ if (field?.type === "dynamic_table" && _.has("values.table_columns")(field)) {
45
+ const tableColumns = _.pathOr([], "values.table_columns")(field);
46
+ const rowValues = _.pathOr([], `${field?.name}.value`)(content);
47
+
48
+ if (_.isEmpty(rowValues)) return true;
49
+
50
+ const requiredErrors = _.flow(
51
+ _.map((row) => _.flow(validateRequired(tableColumns), _.head)([[], row])),
52
+ _.flatten,
53
+ )(rowValues);
54
+
55
+ return !_.isEmpty(requiredErrors);
56
+ }
57
+ return isEmptyValue(content?.[field?.name]?.value);
58
+ }
25
59
 
26
60
  export const validateRequired =
27
61
  (templateContent) =>
28
- ([validations, content]) => {
29
- const newValidations = _.flow([
30
- _.filter((field) => isRequired(field, content)),
31
- _.map("name"),
32
- _.filter((r) => isEmptyValue(_.prop(r)(content))),
33
- _.map((field) => ({ error: "missing required", field })),
34
- ])(templateContent);
35
- return [[...validations, ...newValidations], content];
36
- };
62
+ ([validations, content]) => {
63
+ const newValidations = _.flow([
64
+ _.filter((field) => isRequired(field, content)),
65
+ _.filter((field) => isEmptyField(field, content)),
66
+ _.map((field) => ({ error: "missing required", field: field?.name })),
67
+ ])(templateContent);
68
+ return [[...validations, ...newValidations], content];
69
+ };
37
70
 
38
71
  export const dependentRequired = (field, content) => {
39
72
  if (_.has("mandatory")(field)) {
40
73
  const on = field?.mandatory?.on;
41
- const dependent = content[on];
74
+ const dependent = content[on]?.value;
42
75
  const target = field?.mandatory?.to_be || [];
43
76
  if (_.isArray(dependent)) {
44
77
  return !_.isEmpty(_.intersection(dependent)(target));
@@ -50,11 +83,23 @@ export const dependentRequired = (field, content) => {
50
83
  };
51
84
 
52
85
  export const isRequired = (field, content) =>
53
- _.includes(field?.cardinality)(["1", "+"]) ||
86
+ _.includes(field?.cardinality)(["1", "+"]) || isTableRequired(field, content) ||
54
87
  dependentRequired(field, content);
55
88
 
56
89
  export const enrichRequired = (content) => (field) => {
57
90
  const required = isRequired(field, content);
91
+ if (field?.type === "dynamic_table" && _.has("values.table_columns")(field)) {
92
+ const tableColumns = _.flow(
93
+ _.propOr([], "values.table_columns"),
94
+ _.map((field) => enrichRequired({})(field)))
95
+ (field);
96
+
97
+ return _.flow(
98
+ _.set("values.table_columns", tableColumns),
99
+ _.set("required", required))
100
+ (field);
101
+ }
102
+
58
103
  return { ...field, required };
59
104
  };
60
105