@evoke-platform/ui-components 1.3.0-testing.0 → 1.4.0-dev.0
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 +23 -8
- 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/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 +206 -90
- package/dist/published/components/custom/FormField/AddressFieldComponent/addressFieldComponent.js +6 -2
- package/dist/published/components/custom/FormField/InputFieldComponent/InputFieldComponent.js +6 -2
- 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/Menubar/Menubar.d.ts +2 -3
- package/dist/published/components/custom/Menubar/Menubar.js +15 -12
- 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 +3 -2
- package/dist/published/index.js +3 -2
- package/dist/published/theme/hooks.d.ts +31 -0
- package/dist/published/theme/hooks.js +35 -0
- package/dist/published/theme/index.d.ts +3 -0
- package/dist/published/theme/index.js +3 -0
- package/package.json +4 -5
@@ -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,24 @@ 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
|
+
}
|
652
648
|
return {
|
653
649
|
...component,
|
654
650
|
...(component.type === 'Object' && objectPropertyInputProps),
|
655
651
|
type: `${readOnly ? 'ViewOnly' : ''}${component.type}`,
|
656
652
|
defaultValue,
|
653
|
+
allCriteriaInputs,
|
654
|
+
properties,
|
657
655
|
property,
|
656
|
+
associatedObject,
|
658
657
|
readOnly: component.readOnly || readOnly || property?.formula,
|
659
658
|
multiple: ['array', 'document'].includes(property.type),
|
660
659
|
instance: instance,
|
@@ -693,7 +692,7 @@ formComponents, instance, objectPropertyInputProps, autoSave, readOnly, defaultP
|
|
693
692
|
}
|
694
693
|
if (component.columns) {
|
695
694
|
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);
|
695
|
+
column.components = await addObjectPropertiesToComponentProps(properties, column.components, allCriteriaInputs, instance, objectPropertyInputProps, associatedObject, autoSave, readOnly, undefined, undefined, queryAddresses, apiServices, isModal, fieldHeight, richTextEditor);
|
697
696
|
}
|
698
697
|
return component;
|
699
698
|
}
|
@@ -713,6 +712,14 @@ formComponents, instance, objectPropertyInputProps, autoSave, readOnly, defaultP
|
|
713
712
|
if (item.type.includes('RepeatableField') && !!instance) {
|
714
713
|
item.instance = instance;
|
715
714
|
}
|
715
|
+
// If "associatedObject" is defined, that means the form is associating an existing instance with the current instance.
|
716
|
+
// Set the associated instance as a default value and hide the field.
|
717
|
+
if (associatedObject?.instanceId &&
|
718
|
+
associatedObject?.propertyId &&
|
719
|
+
item.property.id === associatedObject.propertyId) {
|
720
|
+
item.defaultValue = { id: associatedObject.instanceId };
|
721
|
+
item.hidden = true;
|
722
|
+
}
|
716
723
|
}
|
717
724
|
if (nestedFieldProperty) {
|
718
725
|
item.type = `${readOnly ? 'ViewOnly' : ''}${item.type}`;
|
@@ -725,6 +732,7 @@ formComponents, instance, objectPropertyInputProps, autoSave, readOnly, defaultP
|
|
725
732
|
item.user = objectPropertyInputProps?.user;
|
726
733
|
item.defaultPages = defaultPages;
|
727
734
|
item.navigateTo = navigateTo;
|
735
|
+
item.allCriteriaInputs = allCriteriaInputs;
|
728
736
|
item.isModal = isModal;
|
729
737
|
item.fieldHeight = fieldHeight;
|
730
738
|
item.richTextEditor = ['RepeatableField', 'Object'].includes(item.type)
|
@@ -751,7 +759,7 @@ formComponents, instance, objectPropertyInputProps, autoSave, readOnly, defaultP
|
|
751
759
|
}
|
752
760
|
}
|
753
761
|
return {
|
754
|
-
components: await addObjectPropertiesToComponentProps(properties, component.components, instance, objectPropertyInputProps, autoSave, readOnly, defaultPages, navigateTo, queryAddresses, apiServices, isModal, fieldHeight, richTextEditor),
|
762
|
+
components: await addObjectPropertiesToComponentProps(properties, component.components, allCriteriaInputs, instance, objectPropertyInputProps, associatedObject, autoSave, readOnly, defaultPages, navigateTo, queryAddresses, apiServices, isModal, fieldHeight, richTextEditor),
|
755
763
|
...component,
|
756
764
|
...(component.type === 'Object' && objectPropertyInputProps),
|
757
765
|
type: `${readOnly ? 'ViewOnly' : ''}${component.type}`,
|
@@ -1127,61 +1135,100 @@ export function transformToWhere(mongoQuery) {
|
|
1127
1135
|
result[newKey] = isObject(value) ? transformToWhere(value) : value;
|
1128
1136
|
});
|
1129
1137
|
}
|
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);
|
1138
|
+
function compileQueryValues(query, data) {
|
1139
|
+
if ('rules' in query && Array.isArray(query.rules)) {
|
1140
|
+
const updatedRules = query.rules
|
1141
|
+
.map((item) => compileQueryValues(item, data))
|
1142
|
+
.filter((item) => item !== undefined);
|
1143
|
+
if (updatedRules?.length) {
|
1144
|
+
return {
|
1145
|
+
...query,
|
1146
|
+
rules: updatedRules,
|
1147
|
+
};
|
1149
1148
|
}
|
1150
1149
|
else {
|
1151
|
-
|
1152
|
-
typeof value === 'string'
|
1153
|
-
? value
|
1154
|
-
?.replaceAll(!isInputField ? `{{{${field}}}}` : `{{{input.${field}}}}`, fieldValue ?? '')
|
1155
|
-
.trim() || undefined
|
1156
|
-
: value ?? undefined;
|
1150
|
+
return undefined;
|
1157
1151
|
}
|
1158
1152
|
}
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
inputProps && result.push(...inputProps);
|
1172
|
-
}
|
1153
|
+
else {
|
1154
|
+
if ('value' in query && typeof query.value === 'string') {
|
1155
|
+
const template = Handlebars.compileAST(query.value);
|
1156
|
+
const result = template(data);
|
1157
|
+
if (result !== '') {
|
1158
|
+
return {
|
1159
|
+
...query,
|
1160
|
+
value: result,
|
1161
|
+
};
|
1162
|
+
}
|
1163
|
+
else {
|
1164
|
+
return undefined;
|
1173
1165
|
}
|
1174
1166
|
}
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
}
|
1167
|
+
return query;
|
1168
|
+
}
|
1169
|
+
}
|
1170
|
+
export function updateCriteriaInputs(criteria, data, user) {
|
1171
|
+
const dataSet = {
|
1172
|
+
input: {
|
1173
|
+
...data,
|
1174
|
+
},
|
1175
|
+
user: user,
|
1176
|
+
};
|
1177
|
+
const compiledQuery = compileQueryValues(parseMongoDB(criteria), dataSet);
|
1178
|
+
// The "compiledQueryValues" function filters out rules that have a value of "undefined".
|
1179
|
+
// If "compiledQuery" is "undefined", that means that all rules and nested rules have a value of "undefined".
|
1180
|
+
// Therefore, the resulting query is empty.
|
1181
|
+
return !compiledQuery
|
1182
|
+
? {}
|
1183
|
+
: JSON.parse(formatQuery(compiledQuery, {
|
1184
|
+
format: 'mongodb',
|
1185
|
+
ruleProcessor: (rule, options) => {
|
1186
|
+
let updatedRule = rule;
|
1187
|
+
if (['contains', 'beginsWith', 'endsWith'].includes(rule.operator)) {
|
1188
|
+
updatedRule = { ...rule, value: escape(rule.value) };
|
1189
|
+
}
|
1190
|
+
return defaultRuleProcessorMongoDB(updatedRule, options);
|
1191
|
+
},
|
1192
|
+
}));
|
1193
|
+
}
|
1194
|
+
function getRuleValues(query) {
|
1195
|
+
const values = [];
|
1196
|
+
if ('rules' in query && Array.isArray(query.rules)) {
|
1197
|
+
query.rules.forEach((item) => {
|
1198
|
+
values.push(...getRuleValues(item));
|
1199
|
+
});
|
1200
|
+
}
|
1201
|
+
else {
|
1202
|
+
values.push(query.value);
|
1203
|
+
}
|
1204
|
+
return values;
|
1205
|
+
}
|
1206
|
+
export function getCriteriaInputs(criteria) {
|
1207
|
+
if (!criteria)
|
1208
|
+
return [];
|
1209
|
+
const values = getRuleValues(parseMongoDB(criteria)).filter((val) => typeof val === 'string' && val.match(/{{{input\..*}}}/g));
|
1210
|
+
return uniq(values).map((item) => item.replace('{{{input.', '').replace('}}}', ''));
|
1211
|
+
}
|
1212
|
+
export function getAllCriteriaInputs(components) {
|
1213
|
+
const allComponents = components;
|
1214
|
+
const results = allComponents.reduce((inputs, c) => inputs.concat(getCriteriaInputs(c.validate?.criteria ??
|
1215
|
+
c.validation?.criteria)), []);
|
1216
|
+
return results;
|
1217
|
+
}
|
1218
|
+
export async function populateInstanceWithNestedData(instanceId, objectId, paths, apiServices) {
|
1219
|
+
let instance = { id: instanceId, objectId };
|
1220
|
+
try {
|
1221
|
+
instance = await apiServices.get(getPrefixedUrl(`/objects/${objectId}/instances/${instanceId}`), {
|
1222
|
+
params: {
|
1223
|
+
expand: paths,
|
1224
|
+
},
|
1225
|
+
paramsSerializer: (params) => qs.stringify(params, { arrayFormat: 'repeat' }),
|
1226
|
+
});
|
1227
|
+
}
|
1228
|
+
catch (err) {
|
1229
|
+
console.log(err);
|
1183
1230
|
}
|
1184
|
-
return
|
1231
|
+
return instance;
|
1185
1232
|
}
|
1186
1233
|
export function isPropertyVisible(conditional, formData) {
|
1187
1234
|
const isConditional = !!conditional?.when;
|
@@ -1232,3 +1279,72 @@ export function normalizeDates(instances, object) {
|
|
1232
1279
|
});
|
1233
1280
|
});
|
1234
1281
|
}
|
1282
|
+
/**
|
1283
|
+
* Given an object entry in a JsonLogic object, map it to the correct value.
|
1284
|
+
* @param entry An entry in a JsonLogic object.
|
1285
|
+
* @returns entry with all values starting with "instance" replaced with "data._instance"
|
1286
|
+
*/
|
1287
|
+
function processJsonLogicEntry(entry) {
|
1288
|
+
if (entry !== Object(entry)) {
|
1289
|
+
// entry is a primitive
|
1290
|
+
return typeof entry === 'string' ? entry.replace(/^instance/, 'data._instance') : entry;
|
1291
|
+
}
|
1292
|
+
else if (isArray(entry)) {
|
1293
|
+
return entry.map((element) => processJsonLogicEntry(element));
|
1294
|
+
}
|
1295
|
+
else if (typeof entry === 'object' && entry !== null) {
|
1296
|
+
let result = {};
|
1297
|
+
const entries = Object.entries(entry);
|
1298
|
+
for (const [key, val] of entries) {
|
1299
|
+
result = {
|
1300
|
+
...result,
|
1301
|
+
[key]: processJsonLogicEntry(val),
|
1302
|
+
};
|
1303
|
+
}
|
1304
|
+
return result;
|
1305
|
+
}
|
1306
|
+
return entry;
|
1307
|
+
}
|
1308
|
+
/**
|
1309
|
+
* Given a JsonLogic, replace all keys (if any) starting with "instance" with
|
1310
|
+
* "data._instance".
|
1311
|
+
*
|
1312
|
+
* @param jsonLogic A JsonLogic instance.
|
1313
|
+
* @returns jsonLogic, with all keys starting with "instance" replaced with "data._instance".
|
1314
|
+
*/
|
1315
|
+
function normalizeInstanceDataInJsonLogic(jsonLogic) {
|
1316
|
+
if (typeof jsonLogic === 'object' && jsonLogic !== null) {
|
1317
|
+
// jsonLogic is a Record<string, unknown>
|
1318
|
+
let result = {};
|
1319
|
+
const entries = Object.entries(jsonLogic);
|
1320
|
+
for (const [key, entry] of entries) {
|
1321
|
+
result = {
|
1322
|
+
...result,
|
1323
|
+
[key]: processJsonLogicEntry(entry),
|
1324
|
+
};
|
1325
|
+
}
|
1326
|
+
return result;
|
1327
|
+
}
|
1328
|
+
// jsonLogic is a primitive
|
1329
|
+
return jsonLogic;
|
1330
|
+
}
|
1331
|
+
/**
|
1332
|
+
*
|
1333
|
+
* @param visibility A form's visibility entry.
|
1334
|
+
* @returns The form's visibility entry, converted to formio-readable form.
|
1335
|
+
*/
|
1336
|
+
function convertVisibilityToConditional(visibility) {
|
1337
|
+
if (isObject(visibility) && 'conditions' in visibility && isArray(visibility.conditions)) {
|
1338
|
+
const [condition] = visibility.conditions;
|
1339
|
+
return {
|
1340
|
+
show: condition.operator === 'eq',
|
1341
|
+
when: condition.isInstanceProperty ? `_instance.${condition.property}` : condition.property,
|
1342
|
+
eq: condition.value,
|
1343
|
+
};
|
1344
|
+
}
|
1345
|
+
return visibility
|
1346
|
+
? {
|
1347
|
+
json: normalizeInstanceDataInJsonLogic(visibility),
|
1348
|
+
}
|
1349
|
+
: undefined;
|
1350
|
+
}
|
package/dist/published/components/custom/FormField/AddressFieldComponent/addressFieldComponent.js
CHANGED
@@ -48,7 +48,7 @@ const AddressFieldComponent = (props) => {
|
|
48
48
|
!mask ? (React.createElement(TextField, { id: id, inputRef: textFieldRef, onChange: !readOnly ? handleChange : undefined, error: error, errorMessage: errorMessage, value: value, fullWidth: true, onBlur: onBlur, size: size ?? 'medium', placeholder: placeholder, InputProps: {
|
49
49
|
type: 'search',
|
50
50
|
autoComplete: 'off',
|
51
|
-
}, required: required, readOnly: readOnly, multiline: property.type === 'string' && !readOnly && isMultiLineText, rows: isMultiLineText ? (rows ? rows : 3) : undefined, ...(additionalProps ?? {}) })) : (React.createElement(InputMask, { mask: mask,
|
51
|
+
}, required: required, readOnly: readOnly, multiline: property.type === 'string' && !readOnly && isMultiLineText, rows: isMultiLineText ? (rows ? rows : 3) : undefined, ...(additionalProps ?? {}) })) : (React.createElement(InputMask, { mask: mask, maskChar: inputMaskPlaceholderChar ?? '_', value: value, onChange: !readOnly ? handleChange : undefined, onBlur: onBlur, alwaysShowMask: true }, (() => (React.createElement(TextField, { id: id, inputRef: textFieldRef, sx: readOnly
|
52
52
|
? {
|
53
53
|
'& .MuiOutlinedInput-notchedOutline': {
|
54
54
|
border: 'none',
|
@@ -58,7 +58,11 @@ const AddressFieldComponent = (props) => {
|
|
58
58
|
backgroundColor: '#f4f6f8',
|
59
59
|
},
|
60
60
|
}
|
61
|
-
: undefined, required: required, error: error, errorMessage: errorMessage, InputProps: {
|
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
|
+
// Casting to `React.ReactNode` is necessary to resolve TypeScript errors
|
63
|
+
// due to compatibility issues with the outdated `react-input-mask` version
|
64
|
+
// and the newer `@types/react` package.
|
65
|
+
)))),
|
62
66
|
!readOnly && (React.createElement(Popover, { id: popoverId, open: open, anchorEl: anchorEl, onClose: handleClose, disableAutoFocus: true, marginThreshold: undefined, anchorOrigin: {
|
63
67
|
vertical: 'bottom',
|
64
68
|
horizontal: 'left',
|
package/dist/published/components/custom/FormField/InputFieldComponent/InputFieldComponent.js
CHANGED
@@ -62,7 +62,7 @@ const InputFieldComponent = (props) => {
|
|
62
62
|
backgroundColor: '#f4f6f8',
|
63
63
|
},
|
64
64
|
}),
|
65
|
-
}, error: error, errorMessage: errorMessage, value: value, onChange: !readOnly ? handleChange : undefined, InputProps: { ...InputProps, readOnly: readOnly }, required: required, fullWidth: true, onBlur: onBlur, placeholder: placeholder, size: size ?? 'medium', type: property.type === 'integer' ? 'number' : 'text', multiline: property.type === 'string' && !readOnly && isMultiLineText, rows: isMultiLineText ? (rows ? rows : 3) : undefined, ...(additionalProps ?? {}) })) : (React.createElement(InputMask, { mask: mask,
|
65
|
+
}, error: error, errorMessage: errorMessage, value: value, onChange: !readOnly ? handleChange : undefined, InputProps: { ...InputProps, readOnly: readOnly }, required: required, fullWidth: true, onBlur: onBlur, placeholder: placeholder, size: size ?? 'medium', type: property.type === 'integer' ? 'number' : 'text', multiline: property.type === 'string' && !readOnly && isMultiLineText, rows: isMultiLineText ? (rows ? rows : 3) : undefined, ...(additionalProps ?? {}) })) : (React.createElement(InputMask, { mask: mask, maskChar: inputMaskPlaceholderChar ?? '_', value: value, onChange: !readOnly ? handleChange : undefined, onBlur: onBlur, alwaysShowMask: true }, (() => (React.createElement(TextField, { id: id, sx: readOnly
|
66
66
|
? {
|
67
67
|
'& .MuiOutlinedInput-notchedOutline': {
|
68
68
|
border: 'none',
|
@@ -72,6 +72,10 @@ const InputFieldComponent = (props) => {
|
|
72
72
|
backgroundColor: '#f4f6f8',
|
73
73
|
},
|
74
74
|
}
|
75
|
-
: undefined, required: required, error: error, errorMessage: errorMessage, InputProps: { ...
|
75
|
+
: undefined, required: required, error: error, errorMessage: errorMessage, InputProps: { ...InputProps, readOnly: readOnly }, fullWidth: true, size: size ?? 'medium', type: property.type === 'integer' ? 'number' : 'text', multiline: property.type === 'string' && !readOnly && isMultiLineText, rows: isMultiLineText ? (rows ? rows : 3) : undefined, ...(additionalProps ?? {}) })
|
76
|
+
// Casting to `React.ReactNode` is necessary to resolve TypeScript errors
|
77
|
+
// due to compatibility issues with the outdated `react-input-mask` version
|
78
|
+
// and the newer `@types/react` package.
|
79
|
+
))));
|
76
80
|
};
|
77
81
|
export default InputFieldComponent;
|
@@ -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,10 +1,9 @@
|
|
1
|
-
import {
|
2
|
-
import React from 'react';
|
1
|
+
import React, { ReactNode } from 'react';
|
3
2
|
export type MenuBarProps = {
|
4
3
|
showNotifications: boolean;
|
5
4
|
logo: string;
|
6
5
|
logoAltText?: string;
|
7
|
-
navItems?:
|
6
|
+
navItems?: ReactNode;
|
8
7
|
envName?: string;
|
9
8
|
};
|
10
9
|
export default function MenuBar(props: MenuBarProps): React.JSX.Element;
|
@@ -1,18 +1,21 @@
|
|
1
1
|
import { AppBar, Box, CardMedia, Toolbar, Typography } from '@mui/material';
|
2
2
|
import React from 'react';
|
3
|
-
import UIThemeProvider from '../../../theme';
|
4
|
-
const classes = {
|
5
|
-
title: {
|
6
|
-
flexGrow: 1,
|
7
|
-
height: 70,
|
8
|
-
},
|
9
|
-
logo: {
|
10
|
-
paddingRight: '16px',
|
11
|
-
height: '70px',
|
12
|
-
width: 'inherit',
|
13
|
-
},
|
14
|
-
};
|
3
|
+
import UIThemeProvider, { useResponsive } from '../../../theme';
|
15
4
|
export default function MenuBar(props) {
|
5
|
+
const { isXs: isMobileView } = useResponsive();
|
6
|
+
const classes = {
|
7
|
+
title: {
|
8
|
+
height: 70,
|
9
|
+
flexGrow: 1,
|
10
|
+
},
|
11
|
+
logo: {
|
12
|
+
paddingRight: '16px',
|
13
|
+
height: '70px',
|
14
|
+
maxWidth: isMobileView ? '220px' : null,
|
15
|
+
objectFit: 'contain',
|
16
|
+
width: 'auto',
|
17
|
+
},
|
18
|
+
};
|
16
19
|
return (React.createElement(UIThemeProvider, null,
|
17
20
|
React.createElement(AppBar, { color: "inherit", position: "fixed", elevation: 0, sx: { zIndex: (theme) => theme.zIndex.drawer + 1, borderBottom: '1px solid #919EAB3D' } },
|
18
21
|
React.createElement(Toolbar, { sx: { justifyContent: 'space-between' } },
|
@@ -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';
|