mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Compare commits
12 Commits
711-custom
...
1888-docke
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04a10146ac | ||
|
|
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">
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user