@burdenoff/microfe-devportal 2026.623.5 → 2026.623.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/devportal/DevportalRoutes.js +123 -108
- package/dist/devportal/DevportalRoutes.js.map +1 -1
- package/dist/devportal/components/SectionNav.js +71 -5
- package/dist/devportal/components/SectionNav.js.map +1 -0
- package/dist/devportal/components/index.js +1 -1
- package/dist/devportal/hooks/useGraphQL.js +1 -1
- package/dist/devportal/pages/AdminReviewPage.js +39 -39
- package/dist/devportal/pages/AnalyticsDashboardPage.js +54 -54
- package/dist/devportal/pages/AnalyticsDashboardPage.js.map +1 -1
- package/dist/devportal/pages/ApiKeysPage.js +53 -53
- package/dist/devportal/pages/ApiKeysPage.js.map +1 -1
- package/dist/devportal/pages/AppLogsPage.js +9 -9
- package/dist/devportal/pages/ApplicationDetailPage.js +462 -462
- package/dist/devportal/pages/ApplicationDetailPage.js.map +1 -1
- package/dist/devportal/pages/ApplicationVersionsPage.js +120 -120
- package/dist/devportal/pages/ApplicationVersionsPage.js.map +1 -1
- package/dist/devportal/pages/ApplicationsPage.js +73 -73
- package/dist/devportal/pages/ApplicationsPage.js.map +1 -1
- package/dist/devportal/pages/CreateApiKeyPage.js +20 -20
- package/dist/devportal/pages/CreateApplicationPage.js +32 -32
- package/dist/devportal/pages/CreateOAuthClientPage.js +18 -18
- package/dist/devportal/pages/CreateOrganizationPage.js +12 -12
- package/dist/devportal/pages/CreateWebhookPage.js +23 -23
- package/dist/devportal/pages/DashboardPage.js +23 -23
- package/dist/devportal/pages/DelegationsPage.js +22 -22
- package/dist/devportal/pages/EditApplicationPage.js +283 -283
- package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
- package/dist/devportal/pages/ListingPreviewPage.js +9 -9
- package/dist/devportal/pages/OAuthClientDetailPage.js +15 -15
- package/dist/devportal/pages/OAuthClientsPage.js +14 -14
- package/dist/devportal/pages/OrganizationDetailPage.js +84 -84
- package/dist/devportal/pages/OrganizationMembersPage.js +260 -260
- package/dist/devportal/pages/OrganizationMembersPage.js.map +1 -1
- package/dist/devportal/pages/OrganizationsPage.js +16 -16
- package/dist/devportal/pages/PublishPage.js +16 -16
- package/dist/devportal/pages/PublisherProfilePage.js +18 -18
- package/dist/devportal/pages/RevenueDashboardPage.js +29 -29
- package/dist/devportal/pages/SettingsPage.js +17 -17
- package/dist/devportal/pages/SetupPage.js +99 -99
- package/dist/devportal/pages/SetupPage.js.map +1 -1
- package/dist/devportal/pages/WebhookDetailPage.js +143 -143
- package/dist/devportal/pages/WebhookDetailPage.js.map +1 -1
- package/dist/devportal/pages/WebhooksPage.js +133 -133
- package/dist/devportal/pages/WebhooksPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApplicationsPage.js","names":[],"sources":["../../../src/devportal/pages/ApplicationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useMemo, useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Plus,\n Search,\n Grid,\n List,\n AppWindow,\n Loader2,\n AlertCircle,\n Archive,\n Trash2,\n} from \"lucide-react\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { AppCard, AppListItem } from \"../components/AppCard\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { SelectionCheckbox } from \"../components/SelectionCheckbox\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport type { Application, AppStatus, AppType } from \"../types\";\nimport { APP_TYPE_LABELS, APP_STATUS_COLORS } from \"../utils/constants\";\nimport {\n useGetApplicationsQuery,\n useDeleteApplicationMutation,\n useDeactivateAppMutation,\n getErrorMessage,\n useDevportalPermission,\n type ApplicationFieldsFragment,\n} from \"../hooks\";\n\ntype BulkAction = \"delete\" | \"deactivate\" | null;\n\nfunction formatBulkResult(\n action: \"Deleted\" | \"Deactivated\",\n succeeded: number,\n failed: number,\n): string {\n return `${action} ${succeeded} application${succeeded === 1 ? \"\" : \"s\"}${\n failed > 0 ? ` • ${failed} failed` : \"\"\n }`;\n}\n\n/**\n * Map GraphQL application to local Application type\n */\nfunction mapApplication(app: ApplicationFieldsFragment): Application {\n // Convert screenshots array to Record if needed\n const screenshots = Array.isArray(app.screenshots)\n ? app.screenshots.length > 0\n ? (app.screenshots as unknown as Record<string, unknown>)\n : undefined\n : (app.screenshots as Record<string, unknown> | undefined);\n\n // Convert pricingDetails\n const pricingDetails =\n app.pricingDetails && typeof app.pricingDetails === \"object\"\n ? (app.pricingDetails as Record<string, unknown>)\n : undefined;\n\n return {\n id: app.id,\n name: app.name,\n slug: app.slug,\n description: app.description ?? undefined,\n shortDescription: app.shortDescription ?? undefined,\n appType: app.appType as AppType,\n status: app.status as AppStatus,\n visibility: app.visibility as \"PUBLIC\" | \"PRIVATE\" | \"UNLISTED\",\n category: app.category ?? undefined,\n tags: app.tags ?? [],\n keywords: app.keywords ?? [],\n iconUrl: app.iconUrl ?? undefined,\n bannerUrl: app.bannerUrl ?? undefined,\n screenshots,\n videoUrl: app.videoUrl ?? undefined,\n websiteUrl: app.websiteUrl ?? undefined,\n documentationUrl: app.documentationUrl ?? undefined,\n supportUrl: app.supportUrl ?? undefined,\n privacyPolicyUrl: app.privacyPolicyUrl ?? undefined,\n termsOfServiceUrl: app.termsOfServiceUrl ?? undefined,\n githubUrl: app.githubUrl ?? undefined,\n pricingType: app.pricingType ?? undefined,\n pricingDetails,\n isVerified: app.isVerified,\n isFeatured: app.isFeatured,\n averageRating: app.averageRating ?? undefined,\n reviewCount: app.reviewCount ?? 0,\n installCount: app.installCount ?? 0,\n activeInstallCount: app.activeInstallCount ?? 0,\n requiresApproval: app.requiresApproval,\n reviewStatus: app.reviewStatus ?? undefined,\n reviewNotes: app.reviewNotes ?? undefined,\n reviewedBy: app.reviewedBy ?? undefined,\n lastReviewedAt: app.lastReviewedAt ?? undefined,\n submittedAt: app.submittedAt ?? undefined,\n publishedAt: app.publishedAt ?? undefined,\n developerId: app.developerId,\n developerOrganizationId: app.developerOrganizationId ?? undefined,\n tenantId: app.tenantId,\n createdAt: app.createdAt,\n updatedAt: app.updatedAt,\n };\n}\n\n/**\n * Applications listing page\n *\n * Displays all applications for the current developer.\n * Uses GraphQL to fetch real data from the DevPortal backend.\n */\nexport const ApplicationsPage: FC = () => {\n const { navigate, basePath, activeOrgId } = 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 createPerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_CREATE);\n const deletePerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_DELETE);\n const updatePerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_UPDATE);\n const [viewMode, setViewMode] = useState<\"grid\" | \"list\">(\"grid\");\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [statusFilter, setStatusFilter] = useState<AppStatus | \"\">(\"\");\n const [typeFilter, setTypeFilter] = useState<AppType | \"\">(\"\");\n const [selectedAppIds, setSelectedAppIds] = useState<Set<string>>(new Set());\n const [bulkAction, setBulkAction] = useState<BulkAction>(null);\n const [feedback, setFeedback] = useState<{\n type: \"success\" | \"error\";\n message: string;\n } | null>(null);\n\n // Fetch applications from GraphQL API\n const { data, loading, error, refetch } = useGetApplicationsQuery({\n variables: {\n limit: 50,\n offset: 0,\n status: statusFilter || undefined,\n },\n fetchPolicy: \"cache-and-network\",\n });\n\n const applications: Application[] = useMemo(\n () =>\n data?.applications?.edges?.map(\n (edge: { node: ApplicationFieldsFragment }) =>\n mapApplication(edge.node),\n ) ?? [],\n [data?.applications?.edges],\n );\n\n const [deleteApplication] = useDeleteApplicationMutation();\n const [deactivateApp] = useDeactivateAppMutation();\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n // Client-side filtering: org scope + search + type (status filtered server-side)\n const filteredApps = applications.filter((app: Application) => {\n const matchesOrg =\n !activeOrgId || app.developerOrganizationId === activeOrgId;\n const matchesSearch =\n !searchQuery ||\n app.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\n app.shortDescription?.toLowerCase().includes(searchQuery.toLowerCase());\n const matchesType = !typeFilter || app.appType === typeFilter;\n return matchesOrg && matchesSearch && matchesType;\n });\n\n const selectedApps = useMemo(\n () => applications.filter((app: Application) => selectedAppIds.has(app.id)),\n [applications, selectedAppIds],\n );\n\n const deactivatableApps = useMemo(\n () =>\n selectedApps.filter(\n (app: Application) =>\n app.status !== \"INACTIVE\" && app.status !== \"REVOKED\",\n ),\n [selectedApps],\n );\n\n const allVisibleSelected =\n filteredApps.length > 0 &&\n filteredApps.every((app: Application) => selectedAppIds.has(app.id));\n const partiallySelected =\n filteredApps.some((app: Application) => selectedAppIds.has(app.id)) &&\n !allVisibleSelected;\n\n const toggleAppSelection = (appId: string, checked: boolean) => {\n setSelectedAppIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(appId);\n } else {\n next.delete(appId);\n }\n return next;\n });\n };\n\n const toggleAllVisible = (checked: boolean) => {\n setSelectedAppIds((prev) => {\n const next = new Set(prev);\n filteredApps.forEach((app: Application) => {\n if (checked) {\n next.add(app.id);\n } else {\n next.delete(app.id);\n }\n });\n return next;\n });\n };\n\n const clearSelection = () => setSelectedAppIds(new Set());\n\n const runBulkDeactivate = async () => {\n if (deactivatableApps.length === 0) return;\n\n const results = await Promise.allSettled(\n deactivatableApps.map((app: Application) =>\n deactivateApp({ variables: { id: app.id } }),\n ),\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n\n setFeedback({\n type: failed === 0 ? \"success\" : \"error\",\n message: formatBulkResult(\"Deactivated\", succeeded, failed),\n });\n clearSelection();\n setBulkAction(null);\n await refetch();\n };\n\n const runBulkDelete = async () => {\n if (selectedApps.length === 0) return;\n\n const results = await Promise.allSettled(\n selectedApps.map((app: Application) =>\n deleteApplication({ variables: { id: app.id } }),\n ),\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n\n setFeedback({\n type: failed === 0 ? \"success\" : \"error\",\n message: formatBulkResult(\"Deleted\", succeeded, failed),\n });\n clearSelection();\n setBulkAction(null);\n await refetch();\n };\n\n // Loading state\n if (loading && !data) {\n return (\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n <span className=\"ml-2 text-muted-foreground\">\n {tr(\"devportal.loadingApplications\", \"Loading applications...\")}\n </span>\n </div>\n </PageLayout>\n );\n }\n\n // Error state\n if (error) {\n return (\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n >\n <div className=\"rounded-lg border border-destructive/50 bg-destructive/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-destructive\" />\n <h3 className=\"mt-2 font-medium text-destructive\">\n {tr(\n \"devportal.failedToLoadApplications\",\n \"Failed to load applications\",\n )}\n </h3>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {getErrorMessage(error)}\n </p>\n <button\n onClick={() => refetch()}\n className=\"mt-4 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n {tr(\"devportal.tryAgain\", \"Try Again\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.APP_READ}>\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n actions={\n <button\n onClick={() => handleNavigate(\"/apps/new\")}\n disabled={!createPerm.allowed}\n aria-disabled={!createPerm.allowed}\n title={\n !createPerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\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 disabled:cursor-not-allowed focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Plus size={16} aria-hidden=\"true\" />\n {tr(\"devportal.createApp\", \"Create App\")}\n </button>\n }\n >\n {/* Filters */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex flex-1 items-center gap-4\">\n {/* Search */}\n <div className=\"relative flex-1 max-w-md\">\n <Search\n size={16}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground\"\n />\n <input\n type=\"text\"\n placeholder={tr(\n \"devportal.searchApplications\",\n \"Search applications...\",\n )}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full rounded-md border bg-background pl-9 pr-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n />\n </div>\n\n {/* Status Filter */}\n <select\n value={statusFilter}\n onChange={(e) =>\n setStatusFilter(e.target.value as AppStatus | \"\")\n }\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"\">\n {tr(\"devportal.allStatus\", \"All Status\")}\n </option>\n {Object.keys(APP_STATUS_COLORS).map((status) => (\n <option key={status} value={status}>\n {status.replace(/_/g, \" \")}\n </option>\n ))}\n </select>\n\n {/* Type Filter */}\n <select\n value={typeFilter}\n onChange={(e) => setTypeFilter(e.target.value as AppType | \"\")}\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"\">{tr(\"devportal.allTypes\", \"All Types\")}</option>\n {Object.entries(APP_TYPE_LABELS).map(([value, label]) => (\n <option key={value} value={value}>\n {label}\n </option>\n ))}\n </select>\n </div>\n\n {/* View Toggle */}\n <div className=\"flex items-center gap-1 rounded-md border p-1\">\n <button\n onClick={() => setViewMode(\"grid\")}\n className={`rounded p-1.5 ${viewMode === \"grid\" ? \"bg-muted\" : \"hover:bg-muted/50\"}`}\n title=\"Grid view\"\n >\n <Grid size={16} />\n </button>\n <button\n onClick={() => setViewMode(\"list\")}\n className={`rounded p-1.5 ${viewMode === \"list\" ? \"bg-muted\" : \"hover:bg-muted/50\"}`}\n title=\"List view\"\n >\n <List size={16} />\n </button>\n </div>\n </div>\n\n {feedback && (\n <div\n className={`rounded-lg border px-4 py-3 text-sm ${\n feedback.type === \"success\"\n ? \"border-border-subtle bg-status-success-bg-subtle text-status-success-text\"\n : \"border-destructive/40 bg-destructive/10 text-destructive\"\n }`}\n >\n <div className=\"flex items-center justify-between gap-3\">\n <span>{feedback.message}</span>\n <button\n onClick={() => setFeedback(null)}\n className=\"text-xs font-medium underline underline-offset-2\"\n >\n Dismiss\n </button>\n </div>\n </div>\n )}\n\n {filteredApps.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={toggleAllVisible}\n ariaLabel=\"Select all visible applications\"\n />\n <span className=\"text-sm font-medium\">\n Select all visible\n </span>\n </div>\n {selectedAppIds.size > 0 && (\n <button\n onClick={clearSelection}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n 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 {selectedAppIds.size} selected\n </span>\n <button\n onClick={() => setBulkAction(\"deactivate\")}\n disabled={\n deactivatableApps.length === 0 || !updatePerm.allowed\n }\n aria-disabled={\n deactivatableApps.length === 0 || !updatePerm.allowed\n }\n title={\n !updatePerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 rounded-md border border-status-warning-bg px-3 py-2 text-sm font-medium text-status-warning-text transition-colors hover:bg-status-warning-bg-subtle disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Archive size={16} aria-hidden=\"true\" />\n {tr(\"devportal.deactivateSelected\", \"Deactivate Selected\")}\n {deactivatableApps.length > 0\n ? ` (${deactivatableApps.length})`\n : \"\"}\n </button>\n <button\n onClick={() => setBulkAction(\"delete\")}\n disabled={selectedApps.length === 0 || !deletePerm.allowed}\n aria-disabled={\n selectedApps.length === 0 || !deletePerm.allowed\n }\n title={\n !deletePerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 rounded-md border border-status-error-bg px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n {tr(\"devportal.deleteSelected\", \"Delete Selected\")}\n {selectedApps.length > 0 ? ` (${selectedApps.length})` : \"\"}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Results count */}\n <p className=\"text-sm text-muted-foreground\">\n {filteredApps.length} application\n {filteredApps.length !== 1 ? \"s\" : \"\"} found\n </p>\n\n {/* Applications */}\n {filteredApps.length > 0 ? (\n viewMode === \"grid\" ? (\n <div className=\"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {filteredApps.map((app: Application) => (\n <AppCard\n key={app.id}\n app={app}\n selected={selectedAppIds.has(app.id)}\n onToggleSelect={(checked) =>\n toggleAppSelection(app.id, checked)\n }\n />\n ))}\n </div>\n ) : (\n <div className=\"space-y-2\">\n {filteredApps.map((app: Application) => (\n <AppListItem\n key={app.id}\n app={app}\n selected={selectedAppIds.has(app.id)}\n onToggleSelect={(checked) =>\n toggleAppSelection(app.id, checked)\n }\n />\n ))}\n </div>\n )\n ) : (\n <EmptyState\n icon={<AppWindow size={32} />}\n title={tr(\"devportal.noApplicationsFound\", \"No applications found\")}\n description={\n searchQuery || statusFilter || typeFilter\n ? tr(\n \"devportal.tryAdjustingFilters\",\n \"Try adjusting your filters\",\n )\n : tr(\n \"devportal.createFirstApp\",\n \"Create your first application to get started\",\n )\n }\n action={\n !searchQuery && !statusFilter && !typeFilter ? (\n <button\n onClick={() => handleNavigate(\"/apps/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.createApp\", \"Create App\")}\n </button>\n ) : undefined\n }\n />\n )}\n\n <ConfirmDialog\n open={bulkAction === \"deactivate\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={runBulkDeactivate}\n title=\"Deactivate selected applications\"\n description={`Deactivate ${deactivatableApps.length} selected application${deactivatableApps.length === 1 ? \"\" : \"s\"}? Users and integrations may lose access until these apps are re-enabled.`}\n confirmLabel=\"Deactivate\"\n cancelLabel=\"Cancel\"\n variant=\"warning\"\n />\n\n <ConfirmDialog\n open={bulkAction === \"delete\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={runBulkDelete}\n title=\"Delete selected applications\"\n description={`Delete ${selectedApps.length} selected application${selectedApps.length === 1 ? \"\" : \"s\"}? This cannot be undone.`}\n confirmLabel=\"Delete\"\n cancelLabel=\"Cancel\"\n variant=\"danger\"\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ApplicationsPage.js","names":[],"sources":["../../../src/devportal/pages/ApplicationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useMemo, useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Plus,\n Search,\n Grid,\n List,\n AppWindow,\n Loader2,\n AlertCircle,\n Archive,\n Trash2,\n} from \"lucide-react\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { AppCard, AppListItem } from \"../components/AppCard\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { SelectionCheckbox } from \"../components/SelectionCheckbox\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport type { Application, AppStatus, AppType } from \"../types\";\nimport { APP_TYPE_LABELS, APP_STATUS_COLORS } from \"../utils/constants\";\nimport {\n useGetApplicationsQuery,\n useDeleteApplicationMutation,\n useDeactivateAppMutation,\n getErrorMessage,\n useDevportalPermission,\n type ApplicationFieldsFragment,\n} from \"../hooks\";\n\ntype BulkAction = \"delete\" | \"deactivate\" | null;\n\nfunction formatBulkResult(\n action: \"Deleted\" | \"Deactivated\",\n succeeded: number,\n failed: number,\n): string {\n return `${action} ${succeeded} application${succeeded === 1 ? \"\" : \"s\"}${\n failed > 0 ? ` • ${failed} failed` : \"\"\n }`;\n}\n\n/**\n * Map GraphQL application to local Application type\n */\nfunction mapApplication(app: ApplicationFieldsFragment): Application {\n // Convert screenshots array to Record if needed\n const screenshots = Array.isArray(app.screenshots)\n ? app.screenshots.length > 0\n ? (app.screenshots as unknown as Record<string, unknown>)\n : undefined\n : (app.screenshots as Record<string, unknown> | undefined);\n\n // Convert pricingDetails\n const pricingDetails =\n app.pricingDetails && typeof app.pricingDetails === \"object\"\n ? (app.pricingDetails as Record<string, unknown>)\n : undefined;\n\n return {\n id: app.id,\n name: app.name,\n slug: app.slug,\n description: app.description ?? undefined,\n shortDescription: app.shortDescription ?? undefined,\n appType: app.appType as AppType,\n status: app.status as AppStatus,\n visibility: app.visibility as \"PUBLIC\" | \"PRIVATE\" | \"UNLISTED\",\n category: app.category ?? undefined,\n tags: app.tags ?? [],\n keywords: app.keywords ?? [],\n iconUrl: app.iconUrl ?? undefined,\n bannerUrl: app.bannerUrl ?? undefined,\n screenshots,\n videoUrl: app.videoUrl ?? undefined,\n websiteUrl: app.websiteUrl ?? undefined,\n documentationUrl: app.documentationUrl ?? undefined,\n supportUrl: app.supportUrl ?? undefined,\n privacyPolicyUrl: app.privacyPolicyUrl ?? undefined,\n termsOfServiceUrl: app.termsOfServiceUrl ?? undefined,\n githubUrl: app.githubUrl ?? undefined,\n pricingType: app.pricingType ?? undefined,\n pricingDetails,\n isVerified: app.isVerified,\n isFeatured: app.isFeatured,\n averageRating: app.averageRating ?? undefined,\n reviewCount: app.reviewCount ?? 0,\n installCount: app.installCount ?? 0,\n activeInstallCount: app.activeInstallCount ?? 0,\n requiresApproval: app.requiresApproval,\n reviewStatus: app.reviewStatus ?? undefined,\n reviewNotes: app.reviewNotes ?? undefined,\n reviewedBy: app.reviewedBy ?? undefined,\n lastReviewedAt: app.lastReviewedAt ?? undefined,\n submittedAt: app.submittedAt ?? undefined,\n publishedAt: app.publishedAt ?? undefined,\n developerId: app.developerId,\n developerOrganizationId: app.developerOrganizationId ?? undefined,\n tenantId: app.tenantId,\n createdAt: app.createdAt,\n updatedAt: app.updatedAt,\n };\n}\n\n/**\n * Applications listing page\n *\n * Displays all applications for the current developer.\n * Uses GraphQL to fetch real data from the DevPortal backend.\n */\nexport const ApplicationsPage: FC = () => {\n const { navigate, basePath, activeOrgId } = 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 createPerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_CREATE);\n const deletePerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_DELETE);\n const updatePerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_UPDATE);\n const [viewMode, setViewMode] = useState<\"grid\" | \"list\">(\"grid\");\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [statusFilter, setStatusFilter] = useState<AppStatus | \"\">(\"\");\n const [typeFilter, setTypeFilter] = useState<AppType | \"\">(\"\");\n const [selectedAppIds, setSelectedAppIds] = useState<Set<string>>(new Set());\n const [bulkAction, setBulkAction] = useState<BulkAction>(null);\n const [feedback, setFeedback] = useState<{\n type: \"success\" | \"error\";\n message: string;\n } | null>(null);\n\n // Fetch applications from GraphQL API\n const { data, loading, error, refetch } = useGetApplicationsQuery({\n variables: {\n limit: 50,\n offset: 0,\n status: statusFilter || undefined,\n },\n fetchPolicy: \"cache-and-network\",\n });\n\n const applications: Application[] = useMemo(\n () =>\n data?.applications?.edges?.map(\n (edge: { node: ApplicationFieldsFragment }) =>\n mapApplication(edge.node),\n ) ?? [],\n [data?.applications?.edges],\n );\n\n const [deleteApplication] = useDeleteApplicationMutation();\n const [deactivateApp] = useDeactivateAppMutation();\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n // Client-side filtering: org scope + search + type (status filtered server-side)\n const filteredApps = applications.filter((app: Application) => {\n const matchesOrg =\n !activeOrgId || app.developerOrganizationId === activeOrgId;\n const matchesSearch =\n !searchQuery ||\n app.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\n app.shortDescription?.toLowerCase().includes(searchQuery.toLowerCase());\n const matchesType = !typeFilter || app.appType === typeFilter;\n return matchesOrg && matchesSearch && matchesType;\n });\n\n const selectedApps = useMemo(\n () => applications.filter((app: Application) => selectedAppIds.has(app.id)),\n [applications, selectedAppIds],\n );\n\n const deactivatableApps = useMemo(\n () =>\n selectedApps.filter(\n (app: Application) =>\n app.status !== \"INACTIVE\" && app.status !== \"REVOKED\",\n ),\n [selectedApps],\n );\n\n const allVisibleSelected =\n filteredApps.length > 0 &&\n filteredApps.every((app: Application) => selectedAppIds.has(app.id));\n const partiallySelected =\n filteredApps.some((app: Application) => selectedAppIds.has(app.id)) &&\n !allVisibleSelected;\n\n const toggleAppSelection = (appId: string, checked: boolean) => {\n setSelectedAppIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(appId);\n } else {\n next.delete(appId);\n }\n return next;\n });\n };\n\n const toggleAllVisible = (checked: boolean) => {\n setSelectedAppIds((prev) => {\n const next = new Set(prev);\n filteredApps.forEach((app: Application) => {\n if (checked) {\n next.add(app.id);\n } else {\n next.delete(app.id);\n }\n });\n return next;\n });\n };\n\n const clearSelection = () => setSelectedAppIds(new Set());\n\n const runBulkDeactivate = async () => {\n if (deactivatableApps.length === 0) return;\n\n const results = await Promise.allSettled(\n deactivatableApps.map((app: Application) =>\n deactivateApp({ variables: { id: app.id } }),\n ),\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n\n setFeedback({\n type: failed === 0 ? \"success\" : \"error\",\n message: formatBulkResult(\"Deactivated\", succeeded, failed),\n });\n clearSelection();\n setBulkAction(null);\n await refetch();\n };\n\n const runBulkDelete = async () => {\n if (selectedApps.length === 0) return;\n\n const results = await Promise.allSettled(\n selectedApps.map((app: Application) =>\n deleteApplication({ variables: { id: app.id } }),\n ),\n );\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n\n setFeedback({\n type: failed === 0 ? \"success\" : \"error\",\n message: formatBulkResult(\"Deleted\", succeeded, failed),\n });\n clearSelection();\n setBulkAction(null);\n await refetch();\n };\n\n // Loading state\n if (loading && !data) {\n return (\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n <span className=\"ml-2 text-muted-foreground\">\n {tr(\"devportal.loadingApplications\", \"Loading applications...\")}\n </span>\n </div>\n </PageLayout>\n );\n }\n\n // Error state\n if (error) {\n return (\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n >\n <div className=\"rounded-lg border border-destructive/50 bg-destructive/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-destructive\" />\n <h3 className=\"mt-2 font-medium text-destructive\">\n {tr(\n \"devportal.failedToLoadApplications\",\n \"Failed to load applications\",\n )}\n </h3>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {getErrorMessage(error)}\n </p>\n <button\n onClick={() => refetch()}\n className=\"mt-4 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n {tr(\"devportal.tryAgain\", \"Try Again\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.APP_READ}>\n <PageLayout\n title={tr(\"devportal.myApplications\", \"My Applications\")}\n description={tr(\n \"devportal.manageYourApps\",\n \"Manage your developer applications\",\n )}\n actions={\n <button\n onClick={() => handleNavigate(\"/apps/new\")}\n disabled={!createPerm.allowed}\n aria-disabled={!createPerm.allowed}\n title={\n !createPerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\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 disabled:cursor-not-allowed focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Plus size={16} aria-hidden=\"true\" />\n {tr(\"devportal.createApp\", \"Create App\")}\n </button>\n }\n >\n {/* Filters */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex flex-1 items-center gap-4\">\n {/* Search */}\n <div className=\"relative flex-1 max-w-md\">\n <Search\n size={16}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground\"\n />\n <input\n type=\"text\"\n placeholder={tr(\n \"devportal.searchApplications\",\n \"Search applications...\",\n )}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full rounded-md border bg-background pl-9 pr-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n />\n </div>\n\n {/* Status Filter */}\n <select\n value={statusFilter}\n onChange={(e) =>\n setStatusFilter(e.target.value as AppStatus | \"\")\n }\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"\">\n {tr(\"devportal.allStatus\", \"All Status\")}\n </option>\n {Object.keys(APP_STATUS_COLORS).map((status) => (\n <option key={status} value={status}>\n {status.replace(/_/g, \" \")}\n </option>\n ))}\n </select>\n\n {/* Type Filter */}\n <select\n value={typeFilter}\n onChange={(e) => setTypeFilter(e.target.value as AppType | \"\")}\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"\">{tr(\"devportal.allTypes\", \"All Types\")}</option>\n {Object.entries(APP_TYPE_LABELS).map(([value, label]) => (\n <option key={value} value={value}>\n {label}\n </option>\n ))}\n </select>\n </div>\n\n {/* View Toggle */}\n <div className=\"flex items-center gap-1 rounded-md border p-1\">\n <button\n onClick={() => setViewMode(\"grid\")}\n className={`rounded p-1.5 ${viewMode === \"grid\" ? \"bg-muted\" : \"hover:bg-muted/50\"}`}\n title=\"Grid view\"\n >\n <Grid size={16} />\n </button>\n <button\n onClick={() => setViewMode(\"list\")}\n className={`rounded p-1.5 ${viewMode === \"list\" ? \"bg-muted\" : \"hover:bg-muted/50\"}`}\n title=\"List view\"\n >\n <List size={16} />\n </button>\n </div>\n </div>\n\n {feedback && (\n <div\n className={`rounded-lg border px-4 py-3 text-sm ${\n feedback.type === \"success\"\n ? \"border-border-subtle bg-status-success-bg-subtle text-status-success-text\"\n : \"border-destructive/40 bg-destructive/10 text-destructive\"\n }`}\n >\n <div className=\"flex items-center justify-between gap-3\">\n <span>{feedback.message}</span>\n <button\n onClick={() => setFeedback(null)}\n className=\"text-xs font-medium underline underline-offset-2\"\n >\n Dismiss\n </button>\n </div>\n </div>\n )}\n\n {filteredApps.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={toggleAllVisible}\n ariaLabel=\"Select all visible applications\"\n />\n <span className=\"text-sm font-medium\">\n Select all visible\n </span>\n </div>\n {selectedAppIds.size > 0 && (\n <button\n onClick={clearSelection}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n 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 {selectedAppIds.size} selected\n </span>\n <button\n onClick={() => setBulkAction(\"deactivate\")}\n disabled={\n deactivatableApps.length === 0 || !updatePerm.allowed\n }\n aria-disabled={\n deactivatableApps.length === 0 || !updatePerm.allowed\n }\n title={\n !updatePerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 rounded-md border border-status-warning-bg px-3 py-2 text-sm font-medium text-status-warning-text transition-colors hover:bg-status-warning-bg-subtle disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Archive size={16} aria-hidden=\"true\" />\n {tr(\"devportal.deactivateSelected\", \"Deactivate Selected\")}\n {deactivatableApps.length > 0\n ? ` (${deactivatableApps.length})`\n : \"\"}\n </button>\n <button\n onClick={() => setBulkAction(\"delete\")}\n disabled={selectedApps.length === 0 || !deletePerm.allowed}\n aria-disabled={\n selectedApps.length === 0 || !deletePerm.allowed\n }\n title={\n !deletePerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 rounded-md border border-status-error-bg px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n {tr(\"devportal.deleteSelected\", \"Delete Selected\")}\n {selectedApps.length > 0 ? ` (${selectedApps.length})` : \"\"}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Results count */}\n <p className=\"text-sm text-muted-foreground\">\n {filteredApps.length} application\n {filteredApps.length !== 1 ? \"s\" : \"\"} found\n </p>\n\n {/* Applications */}\n {filteredApps.length > 0 ? (\n viewMode === \"grid\" ? (\n <div className=\"grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {filteredApps.map((app: Application) => (\n <AppCard\n key={app.id}\n app={app}\n selected={selectedAppIds.has(app.id)}\n onToggleSelect={(checked) =>\n toggleAppSelection(app.id, checked)\n }\n />\n ))}\n </div>\n ) : (\n <div className=\"space-y-2\">\n {filteredApps.map((app: Application) => (\n <AppListItem\n key={app.id}\n app={app}\n selected={selectedAppIds.has(app.id)}\n onToggleSelect={(checked) =>\n toggleAppSelection(app.id, checked)\n }\n />\n ))}\n </div>\n )\n ) : (\n <EmptyState\n icon={<AppWindow size={32} />}\n title={tr(\"devportal.noApplicationsFound\", \"No applications found\")}\n description={\n searchQuery || statusFilter || typeFilter\n ? tr(\n \"devportal.tryAdjustingFilters\",\n \"Try adjusting your filters\",\n )\n : tr(\n \"devportal.createFirstApp\",\n \"Create your first application to get started\",\n )\n }\n action={\n !searchQuery && !statusFilter && !typeFilter ? (\n <button\n onClick={() => handleNavigate(\"/apps/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.createApp\", \"Create App\")}\n </button>\n ) : undefined\n }\n />\n )}\n\n <ConfirmDialog\n open={bulkAction === \"deactivate\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={runBulkDeactivate}\n title=\"Deactivate selected applications\"\n description={`Deactivate ${deactivatableApps.length} selected application${deactivatableApps.length === 1 ? \"\" : \"s\"}? Users and integrations may lose access until these apps are re-enabled.`}\n confirmLabel=\"Deactivate\"\n cancelLabel=\"Cancel\"\n variant=\"warning\"\n />\n\n <ConfirmDialog\n open={bulkAction === \"delete\"}\n onOpenChange={(open) => {\n if (!open) setBulkAction(null);\n }}\n onConfirm={runBulkDelete}\n title=\"Delete selected applications\"\n description={`Delete ${selectedApps.length} selected application${selectedApps.length === 1 ? \"\" : \"s\"}? This cannot be undone.`}\n confirmLabel=\"Delete\"\n cancelLabel=\"Cancel\"\n variant=\"danger\"\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useDevportal as e } from "../providers/DevportalProvider.js";
|
|
2
2
|
import { useDevportalEventBus as t } from "../events/index.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { useCurrentUserAppsQuery as n, useGenerateApiKeyMutation as r } from "../../generated/global-operations.js";
|
|
4
|
+
import { PageLayout as i, PageSection as a } from "../components/PageLayout.js";
|
|
5
|
+
import { NewSecretAlert as o } from "../components/SecretDisplay.js";
|
|
6
|
+
import { InputField as s, SelectField as c, TagInput as l } from "../components/FormField.js";
|
|
7
|
+
import { Alert as u } from "../components/ConfirmDialog.js";
|
|
8
8
|
import { PermissionGuard as d } from "../components/PermissionGuard.js";
|
|
9
9
|
import "../components/index.js";
|
|
10
10
|
import { DEVPORTAL_PERMISSIONS as f } from "../constants/permissions.js";
|
|
@@ -32,7 +32,7 @@ var w = () => {
|
|
|
32
32
|
let { t: S } = h(), w = (e, t) => {
|
|
33
33
|
let n = S(e);
|
|
34
34
|
return n === e ? t : n;
|
|
35
|
-
}, { navigate: T, basePath: E } = e(), [D, O] = m(null), [k, A] = m({}), [j, M] = m(null), [N, { loading: P }] =
|
|
35
|
+
}, { navigate: T, basePath: E } = e(), [D, O] = m(null), [k, A] = m({}), [j, M] = m(null), [N, { loading: P }] = r(), F = t(), { data: I, loading: L } = n({ fetchPolicy: "cache-and-network" }), R = I?.currentUserApps?.apps.map((e) => ({
|
|
36
36
|
id: e.id,
|
|
37
37
|
name: e.name,
|
|
38
38
|
clientId: e.clientId
|
|
@@ -82,19 +82,19 @@ var w = () => {
|
|
|
82
82
|
}, K = () => {
|
|
83
83
|
V("/api-keys");
|
|
84
84
|
};
|
|
85
|
-
return D ? /* @__PURE__ */ y(
|
|
85
|
+
return D ? /* @__PURE__ */ y(i, {
|
|
86
86
|
title: "API Key Generated",
|
|
87
87
|
description: "Your new API key has been generated successfully",
|
|
88
88
|
children: /* @__PURE__ */ b("div", {
|
|
89
89
|
className: "max-w-2xl space-y-6",
|
|
90
90
|
children: [
|
|
91
|
-
/* @__PURE__ */ y(
|
|
91
|
+
/* @__PURE__ */ y(o, {
|
|
92
92
|
title: "API Key & Secret",
|
|
93
93
|
secret: D.apiSecret,
|
|
94
94
|
description: "Store this secret securely — you won't be able to see it again.",
|
|
95
95
|
onDismiss: K
|
|
96
96
|
}),
|
|
97
|
-
/* @__PURE__ */ y(
|
|
97
|
+
/* @__PURE__ */ y(u, {
|
|
98
98
|
variant: "info",
|
|
99
99
|
title: "Usage Instructions",
|
|
100
100
|
children: /* @__PURE__ */ b("div", {
|
|
@@ -142,7 +142,7 @@ var w = () => {
|
|
|
142
142
|
})
|
|
143
143
|
}) : /* @__PURE__ */ y(d, {
|
|
144
144
|
permission: f.APP_UPDATE,
|
|
145
|
-
children: /* @__PURE__ */ y(
|
|
145
|
+
children: /* @__PURE__ */ y(i, {
|
|
146
146
|
title: "Generate API Key",
|
|
147
147
|
description: "Generate a new API key for programmatic access",
|
|
148
148
|
backLink: "/api-keys",
|
|
@@ -151,13 +151,13 @@ var w = () => {
|
|
|
151
151
|
onSubmit: G,
|
|
152
152
|
className: "max-w-3xl space-y-8",
|
|
153
153
|
children: [
|
|
154
|
-
j && /* @__PURE__ */ y(
|
|
154
|
+
j && /* @__PURE__ */ y(u, {
|
|
155
155
|
variant: "error",
|
|
156
156
|
title: "Error Generating API Key",
|
|
157
157
|
onDismiss: () => M(null),
|
|
158
158
|
children: j
|
|
159
159
|
}),
|
|
160
|
-
/* @__PURE__ */ y(
|
|
160
|
+
/* @__PURE__ */ y(a, {
|
|
161
161
|
title: "Basic Information",
|
|
162
162
|
description: "Configure the API key settings",
|
|
163
163
|
children: /* @__PURE__ */ b("div", {
|
|
@@ -168,7 +168,7 @@ var w = () => {
|
|
|
168
168
|
className: "text-sm text-muted-foreground",
|
|
169
169
|
children: "Loading apps..."
|
|
170
170
|
})]
|
|
171
|
-
}) : R.length === 0 ? /* @__PURE__ */ y(
|
|
171
|
+
}) : R.length === 0 ? /* @__PURE__ */ y(u, {
|
|
172
172
|
variant: "warning",
|
|
173
173
|
title: "No Apps Found",
|
|
174
174
|
children: /* @__PURE__ */ b("p", { children: [
|
|
@@ -181,7 +181,7 @@ var w = () => {
|
|
|
181
181
|
children: "Create an app"
|
|
182
182
|
})
|
|
183
183
|
] })
|
|
184
|
-
}) : /* @__PURE__ */ y(
|
|
184
|
+
}) : /* @__PURE__ */ y(c, {
|
|
185
185
|
label: "App",
|
|
186
186
|
value: z.appId,
|
|
187
187
|
onChange: (e) => U("appId", e.target.value),
|
|
@@ -193,7 +193,7 @@ var w = () => {
|
|
|
193
193
|
error: k.appId,
|
|
194
194
|
required: !0,
|
|
195
195
|
hint: "The OAuth app this API key will be associated with"
|
|
196
|
-
}), /* @__PURE__ */ y(
|
|
196
|
+
}), /* @__PURE__ */ y(s, {
|
|
197
197
|
label: "Key Name",
|
|
198
198
|
placeholder: "e.g., Production Backend Key",
|
|
199
199
|
value: z.name,
|
|
@@ -204,12 +204,12 @@ var w = () => {
|
|
|
204
204
|
})]
|
|
205
205
|
})
|
|
206
206
|
}),
|
|
207
|
-
/* @__PURE__ */ y(
|
|
207
|
+
/* @__PURE__ */ y(a, {
|
|
208
208
|
title: "Scopes",
|
|
209
209
|
description: "Define what this API key can access",
|
|
210
210
|
children: /* @__PURE__ */ y("div", {
|
|
211
211
|
className: "space-y-4",
|
|
212
|
-
children: /* @__PURE__ */ y(
|
|
212
|
+
children: /* @__PURE__ */ y(l, {
|
|
213
213
|
label: "Scopes",
|
|
214
214
|
value: z.scopes,
|
|
215
215
|
onChange: (e) => U("scopes", e),
|
|
@@ -222,10 +222,10 @@ var w = () => {
|
|
|
222
222
|
/* @__PURE__ */ y(x, {
|
|
223
223
|
title: "Advanced settings",
|
|
224
224
|
description: "Rate-limit overrides, allowed origins, scope tuning, and expiration.",
|
|
225
|
-
children: /* @__PURE__ */ b(
|
|
225
|
+
children: /* @__PURE__ */ b(a, {
|
|
226
226
|
title: "Key Expiration",
|
|
227
227
|
description: "Set when this key should expire",
|
|
228
|
-
children: [/* @__PURE__ */ y(
|
|
228
|
+
children: [/* @__PURE__ */ y(c, {
|
|
229
229
|
label: "Expires In",
|
|
230
230
|
value: z.expiresIn,
|
|
231
231
|
onChange: (e) => U("expiresIn", e.target.value),
|
|
@@ -256,7 +256,7 @@ var w = () => {
|
|
|
256
256
|
}
|
|
257
257
|
],
|
|
258
258
|
hint: "Keys can be revoked at any time regardless of expiration"
|
|
259
|
-
}), z.expiresIn === "never" && /* @__PURE__ */ y(
|
|
259
|
+
}), z.expiresIn === "never" && /* @__PURE__ */ y(u, {
|
|
260
260
|
variant: "warning",
|
|
261
261
|
className: "mt-4",
|
|
262
262
|
children: "Non-expiring keys are a security risk. Consider setting an expiration and rotating keys periodically."
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useDevportal as e } from "../providers/DevportalProvider.js";
|
|
2
2
|
import { useDevportalEventBus as t } from "../events/index.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { useCreateApplicationMutation as n, useCurrentUserAppsQuery as r, useGetMyOrganizationsQuery as i } from "../../generated/global-operations.js";
|
|
4
|
+
import { PageLayout as a, PageSection as o } from "../components/PageLayout.js";
|
|
5
|
+
import { APP_TYPE_LABELS as s } from "../utils/constants.js";
|
|
6
|
+
import { CheckboxField as c, InputField as l, SelectField as u, TagInput as d, TextareaField as f } from "../components/FormField.js";
|
|
7
7
|
import { PermissionGuard as p } from "../components/PermissionGuard.js";
|
|
8
8
|
import "../components/index.js";
|
|
9
9
|
import { DEVPORTAL_PERMISSIONS as m } from "../constants/permissions.js";
|
|
@@ -13,7 +13,7 @@ import { useI18n as g } from "@burdenoff/fe-libs/shared/providers/shell/I18nProv
|
|
|
13
13
|
import { Info as _, Save as v, X as y } from "lucide-react";
|
|
14
14
|
import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
15
15
|
//#region src/devportal/pages/CreateApplicationPage.tsx
|
|
16
|
-
var C = Object.entries(
|
|
16
|
+
var C = Object.entries(s).map(([e, t]) => ({
|
|
17
17
|
value: e,
|
|
18
18
|
label: t
|
|
19
19
|
})), w = [
|
|
@@ -63,10 +63,10 @@ var C = Object.entries(i).map(([e, t]) => ({
|
|
|
63
63
|
label: "Triggers"
|
|
64
64
|
}
|
|
65
65
|
], E = () => {
|
|
66
|
-
let { navigate:
|
|
66
|
+
let { navigate: s, basePath: E } = e(), { t: D } = g(), O = (e, t) => {
|
|
67
67
|
let n = D(e);
|
|
68
68
|
return n === e ? t : n;
|
|
69
|
-
}, [k, A] = h({}), [j, { loading: M }] =
|
|
69
|
+
}, [k, A] = h({}), [j, { loading: M }] = n(), N = t(), { data: P } = i({ fetchPolicy: "cache-and-network" }), { data: F, loading: I } = r({ fetchPolicy: "cache-and-network" }), L = [{
|
|
70
70
|
value: "",
|
|
71
71
|
label: "No organization (publish under personal account)"
|
|
72
72
|
}, ...(P?.myDeveloperOrganizations ?? []).map((e) => ({
|
|
@@ -98,7 +98,7 @@ var C = Object.entries(i).map(([e, t]) => ({
|
|
|
98
98
|
appId: "",
|
|
99
99
|
requiresApproval: !1
|
|
100
100
|
}), V = (e) => {
|
|
101
|
-
|
|
101
|
+
s?.(`${E}${e}`);
|
|
102
102
|
}, H = (e) => e.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, ""), U = (e) => {
|
|
103
103
|
let t = e.target.value;
|
|
104
104
|
B((e) => ({
|
|
@@ -123,7 +123,7 @@ var C = Object.entries(i).map(([e, t]) => ({
|
|
|
123
123
|
};
|
|
124
124
|
return /* @__PURE__ */ x(p, {
|
|
125
125
|
permission: m.APP_CREATE,
|
|
126
|
-
children: /* @__PURE__ */ x(
|
|
126
|
+
children: /* @__PURE__ */ x(a, {
|
|
127
127
|
title: O("devportal.createApplication", "Create Application"),
|
|
128
128
|
description: O("devportal.createApplicationDescription", "Register a new application in the developer portal"),
|
|
129
129
|
backLink: `${E}/apps`,
|
|
@@ -168,13 +168,13 @@ var C = Object.entries(i).map(([e, t]) => ({
|
|
|
168
168
|
},
|
|
169
169
|
className: "space-y-8 max-w-3xl",
|
|
170
170
|
children: [
|
|
171
|
-
/* @__PURE__ */ x(
|
|
171
|
+
/* @__PURE__ */ x(o, {
|
|
172
172
|
title: O("devportal.basicInformation", "Basic Information"),
|
|
173
173
|
description: O("devportal.basicInformationDescription", "Core details about your application"),
|
|
174
174
|
children: /* @__PURE__ */ S("div", {
|
|
175
175
|
className: "space-y-4",
|
|
176
176
|
children: [
|
|
177
|
-
/* @__PURE__ */ x(
|
|
177
|
+
/* @__PURE__ */ x(l, {
|
|
178
178
|
label: O("devportal.applicationName", "Application Name"),
|
|
179
179
|
value: z.name,
|
|
180
180
|
onChange: U,
|
|
@@ -183,7 +183,7 @@ var C = Object.entries(i).map(([e, t]) => ({
|
|
|
183
183
|
error: k.name,
|
|
184
184
|
hint: O("devportal.applicationNameHint", "Choose a memorable name for your application")
|
|
185
185
|
}),
|
|
186
|
-
/* @__PURE__ */ x(
|
|
186
|
+
/* @__PURE__ */ x(l, {
|
|
187
187
|
label: O("devportal.slug", "Slug"),
|
|
188
188
|
value: z.slug,
|
|
189
189
|
onChange: (e) => W("slug", e.target.value.toLowerCase()),
|
|
@@ -192,7 +192,7 @@ var C = Object.entries(i).map(([e, t]) => ({
|
|
|
192
192
|
error: k.slug,
|
|
193
193
|
hint: O("devportal.slugHint", "URL-friendly identifier (auto-generated from name)")
|
|
194
194
|
}),
|
|
195
|
-
/* @__PURE__ */ x(
|
|
195
|
+
/* @__PURE__ */ x(f, {
|
|
196
196
|
label: O("devportal.shortDescription", "Short Description"),
|
|
197
197
|
value: z.shortDescription,
|
|
198
198
|
onChange: (e) => W("shortDescription", e.target.value),
|
|
@@ -202,7 +202,7 @@ var C = Object.entries(i).map(([e, t]) => ({
|
|
|
202
202
|
hint: `${z.shortDescription.length}/200 ${O("devportal.characters", "characters")}`,
|
|
203
203
|
rows: 2
|
|
204
204
|
}),
|
|
205
|
-
/* @__PURE__ */ x(
|
|
205
|
+
/* @__PURE__ */ x(f, {
|
|
206
206
|
label: O("devportal.fullDescription", "Full Description"),
|
|
207
207
|
value: z.description,
|
|
208
208
|
onChange: (e) => W("description", e.target.value),
|
|
@@ -213,14 +213,14 @@ var C = Object.entries(i).map(([e, t]) => ({
|
|
|
213
213
|
]
|
|
214
214
|
})
|
|
215
215
|
}),
|
|
216
|
-
/* @__PURE__ */ S(
|
|
216
|
+
/* @__PURE__ */ S(o, {
|
|
217
217
|
title: O("devportal.classification", "Classification"),
|
|
218
218
|
description: O("devportal.classificationDescription", "Categorize your application"),
|
|
219
219
|
children: [
|
|
220
220
|
/* @__PURE__ */ S("div", {
|
|
221
221
|
className: "grid gap-4 sm:grid-cols-2",
|
|
222
222
|
children: [
|
|
223
|
-
/* @__PURE__ */ x(
|
|
223
|
+
/* @__PURE__ */ x(u, {
|
|
224
224
|
label: O("devportal.applicationType", "Application Type"),
|
|
225
225
|
value: z.appType,
|
|
226
226
|
onChange: (e) => W("appType", e.target.value),
|
|
@@ -229,7 +229,7 @@ var C = Object.entries(i).map(([e, t]) => ({
|
|
|
229
229
|
error: k.appType,
|
|
230
230
|
placeholder: O("devportal.selectAppType", "Select app type")
|
|
231
231
|
}),
|
|
232
|
-
/* @__PURE__ */ x(
|
|
232
|
+
/* @__PURE__ */ x(u, {
|
|
233
233
|
label: O("devportal.category", "Category"),
|
|
234
234
|
value: z.category,
|
|
235
235
|
onChange: (e) => W("category", e.target.value),
|
|
@@ -238,14 +238,14 @@ var C = Object.entries(i).map(([e, t]) => ({
|
|
|
238
238
|
error: k.category,
|
|
239
239
|
placeholder: O("devportal.selectCategory", "Select category")
|
|
240
240
|
}),
|
|
241
|
-
/* @__PURE__ */ x(
|
|
241
|
+
/* @__PURE__ */ x(u, {
|
|
242
242
|
label: O("devportal.visibility", "Visibility"),
|
|
243
243
|
value: z.visibility,
|
|
244
244
|
onChange: (e) => W("visibility", e.target.value),
|
|
245
245
|
options: w,
|
|
246
246
|
hint: O("devportal.visibilityHint", "Controls who can see this app once published. Public apps still require admin review and approval before appearing in the store.")
|
|
247
247
|
}),
|
|
248
|
-
/* @__PURE__ */ x(
|
|
248
|
+
/* @__PURE__ */ x(u, {
|
|
249
249
|
label: O("devportal.developerOrganization", "Developer Organization"),
|
|
250
250
|
value: z.developerOrganizationId,
|
|
251
251
|
onChange: (e) => W("developerOrganizationId", e.target.value),
|
|
@@ -254,14 +254,14 @@ var C = Object.entries(i).map(([e, t]) => ({
|
|
|
254
254
|
})
|
|
255
255
|
]
|
|
256
256
|
}),
|
|
257
|
-
/* @__PURE__ */ x(
|
|
257
|
+
/* @__PURE__ */ x(d, {
|
|
258
258
|
label: O("devportal.tags", "Tags"),
|
|
259
259
|
value: z.tags,
|
|
260
260
|
onChange: (e) => W("tags", e),
|
|
261
261
|
placeholder: O("devportal.addTagsPlaceholder", "Add tags (press Enter)"),
|
|
262
262
|
hint: O("devportal.tagsHint", "Help users discover your app")
|
|
263
263
|
}),
|
|
264
|
-
/* @__PURE__ */ x(
|
|
264
|
+
/* @__PURE__ */ x(d, {
|
|
265
265
|
label: O("devportal.keywords", "Keywords"),
|
|
266
266
|
value: z.keywords,
|
|
267
267
|
onChange: (e) => W("keywords", e),
|
|
@@ -270,12 +270,12 @@ var C = Object.entries(i).map(([e, t]) => ({
|
|
|
270
270
|
})
|
|
271
271
|
]
|
|
272
272
|
}),
|
|
273
|
-
/* @__PURE__ */ x(
|
|
273
|
+
/* @__PURE__ */ x(o, {
|
|
274
274
|
title: O("devportal.authenticationAndAuthorization", "Authentication & Authorization"),
|
|
275
275
|
description: O("devportal.authenticationAndAuthorizationDescription", "Link this marketplace app to an auth app for OAuth, client credentials, API keys, delegation, and device flows."),
|
|
276
276
|
children: /* @__PURE__ */ S("div", {
|
|
277
277
|
className: "space-y-4",
|
|
278
|
-
children: [/* @__PURE__ */ x(
|
|
278
|
+
children: [/* @__PURE__ */ x(u, {
|
|
279
279
|
label: O("devportal.linkedAuthApp", "Linked Auth App"),
|
|
280
280
|
value: z.appId,
|
|
281
281
|
onChange: (e) => W("appId", e.target.value),
|
|
@@ -290,48 +290,48 @@ var C = Object.entries(i).map(([e, t]) => ({
|
|
|
290
290
|
})]
|
|
291
291
|
})
|
|
292
292
|
}),
|
|
293
|
-
/* @__PURE__ */ x(
|
|
293
|
+
/* @__PURE__ */ x(o, {
|
|
294
294
|
title: O("devportal.links", "Links"),
|
|
295
295
|
description: O("devportal.linksDescription", "External resources for your application"),
|
|
296
296
|
children: /* @__PURE__ */ S("div", {
|
|
297
297
|
className: "grid gap-4 sm:grid-cols-2",
|
|
298
298
|
children: [
|
|
299
|
-
/* @__PURE__ */ x(
|
|
299
|
+
/* @__PURE__ */ x(l, {
|
|
300
300
|
label: O("devportal.websiteUrl", "Website URL"),
|
|
301
301
|
type: "url",
|
|
302
302
|
value: z.websiteUrl,
|
|
303
303
|
onChange: (e) => W("websiteUrl", e.target.value),
|
|
304
304
|
placeholder: "https://example.com"
|
|
305
305
|
}),
|
|
306
|
-
/* @__PURE__ */ x(
|
|
306
|
+
/* @__PURE__ */ x(l, {
|
|
307
307
|
label: O("devportal.documentationUrl", "Documentation URL"),
|
|
308
308
|
type: "url",
|
|
309
309
|
value: z.documentationUrl,
|
|
310
310
|
onChange: (e) => W("documentationUrl", e.target.value),
|
|
311
311
|
placeholder: "https://docs.example.com"
|
|
312
312
|
}),
|
|
313
|
-
/* @__PURE__ */ x(
|
|
313
|
+
/* @__PURE__ */ x(l, {
|
|
314
314
|
label: O("devportal.supportUrl", "Support URL"),
|
|
315
315
|
type: "url",
|
|
316
316
|
value: z.supportUrl,
|
|
317
317
|
onChange: (e) => W("supportUrl", e.target.value),
|
|
318
318
|
placeholder: "https://support.example.com"
|
|
319
319
|
}),
|
|
320
|
-
/* @__PURE__ */ x(
|
|
320
|
+
/* @__PURE__ */ x(l, {
|
|
321
321
|
label: O("devportal.githubUrl", "GitHub URL"),
|
|
322
322
|
type: "url",
|
|
323
323
|
value: z.githubUrl,
|
|
324
324
|
onChange: (e) => W("githubUrl", e.target.value),
|
|
325
325
|
placeholder: "https://github.com/org/repo"
|
|
326
326
|
}),
|
|
327
|
-
/* @__PURE__ */ x(
|
|
327
|
+
/* @__PURE__ */ x(l, {
|
|
328
328
|
label: O("devportal.privacyPolicyUrl", "Privacy Policy URL"),
|
|
329
329
|
type: "url",
|
|
330
330
|
value: z.privacyPolicyUrl,
|
|
331
331
|
onChange: (e) => W("privacyPolicyUrl", e.target.value),
|
|
332
332
|
placeholder: "https://example.com/privacy"
|
|
333
333
|
}),
|
|
334
|
-
/* @__PURE__ */ x(
|
|
334
|
+
/* @__PURE__ */ x(l, {
|
|
335
335
|
label: O("devportal.termsOfServiceUrl", "Terms of Service URL"),
|
|
336
336
|
type: "url",
|
|
337
337
|
value: z.termsOfServiceUrl,
|
|
@@ -341,12 +341,12 @@ var C = Object.entries(i).map(([e, t]) => ({
|
|
|
341
341
|
]
|
|
342
342
|
})
|
|
343
343
|
}),
|
|
344
|
-
/* @__PURE__ */ S(
|
|
344
|
+
/* @__PURE__ */ S(o, {
|
|
345
345
|
title: O("devportal.settings", "Settings"),
|
|
346
346
|
description: O("devportal.settingsDescription", "Additional configuration options"),
|
|
347
347
|
children: [/* @__PURE__ */ x("div", {
|
|
348
348
|
className: "space-y-4",
|
|
349
|
-
children: /* @__PURE__ */ x(
|
|
349
|
+
children: /* @__PURE__ */ x(c, {
|
|
350
350
|
label: O("devportal.requireWorkspaceAdminApproval", "Require workspace admin approval"),
|
|
351
351
|
description: O("devportal.requireWorkspaceAdminApprovalDescription", "When enabled, workspace admins must approve installations before users can access this app"),
|
|
352
352
|
checked: z.requiresApproval,
|