@burdenoff/microfe-devportal 2026.801.1 → 2026.802.1
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.
- package/dist/devportal/AdminDevportalRoutes.js +14 -14
- package/dist/devportal/DevportalRoutes.js +115 -115
- package/dist/devportal/DevportalRoutes.js.map +1 -1
- package/dist/devportal/components/SectionNav.js +1 -0
- package/dist/devportal/components/SectionNav.js.map +1 -1
- package/dist/devportal/components/TelemetryErrorBoundary.js +7 -7
- package/dist/devportal/pages/AnalyticsDashboardPage.js +41 -41
- package/dist/devportal/pages/AnalyticsDashboardPage.js.map +1 -1
- package/dist/devportal/pages/AppLogsPage.js +27 -27
- package/dist/devportal/pages/ApplicationDetailPage.js +929 -929
- package/dist/devportal/pages/ApplicationDetailPage.js.map +1 -1
- package/dist/devportal/pages/ApplicationVersionsPage.js +39 -39
- package/dist/devportal/pages/ApplicationVersionsPage.js.map +1 -1
- package/dist/devportal/pages/CreateWebhookPage.js +55 -55
- package/dist/devportal/pages/EditApplicationPage.js +36 -36
- package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
- package/dist/devportal/pages/EditPhysicalItemPage.js +40 -40
- package/dist/devportal/pages/InvitationDecisionPage.js +25 -25
- package/dist/devportal/pages/ListingPreviewPage.js +36 -36
- package/dist/devportal/pages/OAuthCallbackPage.js +10 -10
- package/dist/devportal/pages/OAuthClientDetailPage.js +27 -27
- package/dist/devportal/pages/OAuthClientDetailPage.js.map +1 -1
- package/dist/devportal/pages/OrganizationDetailPage.js +329 -329
- package/dist/devportal/pages/OrganizationDetailPage.js.map +1 -1
- package/dist/devportal/pages/OrganizationMembersPage.js +181 -181
- package/dist/devportal/pages/OrganizationMembersPage.js.map +1 -1
- package/dist/devportal/pages/PublishPage.js +43 -43
- package/dist/devportal/pages/PublishPage.js.map +1 -1
- package/dist/devportal/pages/RevenueDashboardPage.js +65 -65
- package/dist/devportal/pages/RevenueDashboardPage.js.map +1 -1
- package/dist/devportal/pages/StoreSubmissionPage.js +126 -126
- package/dist/devportal/pages/StoreSubmissionPage.js.map +1 -1
- package/dist/devportal/pages/WebhookDetailPage.js +28 -28
- package/dist/devportal/pages/WebhookDetailPage.js.map +1 -1
- package/dist/devportal/pages/WebhooksPage.js +47 -47
- package/dist/devportal/pages/WebhooksPage.js.map +1 -1
- package/dist/devportal/providers/DevportalProvider.js +12 -12
- package/package.json +1 -1
- package/dist/node_modules/react-router/dist/production/lib/components.js +0 -124
- package/dist/node_modules/react-router/dist/production/lib/components.js.map +0 -1
- package/dist/node_modules/react-router/dist/production/lib/context.js +0 -32
- package/dist/node_modules/react-router/dist/production/lib/context.js.map +0 -1
- package/dist/node_modules/react-router/dist/production/lib/dom/dom.js +0 -83
- package/dist/node_modules/react-router/dist/production/lib/dom/dom.js.map +0 -1
- package/dist/node_modules/react-router/dist/production/lib/dom/lib.js +0 -358
- package/dist/node_modules/react-router/dist/production/lib/dom/lib.js.map +0 -1
- package/dist/node_modules/react-router/dist/production/lib/dom/ssr/components.js +0 -188
- package/dist/node_modules/react-router/dist/production/lib/dom/ssr/components.js.map +0 -1
- package/dist/node_modules/react-router/dist/production/lib/dom/ssr/invariant.js +0 -8
- package/dist/node_modules/react-router/dist/production/lib/dom/ssr/invariant.js.map +0 -1
- package/dist/node_modules/react-router/dist/production/lib/dom/ssr/links.js +0 -75
- package/dist/node_modules/react-router/dist/production/lib/dom/ssr/links.js.map +0 -1
- package/dist/node_modules/react-router/dist/production/lib/dom/ssr/markup.js +0 -15
- package/dist/node_modules/react-router/dist/production/lib/dom/ssr/markup.js.map +0 -1
- package/dist/node_modules/react-router/dist/production/lib/dom/ssr/routeModules.js +0 -18
- package/dist/node_modules/react-router/dist/production/lib/dom/ssr/routeModules.js.map +0 -1
- package/dist/node_modules/react-router/dist/production/lib/dom/ssr/single-fetch.js +0 -10
- package/dist/node_modules/react-router/dist/production/lib/dom/ssr/single-fetch.js.map +0 -1
- package/dist/node_modules/react-router/dist/production/lib/errors.js +0 -19
- package/dist/node_modules/react-router/dist/production/lib/errors.js.map +0 -1
- package/dist/node_modules/react-router/dist/production/lib/hooks.js +0 -296
- package/dist/node_modules/react-router/dist/production/lib/hooks.js.map +0 -1
- package/dist/node_modules/react-router/dist/production/lib/router/history.js +0 -166
- package/dist/node_modules/react-router/dist/production/lib/router/history.js.map +0 -1
- package/dist/node_modules/react-router/dist/production/lib/router/router.js +0 -33
- package/dist/node_modules/react-router/dist/production/lib/router/router.js.map +0 -1
- package/dist/node_modules/react-router/dist/production/lib/router/url.js +0 -9
- package/dist/node_modules/react-router/dist/production/lib/router/url.js.map +0 -1
- package/dist/node_modules/react-router/dist/production/lib/router/utils.js +0 -236
- package/dist/node_modules/react-router/dist/production/lib/router/utils.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OAuthClientDetailPage.js","names":[],"sources":["../../../src/devportal/pages/OAuthClientDetailPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState } from \"react\";\nimport {\n Copy,\n Eye,\n EyeOff,\n Loader2,\n AlertCircle,\n RefreshCw,\n Trash2,\n ArrowLeft,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n CTAOverflowMenu,\n GlassCard,\n} from \"@burdenoff/fe-libs/ui\";\nimport { useParams } from \"react-router\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { ActiveIndicator } from \"../components/StatusBadge\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport type { AuthApp } from \"../types\";\nimport { cn } from \"../utils/cn\";\nimport {\n nativeCopyText,\n nativeImpact,\n nativeNotify,\n} from \"../../utils/nativeBridge\";\nimport {\n useGetAuthAppQuery,\n useRotateAppSecretMutation,\n useDeactivateAppMutation,\n useUpdateAuthAppMutation,\n getErrorMessage,\n} from \"../hooks\";\n\n/**\n * OAuth App Detail page\n *\n * Shows details for an auth-svc App (replaces devportal-svc OAuthClient detail).\n * Supports secret rotation, deactivation, and status toggle.\n */\nexport const OAuthClientDetailPage: FC = () => {\n const { clientId: appId } = useParams<{ clientId: string }>();\n const { navigate, basePath } = useDevportal();\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 [showSecret, setShowSecret] = useState(false);\n const [newSecret, setNewSecret] = useState<string | null>(null);\n const [confirmDelete, setConfirmDelete] = useState(false);\n const [confirmRotate, setConfirmRotate] = useState(false);\n\n const { data, loading, error, refetch } = useGetAuthAppQuery({\n variables: { id: appId || \"\" },\n skip: !appId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const [rotateSecret, { loading: rotating }] = useRotateAppSecretMutation();\n const [deactivateApp, { loading: deactivating }] = useDeactivateAppMutation();\n const [updateApp] = useUpdateAuthAppMutation();\n\n const app: AuthApp | null = data?.app\n ? {\n id: data.app.id,\n name: data.app.name,\n description: data.app.description ?? undefined,\n clientId: data.app.clientId,\n type: data.app.type as AuthApp[\"type\"],\n status: data.app.status as AuthApp[\"status\"],\n scopes: data.app.scopes ?? [],\n redirectUris: data.app.redirectUris ?? [],\n ownerUserId: data.app.ownerUserId,\n tenantId: data.app.tenantId,\n createdAt: data.app.createdAt,\n updatedAt: data.app.updatedAt,\n }\n : null;\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const handleCopy = async (text: string) => {\n void nativeImpact(\"light\");\n const ok = await nativeCopyText(text);\n void nativeNotify(ok ? \"success\" : \"error\");\n };\n\n const handleRotateSecret = async () => {\n if (!appId) return;\n try {\n const result = await rotateSecret({ variables: { id: appId } });\n const secret = result.data?.rotateAppSecret?.clientSecret;\n if (secret) {\n setNewSecret(secret);\n setShowSecret(true);\n }\n setConfirmRotate(false);\n refetch();\n } catch {\n // error handled by Apollo\n }\n };\n\n const handleDeactivate = async () => {\n if (!appId) return;\n try {\n await deactivateApp({ variables: { id: appId } });\n setConfirmDelete(false);\n handleNavigate(\"/oauth\");\n } catch {\n // error handled by Apollo\n }\n };\n\n const handleToggleStatus = async () => {\n if (!appId || !app) return;\n const newStatus = app.status === \"ACTIVE\" ? \"INACTIVE\" : \"ACTIVE\";\n try {\n await updateApp({\n variables: { id: appId, input: { status: newStatus } },\n });\n refetch();\n } catch {\n // error handled by Apollo\n }\n };\n\n if (loading && !data) {\n return (\n <PageLayout\n title={tr(\"devportal.appDetails\", \"App Details\")}\n description={tr(\"devportal.loadingDots\", \"Loading...\")}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToApps\", \"Back to Apps\")}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n </div>\n </PageLayout>\n );\n }\n\n if (error || !app) {\n return (\n <PageLayout\n title={tr(\"devportal.appDetails\", \"App Details\")}\n description={tr(\"devportal.failedToLoad\", \"Failed to load\")}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToApps\", \"Back to Apps\")}\n >\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-status-error-text\" />\n <h3 className=\"mt-2 font-medium text-status-error-text\">\n {error\n ? tr(\"devportal.failedToLoadApp\", \"Failed to load app\")\n : tr(\"devportal.appNotFound\", \"App not found\")}\n </h3>\n {error && (\n <p className=\"mt-1 text-sm text-text-secondary\">\n {getErrorMessage(error)}\n </p>\n )}\n <button\n onClick={() => handleNavigate(\"/oauth\")}\n className=\"mt-4 inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <ArrowLeft size={16} />\n {tr(\"devportal.backToApps\", \"Back to Apps\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={app.name}\n description={\n app.description ||\n tr(\n \"devportal.oauthAppDetailsAndCredentials\",\n \"OAuth App details and credentials\",\n )\n }\n purpose={tr(\n \"devportal.oauthAppDetailPurpose\",\n \"These are this OAuth app's credentials and the scopes it may request. Copy the client ID for your integration, rotate the secret if it leaks, and keep scopes minimal so users only grant what the app truly needs.\",\n )}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToApps\", \"Back to Apps\")}\n actions={\n <CTAOverflowMenu\n primary={{\n label:\n app.status === \"ACTIVE\"\n ? tr(\"devportal.deactivate\", \"Deactivate\")\n : tr(\"devportal.activate\", \"Activate\"),\n onSelect: handleToggleStatus,\n }}\n actions={[\n {\n label: tr(\"devportal.delete\", \"Delete\"),\n icon: <Trash2 size={16} />,\n intent: \"destructive\",\n onSelect: () => setConfirmDelete(true),\n },\n ]}\n />\n }\n >\n {/* Status & Type */}\n <div className=\"grid gap-6 md:grid-cols-2\">\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-4\">\n {tr(\"devportal.statusAndConfiguration\", \"Status & Configuration\")}\n </h3>\n <div className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <span className=\"text-sm text-text-secondary\">\n {tr(\"devportal.status\", \"Status\")}\n </span>\n <div className=\"flex items-center gap-2\">\n <ActiveIndicator active={app.status === \"ACTIVE\"} />\n <span className=\"text-sm font-medium\">{app.status}</span>\n </div>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-sm text-text-secondary\">\n {tr(\"devportal.type\", \"Type\")}\n </span>\n <span\n className={cn(\n \"rounded px-2 py-0.5 text-xs font-medium\",\n app.type === \"SERVICE\"\n ? \"bg-accent-purple-subtle text-accent-purple\"\n : app.type === \"INTEGRATION\" ||\n app.type === \"API_INTEGRATION\"\n ? \"bg-status-info-bg-subtle text-status-info-text\"\n : \"bg-status-success-bg-subtle text-status-success-text\",\n )}\n >\n {app.type}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-sm text-text-secondary\">\n {tr(\"devportal.created\", \"Created\")}\n </span>\n <span className=\"text-sm\">\n {new Date(app.createdAt).toLocaleDateString()}\n </span>\n </div>\n </div>\n </div>\n\n {/* Credentials — primary emphasis zone */}\n <GlassCard treatment=\"glass\" glow className=\"p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-4\">\n {tr(\"devportal.credentials\", \"Credentials\")}\n </h3>\n <div className=\"space-y-3\">\n <div>\n <label className=\"text-xs text-text-secondary\">\n {tr(\"devportal.clientId\", \"Client ID\")}\n </label>\n <div className=\"mt-1 flex items-center gap-2\">\n <code className=\"flex-1 rounded bg-bg-sunken px-3 py-1.5 text-sm font-mono\">\n {app.clientId}\n </code>\n <button\n onClick={() => handleCopy(app.clientId)}\n className=\"rounded p-1.5 hover:bg-bg-sunken transition-colors\"\n title=\"Copy\"\n >\n <Copy size={14} />\n </button>\n </div>\n </div>\n {newSecret && (\n <div>\n <label className=\"text-xs text-status-error-text font-medium\">\n {tr(\n \"devportal.newClientSecretShownOnce\",\n \"New Client Secret (shown only once!)\",\n )}\n </label>\n <div className=\"mt-1 flex items-center gap-2\">\n <code className=\"flex-1 rounded bg-status-error-bg/10 border border-status-error-border/30 px-3 py-1.5 text-sm font-mono\">\n {showSecret\n ? newSecret\n : \"\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\"}\n </code>\n <button\n onClick={() => setShowSecret(!showSecret)}\n className=\"rounded p-1.5 hover:bg-bg-sunken transition-colors\"\n >\n {showSecret ? <EyeOff size={14} /> : <Eye size={14} />}\n </button>\n <button\n onClick={() => handleCopy(newSecret)}\n className=\"rounded p-1.5 hover:bg-bg-sunken transition-colors\"\n >\n <Copy size={14} />\n </button>\n </div>\n </div>\n )}\n <button\n onClick={() => setConfirmRotate(true)}\n disabled={rotating}\n className=\"mt-2 inline-flex items-center gap-2 rounded-md bg-status-warning-bg-subtle px-3 py-1.5 text-sm font-medium text-status-warning-text hover:bg-status-warning-bg-subtle transition-colors disabled:opacity-50\"\n >\n <RefreshCw\n size={14}\n className={rotating ? \"animate-spin\" : \"\"}\n />\n {tr(\"devportal.rotateSecret\", \"Rotate Secret\")}\n </button>\n </div>\n </GlassCard>\n </div>\n\n {/* Scopes */}\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-3\">\n {tr(\"devportal.scopes\", \"Scopes\")} ({app.scopes.length})\n </h3>\n {app.scopes.length > 0 ? (\n <div className=\"flex flex-wrap gap-2\">\n {app.scopes.map((scope) => (\n <span\n key={scope}\n className=\"rounded-full bg-action-primary-bg/10 px-3 py-1 text-xs font-medium text-primary\"\n >\n {scope}\n </span>\n ))}\n </div>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.noScopesConfigured\", \"No scopes configured\")}\n </p>\n )}\n </div>\n\n {/* Redirect URIs */}\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-3\">\n {tr(\"devportal.redirectUris\", \"Redirect URIs\")} (\n {app.redirectUris.length})\n </h3>\n {app.redirectUris.length > 0 ? (\n <div className=\"space-y-2\">\n {app.redirectUris.map((uri) => (\n <div key={uri} className=\"flex items-center gap-2\">\n <code className=\"rounded bg-bg-sunken px-3 py-1.5 text-sm font-mono\">\n {uri}\n </code>\n <button\n onClick={() => handleCopy(uri)}\n className=\"rounded p-1 hover:bg-bg-sunken transition-colors\"\n >\n <Copy size={12} />\n </button>\n </div>\n ))}\n </div>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"devportal.noRedirectUrisConfigured\",\n \"No redirect URIs configured\",\n )}\n </p>\n )}\n </div>\n\n {/* Confirm Rotate Dialog */}\n <AlertDialog open={confirmRotate} onOpenChange={setConfirmRotate}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>\n {tr(\n \"devportal.rotateClientSecretQuestion\",\n \"Rotate Client Secret?\",\n )}\n </AlertDialogTitle>\n <AlertDialogDescription>\n {tr(\n \"devportal.rotateSecretWarning\",\n \"This will invalidate the current client secret. All integrations using the old secret will stop working immediately.\",\n )}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={rotating}>\n {tr(\"devportal.cancel\", \"Cancel\")}\n </AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault();\n void handleRotateSecret();\n }}\n disabled={rotating}\n className=\"bg-status-warning-bg text-white hover:bg-status-warning-bg/90\"\n >\n {rotating\n ? tr(\"devportal.rotating\", \"Rotating...\")\n : tr(\"devportal.rotateSecret\", \"Rotate Secret\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n\n {/* Confirm Deactivate Dialog */}\n <AlertDialog open={confirmDelete} onOpenChange={setConfirmDelete}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle className=\"text-status-error-text\">\n {tr(\"devportal.deactivateAppQuestion\", \"Deactivate App?\")}\n </AlertDialogTitle>\n <AlertDialogDescription>\n {tr(\n \"devportal.deactivateAppWarning\",\n \"This will deactivate the app and revoke all tokens. This action cannot be undone easily.\",\n )}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={deactivating}>\n {tr(\"devportal.cancel\", \"Cancel\")}\n </AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault();\n void handleDeactivate();\n }}\n disabled={deactivating}\n className=\"bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90\"\n >\n {deactivating\n ? tr(\"devportal.deactivating\", \"Deactivating...\")\n : tr(\"devportal.deactivate\", \"Deactivate\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"OAuthClientDetailPage.js","names":[],"sources":["../../../src/devportal/pages/OAuthClientDetailPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState } from \"react\";\nimport {\n Copy,\n Eye,\n EyeOff,\n Loader2,\n AlertCircle,\n RefreshCw,\n Trash2,\n ArrowLeft,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n CTAOverflowMenu,\n GlassCard,\n} from \"@burdenoff/fe-libs/ui\";\nimport { useParams } from \"react-router\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { ActiveIndicator } from \"../components/StatusBadge\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport type { AuthApp } from \"../types\";\nimport { cn } from \"../utils/cn\";\nimport {\n nativeCopyText,\n nativeImpact,\n nativeNotify,\n} from \"../../utils/nativeBridge\";\nimport {\n useGetAuthAppQuery,\n useRotateAppSecretMutation,\n useDeactivateAppMutation,\n useUpdateAuthAppMutation,\n getErrorMessage,\n} from \"../hooks\";\n\n/**\n * OAuth App Detail page\n *\n * Shows details for an auth-svc App (replaces devportal-svc OAuthClient detail).\n * Supports secret rotation, deactivation, and status toggle.\n */\nexport const OAuthClientDetailPage: FC = () => {\n const { clientId: appId } = useParams<{ clientId: string }>();\n const { navigate, basePath } = useDevportal();\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 [showSecret, setShowSecret] = useState(false);\n const [newSecret, setNewSecret] = useState<string | null>(null);\n const [confirmDelete, setConfirmDelete] = useState(false);\n const [confirmRotate, setConfirmRotate] = useState(false);\n\n const { data, loading, error, refetch } = useGetAuthAppQuery({\n variables: { id: appId || \"\" },\n skip: !appId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const [rotateSecret, { loading: rotating }] = useRotateAppSecretMutation();\n const [deactivateApp, { loading: deactivating }] = useDeactivateAppMutation();\n const [updateApp] = useUpdateAuthAppMutation();\n\n const app: AuthApp | null = data?.app\n ? {\n id: data.app.id,\n name: data.app.name,\n description: data.app.description ?? undefined,\n clientId: data.app.clientId,\n type: data.app.type as AuthApp[\"type\"],\n status: data.app.status as AuthApp[\"status\"],\n scopes: data.app.scopes ?? [],\n redirectUris: data.app.redirectUris ?? [],\n ownerUserId: data.app.ownerUserId,\n tenantId: data.app.tenantId,\n createdAt: data.app.createdAt,\n updatedAt: data.app.updatedAt,\n }\n : null;\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const handleCopy = async (text: string) => {\n void nativeImpact(\"light\");\n const ok = await nativeCopyText(text);\n void nativeNotify(ok ? \"success\" : \"error\");\n };\n\n const handleRotateSecret = async () => {\n if (!appId) return;\n try {\n const result = await rotateSecret({ variables: { id: appId } });\n const secret = result.data?.rotateAppSecret?.clientSecret;\n if (secret) {\n setNewSecret(secret);\n setShowSecret(true);\n }\n setConfirmRotate(false);\n refetch();\n } catch {\n // error handled by Apollo\n }\n };\n\n const handleDeactivate = async () => {\n if (!appId) return;\n try {\n await deactivateApp({ variables: { id: appId } });\n setConfirmDelete(false);\n handleNavigate(\"/oauth\");\n } catch {\n // error handled by Apollo\n }\n };\n\n const handleToggleStatus = async () => {\n if (!appId || !app) return;\n const newStatus = app.status === \"ACTIVE\" ? \"INACTIVE\" : \"ACTIVE\";\n try {\n await updateApp({\n variables: { id: appId, input: { status: newStatus } },\n });\n refetch();\n } catch {\n // error handled by Apollo\n }\n };\n\n if (loading && !data) {\n return (\n <PageLayout\n title={tr(\"devportal.appDetails\", \"App Details\")}\n description={tr(\"devportal.loadingDots\", \"Loading...\")}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToApps\", \"Back to Apps\")}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n </div>\n </PageLayout>\n );\n }\n\n if (error || !app) {\n return (\n <PageLayout\n title={tr(\"devportal.appDetails\", \"App Details\")}\n description={tr(\"devportal.failedToLoad\", \"Failed to load\")}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToApps\", \"Back to Apps\")}\n >\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-status-error-text\" />\n <h3 className=\"mt-2 font-medium text-status-error-text\">\n {error\n ? tr(\"devportal.failedToLoadApp\", \"Failed to load app\")\n : tr(\"devportal.appNotFound\", \"App not found\")}\n </h3>\n {error && (\n <p className=\"mt-1 text-sm text-text-secondary\">\n {getErrorMessage(error)}\n </p>\n )}\n <button\n onClick={() => handleNavigate(\"/oauth\")}\n className=\"mt-4 inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <ArrowLeft size={16} />\n {tr(\"devportal.backToApps\", \"Back to Apps\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={app.name}\n description={\n app.description ||\n tr(\n \"devportal.oauthAppDetailsAndCredentials\",\n \"OAuth App details and credentials\",\n )\n }\n purpose={tr(\n \"devportal.oauthAppDetailPurpose\",\n \"These are this OAuth app's credentials and the scopes it may request. Copy the client ID for your integration, rotate the secret if it leaks, and keep scopes minimal so users only grant what the app truly needs.\",\n )}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToApps\", \"Back to Apps\")}\n actions={\n <CTAOverflowMenu\n primary={{\n label:\n app.status === \"ACTIVE\"\n ? tr(\"devportal.deactivate\", \"Deactivate\")\n : tr(\"devportal.activate\", \"Activate\"),\n onSelect: handleToggleStatus,\n }}\n actions={[\n {\n label: tr(\"devportal.delete\", \"Delete\"),\n icon: <Trash2 size={16} />,\n intent: \"destructive\",\n onSelect: () => setConfirmDelete(true),\n },\n ]}\n />\n }\n >\n {/* Status & Type */}\n <div className=\"grid gap-6 md:grid-cols-2\">\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-4\">\n {tr(\"devportal.statusAndConfiguration\", \"Status & Configuration\")}\n </h3>\n <div className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <span className=\"text-sm text-text-secondary\">\n {tr(\"devportal.status\", \"Status\")}\n </span>\n <div className=\"flex items-center gap-2\">\n <ActiveIndicator active={app.status === \"ACTIVE\"} />\n <span className=\"text-sm font-medium\">{app.status}</span>\n </div>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-sm text-text-secondary\">\n {tr(\"devportal.type\", \"Type\")}\n </span>\n <span\n className={cn(\n \"rounded px-2 py-0.5 text-xs font-medium\",\n app.type === \"SERVICE\"\n ? \"bg-accent-purple-subtle text-accent-purple\"\n : app.type === \"INTEGRATION\" ||\n app.type === \"API_INTEGRATION\"\n ? \"bg-status-info-bg-subtle text-status-info-text\"\n : \"bg-status-success-bg-subtle text-status-success-text\",\n )}\n >\n {app.type}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-sm text-text-secondary\">\n {tr(\"devportal.created\", \"Created\")}\n </span>\n <span className=\"text-sm\">\n {new Date(app.createdAt).toLocaleDateString()}\n </span>\n </div>\n </div>\n </div>\n\n {/* Credentials — primary emphasis zone */}\n <GlassCard treatment=\"glass\" glow className=\"p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-4\">\n {tr(\"devportal.credentials\", \"Credentials\")}\n </h3>\n <div className=\"space-y-3\">\n <div>\n <label className=\"text-xs text-text-secondary\">\n {tr(\"devportal.clientId\", \"Client ID\")}\n </label>\n <div className=\"mt-1 flex items-center gap-2\">\n <code className=\"flex-1 rounded bg-bg-sunken px-3 py-1.5 text-sm font-mono\">\n {app.clientId}\n </code>\n <button\n onClick={() => handleCopy(app.clientId)}\n className=\"rounded p-1.5 hover:bg-bg-sunken transition-colors\"\n title=\"Copy\"\n >\n <Copy size={14} />\n </button>\n </div>\n </div>\n {newSecret && (\n <div>\n <label className=\"text-xs text-status-error-text font-medium\">\n {tr(\n \"devportal.newClientSecretShownOnce\",\n \"New Client Secret (shown only once!)\",\n )}\n </label>\n <div className=\"mt-1 flex items-center gap-2\">\n <code className=\"flex-1 rounded bg-status-error-bg/10 border border-status-error-border/30 px-3 py-1.5 text-sm font-mono\">\n {showSecret\n ? newSecret\n : \"\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\"}\n </code>\n <button\n onClick={() => setShowSecret(!showSecret)}\n className=\"rounded p-1.5 hover:bg-bg-sunken transition-colors\"\n >\n {showSecret ? <EyeOff size={14} /> : <Eye size={14} />}\n </button>\n <button\n onClick={() => handleCopy(newSecret)}\n className=\"rounded p-1.5 hover:bg-bg-sunken transition-colors\"\n >\n <Copy size={14} />\n </button>\n </div>\n </div>\n )}\n <button\n onClick={() => setConfirmRotate(true)}\n disabled={rotating}\n className=\"mt-2 inline-flex items-center gap-2 rounded-md bg-status-warning-bg-subtle px-3 py-1.5 text-sm font-medium text-status-warning-text hover:bg-status-warning-bg-subtle transition-colors disabled:opacity-50\"\n >\n <RefreshCw\n size={14}\n className={rotating ? \"animate-spin\" : \"\"}\n />\n {tr(\"devportal.rotateSecret\", \"Rotate Secret\")}\n </button>\n </div>\n </GlassCard>\n </div>\n\n {/* Scopes */}\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-3\">\n {tr(\"devportal.scopes\", \"Scopes\")} ({app.scopes.length})\n </h3>\n {app.scopes.length > 0 ? (\n <div className=\"flex flex-wrap gap-2\">\n {app.scopes.map((scope) => (\n <span\n key={scope}\n className=\"rounded-full bg-action-primary-bg/10 px-3 py-1 text-xs font-medium text-primary\"\n >\n {scope}\n </span>\n ))}\n </div>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.noScopesConfigured\", \"No scopes configured\")}\n </p>\n )}\n </div>\n\n {/* Redirect URIs */}\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-3\">\n {tr(\"devportal.redirectUris\", \"Redirect URIs\")} (\n {app.redirectUris.length})\n </h3>\n {app.redirectUris.length > 0 ? (\n <div className=\"space-y-2\">\n {app.redirectUris.map((uri) => (\n <div key={uri} className=\"flex items-center gap-2\">\n <code className=\"rounded bg-bg-sunken px-3 py-1.5 text-sm font-mono\">\n {uri}\n </code>\n <button\n onClick={() => handleCopy(uri)}\n className=\"rounded p-1 hover:bg-bg-sunken transition-colors\"\n >\n <Copy size={12} />\n </button>\n </div>\n ))}\n </div>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"devportal.noRedirectUrisConfigured\",\n \"No redirect URIs configured\",\n )}\n </p>\n )}\n </div>\n\n {/* Confirm Rotate Dialog */}\n <AlertDialog open={confirmRotate} onOpenChange={setConfirmRotate}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>\n {tr(\n \"devportal.rotateClientSecretQuestion\",\n \"Rotate Client Secret?\",\n )}\n </AlertDialogTitle>\n <AlertDialogDescription>\n {tr(\n \"devportal.rotateSecretWarning\",\n \"This will invalidate the current client secret. All integrations using the old secret will stop working immediately.\",\n )}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={rotating}>\n {tr(\"devportal.cancel\", \"Cancel\")}\n </AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault();\n void handleRotateSecret();\n }}\n disabled={rotating}\n className=\"bg-status-warning-bg text-white hover:bg-status-warning-bg/90\"\n >\n {rotating\n ? tr(\"devportal.rotating\", \"Rotating...\")\n : tr(\"devportal.rotateSecret\", \"Rotate Secret\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n\n {/* Confirm Deactivate Dialog */}\n <AlertDialog open={confirmDelete} onOpenChange={setConfirmDelete}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle className=\"text-status-error-text\">\n {tr(\"devportal.deactivateAppQuestion\", \"Deactivate App?\")}\n </AlertDialogTitle>\n <AlertDialogDescription>\n {tr(\n \"devportal.deactivateAppWarning\",\n \"This will deactivate the app and revoke all tokens. This action cannot be undone easily.\",\n )}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={deactivating}>\n {tr(\"devportal.cancel\", \"Cancel\")}\n </AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault();\n void handleDeactivate();\n }}\n disabled={deactivating}\n className=\"bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90\"\n >\n {deactivating\n ? tr(\"devportal.deactivating\", \"Deactivating...\")\n : tr(\"devportal.deactivate\", \"Deactivate\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
|