💄 show attached resources in policy list

This commit is contained in:
Fred KISSIE
2026-03-06 04:36:12 +01:00
parent dfe42e9016
commit 37ceba6b81
4 changed files with 91 additions and 5 deletions

View File

@@ -167,6 +167,9 @@
"resourceAdd": "Add Resource",
"resourceErrorDelte": "Error deleting resource",
"resourcePoliciesTitle": "Manage Resource Policies",
"resourcePoliciesAttachedResourcesColumnTitle": "Attached resources",
"resourcePoliciesAttachedResources": "{count} resource(s)",
"resourcePoliciesAttachedResourcesEmpty": "no resources",
"resourcePoliciesDescription": "Create and manage authentication policies to control access to your resources",
"resourcePoliciesSearch": "Search policies...",
"resourcePoliciesAdd": "Add Policy",
@@ -1069,7 +1072,6 @@
"pageNotFoundDescription": "Oops! The page you're looking for doesn't exist.",
"overview": "Overview",
"home": "Home",
"accessControl": "Access Control",
"settings": "Settings",
"usersAll": "All Users",
"license": "License",

View File

@@ -12,11 +12,16 @@ export type GetMaintenanceInfoResponse = {
maintenanceEstimatedTime: string | null;
};
export type AttachedResource = Pick<
Resource,
"resourceId" | "name" | "fullDomain"
>;
export type ResourcePolicyWithResources = Pick<
ResourcePolicy,
"resourcePolicyId" | "niceId" | "name" | "orgId"
> & {
resources: Array<Pick<Resource, "resourceId" | "name" | "fullDomain">>;
resources: Array<AttachedResource>;
};
export type ListResourcePoliciesResponse = PaginatedResponse<{

View File

@@ -3,7 +3,6 @@ import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
import { internal } from "@app/lib/api";
import { authCookieHeader } from "@app/lib/api/cookies";
import { getCachedOrg } from "@app/lib/api/getCachedOrg";
import OrgProvider from "@app/providers/OrgProvider";
import type { GetOrgResponse } from "@server/routers/org";
import type { ListResourcePoliciesResponse } from "@server/routers/resource/types";
import type { AxiosResponse } from "axios";

View File

@@ -3,9 +3,17 @@ import { useEnvContext } from "@app/hooks/useEnvContext";
import { useNavigationContext } from "@app/hooks/useNavigationContext";
import { toast } from "@app/hooks/useToast";
import { createApiClient } from "@app/lib/api";
import type { ListResourcePoliciesResponse } from "@server/routers/resource/types";
import type {
AttachedResource,
ListResourcePoliciesResponse
} from "@server/routers/resource/types";
import type { PaginationState } from "@tanstack/react-table";
import { ArrowRight, MoreHorizontal } from "lucide-react";
import {
ArrowRight,
ChevronDown,
MoreHorizontal,
Waypoints
} from "lucide-react";
import { useTranslations } from "next-intl";
import Link from "next/link";
import { useRouter } from "next/navigation";
@@ -20,6 +28,8 @@ import {
DropdownMenuItem,
DropdownMenuTrigger
} from "./ui/dropdown-menu";
import type { targets } from "@server/db";
import type { TargetHealth } from "./ProxyResourcesTable";
type ResourcePolicyRow = ListResourcePoliciesResponse["policies"][number];
@@ -65,6 +75,63 @@ export function ResourcePoliciesTable({
});
};
function ResourceListCell({
resources
}: {
resources?: AttachedResource[];
}) {
if (!resources || resources.length === 0) {
return (
<div
id="LOOK_FOR_ME"
className="flex items-center gap-2 text-muted-foreground"
>
<Waypoints className="size-4 flex-none" />
<span className="text-sm">
{t("resourcePoliciesAttachedResourcesEmpty")}
</span>
</div>
);
}
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="sm"
className="flex items-center gap-2 h-8 px-0 font-normal"
>
<Waypoints className="size-4 flex-none" />
<span className="text-sm">
{t("resourcePoliciesAttachedResources", {
count: resources.length
})}
</span>
<ChevronDown className="h-3 w-3" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="min-w-70">
{resources.map((resource) => (
<DropdownMenuItem
key={resource.resourceId}
className="flex items-center justify-between gap-4"
>
<div className="flex items-center gap-2">
{resource.name}
</div>
<span
className={`capitalize text-muted-foreground`}
>
{resource.fullDomain}
</span>
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
);
}
const proxyColumns: ExtendedColumnDef<ResourcePolicyRow>[] = [
{
accessorKey: "name",
@@ -83,6 +150,19 @@ export function ResourcePoliciesTable({
return <span>{row.original.niceId || "-"}</span>;
}
},
{
id: "resources",
accessorKey: "resources",
friendlyName: t("resourcePoliciesAttachedResourcesColumnTitle"),
header: () => (
<span className="p-3">
{t("resourcePoliciesAttachedResourcesColumnTitle")}
</span>
),
cell: ({ row }) => {
return <ResourceListCell resources={row.original.resources} />;
}
},
{
id: "actions",
enableHiding: false,