Skip to content

Commit e76f676

Browse files
committed
feat: showing primary endpoint
1 parent b517b56 commit e76f676

2 files changed

Lines changed: 196 additions & 24 deletions

File tree

src/packages/ce/src/flow/components/panels/FlowPanelControlComponent.tsx

Lines changed: 119 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
import React from "react";
2-
import {Flow, LiteralValue, NodeFunction, ReferenceValue, SubFlowValue} from "@code0-tech/sagittarius-graphql-types";
2+
import {
3+
Flow,
4+
LiteralValue,
5+
Namespace,
6+
NamespaceProject,
7+
NodeFunction,
8+
ReferenceValue,
9+
SubFlowValue
10+
} from "@code0-tech/sagittarius-graphql-types";
311
import {
412
Badge,
513
Button,
14+
Spacing,
615
Text,
716
Tooltip,
817
TooltipContent,
@@ -15,10 +24,16 @@ import {Panel} from "@xyflow/react";
1524
import {ButtonGroup} from "@code0-tech/pictor/dist/components/button-group/ButtonGroup";
1625
import {FlowService} from "@edition/flow/services/Flow.service";
1726
import {SuggestionDialogComponent} from "@edition/function/components/suggestion/SuggestionDialogComponent";
18-
import {Suggestion} from "@edition/function/components/suggestion/Suggestion.util";
1927
import {useHotkeys} from "react-hotkeys-hook";
2028
import {useSelectedFunctionNode} from "@edition/function/hooks/FunctionNode.selected.hook";
2129
import {useFunctionSuggestions} from "@edition/function/hooks/Function.suggestion.hook";
30+
import {useParams} from "next/navigation";
31+
import {FlowTypeService} from "@edition/flowtype/services/FlowType.service";
32+
import {ProjectService} from "@edition/project/services/Project.service";
33+
import {ModuleService} from "@edition/module/services/Module.service";
34+
import {IconCheck, IconCopy} from "@tabler/icons-react";
35+
import {InputWrapper} from "@code0-tech/pictor/dist/components/form/InputWrapper";
36+
import {useCopyToClipboard} from "@uidotdev/usehooks";
2237

2338
export interface FlowPanelControlComponentProps {
2439
flowId: Flow['id']
@@ -30,17 +45,71 @@ export const FlowPanelControlComponent: React.FC<FlowPanelControlComponentProps>
3045
const {flowId} = props
3146

3247
//services and stores
48+
const params = useParams()
3349
const flowService = useService(FlowService)
3450
const flowStore = useStore(FlowService)
51+
const flowTypeService = useService(FlowTypeService)
52+
const flowTypeStore = useStore(FlowTypeService)
53+
const projectService = useService(ProjectService)
54+
const projectStore = useStore(ProjectService)
55+
const moduleService = useService(ModuleService)
56+
const moduleStore = useStore(ModuleService)
57+
58+
const [copiedText, copyToClipboard] = useCopyToClipboard();
59+
const hasCopiedText = Boolean(copiedText);
3560
const [, startTransition] = React.useTransition()
3661
const [suggestionDialogOpen, setSuggestionDialogOpen] = React.useState(false)
3762
const [addNextNodeTooltipOpen, setAddNextNodeTooltipOpen] = React.useState(false)
3863

64+
const namespaceIndex = params.namespaceId as any as number
65+
const projectIndex = params.projectId as any as number
66+
const namespaceId: Namespace['id'] = `gid://sagittarius/Namespace/${namespaceIndex}`
67+
const projectId: NamespaceProject['id'] = `gid://sagittarius/NamespaceProject/${projectIndex}`
68+
3969
//memoized values
4070
const selectedNode = useSelectedFunctionNode()
41-
4271
const result = useFunctionSuggestions()
4372

73+
const flow = React.useMemo(
74+
() => flowService.getById(flowId, {
75+
namespaceId,
76+
projectId
77+
}),
78+
[flowId, flowStore, namespaceId, projectId]
79+
)
80+
81+
const project = React.useMemo(
82+
() => projectService.getById(projectId, {
83+
namespaceId
84+
}),
85+
[projectId, namespaceId, projectStore]
86+
)
87+
88+
const flowType = React.useMemo(
89+
() => flowTypeService.getById(flow?.type?.id, {
90+
namespaceId,
91+
projectId,
92+
runtimeId: project?.primaryRuntime?.id
93+
}),
94+
[flow?.type?.id, namespaceId, projectId, project?.primaryRuntime?.id, flowTypeStore]
95+
)
96+
97+
const module = React.useMemo(
98+
() => moduleService.getById(flowType?.runtimeModule?.id, {
99+
namespaceId: namespaceId,
100+
projectId: projectId,
101+
runtimeId: project?.primaryRuntime?.id
102+
}),
103+
[flowType?.runtimeModule?.id, namespaceId, projectId, project?.primaryRuntime?.id, moduleStore]
104+
)
105+
106+
let endpoint = `http://${module?.definitions?.nodes?.[0]?.host}:${module?.definitions?.nodes?.[0]?.port}${module?.definitions?.nodes?.[0]?.endpoint}`
107+
.replace("${{project_slug}}", project?.slug ?? "${{project_slug}}")
108+
109+
flow?.settings?.nodes?.forEach(setting => {
110+
endpoint = endpoint.replace(`\${{${setting?.flowSettingIdentifier}}}`, setting?.value)
111+
})
112+
44113
//callbacks
45114
const deleteActiveNode = React.useCallback(() => {
46115
if (!selectedNode) return
@@ -83,7 +152,7 @@ export const FlowPanelControlComponent: React.FC<FlowPanelControlComponentProps>
83152
disabled={!selectedNode}
84153
onClick={deleteActiveNode}
85154
paddingSize={"xxs"}
86-
variant={"filled"}
155+
variant={"none"}
87156
color={"error"}>
88157
<Text>Delete node</Text>
89158
</Button>
@@ -99,11 +168,11 @@ export const FlowPanelControlComponent: React.FC<FlowPanelControlComponentProps>
99168
<Button data-qa-selector={"flow-builder-control-panel-add"}
100169
disabled={!selectedNode || !!selectedNode.data.functionId}
101170
paddingSize={"xxs"}
102-
variant={"filled"}
171+
variant={"none"}
103172
onClick={() => {
104173
if (selectedNode && !selectedNode.data.functionId) setSuggestionDialogOpen(true)
105174
}}
106-
color={"secondary"}>
175+
color={"tertiary"}>
107176
<Text display={"flex"} align={"center"} style={{gap: "0.35rem"}}>
108177
Add next node
109178
<Badge style={{gap: 0}}>Shift + A</Badge>
@@ -116,7 +185,51 @@ export const FlowPanelControlComponent: React.FC<FlowPanelControlComponentProps>
116185
</TooltipContent>}
117186
</TooltipPortal>
118187
</Tooltip>
188+
{module?.definitions?.nodes?.[0] ? (
189+
<Tooltip>
190+
<TooltipTrigger asChild>
191+
<Button data-qa-selector={"flow-builder-control-panel-execute"}
192+
paddingSize={"xxs"}
193+
variant={"none"}
194+
color={"tertiary"}>
195+
<Text>
196+
Execute flow
197+
</Text>
198+
</Button>
199+
</TooltipTrigger>
200+
<TooltipPortal>
201+
<TooltipContent p={0.7} sideOffset={8} color={"secondary"}>
202+
<Text>
203+
Execute the flow to see the results <br/> in the runtime.
204+
</Text>
205+
<Spacing spacing={"xs"}/>
206+
<InputWrapper title={"Endpoint"} right={
207+
<ButtonGroup color={"primary"}>
208+
<Button onClick={() => {
209+
copyToClipboard(endpoint)
210+
}} paddingSize={"xxs"} variant={"none"} color={"secondary"}>
211+
{hasCopiedText ? <IconCheck size={13}/> : <IconCopy size={13}/>}
212+
</Button>
213+
</ButtonGroup>
214+
}>
215+
<div style={{
216+
alignSelf: "center",
217+
flex: "1 1 auto"
218+
}}>
219+
<Text>
220+
{endpoint}
221+
</Text>
222+
</div>
223+
224+
</InputWrapper>
225+
</TooltipContent>
226+
</TooltipPortal>
227+
</Tooltip>
228+
) : (null as any)}
229+
119230
</ButtonGroup>
231+
232+
120233
</Panel>
121234

122235
}

src/packages/ce/src/function/components/nodes/FunctionNodeTriggerComponent.tsx

Lines changed: 77 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import React, {CSSProperties, memo} from "react";
22
import {Handle, Node, NodeProps, Position} from "@xyflow/react";
3-
import {Badge, Card, Flex, Text, useService, useStore as usePictorStore} from "@code0-tech/pictor";
3+
import {Badge, Card, Flex, Text, useService, useStore, useStore as usePictorStore} from "@code0-tech/pictor";
44
import {FunctionNodeComponentProps} from "@edition/function/components/nodes/FunctionNodeComponent";
55
import {FlowTypeService} from "@edition/flowtype/services/FlowType.service";
66
import {FlowService} from "@edition/flow/services/Flow.service";
77
import {IconVariable} from "@tabler/icons-react";
8-
import {NodeFunction} from "@code0-tech/sagittarius-graphql-types";
8+
import {Namespace, NamespaceProject, NodeFunction} from "@code0-tech/sagittarius-graphql-types";
99
import {icon, IconString} from "@core/util/icons";
1010
import {FALLBACK_FLOW_TYPE_DISPLAY_MESSAGE, FALLBACK_FLOW_TYPE_NAME} from "@core/util/fallback-translations";
1111
import {useFlowValidation} from "@edition/flow/hooks/Flow.validation.hook";
@@ -14,21 +14,73 @@ import {useSelectedFunctionNode} from "@edition/function/hooks/FunctionNode.sele
1414
import {LiteralBadgeComponent} from "@edition/datatype/components/badges/LiteralBadgeComponent";
1515
import {ReferenceBadgeComponent} from "@edition/datatype/components/badges/ReferenceBadgeComponent";
1616
import {NodeBadgeComponent} from "@edition/datatype/components/badges/NodeBadgeComponent";
17+
import {useParams} from "next/navigation";
18+
import {ProjectService} from "@edition/project/services/Project.service";
19+
import {ModuleService} from "@edition/module/services/Module.service";
1720

1821

1922
export type FunctionNodeTriggerComponentProps = NodeProps<Node<FunctionNodeComponentProps>>
2023

2124
export const FunctionNodeTriggerComponent: React.FC<FunctionNodeTriggerComponentProps> = memo((props) => {
2225

2326
const {data, id, selected} = props
27+
28+
const params = useParams()
2429
const flowTypeService = useService(FlowTypeService)
2530
const flowTypeStore = usePictorStore(FlowTypeService)
2631
const flowService = useService(FlowService)
2732
const flowStore = usePictorStore(FlowService)
33+
const projectService = useService(ProjectService)
34+
const projectStore = useStore(ProjectService)
35+
const moduleService = useService(ModuleService)
36+
const moduleStore = useStore(ModuleService)
37+
38+
const namespaceIndex = params.namespaceId as any as number
39+
const projectIndex = params.projectId as any as number
40+
const namespaceId: Namespace['id'] = `gid://sagittarius/Namespace/${namespaceIndex}`
41+
const projectId: NamespaceProject['id'] = `gid://sagittarius/NamespaceProject/${projectIndex}`
42+
43+
const flow = React.useMemo(
44+
() => flowService.getById(data.flowId, {
45+
namespaceId,
46+
projectId
47+
}),
48+
[data.flowId, namespaceId, projectId, flowStore]
49+
)
50+
51+
const project = React.useMemo(
52+
() => projectService.getById(projectId, {
53+
namespaceId
54+
}),
55+
[projectId, namespaceId, projectStore]
56+
)
57+
58+
const flowType = React.useMemo(
59+
() => flowTypeService.getById(flow?.type?.id, {
60+
namespaceId,
61+
projectId,
62+
runtimeId: project?.primaryRuntime?.id
63+
}),
64+
[flow?.type?.id, namespaceId, projectId, project?.primaryRuntime?.id, flowTypeStore]
65+
)
2866

29-
const flow = React.useMemo(() => flowService.getById(data.flowId), [flowStore, data])
30-
const definition = React.useMemo(() => flow ? flowTypeService.getById(flow.type?.id) : undefined, [flowTypeStore, flow])
31-
const DisplayIcon = icon(definition?.displayIcon as IconString)
67+
const module = React.useMemo(
68+
() => moduleService.getById(flowType?.runtimeModule?.id, {
69+
namespaceId: namespaceId,
70+
projectId: projectId,
71+
runtimeId: project?.primaryRuntime?.id
72+
}),
73+
[flowType?.runtimeModule?.id, namespaceId, projectId, project?.primaryRuntime?.id, moduleStore]
74+
)
75+
76+
let endpoint = `http://${module?.definitions?.nodes?.[0]?.host}:${module?.definitions?.nodes?.[0]?.port}${module?.definitions?.nodes?.[0]?.endpoint}`
77+
.replace("${{project_slug}}", project?.slug ?? "${{project_slug}}")
78+
79+
flow?.settings?.nodes?.forEach(setting => {
80+
endpoint = endpoint.replace(`\${{${setting?.flowSettingIdentifier}}}`, setting?.value)
81+
})
82+
83+
const DisplayIcon = icon(flowType?.displayIcon as IconString)
3284
const validation = useFlowValidation(data.flowId)
3385

3486
const triggerValidations = React.useMemo(
@@ -55,15 +107,15 @@ export const FunctionNodeTriggerComponent: React.FC<FunctionNodeTriggerComponent
55107
.flatMap(p => p.trim() === "," ? [","] : p.trim() ? [p.trim()] : [])
56108
)
57109

58-
const displayMessage = React.useMemo(() => splitTemplate(definition?.displayMessages?.[0]?.content ?? FALLBACK_FLOW_TYPE_DISPLAY_MESSAGE).map(item => {
110+
const displayMessage = React.useMemo(() => splitTemplate(flowType?.displayMessages?.[0]?.content ?? FALLBACK_FLOW_TYPE_DISPLAY_MESSAGE).map(item => {
59111

60112
const nodeParameter = flow?.settings?.nodes?.find((_, index) => {
61-
const parameterDefinition = definition?.flowTypeSettings?.[index]
113+
const parameterDefinition = flowType?.flowTypeSettings?.[index]
62114
return parameterDefinition?.identifier == item
63115
})
64116

65-
const parameterDefinition = definition?.flowTypeSettings?.find(pd => pd?.identifier == item)
66-
const parameterIndex = parameterDefinition ? definition?.flowTypeSettings?.findIndex(p => p?.id === parameterDefinition.id) : undefined
117+
const parameterDefinition = flowType?.flowTypeSettings?.find(pd => pd?.identifier == item)
118+
const parameterIndex = parameterDefinition ? flowType?.flowTypeSettings?.findIndex(p => p?.id === parameterDefinition.id) : undefined
67119
const parameterValidation = validation?.filter(v => v.parameterIndex === parameterIndex && !v.nodeId)
68120
const decorationStyle: CSSProperties =
69121
parameterValidation?.length
@@ -94,7 +146,7 @@ export const FunctionNodeTriggerComponent: React.FC<FunctionNodeTriggerComponent
94146
</div>
95147
}
96148
return " " + String(item) + " "
97-
}), [flowStore, data, definition, validation])
149+
}), [flowStore, data, flowType, validation])
98150

99151
const isReferenced = React.useMemo(() => {
100152

@@ -121,17 +173,24 @@ export const FunctionNodeTriggerComponent: React.FC<FunctionNodeTriggerComponent
121173
className={`d-flow-node ${selected ? "d-flow-node--active" : undefined}`}
122174
style={{...(isReferenced === true ? {boxShadow: `0 0 5rem 0 rgba(112, 255, 178, 0.25)`} : {}),}}>
123175

124-
<Badge color={"info"}
125-
pos={"absolute"}
126-
top={"-0.35rem"}
127-
left={"50%"}
128-
style={{transform: "translate(-50%, -100%)"}}>
129-
Starting node
130-
</Badge>
176+
<Flex pos={"absolute"}
177+
top={"-0.35rem"}
178+
left={"50%"}
179+
align={"center"}
180+
style={{transform: "translate(-50%, -100%)", flexDirection: "column", gap: "0.35rem"}}>
181+
<Badge color={"info"}>
182+
Flow trigger
183+
</Badge>
184+
{module?.definitions?.nodes?.[0] && (
185+
<Badge color={"secondary"}>
186+
<Text size={"xs"}>{endpoint}</Text>
187+
</Badge>
188+
)}
189+
</Flex>
131190

132191
<Flex style={{gap: "0.7rem", ...triggerValidationStyle}} align={"center"}>
133192
<DisplayIcon color={data.color} size={16}/>
134-
<Text size={"md"}>{flow ? displayMessage : definition?.names?.[0].content ?? FALLBACK_FLOW_TYPE_NAME}</Text>
193+
<Text size={"md"}>{flow ? displayMessage : flowType?.names?.[0].content ?? FALLBACK_FLOW_TYPE_NAME}</Text>
135194
</Flex>
136195

137196
{

0 commit comments

Comments
 (0)