diff --git a/hivemq-edge/src/frontend/src/modules/EdgeVisualisation/utils/status-utils.spec.ts b/hivemq-edge/src/frontend/src/modules/EdgeVisualisation/utils/status-utils.spec.ts new file mode 100644 index 0000000000..8b49b510f0 --- /dev/null +++ b/hivemq-edge/src/frontend/src/modules/EdgeVisualisation/utils/status-utils.spec.ts @@ -0,0 +1,103 @@ +import { expect } from 'vitest' +import { Node, NodeProps } from 'reactflow' + +import { Adapter, ConnectionStatus } from '@/api/__generated__' + +import { MOCK_NODE_ADAPTER, MOCK_NODE_BRIDGE, MOCK_NODE_LISTENER } from '@/__test-utils__/react-flow/nodes.ts' +import { updateNodeStatus } from '@/modules/EdgeVisualisation/utils/status-utils.ts' +import { NodeTypes } from '@/modules/EdgeVisualisation/types.ts' +import { mockBridgeId } from '@/api/hooks/useGetBridges/__handlers__' +import { MOCK_ADAPTER_ID } from '@/__test-utils__/mocks.ts' + +const disconnectedBridge: NodeProps = { + ...MOCK_NODE_BRIDGE, + data: { + ...MOCK_NODE_BRIDGE.data, + bridgeRuntimeInformation: { + connectionStatus: { + status: ConnectionStatus.status.DISCONNECTED, + }, + }, + }, +} +const disconnectedAdapter: NodeProps = { + ...MOCK_NODE_ADAPTER, + data: { + ...MOCK_NODE_ADAPTER.data, + adapterRuntimeInformation: { + connectionStatus: { + status: ConnectionStatus.status.DISCONNECTED, + }, + }, + }, +} + +interface Suite { + nodes: Node[] + status: ConnectionStatus[] + expected: Node[] +} +const validationSuite: Suite[] = [ + { + nodes: [], + status: [], + expected: [], + }, + { + nodes: [], + status: [ + { status: ConnectionStatus.status.DISCONNECTED, type: NodeTypes.BRIDGE_NODE, id: 'one' }, + { status: ConnectionStatus.status.DISCONNECTED, type: NodeTypes.ADAPTER_NODE, id: 'two' }, + ], + expected: [], + }, + { + // @ts-ignore + nodes: [disconnectedBridge, disconnectedAdapter], + status: [{ status: ConnectionStatus.status.CONNECTED, type: NodeTypes.BRIDGE_NODE, id: 'non-existing-bridge' }], + // @ts-ignore + expected: [disconnectedBridge, disconnectedAdapter], + }, + { + // @ts-ignore + nodes: [MOCK_NODE_LISTENER], + status: [{ status: ConnectionStatus.status.CONNECTED, type: NodeTypes.BRIDGE_NODE, id: 'non-existing-bridge' }], + // @ts-ignore + expected: [MOCK_NODE_LISTENER], + }, + { + // @ts-ignore + nodes: [disconnectedBridge, disconnectedAdapter], + status: [ + { status: ConnectionStatus.status.DISCONNECTED, type: NodeTypes.BRIDGE_NODE, id: mockBridgeId }, + { status: ConnectionStatus.status.DISCONNECTED, type: NodeTypes.ADAPTER_NODE, id: MOCK_ADAPTER_ID }, + ], + // @ts-ignore + expected: [disconnectedBridge, disconnectedAdapter], + }, + { + // @ts-ignore + nodes: [disconnectedBridge, disconnectedAdapter], + status: [ + { status: ConnectionStatus.status.CONNECTING, type: NodeTypes.BRIDGE_NODE, id: mockBridgeId }, + { status: ConnectionStatus.status.CONNECTING, type: NodeTypes.ADAPTER_NODE, id: MOCK_ADAPTER_ID }, + ], + expected: expect.arrayContaining([ + expect.objectContaining({ + data: expect.objectContaining({ + bridgeRuntimeInformation: expect.objectContaining({ + connectionStatus: expect.objectContaining({ status: ConnectionStatus.status.CONNECTING }), + }), + }), + }), + ]), + }, +] + +describe('updateNodeStatus', () => { + it.each(validationSuite)('should work', ({ nodes, status, expected }) => { + const updatedNodes = updateNodeStatus(nodes, status) + expect(updatedNodes.length).toBe(nodes.length) + expect(updatedNodes).toStrictEqual(expected) + }) +}) diff --git a/hivemq-edge/src/frontend/src/modules/EdgeVisualisation/utils/status-utils.ts b/hivemq-edge/src/frontend/src/modules/EdgeVisualisation/utils/status-utils.ts new file mode 100644 index 0000000000..f1b9fdd03f --- /dev/null +++ b/hivemq-edge/src/frontend/src/modules/EdgeVisualisation/utils/status-utils.ts @@ -0,0 +1,37 @@ +import { Node } from 'reactflow' +import { Adapter, Bridge, ConnectionStatus } from '@/api/__generated__' +import { NodeTypes } from '@/modules/EdgeVisualisation/types.ts' + +export const updateNodeStatus = (currentNodes: Node[], updates: ConnectionStatus[]) => { + return currentNodes.map((n) => { + if (n.type === NodeTypes.BRIDGE_NODE) { + const newData = { ...n.data } as Bridge + const newStatus = updates.find((s) => s.id === newData.id) + if (!newStatus) return n + if (newStatus.status === newData.bridgeRuntimeInformation?.connectionStatus?.status) return n + + n.data = { + ...newData, + bridgeRuntimeInformation: { + connectionStatus: newStatus, + }, + } + return n + } + if (n.type === NodeTypes.ADAPTER_NODE) { + const newData = { ...n.data } as Adapter + const newStatus = updates.find((s) => s.id === newData.id) + if (!newStatus) return n + if (newStatus.status === newData.adapterRuntimeInformation?.connectionStatus?.status) return n + + n.data = { + ...newData, + adapterRuntimeInformation: { + connectionStatus: newStatus, + }, + } + return n + } + return n + }) +}