diff --git a/frontend/.storybook/HeadlampTheme.js b/frontend/.storybook/HeadlampTheme.js
index 9b207f3a98..2e176e0373 100644
--- a/frontend/.storybook/HeadlampTheme.js
+++ b/frontend/.storybook/HeadlampTheme.js
@@ -1,7 +1,7 @@
// https://storybook.js.org/docs/react/configure/theming#create-a-theme-quickstart
// To workaround a bug at time of writing, where theme is not refreshed,
// you may need to `npm run storybook --no-manager-cache`
-import { create } from '@storybook/theming';
+import { create } from '@storybook/theming/create';
import logoUrl from '../../docs/headlamp_light.svg';
export default create({
@@ -9,4 +9,6 @@ export default create({
brandTitle: 'Headlamp Kubernetes Web UI dashboard',
brandUrl: 'https://headlamp.dev/docs/latest/development/',
brandImage: logoUrl,
+ fontBase: '"Overpass", sans-serif',
+ fontCode: '"Overpass Mono", monospace',
});
diff --git a/frontend/.storybook/baseMocks.ts b/frontend/.storybook/baseMocks.ts
new file mode 100644
index 0000000000..6f26ea2cee
--- /dev/null
+++ b/frontend/.storybook/baseMocks.ts
@@ -0,0 +1,226 @@
+import { http, HttpResponse } from 'msw';
+import { NODE_DUMMY_DATA } from '../src/components/node/storyHelper';
+
+/**
+ * This contains several mocked endpoints
+ * Those are used in most of the stories
+ *
+ */
+export const baseMocks = [
+ http.get('https://api.iconify.design/mdi.json', () => HttpResponse.json({})),
+ http.post('http://localhost:4466/apis/authorization.k8s.io/v1/selfsubjectaccessreviews', () =>
+ HttpResponse.json({ status: { allowed: true, reason: '', code: 200 } })
+ ),
+ http.get('http://localhost:4466/api/v1/namespaces', () =>
+ HttpResponse.json({
+ kind: 'NamespacesList',
+ items: [
+ {
+ kind: 'Namespace',
+ apiVersion: 'v1',
+ metadata: {
+ name: 'default',
+ creationTimestamp: '2024-08-16T11:12:37.179Z',
+ },
+ spec: {
+ finalizers: ['kubernetes'],
+ },
+ status: {
+ phase: 'Active',
+ },
+ },
+ ],
+ metadata: {},
+ })
+ ),
+ http.get('http://localhost:4466/clusters/cluster0/version', () => HttpResponse.json({})),
+ http.get('http://localhost:4466/clusters/cluster1/version', () => HttpResponse.json({})),
+ http.get('http://localhost:4466/clusters/cluster2/version', () => HttpResponse.json({})),
+ http.get('http://localhost:4466/clusters/cluster0/api/v1/events', () =>
+ HttpResponse.json({
+ kind: 'EventList',
+ items: [],
+ metadata: {},
+ })
+ ),
+ http.get('http://localhost:4466/clusters/cluster1/api/v1/events', () =>
+ HttpResponse.json({
+ kind: 'EventList',
+ items: [],
+ metadata: {},
+ })
+ ),
+ http.get('http://localhost:4466/clusters/cluster2/api/v1/events', () =>
+ HttpResponse.json({
+ kind: 'EventList',
+ items: [],
+ metadata: {},
+ })
+ ),
+ http.get('http://localhost:4466/version', () => HttpResponse.json({})),
+ http.get('http://localhost:4466/api/v1/events', () =>
+ HttpResponse.json({
+ kind: 'EventList',
+ items: [],
+ metadata: {},
+ })
+ ),
+ http.get('http://localhost:4466/api/v1/namespaces/kube-system/events', () =>
+ HttpResponse.json({
+ kind: 'EventList',
+ items: [],
+ metadata: {},
+ })
+ ),
+ http.get('http://localhost:4466/api/v1/nodes', () =>
+ HttpResponse.json({
+ kind: 'NodesList',
+ apiVersion: 'v1',
+ metadata: {
+ resourceVersion: '545284',
+ },
+ items: NODE_DUMMY_DATA,
+ })
+ ),
+ http.get('http://localhost:4466/api/v1/namespaces/default/pods', () =>
+ HttpResponse.json({
+ kind: 'PodList',
+ apiVersion: 'v1',
+ metadata: {},
+ items: [],
+ })
+ ),
+ http.get('http://localhost:4466/apis/metrics.k8s.io/v1beta1/nodes', () =>
+ HttpResponse.json({
+ apiVersion: 'metrics.k8s.io/v1beta1',
+ kind: 'NodeMetricsList',
+ metadata: {},
+ items: [
+ {
+ apiVersion: 'v1',
+ count: 1,
+ eventTime: null,
+ firstTimestamp: '2023-07-13T13:42:00Z',
+ involvedObject: {
+ apiVersion: 'v1',
+ fieldPath: 'spec.containers{hello}',
+ kind: 'Pod',
+ name: 'hello-123-123',
+ namespace: 'default',
+ resourceVersion: '44429432',
+ uid: 'a1234',
+ },
+ kind: 'Event',
+ lastTimestamp: '2023-07-13T13:42:00Z',
+ message: 'Started container hello',
+ metadata: {
+ creationTimestamp: '2023-07-13T13:42:00Z',
+ name: 'hello-123-123.321',
+ namespace: 'default',
+ resourceVersion: '44429443',
+ uid: 'a12345',
+ },
+ reason: 'Started',
+ reportingComponent: '',
+ reportingInstance: '',
+ source: {
+ component: 'kubelet',
+ host: 'aks-agentpool-30159275-vmss00003g',
+ },
+ type: 'Normal',
+ },
+ {
+ apiVersion: 'v1',
+ count: 4449,
+ eventTime: null,
+ firstTimestamp: '2023-07-12T20:07:10Z',
+ involvedObject: {
+ apiVersion: 'autoscaling/v2',
+ kind: 'HorizontalPodAutoscaler',
+ name: 'nginx-deployment',
+ namespace: 'default',
+ resourceVersion: '1',
+ uid: 'b1234',
+ },
+ kind: 'Event',
+ lastTimestamp: '2023-07-13T14:42:17Z',
+ message: 'failed to get cpu utilization: missing request for cpu',
+ metadata: {
+ creationTimestamp: '2023-07-12T20:07:10Z',
+ name: 'nginx-deployment.1234',
+ namespace: 'default',
+ resourceVersion: '1',
+ uid: 'b12345',
+ },
+ reason: 'FailedGetResourceMetric',
+ reportingComponent: '',
+ reportingInstance: '',
+ source: {
+ component: 'horizontal-pod-autoscaler',
+ },
+ type: 'Warning',
+ },
+ {
+ apiVersion: 'v1',
+ kind: 'Event',
+ metadata: {
+ name: 'nginx-deployment-12345',
+ namespace: 'default',
+ creationTimestamp: '2024-02-12T20:07:10Z',
+ uid: 'b123456',
+ resourceVersion: '1',
+ },
+ involvedObject: {
+ kind: 'Pod',
+ name: 'nginx-deployment-1234567890-abcde',
+ namespace: 'default',
+ uid: 'b1234',
+ },
+ reason: 'FailedGetResourceMetric',
+ message: 'failed to get cpu utilization: missing request for cpu',
+ source: {
+ component: 'horizontal-pod-autoscaler',
+ },
+ firstTimestamp: '2024-02-13T14:42:17Z',
+ lastTimestamp: '2024-02-13T14:42:17Z',
+ type: 'Warning',
+ series: {
+ count: 10,
+ lastObservedTime: '2024-02-13T14:42:17Z',
+ },
+ },
+ {
+ apiVersion: 'v1',
+ kind: 'Event',
+ metadata: {
+ name: 'nginx-deployment-12346',
+ namespace: 'default',
+ creationTimestamp: '2024-02-12T20:07:10Z',
+ uid: 'abc123456',
+ resourceVersion: '1',
+ },
+ involvedObject: {
+ kind: 'Pod',
+ name: 'nginx-deployment-abcd-1234567890',
+ namespace: 'default',
+ uid: 'b1234',
+ },
+ reason: 'FailedGetResourceMetric',
+ message: 'failed to get cpu utilization: missing request for cpu',
+ source: {
+ component: 'horizontal-pod-autoscaler',
+ },
+ firstTimestamp: null,
+ lastTimestamp: null,
+ type: 'Warning',
+ series: {
+ count: 10,
+ lastObservedTime: '2024-02-13T15:42:17Z',
+ },
+ reportingComponent: '',
+ reportingInstance: '',
+ },
+ ],
+ })
+ ),
+];
diff --git a/frontend/.storybook/main.js b/frontend/.storybook/main.js
deleted file mode 100644
index 3c32c651cc..0000000000
--- a/frontend/.storybook/main.js
+++ /dev/null
@@ -1,19 +0,0 @@
-export default {
- stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
-
- addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions'],
-
- core: {
- builder: '@storybook/builder-vite',
- disableTelemetry: true,
- },
-
- framework: {
- name: '@storybook/react-vite',
- options: {},
- },
-
- docs: {
- autodocs: true,
- },
-};
diff --git a/frontend/.storybook/main.ts b/frontend/.storybook/main.ts
new file mode 100644
index 0000000000..780f53691f
--- /dev/null
+++ b/frontend/.storybook/main.ts
@@ -0,0 +1,22 @@
+import { StorybookConfig } from '@storybook/react-vite';
+
+export default {
+ framework: '@storybook/react-vite',
+ stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
+
+ addons: [
+ '@storybook/addon-links',
+ '@storybook/addon-essentials',
+ '@storybook/addon-interactions',
+ ],
+
+ core: {
+ disableTelemetry: true,
+ },
+
+ docs: {},
+
+ typescript: {
+ reactDocgen: 'react-docgen-typescript',
+ },
+} satisfies StorybookConfig;
diff --git a/frontend/.storybook/manager.js b/frontend/.storybook/manager.js
index 53d569022a..364512f5b5 100644
--- a/frontend/.storybook/manager.js
+++ b/frontend/.storybook/manager.js
@@ -1,4 +1,4 @@
-import { addons } from '@storybook/addons';
+import { addons } from '@storybook/manager-api';
import theme from './HeadlampTheme';
addons.setConfig({
diff --git a/frontend/.storybook/preview.tsx b/frontend/.storybook/preview.tsx
index 058b044837..f7d0d88565 100644
--- a/frontend/.storybook/preview.tsx
+++ b/frontend/.storybook/preview.tsx
@@ -1,81 +1,72 @@
-import React from 'react';
import themesConf from '../src/lib/themes';
-import { ThemeProvider, StyledEngineProvider } from '@mui/material/styles';
-import { initialize, mswDecorator } from 'msw-storybook-addon';
-import { rest } from 'msw';
+import { ThemeProvider } from '@mui/material/styles';
+import { initialize, mswLoader } from 'msw-storybook-addon';
+import '../src/index.css';
+import { Title, Subtitle, Description, Primary, Controls } from '@storybook/blocks';
+import { baseMocks } from './baseMocks';
// https://github.com/mswjs/msw-storybook-addon
-initialize();
+initialize({
+ onUnhandledRequest: 'warn',
+ waitUntilReady: true,
+});
-const darkTheme = themesConf['dark'];
-const lightTheme = themesConf['light'];
-
-const withThemeProvider = (Story, context) => {
- const backgroundColor = context.globals.backgrounds ? context.globals.backgrounds.value : 'light';
- const theme = backgroundColor !== 'dark' ? lightTheme : darkTheme;
+const withThemeProvider = (Story: any, context: any) => {
+ const theme = themesConf[context.globals.backgrounds?.value === '#1f1f1f' ? 'dark' : 'light'];
const ourThemeProvider = (
-