@burdenoff/microfe-devportal 2026.624.28 → 2026.625.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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApplicationDetailPage.js","names":[],"sources":["../../../src/devportal/pages/ApplicationDetailPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState, useMemo, useCallback, useEffect, useRef } from \"react\";\nimport { gql } from \"@apollo/client\";\nimport { useMutation, useQuery } from \"@apollo/client/react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { useParams, useSearchParams } from \"react-router-dom\";\nimport {\n AppWindow,\n Key,\n Webhook,\n BarChart3,\n Plus,\n ExternalLink,\n MoreHorizontal,\n Loader2,\n AlertCircle,\n CheckCircle,\n CheckCircle2,\n Clock,\n Shield,\n RefreshCw,\n Edit,\n XCircle,\n Power,\n Users,\n Store,\n FlaskConical,\n Download,\n Upload,\n Info,\n X,\n SendHorizontal,\n} from \"lucide-react\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport {\n InputField,\n TextareaField,\n SelectField,\n} from \"../components/FormField\";\nimport {\n StatusBadge,\n VerifiedBadge,\n FeaturedBadge,\n} from \"../components/StatusBadge\";\nimport { DataTable, DetailList } from \"../components/DataTable\";\nimport { NewSecretAlert } from \"../components/SecretDisplay\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { LoadingState } from \"../components/LoadingState\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { SelectionCheckbox } from \"../components/SelectionCheckbox\";\nimport { GrantDelegationModal } from \"../components/GrantDelegationModal\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { usePackageUpload } from \"../hooks/usePackageUpload\";\nimport { nativeNotify } from \"../../utils/nativeBridge\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalPermission } from \"../hooks/usePermission\";\nimport type {\n Application,\n ApplicationVersion,\n Webhook as WebhookType,\n ApplicationAnalytics,\n AppUserDelegation,\n DelegationStatus,\n} from \"../types\";\nimport { cn } from \"../utils/cn\";\nimport { APP_TYPE_LABELS } from \"../utils/constants\";\nimport {\n useGetApplicationQuery,\n useGetWebhooksQuery,\n useGetApplicationAnalyticsQuery,\n useCurrentUserDelegationsQuery,\n useDeactivateAppMutation,\n useRotateAppSecretMutation,\n useRevokeDelegationMutation,\n useUpdateApplicationMutation,\n useInstallApplicationMutation,\n useUninstallApplicationMutation,\n useGetWorkspaceInstallationQuery,\n useSubmitApplicationMutation,\n useGetStoreInstallationsQuery,\n useGetMyPublisherQuery,\n useGetPublisherProductsQuery,\n type ApplicationScopeFieldsFragment,\n} from \"../../generated/global-operations\";\n\n// =============================================================================\n// HELPERS\n// =============================================================================\n\n/** Safely map GraphQL response to Application type */\nfunction mapToApplication(\n data: NonNullable<\n ReturnType<typeof useGetApplicationQuery>[\"data\"]\n >[\"application\"],\n): Application | null {\n if (!data) return null;\n return {\n id: data.id,\n name: data.name,\n slug: data.slug,\n shortDescription: data.shortDescription || undefined,\n description: data.description || undefined,\n appType: data.appType,\n status: data.status,\n visibility: data.visibility,\n tenantId: data.tenantId,\n developerId: data.developerId,\n developerOrganizationId: data.developerOrganizationId || undefined,\n category: data.category || undefined,\n tags: data.tags || [],\n keywords: data.keywords || [],\n iconUrl: data.iconUrl || undefined,\n bannerUrl: data.bannerUrl || undefined,\n videoUrl: data.videoUrl || undefined,\n screenshots: data.screenshots ?? undefined,\n websiteUrl: data.websiteUrl || undefined,\n documentationUrl: data.documentationUrl || undefined,\n supportUrl: data.supportUrl || undefined,\n privacyPolicyUrl: data.privacyPolicyUrl || undefined,\n termsOfServiceUrl: data.termsOfServiceUrl || undefined,\n githubUrl: data.githubUrl || undefined,\n pricingType: data.pricingType || undefined,\n pricingDetails: data.pricingDetails ?? undefined,\n manifest: data.manifest ?? undefined,\n reviewNotes: data.reviewNotes || undefined,\n reviewedBy: data.reviewedBy || undefined,\n installCount: data.installCount,\n activeInstallCount: data.activeInstallCount,\n averageRating: data.averageRating ?? undefined,\n reviewCount: data.reviewCount,\n submittedAt: data.submittedAt || undefined,\n publishedAt: data.publishedAt || undefined,\n lastReviewedAt: data.lastReviewedAt || undefined,\n reviewStatus: data.reviewStatus,\n isFeatured: data.isFeatured,\n isVerified: data.isVerified,\n requiresApproval: data.requiresApproval,\n appId: data.appId || undefined,\n scopes: data.scopes?.map((s: ApplicationScopeFieldsFragment) => ({\n id: s.id,\n applicationId: s.applicationId,\n scope: s.scope,\n description: s.description || undefined,\n isRequired: s.isRequired,\n createdAt: s.createdAt,\n })),\n versions: (data.versions?.edges as Array<{ node: ApplicationVersion }> | undefined)?.map((e) => e.node),\n createdAt: data.createdAt,\n updatedAt: data.updatedAt,\n };\n}\n\n/**\n * Note: OAuth client and API key mappers removed.\n * OAuth apps and API keys are now managed centrally via auth-svc\n * (see /oauth and /api-keys routes).\n */\n\n/** Map GraphQL webhook response to local Webhook type */\nfunction mapToWebhook(\n gqlWebhook: NonNullable<\n ReturnType<typeof useGetWebhooksQuery>[\"data\"]\n >[\"webhooks\"][number],\n): WebhookType {\n return {\n id: gqlWebhook.id,\n applicationId: gqlWebhook.applicationId,\n name: gqlWebhook.name,\n description: gqlWebhook.description || undefined,\n url: gqlWebhook.url,\n secret: gqlWebhook.secret,\n events: gqlWebhook.events,\n isActive: gqlWebhook.isActive,\n status: gqlWebhook.status,\n maxRetries: gqlWebhook.maxRetries,\n retryDelay: gqlWebhook.retryDelay,\n retryEnabled: gqlWebhook.retryEnabled,\n lastTriggeredAt: gqlWebhook.lastTriggeredAt || undefined,\n lastSuccessAt: gqlWebhook.lastSuccessAt || undefined,\n lastFailureAt: gqlWebhook.lastFailureAt || undefined,\n lastFailureReason: gqlWebhook.lastFailureReason || undefined,\n failureCount: gqlWebhook.failureCount,\n successCount: gqlWebhook.successCount,\n createdAt: gqlWebhook.createdAt,\n updatedAt: gqlWebhook.updatedAt,\n };\n}\n\n/** Map GraphQL analytics response to local ApplicationAnalytics type */\nfunction mapToAnalytics(\n gqlAnalytics: NonNullable<\n ReturnType<typeof useGetApplicationAnalyticsQuery>[\"data\"]\n >[\"applicationAnalytics\"][number],\n): ApplicationAnalytics {\n return {\n id: gqlAnalytics.id,\n applicationId: gqlAnalytics.applicationId,\n date: gqlAnalytics.date,\n period: gqlAnalytics.period,\n apiCalls: gqlAnalytics.apiCalls,\n errors: gqlAnalytics.errors,\n sessions: gqlAnalytics.sessions,\n activeUsers: gqlAnalytics.activeUsers,\n newUsers: gqlAnalytics.newUsers,\n avgResponseTime: gqlAnalytics.avgResponseTime ?? undefined,\n avgSessionDuration: gqlAnalytics.avgSessionDuration ?? undefined,\n createdAt: gqlAnalytics.createdAt,\n };\n}\n\n/** Map GraphQL delegation response to local AppUserDelegation type */\nfunction mapToDelegation(\n gqlDelegation: NonNullable<\n ReturnType<typeof useCurrentUserDelegationsQuery>[\"data\"]\n >[\"currentUserDelegations\"][number],\n): AppUserDelegation {\n return {\n id: gqlDelegation.id,\n appId: gqlDelegation.appId,\n app: {\n id: gqlDelegation.app.id,\n name: gqlDelegation.app.name,\n description: gqlDelegation.app.description || undefined,\n type: gqlDelegation.app.type,\n status: gqlDelegation.app.status,\n },\n userId: gqlDelegation.userId,\n scopes: gqlDelegation.scopes,\n workspaceIds: gqlDelegation.workspaceIds ?? [],\n status: gqlDelegation.status as DelegationStatus,\n grantedAt: gqlDelegation.grantedAt,\n grantedBy: gqlDelegation.grantedBy,\n expiresAt: gqlDelegation.expiresAt || undefined,\n revokedAt: gqlDelegation.revokedAt || undefined,\n revokedBy: gqlDelegation.revokedBy || undefined,\n };\n}\n\n// =============================================================================\n// TAB DEFINITIONS\n// =============================================================================\n\ntype TabId =\n | \"overview\"\n | \"permissions\"\n | \"webhooks\"\n | \"delegations\"\n | \"analytics\"\n | \"playground\"\n | \"store-listing\";\n\nconst tabs: Array<{ id: TabId; label: string; icon: FC<{ size?: number }> }> = [\n { id: \"overview\", label: \"Overview\", icon: AppWindow },\n { id: \"permissions\", label: \"Permissions\", icon: Shield },\n { id: \"webhooks\", label: \"Webhooks\", icon: Webhook },\n { id: \"delegations\", label: \"Delegations\", icon: Users },\n { id: \"analytics\", label: \"Analytics\", icon: BarChart3 },\n { id: \"playground\", label: \"API Playground\", icon: ExternalLink },\n { id: \"store-listing\", label: \"Marketplace Listing\", icon: Store },\n];\n\n// =============================================================================\n// DELEGATION STATUS HELPERS\n// =============================================================================\n\nconst DELEGATION_STATUS_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-secondary\",\n};\n\n// =============================================================================\n// TAB LOADING SPINNER\n// =============================================================================\n\nconst TabLoadingSpinner: FC<{ message?: string }> = ({\n message = \"Loading...\",\n}) => (\n <div className=\"flex items-center justify-center gap-3 py-12\">\n <Loader2 size={20} className=\"animate-spin text-muted-foreground\" />\n <p className=\"text-sm text-muted-foreground\">{message}</p>\n </div>\n);\n\nconst TabErrorState: FC<{ message: string }> = ({ message }) => (\n <div className=\"flex flex-col items-center justify-center gap-2 py-12 text-center\">\n <AlertCircle size={32} className=\"text-destructive\" />\n <p className=\"text-sm text-muted-foreground\">{message}</p>\n </div>\n);\n\n// =============================================================================\n// MAIN PAGE COMPONENT\n// =============================================================================\n\n/**\n * Application detail page with tabbed navigation\n */\nexport const ApplicationDetailPage: FC = () => {\n const { navigate, basePath, workspaceId } = 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 { allowed: canUpdate } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_UPDATE,\n );\n const { allowed: canDelete } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_DELETE,\n );\n const { appId } = useParams<{ appId: string }>();\n const [searchParams, setSearchParams] = useSearchParams();\n const VALID_TABS: TabId[] = [\"overview\",\"permissions\",\"webhooks\",\"delegations\",\"analytics\",\"playground\",\"store-listing\"];\n const tabParam = searchParams.get(\"tab\") as TabId | null;\n const [activeTab, setActiveTab] = useState<TabId>(\n tabParam && VALID_TABS.includes(tabParam) ? tabParam : \"overview\",\n );\n\n // Sync state when the URL param changes (e.g. navigating via a link on the same mounted page)\n useEffect(() => {\n if (tabParam && VALID_TABS.includes(tabParam) && tabParam !== activeTab) {\n setActiveTab(tabParam);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [tabParam]);\n\n const handleTabChange = (tab: TabId) => {\n setActiveTab(tab);\n setSearchParams((prev) => { prev.set(\"tab\", tab); return prev; }, { replace: true });\n };\n\n // ---- Dialogs ----\n const [showRotateSecretDialog, setShowRotateSecretDialog] = useState(false);\n const [showDeactivateDialog, setShowDeactivateDialog] = useState(false);\n const [newSecret, setNewSecret] = useState<string | null>(null);\n const [showDelegationModal, setShowDelegationModal] = useState(false);\n\n // ---- Application query ----\n const { data, loading, error } = useGetApplicationQuery({\n variables: { id: appId! },\n skip: !appId,\n });\n\n // ---- Mutations ----\n const [rotateAppSecret, { loading: rotateLoading }] =\n useRotateAppSecretMutation();\n const [deactivateApp, { loading: deactivateLoading }] =\n useDeactivateAppMutation();\n const [installApplication, { loading: installLoading }] =\n useInstallApplicationMutation();\n const [uninstallApplication, { loading: uninstallLoading }] =\n useUninstallApplicationMutation();\n\n // ---- Workspace installation status ----\n const { data: installationData, refetch: refetchInstallation } =\n useGetWorkspaceInstallationQuery({\n variables: {\n applicationId: appId,\n workspaceId: workspaceId ?? undefined,\n },\n skip: !workspaceId || !appId,\n fetchPolicy: \"cache-and-network\",\n });\n const activeInstallation =\n installationData?.appInstallations?.edges?.[0]?.node ?? null;\n\n const handleNavigate = useCallback(\n (path: string) => {\n navigate?.(`${basePath}${path}`);\n },\n [navigate, basePath],\n );\n\n // ---- Rotate Secret ----\n const handleRotateSecret = useCallback(async () => {\n const authAppId = data?.application?.appId;\n if (!authAppId) return;\n try {\n const result = await rotateAppSecret({ variables: { id: authAppId } });\n const secret = result.data?.rotateAppSecret.clientSecret;\n if (secret) {\n setNewSecret(secret);\n }\n setShowRotateSecretDialog(false);\n } catch {\n // Error is displayed via Apollo error state\n }\n }, [data?.application?.appId, rotateAppSecret]);\n\n // ---- Deactivate App ----\n const handleDeactivateApp = useCallback(async () => {\n if (!appId) return;\n try {\n await deactivateApp({ variables: { id: appId } });\n setShowDeactivateDialog(false);\n handleNavigate(\"/apps\");\n } catch {\n // Error is displayed via Apollo error state\n }\n }, [appId, deactivateApp, handleNavigate]);\n\n // ---- Test in Workspace ----\n const handleTestInWorkspace = useCallback(async () => {\n if (!appId || !workspaceId) return;\n try {\n await installApplication({\n variables: {\n input: {\n applicationId: appId,\n scope: \"WORKSPACE\" as const,\n workspaceId,\n autoUpdate: false,\n },\n },\n });\n void refetchInstallation();\n void nativeNotify(\"success\");\n } catch (err) {\n console.error(\"[DevPortal] Test in Workspace failed:\", err);\n void nativeNotify(\"error\");\n }\n }, [appId, workspaceId, installApplication, refetchInstallation]);\n\n // ---- Uninstall from Workspace ----\n const handleUninstall = useCallback(\n async (installationId: string) => {\n try {\n await uninstallApplication({ variables: { id: installationId } });\n void refetchInstallation();\n void nativeNotify(\"success\");\n } catch {\n void nativeNotify(\"error\");\n }\n },\n [uninstallApplication, refetchInstallation],\n );\n\n // ---- Loading / Error / Not Found ----\n // Only show full-page loading on initial load (no cached data yet).\n // With cache-and-network, Apollo sets loading:true on background refetches even\n // when data is already in cache — guarding on !data prevents StoreListingTab\n // (and other tab panels) from unmounting and losing their local form state.\n if (loading && !data) {\n return (\n <LoadingState\n message={tr(\"devportal.loadingApplication\", \"Loading application...\")}\n />\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title={tr(\"devportal.error\", \"Error\")}\n backLink={`${basePath}/apps`}\n backLabel={tr(\"devportal.backToApplications\", \"Back to Applications\")}\n >\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <AlertCircle size={48} className=\"text-destructive mb-4\" />\n <h3 className=\"text-lg font-semibold mb-2\">\n {tr(\n \"devportal.failedToLoadApplication\",\n \"Failed to load application\",\n )}\n </h3>\n <p className=\"text-sm text-muted-foreground\">{error.message}</p>\n </div>\n </PageLayout>\n );\n }\n\n const app = mapToApplication(data?.application);\n\n if (!app) {\n return (\n <PageLayout\n title={tr(\"devportal.notFound\", \"Not Found\")}\n backLink={`${basePath}/apps`}\n backLabel={tr(\"devportal.backToApplications\", \"Back to Applications\")}\n >\n <EmptyState\n icon={<AppWindow size={48} />}\n title={tr(\"devportal.applicationNotFound\", \"Application not found\")}\n description={tr(\n \"devportal.applicationNotFoundDescription\",\n \"The application you're looking for doesn't exist or you don't have access to it.\",\n )}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={app.name}\n description={app.shortDescription}\n backLink={`${basePath}/apps`}\n backLabel={tr(\"devportal.backToApplications\", \"Back to Applications\")}\n actions={\n <div className=\"flex items-center gap-2\">\n {app.appType !== \"NODE\" && app.appType !== \"WORKFLOW\" && (\n <button\n onClick={() => setShowRotateSecretDialog(true)}\n disabled={!app.appId}\n title={\n app.appId\n ? tr(\n \"devportal.rotateSecretHint\",\n \"Generate a new client secret\",\n )\n : tr(\n \"devportal.rotateSecretNoClient\",\n \"Create an OAuth client first to enable secret rotation\",\n )\n }\n className=\"inline-flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <RefreshCw size={16} />\n {tr(\"devportal.rotateSecret\", \"Rotate Secret\")}\n </button>\n )}\n <button\n onClick={() => handleNavigate(`/apps/${app.id}/versions`)}\n className=\"inline-flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted transition-colors\"\n >\n <Clock size={16} />\n {tr(\"devportal.versions\", \"Versions\")}\n </button>\n {app.status !== \"PUBLISHED\" && (\n <button\n onClick={() => handleNavigate(`/apps/${app.id}/publish`)}\n className=\"inline-flex items-center gap-2 rounded-md border border-primary/40 px-4 py-2 text-sm font-medium text-primary hover:bg-primary/10 transition-colors\"\n >\n <SendHorizontal size={16} />\n {tr(\"devportal.submitForReview\", \"Submit for Review\")}\n </button>\n )}\n {app.appType !== \"NODE\" &&\n app.appType !== \"WORKFLOW\" &&\n (activeInstallation ? (\n <button\n onClick={() => void handleUninstall(activeInstallation.id)}\n disabled={uninstallLoading || !workspaceId}\n title={tr(\n \"devportal.uninstallFromWorkspace\",\n \"Uninstall this app from your current workspace\",\n )}\n className=\"inline-flex items-center gap-2 rounded-md border border-destructive/50 px-4 py-2 text-sm font-medium text-destructive hover:bg-destructive/10 transition-colors disabled:opacity-50\"\n >\n {uninstallLoading ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : (\n <XCircle size={16} />\n )}\n {tr(\n \"devportal.uninstallFromWorkspace\",\n \"Uninstall from Workspace\",\n )}\n </button>\n ) : (\n <button\n onClick={() => void handleTestInWorkspace()}\n disabled={installLoading || !workspaceId}\n aria-disabled={!workspaceId}\n title={\n workspaceId\n ? tr(\n \"devportal.testInWorkspaceHint\",\n \"Install this app into your current workspace to test it\",\n )\n : tr(\n \"devportal.noWorkspaceContext\",\n \"No workspace context available\",\n )\n }\n className=\"inline-flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted transition-colors disabled:opacity-50\"\n >\n {installLoading ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : (\n <FlaskConical size={16} />\n )}\n {tr(\"devportal.testInWorkspace\", \"Test in Workspace\")}\n </button>\n ))}\n {app.appType === \"NODE\" && (\n <button\n onClick={() =>\n navigate?.(`/workflows/new?nodeId=${app.id}`)\n }\n disabled={!workspaceId}\n aria-disabled={!workspaceId}\n title={\n workspaceId\n ? tr(\n \"devportal.testInWorkflowBuilderHint\",\n \"Open a new workflow with this node available in the builder\",\n )\n : tr(\n \"devportal.noWorkspaceContext\",\n \"No workspace context available\",\n )\n }\n className=\"inline-flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted transition-colors disabled:opacity-50\"\n >\n <FlaskConical size={16} />\n {tr(\n \"devportal.testInWorkflowBuilder\",\n \"Test in Workflow Builder\",\n )}\n </button>\n )}\n <button\n onClick={() => handleNavigate(`/apps/${app.id}/edit`)}\n disabled={!canUpdate}\n aria-disabled={!canUpdate}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n <Edit size={16} />\n {tr(\"devportal.editApp\", \"Edit App\")}\n </button>\n <button\n onClick={() => setShowDeactivateDialog(true)}\n disabled={!canDelete}\n aria-disabled={!canDelete}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle transition-colors disabled:opacity-50\"\n >\n <Power size={16} />\n {tr(\"devportal.deactivate\", \"Deactivate\")}\n </button>\n </div>\n }\n >\n {/* New Secret Alert (shown after rotation) */}\n {newSecret && (\n <NewSecretAlert\n title={tr(\n \"devportal.newAppSecretGenerated\",\n \"New App Secret Generated\",\n )}\n secret={newSecret}\n description={tr(\n \"devportal.appSecretRotatedDescription\",\n \"Your app secret has been rotated. The old secret is no longer valid.\",\n )}\n onDismiss={() => setNewSecret(null)}\n />\n )}\n\n {/* Status badges */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge status={app.status} type=\"app\" />\n <StatusBadge status={app.visibility} type=\"app\" />\n {app.isVerified && <VerifiedBadge verified />}\n {app.isFeatured && <FeaturedBadge />}\n <span className=\"text-sm text-muted-foreground\">\n {APP_TYPE_LABELS[app.appType] || app.appType}\n </span>\n </div>\n\n {/* Tabs */}\n <div className=\"border-b\">\n <nav\n className=\"-mb-px flex gap-4 overflow-x-auto\"\n role=\"tablist\"\n aria-label={tr(\n \"devportal.applicationSections\",\n \"Application sections\",\n )}\n >\n {tabs\n .filter((tab) => {\n const isPackageType =\n app.appType === \"NODE\" || app.appType === \"WORKFLOW\";\n if (\n isPackageType &&\n (tab.id === \"permissions\" ||\n tab.id === \"webhooks\" ||\n tab.id === \"delegations\" ||\n tab.id === \"playground\")\n ) {\n return false;\n }\n return true;\n })\n .map((tab) => {\n const Icon = tab.icon;\n return (\n <button\n key={tab.id}\n id={`application-tab-${tab.id}`}\n role=\"tab\"\n aria-selected={activeTab === tab.id}\n aria-controls={`application-panel-${tab.id}`}\n onClick={() => handleTabChange(tab.id)}\n className={cn(\n \"flex items-center gap-2 border-b-2 px-1 py-3 text-sm font-medium transition-colors\",\n activeTab === tab.id\n ? \"border-primary text-primary\"\n : \"border-transparent text-muted-foreground hover:text-foreground hover:border-muted-foreground\",\n )}\n >\n <Icon size={16} />\n {tab.label}\n </button>\n );\n })}\n </nav>\n </div>\n\n {/* Tab content */}\n <div\n className=\"mt-6\"\n id={`application-panel-${activeTab}`}\n role=\"tabpanel\"\n aria-labelledby={`application-tab-${activeTab}`}\n tabIndex={0}\n >\n {activeTab === \"overview\" && <OverviewTab app={app} />}\n {activeTab === \"permissions\" && <PermissionsTab app={app} />}\n {activeTab === \"webhooks\" && (\n <WebhooksTabConnected appId={app.id} onNavigate={handleNavigate} />\n )}\n {activeTab === \"delegations\" && (\n <DelegationsTabConnected\n authAppId={app.appId || undefined}\n appName={app.name}\n onGrantDelegation={() => setShowDelegationModal(true)}\n onNavigate={handleNavigate}\n />\n )}\n {activeTab === \"analytics\" && <AnalyticsTabConnected app={app} />}\n {activeTab === \"playground\" && <ApiPlaygroundTab app={app} />}\n {activeTab === \"store-listing\" && <StoreListingTab app={app} />}\n </div>\n\n {/* Rotate Secret Confirmation */}\n <ConfirmDialog\n open={showRotateSecretDialog}\n onOpenChange={setShowRotateSecretDialog}\n onConfirm={handleRotateSecret}\n title={tr(\"devportal.rotateAppSecret\", \"Rotate App Secret\")}\n description={tr(\n \"devportal.rotateAppSecretDescription\",\n \"This will generate a new client secret and invalidate the current one. All existing integrations using the old secret will stop working immediately.\",\n )}\n confirmLabel={tr(\"devportal.rotateSecret\", \"Rotate Secret\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"warning\"\n loading={rotateLoading}\n />\n\n {/* Deactivate App Confirmation */}\n <ConfirmDialog\n open={showDeactivateDialog}\n onOpenChange={setShowDeactivateDialog}\n onConfirm={handleDeactivateApp}\n title={tr(\"devportal.deactivateApplication\", \"Deactivate Application\")}\n description={tr(\n \"devportal.deactivateApplicationDescription\",\n \"This will deactivate the application. All OAuth clients, API keys, and webhooks associated with this app will stop functioning. This action can be reversed by reactivating the app.\",\n )}\n confirmLabel={tr(\"devportal.deactivate\", \"Deactivate\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"destructive\"\n loading={deactivateLoading}\n />\n\n {/* Grant Delegation Modal */}\n <GrantDelegationModal\n open={showDelegationModal}\n onOpenChange={setShowDelegationModal}\n appId={app.appId || \"\"}\n appName={app.name}\n appScopes={app.scopes?.map((s) => s.scope) ?? []}\n onSuccess={() => {\n setShowDelegationModal(false);\n }}\n />\n </PageLayout>\n );\n};\n\n// =============================================================================\n// CONNECTED TAB WRAPPERS (data-fetching layer)\n// =============================================================================\n\n/**\n * OAuth tab — now links to centralized OAuth apps page (auth-svc).\n * Previously fetched devportal-svc OAuthClients per application.\n */\nconst OAuthTabConnected: FC<{\n appId: string;\n onNavigate: (path: string) => void;\n}> = ({ onNavigate }) => {\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=\"space-y-4 py-4 text-center\">\n <Shield className=\"mx-auto h-10 w-10 text-muted-foreground\" />\n <h3 className=\"font-medium\">{tr(\"devportal.oauthApps\", \"OAuth Apps\")}</h3>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n \"devportal.oauthAppsManagedCentrally\",\n \"OAuth apps are now managed centrally. Visit the OAuth Apps page to create and manage your apps.\",\n )}\n </p>\n <button\n onClick={() => onNavigate(\"/oauth\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors\"\n >\n <ExternalLink size={16} />\n {tr(\"devportal.manageOAuthApps\", \"Manage OAuth Apps\")}\n </button>\n </div>\n );\n};\n\n/**\n * API Keys tab — now links to centralized API keys page (auth-svc).\n * Previously fetched devportal-svc ApiKeys per application.\n */\nconst ApiKeysTabConnected: FC<{\n appId: string;\n onNavigate: (path: string) => void;\n}> = ({ onNavigate }) => {\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=\"space-y-4 py-4 text-center\">\n <Key className=\"mx-auto h-10 w-10 text-muted-foreground\" />\n <h3 className=\"font-medium\">{tr(\"devportal.apiKeys\", \"API Keys\")}</h3>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n \"devportal.apiKeysManagedCentrally\",\n \"API keys are now managed centrally. Visit the API Keys page to generate and manage your keys.\",\n )}\n </p>\n <button\n onClick={() => onNavigate(\"/api-keys\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors\"\n >\n <ExternalLink size={16} />\n {tr(\"devportal.manageApiKeys\", \"Manage API Keys\")}\n </button>\n </div>\n );\n};\n\n/** Webhooks tab with real data from useGetWebhooksQuery */\nconst WebhooksTabConnected: FC<{\n appId: string;\n onNavigate: (path: string) => void;\n}> = ({ appId, onNavigate }) => {\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 { data, loading, error } = useGetWebhooksQuery({\n variables: { applicationId: appId },\n });\n\n if (loading)\n return (\n <TabLoadingSpinner\n message={tr(\"devportal.loadingWebhooks\", \"Loading webhooks...\")}\n />\n );\n if (error) return <TabErrorState message={error.message} />;\n\n const webhooks = (data?.webhooks ?? []).map(mapToWebhook);\n\n return (\n <WebhooksTab appId={appId} webhooks={webhooks} onNavigate={onNavigate} />\n );\n};\n\n/** Delegations tab with real data from useCurrentUserDelegationsQuery */\nconst DelegationsTabConnected: FC<{\n authAppId?: string;\n appName: string;\n onGrantDelegation: () => void;\n onNavigate: (path: string) => void;\n}> = ({ authAppId, appName, onGrantDelegation, onNavigate }) => {\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 { data, loading, error, refetch } = useCurrentUserDelegationsQuery();\n const [revokeDelegation] = useRevokeDelegationMutation();\n const [revokeConfirmIds, setRevokeConfirmIds] = useState<string[]>([]);\n const [revokeLoading, setRevokeLoading] = useState(false);\n const [selectedDelegationIds, setSelectedDelegationIds] = useState<\n Set<string>\n >(new Set());\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n\n const appDelegations = useMemo((): AppUserDelegation[] => {\n if (!data?.currentUserDelegations?.delegations) return [];\n return data.currentUserDelegations.delegations\n .filter((d: { appId: string }) => d.appId === authAppId)\n .map(mapToDelegation);\n }, [authAppId, data]);\n\n const activeAppDelegations = useMemo(\n () => appDelegations.filter((delegation) => delegation.status === \"ACTIVE\"),\n [appDelegations],\n );\n const selectedActiveDelegations = useMemo(\n () =>\n activeAppDelegations.filter((delegation) =>\n selectedDelegationIds.has(delegation.id),\n ),\n [activeAppDelegations, selectedDelegationIds],\n );\n const allVisibleSelected =\n activeAppDelegations.length > 0 &&\n activeAppDelegations.every((delegation) =>\n selectedDelegationIds.has(delegation.id),\n );\n const partiallySelected =\n activeAppDelegations.some((delegation) =>\n selectedDelegationIds.has(delegation.id),\n ) && !allVisibleSelected;\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 activeAppDelegations.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 [activeAppDelegations],\n );\n\n const clearSelection = useCallback(() => {\n setSelectedDelegationIds(new Set());\n }, []);\n\n const handleRevoke = useCallback(\n async (delegationIds: string[]) => {\n setRevokeLoading(true);\n try {\n const results = await Promise.allSettled(\n delegationIds.map((delegationId) =>\n revokeDelegation({ variables: { id: delegationId } }),\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 delegationIds.forEach((delegationId) => next.delete(delegationId));\n return next;\n });\n setRevokeConfirmIds([]);\n refetch();\n } catch {\n // Error handled by Apollo\n } finally {\n setRevokeLoading(false);\n }\n },\n [revokeDelegation, refetch],\n );\n\n if (!authAppId) {\n return (\n <EmptyState\n icon={<Shield size={32} />}\n title={tr(\"devportal.linkAuthAppFirst\", \"Link an auth app first\")}\n description={tr(\n \"devportal.linkAuthAppFirstDescription\",\n \"Delegations are managed through auth apps. Create or link an auth app before granting app-as-user access.\",\n )}\n action={\n <button\n onClick={() => onNavigate(\"/oauth\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n <ExternalLink size={16} />\n {tr(\"devportal.manageOAuthApps\", \"Manage OAuth Apps\")}\n </button>\n }\n />\n );\n }\n\n if (loading)\n return (\n <TabLoadingSpinner\n message={tr(\"devportal.loadingDelegations\", \"Loading delegations...\")}\n />\n );\n if (error) return <TabErrorState message={error.message} />;\n\n return (\n <>\n {successMessage && (\n <div className=\"rounded-lg border border-border-subtle bg-status-success-bg-subtle p-3 text-sm text-status-success-text\">\n <div className=\"flex items-center justify-between gap-3\">\n <span>{successMessage}</span>\n <button\n onClick={() => setSuccessMessage(null)}\n className=\"text-status-success-text hover:text-status-success-text\"\n >\n {tr(\"devportal.dismiss\", \"Dismiss\")}\n </button>\n </div>\n </div>\n )}\n\n <DelegationsTab\n appName={appName}\n delegations={appDelegations}\n onGrantDelegation={onGrantDelegation}\n onRevokeDelegation={(id) => setRevokeConfirmIds([id])}\n selectedDelegationIds={selectedDelegationIds}\n onToggleSelectDelegation={toggleDelegationSelection}\n onToggleAllDelegations={toggleAllVisibleDelegations}\n onClearSelection={clearSelection}\n onRevokeSelected={() =>\n setRevokeConfirmIds(\n selectedActiveDelegations.map((delegation) => delegation.id),\n )\n }\n allVisibleSelected={allVisibleSelected}\n partiallySelected={partiallySelected}\n />\n\n <ConfirmDialog\n open={revokeConfirmIds.length > 0}\n onOpenChange={(open) => {\n if (!open) setRevokeConfirmIds([]);\n }}\n onConfirm={() => {\n if (revokeConfirmIds.length > 0) {\n handleRevoke(revokeConfirmIds);\n }\n }}\n title={\n revokeConfirmIds.length > 1\n ? tr(\"devportal.revokeDelegations\", \"Revoke Delegations\")\n : tr(\"devportal.revokeDelegation\", \"Revoke Delegation\")\n }\n description={\n revokeConfirmIds.length > 1\n ? tr(\n \"devportal.revokeMultipleDelegationsDescription\",\n `This will immediately revoke ${revokeConfirmIds.length} selected delegations.`,\n )\n : tr(\n \"devportal.revokeDelegationDescription\",\n \"This will immediately revoke the delegation. The app will no longer be able to act on your behalf with the selected permissions.\",\n )\n }\n confirmLabel={tr(\"devportal.revoke\", \"Revoke\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"destructive\"\n loading={revokeLoading}\n />\n </>\n );\n};\n\n/** Analytics tab with real data from useGetApplicationAnalyticsQuery */\nconst AnalyticsTabConnected: FC<{ app: Application }> = ({ app }) => {\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 isPackageType = app.appType === \"NODE\" || app.appType === \"WORKFLOW\";\n\n const now = useMemo(() => new Date(), []);\n const thirtyDaysAgo = useMemo(() => {\n const d = new Date(now);\n d.setDate(d.getDate() - 30);\n return d;\n }, [now]);\n\n // For NODE/WORKFLOW: two-step lookup — get publisherId, then fetch products to find linked StoreProduct\n const { data: publisherData } = useGetMyPublisherQuery({\n fetchPolicy: \"cache-first\",\n skip: !isPackageType,\n });\n const publisherId = publisherData?.myPublisher?.id ?? null;\n\n const { data: publisherProductsData } = useGetPublisherProductsQuery({\n variables: { publisherId: publisherId ?? \"\" },\n fetchPolicy: \"cache-first\",\n skip: !isPackageType || !publisherId,\n });\n const linkedStoreProductId = publisherProductsData?.products?.find(\n (p: { id: string; productId?: string | null }) => p.productId === app.id,\n )?.id ?? null;\n\n const { data: installData, loading: installLoading } = useGetStoreInstallationsQuery({\n variables: { productId: linkedStoreProductId ?? \"\" },\n skip: !isPackageType || !linkedStoreProductId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const { data, loading, error } = useGetApplicationAnalyticsQuery({\n variables: {\n applicationId: app.id,\n period: \"daily\",\n startDate: thirtyDaysAgo.toISOString(),\n endDate: now.toISOString(),\n },\n skip: isPackageType,\n });\n\n if (isPackageType) {\n type Installation = NonNullable<typeof installData>[\"productInstallations\"][\"items\"][number];\n const installations: Installation[] = installData?.productInstallations?.items ?? [];\n const totalInstalls = installData?.productInstallations?.total ?? 0;\n const activeInstalls = installations.filter((i: Installation) => i.status === \"ACTIVE\").length;\n\n if (installLoading && !installData) {\n return (\n <TabLoadingSpinner\n message={tr(\"devportal.loadingAnalytics\", \"Loading analytics...\")}\n />\n );\n }\n\n return (\n <div className=\"space-y-6\">\n <div className=\"grid gap-4 sm:grid-cols-4\">\n <StatCard\n label={tr(\"devportal.totalInstalls\", \"Total Installs\")}\n value={totalInstalls.toLocaleString()}\n />\n <StatCard\n label={tr(\"devportal.activeInstalls\", \"Active Installs\")}\n value={activeInstalls.toLocaleString()}\n />\n <StatCard\n label={tr(\"devportal.averageRating\", \"Average Rating\")}\n value={\n app.averageRating\n ? `${app.averageRating.toFixed(1)} ★`\n : tr(\"devportal.notAvailable\", \"N/A\")\n }\n />\n <StatCard\n label={tr(\"devportal.reviews\", \"Reviews\")}\n value={app.reviewCount.toString()}\n />\n </div>\n {installations.length > 0 && (\n <PageSection title={tr(\"devportal.installBreakdown\", \"Install Breakdown\")}>\n <DataTable\n data={installations}\n keyField=\"id\"\n columns={[\n {\n key: \"workspaceId\",\n header: tr(\"devportal.workspace\", \"Workspace\"),\n render: (item) => item.workspaceId,\n },\n {\n key: \"version\",\n header: tr(\"devportal.version\", \"Version\"),\n render: (item) => item.version ?? \"—\",\n },\n {\n key: \"status\",\n header: tr(\"devportal.status\", \"Status\"),\n render: (item) => item.status,\n },\n {\n key: \"installedAt\",\n header: tr(\"devportal.installedAt\", \"Installed\"),\n render: (item) =>\n new Date(item.installedAt).toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n }),\n },\n ]}\n />\n </PageSection>\n )}\n </div>\n );\n }\n\n if (loading)\n return (\n <TabLoadingSpinner\n message={tr(\"devportal.loadingAnalytics\", \"Loading analytics...\")}\n />\n );\n if (error) return <TabErrorState message={error.message} />;\n\n const analytics = (data?.applicationAnalytics ?? []).map(mapToAnalytics);\n\n return <AnalyticsTab analytics={analytics} />;\n};\n\n// =============================================================================\n// OVERVIEW TAB\n// =============================================================================\n\nconst OverviewTab: FC<{ app: Application }> = ({ app }) => {\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 { navigate, basePath } = useDevportal();\n const isPackageType = app.appType === \"NODE\" || app.appType === \"WORKFLOW\";\n const isDraft = app.status === \"DRAFT\";\n\n type SetupStep = { label: string; done: boolean; path: string; cta: string };\n const setupSteps: SetupStep[] = isDraft\n ? [\n {\n label: \"Store listing info (name, description, category)\",\n done: !!(app.shortDescription && app.category),\n path: `${basePath}/apps/${app.id}?tab=store-listing`,\n cta: \"Fill store listing →\",\n },\n {\n label: \"Privacy policy & terms of service URLs\",\n done: !!(app.privacyPolicyUrl && app.termsOfServiceUrl),\n path: `${basePath}/apps/${app.id}?tab=store-listing`,\n cta: \"Add legal links →\",\n },\n ...(isPackageType\n ? [\n {\n label:\n app.appType === \"WORKFLOW\"\n ? \"Create a version (manifest JSON)\"\n : \"Create a version (ZIP + manifest JSON)\",\n done: (app.versions?.length ?? 0) > 0,\n path: `${basePath}/apps/${app.id}/versions`,\n cta: \"Create version →\",\n },\n ]\n : []),\n {\n label: \"Submit for marketplace review\",\n done: false,\n path: `${basePath}/apps/${app.id}/publish`,\n cta: \"Submit for review →\",\n },\n ]\n : [];\n\n const pendingSteps = setupSteps.filter((s) => !s.done);\n const nextStep = pendingSteps[0];\n\n return (\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2 space-y-6\">\n {/* Setup progress banner for DRAFT apps */}\n {isDraft && nextStep && (\n <div className=\"rounded-lg border border-primary/30 bg-primary/5 p-4 space-y-3\">\n <div className=\"flex items-center justify-between\">\n <p className=\"font-semibold text-sm text-primary\">\n {tr(\"devportal.setupProgress\", \"Setup Progress\")} — {setupSteps.filter((s) => s.done).length}/{setupSteps.length} complete\n </p>\n <button\n onClick={() => navigate?.(`${basePath}/apps/${app.id}/publish`)}\n className=\"text-xs text-primary hover:underline font-medium\"\n >\n {tr(\"devportal.viewChecklist\", \"View full checklist →\")}\n </button>\n </div>\n <div className=\"space-y-1.5\">\n {setupSteps.map((step, i) => (\n <div key={i} className=\"flex items-center gap-2 text-sm\">\n {step.done ? (\n <CheckCircle2 size={14} className=\"text-status-success-text shrink-0\" />\n ) : (\n <div className=\"h-3.5 w-3.5 rounded-full border-2 border-muted-foreground/40 shrink-0\" />\n )}\n <span className={step.done ? \"line-through text-muted-foreground\" : \"text-foreground\"}>\n {step.label}\n </span>\n {!step.done && i === setupSteps.indexOf(nextStep) && (\n <button\n onClick={() => navigate?.(step.path)}\n className=\"ml-auto text-xs text-primary hover:underline font-medium shrink-0\"\n >\n {step.cta}\n </button>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n {/* Stats */}\n <div className=\"grid gap-4 sm:grid-cols-4\">\n <StatCard\n label={tr(\"devportal.totalInstalls\", \"Total Installs\")}\n value={app.installCount.toLocaleString()}\n />\n <StatCard\n label={tr(\"devportal.activeInstalls\", \"Active Installs\")}\n value={app.activeInstallCount.toLocaleString()}\n />\n <StatCard\n label={tr(\"devportal.averageRating\", \"Average Rating\")}\n value={\n app.averageRating\n ? `${app.averageRating.toFixed(1)} ★`\n : tr(\"devportal.notAvailable\", \"N/A\")\n }\n />\n <StatCard\n label={tr(\"devportal.reviews\", \"Reviews\")}\n value={app.reviewCount.toString()}\n />\n </div>\n\n {/* Description */}\n <PageSection title={tr(\"devportal.description\", \"Description\")}>\n <div className=\"prose prose-sm max-w-none\">\n <pre className=\"whitespace-pre-wrap font-sans text-sm text-foreground bg-transparent p-0 m-0\">\n {app.description ||\n tr(\n \"devportal.noDescriptionProvided\",\n \"No description provided.\",\n )}\n </pre>\n </div>\n </PageSection>\n\n {/* Tags & Keywords */}\n <PageSection title={tr(\"devportal.tagsAndKeywords\", \"Tags & Keywords\")}>\n <div className=\"space-y-3\">\n {app.tags.length > 0 && (\n <div>\n <p className=\"text-xs text-muted-foreground mb-2\">\n {tr(\"devportal.tags\", \"Tags\")}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {app.tags.map((tag) => (\n <span\n key={tag}\n className=\"rounded-full bg-primary/10 px-3 py-1 text-xs font-medium text-primary\"\n >\n {tag}\n </span>\n ))}\n </div>\n </div>\n )}\n {app.keywords.length > 0 && (\n <div>\n <p className=\"text-xs text-muted-foreground mb-2\">\n {tr(\"devportal.keywords\", \"Keywords\")}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {app.keywords.map((keyword) => (\n <span\n key={keyword}\n className=\"rounded-full bg-muted px-3 py-1 text-xs\"\n >\n {keyword}\n </span>\n ))}\n </div>\n </div>\n )}\n </div>\n </PageSection>\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-6\">\n <PageSection title={tr(\"devportal.details\", \"Details\")}>\n <DetailList\n items={[\n {\n label: tr(\"devportal.appId\", \"App ID\"),\n value: <code className=\"text-xs\">{app.id}</code>,\n },\n { label: tr(\"devportal.slug\", \"Slug\"), value: app.slug },\n {\n label: tr(\"devportal.category\", \"Category\"),\n value:\n app.category ||\n tr(\"devportal.uncategorized\", \"Uncategorized\"),\n },\n {\n label: tr(\"devportal.pricing\", \"Pricing\"),\n value: app.pricingType || tr(\"devportal.free\", \"Free\"),\n },\n {\n label: tr(\"devportal.created\", \"Created\"),\n value: new Date(app.createdAt).toLocaleDateString(),\n },\n {\n label: tr(\"devportal.updated\", \"Updated\"),\n value: new Date(app.updatedAt).toLocaleDateString(),\n },\n {\n label: tr(\"devportal.published\", \"Published\"),\n value: app.publishedAt\n ? new Date(app.publishedAt).toLocaleDateString()\n : tr(\"devportal.notPublished\", \"Not published\"),\n },\n ]}\n />\n </PageSection>\n\n <PageSection title={tr(\"devportal.links\", \"Links\")}>\n <div className=\"space-y-2\">\n {app.websiteUrl && (\n <LinkItem\n label={tr(\"devportal.website\", \"Website\")}\n url={app.websiteUrl}\n />\n )}\n {app.documentationUrl && (\n <LinkItem\n label={tr(\"devportal.documentation\", \"Documentation\")}\n url={app.documentationUrl}\n />\n )}\n {app.supportUrl && (\n <LinkItem\n label={tr(\"devportal.support\", \"Support\")}\n url={app.supportUrl}\n />\n )}\n {app.githubUrl && (\n <LinkItem\n label={tr(\"devportal.github\", \"GitHub\")}\n url={app.githubUrl}\n />\n )}\n {app.privacyPolicyUrl && (\n <LinkItem\n label={tr(\"devportal.privacyPolicy\", \"Privacy Policy\")}\n url={app.privacyPolicyUrl}\n />\n )}\n {app.termsOfServiceUrl && (\n <LinkItem\n label={tr(\"devportal.termsOfService\", \"Terms of Service\")}\n url={app.termsOfServiceUrl}\n />\n )}\n </div>\n </PageSection>\n </div>\n </div>\n );\n};\n\n// =============================================================================\n// OAUTH TAB\n// =============================================================================\n\n/**\n * Note: OAuthTab and ApiKeysTab presentation components removed.\n * OAuth apps and API keys are now managed centrally via auth-svc.\n * The connected wrappers above link to the /oauth and /api-keys pages.\n */\n\n// =============================================================================\n// WEBHOOKS TAB\n// =============================================================================\n\nconst WebhooksTab: FC<{\n appId: string;\n webhooks: WebhookType[];\n onNavigate: (path: string) => void;\n}> = ({ appId, webhooks, onNavigate }) => {\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=\"space-y-6\">\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm text-muted-foreground\">\n {webhooks.length}{\" \"}\n {webhooks.length !== 1\n ? tr(\"devportal.webhooks\", \"webhooks\")\n : tr(\"devportal.webhook\", \"webhook\")}{\" \"}\n {tr(\"devportal.configured\", \"configured\")}\n </p>\n <button\n onClick={() => onNavigate(`/apps/${appId}/webhooks/new`)}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.addWebhook\", \"Add Webhook\")}\n </button>\n </div>\n\n {webhooks.length > 0 ? (\n <div className=\"space-y-4\">\n {webhooks.map((webhook) => (\n <div\n key={webhook.id}\n className=\"rounded-lg border bg-card p-4 space-y-4\"\n >\n <div className=\"flex items-start justify-between\">\n <div>\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-medium\">{webhook.name}</h3>\n <StatusBadge status={webhook.status} type=\"webhook\" />\n </div>\n {webhook.description && (\n <p className=\"text-sm text-muted-foreground mt-1\">\n {webhook.description}\n </p>\n )}\n </div>\n <button\n onClick={() =>\n onNavigate(`/apps/${appId}/webhooks/${webhook.id}`)\n }\n className=\"rounded-md p-1 hover:bg-muted\"\n >\n <MoreHorizontal size={20} />\n </button>\n </div>\n\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">\n {tr(\"devportal.endpointUrl\", \"Endpoint URL\")}\n </p>\n <code className=\"text-sm bg-muted px-2 py-1 rounded block truncate\">\n {webhook.url}\n </code>\n </div>\n\n <div>\n <p className=\"text-xs text-muted-foreground mb-2\">\n {tr(\"devportal.events\", \"Events\")}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {webhook.events.map((event) => (\n <span\n key={event}\n className=\"rounded-full bg-muted px-2 py-0.5 text-xs\"\n >\n {event}\n </span>\n ))}\n </div>\n </div>\n\n <div className=\"grid gap-4 sm:grid-cols-4 text-sm\">\n <div>\n <p className=\"text-xs text-muted-foreground\">\n {tr(\"devportal.success\", \"Success\")}\n </p>\n <p className=\"font-medium text-status-success-text\">\n {webhook.successCount.toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-muted-foreground\">\n {tr(\"devportal.failed\", \"Failed\")}\n </p>\n <p className=\"font-medium text-status-error-text\">\n {webhook.failureCount.toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-muted-foreground\">\n {tr(\"devportal.successRate\", \"Success Rate\")}\n </p>\n <p className=\"font-medium\">\n {webhook.successCount + webhook.failureCount > 0\n ? (\n (webhook.successCount /\n (webhook.successCount + webhook.failureCount)) *\n 100\n ).toFixed(1)\n : \"0.0\"}\n %\n </p>\n </div>\n <div>\n <p className=\"text-xs text-muted-foreground\">\n {tr(\"devportal.lastTriggered\", \"Last Triggered\")}\n </p>\n <p className=\"font-medium\">\n {webhook.lastTriggeredAt\n ? new Date(webhook.lastTriggeredAt).toLocaleString()\n : tr(\"devportal.never\", \"Never\")}\n </p>\n </div>\n </div>\n </div>\n ))}\n </div>\n ) : (\n <EmptyState\n icon={<Webhook size={32} />}\n title={tr(\"devportal.noWebhooks\", \"No webhooks\")}\n description={tr(\n \"devportal.noWebhooksDescription\",\n \"Add a webhook to receive event notifications\",\n )}\n action={\n <button\n onClick={() => onNavigate(`/apps/${appId}/webhooks/new`)}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.addWebhook\", \"Add Webhook\")}\n </button>\n }\n />\n )}\n </div>\n );\n};\n\n// =============================================================================\n// DELEGATIONS TAB\n// =============================================================================\n\nconst DelegationsTab: FC<{\n appName: string;\n delegations: AppUserDelegation[];\n onGrantDelegation: () => void;\n onRevokeDelegation: (id: string) => void;\n selectedDelegationIds: Set<string>;\n onToggleSelectDelegation: (id: string, checked: boolean) => void;\n onToggleAllDelegations: (checked: boolean) => void;\n onClearSelection: () => void;\n onRevokeSelected: () => void;\n allVisibleSelected: boolean;\n partiallySelected: boolean;\n}> = ({\n appName,\n delegations,\n onGrantDelegation,\n onRevokeDelegation,\n selectedDelegationIds,\n onToggleSelectDelegation,\n onToggleAllDelegations,\n onClearSelection,\n onRevokeSelected,\n allVisibleSelected,\n partiallySelected,\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 const activeDelegations = delegations.filter((d) => d.status === \"ACTIVE\");\n const inactiveDelegations = delegations.filter((d) => d.status !== \"ACTIVE\");\n\n return (\n <div className=\"space-y-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {delegations.length}{\" \"}\n {delegations.length !== 1\n ? tr(\"devportal.delegations\", \"delegations\")\n : tr(\"devportal.delegation\", \"delegation\")}{\" \"}\n {tr(\"devportal.for\", \"for\")} {appName}\n </p>\n {activeDelegations.length > 0 && (\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {activeDelegations.length} {tr(\"devportal.active\", \"active\")},{\" \"}\n {inactiveDelegations.length}{\" \"}\n {tr(\"devportal.revokedExpired\", \"revoked/expired\")}\n </p>\n )}\n </div>\n <button\n onClick={onGrantDelegation}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.grantDelegation\", \"Grant Delegation\")}\n </button>\n </div>\n\n {activeDelegations.length > 0 && (\n <div className=\"rounded-lg border bg-card 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={onToggleAllDelegations}\n ariaLabel={tr(\n \"devportal.selectAllActiveDelegations\",\n \"Select all active app delegations\",\n )}\n />\n <span className=\"text-sm font-medium\">\n {tr(\"devportal.selectAllActive\", \"Select all active\")}\n </span>\n </div>\n {selectedDelegationIds.size > 0 && (\n <button\n onClick={onClearSelection}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\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-muted px-3 py-1 text-sm font-medium text-muted-foreground\">\n {selectedDelegationIds.size}{\" \"}\n {tr(\"devportal.selected\", \"selected\")}\n </span>\n <button\n onClick={onRevokeSelected}\n disabled={selectedDelegationIds.size === 0}\n className=\"rounded-md border border-status-error-bg px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.revokeSelected\", \"Revoke Selected\")}\n {selectedDelegationIds.size > 0\n ? ` (${selectedDelegationIds.size})`\n : \"\"}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {delegations.length > 0 ? (\n <div className=\"space-y-4\">\n {delegations.map((delegation) => (\n <div\n key={delegation.id}\n className=\"rounded-lg border bg-card p-4 space-y-4\"\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-start gap-3\">\n {delegation.status === \"ACTIVE\" && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selectedDelegationIds.has(delegation.id)}\n onChange={(checked) =>\n onToggleSelectDelegation(delegation.id, checked)\n }\n ariaLabel={`Select delegation ${delegation.id}`}\n className=\"mt-1\"\n />\n </div>\n )}\n <div>\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-medium\">\n Delegation #{delegation.id.slice(0, 8)}\n </h3>\n <span\n className={cn(\n \"rounded-full px-2 py-0.5 text-xs font-medium\",\n DELEGATION_STATUS_STYLES[delegation.status],\n )}\n >\n {delegation.status}\n </span>\n </div>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {tr(\"devportal.granted\", \"Granted\")}{\" \"}\n {new Date(delegation.grantedAt).toLocaleDateString()}{\" \"}\n {tr(\"devportal.by\", \"by\")}{\" \"}\n {delegation.grantedBy === delegation.userId\n ? tr(\"devportal.you\", \"you\")\n : delegation.grantedBy.slice(0, 8)}\n </p>\n </div>\n </div>\n {delegation.status === \"ACTIVE\" && (\n <button\n onClick={() => onRevokeDelegation(delegation.id)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-error-text hover:bg-status-error-bg-subtle transition-colors\"\n >\n <XCircle size={14} />\n {tr(\"devportal.revoke\", \"Revoke\")}\n </button>\n )}\n </div>\n\n {/* Scopes */}\n <div>\n <p className=\"text-xs text-muted-foreground mb-2\">\n {tr(\"devportal.grantedScopes\", \"Granted Scopes\")}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {delegation.scopes.map((scope) => (\n <span\n key={scope}\n className=\"rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-xs text-status-success-text\"\n >\n {scope}\n </span>\n ))}\n </div>\n </div>\n\n {/* Workspace IDs */}\n {delegation.workspaceIds.length > 0 && (\n <div>\n <p className=\"text-xs text-muted-foreground mb-2\">\n {tr(\"devportal.workspaceScope\", \"Workspace Scope\")}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {delegation.workspaceIds.map((wsId) => (\n <code\n key={wsId}\n className=\"rounded bg-muted px-2 py-0.5 text-xs\"\n >\n {wsId}\n </code>\n ))}\n </div>\n </div>\n )}\n\n {/* Metadata */}\n <div className=\"flex items-center gap-4 text-xs text-muted-foreground\">\n {delegation.expiresAt && (\n <span className=\"flex items-center gap-1\">\n <Clock size={12} />\n {tr(\"devportal.expires\", \"Expires\")}{\" \"}\n {new Date(delegation.expiresAt).toLocaleDateString()}\n </span>\n )}\n {!delegation.expiresAt && delegation.status === \"ACTIVE\" && (\n <span className=\"flex items-center gap-1\">\n <CheckCircle\n size={12}\n className=\"text-status-success-text\"\n />\n {tr(\"devportal.noExpiration\", \"No expiration\")}\n </span>\n )}\n {delegation.revokedAt && (\n <span className=\"flex items-center gap-1\">\n <XCircle size={12} className=\"text-status-error-text\" />\n {tr(\"devportal.revoked\", \"Revoked\")}{\" \"}\n {new Date(delegation.revokedAt).toLocaleDateString()}\n </span>\n )}\n </div>\n </div>\n ))}\n </div>\n ) : (\n <EmptyState\n icon={<Users size={32} />}\n title={tr(\"devportal.noDelegations\", \"No delegations\")}\n description={tr(\n \"devportal.noDelegationsDescription\",\n \"Grant a delegation to allow this app to act on your behalf\",\n )}\n action={\n <button\n onClick={onGrantDelegation}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.grantDelegation\", \"Grant Delegation\")}\n </button>\n }\n />\n )}\n </div>\n );\n};\n\n// =============================================================================\n// ANALYTICS TAB\n// =============================================================================\n\nconst AnalyticsTab: FC<{ analytics: ApplicationAnalytics[] }> = ({\n analytics,\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 const latest = analytics[0];\n const previous = analytics[1];\n\n const calculateTrend = (current: number, prev: number) => {\n if (!prev) return 0;\n return ((current - prev) / prev) * 100;\n };\n\n return (\n <div className=\"space-y-6\">\n {/* Summary Stats */}\n <div className=\"grid gap-4 sm:grid-cols-4\">\n <StatCard\n label={tr(\"devportal.activeUsers\", \"Active Users\")}\n value={latest?.activeUsers.toLocaleString() || \"0\"}\n trend={\n previous\n ? calculateTrend(latest.activeUsers, previous.activeUsers)\n : undefined\n }\n />\n <StatCard\n label={tr(\"devportal.apiCalls\", \"API Calls\")}\n value={latest ? `${(latest.apiCalls / 1000).toFixed(1)}K` : \"0\"}\n trend={\n previous\n ? calculateTrend(latest.apiCalls, previous.apiCalls)\n : undefined\n }\n />\n <StatCard\n label={tr(\"devportal.avgResponseTime\", \"Avg Response Time\")}\n value={\n latest?.avgResponseTime\n ? `${latest.avgResponseTime}ms`\n : tr(\"devportal.notAvailable\", \"N/A\")\n }\n trend={\n previous && latest?.avgResponseTime\n ? -calculateTrend(\n latest.avgResponseTime,\n previous.avgResponseTime || 1,\n )\n : undefined\n }\n />\n <StatCard\n label={tr(\"devportal.errorRate\", \"Error Rate\")}\n value={\n latest && latest.apiCalls > 0\n ? `${((latest.errors / latest.apiCalls) * 100).toFixed(2)}%`\n : \"0%\"\n }\n trend={\n previous && latest && latest.apiCalls > 0 && previous.apiCalls > 0\n ? -calculateTrend(\n latest.errors / latest.apiCalls,\n previous.errors / previous.apiCalls,\n )\n : undefined\n }\n />\n </div>\n\n {/* Daily breakdown */}\n <PageSection title={tr(\"devportal.dailyBreakdown\", \"Daily Breakdown\")}>\n {analytics.length > 0 ? (\n <DataTable\n data={analytics}\n keyField=\"id\"\n columns={[\n {\n key: \"date\",\n header: tr(\"devportal.date\", \"Date\"),\n render: (item) => new Date(item.date).toLocaleDateString(),\n },\n {\n key: \"activeUsers\",\n header: tr(\"devportal.activeUsers\", \"Active Users\"),\n render: (item) => item.activeUsers.toLocaleString(),\n },\n {\n key: \"newUsers\",\n header: tr(\"devportal.newUsers\", \"New Users\"),\n render: (item) => item.newUsers.toLocaleString(),\n },\n {\n key: \"apiCalls\",\n header: tr(\"devportal.apiCalls\", \"API Calls\"),\n render: (item) => item.apiCalls.toLocaleString(),\n },\n {\n key: \"errors\",\n header: tr(\"devportal.errors\", \"Errors\"),\n render: (item) => item.errors.toLocaleString(),\n },\n {\n key: \"avgResponseTime\",\n header: tr(\"devportal.avgResponse\", \"Avg Response\"),\n render: (item) =>\n item.avgResponseTime\n ? `${item.avgResponseTime}ms`\n : tr(\"devportal.notAvailable\", \"N/A\"),\n },\n {\n key: \"sessions\",\n header: tr(\"devportal.sessions\", \"Sessions\"),\n render: (item) => item.sessions.toLocaleString(),\n },\n ]}\n />\n ) : (\n <EmptyState\n icon={<BarChart3 size={32} />}\n title={tr(\"devportal.noAnalyticsData\", \"No analytics data\")}\n description={tr(\n \"devportal.noAnalyticsDataDescription\",\n \"Analytics data will appear here once the application starts receiving traffic.\",\n )}\n />\n )}\n </PageSection>\n </div>\n );\n};\n\n// =============================================================================\n// API PLAYGROUND TAB\n// =============================================================================\n\nconst SAMPLE_QUERY = `# Sample query - modify as needed\nquery IntrospectSchema {\n __schema {\n queryType { name }\n mutationType { name }\n types {\n name\n kind\n }\n }\n}`;\n\nconst ApiPlaygroundTab: FC<{ app: Application }> = ({ app }) => {\n const { apiGatewayUrl, workspacesGatewayUrl, authToken } = 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 [query, setQuery] = useState(SAMPLE_QUERY);\n const [variables, setVariables] = useState(\"{}\");\n const [response, setResponse] = useState<string>(\"\");\n const [loading, setLoading] = useState(false);\n const [endpoint, setEndpoint] = useState(\n `${apiGatewayUrl || \"https://gw-global.local.burdenoff.com\"}/global/graphql`,\n );\n const [bearerToken, setBearerToken] = useState(authToken || \"\");\n const [showAuthHelp, setShowAuthHelp] = useState(false);\n\n const handleExecute = useCallback(async () => {\n setLoading(true);\n setResponse(\"\");\n try {\n let parsedVars = {};\n try {\n parsedVars = JSON.parse(variables);\n } catch {\n setResponse(\n JSON.stringify({ error: \"Invalid JSON in variables\" }, null, 2),\n );\n setLoading(false);\n return;\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (bearerToken) {\n headers[\"Authorization\"] = `Bearer ${bearerToken}`;\n }\n\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ query, variables: parsedVars }),\n });\n\n const data = await res.json();\n setResponse(JSON.stringify(data, null, 2));\n } catch (err) {\n setResponse(\n JSON.stringify(\n { error: err instanceof Error ? err.message : \"Request failed\" },\n null,\n 2,\n ),\n );\n } finally {\n setLoading(false);\n }\n }, [query, variables, endpoint, bearerToken]);\n\n const handleAutoFillCredentials = useCallback(() => {\n if (authToken) {\n setBearerToken(authToken);\n }\n setShowAuthHelp(true);\n }, [authToken]);\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-lg font-semibold\">\n {tr(\"devportal.apiPlayground\", \"API Playground\")}\n </h3>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n \"devportal.apiPlaygroundDescription\",\n \"Test GraphQL APIs in the context of\",\n )}{\" \"}\n <strong>{app.name}</strong>\n {app.appId && (\n <span className=\"ml-1 text-xs text-muted-foreground\">\n (OAuth App: {app.appId.slice(0, 8)}...)\n </span>\n )}\n </p>\n </div>\n <button\n onClick={handleAutoFillCredentials}\n className=\"flex items-center gap-2 rounded-md border px-3 py-1.5 text-sm font-medium hover:bg-accent transition-colors\"\n >\n <Key size={14} />\n {tr(\"devportal.autoFillCredentials\", \"Auto-fill Credentials\")}\n </button>\n </div>\n\n {showAuthHelp && (\n <div className=\"rounded-lg border bg-status-info-bg-subtle p-4 text-sm space-y-2\">\n <p className=\"font-medium text-status-info-text\">\n {tr(\"devportal.authenticationGuide\", \"Authentication Guide\")}\n </p>\n <p className=\"text-status-info-text\">\n {tr(\n \"devportal.authenticationGuideText\",\n \"Your current session token has been filled in. For app-level authentication (Client Credentials flow), use the\",\n )}{\" \"}\n <strong>{tr(\"devportal.oauthClientsTab\", \"OAuth Clients\")}</strong>{\" \"}\n {tr(\n \"devportal.authenticationGuideText2\",\n \"tab to get the app's clientId and clientSecret, then call:\",\n )}\n </p>\n <pre className=\"rounded bg-status-info-bg-subtle p-2 text-xs overflow-x-auto text-status-info-text\">\n {`mutation {\n authenticateApp(input: {\n clientId: \"<your-client-id>\"\n clientSecret: \"<your-client-secret>\"\n scopes: []\n }) {\n accessToken\n tokenType\n expiresIn\n }\n}`}\n </pre>\n <p className=\"text-status-info-text\">\n {tr(\"devportal.useReturnedAccessToken\", \"Use the returned\")}{\" \"}\n <code className=\"bg-status-info-bg-subtle px-1 rounded\">\n accessToken\n </code>{\" \"}\n {tr(\"devportal.asBearerToken\", \"as the Bearer token below.\")}\n </p>\n <button\n onClick={() => setShowAuthHelp(false)}\n className=\"text-xs text-accent-blue hover:underline\"\n >\n {tr(\"devportal.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {/* Endpoint */}\n <div>\n <label className=\"block text-sm font-medium mb-1\">\n {tr(\"devportal.gatewayEndpoint\", \"Gateway Endpoint\")}\n </label>\n <div className=\"flex gap-2\">\n <input\n type=\"text\"\n value={endpoint}\n onChange={(e) => setEndpoint(e.target.value)}\n className=\"flex-1 rounded-md border px-3 py-2 text-sm font-mono bg-background\"\n />\n <select\n onChange={(e) => setEndpoint(e.target.value)}\n className=\"rounded-md border px-3 py-2 text-sm bg-background\"\n value={endpoint}\n >\n <option\n value={`${apiGatewayUrl || \"https://gw-global.local.burdenoff.com\"}/global/graphql`}\n >\n {tr(\"devportal.globalGateway\", \"Global Gateway\")}\n </option>\n <option\n value={`${workspacesGatewayUrl || \"https://gw-wspace.local.burdenoff.com\"}/workspaces/graphql`}\n >\n {tr(\"devportal.workspaceGateway\", \"Workspace Gateway\")}\n </option>\n </select>\n </div>\n </div>\n\n {/* Bearer Token */}\n <div>\n <label className=\"block text-sm font-medium mb-1\">\n {tr(\"devportal.bearerToken\", \"Bearer Token\")}\n </label>\n <input\n type=\"password\"\n value={bearerToken}\n onChange={(e) => setBearerToken(e.target.value)}\n placeholder={tr(\n \"devportal.pasteAccessToken\",\n \"Paste access token here...\",\n )}\n className=\"w-full rounded-md border px-3 py-2 text-sm font-mono bg-background\"\n />\n </div>\n\n {/* Query + Variables side by side */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium mb-1\">\n {tr(\"devportal.query\", \"Query\")}\n </label>\n <textarea\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n className=\"w-full h-64 rounded-md border px-3 py-2 text-sm font-mono bg-background resize-y\"\n spellCheck={false}\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">\n {tr(\"devportal.variablesJson\", \"Variables (JSON)\")}\n </label>\n <textarea\n value={variables}\n onChange={(e) => setVariables(e.target.value)}\n className=\"w-full h-64 rounded-md border px-3 py-2 text-sm font-mono bg-background resize-y\"\n spellCheck={false}\n />\n </div>\n </div>\n\n {/* Execute */}\n <button\n onClick={handleExecute}\n disabled={loading}\n className=\"flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n {loading ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : (\n <ExternalLink size={16} />\n )}\n {loading\n ? tr(\"devportal.executing\", \"Executing...\")\n : tr(\"devportal.executeQuery\", \"Execute Query\")}\n </button>\n\n {/* Response */}\n {response && (\n <div>\n <label className=\"block text-sm font-medium mb-1\">\n {tr(\"devportal.response\", \"Response\")}\n </label>\n <pre className=\"w-full max-h-96 overflow-auto rounded-md border bg-muted p-4 text-xs font-mono\">\n {response}\n </pre>\n </div>\n )}\n </div>\n );\n};\n\n// =============================================================================\n// IMAGE UPLOAD COMPONENTS\n// =============================================================================\n\ninterface ImageUploadFieldProps {\n label: string;\n value: string;\n onChange: (url: string) => void;\n hint?: string;\n accept?: string;\n aspectClass?: string; // tailwind class for the preview container ratio\n upload: (file: File) => Promise<{ downloadUrl: string }>;\n uploading: boolean;\n progress: number;\n error: string | null;\n}\n\nconst ImageUploadField: FC<ImageUploadFieldProps> = ({\n label,\n value,\n onChange,\n hint,\n accept = \"image/png,image/jpeg,image/webp,image/gif,image/svg+xml\",\n aspectClass = \"aspect-square\",\n upload,\n uploading,\n progress,\n error,\n}) => {\n const inputRef = useRef<HTMLInputElement>(null);\n\n const handleFile = useCallback(\n async (file: File) => {\n try {\n const result = await upload(file);\n onChange(result.downloadUrl);\n } catch {\n // error shown via error prop\n }\n },\n [upload, onChange],\n );\n\n return (\n <div className=\"space-y-1.5\">\n <label className=\"text-sm font-medium\">{label}</label>\n <div className=\"flex gap-3 items-start\">\n {/* Preview */}\n <div\n className={cn(\n \"relative shrink-0 w-20 rounded-lg border border-border bg-bg-sunken overflow-hidden flex items-center justify-center\",\n aspectClass,\n )}\n >\n {value ? (\n <img\n src={value}\n alt={label}\n className=\"w-full h-full object-cover\"\n />\n ) : (\n <Upload size={18} className=\"text-text-secondary opacity-40\" />\n )}\n {uploading && (\n <div className=\"absolute inset-0 bg-black/40 flex flex-col items-center justify-center gap-1\">\n <Loader2 size={14} className=\"animate-spin text-white\" />\n <span className=\"text-white text-xs\">{progress}%</span>\n </div>\n )}\n </div>\n {/* URL input + upload button */}\n <div className=\"flex-1 space-y-1.5\">\n <input\n type=\"url\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n placeholder=\"https://...\"\n className=\"w-full rounded-md border border-border bg-bg-input px-3 py-1.5 text-sm placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-primary/30\"\n />\n <input\n ref={inputRef}\n type=\"file\"\n accept={accept}\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) void handleFile(f);\n e.target.value = \"\";\n }}\n />\n <button\n type=\"button\"\n disabled={uploading}\n onClick={() => inputRef.current?.click()}\n className=\"inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-xs font-medium hover:bg-muted transition-colors disabled:opacity-50\"\n >\n <Upload size={11} />\n {uploading ? `Uploading… ${progress}%` : \"Upload image\"}\n </button>\n {error && <p className=\"text-xs text-status-error-text\">{error}</p>}\n </div>\n </div>\n {hint && <p className=\"text-xs text-text-secondary\">{hint}</p>}\n </div>\n );\n};\n\ninterface ScreenshotGalleryProps {\n urls: string[];\n onChange: (urls: string[]) => void;\n upload: (file: File) => Promise<{ downloadUrl: string }>;\n uploading: boolean;\n progress: number;\n error: string | null;\n}\n\nconst ScreenshotGallery: FC<ScreenshotGalleryProps> = ({\n urls,\n onChange,\n upload,\n uploading,\n progress,\n error,\n}) => {\n const inputRef = useRef<HTMLInputElement>(null);\n\n const handleFile = useCallback(\n async (file: File) => {\n try {\n const result = await upload(file);\n onChange([...urls, result.downloadUrl]);\n } catch {\n // error shown via error prop\n }\n },\n [upload, onChange, urls],\n );\n\n const remove = (idx: number) => {\n onChange(urls.filter((_, i) => i !== idx));\n };\n\n return (\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Screenshots</label>\n <div className=\"flex flex-wrap gap-3\">\n {urls.map((url, idx) => (\n <div\n key={idx}\n className=\"relative group w-36 aspect-video rounded-lg border border-border overflow-hidden bg-bg-sunken\"\n >\n <img\n src={url}\n alt={`Screenshot ${idx + 1}`}\n className=\"w-full h-full object-cover\"\n />\n <button\n type=\"button\"\n onClick={() => remove(idx)}\n className=\"absolute top-1 right-1 rounded-full bg-black/60 text-white p-0.5 opacity-0 group-hover:opacity-100 transition-opacity\"\n >\n <X size={12} />\n </button>\n </div>\n ))}\n {/* Upload slot */}\n <button\n type=\"button\"\n disabled={uploading}\n onClick={() => inputRef.current?.click()}\n className={cn(\n \"w-36 aspect-video rounded-lg border-2 border-dashed border-border flex flex-col items-center justify-center gap-1.5 text-text-secondary hover:border-border-strong hover:bg-bg-sunken transition-colors disabled:opacity-50\",\n )}\n >\n {uploading ? (\n <>\n <Loader2 size={18} className=\"animate-spin text-primary\" />\n <span className=\"text-xs\">{progress}%</span>\n </>\n ) : (\n <>\n <Upload size={18} />\n <span className=\"text-xs\">Add screenshot</span>\n </>\n )}\n </button>\n </div>\n <input\n ref={inputRef}\n type=\"file\"\n accept=\"image/png,image/jpeg,image/webp,image/gif\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) void handleFile(f);\n e.target.value = \"\";\n }}\n />\n {error && <p className=\"text-xs text-status-error-text\">{error}</p>}\n </div>\n );\n};\n\n// =============================================================================\n// STORE LISTING TAB\n// =============================================================================\n\ninterface ManifestIdentity {\n version: string;\n displayName: string;\n}\n\ninterface ManifestInstall {\n type: string;\n url?: string;\n packageName?: string;\n registryUrl?: string;\n}\n\ninterface ManifestDigital {\n install: ManifestInstall;\n}\n\ninterface ManifestCompatibility {\n minPlatformVersion: string;\n}\n\ninterface StoreManifest {\n manifestVersion: string;\n itemType?: string;\n identity: ManifestIdentity;\n digital?: ManifestDigital;\n jsonContent?: string;\n permissions: string[];\n compatibility: ManifestCompatibility;\n}\n\ninterface StoreListingFormData {\n // Store Presentation\n iconUrl: string;\n bannerUrl: string;\n videoUrl: string;\n shortDescription: string;\n description: string;\n screenshotsText: string;\n // Links & Policies\n websiteUrl: string;\n documentationUrl: string;\n githubUrl: string;\n supportUrl: string;\n privacyPolicyUrl: string;\n termsOfServiceUrl: string;\n // Pricing\n pricingType: string;\n price: string;\n currency: string;\n // Manifest\n manifestItemType: string;\n manifestDisplayName: string;\n manifestVersion: string;\n manifestInstallType: string;\n manifestPackageName: string;\n manifestRegistryUrl: string;\n manifestPermissionsText: string;\n manifestMinPlatformVersion: string;\n // JSON-only content (workflow / template)\n manifestJsonContent: string;\n}\n\n/** Item types whose entire payload IS a JSON document — no zip or binary needed. */\nconst JSON_ONLY_ITEM_TYPES = new Set([\"workflow\", \"template\"]);\n\nconst PRICING_TYPE_OPTIONS = [\n { value: \"FREE\", label: \"Free\" },\n { value: \"PAID\", label: \"Paid\" },\n];\n\nconst ITEM_TYPE_OPTIONS = [\n { value: \"agent\", label: \"Agent\" },\n { value: \"node\", label: \"Node\" },\n { value: \"widget\", label: \"Widget\" },\n { value: \"workflow\", label: \"Workflow\" },\n { value: \"botapp\", label: \"Bot App\" },\n { value: \"console\", label: \"Console\" },\n { value: \"vibemodule\", label: \"Vibe Module\" },\n { value: \"dashboard\", label: \"Dashboard\" },\n { value: \"parser\", label: \"Parser\" },\n { value: \"datasink\", label: \"Data Sink\" },\n { value: \"app\", label: \"App\" },\n { value: \"template\", label: \"Template\" },\n { value: \"integration\", label: \"Integration\" },\n { value: \"extension\", label: \"Extension\" },\n { value: \"theme\", label: \"Theme\" },\n { value: \"plugin\", label: \"Plugin\" },\n { value: \"component\", label: \"Component\" },\n];\n\nconst INSTALL_TYPE_OPTIONS = [\n { value: \"zip\", label: \"zip\" },\n { value: \"builtin\", label: \"builtin\" },\n];\n\nfunction buildInitialFormData(app: Application): StoreListingFormData {\n const manifest = (app.manifest ?? {}) as Record<string, unknown>;\n const identity = (manifest.identity ?? {}) as Record<string, unknown>;\n const digital = (manifest.digital ?? {}) as Record<string, unknown>;\n const install = (digital.install ?? {}) as Record<string, unknown>;\n const compatibility = (manifest.compatibility ?? {}) as Record<\n string,\n unknown\n >;\n const permissions = Array.isArray(manifest.permissions)\n ? (manifest.permissions as string[])\n : [];\n\n const pricingDetails = (app.pricingDetails ?? {}) as Record<string, unknown>;\n const screenshots = Array.isArray(app.screenshots)\n ? (app.screenshots as string[]).join(\"\\n\")\n : \"\";\n\n return {\n iconUrl: app.iconUrl ?? \"\",\n bannerUrl: app.bannerUrl ?? \"\",\n videoUrl: app.videoUrl ?? \"\",\n shortDescription: app.shortDescription ?? \"\",\n description: app.description ?? \"\",\n screenshotsText: screenshots,\n websiteUrl: app.websiteUrl ?? \"\",\n documentationUrl: app.documentationUrl ?? \"\",\n githubUrl: app.githubUrl ?? \"\",\n supportUrl: app.supportUrl ?? \"\",\n privacyPolicyUrl: app.privacyPolicyUrl ?? \"\",\n termsOfServiceUrl: app.termsOfServiceUrl ?? \"\",\n pricingType: app.pricingType ?? \"\",\n price:\n typeof pricingDetails.price === \"number\"\n ? String(pricingDetails.price)\n : \"\",\n currency:\n typeof pricingDetails.currency === \"string\"\n ? pricingDetails.currency\n : \"\",\n manifestItemType:\n typeof manifest.itemType === \"string\" ? manifest.itemType : \"\",\n manifestDisplayName:\n typeof identity.displayName === \"string\"\n ? identity.displayName\n : (app.name ?? \"\"),\n manifestVersion:\n typeof identity.version === \"string\" ? identity.version : \"\",\n manifestInstallType:\n typeof install.type === \"string\" ? install.type : \"zip\",\n manifestPackageName: \"\",\n manifestRegistryUrl:\n typeof install.url === \"string\"\n ? install.url\n : typeof install.registryUrl === \"string\"\n ? install.registryUrl\n : \"\",\n manifestPermissionsText: permissions.join(\"\\n\"),\n manifestMinPlatformVersion:\n typeof compatibility.minPlatformVersion === \"string\"\n ? compatibility.minPlatformVersion\n : \"\",\n manifestJsonContent:\n typeof manifest.jsonContent === \"string\"\n ? manifest.jsonContent\n : typeof manifest.content === \"string\"\n ? manifest.content\n : \"\",\n };\n}\n\nconst MY_PUBLISHER_QUERY = gql`\n query MyPublisherForListing {\n myPublisher { id }\n }\n`;\n\nconst PUBLISHER_PRODUCTS_QUERY = gql`\n query PublisherProductsForListing($publisherId: String!) {\n products(filter: { publisherId: $publisherId }) { id productId }\n }\n`;\n\nconst UPDATE_STORE_PRODUCT_MUTATION = gql`\n mutation UpdateStoreProduct($input: UpdateProductInput!) {\n updateProduct(input: $input) { id name description }\n }\n`;\n\nconst StoreListingTab: FC<{ app: Application }> = ({ app }) => {\n const { workspacesGatewayUrl, authToken, workspaceId, getWorkspaceToken, navigate, basePath } =\n 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\n const [formData, setFormData] = useState<StoreListingFormData>(() =>\n buildInitialFormData(app),\n );\n const [isSaving, setIsSaving] = useState(false);\n const [isDragging, setIsDragging] = useState(false);\n const appRef = useRef(app);\n appRef.current = app;\n\n const { data: publisherMeta } = useQuery<{\n myPublisher: { id: string } | null;\n }>(MY_PUBLISHER_QUERY, { fetchPolicy: \"cache-first\" });\n const myPublisherId = publisherMeta?.myPublisher?.id ?? null;\n\n const { data: publisherProds } = useQuery<{\n products: { id: string; productId?: string | null }[];\n }>(PUBLISHER_PRODUCTS_QUERY, {\n variables: { publisherId: myPublisherId ?? \"\" },\n fetchPolicy: \"cache-first\",\n skip: !myPublisherId,\n });\n const linkedStoreProductId = publisherProds?.products?.find(\n (p) => p.productId === app.id,\n )?.id ?? null;\n\n const [updateStoreProduct] = useMutation(UPDATE_STORE_PRODUCT_MUTATION);\n\n const [updateApplication] = useUpdateApplicationMutation();\n const [submitApplication, { loading: isSubmitting }] =\n useSubmitApplicationMutation();\n\n // Reset form only when navigating to a different app (not on every refetch)\n useEffect(() => {\n setFormData(buildInitialFormData(appRef.current));\n }, [app.id]);\n\n const handleChange = (field: keyof StoreListingFormData, value: string) => {\n setFormData((prev) => ({ ...prev, [field]: value }));\n };\n\n const handleSave = async () => {\n setIsSaving(true);\n try {\n const screenshotUrls = formData.screenshotsText\n .split(\"\\n\")\n .map((s) => s.trim())\n .filter(Boolean);\n\n const permissions = formData.manifestPermissionsText\n .split(\"\\n\")\n .map((s) => s.trim())\n .filter(Boolean);\n\n const isJsonOnly = JSON_ONLY_ITEM_TYPES.has(formData.manifestItemType);\n\n // Build manifest by merging existing app.manifest with form values\n const baseManifest = (app.manifest ?? {}) as Record<string, unknown>;\n const updatedManifest: StoreManifest = {\n manifestVersion:\n typeof baseManifest.manifestVersion === \"string\"\n ? baseManifest.manifestVersion\n : \"1.0\",\n itemType: formData.manifestItemType || undefined,\n identity: {\n version: formData.manifestVersion || \"1.0.0\",\n displayName: formData.manifestDisplayName,\n },\n ...(isJsonOnly\n ? { jsonContent: formData.manifestJsonContent || undefined }\n : {\n digital: {\n install: {\n type: formData.manifestInstallType,\n ...(formData.manifestInstallType === \"zip\" &&\n formData.manifestRegistryUrl\n ? { url: formData.manifestRegistryUrl }\n : {}),\n },\n },\n }),\n permissions,\n compatibility: {\n minPlatformVersion: formData.manifestMinPlatformVersion,\n },\n };\n\n const existingPricingDetails = (app.pricingDetails ?? {}) as Record<\n string,\n unknown\n >;\n const pricingDetails: Record<string, unknown> = {\n ...existingPricingDetails,\n };\n if (formData.pricingType !== \"FREE\") {\n const parsedPrice = parseFloat(formData.price);\n if (!isNaN(parsedPrice)) {\n pricingDetails.price = parsedPrice;\n }\n if (formData.currency) {\n pricingDetails.currency = formData.currency;\n }\n }\n\n await updateApplication({\n variables: {\n id: app.id,\n input: {\n iconUrl: formData.iconUrl || null,\n bannerUrl: formData.bannerUrl || null,\n videoUrl: formData.videoUrl || null,\n shortDescription: formData.shortDescription || null,\n description: formData.description || null,\n screenshots:\n screenshotUrls.length > 0\n ? (screenshotUrls as unknown as Record<string, unknown>)\n : null,\n websiteUrl: formData.websiteUrl || null,\n documentationUrl: formData.documentationUrl || null,\n githubUrl: formData.githubUrl || null,\n supportUrl: formData.supportUrl || null,\n privacyPolicyUrl: formData.privacyPolicyUrl || null,\n termsOfServiceUrl: formData.termsOfServiceUrl || null,\n pricingType: formData.pricingType || null,\n pricingDetails:\n Object.keys(pricingDetails).length > 0 ? pricingDetails : null,\n manifest: updatedManifest as unknown as Record<string, unknown>,\n },\n },\n });\n\n // Sync to linked StoreProduct if one exists\n if (linkedStoreProductId) {\n await updateStoreProduct({\n variables: {\n input: {\n id: linkedStoreProductId,\n name: app.name,\n description: formData.shortDescription || undefined,\n longDescription: formData.description || undefined,\n icon: formData.iconUrl || undefined,\n screenshots: screenshotUrls.length > 0 ? screenshotUrls : undefined,\n documentationUrl: formData.documentationUrl || undefined,\n category: app.category || undefined,\n },\n },\n });\n }\n\n void nativeNotify(\"success\");\n } catch {\n void nativeNotify(\"error\");\n } finally {\n setIsSaving(false);\n }\n };\n\n const handleSubmitForReview = async () => {\n try {\n await submitApplication({ variables: { id: app.id } });\n void nativeNotify(\"success\");\n } catch {\n void nativeNotify(\"error\");\n }\n };\n\n const manifestFileInputRef = useRef<HTMLInputElement>(null);\n const zipFileInputRef = useRef<HTMLInputElement>(null);\n const {\n upload: uploadPackage,\n uploading: packageUploading,\n progress: packageProgress,\n error: packageUploadError,\n } = usePackageUpload(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n getWorkspaceToken,\n );\n const {\n upload: uploadAsset,\n uploading: iconUploading,\n progress: iconProgress,\n error: iconUploadError,\n } = usePackageUpload(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n getWorkspaceToken,\n \"/DevPortal/Assets\",\n );\n const {\n upload: uploadBanner,\n uploading: bannerUploading,\n progress: bannerProgress,\n error: bannerUploadError,\n } = usePackageUpload(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n getWorkspaceToken,\n \"/DevPortal/Assets\",\n );\n const {\n upload: uploadScreenshot,\n uploading: screenshotUploading,\n progress: screenshotProgress,\n error: screenshotUploadError,\n } = usePackageUpload(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n getWorkspaceToken,\n \"/DevPortal/Assets\",\n );\n\n const handleZipUpload = useCallback(\n async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n e.target.value = \"\";\n try {\n const result = await uploadPackage(file);\n setFormData((prev) => ({\n ...prev,\n manifestRegistryUrl: result.downloadUrl,\n }));\n } catch {\n // error shown via packageUploadError state\n }\n },\n [uploadPackage],\n );\n\n const handleZipDrop = useCallback(\n async (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n setIsDragging(false);\n const file = e.dataTransfer.files?.[0];\n if (!file) return;\n try {\n const result = await uploadPackage(file);\n setFormData((prev) => ({\n ...prev,\n manifestRegistryUrl: result.downloadUrl,\n }));\n } catch {\n // error shown via packageUploadError state\n }\n },\n [uploadPackage],\n );\n\n const handleImportManifest = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const reader = new FileReader();\n reader.onload = (ev) => {\n try {\n const parsed = JSON.parse(ev.target?.result as string) as Record<\n string,\n unknown\n >;\n const identity = (parsed.identity ?? {}) as Record<string, unknown>;\n const digital = (parsed.digital ?? {}) as Record<string, unknown>;\n const install = (digital.install ?? {}) as Record<string, unknown>;\n const compatibility = (parsed.compatibility ?? {}) as Record<\n string,\n unknown\n >;\n const permissions = Array.isArray(parsed.permissions)\n ? (parsed.permissions as string[])\n : [];\n setFormData((prev) => ({\n ...prev,\n manifestItemType:\n typeof parsed.itemType === \"string\"\n ? parsed.itemType\n : prev.manifestItemType,\n manifestDisplayName:\n typeof identity.displayName === \"string\"\n ? identity.displayName\n : prev.manifestDisplayName,\n manifestVersion:\n typeof identity.version === \"string\"\n ? identity.version\n : prev.manifestVersion,\n manifestInstallType:\n typeof install.type === \"string\"\n ? install.type\n : prev.manifestInstallType,\n manifestRegistryUrl:\n typeof install.url === \"string\"\n ? install.url\n : typeof install.registryUrl === \"string\"\n ? install.registryUrl\n : prev.manifestRegistryUrl,\n manifestPermissionsText:\n permissions.length > 0\n ? permissions.join(\"\\n\")\n : prev.manifestPermissionsText,\n manifestMinPlatformVersion:\n typeof compatibility.minPlatformVersion === \"string\"\n ? compatibility.minPlatformVersion\n : prev.manifestMinPlatformVersion,\n }));\n } catch {\n // invalid JSON — ignore\n }\n };\n reader.readAsText(file);\n // reset so the same file can be re-imported\n e.target.value = \"\";\n },\n [],\n );\n\n const handleExportManifest = useCallback(() => {\n const permissions = formData.manifestPermissionsText\n .split(\"\\n\")\n .map((s) => s.trim())\n .filter(Boolean);\n const isJsonOnly = JSON_ONLY_ITEM_TYPES.has(formData.manifestItemType);\n const manifest: StoreManifest = {\n manifestVersion: \"1.0\",\n itemType: formData.manifestItemType || undefined,\n identity: {\n version: formData.manifestVersion || \"1.0.0\",\n displayName: formData.manifestDisplayName,\n },\n ...(isJsonOnly\n ? { jsonContent: formData.manifestJsonContent || undefined }\n : {\n digital: {\n install: {\n type: formData.manifestInstallType,\n ...(formData.manifestInstallType === \"zip\" &&\n formData.manifestRegistryUrl\n ? { url: formData.manifestRegistryUrl }\n : {}),\n },\n },\n }),\n permissions,\n compatibility: {\n minPlatformVersion: formData.manifestMinPlatformVersion,\n },\n };\n const blob = new Blob([JSON.stringify(manifest, null, 2)], {\n type: \"application/json\",\n });\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = `${app.slug}-manifest.json`;\n a.click();\n URL.revokeObjectURL(url);\n }, [app.slug, formData]);\n\n const isJsonOnlyType = JSON_ONLY_ITEM_TYPES.has(formData.manifestItemType);\n const isBuiltin = formData.manifestInstallType === \"builtin\";\n const showPriceFields = formData.pricingType !== \"FREE\";\n const zipFileName = formData.manifestRegistryUrl\n ? (formData.manifestRegistryUrl.split(\"/\").pop()?.split(\"?\")[0] ?? \"\")\n : \"\";\n\n const isDraft = app.status === \"DRAFT\";\n const isSubmitted = app.status === \"SUBMITTED\";\n const isPublished = app.status === \"PUBLISHED\";\n const isPackageType =\n app.appType === \"NODE\" || app.appType === \"WORKFLOW\";\n\n const listingCompleteness = [\n { label: \"Short description\", done: !!formData.shortDescription.trim() },\n { label: \"Full description\", done: !!formData.description.trim() },\n { label: \"Icon\", done: !!formData.iconUrl.trim() },\n { label: \"Privacy Policy URL\", done: !!formData.privacyPolicyUrl.trim() },\n { label: \"Terms of Service URL\", done: !!formData.termsOfServiceUrl.trim() },\n ];\n const completedCount = listingCompleteness.filter((i) => i.done).length;\n const totalCount = listingCompleteness.length;\n\n return (\n <div className=\"space-y-8 max-w-3xl\">\n {/* ── How this works ───────────────────────────────────── */}\n <div className=\"rounded-lg border border-primary/20 bg-primary/5 px-4 py-3 space-y-2\">\n <p className=\"text-sm font-semibold text-primary\">\n {tr(\"devportal.listingTabPurpose\", \"What is this tab for?\")}\n </p>\n <ul className=\"text-sm text-muted-foreground space-y-1 list-none pl-0\">\n <li className=\"flex items-start gap-2\">\n <Store size={14} className=\"mt-0.5 shrink-0 text-primary\" />\n <span>\n <strong>\n {tr(\"devportal.thisTab\", \"This tab\")}\n </strong>{\" \"}\n {tr(\n \"devportal.listingTabDesc\",\n \"controls your store card — the name, description, icon and screenshots users see in the marketplace. Save changes here any time without creating a new release.\",\n )}\n </span>\n </li>\n {isPackageType && (\n <li className=\"flex items-start gap-2\">\n <Clock size={14} className=\"mt-0.5 shrink-0 text-primary\" />\n <span>\n {tr(\n \"devportal.versionsTabDesc\",\n \"To release a new version (ZIP package + manifest), go to the\",\n )}{\" \"}\n <button\n type=\"button\"\n className=\"underline text-primary hover:no-underline\"\n onClick={() => navigate?.(`${basePath}/apps/${app.id}/versions`)}\n >\n {tr(\"devportal.versionsTab\", \"Versions page\")}\n </button>\n .\n </span>\n </li>\n )}\n <li className=\"flex items-start gap-2\">\n <SendHorizontal size={14} className=\"mt-0.5 shrink-0 text-primary\" />\n <span>\n {tr(\n \"devportal.submitTabDesc\",\n 'When your listing is ready, click \"Submit for Review\" to send it to the review team.',\n )}\n </span>\n </li>\n </ul>\n </div>\n\n {/* ── Listing completeness ─────────────────────────────── */}\n {!isPublished && (\n <div className=\"rounded-lg border bg-card p-4 space-y-3\">\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm font-medium\">\n {tr(\"devportal.listingCompleteness\", \"Listing completeness\")}{\" \"}\n <span\n className={cn(\n \"ml-1 text-xs font-semibold\",\n completedCount === totalCount\n ? \"text-status-success-text\"\n : \"text-status-warning-text\",\n )}\n >\n {completedCount}/{totalCount}\n </span>\n </p>\n {completedCount === totalCount && (\n <span className=\"text-xs text-status-success-text flex items-center gap-1\">\n <CheckCircle size={12} />\n {tr(\"devportal.readyToSubmit\", \"Ready to submit\")}\n </span>\n )}\n </div>\n <div className=\"grid grid-cols-2 sm:grid-cols-3 gap-2\">\n {listingCompleteness.map((item) => (\n <div key={item.label} className=\"flex items-center gap-1.5 text-xs\">\n {item.done ? (\n <CheckCircle size={12} className=\"text-status-success-text shrink-0\" />\n ) : (\n <AlertCircle size={12} className=\"text-status-warning-text shrink-0\" />\n )}\n <span\n className={\n item.done ? \"text-foreground\" : \"text-muted-foreground\"\n }\n >\n {item.label}\n </span>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* ── Status banner ─────────────────────────────────────── */}\n {isPublished ? (\n <div className=\"flex items-start gap-3 rounded-lg border border-success/30 bg-success/10 px-4 py-3\">\n <CheckCircle size={16} className=\"text-success mt-0.5 shrink-0\" />\n <div className=\"text-sm\">\n <span className=\"font-medium text-success\">\n {tr(\"devportal.storeListing.published\", \"Published\")}\n </span>\n {app.publishedAt && (\n <span className=\"text-muted-foreground ml-2\">\n {tr(\"devportal.storeListing.since\", \"since\")}{\" \"}\n {new Date(app.publishedAt).toLocaleDateString()}\n </span>\n )}\n </div>\n </div>\n ) : isSubmitted ? (\n <div className=\"flex items-start gap-3 rounded-lg border border-primary/30 bg-primary/5 px-4 py-3\">\n <Clock size={16} className=\"text-primary mt-0.5 shrink-0\" />\n <div className=\"text-sm\">\n <span className=\"font-medium text-primary\">\n {tr(\"devportal.storeListing.underReview\", \"Submitted for review\")}\n </span>\n {app.submittedAt && (\n <span className=\"text-muted-foreground ml-2\">\n {new Date(app.submittedAt).toLocaleDateString()}\n </span>\n )}\n {app.reviewStatus && (\n <span className=\"text-muted-foreground ml-2\">\n · {app.reviewStatus}\n </span>\n )}\n </div>\n </div>\n ) : (\n <div className=\"flex items-start gap-3 rounded-lg border border-warning/30 bg-warning/5 px-4 py-3\">\n <AlertCircle size={16} className=\"text-warning mt-0.5 shrink-0\" />\n <div className=\"text-sm\">\n <span className=\"font-medium text-warning\">\n {tr(\"devportal.storeListing.draft\", \"Draft\")}\n </span>\n <span className=\"text-muted-foreground ml-2\">\n {tr(\n \"devportal.storeListing.draftHint\",\n \"Complete your store listing and submit for review to publish.\",\n )}\n </span>\n </div>\n </div>\n )}\n\n {/* ── Section 1: Package ─────────────────────────────────── */}\n {isPackageType ? (\n <div className=\"rounded-lg border border-border-subtle bg-bg-sunken px-4 py-4 flex items-start gap-3\">\n <Info size={16} className=\"shrink-0 mt-0.5 text-muted-foreground\" />\n <div className=\"text-sm space-y-1\">\n <p className=\"font-medium\">\n {tr(\"devportal.packageManagedInVersions\", \"ZIP package & manifest are managed in Versions\")}\n </p>\n <p className=\"text-muted-foreground\">\n {tr(\n \"devportal.packageManagedInVersionsDesc\",\n \"For NODE and WORKFLOW types, each release is uploaded through the Versions page — including the ZIP archive and manifest.json. This keeps your code releases separate from your store card.\",\n )}\n </p>\n </div>\n </div>\n ) : (\n <PageSection\n title={tr(\"devportal.package\", \"Package\")}\n description={tr(\n \"devportal.packageDescription\",\n \"Technical configuration — how FluidGrid installs and runs this item\",\n )}\n >\n <div className=\"space-y-6\">\n {/* Item type — the most important choice */}\n <SelectField\n label={tr(\"devportal.storeItemType\", \"Item Type\")}\n value={formData.manifestItemType}\n onChange={(e) => {\n const next = e.target.value;\n handleChange(\"manifestItemType\", next);\n if (JSON_ONLY_ITEM_TYPES.has(next)) {\n handleChange(\"manifestInstallType\", \"json\");\n } else if (formData.manifestInstallType === \"json\") {\n handleChange(\"manifestInstallType\", \"zip\");\n }\n }}\n options={ITEM_TYPE_OPTIONS}\n placeholder={tr(\"devportal.selectItemType\", \"Select item type…\")}\n hint={tr(\n \"devportal.storeItemTypeHint\",\n \"Determines how this item is categorised and how the platform runs it\",\n )}\n />\n\n {/* Identity */}\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <InputField\n label={tr(\"devportal.manifestDisplayName\", \"Display Name\")}\n value={formData.manifestDisplayName}\n onChange={(e) =>\n handleChange(\"manifestDisplayName\", e.target.value)\n }\n placeholder=\"My Awesome Node\"\n />\n <InputField\n label={tr(\"devportal.manifestVersion\", \"Version\")}\n value={formData.manifestVersion}\n onChange={(e) => handleChange(\"manifestVersion\", e.target.value)}\n placeholder=\"1.0.0\"\n hint={tr(\n \"devportal.semverHint\",\n \"Semantic version (MAJOR.MINOR.PATCH)\",\n )}\n />\n </div>\n\n {/* JSON editor for workflow / template types */}\n {isJsonOnlyType && (\n <TextareaField\n label={tr(\n \"devportal.jsonContent\",\n formData.manifestItemType === \"workflow\"\n ? \"Workflow Definition (JSON)\"\n : \"Template Definition (JSON)\",\n )}\n value={formData.manifestJsonContent}\n onChange={(e) =>\n handleChange(\"manifestJsonContent\", e.target.value)\n }\n rows={12}\n placeholder={'{\\n \"nodes\": [],\\n \"edges\": []\\n}'}\n hint={tr(\n \"devportal.jsonContentHint\",\n \"Paste the full JSON definition. Stored and applied directly — no zip needed.\",\n )}\n />\n )}\n\n {/* Package delivery — for code-bearing items */}\n {!isJsonOnlyType && (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between flex-wrap gap-2\">\n <label className=\"text-sm font-medium\">\n {tr(\"devportal.packageFile\", \"Package File\")}\n </label>\n <label className=\"flex items-center gap-2 text-sm cursor-pointer select-none\">\n <input\n type=\"checkbox\"\n checked={isBuiltin}\n onChange={(e) =>\n handleChange(\n \"manifestInstallType\",\n e.target.checked ? \"builtin\" : \"zip\",\n )\n }\n className=\"h-4 w-4 rounded border-border accent-primary\"\n />\n <span className=\"text-text-secondary\">\n {tr(\n \"devportal.builtinToggle\",\n \"Built-in (pre-installed, no upload needed)\",\n )}\n </span>\n </label>\n </div>\n\n {!isBuiltin && (\n <>\n <div className=\"flex gap-3 rounded-lg border border-border-subtle bg-bg-sunken p-3 text-sm text-text-secondary\">\n <Info size={15} className=\"mt-0.5 shrink-0\" />\n <span>\n {tr(\"devportal.zipModelHint\", \"Package your code and a \")}\n <code className=\"rounded bg-muted px-1 py-0.5 font-mono text-xs\">\n manifest.json\n </code>\n {tr(\n \"devportal.zipModelHint2\",\n \" into a single zip — like a Chrome extension. Upload it below and FluidGrid handles the rest automatically.\",\n )}\n </span>\n </div>\n\n {/* Drag-and-drop upload zone */}\n <div\n onDragOver={(e) => {\n e.preventDefault();\n setIsDragging(true);\n }}\n onDragLeave={() => setIsDragging(false)}\n onDrop={(e) => void handleZipDrop(e)}\n onClick={() =>\n !packageUploading && zipFileInputRef.current?.click()\n }\n className={cn(\n \"relative flex flex-col items-center justify-center gap-3 rounded-xl border-2 border-dashed px-6 py-10 text-center transition-colors cursor-pointer\",\n isDragging\n ? \"border-primary bg-primary/5\"\n : \"border-border hover:border-border-strong hover:bg-bg-sunken\",\n packageUploading && \"pointer-events-none opacity-75\",\n )}\n >\n <input\n ref={zipFileInputRef}\n type=\"file\"\n accept=\".zip,application/zip,application/x-zip-compressed\"\n className=\"hidden\"\n onChange={(e) => void handleZipUpload(e)}\n />\n {packageUploading ? (\n <>\n <Loader2\n size={28}\n className=\"animate-spin text-primary\"\n />\n <div>\n <p className=\"text-sm font-medium\">\n {tr(\"devportal.uploading\", \"Uploading…\")}{\" \"}\n {packageProgress}%\n </p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {tr(\n \"devportal.uploadingHint\",\n \"Stored securely in your workspace\",\n )}\n </p>\n </div>\n <div className=\"w-48 h-1.5 rounded-full bg-muted overflow-hidden\">\n <div\n className=\"h-full bg-primary transition-all\"\n style={{ width: `${packageProgress}%` }}\n />\n </div>\n </>\n ) : zipFileName ? (\n <>\n <CheckCircle\n size={28}\n className=\"text-status-success-text\"\n />\n <div>\n <p className=\"text-sm font-medium\">{zipFileName}</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {tr(\n \"devportal.clickToReplace\",\n \"Click or drag to replace\",\n )}\n </p>\n </div>\n </>\n ) : (\n <>\n <Upload size={28} className=\"text-text-secondary\" />\n <div>\n <p className=\"text-sm font-medium\">\n {tr(\"devportal.dropZipHere\", \"Drop your .zip here\")}\n </p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {tr(\n \"devportal.orClickToBrowse\",\n \"or click to browse\",\n )}\n </p>\n </div>\n </>\n )}\n </div>\n {packageUploadError && (\n <p className=\"text-xs text-status-error-text\">\n {packageUploadError}\n </p>\n )}\n </>\n )}\n\n {isBuiltin && (\n <div className=\"flex gap-3 rounded-lg border border-border-subtle bg-bg-sunken p-3 text-sm text-text-secondary\">\n <Info size={15} className=\"mt-0.5 shrink-0\" />\n <span>\n {tr(\n \"devportal.builtinHint\",\n \"Built-in items are pre-installed by the platform. No package upload is needed.\",\n )}\n </span>\n </div>\n )}\n </div>\n )}\n\n {/* manifest.json import / export helpers */}\n <div className=\"flex flex-wrap items-center gap-2 border-t pt-4\">\n <input\n ref={manifestFileInputRef}\n type=\"file\"\n accept=\".json,application/json\"\n className=\"hidden\"\n onChange={handleImportManifest}\n />\n <span className=\"text-xs text-text-secondary mr-1\">\n manifest.json:\n </span>\n <button\n type=\"button\"\n onClick={() => manifestFileInputRef.current?.click()}\n className=\"inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-xs font-medium hover:bg-muted transition-colors\"\n >\n <Upload size={12} />\n {tr(\"devportal.importManifest\", \"Import\")}\n </button>\n <button\n type=\"button\"\n onClick={handleExportManifest}\n className=\"inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-xs font-medium hover:bg-muted transition-colors\"\n >\n <Download size={12} />\n {tr(\"devportal.exportManifest\", \"Export\")}\n </button>\n <span className=\"text-xs text-text-secondary\">\n {tr(\n \"devportal.manifestTip\",\n \"— export to get a manifest.json to include inside your zip\",\n )}\n </span>\n </div>\n </div>\n </PageSection>\n )}\n\n {/* ── Section 2: Store Presence ──────────────────────────── */}\n <PageSection\n title={tr(\"devportal.storePresentation\", \"Store Presence\")}\n description={tr(\n \"devportal.storePresentationDescription\",\n \"Visual assets and copy shown to users browsing the marketplace\",\n )}\n >\n <div className=\"space-y-5\">\n <div className=\"grid gap-5 sm:grid-cols-2\">\n <ImageUploadField\n label={tr(\"devportal.iconUrl\", \"Icon\")}\n value={formData.iconUrl}\n onChange={(url) => handleChange(\"iconUrl\", url)}\n hint={tr(\n \"devportal.iconUrlHint\",\n \"Square, 256×256 px recommended\",\n )}\n aspectClass=\"aspect-square\"\n upload={uploadAsset}\n uploading={iconUploading}\n progress={iconProgress}\n error={iconUploadError}\n />\n <ImageUploadField\n label={tr(\"devportal.bannerUrl\", \"Banner\")}\n value={formData.bannerUrl}\n onChange={(url) => handleChange(\"bannerUrl\", url)}\n hint={tr(\"devportal.bannerUrlHint\", \"1280×640 px recommended\")}\n aspectClass=\"aspect-video\"\n upload={uploadBanner}\n uploading={bannerUploading}\n progress={bannerProgress}\n error={bannerUploadError}\n />\n </div>\n <InputField\n label={tr(\"devportal.videoUrl\", \"Demo Video URL\")}\n value={formData.videoUrl}\n onChange={(e) => handleChange(\"videoUrl\", e.target.value)}\n placeholder=\"https://...\"\n hint={tr(\"devportal.videoUrlHint\", \"YouTube or Vimeo embed URL\")}\n />\n <TextareaField\n label={tr(\"devportal.shortDescription\", \"Short Description\")}\n value={formData.shortDescription}\n onChange={(e) => handleChange(\"shortDescription\", e.target.value)}\n maxLength={200}\n rows={2}\n hint={`${formData.shortDescription.length}/200 · ${tr(\"devportal.shortDescHint\", \"Shown in search results and cards\")}`}\n />\n <TextareaField\n label={tr(\"devportal.longDescription\", \"Full Description\")}\n value={formData.description}\n onChange={(e) => handleChange(\"description\", e.target.value)}\n rows={5}\n hint={tr(\"devportal.fullDescHint\", \"Markdown supported\")}\n />\n <ScreenshotGallery\n urls={formData.screenshotsText\n .split(\"\\n\")\n .map((s) => s.trim())\n .filter(Boolean)}\n onChange={(urls) =>\n handleChange(\"screenshotsText\", urls.join(\"\\n\"))\n }\n upload={uploadScreenshot}\n uploading={screenshotUploading}\n progress={screenshotProgress}\n error={screenshotUploadError}\n />\n </div>\n </PageSection>\n\n {/* ── Section 3: Links & Policies ────────────────────────── */}\n <PageSection\n title={tr(\"devportal.linksPolicies\", \"Links & Policies\")}\n description={tr(\n \"devportal.linksPoliciesDescription\",\n \"External resources and legal documents — privacy policy and terms are required for store submission\",\n )}\n >\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <InputField\n label={tr(\"devportal.websiteUrl\", \"Website\")}\n value={formData.websiteUrl}\n onChange={(e) => handleChange(\"websiteUrl\", e.target.value)}\n placeholder=\"https://...\"\n />\n <InputField\n label={tr(\"devportal.documentationUrl\", \"Documentation\")}\n value={formData.documentationUrl}\n onChange={(e) => handleChange(\"documentationUrl\", e.target.value)}\n placeholder=\"https://...\"\n />\n <InputField\n label={tr(\"devportal.githubUrl\", \"GitHub\")}\n value={formData.githubUrl}\n onChange={(e) => handleChange(\"githubUrl\", e.target.value)}\n placeholder=\"https://github.com/...\"\n />\n <InputField\n label={tr(\"devportal.supportUrl\", \"Support\")}\n value={formData.supportUrl}\n onChange={(e) => handleChange(\"supportUrl\", e.target.value)}\n placeholder=\"https://...\"\n />\n <InputField\n label={`${tr(\"devportal.privacyPolicyUrl\", \"Privacy Policy\")} *`}\n value={formData.privacyPolicyUrl}\n onChange={(e) => handleChange(\"privacyPolicyUrl\", e.target.value)}\n placeholder=\"https://...\"\n hint={tr(\n \"devportal.requiredForStore\",\n \"Required for store submission\",\n )}\n />\n <InputField\n label={`${tr(\"devportal.termsOfServiceUrl\", \"Terms of Service\")} *`}\n value={formData.termsOfServiceUrl}\n onChange={(e) => handleChange(\"termsOfServiceUrl\", e.target.value)}\n placeholder=\"https://...\"\n hint={tr(\n \"devportal.requiredForStore\",\n \"Required for store submission\",\n )}\n />\n </div>\n </PageSection>\n\n {/* ── Section 4: Pricing ─────────────────────────────────── */}\n <PageSection\n title={tr(\"devportal.pricing\", \"Pricing\")}\n description={tr(\n \"devportal.pricingDescription\",\n \"How this item is priced in the marketplace\",\n )}\n >\n <div className=\"space-y-4\">\n <div>\n <label className=\"mb-2 block text-sm font-medium\">\n {tr(\"devportal.pricingType\", \"Pricing Type\")}\n </label>\n <div className=\"flex flex-wrap gap-2\">\n {PRICING_TYPE_OPTIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => handleChange(\"pricingType\", opt.value)}\n className={cn(\n \"rounded-md border px-3 py-1.5 text-sm font-medium transition-colors\",\n formData.pricingType === opt.value\n ? \"bg-primary text-primary-foreground border-primary\"\n : \"hover:bg-muted\",\n )}\n >\n {opt.label}\n </button>\n ))}\n </div>\n </div>\n {showPriceFields && (\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <InputField\n label={tr(\"devportal.price\", \"Price\")}\n type=\"number\"\n value={formData.price}\n onChange={(e) => handleChange(\"price\", e.target.value)}\n placeholder=\"0.00\"\n />\n <InputField\n label={tr(\"devportal.currency\", \"Currency\")}\n value={formData.currency}\n onChange={(e) => handleChange(\"currency\", e.target.value)}\n placeholder=\"USD\"\n />\n </div>\n )}\n </div>\n </PageSection>\n\n {/* Save + Submit for Review */}\n <div className=\"border-t pt-6 flex items-center gap-3 flex-wrap\">\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={isSaving}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n {isSaving ? (\n <>\n <Loader2 size={16} className=\"animate-spin\" />\n {tr(\"devportal.saving\", \"Saving…\")}\n </>\n ) : (\n <>\n <Store size={16} />\n {tr(\"devportal.saveMarketplaceListing\", \"Save Marketplace Listing\")}\n </>\n )}\n </button>\n {!isPublished && !isSubmitted && (\n <button\n type=\"button\"\n onClick={() => void handleSubmitForReview()}\n disabled={isSubmitting || isSaving}\n className=\"inline-flex items-center gap-2 rounded-md border border-primary px-4 py-2 text-sm font-medium text-primary hover:bg-primary/5 transition-colors disabled:opacity-50\"\n >\n {isSubmitting ? (\n <>\n <Loader2 size={16} className=\"animate-spin\" />\n {tr(\"devportal.submitting\", \"Submitting…\")}\n </>\n ) : (\n <>\n <SendHorizontal size={16} />\n {tr(\"devportal.submitForReview\", \"Submit for Review\")}\n </>\n )}\n </button>\n )}\n {!isPublished && isSubmitted && (\n <p className=\"text-xs text-muted-foreground flex items-center gap-1.5\">\n <Clock size={12} />\n {tr(\n \"devportal.awaitingReview\",\n \"Your listing is under review. You can still update and save — changes take effect after approval.\",\n )}\n </p>\n )}\n </div>\n </div>\n );\n};\n\n// =============================================================================\n// HELPER COMPONENTS\n// =============================================================================\n\nconst StatCard: FC<{ label: string; value: string; trend?: number }> = ({\n label,\n value,\n trend,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n return (\n <div className=\"rounded-lg border bg-card p-4\">\n <p className=\"text-sm text-muted-foreground\">{label}</p>\n <p className=\"text-2xl font-bold\">{value}</p>\n {trend !== undefined && (\n <p\n className={cn(\n \"text-xs mt-1\",\n trend > 0\n ? \"text-status-success-text\"\n : trend < 0\n ? \"text-status-error-text\"\n : \"text-muted-foreground\",\n )}\n >\n {trend > 0 ? \"+\" : \"\"}\n {trend.toFixed(1)}% {tr(\"devportal.vsYesterday\", \"vs yesterday\")}\n </p>\n )}\n </div>\n );\n};\n\nconst LinkItem: FC<{ label: string; url: string }> = ({ label, url }) => (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center gap-2 text-sm text-primary hover:underline\"\n >\n <ExternalLink size={14} />\n {label}\n </a>\n);\n\n// =============================================================================\n// PERMISSIONS TAB\n// =============================================================================\n\nconst PERMISSION_RESOURCES = [\n {\n id: \"auth\",\n label: \"Authentication\",\n description: \"User identity and session management\",\n },\n {\n id: \"billing\",\n label: \"Billing\",\n description: \"Billing accounts and subscriptions\",\n },\n { id: \"files\", label: \"Files\", description: \"File storage and management\" },\n { id: \"tags\", label: \"Tags\", description: \"Tags and labels on resources\" },\n { id: \"calendar\", label: \"Calendar\", description: \"Events and scheduling\" },\n { id: \"workflows\", label: \"Workflows\", description: \"Automation workflows\" },\n { id: \"channels\", label: \"Channels\", description: \"Messaging channels\" },\n {\n id: \"notifications\",\n label: \"Notifications\",\n description: \"Platform notifications\",\n },\n {\n id: \"users\",\n label: \"Users & Members\",\n description: \"Workspace members and profiles\",\n },\n {\n id: \"workspaces\",\n label: \"Workspaces\",\n description: \"Workspace settings and metadata\",\n },\n {\n id: \"content\",\n label: \"Content\",\n description: \"Pages, documents, and content\",\n },\n {\n id: \"analytics\",\n label: \"Analytics\",\n description: \"Usage analytics and reporting\",\n },\n { id: \"webhooks\", label: \"Webhooks\", description: \"Webhook subscriptions\" },\n {\n id: \"rbac\",\n label: \"Roles & Permissions\",\n description: \"Access control configuration\",\n },\n] as const;\n\ntype PermissionResourceId = (typeof PERMISSION_RESOURCES)[number][\"id\"];\ntype PermissionLevel = \"none\" | \"read\" | \"write\";\ntype PermissionMap = Record<PermissionResourceId, PermissionLevel>;\n\nfunction parseManifestPermissions(\n manifest: Record<string, unknown> | null | undefined,\n): PermissionMap {\n const base = Object.fromEntries(\n PERMISSION_RESOURCES.map((r) => [r.id, \"none\" as PermissionLevel]),\n ) as PermissionMap;\n if (!manifest || !Array.isArray(manifest.permissions)) return base;\n for (const entry of manifest.permissions as Array<{\n resource: string;\n level: string;\n }>) {\n if (entry.resource in base) {\n base[entry.resource as PermissionResourceId] =\n entry.level === \"write\" ? \"write\" : \"read\";\n }\n }\n return base;\n}\n\nconst PermissionsTab: FC<{ app: Application }> = ({ app }) => {\n const manifest = (app.manifest ?? {}) as Record<string, unknown>;\n const [permissions, setPermissions] = useState<PermissionMap>(() =>\n parseManifestPermissions(manifest),\n );\n const [saving, setSaving] = useState(false);\n const [saved, setSaved] = useState(false);\n const [updateApplication] = useUpdateApplicationMutation();\n\n const handleChange = (\n resource: PermissionResourceId,\n level: PermissionLevel,\n ) => {\n setSaved(false);\n setPermissions((prev) => ({ ...prev, [resource]: level }));\n };\n\n const handleSave = async () => {\n setSaving(true);\n try {\n const entries = Object.entries(permissions).filter(\n ([, level]) => level !== \"none\",\n );\n const newPermissions = entries.map(([resource, level]) => ({\n resource,\n level,\n }));\n await updateApplication({\n variables: {\n id: app.id,\n input: {\n manifest: {\n ...manifest,\n permissions: newPermissions,\n },\n },\n },\n });\n setSaved(true);\n } finally {\n setSaving(false);\n }\n };\n\n const levelLabels: Record<PermissionLevel, string> = {\n none: \"No access\",\n read: \"Read\",\n write: \"Read & Write\",\n };\n const levels: PermissionLevel[] = [\"none\", \"read\", \"write\"];\n\n return (\n <PageSection\n title=\"Permissions\"\n description=\"Define what platform data this app can request access to. Users see these when authorizing the app.\"\n >\n <div className=\"space-y-4\">\n <div className=\"overflow-x-auto rounded-lg border border-border\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border bg-muted/50\">\n <th className=\"px-4 py-3 text-left font-medium text-muted-foreground w-1/2\">\n Resource\n </th>\n {levels.map((l) => (\n <th\n key={l}\n className=\"px-4 py-3 text-center font-medium text-muted-foreground\"\n >\n {levelLabels[l]}\n </th>\n ))}\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border\">\n {PERMISSION_RESOURCES.map((resource) => (\n <tr\n key={resource.id}\n className=\"hover:bg-muted/30 transition-colors\"\n >\n <td className=\"px-4 py-3\">\n <p className=\"font-medium text-foreground\">\n {resource.label}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {resource.description}\n </p>\n </td>\n {levels.map((level) => (\n <td key={level} className=\"px-4 py-3 text-center\">\n <input\n type=\"radio\"\n name={`perm-${resource.id}`}\n value={level}\n checked={permissions[resource.id] === level}\n onChange={() => handleChange(resource.id, level)}\n className=\"h-4 w-4 accent-primary cursor-pointer\"\n />\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n\n <div className=\"rounded-lg border border-border-subtle bg-muted/30 p-3 flex gap-2 text-xs text-muted-foreground\">\n <Info size={14} className=\"flex-shrink-0 mt-0.5\" />\n <span>\n <strong>Read & Write</strong> implies Read. Request only what\n your app genuinely needs — fewer permissions build more user trust.\n </span>\n </div>\n\n <div className=\"flex items-center justify-end gap-3\">\n {saved && (\n <span className=\"flex items-center gap-1.5 text-sm text-status-success-text\">\n <CheckCircle size={14} />\n Saved\n </span>\n )}\n <button\n type=\"button\"\n onClick={() => void handleSave()}\n disabled={saving}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n {saving ? (\n <Loader2 size={14} className=\"animate-spin\" />\n ) : (\n <Shield size={14} />\n )}\n Save Permissions\n </button>\n </div>\n </div>\n </PageSection>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ApplicationDetailPage.js","names":[],"sources":["../../../src/devportal/pages/ApplicationDetailPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState, useMemo, useCallback, useEffect, useRef } from \"react\";\nimport { gql } from \"@apollo/client\";\nimport { useMutation, useQuery } from \"@apollo/client/react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { useParams, useSearchParams } from \"react-router-dom\";\nimport {\n AppWindow,\n Key,\n Webhook,\n BarChart3,\n Plus,\n ExternalLink,\n MoreHorizontal,\n Loader2,\n AlertCircle,\n CheckCircle,\n CheckCircle2,\n Clock,\n Shield,\n RefreshCw,\n Edit,\n XCircle,\n Power,\n Users,\n Store,\n FlaskConical,\n Download,\n Upload,\n Info,\n X,\n SendHorizontal,\n} from \"lucide-react\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport {\n InputField,\n TextareaField,\n SelectField,\n} from \"../components/FormField\";\nimport {\n StatusBadge,\n VerifiedBadge,\n FeaturedBadge,\n} from \"../components/StatusBadge\";\nimport { DataTable, DetailList } from \"../components/DataTable\";\nimport { NewSecretAlert } from \"../components/SecretDisplay\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { LoadingState } from \"../components/LoadingState\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { SelectionCheckbox } from \"../components/SelectionCheckbox\";\nimport { GrantDelegationModal } from \"../components/GrantDelegationModal\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { usePackageUpload } from \"../hooks/usePackageUpload\";\nimport { nativeNotify } from \"../../utils/nativeBridge\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalPermission } from \"../hooks/usePermission\";\nimport type {\n Application,\n ApplicationVersion,\n Webhook as WebhookType,\n ApplicationAnalytics,\n AppUserDelegation,\n DelegationStatus,\n} from \"../types\";\nimport { cn } from \"../utils/cn\";\nimport { APP_TYPE_LABELS } from \"../utils/constants\";\nimport {\n useGetApplicationQuery,\n useGetWebhooksQuery,\n useGetApplicationAnalyticsQuery,\n useCurrentUserDelegationsQuery,\n useDeactivateAppMutation,\n useRotateAppSecretMutation,\n useRevokeDelegationMutation,\n useUpdateApplicationMutation,\n useInstallApplicationMutation,\n useUninstallApplicationMutation,\n useGetWorkspaceInstallationQuery,\n useSubmitApplicationMutation,\n useGetStoreInstallationsQuery,\n useGetMyPublisherQuery,\n useGetPublisherProductsQuery,\n type ApplicationScopeFieldsFragment,\n} from \"../../generated/global-operations\";\n\n// =============================================================================\n// HELPERS\n// =============================================================================\n\n/** Safely map GraphQL response to Application type */\nfunction mapToApplication(\n data: NonNullable<\n ReturnType<typeof useGetApplicationQuery>[\"data\"]\n >[\"application\"],\n): Application | null {\n if (!data) return null;\n return {\n id: data.id,\n name: data.name,\n slug: data.slug,\n shortDescription: data.shortDescription || undefined,\n description: data.description || undefined,\n appType: data.appType,\n status: data.status,\n visibility: data.visibility,\n tenantId: data.tenantId,\n developerId: data.developerId,\n developerOrganizationId: data.developerOrganizationId || undefined,\n category: data.category || undefined,\n tags: data.tags || [],\n keywords: data.keywords || [],\n iconUrl: data.iconUrl || undefined,\n bannerUrl: data.bannerUrl || undefined,\n videoUrl: data.videoUrl || undefined,\n screenshots: data.screenshots ?? undefined,\n websiteUrl: data.websiteUrl || undefined,\n documentationUrl: data.documentationUrl || undefined,\n supportUrl: data.supportUrl || undefined,\n privacyPolicyUrl: data.privacyPolicyUrl || undefined,\n termsOfServiceUrl: data.termsOfServiceUrl || undefined,\n githubUrl: data.githubUrl || undefined,\n pricingType: data.pricingType || undefined,\n pricingDetails: data.pricingDetails ?? undefined,\n manifest: data.manifest ?? undefined,\n reviewNotes: data.reviewNotes || undefined,\n reviewedBy: data.reviewedBy || undefined,\n installCount: data.installCount,\n activeInstallCount: data.activeInstallCount,\n averageRating: data.averageRating ?? undefined,\n reviewCount: data.reviewCount,\n submittedAt: data.submittedAt || undefined,\n publishedAt: data.publishedAt || undefined,\n lastReviewedAt: data.lastReviewedAt || undefined,\n reviewStatus: data.reviewStatus,\n isFeatured: data.isFeatured,\n isVerified: data.isVerified,\n requiresApproval: data.requiresApproval,\n appId: data.appId || undefined,\n scopes: data.scopes?.map((s: ApplicationScopeFieldsFragment) => ({\n id: s.id,\n applicationId: s.applicationId,\n scope: s.scope,\n description: s.description || undefined,\n isRequired: s.isRequired,\n createdAt: s.createdAt,\n })),\n versions: (data.versions?.edges as Array<{ node: ApplicationVersion }> | undefined)?.map((e) => e.node),\n createdAt: data.createdAt,\n updatedAt: data.updatedAt,\n };\n}\n\n/**\n * Note: OAuth client and API key mappers removed.\n * OAuth apps and API keys are now managed centrally via auth-svc\n * (see /oauth and /api-keys routes).\n */\n\n/** Map GraphQL webhook response to local Webhook type */\nfunction mapToWebhook(\n gqlWebhook: NonNullable<\n ReturnType<typeof useGetWebhooksQuery>[\"data\"]\n >[\"webhooks\"][number],\n): WebhookType {\n return {\n id: gqlWebhook.id,\n applicationId: gqlWebhook.applicationId,\n name: gqlWebhook.name,\n description: gqlWebhook.description || undefined,\n url: gqlWebhook.url,\n secret: gqlWebhook.secret,\n events: gqlWebhook.events,\n isActive: gqlWebhook.isActive,\n status: gqlWebhook.status,\n maxRetries: gqlWebhook.maxRetries,\n retryDelay: gqlWebhook.retryDelay,\n retryEnabled: gqlWebhook.retryEnabled,\n lastTriggeredAt: gqlWebhook.lastTriggeredAt || undefined,\n lastSuccessAt: gqlWebhook.lastSuccessAt || undefined,\n lastFailureAt: gqlWebhook.lastFailureAt || undefined,\n lastFailureReason: gqlWebhook.lastFailureReason || undefined,\n failureCount: gqlWebhook.failureCount,\n successCount: gqlWebhook.successCount,\n createdAt: gqlWebhook.createdAt,\n updatedAt: gqlWebhook.updatedAt,\n };\n}\n\n/** Map GraphQL analytics response to local ApplicationAnalytics type */\nfunction mapToAnalytics(\n gqlAnalytics: NonNullable<\n ReturnType<typeof useGetApplicationAnalyticsQuery>[\"data\"]\n >[\"applicationAnalytics\"][number],\n): ApplicationAnalytics {\n return {\n id: gqlAnalytics.id,\n applicationId: gqlAnalytics.applicationId,\n date: gqlAnalytics.date,\n period: gqlAnalytics.period,\n apiCalls: gqlAnalytics.apiCalls,\n errors: gqlAnalytics.errors,\n sessions: gqlAnalytics.sessions,\n activeUsers: gqlAnalytics.activeUsers,\n newUsers: gqlAnalytics.newUsers,\n avgResponseTime: gqlAnalytics.avgResponseTime ?? undefined,\n avgSessionDuration: gqlAnalytics.avgSessionDuration ?? undefined,\n createdAt: gqlAnalytics.createdAt,\n };\n}\n\n/** Map GraphQL delegation response to local AppUserDelegation type */\nfunction mapToDelegation(\n gqlDelegation: NonNullable<\n ReturnType<typeof useCurrentUserDelegationsQuery>[\"data\"]\n >[\"currentUserDelegations\"][number],\n): AppUserDelegation {\n return {\n id: gqlDelegation.id,\n appId: gqlDelegation.appId,\n app: {\n id: gqlDelegation.app.id,\n name: gqlDelegation.app.name,\n description: gqlDelegation.app.description || undefined,\n type: gqlDelegation.app.type,\n status: gqlDelegation.app.status,\n },\n userId: gqlDelegation.userId,\n scopes: gqlDelegation.scopes,\n workspaceIds: gqlDelegation.workspaceIds ?? [],\n status: gqlDelegation.status as DelegationStatus,\n grantedAt: gqlDelegation.grantedAt,\n grantedBy: gqlDelegation.grantedBy,\n expiresAt: gqlDelegation.expiresAt || undefined,\n revokedAt: gqlDelegation.revokedAt || undefined,\n revokedBy: gqlDelegation.revokedBy || undefined,\n };\n}\n\n// =============================================================================\n// TAB DEFINITIONS\n// =============================================================================\n\ntype TabId =\n | \"overview\"\n | \"permissions\"\n | \"webhooks\"\n | \"delegations\"\n | \"analytics\"\n | \"playground\"\n | \"store-listing\";\n\nconst tabs: Array<{ id: TabId; label: string; icon: FC<{ size?: number }> }> = [\n { id: \"overview\", label: \"Overview\", icon: AppWindow },\n { id: \"permissions\", label: \"Permissions\", icon: Shield },\n { id: \"webhooks\", label: \"Webhooks\", icon: Webhook },\n { id: \"delegations\", label: \"Delegations\", icon: Users },\n { id: \"analytics\", label: \"Analytics\", icon: BarChart3 },\n { id: \"playground\", label: \"API Playground\", icon: ExternalLink },\n { id: \"store-listing\", label: \"Marketplace Listing\", icon: Store },\n];\n\n// =============================================================================\n// DELEGATION STATUS HELPERS\n// =============================================================================\n\nconst DELEGATION_STATUS_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-secondary\",\n};\n\n// =============================================================================\n// TAB LOADING SPINNER\n// =============================================================================\n\nconst TabLoadingSpinner: FC<{ message?: string }> = ({\n message = \"Loading...\",\n}) => (\n <div className=\"flex items-center justify-center gap-3 py-12\">\n <Loader2 size={20} className=\"animate-spin text-muted-foreground\" />\n <p className=\"text-sm text-muted-foreground\">{message}</p>\n </div>\n);\n\nconst TabErrorState: FC<{ message: string }> = ({ message }) => (\n <div className=\"flex flex-col items-center justify-center gap-2 py-12 text-center\">\n <AlertCircle size={32} className=\"text-destructive\" />\n <p className=\"text-sm text-muted-foreground\">{message}</p>\n </div>\n);\n\n// =============================================================================\n// MAIN PAGE COMPONENT\n// =============================================================================\n\n/**\n * Application detail page with tabbed navigation\n */\nexport const ApplicationDetailPage: FC = () => {\n const { navigate, basePath, workspaceId } = 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 { allowed: canUpdate } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_UPDATE,\n );\n const { allowed: canDelete } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.APP_DELETE,\n );\n const { appId } = useParams<{ appId: string }>();\n const [searchParams, setSearchParams] = useSearchParams();\n const VALID_TABS: TabId[] = [\"overview\",\"permissions\",\"webhooks\",\"delegations\",\"analytics\",\"playground\",\"store-listing\"];\n const tabParam = searchParams.get(\"tab\") as TabId | null;\n const [activeTab, setActiveTab] = useState<TabId>(\n tabParam && VALID_TABS.includes(tabParam) ? tabParam : \"overview\",\n );\n\n // Sync state when the URL param changes (e.g. navigating via a link on the same mounted page)\n useEffect(() => {\n if (tabParam && VALID_TABS.includes(tabParam) && tabParam !== activeTab) {\n setActiveTab(tabParam);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [tabParam]);\n\n const handleTabChange = (tab: TabId) => {\n setActiveTab(tab);\n setSearchParams((prev) => { prev.set(\"tab\", tab); return prev; }, { replace: true });\n };\n\n // ---- Dialogs ----\n const [showRotateSecretDialog, setShowRotateSecretDialog] = useState(false);\n const [showDeactivateDialog, setShowDeactivateDialog] = useState(false);\n const [newSecret, setNewSecret] = useState<string | null>(null);\n const [showDelegationModal, setShowDelegationModal] = useState(false);\n\n // ---- Application query ----\n const { data, loading, error } = useGetApplicationQuery({\n variables: { id: appId! },\n skip: !appId,\n });\n\n // ---- Mutations ----\n const [rotateAppSecret, { loading: rotateLoading }] =\n useRotateAppSecretMutation();\n const [deactivateApp, { loading: deactivateLoading }] =\n useDeactivateAppMutation();\n const [installApplication, { loading: installLoading }] =\n useInstallApplicationMutation();\n const [uninstallApplication, { loading: uninstallLoading }] =\n useUninstallApplicationMutation();\n\n // ---- Workspace installation status ----\n const { data: installationData, refetch: refetchInstallation } =\n useGetWorkspaceInstallationQuery({\n variables: {\n applicationId: appId,\n workspaceId: workspaceId ?? undefined,\n },\n skip: !workspaceId || !appId,\n fetchPolicy: \"cache-and-network\",\n });\n const activeInstallation =\n installationData?.appInstallations?.edges?.[0]?.node ?? null;\n\n const handleNavigate = useCallback(\n (path: string) => {\n navigate?.(`${basePath}${path}`);\n },\n [navigate, basePath],\n );\n\n // ---- Rotate Secret ----\n const handleRotateSecret = useCallback(async () => {\n const authAppId = data?.application?.appId;\n if (!authAppId) return;\n try {\n const result = await rotateAppSecret({ variables: { id: authAppId } });\n const secret = result.data?.rotateAppSecret.clientSecret;\n if (secret) {\n setNewSecret(secret);\n }\n setShowRotateSecretDialog(false);\n } catch {\n // Error is displayed via Apollo error state\n }\n }, [data?.application?.appId, rotateAppSecret]);\n\n // ---- Deactivate App ----\n const handleDeactivateApp = useCallback(async () => {\n if (!appId) return;\n try {\n await deactivateApp({ variables: { id: appId } });\n setShowDeactivateDialog(false);\n handleNavigate(\"/apps\");\n } catch {\n // Error is displayed via Apollo error state\n }\n }, [appId, deactivateApp, handleNavigate]);\n\n // ---- Test in Workspace ----\n const handleTestInWorkspace = useCallback(async () => {\n if (!appId || !workspaceId) return;\n try {\n await installApplication({\n variables: {\n input: {\n applicationId: appId,\n scope: \"WORKSPACE\" as const,\n workspaceId,\n autoUpdate: false,\n },\n },\n });\n void refetchInstallation();\n void nativeNotify(\"success\");\n } catch (err) {\n console.error(\"[DevPortal] Test in Workspace failed:\", err);\n void nativeNotify(\"error\");\n }\n }, [appId, workspaceId, installApplication, refetchInstallation]);\n\n const handleTestInWorkflowBuilder = useCallback(async () => {\n if (!appId || !workspaceId) return;\n try {\n if (!activeInstallation) {\n await installApplication({\n variables: {\n input: {\n applicationId: appId,\n scope: \"WORKSPACE\" as const,\n workspaceId,\n autoUpdate: false,\n },\n },\n });\n await refetchInstallation();\n }\n navigate?.(\"/workflows/new\");\n } catch (err) {\n console.error(\"[DevPortal] Test in Workflow Builder failed:\", err);\n void nativeNotify(\"error\");\n }\n }, [appId, workspaceId, installApplication, activeInstallation, refetchInstallation, navigate]);\n\n // ---- Uninstall from Workspace ----\n const handleUninstall = useCallback(\n async (installationId: string) => {\n try {\n await uninstallApplication({ variables: { id: installationId } });\n void refetchInstallation();\n void nativeNotify(\"success\");\n } catch {\n void nativeNotify(\"error\");\n }\n },\n [uninstallApplication, refetchInstallation],\n );\n\n // ---- Loading / Error / Not Found ----\n // Only show full-page loading on initial load (no cached data yet).\n // With cache-and-network, Apollo sets loading:true on background refetches even\n // when data is already in cache — guarding on !data prevents StoreListingTab\n // (and other tab panels) from unmounting and losing their local form state.\n if (loading && !data) {\n return (\n <LoadingState\n message={tr(\"devportal.loadingApplication\", \"Loading application...\")}\n />\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title={tr(\"devportal.error\", \"Error\")}\n backLink={`${basePath}/apps`}\n backLabel={tr(\"devportal.backToApplications\", \"Back to Applications\")}\n >\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <AlertCircle size={48} className=\"text-destructive mb-4\" />\n <h3 className=\"text-lg font-semibold mb-2\">\n {tr(\n \"devportal.failedToLoadApplication\",\n \"Failed to load application\",\n )}\n </h3>\n <p className=\"text-sm text-muted-foreground\">{error.message}</p>\n </div>\n </PageLayout>\n );\n }\n\n const app = mapToApplication(data?.application);\n\n if (!app) {\n return (\n <PageLayout\n title={tr(\"devportal.notFound\", \"Not Found\")}\n backLink={`${basePath}/apps`}\n backLabel={tr(\"devportal.backToApplications\", \"Back to Applications\")}\n >\n <EmptyState\n icon={<AppWindow size={48} />}\n title={tr(\"devportal.applicationNotFound\", \"Application not found\")}\n description={tr(\n \"devportal.applicationNotFoundDescription\",\n \"The application you're looking for doesn't exist or you don't have access to it.\",\n )}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={app.name}\n description={app.shortDescription}\n backLink={`${basePath}/apps`}\n backLabel={tr(\"devportal.backToApplications\", \"Back to Applications\")}\n actions={\n <div className=\"flex items-center gap-2\">\n {app.appType !== \"NODE\" && app.appType !== \"WORKFLOW\" && (\n <button\n onClick={() => setShowRotateSecretDialog(true)}\n disabled={!app.appId}\n title={\n app.appId\n ? tr(\n \"devportal.rotateSecretHint\",\n \"Generate a new client secret\",\n )\n : tr(\n \"devportal.rotateSecretNoClient\",\n \"Create an OAuth client first to enable secret rotation\",\n )\n }\n className=\"inline-flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <RefreshCw size={16} />\n {tr(\"devportal.rotateSecret\", \"Rotate Secret\")}\n </button>\n )}\n <button\n onClick={() => handleNavigate(`/apps/${app.id}/versions`)}\n className=\"inline-flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted transition-colors\"\n >\n <Clock size={16} />\n {tr(\"devportal.versions\", \"Versions\")}\n </button>\n {app.status !== \"PUBLISHED\" && (\n <button\n onClick={() => handleNavigate(`/apps/${app.id}/publish`)}\n className=\"inline-flex items-center gap-2 rounded-md border border-primary/40 px-4 py-2 text-sm font-medium text-primary hover:bg-primary/10 transition-colors\"\n >\n <SendHorizontal size={16} />\n {tr(\"devportal.submitForReview\", \"Submit for Review\")}\n </button>\n )}\n {app.appType !== \"NODE\" &&\n app.appType !== \"WORKFLOW\" &&\n (activeInstallation ? (\n <button\n onClick={() => void handleUninstall(activeInstallation.id)}\n disabled={uninstallLoading || !workspaceId}\n title={tr(\n \"devportal.uninstallFromWorkspace\",\n \"Uninstall this app from your current workspace\",\n )}\n className=\"inline-flex items-center gap-2 rounded-md border border-destructive/50 px-4 py-2 text-sm font-medium text-destructive hover:bg-destructive/10 transition-colors disabled:opacity-50\"\n >\n {uninstallLoading ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : (\n <XCircle size={16} />\n )}\n {tr(\n \"devportal.uninstallFromWorkspace\",\n \"Uninstall from Workspace\",\n )}\n </button>\n ) : (\n <button\n onClick={() => void handleTestInWorkspace()}\n disabled={installLoading || !workspaceId}\n aria-disabled={!workspaceId}\n title={\n workspaceId\n ? tr(\n \"devportal.testInWorkspaceHint\",\n \"Install this app into your current workspace to test it\",\n )\n : tr(\n \"devportal.noWorkspaceContext\",\n \"No workspace context available\",\n )\n }\n className=\"inline-flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted transition-colors disabled:opacity-50\"\n >\n {installLoading ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : (\n <FlaskConical size={16} />\n )}\n {tr(\"devportal.testInWorkspace\", \"Test in Workspace\")}\n </button>\n ))}\n {app.appType === \"NODE\" && (\n <button\n onClick={() => void handleTestInWorkflowBuilder()}\n disabled={installLoading || !workspaceId}\n aria-disabled={!workspaceId}\n title={\n workspaceId\n ? activeInstallation\n ? tr(\n \"devportal.testInWorkflowBuilderHint\",\n \"Open the workflow builder (already installed in workspace)\",\n )\n : tr(\n \"devportal.testInWorkflowBuilderInstallHint\",\n \"Install this node in your workspace and open the workflow builder\",\n )\n : tr(\n \"devportal.noWorkspaceContext\",\n \"No workspace context available\",\n )\n }\n className=\"inline-flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted transition-colors disabled:opacity-50\"\n >\n {installLoading ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : (\n <FlaskConical size={16} />\n )}\n {tr(\n \"devportal.testInWorkflowBuilder\",\n \"Test in Workflow Builder\",\n )}\n </button>\n )}\n <button\n onClick={() => handleNavigate(`/apps/${app.id}/edit`)}\n disabled={!canUpdate}\n aria-disabled={!canUpdate}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n <Edit size={16} />\n {tr(\"devportal.editApp\", \"Edit App\")}\n </button>\n <button\n onClick={() => setShowDeactivateDialog(true)}\n disabled={!canDelete}\n aria-disabled={!canDelete}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle transition-colors disabled:opacity-50\"\n >\n <Power size={16} />\n {tr(\"devportal.deactivate\", \"Deactivate\")}\n </button>\n </div>\n }\n >\n {/* New Secret Alert (shown after rotation) */}\n {newSecret && (\n <NewSecretAlert\n title={tr(\n \"devportal.newAppSecretGenerated\",\n \"New App Secret Generated\",\n )}\n secret={newSecret}\n description={tr(\n \"devportal.appSecretRotatedDescription\",\n \"Your app secret has been rotated. The old secret is no longer valid.\",\n )}\n onDismiss={() => setNewSecret(null)}\n />\n )}\n\n {/* Status badges */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge status={app.status} type=\"app\" />\n <StatusBadge status={app.visibility} type=\"app\" />\n {app.isVerified && <VerifiedBadge verified />}\n {app.isFeatured && <FeaturedBadge />}\n <span className=\"text-sm text-muted-foreground\">\n {APP_TYPE_LABELS[app.appType] || app.appType}\n </span>\n </div>\n\n {/* Tabs */}\n <div className=\"border-b\">\n <nav\n className=\"-mb-px flex gap-4 overflow-x-auto\"\n role=\"tablist\"\n aria-label={tr(\n \"devportal.applicationSections\",\n \"Application sections\",\n )}\n >\n {tabs\n .filter((tab) => {\n const isPackageType =\n app.appType === \"NODE\" || app.appType === \"WORKFLOW\";\n if (\n isPackageType &&\n (tab.id === \"permissions\" ||\n tab.id === \"webhooks\" ||\n tab.id === \"delegations\" ||\n tab.id === \"playground\")\n ) {\n return false;\n }\n return true;\n })\n .map((tab) => {\n const Icon = tab.icon;\n return (\n <button\n key={tab.id}\n id={`application-tab-${tab.id}`}\n role=\"tab\"\n aria-selected={activeTab === tab.id}\n aria-controls={`application-panel-${tab.id}`}\n onClick={() => handleTabChange(tab.id)}\n className={cn(\n \"flex items-center gap-2 border-b-2 px-1 py-3 text-sm font-medium transition-colors\",\n activeTab === tab.id\n ? \"border-primary text-primary\"\n : \"border-transparent text-muted-foreground hover:text-foreground hover:border-muted-foreground\",\n )}\n >\n <Icon size={16} />\n {tab.label}\n </button>\n );\n })}\n </nav>\n </div>\n\n {/* Tab content */}\n <div\n className=\"mt-6\"\n id={`application-panel-${activeTab}`}\n role=\"tabpanel\"\n aria-labelledby={`application-tab-${activeTab}`}\n tabIndex={0}\n >\n {activeTab === \"overview\" && <OverviewTab app={app} />}\n {activeTab === \"permissions\" && <PermissionsTab app={app} />}\n {activeTab === \"webhooks\" && (\n <WebhooksTabConnected appId={app.id} onNavigate={handleNavigate} />\n )}\n {activeTab === \"delegations\" && (\n <DelegationsTabConnected\n authAppId={app.appId || undefined}\n appName={app.name}\n onGrantDelegation={() => setShowDelegationModal(true)}\n onNavigate={handleNavigate}\n />\n )}\n {activeTab === \"analytics\" && <AnalyticsTabConnected app={app} />}\n {activeTab === \"playground\" && <ApiPlaygroundTab app={app} />}\n {activeTab === \"store-listing\" && <StoreListingTab app={app} />}\n </div>\n\n {/* Rotate Secret Confirmation */}\n <ConfirmDialog\n open={showRotateSecretDialog}\n onOpenChange={setShowRotateSecretDialog}\n onConfirm={handleRotateSecret}\n title={tr(\"devportal.rotateAppSecret\", \"Rotate App Secret\")}\n description={tr(\n \"devportal.rotateAppSecretDescription\",\n \"This will generate a new client secret and invalidate the current one. All existing integrations using the old secret will stop working immediately.\",\n )}\n confirmLabel={tr(\"devportal.rotateSecret\", \"Rotate Secret\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"warning\"\n loading={rotateLoading}\n />\n\n {/* Deactivate App Confirmation */}\n <ConfirmDialog\n open={showDeactivateDialog}\n onOpenChange={setShowDeactivateDialog}\n onConfirm={handleDeactivateApp}\n title={tr(\"devportal.deactivateApplication\", \"Deactivate Application\")}\n description={tr(\n \"devportal.deactivateApplicationDescription\",\n \"This will deactivate the application. All OAuth clients, API keys, and webhooks associated with this app will stop functioning. This action can be reversed by reactivating the app.\",\n )}\n confirmLabel={tr(\"devportal.deactivate\", \"Deactivate\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"destructive\"\n loading={deactivateLoading}\n />\n\n {/* Grant Delegation Modal */}\n <GrantDelegationModal\n open={showDelegationModal}\n onOpenChange={setShowDelegationModal}\n appId={app.appId || \"\"}\n appName={app.name}\n appScopes={app.scopes?.map((s) => s.scope) ?? []}\n onSuccess={() => {\n setShowDelegationModal(false);\n }}\n />\n </PageLayout>\n );\n};\n\n// =============================================================================\n// CONNECTED TAB WRAPPERS (data-fetching layer)\n// =============================================================================\n\n/**\n * OAuth tab — now links to centralized OAuth apps page (auth-svc).\n * Previously fetched devportal-svc OAuthClients per application.\n */\nconst OAuthTabConnected: FC<{\n appId: string;\n onNavigate: (path: string) => void;\n}> = ({ onNavigate }) => {\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=\"space-y-4 py-4 text-center\">\n <Shield className=\"mx-auto h-10 w-10 text-muted-foreground\" />\n <h3 className=\"font-medium\">{tr(\"devportal.oauthApps\", \"OAuth Apps\")}</h3>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n \"devportal.oauthAppsManagedCentrally\",\n \"OAuth apps are now managed centrally. Visit the OAuth Apps page to create and manage your apps.\",\n )}\n </p>\n <button\n onClick={() => onNavigate(\"/oauth\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors\"\n >\n <ExternalLink size={16} />\n {tr(\"devportal.manageOAuthApps\", \"Manage OAuth Apps\")}\n </button>\n </div>\n );\n};\n\n/**\n * API Keys tab — now links to centralized API keys page (auth-svc).\n * Previously fetched devportal-svc ApiKeys per application.\n */\nconst ApiKeysTabConnected: FC<{\n appId: string;\n onNavigate: (path: string) => void;\n}> = ({ onNavigate }) => {\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=\"space-y-4 py-4 text-center\">\n <Key className=\"mx-auto h-10 w-10 text-muted-foreground\" />\n <h3 className=\"font-medium\">{tr(\"devportal.apiKeys\", \"API Keys\")}</h3>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n \"devportal.apiKeysManagedCentrally\",\n \"API keys are now managed centrally. Visit the API Keys page to generate and manage your keys.\",\n )}\n </p>\n <button\n onClick={() => onNavigate(\"/api-keys\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors\"\n >\n <ExternalLink size={16} />\n {tr(\"devportal.manageApiKeys\", \"Manage API Keys\")}\n </button>\n </div>\n );\n};\n\n/** Webhooks tab with real data from useGetWebhooksQuery */\nconst WebhooksTabConnected: FC<{\n appId: string;\n onNavigate: (path: string) => void;\n}> = ({ appId, onNavigate }) => {\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 { data, loading, error } = useGetWebhooksQuery({\n variables: { applicationId: appId },\n });\n\n if (loading)\n return (\n <TabLoadingSpinner\n message={tr(\"devportal.loadingWebhooks\", \"Loading webhooks...\")}\n />\n );\n if (error) return <TabErrorState message={error.message} />;\n\n const webhooks = (data?.webhooks ?? []).map(mapToWebhook);\n\n return (\n <WebhooksTab appId={appId} webhooks={webhooks} onNavigate={onNavigate} />\n );\n};\n\n/** Delegations tab with real data from useCurrentUserDelegationsQuery */\nconst DelegationsTabConnected: FC<{\n authAppId?: string;\n appName: string;\n onGrantDelegation: () => void;\n onNavigate: (path: string) => void;\n}> = ({ authAppId, appName, onGrantDelegation, onNavigate }) => {\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 { data, loading, error, refetch } = useCurrentUserDelegationsQuery();\n const [revokeDelegation] = useRevokeDelegationMutation();\n const [revokeConfirmIds, setRevokeConfirmIds] = useState<string[]>([]);\n const [revokeLoading, setRevokeLoading] = useState(false);\n const [selectedDelegationIds, setSelectedDelegationIds] = useState<\n Set<string>\n >(new Set());\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n\n const appDelegations = useMemo((): AppUserDelegation[] => {\n if (!data?.currentUserDelegations?.delegations) return [];\n return data.currentUserDelegations.delegations\n .filter((d: { appId: string }) => d.appId === authAppId)\n .map(mapToDelegation);\n }, [authAppId, data]);\n\n const activeAppDelegations = useMemo(\n () => appDelegations.filter((delegation) => delegation.status === \"ACTIVE\"),\n [appDelegations],\n );\n const selectedActiveDelegations = useMemo(\n () =>\n activeAppDelegations.filter((delegation) =>\n selectedDelegationIds.has(delegation.id),\n ),\n [activeAppDelegations, selectedDelegationIds],\n );\n const allVisibleSelected =\n activeAppDelegations.length > 0 &&\n activeAppDelegations.every((delegation) =>\n selectedDelegationIds.has(delegation.id),\n );\n const partiallySelected =\n activeAppDelegations.some((delegation) =>\n selectedDelegationIds.has(delegation.id),\n ) && !allVisibleSelected;\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 activeAppDelegations.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 [activeAppDelegations],\n );\n\n const clearSelection = useCallback(() => {\n setSelectedDelegationIds(new Set());\n }, []);\n\n const handleRevoke = useCallback(\n async (delegationIds: string[]) => {\n setRevokeLoading(true);\n try {\n const results = await Promise.allSettled(\n delegationIds.map((delegationId) =>\n revokeDelegation({ variables: { id: delegationId } }),\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 delegationIds.forEach((delegationId) => next.delete(delegationId));\n return next;\n });\n setRevokeConfirmIds([]);\n refetch();\n } catch {\n // Error handled by Apollo\n } finally {\n setRevokeLoading(false);\n }\n },\n [revokeDelegation, refetch],\n );\n\n if (!authAppId) {\n return (\n <EmptyState\n icon={<Shield size={32} />}\n title={tr(\"devportal.linkAuthAppFirst\", \"Link an auth app first\")}\n description={tr(\n \"devportal.linkAuthAppFirstDescription\",\n \"Delegations are managed through auth apps. Create or link an auth app before granting app-as-user access.\",\n )}\n action={\n <button\n onClick={() => onNavigate(\"/oauth\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n <ExternalLink size={16} />\n {tr(\"devportal.manageOAuthApps\", \"Manage OAuth Apps\")}\n </button>\n }\n />\n );\n }\n\n if (loading)\n return (\n <TabLoadingSpinner\n message={tr(\"devportal.loadingDelegations\", \"Loading delegations...\")}\n />\n );\n if (error) return <TabErrorState message={error.message} />;\n\n return (\n <>\n {successMessage && (\n <div className=\"rounded-lg border border-border-subtle bg-status-success-bg-subtle p-3 text-sm text-status-success-text\">\n <div className=\"flex items-center justify-between gap-3\">\n <span>{successMessage}</span>\n <button\n onClick={() => setSuccessMessage(null)}\n className=\"text-status-success-text hover:text-status-success-text\"\n >\n {tr(\"devportal.dismiss\", \"Dismiss\")}\n </button>\n </div>\n </div>\n )}\n\n <DelegationsTab\n appName={appName}\n delegations={appDelegations}\n onGrantDelegation={onGrantDelegation}\n onRevokeDelegation={(id) => setRevokeConfirmIds([id])}\n selectedDelegationIds={selectedDelegationIds}\n onToggleSelectDelegation={toggleDelegationSelection}\n onToggleAllDelegations={toggleAllVisibleDelegations}\n onClearSelection={clearSelection}\n onRevokeSelected={() =>\n setRevokeConfirmIds(\n selectedActiveDelegations.map((delegation) => delegation.id),\n )\n }\n allVisibleSelected={allVisibleSelected}\n partiallySelected={partiallySelected}\n />\n\n <ConfirmDialog\n open={revokeConfirmIds.length > 0}\n onOpenChange={(open) => {\n if (!open) setRevokeConfirmIds([]);\n }}\n onConfirm={() => {\n if (revokeConfirmIds.length > 0) {\n handleRevoke(revokeConfirmIds);\n }\n }}\n title={\n revokeConfirmIds.length > 1\n ? tr(\"devportal.revokeDelegations\", \"Revoke Delegations\")\n : tr(\"devportal.revokeDelegation\", \"Revoke Delegation\")\n }\n description={\n revokeConfirmIds.length > 1\n ? tr(\n \"devportal.revokeMultipleDelegationsDescription\",\n `This will immediately revoke ${revokeConfirmIds.length} selected delegations.`,\n )\n : tr(\n \"devportal.revokeDelegationDescription\",\n \"This will immediately revoke the delegation. The app will no longer be able to act on your behalf with the selected permissions.\",\n )\n }\n confirmLabel={tr(\"devportal.revoke\", \"Revoke\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"destructive\"\n loading={revokeLoading}\n />\n </>\n );\n};\n\n/** Analytics tab with real data from useGetApplicationAnalyticsQuery */\nconst AnalyticsTabConnected: FC<{ app: Application }> = ({ app }) => {\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 isPackageType = app.appType === \"NODE\" || app.appType === \"WORKFLOW\";\n\n const now = useMemo(() => new Date(), []);\n const thirtyDaysAgo = useMemo(() => {\n const d = new Date(now);\n d.setDate(d.getDate() - 30);\n return d;\n }, [now]);\n\n // For NODE/WORKFLOW: two-step lookup — get publisherId, then fetch products to find linked StoreProduct\n const { data: publisherData } = useGetMyPublisherQuery({\n fetchPolicy: \"cache-first\",\n skip: !isPackageType,\n });\n const publisherId = publisherData?.myPublisher?.id ?? null;\n\n const { data: publisherProductsData } = useGetPublisherProductsQuery({\n variables: { publisherId: publisherId ?? \"\" },\n fetchPolicy: \"cache-first\",\n skip: !isPackageType || !publisherId,\n });\n const linkedStoreProductId = publisherProductsData?.products?.find(\n (p: { id: string; productId?: string | null }) => p.productId === app.id,\n )?.id ?? null;\n\n const { data: installData, loading: installLoading } = useGetStoreInstallationsQuery({\n variables: { productId: linkedStoreProductId ?? \"\" },\n skip: !isPackageType || !linkedStoreProductId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const { data, loading, error } = useGetApplicationAnalyticsQuery({\n variables: {\n applicationId: app.id,\n period: \"daily\",\n startDate: thirtyDaysAgo.toISOString(),\n endDate: now.toISOString(),\n },\n skip: isPackageType,\n });\n\n if (isPackageType) {\n type Installation = NonNullable<typeof installData>[\"productInstallations\"][\"items\"][number];\n const installations: Installation[] = installData?.productInstallations?.items ?? [];\n const totalInstalls = installData?.productInstallations?.total ?? 0;\n const activeInstalls = installations.filter((i: Installation) => i.status === \"ACTIVE\").length;\n\n if (installLoading && !installData) {\n return (\n <TabLoadingSpinner\n message={tr(\"devportal.loadingAnalytics\", \"Loading analytics...\")}\n />\n );\n }\n\n return (\n <div className=\"space-y-6\">\n <div className=\"grid gap-4 sm:grid-cols-4\">\n <StatCard\n label={tr(\"devportal.totalInstalls\", \"Total Installs\")}\n value={totalInstalls.toLocaleString()}\n />\n <StatCard\n label={tr(\"devportal.activeInstalls\", \"Active Installs\")}\n value={activeInstalls.toLocaleString()}\n />\n <StatCard\n label={tr(\"devportal.averageRating\", \"Average Rating\")}\n value={\n app.averageRating\n ? `${app.averageRating.toFixed(1)} ★`\n : tr(\"devportal.notAvailable\", \"N/A\")\n }\n />\n <StatCard\n label={tr(\"devportal.reviews\", \"Reviews\")}\n value={app.reviewCount.toString()}\n />\n </div>\n {installations.length > 0 && (\n <PageSection title={tr(\"devportal.installBreakdown\", \"Install Breakdown\")}>\n <DataTable\n data={installations}\n keyField=\"id\"\n columns={[\n {\n key: \"workspaceId\",\n header: tr(\"devportal.workspace\", \"Workspace\"),\n render: (item) => item.workspaceId,\n },\n {\n key: \"version\",\n header: tr(\"devportal.version\", \"Version\"),\n render: (item) => item.version ?? \"—\",\n },\n {\n key: \"status\",\n header: tr(\"devportal.status\", \"Status\"),\n render: (item) => item.status,\n },\n {\n key: \"installedAt\",\n header: tr(\"devportal.installedAt\", \"Installed\"),\n render: (item) =>\n new Date(item.installedAt).toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n }),\n },\n ]}\n />\n </PageSection>\n )}\n </div>\n );\n }\n\n if (loading)\n return (\n <TabLoadingSpinner\n message={tr(\"devportal.loadingAnalytics\", \"Loading analytics...\")}\n />\n );\n if (error) return <TabErrorState message={error.message} />;\n\n const analytics = (data?.applicationAnalytics ?? []).map(mapToAnalytics);\n\n return <AnalyticsTab analytics={analytics} />;\n};\n\n// =============================================================================\n// OVERVIEW TAB\n// =============================================================================\n\nconst OverviewTab: FC<{ app: Application }> = ({ app }) => {\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 { navigate, basePath } = useDevportal();\n const isPackageType = app.appType === \"NODE\" || app.appType === \"WORKFLOW\";\n const isDraft = app.status === \"DRAFT\";\n\n type SetupStep = { label: string; done: boolean; path: string; cta: string };\n const setupSteps: SetupStep[] = isDraft\n ? [\n {\n label: \"Store listing info (name, description, category)\",\n done: !!(app.shortDescription && app.category),\n path: `${basePath}/apps/${app.id}?tab=store-listing`,\n cta: \"Fill store listing →\",\n },\n {\n label: \"Privacy policy & terms of service URLs\",\n done: !!(app.privacyPolicyUrl && app.termsOfServiceUrl),\n path: `${basePath}/apps/${app.id}?tab=store-listing`,\n cta: \"Add legal links →\",\n },\n ...(isPackageType\n ? [\n {\n label:\n app.appType === \"WORKFLOW\"\n ? \"Create a version (manifest JSON)\"\n : \"Create a version (ZIP + manifest JSON)\",\n done: (app.versions?.length ?? 0) > 0,\n path: `${basePath}/apps/${app.id}/versions`,\n cta: \"Create version →\",\n },\n ]\n : []),\n {\n label: \"Submit for marketplace review\",\n done: false,\n path: `${basePath}/apps/${app.id}/publish`,\n cta: \"Submit for review →\",\n },\n ]\n : [];\n\n const pendingSteps = setupSteps.filter((s) => !s.done);\n const nextStep = pendingSteps[0];\n\n return (\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2 space-y-6\">\n {/* Setup progress banner for DRAFT apps */}\n {isDraft && nextStep && (\n <div className=\"rounded-lg border border-primary/30 bg-primary/5 p-4 space-y-3\">\n <div className=\"flex items-center justify-between\">\n <p className=\"font-semibold text-sm text-primary\">\n {tr(\"devportal.setupProgress\", \"Setup Progress\")} — {setupSteps.filter((s) => s.done).length}/{setupSteps.length} complete\n </p>\n <button\n onClick={() => navigate?.(`${basePath}/apps/${app.id}/publish`)}\n className=\"text-xs text-primary hover:underline font-medium\"\n >\n {tr(\"devportal.viewChecklist\", \"View full checklist →\")}\n </button>\n </div>\n <div className=\"space-y-1.5\">\n {setupSteps.map((step, i) => (\n <div key={i} className=\"flex items-center gap-2 text-sm\">\n {step.done ? (\n <CheckCircle2 size={14} className=\"text-status-success-text shrink-0\" />\n ) : (\n <div className=\"h-3.5 w-3.5 rounded-full border-2 border-muted-foreground/40 shrink-0\" />\n )}\n <span className={step.done ? \"line-through text-muted-foreground\" : \"text-foreground\"}>\n {step.label}\n </span>\n {!step.done && i === setupSteps.indexOf(nextStep) && (\n <button\n onClick={() => navigate?.(step.path)}\n className=\"ml-auto text-xs text-primary hover:underline font-medium shrink-0\"\n >\n {step.cta}\n </button>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n {/* Stats */}\n <div className=\"grid gap-4 sm:grid-cols-4\">\n <StatCard\n label={tr(\"devportal.totalInstalls\", \"Total Installs\")}\n value={app.installCount.toLocaleString()}\n />\n <StatCard\n label={tr(\"devportal.activeInstalls\", \"Active Installs\")}\n value={app.activeInstallCount.toLocaleString()}\n />\n <StatCard\n label={tr(\"devportal.averageRating\", \"Average Rating\")}\n value={\n app.averageRating\n ? `${app.averageRating.toFixed(1)} ★`\n : tr(\"devportal.notAvailable\", \"N/A\")\n }\n />\n <StatCard\n label={tr(\"devportal.reviews\", \"Reviews\")}\n value={app.reviewCount.toString()}\n />\n </div>\n\n {/* Description */}\n <PageSection title={tr(\"devportal.description\", \"Description\")}>\n <div className=\"prose prose-sm max-w-none\">\n <pre className=\"whitespace-pre-wrap font-sans text-sm text-foreground bg-transparent p-0 m-0\">\n {app.description ||\n tr(\n \"devportal.noDescriptionProvided\",\n \"No description provided.\",\n )}\n </pre>\n </div>\n </PageSection>\n\n {/* Tags & Keywords */}\n <PageSection title={tr(\"devportal.tagsAndKeywords\", \"Tags & Keywords\")}>\n <div className=\"space-y-3\">\n {app.tags.length > 0 && (\n <div>\n <p className=\"text-xs text-muted-foreground mb-2\">\n {tr(\"devportal.tags\", \"Tags\")}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {app.tags.map((tag) => (\n <span\n key={tag}\n className=\"rounded-full bg-primary/10 px-3 py-1 text-xs font-medium text-primary\"\n >\n {tag}\n </span>\n ))}\n </div>\n </div>\n )}\n {app.keywords.length > 0 && (\n <div>\n <p className=\"text-xs text-muted-foreground mb-2\">\n {tr(\"devportal.keywords\", \"Keywords\")}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {app.keywords.map((keyword) => (\n <span\n key={keyword}\n className=\"rounded-full bg-muted px-3 py-1 text-xs\"\n >\n {keyword}\n </span>\n ))}\n </div>\n </div>\n )}\n </div>\n </PageSection>\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-6\">\n <PageSection title={tr(\"devportal.details\", \"Details\")}>\n <DetailList\n items={[\n {\n label: tr(\"devportal.appId\", \"App ID\"),\n value: <code className=\"text-xs\">{app.id}</code>,\n },\n { label: tr(\"devportal.slug\", \"Slug\"), value: app.slug },\n {\n label: tr(\"devportal.category\", \"Category\"),\n value:\n app.category ||\n tr(\"devportal.uncategorized\", \"Uncategorized\"),\n },\n {\n label: tr(\"devportal.pricing\", \"Pricing\"),\n value: app.pricingType || tr(\"devportal.free\", \"Free\"),\n },\n {\n label: tr(\"devportal.created\", \"Created\"),\n value: new Date(app.createdAt).toLocaleDateString(),\n },\n {\n label: tr(\"devportal.updated\", \"Updated\"),\n value: new Date(app.updatedAt).toLocaleDateString(),\n },\n {\n label: tr(\"devportal.published\", \"Published\"),\n value: app.publishedAt\n ? new Date(app.publishedAt).toLocaleDateString()\n : tr(\"devportal.notPublished\", \"Not published\"),\n },\n ]}\n />\n </PageSection>\n\n <PageSection title={tr(\"devportal.links\", \"Links\")}>\n <div className=\"space-y-2\">\n {app.websiteUrl && (\n <LinkItem\n label={tr(\"devportal.website\", \"Website\")}\n url={app.websiteUrl}\n />\n )}\n {app.documentationUrl && (\n <LinkItem\n label={tr(\"devportal.documentation\", \"Documentation\")}\n url={app.documentationUrl}\n />\n )}\n {app.supportUrl && (\n <LinkItem\n label={tr(\"devportal.support\", \"Support\")}\n url={app.supportUrl}\n />\n )}\n {app.githubUrl && (\n <LinkItem\n label={tr(\"devportal.github\", \"GitHub\")}\n url={app.githubUrl}\n />\n )}\n {app.privacyPolicyUrl && (\n <LinkItem\n label={tr(\"devportal.privacyPolicy\", \"Privacy Policy\")}\n url={app.privacyPolicyUrl}\n />\n )}\n {app.termsOfServiceUrl && (\n <LinkItem\n label={tr(\"devportal.termsOfService\", \"Terms of Service\")}\n url={app.termsOfServiceUrl}\n />\n )}\n </div>\n </PageSection>\n </div>\n </div>\n );\n};\n\n// =============================================================================\n// OAUTH TAB\n// =============================================================================\n\n/**\n * Note: OAuthTab and ApiKeysTab presentation components removed.\n * OAuth apps and API keys are now managed centrally via auth-svc.\n * The connected wrappers above link to the /oauth and /api-keys pages.\n */\n\n// =============================================================================\n// WEBHOOKS TAB\n// =============================================================================\n\nconst WebhooksTab: FC<{\n appId: string;\n webhooks: WebhookType[];\n onNavigate: (path: string) => void;\n}> = ({ appId, webhooks, onNavigate }) => {\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=\"space-y-6\">\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm text-muted-foreground\">\n {webhooks.length}{\" \"}\n {webhooks.length !== 1\n ? tr(\"devportal.webhooks\", \"webhooks\")\n : tr(\"devportal.webhook\", \"webhook\")}{\" \"}\n {tr(\"devportal.configured\", \"configured\")}\n </p>\n <button\n onClick={() => onNavigate(`/apps/${appId}/webhooks/new`)}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.addWebhook\", \"Add Webhook\")}\n </button>\n </div>\n\n {webhooks.length > 0 ? (\n <div className=\"space-y-4\">\n {webhooks.map((webhook) => (\n <div\n key={webhook.id}\n className=\"rounded-lg border bg-card p-4 space-y-4\"\n >\n <div className=\"flex items-start justify-between\">\n <div>\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-medium\">{webhook.name}</h3>\n <StatusBadge status={webhook.status} type=\"webhook\" />\n </div>\n {webhook.description && (\n <p className=\"text-sm text-muted-foreground mt-1\">\n {webhook.description}\n </p>\n )}\n </div>\n <button\n onClick={() =>\n onNavigate(`/apps/${appId}/webhooks/${webhook.id}`)\n }\n className=\"rounded-md p-1 hover:bg-muted\"\n >\n <MoreHorizontal size={20} />\n </button>\n </div>\n\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">\n {tr(\"devportal.endpointUrl\", \"Endpoint URL\")}\n </p>\n <code className=\"text-sm bg-muted px-2 py-1 rounded block truncate\">\n {webhook.url}\n </code>\n </div>\n\n <div>\n <p className=\"text-xs text-muted-foreground mb-2\">\n {tr(\"devportal.events\", \"Events\")}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {webhook.events.map((event) => (\n <span\n key={event}\n className=\"rounded-full bg-muted px-2 py-0.5 text-xs\"\n >\n {event}\n </span>\n ))}\n </div>\n </div>\n\n <div className=\"grid gap-4 sm:grid-cols-4 text-sm\">\n <div>\n <p className=\"text-xs text-muted-foreground\">\n {tr(\"devportal.success\", \"Success\")}\n </p>\n <p className=\"font-medium text-status-success-text\">\n {webhook.successCount.toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-muted-foreground\">\n {tr(\"devportal.failed\", \"Failed\")}\n </p>\n <p className=\"font-medium text-status-error-text\">\n {webhook.failureCount.toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-muted-foreground\">\n {tr(\"devportal.successRate\", \"Success Rate\")}\n </p>\n <p className=\"font-medium\">\n {webhook.successCount + webhook.failureCount > 0\n ? (\n (webhook.successCount /\n (webhook.successCount + webhook.failureCount)) *\n 100\n ).toFixed(1)\n : \"0.0\"}\n %\n </p>\n </div>\n <div>\n <p className=\"text-xs text-muted-foreground\">\n {tr(\"devportal.lastTriggered\", \"Last Triggered\")}\n </p>\n <p className=\"font-medium\">\n {webhook.lastTriggeredAt\n ? new Date(webhook.lastTriggeredAt).toLocaleString()\n : tr(\"devportal.never\", \"Never\")}\n </p>\n </div>\n </div>\n </div>\n ))}\n </div>\n ) : (\n <EmptyState\n icon={<Webhook size={32} />}\n title={tr(\"devportal.noWebhooks\", \"No webhooks\")}\n description={tr(\n \"devportal.noWebhooksDescription\",\n \"Add a webhook to receive event notifications\",\n )}\n action={\n <button\n onClick={() => onNavigate(`/apps/${appId}/webhooks/new`)}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.addWebhook\", \"Add Webhook\")}\n </button>\n }\n />\n )}\n </div>\n );\n};\n\n// =============================================================================\n// DELEGATIONS TAB\n// =============================================================================\n\nconst DelegationsTab: FC<{\n appName: string;\n delegations: AppUserDelegation[];\n onGrantDelegation: () => void;\n onRevokeDelegation: (id: string) => void;\n selectedDelegationIds: Set<string>;\n onToggleSelectDelegation: (id: string, checked: boolean) => void;\n onToggleAllDelegations: (checked: boolean) => void;\n onClearSelection: () => void;\n onRevokeSelected: () => void;\n allVisibleSelected: boolean;\n partiallySelected: boolean;\n}> = ({\n appName,\n delegations,\n onGrantDelegation,\n onRevokeDelegation,\n selectedDelegationIds,\n onToggleSelectDelegation,\n onToggleAllDelegations,\n onClearSelection,\n onRevokeSelected,\n allVisibleSelected,\n partiallySelected,\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 const activeDelegations = delegations.filter((d) => d.status === \"ACTIVE\");\n const inactiveDelegations = delegations.filter((d) => d.status !== \"ACTIVE\");\n\n return (\n <div className=\"space-y-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {delegations.length}{\" \"}\n {delegations.length !== 1\n ? tr(\"devportal.delegations\", \"delegations\")\n : tr(\"devportal.delegation\", \"delegation\")}{\" \"}\n {tr(\"devportal.for\", \"for\")} {appName}\n </p>\n {activeDelegations.length > 0 && (\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {activeDelegations.length} {tr(\"devportal.active\", \"active\")},{\" \"}\n {inactiveDelegations.length}{\" \"}\n {tr(\"devportal.revokedExpired\", \"revoked/expired\")}\n </p>\n )}\n </div>\n <button\n onClick={onGrantDelegation}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.grantDelegation\", \"Grant Delegation\")}\n </button>\n </div>\n\n {activeDelegations.length > 0 && (\n <div className=\"rounded-lg border bg-card 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={onToggleAllDelegations}\n ariaLabel={tr(\n \"devportal.selectAllActiveDelegations\",\n \"Select all active app delegations\",\n )}\n />\n <span className=\"text-sm font-medium\">\n {tr(\"devportal.selectAllActive\", \"Select all active\")}\n </span>\n </div>\n {selectedDelegationIds.size > 0 && (\n <button\n onClick={onClearSelection}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\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-muted px-3 py-1 text-sm font-medium text-muted-foreground\">\n {selectedDelegationIds.size}{\" \"}\n {tr(\"devportal.selected\", \"selected\")}\n </span>\n <button\n onClick={onRevokeSelected}\n disabled={selectedDelegationIds.size === 0}\n className=\"rounded-md border border-status-error-bg px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.revokeSelected\", \"Revoke Selected\")}\n {selectedDelegationIds.size > 0\n ? ` (${selectedDelegationIds.size})`\n : \"\"}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {delegations.length > 0 ? (\n <div className=\"space-y-4\">\n {delegations.map((delegation) => (\n <div\n key={delegation.id}\n className=\"rounded-lg border bg-card p-4 space-y-4\"\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-start gap-3\">\n {delegation.status === \"ACTIVE\" && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selectedDelegationIds.has(delegation.id)}\n onChange={(checked) =>\n onToggleSelectDelegation(delegation.id, checked)\n }\n ariaLabel={`Select delegation ${delegation.id}`}\n className=\"mt-1\"\n />\n </div>\n )}\n <div>\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-medium\">\n Delegation #{delegation.id.slice(0, 8)}\n </h3>\n <span\n className={cn(\n \"rounded-full px-2 py-0.5 text-xs font-medium\",\n DELEGATION_STATUS_STYLES[delegation.status],\n )}\n >\n {delegation.status}\n </span>\n </div>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {tr(\"devportal.granted\", \"Granted\")}{\" \"}\n {new Date(delegation.grantedAt).toLocaleDateString()}{\" \"}\n {tr(\"devportal.by\", \"by\")}{\" \"}\n {delegation.grantedBy === delegation.userId\n ? tr(\"devportal.you\", \"you\")\n : delegation.grantedBy.slice(0, 8)}\n </p>\n </div>\n </div>\n {delegation.status === \"ACTIVE\" && (\n <button\n onClick={() => onRevokeDelegation(delegation.id)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-error-text hover:bg-status-error-bg-subtle transition-colors\"\n >\n <XCircle size={14} />\n {tr(\"devportal.revoke\", \"Revoke\")}\n </button>\n )}\n </div>\n\n {/* Scopes */}\n <div>\n <p className=\"text-xs text-muted-foreground mb-2\">\n {tr(\"devportal.grantedScopes\", \"Granted Scopes\")}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {delegation.scopes.map((scope) => (\n <span\n key={scope}\n className=\"rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-xs text-status-success-text\"\n >\n {scope}\n </span>\n ))}\n </div>\n </div>\n\n {/* Workspace IDs */}\n {delegation.workspaceIds.length > 0 && (\n <div>\n <p className=\"text-xs text-muted-foreground mb-2\">\n {tr(\"devportal.workspaceScope\", \"Workspace Scope\")}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {delegation.workspaceIds.map((wsId) => (\n <code\n key={wsId}\n className=\"rounded bg-muted px-2 py-0.5 text-xs\"\n >\n {wsId}\n </code>\n ))}\n </div>\n </div>\n )}\n\n {/* Metadata */}\n <div className=\"flex items-center gap-4 text-xs text-muted-foreground\">\n {delegation.expiresAt && (\n <span className=\"flex items-center gap-1\">\n <Clock size={12} />\n {tr(\"devportal.expires\", \"Expires\")}{\" \"}\n {new Date(delegation.expiresAt).toLocaleDateString()}\n </span>\n )}\n {!delegation.expiresAt && delegation.status === \"ACTIVE\" && (\n <span className=\"flex items-center gap-1\">\n <CheckCircle\n size={12}\n className=\"text-status-success-text\"\n />\n {tr(\"devportal.noExpiration\", \"No expiration\")}\n </span>\n )}\n {delegation.revokedAt && (\n <span className=\"flex items-center gap-1\">\n <XCircle size={12} className=\"text-status-error-text\" />\n {tr(\"devportal.revoked\", \"Revoked\")}{\" \"}\n {new Date(delegation.revokedAt).toLocaleDateString()}\n </span>\n )}\n </div>\n </div>\n ))}\n </div>\n ) : (\n <EmptyState\n icon={<Users size={32} />}\n title={tr(\"devportal.noDelegations\", \"No delegations\")}\n description={tr(\n \"devportal.noDelegationsDescription\",\n \"Grant a delegation to allow this app to act on your behalf\",\n )}\n action={\n <button\n onClick={onGrantDelegation}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.grantDelegation\", \"Grant Delegation\")}\n </button>\n }\n />\n )}\n </div>\n );\n};\n\n// =============================================================================\n// ANALYTICS TAB\n// =============================================================================\n\nconst AnalyticsTab: FC<{ analytics: ApplicationAnalytics[] }> = ({\n analytics,\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 const latest = analytics[0];\n const previous = analytics[1];\n\n const calculateTrend = (current: number, prev: number) => {\n if (!prev) return 0;\n return ((current - prev) / prev) * 100;\n };\n\n return (\n <div className=\"space-y-6\">\n {/* Summary Stats */}\n <div className=\"grid gap-4 sm:grid-cols-4\">\n <StatCard\n label={tr(\"devportal.activeUsers\", \"Active Users\")}\n value={latest?.activeUsers.toLocaleString() || \"0\"}\n trend={\n previous\n ? calculateTrend(latest.activeUsers, previous.activeUsers)\n : undefined\n }\n />\n <StatCard\n label={tr(\"devportal.apiCalls\", \"API Calls\")}\n value={latest ? `${(latest.apiCalls / 1000).toFixed(1)}K` : \"0\"}\n trend={\n previous\n ? calculateTrend(latest.apiCalls, previous.apiCalls)\n : undefined\n }\n />\n <StatCard\n label={tr(\"devportal.avgResponseTime\", \"Avg Response Time\")}\n value={\n latest?.avgResponseTime\n ? `${latest.avgResponseTime}ms`\n : tr(\"devportal.notAvailable\", \"N/A\")\n }\n trend={\n previous && latest?.avgResponseTime\n ? -calculateTrend(\n latest.avgResponseTime,\n previous.avgResponseTime || 1,\n )\n : undefined\n }\n />\n <StatCard\n label={tr(\"devportal.errorRate\", \"Error Rate\")}\n value={\n latest && latest.apiCalls > 0\n ? `${((latest.errors / latest.apiCalls) * 100).toFixed(2)}%`\n : \"0%\"\n }\n trend={\n previous && latest && latest.apiCalls > 0 && previous.apiCalls > 0\n ? -calculateTrend(\n latest.errors / latest.apiCalls,\n previous.errors / previous.apiCalls,\n )\n : undefined\n }\n />\n </div>\n\n {/* Daily breakdown */}\n <PageSection title={tr(\"devportal.dailyBreakdown\", \"Daily Breakdown\")}>\n {analytics.length > 0 ? (\n <DataTable\n data={analytics}\n keyField=\"id\"\n columns={[\n {\n key: \"date\",\n header: tr(\"devportal.date\", \"Date\"),\n render: (item) => new Date(item.date).toLocaleDateString(),\n },\n {\n key: \"activeUsers\",\n header: tr(\"devportal.activeUsers\", \"Active Users\"),\n render: (item) => item.activeUsers.toLocaleString(),\n },\n {\n key: \"newUsers\",\n header: tr(\"devportal.newUsers\", \"New Users\"),\n render: (item) => item.newUsers.toLocaleString(),\n },\n {\n key: \"apiCalls\",\n header: tr(\"devportal.apiCalls\", \"API Calls\"),\n render: (item) => item.apiCalls.toLocaleString(),\n },\n {\n key: \"errors\",\n header: tr(\"devportal.errors\", \"Errors\"),\n render: (item) => item.errors.toLocaleString(),\n },\n {\n key: \"avgResponseTime\",\n header: tr(\"devportal.avgResponse\", \"Avg Response\"),\n render: (item) =>\n item.avgResponseTime\n ? `${item.avgResponseTime}ms`\n : tr(\"devportal.notAvailable\", \"N/A\"),\n },\n {\n key: \"sessions\",\n header: tr(\"devportal.sessions\", \"Sessions\"),\n render: (item) => item.sessions.toLocaleString(),\n },\n ]}\n />\n ) : (\n <EmptyState\n icon={<BarChart3 size={32} />}\n title={tr(\"devportal.noAnalyticsData\", \"No analytics data\")}\n description={tr(\n \"devportal.noAnalyticsDataDescription\",\n \"Analytics data will appear here once the application starts receiving traffic.\",\n )}\n />\n )}\n </PageSection>\n </div>\n );\n};\n\n// =============================================================================\n// API PLAYGROUND TAB\n// =============================================================================\n\nconst SAMPLE_QUERY = `# Sample query - modify as needed\nquery IntrospectSchema {\n __schema {\n queryType { name }\n mutationType { name }\n types {\n name\n kind\n }\n }\n}`;\n\nconst ApiPlaygroundTab: FC<{ app: Application }> = ({ app }) => {\n const { apiGatewayUrl, workspacesGatewayUrl, authToken } = 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 [query, setQuery] = useState(SAMPLE_QUERY);\n const [variables, setVariables] = useState(\"{}\");\n const [response, setResponse] = useState<string>(\"\");\n const [loading, setLoading] = useState(false);\n const [endpoint, setEndpoint] = useState(\n `${apiGatewayUrl || \"https://gw-global.local.burdenoff.com\"}/global/graphql`,\n );\n const [bearerToken, setBearerToken] = useState(authToken || \"\");\n const [showAuthHelp, setShowAuthHelp] = useState(false);\n\n const handleExecute = useCallback(async () => {\n setLoading(true);\n setResponse(\"\");\n try {\n let parsedVars = {};\n try {\n parsedVars = JSON.parse(variables);\n } catch {\n setResponse(\n JSON.stringify({ error: \"Invalid JSON in variables\" }, null, 2),\n );\n setLoading(false);\n return;\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (bearerToken) {\n headers[\"Authorization\"] = `Bearer ${bearerToken}`;\n }\n\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ query, variables: parsedVars }),\n });\n\n const data = await res.json();\n setResponse(JSON.stringify(data, null, 2));\n } catch (err) {\n setResponse(\n JSON.stringify(\n { error: err instanceof Error ? err.message : \"Request failed\" },\n null,\n 2,\n ),\n );\n } finally {\n setLoading(false);\n }\n }, [query, variables, endpoint, bearerToken]);\n\n const handleAutoFillCredentials = useCallback(() => {\n if (authToken) {\n setBearerToken(authToken);\n }\n setShowAuthHelp(true);\n }, [authToken]);\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-lg font-semibold\">\n {tr(\"devportal.apiPlayground\", \"API Playground\")}\n </h3>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n \"devportal.apiPlaygroundDescription\",\n \"Test GraphQL APIs in the context of\",\n )}{\" \"}\n <strong>{app.name}</strong>\n {app.appId && (\n <span className=\"ml-1 text-xs text-muted-foreground\">\n (OAuth App: {app.appId.slice(0, 8)}...)\n </span>\n )}\n </p>\n </div>\n <button\n onClick={handleAutoFillCredentials}\n className=\"flex items-center gap-2 rounded-md border px-3 py-1.5 text-sm font-medium hover:bg-accent transition-colors\"\n >\n <Key size={14} />\n {tr(\"devportal.autoFillCredentials\", \"Auto-fill Credentials\")}\n </button>\n </div>\n\n {showAuthHelp && (\n <div className=\"rounded-lg border bg-status-info-bg-subtle p-4 text-sm space-y-2\">\n <p className=\"font-medium text-status-info-text\">\n {tr(\"devportal.authenticationGuide\", \"Authentication Guide\")}\n </p>\n <p className=\"text-status-info-text\">\n {tr(\n \"devportal.authenticationGuideText\",\n \"Your current session token has been filled in. For app-level authentication (Client Credentials flow), use the\",\n )}{\" \"}\n <strong>{tr(\"devportal.oauthClientsTab\", \"OAuth Clients\")}</strong>{\" \"}\n {tr(\n \"devportal.authenticationGuideText2\",\n \"tab to get the app's clientId and clientSecret, then call:\",\n )}\n </p>\n <pre className=\"rounded bg-status-info-bg-subtle p-2 text-xs overflow-x-auto text-status-info-text\">\n {`mutation {\n authenticateApp(input: {\n clientId: \"<your-client-id>\"\n clientSecret: \"<your-client-secret>\"\n scopes: []\n }) {\n accessToken\n tokenType\n expiresIn\n }\n}`}\n </pre>\n <p className=\"text-status-info-text\">\n {tr(\"devportal.useReturnedAccessToken\", \"Use the returned\")}{\" \"}\n <code className=\"bg-status-info-bg-subtle px-1 rounded\">\n accessToken\n </code>{\" \"}\n {tr(\"devportal.asBearerToken\", \"as the Bearer token below.\")}\n </p>\n <button\n onClick={() => setShowAuthHelp(false)}\n className=\"text-xs text-accent-blue hover:underline\"\n >\n {tr(\"devportal.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {/* Endpoint */}\n <div>\n <label className=\"block text-sm font-medium mb-1\">\n {tr(\"devportal.gatewayEndpoint\", \"Gateway Endpoint\")}\n </label>\n <div className=\"flex gap-2\">\n <input\n type=\"text\"\n value={endpoint}\n onChange={(e) => setEndpoint(e.target.value)}\n className=\"flex-1 rounded-md border px-3 py-2 text-sm font-mono bg-background\"\n />\n <select\n onChange={(e) => setEndpoint(e.target.value)}\n className=\"rounded-md border px-3 py-2 text-sm bg-background\"\n value={endpoint}\n >\n <option\n value={`${apiGatewayUrl || \"https://gw-global.local.burdenoff.com\"}/global/graphql`}\n >\n {tr(\"devportal.globalGateway\", \"Global Gateway\")}\n </option>\n <option\n value={`${workspacesGatewayUrl || \"https://gw-wspace.local.burdenoff.com\"}/workspaces/graphql`}\n >\n {tr(\"devportal.workspaceGateway\", \"Workspace Gateway\")}\n </option>\n </select>\n </div>\n </div>\n\n {/* Bearer Token */}\n <div>\n <label className=\"block text-sm font-medium mb-1\">\n {tr(\"devportal.bearerToken\", \"Bearer Token\")}\n </label>\n <input\n type=\"password\"\n value={bearerToken}\n onChange={(e) => setBearerToken(e.target.value)}\n placeholder={tr(\n \"devportal.pasteAccessToken\",\n \"Paste access token here...\",\n )}\n className=\"w-full rounded-md border px-3 py-2 text-sm font-mono bg-background\"\n />\n </div>\n\n {/* Query + Variables side by side */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium mb-1\">\n {tr(\"devportal.query\", \"Query\")}\n </label>\n <textarea\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n className=\"w-full h-64 rounded-md border px-3 py-2 text-sm font-mono bg-background resize-y\"\n spellCheck={false}\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">\n {tr(\"devportal.variablesJson\", \"Variables (JSON)\")}\n </label>\n <textarea\n value={variables}\n onChange={(e) => setVariables(e.target.value)}\n className=\"w-full h-64 rounded-md border px-3 py-2 text-sm font-mono bg-background resize-y\"\n spellCheck={false}\n />\n </div>\n </div>\n\n {/* Execute */}\n <button\n onClick={handleExecute}\n disabled={loading}\n className=\"flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n {loading ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : (\n <ExternalLink size={16} />\n )}\n {loading\n ? tr(\"devportal.executing\", \"Executing...\")\n : tr(\"devportal.executeQuery\", \"Execute Query\")}\n </button>\n\n {/* Response */}\n {response && (\n <div>\n <label className=\"block text-sm font-medium mb-1\">\n {tr(\"devportal.response\", \"Response\")}\n </label>\n <pre className=\"w-full max-h-96 overflow-auto rounded-md border bg-muted p-4 text-xs font-mono\">\n {response}\n </pre>\n </div>\n )}\n </div>\n );\n};\n\n// =============================================================================\n// IMAGE UPLOAD COMPONENTS\n// =============================================================================\n\ninterface ImageUploadFieldProps {\n label: string;\n value: string;\n onChange: (url: string) => void;\n hint?: string;\n accept?: string;\n aspectClass?: string; // tailwind class for the preview container ratio\n upload: (file: File) => Promise<{ downloadUrl: string }>;\n uploading: boolean;\n progress: number;\n error: string | null;\n}\n\nconst ImageUploadField: FC<ImageUploadFieldProps> = ({\n label,\n value,\n onChange,\n hint,\n accept = \"image/png,image/jpeg,image/webp,image/gif,image/svg+xml\",\n aspectClass = \"aspect-square\",\n upload,\n uploading,\n progress,\n error,\n}) => {\n const inputRef = useRef<HTMLInputElement>(null);\n\n const handleFile = useCallback(\n async (file: File) => {\n try {\n const result = await upload(file);\n onChange(result.downloadUrl);\n } catch {\n // error shown via error prop\n }\n },\n [upload, onChange],\n );\n\n return (\n <div className=\"space-y-1.5\">\n <label className=\"text-sm font-medium\">{label}</label>\n <div className=\"flex gap-3 items-start\">\n {/* Preview */}\n <div\n className={cn(\n \"relative shrink-0 w-20 rounded-lg border border-border bg-bg-sunken overflow-hidden flex items-center justify-center\",\n aspectClass,\n )}\n >\n {value ? (\n <img\n src={value}\n alt={label}\n className=\"w-full h-full object-cover\"\n />\n ) : (\n <Upload size={18} className=\"text-text-secondary opacity-40\" />\n )}\n {uploading && (\n <div className=\"absolute inset-0 bg-black/40 flex flex-col items-center justify-center gap-1\">\n <Loader2 size={14} className=\"animate-spin text-white\" />\n <span className=\"text-white text-xs\">{progress}%</span>\n </div>\n )}\n </div>\n {/* URL input + upload button */}\n <div className=\"flex-1 space-y-1.5\">\n <input\n type=\"url\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n placeholder=\"https://...\"\n className=\"w-full rounded-md border border-border bg-bg-input px-3 py-1.5 text-sm placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-primary/30\"\n />\n <input\n ref={inputRef}\n type=\"file\"\n accept={accept}\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) void handleFile(f);\n e.target.value = \"\";\n }}\n />\n <button\n type=\"button\"\n disabled={uploading}\n onClick={() => inputRef.current?.click()}\n className=\"inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-xs font-medium hover:bg-muted transition-colors disabled:opacity-50\"\n >\n <Upload size={11} />\n {uploading ? `Uploading… ${progress}%` : \"Upload image\"}\n </button>\n {error && <p className=\"text-xs text-status-error-text\">{error}</p>}\n </div>\n </div>\n {hint && <p className=\"text-xs text-text-secondary\">{hint}</p>}\n </div>\n );\n};\n\ninterface ScreenshotGalleryProps {\n urls: string[];\n onChange: (urls: string[]) => void;\n upload: (file: File) => Promise<{ downloadUrl: string }>;\n uploading: boolean;\n progress: number;\n error: string | null;\n}\n\nconst ScreenshotGallery: FC<ScreenshotGalleryProps> = ({\n urls,\n onChange,\n upload,\n uploading,\n progress,\n error,\n}) => {\n const inputRef = useRef<HTMLInputElement>(null);\n\n const handleFile = useCallback(\n async (file: File) => {\n try {\n const result = await upload(file);\n onChange([...urls, result.downloadUrl]);\n } catch {\n // error shown via error prop\n }\n },\n [upload, onChange, urls],\n );\n\n const remove = (idx: number) => {\n onChange(urls.filter((_, i) => i !== idx));\n };\n\n return (\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Screenshots</label>\n <div className=\"flex flex-wrap gap-3\">\n {urls.map((url, idx) => (\n <div\n key={idx}\n className=\"relative group w-36 aspect-video rounded-lg border border-border overflow-hidden bg-bg-sunken\"\n >\n <img\n src={url}\n alt={`Screenshot ${idx + 1}`}\n className=\"w-full h-full object-cover\"\n />\n <button\n type=\"button\"\n onClick={() => remove(idx)}\n className=\"absolute top-1 right-1 rounded-full bg-black/60 text-white p-0.5 opacity-0 group-hover:opacity-100 transition-opacity\"\n >\n <X size={12} />\n </button>\n </div>\n ))}\n {/* Upload slot */}\n <button\n type=\"button\"\n disabled={uploading}\n onClick={() => inputRef.current?.click()}\n className={cn(\n \"w-36 aspect-video rounded-lg border-2 border-dashed border-border flex flex-col items-center justify-center gap-1.5 text-text-secondary hover:border-border-strong hover:bg-bg-sunken transition-colors disabled:opacity-50\",\n )}\n >\n {uploading ? (\n <>\n <Loader2 size={18} className=\"animate-spin text-primary\" />\n <span className=\"text-xs\">{progress}%</span>\n </>\n ) : (\n <>\n <Upload size={18} />\n <span className=\"text-xs\">Add screenshot</span>\n </>\n )}\n </button>\n </div>\n <input\n ref={inputRef}\n type=\"file\"\n accept=\"image/png,image/jpeg,image/webp,image/gif\"\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) void handleFile(f);\n e.target.value = \"\";\n }}\n />\n {error && <p className=\"text-xs text-status-error-text\">{error}</p>}\n </div>\n );\n};\n\n// =============================================================================\n// STORE LISTING TAB\n// =============================================================================\n\ninterface ManifestIdentity {\n version: string;\n displayName: string;\n}\n\ninterface ManifestInstall {\n type: string;\n url?: string;\n packageName?: string;\n registryUrl?: string;\n}\n\ninterface ManifestDigital {\n install: ManifestInstall;\n}\n\ninterface ManifestCompatibility {\n minPlatformVersion: string;\n}\n\ninterface StoreManifest {\n manifestVersion: string;\n itemType?: string;\n identity: ManifestIdentity;\n digital?: ManifestDigital;\n jsonContent?: string;\n permissions: string[];\n compatibility: ManifestCompatibility;\n}\n\ninterface StoreListingFormData {\n // Store Presentation\n iconUrl: string;\n bannerUrl: string;\n videoUrl: string;\n shortDescription: string;\n description: string;\n screenshotsText: string;\n // Links & Policies\n websiteUrl: string;\n documentationUrl: string;\n githubUrl: string;\n supportUrl: string;\n privacyPolicyUrl: string;\n termsOfServiceUrl: string;\n // Pricing\n pricingType: string;\n price: string;\n currency: string;\n // Manifest\n manifestItemType: string;\n manifestDisplayName: string;\n manifestVersion: string;\n manifestInstallType: string;\n manifestPackageName: string;\n manifestRegistryUrl: string;\n manifestPermissionsText: string;\n manifestMinPlatformVersion: string;\n // JSON-only content (workflow / template)\n manifestJsonContent: string;\n}\n\n/** Item types whose entire payload IS a JSON document — no zip or binary needed. */\nconst JSON_ONLY_ITEM_TYPES = new Set([\"workflow\", \"template\"]);\n\nconst PRICING_TYPE_OPTIONS = [\n { value: \"FREE\", label: \"Free\" },\n { value: \"PAID\", label: \"Paid\" },\n];\n\nconst ITEM_TYPE_OPTIONS = [\n { value: \"agent\", label: \"Agent\" },\n { value: \"node\", label: \"Node\" },\n { value: \"widget\", label: \"Widget\" },\n { value: \"workflow\", label: \"Workflow\" },\n { value: \"botapp\", label: \"Bot App\" },\n { value: \"console\", label: \"Console\" },\n { value: \"vibemodule\", label: \"Vibe Module\" },\n { value: \"dashboard\", label: \"Dashboard\" },\n { value: \"parser\", label: \"Parser\" },\n { value: \"datasink\", label: \"Data Sink\" },\n { value: \"app\", label: \"App\" },\n { value: \"template\", label: \"Template\" },\n { value: \"integration\", label: \"Integration\" },\n { value: \"extension\", label: \"Extension\" },\n { value: \"theme\", label: \"Theme\" },\n { value: \"plugin\", label: \"Plugin\" },\n { value: \"component\", label: \"Component\" },\n];\n\nconst INSTALL_TYPE_OPTIONS = [\n { value: \"zip\", label: \"zip\" },\n { value: \"builtin\", label: \"builtin\" },\n];\n\nfunction buildInitialFormData(app: Application): StoreListingFormData {\n const manifest = (app.manifest ?? {}) as Record<string, unknown>;\n const identity = (manifest.identity ?? {}) as Record<string, unknown>;\n const digital = (manifest.digital ?? {}) as Record<string, unknown>;\n const install = (digital.install ?? {}) as Record<string, unknown>;\n const compatibility = (manifest.compatibility ?? {}) as Record<\n string,\n unknown\n >;\n const permissions = Array.isArray(manifest.permissions)\n ? (manifest.permissions as string[])\n : [];\n\n const pricingDetails = (app.pricingDetails ?? {}) as Record<string, unknown>;\n const screenshots = Array.isArray(app.screenshots)\n ? (app.screenshots as string[]).join(\"\\n\")\n : \"\";\n\n return {\n iconUrl: app.iconUrl ?? \"\",\n bannerUrl: app.bannerUrl ?? \"\",\n videoUrl: app.videoUrl ?? \"\",\n shortDescription: app.shortDescription ?? \"\",\n description: app.description ?? \"\",\n screenshotsText: screenshots,\n websiteUrl: app.websiteUrl ?? \"\",\n documentationUrl: app.documentationUrl ?? \"\",\n githubUrl: app.githubUrl ?? \"\",\n supportUrl: app.supportUrl ?? \"\",\n privacyPolicyUrl: app.privacyPolicyUrl ?? \"\",\n termsOfServiceUrl: app.termsOfServiceUrl ?? \"\",\n pricingType: app.pricingType ?? \"\",\n price:\n typeof pricingDetails.price === \"number\"\n ? String(pricingDetails.price)\n : \"\",\n currency:\n typeof pricingDetails.currency === \"string\"\n ? pricingDetails.currency\n : \"\",\n manifestItemType:\n typeof manifest.itemType === \"string\" ? manifest.itemType : \"\",\n manifestDisplayName:\n typeof identity.displayName === \"string\"\n ? identity.displayName\n : (app.name ?? \"\"),\n manifestVersion:\n typeof identity.version === \"string\" ? identity.version : \"\",\n manifestInstallType:\n typeof install.type === \"string\" ? install.type : \"zip\",\n manifestPackageName: \"\",\n manifestRegistryUrl:\n typeof install.url === \"string\"\n ? install.url\n : typeof install.registryUrl === \"string\"\n ? install.registryUrl\n : \"\",\n manifestPermissionsText: permissions.join(\"\\n\"),\n manifestMinPlatformVersion:\n typeof compatibility.minPlatformVersion === \"string\"\n ? compatibility.minPlatformVersion\n : \"\",\n manifestJsonContent:\n typeof manifest.jsonContent === \"string\"\n ? manifest.jsonContent\n : typeof manifest.content === \"string\"\n ? manifest.content\n : \"\",\n };\n}\n\nconst MY_PUBLISHER_QUERY = gql`\n query MyPublisherForListing {\n myPublisher { id }\n }\n`;\n\nconst PUBLISHER_PRODUCTS_QUERY = gql`\n query PublisherProductsForListing($publisherId: String!) {\n products(filter: { publisherId: $publisherId }) { id productId }\n }\n`;\n\nconst UPDATE_STORE_PRODUCT_MUTATION = gql`\n mutation UpdateStoreProduct($input: UpdateProductInput!) {\n updateProduct(input: $input) { id name description }\n }\n`;\n\nconst StoreListingTab: FC<{ app: Application }> = ({ app }) => {\n const { workspacesGatewayUrl, authToken, workspaceId, getWorkspaceToken, navigate, basePath } =\n 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\n const [formData, setFormData] = useState<StoreListingFormData>(() =>\n buildInitialFormData(app),\n );\n const [isSaving, setIsSaving] = useState(false);\n const [isDragging, setIsDragging] = useState(false);\n const appRef = useRef(app);\n appRef.current = app;\n\n const { data: publisherMeta } = useQuery<{\n myPublisher: { id: string } | null;\n }>(MY_PUBLISHER_QUERY, { fetchPolicy: \"cache-first\" });\n const myPublisherId = publisherMeta?.myPublisher?.id ?? null;\n\n const { data: publisherProds } = useQuery<{\n products: { id: string; productId?: string | null }[];\n }>(PUBLISHER_PRODUCTS_QUERY, {\n variables: { publisherId: myPublisherId ?? \"\" },\n fetchPolicy: \"cache-first\",\n skip: !myPublisherId,\n });\n const linkedStoreProductId = publisherProds?.products?.find(\n (p) => p.productId === app.id,\n )?.id ?? null;\n\n const [updateStoreProduct] = useMutation(UPDATE_STORE_PRODUCT_MUTATION);\n\n const [updateApplication] = useUpdateApplicationMutation();\n const [submitApplication, { loading: isSubmitting }] =\n useSubmitApplicationMutation();\n\n // Reset form only when navigating to a different app (not on every refetch)\n useEffect(() => {\n setFormData(buildInitialFormData(appRef.current));\n }, [app.id]);\n\n const handleChange = (field: keyof StoreListingFormData, value: string) => {\n setFormData((prev) => ({ ...prev, [field]: value }));\n };\n\n const handleSave = async () => {\n setIsSaving(true);\n try {\n const screenshotUrls = formData.screenshotsText\n .split(\"\\n\")\n .map((s) => s.trim())\n .filter(Boolean);\n\n const permissions = formData.manifestPermissionsText\n .split(\"\\n\")\n .map((s) => s.trim())\n .filter(Boolean);\n\n const isJsonOnly = JSON_ONLY_ITEM_TYPES.has(formData.manifestItemType);\n\n // Build manifest by merging existing app.manifest with form values\n const baseManifest = (app.manifest ?? {}) as Record<string, unknown>;\n const updatedManifest: StoreManifest = {\n manifestVersion:\n typeof baseManifest.manifestVersion === \"string\"\n ? baseManifest.manifestVersion\n : \"1.0\",\n itemType: formData.manifestItemType || undefined,\n identity: {\n version: formData.manifestVersion || \"1.0.0\",\n displayName: formData.manifestDisplayName,\n },\n ...(isJsonOnly\n ? { jsonContent: formData.manifestJsonContent || undefined }\n : {\n digital: {\n install: {\n type: formData.manifestInstallType,\n ...(formData.manifestInstallType === \"zip\" &&\n formData.manifestRegistryUrl\n ? { url: formData.manifestRegistryUrl }\n : {}),\n },\n },\n }),\n permissions,\n compatibility: {\n minPlatformVersion: formData.manifestMinPlatformVersion,\n },\n };\n\n const existingPricingDetails = (app.pricingDetails ?? {}) as Record<\n string,\n unknown\n >;\n const pricingDetails: Record<string, unknown> = {\n ...existingPricingDetails,\n };\n if (formData.pricingType !== \"FREE\") {\n const parsedPrice = parseFloat(formData.price);\n if (!isNaN(parsedPrice)) {\n pricingDetails.price = parsedPrice;\n }\n if (formData.currency) {\n pricingDetails.currency = formData.currency;\n }\n }\n\n await updateApplication({\n variables: {\n id: app.id,\n input: {\n iconUrl: formData.iconUrl || null,\n bannerUrl: formData.bannerUrl || null,\n videoUrl: formData.videoUrl || null,\n shortDescription: formData.shortDescription || null,\n description: formData.description || null,\n screenshots:\n screenshotUrls.length > 0\n ? (screenshotUrls as unknown as Record<string, unknown>)\n : null,\n websiteUrl: formData.websiteUrl || null,\n documentationUrl: formData.documentationUrl || null,\n githubUrl: formData.githubUrl || null,\n supportUrl: formData.supportUrl || null,\n privacyPolicyUrl: formData.privacyPolicyUrl || null,\n termsOfServiceUrl: formData.termsOfServiceUrl || null,\n pricingType: formData.pricingType || null,\n pricingDetails:\n Object.keys(pricingDetails).length > 0 ? pricingDetails : null,\n manifest: updatedManifest as unknown as Record<string, unknown>,\n },\n },\n });\n\n // Sync to linked StoreProduct if one exists\n if (linkedStoreProductId) {\n await updateStoreProduct({\n variables: {\n input: {\n id: linkedStoreProductId,\n name: app.name,\n description: formData.shortDescription || undefined,\n longDescription: formData.description || undefined,\n icon: formData.iconUrl || undefined,\n screenshots: screenshotUrls.length > 0 ? screenshotUrls : undefined,\n documentationUrl: formData.documentationUrl || undefined,\n category: app.category || undefined,\n },\n },\n });\n }\n\n void nativeNotify(\"success\");\n } catch {\n void nativeNotify(\"error\");\n } finally {\n setIsSaving(false);\n }\n };\n\n const handleSubmitForReview = async () => {\n try {\n await submitApplication({ variables: { id: app.id } });\n void nativeNotify(\"success\");\n } catch {\n void nativeNotify(\"error\");\n }\n };\n\n const manifestFileInputRef = useRef<HTMLInputElement>(null);\n const zipFileInputRef = useRef<HTMLInputElement>(null);\n const {\n upload: uploadPackage,\n uploading: packageUploading,\n progress: packageProgress,\n error: packageUploadError,\n } = usePackageUpload(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n getWorkspaceToken,\n );\n const {\n upload: uploadAsset,\n uploading: iconUploading,\n progress: iconProgress,\n error: iconUploadError,\n } = usePackageUpload(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n getWorkspaceToken,\n \"/DevPortal/Assets\",\n );\n const {\n upload: uploadBanner,\n uploading: bannerUploading,\n progress: bannerProgress,\n error: bannerUploadError,\n } = usePackageUpload(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n getWorkspaceToken,\n \"/DevPortal/Assets\",\n );\n const {\n upload: uploadScreenshot,\n uploading: screenshotUploading,\n progress: screenshotProgress,\n error: screenshotUploadError,\n } = usePackageUpload(\n workspacesGatewayUrl,\n authToken,\n workspaceId,\n getWorkspaceToken,\n \"/DevPortal/Assets\",\n );\n\n const handleZipUpload = useCallback(\n async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n e.target.value = \"\";\n try {\n const result = await uploadPackage(file);\n setFormData((prev) => ({\n ...prev,\n manifestRegistryUrl: result.downloadUrl,\n }));\n } catch {\n // error shown via packageUploadError state\n }\n },\n [uploadPackage],\n );\n\n const handleZipDrop = useCallback(\n async (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n setIsDragging(false);\n const file = e.dataTransfer.files?.[0];\n if (!file) return;\n try {\n const result = await uploadPackage(file);\n setFormData((prev) => ({\n ...prev,\n manifestRegistryUrl: result.downloadUrl,\n }));\n } catch {\n // error shown via packageUploadError state\n }\n },\n [uploadPackage],\n );\n\n const handleImportManifest = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const reader = new FileReader();\n reader.onload = (ev) => {\n try {\n const parsed = JSON.parse(ev.target?.result as string) as Record<\n string,\n unknown\n >;\n const identity = (parsed.identity ?? {}) as Record<string, unknown>;\n const digital = (parsed.digital ?? {}) as Record<string, unknown>;\n const install = (digital.install ?? {}) as Record<string, unknown>;\n const compatibility = (parsed.compatibility ?? {}) as Record<\n string,\n unknown\n >;\n const permissions = Array.isArray(parsed.permissions)\n ? (parsed.permissions as string[])\n : [];\n setFormData((prev) => ({\n ...prev,\n manifestItemType:\n typeof parsed.itemType === \"string\"\n ? parsed.itemType\n : prev.manifestItemType,\n manifestDisplayName:\n typeof identity.displayName === \"string\"\n ? identity.displayName\n : prev.manifestDisplayName,\n manifestVersion:\n typeof identity.version === \"string\"\n ? identity.version\n : prev.manifestVersion,\n manifestInstallType:\n typeof install.type === \"string\"\n ? install.type\n : prev.manifestInstallType,\n manifestRegistryUrl:\n typeof install.url === \"string\"\n ? install.url\n : typeof install.registryUrl === \"string\"\n ? install.registryUrl\n : prev.manifestRegistryUrl,\n manifestPermissionsText:\n permissions.length > 0\n ? permissions.join(\"\\n\")\n : prev.manifestPermissionsText,\n manifestMinPlatformVersion:\n typeof compatibility.minPlatformVersion === \"string\"\n ? compatibility.minPlatformVersion\n : prev.manifestMinPlatformVersion,\n }));\n } catch {\n // invalid JSON — ignore\n }\n };\n reader.readAsText(file);\n // reset so the same file can be re-imported\n e.target.value = \"\";\n },\n [],\n );\n\n const handleExportManifest = useCallback(() => {\n const permissions = formData.manifestPermissionsText\n .split(\"\\n\")\n .map((s) => s.trim())\n .filter(Boolean);\n const isJsonOnly = JSON_ONLY_ITEM_TYPES.has(formData.manifestItemType);\n const manifest: StoreManifest = {\n manifestVersion: \"1.0\",\n itemType: formData.manifestItemType || undefined,\n identity: {\n version: formData.manifestVersion || \"1.0.0\",\n displayName: formData.manifestDisplayName,\n },\n ...(isJsonOnly\n ? { jsonContent: formData.manifestJsonContent || undefined }\n : {\n digital: {\n install: {\n type: formData.manifestInstallType,\n ...(formData.manifestInstallType === \"zip\" &&\n formData.manifestRegistryUrl\n ? { url: formData.manifestRegistryUrl }\n : {}),\n },\n },\n }),\n permissions,\n compatibility: {\n minPlatformVersion: formData.manifestMinPlatformVersion,\n },\n };\n const blob = new Blob([JSON.stringify(manifest, null, 2)], {\n type: \"application/json\",\n });\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = `${app.slug}-manifest.json`;\n a.click();\n URL.revokeObjectURL(url);\n }, [app.slug, formData]);\n\n const isJsonOnlyType = JSON_ONLY_ITEM_TYPES.has(formData.manifestItemType);\n const isBuiltin = formData.manifestInstallType === \"builtin\";\n const showPriceFields = formData.pricingType !== \"FREE\";\n const zipFileName = formData.manifestRegistryUrl\n ? (formData.manifestRegistryUrl.split(\"/\").pop()?.split(\"?\")[0] ?? \"\")\n : \"\";\n\n const isDraft = app.status === \"DRAFT\";\n const isSubmitted = app.status === \"SUBMITTED\";\n const isPublished = app.status === \"PUBLISHED\";\n const isPackageType =\n app.appType === \"NODE\" || app.appType === \"WORKFLOW\";\n const isApiIntegrationType = app.appType === \"API_INTEGRATION\";\n\n const listingCompleteness = [\n { label: \"Short description\", done: !!formData.shortDescription.trim() },\n { label: \"Full description\", done: !!formData.description.trim() },\n { label: \"Icon\", done: !!formData.iconUrl.trim() },\n { label: \"Privacy Policy URL\", done: !!formData.privacyPolicyUrl.trim() },\n { label: \"Terms of Service URL\", done: !!formData.termsOfServiceUrl.trim() },\n ];\n const completedCount = listingCompleteness.filter((i) => i.done).length;\n const totalCount = listingCompleteness.length;\n\n return (\n <div className=\"space-y-8 max-w-3xl\">\n {/* ── How this works ───────────────────────────────────── */}\n <div className=\"rounded-lg border border-primary/20 bg-primary/5 px-4 py-3 space-y-2\">\n <p className=\"text-sm font-semibold text-primary\">\n {tr(\"devportal.listingTabPurpose\", \"What is this tab for?\")}\n </p>\n <ul className=\"text-sm text-muted-foreground space-y-1 list-none pl-0\">\n <li className=\"flex items-start gap-2\">\n <Store size={14} className=\"mt-0.5 shrink-0 text-primary\" />\n <span>\n <strong>\n {tr(\"devportal.thisTab\", \"This tab\")}\n </strong>{\" \"}\n {tr(\n \"devportal.listingTabDesc\",\n \"controls your store card — the name, description, icon and screenshots users see in the marketplace. Save changes here any time without creating a new release.\",\n )}\n </span>\n </li>\n {isPackageType && (\n <li className=\"flex items-start gap-2\">\n <Clock size={14} className=\"mt-0.5 shrink-0 text-primary\" />\n <span>\n {tr(\n \"devportal.versionsTabDesc\",\n \"To release a new version (ZIP package + manifest), go to the\",\n )}{\" \"}\n <button\n type=\"button\"\n className=\"underline text-primary hover:no-underline\"\n onClick={() => navigate?.(`${basePath}/apps/${app.id}/versions`)}\n >\n {tr(\"devportal.versionsTab\", \"Versions page\")}\n </button>\n .\n </span>\n </li>\n )}\n <li className=\"flex items-start gap-2\">\n <SendHorizontal size={14} className=\"mt-0.5 shrink-0 text-primary\" />\n <span>\n {tr(\n \"devportal.submitTabDesc\",\n 'When your listing is ready, click \"Submit for Review\" to send it to the review team.',\n )}\n </span>\n </li>\n </ul>\n </div>\n\n {/* ── Listing completeness ─────────────────────────────── */}\n {!isPublished && (\n <div className=\"rounded-lg border bg-card p-4 space-y-3\">\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm font-medium\">\n {tr(\"devportal.listingCompleteness\", \"Listing completeness\")}{\" \"}\n <span\n className={cn(\n \"ml-1 text-xs font-semibold\",\n completedCount === totalCount\n ? \"text-status-success-text\"\n : \"text-status-warning-text\",\n )}\n >\n {completedCount}/{totalCount}\n </span>\n </p>\n {completedCount === totalCount && (\n <span className=\"text-xs text-status-success-text flex items-center gap-1\">\n <CheckCircle size={12} />\n {tr(\"devportal.readyToSubmit\", \"Ready to submit\")}\n </span>\n )}\n </div>\n <div className=\"grid grid-cols-2 sm:grid-cols-3 gap-2\">\n {listingCompleteness.map((item) => (\n <div key={item.label} className=\"flex items-center gap-1.5 text-xs\">\n {item.done ? (\n <CheckCircle size={12} className=\"text-status-success-text shrink-0\" />\n ) : (\n <AlertCircle size={12} className=\"text-status-warning-text shrink-0\" />\n )}\n <span\n className={\n item.done ? \"text-foreground\" : \"text-muted-foreground\"\n }\n >\n {item.label}\n </span>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* ── Status banner ─────────────────────────────────────── */}\n {isPublished ? (\n <div className=\"flex items-start gap-3 rounded-lg border border-success/30 bg-success/10 px-4 py-3\">\n <CheckCircle size={16} className=\"text-success mt-0.5 shrink-0\" />\n <div className=\"text-sm\">\n <span className=\"font-medium text-success\">\n {tr(\"devportal.storeListing.published\", \"Published\")}\n </span>\n {app.publishedAt && (\n <span className=\"text-muted-foreground ml-2\">\n {tr(\"devportal.storeListing.since\", \"since\")}{\" \"}\n {new Date(app.publishedAt).toLocaleDateString()}\n </span>\n )}\n </div>\n </div>\n ) : isSubmitted ? (\n <div className=\"flex items-start gap-3 rounded-lg border border-primary/30 bg-primary/5 px-4 py-3\">\n <Clock size={16} className=\"text-primary mt-0.5 shrink-0\" />\n <div className=\"text-sm\">\n <span className=\"font-medium text-primary\">\n {tr(\"devportal.storeListing.underReview\", \"Submitted for review\")}\n </span>\n {app.submittedAt && (\n <span className=\"text-muted-foreground ml-2\">\n {new Date(app.submittedAt).toLocaleDateString()}\n </span>\n )}\n {app.reviewStatus && (\n <span className=\"text-muted-foreground ml-2\">\n · {app.reviewStatus}\n </span>\n )}\n </div>\n </div>\n ) : (\n <div className=\"flex items-start gap-3 rounded-lg border border-warning/30 bg-warning/5 px-4 py-3\">\n <AlertCircle size={16} className=\"text-warning mt-0.5 shrink-0\" />\n <div className=\"text-sm\">\n <span className=\"font-medium text-warning\">\n {tr(\"devportal.storeListing.draft\", \"Draft\")}\n </span>\n <span className=\"text-muted-foreground ml-2\">\n {tr(\n \"devportal.storeListing.draftHint\",\n \"Complete your store listing and submit for review to publish.\",\n )}\n </span>\n </div>\n </div>\n )}\n\n {/* ── Section 1: Package ─────────────────────────────────── */}\n {isPackageType ? (\n <div className=\"rounded-lg border border-border-subtle bg-bg-sunken px-4 py-4 flex items-start gap-3\">\n <Info size={16} className=\"shrink-0 mt-0.5 text-muted-foreground\" />\n <div className=\"text-sm space-y-1\">\n <p className=\"font-medium\">\n {tr(\"devportal.packageManagedInVersions\", \"ZIP package & manifest are managed in Versions\")}\n </p>\n <p className=\"text-muted-foreground\">\n {tr(\n \"devportal.packageManagedInVersionsDesc\",\n \"For NODE and WORKFLOW types, each release is uploaded through the Versions page — including the ZIP archive and manifest.json. This keeps your code releases separate from your store card.\",\n )}\n </p>\n </div>\n </div>\n ) : !isApiIntegrationType && (\n <PageSection\n title={tr(\"devportal.package\", \"Package\")}\n description={tr(\n \"devportal.packageDescription\",\n \"Technical configuration — how FluidGrid installs and runs this item\",\n )}\n >\n <div className=\"space-y-6\">\n {/* Item type — the most important choice */}\n <SelectField\n label={tr(\"devportal.storeItemType\", \"Item Type\")}\n value={formData.manifestItemType}\n onChange={(e) => {\n const next = e.target.value;\n handleChange(\"manifestItemType\", next);\n if (JSON_ONLY_ITEM_TYPES.has(next)) {\n handleChange(\"manifestInstallType\", \"json\");\n } else if (formData.manifestInstallType === \"json\") {\n handleChange(\"manifestInstallType\", \"zip\");\n }\n }}\n options={ITEM_TYPE_OPTIONS}\n placeholder={tr(\"devportal.selectItemType\", \"Select item type…\")}\n hint={tr(\n \"devportal.storeItemTypeHint\",\n \"Determines how this item is categorised and how the platform runs it\",\n )}\n />\n\n {/* Identity */}\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <InputField\n label={tr(\"devportal.manifestDisplayName\", \"Display Name\")}\n value={formData.manifestDisplayName}\n onChange={(e) =>\n handleChange(\"manifestDisplayName\", e.target.value)\n }\n placeholder=\"My Awesome Node\"\n />\n <InputField\n label={tr(\"devportal.manifestVersion\", \"Version\")}\n value={formData.manifestVersion}\n onChange={(e) => handleChange(\"manifestVersion\", e.target.value)}\n placeholder=\"1.0.0\"\n hint={tr(\n \"devportal.semverHint\",\n \"Semantic version (MAJOR.MINOR.PATCH)\",\n )}\n />\n </div>\n\n {/* JSON editor for workflow / template types */}\n {isJsonOnlyType && (\n <TextareaField\n label={tr(\n \"devportal.jsonContent\",\n formData.manifestItemType === \"workflow\"\n ? \"Workflow Definition (JSON)\"\n : \"Template Definition (JSON)\",\n )}\n value={formData.manifestJsonContent}\n onChange={(e) =>\n handleChange(\"manifestJsonContent\", e.target.value)\n }\n rows={12}\n placeholder={'{\\n \"nodes\": [],\\n \"edges\": []\\n}'}\n hint={tr(\n \"devportal.jsonContentHint\",\n \"Paste the full JSON definition. Stored and applied directly — no zip needed.\",\n )}\n />\n )}\n\n {/* Package delivery — for code-bearing items */}\n {!isJsonOnlyType && (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between flex-wrap gap-2\">\n <label className=\"text-sm font-medium\">\n {tr(\"devportal.packageFile\", \"Package File\")}\n </label>\n <label className=\"flex items-center gap-2 text-sm cursor-pointer select-none\">\n <input\n type=\"checkbox\"\n checked={isBuiltin}\n onChange={(e) =>\n handleChange(\n \"manifestInstallType\",\n e.target.checked ? \"builtin\" : \"zip\",\n )\n }\n className=\"h-4 w-4 rounded border-border accent-primary\"\n />\n <span className=\"text-text-secondary\">\n {tr(\n \"devportal.builtinToggle\",\n \"Built-in (pre-installed, no upload needed)\",\n )}\n </span>\n </label>\n </div>\n\n {!isBuiltin && (\n <>\n <div className=\"flex gap-3 rounded-lg border border-border-subtle bg-bg-sunken p-3 text-sm text-text-secondary\">\n <Info size={15} className=\"mt-0.5 shrink-0\" />\n <span>\n {tr(\"devportal.zipModelHint\", \"Package your code and a \")}\n <code className=\"rounded bg-muted px-1 py-0.5 font-mono text-xs\">\n manifest.json\n </code>\n {tr(\n \"devportal.zipModelHint2\",\n \" into a single zip — like a Chrome extension. Upload it below and FluidGrid handles the rest automatically.\",\n )}\n </span>\n </div>\n\n {/* Drag-and-drop upload zone */}\n <div\n onDragOver={(e) => {\n e.preventDefault();\n setIsDragging(true);\n }}\n onDragLeave={() => setIsDragging(false)}\n onDrop={(e) => void handleZipDrop(e)}\n onClick={() =>\n !packageUploading && zipFileInputRef.current?.click()\n }\n className={cn(\n \"relative flex flex-col items-center justify-center gap-3 rounded-xl border-2 border-dashed px-6 py-10 text-center transition-colors cursor-pointer\",\n isDragging\n ? \"border-primary bg-primary/5\"\n : \"border-border hover:border-border-strong hover:bg-bg-sunken\",\n packageUploading && \"pointer-events-none opacity-75\",\n )}\n >\n <input\n ref={zipFileInputRef}\n type=\"file\"\n accept=\".zip,application/zip,application/x-zip-compressed\"\n className=\"hidden\"\n onChange={(e) => void handleZipUpload(e)}\n />\n {packageUploading ? (\n <>\n <Loader2\n size={28}\n className=\"animate-spin text-primary\"\n />\n <div>\n <p className=\"text-sm font-medium\">\n {tr(\"devportal.uploading\", \"Uploading…\")}{\" \"}\n {packageProgress}%\n </p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {tr(\n \"devportal.uploadingHint\",\n \"Stored securely in your workspace\",\n )}\n </p>\n </div>\n <div className=\"w-48 h-1.5 rounded-full bg-muted overflow-hidden\">\n <div\n className=\"h-full bg-primary transition-all\"\n style={{ width: `${packageProgress}%` }}\n />\n </div>\n </>\n ) : zipFileName ? (\n <>\n <CheckCircle\n size={28}\n className=\"text-status-success-text\"\n />\n <div>\n <p className=\"text-sm font-medium\">{zipFileName}</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {tr(\n \"devportal.clickToReplace\",\n \"Click or drag to replace\",\n )}\n </p>\n </div>\n </>\n ) : (\n <>\n <Upload size={28} className=\"text-text-secondary\" />\n <div>\n <p className=\"text-sm font-medium\">\n {tr(\"devportal.dropZipHere\", \"Drop your .zip here\")}\n </p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {tr(\n \"devportal.orClickToBrowse\",\n \"or click to browse\",\n )}\n </p>\n </div>\n </>\n )}\n </div>\n {packageUploadError && (\n <p className=\"text-xs text-status-error-text\">\n {packageUploadError}\n </p>\n )}\n </>\n )}\n\n {isBuiltin && (\n <div className=\"flex gap-3 rounded-lg border border-border-subtle bg-bg-sunken p-3 text-sm text-text-secondary\">\n <Info size={15} className=\"mt-0.5 shrink-0\" />\n <span>\n {tr(\n \"devportal.builtinHint\",\n \"Built-in items are pre-installed by the platform. No package upload is needed.\",\n )}\n </span>\n </div>\n )}\n </div>\n )}\n\n {/* manifest.json import / export helpers */}\n <div className=\"flex flex-wrap items-center gap-2 border-t pt-4\">\n <input\n ref={manifestFileInputRef}\n type=\"file\"\n accept=\".json,application/json\"\n className=\"hidden\"\n onChange={handleImportManifest}\n />\n <span className=\"text-xs text-text-secondary mr-1\">\n manifest.json:\n </span>\n <button\n type=\"button\"\n onClick={() => manifestFileInputRef.current?.click()}\n className=\"inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-xs font-medium hover:bg-muted transition-colors\"\n >\n <Upload size={12} />\n {tr(\"devportal.importManifest\", \"Import\")}\n </button>\n <button\n type=\"button\"\n onClick={handleExportManifest}\n className=\"inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-xs font-medium hover:bg-muted transition-colors\"\n >\n <Download size={12} />\n {tr(\"devportal.exportManifest\", \"Export\")}\n </button>\n <span className=\"text-xs text-text-secondary\">\n {tr(\n \"devportal.manifestTip\",\n \"— export to get a manifest.json to include inside your zip\",\n )}\n </span>\n </div>\n </div>\n </PageSection>\n )}\n\n {/* ── Section 2: Store Presence ──────────────────────────── */}\n <PageSection\n title={tr(\"devportal.storePresentation\", \"Store Presence\")}\n description={tr(\n \"devportal.storePresentationDescription\",\n \"Visual assets and copy shown to users browsing the marketplace\",\n )}\n >\n <div className=\"space-y-5\">\n <div className=\"grid gap-5 sm:grid-cols-2\">\n <ImageUploadField\n label={tr(\"devportal.iconUrl\", \"Icon\")}\n value={formData.iconUrl}\n onChange={(url) => handleChange(\"iconUrl\", url)}\n hint={tr(\n \"devportal.iconUrlHint\",\n \"Square, 256×256 px recommended\",\n )}\n aspectClass=\"aspect-square\"\n upload={uploadAsset}\n uploading={iconUploading}\n progress={iconProgress}\n error={iconUploadError}\n />\n <ImageUploadField\n label={tr(\"devportal.bannerUrl\", \"Banner\")}\n value={formData.bannerUrl}\n onChange={(url) => handleChange(\"bannerUrl\", url)}\n hint={tr(\"devportal.bannerUrlHint\", \"1280×640 px recommended\")}\n aspectClass=\"aspect-video\"\n upload={uploadBanner}\n uploading={bannerUploading}\n progress={bannerProgress}\n error={bannerUploadError}\n />\n </div>\n <InputField\n label={tr(\"devportal.videoUrl\", \"Demo Video URL\")}\n value={formData.videoUrl}\n onChange={(e) => handleChange(\"videoUrl\", e.target.value)}\n placeholder=\"https://...\"\n hint={tr(\"devportal.videoUrlHint\", \"YouTube or Vimeo embed URL\")}\n />\n <TextareaField\n label={tr(\"devportal.shortDescription\", \"Short Description\")}\n value={formData.shortDescription}\n onChange={(e) => handleChange(\"shortDescription\", e.target.value)}\n maxLength={200}\n rows={2}\n hint={`${formData.shortDescription.length}/200 · ${tr(\"devportal.shortDescHint\", \"Shown in search results and cards\")}`}\n />\n <TextareaField\n label={tr(\"devportal.longDescription\", \"Full Description\")}\n value={formData.description}\n onChange={(e) => handleChange(\"description\", e.target.value)}\n rows={5}\n hint={tr(\"devportal.fullDescHint\", \"Markdown supported\")}\n />\n <ScreenshotGallery\n urls={formData.screenshotsText\n .split(\"\\n\")\n .map((s) => s.trim())\n .filter(Boolean)}\n onChange={(urls) =>\n handleChange(\"screenshotsText\", urls.join(\"\\n\"))\n }\n upload={uploadScreenshot}\n uploading={screenshotUploading}\n progress={screenshotProgress}\n error={screenshotUploadError}\n />\n </div>\n </PageSection>\n\n {/* ── Section 3: Links & Policies ────────────────────────── */}\n <PageSection\n title={tr(\"devportal.linksPolicies\", \"Links & Policies\")}\n description={tr(\n \"devportal.linksPoliciesDescription\",\n \"External resources and legal documents — privacy policy and terms are required for store submission\",\n )}\n >\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <InputField\n label={tr(\"devportal.websiteUrl\", \"Website\")}\n value={formData.websiteUrl}\n onChange={(e) => handleChange(\"websiteUrl\", e.target.value)}\n placeholder=\"https://...\"\n />\n <InputField\n label={tr(\"devportal.documentationUrl\", \"Documentation\")}\n value={formData.documentationUrl}\n onChange={(e) => handleChange(\"documentationUrl\", e.target.value)}\n placeholder=\"https://...\"\n />\n <InputField\n label={tr(\"devportal.githubUrl\", \"GitHub\")}\n value={formData.githubUrl}\n onChange={(e) => handleChange(\"githubUrl\", e.target.value)}\n placeholder=\"https://github.com/...\"\n />\n <InputField\n label={tr(\"devportal.supportUrl\", \"Support\")}\n value={formData.supportUrl}\n onChange={(e) => handleChange(\"supportUrl\", e.target.value)}\n placeholder=\"https://...\"\n />\n <InputField\n label={`${tr(\"devportal.privacyPolicyUrl\", \"Privacy Policy\")} *`}\n value={formData.privacyPolicyUrl}\n onChange={(e) => handleChange(\"privacyPolicyUrl\", e.target.value)}\n placeholder=\"https://...\"\n hint={tr(\n \"devportal.requiredForStore\",\n \"Required for store submission\",\n )}\n />\n <InputField\n label={`${tr(\"devportal.termsOfServiceUrl\", \"Terms of Service\")} *`}\n value={formData.termsOfServiceUrl}\n onChange={(e) => handleChange(\"termsOfServiceUrl\", e.target.value)}\n placeholder=\"https://...\"\n hint={tr(\n \"devportal.requiredForStore\",\n \"Required for store submission\",\n )}\n />\n </div>\n </PageSection>\n\n {/* ── Section 4: Pricing ─────────────────────────────────── */}\n <PageSection\n title={tr(\"devportal.pricing\", \"Pricing\")}\n description={tr(\n \"devportal.pricingDescription\",\n \"How this item is priced in the marketplace\",\n )}\n >\n <div className=\"space-y-4\">\n <div>\n <label className=\"mb-2 block text-sm font-medium\">\n {tr(\"devportal.pricingType\", \"Pricing Type\")}\n </label>\n <div className=\"flex flex-wrap gap-2\">\n {PRICING_TYPE_OPTIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => handleChange(\"pricingType\", opt.value)}\n className={cn(\n \"rounded-md border px-3 py-1.5 text-sm font-medium transition-colors\",\n formData.pricingType === opt.value\n ? \"bg-primary text-primary-foreground border-primary\"\n : \"hover:bg-muted\",\n )}\n >\n {opt.label}\n </button>\n ))}\n </div>\n </div>\n {showPriceFields && (\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <InputField\n label={tr(\"devportal.price\", \"Price\")}\n type=\"number\"\n value={formData.price}\n onChange={(e) => handleChange(\"price\", e.target.value)}\n placeholder=\"0.00\"\n />\n <InputField\n label={tr(\"devportal.currency\", \"Currency\")}\n value={formData.currency}\n onChange={(e) => handleChange(\"currency\", e.target.value)}\n placeholder=\"USD\"\n />\n </div>\n )}\n </div>\n </PageSection>\n\n {/* Save + Submit for Review */}\n <div className=\"border-t pt-6 flex items-center gap-3 flex-wrap\">\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={isSaving}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n {isSaving ? (\n <>\n <Loader2 size={16} className=\"animate-spin\" />\n {tr(\"devportal.saving\", \"Saving…\")}\n </>\n ) : (\n <>\n <Store size={16} />\n {tr(\"devportal.saveMarketplaceListing\", \"Save Marketplace Listing\")}\n </>\n )}\n </button>\n {!isPublished && !isSubmitted && (\n <button\n type=\"button\"\n onClick={() => void handleSubmitForReview()}\n disabled={isSubmitting || isSaving}\n className=\"inline-flex items-center gap-2 rounded-md border border-primary px-4 py-2 text-sm font-medium text-primary hover:bg-primary/5 transition-colors disabled:opacity-50\"\n >\n {isSubmitting ? (\n <>\n <Loader2 size={16} className=\"animate-spin\" />\n {tr(\"devportal.submitting\", \"Submitting…\")}\n </>\n ) : (\n <>\n <SendHorizontal size={16} />\n {tr(\"devportal.submitForReview\", \"Submit for Review\")}\n </>\n )}\n </button>\n )}\n {!isPublished && isSubmitted && (\n <p className=\"text-xs text-muted-foreground flex items-center gap-1.5\">\n <Clock size={12} />\n {tr(\n \"devportal.awaitingReview\",\n \"Your listing is under review. You can still update and save — changes take effect after approval.\",\n )}\n </p>\n )}\n </div>\n </div>\n );\n};\n\n// =============================================================================\n// HELPER COMPONENTS\n// =============================================================================\n\nconst StatCard: FC<{ label: string; value: string; trend?: number }> = ({\n label,\n value,\n trend,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n return (\n <div className=\"rounded-lg border bg-card p-4\">\n <p className=\"text-sm text-muted-foreground\">{label}</p>\n <p className=\"text-2xl font-bold\">{value}</p>\n {trend !== undefined && (\n <p\n className={cn(\n \"text-xs mt-1\",\n trend > 0\n ? \"text-status-success-text\"\n : trend < 0\n ? \"text-status-error-text\"\n : \"text-muted-foreground\",\n )}\n >\n {trend > 0 ? \"+\" : \"\"}\n {trend.toFixed(1)}% {tr(\"devportal.vsYesterday\", \"vs yesterday\")}\n </p>\n )}\n </div>\n );\n};\n\nconst LinkItem: FC<{ label: string; url: string }> = ({ label, url }) => (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center gap-2 text-sm text-primary hover:underline\"\n >\n <ExternalLink size={14} />\n {label}\n </a>\n);\n\n// =============================================================================\n// PERMISSIONS TAB\n// =============================================================================\n\nconst PERMISSION_RESOURCES = [\n {\n id: \"auth\",\n label: \"Authentication\",\n description: \"User identity and session management\",\n },\n {\n id: \"billing\",\n label: \"Billing\",\n description: \"Billing accounts and subscriptions\",\n },\n { id: \"files\", label: \"Files\", description: \"File storage and management\" },\n { id: \"tags\", label: \"Tags\", description: \"Tags and labels on resources\" },\n { id: \"calendar\", label: \"Calendar\", description: \"Events and scheduling\" },\n { id: \"workflows\", label: \"Workflows\", description: \"Automation workflows\" },\n { id: \"channels\", label: \"Channels\", description: \"Messaging channels\" },\n {\n id: \"notifications\",\n label: \"Notifications\",\n description: \"Platform notifications\",\n },\n {\n id: \"users\",\n label: \"Users & Members\",\n description: \"Workspace members and profiles\",\n },\n {\n id: \"workspaces\",\n label: \"Workspaces\",\n description: \"Workspace settings and metadata\",\n },\n {\n id: \"content\",\n label: \"Content\",\n description: \"Pages, documents, and content\",\n },\n {\n id: \"analytics\",\n label: \"Analytics\",\n description: \"Usage analytics and reporting\",\n },\n { id: \"webhooks\", label: \"Webhooks\", description: \"Webhook subscriptions\" },\n {\n id: \"rbac\",\n label: \"Roles & Permissions\",\n description: \"Access control configuration\",\n },\n] as const;\n\ntype PermissionResourceId = (typeof PERMISSION_RESOURCES)[number][\"id\"];\ntype PermissionLevel = \"none\" | \"read\" | \"write\";\ntype PermissionMap = Record<PermissionResourceId, PermissionLevel>;\n\nfunction parseManifestPermissions(\n manifest: Record<string, unknown> | null | undefined,\n): PermissionMap {\n const base = Object.fromEntries(\n PERMISSION_RESOURCES.map((r) => [r.id, \"none\" as PermissionLevel]),\n ) as PermissionMap;\n if (!manifest || !Array.isArray(manifest.permissions)) return base;\n for (const entry of manifest.permissions as Array<{\n resource: string;\n level: string;\n }>) {\n if (entry.resource in base) {\n base[entry.resource as PermissionResourceId] =\n entry.level === \"write\" ? \"write\" : \"read\";\n }\n }\n return base;\n}\n\nconst PermissionsTab: FC<{ app: Application }> = ({ app }) => {\n const manifest = (app.manifest ?? {}) as Record<string, unknown>;\n const [permissions, setPermissions] = useState<PermissionMap>(() =>\n parseManifestPermissions(manifest),\n );\n const [saving, setSaving] = useState(false);\n const [saved, setSaved] = useState(false);\n const [updateApplication] = useUpdateApplicationMutation();\n\n const handleChange = (\n resource: PermissionResourceId,\n level: PermissionLevel,\n ) => {\n setSaved(false);\n setPermissions((prev) => ({ ...prev, [resource]: level }));\n };\n\n const handleSave = async () => {\n setSaving(true);\n try {\n const entries = Object.entries(permissions).filter(\n ([, level]) => level !== \"none\",\n );\n const newPermissions = entries.map(([resource, level]) => ({\n resource,\n level,\n }));\n await updateApplication({\n variables: {\n id: app.id,\n input: {\n manifest: {\n ...manifest,\n permissions: newPermissions,\n },\n },\n },\n });\n setSaved(true);\n } finally {\n setSaving(false);\n }\n };\n\n const levelLabels: Record<PermissionLevel, string> = {\n none: \"No access\",\n read: \"Read\",\n write: \"Read & Write\",\n };\n const levels: PermissionLevel[] = [\"none\", \"read\", \"write\"];\n\n return (\n <PageSection\n title=\"Permissions\"\n description=\"Define what platform data this app can request access to. Users see these when authorizing the app.\"\n >\n <div className=\"space-y-4\">\n <div className=\"overflow-x-auto rounded-lg border border-border\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border bg-muted/50\">\n <th className=\"px-4 py-3 text-left font-medium text-muted-foreground w-1/2\">\n Resource\n </th>\n {levels.map((l) => (\n <th\n key={l}\n className=\"px-4 py-3 text-center font-medium text-muted-foreground\"\n >\n {levelLabels[l]}\n </th>\n ))}\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border\">\n {PERMISSION_RESOURCES.map((resource) => (\n <tr\n key={resource.id}\n className=\"hover:bg-muted/30 transition-colors\"\n >\n <td className=\"px-4 py-3\">\n <p className=\"font-medium text-foreground\">\n {resource.label}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {resource.description}\n </p>\n </td>\n {levels.map((level) => (\n <td key={level} className=\"px-4 py-3 text-center\">\n <input\n type=\"radio\"\n name={`perm-${resource.id}`}\n value={level}\n checked={permissions[resource.id] === level}\n onChange={() => handleChange(resource.id, level)}\n className=\"h-4 w-4 accent-primary cursor-pointer\"\n />\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n\n <div className=\"rounded-lg border border-border-subtle bg-muted/30 p-3 flex gap-2 text-xs text-muted-foreground\">\n <Info size={14} className=\"flex-shrink-0 mt-0.5\" />\n <span>\n <strong>Read & Write</strong> implies Read. Request only what\n your app genuinely needs — fewer permissions build more user trust.\n </span>\n </div>\n\n <div className=\"flex items-center justify-end gap-3\">\n {saved && (\n <span className=\"flex items-center gap-1.5 text-sm text-status-success-text\">\n <CheckCircle size={14} />\n Saved\n </span>\n )}\n <button\n type=\"button\"\n onClick={() => void handleSave()}\n disabled={saving}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n {saving ? (\n <Loader2 size={14} className=\"animate-spin\" />\n ) : (\n <Shield size={14} />\n )}\n Save Permissions\n </button>\n </div>\n </div>\n </PageSection>\n );\n};\n"],"mappings":"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"}
|