From 6db5f74eb7338b8c5ddea5a2db85519445ebe906 Mon Sep 17 00:00:00 2001 From: Danil Kostromin Date: Thu, 22 Feb 2024 10:21:42 +0200 Subject: [PATCH] feat(performance): add performance form This adds performance check form to check response time for backend to catch regression Signed-off-by: Danil Kostromin --- apps/bublik/src/app/router.tsx | 2 + .../src/pages/performance-page/index.ts | 4 + .../performance-page/performance.page.tsx | 16 ++ apps/bublik/vite.config.ts | 7 + .../features/performance-check/.babelrc | 12 + .../features/performance-check/.eslintrc.json | 18 ++ .../features/performance-check/README.md | 7 + .../features/performance-check/project.json | 20 ++ .../features/performance-check/src/index.ts | 3 + .../performance-list.component.spec.tsx.snap | 47 ++++ .../lib/performance-list.component.spec.tsx | 17 ++ .../performance-list.component.stories.tsx | 87 ++++++ .../src/lib/performance-list.component.tsx | 253 ++++++++++++++++++ .../src/lib/performance-list.container.tsx | 24 ++ .../features/performance-check/tsconfig.json | 20 ++ .../performance-check/tsconfig.lib.json | 23 ++ .../performance-check/tsconfig.spec.json | 26 ++ .../features/performance-check/vite.config.ts | 29 ++ .../sidebar/src/lib/bottom-nav/bottom-nav.tsx | 6 + libs/services/bublik-api/src/lib/bublikAPI.ts | 1 + .../src/lib/endpoints/deploy-endpoints.ts | 6 +- libs/shared/types/src/index.ts | 1 + .../shared/types/src/lib/performance/index.ts | 14 + tsconfig.base.json | 5 +- 24 files changed, 646 insertions(+), 2 deletions(-) create mode 100644 apps/bublik/src/pages/performance-page/index.ts create mode 100644 apps/bublik/src/pages/performance-page/performance.page.tsx create mode 100644 libs/bublik/features/performance-check/.babelrc create mode 100644 libs/bublik/features/performance-check/.eslintrc.json create mode 100644 libs/bublik/features/performance-check/README.md create mode 100644 libs/bublik/features/performance-check/project.json create mode 100644 libs/bublik/features/performance-check/src/index.ts create mode 100644 libs/bublik/features/performance-check/src/lib/__snapshots__/performance-list.component.spec.tsx.snap create mode 100644 libs/bublik/features/performance-check/src/lib/performance-list.component.spec.tsx create mode 100644 libs/bublik/features/performance-check/src/lib/performance-list.component.stories.tsx create mode 100644 libs/bublik/features/performance-check/src/lib/performance-list.component.tsx create mode 100644 libs/bublik/features/performance-check/src/lib/performance-list.container.tsx create mode 100644 libs/bublik/features/performance-check/tsconfig.json create mode 100644 libs/bublik/features/performance-check/tsconfig.lib.json create mode 100644 libs/bublik/features/performance-check/tsconfig.spec.json create mode 100644 libs/bublik/features/performance-check/vite.config.ts create mode 100644 libs/shared/types/src/lib/performance/index.ts diff --git a/apps/bublik/src/app/router.tsx b/apps/bublik/src/app/router.tsx index 5a50a03b..73387d7c 100644 --- a/apps/bublik/src/app/router.tsx +++ b/apps/bublik/src/app/router.tsx @@ -39,6 +39,7 @@ import { } from '../pages'; import { Layout } from './layout'; import { RedirectToLogPage } from './redirects'; +import { PerformancePage } from '../pages/performance-page'; const router = createBrowserRouter( [ @@ -102,6 +103,7 @@ const router = createBrowserRouter( element: , children: [ { path: 'import', element: }, + { path: 'performance', element: }, { path: 'flower', element: }, { path: 'users', element: }, { element: } diff --git a/apps/bublik/src/pages/performance-page/index.ts b/apps/bublik/src/pages/performance-page/index.ts new file mode 100644 index 00000000..5e0e1cc3 --- /dev/null +++ b/apps/bublik/src/pages/performance-page/index.ts @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* SPDX-FileCopyrightText: 2024 OKTET LTD */ + +export * from './performance.page'; diff --git a/apps/bublik/src/pages/performance-page/performance.page.tsx b/apps/bublik/src/pages/performance-page/performance.page.tsx new file mode 100644 index 00000000..064215c2 --- /dev/null +++ b/apps/bublik/src/pages/performance-page/performance.page.tsx @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* SPDX-FileCopyrightText: 2024 OKTET LTD */ + +import { PerformanceListContainer } from '@/bublik/features/performance-check'; + +export const PerformancePage = () => { + return ( +
+
+
+ +
+
+
+ ); +}; diff --git a/apps/bublik/vite.config.ts b/apps/bublik/vite.config.ts index 070d75a2..2ddd9607 100644 --- a/apps/bublik/vite.config.ts +++ b/apps/bublik/vite.config.ts @@ -35,6 +35,7 @@ export default defineConfig(async ({ mode }) => { // Derived const API_PATHNAME = `${URL_PREFIX}/api/v2`; const AUTH_PATHNAME = `${URL_PREFIX}/auth`; + const PERFORMANCE_CHECK_PATHNAME = `${URL_PREFIX}/performance_check`; const EXTERNAL_PATHNAME = `${URL_PREFIX}/external`; return { @@ -55,6 +56,12 @@ export default defineConfig(async ({ mode }) => { secure: false, configure: createRequestLogger('AUTH') }, + [PERFORMANCE_CHECK_PATHNAME]: { + target: DJANGO_TARGET, + changeOrigin: true, + secure: false, + configure: createRequestLogger('PERFORMANCE') + }, [EXTERNAL_PATHNAME]: { target: LOGS_TARGET, changeOrigin: true, diff --git a/libs/bublik/features/performance-check/.babelrc b/libs/bublik/features/performance-check/.babelrc new file mode 100644 index 00000000..abff0913 --- /dev/null +++ b/libs/bublik/features/performance-check/.babelrc @@ -0,0 +1,12 @@ +{ + "presets": [ + [ + "@nx/react/babel", + { + "runtime": "automatic", + "useBuiltIns": "usage" + } + ] + ], + "plugins": [] +} diff --git a/libs/bublik/features/performance-check/.eslintrc.json b/libs/bublik/features/performance-check/.eslintrc.json new file mode 100644 index 00000000..dae03d3c --- /dev/null +++ b/libs/bublik/features/performance-check/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["plugin:@nx/react", "../../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/libs/bublik/features/performance-check/README.md b/libs/bublik/features/performance-check/README.md new file mode 100644 index 00000000..78f516c5 --- /dev/null +++ b/libs/bublik/features/performance-check/README.md @@ -0,0 +1,7 @@ +# performance-check + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test performance-check` to execute the unit tests via [Vitest](https://vitest.dev/). diff --git a/libs/bublik/features/performance-check/project.json b/libs/bublik/features/performance-check/project.json new file mode 100644 index 00000000..beb9dba4 --- /dev/null +++ b/libs/bublik/features/performance-check/project.json @@ -0,0 +1,20 @@ +{ + "name": "performance-check", + "$schema": "../../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/bublik/features/performance-check/src", + "projectType": "library", + "tags": [], + "targets": { + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"] + }, + "test": { + "executor": "@nx/vite:test", + "outputs": ["{options.reportsDirectory}"], + "options": { + "reportsDirectory": "../../../../coverage/libs/bublik/features/performance-check" + } + } + } +} diff --git a/libs/bublik/features/performance-check/src/index.ts b/libs/bublik/features/performance-check/src/index.ts new file mode 100644 index 00000000..723e8cb0 --- /dev/null +++ b/libs/bublik/features/performance-check/src/index.ts @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* SPDX-FileCopyrightText: 2024 OKTET LTD */ +export * from './lib/performance-list.container'; diff --git a/libs/bublik/features/performance-check/src/lib/__snapshots__/performance-list.component.spec.tsx.snap b/libs/bublik/features/performance-check/src/lib/__snapshots__/performance-list.component.spec.tsx.snap new file mode 100644 index 00000000..532378e5 --- /dev/null +++ b/libs/bublik/features/performance-check/src/lib/__snapshots__/performance-list.component.spec.tsx.snap @@ -0,0 +1,47 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[` > should match snapshot 1`] = ` + +
+

+ Health Check +

+ + +
+
+`; diff --git a/libs/bublik/features/performance-check/src/lib/performance-list.component.spec.tsx b/libs/bublik/features/performance-check/src/lib/performance-list.component.spec.tsx new file mode 100644 index 00000000..7f9607fd --- /dev/null +++ b/libs/bublik/features/performance-check/src/lib/performance-list.component.spec.tsx @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* SPDX-FileCopyrightText: 2024 OKTET LTD */ +import { describe, expect, it } from 'vitest'; +import { render } from '@testing-library/react'; +import { PerformanceList } from './performance-list.component'; + +describe('', () => { + it('should match snapshot', () => { + const { asFragment } = render( + + ); + + expect(asFragment()).toMatchSnapshot(); + }); +}); diff --git a/libs/bublik/features/performance-check/src/lib/performance-list.component.stories.tsx b/libs/bublik/features/performance-check/src/lib/performance-list.component.stories.tsx new file mode 100644 index 00000000..c0a0fcec --- /dev/null +++ b/libs/bublik/features/performance-check/src/lib/performance-list.component.stories.tsx @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* SPDX-FileCopyrightText: 2024 OKTET LTD */ +import { Meta, StoryFn, StoryObj } from '@storybook/react'; + +import { withBackground } from '@/shared/tailwind-ui'; + +import { + PerformanceList, + PerformanceListEmpty, + PerformanceListError, + PerformanceListLoading +} from './performance-list.component'; + +const meta = { + title: 'performance/Performance List', + decorators: [ + withBackground, + (story) =>
{story()}
+ ] +} satisfies Meta; +export default meta; + +type Story = StoryObj; + +const Template: StoryFn = (args) => ( + +); + +export const Primary = { + render: Template, + args: { + urls: [ + { + label: 'Google', + url: 'https://www.google.com/', + timeout: 1 + }, + { + label: 'GitHub', + url: 'https://github.com/', + timeout: 10 + }, + { + label: 'Amazon', + url: 'https://www.amazon.com/', + timeout: 10 + }, + { + label: 'Facebook', + url: 'https://www.facebook.com/', + timeout: 10 + }, + { + label: 'Twitter', + url: 'https://twitter.com/', + timeout: 10 + }, + { + label: 'LinkedIn', + url: 'https://www.linkedin.com/', + timeout: 10 + }, + { + label: 'Wikipedia', + url: 'https://www.wikipedia.org/', + timeout: 10 + }, + { + label: 'Netflix', + url: 'https://www.netflix.com/', + timeout: 10 + } + ] + } +} satisfies Story; + +export const Loading = { + render: () => +} satisfies Story; + +export const Empty = { + render: () => +} satisfies Story; + +export const Error = { + render: () => +} satisfies Story; diff --git a/libs/bublik/features/performance-check/src/lib/performance-list.component.tsx b/libs/bublik/features/performance-check/src/lib/performance-list.component.tsx new file mode 100644 index 00000000..44356961 --- /dev/null +++ b/libs/bublik/features/performance-check/src/lib/performance-list.component.tsx @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* SPDX-FileCopyrightText: 2024 OKTET LTD */ +import { + forwardRef, + useCallback, + useImperativeHandle, + useRef, + useState +} from 'react'; + +import { PerformanceResponse } from '@/shared/types'; +import { ButtonTw, cn, Icon, Skeleton } from '@/shared/tailwind-ui'; +import { useMount } from '@/shared/hooks'; +import { getErrorMessage } from '@/services/bublik-api'; + +function PerformanceListEmpty() { + return ( +
+

Health Check

+
+
+
+ +

+ No results +

+

No URLs provided

+
+
+
+
+ ); +} + +interface PerformanceListErrorProps { + error: unknown; +} + +function PerformanceListError(props: PerformanceListErrorProps) { + const { title, description } = getErrorMessage(props.error); + + return ( +
+

Health Check

+
+
+ +

{title}

+

{description}

+
+
+
+ ); +} + +function PerformanceListLoading() { + return ( +
+

Health Check

+
    + {Array.from({ length: 10 }).map((_, idx) => ( + + ))} +
+ Check +
+ ); +} + +interface PerformanceListProps { + urls: PerformanceResponse; +} + +function PerformanceList(props: PerformanceListProps) { + const refs = useRef>(new Map()); + const [isInProgress, setIsInProgress] = useState(false); + + async function checkURLs() { + setIsInProgress(true); + try { + const promises = Array.from(refs.current.values()).map((handle) => + handle.check() + ); + + await Promise.allSettled(promises); + } finally { + setIsInProgress(false); + } + } + + useMount(() => checkURLs()); + + return ( +
+

Health Check

+
    + {props.urls + .filter(({ url }) => Boolean(url)) + .map(({ label, url, timeout }) => ( + { + if (!handle) return; + + refs.current.set(handle.url, handle); + }} + /> + ))} +
+ + Check + +
+ ); +} + +type TestURLResultCommon = { responseTime: number }; +type TestURLSuccess = TestURLResultCommon; +type TestURLError = TestURLResultCommon; +type TestURLResult = TestURLSuccess | TestURLError; +type TestURLFetchStatus = 'passed' | 'failed' | 'idle' | 'loading'; + +interface TestUrlConfig { + url: string; + /* In seconds */ + timeout: number; + onError: (result: TestURLError) => void; + onSuccess: (result: TestURLSuccess) => void; +} + +async function testUrl(config: TestUrlConfig): Promise { + const { url, onSuccess, onError, timeout } = config; + const start = Date.now(); + try { + const result = await fetch(url, { + signal: AbortSignal.timeout(timeout * 1000) + }); + const responseTime = (Date.now() - start) / 1000; + const checkResult = { responseTime }; + + if (result.status !== 200) { + onError(checkResult); + return checkResult; + } + + onSuccess(checkResult); + return { responseTime }; + } catch (e) { + const responseTime = (Date.now() - start) / 1000; + const checkResult = { responseTime }; + onError(checkResult); + return checkResult; + } +} + +type CheckURLHandle = { + check: () => Promise; + url: string; +}; + +const INITIAL_STATE = { responseTime: undefined, status: 'idle' } as const; +const LOADING_STATE = { responseTime: undefined, status: 'loading' } as const; + +interface PerformanceListItemProps { + label: string; + url: string; + timeout: number; +} + +const PerformanceListItem = forwardRef< + CheckURLHandle, + PerformanceListItemProps +>(({ url, label, timeout }, ref) => { + const [fetchStatus, setFetchStatus] = useState<{ + status: TestURLFetchStatus; + responseTime: number | undefined; + }>(INITIAL_STATE); + + const checkURL = useCallback(async () => { + setFetchStatus(LOADING_STATE); + + await testUrl({ + url, + timeout, + onSuccess: ({ responseTime }) => + setFetchStatus({ responseTime, status: 'passed' }), + onError: ({ responseTime }) => + setFetchStatus({ responseTime, status: 'failed' }) + }); + }, [timeout, url]); + + useImperativeHandle(ref, () => ({ check: checkURL, url }), [checkURL, url]); + + const isLoading = fetchStatus.status === 'loading'; + const isPassed = fetchStatus.status === 'passed'; + const isFailed = fetchStatus.status === 'failed'; + + return ( +
  • + + {label} ({timeout}s) + + + {`${ + fetchStatus.responseTime ? fetchStatus.responseTime.toFixed(2) : '' + }${fetchStatus.responseTime ? 's' : ''}`} + {isLoading ? ( + + ) : null} + +
    +
  • + ); +}); + +export { + PerformanceListEmpty, + PerformanceListLoading, + PerformanceListError, + PerformanceList +}; diff --git a/libs/bublik/features/performance-check/src/lib/performance-list.container.tsx b/libs/bublik/features/performance-check/src/lib/performance-list.container.tsx new file mode 100644 index 00000000..0246696b --- /dev/null +++ b/libs/bublik/features/performance-check/src/lib/performance-list.container.tsx @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* SPDX-FileCopyrightText: 2024 OKTET LTD */ +import { useGetPerformanceTimeoutsQuery } from '@/services/bublik-api'; + +import { + PerformanceList, + PerformanceListEmpty, + PerformanceListError, + PerformanceListLoading +} from './performance-list.component'; + +function PerformanceListContainer() { + const { data, isLoading, error } = useGetPerformanceTimeoutsQuery(); + + if (isLoading) return ; + + if (error) return ; + + if (!data || !data.length) return ; + + return ; +} + +export { PerformanceListContainer }; diff --git a/libs/bublik/features/performance-check/tsconfig.json b/libs/bublik/features/performance-check/tsconfig.json new file mode 100644 index 00000000..abd31716 --- /dev/null +++ b/libs/bublik/features/performance-check/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../../../tsconfig.base.json" +} diff --git a/libs/bublik/features/performance-check/tsconfig.lib.json b/libs/bublik/features/performance-check/tsconfig.lib.json new file mode 100644 index 00000000..bd4808c4 --- /dev/null +++ b/libs/bublik/features/performance-check/tsconfig.lib.json @@ -0,0 +1,23 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../../dist/out-tsc", + "types": [ + "node", + + "@nx/react/typings/cssmodule.d.ts", + "@nx/react/typings/image.d.ts" + ] + }, + "exclude": [ + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"] +} diff --git a/libs/bublik/features/performance-check/tsconfig.spec.json b/libs/bublik/features/performance-check/tsconfig.spec.json new file mode 100644 index 00000000..08a39695 --- /dev/null +++ b/libs/bublik/features/performance-check/tsconfig.spec.json @@ -0,0 +1,26 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../../dist/out-tsc", + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest" + ] + }, + "include": [ + "vite.config.ts", + "vitest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/libs/bublik/features/performance-check/vite.config.ts b/libs/bublik/features/performance-check/vite.config.ts new file mode 100644 index 00000000..49fdd305 --- /dev/null +++ b/libs/bublik/features/performance-check/vite.config.ts @@ -0,0 +1,29 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'; + +export default defineConfig({ + root: __dirname, + cacheDir: + '../../../../node_modules/.vite/libs/bublik/features/performance-check', + + plugins: [react(), nxViteTsPaths()], + + // Uncomment this if you are using workers. + // worker: { + // plugins: [ nxViteTsPaths() ], + // }, + + test: { + globals: true, + cache: { dir: '../../../../node_modules/.vitest' }, + environment: 'jsdom', + include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + coverage: { + reportsDirectory: + '../../../../coverage/libs/bublik/features/performance-check', + provider: 'v8' + } + } +}); diff --git a/libs/bublik/features/sidebar/src/lib/bottom-nav/bottom-nav.tsx b/libs/bublik/features/sidebar/src/lib/bottom-nav/bottom-nav.tsx index e952ced8..00667467 100644 --- a/libs/bublik/features/sidebar/src/lib/bottom-nav/bottom-nav.tsx +++ b/libs/bublik/features/sidebar/src/lib/bottom-nav/bottom-nav.tsx @@ -20,6 +20,12 @@ const getNavSections = (isAdmin: boolean) => { to: '/admin/users', pattern: { path: '/admin/users' } }, + { + label: 'Performance', + icon: , + to: '/admin/performance', + pattern: { path: '/admin/performance' } + }, { label: 'Import', icon: , diff --git a/libs/services/bublik-api/src/lib/bublikAPI.ts b/libs/services/bublik-api/src/lib/bublikAPI.ts index dc24d079..23295074 100644 --- a/libs/services/bublik-api/src/lib/bublikAPI.ts +++ b/libs/services/bublik-api/src/lib/bublikAPI.ts @@ -152,6 +152,7 @@ export const { useAdminCreateUserMutation, useAdminDeleteUserMutation, useAdminUpdateUserMutation, + useGetPerformanceTimeoutsQuery, // Utils usePrefetch } = bublikAPI; diff --git a/libs/services/bublik-api/src/lib/endpoints/deploy-endpoints.ts b/libs/services/bublik-api/src/lib/endpoints/deploy-endpoints.ts index 69de4cc0..711f810d 100644 --- a/libs/services/bublik-api/src/lib/endpoints/deploy-endpoints.ts +++ b/libs/services/bublik-api/src/lib/endpoints/deploy-endpoints.ts @@ -9,7 +9,8 @@ import { DeployProjectAPIResponse, DeployGitInfoAPIResponse, DeployInfo, - DeployGitInfo + DeployGitInfo, + PerformanceResponse } from '@/shared/types'; import { BUBLIK_TAG } from '../types'; @@ -47,6 +48,9 @@ export const deployEndpoints = { } }; } + }), + getPerformanceTimeouts: build.query({ + query: () => ({ url: '/performance_check/' }) }) }) }; diff --git a/libs/shared/types/src/index.ts b/libs/shared/types/src/index.ts index f0f142e3..76b3d860 100644 --- a/libs/shared/types/src/index.ts +++ b/libs/shared/types/src/index.ts @@ -12,3 +12,4 @@ export * from './lib/run-import'; export * from './lib/log-json-schema'; export * from './lib/auth'; export * from './lib/import'; +export * from './lib/performance'; diff --git a/libs/shared/types/src/lib/performance/index.ts b/libs/shared/types/src/lib/performance/index.ts new file mode 100644 index 00000000..400df86a --- /dev/null +++ b/libs/shared/types/src/lib/performance/index.ts @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* SPDX-FileCopyrightText: 2024 OKTET LTD */ + +import { z } from 'zod'; + +export const PerformanceResponseSchema = z.array( + z.object({ + label: z.string(), + url: z.string().url().optional(), + timeout: z.number().nonnegative() + }) +); + +export type PerformanceResponse = z.infer; diff --git a/tsconfig.base.json b/tsconfig.base.json index 1ace8d68..cf78e102 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -74,7 +74,10 @@ "@/shared/hooks": ["libs/shared/hooks/src/index.ts"], "@/shared/tailwind-ui": ["libs/shared/tailwind-ui/src/index.ts"], "@/shared/types": ["libs/shared/types/src/index.ts"], - "@/shared/utils": ["libs/shared/utils/src/index.ts"] + "@/shared/utils": ["libs/shared/utils/src/index.ts"], + "@/bublik/features/performance-check": [ + "libs/bublik/features/performance-check/src/index.ts" + ] } }, "exclude": ["node_modules", "tmp"]