From 3df37483d2c06096aaead0929aab1dab3f9e064d Mon Sep 17 00:00:00 2001 From: Giuseppe Scuglia Date: Tue, 21 Jan 2025 11:32:37 +0100 Subject: [PATCH 1/6] feat: add manage workspaces breadcrumb to creation page --- src/routes/route-workspace-creation.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routes/route-workspace-creation.tsx b/src/routes/route-workspace-creation.tsx index 31ae5ef6..1229bcfc 100644 --- a/src/routes/route-workspace-creation.tsx +++ b/src/routes/route-workspace-creation.tsx @@ -8,6 +8,7 @@ export function RouteWorkspaceCreation() { <> + Manage Workspaces Create Workspace From 70527c2cb1f5c96e028618bcea31436d224344a5 Mon Sep 17 00:00:00 2001 From: Giuseppe Scuglia Date: Tue, 21 Jan 2025 12:45:03 +0100 Subject: [PATCH 2/6] feat: retrieve workspace name --- src/Page.tsx | 2 +- src/features/workspace/components/workspace-name.tsx | 10 ++++++++-- src/routes/route-workspace.tsx | 9 ++++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Page.tsx b/src/Page.tsx index 50982d1f..07799fb0 100644 --- a/src/Page.tsx +++ b/src/Page.tsx @@ -16,7 +16,7 @@ export default function Page() { } /> } /> } /> - } /> + } /> } /> } /> - + diff --git a/src/routes/route-workspace.tsx b/src/routes/route-workspace.tsx index c9f0c4a2..d2bbcd13 100644 --- a/src/routes/route-workspace.tsx +++ b/src/routes/route-workspace.tsx @@ -1,10 +1,16 @@ import { BreadcrumbHome } from "@/components/BreadcrumbHome"; +import { ArchiveWorkspace } from "@/features/workspace-system-prompt/components/archive-workspace"; import { SystemPromptEditor } from "@/features/workspace-system-prompt/components/system-prompt-editor"; import { WorkspaceHeading } from "@/features/workspace/components/workspace-heading"; import { WorkspaceName } from "@/features/workspace/components/workspace-name"; import { Breadcrumb, Breadcrumbs } from "@stacklok/ui-kit"; +import { useParams } from "react-router-dom"; export function RouteWorkspace() { + const { name } = useParams(); + + if (!name) throw Error("Workspace name is required"); + return ( <> @@ -14,8 +20,9 @@ export function RouteWorkspace() { - + + ); } From c843553a3272ce6b77423c91df56fe3e204f3319 Mon Sep 17 00:00:00 2001 From: Giuseppe Scuglia Date: Tue, 21 Jan 2025 12:45:30 +0100 Subject: [PATCH 3/6] test: add archive workspace msw --- src/mocks/msw/handlers.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mocks/msw/handlers.ts b/src/mocks/msw/handlers.ts index c0c0f548..a8700bdb 100644 --- a/src/mocks/msw/handlers.ts +++ b/src/mocks/msw/handlers.ts @@ -36,4 +36,7 @@ export const handlers = [ http.post("*/api/v1/workspaces", () => { return HttpResponse.json(mockedWorkspaces); }), + http.delete("*/api/v1/workspaces/:workspace_name", () => + HttpResponse.json({ status: 204 }), + ), ]; From 7b0c5bcbb2852a888c788dc990a85baa0e254188 Mon Sep 17 00:00:00 2001 From: Giuseppe Scuglia Date: Tue, 21 Jan 2025 12:46:16 +0100 Subject: [PATCH 4/6] feat: archive workspace --- .../__tests__/archive-workspace.test.tsx | 35 +++++++++++++++++++ .../components/archive-workspace.tsx | 35 +++++++++++++++++++ .../hooks/use-archive-workspace.ts | 15 ++++++++ 3 files changed, 85 insertions(+) create mode 100644 src/features/workspace-system-prompt/components/__tests__/archive-workspace.test.tsx create mode 100644 src/features/workspace-system-prompt/components/archive-workspace.tsx create mode 100644 src/features/workspace-system-prompt/hooks/use-archive-workspace.ts diff --git a/src/features/workspace-system-prompt/components/__tests__/archive-workspace.test.tsx b/src/features/workspace-system-prompt/components/__tests__/archive-workspace.test.tsx new file mode 100644 index 00000000..2aa85525 --- /dev/null +++ b/src/features/workspace-system-prompt/components/__tests__/archive-workspace.test.tsx @@ -0,0 +1,35 @@ +import { render } from "@/lib/test-utils"; +import { ArchiveWorkspace } from "../archive-workspace"; +import userEvent from "@testing-library/user-event"; +import { screen, waitFor } from "@testing-library/react"; + +const mockNavigate = vi.fn(); +const mockToast = vi.fn(); +vi.mock("react-router-dom", async () => { + const original = + await vi.importActual( + "react-router-dom", + ); + return { + ...original, + useNavigate: () => mockNavigate, + }; +}); + +vi.mock("@stacklok/ui-kit", async () => { + const original = + await vi.importActual( + "@stacklok/ui-kit", + ); + return { + ...original, + toast: { error: () => mockToast }, + }; +}); + +test("archive workspace", async () => { + render(); + + await userEvent.click(screen.getByRole("button", { name: /archive/i })); + await waitFor(() => expect(mockNavigate).toBeCalled()); +}); diff --git a/src/features/workspace-system-prompt/components/archive-workspace.tsx b/src/features/workspace-system-prompt/components/archive-workspace.tsx new file mode 100644 index 00000000..e1fbfdb4 --- /dev/null +++ b/src/features/workspace-system-prompt/components/archive-workspace.tsx @@ -0,0 +1,35 @@ +import { Card, CardBody, Button, Text } from "@stacklok/ui-kit"; +import { twMerge } from "tailwind-merge"; +import { useArchiveWorkspace } from "../hooks/use-archive-workspace"; + +export function ArchiveWorkspace({ + className, + workspaceName, +}: { + workspaceName: string; + className?: string; +}) { + const { mutate, isPending } = useArchiveWorkspace(); + + return ( + + + Archive Workspace +
+ + Archiving this workspace removes it from the main workspaces list, + though it can be restored if needed. + + +
+
+
+ ); +} diff --git a/src/features/workspace-system-prompt/hooks/use-archive-workspace.ts b/src/features/workspace-system-prompt/hooks/use-archive-workspace.ts new file mode 100644 index 00000000..21e03749 --- /dev/null +++ b/src/features/workspace-system-prompt/hooks/use-archive-workspace.ts @@ -0,0 +1,15 @@ +import { v1DeleteWorkspaceMutation } from "@/api/generated/@tanstack/react-query.gen"; +import { toast } from "@stacklok/ui-kit"; +import { useMutation } from "@tanstack/react-query"; +import { useNavigate } from "react-router-dom"; + +export function useArchiveWorkspace() { + const navigate = useNavigate(); + return useMutation({ + ...v1DeleteWorkspaceMutation(), + onSuccess: () => navigate("/workspaces"), + onError: (err) => { + toast.error(err.detail ? `${err.detail}` : "Failed to archive workspace"); + }, + }); +} From 4c6177fd251d7f70a91098a26563da39c8d9eb23 Mon Sep 17 00:00:00 2001 From: Giuseppe Scuglia Date: Tue, 21 Jan 2025 12:59:07 +0100 Subject: [PATCH 5/6] test: define route configuration --- src/routes/__tests__/route-workspace.test.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/routes/__tests__/route-workspace.test.tsx b/src/routes/__tests__/route-workspace.test.tsx index 30235726..97828fbc 100644 --- a/src/routes/__tests__/route-workspace.test.tsx +++ b/src/routes/__tests__/route-workspace.test.tsx @@ -2,7 +2,13 @@ import { render, within } from "@/lib/test-utils"; import { test, expect } from "vitest"; import { RouteWorkspace } from "../route-workspace"; -const renderComponent = () => render(); +const renderComponent = () => + render(, { + routeConfig: { + initialEntries: ["/workspace/foo"], + }, + pathConfig: "/workspace/:name", + }); vi.mock("@monaco-editor/react", () => { const FakeEditor = vi.fn((props) => { From 92ec869c12ed2e1735cb932b3f9791a009b910de Mon Sep 17 00:00:00 2001 From: Giuseppe Scuglia Date: Tue, 21 Jan 2025 13:03:38 +0100 Subject: [PATCH 6/6] refactor: move archive workspace outside --- .../components/__tests__/archive-workspace.test.tsx | 0 .../components/archive-workspace.tsx | 2 +- src/routes/route-workspace.tsx | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/features/{workspace-system-prompt => workspace}/components/__tests__/archive-workspace.test.tsx (100%) rename src/features/{workspace-system-prompt => workspace}/components/archive-workspace.tsx (90%) diff --git a/src/features/workspace-system-prompt/components/__tests__/archive-workspace.test.tsx b/src/features/workspace/components/__tests__/archive-workspace.test.tsx similarity index 100% rename from src/features/workspace-system-prompt/components/__tests__/archive-workspace.test.tsx rename to src/features/workspace/components/__tests__/archive-workspace.test.tsx diff --git a/src/features/workspace-system-prompt/components/archive-workspace.tsx b/src/features/workspace/components/archive-workspace.tsx similarity index 90% rename from src/features/workspace-system-prompt/components/archive-workspace.tsx rename to src/features/workspace/components/archive-workspace.tsx index e1fbfdb4..5f8f1402 100644 --- a/src/features/workspace-system-prompt/components/archive-workspace.tsx +++ b/src/features/workspace/components/archive-workspace.tsx @@ -1,6 +1,6 @@ import { Card, CardBody, Button, Text } from "@stacklok/ui-kit"; import { twMerge } from "tailwind-merge"; -import { useArchiveWorkspace } from "../hooks/use-archive-workspace"; +import { useArchiveWorkspace } from "../../workspace-system-prompt/hooks/use-archive-workspace"; export function ArchiveWorkspace({ className, diff --git a/src/routes/route-workspace.tsx b/src/routes/route-workspace.tsx index d2bbcd13..1a887ecf 100644 --- a/src/routes/route-workspace.tsx +++ b/src/routes/route-workspace.tsx @@ -1,5 +1,5 @@ import { BreadcrumbHome } from "@/components/BreadcrumbHome"; -import { ArchiveWorkspace } from "@/features/workspace-system-prompt/components/archive-workspace"; +import { ArchiveWorkspace } from "@/features/workspace/components/archive-workspace"; import { SystemPromptEditor } from "@/features/workspace-system-prompt/components/system-prompt-editor"; import { WorkspaceHeading } from "@/features/workspace/components/workspace-heading"; import { WorkspaceName } from "@/features/workspace/components/workspace-name";