mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-22 16:55:44 +00:00
🚧 tried to memo proxy resource table, failed
This commit is contained in:
@@ -118,6 +118,11 @@ type ProxyResourcesTableProps = {
|
|||||||
initialFilterSite?: Selectedsite | null;
|
initialFilterSite?: Selectedsite | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const booleanSearchFilterSchema = z
|
||||||
|
.enum(["true", "false"])
|
||||||
|
.optional()
|
||||||
|
.catch(undefined);
|
||||||
|
|
||||||
export default function ProxyResourcesTable({
|
export default function ProxyResourcesTable({
|
||||||
resources,
|
resources,
|
||||||
orgId,
|
orgId,
|
||||||
@@ -224,7 +229,30 @@ export default function ProxyResourcesTable({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const proxyColumns: ExtendedColumnDef<ResourceRow>[] = [
|
const clearSiteFilter = () => {
|
||||||
|
handleFilterChange("siteId", undefined);
|
||||||
|
setSiteFilterOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPickSite = (site: Selectedsite) => {
|
||||||
|
handleFilterChange("siteId", String(site.siteId));
|
||||||
|
setSiteFilterOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const siteFilterOpenRef = useRef(siteFilterOpen);
|
||||||
|
siteFilterOpenRef.current = siteFilterOpen;
|
||||||
|
|
||||||
|
const selectedSiteRef = useRef(selectedSite);
|
||||||
|
selectedSiteRef.current = selectedSite;
|
||||||
|
|
||||||
|
const clearSiteFilterRef = useRef(clearSiteFilter);
|
||||||
|
clearSiteFilterRef.current = clearSiteFilter;
|
||||||
|
|
||||||
|
const onPickSiteRef = useRef(onPickSite);
|
||||||
|
onPickSiteRef.current = onPickSite;
|
||||||
|
|
||||||
|
const proxyColumns = useMemo<ExtendedColumnDef<ResourceRow>[]>(() => {
|
||||||
|
const cols: ExtendedColumnDef<ResourceRow>[] = [
|
||||||
{
|
{
|
||||||
accessorKey: "name",
|
accessorKey: "name",
|
||||||
enableHiding: false,
|
enableHiding: false,
|
||||||
@@ -262,10 +290,14 @@ export default function ProxyResourcesTable({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "sites",
|
id: "sites",
|
||||||
accessorFn: (row) => row.sites.map((s) => s.siteName).join(", "),
|
accessorFn: (row) =>
|
||||||
|
row.sites.map((s) => s.siteName).join(", "),
|
||||||
friendlyName: t("sites"),
|
friendlyName: t("sites"),
|
||||||
header: () => (
|
header: () => (
|
||||||
<Popover open={siteFilterOpen} onOpenChange={setSiteFilterOpen}>
|
<Popover
|
||||||
|
open={siteFilterOpenRef.current}
|
||||||
|
onOpenChange={setSiteFilterOpen}
|
||||||
|
>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -273,18 +305,19 @@ export default function ProxyResourcesTable({
|
|||||||
role="combobox"
|
role="combobox"
|
||||||
className={cn(
|
className={cn(
|
||||||
"justify-between text-sm h-8 px-2 w-full p-3",
|
"justify-between text-sm h-8 px-2 w-full p-3",
|
||||||
!selectedSite && "text-muted-foreground"
|
!selectedSiteRef.current &&
|
||||||
|
"text-muted-foreground"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 min-w-0">
|
<div className="flex items-center gap-2 min-w-0">
|
||||||
{t("sites")}
|
{t("sites")}
|
||||||
<Funnel className="size-4 flex-none" />
|
<Funnel className="size-4 flex-none" />
|
||||||
{selectedSite && (
|
{selectedSiteRef.current && (
|
||||||
<Badge
|
<Badge
|
||||||
className="truncate max-w-[10rem]"
|
className="truncate max-w-[10rem]"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
{selectedSite.name}
|
{selectedSiteRef.current.name}
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -300,15 +333,17 @@ export default function ProxyResourcesTable({
|
|||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="h-8 w-full justify-start font-normal"
|
className="h-8 w-full justify-start font-normal"
|
||||||
onClick={clearSiteFilter}
|
onClick={() => clearSiteFilterRef.current()}
|
||||||
>
|
>
|
||||||
{t("standaloneHcFilterAnySite")}
|
{t("standaloneHcFilterAnySite")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<SitesSelector
|
<SitesSelector
|
||||||
orgId={orgId}
|
orgId={orgId}
|
||||||
selectedSite={selectedSite}
|
selectedSite={selectedSiteRef.current}
|
||||||
onSelectSite={onPickSite}
|
onSelectSite={(site) =>
|
||||||
|
onPickSiteRef.current(site)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
@@ -345,7 +380,10 @@ export default function ProxyResourcesTable({
|
|||||||
header: () => (
|
header: () => (
|
||||||
<ColumnFilterButton
|
<ColumnFilterButton
|
||||||
options={[
|
options={[
|
||||||
{ value: "healthy", label: t("resourcesTableHealthy") },
|
{
|
||||||
|
value: "healthy",
|
||||||
|
label: t("resourcesTableHealthy")
|
||||||
|
},
|
||||||
{
|
{
|
||||||
value: "degraded",
|
value: "degraded",
|
||||||
label: t("resourcesTableDegraded")
|
label: t("resourcesTableDegraded")
|
||||||
@@ -354,7 +392,10 @@ export default function ProxyResourcesTable({
|
|||||||
value: "unhealthy",
|
value: "unhealthy",
|
||||||
label: t("resourcesTableUnhealthy")
|
label: t("resourcesTableUnhealthy")
|
||||||
},
|
},
|
||||||
{ value: "unknown", label: t("resourcesTableUnknown") }
|
{
|
||||||
|
value: "unknown",
|
||||||
|
label: t("resourcesTableUnknown")
|
||||||
|
}
|
||||||
]}
|
]}
|
||||||
selectedValue={
|
selectedValue={
|
||||||
searchParams.get("healthStatus") ?? undefined
|
searchParams.get("healthStatus") ?? undefined
|
||||||
@@ -398,7 +439,9 @@ export default function ProxyResourcesTable({
|
|||||||
header: () => <span className="p-3">{t("uptime30d")}</span>,
|
header: () => <span className="p-3">{t("uptime30d")}</span>,
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const resourceRow = row.original;
|
const resourceRow = row.original;
|
||||||
return <UptimeMiniBar resourceId={resourceRow.id} days={30} />;
|
return (
|
||||||
|
<UptimeMiniBar resourceId={resourceRow.id} days={30} />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -412,7 +455,9 @@ export default function ProxyResourcesTable({
|
|||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2 min-w-0">
|
<div className="flex items-center gap-2 min-w-0">
|
||||||
<CopyToClipboard
|
<CopyToClipboard
|
||||||
text={resourceRow.proxyPort?.toString() || ""}
|
text={
|
||||||
|
resourceRow.proxyPort?.toString() || ""
|
||||||
|
}
|
||||||
isLink={false}
|
isLink={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -468,10 +513,15 @@ export default function ProxyResourcesTable({
|
|||||||
<ColumnFilterButton
|
<ColumnFilterButton
|
||||||
options={[
|
options={[
|
||||||
{ value: "protected", label: t("protected") },
|
{ value: "protected", label: t("protected") },
|
||||||
{ value: "not_protected", label: t("notProtected") },
|
{
|
||||||
|
value: "not_protected",
|
||||||
|
label: t("notProtected")
|
||||||
|
},
|
||||||
{ value: "none", label: t("none") }
|
{ value: "none", label: t("none") }
|
||||||
]}
|
]}
|
||||||
selectedValue={searchParams.get("authState") ?? undefined}
|
selectedValue={
|
||||||
|
searchParams.get("authState") ?? undefined
|
||||||
|
}
|
||||||
onValueChange={(value) =>
|
onValueChange={(value) =>
|
||||||
handleFilterChange("authState", value)
|
handleFilterChange("authState", value)
|
||||||
}
|
}
|
||||||
@@ -530,27 +580,6 @@ export default function ProxyResourcesTable({
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
...(isLabelFeatureEnabled
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
id: "labels",
|
|
||||||
accessorKey: "labels",
|
|
||||||
header: () => (
|
|
||||||
<span className="p-3 text-end w-full inline-block">
|
|
||||||
{t("labels")}
|
|
||||||
</span>
|
|
||||||
),
|
|
||||||
cell: ({ row }: { row: { original: ResourceRow } }) => {
|
|
||||||
return (
|
|
||||||
<ResourceLabelCell
|
|
||||||
resource={row.original}
|
|
||||||
orgId={orgId}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
{
|
{
|
||||||
id: "actions",
|
id: "actions",
|
||||||
enableHiding: false,
|
enableHiding: false,
|
||||||
@@ -561,7 +590,10 @@ export default function ProxyResourcesTable({
|
|||||||
<div className="flex items-center gap-2 justify-end">
|
<div className="flex items-center gap-2 justify-end">
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
className="h-8 w-8 p-0"
|
||||||
|
>
|
||||||
<span className="sr-only">
|
<span className="sr-only">
|
||||||
{t("openMenu")}
|
{t("openMenu")}
|
||||||
</span>
|
</span>
|
||||||
@@ -603,10 +635,23 @@ export default function ProxyResourcesTable({
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const booleanSearchFilterSchema = z
|
if (isLabelFeatureEnabled) {
|
||||||
.enum(["true", "false"])
|
cols.splice(cols.length - 1, 0, {
|
||||||
.optional()
|
id: "labels",
|
||||||
.catch(undefined);
|
accessorKey: "labels",
|
||||||
|
header: () => (
|
||||||
|
<span className="p-3 text-end w-full inline-block">
|
||||||
|
{t("labels")}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
cell: ({ row }: { row: { original: ResourceRow } }) => (
|
||||||
|
<ResourceLabelCell resource={row.original} orgId={orgId} />
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return cols;
|
||||||
|
}, [isLabelFeatureEnabled, orgId, t, searchParams]);
|
||||||
|
|
||||||
function handleFilterChange(
|
function handleFilterChange(
|
||||||
column: string,
|
column: string,
|
||||||
@@ -623,16 +668,6 @@ export default function ProxyResourcesTable({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const clearSiteFilter = () => {
|
|
||||||
handleFilterChange("siteId", undefined);
|
|
||||||
setSiteFilterOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onPickSite = (site: Selectedsite) => {
|
|
||||||
handleFilterChange("siteId", String(site.siteId));
|
|
||||||
setSiteFilterOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
function toggleSort(column: string) {
|
function toggleSort(column: string) {
|
||||||
const newSearch = getNextSortOrder(column, searchParams);
|
const newSearch = getNextSortOrder(column, searchParams);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user