Skip to content

Commit ff8d922

Browse files
authored
Merge pull request #1434 from Dokploy/1301-add-information-tooltips-to-buttons
feat(ui): add tooltips to service action buttons for improved user gu…
2 parents 9816eca + 01c33ad commit ff8d922

File tree

7 files changed

+1039
-550
lines changed

7 files changed

+1039
-550
lines changed

apps/dokploy/components/dashboard/application/general/show.tsx

Lines changed: 168 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,22 @@ import { DialogAction } from "@/components/shared/dialog-action";
44
import { Button } from "@/components/ui/button";
55
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
66
import { Switch } from "@/components/ui/switch";
7+
import {
8+
Tooltip,
9+
TooltipContent,
10+
TooltipProvider,
11+
TooltipTrigger,
12+
} from "@/components/ui/tooltip";
13+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
714
import { api } from "@/utils/api";
8-
import { Ban, CheckCircle2, Hammer, RefreshCcw, Terminal } from "lucide-react";
15+
import {
16+
Ban,
17+
CheckCircle2,
18+
Hammer,
19+
HelpCircle,
20+
RefreshCcw,
21+
Terminal,
22+
} from "lucide-react";
923
import { useRouter } from "next/router";
1024
import { toast } from "sonner";
1125
import { DockerTerminalModal } from "../../settings/web-server/docker-terminal-modal";
@@ -41,128 +55,188 @@ export const ShowGeneralApplication = ({ applicationId }: Props) => {
4155
<CardTitle className="text-xl">Deploy Settings</CardTitle>
4256
</CardHeader>
4357
<CardContent className="flex flex-row gap-4 flex-wrap">
44-
<DialogAction
45-
title="Deploy Application"
46-
description="Are you sure you want to deploy this application?"
47-
type="default"
48-
onClick={async () => {
49-
await deploy({
50-
applicationId: applicationId,
51-
})
52-
.then(() => {
53-
toast.success("Application deployed successfully");
54-
refetch();
55-
router.push(
56-
`/dashboard/project/${data?.projectId}/services/application/${applicationId}?tab=deployments`,
57-
);
58-
})
59-
.catch(() => {
60-
toast.error("Error deploying application");
61-
});
62-
}}
63-
>
64-
<Button
65-
variant="default"
66-
isLoading={data?.applicationStatus === "running"}
67-
>
68-
Deploy
69-
</Button>
70-
</DialogAction>
71-
<DialogAction
72-
title="Reload Application"
73-
description="Are you sure you want to reload this application?"
74-
type="default"
75-
onClick={async () => {
76-
await reload({
77-
applicationId: applicationId,
78-
appName: data?.appName || "",
79-
})
80-
.then(() => {
81-
toast.success("Application reloaded successfully");
82-
refetch();
83-
})
84-
.catch(() => {
85-
toast.error("Error reloading application");
86-
});
87-
}}
88-
>
89-
<Button variant="secondary" isLoading={isReloading}>
90-
Reload
91-
<RefreshCcw className="size-4" />
92-
</Button>
93-
</DialogAction>
94-
<DialogAction
95-
title="Rebuild Application"
96-
description="Are you sure you want to rebuild this application?"
97-
type="default"
98-
onClick={async () => {
99-
await redeploy({
100-
applicationId: applicationId,
101-
})
102-
.then(() => {
103-
toast.success("Application rebuilt successfully");
104-
refetch();
58+
<TooltipProvider delayDuration={0}>
59+
<DialogAction
60+
title="Deploy Application"
61+
description="Are you sure you want to deploy this application?"
62+
type="default"
63+
onClick={async () => {
64+
await deploy({
65+
applicationId: applicationId,
10566
})
106-
.catch(() => {
107-
toast.error("Error rebuilding application");
108-
});
109-
}}
110-
>
111-
<Button
112-
variant="secondary"
113-
isLoading={data?.applicationStatus === "running"}
67+
.then(() => {
68+
toast.success("Application deployed successfully");
69+
refetch();
70+
router.push(
71+
`/dashboard/project/${data?.projectId}/services/application/${applicationId}?tab=deployments`,
72+
);
73+
})
74+
.catch(() => {
75+
toast.error("Error deploying application");
76+
});
77+
}}
11478
>
115-
Rebuild
116-
<Hammer className="size-4" />
117-
</Button>
118-
</DialogAction>
119-
120-
{data?.applicationStatus === "idle" ? (
79+
<Button
80+
variant="default"
81+
isLoading={data?.applicationStatus === "running"}
82+
className="flex items-center gap-1.5"
83+
>
84+
Deploy
85+
<Tooltip>
86+
<TooltipTrigger asChild>
87+
<HelpCircle className="size-4 text-muted-foreground hover:text-foreground transition-colors cursor-pointer" />
88+
</TooltipTrigger>
89+
<TooltipPrimitive.Portal>
90+
<TooltipContent sideOffset={5} className="z-[60]">
91+
<p>
92+
Downloads the source code and performs a complete build
93+
</p>
94+
</TooltipContent>
95+
</TooltipPrimitive.Portal>
96+
</Tooltip>
97+
</Button>
98+
</DialogAction>
12199
<DialogAction
122-
title="Start Application"
123-
description="Are you sure you want to start this application?"
100+
title="Reload Application"
101+
description="Are you sure you want to reload this application?"
124102
type="default"
125103
onClick={async () => {
126-
await start({
104+
await reload({
127105
applicationId: applicationId,
106+
appName: data?.appName || "",
128107
})
129108
.then(() => {
130-
toast.success("Application started successfully");
109+
toast.success("Application reloaded successfully");
131110
refetch();
132111
})
133112
.catch(() => {
134-
toast.error("Error starting application");
113+
toast.error("Error reloading application");
135114
});
136115
}}
137116
>
138-
<Button variant="secondary" isLoading={isStarting}>
139-
Start
140-
<CheckCircle2 className="size-4" />
117+
<Button variant="secondary" isLoading={isReloading}>
118+
Reload
119+
<RefreshCcw className="size-4" />
141120
</Button>
142121
</DialogAction>
143-
) : (
144122
<DialogAction
145-
title="Stop Application"
146-
description="Are you sure you want to stop this application?"
123+
title="Rebuild Application"
124+
description="Are you sure you want to rebuild this application?"
125+
type="default"
147126
onClick={async () => {
148-
await stop({
127+
await redeploy({
149128
applicationId: applicationId,
150129
})
151130
.then(() => {
152-
toast.success("Application stopped successfully");
131+
toast.success("Application rebuilt successfully");
153132
refetch();
154133
})
155134
.catch(() => {
156-
toast.error("Error stopping application");
135+
toast.error("Error rebuilding application");
157136
});
158137
}}
159138
>
160-
<Button variant="destructive" isLoading={isStopping}>
161-
Stop
162-
<Ban className="size-4" />
139+
<Button
140+
variant="secondary"
141+
isLoading={data?.applicationStatus === "running"}
142+
className="flex items-center gap-1.5"
143+
>
144+
Rebuild
145+
<Hammer className="size-4" />
146+
<Tooltip>
147+
<TooltipTrigger asChild>
148+
<HelpCircle className="size-4 text-muted-foreground hover:text-foreground transition-colors cursor-pointer" />
149+
</TooltipTrigger>
150+
<TooltipPrimitive.Portal>
151+
<TooltipContent sideOffset={5} className="z-[60]">
152+
<p>
153+
Only rebuilds the application without downloading new
154+
code
155+
</p>
156+
</TooltipContent>
157+
</TooltipPrimitive.Portal>
158+
</Tooltip>
163159
</Button>
164160
</DialogAction>
165-
)}
161+
162+
{data?.applicationStatus === "idle" ? (
163+
<DialogAction
164+
title="Start Application"
165+
description="Are you sure you want to start this application?"
166+
type="default"
167+
onClick={async () => {
168+
await start({
169+
applicationId: applicationId,
170+
})
171+
.then(() => {
172+
toast.success("Application started successfully");
173+
refetch();
174+
})
175+
.catch(() => {
176+
toast.error("Error starting application");
177+
});
178+
}}
179+
>
180+
<Button
181+
variant="secondary"
182+
isLoading={isStarting}
183+
className="flex items-center gap-1.5"
184+
>
185+
Start
186+
<CheckCircle2 className="size-4" />
187+
<Tooltip>
188+
<TooltipTrigger asChild>
189+
<HelpCircle className="size-4 text-muted-foreground hover:text-foreground transition-colors cursor-pointer" />
190+
</TooltipTrigger>
191+
<TooltipPrimitive.Portal>
192+
<TooltipContent sideOffset={5} className="z-[60]">
193+
<p>
194+
Start the application (requires a previous successful
195+
build)
196+
</p>
197+
</TooltipContent>
198+
</TooltipPrimitive.Portal>
199+
</Tooltip>
200+
</Button>
201+
</DialogAction>
202+
) : (
203+
<DialogAction
204+
title="Stop Application"
205+
description="Are you sure you want to stop this application?"
206+
onClick={async () => {
207+
await stop({
208+
applicationId: applicationId,
209+
})
210+
.then(() => {
211+
toast.success("Application stopped successfully");
212+
refetch();
213+
})
214+
.catch(() => {
215+
toast.error("Error stopping application");
216+
});
217+
}}
218+
>
219+
<Button
220+
variant="destructive"
221+
isLoading={isStopping}
222+
className="flex items-center gap-1.5"
223+
>
224+
Stop
225+
<Ban className="size-4" />
226+
<Tooltip>
227+
<TooltipTrigger asChild>
228+
<HelpCircle className="size-4 text-muted-foreground hover:text-foreground transition-colors cursor-pointer" />
229+
</TooltipTrigger>
230+
<TooltipPrimitive.Portal>
231+
<TooltipContent sideOffset={5} className="z-[60]">
232+
<p>Stop the currently running application</p>
233+
</TooltipContent>
234+
</TooltipPrimitive.Portal>
235+
</Tooltip>
236+
</Button>
237+
</DialogAction>
238+
)}
239+
</TooltipProvider>
166240
<DockerTerminalModal
167241
appName={data?.appName || ""}
168242
serverId={data?.serverId || ""}

0 commit comments

Comments
 (0)