mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-24 22:06:38 +00:00
Fix docker button and positioning
This commit is contained in:
@@ -1007,14 +1007,9 @@ export default function ReverseProxyTargets(props: {
|
|||||||
) => {
|
) => {
|
||||||
updateTarget(row.original.targetId, {
|
updateTarget(row.original.targetId, {
|
||||||
...row.original,
|
...row.original,
|
||||||
ip: hostname
|
ip: hostname,
|
||||||
|
...(port && { port: port })
|
||||||
});
|
});
|
||||||
if (port) {
|
|
||||||
updateTarget(row.original.targetId, {
|
|
||||||
...row.original,
|
|
||||||
port: port
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -58,7 +58,16 @@ import {
|
|||||||
} from "@app/components/ui/popover";
|
} from "@app/components/ui/popover";
|
||||||
import { CaretSortIcon, CheckIcon } from "@radix-ui/react-icons";
|
import { CaretSortIcon, CheckIcon } from "@radix-ui/react-icons";
|
||||||
import { cn } from "@app/lib/cn";
|
import { cn } from "@app/lib/cn";
|
||||||
import { ArrowRight, CircleCheck, CircleX, Info, MoveRight, Plus, Settings, SquareArrowOutUpRight } from "lucide-react";
|
import {
|
||||||
|
ArrowRight,
|
||||||
|
CircleCheck,
|
||||||
|
CircleX,
|
||||||
|
Info,
|
||||||
|
MoveRight,
|
||||||
|
Plus,
|
||||||
|
Settings,
|
||||||
|
SquareArrowOutUpRight
|
||||||
|
} from "lucide-react";
|
||||||
import CopyTextBox from "@app/components/CopyTextBox";
|
import CopyTextBox from "@app/components/CopyTextBox";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
@@ -89,16 +98,25 @@ import { isTargetValid } from "@server/lib/validators";
|
|||||||
import { ListTargetsResponse } from "@server/routers/target";
|
import { ListTargetsResponse } from "@server/routers/target";
|
||||||
import { DockerManager, DockerState } from "@app/lib/docker";
|
import { DockerManager, DockerState } from "@app/lib/docker";
|
||||||
import { parseHostTarget } from "@app/lib/parseHostTarget";
|
import { parseHostTarget } from "@app/lib/parseHostTarget";
|
||||||
import { toASCII, toUnicode } from 'punycode';
|
import { toASCII, toUnicode } from "punycode";
|
||||||
import { DomainRow } from "../../../../../components/DomainsTable";
|
import { DomainRow } from "../../../../../components/DomainsTable";
|
||||||
import { finalizeSubdomainSanitize } from "@app/lib/subdomain-utils";
|
import { finalizeSubdomainSanitize } from "@app/lib/subdomain-utils";
|
||||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@app/components/ui/tooltip";
|
import {
|
||||||
import { PathMatchDisplay, PathMatchModal, PathRewriteDisplay, PathRewriteModal } from "@app/components/PathMatchRenameModal";
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger
|
||||||
|
} from "@app/components/ui/tooltip";
|
||||||
|
import {
|
||||||
|
PathMatchDisplay,
|
||||||
|
PathMatchModal,
|
||||||
|
PathRewriteDisplay,
|
||||||
|
PathRewriteModal
|
||||||
|
} from "@app/components/PathMatchRenameModal";
|
||||||
import { Badge } from "@app/components/ui/badge";
|
import { Badge } from "@app/components/ui/badge";
|
||||||
import HealthCheckDialog from "@app/components/HealthCheckDialog";
|
import HealthCheckDialog from "@app/components/HealthCheckDialog";
|
||||||
import { SwitchInput } from "@app/components/SwitchInput";
|
import { SwitchInput } from "@app/components/SwitchInput";
|
||||||
|
|
||||||
|
|
||||||
const baseResourceFormSchema = z.object({
|
const baseResourceFormSchema = z.object({
|
||||||
name: z.string().min(1).max(255),
|
name: z.string().min(1).max(255),
|
||||||
http: z.boolean()
|
http: z.boolean()
|
||||||
@@ -119,50 +137,57 @@ const targetsSettingsSchema = z.object({
|
|||||||
stickySession: z.boolean()
|
stickySession: z.boolean()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const addTargetSchema = z
|
||||||
const addTargetSchema = z.object({
|
.object({
|
||||||
ip: z.string().refine(isTargetValid),
|
ip: z.string().refine(isTargetValid),
|
||||||
method: z.string().nullable(),
|
method: z.string().nullable(),
|
||||||
port: z.coerce.number().int().positive(),
|
port: z.coerce.number().int().positive(),
|
||||||
siteId: z.number().int().positive(),
|
siteId: z.number().int().positive(),
|
||||||
path: z.string().optional().nullable(),
|
path: z.string().optional().nullable(),
|
||||||
pathMatchType: z.enum(["exact", "prefix", "regex"]).optional().nullable(),
|
pathMatchType: z
|
||||||
rewritePath: z.string().optional().nullable(),
|
.enum(["exact", "prefix", "regex"])
|
||||||
rewritePathType: z.enum(["exact", "prefix", "regex", "stripPrefix"]).optional().nullable(),
|
.optional()
|
||||||
priority: z.number().int().min(1).max(1000)
|
.nullable(),
|
||||||
}).refine(
|
rewritePath: z.string().optional().nullable(),
|
||||||
(data) => {
|
rewritePathType: z
|
||||||
// If path is provided, pathMatchType must be provided
|
.enum(["exact", "prefix", "regex", "stripPrefix"])
|
||||||
if (data.path && !data.pathMatchType) {
|
.optional()
|
||||||
return false;
|
.nullable(),
|
||||||
}
|
priority: z.number().int().min(1).max(1000)
|
||||||
// If pathMatchType is provided, path must be provided
|
})
|
||||||
if (data.pathMatchType && !data.path) {
|
.refine(
|
||||||
return false;
|
(data) => {
|
||||||
}
|
// If path is provided, pathMatchType must be provided
|
||||||
// Validate path based on pathMatchType
|
if (data.path && !data.pathMatchType) {
|
||||||
if (data.path && data.pathMatchType) {
|
return false;
|
||||||
switch (data.pathMatchType) {
|
|
||||||
case "exact":
|
|
||||||
case "prefix":
|
|
||||||
// Path should start with /
|
|
||||||
return data.path.startsWith("/");
|
|
||||||
case "regex":
|
|
||||||
// Validate regex
|
|
||||||
try {
|
|
||||||
new RegExp(data.path);
|
|
||||||
return true;
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// If pathMatchType is provided, path must be provided
|
||||||
|
if (data.pathMatchType && !data.path) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Validate path based on pathMatchType
|
||||||
|
if (data.path && data.pathMatchType) {
|
||||||
|
switch (data.pathMatchType) {
|
||||||
|
case "exact":
|
||||||
|
case "prefix":
|
||||||
|
// Path should start with /
|
||||||
|
return data.path.startsWith("/");
|
||||||
|
case "regex":
|
||||||
|
// Validate regex
|
||||||
|
try {
|
||||||
|
new RegExp(data.path);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "Invalid path configuration"
|
||||||
}
|
}
|
||||||
return true;
|
)
|
||||||
},
|
|
||||||
{
|
|
||||||
message: "Invalid path configuration"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
// If rewritePath is provided, rewritePathType must be provided
|
// If rewritePath is provided, rewritePathType must be provided
|
||||||
@@ -221,7 +246,9 @@ export default function Page() {
|
|||||||
// Target management state
|
// Target management state
|
||||||
const [targets, setTargets] = useState<LocalTarget[]>([]);
|
const [targets, setTargets] = useState<LocalTarget[]>([]);
|
||||||
const [targetsToRemove, setTargetsToRemove] = useState<number[]>([]);
|
const [targetsToRemove, setTargetsToRemove] = useState<number[]>([]);
|
||||||
const [dockerStates, setDockerStates] = useState<Map<number, DockerState>>(new Map());
|
const [dockerStates, setDockerStates] = useState<Map<number, DockerState>>(
|
||||||
|
new Map()
|
||||||
|
);
|
||||||
|
|
||||||
const [selectedTargetForHealthCheck, setSelectedTargetForHealthCheck] =
|
const [selectedTargetForHealthCheck, setSelectedTargetForHealthCheck] =
|
||||||
useState<LocalTarget | null>(null);
|
useState<LocalTarget | null>(null);
|
||||||
@@ -290,12 +317,12 @@ export default function Page() {
|
|||||||
...(!env.flags.allowRawResources
|
...(!env.flags.allowRawResources
|
||||||
? []
|
? []
|
||||||
: [
|
: [
|
||||||
{
|
{
|
||||||
id: "raw" as ResourceType,
|
id: "raw" as ResourceType,
|
||||||
title: t("resourceRaw"),
|
title: t("resourceRaw"),
|
||||||
description: t("resourceRawDescription")
|
description: t("resourceRawDescription")
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
];
|
];
|
||||||
|
|
||||||
const baseForm = useForm({
|
const baseForm = useForm({
|
||||||
@@ -330,7 +357,7 @@ export default function Page() {
|
|||||||
pathMatchType: null,
|
pathMatchType: null,
|
||||||
rewritePath: null,
|
rewritePath: null,
|
||||||
rewritePathType: null,
|
rewritePathType: null,
|
||||||
priority: 100,
|
priority: 100
|
||||||
} as z.infer<typeof addTargetSchema>
|
} as z.infer<typeof addTargetSchema>
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -360,14 +387,14 @@ export default function Page() {
|
|||||||
const dockerManager = new DockerManager(api, siteId);
|
const dockerManager = new DockerManager(api, siteId);
|
||||||
const dockerState = await dockerManager.initializeDocker();
|
const dockerState = await dockerManager.initializeDocker();
|
||||||
|
|
||||||
setDockerStates(prev => new Map(prev.set(siteId, dockerState)));
|
setDockerStates((prev) => new Map(prev.set(siteId, dockerState)));
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshContainersForSite = async (siteId: number) => {
|
const refreshContainersForSite = async (siteId: number) => {
|
||||||
const dockerManager = new DockerManager(api, siteId);
|
const dockerManager = new DockerManager(api, siteId);
|
||||||
const containers = await dockerManager.fetchContainers();
|
const containers = await dockerManager.fetchContainers();
|
||||||
|
|
||||||
setDockerStates(prev => {
|
setDockerStates((prev) => {
|
||||||
const newMap = new Map(prev);
|
const newMap = new Map(prev);
|
||||||
const existingState = newMap.get(siteId);
|
const existingState = newMap.get(siteId);
|
||||||
if (existingState) {
|
if (existingState) {
|
||||||
@@ -378,11 +405,13 @@ export default function Page() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getDockerStateForSite = (siteId: number): DockerState => {
|
const getDockerStateForSite = (siteId: number): DockerState => {
|
||||||
return dockerStates.get(siteId) || {
|
return (
|
||||||
isEnabled: false,
|
dockerStates.get(siteId) || {
|
||||||
isAvailable: false,
|
isEnabled: false,
|
||||||
containers: []
|
isAvailable: false,
|
||||||
};
|
containers: []
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
async function addTarget(data: z.infer<typeof addTargetSchema>) {
|
async function addTarget(data: z.infer<typeof addTargetSchema>) {
|
||||||
@@ -443,7 +472,7 @@ export default function Page() {
|
|||||||
pathMatchType: null,
|
pathMatchType: null,
|
||||||
rewritePath: null,
|
rewritePath: null,
|
||||||
rewritePathType: null,
|
rewritePathType: null,
|
||||||
priority: 100,
|
priority: 100
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,11 +492,11 @@ export default function Page() {
|
|||||||
targets.map((target) =>
|
targets.map((target) =>
|
||||||
target.targetId === targetId
|
target.targetId === targetId
|
||||||
? {
|
? {
|
||||||
...target,
|
...target,
|
||||||
...data,
|
...data,
|
||||||
updated: true,
|
updated: true
|
||||||
// siteType: site?.type || null
|
// siteType: site?.type || null
|
||||||
}
|
}
|
||||||
: target
|
: target
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -497,7 +526,9 @@ export default function Page() {
|
|||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
Object.assign(payload, {
|
Object.assign(payload, {
|
||||||
subdomain: sanitizedSubdomain ? toASCII(sanitizedSubdomain) : undefined,
|
subdomain: sanitizedSubdomain
|
||||||
|
? toASCII(sanitizedSubdomain)
|
||||||
|
: undefined,
|
||||||
domainId: httpData.domainId,
|
domainId: httpData.domainId,
|
||||||
protocol: "tcp"
|
protocol: "tcp"
|
||||||
});
|
});
|
||||||
@@ -660,7 +691,7 @@ export default function Page() {
|
|||||||
const rawDomains = res.data.data.domains as DomainRow[];
|
const rawDomains = res.data.data.domains as DomainRow[];
|
||||||
const domains = rawDomains.map((domain) => ({
|
const domains = rawDomains.map((domain) => ({
|
||||||
...domain,
|
...domain,
|
||||||
baseDomain: toUnicode(domain.baseDomain),
|
baseDomain: toUnicode(domain.baseDomain)
|
||||||
}));
|
}));
|
||||||
setBaseDomains(domains);
|
setBaseDomains(domains);
|
||||||
// if (domains.length) {
|
// if (domains.length) {
|
||||||
@@ -683,10 +714,10 @@ export default function Page() {
|
|||||||
targets.map((target) =>
|
targets.map((target) =>
|
||||||
target.targetId === targetId
|
target.targetId === targetId
|
||||||
? {
|
? {
|
||||||
...target,
|
...target,
|
||||||
...config,
|
...config,
|
||||||
updated: true
|
updated: true
|
||||||
}
|
}
|
||||||
: target
|
: target
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -712,9 +743,7 @@ export default function Page() {
|
|||||||
<Info className="h-4 w-4 text-muted-foreground" />
|
<Info className="h-4 w-4 text-muted-foreground" />
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent className="max-w-xs">
|
<TooltipContent className="max-w-xs">
|
||||||
<p>
|
<p>{t("priorityDescription")}</p>
|
||||||
{t("priorityDescription")}
|
|
||||||
</p>
|
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
@@ -895,19 +924,39 @@ export default function Page() {
|
|||||||
) => {
|
) => {
|
||||||
updateTarget(row.original.targetId, {
|
updateTarget(row.original.targetId, {
|
||||||
...row.original,
|
...row.original,
|
||||||
ip: hostname
|
ip: hostname,
|
||||||
|
...(port && { port: port })
|
||||||
});
|
});
|
||||||
if (port) {
|
|
||||||
updateTarget(row.original.targetId, {
|
|
||||||
...row.original,
|
|
||||||
port: port
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center w-full">
|
<div className="flex items-center w-full">
|
||||||
<div className="flex items-center w-full justify-start py-0 space-x-2 px-0 cursor-default border border-input shadow-2xs rounded-md">
|
<div className="flex items-center w-full justify-start py-0 space-x-2 px-0 cursor-default border border-input shadow-2xs rounded-md">
|
||||||
|
{selectedSite &&
|
||||||
|
selectedSite.type === "newt" &&
|
||||||
|
(() => {
|
||||||
|
const dockerState = getDockerStateForSite(
|
||||||
|
selectedSite.siteId
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<ContainersSelector
|
||||||
|
site={selectedSite}
|
||||||
|
containers={dockerState.containers}
|
||||||
|
isAvailable={
|
||||||
|
dockerState.isAvailable
|
||||||
|
}
|
||||||
|
onContainerSelect={
|
||||||
|
handleContainerSelectForTarget
|
||||||
|
}
|
||||||
|
onRefresh={() =>
|
||||||
|
refreshContainersForSite(
|
||||||
|
selectedSite.siteId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
@@ -916,7 +965,7 @@ export default function Page() {
|
|||||||
className={cn(
|
className={cn(
|
||||||
"w-[180px] justify-between text-sm font-medium border-r pr-4 rounded-none h-8 hover:bg-transparent",
|
"w-[180px] justify-between text-sm font-medium border-r pr-4 rounded-none h-8 hover:bg-transparent",
|
||||||
!row.original.siteId &&
|
!row.original.siteId &&
|
||||||
"text-muted-foreground"
|
"text-muted-foreground"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span className="truncate max-w-[90px]">
|
<span className="truncate max-w-[90px]">
|
||||||
@@ -969,30 +1018,6 @@ export default function Page() {
|
|||||||
</Command>
|
</Command>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
{selectedSite &&
|
|
||||||
selectedSite.type === "newt" &&
|
|
||||||
(() => {
|
|
||||||
const dockerState = getDockerStateForSite(
|
|
||||||
selectedSite.siteId
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<ContainersSelector
|
|
||||||
site={selectedSite}
|
|
||||||
containers={dockerState.containers}
|
|
||||||
isAvailable={
|
|
||||||
dockerState.isAvailable
|
|
||||||
}
|
|
||||||
onContainerSelect={
|
|
||||||
handleContainerSelectForTarget
|
|
||||||
}
|
|
||||||
onRefresh={() =>
|
|
||||||
refreshContainersForSite(
|
|
||||||
selectedSite.siteId
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})()}
|
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
defaultValue={row.original.method ?? "http"}
|
defaultValue={row.original.method ?? "http"}
|
||||||
@@ -1464,10 +1489,10 @@ export default function Page() {
|
|||||||
.target
|
.target
|
||||||
.value
|
.value
|
||||||
? parseInt(
|
? parseInt(
|
||||||
e
|
e
|
||||||
.target
|
.target
|
||||||
.value
|
.value
|
||||||
)
|
)
|
||||||
: undefined
|
: undefined
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1546,60 +1571,87 @@ export default function Page() {
|
|||||||
<TableHeader>
|
<TableHeader>
|
||||||
{table
|
{table
|
||||||
.getHeaderGroups()
|
.getHeaderGroups()
|
||||||
.map((headerGroup) => (
|
.map(
|
||||||
<TableRow key={headerGroup.id}>
|
(
|
||||||
{headerGroup.headers.map(
|
headerGroup
|
||||||
(header) => (
|
) => (
|
||||||
<TableHead
|
<TableRow
|
||||||
key={header.id}
|
key={
|
||||||
>
|
headerGroup.id
|
||||||
{header.isPlaceholder
|
}
|
||||||
? null
|
>
|
||||||
: flexRender(
|
{headerGroup.headers.map(
|
||||||
header
|
(
|
||||||
.column
|
header
|
||||||
.columnDef
|
) => (
|
||||||
.header,
|
<TableHead
|
||||||
header.getContext()
|
|
||||||
)}
|
|
||||||
</TableHead>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{table.getRowModel().rows?.length ? (
|
|
||||||
table
|
|
||||||
.getRowModel()
|
|
||||||
.rows.map((row) => (
|
|
||||||
<TableRow key={row.id}>
|
|
||||||
{row
|
|
||||||
.getVisibleCells()
|
|
||||||
.map((cell) => (
|
|
||||||
<TableCell
|
|
||||||
key={
|
key={
|
||||||
cell.id
|
header.id
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{flexRender(
|
{header.isPlaceholder
|
||||||
cell
|
? null
|
||||||
.column
|
: flexRender(
|
||||||
.columnDef
|
header
|
||||||
.cell,
|
.column
|
||||||
cell.getContext()
|
.columnDef
|
||||||
)}
|
.header,
|
||||||
</TableCell>
|
header.getContext()
|
||||||
))}
|
)}
|
||||||
|
</TableHead>
|
||||||
|
)
|
||||||
|
)}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))
|
)
|
||||||
|
)}
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{table.getRowModel()
|
||||||
|
.rows?.length ? (
|
||||||
|
table
|
||||||
|
.getRowModel()
|
||||||
|
.rows.map(
|
||||||
|
(row) => (
|
||||||
|
<TableRow
|
||||||
|
key={
|
||||||
|
row.id
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{row
|
||||||
|
.getVisibleCells()
|
||||||
|
.map(
|
||||||
|
(
|
||||||
|
cell
|
||||||
|
) => (
|
||||||
|
<TableCell
|
||||||
|
key={
|
||||||
|
cell.id
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{flexRender(
|
||||||
|
cell
|
||||||
|
.column
|
||||||
|
.columnDef
|
||||||
|
.cell,
|
||||||
|
cell.getContext()
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
colSpan={columns.length}
|
colSpan={
|
||||||
|
columns.length
|
||||||
|
}
|
||||||
className="h-24 text-center"
|
className="h-24 text-center"
|
||||||
>
|
>
|
||||||
{t("targetNoOne")}
|
{t(
|
||||||
|
"targetNoOne"
|
||||||
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
)}
|
||||||
@@ -1621,8 +1673,12 @@ export default function Page() {
|
|||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Switch
|
<Switch
|
||||||
id="advanced-mode-toggle"
|
id="advanced-mode-toggle"
|
||||||
checked={isAdvancedMode}
|
checked={
|
||||||
onCheckedChange={setIsAdvancedMode}
|
isAdvancedMode
|
||||||
|
}
|
||||||
|
onCheckedChange={
|
||||||
|
setIsAdvancedMode
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
htmlFor="advanced-mode-toggle"
|
htmlFor="advanced-mode-toggle"
|
||||||
@@ -1639,7 +1695,10 @@ export default function Page() {
|
|||||||
<p className="text-muted-foreground mb-4">
|
<p className="text-muted-foreground mb-4">
|
||||||
{t("targetNoOne")}
|
{t("targetNoOne")}
|
||||||
</p>
|
</p>
|
||||||
<Button onClick={addNewTarget} variant="outline">
|
<Button
|
||||||
|
onClick={addNewTarget}
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
<Plus className="h-4 w-4 mr-2" />
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
{t("addTarget")}
|
{t("addTarget")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -1685,24 +1744,36 @@ export default function Page() {
|
|||||||
<HealthCheckDialog
|
<HealthCheckDialog
|
||||||
open={healthCheckDialogOpen}
|
open={healthCheckDialogOpen}
|
||||||
setOpen={setHealthCheckDialogOpen}
|
setOpen={setHealthCheckDialogOpen}
|
||||||
targetId={selectedTargetForHealthCheck.targetId}
|
targetId={
|
||||||
|
selectedTargetForHealthCheck.targetId
|
||||||
|
}
|
||||||
targetAddress={`${selectedTargetForHealthCheck.ip}:${selectedTargetForHealthCheck.port}`}
|
targetAddress={`${selectedTargetForHealthCheck.ip}:${selectedTargetForHealthCheck.port}`}
|
||||||
targetMethod={
|
targetMethod={
|
||||||
selectedTargetForHealthCheck.method || undefined
|
selectedTargetForHealthCheck.method ||
|
||||||
|
undefined
|
||||||
}
|
}
|
||||||
initialConfig={{
|
initialConfig={{
|
||||||
hcEnabled:
|
hcEnabled:
|
||||||
selectedTargetForHealthCheck.hcEnabled || false,
|
selectedTargetForHealthCheck.hcEnabled ||
|
||||||
hcPath: selectedTargetForHealthCheck.hcPath || "/",
|
false,
|
||||||
|
hcPath:
|
||||||
|
selectedTargetForHealthCheck.hcPath ||
|
||||||
|
"/",
|
||||||
hcMethod:
|
hcMethod:
|
||||||
selectedTargetForHealthCheck.hcMethod || "GET",
|
selectedTargetForHealthCheck.hcMethod ||
|
||||||
|
"GET",
|
||||||
hcInterval:
|
hcInterval:
|
||||||
selectedTargetForHealthCheck.hcInterval || 5,
|
selectedTargetForHealthCheck.hcInterval ||
|
||||||
hcTimeout: selectedTargetForHealthCheck.hcTimeout || 5,
|
5,
|
||||||
|
hcTimeout:
|
||||||
|
selectedTargetForHealthCheck.hcTimeout ||
|
||||||
|
5,
|
||||||
hcHeaders:
|
hcHeaders:
|
||||||
selectedTargetForHealthCheck.hcHeaders || undefined,
|
selectedTargetForHealthCheck.hcHeaders ||
|
||||||
|
undefined,
|
||||||
hcScheme:
|
hcScheme:
|
||||||
selectedTargetForHealthCheck.hcScheme || undefined,
|
selectedTargetForHealthCheck.hcScheme ||
|
||||||
|
undefined,
|
||||||
hcHostname:
|
hcHostname:
|
||||||
selectedTargetForHealthCheck.hcHostname ||
|
selectedTargetForHealthCheck.hcHostname ||
|
||||||
selectedTargetForHealthCheck.ip,
|
selectedTargetForHealthCheck.ip,
|
||||||
@@ -1713,8 +1784,11 @@ export default function Page() {
|
|||||||
selectedTargetForHealthCheck.hcFollowRedirects ||
|
selectedTargetForHealthCheck.hcFollowRedirects ||
|
||||||
true,
|
true,
|
||||||
hcStatus:
|
hcStatus:
|
||||||
selectedTargetForHealthCheck.hcStatus || undefined,
|
selectedTargetForHealthCheck.hcStatus ||
|
||||||
hcMode: selectedTargetForHealthCheck.hcMode || "http",
|
undefined,
|
||||||
|
hcMode:
|
||||||
|
selectedTargetForHealthCheck.hcMode ||
|
||||||
|
"http",
|
||||||
hcUnhealthyInterval:
|
hcUnhealthyInterval:
|
||||||
selectedTargetForHealthCheck.hcUnhealthyInterval ||
|
selectedTargetForHealthCheck.hcUnhealthyInterval ||
|
||||||
30
|
30
|
||||||
@@ -1749,7 +1823,9 @@ export default function Page() {
|
|||||||
{t("resourceAddEntrypoints")}
|
{t("resourceAddEntrypoints")}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
{t("resourceAddEntrypointsEditFile")}
|
{t(
|
||||||
|
"resourceAddEntrypointsEditFile"
|
||||||
|
)}
|
||||||
</p>
|
</p>
|
||||||
<CopyTextBox
|
<CopyTextBox
|
||||||
text={`entryPoints:
|
text={`entryPoints:
|
||||||
@@ -1764,7 +1840,9 @@ export default function Page() {
|
|||||||
{t("resourceExposePorts")}
|
{t("resourceExposePorts")}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
{t("resourceExposePortsEditFile")}
|
{t(
|
||||||
|
"resourceExposePortsEditFile"
|
||||||
|
)}
|
||||||
</p>
|
</p>
|
||||||
<CopyTextBox
|
<CopyTextBox
|
||||||
text={`ports:
|
text={`ports:
|
||||||
|
|||||||
Reference in New Issue
Block a user