diff --git a/.github/workflows/_release-please.yml b/.github/workflows/_release-please.yml index b508f8f2..bb1fae8a 100644 --- a/.github/workflows/_release-please.yml +++ b/.github/workflows/_release-please.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest continue-on-error: true steps: - - uses: googleapis/release-please-action@7987652d64b4581673a76e33ad5e98e3dd56832f # v4 + - uses: googleapis/release-please-action@d1a8f221d7723166f48a584aebba00ef3f6febec # v4 id: release with: token: ${{ secrets.GH_PAT_RELEASE_PLEASE }} diff --git a/CHANGELOG.md b/CHANGELOG.md index b18dc92e..86e833d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## [0.19.0](https://github.com/stacklok/codegate-ui/compare/v0.18.1...v0.19.0) (2025-03-05) + + +### Features + +* replace muxing placeholder ([#365](https://github.com/stacklok/codegate-ui/issues/365)) ([b426bf4](https://github.com/stacklok/codegate-ui/commit/b426bf417bccd294a2bd29d4ab98a5883135529d)) + + +### Bug Fixes + +* handle breaking changes to workspace config ([#349](https://github.com/stacklok/codegate-ui/issues/349)) ([6a897e3](https://github.com/stacklok/codegate-ui/commit/6a897e3331d3b907b7d0a264bf51bc9239bc3aee)) +* remove duplicate react-query-devtools ([#342](https://github.com/stacklok/codegate-ui/issues/342)) ([63bf5ea](https://github.com/stacklok/codegate-ui/commit/63bf5ea14caebd1acf812c7bd71ac40226938b09)) + ## [0.18.1](https://github.com/stacklok/codegate-ui/compare/v0.18.0...v0.18.1) (2025-03-03) diff --git a/index.html b/index.html index 1ba893ea..89a4095c 100644 --- a/index.html +++ b/index.html @@ -7,6 +7,11 @@
+ diff --git a/package-lock.json b/package-lock.json index 7eceed0d..934f3a8d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vite-project", - "version": "0.18.1", + "version": "0.19.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "vite-project", - "version": "0.18.1", + "version": "0.19.0", "dependencies": { "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", @@ -65,7 +65,7 @@ "@vitest/expect": "^3.0.5", "@vitest/ui": "^3.0.5", "autoprefixer": "^10.4.20", - "eslint": "^9.18.0", + "eslint": "^9.21.0", "eslint-import-resolver-typescript": "^3.7.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-react-hooks": "^5.1.0", @@ -79,7 +79,7 @@ "lint-staged": "^15.3.0", "msw": "^2.7.0", "postcss": "^8.4.49", - "prettier": "3.4.2", + "prettier": "3.5.3", "prettier-plugin-classnames": "^0.7.6", "prettier-plugin-merge": "^0.7.2", "prettier-plugin-tailwindcss": "^0.6.11", @@ -943,13 +943,13 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", - "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", + "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.5", + "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -958,10 +958,11 @@ } }, "node_modules/@eslint/core": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz", - "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", + "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" }, @@ -970,9 +971,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", - "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz", + "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1007,18 +1008,19 @@ } }, "node_modules/@eslint/js": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz", - "integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==", + "version": "9.21.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz", + "integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/object-schema": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", - "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1026,12 +1028,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz", - "integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz", + "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.10.0", + "@eslint/core": "^0.12.0", "levn": "^0.4.1" }, "engines": { @@ -1250,9 +1253,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", - "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -6946,21 +6949,22 @@ } }, "node_modules/eslint": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz", - "integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==", + "version": "9.21.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.21.0.tgz", + "integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.19.0", - "@eslint/core": "^0.10.0", - "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.18.0", - "@eslint/plugin-kit": "^0.2.5", + "@eslint/config-array": "^0.19.2", + "@eslint/core": "^0.12.0", + "@eslint/eslintrc": "^3.3.0", + "@eslint/js": "9.21.0", + "@eslint/plugin-kit": "^0.2.7", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.1", + "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", @@ -8343,9 +8347,9 @@ } }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11510,10 +11514,11 @@ } }, "node_modules/prettier": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", - "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, + "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, diff --git a/package.json b/package.json index 3f17577a..f6b3391a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vite-project", "private": true, - "version": "0.18.1", + "version": "0.19.0", "type": "module", "scripts": { "dev": "vite", @@ -78,7 +78,7 @@ "@vitest/expect": "^3.0.5", "@vitest/ui": "^3.0.5", "autoprefixer": "^10.4.20", - "eslint": "^9.18.0", + "eslint": "^9.21.0", "eslint-import-resolver-typescript": "^3.7.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-react-hooks": "^5.1.0", @@ -92,7 +92,7 @@ "lint-staged": "^15.3.0", "msw": "^2.7.0", "postcss": "^8.4.49", - "prettier": "3.4.2", + "prettier": "3.5.3", "prettier-plugin-classnames": "^0.7.6", "prettier-plugin-merge": "^0.7.2", "prettier-plugin-tailwindcss": "^0.6.11", diff --git a/src/api/generated/@tanstack/react-query.gen.ts b/src/api/generated/@tanstack/react-query.gen.ts index a22a7421..cf1307ef 100644 --- a/src/api/generated/@tanstack/react-query.gen.ts +++ b/src/api/generated/@tanstack/react-query.gen.ts @@ -17,6 +17,7 @@ import { v1CreateWorkspace, v1ListActiveWorkspaces, v1ActivateWorkspace, + v1UpdateWorkspace, v1DeleteWorkspace, v1ListArchivedWorkspaces, v1RecoverWorkspace, @@ -55,6 +56,9 @@ import type { V1ActivateWorkspaceData, V1ActivateWorkspaceError, V1ActivateWorkspaceResponse, + V1UpdateWorkspaceData, + V1UpdateWorkspaceError, + V1UpdateWorkspaceResponse, V1DeleteWorkspaceData, V1DeleteWorkspaceError, V1DeleteWorkspaceResponse, @@ -441,6 +445,26 @@ export const v1ActivateWorkspaceMutation = ( return mutationOptions } +export const v1UpdateWorkspaceMutation = ( + options?: Partial> +) => { + const mutationOptions: UseMutationOptions< + V1UpdateWorkspaceResponse, + V1UpdateWorkspaceError, + OptionsLegacyParser + > = { + mutationFn: async (localOptions) => { + const { data } = await v1UpdateWorkspace({ + ...options, + ...localOptions, + throwOnError: true, + }) + return data + }, + } + return mutationOptions +} + export const v1DeleteWorkspaceMutation = ( options?: Partial> ) => { diff --git a/src/api/generated/sdk.gen.ts b/src/api/generated/sdk.gen.ts index e9d216d9..4b8998a7 100644 --- a/src/api/generated/sdk.gen.ts +++ b/src/api/generated/sdk.gen.ts @@ -41,6 +41,9 @@ import type { V1ActivateWorkspaceData, V1ActivateWorkspaceError, V1ActivateWorkspaceResponse, + V1UpdateWorkspaceData, + V1UpdateWorkspaceError, + V1UpdateWorkspaceResponse, V1DeleteWorkspaceData, V1DeleteWorkspaceError, V1DeleteWorkspaceResponse, @@ -312,6 +315,23 @@ export const v1ActivateWorkspace = ( }) } +/** + * Update Workspace + * Update a workspace. + */ +export const v1UpdateWorkspace = ( + options: OptionsLegacyParser +) => { + return (options?.client ?? client).put< + V1UpdateWorkspaceResponse, + V1UpdateWorkspaceError, + ThrowOnError + >({ + ...options, + url: '/api/v1/workspaces/{workspace_name}', + }) +} + /** * Delete Workspace * Delete a workspace by name. diff --git a/src/api/generated/types.gen.ts b/src/api/generated/types.gen.ts index f10667f5..896e4bc3 100644 --- a/src/api/generated/types.gen.ts +++ b/src/api/generated/types.gen.ts @@ -109,14 +109,18 @@ export type Conversation = { alerts?: Array } -export type CreateOrRenameWorkspaceRequest = { +export type CustomInstructions = { + prompt: string +} + +export type FullWorkspace_Input = { name: string - config?: WorkspaceConfig | null - rename_to?: string | null + config?: WorkspaceConfig_Input | null } -export type CustomInstructions = { - prompt: string +export type FullWorkspace_Output = { + name: string + config?: WorkspaceConfig_Output | null } export type HTTPValidationError = { @@ -265,8 +269,13 @@ export type Workspace = { is_active: boolean } -export type WorkspaceConfig = { - system_prompt: string +export type WorkspaceConfig_Input = { + custom_instructions: string + muxing_rules: Array +} + +export type WorkspaceConfig_Output = { + custom_instructions: string muxing_rules: Array } @@ -362,10 +371,10 @@ export type V1ListWorkspacesResponse = ListWorkspacesResponse export type V1ListWorkspacesError = unknown export type V1CreateWorkspaceData = { - body: CreateOrRenameWorkspaceRequest + body: FullWorkspace_Input } -export type V1CreateWorkspaceResponse = Workspace +export type V1CreateWorkspaceResponse = FullWorkspace_Output export type V1CreateWorkspaceError = HTTPValidationError @@ -384,6 +393,17 @@ export type V1ActivateWorkspaceResponse = unknown export type V1ActivateWorkspaceError = HTTPValidationError +export type V1UpdateWorkspaceData = { + body: FullWorkspace_Input + path: { + workspace_name: string + } +} + +export type V1UpdateWorkspaceResponse = FullWorkspace_Output + +export type V1UpdateWorkspaceError = HTTPValidationError + export type V1DeleteWorkspaceData = { path: { workspace_name: string diff --git a/src/api/openapi.json b/src/api/openapi.json index deb5c2de..c636d394 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/provider-endpoints": { "get": { - "tags": [ - "CodeGate API", - "Providers" - ], + "tags": ["CodeGate API", "Providers"], "summary": "List Provider Endpoints", "description": "List all provider endpoints.", "operationId": "v1_list_provider_endpoints", @@ -80,10 +75,7 @@ } }, "post": { - "tags": [ - "CodeGate API", - "Providers" - ], + "tags": ["CodeGate API", "Providers"], "summary": "Add Provider Endpoint", "description": "Add a provider endpoint.", "operationId": "v1_add_provider_endpoint", @@ -123,10 +115,7 @@ }, "/api/v1/provider-endpoints/models": { "get": { - "tags": [ - "CodeGate API", - "Providers" - ], + "tags": ["CodeGate API", "Providers"], "summary": "List All Models For All Providers", "description": "List all models for all providers.", "operationId": "v1_list_all_models_for_all_providers", @@ -150,10 +139,7 @@ }, "/api/v1/provider-endpoints/{provider_id}/models": { "get": { - "tags": [ - "CodeGate API", - "Providers" - ], + "tags": ["CodeGate API", "Providers"], "summary": "List Models By Provider", "description": "List models by provider.", "operationId": "v1_list_models_by_provider", @@ -199,10 +185,7 @@ }, "/api/v1/provider-endpoints/{provider_id}": { "get": { - "tags": [ - "CodeGate API", - "Providers" - ], + "tags": ["CodeGate API", "Providers"], "summary": "Get Provider Endpoint", "description": "Get a provider endpoint by ID.", "operationId": "v1_get_provider_endpoint", @@ -242,10 +225,7 @@ } }, "put": { - "tags": [ - "CodeGate API", - "Providers" - ], + "tags": ["CodeGate API", "Providers"], "summary": "Update Provider Endpoint", "description": "Update a provider endpoint by ID.", "operationId": "v1_update_provider_endpoint", @@ -295,10 +275,7 @@ } }, "delete": { - "tags": [ - "CodeGate API", - "Providers" - ], + "tags": ["CodeGate API", "Providers"], "summary": "Delete Provider Endpoint", "description": "Delete a provider endpoint by id.", "operationId": "v1_delete_provider_endpoint", @@ -338,10 +315,7 @@ }, "/api/v1/provider-endpoints/{provider_id}/auth-material": { "put": { - "tags": [ - "CodeGate API", - "Providers" - ], + "tags": ["CodeGate API", "Providers"], "summary": "Configure Auth Material", "description": "Configure auth material for a provider.", "operationId": "v1_configure_auth_material", @@ -386,10 +360,7 @@ }, "/api/v1/workspaces": { "get": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "List Workspaces", "description": "List all workspaces.", "operationId": "v1_list_workspaces", @@ -407,10 +378,7 @@ } }, "post": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "Create Workspace", "description": "Create a new workspace.", "operationId": "v1_create_workspace", @@ -418,7 +386,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateOrRenameWorkspaceRequest" + "$ref": "#/components/schemas/FullWorkspace-Input" } } }, @@ -430,7 +398,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Workspace" + "$ref": "#/components/schemas/FullWorkspace-Output" } } } @@ -450,10 +418,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", @@ -471,10 +436,7 @@ } }, "post": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "Activate Workspace", "description": "Activate a workspace by name.", "operationId": "v1_activate_workspace", @@ -522,11 +484,57 @@ } }, "/api/v1/workspaces/{workspace_name}": { - "delete": { - "tags": [ - "CodeGate API", - "Workspaces" + "put": { + "tags": ["CodeGate API", "Workspaces"], + "summary": "Update Workspace", + "description": "Update a workspace.", + "operationId": "v1_update_workspace", + "parameters": [ + { + "name": "workspace_name", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Workspace Name" + } + } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FullWorkspace-Input" + } + } + } + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FullWorkspace-Output" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "delete": { + "tags": ["CodeGate API", "Workspaces"], "summary": "Delete Workspace", "description": "Delete a workspace by name.", "operationId": "v1_delete_workspace", @@ -565,10 +573,7 @@ }, "/api/v1/workspaces/archive": { "get": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "List Archived Workspaces", "description": "List all archived workspaces.", "operationId": "v1_list_archived_workspaces", @@ -588,10 +593,7 @@ }, "/api/v1/workspaces/archive/{workspace_name}/recover": { "post": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "Recover Workspace", "description": "Recover an archived workspace by name.", "operationId": "v1_recover_workspace", @@ -625,10 +627,7 @@ }, "/api/v1/workspaces/archive/{workspace_name}": { "delete": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "Hard Delete Workspace", "description": "Hard delete an archived workspace by name.", "operationId": "v1_hard_delete_workspace", @@ -667,10 +666,7 @@ }, "/api/v1/workspaces/{workspace_name}/alerts": { "get": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "Get Workspace Alerts", "description": "Get alerts for a workspace.", "operationId": "v1_get_workspace_alerts", @@ -722,10 +718,7 @@ }, "/api/v1/workspaces/{workspace_name}/messages": { "get": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "Get Workspace Messages", "description": "Get messages for a workspace.", "operationId": "v1_get_workspace_messages", @@ -770,10 +763,7 @@ }, "/api/v1/workspaces/{workspace_name}/custom-instructions": { "get": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "Get Workspace Custom Instructions", "description": "Get the custom instructions of a workspace.", "operationId": "v1_get_workspace_custom_instructions", @@ -812,10 +802,7 @@ } }, "put": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "Set Workspace Custom Instructions", "operationId": "v1_set_workspace_custom_instructions", "parameters": [ @@ -856,10 +843,7 @@ } }, "delete": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "Delete Workspace Custom Instructions", "operationId": "v1_delete_workspace_custom_instructions", "parameters": [ @@ -892,11 +876,7 @@ }, "/api/v1/workspaces/{workspace_name}/muxes": { "get": { - "tags": [ - "CodeGate API", - "Workspaces", - "Muxes" - ], + "tags": ["CodeGate API", "Workspaces", "Muxes"], "summary": "Get Workspace Muxes", "description": "Get the mux rules of a workspace.\n\nThe list is ordered in order of priority. That is, the first rule in the list\nhas the highest priority.", "operationId": "v1_get_workspace_muxes", @@ -939,11 +919,7 @@ } }, "put": { - "tags": [ - "CodeGate API", - "Workspaces", - "Muxes" - ], + "tags": ["CodeGate API", "Workspaces", "Muxes"], "summary": "Set Workspace Muxes", "description": "Set the mux rules of a workspace.", "operationId": "v1_set_workspace_muxes", @@ -991,10 +967,7 @@ }, "/api/v1/workspaces/{provider_id}": { "get": { - "tags": [ - "CodeGate API", - "Workspaces" - ], + "tags": ["CodeGate API", "Workspaces"], "summary": "List Workspaces By Provider", "description": "List workspaces by provider ID.", "operationId": "v1_list_workspaces_by_provider", @@ -1040,10 +1013,7 @@ }, "/api/v1/alerts_notification": { "get": { - "tags": [ - "CodeGate API", - "Dashboard" - ], + "tags": ["CodeGate API", "Dashboard"], "summary": "Stream Sse", "description": "Send alerts event", "operationId": "v1_stream_sse", @@ -1061,10 +1031,7 @@ }, "/api/v1/version": { "get": { - "tags": [ - "CodeGate API", - "Dashboard" - ], + "tags": ["CodeGate API", "Dashboard"], "summary": "Version Check", "operationId": "v1_version_check", "responses": { @@ -1081,11 +1048,7 @@ }, "/api/v1/workspaces/{workspace_name}/token-usage": { "get": { - "tags": [ - "CodeGate API", - "Workspaces", - "Token Usage" - ], + "tags": ["CodeGate API", "Workspaces", "Token Usage"], "summary": "Get Workspace Token Usage", "description": "Get the token usage of a workspace.", "operationId": "v1_get_workspace_token_usage", @@ -1135,9 +1098,7 @@ } }, "type": "object", - "required": [ - "name" - ], + "required": ["name"], "title": "ActivateWorkspaceRequest" }, "ActiveWorkspace": { @@ -1155,11 +1116,7 @@ } }, "type": "object", - "required": [ - "name", - "is_active", - "last_updated" - ], + "required": ["name", "is_active", "last_updated"], "title": "ActiveWorkspace" }, "AddProviderEndpointRequest": { @@ -1210,10 +1167,7 @@ } }, "type": "object", - "required": [ - "name", - "provider_type" - ], + "required": ["name", "provider_type"], "title": "AddProviderEndpointRequest", "description": "Represents a request to add a provider endpoint." }, @@ -1346,10 +1300,7 @@ }, "AlertSeverity": { "type": "string", - "enum": [ - "info", - "critical" - ], + "enum": ["info", "critical"], "title": "AlertSeverity" }, "ChatMessage": { @@ -1369,11 +1320,7 @@ } }, "type": "object", - "required": [ - "message", - "timestamp", - "message_id" - ], + "required": ["message", "timestamp", "message_id"], "title": "ChatMessage", "description": "Represents a chat message." }, @@ -1426,11 +1373,7 @@ } }, "type": "object", - "required": [ - "code", - "language", - "filepath" - ], + "required": ["code", "language", "filepath"], "title": "CodeSnippet", "description": "Represents a code snippet with its programming language.\n\nArgs:\n language: The programming language identifier (e.g., 'python', 'javascript')\n code: The actual code content" }, @@ -1452,9 +1395,7 @@ } }, "type": "object", - "required": [ - "auth_type" - ], + "required": ["auth_type"], "title": "ConfigureAuthMaterial", "description": "Represents a request to configure auth material for a provider." }, @@ -1521,7 +1462,18 @@ "title": "Conversation", "description": "Represents a conversation." }, - "CreateOrRenameWorkspaceRequest": { + "CustomInstructions": { + "properties": { + "prompt": { + "type": "string", + "title": "Prompt" + } + }, + "type": "object", + "required": ["prompt"], + "title": "CustomInstructions" + }, + "FullWorkspace-Input": { "properties": { "name": { "type": "string", @@ -1530,43 +1482,38 @@ "config": { "anyOf": [ { - "$ref": "#/components/schemas/WorkspaceConfig" + "$ref": "#/components/schemas/WorkspaceConfig-Input" }, { "type": "null" } ] + } + }, + "type": "object", + "required": ["name"], + "title": "FullWorkspace" + }, + "FullWorkspace-Output": { + "properties": { + "name": { + "type": "string", + "title": "Name" }, - "rename_to": { + "config": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/WorkspaceConfig-Output" }, { "type": "null" } - ], - "title": "Rename To" - } - }, - "type": "object", - "required": [ - "name" - ], - "title": "CreateOrRenameWorkspaceRequest" - }, - "CustomInstructions": { - "properties": { - "prompt": { - "type": "string", - "title": "Prompt" + ] } }, "type": "object", - "required": [ - "prompt" - ], - "title": "CustomInstructions" + "required": ["name"], + "title": "FullWorkspace" }, "HTTPValidationError": { "properties": { @@ -1592,9 +1539,7 @@ } }, "type": "object", - "required": [ - "workspaces" - ], + "required": ["workspaces"], "title": "ListActiveWorkspacesResponse" }, "ListWorkspacesResponse": { @@ -1608,9 +1553,7 @@ } }, "type": "object", - "required": [ - "workspaces" - ], + "required": ["workspaces"], "title": "ListWorkspacesResponse" }, "ModelByProvider": { @@ -1629,11 +1572,7 @@ } }, "type": "object", - "required": [ - "name", - "provider_id", - "provider_name" - ], + "required": ["name", "provider_id", "provider_name"], "title": "ModelByProvider", "description": "Represents a model supported by a provider.\n\nNote that these are auto-discovered by the provider." }, @@ -1685,21 +1624,13 @@ } }, "type": "object", - "required": [ - "provider_id", - "model", - "matcher_type" - ], + "required": ["provider_id", "model", "matcher_type"], "title": "MuxRule", "description": "Represents a mux rule for a provider." }, "ProviderAuthType": { "type": "string", - "enum": [ - "none", - "passthrough", - "api_key" - ], + "enum": ["none", "passthrough", "api_key"], "title": "ProviderAuthType", "description": "Represents the different types of auth we support for providers." }, @@ -1740,10 +1671,7 @@ } }, "type": "object", - "required": [ - "name", - "provider_type" - ], + "required": ["name", "provider_type"], "title": "ProviderEndpoint", "description": "Represents a provider's endpoint configuration. This\nallows us to persist the configuration for each provider,\nso we can use this for muxing messages." }, @@ -1778,19 +1706,13 @@ } }, "type": "object", - "required": [ - "question", - "answer" - ], + "required": ["question", "answer"], "title": "QuestionAnswer", "description": "Represents a question and answer pair." }, "QuestionType": { "type": "string", - "enum": [ - "chat", - "fim" - ], + "enum": ["chat", "fim"], "title": "QuestionType" }, "TokenUsage": { @@ -1834,10 +1756,7 @@ } }, "type": "object", - "required": [ - "tokens_by_model", - "token_usage" - ], + "required": ["tokens_by_model", "token_usage"], "title": "TokenUsageAggregate", "description": "Represents the tokens used. Includes the information of the tokens used by model.\n`used_tokens` are the total tokens used in the `tokens_by_model` list." }, @@ -1855,11 +1774,7 @@ } }, "type": "object", - "required": [ - "provider_type", - "model", - "token_usage" - ], + "required": ["provider_type", "model", "token_usage"], "title": "TokenUsageByModel", "description": "Represents the tokens used by a model." }, @@ -1889,11 +1804,7 @@ } }, "type": "object", - "required": [ - "loc", - "msg", - "type" - ], + "required": ["loc", "msg", "type"], "title": "ValidationError" }, "Workspace": { @@ -1908,17 +1819,14 @@ } }, "type": "object", - "required": [ - "name", - "is_active" - ], + "required": ["name", "is_active"], "title": "Workspace" }, - "WorkspaceConfig": { + "WorkspaceConfig-Input": { "properties": { - "system_prompt": { + "custom_instructions": { "type": "string", - "title": "System Prompt" + "title": "Custom Instructions" }, "muxing_rules": { "items": { @@ -1929,10 +1837,25 @@ } }, "type": "object", - "required": [ - "system_prompt", - "muxing_rules" - ], + "required": ["custom_instructions", "muxing_rules"], + "title": "WorkspaceConfig" + }, + "WorkspaceConfig-Output": { + "properties": { + "custom_instructions": { + "type": "string", + "title": "Custom Instructions" + }, + "muxing_rules": { + "items": { + "$ref": "#/components/schemas/MuxRule" + }, + "type": "array", + "title": "Muxing Rules" + } + }, + "type": "object", + "required": ["custom_instructions", "muxing_rules"], "title": "WorkspaceConfig" }, "WorkspaceWithModel": { @@ -1952,11 +1875,7 @@ } }, "type": "object", - "required": [ - "id", - "name", - "provider_model_name" - ], + "required": ["id", "name", "provider_model_name"], "title": "WorkspaceWithModel", "description": "Returns a workspace ID with model name" } diff --git a/src/features/workspace/components/__tests__/workspace-name.test.tsx b/src/features/workspace/components/__tests__/workspace-name.test.tsx index 0b4a44af..a5749d72 100644 --- a/src/features/workspace/components/__tests__/workspace-name.test.tsx +++ b/src/features/workspace/components/__tests__/workspace-name.test.tsx @@ -20,7 +20,7 @@ test('can rename workspace', async () => { await userEvent.click(getByRole('button', { name: /save/i })) await waitFor(() => { - expect(getByText(/renamed workspace to "baz-qux"/i)).toBeVisible() + expect(getByText(/updated workspace/i)).toBeVisible() }) }) diff --git a/src/features/workspace/components/workspace-name.tsx b/src/features/workspace/components/workspace-name.tsx index 805e2171..308e6eac 100644 --- a/src/features/workspace/components/workspace-name.tsx +++ b/src/features/workspace/components/workspace-name.tsx @@ -6,17 +6,17 @@ import { Input, Label, TextField, -} from "@stacklok/ui-kit"; -import { useMutationCreateWorkspace } from "../hooks/use-mutation-create-workspace"; -import { useNavigate } from "react-router-dom"; -import { twMerge } from "tailwind-merge"; -import { useFormState } from "@/hooks/useFormState"; -import { FormButtons } from "@/components/FormButtons"; -import { FormEvent, useEffect } from "react"; +} from '@stacklok/ui-kit' +import { useNavigate } from 'react-router-dom' +import { twMerge } from 'tailwind-merge' +import { useFormState } from '@/hooks/useFormState' +import { FormButtons } from '@/components/FormButtons' +import { FormEvent, useEffect } from 'react' +import { useMutationUpdateWorkspace } from '../hooks/use-mutation-update-workspace' export function WorkspaceName({ className, - workspaceName, + workspaceName: oldWorkspaceName, isArchived, }: { className?: string @@ -24,32 +24,37 @@ export function WorkspaceName({ isArchived: boolean | undefined }) { const navigate = useNavigate() - const { mutateAsync, isPending, error } = useMutationCreateWorkspace() + const { mutateAsync, isPending, error } = useMutationUpdateWorkspace() const errorMsg = error?.detail ? `${error?.detail}` : '' const formState = useFormState({ - workspaceName, - }); - const { values, updateFormValues, setInitialValues } = formState; - const isDefault = workspaceName === "default"; - const isUneditable = isArchived || isPending || isDefault; + workspaceName: oldWorkspaceName, + }) + const { values, updateFormValues, setInitialValues } = formState + const isDefault = oldWorkspaceName === 'default' + const isUneditable = isArchived || isPending || isDefault useEffect(() => { - setInitialValues({ workspaceName }); - }, [setInitialValues, workspaceName]); + setInitialValues({ workspaceName: oldWorkspaceName }) + }, [setInitialValues, oldWorkspaceName]) const handleSubmit = (event: FormEvent) => { event.preventDefault() mutateAsync( - { body: { name: workspaceName, rename_to: values.workspaceName } }, { - onSuccess: () => { - formState.setInitialValues({ workspaceName: values.workspaceName }); - navigate(`/workspace/${values.workspaceName}`); + path: { + workspace_name: oldWorkspaceName, }, + body: { name: values.workspaceName, config: null }, }, - ); - }; + { + onSuccess: () => { + formState.setInitialValues({ workspaceName: values.workspaceName }) + navigate(`/workspace/${values.workspaceName}`) + }, + } + ) + } return (
- variables.body.rename_to - ? `Renamed workspace to "${variables.body.rename_to}"` - : `Created "${variables.body.name}" workspace`, + successMsg: (variables) => `Created "${variables.body.name}" workspace`, }) } diff --git a/src/features/workspace/hooks/use-mutation-update-workspace.ts b/src/features/workspace/hooks/use-mutation-update-workspace.ts new file mode 100644 index 00000000..5ae08b88 --- /dev/null +++ b/src/features/workspace/hooks/use-mutation-update-workspace.ts @@ -0,0 +1,29 @@ +import { + v1GetWorkspaceCustomInstructionsQueryKey, + v1GetWorkspaceMuxesQueryKey, + v1UpdateWorkspaceMutation, +} from '@/api/generated/@tanstack/react-query.gen' +import { useInvalidateWorkspaceQueries } from './use-invalidate-workspace-queries' +import { useToastMutation } from '@/hooks/use-toast-mutation' +import { useQueryClient } from '@tanstack/react-query' +import { removeQueriesByIds } from '@/lib/react-query-utils' + +export function useMutationUpdateWorkspace() { + const queryClient = useQueryClient() + const invalidate = useInvalidateWorkspaceQueries() + + return useToastMutation({ + ...v1UpdateWorkspaceMutation(), + onSuccess: async () => { + removeQueriesByIds({ + queryClient, + queryKeyFns: [ + v1GetWorkspaceMuxesQueryKey, + v1GetWorkspaceCustomInstructionsQueryKey, + ], + }) + await invalidate() + }, + successMsg: 'Updated workspace', + }) +} diff --git a/src/features/workspace/lib/utils.ts b/src/features/workspace/lib/utils.ts index 06cd6a5a..5bb2050d 100644 --- a/src/features/workspace/lib/utils.ts +++ b/src/features/workspace/lib/utils.ts @@ -32,7 +32,7 @@ const DEFAULT_RULE = { } const CUSTOM_RULE = { - placeholder: 'e.g. file type, file name', + placeholder: 'e.g. file glob patterns like *.py', selectedKey: '', items: getRequestType(), } diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 00000000..152a2b13 --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1,11 @@ +export interface AppConfig { + DASHBOARD_API_BASE_URL?: string +} + +declare global { + interface Window { + APP_CONFIG: AppConfig + } +} + +export {} diff --git a/src/hooks/useSse.ts b/src/hooks/useSse.ts index 586de07f..50d3e438 100644 --- a/src/hooks/useSse.ts +++ b/src/hooks/useSse.ts @@ -6,8 +6,9 @@ import { v1GetWorkspaceMessagesQueryKey, } from '@/api/generated/@tanstack/react-query.gen' import { invalidateQueries } from '@/lib/react-query-utils' +import { getAppConfig } from '@/lib/utils' -const BASE_URL = import.meta.env.VITE_BASE_API_URL +const baseApiUrl = getAppConfig().DASHBOARD_API_BASE_URL export function useSse() { const location = useLocation() @@ -15,7 +16,7 @@ export function useSse() { useEffect(() => { const eventSource = new EventSource( - `${BASE_URL}/api/v1/alerts_notification` + `${baseApiUrl}/api/v1/alerts_notification` ) eventSource.onmessage = function (event) { diff --git a/src/lib/__tests__/utils.test.ts b/src/lib/__tests__/utils.test.ts new file mode 100644 index 00000000..f1dbde59 --- /dev/null +++ b/src/lib/__tests__/utils.test.ts @@ -0,0 +1,42 @@ +import { getAppConfig } from '../utils' +import { AppConfig } from '@/global' + +describe('getAppConfig', () => { + const mockViteBaseApiUrl = 'https://api.mock.com' + + it('default base api url if ${DASHBOARD_API_BASE_URL}" not configured', () => { + const mockAppConfig: AppConfig = { + DASHBOARD_API_BASE_URL: '${DASHBOARD_API_BASE_URL}', + } + + Object.defineProperty(window, 'APP_CONFIG', { + value: mockAppConfig, + writable: true, + }) + + const expectedConfig: AppConfig = { + ...mockAppConfig, + DASHBOARD_API_BASE_URL: 'https://mock.codegate.ai', + } + + expect(getAppConfig()).toEqual(expectedConfig) + }) + + it('replace base api url if ${DASHBOARD_API_BASE_URL}" is configured', () => { + const mockAppConfig: AppConfig = { + DASHBOARD_API_BASE_URL: mockViteBaseApiUrl, + } + + Object.defineProperty(window, 'APP_CONFIG', { + value: mockAppConfig, + writable: true, + }) + + const expectedConfig: AppConfig = { + ...mockAppConfig, + DASHBOARD_API_BASE_URL: mockViteBaseApiUrl, + } + + expect(getAppConfig()).toEqual(expectedConfig) + }) +}) diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 7e2854aa..9cea1e5e 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,4 +1,5 @@ import { format } from 'date-fns' +import { AppConfig } from '@/global' const FILEPATH_REGEX = /(?:---FILEPATH|Path:|\/\/\s*filepath:)\s*([^\s]+)/g const COMPARE_CODE_REGEX = /Compare this snippet[^:]*:/g @@ -70,3 +71,19 @@ export function sanitizeQuestionPrompt({ return question } } + +export function getAppConfig(): AppConfig { + const baseApiUrl = window.APP_CONFIG?.DASHBOARD_API_BASE_URL + + if (!baseApiUrl || baseApiUrl === '${DASHBOARD_API_BASE_URL}') { + return { + ...window.APP_CONFIG, + DASHBOARD_API_BASE_URL: import.meta.env.VITE_BASE_API_URL, + } + } + + return { + ...window.APP_CONFIG, + DASHBOARD_API_BASE_URL: baseApiUrl, + } +} diff --git a/src/main.tsx b/src/main.tsx index a530b599..c2ed7464 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -4,7 +4,6 @@ import './index.css' import './code.css' import '@stacklok/ui-kit/style' import App from './App.tsx' - import ErrorBoundary from './components/ErrorBoundary.tsx' import { Error } from './components/Error.tsx' import { DarkModeProvider, Toaster } from '@stacklok/ui-kit' @@ -14,10 +13,11 @@ import { BrowserRouter } from 'react-router-dom' import { UiKitClientSideRoutingProvider } from './lib/ui-kit-client-side-routing.tsx' import { ConfirmProvider } from './context/confirm-context.tsx' import { ReactQueryDevtools } from '@tanstack/react-query-devtools' +import { getAppConfig } from './lib/utils.ts' // Initialize the API client client.setConfig({ - baseUrl: import.meta.env.VITE_BASE_API_URL, + baseUrl: getAppConfig().DASHBOARD_API_BASE_URL, }) createRoot(document.getElementById('root')!).render( @@ -27,7 +27,6 @@ createRoot(document.getElementById('root')!).render( }> - diff --git a/src/mocks/msw/handlers.ts b/src/mocks/msw/handlers.ts index fbf0e0f8..5909edfc 100644 --- a/src/mocks/msw/handlers.ts +++ b/src/mocks/msw/handlers.ts @@ -58,6 +58,18 @@ export const handlers = [ mswEndpoint('/api/v1/workspaces/active'), () => new HttpResponse(null, { status: 204 }) ), + http.put(mswEndpoint('/api/v1/workspaces/:workspace_name'), () => + HttpResponse.json( + { + name: 'foo', + config: { + custom_instructions: '', + muxing_rules: [], + }, + }, + { status: 201 } + ) + ), http.post( mswEndpoint('/api/v1/workspaces/archive/:workspace_name/recover'), () => new HttpResponse(null, { status: 204 }) @@ -105,8 +117,8 @@ export const handlers = [ mswEndpoint('/api/v1/workspaces/:workspace_name/custom-instructions'), () => new HttpResponse(null, { status: 204 }) ), - http.get(mswEndpoint("/api/v1/workspaces/:workspace_name/muxes"), () => - HttpResponse.json([]), + http.get(mswEndpoint('/api/v1/workspaces/:workspace_name/muxes'), () => + HttpResponse.json([]) ), http.put( mswEndpoint('/api/v1/workspaces/:workspace_name/muxes'), diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index e8dd3c9e..c997c680 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -1,5 +1,5 @@ /// interface ImportBaseApiEnv { - readonly BASE_API_URL: string + readonly DASHBOARD_API_BASE_URL: string readonly VITE_BASE_API_URL: string } diff --git a/tsconfig.app.json b/tsconfig.app.json index 0c42ab7d..f6c76f7c 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -29,7 +29,8 @@ "openapi-ts.config.ts", "tailwind.config.ts", "vitest.config.ts", - "vitest.setup.ts" + "vitest.setup.ts", + "./global.d.ts" ], "exclude": ["node_modules"] } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy