Skip to content

Commit 38b133a

Browse files
committed
Edit server name
1 parent 28d4c0e commit 38b133a

3 files changed

Lines changed: 276 additions & 16 deletions

File tree

src/app/[serverId]/client.tsx

Lines changed: 115 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client"
22

3-
import { Plus, Plug } from "lucide-react"
3+
import { Plus, Plug, Edit } from "lucide-react"
44
import { z } from "zod"
55
import { zodResolver } from "@hookform/resolvers/zod"
66
import { useForm } from "react-hook-form"
@@ -255,8 +255,8 @@ export function ToolCard({
255255
)}
256256
</div>
257257
<div className="flex items-center gap-2">
258-
<Button variant="outline" onClick={onEdit}>
259-
Edit
258+
<Button variant="ghost" onClick={onEdit}>
259+
<Edit className="h-4 w-4" />
260260
</Button>
261261
<Button variant="destructive" onClick={() => deleteTool(tool.id)}>
262262
Delete
@@ -301,7 +301,7 @@ export function ToolCard({
301301
variant="ghost"
302302
onClick={() => setEditingParameter(parameter)}
303303
>
304-
Edit
304+
<Edit className="h-3 w-3" />
305305
</Button>
306306
<Button
307307
size="sm"
@@ -525,3 +525,114 @@ export function ConnectDialog({
525525
</Dialog>
526526
)
527527
}
528+
529+
type UpsertServerData = {
530+
id?: string
531+
name: string
532+
}
533+
534+
export function ServerHeader({
535+
server,
536+
}: {
537+
server: Database["public"]["Tables"]["servers"]["Row"]
538+
}) {
539+
const supabase = createClient()
540+
const router = useRouter()
541+
const [editingServer, setEditingServer] = useState<UpsertServerData>()
542+
543+
const handleUpsertServer = async (data: UpsertServerData) => {
544+
await supabase.from("servers").upsert({ ...data })
545+
router.refresh()
546+
setEditingServer(undefined)
547+
}
548+
549+
const handleRename = () => {
550+
setEditingServer({
551+
id: server.id,
552+
name: server.name,
553+
})
554+
}
555+
556+
return (
557+
<>
558+
{editingServer && (
559+
<ServerForm
560+
defaultValues={editingServer}
561+
onServerChange={(values) => {
562+
handleUpsertServer({ id: editingServer.id, ...values })
563+
}}
564+
onOpenChange={(open) => {
565+
if (!open) {
566+
setEditingServer(undefined)
567+
}
568+
}}
569+
/>
570+
)}
571+
572+
<div className="flex items-center gap-3">
573+
<h1 className="text-2xl font-bold grow">{server.name}</h1>
574+
<Button variant="ghost" size="sm" onClick={handleRename}>
575+
<Edit className="h-4 w-4" />
576+
</Button>
577+
</div>
578+
</>
579+
)
580+
}
581+
582+
const serverFormSchema = z.object({
583+
name: z.string().min(1, {
584+
message: "Name must be at least 1 character.",
585+
}),
586+
})
587+
588+
export function ServerForm({
589+
defaultValues,
590+
onServerChange,
591+
onOpenChange,
592+
}: {
593+
defaultValues: UpsertServerData
594+
onServerChange?: (values: z.infer<typeof serverFormSchema>) => void
595+
onOpenChange?: (open: boolean) => void
596+
}) {
597+
const form = useForm<z.infer<typeof serverFormSchema>>({
598+
resolver: zodResolver(serverFormSchema),
599+
defaultValues,
600+
})
601+
602+
const onSubmit = (values: z.infer<typeof serverFormSchema>) => {
603+
onServerChange?.(values)
604+
}
605+
606+
return (
607+
<Dialog open onOpenChange={onOpenChange}>
608+
<DialogContent>
609+
<DialogHeader>
610+
<DialogTitle>Rename server</DialogTitle>
611+
<DialogDescription>Update the server name.</DialogDescription>
612+
</DialogHeader>
613+
614+
<Form {...form}>
615+
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
616+
<FormField
617+
control={form.control}
618+
name="name"
619+
render={({ field }) => (
620+
<FormItem>
621+
<FormLabel>Name</FormLabel>
622+
<FormControl>
623+
<Input placeholder="My Server" {...field} />
624+
</FormControl>
625+
<FormDescription>
626+
A descriptive name for your server.
627+
</FormDescription>
628+
<FormMessage />
629+
</FormItem>
630+
)}
631+
/>
632+
<Button type="submit">Update</Button>
633+
</form>
634+
</Form>
635+
</DialogContent>
636+
</Dialog>
637+
)
638+
}

src/app/[serverId]/page.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import { notFound, redirect } from "next/navigation"
44

55
import { Button } from "@/components/ui/button"
66
import { createClient } from "@/lib/supabase/server"
7-
import { ToolSection, ConnectButton } from "@/app/[serverId]/client"
7+
import {
8+
ToolSection,
9+
ConnectButton,
10+
ServerHeader,
11+
} from "@/app/[serverId]/client"
812

913
export default async function ServerPage({
1014
params,
@@ -50,7 +54,7 @@ export default async function ServerPage({
5054
</div>
5155

5256
<div className="flex items-center justify-between mb-10">
53-
<h1 className="text-2xl font-bold grow">{server.name}</h1>
57+
<ServerHeader server={server} />
5458
<ConnectButton serverId={server.id} accessToken={accessToken} />
5559
</div>
5660
</header>

src/app/client.tsx

Lines changed: 155 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,89 @@
11
"use client"
2-
import { Plus } from "lucide-react"
2+
import { Plus, Edit } from "lucide-react"
33
import Link from "next/link"
44
import { useRouter } from "next/navigation"
5+
import { useState } from "react"
6+
import { z } from "zod"
7+
import { zodResolver } from "@hookform/resolvers/zod"
8+
import { useForm } from "react-hook-form"
59

610
import { Button } from "@/components/ui/button"
11+
import {
12+
Dialog,
13+
DialogContent,
14+
DialogDescription,
15+
DialogHeader,
16+
DialogTitle,
17+
} from "@/components/ui/dialog"
18+
import {
19+
Form,
20+
FormControl,
21+
FormDescription,
22+
FormField,
23+
FormItem,
24+
FormLabel,
25+
FormMessage,
26+
} from "@/components/ui/form"
27+
import { Input } from "@/components/ui/input"
728

829
import { createClient } from "@/lib/supabase/client"
930
import { Database } from "../../database.types"
1031

32+
type UpsertServerData = {
33+
id?: string // Omitted if we're adding a new row
34+
name: string
35+
}
36+
1137
export function ServerCard({
1238
server,
1339
}: {
1440
server: Database["public"]["Tables"]["servers"]["Row"]
1541
}) {
1642
const supabase = createClient()
1743
const router = useRouter()
44+
const [editingServer, setEditingServer] = useState<UpsertServerData>()
1845

1946
const handleDelete = async (serverId: string) => {
2047
await supabase.from("servers").delete().eq("id", serverId)
2148
router.refresh()
2249
}
2350

51+
const handleUpsertServer = async (data: UpsertServerData) => {
52+
await supabase.from("servers").upsert({ ...data })
53+
router.refresh()
54+
setEditingServer(undefined)
55+
}
56+
57+
const handleRename = () => {
58+
setEditingServer({
59+
id: server.id,
60+
name: server.name,
61+
})
62+
}
63+
2464
return (
2565
<div className="bg-card border rounded-md px-6 py-6 flex items-center">
66+
{editingServer && (
67+
<ServerForm
68+
defaultValues={editingServer}
69+
onServerChange={(values) => {
70+
handleUpsertServer({ id: editingServer.id, ...values })
71+
}}
72+
onOpenChange={(open) => {
73+
if (!open) {
74+
setEditingServer(undefined)
75+
}
76+
}}
77+
/>
78+
)}
79+
2680
<span className="grow">{server.name}</span>
2781
<div className="flex items-center gap-2">
82+
<Button variant="ghost" size="sm" onClick={handleRename}>
83+
<Edit className="h-4 w-4" />
84+
</Button>
2885
<Button variant="outline" asChild>
29-
<Link href={`/${server.id}`}>Edit</Link>
86+
<Link href={`/${server.id}`}>Manage</Link>
3087
</Button>
3188
<Button variant="destructive" onClick={() => handleDelete(server.id)}>
3289
Delete
@@ -39,18 +96,106 @@ export function ServerCard({
3996
export function AddServerButton() {
4097
const supabase = createClient()
4198
const router = useRouter()
99+
const [editingServer, setEditingServer] = useState<UpsertServerData>()
42100

43-
const handleAddServer = async () => {
44-
await supabase.from("servers").insert({
45-
name: "New Server",
46-
})
101+
const handleUpsertServer = async (data: UpsertServerData) => {
102+
await supabase.from("servers").insert({ name: data.name })
47103
router.refresh()
104+
setEditingServer(undefined)
105+
}
106+
107+
const handleAddServer = () => {
108+
setEditingServer({
109+
name: "",
110+
})
48111
}
49112

50113
return (
51-
<Button className="flex items-center gap-2" onClick={handleAddServer}>
52-
<Plus />
53-
Add Server
54-
</Button>
114+
<>
115+
{editingServer && (
116+
<ServerForm
117+
defaultValues={editingServer}
118+
onServerChange={(values) => {
119+
handleUpsertServer(values)
120+
}}
121+
onOpenChange={(open) => {
122+
if (!open) {
123+
setEditingServer(undefined)
124+
}
125+
}}
126+
/>
127+
)}
128+
129+
<Button className="flex items-center gap-2" onClick={handleAddServer}>
130+
<Plus />
131+
Add Server
132+
</Button>
133+
</>
134+
)
135+
}
136+
137+
const serverFormSchema = z.object({
138+
name: z.string().min(1, {
139+
message: "Name must be at least 1 character.",
140+
}),
141+
})
142+
143+
export function ServerForm({
144+
defaultValues,
145+
onServerChange,
146+
onOpenChange,
147+
}: {
148+
defaultValues: UpsertServerData
149+
onServerChange?: (values: z.infer<typeof serverFormSchema>) => void
150+
onOpenChange?: (open: boolean) => void
151+
}) {
152+
const form = useForm<z.infer<typeof serverFormSchema>>({
153+
resolver: zodResolver(serverFormSchema),
154+
defaultValues,
155+
})
156+
157+
const onSubmit = (values: z.infer<typeof serverFormSchema>) => {
158+
onServerChange?.(values)
159+
}
160+
161+
return (
162+
<Dialog open onOpenChange={onOpenChange}>
163+
<DialogContent>
164+
<DialogHeader>
165+
<DialogTitle>
166+
{defaultValues.id !== undefined ? "Rename server" : "Add a server"}
167+
</DialogTitle>
168+
<DialogDescription>
169+
{defaultValues.id !== undefined
170+
? "Update the server name."
171+
: "Create a new server with a custom name."}
172+
</DialogDescription>
173+
</DialogHeader>
174+
175+
<Form {...form}>
176+
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
177+
<FormField
178+
control={form.control}
179+
name="name"
180+
render={({ field }) => (
181+
<FormItem>
182+
<FormLabel>Name</FormLabel>
183+
<FormControl>
184+
<Input placeholder="My Server" {...field} />
185+
</FormControl>
186+
<FormDescription>
187+
A descriptive name for your server.
188+
</FormDescription>
189+
<FormMessage />
190+
</FormItem>
191+
)}
192+
/>
193+
<Button type="submit">
194+
{defaultValues.id !== undefined ? "Update" : "Create"}
195+
</Button>
196+
</form>
197+
</Form>
198+
</DialogContent>
199+
</Dialog>
55200
)
56201
}

0 commit comments

Comments
 (0)