mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Compare commits
19 Commits
711-custom
...
fix/dokplo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5992688e85 | ||
|
|
425061e481 | ||
|
|
08c0bf8a21 | ||
|
|
64a2c9e0a1 | ||
|
|
21e46f5382 | ||
|
|
52b2158309 | ||
|
|
178d84d438 | ||
|
|
80016b57a8 | ||
|
|
b4b2d12f6e | ||
|
|
294378d95b | ||
|
|
c52812f9d3 | ||
|
|
82f7c5d5f3 | ||
|
|
3d2ae52259 | ||
|
|
bf115c7895 | ||
|
|
c2c29dbaba | ||
|
|
136570b36c | ||
|
|
7d0075c230 | ||
|
|
19b4edee8d | ||
|
|
7f04eb856e |
@@ -86,7 +86,7 @@ export const ShowDeployments = ({
|
|||||||
<span>Webhook URL: </span>
|
<span>Webhook URL: </span>
|
||||||
<div className="flex flex-row items-center gap-2">
|
<div className="flex flex-row items-center gap-2">
|
||||||
<span className="break-all text-muted-foreground">
|
<span className="break-all text-muted-foreground">
|
||||||
{`${url}/api/deploy/${refreshToken}`}
|
{`${url}/api/deploy${type === "compose" ? "/compose" : ""}/${refreshToken}`}
|
||||||
</span>
|
</span>
|
||||||
{(type === "application" || type === "compose") && (
|
{(type === "application" || type === "compose") && (
|
||||||
<RefreshToken id={id} type={type} />
|
<RefreshToken id={id} type={type} />
|
||||||
|
|||||||
@@ -186,30 +186,19 @@ export const ShowDomains = ({ id, type }: Props) => {
|
|||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
key={item.domainId}
|
key={item.domainId}
|
||||||
className="relative overflow-hidden w-full border bg-card transition-all hover:shadow-md bg-transparent h-fit"
|
className="relative overflow-hidden w-full border transition-all hover:shadow-md bg-transparent h-fit"
|
||||||
>
|
>
|
||||||
<CardContent className="p-6">
|
<CardContent className="p-6">
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
{/* Service & Domain Info */}
|
{/* Service & Domain Info */}
|
||||||
<div className="flex items-start justify-between">
|
<div className="flex items-center justify-between flex-wrap gap-y-2">
|
||||||
<div className="flex flex-col gap-2">
|
{item.serviceName && (
|
||||||
{item.serviceName && (
|
<Badge variant="outline" className="w-fit">
|
||||||
<Badge variant="outline" className="w-fit">
|
<Server className="size-3 mr-1" />
|
||||||
<Server className="size-3 mr-1" />
|
{item.serviceName}
|
||||||
{item.serviceName}
|
</Badge>
|
||||||
</Badge>
|
)}
|
||||||
)}
|
<div className="flex gap-2 flex-wrap">
|
||||||
|
|
||||||
<Link
|
|
||||||
className="flex items-center gap-2 text-base font-medium hover:underline"
|
|
||||||
target="_blank"
|
|
||||||
href={`${item.https ? "https" : "http"}://${item.host}${item.path}`}
|
|
||||||
>
|
|
||||||
{item.host}
|
|
||||||
<ExternalLink className="size-4" />
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
<div className="flex gap-2">
|
|
||||||
{!item.host.includes("traefik.me") && (
|
{!item.host.includes("traefik.me") && (
|
||||||
<DnsHelperModal
|
<DnsHelperModal
|
||||||
domain={{
|
domain={{
|
||||||
@@ -266,6 +255,16 @@ export const ShowDomains = ({ id, type }: Props) => {
|
|||||||
</DialogAction>
|
</DialogAction>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="w-full break-all">
|
||||||
|
<Link
|
||||||
|
className="flex items-center gap-2 text-base font-medium hover:underline"
|
||||||
|
target="_blank"
|
||||||
|
href={`${item.https ? "https" : "http"}://${item.host}${item.path}`}
|
||||||
|
>
|
||||||
|
{item.host}
|
||||||
|
<ExternalLink className="size-4 min-w-4" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Domain Details */}
|
{/* Domain Details */}
|
||||||
<div className="flex flex-wrap gap-3">
|
<div className="flex flex-wrap gap-3">
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => {
|
|||||||
enableSubmodules: data.enableSubmodules || false,
|
enableSubmodules: data.enableSubmodules || false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [form.reset, data, form]);
|
}, [form.reset, data?.applicationId, form]);
|
||||||
|
|
||||||
const onSubmit = async (data: BitbucketProvider) => {
|
const onSubmit = async (data: BitbucketProvider) => {
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
@@ -435,7 +435,7 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Input
|
<Input
|
||||||
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
|
placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -454,7 +454,7 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => {
|
|||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const input = document.querySelector(
|
const input = document.querySelector(
|
||||||
'input[placeholder="Enter a path to watch (e.g., src/*, dist/*)"]',
|
'input[placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"]',
|
||||||
) as HTMLInputElement;
|
) as HTMLInputElement;
|
||||||
const value = input.value.trim();
|
const value = input.value.trim();
|
||||||
if (value) {
|
if (value) {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export const SaveDockerProvider = ({ applicationId }: Props) => {
|
|||||||
registryURL: data.registryUrl || "",
|
registryURL: data.registryUrl || "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [form.reset, data, form]);
|
}, [form.reset, data?.applicationId, form]);
|
||||||
|
|
||||||
const onSubmit = async (values: DockerProvider) => {
|
const onSubmit = async (values: DockerProvider) => {
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ export const SaveGitProvider = ({ applicationId }: Props) => {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Input
|
<Input
|
||||||
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
|
placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -281,7 +281,7 @@ export const SaveGitProvider = ({ applicationId }: Props) => {
|
|||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const input = document.querySelector(
|
const input = document.querySelector(
|
||||||
'input[placeholder="Enter a path to watch (e.g., src/*, dist/*)"]',
|
'input[placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"]',
|
||||||
) as HTMLInputElement;
|
) as HTMLInputElement;
|
||||||
const value = input.value.trim();
|
const value = input.value.trim();
|
||||||
if (value) {
|
if (value) {
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => {
|
|||||||
enableSubmodules: data.enableSubmodules || false,
|
enableSubmodules: data.enableSubmodules || false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [form.reset, data, form]);
|
}, [form.reset, data?.applicationId, form]);
|
||||||
|
|
||||||
const onSubmit = async (data: GiteaProvider) => {
|
const onSubmit = async (data: GiteaProvider) => {
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
@@ -470,7 +470,7 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => {
|
|||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
|
placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ export const SaveGithubProvider = ({ applicationId }: Props) => {
|
|||||||
enableSubmodules: data.enableSubmodules ?? false,
|
enableSubmodules: data.enableSubmodules ?? false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [form.reset, data, form]);
|
}, [form.reset, data?.applicationId, form]);
|
||||||
|
|
||||||
const onSubmit = async (data: GithubProvider) => {
|
const onSubmit = async (data: GithubProvider) => {
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
@@ -474,7 +474,7 @@ export const SaveGithubProvider = ({ applicationId }: Props) => {
|
|||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
|
placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ export const SaveGitlabProvider = ({ applicationId }: Props) => {
|
|||||||
enableSubmodules: data.enableSubmodules ?? false,
|
enableSubmodules: data.enableSubmodules ?? false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [form.reset, data, form]);
|
}, [form.reset, data?.applicationId, form]);
|
||||||
|
|
||||||
const onSubmit = async (data: GitlabProvider) => {
|
const onSubmit = async (data: GitlabProvider) => {
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
@@ -452,7 +452,7 @@ export const SaveGitlabProvider = ({ applicationId }: Props) => {
|
|||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
|
placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ export const SaveBitbucketProviderCompose = ({ composeId }: Props) => {
|
|||||||
enableSubmodules: data.enableSubmodules ?? false,
|
enableSubmodules: data.enableSubmodules ?? false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [form.reset, data, form]);
|
}, [form.reset, data?.composeId, form]);
|
||||||
|
|
||||||
const onSubmit = async (data: BitbucketProvider) => {
|
const onSubmit = async (data: BitbucketProvider) => {
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
@@ -437,7 +437,7 @@ export const SaveBitbucketProviderCompose = ({ composeId }: Props) => {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Input
|
<Input
|
||||||
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
|
placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -456,7 +456,7 @@ export const SaveBitbucketProviderCompose = ({ composeId }: Props) => {
|
|||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const input = document.querySelector(
|
const input = document.querySelector(
|
||||||
'input[placeholder="Enter a path to watch (e.g., src/*, dist/*)"]',
|
'input[placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"]',
|
||||||
) as HTMLInputElement;
|
) as HTMLInputElement;
|
||||||
const value = input.value.trim();
|
const value = input.value.trim();
|
||||||
if (value) {
|
if (value) {
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ export const SaveGitProviderCompose = ({ composeId }: Props) => {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Input
|
<Input
|
||||||
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
|
placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -282,7 +282,7 @@ export const SaveGitProviderCompose = ({ composeId }: Props) => {
|
|||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const input = document.querySelector(
|
const input = document.querySelector(
|
||||||
'input[placeholder="Enter a path to watch (e.g., src/*, dist/*)"]',
|
'input[placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"]',
|
||||||
) as HTMLInputElement;
|
) as HTMLInputElement;
|
||||||
const value = input.value.trim();
|
const value = input.value.trim();
|
||||||
if (value) {
|
if (value) {
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ export const SaveGiteaProviderCompose = ({ composeId }: Props) => {
|
|||||||
enableSubmodules: data.enableSubmodules ?? false,
|
enableSubmodules: data.enableSubmodules ?? false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [form.reset, data, form]);
|
}, [form.reset, data?.composeId, form]);
|
||||||
|
|
||||||
const onSubmit = async (data: GiteaProvider) => {
|
const onSubmit = async (data: GiteaProvider) => {
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
@@ -437,7 +437,7 @@ export const SaveGiteaProviderCompose = ({ composeId }: Props) => {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Input
|
<Input
|
||||||
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
|
placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ export const SaveGithubProviderCompose = ({ composeId }: Props) => {
|
|||||||
enableSubmodules: data.enableSubmodules ?? false,
|
enableSubmodules: data.enableSubmodules ?? false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [form.reset, data, form]);
|
}, [form.reset, data?.composeId, form]);
|
||||||
|
|
||||||
const onSubmit = async (data: GithubProvider) => {
|
const onSubmit = async (data: GithubProvider) => {
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
@@ -474,7 +474,7 @@ export const SaveGithubProviderCompose = ({ composeId }: Props) => {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Input
|
<Input
|
||||||
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
|
placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -496,7 +496,7 @@ export const SaveGithubProviderCompose = ({ composeId }: Props) => {
|
|||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const input = document.querySelector(
|
const input = document.querySelector(
|
||||||
'input[placeholder="Enter a path to watch (e.g., src/*, dist/*)"]',
|
'input[placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"]',
|
||||||
) as HTMLInputElement;
|
) as HTMLInputElement;
|
||||||
const value = input.value.trim();
|
const value = input.value.trim();
|
||||||
if (value) {
|
if (value) {
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ export const SaveGitlabProviderCompose = ({ composeId }: Props) => {
|
|||||||
enableSubmodules: data.enableSubmodules ?? false,
|
enableSubmodules: data.enableSubmodules ?? false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [form.reset, data, form]);
|
}, [form.reset, data?.composeId, form]);
|
||||||
|
|
||||||
const onSubmit = async (data: GitlabProvider) => {
|
const onSubmit = async (data: GitlabProvider) => {
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
@@ -453,7 +453,7 @@ export const SaveGitlabProviderCompose = ({ composeId }: Props) => {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Input
|
<Input
|
||||||
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
|
placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -472,7 +472,7 @@ export const SaveGitlabProviderCompose = ({ composeId }: Props) => {
|
|||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const input = document.querySelector(
|
const input = document.querySelector(
|
||||||
'input[placeholder="Enter a path to watch (e.g., src/*, dist/*)"]',
|
'input[placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"]',
|
||||||
) as HTMLInputElement;
|
) as HTMLInputElement;
|
||||||
const value = input.value.trim();
|
const value = input.value.trim();
|
||||||
if (value) {
|
if (value) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { Puzzle, RefreshCw } from "lucide-react";
|
import { Loader2, Puzzle, RefreshCw } from "lucide-react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
|
||||||
@@ -66,36 +66,50 @@ export const ShowConvertedCompose = ({ composeId }: Props) => {
|
|||||||
Preview your docker-compose file with added domains. Note: At least
|
Preview your docker-compose file with added domains. Note: At least
|
||||||
one domain must be specified for this conversion to take effect.
|
one domain must be specified for this conversion to take effect.
|
||||||
</AlertBlock>
|
</AlertBlock>
|
||||||
|
{isLoading ? (
|
||||||
|
<div className="flex flex-row items-center justify-center min-h-[25rem] border p-4 rounded-md">
|
||||||
|
<Loader2 className="h-8 w-8 text-muted-foreground mb-2 animate-spin" />
|
||||||
|
</div>
|
||||||
|
) : compose?.length === 5 ? (
|
||||||
|
<div className="border p-4 rounded-md flex flex-col items-center justify-center min-h-[25rem]">
|
||||||
|
<Puzzle className="h-8 w-8 text-muted-foreground mb-2" />
|
||||||
|
<span className="text-muted-foreground">
|
||||||
|
No converted compose data available.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div className="flex flex-row gap-2 justify-end">
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
isLoading={isLoading}
|
||||||
|
onClick={() => {
|
||||||
|
mutateAsync({ composeId })
|
||||||
|
.then(() => {
|
||||||
|
refetch();
|
||||||
|
toast.success("Fetched source type");
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
toast.error("Error fetching source type", {
|
||||||
|
description: err.message,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Refresh <RefreshCw className="ml-2 h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-row gap-2 justify-end">
|
<pre>
|
||||||
<Button
|
<CodeEditor
|
||||||
variant="secondary"
|
value={compose || ""}
|
||||||
isLoading={isLoading}
|
language="yaml"
|
||||||
onClick={() => {
|
readOnly
|
||||||
mutateAsync({ composeId })
|
height="50rem"
|
||||||
.then(() => {
|
/>
|
||||||
refetch();
|
</pre>
|
||||||
toast.success("Fetched source type");
|
</>
|
||||||
})
|
)}
|
||||||
.catch((err) => {
|
|
||||||
toast.error("Error fetching source type", {
|
|
||||||
description: err.message,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Refresh <RefreshCw className="ml-2 h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
<CodeEditor
|
|
||||||
value={compose || ""}
|
|
||||||
language="yaml"
|
|
||||||
readOnly
|
|
||||||
height="50rem"
|
|
||||||
/>
|
|
||||||
</pre>
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -80,7 +80,13 @@ export default function Custom404({ statusCode, error }: Props) {
|
|||||||
<footer className="mt-auto text-center py-5">
|
<footer className="mt-auto text-center py-5">
|
||||||
<div className="max-w-[85rem] mx-auto px-4 sm:px-6 lg:px-8">
|
<div className="max-w-[85rem] mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<p className="text-sm text-gray-500">
|
<p className="text-sm text-gray-500">
|
||||||
Submit Log in issue on Github
|
<Link
|
||||||
|
href="https://github.com/Dokploy/dokploy/issues"
|
||||||
|
target="_blank"
|
||||||
|
className="underline hover:text-primary transition-colors"
|
||||||
|
>
|
||||||
|
Submit Log in issue on Github
|
||||||
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -217,12 +217,12 @@ const Service = (
|
|||||||
<div className="flex flex-row items-center justify-between w-full gap-4 overflow-x-scroll">
|
<div className="flex flex-row items-center justify-between w-full gap-4 overflow-x-scroll">
|
||||||
<TabsList
|
<TabsList
|
||||||
className={cn(
|
className={cn(
|
||||||
"lg:grid lg:w-fit max-md:overflow-y-scroll justify-start",
|
"xl:grid xl:w-fit max-md:overflow-y-scroll justify-start",
|
||||||
isCloud && data?.serverId
|
isCloud && data?.serverId
|
||||||
? "lg:grid-cols-9"
|
? "xl:grid-cols-9"
|
||||||
: data?.serverId
|
: data?.serverId
|
||||||
? "lg:grid-cols-8"
|
? "xl:grid-cols-8"
|
||||||
: "lg:grid-cols-9",
|
: "xl:grid-cols-9",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<TabsTrigger value="general">General</TabsTrigger>
|
<TabsTrigger value="general">General</TabsTrigger>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { execAsync } from "../process/execAsync";
|
|||||||
import { getS3Credentials, normalizeS3Path } from "./utils";
|
import { getS3Credentials, normalizeS3Path } from "./utils";
|
||||||
import { findDestinationById } from "@dokploy/server/services/destination";
|
import { findDestinationById } from "@dokploy/server/services/destination";
|
||||||
import { IS_CLOUD, paths } from "@dokploy/server/constants";
|
import { IS_CLOUD, paths } from "@dokploy/server/constants";
|
||||||
import { mkdtemp } from "node:fs/promises";
|
import { mkdtemp, rm } from "node:fs/promises";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { tmpdir } from "node:os";
|
import { tmpdir } from "node:os";
|
||||||
import {
|
import {
|
||||||
@@ -51,10 +51,20 @@ export const runWebServerBackup = async (backup: BackupSchedule) => {
|
|||||||
|
|
||||||
const postgresContainerId = containerId.trim();
|
const postgresContainerId = containerId.trim();
|
||||||
|
|
||||||
const postgresCommand = `docker exec ${postgresContainerId} pg_dump -v -Fc -U dokploy -d dokploy > '${tempDir}/database.sql'`;
|
// First dump the database inside the container
|
||||||
|
const dumpCommand = `docker exec ${postgresContainerId} pg_dump -v -Fc -U dokploy -d dokploy -f /tmp/database.sql`;
|
||||||
|
writeStream.write(`Running dump command: ${dumpCommand}\n`);
|
||||||
|
await execAsync(dumpCommand);
|
||||||
|
|
||||||
writeStream.write(`Running command: ${postgresCommand}\n`);
|
// Then copy the file from the container to host
|
||||||
await execAsync(postgresCommand);
|
const copyCommand = `docker cp ${postgresContainerId}:/tmp/database.sql ${tempDir}/database.sql`;
|
||||||
|
writeStream.write(`Copying database dump: ${copyCommand}\n`);
|
||||||
|
await execAsync(copyCommand);
|
||||||
|
|
||||||
|
// Clean up the temp file in the container
|
||||||
|
const cleanupCommand = `docker exec ${postgresContainerId} rm -f /tmp/database.sql`;
|
||||||
|
writeStream.write(`Cleaning up temp file: ${cleanupCommand}\n`);
|
||||||
|
await execAsync(cleanupCommand);
|
||||||
|
|
||||||
await execAsync(
|
await execAsync(
|
||||||
`rsync -av --ignore-errors ${BASE_PATH}/ ${tempDir}/filesystem/`,
|
`rsync -av --ignore-errors ${BASE_PATH}/ ${tempDir}/filesystem/`,
|
||||||
@@ -77,7 +87,11 @@ export const runWebServerBackup = async (backup: BackupSchedule) => {
|
|||||||
await updateDeploymentStatus(deployment.deploymentId, "done");
|
await updateDeploymentStatus(deployment.deploymentId, "done");
|
||||||
return true;
|
return true;
|
||||||
} finally {
|
} finally {
|
||||||
await execAsync(`rm -rf ${tempDir}`);
|
try {
|
||||||
|
await rm(tempDir, { recursive: true, force: true });
|
||||||
|
} catch (cleanupError) {
|
||||||
|
console.error("Cleanup error:", cleanupError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Backup error:", error);
|
console.error("Backup error:", error);
|
||||||
|
|||||||
Reference in New Issue
Block a user