Skip to content

Commit e1d4ebe

Browse files
bchapuisclaude
andcommitted
Replace database and queue widgets with enhanced field components
Move inline creation dialogs into DatabaseField and QueueField, removing the dedicated widget wrappers and their helper dialogs. The field system already renders these resource types on the node canvas, so the widgets were unnecessary indirection. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 1488592 commit e1d4ebe

10 files changed

Lines changed: 206 additions & 604 deletions

File tree

apps/app/src/components/workflow/fields/database-field.tsx

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,60 @@
1+
import { useState } from "react";
2+
3+
import { useAuth } from "@/components/auth-context";
4+
import { Button } from "@/components/ui/button";
5+
import {
6+
Dialog,
7+
DialogContent,
8+
DialogFooter,
9+
DialogHeader,
10+
DialogTitle,
11+
} from "@/components/ui/dialog";
12+
import { Input } from "@/components/ui/input";
13+
import { Label } from "@/components/ui/label";
114
import {
215
Select,
316
SelectContent,
417
SelectItem,
18+
SelectSeparator,
519
SelectTrigger,
620
SelectValue,
721
} from "@/components/ui/select";
8-
import { useDatabases } from "@/services/database-service";
22+
import { createDatabase, useDatabases } from "@/services/database-service";
923
import { cn } from "@/utils/utils";
1024

1125
import type { FieldProps } from "./types";
1226

27+
const CREATE_NEW = "__create_new__";
28+
1329
export function DatabaseField({
1430
className,
1531
connected,
1632
disabled,
1733
onChange,
1834
value,
1935
}: FieldProps) {
20-
const { databases, isDatabasesLoading } = useDatabases();
36+
const { databases, isDatabasesLoading, mutateDatabases } = useDatabases();
37+
const { organization } = useAuth();
38+
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
2139

2240
const stringValue = String(value ?? "");
2341

42+
const handleChange = (val: string) => {
43+
if (val === CREATE_NEW) {
44+
setIsCreateDialogOpen(true);
45+
return;
46+
}
47+
onChange(val || undefined);
48+
};
49+
50+
const handleCreate = async (name: string) => {
51+
if (!organization?.id) return;
52+
const response = await createDatabase({ name }, organization.id);
53+
await mutateDatabases();
54+
onChange(response.id);
55+
setIsCreateDialogOpen(false);
56+
};
57+
2458
if (disabled) {
2559
const label = databases?.find((d) => d.id === stringValue)?.name ?? "";
2660
return (
@@ -40,7 +74,7 @@ export function DatabaseField({
4074
<div className={cn("relative", className)}>
4175
<Select
4276
value={stringValue}
43-
onValueChange={(val) => onChange(val || undefined)}
77+
onValueChange={handleChange}
4478
disabled={isDatabasesLoading}
4579
>
4680
<SelectTrigger>
@@ -66,8 +100,49 @@ export function DatabaseField({
66100
{database.name}
67101
</SelectItem>
68102
))}
103+
<SelectSeparator />
104+
<SelectItem value={CREATE_NEW} className="text-xs">
105+
+ New Database
106+
</SelectItem>
69107
</SelectContent>
70108
</Select>
109+
110+
<Dialog open={isCreateDialogOpen} onOpenChange={setIsCreateDialogOpen}>
111+
<DialogContent>
112+
<DialogHeader>
113+
<DialogTitle>Create New Database</DialogTitle>
114+
</DialogHeader>
115+
<form
116+
onSubmit={async (e) => {
117+
e.preventDefault();
118+
const formData = new FormData(e.currentTarget);
119+
const name = formData.get("name") as string;
120+
await handleCreate(name);
121+
}}
122+
className="space-y-4"
123+
>
124+
<div>
125+
<Label htmlFor="name">Database Name</Label>
126+
<Input
127+
id="name"
128+
name="name"
129+
placeholder="Enter database name"
130+
className="mt-2"
131+
/>
132+
</div>
133+
<DialogFooter>
134+
<Button
135+
variant="outline"
136+
type="button"
137+
onClick={() => setIsCreateDialogOpen(false)}
138+
>
139+
Cancel
140+
</Button>
141+
<Button type="submit">Create Database</Button>
142+
</DialogFooter>
143+
</form>
144+
</DialogContent>
145+
</Dialog>
71146
</div>
72147
);
73148
}

apps/app/src/components/workflow/fields/queue-field.tsx

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,60 @@
1+
import { useState } from "react";
2+
3+
import { useAuth } from "@/components/auth-context";
4+
import { Button } from "@/components/ui/button";
5+
import {
6+
Dialog,
7+
DialogContent,
8+
DialogFooter,
9+
DialogHeader,
10+
DialogTitle,
11+
} from "@/components/ui/dialog";
12+
import { Input } from "@/components/ui/input";
13+
import { Label } from "@/components/ui/label";
114
import {
215
Select,
316
SelectContent,
417
SelectItem,
18+
SelectSeparator,
519
SelectTrigger,
620
SelectValue,
721
} from "@/components/ui/select";
8-
import { useQueues } from "@/services/queue-service";
22+
import { createQueue, useQueues } from "@/services/queue-service";
923
import { cn } from "@/utils/utils";
1024

1125
import type { FieldProps } from "./types";
1226

27+
const CREATE_NEW = "__create_new__";
28+
1329
export function QueueField({
1430
className,
1531
connected,
1632
disabled,
1733
onChange,
1834
value,
1935
}: FieldProps) {
20-
const { queues, isQueuesLoading } = useQueues();
36+
const { queues, isQueuesLoading, mutateQueues } = useQueues();
37+
const { organization } = useAuth();
38+
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
2139

2240
const stringValue = String(value ?? "");
2341

42+
const handleChange = (val: string) => {
43+
if (val === CREATE_NEW) {
44+
setIsCreateDialogOpen(true);
45+
return;
46+
}
47+
onChange(val || undefined);
48+
};
49+
50+
const handleCreate = async (name: string) => {
51+
if (!organization?.id) return;
52+
const response = await createQueue({ name }, organization.id);
53+
await mutateQueues();
54+
onChange(response.id);
55+
setIsCreateDialogOpen(false);
56+
};
57+
2458
if (disabled) {
2559
const label = queues?.find((q) => q.id === stringValue)?.name ?? "";
2660
return (
@@ -40,7 +74,7 @@ export function QueueField({
4074
<div className={cn("relative", className)}>
4175
<Select
4276
value={stringValue}
43-
onValueChange={(val) => onChange(val || undefined)}
77+
onValueChange={handleChange}
4478
disabled={isQueuesLoading}
4579
>
4680
<SelectTrigger>
@@ -62,8 +96,49 @@ export function QueueField({
6296
{queue.name}
6397
</SelectItem>
6498
))}
99+
<SelectSeparator />
100+
<SelectItem value={CREATE_NEW} className="text-xs">
101+
+ New Queue
102+
</SelectItem>
65103
</SelectContent>
66104
</Select>
105+
106+
<Dialog open={isCreateDialogOpen} onOpenChange={setIsCreateDialogOpen}>
107+
<DialogContent>
108+
<DialogHeader>
109+
<DialogTitle>Create New Queue</DialogTitle>
110+
</DialogHeader>
111+
<form
112+
onSubmit={async (e) => {
113+
e.preventDefault();
114+
const formData = new FormData(e.currentTarget);
115+
const name = formData.get("name") as string;
116+
await handleCreate(name);
117+
}}
118+
className="space-y-4"
119+
>
120+
<div>
121+
<Label htmlFor="name">Queue Name</Label>
122+
<Input
123+
id="name"
124+
name="name"
125+
placeholder="Enter queue name"
126+
className="mt-2"
127+
/>
128+
</div>
129+
<DialogFooter>
130+
<Button
131+
variant="outline"
132+
type="button"
133+
onClick={() => setIsCreateDialogOpen(false)}
134+
>
135+
Cancel
136+
</Button>
137+
<Button type="submit">Create Queue</Button>
138+
</DialogFooter>
139+
</form>
140+
</DialogContent>
141+
</Dialog>
67142
</div>
68143
);
69144
}

apps/app/src/components/workflow/widgets/index.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { blobInputWidget } from "./input/blob-input";
1212
import { booleanInputWidget } from "./input/boolean-input";
1313
import { canvasInputWidget } from "./input/canvas-input";
1414
import { cronInputWidget } from "./input/cron-input";
15-
import { databaseTriggerInputWidget } from "./input/database-trigger-input";
1615
import { dateInputWidget } from "./input/date-input";
1716
import { discordTriggerInputWidget } from "./input/discord-trigger-input";
1817
import { documentInputWidget } from "./input/document-input";
@@ -29,7 +28,6 @@ import { imageInputWidget } from "./input/image-input";
2928
import { javascriptInputWidget } from "./input/javascript-input";
3029
import { jsonInputWidget } from "./input/json-input";
3130
import { numberInputWidget } from "./input/number-input";
32-
import { queueTriggerInputWidget } from "./input/queue-trigger-input";
3331
import { replicateModelInputWidget } from "./input/replicate-model-input";
3432
import { schemaExtractInputWidget } from "./input/schema-extract-input";
3533
import { secretInputWidget } from "./input/secret-input";
@@ -78,8 +76,6 @@ const widgets = [
7876
emailTriggerInputWidget,
7977
httpRequestEndpointWidget,
8078
httpWebhookEndpointWidget,
81-
databaseTriggerInputWidget,
82-
queueTriggerInputWidget,
8379
telegramTriggerInputWidget,
8480
whatsappTriggerInputWidget,
8581
javascriptInputWidget,

apps/app/src/components/workflow/widgets/input/database-create-dialog.tsx

Lines changed: 0 additions & 120 deletions
This file was deleted.

0 commit comments

Comments
 (0)