@tari-project/tari-extension-query-builder 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/LICENSE +29 -0
  2. package/README.md +1 -0
  3. package/components.json +21 -0
  4. package/dist/App.d.ts +3 -0
  5. package/dist/App.d.ts.map +1 -0
  6. package/dist/codegen/BuilderCodegen.d.ts +20 -0
  7. package/dist/codegen/BuilderCodegen.d.ts.map +1 -0
  8. package/dist/codegen/sample.d.ts +3 -0
  9. package/dist/codegen/sample.d.ts.map +1 -0
  10. package/dist/components/query-builder/edges/button-edge.d.ts +3 -0
  11. package/dist/components/query-builder/edges/button-edge.d.ts.map +1 -0
  12. package/dist/components/query-builder/input/call-input-checkbox.d.ts +11 -0
  13. package/dist/components/query-builder/input/call-input-checkbox.d.ts.map +1 -0
  14. package/dist/components/query-builder/input/call-input-select.d.ts +14 -0
  15. package/dist/components/query-builder/input/call-input-select.d.ts.map +1 -0
  16. package/dist/components/query-builder/input/call-input-text.d.ts +18 -0
  17. package/dist/components/query-builder/input/call-input-text.d.ts.map +1 -0
  18. package/dist/components/query-builder/input/call-input.d.ts +13 -0
  19. package/dist/components/query-builder/input/call-input.d.ts.map +1 -0
  20. package/dist/components/query-builder/nodes/call-node.types.d.ts +4 -0
  21. package/dist/components/query-builder/nodes/call-node.types.d.ts.map +1 -0
  22. package/dist/components/query-builder/nodes/constants.d.ts +5 -0
  23. package/dist/components/query-builder/nodes/constants.d.ts.map +1 -0
  24. package/dist/components/query-builder/nodes/enter-connection.d.ts +3 -0
  25. package/dist/components/query-builder/nodes/enter-connection.d.ts.map +1 -0
  26. package/dist/components/query-builder/nodes/exit-connection.d.ts +3 -0
  27. package/dist/components/query-builder/nodes/exit-connection.d.ts.map +1 -0
  28. package/dist/components/query-builder/nodes/generic/generic-node.d.ts +5 -0
  29. package/dist/components/query-builder/nodes/generic/generic-node.d.ts.map +1 -0
  30. package/dist/components/query-builder/nodes/generic/node-icon.d.ts +8 -0
  31. package/dist/components/query-builder/nodes/generic/node-icon.d.ts.map +1 -0
  32. package/dist/components/query-builder/nodes/generic-node.types.d.ts +6 -0
  33. package/dist/components/query-builder/nodes/generic-node.types.d.ts.map +1 -0
  34. package/dist/components/query-builder/nodes/input/constants.d.ts +2 -0
  35. package/dist/components/query-builder/nodes/input/constants.d.ts.map +1 -0
  36. package/dist/components/query-builder/nodes/input/editable-label.d.ts +9 -0
  37. package/dist/components/query-builder/nodes/input/editable-label.d.ts.map +1 -0
  38. package/dist/components/query-builder/nodes/input/input-params-node.d.ts +5 -0
  39. package/dist/components/query-builder/nodes/input/input-params-node.d.ts.map +1 -0
  40. package/dist/components/query-builder/query-builder.d.ts +13 -0
  41. package/dist/components/query-builder/query-builder.d.ts.map +1 -0
  42. package/dist/components/ui/alert-dialog.d.ts +15 -0
  43. package/dist/components/ui/alert-dialog.d.ts.map +1 -0
  44. package/dist/components/ui/badge.d.ts +10 -0
  45. package/dist/components/ui/badge.d.ts.map +1 -0
  46. package/dist/components/ui/button.d.ts +11 -0
  47. package/dist/components/ui/button.d.ts.map +1 -0
  48. package/dist/components/ui/checkbox.d.ts +5 -0
  49. package/dist/components/ui/checkbox.d.ts.map +1 -0
  50. package/dist/components/ui/dropdown-menu.d.ts +26 -0
  51. package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
  52. package/dist/components/ui/input.d.ts +4 -0
  53. package/dist/components/ui/input.d.ts.map +1 -0
  54. package/dist/components/ui/label.d.ts +5 -0
  55. package/dist/components/ui/label.d.ts.map +1 -0
  56. package/dist/components/ui/loading-spinner.d.ts +7 -0
  57. package/dist/components/ui/loading-spinner.d.ts.map +1 -0
  58. package/dist/components/ui/popover.d.ts +8 -0
  59. package/dist/components/ui/popover.d.ts.map +1 -0
  60. package/dist/components/ui/select.d.ts +16 -0
  61. package/dist/components/ui/select.d.ts.map +1 -0
  62. package/dist/components/ui/separator.d.ts +5 -0
  63. package/dist/components/ui/separator.d.ts.map +1 -0
  64. package/dist/components/ui/sonner.d.ts +4 -0
  65. package/dist/components/ui/sonner.d.ts.map +1 -0
  66. package/dist/components/ui/textarea.d.ts +4 -0
  67. package/dist/components/ui/textarea.d.ts.map +1 -0
  68. package/dist/components/ui/tooltip.d.ts +8 -0
  69. package/dist/components/ui/tooltip.d.ts.map +1 -0
  70. package/dist/execute/AmbiguousOrderError.d.ts +6 -0
  71. package/dist/execute/AmbiguousOrderError.d.ts.map +1 -0
  72. package/dist/execute/CycleDetectedError.d.ts +4 -0
  73. package/dist/execute/CycleDetectedError.d.ts.map +1 -0
  74. package/dist/execute/ExecutionPlanner.d.ts +30 -0
  75. package/dist/execute/ExecutionPlanner.d.ts.map +1 -0
  76. package/dist/execute/ExecutionPlanner.spec.d.ts +2 -0
  77. package/dist/execute/ExecutionPlanner.spec.d.ts.map +1 -0
  78. package/dist/execute/MissingDataError.d.ts +5 -0
  79. package/dist/execute/MissingDataError.d.ts.map +1 -0
  80. package/dist/execute/types.d.ts +65 -0
  81. package/dist/execute/types.d.ts.map +1 -0
  82. package/dist/index.d.ts +6 -0
  83. package/dist/index.d.ts.map +1 -0
  84. package/dist/lib/get-next-available.d.ts +2 -0
  85. package/dist/lib/get-next-available.d.ts.map +1 -0
  86. package/dist/lib/utils.d.ts +3 -0
  87. package/dist/lib/utils.d.ts.map +1 -0
  88. package/dist/main.d.ts +2 -0
  89. package/dist/main.d.ts.map +1 -0
  90. package/dist/query-builder/tari-type.d.ts +29 -0
  91. package/dist/query-builder/tari-type.d.ts.map +1 -0
  92. package/dist/query-builder/template-reader.d.ts +13 -0
  93. package/dist/query-builder/template-reader.d.ts.map +1 -0
  94. package/dist/store/persistence/handlers.d.ts +12 -0
  95. package/dist/store/persistence/handlers.d.ts.map +1 -0
  96. package/dist/store/persistence/types.d.ts +18 -0
  97. package/dist/store/persistence/types.d.ts.map +1 -0
  98. package/dist/store/persistence/v1_0.d.ts +5 -0
  99. package/dist/store/persistence/v1_0.d.ts.map +1 -0
  100. package/dist/store/store.d.ts +4 -0
  101. package/dist/store/store.d.ts.map +1 -0
  102. package/dist/store/types.d.ts +97 -0
  103. package/dist/store/types.d.ts.map +1 -0
  104. package/dist/tari-extension-query-builder.css +1 -0
  105. package/dist/tari-extension-query-builder.es.js +183368 -0
  106. package/dist/tari-extension-query-builder.umd.js +620 -0
  107. package/dist/types.d.ts +7 -0
  108. package/dist/types.d.ts.map +1 -0
  109. package/eslint.config.js +34 -0
  110. package/index.html +12 -0
  111. package/moon.yml +43 -0
  112. package/package.json +84 -0
  113. package/src/App.tsx +114 -0
  114. package/src/assets/react.svg +1 -0
  115. package/src/codegen/BuilderCodegen.ts +516 -0
  116. package/src/codegen/sample.ts +58 -0
  117. package/src/components/query-builder/edges/button-edge.tsx +50 -0
  118. package/src/components/query-builder/input/call-input-checkbox.tsx +54 -0
  119. package/src/components/query-builder/input/call-input-select.tsx +87 -0
  120. package/src/components/query-builder/input/call-input-text.tsx +98 -0
  121. package/src/components/query-builder/input/call-input.tsx +51 -0
  122. package/src/components/query-builder/nodes/call-node.types.ts +3 -0
  123. package/src/components/query-builder/nodes/constants.ts +4 -0
  124. package/src/components/query-builder/nodes/enter-connection.tsx +16 -0
  125. package/src/components/query-builder/nodes/exit-connection.tsx +16 -0
  126. package/src/components/query-builder/nodes/generic/generic-node.tsx +252 -0
  127. package/src/components/query-builder/nodes/generic/node-icon.tsx +37 -0
  128. package/src/components/query-builder/nodes/generic-node.types.ts +5 -0
  129. package/src/components/query-builder/nodes/input/constants.ts +1 -0
  130. package/src/components/query-builder/nodes/input/editable-label.tsx +142 -0
  131. package/src/components/query-builder/nodes/input/input-params-node.tsx +190 -0
  132. package/src/components/query-builder/query-builder.tsx +577 -0
  133. package/src/components/ui/alert-dialog.tsx +111 -0
  134. package/src/components/ui/badge.tsx +37 -0
  135. package/src/components/ui/button.tsx +50 -0
  136. package/src/components/ui/checkbox.tsx +27 -0
  137. package/src/components/ui/dropdown-menu.tsx +217 -0
  138. package/src/components/ui/input.tsx +21 -0
  139. package/src/components/ui/label.tsx +19 -0
  140. package/src/components/ui/loading-spinner.tsx +46 -0
  141. package/src/components/ui/popover.tsx +40 -0
  142. package/src/components/ui/select.tsx +158 -0
  143. package/src/components/ui/separator.tsx +26 -0
  144. package/src/components/ui/sonner.tsx +23 -0
  145. package/src/components/ui/textarea.tsx +18 -0
  146. package/src/components/ui/tooltip.tsx +46 -0
  147. package/src/execute/AmbiguousOrderError.ts +13 -0
  148. package/src/execute/CycleDetectedError.ts +7 -0
  149. package/src/execute/ExecutionPlanner.spec.ts +174 -0
  150. package/src/execute/ExecutionPlanner.ts +445 -0
  151. package/src/execute/MissingDataError.ts +10 -0
  152. package/src/execute/types.ts +87 -0
  153. package/src/index.css +124 -0
  154. package/src/index.ts +5 -0
  155. package/src/lib/get-next-available.ts +12 -0
  156. package/src/lib/utils.ts +6 -0
  157. package/src/main.tsx +13 -0
  158. package/src/query-builder/tari-type.ts +185 -0
  159. package/src/query-builder/template-reader.ts +69 -0
  160. package/src/root.css +4 -0
  161. package/src/store/persistence/handlers.ts +16 -0
  162. package/src/store/persistence/types.ts +14 -0
  163. package/src/store/persistence/v1_0.ts +35 -0
  164. package/src/store/store.ts +396 -0
  165. package/src/store/types.ts +115 -0
  166. package/src/stories/data/tari-swap-pool.json +317 -0
  167. package/src/stories/data/wallet-functions.json +580 -0
  168. package/src/types.ts +7 -0
  169. package/src/vite-env.d.ts +1 -0
  170. package/src/xy-theme.css +144 -0
  171. package/tsconfig.app.json +31 -0
  172. package/tsconfig.json +15 -0
  173. package/tsconfig.lib.json +13 -0
  174. package/tsconfig.node.json +24 -0
  175. package/vite.config.ts +35 -0
@@ -0,0 +1,87 @@
1
+ import CallInput, { CallInputProps } from "./call-input";
2
+ import { useState } from "react";
3
+ import { SafeParseReturnType } from "zod";
4
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
5
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
6
+ import { cn } from "@/lib/utils";
7
+ import { EditableLabelProps } from "../nodes/input/editable-label";
8
+
9
+ type CallInputSelectProps = {
10
+ readOnly?: boolean;
11
+ choices: string[];
12
+ hasIncomingConnection?: boolean;
13
+ validate?: (data: string) => SafeParseReturnType<unknown, unknown>;
14
+ value?: SafeParseReturnType<unknown, unknown>;
15
+ onChange?: (value: SafeParseReturnType<unknown, unknown>) => void;
16
+ } & Omit<CallInputProps, "children"> &
17
+ Omit<EditableLabelProps, "initialLabel">;
18
+
19
+ function CallInputSelect({
20
+ readOnly = false,
21
+ name,
22
+ label,
23
+ labelWidth,
24
+ choices,
25
+ hasIncomingConnection,
26
+ validate,
27
+ value,
28
+ onChange,
29
+ isValidLabel,
30
+ onLabelChange,
31
+ onRemove,
32
+ }: CallInputSelectProps) {
33
+ const [selectedValue, setSelectedValue] = useState(value?.success ? (value.data as string) : "");
34
+ const errorMessage = !value?.success ? value?.error.errors[0].message : undefined;
35
+ const isValid = !!hasIncomingConnection || (!errorMessage && selectedValue.length);
36
+
37
+ const handleChange = (value: string) => {
38
+ setSelectedValue(value);
39
+ if (validate && onChange) {
40
+ const result = validate(value);
41
+ onChange(result);
42
+ }
43
+ };
44
+
45
+ return (
46
+ <CallInput
47
+ name={name}
48
+ label={label}
49
+ labelWidth={labelWidth}
50
+ invalid={!isValid}
51
+ isValidLabel={isValidLabel}
52
+ onLabelChange={onLabelChange}
53
+ onRemove={onRemove}
54
+ >
55
+ <TooltipProvider>
56
+ <Tooltip open={!!errorMessage}>
57
+ <TooltipTrigger asChild>
58
+ <Select disabled={readOnly} name={name} value={selectedValue} onValueChange={handleChange}>
59
+ <SelectTrigger
60
+ className={cn(
61
+ "nodrag w-full border",
62
+ errorMessage
63
+ ? "border-red-500 focus:border-red-500 focus:ring-red-500 !ring-red-500"
64
+ : "border-gray-400 dark:border-gray-700",
65
+ )}
66
+ >
67
+ <SelectValue />
68
+ </SelectTrigger>
69
+ <SelectContent>
70
+ {choices.map((choice) => (
71
+ <SelectItem key={choice} value={choice}>
72
+ {choice}
73
+ </SelectItem>
74
+ ))}
75
+ </SelectContent>
76
+ </Select>
77
+ </TooltipTrigger>
78
+ <TooltipContent side="right" align="start" className="bg-red-500 text-white ml-5 p-2 rounded-md shadow-lg">
79
+ {errorMessage}
80
+ </TooltipContent>
81
+ </Tooltip>
82
+ </TooltipProvider>
83
+ </CallInput>
84
+ );
85
+ }
86
+
87
+ export default CallInputSelect;
@@ -0,0 +1,98 @@
1
+ import { Input } from "@/components/ui/input";
2
+ import CallInput, { CallInputProps } from "./call-input";
3
+ import { ChangeEvent, HTMLInputTypeAttribute, SyntheticEvent, useState } from "react";
4
+ import { SafeParseReturnType } from "zod";
5
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@radix-ui/react-tooltip";
6
+ import { cn } from "@/lib/utils";
7
+ import { EditableLabelProps } from "../nodes/input/editable-label";
8
+
9
+ type CallInputTextProps = {
10
+ readOnly?: boolean;
11
+ type?: HTMLInputTypeAttribute;
12
+ placeHolder?: string;
13
+ min?: string;
14
+ max?: string;
15
+ hasIncomingConnection?: boolean;
16
+ validate?: (data: string) => SafeParseReturnType<unknown, unknown>;
17
+ value?: SafeParseReturnType<unknown, unknown>;
18
+ onChange?: (value: SafeParseReturnType<unknown, unknown>) => void;
19
+ } & Omit<CallInputProps, "children"> &
20
+ Omit<EditableLabelProps, "initialLabel">;
21
+
22
+ function CallInputText({
23
+ readOnly = false,
24
+ name,
25
+ label,
26
+ labelWidth,
27
+ placeHolder,
28
+ type,
29
+ min,
30
+ max,
31
+ hasIncomingConnection,
32
+ validate,
33
+ value,
34
+ onChange,
35
+ rowHeight,
36
+ isValidLabel,
37
+ onLabelChange,
38
+ onRemove,
39
+ }: CallInputTextProps) {
40
+ const [text, setText] = useState(value?.success ? String(value.data) : "");
41
+ const errorMessage = !value?.success ? value?.error.errors[0].message : undefined;
42
+ const isValid = !!hasIncomingConnection || (!errorMessage && text.length);
43
+
44
+ const handleOnInput = (event: SyntheticEvent<HTMLInputElement>) => {
45
+ const inputElement = event.target as HTMLInputElement;
46
+ setText(inputElement.value);
47
+ };
48
+
49
+ const handleOnChange = (event: ChangeEvent<HTMLInputElement>) => {
50
+ if (validate && onChange) {
51
+ const result = validate(event.target.value);
52
+ onChange(result);
53
+ }
54
+ };
55
+
56
+ return (
57
+ <CallInput
58
+ name={name}
59
+ label={label}
60
+ labelWidth={labelWidth}
61
+ rowHeight={rowHeight}
62
+ invalid={!isValid}
63
+ isValidLabel={isValidLabel}
64
+ onLabelChange={onLabelChange}
65
+ onRemove={onRemove}
66
+ >
67
+ <TooltipProvider>
68
+ <Tooltip open={!!errorMessage}>
69
+ <TooltipTrigger asChild>
70
+ <Input
71
+ readOnly={readOnly}
72
+ name={name}
73
+ type={type}
74
+ autoComplete="off"
75
+ placeholder={placeHolder}
76
+ className={cn(
77
+ "nodrag border",
78
+ errorMessage
79
+ ? "border-red-500 focus:border-red-500 focus:ring-red-500 !ring-red-500"
80
+ : "border-gray-400 dark:border-gray-700",
81
+ )}
82
+ min={min}
83
+ max={max}
84
+ value={text}
85
+ onInput={handleOnInput}
86
+ onChange={handleOnChange}
87
+ />
88
+ </TooltipTrigger>
89
+ <TooltipContent side="right" align="start" className="bg-red-500 text-white ml-5 p-2 rounded-md shadow-lg">
90
+ {errorMessage}
91
+ </TooltipContent>
92
+ </Tooltip>
93
+ </TooltipProvider>
94
+ </CallInput>
95
+ );
96
+ }
97
+
98
+ export default CallInputText;
@@ -0,0 +1,51 @@
1
+ import { Label } from "@/components/ui/label";
2
+ import { DotIcon } from "@radix-ui/react-icons";
3
+ import EditableLabel, { EditableLabelProps } from "../nodes/input/editable-label";
4
+
5
+ export type CallInputProps = {
6
+ name: string;
7
+ label?: string;
8
+ labelWidth?: string;
9
+ labelEditable?: boolean;
10
+ rowHeight?: string;
11
+ invalid?: boolean;
12
+ children: React.ReactNode;
13
+ } & Omit<EditableLabelProps, "initialLabel">;
14
+
15
+ function CallInput({
16
+ name,
17
+ label,
18
+ labelWidth = "160px",
19
+ rowHeight = "36px",
20
+ invalid,
21
+ children,
22
+ isValidLabel,
23
+ onLabelChange,
24
+ onRemove,
25
+ }: CallInputProps) {
26
+ return (
27
+ <div className="flex items-center mt-1" style={{ height: rowHeight }}>
28
+ {name && (
29
+ <Label
30
+ htmlFor={name}
31
+ style={{
32
+ display: "inline-block",
33
+ textAlign: "right",
34
+ width: labelWidth,
35
+ }}
36
+ >
37
+ <DotIcon className={`inline-block mr-1 text-red-500 ${invalid ? "opacity-100" : "opacity-0"}`} />
38
+ <EditableLabel
39
+ initialLabel={label ?? name}
40
+ isValidLabel={isValidLabel}
41
+ onLabelChange={onLabelChange}
42
+ onRemove={onRemove}
43
+ />
44
+ </Label>
45
+ )}
46
+ <div className={name ? "ml-2 w-[64ch]" : "w-full"}>{children}</div>
47
+ </div>
48
+ );
49
+ }
50
+
51
+ export default CallInput;
@@ -0,0 +1,3 @@
1
+ export const CALL_NODE_RETURN = "__CALL_NODE_RETURN__";
2
+ export const CALL_NODE_RETURN_TUPLE_1 = "__CALL_NODE_RETURN_TUPLE_1__";
3
+ export const CALL_NODE_RETURN_TUPLE_2 = "__CALL_NODE_RETURN_TUPLE_2__";
@@ -0,0 +1,4 @@
1
+ export const ROW_PADDING = 4;
2
+ export const ROW_HEIGHT = 36;
3
+ export const OUTPUT_HEIGHT = 28;
4
+ export const ROW_HEIGHT_PX = `${ROW_HEIGHT.toString()}px`;
@@ -0,0 +1,16 @@
1
+ import { Handle, Position } from "@xyflow/react";
2
+ import { NODE_ENTRY } from "./generic-node.types";
3
+
4
+ function EnterConnection() {
5
+ return (
6
+ <Handle
7
+ id={NODE_ENTRY}
8
+ type="target"
9
+ position={Position.Left}
10
+ className="enter-connection"
11
+ style={{ top: "20px" }}
12
+ />
13
+ );
14
+ }
15
+
16
+ export default EnterConnection;
@@ -0,0 +1,16 @@
1
+ import { Handle, Position } from "@xyflow/react";
2
+ import { NODE_EXIT } from "./generic-node.types";
3
+
4
+ function ExitConnection() {
5
+ return (
6
+ <Handle
7
+ id={NODE_EXIT}
8
+ type="source"
9
+ position={Position.Right}
10
+ className="exit-connection"
11
+ style={{ top: "20px" }}
12
+ />
13
+ );
14
+ }
15
+
16
+ export default ExitConnection;
@@ -0,0 +1,252 @@
1
+ import { Handle, NodeProps, Position } from "@xyflow/react";
2
+ import { TrashIcon } from "@radix-ui/react-icons";
3
+ import { Button } from "@/components/ui/button";
4
+ import useStore from "@/store/store";
5
+ import { InputConnectionType, NodeType, type GenericNode } from "@/store/types";
6
+ import ExitConnection from "../exit-connection";
7
+ import EnterConnection from "../enter-connection";
8
+ import NodeIcon from "./node-icon";
9
+ import { Badge } from "@/components/ui/badge";
10
+ import { InputControlType, TariType } from "@/query-builder/tari-type";
11
+ import CallInputText from "../../input/call-input-text";
12
+ import { OUTPUT_HEIGHT, ROW_HEIGHT, ROW_HEIGHT_PX, ROW_PADDING } from "../constants";
13
+ import CallInputCheckbox from "../../input/call-input-checkbox";
14
+ import { Separator } from "@/components/ui/separator";
15
+ import { CALL_NODE_RETURN, CALL_NODE_RETURN_TUPLE_1, CALL_NODE_RETURN_TUPLE_2 } from "../call-node.types";
16
+ import { useCallback } from "react";
17
+ import { SafeParseReturnType, z } from "zod";
18
+ import CallInputSelect from "../../input/call-input-select";
19
+ import { Label } from "@/components/ui/label";
20
+
21
+ const HANDLE_STARTING_OFFSET = 68;
22
+ const FULL_ROW_HEIGHT = ROW_HEIGHT + ROW_PADDING;
23
+
24
+ function GenericNode(props: NodeProps<GenericNode>) {
25
+ const { id, data } = props;
26
+ const { hasEnterConnection, hasExitConnection, icon, badge, title, largeCaption, inputs, output } = data;
27
+
28
+ const removeNode = useStore((store) => store.removeNode);
29
+ const readOnly = useStore((store) => store.readOnly);
30
+ const getNodeById = useStore((store) => store.getNodeById);
31
+ const updateNodeArgValue = useStore((store) => store.updateNodeArgValue);
32
+ const edges = useStore((store) => store.edges);
33
+
34
+ const outputType = output ? new TariType(output.type) : undefined;
35
+
36
+ const getOutputOffset = (idx = 0) => {
37
+ const offset = HANDLE_STARTING_OFFSET + FULL_ROW_HEIGHT * (inputs ? inputs.length : 0) + 25 + idx * OUTPUT_HEIGHT;
38
+ return `${offset.toString()}px`;
39
+ };
40
+
41
+ const getNodeValue = useCallback(
42
+ (name: string) => {
43
+ const node = getNodeById(id);
44
+ if (!node || node.type !== NodeType.GenericNode || !node.data.values) {
45
+ return undefined;
46
+ }
47
+ return node.data.values[name];
48
+ },
49
+ [id, getNodeById],
50
+ );
51
+ const hasConnection = useCallback(
52
+ (handle: string) => edges.some((edge) => edge.target === id && edge.targetHandle === handle),
53
+ [id, edges],
54
+ );
55
+
56
+ const handleOnChange = (argName: string, value: SafeParseReturnType<unknown, unknown>) => {
57
+ updateNodeArgValue(id, argName, value);
58
+ };
59
+
60
+ return (
61
+ <>
62
+ {hasEnterConnection && <EnterConnection />}
63
+ {hasExitConnection && <ExitConnection />}
64
+ {(!!icon || !!badge) && (
65
+ <div className="absolute top-3 left-3 flex items-center">
66
+ {icon && <NodeIcon icon={icon} className="h-5 w-5 mr-1" />}
67
+ {badge && <Badge>{badge}</Badge>}
68
+ </div>
69
+ )}
70
+ <div className="absolute top-1 right-2 nodrag nopan">
71
+ <Button
72
+ variant="ghost"
73
+ size="icon"
74
+ onClick={() => {
75
+ removeNode(id);
76
+ }}
77
+ >
78
+ <TrashIcon className="h-4 w-4" />
79
+ </Button>
80
+ </div>
81
+
82
+ {largeCaption && <Label className="text-4xl font-bold p-8 font-stretch-expanded">{largeCaption}</Label>}
83
+
84
+ {inputs?.map((input, idx) => {
85
+ switch (input.inputConnectionType) {
86
+ case InputConnectionType.Parameter:
87
+ return (
88
+ <Handle
89
+ key={input.name}
90
+ id={input.name}
91
+ type="target"
92
+ position={Position.Left}
93
+ style={{
94
+ border: "2px solid green",
95
+ top: `${(HANDLE_STARTING_OFFSET + idx * FULL_ROW_HEIGHT).toString()}px`,
96
+ }}
97
+ />
98
+ );
99
+ case InputConnectionType.ComponentAddress:
100
+ return (
101
+ <Handle
102
+ key={input.name}
103
+ id={input.name}
104
+ type="target"
105
+ position={Position.Left}
106
+ style={{
107
+ border: "2px solid orange",
108
+ top: `${(HANDLE_STARTING_OFFSET + idx * FULL_ROW_HEIGHT).toString()}px`,
109
+ }}
110
+ />
111
+ );
112
+ }
113
+ })}
114
+
115
+ {title && <h3 className="text-center font-bold pt-1 pb-3 border-b">{title}</h3>}
116
+
117
+ {inputs && (
118
+ <form noValidate>
119
+ {inputs.map((input) => {
120
+ const type = new TariType(input.type);
121
+ switch (type.getInputControlType()) {
122
+ case InputControlType.TextBoxInput: {
123
+ return input.validValues ? (
124
+ <CallInputSelect
125
+ readOnly={readOnly}
126
+ key={input.name}
127
+ name={input.name}
128
+ label={input.label}
129
+ choices={[...input.validValues]}
130
+ validate={(data) => {
131
+ const validValues = input.validValues;
132
+ if (!validValues) {
133
+ return {
134
+ success: true,
135
+ data: undefined,
136
+ };
137
+ }
138
+ return z
139
+ .string()
140
+ .refine((val) => validValues.includes(val), {
141
+ message: `Invalid value. Must be one of: ${validValues.join(", ")}`,
142
+ })
143
+ .safeParse(data);
144
+ }}
145
+ value={getNodeValue(input.name)}
146
+ onChange={(value) => {
147
+ handleOnChange(input.name, value);
148
+ }}
149
+ rowHeight={ROW_HEIGHT_PX}
150
+ />
151
+ ) : (
152
+ <CallInputText
153
+ readOnly={readOnly}
154
+ key={input.name}
155
+ name={input.name}
156
+ label={input.label}
157
+ placeHolder={type.prompt}
158
+ type={type.inputType}
159
+ min={type.min?.toString()}
160
+ max={type.max?.toString()}
161
+ hasIncomingConnection={hasConnection(input.name)}
162
+ validate={(data) => type.validate(data)}
163
+ value={getNodeValue(input.name)}
164
+ onChange={(value) => {
165
+ handleOnChange(input.name, value);
166
+ }}
167
+ rowHeight={ROW_HEIGHT_PX}
168
+ />
169
+ );
170
+ }
171
+ case InputControlType.CheckBoxInput:
172
+ return (
173
+ <CallInputCheckbox
174
+ readOnly={readOnly}
175
+ key={input.name}
176
+ name={input.name}
177
+ label={input.label}
178
+ value={getNodeValue(input.name)}
179
+ onChange={(value) => {
180
+ handleOnChange(input.name, value);
181
+ }}
182
+ rowHeight={ROW_HEIGHT_PX}
183
+ />
184
+ );
185
+ }
186
+ })}
187
+ </form>
188
+ )}
189
+
190
+ {outputType && renderOutputs(outputType, getOutputOffset)}
191
+ </>
192
+ );
193
+ }
194
+
195
+ function renderOutputPrompt(outputType: TariType) {
196
+ return (
197
+ <div className="flex justify-end w-full">
198
+ <span className="font-semibold text-lg pr-2">{outputType.prompt}</span>
199
+ </div>
200
+ );
201
+ }
202
+
203
+ function renderOutputs(outputType: TariType, getOutputOffset: (idx: number) => string) {
204
+ const [tuple1, tuple2] = outputType.getTupleDetails();
205
+ return (
206
+ <>
207
+ <Separator className="my-4 h-px w-full bg-gray-300 dark:bg-gray-600" />
208
+ {renderOutputPrompt(outputType)}
209
+ {!outputType.isVoid() && (
210
+ <Handle
211
+ id={CALL_NODE_RETURN}
212
+ type="source"
213
+ position={Position.Right}
214
+ style={{
215
+ border: "2px solid #608bb9",
216
+ top: getOutputOffset(0),
217
+ }}
218
+ />
219
+ )}
220
+ {tuple1 && (
221
+ <>
222
+ {renderOutputPrompt(tuple1)}
223
+ <Handle
224
+ id={CALL_NODE_RETURN_TUPLE_1}
225
+ type="source"
226
+ position={Position.Right}
227
+ style={{
228
+ border: "2px solid #49698c",
229
+ top: getOutputOffset(1),
230
+ }}
231
+ />
232
+ </>
233
+ )}
234
+ {tuple2 && (
235
+ <>
236
+ {renderOutputPrompt(tuple2)}
237
+ <Handle
238
+ id={CALL_NODE_RETURN_TUPLE_2}
239
+ type="source"
240
+ position={Position.Right}
241
+ style={{
242
+ border: "2px solid #49698c",
243
+ top: getOutputOffset(2),
244
+ }}
245
+ />
246
+ </>
247
+ )}
248
+ </>
249
+ );
250
+ }
251
+
252
+ export default GenericNode;
@@ -0,0 +1,37 @@
1
+ import { GenericNodeIcon } from "@/store/types";
2
+ import {
3
+ ArchiveIcon,
4
+ CheckCircledIcon,
5
+ Component1Icon,
6
+ CubeIcon,
7
+ EnterIcon,
8
+ HomeIcon,
9
+ RocketIcon,
10
+ } from "@radix-ui/react-icons";
11
+
12
+ interface NodeIconProps {
13
+ icon: GenericNodeIcon;
14
+ className: string;
15
+ }
16
+
17
+ function NodeIcon(props: NodeIconProps) {
18
+ const { icon, className } = props;
19
+ switch (icon) {
20
+ case "enter":
21
+ return <EnterIcon className={className} />;
22
+ case "rocket":
23
+ return <RocketIcon className={className} />;
24
+ case "home":
25
+ return <HomeIcon className={className} />;
26
+ case "cube":
27
+ return <CubeIcon className={className} />;
28
+ case "check-circled":
29
+ return <CheckCircledIcon className={className} />;
30
+ case "archive":
31
+ return <ArchiveIcon className={className} />;
32
+ case "component":
33
+ return <Component1Icon className={className} />;
34
+ }
35
+ }
36
+
37
+ export default NodeIcon;
@@ -0,0 +1,5 @@
1
+ export const NODE_ENTRY = "__NODE_ENTRY__";
2
+ export const NODE_EXIT = "__NODE_EXIT__";
3
+ export const COMPONENT_ADDRESS_ENTRY = "__COMPONENT_ADDRESS_ENTRY__";
4
+ export const ALLOCATE_COMPONENT_ADDRESS_RESULT = "__ALLOCATE_COMPONENT_ADDRESS_RESULT__";
5
+ export const ALLOCATE_RESOURCE_ADDRESS_RESULT = "__ALLOCATE_RESOURCE_ADDRESS_RESULT__";
@@ -0,0 +1 @@
1
+ export const NEW_INPUT_PARAM = "__NEW_INPUT_PARAM__";