diff --git a/docs/docs/API-Reference/api-projects.md b/docs/docs/API-Reference/api-projects.md index 7269322ff..86b90e15c 100644 --- a/docs/docs/API-Reference/api-projects.md +++ b/docs/docs/API-Reference/api-projects.md @@ -29,7 +29,7 @@ curl -X GET \ ```json [ { - "name": "My Projects", + "name": "Starter Project", "description": "Manage your own projects. Download and upload projects.", "id": "1415de42-8f01-4f36-bf34-539f23e47466", "parent_id": null @@ -116,7 +116,7 @@ curl -X GET \ ```json [ { - "name": "My Projects", + "name": "Starter Project", "description": "Manage your own projects. Download and upload projects.", "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "parent_id": null @@ -216,4 +216,4 @@ curl -X POST \ -H "accept: application/json" \ -H "Content-Type: multipart/form-data" \ -F "file=@20241230_135006_langflow_flows.zip;type=application/zip" -``` \ No newline at end of file +``` diff --git a/src/backend/base/langflow/alembic/versions/d9a6ea21edcd_rename_default_folder.py b/src/backend/base/langflow/alembic/versions/d9a6ea21edcd_rename_default_folder.py new file mode 100644 index 000000000..631dcfb62 --- /dev/null +++ b/src/backend/base/langflow/alembic/versions/d9a6ea21edcd_rename_default_folder.py @@ -0,0 +1,75 @@ +"""Rename default folder + +Revision ID: d9a6ea21edcd +Revises: 66f72f04a1de +Create Date: 2025-07-02 09:42:46.891585 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +import sqlmodel +from sqlalchemy.engine.reflection import Inspector +from langflow.utils import migration + + +# revision identifiers, used by Alembic. +revision: str = 'd9a6ea21edcd' +down_revision: Union[str, None] = '66f72f04a1de' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + conn = op.get_bind() + + # Check if the folder table exists + inspector = sa.inspect(conn) + table_names = inspector.get_table_names() + + if "folder" not in table_names: + # If folder table doesn't exist, skip this migration + return + + # Rename "My Projects" to "Starter Project" only for users who don't already have a "Starter Project" folder + # This prevents unique constraint violations + update_query = sa.text(""" + UPDATE folder + SET name = 'Starter Project' + WHERE name = 'My Projects' + AND NOT EXISTS ( + SELECT 1 FROM folder f2 + WHERE f2.user_id = folder.user_id + AND f2.name = 'Starter Project' + ) + """) + + conn.execute(update_query) + + +def downgrade() -> None: + conn = op.get_bind() + + # Check if the folder table exists + inspector = sa.inspect(conn) + table_names = inspector.get_table_names() + + if "folder" not in table_names: + # If folder table doesn't exist, skip this migration + return + + # Rename "Starter Project" back to "My Projects" only for users who don't already have a "My Projects" folder + # This prevents unique constraint violations + update_query = sa.text(""" + UPDATE folder + SET name = 'My Projects' + WHERE name = 'Starter Project' + AND NOT EXISTS ( + SELECT 1 FROM folder f2 + WHERE f2.user_id = folder.user_id + AND f2.name = 'My Projects' + ) + """) + + conn.execute(update_query) diff --git a/src/backend/base/langflow/api/v1/mcp_projects.py b/src/backend/base/langflow/api/v1/mcp_projects.py index 6c4361be6..c64471fc8 100644 --- a/src/backend/base/langflow/api/v1/mcp_projects.py +++ b/src/backend/base/langflow/api/v1/mcp_projects.py @@ -36,7 +36,6 @@ from langflow.base.mcp.util import get_flow_snake_case, get_unique_name, sanitiz from langflow.helpers.flow import json_schema_from_flow from langflow.schema.message import Message from langflow.services.database.models import Flow, Folder -from langflow.services.database.models.folder.constants import DEFAULT_FOLDER_NAME, NEW_FOLDER_NAME from langflow.services.deps import get_settings_service, get_storage_service, session_scope from langflow.services.storage.utils import build_content_type_from_extension @@ -390,7 +389,6 @@ async def install_mcp_config( logger.debug("Windows detected, using cmd command") name = project.name - name = NEW_FOLDER_NAME if name == DEFAULT_FOLDER_NAME else name # Create the MCP configuration mcp_config = { @@ -517,7 +515,6 @@ async def check_installed_mcp_servers( # Project server name pattern (must match the logic in install function) name = project.name - name = NEW_FOLDER_NAME if name == DEFAULT_FOLDER_NAME else name project_server_name = f"lf-{sanitize_mcp_name(name)[: (MAX_MCP_SERVER_NAME_LENGTH - 4)]}" logger.debug( diff --git a/src/backend/base/langflow/services/database/models/folder/constants.py b/src/backend/base/langflow/services/database/models/folder/constants.py index 54a5cf46f..36e62359f 100644 --- a/src/backend/base/langflow/services/database/models/folder/constants.py +++ b/src/backend/base/langflow/services/database/models/folder/constants.py @@ -1,3 +1,2 @@ DEFAULT_FOLDER_DESCRIPTION = "Manage your own flows. Download and upload projects." -DEFAULT_FOLDER_NAME = "My Projects" -NEW_FOLDER_NAME = "Starter Project" +DEFAULT_FOLDER_NAME = "Starter Project" diff --git a/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/select-options.tsx b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/select-options.tsx index d62597bca..12afd4344 100644 --- a/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/select-options.tsx +++ b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/select-options.tsx @@ -6,7 +6,7 @@ import { SelectItem, SelectTrigger, } from "@/components/ui/select-custom"; -import { DEFAULT_FOLDER_DEPRECATED } from "@/constants/constants"; +import { DEFAULT_FOLDER } from "@/constants/constants"; import { FolderType } from "@/pages/MainPage/entities"; import { cn } from "@/utils/utils"; import { handleSelectChange } from "../helpers/handle-select-change"; @@ -57,7 +57,7 @@ export const SelectOptions = ({ - {item.name !== DEFAULT_FOLDER_DEPRECATED && ( + {item.name !== DEFAULT_FOLDER && ( { - if (item.name === DEFAULT_FOLDER_DEPRECATED) { + if (item.name === DEFAULT_FOLDER) { return; } @@ -424,9 +421,7 @@ const SideBarFoldersButtonsComponent = ({ /> ) : ( - {item.name === DEFAULT_FOLDER_DEPRECATED - ? DEFAULT_FOLDER - : item.name} + {item.name} )} diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index c8ecac2d9..162562dae 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -558,7 +558,6 @@ export const NOUNS: string[] = [ export const USER_PROJECTS_HEADER = "My Collection"; export const DEFAULT_FOLDER = "Starter Project"; -export const DEFAULT_FOLDER_DEPRECATED = "My Projects"; export const MAX_MCP_SERVER_NAME_LENGTH = 30; diff --git a/src/frontend/src/controllers/API/queries/folders/use-get-folders.ts b/src/frontend/src/controllers/API/queries/folders/use-get-folders.ts index da3878c5c..61151242a 100644 --- a/src/frontend/src/controllers/API/queries/folders/use-get-folders.ts +++ b/src/frontend/src/controllers/API/queries/folders/use-get-folders.ts @@ -1,7 +1,4 @@ -import { - DEFAULT_FOLDER, - DEFAULT_FOLDER_DEPRECATED, -} from "@/constants/constants"; +import { DEFAULT_FOLDER } from "@/constants/constants"; import { FolderType } from "@/pages/MainPage/entities"; import useAuthStore from "@/stores/authStore"; import { useFolderStore } from "@/stores/foldersStore"; @@ -26,9 +23,7 @@ export const useGetFoldersQuery: useQueryFunctionType< const res = await api.get(`${getURL("PROJECTS")}/`); const data = res.data; - const myCollectionId = data?.find( - (f) => f.name === DEFAULT_FOLDER_DEPRECATED, - )?.id; + const myCollectionId = data?.find((f) => f.name === DEFAULT_FOLDER)?.id; setMyCollectionId(myCollectionId); setFolders(data); diff --git a/src/frontend/src/customization/utils/custom-get-download-folders.ts b/src/frontend/src/customization/utils/custom-get-download-folders.ts index 7f713d1da..6ab782b3e 100644 --- a/src/frontend/src/customization/utils/custom-get-download-folders.ts +++ b/src/frontend/src/customization/utils/custom-get-download-folders.ts @@ -16,10 +16,6 @@ export const customGetDownloadFolderBlob = ( folderName?: string, setSuccessData?: (data: any) => void, ) => { - if (folderName === "My Projects") { - folderName = "Starter Project"; - } - // Create a blob from the response data const blob = new Blob([response.data], { type: "application/x-zip-compressed", diff --git a/src/frontend/src/pages/MainPage/components/header/index.tsx b/src/frontend/src/pages/MainPage/components/header/index.tsx index 11e3225ff..f718012e5 100644 --- a/src/frontend/src/pages/MainPage/components/header/index.tsx +++ b/src/frontend/src/pages/MainPage/components/header/index.tsx @@ -3,10 +3,6 @@ import ShadTooltip from "@/components/common/shadTooltipComponent"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { SidebarTrigger } from "@/components/ui/sidebar"; -import { - DEFAULT_FOLDER, - DEFAULT_FOLDER_DEPRECATED, -} from "@/constants/constants"; import { useDeleteDeleteFlows } from "@/controllers/API/queries/flows/use-delete-delete-flows"; import { useGetDownloadFlows } from "@/controllers/API/queries/flows/use-get-download-flows"; import { ENABLE_MCP } from "@/customization/feature-flags"; @@ -15,7 +11,6 @@ import useAlertStore from "@/stores/alertStore"; import { cn } from "@/utils/utils"; import { debounce } from "lodash"; import { useCallback, useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; interface HeaderComponentProps { flowType: "flows" | "components" | "mcp"; @@ -113,7 +108,7 @@ const HeaderComponent = ({ - {folderName === DEFAULT_FOLDER_DEPRECATED ? DEFAULT_FOLDER : folderName} + {folderName} {!isEmptyFolder && ( <> diff --git a/src/frontend/src/pages/MainPage/pages/homePage/components/McpServerTab.tsx b/src/frontend/src/pages/MainPage/pages/homePage/components/McpServerTab.tsx index 50e9cf237..92a0b9e51 100644 --- a/src/frontend/src/pages/MainPage/pages/homePage/components/McpServerTab.tsx +++ b/src/frontend/src/pages/MainPage/pages/homePage/components/McpServerTab.tsx @@ -3,11 +3,7 @@ import ShadTooltip from "@/components/common/shadTooltipComponent"; import ToolsComponent from "@/components/core/parameterRenderComponent/components/ToolsComponent"; import { Button } from "@/components/ui/button"; import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs-button"; -import { - DEFAULT_FOLDER, - DEFAULT_FOLDER_DEPRECATED, - MAX_MCP_SERVER_NAME_LENGTH, -} from "@/constants/constants"; +import { MAX_MCP_SERVER_NAME_LENGTH } from "@/constants/constants"; import { createApiKey } from "@/controllers/API"; import { useGetFlowsMCP, @@ -193,7 +189,7 @@ const McpServerTab = ({ folderName }: { folderName: string }) => { const MCP_SERVER_JSON = `{ "mcpServers": { - "lf-${parseString(folderName === DEFAULT_FOLDER_DEPRECATED ? DEFAULT_FOLDER : (folderName ?? "project"), ["snake_case", "no_blank", "lowercase"]).slice(0, MAX_MCP_SERVER_NAME_LENGTH - 4)}": { + "lf-${parseString(folderName ?? "project", ["snake_case", "no_blank", "lowercase"]).slice(0, MAX_MCP_SERVER_NAME_LENGTH - 4)}": { "command": "${selectedPlatform === "windows" ? "cmd" : selectedPlatform === "wsl" ? "wsl" : "uvx"}", "args": [ ${ diff --git a/src/frontend/tests/core/features/folders.spec.ts b/src/frontend/tests/core/features/folders.spec.ts index 1f9837ed8..71672767c 100644 --- a/src/frontend/tests/core/features/folders.spec.ts +++ b/src/frontend/tests/core/features/folders.spec.ts @@ -79,7 +79,7 @@ test("add a flow into a folder by drag and drop", async ({ page }) => { // Wait for the target element to be available before evaluation - await page.waitForSelector('[data-testid="sidebar-nav-My Projects"]', { + await page.waitForSelector('[data-testid="sidebar-nav-Starter Project"]', { timeout: 100000, }); // Create the DataTransfer and File @@ -94,7 +94,7 @@ test("add a flow into a folder by drag and drop", async ({ page }) => { }, jsonContent); // Now dispatch - await page.getByTestId("sidebar-nav-My Projects").dispatchEvent("drop", { + await page.getByTestId("sidebar-nav-Starter Project").dispatchEvent("drop", { dataTransfer, }); // wait for the file to be uploaded failed with waitforselector @@ -107,7 +107,7 @@ test("add a flow into a folder by drag and drop", async ({ page }) => { expect(true).toBeTruthy(); } - await page.getByTestId("sidebar-nav-My Projects").click(); + await page.getByTestId("sidebar-nav-Starter Project").click(); await page.waitForSelector("text=Getting Started:", { timeout: 100000, diff --git a/src/frontend/tests/extended/regression/general-bugs-move-flow-from-folder.spec.ts b/src/frontend/tests/extended/regression/general-bugs-move-flow-from-folder.spec.ts index 4a87afd41..d8a61121d 100644 --- a/src/frontend/tests/extended/regression/general-bugs-move-flow-from-folder.spec.ts +++ b/src/frontend/tests/extended/regression/general-bugs-move-flow-from-folder.spec.ts @@ -22,7 +22,7 @@ test("user must be able to move flow from folder", async ({ page }) => { //wait for the project to be created and changed to the new project await page.waitForTimeout(1000); - await page.getByTestId("sidebar-nav-My Projects").click(); + await page.getByTestId("sidebar-nav-Starter Project").click(); await page.getByText(randomName).hover();