diff --git a/src/backend/base/langflow/api/utils.py b/src/backend/base/langflow/api/utils.py index b9f10d2c4..e2f6e07e7 100644 --- a/src/backend/base/langflow/api/utils.py +++ b/src/backend/base/langflow/api/utils.py @@ -205,17 +205,12 @@ async def build_and_cache_graph_from_db( flow_id: str, session: Session, chat_service: "ChatService", - graph: Optional[Graph] = None, ): """Build and cache the graph.""" flow: Optional[Flow] = session.get(Flow, flow_id) if not flow or not flow.data: raise ValueError("Invalid flow ID") - other_graph = Graph.from_payload(flow.data, flow_id) - if graph is None: - graph = other_graph - else: - graph = graph.update(other_graph) + graph = Graph.from_payload(flow.data, flow_id) await chat_service.set_cache(flow_id, graph) return graph diff --git a/src/backend/base/langflow/api/v1/chat.py b/src/backend/base/langflow/api/v1/chat.py index d44d96e72..30e709664 100644 --- a/src/backend/base/langflow/api/v1/chat.py +++ b/src/backend/base/langflow/api/v1/chat.py @@ -79,13 +79,8 @@ async def retrieve_vertices_order( """ try: # First, we need to check if the flow_id is in the cache - graph = None if not data: - if cache := await chat_service.get_cache(flow_id): - graph = cache.get("result") - graph = await build_and_cache_graph_from_db( - flow_id=flow_id, session=session, chat_service=chat_service, graph=graph - ) + graph = await build_and_cache_graph_from_db(flow_id=flow_id, session=session, chat_service=chat_service) else: graph = await build_and_cache_graph_from_data( flow_id=flow_id, graph_data=data.model_dump(), chat_service=chat_service diff --git a/src/backend/base/langflow/components/data/APIRequest.py b/src/backend/base/langflow/components/data/APIRequest.py index 83a1edb9d..9f1ca703c 100644 --- a/src/backend/base/langflow/components/data/APIRequest.py +++ b/src/backend/base/langflow/components/data/APIRequest.py @@ -93,14 +93,14 @@ class APIRequest(CustomComponent): self, method: str, urls: List[str], - _headers: Optional[Record] = None, + headers: Optional[Record] = None, body: Optional[Record] = None, timeout: int = 5, ) -> List[Record]: - if _headers is None: - headers = {} + if headers is None: + headers_dict = {} else: - headers = _headers.data + headers_dict = headers.data bodies = [] if body: @@ -114,7 +114,7 @@ class APIRequest(CustomComponent): bodies += [None] * (len(urls) - len(bodies)) # type: ignore async with httpx.AsyncClient() as client: results = await asyncio.gather( - *[self.make_request(client, method, u, headers, rec, timeout) for u, rec in zip(urls, bodies)] + *[self.make_request(client, method, u, headers_dict, rec, timeout) for u, rec in zip(urls, bodies)] ) self.status = results return results diff --git a/src/backend/base/langflow/graph/graph/base.py b/src/backend/base/langflow/graph/graph/base.py index bddfd6795..1744ac687 100644 --- a/src/backend/base/langflow/graph/graph/base.py +++ b/src/backend/base/langflow/graph/graph/base.py @@ -445,9 +445,16 @@ class Graph: vertex = self.get_vertex(vertex_id) vertex.set_state(state) - def mark_branch(self, vertex_id: str, state: str): + def mark_branch(self, vertex_id: str, state: str, visited: Optional[set] = None): """Marks a branch of the graph.""" + if visited is None: + visited = set() + visited.add(vertex_id) + if vertex_id in visited: + return + self.mark_vertex(vertex_id, state) + for child_id in self.parent_child_map[vertex_id]: self.mark_branch(child_id, state) diff --git a/src/backend/base/langflow/services/store/service.py b/src/backend/base/langflow/services/store/service.py index c6205269a..4fabd435c 100644 --- a/src/backend/base/langflow/services/store/service.py +++ b/src/backend/base/langflow/services/store/service.py @@ -59,7 +59,7 @@ def get_id_from_search_string(search_string: str) -> Optional[str]: Returns: Optional[str]: The extracted ID, or None if no ID is found. """ - possible_id = search_string + possible_id: Optional[str] = search_string if "www.langflow.store/store/" in search_string: possible_id = search_string.split("/")[-1] diff --git a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx index f33037ebc..8786cdac6 100644 --- a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx +++ b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx @@ -5,6 +5,7 @@ import useAlertStore from "../../stores/alertStore"; import { useGlobalVariablesStore } from "../../stores/globalVariables"; import { useTypesStore } from "../../stores/typesStore"; import { ResponseErrorDetailAPI } from "../../types/api"; +import { sortByName } from "../../utils/utils"; import ForwardedIconComponent from "../genericIconComponent"; import InputComponent from "../inputComponent"; import { Button } from "../ui/button"; @@ -23,14 +24,19 @@ export default function AddNewVariableButton({ children }): JSX.Element { const setErrorData = useAlertStore((state) => state.setErrorData); const componentFields = useTypesStore((state) => state.ComponentFields); const unavaliableFields = new Set( - Object.keys(useGlobalVariablesStore((state) => state.unavaliableFields)) + Object.keys(useGlobalVariablesStore((state) => state.unavaliableFields)), ); - const availableFields = Array.from(componentFields).filter( - (field) => !unavaliableFields.has(field) - ); + const availableFields = () => { + const fields = Array.from(componentFields).filter( + (field) => !unavaliableFields.has(field), + ); + + return sortByName(fields); + }; + const addGlobalVariable = useGlobalVariablesStore( - (state) => state.addGlobalVariable + (state) => state.addGlobalVariable, ); function handleSaveVariable() { @@ -113,7 +119,7 @@ export default function AddNewVariableButton({ children }): JSX.Element { setSelectedOptions={(value) => setFields(value)} selectedOptions={fields} password={false} - options={availableFields} + options={availableFields()} placeholder="Choose a field for the variable..." id={"apply-to-fields"} > diff --git a/src/frontend/src/components/cardComponent/index.tsx b/src/frontend/src/components/cardComponent/index.tsx index e82263513..ac85926d5 100644 --- a/src/frontend/src/components/cardComponent/index.tsx +++ b/src/frontend/src/components/cardComponent/index.tsx @@ -11,7 +11,6 @@ import cloneFLowWithParent from "../../utils/storeUtils"; import { cn, convertTestName } from "../../utils/utils"; import IconComponent from "../genericIconComponent"; import ShadTooltip from "../shadTooltipComponent"; -import { Badge } from "../ui/badge"; import { Button } from "../ui/button"; import { Card, @@ -170,8 +169,9 @@ export default function CollectionCardComponent({ <> { e.stopPropagation(); setOpenDelete(true); @@ -269,7 +270,7 @@ export default function CollectionCardComponent({ )}
- {data.tags && + {/* {data.tags && data.tags.length > 0 && data.tags.map((tag, index) => ( {tag.name} - ))} + ))} */}
@@ -291,8 +292,8 @@ export default function CollectionCardComponent({ -
-
+
+
{playground && data?.metadata !== undefined ? (
)} - {button && button} {playground && data?.metadata === undefined && ( ), - [hasApiKey, validApiKey, currentFlow, hasStore] + [hasApiKey, validApiKey, currentFlow, hasStore], ); return ( @@ -112,7 +112,7 @@ export default function FlowToolbar(): JSX.Element { "message-button-icon h-5 w-5 fill-muted-foreground stroke-muted-foreground transition-all" } /> - Run + Playground
)}
@@ -128,7 +128,7 @@ export default function FlowToolbar(): JSX.Element { >
{ updateRowHeight(params); }, - [updateRowHeight] + [updateRowHeight], ); const onGridSizeChanged = useCallback( (params: any) => { updateRowHeight(params); }, - [updateRowHeight] + [updateRowHeight], ); return ( @@ -167,6 +167,7 @@ function CsvOutputComponent({ onFirstDataRendered={onFirstDataRendered} onGridSizeChanged={onGridSizeChanged} scrollbarWidth={8} + overlayNoRowsTemplate="No data available" />
)} diff --git a/src/frontend/src/components/tableComponent/index.tsx b/src/frontend/src/components/tableComponent/index.tsx index 300aa5cc3..3404444c5 100644 --- a/src/frontend/src/components/tableComponent/index.tsx +++ b/src/frontend/src/components/tableComponent/index.tsx @@ -5,6 +5,7 @@ import { ComponentPropsWithoutRef, ElementRef, forwardRef } from "react"; import { useDarkStore } from "../../stores/darkStore"; import "../../style/ag-theme-shadcn.css"; // Custom CSS applied to the grid import { cn } from "../../utils/utils"; +import { Card, CardContent } from "../ui/card"; const TableComponent = forwardRef< ElementRef, @@ -17,10 +18,18 @@ const TableComponent = forwardRef<
- + + + + +
); diff --git a/src/frontend/src/modals/IOModal/index.tsx b/src/frontend/src/modals/IOModal/index.tsx index 49283ece0..82350b57e 100644 --- a/src/frontend/src/modals/IOModal/index.tsx +++ b/src/frontend/src/modals/IOModal/index.tsx @@ -117,7 +117,7 @@ export default function IOModal({ return ( state.globalVariablesEntries + (state) => state.globalVariablesEntries, ); const removeGlobalVariable = useGlobalVariablesStore( - (state) => state.removeGlobalVariable + (state) => state.removeGlobalVariable, ); const globalVariables = useGlobalVariablesStore( - (state) => state.globalVariables + (state) => state.globalVariables, ); const setErrorData = useAlertStore((state) => state.setErrorData); const getVariableId = useGlobalVariablesStore((state) => state.getVariableId); @@ -154,7 +154,7 @@ export default function GlobalVariablesPage() { @@ -174,6 +174,8 @@ export default function GlobalVariablesPage() { }} rowSelection="multiple" suppressRowClickSelection={true} + domLayout="autoHeight" + pagination={false} columnDefs={colDefs} rowData={rowData} /> diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx index 768f92e6c..9e6580741 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx @@ -43,10 +43,6 @@ export default function ShortcutsPage() { const combinationToEdit = shortcuts.filter((s) => s.name === selectedRows[0]); const [open, setOpen] = useState(false); - - const unavaliableShortcuts = useShortcutsStore( - (state) => state.unavailableShortcuts - ); useEffect(() => { if (localStorage.getItem("langflow-shortcuts")) { const savedShortcuts = localStorage.getItem("langflow-shortcuts"); @@ -109,7 +105,7 @@ export default function ShortcutsPage() { { setSelectedRows( - event.api.getSelectedRows().map((row) => row.name) + event.api.getSelectedRows().map((row) => row.name), ); }} suppressRowClickSelection={true} diff --git a/src/frontend/src/style/applies.css b/src/frontend/src/style/applies.css index 4b016eb73..a90b5b96c 100644 --- a/src/frontend/src/style/applies.css +++ b/src/frontend/src/style/applies.css @@ -9,7 +9,9 @@ body { @apply bg-background text-foreground; - font-feature-settings: "rlig" 1, "calt" 1; + font-feature-settings: + "rlig" 1, + "calt" 1; } } @@ -1018,6 +1020,9 @@ .langflow-chat-span { @apply text-lg text-foreground; } + .card-filter { + @apply bg-background bg-fixed opacity-20; + } .langflow-chat-desc { @apply w-2/4 rounded-md border border-border bg-muted px-6 py-8; } diff --git a/src/frontend/src/utils/buildUtils.ts b/src/frontend/src/utils/buildUtils.ts index 2f5d557c5..dedc16b46 100644 --- a/src/frontend/src/utils/buildUtils.ts +++ b/src/frontend/src/utils/buildUtils.ts @@ -16,7 +16,7 @@ type BuildVerticesParams = { onBuildUpdate?: ( data: VertexBuildTypeAPI, status: BuildStatus, - buildId: string + buildId: string, ) => void; // Replace any with the actual type if it's not any onBuildComplete?: (allNodesValid: boolean) => void; onBuildError?: (title, list, idList: VertexLayerElementType[]) => void; @@ -53,7 +53,7 @@ export async function updateVerticesOrder( startNodeId?: string | null, stopNodeId?: string | null, nodes?: Node[], - edges?: Edge[] + edges?: Edge[], ): Promise<{ verticesLayers: VertexLayerElementType[][]; verticesIds: string[]; @@ -69,7 +69,7 @@ export async function updateVerticesOrder( startNodeId, stopNodeId, nodes, - edges + edges, ); } catch (error: any) { setErrorData({ @@ -116,33 +116,29 @@ export async function buildVertices({ nodes, edges, }: BuildVerticesParams) { - let verticesBuild = useFlowStore.getState().verticesBuild; // if startNodeId and stopNodeId are provided // something is wrong if (startNodeId && stopNodeId) { return; } + let verticesOrderResponse = await updateVerticesOrder( + flowId, + startNodeId, + stopNodeId, + nodes, + edges, + ); + if (onValidateNodes) { + try { + onValidateNodes(verticesOrderResponse.verticesToRun); + } catch (e) { + useFlowStore.getState().setIsBuilding(false); - if (!verticesBuild || startNodeId || stopNodeId) { - let verticesOrderResponse = await updateVerticesOrder( - flowId, - startNodeId, - stopNodeId, - nodes, - edges - ); - if (onValidateNodes) { - try { - onValidateNodes(verticesOrderResponse.verticesToRun); - } catch (e) { - useFlowStore.getState().setIsBuilding(false); - - return; - } + return; } - if (onGetOrderSuccess) onGetOrderSuccess(); - verticesBuild = useFlowStore.getState().verticesBuild; } + if (onGetOrderSuccess) onGetOrderSuccess(); + let verticesBuild = useFlowStore.getState().verticesBuild; const verticesIds = verticesBuild?.verticesIds!; const verticesLayers = verticesBuild?.verticesLayers!; @@ -192,14 +188,14 @@ export async function buildVertices({ onBuildUpdate( getInactiveVertexData(element.id), BuildStatus.INACTIVE, - runId + runId, ); } if (element.reference) { onBuildUpdate( getInactiveVertexData(element.reference), BuildStatus.INACTIVE, - runId + runId, ); } buildResults.push(false); @@ -224,7 +220,7 @@ export async function buildVertices({ if (stop) { return; } - }) + }), ); // Once the current layer is built, move to the next layer currentLayerIndex += 1; @@ -267,7 +263,7 @@ async function buildVertex({ onBuildError!( "Error Building Component", [buildData.params], - verticesIds.map((id) => ({ id })) + verticesIds.map((id) => ({ id })), ); stopBuild(); } @@ -278,7 +274,7 @@ async function buildVertex({ onBuildError!( "Error Building Component", [(error as AxiosError).response?.data?.detail ?? "Unknown Error"], - verticesIds.map((id) => ({ id })) + verticesIds.map((id) => ({ id })), ); stopBuild(); } diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 43838bb27..7c269d8e4 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -719,3 +719,7 @@ export function freezeObject(obj: any) { export function convertTestName(name: string): string { return name.replace(/ /g, "-").toLowerCase(); } + +export function sortByName(stringList: string[]): string[] { + return stringList.sort((a, b) => a.localeCompare(b)); +} diff --git a/src/frontend/tests/end-to-end/userSettings.spec.ts b/src/frontend/tests/end-to-end/userSettings.spec.ts index 6f90bb19c..af7c93824 100644 --- a/src/frontend/tests/end-to-end/userSettings.spec.ts +++ b/src/frontend/tests/end-to-end/userSettings.spec.ts @@ -63,7 +63,7 @@ test("should interact with global variables", async ({ page }) => { .nth(0) .click(); await page.getByTestId("icon-Trash2").click(); - await page.getByText("No Rows To Show").isVisible(); + await page.getByText("No data available").isVisible(); }); test("should see shortcuts", async ({ page }) => { diff --git a/tests/test_endpoints.py b/tests/test_endpoints.py index 23d965b7d..64a5da351 100644 --- a/tests/test_endpoints.py +++ b/tests/test_endpoints.py @@ -393,13 +393,13 @@ def test_various_prompts(client, prompt, expected_input_variables): def test_get_vertices_flow_not_found(client, logged_in_headers): - response = client.get("/api/v1/build/nonexistent_id/vertices", headers=logged_in_headers) + response = client.post("/api/v1/build/nonexistent_id/vertices", headers=logged_in_headers) assert response.status_code == 500 # Or whatever status code you've set for invalid ID def test_get_vertices(client, added_flow_with_prompt_and_history, logged_in_headers): flow_id = added_flow_with_prompt_and_history["id"] - response = client.get(f"/api/v1/build/{flow_id}/vertices", headers=logged_in_headers) + response = client.post(f"/api/v1/build/{flow_id}/vertices", headers=logged_in_headers) assert response.status_code == 200 assert "ids" in response.json() # The response should contain the list in this order