🔨 refactor(flows.py): change response model of update_flow endpoint to FlowRead
🔨 refactor(parameterComponent): remove unused imports and refactor onChange function to handleOnNewValue ✨ feat(tabsContext): add tabsState and setTabsState to TabsContextType and TabsProvider 🔨 refactor(flowSettingsModal): refactor handleSaveFlow function to update flow and setTabsState with isPending false The update_flow endpoint now returns a FlowRead response model instead of FlowReadWithStyle. The parameterComponent file has been refactored to remove unused imports and to use a handleOnNewValue function to handle onChange events. The TabsContextType and TabsProvider have been updated to include tabsState and setTabsState. The flowSettingsModal has been refactored to update the flow and setTabsState with isPending false. 🔨 refactor(extraSidebarComponent): add tabsState and setTabsState to TabsContextType 🐛 fix(extraSidebarComponent): disable save button when flow is not pending 🐛 fix(extraSidebarComponent): update flow state after saving The TabsContextType now includes tabsState and setTabsState to allow for the management of the state of each tab. The save button is now disabled when the flow is not pending. The flow state is now updated after saving to reflect the changes made.
This commit is contained in:
parent
499d5238e3
commit
03076b3577
6 changed files with 78 additions and 59 deletions
|
|
@ -49,7 +49,7 @@ def read_flow(*, session: Session = Depends(get_session), flow_id: UUID):
|
|||
raise HTTPException(status_code=404, detail="Flow not found")
|
||||
|
||||
|
||||
@router.patch("/{flow_id}", response_model=FlowReadWithStyle, status_code=200)
|
||||
@router.patch("/{flow_id}", response_model=FlowRead, status_code=200)
|
||||
def update_flow(
|
||||
*, session: Session = Depends(get_session), flow_id: UUID, flow: FlowUpdate
|
||||
):
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
import { Handle, Position, useUpdateNodeInternals } from "reactflow";
|
||||
import Tooltip from "../../../../components/TooltipComponent";
|
||||
import {
|
||||
classNames,
|
||||
groupByFamily,
|
||||
isValidConnection,
|
||||
toFirstUpperCase,
|
||||
} from "../../../../utils";
|
||||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
import InputComponent from "../../../../components/inputComponent";
|
||||
import ToggleComponent from "../../../../components/toggleComponent";
|
||||
import InputListComponent from "../../../../components/inputListComponent";
|
||||
import TextAreaComponent from "../../../../components/textAreaComponent";
|
||||
import { typesContext } from "../../../../contexts/typesContext";
|
||||
|
|
@ -43,6 +40,7 @@ export default function ParameterComponent({
|
|||
const updateNodeInternals = useUpdateNodeInternals();
|
||||
const [position, setPosition] = useState(0);
|
||||
const { closePopUp } = useContext(PopUpContext);
|
||||
const { setTabsState, tabId } = useContext(TabsContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (ref.current && ref.current.offsetTop && ref.current.clientHeight) {
|
||||
|
|
@ -66,6 +64,19 @@ export default function ParameterComponent({
|
|||
reactFlowInstance?.getEdges().some((e) => e.targetHandle === id) ?? false;
|
||||
const [myData, setMyData] = useState(useContext(typesContext).data);
|
||||
|
||||
const handleOnNewValue = (newValue: any) => {
|
||||
data.node.template[name].value = newValue;
|
||||
// Set state to pending
|
||||
setTabsState((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
[tabId]: {
|
||||
isPending: true,
|
||||
},
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const groupedObj = groupByFamily(myData, tooltipTitle);
|
||||
|
||||
|
|
@ -165,17 +176,13 @@ export default function ParameterComponent({
|
|||
? [""]
|
||||
: data.node.template[name].value
|
||||
}
|
||||
onChange={(t: string[]) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
/>
|
||||
) : data.node.template[name].multiline ? (
|
||||
<TextAreaComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
/>
|
||||
) : (
|
||||
<InputComponent
|
||||
|
|
@ -183,9 +190,7 @@ export default function ParameterComponent({
|
|||
disableCopyPaste={true}
|
||||
password={data.node.template[name].password ?? false}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -195,7 +200,7 @@ export default function ParameterComponent({
|
|||
disabled={disabled}
|
||||
enabled={enabled}
|
||||
setEnabled={(t) => {
|
||||
data.node.template[name].value = t;
|
||||
handleOnNewValue(t);
|
||||
setEnabled(t);
|
||||
}}
|
||||
size="large"
|
||||
|
|
@ -207,9 +212,7 @@ export default function ParameterComponent({
|
|||
disabled={disabled}
|
||||
disableCopyPaste={true}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
/>
|
||||
</div>
|
||||
) : left === true &&
|
||||
|
|
@ -218,9 +221,7 @@ export default function ParameterComponent({
|
|||
<div className="w-full">
|
||||
<Dropdown
|
||||
options={data.node.template[name].options}
|
||||
onSelect={(newValue) =>
|
||||
(data.node.template[name].value = newValue)
|
||||
}
|
||||
onSelect={handleOnNewValue}
|
||||
value={data.node.template[name].value ?? "Choose an option"}
|
||||
></Dropdown>
|
||||
</div>
|
||||
|
|
@ -228,17 +229,13 @@ export default function ParameterComponent({
|
|||
<CodeAreaComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
/>
|
||||
) : left === true && type === "file" ? (
|
||||
<InputFileComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
fileTypes={data.node.template[name].fileTypes}
|
||||
suffixes={data.node.template[name].suffixes}
|
||||
onFileChange={(t: string) => {
|
||||
|
|
@ -251,18 +248,14 @@ export default function ParameterComponent({
|
|||
disabled={disabled}
|
||||
disableCopyPaste={true}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
/>
|
||||
</div>
|
||||
) : left === true && type === "prompt" ? (
|
||||
<PromptAreaComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
useContext,
|
||||
} from "react";
|
||||
import { FlowType, NodeType } from "../types/flow";
|
||||
import { TabsContextType } from "../types/tabs";
|
||||
import { TabsContextType, TabsState } from "../types/tabs";
|
||||
import { updateIds, updateTemplate } from "../utils";
|
||||
import { alertContext } from "./alertContext";
|
||||
import { typesContext } from "./typesContext";
|
||||
|
|
@ -43,7 +43,8 @@ const TabsContextInitialValue: TabsContextType = {
|
|||
setDisableCopyPaste: (state: boolean) => {},
|
||||
lastCopiedSelection: null,
|
||||
setLastCopiedSelection: (selection: any) => {},
|
||||
|
||||
tabsState: {},
|
||||
setTabsState: (state: TabsState) => {},
|
||||
getNodeId: (nodeType: string) => "",
|
||||
paste: (
|
||||
selection: { nodes: any; edges: any },
|
||||
|
|
@ -64,6 +65,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
const [id, setId] = useState(uid());
|
||||
const { templates, reactFlowInstance } = useContext(typesContext);
|
||||
const [lastCopiedSelection, setLastCopiedSelection] = useState(null);
|
||||
const [tabsState, setTabsState] = useState<TabsState>({});
|
||||
|
||||
const newNodeId = useRef(uid());
|
||||
function incrementNodeId() {
|
||||
|
|
@ -534,6 +536,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
description: flowData.description,
|
||||
name: flow?.name ?? "New Flow",
|
||||
data: flowData.data,
|
||||
id: "",
|
||||
});
|
||||
|
||||
const addFlowToLocalState = (newFlow) => {
|
||||
|
|
@ -582,6 +585,8 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
uploadFlows,
|
||||
uploadFlow,
|
||||
getNodeId,
|
||||
tabsState,
|
||||
setTabsState,
|
||||
paste,
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { ArrowDownTrayIcon } from "@heroicons/react/24/outline";
|
||||
import { useContext, useRef, useState } from "react";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { PopUpContext } from "../../contexts/popUpContext";
|
||||
|
|
@ -14,16 +13,16 @@ import {
|
|||
} from "../../components/ui/dialog";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { SETTINGS_DIALOG_SUBTITLE } from "../../constants";
|
||||
import { updateFlowInDatabase } from "../../controllers/API";
|
||||
import EditFlowSettings from "../../components/EditFlowSettingsComponent";
|
||||
import { Settings2 } from "lucide-react";
|
||||
import { updateFlowInDatabase } from "../../controllers/API";
|
||||
|
||||
export default function FlowSettingsModal() {
|
||||
const [open, setOpen] = useState(true);
|
||||
const { closePopUp } = useContext(PopUpContext);
|
||||
const { setErrorData, setSuccessData } = useContext(alertContext);
|
||||
const ref = useRef();
|
||||
const { flows, tabId, updateFlow } = useContext(TabsContext);
|
||||
const { flows, tabId, updateFlow, setTabsState } = useContext(TabsContext);
|
||||
const maxLength = 50;
|
||||
function setModalOpen(x: boolean) {
|
||||
setOpen(x);
|
||||
|
|
@ -34,22 +33,26 @@ export default function FlowSettingsModal() {
|
|||
}
|
||||
}
|
||||
|
||||
function handleSaveFlow(flow) {
|
||||
if (name !== "") {
|
||||
let newFlow = flows.find((f) => f.id === tabId);
|
||||
if (newFlow) {
|
||||
newFlow.name = name;
|
||||
newFlow.description = description;
|
||||
updateFlow(newFlow);
|
||||
}
|
||||
}
|
||||
async function handleSaveFlow(flow) {
|
||||
try {
|
||||
updateFlowInDatabase(flow);
|
||||
const updatedFlow = await updateFlowInDatabase(flow);
|
||||
if (updatedFlow) {
|
||||
updateFlow(updatedFlow);
|
||||
setTabsState((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
[tabId]: {
|
||||
isPending: false,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
// updateFlowStyleInDataBase(flow);
|
||||
} catch (err) {
|
||||
setErrorData(err);
|
||||
}
|
||||
}
|
||||
|
||||
const [name, setName] = useState(flows.find((f) => f.id === tabId).name);
|
||||
const [description, setDescription] = useState(
|
||||
flows.find((f) => f.id === tabId).description
|
||||
|
|
|
|||
|
|
@ -13,24 +13,23 @@ import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
|
|||
import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
||||
import { Code2, FileDown, FileUp, Save } from "lucide-react";
|
||||
import { PopUpContext } from "../../../../contexts/popUpContext";
|
||||
import ImportModal from "../../../../modals/importModal";
|
||||
import ExportModal from "../../../../modals/exportModal";
|
||||
import ApiModal from "../../../../modals/ApiModal";
|
||||
import { TabsContext } from "../../../../contexts/tabsContext";
|
||||
import { alertContext } from "../../../../contexts/alertContext";
|
||||
import { updateFlowInDatabase } from "../../../../controllers/API";
|
||||
import { INPUT_STYLE } from "../../../../constants";
|
||||
import { Input } from "../../../../components/ui/input";
|
||||
import { Separator } from "../../../../components/ui/separator";
|
||||
|
||||
export default function ExtraSidebar() {
|
||||
const { data } = useContext(typesContext);
|
||||
const { openPopUp } = useContext(PopUpContext);
|
||||
const { flows, tabId, uploadFlow } = useContext(TabsContext);
|
||||
const { flows, tabId, uploadFlow, updateFlow, tabsState, setTabsState } =
|
||||
useContext(TabsContext);
|
||||
const { setSuccessData, setErrorData } = useContext(alertContext);
|
||||
const [dataFilter, setFilterData] = useState(data);
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
const isPending = tabsState[tabId]?.isPending;
|
||||
function onDragStart(
|
||||
event: React.DragEvent<any>,
|
||||
data: { type: string; node?: APIClassType }
|
||||
|
|
@ -62,9 +61,21 @@ export default function ExtraSidebar() {
|
|||
});
|
||||
}
|
||||
|
||||
function handleSaveFlow(flow) {
|
||||
async function handleSaveFlow(flow) {
|
||||
try {
|
||||
updateFlowInDatabase(flow);
|
||||
const updatedFlow = await updateFlowInDatabase(flow);
|
||||
if (updatedFlow) {
|
||||
updateFlow(updatedFlow);
|
||||
setTabsState((prev) => {
|
||||
console.log(prev);
|
||||
return {
|
||||
...prev,
|
||||
[tabId]: {
|
||||
isPending: false,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
// updateFlowStyleInDataBase(flow);
|
||||
} catch (err) {
|
||||
setErrorData(err);
|
||||
|
|
@ -118,8 +129,13 @@ export default function ExtraSidebar() {
|
|||
handleSaveFlow(flows.find((f) => f.id === tabId));
|
||||
setSuccessData({ title: "Changes saved successfully" });
|
||||
}}
|
||||
disabled={!isPending}
|
||||
>
|
||||
<Save className="w-5 h-5 dark:text-gray-300"></Save>
|
||||
<Save
|
||||
className={
|
||||
"w-5 h-5" + (isPending ? " text-muted-foreground" : " ")
|
||||
}
|
||||
></Save>
|
||||
</button>
|
||||
</ShadTooltip>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { Dispatch, SetStateAction } from "react";
|
||||
import { FlowType } from "../flow";
|
||||
|
||||
export type TabsContextType = {
|
||||
|
|
@ -18,6 +19,8 @@ export type TabsContextType = {
|
|||
disableCopyPaste: boolean;
|
||||
setDisableCopyPaste: (value: boolean) => void;
|
||||
getNodeId: (nodeType: string) => string;
|
||||
tabsState: TabsState;
|
||||
setTabsState: Dispatch<SetStateAction<TabsState>>;
|
||||
paste: (
|
||||
selection: { nodes: any; edges: any },
|
||||
position: { x: number; y: number; paneX?: number; paneY?: number }
|
||||
|
|
@ -26,9 +29,8 @@ export type TabsContextType = {
|
|||
setLastCopiedSelection: (selection: { nodes: any; edges: any }) => void;
|
||||
};
|
||||
|
||||
export type LangFlowState = {
|
||||
tabIndex: number;
|
||||
flows: FlowType[];
|
||||
id: string;
|
||||
nodeId: number;
|
||||
export type TabsState = {
|
||||
[key: string]: {
|
||||
isPending: boolean;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue