mirror of
https://github.com/andwati/dokploy.git
synced 2026-11-10 14:05:18 +00:00
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:
@@ -76,6 +76,10 @@ export const AddApplication = ({ projectId, projectName }: Props) => {
|
|||||||
const { data: servers } = api.server.withSSHKey.useQuery();
|
const { data: servers } = api.server.withSSHKey.useQuery();
|
||||||
|
|
||||||
const hasServers = servers && servers.length > 0;
|
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 } =
|
const { mutateAsync, isLoading, error, isError } =
|
||||||
api.application.create.useMutation();
|
api.application.create.useMutation();
|
||||||
@@ -157,7 +161,7 @@ export const AddApplication = ({ projectId, projectName }: Props) => {
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{hasServers && (
|
{shouldShowServerDropdown && (
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="serverId"
|
name="serverId"
|
||||||
@@ -186,21 +190,23 @@ export const AddApplication = ({ projectId, projectName }: Props) => {
|
|||||||
|
|
||||||
<Select
|
<Select
|
||||||
onValueChange={field.onChange}
|
onValueChange={field.onChange}
|
||||||
defaultValue={field.value || "dokploy"}
|
defaultValue={field.value || (!isCloud ? "dokploy" : undefined)}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Dokploy" />
|
<SelectValue placeholder={!isCloud ? "Dokploy" : "Select a Server"} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectGroup>
|
<SelectGroup>
|
||||||
<SelectItem value="dokploy">
|
{!isCloud && (
|
||||||
<span className="flex items-center gap-2 justify-between w-full">
|
<SelectItem value="dokploy">
|
||||||
<span>Dokploy</span>
|
<span className="flex items-center gap-2 justify-between w-full">
|
||||||
<span className="text-muted-foreground text-xs self-center">
|
<span>Dokploy</span>
|
||||||
Default
|
<span className="text-muted-foreground text-xs self-center">
|
||||||
|
Default
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</SelectItem>
|
||||||
</SelectItem>
|
)}
|
||||||
{servers?.map((server) => (
|
{servers?.map((server) => (
|
||||||
<SelectItem
|
<SelectItem
|
||||||
key={server.serverId}
|
key={server.serverId}
|
||||||
@@ -215,7 +221,7 @@ export const AddApplication = ({ projectId, projectName }: Props) => {
|
|||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
<SelectLabel>
|
<SelectLabel>
|
||||||
Servers ({servers?.length + 1})
|
Servers ({servers?.length + (!isCloud ? 1 : 0)})
|
||||||
</SelectLabel>
|
</SelectLabel>
|
||||||
</SelectGroup>
|
</SelectGroup>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ export const AddCompose = ({ projectId, projectName }: Props) => {
|
|||||||
api.compose.create.useMutation();
|
api.compose.create.useMutation();
|
||||||
|
|
||||||
const hasServers = servers && servers.length > 0;
|
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>({
|
const form = useForm<AddCompose>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@@ -165,7 +169,7 @@ export const AddCompose = ({ projectId, projectName }: Props) => {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{hasServers && (
|
{shouldShowServerDropdown && (
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="serverId"
|
name="serverId"
|
||||||
@@ -194,21 +198,23 @@ export const AddCompose = ({ projectId, projectName }: Props) => {
|
|||||||
|
|
||||||
<Select
|
<Select
|
||||||
onValueChange={field.onChange}
|
onValueChange={field.onChange}
|
||||||
defaultValue={field.value || "dokploy"}
|
defaultValue={field.value || (!isCloud ? "dokploy" : undefined)}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Dokploy" />
|
<SelectValue placeholder={!isCloud ? "Dokploy" : "Select a Server"} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectGroup>
|
<SelectGroup>
|
||||||
<SelectItem value="dokploy">
|
{!isCloud && (
|
||||||
<span className="flex items-center gap-2 justify-between w-full">
|
<SelectItem value="dokploy">
|
||||||
<span>Dokploy</span>
|
<span className="flex items-center gap-2 justify-between w-full">
|
||||||
<span className="text-muted-foreground text-xs self-center">
|
<span>Dokploy</span>
|
||||||
Default
|
<span className="text-muted-foreground text-xs self-center">
|
||||||
|
Default
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</SelectItem>
|
||||||
</SelectItem>
|
)}
|
||||||
{servers?.map((server) => (
|
{servers?.map((server) => (
|
||||||
<SelectItem
|
<SelectItem
|
||||||
key={server.serverId}
|
key={server.serverId}
|
||||||
@@ -223,7 +229,7 @@ export const AddCompose = ({ projectId, projectName }: Props) => {
|
|||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
<SelectLabel>
|
<SelectLabel>
|
||||||
Servers ({servers?.length + 1})
|
Servers ({servers?.length + (!isCloud ? 1 : 0)})
|
||||||
</SelectLabel>
|
</SelectLabel>
|
||||||
</SelectGroup>
|
</SelectGroup>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
|
|||||||
const utils = api.useUtils();
|
const utils = api.useUtils();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const slug = slugify(projectName);
|
const slug = slugify(projectName);
|
||||||
|
const { data: isCloud } = api.settings.isCloud.useQuery();
|
||||||
const { data: servers } = api.server.withSSHKey.useQuery();
|
const { data: servers } = api.server.withSSHKey.useQuery();
|
||||||
const postgresMutation = api.postgres.create.useMutation();
|
const postgresMutation = api.postgres.create.useMutation();
|
||||||
const mongoMutation = api.mongo.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 mysqlMutation = api.mysql.create.useMutation();
|
||||||
|
|
||||||
const hasServers = servers && servers.length > 0;
|
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>({
|
const form = useForm<AddDatabase>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@@ -398,7 +403,7 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{hasServers && (
|
{shouldShowServerDropdown && (
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="serverId"
|
name="serverId"
|
||||||
@@ -407,21 +412,23 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
|
|||||||
<FormLabel>Select a Server</FormLabel>
|
<FormLabel>Select a Server</FormLabel>
|
||||||
<Select
|
<Select
|
||||||
onValueChange={field.onChange}
|
onValueChange={field.onChange}
|
||||||
defaultValue={field.value || "dokploy"}
|
defaultValue={field.value || (!isCloud ? "dokploy" : undefined)}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Dokploy" />
|
<SelectValue placeholder={!isCloud ? "Dokploy" : "Select a Server"} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectGroup>
|
<SelectGroup>
|
||||||
<SelectItem value="dokploy">
|
{!isCloud && (
|
||||||
<span className="flex items-center gap-2 justify-between w-full">
|
<SelectItem value="dokploy">
|
||||||
<span>Dokploy</span>
|
<span className="flex items-center gap-2 justify-between w-full">
|
||||||
<span className="text-muted-foreground text-xs self-center">
|
<span>Dokploy</span>
|
||||||
Default
|
<span className="text-muted-foreground text-xs self-center">
|
||||||
|
Default
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</SelectItem>
|
||||||
</SelectItem>
|
)}
|
||||||
{servers?.map((server) => (
|
{servers?.map((server) => (
|
||||||
<SelectItem
|
<SelectItem
|
||||||
key={server.serverId}
|
key={server.serverId}
|
||||||
@@ -431,7 +438,7 @@ export const AddDatabase = ({ projectId, projectName }: Props) => {
|
|||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
<SelectLabel>
|
<SelectLabel>
|
||||||
Servers ({servers?.length + 1})
|
Servers ({servers?.length + (!isCloud ? 1 : 0)})
|
||||||
</SelectLabel>
|
</SelectLabel>
|
||||||
</SelectGroup>
|
</SelectGroup>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
|
|||||||
@@ -138,6 +138,10 @@ export const AddTemplate = ({ projectId, baseUrl }: Props) => {
|
|||||||
}) || [];
|
}) || [];
|
||||||
|
|
||||||
const hasServers = servers && servers.length > 0;
|
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 (
|
return (
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
@@ -427,7 +431,7 @@ export const AddTemplate = ({ projectId, baseUrl }: Props) => {
|
|||||||
project.
|
project.
|
||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
|
|
||||||
{hasServers && (
|
{shouldShowServerDropdown && (
|
||||||
<div>
|
<div>
|
||||||
<TooltipProvider delayDuration={0}>
|
<TooltipProvider delayDuration={0}>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
@@ -456,21 +460,23 @@ export const AddTemplate = ({ projectId, baseUrl }: Props) => {
|
|||||||
onValueChange={(e) => {
|
onValueChange={(e) => {
|
||||||
setServerId(e);
|
setServerId(e);
|
||||||
}}
|
}}
|
||||||
defaultValue="dokploy"
|
defaultValue={!isCloud ? "dokploy" : undefined}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Dokploy" />
|
<SelectValue placeholder={!isCloud ? "Dokploy" : "Select a Server"} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectGroup>
|
<SelectGroup>
|
||||||
<SelectItem value="dokploy">
|
{!isCloud && (
|
||||||
<span className="flex items-center gap-2 justify-between w-full">
|
<SelectItem value="dokploy">
|
||||||
<span>Dokploy</span>
|
<span className="flex items-center gap-2 justify-between w-full">
|
||||||
<span className="text-muted-foreground text-xs self-center">
|
<span>Dokploy</span>
|
||||||
Default
|
<span className="text-muted-foreground text-xs self-center">
|
||||||
|
Default
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</SelectItem>
|
||||||
</SelectItem>
|
)}
|
||||||
{servers?.map((server) => (
|
{servers?.map((server) => (
|
||||||
<SelectItem
|
<SelectItem
|
||||||
key={server.serverId}
|
key={server.serverId}
|
||||||
@@ -485,7 +491,7 @@ export const AddTemplate = ({ projectId, baseUrl }: Props) => {
|
|||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
<SelectLabel>
|
<SelectLabel>
|
||||||
Servers ({servers?.length + 1})
|
Servers ({servers?.length + (!isCloud ? 1 : 0)})
|
||||||
</SelectLabel>
|
</SelectLabel>
|
||||||
</SelectGroup>
|
</SelectGroup>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
|
|||||||
@@ -25,7 +25,12 @@ const examples = [
|
|||||||
export const StepOne = ({ setTemplateInfo, templateInfo }: any) => {
|
export const StepOne = ({ setTemplateInfo, templateInfo }: any) => {
|
||||||
// Get servers from the API
|
// Get servers from the API
|
||||||
const { data: servers } = api.server.withSSHKey.useQuery();
|
const { data: servers } = api.server.withSSHKey.useQuery();
|
||||||
|
const { data: isCloud } = api.settings.isCloud.useQuery();
|
||||||
const hasServers = servers && servers.length > 0;
|
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) => {
|
const handleExampleClick = (example: string) => {
|
||||||
setTemplateInfo({ ...templateInfo, userInput: example });
|
setTemplateInfo({ ...templateInfo, userInput: example });
|
||||||
@@ -48,13 +53,13 @@ export const StepOne = ({ setTemplateInfo, templateInfo }: any) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{hasServers && (
|
{shouldShowServerDropdown && (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="server-deploy">
|
<Label htmlFor="server-deploy">
|
||||||
Select the server where you want to deploy (optional)
|
Select the server where you want to deploy (optional)
|
||||||
</Label>
|
</Label>
|
||||||
<Select
|
<Select
|
||||||
value={templateInfo.server?.serverId || "dokploy"}
|
value={templateInfo.server?.serverId || (!isCloud ? "dokploy" : undefined)}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
if (value === "dokploy") {
|
if (value === "dokploy") {
|
||||||
setTemplateInfo({
|
setTemplateInfo({
|
||||||
@@ -73,24 +78,26 @@ export const StepOne = ({ setTemplateInfo, templateInfo }: any) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
<SelectValue placeholder="Dokploy" />
|
<SelectValue placeholder={!isCloud ? "Dokploy" : "Select a Server"} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectGroup>
|
<SelectGroup>
|
||||||
<SelectItem value="dokploy">
|
{!isCloud && (
|
||||||
<span className="flex items-center gap-2 justify-between w-full">
|
<SelectItem value="dokploy">
|
||||||
<span>Dokploy</span>
|
<span className="flex items-center gap-2 justify-between w-full">
|
||||||
<span className="text-muted-foreground text-xs self-center">
|
<span>Dokploy</span>
|
||||||
Default
|
<span className="text-muted-foreground text-xs self-center">
|
||||||
|
Default
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</SelectItem>
|
||||||
</SelectItem>
|
)}
|
||||||
{servers?.map((server) => (
|
{servers?.map((server) => (
|
||||||
<SelectItem key={server.serverId} value={server.serverId}>
|
<SelectItem key={server.serverId} value={server.serverId}>
|
||||||
{server.name}
|
{server.name}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
<SelectLabel>Servers ({servers?.length + 1})</SelectLabel>
|
<SelectLabel>Servers ({servers?.length + (!isCloud ? 1 : 0)})</SelectLabel>
|
||||||
</SelectGroup>
|
</SelectGroup>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
|||||||
@@ -66,6 +66,10 @@ export const AddCertificate = () => {
|
|||||||
api.certificates.create.useMutation();
|
api.certificates.create.useMutation();
|
||||||
const { data: servers } = api.server.withSSHKey.useQuery();
|
const { data: servers } = api.server.withSSHKey.useQuery();
|
||||||
const hasServers = servers && servers.length > 0;
|
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>({
|
const form = useForm<AddCertificate>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@@ -175,7 +179,7 @@ export const AddCertificate = () => {
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{hasServers && (
|
{shouldShowServerDropdown && (
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="serverId"
|
name="serverId"
|
||||||
@@ -194,21 +198,23 @@ export const AddCertificate = () => {
|
|||||||
|
|
||||||
<Select
|
<Select
|
||||||
onValueChange={field.onChange}
|
onValueChange={field.onChange}
|
||||||
defaultValue={field.value || "dokploy"}
|
defaultValue={field.value || (!isCloud ? "dokploy" : undefined)}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Dokploy" />
|
<SelectValue placeholder={!isCloud ? "Dokploy" : "Select a Server"} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectGroup>
|
<SelectGroup>
|
||||||
<SelectItem value="dokploy">
|
{!isCloud && (
|
||||||
<span className="flex items-center gap-2 justify-between w-full">
|
<SelectItem value="dokploy">
|
||||||
<span>Dokploy</span>
|
<span className="flex items-center gap-2 justify-between w-full">
|
||||||
<span className="text-muted-foreground text-xs self-center">
|
<span>Dokploy</span>
|
||||||
Default
|
<span className="text-muted-foreground text-xs self-center">
|
||||||
|
Default
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</SelectItem>
|
||||||
</SelectItem>
|
)}
|
||||||
{servers?.map((server) => (
|
{servers?.map((server) => (
|
||||||
<SelectItem
|
<SelectItem
|
||||||
key={server.serverId}
|
key={server.serverId}
|
||||||
@@ -223,7 +229,7 @@ export const AddCertificate = () => {
|
|||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
<SelectLabel>
|
<SelectLabel>
|
||||||
Servers ({servers?.length + 1})
|
Servers ({servers?.length + (!isCloud ? 1 : 0)})
|
||||||
</SelectLabel>
|
</SelectLabel>
|
||||||
</SelectGroup>
|
</SelectGroup>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
|
|||||||
Reference in New Issue
Block a user