@storyshelf/app 0.6.2 → 0.8.0
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/README.md +42 -4
- package/dist/app-types.d.mts +2 -6
- package/dist/asset-manifest.mjs +14 -7
- package/dist/asset-manifest.mjs.map +1 -1
- package/dist/assets/{htmx.min.js → htmx.mjs} +9 -1
- package/dist/assets/htmx.mjs.map +1 -0
- package/dist/assets/mark.mjs +9 -0
- package/dist/assets/mark.mjs.map +1 -0
- package/dist/boot-tasks.mjs +79 -0
- package/dist/boot-tasks.mjs.map +1 -0
- package/dist/build-state-flags.mjs +17 -0
- package/dist/build-state-flags.mjs.map +1 -0
- package/dist/build-state-setup.mjs +74 -0
- package/dist/build-state-setup.mjs.map +1 -0
- package/dist/capture-alerts.mjs +45 -0
- package/dist/capture-alerts.mjs.map +1 -0
- package/dist/capture-process.mjs +58 -0
- package/dist/capture-process.mjs.map +1 -0
- package/dist/capture-setup.mjs +96 -119
- package/dist/capture-setup.mjs.map +1 -1
- package/dist/connections.mjs +33 -0
- package/dist/connections.mjs.map +1 -0
- package/dist/consumer-setup.mjs +57 -0
- package/dist/consumer-setup.mjs.map +1 -0
- package/dist/credential-keys.mjs +1 -2
- package/dist/credentials.mjs +1 -2
- package/dist/git-status.mjs +45 -0
- package/dist/git-status.mjs.map +1 -0
- package/dist/hidden-data.mjs +23 -0
- package/dist/hidden-data.mjs.map +1 -0
- package/dist/index.d.mts +3 -5
- package/dist/index.mjs +204 -127
- package/dist/index.mjs.map +1 -1
- package/dist/insights/budget.mjs +48 -0
- package/dist/insights/budget.mjs.map +1 -0
- package/dist/insights/deps.mjs +20 -0
- package/dist/insights/deps.mjs.map +1 -0
- package/dist/insights/errors.mjs +21 -0
- package/dist/insights/errors.mjs.map +1 -0
- package/dist/insights/health-panel.mjs +39 -0
- package/dist/insights/health-panel.mjs.map +1 -0
- package/dist/insights/job.mjs +102 -0
- package/dist/insights/job.mjs.map +1 -0
- package/dist/insights/load-health.mjs +58 -0
- package/dist/insights/load-health.mjs.map +1 -0
- package/dist/insights/load-triage.mjs +97 -0
- package/dist/insights/load-triage.mjs.map +1 -0
- package/dist/insights/panel.mjs +27 -0
- package/dist/insights/panel.mjs.map +1 -0
- package/dist/insights/request.mjs +112 -0
- package/dist/insights/request.mjs.map +1 -0
- package/dist/insights/stale.mjs +20 -0
- package/dist/insights/stale.mjs.map +1 -0
- package/dist/insights/usage-report.mjs +59 -0
- package/dist/insights/usage-report.mjs.map +1 -0
- package/dist/insights/view.mjs +47 -0
- package/dist/insights/view.mjs.map +1 -0
- package/dist/job-canceller.mjs +13 -0
- package/dist/job-canceller.mjs.map +1 -0
- package/dist/job-queue.mjs +50 -0
- package/dist/job-queue.mjs.map +1 -0
- package/dist/jobs-setup.mjs +131 -0
- package/dist/jobs-setup.mjs.map +1 -0
- package/dist/lifecycle.mjs +93 -22
- package/dist/lifecycle.mjs.map +1 -1
- package/dist/middleware/auth-gate.mjs +5 -4
- package/dist/middleware/auth-gate.mjs.map +1 -1
- package/dist/middleware/csrf.mjs +1 -2
- package/dist/middleware/rate-limit.mjs +42 -35
- package/dist/middleware/rate-limit.mjs.map +1 -1
- package/dist/middleware/request-log.mjs +4 -4
- package/dist/middleware/request-log.mjs.map +1 -1
- package/dist/middleware/require-review.mjs +50 -0
- package/dist/middleware/require-review.mjs.map +1 -0
- package/dist/middleware/require-testing.mjs +40 -0
- package/dist/middleware/require-testing.mjs.map +1 -0
- package/dist/middleware/server-timing.mjs +1 -2
- package/dist/middleware/setup-gate.mjs +1 -2
- package/dist/middleware/setup-gate.mjs.map +1 -1
- package/dist/middleware/store-scope.mjs +13 -4
- package/dist/middleware/store-scope.mjs.map +1 -1
- package/dist/notifications-pause.mjs +32 -0
- package/dist/notifications-pause.mjs.map +1 -0
- package/dist/notify.d.mts +3 -4
- package/dist/notify.mjs +79 -41
- package/dist/notify.mjs.map +1 -1
- package/dist/pages/a11y-violations.mjs +115 -0
- package/dist/pages/a11y-violations.mjs.map +1 -0
- package/dist/pages/admin-ai.mjs +77 -0
- package/dist/pages/admin-ai.mjs.map +1 -0
- package/dist/pages/admin-system-origin.mjs +132 -0
- package/dist/pages/admin-system-origin.mjs.map +1 -0
- package/dist/pages/admin-system-targets.mjs +52 -0
- package/dist/pages/admin-system-targets.mjs.map +1 -0
- package/dist/pages/admin-system.mjs +64 -15
- package/dist/pages/admin-system.mjs.map +1 -1
- package/dist/pages/build-detail.mjs +105 -78
- package/dist/pages/build-detail.mjs.map +1 -1
- package/dist/pages/build-diff-actions.mjs +88 -35
- package/dist/pages/build-diff-actions.mjs.map +1 -1
- package/dist/pages/build-diff-comments.mjs +17 -16
- package/dist/pages/build-diff-comments.mjs.map +1 -1
- package/dist/pages/build-diff-default.mjs +53 -0
- package/dist/pages/build-diff-default.mjs.map +1 -0
- package/dist/pages/build-diff-environment.mjs +81 -0
- package/dist/pages/build-diff-environment.mjs.map +1 -0
- package/dist/pages/build-diff-header.mjs +23 -6
- package/dist/pages/build-diff-header.mjs.map +1 -1
- package/dist/pages/build-diff-insight.mjs +112 -0
- package/dist/pages/build-diff-insight.mjs.map +1 -0
- package/dist/pages/build-diff-model.mjs +74 -12
- package/dist/pages/build-diff-model.mjs.map +1 -1
- package/dist/pages/build-diff-nav.mjs +29 -14
- package/dist/pages/build-diff-nav.mjs.map +1 -1
- package/dist/pages/build-diff-reference.mjs +84 -0
- package/dist/pages/build-diff-reference.mjs.map +1 -0
- package/dist/pages/build-diff-shortcuts.mjs +6 -3
- package/dist/pages/build-diff-shortcuts.mjs.map +1 -1
- package/dist/pages/build-diff-stale.mjs +1 -2
- package/dist/pages/build-diff-usage.mjs +62 -0
- package/dist/pages/build-diff-usage.mjs.map +1 -0
- package/dist/pages/build-diff-viewer.mjs +97 -14
- package/dist/pages/build-diff-viewer.mjs.map +1 -1
- package/dist/pages/build-diff.mjs +37 -22
- package/dist/pages/build-diff.mjs.map +1 -1
- package/dist/pages/build-tests.mjs +73 -0
- package/dist/pages/build-tests.mjs.map +1 -0
- package/dist/pages/component-detail.mjs +248 -0
- package/dist/pages/component-detail.mjs.map +1 -0
- package/dist/pages/component-stories.mjs +167 -0
- package/dist/pages/component-stories.mjs.map +1 -0
- package/dist/pages/compute-jobs.mjs +14 -28
- package/dist/pages/compute-jobs.mjs.map +1 -1
- package/dist/pages/design-links.mjs +181 -0
- package/dist/pages/design-links.mjs.map +1 -0
- package/dist/pages/environment-change.mjs +52 -0
- package/dist/pages/environment-change.mjs.map +1 -0
- package/dist/pages/health-panel.mjs +125 -0
- package/dist/pages/health-panel.mjs.map +1 -0
- package/dist/pages/invite.mjs +1 -2
- package/dist/pages/label-detail.mjs +1 -2
- package/dist/pages/library-grid.mjs +104 -0
- package/dist/pages/library-grid.mjs.map +1 -0
- package/dist/pages/library-model.mjs +46 -0
- package/dist/pages/library-model.mjs.map +1 -0
- package/dist/pages/library-snapshots.mjs +129 -0
- package/dist/pages/library-snapshots.mjs.map +1 -0
- package/dist/pages/library.mjs +113 -220
- package/dist/pages/library.mjs.map +1 -1
- package/dist/pages/login.mjs +1 -2
- package/dist/pages/notifications-paused.mjs +21 -0
- package/dist/pages/notifications-paused.mjs.map +1 -0
- package/dist/pages/passkey-ceremony.mjs +1 -2
- package/dist/pages/profile.mjs +54 -50
- package/dist/pages/profile.mjs.map +1 -1
- package/dist/pages/project-builds-table.mjs +3 -4
- package/dist/pages/project-builds-table.mjs.map +1 -1
- package/dist/pages/project-builds.mjs +52 -23
- package/dist/pages/project-builds.mjs.map +1 -1
- package/dist/pages/project-create.mjs +1 -2
- package/dist/pages/project-settings.mjs +52 -14
- package/dist/pages/project-settings.mjs.map +1 -1
- package/dist/pages/projects-card.mjs +15 -3
- package/dist/pages/projects-card.mjs.map +1 -1
- package/dist/pages/projects.mjs +7 -4
- package/dist/pages/projects.mjs.map +1 -1
- package/dist/pages/review-changeset.mjs +115 -0
- package/dist/pages/review-changeset.mjs.map +1 -0
- package/dist/pages/review-comments.mjs +102 -0
- package/dist/pages/review-comments.mjs.map +1 -0
- package/dist/pages/review-verdict.mjs +101 -0
- package/dist/pages/review-verdict.mjs.map +1 -0
- package/dist/pages/root.mjs +1 -2
- package/dist/pages/settings-ai.mjs +68 -0
- package/dist/pages/settings-ai.mjs.map +1 -0
- package/dist/pages/settings-capture.mjs +123 -0
- package/dist/pages/settings-capture.mjs.map +1 -0
- package/dist/pages/settings-design-credential.mjs +98 -0
- package/dist/pages/settings-design-credential.mjs.map +1 -0
- package/dist/pages/settings-design-links.mjs +178 -0
- package/dist/pages/settings-design-links.mjs.map +1 -0
- package/dist/pages/settings-design.mjs +47 -0
- package/dist/pages/settings-design.mjs.map +1 -0
- package/dist/pages/settings-general.mjs +47 -23
- package/dist/pages/settings-general.mjs.map +1 -1
- package/dist/pages/settings-labels.mjs +44 -4
- package/dist/pages/settings-labels.mjs.map +1 -1
- package/dist/pages/settings-links.mjs +111 -0
- package/dist/pages/settings-links.mjs.map +1 -0
- package/dist/pages/settings-members.mjs +1 -2
- package/dist/pages/settings-notifications-git.mjs +127 -0
- package/dist/pages/settings-notifications-git.mjs.map +1 -0
- package/dist/pages/settings-notifications.mjs +80 -44
- package/dist/pages/settings-notifications.mjs.map +1 -1
- package/dist/pages/settings-tests.mjs +34 -4
- package/dist/pages/settings-tests.mjs.map +1 -1
- package/dist/pages/settings-tokens.mjs +1 -2
- package/dist/pages/settings-webhooks.mjs +1 -2
- package/dist/pages/storybook.mjs +1 -2
- package/dist/pages/target-choices.mjs +38 -0
- package/dist/pages/target-choices.mjs.map +1 -0
- package/dist/publish-setup.mjs +88 -0
- package/dist/publish-setup.mjs.map +1 -0
- package/dist/retention-timer.mjs +12 -12
- package/dist/retention-timer.mjs.map +1 -1
- package/dist/review-events.mjs +47 -0
- package/dist/review-events.mjs.map +1 -0
- package/dist/routers/admin-pages.mjs +46 -5
- package/dist/routers/admin-pages.mjs.map +1 -1
- package/dist/routers/admin-public-origin.mjs +92 -0
- package/dist/routers/admin-public-origin.mjs.map +1 -0
- package/dist/routers/admin.mjs +8 -4
- package/dist/routers/admin.mjs.map +1 -1
- package/dist/routers/assets.mjs +10 -4
- package/dist/routers/assets.mjs.map +1 -1
- package/dist/routers/attempts.mjs +1 -2
- package/dist/routers/auth-sync.mjs +1 -2
- package/dist/routers/auth.mjs +2 -3
- package/dist/routers/baseline-guard.mjs +4 -5
- package/dist/routers/baseline-guard.mjs.map +1 -1
- package/dist/routers/baseline-reference.mjs +72 -0
- package/dist/routers/baseline-reference.mjs.map +1 -0
- package/dist/routers/baselines.handlers.mjs +63 -0
- package/dist/routers/baselines.handlers.mjs.map +1 -0
- package/dist/routers/baselines.mjs +124 -0
- package/dist/routers/baselines.mjs.map +1 -0
- package/dist/routers/build-cancel.mjs +67 -0
- package/dist/routers/build-cancel.mjs.map +1 -0
- package/dist/routers/build-changeset.mjs +69 -0
- package/dist/routers/build-changeset.mjs.map +1 -0
- package/dist/routers/build-reviews.handlers.mjs +85 -0
- package/dist/routers/build-reviews.handlers.mjs.map +1 -0
- package/dist/routers/build-reviews.mjs +73 -0
- package/dist/routers/build-reviews.mjs.map +1 -0
- package/dist/routers/builds.handlers.mjs +65 -60
- package/dist/routers/builds.handlers.mjs.map +1 -1
- package/dist/routers/builds.mjs +77 -19
- package/dist/routers/builds.mjs.map +1 -1
- package/dist/routers/capture-cache.mjs +29 -0
- package/dist/routers/capture-cache.mjs.map +1 -0
- package/dist/routers/capture-config.mjs +34 -0
- package/dist/routers/capture-config.mjs.map +1 -0
- package/dist/routers/comments.mjs +42 -17
- package/dist/routers/comments.mjs.map +1 -1
- package/dist/routers/comparison-image.mjs +29 -0
- package/dist/routers/comparison-image.mjs.map +1 -0
- package/dist/routers/component-catalog.handlers.mjs +70 -0
- package/dist/routers/component-catalog.handlers.mjs.map +1 -0
- package/dist/routers/component.handlers.mjs +120 -0
- package/dist/routers/component.handlers.mjs.map +1 -0
- package/dist/routers/connections.mjs +117 -0
- package/dist/routers/connections.mjs.map +1 -0
- package/dist/routers/design-connect.handlers.mjs +43 -0
- package/dist/routers/design-connect.handlers.mjs.map +1 -0
- package/dist/routers/design.handlers.mjs +113 -0
- package/dist/routers/design.handlers.mjs.map +1 -0
- package/dist/routers/flash.mjs +1 -2
- package/dist/routers/health-report.mjs +3 -5
- package/dist/routers/health-report.mjs.map +1 -1
- package/dist/routers/health.mjs +5 -5
- package/dist/routers/health.mjs.map +1 -1
- package/dist/routers/helpers.mjs +20 -5
- package/dist/routers/helpers.mjs.map +1 -1
- package/dist/routers/htmx.mjs +1 -2
- package/dist/routers/insights-ui.mjs +63 -0
- package/dist/routers/insights-ui.mjs.map +1 -0
- package/dist/routers/insights.handlers.mjs +44 -0
- package/dist/routers/insights.handlers.mjs.map +1 -0
- package/dist/routers/insights.mjs +188 -0
- package/dist/routers/insights.mjs.map +1 -0
- package/dist/routers/labels.mjs +1 -2
- package/dist/routers/links.handlers.mjs +79 -0
- package/dist/routers/links.handlers.mjs.map +1 -0
- package/dist/routers/links.mjs +138 -0
- package/dist/routers/links.mjs.map +1 -0
- package/dist/routers/media.mjs +30 -7
- package/dist/routers/media.mjs.map +1 -1
- package/dist/routers/members.mjs +3 -3
- package/dist/routers/members.mjs.map +1 -1
- package/dist/routers/notification-channels.mjs +18 -25
- package/dist/routers/notification-channels.mjs.map +1 -1
- package/dist/routers/notification-subscriptions.mjs +1 -2
- package/dist/routers/oauth-state.mjs +44 -0
- package/dist/routers/oauth-state.mjs.map +1 -0
- package/dist/routers/preview-base.mjs +37 -0
- package/dist/routers/preview-base.mjs.map +1 -0
- package/dist/routers/preview-token.mjs +50 -0
- package/dist/routers/preview-token.mjs.map +1 -0
- package/dist/routers/profile.mjs +4 -3
- package/dist/routers/profile.mjs.map +1 -1
- package/dist/routers/projects.mjs +18 -3
- package/dist/routers/projects.mjs.map +1 -1
- package/dist/routers/publish-upload.mjs +85 -0
- package/dist/routers/publish-upload.mjs.map +1 -0
- package/dist/routers/published-access.mjs +51 -0
- package/dist/routers/published-access.mjs.map +1 -0
- package/dist/routers/published-compression.mjs +109 -0
- package/dist/routers/published-compression.mjs.map +1 -0
- package/dist/routers/published-files.mjs +69 -0
- package/dist/routers/published-files.mjs.map +1 -0
- package/dist/routers/review-forms.mjs +71 -0
- package/dist/routers/review-forms.mjs.map +1 -0
- package/dist/routers/review-next.mjs +1 -2
- package/dist/routers/review-section.handlers.mjs +84 -0
- package/dist/routers/review-section.handlers.mjs.map +1 -0
- package/dist/routers/review-switch-off.mjs +28 -0
- package/dist/routers/review-switch-off.mjs.map +1 -0
- package/dist/routers/schemas.mjs +141 -24
- package/dist/routers/schemas.mjs.map +1 -1
- package/dist/routers/scoped-models.mjs +21 -0
- package/dist/routers/scoped-models.mjs.map +1 -0
- package/dist/routers/settings-ai.mjs +34 -0
- package/dist/routers/settings-ai.mjs.map +1 -0
- package/dist/routers/settings-capture.mjs +76 -0
- package/dist/routers/settings-capture.mjs.map +1 -0
- package/dist/routers/settings-design.mjs +102 -0
- package/dist/routers/settings-design.mjs.map +1 -0
- package/dist/routers/settings-general.mjs +56 -12
- package/dist/routers/settings-general.mjs.map +1 -1
- package/dist/routers/settings-git-channel.mjs +76 -0
- package/dist/routers/settings-git-channel.mjs.map +1 -0
- package/dist/routers/settings-labels.mjs +28 -3
- package/dist/routers/settings-labels.mjs.map +1 -1
- package/dist/routers/settings-links.mjs +62 -0
- package/dist/routers/settings-links.mjs.map +1 -0
- package/dist/routers/settings-members.mjs +5 -9
- package/dist/routers/settings-members.mjs.map +1 -1
- package/dist/routers/settings-notifications.mjs +16 -12
- package/dist/routers/settings-notifications.mjs.map +1 -1
- package/dist/routers/settings-tokens.mjs +3 -7
- package/dist/routers/settings-tokens.mjs.map +1 -1
- package/dist/routers/settings-webhooks.mjs +8 -26
- package/dist/routers/settings-webhooks.mjs.map +1 -1
- package/dist/routers/settings.handlers.mjs +108 -28
- package/dist/routers/settings.handlers.mjs.map +1 -1
- package/dist/routers/settings.mjs +17 -6
- package/dist/routers/settings.mjs.map +1 -1
- package/dist/routers/signed-storybook.mjs +55 -0
- package/dist/routers/signed-storybook.mjs.map +1 -0
- package/dist/routers/snapshot-groups.mjs +62 -0
- package/dist/routers/snapshot-groups.mjs.map +1 -0
- package/dist/routers/snapshots.mjs +104 -7
- package/dist/routers/snapshots.mjs.map +1 -1
- package/dist/routers/storybook.mjs +57 -104
- package/dist/routers/storybook.mjs.map +1 -1
- package/dist/routers/tokens.mjs +3 -7
- package/dist/routers/tokens.mjs.map +1 -1
- package/dist/routers/ui.mjs +38 -7
- package/dist/routers/ui.mjs.map +1 -1
- package/dist/routers/webhooks.mjs +6 -13
- package/dist/routers/webhooks.mjs.map +1 -1
- package/dist/routers/well-known.mjs +12 -6
- package/dist/routers/well-known.mjs.map +1 -1
- package/dist/routes/api-routes.mjs +92 -0
- package/dist/routes/api-routes.mjs.map +1 -0
- package/dist/routes/classification.mjs +37 -0
- package/dist/routes/classification.mjs.map +1 -0
- package/dist/routes/openapi-classes.mjs +21 -0
- package/dist/routes/openapi-classes.mjs.map +1 -0
- package/dist/routes/page-routes.mjs +103 -0
- package/dist/routes/page-routes.mjs.map +1 -0
- package/dist/runtime.mjs +19 -15
- package/dist/runtime.mjs.map +1 -1
- package/dist/serverless.mjs +4 -0
- package/dist/store.mjs +20 -3
- package/dist/store.mjs.map +1 -1
- package/dist/targets.mjs +45 -0
- package/dist/targets.mjs.map +1 -0
- package/dist/ui/avatar.mjs +1 -2
- package/dist/ui/buttons.mjs +17 -5
- package/dist/ui/buttons.mjs.map +1 -1
- package/dist/ui/code-block.mjs +1 -2
- package/dist/ui/compare-stage.mjs +86 -54
- package/dist/ui/compare-stage.mjs.map +1 -1
- package/dist/ui/csrf-field.mjs +1 -2
- package/dist/ui/css.mjs +1 -2
- package/dist/ui/design-reference.mjs +96 -0
- package/dist/ui/design-reference.mjs.map +1 -0
- package/dist/ui/document.mjs +2 -4
- package/dist/ui/document.mjs.map +1 -1
- package/dist/ui/dropdown.mjs +1 -2
- package/dist/ui/feedback.mjs +1 -2
- package/dist/ui/filter-input.mjs +1 -2
- package/dist/ui/forms.mjs +7 -7
- package/dist/ui/forms.mjs.map +1 -1
- package/dist/ui/icons/icon.mjs +1 -2
- package/dist/ui/icons/paths.mjs +2 -2
- package/dist/ui/icons/paths.mjs.map +1 -1
- package/dist/ui/icons/sprite.mjs +1 -2
- package/dist/ui/kbd.mjs +1 -2
- package/dist/ui/layout.mjs +1 -2
- package/dist/ui/preview-embed.mjs +81 -0
- package/dist/ui/preview-embed.mjs.map +1 -0
- package/dist/ui/progress.mjs +1 -2
- package/dist/ui/segmented.mjs +1 -2
- package/dist/ui/shell/account.mjs +1 -2
- package/dist/ui/shell/bare.mjs +1 -2
- package/dist/ui/shell/boot-script.mjs +1 -2
- package/dist/ui/shell/client-script.mjs +86 -2
- package/dist/ui/shell/client-script.mjs.map +1 -1
- package/dist/ui/shell/nav.mjs +13 -10
- package/dist/ui/shell/nav.mjs.map +1 -1
- package/dist/ui/shell/review-script.mjs +25 -3
- package/dist/ui/shell/review-script.mjs.map +1 -1
- package/dist/ui/shell/sidebar.mjs +3 -4
- package/dist/ui/shell/sidebar.mjs.map +1 -1
- package/dist/ui/shell/topbar.mjs +1 -2
- package/dist/ui/stacks.mjs +1 -2
- package/dist/ui/styles/base.mjs +1 -2
- package/dist/ui/styles/behavior.mjs +1 -2
- package/dist/ui/styles/review-layout.mjs +1 -2
- package/dist/ui/styles/review.mjs +1 -2
- package/dist/ui/styles/tokens.mjs +1 -2
- package/dist/ui/styles.mjs +1 -2
- package/dist/ui/subnav.mjs +1 -2
- package/dist/ui/table.mjs +1 -2
- package/dist/ui/theme.mjs +1 -2
- package/dist/ui/thumbnail.mjs +1 -2
- package/dist/ui/time.mjs +1 -2
- package/package.json +14 -12
- package/dist/asset-paths.mjs +0 -23
- package/dist/asset-paths.mjs.map +0 -1
- package/dist/assets/mark.svg +0 -1
- package/dist/pages/settings-status.mjs +0 -137
- package/dist/pages/settings-status.mjs.map +0 -1
- package/dist/routers/settings-status.mjs +0 -77
- package/dist/routers/settings-status.mjs.map +0 -1
- package/dist/routers/status-configs.mjs +0 -108
- package/dist/routers/status-configs.mjs.map +0 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { Badge, Meta } from "../ui/feedback.mjs";
|
|
5
|
+
import { Card, SectionTitle } from "../ui/layout.mjs";
|
|
6
|
+
import { Table } from "../ui/table.mjs";
|
|
7
|
+
import { targetLabel } from "../targets.mjs";
|
|
8
|
+
import { jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
9
|
+
import { unavailableReason } from "@storyshelf/core/adapter/capture-runner";
|
|
10
|
+
// src/pages/admin-system-targets.tsx
|
|
11
|
+
/** The browsers the capture runner offers and whether each can render now (ADR 0007, decision 7). */
|
|
12
|
+
function CaptureTargetsCard(props) {
|
|
13
|
+
const { targets } = props;
|
|
14
|
+
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
15
|
+
/* @__PURE__ */ jsx(SectionTitle, { children: "Capture browsers" }),
|
|
16
|
+
/* @__PURE__ */ jsx(Meta, { children: "What the capture runner offers, default first. A project can only pick a target that is ready; a declared engine that is not installed is listed with the reason." }),
|
|
17
|
+
/* @__PURE__ */ jsx(Table, { children: /* @__PURE__ */ jsxs("table", { children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
18
|
+
/* @__PURE__ */ jsx("th", { children: "Target" }),
|
|
19
|
+
/* @__PURE__ */ jsx("th", { children: "Reaches Storybook" }),
|
|
20
|
+
/* @__PURE__ */ jsx("th", { children: "Status" })
|
|
21
|
+
] }) }), /* @__PURE__ */ jsx("tbody", { children: targets.map((entry, index) => {
|
|
22
|
+
const reason = unavailableReason(entry.status);
|
|
23
|
+
return /* @__PURE__ */ jsxs("tr", { children: [
|
|
24
|
+
/* @__PURE__ */ jsxs("td", { children: [
|
|
25
|
+
/* @__PURE__ */ jsx("strong", { children: targetLabel(entry.target) }),
|
|
26
|
+
" ",
|
|
27
|
+
/* @__PURE__ */ jsx(Meta, {
|
|
28
|
+
as: "span",
|
|
29
|
+
mono: true,
|
|
30
|
+
children: entry.target
|
|
31
|
+
}),
|
|
32
|
+
index === 0 ? /* @__PURE__ */ jsx(Badge, { children: "default" }) : null
|
|
33
|
+
] }),
|
|
34
|
+
/* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(Meta, {
|
|
35
|
+
as: "span",
|
|
36
|
+
children: entry.reach === "url" ? "signed URL" : "local server"
|
|
37
|
+
}) }),
|
|
38
|
+
/* @__PURE__ */ jsxs("td", { children: [/* @__PURE__ */ jsx(Badge, {
|
|
39
|
+
tone: reason === null ? "success" : "danger",
|
|
40
|
+
icon: true,
|
|
41
|
+
children: reason === null ? "ready" : "unavailable"
|
|
42
|
+
}), reason === null ? null : /* @__PURE__ */ jsx(Meta, {
|
|
43
|
+
as: "div",
|
|
44
|
+
children: reason
|
|
45
|
+
})] })
|
|
46
|
+
] }, entry.target);
|
|
47
|
+
}) })] }) })
|
|
48
|
+
] });
|
|
49
|
+
}
|
|
50
|
+
export { CaptureTargetsCard };
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=admin-system-targets.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-system-targets.mjs","names":[],"sources":["../../src/pages/admin-system-targets.tsx"],"sourcesContent":["import { unavailableReason, type RunnerTarget } from \"@storyshelf/core/adapter/capture-runner\";\nimport type { HtmlEscapedString } from \"hono/utils/html\";\nimport { targetLabel } from \"../targets.ts\";\nimport { Badge, Card, Meta, SectionTitle, Table } from \"../ui/components.tsx\";\n\n/* eslint-disable promise-function-async -- Hono JSX components return HtmlEscapedString | Promise<HtmlEscapedString> */\n\n/** The browsers the capture runner offers and whether each can render now (ADR 0007, decision 7). */\nexport function CaptureTargetsCard(props: {\n targets: readonly RunnerTarget[];\n}): HtmlEscapedString | Promise<HtmlEscapedString> {\n const { targets } = props;\n return (\n <Card>\n <SectionTitle>Capture browsers</SectionTitle>\n <Meta>\n What the capture runner offers, default first. A project can only pick a target that is\n ready; a declared engine that is not installed is listed with the reason.\n </Meta>\n <Table>\n <table>\n <thead>\n <tr>\n <th>Target</th>\n <th>Reaches Storybook</th>\n <th>Status</th>\n </tr>\n </thead>\n <tbody>\n {targets.map((entry, index) => {\n const reason = unavailableReason(entry.status);\n return (\n <tr key={entry.target}>\n <td>\n <strong>{targetLabel(entry.target)}</strong>{\" \"}\n <Meta as=\"span\" mono>\n {entry.target}\n </Meta>\n {index === 0 ? <Badge>default</Badge> : null}\n </td>\n <td>\n <Meta as=\"span\">{entry.reach === \"url\" ? \"signed URL\" : \"local server\"}</Meta>\n </td>\n <td>\n <Badge tone={reason === null ? \"success\" : \"danger\"} icon>\n {reason === null ? \"ready\" : \"unavailable\"}\n </Badge>\n {reason === null ? null : <Meta as=\"div\">{reason}</Meta>}\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </Table>\n </Card>\n );\n}\n"],"mappings":";;;;;;;;;;;AAQA,SAAgB,mBAAmB,OAEgB;CACjD,MAAM,EAAE,YAAY;CACpB,OACE,qBAAC,MAAD,EAAA,UAAA;EACE,oBAAC,cAAD,EAAA,UAAc,mBAA8B,CAAA;EAC5C,oBAAC,MAAD,EAAA,UAAM,oKAGA,CAAA;EACN,oBAAC,OAAD,EAAA,UACE,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,SAAD,EAAA,UACE,qBAAC,MAAD,EAAA,UAAA;GACE,oBAAC,MAAD,EAAA,UAAI,SAAU,CAAA;GACd,oBAAC,MAAD,EAAA,UAAI,oBAAqB,CAAA;GACzB,oBAAC,MAAD,EAAA,UAAI,SAAU,CAAA;EACZ,EAAA,CAAA,EACC,CAAA,GACP,oBAAC,SAAD,EAAA,UACG,QAAQ,KAAK,OAAO,UAAU;GAC7B,MAAM,SAAS,kBAAkB,MAAM,MAAM;GAC7C,OACE,qBAAC,MAAD,EAAA,UAAA;IACE,qBAAC,MAAD,EAAA,UAAA;KACE,oBAAC,UAAD,EAAA,UAAS,YAAY,MAAM,MAAM,EAAU,CAAA;KAAE;KAC7C,oBAAC,MAAD;MAAM,IAAG;MAAO,MAAA;MACb,UAAA,MAAM;KACH,CAAA;KACL,UAAU,IAAI,oBAAC,OAAD,EAAA,UAAO,UAAc,CAAA,IAAI;IACtC,EAAA,CAAA;IACJ,oBAAC,MAAD,EAAA,UACE,oBAAC,MAAD;KAAM,IAAG;KAAQ,UAAA,MAAM,UAAU,QAAQ,eAAe;IAAqB,CAAA,EAC3E,CAAA;IACJ,qBAAC,MAAD,EAAA,UAAA,CACE,oBAAC,OAAD;KAAO,MAAM,WAAW,OAAO,YAAY;KAAU,MAAA;KAClD,UAAA,WAAW,OAAO,UAAU;IACxB,CAAA,GACN,WAAW,OAAO,OAAO,oBAAC,MAAD;KAAM,IAAG;KAAO,UAAA;IAAa,CAAA,CACrD,EAAA,CAAA;GACF,EAAA,GAjBK,MAAM,MAiBX;EAER,CAAC,EACI,CAAA,CACF,EAAA,CAAA,EACF,CAAA;CACH,EAAA,CAAA;AAEV"}
|
|
@@ -8,8 +8,11 @@ import { HStack } from "../ui/stacks.mjs";
|
|
|
8
8
|
import { Table } from "../ui/table.mjs";
|
|
9
9
|
import { csrfField } from "../ui/csrf-field.mjs";
|
|
10
10
|
import { DocumentLayout } from "../ui/document.mjs";
|
|
11
|
+
import { PublicOriginCard } from "./admin-system-origin.mjs";
|
|
12
|
+
import { CaptureTargetsCard } from "./admin-system-targets.mjs";
|
|
13
|
+
import { NotificationsPausedNotice } from "./notifications-paused.mjs";
|
|
11
14
|
import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
12
|
-
|
|
15
|
+
// src/pages/admin-system.tsx
|
|
13
16
|
function healthTone(state) {
|
|
14
17
|
if (state === "ok") return "success";
|
|
15
18
|
if (state === "starting") return "info";
|
|
@@ -90,9 +93,27 @@ function AdapterTable(props) {
|
|
|
90
93
|
/* @__PURE__ */ jsx("th", { children: "Detail" })
|
|
91
94
|
] }) }), /* @__PURE__ */ jsx("tbody", { children: report.adapters.map((adapter) => /* @__PURE__ */ jsx(AdapterRow, { adapter }, `${adapter.category}/${adapter.kind}`)) })] }) });
|
|
92
95
|
}
|
|
96
|
+
/** Detected hardware and the capture concurrency it yields (auto unless configured). */
|
|
97
|
+
function CaptureSizing(props) {
|
|
98
|
+
const { cpus, memoryMb, builds, pages } = props.capture;
|
|
99
|
+
return /* @__PURE__ */ jsxs(Meta, { children: [
|
|
100
|
+
"Capture host ",
|
|
101
|
+
cpus,
|
|
102
|
+
" CPU · ",
|
|
103
|
+
memoryMb,
|
|
104
|
+
" MB · builds at once ",
|
|
105
|
+
builds.value,
|
|
106
|
+
builds.auto ? " (auto)" : " (configured)",
|
|
107
|
+
" · pages per build ",
|
|
108
|
+
pages.start,
|
|
109
|
+
"–",
|
|
110
|
+
pages.max,
|
|
111
|
+
" (auto, adapts to load unless the runner pins it)"
|
|
112
|
+
] });
|
|
113
|
+
}
|
|
93
114
|
/** Non-secret server facts (never secret, admin token, or credentials). */
|
|
94
115
|
function ServerFacts(props) {
|
|
95
|
-
const { report, authEnabled, config, authMethods } = props;
|
|
116
|
+
const { report, authEnabled, config, authMethods, capture } = props.data;
|
|
96
117
|
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
97
118
|
/* @__PURE__ */ jsx(SectionTitle, { children: "Server" }),
|
|
98
119
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -115,9 +136,6 @@ function ServerFacts(props) {
|
|
|
115
136
|
/* @__PURE__ */ jsxs(Meta, { children: [
|
|
116
137
|
"Auth ",
|
|
117
138
|
authEnabled ? "enabled" : "disabled — all operations permitted",
|
|
118
|
-
" · Capture concurrency",
|
|
119
|
-
" ",
|
|
120
|
-
formatOptional(config.captureConcurrency),
|
|
121
139
|
" · Purge TTL",
|
|
122
140
|
" ",
|
|
123
141
|
formatOptional(config.purgeTtlDays),
|
|
@@ -126,6 +144,7 @@ function ServerFacts(props) {
|
|
|
126
144
|
config.branchTtlDays === null ? "disabled" : `${formatOptional(config.branchTtlDays)} days`
|
|
127
145
|
] }),
|
|
128
146
|
authMethods && authMethods.length > 0 ? /* @__PURE__ */ jsx(HStack, { children: authMethods.map((method) => /* @__PURE__ */ jsx(Badge, { children: method }, method)) }) : null,
|
|
147
|
+
capture ? /* @__PURE__ */ jsx(CaptureSizing, { capture }) : null,
|
|
129
148
|
/* @__PURE__ */ jsxs(Meta, { children: [
|
|
130
149
|
"Scratch dir ",
|
|
131
150
|
formatOptional(config.scratchDir),
|
|
@@ -188,9 +207,37 @@ function CredentialsCard(props) {
|
|
|
188
207
|
}) : /* @__PURE__ */ jsx(Meta, { children: rotating ? "All credentials use the current secret. Remove SECRET_PREVIOUS." : "To rotate, set SECRET to the new value and SECRET_PREVIOUS to the old one." })
|
|
189
208
|
] });
|
|
190
209
|
}
|
|
210
|
+
/** Notice that `testing` is off, so a misconfigured instance in a fleet is visible (ADR 0006). */
|
|
211
|
+
function HostingOnlyNotice(props) {
|
|
212
|
+
const { hiddenSnapshots } = props;
|
|
213
|
+
return /* @__PURE__ */ jsx("div", {
|
|
214
|
+
class: "mt-1",
|
|
215
|
+
children: /* @__PURE__ */ jsxs(Alert, {
|
|
216
|
+
tone: "info",
|
|
217
|
+
title: "Testing is off: Storybook hosting only",
|
|
218
|
+
children: [
|
|
219
|
+
"This instance publishes and serves Storybooks, but does not capture, compare or keep baselines, and no testing status is posted. Set the ",
|
|
220
|
+
/* @__PURE__ */ jsx("code", { children: "testing" }),
|
|
221
|
+
" option to turn testing on.",
|
|
222
|
+
hiddenSnapshots > 0 ? ` ${hiddenSnapshots} existing snapshot(s) are hidden, not deleted, and reappear when testing is turned on.` : ""
|
|
223
|
+
]
|
|
224
|
+
})
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
/** The public origin and the capture browsers (ADR 0007), when the instance has them. */
|
|
228
|
+
function CaptureCards(props) {
|
|
229
|
+
const { publicOrigin, targets } = props.data;
|
|
230
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [publicOrigin ? /* @__PURE__ */ jsx("div", {
|
|
231
|
+
class: "mt-1",
|
|
232
|
+
children: /* @__PURE__ */ jsx(PublicOriginCard, { origin: publicOrigin })
|
|
233
|
+
}) : null, targets && targets.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
234
|
+
class: "mt-1",
|
|
235
|
+
children: /* @__PURE__ */ jsx(CaptureTargetsCard, { targets })
|
|
236
|
+
}) : null] });
|
|
237
|
+
}
|
|
191
238
|
/** Site-admin System page: adapter inventory with in-depth health. */
|
|
192
239
|
function renderAdminSystemPage(data) {
|
|
193
|
-
const { report,
|
|
240
|
+
const { report, config, credentials } = data;
|
|
194
241
|
return /* @__PURE__ */ jsxs(DocumentLayout, {
|
|
195
242
|
title: "System",
|
|
196
243
|
nav: { active: "admin" },
|
|
@@ -206,19 +253,22 @@ function renderAdminSystemPage(data) {
|
|
|
206
253
|
" ",
|
|
207
254
|
formatUptime(report.uptimeSecs)
|
|
208
255
|
] }),
|
|
209
|
-
actions: /* @__PURE__ */ jsx(Button, {
|
|
256
|
+
actions: /* @__PURE__ */ jsxs(HStack, { children: [data.aiEnabled ? /* @__PURE__ */ jsx(Button, {
|
|
257
|
+
variant: "secondary",
|
|
258
|
+
size: "sm",
|
|
259
|
+
href: "/admin/ai",
|
|
260
|
+
children: "AI usage"
|
|
261
|
+
}) : null, /* @__PURE__ */ jsx(Button, {
|
|
210
262
|
variant: "secondary",
|
|
211
263
|
size: "sm",
|
|
212
264
|
href: "/admin",
|
|
213
265
|
children: "Recheck"
|
|
214
|
-
})
|
|
215
|
-
}),
|
|
216
|
-
/* @__PURE__ */ jsx(ServerFacts, {
|
|
217
|
-
report,
|
|
218
|
-
authEnabled,
|
|
219
|
-
config,
|
|
220
|
-
authMethods
|
|
266
|
+
})] })
|
|
221
267
|
}),
|
|
268
|
+
/* @__PURE__ */ jsx(NotificationsPausedNotice, { paused: data.notificationsPaused }),
|
|
269
|
+
data.testing === false ? /* @__PURE__ */ jsx(HostingOnlyNotice, { hiddenSnapshots: data.hiddenSnapshots ?? 0 }) : null,
|
|
270
|
+
/* @__PURE__ */ jsx(ServerFacts, { data }),
|
|
271
|
+
/* @__PURE__ */ jsx(CaptureCards, { data }),
|
|
222
272
|
credentials ? /* @__PURE__ */ jsx("div", {
|
|
223
273
|
class: "mt-1",
|
|
224
274
|
children: /* @__PURE__ */ jsx(CredentialsCard, {
|
|
@@ -237,7 +287,6 @@ function renderAdminSystemPage(data) {
|
|
|
237
287
|
]
|
|
238
288
|
});
|
|
239
289
|
}
|
|
240
|
-
//#endregion
|
|
241
290
|
export { renderAdminSystemPage };
|
|
242
291
|
|
|
243
292
|
//# sourceMappingURL=admin-system.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-system.mjs","names":[],"sources":["../../src/pages/admin-system.tsx"],"sourcesContent":["import type { ShelfConfig } from \"@storyshelf/core/config\";\nimport type { CredentialProbe } from \"@storyshelf/core/models\";\nimport type { HtmlEscapedString } from \"hono/utils/html\";\nimport type { HealthReport } from \"../routers/health-report.ts\";\nimport {\n Alert,\n Badge,\n Button,\n Card,\n EmptyState,\n HStack,\n Meta,\n PageHeader,\n SectionTitle,\n Stat,\n Table,\n} from \"../ui/components.tsx\";\nimport { csrfField } from \"../ui/csrf-field.tsx\";\nimport { DocumentLayout, type RenderedContent } from \"../ui/document.tsx\";\n\n/* eslint-disable promise-function-async -- Hono JSX components return HtmlEscapedString | Promise<HtmlEscapedString> */\n\n/** Data for the site-admin System page (adapters, health, safe config). */\nexport interface AdminSystemData {\n report: HealthReport;\n authEnabled: boolean;\n config: ShelfConfig;\n /** Active login method labels (read-only badges; empty when auth is off). */\n authMethods?: string[];\n /** Stored-credential state; null/undefined when no secret is configured. */\n credentials?: CredentialProbe | null;\n}\n\nfunction healthTone(state: string): \"success\" | \"info\" | \"danger\" | \"neutral\" {\n if (state === \"ok\") {\n return \"success\";\n }\n if (state === \"starting\") {\n return \"info\";\n }\n if (state === \"failed\" || state === \"degraded\") {\n return \"danger\";\n }\n return \"neutral\";\n}\n\nfunction formatUptime(uptimeSecs: number): string {\n if (uptimeSecs < 60) {\n return `${uptimeSecs}s`;\n }\n const minutes = Math.floor(uptimeSecs / 60);\n if (minutes < 60) {\n return `${minutes}m ${uptimeSecs % 60}s`;\n }\n return `${Math.floor(minutes / 60)}h ${minutes % 60}m`;\n}\n\nfunction formatLatency(latencyMs: number | undefined): string {\n return latencyMs === undefined ? \"—\" : `${latencyMs} ms`;\n}\n\nfunction formatOptional(value: string | number | null | undefined): string {\n if (value === undefined || value === null || value === \"\") {\n return \"—\";\n }\n return String(value);\n}\n\n/** One adapter row: identity, version, live probe state, latency, detail. */\nfunction AdapterRow(props: {\n adapter: HealthReport[\"adapters\"][number];\n}): HtmlEscapedString | Promise<HtmlEscapedString> {\n const { adapter } = props;\n return (\n <tr key={`${adapter.category}/${adapter.kind}`}>\n <td>\n <strong>{adapter.name}</strong>\n {adapter.description ? <Meta as=\"div\">{adapter.description}</Meta> : null}\n {adapter.hasLifecycle ? null : <Meta as=\"div\">No lifecycle hooks</Meta>}\n </td>\n <td>\n <Meta as=\"span\">{adapter.category}</Meta>\n </td>\n <td>\n <Meta as=\"span\" mono>\n {adapter.kind}\n </Meta>\n </td>\n <td>\n <Meta as=\"span\" mono>\n {adapter.version}\n </Meta>\n </td>\n <td>\n <Badge tone={healthTone(adapter.state)} icon>\n {adapter.state}\n </Badge>\n </td>\n <td class=\"nowrap\">\n <Meta as=\"span\">{formatLatency(adapter.latencyMs)}</Meta>\n </td>\n <td>\n <Meta as=\"span\">{adapter.detail ?? \"—\"}</Meta>\n </td>\n </tr>\n );\n}\n\ninterface AdapterTableProps {\n report: HealthReport;\n}\n\n/** Adapter inventory with live health states. */\nfunction AdapterTable(props: AdapterTableProps): HtmlEscapedString | Promise<HtmlEscapedString> {\n const { report } = props;\n if (report.adapters.length === 0) {\n return <EmptyState description=\"No adapters wired.\" />;\n }\n return (\n <Table>\n <table>\n <thead>\n <tr>\n <th>Adapter</th>\n <th>Category</th>\n <th>Kind</th>\n <th>Version</th>\n <th>Health</th>\n <th>Latency</th>\n <th>Detail</th>\n </tr>\n </thead>\n <tbody>\n {report.adapters.map((adapter) => (\n <AdapterRow key={`${adapter.category}/${adapter.kind}`} adapter={adapter} />\n ))}\n </tbody>\n </table>\n </Table>\n );\n}\n\ninterface ServerFactsProps {\n report: HealthReport;\n authEnabled: boolean;\n config: ShelfConfig;\n authMethods?: string[];\n}\n\n/** Non-secret server facts (never secret, admin token, or credentials). */\nfunction ServerFacts(props: ServerFactsProps): HtmlEscapedString | Promise<HtmlEscapedString> {\n const { report, authEnabled, config, authMethods } = props;\n return (\n <Card>\n <SectionTitle>Server</SectionTitle>\n <div class=\"grid grid--3\">\n <Stat label=\"Status\" value={report.status} />\n <Stat label=\"Uptime\" value={formatUptime(report.uptimeSecs)} />\n <Stat label=\"Version\" value={report.version} />\n </div>\n <Meta>\n Auth {authEnabled ? \"enabled\" : \"disabled — all operations permitted\"} · Capture concurrency{\" \"}\n {formatOptional(config.captureConcurrency)} · Purge TTL{\" \"}\n {formatOptional(config.purgeTtlDays)} days · Branch TTL{\" \"}\n {config.branchTtlDays === null\n ? \"disabled\"\n : `${formatOptional(config.branchTtlDays)} days`}\n </Meta>\n {authMethods && authMethods.length > 0 ? (\n <HStack>\n {authMethods.map((method) => (\n <Badge key={method}>{method}</Badge>\n ))}\n </HStack>\n ) : null}\n <Meta>\n Scratch dir {formatOptional(config.scratchDir)} · Published domain{\" \"}\n {formatOptional(config.publishedBaseDomain)} · Max upload{\" \"}\n {formatOptional(config.maxUploadBytes)} bytes\n </Meta>\n </Card>\n );\n}\n\n/** Credential encryption state with the admin-only re-encrypt action. */\nfunction CredentialsCard(props: {\n probe: CredentialProbe;\n config: ShelfConfig;\n}): HtmlEscapedString | Promise<HtmlEscapedString> {\n const { probe, config } = props;\n const rotating = Boolean(config.previousSecret);\n return (\n <Card>\n <SectionTitle>Stored credentials</SectionTitle>\n <Meta>\n Webhook secrets, git tokens and notification secrets are encrypted with the server secret.\n </Meta>\n <div class=\"grid grid--3\">\n <Stat label=\"Current secret\" value={String(probe.current)} />\n <Stat label=\"Previous secret\" value={String(probe.previous)} />\n <Stat label=\"Unreadable\" value={String(probe.unreadable.length)} />\n </div>\n {probe.unreadable.length > 0 ? (\n <Alert tone=\"danger\" title=\"Some credentials cannot be decrypted\">\n No configured secret matches {probe.unreadable.length} stored credential(s) (\n {[...new Set(probe.unreadable.map((row) => row.source))].join(\", \")}). Check that SECRET\n and SECRET_PREVIOUS are correct, or recreate them.\n </Alert>\n ) : null}\n {rotating && probe.previous > 0 ? (\n <form\n method=\"post\"\n action=\"/admin/credentials/reencrypt\"\n hx-post=\"/admin/credentials/reencrypt\"\n hx-target=\"body\"\n >\n {csrfField()}\n <Button type=\"submit\" variant=\"secondary\" size=\"sm\">\n Re-encrypt with current secret\n </Button>\n </form>\n ) : (\n <Meta>\n {rotating\n ? \"All credentials use the current secret. Remove SECRET_PREVIOUS.\"\n : \"To rotate, set SECRET to the new value and SECRET_PREVIOUS to the old one.\"}\n </Meta>\n )}\n </Card>\n );\n}\n\n/** Site-admin System page: adapter inventory with in-depth health. */\nexport function renderAdminSystemPage(data: AdminSystemData): RenderedContent {\n const { report, authEnabled, config, authMethods, credentials } = data;\n return (\n <DocumentLayout title=\"System\" nav={{ active: \"admin\" }}>\n <PageHeader\n title=\"System\"\n description=\"Adapter inventory with in-depth health. Visible to site admins only.\"\n meta={\n <>\n {report.adapters.length} adapters · {report.status} · up{\" \"}\n {formatUptime(report.uptimeSecs)}\n </>\n }\n actions={\n <Button variant=\"secondary\" size=\"sm\" href=\"/admin\">\n Recheck\n </Button>\n }\n />\n <ServerFacts\n report={report}\n authEnabled={authEnabled}\n config={config}\n authMethods={authMethods}\n />\n {credentials ? (\n <div class=\"mt-1\">\n <CredentialsCard probe={credentials} config={config} />\n </div>\n ) : null}\n <div class=\"mt-1\">\n <Card>\n <SectionTitle>Adapters</SectionTitle>\n <Meta>\n Live probe per adapter (2s timeout, parallel). Setup failures surface as failed rows;\n adapters without lifecycle hooks report their wired state.\n </Meta>\n <AdapterTable report={report} />\n </Card>\n </div>\n </DocumentLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"admin-system.mjs","names":[],"sources":["../../src/pages/admin-system.tsx"],"sourcesContent":["import type { RunnerTarget } from \"@storyshelf/core/adapter/capture-runner\";\nimport type { ShelfConfig } from \"@storyshelf/core/config\";\nimport type { CredentialProbe } from \"@storyshelf/core/models\";\nimport type { CaptureHostSummary } from \"@storyshelf/core/utils\";\nimport type { HtmlEscapedString } from \"hono/utils/html\";\nimport type { HealthReport } from \"../routers/health-report.ts\";\nimport {\n Alert,\n Badge,\n Button,\n Card,\n EmptyState,\n HStack,\n Meta,\n PageHeader,\n SectionTitle,\n Stat,\n Table,\n} from \"../ui/components.tsx\";\nimport { csrfField } from \"../ui/csrf-field.tsx\";\nimport { DocumentLayout, type RenderedContent } from \"../ui/document.tsx\";\nimport { PublicOriginCard, type PublicOriginView } from \"./admin-system-origin.tsx\";\nimport { CaptureTargetsCard } from \"./admin-system-targets.tsx\";\nimport { NotificationsPausedNotice } from \"./notifications-paused.tsx\";\n\n/* eslint-disable promise-function-async -- Hono JSX components return HtmlEscapedString | Promise<HtmlEscapedString> */\n\n/** Data for the site-admin System page (adapters, health, safe config). */\nexport interface AdminSystemData {\n report: HealthReport;\n authEnabled: boolean;\n config: ShelfConfig;\n /** Active login method labels (read-only badges; empty when auth is off). */\n authMethods?: string[];\n /** Stored-credential state; null/undefined when no secret is configured. */\n credentials?: CredentialProbe | null;\n /** True when AI is configured (shows the AI usage link). */\n aiEnabled?: boolean;\n /** Whether `options.testing` is set; false shows the hosting-only notice. */\n testing?: boolean;\n /** Snapshots hidden because `testing` is off (only meaningful when it is). */\n hiddenSnapshots?: number;\n /** Detected host budget and effective capture concurrency; null when capture runs elsewhere. */\n capture?: CaptureHostSummary | null;\n /** The browsers the capture runner offers (ADR 0007); omitted without a runner list. */\n targets?: readonly RunnerTarget[] | undefined;\n /** The public origin and where it came from; omitted when the store has no resolver. */\n publicOrigin?: PublicOriginView | undefined;\n /** Notifiers are wired but no public origin resolves, so nothing is sent (ADR 0014, decision 11). */\n notificationsPaused?: boolean | undefined;\n}\n\nfunction healthTone(state: string): \"success\" | \"info\" | \"danger\" | \"neutral\" {\n if (state === \"ok\") {\n return \"success\";\n }\n if (state === \"starting\") {\n return \"info\";\n }\n if (state === \"failed\" || state === \"degraded\") {\n return \"danger\";\n }\n return \"neutral\";\n}\n\nfunction formatUptime(uptimeSecs: number): string {\n if (uptimeSecs < 60) {\n return `${uptimeSecs}s`;\n }\n const minutes = Math.floor(uptimeSecs / 60);\n if (minutes < 60) {\n return `${minutes}m ${uptimeSecs % 60}s`;\n }\n return `${Math.floor(minutes / 60)}h ${minutes % 60}m`;\n}\n\nfunction formatLatency(latencyMs: number | undefined): string {\n return latencyMs === undefined ? \"—\" : `${latencyMs} ms`;\n}\n\nfunction formatOptional(value: string | number | null | undefined): string {\n if (value === undefined || value === null || value === \"\") {\n return \"—\";\n }\n return String(value);\n}\n\n/** One adapter row: identity, version, live probe state, latency, detail. */\nfunction AdapterRow(props: {\n adapter: HealthReport[\"adapters\"][number];\n}): HtmlEscapedString | Promise<HtmlEscapedString> {\n const { adapter } = props;\n return (\n <tr key={`${adapter.category}/${adapter.kind}`}>\n <td>\n <strong>{adapter.name}</strong>\n {adapter.description ? <Meta as=\"div\">{adapter.description}</Meta> : null}\n {adapter.hasLifecycle ? null : <Meta as=\"div\">No lifecycle hooks</Meta>}\n </td>\n <td>\n <Meta as=\"span\">{adapter.category}</Meta>\n </td>\n <td>\n <Meta as=\"span\" mono>\n {adapter.kind}\n </Meta>\n </td>\n <td>\n <Meta as=\"span\" mono>\n {adapter.version}\n </Meta>\n </td>\n <td>\n <Badge tone={healthTone(adapter.state)} icon>\n {adapter.state}\n </Badge>\n </td>\n <td class=\"nowrap\">\n <Meta as=\"span\">{formatLatency(adapter.latencyMs)}</Meta>\n </td>\n <td>\n <Meta as=\"span\">{adapter.detail ?? \"—\"}</Meta>\n </td>\n </tr>\n );\n}\n\ninterface AdapterTableProps {\n report: HealthReport;\n}\n\n/** Adapter inventory with live health states. */\nfunction AdapterTable(props: AdapterTableProps): HtmlEscapedString | Promise<HtmlEscapedString> {\n const { report } = props;\n if (report.adapters.length === 0) {\n return <EmptyState description=\"No adapters wired.\" />;\n }\n return (\n <Table>\n <table>\n <thead>\n <tr>\n <th>Adapter</th>\n <th>Category</th>\n <th>Kind</th>\n <th>Version</th>\n <th>Health</th>\n <th>Latency</th>\n <th>Detail</th>\n </tr>\n </thead>\n <tbody>\n {report.adapters.map((adapter) => (\n <AdapterRow key={`${adapter.category}/${adapter.kind}`} adapter={adapter} />\n ))}\n </tbody>\n </table>\n </Table>\n );\n}\n\n/** Detected hardware and the capture concurrency it yields (auto unless configured). */\nfunction CaptureSizing(props: {\n capture: CaptureHostSummary;\n}): HtmlEscapedString | Promise<HtmlEscapedString> {\n const { cpus, memoryMb, builds, pages } = props.capture;\n return (\n <Meta>\n Capture host {cpus} CPU · {memoryMb} MB · builds at once {builds.value}\n {builds.auto ? \" (auto)\" : \" (configured)\"} · pages per build {pages.start}–{pages.max} (auto,\n adapts to load unless the runner pins it)\n </Meta>\n );\n}\n\ninterface ServerFactsProps {\n data: AdminSystemData;\n}\n\n/** Non-secret server facts (never secret, admin token, or credentials). */\nfunction ServerFacts(props: ServerFactsProps): HtmlEscapedString | Promise<HtmlEscapedString> {\n const { report, authEnabled, config, authMethods, capture } = props.data;\n return (\n <Card>\n <SectionTitle>Server</SectionTitle>\n <div class=\"grid grid--3\">\n <Stat label=\"Status\" value={report.status} />\n <Stat label=\"Uptime\" value={formatUptime(report.uptimeSecs)} />\n <Stat label=\"Version\" value={report.version} />\n </div>\n <Meta>\n Auth {authEnabled ? \"enabled\" : \"disabled — all operations permitted\"} · Purge TTL{\" \"}\n {formatOptional(config.purgeTtlDays)} days · Branch TTL{\" \"}\n {config.branchTtlDays === null\n ? \"disabled\"\n : `${formatOptional(config.branchTtlDays)} days`}\n </Meta>\n {authMethods && authMethods.length > 0 ? (\n <HStack>\n {authMethods.map((method) => (\n <Badge key={method}>{method}</Badge>\n ))}\n </HStack>\n ) : null}\n {capture ? <CaptureSizing capture={capture} /> : null}\n <Meta>\n Scratch dir {formatOptional(config.scratchDir)} · Published domain{\" \"}\n {formatOptional(config.publishedBaseDomain)} · Max upload{\" \"}\n {formatOptional(config.maxUploadBytes)} bytes\n </Meta>\n </Card>\n );\n}\n\n/** Credential encryption state with the admin-only re-encrypt action. */\nfunction CredentialsCard(props: {\n probe: CredentialProbe;\n config: ShelfConfig;\n}): HtmlEscapedString | Promise<HtmlEscapedString> {\n const { probe, config } = props;\n const rotating = Boolean(config.previousSecret);\n return (\n <Card>\n <SectionTitle>Stored credentials</SectionTitle>\n <Meta>\n Webhook secrets, git tokens and notification secrets are encrypted with the server secret.\n </Meta>\n <div class=\"grid grid--3\">\n <Stat label=\"Current secret\" value={String(probe.current)} />\n <Stat label=\"Previous secret\" value={String(probe.previous)} />\n <Stat label=\"Unreadable\" value={String(probe.unreadable.length)} />\n </div>\n {probe.unreadable.length > 0 ? (\n <Alert tone=\"danger\" title=\"Some credentials cannot be decrypted\">\n No configured secret matches {probe.unreadable.length} stored credential(s) (\n {[...new Set(probe.unreadable.map((row) => row.source))].join(\", \")}). Check that SECRET\n and SECRET_PREVIOUS are correct, or recreate them.\n </Alert>\n ) : null}\n {rotating && probe.previous > 0 ? (\n <form\n method=\"post\"\n action=\"/admin/credentials/reencrypt\"\n hx-post=\"/admin/credentials/reencrypt\"\n hx-target=\"body\"\n >\n {csrfField()}\n <Button type=\"submit\" variant=\"secondary\" size=\"sm\">\n Re-encrypt with current secret\n </Button>\n </form>\n ) : (\n <Meta>\n {rotating\n ? \"All credentials use the current secret. Remove SECRET_PREVIOUS.\"\n : \"To rotate, set SECRET to the new value and SECRET_PREVIOUS to the old one.\"}\n </Meta>\n )}\n </Card>\n );\n}\n\n/** Notice that `testing` is off, so a misconfigured instance in a fleet is visible (ADR 0006). */\nfunction HostingOnlyNotice(props: {\n hiddenSnapshots: number;\n}): HtmlEscapedString | Promise<HtmlEscapedString> {\n const { hiddenSnapshots } = props;\n return (\n <div class=\"mt-1\">\n <Alert tone=\"info\" title=\"Testing is off: Storybook hosting only\">\n This instance publishes and serves Storybooks, but does not capture, compare or keep\n baselines, and no testing status is posted. Set the <code>testing</code> option to turn\n testing on.\n {hiddenSnapshots > 0\n ? ` ${hiddenSnapshots} existing snapshot(s) are hidden, not deleted, and reappear when testing is turned on.`\n : \"\"}\n </Alert>\n </div>\n );\n}\n\n/** The public origin and the capture browsers (ADR 0007), when the instance has them. */\nfunction CaptureCards(props: {\n data: AdminSystemData;\n}): HtmlEscapedString | Promise<HtmlEscapedString> {\n const { publicOrigin, targets } = props.data;\n return (\n <>\n {publicOrigin ? (\n <div class=\"mt-1\">\n <PublicOriginCard origin={publicOrigin} />\n </div>\n ) : null}\n {targets && targets.length > 0 ? (\n <div class=\"mt-1\">\n <CaptureTargetsCard targets={targets} />\n </div>\n ) : null}\n </>\n );\n}\n\n/** Site-admin System page: adapter inventory with in-depth health. */\nexport function renderAdminSystemPage(data: AdminSystemData): RenderedContent {\n const { report, config, credentials } = data;\n return (\n <DocumentLayout title=\"System\" nav={{ active: \"admin\" }}>\n <PageHeader\n title=\"System\"\n description=\"Adapter inventory with in-depth health. Visible to site admins only.\"\n meta={\n <>\n {report.adapters.length} adapters · {report.status} · up{\" \"}\n {formatUptime(report.uptimeSecs)}\n </>\n }\n actions={\n <HStack>\n {data.aiEnabled ? (\n <Button variant=\"secondary\" size=\"sm\" href=\"/admin/ai\">\n AI usage\n </Button>\n ) : null}\n <Button variant=\"secondary\" size=\"sm\" href=\"/admin\">\n Recheck\n </Button>\n </HStack>\n }\n />\n <NotificationsPausedNotice paused={data.notificationsPaused} />\n {data.testing === false ? (\n <HostingOnlyNotice hiddenSnapshots={data.hiddenSnapshots ?? 0} />\n ) : null}\n <ServerFacts data={data} />\n <CaptureCards data={data} />\n {credentials ? (\n <div class=\"mt-1\">\n <CredentialsCard probe={credentials} config={config} />\n </div>\n ) : null}\n <div class=\"mt-1\">\n <Card>\n <SectionTitle>Adapters</SectionTitle>\n <Meta>\n Live probe per adapter (2s timeout, parallel). Setup failures surface as failed rows;\n adapters without lifecycle hooks report their wired state.\n </Meta>\n <AdapterTable report={report} />\n </Card>\n </div>\n </DocumentLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,21 +1,32 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
-
import { getStore } from "../store.mjs";
|
|
4
|
+
import { catalogOf, getStore, testingEnabled } from "../store.mjs";
|
|
5
5
|
import { Button } from "../ui/buttons.mjs";
|
|
6
6
|
import { Badge, EmptyState, Meta, Stat, statusTone } from "../ui/feedback.mjs";
|
|
7
|
-
import { TextareaField } from "../ui/forms.mjs";
|
|
8
7
|
import { Card, PageHeader, SectionTitle } from "../ui/layout.mjs";
|
|
9
8
|
import { HStack, VStack } from "../ui/stacks.mjs";
|
|
10
9
|
import { Thumbnail } from "../ui/thumbnail.mjs";
|
|
11
10
|
import { DocumentLayout } from "../ui/document.mjs";
|
|
12
11
|
import { loadBaselineView } from "../routers/baseline-guard.mjs";
|
|
13
|
-
import {
|
|
12
|
+
import { designUrlsFor, loadDesignResolutions, providerNameFor } from "../routers/design.handlers.mjs";
|
|
13
|
+
import { loadReviewSection } from "../routers/review-section.handlers.mjs";
|
|
14
|
+
import { snapshotCard, snapshotCardBody, snapshotCardHead, snapshotCardMeta, snapshotGrid } from "../ui/styles/review.mjs";
|
|
15
|
+
import { a11ySummaryNote, a11ySummaryOf } from "./a11y-violations.mjs";
|
|
16
|
+
import { snapshotVariant } from "./build-diff-model.mjs";
|
|
14
17
|
import { StaleBaselineNotice } from "./build-diff-stale.mjs";
|
|
15
|
-
import {
|
|
18
|
+
import { LinkedUsage } from "./build-diff-usage.mjs";
|
|
19
|
+
import { TestsCard } from "./build-tests.mjs";
|
|
20
|
+
import { DesignButtons } from "./design-links.mjs";
|
|
21
|
+
import { ChangesetCard } from "./review-changeset.mjs";
|
|
22
|
+
import { CommentsCard } from "./review-comments.mjs";
|
|
23
|
+
import { VerdictCard } from "./review-verdict.mjs";
|
|
24
|
+
import { groupComponents, parseTestResults } from "@storyshelf/core/capture";
|
|
25
|
+
import { BuildModel, CaptureAttemptModel, CaptureLogModel, LabelModel, ProjectModel, SnapshotModel } from "@storyshelf/core/models";
|
|
26
|
+
import { CANCELLABLE_BUILD_STATUSES } from "@storyshelf/core/types";
|
|
16
27
|
import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
17
28
|
import { createUrlBuilder } from "@storyshelf/core/urls";
|
|
18
|
-
|
|
29
|
+
// src/pages/build-detail.tsx
|
|
19
30
|
/** Map a capture log level to its badge tone. */
|
|
20
31
|
function logTone(level) {
|
|
21
32
|
if (level === "error") return "danger";
|
|
@@ -24,22 +35,29 @@ function logTone(level) {
|
|
|
24
35
|
return "neutral";
|
|
25
36
|
}
|
|
26
37
|
/** Build overview page: snapshot grid, bulk actions, and build comments. */
|
|
27
|
-
async function renderBuildDetailPage(buildId) {
|
|
38
|
+
async function renderBuildDetailPage(buildId, usageByStory = /* @__PURE__ */ new Map()) {
|
|
28
39
|
const { db } = getStore();
|
|
29
40
|
const build = await new BuildModel(db).get(buildId);
|
|
30
41
|
if (!build) return null;
|
|
31
42
|
const project = await new ProjectModel(db).get(build.projectId);
|
|
32
43
|
if (!project) return null;
|
|
33
44
|
const snapshots = await new SnapshotModel(db).listByBuild(build.id);
|
|
34
|
-
const comments = await new CommentModel(db).listByBuild(build.id);
|
|
35
45
|
const attempts = await new CaptureAttemptModel(db).listByBuild(build.id);
|
|
36
46
|
const logs = new CaptureLogModel(db);
|
|
37
47
|
const attemptLogs = /* @__PURE__ */ new Map();
|
|
38
48
|
for (const attempt of attempts) attemptLogs.set(attempt.id, await logs.listByAttempt(attempt.id));
|
|
39
49
|
const canReview = !getStore().authEnabled || Boolean(getStore().user);
|
|
40
50
|
const { drifted } = await loadBaselineView(project, build, snapshots);
|
|
51
|
+
const designs = await loadDesignResolutions(project, snapshots).catch(() => /* @__PURE__ */ new Map());
|
|
41
52
|
const staleCount = Object.keys(drifted).length;
|
|
42
53
|
const urls = createUrlBuilder("/", getStore().config.publishedBaseDomain);
|
|
54
|
+
const testing = testingEnabled();
|
|
55
|
+
const cancelled = build.status === "cancelled";
|
|
56
|
+
const published = build.status === "approved" && attempts.length === 0;
|
|
57
|
+
const [catalog, labels] = await Promise.all([catalogOf().load(project.id, build.id).catch(() => null), new LabelModel(db).listForBuild(build.id)]);
|
|
58
|
+
const review = await loadReviewSection(project, build, catalog);
|
|
59
|
+
const components = catalog ? groupComponents(catalog.entries) : [];
|
|
60
|
+
const storyCount = catalog?.entries.filter((entry) => entry.type === "story").length ?? 0;
|
|
43
61
|
const grouped = /* @__PURE__ */ new Map();
|
|
44
62
|
for (const snap of snapshots) {
|
|
45
63
|
const key = snap.status;
|
|
@@ -47,7 +65,7 @@ async function renderBuildDetailPage(buildId) {
|
|
|
47
65
|
list.push(snap);
|
|
48
66
|
grouped.set(key, list);
|
|
49
67
|
}
|
|
50
|
-
const
|
|
68
|
+
const a11y = a11ySummaryOf(snapshots);
|
|
51
69
|
const selective = build.affectedOnly && build.affectedImportPaths !== null;
|
|
52
70
|
return /* @__PURE__ */ jsxs(DocumentLayout, {
|
|
53
71
|
title: `Build ${build.gitBranch}`,
|
|
@@ -69,16 +87,24 @@ async function renderBuildDetailPage(buildId) {
|
|
|
69
87
|
" ",
|
|
70
88
|
/* @__PURE__ */ jsx(Badge, {
|
|
71
89
|
tone: statusTone(build.status),
|
|
72
|
-
children: build.status
|
|
90
|
+
children: published ? "Published" : build.status
|
|
73
91
|
}),
|
|
74
|
-
selective ? /* @__PURE__ */ jsxs(Fragment, { children: [" ", /* @__PURE__ */ jsx(Badge, {
|
|
92
|
+
testing && selective ? /* @__PURE__ */ jsxs(Fragment, { children: [" ", /* @__PURE__ */ jsx(Badge, {
|
|
75
93
|
tone: "info",
|
|
76
94
|
children: "affected capture"
|
|
77
95
|
})] }) : null,
|
|
78
|
-
!build.affectedOnly ? /* @__PURE__ */ jsxs(Fragment, { children: [" ", /* @__PURE__ */ jsx(Badge, {
|
|
96
|
+
testing && !build.affectedOnly ? /* @__PURE__ */ jsxs(Fragment, { children: [" ", /* @__PURE__ */ jsx(Badge, {
|
|
79
97
|
tone: "neutral",
|
|
80
98
|
children: "full capture"
|
|
81
|
-
})] }) : null
|
|
99
|
+
})] }) : null,
|
|
100
|
+
labels.map((label) => /* @__PURE__ */ jsxs("span", { children: [" ", /* @__PURE__ */ jsxs(Badge, {
|
|
101
|
+
tone: "neutral",
|
|
102
|
+
children: [
|
|
103
|
+
label.typeKey,
|
|
104
|
+
": ",
|
|
105
|
+
label.value
|
|
106
|
+
]
|
|
107
|
+
})] }, `${label.typeKey}:${label.value}`))
|
|
82
108
|
] }),
|
|
83
109
|
description: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
84
110
|
build.message ?? "No message",
|
|
@@ -87,27 +113,28 @@ async function renderBuildDetailPage(buildId) {
|
|
|
87
113
|
" ",
|
|
88
114
|
"· ",
|
|
89
115
|
new Date(build.createdAt).toLocaleString(),
|
|
90
|
-
selective ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
116
|
+
testing && selective ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
91
117
|
" ",
|
|
92
118
|
"· ",
|
|
93
|
-
|
|
119
|
+
build.snapshotCount - build.inheritedCount,
|
|
94
120
|
" rendered, ",
|
|
95
|
-
inheritedCount,
|
|
96
|
-
"
|
|
121
|
+
build.inheritedCount,
|
|
122
|
+
" ",
|
|
123
|
+
"inherited"
|
|
97
124
|
] }) : null
|
|
98
125
|
] }),
|
|
99
126
|
actions: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
100
|
-
/* @__PURE__ */ jsx(Button, {
|
|
127
|
+
testing ? /* @__PURE__ */ jsx(Button, {
|
|
101
128
|
variant: "primary",
|
|
102
129
|
href: urls.buildDiff(project.slug, build.id),
|
|
103
130
|
children: "Review diffs"
|
|
104
|
-
}),
|
|
131
|
+
}) : null,
|
|
105
132
|
/* @__PURE__ */ jsx(Button, {
|
|
106
|
-
variant: "ghost",
|
|
133
|
+
variant: testing ? "ghost" : "primary",
|
|
107
134
|
href: urls.short(build.id),
|
|
108
135
|
children: "View Storybook"
|
|
109
136
|
}),
|
|
110
|
-
/* @__PURE__ */ jsx("form", {
|
|
137
|
+
testing ? /* @__PURE__ */ jsx("form", {
|
|
111
138
|
method: "post",
|
|
112
139
|
action: `/api/v1/projects/${project.slug}/builds/${build.id}/retry`,
|
|
113
140
|
"hx-post": `/api/v1/projects/${project.slug}/builds/${build.id}/retry`,
|
|
@@ -117,10 +144,22 @@ async function renderBuildDetailPage(buildId) {
|
|
|
117
144
|
type: "submit",
|
|
118
145
|
children: "Retry capture"
|
|
119
146
|
})
|
|
120
|
-
})
|
|
147
|
+
}) : null,
|
|
148
|
+
testing && CANCELLABLE_BUILD_STATUSES.includes(build.status) ? /* @__PURE__ */ jsx("form", {
|
|
149
|
+
method: "post",
|
|
150
|
+
action: `/api/v1/projects/${project.slug}/builds/${build.id}/cancel`,
|
|
151
|
+
"hx-post": `/api/v1/projects/${project.slug}/builds/${build.id}/cancel`,
|
|
152
|
+
"hx-target": "body",
|
|
153
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
154
|
+
variant: "danger",
|
|
155
|
+
size: "sm",
|
|
156
|
+
type: "submit",
|
|
157
|
+
children: "Cancel build"
|
|
158
|
+
})
|
|
159
|
+
}) : null
|
|
121
160
|
] })
|
|
122
161
|
}),
|
|
123
|
-
staleCount > 0 ? /* @__PURE__ */ jsx(StaleBaselineNotice, {
|
|
162
|
+
testing && staleCount > 0 ? /* @__PURE__ */ jsx(StaleBaselineNotice, {
|
|
124
163
|
project,
|
|
125
164
|
build,
|
|
126
165
|
staleCount,
|
|
@@ -130,11 +169,21 @@ async function renderBuildDetailPage(buildId) {
|
|
|
130
169
|
class: "mb-1",
|
|
131
170
|
children: /* @__PURE__ */ jsxs("div", {
|
|
132
171
|
class: "grid grid--3",
|
|
133
|
-
children: [
|
|
172
|
+
children: [catalog ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(Stat, {
|
|
173
|
+
label: "Components",
|
|
174
|
+
value: components.length
|
|
175
|
+
}) }), /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(Stat, {
|
|
176
|
+
label: "Stories",
|
|
177
|
+
value: storyCount
|
|
178
|
+
}) })] }) : null, testing ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
134
179
|
/* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(Stat, {
|
|
135
180
|
label: "Snapshots",
|
|
136
181
|
value: snapshots.length
|
|
137
182
|
}) }),
|
|
183
|
+
/* @__PURE__ */ jsxs(Card, { children: [/* @__PURE__ */ jsx(Stat, {
|
|
184
|
+
label: "Inherited",
|
|
185
|
+
value: build.inheritedCount
|
|
186
|
+
}), /* @__PURE__ */ jsx(Meta, { children: "Reused from the baseline without rendering." })] }),
|
|
138
187
|
/* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(Stat, {
|
|
139
188
|
label: "Changed / new",
|
|
140
189
|
value: build.changedCount,
|
|
@@ -144,11 +193,16 @@ async function renderBuildDetailPage(buildId) {
|
|
|
144
193
|
label: "Approved / unchanged",
|
|
145
194
|
value: build.approvedCount,
|
|
146
195
|
tone: "success"
|
|
147
|
-
}) })
|
|
148
|
-
|
|
196
|
+
}) }),
|
|
197
|
+
/* @__PURE__ */ jsxs(Card, { children: [/* @__PURE__ */ jsx(Stat, {
|
|
198
|
+
label: "Accessibility findings",
|
|
199
|
+
value: a11y.findings,
|
|
200
|
+
tone: a11y.findings > 0 ? "warning" : "neutral"
|
|
201
|
+
}), /* @__PURE__ */ jsx(Meta, { children: a11ySummaryNote(a11y) })] })
|
|
202
|
+
] }) : null]
|
|
149
203
|
})
|
|
150
204
|
}),
|
|
151
|
-
attempts.length > 0 ? /* @__PURE__ */ jsxs(Card, { children: [/* @__PURE__ */ jsx(SectionTitle, { children: "Capture attempts" }), attempts.map((attempt, index) => /* @__PURE__ */ jsxs("details", {
|
|
205
|
+
testing && attempts.length > 0 ? /* @__PURE__ */ jsxs(Card, { children: [/* @__PURE__ */ jsx(SectionTitle, { children: "Capture attempts" }), attempts.map((attempt, index) => /* @__PURE__ */ jsxs("details", {
|
|
152
206
|
open: index === attempts.length - 1,
|
|
153
207
|
children: [
|
|
154
208
|
/* @__PURE__ */ jsxs("summary", { children: [
|
|
@@ -193,7 +247,8 @@ async function renderBuildDetailPage(buildId) {
|
|
|
193
247
|
})
|
|
194
248
|
]
|
|
195
249
|
}, attempt.id))] }) : null,
|
|
196
|
-
|
|
250
|
+
/* @__PURE__ */ jsx(TestsCard, { results: parseTestResults(build.testResults) }),
|
|
251
|
+
testing && canReview && (build.status === "reviewing" || build.status === "comparing") ? /* @__PURE__ */ jsx("div", {
|
|
197
252
|
class: "mb-1",
|
|
198
253
|
children: /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(HStack, { children: [
|
|
199
254
|
/* @__PURE__ */ jsx(Meta, {
|
|
@@ -235,7 +290,11 @@ async function renderBuildDetailPage(buildId) {
|
|
|
235
290
|
})
|
|
236
291
|
] }) })
|
|
237
292
|
}) : null,
|
|
238
|
-
|
|
293
|
+
review ? /* @__PURE__ */ jsx("div", {
|
|
294
|
+
class: "mb-1",
|
|
295
|
+
children: /* @__PURE__ */ jsxs(VStack, { children: [testing || cancelled ? null : /* @__PURE__ */ jsx(VerdictCard, { data: review }), /* @__PURE__ */ jsx(ChangesetCard, { data: review })] })
|
|
296
|
+
}) : null,
|
|
297
|
+
!testing ? null : snapshots.length === 0 ? /* @__PURE__ */ jsx(EmptyState, {
|
|
239
298
|
title: "No snapshots yet",
|
|
240
299
|
description: "Capture is pending or failed. Try retrying capture."
|
|
241
300
|
}) : /* @__PURE__ */ jsx("div", {
|
|
@@ -256,7 +315,7 @@ async function renderBuildDetailPage(buildId) {
|
|
|
256
315
|
/* @__PURE__ */ jsxs("span", {
|
|
257
316
|
class: snapshotCardMeta,
|
|
258
317
|
children: [
|
|
259
|
-
snap
|
|
318
|
+
snapshotVariant(snap),
|
|
260
319
|
" · ",
|
|
261
320
|
snap.viewportWidth,
|
|
262
321
|
"×",
|
|
@@ -290,6 +349,10 @@ async function renderBuildDetailPage(buildId) {
|
|
|
290
349
|
snap.diffPixels === null || snap.diffPixels === void 0 ? "" : ` · ${snap.diffPixels} px`
|
|
291
350
|
]
|
|
292
351
|
}),
|
|
352
|
+
snap.storyImportPath && usageByStory.has(snap.storyImportPath) ? /* @__PURE__ */ jsx(LinkedUsage, {
|
|
353
|
+
usage: usageByStory.get(snap.storyImportPath) ?? [],
|
|
354
|
+
publishedBaseDomain: getStore().config.publishedBaseDomain
|
|
355
|
+
}) : null,
|
|
293
356
|
/* @__PURE__ */ jsxs(HStack, { children: [
|
|
294
357
|
/* @__PURE__ */ jsx(Button, {
|
|
295
358
|
variant: "secondary",
|
|
@@ -303,6 +366,16 @@ async function renderBuildDetailPage(buildId) {
|
|
|
303
366
|
href: urls.short(build.id),
|
|
304
367
|
children: "View Storybook"
|
|
305
368
|
}),
|
|
369
|
+
snap.storyImportPath ? /* @__PURE__ */ jsx(Button, {
|
|
370
|
+
variant: "ghost",
|
|
371
|
+
size: "sm",
|
|
372
|
+
href: `${urls.component(project.slug, snap.storyImportPath)}#${snap.storyId}`,
|
|
373
|
+
children: "Component"
|
|
374
|
+
}) : null,
|
|
375
|
+
/* @__PURE__ */ jsx(DesignButtons, {
|
|
376
|
+
urls: designUrlsFor(designs, snap),
|
|
377
|
+
providerName: providerNameFor
|
|
378
|
+
}),
|
|
306
379
|
canReview && (snap.status === "new" || snap.status === "changed") ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("form", {
|
|
307
380
|
method: "post",
|
|
308
381
|
action: `/api/v1/projects/${project.slug}/builds/${build.id}/snapshots/${snap.id}/approve`,
|
|
@@ -334,59 +407,13 @@ async function renderBuildDetailPage(buildId) {
|
|
|
334
407
|
})]
|
|
335
408
|
}, snap.id))
|
|
336
409
|
}),
|
|
337
|
-
/* @__PURE__ */ jsx("div", {
|
|
410
|
+
review ? /* @__PURE__ */ jsx("div", {
|
|
338
411
|
class: "mt-1",
|
|
339
|
-
children: /* @__PURE__ */ jsxs(
|
|
340
|
-
|
|
341
|
-
comments.length === 0 ? /* @__PURE__ */ jsx(Meta, { children: "No comments. Add one in the diff review page for a specific snapshot." }) : null,
|
|
342
|
-
/* @__PURE__ */ jsx(VStack, { children: comments.map((comment) => /* @__PURE__ */ jsxs("div", {
|
|
343
|
-
class: reviewComment,
|
|
344
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
345
|
-
class: reviewCommentHead,
|
|
346
|
-
children: [
|
|
347
|
-
/* @__PURE__ */ jsx("strong", { children: comment.userId ?? "anonymous" }),
|
|
348
|
-
/* @__PURE__ */ jsxs("span", { children: ["· ", new Date(comment.createdAt).toLocaleString()] }),
|
|
349
|
-
comment.snapshotId ? /* @__PURE__ */ jsx(Badge, {
|
|
350
|
-
tone: "neutral",
|
|
351
|
-
children: snapshots.find((snapshot) => snapshot.id === comment.snapshotId)?.storyName ?? comment.snapshotId.slice(0, 6)
|
|
352
|
-
}) : /* @__PURE__ */ jsx(Badge, {
|
|
353
|
-
tone: "neutral",
|
|
354
|
-
children: "build"
|
|
355
|
-
}),
|
|
356
|
-
comment.resolved ? /* @__PURE__ */ jsx(Badge, {
|
|
357
|
-
tone: "success",
|
|
358
|
-
children: "resolved"
|
|
359
|
-
}) : null
|
|
360
|
-
]
|
|
361
|
-
}), /* @__PURE__ */ jsx("p", {
|
|
362
|
-
class: reviewCommentBody,
|
|
363
|
-
children: comment.body
|
|
364
|
-
})]
|
|
365
|
-
}, comment.id)) }),
|
|
366
|
-
/* @__PURE__ */ jsx("form", {
|
|
367
|
-
method: "post",
|
|
368
|
-
action: `/api/v1/projects/${project.slug}/builds/${build.id}/comments`,
|
|
369
|
-
"hx-post": `/api/v1/projects/${project.slug}/builds/${build.id}/comments`,
|
|
370
|
-
"hx-target": "body",
|
|
371
|
-
class: "mt-1 max-w-prose",
|
|
372
|
-
children: /* @__PURE__ */ jsxs(VStack, { children: [/* @__PURE__ */ jsx(TextareaField, {
|
|
373
|
-
label: "Add build comment",
|
|
374
|
-
name: "body",
|
|
375
|
-
rows: 3,
|
|
376
|
-
required: true,
|
|
377
|
-
placeholder: "Leave a comment on this build…"
|
|
378
|
-
}), /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, {
|
|
379
|
-
variant: "primary",
|
|
380
|
-
type: "submit",
|
|
381
|
-
children: "Comment"
|
|
382
|
-
}) })] })
|
|
383
|
-
})
|
|
384
|
-
] })
|
|
385
|
-
})
|
|
412
|
+
children: /* @__PURE__ */ jsxs(VStack, { children: [testing && !cancelled ? /* @__PURE__ */ jsx(VerdictCard, { data: review }) : null, /* @__PURE__ */ jsx(CommentsCard, { data: review })] })
|
|
413
|
+
}) : null
|
|
386
414
|
]
|
|
387
415
|
});
|
|
388
416
|
}
|
|
389
|
-
//#endregion
|
|
390
417
|
export { renderBuildDetailPage };
|
|
391
418
|
|
|
392
419
|
//# sourceMappingURL=build-detail.mjs.map
|