Fixed rebase

This commit is contained in:
Lucas Oliveira 2024-02-26 17:41:30 +01:00
commit 1601d23d67
9 changed files with 240 additions and 200 deletions

View file

@ -121,7 +121,6 @@ export default function GenericNode({
}, [flowPool, data.id]); }, [flowPool, data.id]);
const showNode = data.showNode ?? true; const showNode = data.showNode ?? true;
const pinned = data.node?.pinned ?? false;
const nameEditable = data.node?.flow || data.type === "CustomComponent"; const nameEditable = data.node?.flow || data.type === "CustomComponent";
@ -161,7 +160,7 @@ export default function GenericNode({
const getIconPlayOrPauseComponent = (name, className) => ( const getIconPlayOrPauseComponent = (name, className) => (
<IconComponent <IconComponent
name={name} name={name}
className={`absolute h-5 stroke-2 ${className} ml-0.5`} className={`h-4 fill-current stroke-2 ${className}`}
/> />
); );
@ -180,15 +179,18 @@ export default function GenericNode({
return "red-status"; return "red-status";
} else if (!validationStatus && buildStatus === BuildStatus.TO_BUILD) { } else if (!validationStatus && buildStatus === BuildStatus.TO_BUILD) {
return "green-status"; return "green-status";
} else if (buildStatus === BuildStatus.BUILDING) {
return "status-build-animation";
} else { } else {
return "green-status"; return "yellow-status";
} }
}; };
const isDark = useDarkStore((state) => state.dark); const isDark = useDarkStore((state) => state.dark);
console.log(isDark); const renderIconStatusComponents = (
buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null
) => {
const className = getStatusClassName(buildStatus, validationStatus);
return <>{getIconPlayOrPauseComponent("CircleDot", className)}</>;
};
const renderIconPlayOrPauseComponents = ( const renderIconPlayOrPauseComponents = (
buildStatus: BuildStatus | undefined, buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null validationStatus: validationStatusType | null
@ -196,8 +198,12 @@ export default function GenericNode({
if (buildStatus === BuildStatus.BUILDING) { if (buildStatus === BuildStatus.BUILDING) {
return <Loading />; return <Loading />;
} else { } else {
const className = getStatusClassName(buildStatus, validationStatus); return (
return <>{getIconPlayOrPauseComponent("Play", className)}</>; <IconComponent
name="Play"
className="absolute ml-0.5 h-5 fill-current stroke-2 text-muted-foreground hover:text-medium-indigo"
/>
);
} }
}; };
@ -450,72 +456,18 @@ export default function GenericNode({
</div> </div>
{showNode && ( {showNode && (
<Button <Button
variant="outline" variant="secondary"
className="h-9 px-1.5" className={"group h-9 px-1.5"}
onClick={() => {
setNode(data.id, (old) => ({
...old,
data: {
...old.data,
node: {
...old.data.node,
pinned: old.data?.node?.pinned ? false : true,
},
},
}));
}}
>
<Tooltip
title={<span>{pinned ? "Pin Output" : "Unpin Output"}</span>}
>
<div className="generic-node-status-position flex items-center">
<IconComponent
name={"Pin"}
className={cn(
"h-5 fill-transparent stroke-chat-trigger stroke-2 transition-all",
pinned ? "animate-wiggle fill-chat-trigger" : ""
)}
/>
</div>
</Tooltip>
</Button>
)}
{showNode && (
<Button
variant="outline"
className={"h-9 px-1.5"}
onClick={() => { onClick={() => {
if (data?.buildStatus === BuildStatus.BUILDING || isBuilding) if (data?.buildStatus === BuildStatus.BUILDING || isBuilding)
return; return;
buildFlow(data.id); buildFlow(data.id);
}} }}
> >
<div> <div>
<Tooltip <Tooltip
title={ title={
data?.buildStatus === BuildStatus.BUILDING ? ( "Build"
<span>Building...</span>
) : !validationStatus ? (
<span className="flex">
Build{" "}
<IconComponent
name="Play"
className=" h-5 stroke-status-green stroke-2"
/>{" "}
flow to validate status.
</span>
) : (
<div className="max-h-96 overflow-auto">
{typeof validationStatus.params === "string"
? `${durationString}\n${validationStatus.params}`
.split("\n")
.map((line, index) => (
<div key={index}>{line}</div>
))
: durationString}
</div>
)
} }
> >
<div className="generic-node-status-position flex items-center justify-center"> <div className="generic-node-status-position flex items-center justify-center">
@ -528,6 +480,32 @@ export default function GenericNode({
</div> </div>
</Button> </Button>
)} )}
<div className="">
<Tooltip
title={
data?.buildStatus === BuildStatus.BUILDING ? (
<span>Building...</span>
) : !validationStatus ? (
<span className="flex">Build to validate status.</span>
) : (
<div className="max-h-96 overflow-auto">
{typeof validationStatus.params === "string"
? `${durationString}\n${validationStatus.params}`
.split("\n")
.map((line, index) => <div key={index}>{line}</div>)
: durationString}
</div>
)
}
>
<div>
{renderIconStatusComponents(
data?.buildStatus,
validationStatus
)}
</div>
</Tooltip>
</div>
</div> </div>
</div> </div>

View file

@ -63,7 +63,7 @@ export default function IOInputField({
} }
} }
return ( return (
<div className="font-xl flex h-full w-full flex-col gap-4 p-4 font-semibold"> <div className="font-xl flex items-start h-full w-full flex-col gap-4 p-4 font-semibold">
{inputType} {inputType}
{handleInputType()} {handleInputType()}
</div> </div>

View file

@ -44,7 +44,7 @@ export default function IOOutputView({
} }
} }
return ( return (
<div className="font-xl flex h-full w-full flex-col gap-4 p-4 font-semibold"> <div className="font-xl flex h-full items-start w-full flex-col gap-4 p-4 font-semibold">
{outputType} {outputType}
{handleOutputType()} {handleOutputType()}
</div> </div>

View file

@ -10,6 +10,7 @@ import IconComponent from "../genericIconComponent";
import NewChatView from "../newChatView"; import NewChatView from "../newChatView";
import { Badge } from "../ui/badge"; import { Badge } from "../ui/badge";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs";
export default function IOView({ children, open, setOpen }): JSX.Element { export default function IOView({ children, open, setOpen }): JSX.Element {
const inputs = useFlowStore((state) => state.inputs).filter( const inputs = useFlowStore((state) => state.inputs).filter(
@ -67,123 +68,147 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
haveChat ? "w-2/6" : "w-full" haveChat ? "w-2/6" : "w-full"
)} )}
> >
<div className="flex w-full items-center justify-between py-2"> <Tabs
<div className="flex items-start gap-4"> value={selectedTab.toString()}
{inputs.length > 0 && ( className={"api-modal-tabs "}
<Button onValueChange={(value) => {
onClick={() => setSelectedTab(1)} setSelectedTab(Number(value));
variant={selectedTab === 1 ? "primary" : "secondary"} }}
> >
<IconComponent <div className="api-modal-tablist-div">
name="FormInput" <TabsList>
className=" file-component-variable" {inputs.length > 0 && (
/> <TabsTrigger value={"1"}>Inputs</TabsTrigger>
<span className="file-component-variables-span text-md"> )}
Inputs {outputs.length > 0 && (
</span> <TabsTrigger value={"2"}>Outputs</TabsTrigger>
</Button> )}
)} </TabsList>
{outputs.length > 0 && (
<Button
onClick={() => setSelectedTab(2)}
variant={selectedTab === 2 ? "primary" : "secondary"}
>
<IconComponent
name="ChevronRightSquare"
className=" file-component-variable"
/>
<span className="file-component-variables-span text-md">
Outputs
</span>
</Button>
)}
</div> </div>
{selectedViewField && haveChat && (
<Button <TabsContent
onClick={() => setSelectedViewField(undefined)} value={"1"}
variant="outline" className="api-modal-tabs-content mt-4"
key={"chat"} >
className="self-end px-2.5" <div className="mx-2 mb-2 flex items-center gap-2 text-sm font-bold">
> <IconComponent className="h-4 w-4" name={"Type"} />
<IconComponent
name="MessageSquareMore"
className="h-5 w-5"
/>
</Button>
)}
</div>
<div className="mx-2 mb-2 mt-4 flex items-center gap-2 font-semibold">
{selectedTab === 1 && (
<>
<IconComponent name={"FormInput"} />
Text Inputs Text Inputs
</> </div>
)} {nodes
{selectedTab === 2 && ( .filter((node) =>
<> inputs.some((input) => input.id === node.id)
<IconComponent name={"ChevronRightSquare"} /> )
Prompt Outputs .map((node, index) => {
</> const input = inputs.find(
)} (input) => input.id === node.id
</div> )!;
{nodes return (
.filter((node) => <div
selectedTab === 1 className="file-component-accordion-div"
? inputs.some((input) => input.id === node.id) key={index}
: outputs.some((output) => output.id === node.id) >
) <AccordionComponent
.map((node, index) => { trigger={
const input = <div className="file-component-badge-div">
selectedTab === 1 <Badge variant="gray" size="md">
? inputs.find((input) => input.id === node.id)! {input.id}
: outputs.find((output) => output.id === node.id)!; </Badge>
return ( {haveChat && (
<div className="file-component-accordion-div" key={index}> <div
<AccordionComponent className="-mb-1 pr-4"
trigger={ onClick={(event) => {
<div className="file-component-badge-div"> event.stopPropagation();
<Badge variant="gray" size="md"> setSelectedViewField(input);
{input.id} }}
</Badge> >
{haveChat && ( <IconComponent
<div className="h-4 w-4"
className="-mb-1 pr-4" name="ExternalLink"
onClick={(event) => { ></IconComponent>
event.stopPropagation(); </div>
setSelectedViewField(input); )}
}}
>
<IconComponent
className="h-4 w-4"
name="ExternalLink"
></IconComponent>
</div> </div>
)} }
</div> key={index}
} keyValue={input.id}
key={index} >
keyValue={input.id} <div className="file-component-tab-column">
> <div className="">
<div className="file-component-tab-column"> {input && (
<div className=""> <IOInputField
{input && inputType={input.type}
(selectedTab === 1 ? ( inputId={input.id}
<IOInputField />
inputType={input.type} )}
inputId={input.id} </div>
/> </div>
) : ( </AccordionComponent>
<IOOutputView
outputType={input.type}
outputId={input.id}
/>
))}
</div>
</div> </div>
</AccordionComponent> );
</div> })}
); </TabsContent>
})} <TabsContent
value={"2"}
className="api-modal-tabs-content mt-4"
>
<div className="mx-2 mb-2 flex items-center gap-2 text-sm font-bold">
<IconComponent className="h-4 w-4" name={"Braces"} />
Prompt Outputs
</div>
{nodes
.filter((node) =>
outputs.some((output) => output.id === node.id)
)
.map((node, index) => {
const output = outputs.find(
(output) => output.id === node.id
)!;
return (
<div
className="file-component-accordion-div"
key={index}
>
<AccordionComponent
trigger={
<div className="file-component-badge-div">
<Badge variant="gray" size="md">
{output.id}
</Badge>
{haveChat && (
<div
className="-mb-1 pr-4"
onClick={(event) => {
event.stopPropagation();
setSelectedViewField(output);
}}
>
<IconComponent
className="h-4 w-4"
name="ExternalLink"
></IconComponent>
</div>
)}
</div>
}
key={index}
keyValue={output.id}
>
<div className="file-component-tab-column">
<div className="">
{output && (
<IOOutputView
outputType={output.type}
outputId={output.id}
/>
)}
</div>
</div>
</AccordionComponent>
</div>
);
})}
</TabsContent>
</Tabs>
</div> </div>
)} )}

View file

@ -681,4 +681,4 @@ export const LANGFLOW_SUPPORTED_TYPES = new Set([
export const priorityFields = new Set(["code", "template"]); export const priorityFields = new Set(["code", "template"]);
export const INPUT_TYPES = new Set(["ChatInput", "TextInput"]); export const INPUT_TYPES = new Set(["ChatInput", "TextInput"]);
export const OUTPUT_TYPES = new Set(["ChatOutput"]); export const OUTPUT_TYPES = new Set(["ChatOutput", "PromptTemplate"]);

View file

@ -255,7 +255,7 @@ export default function GenericModal({
> >
<div className="flex flex-wrap items-center"> <div className="flex flex-wrap items-center">
<IconComponent <IconComponent
name="Variable" name="Braces"
className=" -ml-px mr-1 flex h-4 w-4 text-primary" className=" -ml-px mr-1 flex h-4 w-4 text-primary"
/> />
<span className="text-md font-semibold text-primary"> <span className="text-md font-semibold text-primary">

View file

@ -25,7 +25,7 @@ import {
expandGroupNode, expandGroupNode,
updateFlowPosition, updateFlowPosition,
} from "../../../../utils/reactflowUtils"; } from "../../../../utils/reactflowUtils";
import { classNames } from "../../../../utils/utils"; import { classNames, cn } from "../../../../utils/utils";
export default function NodeToolbarComponent({ export default function NodeToolbarComponent({
data, data,
@ -60,6 +60,7 @@ export default function NodeToolbarComponent({
const isMinimal = numberOfHandles <= 1; const isMinimal = numberOfHandles <= 1;
const isGroup = data.node?.flow ? true : false; const isGroup = data.node?.flow ? true : false;
const pinned = data.node?.pinned ?? false;
const paste = useFlowStore((state) => state.paste); const paste = useFlowStore((state) => state.paste);
const nodes = useFlowStore((state) => state.nodes); const nodes = useFlowStore((state) => state.nodes);
const edges = useFlowStore((state) => state.edges); const edges = useFlowStore((state) => state.edges);
@ -107,6 +108,9 @@ export default function NodeToolbarComponent({
takeSnapshot(); takeSnapshot();
setShowNode(data.showNode ?? true ? false : true); setShowNode(data.showNode ?? true ? false : true);
break; break;
case "Share":
if (hasApiKey || hasStore) setShowconfirmShare(true);
break;
case "Download": case "Download":
downloadNode(flowComponent!); downloadNode(flowComponent!);
break; break;
@ -269,22 +273,35 @@ export default function NodeToolbarComponent({
<IconComponent name="Copy" className="h-4 w-4" /> <IconComponent name="Copy" className="h-4 w-4" />
</button> </button>
</ShadTooltip> </ShadTooltip>
{hasStore && (
<ShadTooltip content="Share" side="top"> <ShadTooltip content="Pin" side="top">
<button <button
className={classNames( className={classNames(
"relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10", "relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10"
!hasApiKey || !validApiKey ? " text-muted-foreground" : "" )}
onClick={(event) => {
event.preventDefault();
setNode(data.id, (old) => ({
...old,
data: {
...old.data,
node: {
...old.data.node,
pinned: old.data?.node?.pinned ? false : true,
},
},
}));
}}
>
<IconComponent
name="Pin"
className={cn(
"h-4 w-4 transition-all",
pinned ? "animate-wiggle fill-current" : ""
)} )}
onClick={(event) => { />
event.preventDefault(); </button>
if (hasApiKey || hasStore) setShowconfirmShare(true); </ShadTooltip>
}}
>
<IconComponent name="Share3" className="-m-1 h-6 w-6" />
</button>
</ShadTooltip>
)}
<Select onValueChange={handleSelectChange} value=""> <Select onValueChange={handleSelectChange} value="">
<ShadTooltip content="More" side="top"> <ShadTooltip content="More" side="top">
@ -340,6 +357,20 @@ export default function NodeToolbarComponent({
</SelectItem> </SelectItem>
) )
)} )}
{hasStore && (
<SelectItem
value={"Share"}
disabled={!hasApiKey || !validApiKey}
>
<div className="flex" data-testid="save-button-modal">
<IconComponent
name="Share3"
className="relative top-0.5 -m-1 mr-1 h-6 w-6"
/>{" "}
Share{" "}
</div>{" "}
</SelectItem>
)}
{!hasStore && ( {!hasStore && (
<SelectItem value={"Download"}> <SelectItem value={"Download"}>
<div className="flex"> <div className="flex">

View file

@ -845,7 +845,7 @@
@apply flex h-full max-w-full flex-col overflow-hidden rounded-md border bg-muted text-center sm:w-[75vw] md:w-[75vw] lg:w-[75vw] xl:w-[76vw] 2xl:w-full; @apply flex h-full max-w-full flex-col overflow-hidden rounded-md border bg-muted text-center sm:w-[75vw] md:w-[75vw] lg:w-[75vw] xl:w-[76vw] 2xl:w-full;
} }
.api-modal-tablist-div { .api-modal-tablist-div {
@apply flex items-center justify-between px-2; @apply flex items-center justify-between px-2 py-2;
} }
.api-modal-tabs-content { .api-modal-tabs-content {
@apply -mt-1 h-full w-full overflow-hidden px-4 pb-4; @apply -mt-1 h-full w-full overflow-hidden px-4 pb-4;

View file

@ -6,6 +6,7 @@ import {
BookmarkPlus, BookmarkPlus,
Bot, Bot,
Boxes, Boxes,
Braces,
Cable, Cable,
Check, Check,
CheckCircle2, CheckCircle2,
@ -18,6 +19,7 @@ import {
ChevronsRight, ChevronsRight,
ChevronsUpDown, ChevronsUpDown,
Circle, Circle,
CircleDot,
Clipboard, Clipboard,
Code, Code,
Code2, Code2,
@ -102,6 +104,7 @@ import {
TextCursorInput, TextCursorInput,
ToyBrick, ToyBrick,
Trash2, Trash2,
Type,
Undo, Undo,
Ungroup, Ungroup,
Unplug, Unplug,
@ -345,6 +348,7 @@ export const nodeIconsLucide: iconsType = {
FileSearch2, FileSearch2,
ChevronRight, ChevronRight,
Circle, Circle,
CircleDot,
Clipboard, Clipboard,
Code2, Code2,
Variable, Variable,
@ -414,6 +418,8 @@ export const nodeIconsLucide: iconsType = {
Sliders, Sliders,
ScreenShare, ScreenShare,
Code, Code,
Type,
Braces,
FlaskConical, FlaskConical,
AlertCircle, AlertCircle,
Bot, Bot,