Skip to content

Commit 750d8f6

Browse files
authored
feat: add workspaces page (#128)
* add workspaces route * add header to page * make sure table has correct columns * make sure there are rows for each workspace * . * handle data fetching * add settigns button * visual adjustments
1 parent 5a7e451 commit 750d8f6

File tree

4 files changed

+120
-10
lines changed

4 files changed

+120
-10
lines changed

src/App.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
} from "./components/ui/breadcrumb";
1919
import { useBreadcrumb } from "./hooks/useBreadcrumb";
2020
import { RouteWorkspace } from "./routes/route-workspace";
21+
import { Workspaces } from "./components/Workspaces";
2122

2223
function App() {
2324
const { data: prompts, isLoading } = usePromptsData();
@@ -59,6 +60,7 @@ function App() {
5960
<Route path="/help/:section" element={<Help />} />
6061
<Route path="/certificates" element={<Certificates />} />
6162
<Route path="/workspace/:id" element={<RouteWorkspace />} />
63+
<Route path="/workspaces" element={<Workspaces />} />
6264
<Route
6365
path="/certificates/security"
6466
element={<CertificateSecurity />}

src/components/Workspaces.test.tsx

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { render } from "@/lib/test-utils";
2+
import { screen, waitFor, within } from "@testing-library/react";
3+
import { describe, expect, it } from "vitest";
4+
import { Workspaces } from "./Workspaces";
5+
6+
describe("Workspaces page", () => {
7+
beforeEach(() => {
8+
render(<Workspaces />);
9+
});
10+
11+
it("has a title", () => {
12+
expect(
13+
screen.getByRole("heading", { name: /manage workspaces/i }),
14+
).toBeVisible();
15+
});
16+
17+
it("has a table with the correct columns", () => {
18+
expect(screen.getByRole("columnheader", { name: /name/i })).toBeVisible();
19+
expect(
20+
screen.getByRole("columnheader", { name: /configuration/i }),
21+
).toBeVisible();
22+
});
23+
24+
it("has a row for each workspace", async () => {
25+
await waitFor(() => {
26+
expect(screen.getAllByRole("row").length).toBeGreaterThan(1);
27+
});
28+
29+
expect(
30+
screen.getByRole("rowheader", { name: /myworkspace/i }),
31+
).toBeVisible();
32+
expect(
33+
screen.getByRole("rowheader", { name: /anotherworkspae/i }),
34+
).toBeVisible();
35+
36+
const firstRow = screen.getByRole("row", { name: /myworkspace/i });
37+
const firstButton = within(firstRow).getByRole("link", {
38+
name: /settings/i,
39+
});
40+
41+
expect(firstButton).toBeVisible();
42+
expect(firstButton).toHaveAttribute("href", "/workspace/myworkspace");
43+
});
44+
});

src/components/Workspaces.tsx

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { useWorkspacesData } from "@/hooks/useWorkspacesData";
2+
import {
3+
Cell,
4+
Column,
5+
Heading,
6+
LinkButton,
7+
Row,
8+
Table,
9+
TableBody,
10+
TableHeader,
11+
} from "@stacklok/ui-kit";
12+
import { Settings } from "lucide-react";
13+
14+
export function Workspaces() {
15+
const result = useWorkspacesData();
16+
const workspaces = result.data?.workspaces ?? [];
17+
18+
return (
19+
<div>
20+
<Heading level={1} className="mb-5">
21+
Manage Workspaces
22+
</Heading>
23+
24+
<Table aria-label="List of workspaces">
25+
<Row>
26+
<TableHeader>
27+
<Column id="name" isRowHeader className="w-full">
28+
Name
29+
</Column>
30+
<Column id="configuration" className="w-56">
31+
Configuration
32+
</Column>
33+
</TableHeader>
34+
</Row>
35+
<TableBody>
36+
{workspaces.map((workspace) => (
37+
<Row key={workspace.name}>
38+
<Cell>{workspace.name}</Cell>
39+
<Cell>
40+
<LinkButton
41+
href={`/workspace/${workspace.name}`}
42+
variant="tertiary"
43+
>
44+
<Settings />
45+
Settings
46+
</LinkButton>
47+
</Cell>
48+
</Row>
49+
))}
50+
</TableBody>
51+
</Table>
52+
</div>
53+
);
54+
}
+20-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1-
[
2-
{
3-
"name": "workspace-1",
4-
"is_active": true
5-
},
6-
{
7-
"name": "workspace-2",
8-
"is_active": false
9-
}
10-
]
1+
{
2+
"workspaces": [
3+
{
4+
"name": "default",
5+
"is_active": true
6+
},
7+
{
8+
"name": "myworkspace",
9+
"is_active": false
10+
},
11+
{
12+
"name": "anotherworkspae",
13+
"is_active": false
14+
},
15+
{
16+
"name": "favoriteworkspace",
17+
"is_active": false
18+
}
19+
]
20+
}

0 commit comments

Comments
 (0)