Merge branch 'dev' into interceptor-dev
This commit is contained in:
commit
bfbe66a547
42 changed files with 3010 additions and 4222 deletions
49
.github/workflows/pre-release.yml
vendored
Normal file
49
.github/workflows/pre-release.yml
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
name: pre-release
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- closed
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
paths:
|
||||||
|
- "pyproject.toml"
|
||||||
|
|
||||||
|
env:
|
||||||
|
POETRY_VERSION: "1.5.1"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
if_release:
|
||||||
|
if: |
|
||||||
|
${{ github.event.pull_request.merged == true }}
|
||||||
|
&& ${{ contains(github.event.pull_request.labels.*.name, 'pre-release') }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Install poetry
|
||||||
|
run: pipx install poetry==$POETRY_VERSION
|
||||||
|
- name: Set up Python 3.10
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: "3.10"
|
||||||
|
cache: "poetry"
|
||||||
|
- name: Build project for distribution
|
||||||
|
run: make build
|
||||||
|
- name: Check Version
|
||||||
|
id: check-version
|
||||||
|
run: |
|
||||||
|
echo version=$(poetry version --short) >> $GITHUB_OUTPUT
|
||||||
|
- name: Create Release
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
with:
|
||||||
|
artifacts: "dist/*"
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
draft: false
|
||||||
|
generateReleaseNotes: true
|
||||||
|
tag: v${{ steps.check-version.outputs.version }}
|
||||||
|
commit: main
|
||||||
|
- name: Publish to PyPI
|
||||||
|
env:
|
||||||
|
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }}
|
||||||
|
run: |
|
||||||
|
poetry publish
|
||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
|
@ -10,7 +10,7 @@ on:
|
||||||
- "pyproject.toml"
|
- "pyproject.toml"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
POETRY_VERSION: "1.4.0"
|
POETRY_VERSION: "1.5.1"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
if_release:
|
if_release:
|
||||||
|
|
|
||||||
3518
src/frontend/package-lock.json
generated
3518
src/frontend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { cloneDeep } from "lodash";
|
||||||
import React, { useContext, useEffect, useRef, useState } from "react";
|
import React, { useContext, useEffect, useRef, useState } from "react";
|
||||||
import { Handle, Position, useUpdateNodeInternals } from "reactflow";
|
import { Handle, Position, useUpdateNodeInternals } from "reactflow";
|
||||||
import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
||||||
|
|
@ -13,14 +14,10 @@ import PromptAreaComponent from "../../../../components/promptComponent";
|
||||||
import TextAreaComponent from "../../../../components/textAreaComponent";
|
import TextAreaComponent from "../../../../components/textAreaComponent";
|
||||||
import ToggleShadComponent from "../../../../components/toggleShadComponent";
|
import ToggleShadComponent from "../../../../components/toggleShadComponent";
|
||||||
import { MAX_LENGTH_TO_SCROLL_TOOLTIP } from "../../../../constants/constants";
|
import { MAX_LENGTH_TO_SCROLL_TOOLTIP } from "../../../../constants/constants";
|
||||||
import { PopUpContext } from "../../../../contexts/popUpContext";
|
|
||||||
import { TabsContext } from "../../../../contexts/tabsContext";
|
import { TabsContext } from "../../../../contexts/tabsContext";
|
||||||
import { typesContext } from "../../../../contexts/typesContext";
|
import { typesContext } from "../../../../contexts/typesContext";
|
||||||
import { ParameterComponentType } from "../../../../types/components";
|
import { ParameterComponentType } from "../../../../types/components";
|
||||||
import {
|
import { isValidConnection } from "../../../../utils/reactflowUtils";
|
||||||
cleanEdges,
|
|
||||||
isValidConnection,
|
|
||||||
} from "../../../../utils/reactflowUtils";
|
|
||||||
import {
|
import {
|
||||||
nodeColors,
|
nodeColors,
|
||||||
nodeIconsLucide,
|
nodeIconsLucide,
|
||||||
|
|
@ -36,6 +33,7 @@ export default function ParameterComponent({
|
||||||
left,
|
left,
|
||||||
id,
|
id,
|
||||||
data,
|
data,
|
||||||
|
setData,
|
||||||
tooltipTitle,
|
tooltipTitle,
|
||||||
title,
|
title,
|
||||||
color,
|
color,
|
||||||
|
|
@ -51,7 +49,6 @@ export default function ParameterComponent({
|
||||||
const infoHtml = useRef(null);
|
const infoHtml = useRef(null);
|
||||||
const updateNodeInternals = useUpdateNodeInternals();
|
const updateNodeInternals = useUpdateNodeInternals();
|
||||||
const [position, setPosition] = useState(0);
|
const [position, setPosition] = useState(0);
|
||||||
const { closePopUp } = useContext(PopUpContext);
|
|
||||||
const { setTabsState, tabId, save } = useContext(TabsContext);
|
const { setTabsState, tabId, save } = useContext(TabsContext);
|
||||||
|
|
||||||
// Update component position
|
// Update component position
|
||||||
|
|
@ -66,15 +63,16 @@ export default function ParameterComponent({
|
||||||
updateNodeInternals(data.id);
|
updateNodeInternals(data.id);
|
||||||
}, [data.id, position, updateNodeInternals]);
|
}, [data.id, position, updateNodeInternals]);
|
||||||
|
|
||||||
useEffect(() => {}, [closePopUp, data.node.template]);
|
|
||||||
|
|
||||||
const { reactFlowInstance } = useContext(typesContext);
|
const { reactFlowInstance } = useContext(typesContext);
|
||||||
let disabled =
|
let disabled =
|
||||||
reactFlowInstance?.getEdges().some((e) => e.targetHandle === id) ?? false;
|
reactFlowInstance?.getEdges().some((e) => e.targetHandle === id) ?? false;
|
||||||
const [myData, setMyData] = useState(useContext(typesContext).data);
|
|
||||||
|
const { data: myData } = useContext(typesContext);
|
||||||
|
|
||||||
const handleOnNewValue = (newValue: any) => {
|
const handleOnNewValue = (newValue: any) => {
|
||||||
data.node.template[name].value = newValue;
|
let newData = cloneDeep(data);
|
||||||
|
newData.node.template[name].value = newValue;
|
||||||
|
setData(newData);
|
||||||
// Set state to pending
|
// Set state to pending
|
||||||
setTabsState((prev) => {
|
setTabsState((prev) => {
|
||||||
return {
|
return {
|
||||||
|
|
@ -244,7 +242,6 @@ export default function ParameterComponent({
|
||||||
) : (
|
) : (
|
||||||
<InputComponent
|
<InputComponent
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
disableCopyPaste={true}
|
|
||||||
password={data.node.template[name].password ?? false}
|
password={data.node.template[name].password ?? false}
|
||||||
value={data.node.template[name].value ?? ""}
|
value={data.node.template[name].value ?? ""}
|
||||||
onChange={handleOnNewValue}
|
onChange={handleOnNewValue}
|
||||||
|
|
@ -266,7 +263,6 @@ export default function ParameterComponent({
|
||||||
<div className="mt-2 w-full">
|
<div className="mt-2 w-full">
|
||||||
<FloatComponent
|
<FloatComponent
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
disableCopyPaste={true}
|
|
||||||
value={data.node.template[name].value ?? ""}
|
value={data.node.template[name].value ?? ""}
|
||||||
onChange={handleOnNewValue}
|
onChange={handleOnNewValue}
|
||||||
/>
|
/>
|
||||||
|
|
@ -311,7 +307,6 @@ export default function ParameterComponent({
|
||||||
<div className="mt-2 w-full">
|
<div className="mt-2 w-full">
|
||||||
<IntComponent
|
<IntComponent
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
disableCopyPaste={true}
|
|
||||||
value={data.node.template[name].value ?? ""}
|
value={data.node.template[name].value ?? ""}
|
||||||
onChange={handleOnNewValue}
|
onChange={handleOnNewValue}
|
||||||
/>
|
/>
|
||||||
|
|
@ -322,15 +317,6 @@ export default function ParameterComponent({
|
||||||
field_name={name}
|
field_name={name}
|
||||||
setNodeClass={(nodeClass) => {
|
setNodeClass={(nodeClass) => {
|
||||||
data.node = nodeClass;
|
data.node = nodeClass;
|
||||||
if (reactFlowInstance) {
|
|
||||||
cleanEdges({
|
|
||||||
flow: {
|
|
||||||
edges: reactFlowInstance.getEdges(),
|
|
||||||
nodes: reactFlowInstance.getNodes(),
|
|
||||||
},
|
|
||||||
updateEdge: (edge) => reactFlowInstance.setEdges(edge),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
nodeClass={data.node}
|
nodeClass={data.node}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,33 @@
|
||||||
|
import { cloneDeep } from "lodash";
|
||||||
import { useContext, useEffect, useRef, useState } from "react";
|
import { useContext, useEffect, useRef, useState } from "react";
|
||||||
import { NodeToolbar } from "reactflow";
|
import { NodeToolbar, useUpdateNodeInternals } from "reactflow";
|
||||||
import ShadTooltip from "../../components/ShadTooltipComponent";
|
import ShadTooltip from "../../components/ShadTooltipComponent";
|
||||||
import Tooltip from "../../components/TooltipComponent";
|
import Tooltip from "../../components/TooltipComponent";
|
||||||
import IconComponent from "../../components/genericIconComponent";
|
import IconComponent from "../../components/genericIconComponent";
|
||||||
import { useSSE } from "../../contexts/SSEContext";
|
import { useSSE } from "../../contexts/SSEContext";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
import { typesContext } from "../../contexts/typesContext";
|
import { typesContext } from "../../contexts/typesContext";
|
||||||
import NodeModal from "../../modals/NodeModal";
|
|
||||||
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
|
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
|
||||||
import { NodeDataType } from "../../types/flow";
|
import { NodeDataType } from "../../types/flow";
|
||||||
|
import { cleanEdges } from "../../utils/reactflowUtils";
|
||||||
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
|
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
|
||||||
import { classNames, toTitleCase } from "../../utils/utils";
|
import { classNames, toTitleCase } from "../../utils/utils";
|
||||||
import ParameterComponent from "./components/parameterComponent";
|
import ParameterComponent from "./components/parameterComponent";
|
||||||
|
|
||||||
export default function GenericNode({
|
export default function GenericNode({
|
||||||
data,
|
data: olddata,
|
||||||
selected,
|
selected,
|
||||||
}: {
|
}: {
|
||||||
data: NodeDataType;
|
data: NodeDataType;
|
||||||
selected: boolean;
|
selected: boolean;
|
||||||
}) {
|
}) {
|
||||||
|
const [data, setData] = useState(olddata);
|
||||||
const { setErrorData } = useContext(alertContext);
|
const { setErrorData } = useContext(alertContext);
|
||||||
|
const { updateFlow, flows, tabId } = useContext(TabsContext);
|
||||||
|
const updateNodeInternals = useUpdateNodeInternals();
|
||||||
const showError = useRef(true);
|
const showError = useRef(true);
|
||||||
const { types, deleteNode } = useContext(typesContext);
|
const { types, deleteNode, reactFlowInstance } = useContext(typesContext);
|
||||||
|
|
||||||
const { closePopUp, openPopUp } = useContext(PopUpContext);
|
|
||||||
// any to avoid type conflict
|
// any to avoid type conflict
|
||||||
const Icon: any =
|
const Icon: any =
|
||||||
nodeIconsLucide[data.type] || nodeIconsLucide[types[data.type]];
|
nodeIconsLucide[data.type] || nodeIconsLucide[types[data.type]];
|
||||||
|
|
@ -33,7 +35,26 @@ export default function GenericNode({
|
||||||
const [validationStatus, setValidationStatus] = useState(null);
|
const [validationStatus, setValidationStatus] = useState(null);
|
||||||
// State for outline color
|
// State for outline color
|
||||||
const { sseData, isBuilding } = useSSE();
|
const { sseData, isBuilding } = useSSE();
|
||||||
const refHtml = useRef(null);
|
useEffect(() => {
|
||||||
|
olddata.node = data.node;
|
||||||
|
let myFlow = flows.find((flow) => flow.id === tabId);
|
||||||
|
if (reactFlowInstance && myFlow) {
|
||||||
|
let flow = cloneDeep(myFlow);
|
||||||
|
flow.data = reactFlowInstance.toObject();
|
||||||
|
cleanEdges({
|
||||||
|
flow: {
|
||||||
|
edges: flow.data.edges,
|
||||||
|
nodes: flow.data.nodes,
|
||||||
|
},
|
||||||
|
updateEdge: (edge) => {
|
||||||
|
flow.data.edges = edge;
|
||||||
|
reactFlowInstance.setEdges(edge);
|
||||||
|
updateNodeInternals(data.id);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
updateFlow(flow);
|
||||||
|
}
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
// New useEffect to watch for changes in sseData and update validation status
|
// New useEffect to watch for changes in sseData and update validation status
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -58,13 +79,12 @@ export default function GenericNode({
|
||||||
deleteNode(data.id);
|
deleteNode(data.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
useEffect(() => {}, [closePopUp, data.node.template]);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NodeToolbar>
|
<NodeToolbar>
|
||||||
<NodeToolbarComponent
|
<NodeToolbarComponent
|
||||||
data={data}
|
data={data}
|
||||||
openPopUp={openPopUp}
|
setData={setData}
|
||||||
deleteNode={deleteNode}
|
deleteNode={deleteNode}
|
||||||
></NodeToolbarComponent>
|
></NodeToolbarComponent>
|
||||||
</NodeToolbar>
|
</NodeToolbar>
|
||||||
|
|
@ -90,15 +110,6 @@ export default function GenericNode({
|
||||||
</ShadTooltip>
|
</ShadTooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="round-button-div">
|
|
||||||
<button
|
|
||||||
className="relative"
|
|
||||||
onClick={(event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
openPopUp(<NodeModal data={data} />);
|
|
||||||
}}
|
|
||||||
></button>
|
|
||||||
</div>
|
|
||||||
<div className="round-button-div">
|
<div className="round-button-div">
|
||||||
<div>
|
<div>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
|
@ -168,6 +179,7 @@ export default function GenericNode({
|
||||||
!data.node.template[t].advanced ? (
|
!data.node.template[t].advanced ? (
|
||||||
<ParameterComponent
|
<ParameterComponent
|
||||||
data={data}
|
data={data}
|
||||||
|
setData={setData}
|
||||||
color={
|
color={
|
||||||
nodeColors[types[data.node.template[t].type]] ??
|
nodeColors[types[data.node.template[t].type]] ??
|
||||||
nodeColors[data.node.template[t].type] ??
|
nodeColors[data.node.template[t].type] ??
|
||||||
|
|
@ -214,6 +226,7 @@ export default function GenericNode({
|
||||||
</div>
|
</div>
|
||||||
<ParameterComponent
|
<ParameterComponent
|
||||||
data={data}
|
data={data}
|
||||||
|
setData={setData}
|
||||||
color={nodeColors[types[data.type]] ?? nodeColors.unknown}
|
color={nodeColors[types[data.type]] ?? nodeColors.unknown}
|
||||||
title={
|
title={
|
||||||
data.node.output_types && data.node.output_types.length > 0
|
data.node.output_types && data.node.output_types.length > 0
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ type InputProps = {
|
||||||
name: string | null;
|
name: string | null;
|
||||||
description: string | null;
|
description: string | null;
|
||||||
maxLength?: number;
|
maxLength?: number;
|
||||||
flows: Array<{ id: string; name: string }>;
|
flows: Array<{ id: string; name: string; description: string }>;
|
||||||
tabId: string;
|
tabId: string;
|
||||||
setName: (name: string) => void;
|
setName: (name: string) => void;
|
||||||
setDescription: (description: string) => void;
|
setDescription: (description: string) => void;
|
||||||
|
|
@ -37,7 +37,13 @@ export const EditFlowSettings: React.FC<InputProps> = ({
|
||||||
setName(value);
|
setName(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const [desc, setDesc] = useState(
|
||||||
|
flows.find((f) => f.id === tabId).description
|
||||||
|
);
|
||||||
|
|
||||||
const handleDescriptionChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
|
const handleDescriptionChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
|
||||||
|
flows.find((f) => f.id === tabId).description = event.target.value;
|
||||||
|
setDesc(flows.find((f) => f.id === tabId).description);
|
||||||
setDescription(event.target.value);
|
setDescription(event.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -51,7 +57,7 @@ export const EditFlowSettings: React.FC<InputProps> = ({
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
className="mt-2 font-normal"
|
className="nopan nodrag noundo nocopy mt-2 font-normal"
|
||||||
onChange={handleNameChange}
|
onChange={handleNameChange}
|
||||||
type="text"
|
type="text"
|
||||||
name="name"
|
name="name"
|
||||||
|
|
@ -62,12 +68,15 @@ export const EditFlowSettings: React.FC<InputProps> = ({
|
||||||
/>
|
/>
|
||||||
</Label>
|
</Label>
|
||||||
<Label>
|
<Label>
|
||||||
<span className="font-medium">Description (optional)</span>
|
<div className="edit-flow-arrangement mt-3">
|
||||||
|
<span className="font-medium ">Description (optional)</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Textarea
|
<Textarea
|
||||||
name="description"
|
name="description"
|
||||||
id="description"
|
id="description"
|
||||||
onChange={handleDescriptionChange}
|
onChange={handleDescriptionChange}
|
||||||
value={description ?? ""}
|
value={desc}
|
||||||
placeholder="Flow description"
|
placeholder="Flow description"
|
||||||
className="mt-2 max-h-[100px] font-normal"
|
className="mt-2 max-h-[100px] font-normal"
|
||||||
rows={3}
|
rows={3}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import CodeAreaModal from "../../modals/codeAreaModal";
|
import CodeAreaModal from "../../modals/codeAreaModal";
|
||||||
import { TextAreaComponentType } from "../../types/components";
|
import { TextAreaComponentType } from "../../types/components";
|
||||||
|
|
||||||
|
|
@ -16,7 +15,6 @@ export default function CodeAreaComponent({
|
||||||
const [myValue, setMyValue] = useState(
|
const [myValue, setMyValue] = useState(
|
||||||
typeof value == "string" ? value : JSON.stringify(value)
|
typeof value == "string" ? value : JSON.stringify(value)
|
||||||
);
|
);
|
||||||
const { openPopUp } = useContext(PopUpContext);
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
setMyValue("");
|
setMyValue("");
|
||||||
|
|
@ -30,10 +28,6 @@ export default function CodeAreaComponent({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={disabled ? "pointer-events-none w-full " : " w-full"}>
|
<div className={disabled ? "pointer-events-none w-full " : " w-full"}>
|
||||||
<div className="flex w-full items-center">
|
|
||||||
<span
|
|
||||||
onClick={() => {
|
|
||||||
openPopUp(
|
|
||||||
<CodeAreaModal
|
<CodeAreaModal
|
||||||
value={myValue}
|
value={myValue}
|
||||||
nodeClass={nodeClass}
|
nodeClass={nodeClass}
|
||||||
|
|
@ -42,9 +36,9 @@ export default function CodeAreaComponent({
|
||||||
setMyValue(t);
|
setMyValue(t);
|
||||||
onChange(t);
|
onChange(t);
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
);
|
<div className="flex w-full items-center">
|
||||||
}}
|
<span
|
||||||
className={
|
className={
|
||||||
editNode
|
editNode
|
||||||
? "input-edit-node input-dialog"
|
? "input-edit-node input-dialog"
|
||||||
|
|
@ -54,21 +48,6 @@ export default function CodeAreaComponent({
|
||||||
>
|
>
|
||||||
{myValue !== "" ? myValue : "Type something..."}
|
{myValue !== "" ? myValue : "Type something..."}
|
||||||
</span>
|
</span>
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
openPopUp(
|
|
||||||
<CodeAreaModal
|
|
||||||
setNodeClass={setNodeClass}
|
|
||||||
value={myValue}
|
|
||||||
nodeClass={nodeClass}
|
|
||||||
setValue={(t: string) => {
|
|
||||||
setMyValue(t);
|
|
||||||
onChange(t);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{!editNode && (
|
{!editNode && (
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="ExternalLink"
|
name="ExternalLink"
|
||||||
|
|
@ -78,8 +57,8 @@ export default function CodeAreaComponent({
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
</CodeAreaModal>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
667
src/frontend/src/components/codeTabsComponent/index.tsx
Normal file
667
src/frontend/src/components/codeTabsComponent/index.tsx
Normal file
|
|
@ -0,0 +1,667 @@
|
||||||
|
import { cloneDeep } from "lodash";
|
||||||
|
import { useContext, useEffect, useState } from "react";
|
||||||
|
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||||
|
import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
|
||||||
|
import AccordionComponent from "../../components/AccordionComponent";
|
||||||
|
import ShadTooltip from "../../components/ShadTooltipComponent";
|
||||||
|
import CodeAreaComponent from "../../components/codeAreaComponent";
|
||||||
|
import Dropdown from "../../components/dropdownComponent";
|
||||||
|
import FloatComponent from "../../components/floatComponent";
|
||||||
|
import InputComponent from "../../components/inputComponent";
|
||||||
|
import InputFileComponent from "../../components/inputFileComponent";
|
||||||
|
import InputListComponent from "../../components/inputListComponent";
|
||||||
|
import IntComponent from "../../components/intComponent";
|
||||||
|
import PromptAreaComponent from "../../components/promptComponent";
|
||||||
|
import TextAreaComponent from "../../components/textAreaComponent";
|
||||||
|
import ToggleShadComponent from "../../components/toggleShadComponent";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "../../components/ui/table";
|
||||||
|
import {
|
||||||
|
Tabs,
|
||||||
|
TabsContent,
|
||||||
|
TabsList,
|
||||||
|
TabsTrigger,
|
||||||
|
} from "../../components/ui/tabs";
|
||||||
|
import { darkContext } from "../../contexts/darkContext";
|
||||||
|
import { FlowType } from "../../types/flow/index";
|
||||||
|
import { classNames } from "../../utils/utils";
|
||||||
|
import IconComponent from "../genericIconComponent";
|
||||||
|
|
||||||
|
export default function CodeTabsComponent({
|
||||||
|
flow,
|
||||||
|
tabs,
|
||||||
|
activeTab,
|
||||||
|
setActiveTab,
|
||||||
|
isMessage,
|
||||||
|
tweaks,
|
||||||
|
}: {
|
||||||
|
flow?: FlowType;
|
||||||
|
tabs: any;
|
||||||
|
activeTab: string;
|
||||||
|
setActiveTab: any;
|
||||||
|
isMessage?: boolean;
|
||||||
|
tweaks?: {
|
||||||
|
tweak?: any;
|
||||||
|
tweaksList?: any;
|
||||||
|
buildContent?: any;
|
||||||
|
getValue?: any;
|
||||||
|
buildTweakObject?: any;
|
||||||
|
};
|
||||||
|
}) {
|
||||||
|
const [isCopied, setIsCopied] = useState<Boolean>(false);
|
||||||
|
const [data, setData] = useState(flow ? flow["data"]["nodes"] : null);
|
||||||
|
const [openAccordion, setOpenAccordion] = useState([]);
|
||||||
|
const { dark } = useContext(darkContext);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (flow && flow["data"]["nodes"]) {
|
||||||
|
setData(flow["data"]["nodes"]);
|
||||||
|
}
|
||||||
|
}, [flow]);
|
||||||
|
|
||||||
|
const copyToClipboard = () => {
|
||||||
|
if (!navigator.clipboard || !navigator.clipboard.writeText) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(tabs[activeTab].code).then(() => {
|
||||||
|
setIsCopied(true);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsCopied(false);
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadAsFile = () => {
|
||||||
|
const fileExtension = tabs[activeTab].language || ".txt";
|
||||||
|
const suggestedFileName = `${"generated-code."}${fileExtension}`;
|
||||||
|
const fileName = window.prompt("Enter the file name.", suggestedFileName);
|
||||||
|
|
||||||
|
if (!fileName) {
|
||||||
|
// user pressed cancel on prompt
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = new Blob([tabs[activeTab].code], { type: "text/plain" });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.download = fileName;
|
||||||
|
link.href = url;
|
||||||
|
link.style.display = "none";
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
function openAccordions() {
|
||||||
|
let accordionsToOpen = [];
|
||||||
|
tweaks.tweak.current.forEach((el) => {
|
||||||
|
Object.keys(el).forEach((key) => {
|
||||||
|
if (Object.keys(el[key]).length > 0) {
|
||||||
|
accordionsToOpen.push(key);
|
||||||
|
setOpenAccordion(accordionsToOpen);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (accordionsToOpen.length == 0) {
|
||||||
|
setOpenAccordion([]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Tabs
|
||||||
|
value={activeTab}
|
||||||
|
className={
|
||||||
|
"api-modal-tabs " +
|
||||||
|
(isMessage ? "dark " : "") +
|
||||||
|
(dark && isMessage ? "bg-background" : "")
|
||||||
|
}
|
||||||
|
onValueChange={(value) => {
|
||||||
|
setActiveTab(value);
|
||||||
|
if (value === "3") {
|
||||||
|
openAccordions();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="api-modal-tablist-div">
|
||||||
|
<TabsList>
|
||||||
|
{tabs.map((tab, index) => (
|
||||||
|
<TabsTrigger
|
||||||
|
className={
|
||||||
|
isMessage ? "data-[state=active]:bg-primary-foreground" : ""
|
||||||
|
}
|
||||||
|
key={index}
|
||||||
|
value={index.toString()}
|
||||||
|
>
|
||||||
|
{tab.name}
|
||||||
|
</TabsTrigger>
|
||||||
|
))}
|
||||||
|
</TabsList>
|
||||||
|
{Number(activeTab) < 3 && (
|
||||||
|
<div className="float-right mx-1 flex gap-2">
|
||||||
|
<button
|
||||||
|
className="flex items-center gap-1.5 rounded bg-none p-1 text-xs text-gray-500 dark:text-gray-300"
|
||||||
|
onClick={copyToClipboard}
|
||||||
|
>
|
||||||
|
{isCopied ? (
|
||||||
|
<IconComponent name="Check" className="h-4 w-4" />
|
||||||
|
) : (
|
||||||
|
<IconComponent name="Clipboard" className="h-4 w-4" />
|
||||||
|
)}
|
||||||
|
{isCopied ? "Copied!" : "Copy code"}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="flex items-center gap-1.5 rounded bg-none p-1 text-xs text-gray-500 dark:text-gray-300"
|
||||||
|
onClick={downloadAsFile}
|
||||||
|
>
|
||||||
|
<IconComponent name="Download" className="h-5 w-5" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{tabs.map((tab, index) => (
|
||||||
|
<TabsContent
|
||||||
|
value={index.toString()}
|
||||||
|
className="api-modal-tabs-content"
|
||||||
|
key={index} // Remember to add a unique key prop
|
||||||
|
>
|
||||||
|
{index < 3 ? (
|
||||||
|
<SyntaxHighlighter
|
||||||
|
className="mt-0 h-full w-full overflow-auto custom-scroll"
|
||||||
|
language={tab.mode}
|
||||||
|
style={oneDark}
|
||||||
|
>
|
||||||
|
{tab.code}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
) : index === 3 ? (
|
||||||
|
<>
|
||||||
|
<div className="api-modal-according-display">
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
"h-[70vh] w-full rounded-lg bg-muted",
|
||||||
|
1 == 1
|
||||||
|
? "overflow-scroll overflow-x-hidden custom-scroll"
|
||||||
|
: "overflow-hidden"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{data.map((t: any, index) => (
|
||||||
|
<div className="px-3" key={index}>
|
||||||
|
{tweaks.tweaksList.current.includes(t["data"]["id"]) && (
|
||||||
|
<AccordionComponent
|
||||||
|
trigger={t["data"]["id"]}
|
||||||
|
open={openAccordion}
|
||||||
|
keyValue={t["data"]["id"]}
|
||||||
|
>
|
||||||
|
<div className="api-modal-table-arrangement">
|
||||||
|
<Table className="table-fixed bg-muted outline-1">
|
||||||
|
<TableHeader className="h-10 border-input text-xs font-medium text-ring">
|
||||||
|
<TableRow className="dark:border-b-muted">
|
||||||
|
<TableHead className="h-7 text-center">
|
||||||
|
PARAM
|
||||||
|
</TableHead>
|
||||||
|
<TableHead className="h-7 p-0 text-center">
|
||||||
|
VALUE
|
||||||
|
</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody className="p-0">
|
||||||
|
{Object.keys(t["data"]["node"]["template"])
|
||||||
|
.filter(
|
||||||
|
(n) =>
|
||||||
|
n.charAt(0) !== "_" &&
|
||||||
|
t.data.node.template[n].show &&
|
||||||
|
(t.data.node.template[n].type === "str" ||
|
||||||
|
t.data.node.template[n].type ===
|
||||||
|
"bool" ||
|
||||||
|
t.data.node.template[n].type ===
|
||||||
|
"float" ||
|
||||||
|
t.data.node.template[n].type ===
|
||||||
|
"code" ||
|
||||||
|
t.data.node.template[n].type ===
|
||||||
|
"prompt" ||
|
||||||
|
t.data.node.template[n].type ===
|
||||||
|
"file" ||
|
||||||
|
t.data.node.template[n].type === "int")
|
||||||
|
)
|
||||||
|
.map((n, i) => {
|
||||||
|
return (
|
||||||
|
<TableRow
|
||||||
|
key={i}
|
||||||
|
className="h-10 dark:border-b-muted"
|
||||||
|
>
|
||||||
|
<TableCell className="p-0 text-center text-sm text-foreground">
|
||||||
|
{n}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="p-0 text-xs text-foreground">
|
||||||
|
<div className="m-auto w-[250px]">
|
||||||
|
{t.data.node.template[n].type ===
|
||||||
|
"str" &&
|
||||||
|
!t.data.node.template[n].options ? (
|
||||||
|
<div className="mx-auto">
|
||||||
|
{t.data.node.template[n]
|
||||||
|
.list ? (
|
||||||
|
<InputListComponent
|
||||||
|
editNode={true}
|
||||||
|
disabled={false}
|
||||||
|
value={
|
||||||
|
!t.data.node.template[n]
|
||||||
|
.value ||
|
||||||
|
t.data.node.template[n]
|
||||||
|
.value === ""
|
||||||
|
? [""]
|
||||||
|
: t.data.node.template[
|
||||||
|
n
|
||||||
|
].value
|
||||||
|
}
|
||||||
|
onChange={(k) => {
|
||||||
|
setData((old) => {
|
||||||
|
let newInputList =
|
||||||
|
cloneDeep(old);
|
||||||
|
newInputList[
|
||||||
|
index
|
||||||
|
].data.node.template[
|
||||||
|
n
|
||||||
|
].value = k;
|
||||||
|
return newInputList;
|
||||||
|
});
|
||||||
|
tweaks.buildTweakObject(
|
||||||
|
t["data"]["id"],
|
||||||
|
k,
|
||||||
|
t.data.node.template[n]
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : t.data.node.template[n]
|
||||||
|
.multiline ? (
|
||||||
|
<ShadTooltip
|
||||||
|
content={tweaks.buildContent(
|
||||||
|
t.data.node.template[n]
|
||||||
|
.value
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<TextAreaComponent
|
||||||
|
disabled={false}
|
||||||
|
editNode={true}
|
||||||
|
value={
|
||||||
|
!t.data.node.template[
|
||||||
|
n
|
||||||
|
].value ||
|
||||||
|
t.data.node.template[
|
||||||
|
n
|
||||||
|
].value === ""
|
||||||
|
? ""
|
||||||
|
: t.data.node
|
||||||
|
.template[n]
|
||||||
|
.value
|
||||||
|
}
|
||||||
|
onChange={(k) => {
|
||||||
|
setData((old) => {
|
||||||
|
let newInputList =
|
||||||
|
cloneDeep(old);
|
||||||
|
newInputList[
|
||||||
|
index
|
||||||
|
].data.node.template[
|
||||||
|
n
|
||||||
|
].value = k;
|
||||||
|
return newInputList;
|
||||||
|
});
|
||||||
|
tweaks.buildTweakObject(
|
||||||
|
t["data"]["id"],
|
||||||
|
k,
|
||||||
|
t.data.node
|
||||||
|
.template[n]
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ShadTooltip>
|
||||||
|
) : (
|
||||||
|
<InputComponent
|
||||||
|
editNode={true}
|
||||||
|
disabled={false}
|
||||||
|
password={
|
||||||
|
t.data.node.template[n]
|
||||||
|
.password ?? false
|
||||||
|
}
|
||||||
|
value={
|
||||||
|
!t.data.node.template[n]
|
||||||
|
.value ||
|
||||||
|
t.data.node.template[n]
|
||||||
|
.value === ""
|
||||||
|
? ""
|
||||||
|
: t.data.node.template[
|
||||||
|
n
|
||||||
|
].value
|
||||||
|
}
|
||||||
|
onChange={(k) => {
|
||||||
|
setData((old) => {
|
||||||
|
let newInputList =
|
||||||
|
cloneDeep(old);
|
||||||
|
newInputList[
|
||||||
|
index
|
||||||
|
].data.node.template[
|
||||||
|
n
|
||||||
|
].value = k;
|
||||||
|
return newInputList;
|
||||||
|
});
|
||||||
|
tweaks.buildTweakObject(
|
||||||
|
t["data"]["id"],
|
||||||
|
k,
|
||||||
|
t.data.node.template[n]
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : t.data.node.template[n].type ===
|
||||||
|
"bool" ? (
|
||||||
|
<div className="ml-auto">
|
||||||
|
{" "}
|
||||||
|
<ToggleShadComponent
|
||||||
|
enabled={
|
||||||
|
t.data.node.template[n]
|
||||||
|
.value
|
||||||
|
}
|
||||||
|
setEnabled={(e) => {
|
||||||
|
setData((old) => {
|
||||||
|
let newInputList =
|
||||||
|
cloneDeep(old);
|
||||||
|
newInputList[
|
||||||
|
index
|
||||||
|
].data.node.template[
|
||||||
|
n
|
||||||
|
].value = e;
|
||||||
|
return newInputList;
|
||||||
|
});
|
||||||
|
tweaks.buildTweakObject(
|
||||||
|
t["data"]["id"],
|
||||||
|
e,
|
||||||
|
t.data.node.template[n]
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
size="small"
|
||||||
|
disabled={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : t.data.node.template[n].type ===
|
||||||
|
"file" ? (
|
||||||
|
<ShadTooltip
|
||||||
|
content={tweaks.buildContent(
|
||||||
|
!t.data.node.template[n]
|
||||||
|
.value ||
|
||||||
|
t.data.node.template[n]
|
||||||
|
.value === ""
|
||||||
|
? ""
|
||||||
|
: t.data.node.template[n]
|
||||||
|
.value
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="mx-auto">
|
||||||
|
<InputFileComponent
|
||||||
|
editNode={true}
|
||||||
|
disabled={false}
|
||||||
|
value={
|
||||||
|
t.data.node.template[n]
|
||||||
|
.value ?? ""
|
||||||
|
}
|
||||||
|
onChange={(k: any) => {}}
|
||||||
|
fileTypes={
|
||||||
|
t.data.node.template[n]
|
||||||
|
.fileTypes
|
||||||
|
}
|
||||||
|
suffixes={
|
||||||
|
t.data.node.template[n]
|
||||||
|
.suffixes
|
||||||
|
}
|
||||||
|
onFileChange={(
|
||||||
|
k: any
|
||||||
|
) => {}}
|
||||||
|
></InputFileComponent>
|
||||||
|
</div>
|
||||||
|
</ShadTooltip>
|
||||||
|
) : t.data.node.template[n].type ===
|
||||||
|
"float" ? (
|
||||||
|
<div className="mx-auto">
|
||||||
|
<FloatComponent
|
||||||
|
disabled={false}
|
||||||
|
editNode={true}
|
||||||
|
value={
|
||||||
|
!t.data.node.template[n]
|
||||||
|
.value ||
|
||||||
|
t.data.node.template[n]
|
||||||
|
.value === ""
|
||||||
|
? ""
|
||||||
|
: t.data.node.template[n]
|
||||||
|
.value
|
||||||
|
}
|
||||||
|
onChange={(k) => {
|
||||||
|
setData((old) => {
|
||||||
|
let newInputList =
|
||||||
|
cloneDeep(old);
|
||||||
|
newInputList[
|
||||||
|
index
|
||||||
|
].data.node.template[
|
||||||
|
n
|
||||||
|
].value = k;
|
||||||
|
return newInputList;
|
||||||
|
});
|
||||||
|
tweaks.buildTweakObject(
|
||||||
|
t["data"]["id"],
|
||||||
|
k,
|
||||||
|
t.data.node.template[n]
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : t.data.node.template[n].type ===
|
||||||
|
"str" &&
|
||||||
|
t.data.node.template[n]
|
||||||
|
.options ? (
|
||||||
|
<div className="mx-auto">
|
||||||
|
<Dropdown
|
||||||
|
editNode={true}
|
||||||
|
apiModal={true}
|
||||||
|
options={
|
||||||
|
t.data.node.template[n]
|
||||||
|
.options
|
||||||
|
}
|
||||||
|
onSelect={(k) => {
|
||||||
|
setData((old) => {
|
||||||
|
let newInputList =
|
||||||
|
cloneDeep(old);
|
||||||
|
newInputList[
|
||||||
|
index
|
||||||
|
].data.node.template[
|
||||||
|
n
|
||||||
|
].value = k;
|
||||||
|
return newInputList;
|
||||||
|
});
|
||||||
|
tweaks.buildTweakObject(
|
||||||
|
t["data"]["id"],
|
||||||
|
k,
|
||||||
|
t.data.node.template[n]
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
value={
|
||||||
|
!t.data.node.template[n]
|
||||||
|
.value ||
|
||||||
|
t.data.node.template[n]
|
||||||
|
.value === ""
|
||||||
|
? ""
|
||||||
|
: t.data.node.template[n]
|
||||||
|
.value
|
||||||
|
}
|
||||||
|
></Dropdown>
|
||||||
|
</div>
|
||||||
|
) : t.data.node.template[n].type ===
|
||||||
|
"int" ? (
|
||||||
|
<div className="mx-auto">
|
||||||
|
<IntComponent
|
||||||
|
disabled={false}
|
||||||
|
editNode={true}
|
||||||
|
value={
|
||||||
|
!t.data.node.template[n]
|
||||||
|
.value ||
|
||||||
|
t.data.node.template[n]
|
||||||
|
.value === ""
|
||||||
|
? ""
|
||||||
|
: t.data.node.template[n]
|
||||||
|
.value
|
||||||
|
}
|
||||||
|
onChange={(k) => {
|
||||||
|
setData((old) => {
|
||||||
|
let newInputList =
|
||||||
|
cloneDeep(old);
|
||||||
|
newInputList[
|
||||||
|
index
|
||||||
|
].data.node.template[
|
||||||
|
n
|
||||||
|
].value = k;
|
||||||
|
return newInputList;
|
||||||
|
});
|
||||||
|
tweaks.buildTweakObject(
|
||||||
|
t["data"]["id"],
|
||||||
|
k,
|
||||||
|
t.data.node.template[n]
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : t.data.node.template[n].type ===
|
||||||
|
"prompt" ? (
|
||||||
|
<ShadTooltip
|
||||||
|
content={tweaks.buildContent(
|
||||||
|
!t.data.node.template[n]
|
||||||
|
.value ||
|
||||||
|
t.data.node.template[n]
|
||||||
|
.value === ""
|
||||||
|
? ""
|
||||||
|
: t.data.node.template[n]
|
||||||
|
.value
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="mx-auto">
|
||||||
|
<PromptAreaComponent
|
||||||
|
editNode={true}
|
||||||
|
disabled={false}
|
||||||
|
value={
|
||||||
|
!t.data.node.template[n]
|
||||||
|
.value ||
|
||||||
|
t.data.node.template[n]
|
||||||
|
.value === ""
|
||||||
|
? ""
|
||||||
|
: t.data.node.template[
|
||||||
|
n
|
||||||
|
].value
|
||||||
|
}
|
||||||
|
onChange={(k) => {
|
||||||
|
setData((old) => {
|
||||||
|
let newInputList =
|
||||||
|
cloneDeep(old);
|
||||||
|
newInputList[
|
||||||
|
index
|
||||||
|
].data.node.template[
|
||||||
|
n
|
||||||
|
].value = k;
|
||||||
|
return newInputList;
|
||||||
|
});
|
||||||
|
tweaks.buildTweakObject(
|
||||||
|
t["data"]["id"],
|
||||||
|
k,
|
||||||
|
t.data.node.template[n]
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ShadTooltip>
|
||||||
|
) : t.data.node.template[n].type ===
|
||||||
|
"code" ? (
|
||||||
|
<ShadTooltip
|
||||||
|
content={tweaks.buildContent(
|
||||||
|
tweaks.getValue(
|
||||||
|
t.data.node.template[n]
|
||||||
|
.value,
|
||||||
|
t.data,
|
||||||
|
t.data.node.template[n]
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="mx-auto">
|
||||||
|
<CodeAreaComponent
|
||||||
|
disabled={false}
|
||||||
|
editNode={true}
|
||||||
|
value={
|
||||||
|
!t.data.node.template[n]
|
||||||
|
.value ||
|
||||||
|
t.data.node.template[n]
|
||||||
|
.value === ""
|
||||||
|
? ""
|
||||||
|
: t.data.node.template[
|
||||||
|
n
|
||||||
|
].value
|
||||||
|
}
|
||||||
|
onChange={(k) => {
|
||||||
|
setData((old) => {
|
||||||
|
let newInputList =
|
||||||
|
cloneDeep(old);
|
||||||
|
newInputList[
|
||||||
|
index
|
||||||
|
].data.node.template[
|
||||||
|
n
|
||||||
|
].value = k;
|
||||||
|
return newInputList;
|
||||||
|
});
|
||||||
|
tweaks.buildTweakObject(
|
||||||
|
t["data"]["id"],
|
||||||
|
k,
|
||||||
|
t.data.node.template[n]
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ShadTooltip>
|
||||||
|
) : t.data.node.template[n].type ===
|
||||||
|
"Any" ? (
|
||||||
|
"-"
|
||||||
|
) : (
|
||||||
|
<div className="hidden"></div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</AccordionComponent>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{tweaks.tweaksList.current.length === 0 && (
|
||||||
|
<>
|
||||||
|
<div className="pt-3">
|
||||||
|
No tweaks are available for this flow.
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
</TabsContent>
|
||||||
|
))}
|
||||||
|
</Tabs>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { Listbox, Transition } from "@headlessui/react";
|
import { Listbox, Transition } from "@headlessui/react";
|
||||||
import { Fragment, useContext, useEffect, useState } from "react";
|
import { Fragment, useEffect, useState } from "react";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import { DropDownComponentType } from "../../types/components";
|
import { DropDownComponentType } from "../../types/components";
|
||||||
import { classNames } from "../../utils/utils";
|
import { classNames } from "../../utils/utils";
|
||||||
import IconComponent from "../genericIconComponent";
|
import IconComponent from "../genericIconComponent";
|
||||||
|
|
@ -13,15 +12,13 @@ export default function Dropdown({
|
||||||
numberOfOptions = 0,
|
numberOfOptions = 0,
|
||||||
apiModal = false,
|
apiModal = false,
|
||||||
}: DropDownComponentType) {
|
}: DropDownComponentType) {
|
||||||
const { closePopUp } = useContext(PopUpContext);
|
|
||||||
|
|
||||||
let [internalValue, setInternalValue] = useState(
|
let [internalValue, setInternalValue] = useState(
|
||||||
value === "" || !value ? "Choose an option" : value
|
value === "" || !value ? "Choose an option" : value
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setInternalValue(value === "" || !value ? "Choose an option" : value);
|
setInternalValue(value === "" || !value ? "Choose an option" : value);
|
||||||
}, [closePopUp]);
|
}, [value]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,12 @@
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useEffect } from "react";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
|
||||||
import { FloatComponentType } from "../../types/components";
|
import { FloatComponentType } from "../../types/components";
|
||||||
|
|
||||||
export default function FloatComponent({
|
export default function FloatComponent({
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
disableCopyPaste = false,
|
|
||||||
disabled,
|
disabled,
|
||||||
editNode = false,
|
editNode = false,
|
||||||
}: FloatComponentType) {
|
}: FloatComponentType) {
|
||||||
const [myValue, setMyValue] = useState(value ?? "");
|
|
||||||
const { setDisableCopyPaste } = useContext(TabsContext);
|
|
||||||
const { closePopUp } = useContext(PopUpContext);
|
|
||||||
|
|
||||||
const step = 0.1;
|
const step = 0.1;
|
||||||
const min = 0;
|
const min = 0;
|
||||||
const max = 1;
|
const max = 1;
|
||||||
|
|
@ -21,24 +14,13 @@ export default function FloatComponent({
|
||||||
// Clear component state
|
// Clear component state
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
setMyValue("");
|
|
||||||
onChange("");
|
onChange("");
|
||||||
}
|
}
|
||||||
}, [disabled, onChange]);
|
}, [disabled, onChange]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setMyValue(value);
|
|
||||||
}, [closePopUp]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={"w-full " + (disabled ? "float-component-pointer" : "")}>
|
<div className={"w-full " + (disabled ? "float-component-pointer" : "")}>
|
||||||
<input
|
<input
|
||||||
onFocus={() => {
|
|
||||||
if (disableCopyPaste) setDisableCopyPaste(true);
|
|
||||||
}}
|
|
||||||
onBlur={() => {
|
|
||||||
if (disableCopyPaste) setDisableCopyPaste(false);
|
|
||||||
}}
|
|
||||||
type="number"
|
type="number"
|
||||||
step={step}
|
step={step}
|
||||||
min={min}
|
min={min}
|
||||||
|
|
@ -51,17 +33,17 @@ export default function FloatComponent({
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
max={max}
|
max={max}
|
||||||
value={myValue}
|
value={value ?? ""}
|
||||||
className={
|
className={
|
||||||
editNode
|
"nopan nodrag noundo nocopy " +
|
||||||
|
(editNode
|
||||||
? "input-edit-node"
|
? "input-edit-node"
|
||||||
: "input-primary" + (disabled ? " input-disable " : "")
|
: "input-primary" + (disabled ? " input-disable " : ""))
|
||||||
}
|
}
|
||||||
placeholder={
|
placeholder={
|
||||||
editNode ? "Number 0 to 1" : "Type a number from zero to one"
|
editNode ? "Number 0 to 1" : "Type a number from zero to one"
|
||||||
}
|
}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setMyValue(e.target.value);
|
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { useContext } from "react";
|
import { useContext, useState } from "react";
|
||||||
import { PopUpContext } from "../../../../contexts/popUpContext";
|
|
||||||
import { TabsContext } from "../../../../contexts/tabsContext";
|
import { TabsContext } from "../../../../contexts/tabsContext";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
|
|
@ -17,10 +16,10 @@ import IconComponent from "../../../genericIconComponent";
|
||||||
import { Button } from "../../../ui/button";
|
import { Button } from "../../../ui/button";
|
||||||
|
|
||||||
export const MenuBar = ({ flows, tabId }) => {
|
export const MenuBar = ({ flows, tabId }) => {
|
||||||
const { updateFlow, setTabId, addFlow } = useContext(TabsContext);
|
const { addFlow } = useContext(TabsContext);
|
||||||
const { setErrorData } = useContext(alertContext);
|
const { setErrorData } = useContext(alertContext);
|
||||||
const { openPopUp } = useContext(PopUpContext);
|
|
||||||
const { undo, redo } = useContext(undoRedoContext);
|
const { undo, redo } = useContext(undoRedoContext);
|
||||||
|
const [openSettings, setOpenSettings] = useState(false);
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
|
@ -62,9 +61,10 @@ export const MenuBar = ({ flows, tabId }) => {
|
||||||
<IconComponent name="Plus" className="header-menu-options" />
|
<IconComponent name="Plus" className="header-menu-options" />
|
||||||
New
|
New
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openPopUp(<FlowSettingsModal />);
|
setOpenSettings(true);
|
||||||
}}
|
}}
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
>
|
>
|
||||||
|
|
@ -74,6 +74,7 @@ export const MenuBar = ({ flows, tabId }) => {
|
||||||
/>
|
/>
|
||||||
Settings
|
Settings
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
undo();
|
undo();
|
||||||
|
|
@ -94,6 +95,10 @@ export const MenuBar = ({ flows, tabId }) => {
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
<FlowSettingsModal
|
||||||
|
open={openSettings}
|
||||||
|
setOpen={setOpenSettings}
|
||||||
|
></FlowSettingsModal>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,56 +1,37 @@
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
|
||||||
import { InputComponentType } from "../../types/components";
|
import { InputComponentType } from "../../types/components";
|
||||||
import { classNames } from "../../utils/utils";
|
import { classNames } from "../../utils/utils";
|
||||||
|
|
||||||
export default function InputComponent({
|
export default function InputComponent({
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
disableCopyPaste = false,
|
|
||||||
disabled,
|
disabled,
|
||||||
password,
|
password,
|
||||||
editNode = false,
|
editNode = false,
|
||||||
}: InputComponentType) {
|
}: InputComponentType) {
|
||||||
const [myValue, setMyValue] = useState(value ?? "");
|
|
||||||
const [pwdVisible, setPwdVisible] = useState(false);
|
const [pwdVisible, setPwdVisible] = useState(false);
|
||||||
const { setDisableCopyPaste } = useContext(TabsContext);
|
|
||||||
const { closePopUp } = useContext(PopUpContext);
|
|
||||||
|
|
||||||
// Clear component state
|
// Clear component state
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
setMyValue("");
|
|
||||||
onChange("");
|
onChange("");
|
||||||
}
|
}
|
||||||
}, [disabled, onChange]);
|
}, [disabled, onChange]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setMyValue(value ?? "");
|
|
||||||
}, [closePopUp]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={disabled ? "input-component-div" : "relative"}>
|
<div className={disabled ? "input-component-div" : "relative"}>
|
||||||
<input
|
<input
|
||||||
value={myValue}
|
value={value}
|
||||||
onFocus={() => {
|
|
||||||
if (disableCopyPaste) setDisableCopyPaste(true);
|
|
||||||
}}
|
|
||||||
onBlur={() => {
|
|
||||||
if (disableCopyPaste) setDisableCopyPaste(false);
|
|
||||||
}}
|
|
||||||
className={classNames(
|
className={classNames(
|
||||||
disabled ? " input-disable " : "",
|
disabled ? " input-disable " : "",
|
||||||
password && !pwdVisible && myValue !== ""
|
password && !pwdVisible && value !== "" ? " text-clip password " : "",
|
||||||
? " text-clip password "
|
|
||||||
: "",
|
|
||||||
editNode ? " input-edit-node " : " input-primary ",
|
editNode ? " input-edit-node " : " input-primary ",
|
||||||
password && editNode ? "pr-8" : "",
|
password && editNode ? "pr-8" : "",
|
||||||
password && !editNode ? "pr-10" : ""
|
password && !editNode ? "pr-10" : "",
|
||||||
|
"nopan nodrag noundo nocopy"
|
||||||
)}
|
)}
|
||||||
placeholder={password && editNode ? "Key" : "Type something..."}
|
placeholder={password && editNode ? "Key" : "Type something..."}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setMyValue(e.target.value);
|
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useEffect } from "react";
|
||||||
import { InputListComponentType } from "../../types/components";
|
import { InputListComponentType } from "../../types/components";
|
||||||
|
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import IconComponent from "../genericIconComponent";
|
import IconComponent from "../genericIconComponent";
|
||||||
|
|
||||||
export default function InputListComponent({
|
export default function InputListComponent({
|
||||||
|
|
@ -10,21 +9,12 @@ export default function InputListComponent({
|
||||||
onChange,
|
onChange,
|
||||||
disabled,
|
disabled,
|
||||||
editNode = false,
|
editNode = false,
|
||||||
onAddInput,
|
|
||||||
}: InputListComponentType) {
|
}: InputListComponentType) {
|
||||||
const [inputList, setInputList] = useState(value ?? [""]);
|
|
||||||
const { closePopUp } = useContext(PopUpContext);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
setInputList([""]);
|
|
||||||
onChange([""]);
|
onChange([""]);
|
||||||
}
|
}
|
||||||
}, [disabled, onChange]);
|
}, [disabled]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setInputList(value);
|
|
||||||
}, [closePopUp]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
@ -33,36 +23,31 @@ export default function InputListComponent({
|
||||||
"flex flex-col gap-3"
|
"flex flex-col gap-3"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{inputList.map((i, idx) => {
|
{value.map((i, idx) => {
|
||||||
return (
|
return (
|
||||||
<div key={idx} className="flex w-full gap-3">
|
<div key={idx} className="flex w-full gap-3">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={i}
|
value={i}
|
||||||
className={
|
className={
|
||||||
editNode
|
"nopan nodrag noundo nocopy " +
|
||||||
|
(editNode
|
||||||
? "input-edit-node "
|
? "input-edit-node "
|
||||||
: "input-primary " + (disabled ? "input-disable" : "")
|
: "input-primary " + (disabled ? "input-disable" : ""))
|
||||||
}
|
}
|
||||||
placeholder="Type something..."
|
placeholder="Type something..."
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setInputList((old) => {
|
let newInputList = _.cloneDeep(value);
|
||||||
let newInputList = _.cloneDeep(old);
|
|
||||||
newInputList[idx] = e.target.value;
|
newInputList[idx] = e.target.value;
|
||||||
return newInputList;
|
onChange(newInputList);
|
||||||
});
|
|
||||||
onChange(inputList);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{idx === inputList.length - 1 ? (
|
{idx === value.length - 1 ? (
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setInputList((old) => {
|
let newInputList = _.cloneDeep(value);
|
||||||
let newInputList = _.cloneDeep(old);
|
|
||||||
newInputList.push("");
|
newInputList.push("");
|
||||||
return newInputList;
|
onChange(newInputList);
|
||||||
});
|
|
||||||
onChange(inputList);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
|
|
@ -73,12 +58,9 @@ export default function InputListComponent({
|
||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setInputList((old) => {
|
let newInputList = _.cloneDeep(value);
|
||||||
let newInputList = _.cloneDeep(old);
|
|
||||||
newInputList.splice(idx, 1);
|
newInputList.splice(idx, 1);
|
||||||
return newInputList;
|
onChange(newInputList);
|
||||||
});
|
|
||||||
onChange(inputList);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,21 @@
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useEffect } from "react";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
|
||||||
import { FloatComponentType } from "../../types/components";
|
import { FloatComponentType } from "../../types/components";
|
||||||
|
|
||||||
export default function IntComponent({
|
export default function IntComponent({
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
disableCopyPaste = false,
|
|
||||||
disabled,
|
disabled,
|
||||||
editNode = false,
|
editNode = false,
|
||||||
}: FloatComponentType) {
|
}: FloatComponentType) {
|
||||||
const [myValue, setMyValue] = useState(value ?? "");
|
|
||||||
const { setDisableCopyPaste } = useContext(TabsContext);
|
|
||||||
const min = 0;
|
const min = 0;
|
||||||
const { closePopUp } = useContext(PopUpContext);
|
|
||||||
|
|
||||||
// Clear component state
|
// Clear component state
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
setMyValue("");
|
|
||||||
onChange("");
|
onChange("");
|
||||||
}
|
}
|
||||||
}, [disabled, onChange]);
|
}, [disabled, onChange]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setMyValue(value);
|
|
||||||
}, [closePopUp]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
|
|
@ -35,12 +24,6 @@ export default function IntComponent({
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
onFocus={() => {
|
|
||||||
if (disableCopyPaste) setDisableCopyPaste(true);
|
|
||||||
}}
|
|
||||||
onBlur={() => {
|
|
||||||
if (disableCopyPaste) setDisableCopyPaste(false);
|
|
||||||
}}
|
|
||||||
onKeyDown={(event) => {
|
onKeyDown={(event) => {
|
||||||
if (
|
if (
|
||||||
event.key !== "Backspace" &&
|
event.key !== "Backspace" &&
|
||||||
|
|
@ -67,15 +50,15 @@ export default function IntComponent({
|
||||||
e.target.value = min.toString();
|
e.target.value = min.toString();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
value={myValue}
|
value={value ?? ""}
|
||||||
className={
|
className={
|
||||||
editNode
|
"nopan nodrag noundo nocopy " +
|
||||||
|
(editNode
|
||||||
? " input-edit-node "
|
? " input-edit-node "
|
||||||
: " input-primary " + (disabled ? " input-disable" : "")
|
: " input-primary " + (disabled ? " input-disable" : ""))
|
||||||
}
|
}
|
||||||
placeholder={editNode ? "Integer number" : "Type an integer number"}
|
placeholder={editNode ? "Integer number" : "Type an integer number"}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setMyValue(e.target.value);
|
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
import { TypeModal } from "../../constants/enums";
|
import { TypeModal } from "../../constants/enums";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import { typesContext } from "../../contexts/typesContext";
|
|
||||||
import { postValidatePrompt } from "../../controllers/API";
|
import { postValidatePrompt } from "../../controllers/API";
|
||||||
import GenericModal from "../../modals/genericModal";
|
import GenericModal from "../../modals/genericModal";
|
||||||
import { TextAreaComponentType } from "../../types/components";
|
import { TextAreaComponentType } from "../../types/components";
|
||||||
|
|
@ -17,18 +15,13 @@ export default function PromptAreaComponent({
|
||||||
disabled,
|
disabled,
|
||||||
editNode = false,
|
editNode = false,
|
||||||
}: TextAreaComponentType) {
|
}: TextAreaComponentType) {
|
||||||
const [myValue, setMyValue] = useState(value);
|
|
||||||
const { openPopUp } = useContext(PopUpContext);
|
|
||||||
const { reactFlowInstance } = useContext(typesContext);
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
setMyValue("");
|
|
||||||
onChange("");
|
onChange("");
|
||||||
}
|
}
|
||||||
}, [disabled, onChange]);
|
}, [disabled]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMyValue(value);
|
|
||||||
if (value !== "" && !editNode) {
|
if (value !== "" && !editNode) {
|
||||||
postValidatePrompt(field_name, value, nodeClass).then((apiReturn) => {
|
postValidatePrompt(field_name, value, nodeClass).then((apiReturn) => {
|
||||||
if (apiReturn.data) {
|
if (apiReturn.data) {
|
||||||
|
|
@ -37,28 +30,23 @@ export default function PromptAreaComponent({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [value, reactFlowInstance]);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={disabled ? "pointer-events-none w-full " : " w-full"}>
|
<div className={disabled ? "pointer-events-none w-full " : " w-full"}>
|
||||||
<div className="flex w-full items-center">
|
|
||||||
<span
|
|
||||||
onClick={() => {
|
|
||||||
openPopUp(
|
|
||||||
<GenericModal
|
<GenericModal
|
||||||
type={TypeModal.PROMPT}
|
type={TypeModal.PROMPT}
|
||||||
value={myValue}
|
value={value}
|
||||||
buttonText="Check & Save"
|
buttonText="Check & Save"
|
||||||
modalTitle="Edit Prompt"
|
modalTitle="Edit Prompt"
|
||||||
setValue={(t: string) => {
|
setValue={(t: string) => {
|
||||||
setMyValue(t);
|
|
||||||
onChange(t);
|
onChange(t);
|
||||||
}}
|
}}
|
||||||
nodeClass={nodeClass}
|
nodeClass={nodeClass}
|
||||||
setNodeClass={setNodeClass}
|
setNodeClass={setNodeClass}
|
||||||
/>
|
>
|
||||||
);
|
<div className="flex w-full items-center">
|
||||||
}}
|
<span
|
||||||
className={
|
className={
|
||||||
editNode
|
editNode
|
||||||
? "input-edit-node input-dialog"
|
? "input-edit-node input-dialog"
|
||||||
|
|
@ -66,27 +54,8 @@ export default function PromptAreaComponent({
|
||||||
" input-primary text-muted-foreground "
|
" input-primary text-muted-foreground "
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{myValue !== "" ? myValue : "Type your prompt here"}
|
{value !== "" ? value : "Type your prompt here..."}
|
||||||
</span>
|
</span>
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
openPopUp(
|
|
||||||
<GenericModal
|
|
||||||
field_name={field_name}
|
|
||||||
type={TypeModal.PROMPT}
|
|
||||||
value={myValue}
|
|
||||||
buttonText="Check & Save"
|
|
||||||
modalTitle="Edit Prompt"
|
|
||||||
setValue={(t: string) => {
|
|
||||||
setMyValue(t);
|
|
||||||
onChange(t);
|
|
||||||
}}
|
|
||||||
nodeClass={nodeClass}
|
|
||||||
setNodeClass={setNodeClass}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{!editNode && (
|
{!editNode && (
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="ExternalLink"
|
name="ExternalLink"
|
||||||
|
|
@ -96,8 +65,8 @@ export default function PromptAreaComponent({
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
</GenericModal>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useEffect } from "react";
|
||||||
import { TypeModal } from "../../constants/enums";
|
import { TypeModal } from "../../constants/enums";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
|
||||||
import GenericModal from "../../modals/genericModal";
|
import GenericModal from "../../modals/genericModal";
|
||||||
import { TextAreaComponentType } from "../../types/components";
|
import { TextAreaComponentType } from "../../types/components";
|
||||||
import IconComponent from "../genericIconComponent";
|
import IconComponent from "../genericIconComponent";
|
||||||
|
|
@ -12,60 +10,38 @@ export default function TextAreaComponent({
|
||||||
disabled,
|
disabled,
|
||||||
editNode = false,
|
editNode = false,
|
||||||
}: TextAreaComponentType) {
|
}: TextAreaComponentType) {
|
||||||
const [myValue, setMyValue] = useState(value);
|
|
||||||
const { openPopUp, closePopUp } = useContext(PopUpContext);
|
|
||||||
const { setDisableCopyPaste } = useContext(TabsContext);
|
|
||||||
|
|
||||||
// Clear text area
|
// Clear text area
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
setMyValue("");
|
|
||||||
onChange("");
|
onChange("");
|
||||||
}
|
}
|
||||||
}, [disabled, onChange]);
|
}, [disabled]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setMyValue(value);
|
|
||||||
}, [closePopUp]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={disabled ? "pointer-events-none w-full " : " w-full"}>
|
<div className={disabled ? "pointer-events-none w-full " : " w-full"}>
|
||||||
<div className="flex w-full items-center">
|
<div className="flex w-full items-center">
|
||||||
<input
|
<input
|
||||||
value={myValue}
|
value={value}
|
||||||
onFocus={() => {
|
|
||||||
setDisableCopyPaste(true);
|
|
||||||
}}
|
|
||||||
onBlur={() => {
|
|
||||||
setDisableCopyPaste(false);
|
|
||||||
}}
|
|
||||||
className={
|
className={
|
||||||
editNode
|
(editNode
|
||||||
? " input-edit-node "
|
? " input-edit-node "
|
||||||
: " input-primary " + (disabled ? " input-disable" : "")
|
: " input-primary " + (disabled ? " input-disable" : "")) +
|
||||||
|
" nopan nodrag noundo nocopy w-full"
|
||||||
}
|
}
|
||||||
placeholder={"Type something..."}
|
placeholder={"Type something..."}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setMyValue(e.target.value);
|
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<div>
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
openPopUp(
|
|
||||||
<GenericModal
|
<GenericModal
|
||||||
type={TypeModal.TEXT}
|
type={TypeModal.TEXT}
|
||||||
buttonText="Finishing Editing"
|
buttonText="Finishing Editing"
|
||||||
modalTitle="Edit Text"
|
modalTitle="Edit Text"
|
||||||
value={myValue}
|
value={value}
|
||||||
setValue={(t: string) => {
|
setValue={(t: string) => {
|
||||||
setMyValue(t);
|
|
||||||
onChange(t);
|
onChange(t);
|
||||||
}}
|
}}
|
||||||
/>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{!editNode && (
|
{!editNode && (
|
||||||
<IconComponent
|
<IconComponent
|
||||||
|
|
@ -76,7 +52,8 @@ export default function TextAreaComponent({
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</button>
|
</GenericModal>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ export default function ToggleShadComponent({
|
||||||
scaleX = 1;
|
scaleX = 1;
|
||||||
scaleY = 1;
|
scaleY = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={disabled ? "pointer-events-none cursor-not-allowed " : ""}>
|
<div className={disabled ? "pointer-events-none cursor-not-allowed " : ""}>
|
||||||
<Switch
|
<Switch
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ const DialogContent = React.forwardRef<
|
||||||
<DialogPrimitive.Content
|
<DialogPrimitive.Content
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed z-50 grid w-full gap-3 rounded-b-lg border bg-background p-6 shadow-lg animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0",
|
"noundo nocopy fixed z-50 flex w-full flex-col gap-3 rounded-b-lg border bg-background p-6 shadow-lg animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
@ -116,10 +116,10 @@ DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogTrigger,
|
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogHeader,
|
|
||||||
DialogFooter,
|
|
||||||
DialogTitle,
|
|
||||||
DialogDescription,
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||||
<input
|
<input
|
||||||
type={type}
|
type={type}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-10 w-full 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 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
"nopan nodrag noundo nocopy flex h-10 w-full 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 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ export default function RenameLabel(props) {
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
onInput={resizeInput}
|
onInput={resizeInput}
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-md bg-transparent px-2 outline-ring hover:outline focus:border-none focus:outline active:outline",
|
"nopan nodrag noundo nocopy rounded-md bg-transparent px-2 outline-ring hover:outline focus:border-none focus:outline active:outline",
|
||||||
props.className
|
props.className
|
||||||
)}
|
)}
|
||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ const TabsList = React.forwardRef<
|
||||||
<TabsPrimitive.List
|
<TabsPrimitive.List
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
|
"inline-flex h-10 items-center justify-center rounded-md p-1 text-muted-foreground",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
@ -51,4 +51,4 @@ const TabsContent = React.forwardRef<
|
||||||
));
|
));
|
||||||
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
||||||
|
|
||||||
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
export { Tabs, TabsContent, TabsList, TabsTrigger };
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,6 @@ const TabsContextInitialValue: TabsContextType = {
|
||||||
uploadFlow: () => {},
|
uploadFlow: () => {},
|
||||||
hardReset: () => {},
|
hardReset: () => {},
|
||||||
saveFlow: async (flow: FlowType) => {},
|
saveFlow: async (flow: FlowType) => {},
|
||||||
disableCopyPaste: false,
|
|
||||||
setDisableCopyPaste: (state: boolean) => {},
|
|
||||||
lastCopiedSelection: null,
|
lastCopiedSelection: null,
|
||||||
setLastCopiedSelection: (selection: any) => {},
|
setLastCopiedSelection: (selection: any) => {},
|
||||||
tabsState: {},
|
tabsState: {},
|
||||||
|
|
@ -585,16 +583,12 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const [disableCopyPaste, setDisableCopyPaste] = useState(false);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TabsContext.Provider
|
<TabsContext.Provider
|
||||||
value={{
|
value={{
|
||||||
saveFlow,
|
saveFlow,
|
||||||
lastCopiedSelection,
|
lastCopiedSelection,
|
||||||
setLastCopiedSelection,
|
setLastCopiedSelection,
|
||||||
disableCopyPaste,
|
|
||||||
setDisableCopyPaste,
|
|
||||||
hardReset,
|
hardReset,
|
||||||
tabId,
|
tabId,
|
||||||
setTabId,
|
setTabId,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import {
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { Edge, Node, useReactFlow } from "reactflow";
|
import { Edge, Node, useReactFlow } from "reactflow";
|
||||||
|
import { isWrappedWithClass } from "../utils/utils";
|
||||||
import { TabsContext } from "./tabsContext";
|
import { TabsContext } from "./tabsContext";
|
||||||
|
|
||||||
type undoRedoContextType = {
|
type undoRedoContextType = {
|
||||||
|
|
@ -20,14 +21,6 @@ type UseUndoRedoOptions = {
|
||||||
enableShortcuts: boolean;
|
enableShortcuts: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type UseUndoRedo = (options?: UseUndoRedoOptions) => {
|
|
||||||
undo: () => void;
|
|
||||||
redo: () => void;
|
|
||||||
takeSnapshot: () => void;
|
|
||||||
canUndo: boolean;
|
|
||||||
canRedo: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
type HistoryItem = {
|
type HistoryItem = {
|
||||||
nodes: Node[];
|
nodes: Node[];
|
||||||
edges: Edge[];
|
edges: Edge[];
|
||||||
|
|
@ -156,18 +149,22 @@ export function UndoRedoProvider({ children }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyDownHandler = (event: KeyboardEvent) => {
|
const keyDownHandler = (event: KeyboardEvent) => {
|
||||||
|
if (!isWrappedWithClass(event, "noundo")) {
|
||||||
if (
|
if (
|
||||||
event.key === "z" &&
|
event.key === "z" &&
|
||||||
(event.ctrlKey || event.metaKey) &&
|
(event.ctrlKey || event.metaKey) &&
|
||||||
event.shiftKey
|
event.shiftKey
|
||||||
) {
|
) {
|
||||||
|
event.preventDefault();
|
||||||
redo();
|
redo();
|
||||||
} else if (event.key === "y" && (event.ctrlKey || event.metaKey)) {
|
} else if (event.key === "y" && (event.ctrlKey || event.metaKey)) {
|
||||||
event.preventDefault(); // prevent the default action
|
event.preventDefault(); // prevent the default action
|
||||||
redo();
|
redo();
|
||||||
} else if (event.key === "z" && (event.ctrlKey || event.metaKey)) {
|
} else if (event.key === "z" && (event.ctrlKey || event.metaKey)) {
|
||||||
|
event.preventDefault();
|
||||||
undo();
|
undo();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener("keydown", keyDownHandler);
|
document.addEventListener("keydown", keyDownHandler);
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,9 @@ code {
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
||||||
monospace;
|
monospace;
|
||||||
}
|
}
|
||||||
|
pre {
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
/* The style below sets the cursor property of the element with the class .react-flow__pane to the default cursor.
|
/* The style below sets the cursor property of the element with the class .react-flow__pane to the default cursor.
|
||||||
The cursor: default; property value restores the browser's default cursor style for the targeted element. By applying this style, the element will no longer have a custom cursor appearance such as "grab" or any other custom cursor defined elsewhere in the application. Instead, it will revert to the default cursor style determined by the browser, typically an arrow-shaped cursor. */
|
The cursor: default; property value restores the browser's default cursor style for the targeted element. By applying this style, the element will no longer have a custom cursor appearance such as "grab" or any other custom cursor defined elsewhere in the application. Instead, it will revert to the default cursor style determined by the browser, typically an arrow-shaped cursor. */
|
||||||
|
|
@ -240,11 +243,11 @@ The cursor: default; property value restores the browser's default cursor style
|
||||||
@apply focus:placeholder-transparent focus:ring-ring focus:border-ring
|
@apply focus:placeholder-transparent focus:ring-ring focus:border-ring
|
||||||
}
|
}
|
||||||
.input-primary {
|
.input-primary {
|
||||||
@apply bg-background block border-border form-input px-3 placeholder:text-muted-foreground rounded-md shadow-sm sm:text-sm truncate w-full;
|
@apply bg-background block text-left border-border form-input px-3 placeholder:text-muted-foreground rounded-md shadow-sm sm:text-sm truncate w-full;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-edit-node{
|
.input-edit-node{
|
||||||
@apply input-primary border-border placeholder:text-center pt-0.5 pb-0.5 text-center
|
@apply input-primary border-border pt-0.5 pb-0.5 text-left w-full
|
||||||
}
|
}
|
||||||
.input-search{
|
.input-search{
|
||||||
@apply input-primary pr-7 mx-2
|
@apply input-primary pr-7 mx-2
|
||||||
|
|
@ -547,7 +550,7 @@ The cursor: default; property value restores the browser's default cursor style
|
||||||
@apply z-10 mt-1 max-h-60 overflow-auto rounded-md bg-background py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm
|
@apply z-10 mt-1 max-h-60 overflow-auto rounded-md bg-background py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm
|
||||||
}
|
}
|
||||||
.dropdown-component-true-options {
|
.dropdown-component-true-options {
|
||||||
@apply dropdown-component-options w-[215px]
|
@apply dropdown-component-options lg:w-[32%]
|
||||||
}
|
}
|
||||||
.dropdown-component-false-options {
|
.dropdown-component-false-options {
|
||||||
@apply dropdown-component-options w-full
|
@apply dropdown-component-options w-full
|
||||||
|
|
@ -932,7 +935,7 @@ The cursor: default; property value restores the browser's default cursor style
|
||||||
}
|
}
|
||||||
|
|
||||||
.api-modal-tabs {
|
.api-modal-tabs {
|
||||||
@apply w-full h-full overflow-hidden text-center bg-muted rounded-md border
|
@apply lg:w-full h-full flex flex-col overflow-hidden text-center bg-muted rounded-md border sm:w-[75vw]
|
||||||
}
|
}
|
||||||
.api-modal-tablist-div {
|
.api-modal-tablist-div {
|
||||||
@apply flex items-center justify-between px-2
|
@apply flex items-center justify-between px-2
|
||||||
|
|
|
||||||
|
|
@ -2,90 +2,54 @@ import "ace-builds/src-noconflict/ext-language_tools";
|
||||||
import "ace-builds/src-noconflict/mode-python";
|
import "ace-builds/src-noconflict/mode-python";
|
||||||
import "ace-builds/src-noconflict/theme-github";
|
import "ace-builds/src-noconflict/theme-github";
|
||||||
import "ace-builds/src-noconflict/theme-twilight";
|
import "ace-builds/src-noconflict/theme-twilight";
|
||||||
import { Check, Clipboard } from "lucide-react";
|
import {
|
||||||
import { useContext, useEffect, useRef, useState } from "react";
|
ReactNode,
|
||||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
forwardRef,
|
||||||
import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
|
useContext,
|
||||||
import AccordionComponent from "../../components/AccordionComponent";
|
useEffect,
|
||||||
import ShadTooltip from "../../components/ShadTooltipComponent";
|
useRef,
|
||||||
import CodeAreaComponent from "../../components/codeAreaComponent";
|
useState,
|
||||||
import Dropdown from "../../components/dropdownComponent";
|
} from "react";
|
||||||
import FloatComponent from "../../components/floatComponent";
|
// import "ace-builds/webpack-resolver";
|
||||||
|
import CodeTabsComponent from "../../components/codeTabsComponent";
|
||||||
import IconComponent from "../../components/genericIconComponent";
|
import IconComponent from "../../components/genericIconComponent";
|
||||||
import InputComponent from "../../components/inputComponent";
|
|
||||||
import InputFileComponent from "../../components/inputFileComponent";
|
|
||||||
import InputListComponent from "../../components/inputListComponent";
|
|
||||||
import IntComponent from "../../components/intComponent";
|
|
||||||
import PromptAreaComponent from "../../components/promptComponent";
|
|
||||||
import TextAreaComponent from "../../components/textAreaComponent";
|
|
||||||
import ToggleShadComponent from "../../components/toggleShadComponent";
|
|
||||||
import {
|
|
||||||
Dialog,
|
|
||||||
DialogContent,
|
|
||||||
DialogDescription,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
DialogTrigger,
|
|
||||||
} from "../../components/ui/dialog";
|
|
||||||
import {
|
|
||||||
Table,
|
|
||||||
TableBody,
|
|
||||||
TableCell,
|
|
||||||
TableHead,
|
|
||||||
TableHeader,
|
|
||||||
TableRow,
|
|
||||||
} from "../../components/ui/table";
|
|
||||||
import {
|
|
||||||
Tabs,
|
|
||||||
TabsContent,
|
|
||||||
TabsList,
|
|
||||||
TabsTrigger,
|
|
||||||
} from "../../components/ui/tabs";
|
|
||||||
import { EXPORT_CODE_DIALOG } from "../../constants/constants";
|
import { EXPORT_CODE_DIALOG } from "../../constants/constants";
|
||||||
import { darkContext } from "../../contexts/darkContext";
|
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
import { FlowType } from "../../types/flow/index";
|
import { FlowType } from "../../types/flow/index";
|
||||||
import { buildTweaks } from "../../utils/reactflowUtils";
|
import { buildTweaks } from "../../utils/reactflowUtils";
|
||||||
import {
|
import {
|
||||||
classNames,
|
|
||||||
getCurlCode,
|
getCurlCode,
|
||||||
getPythonApiCode,
|
getPythonApiCode,
|
||||||
getPythonCode,
|
getPythonCode,
|
||||||
} from "../../utils/utils";
|
} from "../../utils/utils";
|
||||||
export default function ApiModal({ flow }: { flow: FlowType }) {
|
import BaseModal from "../baseModal";
|
||||||
const [open, setOpen] = useState(true);
|
|
||||||
const { dark } = useContext(darkContext);
|
const ApiModal = forwardRef(
|
||||||
const { closePopUp, closeEdit, setCloseEdit } = useContext(PopUpContext);
|
(
|
||||||
|
{
|
||||||
|
flow,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
flow: FlowType;
|
||||||
|
children: ReactNode;
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
const [activeTab, setActiveTab] = useState("0");
|
const [activeTab, setActiveTab] = useState("0");
|
||||||
const [isCopied, setIsCopied] = useState<Boolean>(false);
|
|
||||||
const [enabled, setEnabled] = useState(null);
|
|
||||||
const [openAccordion, setOpenAccordion] = useState([]);
|
|
||||||
const tweak = useRef([]);
|
const tweak = useRef([]);
|
||||||
const tweaksList = useRef([]);
|
const tweaksList = useRef([]);
|
||||||
const { setTweak, getTweak, tabsState } = useContext(TabsContext);
|
const { setTweak, getTweak, tabsState } = useContext(TabsContext);
|
||||||
const copyToClipboard = () => {
|
|
||||||
if (!navigator.clipboard || !navigator.clipboard.writeText) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
navigator.clipboard.writeText(tabs[activeTab].code).then(() => {
|
|
||||||
setIsCopied(true);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
setIsCopied(false);
|
|
||||||
}, 2000);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const pythonApiCode = getPythonApiCode(flow, tweak.current, tabsState);
|
const pythonApiCode = getPythonApiCode(flow, tweak.current, tabsState);
|
||||||
const curl_code = getCurlCode(flow, tweak.current, tabsState);
|
const curl_code = getCurlCode(flow, tweak.current, tabsState);
|
||||||
const pythonCode = getPythonCode(flow, tweak.current, tabsState);
|
const pythonCode = getPythonCode(flow, tweak.current, tabsState);
|
||||||
const tweaksCode = buildTweaks(flow);
|
const tweaksCode = buildTweaks(flow);
|
||||||
const tabs = [
|
const [tabs, setTabs] = useState([
|
||||||
{
|
{
|
||||||
name: "cURL",
|
name: "cURL",
|
||||||
mode: "bash",
|
mode: "bash",
|
||||||
image: "https://curl.se/logo/curl-symbol-transparent.png",
|
image: "https://curl.se/logo/curl-symbol-transparent.png",
|
||||||
|
language: "sh",
|
||||||
code: curl_code,
|
code: curl_code,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -93,58 +57,95 @@ export default function ApiModal({ flow }: { flow: FlowType }) {
|
||||||
mode: "python",
|
mode: "python",
|
||||||
image:
|
image:
|
||||||
"https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w",
|
"https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w",
|
||||||
|
language: "py",
|
||||||
code: pythonApiCode,
|
code: pythonApiCode,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Python Code",
|
name: "Python Code",
|
||||||
mode: "python",
|
mode: "python",
|
||||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||||
|
language: "py",
|
||||||
code: pythonCode,
|
code: pythonCode,
|
||||||
},
|
},
|
||||||
];
|
]);
|
||||||
|
|
||||||
|
function startState() {
|
||||||
|
tweak.current = [];
|
||||||
|
setTweak([]);
|
||||||
|
tweaksList.current = [];
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (closeEdit !== "") {
|
if (flow["data"]["nodes"].length == 0) {
|
||||||
tweak.current = getTweak;
|
startState();
|
||||||
if (tweak.current.length > 0) {
|
|
||||||
setActiveTab("3");
|
|
||||||
openAccordions();
|
|
||||||
} else {
|
} else {
|
||||||
startTweaks();
|
tweak.current = [];
|
||||||
|
const t = buildTweaks(flow);
|
||||||
|
tweak.current.push(t);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (tweak?.current) {
|
|
||||||
startTweaks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [closeEdit]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
filterNodes();
|
filterNodes();
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (Object.keys(tweaksCode).length > 0) {
|
if (Object.keys(tweaksCode).length > 0) {
|
||||||
tabs.push({
|
setActiveTab("0");
|
||||||
|
setTabs([
|
||||||
|
{
|
||||||
|
name: "cURL",
|
||||||
|
mode: "bash",
|
||||||
|
image: "https://curl.se/logo/curl-symbol-transparent.png",
|
||||||
|
language: "sh",
|
||||||
|
code: curl_code,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Python API",
|
||||||
|
mode: "python",
|
||||||
|
image:
|
||||||
|
"https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w",
|
||||||
|
language: "py",
|
||||||
|
code: pythonApiCode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Python Code",
|
||||||
|
mode: "python",
|
||||||
|
language: "py",
|
||||||
|
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||||
|
code: pythonCode,
|
||||||
|
},
|
||||||
|
{
|
||||||
name: "Tweaks",
|
name: "Tweaks",
|
||||||
mode: "python",
|
mode: "python",
|
||||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||||
|
language: "py",
|
||||||
code: pythonCode,
|
code: pythonCode,
|
||||||
});
|
},
|
||||||
}
|
]);
|
||||||
|
} else {
|
||||||
function setModalOpen(x: boolean) {
|
setTabs([
|
||||||
setOpen(x);
|
{
|
||||||
if (x === false) {
|
name: "cURL",
|
||||||
setCloseEdit("");
|
mode: "bash",
|
||||||
setTweak([]);
|
image: "https://curl.se/logo/curl-symbol-transparent.png",
|
||||||
closePopUp();
|
language: "sh",
|
||||||
}
|
code: curl_code,
|
||||||
}
|
},
|
||||||
|
{
|
||||||
function startTweaks() {
|
name: "Python API",
|
||||||
const t = buildTweaks(flow);
|
mode: "python",
|
||||||
tweak?.current?.push(t);
|
image:
|
||||||
|
"https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w",
|
||||||
|
language: "py",
|
||||||
|
code: pythonApiCode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Python Code",
|
||||||
|
mode: "python",
|
||||||
|
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||||
|
language: "py",
|
||||||
|
code: pythonCode,
|
||||||
|
},
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
}, [flow["data"]["nodes"], open]);
|
||||||
|
|
||||||
function filterNodes() {
|
function filterNodes() {
|
||||||
let arrNodesWithValues = [];
|
let arrNodesWithValues = [];
|
||||||
|
|
@ -172,7 +173,6 @@ export default function ApiModal({ flow }: { flow: FlowType }) {
|
||||||
return self.indexOf(value) === index;
|
return self.indexOf(value) === index;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildTweakObject(tw, changes, template) {
|
function buildTweakObject(tw, changes, template) {
|
||||||
if (template.type === "float") {
|
if (template.type === "float") {
|
||||||
changes = parseFloat(changes);
|
changes = parseFloat(changes);
|
||||||
|
|
@ -252,482 +252,35 @@ export default function ApiModal({ flow }: { flow: FlowType }) {
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
function openAccordions() {
|
|
||||||
let accordionsToOpen = [];
|
|
||||||
tweak.current.forEach((el) => {
|
|
||||||
Object.keys(el).forEach((key) => {
|
|
||||||
if (Object.keys(el[key]).length > 0) {
|
|
||||||
accordionsToOpen.push(key);
|
|
||||||
setOpenAccordion(accordionsToOpen);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={true} onOpenChange={setModalOpen}>
|
<BaseModal open={open} setOpen={setOpen}>
|
||||||
<DialogTrigger></DialogTrigger>
|
<BaseModal.Trigger>{children}</BaseModal.Trigger>
|
||||||
<DialogContent className="h-[80vh] md:max-w-[80vw]">
|
<BaseModal.Header description={EXPORT_CODE_DIALOG}>
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle className="flex items-center">
|
|
||||||
<span className="pr-2">Code</span>
|
<span className="pr-2">Code</span>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="Code2"
|
name="Code2"
|
||||||
className="h-6 w-6 pl-1 text-gray-800 dark:text-white"
|
className="h-6 w-6 pl-1 text-gray-800 dark:text-white"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</DialogTitle>
|
</BaseModal.Header>
|
||||||
<DialogDescription>{EXPORT_CODE_DIALOG}</DialogDescription>
|
<BaseModal.Content>
|
||||||
</DialogHeader>
|
<CodeTabsComponent
|
||||||
|
flow={flow}
|
||||||
|
tabs={tabs}
|
||||||
|
activeTab={activeTab}
|
||||||
|
setActiveTab={setActiveTab}
|
||||||
|
tweaks={{
|
||||||
|
tweak,
|
||||||
|
tweaksList,
|
||||||
|
buildContent,
|
||||||
|
buildTweakObject,
|
||||||
|
getValue,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</BaseModal.Content>
|
||||||
|
</BaseModal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
<Tabs
|
export default ApiModal;
|
||||||
value={activeTab}
|
|
||||||
className="api-modal-tabs"
|
|
||||||
onValueChange={(value) => {
|
|
||||||
setActiveTab(value);
|
|
||||||
if (value === "3") {
|
|
||||||
openAccordions();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="api-modal-tablist-div">
|
|
||||||
<TabsList>
|
|
||||||
{tabs.map((tab, index) => (
|
|
||||||
<TabsTrigger key={index} value={index.toString()}>
|
|
||||||
{tab.name}
|
|
||||||
</TabsTrigger>
|
|
||||||
))}
|
|
||||||
</TabsList>
|
|
||||||
{Number(activeTab) < 3 && (
|
|
||||||
<div className="float-right">
|
|
||||||
<button
|
|
||||||
className="flex items-center gap-1.5 rounded bg-none p-1 text-xs text-gray-500 dark:text-gray-300"
|
|
||||||
onClick={copyToClipboard}
|
|
||||||
>
|
|
||||||
{isCopied ? <Check size={18} /> : <Clipboard size={15} />}
|
|
||||||
{isCopied ? "Copied!" : "Copy code"}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{tabs.map((tab, index) => (
|
|
||||||
<TabsContent
|
|
||||||
value={index.toString()}
|
|
||||||
className="api-modal-tabs-content"
|
|
||||||
key={index} // Remember to add a unique key prop
|
|
||||||
>
|
|
||||||
{index < 3 ? (
|
|
||||||
<SyntaxHighlighter
|
|
||||||
className="h-[60vh] w-full overflow-auto custom-scroll"
|
|
||||||
language={tab.mode}
|
|
||||||
style={oneDark}
|
|
||||||
>
|
|
||||||
{tab.code}
|
|
||||||
</SyntaxHighlighter>
|
|
||||||
) : index === 3 ? (
|
|
||||||
<>
|
|
||||||
<div className="api-modal-according-display">
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
"h-[60vh] w-full rounded-lg bg-muted",
|
|
||||||
1 == 1
|
|
||||||
? "overflow-scroll overflow-x-hidden custom-scroll"
|
|
||||||
: "overflow-hidden"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{flow["data"]["nodes"].map((t: any, index) => (
|
|
||||||
<div className="px-3" key={index}>
|
|
||||||
{tweaksList.current.includes(t["data"]["id"]) && (
|
|
||||||
<AccordionComponent
|
|
||||||
trigger={t["data"]["id"]}
|
|
||||||
keyValue={t["data"]["id"]}
|
|
||||||
open={openAccordion}
|
|
||||||
>
|
|
||||||
<div className="api-modal-table-arrangement">
|
|
||||||
<Table className="table-fixed bg-muted outline-1">
|
|
||||||
<TableHeader className="h-10 border-input text-xs font-medium text-ring">
|
|
||||||
<TableRow className="dark:border-b-muted">
|
|
||||||
<TableHead className="h-7 text-center">
|
|
||||||
PARAM
|
|
||||||
</TableHead>
|
|
||||||
<TableHead className="h-7 p-0 text-center">
|
|
||||||
VALUE
|
|
||||||
</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody className="p-0">
|
|
||||||
{Object.keys(t["data"]["node"]["template"])
|
|
||||||
.filter(
|
|
||||||
(n) =>
|
|
||||||
n.charAt(0) !== "_" &&
|
|
||||||
t.data.node.template[n].show &&
|
|
||||||
(t.data.node.template[n].type ===
|
|
||||||
"str" ||
|
|
||||||
t.data.node.template[n].type ===
|
|
||||||
"bool" ||
|
|
||||||
t.data.node.template[n].type ===
|
|
||||||
"float" ||
|
|
||||||
t.data.node.template[n].type ===
|
|
||||||
"code" ||
|
|
||||||
t.data.node.template[n].type ===
|
|
||||||
"prompt" ||
|
|
||||||
t.data.node.template[n].type ===
|
|
||||||
"file" ||
|
|
||||||
t.data.node.template[n].type ===
|
|
||||||
"int")
|
|
||||||
)
|
|
||||||
.map((n, i) => {
|
|
||||||
return (
|
|
||||||
<TableRow
|
|
||||||
key={i}
|
|
||||||
className="h-10 dark:border-b-muted"
|
|
||||||
>
|
|
||||||
<TableCell className="p-0 text-center text-sm text-foreground">
|
|
||||||
{n}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="p-0 text-xs text-foreground">
|
|
||||||
<div className="m-auto w-[250px]">
|
|
||||||
{t.data.node.template[n]
|
|
||||||
.type === "str" &&
|
|
||||||
!t.data.node.template[n]
|
|
||||||
.options ? (
|
|
||||||
<div className="mx-auto">
|
|
||||||
{t.data.node.template[n]
|
|
||||||
.list ? (
|
|
||||||
<InputListComponent
|
|
||||||
editNode={true}
|
|
||||||
disabled={false}
|
|
||||||
value={
|
|
||||||
!t.data.node.template[
|
|
||||||
n
|
|
||||||
].value ||
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
].value === ""
|
|
||||||
? [""]
|
|
||||||
: t.data.node
|
|
||||||
.template[n]
|
|
||||||
.value
|
|
||||||
}
|
|
||||||
onChange={(k) => {}}
|
|
||||||
onAddInput={(k) => {
|
|
||||||
buildTweakObject(
|
|
||||||
t["data"]["id"],
|
|
||||||
k,
|
|
||||||
t.data.node
|
|
||||||
.template[n]
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : t.data.node.template[n]
|
|
||||||
.multiline ? (
|
|
||||||
<ShadTooltip
|
|
||||||
content={buildContent(
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
].value
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<TextAreaComponent
|
|
||||||
disabled={false}
|
|
||||||
editNode={true}
|
|
||||||
value={getValue(
|
|
||||||
t.data.node
|
|
||||||
.template[n]
|
|
||||||
.value,
|
|
||||||
t.data,
|
|
||||||
t.data.node
|
|
||||||
.template[n]
|
|
||||||
)}
|
|
||||||
onChange={(k) => {
|
|
||||||
buildTweakObject(
|
|
||||||
t["data"]["id"],
|
|
||||||
k,
|
|
||||||
t.data.node
|
|
||||||
.template[n]
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</ShadTooltip>
|
|
||||||
) : (
|
|
||||||
<InputComponent
|
|
||||||
editNode={true}
|
|
||||||
disabled={false}
|
|
||||||
password={
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
].password ?? false
|
|
||||||
}
|
|
||||||
value={getValue(
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
].value,
|
|
||||||
t.data,
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
]
|
|
||||||
)}
|
|
||||||
onChange={(k) => {
|
|
||||||
buildTweakObject(
|
|
||||||
t["data"]["id"],
|
|
||||||
k,
|
|
||||||
t.data.node
|
|
||||||
.template[n]
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
) : t.data.node.template[n]
|
|
||||||
.type === "bool" ? (
|
|
||||||
<div className="ml-auto">
|
|
||||||
{" "}
|
|
||||||
<ToggleShadComponent
|
|
||||||
enabled={
|
|
||||||
t.data.node.template[n]
|
|
||||||
.value
|
|
||||||
}
|
|
||||||
setEnabled={(e) => {
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
].value = e;
|
|
||||||
setEnabled(e);
|
|
||||||
buildTweakObject(
|
|
||||||
t["data"]["id"],
|
|
||||||
e,
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
size="small"
|
|
||||||
disabled={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : t.data.node.template[n]
|
|
||||||
.type === "file" ? (
|
|
||||||
<ShadTooltip
|
|
||||||
content={buildContent(
|
|
||||||
getValue(
|
|
||||||
t.data.node.template[n]
|
|
||||||
.value,
|
|
||||||
t.data,
|
|
||||||
t.data.node.template[n]
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="mx-auto">
|
|
||||||
<InputFileComponent
|
|
||||||
editNode={true}
|
|
||||||
disabled={false}
|
|
||||||
value={
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
].value ?? ""
|
|
||||||
}
|
|
||||||
onChange={(
|
|
||||||
k: any
|
|
||||||
) => {}}
|
|
||||||
fileTypes={
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
].fileTypes
|
|
||||||
}
|
|
||||||
suffixes={
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
].suffixes
|
|
||||||
}
|
|
||||||
onFileChange={(
|
|
||||||
k: any
|
|
||||||
) => {}}
|
|
||||||
></InputFileComponent>
|
|
||||||
</div>
|
|
||||||
</ShadTooltip>
|
|
||||||
) : t.data.node.template[n]
|
|
||||||
.type === "float" ? (
|
|
||||||
<div className="mx-auto">
|
|
||||||
<FloatComponent
|
|
||||||
disabled={false}
|
|
||||||
editNode={true}
|
|
||||||
value={getValue(
|
|
||||||
t.data.node.template[n]
|
|
||||||
.value,
|
|
||||||
t.data,
|
|
||||||
t.data.node.template[n]
|
|
||||||
)}
|
|
||||||
onChange={(k) => {
|
|
||||||
buildTweakObject(
|
|
||||||
t["data"]["id"],
|
|
||||||
k,
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : t.data.node.template[n]
|
|
||||||
.type === "str" &&
|
|
||||||
t.data.node.template[n]
|
|
||||||
.options ? (
|
|
||||||
<div className="mx-auto">
|
|
||||||
<Dropdown
|
|
||||||
editNode={true}
|
|
||||||
apiModal={true}
|
|
||||||
options={
|
|
||||||
t.data.node.template[n]
|
|
||||||
.options
|
|
||||||
}
|
|
||||||
onSelect={(k) => {
|
|
||||||
buildTweakObject(
|
|
||||||
t["data"]["id"],
|
|
||||||
k,
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
value={getValue(
|
|
||||||
t.data.node.template[n]
|
|
||||||
.value,
|
|
||||||
t.data,
|
|
||||||
t.data.node.template[n]
|
|
||||||
)}
|
|
||||||
></Dropdown>
|
|
||||||
</div>
|
|
||||||
) : t.data.node.template[n]
|
|
||||||
.type === "int" ? (
|
|
||||||
<div className="mx-auto">
|
|
||||||
<IntComponent
|
|
||||||
disabled={false}
|
|
||||||
editNode={true}
|
|
||||||
value={getValue(
|
|
||||||
t.data.node.template[n]
|
|
||||||
.value,
|
|
||||||
t.data,
|
|
||||||
t.data.node.template[n]
|
|
||||||
)}
|
|
||||||
onChange={(k) => {
|
|
||||||
buildTweakObject(
|
|
||||||
t["data"]["id"],
|
|
||||||
k,
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : t.data.node.template[n]
|
|
||||||
.type === "prompt" ? (
|
|
||||||
<ShadTooltip
|
|
||||||
content={buildContent(
|
|
||||||
getValue(
|
|
||||||
t.data.node.template[n]
|
|
||||||
.value,
|
|
||||||
t.data,
|
|
||||||
t.data.node.template[n]
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="mx-auto">
|
|
||||||
<PromptAreaComponent
|
|
||||||
editNode={true}
|
|
||||||
disabled={false}
|
|
||||||
value={getValue(
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
].value,
|
|
||||||
t.data,
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
]
|
|
||||||
)}
|
|
||||||
onChange={(k) => {
|
|
||||||
buildTweakObject(
|
|
||||||
t["data"]["id"],
|
|
||||||
k,
|
|
||||||
t.data.node
|
|
||||||
.template[n]
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</ShadTooltip>
|
|
||||||
) : t.data.node.template[n]
|
|
||||||
.type === "code" ? (
|
|
||||||
<ShadTooltip
|
|
||||||
content={buildContent(
|
|
||||||
getValue(
|
|
||||||
t.data.node.template[n]
|
|
||||||
.value,
|
|
||||||
t.data,
|
|
||||||
t.data.node.template[n]
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="mx-auto">
|
|
||||||
<CodeAreaComponent
|
|
||||||
disabled={false}
|
|
||||||
editNode={true}
|
|
||||||
value={getValue(
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
].value,
|
|
||||||
t.data,
|
|
||||||
t.data.node.template[
|
|
||||||
n
|
|
||||||
]
|
|
||||||
)}
|
|
||||||
onChange={(k) => {
|
|
||||||
buildTweakObject(
|
|
||||||
t["data"]["id"],
|
|
||||||
k,
|
|
||||||
t.data.node
|
|
||||||
.template[n]
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</ShadTooltip>
|
|
||||||
) : t.data.node.template[n]
|
|
||||||
.type === "Any" ? (
|
|
||||||
"-"
|
|
||||||
) : (
|
|
||||||
<div className="hidden"></div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</div>
|
|
||||||
</AccordionComponent>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{tweaksList.current.length === 0 && (
|
|
||||||
<>
|
|
||||||
<div className="pt-3">
|
|
||||||
No tweaks are available for this flow.
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
</TabsContent>
|
|
||||||
))}
|
|
||||||
</Tabs>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { useContext, useRef, useState } from "react";
|
import { cloneDeep } from "lodash";
|
||||||
|
import { ReactNode, forwardRef, useContext, useEffect, useState } from "react";
|
||||||
import CodeAreaComponent from "../../components/codeAreaComponent";
|
import CodeAreaComponent from "../../components/codeAreaComponent";
|
||||||
import Dropdown from "../../components/dropdownComponent";
|
import Dropdown from "../../components/dropdownComponent";
|
||||||
import FloatComponent from "../../components/floatComponent";
|
import FloatComponent from "../../components/floatComponent";
|
||||||
|
|
@ -12,15 +13,6 @@ import TextAreaComponent from "../../components/textAreaComponent";
|
||||||
import ToggleShadComponent from "../../components/toggleShadComponent";
|
import ToggleShadComponent from "../../components/toggleShadComponent";
|
||||||
import { Badge } from "../../components/ui/badge";
|
import { Badge } from "../../components/ui/badge";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
import {
|
|
||||||
Dialog,
|
|
||||||
DialogContent,
|
|
||||||
DialogDescription,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
DialogTrigger,
|
|
||||||
} from "../../components/ui/dialog";
|
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
|
|
@ -30,95 +22,71 @@ import {
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "../../components/ui/table";
|
} from "../../components/ui/table";
|
||||||
import { limitScrollFieldsModal } from "../../constants/constants";
|
import { limitScrollFieldsModal } from "../../constants/constants";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
import { typesContext } from "../../contexts/typesContext";
|
import { typesContext } from "../../contexts/typesContext";
|
||||||
import { NodeDataType } from "../../types/flow";
|
import { NodeDataType } from "../../types/flow";
|
||||||
import { classNames } from "../../utils/utils";
|
import { classNames } from "../../utils/utils";
|
||||||
|
import BaseModal from "../baseModal";
|
||||||
|
|
||||||
export default function EditNodeModal({ data }: { data: NodeDataType }) {
|
const EditNodeModal = forwardRef(
|
||||||
const [open, setOpen] = useState(true);
|
(
|
||||||
const [nodeLength, setNodeLength] = useState(
|
{
|
||||||
Object.keys(data.node.template).filter(
|
data,
|
||||||
(t) =>
|
setData,
|
||||||
t.charAt(0) !== "_" &&
|
nodeLength,
|
||||||
data.node.template[t].show &&
|
children,
|
||||||
(data.node.template[t].type === "str" ||
|
}: {
|
||||||
data.node.template[t].type === "bool" ||
|
data: NodeDataType;
|
||||||
data.node.template[t].type === "float" ||
|
setData: (data: NodeDataType) => void;
|
||||||
data.node.template[t].type === "code" ||
|
nodeLength: number;
|
||||||
data.node.template[t].type === "prompt" ||
|
children: ReactNode;
|
||||||
data.node.template[t].type === "file" ||
|
},
|
||||||
data.node.template[t].type === "int")
|
ref
|
||||||
).length
|
) => {
|
||||||
);
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
const [nodeValue, setNodeValue] = useState(null);
|
const [myData, setMyData] = useState(data);
|
||||||
const { closePopUp } = useContext(PopUpContext);
|
|
||||||
const { types } = useContext(typesContext);
|
|
||||||
const ref = useRef();
|
|
||||||
const { setTabsState, tabId } = useContext(TabsContext);
|
const { setTabsState, tabId } = useContext(TabsContext);
|
||||||
const { reactFlowInstance } = useContext(typesContext);
|
const { reactFlowInstance } = useContext(typesContext);
|
||||||
|
|
||||||
let disabled =
|
let disabled =
|
||||||
reactFlowInstance?.getEdges().some((e) => e.targetHandle === data.id) ??
|
reactFlowInstance?.getEdges().some((e) => e.targetHandle === data.id) ??
|
||||||
false;
|
false;
|
||||||
if (nodeLength == 0) {
|
|
||||||
closePopUp();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setModalOpen(x: boolean) {
|
function changeAdvanced(n) {
|
||||||
setOpen(x);
|
setMyData((old) => {
|
||||||
if (x === false) {
|
let newData = cloneDeep(old);
|
||||||
closePopUp();
|
newData.node.template[n].advanced = !newData.node.template[n].advanced;
|
||||||
}
|
return newData;
|
||||||
}
|
|
||||||
|
|
||||||
function changeAdvanced(node) {
|
|
||||||
Object.keys(data.node.template).map((n, i) => {
|
|
||||||
if (n === node.name) {
|
|
||||||
data.node.template[n].advanced = !data.node.template[n].advanced;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
});
|
});
|
||||||
setNodeValue(!nodeValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOnNewValue = (newValue: any, name) => {
|
const handleOnNewValue = (newValue: any, name) => {
|
||||||
data.node.template[name].value = newValue;
|
setMyData((old) => {
|
||||||
// Set state to pending
|
let newData = cloneDeep(old);
|
||||||
setTabsState((prev) => {
|
newData.node.template[name].value = newValue;
|
||||||
return {
|
return newData;
|
||||||
...prev,
|
|
||||||
[tabId]: {
|
|
||||||
...prev[tabId],
|
|
||||||
isPending: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMyData(data); // reset data to what it is on node when opening modal
|
||||||
|
}, [modalOpen]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={true} onOpenChange={setModalOpen}>
|
<BaseModal size="large-h-full" open={modalOpen} setOpen={setModalOpen}>
|
||||||
<DialogTrigger asChild></DialogTrigger>
|
<BaseModal.Trigger>{children}</BaseModal.Trigger>
|
||||||
<DialogContent className="sm:max-w-[600px] lg:max-w-[700px]">
|
<BaseModal.Header description={myData.node?.description}>
|
||||||
<DialogHeader>
|
<span className="pr-2">{myData.type}</span>
|
||||||
<DialogTitle className="flex items-center">
|
<Badge variant="secondary">ID: {myData.id}</Badge>
|
||||||
<span className="pr-2">{data.type}</span>
|
</BaseModal.Header>
|
||||||
<Badge variant="secondary">ID: {data.id}</Badge>
|
<BaseModal.Content>
|
||||||
</DialogTitle>
|
<div className="flex pb-2">
|
||||||
<DialogDescription asChild>
|
|
||||||
<div>
|
|
||||||
{data.node?.description}
|
|
||||||
<div className="flex pt-3">
|
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="Variable"
|
name="Variable"
|
||||||
className="edit-node-modal-variable "
|
className="edit-node-modal-variable "
|
||||||
/>
|
/>
|
||||||
<span className="edit-node-modal-span">Parameters</span>
|
<span className="edit-node-modal-span">Parameters</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</DialogDescription>
|
|
||||||
</DialogHeader>
|
|
||||||
|
|
||||||
<div className="edit-node-modal-arrangement">
|
<div className="edit-node-modal-arrangement">
|
||||||
<div
|
<div
|
||||||
|
|
@ -142,49 +110,51 @@ export default function EditNodeModal({ data }: { data: NodeDataType }) {
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody className="p-0">
|
<TableBody className="p-0">
|
||||||
{Object.keys(data.node.template)
|
{Object.keys(myData.node.template)
|
||||||
.filter(
|
.filter(
|
||||||
(t) =>
|
(t) =>
|
||||||
t.charAt(0) !== "_" &&
|
t.charAt(0) !== "_" &&
|
||||||
data.node.template[t].show &&
|
myData.node.template[t].show &&
|
||||||
(data.node.template[t].type === "str" ||
|
(myData.node.template[t].type === "str" ||
|
||||||
data.node.template[t].type === "bool" ||
|
myData.node.template[t].type === "bool" ||
|
||||||
data.node.template[t].type === "float" ||
|
myData.node.template[t].type === "float" ||
|
||||||
data.node.template[t].type === "code" ||
|
myData.node.template[t].type === "code" ||
|
||||||
data.node.template[t].type === "prompt" ||
|
myData.node.template[t].type === "prompt" ||
|
||||||
data.node.template[t].type === "file" ||
|
myData.node.template[t].type === "file" ||
|
||||||
data.node.template[t].type === "int")
|
myData.node.template[t].type === "int")
|
||||||
)
|
)
|
||||||
.map((n, i) => (
|
.map((n, i) => (
|
||||||
<TableRow key={i} className="h-10">
|
<TableRow key={i} className="h-10">
|
||||||
<TableCell className="truncate p-0 text-center text-sm text-foreground sm:px-3">
|
<TableCell className="truncate p-0 text-center text-sm text-foreground sm:px-3">
|
||||||
{data.node.template[n].name
|
{myData.node.template[n].name
|
||||||
? data.node.template[n].name
|
? myData.node.template[n].name
|
||||||
: data.node.template[n].display_name}
|
: myData.node.template[n].display_name}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="w-[300px] p-0 text-center text-xs text-foreground ">
|
<TableCell className="w-[300px] p-0 text-center text-xs text-foreground ">
|
||||||
{data.node.template[n].type === "str" &&
|
{myData.node.template[n].type === "str" &&
|
||||||
!data.node.template[n].options ? (
|
!myData.node.template[n].options ? (
|
||||||
<div className="mx-auto">
|
<div className="mx-auto">
|
||||||
{data.node.template[n].list ? (
|
{myData.node.template[n].list ? (
|
||||||
<InputListComponent
|
<InputListComponent
|
||||||
editNode={true}
|
editNode={true}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
value={
|
value={
|
||||||
!data.node.template[n].value ||
|
!myData.node.template[n].value ||
|
||||||
data.node.template[n].value === ""
|
myData.node.template[n].value === ""
|
||||||
? [""]
|
? [""]
|
||||||
: data.node.template[n].value
|
: myData.node.template[n].value
|
||||||
}
|
}
|
||||||
onChange={(t: string[]) => {
|
onChange={(t: string[]) => {
|
||||||
handleOnNewValue(t, n);
|
handleOnNewValue(t, n);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : data.node.template[n].multiline ? (
|
) : myData.node.template[n].multiline ? (
|
||||||
<TextAreaComponent
|
<TextAreaComponent
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
editNode={true}
|
editNode={true}
|
||||||
value={data.node.template[n].value ?? ""}
|
value={
|
||||||
|
myData.node.template[n].value ?? ""
|
||||||
|
}
|
||||||
onChange={(t: string) => {
|
onChange={(t: string) => {
|
||||||
handleOnNewValue(t, n);
|
handleOnNewValue(t, n);
|
||||||
}}
|
}}
|
||||||
|
|
@ -194,107 +164,112 @@ export default function EditNodeModal({ data }: { data: NodeDataType }) {
|
||||||
editNode={true}
|
editNode={true}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
password={
|
password={
|
||||||
data.node.template[n].password ?? false
|
myData.node.template[n].password ??
|
||||||
|
false
|
||||||
|
}
|
||||||
|
value={
|
||||||
|
myData.node.template[n].value ?? ""
|
||||||
}
|
}
|
||||||
value={data.node.template[n].value ?? ""}
|
|
||||||
onChange={(t) => {
|
onChange={(t) => {
|
||||||
handleOnNewValue(t, n);
|
handleOnNewValue(t, n);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : data.node.template[n].type === "bool" ? (
|
) : myData.node.template[n].type === "bool" ? (
|
||||||
<div className="ml-auto">
|
<div className="ml-auto">
|
||||||
{" "}
|
{" "}
|
||||||
<ToggleShadComponent
|
<ToggleShadComponent
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
enabled={data.node.template[n].value}
|
enabled={myData.node.template[n].value}
|
||||||
setEnabled={(t) => {
|
setEnabled={(t) => {
|
||||||
handleOnNewValue(t, n);
|
handleOnNewValue(t, n);
|
||||||
}}
|
}}
|
||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : data.node.template[n].type === "float" ? (
|
) : myData.node.template[n].type === "float" ? (
|
||||||
<div className="mx-auto">
|
<div className="mx-auto">
|
||||||
<FloatComponent
|
<FloatComponent
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
editNode={true}
|
editNode={true}
|
||||||
value={data.node.template[n].value ?? ""}
|
value={myData.node.template[n].value ?? ""}
|
||||||
onChange={(t) => {
|
onChange={(t) => {
|
||||||
data.node.template[n].value = t;
|
handleOnNewValue(t, n);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : data.node.template[n].type === "str" &&
|
) : myData.node.template[n].type === "str" &&
|
||||||
data.node.template[n].options ? (
|
myData.node.template[n].options ? (
|
||||||
<div className="mx-auto">
|
<div className="mx-auto">
|
||||||
<Dropdown
|
<Dropdown
|
||||||
numberOfOptions={nodeLength}
|
numberOfOptions={nodeLength}
|
||||||
editNode={true}
|
editNode={true}
|
||||||
options={data.node.template[n].options}
|
options={myData.node.template[n].options}
|
||||||
onSelect={(t) => handleOnNewValue(t, n)}
|
onSelect={(t) => handleOnNewValue(t, n)}
|
||||||
value={
|
value={
|
||||||
data.node.template[n].value ??
|
myData.node.template[n].value ??
|
||||||
"Choose an option"
|
"Choose an option"
|
||||||
}
|
}
|
||||||
></Dropdown>
|
></Dropdown>
|
||||||
</div>
|
</div>
|
||||||
) : data.node.template[n].type === "int" ? (
|
) : myData.node.template[n].type === "int" ? (
|
||||||
<div className="mx-auto">
|
<div className="mx-auto">
|
||||||
<IntComponent
|
<IntComponent
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
editNode={true}
|
editNode={true}
|
||||||
value={data.node.template[n].value ?? ""}
|
value={myData.node.template[n].value ?? ""}
|
||||||
onChange={(t) => {
|
onChange={(t) => {
|
||||||
handleOnNewValue(t, n);
|
handleOnNewValue(t, n);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : data.node.template[n].type === "file" ? (
|
) : myData.node.template[n].type === "file" ? (
|
||||||
<div className="mx-auto">
|
<div className="mx-auto">
|
||||||
<InputFileComponent
|
<InputFileComponent
|
||||||
editNode={true}
|
editNode={true}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
value={data.node.template[n].value ?? ""}
|
value={myData.node.template[n].value ?? ""}
|
||||||
onChange={(t: string) => {
|
onChange={(t: string) => {
|
||||||
handleOnNewValue(t, n);
|
handleOnNewValue(t, n);
|
||||||
}}
|
}}
|
||||||
fileTypes={data.node.template[n].fileTypes}
|
fileTypes={
|
||||||
suffixes={data.node.template[n].suffixes}
|
myData.node.template[n].fileTypes
|
||||||
|
}
|
||||||
|
suffixes={myData.node.template[n].suffixes}
|
||||||
onFileChange={(t: string) => {
|
onFileChange={(t: string) => {
|
||||||
handleOnNewValue(t, n);
|
handleOnNewValue(t, n);
|
||||||
}}
|
}}
|
||||||
></InputFileComponent>
|
></InputFileComponent>
|
||||||
</div>
|
</div>
|
||||||
) : data.node.template[n].type === "prompt" ? (
|
) : myData.node.template[n].type === "prompt" ? (
|
||||||
<div className="mx-auto">
|
<div className="mx-auto">
|
||||||
<PromptAreaComponent
|
<PromptAreaComponent
|
||||||
field_name={n}
|
field_name={n}
|
||||||
editNode={true}
|
editNode={true}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
nodeClass={data.node}
|
nodeClass={myData.node}
|
||||||
setNodeClass={(nodeClass) => {
|
setNodeClass={(nodeClass) => {
|
||||||
data.node = nodeClass;
|
myData.node = nodeClass;
|
||||||
}}
|
}}
|
||||||
value={data.node.template[n].value ?? ""}
|
value={myData.node.template[n].value ?? ""}
|
||||||
onChange={(t: string) => {
|
onChange={(t: string) => {
|
||||||
handleOnNewValue(t, n);
|
handleOnNewValue(t, n);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : data.node.template[n].type === "code" ? (
|
) : myData.node.template[n].type === "code" ? (
|
||||||
<div className="mx-auto">
|
<div className="mx-auto">
|
||||||
<CodeAreaComponent
|
<CodeAreaComponent
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
editNode={true}
|
editNode={true}
|
||||||
value={data.node.template[n].value ?? ""}
|
value={myData.node.template[n].value ?? ""}
|
||||||
onChange={(t: string) => {
|
onChange={(t: string) => {
|
||||||
handleOnNewValue(t, n);
|
handleOnNewValue(t, n);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : data.node.template[n].type === "Any" ? (
|
) : myData.node.template[n].type === "Any" ? (
|
||||||
"-"
|
"-"
|
||||||
) : (
|
) : (
|
||||||
<div className="hidden"></div>
|
<div className="hidden"></div>
|
||||||
|
|
@ -303,10 +278,8 @@ export default function EditNodeModal({ data }: { data: NodeDataType }) {
|
||||||
<TableCell className="p-0 text-right">
|
<TableCell className="p-0 text-right">
|
||||||
<div className="items-center text-center">
|
<div className="items-center text-center">
|
||||||
<ToggleShadComponent
|
<ToggleShadComponent
|
||||||
enabled={!data.node.template[n].advanced}
|
enabled={!myData.node.template[n].advanced}
|
||||||
setEnabled={(e) =>
|
setEnabled={(e) => changeAdvanced(n)}
|
||||||
changeAdvanced(data.node.template[n])
|
|
||||||
}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
|
|
@ -320,19 +293,32 @@ export default function EditNodeModal({ data }: { data: NodeDataType }) {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</BaseModal.Content>
|
||||||
|
|
||||||
<DialogFooter>
|
<BaseModal.Footer>
|
||||||
<Button
|
<Button
|
||||||
className="mt-3"
|
className="mt-3"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
setData(cloneDeep(myData)); //saves data with actual state of modal
|
||||||
|
setTabsState((prev) => {
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
[tabId]: {
|
||||||
|
...prev[tabId],
|
||||||
|
isPending: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
setModalOpen(false);
|
setModalOpen(false);
|
||||||
}}
|
}}
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
Save Changes
|
Save Changes
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</BaseModal.Footer>
|
||||||
</DialogContent>
|
</BaseModal>
|
||||||
</Dialog>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default EditNodeModal;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import { Dialog, Transition } from "@headlessui/react";
|
||||||
import { Fragment, useContext, useRef, useState } from "react";
|
import { Fragment, useContext, useRef, useState } from "react";
|
||||||
import IconComponent from "../../components/genericIconComponent";
|
import IconComponent from "../../components/genericIconComponent";
|
||||||
import { limitScrollFieldsModal } from "../../constants/constants";
|
import { limitScrollFieldsModal } from "../../constants/constants";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import { typesContext } from "../../contexts/typesContext";
|
import { typesContext } from "../../contexts/typesContext";
|
||||||
import { NodeDataType } from "../../types/flow";
|
import { NodeDataType } from "../../types/flow";
|
||||||
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
|
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
|
||||||
|
|
@ -10,23 +9,14 @@ import { classNames, toTitleCase } from "../../utils/utils";
|
||||||
import ModalField from "./components/ModalField";
|
import ModalField from "./components/ModalField";
|
||||||
|
|
||||||
export default function NodeModal({ data }: { data: NodeDataType }) {
|
export default function NodeModal({ data }: { data: NodeDataType }) {
|
||||||
const [open, setOpen] = useState(true);
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
const { closePopUp } = useContext(PopUpContext);
|
|
||||||
const { types } = useContext(typesContext);
|
const { types } = useContext(typesContext);
|
||||||
const ref = useRef();
|
const ref = useRef();
|
||||||
function setModalOpen(x: boolean) {
|
|
||||||
setOpen(x);
|
|
||||||
if (x === false) {
|
|
||||||
setTimeout(() => {
|
|
||||||
closePopUp();
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// any to avoid type conflict
|
// any to avoid type conflict
|
||||||
const Icon: any = nodeIconsLucide[types[data.type]];
|
const Icon: any = nodeIconsLucide[types[data.type]];
|
||||||
return (
|
return (
|
||||||
<Transition.Root show={open} appear={true} as={Fragment}>
|
|
||||||
<Dialog
|
<Dialog
|
||||||
|
open={modalOpen}
|
||||||
as="div"
|
as="div"
|
||||||
className="relative z-10"
|
className="relative z-10"
|
||||||
onClose={setModalOpen}
|
onClose={setModalOpen}
|
||||||
|
|
@ -78,8 +68,7 @@ export default function NodeModal({ data }: { data: NodeDataType }) {
|
||||||
strokeWidth={1.5}
|
strokeWidth={1.5}
|
||||||
className="node-modal-icon"
|
className="node-modal-icon"
|
||||||
style={{
|
style={{
|
||||||
color:
|
color: nodeColors[types[data.type]] ?? nodeColors.unknown,
|
||||||
nodeColors[types[data.type]] ?? nodeColors.unknown,
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="node-modal-title-div">
|
<div className="node-modal-title-div">
|
||||||
|
|
@ -158,6 +147,5 @@ export default function NodeModal({ data }: { data: NodeDataType }) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Transition.Root>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { ReactNode, useContext } from "react";
|
import { ReactNode } from "react";
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {
|
import {
|
||||||
|
|
@ -9,14 +9,18 @@ import {
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "../../components/ui/dialog";
|
} from "../../components/ui/dialog";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
|
|
||||||
type ContentProps = { children: ReactNode };
|
type ContentProps = { children: ReactNode };
|
||||||
type HeaderProps = { children: ReactNode; description: string };
|
type HeaderProps = { children: ReactNode; description: string };
|
||||||
|
type FooterProps = { children: ReactNode };
|
||||||
|
type TriggerProps = { children: ReactNode };
|
||||||
|
|
||||||
const Content: React.FC<ContentProps> = ({ children }) => {
|
const Content: React.FC<ContentProps> = ({ children }) => {
|
||||||
return <div className="h-full w-full">{children}</div>;
|
return <div className="h-full w-full">{children}</div>;
|
||||||
};
|
};
|
||||||
|
const Trigger: React.FC<ContentProps> = ({ children }) => {
|
||||||
|
return <>{children}</>;
|
||||||
|
};
|
||||||
|
|
||||||
const Header: React.FC<{ children: ReactNode; description: string }> = ({
|
const Header: React.FC<{ children: ReactNode; description: string }> = ({
|
||||||
children,
|
children,
|
||||||
|
|
@ -29,36 +33,82 @@ const Header: React.FC<{ children: ReactNode; description: string }> = ({
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
interface BaseModalProps {
|
|
||||||
children: [React.ReactElement<ContentProps>, React.ReactElement<HeaderProps>];
|
|
||||||
open: boolean;
|
|
||||||
setOpen: (open: boolean) => void;
|
|
||||||
}
|
|
||||||
function BaseModal({ open, setOpen, children }: BaseModalProps) {
|
|
||||||
const { closePopUp, setCloseEdit } = useContext(PopUpContext);
|
|
||||||
|
|
||||||
function setModalOpen(x: boolean) {
|
const Footer: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||||
setOpen(x);
|
return <>{children}</>;
|
||||||
if (x === false) {
|
};
|
||||||
setTimeout(() => {
|
interface BaseModalProps {
|
||||||
setCloseEdit("editcode");
|
children: [
|
||||||
closePopUp();
|
React.ReactElement<ContentProps>,
|
||||||
}, 300);
|
React.ReactElement<HeaderProps>,
|
||||||
}
|
React.ReactElement<TriggerProps>?,
|
||||||
}
|
React.ReactElement<FooterProps>?
|
||||||
|
];
|
||||||
|
open?: boolean;
|
||||||
|
setOpen?: (open: boolean) => void;
|
||||||
|
size?: "smaller" | "small" | "medium" | "large" | "large-h-full";
|
||||||
|
}
|
||||||
|
function BaseModal({
|
||||||
|
open,
|
||||||
|
setOpen,
|
||||||
|
children,
|
||||||
|
size = "large",
|
||||||
|
}: BaseModalProps) {
|
||||||
const headerChild = React.Children.toArray(children).find(
|
const headerChild = React.Children.toArray(children).find(
|
||||||
(child) => (child as React.ReactElement).type === Header
|
(child) => (child as React.ReactElement).type === Header
|
||||||
);
|
);
|
||||||
|
const triggerChild = React.Children.toArray(children).find(
|
||||||
|
(child) => (child as React.ReactElement).type === Trigger
|
||||||
|
);
|
||||||
const ContentChild = React.Children.toArray(children).find(
|
const ContentChild = React.Children.toArray(children).find(
|
||||||
(child) => (child as React.ReactElement).type === Content
|
(child) => (child as React.ReactElement).type === Content
|
||||||
);
|
);
|
||||||
|
const ContentFooter = React.Children.toArray(children).find(
|
||||||
|
(child) => (child as React.ReactElement).type === Footer
|
||||||
|
);
|
||||||
|
|
||||||
|
let minWidth: string;
|
||||||
|
let height: string;
|
||||||
|
|
||||||
|
switch (size) {
|
||||||
|
case "smaller":
|
||||||
|
minWidth = "min-w-[40vw]";
|
||||||
|
height = "h-[25vh]";
|
||||||
|
break;
|
||||||
|
case "small":
|
||||||
|
minWidth = "min-w-[40vw]";
|
||||||
|
height = "h-[40vh]";
|
||||||
|
break;
|
||||||
|
case "medium":
|
||||||
|
minWidth = "min-w-[60vw]";
|
||||||
|
height = "h-[60vh]";
|
||||||
|
break;
|
||||||
|
case "large":
|
||||||
|
minWidth = "min-w-[80vw]";
|
||||||
|
height = "h-[80vh]";
|
||||||
|
break;
|
||||||
|
case "large-h-full":
|
||||||
|
minWidth = "min-w-[80vw]";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
minWidth = "min-w-[80vw]";
|
||||||
|
height = "h-[80vh]";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//UPDATE COLORS AND STYLE CLASSSES
|
//UPDATE COLORS AND STYLE CLASSSES
|
||||||
return (
|
return (
|
||||||
<Dialog open={true} onOpenChange={setModalOpen}>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
<DialogTrigger className="hidden"></DialogTrigger>
|
<DialogTrigger className="w-full" hidden={triggerChild ? false : true}>
|
||||||
<DialogContent className="min-w-[80vw]">
|
{triggerChild}
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent className={minWidth}>
|
||||||
{headerChild}
|
{headerChild}
|
||||||
<div className="mt-2 flex h-[80vh] w-full ">{ContentChild}</div>
|
<div className={`mt-2 flex flex-col ${height} w-full `}>
|
||||||
|
{ContentChild}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-row-reverse">{ContentFooter}</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|
@ -66,4 +116,6 @@ function BaseModal({ open, setOpen, children }: BaseModalProps) {
|
||||||
|
|
||||||
BaseModal.Content = Content;
|
BaseModal.Content = Content;
|
||||||
BaseModal.Header = Header;
|
BaseModal.Header = Header;
|
||||||
|
BaseModal.Trigger = Trigger;
|
||||||
|
BaseModal.Footer = Footer;
|
||||||
export default BaseModal;
|
export default BaseModal;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
import { DialogTitle } from "@radix-ui/react-dialog";
|
|
||||||
import "ace-builds/src-noconflict/ace";
|
import "ace-builds/src-noconflict/ace";
|
||||||
import "ace-builds/src-noconflict/ext-language_tools";
|
import "ace-builds/src-noconflict/ext-language_tools";
|
||||||
import "ace-builds/src-noconflict/mode-python";
|
import "ace-builds/src-noconflict/mode-python";
|
||||||
import "ace-builds/src-noconflict/theme-github";
|
import "ace-builds/src-noconflict/theme-github";
|
||||||
import "ace-builds/src-noconflict/theme-twilight";
|
import "ace-builds/src-noconflict/theme-twilight";
|
||||||
import { useContext, useState } from "react";
|
import { ReactNode, useContext, useState } from "react";
|
||||||
import AceEditor from "react-ace";
|
import AceEditor from "react-ace";
|
||||||
import IconComponent from "../../components/genericIconComponent";
|
import IconComponent from "../../components/genericIconComponent";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
import { CODE_PROMPT_DIALOG_SUBTITLE } from "../../constants/constants";
|
import { CODE_PROMPT_DIALOG_SUBTITLE } from "../../constants/constants";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
import { darkContext } from "../../contexts/darkContext";
|
import { darkContext } from "../../contexts/darkContext";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import { postValidateCode } from "../../controllers/API";
|
import { postValidateCode } from "../../controllers/API";
|
||||||
import { APIClassType } from "../../types/api";
|
import { APIClassType } from "../../types/api";
|
||||||
import BaseModal from "../baseModal";
|
import BaseModal from "../baseModal";
|
||||||
|
|
@ -21,25 +19,18 @@ export default function CodeAreaModal({
|
||||||
setValue,
|
setValue,
|
||||||
nodeClass,
|
nodeClass,
|
||||||
setNodeClass,
|
setNodeClass,
|
||||||
|
children,
|
||||||
}: {
|
}: {
|
||||||
setValue: (value: string) => void;
|
setValue: (value: string) => void;
|
||||||
value: string;
|
value: string;
|
||||||
nodeClass: APIClassType;
|
nodeClass: APIClassType;
|
||||||
|
children: ReactNode;
|
||||||
setNodeClass: (Class: APIClassType) => void;
|
setNodeClass: (Class: APIClassType) => void;
|
||||||
}) {
|
}) {
|
||||||
const [code, setCode] = useState(value);
|
const [code, setCode] = useState(value);
|
||||||
const { dark } = useContext(darkContext);
|
const { dark } = useContext(darkContext);
|
||||||
const { closePopUp, setCloseEdit } = useContext(PopUpContext);
|
|
||||||
const { setErrorData, setSuccessData } = useContext(alertContext);
|
const { setErrorData, setSuccessData } = useContext(alertContext);
|
||||||
|
|
||||||
function setModalOpen(x: boolean) {
|
|
||||||
if (x === false) {
|
|
||||||
setCloseEdit("codearea");
|
|
||||||
closePopUp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for custom code errors
|
|
||||||
function handleClick() {
|
function handleClick() {
|
||||||
postValidateCode(code)
|
postValidateCode(code)
|
||||||
.then((apiReturn) => {
|
.then((apiReturn) => {
|
||||||
|
|
@ -51,7 +42,7 @@ export default function CodeAreaModal({
|
||||||
title: "Code is ready to run",
|
title: "Code is ready to run",
|
||||||
});
|
});
|
||||||
setValue(code);
|
setValue(code);
|
||||||
setModalOpen(false);
|
setOpen(false);
|
||||||
} else {
|
} else {
|
||||||
if (funcErrors.length !== 0) {
|
if (funcErrors.length !== 0) {
|
||||||
setErrorData({
|
setErrorData({
|
||||||
|
|
@ -79,17 +70,18 @@ export default function CodeAreaModal({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseModal open={true} setOpen={setModalOpen}>
|
<BaseModal open={open} setOpen={setOpen}>
|
||||||
|
<BaseModal.Trigger>{children}</BaseModal.Trigger>
|
||||||
<BaseModal.Header description={CODE_PROMPT_DIALOG_SUBTITLE}>
|
<BaseModal.Header description={CODE_PROMPT_DIALOG_SUBTITLE}>
|
||||||
<DialogTitle className="flex items-center">
|
|
||||||
<span className="pr-2">Edit Code</span>
|
<span className="pr-2">Edit Code</span>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="prompts"
|
name="prompts"
|
||||||
className="h-6 w-6 pl-1 text-primary "
|
className="h-6 w-6 pl-1 text-primary "
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</DialogTitle>
|
|
||||||
</BaseModal.Header>
|
</BaseModal.Header>
|
||||||
<BaseModal.Content>
|
<BaseModal.Content>
|
||||||
<div className="flex h-full w-full flex-col transition-all">
|
<div className="flex h-full w-full flex-col transition-all">
|
||||||
|
|
|
||||||
|
|
@ -1,60 +1,34 @@
|
||||||
import { useContext, useRef, useState } from "react";
|
import { ReactNode, forwardRef, useContext, useState } from "react";
|
||||||
import EditFlowSettings from "../../components/EditFlowSettingsComponent";
|
import EditFlowSettings from "../../components/EditFlowSettingsComponent";
|
||||||
import IconComponent from "../../components/genericIconComponent";
|
import IconComponent from "../../components/genericIconComponent";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
import { Checkbox } from "../../components/ui/checkbox";
|
import { Checkbox } from "../../components/ui/checkbox";
|
||||||
import {
|
|
||||||
Dialog,
|
|
||||||
DialogContent,
|
|
||||||
DialogDescription,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
DialogTrigger,
|
|
||||||
} from "../../components/ui/dialog";
|
|
||||||
import { EXPORT_DIALOG_SUBTITLE } from "../../constants/constants";
|
import { EXPORT_DIALOG_SUBTITLE } from "../../constants/constants";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
import { removeApiKeys } from "../../utils/reactflowUtils";
|
import { removeApiKeys } from "../../utils/reactflowUtils";
|
||||||
|
import BaseModal from "../baseModal";
|
||||||
|
|
||||||
export default function ExportModal() {
|
const ExportModal = forwardRef((props: { children: ReactNode }, ref) => {
|
||||||
const [open, setOpen] = useState(true);
|
|
||||||
const { closePopUp } = useContext(PopUpContext);
|
|
||||||
const ref = useRef();
|
|
||||||
const { setErrorData } = useContext(alertContext);
|
|
||||||
const { flows, tabId, updateFlow, downloadFlow, saveFlow } =
|
const { flows, tabId, updateFlow, downloadFlow, saveFlow } =
|
||||||
useContext(TabsContext);
|
useContext(TabsContext);
|
||||||
const [isMaxLength, setIsMaxLength] = useState(false);
|
|
||||||
function setModalOpen(x: boolean) {
|
|
||||||
setOpen(x);
|
|
||||||
if (x === false) {
|
|
||||||
setTimeout(() => {
|
|
||||||
closePopUp();
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const [checked, setChecked] = useState(false);
|
const [checked, setChecked] = useState(false);
|
||||||
const [name, setName] = useState(flows.find((f) => f.id === tabId).name);
|
const [name, setName] = useState(flows.find((f) => f.id === tabId).name);
|
||||||
const [description, setDescription] = useState(
|
const [description, setDescription] = useState(
|
||||||
flows.find((f) => f.id === tabId).description
|
flows.find((f) => f.id === tabId).description
|
||||||
);
|
);
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
return (
|
return (
|
||||||
<Dialog open={true} onOpenChange={setModalOpen}>
|
<BaseModal size="smaller" open={open} setOpen={setOpen}>
|
||||||
<DialogTrigger asChild></DialogTrigger>
|
<BaseModal.Trigger>{props.children}</BaseModal.Trigger>
|
||||||
<DialogContent className="h-[420px] lg:max-w-[600px] ">
|
<BaseModal.Header description={EXPORT_DIALOG_SUBTITLE}>
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle className="flex items-center">
|
|
||||||
<span className="pr-2">Export</span>
|
<span className="pr-2">Export</span>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="Download"
|
name="Download"
|
||||||
className="h-6 w-6 pl-1 text-foreground"
|
className="h-6 w-6 pl-1 text-foreground"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</DialogTitle>
|
</BaseModal.Header>
|
||||||
<DialogDescription>{EXPORT_DIALOG_SUBTITLE}</DialogDescription>
|
<BaseModal.Content>
|
||||||
</DialogHeader>
|
|
||||||
|
|
||||||
<EditFlowSettings
|
<EditFlowSettings
|
||||||
name={name}
|
name={name}
|
||||||
description={description}
|
description={description}
|
||||||
|
|
@ -64,19 +38,20 @@ export default function ExportModal() {
|
||||||
setDescription={setDescription}
|
setDescription={setDescription}
|
||||||
updateFlow={updateFlow}
|
updateFlow={updateFlow}
|
||||||
/>
|
/>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="mt-3 flex items-center space-x-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="terms"
|
id="terms"
|
||||||
onCheckedChange={(event: boolean) => {
|
onCheckedChange={(event: boolean) => {
|
||||||
setChecked(event);
|
setChecked(event);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<label htmlFor="terms" className="export-modal-save-api text-sm">
|
<label htmlFor="terms" className="export-modal-save-api text-sm ">
|
||||||
Save with my API keys
|
Save with my API keys
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
</BaseModal.Content>
|
||||||
|
|
||||||
<DialogFooter>
|
<BaseModal.Footer>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (checked)
|
if (checked)
|
||||||
|
|
@ -91,15 +66,14 @@ export default function ExportModal() {
|
||||||
name,
|
name,
|
||||||
description
|
description
|
||||||
);
|
);
|
||||||
|
setOpen(false);
|
||||||
closePopUp();
|
|
||||||
}}
|
}}
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
Download Flow
|
Download Flow
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</BaseModal.Footer>
|
||||||
</DialogContent>
|
</BaseModal>
|
||||||
</Dialog>
|
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
export default ExportModal;
|
||||||
|
|
|
||||||
|
|
@ -2,23 +2,18 @@ import { useContext, useRef, useState } from "react";
|
||||||
import EditFlowSettings from "../../components/EditFlowSettingsComponent";
|
import EditFlowSettings from "../../components/EditFlowSettingsComponent";
|
||||||
import IconComponent from "../../components/genericIconComponent";
|
import IconComponent from "../../components/genericIconComponent";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
import {
|
|
||||||
Dialog,
|
|
||||||
DialogContent,
|
|
||||||
DialogDescription,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
DialogTrigger,
|
|
||||||
} from "../../components/ui/dialog";
|
|
||||||
import { SETTINGS_DIALOG_SUBTITLE } from "../../constants/constants";
|
import { SETTINGS_DIALOG_SUBTITLE } from "../../constants/constants";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
|
import BaseModal from "../baseModal";
|
||||||
|
|
||||||
export default function FlowSettingsModal() {
|
export default function FlowSettingsModal({
|
||||||
const [open, setOpen] = useState(true);
|
open,
|
||||||
const { closePopUp } = useContext(PopUpContext);
|
setOpen,
|
||||||
|
}: {
|
||||||
|
open: boolean;
|
||||||
|
setOpen: (open: boolean) => void;
|
||||||
|
}) {
|
||||||
const { setErrorData, setSuccessData } = useContext(alertContext);
|
const { setErrorData, setSuccessData } = useContext(alertContext);
|
||||||
const ref = useRef();
|
const ref = useRef();
|
||||||
const { flows, tabId, updateFlow, setTabsState, saveFlow } =
|
const { flows, tabId, updateFlow, setTabsState, saveFlow } =
|
||||||
|
|
@ -28,34 +23,21 @@ export default function FlowSettingsModal() {
|
||||||
const [description, setDescription] = useState(
|
const [description, setDescription] = useState(
|
||||||
flows.find((f) => f.id === tabId).description
|
flows.find((f) => f.id === tabId).description
|
||||||
);
|
);
|
||||||
function setModalOpen(x: boolean) {
|
|
||||||
setOpen(x);
|
|
||||||
if (x === false) {
|
|
||||||
setTimeout(() => {
|
|
||||||
closePopUp();
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function handleClick() {
|
function handleClick() {
|
||||||
let savedFlow = flows.find((f) => f.id === tabId);
|
let savedFlow = flows.find((f) => f.id === tabId);
|
||||||
savedFlow.name = name;
|
savedFlow.name = name;
|
||||||
savedFlow.description = description;
|
savedFlow.description = description;
|
||||||
saveFlow(savedFlow);
|
saveFlow(savedFlow);
|
||||||
setSuccessData({ title: "Changes saved successfully" });
|
setSuccessData({ title: "Changes saved successfully" });
|
||||||
closePopUp();
|
setOpen(false);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Dialog open={true} onOpenChange={setModalOpen}>
|
<BaseModal open={open} setOpen={setOpen} size="smaller">
|
||||||
<DialogTrigger asChild></DialogTrigger>
|
<BaseModal.Header description={SETTINGS_DIALOG_SUBTITLE}>
|
||||||
<DialogContent className="h-[390px] lg:max-w-[600px]">
|
<span className="pr-2">Settings</span>
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle className="flex items-center">
|
|
||||||
<span className="pr-2">Settings </span>
|
|
||||||
<IconComponent name="Settings2" className="mr-2 h-4 w-4 " />
|
<IconComponent name="Settings2" className="mr-2 h-4 w-4 " />
|
||||||
</DialogTitle>
|
</BaseModal.Header>
|
||||||
<DialogDescription>{SETTINGS_DIALOG_SUBTITLE}</DialogDescription>
|
<BaseModal.Content>
|
||||||
</DialogHeader>
|
|
||||||
|
|
||||||
<EditFlowSettings
|
<EditFlowSettings
|
||||||
name={name}
|
name={name}
|
||||||
description={description}
|
description={description}
|
||||||
|
|
@ -65,13 +47,13 @@ export default function FlowSettingsModal() {
|
||||||
setDescription={setDescription}
|
setDescription={setDescription}
|
||||||
updateFlow={updateFlow}
|
updateFlow={updateFlow}
|
||||||
/>
|
/>
|
||||||
|
</BaseModal.Content>
|
||||||
|
|
||||||
<DialogFooter>
|
<BaseModal.Footer>
|
||||||
<Button onClick={handleClick} type="submit">
|
<Button onClick={handleClick} type="submit">
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</BaseModal.Footer>
|
||||||
</DialogContent>
|
</BaseModal>
|
||||||
</Dialog>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ import remarkMath from "remark-math";
|
||||||
import MaleTechnology from "../../../assets/male-technologist.png";
|
import MaleTechnology from "../../../assets/male-technologist.png";
|
||||||
import Robot from "../../../assets/robot.png";
|
import Robot from "../../../assets/robot.png";
|
||||||
import SanitizedHTMLWrapper from "../../../components/SanitizedHTMLWrapper";
|
import SanitizedHTMLWrapper from "../../../components/SanitizedHTMLWrapper";
|
||||||
|
import CodeTabsComponent from "../../../components/codeTabsComponent";
|
||||||
import IconComponent from "../../../components/genericIconComponent";
|
import IconComponent from "../../../components/genericIconComponent";
|
||||||
import { ChatMessageType } from "../../../types/chat";
|
import { ChatMessageType } from "../../../types/chat";
|
||||||
import { classNames } from "../../../utils/utils";
|
import { classNames } from "../../../utils/utils";
|
||||||
import FileCard from "../fileComponent";
|
import FileCard from "../fileComponent";
|
||||||
import { CodeBlock } from "./codeBlock";
|
|
||||||
export default function ChatMessage({
|
export default function ChatMessage({
|
||||||
chat,
|
chat,
|
||||||
lockChat,
|
lockChat,
|
||||||
|
|
@ -78,13 +78,22 @@ export default function ChatMessage({
|
||||||
<div className="w-full dark:text-white">
|
<div className="w-full dark:text-white">
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
{useMemo(
|
{useMemo(
|
||||||
() => (
|
() =>
|
||||||
|
chat.message.toString() === "" && lockChat ? (
|
||||||
|
<IconComponent
|
||||||
|
name="MoreHorizontal"
|
||||||
|
className="h-8 w-8 animate-pulse"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
remarkPlugins={[remarkGfm, remarkMath]}
|
remarkPlugins={[remarkGfm, remarkMath]}
|
||||||
rehypePlugins={[rehypeMathjax]}
|
rehypePlugins={[rehypeMathjax]}
|
||||||
className="markdown prose inline-block break-words text-primary
|
className="markdown prose inline-block break-words text-primary dark:prose-invert
|
||||||
dark:prose-invert sm:w-[30vw] sm:max-w-[30vw] lg:w-[40vw] lg:max-w-[40vw]"
|
sm:w-[30vw] sm:max-w-[30vw] lg:w-[40vw] lg:max-w-[40vw]"
|
||||||
components={{
|
components={{
|
||||||
|
pre({ node, ...props }) {
|
||||||
|
return <>{props.children}</>;
|
||||||
|
},
|
||||||
code: ({
|
code: ({
|
||||||
node,
|
node,
|
||||||
inline,
|
inline,
|
||||||
|
|
@ -112,11 +121,20 @@ export default function ChatMessage({
|
||||||
);
|
);
|
||||||
|
|
||||||
return !inline ? (
|
return !inline ? (
|
||||||
<CodeBlock
|
<CodeTabsComponent
|
||||||
key={Math.random()}
|
isMessage
|
||||||
language={(match && match[1]) || ""}
|
tabs={[
|
||||||
value={String(children).replace(/\n$/, "")}
|
{
|
||||||
{...props}
|
name: (match && match[1]) || "",
|
||||||
|
mode: (match && match[1]) || "",
|
||||||
|
image:
|
||||||
|
"https://curl.se/logo/curl-symbol-transparent.png",
|
||||||
|
language: (match && match[1]) || "",
|
||||||
|
code: String(children).replace(/\n$/, ""),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
activeTab={"0"}
|
||||||
|
setActiveTab={() => {}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<code className={className} {...props}>
|
<code className={className} {...props}>
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ export default function FormModal({
|
||||||
setOpen,
|
setOpen,
|
||||||
}: {
|
}: {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
setOpen: Function;
|
setOpen: (open: boolean) => void;
|
||||||
flow: FlowType;
|
flow: FlowType;
|
||||||
}) {
|
}) {
|
||||||
const { tabsState, setTabsState } = useContext(TabsContext);
|
const { tabsState, setTabsState } = useContext(TabsContext);
|
||||||
|
|
@ -386,8 +386,8 @@ export default function FormModal({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={setModalOpen}>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
<DialogTrigger className="hidden"></DialogTrigger>
|
<DialogTrigger hidden></DialogTrigger>
|
||||||
{tabsState[flow.id].formKeysData && (
|
{tabsState[flow.id].formKeysData && (
|
||||||
<DialogContent className="min-w-[80vw]">
|
<DialogContent className="min-w-[80vw]">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
import { useContext, useEffect, useRef, useState } from "react";
|
import { ReactNode, useContext, useEffect, useRef, useState } from "react";
|
||||||
import SanitizedHTMLWrapper from "../../components/SanitizedHTMLWrapper";
|
import SanitizedHTMLWrapper from "../../components/SanitizedHTMLWrapper";
|
||||||
import ShadTooltip from "../../components/ShadTooltipComponent";
|
import ShadTooltip from "../../components/ShadTooltipComponent";
|
||||||
import IconComponent from "../../components/genericIconComponent";
|
import IconComponent from "../../components/genericIconComponent";
|
||||||
import { Badge } from "../../components/ui/badge";
|
import { Badge } from "../../components/ui/badge";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
import { DialogTitle } from "../../components/ui/dialog";
|
|
||||||
import { Textarea } from "../../components/ui/textarea";
|
import { Textarea } from "../../components/ui/textarea";
|
||||||
import {
|
import {
|
||||||
INVALID_CHARACTERS,
|
INVALID_CHARACTERS,
|
||||||
|
|
@ -15,8 +14,6 @@ import {
|
||||||
} from "../../constants/constants";
|
} from "../../constants/constants";
|
||||||
import { TypeModal } from "../../constants/enums";
|
import { TypeModal } from "../../constants/enums";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
import { darkContext } from "../../contexts/darkContext";
|
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import { postValidatePrompt } from "../../controllers/API";
|
import { postValidatePrompt } from "../../controllers/API";
|
||||||
import { APIClassType } from "../../types/api";
|
import { APIClassType } from "../../types/api";
|
||||||
import {
|
import {
|
||||||
|
|
@ -35,6 +32,7 @@ export default function GenericModal({
|
||||||
type,
|
type,
|
||||||
nodeClass,
|
nodeClass,
|
||||||
setNodeClass,
|
setNodeClass,
|
||||||
|
children,
|
||||||
}: {
|
}: {
|
||||||
field_name?: string;
|
field_name?: string;
|
||||||
setValue: (value: string) => void;
|
setValue: (value: string) => void;
|
||||||
|
|
@ -42,6 +40,7 @@ export default function GenericModal({
|
||||||
buttonText: string;
|
buttonText: string;
|
||||||
modalTitle: string;
|
modalTitle: string;
|
||||||
type: number;
|
type: number;
|
||||||
|
children: ReactNode;
|
||||||
nodeClass?: APIClassType;
|
nodeClass?: APIClassType;
|
||||||
setNodeClass?: (Class: APIClassType) => void;
|
setNodeClass?: (Class: APIClassType) => void;
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -51,17 +50,9 @@ export default function GenericModal({
|
||||||
const [inputValue, setInputValue] = useState(value);
|
const [inputValue, setInputValue] = useState(value);
|
||||||
const [isEdit, setIsEdit] = useState(true);
|
const [isEdit, setIsEdit] = useState(true);
|
||||||
const [wordsHighlight, setWordsHighlight] = useState([]);
|
const [wordsHighlight, setWordsHighlight] = useState([]);
|
||||||
const { dark } = useContext(darkContext);
|
|
||||||
const { setErrorData, setSuccessData, setNoticeData } =
|
const { setErrorData, setSuccessData, setNoticeData } =
|
||||||
useContext(alertContext);
|
useContext(alertContext);
|
||||||
const { closePopUp, setCloseEdit } = useContext(PopUpContext);
|
|
||||||
const ref = useRef();
|
const ref = useRef();
|
||||||
function setModalOpen(x: boolean) {
|
|
||||||
if (x === false) {
|
|
||||||
setCloseEdit("generic");
|
|
||||||
closePopUp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const divRef = useRef(null);
|
const divRef = useRef(null);
|
||||||
const divRefPrompt = useRef(null);
|
const divRefPrompt = useRef(null);
|
||||||
|
|
||||||
|
|
@ -105,6 +96,10 @@ export default function GenericModal({
|
||||||
}
|
}
|
||||||
}, [inputValue, type]);
|
}, [inputValue, type]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setInputValue(value);
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
const coloredContent = (inputValue || "")
|
const coloredContent = (inputValue || "")
|
||||||
.replace(/</g, "<")
|
.replace(/</g, "<")
|
||||||
.replace(/>/g, ">")
|
.replace(/>/g, ">")
|
||||||
|
|
@ -138,7 +133,6 @@ export default function GenericModal({
|
||||||
postValidatePrompt(field_name, inputValue, nodeClass)
|
postValidatePrompt(field_name, inputValue, nodeClass)
|
||||||
.then((apiReturn) => {
|
.then((apiReturn) => {
|
||||||
if (apiReturn.data) {
|
if (apiReturn.data) {
|
||||||
setNodeClass(apiReturn.data?.frontend_node);
|
|
||||||
let inputVariables = apiReturn.data.input_variables ?? [];
|
let inputVariables = apiReturn.data.input_variables ?? [];
|
||||||
if (inputVariables && inputVariables.length === 0) {
|
if (inputVariables && inputVariables.length === 0) {
|
||||||
setIsEdit(true);
|
setIsEdit(true);
|
||||||
|
|
@ -150,6 +144,7 @@ export default function GenericModal({
|
||||||
setSuccessData({
|
setSuccessData({
|
||||||
title: "Prompt is ready",
|
title: "Prompt is ready",
|
||||||
});
|
});
|
||||||
|
setNodeClass(apiReturn.data?.frontend_node);
|
||||||
setModalOpen(closeModal);
|
setModalOpen(closeModal);
|
||||||
setValue(inputValue);
|
setValue(inputValue);
|
||||||
}
|
}
|
||||||
|
|
@ -170,8 +165,11 @@ export default function GenericModal({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseModal open={true} setOpen={setModalOpen}>
|
<BaseModal open={modalOpen} setOpen={setModalOpen}>
|
||||||
|
<BaseModal.Trigger>{children}</BaseModal.Trigger>
|
||||||
<BaseModal.Header
|
<BaseModal.Header
|
||||||
description={(() => {
|
description={(() => {
|
||||||
switch (myModalTitle) {
|
switch (myModalTitle) {
|
||||||
|
|
@ -186,14 +184,12 @@ export default function GenericModal({
|
||||||
}
|
}
|
||||||
})()}
|
})()}
|
||||||
>
|
>
|
||||||
<DialogTitle className="flex items-center">
|
|
||||||
<span className="pr-2">{myModalTitle}</span>
|
<span className="pr-2">{myModalTitle}</span>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="FileText"
|
name="FileText"
|
||||||
className="h-6 w-6 pl-1 text-primary "
|
className="h-6 w-6 pl-1 text-primary "
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</DialogTitle>
|
|
||||||
</BaseModal.Header>
|
</BaseModal.Header>
|
||||||
<BaseModal.Content>
|
<BaseModal.Content>
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full flex-col">
|
||||||
|
|
@ -277,7 +273,7 @@ export default function GenericModal({
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span className="mt-1 text-xs text-muted-foreground">
|
<span className="mt-2 text-xs text-muted-foreground">
|
||||||
Prompt variables can be created with any chosen name inside
|
Prompt variables can be created with any chosen name inside
|
||||||
curly brackets, e.g. {"{variable_name}"}
|
curly brackets, e.g. {"{variable_name}"}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -287,11 +283,11 @@ export default function GenericModal({
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
switch (myModalType) {
|
switch (myModalType) {
|
||||||
case 1:
|
case TypeModal.TEXT:
|
||||||
setValue(inputValue);
|
setValue(inputValue);
|
||||||
setModalOpen(false);
|
setModalOpen(false);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case TypeModal.PROMPT:
|
||||||
!inputValue || inputValue === ""
|
!inputValue || inputValue === ""
|
||||||
? setModalOpen(false)
|
? setModalOpen(false)
|
||||||
: validatePrompt(false);
|
: validatePrompt(false);
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ import {
|
||||||
} from "../../components/ui/dialog";
|
} from "../../components/ui/dialog";
|
||||||
import { IMPORT_DIALOG_SUBTITLE } from "../../constants/constants";
|
import { IMPORT_DIALOG_SUBTITLE } from "../../constants/constants";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
import { getExamples } from "../../controllers/API";
|
import { getExamples } from "../../controllers/API";
|
||||||
import { FlowType } from "../../types/flow";
|
import { FlowType } from "../../types/flow";
|
||||||
|
|
@ -27,20 +26,11 @@ import ButtonBox from "./buttonBox";
|
||||||
export default function ImportModal() {
|
export default function ImportModal() {
|
||||||
const [open, setOpen] = useState(true);
|
const [open, setOpen] = useState(true);
|
||||||
const { setErrorData } = useContext(alertContext);
|
const { setErrorData } = useContext(alertContext);
|
||||||
const { closePopUp } = useContext(PopUpContext);
|
|
||||||
const ref = useRef();
|
const ref = useRef();
|
||||||
const [showExamples, setShowExamples] = useState(false);
|
const [showExamples, setShowExamples] = useState(false);
|
||||||
const [loadingExamples, setLoadingExamples] = useState(false);
|
const [loadingExamples, setLoadingExamples] = useState(false);
|
||||||
const [examples, setExamples] = useState<FlowType[]>([]);
|
const [examples, setExamples] = useState<FlowType[]>([]);
|
||||||
const { uploadFlow, addFlow } = useContext(TabsContext);
|
const { uploadFlow, addFlow } = useContext(TabsContext);
|
||||||
function setModalOpen(x: boolean) {
|
|
||||||
setOpen(x);
|
|
||||||
if (x === false) {
|
|
||||||
setTimeout(() => {
|
|
||||||
closePopUp();
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleExamples() {
|
function handleExamples() {
|
||||||
setLoadingExamples(true);
|
setLoadingExamples(true);
|
||||||
|
|
@ -57,8 +47,10 @@ export default function ImportModal() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={true} onOpenChange={setModalOpen}>
|
<Dialog open={modalOpen} onOpenChange={setModalOpen}>
|
||||||
<DialogTrigger></DialogTrigger>
|
<DialogTrigger></DialogTrigger>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import { undoRedoContext } from "../../../../contexts/undoRedoContext";
|
||||||
import { APIClassType } from "../../../../types/api";
|
import { APIClassType } from "../../../../types/api";
|
||||||
import { FlowType, NodeType } from "../../../../types/flow";
|
import { FlowType, NodeType } from "../../../../types/flow";
|
||||||
import { isValidConnection } from "../../../../utils/reactflowUtils";
|
import { isValidConnection } from "../../../../utils/reactflowUtils";
|
||||||
|
import { isWrappedWithClass } from "../../../../utils/utils";
|
||||||
import ConnectionLineComponent from "../ConnectionLineComponent";
|
import ConnectionLineComponent from "../ConnectionLineComponent";
|
||||||
import ExtraSidebar from "../extraSidebarComponent";
|
import ExtraSidebar from "../extraSidebarComponent";
|
||||||
|
|
||||||
|
|
@ -38,7 +39,6 @@ export default function Page({ flow }: { flow: FlowType }) {
|
||||||
let {
|
let {
|
||||||
updateFlow,
|
updateFlow,
|
||||||
uploadFlow,
|
uploadFlow,
|
||||||
disableCopyPaste,
|
|
||||||
addFlow,
|
addFlow,
|
||||||
getNodeId,
|
getNodeId,
|
||||||
paste,
|
paste,
|
||||||
|
|
@ -63,11 +63,11 @@ export default function Page({ flow }: { flow: FlowType }) {
|
||||||
// this effect is used to attach the global event handlers
|
// this effect is used to attach the global event handlers
|
||||||
|
|
||||||
const onKeyDown = (event: KeyboardEvent) => {
|
const onKeyDown = (event: KeyboardEvent) => {
|
||||||
|
if (!isWrappedWithClass(event, "nocopy")) {
|
||||||
if (
|
if (
|
||||||
(event.ctrlKey || event.metaKey) &&
|
(event.ctrlKey || event.metaKey) &&
|
||||||
event.key === "c" &&
|
event.key === "c" &&
|
||||||
lastSelection &&
|
lastSelection
|
||||||
!disableCopyPaste
|
|
||||||
) {
|
) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setLastCopiedSelection(_.cloneDeep(lastSelection));
|
setLastCopiedSelection(_.cloneDeep(lastSelection));
|
||||||
|
|
@ -75,8 +75,7 @@ export default function Page({ flow }: { flow: FlowType }) {
|
||||||
if (
|
if (
|
||||||
(event.ctrlKey || event.metaKey) &&
|
(event.ctrlKey || event.metaKey) &&
|
||||||
event.key === "v" &&
|
event.key === "v" &&
|
||||||
lastCopiedSelection &&
|
lastCopiedSelection
|
||||||
!disableCopyPaste
|
|
||||||
) {
|
) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let bounds = reactFlowWrapper.current.getBoundingClientRect();
|
let bounds = reactFlowWrapper.current.getBoundingClientRect();
|
||||||
|
|
@ -92,6 +91,7 @@ export default function Page({ flow }: { flow: FlowType }) {
|
||||||
) {
|
) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const handleMouseMove = (event) => {
|
const handleMouseMove = (event) => {
|
||||||
setPosition({ x: event.clientX, y: event.clientY });
|
setPosition({ x: event.clientX, y: event.clientY });
|
||||||
|
|
@ -124,7 +124,7 @@ export default function Page({ flow }: { flow: FlowType }) {
|
||||||
updateFlow(flow);
|
updateFlow(flow);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [nodes, edges]);
|
}, [edges]);
|
||||||
//update flow when tabs change
|
//update flow when tabs change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setNodes(flow?.data?.nodes ?? []);
|
setNodes(flow?.data?.nodes ?? []);
|
||||||
|
|
@ -355,8 +355,6 @@ export default function Page({ flow }: { flow: FlowType }) {
|
||||||
setLastSelection(flow);
|
setLastSelection(flow);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const { setDisableCopyPaste } = useContext(TabsContext);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full overflow-hidden">
|
<div className="flex h-full overflow-hidden">
|
||||||
<ExtraSidebar />
|
<ExtraSidebar />
|
||||||
|
|
@ -378,15 +376,6 @@ export default function Page({ flow }: { flow: FlowType }) {
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
edges={edges}
|
edges={edges}
|
||||||
onPaneClick={() => {
|
|
||||||
setDisableCopyPaste(false);
|
|
||||||
}}
|
|
||||||
onPaneMouseLeave={() => {
|
|
||||||
setDisableCopyPaste(true);
|
|
||||||
}}
|
|
||||||
onPaneMouseEnter={() => {
|
|
||||||
setDisableCopyPaste(false);
|
|
||||||
}}
|
|
||||||
onNodesChange={onNodesChangeMod}
|
onNodesChange={onNodesChangeMod}
|
||||||
onEdgesChange={onEdgesChangeMod}
|
onEdgesChange={onEdgesChangeMod}
|
||||||
onConnect={onConnect}
|
onConnect={onConnect}
|
||||||
|
|
@ -407,9 +396,6 @@ export default function Page({ flow }: { flow: FlowType }) {
|
||||||
onDrop={onDrop}
|
onDrop={onDrop}
|
||||||
onNodesDelete={onDelete}
|
onNodesDelete={onDelete}
|
||||||
onSelectionChange={onSelectionChange}
|
onSelectionChange={onSelectionChange}
|
||||||
nodesDraggable={!disableCopyPaste}
|
|
||||||
panOnDrag={!disableCopyPaste}
|
|
||||||
zoomOnDoubleClick={!disableCopyPaste}
|
|
||||||
className="theme-attribution"
|
className="theme-attribution"
|
||||||
minZoom={0.01}
|
minZoom={0.01}
|
||||||
maxZoom={8}
|
maxZoom={8}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
import { Search } from "lucide-react";
|
|
||||||
import { useContext, useState } from "react";
|
import { useContext, useState } from "react";
|
||||||
import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
||||||
import IconComponent from "../../../../components/genericIconComponent";
|
import IconComponent from "../../../../components/genericIconComponent";
|
||||||
import { Separator } from "../../../../components/ui/separator";
|
import { Separator } from "../../../../components/ui/separator";
|
||||||
import { alertContext } from "../../../../contexts/alertContext";
|
import { alertContext } from "../../../../contexts/alertContext";
|
||||||
import { PopUpContext } from "../../../../contexts/popUpContext";
|
|
||||||
import { TabsContext } from "../../../../contexts/tabsContext";
|
import { TabsContext } from "../../../../contexts/tabsContext";
|
||||||
import { typesContext } from "../../../../contexts/typesContext";
|
import { typesContext } from "../../../../contexts/typesContext";
|
||||||
import ApiModal from "../../../../modals/ApiModal";
|
import ApiModal from "../../../../modals/ApiModal";
|
||||||
|
|
@ -20,7 +18,6 @@ import DisclosureComponent from "../DisclosureComponent";
|
||||||
|
|
||||||
export default function ExtraSidebar() {
|
export default function ExtraSidebar() {
|
||||||
const { data } = useContext(typesContext);
|
const { data } = useContext(typesContext);
|
||||||
const { openPopUp } = useContext(PopUpContext);
|
|
||||||
const { flows, tabId, uploadFlow, tabsState, saveFlow } =
|
const { flows, tabId, uploadFlow, tabsState, saveFlow } =
|
||||||
useContext(TabsContext);
|
useContext(TabsContext);
|
||||||
const { setSuccessData, setErrorData } = useContext(alertContext);
|
const { setSuccessData, setErrorData } = useContext(alertContext);
|
||||||
|
|
@ -58,6 +55,7 @@ export default function ExtraSidebar() {
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const flow = flows.find((f) => f.id === tabId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="side-bar-arrangement">
|
<div className="side-bar-arrangement">
|
||||||
|
|
@ -74,31 +72,27 @@ export default function ExtraSidebar() {
|
||||||
</ShadTooltip>
|
</ShadTooltip>
|
||||||
|
|
||||||
<ShadTooltip content="Export" side="top">
|
<ShadTooltip content="Export" side="top">
|
||||||
<button
|
<ExportModal>
|
||||||
className={classNames("extra-side-bar-buttons")}
|
<div className={classNames("extra-side-bar-buttons")}>
|
||||||
onClick={(event) => {
|
|
||||||
openPopUp(<ExportModal />);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<IconComponent name="FileDown" className="side-bar-button-size" />
|
<IconComponent name="FileDown" className="side-bar-button-size" />
|
||||||
</button>
|
</div>
|
||||||
|
</ExportModal>
|
||||||
</ShadTooltip>
|
</ShadTooltip>
|
||||||
<ShadTooltip content="Code" side="top">
|
<ShadTooltip content="Code" side="top">
|
||||||
<button
|
{flow && flow.data && (
|
||||||
className={classNames("extra-side-bar-buttons")}
|
<ApiModal flow={flow}>
|
||||||
onClick={(event) => {
|
<div className={classNames("extra-side-bar-buttons")}>
|
||||||
openPopUp(<ApiModal flow={flows.find((f) => f.id === tabId)} />);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<IconComponent name="Code2" className="side-bar-button-size" />
|
<IconComponent name="Code2" className="side-bar-button-size" />
|
||||||
</button>
|
</div>
|
||||||
|
</ApiModal>
|
||||||
|
)}
|
||||||
</ShadTooltip>
|
</ShadTooltip>
|
||||||
|
|
||||||
<ShadTooltip content="Save" side="top">
|
<ShadTooltip content="Save" side="top">
|
||||||
<button
|
<button
|
||||||
className="extra-side-bar-buttons"
|
className="extra-side-bar-buttons"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
saveFlow(flows.find((f) => f.id === tabId));
|
saveFlow(flow);
|
||||||
setSuccessData({ title: "Changes saved successfully" });
|
setSuccessData({ title: "Changes saved successfully" });
|
||||||
}}
|
}}
|
||||||
disabled={!isPending}
|
disabled={!isPending}
|
||||||
|
|
@ -120,7 +114,7 @@ export default function ExtraSidebar() {
|
||||||
name="search"
|
name="search"
|
||||||
id="search"
|
id="search"
|
||||||
placeholder="Search"
|
placeholder="Search"
|
||||||
className="input-search"
|
className="nopan nodrag noundo nocopy input-search"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
handleSearchInput(e.target.value);
|
handleSearchInput(e.target.value);
|
||||||
// Set search input state
|
// Set search input state
|
||||||
|
|
@ -128,7 +122,11 @@ export default function ExtraSidebar() {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="search-icon">
|
<div className="search-icon">
|
||||||
<Search size={20} strokeWidth={1.5} className="text-primary" />
|
<IconComponent
|
||||||
|
name="Search"
|
||||||
|
className={"h-5 w-5 stroke-[1.5] text-primary"}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,24 +6,24 @@ import { TabsContext } from "../../../../contexts/tabsContext";
|
||||||
import EditNodeModal from "../../../../modals/EditNodeModal";
|
import EditNodeModal from "../../../../modals/EditNodeModal";
|
||||||
import { classNames } from "../../../../utils/utils";
|
import { classNames } from "../../../../utils/utils";
|
||||||
|
|
||||||
const NodeToolbarComponent = (props) => {
|
export default function NodeToolbarComponent({ data, setData, deleteNode }) {
|
||||||
const [nodeLength, setNodeLength] = useState(
|
const [nodeLength, setNodeLength] = useState(
|
||||||
Object.keys(props.data.node.template).filter(
|
Object.keys(data.node.template).filter(
|
||||||
(t) =>
|
(t) =>
|
||||||
t.charAt(0) !== "_" &&
|
t.charAt(0) !== "_" &&
|
||||||
props.data.node.template[t].show &&
|
data.node.template[t].show &&
|
||||||
(props.data.node.template[t].type === "str" ||
|
(data.node.template[t].type === "str" ||
|
||||||
props.data.node.template[t].type === "bool" ||
|
data.node.template[t].type === "bool" ||
|
||||||
props.data.node.template[t].type === "float" ||
|
data.node.template[t].type === "float" ||
|
||||||
props.data.node.template[t].type === "code" ||
|
data.node.template[t].type === "code" ||
|
||||||
props.data.node.template[t].type === "prompt" ||
|
data.node.template[t].type === "prompt" ||
|
||||||
props.data.node.template[t].type === "file" ||
|
data.node.template[t].type === "file" ||
|
||||||
props.data.node.template[t].type === "Any" ||
|
data.node.template[t].type === "Any" ||
|
||||||
props.data.node.template[t].type === "int")
|
data.node.template[t].type === "int")
|
||||||
).length
|
).length
|
||||||
);
|
);
|
||||||
|
|
||||||
const { setLastCopiedSelection, paste } = useContext(TabsContext);
|
const { paste } = useContext(TabsContext);
|
||||||
const reactFlowInstance = useReactFlow();
|
const reactFlowInstance = useReactFlow();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -33,7 +33,7 @@ const NodeToolbarComponent = (props) => {
|
||||||
<button
|
<button
|
||||||
className="relative inline-flex items-center rounded-l-md 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"
|
className="relative inline-flex items-center rounded-l-md 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"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
props.deleteNode(props.data.id);
|
deleteNode(data.id);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconComponent name="Trash2" className="h-4 w-4" />
|
<IconComponent name="Trash2" className="h-4 w-4" />
|
||||||
|
|
@ -49,14 +49,14 @@ const NodeToolbarComponent = (props) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
paste(
|
paste(
|
||||||
{
|
{
|
||||||
nodes: [reactFlowInstance.getNode(props.data.id)],
|
nodes: [reactFlowInstance.getNode(data.id)],
|
||||||
edges: [],
|
edges: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: 50,
|
x: 50,
|
||||||
y: 10,
|
y: 10,
|
||||||
paneX: reactFlowInstance.getNode(props.data.id).position.x,
|
paneX: reactFlowInstance.getNode(data.id).position.x,
|
||||||
paneY: reactFlowInstance.getNode(props.data.id).position.y,
|
paneY: reactFlowInstance.getNode(data.id).position.y,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
|
@ -67,25 +67,23 @@ const NodeToolbarComponent = (props) => {
|
||||||
|
|
||||||
<ShadTooltip
|
<ShadTooltip
|
||||||
content={
|
content={
|
||||||
props.data.node.documentation === ""
|
data.node.documentation === "" ? "Coming Soon" : "Documentation"
|
||||||
? "Coming Soon"
|
|
||||||
: "Documentation"
|
|
||||||
}
|
}
|
||||||
side="top"
|
side="top"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
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" +
|
||||||
(props.data.node.documentation === ""
|
(data.node.documentation === ""
|
||||||
? " text-muted-foreground"
|
? " text-muted-foreground"
|
||||||
: " text-foreground")
|
: " text-foreground")
|
||||||
)}
|
)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
href={props.data.node.documentation}
|
href={data.node.documentation}
|
||||||
// deactivate link if no documentation is provided
|
// deactivate link if no documentation is provided
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
if (props.data.node.documentation === "") {
|
if (data.node.documentation === "") {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
@ -95,28 +93,27 @@ const NodeToolbarComponent = (props) => {
|
||||||
</ShadTooltip>
|
</ShadTooltip>
|
||||||
|
|
||||||
<ShadTooltip content="Edit" side="top">
|
<ShadTooltip content="Edit" side="top">
|
||||||
<button
|
<div>
|
||||||
|
<EditNodeModal
|
||||||
|
data={data}
|
||||||
|
setData={setData}
|
||||||
|
nodeLength={nodeLength}
|
||||||
|
>
|
||||||
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"relative -ml-px inline-flex items-center rounded-r-md 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 rounded-r-md 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" +
|
||||||
(nodeLength == 0
|
(nodeLength == 0
|
||||||
? " text-muted-foreground"
|
? " text-muted-foreground"
|
||||||
: " text-foreground")
|
: " text-foreground")
|
||||||
)}
|
)}
|
||||||
onClick={(event) => {
|
|
||||||
if (nodeLength == 0) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
event.preventDefault();
|
|
||||||
props.openPopUp(<EditNodeModal data={props.data} />);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<IconComponent name="Settings2" className="h-4 w-4 " />
|
<IconComponent name="Settings2" className="h-4 w-4 " />
|
||||||
</button>
|
</div>
|
||||||
|
</EditNodeModal>
|
||||||
|
</div>
|
||||||
</ShadTooltip>
|
</ShadTooltip>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
export default NodeToolbarComponent;
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ export type InputComponentType = {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
password: boolean;
|
password: boolean;
|
||||||
disableCopyPaste?: boolean;
|
|
||||||
editNode?: boolean;
|
editNode?: boolean;
|
||||||
onChangePass?: (value: boolean | boolean) => void;
|
onChangePass?: (value: boolean | boolean) => void;
|
||||||
showPass?: boolean;
|
showPass?: boolean;
|
||||||
|
|
@ -28,6 +27,7 @@ export type DropDownComponentType = {
|
||||||
};
|
};
|
||||||
export type ParameterComponentType = {
|
export type ParameterComponentType = {
|
||||||
data: NodeDataType;
|
data: NodeDataType;
|
||||||
|
setData: (value: NodeDataType) => void;
|
||||||
title: string;
|
title: string;
|
||||||
id: string;
|
id: string;
|
||||||
color: string;
|
color: string;
|
||||||
|
|
@ -45,7 +45,6 @@ export type InputListComponentType = {
|
||||||
onChange: (value: string[]) => void;
|
onChange: (value: string[]) => void;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
editNode?: boolean;
|
editNode?: boolean;
|
||||||
onAddInput?: (value?: string[]) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TextAreaComponentType = {
|
export type TextAreaComponentType = {
|
||||||
|
|
@ -93,7 +92,6 @@ export type DisclosureComponentType = {
|
||||||
export type FloatComponentType = {
|
export type FloatComponentType = {
|
||||||
value: string;
|
value: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
disableCopyPaste?: boolean;
|
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
editNode?: boolean;
|
editNode?: boolean;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,6 @@ export type TabsContextType = {
|
||||||
uploadFlows: () => void;
|
uploadFlows: () => void;
|
||||||
uploadFlow: (newFlow?: boolean, file?: File) => void;
|
uploadFlow: (newFlow?: boolean, file?: File) => void;
|
||||||
hardReset: () => void;
|
hardReset: () => void;
|
||||||
//disable CopyPaste
|
|
||||||
disableCopyPaste: boolean;
|
|
||||||
setDisableCopyPaste: (value: boolean) => void;
|
|
||||||
getNodeId: (nodeType: string) => string;
|
getNodeId: (nodeType: string) => string;
|
||||||
tabsState: TabsState;
|
tabsState: TabsState;
|
||||||
setTabsState: Dispatch<SetStateAction<TabsState>>;
|
setTabsState: Dispatch<SetStateAction<TabsState>>;
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ import {
|
||||||
MessageSquare,
|
MessageSquare,
|
||||||
MessagesSquare,
|
MessagesSquare,
|
||||||
MoonIcon,
|
MoonIcon,
|
||||||
|
MoreHorizontal,
|
||||||
Paperclip,
|
Paperclip,
|
||||||
Plus,
|
Plus,
|
||||||
Redo,
|
Redo,
|
||||||
|
|
@ -268,6 +269,7 @@ export const nodeIconsLucide = {
|
||||||
Copy,
|
Copy,
|
||||||
Upload,
|
Upload,
|
||||||
MessageSquare,
|
MessageSquare,
|
||||||
|
MoreHorizontal,
|
||||||
};
|
};
|
||||||
export function getConnectedNodes(edge: Edge, nodes: Array<Node>): Array<Node> {
|
export function getConnectedNodes(edge: Edge, nodes: Array<Node>): Array<Node> {
|
||||||
const sourceId = edge.source;
|
const sourceId = edge.source;
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,9 @@ export function checkUpperWords(str: string) {
|
||||||
return words.join(" ");
|
return words.join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const isWrappedWithClass = (event: any, className: string | undefined) =>
|
||||||
|
event.target.closest(`.${className}`);
|
||||||
|
|
||||||
export function groupByFamily(data, baseClasses, left, type) {
|
export function groupByFamily(data, baseClasses, left, type) {
|
||||||
let parentOutput: string;
|
let parentOutput: string;
|
||||||
let arrOfParent: string[] = [];
|
let arrOfParent: string[] = [];
|
||||||
|
|
@ -272,7 +275,7 @@ export function buildTweakObject(tweak) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const tweakString = JSON.stringify(tweak, null, 2);
|
const tweakString = JSON.stringify(tweak.at(-1), null, 2);
|
||||||
return tweakString;
|
return tweakString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue