datastake-daf 0.6.100 → 0.6.102

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 (67) hide show
  1. package/dist/components/index.css +1 -1
  2. package/dist/components/index.js +2722 -226
  3. package/package.json +1 -1
  4. package/rollup.config.js +41 -83
  5. package/src/@daf/core/components/Dashboard/Map/helper.js +434 -439
  6. package/src/@daf/core/components/Dashboard/Map/storyConfig1.js +230 -233
  7. package/src/@daf/core/components/EditForm/components/AjaxSubGroup/index.js +0 -2
  8. package/src/@daf/core/components/PdfForm/components/AjaxSubGroup.js +106 -0
  9. package/src/@daf/core/components/PdfForm/components/ajaxSubGroupHandler.js +12 -0
  10. package/src/@daf/core/components/PdfForm/components/dataLinkGroupHandler.js +24 -15
  11. package/src/@daf/core/components/PdfForm/components/dataLinkHandler.js +51 -17
  12. package/src/@daf/core/components/PdfForm/index.js +208 -22
  13. package/src/@daf/core/components/PdfForm/storyConfig.js +464 -163
  14. package/src/@daf/core/components/PdfForm/style.scss +145 -3
  15. package/src/@daf/core/components/PdfForm/utils/fieldData.js +82 -3
  16. package/src/@daf/core/components/PdfForm/utils/fieldRenderer.js +14 -6
  17. package/src/helpers/Map.js +6 -82
  18. package/src/styles/_index.scss +1 -1
  19. package/src/styles/datastake.scss +4454 -1
  20. package/.vscode/settings.json +0 -13
  21. package/dist/style/datastake/_index.css +0 -5
  22. package/dist/style/datastake/datastake.css +0 -5081
  23. package/dist/style/datastake/fonts/Outfit-Black.ttf +0 -0
  24. package/dist/style/datastake/fonts/Outfit-Bold.ttf +0 -0
  25. package/dist/style/datastake/fonts/Outfit-ExtraBold.ttf +0 -0
  26. package/dist/style/datastake/fonts/Outfit-ExtraLight.ttf +0 -0
  27. package/dist/style/datastake/fonts/Outfit-Light.ttf +0 -0
  28. package/dist/style/datastake/fonts/Outfit-Medium.ttf +0 -0
  29. package/dist/style/datastake/fonts/Outfit-Regular.ttf +0 -0
  30. package/dist/style/datastake/fonts/Outfit-SemiBold.ttf +0 -0
  31. package/dist/style/datastake/fonts/Outfit-Thin.ttf +0 -0
  32. package/dist/style/datastake/fonts/outfit.css +0 -62
  33. package/dist/style/datastake/fonts/sf-ui-display-black-58646a6b80d5a.woff +0 -0
  34. package/dist/style/datastake/fonts/sf-ui-display-bold-58646a511e3d9.woff +0 -0
  35. package/dist/style/datastake/fonts/sf-ui-display-heavy-586470160b9e5.woff +0 -0
  36. package/dist/style/datastake/fonts/sf-ui-display-light-58646b33e0551.woff +0 -0
  37. package/dist/style/datastake/fonts/sf-ui-display-medium-58646be638f96.woff +0 -0
  38. package/dist/style/datastake/fonts/sf-ui-display-semibold-58646eddcae92.woff +0 -0
  39. package/dist/style/datastake/fonts/sf-ui-display-thin-58646e9b26e8b.woff +0 -0
  40. package/dist/style/datastake/fonts/sf-ui-display-ultralight-58646b19bf205.woff +0 -0
  41. package/dist/style/datastake/fonts/sfDisplay.css +0 -59
  42. package/dist/style/datastake/leaflet.css +0 -671
  43. package/dist/style/datastake/leaflet.markercluster.css +0 -60
  44. package/dist/style/style.css +0 -1
  45. package/src/styles/datastake/_index.css +0 -5
  46. package/src/styles/datastake/datastake.css +0 -5081
  47. package/src/styles/datastake/fonts/Outfit-Black.ttf +0 -0
  48. package/src/styles/datastake/fonts/Outfit-Bold.ttf +0 -0
  49. package/src/styles/datastake/fonts/Outfit-ExtraBold.ttf +0 -0
  50. package/src/styles/datastake/fonts/Outfit-ExtraLight.ttf +0 -0
  51. package/src/styles/datastake/fonts/Outfit-Light.ttf +0 -0
  52. package/src/styles/datastake/fonts/Outfit-Medium.ttf +0 -0
  53. package/src/styles/datastake/fonts/Outfit-Regular.ttf +0 -0
  54. package/src/styles/datastake/fonts/Outfit-SemiBold.ttf +0 -0
  55. package/src/styles/datastake/fonts/Outfit-Thin.ttf +0 -0
  56. package/src/styles/datastake/fonts/outfit.css +0 -62
  57. package/src/styles/datastake/fonts/sf-ui-display-black-58646a6b80d5a.woff +0 -0
  58. package/src/styles/datastake/fonts/sf-ui-display-bold-58646a511e3d9.woff +0 -0
  59. package/src/styles/datastake/fonts/sf-ui-display-heavy-586470160b9e5.woff +0 -0
  60. package/src/styles/datastake/fonts/sf-ui-display-light-58646b33e0551.woff +0 -0
  61. package/src/styles/datastake/fonts/sf-ui-display-medium-58646be638f96.woff +0 -0
  62. package/src/styles/datastake/fonts/sf-ui-display-semibold-58646eddcae92.woff +0 -0
  63. package/src/styles/datastake/fonts/sf-ui-display-thin-58646e9b26e8b.woff +0 -0
  64. package/src/styles/datastake/fonts/sf-ui-display-ultralight-58646b19bf205.woff +0 -0
  65. package/src/styles/datastake/fonts/sfDisplay.css +0 -59
  66. package/src/styles/datastake/leaflet.css +0 -671
  67. package/src/styles/datastake/leaflet.markercluster.css +0 -60
@@ -19,8 +19,7 @@ export const handleDataLinkGroupWithTableKeys = ({
19
19
  if (!(config.type === 'dataLinkGroup' || config.type === 'dataLink')) {
20
20
  return null;
21
21
  }
22
- console.log({app})
23
-
22
+
24
23
  if (inputConfig?.type !== 'dataLink' || !inputConfig?.meta?.tableKeys) {
25
24
  const parentInputKeys = Object.keys(config.inputs || {});
26
25
  const isHandledBySiblingDataLink = parentInputKeys.some(otherInputKey => {
@@ -41,10 +40,6 @@ export const handleDataLinkGroupWithTableKeys = ({
41
40
  return null;
42
41
  }
43
42
 
44
- if (!(value && typeof value === 'object')) {
45
- return null;
46
- }
47
-
48
43
  const tableKeys = inputConfig.meta.tableKeys;
49
44
  const additionalTableKeys = config.meta?.additionalTableKeys || [];
50
45
  const allTableKeys = [...new Set([...tableKeys, ...additionalTableKeys])];
@@ -88,6 +83,14 @@ export const handleDataLinkGroupWithTableKeys = ({
88
83
  const inputs = {};
89
84
  const values = {};
90
85
 
86
+ const uploadTypeFields = ['documents', 'links', 'pictures', 'videos'];
87
+ const uploadTypeLabels = {
88
+ 'documents': 'File',
89
+ 'links': 'Link',
90
+ 'pictures': 'Image',
91
+ 'videos': 'Video'
92
+ };
93
+
91
94
  tableKeys
92
95
  .filter(tableKey => tableKey !== 'datastakeId')
93
96
  .forEach(tableKey => {
@@ -96,7 +99,9 @@ export const handleDataLinkGroupWithTableKeys = ({
96
99
  if (formInputConfig) {
97
100
  inputs[tableKey] = {
98
101
  ...formInputConfig,
99
- label: formInputConfig.label || formInputConfig.tableLabel || tableKey
102
+ label: uploadTypeFields.includes(tableKey)
103
+ ? uploadTypeLabels[tableKey]
104
+ : (formInputConfig.label || formInputConfig.tableLabel || tableKey)
100
105
  };
101
106
 
102
107
  if (formInputConfig.label && typeof formInputConfig.label === 'object') {
@@ -113,13 +118,14 @@ export const handleDataLinkGroupWithTableKeys = ({
113
118
  }
114
119
  }
115
120
  }
116
- inputs[tableKey].label = resolvedLabel || Object.values(formInputConfig.label)[0] || tableKey;
121
+ inputs[tableKey].label = resolvedLabel || Object.values(formInputConfig.label)[0] ||
122
+ (uploadTypeFields.includes(tableKey) ? uploadTypeLabels[tableKey] : tableKey);
117
123
  }
118
124
 
119
125
  values[tableKey] = item?.[tableKey];
120
126
  } else {
121
127
  inputs[tableKey] = {
122
- label: tableKey,
128
+ label: uploadTypeFields.includes(tableKey) ? uploadTypeLabels[tableKey] : tableKey,
123
129
  type: inputConfig?.type
124
130
  };
125
131
  values[tableKey] = item?.[tableKey];
@@ -138,7 +144,9 @@ export const handleDataLinkGroupWithTableKeys = ({
138
144
 
139
145
  inputs[fieldKey] = {
140
146
  ...formInputConfig,
141
- label: formInputConfig.label || formInputConfig.tableLabel || fieldKey
147
+ label: uploadTypeFields.includes(fieldKey)
148
+ ? uploadTypeLabels[fieldKey]
149
+ : (formInputConfig.label || formInputConfig.tableLabel || fieldKey)
142
150
  };
143
151
 
144
152
  if (formInputConfig.label && typeof formInputConfig.label === 'object') {
@@ -155,7 +163,8 @@ export const handleDataLinkGroupWithTableKeys = ({
155
163
  }
156
164
  }
157
165
  }
158
- inputs[fieldKey].label = resolvedLabel || Object.values(formInputConfig.label)[0] || fieldKey;
166
+ inputs[fieldKey].label = resolvedLabel || Object.values(formInputConfig.label)[0] ||
167
+ (uploadTypeFields.includes(fieldKey) ? uploadTypeLabels[fieldKey] : fieldKey);
159
168
  }
160
169
 
161
170
  values[fieldKey] = item?.[fieldKey];
@@ -173,9 +182,9 @@ export const handleDataLinkGroupWithTableKeys = ({
173
182
  return (
174
183
  <TreeNodeComponent
175
184
  key={`${inputKey}-${itemIndex}`}
176
- nodeKey={datastakeIdValue || `Unknown ID ${itemIndex + 1}`}
185
+ nodeKey={datastakeIdValue || t(`No ID ${itemIndex + 1}`)}
177
186
  config={{
178
- label: datastakeIdValue || `Unknown ID ${itemIndex + 1}`,
187
+ label: datastakeIdValue || t(`No ID ${itemIndex + 1}`),
179
188
  type: 'custom-datalink-group',
180
189
  inputs: inputs
181
190
  }}
@@ -199,9 +208,9 @@ export const handleDataLinkGroupWithTableKeys = ({
199
208
  return (
200
209
  <TreeNodeComponent
201
210
  key={`${inputKey}-group`}
202
- nodeKey={datastakeIdValue || 'Unknown ID'}
211
+ nodeKey={datastakeIdValue || t('No ID')}
203
212
  config={{
204
- label: datastakeIdValue || 'Unknown ID',
213
+ label: datastakeIdValue || t('No ID'),
205
214
  type: 'custom-datalink-group',
206
215
  inputs: inputs
207
216
  }}
@@ -1,5 +1,6 @@
1
1
  import React, { useMemo } from 'react';
2
2
  import useAjaxModal from '../utils/useAjaxModal';
3
+ import { processConditionalTableKeys } from '../utils/fieldData';
3
4
 
4
5
  export const handleDataLinkWithTableKeys = ({
5
6
  inputConfig,
@@ -15,14 +16,9 @@ export const handleDataLinkWithTableKeys = ({
15
16
  app,
16
17
  TreeNodeComponent
17
18
  }) => {
18
-
19
19
  if (inputConfig?.type !== 'dataLink' || !inputConfig?.meta?.tableKeys) {
20
20
  return null;
21
21
  }
22
-
23
- if (!(value && typeof value === 'object')) {
24
- return null;
25
- }
26
22
 
27
23
  const tableKeys = inputConfig.meta.tableKeys;
28
24
  const isAjaxModal = useMemo(() => !!inputConfig?.meta?.namespace, [inputConfig]);
@@ -45,15 +41,36 @@ export const handleDataLinkWithTableKeys = ({
45
41
  const inputs = {};
46
42
  const values = {};
47
43
 
48
- tableKeys
44
+ const uploadTypeFields = ['documents', 'links', 'pictures', 'videos'];
45
+ const uploadTypeLabels = {
46
+ 'documents': 'File',
47
+ 'links': 'Link',
48
+ 'pictures': 'Image',
49
+ 'videos': 'Video'
50
+ };
51
+
52
+ const isUploadFieldEmpty = (fieldKey, itemToCheck) => {
53
+ if (uploadTypeFields.includes(fieldKey)) {
54
+ const itemValue = itemToCheck?.[fieldKey];
55
+ return itemValue === undefined || itemValue === null || (Array.isArray(itemValue) && itemValue.length === 0);
56
+ }
57
+ return false;
58
+ };
59
+
60
+ const processedTableKeys = processConditionalTableKeys(tableKeys, item);
61
+
62
+ processedTableKeys
49
63
  .filter(tableKey => tableKey !== 'datastakeId')
64
+ .filter(tableKey => !isUploadFieldEmpty(tableKey, item))
50
65
  .forEach(tableKey => {
51
66
  const formInputConfig = dataLinkForm?.[tableKey] || dataLinkForm?.['identification']?.[tableKey];
52
67
 
53
68
  if (formInputConfig) {
54
69
  inputs[tableKey] = {
55
70
  ...formInputConfig,
56
- label: formInputConfig.label || formInputConfig.tableLabel || tableKey
71
+ label: uploadTypeFields.includes(tableKey)
72
+ ? uploadTypeLabels[tableKey]
73
+ : (formInputConfig.label || formInputConfig.tableLabel || tableKey)
57
74
  };
58
75
 
59
76
  if (formInputConfig.label && typeof formInputConfig.label === 'object') {
@@ -70,13 +87,14 @@ export const handleDataLinkWithTableKeys = ({
70
87
  }
71
88
  }
72
89
  }
73
- inputs[tableKey].label = resolvedLabel || Object.values(formInputConfig.label)[0] || tableKey;
90
+ inputs[tableKey].label = resolvedLabel || Object.values(formInputConfig.label)[0] ||
91
+ (uploadTypeFields.includes(tableKey) ? uploadTypeLabels[tableKey] : tableKey);
74
92
  }
75
93
 
76
94
  values[tableKey] = item?.[tableKey];
77
95
  } else {
78
96
  inputs[tableKey] = {
79
- label: tableKey,
97
+ label: uploadTypeFields.includes(tableKey) ? uploadTypeLabels[tableKey] : tableKey,
80
98
  type: inputConfig?.type
81
99
  };
82
100
  values[tableKey] = item?.[tableKey];
@@ -85,7 +103,13 @@ export const handleDataLinkWithTableKeys = ({
85
103
 
86
104
  if (dataLinkForm?.identification && typeof dataLinkForm.identification === 'object') {
87
105
  Object.keys(dataLinkForm.identification)
88
- .filter(fieldKey => fieldKey !== 'datastakeId' && !tableKeys.includes(fieldKey))
106
+ .filter(fieldKey => {
107
+ if (uploadTypeFields.includes(fieldKey)) {
108
+ return !isUploadFieldEmpty(fieldKey, item);
109
+ }
110
+ return true;
111
+ })
112
+ .filter(fieldKey => fieldKey !== 'datastakeId' && !processedTableKeys.includes(fieldKey))
89
113
  .filter(fieldKey => {
90
114
  const formInputConfig = dataLinkForm.identification[fieldKey];
91
115
  return formInputConfig && typeof formInputConfig === 'object' && !Array.isArray(formInputConfig);
@@ -95,9 +119,10 @@ export const handleDataLinkWithTableKeys = ({
95
119
 
96
120
  inputs[fieldKey] = {
97
121
  ...formInputConfig,
98
- label: formInputConfig.label || formInputConfig.tableLabel || fieldKey
122
+ label: uploadTypeFields.includes(fieldKey)
123
+ ? uploadTypeLabels[fieldKey]
124
+ : (formInputConfig.label || formInputConfig.tableLabel || fieldKey)
99
125
  };
100
-
101
126
  if (formInputConfig.label && typeof formInputConfig.label === 'object') {
102
127
  const dynamicLabelKeys = Object.keys(formInputConfig.label);
103
128
  let resolvedLabel = null;
@@ -112,7 +137,8 @@ export const handleDataLinkWithTableKeys = ({
112
137
  }
113
138
  }
114
139
  }
115
- inputs[fieldKey].label = resolvedLabel || Object.values(formInputConfig.label)[0] || fieldKey;
140
+ inputs[fieldKey].label = resolvedLabel || Object.values(formInputConfig.label)[0] ||
141
+ (uploadTypeFields.includes(fieldKey) ? uploadTypeLabels[fieldKey] : fieldKey);
116
142
  }
117
143
 
118
144
  values[fieldKey] = item?.[fieldKey];
@@ -127,12 +153,16 @@ export const handleDataLinkWithTableKeys = ({
127
153
  const datastakeIdValue = item?.datastakeId;
128
154
  const { inputs, values } = createInputsAndValues(item);
129
155
 
156
+ if (Object.keys(inputs).length === 0) {
157
+ return null;
158
+ }
159
+
130
160
  return (
131
161
  <TreeNodeComponent
132
162
  key={`${inputKey}-${itemIndex}`}
133
- nodeKey={datastakeIdValue || `Unknown ID ${itemIndex + 1}`}
163
+ nodeKey={datastakeIdValue || t(`No ID ${itemIndex + 1}`)}
134
164
  config={{
135
- label: datastakeIdValue || `Unknown ID ${itemIndex + 1}`,
165
+ label: datastakeIdValue || t(`No ID ${itemIndex + 1}`),
136
166
  type: 'custom-datalink',
137
167
  inputs: inputs
138
168
  }}
@@ -153,12 +183,16 @@ export const handleDataLinkWithTableKeys = ({
153
183
  const datastakeIdValue = value?.datastakeId;
154
184
  const { inputs, values } = createInputsAndValues(value);
155
185
 
186
+ if (Object.keys(inputs).length === 0) {
187
+ return null;
188
+ }
189
+
156
190
  return (
157
191
  <TreeNodeComponent
158
192
  key={`${inputKey}-single`}
159
- nodeKey={datastakeIdValue || 'Unknown ID'}
193
+ nodeKey={datastakeIdValue || t('No ID')}
160
194
  config={{
161
- label: datastakeIdValue || 'Unknown ID',
195
+ label: datastakeIdValue || t('No ID'),
162
196
  type: 'custom-datalink',
163
197
  inputs: inputs
164
198
  }}
@@ -12,14 +12,26 @@ import './style.scss';
12
12
  import { resolveDynamicLabel } from './utils.js';
13
13
  import { findOptions } from '../../../../helpers/StringHelper.js';
14
14
  import GroupInputsHandler from './components/groupInputsHandler.js';
15
+ import { handleAjaxSubGroupChildren } from './components/ajaxSubGroupHandler.js';
16
+ import { evaluateShowIfCondition } from './utils/fieldData.js';
15
17
 
16
18
  const TreeNode = ({ nodeKey, config, value, level = 0, isLast = false, t, rootForm, allData, user, getApiBaseUrl = () => {}, getAppHeader = () => {}, app }) => {
17
- const hasChildren = determineHasChildren({ config, level });
19
+ if (config.showIf && !evaluateShowIfCondition(config.showIf, allData)) {
20
+ return null;
21
+ }
22
+
23
+ const hasMetaComment = level <= 2 && allData?.meta?.[nodeKey]?.comment;
24
+
25
+ const originalHasChildren = determineHasChildren({ config, level });
26
+ const hasChildren = originalHasChildren || hasMetaComment;
27
+
18
28
  const label = resolveDynamicLabel(config?.label, allData || value, nodeKey);
19
29
  const nodeType = config?.type || 'field';
20
30
 
21
- let renderNodeValue = () => renderValue({ value, hasChildren, config, user, getApiBaseUrl, getAppHeader, app });
22
-
31
+ let renderNodeValue = () => renderValue({ value, hasChildren: originalHasChildren, config, user, getApiBaseUrl, getAppHeader, app });
32
+ if(nodeKey === 'keyIncidents') {
33
+ console.log({config, value, hasChildren})
34
+ }
23
35
 
24
36
  const renderChildren = () => {
25
37
  if (!hasChildren) return null;
@@ -39,11 +51,27 @@ const TreeNode = ({ nodeKey, config, value, level = 0, isLast = false, t, rootFo
39
51
  TreeNodeComponent: TreeNode
40
52
  });
41
53
 
42
- if (sectionChildren) {
54
+ if (config.type === 'ajaxSubGroup') {
55
+ const ajaxSubGroupChildren = handleAjaxSubGroupChildren({
56
+ config,
57
+ value,
58
+ allData,
59
+ level,
60
+ t,
61
+ rootForm,
62
+ user,
63
+ app,
64
+ getApiBaseUrl,
65
+ getAppHeader,
66
+ TreeNodeComponent: TreeNode
67
+ });
68
+
69
+ if (ajaxSubGroupChildren) {
70
+ children = ajaxSubGroupChildren;
71
+ }
72
+ } else if (sectionChildren) {
43
73
  children = sectionChildren;
44
- } else if (config.type === 'groupInputs') {
45
- console.log({value})
46
- } else if (config.type === 'dataLink' && config?.meta?.tableKeys && !config.inputs) {
74
+ } else if (config.type === 'dataLink') {
47
75
  const singleDataLinkChildren = handleDataLinkWithTableKeys({
48
76
  inputConfig: config,
49
77
  inputKey: nodeKey,
@@ -64,11 +92,20 @@ const TreeNode = ({ nodeKey, config, value, level = 0, isLast = false, t, rootFo
64
92
  }
65
93
  } else if (config?.inputs) {
66
94
  if (config.type === 'dataLinkGroup' || config.type === 'dataLink') {
67
- const inputKeys = Object.keys(config.inputs).sort((a, b) => {
68
- const positionA = config.inputs[a]?.position || 0;
69
- const positionB = config.inputs[b]?.position || 0;
70
- return positionA - positionB;
71
- });
95
+ const inputKeys = Object.keys(config.inputs)
96
+ .filter(inputKey => {
97
+ const inputConfig = config.inputs[inputKey];
98
+ // Check showIf condition for input
99
+ if (inputConfig?.showIf && !evaluateShowIfCondition(inputConfig.showIf, allData)) {
100
+ return false;
101
+ }
102
+ return true;
103
+ })
104
+ .sort((a, b) => {
105
+ const positionA = config.inputs[a]?.position || 0;
106
+ const positionB = config.inputs[b]?.position || 0;
107
+ return positionA - positionB;
108
+ });
72
109
 
73
110
  children = inputKeys.map((inputKey, index, array) => {
74
111
  const inputConfig = config.inputs[inputKey];
@@ -153,11 +190,20 @@ const TreeNode = ({ nodeKey, config, value, level = 0, isLast = false, t, rootFo
153
190
  if (arrayChildren) {
154
191
  children = arrayChildren;
155
192
  } else {
156
- const inputKeys = Object.keys(config.inputs).sort((a, b) => {
157
- const positionA = config.inputs[a]?.position || 0;
158
- const positionB = config.inputs[b]?.position || 0;
159
- return positionA - positionB;
160
- });
193
+ const inputKeys = Object.keys(config.inputs)
194
+ .filter(inputKey => {
195
+ const inputConfig = config.inputs[inputKey];
196
+ // Check showIf condition for input
197
+ if (inputConfig?.showIf && !evaluateShowIfCondition(inputConfig.showIf, allData)) {
198
+ return false;
199
+ }
200
+ return true;
201
+ })
202
+ .sort((a, b) => {
203
+ const positionA = config.inputs[a]?.position || 0;
204
+ const positionB = config.inputs[b]?.position || 0;
205
+ return positionA - positionB;
206
+ });
161
207
 
162
208
  children = inputKeys.map((inputKey, index, array) => {
163
209
  const inputConfig = config.inputs[inputKey];
@@ -208,6 +254,37 @@ const TreeNode = ({ nodeKey, config, value, level = 0, isLast = false, t, rootFo
208
254
  }
209
255
  }
210
256
 
257
+ // Ensure children is always an array before adding meta comment
258
+ if (!Array.isArray(children)) {
259
+ children = children ? [children] : [];
260
+ }
261
+
262
+ // Add meta comment as a child if it exists
263
+ if (hasMetaComment) {
264
+ const commentChild = (
265
+ <TreeNode
266
+ key={`${nodeKey}-comment`}
267
+ nodeKey="comment"
268
+ config={{
269
+ label: "Comment",
270
+ type: "field",
271
+ meta: { isComment: true } // Add a marker to identify this as a comment
272
+ }}
273
+ value={allData.meta[nodeKey].comment}
274
+ level={level + 1}
275
+ isLast={children.length === 0} // This will be the last child if no other children
276
+ t={t}
277
+ rootForm={rootForm}
278
+ allData={allData}
279
+ user={user}
280
+ app={app}
281
+ getApiBaseUrl={getApiBaseUrl}
282
+ getAppHeader={getAppHeader}
283
+ />
284
+ );
285
+ children.push(commentChild);
286
+ }
287
+
211
288
  return (
212
289
  <div className="tree-children">
213
290
  {children}
@@ -221,7 +298,7 @@ const TreeNode = ({ nodeKey, config, value, level = 0, isLast = false, t, rootFo
221
298
  };
222
299
  }
223
300
  return (
224
- <div className={`tree-node level-${level} ${hasChildren ? 'parent' : 'leaf'} ${isLast ? 'last' : ''}`}>
301
+ <div className={`tree-node level-${level} ${hasChildren ? 'parent' : 'leaf'} ${isLast ? 'last' : ''} ${nodeKey === 'comment' ? 'comment-node' : ''}`}>
225
302
  <div className="tree-node-content">
226
303
  <div className="tree-indent">
227
304
  {Array.from({ length: level }, (_, i) => (
@@ -230,7 +307,7 @@ const TreeNode = ({ nodeKey, config, value, level = 0, isLast = false, t, rootFo
230
307
  </div>
231
308
 
232
309
  <div className="tree-node-title">
233
- <span className="tree-label">{label}{!hasChildren && renderNodeValue() ? ':' : ''}</span>
310
+ <span className={`tree-label ${nodeKey === 'comment' ? 'comment-label' : ''}`}>{label}{!hasChildren && renderNodeValue() && !label.endsWith('?') ? ':' : ''}</span>
234
311
  <div className="tree-value-container">
235
312
  {renderNodeValue()}
236
313
  </div>
@@ -269,6 +346,11 @@ const PdfFormContent = ({
269
346
  <div className="pdf-tree">
270
347
  {Object.keys(form)
271
348
  .filter(sectionKey => {
349
+ const section = form[sectionKey];
350
+ // Check if section should be shown based on showIf condition
351
+ if (section?.showIf && !evaluateShowIfCondition(section.showIf, data)) {
352
+ return false;
353
+ }
272
354
  return !(sectionKey === 'id' || sectionKey === 'label' || sectionKey === 'position' || sectionKey === 'subTitle');
273
355
  })
274
356
  .sort((a, b) => {
@@ -321,11 +403,115 @@ const PdfForm = ({
321
403
  getAppHeader = () => {},
322
404
  app
323
405
  }) => {
406
+ // Group objects under headers based on position
407
+ const organizeFormByHeaders = (formData) => {
408
+ const organizedSections = {};
409
+
410
+ Object.keys(formData).forEach((sectionKey) => {
411
+ const section = formData[sectionKey];
412
+
413
+ if (typeof section !== 'object' || !section.label) {
414
+ return;
415
+ }
416
+
417
+ // Get all objects from this section and sort by position
418
+ const allObjects = Object.keys(section)
419
+ .filter(key => {
420
+ return !(key === 'id' || key === 'label' || key === 'position' || key === 'subTitle');
421
+ })
422
+ .map(key => ({
423
+ key,
424
+ ...section[key]
425
+ }))
426
+ .sort((a, b) => {
427
+ const positionA = a.position || 0;
428
+ const positionB = b.position || 0;
429
+ return positionA - positionB;
430
+ });
431
+
432
+ // Identify headers and regular objects
433
+ const headers = allObjects.filter(obj => obj.type === 'header');
434
+ const nonHeaders = allObjects.filter(obj => obj.type !== 'header');
435
+
436
+ if (headers.length === 0) {
437
+ // No headers found, keep original structure
438
+ organizedSections[sectionKey] = section;
439
+ return;
440
+ }
441
+
442
+ const organizedSection = {
443
+ ...section,
444
+ // Keep the section-level properties
445
+ };
446
+
447
+ // Clear the section of its original objects
448
+ Object.keys(section).forEach(key => {
449
+ if (!(key === 'id' || key === 'label' || key === 'position' || key === 'subTitle')) {
450
+ delete organizedSection[key];
451
+ }
452
+ });
453
+
454
+ headers.forEach((header, index) => {
455
+ const headerPosition = header.position || 0;
456
+ const nextHeaderPosition = index < headers.length - 1
457
+ ? (headers[index + 1].position || 0)
458
+ : Infinity;
459
+
460
+ // Find objects that belong under this header
461
+ const childrenObjects = nonHeaders.filter(obj => {
462
+ const objPosition = obj.position || 0;
463
+ return objPosition > headerPosition && objPosition < nextHeaderPosition;
464
+ });
465
+
466
+ // Create the header structure with children as inputs
467
+ const headerWithChildren = { ...header };
468
+ delete headerWithChildren.key; // Remove the key we added temporarily
469
+
470
+ if (childrenObjects.length > 0) {
471
+ headerWithChildren.inputs = {};
472
+ childrenObjects.forEach(child => {
473
+ const childKey = child.key;
474
+ const childData = { ...child };
475
+ delete childData.key; // Remove the temporary key
476
+ headerWithChildren.inputs[childKey] = childData;
477
+ });
478
+ }
479
+
480
+ organizedSection[header.key] = headerWithChildren;
481
+ });
482
+
483
+ // Add any remaining objects that don't fall under any header
484
+ const uncategorizedObjects = nonHeaders.filter(obj => {
485
+ const objPosition = obj.position || 0;
486
+ return !headers.some((header, index) => {
487
+ const headerPosition = header.position || 0;
488
+ const nextHeaderPosition = index < headers.length - 1
489
+ ? (headers[index + 1].position || 0)
490
+ : Infinity;
491
+ return objPosition > headerPosition && objPosition < nextHeaderPosition;
492
+ });
493
+ });
494
+
495
+ uncategorizedObjects.forEach(obj => {
496
+ const objKey = obj.key;
497
+ const objData = { ...obj };
498
+ delete objData.key;
499
+ organizedSection[objKey] = objData;
500
+ });
501
+
502
+ organizedSections[sectionKey] = organizedSection;
503
+ });
504
+
505
+ return organizedSections;
506
+ };
507
+
508
+ const organizedForm = useMemo(() => organizeFormByHeaders(form), [form]);
509
+
324
510
  const pdfConfig = useMemo(() => {
325
511
  const sections = [];
326
512
 
327
- Object.keys(form).forEach((sectionKey) => {
328
- const section = form[sectionKey];
513
+ Object.keys(organizedForm).forEach((sectionKey) => {
514
+ const section = organizedForm[sectionKey];
329
515
 
330
516
  if (typeof section !== 'object' || !section.label) {
331
517
  return;
@@ -356,7 +542,7 @@ const PdfForm = ({
356
542
  });
357
543
 
358
544
  return sections;
359
- }, [form, data, t, getApiBaseUrl, getAppHeader, app]);
545
+ }, [organizedForm, data, t, getApiBaseUrl, getAppHeader, app, formName, source, version]);
360
546
 
361
547
  return (
362
548
  <PdfView