diff --git a/src/App.tsx b/src/App.tsx
index f0da106f..cbfe765b 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -18,6 +18,7 @@ import {
} from "./components/ui/breadcrumb";
import { useBreadcrumb } from "./hooks/useBreadcrumb";
import { RouteWorkspace } from "./routes/route-workspace";
+import { Workspaces } from "./components/Workspaces";
function App() {
const { data: prompts, isLoading } = usePromptsData();
@@ -59,6 +60,7 @@ function App() {
} />
} />
} />
+ } />
}
diff --git a/src/components/Workspaces.test.tsx b/src/components/Workspaces.test.tsx
new file mode 100644
index 00000000..e6f706b0
--- /dev/null
+++ b/src/components/Workspaces.test.tsx
@@ -0,0 +1,44 @@
+import { render } from "@/lib/test-utils";
+import { screen, waitFor, within } from "@testing-library/react";
+import { describe, expect, it } from "vitest";
+import { Workspaces } from "./Workspaces";
+
+describe("Workspaces page", () => {
+ beforeEach(() => {
+ render();
+ });
+
+ it("has a title", () => {
+ expect(
+ screen.getByRole("heading", { name: /manage workspaces/i }),
+ ).toBeVisible();
+ });
+
+ it("has a table with the correct columns", () => {
+ expect(screen.getByRole("columnheader", { name: /name/i })).toBeVisible();
+ expect(
+ screen.getByRole("columnheader", { name: /configuration/i }),
+ ).toBeVisible();
+ });
+
+ it("has a row for each workspace", async () => {
+ await waitFor(() => {
+ expect(screen.getAllByRole("row").length).toBeGreaterThan(1);
+ });
+
+ expect(
+ screen.getByRole("rowheader", { name: /myworkspace/i }),
+ ).toBeVisible();
+ expect(
+ screen.getByRole("rowheader", { name: /anotherworkspae/i }),
+ ).toBeVisible();
+
+ const firstRow = screen.getByRole("row", { name: /myworkspace/i });
+ const firstButton = within(firstRow).getByRole("link", {
+ name: /settings/i,
+ });
+
+ expect(firstButton).toBeVisible();
+ expect(firstButton).toHaveAttribute("href", "/workspace/myworkspace");
+ });
+});
diff --git a/src/components/Workspaces.tsx b/src/components/Workspaces.tsx
new file mode 100644
index 00000000..e57787a5
--- /dev/null
+++ b/src/components/Workspaces.tsx
@@ -0,0 +1,54 @@
+import { useWorkspacesData } from "@/hooks/useWorkspacesData";
+import {
+ Cell,
+ Column,
+ Heading,
+ LinkButton,
+ Row,
+ Table,
+ TableBody,
+ TableHeader,
+} from "@stacklok/ui-kit";
+import { Settings } from "lucide-react";
+
+export function Workspaces() {
+ const result = useWorkspacesData();
+ const workspaces = result.data?.workspaces ?? [];
+
+ return (
+
+
+ Manage Workspaces
+
+
+
+
+
+
+ Name
+
+
+ Configuration
+
+
+
+
+ {workspaces.map((workspace) => (
+
+ {workspace.name} |
+
+
+
+ Settings
+
+ |
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/mocks/msw/fixtures/GET_WORKSPACES.json b/src/mocks/msw/fixtures/GET_WORKSPACES.json
index e7669999..571fdb2b 100644
--- a/src/mocks/msw/fixtures/GET_WORKSPACES.json
+++ b/src/mocks/msw/fixtures/GET_WORKSPACES.json
@@ -1,10 +1,20 @@
-[
- {
- "name": "workspace-1",
- "is_active": true
- },
- {
- "name": "workspace-2",
- "is_active": false
- }
-]
\ No newline at end of file
+{
+ "workspaces": [
+ {
+ "name": "default",
+ "is_active": true
+ },
+ {
+ "name": "myworkspace",
+ "is_active": false
+ },
+ {
+ "name": "anotherworkspae",
+ "is_active": false
+ },
+ {
+ "name": "favoriteworkspace",
+ "is_active": false
+ }
+ ]
+}