From e7f4b3ec8026678406cf1d626f247a85890826e3 Mon Sep 17 00:00:00 2001 From: Patrick Ear Date: Tue, 3 Mar 2026 15:18:48 +0100 Subject: [PATCH 1/2] fix biomejs when you open from root --- biome.jsonc | 40 ++++++++++++++++++++++++++++++++++++++++ shell-ui/biome.json | 40 +--------------------------------------- ui/biome.json | 40 +--------------------------------------- 3 files changed, 42 insertions(+), 78 deletions(-) create mode 100644 biome.jsonc diff --git a/biome.jsonc b/biome.jsonc new file mode 100644 index 0000000000..d2dddeb5b5 --- /dev/null +++ b/biome.jsonc @@ -0,0 +1,40 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { "ignoreUnknown": false }, + "formatter": { + "enabled": true, + "formatWithErrors": false, + "indentStyle": "space", + "indentWidth": 2, + "lineEnding": "lf", + "lineWidth": 120, + "useEditorconfig": true + }, + "linter": { + "enabled": true, + "rules": { "recommended": true }, + "domains": { + "react": "recommended" + } + }, + "javascript": { + "formatter": { + "jsxQuoteStyle": "double", + "quoteProperties": "asNeeded", + "trailingCommas": "all", + "semicolons": "always", + "arrowParentheses": "always", + "quoteStyle": "single" + } + }, + "html": { "formatter": { "selfCloseVoidElements": "always" } }, + "assist": { + "enabled": true, + "actions": { "source": { "organizeImports": "on" } } + } +} diff --git a/shell-ui/biome.json b/shell-ui/biome.json index 4bfa9b523d..e0e6afe7c1 100644 --- a/shell-ui/biome.json +++ b/shell-ui/biome.json @@ -1,41 +1,3 @@ { - "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json", - "vcs": { - "enabled": true, - "clientKind": "git", - "useIgnoreFile": true - }, - "files": { "ignoreUnknown": false }, - "formatter": { - "enabled": true, - "formatWithErrors": false, - "indentStyle": "space", - "indentWidth": 2, - "lineEnding": "lf", - "lineWidth": 120, - "useEditorconfig": true - }, - "linter": { - "enabled": true, - "rules": { "recommended": true }, - "domains": { - "next": "recommended", - "react": "recommended" - } - }, - "javascript": { - "formatter": { - "jsxQuoteStyle": "double", - "quoteProperties": "asNeeded", - "trailingCommas": "all", - "semicolons": "always", - "arrowParentheses": "always", - "quoteStyle": "single" - } - }, - "html": { "formatter": { "selfCloseVoidElements": "always" } }, - "assist": { - "enabled": true, - "actions": { "source": { "organizeImports": "on" } } - } + "extends": "//" } diff --git a/ui/biome.json b/ui/biome.json index 4bfa9b523d..e0e6afe7c1 100644 --- a/ui/biome.json +++ b/ui/biome.json @@ -1,41 +1,3 @@ { - "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json", - "vcs": { - "enabled": true, - "clientKind": "git", - "useIgnoreFile": true - }, - "files": { "ignoreUnknown": false }, - "formatter": { - "enabled": true, - "formatWithErrors": false, - "indentStyle": "space", - "indentWidth": 2, - "lineEnding": "lf", - "lineWidth": 120, - "useEditorconfig": true - }, - "linter": { - "enabled": true, - "rules": { "recommended": true }, - "domains": { - "next": "recommended", - "react": "recommended" - } - }, - "javascript": { - "formatter": { - "jsxQuoteStyle": "double", - "quoteProperties": "asNeeded", - "trailingCommas": "all", - "semicolons": "always", - "arrowParentheses": "always", - "quoteStyle": "single" - } - }, - "html": { "formatter": { "selfCloseVoidElements": "always" } }, - "assist": { - "enabled": true, - "actions": { "source": { "organizeImports": "on" } } - } + "extends": "//" } From 4a1272d1ae9db778b770fe6d48d40480c881abb2 Mon Sep 17 00:00:00 2001 From: Patrick Ear Date: Tue, 3 Mar 2026 15:32:53 +0100 Subject: [PATCH 2/2] chore - format all ui with biomejs --- shell-ui/jest.config.js | 4 +- shell-ui/src/FederatedApp.spec.tsx | 219 +++---- shell-ui/src/FederatedApp.tsx | 62 +- shell-ui/src/NotificationCenterProvider.tsx | 32 +- shell-ui/src/QueryClientProvider.tsx | 16 +- shell-ui/src/alerts/AlertProvider.tsx | 4 +- shell-ui/src/alerts/Alerts.spec.tsx | 10 +- shell-ui/src/alerts/alertHooks.test.tsx | 9 +- shell-ui/src/alerts/alertHooks.ts | 9 +- shell-ui/src/alerts/index.ts | 2 +- shell-ui/src/alerts/services/alertManager.ts | 12 +- shell-ui/src/alerts/services/alertUtils.ts | 53 +- shell-ui/src/alerts/services/loki.ts | 17 +- shell-ui/src/auth/AuthConfigProvider.tsx | 11 +- shell-ui/src/auth/AuthProvider.tsx | 37 +- shell-ui/src/auth/FirstTimeLoginProvider.tsx | 24 +- shell-ui/src/auth/useFirstTimeLogin.spec.tsx | 4 +- shell-ui/src/index.css | 39 +- .../ConfigurationProviders.spec.tsx | 191 +++--- .../initFederation/ConfigurationProviders.tsx | 125 ++-- .../initFederation/ShellConfigProvider.tsx | 13 +- .../initFederation/ShellHistoryProvider.tsx | 14 +- .../ShellThemeSelectorProvider.tsx | 27 +- .../initFederation/UIListProvider.spec.tsx | 6 +- .../src/initFederation/UIListProvider.tsx | 31 +- shell-ui/src/navbar/InstanceName.spec.tsx | 17 +- shell-ui/src/navbar/InstanceName.tsx | 34 +- shell-ui/src/navbar/NavBar.tsx | 81 +-- shell-ui/src/navbar/NavbarConfigProvider.tsx | 10 +- .../src/navbar/NavbarUpdaterComponents.tsx | 13 +- .../src/navbar/NotificationCenter.spec.tsx | 98 +-- shell-ui/src/navbar/NotificationCenter.tsx | 78 +-- .../src/navbar/SleepingNotificationBell.tsx | 8 +- .../navbar/__TESTS__/testMultipleHooks.tsx | 39 +- shell-ui/src/navbar/__TESTS__/utils.ts | 12 +- .../src/navbar/auth/permissionUtils.spec.ts | 29 +- shell-ui/src/navbar/auth/permissionUtils.ts | 22 +- shell-ui/src/navbar/events.ts | 5 +- shell-ui/src/navbar/favicon.ts | 4 +- shell-ui/src/navbar/index.spec.tsx | 12 +- shell-ui/src/navbar/lang.tsx | 23 +- shell-ui/src/navbar/library.ts | 6 +- shell-ui/src/navbar/translations/en.json | 2 +- shell-ui/src/navbar/translations/fr.json | 2 +- shell-ui/src/platform/service/k8s.spec.tsx | 6 +- shell-ui/src/platform/service/k8s.ts | 16 +- shell-ui/src/useNotificationCenter.ts | 30 +- shell-ui/tsconfig.json | 8 +- ui/public/brand/assets/login/styles-light.css | 34 +- ui/public/brand/assets/login/styles.css | 22 +- ui/src/FederableApp.tsx | 11 +- ui/src/QueryClientProvider.tsx | 5 +- .../ConfigureAlerting.test.tsx | 229 ++----- .../alert-configuration/ConfigureAlerting.tsx | 178 +----- .../domain/AlertConfigurationDomain.ts | 36 +- .../Metalk8sCSCAlertConfigurationStore.ts | 286 ++++----- ui/src/components/ActiveAlertsCounter.tsx | 10 +- .../components/ActiveAlertsFilters.spec.tsx | 8 +- ui/src/components/ActiveAlertsFilters.tsx | 4 +- .../AlertNavbarUpdaterComponent.test.tsx | 9 +- .../AlertNavbarUpdaterComponent.tsx | 54 +- ui/src/components/AlertsTab.tsx | 20 +- ui/src/components/DashboardAlerts.test.tsx | 4 +- ui/src/components/DashboardAlerts.tsx | 36 +- ui/src/components/DashboardBandwidthChart.tsx | 36 +- ui/src/components/DashboardChartCpuUsage.tsx | 16 +- ui/src/components/DashboardChartMemory.tsx | 18 +- .../components/DashboardChartSystemLoad.tsx | 16 +- .../components/DashboardChartThroughput.tsx | 35 +- ui/src/components/DashboardGlobalHealth.tsx | 26 +- ui/src/components/DashboardInventory.test.tsx | 29 +- ui/src/components/DashboardInventory.tsx | 39 +- ui/src/components/DashboardMetrics.tsx | 16 +- ui/src/components/DashboardNetwork.tsx | 16 +- ui/src/components/DashboardPlane.test.tsx | 12 +- ui/src/components/DashboardPlaneHealth.tsx | 10 +- ui/src/components/DashboardServices.test.tsx | 12 +- ui/src/components/DashboardServices.tsx | 90 +-- ui/src/components/HealthItem.tsx | 18 +- ui/src/components/InformationList.ts | 8 +- ui/src/components/Latency.tsx | 15 +- ui/src/components/MetricChart.tsx | 38 +- ui/src/components/MetricSymmetricalChart.tsx | 69 +-- ui/src/components/ModalFormStyle.ts | 2 +- ui/src/components/NoRowsRenderer.tsx | 2 +- ui/src/components/NodeListTable.tsx | 20 +- .../components/NodePageOverviewTab.spec.tsx | 11 +- ui/src/components/NodePageOverviewTab.tsx | 93 +-- ui/src/components/NodePagePartitionTab.tsx | 7 +- ui/src/components/NodePagePodsTab.spec.tsx | 12 +- ui/src/components/NodePagePodsTab.tsx | 30 +- ui/src/components/NodePageVolumesTab.tsx | 10 +- ui/src/components/NodePageVolumesTable.tsx | 33 +- ui/src/components/NodePartitionTable.test.tsx | 541 ++++++++-------- ui/src/components/NodePartitionTable.tsx | 47 +- .../NonSymmetricalQuantileChart.tsx | 31 +- ui/src/components/QuantileTooltip.tsx | 26 +- ui/src/components/StatusIcon.tsx | 10 +- .../components/SymmetricalQuantileChart.tsx | 32 +- .../components/SymmetricalQuantileTooltip.tsx | 35 +- ui/src/components/TableBasedPageStyle.ts | 2 +- ui/src/components/TableRow.tsx | 4 +- ui/src/components/VolumeCharts.tsx | 25 +- ui/src/components/VolumeListTable.tsx | 23 +- ui/src/components/VolumeMetricsTab.tsx | 51 +- ui/src/components/VolumeOverviewTab.tsx | 97 +-- ui/src/components/__TEST__/util.tsx | 39 +- .../shared/QuantileTooltipShared.tsx | 92 +-- ui/src/components/style/BreadcrumbStyle.ts | 2 +- ui/src/components/style/ModalFormStyle.ts | 2 +- .../components/style/TableBasedPageStyle.ts | 2 +- ui/src/components/style/TableStyle.ts | 2 +- ui/src/constants.ts | 9 +- ui/src/containers/AlertPage.tsx | 28 +- ui/src/containers/AlertProvider.tsx | 12 +- ui/src/containers/CreateVolume.tsx | 108 +--- ui/src/containers/Layout.tsx | 47 +- ui/src/containers/NodeCreateForm.tsx | 48 +- ui/src/containers/NodePageContent.tsx | 14 +- ui/src/containers/NodePageMetricsTab.tsx | 23 +- ui/src/containers/NodePageRSP.tsx | 67 +- ui/src/containers/PrivateRoute.tsx | 25 +- ui/src/containers/StartTimeProvider.tsx | 11 +- ui/src/containers/TimespanSelector.tsx | 16 +- ui/src/containers/VolumePage.tsx | 18 +- ui/src/containers/VolumePageContent.tsx | 14 +- ui/src/containers/VolumePageRSP.tsx | 65 +- ui/src/ducks/app/authError.ts | 7 +- ui/src/ducks/app/monitoring.ts | 122 +--- ui/src/ducks/app/nodes.test.ts | 5 +- ui/src/ducks/app/nodes.ts | 72 +-- ui/src/ducks/app/notifications.ts | 12 +- ui/src/ducks/app/pods.ts | 11 +- ui/src/ducks/app/salt.test.ts | 18 +- ui/src/ducks/app/salt.ts | 27 +- ui/src/ducks/app/volumes.ts | 101 +-- ui/src/ducks/config.ts | 18 +- ui/src/ducks/history.ts | 9 +- ui/src/ducks/login.ts | 9 +- ui/src/hooks.tsx | 70 +-- ui/src/hooks/monitoring.ts | 9 +- ui/src/hooks/nodes.ts | 35 +- .../hooks/useChartLegendRegistration.spec.ts | 57 +- ui/src/hooks/useChartLegendRegistration.ts | 11 +- ui/src/hooks/volumes.ts | 6 +- ui/src/serviceWorker.ts | 15 +- ui/src/services/ApiClient.ts | 8 +- ui/src/services/NodeUtils.ts | 37 +- ui/src/services/NodeVolumesUtils.test.ts | 11 +- ui/src/services/NodeVolumesUtils.ts | 109 +--- ui/src/services/NodeVolumesUtilsData.ts | 58 +- ui/src/services/PodUtils.ts | 4 +- ui/src/services/alertUtils.test.ts | 58 +- ui/src/services/alertUtils.ts | 57 +- ui/src/services/alertUtilsData.ts | 9 +- ui/src/services/alertmanager/api.ts | 10 +- ui/src/services/api.ts | 4 +- ui/src/services/errorhandler.ts | 2 +- ui/src/services/graphUtils.test.ts | 35 +- ui/src/services/graphUtils.ts | 110 +--- .../k8s/Metalk8sLocalVolumeProvider.test.ts | 101 +-- .../k8s/Metalk8sLocalVolumeProvider.ts | 102 +--- .../k8s/Metalk8sVolumeClient.generated.ts | 26 +- ui/src/services/k8s/api.ts | 6 +- ui/src/services/k8s/core.key.ts | 2 +- ui/src/services/k8s/core.ts | 41 +- ui/src/services/k8s/volumes.ts | 5 +- ui/src/services/loki/api.ts | 32 +- ui/src/services/platformlibrary/k8s.spec.tsx | 6 +- ui/src/services/platformlibrary/k8s.ts | 14 +- ui/src/services/platformlibrary/metrics.ts | 577 ++++-------------- ui/src/services/prometheus/api.ts | 11 +- ui/src/services/prometheus/fetchMetrics.ts | 15 +- ui/src/services/salt/api.ts | 6 +- ui/src/services/salt/utils.test.ts | 2 +- ui/src/services/salt/utils.ts | 7 +- ui/src/services/utils.test.ts | 24 +- ui/src/services/utils.ts | 110 ++-- ui/src/setupTests.tsx | 10 +- ui/src/tests/mocks/salt/constants.ts | 2 +- ui/src/tests/mocks/salt/eventRet.ts | 2 +- ui/src/tests/mocks/salt/printJob.ts | 17 +- ui/src/tests/mocks/util.ts | 2 +- ui/src/typeGuard.ts | 5 +- ui/src/types.ts | 2 +- ui/tsconfig.json | 12 +- 186 files changed, 1890 insertions(+), 5154 deletions(-) diff --git a/shell-ui/jest.config.js b/shell-ui/jest.config.js index f40dfa44ea..b7b2b95dd9 100644 --- a/shell-ui/jest.config.js +++ b/shell-ui/jest.config.js @@ -1,7 +1,5 @@ module.exports = { - transformIgnorePatterns: [ - '/node_modules/(?!vega-lite|@scality|pretty-bytes|uuid)', - ], + transformIgnorePatterns: ['/node_modules/(?!vega-lite|@scality|pretty-bytes|uuid)'], setupFilesAfterEnv: ['./src/setupTests.ts'], clearMocks: true, moduleNameMapper: { diff --git a/shell-ui/src/FederatedApp.spec.tsx b/shell-ui/src/FederatedApp.spec.tsx index 7f6403ab98..c92cf0ae01 100644 --- a/shell-ui/src/FederatedApp.spec.tsx +++ b/shell-ui/src/FederatedApp.spec.tsx @@ -7,94 +7,86 @@ import { waitForLoadingToFinish } from './navbar/__TESTS__/utils'; import './navbar/index'; export const configurationHandlers = [ - rest.get( - 'http://localhost:3000/.well-known/micro-app-configuration', - (req, res, ctx) => { - return res( - ctx.json({ - kind: 'MicroAppConfiguration', - apiVersion: 'ui.scality.com/v1alpha1', - metadata: { - kind: 'metalk8s-ui', - }, - spec: { - remoteEntryPath: '/static/js/remoteEntry.js', - views: { - platform: { - path: '/', - label: { - en: 'Platform', - fr: 'Plateforme', - }, - module: './FederableApp', - scope: 'metalk8s', - }, - alerts: { - path: '/alerts', - label: { - en: 'Alerts', - fr: 'Alertes', - }, - module: './FederableApp', - scope: 'metalk8s', - }, - }, - hooks: { - TODO_useAlert_and_platform_lib_hooks: { - module: '', - scope: '', + rest.get('http://localhost:3000/.well-known/micro-app-configuration', (req, res, ctx) => { + return res( + ctx.json({ + kind: 'MicroAppConfiguration', + apiVersion: 'ui.scality.com/v1alpha1', + metadata: { + kind: 'metalk8s-ui', + }, + spec: { + remoteEntryPath: '/static/js/remoteEntry.js', + views: { + platform: { + path: '/', + label: { + en: 'Platform', + fr: 'Plateforme', }, + module: './FederableApp', + scope: 'metalk8s', }, - components: { - TODO_AlertProvider: { - module: '', - scope: '', + alerts: { + path: '/alerts', + label: { + en: 'Alerts', + fr: 'Alertes', }, + module: './FederableApp', + scope: 'metalk8s', }, }, - }), - ); - }, - ), - rest.get( - 'http://localhost:3000/.well-known/runtime-app-configuration', - (req, res, ctx) => { - return res( - ctx.json({ - kind: 'MicroAppRuntimeConfiguration', - apiVersion: 'ui.scality.com/v1alpha1', - metadata: { - kind: 'metalk8s-ui', - name: 'metalk8s.eu-west-1', - }, - spec: { - title: 'MetalK8s Platform', - selfConfiguration: { - url: '/api/kubernetes', - url_salt: '/api/salt', - url_prometheus: '/api/prometheus', - url_grafana: '/grafana', - url_doc: '/docs', - url_alertmanager: '/api/alertmanager', - flags: [], - ui_base_path: '/', - url_support: - 'https://github.com/scality/metalk8s/discussions/new', + hooks: { + TODO_useAlert_and_platform_lib_hooks: { + module: '', + scope: '', }, - auth: { - kind: 'OIDC', - providerUrl: '/oidc', - redirectUrl: 'http://localhost:3000/', - clientId: 'metalk8s-ui', - responseType: 'code', - scopes: - 'openid profile email groups offline_access audience:server:client_id:oidc-auth-client', + }, + components: { + TODO_AlertProvider: { + module: '', + scope: '', }, }, - }), - ); - }, - ), + }, + }), + ); + }), + rest.get('http://localhost:3000/.well-known/runtime-app-configuration', (req, res, ctx) => { + return res( + ctx.json({ + kind: 'MicroAppRuntimeConfiguration', + apiVersion: 'ui.scality.com/v1alpha1', + metadata: { + kind: 'metalk8s-ui', + name: 'metalk8s.eu-west-1', + }, + spec: { + title: 'MetalK8s Platform', + selfConfiguration: { + url: '/api/kubernetes', + url_salt: '/api/salt', + url_prometheus: '/api/prometheus', + url_grafana: '/grafana', + url_doc: '/docs', + url_alertmanager: '/api/alertmanager', + flags: [], + ui_base_path: '/', + url_support: 'https://github.com/scality/metalk8s/discussions/new', + }, + auth: { + kind: 'OIDC', + providerUrl: '/oidc', + redirectUrl: 'http://localhost:3000/', + clientId: 'metalk8s-ui', + responseType: 'code', + scopes: 'openid profile email groups offline_access audience:server:client_id:oidc-auth-client', + }, + }, + }), + ); + }), rest.get('http://localhost/shell/deployed-ui-apps.json', (req, res, ctx) => { return res( ctx.json([ @@ -138,46 +130,24 @@ export const configurationHandlers = [ ); }), rest.get('http://localhost/static/js/remoteEntry.js', (req, res, ctx) => { - return res( - ctx.set('Content-Type', 'application/javascript'), - ctx.text('window.metalk8s = {init: () => {}};'), - ); + return res(ctx.set('Content-Type', 'application/javascript'), ctx.text('window.metalk8s = {init: () => {}};')); + }), + rest.get('http://localhost/oidc/.well-known/openid-configuration', (req, res, ctx) => { + const result = { + issuer: 'https://mocked.ingress/oidc', + authorization_endpoint: 'https://mocked.ingress/oidc/auth', + token_endpoint: 'https://mocked.ingress/oidc/token', + jwks_uri: 'https://mocked.ingress/oidc/keys', + userinfo_endpoint: 'https://mocked.ingress/oidc/userinfo', + response_types_supported: ['code', 'id_token', 'token'], + subject_types_supported: ['public'], + id_token_signing_alg_values_supported: ['RS256'], + scopes_supported: ['openid', 'email', 'groups', 'profile', 'offline_access'], + token_endpoint_auth_methods_supported: ['client_secret_basic'], + claims_supported: ['aud', 'email', 'email_verified', 'exp', 'iat', 'iss', 'locale', 'name', 'sub'], + }; + return res(ctx.json(result)); }), - rest.get( - 'http://localhost/oidc/.well-known/openid-configuration', - (req, res, ctx) => { - const result = { - issuer: 'https://mocked.ingress/oidc', - authorization_endpoint: 'https://mocked.ingress/oidc/auth', - token_endpoint: 'https://mocked.ingress/oidc/token', - jwks_uri: 'https://mocked.ingress/oidc/keys', - userinfo_endpoint: 'https://mocked.ingress/oidc/userinfo', - response_types_supported: ['code', 'id_token', 'token'], - subject_types_supported: ['public'], - id_token_signing_alg_values_supported: ['RS256'], - scopes_supported: [ - 'openid', - 'email', - 'groups', - 'profile', - 'offline_access', - ], - token_endpoint_auth_methods_supported: ['client_secret_basic'], - claims_supported: [ - 'aud', - 'email', - 'email_verified', - 'exp', - 'iat', - 'iss', - 'locale', - 'name', - 'sub', - ], - }; - return res(ctx.json(result)); - }, - ), ]; const server = setupServer(...configurationHandlers); @@ -185,8 +155,7 @@ const mockOIDCProvider = () => { // This is a hack to workarround the following issue : MSW return lower cased content-type header, // oidc-client is internally using XMLHttpRequest to perform queries and retrieve response header Content-Type using 'XMLHttpRequest.prototype.getResponseHeader'. // XMLHttpRequest.prototype.getResponseHeader is case sensitive and hence when receiving a response with header content-type it is not mapping it to Content-Type - const caseSensitiveGetResponseHeader = - XMLHttpRequest.prototype.getResponseHeader; + const caseSensitiveGetResponseHeader = XMLHttpRequest.prototype.getResponseHeader; XMLHttpRequest.prototype.getResponseHeader = function (header) { if (header === 'Content-Type') { @@ -242,9 +211,7 @@ describe('FederatedApp', () => { //S render(); //E - await waitFor(() => - expect(screen.getByRole('navigation')).toBeInTheDocument(), - ); + await waitFor(() => expect(screen.getByRole('navigation')).toBeInTheDocument()); //V let navbar = screen.getByRole('navigation'); expect(navbar).toBeInTheDocument(); @@ -253,9 +220,7 @@ describe('FederatedApp', () => { () => { navbar = screen.getByRole('navigation'); - return expect( - within(navbar).getByText(/Platform/i), - ).toBeInTheDocument(); + return expect(within(navbar).getByText(/Platform/i)).toBeInTheDocument(); }, { timeout: 5000 }, ); diff --git a/shell-ui/src/FederatedApp.tsx b/shell-ui/src/FederatedApp.tsx index b3e8336d95..28c4349530 100644 --- a/shell-ui/src/FederatedApp.tsx +++ b/shell-ui/src/FederatedApp.tsx @@ -3,11 +3,7 @@ import { ErrorPage500 } from '@scality/core-ui/dist/components/error-pages/Error import { Loader } from '@scality/core-ui/dist/components/loader/Loader.component'; import { ScrollbarWrapper } from '@scality/core-ui/dist/components/scrollbarwrapper/ScrollbarWrapper.component'; import { ToastProvider } from '@scality/core-ui/dist/components/toast/ToastProvider'; -import { - FederatedComponent, - FederatedComponentProps, - SolutionUI, -} from '@scality/module-federation'; +import { FederatedComponent, FederatedComponentProps, SolutionUI } from '@scality/module-federation'; import React, { useEffect, useMemo } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; import { QueryClient } from 'react-query'; @@ -18,22 +14,10 @@ import { useQuery } from 'react-query'; import { AuthConfigProvider, useAuthConfig } from './auth/AuthConfigProvider'; import { AuthProvider } from './auth/AuthProvider'; import { FirstTimeLoginProvider } from './auth/FirstTimeLoginProvider'; -import { - ShellAlerts, - shellAlerts, - ShellHooks, - shellHooks, -} from './hooks/useShellHooks'; +import { ShellAlerts, shellAlerts, ShellHooks, shellHooks } from './hooks/useShellHooks'; import './index.css'; -import { - ConfigurationProvider, - useConfigRetriever, - useFederatedRoutes, -} from './initFederation/ConfigurationProviders'; -import { - ShellConfigProvider, - useShellConfig, -} from './initFederation/ShellConfigProvider'; +import { ConfigurationProvider, useConfigRetriever, useFederatedRoutes } from './initFederation/ConfigurationProviders'; +import { ShellConfigProvider, useShellConfig } from './initFederation/ShellConfigProvider'; import { ShellHistoryProvider } from './initFederation/ShellHistoryProvider'; import { ShellThemeSelectorProvider } from './initFederation/ShellThemeSelectorProvider'; import { UIListProvider } from './initFederation/UIListProvider'; @@ -55,8 +39,7 @@ import { QueryClientProvider } from './QueryClientProvider'; const mockLoadShare: typeof loadShare = () => { return Promise.resolve(false); }; -const loadShareModule = - process.env.NODE_ENV === 'test' ? mockLoadShare : loadShare; +const loadShareModule = process.env.NODE_ENV === 'test' ? mockLoadShare : loadShare; export const queryClient = new QueryClient(); @@ -95,11 +78,7 @@ function FederatedRoute({ scope, module, app }: FederatedRouteProps) { }); return ( - ( - - )} - > + }> - ), + element: , })), [JSON.stringify(federatedRoutes)], ); @@ -150,11 +127,7 @@ function InternalRouter() { return ( {routes.map((route) => ( - + ))} ); @@ -200,11 +173,7 @@ function InternalApp() { ); } -export function WithInitFederationProviders({ - children, -}: { - children: React.ReactNode; -}) { +export function WithInitFederationProviders({ children }: { children: React.ReactNode }) { const { config: shellConfig } = useShellConfig(); return ( @@ -224,21 +193,12 @@ const AppProviderWrapper = () => { FallbackComponent={({ error }) => { if ('en' in error && 'fr' in error) { return ( - + ); } if (error instanceof Error) { if (error.message.includes('AbortError: The operation was aborted')) { - return ( - <> - Loading of the application has been aborted due to a redirection - in progress. - - ); + return <>Loading of the application has been aborted due to a redirection in progress.; } return ( ; }; -export const NotificationCenterContext = - createContext(null); +export const NotificationCenterContext = createContext(null); type NotificationCenterProviderProps = { children: ReactNode; @@ -46,18 +45,11 @@ export type NotificationCenterActions = const LOCAL_STORAGE_NOTIFICATION_PREFIX = 'notification-center__'; -const NotificationCenterProvider: FC = ({ - children, -}) => { - const notificationReducer = ( - state: InternalNotification[], - action: NotificationCenterActions, - ) => { +const NotificationCenterProvider: FC = ({ children }) => { + const notificationReducer = (state: InternalNotification[], action: NotificationCenterActions) => { switch (action.type) { case NotificationActionType.PUBLISH: - const storedReadOn = localStorage.getItem( - LOCAL_STORAGE_NOTIFICATION_PREFIX + action.notification.id, - ); + const storedReadOn = localStorage.getItem(LOCAL_STORAGE_NOTIFICATION_PREFIX + action.notification.id); const readOn = storedReadOn ? new Date(storedReadOn) : undefined; // if the Notification is already stored, update it with the newly published one. if (state.find((n) => n.id === action.notification.id)) { @@ -69,16 +61,9 @@ const NotificationCenterProvider: FC = ({ }); } // sort the Notifications by the createdOn date - const index = state.findIndex( - (n) => - n.createdOn.getTime() > action.notification.createdOn.getTime(), - ); + const index = state.findIndex((n) => n.createdOn.getTime() > action.notification.createdOn.getTime()); - return [ - ...state.slice(0, index + 1), - { ...action.notification, readOn }, - ...state.slice(index + 1), - ]; + return [...state.slice(0, index + 1), { ...action.notification, readOn }, ...state.slice(index + 1)]; case NotificationActionType.UNPUBLISH: localStorage.removeItem(LOCAL_STORAGE_NOTIFICATION_PREFIX + action.id); @@ -87,10 +72,7 @@ const NotificationCenterProvider: FC = ({ const date = new Date(); return state.map((n) => { if (!n.readOn) { - localStorage.setItem( - LOCAL_STORAGE_NOTIFICATION_PREFIX + n.id, - date.toISOString(), - ); + localStorage.setItem(LOCAL_STORAGE_NOTIFICATION_PREFIX + n.id, date.toISOString()); return { ...n, readOn: date }; } return n; diff --git a/shell-ui/src/QueryClientProvider.tsx b/shell-ui/src/QueryClientProvider.tsx index 915ba3a36c..15596b3cc4 100644 --- a/shell-ui/src/QueryClientProvider.tsx +++ b/shell-ui/src/QueryClientProvider.tsx @@ -1,11 +1,7 @@ -import { - QueryClient, - QueryClientProvider as BaseQueryClientProvider, -} from 'react-query'; +import { QueryClient, QueryClientProvider as BaseQueryClientProvider } from 'react-query'; -export const QueryClientProvider = - BaseQueryClientProvider as React.ComponentType<{ - client: QueryClient; - contextSharing?: boolean; - children?: React.ReactNode; - }>; +export const QueryClientProvider = BaseQueryClientProvider as React.ComponentType<{ + client: QueryClient; + contextSharing?: boolean; + children?: React.ReactNode; +}>; diff --git a/shell-ui/src/alerts/AlertProvider.tsx b/shell-ui/src/alerts/AlertProvider.tsx index fb05e85c5b..6e43c94117 100644 --- a/shell-ui/src/alerts/AlertProvider.tsx +++ b/shell-ui/src/alerts/AlertProvider.tsx @@ -27,9 +27,7 @@ export default function AlertProvider({ }); return ( - {query.status === 'loading' && ( - - )} + {query.status === 'loading' && } {query.status !== 'loading' && children} ); diff --git a/shell-ui/src/alerts/Alerts.spec.tsx b/shell-ui/src/alerts/Alerts.spec.tsx index 48af353ca4..9fcf4dbf95 100644 --- a/shell-ui/src/alerts/Alerts.spec.tsx +++ b/shell-ui/src/alerts/Alerts.spec.tsx @@ -16,8 +16,7 @@ const testService = 'http://10.0.0.1/api/alertmanager'; const alerts = [ { annotations: { - description: - 'Cluster has overcommitted CPU resource requests for Pods and cannot tolerate node failure.', + description: 'Cluster has overcommitted CPU resource requests for Pods and cannot tolerate node failure.', runbook_url: 'https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-kubecpuovercommit', summary: 'Cluster has overcommitted CPU resource requests.', @@ -46,8 +45,7 @@ const alerts = [ }, { annotations: { - description: - 'Cluster has overcommitted memory resource requests for Pods and cannot tolerate node failure.', + description: 'Cluster has overcommitted memory resource requests for Pods and cannot tolerate node failure.', runbook_url: 'https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-kubememoryovercommit', summary: 'Cluster has overcommitted memory resource requests.', @@ -141,9 +139,7 @@ describe('alerts', () => { }); await waitForNextUpdate(); //V - expect( - result.current.alerts.map((alert) => alert.originalAlert), - ).toStrictEqual(alerts); + expect(result.current.alerts.map((alert) => alert.originalAlert)).toStrictEqual(alerts); }); afterAll(() => server.close()); }); diff --git a/shell-ui/src/alerts/alertHooks.test.tsx b/shell-ui/src/alerts/alertHooks.test.tsx index 45f81611a4..8c0da34831 100644 --- a/shell-ui/src/alerts/alertHooks.test.tsx +++ b/shell-ui/src/alerts/alertHooks.test.tsx @@ -11,8 +11,7 @@ const testService = 'http://10.0.0.1/api/alertmanager'; const VOLUME_DEGRADED_ALERT = { annotations: { - description: - 'Filesystem on /dev/vdc at 192.168.1.29:9100 has only 3.13% available space left.', + description: 'Filesystem on /dev/vdc at 192.168.1.29:9100 has only 3.13% available space left.', runbook_url: 'https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-nodefilesystemalmostoutofspace', summary: 'Filesystem has less than 5% space left.', @@ -33,8 +32,7 @@ const VOLUME_DEGRADED_ALERT = { }; const VOLUME_AT_RISK_ALERT = { annotations: { - description: - 'Filesystem on /dev/vdc at 192.168.1.29:9100 has only 3.13% available space left.', + description: 'Filesystem on /dev/vdc at 192.168.1.29:9100 has only 3.13% available space left.', runbook_url: 'https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-nodefilesystemalmostoutofspace', summary: 'Filesystem has less than 5% space left.', @@ -55,8 +53,7 @@ const VOLUME_AT_RISK_ALERT = { }; const VOLUME_AT_RISK_ALERT_NON_ACTIVE = { annotations: { - description: - 'Filesystem on /dev/vdc at 192.168.1.29:9100 has only 3.13% available space left.', + description: 'Filesystem on /dev/vdc at 192.168.1.29:9100 has only 3.13% available space left.', runbook_url: 'https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-nodefilesystemalmostoutofspace', summary: 'Filesystem has less than 5% space left.', diff --git a/shell-ui/src/alerts/alertHooks.ts b/shell-ui/src/alerts/alertHooks.ts index 0790969b15..e86defe0b4 100644 --- a/shell-ui/src/alerts/alertHooks.ts +++ b/shell-ui/src/alerts/alertHooks.ts @@ -30,10 +30,7 @@ export const getServicesAlertSelectors = (): FilterLabels => { }; export const getK8SMasterAlertSelectors = (): FilterLabels => { return { - alertname: [ - 'KubernetesControlPlaneAtRisk', - 'KubernetesControlPlaneDegraded', - ], + alertname: ['KubernetesControlPlaneAtRisk', 'KubernetesControlPlaneDegraded'], }; }; export const getBootstrapAlertSelectors = (): FilterLabels => { @@ -94,9 +91,7 @@ export function useAlerts(filters?: FilterLabels) { const query = useContext(AlertContext); if (!query) { - throw new Error( - 'The useAlerts hook can only be used within AlertProvider.', - ); + throw new Error('The useAlerts hook can only be used within AlertProvider.'); } else if (query.status === 'success') { const newQuery = { ...query, alerts: filterAlerts(query.data, filters) }; delete newQuery.data; diff --git a/shell-ui/src/alerts/index.ts b/shell-ui/src/alerts/index.ts index 3aaaff9fee..f802f457e6 100644 --- a/shell-ui/src/alerts/index.ts +++ b/shell-ui/src/alerts/index.ts @@ -1,2 +1,2 @@ export * from './AlertProvider'; -export * from './alertHooks'; \ No newline at end of file +export * from './alertHooks'; diff --git a/shell-ui/src/alerts/services/alertManager.ts b/shell-ui/src/alerts/services/alertManager.ts index 2f1d928b70..56d5ea4a06 100644 --- a/shell-ui/src/alerts/services/alertManager.ts +++ b/shell-ui/src/alerts/services/alertManager.ts @@ -1,10 +1,4 @@ -import { - removeWarningAlerts, - formatActiveAlerts, - sortAlerts, - STATUS_CRITICAL, - STATUS_HEALTH, -} from './alertUtils'; +import { removeWarningAlerts, formatActiveAlerts, sortAlerts, STATUS_CRITICAL, STATUS_HEALTH } from './alertUtils'; export type PrometheusAlert = { annotations: Record; receivers: { @@ -56,9 +50,7 @@ export const checkActiveAlertProvider = (): Promise<{ // depends on Watchdog to see the if Alertmanager is up // @ts-expect-error - FIXME when you are working on it return getAlerts().then((result) => { - const watchdog = result.find( - (alert) => alert.labels.alertname === 'Watchdog', - ); + const watchdog = result.find((alert) => alert.labels.alertname === 'Watchdog'); if (watchdog) return STATUS_HEALTH; else return STATUS_CRITICAL; }); diff --git a/shell-ui/src/alerts/services/alertUtils.ts b/shell-ui/src/alerts/services/alertUtils.ts index 2de0107a5d..acab23d983 100644 --- a/shell-ui/src/alerts/services/alertUtils.ts +++ b/shell-ui/src/alerts/services/alertUtils.ts @@ -34,10 +34,7 @@ export const compareHealth = (status1, status2) => { }; // Return boolean if the two alerts have the same labels but different severity -const isSameAlertWithDiffSeverity = ( - alert1: AlertLabels, - alert2: AlertLabels, -): boolean => { +const isSameAlertWithDiffSeverity = (alert1: AlertLabels, alert2: AlertLabels): boolean => { // filter out the `severity`, `summary` and `children`property function replacer(key, value) { if (key === 'severity' || key === 'summary' || key === 'children') { @@ -62,10 +59,7 @@ export const removeWarningAlerts = (alerts: Alert[]): Alert[] => { } // check if there is a critical alert with the same labels const isSameAlert = alerts.find((a) => { - return ( - a.severity === STATUS_CRITICAL && - isSameAlertWithDiffSeverity(a.labels, alert.labels) - ); + return a.severity === STATUS_CRITICAL && isSameAlertWithDiffSeverity(a.labels, alert.labels); }); return !isSameAlert; }); @@ -93,15 +87,11 @@ export const formatActiveAlerts = (alerts: Array): Alert[] => { startsAt: alert.startsAt, endsAt: alert.endsAt || new Date().toISOString(), severity: alert.labels.severity, - documentationUrl: - (alert.annotations && alert.annotations.runbook_url) || '', + documentationUrl: (alert.annotations && alert.annotations.runbook_url) || '', labels: { ...alert.labels, ...alert.annotations, - selectors: - (alert.annotations.selectors && - alert.annotations.selectors.split(',')) || - [], + selectors: (alert.annotations.selectors && alert.annotations.selectors.split(',')) || [], }, childrenJsonPath: alert.annotations && alert.annotations.childrenJsonPath, originalAlert: alert, @@ -118,10 +108,7 @@ export const formatActiveAlerts = (alerts: Array): Alert[] => { e.g. alertname: [NODE_FILESYSTEM_SPACE_FILLINGUP, NODE_FILESYSTEM_ALMOST_OUTOF_SPACE, NODE_FILESYSTEM_FILES_FILLINGUP, NODE_FILESYSTEM_ALMOST_OUTOF_FILES] */ -export const isAlertSelected = ( - labels: AlertLabels, - filters: FilterLabels, -): boolean => { +export const isAlertSelected = (labels: AlertLabels, filters: FilterLabels): boolean => { return Object.getOwnPropertyNames(filters) .map((key) => { if (!filters[key] || !labels[key]) return false; @@ -149,10 +136,7 @@ export const isAlertSelected = ( alerts: the formatted alert returned by AM or Loki API. filters: can be optional, meaning to get all the alerts. */ -export const filterAlerts = ( - alerts: Alert[], - filters?: FilterLabels, -): Alert[] => { +export const filterAlerts = (alerts: Alert[], filters?: FilterLabels): Alert[] => { if (!alerts) return []; if (!filters) { @@ -173,10 +157,7 @@ export const dateIsBetween = (start: string, end: string, date: string) => { return true; } else return false; }; -export const getHealthStatus = ( - alerts: Alert[], - activeOn: string = new Date().toISOString(), -): Health => { +export const getHealthStatus = (alerts: Alert[], activeOn: string = new Date().toISOString()): Health => { if (!alerts.length) return STATUS_HEALTH; const severityArr = alerts.map((alert) => { if (dateIsBetween(alert.startsAt, alert.endsAt, activeOn)) { @@ -186,12 +167,9 @@ export const getHealthStatus = ( return ''; }); if (severityArr.every((item) => item === '')) return STATUS_HEALTH; - if (severityArr.find((severity) => severity === 'critical')) - return STATUS_CRITICAL; - else if (severityArr.find((severity) => severity === 'warning')) - return STATUS_WARNING; - else if (severityArr.find((severity) => severity === 'info')) - return STATUS_INFO; + if (severityArr.find((severity) => severity === 'critical')) return STATUS_CRITICAL; + else if (severityArr.find((severity) => severity === 'warning')) return STATUS_WARNING; + else if (severityArr.find((severity) => severity === 'info')) return STATUS_INFO; return STATUS_NONE; }; @@ -209,17 +187,12 @@ export const formatHistoryAlerts = (streamValues: StreamValue): Alert[] => { summary: (alert.annotations && alert.annotations.summary) || '', description: alert.annotations.description || alert.annotations.message, startsAt: alert.startsAt, - endsAt: - alert.status === 'firing' ? new Date().toISOString() : alert.endsAt, + endsAt: alert.status === 'firing' ? new Date().toISOString() : alert.endsAt, severity: alert.labels.severity, - documentationUrl: - (alert.annotations && alert.annotations.runbook_url) || '', + documentationUrl: (alert.annotations && alert.annotations.runbook_url) || '', labels: { ...alert.labels, - selectors: - (alert.annotations.selectors && - alert.annotations.selectors.split(',')) || - [], + selectors: (alert.annotations.selectors && alert.annotations.selectors.split(',')) || [], }, originalAlert: alert, }, diff --git a/shell-ui/src/alerts/services/loki.ts b/shell-ui/src/alerts/services/loki.ts index 55730165bd..ca5f02d70d 100644 --- a/shell-ui/src/alerts/services/loki.ts +++ b/shell-ui/src/alerts/services/loki.ts @@ -17,22 +17,13 @@ type LokiQueryResult = { }; // by default to get the last 7day alerts from Loki export function getLast7DaysAlerts(lokiUrl: string): Promise { - const start = new Date( - new Date().getTime() - 7 * 24 * 60 * 60 * 1000, - ).toISOString(); + const start = new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000).toISOString(); const end = new Date().toISOString(); return getAlertsLoki(lokiUrl, start, end); } // customise the `start` and `end` time to retrieve the history alerts -export function getAlertsLoki( - lokiUrl: string, - start: string, - end: string, -): Promise { - return fetch( - lokiUrl + - `/loki/api/v1/query_range?start=${start}&end=${end}&query=${METALK8S_HISTORY_ALERTS_QUERY}`, - ) +export function getAlertsLoki(lokiUrl: string, start: string, end: string): Promise { + return fetch(lokiUrl + `/loki/api/v1/query_range?start=${start}&end=${end}&query=${METALK8S_HISTORY_ALERTS_QUERY}`) .then((r) => { if (r.ok) { return r.json(); @@ -68,4 +59,4 @@ export function isLokiReady(lokiUrl: string): Promise { return resolve === 'ready'; }); -} \ No newline at end of file +} diff --git a/shell-ui/src/auth/AuthConfigProvider.tsx b/shell-ui/src/auth/AuthConfigProvider.tsx index 763e19b81e..b3e162304e 100644 --- a/shell-ui/src/auth/AuthConfigProvider.tsx +++ b/shell-ui/src/auth/AuthConfigProvider.tsx @@ -1,9 +1,6 @@ import React from 'react'; import { createContext, useContext, useState } from 'react'; -import type { - OIDCConfig, - OAuth2ProxyConfig, -} from '../initFederation/ConfigurationProviders'; +import type { OIDCConfig, OAuth2ProxyConfig } from '../initFederation/ConfigurationProviders'; const AuthConfigContext = createContext(null); export const useAuthConfig = (): { authConfig: OAuth2ProxyConfig | OIDCConfig | undefined; @@ -17,11 +14,7 @@ export const useAuthConfig = (): { return contextValue; }; -export function AuthConfigProvider({ - children, -}: { - children: React.ReactNode; -}) { +export function AuthConfigProvider({ children }: { children: React.ReactNode }) { const [authConfig, setAuthConfig] = useState(undefined); return ( { - const queryParamas = new URLSearchParams(window.location.search); + return this._getMetadataProperty('authorization_endpoint').then((authorizationEndpoint) => { + const queryParamas = new URLSearchParams(window.location.search); - if (!queryParamas.has('displayLoginChoice')) { - return authorizationEndpoint + '?connector_id=' + connectorId; - } + if (!queryParamas.has('displayLoginChoice')) { + return authorizationEndpoint + '?connector_id=' + connectorId; + } - return authorizationEndpoint as string; - }, - ); + return authorizationEndpoint as string; + }); } } @@ -264,14 +254,9 @@ function useInternalLogout( if (authConfig.providerLogout) { userManager.signoutRedirect().catch((e) => { if (e.message === 'no end session endpoint') { - console.log( - "OIDC provider doesn't support end session endpoint, fallback to clearing document cookies", - ); + console.log("OIDC provider doesn't support end session endpoint, fallback to clearing document cookies"); document.cookie.split(';').forEach(function (c) { - document.cookie = - c.trim().split('=')[0] + - '=;' + - 'expires=Thu, 01 Jan 1970 00:00:00 UTC;'; + document.cookie = c.trim().split('=')[0] + '=;' + 'expires=Thu, 01 Jan 1970 00:00:00 UTC;'; }); } else { console.error(e); diff --git a/shell-ui/src/auth/FirstTimeLoginProvider.tsx b/shell-ui/src/auth/FirstTimeLoginProvider.tsx index 7cce816657..44488051e4 100644 --- a/shell-ui/src/auth/FirstTimeLoginProvider.tsx +++ b/shell-ui/src/auth/FirstTimeLoginProvider.tsx @@ -12,41 +12,27 @@ export const useFirstTimeLogin = (): { const contextValue = React.useContext(FirstTimeLoginContext); if (contextValue === null) { - throw new Error( - "Can't use useFirstTimeLogin outside FirstTimeLoginProvider", - ); + throw new Error("Can't use useFirstTimeLogin outside FirstTimeLoginProvider"); } return contextValue; }; -export function FirstTimeLoginProvider({ - children, -}: { - children: React.ReactNode; -}) { - const [firstTimeLogin, setFirstTimeLogin] = useState( - undefined, - ); +export function FirstTimeLoginProvider({ children }: { children: React.ReactNode }) { + const [firstTimeLogin, setFirstTimeLogin] = useState(undefined); const { userData } = useAuth(); const userID = userData?.id; const ALREADY_LOGGED_IN_USER_IDS = 'alreadyLoggedInUserIds'; // Store the userID in the LocalStorage to maintain a record of all users who have logged in from this machine - const ids = useMemo( - () => localStorage.getItem(ALREADY_LOGGED_IN_USER_IDS)?.split(',') || [], - [], - ); + const ids = useMemo(() => localStorage.getItem(ALREADY_LOGGED_IN_USER_IDS)?.split(',') || [], []); // Because of the way the OIDC library works there is a redirect to the login page, which causes the firstTimeLogin set to false when redirect to the UI. // So we have to check if it is in the process of signing in and if so, don't set the firstTimeLogin to false. const location = useLocation(); const searchParams = new URLSearchParams(location.search); - const isSigningIn = - searchParams.has('code') && - searchParams.has('state') && - searchParams.has('session_state'); + const isSigningIn = searchParams.has('code') && searchParams.has('state') && searchParams.has('session_state'); useEffect(() => { if (isSigningIn) { return; diff --git a/shell-ui/src/auth/useFirstTimeLogin.spec.tsx b/shell-ui/src/auth/useFirstTimeLogin.spec.tsx index 9ea7286ef8..8326ad3406 100644 --- a/shell-ui/src/auth/useFirstTimeLogin.spec.tsx +++ b/shell-ui/src/auth/useFirstTimeLogin.spec.tsx @@ -22,9 +22,7 @@ describe('useFirstTimeLogin hook', () => { //S+E const { result } = renderHook(() => useFirstTimeLogin()); //V - expect(result.error).toEqual( - Error("Can't use useFirstTimeLogin outside FirstTimeLoginProvider"), - ); + expect(result.error).toEqual(Error("Can't use useFirstTimeLogin outside FirstTimeLoginProvider")); }); it('should return firstTimeLogin as true if the user is logging in for the first time', async () => { diff --git a/shell-ui/src/index.css b/shell-ui/src/index.css index c7dafad021..5c9cccbf8e 100644 --- a/shell-ui/src/index.css +++ b/shell-ui/src/index.css @@ -1,14 +1,16 @@ -@import '@scality/core-ui/dist/index.css'; +@import "@scality/core-ui/dist/index.css"; /* Set base font size to achieve responsive font */ -html { font-size: max(14px, calc(0.2em + 0.8vw)); } +html { + font-size: max(14px, calc(0.2em + 0.8vw)); +} body { margin: 0; padding: 0; - font-family: 'Lato', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; + font-family: + "Lato", -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", + "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } @@ -20,9 +22,9 @@ h4, h5, h6, input { - font-family: 'Lato', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; + font-family: + "Lato", -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", + "Helvetica Neue", sans-serif; } .main { @@ -30,28 +32,29 @@ input { } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; } /* Lato-Regular */ @font-face { - font-family: 'Lato'; + font-family: "Lato"; font-style: normal; font-weight: normal; - src: local(''), - url('../public/brand/assets/fonts/lato/Lato-Regular.woff2') format('woff2'), + src: + local(""), + url("../public/brand/assets/fonts/lato/Lato-Regular.woff2") format("woff2"), /* Chrome 26+, Opera 23+, Firefox 39+ */ - url('../public/brand/assets/fonts/lato/Lato-Regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + url("../public/brand/assets/fonts/lato/Lato-Regular.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ } /* Lato-Bold */ @font-face { - font-family: 'Lato'; + font-family: "Lato"; font-style: normal; font-weight: bold; - src: local(''), - url('../public/brand/assets/fonts/lato/Lato-Bold.woff2') format('woff2'), + src: + local(""), + url("../public/brand/assets/fonts/lato/Lato-Bold.woff2") format("woff2"), /* Chrome 26+, Opera 23+, Firefox 39+ */ - url('../public/brand/assets/fonts/lato/Lato-Bold.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + url("../public/brand/assets/fonts/lato/Lato-Bold.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ } diff --git a/shell-ui/src/initFederation/ConfigurationProviders.spec.tsx b/shell-ui/src/initFederation/ConfigurationProviders.spec.tsx index 69be961284..4fd10f468d 100644 --- a/shell-ui/src/initFederation/ConfigurationProviders.spec.tsx +++ b/shell-ui/src/initFederation/ConfigurationProviders.spec.tsx @@ -5,10 +5,7 @@ import { setupServer } from 'msw/node'; import { QueryClient } from 'react-query'; import { QueryClientProvider } from '../QueryClientProvider'; import type { BuildtimeWebFinger, View } from './ConfigurationProviders'; -import { - ConfigurationProvider, - useFederatedRoutes, -} from './ConfigurationProviders'; +import { ConfigurationProvider, useFederatedRoutes } from './ConfigurationProviders'; import { UIListProvider } from './UIListProvider'; const testService = 'http://10.0.0.1/uilist.json'; @@ -48,10 +45,7 @@ const externalHookUI = { const singleDeployedUI = [testLocalUI]; const allDeployedUIs = [testLocalUI, addonUIV1, addonUIV2, externalHookUI]; -const createMockBuildConfig = ( - kind: string, - views: Record, -): BuildtimeWebFinger => ({ +const createMockBuildConfig = (kind: string, views: Record): BuildtimeWebFinger => ({ kind: 'MicroAppConfiguration', apiVersion: 'ui.scality.com/v1alpha1', metadata: { @@ -81,33 +75,27 @@ const server = setupServer( rest.get(`${testService}`, (req, res, ctx) => { return res(ctx.json(singleDeployedUI)); }), - rest.get( - `http://test.local.test/.well-known/micro-app-configuration`, - (req, res, ctx) => { - return res( - ctx.json( - createMockBuildConfig('test-ui', { - overview: { - path: '/', - exact: true, - label: { - en: 'Overview', - fr: 'Vue générale', - }, - module: './FederableApp', - scope: 'artesca', + rest.get(`http://test.local.test/.well-known/micro-app-configuration`, (req, res, ctx) => { + return res( + ctx.json( + createMockBuildConfig('test-ui', { + overview: { + path: '/', + exact: true, + label: { + en: 'Overview', + fr: 'Vue générale', }, - }), - ), - ); - }, - ), - rest.get( - `http://test.local.test/.well-known/runtime-app-configuration`, - (req, res, ctx) => { - return res(ctx.json(createRuntimeAppConfig('test-ui', 'test.local'))); - }, - ), + module: './FederableApp', + scope: 'artesca', + }, + }), + ), + ); + }), + rest.get(`http://test.local.test/.well-known/runtime-app-configuration`, (req, res, ctx) => { + return res(ctx.json(createRuntimeAppConfig('test-ui', 'test.local'))); + }), ); describe('useFederatedRoutes', () => { @@ -161,66 +149,67 @@ describe('useFederatedRoutes', () => { it('should retrieve federated routes with same kind', async () => { const configs = { - 'http://test.local.test/.well-known/micro-app-configuration': - createMockBuildConfig('test-ui', { - overview: { - path: '/', - exact: true, - label: { - en: 'Overview', - fr: 'Vue générale', - }, - module: './FederableApp', - scope: 'artesca', + 'http://test.local.test/.well-known/micro-app-configuration': createMockBuildConfig('test-ui', { + overview: { + path: '/', + exact: true, + label: { + en: 'Overview', + fr: 'Vue générale', }, - }), - 'http://test.local.test/.well-known/runtime-app-configuration': - createRuntimeAppConfig('test-ui', 'test.local'), - 'http://addon-v1.local.test/.well-known/micro-app-configuration': - createMockBuildConfig('addon-ui', { - addon1: { - path: '/addon-v1', - exact: true, - label: { - en: 'Addon v1', - fr: 'Addon v1', - }, - module: './AddonApp', - scope: 'addon1', + module: './FederableApp', + scope: 'artesca', + }, + }), + 'http://test.local.test/.well-known/runtime-app-configuration': createRuntimeAppConfig('test-ui', 'test.local'), + 'http://addon-v1.local.test/.well-known/micro-app-configuration': createMockBuildConfig('addon-ui', { + addon1: { + path: '/addon-v1', + exact: true, + label: { + en: 'Addon v1', + fr: 'Addon v1', }, - }), - 'http://addon-v1.local.test/.well-known/runtime-app-configuration': - createRuntimeAppConfig('addon-ui', 'addon-v1.local'), - 'http://addon-v2.local.test/.well-known/micro-app-configuration': - createMockBuildConfig('addon-ui', { - addon2: { - path: '/addon-v2', - exact: true, - label: { - en: 'Addon v2', - fr: 'Addon v2', - }, - module: './AddonApp', - scope: 'addon2', + module: './AddonApp', + scope: 'addon1', + }, + }), + 'http://addon-v1.local.test/.well-known/runtime-app-configuration': createRuntimeAppConfig( + 'addon-ui', + 'addon-v1.local', + ), + 'http://addon-v2.local.test/.well-known/micro-app-configuration': createMockBuildConfig('addon-ui', { + addon2: { + path: '/addon-v2', + exact: true, + label: { + en: 'Addon v2', + fr: 'Addon v2', }, - }), - 'http://addon-v2.local.test/.well-known/runtime-app-configuration': - createRuntimeAppConfig('addon-ui', 'addon-v2.local'), - 'http://external-hook.local.test/.well-known/micro-app-configuration': - createMockBuildConfig('external-hook-ui', { - externalHook: { - path: '/external-hook', - exact: true, - label: { - en: 'External hook', - fr: 'External hook', - }, - module: './ExternalHookApp', - scope: 'external-hook', + module: './AddonApp', + scope: 'addon2', + }, + }), + 'http://addon-v2.local.test/.well-known/runtime-app-configuration': createRuntimeAppConfig( + 'addon-ui', + 'addon-v2.local', + ), + 'http://external-hook.local.test/.well-known/micro-app-configuration': createMockBuildConfig('external-hook-ui', { + externalHook: { + path: '/external-hook', + exact: true, + label: { + en: 'External hook', + fr: 'External hook', }, - }), - 'http://external-hook.local.test/.well-known/runtime-app-configuration': - createRuntimeAppConfig('external-hook-ui', 'external-hook.local'), + module: './ExternalHookApp', + scope: 'external-hook', + }, + }), + 'http://external-hook.local.test/.well-known/runtime-app-configuration': createRuntimeAppConfig( + 'external-hook-ui', + 'external-hook.local', + ), }; server.use( rest.get(`${testService}`, (req, res, ctx) => { @@ -328,22 +317,12 @@ describe('useFederatedRoutes', () => { rest.get(`${testService}`, (req, res, ctx) => { return res(ctx.json(singleDeployedUI)); }), - rest.get( - `http://test.local.test/.well-known/micro-app-configuration`, - (req, res, ctx) => { - return res(ctx.json(createMockBuildConfig('test-ui', {}))); - }, - ), - rest.get( - `http://test.local.test/.well-known/runtime-app-configuration`, - (req, res, ctx) => { - return res( - ctx.json( - createRuntimeAppConfig('wrong-kind-test-ui', 'test.local'), - ), - ); - }, - ), + rest.get(`http://test.local.test/.well-known/micro-app-configuration`, (req, res, ctx) => { + return res(ctx.json(createMockBuildConfig('test-ui', {}))); + }), + rest.get(`http://test.local.test/.well-known/runtime-app-configuration`, (req, res, ctx) => { + return res(ctx.json(createRuntimeAppConfig('wrong-kind-test-ui', 'test.local'))); + }), ); const { result } = renderHook(() => useFederatedRoutes(), { diff --git a/shell-ui/src/initFederation/ConfigurationProviders.tsx b/shell-ui/src/initFederation/ConfigurationProviders.tsx index 848623a67f..4f55208828 100644 --- a/shell-ui/src/initFederation/ConfigurationProviders.tsx +++ b/shell-ui/src/initFederation/ConfigurationProviders.tsx @@ -76,26 +76,20 @@ export function useConfigRetriever(): { configType: T extends 'build' ? 'build' : 'run'; name: string; url?: string; - }) => - | (T extends 'build' ? EnrichedBuildtimeWebFinger : RuntimeWebFinger) - | null; + }) => (T extends 'build' ? EnrichedBuildtimeWebFinger : RuntimeWebFinger) | null; } { const { state: webFingerContextValue } = useWebFingersStore(); const { retrieveDeployedApps } = useDeployedAppsRetriever(); if (!webFingerContextValue) { - throw new Error( - "Can't use useConfigRetriever outside of ConfigurationProvider", - ); + throw new Error("Can't use useConfigRetriever outside of ConfigurationProvider"); } return { // @ts-expect-error - impossible to type retrieveConfiguration: ({ configType, name, url }) => { if (configType !== 'build' && configType !== 'run') { - throw new Error( - `Invalid configType : it should be build or run but received ${configType}`, - ); + throw new Error(`Invalid configType : it should be build or run but received ${configType}`); } const apps = retrieveDeployedApps({ @@ -110,25 +104,17 @@ export function useConfigRetriever(): { .filter((webFinger) => { return ( webFinger.status === 'success' && - ((configType === 'build' && - webFinger.data.kind === 'MicroAppConfiguration') || - (configType === 'run' && - webFinger.data.kind === 'MicroAppRuntimeConfiguration')) + ((configType === 'build' && webFinger.data.kind === 'MicroAppConfiguration') || + (configType === 'run' && webFinger.data.kind === 'MicroAppRuntimeConfiguration')) ); }) .map((webFinger) => webFinger.data); ///TODO validate web fingers against JsonSchemas const config = configs.find((webFinger) => { - if ( - webFinger.kind === 'MicroAppRuntimeConfiguration' && - webFinger.metadata.name === name - ) { + if (webFinger.kind === 'MicroAppRuntimeConfiguration' && webFinger.metadata.name === name) { return true; } - if ( - webFinger.kind === 'MicroAppConfiguration' && - webFinger.metadata.kind === apps[0].kind - ) { + if (webFinger.kind === 'MicroAppConfiguration' && webFinger.metadata.kind === apps[0].kind) { if (url) { return webFinger.metadata.url === url; } @@ -166,9 +152,7 @@ export function useConfig>({ }: { configType: T extends 'build' ? 'build' : 'run'; name: string; -}): null | T extends 'build' - ? EnrichedBuildtimeWebFinger - : RuntimeWebFinger { +}): null | T extends 'build' ? EnrichedBuildtimeWebFinger : RuntimeWebFinger { // Utiliser le nouveau hook useWebFingersStore const { state: webFingerContextValue } = useWebFingersStore(); @@ -213,10 +197,8 @@ export type ViewDefinition = FederatedView | NonFederatedView; // External store implementation class WebFingersStore { private listeners: Set<() => void> = new Set(); - private _state: UseQueryResult< - EnrichedBuildtimeWebFinger | RuntimeWebFinger>, - unknown - >[] = []; + private _state: UseQueryResult>, unknown>[] = + []; subscribe = (listener: () => void) => { this.listeners.add(listener); @@ -230,29 +212,17 @@ class WebFingersStore { }; private isStateEqual( - currentState: UseQueryResult< - EnrichedBuildtimeWebFinger | RuntimeWebFinger>, - unknown - >[], - newState: UseQueryResult< - EnrichedBuildtimeWebFinger | RuntimeWebFinger>, - unknown - >[], + currentState: UseQueryResult>, unknown>[], + newState: UseQueryResult>, unknown>[], ) { return ( currentState.length === newState.length && - currentState.every( - (item, index) => - JSON.stringify(item) === JSON.stringify(newState[index]), - ) + currentState.every((item, index) => JSON.stringify(item) === JSON.stringify(newState[index])) ); } updateState = ( - newState: UseQueryResult< - EnrichedBuildtimeWebFinger | RuntimeWebFinger>, - unknown - >[], + newState: UseQueryResult>, unknown>[], ) => { if (!this.isStateEqual(this._state, newState)) { this._state = newState; @@ -264,10 +234,7 @@ class WebFingersStore { const webFingersStore = new WebFingersStore(); export function useWebFingersStore() { - const state = useSyncExternalStore( - webFingersStore.subscribe, - webFingersStore.getState, - ); + const state = useSyncExternalStore(webFingersStore.subscribe, webFingersStore.getState); return { state, @@ -321,11 +288,7 @@ export function useDiscoveredViews(): ViewDefinition[] { name: app.name, }); - if ( - appBuildConfig && - appBuildConfig.spec.views && - appBuildConfig.spec.views[navbarEntry.view] - ) { + if (appBuildConfig && appBuildConfig.spec.views && appBuildConfig.spec.views[navbarEntry.view]) { const view = appBuildConfig.spec.views[navbarEntry.view]; return [ { @@ -357,9 +320,7 @@ export function useFederatedRoutes(): FederatedRoute[] { return deployedApps.flatMap((app) => { // Validate base path once per app during iteration if (app.appHistoryBasePath.endsWith('/')) { - throw new Error( - `appHistoryBasePath of app ${app.name} ends with a /, this is not allowed`, - ); + throw new Error(`appHistoryBasePath of app ${app.name} ends with a /, this is not allowed`); } const appBuildConfig = retrieveConfiguration<'build'>({ @@ -372,15 +333,13 @@ export function useFederatedRoutes(): FederatedRoute[] { return []; } - const routesFromSingleApp = Object.entries(appBuildConfig.spec.views).map( - ([view]) => { - return { - kind: app.kind, - view: appBuildConfig.spec.views[view], - app, - }; - }, - ); + const routesFromSingleApp = Object.entries(appBuildConfig.spec.views).map(([view]) => { + return { + kind: app.kind, + view: appBuildConfig.spec.views[view], + app, + }; + }); return routesFromSingleApp; }); @@ -395,16 +354,16 @@ export const useLinkOpener = () => { openLink: ( to: | { - isExternal?: boolean; - app: SolutionUI; - view: View; - isFederated: true; - } + isExternal?: boolean; + app: SolutionUI; + view: View; + isFederated: true; + } | { - isFederated: false; - isExternal?: boolean; - url: string; - }, + isFederated: false; + isExternal?: boolean; + url: string; + }, ) => { if (to.isExternal) { if (to.isFederated) { @@ -422,11 +381,7 @@ export const useLinkOpener = () => { }, }; }; -export const ConfigurationProvider = ({ - children, -}: { - children: React.ReactNode; -}) => { +export const ConfigurationProvider = ({ children }: { children: React.ReactNode }) => { const { updateWebFingersState } = useWebFingersStore(); const deployedUIs = useDeployedApps(); @@ -436,9 +391,7 @@ export const ConfigurationProvider = ({ queryKey: `${ui.name}.${ui.kind}.${ui.version}-buildtime-WebFinger`, refetchOnWindowFocus: false, queryFn: () => { - return fetch( - `${ui.url}/.well-known/micro-app-configuration?version=${ui.version}`, - ).then(async (r) => { + return fetch(`${ui.url}/.well-known/micro-app-configuration?version=${ui.version}`).then(async (r) => { if (r.ok) { const json: BuildtimeWebFinger = await r.json(); @@ -471,13 +424,9 @@ export const ConfigurationProvider = ({ queryKey: `${ui.name}.${ui.kind}.${ui.version}-runtime-WebFinger`, refetchOnWindowFocus: false, queryFn: () => { - return fetch( - `${ui.url}/.well-known/runtime-app-configuration?version=${ui.version}`, - ).then((r) => { + return fetch(`${ui.url}/.well-known/runtime-app-configuration?version=${ui.version}`).then((r) => { if (r.ok) { - return r.json() as Promise< - RuntimeWebFinger> - >; + return r.json() as Promise>>; } else { return Promise.reject(); } diff --git a/shell-ui/src/initFederation/ShellConfigProvider.tsx b/shell-ui/src/initFederation/ShellConfigProvider.tsx index 7d4b80546e..4cb7128553 100644 --- a/shell-ui/src/initFederation/ShellConfigProvider.tsx +++ b/shell-ui/src/initFederation/ShellConfigProvider.tsx @@ -1,9 +1,6 @@ import { ErrorPage500 } from '@scality/core-ui/dist/components/error-pages/ErrorPage500.component'; import { Loader } from '@scality/core-ui/dist/components/loader/Loader.component'; -import { - CoreUITheme, - CoreUIThemeName, -} from '@scality/core-ui/dist/style/theme'; +import { CoreUITheme, CoreUIThemeName } from '@scality/core-ui/dist/style/theme'; import React, { createContext, useContext } from 'react'; import { useQuery } from 'react-query'; @@ -35,9 +32,7 @@ type CustomShellThemeDescription = { colors: CoreUITheme; }; -type ThemeDescription = - | CoreUIShellThemeDescription - | CustomShellThemeDescription; +type ThemeDescription = CoreUIShellThemeDescription | CustomShellThemeDescription; type Themes = { dark: ThemeDescription; @@ -108,9 +103,7 @@ export const ShellConfigProvider = ({ shellConfigUrl, children }) => { status, }} > - {(status === 'idle' || status === 'loading') && ( - - )} + {(status === 'idle' || status === 'loading') && } {status === 'error' && } {status === 'success' && children} diff --git a/shell-ui/src/initFederation/ShellHistoryProvider.tsx b/shell-ui/src/initFederation/ShellHistoryProvider.tsx index f37ae58754..ed793a28fe 100644 --- a/shell-ui/src/initFederation/ShellHistoryProvider.tsx +++ b/shell-ui/src/initFederation/ShellHistoryProvider.tsx @@ -1,26 +1,18 @@ import { createContext, useContext } from 'react'; import { useNavigate } from 'react-router'; -const ShellHistoryContext = createContext | null>(null); +const ShellHistoryContext = createContext | null>(null); export const useShellHistory = () => { const contextValue = useContext(ShellHistoryContext); if (!contextValue) { - throw new Error( - "useShellHistory can't be used outside of ShellHistoryProvider", - ); + throw new Error("useShellHistory can't be used outside of ShellHistoryProvider"); } return contextValue; }; export const ShellHistoryProvider = ({ children }) => { const history = useNavigate(); - return ( - - {children} - - ); + return {children}; }; diff --git a/shell-ui/src/initFederation/ShellThemeSelectorProvider.tsx b/shell-ui/src/initFederation/ShellThemeSelectorProvider.tsx index e1e095677c..259b05fdef 100644 --- a/shell-ui/src/initFederation/ShellThemeSelectorProvider.tsx +++ b/shell-ui/src/initFederation/ShellThemeSelectorProvider.tsx @@ -1,8 +1,4 @@ -import { - CoreUITheme, - coreUIAvailableThemes, - coreUIAvailableThemesNames, -} from '@scality/core-ui/dist/style/theme'; +import { CoreUITheme, coreUIAvailableThemes, coreUIAvailableThemesNames } from '@scality/core-ui/dist/style/theme'; import React, { useContext, useState } from 'react'; import { useShellConfig } from './ShellConfigProvider'; type ThemeMode = 'dark' | 'light'; @@ -19,9 +15,7 @@ export function useShellThemeSelector(): ThemeContextValues { const themeContext: ThemeContextValues = useContext(ShellThemeContext); if (themeContext === null) { - throw new Error( - "useShellThemeSelector hook can't be use outside ", - ); + throw new Error("useShellThemeSelector hook can't be use outside "); } return { ...themeContext }; @@ -53,27 +47,18 @@ export function ShellThemeSelectorProvider({ } if (!['custom', 'core-ui'].includes(themeDescription.type)) { - throw new Error( - `"${themeDescription.type}" is not a valid theme type, use either custom or core-ui`, - ); + throw new Error(`"${themeDescription.type}" is not a valid theme type, use either custom or core-ui`); } - if ( - themeDescription.type === 'core-ui' && - !coreUIAvailableThemesNames.includes(themeDescription.name) - ) { + if (themeDescription.type === 'core-ui' && !coreUIAvailableThemesNames.includes(themeDescription.name)) { throw new Error( - `${ - themeDescription.name - } does not exist in core-ui themes. Available themes : ${coreUIAvailableThemesNames.join( + `${themeDescription.name} does not exist in core-ui themes. Available themes : ${coreUIAvailableThemesNames.join( ', ', )}`, ); } const selectedTheme = - themeDescription.type === 'custom' - ? themeDescription.colors - : coreUIAvailableThemes[themeDescription.name]; + themeDescription.type === 'custom' ? themeDescription.colors : coreUIAvailableThemes[themeDescription.name]; const assets = { logoPath: themeDescription.logoPath, diff --git a/shell-ui/src/initFederation/UIListProvider.spec.tsx b/shell-ui/src/initFederation/UIListProvider.spec.tsx index dd509e41a5..f8e6226e1d 100644 --- a/shell-ui/src/initFederation/UIListProvider.spec.tsx +++ b/shell-ui/src/initFederation/UIListProvider.spec.tsx @@ -51,11 +51,7 @@ describe('useDeployedApps', () => { // E await waitForNextUpdate(); // V - expect(result.current).toStrictEqual([ - testLocalUI, - testEuWestUI, - anotherUI, - ]); + expect(result.current).toStrictEqual([testLocalUI, testEuWestUI, anotherUI]); }); it('should retrieve an UI selected by name', async () => { const { result, waitForNextUpdate } = renderHook( diff --git a/shell-ui/src/initFederation/UIListProvider.tsx b/shell-ui/src/initFederation/UIListProvider.tsx index 501739479c..c243b873c9 100644 --- a/shell-ui/src/initFederation/UIListProvider.tsx +++ b/shell-ui/src/initFederation/UIListProvider.tsx @@ -31,17 +31,12 @@ type ValidatedUIList = z.infer; const UIListContext = createContext<{ uis: ValidatedUIList | undefined } | null>(null); export function useDeployedAppsRetriever(): { - retrieveDeployedApps: (selectors?: { - kind?: string; - name?: string; - }) => ValidatedUIData[]; + retrieveDeployedApps: (selectors?: { kind?: string; name?: string }) => ValidatedUIData[]; } { const uiListContext = useContext(UIListContext); if (!uiListContext) { - throw new Error( - "Can't use useDeployedAppsRetriever outside of UIListProvider", - ); + throw new Error("Can't use useDeployedAppsRetriever outside of UIListProvider"); } return { @@ -49,8 +44,7 @@ export function useDeployedAppsRetriever(): { if (selectors && uiListContext.uis) { return uiListContext.uis.filter((ui) => { return ( - ((selectors.kind && selectors.kind === ui.kind) || - !selectors.kind) && + ((selectors.kind && selectors.kind === ui.kind) || !selectors.kind) && ((selectors.name && selectors.name === ui.name) || !selectors.name) ); }); @@ -59,10 +53,7 @@ export function useDeployedAppsRetriever(): { }, }; } -export const useDeployedApps = (selectors?: { - kind?: string; - name?: string; -}): ValidatedUIData[] => { +export const useDeployedApps = (selectors?: { kind?: string; name?: string }): ValidatedUIData[] => { const uiListContext = useContext(UIListContext); if (!uiListContext) { @@ -72,13 +63,7 @@ export const useDeployedApps = (selectors?: { const { retrieveDeployedApps } = useDeployedAppsRetriever(); return retrieveDeployedApps(selectors); }; -export const UIListProvider = ({ - children, - discoveryURL, -}: { - children: React.ReactNode; - discoveryURL: string; -}) => { +export const UIListProvider = ({ children, discoveryURL }: { children: React.ReactNode; discoveryURL: string }) => { const { status, data } = useQuery( 'discoveredUIs', async () => { @@ -89,7 +74,7 @@ export const UIListProvider = ({ // Validate the response data with Zod const validatedData = UIListSchema.parse(rawData); // Apply transformations after validation to ensure type safety - const transformedData = validatedData.map(ui => ({ + const transformedData = validatedData.map((ui) => ({ ...ui, url: removeTrailingSlash(ui.url), appHistoryBasePath: removeTrailingSlash(ui.appHistoryBasePath), @@ -119,9 +104,7 @@ export const UIListProvider = ({ uis: data, }} > - {(status === 'loading' || status === 'idle') && ( - - )} + {(status === 'loading' || status === 'idle') && } {status === 'error' && } {status === 'success' && children} diff --git a/shell-ui/src/navbar/InstanceName.spec.tsx b/shell-ui/src/navbar/InstanceName.spec.tsx index 11b0610b08..09150c5fb3 100644 --- a/shell-ui/src/navbar/InstanceName.spec.tsx +++ b/shell-ui/src/navbar/InstanceName.spec.tsx @@ -1,12 +1,6 @@ import React, { PropsWithChildren } from 'react'; import { InstanceNameProvider, _InternalInstanceName } from './InstanceName'; -import { - render, - screen, - waitFor, - waitForElementToBeRemoved, - within, -} from '@testing-library/react'; +import { render, screen, waitFor, waitForElementToBeRemoved, within } from '@testing-library/react'; import { jest } from '@jest/globals'; import userEvent from '@testing-library/user-event'; import { QueryClient } from 'react-query'; @@ -67,9 +61,7 @@ const Wrapper = ({ children }: PropsWithChildren<{}>) => ( describe('InstanceName', () => { it('should display the instance name input when it resolved its configuration', async () => { //S - const getInstanceName = jest - .fn<(userData: UserData) => Promise>() - .mockResolvedValue('default'); + const getInstanceName = jest.fn<(userData: UserData) => Promise>().mockResolvedValue('default'); const setInstanceName = jest.fn<(userData: UserData) => Promise>(); render( <_InternalInstanceName @@ -98,9 +90,6 @@ describe('InstanceName', () => { await waitFor(() => expect(setInstanceName).toHaveBeenCalledTimes(1)); //V expect(getInstanceName).toHaveBeenCalledTimes(1); - expect(setInstanceName).toHaveBeenCalledWith( - { token: 'test' }, - 'defaulttest', - ); + expect(setInstanceName).toHaveBeenCalledWith({ token: 'test' }, 'defaulttest'); }); }); diff --git a/shell-ui/src/navbar/InstanceName.tsx b/shell-ui/src/navbar/InstanceName.tsx index 717e0e3d04..0816c3e492 100644 --- a/shell-ui/src/navbar/InstanceName.tsx +++ b/shell-ui/src/navbar/InstanceName.tsx @@ -1,9 +1,4 @@ -import React, { - PropsWithChildren, - createContext, - useContext, - useState, -} from 'react'; +import React, { PropsWithChildren, createContext, useContext, useState } from 'react'; import { useShellConfig } from '../initFederation/ShellConfigProvider'; import { InlineInput } from '@scality/core-ui/dist/components/inlineinput/InlineInput'; import { useMutation, useQuery } from 'react-query'; @@ -21,18 +16,14 @@ const InstanceNameContext = createContext<{ export const InstanceNameProvider = ({ children }: PropsWithChildren<{}>) => { const [instanceName, setInstanceName] = useState(''); return ( - - {children} - + {children} ); }; export const useInstanceName = () => { const context = useContext(InstanceNameContext); if (!context) { - throw new Error( - 'useInstanceName must be used within a InstanceNameProvider', - ); + throw new Error('useInstanceName must be used within a InstanceNameProvider'); } return context.instanceName; }; @@ -40,9 +31,7 @@ export const useInstanceName = () => { const useSetInstanceName = () => { const context = useContext(InstanceNameContext); if (!context) { - throw new Error( - 'useSetInstanceName must be used within a InstanceNameProvider', - ); + throw new Error('useSetInstanceName must be used within a InstanceNameProvider'); } return context.setInstanceName; }; @@ -76,10 +65,7 @@ export const _InternalInstanceName = ({ moduleExports: { [moduleName: string]: { getInstanceName: (userData: UserData | undefined) => Promise; - setInstanceName: ( - userData: UserData | undefined, - name: string, - ) => Promise; + setInstanceName: (userData: UserData | undefined, name: string) => Promise; }; }; }) => { @@ -89,10 +75,7 @@ export const _InternalInstanceName = ({ const { userData } = useAuth(); const { data, status } = useQuery({ queryKey: ['instanceName'], - queryFn: () => - moduleExports[instanceNameAdapter?.module ?? ''].getInstanceName( - userData, - ), + queryFn: () => moduleExports[instanceNameAdapter?.module ?? ''].getInstanceName(userData), onSuccess: (data) => { setInstanceName(data); }, @@ -100,10 +83,7 @@ export const _InternalInstanceName = ({ const mutation = useMutation({ mutationFn: ({ value }: { value: string }) => { - return moduleExports[instanceNameAdapter?.module ?? ''].setInstanceName( - userData, - value, - ); + return moduleExports[instanceNameAdapter?.module ?? ''].setInstanceName(userData, value); }, }); diff --git a/shell-ui/src/navbar/NavBar.tsx b/shell-ui/src/navbar/NavBar.tsx index e291e359bd..e3825d0a3b 100644 --- a/shell-ui/src/navbar/NavBar.tsx +++ b/shell-ui/src/navbar/NavBar.tsx @@ -4,10 +4,7 @@ import { useLocation } from 'react-router-dom'; import styled, { createGlobalStyle } from 'styled-components'; import { Button } from '@scality/core-ui/dist/components/buttonv2/Buttonv2.component'; -import { - Icon, - IconName, -} from '@scality/core-ui/dist/components/icon/Icon.component'; +import { Icon, IconName } from '@scality/core-ui/dist/components/icon/Icon.component'; import { Layout } from '@scality/core-ui/dist/components/layout/v2/index'; import { Navbar as CoreUINavbar } from '@scality/core-ui/dist/components/navbar/Navbar.component'; @@ -69,15 +66,7 @@ const NavbarDropDownItemExternal = styled.div` color: ${(props) => props.theme.textLink}; `; -const Item = ({ - icon, - label, - isExternal, -}: { - icon?: IconName; - label: string; - isExternal?: boolean; -}) => { +const Item = ({ icon, label, isExternal }: { icon?: IconName; label: string; isExternal?: boolean }) => { return ( {icon && ( @@ -140,15 +129,9 @@ export const useNavbarLinksToActions = ( .sort((a, b) => { if (!a.view.isFederated || !b.view.isFederated) { return 0; - } else if ( - (a.view.view.exact && !b.view.view.exact) || - (a.view.view.strict && !b.view.view.strict) - ) { + } else if ((a.view.view.exact && !b.view.view.exact) || (a.view.view.strict && !b.view.view.strict)) { return -1; - } else if ( - (!a.view.view.exact && b.view.view.exact) || - (!a.view.view.strict && b.view.view.strict) - ) { + } else if ((!a.view.view.exact && b.view.view.exact) || (!a.view.view.strict && b.view.view.strict)) { return 1; } @@ -159,15 +142,10 @@ export const useNavbarLinksToActions = ( ? doesRouteMatch({ exact: link.view.view.exact, path: link.view.view.activeIfMatches - ? new RegExp( - link.view.app.appHistoryBasePath + - link.view.view.activeIfMatches, - 'i', - ).toString() + ? new RegExp(link.view.app.appHistoryBasePath + link.view.view.activeIfMatches, 'i').toString() : link.view.app.appHistoryBasePath + link.view.view.path, }) - : normalizePath((link.view as NonFederatedView).url) === - window.location.origin + window.location.pathname, + : normalizePath((link.view as NonFederatedView).url) === window.location.origin + window.location.pathname, ); return links.map((link) => { @@ -175,14 +153,11 @@ export const useNavbarLinksToActions = ( link, selected: selectedTab && selectedTab.view.isFederated && link.view.isFederated - ? selectedTab.view.app.name === link.view.app.name && - selectedTab.view.view.path === link.view.view.path - : selectedTab && - !selectedTab.view.isFederated && - !link.view.isFederated - ? normalizePath((selectedTab.view as NonFederatedView).url) === - normalizePath((link.view as NonFederatedView).url) - : false, + ? selectedTab.view.app.name === link.view.app.name && selectedTab.view.view.path === link.view.view.path + : selectedTab && !selectedTab.view.isFederated && !link.view.isFederated + ? normalizePath((selectedTab.view as NonFederatedView).url) === + normalizePath((link.view as NonFederatedView).url) + : false, }; }); }; @@ -192,12 +167,7 @@ export const useFederatedNavbarEntries = (): { const { userData } = useAuth(); const discoveredViews = useDiscoveredViews(); const accessibleViews = discoveredViews.filter( - (discoveredView) => - userData && - (discoveredView.groups?.some((group) => - userData.groups.includes(group), - ) ?? - true), + (discoveredView) => userData && (discoveredView.groups?.some((group) => userData.groups.includes(group)) ?? true), ); return { accessibleViews, @@ -239,9 +209,7 @@ export const Navbar = ({ const navbarLinks = useMemo(() => getLinks(), [getLinks]); const navbarMainActions = useNavbarLinksToActions(navbarLinks.main); const navbarSecondaryActions = useNavbarLinksToActions(navbarLinks.secondary); - const navbarSubloginActions = useNavbarLinksToActions( - navbarLinks.userDropdown, - ); + const navbarSubloginActions = useNavbarLinksToActions(navbarLinks.userDropdown); const navbarEntrySelected = navbarMainActions.find((act) => act.selected) || navbarSecondaryActions.find((act) => act.selected) || @@ -261,18 +229,9 @@ export const Navbar = ({ useEffect(() => { const navbarMainSelected = navbarMainActions.find((act) => act.selected); - const navbarSecondarySelected = navbarSecondaryActions.find( - (act) => act.selected, - ); - const navbarSubloginSelected = navbarSubloginActions.find( - (act) => act.selected, - ); - if ( - navbarMainActions.length && - !navbarMainSelected && - !navbarSecondarySelected && - !navbarSubloginSelected - ) { + const navbarSecondarySelected = navbarSecondaryActions.find((act) => act.selected); + const navbarSubloginSelected = navbarSubloginActions.find((act) => act.selected); + if (navbarMainActions.length && !navbarMainSelected && !navbarSecondarySelected && !navbarSubloginSelected) { const link = navbarMainActions?.[0]?.link; const url = link.view.isFederated ? link.view.app.appHistoryBasePath + link.view.view.path @@ -287,9 +246,7 @@ export const Navbar = ({ link: action.link.render ? ( ) : ( - - {action.link.view.view.label[language]} - + {action.link.view.view.label[language]} ), selected: action.selected, }; @@ -301,9 +258,7 @@ export const Navbar = ({ action.link.render ? ( ) : ( - - {action.link.view.view.label[language]} - + {action.link.view.view.label[language]} ), })); diff --git a/shell-ui/src/navbar/NavbarConfigProvider.tsx b/shell-ui/src/navbar/NavbarConfigProvider.tsx index 49e89e99ae..bfc73afb7c 100644 --- a/shell-ui/src/navbar/NavbarConfigProvider.tsx +++ b/shell-ui/src/navbar/NavbarConfigProvider.tsx @@ -4,11 +4,7 @@ import { useFederatedNavbarEntries } from './NavBar'; import type { NavbarLinks, Navbar, Link } from './navbarHooks'; import './navbarHooks'; import { NavbarContext } from './navbarContext'; -export const NavbarConfigProvider = ({ - children, -}: { - children: ReactElement; -}): ReactElement => { +export const NavbarConfigProvider = ({ children }: { children: ReactElement }): ReactElement => { const { accessibleViews } = useFederatedNavbarEntries(); const [logoLink, setLogoLink] = useState(''); const [mainLinks, setMainLinks] = useState([]); @@ -43,7 +39,5 @@ export const NavbarConfigProvider = ({ setUserDropdownLinks, getLinks: () => navbarLinks, }; - return ( - {children} - ); + return {children}; }; diff --git a/shell-ui/src/navbar/NavbarUpdaterComponents.tsx b/shell-ui/src/navbar/NavbarUpdaterComponents.tsx index 43276cc7ca..d4e4a5fcf4 100644 --- a/shell-ui/src/navbar/NavbarUpdaterComponents.tsx +++ b/shell-ui/src/navbar/NavbarUpdaterComponents.tsx @@ -9,12 +9,7 @@ import { useConfigRetriever } from '../initFederation/ConfigurationProviders'; import { useDeployedApps } from '../initFederation/UIListProvider'; import { useNotificationCenter } from '../useNotificationCenter'; import { useNavbar } from './navbarHooks'; -import { - ShellAlerts, - shellAlerts, - ShellHooks, - shellHooks, -} from '../hooks/useShellHooks'; +import { ShellAlerts, shellAlerts, ShellHooks, shellHooks } from '../hooks/useShellHooks'; export const NavbarUpdaterComponents = () => { const deployedApps = useDeployedApps(); @@ -49,11 +44,7 @@ export const NavbarUpdaterComponents = () => { { - console.error( - 'error while loading navbar updater component', - component, - props, - ); + console.error('error while loading navbar updater component', component, props); return <>; }} > diff --git a/shell-ui/src/navbar/NotificationCenter.spec.tsx b/shell-ui/src/navbar/NotificationCenter.spec.tsx index 12aff93045..7800e6b710 100644 --- a/shell-ui/src/navbar/NotificationCenter.spec.tsx +++ b/shell-ui/src/navbar/NotificationCenter.spec.tsx @@ -1,9 +1,6 @@ import React, { PropsWithChildren } from 'react'; import { act, screen, waitFor, within } from '@testing-library/react'; -import NotificationCenterProvider, { - InternalNotification, - Notification, -} from '../NotificationCenterProvider'; +import NotificationCenterProvider, { InternalNotification, Notification } from '../NotificationCenterProvider'; import NotificationCenter from './NotificationCenter'; import userEvent from '@testing-library/user-event'; import { QueryClient } from 'react-query'; @@ -14,16 +11,11 @@ import { useNotificationCenter } from '../useNotificationCenter'; import { QueryClientProvider } from '../QueryClientProvider'; export const notificationCenterSelectors = { - notificationCenterButton: () => - screen.getByRole('button', { name: /notification center/i }), - emptyNotificationCenterIcon: () => - screen.getByRole('img', { name: /Notification Center \(Empty\)/i }), - noNotifications: () => - screen.getByText(/You have no new notifications at the moment./i), - notification: (title: string | RegExp) => - screen.getByRole('option', { name: title }), - notificationCenterComboBox: () => - screen.getByRole('combobox', { name: /notification center/i }), + notificationCenterButton: () => screen.getByRole('button', { name: /notification center/i }), + emptyNotificationCenterIcon: () => screen.getByRole('img', { name: /Notification Center \(Empty\)/i }), + noNotifications: () => screen.getByText(/You have no new notifications at the moment./i), + notification: (title: string | RegExp) => screen.getByRole('option', { name: title }), + notificationCenterComboBox: () => screen.getByRole('combobox', { name: /notification center/i }), }; describe('NotificationCenter', () => { @@ -94,15 +86,11 @@ describe('NotificationCenter', () => { return { TRIAL_LICENSE_EXPIRED, NEW_ALERTS, NEW_VERSION_AVAILABLE }; } const renderNotificationCenter = async () => { - const { renderAdditionalHook, waitForWrapperToBeReady } = - prepareRenderMultipleHooks({ - wrapper, - }); + const { renderAdditionalHook, waitForWrapperToBeReady } = prepareRenderMultipleHooks({ + wrapper, + }); await waitForWrapperToBeReady(); - const { result, waitFor } = renderAdditionalHook( - 'useNotificationCenter', - useNotificationCenter, - ); + const { result, waitFor } = renderAdditionalHook('useNotificationCenter', useNotificationCenter); return { result, waitFor }; }; @@ -113,9 +101,7 @@ describe('NotificationCenter', () => { }); //E await waitFor(() => { - expect( - notificationCenterSelectors.emptyNotificationCenterIcon(), - ).toBeInTheDocument(); + expect(notificationCenterSelectors.emptyNotificationCenterIcon()).toBeInTheDocument(); }); userEvent.click(notificationCenterSelectors.notificationCenterButton()); //V @@ -126,30 +112,19 @@ describe('NotificationCenter', () => { //S+E //We use the `prepareRenderMultipleHooks` to get the `screen`, which is not exposed by the React Hook Testing Library. const { result, waitFor } = await renderNotificationCenter(); - const { TRIAL_LICENSE_EXPIRED, NEW_ALERTS, NEW_VERSION_AVAILABLE } = - publishNewNotifications(result); - expect( - notificationCenterSelectors.notificationCenterButton(), - ).toBeInTheDocument(); + const { TRIAL_LICENSE_EXPIRED, NEW_ALERTS, NEW_VERSION_AVAILABLE } = publishNewNotifications(result); + expect(notificationCenterSelectors.notificationCenterButton()).toBeInTheDocument(); // Open the notification center userEvent.click(notificationCenterSelectors.notificationCenterButton()); // Note that the waitFor from the React Hook Testing Library is different from the one from the React Testing Library. - await waitFor( - () => !!screen.queryByText(new RegExp(TRIAL_LICENSE_EXPIRED)), - ); + await waitFor(() => !!screen.queryByText(new RegExp(TRIAL_LICENSE_EXPIRED))); //V the trial license expired is the first notification list - expect(screen.getAllByRole('option')[0]).toHaveTextContent( - new RegExp(NEW_ALERTS), - ); + expect(screen.getAllByRole('option')[0]).toHaveTextContent(new RegExp(NEW_ALERTS)); //V the new version available is the second notification list - expect(screen.getAllByRole('option')[1]).toHaveTextContent( - new RegExp(NEW_VERSION_AVAILABLE), - ); + expect(screen.getAllByRole('option')[1]).toHaveTextContent(new RegExp(NEW_VERSION_AVAILABLE)); //V the new alerts is the third notification list - expect(screen.getAllByRole('option')[2]).toHaveTextContent( - new RegExp(TRIAL_LICENSE_EXPIRED), - ); + expect(screen.getAllByRole('option')[2]).toHaveTextContent(new RegExp(TRIAL_LICENSE_EXPIRED)); //V the notifications are marked as unread expect( within(screen.getAllByRole('option')[0]).getByRole('img', { @@ -194,40 +169,23 @@ describe('NotificationCenter', () => { it('can be navigated with the keyboard', async () => { const { result } = await renderNotificationCenter(); - const { TRIAL_LICENSE_EXPIRED, NEW_ALERTS, NEW_VERSION_AVAILABLE } = - publishNewNotifications(result); - const notificationCenterButton = - notificationCenterSelectors.notificationCenterButton(); + const { TRIAL_LICENSE_EXPIRED, NEW_ALERTS, NEW_VERSION_AVAILABLE } = publishNewNotifications(result); + const notificationCenterButton = notificationCenterSelectors.notificationCenterButton(); userEvent.click(notificationCenterButton); - const notificationCenterComboBox = - notificationCenterSelectors.notificationCenterComboBox(); + const notificationCenterComboBox = notificationCenterSelectors.notificationCenterComboBox(); userEvent.keyboard('{arrowdown}'); - const notification = notificationCenterSelectors.notification( - new RegExp(NEW_ALERTS), - ); - expect( - notificationCenterComboBox.attributes.getNamedItem( - 'aria-activedescendant', - )?.value, - ).toBe(notification.id); + const notification = notificationCenterSelectors.notification(new RegExp(NEW_ALERTS)); + expect(notificationCenterComboBox.attributes.getNamedItem('aria-activedescendant')?.value).toBe(notification.id); userEvent.keyboard('{arrowdown}'); - const nextNotification = notificationCenterSelectors.notification( - new RegExp(NEW_VERSION_AVAILABLE), + const nextNotification = notificationCenterSelectors.notification(new RegExp(NEW_VERSION_AVAILABLE)); + expect(notificationCenterComboBox.attributes.getNamedItem('aria-activedescendant')?.value).toBe( + nextNotification.id, ); - expect( - notificationCenterComboBox.attributes.getNamedItem( - 'aria-activedescendant', - )?.value, - ).toBe(nextNotification.id); userEvent.keyboard('{arrowdown}'); - const lastNotification = notificationCenterSelectors.notification( - new RegExp(TRIAL_LICENSE_EXPIRED), + const lastNotification = notificationCenterSelectors.notification(new RegExp(TRIAL_LICENSE_EXPIRED)); + expect(notificationCenterComboBox.attributes.getNamedItem('aria-activedescendant')?.value).toBe( + lastNotification.id, ); - expect( - notificationCenterComboBox.attributes.getNamedItem( - 'aria-activedescendant', - )?.value, - ).toBe(lastNotification.id); userEvent.keyboard('{enter}'); diff --git a/shell-ui/src/navbar/NotificationCenter.tsx b/shell-ui/src/navbar/NotificationCenter.tsx index 36d0ecb336..a3042be7ed 100644 --- a/shell-ui/src/navbar/NotificationCenter.tsx +++ b/shell-ui/src/navbar/NotificationCenter.tsx @@ -22,22 +22,14 @@ const NotificationMenu = styled.ul<{ // TO MAKE SURE THE LIST IS CENTERED ON THE BELL BUTTON left: ${(props) => { const notificationCenterWidth = 0.25 * window.innerWidth; - const leftRelativeToButton = - -notificationCenterWidth / 2 + props.buttonBoundingRect.width / 2; - const absoluteNotificationCenterX = - props.buttonBoundingRect.x + leftRelativeToButton; - if ( - absoluteNotificationCenterX + notificationCenterWidth > - window.innerWidth - ) { + const leftRelativeToButton = -notificationCenterWidth / 2 + props.buttonBoundingRect.width / 2; + const absoluteNotificationCenterX = props.buttonBoundingRect.x + leftRelativeToButton; + if (absoluteNotificationCenterX + notificationCenterWidth > window.innerWidth) { // |<------------------window.innerWidth------------------------------------>|<--offset-->| // |<------------------button x------------------------------>|buttonwidth|---------------| // |---------------------------------|<-LeftRelativeToButton->|---------------------------| // |<--absoluteNotificationCenterX-->|<--notificationCenterWidth------------------------->| - const offset = - absoluteNotificationCenterX + - notificationCenterWidth - - window.innerWidth; + const offset = absoluteNotificationCenterX + notificationCenterWidth - window.innerWidth; return leftRelativeToButton - offset; } return leftRelativeToButton; @@ -70,8 +62,8 @@ const NotificationItem = styled.li<{ props.isHighlighted ? props.theme.highlight : props.isRead - ? props.theme.backgroundLevel4 - : props.theme.backgroundLevel3}; + ? props.theme.backgroundLevel4 + : props.theme.backgroundLevel3}; `; const NotificationCenterHeader = styled.div` @@ -82,17 +74,9 @@ const NotificationCenterHeader = styled.div` const NotificationCenter = () => { const { notifications, readAllNotifications } = useNotificationCenter(); - const [buttonBoundingRect, setButtonBoundingRect] = useState( - new DOMRect(), - ); + const [buttonBoundingRect, setButtonBoundingRect] = useState(new DOMRect()); const theme = useTheme(); - const { - isOpen, - getToggleButtonProps, - getMenuProps, - highlightedIndex, - getItemProps, - } = useSelect({ + const { isOpen, getToggleButtonProps, getMenuProps, highlightedIndex, getItemProps } = useSelect({ items: notifications, onIsOpenChange: ({ isOpen }) => { if (!isOpen) { @@ -107,9 +91,7 @@ const NotificationCenter = () => { readAllNotifications(); }, }); - const isAtLeastOneNotificationUnread = notifications.some( - (notification) => !notification.readOn, - ); + const isAtLeastOneNotificationUnread = notifications.some((notification) => !notification.readOn); const navigate = useShellHistory(); return (
{ {...getToggleButtonProps({ 'aria-label': 'Notification Center', ref: (e: HTMLDivElement) => { - if ( - e && - (buttonBoundingRect.x === 0 || buttonBoundingRect.width === 0) - ) { + if (e && (buttonBoundingRect.x === 0 || buttonBoundingRect.width === 0)) { setButtonBoundingRect(e.getBoundingClientRect()); } }, @@ -132,18 +111,14 @@ const NotificationCenter = () => { n.severity === 'critical') ? 'statusCritical' : notifications.find((n) => n.severity === 'warning') - ? 'statusWarning' - : 'infoPrimary' + ? 'statusWarning' + : 'infoPrimary' } size="lg" style={ @@ -178,10 +153,7 @@ const NotificationCenter = () => { Notifications {isAtLeastOneNotificationUnread && ( - !n.readOn).length}`} - variant="selectedActive" - /> + !n.readOn).length}`} variant="selectedActive" /> )} @@ -189,9 +161,7 @@ const NotificationCenter = () => { - - You have no new notifications at the moment. - + You have no new notifications at the moment. )} @@ -210,15 +180,15 @@ const NotificationCenter = () => { notification.severity === 'critical' ? 'statusCritical' : notification.severity === 'warning' - ? 'statusWarning' - : 'infoPrimary' + ? 'statusWarning' + : 'infoPrimary' } name={ notification.severity === 'critical' ? 'Times-circle' : notification.severity === 'warning' - ? 'Exclamation-circle' - : 'Dot-circle' + ? 'Exclamation-circle' + : 'Dot-circle' } /> @@ -241,20 +211,14 @@ const NotificationCenter = () => { {notification.title} - + + {notification.description} } diff --git a/shell-ui/src/navbar/SleepingNotificationBell.tsx b/shell-ui/src/navbar/SleepingNotificationBell.tsx index 588a82b48a..b2da7ab216 100644 --- a/shell-ui/src/navbar/SleepingNotificationBell.tsx +++ b/shell-ui/src/navbar/SleepingNotificationBell.tsx @@ -1,13 +1,7 @@ import React from 'react'; export const SleepingNotificationBell = () => ( - + ( }; export function prepareRenderMultipleHooks(options: { - wrapper: FunctionComponent< - React.PropsWithChildren>> - >; + wrapper: FunctionComponent>>>; }): { renderAdditionalHook: RenderAdditionalHook; waitForWrapperToBeReady: () => Promise; @@ -34,17 +21,11 @@ export function prepareRenderMultipleHooks(options: { const RENDER_HOOK_EVENT = 'RENDER_HOOK_EVENT'; const READY_STRING = 'READY_STRING'; - function TestComponents({ - addValues, - }: { - addValues: (vals: { key: string; value: unknown }[]) => void; - }) { + function TestComponents({ addValues }: { addValues: (vals: { key: string; value: unknown }[]) => void }) { const [components, setComponents] = useState([]); useEffect(() => { - const listener = ( - e: CustomEvent<{ key: string; callback: () => unknown }>, - ) => { + const listener = (e: CustomEvent<{ key: string; callback: () => unknown }>) => { function TestComponent() { const hook = e.detail.callback(); @@ -78,10 +59,7 @@ export function prepareRenderMultipleHooks(options: { } const values: { key: string; value: unknown }[] = []; render( -
error
} - > +
error
}> {/* @ts-expect-error - FIXME when you are working on it */} ( - key: string, - callback: () => THookResult, - ) => { + renderAdditionalHook: (key: string, callback: () => THookResult) => { try { screen.getByText(READY_STRING); } catch (e) { diff --git a/shell-ui/src/navbar/__TESTS__/utils.ts b/shell-ui/src/navbar/__TESTS__/utils.ts index da58eeb869..405228da7c 100644 --- a/shell-ui/src/navbar/__TESTS__/utils.ts +++ b/shell-ui/src/navbar/__TESTS__/utils.ts @@ -1,11 +1,5 @@ import { screen, waitForElementToBeRemoved } from '@testing-library/react'; export const waitForLoadingToFinish = () => - waitForElementToBeRemoved( - () => [ - ...screen.queryAllByLabelText(/loading/i), - ...screen.queryAllByText(/loading/i), - ], - { - timeout: 4000, - }, - ); \ No newline at end of file + waitForElementToBeRemoved(() => [...screen.queryAllByLabelText(/loading/i), ...screen.queryAllByText(/loading/i)], { + timeout: 4000, + }); diff --git a/shell-ui/src/navbar/auth/permissionUtils.spec.ts b/shell-ui/src/navbar/auth/permissionUtils.spec.ts index 384542b17a..6ab2a5c769 100644 --- a/shell-ui/src/navbar/auth/permissionUtils.spec.ts +++ b/shell-ui/src/navbar/auth/permissionUtils.spec.ts @@ -1,10 +1,5 @@ import '../index'; -import { - getUserGroups, - isEntryAccessibleByTheUser, - isPathAccessible, - normalizePath, -} from './permissionUtils'; +import { getUserGroups, isEntryAccessibleByTheUser, isPathAccessible, normalizePath } from './permissionUtils'; describe('permission utils - isEntryAccessibleByTheUser', () => { it('should return true if the user has explicit access', () => { //E @@ -57,12 +52,8 @@ describe('permission utils - isEntryAccessibleByTheUser', () => { describe('permission utils - normalizePath', () => { it('should normalize path', () => { - expect(normalizePath('http://fake/groupPath')).toEqual( - 'http://fake/groupPath', - ); - expect(normalizePath('http://fake/path/subPath?a=test#test')).toEqual( - 'http://fake/path/subPath', - ); + expect(normalizePath('http://fake/groupPath')).toEqual('http://fake/groupPath'); + expect(normalizePath('http://fake/path/subPath?a=test#test')).toEqual('http://fake/path/subPath'); }); it('should throw if the path is an invalid url', () => { expect(() => normalizePath('invalidUrl')).toThrow(); @@ -71,17 +62,13 @@ describe('permission utils - normalizePath', () => { describe('permission utils - isPathAccessible', () => { it('should return true when the path is accessible', () => { //E - const isAccessible = isPathAccessible('http://fake/path?hello=world', [ - 'http://fake/path?hello=test', - ]); + const isAccessible = isPathAccessible('http://fake/path?hello=world', ['http://fake/path?hello=test']); //V expect(isAccessible).toBe(true); }); it('should return false when the path is not accessible', () => { //E - const isAccessible = isPathAccessible('http://fake/path?hello=world', [ - 'http://fake/another-path?hello=test', - ]); + const isAccessible = isPathAccessible('http://fake/path?hello=world', ['http://fake/another-path?hello=test']); //V expect(isAccessible).toBe(false); }); @@ -140,10 +127,6 @@ describe('permission utils - getUserGroups', () => { }, ); //V - expect(groups).toEqual([ - ...oidcAndStaticGroups, - ...oidcOnlyGroups, - ...staticOnlyGroups, - ]); + expect(groups).toEqual([...oidcAndStaticGroups, ...oidcOnlyGroups, ...staticOnlyGroups]); }); }); diff --git a/shell-ui/src/navbar/auth/permissionUtils.ts b/shell-ui/src/navbar/auth/permissionUtils.ts index 5042c6f68b..8dead4cff8 100644 --- a/shell-ui/src/navbar/auth/permissionUtils.ts +++ b/shell-ui/src/navbar/auth/permissionUtils.ts @@ -7,31 +7,19 @@ export const isEntryAccessibleByTheUser = ( [path, pathDescription]: [string, PathDescription], userGroups: string[], ): boolean => { - return ( - pathDescription.groups?.some((group) => userGroups.includes(group)) ?? true - ); + return pathDescription.groups?.some((group) => userGroups.includes(group)) ?? true; }; export const normalizePath = (path: string): string => { const url = new URL(path); return url.origin + url.pathname; }; -export const isPathAccessible = ( - path: string, - accessiblePaths: string[], -): boolean => { +export const isPathAccessible = (path: string, accessiblePaths: string[]): boolean => { const normalizedPath = normalizePath(path); - return accessiblePaths.some( - (accessiblePath) => normalizePath(accessiblePath) === normalizedPath, - ); + return accessiblePaths.some((accessiblePath) => normalizePath(accessiblePath) === normalizedPath); }; -export const getUserGroups = ( - user?: User, - userGroupsMapping?: UserGroupsMapping, -): string[] => { +export const getUserGroups = (user?: User, userGroupsMapping?: UserGroupsMapping): string[] => { const userOIDCGroups: string[] = (user?.profile?.groups as string[]) || []; - const userMappedGroups = userGroupsMapping - ? userGroupsMapping[user?.profile?.email || ''] || [] - : []; + const userMappedGroups = userGroupsMapping ? userGroupsMapping[user?.profile?.email || ''] || [] : []; return Array.from(new Set([...userOIDCGroups, ...userMappedGroups])); }; diff --git a/shell-ui/src/navbar/events.ts b/shell-ui/src/navbar/events.ts index 5ecd7b6a67..b722330c38 100644 --- a/shell-ui/src/navbar/events.ts +++ b/shell-ui/src/navbar/events.ts @@ -1,5 +1,4 @@ const EVENTS_PREFIX = 'solutions-navbar--'; export const AUTHENTICATED_EVENT: string = EVENTS_PREFIX + 'authenticated'; -export const LANGUAGE_CHANGED_EVENT: string = - EVENTS_PREFIX + 'language-changed'; -export const THEME_CHANGED_EVENT: string = EVENTS_PREFIX + 'theme-changed'; \ No newline at end of file +export const LANGUAGE_CHANGED_EVENT: string = EVENTS_PREFIX + 'language-changed'; +export const THEME_CHANGED_EVENT: string = EVENTS_PREFIX + 'theme-changed'; diff --git a/shell-ui/src/navbar/favicon.ts b/shell-ui/src/navbar/favicon.ts index 94d2877e92..263125e1bd 100644 --- a/shell-ui/src/navbar/favicon.ts +++ b/shell-ui/src/navbar/favicon.ts @@ -1,9 +1,7 @@ import { useEffect } from 'react'; export const useFavicon = (favicon: string) => { useEffect(() => { - const link: HTMLLinkElement = - document.querySelector("link[rel*='icon']") || - document.createElement('link'); + const link: HTMLLinkElement = document.querySelector("link[rel*='icon']") || document.createElement('link'); link.type = 'image/x-icon'; link.rel = 'shortcut icon'; link.href = favicon; diff --git a/shell-ui/src/navbar/index.spec.tsx b/shell-ui/src/navbar/index.spec.tsx index 0fa12aa77e..18190d50b6 100644 --- a/shell-ui/src/navbar/index.spec.tsx +++ b/shell-ui/src/navbar/index.spec.tsx @@ -132,9 +132,7 @@ describe('useNavbar', () => { wrapper, }); await waitFor(() => { - expect(result.current.getLinks()).toStrictEqual( - expectedDefaultNavbarLinks, - ); + expect(result.current.getLinks()).toStrictEqual(expectedDefaultNavbarLinks); }); }); it('should set main navbar links', async () => { @@ -231,9 +229,7 @@ describe('useNavbar', () => { //E await waitForLoadingToFinish(); //Verify the Notification Center is displayed in the Navbar - expect( - screen.getByRole('button', { name: /Notification Center/i }), - ).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /Notification Center/i })).toBeInTheDocument(); }); it('should hide the Notification Center for non Platform Admin', async () => { //S @@ -254,8 +250,6 @@ describe('useNavbar', () => { //E await waitForLoadingToFinish(); //V - expect(screen.queryByRole('button', { name: /Notification Center/i })).toBe( - null, - ); + expect(screen.queryByRole('button', { name: /Notification Center/i })).toBe(null); }); }); diff --git a/shell-ui/src/navbar/lang.tsx b/shell-ui/src/navbar/lang.tsx index 5da8ab569b..5b9c5f4adc 100644 --- a/shell-ui/src/navbar/lang.tsx +++ b/shell-ui/src/navbar/lang.tsx @@ -1,9 +1,4 @@ -import React, { - useContext, - useState, - useLayoutEffect, - createContext, -} from 'react'; +import React, { useContext, useState, useLayoutEffect, createContext } from 'react'; import { IntlProvider } from 'react-intl'; import translations_en from './translations/en.json'; import translations_fr from './translations/fr.json'; @@ -25,17 +20,13 @@ export function useLanguage(): { const languageContext = useContext(LanguageContext); if (languageContext === null) { - throw new Error( - "useLanguage hook can't be use outside ", - ); + throw new Error("useLanguage hook can't be use outside "); } return { language: languageContext.language, setLanguage: languageContext.setLanguage, - unSelectedLanguages: languages.filter( - (lang) => lang !== languageContext.language, - ), + unSelectedLanguages: languages.filter((lang) => lang !== languageContext.language), }; } export function LanguageProvider({ @@ -49,8 +40,7 @@ export function LanguageProvider({ }) { const [language, setLang] = useState( canChangeLanguage - ? (localStorage.getItem('lang') as any as Language) || - (navigator.language.startsWith('fr') ? 'fr' : 'en') + ? (localStorage.getItem('lang') as any as Language) || (navigator.language.startsWith('fr') ? 'fr' : 'en') : 'en', ); useLayoutEffect(() => { @@ -75,10 +65,7 @@ export function LanguageProvider({ setLanguage, }} > - + {children} diff --git a/shell-ui/src/navbar/library.ts b/shell-ui/src/navbar/library.ts index b1c5c1241a..719c52c96c 100644 --- a/shell-ui/src/navbar/library.ts +++ b/shell-ui/src/navbar/library.ts @@ -1,8 +1,4 @@ -import { - AUTHENTICATED_EVENT, - LANGUAGE_CHANGED_EVENT, - THEME_CHANGED_EVENT, -} from './events'; +import { AUTHENTICATED_EVENT, LANGUAGE_CHANGED_EVENT, THEME_CHANGED_EVENT } from './events'; import packageJson from '../../package.json'; const { version } = packageJson; // @ts-expect-error - FIXME when you are working on it diff --git a/shell-ui/src/navbar/translations/en.json b/shell-ui/src/navbar/translations/en.json index 5bd6a12776..5c00d135fc 100644 --- a/shell-ui/src/navbar/translations/en.json +++ b/shell-ui/src/navbar/translations/en.json @@ -1,3 +1,3 @@ { - "sign-out": "Log Out" + "sign-out": "Log Out" } diff --git a/shell-ui/src/navbar/translations/fr.json b/shell-ui/src/navbar/translations/fr.json index 9a4d3d26a8..f5b3c1d76f 100644 --- a/shell-ui/src/navbar/translations/fr.json +++ b/shell-ui/src/navbar/translations/fr.json @@ -1,3 +1,3 @@ { - "sign-out": "Déconnexion" + "sign-out": "Déconnexion" } diff --git a/shell-ui/src/platform/service/k8s.spec.tsx b/shell-ui/src/platform/service/k8s.spec.tsx index eb735aa911..21b8418274 100644 --- a/shell-ui/src/platform/service/k8s.spec.tsx +++ b/shell-ui/src/platform/service/k8s.spec.tsx @@ -43,11 +43,7 @@ describe('getNodesCount', () => { ); afterEach(() => server.resetHandlers()); - const wrapper = ({ children }) => ( - - {children} - - ); + const wrapper = ({ children }) => {children}; it('should return the number of nodes in the cluster', async () => { // S diff --git a/shell-ui/src/platform/service/k8s.ts b/shell-ui/src/platform/service/k8s.ts index f79de58406..8b1ae6dd72 100644 --- a/shell-ui/src/platform/service/k8s.ts +++ b/shell-ui/src/platform/service/k8s.ts @@ -28,8 +28,7 @@ export const useGetNodesCount = ( }; navbarElement.addEventListener(AUTHENTICATED_EVENT, onAuthenticated); - return () => - navbarElement.removeEventListener(AUTHENTICATED_EVENT, onAuthenticated); + return () => navbarElement.removeEventListener(AUTHENTICATED_EVENT, onAuthenticated); }, []); const queryNodesResult = useQuery(getNodesCountQuery(k8sUrl, token)); queryNodesResult.nodesCount = queryNodesResult.data; @@ -63,18 +62,14 @@ export const useGetVolumesCount = ( }; navbarElement.addEventListener(AUTHENTICATED_EVENT, onAuthenticated); - return () => - navbarElement.removeEventListener(AUTHENTICATED_EVENT, onAuthenticated); + return () => navbarElement.removeEventListener(AUTHENTICATED_EVENT, onAuthenticated); }, []); const queryVolumesResult = useQuery(getVolumesCountQuery(k8sUrl, token)); queryVolumesResult.volumesCount = queryVolumesResult.data; delete queryVolumesResult.data; return queryVolumesResult; }; -export const getNodesCountQuery = ( - k8sUrl: string, - token?: string | null, -): typeof useQuery => { +export const getNodesCountQuery = (k8sUrl: string, token?: string | null): typeof useQuery => { return { // @ts-expect-error - FIXME when you are working on it queryKey: 'countNodes', @@ -96,10 +91,7 @@ export const getNodesCountQuery = ( enabled: token ? true : false, }; }; -export const getVolumesCountQuery = ( - k8sUrl: string, - token?: string | null, -): typeof useQuery => { +export const getVolumesCountQuery = (k8sUrl: string, token?: string | null): typeof useQuery => { return { // @ts-expect-error - FIXME when you are working on it queryKey: 'countVolumes', diff --git a/shell-ui/src/useNotificationCenter.ts b/shell-ui/src/useNotificationCenter.ts index 0f6f6e3622..d58f7f94ed 100644 --- a/shell-ui/src/useNotificationCenter.ts +++ b/shell-ui/src/useNotificationCenter.ts @@ -6,29 +6,23 @@ import { NotificationCenterContext, } from './NotificationCenterProvider'; -const publish = - (dispatch: Dispatch) => - (notification: Notification) => { - dispatch({ - type: NotificationActionType.PUBLISH, - notification: notification, - }); - }; -const unPublish = - (dispatch: Dispatch) => (id: string) => { - dispatch({ type: NotificationActionType.UNPUBLISH, id: id }); - }; +const publish = (dispatch: Dispatch) => (notification: Notification) => { + dispatch({ + type: NotificationActionType.PUBLISH, + notification: notification, + }); +}; +const unPublish = (dispatch: Dispatch) => (id: string) => { + dispatch({ type: NotificationActionType.UNPUBLISH, id: id }); +}; -const readAllNotifications = - (dispatch: Dispatch) => () => - dispatch({ type: NotificationActionType.READ_ALL }); +const readAllNotifications = (dispatch: Dispatch) => () => + dispatch({ type: NotificationActionType.READ_ALL }); export const useNotificationCenter = () => { const context = useContext(NotificationCenterContext); if (!context) { - throw new Error( - 'useNotificationCenter must be used within a NotificationCenterProvider', - ); + throw new Error('useNotificationCenter must be used within a NotificationCenterProvider'); } const { dispatch } = context; return { diff --git a/shell-ui/tsconfig.json b/shell-ui/tsconfig.json index b080598990..b7ad44e795 100644 --- a/shell-ui/tsconfig.json +++ b/shell-ui/tsconfig.json @@ -6,11 +6,7 @@ // "incremental": true, /* Enable incremental compilation */ "target": "ES2023" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, - "lib": [ - "es2023", - "DOM", - "dom.iterable" - ] /* Specify library files to be included in the compilation. */, + "lib": ["es2023", "DOM", "dom.iterable"] /* Specify library files to be included in the compilation. */, // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ "jsx": "react-jsx" /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */, @@ -78,7 +74,7 @@ "@scality/core-ui/types/styled.d.ts", "node", "jest", - "@testing-library/jest-dom", + "@testing-library/jest-dom" ] /* The type definition files to be included in the compilation. */ }, "exclude": ["@mf-types"] diff --git a/ui/public/brand/assets/login/styles-light.css b/ui/public/brand/assets/login/styles-light.css index 7d26d83da8..b26ca019e5 100644 --- a/ui/public/brand/assets/login/styles-light.css +++ b/ui/public/brand/assets/login/styles-light.css @@ -1,13 +1,13 @@ .theme-body { text-align: center; - background-color: #FFFFFF; - color: #313B44; - font-family: 'Source Sans Pro', Helvetica, sans-serif; + background-color: #ffffff; + color: #313b44; + font-family: "Source Sans Pro", Helvetica, sans-serif; } .theme-navbar { - background-color: #FFFFFF; - color: #313B44; + background-color: #ffffff; + color: #313b44; font-size: 13px; font-weight: 100; height: 46px; @@ -33,30 +33,30 @@ font-weight: 500; margin-bottom: 10px; margin-top: 0; - color: #313B44; + color: #313b44; } .theme-panel { display: inline-block; text-align: center; - background-color:#FAF9FB; + background-color: #faf9fb; padding: 30px; width: 500px; } .theme-btn-provider { background-color: #607080; - color: #FFFFFF; + color: #ffffff; min-width: 250px; } .theme-btn-provider:hover { background-color: #798a9a; - color: #FFFFFF; + color: #ffffff; } .theme-btn--primary { - background-color: #057AFF; + background-color: #057aff; border: none; color: #fff; min-width: 250px; @@ -71,13 +71,13 @@ } .theme-btn--success { - background-color: #2FC98E; + background-color: #2fc98e; color: #fff; width: 250px; } .theme-btn--success:hover { - background-color: #49E3A8; + background-color: #49e3a8; } .theme-form-row { @@ -87,9 +87,9 @@ .theme-form-input { border-radius: 4px; - border: 1px solid #A5A5A5; + border: 1px solid #a5a5a5; box-shadow: inset 0 1px 1px rgba(87, 66, 66, 0.075); - color: #313B44; + color: #313b44; display: block; font-size: 14px; height: 36px; @@ -97,12 +97,12 @@ margin: auto; padding: 6px 12px; width: 250px; - background-color: #EDEAF0; + background-color: #edeaf0; } .theme-form-input:focus, .theme-form-input:active { - border-color: #66AFE9; + border-color: #66afe9; outline: none; } @@ -113,7 +113,7 @@ position: relative; text-align: left; width: 250px; - color:#313B44; + color: #313b44; } .theme-link-back { diff --git a/ui/public/brand/assets/login/styles.css b/ui/public/brand/assets/login/styles.css index 9c7eb09c16..708a45c9ed 100644 --- a/ui/public/brand/assets/login/styles.css +++ b/ui/public/brand/assets/login/styles.css @@ -1,13 +1,13 @@ .theme-body { text-align: center; background-color: #121214; - color: #FEFEFE; - font-family: 'Source Sans Pro', Helvetica, sans-serif; + color: #fefefe; + font-family: "Source Sans Pro", Helvetica, sans-serif; } .theme-navbar { background-color: #121214; - color: #FEFEFE; + color: #fefefe; font-size: 13px; font-weight: 100; height: 46px; @@ -33,13 +33,13 @@ font-weight: 500; margin-bottom: 10px; margin-top: 0; - color:#FEFEFE; + color: #fefefe; } .theme-panel { display: inline-block; text-align: center; - background-color: #32323B; + background-color: #32323b; padding: 30px; width: 500px; } @@ -55,7 +55,7 @@ } .theme-btn--primary { - background-color: #057AFF; + background-color: #057aff; border: none; color: #fff; min-width: 250px; @@ -65,18 +65,18 @@ } .theme-btn--primary:hover { - background-color: #057AFF; + background-color: #057aff; color: #fff; } .theme-btn--success { - background-color: #2FC98E; + background-color: #2fc98e; color: #fff; width: 250px; } .theme-btn--success:hover { - background-color: #49E3A8; + background-color: #49e3a8; } .theme-form-row { @@ -101,7 +101,7 @@ .theme-form-input:focus, .theme-form-input:active { - border-color: #66AFE9; + border-color: #66afe9; outline: none; } @@ -112,7 +112,7 @@ position: relative; text-align: left; width: 250px; - color:#FEFEFE; + color: #fefefe; } .theme-link-back { diff --git a/ui/src/FederableApp.tsx b/ui/src/FederableApp.tsx index 8f898033c2..645a702433 100644 --- a/ui/src/FederableApp.tsx +++ b/ui/src/FederableApp.tsx @@ -13,11 +13,7 @@ import reducer from './ducks/reducer'; import sagas from './ducks/sagas'; import { useTypedSelector } from './hooks'; import { AuthError } from './services/errorhandler'; -import { - ShellHooksProvider, - useBasenameRelativeNavigate, - useShellHooks, -} from '@scality/module-federation'; +import { ShellHooksProvider, useBasenameRelativeNavigate, useShellHooks } from '@scality/module-federation'; import { FederatedAppProps } from '../@mf-types/shell/App'; const composeEnhancers = @@ -119,10 +115,7 @@ export const AppConfigProvider = ({ export default function FederableApp(props: FederatedAppProps) { return ( - + diff --git a/ui/src/QueryClientProvider.tsx b/ui/src/QueryClientProvider.tsx index 0856f07f40..b3e70048d4 100644 --- a/ui/src/QueryClientProvider.tsx +++ b/ui/src/QueryClientProvider.tsx @@ -1,8 +1,5 @@ import { ComponentType, ReactNode } from 'react'; -import { - QueryClient, - QueryClientProvider as BaseQueryClientProvider, -} from 'react-query'; +import { QueryClient, QueryClientProvider as BaseQueryClientProvider } from 'react-query'; export const QueryClientProvider = BaseQueryClientProvider as ComponentType<{ client: QueryClient; diff --git a/ui/src/alert-configuration/ConfigureAlerting.test.tsx b/ui/src/alert-configuration/ConfigureAlerting.test.tsx index d7f8a2a704..ced26c784e 100644 --- a/ui/src/alert-configuration/ConfigureAlerting.test.tsx +++ b/ui/src/alert-configuration/ConfigureAlerting.test.tsx @@ -1,10 +1,4 @@ -import { - act, - configure, - screen, - waitFor, - waitForElementToBeRemoved, -} from '@testing-library/react'; +import { act, configure, screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import fs from 'fs'; import { rest } from 'msw'; @@ -104,38 +98,29 @@ const server = setupServer( return res(ctx.json(result)); }), - rest.get( - 'http://localhost/api/kubernetes/api/v1/namespaces/metalk8s-monitoring/pods', - (req, res, ctx) => { - const result = { - items: [ - { - metadata: { - name: 'pods', - }, + rest.get('http://localhost/api/kubernetes/api/v1/namespaces/metalk8s-monitoring/pods', (req, res, ctx) => { + const result = { + items: [ + { + metadata: { + name: 'pods', }, - ], - }; - return res(ctx.json(result)); - }, - ), + }, + ], + }; + return res(ctx.json(result)); + }), - rest.post( - 'http://localhost/api/alertmanager/api/v2/alerts', - (req, res, ctx) => { - const result = { - status: 'success', - }; - return res(ctx.json(result)); - }, - ), + rest.post('http://localhost/api/alertmanager/api/v2/alerts', (req, res, ctx) => { + const result = { + status: 'success', + }; + return res(ctx.json(result)); + }), ); const overrideMSWAlertmanagerConfig = (testYAMLPath: string) => { - const configYaml = fs.readFileSync( - path.join(__dirname, testYAMLPath), - 'utf8', - ); + const configYaml = fs.readFileSync(path.join(__dirname, testYAMLPath), 'utf8'); server.use( rest.get( `http://localhost/api/kubernetes/api/v1/namespaces/metalk8s-monitoring/configmaps/metalk8s-alertmanager-config`, @@ -189,16 +174,14 @@ describe('', () => { afterAll(() => server.close()); const selectors = { - enableConfiguration: () => - screen.getByLabelText(/Enable Email Notification Configuration \*/i), + enableConfiguration: () => screen.getByLabelText(/Enable Email Notification Configuration \*/i), host: () => screen.getByLabelText(/SMTP Host \*/i), port: () => screen.getByLabelText(/SMTP Port \*/i), enableTls: () => screen.getByLabelText(/Enable SMTP Over TLS/i), authSelect: { label: () => screen.getByLabelText(/SMTP Auth \*/i).parentElement, authClick: () => screen.getByLabelText(/SMTP Auth \*/i), - optionNoAuth: () => - screen.getByRole('option', { name: /NO AUTHENTICATION/i }), + optionNoAuth: () => screen.getByRole('option', { name: /NO AUTHENTICATION/i }), optionLogin: () => screen.getByRole('option', { name: /LOGIN/i }), optionCramMd5: () => screen.getByRole('option', { name: /CRAM-MD5/i }), optionPlain: () => screen.getByRole('option', { name: /PLAIN/i }), @@ -209,13 +192,10 @@ describe('', () => { secret: () => screen.getByLabelText(/Secret \*/), sender: () => screen.getByLabelText(/Sender Email Address \*/i), recipient: () => screen.getByLabelText(/Recipient Email Addresses \*/i), - receiveResolved: () => - screen.getByLabelText(/Enable Receive Resolved Alerts/i), - sendTestingEmailButton: () => - screen.getByRole('button', { name: /send a test email|sending\.\.\./i }), + receiveResolved: () => screen.getByLabelText(/Enable Receive Resolved Alerts/i), + sendTestingEmailButton: () => screen.getByRole('button', { name: /send a test email|sending\.\.\./i }), cancelButton: () => screen.getByRole('button', { name: /cancel/i }), - saveButton: () => - screen.getByRole('button', { name: /save|saving\.\.\./i }), + saveButton: () => screen.getByRole('button', { name: /save|saving\.\.\./i }), }; it('render default value when the form is not defined', async () => { @@ -399,9 +379,7 @@ describe('', () => { }); await waitFor(() => { - return expect( - screen.getByText(/Redirected Alert Page/i), - ).toBeInTheDocument(); + return expect(screen.getByText(/Redirected Alert Page/i)).toBeInTheDocument(); }); expect(screen.getByText(/Redirected Alert Page/i)).toBeInTheDocument(); @@ -411,18 +389,12 @@ describe('', () => { await commonSetup(); await act(async () => { - await userEvent.type( - selectors.host(), - 'smtp4dev.default.svc.cluster.local', - ); + await userEvent.type(selectors.host(), 'smtp4dev.default.svc.cluster.local'); await userEvent.type(selectors.port(), '42'); await userEvent.type(selectors.sender(), 'renard.admin@scality.com'); - await userEvent.type( - selectors.recipient(), - 'user1@test.com, user2@test.com', - ); + await userEvent.type(selectors.recipient(), 'user1@test.com, user2@test.com'); }); await waitFor(() => { @@ -467,9 +439,7 @@ spec: }, }); await waitFor(() => { - return expect( - screen.getByText(/Redirected Alert Page/i), - ).toBeInTheDocument(); + return expect(screen.getByText(/Redirected Alert Page/i)).toBeInTheDocument(); }); expect(screen.getByText(/Redirected Alert Page/i)).toBeInTheDocument(); }); @@ -480,10 +450,7 @@ spec: await act(async () => { await userEvent.clear(selectors.host()); - await userEvent.type( - selectors.host(), - 'smtp4dev.default.svc.cluster.local', - ); + await userEvent.type(selectors.host(), 'smtp4dev.default.svc.cluster.local'); await userEvent.clear(selectors.port()); await userEvent.type(selectors.port(), '22'); }); @@ -508,10 +475,7 @@ spec: await userEvent.type(selectors.sender(), 'renard.admin@scality.com'); await userEvent.clear(selectors.recipient()); - await userEvent.type( - selectors.recipient(), - 'user1@test.com, user2@test.com', - ); + await userEvent.type(selectors.recipient(), 'user1@test.com, user2@test.com'); await waitFor(() => { expect(selectors.saveButton()).toBeInTheDocument(); @@ -563,9 +527,7 @@ spec: }, }); await waitFor(() => { - return expect( - screen.getByText(/Redirected Alert Page/i), - ).toBeInTheDocument(); + return expect(screen.getByText(/Redirected Alert Page/i)).toBeInTheDocument(); }); expect(screen.getByText(/Redirected Alert Page/i)).toBeInTheDocument(); }); @@ -575,18 +537,12 @@ spec: await act(async () => { await userEvent.click(selectors.enableConfiguration()); - await userEvent.type( - selectors.host(), - 'smtp4dev.default.svc.cluster.local', - ); + await userEvent.type(selectors.host(), 'smtp4dev.default.svc.cluster.local'); await userEvent.type(selectors.port(), '42'); await userEvent.type(selectors.sender(), 'renard.admin@scality.com'); - await userEvent.type( - selectors.recipient(), - 'user1@test.com, user2@test.com', - ); + await userEvent.type(selectors.recipient(), 'user1@test.com, user2@test.com'); }); await waitFor(() => { @@ -637,9 +593,7 @@ spec: }, }); await waitFor(() => { - return expect( - screen.getByText(/Redirected Alert Page/i), - ).toBeInTheDocument(); + return expect(screen.getByText(/Redirected Alert Page/i)).toBeInTheDocument(); }); expect(screen.getByText(/Redirected Alert Page/i)).toBeInTheDocument(); }); @@ -648,10 +602,7 @@ spec: await commonSetup(); await act(async () => { - await userEvent.type( - selectors.host(), - 'smtp4dev.default.svc.cluster.local', - ); + await userEvent.type(selectors.host(), 'smtp4dev.default.svc.cluster.local'); await userEvent.type(selectors.port(), '42'); }); @@ -662,10 +613,7 @@ spec: await userEvent.type(selectors.password(), 'Renard Password'); await userEvent.type(selectors.sender(), 'renard.admin@scality.com'); - await userEvent.type( - selectors.recipient(), - 'user1@test.com, user2@test.com', - ); + await userEvent.type(selectors.recipient(), 'user1@test.com, user2@test.com'); await userEvent.click(selectors.saveButton()); @@ -705,9 +653,7 @@ spec: }, }); await waitFor(() => { - return expect( - screen.getByText(/Redirected Alert Page/i), - ).toBeInTheDocument(); + return expect(screen.getByText(/Redirected Alert Page/i)).toBeInTheDocument(); }); expect(screen.getByText(/Redirected Alert Page/i)).toBeInTheDocument(); }); @@ -716,10 +662,7 @@ spec: await commonSetup(); await act(async () => { - await userEvent.type( - selectors.host(), - 'smtp4dev.default.svc.cluster.local', - ); + await userEvent.type(selectors.host(), 'smtp4dev.default.svc.cluster.local'); await userEvent.type(selectors.port(), '42'); }); @@ -730,10 +673,7 @@ spec: await userEvent.type(selectors.secret(), 'xxxyyyzzz-secret'); await userEvent.type(selectors.sender(), 'renard.admin@scality.com'); - await userEvent.type( - selectors.recipient(), - 'user1@test.com, user2@test.com', - ); + await userEvent.type(selectors.recipient(), 'user1@test.com, user2@test.com'); await userEvent.click(selectors.saveButton()); @@ -773,9 +713,7 @@ spec: }, }); await waitFor(() => { - return expect( - screen.getByText(/Redirected Alert Page/i), - ).toBeInTheDocument(); + return expect(screen.getByText(/Redirected Alert Page/i)).toBeInTheDocument(); }); expect(screen.getByText(/Redirected Alert Page/i)).toBeInTheDocument(); }); @@ -784,10 +722,7 @@ spec: await commonSetup(); await act(async () => { - await userEvent.type( - selectors.host(), - 'smtp4dev.default.svc.cluster.local', - ); + await userEvent.type(selectors.host(), 'smtp4dev.default.svc.cluster.local'); await userEvent.type(selectors.port(), '42'); }); await userEvent.click(selectors.authSelect.authClick()); @@ -798,10 +733,7 @@ spec: await userEvent.type(selectors.password(), 'xxxyyyzzz-password'); await userEvent.type(selectors.sender(), 'renard.admin@scality.com'); - await userEvent.type( - selectors.recipient(), - 'user1@test.com, user2@test.com', - ); + await userEvent.type(selectors.recipient(), 'user1@test.com, user2@test.com'); await userEvent.click(selectors.saveButton()); @@ -842,9 +774,7 @@ spec: }, }); await waitFor(() => { - return expect( - screen.getByText(/Redirected Alert Page/i), - ).toBeInTheDocument(); + return expect(screen.getByText(/Redirected Alert Page/i)).toBeInTheDocument(); }); expect(screen.getByText(/Redirected Alert Page/i)).toBeInTheDocument(); }); @@ -853,18 +783,12 @@ spec: await commonSetup(); await act(async () => { - await userEvent.type( - selectors.host(), - 'smtp4dev.default.svc.cluster.local', - ); + await userEvent.type(selectors.host(), 'smtp4dev.default.svc.cluster.local'); await userEvent.type(selectors.port(), '42'); await userEvent.type(selectors.sender(), 'renard.admin@scality.com'); - await userEvent.type( - selectors.recipient(), - 'user1@test.com, user2@test.com', - ); + await userEvent.type(selectors.recipient(), 'user1@test.com, user2@test.com'); await userEvent.click(selectors.sendTestingEmailButton()); }); @@ -911,9 +835,7 @@ spec: }, }); await waitFor(() => { - return expect( - screen.getByText(/The email has been sent, please check your email/i), - ).toBeInTheDocument(); + return expect(screen.getByText(/The email has been sent, please check your email/i)).toBeInTheDocument(); }); }); @@ -921,10 +843,7 @@ spec: await commonSetup(); await act(async () => { - await userEvent.type( - selectors.host(), - 'smtp4dev.default.svc.cluster.local', - ); + await userEvent.type(selectors.host(), 'smtp4dev.default.svc.cluster.local'); await userEvent.type(selectors.port(), '42'); }); await userEvent.click(selectors.authSelect.authClick()); @@ -934,10 +853,7 @@ spec: await userEvent.type(selectors.password(), 'Renard Password'); await userEvent.type(selectors.sender(), 'renard.admin@scality.com'); - await userEvent.type( - selectors.recipient(), - 'user1@test.com, user2@test.com', - ); + await userEvent.type(selectors.recipient(), 'user1@test.com, user2@test.com'); await userEvent.click(selectors.sendTestingEmailButton()); @@ -984,9 +900,7 @@ spec: }, }); await waitFor(() => { - return expect( - screen.getByText(/The email has been sent, please check your email/i), - ).toBeInTheDocument(); + return expect(screen.getByText(/The email has been sent, please check your email/i)).toBeInTheDocument(); }); }); @@ -994,10 +908,7 @@ spec: await commonSetup(); await act(async () => { - await userEvent.type( - selectors.host(), - 'smtp4dev.default.svc.cluster.local', - ); + await userEvent.type(selectors.host(), 'smtp4dev.default.svc.cluster.local'); await userEvent.type(selectors.port(), '42'); }); @@ -1009,10 +920,7 @@ spec: await userEvent.type(selectors.password(), 'Renard Password'); await userEvent.type(selectors.sender(), 'renard.admin@scality.com'); - await userEvent.type( - selectors.recipient(), - 'user1@test.com, user2@test.com', - ); + await userEvent.type(selectors.recipient(), 'user1@test.com, user2@test.com'); await userEvent.click(selectors.sendTestingEmailButton()); @@ -1060,9 +968,7 @@ spec: }, }); await waitFor(() => { - return expect( - screen.getByText(/The email has been sent, please check your email/i), - ).toBeInTheDocument(); + return expect(screen.getByText(/The email has been sent, please check your email/i)).toBeInTheDocument(); }); }); @@ -1070,18 +976,12 @@ spec: await commonSetup(); await act(async () => { - await userEvent.type( - selectors.host(), - 'smtp4dev.default.svc.cluster.local', - ); + await userEvent.type(selectors.host(), 'smtp4dev.default.svc.cluster.local'); await userEvent.type(selectors.port(), '42'); await userEvent.type(selectors.sender(), 'renard.admin@scality.com'); - await userEvent.type( - selectors.recipient(), - 'user1@test.com, user2@test.com', - ); + await userEvent.type(selectors.recipient(), 'user1@test.com, user2@test.com'); server.use( rest.get( `http://localhost/api/kubernetes/api/v1/namespaces/metalk8s-monitoring/pods/alertmanager-prometheus-operator-alertmanager-0/log`, @@ -1137,15 +1037,11 @@ spec: }, }); await waitFor(() => { - return expect( - screen.getByText(/The email has been sent, please check your email/i), - ).toBeInTheDocument(); + return expect(screen.getByText(/The email has been sent, please check your email/i)).toBeInTheDocument(); }); await waitFor(() => { return expect( - screen.getByText( - /establish connection to server: dial tcp: lookup smtp4dev.default.svc.cluster.local1/i, - ), + screen.getByText(/establish connection to server: dial tcp: lookup smtp4dev.default.svc.cluster.local1/i), ).toBeInTheDocument(); }); }); @@ -1155,16 +1051,9 @@ spec: await act(async () => { await userEvent.type(selectors.sender(), 'fsdjfkl'); - await userEvent.type( - selectors.recipient(), - 'user1@test.com, user2@test.com <>', - ); + await userEvent.type(selectors.recipient(), 'user1@test.com, user2@test.com <>'); }); - expect( - screen.getByText(/The email address is invalid/i), - ).toBeInTheDocument(); - expect( - screen.getByText(/The email addresses are invalid/i), - ).toBeInTheDocument(); + expect(screen.getByText(/The email address is invalid/i)).toBeInTheDocument(); + expect(screen.getByText(/The email addresses are invalid/i)).toBeInTheDocument(); }); }); diff --git a/ui/src/alert-configuration/ConfigureAlerting.tsx b/ui/src/alert-configuration/ConfigureAlerting.tsx index 84bad31319..ef1fc97ec2 100644 --- a/ui/src/alert-configuration/ConfigureAlerting.tsx +++ b/ui/src/alert-configuration/ConfigureAlerting.tsx @@ -35,8 +35,7 @@ import { Metalk8sCSCAlertConfigurationStore } from './infrastructure/Metalk8sCSC import { useBasenameRelativeNavigate } from '@scality/module-federation'; const LogsBanner = ({ logs }: { logs: PromiseResult }) => { - const firstLog = - logs.status === 'success' && logs.value.length > 0 ? logs.value[0] : null; + const firstLog = logs.status === 'success' && logs.value.length > 0 ? logs.value[0] : null; const bannerRef = useRef(null); @@ -52,10 +51,7 @@ const LogsBanner = ({ logs }: { logs: PromiseResult }) => { return (
- } - > + }> {`Error: ${firstLog.message} `} @@ -71,9 +67,7 @@ const rfc5322EmailAddressRegex = /^((([^ ]+ )+<[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*>|[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*|<[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*>)(, ?)?)+$/i; const schema = Joi.object({ - enabled: Joi.boolean() - .required() - .label('Enable Email Notification Configuration'), + enabled: Joi.boolean().required().label('Enable Email Notification Configuration'), host: Joi.string().required().label('SMTP Host'), port: Joi.number().required().min(1).label('SMTP Port'), isTLSEnabled: Joi.boolean().required().label('Enable SMTP Over TLS'), @@ -99,44 +93,26 @@ const schema = Joi.object({ then: Joi.string().required().label('Password'), otherwise: Joi.valid(), }), - from: Joi.string() - .required() - .label('Sender Email Address') - .regex(emailRegex) - .message('The email address is invalid'), + from: Joi.string().required().label('Sender Email Address').regex(emailRegex).message('The email address is invalid'), to: Joi.string() .required() .label('Recipient Email Addresses') .regex(rfc5322EmailAddressRegex) .message('The email addresses are invalid'), - sendResolved: Joi.boolean() - .required() - .label('Enable Receive Resolved Alerts'), + sendResolved: Joi.boolean().required().label('Enable Receive Resolved Alerts'), }); export default function ConfigureAlerting() { const theme = useTheme(); const navigate = useBasenameRelativeNavigate(); const dispatch = useDispatch(); - const { - register, - reset, - handleSubmit, - control, - watch, - getValues, - formState, - } = useForm({ + const { register, reset, handleSubmit, control, watch, getValues, formState } = useForm({ mode: 'onChange', resolver: joiResolver(schema), }); const credsType = watch('type'); - const { - url: kubernetesApiUrl, - url_salt: saltApiUrl, - url_alertmanager: alertManagerUrl, - } = useConfig(); + const { url: kubernetesApiUrl, url_salt: saltApiUrl, url_alertmanager: alertManagerUrl } = useConfig(); const { userData, getToken } = useAuth(); const email = userData?.email || ''; @@ -175,10 +151,9 @@ export default function ConfigureAlerting() { } }, [alertConfiguration.status]); - const { sendTestAlertMutation, logs: testAlertlogs } = - useTestAlertConfiguration({ - alertConfigurationStore, - }); + const { sendTestAlertMutation, logs: testAlertlogs } = useTestAlertConfiguration({ + alertConfigurationStore, + }); useEffect(() => { if (sendTestAlertMutation.status === 'success') { @@ -193,10 +168,7 @@ export default function ConfigureAlerting() { const labelWidth = 270; - const disableFormButton = - editAlertMutation.isLoading || - sendTestAlertMutation.isLoading || - !formState.isDirty; + const disableFormButton = editAlertMutation.isLoading || sendTestAlertMutation.isLoading || !formState.isDirty; if (alertConfiguration.status === 'loading') { return
Loading...
; @@ -225,19 +197,14 @@ export default function ConfigureAlerting() { type="button" variant="secondary" tooltip={ - Object.entries(formState.dirtyFields).filter( - ([key]) => key !== 'enabled', - ).length > 0 + Object.entries(formState.dirtyFields).filter(([key]) => key !== 'enabled').length > 0 ? { overlay: 'Triggering a test mail will restart alerting service, alerts will be retriggered few minutes after.', } : undefined } - disabled={ - sendTestAlertMutation.isLoading || - editAlertMutation.isLoading - } + disabled={sendTestAlertMutation.isLoading || editAlertMutation.isLoading} label={ sendTestAlertMutation.isLoading ? ( - {sendTestAlertMutation.status === 'success' && ( - - )} + {sendTestAlertMutation.status === 'success' && } } > @@ -306,23 +271,14 @@ export default function ConfigureAlerting() { content={} /> - + - } + content={} /> - } + content={} /> - } + content={} /> - + field.onChange(value)} onBlur={field.onBlur} > - - NO AUTHENTICATION - + NO AUTHENTICATION LOGIN - - CRAM-MD5 - + CRAM-MD5 PLAIN ); @@ -395,13 +335,7 @@ export default function ConfigureAlerting() { // @ts-expect-error - FIXME when you are working on it error={formState.errors?.username?.message ?? ''} helpErrorPosition="bottom" - content={ - - } + content={} /> - } + content={} /> ) : ( @@ -433,13 +360,7 @@ export default function ConfigureAlerting() { // @ts-expect-error - FIXME when you are working on it error={formState.errors?.identity?.message ?? ''} helpErrorPosition="bottom" - content={ - - } + content={} /> - } + content={} /> - } + content={} /> ) : ( @@ -486,13 +394,7 @@ export default function ConfigureAlerting() { // @ts-expect-error - FIXME when you are working on it error={formState.errors?.username?.message ?? ''} helpErrorPosition="bottom" - content={ - - } + content={} /> - } + content={} /> ) : ( <> )} - + - } + content={} /> - } + content={} /> diff --git a/ui/src/alert-configuration/domain/AlertConfigurationDomain.ts b/ui/src/alert-configuration/domain/AlertConfigurationDomain.ts index e0e7bf9120..f41fa5b612 100644 --- a/ui/src/alert-configuration/domain/AlertConfigurationDomain.ts +++ b/ui/src/alert-configuration/domain/AlertConfigurationDomain.ts @@ -1,12 +1,7 @@ import { useMemo, useRef, useState } from 'react'; import { useMutation, useQuery, useQueryClient } from 'react-query'; -export const SMTPAuthTypes = [ - 'CRAM-MD5', - 'PLAIN', - 'LOGIN', - 'NO_AUTHENTICATION', -] as const; +export const SMTPAuthTypes = ['CRAM-MD5', 'PLAIN', 'LOGIN', 'NO_AUTHENTICATION'] as const; export type AuthType = (typeof SMTPAuthTypes)[number]; @@ -41,12 +36,7 @@ export type AlertConfiguration = { from: string; to: string; sendResolved: boolean; -} & ( - | PLAINCRedentials - | LOGINCRedentials - | CRAMMD5Credentials - | NO_AUTHENCATIONCredentials -); +} & (PLAINCRedentials | LOGINCRedentials | CRAMMD5Credentials | NO_AUTHENCATIONCredentials); type Loading = 'loading'; type Success = 'success'; @@ -69,10 +59,7 @@ export interface PromiseLoadingResult { status: Loading; } -export type PromiseResult = - | PromiseLoadingResult - | PromiseSucceedResult - | PromiseRejectedResult; +export type PromiseResult = PromiseLoadingResult | PromiseSucceedResult | PromiseRejectedResult; export const useAlertConfiguration = ({ alertConfigurationStore, @@ -149,10 +136,7 @@ export interface IAlertConfigurationStore { getAlertConfiguration(): Promise; putAlertConfiguration(alertConfiguration: AlertConfiguration): Promise; getTestConfiguration(): Promise; - testAlertConfiguration( - alertConfiguration: AlertConfiguration, - configurationHasChanged: boolean, - ): Promise; + testAlertConfiguration(alertConfiguration: AlertConfiguration, configurationHasChanged: boolean): Promise; getAlertStoreLogsForTestAlert(): Promise; getAlertStoreLogs(): Promise; } @@ -170,10 +154,7 @@ export const useEditAlertConfiguration = ({ onSuccess: (_, alertConfiguration) => { queryClient.refetchQueries(['alertstorelogs']); queryClient.setQueryData(['alertstoretestlogs'], []); - queryClient.setQueriesData( - ['alertConfiguration'], - alertConfiguration, - ); + queryClient.setQueriesData(['alertConfiguration'], alertConfiguration); }, }); @@ -205,8 +186,7 @@ export const useTestAlertConfiguration = ({ return alertConfigurationStore.testAlertConfiguration( alertConfiguration, - JSON.stringify(data) !== - JSON.stringify({ ...alertConfiguration, enabled: true }), + JSON.stringify(data) !== JSON.stringify({ ...alertConfiguration, enabled: true }), ); }, onSuccess: () => { @@ -223,9 +203,7 @@ export const useTestAlertConfiguration = ({ refetchInterval: isTestInProgress ? 1_000 : Infinity, }); - const hasFailedToSendTestAlert = !!logsData?.find( - (logLine) => logLine.level === 'ERROR', - ); + const hasFailedToSendTestAlert = !!logsData?.find((logLine) => logLine.level === 'ERROR'); const overOneMinute = testDateRef.current < new Date(Date.now() - 60_000); useMemo(() => { diff --git a/ui/src/alert-configuration/infrastructure/Metalk8sCSCAlertConfigurationStore.ts b/ui/src/alert-configuration/infrastructure/Metalk8sCSCAlertConfigurationStore.ts index 9faab0c40f..cb23726992 100644 --- a/ui/src/alert-configuration/infrastructure/Metalk8sCSCAlertConfigurationStore.ts +++ b/ui/src/alert-configuration/infrastructure/Metalk8sCSCAlertConfigurationStore.ts @@ -1,19 +1,12 @@ import { AlertManagerConfig, Receiver, Route } from './AlertManagerTypes'; -import { - AlertConfiguration, - AlertStoreLogLine, - IAlertConfigurationStore, -} from '../domain/AlertConfigurationDomain'; +import { AlertConfiguration, AlertStoreLogLine, IAlertConfigurationStore } from '../domain/AlertConfigurationDomain'; import YAML from 'yaml'; import { V1ConfigMap, V1NodeList } from '@kubernetes/client-node'; import { getTokenType } from '../../services/platformlibrary/k8s'; type AlertmanagerConfigKind = 'AlertmanagerConfig'; -type Metalk8sCSCConfiguration< - KIND extends string, - T extends Record, -> = { +type Metalk8sCSCConfiguration> = { apiVersion: 'addons.metalk8s.scality.com'; kind: KIND; spec: T; @@ -50,9 +43,7 @@ export type SaltLoginResponse = error: string; }; -export class Metalk8sCSCAlertConfigurationStore - implements IAlertConfigurationStore -{ +export class Metalk8sCSCAlertConfigurationStore implements IAlertConfigurationStore { constructor( private k8sApiBaseUrl: string, private saltApiBaseUrl: string, @@ -84,30 +75,23 @@ export class Metalk8sCSCAlertConfigurationStore const configMap: V1ConfigMap = await configMapResponse.json(); const rawAlertManagerConfig = configMap.data?.['config.yaml'] || ''; - const alertManagerConfig: Metalk8sAlertManagerConfig = YAML.parse( - rawAlertManagerConfig, - ); + const alertManagerConfig: Metalk8sAlertManagerConfig = YAML.parse(rawAlertManagerConfig); return alertManagerConfig; } - async _applyConfigMapChangesAndCallSalt( - newConfig: Metalk8sAlertManagerConfig, - ) { - await fetch( - `${this.k8sApiBaseUrl}/api/v1/namespaces/metalk8s-monitoring/configmaps/metalk8s-alertmanager-config`, - { - method: 'PATCH', - headers: { - 'Content-Type': 'application/merge-patch+json', - Authorization: `Bearer ${await this.getToken()}`, - }, - body: JSON.stringify({ - data: { - ['config.yaml']: YAML.stringify(newConfig), - }, - }), + async _applyConfigMapChangesAndCallSalt(newConfig: Metalk8sAlertManagerConfig) { + await fetch(`${this.k8sApiBaseUrl}/api/v1/namespaces/metalk8s-monitoring/configmaps/metalk8s-alertmanager-config`, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/merge-patch+json', + Authorization: `Bearer ${await this.getToken()}`, }, - ); + body: JSON.stringify({ + data: { + ['config.yaml']: YAML.stringify(newConfig), + }, + }), + }); //Login salt api const saltLoginFetchResponse = await fetch(`${this.saltApiBaseUrl}/login`, { @@ -126,33 +110,26 @@ export class Metalk8sCSCAlertConfigurationStore throw new Error('Error login with salt api'); } - const saltLoginResponse: SaltLoginResponse = - await saltLoginFetchResponse.json(); + const saltLoginResponse: SaltLoginResponse = await saltLoginFetchResponse.json(); if ('error' in saltLoginResponse) { throw new Error('Error login with salt api'); } - const nodesFetchResponse = await fetch( - `${this.k8sApiBaseUrl}/api/v1/nodes`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${await this.getToken()}`, - }, + const nodesFetchResponse = await fetch(`${this.k8sApiBaseUrl}/api/v1/nodes`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${await this.getToken()}`, }, - ); + }); if (nodesFetchResponse.status !== 200) { throw new Error('Error fetching nodes information'); } const nodesResponse: V1NodeList = await nodesFetchResponse.json(); - const metalk8sVersion = - nodesResponse.items[0].metadata?.labels?.[ - 'metalk8s.scality.com/version' - ] || null; + const metalk8sVersion = nodesResponse.items[0].metadata?.labels?.['metalk8s.scality.com/version'] || null; if (!metalk8sVersion) { throw new Error('Error fetching metalk8s version'); @@ -176,32 +153,25 @@ export class Metalk8sCSCAlertConfigurationStore }); } - async _getAlertConfiguration( - selectTestConfig: boolean, - ): Promise { - const alertManagerConfig: Metalk8sAlertManagerConfig = - await this._getAlertManagerConfig(); + async _getAlertConfiguration(selectTestConfig: boolean): Promise { + const alertManagerConfig: Metalk8sAlertManagerConfig = await this._getAlertManagerConfig(); - const currentEmailreceiver: Receiver = - alertManagerConfig.spec.notification?.config?.receivers?.find( - (receiver) => { - return ( - receiver.email_configs && - receiver.email_configs.length > 0 && - (selectTestConfig - ? receiver.name === 'test-receiver-config-from-ui' - : receiver.name !== 'test-receiver-config-from-ui') - ); - }, - ) || { - name: selectTestConfig ? 'test-receiver-config-from-ui' : 'default', - }; + const currentEmailreceiver: Receiver = alertManagerConfig.spec.notification?.config?.receivers?.find((receiver) => { + return ( + receiver.email_configs && + receiver.email_configs.length > 0 && + (selectTestConfig + ? receiver.name === 'test-receiver-config-from-ui' + : receiver.name !== 'test-receiver-config-from-ui') + ); + }) || { + name: selectTestConfig ? 'test-receiver-config-from-ui' : 'default', + }; const receiverName = currentEmailreceiver.name; - const isEnable = - alertManagerConfig.spec.notification?.config?.route?.routes?.find( - (r) => r.receiver === receiverName, - ); + const isEnable = alertManagerConfig.spec.notification?.config?.route?.routes?.find( + (r) => r.receiver === receiverName, + ); const smtpHostAndPort = parseHostAndPort( currentEmailreceiver?.email_configs?.[0].smarthost || @@ -209,26 +179,21 @@ export class Metalk8sCSCAlertConfigurationStore '', ); - const alertConfiguration: Omit< - AlertConfiguration, - 'type' | 'username' | 'password' | 'secret' | 'identity' - > = { + const alertConfiguration: Omit = { enabled: !!isEnable, host: smtpHostAndPort.host, port: smtpHostAndPort.port, isTLSEnabled: !!( currentEmailreceiver?.email_configs?.[0].require_tls === true || (currentEmailreceiver?.email_configs?.[0].require_tls !== false && - alertManagerConfig.spec.notification?.config?.global - ?.smtp_require_tls) + alertManagerConfig.spec.notification?.config?.global?.smtp_require_tls) ), from: currentEmailreceiver?.email_configs?.[0].from || alertManagerConfig.spec.notification?.config?.global?.smtp_from || '', to: currentEmailreceiver?.email_configs?.[0].to || '', - sendResolved: - currentEmailreceiver?.email_configs?.[0].send_resolved === true, + sendResolved: currentEmailreceiver?.email_configs?.[0].send_resolved === true, }; const username = @@ -312,17 +277,17 @@ export class Metalk8sCSCAlertConfigurationStore auth_secret: alertConfiguration.secret, } : alertConfiguration.type === 'LOGIN' - ? { - auth_username: alertConfiguration.username, - auth_password: alertConfiguration.password, - } - : alertConfiguration.type === 'PLAIN' - ? { - auth_identity: alertConfiguration.identity, - auth_username: alertConfiguration.username, - auth_password: alertConfiguration.password, - } - : {}), + ? { + auth_username: alertConfiguration.username, + auth_password: alertConfiguration.password, + } + : alertConfiguration.type === 'PLAIN' + ? { + auth_identity: alertConfiguration.identity, + auth_username: alertConfiguration.username, + auth_password: alertConfiguration.password, + } + : {}), }, ...(currentEmailreceiver.email_configs?.slice(1) || []), ], @@ -330,29 +295,20 @@ export class Metalk8sCSCAlertConfigurationStore } async putAlertConfiguration(alertConfiguration: AlertConfiguration) { - const alertManagerConfig: Metalk8sAlertManagerConfig = - await this._getAlertManagerConfig(); + const alertManagerConfig: Metalk8sAlertManagerConfig = await this._getAlertManagerConfig(); - const currentEmailreceiver: Receiver = - alertManagerConfig.spec.notification?.config?.receivers?.find( - (receiver) => { - return ( - receiver.email_configs && - receiver.email_configs.length > 0 && - receiver.name !== 'test-receiver-config-from-ui' - ); - }, - ) || { name: 'default' }; + const currentEmailreceiver: Receiver = alertManagerConfig.spec.notification?.config?.receivers?.find((receiver) => { + return ( + receiver.email_configs && receiver.email_configs.length > 0 && receiver.name !== 'test-receiver-config-from-ui' + ); + }) || { name: 'default' }; const receiverWithoutTest = alertManagerConfig.spec.notification?.config?.receivers?.filter( (r) => r.name !== 'test-receiver-config-from-ui', ) || []; const emailReceiverIndexToPatch = - receiverWithoutTest.findIndex( - (receiver) => - receiver.email_configs && receiver.email_configs.length > 0, - ) || 0; + receiverWithoutTest.findIndex((receiver) => receiver.email_configs && receiver.email_configs.length > 0) || 0; const newEmailReceiver: Receiver = await this._convertAndMergeEmailReceiver( alertConfiguration, @@ -372,9 +328,7 @@ export class Metalk8sCSCAlertConfigurationStore ) ?? []; const defaultReceiverRouteIndex = - routesWithoutTest.findIndex( - (route) => route.receiver === currentEmailreceiver.name, - ) || 0; + routesWithoutTest.findIndex((route) => route.receiver === currentEmailreceiver.name) || 0; const routes = alertConfiguration.enabled ? [ @@ -382,9 +336,7 @@ export class Metalk8sCSCAlertConfigurationStore newDefaultReceiverRoute, ...(routesWithoutTest?.slice(defaultReceiverRouteIndex + 1) || []), ] - : routesWithoutTest?.filter( - (r) => r.receiver !== currentEmailreceiver.name, - ); + : routesWithoutTest?.filter((r) => r.receiver !== currentEmailreceiver.name); const newConfig: Metalk8sAlertManagerConfig = { ...alertManagerConfig, @@ -399,11 +351,9 @@ export class Metalk8sCSCAlertConfigurationStore routes: routes, }, receivers: [ - ...(receiverWithoutTest?.slice(0, emailReceiverIndexToPatch) || - []), + ...(receiverWithoutTest?.slice(0, emailReceiverIndexToPatch) || []), newEmailReceiver, - ...(receiverWithoutTest?.slice(emailReceiverIndexToPatch + 1) || - []), + ...(receiverWithoutTest?.slice(emailReceiverIndexToPatch + 1) || []), ], }, }, @@ -413,25 +363,17 @@ export class Metalk8sCSCAlertConfigurationStore await this._applyConfigMapChangesAndCallSalt(newConfig); } - async testAlertConfiguration( - alertConfiguration: AlertConfiguration, - configurationHasChanged: boolean, - ) { + async testAlertConfiguration(alertConfiguration: AlertConfiguration, configurationHasChanged: boolean) { if (configurationHasChanged) { // Edit configmap - const alertManagerConfig: Metalk8sAlertManagerConfig = - await this._getAlertManagerConfig(); + const alertManagerConfig: Metalk8sAlertManagerConfig = await this._getAlertManagerConfig(); const testReceiverName = 'test-receiver-config-from-ui'; const emptyReceiver: Receiver = { name: testReceiverName, }; - const newEmailReceiver: Receiver = - await this._convertAndMergeEmailReceiver( - alertConfiguration, - emptyReceiver, - ); + const newEmailReceiver: Receiver = await this._convertAndMergeEmailReceiver(alertConfiguration, emptyReceiver); delete newEmailReceiver.email_configs?.[0].send_resolved; @@ -478,15 +420,12 @@ export class Metalk8sCSCAlertConfigurationStore // We need to wait that alert manager pods is ready to receive alert const fetchAlertManagerPods = async (): Promise => { - const podsResponse = await fetch( - `${this.k8sApiBaseUrl}/api/v1/namespaces/metalk8s-monitoring/pods`, - { - method: 'GET', - headers: { - Authorization: `Bearer ${await this.getToken()}`, - }, + const podsResponse = await fetch(`${this.k8sApiBaseUrl}/api/v1/namespaces/metalk8s-monitoring/pods`, { + method: 'GET', + headers: { + Authorization: `Bearer ${await this.getToken()}`, }, - ); + }); if (podsResponse.status !== 200) { return; @@ -495,22 +434,17 @@ export class Metalk8sCSCAlertConfigurationStore const pods: V1NodeList = await podsResponse.json(); const alertManagerPods = pods.items.filter((pod) => { - return pod.metadata?.name?.includes( - 'alertmanager-prometheus-operator-alertmanager', - ); + return pod.metadata?.name?.includes('alertmanager-prometheus-operator-alertmanager'); }); // compare each pods metadata creation timestamp with the date and check if they status is ready const podsReady = alertManagerPods.every((pod) => { - const podCreationDate = new Date( - pod.metadata?.creationTimestamp || '', - ); + const podCreationDate = new Date(pod.metadata?.creationTimestamp || ''); return ( pod.status?.conditions?.findIndex( - (condition) => - condition.type === 'Ready' && condition.status === 'True', + (condition) => condition.type === 'Ready' && condition.status === 'True', ) !== -1 && podCreationDate.getTime() > date.getTime() ); }); @@ -545,32 +479,27 @@ export class Metalk8sCSCAlertConfigurationStore TLS(${alertConfWithoutCreds.isTLSEnabled ? 'enabled' : 'disabled'}), From(${alertConfWithoutCreds.from}), To(${alertConfWithoutCreds.to}), - Send resolved(${ - alertConfWithoutCreds.sendResolved ? 'enabled' : 'disabled' - }) + Send resolved(${alertConfWithoutCreds.sendResolved ? 'enabled' : 'disabled'}) ${credsTemplate}.`; - const alertFetchResponse = await fetch( - `${this.alertManagerApiBaseUrl}/api/v2/alerts`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify([ - { - labels: { - alertname: 'dummy_alert', - severity: 'critical', - testedOn: new Date().toISOString(), - }, - annotations: { - description: descriptionTemplate, - }, - }, - ]), + const alertFetchResponse = await fetch(`${this.alertManagerApiBaseUrl}/api/v2/alerts`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', }, - ); + body: JSON.stringify([ + { + labels: { + alertname: 'dummy_alert', + severity: 'critical', + testedOn: new Date().toISOString(), + }, + annotations: { + description: descriptionTemplate, + }, + }, + ]), + }); if (alertFetchResponse.status !== 200) { throw new Error(`Error while sending test alert`); @@ -578,9 +507,7 @@ export class Metalk8sCSCAlertConfigurationStore const alertResponse = await alertFetchResponse.json(); if (alertResponse.status !== 'success') { - throw new Error( - `Error while sending test alert : ${alertResponse.error.message}`, - ); + throw new Error(`Error while sending test alert : ${alertResponse.error.message}`); } } @@ -608,20 +535,21 @@ export class Metalk8sCSCAlertConfigurationStore line.includes(`receiver="${receiverName}`) || line.includes(`err="${receiverName}`)) ) { - const components = line.match( - /(?\w+)=("(?(\\"|[^"])+)"|(?[^ ]*))/g, - ); + const components = line.match(/(?\w+)=("(?(\\"|[^"])+)"|(?[^ ]*))/g); - const obj = components?.reduce((acc, component) => { - let [key, value] = component.split('='); + const obj = components?.reduce( + (acc, component) => { + let [key, value] = component.split('='); - value = value.replace(/"/g, ''); + value = value.replace(/"/g, ''); - return { - ...acc, - [key]: value, - }; - }, {} as { err: string; ts: string }); + return { + ...acc, + [key]: value, + }; + }, + {} as { err: string; ts: string }, + ); if (!obj) { return []; diff --git a/ui/src/components/ActiveAlertsCounter.tsx b/ui/src/components/ActiveAlertsCounter.tsx index 7adf450943..ccea30b211 100644 --- a/ui/src/components/ActiveAlertsCounter.tsx +++ b/ui/src/components/ActiveAlertsCounter.tsx @@ -66,20 +66,14 @@ const ActiveAlertsCounter = (props) => { return ( - navigate(getLink(STATUS_CRITICAL))} - data-cy="critical_counter_node" - > + navigate(getLink(STATUS_CRITICAL))} data-cy="critical_counter_node"> Critical {criticalCounter} - navigate(getLink(STATUS_WARNING))} - data-cy="warning_counter_node" - > + navigate(getLink(STATUS_WARNING))} data-cy="warning_counter_node"> Warning diff --git a/ui/src/components/ActiveAlertsFilters.spec.tsx b/ui/src/components/ActiveAlertsFilters.spec.tsx index c2d9c6c658..a559950205 100644 --- a/ui/src/components/ActiveAlertsFilters.spec.tsx +++ b/ui/src/components/ActiveAlertsFilters.spec.tsx @@ -27,9 +27,7 @@ describe('ActiveAlertsFilter', () => { , ); - await userEvent.click( - screen.getByRole('textbox', { name: 'Filter by severity' }), - ); + await userEvent.click(screen.getByRole('textbox', { name: 'Filter by severity' })); await userEvent.click(screen.getByRole('option', { name: 'Critical' })); expect(SUT).toHaveBeenCalledWith( @@ -38,9 +36,7 @@ describe('ActiveAlertsFilter', () => { }), ); - await userEvent.click( - screen.getByRole('textbox', { name: 'Filter by severity' }), - ); + await userEvent.click(screen.getByRole('textbox', { name: 'Filter by severity' })); await userEvent.click(screen.getByRole('option', { name: 'Warning' })); expect(SUT).toHaveBeenCalledWith( expect.objectContaining({ diff --git a/ui/src/components/ActiveAlertsFilters.tsx b/ui/src/components/ActiveAlertsFilters.tsx index f539e0c16e..cfb35afd0c 100644 --- a/ui/src/components/ActiveAlertsFilters.tsx +++ b/ui/src/components/ActiveAlertsFilters.tsx @@ -10,9 +10,7 @@ const ActiveAlertsFilter = () => { const selectedFilter = query.get('severity') ?? 'all'; const displayOptions = ['all', 'warning', 'critical']; - const options = defaultOptions.filter((option) => - displayOptions.includes(option.value), - ); + const options = defaultOptions.filter((option) => displayOptions.includes(option.value)); return ( { }; const WATCHDOG_ALERT = { id: 'fc30b79dbdb0a043', - summary: - 'An alert that should always be firing to certify that Alertmanager is working properly.', + summary: 'An alert that should always be firing to certify that Alertmanager is working properly.', description: 'This is an alert meant to ensure that the entire alerting pipeline is functional.\nThis alert is always firing, therefore it should always be firing in Alertmanager\nand always fire against a receiver. There are integrations with various notification\nmechanisms that send a notification when this alert is not firing. For example the\n"DeadMansSnitch" integration in PagerDuty.', startsAt: '2023-08-11T06:02:15.628Z', @@ -91,8 +90,7 @@ describe('AlertNavbarUpdaterComponent', () => { expect(publishNotification).toBeCalledWith({ id: 'CriticalNotification', title: 'Alerts', - description: - 'There is 1 critical alert currently firing on the platform.', + description: 'There is 1 critical alert currently firing on the platform.', severity: 'critical', createdOn: new Date('2023-08-11T06:03:19.730Z'), redirectUrl: '/platform/alerts', @@ -177,8 +175,7 @@ describe('AlertNavbarUpdaterComponent', () => { expect(publishNotification).toBeCalledWith({ id: 'CriticalNotification', title: 'Alerts', - description: - 'There are 1 critical alert and 1 warning alert currently firing on the platform.', + description: 'There are 1 critical alert and 1 warning alert currently firing on the platform.', severity: 'critical', createdOn: new Date('2023-08-11T06:03:19.730Z'), redirectUrl: '/platform/alerts', diff --git a/ui/src/components/AlertNavbarUpdaterComponent.tsx b/ui/src/components/AlertNavbarUpdaterComponent.tsx index f769548232..7555e1c3b9 100644 --- a/ui/src/components/AlertNavbarUpdaterComponent.tsx +++ b/ui/src/components/AlertNavbarUpdaterComponent.tsx @@ -2,11 +2,7 @@ import { useEffect } from 'react'; import AlertProvider, { useAlerts } from '../containers/AlertProvider'; import { Alert } from '../services/alertUtils'; import FederatedIntlProvider from '../containers/IntlProvider'; -import { - AppConfigProvider, - AppConfigProviderWithoutRedux, - useConfig, -} from '../FederableApp'; +import { AppConfigProvider, AppConfigProviderWithoutRedux, useConfig } from '../FederableApp'; type Notification = { id: string; @@ -61,14 +57,10 @@ function publishCriticalNotification( warningAlerts.length > 0 ? `There ${alertsNum > 1 ? 'are' : 'is'} ${ criticalAlerts.length - } critical alert${criticalAlerts.length > 1 ? 's' : ''} and ${ - warningAlerts.length - } warning alert${ + } critical alert${criticalAlerts.length > 1 ? 's' : ''} and ${warningAlerts.length} warning alert${ warningAlerts.length > 1 ? 's' : '' } currently firing on the platform.` - : `There ${alertsNum > 1 ? 'are' : 'is'} ${ - criticalAlerts.length - } critical alert${ + : `There ${alertsNum > 1 ? 'are' : 'is'} ${criticalAlerts.length} critical alert${ criticalAlerts.length > 1 ? 's' : '' } currently firing on the platform.`, severity: 'critical', @@ -85,9 +77,7 @@ function publishWarningNotification( publishNotification({ id: WARNING_NOTIFICATION_ID, title: 'Alerts', - description: `There ${alertsNum > 1 ? 'are' : 'is'} ${ - warningAlerts.length - } warning alert${ + description: `There ${alertsNum > 1 ? 'are' : 'is'} ${warningAlerts.length} warning alert${ warningAlerts.length > 1 ? 's' : '' } currently firing on the platform.`, severity: 'warning', @@ -108,13 +98,9 @@ export const AlertNavbarUpdaterComponentInternal = ({ return new Date(b.startsAt) > new Date(a.startsAt) ? 1 : -1; }); const { ui_base_path } = useConfig(); - const watchdogAlert = alerts?.find( - (alert: Alert) => alert.labels.alertname === WATCHDOG_ALERT_NAME, - ); - const criticalAlerts = - alerts?.filter((alert: Alert) => alert.severity === 'critical') ?? []; - const warningAlerts = - alerts?.filter((alert: Alert) => alert.severity === 'warning') ?? []; + const watchdogAlert = alerts?.find((alert: Alert) => alert.labels.alertname === WATCHDOG_ALERT_NAME); + const criticalAlerts = alerts?.filter((alert: Alert) => alert.severity === 'critical') ?? []; + const warningAlerts = alerts?.filter((alert: Alert) => alert.severity === 'warning') ?? []; useEffect(() => { // We have initialData when loading alerts, so we should check if the query is fetching or not. @@ -150,23 +136,14 @@ export const AlertNavbarUpdaterComponentInternal = ({ if (newlyRaisedAlertNum) { unPublishNotification(CRITICAL_NOTIFICATION_ID); } - publishCriticalNotification( - publishNotification, - warningAlerts, - criticalAlerts, - ui_base_path, - ); + publishCriticalNotification(publishNotification, warningAlerts, criticalAlerts, ui_base_path); } else if (warningAlerts.length) { unPublishNotification(WATCHDOG_ALERT_NAME); unPublishNotification(CRITICAL_NOTIFICATION_ID); if (newlyRaisedAlertNum) { unPublishNotification(WARNING_NOTIFICATION_ID); } - publishWarningNotification( - publishNotification, - warningAlerts, - ui_base_path, - ); + publishWarningNotification(publishNotification, warningAlerts, ui_base_path); } else { unPublishNotification(CRITICAL_NOTIFICATION_ID); unPublishNotification(WARNING_NOTIFICATION_ID); @@ -174,17 +151,8 @@ export const AlertNavbarUpdaterComponentInternal = ({ } // Update the alerts Id in the localstorage - localStorage.setItem( - LOCAL_STORAGE_ALL_ALERTS_ID, - `${alerts?.map((alert) => alert.id).join(',')}`, - ); - }, [ - criticalAlerts.length, - warningAlerts.length, - watchdogAlert === undefined, - status, - isFetching, - ]); + localStorage.setItem(LOCAL_STORAGE_ALL_ALERTS_ID, `${alerts?.map((alert) => alert.id).join(',')}`); + }, [criticalAlerts.length, warningAlerts.length, watchdogAlert === undefined, status, isFetching]); return <>; }; diff --git a/ui/src/components/AlertsTab.tsx b/ui/src/components/AlertsTab.tsx index 0a9ed0ae7c..cbb6a920fc 100644 --- a/ui/src/components/AlertsTab.tsx +++ b/ui/src/components/AlertsTab.tsx @@ -8,13 +8,7 @@ import CircleStatus from './CircleStatus'; import { useIntl } from 'react-intl'; import { NotBoundContainer } from './style/CommonLayoutStyle'; -const AlertsTab = ({ - alerts, - status, -}: { - alerts: Alert[]; - status: 'idle' | 'loading' | 'error' | 'success'; -}) => { +const AlertsTab = ({ alerts, status }: { alerts: Alert[]; status: 'idle' | 'loading' | 'error' | 'success' }) => { const query = useURLQuery(); // Retrieve the severity filter from URL. // Filter more than one severity, the URL should be: @@ -78,12 +72,7 @@ const AlertsTab = ({ width: 'unset', }, Cell: ({ value }) => { - return ( - - ); + return ; }, }, ]; @@ -103,10 +92,7 @@ const AlertsTab = ({ }, }} > - + ); diff --git a/ui/src/components/DashboardAlerts.test.tsx b/ui/src/components/DashboardAlerts.test.tsx index fca56d9fd1..957ef319a5 100644 --- a/ui/src/components/DashboardAlerts.test.tsx +++ b/ui/src/components/DashboardAlerts.test.tsx @@ -90,9 +90,7 @@ describe('the dashboard alerts sub-panel', () => { (useAlerts as any).mockImplementation(() => ({ alerts: [], })); - const { queryByTestId, getByTestId, getByText } = render( - , - ); + const { queryByTestId, getByTestId, getByText } = render(); expect(getByText('No active alerts')).toBeInTheDocument(); expect(getByTestId('all-alert-badge')).toHaveTextContent('0'); expect(queryByTestId('warning-alert-badge')).not.toBeInTheDocument(); diff --git a/ui/src/components/DashboardAlerts.tsx b/ui/src/components/DashboardAlerts.tsx index 3e307aa53c..89e1a11c61 100644 --- a/ui/src/components/DashboardAlerts.tsx +++ b/ui/src/components/DashboardAlerts.tsx @@ -5,10 +5,7 @@ import { useMemo } from 'react'; import { useIntl } from 'react-intl'; import styled from 'styled-components'; import { useAlertLibrary, useAlerts } from '../containers/AlertProvider'; -import { - useDiscoveredViews, - useLinkOpener, -} from '../containers/ConfigProvider'; +import { useDiscoveredViews, useLinkOpener } from '../containers/ConfigProvider'; import { getChildrenAlerts } from '../services/alertUtils'; import { useBasenameRelativeNavigate } from '@scality/module-federation'; @@ -47,18 +44,11 @@ const DashboardAlerts = () => { // in MetalK8s dashboard, we want to display the number of the alerts only for metalk8s namespace const metalk8sAtomicAlerts = useMemo(() => { if (topLevelAlerts?.alerts?.length && alerts?.alerts?.length) - return getChildrenAlerts( - topLevelAlerts.alerts.map((alert) => alert.childrenJsonPath) || [], - alerts.alerts, - ); + return getChildrenAlerts(topLevelAlerts.alerts.map((alert) => alert.childrenJsonPath) || [], alerts.alerts); else return []; }, [JSON.stringify(alerts.alerts), JSON.stringify(topLevelAlerts.alerts)]); - const criticalAlerts = metalk8sAtomicAlerts.filter( - (alert) => alert.severity === 'critical', - ); - const warningAlerts = metalk8sAtomicAlerts.filter( - (alert) => alert.severity === 'warning', - ); + const criticalAlerts = metalk8sAtomicAlerts.filter((alert) => alert.severity === 'critical'); + const warningAlerts = metalk8sAtomicAlerts.filter((alert) => alert.severity === 'warning'); const totalAlerts = criticalAlerts.length + warningAlerts.length; return ( @@ -68,11 +58,7 @@ const DashboardAlerts = () => { id: 'platform_active_alerts', })} - +
{totalAlerts === 0 ? ( @@ -85,19 +71,11 @@ const DashboardAlerts = () => {
Critical - +
Warning - +
[ - getNodesPlanesBandwidthInQuery(timeSpanProps, devices), - ], - getBelowQueries: (timeSpanProps) => [ - getNodesPlanesBandwidthOutQuery(timeSpanProps, devices), - ], + getAboveQueries: (timeSpanProps) => [getNodesPlanesBandwidthInQuery(timeSpanProps, devices)], + getBelowQueries: (timeSpanProps) => [getNodesPlanesBandwidthOutQuery(timeSpanProps, devices)], // @ts-expect-error - FIXME when you are working on it transformPrometheusDataToSeries: useCallback( ([prometheusResultAbove], [prometheusResultBelow]) => { @@ -113,13 +101,7 @@ const DashboardBandwidthChartWithoutQuantile = ({ ); }; -const DashboardBandwidthChart = ({ - title, - plane, -}: { - title: string; - plane: 'controlPlane' | 'workloadPlane'; -}) => { +const DashboardBandwidthChart = ({ title, plane }: { title: string; plane: 'controlPlane' | 'workloadPlane' }) => { const dispatch = useDispatch(); useEffect(() => { dispatch(fetchNodesAction()); @@ -132,12 +114,8 @@ const DashboardBandwidthChart = ({ { const { isLoading, series, startingTimeStamp } = useSingleChartSerie({ getQuery: (timeSpanProps) => getNodesCPUUsageQuery(timeSpanProps), transformPrometheusDataToSeries: useCallback( - (prometheusResult) => - getMultiResourceSeriesForChart(prometheusResult, nodeAddresses), + (prometheusResult) => getMultiResourceSeriesForChart(prometheusResult, nodeAddresses), //Expect warning because of complex dependency // eslint-disable-next-line react-hooks/exhaustive-deps [JSON.stringify(nodeAddresses)], diff --git a/ui/src/components/DashboardChartMemory.tsx b/ui/src/components/DashboardChartMemory.tsx index 51a500bf7a..6c7a795749 100644 --- a/ui/src/components/DashboardChartMemory.tsx +++ b/ui/src/components/DashboardChartMemory.tsx @@ -1,16 +1,7 @@ -import { - LineTimeSerieChart, - useMetricsTimeSpan, - useChartId, -} from '@scality/core-ui/dist/next'; +import { LineTimeSerieChart, useMetricsTimeSpan, useChartId } from '@scality/core-ui/dist/next'; import { useChartLegendRegistration } from '../hooks/useChartLegendRegistration'; import { useCallback } from 'react'; -import { - useNodes, - useNodeAddressesSelector, - useSingleChartSerie, - useShowQuantileChart, -} from '../hooks'; +import { useNodes, useNodeAddressesSelector, useSingleChartSerie, useShowQuantileChart } from '../hooks'; import { getNodesMemoryOutpassingThresholdQuery, getNodesMemoryQuantileQuery, @@ -48,10 +39,7 @@ const DashboardChartMemoryWithoutQuantiles = () => { getQuery: (timeSpanProps) => getNodesMemoryQuery(timeSpanProps), transformPrometheusDataToSeries: useCallback( (prometheusResult) => { - const result = getMultiResourceSeriesForChart( - prometheusResult, - nodeAddresses, - ); + const result = getMultiResourceSeriesForChart(prometheusResult, nodeAddresses); return result; }, //Expect warning because of complex dependency diff --git a/ui/src/components/DashboardChartSystemLoad.tsx b/ui/src/components/DashboardChartSystemLoad.tsx index 314114c455..ade94e5687 100644 --- a/ui/src/components/DashboardChartSystemLoad.tsx +++ b/ui/src/components/DashboardChartSystemLoad.tsx @@ -1,17 +1,8 @@ -import { - LineTimeSerieChart, - useMetricsTimeSpan, - useChartId, -} from '@scality/core-ui/dist/next'; +import { LineTimeSerieChart, useMetricsTimeSpan, useChartId } from '@scality/core-ui/dist/next'; import { useChartLegendRegistration } from '../hooks/useChartLegendRegistration'; import { useCallback } from 'react'; -import { - useNodeAddressesSelector, - useNodes, - useShowQuantileChart, - useSingleChartSerie, -} from '../hooks'; +import { useNodeAddressesSelector, useNodes, useShowQuantileChart, useSingleChartSerie } from '../hooks'; import { getMultiResourceSeriesForChart } from '../services/graphUtils'; import { getNodesSystemLoadOutpassingThresholdQuery, @@ -48,8 +39,7 @@ const DashboardChartSystemLoadWithoutQuantiles = () => { const { isLoading, series, startingTimeStamp } = useSingleChartSerie({ getQuery: (timeSpanProps) => getNodesSystemLoadQuery(timeSpanProps), transformPrometheusDataToSeries: useCallback( - (prometheusResult) => - getMultiResourceSeriesForChart(prometheusResult, nodeAddresses), + (prometheusResult) => getMultiResourceSeriesForChart(prometheusResult, nodeAddresses), //Expect warning because of complex dependency // eslint-disable-next-line react-hooks/exhaustive-deps [JSON.stringify(nodeAddresses)], diff --git a/ui/src/components/DashboardChartThroughput.tsx b/ui/src/components/DashboardChartThroughput.tsx index 862e0922f4..7cd3e6de4f 100644 --- a/ui/src/components/DashboardChartThroughput.tsx +++ b/ui/src/components/DashboardChartThroughput.tsx @@ -1,17 +1,8 @@ -import { - LineTimeSerieChart, - useMetricsTimeSpan, - useChartId, -} from '@scality/core-ui/dist/next'; +import { LineTimeSerieChart, useMetricsTimeSpan, useChartId } from '@scality/core-ui/dist/next'; import { useChartLegendRegistration } from '../hooks/useChartLegendRegistration'; import { useCallback } from 'react'; -import { - useNodeAddressesSelector, - useNodes, - useShowQuantileChart, - useSymetricalChartSeries, -} from '../hooks'; +import { useNodeAddressesSelector, useNodes, useShowQuantileChart, useSymetricalChartSeries } from '../hooks'; import { getNodesThroughputOutpassingThresholdQuery, getNodesThroughputReadQuantileQuery, @@ -22,11 +13,7 @@ import { } from '../services/platformlibrary/metrics'; import { getMultipleSymmetricalSeries } from '../services/graphUtils'; import SymmetricalQuantileChart from './SymmetricalQuantileChart'; -import { - HEIGHT_SYMMETRICAL_CHART, - UNIT_RANGE_BS, - YAXIS_TITLE_READ_WRITE, -} from '../constants'; +import { HEIGHT_SYMMETRICAL_CHART, UNIT_RANGE_BS, YAXIS_TITLE_READ_WRITE } from '../constants'; const DashboardChartThroughput = () => { const { isShowQuantileChart } = useShowQuantileChart(); @@ -36,12 +23,8 @@ const DashboardChartThroughput = () => { { const { interval, duration } = useMetricsTimeSpan(); const { isLoading, series, startingTimeStamp } = useSymetricalChartSeries({ - getAboveQueries: (timeSpanProps) => [ - getNodesThroughputWriteQuery(timeSpanProps), - ], - getBelowQueries: (timeSpanProps) => [ - getNodesThroughputReadQuery(timeSpanProps), - ], + getAboveQueries: (timeSpanProps) => [getNodesThroughputWriteQuery(timeSpanProps)], + getBelowQueries: (timeSpanProps) => [getNodesThroughputReadQuery(timeSpanProps)], transformPrometheusDataToSeries: useCallback( ([prometheusResultAbove], [prometheusResultBelow]) => { if (!prometheusResultAbove || !prometheusResultBelow) { diff --git a/ui/src/components/DashboardGlobalHealth.tsx b/ui/src/components/DashboardGlobalHealth.tsx index 45049d36e5..8f560fb344 100644 --- a/ui/src/components/DashboardGlobalHealth.tsx +++ b/ui/src/components/DashboardGlobalHealth.tsx @@ -12,15 +12,8 @@ import { Stack, IconHelp, } from '@scality/core-ui'; -import { - Alert, - GlobalHealthBar as GlobalHealthBarRecharts, -} from '@scality/core-ui/dist/next'; -import { - highestAlertToStatus, - useAlertLibrary, - useHighestSeverityAlerts, -} from '../containers/AlertProvider'; +import { Alert, GlobalHealthBar as GlobalHealthBarRecharts } from '@scality/core-ui/dist/next'; +import { highestAlertToStatus, useAlertLibrary, useHighestSeverityAlerts } from '../containers/AlertProvider'; import { useIntl } from 'react-intl'; import { useStartingTimeStamp } from '../containers/StartTimeProvider'; import CircleStatus from './CircleStatus'; @@ -48,12 +41,8 @@ const DashboardGlobalHealth = () => { const { startingTimeISO, currentTimeISO } = useStartingTimeStamp(); const alertsLibrary = useAlertLibrary(); const { duration } = useMetricsTimeSpan(); - const { data: alerts, status: historyAlertStatus } = useQuery( - getClusterAlertSegmentQuery(duration), - ); - const platformHighestSeverityAlert = useHighestSeverityAlerts( - alertsLibrary.getPlatformAlertSelectors(), - ); + const { data: alerts, status: historyAlertStatus } = useQuery(getClusterAlertSegmentQuery(duration)); + const platformHighestSeverityAlert = useHighestSeverityAlerts(alertsLibrary.getPlatformAlertSelectors()); const platformStatus = highestAlertToStatus(platformHighestSeverityAlert); return ( @@ -92,9 +81,7 @@ const DashboardGlobalHealth = () => { }) .split('\n') .map((line, key) => ( - - {line} - + {line} ))} } @@ -116,8 +103,7 @@ const DashboardGlobalHealth = () => { startsAt: startingTimeISO, endsAt: currentTimeISO, severity: 'unavailable', - description: - 'Failed to load alert history for the selected period', + description: 'Failed to load alert history for the selected period', }, ] as Alert[]) : alerts || [] diff --git a/ui/src/components/DashboardInventory.test.tsx b/ui/src/components/DashboardInventory.test.tsx index 8163e93e36..60df7d6e5b 100644 --- a/ui/src/components/DashboardInventory.test.tsx +++ b/ui/src/components/DashboardInventory.test.tsx @@ -4,10 +4,7 @@ import DashboardInventory from './DashboardInventory'; import { waitForLoadingToFinish, render } from './__TEST__/util'; import type { Alert } from '../services/alertUtils'; import { useHighestSeverityAlerts } from '../containers/AlertProvider'; -import { - getNodesCountQuery, - getVolumesCountQuery, -} from '../services/platformlibrary/k8s'; +import { getNodesCountQuery, getVolumesCountQuery } from '../services/platformlibrary/k8s'; import { STATUS_WARNING, STATUS_CRITICAL, STATUS_HEALTH } from '../constants'; const alertsCritical = [ { @@ -62,12 +59,8 @@ describe('the dashboard inventory panel', () => { // Loading await waitForLoadingToFinish(); // Verify - expect( - screen.getAllByLabelText(`Node-backend ${STATUS_CRITICAL}`).length, - ).toEqual(1); - expect( - screen.getAllByLabelText(`Volume-backend ${STATUS_CRITICAL}`).length, - ).toEqual(1); + expect(screen.getAllByLabelText(`Node-backend ${STATUS_CRITICAL}`).length).toEqual(1); + expect(screen.getAllByLabelText(`Volume-backend ${STATUS_CRITICAL}`).length).toEqual(1); }); test('displays properly the status WARNING for nodes and volumes', async () => { // Have to any type jest.fn function to avoid Flow warning for mockImplementation() @@ -77,12 +70,8 @@ describe('the dashboard inventory panel', () => { // Loading await waitForLoadingToFinish(); // Verify - expect( - screen.getAllByLabelText(`Node-backend ${STATUS_WARNING}`).length, - ).toEqual(1); - expect( - screen.getAllByLabelText(`Volume-backend ${STATUS_WARNING}`).length, - ).toEqual(1); + expect(screen.getAllByLabelText(`Node-backend ${STATUS_WARNING}`).length).toEqual(1); + expect(screen.getAllByLabelText(`Volume-backend ${STATUS_WARNING}`).length).toEqual(1); }); test('displays properly the status HEALTHY for nodes and volumes', async () => { // Have to any type jest.fn function to avoid Flow warning for mockImplementation() @@ -92,12 +81,8 @@ describe('the dashboard inventory panel', () => { // Loading await waitForLoadingToFinish(); // Verify - expect( - screen.getAllByLabelText(`Node-backend ${STATUS_HEALTH}`).length, - ).toEqual(1); - expect( - screen.getAllByLabelText(`Volume-backend ${STATUS_HEALTH}`).length, - ).toEqual(1); + expect(screen.getAllByLabelText(`Node-backend ${STATUS_HEALTH}`).length).toEqual(1); + expect(screen.getAllByLabelText(`Volume-backend ${STATUS_HEALTH}`).length).toEqual(1); }); test('displays the loader if the query does not return a result', async () => { // Have to any type jest.fn function to avoid Flow warning for mockImplementation() diff --git a/ui/src/components/DashboardInventory.tsx b/ui/src/components/DashboardInventory.tsx index 677d3a1fa7..3e0873ef77 100644 --- a/ui/src/components/DashboardInventory.tsx +++ b/ui/src/components/DashboardInventory.tsx @@ -5,17 +5,10 @@ import { useQuery } from 'react-query'; import styled from 'styled-components'; import { PageSubtitle } from '../components/style/CommonLayoutStyle'; import { STATUS_CRITICAL, STATUS_WARNING } from '../constants'; -import { - highestAlertToStatus, - useAlertLibrary, - useHighestSeverityAlerts, -} from '../containers/AlertProvider'; +import { highestAlertToStatus, useAlertLibrary, useHighestSeverityAlerts } from '../containers/AlertProvider'; import { useAuth } from '../containers/PrivateRoute'; import { useTypedSelector } from '../hooks'; -import { - getNodesCountQuery, - getVolumesCountQuery, -} from '../services/platformlibrary/k8s'; +import { getNodesCountQuery, getVolumesCountQuery } from '../services/platformlibrary/k8s'; import { useBasenameRelativeNavigate } from '@scality/module-federation'; const InventoryContainer = styled.div` @@ -54,13 +47,9 @@ const getStatusColor = (status) => { const DashboardInventory = () => { const intl = useIntl(); const alertsLibrary = useAlertLibrary(); - const nodesAlerts = useHighestSeverityAlerts( - alertsLibrary.getNodesAlertSelectors(), - ); + const nodesAlerts = useHighestSeverityAlerts(alertsLibrary.getNodesAlertSelectors()); const nodesStatus = highestAlertToStatus(nodesAlerts); - const volumesAlerts = useHighestSeverityAlerts( - alertsLibrary.getVolumesAlertSelectors(), - ); + const volumesAlerts = useHighestSeverityAlerts(alertsLibrary.getVolumesAlertSelectors()); const volumesStatus = highestAlertToStatus(volumesAlerts); const { getToken } = useAuth(); const config = useTypedSelector((state) => state.config.api?.url); @@ -101,16 +90,10 @@ const DashboardInventory = () => { - + - - {nodesCount as number} - + {nodesCount as number} @@ -136,16 +119,10 @@ const DashboardInventory = () => { - + - - {volumesCount as number} - + {volumesCount as number} diff --git a/ui/src/components/DashboardMetrics.tsx b/ui/src/components/DashboardMetrics.tsx index f05a86785d..a8342b5d29 100644 --- a/ui/src/components/DashboardMetrics.tsx +++ b/ui/src/components/DashboardMetrics.tsx @@ -1,18 +1,10 @@ import React from 'react'; -import { - Box, - Button, - ChartLegend, - ChartLegendWrapper, -} from '@scality/core-ui/dist/next'; +import { Box, Button, ChartLegend, ChartLegendWrapper } from '@scality/core-ui/dist/next'; import { useIntl } from 'react-intl'; import { GRAFANA_DASHBOARDS } from '../constants'; import { createColorSet } from '../services/graphUtils'; -import { - PageSubtitle, - GraphsWrapper, -} from '../components/style/CommonLayoutStyle'; +import { PageSubtitle, GraphsWrapper } from '../components/style/CommonLayoutStyle'; import DashboardChartCpuUsage from './DashboardChartCpuUsage'; import DashboardChartThroughput from './DashboardChartThroughput'; import DashboardChartSystemLoad from './DashboardChartSystemLoad'; @@ -35,9 +27,7 @@ export const QuantileHelpTooltip = () => { }) .split('\n') .map((line, key) => ( - - {line} - + {line} ))} } diff --git a/ui/src/components/DashboardNetwork.tsx b/ui/src/components/DashboardNetwork.tsx index 7ec761e788..4b648f7b94 100644 --- a/ui/src/components/DashboardNetwork.tsx +++ b/ui/src/components/DashboardNetwork.tsx @@ -45,19 +45,9 @@ const DashboardNetwork = () => { - - - + + + diff --git a/ui/src/components/DashboardPlane.test.tsx b/ui/src/components/DashboardPlane.test.tsx index 77f9887e9f..327db8ecf3 100644 --- a/ui/src/components/DashboardPlane.test.tsx +++ b/ui/src/components/DashboardPlane.test.tsx @@ -48,9 +48,7 @@ describe("the dashboard network's plane panel", () => { // Have to any type jest.fn function to avoid Flow warning for mockImplementation() (useHighestSeverityAlerts as any).mockImplementation(() => noAlerts); render(); - expect( - screen.getAllByLabelText(`Check-circle status ${STATUS_HEALTH}`), - ).toHaveLength(NB_ITEMS); + expect(screen.getAllByLabelText(`Check-circle status ${STATUS_HEALTH}`)).toHaveLength(NB_ITEMS); }); test('displays 2 warning statuses when warning alerts are present as well as link to the alerts page', async () => { // Have to any type jest.fn function to avoid Flow warning for mockImplementation() @@ -58,9 +56,7 @@ describe("the dashboard network's plane panel", () => { // Render render(); // Verify - expect( - screen.getAllByLabelText(`Exclamation-circle status ${STATUS_WARNING}`), - ).toHaveLength(NB_ITEMS); + expect(screen.getAllByLabelText(`Exclamation-circle status ${STATUS_WARNING}`)).toHaveLength(NB_ITEMS); expect(screen.getAllByTestId('alert-link')).toHaveLength(NB_ITEMS); }); test('displays 2 critical statuses when warning alerts are present as well as link to the alerts page', async () => { @@ -69,9 +65,7 @@ describe("the dashboard network's plane panel", () => { // Render render(); // Verify - expect( - screen.getAllByLabelText(`Times-circle status ${STATUS_CRITICAL}`), - ).toHaveLength(NB_ITEMS); + expect(screen.getAllByLabelText(`Times-circle status ${STATUS_CRITICAL}`)).toHaveLength(NB_ITEMS); expect(screen.getAllByTestId('alert-link')).toHaveLength(NB_ITEMS); }); }); diff --git a/ui/src/components/DashboardPlaneHealth.tsx b/ui/src/components/DashboardPlaneHealth.tsx index 669ea8578f..40a58700a4 100644 --- a/ui/src/components/DashboardPlaneHealth.tsx +++ b/ui/src/components/DashboardPlaneHealth.tsx @@ -1,19 +1,13 @@ import React from 'react'; import { useIntl } from 'react-intl'; -import { - useAlertLibrary, - useHighestSeverityAlerts, - highestAlertToStatus, -} from '../containers/AlertProvider'; +import { useAlertLibrary, useHighestSeverityAlerts, highestAlertToStatus } from '../containers/AlertProvider'; import HealthItem from './HealthItem'; import { spacing, Stack } from '@scality/core-ui'; const DashboardPlaneHealth = () => { const intl = useIntl(); const alertsLibrary = useAlertLibrary(); - const planesHighestSecurityAlert = useHighestSeverityAlerts( - alertsLibrary.getNetworksAlertSelectors(), - ); + const planesHighestSecurityAlert = useHighestSeverityAlerts(alertsLibrary.getNetworksAlertSelectors()); const planesStatus = highestAlertToStatus(planesHighestSecurityAlert); return ( diff --git a/ui/src/components/DashboardServices.test.tsx b/ui/src/components/DashboardServices.test.tsx index a92cae69be..a8886283d0 100644 --- a/ui/src/components/DashboardServices.test.tsx +++ b/ui/src/components/DashboardServices.test.tsx @@ -47,9 +47,7 @@ describe('the dashboard inventory panel', () => { // Render render(); // Verify - expect( - screen.getAllByLabelText(`Check-circle status ${STATUS_HEALTH}`), - ).toHaveLength(8); + expect(screen.getAllByLabelText(`Check-circle status ${STATUS_HEALTH}`)).toHaveLength(8); }); test('displays the services panel and display all 8 warning statuses when warning alerts are present as well as link to the alerts page', async () => { // Have to any type jest.fn function to avoid Flow warning for mockImplementation() @@ -57,9 +55,7 @@ describe('the dashboard inventory panel', () => { // Render render(); // Verify - expect( - screen.getAllByLabelText(`Exclamation-circle status ${STATUS_WARNING}`), - ).toHaveLength(8); + expect(screen.getAllByLabelText(`Exclamation-circle status ${STATUS_WARNING}`)).toHaveLength(8); expect(screen.getAllByTestId('alert-link')).toHaveLength(8); }); test('displays the services panel and display all 8 critical statuses when warning alerts are present as well as link to the alerts page', async () => { @@ -68,9 +64,7 @@ describe('the dashboard inventory panel', () => { // Render render(); // Verify - expect( - screen.getAllByLabelText(`Times-circle status ${STATUS_CRITICAL}`), - ).toHaveLength(8); + expect(screen.getAllByLabelText(`Times-circle status ${STATUS_CRITICAL}`)).toHaveLength(8); expect(screen.getAllByTestId('alert-link')).toHaveLength(8); }); }); diff --git a/ui/src/components/DashboardServices.tsx b/ui/src/components/DashboardServices.tsx index 1023de862b..4dd528e6ad 100644 --- a/ui/src/components/DashboardServices.tsx +++ b/ui/src/components/DashboardServices.tsx @@ -3,11 +3,7 @@ import styled from 'styled-components'; import { useIntl } from 'react-intl'; import { spacing } from '@scality/core-ui/dist/style/theme'; import { PageSubtitle } from '../components/style/CommonLayoutStyle'; -import { - useAlertLibrary, - useHighestSeverityAlerts, - highestAlertToStatus, -} from '../containers/AlertProvider'; +import { useAlertLibrary, useHighestSeverityAlerts, highestAlertToStatus } from '../containers/AlertProvider'; import HealthItem from './HealthItem'; const ServiceItems = styled.div` display: flex; @@ -19,49 +15,29 @@ const DashboardServices = () => { const intl = useIntl(); const alertsLibrary = useAlertLibrary(); // K8s Master - const k8sHighestSeverityAlert = useHighestSeverityAlerts( - alertsLibrary.getK8SMasterAlertSelectors(), - ); + const k8sHighestSeverityAlert = useHighestSeverityAlerts(alertsLibrary.getK8SMasterAlertSelectors()); const k8sStatus = highestAlertToStatus(k8sHighestSeverityAlert); // Bootstrap - const bootstrapHighestSeverityAlert = useHighestSeverityAlerts( - alertsLibrary.getBootstrapAlertSelectors(), - ); + const bootstrapHighestSeverityAlert = useHighestSeverityAlerts(alertsLibrary.getBootstrapAlertSelectors()); const bootstrapStatus = highestAlertToStatus(bootstrapHighestSeverityAlert); // Monitoring - const monitoringHighestSeverityAlert = useHighestSeverityAlerts( - alertsLibrary.getMonitoringAlertSelectors(), - ); + const monitoringHighestSeverityAlert = useHighestSeverityAlerts(alertsLibrary.getMonitoringAlertSelectors()); const monitoringStatus = highestAlertToStatus(monitoringHighestSeverityAlert); // Alerting - const alertingHighestSeverityAlert = useHighestSeverityAlerts( - alertsLibrary.getAlertingAlertSelectors(), - ); + const alertingHighestSeverityAlert = useHighestSeverityAlerts(alertsLibrary.getAlertingAlertSelectors()); const alertingStatus = highestAlertToStatus(alertingHighestSeverityAlert); // Logging - const loggingHighestSeverityAlert = useHighestSeverityAlerts( - alertsLibrary.getLoggingAlertSelectors(), - ); + const loggingHighestSeverityAlert = useHighestSeverityAlerts(alertsLibrary.getLoggingAlertSelectors()); const loggingStatus = highestAlertToStatus(loggingHighestSeverityAlert); // Dashboarding - const dashboardingHighestSeverityAlert = useHighestSeverityAlerts( - alertsLibrary.getDashboardingAlertSelectors(), - ); - const dashboardingStatus = highestAlertToStatus( - dashboardingHighestSeverityAlert, - ); + const dashboardingHighestSeverityAlert = useHighestSeverityAlerts(alertsLibrary.getDashboardingAlertSelectors()); + const dashboardingStatus = highestAlertToStatus(dashboardingHighestSeverityAlert); // Ingress Controller - const ingressHighestSeverityAlert = useHighestSeverityAlerts( - alertsLibrary.getIngressControllerAlertSelectors(), - ); + const ingressHighestSeverityAlert = useHighestSeverityAlerts(alertsLibrary.getIngressControllerAlertSelectors()); const ingressStatus = highestAlertToStatus(ingressHighestSeverityAlert); // Authentication - const authenticationHighestSeverityAlert = useHighestSeverityAlerts( - alertsLibrary.getAuthenticationAlertSelectors(), - ); - const authenticationStatus = highestAlertToStatus( - authenticationHighestSeverityAlert, - ); + const authenticationHighestSeverityAlert = useHighestSeverityAlerts(alertsLibrary.getAuthenticationAlertSelectors()); + const authenticationStatus = highestAlertToStatus(authenticationHighestSeverityAlert); return (
@@ -76,16 +52,8 @@ const DashboardServices = () => { id: 'core', })} - - + + @@ -93,26 +61,10 @@ const DashboardServices = () => { id: 'observability', })} - - - - + + + + @@ -120,11 +72,7 @@ const DashboardServices = () => { id: 'access', })} - + { ); }; -export default DashboardServices; \ No newline at end of file +export default DashboardServices; diff --git a/ui/src/components/HealthItem.tsx b/ui/src/components/HealthItem.tsx index ebde176827..0103fc2fea 100644 --- a/ui/src/components/HealthItem.tsx +++ b/ui/src/components/HealthItem.tsx @@ -1,19 +1,10 @@ -import { - FormattedDateTime, - Icon, - StatusText, - Tooltip, - spacing, -} from '@scality/core-ui'; +import { FormattedDateTime, Icon, StatusText, Tooltip, spacing } from '@scality/core-ui'; import { fontSize, fontWeight } from '@scality/core-ui/dist/style/theme'; import { useIntl } from 'react-intl'; import styled from 'styled-components'; import { STATUS_HEALTH } from '../constants'; import type { Status } from '../containers/AlertProvider'; -import { - useDiscoveredViews, - useLinkOpener, -} from '../containers/ConfigProvider'; +import { useDiscoveredViews, useLinkOpener } from '../containers/ConfigProvider'; import type { Alert } from '../services/alertUtils'; import CircleStatus from './CircleStatus'; import { useBasenameRelativeNavigate } from '@scality/module-federation'; @@ -132,10 +123,7 @@ const HealthItem = ({ id: 'start', })} - + )} diff --git a/ui/src/components/InformationList.ts b/ui/src/components/InformationList.ts index 1ea7d352f0..4877127faa 100644 --- a/ui/src/components/InformationList.ts +++ b/ui/src/components/InformationList.ts @@ -1,8 +1,4 @@ -import { - padding, - fontSize, - fontWeight, -} from '@scality/core-ui/dist/style/theme'; +import { padding, fontSize, fontWeight } from '@scality/core-ui/dist/style/theme'; import styled from 'styled-components'; export const InformationListContainer = styled.div` color: ${(props) => props.theme.textPrimary}; @@ -24,4 +20,4 @@ export const InformationValue = styled.span` `; export const InformationMainValue = styled(InformationValue)` font-weight: ${fontWeight.bold}; -`; \ No newline at end of file +`; diff --git a/ui/src/components/Latency.tsx b/ui/src/components/Latency.tsx index 21b9e2474c..95926d6f8d 100644 --- a/ui/src/components/Latency.tsx +++ b/ui/src/components/Latency.tsx @@ -9,27 +9,18 @@ const units = [ { units: 'd', threshold: 24 * 60 * 60 * 1000 * 1000 }, ]; -export const Latency = ({ - latencyInMicroSeconds, -}: { - latencyInMicroSeconds: number; -}) => { +export const Latency = ({ latencyInMicroSeconds }: { latencyInMicroSeconds: number }) => { const readableLatency = useMemo(() => { for (let i = 1; i < units.length; i++) { const unit = units[i]; - const readableLatency = `${( - latencyInMicroSeconds / unit.threshold - ).toFixed(2)} ${unit.units}`; + const readableLatency = `${(latencyInMicroSeconds / unit.threshold).toFixed(2)} ${unit.units}`; if ( i !== units.length - 1 && latencyInMicroSeconds > unit.threshold && latencyInMicroSeconds < units[i + 1].threshold ) { return readableLatency; - } else if ( - i === units.length - 1 && - latencyInMicroSeconds > unit.threshold - ) { + } else if (i === units.length - 1 && latencyInMicroSeconds > unit.threshold) { return readableLatency; } } diff --git a/ui/src/components/MetricChart.tsx b/ui/src/components/MetricChart.tsx index 53bc5d81c3..8fd56500e2 100644 --- a/ui/src/components/MetricChart.tsx +++ b/ui/src/components/MetricChart.tsx @@ -1,17 +1,9 @@ import React, { useCallback, useMemo } from 'react'; import type { UseQueryOptions } from 'react-query'; import 'react-query'; -import { - LineTimeSerieChart, - useChartId, - useMetricsTimeSpan, -} from '@scality/core-ui/dist/next'; +import { LineTimeSerieChart, useChartId, useMetricsTimeSpan } from '@scality/core-ui/dist/next'; import { convertPrometheusResultToSerieWithAverage } from '../services/graphUtils'; -import { - CLUSTER_AVERAGE, - HEIGHT_DEFAULT_CHART, - NODE_SYNC_ID, -} from '../constants'; +import { CLUSTER_AVERAGE, HEIGHT_DEFAULT_CHART, NODE_SYNC_ID } from '../constants'; import { useChartSeries } from '../hooks'; import { TimeSpanProps } from '../services/platformlibrary/metrics'; import { useChartLegendRegistration } from '../hooks/useChartLegendRegistration'; @@ -31,14 +23,8 @@ const MetricChart = ({ nodeName: string; instanceIP: string; showAvg: boolean; - getMetricQuery: ( - instanceIP: string, - timeSpanProps: TimeSpanProps, - ) => UseQueryOptions; - getMetricAvgQuery: ( - timeSpanProps: TimeSpanProps, - showAvg: boolean, - ) => UseQueryOptions; + getMetricQuery: (instanceIP: string, timeSpanProps: TimeSpanProps) => UseQueryOptions; + getMetricAvgQuery: (timeSpanProps: TimeSpanProps, showAvg: boolean) => UseQueryOptions; unitRange?: { threshold: number; label: string; @@ -50,10 +36,7 @@ const MetricChart = ({ getQueries: useCallback( (timeSpanProps) => { if (showAvg) { - return [ - getMetricQuery(instanceIP, timeSpanProps), - getMetricAvgQuery(timeSpanProps, showAvg), - ]; + return [getMetricQuery(instanceIP, timeSpanProps), getMetricAvgQuery(timeSpanProps, showAvg)]; } else { return [getMetricQuery(instanceIP, timeSpanProps)]; } @@ -63,11 +46,7 @@ const MetricChart = ({ transformPrometheusDataToSeries: useCallback( ([result, resultAvg]) => { if (showAvg) { - return convertPrometheusResultToSerieWithAverage( - result, - nodeName, - resultAvg, - ); + return convertPrometheusResultToSerieWithAverage(result, nodeName, resultAvg); } else { return convertPrometheusResultToSerieWithAverage(result, nodeName); } @@ -75,10 +54,7 @@ const MetricChart = ({ [nodeName, showAvg], ), }); - const additionalNames = useMemo( - () => (showAvg ? [CLUSTER_AVERAGE] : []), - [showAvg], - ); + const additionalNames = useMemo(() => (showAvg ? [CLUSTER_AVERAGE] : []), [showAvg]); useChartLegendRegistration({ chartId, series, diff --git a/ui/src/components/MetricSymmetricalChart.tsx b/ui/src/components/MetricSymmetricalChart.tsx index d8761e1bcc..4328dea0f7 100644 --- a/ui/src/components/MetricSymmetricalChart.tsx +++ b/ui/src/components/MetricSymmetricalChart.tsx @@ -1,17 +1,9 @@ import React, { useCallback, useMemo } from 'react'; import type { UseQueryOptions } from 'react-query'; import 'react-query'; -import { - LineTimeSerieChart, - useChartId, - useMetricsTimeSpan, -} from '@scality/core-ui/dist/next'; +import { LineTimeSerieChart, useChartId, useMetricsTimeSpan } from '@scality/core-ui/dist/next'; import { getSeriesForSymmetricalChart } from '../services/graphUtils'; -import { - CLUSTER_AVERAGE, - HEIGHT_SYMMETRICAL_CHART, - NODE_SYNC_ID, -} from '../constants'; +import { CLUSTER_AVERAGE, HEIGHT_SYMMETRICAL_CHART, NODE_SYNC_ID } from '../constants'; import { NodesState } from '../ducks/app/nodes'; import { useSymetricalChartSeries } from '../hooks'; import { TimeSpanProps } from '../services/platformlibrary/metrics'; @@ -40,16 +32,8 @@ const MetricSymmetricalChart = ({ instanceIP: string; showAvg: boolean; nodesIPsInfo: NodesState['IPsInfo']; - getMetricAboveQuery: ( - instanceIP: string, - timeSpanProps: TimeSpanProps, - planeInterface: string, - ) => UseQueryOptions; - getMetricBelowQuery: ( - instanceIP: string, - timeSpanProps: TimeSpanProps, - planeInterface: string, - ) => UseQueryOptions; + getMetricAboveQuery: (instanceIP: string, timeSpanProps: TimeSpanProps, planeInterface: string) => UseQueryOptions; + getMetricBelowQuery: (instanceIP: string, timeSpanProps: TimeSpanProps, planeInterface: string) => UseQueryOptions; getMetricAboveAvgQuery: ( timeSpanProps: TimeSpanProps, showAvg: boolean, @@ -80,27 +64,13 @@ const MetricSymmetricalChart = ({ return [ getMetricAboveQuery(instanceIP, timeSpanProps, planeInterface), - getMetricAboveAvgQuery( - timeSpanProps, - showAvg, - instanceIP, - nodesIPsInfo, - ), + getMetricAboveAvgQuery(timeSpanProps, showAvg, instanceIP, nodesIPsInfo), ]; } else { - return [ - getMetricAboveQuery(instanceIP, timeSpanProps, planeInterface), - ]; + return [getMetricAboveQuery(instanceIP, timeSpanProps, planeInterface)]; } }, - [ - instanceIP, - showAvg, - planeInterface, - nodesIPsInfo, - getMetricAboveQuery, - getMetricAboveAvgQuery, - ], + [instanceIP, showAvg, planeInterface, nodesIPsInfo, getMetricAboveQuery, getMetricAboveAvgQuery], ), getBelowQueries: useCallback( (timeSpanProps) => { @@ -108,27 +78,13 @@ const MetricSymmetricalChart = ({ return [ getMetricBelowQuery(instanceIP, timeSpanProps, planeInterface), - getMetricBelowAvgQuery( - timeSpanProps, - showAvg, - instanceIP, - nodesIPsInfo, - ), + getMetricBelowAvgQuery(timeSpanProps, showAvg, instanceIP, nodesIPsInfo), ]; } else { - return [ - getMetricBelowQuery(instanceIP, timeSpanProps, planeInterface), - ]; + return [getMetricBelowQuery(instanceIP, timeSpanProps, planeInterface)]; } }, - [ - instanceIP, - showAvg, - planeInterface, - nodesIPsInfo, - getMetricBelowQuery, - getMetricBelowAvgQuery, - ], + [instanceIP, showAvg, planeInterface, nodesIPsInfo, getMetricBelowQuery, getMetricBelowAvgQuery], ), transformPrometheusDataToSeries: useCallback( (resultsAbove, resultsBelow) => { @@ -161,10 +117,7 @@ const MetricSymmetricalChart = ({ [showAvg, nodeName, metricPrefixAbove, metricPrefixBelow], ), }); - const additionalNames = useMemo( - () => (showAvg ? [CLUSTER_AVERAGE] : []), - [showAvg], - ); + const additionalNames = useMemo(() => (showAvg ? [CLUSTER_AVERAGE] : []), [showAvg]); useChartLegendRegistration({ chartId, series, diff --git a/ui/src/components/ModalFormStyle.ts b/ui/src/components/ModalFormStyle.ts index 1c1fd7d121..7ade914bca 100644 --- a/ui/src/components/ModalFormStyle.ts +++ b/ui/src/components/ModalFormStyle.ts @@ -20,4 +20,4 @@ export const ActionContainer = styled.div` justify-content: space-between; margin: 10px 0; padding: 10px 0; -`; \ No newline at end of file +`; diff --git a/ui/src/components/NoRowsRenderer.tsx b/ui/src/components/NoRowsRenderer.tsx index 70c41e2748..90f48ce899 100644 --- a/ui/src/components/NoRowsRenderer.tsx +++ b/ui/src/components/NoRowsRenderer.tsx @@ -13,4 +13,4 @@ const NoRowsRenderer = ({ content }) => { return {content}; }; -export default NoRowsRenderer; \ No newline at end of file +export default NoRowsRenderer; diff --git a/ui/src/components/NodeListTable.tsx b/ui/src/components/NodeListTable.tsx index 6f94ce146f..40a1564f5a 100644 --- a/ui/src/components/NodeListTable.tsx +++ b/ui/src/components/NodeListTable.tsx @@ -1,11 +1,4 @@ -import { - ConstrainedText, - Icon, - Stack, - Text, - Wrap, - spacing, -} from '@scality/core-ui'; +import { ConstrainedText, Icon, Stack, Text, Wrap, spacing } from '@scality/core-ui'; import { Button, Table } from '@scality/core-ui/dist/next'; import React, { useCallback } from 'react'; import { useIntl } from 'react-intl'; @@ -61,11 +54,7 @@ const NodeListTable = ({ nodeTableData }) => { <> + {name} } @@ -132,10 +121,7 @@ const NodeListTable = ({ nodeTableData }) => { location.pathname.endsWith('partitions') || location.pathname.endsWith('details'); - const newPath = location.pathname.replace( - /\/nodes\/[^/]*\//, - `/nodes/${nodeName}/`, - ); + const newPath = location.pathname.replace(/\/nodes\/[^/]*\//, `/nodes/${nodeName}/`); if (isTabSelected) { navigate(`${newPath}?${query.toString()}`); } else { diff --git a/ui/src/components/NodePageOverviewTab.spec.tsx b/ui/src/components/NodePageOverviewTab.spec.tsx index 0afd0a5a15..fdafb254a9 100644 --- a/ui/src/components/NodePageOverviewTab.spec.tsx +++ b/ui/src/components/NodePageOverviewTab.spec.tsx @@ -43,13 +43,10 @@ const mockProps = { }; const server = setupServer( - rest.patch( - `http://localhost/api/kubernetes/api/v1/nodes/${mockProps.nodeName}`, - (req, res, ctx) => { - SUT(req.body); - return res(ctx.status(200), ctx.json({})); - }, - ), + rest.patch(`http://localhost/api/kubernetes/api/v1/nodes/${mockProps.nodeName}`, (req, res, ctx) => { + SUT(req.body); + return res(ctx.status(200), ctx.json({})); + }), ); describe('NodePageOverviewTab', () => { diff --git a/ui/src/components/NodePageOverviewTab.tsx b/ui/src/components/NodePageOverviewTab.tsx index 1c5db39971..0193c3f034 100644 --- a/ui/src/components/NodePageOverviewTab.tsx +++ b/ui/src/components/NodePageOverviewTab.tsx @@ -1,11 +1,4 @@ -import { - InlineInput, - Loader, - Stack, - Steppers, - spacing, - FormattedDateTime, -} from '@scality/core-ui'; +import { InlineInput, Loader, Stack, Steppers, spacing, FormattedDateTime } from '@scality/core-ui'; import React from 'react'; import { Button } from '@scality/core-ui/dist/next'; import { fontSize, fontWeight } from '@scality/core-ui/dist/style/theme'; @@ -15,14 +8,8 @@ import { useIntl } from 'react-intl'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components'; import { API_STATUS_UNKNOWN } from '../constants'; -import { - deployNodeAction, - fetchClusterVersionAction, -} from '../ducks/app/nodes'; -import { - useUpdateNodeDisplayName, - useShowNodeDisplayName, -} from '../hooks/nodes'; +import { deployNodeAction, fetchClusterVersionAction } from '../ducks/app/nodes'; +import { useUpdateNodeDisplayName, useShowNodeDisplayName } from '../hooks/nodes'; import ActiveAlertsCounter from './ActiveAlertsCounter'; import { ActiveAlertTitle, @@ -88,9 +75,7 @@ const NodePageOverviewTab = (props) => { }, [dispatch]); const jobs = useSelector((state) => // @ts-expect-error - FIXME when you are working on it - state.app.salt.jobs.filter( - (job) => job.type === 'deploy-node' && job.node === nodeName, - ), + state.app.salt.jobs.filter((job) => job.type === 'deploy-node' && job.node === nodeName), ); let activeJob = jobs.find((job) => !job.completed); @@ -159,19 +144,11 @@ const NodePageOverviewTab = (props) => { // in the Steppers component const activeStep = success ? steps.length : steps.length - 1; // The node object used by Node List Table - const currentNode = nodeTableData?.find( - (node) => node.name.name === nodeName, - ); + const currentNode = nodeTableData?.find((node) => node.name.name === nodeName); const currentNodeReturnByK8S = nodes?.find((node) => node.name === nodeName); - const creationTimestamp = currentNodeReturnByK8S - ? new Date(currentNodeReturnByK8S.creationTimestamp) - : ''; - const volumesAttachedCurrentNode = volumes?.filter( - (volume) => volume.spec.nodeName === nodeName, - ); - const podsScheduledOnCurrentNode = pods?.filter( - (pod) => pod.nodeName === nodeName, - ); + const creationTimestamp = currentNodeReturnByK8S ? new Date(currentNodeReturnByK8S.creationTimestamp) : ''; + const volumesAttachedCurrentNode = volumes?.filter((volume) => volume.spec.nodeName === nodeName); + const podsScheduledOnCurrentNode = pods?.filter((pod) => pod.nodeName === nodeName); const mutation = useUpdateNodeDisplayName(nodeName); @@ -181,8 +158,7 @@ const NodePageOverviewTab = (props) => {

- {currentNodeReturnByK8S?.status === API_STATUS_UNKNOWN && - !currentNodeReturnByK8S.internalIP ? ( + {currentNodeReturnByK8S?.status === API_STATUS_UNKNOWN && !currentNodeReturnByK8S.internalIP ? ( !currentNodeReturnByK8S?.deploying ? ( { Node ID - - {currentNode?.id} - + {currentNode?.id} {isDisplayNodeNameShown && ( - + Display Name )} Name - - {currentNode?.name?.name} - + {currentNode?.name?.name} - - Control Plane IP - + Control Plane IP - - {currentNode?.name?.controlPlaneIP} - + {currentNode?.name?.controlPlaneIP} - - Workload Plane IP - + Workload Plane IP - - {currentNode?.name?.workloadPlaneIP} - + {currentNode?.name?.workloadPlaneIP} Roles - - {currentNode?.roles} - + {currentNode?.roles} @@ -279,10 +236,7 @@ const NodePageOverviewTab = (props) => { {currentNode?.status?.computedStatus?.map((cond) => { return ( - + {intl.formatMessage({ id: `${cond}`, })} @@ -301,10 +255,7 @@ const NodePageOverviewTab = (props) => { {creationTimestamp ? ( - + ) : ( @@ -314,9 +265,7 @@ const NodePageOverviewTab = (props) => { K8s Version - - {currentNodeReturnByK8S?.kubeletVersion} - + {currentNodeReturnByK8S?.kubeletVersion} diff --git a/ui/src/components/NodePagePartitionTab.tsx b/ui/src/components/NodePagePartitionTab.tsx index f6bc1dfae3..487ec5c34a 100644 --- a/ui/src/components/NodePagePartitionTab.tsx +++ b/ui/src/components/NodePagePartitionTab.tsx @@ -21,12 +21,9 @@ const NodePagePartitionTab = (props: Record) => { const intl = useIntl(); // To redirect to the right Node(Detailed) dashboard in Grafana const api = useTypedSelector((state) => state.config.api); - const unameInfos = useTypedSelector( - (state) => state.app.monitoring.unameInfo, - ); + const unameInfos = useTypedSelector((state) => state.app.monitoring.unameInfo); const hostnameLabel = unameInfos.find( - (unameInfo) => - unameInfo?.metric?.instance === `${instanceIP}:${PORT_NODE_EXPORTER}`, + (unameInfo) => unameInfo?.metric?.instance === `${instanceIP}:${PORT_NODE_EXPORTER}`, )?.metric?.nodename; return ( diff --git a/ui/src/components/NodePagePodsTab.spec.tsx b/ui/src/components/NodePagePodsTab.spec.tsx index 097878150d..57451c2d9f 100644 --- a/ui/src/components/NodePagePodsTab.spec.tsx +++ b/ui/src/components/NodePagePodsTab.spec.tsx @@ -49,9 +49,7 @@ const CustomWrapper = ({ children }: { children?: React.ReactNode }) => { } > - - {children} - + {children} ); @@ -89,9 +87,7 @@ describe('NodePagePodsTab', () => { expect(selectors.podAge()).toBeInTheDocument(); expect(selectors.podNamespace()).toBeInTheDocument(); - const { color } = window.getComputedStyle( - selectors.podStatus('Running (3/3)'), - ); + const { color } = window.getComputedStyle(selectors.podStatus('Running (3/3)')); expect(color).toBe(statusHealthyRGB); }); @@ -106,9 +102,7 @@ describe('NodePagePodsTab', () => { expect(selectors.podAge()).toBeInTheDocument(); expect(selectors.podNamespace()).toBeInTheDocument(); - const { color } = window.getComputedStyle( - selectors.podStatus('Running (2/3)'), - ); + const { color } = window.getComputedStyle(selectors.podStatus('Running (2/3)')); expect(color).toBe(statusWarningRGB); }); diff --git a/ui/src/components/NodePagePodsTab.tsx b/ui/src/components/NodePagePodsTab.tsx index 0c79a98f85..8733d72eda 100644 --- a/ui/src/components/NodePagePodsTab.tsx +++ b/ui/src/components/NodePagePodsTab.tsx @@ -7,13 +7,7 @@ import { Table } from '@scality/core-ui/dist/next'; import { NodeTab } from './style/CommonLayoutStyle'; import { TooltipContent } from './TableRow'; import { fromMilliSectoAge } from '../services/utils'; -import { - STATUS_RUNNING, - STATUS_PENDING, - STATUS_FAILED, - STATUS_UNKNOWN, - GRAFANA_DASHBOARDS, -} from '../constants'; +import { STATUS_RUNNING, STATUS_PENDING, STATUS_FAILED, STATUS_UNKNOWN, GRAFANA_DASHBOARDS } from '../constants'; import { useIntl } from 'react-intl'; const PodTableContainer = styled.div` color: ${(props) => props.theme.textPrimary}; @@ -34,10 +28,7 @@ const StatusText = styled.div<{ status; numContainer?; numContainerRunning? }>` if (status === STATUS_RUNNING && numContainer === numContainerRunning) { return props.theme.statusHealthy; - } else if ( - status === STATUS_RUNNING && - numContainer !== numContainerRunning - ) { + } else if (status === STATUS_RUNNING && numContainer !== numContainerRunning) { return props.theme.statusWarning; } else if (status === STATUS_RUNNING || status === STATUS_PENDING) { return props.theme.statusWarning; @@ -83,20 +74,14 @@ const NodePagePodsTab = React.memo((props) => { const { values: { status: statusB }, } = rowb; - const valueA = - statusA.status + statusA.numContainer + statusA.numContainerRunning; - const valueB = - statusB.status + statusB.numContainer + statusB.numContainerRunning; + const valueA = statusA.status + statusA.numContainer + statusA.numContainerRunning; + const valueB = statusB.status + statusB.numContainer + statusB.numContainerRunning; return valueA.localeCompare(valueB); }, Cell: (cellProps) => { const { status, numContainer, numContainerRunning } = cellProps.value; return status === STATUS_RUNNING ? ( - + {`${status} (${numContainerRunning}/${numContainer})`} ) : ( @@ -174,10 +159,7 @@ const NodePagePodsTab = React.memo((props) => { }, }} > - +
); diff --git a/ui/src/components/NodePageVolumesTab.tsx b/ui/src/components/NodePageVolumesTab.tsx index c0bc13315a..2586d90122 100644 --- a/ui/src/components/NodePageVolumesTab.tsx +++ b/ui/src/components/NodePageVolumesTab.tsx @@ -23,14 +23,8 @@ const NodePageVolumesTab = (props) => { const dispatch = useDispatch(); const volumeListData = useVolumesWithAlerts(nodeName); useRefreshEffect(refreshVolumesAction, stopRefreshVolumesAction); - useRefreshEffect( - refreshCurrentVolumeStatsAction, - stopRefreshCurrentVolumeStatsAction, - ); - useRefreshEffect( - refreshPersistentVolumesAction, - stopRefreshPersistentVolumesAction, - ); + useRefreshEffect(refreshCurrentVolumeStatsAction, stopRefreshCurrentVolumeStatsAction); + useRefreshEffect(refreshPersistentVolumesAction, stopRefreshPersistentVolumesAction); useEffect(() => { // @ts-expect-error - FIXME when you are working on it dispatch(fetchVolumeStatsAction()); diff --git a/ui/src/components/NodePageVolumesTable.tsx b/ui/src/components/NodePageVolumesTable.tsx index c316efd5ec..5d9817ed57 100644 --- a/ui/src/components/NodePageVolumesTable.tsx +++ b/ui/src/components/NodePageVolumesTable.tsx @@ -1,22 +1,10 @@ -import { - ConstrainedText, - Icon, - Link, - ProgressBar, - Tooltip, - Wrap, - spacing, -} from '@scality/core-ui'; +import { ConstrainedText, Icon, Link, ProgressBar, Tooltip, Wrap, spacing } from '@scality/core-ui'; import { Button, Table } from '@scality/core-ui/dist/next'; import isEqual from 'lodash.isequal'; import React from 'react'; import { useIntl } from 'react-intl'; import { useTheme } from 'styled-components'; -import { - VOLUME_CONDITION_EXCLAMATION, - VOLUME_CONDITION_LINK, - VOLUME_CONDITION_UNLINK, -} from '../constants'; +import { VOLUME_CONDITION_EXCLAMATION, VOLUME_CONDITION_LINK, VOLUME_CONDITION_UNLINK } from '../constants'; import { formatSizeForDisplay } from '../services/utils'; import CircleStatus from './CircleStatus'; import { Latency } from './Latency'; @@ -128,18 +116,14 @@ const VolumeListTable = React.memo((props) => { flex: 0.5, }, Cell: (cellProps) => { - const volume = volumeListData?.find( - (vol) => vol.name === cellProps.cell.row.values.name, - ); + const volume = volumeListData?.find((vol) => vol.name === cellProps.cell.row.values.name); switch (cellProps.value) { case 'exclamation': return ( {volume?.errorReason} - } + overlay={{volume?.errorReason}} > @@ -200,9 +184,7 @@ const VolumeListTable = React.memo((props) => { minWidth: '3rem', }, Cell: (cellProps) => { - return cellProps.value !== undefined ? ( - - ) : null; + return cellProps.value !== undefined ? : null; }, }, ]; // eslint-disable-next-line react-hooks/exhaustive-deps @@ -238,10 +220,7 @@ const VolumeListTable = React.memo((props) => { data-cy="create_volume_button" /> - + ); }, isEqual); diff --git a/ui/src/components/NodePartitionTable.test.tsx b/ui/src/components/NodePartitionTable.test.tsx index 332574aff3..a3667d23f7 100644 --- a/ui/src/components/NodePartitionTable.test.tsx +++ b/ui/src/components/NodePartitionTable.test.tsx @@ -10,266 +10,257 @@ import { mockOffsetSize } from '../tests/mocks/util'; import { useAlerts } from '../containers/AlertProvider'; const server = setupServer( - rest.get( - `http://${FAKE_CONTROL_PLANE_IP}:8443/api/prometheus/api/v1/query_range`, - (req, res, ctx) => { - const result = { - status: 'success', - data: { - resultType: 'matrix', - result: [ - { - values: [], + rest.get(`http://${FAKE_CONTROL_PLANE_IP}:8443/api/prometheus/api/v1/query_range`, (req, res, ctx) => { + const result = { + status: 'success', + data: { + resultType: 'matrix', + result: [ + { + values: [], + }, + ], + }, + }; + // return success status + return res(ctx.json(result)); + }), + rest.get(`http://${FAKE_CONTROL_PLANE_IP}:8443/api/prometheus/api/v1/query`, (req, res, ctx) => { + const result = { + status: 'success', + data: { + resultType: 'vector', + result: [ + { + metric: { + container: 'node-exporter', + device: '/dev/vdc', + endpoint: 'metrics', + fstype: 'xfs', + instance: '192.168.1.29:9100', + job: 'node-exporter', + mountpoint: '/mnt/testpart', + namespace: 'metalk8s-monitoring', + pod: 'prometheus-operator-prometheus-node-exporter-wk86s', + service: 'prometheus-operator-prometheus-node-exporter', }, - ], - }, - }; - // return success status - return res(ctx.json(result)); - }, - ), - rest.get( - `http://${FAKE_CONTROL_PLANE_IP}:8443/api/prometheus/api/v1/query`, - (req, res, ctx) => { - const result = { - status: 'success', - data: { - resultType: 'vector', - result: [ - { - metric: { - container: 'node-exporter', - device: '/dev/vdc', - endpoint: 'metrics', - fstype: 'xfs', - instance: '192.168.1.29:9100', - job: 'node-exporter', - mountpoint: '/mnt/testpart', - namespace: 'metalk8s-monitoring', - pod: 'prometheus-operator-prometheus-node-exporter-wk86s', - service: 'prometheus-operator-prometheus-node-exporter', - }, - value: [1611905929.203, '96.86575443786982'], + value: [1611905929.203, '96.86575443786982'], + }, + ], + }, + }; + // return success status + return res(ctx.json(result)); + }), + rest.get(`http://${FAKE_CONTROL_PLANE_IP}:8443/api/loki/loki/api/v1/query_range`, (req, res, ctx) => { + const result = { + status: 'success', + data: { + resultType: 'streams', + result: [ + { + stream: { + pod: 'metalk8s-alert-logger-b67bf87bc-kdwkz', + stream: 'stderr', + app: 'metalk8s-alert-logger', + container: 'metalk8s-alert-logger', + job: 'fluent-bit', + namespace: 'metalk8s-monitoring', + node: 'mf-210-dev-10.novalocal', }, - ], - }, - }; - // return success status - return res(ctx.json(result)); - }, - ), - rest.get( - `http://${FAKE_CONTROL_PLANE_IP}:8443/api/loki/loki/api/v1/query_range`, - (req, res, ctx) => { - const result = { - status: 'success', - data: { - resultType: 'streams', - result: [ - { - stream: { - pod: 'metalk8s-alert-logger-b67bf87bc-kdwkz', - stream: 'stderr', - app: 'metalk8s-alert-logger', - container: 'metalk8s-alert-logger', - job: 'fluent-bit', - namespace: 'metalk8s-monitoring', - node: 'mf-210-dev-10.novalocal', - }, - values: [ - [ - '1629707875531297840', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-23T08:37:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', - ], - [ - '1629707875531247885', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-23T08:37:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', - ], - [ - '1629707305530586315', - '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-23T08:26:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', - ], - [ - '1629580226958515632', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', - ], - [ - '1629580226953237917', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', - ], - [ - '1629579656791809397', - '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', - ], - [ - '1629537026778010423', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', - ], - [ - '1629537026777933801', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', - ], - [ - '1629536456645081557', - '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', - ], - [ - '1629493826618100128', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', - ], - [ - '1629493826617324680', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', - ], - [ - '1629493256512899899', - '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', - ], - [ - '1629450626478361524', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', - ], - [ - '1629450626477841630', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', - ], - [ - '1629450056375677744', - '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', - ], - [ - '1629407426337176558', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', - ], - [ - '1629407426337118392', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', - ], - [ - '1629406856255835472', - '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', - ], - [ - '1629364226207205213', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', - ], - [ - '1629364226207153342', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', - ], - [ - '1629363656142721059', - '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', - ], - [ - '1629321026093608878', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', - ], - [ - '1629321026092823411', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', - ], - [ - '1629320456041614491', - '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', - ], - [ - '1629277825968714769', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', - ], - [ - '1629277825967805017', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', - ], - [ - '1629277255925034096', - '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', - ], - [ - '1629234625848652913', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', - ], - [ - '1629234625848057590', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', - ], - [ - '1629234055826279655', - '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', - ], - [ - '1629191425734623751', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', - ], - [ - '1629191425734556286', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', - ], - [ - '1629190855718934272', - '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', - ], - [ - '1629148225637370582', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', - ], - [ - '1629148225631328388', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', - ], - [ - '1629147655622974778', - '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', - ], - [ - '1629105025529967337', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', - ], - [ - '1629105025529492733', - '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', - ], + values: [ + [ + '1629707875531297840', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-23T08:37:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', ], - }, - ], - stats: { - summary: { - bytesProcessedPerSecond: 19975140, - linesProcessedPerSecond: 21082, - totalBytesProcessed: 70114, - totalLinesProcessed: 74, - execTime: 0.003510063, - }, - store: { - totalChunksRef: 26, - totalChunksDownloaded: 26, - chunksDownloadTime: 0.00116932, - headChunkBytes: 0, - headChunkLines: 0, - decompressedBytes: 70114, - decompressedLines: 74, - compressedBytes: 16492, - totalDuplicates: 35, - }, - ingester: { - totalReached: 1, - totalChunksMatched: 0, - totalBatches: 0, - totalLinesSent: 0, - headChunkBytes: 0, - headChunkLines: 0, - decompressedBytes: 0, - decompressedLines: 0, - compressedBytes: 0, - totalDuplicates: 0, - }, + [ + '1629707875531247885', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-23T08:37:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', + ], + [ + '1629707305530586315', + '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-23T08:26:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', + ], + [ + '1629580226958515632', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', + ], + [ + '1629580226953237917', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', + ], + [ + '1629579656791809397', + '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', + ], + [ + '1629537026778010423', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', + ], + [ + '1629537026777933801', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', + ], + [ + '1629536456645081557', + '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', + ], + [ + '1629493826618100128', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', + ], + [ + '1629493826617324680', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', + ], + [ + '1629493256512899899', + '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', + ], + [ + '1629450626478361524', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', + ], + [ + '1629450626477841630', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', + ], + [ + '1629450056375677744', + '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', + ], + [ + '1629407426337176558', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', + ], + [ + '1629407426337118392', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', + ], + [ + '1629406856255835472', + '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', + ], + [ + '1629364226207205213', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', + ], + [ + '1629364226207153342', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', + ], + [ + '1629363656142721059', + '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', + ], + [ + '1629321026093608878', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', + ], + [ + '1629321026092823411', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', + ], + [ + '1629320456041614491', + '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', + ], + [ + '1629277825968714769', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', + ], + [ + '1629277825967805017', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', + ], + [ + '1629277255925034096', + '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', + ], + [ + '1629234625848652913', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', + ], + [ + '1629234625848057590', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', + ], + [ + '1629234055826279655', + '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', + ], + [ + '1629191425734623751', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', + ], + [ + '1629191425734556286', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', + ], + [ + '1629190855718934272', + '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', + ], + [ + '1629148225637370582', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', + ], + [ + '1629148225631328388', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', + ], + [ + '1629147655622974778', + '{"status":"firing","labels":{"alertname":"Watchdog","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","severity":"none"},"annotations":{"description":"This is an alert meant to ensure that the entire alerting pipeline is functional.\\nThis alert is always firing, therefore it should always be firing in Alertmanager\\nand always fire against a receiver. There are integrations with various notification\\nmechanisms that send a notification when this alert is not firing. For example the\\n\\"DeadMansSnitch\\" integration in PagerDuty.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-watchdog","summary":"An alert that should always be firing to certify that Alertmanager is working properly."},"startsAt":"2021-08-16T08:59:25.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=vector%281%29\\u0026g0.tab=1","fingerprint":"fc30b79dbdb0a043"}', + ], + [ + '1629105025529967337', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"node-exporter","namespace":"metalk8s-monitoring","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-prometheus-node-exporter","severity":"warning"},"annotations":{"description":"50% of the node-exporter/prometheus-operator-prometheus-node-exporter targets in metalk8s-monitoring namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"f0b37a44b73d5b4d"}', + ], + [ + '1629105025529492733', + '{"status":"firing","labels":{"alertname":"TargetDown","job":"kube-proxy","namespace":"kube-system","prometheus":"metalk8s-monitoring/prometheus-operator-prometheus","service":"prometheus-operator-kube-proxy","severity":"warning"},"annotations":{"description":"50% of the kube-proxy/prometheus-operator-kube-proxy targets in kube-system namespace are down.","runbook_url":"https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-targetdown","summary":"One or more targets are unreachable."},"startsAt":"2021-08-16T09:09:55.52Z","endsAt":"0001-01-01T00:00:00Z","generatorURL":"http://prometheus-operator-prometheus.metalk8s-monitoring:9090/graph?g0.expr=100+%2A+%28count+by%28job%2C+namespace%2C+service%29+%28up+%3D%3D+0%29+%2F+count+by%28job%2C+namespace%2C+service%29+%28up%29%29+%3E+10\\u0026g0.tab=1","fingerprint":"bfc9d3bf855f292b"}', + ], + ], + }, + ], + stats: { + summary: { + bytesProcessedPerSecond: 19975140, + linesProcessedPerSecond: 21082, + totalBytesProcessed: 70114, + totalLinesProcessed: 74, + execTime: 0.003510063, + }, + store: { + totalChunksRef: 26, + totalChunksDownloaded: 26, + chunksDownloadTime: 0.00116932, + headChunkBytes: 0, + headChunkLines: 0, + decompressedBytes: 70114, + decompressedLines: 74, + compressedBytes: 16492, + totalDuplicates: 35, + }, + ingester: { + totalReached: 1, + totalChunksMatched: 0, + totalBatches: 0, + totalLinesSent: 0, + headChunkBytes: 0, + headChunkLines: 0, + decompressedBytes: 0, + decompressedLines: 0, + compressedBytes: 0, + totalDuplicates: 0, }, }, - }; - // return success status - return res(ctx.json(result)); - }, - ), + }, + }; + // return success status + return res(ctx.json(result)); + }), ); describe('the system partition table', () => { beforeAll(() => { @@ -285,8 +276,7 @@ describe('the system partition table', () => { const alerts = [ { annotations: { - description: - 'Filesystem on /dev/vdc at 192.168.1.29:9100 has only 3.13% available space left.', + description: 'Filesystem on /dev/vdc at 192.168.1.29:9100 has only 3.13% available space left.', runbook_url: 'https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-nodefilesystemalmostoutofspace', summary: 'Filesystem has less than 5% space left.', @@ -297,9 +287,7 @@ describe('the system partition table', () => { Since we can't spy on the `activeOn` in getHealthStatus(). If we use ```endsAt: new Date().toISOString()```, there will be a slightly difference between the two current times. Hence, here we add one day to make sure the alert is active. */ - endsAt: new Date( - new Date().getTime() + 1000 * 60 * 60 * 24, - ).toISOString(), + endsAt: new Date(new Date().getTime() + 1000 * 60 * 60 * 24).toISOString(), fingerprint: '37b2591ac3cdb320', receivers: [ { @@ -341,17 +329,11 @@ describe('the system partition table', () => { initializeAM(`http://${FAKE_CONTROL_PLANE_IP}:8443/api/alertmanager`); initializeLoki(`http://${FAKE_CONTROL_PLANE_IP}:8443/api/loki`); render(); - expect( - screen.getByText(/Loading system partitions.../i), - ).toBeInTheDocument(); + expect(screen.getByText(/Loading system partitions.../i)).toBeInTheDocument(); // E - await waitForElementToBeRemoved(() => - screen.getByText(/Loading system partitions.../i), - ); + await waitForElementToBeRemoved(() => screen.getByText(/Loading system partitions.../i)); // Verify - expect( - screen.getByLabelText('Exclamation-circle status warning'), - ).toBeInTheDocument(); + expect(screen.getByLabelText('Exclamation-circle status warning')).toBeInTheDocument(); expect(screen.getByLabelText('97%')).toBeInTheDocument(); expect(screen.getByText('/mnt/testpart')).toBeInTheDocument(); // since we use the same query, so the number of global size is the same as usage @@ -365,26 +347,17 @@ describe('the system partition table', () => { initializeLoki(`http://${FAKE_CONTROL_PLANE_IP}:8443/api/loki`); // override the default route with error status server.use( - rest.get( - `http://${FAKE_CONTROL_PLANE_IP}:8443/api/prometheus/api/v1/query`, - (req, res, ctx) => { - return res(ctx.status(500)); - }, - ), + rest.get(`http://${FAKE_CONTROL_PLANE_IP}:8443/api/prometheus/api/v1/query`, (req, res, ctx) => { + return res(ctx.status(500)); + }), ); render(); - expect( - screen.getByText(/Loading system partitions.../i), - ).toBeInTheDocument(); + expect(screen.getByText(/Loading system partitions.../i)).toBeInTheDocument(); // E - await waitForElementToBeRemoved(() => - screen.getByText(/Loading system partitions.../i), - ); + await waitForElementToBeRemoved(() => screen.getByText(/Loading system partitions.../i)); // V expect( - screen.getByText( - 'An error occurred while loading the system partitions, please refresh the page.', - ), + screen.getByText('An error occurred while loading the system partitions, please refresh the page.'), ).toBeInTheDocument(); }); afterAll(() => { diff --git a/ui/src/components/NodePartitionTable.tsx b/ui/src/components/NodePartitionTable.tsx index 68c0e158f6..8fafa48f6b 100644 --- a/ui/src/components/NodePartitionTable.tsx +++ b/ui/src/components/NodePartitionTable.tsx @@ -14,10 +14,7 @@ import { } from '../constants'; import { useAlerts } from '../containers/AlertProvider'; import { getNodePartitionsTableData } from '../services/NodeVolumesUtils'; -import { - queryNodeFSSize, - queryNodeFSUsage, -} from '../services/prometheus/fetchMetrics'; +import { queryNodeFSSize, queryNodeFSUsage } from '../services/prometheus/fetchMetrics'; import CircleStatus from './CircleStatus'; const NodePartitionTable = ({ instanceIP }: { instanceIP: string }) => { @@ -93,32 +90,27 @@ const NodePartitionTable = ({ instanceIP }: { instanceIP: string }) => { ['nodeDevices', instanceIP], useCallback( () => - Promise.all([ - queryNodeFSUsage(instanceIP), - queryNodeFSSize(instanceIP), - ]).then(([nodeFSUsageResult, nodeFSSizeResult]) => { - if ( - nodeFSUsageResult.status === 'success' && - nodeFSSizeResult.status === 'success' && - nodeFSUsageResult.data.resultType === 'vector' && - nodeFSSizeResult.data.resultType === 'vector' - ) { - return { - nodeFSUsage: nodeFSUsageResult.data.result, - nodeFSSize: nodeFSSizeResult.data.result, - }; - } - }), + Promise.all([queryNodeFSUsage(instanceIP), queryNodeFSSize(instanceIP)]).then( + ([nodeFSUsageResult, nodeFSSizeResult]) => { + if ( + nodeFSUsageResult.status === 'success' && + nodeFSSizeResult.status === 'success' && + nodeFSUsageResult.data.resultType === 'vector' && + nodeFSSizeResult.data.resultType === 'vector' + ) { + return { + nodeFSUsage: nodeFSUsageResult.data.result, + nodeFSSize: nodeFSSizeResult.data.result, + }; + } + }, + ), [instanceIP], ), ); let partitions = []; if (status === 'success') - partitions = getNodePartitionsTableData( - nodeFSResult.nodeFSUsage, - nodeFSResult.nodeFSSize, - alertNF, - ); + partitions = getNodePartitionsTableData(nodeFSResult.nodeFSUsage, nodeFSResult.nodeFSSize, alertNF); return ( { }, }} > - +
); }; diff --git a/ui/src/components/NonSymmetricalQuantileChart.tsx b/ui/src/components/NonSymmetricalQuantileChart.tsx index a2f8df004c..8ba147392d 100644 --- a/ui/src/components/NonSymmetricalQuantileChart.tsx +++ b/ui/src/components/NonSymmetricalQuantileChart.tsx @@ -1,17 +1,9 @@ import { ChartLegendWrapper } from '@scality/core-ui/dist/next'; -import { - ChartLegend, - LineTimeSerieChart, - useMetricsTimeSpan, -} from '@scality/core-ui/dist/next'; +import { ChartLegend, LineTimeSerieChart, useMetricsTimeSpan } from '@scality/core-ui/dist/next'; import { useCallback, useMemo } from 'react'; import { UseQueryOptions } from 'react-query'; import { useSelector } from 'react-redux'; -import { - DASHBOARD_QUANTILE_SYNC_ID, - HEIGHT_DEFAULT_CHART, - PORT_NODE_EXPORTER, -} from '../constants'; +import { DASHBOARD_QUANTILE_SYNC_ID, HEIGHT_DEFAULT_CHART, PORT_NODE_EXPORTER } from '../constants'; import { useChartSeries, useNodeAddressesSelector, useNodes } from '../hooks'; import { convertPrometheusResultToSerie, @@ -78,11 +70,7 @@ const NonSymmetricalQuantileChart = ({ getQuantileQuery(timeSpanProps, 0.05), ], transformPrometheusDataToSeries: useCallback( - ([ - prometheusResultQuantile5, - prometheusResultMedian, - prometheusResultQuantile90, - ]) => { + ([prometheusResultQuantile5, prometheusResultMedian, prometheusResultQuantile90]) => { return [ convertPrometheusResultToSerie(prometheusResultQuantile90, 'Q90'), convertPrometheusResultToSerie(prometheusResultMedian, 'Median'), @@ -104,9 +92,7 @@ const NonSymmetricalQuantileChart = ({ const allValues = seriesQuantile.flatMap((serie: any) => serie.data - .map(([_, value]: [number, any]) => - typeof value === 'string' ? parseFloat(value) : value, - ) + .map(([_, value]: [number, any]) => (typeof value === 'string' ? parseFloat(value) : value)) .filter((v: any) => v !== null && !isNaN(v)), ); @@ -140,14 +126,7 @@ const NonSymmetricalQuantileChart = ({ /> ); }, - [ - getQuantileHoverQuery, - nodeMapPerIp, - devices, - valueBase, - unitLabel, - timeFormat, - ], + [getQuantileHoverQuery, nodeMapPerIp, devices, valueBase, unitLabel, timeFormat], ); const colorSet = useMemo(() => { diff --git a/ui/src/components/QuantileTooltip.tsx b/ui/src/components/QuantileTooltip.tsx index 7fe3aa0c63..a876114f45 100644 --- a/ui/src/components/QuantileTooltip.tsx +++ b/ui/src/components/QuantileTooltip.tsx @@ -1,11 +1,7 @@ import React, { useMemo } from 'react'; import { useQuery } from 'react-query'; import type { TooltipContentProps } from 'recharts'; -import { - QuantileTooltipRenderer, - transformRegularPayload, - sortPayloadEntries, -} from './shared/QuantileTooltipShared'; +import { QuantileTooltipRenderer, transformRegularPayload, sortPayloadEntries } from './shared/QuantileTooltipShared'; type QuantileTooltipProps = { tooltipProps: TooltipContentProps; @@ -46,10 +42,7 @@ export const QuantileTooltip: React.FC = ({ // Determine if additional fetching is needed const isOnHoverFetchingNeeded = useMemo(() => { if (!quantileData) return false; - return ( - quantileData.median !== quantileData.q90 || - quantileData.median !== quantileData.q5 - ); + return quantileData.median !== quantileData.q90 || quantileData.median !== quantileData.q5; }, [quantileData]); // Fetch quantile hover data @@ -67,13 +60,7 @@ export const QuantileTooltip: React.FC = ({ ); const quantile5Result = useQuery( - getQuantileHoverQuery( - quantileData?.timestamp?.toString(), - quantileData?.q5, - '<', - isOnHoverFetchingNeeded, - devices, - ), + getQuantileHoverQuery(quantileData?.timestamp?.toString(), quantileData?.q5, '<', isOnHoverFetchingNeeded, devices), { enabled: !!quantileData && isOnHoverFetchingNeeded && !!quantileData.q5, }, @@ -89,12 +76,7 @@ export const QuantileTooltip: React.FC = ({ // Add quantile results to payload entries const enrichedPayload = sortedPayload.map((entry) => ({ ...entry, - quantileResult: - entry.name === 'Q90' - ? quantile90Result - : entry.name === 'Q5' - ? quantile5Result - : null, + quantileResult: entry.name === 'Q90' ? quantile90Result : entry.name === 'Q5' ? quantile5Result : null, })); return ( diff --git a/ui/src/components/StatusIcon.tsx b/ui/src/components/StatusIcon.tsx index 3588ba5031..8afe5db05e 100644 --- a/ui/src/components/StatusIcon.tsx +++ b/ui/src/components/StatusIcon.tsx @@ -1,11 +1,5 @@ import { Icon } from '@scality/core-ui/dist/components/icon/Icon.component'; -import { - STATUS_WARNING, - STATUS_CRITICAL, - STATUS_SUCCESS, - STATUS_NONE, - STATUS_HEALTH, -} from '../constants'; +import { STATUS_WARNING, STATUS_CRITICAL, STATUS_SUCCESS, STATUS_NONE, STATUS_HEALTH } from '../constants'; const StatusIcon = ({ name, status }) => { const color = (() => { @@ -33,4 +27,4 @@ const StatusIcon = ({ name, status }) => { return ; }; -export default StatusIcon; \ No newline at end of file +export default StatusIcon; diff --git a/ui/src/components/SymmetricalQuantileChart.tsx b/ui/src/components/SymmetricalQuantileChart.tsx index eac578255b..b6a23e090a 100644 --- a/ui/src/components/SymmetricalQuantileChart.tsx +++ b/ui/src/components/SymmetricalQuantileChart.tsx @@ -1,21 +1,9 @@ import { ChartLegendWrapper } from '@scality/core-ui/dist/next'; -import { - ChartLegend, - LineTimeSerieChart, - useMetricsTimeSpan, -} from '@scality/core-ui/dist/next'; +import { ChartLegend, LineTimeSerieChart, useMetricsTimeSpan } from '@scality/core-ui/dist/next'; import { useCallback, useMemo } from 'react'; import { useSelector } from 'react-redux'; -import { - DASHBOARD_QUANTILE_SYNC_ID, - HEIGHT_SYMMETRICAL_CHART, - PORT_NODE_EXPORTER, -} from '../constants'; -import { - useNodeAddressesSelector, - useNodes, - useSymetricalChartSeries, -} from '../hooks'; +import { DASHBOARD_QUANTILE_SYNC_ID, HEIGHT_SYMMETRICAL_CHART, PORT_NODE_EXPORTER } from '../constants'; +import { useNodeAddressesSelector, useNodes, useSymetricalChartSeries } from '../hooks'; import { createSymmetricalQuantileColorSet, getNodesInterfacesString, @@ -131,15 +119,10 @@ const SymmetricalQuantileChart = ({ return { valueBase: 1, unitLabel: '' }; } - const allSeries = [ - ...(seriesQuantile.above || []), - ...(seriesQuantile.below || []), - ]; + const allSeries = [...(seriesQuantile.above || []), ...(seriesQuantile.below || [])]; const allValues = allSeries.flatMap((serie: any) => serie.data - .map(([_, value]: [number, any]) => - typeof value === 'string' ? parseFloat(value) : Math.abs(value), - ) + .map(([_, value]: [number, any]) => (typeof value === 'string' ? parseFloat(value) : Math.abs(value))) .filter((v: any) => v !== null && !isNaN(v)), ); @@ -155,10 +138,7 @@ const SymmetricalQuantileChart = ({ }, [seriesQuantile]); const colorSet = useMemo(() => { - return createSymmetricalQuantileColorSet( - seriesQuantile.above || [], - seriesQuantile.below || [], - ); + return createSymmetricalQuantileColorSet(seriesQuantile.above || [], seriesQuantile.below || []); }, [seriesQuantile]); const timeFormat = useMemo(() => { diff --git a/ui/src/components/SymmetricalQuantileTooltip.tsx b/ui/src/components/SymmetricalQuantileTooltip.tsx index a8311c6b7f..bdce5d7d01 100644 --- a/ui/src/components/SymmetricalQuantileTooltip.tsx +++ b/ui/src/components/SymmetricalQuantileTooltip.tsx @@ -35,9 +35,7 @@ type SymmetricalQuantileTooltipProps = { devices?: string | string[]; }; -export const SymmetricalQuantileTooltip: React.FC< - SymmetricalQuantileTooltipProps -> = ({ +export const SymmetricalQuantileTooltip: React.FC = ({ tooltipProps, nodeMapPerIp, devices, @@ -54,12 +52,7 @@ export const SymmetricalQuantileTooltip: React.FC< // Extract quantile data for symmetrical chart const quantileData = useMemo(() => { if (!payload || !payload.length) return null; - return transformSymmetricalPayload( - payload, - label, - metricPrefixAbove, - metricPrefixBelow, - ); + return transformSymmetricalPayload(payload, label, metricPrefixAbove, metricPrefixBelow); }, [payload, label, metricPrefixAbove, metricPrefixBelow]); // Determine if additional fetching is needed @@ -83,11 +76,7 @@ export const SymmetricalQuantileTooltip: React.FC< devices, ), { - enabled: - !!quantileData && - isOnHoverFetchingNeeded && - !!getAboveQuantileHoverQuery && - !!quantileData.q90.above, + enabled: !!quantileData && isOnHoverFetchingNeeded && !!getAboveQuantileHoverQuery && !!quantileData.q90.above, }, ); @@ -100,11 +89,7 @@ export const SymmetricalQuantileTooltip: React.FC< devices, ), { - enabled: - !!quantileData && - isOnHoverFetchingNeeded && - !!getAboveQuantileHoverQuery && - !!quantileData.q5.above, + enabled: !!quantileData && isOnHoverFetchingNeeded && !!getAboveQuantileHoverQuery && !!quantileData.q5.above, }, ); @@ -118,11 +103,7 @@ export const SymmetricalQuantileTooltip: React.FC< devices, ), { - enabled: - !!quantileData && - isOnHoverFetchingNeeded && - !!getBelowQuantileHoverQuery && - !!quantileData.q90.below, + enabled: !!quantileData && isOnHoverFetchingNeeded && !!getBelowQuantileHoverQuery && !!quantileData.q90.below, }, ); @@ -135,11 +116,7 @@ export const SymmetricalQuantileTooltip: React.FC< devices, ), { - enabled: - !!quantileData && - isOnHoverFetchingNeeded && - !!getBelowQuantileHoverQuery && - !!quantileData.q5.below, + enabled: !!quantileData && isOnHoverFetchingNeeded && !!getBelowQuantileHoverQuery && !!quantileData.q5.below, }, ); diff --git a/ui/src/components/TableBasedPageStyle.ts b/ui/src/components/TableBasedPageStyle.ts index 7ddd862572..d9fba3f9d2 100644 --- a/ui/src/components/TableBasedPageStyle.ts +++ b/ui/src/components/TableBasedPageStyle.ts @@ -7,4 +7,4 @@ const TableBasedPageStyle = styled.div` height: 100%; padding: ${padding.small}; `; -export default TableBasedPageStyle; \ No newline at end of file +export default TableBasedPageStyle; diff --git a/ui/src/components/TableRow.tsx b/ui/src/components/TableRow.tsx index f98ce221d3..954e302d54 100644 --- a/ui/src/components/TableRow.tsx +++ b/ui/src/components/TableRow.tsx @@ -18,9 +18,7 @@ const TableRowStyle = styled.div` border-right: 4px solid ${(props) => // @ts-expect-error - FIXME when you are working on it - props.isSelected - ? props.theme.selectedActive - : props.theme.backgroundLevel2}; + props.isSelected ? props.theme.selectedActive : props.theme.backgroundLevel2}; background-color: ${(props) => // @ts-expect-error - FIXME when you are working on it diff --git a/ui/src/components/VolumeCharts.tsx b/ui/src/components/VolumeCharts.tsx index 29caec0acf..dde66f93f4 100644 --- a/ui/src/components/VolumeCharts.tsx +++ b/ui/src/components/VolumeCharts.tsx @@ -1,8 +1,4 @@ -import { - LineTimeSerieChart, - useMetricsTimeSpan, - useChartId, -} from '@scality/core-ui/dist/next'; +import { LineTimeSerieChart, useMetricsTimeSpan, useChartId } from '@scality/core-ui/dist/next'; import { useCallback } from 'react'; import { HEIGHT_DEFAULT_CHART, @@ -12,10 +8,7 @@ import { YAXIS_TITLE_READ_WRITE, } from '../constants'; import { useSingleChartSerie, useSymetricalChartSeries } from '../hooks'; -import { - convertPrometheusResultToSerieWithAverage, - getSeriesForSymmetricalChart, -} from '../services/graphUtils'; +import { convertPrometheusResultToSerieWithAverage, getSeriesForSymmetricalChart } from '../services/graphUtils'; import type { TimeSpanProps } from '../services/platformlibrary/metrics'; import { getVolumeIOPSReadQuery, @@ -146,12 +139,8 @@ export const VolumeIOPSChart = ({ const chartId = useChartId(); const { interval, duration } = useMetricsTimeSpan(); const { series, startingTimeStamp, isLoading } = useSymetricalChartSeries({ - getAboveQueries: (timeSpanProps: TimeSpanProps) => [ - getVolumeIOPSWriteQuery(instanceIp, deviceName, timeSpanProps), - ], - getBelowQueries: (timeSpanProps: TimeSpanProps) => [ - getVolumeIOPSReadQuery(instanceIp, deviceName, timeSpanProps), - ], + getAboveQueries: (timeSpanProps: TimeSpanProps) => [getVolumeIOPSWriteQuery(instanceIp, deviceName, timeSpanProps)], + getBelowQueries: (timeSpanProps: TimeSpanProps) => [getVolumeIOPSReadQuery(instanceIp, deviceName, timeSpanProps)], transformPrometheusDataToSeries: useCallback( ([prometheusResultAbove], [prometheusResultBelow]) => { const allSeries = getSeriesForSymmetricalChart( @@ -197,11 +186,9 @@ export const VolumeUsageChart = ({ const chartId = useChartId(); const { interval, duration } = useMetricsTimeSpan(); const { series, startingTimeStamp, isLoading } = useSingleChartSerie({ - getQuery: (timeSpanProps: TimeSpanProps) => - getVolumeUsageQuery(pvcName, namespace, timeSpanProps), + getQuery: (timeSpanProps: TimeSpanProps) => getVolumeUsageQuery(pvcName, namespace, timeSpanProps), transformPrometheusDataToSeries: useCallback( - (prometheusResult) => - convertPrometheusResultToSerieWithAverage(prometheusResult, volumeName), + (prometheusResult) => convertPrometheusResultToSerieWithAverage(prometheusResult, volumeName), [volumeName], ), }); diff --git a/ui/src/components/VolumeListTable.tsx b/ui/src/components/VolumeListTable.tsx index 000723af84..2182279349 100644 --- a/ui/src/components/VolumeListTable.tsx +++ b/ui/src/components/VolumeListTable.tsx @@ -85,18 +85,14 @@ const VolumeListTable = (props) => { width: '3rem', }, Cell: (cellProps) => { - const volume = volumeListData?.find( - (vol) => vol.name === cellProps.cell.row.values.name, - ); + const volume = volumeListData?.find((vol) => vol.name === cellProps.cell.row.values.name); switch (cellProps.value) { case 'exclamation': return ( {volume?.errorReason} - } + overlay={{volume?.errorReason}} > @@ -148,9 +144,7 @@ const VolumeListTable = (props) => { width: '3.5rem', }, Cell: (cellProps) => { - return cellProps.value !== undefined ? ( - - ) : null; + return cellProps.value !== undefined ? : null; }, }, ]; // eslint-disable-next-line react-hooks/exhaustive-deps @@ -165,17 +159,10 @@ const VolumeListTable = (props) => { location.pathname.endsWith('/details'); if (isTabSelected) { - const newPath = location.pathname.replace( - /\/volumes\/[^/]*\//, - `/volumes/${row.values.name}/`, - ); + const newPath = location.pathname.replace(/\/volumes\/[^/]*\//, `/volumes/${row.values.name}/`); navigate(`${newPath}?${query.toString()}`); } else { - navigate( - `${appHistoryBasePath}/volumes/${ - row.values.name - }/overview?${query.toString()}`, - ); + navigate(`${appHistoryBasePath}/volumes/${row.values.name}/overview?${query.toString()}`); } }; diff --git a/ui/src/components/VolumeMetricsTab.tsx b/ui/src/components/VolumeMetricsTab.tsx index 7f0e7df75c..606f09e342 100644 --- a/ui/src/components/VolumeMetricsTab.tsx +++ b/ui/src/components/VolumeMetricsTab.tsx @@ -1,36 +1,17 @@ -import { - Button, - ChartLegend, - ChartLegendWrapper, -} from '@scality/core-ui/dist/next'; +import { Button, ChartLegend, ChartLegendWrapper } from '@scality/core-ui/dist/next'; import { useSelector } from 'react-redux'; import { Icon, spacing } from '@scality/core-ui'; import { useIntl } from 'react-intl'; import { GRAFANA_DASHBOARDS, VOLUME_CONDITION_LINK } from '../constants'; import TimespanSelector from '../containers/TimespanSelector'; -import { - MetricsActionContainer, - NotBoundContainer, -} from './style/CommonLayoutStyle'; -import { - VolumeIOPSChart, - VolumeLatencyChart, - VolumeThroughputChart, - VolumeUsageChart, -} from './VolumeCharts'; +import { MetricsActionContainer, NotBoundContainer } from './style/CommonLayoutStyle'; +import { VolumeIOPSChart, VolumeLatencyChart, VolumeThroughputChart, VolumeUsageChart } from './VolumeCharts'; import { GraphGrid, ChartContainer } from '../containers/NodePageMetricsTab'; import { createColorSet } from '../services/graphUtils'; const MetricsTab = (props) => { - const { - volumeCondition, - deviceName, - instanceIp, - volumeName, - volumeNamespace, - volumePVCName, - } = props; + const { volumeCondition, deviceName, instanceIp, volumeName, volumeNamespace, volumePVCName } = props; const intl = useIntl(); // @ts-expect-error - FIXME when you are working on it const config = useSelector((state) => state.config); @@ -60,29 +41,13 @@ const MetricsTab = (props) => { - + - + - + - + diff --git a/ui/src/components/VolumeOverviewTab.tsx b/ui/src/components/VolumeOverviewTab.tsx index 0790ee1dd5..743ee79669 100644 --- a/ui/src/components/VolumeOverviewTab.tsx +++ b/ui/src/components/VolumeOverviewTab.tsx @@ -1,12 +1,4 @@ -import { - Banner, - FormattedDateTime, - Icon, - Link, - Modal, - ProgressBar, - spacing, -} from '@scality/core-ui'; +import { Banner, FormattedDateTime, Icon, Link, Modal, ProgressBar, spacing } from '@scality/core-ui'; import { Box, Button } from '@scality/core-ui/dist/next'; import { fontSize, fontWeight } from '@scality/core-ui/dist/style/theme'; import { useState } from 'react'; @@ -14,12 +6,7 @@ import { useIntl } from 'react-intl'; import { useDispatch } from 'react-redux'; import { useLocation } from 'react-router-dom'; import styled, { useTheme } from 'styled-components'; -import { - LVM_LOGICAL_VOLUME, - STATUS_CRITICAL, - STATUS_WARNING, - VOLUME_CONDITION_LINK, -} from '../constants'; +import { LVM_LOGICAL_VOLUME, STATUS_CRITICAL, STATUS_WARNING, VOLUME_CONDITION_LINK } from '../constants'; import { RenderNoDataAvailable } from '../containers/NodePageMetricsTab'; import { deleteVolumeAction } from '../ducks/app/volumes'; import { isVolumeDeletable } from '../services/NodeVolumesUtils'; @@ -115,11 +102,9 @@ const VolumeDetailCard = (props) => { const theme = useTheme(); const isVolumeUsageRetrievable = volumeUsagePercentage !== undefined; - const deleteVolume = (deleteVolumeName) => - dispatch(deleteVolumeAction(deleteVolumeName)); + const deleteVolume = (deleteVolumeName) => dispatch(deleteVolumeAction(deleteVolumeName)); - const [isDeleteConfirmationModalOpen, setisDeleteConfirmationModalOpen] = - useState(false); + const [isDeleteConfirmationModalOpen, setisDeleteConfirmationModalOpen] = useState(false); // Confirm the deletion const onClickDeleteButton = (deleteVolumeName, nodeName) => { @@ -233,9 +218,7 @@ const VolumeDetailCard = (props) => { id: 'status', })} - - {status} - + {status} @@ -243,9 +226,7 @@ const VolumeDetailCard = (props) => { id: 'storageClass', })} - - {storageClassName} - + {storageClassName} @@ -255,10 +236,7 @@ const VolumeDetailCard = (props) => { {creationTimestamp ? ( - + ) : ( '' @@ -288,18 +266,12 @@ const VolumeDetailCard = (props) => { id: 'backend_disk', })} - - {devicePath} - + {devicePath} ) : ( <> - - VG Name - - - {vgName} - + VG Name + {vgName} )} @@ -313,12 +285,8 @@ const VolumeDetailCard = (props) => { {labels?.map((label) => { return (
- - {label.name} - - - {label.value} - + {label.name} + {label.value}
); })} @@ -335,16 +303,8 @@ const VolumeDetailCard = (props) => { })} item?.labels?.severity === STATUS_CRITICAL, - ).length - } - warningCounter={ - alertlist?.filter( - (item) => item?.labels?.severity === STATUS_WARNING, - ).length - } + criticalCounter={alertlist?.filter((item) => item?.labels?.severity === STATUS_CRITICAL).length} + warningCounter={alertlist?.filter((item) => item?.labels?.severity === STATUS_WARNING).length} /> )} @@ -355,22 +315,19 @@ const VolumeDetailCard = (props) => { })} {!isVolumeUsageRetrievable && } - {isVolumeUsageRetrievable && - condition === VOLUME_CONDITION_LINK && ( - - - - )} + {isVolumeUsageRetrievable && condition === VOLUME_CONDITION_LINK && ( + + + + )} createStore(reducer, enhancer); export const waitForLoadingToFinish = () => - waitForElementToBeRemoved( - () => [ - ...screen.queryAllByLabelText(/loading/i), - ...screen.queryAllByText(/loading/i), - ], - { - timeout: 4000, - }, - ); + waitForElementToBeRemoved(() => [...screen.queryAllByLabelText(/loading/i), ...screen.queryAllByText(/loading/i)], { + timeout: 4000, + }); /** * StyleSheetManager + simplifiedStylesPlugin will remove