import {
configurableValue,
ConfigurableEditorComp,
ConfigurableEditorConfigStructured,
evaluateCondition,
ConfigurableValue,
PartialEditorPorts,
} from "@flyde/core";
import { ConfigurableFieldEditor } from "../../ui";
import { usePorts } from "../../flow-editor/ports";
import { useState } from "react";
// Define the GroupFieldDefinition type
interface GroupFieldDefinition {
type: "group";
configKey: string;
label: string;
description?: string;
condition?: string;
fields: any[]; // Using any[] to avoid typing issues
typeData?: {
collapsible?: boolean;
defaultCollapsed?: boolean;
};
}
// Type guard to check if a field is a group
function isGroupField(field: any): field is GroupFieldDefinition {
return field && field.type === "group" && Array.isArray(field.fields);
}
// Helper function to evaluate field visibility based on its condition
function evaluateFieldVisibility(field: any, value: any): boolean {
if (field.condition) {
return evaluateCondition(field.condition, value);
}
return true;
}
// Component to render a group of fields
function GroupFields({
group,
value,
onChange,
ports,
nodeId,
insId
}: {
group: GroupFieldDefinition;
value: any;
onChange: (value: any) => void;
ports: PartialEditorPorts;
nodeId: string;
insId?: string;
}) {
const [isCollapsed, setIsCollapsed] = useState(
group.typeData?.defaultCollapsed ?? false
);
if (!evaluateFieldVisibility(group, value)) {
return null;
}
return (
{
if (group.typeData?.collapsible) {
setIsCollapsed(!isCollapsed);
}
}}
>
{group.label}
{group.typeData?.collapsible && (
{isCollapsed ? "▼ Show" : "▲ Hide"}
)}
{group.description && (
{group.description}
)}
{!isCollapsed && (
{group.fields.map((field: any) => {
// Check if the field is a group
if (isGroupField(field)) {
return (
);
}
// Check if the field should be visible
if (!evaluateFieldVisibility(field, value)) {
return null;
}
// Use ConfigurableFieldEditor for all fields
return (
onChange({
...value,
[field.configKey]: newValue,
})
}
ports={ports}
config={field}
nodeId={nodeId}
insId={insId}
/>
);
})}
)}
);
}
export function StructuredConfigurableEditorComp(
editorConfig: ConfigurableEditorConfigStructured
): ConfigurableEditorComp {
return (props) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const ports = usePorts();
return (
{editorConfig.fields.map((field: any) => {
// Check if the field is a group
if (isGroupField(field)) {
return (
);
}
// Check if the field has a condition and evaluate it
if (!evaluateFieldVisibility(field, props.value)) {
return null;
}
const configValue: Record = props.value && typeof props.value === "object" ? props.value : {};
const value = configValue[field.configKey] ?? configurableValue("dynamic", "");
// Use ConfigurableFieldEditor for all fields
return (
props.onChange({
...props.value,
[field.configKey]: newValue,
})
}
config={field}
ports={ports}
nodeId={props.nodeId}
insId={props.insId}
/>
);
})}
);
};
}