mirror of
https://github.com/andwati/dokploy.git
synced 2026-11-09 13:35:19 +00:00
feat: better UI for submitting labels
This commit is contained in:
+91
-20
@@ -1,4 +1,5 @@
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -27,9 +28,15 @@ import {
|
|||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { Settings2 } from "lucide-react";
|
import { HelpCircle, Plus, Settings2, X } from "lucide-react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
@@ -42,7 +49,7 @@ const schema = z
|
|||||||
wildcardDomain: z.string(),
|
wildcardDomain: z.string(),
|
||||||
port: z.number(),
|
port: z.number(),
|
||||||
previewLimit: z.number(),
|
previewLimit: z.number(),
|
||||||
previewLabels: z.string(),
|
previewLabels: z.array(z.string()).optional(),
|
||||||
previewHttps: z.boolean(),
|
previewHttps: z.boolean(),
|
||||||
previewPath: z.string(),
|
previewPath: z.string(),
|
||||||
previewCertificateType: z.enum(["letsencrypt", "none", "custom"]),
|
previewCertificateType: z.enum(["letsencrypt", "none", "custom"]),
|
||||||
@@ -82,7 +89,7 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => {
|
|||||||
wildcardDomain: "*.traefik.me",
|
wildcardDomain: "*.traefik.me",
|
||||||
port: 3000,
|
port: 3000,
|
||||||
previewLimit: 3,
|
previewLimit: 3,
|
||||||
previewLabels: "",
|
previewLabels: [],
|
||||||
previewHttps: false,
|
previewHttps: false,
|
||||||
previewPath: "/",
|
previewPath: "/",
|
||||||
previewCertificateType: "none",
|
previewCertificateType: "none",
|
||||||
@@ -104,7 +111,7 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => {
|
|||||||
buildArgs: data.previewBuildArgs || "",
|
buildArgs: data.previewBuildArgs || "",
|
||||||
wildcardDomain: data.previewWildcard || "*.traefik.me",
|
wildcardDomain: data.previewWildcard || "*.traefik.me",
|
||||||
port: data.previewPort || 3000,
|
port: data.previewPort || 3000,
|
||||||
previewLabels: data.previewLabels || "",
|
previewLabels: data.previewLabels || [],
|
||||||
previewLimit: data.previewLimit || 3,
|
previewLimit: data.previewLimit || 3,
|
||||||
previewHttps: data.previewHttps || false,
|
previewHttps: data.previewHttps || false,
|
||||||
previewPath: data.previewPath || "/",
|
previewPath: data.previewPath || "/",
|
||||||
@@ -204,22 +211,86 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => {
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="previewLabels"
|
name="previewLabels"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem className="md:col-span-2">
|
||||||
<FormLabel>Labels</FormLabel>
|
<div className="flex items-center gap-2">
|
||||||
<FormControl>
|
<FormLabel>Preview Labels</FormLabel>
|
||||||
<Input
|
<TooltipProvider>
|
||||||
placeholder="enhancement,needs-review (Leave empty for all labels)"
|
<Tooltip>
|
||||||
{...field}
|
<TooltipTrigger asChild>
|
||||||
/>
|
<HelpCircle className="size-4 text-muted-foreground hover:text-foreground transition-colors cursor-pointer" />
|
||||||
</FormControl>
|
</TooltipTrigger>
|
||||||
<FormMessage />
|
<TooltipContent>
|
||||||
</FormItem>
|
<p>
|
||||||
)}
|
Add a labels that will trigger a preview deployment
|
||||||
/>
|
for a pull request. If no labels are specified, all
|
||||||
|
pull requests will trigger a preview deployment.
|
||||||
|
</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-2 mb-2">
|
||||||
|
{field.value?.map((label, index) => (
|
||||||
|
<Badge
|
||||||
|
key={index}
|
||||||
|
variant="secondary"
|
||||||
|
className="flex items-center gap-1"
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
<X
|
||||||
|
className="size-3 cursor-pointer hover:text-destructive"
|
||||||
|
onClick={() => {
|
||||||
|
const newLabels = [...(field.value || [])];
|
||||||
|
newLabels.splice(index, 1);
|
||||||
|
field.onChange(newLabels);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Badge>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
placeholder="Enter a label (e.g. enhancements, needs-review)"
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
e.preventDefault();
|
||||||
|
const input = e.currentTarget;
|
||||||
|
const label = input.value.trim();
|
||||||
|
if (label) {
|
||||||
|
field.onChange([...(field.value || []), label]);
|
||||||
|
input.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
onClick={() => {
|
||||||
|
const input = document.querySelector(
|
||||||
|
'input[placeholder*="Enter a label"]',
|
||||||
|
) as HTMLInputElement;
|
||||||
|
const label = input.value.trim();
|
||||||
|
if (label) {
|
||||||
|
field.onChange([...(field.value || []), label]);
|
||||||
|
input.value = "";
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Plus className="size-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="previewLimit"
|
name="previewLimit"
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
ALTER TABLE "application" ADD COLUMN "previewLabels" text;
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "application" ADD COLUMN "previewLabels" text[];
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -743,6 +743,13 @@
|
|||||||
"when": 1754259281559,
|
"when": 1754259281559,
|
||||||
"tag": "0105_clumsy_quicksilver",
|
"tag": "0105_clumsy_quicksilver",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 106,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1754912062243,
|
||||||
|
"tag": "0106_purple_maggott",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -443,12 +443,11 @@ export default async function handler(
|
|||||||
|
|
||||||
for (const app of secureApps) {
|
for (const app of secureApps) {
|
||||||
// check for labels
|
// check for labels
|
||||||
if (app?.previewLabels != "") {
|
if (app?.previewLabels.size() > 0) {
|
||||||
const previewLabels = app?.previewLabels?.split(",");
|
|
||||||
let hasLabel: boolean = false;
|
let hasLabel: boolean = false;
|
||||||
const labels = githubBody?.pull_request?.labels;
|
const labels = githubBody?.pull_request?.labels;
|
||||||
for (const label of labels) {
|
for (const label of labels) {
|
||||||
if (previewLabels.contains(label.name)) {
|
if (app?.previewLabels.contains(label.name)) {
|
||||||
hasLabel = true;
|
hasLabel = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ export const applications = pgTable("application", {
|
|||||||
previewEnv: text("previewEnv"),
|
previewEnv: text("previewEnv"),
|
||||||
watchPaths: text("watchPaths").array(),
|
watchPaths: text("watchPaths").array(),
|
||||||
previewBuildArgs: text("previewBuildArgs"),
|
previewBuildArgs: text("previewBuildArgs"),
|
||||||
previewLabels: text("previewLabels"),
|
previewLabels: text("previewLabels").array(),
|
||||||
previewWildcard: text("previewWildcard"),
|
previewWildcard: text("previewWildcard"),
|
||||||
previewPort: integer("previewPort").default(3000),
|
previewPort: integer("previewPort").default(3000),
|
||||||
previewHttps: boolean("previewHttps").notNull().default(false),
|
previewHttps: boolean("previewHttps").notNull().default(false),
|
||||||
|
|||||||
Reference in New Issue
Block a user