df-ae-forms-package 1.0.96 → 1.0.98
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/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +16 -5
- package/dist/index.esm.js +147 -223
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +145 -221
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4334,57 +4334,20 @@ const DraggableGridComponent = ({ component, selectedComponent, mode, onComponen
|
|
|
4334
4334
|
e.currentTarget.style.backgroundColor = '#ef4444';
|
|
4335
4335
|
}, children: jsxRuntime.jsx(lucideReact.Trash2, { size: 12 }) })] }))] }));
|
|
4336
4336
|
};
|
|
4337
|
-
|
|
4338
|
-
const GridDropZone = ({ gridComponents, mode, onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, selectedComponent, renderFormComponent, gridId, formData, formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChange, onAttachmentChange, columnView, shouldShowComponent }) => {
|
|
4337
|
+
const GridDropZone = ({ gridComponents, mode, onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, selectedComponent, renderFormComponent, gridId, formData = {}, formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChange, onAttachmentChange, columnView = false, shouldShowComponent }) => {
|
|
4339
4338
|
const { setNodeRef, isOver } = core.useDroppable({
|
|
4340
4339
|
id: `grid-drop-zone-${gridId}`,
|
|
4341
|
-
disabled: mode !== 'edit'
|
|
4342
|
-
data: {
|
|
4343
|
-
isGridDropZone: true,
|
|
4344
|
-
gridId: gridId
|
|
4345
|
-
}
|
|
4346
|
-
});
|
|
4347
|
-
// Sensors for drag and drop
|
|
4348
|
-
const sensors = core.useSensors(core.useSensor(core.PointerSensor, {
|
|
4349
|
-
activationConstraint: {
|
|
4350
|
-
distance: 8,
|
|
4351
|
-
},
|
|
4352
|
-
}), core.useSensor(core.KeyboardSensor, {
|
|
4353
|
-
coordinateGetter: sortable.sortableKeyboardCoordinates,
|
|
4354
|
-
}));
|
|
4355
|
-
const handleDragEnd = ((event) => {
|
|
4356
|
-
const { active, over } = event;
|
|
4357
|
-
if (over && active.id !== over.id) {
|
|
4358
|
-
gridComponents.findIndex((item) => item.id === active.id);
|
|
4359
|
-
gridComponents.findIndex((item) => item.id === over.id);
|
|
4360
|
-
}
|
|
4340
|
+
disabled: mode !== 'edit'
|
|
4361
4341
|
});
|
|
4362
|
-
return (jsxRuntime.jsx("div", { ref: setNodeRef, className:
|
|
4363
|
-
border: isOver ? '2px dashed #3b82f6' : '
|
|
4342
|
+
return (jsxRuntime.jsx("div", { ref: setNodeRef, className: "grid-drop-zone", style: {
|
|
4343
|
+
border: isOver ? '2px dashed #3b82f6' : '2px dashed #d1d5db',
|
|
4364
4344
|
borderRadius: '8px',
|
|
4365
4345
|
padding: '16px',
|
|
4366
|
-
backgroundColor: isOver ? 'var(--df-color-primary-light)' : '
|
|
4367
|
-
minHeight: '
|
|
4368
|
-
transition: 'all 0.2s ease'
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
color: 'var(--df-color-text-light)',
|
|
4372
|
-
fontSize: '14px',
|
|
4373
|
-
padding: '40px 20px',
|
|
4374
|
-
display: 'flex',
|
|
4375
|
-
flexDirection: 'column',
|
|
4376
|
-
alignItems: 'center',
|
|
4377
|
-
gap: '8px',
|
|
4378
|
-
backgroundColor: 'var(--df-color-fb-container)',
|
|
4379
|
-
border: '1px dashed var(--df-color-fb-border)',
|
|
4380
|
-
borderRadius: '8px'
|
|
4381
|
-
}, children: [jsxRuntime.jsx("div", { style: {
|
|
4382
|
-
fontWeight: '500',
|
|
4383
|
-
color: isOver ? 'var(--df-color-primary)' : 'var(--df-color-text-dark)'
|
|
4384
|
-
}, children: isOver ? 'Drop components here' : 'Empty DataGrid' }), jsxRuntime.jsx("div", { style: {
|
|
4385
|
-
fontSize: '12px',
|
|
4386
|
-
color: '#9ca3af'
|
|
4387
|
-
}, children: "Drag and drop components here to create your grid" })] })) : (jsxRuntime.jsxs(core.DndContext, { sensors: sensors, onDragEnd: handleDragEnd, children: [jsxRuntime.jsx(sortable.SortableContext, { items: gridComponents.map(c => c.id), strategy: columnView ? sortable.verticalListSortingStrategy : sortable.horizontalListSortingStrategy, children: jsxRuntime.jsx("div", { style: {
|
|
4346
|
+
backgroundColor: isOver ? 'var(--df-color-primary-light)' : 'var(--df-color-fb-container)',
|
|
4347
|
+
minHeight: '120px',
|
|
4348
|
+
transition: 'all 0.2s ease',
|
|
4349
|
+
position: 'relative'
|
|
4350
|
+
}, children: gridComponents.length > 0 ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(sortable.SortableContext, { items: gridComponents.map(c => c.id), strategy: sortable.horizontalListSortingStrategy, children: jsxRuntime.jsx("div", { style: {
|
|
4388
4351
|
display: 'flex',
|
|
4389
4352
|
flexDirection: columnView ? 'column' : 'row',
|
|
4390
4353
|
flexWrap: 'nowrap',
|
|
@@ -4409,14 +4372,28 @@ const GridDropZone = ({ gridComponents, mode, onComponentSelect, onComponentDele
|
|
|
4409
4372
|
minHeight: '40px',
|
|
4410
4373
|
display: 'flex',
|
|
4411
4374
|
alignItems: 'center',
|
|
4412
|
-
justifyContent: 'center'
|
|
4413
|
-
|
|
4414
|
-
|
|
4375
|
+
justifyContent: 'center'
|
|
4376
|
+
}, children: isOver ? (jsxRuntime.jsx("span", { style: { color: '#3b82f6', fontWeight: '500' }, children: "Drop component here to add to grid" })) : (jsxRuntime.jsx("span", { children: "+ Drop more components here" })) })] })) : (jsxRuntime.jsxs("div", { style: {
|
|
4377
|
+
textAlign: 'center',
|
|
4378
|
+
color: 'var(--df-color-text-light)',
|
|
4379
|
+
fontSize: '14px',
|
|
4380
|
+
padding: '40px 20px',
|
|
4381
|
+
display: 'flex',
|
|
4382
|
+
flexDirection: 'column',
|
|
4383
|
+
alignItems: 'center',
|
|
4384
|
+
gap: '8px',
|
|
4385
|
+
backgroundColor: 'var(--df-color-fb-container)',
|
|
4386
|
+
border: '1px dashed var(--df-color-fb-border)',
|
|
4387
|
+
borderRadius: '8px'
|
|
4388
|
+
}, children: [jsxRuntime.jsx("div", { style: {
|
|
4389
|
+
fontWeight: '500',
|
|
4390
|
+
color: isOver ? 'var(--df-color-primary)' : 'var(--df-color-text-dark)'
|
|
4391
|
+
}, children: isOver ? 'Drop components here' : 'Empty DataGrid' }), jsxRuntime.jsx("div", { style: {
|
|
4392
|
+
fontSize: '12px',
|
|
4393
|
+
color: '#9ca3af'
|
|
4394
|
+
}, children: "Drag and drop components here to create your grid" })] })) }));
|
|
4415
4395
|
};
|
|
4416
|
-
|
|
4417
|
-
const TableView = ({ templateComponents, dataEntries, renderFormComponent, mode, allowAddRemoveEntries, addAnotherText, removeText, maxEntries, minEntries, displayAsGrid = true, onAddEntry, onRemoveEntry, formData, // Use current formData to render values
|
|
4418
|
-
formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChange, onAttachmentChange, columnView, shouldShowComponent }) => {
|
|
4419
|
-
const _formData = formData || {};
|
|
4396
|
+
const TableView = ({ templateComponents, dataEntries, renderFormComponent, mode = 'preview', allowAddRemoveEntries = true, addAnotherText = 'Add Another', removeText = 'Remove', maxEntries = 10, minEntries = 1, displayAsGrid = true, onAddEntry, onRemoveEntry, formData: _formData = {}, formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChange, onAttachmentChange, columnView = false, shouldShowComponent }) => {
|
|
4420
4397
|
const visibleTemplateComponents = React.useMemo(() => {
|
|
4421
4398
|
if (!shouldShowComponent)
|
|
4422
4399
|
return templateComponents;
|
|
@@ -4478,18 +4455,16 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
|
|
|
4478
4455
|
whiteSpace: 'nowrap',
|
|
4479
4456
|
overflow: 'hidden',
|
|
4480
4457
|
textOverflow: 'ellipsis'
|
|
4481
|
-
}, children: component.basic?.label || `Column ${index + 1}` }, `header-${component.id
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
: undefined,
|
|
4458
|
+
}, children: component.basic?.label || `Column ${index + 1}` }, `header-${component.id}`))) })), dataEntries.length > 0 ? (dataEntries.map((entry, entryIndex) => (jsxRuntime.jsxs("div", { className: "table-row", style: {
|
|
4459
|
+
display: 'grid',
|
|
4460
|
+
// Change grid columns to 1fr for column view
|
|
4461
|
+
gridTemplateColumns: columnView
|
|
4462
|
+
? '1fr'
|
|
4463
|
+
: `repeat(${visibleTemplateComponents.length}, minmax(150px, 1fr))`,
|
|
4488
4464
|
borderBottom: entryIndex < dataEntries.length - 1 ? '1px solid var(--df-color-fb-border)' : 'none',
|
|
4489
4465
|
backgroundColor: entryIndex % 2 === 0 ? 'var(--df-color-fb-container)' : 'var(--df-color-fb-bg)',
|
|
4490
4466
|
position: 'relative',
|
|
4491
|
-
minWidth: columnView ? '100%' : `${visibleTemplateComponents.length * 150}px
|
|
4492
|
-
padding: columnView ? '16px' : '0'
|
|
4467
|
+
minWidth: columnView ? '100%' : `${visibleTemplateComponents.length * 150}px`
|
|
4493
4468
|
}, children: [visibleTemplateComponents.map((templateComponent, componentIndex) => {
|
|
4494
4469
|
let entryComponent = entry.components?.[componentIndex];
|
|
4495
4470
|
if (!entryComponent) {
|
|
@@ -4515,24 +4490,21 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
|
|
|
4515
4490
|
};
|
|
4516
4491
|
}
|
|
4517
4492
|
return (jsxRuntime.jsx("div", { style: {
|
|
4518
|
-
padding:
|
|
4493
|
+
padding: '12px 16px',
|
|
4519
4494
|
borderRight: !columnView && componentIndex < visibleTemplateComponents.length - 1 ? '1px solid var(--df-color-fb-border)' : 'none',
|
|
4520
4495
|
// Add bottom border for fields in column view except the last one
|
|
4521
4496
|
borderBottom: columnView && componentIndex < visibleTemplateComponents.length - 1 ? '1px dashed var(--df-color-fb-border)' : 'none',
|
|
4522
|
-
minHeight:
|
|
4497
|
+
minHeight: '60px',
|
|
4523
4498
|
minWidth: columnView ? '100%' : '150px',
|
|
4524
|
-
width: columnView ? '100%' : 'auto',
|
|
4525
4499
|
display: 'flex',
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
overflow: 'hidden',
|
|
4529
|
-
gap: columnView ? '8px' : '0'
|
|
4500
|
+
alignItems: 'center',
|
|
4501
|
+
overflow: 'hidden'
|
|
4530
4502
|
}, children: jsxRuntime.jsx("div", { style: {
|
|
4531
4503
|
width: '100%',
|
|
4532
|
-
minWidth:
|
|
4504
|
+
minWidth: '120px',
|
|
4533
4505
|
overflow: 'hidden'
|
|
4534
4506
|
}, children: renderFormComponent(entryComponent, !columnView) }) }, `${entry.id}-${componentIndex}`));
|
|
4535
|
-
}), mode === 'test' && allowAddRemoveEntries && dataEntries.length > minEntries && (jsxRuntime.jsx("button", { onClick: () => onRemoveEntry(entryIndex), disabled: dataEntries.length <= minEntries, style: {
|
|
4507
|
+
}), mode === 'test' && allowAddRemoveEntries && dataEntries.length > minEntries && (jsxRuntime.jsx("button", { onClick: () => onRemoveEntry?.(entryIndex), disabled: dataEntries.length <= minEntries, style: {
|
|
4536
4508
|
position: 'absolute',
|
|
4537
4509
|
top: '8px',
|
|
4538
4510
|
right: '8px',
|
|
@@ -4566,7 +4538,7 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
|
|
|
4566
4538
|
position: 'sticky',
|
|
4567
4539
|
bottom: 0,
|
|
4568
4540
|
zIndex: 5
|
|
4569
|
-
}, children: jsxRuntime.jsxs("button", { onClick:
|
|
4541
|
+
}, children: jsxRuntime.jsxs("button", { onClick: onAddEntry, disabled: dataEntries.length >= maxEntries, style: {
|
|
4570
4542
|
padding: '8px 16px',
|
|
4571
4543
|
backgroundColor: dataEntries.length >= maxEntries ? '#f3f4f6' : '#10b981',
|
|
4572
4544
|
color: dataEntries.length >= maxEntries ? '#9ca3af' : '#ffffff',
|
|
@@ -4604,7 +4576,7 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
|
|
|
4604
4576
|
fontWeight: '600',
|
|
4605
4577
|
color: 'var(--df-color-text-dark)',
|
|
4606
4578
|
fontSize: '14px'
|
|
4607
|
-
}, children: ["Entry #", entryIndex + 1] }), mode === 'test' && allowAddRemoveEntries && dataEntries.length > 1 && (jsxRuntime.jsx("button", { onClick: () => onRemoveEntry(entryIndex), disabled: dataEntries.length <= minEntries, style: {
|
|
4579
|
+
}, children: ["Entry #", entryIndex + 1] }), mode === 'test' && allowAddRemoveEntries && dataEntries.length > 1 && (jsxRuntime.jsx("button", { onClick: () => onRemoveEntry?.(entryIndex), disabled: dataEntries.length <= minEntries, style: {
|
|
4608
4580
|
padding: '4px 8px',
|
|
4609
4581
|
backgroundColor: dataEntries.length <= minEntries ? '#f3f4f6' : '#ef4444',
|
|
4610
4582
|
color: dataEntries.length <= minEntries ? '#9ca3af' : '#ffffff',
|
|
@@ -4620,39 +4592,40 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
|
|
|
4620
4592
|
height: '24px',
|
|
4621
4593
|
justifyContent: 'center'
|
|
4622
4594
|
}, title: removeText, children: jsxRuntime.jsx("span", { style: { fontSize: '14px' }, children: "\u00D7" }) }))] }), jsxRuntime.jsx("div", { style: {
|
|
4623
|
-
display:
|
|
4624
|
-
|
|
4625
|
-
gridTemplateColumns: !columnView ? 'repeat(auto-fit, minmax(200px, 1fr))' : undefined,
|
|
4595
|
+
display: 'grid',
|
|
4596
|
+
gridTemplateColumns: columnView ? '1fr' : 'repeat(auto-fit, minmax(200px, 1fr))',
|
|
4626
4597
|
gap: '16px'
|
|
4627
4598
|
}, children: visibleTemplateComponents.map((templateComponent, componentIndex) => {
|
|
4599
|
+
// Find the corresponding component in this entry by index first, then by name+label
|
|
4628
4600
|
let entryComponent = entry.components?.[componentIndex];
|
|
4601
|
+
// If no component at this index, try to find by name+label
|
|
4629
4602
|
if (!entryComponent) {
|
|
4630
4603
|
entryComponent = entry.components?.find((comp) => comp.name === templateComponent.name &&
|
|
4631
4604
|
comp.basic?.label === templateComponent.basic?.label);
|
|
4632
4605
|
}
|
|
4633
4606
|
if (!entryComponent) {
|
|
4607
|
+
// Use entry.id (which is unique) instead of entryIndex
|
|
4634
4608
|
const uniqueId = `${templateComponent.id}-${entry.id}-${componentIndex}`;
|
|
4635
4609
|
entryComponent = {
|
|
4636
4610
|
...templateComponent,
|
|
4637
4611
|
id: uniqueId,
|
|
4638
4612
|
basic: {
|
|
4639
4613
|
...templateComponent.basic,
|
|
4640
|
-
showLabel:
|
|
4614
|
+
showLabel: false // Hide label in datagrid cells
|
|
4641
4615
|
}
|
|
4642
4616
|
};
|
|
4643
4617
|
}
|
|
4644
4618
|
else {
|
|
4619
|
+
// Preserve the original ID to maintain form value connections
|
|
4645
4620
|
entryComponent = {
|
|
4646
4621
|
...entryComponent,
|
|
4647
|
-
id: entryComponent.id,
|
|
4622
|
+
id: entryComponent.id, // Keep the original ID
|
|
4648
4623
|
basic: {
|
|
4649
4624
|
...entryComponent.basic,
|
|
4650
|
-
showLabel:
|
|
4625
|
+
showLabel: false // Hide label in datagrid cells
|
|
4651
4626
|
}
|
|
4652
4627
|
};
|
|
4653
4628
|
}
|
|
4654
|
-
if (!entryComponent)
|
|
4655
|
-
return null;
|
|
4656
4629
|
return (jsxRuntime.jsxs("div", { style: {
|
|
4657
4630
|
display: 'flex',
|
|
4658
4631
|
flexDirection: 'column',
|
|
@@ -4688,7 +4661,7 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
|
|
|
4688
4661
|
borderRadius: '8px',
|
|
4689
4662
|
display: 'flex',
|
|
4690
4663
|
justifyContent: 'center'
|
|
4691
|
-
}, children: jsxRuntime.jsxs("button", { onClick:
|
|
4664
|
+
}, children: jsxRuntime.jsxs("button", { onClick: onAddEntry, disabled: dataEntries.length >= maxEntries, style: {
|
|
4692
4665
|
padding: '8px 16px',
|
|
4693
4666
|
backgroundColor: dataEntries.length >= maxEntries ? '#f3f4f6' : '#10b981',
|
|
4694
4667
|
color: dataEntries.length >= maxEntries ? '#9ca3af' : '#ffffff',
|
|
@@ -4701,19 +4674,11 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
|
|
|
4701
4674
|
alignItems: 'center',
|
|
4702
4675
|
gap: '8px',
|
|
4703
4676
|
transition: 'all 0.2s ease'
|
|
4704
|
-
}, onMouseEnter: (e) => {
|
|
4705
|
-
if (dataEntries.length < maxEntries) {
|
|
4706
|
-
e.currentTarget.style.backgroundColor = '#059669';
|
|
4707
|
-
}
|
|
4708
|
-
}, onMouseLeave: (e) => {
|
|
4709
|
-
e.currentTarget.style.backgroundColor = '#10b981';
|
|
4710
4677
|
}, children: [jsxRuntime.jsx("span", { children: "+" }), addAnotherText] }) }))] }));
|
|
4711
4678
|
};
|
|
4712
4679
|
const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueChange, onSelect, isSelected = false, className = '', onDataGridSelect, onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, selectedComponent, renderFormComponent, onEntryAdd, onEntryRemove, formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChange, onAttachmentChange, shouldShowComponent }) => {
|
|
4713
4680
|
const [isCollapsed, setIsCollapsed] = React.useState(false);
|
|
4714
4681
|
const hasInitialized = React.useRef(false);
|
|
4715
|
-
// Track local form values for entry components to prevent value loss during parent round-trip
|
|
4716
|
-
const localFormValuesRef = React.useRef({});
|
|
4717
4682
|
// Get all components in the grid and sanitize them to ensure no data leaks into templates
|
|
4718
4683
|
let gridComponents = (properties.templateComponents || []).map(comp => ({
|
|
4719
4684
|
...comp,
|
|
@@ -4791,6 +4756,87 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
|
|
|
4791
4756
|
}
|
|
4792
4757
|
}
|
|
4793
4758
|
}
|
|
4759
|
+
else {
|
|
4760
|
+
// Update existing entries to include all template components and sync their properties
|
|
4761
|
+
const needsUpdate = dataEntries.some(entry => {
|
|
4762
|
+
// Check if entry is missing any template components or if existing components need updates
|
|
4763
|
+
return gridComponents.some((templateComp, componentIndex) => {
|
|
4764
|
+
const existingComponent = entry.components?.[componentIndex];
|
|
4765
|
+
if (!existingComponent) {
|
|
4766
|
+
return true; // Missing component at this index
|
|
4767
|
+
}
|
|
4768
|
+
// We don't check for ID matches here anymore
|
|
4769
|
+
// const expectedId = `${templateComp.id}-entry-${entry.index}-${componentIndex}`
|
|
4770
|
+
// const hasProperId = existingComponent.id === expectedId
|
|
4771
|
+
// Check if existing component needs to be updated with new template properties
|
|
4772
|
+
// Compare key properties that should be synced
|
|
4773
|
+
const needsPropertyUpdate = JSON.stringify(existingComponent.basic?.options) !== JSON.stringify(templateComp.basic?.options) ||
|
|
4774
|
+
existingComponent.basic?.placeholder !== templateComp.basic?.placeholder ||
|
|
4775
|
+
existingComponent.basic?.defaultValue !== templateComp.basic?.defaultValue ||
|
|
4776
|
+
existingComponent.basic?.label !== templateComp.basic?.label ||
|
|
4777
|
+
existingComponent.validation?.required !== templateComp.validation?.required;
|
|
4778
|
+
// We do not check for ID mismatch anymore as we want to preserve unique IDs
|
|
4779
|
+
return needsPropertyUpdate;
|
|
4780
|
+
});
|
|
4781
|
+
});
|
|
4782
|
+
if (needsUpdate && onValueChange) {
|
|
4783
|
+
const updatedEntries = dataEntries.map(entry => {
|
|
4784
|
+
// Use index-based matching to ensure each template component maps to the correct entry component
|
|
4785
|
+
const updatedComponents = gridComponents.map((templateComp, componentIndex) => {
|
|
4786
|
+
// Find existing component by index first
|
|
4787
|
+
let existingComponent = entry.components?.[componentIndex];
|
|
4788
|
+
// If no component at this index, try to find by name+label (for backward compatibility)
|
|
4789
|
+
if (!existingComponent) {
|
|
4790
|
+
existingComponent = entry.components?.find((comp) => comp.name === templateComp.name &&
|
|
4791
|
+
comp.basic?.label === templateComp.basic?.label);
|
|
4792
|
+
}
|
|
4793
|
+
// Always ensure a valid ID exists, but respect existing one if possible
|
|
4794
|
+
// const uniqueId = `${templateComp.id}-entry-${entry.index}-${componentIndex}`
|
|
4795
|
+
if (existingComponent) {
|
|
4796
|
+
// Update existing component with new template properties while ensuring unique ID and preserving form values
|
|
4797
|
+
const updatedComponent = {
|
|
4798
|
+
...templateComp,
|
|
4799
|
+
id: existingComponent.id, // Preserve existing ID !!
|
|
4800
|
+
basic: {
|
|
4801
|
+
...templateComp.basic,
|
|
4802
|
+
showLabel: false, // Hide label in datagrid cells
|
|
4803
|
+
// Preserve any user-entered values
|
|
4804
|
+
value: existingComponent.basic?.value || templateComp.basic?.defaultValue || ''
|
|
4805
|
+
}
|
|
4806
|
+
};
|
|
4807
|
+
return updatedComponent;
|
|
4808
|
+
}
|
|
4809
|
+
else {
|
|
4810
|
+
// Create new component based on template
|
|
4811
|
+
// Only for NEW components in existing entries (e.g. column added) do we generate a new ID
|
|
4812
|
+
const uniqueSuffix = `${Date.now()}-${Math.random().toString(36).substr(2, 5)}`;
|
|
4813
|
+
const newId = `${templateComp.id}-${uniqueSuffix}-${componentIndex}`;
|
|
4814
|
+
const newComponent = {
|
|
4815
|
+
...templateComp,
|
|
4816
|
+
id: newId,
|
|
4817
|
+
basic: {
|
|
4818
|
+
...templateComp.basic,
|
|
4819
|
+
showLabel: false // Hide label in datagrid cells
|
|
4820
|
+
}
|
|
4821
|
+
};
|
|
4822
|
+
return newComponent;
|
|
4823
|
+
}
|
|
4824
|
+
});
|
|
4825
|
+
return {
|
|
4826
|
+
...entry,
|
|
4827
|
+
components: updatedComponents
|
|
4828
|
+
};
|
|
4829
|
+
});
|
|
4830
|
+
const newValue = { ...properties, entries: updatedEntries };
|
|
4831
|
+
// Only call onValueChange if the data actually changed
|
|
4832
|
+
if (JSON.stringify(newValue) !== JSON.stringify(properties)) {
|
|
4833
|
+
onValueChange({
|
|
4834
|
+
id,
|
|
4835
|
+
value: newValue
|
|
4836
|
+
});
|
|
4837
|
+
}
|
|
4838
|
+
}
|
|
4839
|
+
}
|
|
4794
4840
|
}
|
|
4795
4841
|
}, [gridComponents, dataEntries, id, onValueChange, properties, mode, properties.templateComponents]);
|
|
4796
4842
|
const handleDataGridClick = React.useCallback((event) => {
|
|
@@ -4847,9 +4893,8 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
|
|
|
4847
4893
|
// Handle component value change for form data updates (test mode)
|
|
4848
4894
|
const handleComponentValueChange = React.useCallback((change) => {
|
|
4849
4895
|
if (mode === 'test') {
|
|
4850
|
-
//
|
|
4851
|
-
|
|
4852
|
-
// Also propagate up to parent for persistence
|
|
4896
|
+
// In test mode, update form data through the parent's onValueChange
|
|
4897
|
+
// This allows the form data to be updated for interactive components
|
|
4853
4898
|
if (onValueChange) {
|
|
4854
4899
|
onValueChange({
|
|
4855
4900
|
id: change.id,
|
|
@@ -4860,10 +4905,6 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
|
|
|
4860
4905
|
// In edit/preview modes, don't handle value changes as components are read-only
|
|
4861
4906
|
}, [mode, onValueChange]);
|
|
4862
4907
|
const handleAddEntry = React.useCallback(() => {
|
|
4863
|
-
console.log('[DfFormDataGrid] handleAddEntry called');
|
|
4864
|
-
console.log('[DfFormDataGrid] gridComponents:', gridComponents.length, gridComponents.map(c => c.id));
|
|
4865
|
-
console.log('[DfFormDataGrid] current entries:', properties.entries?.length);
|
|
4866
|
-
console.log('[DfFormDataGrid] onValueChange exists:', !!onValueChange);
|
|
4867
4908
|
// Use timestamp and random string to ensure uniqueness even if entries are deleted
|
|
4868
4909
|
const uniqueSuffix = `${Date.now()}-${Math.random().toString(36).substr(2, 5)}`;
|
|
4869
4910
|
const newEntryId = `entry-${uniqueSuffix}`;
|
|
@@ -4885,19 +4926,13 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
|
|
|
4885
4926
|
}),
|
|
4886
4927
|
styles: {}
|
|
4887
4928
|
};
|
|
4888
|
-
console.log('[DfFormDataGrid] newEntry created:', newEntry.id, 'with', newEntry.components.length, 'components');
|
|
4889
4929
|
const updatedEntries = [...properties.entries, newEntry];
|
|
4890
|
-
console.log('[DfFormDataGrid] updatedEntries count:', updatedEntries.length);
|
|
4891
4930
|
if (onValueChange) {
|
|
4892
|
-
console.log('[DfFormDataGrid] calling onValueChange with updated entries');
|
|
4893
4931
|
onValueChange({
|
|
4894
4932
|
id,
|
|
4895
4933
|
value: { ...properties, entries: updatedEntries }
|
|
4896
4934
|
});
|
|
4897
4935
|
}
|
|
4898
|
-
else {
|
|
4899
|
-
console.log('[DfFormDataGrid] WARNING: onValueChange is not defined!');
|
|
4900
|
-
}
|
|
4901
4936
|
onEntryAdd?.();
|
|
4902
4937
|
}, [properties, onValueChange, id, onEntryAdd, gridComponents]);
|
|
4903
4938
|
const handleRemoveEntry = React.useCallback((entryIndex) => {
|
|
@@ -4913,11 +4948,7 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
|
|
|
4913
4948
|
}, [properties, onValueChange, id, onEntryRemove]);
|
|
4914
4949
|
// Use our own render function to ensure proper onComponentUpdate handling
|
|
4915
4950
|
const renderComponent = React.useCallback((field, hideLabel = false) => {
|
|
4916
|
-
|
|
4917
|
-
// This ensures typed values in entry 2+ persist immediately
|
|
4918
|
-
const formValue = mode === 'test'
|
|
4919
|
-
? (localFormValuesRef.current[field.id] ?? formData[field.id] ?? field.basic?.value ?? ('defaultValue' in field.basic ? field.basic.defaultValue || '' : ''))
|
|
4920
|
-
: ('defaultValue' in field.basic ? field.basic.defaultValue || '' : '');
|
|
4951
|
+
const formValue = mode === 'test' ? (formData[field.id] || ('defaultValue' in field.basic ? field.basic.defaultValue || '' : '')) : ('defaultValue' in field.basic ? field.basic.defaultValue || '' : '');
|
|
4921
4952
|
const commonProps = {
|
|
4922
4953
|
id: field.id,
|
|
4923
4954
|
properties: field,
|
|
@@ -4998,7 +5029,7 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
|
|
|
4998
5029
|
, {
|
|
4999
5030
|
// Cast to FormComponentType[] to satisfy TableView typing; gridComponents
|
|
5000
5031
|
// are always child form components of the datagrid.
|
|
5001
|
-
templateComponents: gridComponents, dataEntries: dataEntries, renderFormComponent: renderFormComponent || renderComponent, mode: mode, allowAddRemoveEntries: properties.datagrid?.allowAddRemoveEntries ?? true, addAnotherText: properties.datagrid?.addAnotherText ?? 'Add Entry', removeText: properties.datagrid?.removeText ?? 'Remove', maxEntries: properties.datagrid?.maxEntries ?? 10, minEntries: properties.datagrid?.minEntries ?? 1, displayAsGrid: properties.datagrid?.displayAsGrid ?? true, onAddEntry: handleAddEntry, onRemoveEntry: handleRemoveEntry, formData: formData, formTemplateId: formTemplateId, onThresholdActionCompletion: onThresholdActionCompletion, onThresholdIssueRaised: onThresholdIssueRaised, onNotesChange: onNotesChange, onAttachmentChange: onAttachmentChange, columnView: properties.datagrid?.columnView, shouldShowComponent: shouldShowComponent })) }))] }));
|
|
5032
|
+
templateComponents: gridComponents, dataEntries: dataEntries, renderFormComponent: renderFormComponent || renderComponent, mode: mode, allowAddRemoveEntries: properties.datagrid?.allowAddRemoveEntries ?? true, addAnotherText: properties.datagrid?.addAnotherText ?? 'Add Entry', removeText: properties.datagrid?.removeText ?? 'Remove', maxEntries: properties.datagrid?.maxEntries ?? 10, minEntries: properties.datagrid?.minEntries ?? 1, displayAsGrid: properties.datagrid?.displayAsGrid ?? true, onAddEntry: onEntryAdd ? onEntryAdd : handleAddEntry, onRemoveEntry: onEntryRemove ? onEntryRemove : handleRemoveEntry, formData: formData, formTemplateId: formTemplateId, onThresholdActionCompletion: onThresholdActionCompletion, onThresholdIssueRaised: onThresholdIssueRaised, onNotesChange: onNotesChange, onAttachmentChange: onAttachmentChange, columnView: properties.datagrid?.columnView, shouldShowComponent: shouldShowComponent })) }))] }));
|
|
5002
5033
|
};
|
|
5003
5034
|
|
|
5004
5035
|
const DraggableChild = ({ child, selectedChild, mode, onChildSelect, onChildDelete, renderFormComponent, isOverlay = false, isChildrenEditMode = false, formData = {}, formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChange, onAttachmentChange, workOrderNumber, assetNumber, user, onCreateIssue, onUpdateIssue }) => {
|
|
@@ -6421,9 +6452,12 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
6421
6452
|
onFormDataChange?.(updatedComponents);
|
|
6422
6453
|
} }) }));
|
|
6423
6454
|
case 'datagrid':
|
|
6455
|
+
// Align package datagrid wiring with main app behaviour:
|
|
6456
|
+
// - Let DfFormDataGrid manage entry structure via onValueChange
|
|
6457
|
+
// - Use the shared onFormValueChange handler for nested field values
|
|
6458
|
+
// - Keep notes/attachments wiring as before
|
|
6424
6459
|
return (jsxRuntime.jsx(DfFormDataGrid, { ...commonProps, properties: component, formData: formValues, formTemplateId: formTemplateId, mode: commonProps.mode, onThresholdActionCompletion: handleThresholdActionCompletion, onThresholdIssueRaised: handleThresholdIssueRaised, onNotesChange: (componentId, notes) => {
|
|
6425
6460
|
handleComponentNotesChange(componentId, notes);
|
|
6426
|
-
// Handle notes change for datagrid entry components
|
|
6427
6461
|
const updatedComponents = localFormComponents.map(comp => {
|
|
6428
6462
|
if (comp.id === component.id && comp.entries) {
|
|
6429
6463
|
const updatedEntries = comp.entries.map((entry) => {
|
|
@@ -6451,7 +6485,6 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
6451
6485
|
onFormDataChange?.(updatedComponents);
|
|
6452
6486
|
}, onAttachmentChange: (componentId, attachments) => {
|
|
6453
6487
|
handleComponentAttachmentChange(componentId, attachments);
|
|
6454
|
-
// Handle attachment change for datagrid entry components
|
|
6455
6488
|
const updatedComponents = localFormComponents.map(comp => {
|
|
6456
6489
|
if (comp.id === component.id && comp.entries) {
|
|
6457
6490
|
const updatedEntries = comp.entries.map((entry) => {
|
|
@@ -6477,116 +6510,7 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
6477
6510
|
return comp;
|
|
6478
6511
|
});
|
|
6479
6512
|
onFormDataChange?.(updatedComponents);
|
|
6480
|
-
}, onValueChange: (
|
|
6481
|
-
console.log('[DfFormPreview] datagrid onValueChange received:', change.id, 'hasEntries:', change.value && typeof change.value === 'object' && 'entries' in change.value);
|
|
6482
|
-
// Handle datagrid value changes (entries updates)
|
|
6483
|
-
if (change.id === component.id && change.value && typeof change.value === 'object' && 'entries' in change.value) {
|
|
6484
|
-
console.log('[DfFormPreview] datagrid entries update - entries count:', change.value.entries?.length);
|
|
6485
|
-
// Update localFormComponents with new entries structure
|
|
6486
|
-
const updatedComponents = localFormComponents.map(comp => {
|
|
6487
|
-
if (comp.id === component.id) {
|
|
6488
|
-
return {
|
|
6489
|
-
...comp,
|
|
6490
|
-
...change.value
|
|
6491
|
-
};
|
|
6492
|
-
}
|
|
6493
|
-
return comp;
|
|
6494
|
-
});
|
|
6495
|
-
// CRITICAL: Update local state immediately so new entries render without Angular round-trip
|
|
6496
|
-
setLocalFormComponents(updatedComponents);
|
|
6497
|
-
onFormDataChange?.(updatedComponents);
|
|
6498
|
-
// Also update formValues for nested components
|
|
6499
|
-
if (change.value.entries && Array.isArray(change.value.entries)) {
|
|
6500
|
-
change.value.entries.forEach((entry) => {
|
|
6501
|
-
if (entry.components && Array.isArray(entry.components)) {
|
|
6502
|
-
entry.components.forEach((nestedComp) => {
|
|
6503
|
-
const nestedValue = formValues[nestedComp.id];
|
|
6504
|
-
if (nestedValue !== undefined) ;
|
|
6505
|
-
else {
|
|
6506
|
-
// Initialize with defaultValue if available
|
|
6507
|
-
const defaultValue = nestedComp.basic?.defaultValue;
|
|
6508
|
-
if (defaultValue !== undefined) {
|
|
6509
|
-
setFormValues(prev => ({
|
|
6510
|
-
...prev,
|
|
6511
|
-
[nestedComp.id]: defaultValue
|
|
6512
|
-
}));
|
|
6513
|
-
}
|
|
6514
|
-
}
|
|
6515
|
-
});
|
|
6516
|
-
}
|
|
6517
|
-
});
|
|
6518
|
-
}
|
|
6519
|
-
}
|
|
6520
|
-
else {
|
|
6521
|
-
// For nested component value changes, use the regular handler
|
|
6522
|
-
onFormValueChange(change);
|
|
6523
|
-
}
|
|
6524
|
-
}, onEntryAdd: () => {
|
|
6525
|
-
// CRITICAL: Entry has already been added via onValueChange in DfFormDataGrid
|
|
6526
|
-
// Get the updated component from localFormComponents (which should have been updated by onValueChange)
|
|
6527
|
-
const currentComponent = localFormComponents.find(comp => comp.id === component.id);
|
|
6528
|
-
if (currentComponent && currentComponent.entries) {
|
|
6529
|
-
// Entry should already be in the component via onValueChange
|
|
6530
|
-
// Just ensure localFormComponents is in sync (no-op if already synced)
|
|
6531
|
-
const updatedComponents = localFormComponents.map(comp => {
|
|
6532
|
-
if (comp.id === component.id) {
|
|
6533
|
-
// Ensure entries are properly structured
|
|
6534
|
-
return {
|
|
6535
|
-
...comp,
|
|
6536
|
-
entries: comp.entries || []
|
|
6537
|
-
};
|
|
6538
|
-
}
|
|
6539
|
-
return comp;
|
|
6540
|
-
});
|
|
6541
|
-
onFormDataChange?.(updatedComponents);
|
|
6542
|
-
}
|
|
6543
|
-
else {
|
|
6544
|
-
// Fallback: If component doesn't have entries yet, try to get from formValues
|
|
6545
|
-
setTimeout(() => {
|
|
6546
|
-
const datagridValue = formValues[component.id];
|
|
6547
|
-
if (datagridValue && typeof datagridValue === 'object' && 'entries' in datagridValue) {
|
|
6548
|
-
const updatedComponents = localFormComponents.map(comp => {
|
|
6549
|
-
if (comp.id === component.id) {
|
|
6550
|
-
return {
|
|
6551
|
-
...comp,
|
|
6552
|
-
entries: datagridValue.entries
|
|
6553
|
-
};
|
|
6554
|
-
}
|
|
6555
|
-
return comp;
|
|
6556
|
-
});
|
|
6557
|
-
onFormDataChange?.(updatedComponents);
|
|
6558
|
-
}
|
|
6559
|
-
}, 100);
|
|
6560
|
-
}
|
|
6561
|
-
}, onEntryRemove: (entryIndex) => {
|
|
6562
|
-
// Handle entry remove - update form components
|
|
6563
|
-
const updatedComponents = localFormComponents.map(comp => {
|
|
6564
|
-
if (comp.id === component.id && comp.entries) {
|
|
6565
|
-
const currentEntries = comp.entries || [];
|
|
6566
|
-
const updatedEntries = currentEntries
|
|
6567
|
-
.filter((_, index) => index !== entryIndex)
|
|
6568
|
-
.map((entry, index) => ({
|
|
6569
|
-
...entry,
|
|
6570
|
-
index,
|
|
6571
|
-
id: `entry-${comp.id}-${index}`,
|
|
6572
|
-
components: entry.components?.map((comp, compIndex) => {
|
|
6573
|
-
const templateComp = (comp.templateComponents || [])[compIndex];
|
|
6574
|
-
return {
|
|
6575
|
-
...comp,
|
|
6576
|
-
id: templateComp ? `${templateComp.id}-entry-${index}-${compIndex}` : comp.id
|
|
6577
|
-
};
|
|
6578
|
-
}) || []
|
|
6579
|
-
}));
|
|
6580
|
-
return {
|
|
6581
|
-
...comp,
|
|
6582
|
-
entries: updatedEntries
|
|
6583
|
-
};
|
|
6584
|
-
}
|
|
6585
|
-
return comp;
|
|
6586
|
-
});
|
|
6587
|
-
onFormDataChange?.(updatedComponents);
|
|
6588
|
-
}, renderFormComponent: (field) => {
|
|
6589
|
-
// Ensure the nested component gets the proper form value
|
|
6513
|
+
}, onValueChange: onFormValueChange, renderFormComponent: (field) => {
|
|
6590
6514
|
return renderFormComponent(field);
|
|
6591
6515
|
} }));
|
|
6592
6516
|
case 'file':
|