Loading portal-gui/src/app/config/navigation.ts +9 −0 Changes for portal-gui/src/app/config/navigation.ts: 9 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ import { Rocket, UserIcon, Handshake, KeyRoundIcon, } from 'lucide-react'; import { ROUTES } from './route'; Loading @@ -30,6 +31,14 @@ export const mainNavItems: NavItem[] = [ showInSidebar: true, }, { title: 'API clients', to: ROUTES.API_CLIENTS, description: 'Credentials for calling the APIs from your own systems.', icon: KeyRoundIcon, showInSidebar: true, roles: ['app-provider'], }, { title: 'Applications', to: ROUTES.APPLICATIONS, Loading portal-gui/src/app/config/route.ts +1 −0 Changes for portal-gui/src/app/config/route.ts: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ export const ROUTES = { PROFILE: '/profile', APIS: '/apis', API_CLIENTS: '/api-clients', API: '/apis/:id', APPLICATIONS: '/applications', APPLICATION_PROFILES: '/applications/profiles', Loading portal-gui/src/app/router.tsx +9 −0 Changes for portal-gui/src/app/router.tsx: 9 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ import { RoleGuard } from './guards/role-guard'; import HomePage from '@/pages/home/index'; import ProfilePage from '@/pages/profile'; import LoginPage from '@/pages/auth/login'; import ApiClientsPage from '@/pages/api-clients'; import ApisPage from '@/pages/apis/'; import ApiDetailsPage from '@/pages/apis/api-details'; import ApplicationsPage from '@/pages/applications/index'; Loading Loading @@ -60,6 +61,14 @@ export const router = createBrowserRouter([ path: ROUTES.APIS, element: <ApisPage />, }, { path: ROUTES.API_CLIENTS, element: ( <RoleGuard allowedRoles={['app-provider']}> <ApiClientsPage /> </RoleGuard> ), }, // API details MUST match /apis/:id { Loading portal-gui/src/components/api-clients/api-client-columns.tsx 0 → 100644 +70 −0 Changes for portal-gui/src/components/api-clients/api-client-columns.tsx: 70 added lines, 0 removed lines. Original line number Diff line number Diff line import type { ColumnDef } from '@tanstack/react-table'; import { Badge } from '@/components/ui/badge'; import type { ApiClient } from '@/types/api-clients'; export const apiClientColumns: ColumnDef<ApiClient>[] = [ { id: 'drag', header: () => null, enableHiding: false, size: 40, }, { id: 'name', accessorKey: 'name', header: 'Name', cell: ({ row }) => { const client = row.original; return ( <> <span className="block max-w-64 truncate font-medium" title={client.name} > {client.name} </span> {client.description && ( <p className="mt-1 max-w-64 truncate text-xs text-muted-foreground"> {client.description} </p> )} </> ); }, size: 220, }, { id: 'client_id', accessorKey: 'client_id', header: 'Client ID', cell: ({ row }) => ( <span className="font-mono text-xs">{row.original.client_id}</span> ), size: 140, }, { id: 'products', header: 'Products', cell: ({ row }) => ( <div className="flex flex-wrap gap-1"> {row.original.products.map((product) => ( <Badge key={product} variant="secondary"> {product} </Badge> ))} </div> ), size: 280, }, { id: 'created', accessorKey: 'created_at', header: 'Created', cell: ({ row }) => row.original.created_at ? new Date(row.original.created_at).toLocaleDateString() : '—', size: 120, }, ]; portal-gui/src/components/api-clients/api-clients-notices.tsx 0 → 100644 +24 −0 Changes for portal-gui/src/components/api-clients/api-clients-notices.tsx: 24 added lines, 0 removed lines. Original line number Diff line number Diff line import { InfoIcon } from 'lucide-react'; // R2 has no automatic clean-up, so these say what the portal does not do. export function ApiClientsNotice() { return ( <div className="mx-4 flex gap-3 rounded-md border bg-muted/40 p-3 text-sm lg:mx-6"> <InfoIcon className="mt-0.5 size-4 shrink-0 text-muted-foreground" /> <p> API clients keep working until they are deleted. If you leave your organization, lose access to a product or no longer need an app, delete its API client, or ask an administrator to. </p> </div> ); } export function ApiClientsFootnote() { return ( <p className="px-4 text-sm text-muted-foreground lg:px-6"> Changes an administrator makes in Keycloak may not show here. You can still delete any client from this page. </p> ); } Loading
portal-gui/src/app/config/navigation.ts +9 −0 Changes for portal-gui/src/app/config/navigation.ts: 9 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ import { Rocket, UserIcon, Handshake, KeyRoundIcon, } from 'lucide-react'; import { ROUTES } from './route'; Loading @@ -30,6 +31,14 @@ export const mainNavItems: NavItem[] = [ showInSidebar: true, }, { title: 'API clients', to: ROUTES.API_CLIENTS, description: 'Credentials for calling the APIs from your own systems.', icon: KeyRoundIcon, showInSidebar: true, roles: ['app-provider'], }, { title: 'Applications', to: ROUTES.APPLICATIONS, Loading
portal-gui/src/app/config/route.ts +1 −0 Changes for portal-gui/src/app/config/route.ts: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ export const ROUTES = { PROFILE: '/profile', APIS: '/apis', API_CLIENTS: '/api-clients', API: '/apis/:id', APPLICATIONS: '/applications', APPLICATION_PROFILES: '/applications/profiles', Loading
portal-gui/src/app/router.tsx +9 −0 Changes for portal-gui/src/app/router.tsx: 9 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ import { RoleGuard } from './guards/role-guard'; import HomePage from '@/pages/home/index'; import ProfilePage from '@/pages/profile'; import LoginPage from '@/pages/auth/login'; import ApiClientsPage from '@/pages/api-clients'; import ApisPage from '@/pages/apis/'; import ApiDetailsPage from '@/pages/apis/api-details'; import ApplicationsPage from '@/pages/applications/index'; Loading Loading @@ -60,6 +61,14 @@ export const router = createBrowserRouter([ path: ROUTES.APIS, element: <ApisPage />, }, { path: ROUTES.API_CLIENTS, element: ( <RoleGuard allowedRoles={['app-provider']}> <ApiClientsPage /> </RoleGuard> ), }, // API details MUST match /apis/:id { Loading
portal-gui/src/components/api-clients/api-client-columns.tsx 0 → 100644 +70 −0 Changes for portal-gui/src/components/api-clients/api-client-columns.tsx: 70 added lines, 0 removed lines. Original line number Diff line number Diff line import type { ColumnDef } from '@tanstack/react-table'; import { Badge } from '@/components/ui/badge'; import type { ApiClient } from '@/types/api-clients'; export const apiClientColumns: ColumnDef<ApiClient>[] = [ { id: 'drag', header: () => null, enableHiding: false, size: 40, }, { id: 'name', accessorKey: 'name', header: 'Name', cell: ({ row }) => { const client = row.original; return ( <> <span className="block max-w-64 truncate font-medium" title={client.name} > {client.name} </span> {client.description && ( <p className="mt-1 max-w-64 truncate text-xs text-muted-foreground"> {client.description} </p> )} </> ); }, size: 220, }, { id: 'client_id', accessorKey: 'client_id', header: 'Client ID', cell: ({ row }) => ( <span className="font-mono text-xs">{row.original.client_id}</span> ), size: 140, }, { id: 'products', header: 'Products', cell: ({ row }) => ( <div className="flex flex-wrap gap-1"> {row.original.products.map((product) => ( <Badge key={product} variant="secondary"> {product} </Badge> ))} </div> ), size: 280, }, { id: 'created', accessorKey: 'created_at', header: 'Created', cell: ({ row }) => row.original.created_at ? new Date(row.original.created_at).toLocaleDateString() : '—', size: 120, }, ];
portal-gui/src/components/api-clients/api-clients-notices.tsx 0 → 100644 +24 −0 Changes for portal-gui/src/components/api-clients/api-clients-notices.tsx: 24 added lines, 0 removed lines. Original line number Diff line number Diff line import { InfoIcon } from 'lucide-react'; // R2 has no automatic clean-up, so these say what the portal does not do. export function ApiClientsNotice() { return ( <div className="mx-4 flex gap-3 rounded-md border bg-muted/40 p-3 text-sm lg:mx-6"> <InfoIcon className="mt-0.5 size-4 shrink-0 text-muted-foreground" /> <p> API clients keep working until they are deleted. If you leave your organization, lose access to a product or no longer need an app, delete its API client, or ask an administrator to. </p> </div> ); } export function ApiClientsFootnote() { return ( <p className="px-4 text-sm text-muted-foreground lg:px-6"> Changes an administrator makes in Keycloak may not show here. You can still delete any client from this page. </p> ); }