Skip to content

Commit 4e9ec90

Browse files
committed
feat(web): add NodeDocsDialog for worflow node docs
1 parent c9afa9e commit 4e9ec90

3 files changed

Lines changed: 245 additions & 186 deletions

File tree

apps/web/src/components/docs/node-card.tsx

Lines changed: 5 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -4,199 +4,18 @@ import { DynamicIcon } from "lucide-react/dynamic.mjs";
44
import { useState } from "react";
55

66
import { Badge } from "@/components/ui/badge";
7-
import { Button } from "@/components/ui/button";
87
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
9-
import {
10-
Dialog,
11-
DialogContent,
12-
DialogDescription,
13-
DialogHeader,
14-
DialogTitle,
15-
} from "@/components/ui/dialog";
16-
import { Separator } from "@/components/ui/separator";
178
import { NodeTags } from "@/components/workflow/node-tags";
189
import { getTagColor } from "@/utils/tag-colors";
1910

11+
import { NodeDocsDialog } from "./node-docs-dialog";
12+
2013
interface NodeCardProps {
2114
nodeType: NodeType;
2215
variant?: "card" | "list";
2316
}
2417

25-
interface NodeDetailsDialogProps {
26-
nodeType: NodeType;
27-
isOpen: boolean;
28-
onOpenChange: (open: boolean) => void;
29-
}
30-
31-
function NodeDetailsDialog({
32-
nodeType,
33-
isOpen,
34-
onOpenChange,
35-
}: NodeDetailsDialogProps) {
36-
return (
37-
<Dialog open={isOpen} onOpenChange={onOpenChange}>
38-
<DialogContent className="max-w-2xl max-h-[80vh] flex flex-col gap-0">
39-
<DialogHeader className="shrink-0">
40-
<DialogTitle className="flex items-center gap-3">
41-
<div className="flex-1">
42-
<div className="flex items-center gap-2">
43-
{nodeType.name}
44-
<NodeTags
45-
tags={nodeType.tags}
46-
functionCalling={nodeType.functionCalling}
47-
/>
48-
</div>
49-
</div>
50-
</DialogTitle>
51-
{nodeType.description && (
52-
<DialogDescription className="text-base">
53-
{nodeType.description}
54-
</DialogDescription>
55-
)}
56-
</DialogHeader>
57-
58-
<div className="flex-1 overflow-y-auto px-1 -mx-1">
59-
<div className="space-y-6 py-4">
60-
{/* Basic Information */}
61-
<div className="space-y-3">
62-
<h4 className="text-sm font-semibold">Basic Information</h4>
63-
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm">
64-
<div>
65-
<span className="font-medium text-muted-foreground">
66-
Type ID:
67-
</span>
68-
<p className="font-mono text-xs bg-muted px-2 py-1 rounded mt-1">
69-
{nodeType.type}
70-
</p>
71-
</div>
72-
<div>
73-
<span className="font-medium text-muted-foreground">
74-
Unique ID:
75-
</span>
76-
<p className="font-mono text-xs bg-muted px-2 py-1 rounded mt-1">
77-
{nodeType.id}
78-
</p>
79-
</div>
80-
</div>
81-
</div>
82-
83-
{/* Compatibility */}
84-
{nodeType.compatibility && nodeType.compatibility.length > 0 && (
85-
<>
86-
<Separator />
87-
<div className="space-y-3">
88-
<h4 className="text-sm font-semibold">
89-
Workflow Compatibility
90-
</h4>
91-
<div className="flex flex-wrap gap-2">
92-
{nodeType.compatibility.map((type) => (
93-
<Badge key={type} variant="outline" className="text-xs">
94-
{type.replace("_", " ")}
95-
</Badge>
96-
))}
97-
</div>
98-
</div>
99-
</>
100-
)}
101-
102-
{/* Parameters List */}
103-
{((nodeType.inputs && nodeType.inputs.length > 0) ||
104-
(nodeType.outputs && nodeType.outputs.length > 0)) && (
105-
<>
106-
<Separator />
107-
<div className="space-y-4">
108-
<h4 className="text-sm font-semibold">Parameters</h4>
109-
110-
{/* Inputs */}
111-
{nodeType.inputs && nodeType.inputs.length > 0 && (
112-
<div className="space-y-2">
113-
<h5 className="text-xs font-medium text-muted-foreground uppercase tracking-wide">
114-
Inputs ({nodeType.inputs.length})
115-
</h5>
116-
<div className="space-y-2">
117-
{nodeType.inputs.map((input, index) => (
118-
<div
119-
key={index}
120-
className="flex items-start gap-3 p-2 rounded border bg-blue-50/30 dark:bg-blue-950/10"
121-
>
122-
<div className="w-2 h-2 rounded-full bg-blue-500 mt-1.5 shrink-0"></div>
123-
<div className="flex-1 min-w-0">
124-
<div className="flex items-center gap-2 flex-wrap">
125-
<span className="font-medium text-sm">
126-
{input.name}
127-
</span>
128-
<Badge variant="outline" className="text-xs">
129-
{input.type}
130-
</Badge>
131-
{input.required && (
132-
<Badge
133-
variant="destructive"
134-
className="text-xs"
135-
>
136-
Required
137-
</Badge>
138-
)}
139-
</div>
140-
{input.description && (
141-
<p className="text-xs text-muted-foreground mt-1">
142-
{input.description}
143-
</p>
144-
)}
145-
</div>
146-
</div>
147-
))}
148-
</div>
149-
</div>
150-
)}
151-
152-
{/* Outputs */}
153-
{nodeType.outputs && nodeType.outputs.length > 0 && (
154-
<div className="space-y-2">
155-
<h5 className="text-xs font-medium text-muted-foreground uppercase tracking-wide">
156-
Outputs ({nodeType.outputs.length})
157-
</h5>
158-
<div className="space-y-2">
159-
{nodeType.outputs.map((output, index) => (
160-
<div
161-
key={index}
162-
className="flex items-start gap-3 p-2 rounded border bg-green-50/30 dark:bg-green-950/10"
163-
>
164-
<div className="w-2 h-2 rounded-full bg-green-500 mt-1.5 shrink-0"></div>
165-
<div className="flex-1 min-w-0">
166-
<div className="flex items-center gap-2 flex-wrap">
167-
<span className="font-medium text-sm">
168-
{output.name}
169-
</span>
170-
<Badge variant="outline" className="text-xs">
171-
{output.type}
172-
</Badge>
173-
</div>
174-
{output.description && (
175-
<p className="text-xs text-muted-foreground mt-1">
176-
{output.description}
177-
</p>
178-
)}
179-
</div>
180-
</div>
181-
))}
182-
</div>
183-
</div>
184-
)}
185-
</div>
186-
</>
187-
)}
188-
</div>
189-
</div>
190-
191-
<div className="flex justify-end gap-2 pt-4 border-t shrink-0">
192-
<Button variant="outline" onClick={() => onOpenChange(false)}>
193-
Close
194-
</Button>
195-
</div>
196-
</DialogContent>
197-
</Dialog>
198-
);
199-
}
18+
// Dialog moved to reusable component
20019

20120
export function NodeCard({ nodeType, variant = "card" }: NodeCardProps) {
20221
const [isDialogOpen, setIsDialogOpen] = useState(false);
@@ -253,7 +72,7 @@ export function NodeCard({ nodeType, variant = "card" }: NodeCardProps) {
25372
</CardContent>
25473
</Card>
25574

256-
<NodeDetailsDialog
75+
<NodeDocsDialog
25776
nodeType={nodeType}
25877
isOpen={isDialogOpen}
25978
onOpenChange={setIsDialogOpen}
@@ -304,7 +123,7 @@ export function NodeCard({ nodeType, variant = "card" }: NodeCardProps) {
304123
</CardContent>
305124
</Card>
306125

307-
<NodeDetailsDialog
126+
<NodeDocsDialog
308127
nodeType={nodeType}
309128
isOpen={isDialogOpen}
310129
onOpenChange={setIsDialogOpen}

0 commit comments

Comments
 (0)