@burdenoff/microfe-devportal 2026.1112.2 → 2026.1113.2
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/DevportalRoot.js +65 -119
- package/dist/devportal/DevportalRoot.js.map +1 -1
- package/dist/devportal/components/AppCard.js +72 -69
- package/dist/devportal/components/AppCard.js.map +1 -1
- package/dist/devportal/components/DeveloperSettingsHub.d.ts +6 -0
- package/dist/devportal/components/DeveloperSettingsHub.js +59 -0
- package/dist/devportal/components/DeveloperSettingsHub.js.map +1 -0
- package/dist/devportal/components/ImageUploadField.js +82 -80
- package/dist/devportal/components/ImageUploadField.js.map +1 -1
- package/dist/devportal/components/SectionNav.d.ts +1 -1
- package/dist/devportal/components/SectionNav.js +60 -36
- package/dist/devportal/components/SectionNav.js.map +1 -1
- package/dist/devportal/components/StoreImage.d.ts +15 -0
- package/dist/devportal/components/StoreImage.js +30 -0
- package/dist/devportal/components/StoreImage.js.map +1 -0
- package/dist/devportal/components/index.d.ts +1 -0
- package/dist/devportal/components/index.js +17 -16
- package/dist/devportal/hooks/usePackageUpload.d.ts +46 -4
- package/dist/devportal/hooks/usePackageUpload.js +90 -36
- package/dist/devportal/hooks/usePackageUpload.js.map +1 -1
- package/dist/devportal/pages/AdminReviewPage.js +205 -202
- package/dist/devportal/pages/AdminReviewPage.js.map +1 -1
- package/dist/devportal/pages/AnalyticsDashboardPage.js +186 -179
- package/dist/devportal/pages/AnalyticsDashboardPage.js.map +1 -1
- package/dist/devportal/pages/ApiKeysPage.js +113 -111
- package/dist/devportal/pages/ApiKeysPage.js.map +1 -1
- package/dist/devportal/pages/AppLogsPage.js +80 -84
- package/dist/devportal/pages/AppLogsPage.js.map +1 -1
- package/dist/devportal/pages/ApplicationDetailPage.js +529 -504
- package/dist/devportal/pages/ApplicationDetailPage.js.map +1 -1
- package/dist/devportal/pages/ApplicationsPage.js +186 -183
- package/dist/devportal/pages/ApplicationsPage.js.map +1 -1
- package/dist/devportal/pages/CreateApiKeyPage.js +163 -166
- package/dist/devportal/pages/CreateApiKeyPage.js.map +1 -1
- package/dist/devportal/pages/CreateOAuthClientPage.js +134 -130
- package/dist/devportal/pages/CreateOAuthClientPage.js.map +1 -1
- package/dist/devportal/pages/CreatePhysicalItemPage.js +2 -2
- package/dist/devportal/pages/CreatePhysicalItemPage.js.map +1 -1
- package/dist/devportal/pages/DelegationsPage.js +11 -11
- package/dist/devportal/pages/DocumentationPage.js +100 -94
- package/dist/devportal/pages/DocumentationPage.js.map +1 -1
- package/dist/devportal/pages/EditApplicationPage.js +379 -377
- package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
- package/dist/devportal/pages/EditPhysicalItemPage.js +312 -307
- package/dist/devportal/pages/EditPhysicalItemPage.js.map +1 -1
- package/dist/devportal/pages/InvitationDecisionPage.js +83 -79
- package/dist/devportal/pages/InvitationDecisionPage.js.map +1 -1
- package/dist/devportal/pages/ListingPreviewPage.js +175 -171
- package/dist/devportal/pages/ListingPreviewPage.js.map +1 -1
- package/dist/devportal/pages/OAuthClientDetailPage.js +76 -76
- package/dist/devportal/pages/OAuthClientDetailPage.js.map +1 -1
- package/dist/devportal/pages/OAuthClientsPage.js +126 -124
- package/dist/devportal/pages/OAuthClientsPage.js.map +1 -1
- package/dist/devportal/pages/OrganizationDetailPage.js +19 -19
- package/dist/devportal/pages/OrganizationMembersPage.js +223 -204
- package/dist/devportal/pages/OrganizationMembersPage.js.map +1 -1
- package/dist/devportal/pages/ResourcesPage.d.ts +6 -0
- package/dist/devportal/pages/ResourcesPage.js +171 -155
- package/dist/devportal/pages/ResourcesPage.js.map +1 -1
- package/dist/devportal/pages/SellerDashboardPage.js +117 -115
- package/dist/devportal/pages/SellerDashboardPage.js.map +1 -1
- package/dist/devportal/pages/SellerItemsPage.js +202 -199
- package/dist/devportal/pages/SellerItemsPage.js.map +1 -1
- package/dist/devportal/pages/SettingsPage.js +330 -315
- package/dist/devportal/pages/SettingsPage.js.map +1 -1
- package/dist/devportal/pages/SetupPage.js +5 -5
- package/dist/devportal/pages/StoreSubmissionPage.js +133 -131
- package/dist/devportal/pages/StoreSubmissionPage.js.map +1 -1
- package/dist/devportal/pages/WebhookDetailPage.js +6 -6
- package/dist/devportal/pages/WebhooksPage.js +39 -39
- package/dist/devportal/pages/WebhooksPage.js.map +1 -1
- package/dist/devportal/utils/appDetailTabs.d.ts +73 -0
- package/dist/devportal/utils/appDetailTabs.js +62 -0
- package/dist/devportal/utils/appDetailTabs.js.map +1 -0
- package/dist/devportal/utils/developerNav.d.ts +39 -0
- package/dist/devportal/utils/developerNav.js +304 -0
- package/dist/devportal/utils/developerNav.js.map +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StoreSubmissionPage.js","names":["StoreIcon","APP_QUERY","SUBMIT_MUTATION","UNLIST_MUTATION","PUBLISH_VERSION_MUTATION","inferSubmission","app","metadata","productId","rawMetaStatus","status","metaSubmittedAt","statusLabels","Clock","CheckCircle2","EyeOff","XCircle","AlertTriangle","StoreSubmissionPage","useParams","navigate","useNavigate","bus","useDevportalEventBus","tr","useTr","submitPerm","useDevportalPermission","DEVPORTAL_PERMISSIONS","setApp","useState","loading","setLoading","error","setError","submitting","setSubmitting","unlisting","setUnlisting","showUnlistConfirm","setShowUnlistConfirm","overrideStatus","setOverrideStatus","notes","setNotes","load","appId","result","graphqlFetch","err","useEffect","name","reg","submit","draftVersions","v","vResult","unlist","submission","effectiveStatus","statusMeta","StatusIcon","allVersions","isPackageApp","noVersionsBlock","ArrowLeft","Store","RefreshCw","PagePurpose","GitBranch","Package","IllustratedEmptyState"],"sources":["../../../src/devportal/pages/StoreSubmissionPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { useNavigate, useParams } from \"react-router\";\nimport {\n ArrowLeft,\n CheckCircle2,\n Clock,\n RefreshCw,\n XCircle,\n AlertTriangle,\n Store as StoreIcon,\n EyeOff,\n Package,\n GitBranch,\n} from \"lucide-react\";\nimport { graphqlFetch } from \"@burdenoff/fe-libs/shared/graphql\";\nimport { IllustratedEmptyState, PagePurpose } from \"@burdenoff/fe-libs/ui\";\nimport { useDevportalEventBus } from \"../events\";\nimport { useTr } from \"../utils/i18n\";\nimport { useDevportalPermission } from \"../hooks\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\n\ntype SubmissionStatus =\n | \"DRAFT\"\n | \"PENDING_REVIEW\"\n | \"PUBLISHED\"\n | \"UNLISTED\"\n | \"REJECTED\"\n | \"UNKNOWN\";\n\ntype StoreSubmission = {\n productId: string;\n status: SubmissionStatus;\n submittedAt: string | null;\n reviewedAt: string | null;\n publishedAt: string | null;\n reviewNotes: string | null;\n rejectedReason: string | null;\n};\n\ntype ApplicationVersion = {\n id: string;\n version: string;\n status: string;\n releaseNotes: string | null;\n packageUrl: string | null;\n};\n\ntype Application = {\n id: string;\n name: string;\n slug: string;\n status: string;\n appType: string;\n reviewStatus: string;\n reviewNotes: string | null;\n iconUrl: string | null;\n submittedAt: string | null;\n metadata: Record<string, unknown> | null;\n versions: { edges: { node: ApplicationVersion }[] };\n};\n\nconst APP_QUERY = /* GraphQL */ `\n query DevportalAppForSubmission($id: ID!) {\n application(id: $id) {\n id\n name\n slug\n status\n appType\n reviewStatus\n reviewNotes\n iconUrl\n submittedAt\n metadata\n versions {\n edges {\n node {\n id\n version\n status\n releaseNotes\n packageUrl\n }\n }\n }\n }\n }\n`;\n\nconst SUBMIT_MUTATION = /* GraphQL */ `\n mutation DevportalSubmitForReview($id: ID!, $notes: String) {\n submitApplicationForReview(id: $id, notes: $notes) {\n id\n status\n submittedAt\n metadata\n }\n }\n`;\n\nconst UNLIST_MUTATION = /* GraphQL */ `\n mutation DevportalUnlistProduct($id: ID!) {\n unlistProduct(id: $id) {\n id\n status\n }\n }\n`;\n\nconst PUBLISH_VERSION_MUTATION = /* GraphQL */ `\n mutation DevportalPublishVersion($id: ID!) {\n publishApplicationVersion(id: $id) {\n id\n status\n }\n }\n`;\n\nfunction inferSubmission(app: Application | null): StoreSubmission | null {\n if (!app) return null;\n const metadata = (app.metadata ?? {}) as Record<string, unknown>;\n const productId =\n typeof metadata.storeProductId === \"string\" ? metadata.storeProductId : \"\";\n\n // Prefer metadata status (most accurate), but fall back to app.status so the\n // page reflects reality even when the metadata write failed after submission.\n const rawMetaStatus =\n typeof metadata.storeSubmissionStatus === \"string\"\n ? metadata.storeSubmissionStatus\n : null;\n\n let status: SubmissionStatus;\n if (\n rawMetaStatus === \"PENDING_REVIEW\" ||\n rawMetaStatus === \"PUBLISHED\" ||\n rawMetaStatus === \"REJECTED\" ||\n rawMetaStatus === \"DRAFT\"\n ) {\n status = rawMetaStatus;\n } else if (app.status === \"SUBMITTED\") {\n status = \"PENDING_REVIEW\";\n } else if (app.status === \"PUBLISHED\") {\n status = \"PUBLISHED\";\n } else if (app.status === \"REJECTED\") {\n status = \"REJECTED\";\n } else {\n status = \"UNKNOWN\";\n }\n\n const metaSubmittedAt =\n typeof metadata.storeSubmissionAt === \"string\"\n ? metadata.storeSubmissionAt\n : null;\n\n return {\n productId,\n status,\n submittedAt: metaSubmittedAt ?? app.submittedAt,\n reviewedAt: null,\n publishedAt: null,\n reviewNotes: null,\n rejectedReason: null,\n };\n}\n\ntype StatusMeta = {\n i18nKey: string;\n fallback: string;\n icon: typeof CheckCircle2;\n tone: string;\n};\n\nconst statusLabels: Record<SubmissionStatus, StatusMeta> = {\n DRAFT: {\n i18nKey: \"devportal.storeSubmission.status.draft\",\n fallback: \"Draft\",\n icon: Clock,\n tone: \"text-text-secondary\",\n },\n PENDING_REVIEW: {\n i18nKey: \"devportal.storeSubmission.status.pending\",\n fallback: \"Pending review\",\n icon: Clock,\n tone: \"text-status-warning-text\",\n },\n PUBLISHED: {\n i18nKey: \"devportal.storeSubmission.status.published\",\n fallback: \"Published\",\n icon: CheckCircle2,\n tone: \"text-status-success-text\",\n },\n UNLISTED: {\n i18nKey: \"devportal.storeSubmission.status.unlisted\",\n fallback: \"Unlisted\",\n icon: EyeOff,\n tone: \"text-text-secondary\",\n },\n REJECTED: {\n i18nKey: \"devportal.storeSubmission.status.rejected\",\n fallback: \"Rejected\",\n icon: XCircle,\n tone: \"text-status-danger-text\",\n },\n UNKNOWN: {\n i18nKey: \"devportal.storeSubmission.status.unknown\",\n fallback: \"Not yet submitted\",\n icon: AlertTriangle,\n tone: \"text-text-tertiary\",\n },\n};\n\nexport const StoreSubmissionPage: FC = () => {\n const { appId } = useParams<{ appId: string }>();\n const navigate = useNavigate();\n const bus = useDevportalEventBus();\n const tr = useTr();\n const submitPerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_SUBMIT);\n const [app, setApp] = useState<Application | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [submitting, setSubmitting] = useState(false);\n const [unlisting, setUnlisting] = useState(false);\n const [showUnlistConfirm, setShowUnlistConfirm] = useState(false);\n const [overrideStatus, setOverrideStatus] = useState<SubmissionStatus | null>(\n null,\n );\n const [notes, setNotes] = useState(\"\");\n const load = async () => {\n if (!appId) return;\n setLoading(true);\n setError(null);\n try {\n const result = await graphqlFetch<{ application: Application | null }>({\n gateway: \"global\",\n query: APP_QUERY,\n variables: { id: appId },\n });\n if (result.errors?.length) {\n throw new Error(\n result.errors[0]?.message ??\n tr(\n \"devportal.storeSubmission.errors.loadFailed\",\n \"Failed to load application\",\n ),\n );\n }\n setApp(result.data?.application ?? null);\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.storeSubmission.errors.loadFailed\",\n \"Failed to load application\",\n ),\n );\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n void load();\n }, [appId]); // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n const name = app?.name;\n if (!appId || !name) return;\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n reg?.register(appId, name);\n return () => reg?.unregister(appId);\n }, [appId, app?.name]);\n\n const submit = async () => {\n if (!appId) return;\n setSubmitting(true);\n setError(null);\n try {\n // Auto-publish all draft versions alongside the app submission\n const draftVersions = (app?.versions.edges ?? [])\n .map((e) => e.node)\n .filter((v) => v.status === \"draft\");\n for (const v of draftVersions) {\n const vResult = await graphqlFetch({\n gateway: \"global\",\n query: PUBLISH_VERSION_MUTATION,\n variables: { id: v.id },\n });\n if (vResult.errors?.length) {\n throw new Error(\n vResult.errors[0]?.message ??\n `Failed to submit version ${v.version}`,\n );\n }\n }\n\n const result = await graphqlFetch({\n gateway: \"global\",\n query: SUBMIT_MUTATION,\n variables: { id: appId, notes: notes || null },\n });\n if (result.errors?.length) {\n throw new Error(\n result.errors[0]?.message ??\n tr(\n \"devportal.storeSubmission.errors.submitFailed\",\n \"Submission failed\",\n ),\n );\n }\n bus.emit(\"devportal.app.submitted\", { appId });\n await load();\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.storeSubmission.errors.submitFailed\",\n \"Submission failed\",\n ),\n );\n } finally {\n setSubmitting(false);\n }\n };\n\n const unlist = async () => {\n const productId = inferSubmission(app)?.productId;\n if (!productId) return;\n setUnlisting(true);\n setError(null);\n try {\n const result = await graphqlFetch({\n gateway: \"global\",\n query: UNLIST_MUTATION,\n variables: { id: productId },\n });\n if (result.errors?.length) {\n throw new Error(\n result.errors[0]?.message ??\n tr(\n \"devportal.storeSubmission.errors.unlistFailed\",\n \"Failed to unlist\",\n ),\n );\n }\n setOverrideStatus(\"UNLISTED\");\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.storeSubmission.errors.unlistFailed\",\n \"Failed to unlist\",\n ),\n );\n } finally {\n setUnlisting(false);\n setShowUnlistConfirm(false);\n }\n };\n\n const submission = inferSubmission(app);\n const effectiveStatus = overrideStatus ?? submission?.status ?? \"UNKNOWN\";\n const statusMeta = statusLabels[effectiveStatus];\n const StatusIcon = statusMeta.icon;\n\n const allVersions = (app?.versions.edges ?? []).map((e) => e.node);\n const draftVersions = allVersions.filter((v) => v.status === \"draft\");\n const isPackageApp = app?.appType === \"NODE\" || app?.appType === \"WORKFLOW\";\n const noVersionsBlock = isPackageApp && allVersions.length === 0;\n\n return (\n <main\n className=\"min-h-screen bg-surface-default\"\n aria-labelledby=\"store-submission-heading\"\n >\n <div className=\"border-b border-border-default bg-surface-raised\">\n <div className=\"mx-auto max-w-3xl px-6 py-4\">\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => navigate(-1)}\n className=\"inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-sm text-text-secondary hover:bg-surface-hover hover:text-text-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <ArrowLeft className=\"h-4 w-4\" aria-hidden=\"true\" />\n {tr(\"devportal.common.back\", \"Back\")}\n </button>\n <div className=\"flex items-center gap-2\">\n <StoreIcon\n className=\"h-5 w-5 text-text-primary\"\n aria-hidden=\"true\"\n />\n <h1\n id=\"store-submission-heading\"\n className=\"text-xl font-semibold text-text-primary\"\n >\n {tr(\"devportal.storeSubmission.title\", \"Store submission\")}\n </h1>\n </div>\n </div>\n </div>\n </div>\n\n {/* Unlist confirm dialog */}\n {showUnlistConfirm && (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"unlist-dialog-title\"\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\"\n >\n <div className=\"w-full max-w-md rounded-lg border border-border-default bg-surface-raised p-6 shadow-xl\">\n <div className=\"mb-4 flex items-start gap-3\">\n <EyeOff\n className=\"mt-0.5 h-5 w-5 shrink-0 text-text-secondary\"\n aria-hidden=\"true\"\n />\n <div>\n <h2\n id=\"unlist-dialog-title\"\n className=\"text-base font-semibold text-text-primary\"\n >\n {tr(\n \"devportal.storeSubmission.unlistTitle\",\n \"Unlist from marketplace?\",\n )}\n </h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.unlistDescription\",\n \"Your app will no longer appear in the marketplace for new users. Existing installations are not affected — users who already have it installed can continue using it.\",\n )}\n </p>\n </div>\n </div>\n <div className=\"flex justify-end gap-3\">\n <button\n type=\"button\"\n onClick={() => setShowUnlistConfirm(false)}\n className=\"rounded-md border border-border-default px-4 py-2 text-sm font-medium text-text-secondary hover:bg-surface-hover\"\n >\n {tr(\"devportal.common.cancel\", \"Cancel\")}\n </button>\n <button\n type=\"button\"\n onClick={() => void unlist()}\n disabled={unlisting}\n className=\"inline-flex items-center gap-2 rounded-md bg-surface-danger px-4 py-2 text-sm font-semibold text-text-on-danger hover:opacity-90 disabled:opacity-60\"\n >\n {unlisting && (\n <RefreshCw\n className=\"h-4 w-4 animate-spin\"\n aria-hidden=\"true\"\n />\n )}\n {tr(\"devportal.storeSubmission.confirmUnlist\", \"Unlist app\")}\n </button>\n </div>\n </div>\n </div>\n )}\n\n <div className=\"mx-auto max-w-3xl px-6 py-6\">\n {(loading ||\n !submission ||\n effectiveStatus === \"UNKNOWN\" ||\n effectiveStatus === \"DRAFT\" ||\n effectiveStatus === \"REJECTED\") && (\n <PagePurpose className=\"mb-5\">\n {tr(\n \"devportal.storeSubmission.purpose\",\n \"Finalize the details the marketplace needs before your app can be reviewed — pricing, categories, and required assets. Completing this is what makes the app eligible to submit for publication.\",\n )}\n </PagePurpose>\n )}\n\n {error && (\n <div\n role=\"alert\"\n className=\"mb-4 rounded-md border border-border-danger bg-surface-danger-muted px-4 py-3 text-sm text-text-danger\"\n >\n {error}\n </div>\n )}\n\n {loading && !app ? (\n <div\n className=\"py-16 text-center text-text-secondary\"\n role=\"status\"\n aria-live=\"polite\"\n >\n {tr(\"devportal.storeSubmission.loading\", \"Loading application…\")}\n </div>\n ) : !app ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title={tr(\n \"devportal.storeSubmission.notFoundTitle\",\n \"Application not found\",\n )}\n description={tr(\n \"devportal.storeSubmission.notFound\",\n \"Application not found.\",\n )}\n />\n ) : (\n <div className=\"space-y-4\">\n {/* App header card */}\n <div className=\"rounded-lg border border-border-default bg-surface-raised p-4\">\n <div className=\"flex items-center gap-3\">\n {app.iconUrl ? (\n <img\n src={app.iconUrl}\n alt=\"\"\n className=\"h-14 w-14 flex-shrink-0 rounded-md object-cover\"\n />\n ) : (\n <div className=\"flex h-14 w-14 flex-shrink-0 items-center justify-center rounded-md bg-surface-muted text-text-secondary text-sm font-medium\">\n {app.name.slice(0, 2).toUpperCase()}\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {app.name}\n </h2>\n <p className=\"font-mono text-xs text-text-tertiary\">\n {app.slug}\n </p>\n </div>\n <div\n className={`flex items-center gap-1.5 ${statusMeta.tone}`}\n role=\"status\"\n >\n <StatusIcon className=\"h-5 w-5\" aria-hidden=\"true\" />\n <span className=\"text-sm font-medium\">\n {tr(statusMeta.i18nKey, statusMeta.fallback)}\n </span>\n </div>\n </div>\n </div>\n\n {/* Pending review — what happens next */}\n {effectiveStatus === \"PENDING_REVIEW\" && (\n <div className=\"rounded-lg border border-primary/20 bg-action-primary-bg/5 p-5 space-y-4\">\n <div className=\"flex items-start gap-3\">\n <Clock\n className=\"h-5 w-5 mt-0.5 shrink-0 text-primary\"\n aria-hidden=\"true\"\n />\n <div>\n <p className=\"text-sm font-semibold text-text-primary\">\n {tr(\n \"devportal.storeSubmission.underReview\",\n \"Your app is under review\",\n )}\n </p>\n {app.submittedAt && (\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.submittedOn\",\n \"Submitted on\",\n )}{\" \"}\n {new Date(app.submittedAt).toLocaleString()}\n </p>\n )}\n </div>\n </div>\n\n <div className=\"border-t border-border-default pt-4\">\n <p className=\"text-xs font-medium text-text-secondary mb-3\">\n {tr(\n \"devportal.storeSubmission.whatNext\",\n \"What happens next\",\n )}\n </p>\n <ol className=\"space-y-2.5 text-sm text-text-secondary\">\n <li className=\"flex items-start gap-2\">\n <span className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-surface-muted text-xs font-medium text-text-tertiary\">\n 1\n </span>\n Our team reviews your app's listing, assets, and\n compliance.\n </li>\n <li className=\"flex items-start gap-2\">\n <span className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-surface-muted text-xs font-medium text-text-tertiary\">\n 2\n </span>\n You'll receive a notification when a decision is made.\n </li>\n <li className=\"flex items-start gap-2\">\n <span className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-surface-muted text-xs font-medium text-text-tertiary\">\n 3\n </span>\n If approved, your app goes live in the marketplace\n automatically.\n </li>\n </ol>\n </div>\n\n {app.reviewNotes && (\n <div className=\"border-t border-border-default pt-4\">\n <p className=\"text-xs font-medium text-text-secondary mb-1\">\n {tr(\n \"devportal.storeSubmission.reviewerNotes\",\n \"Reviewer notes\",\n )}\n </p>\n <p className=\"text-sm text-text-primary\">\n {app.reviewNotes}\n </p>\n </div>\n )}\n </div>\n )}\n\n {/* Published */}\n {effectiveStatus === \"PUBLISHED\" && (\n <div className=\"rounded-lg border border-status-success-bg bg-status-success-bg-subtle p-5 space-y-4\">\n <div className=\"flex items-start gap-3\">\n <CheckCircle2\n className=\"h-5 w-5 mt-0.5 shrink-0 text-status-success-text\"\n aria-hidden=\"true\"\n />\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-semibold text-status-success-text\">\n {tr(\n \"devportal.storeSubmission.publishedTitle\",\n \"Your app is live in the marketplace\",\n )}\n </p>\n {submission?.publishedAt && (\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.publishedOn\",\n \"Published on\",\n )}{\" \"}\n {new Date(submission.publishedAt).toLocaleString()}\n </p>\n )}\n </div>\n </div>\n {submission?.productId && (\n <div className=\"border-t border-status-success-bg pt-4\">\n <p className=\"mb-2 text-xs text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.unlistHint\",\n \"Need to remove this app from the marketplace? Unlisting hides it from new users while keeping existing installations active.\",\n )}\n </p>\n <button\n type=\"button\"\n onClick={() => setShowUnlistConfirm(true)}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-default bg-surface-raised px-3 py-1.5 text-sm font-medium text-text-secondary hover:bg-surface-hover hover:text-text-primary\"\n >\n <EyeOff className=\"h-4 w-4\" aria-hidden=\"true\" />\n {tr(\n \"devportal.storeSubmission.unlistButton\",\n \"Unlist from marketplace\",\n )}\n </button>\n </div>\n )}\n </div>\n )}\n\n {/* Unlisted */}\n {effectiveStatus === \"UNLISTED\" && (\n <div className=\"rounded-lg border border-border-default bg-surface-muted p-5 flex items-start gap-3\">\n <EyeOff\n className=\"h-5 w-5 mt-0.5 shrink-0 text-text-secondary\"\n aria-hidden=\"true\"\n />\n <div>\n <p className=\"text-sm font-semibold text-text-primary\">\n {tr(\n \"devportal.storeSubmission.unlistedTitle\",\n \"Your app has been unlisted\",\n )}\n </p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.unlistedDescription\",\n \"It no longer appears in the marketplace for new users. Existing installations remain active and unaffected.\",\n )}\n </p>\n </div>\n </div>\n )}\n\n {/* Rejected */}\n {effectiveStatus === \"REJECTED\" && (\n <div className=\"rounded-lg border border-status-error-bg bg-status-error-bg-subtle p-5 space-y-3\">\n <div className=\"flex items-start gap-3\">\n <XCircle\n className=\"h-5 w-5 mt-0.5 shrink-0 text-status-error-text\"\n aria-hidden=\"true\"\n />\n <div>\n <p className=\"text-sm font-semibold text-status-error-text\">\n {tr(\n \"devportal.storeSubmission.rejectedTitle\",\n \"Submission was not approved\",\n )}\n </p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.rejectedHint\",\n \"Address the feedback below and resubmit.\",\n )}\n </p>\n </div>\n </div>\n {app.reviewNotes && (\n <div className=\"rounded-md bg-surface-muted p-3\">\n <p className=\"text-xs font-medium text-text-secondary mb-1\">\n {tr(\n \"devportal.storeSubmission.reviewerFeedback\",\n \"Reviewer feedback\",\n )}\n </p>\n <p className=\"text-sm text-text-primary\">\n {app.reviewNotes}\n </p>\n </div>\n )}\n </div>\n )}\n\n {/* Submit / resubmit form */}\n {(effectiveStatus === \"UNKNOWN\" ||\n effectiveStatus === \"DRAFT\" ||\n effectiveStatus === \"REJECTED\") && (\n <div className=\"rounded-lg border border-border-default bg-surface-raised p-4 space-y-4\">\n <div>\n <h3 className=\"mb-1 text-sm font-semibold text-text-primary\">\n {effectiveStatus === \"REJECTED\"\n ? tr(\n \"devportal.storeSubmission.resubmitForReview\",\n \"Resubmit for review\",\n )\n : tr(\n \"devportal.storeSubmission.submitForReview\",\n \"Submit for review\",\n )}\n </h3>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.help\",\n \"Your application will be sent to the store's review queue. Whether it's auto-published or requires admin approval depends on the target store's configuration.\",\n )}\n </p>\n </div>\n\n {/* Versions included in this submission */}\n {isPackageApp && (\n <div className=\"rounded-md border border-border-default bg-surface-muted p-3 space-y-2\">\n <div className=\"flex items-center gap-2 text-xs font-medium text-text-secondary\">\n <GitBranch className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n {tr(\n \"devportal.storeSubmission.versionsIncluded\",\n \"Versions included in this submission\",\n )}\n </div>\n\n {noVersionsBlock ? (\n <div className=\"flex items-start gap-2 text-sm text-status-danger-text\">\n <AlertTriangle\n className=\"h-4 w-4 mt-0.5 shrink-0\"\n aria-hidden=\"true\"\n />\n <span>\n {tr(\n \"devportal.storeSubmission.noVersionsError\",\n \"You must create at least one version before submitting. Go to the Versions tab to create one.\",\n )}\n </span>\n </div>\n ) : draftVersions.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.noDraftVersions\",\n \"No draft versions — all versions are already submitted or published.\",\n )}\n </p>\n ) : (\n <ul className=\"space-y-1\">\n {draftVersions.map((v) => (\n <li\n key={v.id}\n className=\"flex items-center gap-2 text-sm\"\n >\n <Package\n className=\"h-3.5 w-3.5 text-text-secondary shrink-0\"\n aria-hidden=\"true\"\n />\n <span className=\"font-mono font-medium\">\n {v.version}\n </span>\n {v.releaseNotes && (\n <span className=\"text-xs text-text-secondary truncate\">\n — {v.releaseNotes}\n </span>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n\n <div>\n <label className=\"block\" htmlFor=\"store-submission-notes\">\n <span className=\"sr-only\">\n {tr(\n \"devportal.storeSubmission.notesLabel\",\n \"Notes for the reviewer (optional)\",\n )}\n </span>\n </label>\n <textarea\n id=\"store-submission-notes\"\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n rows={3}\n placeholder={tr(\n \"devportal.storeSubmission.notesLabel\",\n \"Notes for the reviewer (optional)\",\n )}\n className=\"mb-3 w-full rounded-md border border-border-default bg-surface-default px-3 py-2 text-sm text-text-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n />\n <button\n type=\"button\"\n onClick={() => void submit()}\n disabled={\n submitting || !submitPerm.allowed || noVersionsBlock\n }\n aria-disabled={\n submitting || !submitPerm.allowed || noVersionsBlock\n }\n title={\n noVersionsBlock\n ? tr(\n \"devportal.storeSubmission.noVersionsError\",\n \"Create a version first\",\n )\n : !submitPerm.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-action-primary-bg px-4 py-2 text-sm font-semibold text-action-primary-text hover:opacity-90 disabled:opacity-60 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n {submitting && (\n <RefreshCw\n className=\"h-4 w-4 animate-spin\"\n aria-hidden=\"true\"\n />\n )}\n {effectiveStatus === \"REJECTED\"\n ? tr(\"devportal.storeSubmission.resubmit\", \"Resubmit\")\n : tr(\n \"devportal.storeSubmission.submitForReview\",\n \"Submit for review\",\n )}\n </button>\n </div>\n </div>\n )}\n\n {submission?.productId && (\n <div className=\"rounded-lg border border-border-default bg-surface-raised p-4\">\n <p className=\"text-xs font-medium text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.storeProductId\",\n \"Store product ID\",\n )}\n </p>\n <code className=\"mt-1 block break-all font-mono text-xs text-text-primary\">\n {submission.productId}\n </code>\n </div>\n )}\n </div>\n )}\n </div>\n </main>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"StoreSubmissionPage.js","names":["StoreIcon","APP_QUERY","SUBMIT_MUTATION","UNLIST_MUTATION","PUBLISH_VERSION_MUTATION","inferSubmission","app","metadata","productId","rawMetaStatus","status","metaSubmittedAt","statusLabels","Clock","CheckCircle2","EyeOff","XCircle","AlertTriangle","StoreSubmissionPage","useParams","navigate","useNavigate","bus","useDevportalEventBus","tr","useTr","submitPerm","useDevportalPermission","DEVPORTAL_PERMISSIONS","setApp","useState","loading","setLoading","error","setError","submitting","setSubmitting","unlisting","setUnlisting","showUnlistConfirm","setShowUnlistConfirm","overrideStatus","setOverrideStatus","notes","setNotes","load","appId","result","graphqlFetch","err","useEffect","name","reg","submit","draftVersions","v","vResult","unlist","submission","effectiveStatus","statusMeta","StatusIcon","allVersions","isPackageApp","noVersionsBlock","ArrowLeft","Store","RefreshCw","PagePurpose","StoreImage","GitBranch","Package","IllustratedEmptyState"],"sources":["../../../src/devportal/pages/StoreSubmissionPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { useNavigate, useParams } from \"react-router\";\nimport {\n ArrowLeft,\n CheckCircle2,\n Clock,\n RefreshCw,\n XCircle,\n AlertTriangle,\n Store as StoreIcon,\n EyeOff,\n Package,\n GitBranch,\n} from \"lucide-react\";\nimport { graphqlFetch } from \"@burdenoff/fe-libs/shared/graphql\";\nimport { IllustratedEmptyState, PagePurpose } from \"@burdenoff/fe-libs/ui\";\nimport { useDevportalEventBus } from \"../events\";\nimport { useTr } from \"../utils/i18n\";\nimport { useDevportalPermission } from \"../hooks\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { StoreImage } from \"../components/StoreImage\";\n\ntype SubmissionStatus =\n | \"DRAFT\"\n | \"PENDING_REVIEW\"\n | \"PUBLISHED\"\n | \"UNLISTED\"\n | \"REJECTED\"\n | \"UNKNOWN\";\n\ntype StoreSubmission = {\n productId: string;\n status: SubmissionStatus;\n submittedAt: string | null;\n reviewedAt: string | null;\n publishedAt: string | null;\n reviewNotes: string | null;\n rejectedReason: string | null;\n};\n\ntype ApplicationVersion = {\n id: string;\n version: string;\n status: string;\n releaseNotes: string | null;\n packageUrl: string | null;\n};\n\ntype Application = {\n id: string;\n name: string;\n slug: string;\n status: string;\n appType: string;\n reviewStatus: string;\n reviewNotes: string | null;\n iconUrl: string | null;\n submittedAt: string | null;\n metadata: Record<string, unknown> | null;\n versions: { edges: { node: ApplicationVersion }[] };\n};\n\nconst APP_QUERY = /* GraphQL */ `\n query DevportalAppForSubmission($id: ID!) {\n application(id: $id) {\n id\n name\n slug\n status\n appType\n reviewStatus\n reviewNotes\n iconUrl\n submittedAt\n metadata\n versions {\n edges {\n node {\n id\n version\n status\n releaseNotes\n packageUrl\n }\n }\n }\n }\n }\n`;\n\nconst SUBMIT_MUTATION = /* GraphQL */ `\n mutation DevportalSubmitForReview($id: ID!, $notes: String) {\n submitApplicationForReview(id: $id, notes: $notes) {\n id\n status\n submittedAt\n metadata\n }\n }\n`;\n\nconst UNLIST_MUTATION = /* GraphQL */ `\n mutation DevportalUnlistProduct($id: ID!) {\n unlistProduct(id: $id) {\n id\n status\n }\n }\n`;\n\nconst PUBLISH_VERSION_MUTATION = /* GraphQL */ `\n mutation DevportalPublishVersion($id: ID!) {\n publishApplicationVersion(id: $id) {\n id\n status\n }\n }\n`;\n\nfunction inferSubmission(app: Application | null): StoreSubmission | null {\n if (!app) return null;\n const metadata = (app.metadata ?? {}) as Record<string, unknown>;\n const productId =\n typeof metadata.storeProductId === \"string\" ? metadata.storeProductId : \"\";\n\n // Prefer metadata status (most accurate), but fall back to app.status so the\n // page reflects reality even when the metadata write failed after submission.\n const rawMetaStatus =\n typeof metadata.storeSubmissionStatus === \"string\"\n ? metadata.storeSubmissionStatus\n : null;\n\n let status: SubmissionStatus;\n if (\n rawMetaStatus === \"PENDING_REVIEW\" ||\n rawMetaStatus === \"PUBLISHED\" ||\n rawMetaStatus === \"REJECTED\" ||\n rawMetaStatus === \"DRAFT\"\n ) {\n status = rawMetaStatus;\n } else if (app.status === \"SUBMITTED\") {\n status = \"PENDING_REVIEW\";\n } else if (app.status === \"PUBLISHED\") {\n status = \"PUBLISHED\";\n } else if (app.status === \"REJECTED\") {\n status = \"REJECTED\";\n } else {\n status = \"UNKNOWN\";\n }\n\n const metaSubmittedAt =\n typeof metadata.storeSubmissionAt === \"string\"\n ? metadata.storeSubmissionAt\n : null;\n\n return {\n productId,\n status,\n submittedAt: metaSubmittedAt ?? app.submittedAt,\n reviewedAt: null,\n publishedAt: null,\n reviewNotes: null,\n rejectedReason: null,\n };\n}\n\ntype StatusMeta = {\n i18nKey: string;\n fallback: string;\n icon: typeof CheckCircle2;\n tone: string;\n};\n\nconst statusLabels: Record<SubmissionStatus, StatusMeta> = {\n DRAFT: {\n i18nKey: \"devportal.storeSubmission.status.draft\",\n fallback: \"Draft\",\n icon: Clock,\n tone: \"text-text-secondary\",\n },\n PENDING_REVIEW: {\n i18nKey: \"devportal.storeSubmission.status.pending\",\n fallback: \"Pending review\",\n icon: Clock,\n tone: \"text-status-warning-text\",\n },\n PUBLISHED: {\n i18nKey: \"devportal.storeSubmission.status.published\",\n fallback: \"Published\",\n icon: CheckCircle2,\n tone: \"text-status-success-text\",\n },\n UNLISTED: {\n i18nKey: \"devportal.storeSubmission.status.unlisted\",\n fallback: \"Unlisted\",\n icon: EyeOff,\n tone: \"text-text-secondary\",\n },\n REJECTED: {\n i18nKey: \"devportal.storeSubmission.status.rejected\",\n fallback: \"Rejected\",\n icon: XCircle,\n tone: \"text-status-danger-text\",\n },\n UNKNOWN: {\n i18nKey: \"devportal.storeSubmission.status.unknown\",\n fallback: \"Not yet submitted\",\n icon: AlertTriangle,\n tone: \"text-text-tertiary\",\n },\n};\n\nexport const StoreSubmissionPage: FC = () => {\n const { appId } = useParams<{ appId: string }>();\n const navigate = useNavigate();\n const bus = useDevportalEventBus();\n const tr = useTr();\n const submitPerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_SUBMIT);\n const [app, setApp] = useState<Application | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [submitting, setSubmitting] = useState(false);\n const [unlisting, setUnlisting] = useState(false);\n const [showUnlistConfirm, setShowUnlistConfirm] = useState(false);\n const [overrideStatus, setOverrideStatus] = useState<SubmissionStatus | null>(\n null,\n );\n const [notes, setNotes] = useState(\"\");\n const load = async () => {\n if (!appId) return;\n setLoading(true);\n setError(null);\n try {\n const result = await graphqlFetch<{ application: Application | null }>({\n gateway: \"global\",\n query: APP_QUERY,\n variables: { id: appId },\n });\n if (result.errors?.length) {\n throw new Error(\n result.errors[0]?.message ??\n tr(\n \"devportal.storeSubmission.errors.loadFailed\",\n \"Failed to load application\",\n ),\n );\n }\n setApp(result.data?.application ?? null);\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.storeSubmission.errors.loadFailed\",\n \"Failed to load application\",\n ),\n );\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n void load();\n }, [appId]); // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n const name = app?.name;\n if (!appId || !name) return;\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n reg?.register(appId, name);\n return () => reg?.unregister(appId);\n }, [appId, app?.name]);\n\n const submit = async () => {\n if (!appId) return;\n setSubmitting(true);\n setError(null);\n try {\n // Auto-publish all draft versions alongside the app submission\n const draftVersions = (app?.versions.edges ?? [])\n .map((e) => e.node)\n .filter((v) => v.status === \"draft\");\n for (const v of draftVersions) {\n const vResult = await graphqlFetch({\n gateway: \"global\",\n query: PUBLISH_VERSION_MUTATION,\n variables: { id: v.id },\n });\n if (vResult.errors?.length) {\n throw new Error(\n vResult.errors[0]?.message ??\n `Failed to submit version ${v.version}`,\n );\n }\n }\n\n const result = await graphqlFetch({\n gateway: \"global\",\n query: SUBMIT_MUTATION,\n variables: { id: appId, notes: notes || null },\n });\n if (result.errors?.length) {\n throw new Error(\n result.errors[0]?.message ??\n tr(\n \"devportal.storeSubmission.errors.submitFailed\",\n \"Submission failed\",\n ),\n );\n }\n bus.emit(\"devportal.app.submitted\", { appId });\n await load();\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.storeSubmission.errors.submitFailed\",\n \"Submission failed\",\n ),\n );\n } finally {\n setSubmitting(false);\n }\n };\n\n const unlist = async () => {\n const productId = inferSubmission(app)?.productId;\n if (!productId) return;\n setUnlisting(true);\n setError(null);\n try {\n const result = await graphqlFetch({\n gateway: \"global\",\n query: UNLIST_MUTATION,\n variables: { id: productId },\n });\n if (result.errors?.length) {\n throw new Error(\n result.errors[0]?.message ??\n tr(\n \"devportal.storeSubmission.errors.unlistFailed\",\n \"Failed to unlist\",\n ),\n );\n }\n setOverrideStatus(\"UNLISTED\");\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.storeSubmission.errors.unlistFailed\",\n \"Failed to unlist\",\n ),\n );\n } finally {\n setUnlisting(false);\n setShowUnlistConfirm(false);\n }\n };\n\n const submission = inferSubmission(app);\n const effectiveStatus = overrideStatus ?? submission?.status ?? \"UNKNOWN\";\n const statusMeta = statusLabels[effectiveStatus];\n const StatusIcon = statusMeta.icon;\n\n const allVersions = (app?.versions.edges ?? []).map((e) => e.node);\n const draftVersions = allVersions.filter((v) => v.status === \"draft\");\n const isPackageApp = app?.appType === \"NODE\" || app?.appType === \"WORKFLOW\";\n const noVersionsBlock = isPackageApp && allVersions.length === 0;\n\n return (\n <main\n className=\"min-h-screen bg-surface-default\"\n aria-labelledby=\"store-submission-heading\"\n >\n <div className=\"border-b border-border-default bg-surface-raised\">\n <div className=\"mx-auto max-w-3xl px-6 py-4\">\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => navigate(-1)}\n className=\"inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-sm text-text-secondary hover:bg-surface-hover hover:text-text-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <ArrowLeft className=\"h-4 w-4\" aria-hidden=\"true\" />\n {tr(\"devportal.common.back\", \"Back\")}\n </button>\n <div className=\"flex items-center gap-2\">\n <StoreIcon\n className=\"h-5 w-5 text-text-primary\"\n aria-hidden=\"true\"\n />\n <h1\n id=\"store-submission-heading\"\n className=\"text-xl font-semibold text-text-primary\"\n >\n {tr(\"devportal.storeSubmission.title\", \"Store submission\")}\n </h1>\n </div>\n </div>\n </div>\n </div>\n\n {/* Unlist confirm dialog */}\n {showUnlistConfirm && (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"unlist-dialog-title\"\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\"\n >\n <div className=\"w-full max-w-md rounded-lg border border-border-default bg-surface-raised p-6 shadow-xl\">\n <div className=\"mb-4 flex items-start gap-3\">\n <EyeOff\n className=\"mt-0.5 h-5 w-5 shrink-0 text-text-secondary\"\n aria-hidden=\"true\"\n />\n <div>\n <h2\n id=\"unlist-dialog-title\"\n className=\"text-base font-semibold text-text-primary\"\n >\n {tr(\n \"devportal.storeSubmission.unlistTitle\",\n \"Unlist from marketplace?\",\n )}\n </h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.unlistDescription\",\n \"Your app will no longer appear in the marketplace for new users. Existing installations are not affected — users who already have it installed can continue using it.\",\n )}\n </p>\n </div>\n </div>\n <div className=\"flex justify-end gap-3\">\n <button\n type=\"button\"\n onClick={() => setShowUnlistConfirm(false)}\n className=\"rounded-md border border-border-default px-4 py-2 text-sm font-medium text-text-secondary hover:bg-surface-hover\"\n >\n {tr(\"devportal.common.cancel\", \"Cancel\")}\n </button>\n <button\n type=\"button\"\n onClick={() => void unlist()}\n disabled={unlisting}\n className=\"inline-flex items-center gap-2 rounded-md bg-surface-danger px-4 py-2 text-sm font-semibold text-text-on-danger hover:opacity-90 disabled:opacity-60\"\n >\n {unlisting && (\n <RefreshCw\n className=\"h-4 w-4 animate-spin\"\n aria-hidden=\"true\"\n />\n )}\n {tr(\"devportal.storeSubmission.confirmUnlist\", \"Unlist app\")}\n </button>\n </div>\n </div>\n </div>\n )}\n\n <div className=\"mx-auto max-w-3xl px-6 py-6\">\n {(loading ||\n !submission ||\n effectiveStatus === \"UNKNOWN\" ||\n effectiveStatus === \"DRAFT\" ||\n effectiveStatus === \"REJECTED\") && (\n <PagePurpose className=\"mb-5\">\n {tr(\n \"devportal.storeSubmission.purpose\",\n \"Finalize the details the marketplace needs before your app can be reviewed — pricing, categories, and required assets. Completing this is what makes the app eligible to submit for publication.\",\n )}\n </PagePurpose>\n )}\n\n {error && (\n <div\n role=\"alert\"\n className=\"mb-4 rounded-md border border-border-danger bg-surface-danger-muted px-4 py-3 text-sm text-text-danger\"\n >\n {error}\n </div>\n )}\n\n {loading && !app ? (\n <div\n className=\"py-16 text-center text-text-secondary\"\n role=\"status\"\n aria-live=\"polite\"\n >\n {tr(\"devportal.storeSubmission.loading\", \"Loading application…\")}\n </div>\n ) : !app ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title={tr(\n \"devportal.storeSubmission.notFoundTitle\",\n \"Application not found\",\n )}\n description={tr(\n \"devportal.storeSubmission.notFound\",\n \"Application not found.\",\n )}\n />\n ) : (\n <div className=\"space-y-4\">\n {/* App header card */}\n <div className=\"rounded-lg border border-border-default bg-surface-raised p-4\">\n <div className=\"flex items-center gap-3\">\n <StoreImage\n src={app.iconUrl}\n alt=\"\"\n className=\"h-14 w-14 flex-shrink-0 rounded-md object-cover\"\n fallback={\n <div className=\"flex h-14 w-14 flex-shrink-0 items-center justify-center rounded-md bg-surface-muted text-text-secondary text-sm font-medium\">\n {app.name.slice(0, 2).toUpperCase()}\n </div>\n }\n />\n <div className=\"min-w-0 flex-1\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {app.name}\n </h2>\n <p className=\"font-mono text-xs text-text-tertiary\">\n {app.slug}\n </p>\n </div>\n <div\n className={`flex items-center gap-1.5 ${statusMeta.tone}`}\n role=\"status\"\n >\n <StatusIcon className=\"h-5 w-5\" aria-hidden=\"true\" />\n <span className=\"text-sm font-medium\">\n {tr(statusMeta.i18nKey, statusMeta.fallback)}\n </span>\n </div>\n </div>\n </div>\n\n {/* Pending review — what happens next */}\n {effectiveStatus === \"PENDING_REVIEW\" && (\n <div className=\"rounded-lg border border-primary/20 bg-action-primary-bg/5 p-5 space-y-4\">\n <div className=\"flex items-start gap-3\">\n <Clock\n className=\"h-5 w-5 mt-0.5 shrink-0 text-primary\"\n aria-hidden=\"true\"\n />\n <div>\n <p className=\"text-sm font-semibold text-text-primary\">\n {tr(\n \"devportal.storeSubmission.underReview\",\n \"Your app is under review\",\n )}\n </p>\n {app.submittedAt && (\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.submittedOn\",\n \"Submitted on\",\n )}{\" \"}\n {new Date(app.submittedAt).toLocaleString()}\n </p>\n )}\n </div>\n </div>\n\n <div className=\"border-t border-border-default pt-4\">\n <p className=\"text-xs font-medium text-text-secondary mb-3\">\n {tr(\n \"devportal.storeSubmission.whatNext\",\n \"What happens next\",\n )}\n </p>\n <ol className=\"space-y-2.5 text-sm text-text-secondary\">\n <li className=\"flex items-start gap-2\">\n <span className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-surface-muted text-xs font-medium text-text-tertiary\">\n 1\n </span>\n Our team reviews your app's listing, assets, and\n compliance.\n </li>\n <li className=\"flex items-start gap-2\">\n <span className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-surface-muted text-xs font-medium text-text-tertiary\">\n 2\n </span>\n You'll receive a notification when a decision is made.\n </li>\n <li className=\"flex items-start gap-2\">\n <span className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-surface-muted text-xs font-medium text-text-tertiary\">\n 3\n </span>\n If approved, your app goes live in the marketplace\n automatically.\n </li>\n </ol>\n </div>\n\n {app.reviewNotes && (\n <div className=\"border-t border-border-default pt-4\">\n <p className=\"text-xs font-medium text-text-secondary mb-1\">\n {tr(\n \"devportal.storeSubmission.reviewerNotes\",\n \"Reviewer notes\",\n )}\n </p>\n <p className=\"text-sm text-text-primary\">\n {app.reviewNotes}\n </p>\n </div>\n )}\n </div>\n )}\n\n {/* Published */}\n {effectiveStatus === \"PUBLISHED\" && (\n <div className=\"rounded-lg border border-status-success-bg bg-status-success-bg-subtle p-5 space-y-4\">\n <div className=\"flex items-start gap-3\">\n <CheckCircle2\n className=\"h-5 w-5 mt-0.5 shrink-0 text-status-success-text\"\n aria-hidden=\"true\"\n />\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-semibold text-status-success-text\">\n {tr(\n \"devportal.storeSubmission.publishedTitle\",\n \"Your app is live in the marketplace\",\n )}\n </p>\n {submission?.publishedAt && (\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.publishedOn\",\n \"Published on\",\n )}{\" \"}\n {new Date(submission.publishedAt).toLocaleString()}\n </p>\n )}\n </div>\n </div>\n {submission?.productId && (\n <div className=\"border-t border-status-success-bg pt-4\">\n <p className=\"mb-2 text-xs text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.unlistHint\",\n \"Need to remove this app from the marketplace? Unlisting hides it from new users while keeping existing installations active.\",\n )}\n </p>\n <button\n type=\"button\"\n onClick={() => setShowUnlistConfirm(true)}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-default bg-surface-raised px-3 py-1.5 text-sm font-medium text-text-secondary hover:bg-surface-hover hover:text-text-primary\"\n >\n <EyeOff className=\"h-4 w-4\" aria-hidden=\"true\" />\n {tr(\n \"devportal.storeSubmission.unlistButton\",\n \"Unlist from marketplace\",\n )}\n </button>\n </div>\n )}\n </div>\n )}\n\n {/* Unlisted */}\n {effectiveStatus === \"UNLISTED\" && (\n <div className=\"rounded-lg border border-border-default bg-surface-muted p-5 flex items-start gap-3\">\n <EyeOff\n className=\"h-5 w-5 mt-0.5 shrink-0 text-text-secondary\"\n aria-hidden=\"true\"\n />\n <div>\n <p className=\"text-sm font-semibold text-text-primary\">\n {tr(\n \"devportal.storeSubmission.unlistedTitle\",\n \"Your app has been unlisted\",\n )}\n </p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.unlistedDescription\",\n \"It no longer appears in the marketplace for new users. Existing installations remain active and unaffected.\",\n )}\n </p>\n </div>\n </div>\n )}\n\n {/* Rejected */}\n {effectiveStatus === \"REJECTED\" && (\n <div className=\"rounded-lg border border-status-error-bg bg-status-error-bg-subtle p-5 space-y-3\">\n <div className=\"flex items-start gap-3\">\n <XCircle\n className=\"h-5 w-5 mt-0.5 shrink-0 text-status-error-text\"\n aria-hidden=\"true\"\n />\n <div>\n <p className=\"text-sm font-semibold text-status-error-text\">\n {tr(\n \"devportal.storeSubmission.rejectedTitle\",\n \"Submission was not approved\",\n )}\n </p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.rejectedHint\",\n \"Address the feedback below and resubmit.\",\n )}\n </p>\n </div>\n </div>\n {app.reviewNotes && (\n <div className=\"rounded-md bg-surface-muted p-3\">\n <p className=\"text-xs font-medium text-text-secondary mb-1\">\n {tr(\n \"devportal.storeSubmission.reviewerFeedback\",\n \"Reviewer feedback\",\n )}\n </p>\n <p className=\"text-sm text-text-primary\">\n {app.reviewNotes}\n </p>\n </div>\n )}\n </div>\n )}\n\n {/* Submit / resubmit form */}\n {(effectiveStatus === \"UNKNOWN\" ||\n effectiveStatus === \"DRAFT\" ||\n effectiveStatus === \"REJECTED\") && (\n <div className=\"rounded-lg border border-border-default bg-surface-raised p-4 space-y-4\">\n <div>\n <h3 className=\"mb-1 text-sm font-semibold text-text-primary\">\n {effectiveStatus === \"REJECTED\"\n ? tr(\n \"devportal.storeSubmission.resubmitForReview\",\n \"Resubmit for review\",\n )\n : tr(\n \"devportal.storeSubmission.submitForReview\",\n \"Submit for review\",\n )}\n </h3>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.help\",\n \"Your application will be sent to the store's review queue. Whether it's auto-published or requires admin approval depends on the target store's configuration.\",\n )}\n </p>\n </div>\n\n {/* Versions included in this submission */}\n {isPackageApp && (\n <div className=\"rounded-md border border-border-default bg-surface-muted p-3 space-y-2\">\n <div className=\"flex items-center gap-2 text-xs font-medium text-text-secondary\">\n <GitBranch className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n {tr(\n \"devportal.storeSubmission.versionsIncluded\",\n \"Versions included in this submission\",\n )}\n </div>\n\n {noVersionsBlock ? (\n <div className=\"flex items-start gap-2 text-sm text-status-danger-text\">\n <AlertTriangle\n className=\"h-4 w-4 mt-0.5 shrink-0\"\n aria-hidden=\"true\"\n />\n <span>\n {tr(\n \"devportal.storeSubmission.noVersionsError\",\n \"You must create at least one version before submitting. Go to the Versions tab to create one.\",\n )}\n </span>\n </div>\n ) : draftVersions.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.noDraftVersions\",\n \"No draft versions — all versions are already submitted or published.\",\n )}\n </p>\n ) : (\n <ul className=\"space-y-1\">\n {draftVersions.map((v) => (\n <li\n key={v.id}\n className=\"flex items-center gap-2 text-sm\"\n >\n <Package\n className=\"h-3.5 w-3.5 text-text-secondary shrink-0\"\n aria-hidden=\"true\"\n />\n <span className=\"font-mono font-medium\">\n {v.version}\n </span>\n {v.releaseNotes && (\n <span className=\"text-xs text-text-secondary truncate\">\n — {v.releaseNotes}\n </span>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n\n <div>\n <label className=\"block\" htmlFor=\"store-submission-notes\">\n <span className=\"sr-only\">\n {tr(\n \"devportal.storeSubmission.notesLabel\",\n \"Notes for the reviewer (optional)\",\n )}\n </span>\n </label>\n <textarea\n id=\"store-submission-notes\"\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n rows={3}\n placeholder={tr(\n \"devportal.storeSubmission.notesLabel\",\n \"Notes for the reviewer (optional)\",\n )}\n className=\"mb-3 w-full rounded-md border border-border-default bg-surface-default px-3 py-2 text-sm text-text-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n />\n <button\n type=\"button\"\n onClick={() => void submit()}\n disabled={\n submitting || !submitPerm.allowed || noVersionsBlock\n }\n aria-disabled={\n submitting || !submitPerm.allowed || noVersionsBlock\n }\n title={\n noVersionsBlock\n ? tr(\n \"devportal.storeSubmission.noVersionsError\",\n \"Create a version first\",\n )\n : !submitPerm.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-action-primary-bg px-4 py-2 text-sm font-semibold text-action-primary-text hover:opacity-90 disabled:opacity-60 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n {submitting && (\n <RefreshCw\n className=\"h-4 w-4 animate-spin\"\n aria-hidden=\"true\"\n />\n )}\n {effectiveStatus === \"REJECTED\"\n ? tr(\"devportal.storeSubmission.resubmit\", \"Resubmit\")\n : tr(\n \"devportal.storeSubmission.submitForReview\",\n \"Submit for review\",\n )}\n </button>\n </div>\n </div>\n )}\n\n {submission?.productId && (\n <div className=\"rounded-lg border border-border-default bg-surface-raised p-4\">\n <p className=\"text-xs font-medium text-text-secondary\">\n {tr(\n \"devportal.storeSubmission.storeProductId\",\n \"Store product ID\",\n )}\n </p>\n <code className=\"mt-1 block break-all font-mono text-xs text-text-primary\">\n {submission.productId}\n </code>\n </div>\n )}\n </div>\n )}\n </div>\n </main>\n );\n};\n"],"mappings":"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"}
|
|
@@ -17,11 +17,11 @@ import { useEffect as v, useMemo as ae, useState as y } from "react";
|
|
|
17
17
|
import { AlertCircle as oe, CheckCircle as b, Clock as se, ExternalLink as ce, Loader2 as le, Pause as x, Play as S, Send as C, Trash2 as ue, Webhook as de, XCircle as fe } from "lucide-react";
|
|
18
18
|
import { useParams as w } from "react-router";
|
|
19
19
|
import { jsx as T, jsxs as E } from "react/jsx-runtime";
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
20
|
+
import { CTAOverflowMenu as D, EmphasisPanel as O, NextSteps as k } from "@burdenoff/fe-libs/ui";
|
|
21
|
+
import { useI18n as A } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
22
22
|
// src/devportal/pages/WebhookDetailPage.tsx
|
|
23
23
|
var j = (t) => t ? e(new Date(t), "MMM d, yyyy HH:mm:ss") : "Never", M = () => {
|
|
24
|
-
let { appId: M, webhookId: N } = w(), { navigate: P, basePath: F } = p(), { t: I } =
|
|
24
|
+
let { appId: M, webhookId: N } = w(), { navigate: P, basePath: F } = p(), { t: I } = A(), L = (e, t) => {
|
|
25
25
|
let n = I(e);
|
|
26
26
|
return n === e ? t : n;
|
|
27
27
|
}, { allowed: R } = _(g.WEBHOOK_UPDATE), { allowed: z } = _(g.WEBHOOK_DELETE), [B, V] = y(!1), [pe, H] = y(!1), [U, W] = y(null), [me, G] = y(!1), { data: K } = ee({
|
|
@@ -106,7 +106,7 @@ var j = (t) => t ? e(new Date(t), "MMM d, yyyy HH:mm:ss") : "Never", M = () => {
|
|
|
106
106
|
purpose: L("devportal.webhookDetailPurpose", "This endpoint receives the events you subscribed to, signed with your secret. Check the delivery history to confirm your server is responding with 2xx, send a test event, and pause it if your endpoint is down so deliveries are not lost to repeated failures."),
|
|
107
107
|
backLink: `/apps/${Q}/webhooks`,
|
|
108
108
|
backLabel: L("devportal.backToWebhooks", "Back to Webhooks"),
|
|
109
|
-
actions: /* @__PURE__ */ T(
|
|
109
|
+
actions: /* @__PURE__ */ T(D, {
|
|
110
110
|
primary: {
|
|
111
111
|
label: L("devportal.test", "Test"),
|
|
112
112
|
icon: /* @__PURE__ */ T(C, { size: 16 }),
|
|
@@ -128,7 +128,7 @@ var j = (t) => t ? e(new Date(t), "MMM d, yyyy HH:mm:ss") : "Never", M = () => {
|
|
|
128
128
|
}]
|
|
129
129
|
}),
|
|
130
130
|
children: [
|
|
131
|
-
/* @__PURE__ */ T(
|
|
131
|
+
/* @__PURE__ */ T(O, { children: /* @__PURE__ */ E(c, {
|
|
132
132
|
columns: 4,
|
|
133
133
|
children: [
|
|
134
134
|
/* @__PURE__ */ T(s, {
|
|
@@ -153,7 +153,7 @@ var j = (t) => t ? e(new Date(t), "MMM d, yyyy HH:mm:ss") : "Never", M = () => {
|
|
|
153
153
|
})
|
|
154
154
|
]
|
|
155
155
|
}) }),
|
|
156
|
-
/* @__PURE__ */ T(
|
|
156
|
+
/* @__PURE__ */ T(k, {
|
|
157
157
|
storageKey: `devportal-webhook-${X.id}`,
|
|
158
158
|
steps: [{
|
|
159
159
|
id: "test",
|
|
@@ -4,22 +4,22 @@ import { StatusBadge as n } from "../components/StatusBadge.js";
|
|
|
4
4
|
import { useGetApplicationQuery as r, useGetApplicationsQuery as i, useGetWebhooksQuery as a } from "../../generated/global-operations.js";
|
|
5
5
|
import { getErrorMessage as o } from "../hooks/useGraphQL.js";
|
|
6
6
|
import { EmptyState as s } from "../components/EmptyState.js";
|
|
7
|
-
import { AppListItem as
|
|
7
|
+
import { AppListItem as ee } from "../components/AppCard.js";
|
|
8
8
|
import "../components/index.js";
|
|
9
|
-
import { useDevportal as
|
|
10
|
-
import { PermissionGuard as
|
|
11
|
-
import { DEVPORTAL_PERMISSIONS as
|
|
12
|
-
import { useDevportalPermission as
|
|
9
|
+
import { useDevportal as c } from "../providers/DevportalProvider.js";
|
|
10
|
+
import { PermissionGuard as l } from "../components/PermissionGuard.js";
|
|
11
|
+
import { DEVPORTAL_PERMISSIONS as u } from "../constants/permissions.js";
|
|
12
|
+
import { useDevportalPermission as d } from "../hooks/usePermission.js";
|
|
13
13
|
import { cn as f } from "../utils/cn.js";
|
|
14
14
|
import "../hooks/index.js";
|
|
15
|
-
import { useEffect as
|
|
16
|
-
import { AlertCircle as
|
|
15
|
+
import { useEffect as p, useState as m } from "react";
|
|
16
|
+
import { AlertCircle as h, AlertTriangle as te, AppWindow as ne, CheckCircle as g, Loader2 as _, PauseCircle as v, Plus as y, Search as b, Webhook as x, XCircle as S } from "lucide-react";
|
|
17
17
|
import { useParams as C } from "react-router";
|
|
18
18
|
import { jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
19
|
-
import { useI18n as re } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
20
19
|
import { EmphasisPanel as E, GlassCard as D } from "@burdenoff/fe-libs/ui";
|
|
20
|
+
import { useI18n as O } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
21
21
|
// src/devportal/pages/WebhooksPage.tsx
|
|
22
|
-
function
|
|
22
|
+
function k(e) {
|
|
23
23
|
return {
|
|
24
24
|
id: e.id,
|
|
25
25
|
applicationId: e.applicationId,
|
|
@@ -43,31 +43,31 @@ function O(e) {
|
|
|
43
43
|
updatedAt: e.updatedAt
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
|
-
var
|
|
47
|
-
let { appId:
|
|
46
|
+
var A = () => {
|
|
47
|
+
let { appId: A } = C(), { navigate: re, basePath: ie, activeOrgId: M } = c(), { t: ae } = O(), N = (e, t) => {
|
|
48
48
|
let n = ae(e);
|
|
49
49
|
return n === e ? t : n;
|
|
50
|
-
}, P =
|
|
51
|
-
variables: { id:
|
|
52
|
-
skip: !
|
|
50
|
+
}, P = d(u.WEBHOOK_CREATE), [F, I] = m(""), [L, R] = m(""), { data: z } = r({
|
|
51
|
+
variables: { id: A ?? "" },
|
|
52
|
+
skip: !A,
|
|
53
53
|
fetchPolicy: "cache-first"
|
|
54
54
|
});
|
|
55
|
-
|
|
55
|
+
p(() => {
|
|
56
56
|
let e = z?.application?.name;
|
|
57
|
-
if (!
|
|
57
|
+
if (!A || !e) return;
|
|
58
58
|
let t = window.__breadcrumbRegistry;
|
|
59
|
-
return t?.register(
|
|
60
|
-
}, [
|
|
59
|
+
return t?.register(A, e), () => t?.unregister(A);
|
|
60
|
+
}, [A, z?.application?.name]);
|
|
61
61
|
let { data: B, loading: V, error: H, refetch: U } = i({
|
|
62
62
|
variables: { limit: 100 },
|
|
63
|
-
skip: !!
|
|
63
|
+
skip: !!A,
|
|
64
64
|
fetchPolicy: "cache-and-network"
|
|
65
65
|
}), { data: W, loading: G, error: K, refetch: q } = a({
|
|
66
|
-
variables: { applicationId:
|
|
67
|
-
skip: !
|
|
66
|
+
variables: { applicationId: A || "" },
|
|
67
|
+
skip: !A,
|
|
68
68
|
fetchPolicy: "cache-and-network"
|
|
69
|
-
}), J = W?.webhooks?.map(
|
|
70
|
-
|
|
69
|
+
}), J = W?.webhooks?.map(k) ?? [], Y = B?.applications?.edges?.map((e) => e.node) ?? [], X = M ? Y.filter((e) => e.developerOrganizationId === M) : Y, Z = (e) => {
|
|
70
|
+
re?.(`${ie}${e}`);
|
|
71
71
|
}, Q = J.filter((e) => {
|
|
72
72
|
let t = !F || e.name.toLowerCase().includes(F.toLowerCase()) || e.url.toLowerCase().includes(F.toLowerCase()), n = !L || e.status === L;
|
|
73
73
|
return t && n;
|
|
@@ -85,7 +85,7 @@ var k = () => {
|
|
|
85
85
|
size: 16,
|
|
86
86
|
className: "text-status-error-text"
|
|
87
87
|
});
|
|
88
|
-
case "DISABLED": return /* @__PURE__ */ w(
|
|
88
|
+
case "DISABLED": return /* @__PURE__ */ w(te, {
|
|
89
89
|
size: 16,
|
|
90
90
|
className: "text-text-tertiary"
|
|
91
91
|
});
|
|
@@ -95,13 +95,13 @@ var k = () => {
|
|
|
95
95
|
let t = e.successCount + e.failureCount;
|
|
96
96
|
return t === 0 ? 100 : Math.round(e.successCount / t * 100);
|
|
97
97
|
};
|
|
98
|
-
if (!
|
|
98
|
+
if (!A) {
|
|
99
99
|
let t = X.filter((e) => {
|
|
100
100
|
if (!F) return !0;
|
|
101
101
|
let t = F.toLowerCase();
|
|
102
102
|
return e.name.toLowerCase().includes(t) || (e.slug ?? "").toLowerCase().includes(t);
|
|
103
103
|
});
|
|
104
|
-
return /* @__PURE__ */ w(
|
|
104
|
+
return /* @__PURE__ */ w(l, {
|
|
105
105
|
authOnly: !0,
|
|
106
106
|
children: /* @__PURE__ */ w(e, {
|
|
107
107
|
title: N("devportal.webhooks", "Webhooks"),
|
|
@@ -136,7 +136,7 @@ var k = () => {
|
|
|
136
136
|
}) : H ? /* @__PURE__ */ T("div", {
|
|
137
137
|
className: "rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center",
|
|
138
138
|
children: [
|
|
139
|
-
/* @__PURE__ */ w(
|
|
139
|
+
/* @__PURE__ */ w(h, { className: "mx-auto h-8 w-8 text-status-error-text" }),
|
|
140
140
|
/* @__PURE__ */ w("h3", {
|
|
141
141
|
className: "mt-2 font-medium text-status-error-text",
|
|
142
142
|
children: "Failed to load applications"
|
|
@@ -153,7 +153,7 @@ var k = () => {
|
|
|
153
153
|
]
|
|
154
154
|
}) : t.length > 0 ? /* @__PURE__ */ w("div", {
|
|
155
155
|
className: "space-y-2",
|
|
156
|
-
children: t.map((e) => /* @__PURE__ */ w(
|
|
156
|
+
children: t.map((e) => /* @__PURE__ */ w(ee, {
|
|
157
157
|
app: e,
|
|
158
158
|
onClick: () => Z(`/apps/${e.id}/webhooks`)
|
|
159
159
|
}, e.id))
|
|
@@ -176,7 +176,7 @@ var k = () => {
|
|
|
176
176
|
if (G && !W) return /* @__PURE__ */ w(e, {
|
|
177
177
|
title: N("devportal.webhooks", "Webhooks"),
|
|
178
178
|
description: N("devportal.manageWebhooksApp", "Manage webhooks for this application"),
|
|
179
|
-
backLink: `/apps/${
|
|
179
|
+
backLink: `/apps/${A}`,
|
|
180
180
|
backLabel: N("devportal.backToApplication", "Back to Application"),
|
|
181
181
|
children: /* @__PURE__ */ T("div", {
|
|
182
182
|
className: "flex items-center justify-center py-12",
|
|
@@ -189,12 +189,12 @@ var k = () => {
|
|
|
189
189
|
if (K) return /* @__PURE__ */ w(e, {
|
|
190
190
|
title: N("devportal.webhooks", "Webhooks"),
|
|
191
191
|
description: N("devportal.manageWebhooksApp", "Manage webhooks for this application"),
|
|
192
|
-
backLink: `/apps/${
|
|
192
|
+
backLink: `/apps/${A}`,
|
|
193
193
|
backLabel: N("devportal.backToApplication", "Back to Application"),
|
|
194
194
|
children: /* @__PURE__ */ T("div", {
|
|
195
195
|
className: "rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center",
|
|
196
196
|
children: [
|
|
197
|
-
/* @__PURE__ */ w(
|
|
197
|
+
/* @__PURE__ */ w(h, { className: "mx-auto h-8 w-8 text-status-error-text" }),
|
|
198
198
|
/* @__PURE__ */ w("h3", {
|
|
199
199
|
className: "mt-2 font-medium text-status-error-text",
|
|
200
200
|
children: N("devportal.failedToLoadWebhooks", "Failed to load webhooks")
|
|
@@ -307,7 +307,7 @@ var k = () => {
|
|
|
307
307
|
header: "Last Triggered",
|
|
308
308
|
render: (e) => /* @__PURE__ */ w("span", {
|
|
309
309
|
className: "text-sm text-text-secondary",
|
|
310
|
-
children: e.lastTriggeredAt ?
|
|
310
|
+
children: e.lastTriggeredAt ? j(e.lastTriggeredAt) : "Never"
|
|
311
311
|
})
|
|
312
312
|
}
|
|
313
313
|
], $ = {
|
|
@@ -316,16 +316,16 @@ var k = () => {
|
|
|
316
316
|
failed: J.filter((e) => e.status === "FAILED").length,
|
|
317
317
|
paused: J.filter((e) => e.status === "PAUSED").length
|
|
318
318
|
};
|
|
319
|
-
return /* @__PURE__ */ w(
|
|
319
|
+
return /* @__PURE__ */ w(l, {
|
|
320
320
|
authOnly: !0,
|
|
321
321
|
children: /* @__PURE__ */ T(e, {
|
|
322
322
|
title: N("devportal.webhooks", "Webhooks"),
|
|
323
323
|
description: N("devportal.manageWebhooksApp", "Manage webhooks for this application"),
|
|
324
324
|
purpose: N("devportal.webhooksAppPurpose", "These webhooks deliver this application's events to your endpoints. Add a URL, choose which events to subscribe to, and send a test delivery to confirm your server receives and verifies the signed payload."),
|
|
325
|
-
backLink: `/apps/${
|
|
325
|
+
backLink: `/apps/${A}`,
|
|
326
326
|
backLabel: N("devportal.backToApplication", "Back to Application"),
|
|
327
327
|
actions: /* @__PURE__ */ T("button", {
|
|
328
|
-
onClick: () => Z(`/apps/${
|
|
328
|
+
onClick: () => Z(`/apps/${A}/webhooks/new`),
|
|
329
329
|
disabled: !P.allowed,
|
|
330
330
|
"aria-disabled": !P.allowed,
|
|
331
331
|
title: P.allowed ? void 0 : N("devportal.common.noPermission", "You do not have permission to perform this action"),
|
|
@@ -455,13 +455,13 @@ var k = () => {
|
|
|
455
455
|
data: Q,
|
|
456
456
|
columns: ce,
|
|
457
457
|
keyField: "id",
|
|
458
|
-
onRowClick: (e) => Z(`/apps/${
|
|
458
|
+
onRowClick: (e) => Z(`/apps/${A}/webhooks/${e.id}`)
|
|
459
459
|
}) : /* @__PURE__ */ w(s, {
|
|
460
460
|
illustration: "empty-notifications",
|
|
461
461
|
title: N("devportal.noWebhooksFound", "No webhooks found"),
|
|
462
462
|
description: F || L ? N("devportal.tryAdjustingFilters", "Try adjusting your filters") : N("devportal.createFirstWebhook", "Create your first webhook to receive real-time event notifications"),
|
|
463
463
|
action: !F && !L ? /* @__PURE__ */ T("button", {
|
|
464
|
-
onClick: () => Z(`/apps/${
|
|
464
|
+
onClick: () => Z(`/apps/${A}/webhooks/new`),
|
|
465
465
|
className: "inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
466
466
|
children: [/* @__PURE__ */ w(y, { size: 16 }), N("devportal.createWebhook", "Create Webhook")]
|
|
467
467
|
}) : void 0
|
|
@@ -470,10 +470,10 @@ var k = () => {
|
|
|
470
470
|
})
|
|
471
471
|
});
|
|
472
472
|
};
|
|
473
|
-
function
|
|
473
|
+
function j(e) {
|
|
474
474
|
let t = new Date(e), n = (/* @__PURE__ */ new Date()).getTime() - t.getTime(), r = Math.floor(n / 6e4), i = Math.floor(r / 60), a = Math.floor(i / 24);
|
|
475
475
|
return r < 1 ? "Just now" : r < 60 ? `${r}m ago` : i < 24 ? `${i}h ago` : a < 7 ? `${a}d ago` : t.toLocaleDateString();
|
|
476
476
|
}
|
|
477
|
-
export {
|
|
477
|
+
export { A as WebhooksPage };
|
|
478
478
|
|
|
479
479
|
//# sourceMappingURL=WebhooksPage.js.map
|