diff --git a/src/api/generated/@tanstack/react-query.gen.ts b/src/api/generated/@tanstack/react-query.gen.ts index dd8c37dd..03b41ea4 100644 --- a/src/api/generated/@tanstack/react-query.gen.ts +++ b/src/api/generated/@tanstack/react-query.gen.ts @@ -14,6 +14,8 @@ import { v1ListActiveWorkspaces, v1ActivateWorkspace, v1DeleteWorkspace, + v1GetWorkspaceAlerts, + v1GetWorkspaceMessages, } from "../sdk.gen"; import type { V1CreateWorkspaceData, @@ -25,6 +27,8 @@ import type { V1DeleteWorkspaceData, V1DeleteWorkspaceError, V1DeleteWorkspaceResponse, + V1GetWorkspaceAlertsData, + V1GetWorkspaceMessagesData, } from "../types.gen"; type QueryKey = [ @@ -297,3 +301,45 @@ export const v1DeleteWorkspaceMutation = ( }; return mutationOptions; }; + +export const v1GetWorkspaceAlertsQueryKey = ( + options: OptionsLegacyParser, +) => [createQueryKey("v1GetWorkspaceAlerts", options)]; + +export const v1GetWorkspaceAlertsOptions = ( + options: OptionsLegacyParser, +) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await v1GetWorkspaceAlerts({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: v1GetWorkspaceAlertsQueryKey(options), + }); +}; + +export const v1GetWorkspaceMessagesQueryKey = ( + options: OptionsLegacyParser, +) => [createQueryKey("v1GetWorkspaceMessages", options)]; + +export const v1GetWorkspaceMessagesOptions = ( + options: OptionsLegacyParser, +) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await v1GetWorkspaceMessages({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: v1GetWorkspaceMessagesQueryKey(options), + }); +}; diff --git a/src/api/generated/sdk.gen.ts b/src/api/generated/sdk.gen.ts index f7a504b0..26c83a75 100644 --- a/src/api/generated/sdk.gen.ts +++ b/src/api/generated/sdk.gen.ts @@ -29,6 +29,12 @@ import type { V1DeleteWorkspaceData, V1DeleteWorkspaceError, V1DeleteWorkspaceResponse, + V1GetWorkspaceAlertsData, + V1GetWorkspaceAlertsError, + V1GetWorkspaceAlertsResponse, + V1GetWorkspaceMessagesData, + V1GetWorkspaceMessagesError, + V1GetWorkspaceMessagesResponse, } from "./types.gen"; export const client = createClient(createConfig()); @@ -203,3 +209,37 @@ export const v1DeleteWorkspace = ( url: "/api/v1/workspaces/{workspace_name}", }); }; + +/** + * Get Workspace Alerts + * Get alerts for a workspace. + */ +export const v1GetWorkspaceAlerts = ( + options: OptionsLegacyParser, +) => { + return (options?.client ?? client).get< + V1GetWorkspaceAlertsResponse, + V1GetWorkspaceAlertsError, + ThrowOnError + >({ + ...options, + url: "/api/v1/workspaces/{workspace_name}/alerts", + }); +}; + +/** + * Get Workspace Messages + * Get messages for a workspace. + */ +export const v1GetWorkspaceMessages = ( + options: OptionsLegacyParser, +) => { + return (options?.client ?? client).get< + V1GetWorkspaceMessagesResponse, + V1GetWorkspaceMessagesError, + ThrowOnError + >({ + ...options, + url: "/api/v1/workspaces/{workspace_name}/messages", + }); +}; diff --git a/src/api/generated/types.gen.ts b/src/api/generated/types.gen.ts index fa5acf81..fb0e0f7f 100644 --- a/src/api/generated/types.gen.ts +++ b/src/api/generated/types.gen.ts @@ -118,7 +118,7 @@ export type V1CreateWorkspaceData = { body: CreateWorkspaceRequest; }; -export type V1CreateWorkspaceResponse = unknown; +export type V1CreateWorkspaceResponse = Workspace; export type V1CreateWorkspaceError = HTTPValidationError; @@ -143,6 +143,26 @@ export type V1DeleteWorkspaceData = { }; }; -export type V1DeleteWorkspaceResponse = void; +export type V1DeleteWorkspaceResponse = unknown; export type V1DeleteWorkspaceError = HTTPValidationError; + +export type V1GetWorkspaceAlertsData = { + path: { + workspace_name: string; + }; +}; + +export type V1GetWorkspaceAlertsResponse = Array; + +export type V1GetWorkspaceAlertsError = HTTPValidationError; + +export type V1GetWorkspaceMessagesData = { + path: { + workspace_name: string; + }; +}; + +export type V1GetWorkspaceMessagesResponse = Array; + +export type V1GetWorkspaceMessagesError = HTTPValidationError; diff --git a/src/api/openapi.json b/src/api/openapi.json index aadbee66..744fc9d2 100644 --- a/src/api/openapi.json +++ b/src/api/openapi.json @@ -8,9 +8,7 @@ "paths": { "/health": { "get": { - "tags": [ - "System" - ], + "tags": ["System"], "summary": "Health Check", "operationId": "health_check_health_get", "responses": { @@ -27,10 +25,7 @@ }, "/api/v1/dashboard/messages": { "get": { - "tags": [ - "CodeGate API", - "Dashboard" - ], + "tags": ["CodeGate API", "Dashboard"], "summary": "Get Messages", "description": "Get all the messages from the database and return them as a list of conversations.", "operationId": "v1_get_messages", @@ -54,10 +49,7 @@ }, "/api/v1/dashboard/alerts": { "get": { - "tags": [ - "CodeGate API", - "Dashboard" - ], + "tags": ["CodeGate API", "Dashboard"], "summary": "Get Alerts", "description": "Get all the messages from the database and return them as a list of conversations.", "operationId": "v1_get_alerts", @@ -88,10 +80,7 @@ }, "/api/v1/dashboard/alerts_notification": { "get": { - "tags": [ - "CodeGate API", - "Dashboard" - ], + "tags": ["CodeGate API", "Dashboard"], "summary": "Stream Sse", "description": "Send alerts event", "operationId": "v1_stream_sse", @@ -109,10 +98,7 @@ }, "/api/v1/dashboard/version": { "get": { - "tags": [ - "CodeGate API", - "Dashboard" - ], + "tags": ["CodeGate API", "Dashboard"], "summary": "Version Check", "operationId": "v1_version_check", "responses": { @@ -129,10 +115,7 @@ }, "/api/v1/workspaces": { "get": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "List Workspaces", "description": "List all workspaces.", "operationId": "v1_list_workspaces", @@ -150,10 +133,7 @@ } }, "post": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "Create Workspace", "description": "Create a new workspace.", "operationId": "v1_create_workspace", @@ -172,7 +152,9 @@ "description": "Successful Response", "content": { "application/json": { - "schema": {} + "schema": { + "$ref": "#/components/schemas/Workspace" + } } } }, @@ -191,10 +173,7 @@ }, "/api/v1/workspaces/active": { "get": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "List Active Workspaces", "description": "List all active workspaces.\n\nIn it's current form, this function will only return one workspace. That is,\nthe globally active workspace.", "operationId": "v1_list_active_workspaces", @@ -212,10 +191,7 @@ } }, "post": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "Activate Workspace", "description": "Activate a workspace by name.", "operationId": "v1_activate_workspace", @@ -264,10 +240,7 @@ }, "/api/v1/workspaces/{workspace_name}": { "delete": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "Delete Workspace", "description": "Delete a workspace by name.", "operationId": "v1_delete_workspace", @@ -283,8 +256,110 @@ } ], "responses": { - "204": { - "description": "Successful Response" + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/api/v1/workspaces/{workspace_name}/alerts": { + "get": { + "tags": ["CodeGate API", "Workspaces"], + "summary": "Get Workspace Alerts", + "description": "Get alerts for a workspace.", + "operationId": "v1_get_workspace_alerts", + "parameters": [ + { + "name": "workspace_name", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Workspace Name" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/AlertConversation" + }, + { + "type": "null" + } + ] + }, + "title": "Response V1 Get Workspace Alerts" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/api/v1/workspaces/{workspace_name}/messages": { + "get": { + "tags": ["CodeGate API", "Workspaces"], + "summary": "Get Workspace Messages", + "description": "Get messages for a workspace.", + "operationId": "v1_get_workspace_messages", + "parameters": [ + { + "name": "workspace_name", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Workspace Name" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Conversation" + }, + "title": "Response V1 Get Workspace Messages" + } + } + } }, "422": { "description": "Validation Error", @@ -310,9 +385,7 @@ } }, "type": "object", - "required": [ - "name" - ], + "required": ["name"], "title": "ActivateWorkspaceRequest" }, "ActiveWorkspace": { @@ -330,11 +403,7 @@ } }, "type": "object", - "required": [ - "name", - "is_active", - "last_updated" - ], + "required": ["name", "is_active", "last_updated"], "title": "ActiveWorkspace" }, "AlertConversation": { @@ -421,11 +490,7 @@ } }, "type": "object", - "required": [ - "message", - "timestamp", - "message_id" - ], + "required": ["message", "timestamp", "message_id"], "title": "ChatMessage", "description": "Represents a chat message." }, @@ -466,11 +531,7 @@ } }, "type": "object", - "required": [ - "code", - "language", - "filepath" - ], + "required": ["code", "language", "filepath"], "title": "CodeSnippet" }, "Conversation": { @@ -526,9 +587,7 @@ } }, "type": "object", - "required": [ - "name" - ], + "required": ["name"], "title": "CreateWorkspaceRequest" }, "HTTPValidationError": { @@ -555,9 +614,7 @@ } }, "type": "object", - "required": [ - "workspaces" - ], + "required": ["workspaces"], "title": "ListActiveWorkspacesResponse" }, "ListWorkspacesResponse": { @@ -571,9 +628,7 @@ } }, "type": "object", - "required": [ - "workspaces" - ], + "required": ["workspaces"], "title": "ListWorkspacesResponse" }, "QuestionAnswer": { @@ -593,10 +648,7 @@ } }, "type": "object", - "required": [ - "question", - "answer" - ], + "required": ["question", "answer"], "title": "QuestionAnswer", "description": "Represents a question and answer pair." }, @@ -626,11 +678,7 @@ } }, "type": "object", - "required": [ - "loc", - "msg", - "type" - ], + "required": ["loc", "msg", "type"], "title": "ValidationError" }, "Workspace": { @@ -645,10 +693,7 @@ } }, "type": "object", - "required": [ - "name", - "is_active" - ], + "required": ["name", "is_active"], "title": "Workspace" } } diff --git a/src/features/workspace/components/workspaces-selection.tsx b/src/features/workspace/components/workspaces-selection.tsx index eefcd229..87965add 100644 --- a/src/features/workspace/components/workspaces-selection.tsx +++ b/src/features/workspace/components/workspaces-selection.tsx @@ -13,19 +13,17 @@ import { import { useQueryClient } from "@tanstack/react-query"; import { ChevronDown, Search, Settings } from "lucide-react"; import { useState } from "react"; -import { useActiveWorkspaces } from "../hooks/use-active-workspaces"; import { useActivateWorkspace } from "../hooks/use-activate-workspace"; import clsx from "clsx"; +import { useActiveWorkspaceName } from "../hooks/use-active-workspace-name"; export function WorkspacesSelection() { const queryClient = useQueryClient(); const { data: workspacesResponse } = useListWorkspaces(); - const { data: activeWorkspacesResponse } = useActiveWorkspaces(); const { mutateAsync: activateWorkspace } = useActivateWorkspace(); - const activeWorkspaceName: string | null = - activeWorkspacesResponse?.workspaces?.[0]?.name ?? null; + const { data: activeWorkspaceName } = useActiveWorkspaceName(); const [isOpen, setIsOpen] = useState(false); const [searchWorkspace, setSearchWorkspace] = useState(""); diff --git a/src/features/workspace/hooks/use-active-workspace-name.ts b/src/features/workspace/hooks/use-active-workspace-name.ts new file mode 100644 index 00000000..ab365f59 --- /dev/null +++ b/src/features/workspace/hooks/use-active-workspace-name.ts @@ -0,0 +1,7 @@ +import { useActiveWorkspaces } from "./use-active-workspaces"; + +export function useActiveWorkspaceName() { + return useActiveWorkspaces({ + select: (d) => d?.workspaces?.[0]?.name ?? null, + }); +} diff --git a/src/features/workspace/hooks/use-active-workspaces.ts b/src/features/workspace/hooks/use-active-workspaces.ts index 8079bd7d..3a088a31 100644 --- a/src/features/workspace/hooks/use-active-workspaces.ts +++ b/src/features/workspace/hooks/use-active-workspaces.ts @@ -1,7 +1,12 @@ +import { ListActiveWorkspacesResponse } from "@/api/generated"; import { v1ListActiveWorkspacesOptions } from "@/api/generated/@tanstack/react-query.gen"; import { useQuery } from "@tanstack/react-query"; -export function useActiveWorkspaces() { +export function useActiveWorkspaces({ + select, +}: { + select?: (data?: ListActiveWorkspacesResponse) => T; +} = {}) { return useQuery({ ...v1ListActiveWorkspacesOptions(), refetchInterval: 5_000, @@ -10,5 +15,6 @@ export function useActiveWorkspaces() { refetchOnReconnect: true, refetchOnWindowFocus: true, retry: false, + select, }); } diff --git a/src/hooks/useAlertsData.ts b/src/hooks/useAlertsData.ts index d26af557..8d40bc34 100644 --- a/src/hooks/useAlertsData.ts +++ b/src/hooks/useAlertsData.ts @@ -1,12 +1,19 @@ import { useQuery } from "@tanstack/react-query"; -import { AlertConversation, v1GetAlerts } from "@/api/generated"; +import { + AlertConversation, + v1GetWorkspaceAlerts, + V1GetWorkspaceAlertsData, +} from "@/api/generated"; import { getMaliciousPackage } from "@/lib/utils"; import { MaliciousPkgType, TriggerType } from "@/types"; import { useAlertSearch } from "./useAlertSearch"; -import { v1GetAlertsQueryKey } from "@/api/generated/@tanstack/react-query.gen"; +import { v1GetWorkspaceAlertsQueryKey } from "@/api/generated/@tanstack/react-query.gen"; +import { useActiveWorkspaceName } from "@/features/workspace/hooks/use-active-workspace-name"; -const fetchAlerts = async (): Promise => { - const { data } = await v1GetAlerts(); +const fetchAlerts = async ( + options: V1GetWorkspaceAlertsData, +): Promise => { + const { data } = await v1GetWorkspaceAlerts(options); const results = (data ?? []) .filter((alert): alert is AlertConversation => alert !== null) @@ -25,9 +32,17 @@ const fetchAlerts = async (): Promise => { }; export const useAlertsData = ({ ...args } = {}) => { + const { data: activeWorkspaceName } = useActiveWorkspaceName(); + + const options: V1GetWorkspaceAlertsData = { + path: { + workspace_name: activeWorkspaceName ?? "default", + }, + }; + return useQuery({ - queryKey: v1GetAlertsQueryKey(), - queryFn: fetchAlerts, + queryKey: v1GetWorkspaceAlertsQueryKey(options), + queryFn: () => fetchAlerts(options), ...args, }); }; diff --git a/src/hooks/usePromptsData.ts b/src/hooks/usePromptsData.ts index 49ce56c6..1ef90e67 100644 --- a/src/hooks/usePromptsData.ts +++ b/src/hooks/usePromptsData.ts @@ -1,6 +1,11 @@ import { useQuery } from "@tanstack/react-query"; -import { Conversation, V1GetMessagesResponse } from "@/api/generated"; -import { v1GetMessagesOptions } from "@/api/generated/@tanstack/react-query.gen"; +import { + Conversation, + V1GetMessagesResponse, + V1GetWorkspaceMessagesData, +} from "@/api/generated"; +import { v1GetWorkspaceMessagesOptions } from "@/api/generated/@tanstack/react-query.gen"; +import { useActiveWorkspaceName } from "@/features/workspace/hooks/use-active-workspace-name"; const selectConversations = (data: V1GetMessagesResponse): Conversation[] => { return data.filter((prompt) => @@ -9,8 +14,16 @@ const selectConversations = (data: V1GetMessagesResponse): Conversation[] => { }; export const usePromptsData = () => { + const { data: activeWorkspaceName } = useActiveWorkspaceName(); + + const options: V1GetWorkspaceMessagesData = { + path: { + workspace_name: activeWorkspaceName ?? "default", + }, + }; + return useQuery({ - ...v1GetMessagesOptions(), + ...v1GetWorkspaceMessagesOptions(options), select: selectConversations, }); }; diff --git a/src/mocks/msw/handlers.ts b/src/mocks/msw/handlers.ts index a0b5db3b..c0c0f548 100644 --- a/src/mocks/msw/handlers.ts +++ b/src/mocks/msw/handlers.ts @@ -24,10 +24,10 @@ export const handlers = [ }, ]), ), - http.get("*/api/v1/dashboard/messages", () => { + http.get("*/api/v1/workspaces/:name/messages", () => { return HttpResponse.json(mockedPrompts); }), - http.get("*/api/v1/dashboard/alerts", () => { + http.get("*/api/v1/workspaces/:name/alerts", () => { return HttpResponse.json(mockedAlerts); }), http.get("*/api/v1/workspaces", () => { diff --git a/src/routes/__tests__/route-dashboard.test.tsx b/src/routes/__tests__/route-dashboard.test.tsx index 7ee6bd86..1f6d30bf 100644 --- a/src/routes/__tests__/route-dashboard.test.tsx +++ b/src/routes/__tests__/route-dashboard.test.tsx @@ -89,7 +89,7 @@ const fakeConversionation2 = { function mockAlertsWithMaliciousPkg() { server.use( - http.get("*/dashboard/alerts", () => { + http.get("*/workspaces/:name/alerts", () => { return HttpResponse.json([fakeConversionation1, fakeConversionation2]); }), ); @@ -97,7 +97,7 @@ function mockAlertsWithMaliciousPkg() { function mockManyAlerts() { server.use( - http.get("*/dashboard/alerts", () => { + http.get("*/workspaces/:name/alerts", () => { return HttpResponse.json( [ ...mockedAlerts,