diff --git a/dashboard/src/components/dynamic-form/DynamicConfigForm.tsx b/dashboard/src/components/dynamic-form/DynamicConfigForm.tsx index 012c2dbd..ee1d7339 100644 --- a/dashboard/src/components/dynamic-form/DynamicConfigForm.tsx +++ b/dashboard/src/components/dynamic-form/DynamicConfigForm.tsx @@ -5,7 +5,6 @@ import { Button } from '@/components/ui/button' import { Card, CardContent, - CardDescription, CardHeader, CardTitle, } from '@/components/ui/card' @@ -31,20 +30,10 @@ function buildFieldPath(basePath: string, fieldName: string) { return basePath ? `${basePath}.${fieldName}` : fieldName } -function hasTopLevelAdvancedFields(schema: ConfigSchema) { - return schema.fields.some((field) => field.advanced && !schema.nested?.[field.name]) -} - function resolveSectionTitle(schema: ConfigSchema) { return schema.uiLabel || schema.classDoc || schema.className } -function resolveSectionDescription(schema: ConfigSchema, sectionTitle: string) { - return schema.classDoc && schema.classDoc !== sectionTitle - ? schema.classDoc - : undefined -} - function SectionIcon({ iconName }: { iconName?: string }) { if (!iconName) return null const IconComponent = LucideIcons[iconName as keyof typeof LucideIcons] as @@ -54,7 +43,7 @@ function SectionIcon({ iconName }: { iconName?: string }) { return } -function AdvancedSettingsButton({ +export function AdvancedSettingsButton({ active, onClick, }: { @@ -74,51 +63,39 @@ function AdvancedSettingsButton({ } function DynamicConfigSection({ + advancedVisible, basePath, hooks, level, nestedSchema, onChange, - sectionDescription, sectionKey, sectionTitle, values, }: { + advancedVisible: boolean basePath: string hooks: FieldHookRegistry level: number nestedSchema: ConfigSchema onChange: (field: string, value: unknown) => void - sectionDescription?: string sectionKey: string sectionTitle: string values: Record }) { - const [advancedVisible, setAdvancedVisible] = React.useState(false) - const hasAdvanced = hasTopLevelAdvancedFields(nestedSchema) - return ( - +
- {sectionTitle} + {sectionTitle}
- {sectionDescription && ( - {sectionDescription} - )}
- {hasAdvanced && ( - setAdvancedVisible((current) => !current)} - /> - )}
- + @@ -154,8 +131,7 @@ export const DynamicConfigForm: React.FC = ({ advancedVisible, sectionColumns = 1, }) => { - const [localAdvancedVisible, setLocalAdvancedVisible] = React.useState(false) - const resolvedAdvancedVisible = advancedVisible ?? localAdvancedVisible + const resolvedAdvancedVisible = advancedVisible ?? false const fieldMap = React.useMemo( () => new Map(schema.fields.map((field) => [field.name, field])), @@ -230,6 +206,51 @@ export const DynamicConfigForm: React.FC = ({ return hooks.get(fieldPath)?.type === 'replace' } + const schemaHasVisibleContent = React.useCallback( + (targetSchema: ConfigSchema, targetBasePath: string): boolean => { + const targetFields = targetSchema.fields ?? [] + const hasVisibleInlineField = targetFields.some((field) => { + const fieldPath = buildFieldPath(targetBasePath, field.name) + const hookEntry = hooks.get(fieldPath) + + if (hookEntry?.type === 'hidden') { + return false + } + + if (targetSchema.nested?.[field.name] && hookEntry?.type !== 'replace') { + return false + } + + return resolvedAdvancedVisible || !field.advanced + }) + + if (hasVisibleInlineField) { + return true + } + + return Object.entries(targetSchema.nested ?? {}).some(([key, nestedSchema]) => { + const nestedField = targetFields.find((field) => field.name === key) + const nestedFieldPath = buildFieldPath(targetBasePath, key) + const hookEntry = hooks.get(nestedFieldPath) + + if (hookEntry?.type === 'hidden') { + return false + } + + if (nestedField?.advanced && !resolvedAdvancedVisible) { + return false + } + + if (hookEntry?.type === 'replace') { + return true + } + + return schemaHasVisibleContent(nestedSchema, nestedFieldPath) + }) + }, + [hooks, resolvedAdvancedVisible], + ) + const inlineFields = schema.fields.filter(shouldRenderFieldInline) const inlineNestedFieldNames = new Set( inlineFields @@ -302,16 +323,8 @@ export const DynamicConfigForm: React.FC = ({ return (
- {inlineFields.length > 0 && ( + {visibleFields.length > 0 && (
- {advancedVisible === undefined && advancedFields.length > 0 && ( -
- setLocalAdvancedVisible((current) => !current)} - /> -
- )} {renderFieldList(visibleFields)}
)} @@ -327,6 +340,15 @@ export const DynamicConfigForm: React.FC = ({ if (hooks.has(nestedFieldPath)) { const hookEntry = hooks.get(nestedFieldPath) if (!hookEntry) return null + if (hookEntry.type === 'hidden') return null + if (nestedField?.advanced && !resolvedAdvancedVisible) return null + if ( + hookEntry.type !== 'replace' && + nestedSchema && + !schemaHasVisibleContent(nestedSchema, nestedFieldPath) + ) { + return null + } const HookComponent = hookEntry.component if (hookEntry.type === 'replace') { @@ -363,6 +385,7 @@ export const DynamicConfigForm: React.FC = ({ basePath={nestedFieldPath} hooks={hooks} level={level + 1} + advancedVisible={resolvedAdvancedVisible} sectionColumns={1} /> @@ -371,12 +394,15 @@ export const DynamicConfigForm: React.FC = ({ } const sectionTitle = resolveSectionTitle(nestedSchema) - const sectionDescription = resolveSectionDescription(nestedSchema, sectionTitle) + if (!schemaHasVisibleContent(nestedSchema, nestedFieldPath)) { + return null + } if (level === 0) { return ( ) || {}} onChange={onChange} @@ -385,29 +411,23 @@ export const DynamicConfigForm: React.FC = ({ level={level + 1} sectionKey={key} sectionTitle={sectionTitle} - sectionDescription={sectionDescription} /> ) } return ( - +
- {sectionTitle} + {sectionTitle}
- {sectionDescription && ( - - {sectionDescription} - - )}
- + ) || {}} @@ -415,6 +435,7 @@ export const DynamicConfigForm: React.FC = ({ basePath={nestedFieldPath} hooks={hooks} level={level + 1} + advancedVisible={resolvedAdvancedVisible} sectionColumns={1} /> diff --git a/dashboard/src/components/dynamic-form/DynamicField.tsx b/dashboard/src/components/dynamic-form/DynamicField.tsx index 0e6156fc..cfd6171a 100644 --- a/dashboard/src/components/dynamic-form/DynamicField.tsx +++ b/dashboard/src/components/dynamic-form/DynamicField.tsx @@ -158,10 +158,10 @@ export const DynamicField: React.FC = ({ const label = (