Skip to content

Commit eb7bae2

Browse files
authored
Merge pull request #1006 from Dokploy/canary
v0.16.0
2 parents 839e1c0 + 4533b19 commit eb7bae2

File tree

116 files changed

+12144
-1421
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+12144
-1421
lines changed

apps/dokploy/components/dashboard/application/deployments/show-deployment.tsx

+69-33
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1+
import { Badge } from "@/components/ui/badge";
2+
import { Checkbox } from "@/components/ui/checkbox";
13
import {
24
Dialog,
35
DialogContent,
46
DialogDescription,
57
DialogHeader,
68
DialogTitle,
79
} from "@/components/ui/dialog";
10+
import { Loader2 } from "lucide-react";
811
import { useEffect, useRef, useState } from "react";
912
import { TerminalLine } from "../../docker/logs/terminal-line";
10-
import { LogLine, parseLogs } from "../../docker/logs/utils";
11-
import { Badge } from "@/components/ui/badge";
12-
import { Loader2 } from "lucide-react";
13+
import { type LogLine, parseLogs } from "../../docker/logs/utils";
1314

1415
interface Props {
1516
logPath: string | null;
@@ -19,26 +20,26 @@ interface Props {
1920
}
2021
export const ShowDeployment = ({ logPath, open, onClose, serverId }: Props) => {
2122
const [data, setData] = useState("");
23+
const [showExtraLogs, setShowExtraLogs] = useState(false);
2224
const [filteredLogs, setFilteredLogs] = useState<LogLine[]>([]);
2325
const wsRef = useRef<WebSocket | null>(null); // Ref to hold WebSocket instance
2426
const [autoScroll, setAutoScroll] = useState(true);
2527
const scrollRef = useRef<HTMLDivElement>(null);
2628

27-
2829
const scrollToBottom = () => {
2930
if (autoScroll && scrollRef.current) {
30-
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
31+
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
3132
}
32-
};
33-
33+
};
34+
3435
const handleScroll = () => {
3536
if (!scrollRef.current) return;
36-
37+
3738
const { scrollTop, scrollHeight, clientHeight } = scrollRef.current;
3839
const isAtBottom = Math.abs(scrollHeight - scrollTop - clientHeight) < 10;
3940
setAutoScroll(isAtBottom);
40-
};
41-
41+
};
42+
4243
useEffect(() => {
4344
if (!open || !logPath) return;
4445

@@ -69,20 +70,34 @@ export const ShowDeployment = ({ logPath, open, onClose, serverId }: Props) => {
6970
};
7071
}, [logPath, open]);
7172

72-
7373
useEffect(() => {
7474
const logs = parseLogs(data);
75-
setFilteredLogs(logs);
76-
}, [data]);
75+
let filteredLogsResult = logs;
76+
if (serverId) {
77+
let hideSubsequentLogs = false;
78+
filteredLogsResult = logs.filter((log) => {
79+
if (
80+
log.message.includes(
81+
"===================================EXTRA LOGS============================================",
82+
)
83+
) {
84+
hideSubsequentLogs = true;
85+
return showExtraLogs;
86+
}
87+
return showExtraLogs ? true : !hideSubsequentLogs;
88+
});
89+
}
90+
91+
setFilteredLogs(filteredLogsResult);
92+
}, [data, showExtraLogs]);
7793

7894
useEffect(() => {
7995
scrollToBottom();
80-
96+
8197
if (autoScroll && scrollRef.current) {
82-
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
98+
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
8399
}
84-
}, [filteredLogs, autoScroll]);
85-
100+
}, [filteredLogs, autoScroll]);
86101

87102
return (
88103
<Dialog
@@ -103,28 +118,49 @@ export const ShowDeployment = ({ logPath, open, onClose, serverId }: Props) => {
103118
<DialogContent className={"sm:max-w-5xl overflow-y-auto max-h-screen"}>
104119
<DialogHeader>
105120
<DialogTitle>Deployment</DialogTitle>
106-
<DialogDescription>
107-
See all the details of this deployment | <Badge variant="blank" className="text-xs">{filteredLogs.length} lines</Badge>
121+
<DialogDescription className="flex items-center gap-2">
122+
<span>
123+
See all the details of this deployment |{" "}
124+
<Badge variant="blank" className="text-xs">
125+
{filteredLogs.length} lines
126+
</Badge>
127+
</span>
128+
129+
{serverId && (
130+
<div className="flex items-center space-x-2">
131+
<Checkbox
132+
id="show-extra-logs"
133+
checked={showExtraLogs}
134+
onCheckedChange={(checked) =>
135+
setShowExtraLogs(checked as boolean)
136+
}
137+
/>
138+
<label
139+
htmlFor="show-extra-logs"
140+
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
141+
>
142+
Show Extra Logs
143+
</label>
144+
</div>
145+
)}
108146
</DialogDescription>
109147
</DialogHeader>
110148

111-
<div
149+
<div
112150
ref={scrollRef}
113151
onScroll={handleScroll}
114152
className="h-[720px] overflow-y-auto space-y-0 border p-4 bg-[#fafafa] dark:bg-[#050506] rounded custom-logs-scrollbar"
115-
> {
116-
filteredLogs.length > 0 ? filteredLogs.map((log: LogLine, index: number) => (
117-
<TerminalLine
118-
key={index}
119-
log={log}
120-
noTimestamp
121-
/>
122-
)) :
123-
(
124-
<div className="flex justify-center items-center h-full text-muted-foreground">
125-
<Loader2 className="h-6 w-6 animate-spin" />
126-
</div>
127-
)}
153+
>
154+
{" "}
155+
{filteredLogs.length > 0 ? (
156+
filteredLogs.map((log: LogLine, index: number) => (
157+
<TerminalLine key={index} log={log} noTimestamp />
158+
))
159+
) : (
160+
<div className="flex justify-center items-center h-full text-muted-foreground">
161+
<Loader2 className="h-6 w-6 animate-spin" />
162+
</div>
163+
)}
128164
</div>
129165
</DialogContent>
130166
</Dialog>

apps/dokploy/components/dashboard/application/domains/add-domain.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -264,21 +264,21 @@ export const AddDomain = ({
264264
name="certificateType"
265265
render={({ field }) => (
266266
<FormItem className="col-span-2">
267-
<FormLabel>Certificate</FormLabel>
267+
<FormLabel>Certificate Provider</FormLabel>
268268
<Select
269269
onValueChange={field.onChange}
270270
defaultValue={field.value || ""}
271271
>
272272
<FormControl>
273273
<SelectTrigger>
274-
<SelectValue placeholder="Select a certificate" />
274+
<SelectValue placeholder="Select a certificate provider" />
275275
</SelectTrigger>
276276
</FormControl>
277277

278278
<SelectContent>
279279
<SelectItem value="none">None</SelectItem>
280280
<SelectItem value={"letsencrypt"}>
281-
Letsencrypt (Default)
281+
Let's Encrypt
282282
</SelectItem>
283283
</SelectContent>
284284
</Select>

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

+101-22
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Badge } from "@/components/ui/badge";
12
import {
23
Card,
34
CardContent,
@@ -15,6 +16,7 @@ import {
1516
SelectTrigger,
1617
SelectValue,
1718
} from "@/components/ui/select";
19+
import { Switch } from "@/components/ui/switch";
1820
import { api } from "@/utils/api";
1921
import { Loader2 } from "lucide-react";
2022
import dynamic from "next/dynamic";
@@ -29,28 +31,67 @@ export const DockerLogs = dynamic(
2931
},
3032
);
3133

34+
export const badgeStateColor = (state: string) => {
35+
switch (state) {
36+
case "running":
37+
return "green";
38+
case "exited":
39+
case "shutdown":
40+
return "red";
41+
case "accepted":
42+
case "created":
43+
return "blue";
44+
default:
45+
return "default";
46+
}
47+
};
48+
3249
interface Props {
3350
appName: string;
3451
serverId?: string;
3552
}
3653

3754
export const ShowDockerLogs = ({ appName, serverId }: Props) => {
38-
const { data, isLoading } = api.docker.getContainersByAppNameMatch.useQuery(
39-
{
40-
appName,
41-
serverId,
42-
},
43-
{
44-
enabled: !!appName,
45-
},
46-
);
4755
const [containerId, setContainerId] = useState<string | undefined>();
56+
const [option, setOption] = useState<"swarm" | "native">("native");
57+
58+
const { data: services, isLoading: servicesLoading } =
59+
api.docker.getServiceContainersByAppName.useQuery(
60+
{
61+
appName,
62+
serverId,
63+
},
64+
{
65+
enabled: !!appName && option === "swarm",
66+
},
67+
);
68+
69+
const { data: containers, isLoading: containersLoading } =
70+
api.docker.getContainersByAppNameMatch.useQuery(
71+
{
72+
appName,
73+
serverId,
74+
},
75+
{
76+
enabled: !!appName && option === "native",
77+
},
78+
);
4879

4980
useEffect(() => {
50-
if (data && data?.length > 0) {
51-
setContainerId(data[0]?.containerId);
81+
if (option === "native") {
82+
if (containers && containers?.length > 0) {
83+
setContainerId(containers[0]?.containerId);
84+
}
85+
} else {
86+
if (services && services?.length > 0) {
87+
setContainerId(services[0]?.containerId);
88+
}
5289
}
53-
}, [data]);
90+
}, [option, services, containers]);
91+
92+
const isLoading = option === "native" ? containersLoading : servicesLoading;
93+
const containersLenght =
94+
option === "native" ? containers?.length : services?.length;
5495

5596
return (
5697
<Card className="bg-background">
@@ -62,7 +103,21 @@ export const ShowDockerLogs = ({ appName, serverId }: Props) => {
62103
</CardHeader>
63104

64105
<CardContent className="flex flex-col gap-4">
65-
<Label>Select a container to view logs</Label>
106+
<div className="flex flex-row justify-between items-center gap-2">
107+
<Label>Select a container to view logs</Label>
108+
<div className="flex flex-row gap-2 items-center">
109+
<span className="text-sm text-muted-foreground">
110+
{option === "native" ? "Native" : "Swarm"}
111+
</span>
112+
<Switch
113+
checked={option === "native"}
114+
onCheckedChange={(checked) => {
115+
setOption(checked ? "native" : "swarm");
116+
}}
117+
/>
118+
</div>
119+
</div>
120+
66121
<Select onValueChange={setContainerId} value={containerId}>
67122
<SelectTrigger>
68123
{isLoading ? (
@@ -76,21 +131,45 @@ export const ShowDockerLogs = ({ appName, serverId }: Props) => {
76131
</SelectTrigger>
77132
<SelectContent>
78133
<SelectGroup>
79-
{data?.map((container) => (
80-
<SelectItem
81-
key={container.containerId}
82-
value={container.containerId}
83-
>
84-
{container.name} ({container.containerId}) {container.state}
85-
</SelectItem>
86-
))}
87-
<SelectLabel>Containers ({data?.length})</SelectLabel>
134+
{option === "native" ? (
135+
<div>
136+
{containers?.map((container) => (
137+
<SelectItem
138+
key={container.containerId}
139+
value={container.containerId}
140+
>
141+
{container.name} ({container.containerId}){" "}
142+
<Badge variant={badgeStateColor(container.state)}>
143+
{container.state}
144+
</Badge>
145+
</SelectItem>
146+
))}
147+
</div>
148+
) : (
149+
<>
150+
{services?.map((container) => (
151+
<SelectItem
152+
key={container.containerId}
153+
value={container.containerId}
154+
>
155+
{container.name} ({container.containerId}@{container.node}
156+
)
157+
<Badge variant={badgeStateColor(container.state)}>
158+
{container.state}
159+
</Badge>
160+
</SelectItem>
161+
))}
162+
</>
163+
)}
164+
165+
<SelectLabel>Containers ({containersLenght})</SelectLabel>
88166
</SelectGroup>
89167
</SelectContent>
90168
</Select>
91169
<DockerLogs
92170
serverId={serverId || ""}
93171
containerId={containerId || "select-a-container"}
172+
runType={option}
94173
/>
95174
</CardContent>
96175
</Card>

apps/dokploy/components/dashboard/application/preview-deployments/add-preview-domain.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -265,21 +265,21 @@ export const AddPreviewDomain = ({
265265
name="certificateType"
266266
render={({ field }) => (
267267
<FormItem className="col-span-2">
268-
<FormLabel>Certificate</FormLabel>
268+
<FormLabel>Certificate Provider</FormLabel>
269269
<Select
270270
onValueChange={field.onChange}
271271
defaultValue={field.value || ""}
272272
>
273273
<FormControl>
274274
<SelectTrigger>
275-
<SelectValue placeholder="Select a certificate" />
275+
<SelectValue placeholder="Select a certificate provider" />
276276
</SelectTrigger>
277277
</FormControl>
278278

279279
<SelectContent>
280280
<SelectItem value="none">None</SelectItem>
281281
<SelectItem value={"letsencrypt"}>
282-
Letsencrypt (Default)
282+
Let's Encrypt
283283
</SelectItem>
284284
</SelectContent>
285285
</Select>

0 commit comments

Comments
 (0)