diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 58a2c0824c..37534e2ab0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -28,10 +28,10 @@ repos: hooks: - id: local-biome-check name: biome check - entry: npx biome check --write --files-ignore-unknown=true --no-errors-on-unmatched + entry: bash -c 'cd frontend && npm run lint' language: system types: [text] - files: "\\.(jsx?|tsx?|c(js|ts)|m(js|ts)|d\\.(ts|cts|mts)|jsonc?|css|svelte|vue|astro|graphql|gql)$" + files: ^frontend/ ci: autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks diff --git a/frontend/biome.json b/frontend/biome.json index a06315dc2a..f90bd7e90f 100644 --- a/frontend/biome.json +++ b/frontend/biome.json @@ -1,14 +1,16 @@ { - "$schema": "https://biomejs.dev/schemas/1.6.1/schema.json", - "organizeImports": { - "enabled": true - }, + "$schema": "https://biomejs.dev/schemas/2.2.3/schema.json", + "assist": { "actions": { "source": { "organizeImports": "on" } } }, "files": { - "ignore": [ - "node_modules", - "src/routeTree.gen.ts", - "playwright.config.ts", - "playwright-report" + "includes": [ + "**", + "!**/dist/**/*", + "!**/node_modules/**/*", + "!**/src/routeTree.gen.ts", + "!**/src/client/**/*", + "!**/src/components/ui/**/*", + "!**/playwright-report", + "!**/playwright.config.ts" ] }, "linter": { @@ -20,7 +22,10 @@ "noArrayIndexKey": "off" }, "style": { - "noNonNullAssertion": "off" + "noNonNullAssertion": "off", + "noParameterAssign": "error", + "useSelfClosingElements": "error", + "noUselessElse": "error" } } }, diff --git a/frontend/openapi-ts.config.ts b/frontend/openapi-ts.config.ts index c473bcbe32..b5a69e20eb 100644 --- a/frontend/openapi-ts.config.ts +++ b/frontend/openapi-ts.config.ts @@ -13,9 +13,9 @@ export default defineConfig({ operationId: true, classNameBuilder: "{{name}}Service", methodNameBuilder: (operation) => { - // @ts-ignore + // @ts-expect-error let name: string = operation.name - // @ts-ignore + // @ts-expect-error const service: string = operation.service if (service && name.toLowerCase().startsWith(service.toLowerCase())) { @@ -30,4 +30,4 @@ export default defineConfig({ type: "json", }, ], -}) \ No newline at end of file +}) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 34bf9ba07c..e0126ac480 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -23,7 +23,7 @@ "react-icons": "^5.5.0" }, "devDependencies": { - "@biomejs/biome": "1.9.4", + "@biomejs/biome": "^2.2.3", "@hey-api/openapi-ts": "0.73.0", "@playwright/test": "^1.55.0", "@tanstack/router-devtools": "^1.131.36", @@ -552,11 +552,10 @@ } }, "node_modules/@biomejs/biome": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.9.4.tgz", - "integrity": "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.2.3.tgz", + "integrity": "sha512-9w0uMTvPrIdvUrxazZ42Ib7t8Y2yoGLKLdNne93RLICmaHw7mcLv4PPb5LvZLJF3141gQHiCColOh/v6VWlWmg==", "dev": true, - "hasInstallScript": true, "license": "MIT OR Apache-2.0", "bin": { "biome": "bin/biome" @@ -569,20 +568,20 @@ "url": "https://opencollective.com/biome" }, "optionalDependencies": { - "@biomejs/cli-darwin-arm64": "1.9.4", - "@biomejs/cli-darwin-x64": "1.9.4", - "@biomejs/cli-linux-arm64": "1.9.4", - "@biomejs/cli-linux-arm64-musl": "1.9.4", - "@biomejs/cli-linux-x64": "1.9.4", - "@biomejs/cli-linux-x64-musl": "1.9.4", - "@biomejs/cli-win32-arm64": "1.9.4", - "@biomejs/cli-win32-x64": "1.9.4" + "@biomejs/cli-darwin-arm64": "2.2.3", + "@biomejs/cli-darwin-x64": "2.2.3", + "@biomejs/cli-linux-arm64": "2.2.3", + "@biomejs/cli-linux-arm64-musl": "2.2.3", + "@biomejs/cli-linux-x64": "2.2.3", + "@biomejs/cli-linux-x64-musl": "2.2.3", + "@biomejs/cli-win32-arm64": "2.2.3", + "@biomejs/cli-win32-x64": "2.2.3" } }, "node_modules/@biomejs/cli-darwin-arm64": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz", - "integrity": "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.3.tgz", + "integrity": "sha512-OrqQVBpadB5eqzinXN4+Q6honBz+tTlKVCsbEuEpljK8ASSItzIRZUA02mTikl3H/1nO2BMPFiJ0nkEZNy3B1w==", "cpu": [ "arm64" ], @@ -597,9 +596,9 @@ } }, "node_modules/@biomejs/cli-darwin-x64": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz", - "integrity": "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.3.tgz", + "integrity": "sha512-OCdBpb1TmyfsTgBAM1kPMXyYKTohQ48WpiN9tkt9xvU6gKVKHY4oVwteBebiOqyfyzCNaSiuKIPjmHjUZ2ZNMg==", "cpu": [ "x64" ], @@ -614,9 +613,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.4.tgz", - "integrity": "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.3.tgz", + "integrity": "sha512-g/Uta2DqYpECxG+vUmTAmUKlVhnGEcY7DXWgKP8ruLRa8Si1QHsWknPY3B/wCo0KgYiFIOAZ9hjsHfNb9L85+g==", "cpu": [ "arm64" ], @@ -631,9 +630,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64-musl": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.4.tgz", - "integrity": "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.3.tgz", + "integrity": "sha512-q3w9jJ6JFPZPeqyvwwPeaiS/6NEszZ+pXKF+IczNo8Xj6fsii45a4gEEicKyKIytalV+s829ACZujQlXAiVLBQ==", "cpu": [ "arm64" ], @@ -648,9 +647,9 @@ } }, "node_modules/@biomejs/cli-linux-x64": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz", - "integrity": "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.3.tgz", + "integrity": "sha512-LEtyYL1fJsvw35CxrbQ0gZoxOG3oZsAjzfRdvRBRHxOpQ91Q5doRVjvWW/wepgSdgk5hlaNzfeqpyGmfSD0Eyw==", "cpu": [ "x64" ], @@ -665,9 +664,9 @@ } }, "node_modules/@biomejs/cli-linux-x64-musl": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz", - "integrity": "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.3.tgz", + "integrity": "sha512-y76Dn4vkP1sMRGPFlNc+OTETBhGPJ90jY3il6jAfur8XWrYBQV3swZ1Jo0R2g+JpOeeoA0cOwM7mJG6svDz79w==", "cpu": [ "x64" ], @@ -682,9 +681,9 @@ } }, "node_modules/@biomejs/cli-win32-arm64": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz", - "integrity": "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.3.tgz", + "integrity": "sha512-Ms9zFYzjcJK7LV+AOMYnjN3pV3xL8Prxf9aWdDVL74onLn5kcvZ1ZMQswE5XHtnd/r/0bnUd928Rpbs14BzVmA==", "cpu": [ "arm64" ], @@ -699,9 +698,9 @@ } }, "node_modules/@biomejs/cli-win32-x64": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz", - "integrity": "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.3.tgz", + "integrity": "sha512-gvCpewE7mBwBIpqk1YrUqNR4mCiyJm6UI3YWQQXkedSSEwzRdodRpaKhbdbHw1/hmTWOVXQ+Eih5Qctf4TCVOQ==", "cpu": [ "x64" ], @@ -5975,74 +5974,74 @@ } }, "@biomejs/biome": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.9.4.tgz", - "integrity": "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.2.3.tgz", + "integrity": "sha512-9w0uMTvPrIdvUrxazZ42Ib7t8Y2yoGLKLdNne93RLICmaHw7mcLv4PPb5LvZLJF3141gQHiCColOh/v6VWlWmg==", "dev": true, "requires": { - "@biomejs/cli-darwin-arm64": "1.9.4", - "@biomejs/cli-darwin-x64": "1.9.4", - "@biomejs/cli-linux-arm64": "1.9.4", - "@biomejs/cli-linux-arm64-musl": "1.9.4", - "@biomejs/cli-linux-x64": "1.9.4", - "@biomejs/cli-linux-x64-musl": "1.9.4", - "@biomejs/cli-win32-arm64": "1.9.4", - "@biomejs/cli-win32-x64": "1.9.4" + "@biomejs/cli-darwin-arm64": "2.2.3", + "@biomejs/cli-darwin-x64": "2.2.3", + "@biomejs/cli-linux-arm64": "2.2.3", + "@biomejs/cli-linux-arm64-musl": "2.2.3", + "@biomejs/cli-linux-x64": "2.2.3", + "@biomejs/cli-linux-x64-musl": "2.2.3", + "@biomejs/cli-win32-arm64": "2.2.3", + "@biomejs/cli-win32-x64": "2.2.3" } }, "@biomejs/cli-darwin-arm64": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz", - "integrity": "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.3.tgz", + "integrity": "sha512-OrqQVBpadB5eqzinXN4+Q6honBz+tTlKVCsbEuEpljK8ASSItzIRZUA02mTikl3H/1nO2BMPFiJ0nkEZNy3B1w==", "dev": true, "optional": true }, "@biomejs/cli-darwin-x64": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz", - "integrity": "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.3.tgz", + "integrity": "sha512-OCdBpb1TmyfsTgBAM1kPMXyYKTohQ48WpiN9tkt9xvU6gKVKHY4oVwteBebiOqyfyzCNaSiuKIPjmHjUZ2ZNMg==", "dev": true, "optional": true }, "@biomejs/cli-linux-arm64": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.4.tgz", - "integrity": "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.3.tgz", + "integrity": "sha512-g/Uta2DqYpECxG+vUmTAmUKlVhnGEcY7DXWgKP8ruLRa8Si1QHsWknPY3B/wCo0KgYiFIOAZ9hjsHfNb9L85+g==", "dev": true, "optional": true }, "@biomejs/cli-linux-arm64-musl": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.4.tgz", - "integrity": "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.3.tgz", + "integrity": "sha512-q3w9jJ6JFPZPeqyvwwPeaiS/6NEszZ+pXKF+IczNo8Xj6fsii45a4gEEicKyKIytalV+s829ACZujQlXAiVLBQ==", "dev": true, "optional": true }, "@biomejs/cli-linux-x64": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz", - "integrity": "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.3.tgz", + "integrity": "sha512-LEtyYL1fJsvw35CxrbQ0gZoxOG3oZsAjzfRdvRBRHxOpQ91Q5doRVjvWW/wepgSdgk5hlaNzfeqpyGmfSD0Eyw==", "dev": true, "optional": true }, "@biomejs/cli-linux-x64-musl": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz", - "integrity": "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.3.tgz", + "integrity": "sha512-y76Dn4vkP1sMRGPFlNc+OTETBhGPJ90jY3il6jAfur8XWrYBQV3swZ1Jo0R2g+JpOeeoA0cOwM7mJG6svDz79w==", "dev": true, "optional": true }, "@biomejs/cli-win32-arm64": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz", - "integrity": "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.3.tgz", + "integrity": "sha512-Ms9zFYzjcJK7LV+AOMYnjN3pV3xL8Prxf9aWdDVL74onLn5kcvZ1ZMQswE5XHtnd/r/0bnUd928Rpbs14BzVmA==", "dev": true, "optional": true }, "@biomejs/cli-win32-x64": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz", - "integrity": "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.3.tgz", + "integrity": "sha512-gvCpewE7mBwBIpqk1YrUqNR4mCiyJm6UI3YWQQXkedSSEwzRdodRpaKhbdbHw1/hmTWOVXQ+Eih5Qctf4TCVOQ==", "dev": true, "optional": true }, diff --git a/frontend/package.json b/frontend/package.json index 27d3e98bb8..258e5d4448 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,7 +6,7 @@ "scripts": { "dev": "vite", "build": "tsc -p tsconfig.build.json && vite build", - "lint": "biome check --apply-unsafe --no-errors-on-unmatched --files-ignore-unknown=true ./", + "lint": "biome check --write --unsafe --no-errors-on-unmatched --files-ignore-unknown=true ./", "preview": "vite preview", "generate-client": "openapi-ts" }, @@ -26,7 +26,7 @@ "react-icons": "^5.5.0" }, "devDependencies": { - "@biomejs/biome": "1.9.4", + "@biomejs/biome": "^2.2.3", "@hey-api/openapi-ts": "0.73.0", "@playwright/test": "^1.55.0", "@tanstack/router-devtools": "^1.131.36", diff --git a/frontend/src/client/core/ApiError.ts b/frontend/src/client/core/ApiError.ts index 5499aa8f05..36675d288a 100644 --- a/frontend/src/client/core/ApiError.ts +++ b/frontend/src/client/core/ApiError.ts @@ -1,25 +1,21 @@ -import type { ApiRequestOptions } from "./ApiRequestOptions" -import type { ApiResult } from "./ApiResult" +import type { ApiRequestOptions } from './ApiRequestOptions'; +import type { ApiResult } from './ApiResult'; export class ApiError extends Error { - public readonly url: string - public readonly status: number - public readonly statusText: string - public readonly body: unknown - public readonly request: ApiRequestOptions + public readonly url: string; + public readonly status: number; + public readonly statusText: string; + public readonly body: unknown; + public readonly request: ApiRequestOptions; - constructor( - request: ApiRequestOptions, - response: ApiResult, - message: string, - ) { - super(message) + constructor(request: ApiRequestOptions, response: ApiResult, message: string) { + super(message); - this.name = "ApiError" - this.url = response.url - this.status = response.status - this.statusText = response.statusText - this.body = response.body - this.request = request - } -} + this.name = 'ApiError'; + this.url = response.url; + this.status = response.status; + this.statusText = response.statusText; + this.body = response.body; + this.request = request; + } +} \ No newline at end of file diff --git a/frontend/src/client/core/ApiRequestOptions.ts b/frontend/src/client/core/ApiRequestOptions.ts index d1136f428b..939a0aa4c8 100644 --- a/frontend/src/client/core/ApiRequestOptions.ts +++ b/frontend/src/client/core/ApiRequestOptions.ts @@ -1,21 +1,21 @@ export type ApiRequestOptions = { - readonly body?: any - readonly cookies?: Record - readonly errors?: Record - readonly formData?: Record | any[] | Blob | File - readonly headers?: Record - readonly mediaType?: string - readonly method: - | "DELETE" - | "GET" - | "HEAD" - | "OPTIONS" - | "PATCH" - | "POST" - | "PUT" - readonly path?: Record - readonly query?: Record - readonly responseHeader?: string - readonly responseTransformer?: (data: unknown) => Promise - readonly url: string -} + readonly body?: any; + readonly cookies?: Record; + readonly errors?: Record; + readonly formData?: Record | any[] | Blob | File; + readonly headers?: Record; + readonly mediaType?: string; + readonly method: + | 'DELETE' + | 'GET' + | 'HEAD' + | 'OPTIONS' + | 'PATCH' + | 'POST' + | 'PUT'; + readonly path?: Record; + readonly query?: Record; + readonly responseHeader?: string; + readonly responseTransformer?: (data: unknown) => Promise; + readonly url: string; +}; \ No newline at end of file diff --git a/frontend/src/client/core/ApiResult.ts b/frontend/src/client/core/ApiResult.ts index f88b8c64f1..4c58e39138 100644 --- a/frontend/src/client/core/ApiResult.ts +++ b/frontend/src/client/core/ApiResult.ts @@ -1,7 +1,7 @@ export type ApiResult = { - readonly body: TData - readonly ok: boolean - readonly status: number - readonly statusText: string - readonly url: string -} + readonly body: TData; + readonly ok: boolean; + readonly status: number; + readonly statusText: string; + readonly url: string; +}; \ No newline at end of file diff --git a/frontend/src/client/core/CancelablePromise.ts b/frontend/src/client/core/CancelablePromise.ts index f47db79eae..ccc082e8f2 100644 --- a/frontend/src/client/core/CancelablePromise.ts +++ b/frontend/src/client/core/CancelablePromise.ts @@ -1,126 +1,126 @@ export class CancelError extends Error { - constructor(message: string) { - super(message) - this.name = "CancelError" - } - - public get isCancelled(): boolean { - return true - } + constructor(message: string) { + super(message); + this.name = 'CancelError'; + } + + public get isCancelled(): boolean { + return true; + } } export interface OnCancel { - readonly isResolved: boolean - readonly isRejected: boolean - readonly isCancelled: boolean + readonly isResolved: boolean; + readonly isRejected: boolean; + readonly isCancelled: boolean; - (cancelHandler: () => void): void + (cancelHandler: () => void): void; } export class CancelablePromise implements Promise { - private _isResolved: boolean - private _isRejected: boolean - private _isCancelled: boolean - readonly cancelHandlers: (() => void)[] - readonly promise: Promise - private _resolve?: (value: T | PromiseLike) => void - private _reject?: (reason?: unknown) => void - - constructor( - executor: ( - resolve: (value: T | PromiseLike) => void, - reject: (reason?: unknown) => void, - onCancel: OnCancel, - ) => void, - ) { - this._isResolved = false - this._isRejected = false - this._isCancelled = false - this.cancelHandlers = [] - this.promise = new Promise((resolve, reject) => { - this._resolve = resolve - this._reject = reject - - const onResolve = (value: T | PromiseLike): void => { - if (this._isResolved || this._isRejected || this._isCancelled) { - return - } - this._isResolved = true - if (this._resolve) this._resolve(value) - } - - const onReject = (reason?: unknown): void => { - if (this._isResolved || this._isRejected || this._isCancelled) { - return - } - this._isRejected = true - if (this._reject) this._reject(reason) - } - - const onCancel = (cancelHandler: () => void): void => { - if (this._isResolved || this._isRejected || this._isCancelled) { - return - } - this.cancelHandlers.push(cancelHandler) - } - - Object.defineProperty(onCancel, "isResolved", { - get: (): boolean => this._isResolved, - }) - - Object.defineProperty(onCancel, "isRejected", { - get: (): boolean => this._isRejected, - }) - - Object.defineProperty(onCancel, "isCancelled", { - get: (): boolean => this._isCancelled, - }) - - return executor(onResolve, onReject, onCancel as OnCancel) - }) - } - - get [Symbol.toStringTag]() { - return "Cancellable Promise" - } - - public then( - onFulfilled?: ((value: T) => TResult1 | PromiseLike) | null, - onRejected?: ((reason: unknown) => TResult2 | PromiseLike) | null, - ): Promise { - return this.promise.then(onFulfilled, onRejected) - } - - public catch( - onRejected?: ((reason: unknown) => TResult | PromiseLike) | null, - ): Promise { - return this.promise.catch(onRejected) - } - - public finally(onFinally?: (() => void) | null): Promise { - return this.promise.finally(onFinally) - } - - public cancel(): void { - if (this._isResolved || this._isRejected || this._isCancelled) { - return - } - this._isCancelled = true - if (this.cancelHandlers.length) { - try { - for (const cancelHandler of this.cancelHandlers) { - cancelHandler() - } - } catch (error) { - console.warn("Cancellation threw an error", error) - return - } - } - this.cancelHandlers.length = 0 - if (this._reject) this._reject(new CancelError("Request aborted")) - } - - public get isCancelled(): boolean { - return this._isCancelled - } -} + private _isResolved: boolean; + private _isRejected: boolean; + private _isCancelled: boolean; + readonly cancelHandlers: (() => void)[]; + readonly promise: Promise; + private _resolve?: (value: T | PromiseLike) => void; + private _reject?: (reason?: unknown) => void; + + constructor( + executor: ( + resolve: (value: T | PromiseLike) => void, + reject: (reason?: unknown) => void, + onCancel: OnCancel + ) => void + ) { + this._isResolved = false; + this._isRejected = false; + this._isCancelled = false; + this.cancelHandlers = []; + this.promise = new Promise((resolve, reject) => { + this._resolve = resolve; + this._reject = reject; + + const onResolve = (value: T | PromiseLike): void => { + if (this._isResolved || this._isRejected || this._isCancelled) { + return; + } + this._isResolved = true; + if (this._resolve) this._resolve(value); + }; + + const onReject = (reason?: unknown): void => { + if (this._isResolved || this._isRejected || this._isCancelled) { + return; + } + this._isRejected = true; + if (this._reject) this._reject(reason); + }; + + const onCancel = (cancelHandler: () => void): void => { + if (this._isResolved || this._isRejected || this._isCancelled) { + return; + } + this.cancelHandlers.push(cancelHandler); + }; + + Object.defineProperty(onCancel, 'isResolved', { + get: (): boolean => this._isResolved, + }); + + Object.defineProperty(onCancel, 'isRejected', { + get: (): boolean => this._isRejected, + }); + + Object.defineProperty(onCancel, 'isCancelled', { + get: (): boolean => this._isCancelled, + }); + + return executor(onResolve, onReject, onCancel as OnCancel); + }); + } + + get [Symbol.toStringTag]() { + return "Cancellable Promise"; + } + + public then( + onFulfilled?: ((value: T) => TResult1 | PromiseLike) | null, + onRejected?: ((reason: unknown) => TResult2 | PromiseLike) | null + ): Promise { + return this.promise.then(onFulfilled, onRejected); + } + + public catch( + onRejected?: ((reason: unknown) => TResult | PromiseLike) | null + ): Promise { + return this.promise.catch(onRejected); + } + + public finally(onFinally?: (() => void) | null): Promise { + return this.promise.finally(onFinally); + } + + public cancel(): void { + if (this._isResolved || this._isRejected || this._isCancelled) { + return; + } + this._isCancelled = true; + if (this.cancelHandlers.length) { + try { + for (const cancelHandler of this.cancelHandlers) { + cancelHandler(); + } + } catch (error) { + console.warn('Cancellation threw an error', error); + return; + } + } + this.cancelHandlers.length = 0; + if (this._reject) this._reject(new CancelError('Request aborted')); + } + + public get isCancelled(): boolean { + return this._isCancelled; + } +} \ No newline at end of file diff --git a/frontend/src/client/core/OpenAPI.ts b/frontend/src/client/core/OpenAPI.ts index e99068ea2e..74f92b4085 100644 --- a/frontend/src/client/core/OpenAPI.ts +++ b/frontend/src/client/core/OpenAPI.ts @@ -1,57 +1,57 @@ -import type { AxiosRequestConfig, AxiosResponse } from "axios" -import type { ApiRequestOptions } from "./ApiRequestOptions" +import type { AxiosRequestConfig, AxiosResponse } from 'axios'; +import type { ApiRequestOptions } from './ApiRequestOptions'; -type Headers = Record -type Middleware = (value: T) => T | Promise -type Resolver = (options: ApiRequestOptions) => Promise +type Headers = Record; +type Middleware = (value: T) => T | Promise; +type Resolver = (options: ApiRequestOptions) => Promise; export class Interceptors { - _fns: Middleware[] + _fns: Middleware[]; constructor() { - this._fns = [] + this._fns = []; } eject(fn: Middleware): void { - const index = this._fns.indexOf(fn) + const index = this._fns.indexOf(fn); if (index !== -1) { - this._fns = [...this._fns.slice(0, index), ...this._fns.slice(index + 1)] + this._fns = [...this._fns.slice(0, index), ...this._fns.slice(index + 1)]; } } use(fn: Middleware): void { - this._fns = [...this._fns, fn] + this._fns = [...this._fns, fn]; } } export type OpenAPIConfig = { - BASE: string - CREDENTIALS: "include" | "omit" | "same-origin" - ENCODE_PATH?: ((path: string) => string) | undefined - HEADERS?: Headers | Resolver | undefined - PASSWORD?: string | Resolver | undefined - TOKEN?: string | Resolver | undefined - USERNAME?: string | Resolver | undefined - VERSION: string - WITH_CREDENTIALS: boolean - interceptors: { - request: Interceptors - response: Interceptors - } -} + BASE: string; + CREDENTIALS: 'include' | 'omit' | 'same-origin'; + ENCODE_PATH?: ((path: string) => string) | undefined; + HEADERS?: Headers | Resolver | undefined; + PASSWORD?: string | Resolver | undefined; + TOKEN?: string | Resolver | undefined; + USERNAME?: string | Resolver | undefined; + VERSION: string; + WITH_CREDENTIALS: boolean; + interceptors: { + request: Interceptors; + response: Interceptors; + }; +}; export const OpenAPI: OpenAPIConfig = { - BASE: "", - CREDENTIALS: "include", - ENCODE_PATH: undefined, - HEADERS: undefined, - PASSWORD: undefined, - TOKEN: undefined, - USERNAME: undefined, - VERSION: "0.1.0", - WITH_CREDENTIALS: false, - interceptors: { - request: new Interceptors(), - response: new Interceptors(), - }, -} + BASE: '', + CREDENTIALS: 'include', + ENCODE_PATH: undefined, + HEADERS: undefined, + PASSWORD: undefined, + TOKEN: undefined, + USERNAME: undefined, + VERSION: '0.1.0', + WITH_CREDENTIALS: false, + interceptors: { + request: new Interceptors(), + response: new Interceptors(), + }, +}; \ No newline at end of file diff --git a/frontend/src/client/core/request.ts b/frontend/src/client/core/request.ts index 8b42272b93..ecc2e393cd 100644 --- a/frontend/src/client/core/request.ts +++ b/frontend/src/client/core/request.ts @@ -1,325 +1,301 @@ -import axios from "axios" -import type { - AxiosError, - AxiosRequestConfig, - AxiosResponse, - AxiosInstance, -} from "axios" - -import { ApiError } from "./ApiError" -import type { ApiRequestOptions } from "./ApiRequestOptions" -import type { ApiResult } from "./ApiResult" -import { CancelablePromise } from "./CancelablePromise" -import type { OnCancel } from "./CancelablePromise" -import type { OpenAPIConfig } from "./OpenAPI" +import axios from 'axios'; +import type { AxiosError, AxiosRequestConfig, AxiosResponse, AxiosInstance } from 'axios'; + +import { ApiError } from './ApiError'; +import type { ApiRequestOptions } from './ApiRequestOptions'; +import type { ApiResult } from './ApiResult'; +import { CancelablePromise } from './CancelablePromise'; +import type { OnCancel } from './CancelablePromise'; +import type { OpenAPIConfig } from './OpenAPI'; export const isString = (value: unknown): value is string => { - return typeof value === "string" -} + return typeof value === 'string'; +}; export const isStringWithValue = (value: unknown): value is string => { - return isString(value) && value !== "" -} + return isString(value) && value !== ''; +}; export const isBlob = (value: any): value is Blob => { - return value instanceof Blob -} + return value instanceof Blob; +}; export const isFormData = (value: unknown): value is FormData => { - return value instanceof FormData -} + return value instanceof FormData; +}; export const isSuccess = (status: number): boolean => { - return status >= 200 && status < 300 -} + return status >= 200 && status < 300; +}; export const base64 = (str: string): string => { - try { - return btoa(str) - } catch (err) { - // @ts-ignore - return Buffer.from(str).toString("base64") - } -} + try { + return btoa(str); + } catch (err) { + // @ts-ignore + return Buffer.from(str).toString('base64'); + } +}; export const getQueryString = (params: Record): string => { - const qs: string[] = [] + const qs: string[] = []; - const append = (key: string, value: unknown) => { - qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`) - } + const append = (key: string, value: unknown) => { + qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`); + }; - const encodePair = (key: string, value: unknown) => { - if (value === undefined || value === null) { - return - } + const encodePair = (key: string, value: unknown) => { + if (value === undefined || value === null) { + return; + } - if (value instanceof Date) { - append(key, value.toISOString()) - } else if (Array.isArray(value)) { - value.forEach((v) => encodePair(key, v)) - } else if (typeof value === "object") { - Object.entries(value).forEach(([k, v]) => encodePair(`${key}[${k}]`, v)) - } else { - append(key, value) - } - } + if (value instanceof Date) { + append(key, value.toISOString()); + } else if (Array.isArray(value)) { + value.forEach(v => encodePair(key, v)); + } else if (typeof value === 'object') { + Object.entries(value).forEach(([k, v]) => encodePair(`${key}[${k}]`, v)); + } else { + append(key, value); + } + }; - Object.entries(params).forEach(([key, value]) => encodePair(key, value)) + Object.entries(params).forEach(([key, value]) => encodePair(key, value)); - return qs.length ? `?${qs.join("&")}` : "" -} + return qs.length ? `?${qs.join('&')}` : ''; +}; const getUrl = (config: OpenAPIConfig, options: ApiRequestOptions): string => { - const encoder = config.ENCODE_PATH || encodeURI - - const path = options.url - .replace("{api-version}", config.VERSION) - .replace(/{(.*?)}/g, (substring: string, group: string) => { - if (options.path?.hasOwnProperty(group)) { - return encoder(String(options.path[group])) - } - return substring - }) - - const url = config.BASE + path - return options.query ? url + getQueryString(options.query) : url -} - -export const getFormData = ( - options: ApiRequestOptions, -): FormData | undefined => { - if (options.formData) { - const formData = new FormData() - - const process = (key: string, value: unknown) => { - if (isString(value) || isBlob(value)) { - formData.append(key, value) - } else { - formData.append(key, JSON.stringify(value)) - } - } - - Object.entries(options.formData) - .filter(([, value]) => value !== undefined && value !== null) - .forEach(([key, value]) => { - if (Array.isArray(value)) { - value.forEach((v) => process(key, v)) - } else { - process(key, value) - } - }) - - return formData - } - return undefined -} - -type Resolver = (options: ApiRequestOptions) => Promise - -export const resolve = async ( - options: ApiRequestOptions, - resolver?: T | Resolver, -): Promise => { - if (typeof resolver === "function") { - return (resolver as Resolver)(options) - } - return resolver -} - -export const getHeaders = async ( - config: OpenAPIConfig, - options: ApiRequestOptions, -): Promise> => { - const [token, username, password, additionalHeaders] = await Promise.all([ - // @ts-ignore - resolve(options, config.TOKEN), - // @ts-ignore - resolve(options, config.USERNAME), - // @ts-ignore - resolve(options, config.PASSWORD), - // @ts-ignore - resolve(options, config.HEADERS), - ]) - - const headers = Object.entries({ - Accept: "application/json", - ...additionalHeaders, - ...options.headers, - }) - .filter(([, value]) => value !== undefined && value !== null) - .reduce( - (headers, [key, value]) => ({ - ...headers, - [key]: String(value), - }), - {} as Record, - ) - - if (isStringWithValue(token)) { - headers["Authorization"] = `Bearer ${token}` - } - - if (isStringWithValue(username) && isStringWithValue(password)) { - const credentials = base64(`${username}:${password}`) - headers["Authorization"] = `Basic ${credentials}` - } - - if (options.body !== undefined) { - if (options.mediaType) { - headers["Content-Type"] = options.mediaType - } else if (isBlob(options.body)) { - headers["Content-Type"] = options.body.type || "application/octet-stream" - } else if (isString(options.body)) { - headers["Content-Type"] = "text/plain" - } else if (!isFormData(options.body)) { - headers["Content-Type"] = "application/json" - } - } else if (options.formData !== undefined) { - if (options.mediaType) { - headers["Content-Type"] = options.mediaType - } - } - - return headers -} + const encoder = config.ENCODE_PATH || encodeURI; + + const path = options.url + .replace('{api-version}', config.VERSION) + .replace(/{(.*?)}/g, (substring: string, group: string) => { + if (options.path?.hasOwnProperty(group)) { + return encoder(String(options.path[group])); + } + return substring; + }); + + const url = config.BASE + path; + return options.query ? url + getQueryString(options.query) : url; +}; + +export const getFormData = (options: ApiRequestOptions): FormData | undefined => { + if (options.formData) { + const formData = new FormData(); + + const process = (key: string, value: unknown) => { + if (isString(value) || isBlob(value)) { + formData.append(key, value); + } else { + formData.append(key, JSON.stringify(value)); + } + }; + + Object.entries(options.formData) + .filter(([, value]) => value !== undefined && value !== null) + .forEach(([key, value]) => { + if (Array.isArray(value)) { + value.forEach(v => process(key, v)); + } else { + process(key, value); + } + }); + + return formData; + } + return undefined; +}; + +type Resolver = (options: ApiRequestOptions) => Promise; + +export const resolve = async (options: ApiRequestOptions, resolver?: T | Resolver): Promise => { + if (typeof resolver === 'function') { + return (resolver as Resolver)(options); + } + return resolver; +}; + +export const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptions): Promise> => { + const [token, username, password, additionalHeaders] = await Promise.all([ + // @ts-ignore + resolve(options, config.TOKEN), + // @ts-ignore + resolve(options, config.USERNAME), + // @ts-ignore + resolve(options, config.PASSWORD), + // @ts-ignore + resolve(options, config.HEADERS), + ]); + + const headers = Object.entries({ + Accept: 'application/json', + ...additionalHeaders, + ...options.headers, + }) + .filter(([, value]) => value !== undefined && value !== null) + .reduce((headers, [key, value]) => ({ + ...headers, + [key]: String(value), + }), {} as Record); + + if (isStringWithValue(token)) { + headers['Authorization'] = `Bearer ${token}`; + } + + if (isStringWithValue(username) && isStringWithValue(password)) { + const credentials = base64(`${username}:${password}`); + headers['Authorization'] = `Basic ${credentials}`; + } + + if (options.body !== undefined) { + if (options.mediaType) { + headers['Content-Type'] = options.mediaType; + } else if (isBlob(options.body)) { + headers['Content-Type'] = options.body.type || 'application/octet-stream'; + } else if (isString(options.body)) { + headers['Content-Type'] = 'text/plain'; + } else if (!isFormData(options.body)) { + headers['Content-Type'] = 'application/json'; + } + } else if (options.formData !== undefined) { + if (options.mediaType) { + headers['Content-Type'] = options.mediaType; + } + } + + return headers; +}; export const getRequestBody = (options: ApiRequestOptions): unknown => { - if (options.body) { - return options.body - } - return undefined -} + if (options.body) { + return options.body; + } + return undefined; +}; export const sendRequest = async ( - config: OpenAPIConfig, - options: ApiRequestOptions, - url: string, - body: unknown, - formData: FormData | undefined, - headers: Record, - onCancel: OnCancel, - axiosClient: AxiosInstance, + config: OpenAPIConfig, + options: ApiRequestOptions, + url: string, + body: unknown, + formData: FormData | undefined, + headers: Record, + onCancel: OnCancel, + axiosClient: AxiosInstance ): Promise> => { - const controller = new AbortController() - - let requestConfig: AxiosRequestConfig = { - data: body ?? formData, - headers, - method: options.method, - signal: controller.signal, - url, - withCredentials: config.WITH_CREDENTIALS, - } - - onCancel(() => controller.abort()) - - for (const fn of config.interceptors.request._fns) { - requestConfig = await fn(requestConfig) - } - - try { - return await axiosClient.request(requestConfig) - } catch (error) { - const axiosError = error as AxiosError - if (axiosError.response) { - return axiosError.response - } - throw error - } -} - -export const getResponseHeader = ( - response: AxiosResponse, - responseHeader?: string, -): string | undefined => { - if (responseHeader) { - const content = response.headers[responseHeader] - if (isString(content)) { - return content - } - } - return undefined -} + const controller = new AbortController(); + + let requestConfig: AxiosRequestConfig = { + data: body ?? formData, + headers, + method: options.method, + signal: controller.signal, + url, + withCredentials: config.WITH_CREDENTIALS, + }; + + onCancel(() => controller.abort()); + + for (const fn of config.interceptors.request._fns) { + requestConfig = await fn(requestConfig); + } + + try { + return await axiosClient.request(requestConfig); + } catch (error) { + const axiosError = error as AxiosError; + if (axiosError.response) { + return axiosError.response; + } + throw error; + } +}; + +export const getResponseHeader = (response: AxiosResponse, responseHeader?: string): string | undefined => { + if (responseHeader) { + const content = response.headers[responseHeader]; + if (isString(content)) { + return content; + } + } + return undefined; +}; export const getResponseBody = (response: AxiosResponse): unknown => { - if (response.status !== 204) { - return response.data - } - return undefined -} - -export const catchErrorCodes = ( - options: ApiRequestOptions, - result: ApiResult, -): void => { - const errors: Record = { - 400: "Bad Request", - 401: "Unauthorized", - 402: "Payment Required", - 403: "Forbidden", - 404: "Not Found", - 405: "Method Not Allowed", - 406: "Not Acceptable", - 407: "Proxy Authentication Required", - 408: "Request Timeout", - 409: "Conflict", - 410: "Gone", - 411: "Length Required", - 412: "Precondition Failed", - 413: "Payload Too Large", - 414: "URI Too Long", - 415: "Unsupported Media Type", - 416: "Range Not Satisfiable", - 417: "Expectation Failed", - 418: "Im a teapot", - 421: "Misdirected Request", - 422: "Unprocessable Content", - 423: "Locked", - 424: "Failed Dependency", - 425: "Too Early", - 426: "Upgrade Required", - 428: "Precondition Required", - 429: "Too Many Requests", - 431: "Request Header Fields Too Large", - 451: "Unavailable For Legal Reasons", - 500: "Internal Server Error", - 501: "Not Implemented", - 502: "Bad Gateway", - 503: "Service Unavailable", - 504: "Gateway Timeout", - 505: "HTTP Version Not Supported", - 506: "Variant Also Negotiates", - 507: "Insufficient Storage", - 508: "Loop Detected", - 510: "Not Extended", - 511: "Network Authentication Required", - ...options.errors, - } - - const error = errors[result.status] - if (error) { - throw new ApiError(options, result, error) - } - - if (!result.ok) { - const errorStatus = result.status ?? "unknown" - const errorStatusText = result.statusText ?? "unknown" - const errorBody = (() => { - try { - return JSON.stringify(result.body, null, 2) - } catch (e) { - return undefined - } - })() - - throw new ApiError( - options, - result, - `Generic Error: status: ${errorStatus}; status text: ${errorStatusText}; body: ${errorBody}`, - ) - } -} + if (response.status !== 204) { + return response.data; + } + return undefined; +}; + +export const catchErrorCodes = (options: ApiRequestOptions, result: ApiResult): void => { + const errors: Record = { + 400: 'Bad Request', + 401: 'Unauthorized', + 402: 'Payment Required', + 403: 'Forbidden', + 404: 'Not Found', + 405: 'Method Not Allowed', + 406: 'Not Acceptable', + 407: 'Proxy Authentication Required', + 408: 'Request Timeout', + 409: 'Conflict', + 410: 'Gone', + 411: 'Length Required', + 412: 'Precondition Failed', + 413: 'Payload Too Large', + 414: 'URI Too Long', + 415: 'Unsupported Media Type', + 416: 'Range Not Satisfiable', + 417: 'Expectation Failed', + 418: 'Im a teapot', + 421: 'Misdirected Request', + 422: 'Unprocessable Content', + 423: 'Locked', + 424: 'Failed Dependency', + 425: 'Too Early', + 426: 'Upgrade Required', + 428: 'Precondition Required', + 429: 'Too Many Requests', + 431: 'Request Header Fields Too Large', + 451: 'Unavailable For Legal Reasons', + 500: 'Internal Server Error', + 501: 'Not Implemented', + 502: 'Bad Gateway', + 503: 'Service Unavailable', + 504: 'Gateway Timeout', + 505: 'HTTP Version Not Supported', + 506: 'Variant Also Negotiates', + 507: 'Insufficient Storage', + 508: 'Loop Detected', + 510: 'Not Extended', + 511: 'Network Authentication Required', + ...options.errors, + } + + const error = errors[result.status]; + if (error) { + throw new ApiError(options, result, error); + } + + if (!result.ok) { + const errorStatus = result.status ?? 'unknown'; + const errorStatusText = result.statusText ?? 'unknown'; + const errorBody = (() => { + try { + return JSON.stringify(result.body, null, 2); + } catch (e) { + return undefined; + } + })(); + + throw new ApiError(options, result, + `Generic Error: status: ${errorStatus}; status text: ${errorStatusText}; body: ${errorBody}` + ); + } +}; /** * Request method @@ -329,59 +305,43 @@ export const catchErrorCodes = ( * @returns CancelablePromise * @throws ApiError */ -export const request = ( - config: OpenAPIConfig, - options: ApiRequestOptions, - axiosClient: AxiosInstance = axios, -): CancelablePromise => { - return new CancelablePromise(async (resolve, reject, onCancel) => { - try { - const url = getUrl(config, options) - const formData = getFormData(options) - const body = getRequestBody(options) - const headers = await getHeaders(config, options) - - if (!onCancel.isCancelled) { - let response = await sendRequest( - config, - options, - url, - body, - formData, - headers, - onCancel, - axiosClient, - ) - - for (const fn of config.interceptors.response._fns) { - response = await fn(response) - } - - const responseBody = getResponseBody(response) - const responseHeader = getResponseHeader( - response, - options.responseHeader, - ) - - let transformedBody = responseBody - if (options.responseTransformer && isSuccess(response.status)) { - transformedBody = await options.responseTransformer(responseBody) - } - - const result: ApiResult = { - url, - ok: isSuccess(response.status), - status: response.status, - statusText: response.statusText, - body: responseHeader ?? transformedBody, - } - - catchErrorCodes(options, result) - - resolve(result.body) - } - } catch (error) { - reject(error) - } - }) -} +export const request = (config: OpenAPIConfig, options: ApiRequestOptions, axiosClient: AxiosInstance = axios): CancelablePromise => { + return new CancelablePromise(async (resolve, reject, onCancel) => { + try { + const url = getUrl(config, options); + const formData = getFormData(options); + const body = getRequestBody(options); + const headers = await getHeaders(config, options); + + if (!onCancel.isCancelled) { + let response = await sendRequest(config, options, url, body, formData, headers, onCancel, axiosClient); + + for (const fn of config.interceptors.response._fns) { + response = await fn(response); + } + + const responseBody = getResponseBody(response); + const responseHeader = getResponseHeader(response, options.responseHeader); + + let transformedBody = responseBody; + if (options.responseTransformer && isSuccess(response.status)) { + transformedBody = await options.responseTransformer(responseBody) + } + + const result: ApiResult = { + url, + ok: isSuccess(response.status), + status: response.status, + statusText: response.statusText, + body: responseHeader ?? transformedBody, + }; + + catchErrorCodes(options, result); + + resolve(result.body); + } + } catch (error) { + reject(error); + } + }); +}; \ No newline at end of file diff --git a/frontend/src/client/index.ts b/frontend/src/client/index.ts index 2228dde8b4..50a1dd734c 100644 --- a/frontend/src/client/index.ts +++ b/frontend/src/client/index.ts @@ -1,6 +1,6 @@ // This file is auto-generated by @hey-api/openapi-ts -export { ApiError } from "./core/ApiError" -export { CancelablePromise, CancelError } from "./core/CancelablePromise" -export { OpenAPI, type OpenAPIConfig } from "./core/OpenAPI" -export * from "./sdk.gen" -export * from "./types.gen" +export { ApiError } from './core/ApiError'; +export { CancelablePromise, CancelError } from './core/CancelablePromise'; +export { OpenAPI, type OpenAPIConfig } from './core/OpenAPI'; +export * from './sdk.gen'; +export * from './types.gen'; \ No newline at end of file diff --git a/frontend/src/client/schemas.gen.ts b/frontend/src/client/schemas.gen.ts index 1c4f784a87..a5c029db0a 100644 --- a/frontend/src/client/schemas.gen.ts +++ b/frontend/src/client/schemas.gen.ts @@ -1,526 +1,526 @@ // This file is auto-generated by @hey-api/openapi-ts export const Body_login_login_access_tokenSchema = { - properties: { - grant_type: { - anyOf: [ - { - type: "string", - pattern: "password", - }, - { - type: "null", - }, - ], - title: "Grant Type", - }, - username: { - type: "string", - title: "Username", - }, - password: { - type: "string", - title: "Password", - }, - scope: { - type: "string", - title: "Scope", - default: "", - }, - client_id: { - anyOf: [ - { - type: "string", + properties: { + grant_type: { + anyOf: [ + { + type: 'string', + pattern: 'password' + }, + { + type: 'null' + } + ], + title: 'Grant Type' }, - { - type: "null", + username: { + type: 'string', + title: 'Username' }, - ], - title: "Client Id", - }, - client_secret: { - anyOf: [ - { - type: "string", + password: { + type: 'string', + title: 'Password' }, - { - type: "null", + scope: { + type: 'string', + title: 'Scope', + default: '' }, - ], - title: "Client Secret", - }, - }, - type: "object", - required: ["username", "password"], - title: "Body_login-login_access_token", -} as const + client_id: { + anyOf: [ + { + type: 'string' + }, + { + type: 'null' + } + ], + title: 'Client Id' + }, + client_secret: { + anyOf: [ + { + type: 'string' + }, + { + type: 'null' + } + ], + title: 'Client Secret' + } + }, + type: 'object', + required: ['username', 'password'], + title: 'Body_login-login_access_token' +} as const; export const HTTPValidationErrorSchema = { - properties: { - detail: { - items: { - $ref: "#/components/schemas/ValidationError", - }, - type: "array", - title: "Detail", - }, - }, - type: "object", - title: "HTTPValidationError", -} as const + properties: { + detail: { + items: { + '$ref': '#/components/schemas/ValidationError' + }, + type: 'array', + title: 'Detail' + } + }, + type: 'object', + title: 'HTTPValidationError' +} as const; export const ItemCreateSchema = { - properties: { - title: { - type: "string", - maxLength: 255, - minLength: 1, - title: "Title", - }, - description: { - anyOf: [ - { - type: "string", - maxLength: 255, - }, - { - type: "null", + properties: { + title: { + type: 'string', + maxLength: 255, + minLength: 1, + title: 'Title' }, - ], - title: "Description", - }, - }, - type: "object", - required: ["title"], - title: "ItemCreate", -} as const + description: { + anyOf: [ + { + type: 'string', + maxLength: 255 + }, + { + type: 'null' + } + ], + title: 'Description' + } + }, + type: 'object', + required: ['title'], + title: 'ItemCreate' +} as const; export const ItemPublicSchema = { - properties: { - title: { - type: "string", - maxLength: 255, - minLength: 1, - title: "Title", - }, - description: { - anyOf: [ - { - type: "string", - maxLength: 255, + properties: { + title: { + type: 'string', + maxLength: 255, + minLength: 1, + title: 'Title' }, - { - type: "null", + description: { + anyOf: [ + { + type: 'string', + maxLength: 255 + }, + { + type: 'null' + } + ], + title: 'Description' }, - ], - title: "Description", - }, - id: { - type: "string", - format: "uuid", - title: "Id", - }, - owner_id: { - type: "string", - format: "uuid", - title: "Owner Id", - }, - }, - type: "object", - required: ["title", "id", "owner_id"], - title: "ItemPublic", -} as const + id: { + type: 'string', + format: 'uuid', + title: 'Id' + }, + owner_id: { + type: 'string', + format: 'uuid', + title: 'Owner Id' + } + }, + type: 'object', + required: ['title', 'id', 'owner_id'], + title: 'ItemPublic' +} as const; export const ItemUpdateSchema = { - properties: { - title: { - anyOf: [ - { - type: "string", - maxLength: 255, - minLength: 1, - }, - { - type: "null", - }, - ], - title: "Title", - }, - description: { - anyOf: [ - { - type: "string", - maxLength: 255, + properties: { + title: { + anyOf: [ + { + type: 'string', + maxLength: 255, + minLength: 1 + }, + { + type: 'null' + } + ], + title: 'Title' }, - { - type: "null", - }, - ], - title: "Description", - }, - }, - type: "object", - title: "ItemUpdate", -} as const + description: { + anyOf: [ + { + type: 'string', + maxLength: 255 + }, + { + type: 'null' + } + ], + title: 'Description' + } + }, + type: 'object', + title: 'ItemUpdate' +} as const; export const ItemsPublicSchema = { - properties: { - data: { - items: { - $ref: "#/components/schemas/ItemPublic", - }, - type: "array", - title: "Data", - }, - count: { - type: "integer", - title: "Count", - }, - }, - type: "object", - required: ["data", "count"], - title: "ItemsPublic", -} as const + properties: { + data: { + items: { + '$ref': '#/components/schemas/ItemPublic' + }, + type: 'array', + title: 'Data' + }, + count: { + type: 'integer', + title: 'Count' + } + }, + type: 'object', + required: ['data', 'count'], + title: 'ItemsPublic' +} as const; export const MessageSchema = { - properties: { - message: { - type: "string", - title: "Message", - }, - }, - type: "object", - required: ["message"], - title: "Message", -} as const + properties: { + message: { + type: 'string', + title: 'Message' + } + }, + type: 'object', + required: ['message'], + title: 'Message' +} as const; export const NewPasswordSchema = { - properties: { - token: { - type: "string", - title: "Token", - }, - new_password: { - type: "string", - maxLength: 40, - minLength: 8, - title: "New Password", - }, - }, - type: "object", - required: ["token", "new_password"], - title: "NewPassword", -} as const + properties: { + token: { + type: 'string', + title: 'Token' + }, + new_password: { + type: 'string', + maxLength: 40, + minLength: 8, + title: 'New Password' + } + }, + type: 'object', + required: ['token', 'new_password'], + title: 'NewPassword' +} as const; export const PrivateUserCreateSchema = { - properties: { - email: { - type: "string", - title: "Email", - }, - password: { - type: "string", - title: "Password", - }, - full_name: { - type: "string", - title: "Full Name", - }, - is_verified: { - type: "boolean", - title: "Is Verified", - default: false, - }, - }, - type: "object", - required: ["email", "password", "full_name"], - title: "PrivateUserCreate", -} as const + properties: { + email: { + type: 'string', + title: 'Email' + }, + password: { + type: 'string', + title: 'Password' + }, + full_name: { + type: 'string', + title: 'Full Name' + }, + is_verified: { + type: 'boolean', + title: 'Is Verified', + default: false + } + }, + type: 'object', + required: ['email', 'password', 'full_name'], + title: 'PrivateUserCreate' +} as const; export const TokenSchema = { - properties: { - access_token: { - type: "string", - title: "Access Token", - }, - token_type: { - type: "string", - title: "Token Type", - default: "bearer", - }, - }, - type: "object", - required: ["access_token"], - title: "Token", -} as const + properties: { + access_token: { + type: 'string', + title: 'Access Token' + }, + token_type: { + type: 'string', + title: 'Token Type', + default: 'bearer' + } + }, + type: 'object', + required: ['access_token'], + title: 'Token' +} as const; export const UpdatePasswordSchema = { - properties: { - current_password: { - type: "string", - maxLength: 40, - minLength: 8, - title: "Current Password", - }, - new_password: { - type: "string", - maxLength: 40, - minLength: 8, - title: "New Password", - }, - }, - type: "object", - required: ["current_password", "new_password"], - title: "UpdatePassword", -} as const + properties: { + current_password: { + type: 'string', + maxLength: 40, + minLength: 8, + title: 'Current Password' + }, + new_password: { + type: 'string', + maxLength: 40, + minLength: 8, + title: 'New Password' + } + }, + type: 'object', + required: ['current_password', 'new_password'], + title: 'UpdatePassword' +} as const; export const UserCreateSchema = { - properties: { - email: { - type: "string", - maxLength: 255, - format: "email", - title: "Email", - }, - is_active: { - type: "boolean", - title: "Is Active", - default: true, - }, - is_superuser: { - type: "boolean", - title: "Is Superuser", - default: false, - }, - full_name: { - anyOf: [ - { - type: "string", - maxLength: 255, + properties: { + email: { + type: 'string', + maxLength: 255, + format: 'email', + title: 'Email' }, - { - type: "null", + is_active: { + type: 'boolean', + title: 'Is Active', + default: true }, - ], - title: "Full Name", - }, - password: { - type: "string", - maxLength: 40, - minLength: 8, - title: "Password", - }, - }, - type: "object", - required: ["email", "password"], - title: "UserCreate", -} as const + is_superuser: { + type: 'boolean', + title: 'Is Superuser', + default: false + }, + full_name: { + anyOf: [ + { + type: 'string', + maxLength: 255 + }, + { + type: 'null' + } + ], + title: 'Full Name' + }, + password: { + type: 'string', + maxLength: 40, + minLength: 8, + title: 'Password' + } + }, + type: 'object', + required: ['email', 'password'], + title: 'UserCreate' +} as const; export const UserPublicSchema = { - properties: { - email: { - type: "string", - maxLength: 255, - format: "email", - title: "Email", - }, - is_active: { - type: "boolean", - title: "Is Active", - default: true, - }, - is_superuser: { - type: "boolean", - title: "Is Superuser", - default: false, - }, - full_name: { - anyOf: [ - { - type: "string", - maxLength: 255, + properties: { + email: { + type: 'string', + maxLength: 255, + format: 'email', + title: 'Email' }, - { - type: "null", + is_active: { + type: 'boolean', + title: 'Is Active', + default: true }, - ], - title: "Full Name", - }, - id: { - type: "string", - format: "uuid", - title: "Id", - }, - }, - type: "object", - required: ["email", "id"], - title: "UserPublic", -} as const + is_superuser: { + type: 'boolean', + title: 'Is Superuser', + default: false + }, + full_name: { + anyOf: [ + { + type: 'string', + maxLength: 255 + }, + { + type: 'null' + } + ], + title: 'Full Name' + }, + id: { + type: 'string', + format: 'uuid', + title: 'Id' + } + }, + type: 'object', + required: ['email', 'id'], + title: 'UserPublic' +} as const; export const UserRegisterSchema = { - properties: { - email: { - type: "string", - maxLength: 255, - format: "email", - title: "Email", - }, - password: { - type: "string", - maxLength: 40, - minLength: 8, - title: "Password", - }, - full_name: { - anyOf: [ - { - type: "string", - maxLength: 255, + properties: { + email: { + type: 'string', + maxLength: 255, + format: 'email', + title: 'Email' }, - { - type: "null", + password: { + type: 'string', + maxLength: 40, + minLength: 8, + title: 'Password' }, - ], - title: "Full Name", - }, - }, - type: "object", - required: ["email", "password"], - title: "UserRegister", -} as const + full_name: { + anyOf: [ + { + type: 'string', + maxLength: 255 + }, + { + type: 'null' + } + ], + title: 'Full Name' + } + }, + type: 'object', + required: ['email', 'password'], + title: 'UserRegister' +} as const; export const UserUpdateSchema = { - properties: { - email: { - anyOf: [ - { - type: "string", - maxLength: 255, - format: "email", - }, - { - type: "null", - }, - ], - title: "Email", - }, - is_active: { - type: "boolean", - title: "Is Active", - default: true, - }, - is_superuser: { - type: "boolean", - title: "Is Superuser", - default: false, - }, - full_name: { - anyOf: [ - { - type: "string", - maxLength: 255, + properties: { + email: { + anyOf: [ + { + type: 'string', + maxLength: 255, + format: 'email' + }, + { + type: 'null' + } + ], + title: 'Email' }, - { - type: "null", + is_active: { + type: 'boolean', + title: 'Is Active', + default: true }, - ], - title: "Full Name", - }, - password: { - anyOf: [ - { - type: "string", - maxLength: 40, - minLength: 8, - }, - { - type: "null", - }, - ], - title: "Password", - }, - }, - type: "object", - title: "UserUpdate", -} as const + is_superuser: { + type: 'boolean', + title: 'Is Superuser', + default: false + }, + full_name: { + anyOf: [ + { + type: 'string', + maxLength: 255 + }, + { + type: 'null' + } + ], + title: 'Full Name' + }, + password: { + anyOf: [ + { + type: 'string', + maxLength: 40, + minLength: 8 + }, + { + type: 'null' + } + ], + title: 'Password' + } + }, + type: 'object', + title: 'UserUpdate' +} as const; export const UserUpdateMeSchema = { - properties: { - full_name: { - anyOf: [ - { - type: "string", - maxLength: 255, - }, - { - type: "null", - }, - ], - title: "Full Name", - }, - email: { - anyOf: [ - { - type: "string", - maxLength: 255, - format: "email", - }, - { - type: "null", - }, - ], - title: "Email", - }, - }, - type: "object", - title: "UserUpdateMe", -} as const + properties: { + full_name: { + anyOf: [ + { + type: 'string', + maxLength: 255 + }, + { + type: 'null' + } + ], + title: 'Full Name' + }, + email: { + anyOf: [ + { + type: 'string', + maxLength: 255, + format: 'email' + }, + { + type: 'null' + } + ], + title: 'Email' + } + }, + type: 'object', + title: 'UserUpdateMe' +} as const; export const UsersPublicSchema = { - properties: { - data: { - items: { - $ref: "#/components/schemas/UserPublic", - }, - type: "array", - title: "Data", - }, - count: { - type: "integer", - title: "Count", - }, - }, - type: "object", - required: ["data", "count"], - title: "UsersPublic", -} as const + properties: { + data: { + items: { + '$ref': '#/components/schemas/UserPublic' + }, + type: 'array', + title: 'Data' + }, + count: { + type: 'integer', + title: 'Count' + } + }, + type: 'object', + required: ['data', 'count'], + title: 'UsersPublic' +} as const; export const ValidationErrorSchema = { - properties: { - loc: { - items: { - anyOf: [ - { - type: "string", - }, - { - type: "integer", - }, - ], - }, - type: "array", - title: "Location", - }, - msg: { - type: "string", - title: "Message", - }, - type: { - type: "string", - title: "Error Type", - }, - }, - type: "object", - required: ["loc", "msg", "type"], - title: "ValidationError", -} as const + properties: { + loc: { + items: { + anyOf: [ + { + type: 'string' + }, + { + type: 'integer' + } + ] + }, + type: 'array', + title: 'Location' + }, + msg: { + type: 'string', + title: 'Message' + }, + type: { + type: 'string', + title: 'Error Type' + } + }, + type: 'object', + required: ['loc', 'msg', 'type'], + title: 'ValidationError' +} as const; \ No newline at end of file diff --git a/frontend/src/client/sdk.gen.ts b/frontend/src/client/sdk.gen.ts index 156003aec9..ba79e3f726 100644 --- a/frontend/src/client/sdk.gen.ts +++ b/frontend/src/client/sdk.gen.ts @@ -1,549 +1,468 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { CancelablePromise } from "./core/CancelablePromise" -import { OpenAPI } from "./core/OpenAPI" -import { request as __request } from "./core/request" -import type { - ItemsReadItemsData, - ItemsReadItemsResponse, - ItemsCreateItemData, - ItemsCreateItemResponse, - ItemsReadItemData, - ItemsReadItemResponse, - ItemsUpdateItemData, - ItemsUpdateItemResponse, - ItemsDeleteItemData, - ItemsDeleteItemResponse, - LoginLoginAccessTokenData, - LoginLoginAccessTokenResponse, - LoginTestTokenResponse, - LoginRecoverPasswordData, - LoginRecoverPasswordResponse, - LoginResetPasswordData, - LoginResetPasswordResponse, - LoginRecoverPasswordHtmlContentData, - LoginRecoverPasswordHtmlContentResponse, - PrivateCreateUserData, - PrivateCreateUserResponse, - UsersReadUsersData, - UsersReadUsersResponse, - UsersCreateUserData, - UsersCreateUserResponse, - UsersReadUserMeResponse, - UsersDeleteUserMeResponse, - UsersUpdateUserMeData, - UsersUpdateUserMeResponse, - UsersUpdatePasswordMeData, - UsersUpdatePasswordMeResponse, - UsersRegisterUserData, - UsersRegisterUserResponse, - UsersReadUserByIdData, - UsersReadUserByIdResponse, - UsersUpdateUserData, - UsersUpdateUserResponse, - UsersDeleteUserData, - UsersDeleteUserResponse, - UtilsTestEmailData, - UtilsTestEmailResponse, - UtilsHealthCheckResponse, -} from "./types.gen" +import type { CancelablePromise } from './core/CancelablePromise'; +import { OpenAPI } from './core/OpenAPI'; +import { request as __request } from './core/request'; +import type { ItemsReadItemsData, ItemsReadItemsResponse, ItemsCreateItemData, ItemsCreateItemResponse, ItemsReadItemData, ItemsReadItemResponse, ItemsUpdateItemData, ItemsUpdateItemResponse, ItemsDeleteItemData, ItemsDeleteItemResponse, LoginLoginAccessTokenData, LoginLoginAccessTokenResponse, LoginTestTokenResponse, LoginRecoverPasswordData, LoginRecoverPasswordResponse, LoginResetPasswordData, LoginResetPasswordResponse, LoginRecoverPasswordHtmlContentData, LoginRecoverPasswordHtmlContentResponse, PrivateCreateUserData, PrivateCreateUserResponse, UsersReadUsersData, UsersReadUsersResponse, UsersCreateUserData, UsersCreateUserResponse, UsersReadUserMeResponse, UsersDeleteUserMeResponse, UsersUpdateUserMeData, UsersUpdateUserMeResponse, UsersUpdatePasswordMeData, UsersUpdatePasswordMeResponse, UsersRegisterUserData, UsersRegisterUserResponse, UsersReadUserByIdData, UsersReadUserByIdResponse, UsersUpdateUserData, UsersUpdateUserResponse, UsersDeleteUserData, UsersDeleteUserResponse, UtilsTestEmailData, UtilsTestEmailResponse, UtilsHealthCheckResponse } from './types.gen'; export class ItemsService { - /** - * Read Items - * Retrieve items. - * @param data The data for the request. - * @param data.skip - * @param data.limit - * @returns ItemsPublic Successful Response - * @throws ApiError - */ - public static readItems( - data: ItemsReadItemsData = {}, - ): CancelablePromise { - return __request(OpenAPI, { - method: "GET", - url: "/api/v1/items/", - query: { - skip: data.skip, - limit: data.limit, - }, - errors: { - 422: "Validation Error", - }, - }) - } - - /** - * Create Item - * Create new item. - * @param data The data for the request. - * @param data.requestBody - * @returns ItemPublic Successful Response - * @throws ApiError - */ - public static createItem( - data: ItemsCreateItemData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "POST", - url: "/api/v1/items/", - body: data.requestBody, - mediaType: "application/json", - errors: { - 422: "Validation Error", - }, - }) - } - - /** - * Read Item - * Get item by ID. - * @param data The data for the request. - * @param data.id - * @returns ItemPublic Successful Response - * @throws ApiError - */ - public static readItem( - data: ItemsReadItemData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "GET", - url: "/api/v1/items/{id}", - path: { - id: data.id, - }, - errors: { - 422: "Validation Error", - }, - }) - } - - /** - * Update Item - * Update an item. - * @param data The data for the request. - * @param data.id - * @param data.requestBody - * @returns ItemPublic Successful Response - * @throws ApiError - */ - public static updateItem( - data: ItemsUpdateItemData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "PUT", - url: "/api/v1/items/{id}", - path: { - id: data.id, - }, - body: data.requestBody, - mediaType: "application/json", - errors: { - 422: "Validation Error", - }, - }) - } - - /** - * Delete Item - * Delete an item. - * @param data The data for the request. - * @param data.id - * @returns Message Successful Response - * @throws ApiError - */ - public static deleteItem( - data: ItemsDeleteItemData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "DELETE", - url: "/api/v1/items/{id}", - path: { - id: data.id, - }, - errors: { - 422: "Validation Error", - }, - }) - } + /** + * Read Items + * Retrieve items. + * @param data The data for the request. + * @param data.skip + * @param data.limit + * @returns ItemsPublic Successful Response + * @throws ApiError + */ + public static readItems(data: ItemsReadItemsData = {}): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/api/v1/items/', + query: { + skip: data.skip, + limit: data.limit + }, + errors: { + 422: 'Validation Error' + } + }); + } + + /** + * Create Item + * Create new item. + * @param data The data for the request. + * @param data.requestBody + * @returns ItemPublic Successful Response + * @throws ApiError + */ + public static createItem(data: ItemsCreateItemData): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v1/items/', + body: data.requestBody, + mediaType: 'application/json', + errors: { + 422: 'Validation Error' + } + }); + } + + /** + * Read Item + * Get item by ID. + * @param data The data for the request. + * @param data.id + * @returns ItemPublic Successful Response + * @throws ApiError + */ + public static readItem(data: ItemsReadItemData): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/api/v1/items/{id}', + path: { + id: data.id + }, + errors: { + 422: 'Validation Error' + } + }); + } + + /** + * Update Item + * Update an item. + * @param data The data for the request. + * @param data.id + * @param data.requestBody + * @returns ItemPublic Successful Response + * @throws ApiError + */ + public static updateItem(data: ItemsUpdateItemData): CancelablePromise { + return __request(OpenAPI, { + method: 'PUT', + url: '/api/v1/items/{id}', + path: { + id: data.id + }, + body: data.requestBody, + mediaType: 'application/json', + errors: { + 422: 'Validation Error' + } + }); + } + + /** + * Delete Item + * Delete an item. + * @param data The data for the request. + * @param data.id + * @returns Message Successful Response + * @throws ApiError + */ + public static deleteItem(data: ItemsDeleteItemData): CancelablePromise { + return __request(OpenAPI, { + method: 'DELETE', + url: '/api/v1/items/{id}', + path: { + id: data.id + }, + errors: { + 422: 'Validation Error' + } + }); + } } export class LoginService { - /** - * Login Access Token - * OAuth2 compatible token login, get an access token for future requests - * @param data The data for the request. - * @param data.formData - * @returns Token Successful Response - * @throws ApiError - */ - public static loginAccessToken( - data: LoginLoginAccessTokenData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "POST", - url: "/api/v1/login/access-token", - formData: data.formData, - mediaType: "application/x-www-form-urlencoded", - errors: { - 422: "Validation Error", - }, - }) - } - - /** - * Test Token - * Test access token - * @returns UserPublic Successful Response - * @throws ApiError - */ - public static testToken(): CancelablePromise { - return __request(OpenAPI, { - method: "POST", - url: "/api/v1/login/test-token", - }) - } - - /** - * Recover Password - * Password Recovery - * @param data The data for the request. - * @param data.email - * @returns Message Successful Response - * @throws ApiError - */ - public static recoverPassword( - data: LoginRecoverPasswordData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "POST", - url: "/api/v1/password-recovery/{email}", - path: { - email: data.email, - }, - errors: { - 422: "Validation Error", - }, - }) - } - - /** - * Reset Password - * Reset password - * @param data The data for the request. - * @param data.requestBody - * @returns Message Successful Response - * @throws ApiError - */ - public static resetPassword( - data: LoginResetPasswordData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "POST", - url: "/api/v1/reset-password/", - body: data.requestBody, - mediaType: "application/json", - errors: { - 422: "Validation Error", - }, - }) - } - - /** - * Recover Password Html Content - * HTML Content for Password Recovery - * @param data The data for the request. - * @param data.email - * @returns string Successful Response - * @throws ApiError - */ - public static recoverPasswordHtmlContent( - data: LoginRecoverPasswordHtmlContentData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "POST", - url: "/api/v1/password-recovery-html-content/{email}", - path: { - email: data.email, - }, - errors: { - 422: "Validation Error", - }, - }) - } + /** + * Login Access Token + * OAuth2 compatible token login, get an access token for future requests + * @param data The data for the request. + * @param data.formData + * @returns Token Successful Response + * @throws ApiError + */ + public static loginAccessToken(data: LoginLoginAccessTokenData): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v1/login/access-token', + formData: data.formData, + mediaType: 'application/x-www-form-urlencoded', + errors: { + 422: 'Validation Error' + } + }); + } + + /** + * Test Token + * Test access token + * @returns UserPublic Successful Response + * @throws ApiError + */ + public static testToken(): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v1/login/test-token' + }); + } + + /** + * Recover Password + * Password Recovery + * @param data The data for the request. + * @param data.email + * @returns Message Successful Response + * @throws ApiError + */ + public static recoverPassword(data: LoginRecoverPasswordData): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v1/password-recovery/{email}', + path: { + email: data.email + }, + errors: { + 422: 'Validation Error' + } + }); + } + + /** + * Reset Password + * Reset password + * @param data The data for the request. + * @param data.requestBody + * @returns Message Successful Response + * @throws ApiError + */ + public static resetPassword(data: LoginResetPasswordData): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v1/reset-password/', + body: data.requestBody, + mediaType: 'application/json', + errors: { + 422: 'Validation Error' + } + }); + } + + /** + * Recover Password Html Content + * HTML Content for Password Recovery + * @param data The data for the request. + * @param data.email + * @returns string Successful Response + * @throws ApiError + */ + public static recoverPasswordHtmlContent(data: LoginRecoverPasswordHtmlContentData): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v1/password-recovery-html-content/{email}', + path: { + email: data.email + }, + errors: { + 422: 'Validation Error' + } + }); + } } export class PrivateService { - /** - * Create User - * Create a new user. - * @param data The data for the request. - * @param data.requestBody - * @returns UserPublic Successful Response - * @throws ApiError - */ - public static createUser( - data: PrivateCreateUserData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "POST", - url: "/api/v1/private/users/", - body: data.requestBody, - mediaType: "application/json", - errors: { - 422: "Validation Error", - }, - }) - } + /** + * Create User + * Create a new user. + * @param data The data for the request. + * @param data.requestBody + * @returns UserPublic Successful Response + * @throws ApiError + */ + public static createUser(data: PrivateCreateUserData): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v1/private/users/', + body: data.requestBody, + mediaType: 'application/json', + errors: { + 422: 'Validation Error' + } + }); + } } export class UsersService { - /** - * Read Users - * Retrieve users. - * @param data The data for the request. - * @param data.skip - * @param data.limit - * @returns UsersPublic Successful Response - * @throws ApiError - */ - public static readUsers( - data: UsersReadUsersData = {}, - ): CancelablePromise { - return __request(OpenAPI, { - method: "GET", - url: "/api/v1/users/", - query: { - skip: data.skip, - limit: data.limit, - }, - errors: { - 422: "Validation Error", - }, - }) - } - - /** - * Create User - * Create new user. - * @param data The data for the request. - * @param data.requestBody - * @returns UserPublic Successful Response - * @throws ApiError - */ - public static createUser( - data: UsersCreateUserData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "POST", - url: "/api/v1/users/", - body: data.requestBody, - mediaType: "application/json", - errors: { - 422: "Validation Error", - }, - }) - } - - /** - * Read User Me - * Get current user. - * @returns UserPublic Successful Response - * @throws ApiError - */ - public static readUserMe(): CancelablePromise { - return __request(OpenAPI, { - method: "GET", - url: "/api/v1/users/me", - }) - } - - /** - * Delete User Me - * Delete own user. - * @returns Message Successful Response - * @throws ApiError - */ - public static deleteUserMe(): CancelablePromise { - return __request(OpenAPI, { - method: "DELETE", - url: "/api/v1/users/me", - }) - } - - /** - * Update User Me - * Update own user. - * @param data The data for the request. - * @param data.requestBody - * @returns UserPublic Successful Response - * @throws ApiError - */ - public static updateUserMe( - data: UsersUpdateUserMeData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "PATCH", - url: "/api/v1/users/me", - body: data.requestBody, - mediaType: "application/json", - errors: { - 422: "Validation Error", - }, - }) - } - - /** - * Update Password Me - * Update own password. - * @param data The data for the request. - * @param data.requestBody - * @returns Message Successful Response - * @throws ApiError - */ - public static updatePasswordMe( - data: UsersUpdatePasswordMeData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "PATCH", - url: "/api/v1/users/me/password", - body: data.requestBody, - mediaType: "application/json", - errors: { - 422: "Validation Error", - }, - }) - } - - /** - * Register User - * Create new user without the need to be logged in. - * @param data The data for the request. - * @param data.requestBody - * @returns UserPublic Successful Response - * @throws ApiError - */ - public static registerUser( - data: UsersRegisterUserData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "POST", - url: "/api/v1/users/signup", - body: data.requestBody, - mediaType: "application/json", - errors: { - 422: "Validation Error", - }, - }) - } - - /** - * Read User By Id - * Get a specific user by id. - * @param data The data for the request. - * @param data.userId - * @returns UserPublic Successful Response - * @throws ApiError - */ - public static readUserById( - data: UsersReadUserByIdData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "GET", - url: "/api/v1/users/{user_id}", - path: { - user_id: data.userId, - }, - errors: { - 422: "Validation Error", - }, - }) - } - - /** - * Update User - * Update a user. - * @param data The data for the request. - * @param data.userId - * @param data.requestBody - * @returns UserPublic Successful Response - * @throws ApiError - */ - public static updateUser( - data: UsersUpdateUserData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "PATCH", - url: "/api/v1/users/{user_id}", - path: { - user_id: data.userId, - }, - body: data.requestBody, - mediaType: "application/json", - errors: { - 422: "Validation Error", - }, - }) - } - - /** - * Delete User - * Delete a user. - * @param data The data for the request. - * @param data.userId - * @returns Message Successful Response - * @throws ApiError - */ - public static deleteUser( - data: UsersDeleteUserData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "DELETE", - url: "/api/v1/users/{user_id}", - path: { - user_id: data.userId, - }, - errors: { - 422: "Validation Error", - }, - }) - } + /** + * Read Users + * Retrieve users. + * @param data The data for the request. + * @param data.skip + * @param data.limit + * @returns UsersPublic Successful Response + * @throws ApiError + */ + public static readUsers(data: UsersReadUsersData = {}): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/api/v1/users/', + query: { + skip: data.skip, + limit: data.limit + }, + errors: { + 422: 'Validation Error' + } + }); + } + + /** + * Create User + * Create new user. + * @param data The data for the request. + * @param data.requestBody + * @returns UserPublic Successful Response + * @throws ApiError + */ + public static createUser(data: UsersCreateUserData): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v1/users/', + body: data.requestBody, + mediaType: 'application/json', + errors: { + 422: 'Validation Error' + } + }); + } + + /** + * Read User Me + * Get current user. + * @returns UserPublic Successful Response + * @throws ApiError + */ + public static readUserMe(): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/api/v1/users/me' + }); + } + + /** + * Delete User Me + * Delete own user. + * @returns Message Successful Response + * @throws ApiError + */ + public static deleteUserMe(): CancelablePromise { + return __request(OpenAPI, { + method: 'DELETE', + url: '/api/v1/users/me' + }); + } + + /** + * Update User Me + * Update own user. + * @param data The data for the request. + * @param data.requestBody + * @returns UserPublic Successful Response + * @throws ApiError + */ + public static updateUserMe(data: UsersUpdateUserMeData): CancelablePromise { + return __request(OpenAPI, { + method: 'PATCH', + url: '/api/v1/users/me', + body: data.requestBody, + mediaType: 'application/json', + errors: { + 422: 'Validation Error' + } + }); + } + + /** + * Update Password Me + * Update own password. + * @param data The data for the request. + * @param data.requestBody + * @returns Message Successful Response + * @throws ApiError + */ + public static updatePasswordMe(data: UsersUpdatePasswordMeData): CancelablePromise { + return __request(OpenAPI, { + method: 'PATCH', + url: '/api/v1/users/me/password', + body: data.requestBody, + mediaType: 'application/json', + errors: { + 422: 'Validation Error' + } + }); + } + + /** + * Register User + * Create new user without the need to be logged in. + * @param data The data for the request. + * @param data.requestBody + * @returns UserPublic Successful Response + * @throws ApiError + */ + public static registerUser(data: UsersRegisterUserData): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v1/users/signup', + body: data.requestBody, + mediaType: 'application/json', + errors: { + 422: 'Validation Error' + } + }); + } + + /** + * Read User By Id + * Get a specific user by id. + * @param data The data for the request. + * @param data.userId + * @returns UserPublic Successful Response + * @throws ApiError + */ + public static readUserById(data: UsersReadUserByIdData): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/api/v1/users/{user_id}', + path: { + user_id: data.userId + }, + errors: { + 422: 'Validation Error' + } + }); + } + + /** + * Update User + * Update a user. + * @param data The data for the request. + * @param data.userId + * @param data.requestBody + * @returns UserPublic Successful Response + * @throws ApiError + */ + public static updateUser(data: UsersUpdateUserData): CancelablePromise { + return __request(OpenAPI, { + method: 'PATCH', + url: '/api/v1/users/{user_id}', + path: { + user_id: data.userId + }, + body: data.requestBody, + mediaType: 'application/json', + errors: { + 422: 'Validation Error' + } + }); + } + + /** + * Delete User + * Delete a user. + * @param data The data for the request. + * @param data.userId + * @returns Message Successful Response + * @throws ApiError + */ + public static deleteUser(data: UsersDeleteUserData): CancelablePromise { + return __request(OpenAPI, { + method: 'DELETE', + url: '/api/v1/users/{user_id}', + path: { + user_id: data.userId + }, + errors: { + 422: 'Validation Error' + } + }); + } } export class UtilsService { - /** - * Test Email - * Test emails. - * @param data The data for the request. - * @param data.emailTo - * @returns Message Successful Response - * @throws ApiError - */ - public static testEmail( - data: UtilsTestEmailData, - ): CancelablePromise { - return __request(OpenAPI, { - method: "POST", - url: "/api/v1/utils/test-email/", - query: { - email_to: data.emailTo, - }, - errors: { - 422: "Validation Error", - }, - }) - } - - /** - * Health Check - * @returns boolean Successful Response - * @throws ApiError - */ - public static healthCheck(): CancelablePromise { - return __request(OpenAPI, { - method: "GET", - url: "/api/v1/utils/health-check/", - }) - } -} + /** + * Test Email + * Test emails. + * @param data The data for the request. + * @param data.emailTo + * @returns Message Successful Response + * @throws ApiError + */ + public static testEmail(data: UtilsTestEmailData): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v1/utils/test-email/', + query: { + email_to: data.emailTo + }, + errors: { + 422: 'Validation Error' + } + }); + } + + /** + * Health Check + * @returns boolean Successful Response + * @throws ApiError + */ + public static healthCheck(): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/api/v1/utils/health-check/' + }); + } +} \ No newline at end of file diff --git a/frontend/src/client/types.gen.ts b/frontend/src/client/types.gen.ts index 67d4abd286..e5cf34c34c 100644 --- a/frontend/src/client/types.gen.ts +++ b/frontend/src/client/types.gen.ts @@ -1,234 +1,234 @@ // This file is auto-generated by @hey-api/openapi-ts export type Body_login_login_access_token = { - grant_type?: string | null - username: string - password: string - scope?: string - client_id?: string | null - client_secret?: string | null -} + grant_type?: (string | null); + username: string; + password: string; + scope?: string; + client_id?: (string | null); + client_secret?: (string | null); +}; export type HTTPValidationError = { - detail?: Array -} + detail?: Array; +}; export type ItemCreate = { - title: string - description?: string | null -} + title: string; + description?: (string | null); +}; export type ItemPublic = { - title: string - description?: string | null - id: string - owner_id: string -} + title: string; + description?: (string | null); + id: string; + owner_id: string; +}; export type ItemsPublic = { - data: Array - count: number -} + data: Array; + count: number; +}; export type ItemUpdate = { - title?: string | null - description?: string | null -} + title?: (string | null); + description?: (string | null); +}; export type Message = { - message: string -} + message: string; +}; export type NewPassword = { - token: string - new_password: string -} + token: string; + new_password: string; +}; export type PrivateUserCreate = { - email: string - password: string - full_name: string - is_verified?: boolean -} + email: string; + password: string; + full_name: string; + is_verified?: boolean; +}; export type Token = { - access_token: string - token_type?: string -} + access_token: string; + token_type?: string; +}; export type UpdatePassword = { - current_password: string - new_password: string -} + current_password: string; + new_password: string; +}; export type UserCreate = { - email: string - is_active?: boolean - is_superuser?: boolean - full_name?: string | null - password: string -} + email: string; + is_active?: boolean; + is_superuser?: boolean; + full_name?: (string | null); + password: string; +}; export type UserPublic = { - email: string - is_active?: boolean - is_superuser?: boolean - full_name?: string | null - id: string -} + email: string; + is_active?: boolean; + is_superuser?: boolean; + full_name?: (string | null); + id: string; +}; export type UserRegister = { - email: string - password: string - full_name?: string | null -} + email: string; + password: string; + full_name?: (string | null); +}; export type UsersPublic = { - data: Array - count: number -} + data: Array; + count: number; +}; export type UserUpdate = { - email?: string | null - is_active?: boolean - is_superuser?: boolean - full_name?: string | null - password?: string | null -} + email?: (string | null); + is_active?: boolean; + is_superuser?: boolean; + full_name?: (string | null); + password?: (string | null); +}; export type UserUpdateMe = { - full_name?: string | null - email?: string | null -} + full_name?: (string | null); + email?: (string | null); +}; export type ValidationError = { - loc: Array - msg: string - type: string -} + loc: Array<(string | number)>; + msg: string; + type: string; +}; export type ItemsReadItemsData = { - limit?: number - skip?: number -} + limit?: number; + skip?: number; +}; -export type ItemsReadItemsResponse = ItemsPublic +export type ItemsReadItemsResponse = (ItemsPublic); export type ItemsCreateItemData = { - requestBody: ItemCreate -} + requestBody: ItemCreate; +}; -export type ItemsCreateItemResponse = ItemPublic +export type ItemsCreateItemResponse = (ItemPublic); export type ItemsReadItemData = { - id: string -} + id: string; +}; -export type ItemsReadItemResponse = ItemPublic +export type ItemsReadItemResponse = (ItemPublic); export type ItemsUpdateItemData = { - id: string - requestBody: ItemUpdate -} + id: string; + requestBody: ItemUpdate; +}; -export type ItemsUpdateItemResponse = ItemPublic +export type ItemsUpdateItemResponse = (ItemPublic); export type ItemsDeleteItemData = { - id: string -} + id: string; +}; -export type ItemsDeleteItemResponse = Message +export type ItemsDeleteItemResponse = (Message); export type LoginLoginAccessTokenData = { - formData: Body_login_login_access_token -} + formData: Body_login_login_access_token; +}; -export type LoginLoginAccessTokenResponse = Token +export type LoginLoginAccessTokenResponse = (Token); -export type LoginTestTokenResponse = UserPublic +export type LoginTestTokenResponse = (UserPublic); export type LoginRecoverPasswordData = { - email: string -} + email: string; +}; -export type LoginRecoverPasswordResponse = Message +export type LoginRecoverPasswordResponse = (Message); export type LoginResetPasswordData = { - requestBody: NewPassword -} + requestBody: NewPassword; +}; -export type LoginResetPasswordResponse = Message +export type LoginResetPasswordResponse = (Message); export type LoginRecoverPasswordHtmlContentData = { - email: string -} + email: string; +}; -export type LoginRecoverPasswordHtmlContentResponse = string +export type LoginRecoverPasswordHtmlContentResponse = (string); export type PrivateCreateUserData = { - requestBody: PrivateUserCreate -} + requestBody: PrivateUserCreate; +}; -export type PrivateCreateUserResponse = UserPublic +export type PrivateCreateUserResponse = (UserPublic); export type UsersReadUsersData = { - limit?: number - skip?: number -} + limit?: number; + skip?: number; +}; -export type UsersReadUsersResponse = UsersPublic +export type UsersReadUsersResponse = (UsersPublic); export type UsersCreateUserData = { - requestBody: UserCreate -} + requestBody: UserCreate; +}; -export type UsersCreateUserResponse = UserPublic +export type UsersCreateUserResponse = (UserPublic); -export type UsersReadUserMeResponse = UserPublic +export type UsersReadUserMeResponse = (UserPublic); -export type UsersDeleteUserMeResponse = Message +export type UsersDeleteUserMeResponse = (Message); export type UsersUpdateUserMeData = { - requestBody: UserUpdateMe -} + requestBody: UserUpdateMe; +}; -export type UsersUpdateUserMeResponse = UserPublic +export type UsersUpdateUserMeResponse = (UserPublic); export type UsersUpdatePasswordMeData = { - requestBody: UpdatePassword -} + requestBody: UpdatePassword; +}; -export type UsersUpdatePasswordMeResponse = Message +export type UsersUpdatePasswordMeResponse = (Message); export type UsersRegisterUserData = { - requestBody: UserRegister -} + requestBody: UserRegister; +}; -export type UsersRegisterUserResponse = UserPublic +export type UsersRegisterUserResponse = (UserPublic); export type UsersReadUserByIdData = { - userId: string -} + userId: string; +}; -export type UsersReadUserByIdResponse = UserPublic +export type UsersReadUserByIdResponse = (UserPublic); export type UsersUpdateUserData = { - requestBody: UserUpdate - userId: string -} + requestBody: UserUpdate; + userId: string; +}; -export type UsersUpdateUserResponse = UserPublic +export type UsersUpdateUserResponse = (UserPublic); export type UsersDeleteUserData = { - userId: string -} + userId: string; +}; -export type UsersDeleteUserResponse = Message +export type UsersDeleteUserResponse = (Message); export type UtilsTestEmailData = { - emailTo: string -} + emailTo: string; +}; -export type UtilsTestEmailResponse = Message +export type UtilsTestEmailResponse = (Message); -export type UtilsHealthCheckResponse = boolean +export type UtilsHealthCheckResponse = (boolean); \ No newline at end of file diff --git a/frontend/src/components/Admin/AddUser.tsx b/frontend/src/components/Admin/AddUser.tsx index db353a3a2c..2276b43c24 100644 --- a/frontend/src/components/Admin/AddUser.tsx +++ b/frontend/src/components/Admin/AddUser.tsx @@ -1,10 +1,3 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query" -import { Controller, type SubmitHandler, useForm } from "react-hook-form" - -import { type UserCreate, UsersService } from "@/client" -import type { ApiError } from "@/client/core/ApiError" -import useCustomToast from "@/hooks/useCustomToast" -import { emailPattern, handleError } from "@/utils" import { Button, DialogActionTrigger, @@ -14,8 +7,14 @@ import { Text, VStack, } from "@chakra-ui/react" +import { useMutation, useQueryClient } from "@tanstack/react-query" import { useState } from "react" +import { Controller, type SubmitHandler, useForm } from "react-hook-form" import { FaPlus } from "react-icons/fa" +import { type UserCreate, UsersService } from "@/client" +import type { ApiError } from "@/client/core/ApiError" +import useCustomToast from "@/hooks/useCustomToast" +import { emailPattern, handleError } from "@/utils" import { Checkbox } from "../ui/checkbox" import { DialogBody, @@ -106,7 +105,6 @@ const AddUser = () => { label="Email" > { label="Full Name" > { label="Set Password" > { label="Confirm Password" > diff --git a/frontend/src/components/Admin/EditUser.tsx b/frontend/src/components/Admin/EditUser.tsx index 6195fcce88..545f334a51 100644 --- a/frontend/src/components/Admin/EditUser.tsx +++ b/frontend/src/components/Admin/EditUser.tsx @@ -1,6 +1,3 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query" -import { Controller, type SubmitHandler, useForm } from "react-hook-form" - import { Button, DialogActionTrigger, @@ -11,10 +8,12 @@ import { Text, VStack, } from "@chakra-ui/react" +import { useMutation, useQueryClient } from "@tanstack/react-query" import { useState } from "react" +import { Controller, type SubmitHandler, useForm } from "react-hook-form" import { FaExchangeAlt } from "react-icons/fa" -import { type UserPublic, type UserUpdate, UsersService } from "@/client" +import { type UserPublic, UsersService, type UserUpdate } from "@/client" import type { ApiError } from "@/client/core/ApiError" import useCustomToast from "@/hooks/useCustomToast" import { emailPattern, handleError } from "@/utils" @@ -105,7 +104,6 @@ const EditUser = ({ user }: EditUserProps) => { label="Email" > { label="Full Name" > { label="Set Password" > { label="Confirm Password" > value === getValues().password || diff --git a/frontend/src/components/Common/ItemActionsMenu.tsx b/frontend/src/components/Common/ItemActionsMenu.tsx index a647600176..18e424fdd4 100644 --- a/frontend/src/components/Common/ItemActionsMenu.tsx +++ b/frontend/src/components/Common/ItemActionsMenu.tsx @@ -1,10 +1,9 @@ import { IconButton } from "@chakra-ui/react" import { BsThreeDotsVertical } from "react-icons/bs" -import { MenuContent, MenuRoot, MenuTrigger } from "../ui/menu" - import type { ItemPublic } from "@/client" import DeleteItem from "../Items/DeleteItem" import EditItem from "../Items/EditItem" +import { MenuContent, MenuRoot, MenuTrigger } from "../ui/menu" interface ItemActionsMenuProps { item: ItemPublic diff --git a/frontend/src/components/Common/NotFound.tsx b/frontend/src/components/Common/NotFound.tsx index 2a00f2b388..9e4f18528e 100644 --- a/frontend/src/components/Common/NotFound.tsx +++ b/frontend/src/components/Common/NotFound.tsx @@ -3,54 +3,41 @@ import { Link } from "@tanstack/react-router" const NotFound = () => { return ( - <> - - - - - 404 - - - Oops! - - + + + + + 404 + + + Oops! + - - - The page you are looking for was not found. - -
- - - -
- + + + The page you are looking for was not found. + +
+ + + +
+
) } diff --git a/frontend/src/components/Common/UserActionsMenu.tsx b/frontend/src/components/Common/UserActionsMenu.tsx index 286247f250..882ecb4dd8 100644 --- a/frontend/src/components/Common/UserActionsMenu.tsx +++ b/frontend/src/components/Common/UserActionsMenu.tsx @@ -1,10 +1,9 @@ import { IconButton } from "@chakra-ui/react" import { BsThreeDotsVertical } from "react-icons/bs" -import { MenuContent, MenuRoot, MenuTrigger } from "../ui/menu" - import type { UserPublic } from "@/client" import DeleteUser from "../Admin/DeleteUser" import EditUser from "../Admin/EditUser" +import { MenuContent, MenuRoot, MenuTrigger } from "../ui/menu" interface UserActionsMenuProps { user: UserPublic diff --git a/frontend/src/components/Items/AddItem.tsx b/frontend/src/components/Items/AddItem.tsx index e7b3104d4f..5a377b952a 100644 --- a/frontend/src/components/Items/AddItem.tsx +++ b/frontend/src/components/Items/AddItem.tsx @@ -1,6 +1,3 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query" -import { type SubmitHandler, useForm } from "react-hook-form" - import { Button, DialogActionTrigger, @@ -9,7 +6,9 @@ import { Text, VStack, } from "@chakra-ui/react" +import { useMutation, useQueryClient } from "@tanstack/react-query" import { useState } from "react" +import { type SubmitHandler, useForm } from "react-hook-form" import { FaPlus } from "react-icons/fa" import { type ItemCreate, ItemsService } from "@/client" @@ -93,7 +92,6 @@ const AddItem = () => { label="Title" > { label="Description" > { label="Title" > { label="Description" > { const { theme, setTheme } = useTheme() return ( - <> - - - Appearance - + + + Appearance + - setTheme(e.value ?? "system")} - value={theme} - colorPalette="teal" - > - - System - Light Mode - Dark Mode - - - - + setTheme(e.value ?? "system")} + value={theme} + colorPalette="teal" + > + + System + Light Mode + Dark Mode + + + ) } export default Appearance diff --git a/frontend/src/components/UserSettings/ChangePassword.tsx b/frontend/src/components/UserSettings/ChangePassword.tsx index 24e388c254..8cd0b541b4 100644 --- a/frontend/src/components/UserSettings/ChangePassword.tsx +++ b/frontend/src/components/UserSettings/ChangePassword.tsx @@ -42,46 +42,39 @@ const ChangePassword = () => { } return ( - <> - - - Change Password - - - - } - {...register("current_password", passwordRules())} - placeholder="Current Password" - errors={errors} - /> - } - {...register("new_password", passwordRules())} - placeholder="New Password" - errors={errors} - /> - } - {...register("confirm_password", confirmPasswordRules(getValues))} - placeholder="Confirm Password" - errors={errors} - /> - - - - - + + + Change Password + + + + } + {...register("current_password", passwordRules())} + placeholder="Current Password" + errors={errors} + /> + } + {...register("new_password", passwordRules())} + placeholder="New Password" + errors={errors} + /> + } + {...register("confirm_password", confirmPasswordRules(getValues))} + placeholder="Confirm Password" + errors={errors} + /> + + + + ) } export default ChangePassword diff --git a/frontend/src/components/UserSettings/DeleteConfirmation.tsx b/frontend/src/components/UserSettings/DeleteConfirmation.tsx index 67455d06bc..3885a570d7 100644 --- a/frontend/src/components/UserSettings/DeleteConfirmation.tsx +++ b/frontend/src/components/UserSettings/DeleteConfirmation.tsx @@ -49,60 +49,58 @@ const DeleteConfirmation = () => { } return ( - <> - setIsOpen(open)} - > - - - + setIsOpen(open)} + > + + + - -
- - - Confirmation Required - - - - All your account data will be{" "} - permanently deleted. If you are sure, please - click "Confirm" to proceed. This action cannot - be undone. - - + + + + + Confirmation Required + + + + All your account data will be{" "} + permanently deleted. If you are sure, please + click "Confirm" to proceed. This action cannot be + undone. + + - - - - - + + + - - - - -
- + + + + + + +
) } diff --git a/frontend/src/components/UserSettings/UserInformation.tsx b/frontend/src/components/UserSettings/UserInformation.tsx index a7b7c83cc3..c9e64693c1 100644 --- a/frontend/src/components/UserSettings/UserInformation.tsx +++ b/frontend/src/components/UserSettings/UserInformation.tsx @@ -14,8 +14,8 @@ import { type SubmitHandler, useForm } from "react-hook-form" import { type ApiError, type UserPublic, - type UserUpdateMe, UsersService, + type UserUpdateMe, } from "@/client" import useAuth from "@/hooks/useAuth" import useCustomToast from "@/hooks/useCustomToast" @@ -70,80 +70,78 @@ const UserInformation = () => { } return ( - <> - - - User Information - - + + User Information + + + + {editMode ? ( + + ) : ( + + {currentUser?.full_name || "N/A"} + + )} + + - - {editMode ? ( - - ) : ( - - {currentUser?.full_name || "N/A"} - - )} - - + ) : ( + + {currentUser?.email} + + )} + + + + {editMode && ( - {editMode && ( - - )} - - - - + )} +
+ + ) } diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 05307729f8..77f648090d 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -4,13 +4,12 @@ import { QueryClient, QueryClientProvider, } from "@tanstack/react-query" -import { RouterProvider, createRouter } from "@tanstack/react-router" +import { createRouter, RouterProvider } from "@tanstack/react-router" import { StrictMode } from "react" import ReactDOM from "react-dom/client" -import { routeTree } from "./routeTree.gen" - import { ApiError, OpenAPI } from "./client" import { CustomProvider } from "./components/ui/provider" +import { routeTree } from "./routeTree.gen" OpenAPI.BASE = import.meta.env.VITE_API_URL OpenAPI.TOKEN = async () => { diff --git a/frontend/src/routes/__root.tsx b/frontend/src/routes/__root.tsx index 5059200ec4..ab74696101 100644 --- a/frontend/src/routes/__root.tsx +++ b/frontend/src/routes/__root.tsx @@ -1,4 +1,4 @@ -import { Outlet, createRootRoute } from "@tanstack/react-router" +import { createRootRoute, Outlet } from "@tanstack/react-router" import React, { Suspense } from "react" import NotFound from "@/components/Common/NotFound" diff --git a/frontend/src/routes/_layout.tsx b/frontend/src/routes/_layout.tsx index c0634a74f3..2514324271 100644 --- a/frontend/src/routes/_layout.tsx +++ b/frontend/src/routes/_layout.tsx @@ -1,5 +1,5 @@ import { Flex } from "@chakra-ui/react" -import { Outlet, createFileRoute, redirect } from "@tanstack/react-router" +import { createFileRoute, Outlet, redirect } from "@tanstack/react-router" import Navbar from "@/components/Common/Navbar" import Sidebar from "@/components/Common/Sidebar" diff --git a/frontend/src/routes/_layout/index.tsx b/frontend/src/routes/_layout/index.tsx index 0313854054..66e32e0b30 100644 --- a/frontend/src/routes/_layout/index.tsx +++ b/frontend/src/routes/_layout/index.tsx @@ -11,15 +11,13 @@ function Dashboard() { const { user: currentUser } = useAuth() return ( - <> - - - - Hi, {currentUser?.full_name || currentUser?.email} 👋🏼 - - Welcome back, nice to see you again! - - - + + + + Hi, {currentUser?.full_name || currentUser?.email} 👋🏼 + + Welcome back, nice to see you again! + + ) } diff --git a/frontend/src/routes/login.tsx b/frontend/src/routes/login.tsx index 279aefd9af..2e0539d9d9 100644 --- a/frontend/src/routes/login.tsx +++ b/frontend/src/routes/login.tsx @@ -1,7 +1,7 @@ import { Container, Image, Input, Text } from "@chakra-ui/react" import { - Link as RouterLink, createFileRoute, + Link as RouterLink, redirect, } from "@tanstack/react-router" import { type SubmitHandler, useForm } from "react-hook-form" @@ -55,61 +55,58 @@ function Login() { } return ( - <> - + FastAPI logo + - FastAPI logo - - }> - - - - } - {...register("password", passwordRules())} - placeholder="Password" - errors={errors} - /> - - Forgot Password? + }> + + + + } + {...register("password", passwordRules())} + placeholder="Password" + errors={errors} + /> + + Forgot Password? + + + + Don't have an account?{" "} + + Sign Up - - - Don't have an account?{" "} - - Sign Up - - - - + + ) } diff --git a/frontend/src/routes/recover-password.tsx b/frontend/src/routes/recover-password.tsx index afc1596888..084fbdd73a 100644 --- a/frontend/src/routes/recover-password.tsx +++ b/frontend/src/routes/recover-password.tsx @@ -77,7 +77,6 @@ function RecoverPassword() { }> - - + + FastAPI logo + - FastAPI logo - - }> - - - + }> + + + - - }> - - - - } - {...register("password", passwordRules())} - placeholder="Password" - errors={errors} - /> - } - {...register("confirm_password", confirmPasswordRules(getValues))} - placeholder="Confirm Password" - errors={errors} - /> - - - Already have an account?{" "} - - Log In - - - - - + + }> + + + + } + {...register("password", passwordRules())} + placeholder="Password" + errors={errors} + /> + } + {...register("confirm_password", confirmPasswordRules(getValues))} + placeholder="Confirm Password" + errors={errors} + /> + + + Already have an account?{" "} + + Log In + + + +
) } diff --git a/frontend/tests/login.spec.ts b/frontend/tests/login.spec.ts index e482934916..b639fd7998 100644 --- a/frontend/tests/login.spec.ts +++ b/frontend/tests/login.spec.ts @@ -1,4 +1,4 @@ -import { type Page, expect, test } from "@playwright/test" +import { expect, type Page, test } from "@playwright/test" import { firstSuperuser, firstSuperuserPassword } from "./config.ts" import { randomPassword } from "./utils/random.ts" diff --git a/frontend/tests/sign-up.spec.ts b/frontend/tests/sign-up.spec.ts index e4e31c368d..750edb1830 100644 --- a/frontend/tests/sign-up.spec.ts +++ b/frontend/tests/sign-up.spec.ts @@ -1,4 +1,4 @@ -import { type Page, expect, test } from "@playwright/test" +import { expect, type Page, test } from "@playwright/test" import { randomEmail, randomPassword } from "./utils/random" diff --git a/frontend/tests/utils/mailcatcher.ts b/frontend/tests/utils/mailcatcher.ts index 049792d0c8..8e6f78b2c8 100644 --- a/frontend/tests/utils/mailcatcher.ts +++ b/frontend/tests/utils/mailcatcher.ts @@ -9,7 +9,10 @@ type Email = { async function findEmail({ request, filter, -}: { request: APIRequestContext; filter?: (email: Email) => boolean }) { +}: { + request: APIRequestContext + filter?: (email: Email) => boolean +}) { const response = await request.get(`${process.env.MAILCATCHER_HOST}/messages`) let emails = await response.json() diff --git a/frontend/tests/utils/user.ts b/frontend/tests/utils/user.ts index 6d53cf0ff5..4e31fe0ff7 100644 --- a/frontend/tests/utils/user.ts +++ b/frontend/tests/utils/user.ts @@ -1,4 +1,4 @@ -import { type Page, expect } from "@playwright/test" +import { expect, type Page } from "@playwright/test" export async function signUpNewUser( page: Page, diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index b1d5b6ec07..997b7dd7fc 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,5 +1,5 @@ import path from "node:path" -import { tanstackRouter } from '@tanstack/router-plugin/vite' +import { tanstackRouter } from "@tanstack/router-plugin/vite" import react from "@vitejs/plugin-react-swc" import { defineConfig } from "vite" @@ -15,5 +15,6 @@ export default defineConfig({ target: "react", autoCodeSplitting: true, }), - react()], + react(), + ], }) diff --git a/scripts/generate-client.sh b/scripts/generate-client.sh index 1e76864d42..c4f85df84b 100644 --- a/scripts/generate-client.sh +++ b/scripts/generate-client.sh @@ -8,5 +8,4 @@ python -c "import app.main; import json; print(json.dumps(app.main.app.openapi() cd .. mv openapi.json frontend/ cd frontend -npm run generate-client -npx biome format --write ./src/client +npm run generate-client \ No newline at end of file