mirror of
https://github.com/andwati/dokploy.git
synced 2026-11-10 22:15:16 +00:00
feat(cluster-settings): refactor cluster settings components to support multiple database types and add new swarm configuration fields
This commit is contained in:
+41
-19
@@ -1,3 +1,9 @@
|
|||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { HelpCircle, Settings } from "lucide-react";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import { z } from "zod";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { CodeEditor } from "@/components/shared/code-editor";
|
import { CodeEditor } from "@/components/shared/code-editor";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -26,12 +32,6 @@ import {
|
|||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
|
||||||
import { HelpCircle, Settings } from "lucide-react";
|
|
||||||
import { useEffect } from "react";
|
|
||||||
import { useForm } from "react-hook-form";
|
|
||||||
import { toast } from "sonner";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
const HealthCheckSwarmSchema = z
|
const HealthCheckSwarmSchema = z
|
||||||
.object({
|
.object({
|
||||||
@@ -181,21 +181,38 @@ const addSwarmSettings = z.object({
|
|||||||
type AddSwarmSettings = z.infer<typeof addSwarmSettings>;
|
type AddSwarmSettings = z.infer<typeof addSwarmSettings>;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
applicationId: string;
|
id: string;
|
||||||
|
type: "postgres" | "mariadb" | "mongo" | "mysql" | "redis" | "application";
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AddSwarmSettings = ({ applicationId }: Props) => {
|
export const AddSwarmSettings = ({ id, type }: Props) => {
|
||||||
const { data, refetch } = api.application.one.useQuery(
|
const queryMap = {
|
||||||
{
|
postgres: () =>
|
||||||
applicationId,
|
api.postgres.one.useQuery({ postgresId: id }, { enabled: !!id }),
|
||||||
},
|
redis: () => api.redis.one.useQuery({ redisId: id }, { enabled: !!id }),
|
||||||
{
|
mysql: () => api.mysql.one.useQuery({ mysqlId: id }, { enabled: !!id }),
|
||||||
enabled: !!applicationId,
|
mariadb: () =>
|
||||||
},
|
api.mariadb.one.useQuery({ mariadbId: id }, { enabled: !!id }),
|
||||||
);
|
application: () =>
|
||||||
|
api.application.one.useQuery({ applicationId: id }, { enabled: !!id }),
|
||||||
|
mongo: () => api.mongo.one.useQuery({ mongoId: id }, { enabled: !!id }),
|
||||||
|
};
|
||||||
|
const { data, refetch } = queryMap[type]
|
||||||
|
? queryMap[type]()
|
||||||
|
: api.mongo.one.useQuery({ mongoId: id }, { enabled: !!id });
|
||||||
|
|
||||||
const { mutateAsync, isError, error, isLoading } =
|
const mutationMap = {
|
||||||
api.application.update.useMutation();
|
postgres: () => api.postgres.update.useMutation(),
|
||||||
|
redis: () => api.redis.update.useMutation(),
|
||||||
|
mysql: () => api.mysql.update.useMutation(),
|
||||||
|
mariadb: () => api.mariadb.update.useMutation(),
|
||||||
|
application: () => api.application.update.useMutation(),
|
||||||
|
mongo: () => api.mongo.update.useMutation(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const { mutateAsync, isError, error, isLoading } = mutationMap[type]
|
||||||
|
? mutationMap[type]()
|
||||||
|
: api.mongo.update.useMutation();
|
||||||
|
|
||||||
const form = useForm<AddSwarmSettings>({
|
const form = useForm<AddSwarmSettings>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@@ -244,7 +261,12 @@ export const AddSwarmSettings = ({ applicationId }: Props) => {
|
|||||||
|
|
||||||
const onSubmit = async (data: AddSwarmSettings) => {
|
const onSubmit = async (data: AddSwarmSettings) => {
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
applicationId,
|
applicationId: id || "",
|
||||||
|
postgresId: id || "",
|
||||||
|
redisId: id || "",
|
||||||
|
mysqlId: id || "",
|
||||||
|
mariadbId: id || "",
|
||||||
|
mongoId: id || "",
|
||||||
healthCheckSwarm: data.healthCheckSwarm,
|
healthCheckSwarm: data.healthCheckSwarm,
|
||||||
restartPolicySwarm: data.restartPolicySwarm,
|
restartPolicySwarm: data.restartPolicySwarm,
|
||||||
placementSwarm: data.placementSwarm,
|
placementSwarm: data.placementSwarm,
|
||||||
|
|||||||
+119
-81
@@ -1,3 +1,10 @@
|
|||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { Server } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import { z } from "zod";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
@@ -26,43 +33,57 @@ import {
|
|||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
|
||||||
import { Server } from "lucide-react";
|
|
||||||
import Link from "next/link";
|
|
||||||
import { useEffect } from "react";
|
|
||||||
import { useForm } from "react-hook-form";
|
|
||||||
import { toast } from "sonner";
|
|
||||||
import { z } from "zod";
|
|
||||||
import { AddSwarmSettings } from "./modify-swarm-settings";
|
import { AddSwarmSettings } from "./modify-swarm-settings";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
applicationId: string;
|
id: string;
|
||||||
|
type: "postgres" | "mariadb" | "mongo" | "mysql" | "redis" | "application";
|
||||||
}
|
}
|
||||||
|
|
||||||
const AddRedirectchema = z.object({
|
const AddRedirectchema = z.object({
|
||||||
replicas: z.number().min(1, "Replicas must be at least 1"),
|
replicas: z.number().min(1, "Replicas must be at least 1"),
|
||||||
registryId: z.string(),
|
registryId: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
type AddCommand = z.infer<typeof AddRedirectchema>;
|
type AddCommand = z.infer<typeof AddRedirectchema>;
|
||||||
|
|
||||||
export const ShowClusterSettings = ({ applicationId }: Props) => {
|
export const ShowClusterSettings = ({ id, type }: Props) => {
|
||||||
const { data } = api.application.one.useQuery(
|
const queryMap = {
|
||||||
{
|
postgres: () =>
|
||||||
applicationId,
|
api.postgres.one.useQuery({ postgresId: id }, { enabled: !!id }),
|
||||||
},
|
redis: () => api.redis.one.useQuery({ redisId: id }, { enabled: !!id }),
|
||||||
{ enabled: !!applicationId },
|
mysql: () => api.mysql.one.useQuery({ mysqlId: id }, { enabled: !!id }),
|
||||||
);
|
mariadb: () =>
|
||||||
|
api.mariadb.one.useQuery({ mariadbId: id }, { enabled: !!id }),
|
||||||
|
application: () =>
|
||||||
|
api.application.one.useQuery({ applicationId: id }, { enabled: !!id }),
|
||||||
|
mongo: () => api.mongo.one.useQuery({ mongoId: id }, { enabled: !!id }),
|
||||||
|
};
|
||||||
|
const { data, refetch } = queryMap[type]
|
||||||
|
? queryMap[type]()
|
||||||
|
: api.mongo.one.useQuery({ mongoId: id }, { enabled: !!id });
|
||||||
const { data: registries } = api.registry.all.useQuery();
|
const { data: registries } = api.registry.all.useQuery();
|
||||||
|
|
||||||
const utils = api.useUtils();
|
const mutationMap = {
|
||||||
|
postgres: () => api.postgres.update.useMutation(),
|
||||||
|
redis: () => api.redis.update.useMutation(),
|
||||||
|
mysql: () => api.mysql.update.useMutation(),
|
||||||
|
mariadb: () => api.mariadb.update.useMutation(),
|
||||||
|
application: () => api.application.update.useMutation(),
|
||||||
|
mongo: () => api.mongo.update.useMutation(),
|
||||||
|
};
|
||||||
|
|
||||||
const { mutateAsync, isLoading } = api.application.update.useMutation();
|
const { mutateAsync, isLoading } = mutationMap[type]
|
||||||
|
? mutationMap[type]()
|
||||||
|
: api.mongo.update.useMutation();
|
||||||
|
|
||||||
const form = useForm<AddCommand>({
|
const form = useForm<AddCommand>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
registryId: data?.registryId || "",
|
...(type === "application" && "registryId" in data
|
||||||
|
? {
|
||||||
|
registryId: data?.registryId || "",
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
replicas: data?.replicas || 1,
|
replicas: data?.replicas || 1,
|
||||||
},
|
},
|
||||||
resolver: zodResolver(AddRedirectchema),
|
resolver: zodResolver(AddRedirectchema),
|
||||||
@@ -71,26 +92,39 @@ export const ShowClusterSettings = ({ applicationId }: Props) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data?.command) {
|
if (data?.command) {
|
||||||
form.reset({
|
form.reset({
|
||||||
registryId: data?.registryId || "",
|
...(type === "application" && "registryId" in data
|
||||||
|
? {
|
||||||
|
registryId: data?.registryId || "",
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
replicas: data?.replicas || 1,
|
replicas: data?.replicas || 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [form, form.reset, form.formState.isSubmitSuccessful, data?.command]);
|
}, [form, form.reset, form.formState.isSubmitSuccessful, data?.command]);
|
||||||
|
|
||||||
|
console.log(form.formState.errors);
|
||||||
|
|
||||||
const onSubmit = async (data: AddCommand) => {
|
const onSubmit = async (data: AddCommand) => {
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
applicationId,
|
applicationId: id || "",
|
||||||
registryId:
|
postgresId: id || "",
|
||||||
data?.registryId === "none" || !data?.registryId
|
redisId: id || "",
|
||||||
? null
|
mysqlId: id || "",
|
||||||
: data?.registryId,
|
mariadbId: id || "",
|
||||||
|
mongoId: id || "",
|
||||||
|
...(type === "application"
|
||||||
|
? {
|
||||||
|
registryId:
|
||||||
|
data?.registryId === "none" || !data?.registryId
|
||||||
|
? null
|
||||||
|
: data?.registryId,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
replicas: data?.replicas,
|
replicas: data?.replicas,
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
toast.success("Command Updated");
|
toast.success("Command Updated");
|
||||||
await utils.application.one.invalidate({
|
await refetch();
|
||||||
applicationId,
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
toast.error("Error updating the command");
|
toast.error("Error updating the command");
|
||||||
@@ -106,7 +140,7 @@ export const ShowClusterSettings = ({ applicationId }: Props) => {
|
|||||||
Add the registry and the replicas of the application
|
Add the registry and the replicas of the application
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
<AddSwarmSettings applicationId={applicationId} />
|
<AddSwarmSettings id={id} type={type} />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="flex flex-col gap-4">
|
<CardContent className="flex flex-col gap-4">
|
||||||
<AlertBlock type="info">
|
<AlertBlock type="info">
|
||||||
@@ -144,58 +178,62 @@ export const ShowClusterSettings = ({ applicationId }: Props) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{registries && registries?.length === 0 ? (
|
{type === "application" && (
|
||||||
<div className="pt-10">
|
|
||||||
<div className="flex flex-col items-center gap-3">
|
|
||||||
<Server className="size-8 text-muted-foreground" />
|
|
||||||
<span className="text-base text-muted-foreground">
|
|
||||||
To use a cluster feature, you need to configure at least a
|
|
||||||
registry first. Please, go to{" "}
|
|
||||||
<Link
|
|
||||||
href="/dashboard/settings/cluster"
|
|
||||||
className="text-foreground"
|
|
||||||
>
|
|
||||||
Settings
|
|
||||||
</Link>{" "}
|
|
||||||
to do so.
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<>
|
<>
|
||||||
<FormField
|
{registries && registries?.length === 0 ? (
|
||||||
control={form.control}
|
<div className="pt-10">
|
||||||
name="registryId"
|
<div className="flex flex-col items-center gap-3">
|
||||||
render={({ field }) => (
|
<Server className="size-8 text-muted-foreground" />
|
||||||
<FormItem>
|
<span className="text-base text-muted-foreground">
|
||||||
<FormLabel>Select a registry</FormLabel>
|
To use a cluster feature, you need to configure at least
|
||||||
<Select
|
a registry first. Please, go to{" "}
|
||||||
onValueChange={field.onChange}
|
<Link
|
||||||
defaultValue={field.value}
|
href="/dashboard/settings/cluster"
|
||||||
>
|
className="text-foreground"
|
||||||
<SelectTrigger>
|
>
|
||||||
<SelectValue placeholder="Select a registry" />
|
Settings
|
||||||
</SelectTrigger>
|
</Link>{" "}
|
||||||
<SelectContent>
|
to do so.
|
||||||
<SelectGroup>
|
</span>
|
||||||
{registries?.map((registry) => (
|
</div>
|
||||||
<SelectItem
|
</div>
|
||||||
key={registry.registryId}
|
) : (
|
||||||
value={registry.registryId}
|
<>
|
||||||
>
|
<FormField
|
||||||
{registry.registryName}
|
control={form.control}
|
||||||
</SelectItem>
|
name="registryId"
|
||||||
))}
|
render={({ field }) => (
|
||||||
<SelectItem value={"none"}>None</SelectItem>
|
<FormItem>
|
||||||
<SelectLabel>
|
<FormLabel>Select a registry</FormLabel>
|
||||||
Registries ({registries?.length})
|
<Select
|
||||||
</SelectLabel>
|
onValueChange={field.onChange}
|
||||||
</SelectGroup>
|
defaultValue={field.value}
|
||||||
</SelectContent>
|
>
|
||||||
</Select>
|
<SelectTrigger>
|
||||||
</FormItem>
|
<SelectValue placeholder="Select a registry" />
|
||||||
)}
|
</SelectTrigger>
|
||||||
/>
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
{registries?.map((registry) => (
|
||||||
|
<SelectItem
|
||||||
|
key={registry.registryId}
|
||||||
|
value={registry.registryId}
|
||||||
|
>
|
||||||
|
{registry.registryName}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
<SelectItem value={"none"}>None</SelectItem>
|
||||||
|
<SelectLabel>
|
||||||
|
Registries ({registries?.length})
|
||||||
|
</SelectLabel>
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ShowResources } from "@/components/dashboard/application/advanced/show-resources";
|
import { ShowResources } from "@/components/dashboard/application/advanced/show-resources";
|
||||||
import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes/show-volumes";
|
import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes/show-volumes";
|
||||||
import { ShowCustomCommand } from "@/components/dashboard/postgres/advanced/show-custom-command";
|
import { ShowCustomCommand } from "@/components/dashboard/postgres/advanced/show-custom-command";
|
||||||
|
import { ShowClusterSettings } from "../application/advanced/cluster/show-cluster-settings";
|
||||||
import { RebuildDatabase } from "./rebuild-database";
|
import { RebuildDatabase } from "./rebuild-database";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -12,6 +13,7 @@ export const ShowDatabaseAdvancedSettings = ({ id, type }: Props) => {
|
|||||||
return (
|
return (
|
||||||
<div className="flex w-full flex-col gap-5">
|
<div className="flex w-full flex-col gap-5">
|
||||||
<ShowCustomCommand id={id} type={type} />
|
<ShowCustomCommand id={id} type={type} />
|
||||||
|
<ShowClusterSettings id={id} type={type} />
|
||||||
<ShowVolumes id={id} type={type} />
|
<ShowVolumes id={id} type={type} />
|
||||||
<ShowResources id={id} type={type} />
|
<ShowResources id={id} type={type} />
|
||||||
<RebuildDatabase id={id} type={type} />
|
<RebuildDatabase id={id} type={type} />
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
ALTER TABLE "postgres" ADD COLUMN "healthCheckSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "restartPolicySwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "placementSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "updateConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "rollbackConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "modeSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "labelsSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "networkSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "replicas" integer DEFAULT 1 NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "healthCheckSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "restartPolicySwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "placementSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "updateConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "rollbackConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "modeSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "labelsSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "networkSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "replicas" integer DEFAULT 1 NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "healthCheckSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "restartPolicySwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "placementSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "updateConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "rollbackConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "modeSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "labelsSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "networkSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "replicas" integer DEFAULT 1 NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "healthCheckSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "restartPolicySwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "placementSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "updateConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "rollbackConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "modeSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "labelsSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "networkSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "replicas" integer DEFAULT 1 NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "healthCheckSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "restartPolicySwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "placementSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "updateConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "rollbackConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "modeSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "labelsSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "networkSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "replicas" integer DEFAULT 1 NOT NULL;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -736,6 +736,13 @@
|
|||||||
"when": 1754207407121,
|
"when": 1754207407121,
|
||||||
"tag": "0104_omniscient_randall",
|
"tag": "0104_omniscient_randall",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 105,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1754259281559,
|
||||||
|
"tag": "0105_clumsy_quicksilver",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+18
-15
@@ -1,3 +1,17 @@
|
|||||||
|
import { validateRequest } from "@dokploy/server/lib/auth";
|
||||||
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
|
import copy from "copy-to-clipboard";
|
||||||
|
import { GlobeIcon, HelpCircle, ServerOff } from "lucide-react";
|
||||||
|
import type {
|
||||||
|
GetServerSidePropsContext,
|
||||||
|
InferGetServerSidePropsType,
|
||||||
|
} from "next";
|
||||||
|
import Head from "next/head";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { type ReactElement, useEffect, useState } from "react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import superjson from "superjson";
|
||||||
import { ShowClusterSettings } from "@/components/dashboard/application/advanced/cluster/show-cluster-settings";
|
import { ShowClusterSettings } from "@/components/dashboard/application/advanced/cluster/show-cluster-settings";
|
||||||
import { AddCommand } from "@/components/dashboard/application/advanced/general/add-command";
|
import { AddCommand } from "@/components/dashboard/application/advanced/general/add-command";
|
||||||
import { ShowPorts } from "@/components/dashboard/application/advanced/ports/show-port";
|
import { ShowPorts } from "@/components/dashboard/application/advanced/ports/show-port";
|
||||||
@@ -39,20 +53,6 @@ import {
|
|||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { validateRequest } from "@dokploy/server/lib/auth";
|
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
|
||||||
import copy from "copy-to-clipboard";
|
|
||||||
import { GlobeIcon, HelpCircle, ServerOff } from "lucide-react";
|
|
||||||
import type {
|
|
||||||
GetServerSidePropsContext,
|
|
||||||
InferGetServerSidePropsType,
|
|
||||||
} from "next";
|
|
||||||
import Head from "next/head";
|
|
||||||
import Link from "next/link";
|
|
||||||
import { useRouter } from "next/router";
|
|
||||||
import { type ReactElement, useEffect, useState } from "react";
|
|
||||||
import { toast } from "sonner";
|
|
||||||
import superjson from "superjson";
|
|
||||||
|
|
||||||
type TabState =
|
type TabState =
|
||||||
| "projects"
|
| "projects"
|
||||||
@@ -345,7 +345,10 @@ const Service = (
|
|||||||
<TabsContent value="advanced">
|
<TabsContent value="advanced">
|
||||||
<div className="flex flex-col gap-4 pt-2.5">
|
<div className="flex flex-col gap-4 pt-2.5">
|
||||||
<AddCommand applicationId={applicationId} />
|
<AddCommand applicationId={applicationId} />
|
||||||
<ShowClusterSettings applicationId={applicationId} />
|
<ShowClusterSettings
|
||||||
|
id={applicationId}
|
||||||
|
type="application"
|
||||||
|
/>
|
||||||
|
|
||||||
<ShowResources id={applicationId} type="application" />
|
<ShowResources id={applicationId} type="application" />
|
||||||
<ShowVolumes id={applicationId} type="application" />
|
<ShowVolumes id={applicationId} type="application" />
|
||||||
|
|||||||
@@ -24,7 +24,25 @@ import { redirects } from "./redirects";
|
|||||||
import { registry } from "./registry";
|
import { registry } from "./registry";
|
||||||
import { security } from "./security";
|
import { security } from "./security";
|
||||||
import { server } from "./server";
|
import { server } from "./server";
|
||||||
import { applicationStatus, certificateType, triggerType } from "./shared";
|
import {
|
||||||
|
applicationStatus,
|
||||||
|
certificateType,
|
||||||
|
type HealthCheckSwarm,
|
||||||
|
HealthCheckSwarmSchema,
|
||||||
|
type LabelsSwarm,
|
||||||
|
LabelsSwarmSchema,
|
||||||
|
type NetworkSwarm,
|
||||||
|
NetworkSwarmSchema,
|
||||||
|
type PlacementSwarm,
|
||||||
|
PlacementSwarmSchema,
|
||||||
|
type RestartPolicySwarm,
|
||||||
|
RestartPolicySwarmSchema,
|
||||||
|
type ServiceModeSwarm,
|
||||||
|
ServiceModeSwarmSchema,
|
||||||
|
triggerType,
|
||||||
|
type UpdateConfigSwarm,
|
||||||
|
UpdateConfigSwarmSchema,
|
||||||
|
} from "./shared";
|
||||||
import { sshKeys } from "./ssh-key";
|
import { sshKeys } from "./ssh-key";
|
||||||
import { generateAppName } from "./utils";
|
import { generateAppName } from "./utils";
|
||||||
export const sourceType = pgEnum("sourceType", [
|
export const sourceType = pgEnum("sourceType", [
|
||||||
@@ -46,64 +64,6 @@ export const buildType = pgEnum("buildType", [
|
|||||||
"railpack",
|
"railpack",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export interface HealthCheckSwarm {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PlacementSwarm {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ServiceModeSwarm {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LabelsSwarm {
|
|
||||||
[name: string]: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const applications = pgTable("application", {
|
export const applications = pgTable("application", {
|
||||||
applicationId: text("applicationId")
|
applicationId: text("applicationId")
|
||||||
.notNull()
|
.notNull()
|
||||||
@@ -283,94 +243,6 @@ export const applicationsRelations = relations(
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
const RestartPolicySwarmSchema = z
|
|
||||||
.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();
|
|
||||||
|
|
||||||
const PlatformSchema = z
|
|
||||||
.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();
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
const ReplicatedSchema = z
|
|
||||||
.object({
|
|
||||||
Replicas: z.number().optional(),
|
|
||||||
})
|
|
||||||
.strict();
|
|
||||||
|
|
||||||
const ReplicatedJobSchema = z
|
|
||||||
.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();
|
|
||||||
|
|
||||||
const NetworkSwarmSchema = z.array(
|
|
||||||
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, {
|
const createSchema = createInsertSchema(applications, {
|
||||||
appName: z.string(),
|
appName: z.string(),
|
||||||
createdAt: z.string(),
|
createdAt: z.string(),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
import { integer, pgTable, text } from "drizzle-orm/pg-core";
|
import { integer, json, pgTable, text } from "drizzle-orm/pg-core";
|
||||||
import { createInsertSchema } from "drizzle-zod";
|
import { createInsertSchema } from "drizzle-zod";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@@ -7,7 +7,23 @@ import { backups } from "./backups";
|
|||||||
import { mounts } from "./mount";
|
import { mounts } from "./mount";
|
||||||
import { projects } from "./project";
|
import { projects } from "./project";
|
||||||
import { server } from "./server";
|
import { server } from "./server";
|
||||||
import { applicationStatus } from "./shared";
|
import {
|
||||||
|
applicationStatus,
|
||||||
|
type HealthCheckSwarm,
|
||||||
|
HealthCheckSwarmSchema,
|
||||||
|
type LabelsSwarm,
|
||||||
|
LabelsSwarmSchema,
|
||||||
|
type NetworkSwarm,
|
||||||
|
NetworkSwarmSchema,
|
||||||
|
type PlacementSwarm,
|
||||||
|
PlacementSwarmSchema,
|
||||||
|
type RestartPolicySwarm,
|
||||||
|
RestartPolicySwarmSchema,
|
||||||
|
type ServiceModeSwarm,
|
||||||
|
ServiceModeSwarmSchema,
|
||||||
|
type UpdateConfigSwarm,
|
||||||
|
UpdateConfigSwarmSchema,
|
||||||
|
} from "./shared";
|
||||||
import { generateAppName } from "./utils";
|
import { generateAppName } from "./utils";
|
||||||
|
|
||||||
export const mariadb = pgTable("mariadb", {
|
export const mariadb = pgTable("mariadb", {
|
||||||
@@ -38,6 +54,15 @@ export const mariadb = pgTable("mariadb", {
|
|||||||
applicationStatus: applicationStatus("applicationStatus")
|
applicationStatus: applicationStatus("applicationStatus")
|
||||||
.notNull()
|
.notNull()
|
||||||
.default("idle"),
|
.default("idle"),
|
||||||
|
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(),
|
||||||
createdAt: text("createdAt")
|
createdAt: text("createdAt")
|
||||||
.notNull()
|
.notNull()
|
||||||
.$defaultFn(() => new Date().toISOString()),
|
.$defaultFn(() => new Date().toISOString()),
|
||||||
@@ -83,6 +108,14 @@ const createSchema = createInsertSchema(mariadb, {
|
|||||||
externalPort: z.number(),
|
externalPort: z.number(),
|
||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
serverId: z.string().optional(),
|
serverId: z.string().optional(),
|
||||||
|
healthCheckSwarm: HealthCheckSwarmSchema.nullable(),
|
||||||
|
restartPolicySwarm: RestartPolicySwarmSchema.nullable(),
|
||||||
|
placementSwarm: PlacementSwarmSchema.nullable(),
|
||||||
|
updateConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
rollbackConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
modeSwarm: ServiceModeSwarmSchema.nullable(),
|
||||||
|
labelsSwarm: LabelsSwarmSchema.nullable(),
|
||||||
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreateMariaDB = createSchema
|
export const apiCreateMariaDB = createSchema
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
import { boolean, integer, pgTable, text } from "drizzle-orm/pg-core";
|
import { boolean, integer, json, pgTable, text } from "drizzle-orm/pg-core";
|
||||||
import { createInsertSchema } from "drizzle-zod";
|
import { createInsertSchema } from "drizzle-zod";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@@ -7,7 +7,23 @@ import { backups } from "./backups";
|
|||||||
import { mounts } from "./mount";
|
import { mounts } from "./mount";
|
||||||
import { projects } from "./project";
|
import { projects } from "./project";
|
||||||
import { server } from "./server";
|
import { server } from "./server";
|
||||||
import { applicationStatus } from "./shared";
|
import {
|
||||||
|
applicationStatus,
|
||||||
|
type HealthCheckSwarm,
|
||||||
|
HealthCheckSwarmSchema,
|
||||||
|
type LabelsSwarm,
|
||||||
|
LabelsSwarmSchema,
|
||||||
|
type NetworkSwarm,
|
||||||
|
NetworkSwarmSchema,
|
||||||
|
type PlacementSwarm,
|
||||||
|
PlacementSwarmSchema,
|
||||||
|
type RestartPolicySwarm,
|
||||||
|
RestartPolicySwarmSchema,
|
||||||
|
type ServiceModeSwarm,
|
||||||
|
ServiceModeSwarmSchema,
|
||||||
|
type UpdateConfigSwarm,
|
||||||
|
UpdateConfigSwarmSchema,
|
||||||
|
} from "./shared";
|
||||||
import { generateAppName } from "./utils";
|
import { generateAppName } from "./utils";
|
||||||
|
|
||||||
export const mongo = pgTable("mongo", {
|
export const mongo = pgTable("mongo", {
|
||||||
@@ -34,6 +50,15 @@ export const mongo = pgTable("mongo", {
|
|||||||
applicationStatus: applicationStatus("applicationStatus")
|
applicationStatus: applicationStatus("applicationStatus")
|
||||||
.notNull()
|
.notNull()
|
||||||
.default("idle"),
|
.default("idle"),
|
||||||
|
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(),
|
||||||
createdAt: text("createdAt")
|
createdAt: text("createdAt")
|
||||||
.notNull()
|
.notNull()
|
||||||
.$defaultFn(() => new Date().toISOString()),
|
.$defaultFn(() => new Date().toISOString()),
|
||||||
@@ -79,6 +104,14 @@ const createSchema = createInsertSchema(mongo, {
|
|||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
serverId: z.string().optional(),
|
serverId: z.string().optional(),
|
||||||
replicaSets: z.boolean().default(false),
|
replicaSets: z.boolean().default(false),
|
||||||
|
healthCheckSwarm: HealthCheckSwarmSchema.nullable(),
|
||||||
|
restartPolicySwarm: RestartPolicySwarmSchema.nullable(),
|
||||||
|
placementSwarm: PlacementSwarmSchema.nullable(),
|
||||||
|
updateConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
rollbackConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
modeSwarm: ServiceModeSwarmSchema.nullable(),
|
||||||
|
labelsSwarm: LabelsSwarmSchema.nullable(),
|
||||||
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreateMongo = createSchema
|
export const apiCreateMongo = createSchema
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
import { integer, pgTable, text } from "drizzle-orm/pg-core";
|
import { integer, json, pgTable, text } from "drizzle-orm/pg-core";
|
||||||
import { createInsertSchema } from "drizzle-zod";
|
import { createInsertSchema } from "drizzle-zod";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@@ -7,7 +7,23 @@ import { backups } from "./backups";
|
|||||||
import { mounts } from "./mount";
|
import { mounts } from "./mount";
|
||||||
import { projects } from "./project";
|
import { projects } from "./project";
|
||||||
import { server } from "./server";
|
import { server } from "./server";
|
||||||
import { applicationStatus } from "./shared";
|
import {
|
||||||
|
applicationStatus,
|
||||||
|
type HealthCheckSwarm,
|
||||||
|
HealthCheckSwarmSchema,
|
||||||
|
type LabelsSwarm,
|
||||||
|
LabelsSwarmSchema,
|
||||||
|
type NetworkSwarm,
|
||||||
|
NetworkSwarmSchema,
|
||||||
|
type PlacementSwarm,
|
||||||
|
PlacementSwarmSchema,
|
||||||
|
type RestartPolicySwarm,
|
||||||
|
RestartPolicySwarmSchema,
|
||||||
|
type ServiceModeSwarm,
|
||||||
|
ServiceModeSwarmSchema,
|
||||||
|
type UpdateConfigSwarm,
|
||||||
|
UpdateConfigSwarmSchema,
|
||||||
|
} from "./shared";
|
||||||
import { generateAppName } from "./utils";
|
import { generateAppName } from "./utils";
|
||||||
|
|
||||||
export const mysql = pgTable("mysql", {
|
export const mysql = pgTable("mysql", {
|
||||||
@@ -36,6 +52,15 @@ export const mysql = pgTable("mysql", {
|
|||||||
applicationStatus: applicationStatus("applicationStatus")
|
applicationStatus: applicationStatus("applicationStatus")
|
||||||
.notNull()
|
.notNull()
|
||||||
.default("idle"),
|
.default("idle"),
|
||||||
|
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(),
|
||||||
createdAt: text("createdAt")
|
createdAt: text("createdAt")
|
||||||
.notNull()
|
.notNull()
|
||||||
.$defaultFn(() => new Date().toISOString()),
|
.$defaultFn(() => new Date().toISOString()),
|
||||||
@@ -81,6 +106,14 @@ const createSchema = createInsertSchema(mysql, {
|
|||||||
externalPort: z.number(),
|
externalPort: z.number(),
|
||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
serverId: z.string().optional(),
|
serverId: z.string().optional(),
|
||||||
|
healthCheckSwarm: HealthCheckSwarmSchema.nullable(),
|
||||||
|
restartPolicySwarm: RestartPolicySwarmSchema.nullable(),
|
||||||
|
placementSwarm: PlacementSwarmSchema.nullable(),
|
||||||
|
updateConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
rollbackConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
modeSwarm: ServiceModeSwarmSchema.nullable(),
|
||||||
|
labelsSwarm: LabelsSwarmSchema.nullable(),
|
||||||
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreateMySql = createSchema
|
export const apiCreateMySql = createSchema
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
import { integer, pgTable, text } from "drizzle-orm/pg-core";
|
import { integer, json, pgTable, text } from "drizzle-orm/pg-core";
|
||||||
import { createInsertSchema } from "drizzle-zod";
|
import { createInsertSchema } from "drizzle-zod";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@@ -7,7 +7,23 @@ import { backups } from "./backups";
|
|||||||
import { mounts } from "./mount";
|
import { mounts } from "./mount";
|
||||||
import { projects } from "./project";
|
import { projects } from "./project";
|
||||||
import { server } from "./server";
|
import { server } from "./server";
|
||||||
import { applicationStatus } from "./shared";
|
import {
|
||||||
|
applicationStatus,
|
||||||
|
type HealthCheckSwarm,
|
||||||
|
HealthCheckSwarmSchema,
|
||||||
|
type LabelsSwarm,
|
||||||
|
LabelsSwarmSchema,
|
||||||
|
type NetworkSwarm,
|
||||||
|
NetworkSwarmSchema,
|
||||||
|
type PlacementSwarm,
|
||||||
|
PlacementSwarmSchema,
|
||||||
|
type RestartPolicySwarm,
|
||||||
|
RestartPolicySwarmSchema,
|
||||||
|
type ServiceModeSwarm,
|
||||||
|
ServiceModeSwarmSchema,
|
||||||
|
type UpdateConfigSwarm,
|
||||||
|
UpdateConfigSwarmSchema,
|
||||||
|
} from "./shared";
|
||||||
import { generateAppName } from "./utils";
|
import { generateAppName } from "./utils";
|
||||||
|
|
||||||
export const postgres = pgTable("postgres", {
|
export const postgres = pgTable("postgres", {
|
||||||
@@ -35,6 +51,16 @@ export const postgres = pgTable("postgres", {
|
|||||||
applicationStatus: applicationStatus("applicationStatus")
|
applicationStatus: applicationStatus("applicationStatus")
|
||||||
.notNull()
|
.notNull()
|
||||||
.default("idle"),
|
.default("idle"),
|
||||||
|
|
||||||
|
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(),
|
||||||
createdAt: text("createdAt")
|
createdAt: text("createdAt")
|
||||||
.notNull()
|
.notNull()
|
||||||
.$defaultFn(() => new Date().toISOString()),
|
.$defaultFn(() => new Date().toISOString()),
|
||||||
@@ -78,6 +104,14 @@ const createSchema = createInsertSchema(postgres, {
|
|||||||
createdAt: z.string(),
|
createdAt: z.string(),
|
||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
serverId: z.string().optional(),
|
serverId: z.string().optional(),
|
||||||
|
healthCheckSwarm: HealthCheckSwarmSchema.nullable(),
|
||||||
|
restartPolicySwarm: RestartPolicySwarmSchema.nullable(),
|
||||||
|
placementSwarm: PlacementSwarmSchema.nullable(),
|
||||||
|
updateConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
rollbackConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
modeSwarm: ServiceModeSwarmSchema.nullable(),
|
||||||
|
labelsSwarm: LabelsSwarmSchema.nullable(),
|
||||||
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreatePostgres = createSchema
|
export const apiCreatePostgres = createSchema
|
||||||
|
|||||||
@@ -1,12 +1,28 @@
|
|||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
import { integer, pgTable, text } from "drizzle-orm/pg-core";
|
import { integer, json, pgTable, text } from "drizzle-orm/pg-core";
|
||||||
import { createInsertSchema } from "drizzle-zod";
|
import { createInsertSchema } from "drizzle-zod";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { mounts } from "./mount";
|
import { mounts } from "./mount";
|
||||||
import { projects } from "./project";
|
import { projects } from "./project";
|
||||||
import { server } from "./server";
|
import { server } from "./server";
|
||||||
import { applicationStatus } from "./shared";
|
import {
|
||||||
|
applicationStatus,
|
||||||
|
type HealthCheckSwarm,
|
||||||
|
HealthCheckSwarmSchema,
|
||||||
|
type LabelsSwarm,
|
||||||
|
LabelsSwarmSchema,
|
||||||
|
type NetworkSwarm,
|
||||||
|
NetworkSwarmSchema,
|
||||||
|
type PlacementSwarm,
|
||||||
|
PlacementSwarmSchema,
|
||||||
|
type RestartPolicySwarm,
|
||||||
|
RestartPolicySwarmSchema,
|
||||||
|
type ServiceModeSwarm,
|
||||||
|
ServiceModeSwarmSchema,
|
||||||
|
type UpdateConfigSwarm,
|
||||||
|
UpdateConfigSwarmSchema,
|
||||||
|
} from "./shared";
|
||||||
import { generateAppName } from "./utils";
|
import { generateAppName } from "./utils";
|
||||||
|
|
||||||
export const redis = pgTable("redis", {
|
export const redis = pgTable("redis", {
|
||||||
@@ -35,6 +51,15 @@ export const redis = pgTable("redis", {
|
|||||||
applicationStatus: applicationStatus("applicationStatus")
|
applicationStatus: applicationStatus("applicationStatus")
|
||||||
.notNull()
|
.notNull()
|
||||||
.default("idle"),
|
.default("idle"),
|
||||||
|
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(),
|
||||||
projectId: text("projectId")
|
projectId: text("projectId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => projects.projectId, { onDelete: "cascade" }),
|
.references(() => projects.projectId, { onDelete: "cascade" }),
|
||||||
@@ -73,6 +98,14 @@ const createSchema = createInsertSchema(redis, {
|
|||||||
externalPort: z.number(),
|
externalPort: z.number(),
|
||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
serverId: z.string().optional(),
|
serverId: z.string().optional(),
|
||||||
|
healthCheckSwarm: HealthCheckSwarmSchema.nullable(),
|
||||||
|
restartPolicySwarm: RestartPolicySwarmSchema.nullable(),
|
||||||
|
placementSwarm: PlacementSwarmSchema.nullable(),
|
||||||
|
updateConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
rollbackConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
modeSwarm: ServiceModeSwarmSchema.nullable(),
|
||||||
|
labelsSwarm: LabelsSwarmSchema.nullable(),
|
||||||
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreateRedis = createSchema
|
export const apiCreateRedis = createSchema
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { pgEnum } from "drizzle-orm/pg-core";
|
import { pgEnum } from "drizzle-orm/pg-core";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
export const applicationStatus = pgEnum("applicationStatus", [
|
export const applicationStatus = pgEnum("applicationStatus", [
|
||||||
"idle",
|
"idle",
|
||||||
@@ -14,3 +15,149 @@ export const certificateType = pgEnum("certificateType", [
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
export const triggerType = pgEnum("triggerType", ["push", "tag"]);
|
export const triggerType = pgEnum("triggerType", ["push", "tag"]);
|
||||||
|
|
||||||
|
export interface HealthCheckSwarm {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PlacementSwarm {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServiceModeSwarm {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LabelsSwarm {
|
||||||
|
[name: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export 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();
|
||||||
|
|
||||||
|
export const RestartPolicySwarmSchema = z
|
||||||
|
.object({
|
||||||
|
Condition: z.string().optional(),
|
||||||
|
Delay: z.number().optional(),
|
||||||
|
MaxAttempts: z.number().optional(),
|
||||||
|
Window: z.number().optional(),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export const PreferenceSchema = z
|
||||||
|
.object({
|
||||||
|
Spread: z.object({
|
||||||
|
SpreadDescriptor: z.string(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export const PlatformSchema = z
|
||||||
|
.object({
|
||||||
|
Architecture: z.string(),
|
||||||
|
OS: z.string(),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export 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();
|
||||||
|
|
||||||
|
export 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();
|
||||||
|
|
||||||
|
export const ReplicatedSchema = z
|
||||||
|
.object({
|
||||||
|
Replicas: z.number().optional(),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export const ReplicatedJobSchema = z
|
||||||
|
.object({
|
||||||
|
MaxConcurrent: z.number().optional(),
|
||||||
|
TotalCompletions: z.number().optional(),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export const ServiceModeSwarmSchema = z
|
||||||
|
.object({
|
||||||
|
Replicated: ReplicatedSchema.optional(),
|
||||||
|
Global: z.object({}).optional(),
|
||||||
|
ReplicatedJob: ReplicatedJobSchema.optional(),
|
||||||
|
GlobalJob: z.object({}).optional(),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export const NetworkSwarmSchema = z.array(
|
||||||
|
z
|
||||||
|
.object({
|
||||||
|
Target: z.string().optional(),
|
||||||
|
Aliases: z.array(z.string()).optional(),
|
||||||
|
DriverOpts: z.object({}).optional(),
|
||||||
|
})
|
||||||
|
.strict(),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const LabelsSwarmSchema = z.record(z.string());
|
||||||
|
|||||||
Reference in New Issue
Block a user