feat(ui): add conditional server dropdown with Dokploy default option - Add IS_CLOUD flag support for server selection dropdown - Show "Dokploy" as default option in self-hosted environments - Hide dropdown when no remote servers exist - Add conditional placeholder text and server count display - Handle "dokploy" value in form submission (converts to undefined) - Apply changes to all relevant components: add-application, add-compose, add-template, add-database, add-certificate, and AI step-one Resolves #1852

This commit is contained in:
HarikrishnanD
2025-09-04 13:54:19 +05:30
parent 52e21dab4e
commit 46f1af3bb3
6 changed files with 104 additions and 66 deletions

View File

@@ -76,6 +76,10 @@ export const AddApplication = ({ projectId, projectName }: Props) => {
const { data: servers } = api.server.withSSHKey.useQuery();
const hasServers = servers && servers.length > 0;
// Show dropdown logic based on cloud environment
// Cloud: show only if there are remote servers (no Dokploy option)
// Self-hosted: show only if there are remote servers (Dokploy is default, hide if no remote servers)
const shouldShowServerDropdown = hasServers;
const { mutateAsync, isLoading, error, isError } =
api.application.create.useMutation();
@@ -157,7 +161,7 @@ export const AddApplication = ({ projectId, projectName }: Props) => {
</FormItem>
)}
/>
{hasServers && (
{shouldShowServerDropdown && (
<FormField
control={form.control}
name="serverId"
@@ -186,21 +190,23 @@ export const AddApplication = ({ projectId, projectName }: Props) => {
<Select
onValueChange={field.onChange}
defaultValue={field.value || "dokploy"}
defaultValue={field.value || (!isCloud ? "dokploy" : undefined)}
>
<SelectTrigger>
<SelectValue placeholder="Dokploy" />
<SelectValue placeholder={!isCloud ? "Dokploy" : "Select a Server"} />
</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
{!isCloud && (
<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>
</span>
</SelectItem>
</SelectItem>
)}
{servers?.map((server) => (
<SelectItem
key={server.serverId}
@@ -215,7 +221,7 @@ export const AddApplication = ({ projectId, projectName }: Props) => {
</SelectItem>
))}
<SelectLabel>
Servers ({servers?.length + 1})
Servers ({servers?.length + (!isCloud ? 1 : 0)})
</SelectLabel>
</SelectGroup>
</SelectContent>

View File

@@ -79,6 +79,10 @@ export const AddCompose = ({ projectId, projectName }: Props) => {
api.compose.create.useMutation();
const hasServers = servers && servers.length > 0;
// Show dropdown logic based on cloud environment
// Cloud: show only if there are remote servers (no Dokploy option)
// Self-hosted: show only if there are remote servers (Dokploy is default, hide if no remote servers)
const shouldShowServerDropdown = hasServers;
const form = useForm<AddCompose>({
defaultValues: {
@@ -165,7 +169,7 @@ export const AddCompose = ({ projectId, projectName }: Props) => {
)}
/>
</div>
{hasServers && (
{shouldShowServerDropdown && (
<FormField
control={form.control}
name="serverId"
@@ -194,21 +198,23 @@ export const AddCompose = ({ projectId, projectName }: Props) => {
<Select
onValueChange={field.onChange}
defaultValue={field.value || "dokploy"}
defaultValue={field.value || (!isCloud ? "dokploy" : undefined)}
>
<SelectTrigger>
<SelectValue placeholder="Dokploy" />
<SelectValue placeholder={!isCloud ? "Dokploy" : "Select a Server"} />
</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
{!isCloud && (
<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>
</span>
</SelectItem>
</SelectItem>
)}
{servers?.map((server) => (
<SelectItem
key={server.serverId}
@@ -223,7 +229,7 @@ export const AddCompose = ({ projectId, projectName }: Props) => {
</SelectItem>
))}
<SelectLabel>
Servers ({servers?.length + 1})
Servers ({servers?.length + (!isCloud ? 1 : 0)})
</SelectLabel>
</SelectGroup>
</SelectContent>

View File

@@ -178,6 +178,7 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
const utils = api.useUtils();
const [visible, setVisible] = useState(false);
const slug = slugify(projectName);
const { data: isCloud } = api.settings.isCloud.useQuery();
const { data: servers } = api.server.withSSHKey.useQuery();
const postgresMutation = api.postgres.create.useMutation();
const mongoMutation = api.mongo.create.useMutation();
@@ -186,6 +187,10 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
const mysqlMutation = api.mysql.create.useMutation();
const hasServers = servers && servers.length > 0;
// Show dropdown logic based on cloud environment
// Cloud: show only if there are remote servers (no Dokploy option)
// Self-hosted: show only if there are remote servers (Dokploy is default, hide if no remote servers)
const shouldShowServerDropdown = hasServers;
const form = useForm<AddDatabase>({
defaultValues: {
@@ -398,7 +403,7 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
</FormItem>
)}
/>
{hasServers && (
{shouldShowServerDropdown && (
<FormField
control={form.control}
name="serverId"
@@ -407,21 +412,23 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
<FormLabel>Select a Server</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value || "dokploy"}
defaultValue={field.value || (!isCloud ? "dokploy" : undefined)}
>
<SelectTrigger>
<SelectValue placeholder="Dokploy" />
<SelectValue placeholder={!isCloud ? "Dokploy" : "Select a Server"} />
</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
{!isCloud && (
<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>
</span>
</SelectItem>
</SelectItem>
)}
{servers?.map((server) => (
<SelectItem
key={server.serverId}
@@ -431,7 +438,7 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
</SelectItem>
))}
<SelectLabel>
Servers ({servers?.length + 1})
Servers ({servers?.length + (!isCloud ? 1 : 0)})
</SelectLabel>
</SelectGroup>
</SelectContent>

View File

@@ -138,6 +138,10 @@ export const AddTemplate = ({ projectId, baseUrl }: Props) => {
}) || [];
const hasServers = servers && servers.length > 0;
// Show dropdown logic based on cloud environment
// Cloud: show only if there are remote servers (no Dokploy option)
// Self-hosted: show only if there are remote servers (Dokploy is default, hide if no remote servers)
const shouldShowServerDropdown = hasServers;
return (
<Dialog open={open} onOpenChange={setOpen}>
@@ -427,7 +431,7 @@ export const AddTemplate = ({ projectId, baseUrl }: Props) => {
project.
</AlertDialogDescription>
{hasServers && (
{shouldShowServerDropdown && (
<div>
<TooltipProvider delayDuration={0}>
<Tooltip>
@@ -456,21 +460,23 @@ export const AddTemplate = ({ projectId, baseUrl }: Props) => {
onValueChange={(e) => {
setServerId(e);
}}
defaultValue="dokploy"
defaultValue={!isCloud ? "dokploy" : undefined}
>
<SelectTrigger>
<SelectValue placeholder="Dokploy" />
<SelectValue placeholder={!isCloud ? "Dokploy" : "Select a Server"} />
</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
{!isCloud && (
<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>
</span>
</SelectItem>
</SelectItem>
)}
{servers?.map((server) => (
<SelectItem
key={server.serverId}
@@ -485,7 +491,7 @@ export const AddTemplate = ({ projectId, baseUrl }: Props) => {
</SelectItem>
))}
<SelectLabel>
Servers ({servers?.length + 1})
Servers ({servers?.length + (!isCloud ? 1 : 0)})
</SelectLabel>
</SelectGroup>
</SelectContent>

View File

@@ -25,7 +25,12 @@ const examples = [
export const StepOne = ({ setTemplateInfo, templateInfo }: any) => {
// Get servers from the API
const { data: servers } = api.server.withSSHKey.useQuery();
const { data: isCloud } = api.settings.isCloud.useQuery();
const hasServers = servers && servers.length > 0;
// Show dropdown logic based on cloud environment
// Cloud: show only if there are remote servers (no Dokploy option)
// Self-hosted: show only if there are remote servers (Dokploy is default, hide if no remote servers)
const shouldShowServerDropdown = hasServers;
const handleExampleClick = (example: string) => {
setTemplateInfo({ ...templateInfo, userInput: example });
@@ -48,13 +53,13 @@ export const StepOne = ({ setTemplateInfo, templateInfo }: any) => {
/>
</div>
{hasServers && (
{shouldShowServerDropdown && (
<div className="space-y-2">
<Label htmlFor="server-deploy">
Select the server where you want to deploy (optional)
</Label>
<Select
value={templateInfo.server?.serverId || "dokploy"}
value={templateInfo.server?.serverId || (!isCloud ? "dokploy" : undefined)}
onValueChange={(value) => {
if (value === "dokploy") {
setTemplateInfo({
@@ -73,24 +78,26 @@ export const StepOne = ({ setTemplateInfo, templateInfo }: any) => {
}}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="Dokploy" />
<SelectValue placeholder={!isCloud ? "Dokploy" : "Select a Server"} />
</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
{!isCloud && (
<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>
</span>
</SelectItem>
</SelectItem>
)}
{servers?.map((server) => (
<SelectItem key={server.serverId} value={server.serverId}>
{server.name}
</SelectItem>
))}
<SelectLabel>Servers ({servers?.length + 1})</SelectLabel>
<SelectLabel>Servers ({servers?.length + (!isCloud ? 1 : 0)})</SelectLabel>
</SelectGroup>
</SelectContent>
</Select>

View File

@@ -66,6 +66,10 @@ export const AddCertificate = () => {
api.certificates.create.useMutation();
const { data: servers } = api.server.withSSHKey.useQuery();
const hasServers = servers && servers.length > 0;
// Show dropdown logic based on cloud environment
// Cloud: show only if there are remote servers (no Dokploy option)
// Self-hosted: show only if there are remote servers (Dokploy is default, hide if no remote servers)
const shouldShowServerDropdown = hasServers;
const form = useForm<AddCertificate>({
defaultValues: {
@@ -175,7 +179,7 @@ export const AddCertificate = () => {
</FormItem>
)}
/>
{hasServers && (
{shouldShowServerDropdown && (
<FormField
control={form.control}
name="serverId"
@@ -194,21 +198,23 @@ export const AddCertificate = () => {
<Select
onValueChange={field.onChange}
defaultValue={field.value || "dokploy"}
defaultValue={field.value || (!isCloud ? "dokploy" : undefined)}
>
<SelectTrigger>
<SelectValue placeholder="Dokploy" />
<SelectValue placeholder={!isCloud ? "Dokploy" : "Select a Server"} />
</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
{!isCloud && (
<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>
</span>
</SelectItem>
</SelectItem>
)}
{servers?.map((server) => (
<SelectItem
key={server.serverId}
@@ -223,7 +229,7 @@ export const AddCertificate = () => {
</SelectItem>
))}
<SelectLabel>
Servers ({servers?.length + 1})
Servers ({servers?.length + (!isCloud ? 1 : 0)})
</SelectLabel>
</SelectGroup>
</SelectContent>