mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
chore: remove application delete volume
This commit is contained in:
@@ -1,22 +1,21 @@
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { api } from "@/utils/api";
|
||||
@@ -29,158 +28,134 @@ import { toast } from "sonner";
|
||||
import { z } from "zod";
|
||||
|
||||
const deleteApplicationSchema = z.object({
|
||||
projectName: z.string().min(1, {
|
||||
message: "Application name is required",
|
||||
}),
|
||||
deleteVolumes: z.boolean(),
|
||||
projectName: z.string().min(1, {
|
||||
message: "Application name is required",
|
||||
}),
|
||||
});
|
||||
|
||||
type DeleteApplication = z.infer<typeof deleteApplicationSchema>;
|
||||
|
||||
interface Props {
|
||||
applicationId: string;
|
||||
applicationId: string;
|
||||
}
|
||||
|
||||
export const DeleteApplication = ({ applicationId }: Props) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const { mutateAsync, isLoading } = api.application.delete.useMutation();
|
||||
const { data } = api.application.one.useQuery(
|
||||
{ applicationId },
|
||||
{ enabled: !!applicationId },
|
||||
);
|
||||
const { push } = useRouter();
|
||||
const form = useForm<DeleteApplication>({
|
||||
defaultValues: {
|
||||
projectName: "",
|
||||
deleteVolumes: false,
|
||||
},
|
||||
resolver: zodResolver(deleteApplicationSchema),
|
||||
});
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const { mutateAsync, isLoading } = api.application.delete.useMutation();
|
||||
const { data } = api.application.one.useQuery(
|
||||
{ applicationId },
|
||||
{ enabled: !!applicationId }
|
||||
);
|
||||
const { push } = useRouter();
|
||||
const form = useForm<DeleteApplication>({
|
||||
defaultValues: {
|
||||
projectName: "",
|
||||
},
|
||||
resolver: zodResolver(deleteApplicationSchema),
|
||||
});
|
||||
|
||||
const onSubmit = async (formData: DeleteApplication) => {
|
||||
const expectedName = `${data?.name}/${data?.appName}`;
|
||||
if (formData.projectName === expectedName) {
|
||||
await mutateAsync({
|
||||
applicationId,
|
||||
deleteVolumes: formData.deleteVolumes,
|
||||
})
|
||||
.then((data) => {
|
||||
push(`/dashboard/project/${data?.projectId}`);
|
||||
toast.success("Application deleted successfully");
|
||||
setIsOpen(false);
|
||||
})
|
||||
.catch(() => {
|
||||
toast.error("Error deleting the application");
|
||||
});
|
||||
} else {
|
||||
form.setError("projectName", {
|
||||
message: "Project name does not match",
|
||||
});
|
||||
}
|
||||
};
|
||||
const onSubmit = async (formData: DeleteApplication) => {
|
||||
const expectedName = `${data?.name}/${data?.appName}`;
|
||||
if (formData.projectName === expectedName) {
|
||||
await mutateAsync({
|
||||
applicationId,
|
||||
})
|
||||
.then((data) => {
|
||||
push(`/dashboard/project/${data?.projectId}`);
|
||||
toast.success("Application deleted successfully");
|
||||
setIsOpen(false);
|
||||
})
|
||||
.catch(() => {
|
||||
toast.error("Error deleting the application");
|
||||
});
|
||||
} else {
|
||||
form.setError("projectName", {
|
||||
message: "Project name does not match",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="ghost" isLoading={isLoading}>
|
||||
<TrashIcon className="size-4 text-muted-foreground" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-h-screen overflow-y-auto sm:max-w-lg">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Are you absolutely sure?</DialogTitle>
|
||||
<DialogDescription>
|
||||
This action cannot be undone. This will permanently delete the
|
||||
application. If you are sure please enter the application name to
|
||||
delete this application.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="grid gap-4">
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
id="hook-form-delete-application"
|
||||
className="grid w-full gap-4"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="projectName"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex items-center gap-2">
|
||||
<span>
|
||||
To confirm, type{" "}
|
||||
<Badge
|
||||
className="p-2 rounded-md ml-1 mr-1 hover:border-primary hover:text-primary-foreground hover:bg-primary hover:cursor-pointer"
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
if (data?.name && data?.appName) {
|
||||
navigator.clipboard.writeText(
|
||||
`${data.name}/${data.appName}`,
|
||||
);
|
||||
toast.success("Copied to clipboard. Be careful!");
|
||||
}
|
||||
}}
|
||||
>
|
||||
{data?.name}/{data?.appName}
|
||||
<Copy className="h-4 w-4 ml-1 text-muted-foreground" />
|
||||
</Badge>{" "}
|
||||
in the box below:
|
||||
</span>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="Enter application name to confirm"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="deleteVolumes"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<div className="flex items-center">
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormLabel className="ml-2">
|
||||
Delete volumes associated with this compose
|
||||
</FormLabel>
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => {
|
||||
setIsOpen(false);
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
isLoading={isLoading}
|
||||
form="hook-form-delete-application"
|
||||
type="submit"
|
||||
variant="destructive"
|
||||
>
|
||||
Confirm
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="ghost" isLoading={isLoading}>
|
||||
<TrashIcon className="size-4 text-muted-foreground" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-h-screen overflow-y-auto sm:max-w-lg">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Are you absolutely sure?</DialogTitle>
|
||||
<DialogDescription>
|
||||
This action cannot be undone. This will permanently delete the
|
||||
application. If you are sure please enter the application name to
|
||||
delete this application.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="grid gap-4">
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
id="hook-form-delete-application"
|
||||
className="grid w-full gap-4"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="projectName"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex items-center gap-2">
|
||||
<span>
|
||||
To confirm, type{" "}
|
||||
<Badge
|
||||
className="p-2 rounded-md ml-1 mr-1 hover:border-primary hover:text-primary-foreground hover:bg-primary hover:cursor-pointer"
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
if (data?.name && data?.appName) {
|
||||
navigator.clipboard.writeText(
|
||||
`${data.name}/${data.appName}`
|
||||
);
|
||||
toast.success("Copied to clipboard. Be careful!");
|
||||
}
|
||||
}}
|
||||
>
|
||||
{data?.name}/{data?.appName}
|
||||
<Copy className="h-4 w-4 ml-1 text-muted-foreground" />
|
||||
</Badge>{" "}
|
||||
in the box below:
|
||||
</span>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="Enter application name to confirm"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => {
|
||||
setIsOpen(false);
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
isLoading={isLoading}
|
||||
form="hook-form-delete-application"
|
||||
type="submit"
|
||||
variant="destructive"
|
||||
>
|
||||
Confirm
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,11 @@
|
||||
import { relations } from "drizzle-orm";
|
||||
import {
|
||||
boolean,
|
||||
integer,
|
||||
json,
|
||||
pgEnum,
|
||||
pgTable,
|
||||
text,
|
||||
boolean,
|
||||
integer,
|
||||
json,
|
||||
pgEnum,
|
||||
pgTable,
|
||||
text,
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { createInsertSchema } from "drizzle-zod";
|
||||
import { nanoid } from "nanoid";
|
||||
@@ -28,498 +28,493 @@ import { sshKeys } from "./ssh-key";
|
||||
import { generateAppName } from "./utils";
|
||||
|
||||
export const sourceType = pgEnum("sourceType", [
|
||||
"docker",
|
||||
"git",
|
||||
"github",
|
||||
"gitlab",
|
||||
"bitbucket",
|
||||
"drop",
|
||||
"docker",
|
||||
"git",
|
||||
"github",
|
||||
"gitlab",
|
||||
"bitbucket",
|
||||
"drop",
|
||||
]);
|
||||
|
||||
export const buildType = pgEnum("buildType", [
|
||||
"dockerfile",
|
||||
"heroku_buildpacks",
|
||||
"paketo_buildpacks",
|
||||
"nixpacks",
|
||||
"static",
|
||||
"dockerfile",
|
||||
"heroku_buildpacks",
|
||||
"paketo_buildpacks",
|
||||
"nixpacks",
|
||||
"static",
|
||||
]);
|
||||
|
||||
// TODO: refactor this types
|
||||
export interface HealthCheckSwarm {
|
||||
Test?: string[] | undefined;
|
||||
Interval?: number | undefined;
|
||||
Timeout?: number | undefined;
|
||||
StartPeriod?: number | undefined;
|
||||
Retries?: number | undefined;
|
||||
Test?: string[] | undefined;
|
||||
Interval?: number | undefined;
|
||||
Timeout?: number | undefined;
|
||||
StartPeriod?: number | undefined;
|
||||
Retries?: number | undefined;
|
||||
}
|
||||
|
||||
export interface RestartPolicySwarm {
|
||||
Condition?: string | undefined;
|
||||
Delay?: number | undefined;
|
||||
MaxAttempts?: number | undefined;
|
||||
Window?: number | undefined;
|
||||
Condition?: string | undefined;
|
||||
Delay?: number | undefined;
|
||||
MaxAttempts?: number | undefined;
|
||||
Window?: number | undefined;
|
||||
}
|
||||
|
||||
export interface PlacementSwarm {
|
||||
Constraints?: string[] | undefined;
|
||||
Preferences?: Array<{ Spread: { SpreadDescriptor: string } }> | undefined;
|
||||
MaxReplicas?: number | undefined;
|
||||
Platforms?:
|
||||
| Array<{
|
||||
Architecture: string;
|
||||
OS: string;
|
||||
}>
|
||||
| undefined;
|
||||
Constraints?: string[] | undefined;
|
||||
Preferences?: Array<{ Spread: { SpreadDescriptor: string } }> | undefined;
|
||||
MaxReplicas?: number | undefined;
|
||||
Platforms?:
|
||||
| Array<{
|
||||
Architecture: string;
|
||||
OS: string;
|
||||
}>
|
||||
| undefined;
|
||||
}
|
||||
|
||||
export interface UpdateConfigSwarm {
|
||||
Parallelism: number;
|
||||
Delay?: number | undefined;
|
||||
FailureAction?: string | undefined;
|
||||
Monitor?: number | undefined;
|
||||
MaxFailureRatio?: number | undefined;
|
||||
Order: string;
|
||||
Parallelism: number;
|
||||
Delay?: number | undefined;
|
||||
FailureAction?: string | undefined;
|
||||
Monitor?: number | undefined;
|
||||
MaxFailureRatio?: number | undefined;
|
||||
Order: string;
|
||||
}
|
||||
|
||||
export interface ServiceModeSwarm {
|
||||
Replicated?: { Replicas?: number | undefined } | undefined;
|
||||
Global?: {} | undefined;
|
||||
ReplicatedJob?:
|
||||
| {
|
||||
MaxConcurrent?: number | undefined;
|
||||
TotalCompletions?: number | undefined;
|
||||
}
|
||||
| undefined;
|
||||
GlobalJob?: {} | undefined;
|
||||
Replicated?: { Replicas?: number | undefined } | undefined;
|
||||
Global?: {} | undefined;
|
||||
ReplicatedJob?:
|
||||
| {
|
||||
MaxConcurrent?: number | undefined;
|
||||
TotalCompletions?: number | undefined;
|
||||
}
|
||||
| undefined;
|
||||
GlobalJob?: {} | undefined;
|
||||
}
|
||||
|
||||
export interface NetworkSwarm {
|
||||
Target?: string | undefined;
|
||||
Aliases?: string[] | undefined;
|
||||
DriverOpts?: { [key: string]: string } | undefined;
|
||||
Target?: string | undefined;
|
||||
Aliases?: string[] | undefined;
|
||||
DriverOpts?: { [key: string]: string } | undefined;
|
||||
}
|
||||
|
||||
export interface LabelsSwarm {
|
||||
[name: string]: string;
|
||||
[name: string]: string;
|
||||
}
|
||||
|
||||
export const applications = pgTable("application", {
|
||||
applicationId: text("applicationId")
|
||||
.notNull()
|
||||
.primaryKey()
|
||||
.$defaultFn(() => nanoid()),
|
||||
name: text("name").notNull(),
|
||||
appName: text("appName")
|
||||
.notNull()
|
||||
.$defaultFn(() => generateAppName("app"))
|
||||
.unique(),
|
||||
description: text("description"),
|
||||
env: text("env"),
|
||||
previewEnv: text("previewEnv"),
|
||||
previewBuildArgs: text("previewBuildArgs"),
|
||||
previewWildcard: text("previewWildcard"),
|
||||
previewPort: integer("previewPort").default(3000),
|
||||
previewHttps: boolean("previewHttps").notNull().default(false),
|
||||
previewPath: text("previewPath").default("/"),
|
||||
previewCertificateType: certificateType("certificateType")
|
||||
.notNull()
|
||||
.default("none"),
|
||||
previewLimit: integer("previewLimit").default(3),
|
||||
isPreviewDeploymentsActive: boolean("isPreviewDeploymentsActive").default(
|
||||
false,
|
||||
),
|
||||
buildArgs: text("buildArgs"),
|
||||
memoryReservation: integer("memoryReservation"),
|
||||
memoryLimit: integer("memoryLimit"),
|
||||
cpuReservation: integer("cpuReservation"),
|
||||
cpuLimit: integer("cpuLimit"),
|
||||
title: text("title"),
|
||||
enabled: boolean("enabled"),
|
||||
subtitle: text("subtitle"),
|
||||
command: text("command"),
|
||||
refreshToken: text("refreshToken").$defaultFn(() => nanoid()),
|
||||
sourceType: sourceType("sourceType").notNull().default("github"),
|
||||
// Github
|
||||
repository: text("repository"),
|
||||
owner: text("owner"),
|
||||
branch: text("branch"),
|
||||
buildPath: text("buildPath").default("/"),
|
||||
autoDeploy: boolean("autoDeploy").$defaultFn(() => true),
|
||||
// Gitlab
|
||||
gitlabProjectId: integer("gitlabProjectId"),
|
||||
gitlabRepository: text("gitlabRepository"),
|
||||
gitlabOwner: text("gitlabOwner"),
|
||||
gitlabBranch: text("gitlabBranch"),
|
||||
gitlabBuildPath: text("gitlabBuildPath").default("/"),
|
||||
gitlabPathNamespace: text("gitlabPathNamespace"),
|
||||
// Bitbucket
|
||||
bitbucketRepository: text("bitbucketRepository"),
|
||||
bitbucketOwner: text("bitbucketOwner"),
|
||||
bitbucketBranch: text("bitbucketBranch"),
|
||||
bitbucketBuildPath: text("bitbucketBuildPath").default("/"),
|
||||
// Docker
|
||||
username: text("username"),
|
||||
password: text("password"),
|
||||
dockerImage: text("dockerImage"),
|
||||
registryUrl: text("registryUrl"),
|
||||
// Git
|
||||
customGitUrl: text("customGitUrl"),
|
||||
customGitBranch: text("customGitBranch"),
|
||||
customGitBuildPath: text("customGitBuildPath"),
|
||||
customGitSSHKeyId: text("customGitSSHKeyId").references(
|
||||
() => sshKeys.sshKeyId,
|
||||
{
|
||||
onDelete: "set null",
|
||||
},
|
||||
),
|
||||
dockerfile: text("dockerfile"),
|
||||
dockerContextPath: text("dockerContextPath"),
|
||||
dockerBuildStage: text("dockerBuildStage"),
|
||||
// Drop
|
||||
dropBuildPath: text("dropBuildPath"),
|
||||
// Docker swarm json
|
||||
healthCheckSwarm: json("healthCheckSwarm").$type<HealthCheckSwarm>(),
|
||||
restartPolicySwarm: json("restartPolicySwarm").$type<RestartPolicySwarm>(),
|
||||
placementSwarm: json("placementSwarm").$type<PlacementSwarm>(),
|
||||
updateConfigSwarm: json("updateConfigSwarm").$type<UpdateConfigSwarm>(),
|
||||
rollbackConfigSwarm: json("rollbackConfigSwarm").$type<UpdateConfigSwarm>(),
|
||||
modeSwarm: json("modeSwarm").$type<ServiceModeSwarm>(),
|
||||
labelsSwarm: json("labelsSwarm").$type<LabelsSwarm>(),
|
||||
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||
//
|
||||
replicas: integer("replicas").default(1).notNull(),
|
||||
applicationStatus: applicationStatus("applicationStatus")
|
||||
.notNull()
|
||||
.default("idle"),
|
||||
buildType: buildType("buildType").notNull().default("nixpacks"),
|
||||
herokuVersion: text("herokuVersion").default("24"),
|
||||
publishDirectory: text("publishDirectory"),
|
||||
createdAt: text("createdAt")
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date().toISOString()),
|
||||
registryId: text("registryId").references(() => registry.registryId, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
projectId: text("projectId")
|
||||
.notNull()
|
||||
.references(() => projects.projectId, { onDelete: "cascade" }),
|
||||
githubId: text("githubId").references(() => github.githubId, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
gitlabId: text("gitlabId").references(() => gitlab.gitlabId, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
bitbucketId: text("bitbucketId").references(() => bitbucket.bitbucketId, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
serverId: text("serverId").references(() => server.serverId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
applicationId: text("applicationId")
|
||||
.notNull()
|
||||
.primaryKey()
|
||||
.$defaultFn(() => nanoid()),
|
||||
name: text("name").notNull(),
|
||||
appName: text("appName")
|
||||
.notNull()
|
||||
.$defaultFn(() => generateAppName("app"))
|
||||
.unique(),
|
||||
description: text("description"),
|
||||
env: text("env"),
|
||||
previewEnv: text("previewEnv"),
|
||||
previewBuildArgs: text("previewBuildArgs"),
|
||||
previewWildcard: text("previewWildcard"),
|
||||
previewPort: integer("previewPort").default(3000),
|
||||
previewHttps: boolean("previewHttps").notNull().default(false),
|
||||
previewPath: text("previewPath").default("/"),
|
||||
previewCertificateType: certificateType("certificateType")
|
||||
.notNull()
|
||||
.default("none"),
|
||||
previewLimit: integer("previewLimit").default(3),
|
||||
isPreviewDeploymentsActive: boolean("isPreviewDeploymentsActive").default(
|
||||
false
|
||||
),
|
||||
buildArgs: text("buildArgs"),
|
||||
memoryReservation: integer("memoryReservation"),
|
||||
memoryLimit: integer("memoryLimit"),
|
||||
cpuReservation: integer("cpuReservation"),
|
||||
cpuLimit: integer("cpuLimit"),
|
||||
title: text("title"),
|
||||
enabled: boolean("enabled"),
|
||||
subtitle: text("subtitle"),
|
||||
command: text("command"),
|
||||
refreshToken: text("refreshToken").$defaultFn(() => nanoid()),
|
||||
sourceType: sourceType("sourceType").notNull().default("github"),
|
||||
// Github
|
||||
repository: text("repository"),
|
||||
owner: text("owner"),
|
||||
branch: text("branch"),
|
||||
buildPath: text("buildPath").default("/"),
|
||||
autoDeploy: boolean("autoDeploy").$defaultFn(() => true),
|
||||
// Gitlab
|
||||
gitlabProjectId: integer("gitlabProjectId"),
|
||||
gitlabRepository: text("gitlabRepository"),
|
||||
gitlabOwner: text("gitlabOwner"),
|
||||
gitlabBranch: text("gitlabBranch"),
|
||||
gitlabBuildPath: text("gitlabBuildPath").default("/"),
|
||||
gitlabPathNamespace: text("gitlabPathNamespace"),
|
||||
// Bitbucket
|
||||
bitbucketRepository: text("bitbucketRepository"),
|
||||
bitbucketOwner: text("bitbucketOwner"),
|
||||
bitbucketBranch: text("bitbucketBranch"),
|
||||
bitbucketBuildPath: text("bitbucketBuildPath").default("/"),
|
||||
// Docker
|
||||
username: text("username"),
|
||||
password: text("password"),
|
||||
dockerImage: text("dockerImage"),
|
||||
registryUrl: text("registryUrl"),
|
||||
// Git
|
||||
customGitUrl: text("customGitUrl"),
|
||||
customGitBranch: text("customGitBranch"),
|
||||
customGitBuildPath: text("customGitBuildPath"),
|
||||
customGitSSHKeyId: text("customGitSSHKeyId").references(
|
||||
() => sshKeys.sshKeyId,
|
||||
{
|
||||
onDelete: "set null",
|
||||
}
|
||||
),
|
||||
dockerfile: text("dockerfile"),
|
||||
dockerContextPath: text("dockerContextPath"),
|
||||
dockerBuildStage: text("dockerBuildStage"),
|
||||
// Drop
|
||||
dropBuildPath: text("dropBuildPath"),
|
||||
// Docker swarm json
|
||||
healthCheckSwarm: json("healthCheckSwarm").$type<HealthCheckSwarm>(),
|
||||
restartPolicySwarm: json("restartPolicySwarm").$type<RestartPolicySwarm>(),
|
||||
placementSwarm: json("placementSwarm").$type<PlacementSwarm>(),
|
||||
updateConfigSwarm: json("updateConfigSwarm").$type<UpdateConfigSwarm>(),
|
||||
rollbackConfigSwarm: json("rollbackConfigSwarm").$type<UpdateConfigSwarm>(),
|
||||
modeSwarm: json("modeSwarm").$type<ServiceModeSwarm>(),
|
||||
labelsSwarm: json("labelsSwarm").$type<LabelsSwarm>(),
|
||||
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||
//
|
||||
replicas: integer("replicas").default(1).notNull(),
|
||||
applicationStatus: applicationStatus("applicationStatus")
|
||||
.notNull()
|
||||
.default("idle"),
|
||||
buildType: buildType("buildType").notNull().default("nixpacks"),
|
||||
herokuVersion: text("herokuVersion").default("24"),
|
||||
publishDirectory: text("publishDirectory"),
|
||||
createdAt: text("createdAt")
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date().toISOString()),
|
||||
registryId: text("registryId").references(() => registry.registryId, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
projectId: text("projectId")
|
||||
.notNull()
|
||||
.references(() => projects.projectId, { onDelete: "cascade" }),
|
||||
githubId: text("githubId").references(() => github.githubId, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
gitlabId: text("gitlabId").references(() => gitlab.gitlabId, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
bitbucketId: text("bitbucketId").references(() => bitbucket.bitbucketId, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
serverId: text("serverId").references(() => server.serverId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
});
|
||||
|
||||
export const applicationsRelations = relations(
|
||||
applications,
|
||||
({ one, many }) => ({
|
||||
project: one(projects, {
|
||||
fields: [applications.projectId],
|
||||
references: [projects.projectId],
|
||||
}),
|
||||
deployments: many(deployments),
|
||||
customGitSSHKey: one(sshKeys, {
|
||||
fields: [applications.customGitSSHKeyId],
|
||||
references: [sshKeys.sshKeyId],
|
||||
}),
|
||||
domains: many(domains),
|
||||
mounts: many(mounts),
|
||||
redirects: many(redirects),
|
||||
security: many(security),
|
||||
ports: many(ports),
|
||||
registry: one(registry, {
|
||||
fields: [applications.registryId],
|
||||
references: [registry.registryId],
|
||||
}),
|
||||
github: one(github, {
|
||||
fields: [applications.githubId],
|
||||
references: [github.githubId],
|
||||
}),
|
||||
gitlab: one(gitlab, {
|
||||
fields: [applications.gitlabId],
|
||||
references: [gitlab.gitlabId],
|
||||
}),
|
||||
bitbucket: one(bitbucket, {
|
||||
fields: [applications.bitbucketId],
|
||||
references: [bitbucket.bitbucketId],
|
||||
}),
|
||||
server: one(server, {
|
||||
fields: [applications.serverId],
|
||||
references: [server.serverId],
|
||||
}),
|
||||
previewDeployments: many(previewDeployments),
|
||||
}),
|
||||
applications,
|
||||
({ one, many }) => ({
|
||||
project: one(projects, {
|
||||
fields: [applications.projectId],
|
||||
references: [projects.projectId],
|
||||
}),
|
||||
deployments: many(deployments),
|
||||
customGitSSHKey: one(sshKeys, {
|
||||
fields: [applications.customGitSSHKeyId],
|
||||
references: [sshKeys.sshKeyId],
|
||||
}),
|
||||
domains: many(domains),
|
||||
mounts: many(mounts),
|
||||
redirects: many(redirects),
|
||||
security: many(security),
|
||||
ports: many(ports),
|
||||
registry: one(registry, {
|
||||
fields: [applications.registryId],
|
||||
references: [registry.registryId],
|
||||
}),
|
||||
github: one(github, {
|
||||
fields: [applications.githubId],
|
||||
references: [github.githubId],
|
||||
}),
|
||||
gitlab: one(gitlab, {
|
||||
fields: [applications.gitlabId],
|
||||
references: [gitlab.gitlabId],
|
||||
}),
|
||||
bitbucket: one(bitbucket, {
|
||||
fields: [applications.bitbucketId],
|
||||
references: [bitbucket.bitbucketId],
|
||||
}),
|
||||
server: one(server, {
|
||||
fields: [applications.serverId],
|
||||
references: [server.serverId],
|
||||
}),
|
||||
previewDeployments: many(previewDeployments),
|
||||
})
|
||||
);
|
||||
|
||||
const HealthCheckSwarmSchema = z
|
||||
.object({
|
||||
Test: z.array(z.string()).optional(),
|
||||
Interval: z.number().optional(),
|
||||
Timeout: z.number().optional(),
|
||||
StartPeriod: z.number().optional(),
|
||||
Retries: z.number().optional(),
|
||||
})
|
||||
.strict();
|
||||
.object({
|
||||
Test: z.array(z.string()).optional(),
|
||||
Interval: z.number().optional(),
|
||||
Timeout: z.number().optional(),
|
||||
StartPeriod: z.number().optional(),
|
||||
Retries: z.number().optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
const RestartPolicySwarmSchema = z
|
||||
.object({
|
||||
Condition: z.string().optional(),
|
||||
Delay: z.number().optional(),
|
||||
MaxAttempts: z.number().optional(),
|
||||
Window: z.number().optional(),
|
||||
})
|
||||
.strict();
|
||||
.object({
|
||||
Condition: z.string().optional(),
|
||||
Delay: z.number().optional(),
|
||||
MaxAttempts: z.number().optional(),
|
||||
Window: z.number().optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
const PreferenceSchema = z
|
||||
.object({
|
||||
Spread: z.object({
|
||||
SpreadDescriptor: z.string(),
|
||||
}),
|
||||
})
|
||||
.strict();
|
||||
.object({
|
||||
Spread: z.object({
|
||||
SpreadDescriptor: z.string(),
|
||||
}),
|
||||
})
|
||||
.strict();
|
||||
|
||||
const PlatformSchema = z
|
||||
.object({
|
||||
Architecture: z.string(),
|
||||
OS: z.string(),
|
||||
})
|
||||
.strict();
|
||||
.object({
|
||||
Architecture: z.string(),
|
||||
OS: z.string(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
const PlacementSwarmSchema = z
|
||||
.object({
|
||||
Constraints: z.array(z.string()).optional(),
|
||||
Preferences: z.array(PreferenceSchema).optional(),
|
||||
MaxReplicas: z.number().optional(),
|
||||
Platforms: z.array(PlatformSchema).optional(),
|
||||
})
|
||||
.strict();
|
||||
.object({
|
||||
Constraints: z.array(z.string()).optional(),
|
||||
Preferences: z.array(PreferenceSchema).optional(),
|
||||
MaxReplicas: z.number().optional(),
|
||||
Platforms: z.array(PlatformSchema).optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
const UpdateConfigSwarmSchema = z
|
||||
.object({
|
||||
Parallelism: z.number(),
|
||||
Delay: z.number().optional(),
|
||||
FailureAction: z.string().optional(),
|
||||
Monitor: z.number().optional(),
|
||||
MaxFailureRatio: z.number().optional(),
|
||||
Order: z.string(),
|
||||
})
|
||||
.strict();
|
||||
.object({
|
||||
Parallelism: z.number(),
|
||||
Delay: z.number().optional(),
|
||||
FailureAction: z.string().optional(),
|
||||
Monitor: z.number().optional(),
|
||||
MaxFailureRatio: z.number().optional(),
|
||||
Order: z.string(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
const ReplicatedSchema = z
|
||||
.object({
|
||||
Replicas: z.number().optional(),
|
||||
})
|
||||
.strict();
|
||||
.object({
|
||||
Replicas: z.number().optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
const ReplicatedJobSchema = z
|
||||
.object({
|
||||
MaxConcurrent: z.number().optional(),
|
||||
TotalCompletions: z.number().optional(),
|
||||
})
|
||||
.strict();
|
||||
.object({
|
||||
MaxConcurrent: z.number().optional(),
|
||||
TotalCompletions: z.number().optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
const ServiceModeSwarmSchema = z
|
||||
.object({
|
||||
Replicated: ReplicatedSchema.optional(),
|
||||
Global: z.object({}).optional(),
|
||||
ReplicatedJob: ReplicatedJobSchema.optional(),
|
||||
GlobalJob: z.object({}).optional(),
|
||||
})
|
||||
.strict();
|
||||
.object({
|
||||
Replicated: ReplicatedSchema.optional(),
|
||||
Global: z.object({}).optional(),
|
||||
ReplicatedJob: ReplicatedJobSchema.optional(),
|
||||
GlobalJob: z.object({}).optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
const NetworkSwarmSchema = z.array(
|
||||
z
|
||||
.object({
|
||||
Target: z.string().optional(),
|
||||
Aliases: z.array(z.string()).optional(),
|
||||
DriverOpts: z.object({}).optional(),
|
||||
})
|
||||
.strict(),
|
||||
z
|
||||
.object({
|
||||
Target: z.string().optional(),
|
||||
Aliases: z.array(z.string()).optional(),
|
||||
DriverOpts: z.object({}).optional(),
|
||||
})
|
||||
.strict()
|
||||
);
|
||||
|
||||
const LabelsSwarmSchema = z.record(z.string());
|
||||
|
||||
const createSchema = createInsertSchema(applications, {
|
||||
appName: z.string(),
|
||||
createdAt: z.string(),
|
||||
applicationId: z.string(),
|
||||
autoDeploy: z.boolean(),
|
||||
env: z.string().optional(),
|
||||
buildArgs: z.string().optional(),
|
||||
name: z.string().min(1),
|
||||
description: z.string().optional(),
|
||||
memoryReservation: z.number().optional(),
|
||||
memoryLimit: z.number().optional(),
|
||||
cpuReservation: z.number().optional(),
|
||||
cpuLimit: z.number().optional(),
|
||||
title: z.string().optional(),
|
||||
enabled: z.boolean().optional(),
|
||||
subtitle: z.string().optional(),
|
||||
dockerImage: z.string().optional(),
|
||||
username: z.string().optional(),
|
||||
isPreviewDeploymentsActive: z.boolean().optional(),
|
||||
password: z.string().optional(),
|
||||
registryUrl: z.string().optional(),
|
||||
customGitSSHKeyId: z.string().optional(),
|
||||
repository: z.string().optional(),
|
||||
dockerfile: z.string().optional(),
|
||||
branch: z.string().optional(),
|
||||
customGitBranch: z.string().optional(),
|
||||
customGitBuildPath: z.string().optional(),
|
||||
customGitUrl: z.string().optional(),
|
||||
buildPath: z.string().optional(),
|
||||
projectId: z.string(),
|
||||
sourceType: z.enum(["github", "docker", "git"]).optional(),
|
||||
applicationStatus: z.enum(["idle", "running", "done", "error"]),
|
||||
buildType: z.enum([
|
||||
"dockerfile",
|
||||
"heroku_buildpacks",
|
||||
"paketo_buildpacks",
|
||||
"nixpacks",
|
||||
"static",
|
||||
]),
|
||||
herokuVersion: z.string().optional(),
|
||||
publishDirectory: z.string().optional(),
|
||||
owner: z.string(),
|
||||
healthCheckSwarm: HealthCheckSwarmSchema.nullable(),
|
||||
restartPolicySwarm: RestartPolicySwarmSchema.nullable(),
|
||||
placementSwarm: PlacementSwarmSchema.nullable(),
|
||||
updateConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||
rollbackConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||
modeSwarm: ServiceModeSwarmSchema.nullable(),
|
||||
labelsSwarm: LabelsSwarmSchema.nullable(),
|
||||
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||
previewPort: z.number().optional(),
|
||||
previewEnv: z.string().optional(),
|
||||
previewBuildArgs: z.string().optional(),
|
||||
previewWildcard: z.string().optional(),
|
||||
previewLimit: z.number().optional(),
|
||||
previewHttps: z.boolean().optional(),
|
||||
previewPath: z.string().optional(),
|
||||
previewCertificateType: z.enum(["letsencrypt", "none"]).optional(),
|
||||
appName: z.string(),
|
||||
createdAt: z.string(),
|
||||
applicationId: z.string(),
|
||||
autoDeploy: z.boolean(),
|
||||
env: z.string().optional(),
|
||||
buildArgs: z.string().optional(),
|
||||
name: z.string().min(1),
|
||||
description: z.string().optional(),
|
||||
memoryReservation: z.number().optional(),
|
||||
memoryLimit: z.number().optional(),
|
||||
cpuReservation: z.number().optional(),
|
||||
cpuLimit: z.number().optional(),
|
||||
title: z.string().optional(),
|
||||
enabled: z.boolean().optional(),
|
||||
subtitle: z.string().optional(),
|
||||
dockerImage: z.string().optional(),
|
||||
username: z.string().optional(),
|
||||
isPreviewDeploymentsActive: z.boolean().optional(),
|
||||
password: z.string().optional(),
|
||||
registryUrl: z.string().optional(),
|
||||
customGitSSHKeyId: z.string().optional(),
|
||||
repository: z.string().optional(),
|
||||
dockerfile: z.string().optional(),
|
||||
branch: z.string().optional(),
|
||||
customGitBranch: z.string().optional(),
|
||||
customGitBuildPath: z.string().optional(),
|
||||
customGitUrl: z.string().optional(),
|
||||
buildPath: z.string().optional(),
|
||||
projectId: z.string(),
|
||||
sourceType: z.enum(["github", "docker", "git"]).optional(),
|
||||
applicationStatus: z.enum(["idle", "running", "done", "error"]),
|
||||
buildType: z.enum([
|
||||
"dockerfile",
|
||||
"heroku_buildpacks",
|
||||
"paketo_buildpacks",
|
||||
"nixpacks",
|
||||
"static",
|
||||
]),
|
||||
herokuVersion: z.string().optional(),
|
||||
publishDirectory: z.string().optional(),
|
||||
owner: z.string(),
|
||||
healthCheckSwarm: HealthCheckSwarmSchema.nullable(),
|
||||
restartPolicySwarm: RestartPolicySwarmSchema.nullable(),
|
||||
placementSwarm: PlacementSwarmSchema.nullable(),
|
||||
updateConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||
rollbackConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||
modeSwarm: ServiceModeSwarmSchema.nullable(),
|
||||
labelsSwarm: LabelsSwarmSchema.nullable(),
|
||||
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||
previewPort: z.number().optional(),
|
||||
previewEnv: z.string().optional(),
|
||||
previewBuildArgs: z.string().optional(),
|
||||
previewWildcard: z.string().optional(),
|
||||
previewLimit: z.number().optional(),
|
||||
previewHttps: z.boolean().optional(),
|
||||
previewPath: z.string().optional(),
|
||||
previewCertificateType: z.enum(["letsencrypt", "none"]).optional(),
|
||||
});
|
||||
|
||||
export const apiCreateApplication = createSchema.pick({
|
||||
name: true,
|
||||
appName: true,
|
||||
description: true,
|
||||
projectId: true,
|
||||
serverId: true,
|
||||
name: true,
|
||||
appName: true,
|
||||
description: true,
|
||||
projectId: true,
|
||||
serverId: true,
|
||||
});
|
||||
|
||||
export const apiFindOneApplication = createSchema
|
||||
.pick({
|
||||
applicationId: true,
|
||||
})
|
||||
.required();
|
||||
.pick({
|
||||
applicationId: true,
|
||||
})
|
||||
.required();
|
||||
|
||||
export const apiReloadApplication = createSchema
|
||||
.pick({
|
||||
appName: true,
|
||||
applicationId: true,
|
||||
})
|
||||
.required();
|
||||
.pick({
|
||||
appName: true,
|
||||
applicationId: true,
|
||||
})
|
||||
.required();
|
||||
|
||||
export const apiSaveBuildType = createSchema
|
||||
.pick({
|
||||
applicationId: true,
|
||||
buildType: true,
|
||||
dockerfile: true,
|
||||
dockerContextPath: true,
|
||||
dockerBuildStage: true,
|
||||
herokuVersion: true,
|
||||
})
|
||||
.required()
|
||||
.merge(createSchema.pick({ publishDirectory: true }));
|
||||
.pick({
|
||||
applicationId: true,
|
||||
buildType: true,
|
||||
dockerfile: true,
|
||||
dockerContextPath: true,
|
||||
dockerBuildStage: true,
|
||||
herokuVersion: true,
|
||||
})
|
||||
.required()
|
||||
.merge(createSchema.pick({ publishDirectory: true }));
|
||||
|
||||
export const apiSaveGithubProvider = createSchema
|
||||
.pick({
|
||||
applicationId: true,
|
||||
repository: true,
|
||||
branch: true,
|
||||
owner: true,
|
||||
buildPath: true,
|
||||
githubId: true,
|
||||
})
|
||||
.required();
|
||||
.pick({
|
||||
applicationId: true,
|
||||
repository: true,
|
||||
branch: true,
|
||||
owner: true,
|
||||
buildPath: true,
|
||||
githubId: true,
|
||||
})
|
||||
.required();
|
||||
|
||||
export const apiSaveGitlabProvider = createSchema
|
||||
.pick({
|
||||
applicationId: true,
|
||||
gitlabBranch: true,
|
||||
gitlabBuildPath: true,
|
||||
gitlabOwner: true,
|
||||
gitlabRepository: true,
|
||||
gitlabId: true,
|
||||
gitlabProjectId: true,
|
||||
gitlabPathNamespace: true,
|
||||
})
|
||||
.required();
|
||||
.pick({
|
||||
applicationId: true,
|
||||
gitlabBranch: true,
|
||||
gitlabBuildPath: true,
|
||||
gitlabOwner: true,
|
||||
gitlabRepository: true,
|
||||
gitlabId: true,
|
||||
gitlabProjectId: true,
|
||||
gitlabPathNamespace: true,
|
||||
})
|
||||
.required();
|
||||
|
||||
export const apiSaveBitbucketProvider = createSchema
|
||||
.pick({
|
||||
bitbucketBranch: true,
|
||||
bitbucketBuildPath: true,
|
||||
bitbucketOwner: true,
|
||||
bitbucketRepository: true,
|
||||
bitbucketId: true,
|
||||
applicationId: true,
|
||||
})
|
||||
.required();
|
||||
.pick({
|
||||
bitbucketBranch: true,
|
||||
bitbucketBuildPath: true,
|
||||
bitbucketOwner: true,
|
||||
bitbucketRepository: true,
|
||||
bitbucketId: true,
|
||||
applicationId: true,
|
||||
})
|
||||
.required();
|
||||
|
||||
export const apiSaveDockerProvider = createSchema
|
||||
.pick({
|
||||
dockerImage: true,
|
||||
applicationId: true,
|
||||
username: true,
|
||||
password: true,
|
||||
registryUrl: true,
|
||||
})
|
||||
.required();
|
||||
.pick({
|
||||
dockerImage: true,
|
||||
applicationId: true,
|
||||
username: true,
|
||||
password: true,
|
||||
registryUrl: true,
|
||||
})
|
||||
.required();
|
||||
|
||||
export const apiSaveGitProvider = createSchema
|
||||
.pick({
|
||||
customGitBranch: true,
|
||||
applicationId: true,
|
||||
customGitBuildPath: true,
|
||||
customGitUrl: true,
|
||||
})
|
||||
.required()
|
||||
.merge(
|
||||
createSchema.pick({
|
||||
customGitSSHKeyId: true,
|
||||
}),
|
||||
);
|
||||
.pick({
|
||||
customGitBranch: true,
|
||||
applicationId: true,
|
||||
customGitBuildPath: true,
|
||||
customGitUrl: true,
|
||||
})
|
||||
.required()
|
||||
.merge(
|
||||
createSchema.pick({
|
||||
customGitSSHKeyId: true,
|
||||
})
|
||||
);
|
||||
|
||||
export const apiSaveEnvironmentVariables = createSchema
|
||||
.pick({
|
||||
applicationId: true,
|
||||
env: true,
|
||||
buildArgs: true,
|
||||
})
|
||||
.required();
|
||||
.pick({
|
||||
applicationId: true,
|
||||
env: true,
|
||||
buildArgs: true,
|
||||
})
|
||||
.required();
|
||||
|
||||
export const apiFindMonitoringStats = createSchema
|
||||
.pick({
|
||||
appName: true,
|
||||
})
|
||||
.required();
|
||||
.pick({
|
||||
appName: true,
|
||||
})
|
||||
.required();
|
||||
|
||||
export const apiUpdateApplication = createSchema
|
||||
.partial()
|
||||
.extend({
|
||||
applicationId: z.string().min(1),
|
||||
})
|
||||
.omit({ serverId: true });
|
||||
|
||||
export const apiDeleteApplication = z.object({
|
||||
applicationId: z.string().min(1),
|
||||
deleteVolumes: z.boolean(),
|
||||
});
|
||||
.partial()
|
||||
.extend({
|
||||
applicationId: z.string().min(1),
|
||||
})
|
||||
.omit({ serverId: true });
|
||||
|
||||
Reference in New Issue
Block a user