Skip to content

Commit

Permalink
Merge pull request #699
Browse files Browse the repository at this point in the history
* fix(28810): refactor the adapter flags with the north and southbound …

* fix(28810): fix status update

* test(28866): fix tests
  • Loading branch information
vanch3d authored Dec 12, 2024
1 parent 5417a21 commit 20115dd
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 45 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
/// <reference types="cypress" />

import { mockReactFlow } from '@/__test-utils__/react-flow/providers.tsx'
import { CustomNodeTesting } from '@/__test-utils__/react-flow/CustomNodeTesting.tsx'
import { MOCK_NODE_ADAPTER } from '@/__test-utils__/react-flow/nodes.ts'
import { MOCK_TOPIC_REF1, MOCK_TOPIC_REF2 } from '@/__test-utils__/react-flow/topics.ts'
import { MOCK_ADAPTER_ID } from '@/__test-utils__/mocks.ts'

import { mockProtocolAdapter } from '@/api/hooks/useProtocolAdapters/__handlers__'
import { formatTopicString } from '@/components/MQTT/topic-utils.ts'
import { NodeTypes } from '@/modules/Workspace/types.ts'

import NodeAdapter from './NodeAdapter.tsx'
import {
MOCK_NORTHBOUND_MAPPING,
MOCK_SOUTHBOUND_MAPPING,
} from '@/api/hooks/useProtocolAdapters/__handlers__/mapping.mocks.ts'

describe('NodeAdapter', () => {
beforeEach(() => {
Expand All @@ -25,17 +26,22 @@ describe('NodeAdapter', () => {
},
],
})

cy.intercept('/api/v1/management/protocol-adapters/adapters/*/northboundMappings', {
items: [MOCK_NORTHBOUND_MAPPING],
}).as('getNorthboundMappings')

cy.intercept('/api/v1/management/protocol-adapters/adapters/*/southboundMappings', {
items: [MOCK_SOUTHBOUND_MAPPING],
}).as('getSouthboundMappings')
})

it('should render properly', () => {
cy.mountWithProviders(mockReactFlow(<NodeAdapter {...MOCK_NODE_ADAPTER} />))

cy.getByTestId('adapter-node-name').should('contain', MOCK_ADAPTER_ID)
cy.getByTestId('connection-status').should('contain.text', 'Connected')
cy.getByTestId('topics-container')
.should('be.visible')
.should('contain.text', formatTopicString(MOCK_TOPIC_REF1))
.should('contain.text', formatTopicString(MOCK_TOPIC_REF2))
cy.getByTestId('topics-container').should('be.visible').should('contain.text', formatTopicString('my/topic'))
})

it('should render the selected adapter properly', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import { Box, HStack, Icon, Image, SkeletonText, Text, VStack } from '@chakra-ui

import { type Adapter } from '@/api/__generated__'
import { useGetAdapterTypes } from '@/api/hooks/useProtocolAdapters/useGetAdapterTypes.ts'
import { CustomFormat } from '@/api/types/json-schema.ts'
import { useListNorthboundMappings } from '@/api/hooks/useProtocolAdapters/useListNorthboundMappings.ts'
import { useListSouthboundMappings } from '@/api/hooks/useProtocolAdapters/useListSouthboundMappings.ts'

import IconButton from '@/components/Chakra/IconButton.tsx'
import { ConnectionStatusBadge } from '@/components/ConnectionStatusBadge'
import ToolbarButtonGroup from '@/components/react-flow/ToolbarButtonGroup.tsx'
import { useEdgeFlowContext } from '@/modules/Workspace/hooks/useEdgeFlowContext.ts'
import { discoverAdapterTopics } from '@/modules/Workspace/utils/topics-utils.ts'
import { useContextMenu } from '@/modules/Workspace/hooks/useContextMenu.ts'
import { deviceCapabilityIcon, isBidirectional } from '@/modules/Workspace/utils/adapter.utils.ts'
import ContextualToolbar from '@/modules/Workspace/components/nodes/ContextualToolbar.tsx'
Expand All @@ -25,17 +26,18 @@ const NodeAdapter: FC<NodeProps<Adapter>> = ({ id, data: adapter, selected, drag
const { data: protocols } = useGetAdapterTypes()
const adapterProtocol = protocols?.items?.find((e) => e.id === adapter.type)
const { options } = useEdgeFlowContext()
const { data: northMappings } = useListNorthboundMappings(adapter.id)
const { data: southMappings } = useListSouthboundMappings(adapter.id)

const northFlags = useMemo(() => {
return northMappings?.items?.map((mapping) => mapping.topic) || []
}, [northMappings?.items])

const southFlags = useMemo(() => {
const sss = southMappings?.items?.map((mapping) => mapping.topicFilter) || []
return sss.filter((item) => item) as string[]
}, [southMappings?.items])

const topicFilters = useMemo<string[]>(() => {
if (!adapterProtocol) return []
if (!adapter.config) return []
return discoverAdapterTopics(adapterProtocol, adapter.config, CustomFormat.MQTT_TOPIC_FILTER)
}, [adapter.config, adapterProtocol])
const topics = useMemo<string[]>(() => {
if (!adapterProtocol) return []
if (!adapter.config) return []
return discoverAdapterTopics(adapterProtocol, adapter.config)
}, [adapter.config, adapterProtocol])
const { onContextMenu } = useContextMenu(id, selected, `/workspace/node/adapter/${adapter.type}`)
const navigate = useNavigate()
const showSkeleton = useStore(selectorIsSkeletonZoom)
Expand Down Expand Up @@ -70,7 +72,7 @@ const NodeAdapter: FC<NodeProps<Adapter>> = ({ id, data: adapter, selected, drag
>
{!showSkeleton && (
<VStack>
{bidirectional && <MappingBadge destinations={topicFilters} isTag />}
{bidirectional && <MappingBadge destinations={southFlags} />}

<HStack>
<Image aria-label={adapter.type} boxSize="20px" objectFit="scale-down" src={adapterProtocol?.logoUrl} />
Expand All @@ -83,7 +85,7 @@ const NodeAdapter: FC<NodeProps<Adapter>> = ({ id, data: adapter, selected, drag
<ConnectionStatusBadge status={adapter.status} />
</Box>
)}
{options.showTopics && <MappingBadge destinations={topics} />}
{options.showTopics && <MappingBadge destinations={northFlags} />}
</VStack>
)}
{showSkeleton && (
Expand All @@ -93,7 +95,7 @@ const NodeAdapter: FC<NodeProps<Adapter>> = ({ id, data: adapter, selected, drag
</Box>
<Box w="100%">
<SkeletonText
noOfLines={topics.length ? 2 : 1}
noOfLines={northFlags.length ? 2 : 1}
spacing="4"
skeletonHeight="2"
startColor="gray.500"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ describe('getEdgeStatus', () => {
},
},
])('should return the correct style for $isConnected and $hasTopics', ({ isConnected, hasTopics, expected }) => {
const edgeStyle = getEdgeStatus(isConnected, hasTopics, color)
const edgeStyle = getEdgeStatus(isConnected, hasTopics, true, color)
expect(edgeStyle).toStrictEqual(expected)
})
})
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { Edge, Instance, MarkerType, Node } from 'reactflow'
import { GenericObjectType } from '@rjsf/utils'
import { WithCSSVar } from '@chakra-ui/react'
import { Dict } from '@chakra-ui/utils'

import { Adapter, Bridge, ProtocolAdapter, Status } from '@/api/__generated__'
import { CustomFormat } from '@/api/types/json-schema.ts'

import { Group, NodeTypes } from '../types.ts'
import { discoverAdapterTopics, getBridgeTopics } from './topics-utils.ts'
import { getBridgeTopics } from './topics-utils.ts'
import { isBidirectional } from '@/modules/Workspace/utils/adapter.utils.ts'

/**
* @param theme
Expand Down Expand Up @@ -62,19 +61,28 @@ export const updateNodeStatus = (currentNodes: Node[], updates: Status[]) => {

export type EdgeStyle = Pick<Edge, 'style' | 'animated' | 'markerEnd' | 'data'>

export const getEdgeStatus = (isConnected: boolean, hasTopics: boolean, themeForStatus: string): EdgeStyle => {
export const getEdgeStatus = (
isConnected: boolean,
hasTopics: boolean,
hasMarker: boolean,
themeForStatus: string
): EdgeStyle => {
const edge: EdgeStyle = {}
edge.style = {
strokeWidth: 1.5,
stroke: themeForStatus,
}
edge.animated = isConnected && hasTopics
edge.markerEnd = {
type: MarkerType.ArrowClosed,
width: 20,
height: 20,
color: themeForStatus,
}

edge.markerEnd = hasMarker
? {
type: MarkerType.ArrowClosed,
width: 20,
height: 20,
color: themeForStatus,
}
: undefined

edge.data = {
isConnected,
hasTopics,
Expand Down Expand Up @@ -107,7 +115,7 @@ export const updateEdgesStatus = (
connection: isConnected ? Status.connection.CONNECTED : Status.connection.DISCONNECTED,
}

newEdges.push({ ...edge, ...getEdgeStatus(isConnected, hasTopics, getThemeForStatus(theme, status)) })
newEdges.push({ ...edge, ...getEdgeStatus(isConnected, hasTopics, true, getThemeForStatus(theme, status)) })
return
}

Expand All @@ -127,28 +135,23 @@ export const updateEdgesStatus = (
if (source && source.type === NodeTypes.ADAPTER_NODE) {
const type = adapterTypes?.find((e) => e.id === (source.data as Adapter).type)
if (target?.type === NodeTypes.DEVICE_NODE) {
const topicFilters = type
? discoverAdapterTopics(
type,
(source.data as Adapter).config as GenericObjectType,
CustomFormat.MQTT_TOPIC_FILTER
)
: []
newEdges.push({
...edge,
...getEdgeStatus(isConnected, !!topicFilters.length, getThemeForStatus(theme, status)),
...getEdgeStatus(isConnected, false, isBidirectional(type), getThemeForStatus(theme, status)),
})
} else {
const topics = type ? discoverAdapterTopics(type, (source.data as Adapter).config as GenericObjectType) : []
newEdges.push({ ...edge, ...getEdgeStatus(isConnected, !!topics.length, getThemeForStatus(theme, status)) })
newEdges.push({
...edge,
...getEdgeStatus(isConnected, false, true, getThemeForStatus(theme, status)),
})
}

return
}

if (source && source.type === NodeTypes.BRIDGE_NODE) {
const { remote } = getBridgeTopics(source.data as Bridge)
newEdges.push({ ...edge, ...getEdgeStatus(isConnected, !!remote.length, getThemeForStatus(theme, status)) })
newEdges.push({ ...edge, ...getEdgeStatus(isConnected, !!remote.length, true, getThemeForStatus(theme, status)) })
return
}
newEdges.push(edge)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ const getTopicsFromPath = (path: string, instance: GenericObjectType): string[]
return getTopicsFromPath(rest.join('.'), instance?.[property])
}

/**
* @deprecated This is not in use anymore; check the north and south mappings
*/
export const discoverAdapterTopics = (
protocol: ProtocolAdapter,
instance: GenericObjectType,
Expand Down

0 comments on commit 20115dd

Please sign in to comment.