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