mirror of
https://github.com/andwati/dokploy.git
synced 2026-11-01 01:32:16 +00:00
Merge branch 'canary' into 319-ability-to-roll-back-service-depoyments
This commit is contained in:
@@ -263,7 +263,7 @@ export const ShowImport = ({ composeId }: Props) => {
|
||||
{templateInfo.template.envs.map((env, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="rounded-lg border bg-card p-2 font-mono text-sm"
|
||||
className="rounded-lg truncate border bg-card p-2 font-mono text-sm"
|
||||
>
|
||||
{env}
|
||||
</div>
|
||||
@@ -328,7 +328,7 @@ export const ShowImport = ({ composeId }: Props) => {
|
||||
<DialogDescription>Mount File Content</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<ScrollArea className="h-[25vh] pr-4">
|
||||
<ScrollArea className="h-[45vh] pr-4">
|
||||
<CodeEditor
|
||||
language="yaml"
|
||||
value={selectedMount?.content || ""}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
@@ -63,10 +64,11 @@ const mySchema = z.discriminatedUnion("buildType", [
|
||||
publishDirectory: z.string().optional(),
|
||||
}),
|
||||
z.object({
|
||||
buildType: z.literal(BuildType.static),
|
||||
buildType: z.literal(BuildType.railpack),
|
||||
}),
|
||||
z.object({
|
||||
buildType: z.literal(BuildType.railpack),
|
||||
buildType: z.literal(BuildType.static),
|
||||
isStaticSpa: z.boolean().default(false),
|
||||
}),
|
||||
]);
|
||||
|
||||
@@ -83,6 +85,7 @@ interface ApplicationData {
|
||||
dockerBuildStage?: string | null;
|
||||
herokuVersion?: string | null;
|
||||
publishDirectory?: string | null;
|
||||
isStaticSpa?: boolean | null;
|
||||
}
|
||||
|
||||
function isValidBuildType(value: string): value is BuildType {
|
||||
@@ -115,16 +118,18 @@ const resetData = (data: ApplicationData): AddTemplate => {
|
||||
case BuildType.static:
|
||||
return {
|
||||
buildType: BuildType.static,
|
||||
isStaticSpa: data.isStaticSpa ?? false,
|
||||
};
|
||||
case BuildType.railpack:
|
||||
return {
|
||||
buildType: BuildType.railpack,
|
||||
};
|
||||
default:
|
||||
default: {
|
||||
const buildType = data.buildType as BuildType;
|
||||
return {
|
||||
buildType,
|
||||
} as AddTemplate;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -174,6 +179,8 @@ export const ShowBuildChooseForm = ({ applicationId }: Props) => {
|
||||
data.buildType === BuildType.heroku_buildpacks
|
||||
? data.herokuVersion
|
||||
: null,
|
||||
isStaticSpa:
|
||||
data.buildType === BuildType.static ? data.isStaticSpa : null,
|
||||
})
|
||||
.then(async () => {
|
||||
toast.success("Build type saved");
|
||||
@@ -364,6 +371,30 @@ export const ShowBuildChooseForm = ({ applicationId }: Props) => {
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{buildType === BuildType.static && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="isStaticSpa"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<div className="flex items-center gap-x-2 p-2">
|
||||
<Checkbox
|
||||
id="checkboxIsStaticSpa"
|
||||
value={String(field.value)}
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
<FormLabel htmlFor="checkboxIsStaticSpa">
|
||||
Single Page Application (SPA)
|
||||
</FormLabel>
|
||||
</div>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<div className="flex w-full justify-end">
|
||||
<Button isLoading={isLoading} type="submit">
|
||||
Save
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DateTooltip } from "@/components/shared/date-tooltip";
|
||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
@@ -9,12 +10,11 @@ import {
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { type RouterOutputs, api } from "@/utils/api";
|
||||
import { RocketIcon, Clock, Loader2 } from "lucide-react";
|
||||
import { Clock, Loader2, RocketIcon } from "lucide-react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { CancelQueues } from "./cancel-queues";
|
||||
import { RefreshToken } from "./refresh-token";
|
||||
import { ShowDeployment } from "./show-deployment";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
@@ -86,7 +86,7 @@ export const ShowDeployments = ({
|
||||
<span>Webhook URL: </span>
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<span className="break-all text-muted-foreground">
|
||||
{`${url}/api/deploy/${refreshToken}`}
|
||||
{`${url}/api/deploy${type === "compose" ? "/compose" : ""}/${refreshToken}`}
|
||||
</span>
|
||||
{(type === "application" || type === "compose") && (
|
||||
<RefreshToken id={id} type={type} />
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -6,8 +8,6 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { Copy, HelpCircle, Server } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { DialogAction } from "@/components/shared/dialog-action";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
@@ -7,6 +8,12 @@ import {
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { api } from "@/utils/api";
|
||||
import {
|
||||
CheckCircle2,
|
||||
@@ -21,17 +28,10 @@ import {
|
||||
XCircle,
|
||||
} from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { toast } from "sonner";
|
||||
import { AddDomain } from "./handle-domain";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { toast } from "sonner";
|
||||
import { DnsHelperModal } from "./dns-helper-modal";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { AddDomain } from "./handle-domain";
|
||||
|
||||
export type ValidationState = {
|
||||
isLoading: boolean;
|
||||
@@ -186,30 +186,19 @@ export const ShowDomains = ({ id, type }: Props) => {
|
||||
return (
|
||||
<Card
|
||||
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">
|
||||
<div className="flex flex-col gap-4">
|
||||
{/* Service & Domain Info */}
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex flex-col gap-2">
|
||||
{item.serviceName && (
|
||||
<Badge variant="outline" className="w-fit">
|
||||
<Server className="size-3 mr-1" />
|
||||
{item.serviceName}
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
<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">
|
||||
<div className="flex items-center justify-between flex-wrap gap-y-2">
|
||||
{item.serviceName && (
|
||||
<Badge variant="outline" className="w-fit">
|
||||
<Server className="size-3 mr-1" />
|
||||
{item.serviceName}
|
||||
</Badge>
|
||||
)}
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
{!item.host.includes("traefik.me") && (
|
||||
<DnsHelperModal
|
||||
domain={{
|
||||
@@ -266,6 +255,16 @@ export const ShowDomains = ({ id, type }: Props) => {
|
||||
</DialogAction>
|
||||
</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 */}
|
||||
<div className="flex flex-wrap gap-3">
|
||||
|
||||
+3
-3
@@ -136,7 +136,7 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => {
|
||||
enableSubmodules: data.enableSubmodules || false,
|
||||
});
|
||||
}
|
||||
}, [form.reset, data, form]);
|
||||
}, [form.reset, data?.applicationId, form]);
|
||||
|
||||
const onSubmit = async (data: BitbucketProvider) => {
|
||||
await mutateAsync({
|
||||
@@ -435,7 +435,7 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => {
|
||||
<FormControl>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
|
||||
placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
@@ -454,7 +454,7 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => {
|
||||
variant="secondary"
|
||||
onClick={() => {
|
||||
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;
|
||||
const value = input.value.trim();
|
||||
if (value) {
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ export const SaveDockerProvider = ({ applicationId }: Props) => {
|
||||
registryURL: data.registryUrl || "",
|
||||
});
|
||||
}
|
||||
}, [form.reset, data, form]);
|
||||
}, [form.reset, data?.applicationId, form]);
|
||||
|
||||
const onSubmit = async (values: DockerProvider) => {
|
||||
await mutateAsync({
|
||||
|
||||
@@ -17,13 +17,13 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { api } from "@/utils/api";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { KeyRoundIcon, LockIcon, X } from "lucide-react";
|
||||
@@ -262,7 +262,7 @@ export const SaveGitProvider = ({ applicationId }: Props) => {
|
||||
<FormControl>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
|
||||
placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
@@ -281,7 +281,7 @@ export const SaveGitProvider = ({ applicationId }: Props) => {
|
||||
variant="secondary"
|
||||
onClick={() => {
|
||||
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;
|
||||
const value = input.value.trim();
|
||||
if (value) {
|
||||
|
||||
+2
-2
@@ -158,7 +158,7 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => {
|
||||
enableSubmodules: data.enableSubmodules || false,
|
||||
});
|
||||
}
|
||||
}, [form.reset, data, form]);
|
||||
}, [form.reset, data?.applicationId, form]);
|
||||
|
||||
const onSubmit = async (data: GiteaProvider) => {
|
||||
await mutateAsync({
|
||||
@@ -470,7 +470,7 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => {
|
||||
<div className="flex gap-2">
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
|
||||
placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
|
||||
+2
-2
@@ -134,7 +134,7 @@ export const SaveGithubProvider = ({ applicationId }: Props) => {
|
||||
enableSubmodules: data.enableSubmodules ?? false,
|
||||
});
|
||||
}
|
||||
}, [form.reset, data, form]);
|
||||
}, [form.reset, data?.applicationId, form]);
|
||||
|
||||
const onSubmit = async (data: GithubProvider) => {
|
||||
await mutateAsync({
|
||||
@@ -474,7 +474,7 @@ export const SaveGithubProvider = ({ applicationId }: Props) => {
|
||||
<div className="flex gap-2">
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
|
||||
placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
|
||||
+2
-2
@@ -141,7 +141,7 @@ export const SaveGitlabProvider = ({ applicationId }: Props) => {
|
||||
enableSubmodules: data.enableSubmodules ?? false,
|
||||
});
|
||||
}
|
||||
}, [form.reset, data, form]);
|
||||
}, [form.reset, data?.applicationId, form]);
|
||||
|
||||
const onSubmit = async (data: GitlabProvider) => {
|
||||
await mutateAsync({
|
||||
@@ -452,7 +452,7 @@ export const SaveGitlabProvider = ({ applicationId }: Props) => {
|
||||
<div className="flex gap-2">
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
|
||||
placeholder="Enter a path to watch (e.g., src/**, dist/*.js)"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
|
||||
+1
-1
@@ -24,9 +24,9 @@ import {
|
||||
} from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { ShowModalLogs } from "../../settings/web-server/show-modal-logs";
|
||||
import { ShowDeploymentsModal } from "../deployments/show-deployments-modal";
|
||||
import { AddPreviewDomain } from "./add-preview-domain";
|
||||
import { ShowPreviewSettings } from "./show-preview-settings";
|
||||
import { ShowDeploymentsModal } from "../deployments/show-deployments-modal";
|
||||
|
||||
interface Props {
|
||||
applicationId: string;
|
||||
|
||||
@@ -1,40 +1,6 @@
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { CodeEditor } from "@/components/shared/code-editor";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
FormDescription,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { api } from "@/utils/api";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
Info,
|
||||
PlusCircle,
|
||||
PenBoxIcon,
|
||||
RefreshCw,
|
||||
DatabaseZap,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -42,10 +8,44 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { toast } from "sonner";
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { CodeEditor } from "@/components/shared/code-editor";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { api } from "@/utils/api";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import {
|
||||
DatabaseZap,
|
||||
Info,
|
||||
PenBoxIcon,
|
||||
PlusCircle,
|
||||
RefreshCw,
|
||||
} from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
import { z } from "zod";
|
||||
import type { CacheType } from "../domains/handle-domain";
|
||||
|
||||
export const commonCronExpressions = [
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
import { DialogAction } from "@/components/shared/dialog-action";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { api } from "@/utils/api";
|
||||
import { HandleSchedules } from "./handle-schedules";
|
||||
import {
|
||||
Clock,
|
||||
Play,
|
||||
Terminal,
|
||||
Trash2,
|
||||
ClipboardList,
|
||||
Loader2,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
@@ -16,16 +8,24 @@ import {
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { DialogAction } from "@/components/shared/dialog-action";
|
||||
import { api } from "@/utils/api";
|
||||
import {
|
||||
ClipboardList,
|
||||
Clock,
|
||||
Loader2,
|
||||
Play,
|
||||
Terminal,
|
||||
Trash2,
|
||||
} from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { ShowDeploymentsModal } from "../deployments/show-deployments-modal";
|
||||
import { HandleSchedules } from "./handle-schedules";
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
|
||||
Reference in New Issue
Block a user