diff --git a/src/App.test.tsx b/src/App.test.tsx
index 298c77b1..8593b0c7 100644
--- a/src/App.test.tsx
+++ b/src/App.test.tsx
@@ -61,7 +61,7 @@ describe("App", () => {
render();
await waitFor(() =>
expect(
- screen.getByRole("link", { name: /codeGate dashboard/i }),
+ screen.getByRole("link", { name: "CodeGate Dashboard" }),
).toBeVisible(),
);
expect(screen.getByRole("link", { name: "Dashboard" })).toBeVisible();
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index b4bc5743..2f28839c 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -2,6 +2,7 @@ import { Link } from "react-router-dom";
import { SidebarTrigger } from "./ui/sidebar";
import { HoverPopover } from "./HoverPopover";
import { Separator, ButtonDarkMode } from "@stacklok/ui-kit";
+import { WorkspacesSelection } from "@/features/workspace/components/workspaces-selection";
export function Header({ hasError }: { hasError?: boolean }) {
return (
@@ -9,21 +10,23 @@ export function Header({ hasError }: { hasError?: boolean }) {
aria-label="App header"
className="shrink-0 h-16 px-3 items-center flex w-full bg-gray-25 border-b-gray-200 border-b"
>
-
+
{!hasError && (
<>
-
+
>
)}
-
diff --git a/src/features/workspace/components/workspaces-selection.tsx b/src/features/workspace/components/workspaces-selection.tsx
new file mode 100644
index 00000000..010eac1e
--- /dev/null
+++ b/src/features/workspace/components/workspaces-selection.tsx
@@ -0,0 +1,92 @@
+import { useWorkspacesData } from "@/hooks/useWorkspacesData";
+import {
+ Button,
+ DialogTrigger,
+ Input,
+ ListBox,
+ ListBoxItem,
+ Popover,
+ SearchField,
+ Separator,
+} from "@stacklok/ui-kit";
+import { useQueryClient } from "@tanstack/react-query";
+import clsx from "clsx";
+import { ChevronDown, Search, Settings } from "lucide-react";
+import { useState } from "react";
+import { Link } from "react-router-dom";
+
+export function WorkspacesSelection() {
+ const queryClient = useQueryClient();
+ const { data } = useWorkspacesData();
+ const [isOpen, setIsOpen] = useState(false);
+ const [searchWorkspace, setSearchWorkspace] = useState("");
+ const workspaces = data?.workspaces ?? [];
+ const filteredWorkspaces = workspaces.filter((workspace) =>
+ workspace.name.toLowerCase().includes(searchWorkspace.toLowerCase()),
+ );
+ const activeWorkspace = workspaces.find((workspace) => workspace.is_active);
+
+ const handleWorkspaceClick = () => {
+ queryClient.invalidateQueries({ refetchType: "all" });
+ setIsOpen(false);
+ };
+
+ return (
+ setIsOpen(test)}>
+
+
+
+
+
+
+ } />
+
+
+
+
(
+ No workspaces found
+ )}
+ >
+ {(item) => (
+ handleWorkspaceClick()}
+ className={clsx(
+ "cursor-pointer py-2 m-1 text-base hover:bg-gray-300",
+ {
+ "bg-gray-900 text-white hover:text-secondary":
+ item.is_active,
+ },
+ )}
+ key={item.name}
+ >
+ {item.name}
+
+ )}
+
+
+
setIsOpen(false)}
+ className="text-secondary pt-3 px-2 gap-2 flex"
+ >
+
+ Manage Workspaces
+
+
+
+
+ );
+}
diff --git a/src/hooks/useSse.ts b/src/hooks/useSse.ts
index 9ee84483..baf753fc 100644
--- a/src/hooks/useSse.ts
+++ b/src/hooks/useSse.ts
@@ -12,12 +12,12 @@ export function useSse() {
useEffect(() => {
const eventSource = new EventSource(
- `${BASE_URL}/dashboard/alerts_notification`,
+ `${BASE_URL}/api/v1/dashboard/alerts_notification`,
);
eventSource.onmessage = function (event) {
- queryClient.invalidateQueries({ refetchType: "all" });
if (event.data.toLowerCase().includes("new alert detected")) {
+ queryClient.invalidateQueries({ refetchType: "all" });
sendNotification("CodeGate Dashboard", {
body: "New Alert detected!",
});
diff --git a/src/mocks/msw/fixtures/GET_WORKSPACES.json b/src/mocks/msw/fixtures/GET_WORKSPACES.json
new file mode 100644
index 00000000..e7669999
--- /dev/null
+++ b/src/mocks/msw/fixtures/GET_WORKSPACES.json
@@ -0,0 +1,10 @@
+[
+ {
+ "name": "workspace-1",
+ "is_active": true
+ },
+ {
+ "name": "workspace-2",
+ "is_active": false
+ }
+]
\ No newline at end of file
diff --git a/src/mocks/msw/handlers.ts b/src/mocks/msw/handlers.ts
index 46e62cd6..f202e94f 100644
--- a/src/mocks/msw/handlers.ts
+++ b/src/mocks/msw/handlers.ts
@@ -1,6 +1,7 @@
import { http, HttpResponse } from "msw";
import mockedPrompts from "@/mocks/msw/fixtures/GET_MESSAGES.json";
import mockedAlerts from "@/mocks/msw/fixtures/GET_ALERTS.json";
+import mockedWorkspaces from "@/mocks/msw/fixtures/GET_WORKSPACES.json";
export const handlers = [
http.get("*/health", () =>
@@ -20,4 +21,7 @@ export const handlers = [
http.get("*/dashboard/alerts", () => {
return HttpResponse.json(mockedAlerts);
}),
+ http.get("*/workspaces", () => {
+ return HttpResponse.json(mockedWorkspaces);
+ }),
];