diff --git a/src/backend/base/langflow/alembic/versions/1f4d6df60295_add_default_fields_column.py b/src/backend/base/langflow/alembic/versions/1f4d6df60295_add_default_fields_column.py index 7b69058c2..7cf2fd083 100644 --- a/src/backend/base/langflow/alembic/versions/1f4d6df60295_add_default_fields_column.py +++ b/src/backend/base/langflow/alembic/versions/1f4d6df60295_add_default_fields_column.py @@ -22,7 +22,6 @@ depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: conn = op.get_bind() inspector = Inspector.from_engine(conn) # type: ignore - table_names = inspector.get_table_names() # ### commands auto generated by Alembic - please adjust! ### column_names = [column["name"] for column in inspector.get_columns("variable")] with op.batch_alter_table("variable", schema=None) as batch_op: @@ -35,7 +34,6 @@ def upgrade() -> None: def downgrade() -> None: conn = op.get_bind() inspector = Inspector.from_engine(conn) # type: ignore - table_names = inspector.get_table_names() # ### commands auto generated by Alembic - please adjust! ### column_names = [column["name"] for column in inspector.get_columns("variable")] with op.batch_alter_table("variable", schema=None) as batch_op: diff --git a/src/backend/base/langflow/alembic/versions/c153816fd85f_set_name_and_value_to_not_nullable.py b/src/backend/base/langflow/alembic/versions/c153816fd85f_set_name_and_value_to_not_nullable.py new file mode 100644 index 000000000..cec3f6081 --- /dev/null +++ b/src/backend/base/langflow/alembic/versions/c153816fd85f_set_name_and_value_to_not_nullable.py @@ -0,0 +1,52 @@ +"""Set name and value to not nullable + +Revision ID: c153816fd85f +Revises: 1f4d6df60295 +Create Date: 2024-04-30 14:31:23.898995 + +""" + +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op +from sqlalchemy.engine.reflection import Inspector + +# revision identifiers, used by Alembic. +revision: str = "c153816fd85f" +down_revision: Union[str, None] = "1f4d6df60295" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + # ### commands auto generated by Alembic - please adjust! ### + columns = inspector.get_columns("variable") + with op.batch_alter_table("variable", schema=None) as batch_op: + name_column = [column for column in columns if column["name"] == "name"][0] + if name_column and name_column["nullable"]: + batch_op.alter_column("name", existing_type=sa.VARCHAR(), nullable=False) + value_column = [column for column in columns if column["name"] == "value"][0] + if value_column and value_column["nullable"]: + batch_op.alter_column("value", existing_type=sa.VARCHAR(), nullable=False) + + +# ### end Alembic commands ### + + +def downgrade() -> None: + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + columns = inspector.get_columns("variable") + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("variable", schema=None) as batch_op: + name_column = [column for column in columns if column["name"] == "name"][0] + if name_column and not name_column["nullable"]: + batch_op.alter_column("name", existing_type=sa.VARCHAR(), nullable=True) + value_column = [column for column in columns if column["name"] == "value"][0] + if value_column and not value_column["nullable"]: + batch_op.alter_column("name", existing_type=sa.VARCHAR(), nullable=True) + + # ### end Alembic commands ### diff --git a/src/backend/base/langflow/api/v1/variable.py b/src/backend/base/langflow/api/v1/variable.py index b1cca14c1..f992c1429 100644 --- a/src/backend/base/langflow/api/v1/variable.py +++ b/src/backend/base/langflow/api/v1/variable.py @@ -37,7 +37,11 @@ def create_variable( variable_dict["user_id"] = current_user.id db_variable = Variable.model_validate(variable_dict) - if not db_variable.value: + if not db_variable.name and not db_variable.value: + raise HTTPException(status_code=400, detail="Variable name and value cannot be empty") + elif not db_variable.name: + raise HTTPException(status_code=400, detail="Variable name cannot be empty") + elif not db_variable.value: raise HTTPException(status_code=400, detail="Variable value cannot be empty") encrypted = auth_utils.encrypt_api_key(db_variable.value, settings_service=settings_service) db_variable.value = encrypted diff --git a/src/backend/base/langflow/components/models/AzureOpenAIModel.py b/src/backend/base/langflow/components/models/AzureOpenAIModel.py index b6d3607f3..a2ee20b28 100644 --- a/src/backend/base/langflow/components/models/AzureOpenAIModel.py +++ b/src/backend/base/langflow/components/models/AzureOpenAIModel.py @@ -1,6 +1,5 @@ from typing import Optional -from langchain.llms.base import BaseLanguageModel from langchain_openai import AzureChatOpenAI from pydantic.v1 import SecretStr diff --git a/src/backend/base/langflow/components/models/ChatLiteLLMModel.py b/src/backend/base/langflow/components/models/ChatLiteLLMModel.py index 23ac483cb..95574f0a5 100644 --- a/src/backend/base/langflow/components/models/ChatLiteLLMModel.py +++ b/src/backend/base/langflow/components/models/ChatLiteLLMModel.py @@ -4,7 +4,7 @@ from langchain_community.chat_models.litellm import ChatLiteLLM, ChatLiteLLMExce from langflow.base.constants import STREAM_INFO_TEXT from langflow.base.models.model import LCModelComponent -from langflow.field_typing import BaseLanguageModel, Text +from langflow.field_typing import Text class ChatLiteLLMModelComponent(LCModelComponent): diff --git a/src/backend/base/langflow/schema/schema.py b/src/backend/base/langflow/schema/schema.py index 979c78920..5d2967dac 100644 --- a/src/backend/base/langflow/schema/schema.py +++ b/src/backend/base/langflow/schema/schema.py @@ -4,7 +4,7 @@ from typing import Literal, Optional from langchain_core.documents import Document from langchain_core.messages import BaseMessage from pydantic import BaseModel, model_validator -from langchain_core.messages import HumanMessage, AIMessage, BaseMessage +from langchain_core.messages import HumanMessage, AIMessage class Record(BaseModel): diff --git a/src/backend/base/langflow/services/database/models/variable/model.py b/src/backend/base/langflow/services/database/models/variable/model.py index 5c56f5b6d..bf61c25dc 100644 --- a/src/backend/base/langflow/services/database/models/variable/model.py +++ b/src/backend/base/langflow/services/database/models/variable/model.py @@ -13,8 +13,8 @@ def utc_now(): class VariableBase(SQLModel): - name: Optional[str] = Field(None, description="Name of the variable") - value: Optional[str] = Field(None, description="Encrypted value of the variable") + name: str = Field(description="Name of the variable") + value: str = Field(description="Encrypted value of the variable") default_fields: Optional[List[str]] = Field(sa_column=Column(JSON)) type: Optional[str] = Field(None, description="Type of the variable") diff --git a/src/backend/base/langflow/services/database/service.py b/src/backend/base/langflow/services/database/service.py index 5ca20c642..ee2812d32 100644 --- a/src/backend/base/langflow/services/database/service.py +++ b/src/backend/base/langflow/services/database/service.py @@ -133,7 +133,7 @@ class DatabaseService(Service): alembic_cfg = Config(stdout=buffer) # alembic_cfg.attributes["connection"] = session alembic_cfg.set_main_option("script_location", str(self.script_location)) - alembic_cfg.set_main_option("sqlalchemy.url", self.database_url.replace('%', '%%')) + alembic_cfg.set_main_option("sqlalchemy.url", self.database_url.replace("%", "%%")) should_initialize_alembic = False with Session(self.engine) as session: diff --git a/src/frontend/.prettierignore b/src/frontend/.prettierignore new file mode 100644 index 000000000..07ed7069a --- /dev/null +++ b/src/frontend/.prettierignore @@ -0,0 +1 @@ +build/* \ No newline at end of file diff --git a/src/frontend/package.json b/src/frontend/package.json index 26dc911af..bc8dcc041 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -72,7 +72,7 @@ "start": "vite", "build": "vite build", "serve": "vite preview", - "format": "npx prettier --write \"./**/*.{js,jsx,ts,tsx,json,md}\"", + "format": "npx prettier --write \"./**/*.{js,jsx,ts,tsx,json,md}\" --ignore-path .prettierignore", "type-check": "tsc --noEmit --pretty --project tsconfig.json && vite" }, "eslintConfig": { diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 6c5af17df..396906e91 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -22,7 +22,6 @@ import useFlowsManagerStore from "./stores/flowsManagerStore"; import { useGlobalVariablesStore } from "./stores/globalVariables"; import { useStoreStore } from "./stores/storeStore"; import { useTypesStore } from "./stores/typesStore"; - export default function App() { const removeFromTempNotificationList = useAlertStore( (state) => state.removeFromTempNotificationList @@ -48,6 +47,9 @@ export default function App() { const setGlobalVariables = useGlobalVariablesStore( (state) => state.setGlobalVariables ); + const setUnavailableFields = useGlobalVariablesStore( + (state) => state.setUnavaliableFields + ); const checkHasStore = useStoreStore((state) => state.checkHasStore); const navigate = useNavigate(); const dark = useDarkStore((state) => state.dark); diff --git a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx index aae36775d..e5e8dd488 100644 --- a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx +++ b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx @@ -3,6 +3,7 @@ import { registerGlobalVariable } from "../../controllers/API"; import BaseModal from "../../modals/baseModal"; import useAlertStore from "../../stores/alertStore"; import { useGlobalVariablesStore } from "../../stores/globalVariables"; +import { useTypesStore } from "../../stores/typesStore"; import { ResponseErrorDetailAPI } from "../../types/api"; import ForwardedIconComponent from "../genericIconComponent"; import InputComponent from "../inputComponent"; @@ -10,27 +11,39 @@ import { Button } from "../ui/button"; import { Input } from "../ui/input"; import { Label } from "../ui/label"; import { Textarea } from "../ui/textarea"; -import { useTypesStore } from "../../stores/typesStore"; //TODO IMPLEMENT FORM LOGIC export default function AddNewVariableButton({ children }): JSX.Element { const [key, setKey] = useState(""); const [value, setValue] = useState(""); - const [type, setType] = useState(""); + const [type, setType] = useState("Generic"); const [fields, setFields] = useState([]); const [open, setOpen] = useState(false); const setErrorData = useAlertStore((state) => state.setErrorData); const componentFields = useTypesStore((state) => state.ComponentFields); + const unavaliableFields =new Set(Object.keys(useGlobalVariablesStore( + (state) => state.unavaliableFields + ))); + + const availableFields = Array.from(componentFields).filter( + (field) => !unavaliableFields.has(field) + ); const addGlobalVariable = useGlobalVariablesStore( (state) => state.addGlobalVariable ); + function handleSaveVariable() { - let data: { name: string; value: string; type?: string; default_fields?: string[] } = { + let data: { + name: string; + value: string; + type?: string; + default_fields?: string[]; + } = { name: key, type, value, - default_fields: fields + default_fields: fields, }; registerGlobalVariable(data) .then((res) => { @@ -39,6 +52,7 @@ export default function AddNewVariableButton({ children }): JSX.Element { setKey(""); setValue(""); setType(""); + setFields([]); setOpen(false); }) .catch((error) => { @@ -98,8 +112,8 @@ export default function AddNewVariableButton({ children }): JSX.Element { setSelectedOptions={(value) => setFields(value)} selectedOptions={fields} password={false} - options={Array.from(componentFields)} - placeholder="Choose a type for the variable..." + options={availableFields} + placeholder="Choose a field for the variable..." > diff --git a/src/frontend/src/components/dropdownComponent/index.tsx b/src/frontend/src/components/dropdownComponent/index.tsx index c3407aba8..b17332268 100644 --- a/src/frontend/src/components/dropdownComponent/index.tsx +++ b/src/frontend/src/components/dropdownComponent/index.tsx @@ -33,7 +33,9 @@ export default function Dropdown({ const refButton = useRef(null); - const PopoverContentDropdown = children ? PopoverContent : PopoverContentWithoutPortal; + const PopoverContentDropdown = children + ? PopoverContent + : PopoverContentWithoutPortal; return ( <> @@ -77,7 +79,11 @@ export default function Dropdown({ )} diff --git a/src/frontend/src/components/inputGlobalComponent/index.tsx b/src/frontend/src/components/inputGlobalComponent/index.tsx index b2052ab84..235b00988 100644 --- a/src/frontend/src/components/inputGlobalComponent/index.tsx +++ b/src/frontend/src/components/inputGlobalComponent/index.tsx @@ -3,7 +3,6 @@ import { deleteGlobalVariable } from "../../controllers/API"; import DeleteConfirmationModal from "../../modals/DeleteConfirmationModal"; import useAlertStore from "../../stores/alertStore"; import { useGlobalVariablesStore } from "../../stores/globalVariables"; -import { ResponseErrorDetailAPI } from "../../types/api"; import { InputGlobalComponentType } from "../../types/components"; import { cn } from "../../utils/utils"; import AddNewVariableButton from "../addNewVariableButtonComponent/addNewVariableButton"; @@ -24,6 +23,9 @@ export default function InputGlobalComponent({ ); const getVariableId = useGlobalVariablesStore((state) => state.getVariableId); + const unavaliableFields = useGlobalVariablesStore( + (state) => state.unavaliableFields + ); const removeGlobalVariable = useGlobalVariablesStore( (state) => state.removeGlobalVariable ); @@ -40,10 +42,24 @@ export default function InputGlobalComponent({ } }, [globalVariablesEntries]); - function handleDelete(key: string) { + useEffect(() => { + if ( + !data.node?.template[name].value && + data.node?.template[name].display_name + ) { + if (unavaliableFields[data.node?.template[name].display_name!]) { + setDb(true); + onChange(unavaliableFields[data.node?.template[name].display_name!]); + } + } + }, [unavaliableFields]); + + async function handleDelete(key: string) { const id = getVariableId(key); if (id !== undefined) { - removeGlobalVariable(key).then((_) => { + await deleteGlobalVariable(id) + .then(() => { + removeGlobalVariable(key); if ( data?.node?.template[name].value === key && data?.node?.template[name].load_from_db @@ -52,11 +68,10 @@ export default function InputGlobalComponent({ setDb(false); } }) - .catch((error) => { - let responseError = error as ResponseErrorDetailAPI; + .catch(() => { setErrorData({ title: "Error deleting variable", - list: [responseError.response.data.detail ?? "Unknown error"], + list: [cn("ID not found for variable: ", key)], }); }); } else { @@ -115,7 +130,8 @@ export default function InputGlobalComponent({ )} selectedOption={ - data?.node?.template[name].load_from_db ?? false + data?.node?.template[name].load_from_db && + globalVariablesEntries.includes(data?.node?.template[name].value??"") ? data?.node?.template[name].value : "" } diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index 8770f1b5e..ee65ed27e 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -860,14 +860,14 @@ export async function requestLogout() { } export async function getGlobalVariables(): Promise<{ - [key: string]: { id: string; type: string,default_fields:string[] }; + [key: string]: { id: string; type: string; default_fields: string[] }; }> { const globalVariables = {}; (await api.get(`${BASE_URL_API}variables/`)).data.forEach((element) => { globalVariables[element.name] = { id: element.id, type: element.type, - default_fields:element.default_fields + default_fields: element.default_fields, }; }); return globalVariables; @@ -877,23 +877,33 @@ export async function registerGlobalVariable({ name, value, type, - default_fields=[], + default_fields = [], }: { name: string; value: string; type?: string; default_fields?: string[]; }): Promise> { - return await api.post(`${BASE_URL_API}variables/`, { - name, - value, - type, - default_fields:default_fields - }); + try { + const response = await api.post(`${BASE_URL_API}variables/`, { + name, + value, + type, + default_fields: default_fields, + }); + return response; + } catch (error) { + throw error; + } } export async function deleteGlobalVariable(id: string) { - api.delete(`${BASE_URL_API}variables/${id}`); + try { + const response = await api.delete(`${BASE_URL_API}variables/${id}`); + return response; + } catch (error) { + throw error; + } } export async function updateGlobalVariable( @@ -901,10 +911,16 @@ export async function updateGlobalVariable( value: string, id: string ) { - api.patch(`${BASE_URL_API}variables/${id}`, { - name, - value, - }); + try { + const response = api.patch(`${BASE_URL_API}variables/${id}`, { + name, + value, + }); + + return response; + } catch (error) { + throw error; + } } export async function getVerticesOrder( diff --git a/src/frontend/src/pages/SettingsPage/index.tsx b/src/frontend/src/pages/SettingsPage/index.tsx index 86d47cd34..554be79b6 100644 --- a/src/frontend/src/pages/SettingsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/index.tsx @@ -16,16 +16,16 @@ export default function SettingsPage(): JSX.Element { const sidebarNavItems = [ { - title: "General", - href: "/settings/general", - icon: ( - - ), - }, - /* { + title: "General", + href: "/settings/general", + icon: ( + + ), + }, + /* { title: "Theme", href: "/settings/theme", icon: ( diff --git a/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx index 955a7cccd..6bf31f245 100644 --- a/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx @@ -8,6 +8,8 @@ import Dropdown from "../../../../components/dropdownComponent"; import ForwardedIconComponent from "../../../../components/genericIconComponent"; import TableComponent from "../../../../components/tableComponent"; import { Badge } from "../../../../components/ui/badge"; +import { deleteGlobalVariable } from "../../../../controllers/API"; +import useAlertStore from "../../../../stores/alertStore"; import { useGlobalVariablesStore } from "../../../../stores/globalVariables"; import { cn } from "../../../../utils/utils"; @@ -21,6 +23,8 @@ export default function GlobalVariablesPage() { const globalVariables = useGlobalVariablesStore( (state) => state.globalVariables ); + const setErrorData = useAlertStore((state) => state.setErrorData); + const getVariableId = useGlobalVariablesStore((state) => state.getVariableId); const BadgeRenderer = (props) => { return props.value !== "" ? ( @@ -34,25 +38,31 @@ export default function GlobalVariablesPage() { ); }; - - const [rowData, setRowData] = useState<{ type: string | undefined; - id: string; name: string; default_fields:string | undefined }[]>(); + const [rowData, setRowData] = useState< + { + type: string | undefined; + id: string; + name: string; + default_fields: string | undefined; + }[] + >(); useEffect(() => { - const rows:Array<{type: string | undefined; id: string; - name: string;default_fields:string | undefined}> = []; - + const rows: Array<{ + type: string | undefined; + id: string; + name: string; + default_fields: string | undefined; + }> = []; globalVariablesEntries.forEach((entrie) => { const globalVariableObj = globalVariables[entrie]; - rows.push({ type: globalVariableObj.type, id: globalVariableObj.id, - default_fields: (globalVariableObj.default_fields??[]).join(", "), + default_fields: (globalVariableObj.default_fields ?? []).join(", "), name: entrie, }); }); - console.log(rows); setRowData(rows); }, [globalVariables]); @@ -95,15 +105,27 @@ export default function GlobalVariablesPage() { flex: 1, editable: false, }, - ]); const [selectedRows, setSelectedRows] = useState([]); - function removeVariables() { - selectedRows.forEach((row) => { - removeGlobalVariable(row); + async function removeVariables() { + const deleteGlobalVariablesPromise = selectedRows.map(async (row) => { + const id = getVariableId(row); + const deleteGlobalVariables = deleteGlobalVariable(id!); + await deleteGlobalVariables; }); + Promise.all(deleteGlobalVariablesPromise) + .then(() => { + selectedRows.forEach((row) => { + removeGlobalVariable(row); + }); + }) + .catch(() => { + setErrorData({ + title: `Error deleting global variables.`, + }); + }); } return ( diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx index 1dac8d095..adcfcefef 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx @@ -124,9 +124,7 @@ export default function ShortcutsPage() { Flow - - Shortcuts relating to the flow. - + Shortcuts relating to the flow. ((set, get) => ({ ); useTypesStore.setState((state) => ({ data: { ...state.data, ["saved_components"]: data }, - ComponentFields: extractFieldsFromComponenents({...state.data, ["saved_components"]: data }), + ComponentFields: extractFieldsFromComponenents({ + ...state.data, + ["saved_components"]: data, + }), })); set({ isLoading: false }); resolve(); @@ -199,7 +202,10 @@ const useFlowsManagerStore = create((set, get) => ({ set({ isLoading: false }); useTypesStore.setState((state) => ({ data: { ...state.data, ["saved_components"]: data }, - ComponentFields: extractFieldsFromComponenents({...state.data, ["saved_components"]: data }), + ComponentFields: extractFieldsFromComponenents({ + ...state.data, + ["saved_components"]: data, + }), })); }, 200); // addFlowToLocalState(newFlow); @@ -222,7 +228,10 @@ const useFlowsManagerStore = create((set, get) => ({ set({ isLoading: false }); useTypesStore.setState((state) => ({ data: { ...state.data, ["saved_components"]: data }, - ComponentFields: extractFieldsFromComponenents({...state.data, ["saved_components"]: data }), + ComponentFields: extractFieldsFromComponenents({ + ...state.data, + ["saved_components"]: data, + }), })); // Return the id @@ -252,7 +261,10 @@ const useFlowsManagerStore = create((set, get) => ({ set({ isLoading: false }); useTypesStore.setState((state) => ({ data: { ...state.data, ["saved_components"]: data }, - ComponentFields: extractFieldsFromComponenents({...state.data, ["saved_components"]: data }), + ComponentFields: extractFieldsFromComponenents({ + ...state.data, + ["saved_components"]: data, + }), })); resolve(); }); diff --git a/src/frontend/src/stores/globalVariables.ts b/src/frontend/src/stores/globalVariables.ts index 5a2a67fa4..3adf8cbf8 100644 --- a/src/frontend/src/stores/globalVariables.ts +++ b/src/frontend/src/stores/globalVariables.ts @@ -1,18 +1,17 @@ import { create } from "zustand"; import { GlobalVariablesStore } from "../types/zustand/globalVariables"; -import { deleteGlobalVariable } from "../controllers/API"; +import { getUnavailableFields } from "../utils/utils"; export const useGlobalVariablesStore = create( (set, get) => ({ - unavaliableFields: new Set(), + unavaliableFields: {}, setUnavaliableFields: (fields) => { set({ unavaliableFields: fields }); }, - addUnavaliableField: (field) => { - set({ unavaliableFields: get().unavaliableFields.add(field) }); - }, removeUnavaliableField: (field) => { - get().unavaliableFields.delete(field); + const newFields = get().unavaliableFields; + delete newFields[field]; + set({ unavaliableFields: newFields }); }, globalVariablesEntries: [], globalVariables: {}, @@ -20,6 +19,7 @@ export const useGlobalVariablesStore = create( set({ globalVariables: variables, globalVariablesEntries: Object.keys(variables), + unavaliableFields: getUnavailableFields(variables), }); }, addGlobalVariable: (name, id, type, default_fields) => { @@ -28,17 +28,18 @@ export const useGlobalVariablesStore = create( set({ globalVariables: newVariables, globalVariablesEntries: Object.keys(newVariables), + unavaliableFields: getUnavailableFields(newVariables), }); }, - removeGlobalVariable:async (name) => { + removeGlobalVariable: async (name) => { const id = get().globalVariables[name]?.id; if (id === undefined) return; - await deleteGlobalVariable(id) const newVariables = { ...get().globalVariables }; delete newVariables[name]; set({ globalVariables: newVariables, globalVariablesEntries: Object.keys(newVariables), + unavaliableFields: getUnavailableFields(newVariables), }); }, getVariableId: (name) => { diff --git a/src/frontend/src/stores/typesStore.ts b/src/frontend/src/stores/typesStore.ts index f2539a8d3..c92236e03 100644 --- a/src/frontend/src/stores/typesStore.ts +++ b/src/frontend/src/stores/typesStore.ts @@ -2,7 +2,11 @@ import { create } from "zustand"; import { getAll } from "../controllers/API"; import { APIDataType } from "../types/api"; import { TypesStoreType } from "../types/zustand/types"; -import { extractFieldsFromComponenents, templatesGenerator, typesGenerator } from "../utils/reactflowUtils"; +import { + extractFieldsFromComponenents, + templatesGenerator, + typesGenerator, +} from "../utils/reactflowUtils"; import useAlertStore from "./alertStore"; import useFlowsManagerStore from "./flowsManagerStore"; @@ -28,7 +32,10 @@ export const useTypesStore = create((set, get) => ({ set((old) => ({ types: typesGenerator(data), data: { ...old.data, ...data }, - ComponentFields: extractFieldsFromComponenents({ ...old.data, ...data }), + ComponentFields: extractFieldsFromComponenents({ + ...old.data, + ...data, + }), templates: templatesGenerator(data), })); setLoading(false); @@ -50,7 +57,7 @@ export const useTypesStore = create((set, get) => ({ }, setData: (change: APIDataType | ((old: APIDataType) => APIDataType)) => { let newChange = typeof change === "function" ? change(get().data) : change; - set({ data: newChange}); + set({ data: newChange }); get().setComponentFields(extractFieldsFromComponenents(newChange)); }, })); diff --git a/src/frontend/src/types/zustand/globalVariables/index.ts b/src/frontend/src/types/zustand/globalVariables/index.ts index 45fda27cd..752336c19 100644 --- a/src/frontend/src/types/zustand/globalVariables/index.ts +++ b/src/frontend/src/types/zustand/globalVariables/index.ts @@ -9,7 +9,12 @@ export type GlobalVariablesStore = { }; }; setGlobalVariables: (variables: { - [name: string]: { id: string; type?: string; default_fields?: string[],value?: string }; + [name: string]: { + id: string; + type?: string; + default_fields?: string[]; + value?: string; + }; }) => void; addGlobalVariable: ( name: string, @@ -20,8 +25,7 @@ export type GlobalVariablesStore = { ) => void; removeGlobalVariable: (name: string) => Promise; getVariableId: (name: string) => string | undefined; - unavaliableFields: Set; - setUnavaliableFields: (fields: Set) => void; - addUnavaliableField: (field: string) => void; + unavaliableFields: {[name: string]: string}; + setUnavaliableFields: (fields: {[name: string]: string}) => void; removeUnavaliableField: (field: string) => void; }; diff --git a/src/frontend/src/utils/reactflowUtils.ts b/src/frontend/src/utils/reactflowUtils.ts index ad1244495..deb470f80 100644 --- a/src/frontend/src/utils/reactflowUtils.ts +++ b/src/frontend/src/utils/reactflowUtils.ts @@ -1234,17 +1234,19 @@ export function templatesGenerator(data: APIObjectType) { }, {}); } -export function extractFieldsFromComponenents(data:APIObjectType ) { +export function extractFieldsFromComponenents(data: APIObjectType) { const fields = new Set(); Object.keys(data).forEach((key) => { Object.keys(data[key]).forEach((kind) => { Object.keys(data[key][kind].template).forEach((field) => { - if(data[key][kind].template[field].display_name && data[key][kind].template[field].show) - fields.add(data[key][kind].template[field].display_name!); + if ( + data[key][kind].template[field].display_name && + data[key][kind].template[field].show + ) + fields.add(data[key][kind].template[field].display_name!); }); }); }); - console.log(fields); return fields; } diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index afcc264f6..1c580fa4b 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -91,6 +91,20 @@ export function toTitleCase( .join(" "); } +export function getUnavailableFields(variables: { + [key: string]: { default_fields?: string[] }; +}): {[name: string]: string} { + const unVariables:{[name: string]: string} = {}; + Object.keys(variables).forEach((key) => { + if (variables[key].default_fields) { + variables[key].default_fields!.forEach((field) => { + unVariables[field] = key; + }); + } + }); + return unVariables; +} + export const upperCaseWords: string[] = ["llm", "uri"]; export function checkUpperWords(str: string): string { const words = str.split(" ").map((word) => {