Added Hide Outputs functionality

This commit is contained in:
Lucas Oliveira 2024-06-12 19:40:38 -03:00
commit c65f2e1ab1
5 changed files with 161 additions and 40 deletions

View file

@ -164,6 +164,9 @@ class Output(BaseModel):
name: str = Field(default=None) name: str = Field(default=None)
"""The name of the field.""" """The name of the field."""
hide: Optional[bool] = Field(default=None)
"""Dictates if the field is hidden."""
display_name: Optional[str] = Field(default=None) display_name: Optional[str] = Field(default=None)
"""The display name of the field.""" """The display name of the field."""

View file

@ -135,6 +135,12 @@ export default function ParameterComponent({
edge.targetHandle === scapedJSONStringfy(proxy ? { ...id, proxy } : id) edge.targetHandle === scapedJSONStringfy(proxy ? { ...id, proxy } : id)
) ?? false; ) ?? false;
let disabledOutput =
edges.some(
(edge) =>
edge.sourceHandle === scapedJSONStringfy(proxy ? { ...id, proxy } : id),
) ?? false;
const handleRefreshButtonPress = async (name, data) => { const handleRefreshButtonPress = async (name, data) => {
handleRefreshButtonPressHook(name, data); handleRefreshButtonPressHook(name, data);
}; };
@ -190,6 +196,32 @@ export default function ParameterComponent({
optionalHandle = null; optionalHandle = null;
} }
const handleUpdateOutputHide = (value?: boolean) => {
setNode(data.id, (oldNode) => {
let newNode = cloneDeep(oldNode);
newNode.data = {
...newNode.data,
node: {
...newNode.data.node,
outputs: newNode.data.node.outputs?.map((output, i) => {
if (i === index) {
output.hide = value ?? !output.hide;
}
return output;
}),
},
};
return newNode;
});
updateNodeInternals(data.id);
};
useEffect(() => {
if (disabledOutput) {
handleUpdateOutputHide(false);
}
}, [disabledOutput]);
return !showNode ? ( return !showNode ? (
left && LANGFLOW_SUPPORTED_TYPES.has(type ?? "") && !optionalHandle ? ( left && LANGFLOW_SUPPORTED_TYPES.has(type ?? "") && !optionalHandle ? (
<></> <></>
@ -262,6 +294,23 @@ export default function ParameterComponent({
(left ? "" : " justify-end") (left ? "" : " justify-end")
} }
> >
{!left && (
<div className="flex-1">
<Button
disabled={disabledOutput}
variant="none"
size="none"
onClick={() => handleUpdateOutputHide()}
data-testid={`output-inspection-${title.toLowerCase()}`}
>
<IconComponent
className="h-4 w-4"
strokeWidth={1.5}
name={data.node?.outputs![index].hide ? "EyeOff" : "Eye"}
/>
</Button>
</div>
)}
<Case condition={left && data.node?.frozen}> <Case condition={left && data.node?.frozen}>
<div className="pr-1"> <div className="pr-1">
<IconComponent className="h-5 w-5 text-ice" name={"Snowflake"} /> <IconComponent className="h-5 w-5 text-ice" name={"Snowflake"} />
@ -325,6 +374,7 @@ export default function ParameterComponent({
)} )}
</div> </div>
</div> </div>
{left && LANGFLOW_SUPPORTED_TYPES.has(type ?? "") && !optionalHandle ? ( {left && LANGFLOW_SUPPORTED_TYPES.has(type ?? "") && !optionalHandle ? (
<></> <></>
) : ( ) : (

View file

@ -3,7 +3,9 @@ import { useEffect, useMemo, useState } from "react";
import { useHotkeys } from "react-hotkeys-hook"; import { useHotkeys } from "react-hotkeys-hook";
import Markdown from "react-markdown"; import Markdown from "react-markdown";
import { NodeToolbar, useUpdateNodeInternals } from "reactflow"; import { NodeToolbar, useUpdateNodeInternals } from "reactflow";
import IconComponent from "../../components/genericIconComponent"; import IconComponent, {
ForwardedIconComponent,
} from "../../components/genericIconComponent";
import InputComponent from "../../components/inputComponent"; import InputComponent from "../../components/inputComponent";
import ShadTooltip from "../../components/shadTooltipComponent"; import ShadTooltip from "../../components/shadTooltipComponent";
import { Button } from "../../components/ui/button"; import { Button } from "../../components/ui/button";
@ -210,6 +212,8 @@ export default function GenericNode({
const [loadingUpdate, setLoadingUpdate] = useState(false); const [loadingUpdate, setLoadingUpdate] = useState(false);
const [showHiddenOutputs, setShowHiddenOutputs] = useState(false);
const handleUpdateCode = () => { const handleUpdateCode = () => {
setLoadingUpdate(true); setLoadingUpdate(true);
takeSnapshot(); takeSnapshot();
@ -241,6 +245,12 @@ export default function GenericNode({
} }
} }
const shownOutputs =
data.node!.outputs?.filter((output) => !output.hide) ?? [];
const hiddenOutputs =
data.node!.outputs?.filter((output) => output.hide) ?? [];
function handlePlayWShortcut() { function handlePlayWShortcut() {
if (buildStatus === BuildStatus.BUILDING || isBuilding || !selected) return; if (buildStatus === BuildStatus.BUILDING || isBuilding || !selected) return;
setValidationStatus(null); setValidationStatus(null);
@ -256,6 +266,42 @@ export default function GenericNode({
const shortcuts = useShortcutsStore((state) => state.shortcuts); const shortcuts = useShortcutsStore((state) => state.shortcuts);
const renderOutputParameter = (output, idx) => {
return (
<ParameterComponent
index={idx}
key={
scapedJSONStringfy({
output_types: output.types,
name: output.name,
id: data.id,
dataType: data.type,
}) + idx
}
data={data}
color={
nodeColors[output.selected ?? output.types[0]] ??
nodeColors[types[output.selected ?? output.types[0]]] ??
nodeColors[types[data.type]] ??
nodeColors.unknown
}
outputProxy={output.proxy}
title={output.display_name ?? output.name}
tooltipTitle={output.selected ?? output.types[0]}
id={{
output_types: [output.selected ?? output.types[0]],
id: data.id,
dataType: data.type,
name: output.name,
}}
type={output.types.join("|")}
left={false}
showNode={showNode}
outputName={output.name}
/>
);
};
const memoizedNodeToolbarComponent = useMemo(() => { const memoizedNodeToolbarComponent = useMemo(() => {
return ( return (
<NodeToolbar> <NodeToolbar>
@ -582,13 +628,14 @@ export default function GenericNode({
{showNode && ( {showNode && (
<div <div
className={ className={cn(
showNode showNode
? data.node?.description === "" && !nameEditable ? data.node?.description === "" && !nameEditable
? "pb-5" ? "pb-8"
: "py-5" : "pb-8 pt-5"
: "" : "",
} "relative",
)}
> >
{/* increase height!! */} {/* increase height!! */}
<div className="generic-node-desc"> <div className="generic-node-desc">
@ -751,39 +798,58 @@ export default function GenericNode({
> >
{" "} {" "}
</div> </div>
{data.node!.outputs && {!showHiddenOutputs &&
data.node!.outputs.length > 0 && shownOutputs &&
data.node!.outputs.map((output, idx) => ( shownOutputs.map((output, idx) =>
<ParameterComponent renderOutputParameter(
index={idx} output,
key={scapedJSONStringfy({ data.node!.outputs?.findIndex(
output_types: output.types, (out) => out.name === output.name,
name: output.name, ) ?? idx,
id: data.id, ),
dataType: data.type, )}
})} <div
data={data} className={cn(showHiddenOutputs ? "" : "h-0 overflow-hidden")}
color={ >
nodeColors[output.selected ?? output.types[0]] ?? <div className="block">
nodeColors[types[output.selected ?? output.types[0]]] ?? {data.node!.outputs &&
nodeColors[types[data.type]] ?? data.node!.outputs.map((output, idx) =>
nodeColors.unknown renderOutputParameter(
} output,
outputProxy={output.proxy} data.node!.outputs?.findIndex(
title={output.display_name ?? output.name} (out) => out.name === output.name,
tooltipTitle={output.selected ?? output.types[0]} ) ?? idx,
id={{ ),
output_types: [output.selected ?? output.types[0]], )}
id: data.id, </div>
dataType: data.type, </div>
name: output.name, {hiddenOutputs && hiddenOutputs.length > 0 && (
}} <div
type={output.types.join("|")} className={cn(
left={false} "absolute left-0 right-0 flex justify-center",
showNode={showNode} (shownOutputs && shownOutputs.length > 0) ||
outputName={output.name} showHiddenOutputs
/> ? "bottom-5"
))} : "bottom-1.5",
)}
>
<Button
variant="none"
size="none"
className="left-0 right-0 rounded-full border bg-background"
onClick={() => setShowHiddenOutputs(!showHiddenOutputs)}
>
<ForwardedIconComponent
name={"ChevronDown"}
strokeWidth={1.5}
className={cn(
"h-5 w-5 pt-px text-muted-foreground transition-all group-hover:text-medium-indigo group-hover/node:opacity-100",
showHiddenOutputs ? "rotate-180 transform" : "",
)}
/>
</Button>
</div>
)}
</> </>
</div> </div>
)} )}

View file

@ -76,6 +76,7 @@ export type OutputFieldType = {
selected?: string; selected?: string;
name: string; name: string;
display_name: string; display_name: string;
hide?: boolean;
proxy?: OutputFieldProxyType; proxy?: OutputFieldProxyType;
}; };
export type sendAllProps = { export type sendAllProps = {

View file

@ -59,10 +59,11 @@ export type DropDownComponentType = {
children?: ReactNode; children?: ReactNode;
}; };
export type ParameterComponentType = { export type ParameterComponentType = {
selected: boolean; selected?: boolean;
data: NodeDataType; data: NodeDataType;
title: string; title: string;
conditionPath?: string | null; conditionPath?: string | null;
key: string;
id: sourceHandleType | targetHandleType; id: sourceHandleType | targetHandleType;
color: string; color: string;
left: boolean; left: boolean;