feat(frontend): add new OutputComponent to handle dropdown menu for selecting output types in generic nodes

feat(frontend): remove ComponentOutputs component and integrate its functionality into ParameterComponent
feat(frontend): update ParameterComponent to use OutputComponent for displaying output types
feat(frontend): update GenericNode to use OutputComponent for displaying output types and remove ComponentOutputs
feat(types): update ParameterComponentType to use number type for index instead of string
This commit is contained in:
anovazzi1 2024-05-27 16:08:34 -03:00
commit 596ab2f282
5 changed files with 57 additions and 103 deletions

View file

@ -8,20 +8,20 @@ import ForwardedIconComponent from "../../../../components/genericIconComponent"
import { outputComponentType } from "../../../../types/components"; import { outputComponentType } from "../../../../types/components";
import { cn } from "../../../../utils/utils"; import { cn } from "../../../../utils/utils";
import useFlowStore from "../../../../stores/flowStore"; import useFlowStore from "../../../../stores/flowStore";
import { NodeDataType } from "../../../../types/flow";
import { cloneDeep } from "lodash";
export default function ComponentOutput({ export default function OutputComponent({
selected, selected,
types, types,
frozen = false, frozen = false,
nodeId, nodeId,
idx,
}: outputComponentType) { }: outputComponentType) {
const setNode = useFlowStore((state) => state.setNode); const setNode = useFlowStore((state) => state.setNode);
let displayTitle = selected ?? types[0];
if (types.length < 2) { if (types.length < 2) {
return ( return <span className={cn(frozen ? " text-ice" : "")}>{selected}</span>;
<span className={cn(frozen ? " text-ice" : "")}>{displayTitle}</span>
);
} }
return ( return (
@ -30,7 +30,7 @@ export default function ComponentOutput({
<span <span
className={cn(frozen ? " text-ice" : "", "flex items-center gap-1")} className={cn(frozen ? " text-ice" : "", "flex items-center gap-1")}
> >
{displayTitle} {selected}
<ForwardedIconComponent name="ChevronDown" className="h-4 w-4" /> <ForwardedIconComponent name="ChevronDown" className="h-4 w-4" />
</span> </span>
</DropdownMenuTrigger> </DropdownMenuTrigger>
@ -39,10 +39,12 @@ export default function ComponentOutput({
<DropdownMenuItem <DropdownMenuItem
onSelect={() => { onSelect={() => {
// TODO: UDPDATE SET NODE TO NEW NODE FORM // TODO: UDPDATE SET NODE TO NEW NODE FORM
setNode(nodeId, (node) => ({ setNode(nodeId, (node) => {
...node, const newNode = cloneDeep(node);
data: { ...node.data, selected: type }, (newNode.data as NodeDataType).node!.outputs![idx].selected =
})); type;
return newNode;
});
}} }}
> >
{type} {type}

View file

@ -1,17 +0,0 @@
import { NodeDataType } from "../../../../types/flow";
import ComponentOutput from "../ComponentOutput";
export default function ComponentOutputs({ data }: { data: NodeDataType }) {
return (
<div>
{data.node?.outputs?.map((output) => (
<ComponentOutput
nodeId={data.id}
frozen={data.node?.frozen}
types={output.types}
selected={output.selected ?? output.types[0]}
/>
))}
</div>
);
}

View file

@ -55,6 +55,7 @@ import useHandleNodeClass from "../../../hooks/use-handle-node-class";
import useHandleRefreshButtonPress from "../../../hooks/use-handle-refresh-buttons"; import useHandleRefreshButtonPress from "../../../hooks/use-handle-refresh-buttons";
import TooltipRenderComponent from "../tooltipRenderComponent"; import TooltipRenderComponent from "../tooltipRenderComponent";
import HandleTooltips from "../HandleTooltipComponent"; import HandleTooltips from "../HandleTooltipComponent";
import OutputComponent from "../OutputComponent";
export default function ParameterComponent({ export default function ParameterComponent({
left, left,
@ -70,12 +71,9 @@ export default function ParameterComponent({
info = "", info = "",
proxy, proxy,
showNode, showNode,
index = "", index,
}: ParameterComponentType): JSX.Element { }: ParameterComponentType): JSX.Element {
const ref = useRef<HTMLDivElement>(null);
const infoHtml = useRef<HTMLDivElement & ReactNode>(null); const infoHtml = useRef<HTMLDivElement & ReactNode>(null);
const setErrorData = useAlertStore((state) => state.setErrorData);
const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
const nodes = useFlowStore((state) => state.nodes); const nodes = useFlowStore((state) => state.nodes);
const edges = useFlowStore((state) => state.edges); const edges = useFlowStore((state) => state.edges);
const setNode = useFlowStore((state) => state.setNode); const setNode = useFlowStore((state) => state.setNode);
@ -145,40 +143,16 @@ export default function ParameterComponent({
}, [info]); }, [info]);
function renderTitle() { function renderTitle() {
const output_types = title.split("|"); return !left ? (
const displayTitle = data.selected_output_type ?? output_types[0]; <OutputComponent
return !left && output_types.length > 1 ? ( idx={index}
<DropdownMenu> types={type?.split("|") ?? []}
<DropdownMenuTrigger> selected={title}
<span nodeId={data.id}
className={cn( frozen={data.node?.frozen}
!left && data.node?.frozen ? " text-ice" : "", />
"flex items-center gap-1",
)}
>
{displayTitle}
<ForwardedIconComponent name="ChevronDown" className="h-4 w-4" />
</span>
</DropdownMenuTrigger>
<DropdownMenuContent>
{output_types.map((type) => (
<DropdownMenuItem
onSelect={() => {
setNode(data.id, (node) => ({
...node,
data: { ...node.data, selected_output_type: type },
}));
}}
>
{type}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
) : ( ) : (
<span className={cn(!left && data.node?.frozen ? " text-ice" : "")}> <span>{title}</span>
{title}
</span>
); );
} }
@ -244,7 +218,6 @@ export default function ParameterComponent({
) )
) : ( ) : (
<div <div
ref={ref}
className={ className={
"relative mt-1 flex w-full flex-wrap items-center justify-between bg-muted px-5 py-2" + "relative mt-1 flex w-full flex-wrap items-center justify-between bg-muted px-5 py-2" +
((name === "code" && type === "code") || ((name === "code" && type === "code") ||

View file

@ -31,7 +31,6 @@ import { classNames, cn } from "../../utils/utils";
import ParameterComponent from "./components/parameterComponent"; import ParameterComponent from "./components/parameterComponent";
import getFieldTitle from "../utils/get-field-title"; import getFieldTitle from "../utils/get-field-title";
import sortFields from "../utils/sort-fields"; import sortFields from "../utils/sort-fields";
import ComponentOutputs from "./components/componentOutputs";
export default function GenericNode({ export default function GenericNode({
data, data,
@ -498,7 +497,7 @@ export default function GenericNode({
data.node!.template[templateField].show && data.node!.template[templateField].show &&
!data.node!.template[templateField].advanced && ( !data.node!.template[templateField].advanced && (
<ParameterComponent <ParameterComponent
index={idx.toString()} index={idx}
key={scapedJSONStringfy({ key={scapedJSONStringfy({
inputTypes: inputTypes:
data.node!.template[templateField].input_types, data.node!.template[templateField].input_types,
@ -571,6 +570,7 @@ export default function GenericNode({
), ),
)} )}
<ParameterComponent <ParameterComponent
index={0}
key={scapedJSONStringfy({ key={scapedJSONStringfy({
baseClasses: data.node!.base_classes, baseClasses: data.node!.base_classes,
id: data.id, id: data.id,
@ -748,7 +748,7 @@ export default function GenericNode({
{data.node!.template[templateField].show && {data.node!.template[templateField].show &&
!data.node!.template[templateField].advanced ? ( !data.node!.template[templateField].advanced ? (
<ParameterComponent <ParameterComponent
index={idx.toString()} index={idx}
key={scapedJSONStringfy({ key={scapedJSONStringfy({
inputTypes: inputTypes:
data.node!.template[templateField].input_types, data.node!.template[templateField].input_types,
@ -825,40 +825,35 @@ export default function GenericNode({
> >
{" "} {" "}
</div> </div>
{data.node!.outputs && data.node!.outputs.length > 0 && ( {data.node!.outputs &&
<ComponentOutputs data={data} /> data.node!.outputs.length > 0 &&
)} data.node!.outputs.map((output, idx) => (
{data.node!.base_classes.length > 0 && ( <ParameterComponent
<ParameterComponent index={idx}
key={scapedJSONStringfy({ key={scapedJSONStringfy({
baseClasses: data.node!.base_classes, baseClasses: [output.selected ?? output.types[0]],
id: data.id, id: data.id,
dataType: data.type, dataType: data.type,
})} })}
data={data} data={data}
color={ color={
(data.node?.output_types && nodeColors[output.selected ?? output.types[0]] ??
data.node.output_types.length > 0 nodeColors[types[output.selected ?? output.types[0]]] ??
? nodeColors[data.node.output_types[0]] ?? nodeColors[types[data.type]] ??
nodeColors[types[data.node.output_types[0]]] nodeColors.unknown
: nodeColors[types[data.type]]) ?? nodeColors.unknown }
} title={output.selected ?? output.types[0]}
title={ tooltipTitle={output.selected ?? output.types[0]}
data.node?.output_types && data.node.output_types.length > 0 id={{
? data.node.output_types.join(" | ") baseClasses: [output.selected ?? output.types[0]],
: data.type id: data.id,
} dataType: data.type,
tooltipTitle={data.node?.base_classes.join("\n")} }}
id={{ type={output.types.join("|")}
baseClasses: data.node!.base_classes, left={false}
id: data.id, showNode={showNode}
dataType: data.type, />
}} ))}
type={data.node?.base_classes.join("|")}
left={false}
showNode={showNode}
/>
)}
</> </>
</div> </div>
)} )}

View file

@ -67,7 +67,7 @@ export type ParameterComponentType = {
info?: string; info?: string;
proxy?: { field: string; id: string }; proxy?: { field: string; id: string };
showNode?: boolean; showNode?: boolean;
index?: string; index: number;
onCloseModal?: (close: boolean) => void; onCloseModal?: (close: boolean) => void;
}; };
export type InputListComponentType = { export type InputListComponentType = {
@ -116,6 +116,7 @@ export type outputComponentType = {
selected: string; selected: string;
nodeId: string; nodeId: string;
frozen?: boolean; frozen?: boolean;
idx: number;
}; };
export type PromptAreaComponentType = { export type PromptAreaComponentType = {