Skip to content

Commit 10d47e9

Browse files
author
Bob Strahan
committed
improve attribute field distribution
1 parent af52393 commit 10d47e9

File tree

1 file changed

+157
-31
lines changed

1 file changed

+157
-31
lines changed

src/ui/src/components/configuration-layout/FormView.jsx

Lines changed: 157 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -826,61 +826,187 @@ const FormView = ({ schema, formValues, defaultConfig, isCustomized, onResetToDe
826826
}))
827827
.sort((a, b) => a.order - b.order);
828828

829-
// Add debugging to see actual column count
830-
console.log(`Rendering ${columnCount} columns for ${propEntries.length} properties`);
829+
// Function to check if a field should be visible (not hidden by dependencies)
830+
const isFieldVisible = (propKey, propSchema) => {
831+
if (!propSchema.dependsOn) return true;
832+
833+
const dependencyField = propSchema.dependsOn.field;
834+
const dependencyValues = Array.isArray(propSchema.dependsOn.values)
835+
? propSchema.dependsOn.values
836+
: [propSchema.dependsOn.value];
837+
838+
let dependencyPath;
839+
const fieldPath = `${itemPath}.${propKey}`;
840+
841+
// Special handling for nested attributes looking for attributeType
842+
if (
843+
dependencyField === 'attributeType' &&
844+
(fieldPath.includes('groupAttributes[') ||
845+
fieldPath.includes('listItemTemplate.itemAttributes['))
846+
) {
847+
if (fieldPath.includes('groupAttributes[')) {
848+
const attributeMatch = fieldPath.match(/^(.+\.attributes\[\d+\])\.groupAttributes/);
849+
dependencyPath = attributeMatch ? `${attributeMatch[1]}.attributeType` : null;
850+
} else if (fieldPath.includes('listItemTemplate.itemAttributes[')) {
851+
const attributeMatch = fieldPath.match(
852+
/^(.+\.attributes\[\d+\])\.listItemTemplate\.itemAttributes/,
853+
);
854+
dependencyPath = attributeMatch ? `${attributeMatch[1]}.attributeType` : null;
855+
}
856+
} else {
857+
const parentPath = fieldPath.substring(0, fieldPath.lastIndexOf('.'));
858+
dependencyPath =
859+
parentPath.length > 0 ? `${parentPath}.${dependencyField}` : dependencyField;
860+
}
861+
862+
if (!dependencyPath) return false;
863+
864+
const dependencyValue = getValueAtPath(formValues, dependencyPath);
865+
return dependencyValue !== undefined && dependencyValues.includes(dependencyValue);
866+
};
831867

832868
// Separate regular fields from special fields (lists, objects with dependencies)
833869
const regularProps = [];
834870
const specialProps = []; // For lists, objects with dependsOn, or objects with sectionLabel
835871

836-
// Identify and separate the fields
872+
// Identify and separate the fields, filtering out hidden ones
837873
propEntries.forEach(({ propKey, prop: propSchema }) => {
838874
if (
839875
propSchema.type === 'list' ||
840876
propSchema.type === 'array' ||
841877
(propSchema.type === 'object' && (propSchema.dependsOn || propSchema.sectionLabel))
842878
) {
843879
specialProps.push({ propKey, propSchema });
844-
} else {
880+
} else if (isFieldVisible(propKey, propSchema)) {
881+
// Only include regular fields that are actually visible
845882
regularProps.push({ propKey, propSchema });
846883
}
847884
});
848885

886+
// Add debugging to see field distribution
887+
console.log(`Field distribution for ${key}:`, {
888+
totalProperties: propEntries.length,
889+
requestedColumns: columnCount,
890+
visibleRegularFields: regularProps.length,
891+
specialFields: specialProps.length,
892+
hiddenByDependencies: propEntries.length - regularProps.length - specialProps.length,
893+
});
894+
895+
// Enhanced column distribution algorithm - only for visible fields
896+
const distributeFieldsToColumns = (fields, numColumns) => {
897+
// Create columns array
898+
const columns = Array.from({ length: numColumns }, () => []);
899+
900+
// Special handling for description field - it should span full width if it exists
901+
const descriptionField = fields.find(({ propKey }) => propKey === 'description');
902+
const nonDescriptionFields = fields.filter(({ propKey }) => propKey !== 'description');
903+
904+
// Calculate optimal column count based on actual field count
905+
const actualColumnCount = Math.min(numColumns, Math.max(1, nonDescriptionFields.length));
906+
907+
// Distribute non-description fields evenly across columns using round-robin
908+
nonDescriptionFields.forEach((field, fieldIndex) => {
909+
const targetColumn = fieldIndex % actualColumnCount;
910+
columns[targetColumn].push(field);
911+
});
912+
913+
// Return only the columns that have content
914+
const nonEmptyColumns = columns.slice(0, actualColumnCount);
915+
916+
return {
917+
columns: nonEmptyColumns,
918+
descriptionField,
919+
actualColumnCount,
920+
};
921+
};
922+
923+
const {
924+
columns: fieldColumns,
925+
descriptionField,
926+
actualColumnCount,
927+
} = distributeFieldsToColumns(regularProps, columnCount);
928+
929+
// Calculate maximum rows needed
930+
const maxRows = Math.max(...fieldColumns.map((col) => col.length));
931+
932+
// Validation and debugging for field distribution
933+
console.log(`Distribution result for ${key}:`, {
934+
actualColumnCount,
935+
maxRows,
936+
columnLengths: fieldColumns.map((col) => col.length),
937+
totalFieldsDistributed: fieldColumns.reduce((sum, col) => sum + col.length, 0),
938+
hasDescription: !!descriptionField,
939+
});
940+
849941
// Render the regular fields using HTML table for guaranteed columns
850942
const renderedRegularFields = (
851943
<Box padding="0" style={{ margin: 0 }}>
852944
<table
853945
style={{ width: '100%', borderCollapse: 'separate', borderSpacing: '4px 0', margin: 0 }}
854946
>
855947
<tbody style={{ margin: 0, padding: 0 }}>
856-
{/* Split fields into rows based on columnCount */}
857-
{Array.from({ length: Math.ceil(regularProps.length / columnCount) }).map(
858-
(rowItem, rowIndex) => (
859-
<tr key={`row-${rowIndex}`}>
860-
{Array.from({ length: columnCount }).map((colItem, colIndex) => {
861-
const fieldIndex = rowIndex * columnCount + colIndex;
862-
if (fieldIndex >= regularProps.length)
863-
return <td key={`empty-${colIndex}`} aria-hidden="true" />;
864-
865-
const { propKey, propSchema } = regularProps[fieldIndex];
866-
867-
// Skip rendering the name field since it's already shown in the header
868-
if (propKey === 'name') {
869-
return <td key={propKey} style={{ display: 'none' }} aria-hidden="true" />;
870-
}
871-
872-
return (
873-
<td
874-
key={propKey}
875-
style={{ verticalAlign: 'top', width: `${100 / columnCount}%` }}
876-
>
877-
<Box padding="0">{renderField(propKey, propSchema, itemPath)}</Box>
878-
</td>
879-
);
880-
})}
881-
</tr>
882-
),
948+
{/* Render description field first if it exists, spanning full width */}
949+
{descriptionField && (
950+
<tr key="description-row">
951+
<td colSpan={actualColumnCount} style={{ verticalAlign: 'top' }}>
952+
<Box padding="0">
953+
{renderField(descriptionField.propKey, descriptionField.propSchema, itemPath)}
954+
</Box>
955+
</td>
956+
</tr>
883957
)}
958+
959+
{/* Render fields in balanced columns - only create rows with content */}
960+
{maxRows > 0 &&
961+
Array.from({ length: maxRows })
962+
.map((_, rowIndex) => {
963+
// Check if this row has any actual content
964+
const rowHasContent = fieldColumns.some((column) => {
965+
const field = column[rowIndex];
966+
return field && field.propKey !== 'name';
967+
});
968+
969+
// Skip empty rows
970+
if (!rowHasContent) {
971+
return null;
972+
}
973+
974+
return (
975+
<tr key={`row-${rowIndex}`}>
976+
{fieldColumns
977+
.map((column, colIndex) => {
978+
const field = column[rowIndex];
979+
980+
// Skip name field - already shown in header
981+
if (field && field.propKey === 'name') {
982+
return null;
983+
}
984+
985+
// Only render cells that have actual content
986+
if (!field) {
987+
return null;
988+
}
989+
990+
const { propKey, propSchema } = field;
991+
992+
return (
993+
<td
994+
key={`${propKey}-${colIndex}-${rowIndex}`}
995+
style={{
996+
verticalAlign: 'top',
997+
width: `${100 / actualColumnCount}%`,
998+
padding: '0 4px',
999+
}}
1000+
>
1001+
<Box padding="0">{renderField(propKey, propSchema, itemPath)}</Box>
1002+
</td>
1003+
);
1004+
})
1005+
.filter(Boolean)}
1006+
</tr>
1007+
);
1008+
})
1009+
.filter(Boolean)}
8841010
</tbody>
8851011
</table>
8861012
</Box>

0 commit comments

Comments
 (0)