df-ae-forms-package 1.1.1 → 1.1.3
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.esm.js +229 -78
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +229 -78
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -4241,6 +4241,33 @@ const ComponentSubmissionActions = ({ component }) => {
|
|
|
4241
4241
|
return (jsx("div", { className: "component-submission-actions", children: jsxs("div", { className: "actions-content", children: [hasNotes && (jsx("div", { className: "notes-summary-section", children: jsxs("div", { className: "notes-full-text", children: [jsx("span", { className: "notes-label", children: "Notes:" }), " ", notes] }) })), hasAttachments && (jsx("div", { className: "attachments-section", children: jsx(SubmissionAttachmentThumbnails, { attachments: attachments }) }))] }) }));
|
|
4242
4242
|
};
|
|
4243
4243
|
|
|
4244
|
+
// Helper to ensure an ID is a stable string, handling MongoDB-style object IDs
|
|
4245
|
+
// Helper to ensure an ID is a stable string, handling MongoDB-style object IDs
|
|
4246
|
+
function ensureStringId$2(id) {
|
|
4247
|
+
if (!id)
|
|
4248
|
+
return '';
|
|
4249
|
+
if (typeof id === 'string') {
|
|
4250
|
+
if (id.includes('[object Object]'))
|
|
4251
|
+
return '';
|
|
4252
|
+
return id;
|
|
4253
|
+
}
|
|
4254
|
+
if (typeof id === 'object' && id !== null) {
|
|
4255
|
+
if (id.$oid)
|
|
4256
|
+
return String(id.$oid);
|
|
4257
|
+
if (id._id)
|
|
4258
|
+
return ensureStringId$2(id._id);
|
|
4259
|
+
try {
|
|
4260
|
+
const str = id.toString();
|
|
4261
|
+
if (str && str !== '[object Object]')
|
|
4262
|
+
return str;
|
|
4263
|
+
return JSON.stringify(id);
|
|
4264
|
+
}
|
|
4265
|
+
catch (e) {
|
|
4266
|
+
return 'id-error';
|
|
4267
|
+
}
|
|
4268
|
+
}
|
|
4269
|
+
return String(id);
|
|
4270
|
+
}
|
|
4244
4271
|
const DraggableGridComponent = ({ component, selectedComponent, mode, onComponentSelect, onComponentDelete, onComponentEdit, renderFormComponent, isOverlay = false, formData = {}, formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChange, onAttachmentChange, shouldShowComponent }) => {
|
|
4245
4272
|
const formValue = formData[component.id];
|
|
4246
4273
|
const isVisible = shouldShowComponent ? shouldShowComponent(component.id) : true;
|
|
@@ -4492,7 +4519,7 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
|
|
|
4492
4519
|
let entryComponent = entry.components?.[componentIndex];
|
|
4493
4520
|
if (!entryComponent) {
|
|
4494
4521
|
// Use entry.id (which is unique) instead of entryIndex to prevent data collisions
|
|
4495
|
-
const uniqueId = `${templateComponent.id || 'comp'}-${entry.id}-${componentIndex}`;
|
|
4522
|
+
const uniqueId = `${ensureStringId$2(templateComponent.id) || 'comp'}-${ensureStringId$2(entry.id)}-${componentIndex}`;
|
|
4496
4523
|
entryComponent = {
|
|
4497
4524
|
...templateComponent,
|
|
4498
4525
|
id: uniqueId,
|
|
@@ -4505,7 +4532,7 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
|
|
|
4505
4532
|
else {
|
|
4506
4533
|
entryComponent = {
|
|
4507
4534
|
...entryComponent,
|
|
4508
|
-
id: entryComponent.id || `${templateComponent.id || 'comp'}-${entry.id}-${componentIndex}`,
|
|
4535
|
+
id: ensureStringId$2(entryComponent.id) || `${ensureStringId$2(templateComponent.id) || 'comp'}-${ensureStringId$2(entry.id)}-${componentIndex}`,
|
|
4509
4536
|
basic: {
|
|
4510
4537
|
...entryComponent.basic,
|
|
4511
4538
|
showLabel: columnView // Show label in column view
|
|
@@ -4564,7 +4591,11 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
|
|
|
4564
4591
|
position: 'sticky',
|
|
4565
4592
|
bottom: 0,
|
|
4566
4593
|
zIndex: 5
|
|
4567
|
-
}, children: jsxs("button", { onClick: () => {
|
|
4594
|
+
}, children: jsxs("button", { onClick: (e) => {
|
|
4595
|
+
e.stopPropagation();
|
|
4596
|
+
console.log('[TableView] Add Entry button clicked (grid view)', 'entries:', dataEntries.length, 'max:', maxEntries);
|
|
4597
|
+
onAddEntry();
|
|
4598
|
+
}, disabled: dataEntries.length >= maxEntries, style: {
|
|
4568
4599
|
padding: '8px 16px',
|
|
4569
4600
|
backgroundColor: dataEntries.length >= maxEntries ? '#f3f4f6' : '#10b981',
|
|
4570
4601
|
color: dataEntries.length >= maxEntries ? '#9ca3af' : '#ffffff',
|
|
@@ -4629,7 +4660,7 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
|
|
|
4629
4660
|
comp.basic?.label === templateComponent.basic?.label);
|
|
4630
4661
|
}
|
|
4631
4662
|
if (!entryComponent) {
|
|
4632
|
-
const uniqueId = `${templateComponent.id || 'comp'}-${entry.id}-${componentIndex}`;
|
|
4663
|
+
const uniqueId = `${ensureStringId$2(templateComponent.id) || 'comp'}-${ensureStringId$2(entry.id)}-${componentIndex}`;
|
|
4633
4664
|
entryComponent = {
|
|
4634
4665
|
...templateComponent,
|
|
4635
4666
|
id: uniqueId,
|
|
@@ -4642,7 +4673,7 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
|
|
|
4642
4673
|
else {
|
|
4643
4674
|
entryComponent = {
|
|
4644
4675
|
...entryComponent,
|
|
4645
|
-
id: entryComponent.id || `${templateComponent.id || 'comp'}-${entry.id}-${componentIndex}`,
|
|
4676
|
+
id: ensureStringId$2(entryComponent.id) || `${ensureStringId$2(templateComponent.id) || 'comp'}-${ensureStringId$2(entry.id)}-${componentIndex}`,
|
|
4646
4677
|
basic: {
|
|
4647
4678
|
...entryComponent.basic,
|
|
4648
4679
|
showLabel: columnView // Show label in column view, hide in grid view
|
|
@@ -4686,7 +4717,11 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
|
|
|
4686
4717
|
borderRadius: '8px',
|
|
4687
4718
|
display: 'flex',
|
|
4688
4719
|
justifyContent: 'center'
|
|
4689
|
-
}, children: jsxs("button", { onClick: () => {
|
|
4720
|
+
}, children: jsxs("button", { onClick: (e) => {
|
|
4721
|
+
e.stopPropagation();
|
|
4722
|
+
console.log('[TableView] Add Entry button clicked (list view)', 'entries:', dataEntries.length, 'max:', maxEntries);
|
|
4723
|
+
onAddEntry();
|
|
4724
|
+
}, disabled: dataEntries.length >= maxEntries, style: {
|
|
4690
4725
|
padding: '8px 16px',
|
|
4691
4726
|
backgroundColor: dataEntries.length >= maxEntries ? '#f3f4f6' : '#10b981',
|
|
4692
4727
|
color: dataEntries.length >= maxEntries ? '#9ca3af' : '#ffffff',
|
|
@@ -4710,10 +4745,11 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
|
|
|
4710
4745
|
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 }) => {
|
|
4711
4746
|
const [isCollapsed, setIsCollapsed] = useState(false);
|
|
4712
4747
|
const hasInitialized = useRef(false);
|
|
4748
|
+
const gridId = ensureStringId$2(id) || properties._id || (typeof id === 'string' ? id : 'datagrid-id');
|
|
4713
4749
|
// Get all components in the grid and sanitize them to ensure no data leaks into templates
|
|
4714
4750
|
let gridComponents = (properties.templateComponents || []).map((comp, index) => ({
|
|
4715
4751
|
...comp,
|
|
4716
|
-
id: comp.id || `${
|
|
4752
|
+
id: ensureStringId$2(comp.id) || `${gridId}-template-${index}`, // CRITICAL: Ensure template components have stable string IDs
|
|
4717
4753
|
basic: {
|
|
4718
4754
|
...comp.basic,
|
|
4719
4755
|
// Use an empty string instead of undefined to satisfy component typing
|
|
@@ -4727,7 +4763,7 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
|
|
|
4727
4763
|
gridComponents = dataEntries[0].components.map((comp, index) => ({
|
|
4728
4764
|
...comp,
|
|
4729
4765
|
// Remove entry suffix for template, use stable ID if missing
|
|
4730
|
-
id: comp.id
|
|
4766
|
+
id: ensureStringId$2(comp.id).replace(/-entry-.*$/, '') || `${gridId}-template-${index}`,
|
|
4731
4767
|
basic: {
|
|
4732
4768
|
...comp.basic,
|
|
4733
4769
|
// Clear any data values while keeping types happy
|
|
@@ -4770,7 +4806,7 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
|
|
|
4770
4806
|
index: 0,
|
|
4771
4807
|
components: gridComponents.map((comp, componentIndex) => ({
|
|
4772
4808
|
...comp,
|
|
4773
|
-
id: `${comp.id}-${newEntryId}-${componentIndex}`,
|
|
4809
|
+
id: `${ensureStringId$2(comp.id)}-${newEntryId}-${componentIndex}`,
|
|
4774
4810
|
basic: {
|
|
4775
4811
|
...comp.basic,
|
|
4776
4812
|
showLabel: false // Hide label in datagrid cells
|
|
@@ -4825,8 +4861,10 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
|
|
|
4825
4861
|
// Update existing component with new template properties while ensuring unique ID and preserving form values
|
|
4826
4862
|
const updatedComponent = {
|
|
4827
4863
|
...templateComp,
|
|
4828
|
-
// Preserve existing ID or generate one if missing
|
|
4829
|
-
id: existingComponent.id
|
|
4864
|
+
// Preserve existing ID (ensure it's a string) or generate one if missing
|
|
4865
|
+
id: (existingComponent.id && typeof existingComponent.id === 'string')
|
|
4866
|
+
? existingComponent.id
|
|
4867
|
+
: `${ensureStringId$2(templateComp.id)}-${ensureStringId$2(entry.id)}-${componentIndex}`,
|
|
4830
4868
|
basic: {
|
|
4831
4869
|
...templateComp.basic,
|
|
4832
4870
|
showLabel: false, // Hide label in datagrid cells
|
|
@@ -4840,7 +4878,7 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
|
|
|
4840
4878
|
// Create new component based on template
|
|
4841
4879
|
// Only for NEW components in existing entries (e.g. column added) do we generate a new ID
|
|
4842
4880
|
const uniqueSuffix = `${Date.now()}-${Math.random().toString(36).substr(2, 5)}`;
|
|
4843
|
-
const newId = `${templateComp.id}-${uniqueSuffix}-${componentIndex}`;
|
|
4881
|
+
const newId = `${ensureStringId$2(templateComp.id)}-${uniqueSuffix}-${componentIndex}`;
|
|
4844
4882
|
const newComponent = {
|
|
4845
4883
|
...templateComp,
|
|
4846
4884
|
id: newId,
|
|
@@ -4935,25 +4973,27 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
|
|
|
4935
4973
|
// In edit/preview modes, don't handle value changes as components are read-only
|
|
4936
4974
|
}, [mode, onValueChange]);
|
|
4937
4975
|
const handleAddEntry = useCallback(() => {
|
|
4938
|
-
console.log('[DfFormDataGrid] handleAddEntry called');
|
|
4939
|
-
|
|
4940
|
-
|
|
4976
|
+
console.log('[DfFormDataGrid] handleAddEntry called - Component ID:', id);
|
|
4977
|
+
// Safety check: ensure we have entries array
|
|
4978
|
+
const currentEntries = Array.isArray(properties.entries) ? properties.entries : [];
|
|
4979
|
+
console.log('[DfFormDataGrid] gridComponents:', gridComponents.length);
|
|
4980
|
+
console.log('[DfFormDataGrid] current entries count:', currentEntries.length);
|
|
4941
4981
|
console.log('[DfFormDataGrid] onValueChange exists:', !!onValueChange);
|
|
4942
4982
|
// Use timestamp and random string to ensure uniqueness even if entries are deleted
|
|
4943
4983
|
const uniqueSuffix = `${Date.now()}-${Math.random().toString(36).substr(2, 5)}`;
|
|
4944
4984
|
const newEntryId = `entry-${uniqueSuffix}`;
|
|
4945
4985
|
const newEntry = {
|
|
4946
4986
|
id: newEntryId,
|
|
4947
|
-
index:
|
|
4987
|
+
index: currentEntries.length,
|
|
4948
4988
|
components: gridComponents.map((comp, componentIndex) => {
|
|
4949
|
-
const componentId = `${comp.id}-${newEntryId}-${componentIndex}`;
|
|
4989
|
+
const componentId = `${ensureStringId$2(comp.id)}-${newEntryId}-${componentIndex}`;
|
|
4950
4990
|
return {
|
|
4951
4991
|
...comp,
|
|
4952
4992
|
// Use the unique entry ID in the component ID to prevent collisions
|
|
4953
4993
|
id: componentId,
|
|
4954
4994
|
basic: {
|
|
4955
4995
|
...comp.basic,
|
|
4956
|
-
value: '', //
|
|
4996
|
+
value: comp.basic?.defaultValue || '', // Use defaultValue if available, else empty
|
|
4957
4997
|
showLabel: false // Hide label in datagrid cells
|
|
4958
4998
|
}
|
|
4959
4999
|
};
|
|
@@ -4961,31 +5001,41 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
|
|
|
4961
5001
|
styles: {}
|
|
4962
5002
|
};
|
|
4963
5003
|
console.log('[DfFormDataGrid] newEntry created:', newEntry.id, 'with', newEntry.components.length, 'components');
|
|
4964
|
-
const updatedEntries = [...
|
|
5004
|
+
const updatedEntries = [...currentEntries, newEntry];
|
|
4965
5005
|
console.log('[DfFormDataGrid] updatedEntries count:', updatedEntries.length);
|
|
4966
5006
|
if (onValueChange) {
|
|
4967
|
-
console.log('[DfFormDataGrid] calling onValueChange with updated
|
|
5007
|
+
console.log('[DfFormDataGrid] calling onValueChange with updated datagrid structure - Entries:', updatedEntries.length);
|
|
4968
5008
|
onValueChange({
|
|
4969
|
-
id,
|
|
4970
|
-
value: {
|
|
5009
|
+
id: gridId, // Use sanitized gridId
|
|
5010
|
+
value: {
|
|
5011
|
+
...properties,
|
|
5012
|
+
entries: updatedEntries
|
|
5013
|
+
}
|
|
4971
5014
|
});
|
|
5015
|
+
// Notify parent if callback provided
|
|
5016
|
+
if (onEntryAdd) {
|
|
5017
|
+
console.log('[DfFormDataGrid] calling onEntryAdd callback');
|
|
5018
|
+
onEntryAdd();
|
|
5019
|
+
}
|
|
4972
5020
|
}
|
|
4973
5021
|
else {
|
|
4974
|
-
console.
|
|
5022
|
+
console.warn('[DfFormDataGrid] Cannot add entry: onValueChange is missing');
|
|
4975
5023
|
}
|
|
4976
|
-
|
|
4977
|
-
}, [properties, onValueChange, id, onEntryAdd, gridComponents]);
|
|
5024
|
+
}, [onValueChange, properties, gridId, gridComponents, onEntryAdd]);
|
|
4978
5025
|
const handleRemoveEntry = useCallback((entryIndex) => {
|
|
4979
|
-
|
|
5026
|
+
// Safety check: ensure we have entries array
|
|
5027
|
+
const currentEntries = Array.isArray(properties.entries) ? properties.entries : [];
|
|
5028
|
+
const updatedEntries = currentEntries
|
|
4980
5029
|
.filter((_, index) => index !== entryIndex)
|
|
4981
5030
|
.map((entry, index) => ({ ...entry, index })); // Only update index, preserve unique ID
|
|
4982
5031
|
if (onValueChange) {
|
|
5032
|
+
console.log('[DfFormDataGrid] Removing entry at index:', entryIndex, 'New count:', updatedEntries.length);
|
|
4983
5033
|
onValueChange({
|
|
4984
|
-
id,
|
|
5034
|
+
id: gridId, // Use sanitized gridId
|
|
4985
5035
|
value: { ...properties, entries: updatedEntries }
|
|
4986
5036
|
});
|
|
4987
5037
|
}
|
|
4988
|
-
}, [properties, onValueChange,
|
|
5038
|
+
}, [properties.entries, onValueChange, gridId, properties]);
|
|
4989
5039
|
// Use our own render function to ensure proper onComponentUpdate handling
|
|
4990
5040
|
const renderComponent = useCallback((field, hideLabel = false) => {
|
|
4991
5041
|
const formValue = mode === 'test' ? (formData[field.id] || ('defaultValue' in field.basic ? field.basic.defaultValue || '' : '')) : ('defaultValue' in field.basic ? field.basic.defaultValue || '' : '');
|
|
@@ -5310,6 +5360,37 @@ const DfFormSection = ({ id, properties, mode = 'edit', formData = {}, onValueCh
|
|
|
5310
5360
|
|
|
5311
5361
|
// Dynamic imports to avoid circular dependencies
|
|
5312
5362
|
const DfFormTable$1 = React.lazy(() => Promise.resolve().then(function () { return dfFormTable; }));
|
|
5363
|
+
// Helper to ensure an ID is a stable string, handling MongoDB-style object IDs
|
|
5364
|
+
// This is used globally in this file to prevent [object Object] corruption
|
|
5365
|
+
const ensureStringId$1 = (id) => {
|
|
5366
|
+
if (!id)
|
|
5367
|
+
return '';
|
|
5368
|
+
if (typeof id === 'string') {
|
|
5369
|
+
// If the ID is already corrupted, return empty to trigger regeneration
|
|
5370
|
+
if (id.includes('[object Object]'))
|
|
5371
|
+
return '';
|
|
5372
|
+
return id;
|
|
5373
|
+
}
|
|
5374
|
+
if (typeof id === 'object' && id !== null) {
|
|
5375
|
+
if (id.$oid)
|
|
5376
|
+
return String(id.$oid);
|
|
5377
|
+
if (id._id)
|
|
5378
|
+
return ensureStringId$1(id._id);
|
|
5379
|
+
// Fallback for other object structures that might be IDs
|
|
5380
|
+
try {
|
|
5381
|
+
// If it has a toString that isn't the default, use it
|
|
5382
|
+
const str = id.toString();
|
|
5383
|
+
if (str && str !== '[object Object]')
|
|
5384
|
+
return str;
|
|
5385
|
+
// Otherwise, use a hash or just JSON
|
|
5386
|
+
return JSON.stringify(id);
|
|
5387
|
+
}
|
|
5388
|
+
catch (e) {
|
|
5389
|
+
return 'id-error';
|
|
5390
|
+
}
|
|
5391
|
+
}
|
|
5392
|
+
return String(id);
|
|
5393
|
+
};
|
|
5313
5394
|
// Normalize a table row from API format (object with numeric keys) into a proper array.
|
|
5314
5395
|
// The API may return cells as [{"0": {cell}, "1": {cell}}, ...] instead of [[cell, cell], ...].
|
|
5315
5396
|
const normalizeTableRow = (row) => {
|
|
@@ -5355,16 +5436,17 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
5355
5436
|
// Recursive function to initialize values from nested components
|
|
5356
5437
|
const initializeComponentValues = (components, values) => {
|
|
5357
5438
|
components.forEach(component => {
|
|
5358
|
-
|
|
5439
|
+
const componentId = ensureStringId$1(component.id);
|
|
5440
|
+
if (componentId) {
|
|
5359
5441
|
// ALWAYS prioritize existing form state (values param) if it exists
|
|
5360
|
-
if (values[
|
|
5361
|
-
// Then
|
|
5362
|
-
else if (component.basic && 'value' in component.basic && component.basic.value !== undefined
|
|
5363
|
-
values[
|
|
5442
|
+
if (values[componentId] !== undefined) ;
|
|
5443
|
+
// Then use captured value in basic.value
|
|
5444
|
+
else if (component.basic && 'value' in component.basic && component.basic.value !== undefined) {
|
|
5445
|
+
values[componentId] = component.basic.value;
|
|
5364
5446
|
}
|
|
5365
|
-
// Then
|
|
5366
|
-
else if (component.basic && 'defaultValue' in component.basic && component.basic.defaultValue !== undefined
|
|
5367
|
-
values[
|
|
5447
|
+
// Then use defaultValue
|
|
5448
|
+
else if (component.basic && 'defaultValue' in component.basic && component.basic.defaultValue !== undefined) {
|
|
5449
|
+
values[componentId] = component.basic.defaultValue;
|
|
5368
5450
|
}
|
|
5369
5451
|
// Only then default to empty
|
|
5370
5452
|
else {
|
|
@@ -5434,12 +5516,13 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
5434
5516
|
// Helper to extract notes and attachments recursively
|
|
5435
5517
|
const extractNotesAndAttachments = (components) => {
|
|
5436
5518
|
components.forEach(comp => {
|
|
5437
|
-
|
|
5519
|
+
const componentId = ensureStringId$1(comp.id);
|
|
5520
|
+
if (componentId) {
|
|
5438
5521
|
if (comp.basic?.notes || comp.basic?.comments) {
|
|
5439
|
-
initialNotes[
|
|
5522
|
+
initialNotes[componentId] = comp.basic?.notes || comp.basic?.comments;
|
|
5440
5523
|
}
|
|
5441
5524
|
if (comp.basic?.attachments) {
|
|
5442
|
-
initialAttachments[
|
|
5525
|
+
initialAttachments[componentId] = comp.basic.attachments;
|
|
5443
5526
|
}
|
|
5444
5527
|
}
|
|
5445
5528
|
// Recurse
|
|
@@ -5461,27 +5544,43 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
5461
5544
|
};
|
|
5462
5545
|
// Validate component IDs for uniqueness without mutating original props
|
|
5463
5546
|
const getValidatedComponents = (components, parentId) => {
|
|
5547
|
+
const parentIdStr = parentId ? ensureStringId$1(parentId) : '';
|
|
5464
5548
|
return components.map((component, index) => {
|
|
5465
5549
|
let validatedComponent = { ...component };
|
|
5466
|
-
// Ensure component has
|
|
5467
|
-
|
|
5550
|
+
// Ensure component has a valid string ID
|
|
5551
|
+
let currentId = validatedComponent.id;
|
|
5552
|
+
// CRITICAL: Reject any ID that is not a string, is empty, or contains "[object Object]"
|
|
5553
|
+
let isIdValid = typeof currentId === 'string' &&
|
|
5554
|
+
currentId.trim() !== '' &&
|
|
5555
|
+
!currentId.includes('[object Object]');
|
|
5556
|
+
if (!isIdValid) {
|
|
5557
|
+
// If it's an object ID (but not a corrupted string), convert it to string
|
|
5558
|
+
if (currentId && typeof currentId === 'object') {
|
|
5559
|
+
const convertedId = ensureStringId$1(currentId);
|
|
5560
|
+
if (convertedId && !convertedId.includes('[object Object]')) {
|
|
5561
|
+
validatedComponent.id = convertedId;
|
|
5562
|
+
isIdValid = true;
|
|
5563
|
+
}
|
|
5564
|
+
}
|
|
5565
|
+
}
|
|
5566
|
+
if (!isIdValid) {
|
|
5468
5567
|
// Determine a base name for the ID
|
|
5469
5568
|
const name = validatedComponent.name || 'component';
|
|
5470
5569
|
const label = validatedComponent.basic?.label || '';
|
|
5471
5570
|
const safeLabel = label.replace(/[^a-zA-Z0-9]/g, '').toLowerCase().substring(0, 10);
|
|
5472
5571
|
// Generate a stable unique ID if parentId is provided, otherwise fallback to semi-stable
|
|
5473
|
-
if (
|
|
5474
|
-
validatedComponent.id = `${
|
|
5572
|
+
if (parentIdStr) {
|
|
5573
|
+
validatedComponent.id = `${parentIdStr}-${name}-${index}`;
|
|
5475
5574
|
}
|
|
5476
5575
|
else {
|
|
5477
5576
|
// For root components, use label if available for stability
|
|
5478
5577
|
const labelPart = safeLabel ? `-${safeLabel}` : '';
|
|
5479
5578
|
validatedComponent.id = `${name}${labelPart}-${index}`;
|
|
5480
5579
|
}
|
|
5481
|
-
console.warn(`[DfFormPreview]
|
|
5580
|
+
console.warn(`[DfFormPreview] Fixed missing/invalid ID: ${validatedComponent.id}`);
|
|
5482
5581
|
}
|
|
5483
5582
|
else {
|
|
5484
|
-
//
|
|
5583
|
+
// ID is a valid string, check for duplicates
|
|
5485
5584
|
if (seenIds.has(validatedComponent.id)) {
|
|
5486
5585
|
console.error(`[DfFormPreview] Duplicate component ID detected: ${validatedComponent.id}`);
|
|
5487
5586
|
// Generate a unique ID for duplicate - using index to keep it somewhat stable
|
|
@@ -5501,7 +5600,7 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
5501
5600
|
return normalizedRow.map((cell, cellIndex) => {
|
|
5502
5601
|
if (cell && cell.components && Array.isArray(cell.components)) {
|
|
5503
5602
|
// Stable ID for table cells: tableId-row-X-cell-Y
|
|
5504
|
-
const cellContextId = `${validatedComponent.id}-row-${rowIndex}-cell-${cellIndex}`;
|
|
5603
|
+
const cellContextId = `${ensureStringId$1(validatedComponent.id)}-row-${rowIndex}-cell-${cellIndex}`;
|
|
5505
5604
|
return {
|
|
5506
5605
|
...cell,
|
|
5507
5606
|
components: getValidatedComponents(cell.components, cellContextId)
|
|
@@ -5517,14 +5616,21 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
5517
5616
|
validatedComponent.entries = validatedComponent.entries.map((entry) => {
|
|
5518
5617
|
if (entry && entry.components && Array.isArray(entry.components)) {
|
|
5519
5618
|
// Stable ID for datagrid entries: datagridId-entryId or using entry.id
|
|
5619
|
+
const entryId = entry.id ? ensureStringId$1(entry.id) : `${ensureStringId$1(validatedComponent.id)}-entry-${entry.index}`;
|
|
5520
5620
|
return {
|
|
5521
5621
|
...entry,
|
|
5522
|
-
|
|
5622
|
+
id: entryId, // Ensure entry itself has a string ID
|
|
5623
|
+
components: getValidatedComponents(entry.components, entryId)
|
|
5523
5624
|
};
|
|
5524
5625
|
}
|
|
5525
5626
|
return entry;
|
|
5526
5627
|
});
|
|
5527
5628
|
}
|
|
5629
|
+
// CRITICAL: Also validate templateComponents for datagrids
|
|
5630
|
+
if (validatedComponent.name === 'datagrid' && validatedComponent.templateComponents && Array.isArray(validatedComponent.templateComponents)) {
|
|
5631
|
+
const datagridId = ensureStringId$1(validatedComponent.id);
|
|
5632
|
+
validatedComponent.templateComponents = getValidatedComponents(validatedComponent.templateComponents, `${datagridId}-template`);
|
|
5633
|
+
}
|
|
5528
5634
|
return validatedComponent;
|
|
5529
5635
|
});
|
|
5530
5636
|
};
|
|
@@ -5532,8 +5638,10 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
5532
5638
|
let validatedFormComponents = localFormComponents;
|
|
5533
5639
|
if (localFormComponents && localFormComponents.length > 0) {
|
|
5534
5640
|
validatedFormComponents = getValidatedComponents(localFormComponents);
|
|
5535
|
-
//
|
|
5641
|
+
// Synchronize local state if components were mutated (IDs added/fixed)
|
|
5536
5642
|
if (JSON.stringify(validatedFormComponents) !== JSON.stringify(localFormComponents)) {
|
|
5643
|
+
console.log('[DfFormPreview] Synchronizing local components after ID validation');
|
|
5644
|
+
setLocalFormComponents(validatedFormComponents);
|
|
5537
5645
|
onFormDataChange?.(validatedFormComponents);
|
|
5538
5646
|
}
|
|
5539
5647
|
}
|
|
@@ -6312,13 +6420,10 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
6312
6420
|
const componentIdCacheRef = useRef(new Map());
|
|
6313
6421
|
const componentCounterRef = useRef(0);
|
|
6314
6422
|
const renderFormComponent = (component) => {
|
|
6315
|
-
// CRITICAL: Ensure component has a valid unique ID
|
|
6423
|
+
// CRITICAL: Ensure component has a valid unique string ID
|
|
6316
6424
|
// NEVER regenerate IDs - always use existing or cached ID
|
|
6317
|
-
let finalComponentId;
|
|
6318
|
-
if (
|
|
6319
|
-
// Component already has an ID - use it (most common case)
|
|
6320
|
-
finalComponentId = component.id;
|
|
6321
|
-
}
|
|
6425
|
+
let finalComponentId = ensureStringId$1(component.id);
|
|
6426
|
+
if (finalComponentId && finalComponentId.trim() !== '') ;
|
|
6322
6427
|
else {
|
|
6323
6428
|
// Component is missing an ID - need to generate and cache it
|
|
6324
6429
|
// Create a stable cache key using component properties that don't change
|
|
@@ -6448,12 +6553,13 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
6448
6553
|
return renderFormComponent(field);
|
|
6449
6554
|
}, onNotesChange: (componentId, notes) => {
|
|
6450
6555
|
// Handle notes change for table cell components
|
|
6556
|
+
const targetTableId = ensureStringId$1(component.id);
|
|
6451
6557
|
const updatedComponents = localFormComponents.map(comp => {
|
|
6452
|
-
if (comp.id ===
|
|
6558
|
+
if (ensureStringId$1(comp.id) === targetTableId && comp.cells) {
|
|
6453
6559
|
const updatedCells = comp.cells.map((row) => normalizeTableRow(row).map((cell) => {
|
|
6454
6560
|
if (cell.components) {
|
|
6455
6561
|
const updatedCellComponents = cell.components.map((cellComp) => {
|
|
6456
|
-
if (cellComp.id === componentId) {
|
|
6562
|
+
if (ensureStringId$1(cellComp.id) === componentId) {
|
|
6457
6563
|
return {
|
|
6458
6564
|
...cellComp,
|
|
6459
6565
|
basic: {
|
|
@@ -6475,12 +6581,13 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
6475
6581
|
onFormDataChange?.(updatedComponents);
|
|
6476
6582
|
}, onAttachmentChange: (componentId, attachments) => {
|
|
6477
6583
|
// Handle attachment change for table cell components
|
|
6584
|
+
const targetTableId = ensureStringId$1(component.id);
|
|
6478
6585
|
const updatedComponents = localFormComponents.map(comp => {
|
|
6479
|
-
if (comp.id ===
|
|
6586
|
+
if (ensureStringId$1(comp.id) === targetTableId && comp.cells) {
|
|
6480
6587
|
const updatedCells = comp.cells.map((row) => normalizeTableRow(row).map((cell) => {
|
|
6481
6588
|
if (cell.components) {
|
|
6482
6589
|
const updatedCellComponents = cell.components.map((cellComp) => {
|
|
6483
|
-
if (cellComp.id === componentId) {
|
|
6590
|
+
if (ensureStringId$1(cellComp.id) === componentId) {
|
|
6484
6591
|
return {
|
|
6485
6592
|
...cellComp,
|
|
6486
6593
|
basic: {
|
|
@@ -6505,12 +6612,13 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
6505
6612
|
return (jsx(DfFormDataGrid, { ...commonProps, properties: component, formData: formValues, formTemplateId: formTemplateId, mode: commonProps.mode, onThresholdActionCompletion: handleThresholdActionCompletion, onThresholdIssueRaised: handleThresholdIssueRaised, onNotesChange: (componentId, notes) => {
|
|
6506
6613
|
handleComponentNotesChange(componentId, notes);
|
|
6507
6614
|
// Handle notes change for datagrid entry components
|
|
6615
|
+
const targetGridId = ensureStringId$1(component.id);
|
|
6508
6616
|
const updatedComponents = localFormComponents.map(comp => {
|
|
6509
|
-
if (comp.id ===
|
|
6617
|
+
if (ensureStringId$1(comp.id) === targetGridId && comp.entries) {
|
|
6510
6618
|
const updatedEntries = comp.entries.map((entry) => {
|
|
6511
6619
|
if (entry.components) {
|
|
6512
6620
|
const updatedEntryComponents = entry.components.map((entryComp) => {
|
|
6513
|
-
if (entryComp.id === componentId) {
|
|
6621
|
+
if (ensureStringId$1(entryComp.id) === componentId) {
|
|
6514
6622
|
return {
|
|
6515
6623
|
...entryComp,
|
|
6516
6624
|
basic: {
|
|
@@ -6533,12 +6641,13 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
6533
6641
|
}, onAttachmentChange: (componentId, attachments) => {
|
|
6534
6642
|
handleComponentAttachmentChange(componentId, attachments);
|
|
6535
6643
|
// Handle attachment change for datagrid entry components
|
|
6644
|
+
const targetGridId = ensureStringId$1(component.id);
|
|
6536
6645
|
const updatedComponents = localFormComponents.map(comp => {
|
|
6537
|
-
if (comp.id ===
|
|
6646
|
+
if (ensureStringId$1(comp.id) === targetGridId && comp.entries) {
|
|
6538
6647
|
const updatedEntries = comp.entries.map((entry) => {
|
|
6539
6648
|
if (entry.components) {
|
|
6540
6649
|
const updatedEntryComponents = entry.components.map((entryComp) => {
|
|
6541
|
-
if (entryComp.id === componentId) {
|
|
6650
|
+
if (ensureStringId$1(entryComp.id) === componentId) {
|
|
6542
6651
|
return {
|
|
6543
6652
|
...entryComp,
|
|
6544
6653
|
basic: {
|
|
@@ -6559,13 +6668,16 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
6559
6668
|
});
|
|
6560
6669
|
onFormDataChange?.(updatedComponents);
|
|
6561
6670
|
}, onValueChange: (change) => {
|
|
6562
|
-
|
|
6671
|
+
const changeId = ensureStringId$1(change.id);
|
|
6672
|
+
const componentId = ensureStringId$1(component.id);
|
|
6673
|
+
console.log(`[DfFormPreview] datagrid onValueChange - Target: ${changeId}, Component: ${componentId}`);
|
|
6563
6674
|
// Handle datagrid value changes (entries updates)
|
|
6564
|
-
if (
|
|
6675
|
+
if (changeId === componentId && change.value && typeof change.value === 'object' && 'entries' in change.value) {
|
|
6565
6676
|
console.log('[DfFormPreview] datagrid entries update - entries count:', change.value.entries?.length);
|
|
6566
6677
|
// Update localFormComponents with new entries structure
|
|
6567
6678
|
const updatedComponents = localFormComponents.map(comp => {
|
|
6568
|
-
|
|
6679
|
+
const currentCompId = ensureStringId$1(comp.id);
|
|
6680
|
+
if (currentCompId === componentId) {
|
|
6569
6681
|
return {
|
|
6570
6682
|
...comp,
|
|
6571
6683
|
...change.value
|
|
@@ -6576,26 +6688,37 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
6576
6688
|
// CRITICAL: Update local state immediately so new entries render without Angular round-trip
|
|
6577
6689
|
setLocalFormComponents(updatedComponents);
|
|
6578
6690
|
onFormDataChange?.(updatedComponents);
|
|
6579
|
-
// Also update formValues for nested components
|
|
6691
|
+
// Also update formValues for nested components to prevent undefined values
|
|
6580
6692
|
if (change.value.entries && Array.isArray(change.value.entries)) {
|
|
6693
|
+
const newValues = { ...formValues };
|
|
6694
|
+
let valuesChanged = false;
|
|
6581
6695
|
change.value.entries.forEach((entry) => {
|
|
6582
6696
|
if (entry.components && Array.isArray(entry.components)) {
|
|
6583
6697
|
entry.components.forEach((nestedComp) => {
|
|
6584
|
-
const
|
|
6585
|
-
if (
|
|
6586
|
-
|
|
6587
|
-
|
|
6698
|
+
const nestedId = ensureStringId$1(nestedComp.id);
|
|
6699
|
+
if (!nestedId)
|
|
6700
|
+
return;
|
|
6701
|
+
if (newValues[nestedId] === undefined) {
|
|
6702
|
+
// Initialize with defaultValue if available, otherwise empty string/array
|
|
6588
6703
|
const defaultValue = nestedComp.basic?.defaultValue;
|
|
6589
6704
|
if (defaultValue !== undefined) {
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6705
|
+
newValues[nestedId] = defaultValue;
|
|
6706
|
+
}
|
|
6707
|
+
else if (nestedComp.name === 'checkbox' || nestedComp.name === 'select') {
|
|
6708
|
+
newValues[nestedId] = [];
|
|
6594
6709
|
}
|
|
6710
|
+
else {
|
|
6711
|
+
newValues[nestedId] = '';
|
|
6712
|
+
}
|
|
6713
|
+
valuesChanged = true;
|
|
6595
6714
|
}
|
|
6596
6715
|
});
|
|
6597
6716
|
}
|
|
6598
6717
|
});
|
|
6718
|
+
if (valuesChanged) {
|
|
6719
|
+
console.log('[DfFormPreview] Initializing form values for new datagrid entries');
|
|
6720
|
+
setFormValues(newValues);
|
|
6721
|
+
}
|
|
6599
6722
|
}
|
|
6600
6723
|
}
|
|
6601
6724
|
else {
|
|
@@ -6804,6 +6927,32 @@ const DfFormComments = ({ comment = '', onSave, placeholder = 'Enter your reason
|
|
|
6804
6927
|
return (jsxs("div", { className: `df-form-comments ${className}`, children: [jsxs("div", { className: "df-form-comments__header", children: [jsx("h3", { className: "df-form-comments__title", children: "Comments" }), jsx("button", { className: "df-form-comments__toggle", type: "button", onClick: toggleComments, "aria-expanded": isExpanded, "aria-label": "Toggle comments section", disabled: disabled, children: isExpanded ? (jsx("span", { className: "df-form-comments__toggle-icon", children: "\u25BC" })) : (jsx("span", { className: "df-form-comments__toggle-icon", children: "\u25B6" })) })] }), jsx("div", { className: `df-form-comments__content ${isExpanded ? 'df-form-comments__content--expanded' : ''}`, children: jsx("div", { className: "df-form-comments__input-container", children: jsx("div", { className: "df-form-comments__input-line", children: jsx("input", { type: "text", id: "comment-input", className: "df-form-comments__input", value: currentComment, onChange: handleInputChange, onBlur: handleInputBlur, onFocus: handleInputFocus, placeholder: placeholder, disabled: disabled }) }) }) })] }));
|
|
6805
6928
|
};
|
|
6806
6929
|
|
|
6930
|
+
// Helper to ensure an ID is a stable string, handling MongoDB-style object IDs
|
|
6931
|
+
const ensureStringId = (id) => {
|
|
6932
|
+
if (!id)
|
|
6933
|
+
return '';
|
|
6934
|
+
if (typeof id === 'string') {
|
|
6935
|
+
if (id.includes('[object Object]'))
|
|
6936
|
+
return '';
|
|
6937
|
+
return id;
|
|
6938
|
+
}
|
|
6939
|
+
if (typeof id === 'object' && id !== null) {
|
|
6940
|
+
if (id.$oid)
|
|
6941
|
+
return String(id.$oid);
|
|
6942
|
+
if (id._id)
|
|
6943
|
+
return ensureStringId(id._id);
|
|
6944
|
+
try {
|
|
6945
|
+
const str = id.toString();
|
|
6946
|
+
if (str && str !== '[object Object]')
|
|
6947
|
+
return str;
|
|
6948
|
+
return JSON.stringify(id);
|
|
6949
|
+
}
|
|
6950
|
+
catch (e) {
|
|
6951
|
+
return 'id-error';
|
|
6952
|
+
}
|
|
6953
|
+
}
|
|
6954
|
+
return String(id);
|
|
6955
|
+
};
|
|
6807
6956
|
// Normalize a row from the API format (object with numeric keys) into a proper TableCell array.
|
|
6808
6957
|
// The API may return cells as [{"0": {cell}, "1": {cell}}, ...] instead of [[cell, cell], ...].
|
|
6809
6958
|
const normalizeRow = (row) => {
|
|
@@ -6998,13 +7147,15 @@ const DfFormTable = ({ id, properties, mode = 'edit', formData = {}, validationE
|
|
|
6998
7147
|
? cell.components.map((comp, compIndex) => {
|
|
6999
7148
|
// CRITICAL: Only generate ID if it's missing - never regenerate existing IDs
|
|
7000
7149
|
// This prevents component remounting and losing input state
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7150
|
+
const existingId = ensureStringId(comp.id);
|
|
7151
|
+
if (existingId) {
|
|
7152
|
+
// ID already exists and is valid - keep it but ensure it's a string
|
|
7153
|
+
return { ...comp, id: existingId };
|
|
7004
7154
|
}
|
|
7005
7155
|
// Generate unique ID that includes table ID, row, cell, and component index
|
|
7006
7156
|
// This ensures no conflicts with other components
|
|
7007
|
-
const
|
|
7157
|
+
const sanitizedTableId = ensureStringId(id);
|
|
7158
|
+
const uniqueId = `${comp.name || 'component'}-table-${sanitizedTableId}-row-${rowIndex}-cell-${cellIndex}-comp-${compIndex}`;
|
|
7008
7159
|
return {
|
|
7009
7160
|
...comp,
|
|
7010
7161
|
id: uniqueId
|