@evoke-platform/ui-components 1.4.0-testing.1 → 1.4.0-testing.11
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.
- package/dist/published/components/core/Alert/Alert.js +1 -1
- package/dist/published/components/core/Autocomplete/Autocomplete.js +3 -3
- package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.js +2 -18
- package/dist/published/components/custom/CriteriaBuilder/PropertyTree.js +2 -2
- package/dist/published/components/custom/CriteriaBuilder/ValueEditor.js +25 -17
- package/dist/published/components/custom/CriteriaBuilder/index.d.ts +2 -1
- package/dist/published/components/custom/CriteriaBuilder/index.js +2 -1
- package/dist/published/components/custom/CriteriaBuilder/utils.d.ts +13 -0
- package/dist/published/components/custom/CriteriaBuilder/utils.js +58 -1
- package/dist/published/components/custom/Form/Common/Form.js +37 -26
- package/dist/published/components/custom/Form/Common/FormComponentWrapper.js +2 -1
- package/dist/published/components/custom/Form/FormComponents/CriteriaComponent/Criteria.js +52 -1
- package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectComponent.d.ts +2 -0
- package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectComponent.js +75 -26
- package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectPropertyInput.js +3 -2
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ActionDialog.d.ts +5 -2
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ActionDialog.js +4 -6
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableField.js +4 -2
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableFieldComponent.js +31 -13
- package/dist/published/components/custom/Form/tests/Form.test.d.ts +1 -0
- package/dist/published/components/custom/Form/tests/Form.test.js +158 -0
- package/dist/published/components/custom/Form/tests/test-data.d.ts +13 -0
- package/dist/published/components/custom/Form/tests/test-data.js +381 -0
- package/dist/published/components/custom/Form/utils.d.ts +10 -4
- package/dist/published/components/custom/Form/utils.js +213 -90
- package/dist/published/components/custom/FormField/AddressFieldComponent/addressFieldComponent.js +1 -1
- package/dist/published/components/custom/HistoryLog/DisplayedProperty.d.ts +2 -1
- package/dist/published/components/custom/HistoryLog/DisplayedProperty.js +5 -2
- package/dist/published/components/custom/HistoryLog/HistoryData.d.ts +1 -0
- package/dist/published/components/custom/HistoryLog/HistoryData.js +9 -3
- package/dist/published/components/custom/HistoryLog/index.js +24 -2
- package/dist/published/components/custom/index.d.ts +1 -1
- package/dist/published/components/custom/index.js +1 -1
- package/dist/published/index.d.ts +1 -1
- package/dist/published/index.js +1 -1
- package/package.json +3 -4
@@ -1,6 +1,10 @@
|
|
1
1
|
import { camelCase, get, isArray, isEmpty, isNil, isObject, isUndefined, pick, startCase, transform, uniq, } from 'lodash';
|
2
2
|
import { DateTime } from 'luxon';
|
3
3
|
import { nanoid } from 'nanoid';
|
4
|
+
import Handlebars from 'no-eval-handlebars';
|
5
|
+
import qs from 'qs';
|
6
|
+
import { defaultRuleProcessorMongoDB, formatQuery, parseMongoDB, } from 'react-querybuilder';
|
7
|
+
import escape from 'string-escape-regex';
|
4
8
|
// The following functions are used to build the FormIO form components from the form parameters.
|
5
9
|
export function determineComponentType(properties, parameter) {
|
6
10
|
if (!parameter)
|
@@ -96,15 +100,7 @@ export function convertFormToComponents(entries, parameters, object) {
|
|
96
100
|
? convertFormToComponents(section.entries, parameters, object)
|
97
101
|
: [],
|
98
102
|
})),
|
99
|
-
conditional:
|
100
|
-
? {
|
101
|
-
show: entry.visibility.conditions[0].operator === 'eq',
|
102
|
-
when: entry.visibility.conditions[0].property,
|
103
|
-
eq: entry.visibility.conditions[0].value,
|
104
|
-
}
|
105
|
-
: {
|
106
|
-
json: entry.visibility,
|
107
|
-
},
|
103
|
+
conditional: convertVisibilityToConditional(entry.visibility),
|
108
104
|
};
|
109
105
|
}
|
110
106
|
else if (entry.type === 'columns') {
|
@@ -120,15 +116,7 @@ export function convertFormToComponents(entries, parameters, object) {
|
|
120
116
|
? convertFormToComponents(column.entries, parameters, object)
|
121
117
|
: [],
|
122
118
|
})),
|
123
|
-
conditional:
|
124
|
-
? {
|
125
|
-
show: entry.visibility.conditions[0].operator === 'eq',
|
126
|
-
when: entry.visibility.conditions[0].property,
|
127
|
-
eq: entry.visibility.conditions[0].value,
|
128
|
-
}
|
129
|
-
: {
|
130
|
-
json: entry.visibility,
|
131
|
-
},
|
119
|
+
conditional: convertVisibilityToConditional(entry.visibility),
|
132
120
|
};
|
133
121
|
}
|
134
122
|
else if (entry.type === 'content') {
|
@@ -136,15 +124,7 @@ export function convertFormToComponents(entries, parameters, object) {
|
|
136
124
|
type: 'Content',
|
137
125
|
key: nanoid(),
|
138
126
|
html: entry.html,
|
139
|
-
conditional:
|
140
|
-
? {
|
141
|
-
show: entry.visibility.conditions[0].operator === 'eq',
|
142
|
-
when: entry.visibility.conditions[0].property,
|
143
|
-
eq: entry.visibility.conditions[0].value,
|
144
|
-
}
|
145
|
-
: {
|
146
|
-
json: entry.visibility,
|
147
|
-
},
|
127
|
+
conditional: convertVisibilityToConditional(entry.visibility),
|
148
128
|
};
|
149
129
|
}
|
150
130
|
else {
|
@@ -163,6 +143,7 @@ export function convertFormToComponents(entries, parameters, object) {
|
|
163
143
|
name: topLevelProperty?.name
|
164
144
|
? `${topLevelProperty.name} ${startCase(property.id.split('.')[1])}`
|
165
145
|
: startCase(property.id.split('.')[1]),
|
146
|
+
type: topLevelProperty?.type,
|
166
147
|
};
|
167
148
|
}
|
168
149
|
const type = determineComponentType(object.properties ?? [], parameter);
|
@@ -261,17 +242,7 @@ export function convertFormToComponents(entries, parameters, object) {
|
|
261
242
|
widget: (parameter.type === 'string' && parameter.enum) || parameter.type === 'array'
|
262
243
|
? 'choicejs'
|
263
244
|
: undefined,
|
264
|
-
conditional: displayOptions?.visibility
|
265
|
-
typeof displayOptions?.visibility !== 'string' &&
|
266
|
-
displayOptions.visibility.conditions?.length
|
267
|
-
? {
|
268
|
-
show: displayOptions?.visibility.conditions[0].operator === 'eq',
|
269
|
-
when: displayOptions?.visibility.conditions[0].property,
|
270
|
-
eq: displayOptions?.visibility.conditions[0].value,
|
271
|
-
}
|
272
|
-
: {
|
273
|
-
json: displayOptions?.visibility,
|
274
|
-
},
|
245
|
+
conditional: convertVisibilityToConditional(displayOptions?.visibility),
|
275
246
|
viewLayout: displayOptions?.viewLayout,
|
276
247
|
};
|
277
248
|
}
|
@@ -482,11 +453,26 @@ export function getPrefixedUrl(url) {
|
|
482
453
|
console.error('Invalid URL');
|
483
454
|
return url;
|
484
455
|
}
|
456
|
+
export function flattenFormComponents(components) {
|
457
|
+
if (!components)
|
458
|
+
return [];
|
459
|
+
return components.reduce((acc, component) => {
|
460
|
+
if (component.type === 'Section') {
|
461
|
+
return acc.concat(component.components?.flatMap((components) => flattenFormComponents(components.components)) ?? []);
|
462
|
+
}
|
463
|
+
else if (component.type === 'Columns') {
|
464
|
+
return acc.concat(component.columns?.flatMap((column) => flattenFormComponents(column.components)) ?? []);
|
465
|
+
}
|
466
|
+
else {
|
467
|
+
return acc.concat(component);
|
468
|
+
}
|
469
|
+
}, []);
|
470
|
+
}
|
485
471
|
// The following function adds the object properties to the form components.
|
486
472
|
// This function is used when there is no form configured in the form builder.
|
487
473
|
export async function addObjectPropertiesToComponentProps(properties,
|
488
474
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
489
|
-
formComponents, instance, objectPropertyInputProps, autoSave, readOnly, defaultPages, navigateTo, queryAddresses, apiServices, isModal, fieldHeight, richTextEditor) {
|
475
|
+
formComponents, allCriteriaInputs, instance, objectPropertyInputProps, associatedObject, autoSave, readOnly, defaultPages, navigateTo, queryAddresses, apiServices, isModal, fieldHeight, richTextEditor) {
|
490
476
|
return [
|
491
477
|
...(await Promise.all(formComponents
|
492
478
|
?.filter((component) => !isUndefined(component) && !isNil(component))
|
@@ -624,6 +610,8 @@ formComponents, instance, objectPropertyInputProps, autoSave, readOnly, defaultP
|
|
624
610
|
...(component.type === 'Object' && objectPropertyInputProps),
|
625
611
|
defaultValue,
|
626
612
|
property,
|
613
|
+
allCriteriaInputs,
|
614
|
+
properties,
|
627
615
|
type: `${readOnly ? 'ViewOnly' : ''}${component.type}`,
|
628
616
|
readOnly: component.readOnly || readOnly || property?.formula,
|
629
617
|
multiple: ['array', 'document'].includes(property.type),
|
@@ -648,13 +636,27 @@ formComponents, instance, objectPropertyInputProps, autoSave, readOnly, defaultP
|
|
648
636
|
: undefined,
|
649
637
|
};
|
650
638
|
}
|
651
|
-
|
639
|
+
let defaultValue = getDefaultValue(isNil(instanceValue) ? component.initialValue : instanceValue, component?.data?.values);
|
640
|
+
// If "associatedObject" is defined, that means the form is associating an existing instance with the current instance.
|
641
|
+
// Set the associated instance as a default value and hide the field.
|
642
|
+
if (associatedObject?.instanceId &&
|
643
|
+
associatedObject?.propertyId &&
|
644
|
+
associatedObject?.propertyId === property.id) {
|
645
|
+
defaultValue = { id: associatedObject.instanceId };
|
646
|
+
component.hidden = true;
|
647
|
+
// If "conditional" is defined, the "hidden" property isn't respected.
|
648
|
+
// Remove the "conditional" property after setting "hidden" to true.
|
649
|
+
delete component.conditional;
|
650
|
+
}
|
652
651
|
return {
|
653
652
|
...component,
|
654
653
|
...(component.type === 'Object' && objectPropertyInputProps),
|
655
654
|
type: `${readOnly ? 'ViewOnly' : ''}${component.type}`,
|
656
655
|
defaultValue,
|
656
|
+
allCriteriaInputs,
|
657
|
+
properties,
|
657
658
|
property,
|
659
|
+
associatedObject,
|
658
660
|
readOnly: component.readOnly || readOnly || property?.formula,
|
659
661
|
multiple: ['array', 'document'].includes(property.type),
|
660
662
|
instance: instance,
|
@@ -693,7 +695,7 @@ formComponents, instance, objectPropertyInputProps, autoSave, readOnly, defaultP
|
|
693
695
|
}
|
694
696
|
if (component.columns) {
|
695
697
|
for (const column of component.columns) {
|
696
|
-
column.components = await addObjectPropertiesToComponentProps(properties, column.components, instance, objectPropertyInputProps, autoSave, readOnly, undefined, undefined, queryAddresses, apiServices, isModal, fieldHeight, richTextEditor);
|
698
|
+
column.components = await addObjectPropertiesToComponentProps(properties, column.components, allCriteriaInputs, instance, objectPropertyInputProps, associatedObject, autoSave, readOnly, undefined, undefined, queryAddresses, apiServices, isModal, fieldHeight, richTextEditor);
|
697
699
|
}
|
698
700
|
return component;
|
699
701
|
}
|
@@ -713,6 +715,17 @@ formComponents, instance, objectPropertyInputProps, autoSave, readOnly, defaultP
|
|
713
715
|
if (item.type.includes('RepeatableField') && !!instance) {
|
714
716
|
item.instance = instance;
|
715
717
|
}
|
718
|
+
// If "associatedObject" is defined, that means the form is associating an existing instance with the current instance.
|
719
|
+
// Set the associated instance as a default value and hide the field.
|
720
|
+
if (associatedObject?.instanceId &&
|
721
|
+
associatedObject?.propertyId &&
|
722
|
+
item.property.id === associatedObject.propertyId) {
|
723
|
+
item.defaultValue = { id: associatedObject.instanceId };
|
724
|
+
item.hidden = true;
|
725
|
+
// If "conditional" is defined, the "hidden" property isn't respected.
|
726
|
+
// Remove the "conditional" property after setting "hidden" to true.
|
727
|
+
delete item.conditional;
|
728
|
+
}
|
716
729
|
}
|
717
730
|
if (nestedFieldProperty) {
|
718
731
|
item.type = `${readOnly ? 'ViewOnly' : ''}${item.type}`;
|
@@ -725,6 +738,8 @@ formComponents, instance, objectPropertyInputProps, autoSave, readOnly, defaultP
|
|
725
738
|
item.user = objectPropertyInputProps?.user;
|
726
739
|
item.defaultPages = defaultPages;
|
727
740
|
item.navigateTo = navigateTo;
|
741
|
+
item.allCriteriaInputs = allCriteriaInputs;
|
742
|
+
item.properties = properties;
|
728
743
|
item.isModal = isModal;
|
729
744
|
item.fieldHeight = fieldHeight;
|
730
745
|
item.richTextEditor = ['RepeatableField', 'Object'].includes(item.type)
|
@@ -751,7 +766,7 @@ formComponents, instance, objectPropertyInputProps, autoSave, readOnly, defaultP
|
|
751
766
|
}
|
752
767
|
}
|
753
768
|
return {
|
754
|
-
components: await addObjectPropertiesToComponentProps(properties, component.components, instance, objectPropertyInputProps, autoSave, readOnly, defaultPages, navigateTo, queryAddresses, apiServices, isModal, fieldHeight, richTextEditor),
|
769
|
+
components: await addObjectPropertiesToComponentProps(properties, component.components, allCriteriaInputs, instance, objectPropertyInputProps, associatedObject, autoSave, readOnly, defaultPages, navigateTo, queryAddresses, apiServices, isModal, fieldHeight, richTextEditor),
|
755
770
|
...component,
|
756
771
|
...(component.type === 'Object' && objectPropertyInputProps),
|
757
772
|
type: `${readOnly ? 'ViewOnly' : ''}${component.type}`,
|
@@ -1127,61 +1142,100 @@ export function transformToWhere(mongoQuery) {
|
|
1127
1142
|
result[newKey] = isObject(value) ? transformToWhere(value) : value;
|
1128
1143
|
});
|
1129
1144
|
}
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
? value[index]
|
1141
|
-
?.replaceAll(!isInputField ? `{{{${field}}}}` : `{{{input.${field}}}}`, fieldValue ?? '')
|
1142
|
-
.trim() || undefined
|
1143
|
-
: value ?? undefined;
|
1144
|
-
}
|
1145
|
-
}
|
1146
|
-
}
|
1147
|
-
else if (isObject(value)) {
|
1148
|
-
updateCriteriaInputs(value, field, fieldValue, isInputField);
|
1145
|
+
function compileQueryValues(query, data) {
|
1146
|
+
if ('rules' in query && Array.isArray(query.rules)) {
|
1147
|
+
const updatedRules = query.rules
|
1148
|
+
.map((item) => compileQueryValues(item, data))
|
1149
|
+
.filter((item) => item !== undefined);
|
1150
|
+
if (updatedRules?.length) {
|
1151
|
+
return {
|
1152
|
+
...query,
|
1153
|
+
rules: updatedRules,
|
1154
|
+
};
|
1149
1155
|
}
|
1150
1156
|
else {
|
1151
|
-
|
1152
|
-
typeof value === 'string'
|
1153
|
-
? value
|
1154
|
-
?.replaceAll(!isInputField ? `{{{${field}}}}` : `{{{input.${field}}}}`, fieldValue ?? '')
|
1155
|
-
.trim() || undefined
|
1156
|
-
: value ?? undefined;
|
1157
|
+
return undefined;
|
1157
1158
|
}
|
1158
1159
|
}
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
inputProps && result.push(...inputProps);
|
1172
|
-
}
|
1160
|
+
else {
|
1161
|
+
if ('value' in query && typeof query.value === 'string') {
|
1162
|
+
const template = Handlebars.compileAST(query.value);
|
1163
|
+
const result = template(data);
|
1164
|
+
if (result !== '') {
|
1165
|
+
return {
|
1166
|
+
...query,
|
1167
|
+
value: result,
|
1168
|
+
};
|
1169
|
+
}
|
1170
|
+
else {
|
1171
|
+
return undefined;
|
1173
1172
|
}
|
1174
1173
|
}
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
}
|
1174
|
+
return query;
|
1175
|
+
}
|
1176
|
+
}
|
1177
|
+
export function updateCriteriaInputs(criteria, data, user) {
|
1178
|
+
const dataSet = {
|
1179
|
+
input: {
|
1180
|
+
...data,
|
1181
|
+
},
|
1182
|
+
user: user,
|
1183
|
+
};
|
1184
|
+
const compiledQuery = compileQueryValues(parseMongoDB(criteria), dataSet);
|
1185
|
+
// The "compiledQueryValues" function filters out rules that have a value of "undefined".
|
1186
|
+
// If "compiledQuery" is "undefined", that means that all rules and nested rules have a value of "undefined".
|
1187
|
+
// Therefore, the resulting query is empty.
|
1188
|
+
return !compiledQuery
|
1189
|
+
? {}
|
1190
|
+
: JSON.parse(formatQuery(compiledQuery, {
|
1191
|
+
format: 'mongodb',
|
1192
|
+
ruleProcessor: (rule, options) => {
|
1193
|
+
let updatedRule = rule;
|
1194
|
+
if (['contains', 'beginsWith', 'endsWith'].includes(rule.operator)) {
|
1195
|
+
updatedRule = { ...rule, value: escape(rule.value) };
|
1196
|
+
}
|
1197
|
+
return defaultRuleProcessorMongoDB(updatedRule, options);
|
1198
|
+
},
|
1199
|
+
}));
|
1200
|
+
}
|
1201
|
+
function getRuleValues(query) {
|
1202
|
+
const values = [];
|
1203
|
+
if ('rules' in query && Array.isArray(query.rules)) {
|
1204
|
+
query.rules.forEach((item) => {
|
1205
|
+
values.push(...getRuleValues(item));
|
1206
|
+
});
|
1207
|
+
}
|
1208
|
+
else {
|
1209
|
+
values.push(query.value);
|
1210
|
+
}
|
1211
|
+
return values;
|
1212
|
+
}
|
1213
|
+
export function getCriteriaInputs(criteria) {
|
1214
|
+
if (!criteria)
|
1215
|
+
return [];
|
1216
|
+
const values = getRuleValues(parseMongoDB(criteria)).filter((val) => typeof val === 'string' && val.match(/{{{input\..*}}}/g));
|
1217
|
+
return uniq(values).map((item) => item.replace('{{{input.', '').replace('}}}', ''));
|
1218
|
+
}
|
1219
|
+
export function getAllCriteriaInputs(components) {
|
1220
|
+
const allComponents = components;
|
1221
|
+
const results = allComponents.reduce((inputs, c) => inputs.concat(getCriteriaInputs(c.validate?.criteria ??
|
1222
|
+
c.validation?.criteria)), []);
|
1223
|
+
return results;
|
1224
|
+
}
|
1225
|
+
export async function populateInstanceWithNestedData(instanceId, objectId, paths, apiServices) {
|
1226
|
+
let instance = { id: instanceId, objectId };
|
1227
|
+
try {
|
1228
|
+
instance = await apiServices.get(getPrefixedUrl(`/objects/${objectId}/instances/${instanceId}`), {
|
1229
|
+
params: {
|
1230
|
+
expand: paths,
|
1231
|
+
},
|
1232
|
+
paramsSerializer: (params) => qs.stringify(params, { arrayFormat: 'repeat' }),
|
1233
|
+
});
|
1234
|
+
}
|
1235
|
+
catch (err) {
|
1236
|
+
console.log(err);
|
1183
1237
|
}
|
1184
|
-
return
|
1238
|
+
return instance;
|
1185
1239
|
}
|
1186
1240
|
export function isPropertyVisible(conditional, formData) {
|
1187
1241
|
const isConditional = !!conditional?.when;
|
@@ -1232,3 +1286,72 @@ export function normalizeDates(instances, object) {
|
|
1232
1286
|
});
|
1233
1287
|
});
|
1234
1288
|
}
|
1289
|
+
/**
|
1290
|
+
* Given an object entry in a JsonLogic object, map it to the correct value.
|
1291
|
+
* @param entry An entry in a JsonLogic object.
|
1292
|
+
* @returns entry with all values starting with "instance" replaced with "data._instance"
|
1293
|
+
*/
|
1294
|
+
function processJsonLogicEntry(entry) {
|
1295
|
+
if (entry !== Object(entry)) {
|
1296
|
+
// entry is a primitive
|
1297
|
+
return typeof entry === 'string' ? entry.replace(/^instance/, 'data._instance') : entry;
|
1298
|
+
}
|
1299
|
+
else if (isArray(entry)) {
|
1300
|
+
return entry.map((element) => processJsonLogicEntry(element));
|
1301
|
+
}
|
1302
|
+
else if (typeof entry === 'object' && entry !== null) {
|
1303
|
+
let result = {};
|
1304
|
+
const entries = Object.entries(entry);
|
1305
|
+
for (const [key, val] of entries) {
|
1306
|
+
result = {
|
1307
|
+
...result,
|
1308
|
+
[key]: processJsonLogicEntry(val),
|
1309
|
+
};
|
1310
|
+
}
|
1311
|
+
return result;
|
1312
|
+
}
|
1313
|
+
return entry;
|
1314
|
+
}
|
1315
|
+
/**
|
1316
|
+
* Given a JsonLogic, replace all keys (if any) starting with "instance" with
|
1317
|
+
* "data._instance".
|
1318
|
+
*
|
1319
|
+
* @param jsonLogic A JsonLogic instance.
|
1320
|
+
* @returns jsonLogic, with all keys starting with "instance" replaced with "data._instance".
|
1321
|
+
*/
|
1322
|
+
function normalizeInstanceDataInJsonLogic(jsonLogic) {
|
1323
|
+
if (typeof jsonLogic === 'object' && jsonLogic !== null) {
|
1324
|
+
// jsonLogic is a Record<string, unknown>
|
1325
|
+
let result = {};
|
1326
|
+
const entries = Object.entries(jsonLogic);
|
1327
|
+
for (const [key, entry] of entries) {
|
1328
|
+
result = {
|
1329
|
+
...result,
|
1330
|
+
[key]: processJsonLogicEntry(entry),
|
1331
|
+
};
|
1332
|
+
}
|
1333
|
+
return result;
|
1334
|
+
}
|
1335
|
+
// jsonLogic is a primitive
|
1336
|
+
return jsonLogic;
|
1337
|
+
}
|
1338
|
+
/**
|
1339
|
+
*
|
1340
|
+
* @param visibility A form's visibility entry.
|
1341
|
+
* @returns The form's visibility entry, converted to formio-readable form.
|
1342
|
+
*/
|
1343
|
+
function convertVisibilityToConditional(visibility) {
|
1344
|
+
if (isObject(visibility) && 'conditions' in visibility && isArray(visibility.conditions)) {
|
1345
|
+
const [condition] = visibility.conditions;
|
1346
|
+
return {
|
1347
|
+
show: condition.operator === 'eq',
|
1348
|
+
when: condition.isInstanceProperty ? `_instance.${condition.property}` : condition.property,
|
1349
|
+
eq: condition.value,
|
1350
|
+
};
|
1351
|
+
}
|
1352
|
+
return visibility
|
1353
|
+
? {
|
1354
|
+
json: normalizeInstanceDataInJsonLogic(visibility),
|
1355
|
+
}
|
1356
|
+
: undefined;
|
1357
|
+
}
|
package/dist/published/components/custom/FormField/AddressFieldComponent/addressFieldComponent.js
CHANGED
@@ -58,7 +58,7 @@ const AddressFieldComponent = (props) => {
|
|
58
58
|
backgroundColor: '#f4f6f8',
|
59
59
|
},
|
60
60
|
}
|
61
|
-
: undefined, required: required, error: error, errorMessage: errorMessage, InputProps: { readOnly: readOnly }, fullWidth: true, size: size ?? 'medium', type: 'text', multiline: property.type === 'string' && !readOnly && isMultiLineText, rows: isMultiLineText ? rows ?? 3 : undefined, value: value, ...(additionalProps ?? {}) })
|
61
|
+
: undefined, required: required, error: error, errorMessage: errorMessage, InputProps: { readOnly: readOnly }, fullWidth: true, size: size ?? 'medium', type: 'text', multiline: property.type === 'string' && !readOnly && isMultiLineText, rows: isMultiLineText ? (rows ?? 3) : undefined, value: value, ...(additionalProps ?? {}) })
|
62
62
|
// Casting to `React.ReactNode` is necessary to resolve TypeScript errors
|
63
63
|
// due to compatibility issues with the outdated `react-input-mask` version
|
64
64
|
// and the newer `@types/react` package.
|
@@ -1,8 +1,9 @@
|
|
1
|
-
import { Property } from '@evoke-platform/context';
|
1
|
+
import { Obj, Property } from '@evoke-platform/context';
|
2
2
|
import React from 'react';
|
3
3
|
type DisplayedPropertyProps = {
|
4
4
|
property: Property;
|
5
5
|
value: unknown;
|
6
|
+
referencedObject?: Obj;
|
6
7
|
};
|
7
8
|
declare const DisplayedProperty: (props: DisplayedPropertyProps) => React.JSX.Element;
|
8
9
|
export default DisplayedProperty;
|
@@ -2,9 +2,10 @@ import { DateTime } from 'luxon';
|
|
2
2
|
import React from 'react';
|
3
3
|
import { CardMedia, Typography } from '../../core';
|
4
4
|
import { Grid } from '../../layout';
|
5
|
+
import { getReadableQuery } from '../CriteriaBuilder';
|
5
6
|
import { RichTextViewer } from '../RichTextViewer';
|
6
7
|
const DisplayedProperty = (props) => {
|
7
|
-
const { property, value } = props;
|
8
|
+
const { property, value, referencedObject } = props;
|
8
9
|
const getAddressAsString = (address) => {
|
9
10
|
let stringAddress = '';
|
10
11
|
if (address?.line1)
|
@@ -22,7 +23,7 @@ const DisplayedProperty = (props) => {
|
|
22
23
|
return stringAddress;
|
23
24
|
};
|
24
25
|
const formatData = (property, value) => {
|
25
|
-
if (property?.objectId) {
|
26
|
+
if (property?.objectId && property?.type === 'object') {
|
26
27
|
return value?.name ?? value?.id;
|
27
28
|
}
|
28
29
|
switch (property?.type) {
|
@@ -47,6 +48,8 @@ const DisplayedProperty = (props) => {
|
|
47
48
|
return value ? DateTime.fromISO(value).toFormat('MM/dd/yyyy hh:mm a') : undefined;
|
48
49
|
case 'document':
|
49
50
|
return value && Array.isArray(value) ? value.map((v) => v.name).join(', ') : undefined;
|
51
|
+
case 'criteria':
|
52
|
+
return getReadableQuery(value ?? {}, referencedObject?.properties);
|
50
53
|
}
|
51
54
|
return value;
|
52
55
|
};
|
@@ -30,7 +30,7 @@ const styles = {
|
|
30
30
|
},
|
31
31
|
};
|
32
32
|
const HistoricalData = (props) => {
|
33
|
-
const { records, documentHistory, object } = props;
|
33
|
+
const { records, documentHistory, object, referencedObjects } = props;
|
34
34
|
const getPastDocumentVersion = (history) => {
|
35
35
|
const documentVersions = documentHistory?.[history.subject?.id ?? 'unknown'] ?? [];
|
36
36
|
const currentVersion = documentVersions?.map((v) => v.timestamp).indexOf(history.timestamp);
|
@@ -65,11 +65,17 @@ const HistoricalData = (props) => {
|
|
65
65
|
fontWeight: 600,
|
66
66
|
minWidth: 'fit-content',
|
67
67
|
alignSelf: 'flex-start',
|
68
|
+
lineHeight: '17px',
|
69
|
+
padding: '3px 8px',
|
68
70
|
} }, property.name)),
|
69
|
-
React.createElement(DisplayedProperty, { property: property, value: d.historicalValue
|
71
|
+
React.createElement(DisplayedProperty, { property: property, value: d.historicalValue, referencedObject: property.objectId
|
72
|
+
? referencedObjects?.find((o) => o.id === property.objectId)
|
73
|
+
: undefined }),
|
70
74
|
React.createElement(Grid, { item: true, xs: 0.5 },
|
71
75
|
React.createElement(ArrowForward, { sx: { fontSize: '12px' } })),
|
72
|
-
React.createElement(DisplayedProperty, { property: property, value: d.updatedValue
|
76
|
+
React.createElement(DisplayedProperty, { property: property, value: d.updatedValue, referencedObject: property.objectId
|
77
|
+
? referencedObjects?.find((o) => o.id === property.objectId)
|
78
|
+
: undefined }))));
|
73
79
|
}))),
|
74
80
|
['document', 'correspondence'].includes(r.type) && (React.createElement(Box, null,
|
75
81
|
React.createElement(Box, { display: "grid", gridTemplateColumns: 'fit-content(100%) fit-content(2%) fit-content(100%)', alignItems: "center", sx: { overflowWrap: 'break-word' } },
|
@@ -1,6 +1,9 @@
|
|
1
|
+
import { useApiServices } from '@evoke-platform/context';
|
1
2
|
import { Circle } from '@mui/icons-material';
|
3
|
+
import { uniq } from 'lodash';
|
2
4
|
import { DateTime } from 'luxon';
|
3
5
|
import React, { useEffect, useState } from 'react';
|
6
|
+
import { Snackbar } from '../../core';
|
4
7
|
import Typography from '../../core/Typography';
|
5
8
|
import Box from '../../layout/Box';
|
6
9
|
import HistoryFilter from './Filter';
|
@@ -20,9 +23,27 @@ export const HistoryLog = (props) => {
|
|
20
23
|
const { object, history, loading, title } = props;
|
21
24
|
const [historyMap, setHistoryMap] = useState({});
|
22
25
|
const [documentHistory, setDocumentHistory] = useState({});
|
26
|
+
const [referencedObjects, setReferencedObjects] = useState([]);
|
23
27
|
const [filteredHistory, setFilteredHistory] = useState({});
|
24
28
|
const [filter, setFilter] = useState([]);
|
25
29
|
const [order, setOrder] = useState('desc');
|
30
|
+
const [showSnackbar, setShowSnackbar] = useState(false);
|
31
|
+
const apiServices = useApiServices();
|
32
|
+
useEffect(() => {
|
33
|
+
const criteriaProperties = object.properties?.filter((property) => property.type === 'criteria');
|
34
|
+
if (criteriaProperties?.length) {
|
35
|
+
const uniqueObjectIds = uniq(criteriaProperties?.map((property) => property.objectId));
|
36
|
+
Promise.all(uniqueObjectIds.map((objectId) => apiServices.get(`/data/objects/${objectId}/effective`, {
|
37
|
+
params: {
|
38
|
+
filter: {
|
39
|
+
fields: ['id', 'name', 'properties'],
|
40
|
+
},
|
41
|
+
},
|
42
|
+
})))
|
43
|
+
.then((objs) => setReferencedObjects(objs))
|
44
|
+
.catch(() => setShowSnackbar(true));
|
45
|
+
}
|
46
|
+
}, [object, apiServices]);
|
26
47
|
const sortHistoryByTimestamp = (historicalData, order) => {
|
27
48
|
return historicalData.sort((a, b) => order === 'desc' ? b.timestamp.localeCompare(a.timestamp) : a.timestamp.localeCompare(b.timestamp));
|
28
49
|
};
|
@@ -78,13 +99,14 @@ export const HistoryLog = (props) => {
|
|
78
99
|
' ',
|
79
100
|
"\u00A0"),
|
80
101
|
React.createElement(Typography, { sx: { fontWeight: 600, fontSize: '16px', color: '#637381' } }, format(new Date(date + ' 00:00:000'), 'MMM dd, yyyy'))),
|
81
|
-
React.createElement(HistoricalData, { object: object, records: records, documentHistory: documentHistory })));
|
102
|
+
React.createElement(HistoricalData, { object: object, records: records, documentHistory: documentHistory, referencedObjects: referencedObjects })));
|
82
103
|
}
|
83
104
|
return null;
|
84
105
|
}),
|
85
106
|
!loading && filteredHistory && Object.values(filteredHistory).every((v) => !v.length) && (React.createElement(Box, { width: '100%', display: 'grid', justifyContent: 'center', marginTop: '60px' },
|
86
107
|
React.createElement(Typography, { fontSize: '20px', fontWeight: 700 }, "You Have No History"),
|
87
108
|
React.createElement(Typography, { fontSize: '14px', fontWeight: 400 }, "Try modifying the history type."))),
|
88
|
-
loading && React.createElement(HistoryLoading, null)
|
109
|
+
loading && React.createElement(HistoryLoading, null),
|
110
|
+
React.createElement(Snackbar, { open: showSnackbar, handleClose: () => setShowSnackbar(false), message: 'Error occurred when loading referenced objects', error: true })));
|
89
111
|
};
|
90
112
|
export default HistoryLog;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
export { BuilderGrid } from './BuilderGrid';
|
2
|
-
export { CriteriaBuilder } from './CriteriaBuilder';
|
2
|
+
export { CriteriaBuilder, getReadableQuery } from './CriteriaBuilder';
|
3
3
|
export { DataGrid } from './DataGrid';
|
4
4
|
export { ErrorComponent } from './ErrorComponent';
|
5
5
|
export { Form } from './Form';
|
@@ -1,5 +1,5 @@
|
|
1
1
|
export { BuilderGrid } from './BuilderGrid';
|
2
|
-
export { CriteriaBuilder } from './CriteriaBuilder';
|
2
|
+
export { CriteriaBuilder, getReadableQuery } from './CriteriaBuilder';
|
3
3
|
export { DataGrid } from './DataGrid';
|
4
4
|
export { ErrorComponent } from './ErrorComponent';
|
5
5
|
export { Form } from './Form';
|
@@ -2,7 +2,7 @@ export { ClickAwayListener, createTheme, darken, lighten, styled, Toolbar } from
|
|
2
2
|
export { CalendarPicker, DateTimePicker, MonthPicker, PickersDay, StaticDateTimePicker, StaticTimePicker, TimePicker, YearPicker, } from '@mui/x-date-pickers';
|
3
3
|
export * from './colors';
|
4
4
|
export * from './components/core';
|
5
|
-
export { BuilderGrid, CriteriaBuilder, DataGrid, ErrorComponent, Form, FormField, HistoryLog, MenuBar, MultiSelect, RepeatableField, RichTextViewer, UserAvatar, } from './components/custom';
|
5
|
+
export { BuilderGrid, CriteriaBuilder, DataGrid, ErrorComponent, Form, FormField, getReadableQuery, HistoryLog, MenuBar, MultiSelect, RepeatableField, RichTextViewer, UserAvatar, } from './components/custom';
|
6
6
|
export type { FormRef } from './components/custom';
|
7
7
|
export { NumericFormat } from './components/custom/FormField/InputFieldComponent';
|
8
8
|
export { Box, Container, Grid, Stack } from './components/layout';
|
package/dist/published/index.js
CHANGED
@@ -2,7 +2,7 @@ export { ClickAwayListener, createTheme, darken, lighten, styled, Toolbar } from
|
|
2
2
|
export { CalendarPicker, DateTimePicker, MonthPicker, PickersDay, StaticDateTimePicker, StaticTimePicker, TimePicker, YearPicker, } from '@mui/x-date-pickers';
|
3
3
|
export * from './colors';
|
4
4
|
export * from './components/core';
|
5
|
-
export { BuilderGrid, CriteriaBuilder, DataGrid, ErrorComponent, Form, FormField, HistoryLog, MenuBar, MultiSelect, RepeatableField, RichTextViewer, UserAvatar, } from './components/custom';
|
5
|
+
export { BuilderGrid, CriteriaBuilder, DataGrid, ErrorComponent, Form, FormField, getReadableQuery, HistoryLog, MenuBar, MultiSelect, RepeatableField, RichTextViewer, UserAvatar, } from './components/custom';
|
6
6
|
export { NumericFormat } from './components/custom/FormField/InputFieldComponent';
|
7
7
|
export { Box, Container, Grid, Stack } from './components/layout';
|
8
8
|
export * from './theme';
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@evoke-platform/ui-components",
|
3
|
-
"version": "1.4.0-testing.
|
3
|
+
"version": "1.4.0-testing.11",
|
4
4
|
"description": "",
|
5
5
|
"main": "dist/published/index.js",
|
6
6
|
"module": "dist/published/index.js",
|
@@ -51,7 +51,6 @@
|
|
51
51
|
"@testing-library/jest-dom": "^6.4.2",
|
52
52
|
"@testing-library/react": "^14.2.2",
|
53
53
|
"@testing-library/user-event": "^14.5.2",
|
54
|
-
"@types/dot-object": "^2.1.6",
|
55
54
|
"@types/flat": "^5.0.5",
|
56
55
|
"@types/jest": "^28.1.4",
|
57
56
|
"@types/luxon": "^3.4.2",
|
@@ -95,7 +94,7 @@
|
|
95
94
|
"@dnd-kit/sortable": "^7.0.1",
|
96
95
|
"@emotion/react": "^11.13.5",
|
97
96
|
"@emotion/styled": "^11.8.1",
|
98
|
-
"@evoke-platform/context": "^1.1.0-testing.
|
97
|
+
"@evoke-platform/context": "^1.1.0-testing.4",
|
99
98
|
"@formio/react": "^5.2.4-rc.1",
|
100
99
|
"@js-joda/core": "^3.2.0",
|
101
100
|
"@js-joda/locale_en-us": "^3.2.2",
|
@@ -111,12 +110,12 @@
|
|
111
110
|
"devexpress-richedit": "^23.1.5",
|
112
111
|
"devextreme": "^23.1.5",
|
113
112
|
"devextreme-dist": "^23.1.5",
|
114
|
-
"dot-object": "^2.1.5",
|
115
113
|
"eslint-plugin-no-inline-styles": "^1.0.5",
|
116
114
|
"flat": "^6.0.1",
|
117
115
|
"formiojs": "^4.15.0-rc.23",
|
118
116
|
"html-react-parser": "^5.1.18",
|
119
117
|
"luxon": "^2.5.2",
|
118
|
+
"msw": "^2.7.3",
|
120
119
|
"nanoid": "^5.0.8",
|
121
120
|
"nanoid-dictionary": "^4.3.0",
|
122
121
|
"no-eval-handlebars": "^1.0.2",
|