Merge branch 'db' into merge/mp
This commit is contained in:
commit
3d69d76c6f
63 changed files with 833 additions and 646 deletions
10
src/frontend/package-lock.json
generated
10
src/frontend/package-lock.json
generated
|
|
@ -53,6 +53,7 @@
|
|||
"remark-gfm": "^3.0.1",
|
||||
"remark-math": "^5.1.1",
|
||||
"shadcn-ui": "^0.1.3",
|
||||
"short-unique-id": "^4.4.4",
|
||||
"switch": "^0.0.0",
|
||||
"table": "^6.8.1",
|
||||
"tailwind-merge": "^1.13.0",
|
||||
|
|
@ -8642,6 +8643,15 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/short-unique-id": {
|
||||
"version": "4.4.4",
|
||||
"resolved": "https://registry.npmjs.org/short-unique-id/-/short-unique-id-4.4.4.tgz",
|
||||
"integrity": "sha512-oLF1NCmtbiTWl2SqdXZQbo5KM1b7axdp0RgQLq8qCBBLoq+o3A5wmLrNM6bZIh54/a8BJ3l69kTXuxwZ+XCYuw==",
|
||||
"bin": {
|
||||
"short-unique-id": "bin/short-unique-id",
|
||||
"suid": "bin/short-unique-id"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.0.4",
|
||||
"dev": true,
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
"remark-gfm": "^3.0.1",
|
||||
"remark-math": "^5.1.1",
|
||||
"shadcn-ui": "^0.1.3",
|
||||
"short-unique-id": "^4.4.4",
|
||||
"switch": "^0.0.0",
|
||||
"table": "^6.8.1",
|
||||
"tailwind-merge": "^1.13.0",
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import React from "react";
|
|||
import { nodeColors } from "../../../../utils";
|
||||
import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
||||
import { PopUpContext } from "../../../../contexts/popUpContext";
|
||||
import ToggleShadComponent from "../../../../components/toggleShadComponent";
|
||||
|
||||
export default function ParameterComponent({
|
||||
left,
|
||||
|
|
@ -39,7 +40,6 @@ export default function ParameterComponent({
|
|||
}: ParameterComponentType) {
|
||||
const ref = useRef(null);
|
||||
const refHtml = useRef(null);
|
||||
const refData = useRef(null);
|
||||
const updateNodeInternals = useUpdateNodeInternals();
|
||||
const [position, setPosition] = useState(0);
|
||||
const { closePopUp } = useContext(PopUpContext);
|
||||
|
|
@ -64,11 +64,11 @@ export default function ParameterComponent({
|
|||
const { reactFlowInstance } = useContext(typesContext);
|
||||
let disabled =
|
||||
reactFlowInstance?.getEdges().some((e) => e.targetHandle === id) ?? false;
|
||||
|
||||
const [myData, setMyData] = useState(useContext(typesContext).data);
|
||||
|
||||
useEffect(() => {
|
||||
const groupedObj = groupByFamily(myData, tooltipTitle);
|
||||
|
||||
refHtml.current = groupedObj.map((item, i) => (
|
||||
<span
|
||||
key={i}
|
||||
|
|
@ -108,169 +108,166 @@ export default function ParameterComponent({
|
|||
}, [tooltipTitle]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
ref={ref}
|
||||
className="w-full flex flex-wrap justify-between items-center bg-muted dark:bg-gray-800 dark:text-white mt-1 px-5 py-2"
|
||||
>
|
||||
<>
|
||||
<div
|
||||
className={"text-sm truncate w-full " + (left ? "" : "text-end")}
|
||||
<div
|
||||
ref={ref}
|
||||
className="w-full flex flex-wrap justify-between items-center bg-muted dark:bg-gray-800 dark:text-white mt-1 px-5 py-2"
|
||||
>
|
||||
<>
|
||||
<div className={"text-sm truncate w-full " + (left ? "" : "text-end")}>
|
||||
{title}
|
||||
<span className="text-red-600">{required ? " *" : ""}</span>
|
||||
</div>
|
||||
{left &&
|
||||
(type === "str" ||
|
||||
type === "bool" ||
|
||||
type === "float" ||
|
||||
type === "code" ||
|
||||
type === "prompt" ||
|
||||
type === "file" ||
|
||||
type === "int") ? (
|
||||
<></>
|
||||
) : (
|
||||
<ShadTooltip
|
||||
delayDuration={0}
|
||||
content={refHtml.current}
|
||||
side={left ? "left" : "right"}
|
||||
open={refHtml?.current?.length > 0}
|
||||
>
|
||||
{title}
|
||||
<span className="text-red-600">{required ? " *" : ""}</span>
|
||||
</div>
|
||||
{left &&
|
||||
(type === "str" ||
|
||||
type === "bool" ||
|
||||
type === "float" ||
|
||||
type === "code" ||
|
||||
type === "prompt" ||
|
||||
type === "file" ||
|
||||
type === "int") ? (
|
||||
<></>
|
||||
) : (
|
||||
<ShadTooltip
|
||||
delayDuration={0}
|
||||
content={refHtml.current}
|
||||
side={left ? "left" : "right"}
|
||||
open={refHtml?.current?.length > 0}
|
||||
>
|
||||
<Handle
|
||||
type={left ? "target" : "source"}
|
||||
position={left ? Position.Left : Position.Right}
|
||||
id={id}
|
||||
isValidConnection={(connection) =>
|
||||
isValidConnection(connection, reactFlowInstance)
|
||||
}
|
||||
className={classNames(
|
||||
left ? "-ml-0.5 " : "-mr-0.5 ",
|
||||
"w-3 h-3 rounded-full border-2 bg-white dark:bg-gray-800"
|
||||
)}
|
||||
style={{
|
||||
borderColor: color,
|
||||
top: position,
|
||||
}}
|
||||
></Handle>
|
||||
</ShadTooltip>
|
||||
)}
|
||||
|
||||
{left === true &&
|
||||
type === "str" &&
|
||||
!data.node.template[name].options ? (
|
||||
<div className="mt-2 w-full">
|
||||
{data.node.template[name].list ? (
|
||||
<InputListComponent
|
||||
disabled={disabled}
|
||||
value={
|
||||
!data.node.template[name].value ||
|
||||
data.node.template[name].value === ""
|
||||
? [""]
|
||||
: data.node.template[name].value
|
||||
}
|
||||
onChange={(t: string[]) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
/>
|
||||
) : data.node.template[name].multiline ? (
|
||||
<TextAreaComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<InputComponent
|
||||
disabled={disabled}
|
||||
disableCopyPaste={true}
|
||||
password={data.node.template[name].password ?? false}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
/>
|
||||
<Handle
|
||||
type={left ? "target" : "source"}
|
||||
position={left ? Position.Left : Position.Right}
|
||||
id={id}
|
||||
isValidConnection={(connection) =>
|
||||
isValidConnection(connection, reactFlowInstance)
|
||||
}
|
||||
className={classNames(
|
||||
left ? "-ml-0.5 " : "-mr-0.5 ",
|
||||
"w-3 h-3 rounded-full border-2 bg-white dark:bg-gray-800"
|
||||
)}
|
||||
</div>
|
||||
) : left === true && type === "bool" ? (
|
||||
<div className="mt-2">
|
||||
<ToggleComponent
|
||||
style={{
|
||||
borderColor: color,
|
||||
top: position,
|
||||
}}
|
||||
></Handle>
|
||||
</ShadTooltip>
|
||||
)}
|
||||
|
||||
{left === true &&
|
||||
type === "str" &&
|
||||
!data.node.template[name].options ? (
|
||||
<div className="mt-2 w-full">
|
||||
{data.node.template[name].list ? (
|
||||
<InputListComponent
|
||||
disabled={disabled}
|
||||
enabled={enabled}
|
||||
setEnabled={(t) => {
|
||||
data.node.template[name].value = t;
|
||||
setEnabled(t);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : left === true && type === "float" ? (
|
||||
<div className="mt-2 w-full">
|
||||
<FloatComponent
|
||||
disabled={disabled}
|
||||
disableCopyPaste={true}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : left === true &&
|
||||
type === "str" &&
|
||||
data.node.template[name].options ? (
|
||||
<div className="w-full">
|
||||
<Dropdown
|
||||
options={data.node.template[name].options}
|
||||
onSelect={(newValue) =>
|
||||
(data.node.template[name].value = newValue)
|
||||
value={
|
||||
!data.node.template[name].value ||
|
||||
data.node.template[name].value === ""
|
||||
? [""]
|
||||
: data.node.template[name].value
|
||||
}
|
||||
value={data.node.template[name].value ?? "Choose an option"}
|
||||
></Dropdown>
|
||||
</div>
|
||||
) : left === true && type === "code" ? (
|
||||
<CodeAreaComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
/>
|
||||
) : left === true && type === "file" ? (
|
||||
<InputFileComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
fileTypes={data.node.template[name].fileTypes}
|
||||
suffixes={data.node.template[name].suffixes}
|
||||
onFileChange={(t: string) => {
|
||||
data.node.template[name].content = t;
|
||||
}}
|
||||
></InputFileComponent>
|
||||
) : left === true && type === "int" ? (
|
||||
<div className="mt-2 w-full">
|
||||
<IntComponent
|
||||
onChange={(t: string[]) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
/>
|
||||
) : data.node.template[name].multiline ? (
|
||||
<TextAreaComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<InputComponent
|
||||
disabled={disabled}
|
||||
disableCopyPaste={true}
|
||||
password={data.node.template[name].password ?? false}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : left === true && type === "prompt" ? (
|
||||
<PromptAreaComponent
|
||||
)}
|
||||
</div>
|
||||
) : left === true && type === "bool" ? (
|
||||
<div className="mt-2">
|
||||
<ToggleShadComponent
|
||||
disabled={disabled}
|
||||
enabled={enabled}
|
||||
setEnabled={(t) => {
|
||||
data.node.template[name].value = t;
|
||||
setEnabled(t);
|
||||
}}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
) : left === true && type === "float" ? (
|
||||
<div className="mt-2 w-full">
|
||||
<FloatComponent
|
||||
disabled={disabled}
|
||||
disableCopyPaste={true}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
onChange={(t) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
) : left === true &&
|
||||
type === "str" &&
|
||||
data.node.template[name].options ? (
|
||||
<div className="w-full">
|
||||
<Dropdown
|
||||
options={data.node.template[name].options}
|
||||
onSelect={(newValue) =>
|
||||
(data.node.template[name].value = newValue)
|
||||
}
|
||||
value={data.node.template[name].value ?? "Choose an option"}
|
||||
></Dropdown>
|
||||
</div>
|
||||
) : left === true && type === "code" ? (
|
||||
<CodeAreaComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
/>
|
||||
) : left === true && type === "file" ? (
|
||||
<InputFileComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
fileTypes={data.node.template[name].fileTypes}
|
||||
suffixes={data.node.template[name].suffixes}
|
||||
onFileChange={(t: string) => {
|
||||
data.node.template[name].content = t;
|
||||
}}
|
||||
></InputFileComponent>
|
||||
) : left === true && type === "int" ? (
|
||||
<div className="mt-2 w-full">
|
||||
<IntComponent
|
||||
disabled={disabled}
|
||||
disableCopyPaste={true}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : left === true && type === "prompt" ? (
|
||||
<PromptAreaComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,3 @@
|
|||
import {
|
||||
BugAntIcon,
|
||||
Cog6ToothIcon,
|
||||
InformationCircleIcon,
|
||||
TrashIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
|
||||
import {
|
||||
CheckCircleIcon,
|
||||
EllipsisHorizontalCircleIcon,
|
||||
ExclamationCircleIcon,
|
||||
} from "@heroicons/react/24/solid";
|
||||
|
||||
import {
|
||||
classNames,
|
||||
nodeColors,
|
||||
|
|
@ -33,6 +20,7 @@ import { NodeToolbar } from "reactflow";
|
|||
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
|
||||
|
||||
import ShadTooltip from "../../components/ShadTooltipComponent";
|
||||
import { postValidateNode } from "../../controllers/API";
|
||||
export default function GenericNode({
|
||||
data,
|
||||
selected,
|
||||
|
|
@ -62,17 +50,13 @@ export default function GenericNode({
|
|||
const validateNode = useCallback(
|
||||
debounce(async () => {
|
||||
try {
|
||||
const response = await fetch(`/validate/node/${data.id}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(reactFlowInstance.toObject()),
|
||||
});
|
||||
const response = await postValidateNode(
|
||||
data.id,
|
||||
reactFlowInstance.toObject()
|
||||
);
|
||||
|
||||
if (response.status === 200) {
|
||||
let jsonResponse = await response.json();
|
||||
let jsonResponseParsed = await JSON.parse(jsonResponse);
|
||||
let jsonResponseParsed = await JSON.parse(response.data);
|
||||
setValidationStatus(jsonResponseParsed);
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
@ -150,11 +134,10 @@ export default function GenericNode({
|
|||
"Validating..."
|
||||
) : (
|
||||
<div className="max-h-96 overflow-auto">
|
||||
{validationStatus.params
|
||||
.split("\n")
|
||||
.map((line, index) => (
|
||||
<div key={index}>{line}</div>
|
||||
))}
|
||||
{validationStatus.params ||
|
||||
""
|
||||
.split("\n")
|
||||
.map((line, index) => <div key={index}>{line}</div>)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -191,7 +174,7 @@ export default function GenericNode({
|
|||
</div>
|
||||
|
||||
<div className="h-full w-full py-5 text-gray-800">
|
||||
<div className="w-full px-5 pb-3 text-sm text-gray-500 dark:text-gray-300">
|
||||
<div className="w-full px-5 pb-3 text-sm text-muted-foreground">
|
||||
{data.node.description}
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useState, ChangeEvent } from "react";
|
||||
import { Textarea } from "../ui/textarea";
|
||||
import { Label } from "../ui/label";
|
||||
import { Input } from "../ui/input";
|
||||
import { Textarea } from "../../components/ui/textarea";
|
||||
import { Label } from "../../components/ui/label";
|
||||
import { Input } from "../../components/ui/input";
|
||||
|
||||
type InputProps = {
|
||||
name: string | null;
|
||||
|
|
@ -62,7 +62,7 @@ export const EditFlowSettings: React.FC<InputProps> = ({
|
|||
)}
|
||||
</div>
|
||||
<Input
|
||||
className="mt-2"
|
||||
className="mt-2 font-normal"
|
||||
onChange={handleNameChange}
|
||||
type="text"
|
||||
name="name"
|
||||
|
|
@ -80,7 +80,7 @@ export const EditFlowSettings: React.FC<InputProps> = ({
|
|||
onChange={handleDescriptionChange}
|
||||
value={description ?? ""}
|
||||
placeholder="Flow description"
|
||||
className="max-h-[100px] mt-2"
|
||||
className="max-h-[100px] mt-2 font-normal"
|
||||
rows={3}
|
||||
/>
|
||||
</Label>
|
||||
|
|
@ -40,7 +40,7 @@ export const CardComponent = ({
|
|||
</div>
|
||||
{onDelete && (
|
||||
<button onClick={onDelete}>
|
||||
<Trash2 className="w-5 text-primary opacity-0 group-hover:opacity-100 transition-all" />
|
||||
<Trash2 className="w-4 h-4 text-primary opacity-0 group-hover:opacity-100 transition-all" />
|
||||
</button>
|
||||
)}
|
||||
</CardTitle>
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export default function Dropdown({
|
|||
className={({ active }) =>
|
||||
classNames(
|
||||
active
|
||||
? "text-white bg-slate-400 dark:bg-white dark:text-gray-500"
|
||||
? " bg-accent dark:bg-white dark:text-gray-500"
|
||||
: "",
|
||||
editNode
|
||||
? "relative cursor-default select-none py-0.5 pl-3 pr-12 dark:text-gray-300 dark:bg-gray-800"
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ export const MenuBar = ({ flows, tabId }) => {
|
|||
return (
|
||||
<div className="flex gap-2 items-center">
|
||||
<Link to="/">
|
||||
<ChevronLeft className="w-5" />
|
||||
<ChevronLeft className="w-4" />
|
||||
</Link>
|
||||
<div className="flex items-center font-medium text-sm rounded-md py-1 px-1.5 gap-0.5">
|
||||
<DropdownMenu>
|
||||
|
|
@ -62,7 +62,7 @@ export const MenuBar = ({ flows, tabId }) => {
|
|||
openPopUp(<FlowSettingsModal />);
|
||||
}}
|
||||
>
|
||||
<Settings2 className="w-4 h-4 mr-2" />
|
||||
<Settings2 className="w-4 h-4 mr-2 dark:text-gray-300" />
|
||||
Settings
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
|
|
@ -70,7 +70,7 @@ export const MenuBar = ({ flows, tabId }) => {
|
|||
undo();
|
||||
}}
|
||||
>
|
||||
<Undo className="w-4 h-4 mr-2" />
|
||||
<Undo className="w-4 h-4 mr-2 dark:text-gray-300" />
|
||||
Undo
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
|
|
@ -78,7 +78,7 @@ export const MenuBar = ({ flows, tabId }) => {
|
|||
redo();
|
||||
}}
|
||||
>
|
||||
<Redo className="w-4 h-4 mr-2" />
|
||||
<Redo className="w-4 h-4 mr-2 dark:text-gray-300" />
|
||||
Redo
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ export default function Header() {
|
|||
Join The Community
|
||||
</a>
|
||||
</Button>
|
||||
<button
|
||||
{/* <button
|
||||
className="text-gray-600 hover:text-gray-500 dark:text-gray-300 dark:hover:text-gray-200"
|
||||
onClick={() => {
|
||||
setDark(!dark);
|
||||
|
|
@ -83,7 +83,7 @@ export default function Header() {
|
|||
) : (
|
||||
<MoonIcon className="h-5 w-5" />
|
||||
)}
|
||||
</button>
|
||||
</button> */}
|
||||
<button
|
||||
className="text-gray-600 hover:text-gray-500 dark:text-gray-300 dark:hover:text-gray-200 relative"
|
||||
onClick={(event: React.MouseEvent<HTMLElement>) => {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export default function IntComponent({
|
|||
if (disableCopyPaste) setDisableCopyPaste(false);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
console.log(event);
|
||||
// console.log(event);
|
||||
if (
|
||||
event.key !== "Backspace" &&
|
||||
event.key !== "Enter" &&
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { classNames } from "../../utils";
|
||||
import { useEffect } from "react";
|
||||
import { ToggleComponentType } from "../../types/components";
|
||||
import { Switch } from "../ui/switch";
|
||||
|
|
@ -7,17 +6,36 @@ export default function ToggleShadComponent({
|
|||
enabled,
|
||||
setEnabled,
|
||||
disabled,
|
||||
size,
|
||||
}: ToggleComponentType) {
|
||||
useEffect(() => {
|
||||
if (disabled) {
|
||||
setEnabled(false);
|
||||
}
|
||||
}, [disabled, setEnabled]);
|
||||
let scaleX, scaleY;
|
||||
switch (size) {
|
||||
case "small":
|
||||
scaleX = 0.6;
|
||||
scaleY = 0.6;
|
||||
break;
|
||||
case "medium":
|
||||
scaleX = 0.8;
|
||||
scaleY = 0.8;
|
||||
break;
|
||||
case "large":
|
||||
scaleX = 1;
|
||||
scaleY = 1;
|
||||
break;
|
||||
default:
|
||||
scaleX = 1;
|
||||
scaleY = 1;
|
||||
}
|
||||
return (
|
||||
<div className={disabled ? "pointer-events-none cursor-not-allowed" : ""}>
|
||||
<Switch
|
||||
style={{
|
||||
transform: "scaleX(0.6) scaleY(0.6)",
|
||||
transform: `scaleX(${scaleX}) scaleY(${scaleY})`,
|
||||
}}
|
||||
className="data-[state=unchecked]:bg-slate-500"
|
||||
checked={enabled}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
// src/constants.tsx
|
||||
|
||||
import { FlowType } from "./types/flow";
|
||||
import { buildTweaks } from "./utils";
|
||||
|
||||
/**
|
||||
* The base text for subtitle of Export Dialog (Toolbar)
|
||||
* @constant
|
||||
|
|
@ -51,10 +54,21 @@ export const TEXT_DIALOG_SUBTITLE = "Edit your text.";
|
|||
* @param {string} flowId - The id of the flow
|
||||
* @returns {string} - The python code
|
||||
*/
|
||||
export const getPythonApiCode = (flowId: string): string => {
|
||||
export const getPythonApiCode = (flow: FlowType): string => {
|
||||
const flowId = flow.id;
|
||||
|
||||
// create a dictionary of node ids and the values is an empty dictionary
|
||||
// flow.data.nodes.forEach((node) => {
|
||||
// node.data.id
|
||||
// }
|
||||
const tweaks = buildTweaks(flow);
|
||||
return `import requests
|
||||
|
||||
BASE_API_URL = "${window.location.protocol}//${window.location.host}/predict"
|
||||
BASE_API_URL = "${window.location.protocol}//${
|
||||
window.location.host
|
||||
}/ap1/v1/predict"
|
||||
FLOW_ID = "${flowId}"
|
||||
TWEAKS = ${JSON.stringify(tweaks, null, 2)}
|
||||
|
||||
def run_flow(message: str, flow_id: str, tweaks: dict = None) -> dict:
|
||||
"""
|
||||
|
|
@ -76,32 +90,35 @@ def run_flow(message: str, flow_id: str, tweaks: dict = None) -> dict:
|
|||
return response.json()
|
||||
|
||||
# Setup any tweaks you want to apply to the flow
|
||||
tweaks = {} # {"nodeId": {"key": "value"}, "nodeId2": {"key": "value"}}
|
||||
|
||||
FLOW_ID = "${flowId}"
|
||||
|
||||
print(run_flow("Your message", flow_id=FLOW_ID, tweaks=tweaks))`;
|
||||
print(run_flow("Your message", flow_id=FLOW_ID, tweaks=TWEAKS))`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function to get the curl code for the API
|
||||
* @param {string} flowId - The id of the flow
|
||||
* @returns {string} - The curl code
|
||||
*/
|
||||
export const getCurlCode = (flowId: string): string => {
|
||||
export const getCurlCode = (flow: FlowType): string => {
|
||||
const flowId = flow.id;
|
||||
const tweaks = buildTweaks(flow);
|
||||
return `curl -X POST \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-H "Authorization: Bearer ${flowId}" \\
|
||||
-d '{"message": "Your message"}' \\
|
||||
${window.location.protocol}//${window.location.host}/predict`;
|
||||
${window.location.protocol}//${
|
||||
window.location.host
|
||||
}/api/v1/predict/${flowId} \\
|
||||
-H 'Content-Type: application/json' \\
|
||||
-d '{"message": "Your message", "tweaks": ${JSON.stringify(
|
||||
tweaks,
|
||||
null,
|
||||
2
|
||||
)}}'`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function to get the python code for the API
|
||||
* @param {string} flowName - The name of the flow
|
||||
* @returns {string} - The python code
|
||||
*/
|
||||
export const getPythonCode = (flowName: string): string => {
|
||||
export const getPythonCode = (flow: FlowType): string => {
|
||||
const flowName = flow.name;
|
||||
return `from langflow import load_flow_from_json
|
||||
|
||||
flow = load_flow_from_json("${flowName}.json")
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { updateIds, updateTemplate } from "../utils";
|
|||
import { alertContext } from "./alertContext";
|
||||
import { typesContext } from "./typesContext";
|
||||
import { APITemplateType } from "../types/api";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import { addEdge } from "reactflow";
|
||||
import {
|
||||
readFlowsFromDatabase,
|
||||
|
|
@ -23,14 +23,17 @@ import {
|
|||
} from "../controllers/API";
|
||||
import _ from "lodash";
|
||||
|
||||
const uid = new ShortUniqueId({ length: 5 });
|
||||
|
||||
const TabsContextInitialValue: TabsContextType = {
|
||||
save: () => {},
|
||||
tabId: "",
|
||||
setTabId: (index: string) => {},
|
||||
flows: [],
|
||||
removeFlow: (id: string) => {},
|
||||
addFlow: async (flowData?: any) => "",
|
||||
updateFlow: (newFlow: FlowType) => {},
|
||||
incrementNodeId: () => uuidv4(),
|
||||
incrementNodeId: () => uid(),
|
||||
downloadFlow: (flow: FlowType) => {},
|
||||
downloadFlows: () => {},
|
||||
uploadFlows: () => {},
|
||||
|
|
@ -41,7 +44,7 @@ const TabsContextInitialValue: TabsContextType = {
|
|||
lastCopiedSelection: null,
|
||||
setLastCopiedSelection: (selection: any) => {},
|
||||
|
||||
getNodeId: () => "",
|
||||
getNodeId: (nodeType: string) => "",
|
||||
paste: (
|
||||
selection: { nodes: any; edges: any },
|
||||
position: { x: number; y: number; paneX?: number; paneY?: number }
|
||||
|
|
@ -54,18 +57,46 @@ export const TabsContext = createContext<TabsContextType>(
|
|||
|
||||
export function TabsProvider({ children }: { children: ReactNode }) {
|
||||
const { setErrorData, setNoticeData } = useContext(alertContext);
|
||||
|
||||
const [tabId, setTabId] = useState("");
|
||||
const [flows, setFlows] = useState([]);
|
||||
const [id, setId] = useState(uuidv4());
|
||||
|
||||
const [flows, setFlows] = useState<Array<FlowType>>([]);
|
||||
const [id, setId] = useState(uid());
|
||||
const { templates, reactFlowInstance } = useContext(typesContext);
|
||||
const [lastCopiedSelection, setLastCopiedSelection] = useState(null);
|
||||
|
||||
const newNodeId = useRef(uuidv4());
|
||||
const newNodeId = useRef(uid());
|
||||
function incrementNodeId() {
|
||||
newNodeId.current = uuidv4();
|
||||
newNodeId.current = uid();
|
||||
return newNodeId.current;
|
||||
}
|
||||
|
||||
function save() {
|
||||
// added clone deep to avoid mutating the original object
|
||||
let Saveflows = _.cloneDeep(flows);
|
||||
if (Saveflows.length !== 0) {
|
||||
Saveflows.forEach((flow) => {
|
||||
if (flow.data && flow.data?.nodes)
|
||||
flow.data?.nodes.forEach((node) => {
|
||||
// console.log(node.data.type);
|
||||
//looking for file fields to prevent saving the content and breaking the flow for exceeding the the data limite for local storage
|
||||
Object.keys(node.data.node.template).forEach((key) => {
|
||||
// console.log(node.data.node.template[key].type);
|
||||
if (node.data.node.template[key].type === "file") {
|
||||
// console.log(node.data.node.template[key]);
|
||||
node.data.node.template[key].content = null;
|
||||
node.data.node.template[key].value = "";
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
window.localStorage.setItem(
|
||||
"tabsData",
|
||||
JSON.stringify({ tabId, flows: Saveflows, id })
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// function loadCookie(cookie: string) {
|
||||
// if (cookie && Object.keys(templates).length > 0) {
|
||||
// let cookieObject: LangFlowState = JSON.parse(cookie);
|
||||
|
|
@ -206,10 +237,11 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
}
|
||||
|
||||
function hardReset() {
|
||||
newNodeId.current = uuidv4();
|
||||
newNodeId.current = uid();
|
||||
setTabId("");
|
||||
|
||||
setFlows([]);
|
||||
setId(uuidv4());
|
||||
setId(uid());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -249,8 +281,8 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
});
|
||||
}
|
||||
|
||||
function getNodeId() {
|
||||
return `dndnode_` + incrementNodeId();
|
||||
function getNodeId(nodeType: string) {
|
||||
return nodeType + "-" + incrementNodeId();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -262,6 +294,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
// create a file input
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = ".json";
|
||||
// add a change event listener to the file input
|
||||
input.onchange = (e: Event) => {
|
||||
// check if the file type is application/json
|
||||
|
|
@ -343,9 +376,9 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
? { x: position.paneX + position.x, y: position.paneY + position.y }
|
||||
: reactFlowInstance.project({ x: position.x, y: position.y });
|
||||
|
||||
selectionInstance.nodes.forEach((n) => {
|
||||
selectionInstance.nodes.forEach((n: NodeType) => {
|
||||
// Generate a unique node ID
|
||||
let newId = getNodeId();
|
||||
let newId = getNodeId(n.data.type);
|
||||
idsMap[n.id] = newId;
|
||||
|
||||
// Create a new node object
|
||||
|
|
@ -500,7 +533,6 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
const createNewFlow = (flowData, flow) => ({
|
||||
description: flowData.description,
|
||||
name: flow?.name ?? "New Flow",
|
||||
id: uuidv4(),
|
||||
data: flowData.data,
|
||||
});
|
||||
|
||||
|
|
@ -540,6 +572,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
tabId,
|
||||
setTabId,
|
||||
flows,
|
||||
save,
|
||||
incrementNodeId,
|
||||
removeFlow,
|
||||
addFlow,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { PromptTypeAPI, errorsTypeAPI } from "./../../types/api/index";
|
|||
import { APIObjectType, sendAllProps } from "../../types/api/index";
|
||||
import axios, { AxiosResponse } from "axios";
|
||||
import { FlowStyleType, FlowType } from "../../types/flow";
|
||||
import { ReactFlowJsonObject } from "reactflow";
|
||||
|
||||
/**
|
||||
* Fetches all objects from the API endpoint.
|
||||
|
|
@ -22,18 +23,19 @@ export async function sendAll(data: sendAllProps) {
|
|||
return await axios.post(`/api/v1/predict`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates code by sending it to an API endpoint.
|
||||
*
|
||||
* @param {string} code - The code to validate.
|
||||
* @returns {Promise<AxiosResponse<errorsTypeAPI>>} A promise that resolves to an AxiosResponse containing the validation results.
|
||||
*/
|
||||
export async function checkCode(
|
||||
export async function postValidateCode(
|
||||
code: string
|
||||
): Promise<AxiosResponse<errorsTypeAPI>> {
|
||||
return await axios.post("/api/v1/validate/code", { code });
|
||||
}
|
||||
|
||||
export async function postValidateNode(
|
||||
nodeId: string,
|
||||
data: any
|
||||
): Promise<AxiosResponse<string>> {
|
||||
return await axios.post(`/api/v1/validate/node/${nodeId}`, { data });
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the prompt for the code block by sending it to an API endpoint.
|
||||
*
|
||||
|
|
@ -75,7 +77,13 @@ export async function getExamples(): Promise<FlowType[]> {
|
|||
* @returns {Promise<any>} The saved flow data.
|
||||
* @throws Will throw an error if saving fails.
|
||||
*/
|
||||
export async function saveFlowToDatabase(newFlow: FlowType): Promise<FlowType> {
|
||||
export async function saveFlowToDatabase(newFlow: {
|
||||
name: string;
|
||||
id: string;
|
||||
data: ReactFlowJsonObject;
|
||||
description: string;
|
||||
style?: FlowStyleType;
|
||||
}): Promise<FlowType> {
|
||||
try {
|
||||
const response = await axios.post("/api/v1/flows/", {
|
||||
name: newFlow.name,
|
||||
|
|
|
|||
|
|
@ -72,47 +72,85 @@
|
|||
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
/* hsl(0 0% 100%) */
|
||||
--foreground: 222.2 47.4% 11.2%;
|
||||
--muted: 210 30% 98.5%;
|
||||
/* hsl(222 47% 11%) */
|
||||
--muted: 210 40% 98%;
|
||||
/* hsl(210 40% 98%) */
|
||||
--muted-foreground: 215.4 16.3% 46.9%;
|
||||
/* hsl(215 16% 46%) */
|
||||
--popover: 0 0% 100%;
|
||||
/* hsl(0 0% 100%) */
|
||||
--popover-foreground: 222.2 47.4% 11.2%;
|
||||
/* hsl(222 47% 11%) */
|
||||
--card: 0 0% 100%;
|
||||
/* hsl(0 0% 100%) */
|
||||
--card-foreground: 222.2 47.4% 11.2%;
|
||||
--border: 214.3 31.8% 93.4%;
|
||||
/* hsl(222 47% 11%) */
|
||||
--border: 214.3 31.8% 91.4%;
|
||||
/* hsl(214 32% 91%) */
|
||||
--input: 214.3 31.8% 91.4%;
|
||||
--primary: 222.2 37.4% 18%;
|
||||
/* hsl(214 32% 91%) */
|
||||
--primary: 222.2 47.4% 18%;
|
||||
/* hsl(222 47% 18%) */
|
||||
--primary-foreground: 210 40% 98%;
|
||||
--secondary: 210 30% 96.1%;
|
||||
/* hsl(210 40% 98%) */
|
||||
--secondary: 210 40% 96.1%;
|
||||
/* hsl(210 40% 96%) */
|
||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||
--accent: 210 30% 96.1%;
|
||||
--accent-foreground: 222.2 37.4% 11.2%;
|
||||
/* hsl(222 47% 11%) */
|
||||
--accent: 210 40% 96.1%;
|
||||
/* hsl(210 40% 96%) */
|
||||
--accent-foreground: 222.2 47.4% 11.2%;
|
||||
/* hsl(222 47% 11%) */
|
||||
--destructive: 0 100% 50%;
|
||||
/* hsl(0 100% 50%) */
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
/* hsl(210 40% 98%) */
|
||||
--ring: 215 20.2% 65.1%;
|
||||
/* hsl(215 20% 65%) */
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
-background: 224 71% 4%;
|
||||
/* hsl(224 71% 4%) */
|
||||
-foreground: 213 31% 91%;
|
||||
/* hsl(213 31% 91%) */
|
||||
-muted: 223 47% 11%;
|
||||
/* hsl(223 47% 11%) */
|
||||
-muted-foreground: 215.4 16.3% 56.9%;
|
||||
/* hsl(215 16% 56%) */
|
||||
-popover: 224 71% 4%;
|
||||
/* hsl(224 71% 4%) */
|
||||
-popover-foreground: 215 20.2% 65.1%;
|
||||
/* hsl(215 20% 65%) */
|
||||
-card: 224 71% 4%;
|
||||
/* hsl(224 71% 4%) */
|
||||
-card-foreground: 213 31% 91%;
|
||||
/* hsl(213 31% 91%) */
|
||||
-border: 216 34% 17%;
|
||||
/* hsl(216 34% 17%) */
|
||||
-input: 216 34% 17%;
|
||||
/* hsl(216 34% 17%) */
|
||||
-primary: 210 40% 98%;
|
||||
/* hsl(210 40% 98%) */
|
||||
-primary-foreground: 222.2 47.4% 1.2%;
|
||||
/* hsl(222 47% 1%) */
|
||||
-secondary: 222.2 47.4% 11.2%;
|
||||
/* hsl(222 47% 11%) */
|
||||
-secondary-foreground: 210 40% 98%;
|
||||
/* hsl(210 40% 98%) */
|
||||
-accent: 216 34% 17%;
|
||||
/* hsl(216 34% 17%) */
|
||||
-accent-foreground: 210 40% 98%;
|
||||
/* hsl(210 40% 98%) */
|
||||
-destructive: 0 63% 31%;
|
||||
/* hsl(0 63% 31%) */
|
||||
-destructive-foreground: 210 40% 98%;
|
||||
/* hsl(210 40% 98%) */
|
||||
-ring: 216 34% 17%;
|
||||
/* hsl(216 34% 17%) */
|
||||
-radius: 0.5rem;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
import { IconCheck, IconClipboard, IconDownload } from "@tabler/icons-react";
|
||||
import {
|
||||
XMarkIcon,
|
||||
CommandLineIcon,
|
||||
CodeBracketSquareIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { Fragment, useContext, useRef, useState } from "react";
|
||||
import { IconCheck, IconClipboard } from "@tabler/icons-react";
|
||||
import { CodeBracketSquareIcon } from "@heroicons/react/24/outline";
|
||||
import { useContext, useState } from "react";
|
||||
import { PopUpContext } from "../../contexts/popUpContext";
|
||||
import "ace-builds/src-noconflict/mode-python";
|
||||
import "ace-builds/src-noconflict/theme-github";
|
||||
|
|
@ -18,13 +14,11 @@ import {
|
|||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "../../components/ui/dialog";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { FlowType } from "../../types/flow";
|
||||
import { FlowType } from "../../types/flow/index";
|
||||
import { getCurlCode, getPythonApiCode, getPythonCode } from "../../constants";
|
||||
import { EXPORT_CODE_DIALOG } from "../../constants";
|
||||
|
||||
|
|
@ -55,10 +49,10 @@ export default function ApiModal({ flow }: { flow: FlowType }) {
|
|||
}
|
||||
}
|
||||
|
||||
const pythonApiCode = getPythonApiCode(flow.id);
|
||||
const pythonApiCode = getPythonApiCode(flow);
|
||||
|
||||
const curl_code = getCurlCode(flow.id);
|
||||
const pythonCode = getPythonCode(flow.name);
|
||||
const curl_code = getCurlCode(flow);
|
||||
const pythonCode = getPythonCode(flow);
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
|
|
@ -96,8 +90,8 @@ export default function ApiModal({ flow }: { flow: FlowType }) {
|
|||
<DialogDescription>{EXPORT_CODE_DIALOG}</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="flex flex-col h-full w-full ">
|
||||
<div className="flex px-5 z-10">
|
||||
<div className="flex flex-col h-full w-full overflow-hidden">
|
||||
<div className="flex px-5 z-10 w-full">
|
||||
{tabs.map((tab, index) => (
|
||||
<button
|
||||
key={index}
|
||||
|
|
@ -117,7 +111,7 @@ export default function ApiModal({ flow }: { flow: FlowType }) {
|
|||
))}
|
||||
</div>
|
||||
<div className=" overflow-hidden px-4 sm:p-4 sm:pb-0 sm:pt-0 w-full h-full rounded-lg border-gray-200 border-[1px] bg-muted dark:bg-gray-800">
|
||||
<div className="items-center mb-2">
|
||||
<div className="items-center mb-2 w-full">
|
||||
<div className="float-right">
|
||||
<button
|
||||
className="flex gap-1.5 items-center rounded bg-none p-1 text-xs text-gray-500 dark:text-gray-300"
|
||||
|
|
@ -133,7 +127,7 @@ export default function ApiModal({ flow }: { flow: FlowType }) {
|
|||
</div>
|
||||
</div>
|
||||
<SyntaxHighlighter
|
||||
className="h-[350px] w-full"
|
||||
className="h-[350px] w-full overflow-auto"
|
||||
language={tabs[activeTab].mode}
|
||||
style={oneDark}
|
||||
customStyle={{ margin: 0 }}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,21 @@
|
|||
import {
|
||||
ChevronDoubleLeftIcon,
|
||||
ChevronDoubleRightIcon,
|
||||
PencilSquareIcon,
|
||||
XMarkIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { Fragment, useContext, useEffect, useRef, useState } from "react";
|
||||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
import { PopUpContext } from "../../contexts/popUpContext";
|
||||
import { NodeDataType } from "../../types/flow";
|
||||
import { classNames, limitScrollFieldsModal, nodeIcons } from "../../utils";
|
||||
import { classNames, limitScrollFieldsModal } from "../../utils";
|
||||
import { typesContext } from "../../contexts/typesContext";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCaption,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "../../components/ui/table";
|
||||
import { Switch } from "../../components/ui/switch";
|
||||
import ToggleShadComponent from "../../components/toggleShadComponent";
|
||||
import { VariableIcon } from "@heroicons/react/24/outline";
|
||||
import InputListComponent from "../../components/inputListComponent";
|
||||
import TextAreaComponent from "../../components/textAreaComponent";
|
||||
import InputComponent from "../../components/inputComponent";
|
||||
import ToggleComponent from "../../components/toggleComponent";
|
||||
import FloatComponent from "../../components/floatComponent";
|
||||
import Dropdown from "../../components/dropdownComponent";
|
||||
import IntComponent from "../../components/intComponent";
|
||||
|
|
@ -42,8 +33,8 @@ import {
|
|||
DialogTrigger,
|
||||
} from "../../components/ui/dialog";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { EDIT_DIALOG_SUBTITLE } from "../../constants";
|
||||
import { Edit } from "lucide-react";
|
||||
import { Badge } from "../../components/ui/badge";
|
||||
|
||||
export default function EditNodeModal({ data }: { data: NodeDataType }) {
|
||||
const [open, setOpen] = useState(true);
|
||||
|
|
@ -95,14 +86,11 @@ export default function EditNodeModal({ data }: { data: NodeDataType }) {
|
|||
<DialogContent className="lg:max-w-[700px] ">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center">
|
||||
<span className="pr-2">Edit Node</span>
|
||||
<Edit
|
||||
className="h-5 w-5 text-gray-800 pl-1 dark:text-white"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span className="pr-2">{data.type}</span>
|
||||
<Badge variant="secondary">ID: {data.id}</Badge>
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
{EDIT_DIALOG_SUBTITLE}
|
||||
{data.node?.description}
|
||||
<div className="flex pt-4">
|
||||
<VariableIcon className="w-5 h-5 pe-1 text-gray-700 stroke-2 dark:text-slate-200">
|
||||
|
||||
|
|
@ -151,7 +139,7 @@ export default function EditNodeModal({ data }: { data: NodeDataType }) {
|
|||
)
|
||||
.map((n, i) => (
|
||||
<TableRow key={i} className="h-10 dark:border-b-muted">
|
||||
<TableCell className="p-0 text-center text-gray-900 text-xs dark:text-gray-300 text-sm">
|
||||
<TableCell className="p-0 text-center text-gray-900 dark:text-gray-300 text-sm">
|
||||
{data.node.template[n].name
|
||||
? data.node.template[n].name
|
||||
: data.node.template[n].display_name}
|
||||
|
|
@ -206,6 +194,7 @@ export default function EditNodeModal({ data }: { data: NodeDataType }) {
|
|||
data.node.template[n].value = e;
|
||||
setEnabled(e);
|
||||
}}
|
||||
size="small"
|
||||
disabled={false}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -299,6 +288,7 @@ export default function EditNodeModal({ data }: { data: NodeDataType }) {
|
|||
changeAdvanced(data.node.template[n])
|
||||
}
|
||||
disabled={false}
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
</TableCell>
|
||||
|
|
@ -319,7 +309,7 @@ export default function EditNodeModal({ data }: { data: NodeDataType }) {
|
|||
}}
|
||||
type="submit"
|
||||
>
|
||||
Save changes
|
||||
Save Changes
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ export default function ChatInput({
|
|||
}}
|
||||
className={classNames(
|
||||
lockChat
|
||||
? " bg-gray-300 text-black dark:bg-gray-700 dark:text-gray-300"
|
||||
? " bg-input text-black dark:bg-gray-700 dark:text-gray-300"
|
||||
: " bg-white-200 text-black dark:bg-gray-900 dark:text-gray-300",
|
||||
"form-input block w-full custom-scroll rounded-md border-gray-300 dark:border-gray-600 pr-10 sm:text-sm" +
|
||||
INPUT_STYLE
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ export default function ChatMessage({
|
|||
className={classNames(
|
||||
"w-full py-2 pl-2 flex",
|
||||
chat.isSend
|
||||
? "bg-white dark:bg-gray-900 "
|
||||
: "bg-gray-200 dark:bg-gray-800"
|
||||
? "bg-background dark:bg-gray-900 "
|
||||
: "bg-input dark:bg-gray-800"
|
||||
)}
|
||||
>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import "ace-builds/src-noconflict/theme-twilight";
|
|||
import "ace-builds/src-noconflict/ext-language_tools";
|
||||
// import "ace-builds/webpack-resolver";
|
||||
import { darkContext } from "../../contexts/darkContext";
|
||||
import { checkCode } from "../../controllers/API";
|
||||
import { postValidateCode } from "../../controllers/API";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
import {
|
||||
|
|
@ -81,7 +81,7 @@ export default function CodeAreaModal({
|
|||
<Button
|
||||
className="mt-3"
|
||||
onClick={() => {
|
||||
checkCode(code)
|
||||
postValidateCode(code)
|
||||
.then((apiReturn) => {
|
||||
if (apiReturn.data) {
|
||||
let importsErrors = apiReturn.data.imports.errors;
|
||||
|
|
|
|||
|
|
@ -16,11 +16,8 @@ import {
|
|||
import { Button } from "../../components/ui/button";
|
||||
import { Checkbox } from "../../components/ui/checkbox";
|
||||
import { EXPORT_DIALOG_SUBTITLE } from "../../constants";
|
||||
import EditFlowSettings from "../../components/nameInputComponent";
|
||||
import { Label } from "../../components/ui/label";
|
||||
import { Input } from "../../components/ui/input";
|
||||
import { Textarea } from "../../components/ui/textarea";
|
||||
import { Download } from "lucide-react";
|
||||
import EditFlowSettings from "../../components/EditFlowSettingsComponent";
|
||||
|
||||
export default function ExportModal() {
|
||||
const [open, setOpen] = useState(true);
|
||||
|
|
@ -57,44 +54,15 @@ export default function ExportModal() {
|
|||
<DialogDescription>{EXPORT_DIALOG_SUBTITLE}</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<Label>
|
||||
<span className="font-medium">Name</span>
|
||||
|
||||
<Input
|
||||
className="mt-2 focus-visible:ring-1"
|
||||
onChange={(event) => {
|
||||
if (event.target.value != "") {
|
||||
let newFlow = flows.find((f) => f.id === tabId);
|
||||
newFlow.name = event.target.value;
|
||||
setName(event.target.value);
|
||||
updateFlow(newFlow);
|
||||
} else {
|
||||
setName(event.target.value);
|
||||
}
|
||||
}}
|
||||
type="text"
|
||||
name="name"
|
||||
value={name ?? null}
|
||||
placeholder="File name"
|
||||
id="name"
|
||||
/>
|
||||
</Label>
|
||||
<Label>
|
||||
<span className="font-medium">Description (optional)</span>
|
||||
<Textarea
|
||||
name="description"
|
||||
id="description"
|
||||
onChange={(event) => {
|
||||
let newFlow = flows.find((f) => f.id === tabId);
|
||||
newFlow.description = event.target.value;
|
||||
updateFlow(newFlow);
|
||||
}}
|
||||
value={flows.find((f) => f.id === tabId).description ?? null}
|
||||
placeholder="Flow description"
|
||||
className="max-h-[100px] mt-2 focus-visible:ring-1"
|
||||
rows={3}
|
||||
/>
|
||||
</Label>
|
||||
<EditFlowSettings
|
||||
name={name}
|
||||
description={description}
|
||||
flows={flows}
|
||||
tabId={tabId}
|
||||
setName={setName}
|
||||
setDescription={setDescription}
|
||||
updateFlow={updateFlow}
|
||||
/>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="terms"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import {
|
|||
import { Button } from "../../components/ui/button";
|
||||
import { SETTINGS_DIALOG_SUBTITLE } from "../../constants";
|
||||
import { updateFlowInDatabase } from "../../controllers/API";
|
||||
import EditFlowSettings from "../../components/nameInputComponent";
|
||||
import EditFlowSettings from "../../components/EditFlowSettingsComponent";
|
||||
|
||||
export default function FlowSettingsModal() {
|
||||
const [open, setOpen] = useState(true);
|
||||
|
|
@ -52,10 +52,6 @@ export default function FlowSettingsModal() {
|
|||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center">
|
||||
<span className="pr-2">Settings</span>
|
||||
<ArrowDownTrayIcon
|
||||
className="h-6 w-6 text-gray-800 pl-1 dark:text-white"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</DialogTitle>
|
||||
<DialogDescription>{SETTINGS_DIALOG_SUBTITLE}</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ export default function PromptAreaModal({
|
|||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div className="fixed inset-0 bg-gray-500 dark:bg-gray-600 dark:bg-opacity-75 bg-opacity-75 transition-opacity" />
|
||||
<div className="fixed inset-0 bg-ring dark:bg-gray-600 dark:bg-opacity-75 bg-opacity-75 transition-opacity" />
|
||||
</Transition.Child>
|
||||
|
||||
<div className="fixed inset-0 z-10 overflow-y-auto">
|
||||
|
|
@ -87,7 +87,7 @@ export default function PromptAreaModal({
|
|||
</Dialog.Title>
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-full w-full bg-gray-200 overflow-auto dark:bg-gray-900 p-4 gap-4 flex flex-row justify-center items-center">
|
||||
<div className="h-full w-full bg-accent overflow-auto dark:bg-gray-900 p-4 gap-4 flex flex-row justify-center items-center">
|
||||
<div className="flex h-full w-full">
|
||||
<div className="overflow-hidden px-4 py-5 sm:p-6 w-full h-full rounded-lg bg-white dark:bg-gray-800 shadow">
|
||||
<textarea
|
||||
|
|
|
|||
|
|
@ -1,42 +1,10 @@
|
|||
import {
|
||||
Tabs,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
TabsContent,
|
||||
} from "../../components/ui/tabs";
|
||||
import ExtraSidebar from "../../components/ExtraSidebarComponent";
|
||||
import { ReactFlowProvider } from "reactflow";
|
||||
import FlowPage from "../FlowPage";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import {
|
||||
SunIcon,
|
||||
MoonIcon,
|
||||
BellIcon,
|
||||
GithubIcon,
|
||||
Download,
|
||||
Upload,
|
||||
Plus,
|
||||
Home,
|
||||
Users2,
|
||||
GitFork,
|
||||
} from "lucide-react";
|
||||
import { GithubIcon, Users2, GitFork } from "lucide-react";
|
||||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
import AlertDropdown from "../../alerts/alertDropDown";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { darkContext } from "../../contexts/darkContext";
|
||||
import { PopUpContext } from "../../contexts/popUpContext";
|
||||
import { typesContext } from "../../contexts/typesContext";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { FaGithub } from "react-icons/fa";
|
||||
|
||||
import _ from "lodash";
|
||||
|
||||
import {
|
||||
getExamples,
|
||||
updateFlowInDatabase,
|
||||
uploadFlowsToDatabase,
|
||||
} from "../../controllers/API";
|
||||
import { MenuBar } from "../../components/headerComponent/components/menuBar";
|
||||
import { getExamples } from "../../controllers/API";
|
||||
import { FlowType } from "../../types/flow";
|
||||
import { CardComponent } from "../../components/cardComponent";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ export default function Page({ flow }: { flow: FlowType }) {
|
|||
setEdges(flow?.data?.edges ?? []);
|
||||
if (reactFlowInstance) {
|
||||
setViewport(flow?.data?.viewport ?? { x: 1, y: 0, zoom: 0.5 });
|
||||
reactFlowInstance.fitView();
|
||||
}
|
||||
}, [flow, reactFlowInstance, setEdges, setNodes, setViewport]);
|
||||
//set extra sidebar
|
||||
|
|
@ -213,7 +214,8 @@ export default function Page({ flow }: { flow: FlowType }) {
|
|||
});
|
||||
|
||||
// Generate a unique node ID
|
||||
let newId = getNodeId();
|
||||
let { type } = data;
|
||||
let newId = getNodeId(type);
|
||||
let newNode: NodeType;
|
||||
|
||||
if (data.type !== "groupNode") {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,4 @@
|
|||
import {
|
||||
Bars2Icon,
|
||||
PencilSquareIcon,
|
||||
Square2StackIcon,
|
||||
TrashIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { Bars2Icon } from "@heroicons/react/24/outline";
|
||||
import DisclosureComponent from "../DisclosureComponent";
|
||||
import {
|
||||
classNames,
|
||||
|
|
@ -11,26 +6,27 @@ import {
|
|||
nodeIcons,
|
||||
nodeNames,
|
||||
} from "../../../../utils";
|
||||
import { useContext, useEffect, useState, useRef } from "react";
|
||||
import { useContext, useState } from "react";
|
||||
import { typesContext } from "../../../../contexts/typesContext";
|
||||
import { APIClassType, APIObjectType } from "../../../../types/api";
|
||||
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
|
||||
import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
||||
import { Code, Code2, FileDown, FileUp, Import, Save } from "lucide-react";
|
||||
import { Code2, FileDown, FileUp, Save } from "lucide-react";
|
||||
import { PopUpContext } from "../../../../contexts/popUpContext";
|
||||
import ImportModal from "../../../../modals/importModal";
|
||||
import ExportModal from "../../../../modals/exportModal";
|
||||
import ApiModal from "../../../../modals/ApiModal";
|
||||
import { TabsContext } from "../../../../contexts/tabsContext";
|
||||
import { Separator } from "../../../../components/ui/separator";
|
||||
import { alertContext } from "../../../../contexts/alertContext";
|
||||
import { updateFlowInDatabase } from "../../../../controllers/API";
|
||||
import { INPUT_STYLE } from "../../../../constants";
|
||||
import { Input } from "../../../../components/ui/input";
|
||||
import { Separator } from "../../../../components/ui/separator";
|
||||
|
||||
export default function ExtraSidebar() {
|
||||
const { data } = useContext(typesContext);
|
||||
const { openPopUp } = useContext(PopUpContext);
|
||||
const { flows, tabId } = useContext(TabsContext);
|
||||
const { flows, tabId, uploadFlow } = useContext(TabsContext);
|
||||
const { setSuccessData, setErrorData } = useContext(alertContext);
|
||||
const [dataFilter, setFilterData] = useState(data);
|
||||
const [search, setSearch] = useState("");
|
||||
|
|
@ -82,7 +78,8 @@ export default function ExtraSidebar() {
|
|||
<button
|
||||
className="hover:dark:hover:bg-[#242f47] text-gray-700 w-full justify-center shadow-sm transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 relative inline-flex items-center rounded-md bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
|
||||
onClick={() => {
|
||||
openPopUp(<ImportModal />);
|
||||
// openPopUp(<ImportModal />);
|
||||
uploadFlow();
|
||||
}}
|
||||
>
|
||||
<FileUp className="w-5 h-5 dark:text-gray-300"></FileUp>
|
||||
|
|
@ -132,7 +129,7 @@ export default function ExtraSidebar() {
|
|||
type="text"
|
||||
name="search"
|
||||
id="search"
|
||||
placeholder="Search nodes"
|
||||
placeholder="Search Nodes"
|
||||
className={
|
||||
INPUT_STYLE +
|
||||
"border-1 dark:border-slate-600 dark:border-0.5 dark:ring-0 focus-visible:dark:ring-0 focus-visible:dark:ring-offset-1 rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
||||
|
|
|
|||
|
|
@ -1,21 +1,9 @@
|
|||
import React, { useContext, useState } from "react";
|
||||
import { Menu, Transition } from "@headlessui/react";
|
||||
import { EllipsisVerticalIcon } from "@heroicons/react/20/solid";
|
||||
import {
|
||||
Cog6ToothIcon,
|
||||
TrashIcon,
|
||||
PencilSquareIcon,
|
||||
DocumentDuplicateIcon,
|
||||
DocumentPlusIcon,
|
||||
Square2StackIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { useContext, useState } from "react";
|
||||
import { Settings2, Copy, Trash2 } from "lucide-react";
|
||||
import { classNames } from "../../../../utils";
|
||||
import { Fragment } from "react";
|
||||
import NodeModal from "../../../../modals/NodeModal";
|
||||
import { TabsContext } from "../../../../contexts/tabsContext";
|
||||
import { useReactFlow } from "reactflow";
|
||||
import EditNodeModal from "../../../../modals/EditNodeModal";
|
||||
import TooltipReact from "../../../../components/ReactTooltipComponent";
|
||||
import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
||||
|
||||
const NodeToolbarComponent = (props) => {
|
||||
|
|
@ -48,7 +36,7 @@ const NodeToolbarComponent = (props) => {
|
|||
props.deleteNode(props.data.id);
|
||||
}}
|
||||
>
|
||||
<TrashIcon className="w-5 h-5 dark:text-gray-300"></TrashIcon>
|
||||
<Trash2 className="w-4 h-4 dark:text-gray-300"></Trash2>
|
||||
</button>
|
||||
</ShadTooltip>
|
||||
|
||||
|
|
@ -61,7 +49,7 @@ const NodeToolbarComponent = (props) => {
|
|||
)}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
console.log(reactFlowInstance.getNode(props.data.id));
|
||||
// console.log(reactFlowInstance.getNode(props.data.id));
|
||||
paste(
|
||||
{
|
||||
nodes: [reactFlowInstance.getNode(props.data.id)],
|
||||
|
|
@ -76,7 +64,7 @@ const NodeToolbarComponent = (props) => {
|
|||
);
|
||||
}}
|
||||
>
|
||||
<Square2StackIcon className="w-5 h-5 dark:text-gray-300"></Square2StackIcon>
|
||||
<Copy className="w-4 h-4 dark:text-gray-300"></Copy>
|
||||
</button>
|
||||
</ShadTooltip>
|
||||
|
||||
|
|
@ -89,12 +77,12 @@ const NodeToolbarComponent = (props) => {
|
|||
props.openPopUp(<EditNodeModal data={props.data} />);
|
||||
}}
|
||||
>
|
||||
<PencilSquareIcon className="w-5 h-5 dark:text-gray-300"></PencilSquareIcon>
|
||||
<Settings2 className="w-4 h-4 dark:text-gray-300"></Settings2>
|
||||
</button>
|
||||
</ShadTooltip>
|
||||
)}
|
||||
|
||||
{/*
|
||||
{/*
|
||||
<Menu as="div" className="relative inline-block text-left z-100">
|
||||
<button className="hover:dark:hover:bg-[#242f47] text-gray-700 transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 shadow-md relative -ml-px inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-muted focus:z-10 rounded-r-md">
|
||||
<div>
|
||||
|
|
@ -133,7 +121,7 @@ const NodeToolbarComponent = (props) => {
|
|||
"w-full group flex items-center px-4 py-2 text-sm"
|
||||
)}
|
||||
>
|
||||
<PencilSquareIcon
|
||||
<Settings
|
||||
className="mr-3 h-5 w-5 text-gray-400 group-hover:text-gray-500"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export default function HomePage() {
|
|||
}}
|
||||
>
|
||||
<Download className="w-4 mr-2" />
|
||||
Download Database
|
||||
Download Collection
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
|
|
@ -35,7 +35,7 @@ export default function HomePage() {
|
|||
}}
|
||||
>
|
||||
<Upload className="w-4 mr-2" />
|
||||
Upload Database
|
||||
Upload Collection
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ export type ToggleComponentType = {
|
|||
enabled: boolean;
|
||||
setEnabled: (state: boolean) => void;
|
||||
disabled: boolean;
|
||||
size: "small" | "medium" | "large";
|
||||
};
|
||||
export type DropDownComponentType = {
|
||||
value: string;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { FlowType } from "../flow";
|
||||
|
||||
export type TabsContextType = {
|
||||
save: () => void;
|
||||
tabId: string;
|
||||
setTabId: (index: string) => void;
|
||||
flows: Array<FlowType>;
|
||||
|
|
@ -16,7 +17,7 @@ export type TabsContextType = {
|
|||
//disable CopyPaste
|
||||
disableCopyPaste: boolean;
|
||||
setDisableCopyPaste: (value: boolean) => void;
|
||||
getNodeId: () => string;
|
||||
getNodeId: (nodeType: string) => string;
|
||||
paste: (
|
||||
selection: { nodes: any; edges: any },
|
||||
position: { x: number; y: number; paneX?: number; paneY?: number }
|
||||
|
|
|
|||
|
|
@ -16,14 +16,13 @@ import {
|
|||
Squares2X2Icon,
|
||||
Bars3CenterLeftIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { Connection, Edge, Node, ReactFlowInstance, addEdge } from "reactflow";
|
||||
import { FlowType, NodeType } from "./types/flow";
|
||||
import { APITemplateType, TemplateVariableType } from "./types/api";
|
||||
import { Connection, Edge, Node, ReactFlowInstance } from "reactflow";
|
||||
import { FlowType, NodeDataType, NodeType } from "./types/flow";
|
||||
import { APITemplateType } from "./types/api";
|
||||
import _ from "lodash";
|
||||
import { ChromaIcon } from "./icons/ChromaIcon";
|
||||
import { AnthropicIcon } from "./icons/Anthropic";
|
||||
import { AirbyteIcon } from "./icons/Airbyte";
|
||||
import { AzIcon } from "./icons/AzLogo";
|
||||
import { BingIcon } from "./icons/Bing";
|
||||
import { CohereIcon } from "./icons/Cohere";
|
||||
import { EvernoteIcon } from "./icons/Evernote";
|
||||
|
|
@ -37,17 +36,9 @@ import { MetaIcon } from "./icons/Meta";
|
|||
import { MidjorneyIcon } from "./icons/Midjorney";
|
||||
import { NotionIcon } from "./icons/Notion";
|
||||
import { OpenAiIcon } from "./icons/OpenAi";
|
||||
import { PowerPointIcon } from "./icons/PowerPoint";
|
||||
import { QDrantIcon } from "./icons/QDrant";
|
||||
import { ReadTheDocsIcon } from "./icons/ReadTheDocs";
|
||||
import { SearxIcon } from "./icons/Searx";
|
||||
import { SlackIcon } from "./icons/Slack";
|
||||
import { WeaviateIcon } from "./icons/Weaviate";
|
||||
import { WikipediaIcon } from "./icons/Wikipedia";
|
||||
import { WolframIcon } from "./icons/Wolfram";
|
||||
import { WordIcon } from "./icons/Word";
|
||||
import { SerperIcon } from "./icons/Serper";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import clsx, { ClassValue } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
|
|
@ -634,9 +625,9 @@ export function checkUpperWords(str: string) {
|
|||
export function updateIds(newFlow, getNodeId) {
|
||||
let idsMap = {};
|
||||
|
||||
newFlow.nodes.forEach((n) => {
|
||||
newFlow.nodes.forEach((n: NodeType) => {
|
||||
// Generate a unique node ID
|
||||
let newId = getNodeId();
|
||||
let newId = getNodeId(n.data.type);
|
||||
idsMap[n.id] = newId;
|
||||
n.id = newId;
|
||||
n.data.id = newId;
|
||||
|
|
@ -720,3 +711,10 @@ export function groupByFamily(data, baseClasses) {
|
|||
|
||||
return groupedObj;
|
||||
}
|
||||
|
||||
export function buildTweaks(flow) {
|
||||
return flow.data.nodes.reduce((acc, node) => {
|
||||
acc[node.data.id] = {};
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react-swc";
|
||||
import svgr from "vite-plugin-svgr";
|
||||
const apiRoutes = ["^/api/v1/"];
|
||||
const apiRoutes = ["^/api/v1/", "/health"];
|
||||
|
||||
// Use environment variable to determine the target.
|
||||
const target = process.env.VITE_PROXY_TARGET || "http://127.0.0.1:7860";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue