@evoke-platform/ui-components 1.13.0-dev.7 → 1.14.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.
Files changed (65) hide show
  1. package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.d.ts +4 -4
  2. package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.js +72 -145
  3. package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.test.js +67 -189
  4. package/dist/published/components/custom/CriteriaBuilder/PropertyTree.d.ts +6 -6
  5. package/dist/published/components/custom/CriteriaBuilder/PropertyTree.js +25 -12
  6. package/dist/published/components/custom/CriteriaBuilder/PropertyTreeItem.d.ts +5 -4
  7. package/dist/published/components/custom/CriteriaBuilder/PropertyTreeItem.js +22 -34
  8. package/dist/published/components/custom/CriteriaBuilder/types.d.ts +11 -2
  9. package/dist/published/components/custom/CriteriaBuilder/utils.d.ts +34 -6
  10. package/dist/published/components/custom/CriteriaBuilder/utils.js +89 -18
  11. package/dist/published/components/custom/Form/FormComponents/DocumentComponent/Document.js +1 -1
  12. package/dist/published/components/custom/Form/FormComponents/DocumentComponent/DocumentList.js +3 -6
  13. package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableField.js +1 -1
  14. package/dist/published/components/custom/Form/utils.d.ts +0 -1
  15. package/dist/published/components/custom/FormField/DateTimePickerSelect/DateTimePickerSelect.js +1 -2
  16. package/dist/published/components/custom/FormV2/FormRenderer.d.ts +2 -2
  17. package/dist/published/components/custom/FormV2/FormRenderer.js +29 -26
  18. package/dist/published/components/custom/FormV2/FormRendererContainer.d.ts +3 -1
  19. package/dist/published/components/custom/FormV2/FormRendererContainer.js +88 -95
  20. package/dist/published/components/custom/FormV2/components/Body.js +1 -1
  21. package/dist/published/components/custom/FormV2/components/Footer.js +1 -1
  22. package/dist/published/components/custom/FormV2/components/FormContext.d.ts +0 -1
  23. package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/ActionDialog.d.ts +0 -1
  24. package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/DropdownRepeatableField.js +143 -86
  25. package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/DropdownRepeatableFieldInput.d.ts +2 -0
  26. package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/DropdownRepeatableFieldInput.js +4 -1
  27. package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/RepeatableField.js +186 -106
  28. package/dist/published/components/custom/FormV2/components/FormFieldTypes/Criteria.js +49 -36
  29. package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/Document.d.ts +2 -3
  30. package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/Document.js +32 -51
  31. package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/DocumentList.d.ts +3 -4
  32. package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/DocumentList.js +38 -40
  33. package/dist/published/components/custom/FormV2/components/FormFieldTypes/UserProperty.js +21 -17
  34. package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/InstanceLookup.js +1 -1
  35. package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/ObjectPropertyInput.js +169 -95
  36. package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/RelatedObjectInstance.d.ts +2 -0
  37. package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/RelatedObjectInstance.js +6 -12
  38. package/dist/published/components/custom/FormV2/components/FormSections.js +0 -1
  39. package/dist/published/components/custom/FormV2/components/Header.d.ts +1 -0
  40. package/dist/published/components/custom/FormV2/components/Header.js +19 -8
  41. package/dist/published/components/custom/FormV2/components/HtmlView.d.ts +9 -0
  42. package/dist/published/components/custom/FormV2/components/HtmlView.js +46 -0
  43. package/dist/published/components/custom/FormV2/components/RecursiveEntryRenderer.d.ts +1 -2
  44. package/dist/published/components/custom/FormV2/components/RecursiveEntryRenderer.js +20 -46
  45. package/dist/published/components/custom/FormV2/components/types.d.ts +1 -6
  46. package/dist/published/components/custom/FormV2/components/utils.d.ts +11 -11
  47. package/dist/published/components/custom/FormV2/components/utils.js +104 -181
  48. package/dist/published/components/custom/FormV2/tests/FormRenderer.test.js +17 -50
  49. package/dist/published/components/custom/FormV2/tests/FormRendererContainer.test.js +131 -40
  50. package/dist/published/components/custom/HistoryLog/HistoryData.js +1 -2
  51. package/dist/published/components/custom/HistoryLog/index.js +1 -2
  52. package/dist/published/components/custom/ViewDetailsV2/InstanceEntryRenderer.d.ts +1 -2
  53. package/dist/published/components/custom/ViewDetailsV2/InstanceEntryRenderer.js +22 -61
  54. package/dist/published/components/custom/ViewDetailsV2/ViewDetailsV2Container.d.ts +3 -0
  55. package/dist/published/components/custom/ViewDetailsV2/ViewDetailsV2Container.js +5 -8
  56. package/dist/published/stories/Backdrop.stories.d.ts +2 -2
  57. package/dist/published/stories/CriteriaBuilder.stories.js +22 -70
  58. package/dist/published/stories/FormLabel.stories.d.ts +2 -2
  59. package/dist/published/stories/FormRenderer.stories.d.ts +3 -3
  60. package/dist/published/stories/FormRendererContainer.stories.d.ts +15 -5
  61. package/dist/published/stories/ViewDetailsV2Container.stories.d.ts +9 -0
  62. package/dist/published/theme/hooks.d.ts +1 -2
  63. package/package.json +11 -17
  64. package/dist/published/components/custom/FormV2/components/ConditionalQueryClientProvider.d.ts +0 -5
  65. package/dist/published/components/custom/FormV2/components/ConditionalQueryClientProvider.js +0 -21
@@ -1,41 +1,53 @@
1
1
  import { useApiServices, useApp, useNavigate, } from '@evoke-platform/context';
2
- import { useQuery } from '@tanstack/react-query';
3
2
  import cleanDeep from 'clean-deep';
4
- import { cloneDeep, debounce, isEmpty, isNil } from 'lodash';
3
+ import { cloneDeep, debounce, isEmpty, isEqual, isNil } from 'lodash';
5
4
  import Handlebars from 'no-eval-handlebars';
6
- import React, { useEffect, useMemo, useRef, useState } from 'react';
5
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
7
6
  import { Close } from '../../../../../../icons';
8
7
  import { useFormContext } from '../../../../../../theme/hooks';
9
8
  import { Autocomplete, Button, IconButton, Link, ListItem, Paper, Snackbar, TextField, Tooltip, Typography, } from '../../../../../core';
10
9
  import { Box } from '../../../../../layout';
11
- import { getDefaultPages, getPrefixedUrl, transformToWhere, useFormById } from '../../utils';
10
+ import { getDefaultPages, getPrefixedUrl, transformToWhere } from '../../utils';
12
11
  import RelatedObjectInstance from './RelatedObjectInstance';
13
12
  const ObjectPropertyInput = (props) => {
14
13
  const { id, fieldDefinition, readOnly, error, mode, displayOption, filter, defaultValueCriteria, sortBy, orderBy, isModal, initialValue, viewLayout, hasDescription, createActionId, formId, relatedObjectId, } = props;
15
14
  const { fetchedOptions, setFetchedOptions, fieldHeight, handleChange: handleChangeObjectField, onAutosave: onAutosave, instance, } = useFormContext();
16
15
  const { defaultPages, findDefaultPageSlugFor } = useApp();
17
- const [debouncedDropdownInput, setDebouncedDropdownInput] = useState();
18
16
  const [selectedInstance, setSelectedInstance] = useState(initialValue || undefined);
19
17
  const [openCreateDialog, setOpenCreateDialog] = useState(false);
18
+ const [loadingOptions, setLoadingOptions] = useState(false);
19
+ const [navigationSlug, setNavigationSlug] = useState(fetchedOptions[`${id}NavigationSlug`]);
20
+ const [relatedObject, setRelatedObject] = useState(fetchedOptions[`${id}RelatedObject`]);
20
21
  const [dropdownInput, setDropdownInput] = useState();
21
22
  const [openOptions, setOpenOptions] = useState(false);
23
+ const [hasFetched, setHasFetched] = useState(fetchedOptions[`${id}OptionsHaveFetched`] || false);
24
+ const [options, setOptions] = useState(fetchedOptions[`${id}Options`] || []);
22
25
  const [layout, setLayout] = useState(fetchedOptions[`${id}ViewLayout`]);
26
+ const [form, setForm] = useState();
23
27
  const [snackbarError, setSnackbarError] = useState({
24
28
  showAlert: false,
25
29
  isError: true,
26
30
  });
27
- const { data: relatedObject } = useQuery({
28
- queryKey: [relatedObjectId, 'sanitized'],
29
- queryFn: () => apiServices.get(getPrefixedUrl(`/objects/${relatedObjectId}/effective?sanitizedVersion=true`)),
30
- enabled: !!relatedObjectId,
31
- staleTime: Infinity,
32
- });
33
31
  const action = relatedObject?.actions?.find((action) => action.id === createActionId);
34
32
  const apiServices = useApiServices();
35
33
  const navigateTo = useNavigate();
34
+ const updatedCriteria = useMemo(() => {
35
+ let criteria = filter ? { where: transformToWhere(filter) } : undefined;
36
+ if (dropdownInput) {
37
+ const nameQuery = transformToWhere({
38
+ name: {
39
+ like: dropdownInput,
40
+ options: 'i',
41
+ },
42
+ });
43
+ criteria = {
44
+ ...criteria,
45
+ where: criteria?.where ? { and: [criteria.where, nameQuery] } : nameQuery,
46
+ };
47
+ }
48
+ return criteria;
49
+ }, [filter, dropdownInput]);
36
50
  const listboxRef = useRef(null);
37
- const formIdToFetch = formId || action?.defaultFormId;
38
- const { data: form } = useFormById(formIdToFetch ?? '', apiServices, 'Error fetching form: ');
39
51
  useEffect(() => {
40
52
  if (relatedObject) {
41
53
  let defaultViewLayout;
@@ -73,102 +85,143 @@ const ObjectPropertyInput = (props) => {
73
85
  }
74
86
  }
75
87
  }, [displayOption, relatedObject, viewLayout]);
76
- const debouncedSetDropdownInput = useMemo(() => debounce((value) => {
77
- setDebouncedDropdownInput(value);
78
- }, 200), []);
79
88
  useEffect(() => {
80
- debouncedSetDropdownInput(dropdownInput);
81
- return () => {
82
- debouncedSetDropdownInput.cancel();
83
- };
84
- }, [dropdownInput, debouncedSetDropdownInput]);
85
- const updatedCriteria = useMemo(() => {
86
- let criteria = filter ? { where: transformToWhere(filter) } : undefined;
87
- if (debouncedDropdownInput) {
88
- const nameQuery = transformToWhere({
89
- name: {
90
- like: debouncedDropdownInput,
91
- options: 'i',
92
- },
93
- });
94
- criteria = {
95
- ...criteria,
96
- where: criteria?.where ? { and: [criteria.where, nameQuery] } : nameQuery,
97
- };
98
- }
99
- return criteria;
100
- }, [filter, debouncedDropdownInput]);
101
- const { data: defaultInstances, isLoading: isLoadingDefaultInstances } = useQuery({
102
- queryKey: ['defaultInstances', relatedObjectId, updatedCriteria],
103
- queryFn: async () => {
89
+ // setting the default value when there is default criteria
90
+ if (!isEmpty(defaultValueCriteria) && !selectedInstance && (!instance || !instance[id])) {
104
91
  const updatedFilter = cleanDeep({
105
92
  where: transformToWhere({ $and: [defaultValueCriteria, updatedCriteria?.where ?? {}] }),
106
93
  order: orderBy && sortBy ? encodeURIComponent(sortBy + ' ' + orderBy) : undefined,
107
94
  limit: 1,
108
95
  });
109
96
  if (updatedFilter.where) {
110
- return apiServices.get(getPrefixedUrl(`/objects/${relatedObjectId}/instances?filter=${encodeURIComponent(JSON.stringify(updatedFilter))}`));
97
+ setLoadingOptions(true);
98
+ apiServices.get(getPrefixedUrl(`/objects/${relatedObjectId}/instances?filter=${encodeURIComponent(JSON.stringify(updatedFilter))}`), async (error, instances) => {
99
+ if (error) {
100
+ console.error(error);
101
+ setLoadingOptions(false);
102
+ }
103
+ if (instances && instances.length > 0) {
104
+ setSelectedInstance(instances[0]);
105
+ try {
106
+ handleChangeObjectField && (await handleChangeObjectField(id, instances[0]));
107
+ }
108
+ catch (error) {
109
+ console.error('Failed to update field:', error);
110
+ setLoadingOptions(false);
111
+ return;
112
+ }
113
+ try {
114
+ await onAutosave?.(id);
115
+ }
116
+ catch (error) {
117
+ console.error('Autosave failed:', error);
118
+ }
119
+ }
120
+ setLoadingOptions(false);
121
+ });
111
122
  }
112
- },
113
- enabled: !isEmpty(defaultValueCriteria) && !selectedInstance && (!instance || !instance[id]),
114
- staleTime: Infinity,
115
- });
123
+ }
124
+ }, [relatedObjectId, defaultValueCriteria, sortBy, orderBy]);
125
+ const getDropdownOptions = useCallback(() => {
126
+ if (((!fetchedOptions?.[`${id}Options`] ||
127
+ (fetchedOptions?.[`${id}Options`]).length === 0) &&
128
+ !hasFetched) ||
129
+ !isEqual(fetchedOptions?.[`${id}UpdatedCriteria`], updatedCriteria)) {
130
+ setFetchedOptions({ [`${id}UpdatedCriteria`]: updatedCriteria });
131
+ setLoadingOptions(true);
132
+ const updatedFilter = cloneDeep(updatedCriteria) || {};
133
+ updatedFilter.limit = 100;
134
+ const { propertyId, direction } = layout?.sort ?? {
135
+ propertyId: 'name',
136
+ direction: 'asc',
137
+ };
138
+ updatedFilter.order = `${propertyId} ${direction}`;
139
+ apiServices.get(getPrefixedUrl(`/objects/${relatedObjectId}/instances?filter=${JSON.stringify(updatedFilter)}`), (error, instances) => {
140
+ if (error) {
141
+ console.error(error);
142
+ setLoadingOptions(false);
143
+ }
144
+ if (instances) {
145
+ setOptions(instances);
146
+ setLoadingOptions(false);
147
+ // so if you go off a section too quickly and it doesn't fetch it re-fetches but doesn't cause an infinite loop
148
+ setHasFetched(true);
149
+ }
150
+ });
151
+ }
152
+ }, [
153
+ relatedObjectId,
154
+ updatedCriteria,
155
+ layout,
156
+ fetchedOptions?.[`${id}Options`],
157
+ fetchedOptions?.[`${id}UpdatedCriteria`],
158
+ hasFetched,
159
+ id,
160
+ ]);
161
+ const debouncedGetDropdownOptions = useCallback(debounce(getDropdownOptions, 200), [getDropdownOptions]);
116
162
  useEffect(() => {
117
- if (defaultInstances?.[0]) {
118
- setSelectedInstance(defaultInstances[0]);
119
- (async () => {
120
- try {
121
- handleChangeObjectField && (await handleChangeObjectField(id, defaultInstances[0]));
163
+ if (displayOption === 'dropdown') {
164
+ debouncedGetDropdownOptions();
165
+ return () => debouncedGetDropdownOptions.cancel();
166
+ }
167
+ }, [displayOption, debouncedGetDropdownOptions]);
168
+ useEffect(() => {
169
+ setSelectedInstance(initialValue);
170
+ }, [initialValue]);
171
+ useEffect(() => {
172
+ // Early return if already fetched
173
+ if (fetchedOptions[`${id}Form`])
174
+ return;
175
+ const fetchForm = async () => {
176
+ try {
177
+ let evokeForm;
178
+ if (formId || action?.defaultFormId) {
179
+ evokeForm = await apiServices.get(getPrefixedUrl(`/forms/${formId || action?.defaultFormId}`));
122
180
  }
123
- catch (error) {
124
- console.error('Failed to update field:', error);
125
- return;
181
+ if (evokeForm) {
182
+ setForm(evokeForm);
183
+ setFetchedOptions({
184
+ [`${id}Form`]: evokeForm,
185
+ });
126
186
  }
127
- try {
128
- await onAutosave?.(id);
187
+ }
188
+ catch (error) {
189
+ console.error('Error fetching form:', error);
190
+ }
191
+ };
192
+ fetchForm();
193
+ }, [action, formId, id, apiServices, fetchedOptions]);
194
+ useEffect(() => {
195
+ if (!fetchedOptions[`${id}RelatedObject`]) {
196
+ apiServices.get(getPrefixedUrl(`/objects/${relatedObjectId}/effective?sanitizedVersion=true`), (error, object) => {
197
+ if (error) {
198
+ console.error(error);
129
199
  }
130
- catch (error) {
131
- console.error('Autosave failed:', error);
200
+ else {
201
+ setRelatedObject(object);
132
202
  }
133
- })();
203
+ });
134
204
  }
135
- }, [defaultInstances]);
136
- // Construct filter from debounced criteria
137
- const updatedFilter = useMemo(() => {
138
- const filter = cloneDeep(updatedCriteria) || {};
139
- filter.limit = 100;
140
- const { propertyId, direction } = layout?.sort ?? {
141
- propertyId: 'name',
142
- direction: 'asc',
143
- };
144
- filter.order = `${propertyId} ${direction}`;
145
- return filter;
146
- }, [updatedCriteria, layout]);
147
- const {
148
- // Sets the default value of options to an empty array
149
- data: options = [], isLoading: isLoadingOptions, } = useQuery({
150
- queryKey: ['dropdownOptions', relatedObjectId, updatedFilter],
151
- queryFn: () => apiServices.get(getPrefixedUrl(`/objects/${relatedObjectId}/instances?filter=${JSON.stringify(updatedFilter)}`)),
152
- staleTime: 300000,
153
- // Keep old data while fetching new data
154
- placeholderData: (previousData) => previousData,
155
- });
205
+ }, [relatedObjectId, fetchedOptions, id]);
156
206
  useEffect(() => {
157
- setSelectedInstance(initialValue);
158
- }, [initialValue]);
159
- const loadingOptions = isLoadingOptions || isLoadingDefaultInstances;
160
- const { data: navigationSlug } = useQuery({
161
- queryKey: ['navigationSlug', id, relatedObjectId],
162
- queryFn: async () => {
163
- const pages = await getDefaultPages([{ ...fieldDefinition, objectId: relatedObjectId }], defaultPages, findDefaultPageSlugFor);
164
- if (relatedObjectId && pages[relatedObjectId]) {
165
- return pages[relatedObjectId];
207
+ (async () => {
208
+ if (fetchedOptions[`${id}NavigationSlug`] === undefined) {
209
+ const pages = await getDefaultPages([{ ...fieldDefinition, objectId: relatedObjectId }], defaultPages, findDefaultPageSlugFor);
210
+ if (relatedObjectId && pages[relatedObjectId]) {
211
+ setNavigationSlug(pages[relatedObjectId]);
212
+ setFetchedOptions({
213
+ [`${id}NavigationSlug`]: pages[relatedObjectId],
214
+ });
215
+ }
216
+ else {
217
+ // setting the nav slug to null if there is no default page for this object to avoid re-fetching
218
+ setFetchedOptions({
219
+ [`${id}NavigationSlug`]: null,
220
+ });
221
+ }
166
222
  }
167
- return null;
168
- },
169
- enabled: !!(relatedObjectId && defaultPages && findDefaultPageSlugFor),
170
- staleTime: Infinity,
171
- });
223
+ })();
224
+ }, [id, fieldDefinition, defaultPages, findDefaultPageSlugFor, relatedObjectId, fetchedOptions]);
172
225
  const handleClose = () => {
173
226
  setOpenCreateDialog(false);
174
227
  };
@@ -176,6 +229,27 @@ const ObjectPropertyInput = (props) => {
176
229
  const template = Handlebars.compileAST(expression);
177
230
  return instance ? template(instance) : undefined;
178
231
  };
232
+ useEffect(() => {
233
+ if (relatedObject && !fetchedOptions[`${id}RelatedObject`]) {
234
+ setFetchedOptions({
235
+ [`${id}RelatedObject`]: relatedObject,
236
+ });
237
+ }
238
+ if (options &&
239
+ (!fetchedOptions[`${id}Options`] || fetchedOptions[`${id}Options`].length === 0) &&
240
+ hasFetched &&
241
+ !fetchedOptions[`${id}OptionsHaveFetched`]) {
242
+ setFetchedOptions({
243
+ [`${id}Options`]: options,
244
+ [`${id}OptionsHaveFetched`]: hasFetched,
245
+ });
246
+ }
247
+ if (navigationSlug && !fetchedOptions[`${id}NavigationSlug`]) {
248
+ setFetchedOptions({
249
+ [`${id}NavigationSlug`]: navigationSlug,
250
+ });
251
+ }
252
+ }, [relatedObject, options, hasFetched, navigationSlug, fetchedOptions, id]);
179
253
  const dropdownOptions = [
180
254
  ...options.map((o) => ({ label: o.name, value: o.id })),
181
255
  ...(mode !== 'existingOnly' && relatedObject?.actions?.some((a) => a.id === createActionId)
@@ -348,7 +422,7 @@ const ObjectPropertyInput = (props) => {
348
422
  }
349
423
  }, selectOnFocus: false, onBlur: () => {
350
424
  if (dropdownInput) {
351
- setDropdownInput(undefined);
425
+ getDropdownOptions();
352
426
  }
353
427
  }, renderInput: (params) => (React.createElement(TextField, { ...params, placeholder: selectedInstance?.id || readOnly ? '' : 'Select', readOnly: !loadingOptions && !selectedInstance?.id && readOnly, onChange: (event) => setDropdownInput(event.target.value), sx: {
354
428
  ...(!loadingOptions && selectedInstance?.id
@@ -455,7 +529,7 @@ const ObjectPropertyInput = (props) => {
455
529
  event.stopPropagation();
456
530
  setOpenCreateDialog(true);
457
531
  }, "aria-label": `Add` }, "Add")))),
458
- React.createElement(RelatedObjectInstance, { open: openCreateDialog, title: form?.name ?? `Add ${fieldDefinition.name}`, handleClose: handleClose, setSelectedInstance: setSelectedInstance, relatedObject: relatedObject, id: id, mode: mode, displayOption: displayOption, filter: updatedCriteria, layout: layout, formId: formIdToFetch, actionId: createActionId, setSnackbarError: setSnackbarError }),
532
+ React.createElement(RelatedObjectInstance, { open: openCreateDialog, title: form?.name ?? `Add ${fieldDefinition.name}`, handleClose: handleClose, setSelectedInstance: setSelectedInstance, relatedObject: relatedObject, id: id, mode: mode, displayOption: displayOption, setOptions: setOptions, options: options, filter: updatedCriteria, layout: layout, formId: formId ?? form?.id, actionId: createActionId, setSnackbarError: setSnackbarError }),
459
533
  React.createElement(Snackbar, { open: snackbarError.showAlert, handleClose: () => setSnackbarError({
460
534
  isError: snackbarError.isError,
461
535
  showAlert: false,
@@ -15,6 +15,8 @@ export type RelatedObjectInstanceProps = BaseProps & {
15
15
  isError: boolean;
16
16
  }>>;
17
17
  displayOption?: 'dropdown' | 'dialogBox';
18
+ setOptions: (options: ObjectInstance[]) => void;
19
+ options: ObjectInstance[];
18
20
  filter?: Record<string, unknown>;
19
21
  layout?: TableViewLayout;
20
22
  formId?: string;
@@ -1,6 +1,5 @@
1
1
  import { useApiServices } from '@evoke-platform/context';
2
2
  import { DialogActions } from '@mui/material';
3
- import { useQueryClient } from '@tanstack/react-query';
4
3
  import { isEmpty } from 'lodash';
5
4
  import React, { useCallback, useRef, useState } from 'react';
6
5
  import { Close } from '../../../../../../icons';
@@ -30,7 +29,7 @@ const styles = {
30
29
  },
31
30
  };
32
31
  const RelatedObjectInstance = (props) => {
33
- const { relatedObject, open, title, id, setSelectedInstance, handleClose, mode, displayOption, filter, layout, formId, actionId, setSnackbarError, } = props;
32
+ const { relatedObject, open, title, id, setSelectedInstance, handleClose, mode, displayOption, filter, layout, formId, actionId, setSnackbarError, setOptions, options, } = props;
34
33
  const { handleChange: handleChangeObjectField, onAutosave, richTextEditor, fieldHeight, width } = useFormContext();
35
34
  const [selectedRow, setSelectedRow] = useState();
36
35
  const [relationType, setRelationType] = useState(displayOption === 'dropdown' || mode === 'newOnly' ? 'new' : 'existing');
@@ -41,7 +40,6 @@ const RelatedObjectInstance = (props) => {
41
40
  defaultWidth: width,
42
41
  });
43
42
  const { isXs, isSm } = breakpoints;
44
- const queryClient = useQueryClient();
45
43
  const linkExistingInstance = async () => {
46
44
  if (selectedRow && handleChangeObjectField) {
47
45
  setSelectedInstance(selectedRow);
@@ -95,11 +93,7 @@ const RelatedObjectInstance = (props) => {
95
93
  message: 'New instance created',
96
94
  isError: false,
97
95
  });
98
- // Clear option cache to then fetch newly created instance
99
- queryClient.invalidateQueries({
100
- queryKey: ['dropdownOptions', relatedObject.id],
101
- exact: false,
102
- });
96
+ setOptions(options.concat([response]));
103
97
  onClose();
104
98
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
105
99
  }
@@ -119,14 +113,14 @@ const RelatedObjectInstance = (props) => {
119
113
  }
120
114
  };
121
115
  const shouldShowRadioButtons = displayOption !== 'dropdown' && mode !== 'existingOnly' && mode !== 'newOnly' && actionId;
122
- const RadioButtons = useCallback(() => shouldShowRadioButtons ? (React.createElement(RadioGroup, { row: true, "aria-label": "Relation Type", onChange: (event) => {
116
+ const RadioButtons = () => shouldShowRadioButtons ? (React.createElement(RadioGroup, { row: true, "aria-label": "Relation Type", onChange: (event) => {
123
117
  const { value } = event.target;
124
118
  if (value === 'new' || value === 'existing') {
125
119
  setRelationType(value);
126
120
  }
127
121
  }, value: relationType },
128
122
  React.createElement(FormControlLabel, { value: "existing", control: React.createElement(Radio, { sx: { '&.Mui-checked': { color: 'primary' } } }), label: "Existing" }),
129
- React.createElement(FormControlLabel, { value: "new", control: React.createElement(Radio, { sx: { '&.Mui-checked': { color: 'primary' } } }), label: "New" }))) : null, [shouldShowRadioButtons, relationType]);
123
+ React.createElement(FormControlLabel, { value: "new", control: React.createElement(Radio, { sx: { '&.Mui-checked': { color: 'primary' } } }), label: "New" }))) : null;
130
124
  const DialogForm = useCallback(() => (React.createElement(FormRendererContainer, { formId: formId, display: { fieldHeight: fieldHeight ?? 'medium' }, actionId: actionId, objectId: relatedObject.id, onSubmit: createNewInstance, onDiscardChanges: onClose, onSubmitError: handleSubmitError, richTextEditor: richTextEditor, renderHeader: () => null, renderBody: (bodyProps) => (React.createElement(DialogContent, { sx: styles.dialogContent },
131
125
  relationType === 'new' ? (React.createElement("div", { ref: validationErrorsRef }, !isEmpty(bodyProps.errors) && bodyProps.shouldShowValidationErrors ? (React.createElement(FormRenderer.ValidationErrors, { errors: bodyProps.errors, sx: {
132
126
  my: isSm || isXs ? 2 : 3,
@@ -152,7 +146,7 @@ const RelatedObjectInstance = (props) => {
152
146
  maxWidth: '950px',
153
147
  width: '100%',
154
148
  },
155
- } }, open && (React.createElement(React.Fragment, null,
149
+ } },
156
150
  React.createElement(DialogTitle, { sx: {
157
151
  padding: 3,
158
152
  borderBottom: '1px solid #e9ecef',
@@ -182,6 +176,6 @@ const RelatedObjectInstance = (props) => {
182
176
  marginLeft: '8px',
183
177
  width: '85px',
184
178
  '&:hover': { boxShadow: 'none' },
185
- }, onClick: linkExistingInstance, variant: "contained", disabled: !selectedRow, "aria-label": `Add` }, "Add")))))))));
179
+ }, onClick: linkExistingInstance, variant: "contained", disabled: !selectedRow, "aria-label": `Add` }, "Add")))))));
186
180
  };
187
181
  export default RelatedObjectInstance;
@@ -126,7 +126,6 @@ function FormSections(props) {
126
126
  display: 'flex',
127
127
  flexDirection: 'column',
128
128
  justifyContent: section.entries && section?.entries.length > 0 ? 'space-between' : 'flex-end',
129
- height: '100%',
130
129
  } },
131
130
  React.createElement(Box, null, section.entries &&
132
131
  section.entries.map((sectionEntry, index) => {
@@ -7,6 +7,7 @@ export type HeaderProps = {
7
7
  hasAccordions: boolean;
8
8
  shouldShowValidationErrors?: boolean;
9
9
  validationContainerRef?: React.Ref<HTMLDivElement>;
10
+ hideTitle: boolean;
10
11
  title?: string;
11
12
  expandedSections?: ExpandedSection[];
12
13
  onExpandAll?: () => void;
@@ -7,7 +7,7 @@ import { Typography } from '../../../core/Typography';
7
7
  import Box from '../../../layout/Box/Box';
8
8
  import ValidationErrors from './ValidationFiles/ValidationErrors';
9
9
  const Header = (props) => {
10
- const { title, errors, hasAccordions, shouldShowValidationErrors, validationContainerRef, sx, autosaveEnabled } = props;
10
+ const { title, errors, hasAccordions, shouldShowValidationErrors, validationContainerRef, sx, autosaveEnabled, hideTitle, autosaving, } = props;
11
11
  const { width } = useFormContext();
12
12
  const { breakpoints, isBelow } = useWidgetSize({
13
13
  scroll: false,
@@ -17,23 +17,32 @@ const Header = (props) => {
17
17
  const { isXs, isSm } = breakpoints;
18
18
  const isSmall = isSm || isXs;
19
19
  const displayValidationErrors = shouldShowValidationErrors && !isEmpty(errors);
20
+ if (hideTitle && !autosaveEnabled && !hasAccordions && !displayValidationErrors) {
21
+ return null;
22
+ }
20
23
  return (React.createElement(Box, { sx: {
21
24
  paddingX: isSmallerThanMd ? 2 : 3,
22
25
  paddingTop: '0px',
23
26
  display: 'flex',
24
27
  alignItems: 'center',
28
+ justifyContent: 'flex-end',
25
29
  flexWrap: 'wrap',
26
30
  paddingY: isSm || isXs ? 2 : 3,
27
31
  borderBottom: '1px solid #e9ecef',
28
32
  gap: isSm || isXs ? 2 : 3,
33
+ minHeight: '24px',
29
34
  ...sx,
30
35
  }, ref: validationContainerRef },
31
- title && (React.createElement(Box, { sx: { flex: '1 1 auto', minWidth: 0, display: 'flex', alignItems: 'center', gap: 1 } },
32
- React.createElement(Title, { ...props }),
33
- props.autosaving && !isSmall && React.createElement(SavingIndicator, null))),
34
- hasAccordions && (React.createElement(Box, { sx: { flex: '0 0 auto', display: 'flex', alignItems: 'center' } },
35
- React.createElement(Box, { sx: { display: 'flex', alignItems: 'center' } },
36
- React.createElement(AccordionActions, { ...props })),
36
+ ((!hideTitle && title) || (autosaving && !isSmall)) && (React.createElement(Box, { sx: {
37
+ flex: '1 1 auto',
38
+ minWidth: 0,
39
+ display: 'flex',
40
+ alignItems: 'center',
41
+ gap: 1,
42
+ } },
43
+ !hideTitle && title && React.createElement(Title, { ...props }),
44
+ autosaving && !isSmall ? React.createElement(SavingIndicator, null) : React.createElement(React.Fragment, null))),
45
+ hasAccordions && (React.createElement(Box, { sx: { flex: '0 0 auto', display: 'flex', alignItems: 'center', justifyContent: 'space-between' } },
37
46
  autosaveEnabled && (React.createElement(Box, { sx: {
38
47
  width: '96px',
39
48
  minWidth: '72px',
@@ -41,7 +50,9 @@ const Header = (props) => {
41
50
  justifyContent: 'flex-end',
42
51
  alignItems: 'center',
43
52
  marginLeft: 0.5,
44
- } }, props.autosaving && isSmall ? React.createElement(SavingIndicator, null) : React.createElement(Box, { sx: { width: '100%' } }))))),
53
+ } }, autosaving && isSmall ? React.createElement(SavingIndicator, null) : React.createElement(React.Fragment, null))),
54
+ React.createElement(Box, { sx: { display: 'flex', alignItems: 'center', justifyContent: 'center' } },
55
+ React.createElement(AccordionActions, { ...props })))),
45
56
  displayValidationErrors ? React.createElement(ValidationErrors, { errors: errors }) : null));
46
57
  };
47
58
  // Default slot components for convenience
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import 'quill/dist/quill.snow.css';
3
+ import 'quill-table-up/index.css';
4
+ type EditorProps = {
5
+ /** HTML content to display in the read-only editor */
6
+ value: string;
7
+ };
8
+ declare const HtmlView: ({ value }: EditorProps) => React.JSX.Element;
9
+ export default HtmlView;
@@ -0,0 +1,46 @@
1
+ import Quill from 'quill';
2
+ import React, { useEffect, useRef } from 'react';
3
+ import 'quill/dist/quill.snow.css';
4
+ import TableUp from 'quill-table-up';
5
+ import 'quill-table-up/index.css';
6
+ import { Box } from '@mui/material';
7
+ import DOMPurify from 'dompurify';
8
+ const fontSizeArr = ['8px', '10px', '12px', '14px', '16px', '18px', '20px', '22px', '24px', '26px', '28px'];
9
+ Quill.register({ [`modules/${TableUp.moduleName}`]: TableUp }, true);
10
+ const Size = Quill.import('attributors/style/size');
11
+ Size.whitelist = fontSizeArr;
12
+ Quill.register(Size, true);
13
+ const HtmlView = ({ value }) => {
14
+ const containerRef = useRef(null);
15
+ const quillRef = useRef(null);
16
+ // Initialize ONCE
17
+ useEffect(() => {
18
+ if (!containerRef.current || quillRef.current)
19
+ return;
20
+ const quill = new Quill(containerRef.current, {
21
+ theme: 'snow',
22
+ readOnly: true,
23
+ modules: {
24
+ toolbar: false,
25
+ },
26
+ });
27
+ quillRef.current = quill;
28
+ }, []);
29
+ // Update content only
30
+ useEffect(() => {
31
+ if (!quillRef.current)
32
+ return;
33
+ quillRef.current.setContents([]);
34
+ quillRef.current.clipboard.dangerouslyPasteHTML(DOMPurify.sanitize(value));
35
+ }, [value]);
36
+ return (React.createElement(Box, { sx: {
37
+ width: '100%',
38
+ height: '100%',
39
+ '.ql-container.ql-snow': {
40
+ border: 'none',
41
+ minHeight: 20,
42
+ },
43
+ } },
44
+ React.createElement("div", { ref: containerRef })));
45
+ };
46
+ export default HtmlView;
@@ -1,3 +1,2 @@
1
- import React from 'react';
2
1
  import { EntryRendererProps } from './types';
3
- export declare function RecursiveEntryRenderer(props: EntryRendererProps): React.JSX.Element | null;
2
+ export declare function RecursiveEntryRenderer(props: EntryRendererProps): any;