Skip to content

Commit 1c875af

Browse files
authored
Merge pull request #383
fix(20360): Fix the serialisation of multiple scripts * fix(20360): remove the (unrecognised) format from the JSON schema for… * refactor(20360): export the summary of the dryrun as a component * refactor(20360): rename function * refactor(20360): add reducer for unique resources * fix(20360): fix the serialisation of multiple scripts * chore(20360): fix config of code coverage * chore(20360): a bit of cleaning * test(20360): fix test * refactor(20360): export and refactor function name utilities * test(20360): add test * fix(20360): fix layout of scripts * chore(20360): fix duplicate engines
1 parent 5bda3c5 commit 1c875af

File tree

14 files changed

+179
-96
lines changed

14 files changed

+179
-96
lines changed

hivemq-edge/src/frontend/package.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@
2525
"test:ui": "vitest --ui",
2626
"preview": "vite preview"
2727
},
28-
"engines": {
29-
"node": "20",
30-
"pnpm": "8"
31-
},
3228
"dependencies": {
3329
"@chakra-ui/anatomy": "^2.1.1",
3430
"@chakra-ui/icons": "^2.0.19",

hivemq-edge/src/frontend/src/components/PaginatedTable/PaginatedTable.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ const PaginatedTable = <T,>({
9393
.flat()
9494
.filter(Boolean).length > 0
9595

96-
console.log('XXXXX', hasFooters)
9796
return (
9897
<>
9998
<TableContainer overflowY="auto" overflowX="auto" whiteSpace="normal">

hivemq-edge/src/frontend/src/extensions/datahub/api/__generated__/schemas/OperationData.json

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

hivemq-edge/src/frontend/src/extensions/datahub/components/controls/ToolboxDryRun.tsx

Lines changed: 7 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,7 @@
11
import { FC, useCallback, useMemo } from 'react'
22
import { Node } from 'reactflow'
33
import { useTranslation } from 'react-i18next'
4-
import {
5-
Alert,
6-
AlertDescription,
7-
AlertIcon,
8-
AlertTitle,
9-
Box,
10-
Button,
11-
HStack,
12-
Icon,
13-
Stack,
14-
AlertStatus,
15-
CloseButton,
16-
Link,
17-
Text,
18-
} from '@chakra-ui/react'
19-
20-
import { ConditionalWrapper } from '@/components/ConditonalWrapper.tsx'
4+
import { Box, Button, HStack, Icon, Stack } from '@chakra-ui/react'
215

226
import PolicyErrorReport from '@datahub/components/helpers/PolicyErrorReport.tsx'
237
import { usePolicyDryRun } from '@datahub/hooks/usePolicyDryRun.ts'
@@ -26,6 +10,7 @@ import { usePolicyChecksStore } from '@datahub/hooks/usePolicyChecksStore.ts'
2610
import { getDryRunStatusIcon } from '@datahub/utils/node.utils.ts'
2711
import { DataHubNodeData, DesignerStatus, PolicyDryRunStatus } from '@datahub/types.ts'
2812
import { DesignerToolBoxProps } from '@datahub/components/controls/DesignerToolbox.tsx'
13+
import PolicySummaryReport from '@datahub/components/helpers/PolicySummaryReport.tsx'
2914

3015
interface ToolboxDryRunProps extends DesignerToolBoxProps {
3116
onShowNode?: (node: Node) => void
@@ -72,7 +57,6 @@ export const ToolboxDryRun: FC<ToolboxDryRunProps> = ({ onActiveStep, onShowNode
7257
})
7358
}
7459
const errorNodeFrom = useCallback((id: string) => nodes.find((node) => node.id === id), [nodes])
75-
const alertStatus: AlertStatus = status === PolicyDryRunStatus.SUCCESS ? 'success' : 'warning'
7660

7761
return (
7862
<Stack maxW={500}>
@@ -98,30 +82,11 @@ export const ToolboxDryRun: FC<ToolboxDryRunProps> = ({ onActiveStep, onShowNode
9882

9983
{report && (
10084
<>
101-
<Alert status={alertStatus} data-testid="toolbox-policy-check-status">
102-
<AlertIcon />
103-
<Box whiteSpace="normal">
104-
<AlertTitle>
105-
<Text as="span">{t('workspace.dryRun.report.success.title', { context: alertStatus })}</Text>
106-
</AlertTitle>
107-
<AlertDescription>
108-
<ConditionalWrapper
109-
condition={status === PolicyDryRunStatus.SUCCESS}
110-
wrapper={(children) => (
111-
<Link
112-
aria-label={t('workspace.toolbox.navigation.goPublish') as string}
113-
onClick={() => onActiveStep?.(DesignerToolBoxProps.Steps.TOOLBOX_CHECK)}
114-
>
115-
{children}
116-
</Link>
117-
)}
118-
>
119-
<Text as="span">{t('workspace.dryRun.report.success.description', { context: alertStatus })}</Text>
120-
</ConditionalWrapper>
121-
</AlertDescription>
122-
</Box>
123-
<CloseButton alignSelf="flex-start" position="relative" right={-1} top={-1} onClick={handleClearPolicy} />
124-
</Alert>
85+
<PolicySummaryReport
86+
status={status || PolicyDryRunStatus.FAILURE}
87+
onOpenPublish={() => onActiveStep?.(DesignerToolBoxProps.Steps.TOOLBOX_PUBLISH)}
88+
onClearPolicy={handleClearPolicy}
89+
/>
12590
<PolicyErrorReport
12691
errors={getErrors() || []}
12792
onFitView={(id) => {
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { FC } from 'react'
2+
import {
3+
Alert,
4+
AlertDescription,
5+
AlertIcon,
6+
AlertStatus,
7+
AlertTitle,
8+
Box,
9+
CloseButton,
10+
Link,
11+
Text,
12+
} from '@chakra-ui/react'
13+
import { useTranslation } from 'react-i18next'
14+
import { ConditionalWrapper } from '@/components/ConditonalWrapper.tsx'
15+
import { PolicyDryRunStatus } from '@datahub/types.ts'
16+
17+
interface PolicySummaryReportProps {
18+
status: PolicyDryRunStatus
19+
onOpenPublish?: () => void
20+
onClearPolicy?: () => void
21+
}
22+
23+
const PolicySummaryReport: FC<PolicySummaryReportProps> = ({ status, onOpenPublish, onClearPolicy }) => {
24+
const { t } = useTranslation('datahub')
25+
const alertStatus: AlertStatus = status === PolicyDryRunStatus.SUCCESS ? 'success' : 'warning'
26+
27+
return (
28+
<Alert status={alertStatus} data-testid="toolbox-policy-check-status">
29+
<AlertIcon />
30+
<Box whiteSpace="normal">
31+
<AlertTitle>
32+
<Text as="span">{t('workspace.dryRun.report.success.title', { context: alertStatus })}</Text>
33+
</AlertTitle>
34+
<AlertDescription>
35+
<ConditionalWrapper
36+
condition={status === PolicyDryRunStatus.SUCCESS}
37+
wrapper={(children) => (
38+
<Link aria-label={t('workspace.toolbox.navigation.goPublish') as string} onClick={onOpenPublish}>
39+
{children}
40+
</Link>
41+
)}
42+
>
43+
<Text as="span">{t('workspace.dryRun.report.success.description', { context: alertStatus })}</Text>
44+
</ConditionalWrapper>
45+
</AlertDescription>
46+
</Box>
47+
<CloseButton alignSelf="flex-start" position="relative" right={-1} top={-1} onClick={onClearPolicy} />
48+
</Alert>
49+
)
50+
}
51+
52+
export default PolicySummaryReport

hivemq-edge/src/frontend/src/extensions/datahub/designer/checks.utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { XYPosition } from 'reactflow'
44
export const CANVAS_POSITION = {
55
Client: { x: -300, y: 0 } as XYPosition,
66
Topic: { x: -300, y: 0 } as XYPosition,
7-
Function: { x: 0, y: -275 } as XYPosition,
7+
Function: { x: 350, y: -400 } as XYPosition,
88
Transition: { x: 400, y: 100 } as XYPosition,
99
Schema: { x: 0, y: -150 } as XYPosition,
1010
Validator: { x: 0, y: -150 } as XYPosition,

hivemq-edge/src/frontend/src/extensions/datahub/designer/operation/OperationNode.utils.spec.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ describe('checkValidityTransformFunction', () => {
351351
const { node, data, error, resources } = results[2]
352352
expect(node).toStrictEqual(MOCK_NODE_OPERATION)
353353
expect(error).toBeUndefined()
354-
expect(resources).toBeUndefined()
354+
expect(resources).toHaveLength(2)
355355
expect(data).toEqual(
356356
expect.objectContaining({
357357
arguments: {
@@ -367,14 +367,12 @@ describe('checkValidityTransformFunction', () => {
367367
const { node, data, error, resources } = results[1]
368368
expect(node).toStrictEqual(MOCK_NODE_OPERATION)
369369
expect(error).toBeUndefined()
370-
expect(resources).toHaveLength(2)
370+
expect(resources).toBeUndefined()
371371
expect(data).toEqual(
372372
expect.objectContaining({
373-
arguments: {
374-
transform: ['the_function'],
375-
},
373+
arguments: {},
376374
functionId: 'fn:the_function:latest',
377-
id: 'node-id',
375+
id: 'node-function',
378376
})
379377
)
380378
}

hivemq-edge/src/frontend/src/extensions/datahub/designer/operation/OperationNode.utils.ts

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ import {
1515
WorkspaceAction,
1616
WorkspaceState,
1717
} from '@datahub/types.ts'
18-
import { checkValidityJSScript, loadScripts } from '@datahub/designer/script/FunctionNode.utils.ts'
18+
import {
19+
checkValidityJSScript,
20+
formatScriptName,
21+
loadScripts,
22+
parseScriptName,
23+
} from '@datahub/designer/script/FunctionNode.utils.ts'
1924
import { checkValiditySchema, loadSchema } from '@datahub/designer/schema/SchemaNode.utils.ts'
2025
import { PolicyCheckErrors } from '@datahub/designer/validation.errors.ts'
2126
import { isFunctionNodeType, isSchemaNodeType } from '@datahub/utils/node.utils.ts'
@@ -39,7 +44,6 @@ export function checkValidityTransformFunction(
3944

4045
///////// Check the function handle
4146
const functions = getIncomers(operationNode, nodes, edges).filter(isFunctionNodeType)
42-
4347
if (!functions.length) {
4448
return [
4549
{
@@ -51,9 +55,9 @@ export function checkValidityTransformFunction(
5155

5256
///////// Check the serializers
5357
const serialisers = getIncomers(operationNode, nodes, edges).filter(isSchemaNodeType)
54-
5558
const connectedEdges = getConnectedEdges([...serialisers], edges).filter(
56-
(e) => e.targetHandle === OperationData.Handle.SERIALISER || e.targetHandle === OperationData.Handle.DESERIALISER
59+
(edge) =>
60+
edge.targetHandle === OperationData.Handle.SERIALISER || edge.targetHandle === OperationData.Handle.DESERIALISER
5761
)
5862
const [serial, ...restSerial] = connectedEdges.filter((edge) => edge.targetHandle === OperationData.Handle.SERIALISER)
5963
const [deserial, ...restDeserial] = connectedEdges.filter(
@@ -78,14 +82,11 @@ export function checkValidityTransformFunction(
7882
]
7983
}
8084

81-
// TODO[19240] Should serial and deserial be different ?
82-
8385
///////// Check the resources
8486
const scriptNodes = functions.map((node) => checkValidityJSScript(node))
8587
const schemaNodes = serialisers.map((node) => checkValiditySchema(node))
8688

87-
const scriptName = scriptNodes[0].node as Node<FunctionData>
88-
if (!scriptName) {
89+
if (!scriptNodes.length) {
8990
return [
9091
{
9192
node: operationNode,
@@ -94,9 +95,23 @@ export function checkValidityTransformFunction(
9495
]
9596
}
9697

97-
// TODO[19497] This should not have to happen on the client side!
98-
const formattedScriptName = (functionNode: Node<FunctionData>): string => {
99-
return `fn:${functionNode.data.name}:latest`
98+
const { transform } = operationNode.data.formData as unknown as OperationData.DataHubTransformType
99+
const defaultOrder = transform.length ? transform : scriptNodes.map((e) => e.data?.id)
100+
101+
const allTransformScripts: DryRunResults<PolicyOperation, Script>[] = []
102+
for (const scriptId of defaultOrder) {
103+
const script = scriptNodes.find((e) => e.data?.id === scriptId)
104+
if (script) {
105+
const scriptName = script.node as Node<FunctionData>
106+
107+
const operation: PolicyOperation = {
108+
functionId: formatScriptName(scriptName),
109+
arguments: {},
110+
// TODO[19466] Id should be user-facing; Need to fix before merging!
111+
id: scriptName.id,
112+
}
113+
allTransformScripts.push({ data: operation, node: operationNode })
114+
}
100115
}
101116

102117
const sourceDeserial = serialisers.find((node) => node.id === deserial.source)
@@ -120,14 +135,6 @@ export function checkValidityTransformFunction(
120135
id: `${operationNode.id}-deserializer`,
121136
}
122137

123-
// TODO[19497] there should be a list of functions
124-
const operation: PolicyOperation = {
125-
functionId: formattedScriptName(scriptName),
126-
arguments: operationNode.data.formData,
127-
// TODO[19466] Id should be user-facing; Need to fix before merging!
128-
id: operationNode.id,
129-
}
130-
131138
const sourceSerial = serialisers.find((node) => node.id === serial.source)
132139
if (!sourceSerial) {
133140
return [
@@ -149,10 +156,12 @@ export function checkValidityTransformFunction(
149156
} as PolicyOperationArguments,
150157
id: `${operationNode.id}-serializer`,
151158
}
159+
160+
// The resources are added tp the last item for convenience
152161
return [
153162
{ data: deserializer, node: operationNode },
154-
{ data: operation, node: operationNode, resources: [...scriptNodes, ...schemaNodes] },
155-
{ data: serializer, node: operationNode },
163+
...allTransformScripts,
164+
{ data: serializer, node: operationNode, resources: [...scriptNodes, ...schemaNodes] },
156165
]
157166
}
158167

@@ -307,7 +316,7 @@ export const loadPipeline = (
307316
isTerminal: false,
308317
hasArguments: true,
309318
},
310-
formData: { transform: functions.map((e) => e.functionId) },
319+
formData: { transform: functions.map((operation) => parseScriptName(operation)) },
311320
},
312321
}
313322

hivemq-edge/src/frontend/src/extensions/datahub/designer/script/FunctionNode.utils.spec.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ import { Node } from 'reactflow'
33
import { MOCK_DEFAULT_NODE } from '@/__test-utils__/react-flow/nodes.ts'
44

55
import { DataHubNodeType, FunctionData } from '@datahub/types.ts'
6-
import { checkValidityJSScript } from '@datahub/designer/script/FunctionNode.utils.ts'
6+
import {
7+
checkValidityJSScript,
8+
formatScriptName,
9+
parseScriptName,
10+
} from '@datahub/designer/script/FunctionNode.utils.ts'
711

812
describe('checkValidityJSScript', () => {
913
it('should return error when not configured', async () => {
@@ -60,3 +64,28 @@ describe('checkValidityJSScript', () => {
6064
expect(resources).toBeUndefined()
6165
})
6266
})
67+
68+
describe('parseScriptName', () => {
69+
it('should extract the function name from the operation', async () => {
70+
expect(parseScriptName({ functionId: 'fn:my-function:1', id: 'fakeId', arguments: {} })).toEqual('my-function')
71+
expect(parseScriptName({ functionId: 'my-raw-id', id: 'fakeId', arguments: {} })).toEqual('my-raw-id')
72+
})
73+
})
74+
75+
describe('formatScriptName', () => {
76+
it('should format the id of the script', async () => {
77+
const MOCK_NODE_SCRIPT: Node<FunctionData> = {
78+
id: 'node-id',
79+
type: DataHubNodeType.FUNCTION,
80+
data: {
81+
type: 'Javascript',
82+
name: 'my-name',
83+
version: 1,
84+
},
85+
...MOCK_DEFAULT_NODE,
86+
position: { x: 0, y: 0 },
87+
}
88+
89+
expect(formatScriptName(MOCK_NODE_SCRIPT)).toEqual('fn:my-name:latest')
90+
})
91+
})

0 commit comments

Comments
 (0)