Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/app/(dashboard)/agent-network/configuration/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export default function AgentNetworkConfigurationPage() {
</VerticalTabs.List>
<RestrictedAccess
page={"Configuration"}
hasAccess={permission?.services?.read}
hasAccess={permission?.["agent_network.settings"]?.read}
>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
<GroupsProvider>
<PeersProvider>
Expand Down
2 changes: 1 addition & 1 deletion src/app/(dashboard)/agent-network/policies/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export default function AgentNetworkPoliciesPage() {

<RestrictedAccess
page={"Policies"}
hasAccess={permission?.services?.read}
hasAccess={permission?.["agent_network.policies"]?.read}
>
<AIProvidersProvider>
<Suspense fallback={<SkeletonTable />}>
Expand Down
4 changes: 2 additions & 2 deletions src/app/(dashboard)/agent-network/providers/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,10 @@ export default function AgentNetworkProvidersPage() {
<PageContainer>
{/* Gate the whole surface: AIProvidersProvider and EndpointHeader fetch
agent-network state, so they must not mount for users without
services.read. */}
read on the providers submodule. */}
<RestrictedAccess
page={"Providers"}
hasAccess={permission?.services?.read}
hasAccess={permission?.["agent_network.providers"]?.read}
>
<AIProvidersProvider>
<div className={"p-default py-6"}>
Expand Down
5 changes: 4 additions & 1 deletion src/app/(dashboard)/agent-network/usage/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ export default function UsageAndLogsPage() {

<RestrictedAccess
page={"Usage & Logs"}
hasAccess={permission?.services?.read}
hasAccess={
permission?.["agent_network.usage"]?.read ||
permission?.["agent_network.logs"]?.read
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
>
<GroupsProvider>
<PeersProvider>
Expand Down
8 changes: 8 additions & 0 deletions src/contexts/PermissionsProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ const MODULE_KEYS: Array<keyof Permissions["modules"]> = [
"proxy",
"proxy_configuration",
"services",
"agent_network",
"agent_network.providers",
"agent_network.policies",
"agent_network.guardrails",
"agent_network.budgets",
"agent_network.usage",
"agent_network.logs",
"agent_network.settings",
];

const DENIED: Permission = {
Expand Down
9 changes: 9 additions & 0 deletions src/interfaces/Permission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ export interface Permissions {
proxy_configuration: Permission;

services: Permission;

agent_network: Permission;
"agent_network.providers": Permission;
"agent_network.policies": Permission;
"agent_network.guardrails": Permission;
"agent_network.budgets": Permission;
"agent_network.usage": Permission;
"agent_network.logs": Permission;
"agent_network.settings": Permission;
};
}

Expand Down
2 changes: 2 additions & 0 deletions src/interfaces/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,6 @@ export enum Role {
BillingAdmin = "billing_admin",
Auditor = "auditor",
NetworkAdmin = "network_admin",
AgentNetworkAdmin = "agent_network_admin",
UsageViewer = "usage_viewer",
}
37 changes: 29 additions & 8 deletions src/layouts/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,38 +197,59 @@ export default function Navigation({
href={"/agent-network/providers"}
collapsible
exactPathMatch={false}
// Parent is visible when at least one child is permitted. All
// Agent Network pages guard on services.read, so the section
// tracks that (plus the feature gating).
visible={agentNetworkEnabled && permission?.services?.read}
// Parent is visible when at least one child is permitted.
// Each page tracks its agent_network submodule, so delegated
// roles (agent_network_admin, usage_viewer) see exactly the
// pages their grants cover.
visible={
agentNetworkEnabled &&
(permission?.["agent_network.providers"]?.read ||
permission?.["agent_network.policies"]?.read ||
permission?.["agent_network.usage"]?.read ||
permission?.["agent_network.logs"]?.read ||
permission?.["agent_network.settings"]?.read)
}
>
<SidebarItem
label="Providers"
isChild
href={"/agent-network/providers"}
exactPathMatch={true}
visible={agentNetworkEnabled && permission?.services?.read}
visible={
agentNetworkEnabled &&
permission?.["agent_network.providers"]?.read
}
/>
<SidebarItem
label="Policies"
isChild
href={"/agent-network/policies"}
exactPathMatch={true}
visible={agentNetworkEnabled && permission?.services?.read}
visible={
agentNetworkEnabled &&
permission?.["agent_network.policies"]?.read
}
/>
<SidebarItem
label="Usage & Logs"
isChild
href={"/agent-network/usage"}
exactPathMatch={true}
visible={agentNetworkEnabled && permission?.services?.read}
visible={
agentNetworkEnabled &&
(permission?.["agent_network.usage"]?.read ||
permission?.["agent_network.logs"]?.read)
}
/>
<SidebarItem
label="Configuration"
isChild
href={"/agent-network/configuration"}
exactPathMatch={true}
visible={agentNetworkEnabled && permission?.services?.read}
visible={
agentNetworkEnabled &&
permission?.["agent_network.settings"]?.read
}
/>
</SidebarItem>

Expand Down
16 changes: 16 additions & 0 deletions src/modules/users/UserInvitesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@ import {
CreditCardIcon,
ExternalLinkIcon,
EyeIcon,
GaugeIcon,
Link2,
MailPlus,
NetworkIcon,
Trash2,
User2,
} from "lucide-react";
import AgentNetworkIcon from "@/assets/icons/AgentNetworkIcon";
import NetBirdIcon from "@/assets/icons/NetBirdIcon";
import Badge from "@components/Badge";
import { usePathname } from "next/navigation";
Expand Down Expand Up @@ -145,6 +147,18 @@ function InviteRoleCell({ invite }: { invite: UserInvite }) {
Network Admin
</>
)}
{role === Role.AgentNetworkAdmin && (
<>
<AgentNetworkIcon size={14} />
Agent Network Admin
</>
)}
{role === Role.UsageViewer && (
<>
<GaugeIcon size={14} />
Usage Viewer
</>
)}
</Badge>
</div>
);
Expand Down Expand Up @@ -500,6 +514,8 @@ export default function UserInvitesTable({
{ value: "admin", label: "Admin" },
{ value: "user", label: "User" },
{ value: "network_admin", label: "Network Admin" },
{ value: "agent_network_admin", label: "Agent Network Admin" },
{ value: "usage_viewer", label: "Usage Viewer" },
{ value: "billing_admin", label: "Billing Admin" },
{ value: "auditor", label: "Auditor" },
],
Expand Down
12 changes: 12 additions & 0 deletions src/modules/users/UserRoleSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import {
Cog,
CreditCard,
EyeIcon,
GaugeIcon,
NetworkIcon,
User2,
} from "lucide-react";
import * as React from "react";
import { useState } from "react";
import AgentNetworkIcon from "@/assets/icons/AgentNetworkIcon";
import NetBirdIcon from "@/assets/icons/NetBirdIcon";
import { useMSP } from "@/cloud/msp/contexts/MSPProvider";
import { useDialog } from "@/contexts/DialogProvider";
Expand Down Expand Up @@ -51,6 +53,16 @@ export const UserRoles = [
value: Role.NetworkAdmin,
icon: NetworkIcon,
},
{
name: "Agent Network Admin",
value: Role.AgentNetworkAdmin,
icon: AgentNetworkIcon,
},
{
name: "Usage Viewer",
value: Role.UsageViewer,
icon: GaugeIcon,
},
{
name: "Billing Admin",
value: Role.BillingAdmin,
Expand Down
2 changes: 2 additions & 0 deletions src/modules/users/UsersTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ export default function UsersTable({
{ value: "admin", label: "Admin" },
{ value: "user", label: "User" },
{ value: "network_admin", label: "Network Admin" },
{ value: "agent_network_admin", label: "Agent Network Admin" },
{ value: "usage_viewer", label: "Usage Viewer" },
{ value: "billing_admin", label: "Billing Admin" },
{ value: "auditor", label: "Auditor" },
],
Expand Down
22 changes: 21 additions & 1 deletion src/modules/users/table-cells/UserRoleCell.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import Badge from "@components/Badge";
import { cn } from "@utils/helpers";
import { Cog, CreditCardIcon, EyeIcon, NetworkIcon, User2 } from "lucide-react";
import {
Cog,
CreditCardIcon,
EyeIcon,
GaugeIcon,
NetworkIcon,
User2,
} from "lucide-react";
import React from "react";
import AgentNetworkIcon from "@/assets/icons/AgentNetworkIcon";
import NetBirdIcon from "@/assets/icons/NetBirdIcon";
import { Role, User } from "@/interfaces/User";

Expand Down Expand Up @@ -51,6 +59,18 @@ export default function UserRoleCell({ user }: Readonly<Props>) {
Network Admin
</>
)}
{role === Role.AgentNetworkAdmin && (
<>
<AgentNetworkIcon size={14} />
Agent Network Admin
</>
)}
{role === Role.UsageViewer && (
<>
<GaugeIcon size={14} />
Usage Viewer
</>
)}
</Badge>
</div>
);
Expand Down
Loading