@burdenoff/microfe-devportal 2026.720.5 → 2026.720.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/devportal/hooks/usePackageUpload.d.ts.map +1 -1
  2. package/dist/devportal/hooks/usePackageUpload.js.map +1 -1
  3. package/dist/devportal/pages/CreateApiKeyPage.d.ts.map +1 -1
  4. package/dist/devportal/pages/CreateApiKeyPage.js +103 -104
  5. package/dist/devportal/pages/CreateApiKeyPage.js.map +1 -1
  6. package/dist/devportal/pages/CreateApplicationPage.d.ts.map +1 -1
  7. package/dist/devportal/pages/CreateApplicationPage.js +115 -116
  8. package/dist/devportal/pages/CreateApplicationPage.js.map +1 -1
  9. package/dist/devportal/pages/CreateOAuthClientPage.d.ts.map +1 -1
  10. package/dist/devportal/pages/CreateOAuthClientPage.js +129 -130
  11. package/dist/devportal/pages/CreateOAuthClientPage.js.map +1 -1
  12. package/dist/devportal/pages/CreateWebhookPage.js +1 -1
  13. package/dist/devportal/pages/CreateWebhookPage.js.map +1 -1
  14. package/dist/devportal/pages/DelegationsPage.js +214 -214
  15. package/dist/devportal/pages/DelegationsPage.js.map +1 -1
  16. package/dist/devportal/pages/EditApplicationPage.d.ts.map +1 -1
  17. package/dist/devportal/pages/EditApplicationPage.js +1 -1
  18. package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
  19. package/dist/devportal/pages/PublishPage.d.ts.map +1 -1
  20. package/dist/devportal/pages/PublishPage.js +106 -106
  21. package/dist/devportal/pages/PublishPage.js.map +1 -1
  22. package/dist/devportal/pages/SellerDashboardPage.d.ts.map +1 -1
  23. package/dist/devportal/pages/SellerDashboardPage.js +136 -137
  24. package/dist/devportal/pages/SellerDashboardPage.js.map +1 -1
  25. package/dist/devportal/pages/SellerItemsPage.d.ts.map +1 -1
  26. package/dist/devportal/pages/SellerItemsPage.js +190 -191
  27. package/dist/devportal/pages/SellerItemsPage.js.map +1 -1
  28. package/dist/devportal/pages/SellerOrdersPage.d.ts.map +1 -1
  29. package/dist/devportal/pages/SellerOrdersPage.js +138 -139
  30. package/dist/devportal/pages/SellerOrdersPage.js.map +1 -1
  31. package/dist/devportal/types/index.d.ts.map +1 -1
  32. package/dist/devportal/types/index.js.map +1 -1
  33. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"DelegationsPage.js","names":[],"sources":["../../../src/devportal/pages/DelegationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState, useCallback, useEffect, useMemo } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Shield,\n Users,\n Clock,\n XCircle,\n AlertTriangle,\n Loader2,\n AlertCircle,\n Bot,\n Zap,\n Cog,\n} from \"lucide-react\";\nimport { EmphasisPanel, GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { LoadingState } from \"../components/LoadingState\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { SelectionCheckbox } from \"../components/SelectionCheckbox\";\nimport { cn } from \"../utils/cn\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalPermission } from \"../hooks/usePermission\";\nimport type { AppUserDelegation, DelegationStatus } from \"../types\";\nimport {\n useCurrentUserDelegationsQuery,\n useCurrentUserGrantedDelegationsQuery,\n useRevokeDelegationMutation,\n} from \"../../generated/global-operations\";\n\n// =============================================================================\n// HELPERS\n// =============================================================================\n\ntype ActiveTab = \"acting-as-me\" | \"granted-by-me\";\n\n/**\n * Map a GraphQL delegation fragment to the local AppUserDelegation type\n */\nfunction mapDelegation(d: {\n id: string;\n appId: string;\n userId: string;\n scopes: string[];\n workspaceIds?: string[] | null;\n status: string;\n grantedAt: string;\n grantedBy: string;\n expiresAt?: string | null;\n revokedAt?: string | null;\n revokedBy?: string | null;\n app: {\n id: string;\n name: string;\n description?: string | null;\n type: string;\n status: string;\n };\n}): AppUserDelegation {\n return {\n id: d.id,\n appId: d.appId,\n userId: d.userId,\n scopes: d.scopes,\n workspaceIds: d.workspaceIds ?? [],\n status: d.status as DelegationStatus,\n grantedAt: d.grantedAt,\n grantedBy: d.grantedBy,\n expiresAt: d.expiresAt ?? undefined,\n revokedAt: d.revokedAt ?? undefined,\n revokedBy: d.revokedBy ?? undefined,\n app: {\n id: d.app.id,\n name: d.app.name,\n description: d.app.description ?? undefined,\n type: d.app.type,\n status: d.app.status,\n },\n };\n}\n\n/**\n * Format a date string to relative time (\"2 hours ago\", \"3 days ago\", etc.)\n */\nfunction formatRelativeTime(dateString: string): string {\n const date = new Date(dateString);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffSeconds = Math.floor(diffMs / 1000);\n const diffMinutes = Math.floor(diffSeconds / 60);\n const diffHours = Math.floor(diffMinutes / 60);\n const diffDays = Math.floor(diffHours / 24);\n const diffWeeks = Math.floor(diffDays / 7);\n const diffMonths = Math.floor(diffDays / 30);\n\n if (diffSeconds < 60) return \"just now\";\n if (diffMinutes < 60)\n return `${diffMinutes} minute${diffMinutes !== 1 ? \"s\" : \"\"} ago`;\n if (diffHours < 24)\n return `${diffHours} hour${diffHours !== 1 ? \"s\" : \"\"} ago`;\n if (diffDays < 7) return `${diffDays} day${diffDays !== 1 ? \"s\" : \"\"} ago`;\n if (diffWeeks < 5)\n return `${diffWeeks} week${diffWeeks !== 1 ? \"s\" : \"\"} ago`;\n if (diffMonths < 12)\n return `${diffMonths} month${diffMonths !== 1 ? \"s\" : \"\"} ago`;\n\n return date.toLocaleDateString();\n}\n\n/**\n * Format a future date as relative time (\"in 3 days\", \"in 2 hours\", etc.)\n */\nfunction formatExpirationTime(dateString: string): string {\n const date = new Date(dateString);\n const now = new Date();\n const diffMs = date.getTime() - now.getTime();\n\n if (diffMs <= 0) return \"expired\";\n\n const diffMinutes = Math.floor(diffMs / (1000 * 60));\n const diffHours = Math.floor(diffMs / (1000 * 60 * 60));\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffMinutes < 60)\n return `in ${diffMinutes} minute${diffMinutes !== 1 ? \"s\" : \"\"}`;\n if (diffHours < 24)\n return `in ${diffHours} hour${diffHours !== 1 ? \"s\" : \"\"}`;\n return `in ${diffDays} day${diffDays !== 1 ? \"s\" : \"\"}`;\n}\n\n// =============================================================================\n// SUB-COMPONENTS\n// =============================================================================\n\n/**\n * Icon for app type (SERVICE, BOT, INTEGRATION, etc.)\n */\nconst AppTypeIcon: FC<{ type: string; className?: string }> = ({\n type,\n className,\n}) => {\n const iconProps = { className: cn(\"h-5 w-5\", className) };\n\n switch (type) {\n case \"SERVICE\":\n return <Cog {...iconProps} />;\n case \"BOT\":\n return <Bot {...iconProps} />;\n case \"INTEGRATION\":\n return <Zap {...iconProps} />;\n default:\n return <Shield {...iconProps} />;\n }\n};\n\n/**\n * Delegation status badge with color coding\n */\nconst DelegationStatusBadge: FC<{ status: DelegationStatus }> = ({\n status,\n}) => {\n const styles: Record<DelegationStatus, string> = {\n ACTIVE: \"bg-status-success-bg-subtle text-status-success-text\",\n REVOKED: \"bg-status-error-bg-subtle text-status-error-text\",\n EXPIRED: \"bg-bg-sunken text-text-primary\",\n };\n\n return (\n <span\n className={cn(\n \"inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium\",\n styles[status],\n )}\n >\n {status}\n </span>\n );\n};\n\n/**\n * Success toast that auto-dismisses\n */\nconst SuccessToast: FC<{ message: string; onDismiss: () => void }> = ({\n message,\n onDismiss,\n}) => {\n useEffect(() => {\n const timer = setTimeout(onDismiss, 5000);\n return () => clearTimeout(timer);\n }, [onDismiss]);\n\n return (\n <div className=\"rounded-lg border border-border-subtle bg-status-success-bg-subtle p-4\">\n <div className=\"flex items-center gap-3\">\n <Shield className=\"h-5 w-5 text-status-success-text\" />\n <p className=\"text-sm font-medium text-status-success-text\">\n {message}\n </p>\n </div>\n </div>\n );\n};\n\n/**\n * Error banner\n */\nconst ErrorBanner: FC<{ message: string; onRetry?: () => void }> = ({\n message,\n onRetry,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n return (\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-4\">\n <div className=\"flex items-center gap-3\">\n <AlertCircle className=\"h-5 w-5 text-status-error-text\" />\n <p className=\"flex-1 text-sm text-status-error-text\">{message}</p>\n {onRetry && (\n <button\n onClick={onRetry}\n className=\"rounded-md border px-3 py-1.5 text-xs font-medium hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"devportal.retry\", \"Retry\")}\n </button>\n )}\n </div>\n </div>\n );\n};\n\n/**\n * Single delegation card for \"Apps Acting as Me\" tab\n */\nconst DelegationCard: FC<{\n delegation: AppUserDelegation;\n onRevoke: (delegation: AppUserDelegation) => void;\n isRevoking: boolean;\n selected: boolean;\n onToggleSelect: (checked: boolean) => void;\n canRevoke: boolean;\n}> = ({\n delegation,\n onRevoke,\n isRevoking,\n selected,\n onToggleSelect,\n canRevoke,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n return (\n <div\n className={cn(\n \"rounded-card border border-border-seam bg-bg-surface p-5 transition-colors hover:border-border-subtle/80\",\n selected && \"border-primary bg-action-primary-bg/5\",\n delegation.status !== \"ACTIVE\" && \"opacity-60\",\n )}\n >\n <div className=\"flex items-start justify-between gap-4\">\n {/* Left: App info */}\n <div className=\"flex items-start gap-4 min-w-0\">\n {delegation.status === \"ACTIVE\" && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selected}\n onChange={onToggleSelect}\n ariaLabel={tr(\n \"devportal.selectDelegationAriaLabel\",\n `Select delegation ${delegation.app?.name ?? delegation.id}`,\n )}\n className=\"mt-1\"\n />\n </div>\n )}\n <div\n className={cn(\n \"flex h-12 w-12 shrink-0 items-center justify-center rounded-lg\",\n delegation.status === \"ACTIVE\"\n ? \"bg-action-primary-bg/10 text-primary\"\n : \"bg-bg-sunken text-text-secondary\",\n )}\n >\n <AppTypeIcon\n type={delegation.app?.type ?? \"SERVICE\"}\n className=\"h-6 w-6\"\n />\n </div>\n\n <div className=\"min-w-0 space-y-2\">\n {/* Name + status */}\n <div className=\"flex items-center gap-2\">\n <h3 className=\"truncate font-semibold\">\n {delegation.app?.name ??\n tr(\"devportal.unknownApp\", \"Unknown App\")}\n </h3>\n <DelegationStatusBadge status={delegation.status} />\n </div>\n\n {/* Description */}\n {delegation.app?.description && (\n <p className=\"text-sm text-text-secondary line-clamp-2\">\n {delegation.app.description}\n </p>\n )}\n\n {/* Metadata row */}\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 text-sm text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" />\n {tr(\"devportal.granted\", \"Granted\")}{\" \"}\n {formatRelativeTime(delegation.grantedAt)}\n </span>\n {delegation.expiresAt && (\n <span className=\"flex items-center gap-1\">\n <AlertTriangle className=\"h-3.5 w-3.5\" />\n {tr(\"devportal.expires\", \"Expires\")}{\" \"}\n {formatExpirationTime(delegation.expiresAt)}\n </span>\n )}\n <span\n className={cn(\n \"rounded-md px-2 py-0.5 text-xs font-mono\",\n \"bg-bg-sunken text-text-secondary\",\n )}\n >\n {delegation.app?.type ?? \"UNKNOWN\"}\n </span>\n </div>\n\n {/* Scopes */}\n {delegation.scopes.length > 0 && (\n <div>\n <p className=\"mb-1.5 text-xs text-text-secondary\">\n {tr(\"devportal.permissions\", \"Permissions:\")}\n </p>\n <div className=\"flex flex-wrap gap-1.5\">\n {delegation.scopes.map((scope) => (\n <span\n key={scope}\n className=\"rounded-md bg-status-info-bg-subtle px-2 py-0.5 text-xs text-status-info-text\"\n >\n {scope}\n </span>\n ))}\n </div>\n </div>\n )}\n\n {/* Workspace count */}\n {delegation.workspaceIds.length > 0 && (\n <p className=\"flex items-center gap-1 text-xs text-text-secondary\">\n <Users className=\"h-3.5 w-3.5\" />\n {tr(\"devportal.accessToWorkspaces\", \"Access to\")}{\" \"}\n {delegation.workspaceIds.length}{\" \"}\n {tr(\"devportal.workspace\", \"workspace\")}\n {delegation.workspaceIds.length !== 1\n ? tr(\"devportal.workspacePluralSuffix\", \"s\")\n : \"\"}\n </p>\n )}\n </div>\n </div>\n\n {/* Right: Revoke button (only for active delegations) */}\n {delegation.status === \"ACTIVE\" && (\n <button\n onClick={() => onRevoke(delegation)}\n disabled={isRevoking || !canRevoke}\n aria-disabled={!canRevoke}\n className=\"inline-flex shrink-0 items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {isRevoking ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <XCircle className=\"h-4 w-4\" />\n )}\n {tr(\"devportal.revoke\", \"Revoke\")}\n </button>\n )}\n </div>\n </div>\n );\n};\n\n/**\n * Single delegation card for \"Delegations I Granted\" tab\n */\nconst GrantedDelegationCard: FC<{\n delegation: AppUserDelegation;\n onRevoke: (delegation: AppUserDelegation) => void;\n isRevoking: boolean;\n selected: boolean;\n onToggleSelect: (checked: boolean) => void;\n canRevoke: boolean;\n}> = ({\n delegation,\n onRevoke,\n isRevoking,\n selected,\n onToggleSelect,\n canRevoke,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n return (\n <div\n className={cn(\n \"rounded-card border border-border-seam bg-bg-surface p-5 transition-colors hover:border-border-subtle/80\",\n selected && \"border-primary bg-action-primary-bg/5\",\n )}\n >\n <div className=\"flex items-start justify-between gap-4\">\n {/* Left: App info */}\n <div className=\"flex items-start gap-4 min-w-0\">\n {delegation.status === \"ACTIVE\" && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selected}\n onChange={onToggleSelect}\n ariaLabel={tr(\n \"devportal.selectDelegationAriaLabel\",\n `Select delegation ${delegation.app?.name ?? delegation.id}`,\n )}\n className=\"mt-1\"\n />\n </div>\n )}\n <div className=\"flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-accent-purple-subtle text-accent-purple\">\n <AppTypeIcon\n type={delegation.app?.type ?? \"SERVICE\"}\n className=\"h-6 w-6\"\n />\n </div>\n\n <div className=\"min-w-0 space-y-2\">\n {/* Name + status */}\n <div className=\"flex items-center gap-2\">\n <h3 className=\"truncate font-semibold\">\n {delegation.app?.name ??\n tr(\"devportal.unknownApp\", \"Unknown App\")}\n </h3>\n <DelegationStatusBadge status={delegation.status} />\n </div>\n\n {/* Target user */}\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.grantedToUser\", \"Granted to user:\")}{\" \"}\n <code className=\"rounded bg-bg-sunken px-1.5 py-0.5 text-xs\">\n {delegation.userId}\n </code>\n </p>\n\n {/* Time */}\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 text-sm text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" />\n {tr(\"devportal.granted\", \"Granted\")}{\" \"}\n {formatRelativeTime(delegation.grantedAt)}\n </span>\n {delegation.expiresAt && (\n <span className=\"flex items-center gap-1\">\n <AlertTriangle className=\"h-3.5 w-3.5\" />\n {tr(\"devportal.expires\", \"Expires\")}{\" \"}\n {new Date(delegation.expiresAt).toLocaleDateString()}\n </span>\n )}\n </div>\n\n {/* Scopes */}\n {delegation.scopes.length > 0 && (\n <div>\n <p className=\"mb-1.5 text-xs text-text-secondary\">\n {tr(\"devportal.permissionsGranted\", \"Permissions granted:\")}\n </p>\n <div className=\"flex flex-wrap gap-1.5\">\n {delegation.scopes.map((scope) => (\n <span\n key={scope}\n className=\"rounded-md bg-accent-purple-subtle px-2 py-0.5 text-xs text-accent-purple\"\n >\n {scope}\n </span>\n ))}\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Right: Revoke button */}\n {delegation.status === \"ACTIVE\" && (\n <button\n onClick={() => onRevoke(delegation)}\n disabled={isRevoking || !canRevoke}\n aria-disabled={!canRevoke}\n className=\"inline-flex shrink-0 items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {isRevoking ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <XCircle className=\"h-4 w-4\" />\n )}\n {tr(\"devportal.revoke\", \"Revoke\")}\n </button>\n )}\n </div>\n </div>\n );\n};\n\n/**\n * Revocation history section (dimmed, for revoked/expired delegations)\n */\nconst RevocationHistory: FC<{ delegations: AppUserDelegation[] }> = ({\n delegations,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n if (delegations.length === 0) return null;\n\n return (\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-semibold\">\n {tr(\"devportal.revocationHistory\", \"Revocation History\")}\n </h2>\n <div className=\"space-y-3 opacity-60\">\n {delegations.map((delegation) => (\n <div\n key={delegation.id}\n className=\"flex items-center justify-between rounded-lg border bg-bg-sunken/30 p-4\"\n >\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-lg bg-bg-sunken text-text-secondary\">\n <AppTypeIcon\n type={delegation.app?.type ?? \"SERVICE\"}\n className=\"h-5 w-5\"\n />\n </div>\n <div>\n <h3 className=\"font-medium\">\n {delegation.app?.name ??\n tr(\"devportal.unknownApp\", \"Unknown App\")}\n </h3>\n <p className=\"text-sm text-text-secondary\">\n {delegation.status === \"REVOKED\"\n ? tr(\"devportal.revoked\", \"Revoked\")\n : tr(\"devportal.expired\", \"Expired\")}{\" \"}\n {delegation.revokedAt\n ? formatRelativeTime(delegation.revokedAt)\n : \"\"}\n </p>\n </div>\n </div>\n <DelegationStatusBadge status={delegation.status} />\n </div>\n ))}\n </div>\n </div>\n );\n};\n\n// =============================================================================\n// MAIN COMPONENT\n// =============================================================================\n\n/**\n * Delegations management page for the Developer Portal.\n *\n * Consolidates delegation management previously at /auth/delegations in\n * microfe-auth. Shows two tabs:\n * - \"Apps Acting as Me\": delegations where the current user is the subject\n * - \"Delegations I Granted\": delegations the current user granted to others\n */\nexport const DelegationsPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const { allowed: canRevoke } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.DELEGATION_REVOKE,\n );\n // ---------------------------------------------------------------------------\n // State\n // ---------------------------------------------------------------------------\n const [activeTab, setActiveTab] = useState<ActiveTab>(\"acting-as-me\");\n const [revokeTargets, setRevokeTargets] = useState<AppUserDelegation[]>([]);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n const [selectedDelegationIds, setSelectedDelegationIds] = useState<\n Set<string>\n >(new Set());\n\n // ---------------------------------------------------------------------------\n // Queries\n // ---------------------------------------------------------------------------\n const {\n data: delegationsData,\n loading: delegationsLoading,\n error: delegationsError,\n refetch: refetchDelegations,\n } = useCurrentUserDelegationsQuery({\n fetchPolicy: \"cache-and-network\",\n });\n\n const {\n data: grantedData,\n loading: grantedLoading,\n error: grantedError,\n refetch: refetchGranted,\n } = useCurrentUserGrantedDelegationsQuery({\n fetchPolicy: \"cache-and-network\",\n });\n\n // ---------------------------------------------------------------------------\n // Mutation\n // ---------------------------------------------------------------------------\n const [revokeDelegationMutation, { loading: revokeLoading }] =\n useRevokeDelegationMutation();\n\n // ---------------------------------------------------------------------------\n // Derived data\n // ---------------------------------------------------------------------------\n const delegations: AppUserDelegation[] = (\n delegationsData?.currentUserDelegations?.delegations ?? []\n ).map(mapDelegation);\n\n const grantedDelegations: AppUserDelegation[] = (\n grantedData?.currentUserGrantedDelegations?.delegations ?? []\n ).map(mapDelegation);\n\n const activeDelegations = delegations.filter((d) => d.status === \"ACTIVE\");\n const inactiveDelegations = delegations.filter((d) => d.status !== \"ACTIVE\");\n const activeGrantedDelegations = grantedDelegations.filter(\n (d) => d.status === \"ACTIVE\",\n );\n const visibleActiveDelegations =\n activeTab === \"acting-as-me\" ? activeDelegations : activeGrantedDelegations;\n const selectedActiveDelegations = useMemo(\n () =>\n visibleActiveDelegations.filter((delegation) =>\n selectedDelegationIds.has(delegation.id),\n ),\n [selectedDelegationIds, visibleActiveDelegations],\n );\n const allVisibleSelected =\n visibleActiveDelegations.length > 0 &&\n visibleActiveDelegations.every((delegation) =>\n selectedDelegationIds.has(delegation.id),\n );\n const partiallySelected =\n visibleActiveDelegations.some((delegation) =>\n selectedDelegationIds.has(delegation.id),\n ) && !allVisibleSelected;\n\n const isLoading =\n activeTab === \"acting-as-me\" ? delegationsLoading : grantedLoading;\n const queryError =\n activeTab === \"acting-as-me\" ? delegationsError : grantedError;\n\n // ---------------------------------------------------------------------------\n // Handlers\n // ---------------------------------------------------------------------------\n const handleRevokeClick = useCallback((delegation: AppUserDelegation) => {\n setRevokeTargets([delegation]);\n }, []);\n\n const toggleDelegationSelection = useCallback(\n (delegationId: string, checked: boolean) => {\n setSelectedDelegationIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(delegationId);\n } else {\n next.delete(delegationId);\n }\n return next;\n });\n },\n [],\n );\n\n const toggleAllVisibleDelegations = useCallback(\n (checked: boolean) => {\n setSelectedDelegationIds((prev) => {\n const next = new Set(prev);\n visibleActiveDelegations.forEach((delegation) => {\n if (checked) {\n next.add(delegation.id);\n } else {\n next.delete(delegation.id);\n }\n });\n return next;\n });\n },\n [visibleActiveDelegations],\n );\n\n const clearSelection = useCallback(() => {\n setSelectedDelegationIds(new Set());\n }, []);\n\n const handleBulkRevokeClick = useCallback(() => {\n if (selectedActiveDelegations.length === 0) return;\n setRevokeTargets(selectedActiveDelegations);\n }, [selectedActiveDelegations]);\n\n const handleRevokeConfirm = useCallback(async () => {\n if (revokeTargets.length === 0) return;\n try {\n const results = await Promise.allSettled(\n revokeTargets.map((delegation) =>\n revokeDelegationMutation({\n variables: {\n id: delegation.id,\n reason: tr(\n \"devportal.userRevokedAccessReason\",\n \"User revoked access via Developer Portal\",\n ),\n },\n }),\n ),\n );\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) =>\n result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setSuccessMessage(\n `Revoked ${succeeded} delegation${succeeded === 1 ? \"\" : \"s\"}${failed > 0 ? ` • ${failed} failed` : \"\"}`,\n );\n setSelectedDelegationIds((prev) => {\n const next = new Set(prev);\n revokeTargets.forEach((delegation) => next.delete(delegation.id));\n return next;\n });\n setRevokeTargets([]);\n // Refetch both queries to keep data fresh\n void refetchDelegations();\n void refetchGranted();\n } catch {\n // Error is available via the mutation hook's error state;\n // the ConfirmDialog will close and we show the error via queryError fallback\n setRevokeTargets([]);\n }\n }, [\n revokeTargets,\n revokeDelegationMutation,\n refetchDelegations,\n refetchGranted,\n ]);\n\n const handleDismissSuccess = useCallback(() => {\n setSuccessMessage(null);\n }, []);\n\n // ---------------------------------------------------------------------------\n // Summary stats for header\n // ---------------------------------------------------------------------------\n const totalActive = activeDelegations.length;\n const totalGranted = activeGrantedDelegations.length;\n\n // ---------------------------------------------------------------------------\n // Render\n // ---------------------------------------------------------------------------\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.INSTALLATION_READ}>\n <PageLayout\n title={tr(\"devportal.appDelegationsTitle\", \"App Delegations\")}\n description={tr(\n \"devportal.appDelegationsDescription\",\n \"Manage which apps can act on your behalf. Revoke access at any time.\",\n )}\n purpose={tr(\n \"devportal.appDelegationsPurpose\",\n \"Delegations are the consent grants that let an app perform actions as you within a limited scope and time window. Review what you have authorized here, see what each app can do, and revoke anything you no longer trust.\",\n )}\n >\n {/* Success message */}\n {successMessage && (\n <SuccessToast\n message={successMessage}\n onDismiss={handleDismissSuccess}\n />\n )}\n\n {/* Error message */}\n {queryError && (\n <ErrorBanner\n message={\n queryError.message ||\n tr(\n \"devportal.failedToLoadDelegations\",\n \"Failed to load delegations\",\n )\n }\n onRetry={() => {\n void refetchDelegations();\n void refetchGranted();\n }}\n />\n )}\n\n {/* Summary stats — primary emphasis zone */}\n <EmphasisPanel>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-4\">\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-2 text-text-secondary\">\n <Shield className=\"h-4 w-4\" />\n <span className=\"text-sm\">\n {tr(\"devportal.activeDelegations\", \"Active Delegations\")}\n </span>\n </div>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {totalActive}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-2 text-text-secondary\">\n <Users className=\"h-4 w-4\" />\n <span className=\"text-sm\">\n {tr(\"devportal.grantedByMe\", \"Granted by Me\")}\n </span>\n </div>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {totalGranted}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-2 text-status-warning-text\">\n <AlertTriangle className=\"h-4 w-4\" />\n <span className=\"text-sm\">\n {tr(\"devportal.revokedExpired\", \"Revoked / Expired\")}\n </span>\n </div>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {inactiveDelegations.length}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-2 text-text-secondary\">\n <Clock className=\"h-4 w-4\" />\n <span className=\"text-sm\">\n {tr(\"devportal.totalAllTime\", \"Total All-Time\")}\n </span>\n </div>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {delegations.length}\n </p>\n </GlassCard>\n </div>\n </EmphasisPanel>\n\n {/* Tabs */}\n <div className=\"border-b\">\n <div\n className=\"flex overflow-x-auto\"\n role=\"tablist\"\n aria-label={tr(\n \"devportal.delegationSections\",\n \"Delegation sections\",\n )}\n >\n <button\n id=\"delegations-tab-acting-as-me\"\n role=\"tab\"\n aria-selected={activeTab === \"acting-as-me\"}\n onClick={() => {\n clearSelection();\n setActiveTab(\"acting-as-me\");\n }}\n className={cn(\n \"-mb-px border-b-2 px-4 py-3 text-sm font-medium transition-colors\",\n activeTab === \"acting-as-me\"\n ? \"border-primary text-primary\"\n : \"border-transparent text-text-secondary hover:text-text-primary\",\n )}\n >\n {tr(\"devportal.appsActingAsMe\", \"Apps Acting as Me\")}\n {totalActive > 0 && (\n <span className=\"ml-2 inline-flex items-center justify-center rounded-full bg-action-primary-bg/10 px-2 py-0.5 text-xs font-medium text-primary\">\n {totalActive}\n </span>\n )}\n </button>\n <button\n id=\"delegations-tab-granted-by-me\"\n role=\"tab\"\n aria-selected={activeTab === \"granted-by-me\"}\n onClick={() => {\n clearSelection();\n setActiveTab(\"granted-by-me\");\n }}\n className={cn(\n \"-mb-px border-b-2 px-4 py-3 text-sm font-medium transition-colors\",\n activeTab === \"granted-by-me\"\n ? \"border-primary text-primary\"\n : \"border-transparent text-text-secondary hover:text-text-primary\",\n )}\n >\n {tr(\"devportal.delegationsIGranted\", \"Delegations I Granted\")}\n {totalGranted > 0 && (\n <span className=\"ml-2 inline-flex items-center justify-center rounded-full bg-action-primary-bg/10 px-2 py-0.5 text-xs font-medium text-primary\">\n {totalGranted}\n </span>\n )}\n </button>\n </div>\n </div>\n\n {visibleActiveDelegations.length > 0 && (\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisibleDelegations}\n ariaLabel={tr(\n \"devportal.selectAllVisibleDelegations\",\n \"Select all visible delegations\",\n )}\n />\n <span className=\"text-sm font-medium\">\n {tr(\"devportal.selectAllVisible\", \"Select all visible\")}\n </span>\n </div>\n {selectedDelegationIds.size > 0 && (\n <button\n onClick={clearSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n {tr(\"devportal.clearSelection\", \"Clear selection\")}\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedDelegationIds.size}{\" \"}\n {tr(\"devportal.selected\", \"selected\")}\n </span>\n </div>\n <p className=\"mt-1 text-2xl font-semibold\">{totalActive}</p>\n </div>\n </div>\n )}\n\n {/* Loading */}\n {isLoading && !delegationsData && !grantedData && (\n <LoadingState\n message={tr(\n \"devportal.loadingDelegations\",\n \"Loading delegations...\",\n )}\n />\n )}\n\n {/* ------------------------------------------------------------------- */}\n {/* Tab 1: Apps Acting as Me */}\n {/* ------------------------------------------------------------------- */}\n {!isLoading && activeTab === \"acting-as-me\" && (\n <div\n className=\"space-y-8\"\n id=\"delegations-panel-acting-as-me\"\n role=\"tabpanel\"\n aria-labelledby=\"delegations-tab-acting-as-me\"\n tabIndex={0}\n >\n {activeDelegations.length === 0 &&\n inactiveDelegations.length === 0 ? (\n <EmptyState\n illustration=\"empty-people\"\n title={tr(\n \"devportal.noActiveDelegations\",\n \"No Active Delegations\",\n )}\n description={tr(\n \"devportal.noAppsAuthorizedOnYourBehalf\",\n \"No apps are currently authorized to act on your behalf.\",\n )}\n />\n ) : (\n <>\n {/* Active delegation cards */}\n {activeDelegations.length === 0 ? (\n <EmptyState\n illustration=\"empty-people\"\n icon={<Shield size={32} />}\n title={tr(\n \"devportal.noActiveDelegations\",\n \"No Active Delegations\",\n )}\n description={tr(\n \"devportal.allPreviousDelegationsRevokedOrExpired\",\n \"All previous delegations have been revoked or expired.\",\n )}\n />\n ) : (\n <div className=\"space-y-4\">\n {activeDelegations.map((delegation) => (\n <DelegationCard\n key={delegation.id}\n delegation={delegation}\n onRevoke={handleRevokeClick}\n isRevoking={\n revokeLoading &&\n revokeTargets.some(\n (item) => item.id === delegation.id,\n )\n }\n selected={selectedDelegationIds.has(delegation.id)}\n onToggleSelect={(checked) =>\n toggleDelegationSelection(delegation.id, checked)\n }\n canRevoke={canRevoke}\n />\n ))}\n </div>\n )}\n\n {/* Revocation history */}\n <RevocationHistory delegations={inactiveDelegations} />\n </>\n )}\n </div>\n )}\n\n {/* ------------------------------------------------------------------- */}\n {/* Tab 2: Delegations I Granted */}\n {/* ------------------------------------------------------------------- */}\n {!isLoading && activeTab === \"granted-by-me\" && (\n <div\n className=\"space-y-4\"\n id=\"delegations-panel-granted-by-me\"\n role=\"tabpanel\"\n aria-labelledby=\"delegations-tab-granted-by-me\"\n tabIndex={0}\n >\n {grantedDelegations.length === 0 ? (\n <EmptyState\n illustration=\"empty-people\"\n title={tr(\n \"devportal.noDelegationsGranted\",\n \"No Delegations Granted\",\n )}\n description={tr(\n \"devportal.noGrantedDelegationsDescription\",\n \"You haven't granted any app delegations to other users.\",\n )}\n />\n ) : (\n grantedDelegations.map((delegation) => (\n <GrantedDelegationCard\n key={delegation.id}\n delegation={delegation}\n onRevoke={handleRevokeClick}\n isRevoking={\n revokeLoading &&\n revokeTargets.some((item) => item.id === delegation.id)\n }\n selected={selectedDelegationIds.has(delegation.id)}\n onToggleSelect={(checked) =>\n toggleDelegationSelection(delegation.id, checked)\n }\n canRevoke={canRevoke}\n />\n ))\n )}\n </div>\n )}\n\n {/* Info card */}\n <div className=\"rounded-lg border border-border-subtle bg-status-info-bg-subtle p-5\">\n <div className=\"flex gap-4\">\n <AlertCircle className=\"h-6 w-6 shrink-0 text-accent-blue\" />\n <div>\n <h3 className=\"font-semibold text-status-info-text\">\n {tr(\"devportal.aboutAppDelegations\", \"About App Delegations\")}\n </h3>\n <p className=\"mt-1 text-sm text-status-info-text\">\n {tr(\n \"devportal.aboutAppDelegationsText\",\n \"App delegations allow automated services, bots, and integrations to perform actions on your behalf. Each delegation specifies which permissions (scopes) and workspaces the app can access. You can revoke access at any time, which immediately prevents the app from acting as you.\",\n )}\n </p>\n </div>\n </div>\n </div>\n\n {/* Revoke confirmation dialog */}\n <ConfirmDialog\n open={revokeTargets.length > 0}\n onOpenChange={(open) => {\n if (!open) setRevokeTargets([]);\n }}\n onConfirm={handleRevokeConfirm}\n title={\n revokeTargets.length > 1\n ? tr(\"devportal.revokeDelegations\", \"Revoke Delegations\")\n : tr(\"devportal.revokeDelegation\", \"Revoke Delegation\")\n }\n description={\n revokeTargets.length > 1\n ? tr(\n \"devportal.revokeDelegationsBulkConfirm\",\n `Are you sure you want to revoke ${revokeTargets.length} selected delegations? Those apps will no longer be able to act on the delegated users' behalf.`,\n )\n : tr(\n \"devportal.revokeDelegationSingleConfirm\",\n `Are you sure you want to revoke access for \"${revokeTargets[0]?.app?.name ?? \"this app\"}\"? This app will no longer be able to act on your behalf.`,\n )\n }\n confirmLabel={tr(\"devportal.revokeAccess\", \"Revoke Access\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"danger\"\n loading={revokeLoading}\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"DelegationsPage.js","names":[],"sources":["../../../src/devportal/pages/DelegationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState, useCallback, useEffect, useMemo } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Shield,\n Users,\n Clock,\n XCircle,\n AlertTriangle,\n Loader2,\n AlertCircle,\n Bot,\n Zap,\n Cog,\n} from \"lucide-react\";\nimport { EmphasisPanel, GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { LoadingState } from \"../components/LoadingState\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { SelectionCheckbox } from \"../components/SelectionCheckbox\";\nimport { cn } from \"../utils/cn\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalPermission } from \"../hooks/usePermission\";\nimport type { AppUserDelegation, DelegationStatus } from \"../types\";\nimport {\n useCurrentUserDelegationsQuery,\n useCurrentUserGrantedDelegationsQuery,\n useRevokeDelegationMutation,\n} from \"../../generated/global-operations\";\n\n// =============================================================================\n// HELPERS\n// =============================================================================\n\ntype ActiveTab = \"acting-as-me\" | \"granted-by-me\";\n\n/**\n * Map a GraphQL delegation fragment to the local AppUserDelegation type\n */\nfunction mapDelegation(d: {\n id: string;\n appId: string;\n userId: string;\n scopes: string[];\n workspaceIds?: string[] | null;\n status: string;\n grantedAt: string;\n grantedBy: string;\n expiresAt?: string | null;\n revokedAt?: string | null;\n revokedBy?: string | null;\n app: {\n id: string;\n name: string;\n description?: string | null;\n type: string;\n status: string;\n };\n}): AppUserDelegation {\n return {\n id: d.id,\n appId: d.appId,\n userId: d.userId,\n scopes: d.scopes,\n workspaceIds: d.workspaceIds ?? [],\n status: d.status as DelegationStatus,\n grantedAt: d.grantedAt,\n grantedBy: d.grantedBy,\n expiresAt: d.expiresAt ?? undefined,\n revokedAt: d.revokedAt ?? undefined,\n revokedBy: d.revokedBy ?? undefined,\n app: {\n id: d.app.id,\n name: d.app.name,\n description: d.app.description ?? undefined,\n type: d.app.type,\n status: d.app.status,\n },\n };\n}\n\n/**\n * Format a date string to relative time (\"2 hours ago\", \"3 days ago\", etc.)\n */\nfunction formatRelativeTime(dateString: string): string {\n const date = new Date(dateString);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffSeconds = Math.floor(diffMs / 1000);\n const diffMinutes = Math.floor(diffSeconds / 60);\n const diffHours = Math.floor(diffMinutes / 60);\n const diffDays = Math.floor(diffHours / 24);\n const diffWeeks = Math.floor(diffDays / 7);\n const diffMonths = Math.floor(diffDays / 30);\n\n if (diffSeconds < 60) return \"just now\";\n if (diffMinutes < 60)\n return `${diffMinutes} minute${diffMinutes !== 1 ? \"s\" : \"\"} ago`;\n if (diffHours < 24)\n return `${diffHours} hour${diffHours !== 1 ? \"s\" : \"\"} ago`;\n if (diffDays < 7) return `${diffDays} day${diffDays !== 1 ? \"s\" : \"\"} ago`;\n if (diffWeeks < 5)\n return `${diffWeeks} week${diffWeeks !== 1 ? \"s\" : \"\"} ago`;\n if (diffMonths < 12)\n return `${diffMonths} month${diffMonths !== 1 ? \"s\" : \"\"} ago`;\n\n return date.toLocaleDateString();\n}\n\n/**\n * Format a future date as relative time (\"in 3 days\", \"in 2 hours\", etc.)\n */\nfunction formatExpirationTime(dateString: string): string {\n const date = new Date(dateString);\n const now = new Date();\n const diffMs = date.getTime() - now.getTime();\n\n if (diffMs <= 0) return \"expired\";\n\n const diffMinutes = Math.floor(diffMs / (1000 * 60));\n const diffHours = Math.floor(diffMs / (1000 * 60 * 60));\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffMinutes < 60)\n return `in ${diffMinutes} minute${diffMinutes !== 1 ? \"s\" : \"\"}`;\n if (diffHours < 24)\n return `in ${diffHours} hour${diffHours !== 1 ? \"s\" : \"\"}`;\n return `in ${diffDays} day${diffDays !== 1 ? \"s\" : \"\"}`;\n}\n\n// =============================================================================\n// SUB-COMPONENTS\n// =============================================================================\n\n/**\n * Icon for app type (SERVICE, BOT, INTEGRATION, etc.)\n */\nconst AppTypeIcon: FC<{ type: string; className?: string }> = ({\n type,\n className,\n}) => {\n const iconProps = { className: cn(\"h-5 w-5\", className) };\n\n switch (type) {\n case \"SERVICE\":\n return <Cog {...iconProps} />;\n case \"BOT\":\n return <Bot {...iconProps} />;\n case \"INTEGRATION\":\n return <Zap {...iconProps} />;\n default:\n return <Shield {...iconProps} />;\n }\n};\n\n/**\n * Delegation status badge with color coding\n */\nconst DelegationStatusBadge: FC<{ status: DelegationStatus }> = ({\n status,\n}) => {\n const styles: Record<DelegationStatus, string> = {\n ACTIVE: \"bg-status-success-bg-subtle text-status-success-text\",\n REVOKED: \"bg-status-error-bg-subtle text-status-error-text\",\n EXPIRED: \"bg-bg-sunken text-text-primary\",\n };\n\n return (\n <span\n className={cn(\n \"inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium\",\n styles[status],\n )}\n >\n {status}\n </span>\n );\n};\n\n/**\n * Success toast that auto-dismisses\n */\nconst SuccessToast: FC<{ message: string; onDismiss: () => void }> = ({\n message,\n onDismiss,\n}) => {\n useEffect(() => {\n const timer = setTimeout(onDismiss, 5000);\n return () => clearTimeout(timer);\n }, [onDismiss]);\n\n return (\n <div className=\"rounded-lg border border-border-subtle bg-status-success-bg-subtle p-4\">\n <div className=\"flex items-center gap-3\">\n <Shield className=\"h-5 w-5 text-status-success-text\" />\n <p className=\"text-sm font-medium text-status-success-text\">\n {message}\n </p>\n </div>\n </div>\n );\n};\n\n/**\n * Error banner\n */\nconst ErrorBanner: FC<{ message: string; onRetry?: () => void }> = ({\n message,\n onRetry,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n return (\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-4\">\n <div className=\"flex items-center gap-3\">\n <AlertCircle className=\"h-5 w-5 text-status-error-text\" />\n <p className=\"flex-1 text-sm text-status-error-text\">{message}</p>\n {onRetry && (\n <button\n onClick={onRetry}\n className=\"rounded-md border px-3 py-1.5 text-xs font-medium hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"devportal.retry\", \"Retry\")}\n </button>\n )}\n </div>\n </div>\n );\n};\n\n/**\n * Single delegation card for \"Apps Acting as Me\" tab\n */\nconst DelegationCard: FC<{\n delegation: AppUserDelegation;\n onRevoke: (delegation: AppUserDelegation) => void;\n isRevoking: boolean;\n selected: boolean;\n onToggleSelect: (checked: boolean) => void;\n canRevoke: boolean;\n}> = ({\n delegation,\n onRevoke,\n isRevoking,\n selected,\n onToggleSelect,\n canRevoke,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n return (\n <div\n className={cn(\n \"rounded-card border border-border-seam bg-bg-surface p-5 transition-colors hover:border-border-subtle/80\",\n selected && \"border-primary bg-action-primary-bg/5\",\n delegation.status !== \"ACTIVE\" && \"opacity-60\",\n )}\n >\n <div className=\"flex items-start justify-between gap-4\">\n {/* Left: App info */}\n <div className=\"flex items-start gap-4 min-w-0\">\n {delegation.status === \"ACTIVE\" && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selected}\n onChange={onToggleSelect}\n ariaLabel={tr(\n \"devportal.selectDelegationAriaLabel\",\n `Select delegation ${delegation.app?.name ?? delegation.id}`,\n )}\n className=\"mt-1\"\n />\n </div>\n )}\n <div\n className={cn(\n \"flex h-12 w-12 shrink-0 items-center justify-center rounded-lg\",\n delegation.status === \"ACTIVE\"\n ? \"bg-action-primary-bg/10 text-primary\"\n : \"bg-bg-sunken text-text-secondary\",\n )}\n >\n <AppTypeIcon\n type={delegation.app?.type ?? \"SERVICE\"}\n className=\"h-6 w-6\"\n />\n </div>\n\n <div className=\"min-w-0 space-y-2\">\n {/* Name + status */}\n <div className=\"flex items-center gap-2\">\n <h3 className=\"truncate font-semibold\">\n {delegation.app?.name ??\n tr(\"devportal.unknownApp\", \"Unknown App\")}\n </h3>\n <DelegationStatusBadge status={delegation.status} />\n </div>\n\n {/* Description */}\n {delegation.app?.description && (\n <p className=\"text-sm text-text-secondary line-clamp-2\">\n {delegation.app.description}\n </p>\n )}\n\n {/* Metadata row */}\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 text-sm text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" />\n {tr(\"devportal.granted\", \"Granted\")}{\" \"}\n {formatRelativeTime(delegation.grantedAt)}\n </span>\n {delegation.expiresAt && (\n <span className=\"flex items-center gap-1\">\n <AlertTriangle className=\"h-3.5 w-3.5\" />\n {tr(\"devportal.expires\", \"Expires\")}{\" \"}\n {formatExpirationTime(delegation.expiresAt)}\n </span>\n )}\n <span\n className={cn(\n \"rounded-md px-2 py-0.5 text-xs font-mono\",\n \"bg-bg-sunken text-text-secondary\",\n )}\n >\n {delegation.app?.type ?? \"UNKNOWN\"}\n </span>\n </div>\n\n {/* Scopes */}\n {delegation.scopes.length > 0 && (\n <div>\n <p className=\"mb-1.5 text-xs text-text-secondary\">\n {tr(\"devportal.permissions\", \"Permissions:\")}\n </p>\n <div className=\"flex flex-wrap gap-1.5\">\n {delegation.scopes.map((scope) => (\n <span\n key={scope}\n className=\"rounded-md bg-status-info-bg-subtle px-2 py-0.5 text-xs text-status-info-text\"\n >\n {scope}\n </span>\n ))}\n </div>\n </div>\n )}\n\n {/* Workspace count */}\n {delegation.workspaceIds.length > 0 && (\n <p className=\"flex items-center gap-1 text-xs text-text-secondary\">\n <Users className=\"h-3.5 w-3.5\" />\n {tr(\"devportal.accessToWorkspaces\", \"Access to\")}{\" \"}\n {delegation.workspaceIds.length}{\" \"}\n {tr(\"devportal.workspace\", \"workspace\")}\n {delegation.workspaceIds.length !== 1\n ? tr(\"devportal.workspacePluralSuffix\", \"s\")\n : \"\"}\n </p>\n )}\n </div>\n </div>\n\n {/* Right: Revoke button (only for active delegations) */}\n {delegation.status === \"ACTIVE\" && (\n <button\n onClick={() => onRevoke(delegation)}\n disabled={isRevoking || !canRevoke}\n aria-disabled={!canRevoke}\n className=\"inline-flex shrink-0 items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {isRevoking ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <XCircle className=\"h-4 w-4\" />\n )}\n {tr(\"devportal.revoke\", \"Revoke\")}\n </button>\n )}\n </div>\n </div>\n );\n};\n\n/**\n * Single delegation card for \"Delegations I Granted\" tab\n */\nconst GrantedDelegationCard: FC<{\n delegation: AppUserDelegation;\n onRevoke: (delegation: AppUserDelegation) => void;\n isRevoking: boolean;\n selected: boolean;\n onToggleSelect: (checked: boolean) => void;\n canRevoke: boolean;\n}> = ({\n delegation,\n onRevoke,\n isRevoking,\n selected,\n onToggleSelect,\n canRevoke,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n return (\n <div\n className={cn(\n \"rounded-card border border-border-seam bg-bg-surface p-5 transition-colors hover:border-border-subtle/80\",\n selected && \"border-primary bg-action-primary-bg/5\",\n )}\n >\n <div className=\"flex items-start justify-between gap-4\">\n {/* Left: App info */}\n <div className=\"flex items-start gap-4 min-w-0\">\n {delegation.status === \"ACTIVE\" && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selected}\n onChange={onToggleSelect}\n ariaLabel={tr(\n \"devportal.selectDelegationAriaLabel\",\n `Select delegation ${delegation.app?.name ?? delegation.id}`,\n )}\n className=\"mt-1\"\n />\n </div>\n )}\n <div className=\"flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-accent-purple-subtle text-accent-purple\">\n <AppTypeIcon\n type={delegation.app?.type ?? \"SERVICE\"}\n className=\"h-6 w-6\"\n />\n </div>\n\n <div className=\"min-w-0 space-y-2\">\n {/* Name + status */}\n <div className=\"flex items-center gap-2\">\n <h3 className=\"truncate font-semibold\">\n {delegation.app?.name ??\n tr(\"devportal.unknownApp\", \"Unknown App\")}\n </h3>\n <DelegationStatusBadge status={delegation.status} />\n </div>\n\n {/* Target user */}\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.grantedToUser\", \"Granted to user:\")}{\" \"}\n <code className=\"rounded bg-bg-sunken px-1.5 py-0.5 text-xs\">\n {delegation.userId}\n </code>\n </p>\n\n {/* Time */}\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 text-sm text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" />\n {tr(\"devportal.granted\", \"Granted\")}{\" \"}\n {formatRelativeTime(delegation.grantedAt)}\n </span>\n {delegation.expiresAt && (\n <span className=\"flex items-center gap-1\">\n <AlertTriangle className=\"h-3.5 w-3.5\" />\n {tr(\"devportal.expires\", \"Expires\")}{\" \"}\n {new Date(delegation.expiresAt).toLocaleDateString()}\n </span>\n )}\n </div>\n\n {/* Scopes */}\n {delegation.scopes.length > 0 && (\n <div>\n <p className=\"mb-1.5 text-xs text-text-secondary\">\n {tr(\"devportal.permissionsGranted\", \"Permissions granted:\")}\n </p>\n <div className=\"flex flex-wrap gap-1.5\">\n {delegation.scopes.map((scope) => (\n <span\n key={scope}\n className=\"rounded-md bg-accent-purple-subtle px-2 py-0.5 text-xs text-accent-purple\"\n >\n {scope}\n </span>\n ))}\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Right: Revoke button */}\n {delegation.status === \"ACTIVE\" && (\n <button\n onClick={() => onRevoke(delegation)}\n disabled={isRevoking || !canRevoke}\n aria-disabled={!canRevoke}\n className=\"inline-flex shrink-0 items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {isRevoking ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <XCircle className=\"h-4 w-4\" />\n )}\n {tr(\"devportal.revoke\", \"Revoke\")}\n </button>\n )}\n </div>\n </div>\n );\n};\n\n/**\n * Revocation history section (dimmed, for revoked/expired delegations)\n */\nconst RevocationHistory: FC<{ delegations: AppUserDelegation[] }> = ({\n delegations,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n if (delegations.length === 0) return null;\n\n return (\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-semibold\">\n {tr(\"devportal.revocationHistory\", \"Revocation History\")}\n </h2>\n <div className=\"space-y-3 opacity-60\">\n {delegations.map((delegation) => (\n <div\n key={delegation.id}\n className=\"flex items-center justify-between rounded-lg border bg-bg-sunken/30 p-4\"\n >\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-lg bg-bg-sunken text-text-secondary\">\n <AppTypeIcon\n type={delegation.app?.type ?? \"SERVICE\"}\n className=\"h-5 w-5\"\n />\n </div>\n <div>\n <h3 className=\"font-medium\">\n {delegation.app?.name ??\n tr(\"devportal.unknownApp\", \"Unknown App\")}\n </h3>\n <p className=\"text-sm text-text-secondary\">\n {delegation.status === \"REVOKED\"\n ? tr(\"devportal.revoked\", \"Revoked\")\n : tr(\"devportal.expired\", \"Expired\")}{\" \"}\n {delegation.revokedAt\n ? formatRelativeTime(delegation.revokedAt)\n : \"\"}\n </p>\n </div>\n </div>\n <DelegationStatusBadge status={delegation.status} />\n </div>\n ))}\n </div>\n </div>\n );\n};\n\n// =============================================================================\n// MAIN COMPONENT\n// =============================================================================\n\n/**\n * Delegations management page for the Developer Portal.\n *\n * Consolidates delegation management previously at /auth/delegations in\n * microfe-auth. Shows two tabs:\n * - \"Apps Acting as Me\": delegations where the current user is the subject\n * - \"Delegations I Granted\": delegations the current user granted to others\n */\nexport const DelegationsPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const { allowed: canRevoke } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.DELEGATION_REVOKE,\n );\n // ---------------------------------------------------------------------------\n // State\n // ---------------------------------------------------------------------------\n const [activeTab, setActiveTab] = useState<ActiveTab>(\"acting-as-me\");\n const [revokeTargets, setRevokeTargets] = useState<AppUserDelegation[]>([]);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n const [selectedDelegationIds, setSelectedDelegationIds] = useState<\n Set<string>\n >(new Set());\n\n // ---------------------------------------------------------------------------\n // Queries\n // ---------------------------------------------------------------------------\n const {\n data: delegationsData,\n loading: delegationsLoading,\n error: delegationsError,\n refetch: refetchDelegations,\n } = useCurrentUserDelegationsQuery({\n fetchPolicy: \"cache-and-network\",\n });\n\n const {\n data: grantedData,\n loading: grantedLoading,\n error: grantedError,\n refetch: refetchGranted,\n } = useCurrentUserGrantedDelegationsQuery({\n fetchPolicy: \"cache-and-network\",\n });\n\n // ---------------------------------------------------------------------------\n // Mutation\n // ---------------------------------------------------------------------------\n const [revokeDelegationMutation, { loading: revokeLoading }] =\n useRevokeDelegationMutation();\n\n // ---------------------------------------------------------------------------\n // Derived data\n // ---------------------------------------------------------------------------\n const delegations: AppUserDelegation[] = (\n delegationsData?.currentUserDelegations?.delegations ?? []\n ).map(mapDelegation);\n\n const grantedDelegations: AppUserDelegation[] = (\n grantedData?.currentUserGrantedDelegations?.delegations ?? []\n ).map(mapDelegation);\n\n const activeDelegations = delegations.filter((d) => d.status === \"ACTIVE\");\n const inactiveDelegations = delegations.filter((d) => d.status !== \"ACTIVE\");\n const activeGrantedDelegations = grantedDelegations.filter(\n (d) => d.status === \"ACTIVE\",\n );\n const visibleActiveDelegations =\n activeTab === \"acting-as-me\" ? activeDelegations : activeGrantedDelegations;\n const selectedActiveDelegations = useMemo(\n () =>\n visibleActiveDelegations.filter((delegation) =>\n selectedDelegationIds.has(delegation.id),\n ),\n [selectedDelegationIds, visibleActiveDelegations],\n );\n const allVisibleSelected =\n visibleActiveDelegations.length > 0 &&\n visibleActiveDelegations.every((delegation) =>\n selectedDelegationIds.has(delegation.id),\n );\n const partiallySelected =\n visibleActiveDelegations.some((delegation) =>\n selectedDelegationIds.has(delegation.id),\n ) && !allVisibleSelected;\n\n const isLoading =\n activeTab === \"acting-as-me\" ? delegationsLoading : grantedLoading;\n const queryError =\n activeTab === \"acting-as-me\" ? delegationsError : grantedError;\n\n // ---------------------------------------------------------------------------\n // Handlers\n // ---------------------------------------------------------------------------\n const handleRevokeClick = useCallback((delegation: AppUserDelegation) => {\n setRevokeTargets([delegation]);\n }, []);\n\n const toggleDelegationSelection = useCallback(\n (delegationId: string, checked: boolean) => {\n setSelectedDelegationIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(delegationId);\n } else {\n next.delete(delegationId);\n }\n return next;\n });\n },\n [],\n );\n\n const toggleAllVisibleDelegations = useCallback(\n (checked: boolean) => {\n setSelectedDelegationIds((prev) => {\n const next = new Set(prev);\n visibleActiveDelegations.forEach((delegation) => {\n if (checked) {\n next.add(delegation.id);\n } else {\n next.delete(delegation.id);\n }\n });\n return next;\n });\n },\n [visibleActiveDelegations],\n );\n\n const clearSelection = useCallback(() => {\n setSelectedDelegationIds(new Set());\n }, []);\n\n const handleBulkRevokeClick = useCallback(() => {\n if (selectedActiveDelegations.length === 0) return;\n setRevokeTargets(selectedActiveDelegations);\n }, [selectedActiveDelegations]);\n\n const handleRevokeConfirm = useCallback(async () => {\n if (revokeTargets.length === 0) return;\n try {\n const results = await Promise.allSettled(\n revokeTargets.map((delegation) =>\n revokeDelegationMutation({\n variables: {\n id: delegation.id,\n reason: tr(\n \"devportal.userRevokedAccessReason\",\n \"User revoked access via Developer Portal\",\n ),\n },\n }),\n ),\n );\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) =>\n result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setSuccessMessage(\n `Revoked ${succeeded} delegation${succeeded === 1 ? \"\" : \"s\"}${failed > 0 ? ` • ${failed} failed` : \"\"}`,\n );\n setSelectedDelegationIds((prev) => {\n const next = new Set(prev);\n revokeTargets.forEach((delegation) => next.delete(delegation.id));\n return next;\n });\n setRevokeTargets([]);\n // Refetch both queries to keep data fresh\n void refetchDelegations();\n void refetchGranted();\n } catch {\n // Error is available via the mutation hook's error state;\n // the ConfirmDialog will close and we show the error via queryError fallback\n setRevokeTargets([]);\n }\n }, [\n revokeTargets,\n revokeDelegationMutation,\n refetchDelegations,\n refetchGranted,\n ]);\n\n const handleDismissSuccess = useCallback(() => {\n setSuccessMessage(null);\n }, []);\n\n // ---------------------------------------------------------------------------\n // Summary stats for header\n // ---------------------------------------------------------------------------\n const totalActive = activeDelegations.length;\n const totalGranted = activeGrantedDelegations.length;\n\n // ---------------------------------------------------------------------------\n // Render\n // ---------------------------------------------------------------------------\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={tr(\"devportal.appDelegationsTitle\", \"App Delegations\")}\n description={tr(\n \"devportal.appDelegationsDescription\",\n \"Manage which apps can act on your behalf. Revoke access at any time.\",\n )}\n purpose={tr(\n \"devportal.appDelegationsPurpose\",\n \"Delegations are the consent grants that let an app perform actions as you within a limited scope and time window. Review what you have authorized here, see what each app can do, and revoke anything you no longer trust.\",\n )}\n >\n {/* Success message */}\n {successMessage && (\n <SuccessToast\n message={successMessage}\n onDismiss={handleDismissSuccess}\n />\n )}\n\n {/* Error message */}\n {queryError && (\n <ErrorBanner\n message={\n queryError.message ||\n tr(\n \"devportal.failedToLoadDelegations\",\n \"Failed to load delegations\",\n )\n }\n onRetry={() => {\n void refetchDelegations();\n void refetchGranted();\n }}\n />\n )}\n\n {/* Summary stats — primary emphasis zone */}\n <EmphasisPanel>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-4\">\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-2 text-text-secondary\">\n <Shield className=\"h-4 w-4\" />\n <span className=\"text-sm\">\n {tr(\"devportal.activeDelegations\", \"Active Delegations\")}\n </span>\n </div>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {totalActive}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-2 text-text-secondary\">\n <Users className=\"h-4 w-4\" />\n <span className=\"text-sm\">\n {tr(\"devportal.grantedByMe\", \"Granted by Me\")}\n </span>\n </div>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {totalGranted}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-2 text-status-warning-text\">\n <AlertTriangle className=\"h-4 w-4\" />\n <span className=\"text-sm\">\n {tr(\"devportal.revokedExpired\", \"Revoked / Expired\")}\n </span>\n </div>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {inactiveDelegations.length}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-2 text-text-secondary\">\n <Clock className=\"h-4 w-4\" />\n <span className=\"text-sm\">\n {tr(\"devportal.totalAllTime\", \"Total All-Time\")}\n </span>\n </div>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums\">\n {delegations.length}\n </p>\n </GlassCard>\n </div>\n </EmphasisPanel>\n\n {/* Tabs */}\n <div className=\"border-b\">\n <div\n className=\"flex overflow-x-auto\"\n role=\"tablist\"\n aria-label={tr(\n \"devportal.delegationSections\",\n \"Delegation sections\",\n )}\n >\n <button\n id=\"delegations-tab-acting-as-me\"\n role=\"tab\"\n aria-selected={activeTab === \"acting-as-me\"}\n onClick={() => {\n clearSelection();\n setActiveTab(\"acting-as-me\");\n }}\n className={cn(\n \"-mb-px border-b-2 px-4 py-3 text-sm font-medium transition-colors\",\n activeTab === \"acting-as-me\"\n ? \"border-primary text-primary\"\n : \"border-transparent text-text-secondary hover:text-text-primary\",\n )}\n >\n {tr(\"devportal.appsActingAsMe\", \"Apps Acting as Me\")}\n {totalActive > 0 && (\n <span className=\"ml-2 inline-flex items-center justify-center rounded-full bg-action-primary-bg/10 px-2 py-0.5 text-xs font-medium text-primary\">\n {totalActive}\n </span>\n )}\n </button>\n <button\n id=\"delegations-tab-granted-by-me\"\n role=\"tab\"\n aria-selected={activeTab === \"granted-by-me\"}\n onClick={() => {\n clearSelection();\n setActiveTab(\"granted-by-me\");\n }}\n className={cn(\n \"-mb-px border-b-2 px-4 py-3 text-sm font-medium transition-colors\",\n activeTab === \"granted-by-me\"\n ? \"border-primary text-primary\"\n : \"border-transparent text-text-secondary hover:text-text-primary\",\n )}\n >\n {tr(\"devportal.delegationsIGranted\", \"Delegations I Granted\")}\n {totalGranted > 0 && (\n <span className=\"ml-2 inline-flex items-center justify-center rounded-full bg-action-primary-bg/10 px-2 py-0.5 text-xs font-medium text-primary\">\n {totalGranted}\n </span>\n )}\n </button>\n </div>\n </div>\n\n {visibleActiveDelegations.length > 0 && (\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisibleDelegations}\n ariaLabel={tr(\n \"devportal.selectAllVisibleDelegations\",\n \"Select all visible delegations\",\n )}\n />\n <span className=\"text-sm font-medium\">\n {tr(\"devportal.selectAllVisible\", \"Select all visible\")}\n </span>\n </div>\n {selectedDelegationIds.size > 0 && (\n <button\n onClick={clearSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n {tr(\"devportal.clearSelection\", \"Clear selection\")}\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedDelegationIds.size}{\" \"}\n {tr(\"devportal.selected\", \"selected\")}\n </span>\n </div>\n <p className=\"mt-1 text-2xl font-semibold\">{totalActive}</p>\n </div>\n </div>\n )}\n\n {/* Loading */}\n {isLoading && !delegationsData && !grantedData && (\n <LoadingState\n message={tr(\n \"devportal.loadingDelegations\",\n \"Loading delegations...\",\n )}\n />\n )}\n\n {/* ------------------------------------------------------------------- */}\n {/* Tab 1: Apps Acting as Me */}\n {/* ------------------------------------------------------------------- */}\n {!isLoading && activeTab === \"acting-as-me\" && (\n <div\n className=\"space-y-8\"\n id=\"delegations-panel-acting-as-me\"\n role=\"tabpanel\"\n aria-labelledby=\"delegations-tab-acting-as-me\"\n tabIndex={0}\n >\n {activeDelegations.length === 0 &&\n inactiveDelegations.length === 0 ? (\n <EmptyState\n illustration=\"empty-people\"\n title={tr(\n \"devportal.noActiveDelegations\",\n \"No Active Delegations\",\n )}\n description={tr(\n \"devportal.noAppsAuthorizedOnYourBehalf\",\n \"No apps are currently authorized to act on your behalf.\",\n )}\n />\n ) : (\n <>\n {/* Active delegation cards */}\n {activeDelegations.length === 0 ? (\n <EmptyState\n illustration=\"empty-people\"\n icon={<Shield size={32} />}\n title={tr(\n \"devportal.noActiveDelegations\",\n \"No Active Delegations\",\n )}\n description={tr(\n \"devportal.allPreviousDelegationsRevokedOrExpired\",\n \"All previous delegations have been revoked or expired.\",\n )}\n />\n ) : (\n <div className=\"space-y-4\">\n {activeDelegations.map((delegation) => (\n <DelegationCard\n key={delegation.id}\n delegation={delegation}\n onRevoke={handleRevokeClick}\n isRevoking={\n revokeLoading &&\n revokeTargets.some(\n (item) => item.id === delegation.id,\n )\n }\n selected={selectedDelegationIds.has(delegation.id)}\n onToggleSelect={(checked) =>\n toggleDelegationSelection(delegation.id, checked)\n }\n canRevoke={canRevoke}\n />\n ))}\n </div>\n )}\n\n {/* Revocation history */}\n <RevocationHistory delegations={inactiveDelegations} />\n </>\n )}\n </div>\n )}\n\n {/* ------------------------------------------------------------------- */}\n {/* Tab 2: Delegations I Granted */}\n {/* ------------------------------------------------------------------- */}\n {!isLoading && activeTab === \"granted-by-me\" && (\n <div\n className=\"space-y-4\"\n id=\"delegations-panel-granted-by-me\"\n role=\"tabpanel\"\n aria-labelledby=\"delegations-tab-granted-by-me\"\n tabIndex={0}\n >\n {grantedDelegations.length === 0 ? (\n <EmptyState\n illustration=\"empty-people\"\n title={tr(\n \"devportal.noDelegationsGranted\",\n \"No Delegations Granted\",\n )}\n description={tr(\n \"devportal.noGrantedDelegationsDescription\",\n \"You haven't granted any app delegations to other users.\",\n )}\n />\n ) : (\n grantedDelegations.map((delegation) => (\n <GrantedDelegationCard\n key={delegation.id}\n delegation={delegation}\n onRevoke={handleRevokeClick}\n isRevoking={\n revokeLoading &&\n revokeTargets.some((item) => item.id === delegation.id)\n }\n selected={selectedDelegationIds.has(delegation.id)}\n onToggleSelect={(checked) =>\n toggleDelegationSelection(delegation.id, checked)\n }\n canRevoke={canRevoke}\n />\n ))\n )}\n </div>\n )}\n\n {/* Info card */}\n <div className=\"rounded-lg border border-border-subtle bg-status-info-bg-subtle p-5\">\n <div className=\"flex gap-4\">\n <AlertCircle className=\"h-6 w-6 shrink-0 text-accent-blue\" />\n <div>\n <h3 className=\"font-semibold text-status-info-text\">\n {tr(\"devportal.aboutAppDelegations\", \"About App Delegations\")}\n </h3>\n <p className=\"mt-1 text-sm text-status-info-text\">\n {tr(\n \"devportal.aboutAppDelegationsText\",\n \"App delegations allow automated services, bots, and integrations to perform actions on your behalf. Each delegation specifies which permissions (scopes) and workspaces the app can access. You can revoke access at any time, which immediately prevents the app from acting as you.\",\n )}\n </p>\n </div>\n </div>\n </div>\n\n {/* Revoke confirmation dialog */}\n <ConfirmDialog\n open={revokeTargets.length > 0}\n onOpenChange={(open) => {\n if (!open) setRevokeTargets([]);\n }}\n onConfirm={handleRevokeConfirm}\n title={\n revokeTargets.length > 1\n ? tr(\"devportal.revokeDelegations\", \"Revoke Delegations\")\n : tr(\"devportal.revokeDelegation\", \"Revoke Delegation\")\n }\n description={\n revokeTargets.length > 1\n ? tr(\n \"devportal.revokeDelegationsBulkConfirm\",\n `Are you sure you want to revoke ${revokeTargets.length} selected delegations? Those apps will no longer be able to act on the delegated users' behalf.`,\n )\n : tr(\n \"devportal.revokeDelegationSingleConfirm\",\n `Are you sure you want to revoke access for \"${revokeTargets[0]?.app?.name ?? \"this app\"}\"? This app will no longer be able to act on your behalf.`,\n )\n }\n confirmLabel={tr(\"devportal.revokeAccess\", \"Revoke Access\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"danger\"\n loading={revokeLoading}\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"EditApplicationPage.d.ts","sourceRoot":"","sources":["../../../src/devportal/pages/EditApplicationPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAsKhC;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,EAwiCjC,CAAC"}
1
+ {"version":3,"file":"EditApplicationPage.d.ts","sourceRoot":"","sources":["../../../src/devportal/pages/EditApplicationPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAsKhC;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,EA2iCjC,CAAC"}
@@ -308,7 +308,7 @@ var S = () => {
308
308
  });
309
309
  let We = K.status === "DRAFT" || K.status === "REJECTED", Ge = K.status === "PUBLISHED", Ke = K.status === "ACTIVE" || K.status === "PUBLISHED";
310
310
  return /* @__PURE__ */ y(le, {
311
- permission: p.APP_UPDATE,
311
+ authOnly: !0,
312
312
  children: /* @__PURE__ */ b(r, {
313
313
  title: `${D("devportal.editAppTitlePrefix", "Edit:")} ${K.name}`,
314
314
  description: D("devportal.editAppDescription", "Update your application settings"),