feat(ui): add default "Dokploy" option to server selection dropdown - Add "Dokploy" as default option in server selection dropdowns - Hide dropdown when only one server is available (servers.length <= 1) - Show dropdown only when multiple servers exist (servers.length > 1) - Update placeholder text from "Select a Server" to "Dokploy" - Fix issue where users couldn't switch back to default server - Update form submission logic to handle "dokploy" default value - Apply changes to all deployment components (application, compose, template, database, certificate, AI) Resolves #1852

This commit is contained in:
HarikrishnanD
2025-09-02 19:17:46 +05:30
parent f8ebf77575
commit 940b9967b8
6 changed files with 131 additions and 72 deletions

View File

@@ -95,7 +95,7 @@ export const AddApplication = ({ projectId, projectName }: Props) => {
appName: data.appName,
description: data.description,
projectId,
serverId: data.serverId,
serverId: data.serverId === "dokploy" ? undefined : data.serverId,
})
.then(async () => {
toast.success("Service Created");
@@ -157,7 +157,7 @@ export const AddApplication = ({ projectId, projectName }: Props) => {
</FormItem>
)}
/>
{hasServers && (
{hasServers && servers.length > 1 && (
<FormField
control={form.control}
name="serverId"
@@ -186,13 +186,21 @@ export const AddApplication = ({ projectId, projectName }: Props) => {
<Select
onValueChange={field.onChange}
defaultValue={field.value}
defaultValue={field.value || "dokploy"}
>
<SelectTrigger>
<SelectValue placeholder="Select a Server" />
<SelectValue placeholder="Dokploy" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="dokploy">
<span className="flex items-center gap-2 justify-between w-full">
<span>Dokploy</span>
<span className="text-muted-foreground text-xs self-center">
Default
</span>
</span>
</SelectItem>
{servers?.map((server) => (
<SelectItem
key={server.serverId}
@@ -206,7 +214,7 @@ export const AddApplication = ({ projectId, projectName }: Props) => {
</span>
</SelectItem>
))}
<SelectLabel>Servers ({servers?.length})</SelectLabel>
<SelectLabel>Servers ({servers?.length + 1})</SelectLabel>
</SelectGroup>
</SelectContent>
</Select>

View File

@@ -101,7 +101,7 @@ export const AddCompose = ({ projectId, projectName }: Props) => {
projectId,
composeType: data.composeType,
appName: data.appName,
serverId: data.serverId,
serverId: data.serverId === "dokploy" ? undefined : data.serverId,
})
.then(async () => {
toast.success("Compose Created");
@@ -165,7 +165,7 @@ export const AddCompose = ({ projectId, projectName }: Props) => {
)}
/>
</div>
{hasServers && (
{hasServers && servers.length > 1 && (
<FormField
control={form.control}
name="serverId"
@@ -194,13 +194,21 @@ export const AddCompose = ({ projectId, projectName }: Props) => {
<Select
onValueChange={field.onChange}
defaultValue={field.value}
defaultValue={field.value || "dokploy"}
>
<SelectTrigger>
<SelectValue placeholder="Select a Server" />
<SelectValue placeholder="Dokploy" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="dokploy">
<span className="flex items-center gap-2 justify-between w-full">
<span>Dokploy</span>
<span className="text-muted-foreground text-xs self-center">
Default
</span>
</span>
</SelectItem>
{servers?.map((server) => (
<SelectItem
key={server.serverId}
@@ -214,7 +222,7 @@ export const AddCompose = ({ projectId, projectName }: Props) => {
</span>
</SelectItem>
))}
<SelectLabel>Servers ({servers?.length})</SelectLabel>
<SelectLabel>Servers ({servers?.length + 1})</SelectLabel>
</SelectGroup>
</SelectContent>
</Select>

View File

@@ -220,7 +220,7 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
appName: data.appName,
dockerImage: defaultDockerImage,
projectId,
serverId: data.serverId,
serverId: data.serverId === "dokploy" ? undefined : data.serverId,
description: data.description,
};
@@ -232,7 +232,7 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
databaseUser:
data.databaseUser || databasesUserDefaultPlaceholder[data.type],
serverId: data.serverId,
serverId: data.serverId === "dokploy" ? undefined : data.serverId,
});
} else if (data.type === "mongo") {
promise = mongoMutation.mutateAsync({
@@ -240,14 +240,14 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
databasePassword: data.databasePassword,
databaseUser:
data.databaseUser || databasesUserDefaultPlaceholder[data.type],
serverId: data.serverId,
serverId: data.serverId === "dokploy" ? undefined : data.serverId,
replicaSets: data.replicaSets,
});
} else if (data.type === "redis") {
promise = redisMutation.mutateAsync({
...commonParams,
databasePassword: data.databasePassword,
serverId: data.serverId,
serverId: data.serverId === "dokploy" ? undefined : data.serverId,
projectId,
});
} else if (data.type === "mariadb") {
@@ -258,7 +258,7 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
databaseName: data.databaseName || "mariadb",
databaseUser:
data.databaseUser || databasesUserDefaultPlaceholder[data.type],
serverId: data.serverId,
serverId: data.serverId === "dokploy" ? undefined : data.serverId,
});
} else if (data.type === "mysql") {
promise = mysqlMutation.mutateAsync({
@@ -268,7 +268,7 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
databaseUser:
data.databaseUser || databasesUserDefaultPlaceholder[data.type],
databaseRootPassword: data.databaseRootPassword,
serverId: data.serverId,
serverId: data.serverId === "dokploy" ? undefined : data.serverId,
});
}
@@ -398,7 +398,7 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
</FormItem>
)}
/>
{hasServers && (
{hasServers && servers.length > 1 && (
<FormField
control={form.control}
name="serverId"
@@ -407,13 +407,21 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
<FormLabel>Select a Server</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value || ""}
defaultValue={field.value || "dokploy"}
>
<SelectTrigger>
<SelectValue placeholder="Select a Server" />
<SelectValue placeholder="Dokploy" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="dokploy">
<span className="flex items-center gap-2 justify-between w-full">
<span>Dokploy</span>
<span className="text-muted-foreground text-xs self-center">
Default
</span>
</span>
</SelectItem>
{servers?.map((server) => (
<SelectItem
key={server.serverId}
@@ -423,7 +431,7 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
</SelectItem>
))}
<SelectLabel>
Servers ({servers?.length})
Servers ({servers?.length + 1})
</SelectLabel>
</SelectGroup>
</SelectContent>

View File

@@ -427,7 +427,7 @@ export const AddTemplate = ({ projectId, baseUrl }: Props) => {
project.
</AlertDialogDescription>
{hasServers && (
{hasServers && servers.length > 1 && (
<div>
<TooltipProvider delayDuration={0}>
<Tooltip>
@@ -456,12 +456,21 @@ export const AddTemplate = ({ projectId, baseUrl }: Props) => {
onValueChange={(e) => {
setServerId(e);
}}
defaultValue="dokploy"
>
<SelectTrigger>
<SelectValue placeholder="Select a Server" />
<SelectValue placeholder="Dokploy" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="dokploy">
<span className="flex items-center gap-2 justify-between w-full">
<span>Dokploy</span>
<span className="text-muted-foreground text-xs self-center">
Default
</span>
</span>
</SelectItem>
{servers?.map((server) => (
<SelectItem
key={server.serverId}
@@ -476,7 +485,7 @@ export const AddTemplate = ({ projectId, baseUrl }: Props) => {
</SelectItem>
))}
<SelectLabel>
Servers ({servers?.length})
Servers ({servers?.length + 1})
</SelectLabel>
</SelectGroup>
</SelectContent>
@@ -491,7 +500,7 @@ export const AddTemplate = ({ projectId, baseUrl }: Props) => {
onClick={async () => {
const promise = mutateAsync({
projectId,
serverId: serverId || undefined,
serverId: serverId === "dokploy" ? undefined : serverId,
id: template.id,
baseUrl: customBaseUrl,
});

View File

@@ -48,34 +48,49 @@ export const StepOne = ({ setTemplateInfo, templateInfo }: any) => {
/>
</div>
{hasServers && (
{hasServers && servers.length > 1 && (
<div className="space-y-2">
<Label htmlFor="server-deploy">
Select the server where you want to deploy (optional)
</Label>
<Select
value={templateInfo.server?.serverId}
value={templateInfo.server?.serverId || "dokploy"}
onValueChange={(value) => {
const server = servers?.find((s) => s.serverId === value);
if (server) {
if (value === "dokploy") {
setTemplateInfo({
...templateInfo,
server: server,
server: undefined,
});
} else {
const server = servers?.find((s) => s.serverId === value);
if (server) {
setTemplateInfo({
...templateInfo,
server: server,
});
}
}
}}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select a server" />
<SelectValue placeholder="Dokploy" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="dokploy">
<span className="flex items-center gap-2 justify-between w-full">
<span>Dokploy</span>
<span className="text-muted-foreground text-xs self-center">
Default
</span>
</span>
</SelectItem>
{servers?.map((server) => (
<SelectItem key={server.serverId} value={server.serverId}>
{server.name}
</SelectItem>
))}
<SelectLabel>Servers ({servers?.length})</SelectLabel>
<SelectLabel>Servers ({servers?.length + 1})</SelectLabel>
</SelectGroup>
</SelectContent>
</Select>

View File

@@ -65,6 +65,7 @@ export const AddCertificate = () => {
const { mutateAsync, isError, error, isLoading } =
api.certificates.create.useMutation();
const { data: servers } = api.server.withSSHKey.useQuery();
const hasServers = servers && servers.length > 0;
const form = useForm<AddCertificate>({
defaultValues: {
@@ -85,7 +86,7 @@ export const AddCertificate = () => {
certificateData: data.certificateData,
privateKey: data.privateKey,
autoRenew: data.autoRenew,
serverId: data.serverId,
serverId: data.serverId === "dokploy" ? undefined : data.serverId,
organizationId: "",
})
.then(async () => {
@@ -174,52 +175,62 @@ export const AddCertificate = () => {
</FormItem>
)}
/>
<FormField
control={form.control}
name="serverId"
render={({ field }) => (
<FormItem>
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<FormLabel className="break-all w-fit flex flex-row gap-1 items-center">
Select a Server {!isCloud && "(Optional)"}
<HelpCircle className="size-4 text-muted-foreground" />
</FormLabel>
</TooltipTrigger>
</Tooltip>
</TooltipProvider>
{hasServers && servers.length > 1 && (
<FormField
control={form.control}
name="serverId"
render={({ field }) => (
<FormItem>
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<FormLabel className="break-all w-fit flex flex-row gap-1 items-center">
Select a Server {!isCloud && "(Optional)"}
<HelpCircle className="size-4 text-muted-foreground" />
</FormLabel>
</TooltipTrigger>
</Tooltip>
</TooltipProvider>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<SelectTrigger>
<SelectValue placeholder="Select a Server" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{servers?.map((server) => (
<SelectItem
key={server.serverId}
value={server.serverId}
>
<Select
onValueChange={field.onChange}
defaultValue={field.value || "dokploy"}
>
<SelectTrigger>
<SelectValue placeholder="Dokploy" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="dokploy">
<span className="flex items-center gap-2 justify-between w-full">
<span>{server.name}</span>
<span>Dokploy</span>
<span className="text-muted-foreground text-xs self-center">
{server.ipAddress}
Default
</span>
</span>
</SelectItem>
))}
<SelectLabel>Servers ({servers?.length})</SelectLabel>
</SelectGroup>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
{servers?.map((server) => (
<SelectItem
key={server.serverId}
value={server.serverId}
>
<span className="flex items-center gap-2 justify-between w-full">
<span>{server.name}</span>
<span className="text-muted-foreground text-xs self-center">
{server.ipAddress}
</span>
</span>
</SelectItem>
))}
<SelectLabel>Servers ({servers?.length + 1})</SelectLabel>
</SelectGroup>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
)}
</form>
<DialogFooter className="flex w-full flex-row !justify-end">