mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-25 06:16:40 +00:00
Adjust styling to make it more clear
This commit is contained in:
@@ -513,6 +513,7 @@
|
|||||||
"ipAddressErrorInvalidFormat": "Invalid IP address format",
|
"ipAddressErrorInvalidFormat": "Invalid IP address format",
|
||||||
"ipAddressErrorInvalidOctet": "Invalid IP address octet",
|
"ipAddressErrorInvalidOctet": "Invalid IP address octet",
|
||||||
"path": "Path",
|
"path": "Path",
|
||||||
|
"matchPath": "Match Path",
|
||||||
"ipAddressRange": "IP Range",
|
"ipAddressRange": "IP Range",
|
||||||
"rulesErrorFetch": "Failed to fetch rules",
|
"rulesErrorFetch": "Failed to fetch rules",
|
||||||
"rulesErrorFetchDescription": "An error occurred while fetching rules",
|
"rulesErrorFetchDescription": "An error occurred while fetching rules",
|
||||||
|
|||||||
@@ -71,7 +71,9 @@ import {
|
|||||||
Heart,
|
Heart,
|
||||||
Check,
|
Check,
|
||||||
CircleCheck,
|
CircleCheck,
|
||||||
CircleX
|
CircleX,
|
||||||
|
ArrowRight,
|
||||||
|
MoveRight
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { ContainersSelector } from "@app/components/ContainersSelector";
|
import { ContainersSelector } from "@app/components/ContainersSelector";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
@@ -565,6 +567,89 @@ export default function ReverseProxyTargets(props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const columns: ColumnDef<LocalTarget>[] = [
|
const columns: ColumnDef<LocalTarget>[] = [
|
||||||
|
{
|
||||||
|
accessorKey: "path",
|
||||||
|
header: t("matchPath"),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const [showPathInput, setShowPathInput] = useState(
|
||||||
|
!!(row.original.path || row.original.pathMatchType)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!showPathInput) {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setShowPathInput(true)}
|
||||||
|
>
|
||||||
|
+ {t("matchPath")}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex gap-2 min-w-[200px] items-center">
|
||||||
|
<Select
|
||||||
|
defaultValue={row.original.pathMatchType || "exact"}
|
||||||
|
onValueChange={(value) =>
|
||||||
|
updateTarget(row.original.targetId, {
|
||||||
|
...row.original,
|
||||||
|
pathMatchType: value as "exact" | "prefix" | "regex"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-25">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="exact">Exact</SelectItem>
|
||||||
|
<SelectItem value="prefix">Prefix</SelectItem>
|
||||||
|
<SelectItem value="regex">Regex</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<Input
|
||||||
|
placeholder={
|
||||||
|
row.original.pathMatchType === "regex"
|
||||||
|
? "^/api/.*"
|
||||||
|
: "/path"
|
||||||
|
}
|
||||||
|
defaultValue={row.original.path || ""}
|
||||||
|
className="flex-1 min-w-[150px]"
|
||||||
|
onBlur={(e) => {
|
||||||
|
const value = e.target.value.trim();
|
||||||
|
if (!value) {
|
||||||
|
setShowPathInput(false);
|
||||||
|
updateTarget(row.original.targetId, {
|
||||||
|
...row.original,
|
||||||
|
path: null,
|
||||||
|
pathMatchType: null
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
updateTarget(row.original.targetId, {
|
||||||
|
...row.original,
|
||||||
|
path: value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => {
|
||||||
|
setShowPathInput(false);
|
||||||
|
updateTarget(row.original.targetId, {
|
||||||
|
...row.original,
|
||||||
|
path: null,
|
||||||
|
pathMatchType: null
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<MoveRight className="ml-4 h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "siteId",
|
accessorKey: "siteId",
|
||||||
header: t("site"),
|
header: t("site"),
|
||||||
@@ -762,87 +847,6 @@ export default function ReverseProxyTargets(props: {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
|
||||||
accessorKey: "path",
|
|
||||||
header: t("path"),
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const [showPathInput, setShowPathInput] = useState(
|
|
||||||
!!(row.original.path || row.original.pathMatchType)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!showPathInput) {
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => setShowPathInput(true)}
|
|
||||||
>
|
|
||||||
+ Path
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex gap-2 min-w-[200px]">
|
|
||||||
<Select
|
|
||||||
defaultValue={row.original.pathMatchType || "exact"}
|
|
||||||
onValueChange={(value) =>
|
|
||||||
updateTarget(row.original.targetId, {
|
|
||||||
...row.original,
|
|
||||||
pathMatchType: value as "exact" | "prefix" | "regex"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-25">
|
|
||||||
<SelectValue />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="exact">Exact</SelectItem>
|
|
||||||
<SelectItem value="prefix">Prefix</SelectItem>
|
|
||||||
<SelectItem value="regex">Regex</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<Input
|
|
||||||
placeholder={
|
|
||||||
row.original.pathMatchType === "regex"
|
|
||||||
? "^/api/.*"
|
|
||||||
: "/path"
|
|
||||||
}
|
|
||||||
defaultValue={row.original.path || ""}
|
|
||||||
className="flex-1 min-w-[150px]"
|
|
||||||
onBlur={(e) => {
|
|
||||||
const value = e.target.value.trim();
|
|
||||||
if (!value) {
|
|
||||||
setShowPathInput(false);
|
|
||||||
updateTarget(row.original.targetId, {
|
|
||||||
...row.original,
|
|
||||||
path: null,
|
|
||||||
pathMatchType: null
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
updateTarget(row.original.targetId, {
|
|
||||||
...row.original,
|
|
||||||
path: value
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => {
|
|
||||||
setShowPathInput(false);
|
|
||||||
updateTarget(row.original.targetId, {
|
|
||||||
...row.original,
|
|
||||||
path: null,
|
|
||||||
pathMatchType: null
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
×
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// {
|
// {
|
||||||
// accessorKey: "protocol",
|
// accessorKey: "protocol",
|
||||||
// header: t('targetProtocol'),
|
// header: t('targetProtocol'),
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ 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 { SquareArrowOutUpRight } from "lucide-react";
|
import { ArrowRight, MoveRight, 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";
|
||||||
@@ -355,8 +355,6 @@ export default function Page() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function onSubmit() {
|
async function onSubmit() {
|
||||||
setShowSnippets(true);
|
|
||||||
router.refresh();
|
|
||||||
setCreateLoading(true);
|
setCreateLoading(true);
|
||||||
|
|
||||||
const baseData = baseForm.getValues();
|
const baseData = baseForm.getValues();
|
||||||
@@ -537,6 +535,89 @@ export default function Page() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const columns: ColumnDef<LocalTarget>[] = [
|
const columns: ColumnDef<LocalTarget>[] = [
|
||||||
|
{
|
||||||
|
accessorKey: "path",
|
||||||
|
header: t("matchPath"),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const [showPathInput, setShowPathInput] = useState(
|
||||||
|
!!(row.original.path || row.original.pathMatchType)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!showPathInput) {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setShowPathInput(true)}
|
||||||
|
>
|
||||||
|
+ {t("matchPath")}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex gap-2 min-w-[200px] items-center">
|
||||||
|
<Select
|
||||||
|
defaultValue={row.original.pathMatchType || "exact"}
|
||||||
|
onValueChange={(value) =>
|
||||||
|
updateTarget(row.original.targetId, {
|
||||||
|
...row.original,
|
||||||
|
pathMatchType: value as "exact" | "prefix" | "regex"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-25">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="exact">Exact</SelectItem>
|
||||||
|
<SelectItem value="prefix">Prefix</SelectItem>
|
||||||
|
<SelectItem value="regex">Regex</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<Input
|
||||||
|
placeholder={
|
||||||
|
row.original.pathMatchType === "regex"
|
||||||
|
? "^/api/.*"
|
||||||
|
: "/path"
|
||||||
|
}
|
||||||
|
defaultValue={row.original.path || ""}
|
||||||
|
className="flex-1 min-w-[150px]"
|
||||||
|
onBlur={(e) => {
|
||||||
|
const value = e.target.value.trim();
|
||||||
|
if (!value) {
|
||||||
|
setShowPathInput(false);
|
||||||
|
updateTarget(row.original.targetId, {
|
||||||
|
...row.original,
|
||||||
|
path: null,
|
||||||
|
pathMatchType: null
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
updateTarget(row.original.targetId, {
|
||||||
|
...row.original,
|
||||||
|
path: value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => {
|
||||||
|
setShowPathInput(false);
|
||||||
|
updateTarget(row.original.targetId, {
|
||||||
|
...row.original,
|
||||||
|
path: null,
|
||||||
|
pathMatchType: null
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<MoveRight className="ml-4 h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "siteId",
|
accessorKey: "siteId",
|
||||||
header: t("site"),
|
header: t("site"),
|
||||||
@@ -710,87 +791,6 @@ export default function Page() {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
|
||||||
accessorKey: "path",
|
|
||||||
header: t("path"),
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const [showPathInput, setShowPathInput] = useState(
|
|
||||||
!!(row.original.path || row.original.pathMatchType)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!showPathInput) {
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => setShowPathInput(true)}
|
|
||||||
>
|
|
||||||
+ Path
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex gap-2 min-w-[200px]">
|
|
||||||
<Select
|
|
||||||
defaultValue={row.original.pathMatchType || "exact"}
|
|
||||||
onValueChange={(value) =>
|
|
||||||
updateTarget(row.original.targetId, {
|
|
||||||
...row.original,
|
|
||||||
pathMatchType: value as "exact" | "prefix" | "regex"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-25">
|
|
||||||
<SelectValue />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="exact">Exact</SelectItem>
|
|
||||||
<SelectItem value="prefix">Prefix</SelectItem>
|
|
||||||
<SelectItem value="regex">Regex</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<Input
|
|
||||||
placeholder={
|
|
||||||
row.original.pathMatchType === "regex"
|
|
||||||
? "^/api/.*"
|
|
||||||
: "/path"
|
|
||||||
}
|
|
||||||
defaultValue={row.original.path || ""}
|
|
||||||
className="flex-1 min-w-[150px]"
|
|
||||||
onBlur={(e) => {
|
|
||||||
const value = e.target.value.trim();
|
|
||||||
if (!value) {
|
|
||||||
setShowPathInput(false);
|
|
||||||
updateTarget(row.original.targetId, {
|
|
||||||
...row.original,
|
|
||||||
path: null,
|
|
||||||
pathMatchType: null
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
updateTarget(row.original.targetId, {
|
|
||||||
...row.original,
|
|
||||||
path: value
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => {
|
|
||||||
setShowPathInput(false);
|
|
||||||
updateTarget(row.original.targetId, {
|
|
||||||
...row.original,
|
|
||||||
path: null,
|
|
||||||
pathMatchType: null
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
×
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessorKey: "enabled",
|
accessorKey: "enabled",
|
||||||
header: t("enabled"),
|
header: t("enabled"),
|
||||||
|
|||||||
Reference in New Issue
Block a user