From 271c98eddbf1f992b57c94248b5f7a65b52b10c0 Mon Sep 17 00:00:00 2001 From: Nicolas Van Labeke <nicolas.vanlabeke@hivemq.com> Date: Tue, 28 Jan 2025 18:51:21 +0000 Subject: [PATCH 1/8] fix(29319): add missing capabilities enum --- .../src/api/hooks/useFrontendServices/useGetCapability.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hivemq-edge/src/frontend/src/api/hooks/useFrontendServices/useGetCapability.ts b/hivemq-edge/src/frontend/src/api/hooks/useFrontendServices/useGetCapability.ts index cf82d78fe4..83447c1818 100644 --- a/hivemq-edge/src/frontend/src/api/hooks/useFrontendServices/useGetCapability.ts +++ b/hivemq-edge/src/frontend/src/api/hooks/useFrontendServices/useGetCapability.ts @@ -3,9 +3,16 @@ import type { Capability } from '@/api/__generated__' import { useGetCapabilities } from './useGetCapabilities.ts' +/** + * Another nonsensical backend magic code that needs to be duplicated (and therefore disconnected) in the frontend + * We have a single source of truth with OpenAPI; can we finally just use it? + */ export enum CAPABILITY { PERSISTENCE = 'mqtt-persistence', DATAHUB = 'data-hub', + BIDIRECTIONAL_ADAPTER = 'bi-directional protocol adapters', + CONTROL_PLANE = 'control-plane-connectivity', + WRITEABLE_CONFIG = 'config-writeable', } export const useGetCapability = (id: string) => { From fb6a5621cd55433affbaeca450b61f86fead5ad0 Mon Sep 17 00:00:00 2001 From: Nicolas Van Labeke <nicolas.vanlabeke@hivemq.com> Date: Tue, 28 Jan 2025 18:51:43 +0000 Subject: [PATCH 2/8] feat(29319): add notification --- .../hooks/useGetManagedNotifications.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.tsx b/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.tsx index 431fa47c62..58ad0fb872 100644 --- a/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.tsx +++ b/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.tsx @@ -8,12 +8,14 @@ import { ExternalLinkIcon } from '@chakra-ui/icons' import { useGetReleases } from '@/api/hooks/useGitHub/useGetReleases.ts' import { useGetNotifications } from '@/api/hooks/useFrontendServices/useGetNotifications.ts' import { useGetConfiguration } from '@/api/hooks/useFrontendServices/useGetConfiguration.ts' +import { CAPABILITY, useGetCapability } from '@/api/hooks/useFrontendServices/useGetCapability.ts' export const useGetManagedNotifications = () => { const { t } = useTranslation() const { data: configuration } = useGetConfiguration() const { data: releases, isSuccess: isReleasesSuccess } = useGetReleases() const { data: notification, isSuccess: isNotificationsSuccess } = useGetNotifications() + const isWritableConfig = useGetCapability(CAPABILITY.WRITEABLE_CONFIG) const [readNotifications, setReadNotifications] = useState<string[]>([]) const [skip] = useLocalStorage<string[]>('edge.notifications', []) @@ -51,6 +53,21 @@ export const useGetManagedNotifications = () => { list.push(...toasts) } + if (!isWritableConfig && !skip.includes(CAPABILITY.WRITEABLE_CONFIG)) { + // TODO[EDGE] The important feature is when the config is NOT writable (API request will fail) + // The question is whether undefined (because it's not found) and undefined (because it is not supported) + // have the same effect + + list.push({ + ...defaults, + id: CAPABILITY.WRITEABLE_CONFIG, + status: 'warning', + title: <Text>{t('capabilities.WRITEABLE_CONFIG.title')} </Text>, + description: <Text>{t('capabilities.WRITEABLE_CONFIG.description')} </Text>, + onCloseComplete: () => handleReadNotification(CAPABILITY.WRITEABLE_CONFIG), + }) + } + if (configuration && releases && releases.length > 0) { const { name, html_url } = releases[0] const currentVersion = configuration.environment?.properties?.version From 37347773f9c76380c2dd922aa33a0b49e6ee3c3e Mon Sep 17 00:00:00 2001 From: Nicolas Van Labeke <nicolas.vanlabeke@hivemq.com> Date: Tue, 28 Jan 2025 18:51:53 +0000 Subject: [PATCH 3/8] feat(29319): add translations --- hivemq-edge/src/frontend/src/locales/en/translation.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hivemq-edge/src/frontend/src/locales/en/translation.json b/hivemq-edge/src/frontend/src/locales/en/translation.json index b0730e8ce4..cb239b4ae6 100755 --- a/hivemq-edge/src/frontend/src/locales/en/translation.json +++ b/hivemq-edge/src/frontend/src/locales/en/translation.json @@ -28,6 +28,12 @@ "status_ERROR": "Error" } }, + "capabilities": { + "WRITEABLE_CONFIG": { + "title": "Config cannot be manipulated via the REST API", + "description": "Changes to the configuration made via the web app will NOT be persisted back into the config.xml. The requests will fail with an error message highlighting this situation." + } + }, "navigation": { "mainPage": "Main content", "gateway": { From 0deaf0b8a19b2d4ad9c52dd19de3f067b1124583 Mon Sep 17 00:00:00 2001 From: Nicolas Van Labeke <nicolas.vanlabeke@hivemq.com> Date: Tue, 28 Jan 2025 19:07:47 +0000 Subject: [PATCH 4/8] test(29319): fix test (but that's a wrong fix!) --- .../hooks/useGetManagedNotifications.spec.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.spec.ts b/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.spec.ts index d3e4a3dfd1..f6e70116f9 100644 --- a/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.spec.ts +++ b/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.spec.ts @@ -29,7 +29,7 @@ describe('useGetManagedNotifications', () => { expect(result.current.isSuccess).toBeTruthy() }) - expect(result.current.notifications).toHaveLength(2) + expect(result.current.notifications).toHaveLength(3) expect(result.current.readNotifications).toHaveLength(0) }) @@ -40,7 +40,7 @@ describe('useGetManagedNotifications', () => { expect(result.current.isSuccess).toBeTruthy() }) - expect(result.current.notifications).toHaveLength(2) + expect(result.current.notifications).toHaveLength(3) expect(result.current.readNotifications).toHaveLength(0) // close the first notification @@ -48,7 +48,7 @@ describe('useGetManagedNotifications', () => { result.current.notifications[0].onCloseComplete?.() }) - expect(result.current.notifications).toHaveLength(1) + expect(result.current.notifications).toHaveLength(2) expect(result.current.readNotifications).toHaveLength(1) expect(result.current.readNotifications).toContainEqual('Default Credentials Need Changing!') @@ -57,9 +57,9 @@ describe('useGetManagedNotifications', () => { result.current.notifications[0].onCloseComplete?.() }) - expect(result.current.notifications).toHaveLength(0) + expect(result.current.notifications).toHaveLength(2) expect(result.current.readNotifications).toHaveLength(2) expect(result.current.readNotifications).toContainEqual('Default Credentials Need Changing!') - expect(result.current.readNotifications).toContainEqual('2023.XXX') + expect(result.current.readNotifications).toContainEqual('config-writeable') }) }) From c6d33bd4864bac12dc9aadf156ed5f4175f9782f Mon Sep 17 00:00:00 2001 From: Nicolas Van Labeke <nicolas.vanlabeke@hivemq.com> Date: Wed, 29 Jan 2025 08:55:51 +0000 Subject: [PATCH 5/8] test(29319): add test --- .../hooks/useGetManagedNotifications.spec.ts | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.spec.ts b/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.spec.ts index f6e70116f9..dbdef86d61 100644 --- a/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.spec.ts +++ b/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.spec.ts @@ -5,7 +5,11 @@ import { act, renderHook, waitFor } from '@testing-library/react' import { server } from '@/__test-utils__/msw/mockServer.ts' import { SimpleWrapper as wrapper } from '@/__test-utils__/hooks/SimpleWrapper.tsx' -import { handlers as frontendHandler } from '@/api/hooks/useFrontendServices/__handlers__' +import { + handlerCapabilities, + handlers as frontendHandler, + MOCK_CAPABILITY_WRITEABLE_CONFIG, +} from '@/api/hooks/useFrontendServices/__handlers__' import { handlers as gitHubHandler } from '@/api/hooks/useGitHub/__handlers__' import { useGetManagedNotifications } from './useGetManagedNotifications.tsx' @@ -62,4 +66,35 @@ describe('useGetManagedNotifications', () => { expect(result.current.readNotifications).toContainEqual('Default Credentials Need Changing!') expect(result.current.readNotifications).toContainEqual('config-writeable') }) + + it('should handle config-writeable', async () => { + server.use(...handlerCapabilities({ items: [MOCK_CAPABILITY_WRITEABLE_CONFIG] })) + + const { result } = renderHook(useGetManagedNotifications, { wrapper }) + + await waitFor(() => { + expect(result.current.isSuccess).toBeTruthy() + }) + + expect(result.current.notifications).toHaveLength(2) + + // close the first notification + act(() => { + result.current.notifications[0].onCloseComplete?.() + }) + + expect(result.current.notifications).toHaveLength(1) + expect(result.current.readNotifications).toHaveLength(1) + expect(result.current.readNotifications).toContainEqual('Default Credentials Need Changing!') + + // close the first notification + act(() => { + result.current.notifications[0].onCloseComplete?.() + }) + + expect(result.current.notifications).toHaveLength(0) + expect(result.current.readNotifications).toHaveLength(2) + expect(result.current.readNotifications).toContainEqual('Default Credentials Need Changing!') + expect(result.current.readNotifications).toContainEqual('2023.XXX') + }) }) From cc63ecb0e9708100de13b3fc76ab1cd20a7441f0 Mon Sep 17 00:00:00 2001 From: Nicolas Van Labeke <nicolas.vanlabeke@hivemq.com> Date: Wed, 29 Jan 2025 08:55:58 +0000 Subject: [PATCH 6/8] test(29319): fix mocks --- .../hooks/useFrontendServices/__handlers__/index.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hivemq-edge/src/frontend/src/api/hooks/useFrontendServices/__handlers__/index.ts b/hivemq-edge/src/frontend/src/api/hooks/useFrontendServices/__handlers__/index.ts index d4a97c38e2..3c73b390ec 100644 --- a/hivemq-edge/src/frontend/src/api/hooks/useFrontendServices/__handlers__/index.ts +++ b/hivemq-edge/src/frontend/src/api/hooks/useFrontendServices/__handlers__/index.ts @@ -127,6 +127,12 @@ export const MOCK_CAPABILITY_DATAHUB: Capability = { 'This enables HiveMQ Edge to make use of the HiveMQ Data Hub. This includes validation and transformation of data.', } +export const MOCK_CAPABILITY_WRITEABLE_CONFIG: Capability = { + id: 'config-writeable', + displayName: 'Config can be manipulated via the REST API', + description: 'Changes to the configuration made via the REST API are persisted back into the config.xml.', +} + export const MOCK_CAPABILITY_DUMMY: Capability = { id: 'edge', displayName: 'This is a test capability', @@ -150,3 +156,9 @@ export const handlers = [ return HttpResponse.json<CapabilityList>(MOCK_CAPABILITIES, { status: 200 }) }), ] + +export const handlerCapabilities = (source: CapabilityList) => [ + http.get('**/frontend/capabilities', () => { + return HttpResponse.json<CapabilityList>(source, { status: 200 }) + }), +] From cfef877ae334b62a6f02e774a8a544ff8c3c9f06 Mon Sep 17 00:00:00 2001 From: Nicolas Van Labeke <nicolas.vanlabeke@hivemq.com> Date: Wed, 29 Jan 2025 09:00:26 +0000 Subject: [PATCH 7/8] fix(29319): linting --- .../modules/Notifications/hooks/useGetManagedNotifications.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.tsx b/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.tsx index 58ad0fb872..e68ca5d33e 100644 --- a/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.tsx +++ b/hivemq-edge/src/frontend/src/modules/Notifications/hooks/useGetManagedNotifications.tsx @@ -94,7 +94,7 @@ export const useGetManagedNotifications = () => { } return list - }, [notification?.items, configuration, releases, readNotifications, skip, t]) + }, [notification?.items, isWritableConfig, skip, configuration, releases, readNotifications, t]) return { notifications, isSuccess: isNotificationsSuccess && isReleasesSuccess, readNotifications } } From 39c6fa860d6d00705f78e4c6c01c8cb67d7b430e Mon Sep 17 00:00:00 2001 From: Nicolas Van Labeke <nicolas.vanlabeke@hivemq.com> Date: Wed, 29 Jan 2025 10:07:13 +0000 Subject: [PATCH 8/8] fix(29319): fix translations --- hivemq-edge/src/frontend/src/locales/en/translation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hivemq-edge/src/frontend/src/locales/en/translation.json b/hivemq-edge/src/frontend/src/locales/en/translation.json index cb239b4ae6..7214c87cc6 100755 --- a/hivemq-edge/src/frontend/src/locales/en/translation.json +++ b/hivemq-edge/src/frontend/src/locales/en/translation.json @@ -30,7 +30,7 @@ }, "capabilities": { "WRITEABLE_CONFIG": { - "title": "Config cannot be manipulated via the REST API", + "title": "Config cannot be manipulated via the web app", "description": "Changes to the configuration made via the web app will NOT be persisted back into the config.xml. The requests will fail with an error message highlighting this situation." } },