mirror of
https://github.com/fosrl/pangolin.git
synced 2026-07-06 12:19:50 +00:00
adjust targets input styles
This commit is contained in:
@@ -10,7 +10,10 @@ import {
|
|||||||
PathRewriteDisplay,
|
PathRewriteDisplay,
|
||||||
PathRewriteModal
|
PathRewriteModal
|
||||||
} from "@app/components/PathMatchRenameModal";
|
} from "@app/components/PathMatchRenameModal";
|
||||||
import { ResourceTargetAddressItem } from "@app/components/resource-target-address-item";
|
import {
|
||||||
|
ResourceTargetAddressItem,
|
||||||
|
ResourceTargetSiteItem
|
||||||
|
} from "@app/components/resource-target-address-item";
|
||||||
import {
|
import {
|
||||||
SettingsSection,
|
SettingsSection,
|
||||||
SettingsSectionBody,
|
SettingsSectionBody,
|
||||||
@@ -65,6 +68,7 @@ import {
|
|||||||
useMemo,
|
useMemo,
|
||||||
useState
|
useState
|
||||||
} from "react";
|
} from "react";
|
||||||
|
import { maxSize } from "zod";
|
||||||
|
|
||||||
export type LocalTarget = Omit<
|
export type LocalTarget = Omit<
|
||||||
ArrayElement<ListTargetsResponse["targets"]> & {
|
ArrayElement<ListTargetsResponse["targets"]> & {
|
||||||
@@ -269,7 +273,7 @@ export function ProxyResourceTargetsForm({
|
|||||||
const priorityColumn: ColumnDef<LocalTarget> = {
|
const priorityColumn: ColumnDef<LocalTarget> = {
|
||||||
id: "priority",
|
id: "priority",
|
||||||
header: () => (
|
header: () => (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2 p-3">
|
||||||
{t("priority")}
|
{t("priority")}
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
@@ -285,7 +289,6 @@ export function ProxyResourceTargetsForm({
|
|||||||
),
|
),
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center w-full">
|
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
min="1"
|
min="1"
|
||||||
@@ -303,7 +306,6 @@ export function ProxyResourceTargetsForm({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
size: 120,
|
size: 120,
|
||||||
@@ -437,13 +439,12 @@ export function ProxyResourceTargetsForm({
|
|||||||
maxSize: 200
|
maxSize: 200
|
||||||
};
|
};
|
||||||
|
|
||||||
const addressColumn: ColumnDef<LocalTarget> = {
|
const siteColumn: ColumnDef<LocalTarget> = {
|
||||||
accessorKey: "address",
|
accessorKey: "site",
|
||||||
header: () => <span className="p-3">{t("address")}</span>,
|
header: () => <span className="p-3">{t("site")}</span>,
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
return (
|
return (
|
||||||
<ResourceTargetAddressItem
|
<ResourceTargetSiteItem
|
||||||
isHttp={isHttp}
|
|
||||||
orgId={orgId}
|
orgId={orgId}
|
||||||
getDockerStateForSite={getDockerStateForSite}
|
getDockerStateForSite={getDockerStateForSite}
|
||||||
proxyTarget={row.original}
|
proxyTarget={row.original}
|
||||||
@@ -452,9 +453,26 @@ export function ProxyResourceTargetsForm({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
size: 400,
|
size: 220,
|
||||||
minSize: 350,
|
minSize: 180,
|
||||||
maxSize: 500
|
maxSize: 280
|
||||||
|
};
|
||||||
|
|
||||||
|
const addressColumn: ColumnDef<LocalTarget> = {
|
||||||
|
accessorKey: "address",
|
||||||
|
header: () => <span className="p-3">{t("address")}</span>,
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<ResourceTargetAddressItem
|
||||||
|
isHttp={isHttp}
|
||||||
|
proxyTarget={row.original}
|
||||||
|
updateTarget={updateTarget}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
size: 350,
|
||||||
|
minSize: 300,
|
||||||
|
maxSize: 450
|
||||||
};
|
};
|
||||||
|
|
||||||
const rewritePathColumn: ColumnDef<LocalTarget> = {
|
const rewritePathColumn: ColumnDef<LocalTarget> = {
|
||||||
@@ -567,6 +585,7 @@ export function ProxyResourceTargetsForm({
|
|||||||
|
|
||||||
if (isAdvancedMode) {
|
if (isAdvancedMode) {
|
||||||
const cols = [
|
const cols = [
|
||||||
|
siteColumn,
|
||||||
addressColumn,
|
addressColumn,
|
||||||
healthCheckColumn,
|
healthCheckColumn,
|
||||||
enabledColumn,
|
enabledColumn,
|
||||||
@@ -575,12 +594,13 @@ export function ProxyResourceTargetsForm({
|
|||||||
|
|
||||||
if (isHttp) {
|
if (isHttp) {
|
||||||
cols.unshift(matchPathColumn);
|
cols.unshift(matchPathColumn);
|
||||||
cols.splice(3, 0, rewritePathColumn, priorityColumn);
|
cols.splice(4, 0, rewritePathColumn, priorityColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cols;
|
return cols;
|
||||||
} else {
|
} else {
|
||||||
return [
|
return [
|
||||||
|
siteColumn,
|
||||||
addressColumn,
|
addressColumn,
|
||||||
healthCheckColumn,
|
healthCheckColumn,
|
||||||
enabledColumn,
|
enabledColumn,
|
||||||
@@ -818,6 +838,10 @@ export function ProxyResourceTargetsForm({
|
|||||||
header.column
|
header.column
|
||||||
.id ===
|
.id ===
|
||||||
"actions";
|
"actions";
|
||||||
|
const isSiteColumn =
|
||||||
|
header.column
|
||||||
|
.id ===
|
||||||
|
"site";
|
||||||
return (
|
return (
|
||||||
<TableHead
|
<TableHead
|
||||||
key={
|
key={
|
||||||
@@ -826,7 +850,9 @@ export function ProxyResourceTargetsForm({
|
|||||||
className={
|
className={
|
||||||
isActionsColumn
|
isActionsColumn
|
||||||
? "sticky right-0 z-10 w-auto min-w-fit bg-card"
|
? "sticky right-0 z-10 w-auto min-w-fit bg-card"
|
||||||
: ""
|
: isSiteColumn
|
||||||
|
? "w-45"
|
||||||
|
: ""
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{header.isPlaceholder
|
{header.isPlaceholder
|
||||||
@@ -858,6 +884,10 @@ export function ProxyResourceTargetsForm({
|
|||||||
cell.column
|
cell.column
|
||||||
.id ===
|
.id ===
|
||||||
"actions";
|
"actions";
|
||||||
|
const isSiteColumn =
|
||||||
|
cell.column
|
||||||
|
.id ===
|
||||||
|
"site";
|
||||||
return (
|
return (
|
||||||
<TableCell
|
<TableCell
|
||||||
key={
|
key={
|
||||||
@@ -866,7 +896,9 @@ export function ProxyResourceTargetsForm({
|
|||||||
className={
|
className={
|
||||||
isActionsColumn
|
isActionsColumn
|
||||||
? "sticky right-0 z-10 w-auto min-w-fit bg-card"
|
? "sticky right-0 z-10 w-auto min-w-fit bg-card"
|
||||||
: ""
|
: isSiteColumn
|
||||||
|
? "w-45"
|
||||||
|
: ""
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{flexRender(
|
{flexRender(
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import { cn } from "@app/lib/cn";
|
import { cn } from "@app/lib/cn";
|
||||||
import type { DockerState } from "@app/lib/docker";
|
import type { DockerState } from "@app/lib/docker";
|
||||||
import { parseHostTarget } from "@app/lib/parseHostTarget";
|
import { parseHostTarget } from "@app/lib/parseHostTarget";
|
||||||
import { orgQueries } from "@app/lib/queries";
|
|
||||||
import { CaretSortIcon } from "@radix-ui/react-icons";
|
import { CaretSortIcon } from "@radix-ui/react-icons";
|
||||||
import type { ListSitesResponse } from "@server/routers/site";
|
import type { ListSitesResponse } from "@server/routers/site";
|
||||||
import { type ListTargetsResponse } from "@server/routers/target";
|
import { type ListTargetsResponse } from "@server/routers/target";
|
||||||
import type { ArrayElement } from "@server/types/ArrayElement";
|
import type { ArrayElement } from "@server/types/ArrayElement";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
|
||||||
import { CheckIcon } from "lucide-react";
|
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { useMemo, useState } from "react";
|
import { useState } from "react";
|
||||||
import { ContainersSelector } from "./ContainersSelector";
|
import { ContainersSelector } from "./ContainersSelector";
|
||||||
import { Button } from "./ui/button";
|
import { Button } from "./ui/button";
|
||||||
import { Input } from "./ui/input";
|
import { Input } from "./ui/input";
|
||||||
@@ -28,23 +25,21 @@ export type LocalTarget = Omit<
|
|||||||
"protocol"
|
"protocol"
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type ResourceTargetAddressItemProps = {
|
export type ResourceTargetSiteItemProps = {
|
||||||
getDockerStateForSite: (siteId: number) => DockerState;
|
getDockerStateForSite: (siteId: number) => DockerState;
|
||||||
updateTarget: (targetId: number, data: Partial<LocalTarget>) => void;
|
updateTarget: (targetId: number, data: Partial<LocalTarget>) => void;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
proxyTarget: LocalTarget;
|
proxyTarget: LocalTarget;
|
||||||
isHttp: boolean;
|
|
||||||
refreshContainersForSite: (siteId: number) => void;
|
refreshContainersForSite: (siteId: number) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ResourceTargetAddressItem({
|
export function ResourceTargetSiteItem({
|
||||||
orgId,
|
orgId,
|
||||||
getDockerStateForSite,
|
getDockerStateForSite,
|
||||||
updateTarget,
|
updateTarget,
|
||||||
proxyTarget,
|
proxyTarget,
|
||||||
isHttp,
|
|
||||||
refreshContainersForSite
|
refreshContainersForSite
|
||||||
}: ResourceTargetAddressItemProps) {
|
}: ResourceTargetSiteItemProps) {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
|
|
||||||
const [selectedSite, setSelectedSite] = useState<Pick<
|
const [selectedSite, setSelectedSite] = useState<Pick<
|
||||||
@@ -76,62 +71,78 @@ export function ResourceTargetAddressItem({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex w-full min-w-0 items-center h-9 border border-input rounded-md"
|
||||||
|
key={proxyTarget.targetId}
|
||||||
|
>
|
||||||
|
{selectedSite && selectedSite.type === "newt" && (
|
||||||
|
<ContainersSelector
|
||||||
|
site={selectedSite}
|
||||||
|
containers={
|
||||||
|
getDockerStateForSite(selectedSite.siteId).containers
|
||||||
|
}
|
||||||
|
isAvailable={
|
||||||
|
getDockerStateForSite(selectedSite.siteId).isAvailable
|
||||||
|
}
|
||||||
|
onContainerSelect={handleContainerSelectForTarget}
|
||||||
|
onRefresh={() =>
|
||||||
|
refreshContainersForSite(selectedSite.siteId)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
role="combobox"
|
||||||
|
className={cn(
|
||||||
|
"h-9 min-w-0 flex-1 justify-between px-3 rounded-none hover:bg-transparent",
|
||||||
|
!proxyTarget.siteId && "text-muted-foreground"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span className="truncate">
|
||||||
|
{proxyTarget.siteId
|
||||||
|
? selectedSite?.name
|
||||||
|
: t("siteSelect")}
|
||||||
|
</span>
|
||||||
|
<CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="p-0">
|
||||||
|
<SitesSelector
|
||||||
|
orgId={orgId}
|
||||||
|
selectedSite={selectedSite}
|
||||||
|
onSelectSite={(site) => {
|
||||||
|
updateTarget(proxyTarget.targetId, {
|
||||||
|
siteId: site.siteId,
|
||||||
|
siteType: site.type,
|
||||||
|
siteName: site.name
|
||||||
|
});
|
||||||
|
setSelectedSite(site);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ResourceTargetAddressItemProps = {
|
||||||
|
updateTarget: (targetId: number, data: Partial<LocalTarget>) => void;
|
||||||
|
proxyTarget: LocalTarget;
|
||||||
|
isHttp: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function ResourceTargetAddressItem({
|
||||||
|
updateTarget,
|
||||||
|
proxyTarget,
|
||||||
|
isHttp
|
||||||
|
}: ResourceTargetAddressItemProps) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center w-full" key={proxyTarget.targetId}>
|
<div className="flex items-center w-full" key={proxyTarget.targetId}>
|
||||||
<div className="flex items-center w-full justify-start py-0 space-x-2 px-0 cursor-default border border-input rounded-md">
|
<div className="flex items-center w-full justify-start py-0 space-x-2 px-0 cursor-default border border-input rounded-md">
|
||||||
{selectedSite && selectedSite.type === "newt" && (
|
|
||||||
<ContainersSelector
|
|
||||||
site={selectedSite}
|
|
||||||
containers={
|
|
||||||
getDockerStateForSite(selectedSite.siteId)
|
|
||||||
.containers
|
|
||||||
}
|
|
||||||
isAvailable={
|
|
||||||
getDockerStateForSite(selectedSite.siteId)
|
|
||||||
.isAvailable
|
|
||||||
}
|
|
||||||
onContainerSelect={handleContainerSelectForTarget}
|
|
||||||
onRefresh={() =>
|
|
||||||
refreshContainersForSite(selectedSite.siteId)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Popover>
|
|
||||||
<PopoverTrigger asChild>
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
role="combobox"
|
|
||||||
className={cn(
|
|
||||||
"w-45 justify-between text-sm border-r pr-4 rounded-none h-8 hover:bg-transparent",
|
|
||||||
"",
|
|
||||||
!proxyTarget.siteId && "text-muted-foreground"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<span className="truncate max-w-37.5">
|
|
||||||
{proxyTarget.siteId
|
|
||||||
? selectedSite?.name
|
|
||||||
: t("siteSelect")}
|
|
||||||
</span>
|
|
||||||
<CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
|
||||||
</Button>
|
|
||||||
</PopoverTrigger>
|
|
||||||
<PopoverContent className="p-0">
|
|
||||||
<SitesSelector
|
|
||||||
orgId={orgId}
|
|
||||||
selectedSite={selectedSite}
|
|
||||||
onSelectSite={(site) => {
|
|
||||||
updateTarget(proxyTarget.targetId, {
|
|
||||||
siteId: site.siteId,
|
|
||||||
siteType: site.type,
|
|
||||||
siteName: site.name
|
|
||||||
});
|
|
||||||
setSelectedSite(site);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</PopoverContent>
|
|
||||||
</Popover>
|
|
||||||
|
|
||||||
{isHttp && (
|
{isHttp && (
|
||||||
<Select
|
<Select
|
||||||
defaultValue={proxyTarget.method ?? "http"}
|
defaultValue={proxyTarget.method ?? "http"}
|
||||||
@@ -142,7 +153,7 @@ export function ResourceTargetAddressItem({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="h-8 px-2 w-17.5 border-none bg-transparent shadow-none data-[state=open]:bg-transparent rounded-none">
|
<SelectTrigger className="h-9 pl-2 w-17.5 border-none bg-transparent shadow-none data-[state=open]:bg-transparent rounded-none mr-0 pr-0">
|
||||||
{proxyTarget.method || "http"}
|
{proxyTarget.method || "http"}
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@@ -154,7 +165,7 @@ export function ResourceTargetAddressItem({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{isHttp && (
|
{isHttp && (
|
||||||
<div className="flex items-center justify-center px-2 h-9">
|
<div className="flex items-center justify-center h-9 mr-0 pl-1">
|
||||||
{"://"}
|
{"://"}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -195,7 +206,7 @@ export function ResourceTargetAddressItem({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="flex items-center justify-center px-2 h-9">
|
<div className="flex items-center justify-center h-9 mr-0">
|
||||||
{":"}
|
{":"}
|
||||||
</div>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
|
|||||||
Reference in New Issue
Block a user