@storyshelf/app 0.7.0 → 0.9.0-next-d2cc082

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.
Files changed (270) hide show
  1. package/dist/app-types.d.mts +1 -3
  2. package/dist/asset-manifest.mjs +1 -2
  3. package/dist/assets/htmx.mjs +1 -2
  4. package/dist/assets/mark.mjs +1 -2
  5. package/dist/boot-tasks.mjs +1 -2
  6. package/dist/build-state-flags.mjs +1 -2
  7. package/dist/build-state-setup.mjs +1 -2
  8. package/dist/capture-alerts.mjs +1 -2
  9. package/dist/capture-process.mjs +1 -2
  10. package/dist/capture-setup.mjs +1 -2
  11. package/dist/connections.mjs +1 -2
  12. package/dist/consumer-setup.mjs +1 -2
  13. package/dist/credential-keys.mjs +1 -2
  14. package/dist/credentials.mjs +1 -2
  15. package/dist/design-events.mjs +71 -0
  16. package/dist/design-events.mjs.map +1 -0
  17. package/dist/git-status.mjs +1 -2
  18. package/dist/hidden-data.mjs +1 -2
  19. package/dist/index.d.mts +0 -2
  20. package/dist/index.mjs +2 -3
  21. package/dist/insights/budget.mjs +1 -2
  22. package/dist/insights/deps.mjs +1 -2
  23. package/dist/insights/errors.mjs +1 -2
  24. package/dist/insights/health-panel.mjs +0 -1
  25. package/dist/insights/job.mjs +1 -2
  26. package/dist/insights/load-health.mjs +1 -2
  27. package/dist/insights/load-triage.mjs +1 -2
  28. package/dist/insights/panel.mjs +1 -2
  29. package/dist/insights/request.mjs +1 -2
  30. package/dist/insights/stale.mjs +1 -2
  31. package/dist/insights/usage-report.mjs +1 -2
  32. package/dist/insights/view.mjs +1 -2
  33. package/dist/job-canceller.mjs +1 -2
  34. package/dist/job-queue.mjs +1 -2
  35. package/dist/jobs-setup.mjs +1 -2
  36. package/dist/lifecycle.mjs +2 -3
  37. package/dist/lifecycle.mjs.map +1 -1
  38. package/dist/middleware/auth-gate.mjs +1 -2
  39. package/dist/middleware/csrf.mjs +1 -2
  40. package/dist/middleware/rate-limit.mjs +1 -2
  41. package/dist/middleware/request-log.mjs +1 -2
  42. package/dist/middleware/require-review.mjs +1 -2
  43. package/dist/middleware/require-testing.mjs +1 -2
  44. package/dist/middleware/server-timing.mjs +1 -2
  45. package/dist/middleware/setup-gate.mjs +1 -2
  46. package/dist/middleware/store-scope.mjs +1 -2
  47. package/dist/notifications-pause.mjs +1 -2
  48. package/dist/notify.d.mts +1 -3
  49. package/dist/notify.mjs +5 -3
  50. package/dist/notify.mjs.map +1 -1
  51. package/dist/pages/a11y-violations.mjs +1 -2
  52. package/dist/pages/admin-ai.mjs +1 -2
  53. package/dist/pages/admin-system-origin.mjs +19 -10
  54. package/dist/pages/admin-system-origin.mjs.map +1 -1
  55. package/dist/pages/admin-system-targets.mjs +1 -2
  56. package/dist/pages/admin-system.mjs +1 -2
  57. package/dist/pages/build-detail.mjs +1 -2
  58. package/dist/pages/build-diff-actions.mjs +1 -2
  59. package/dist/pages/build-diff-comments.mjs +1 -2
  60. package/dist/pages/build-diff-default.mjs +53 -0
  61. package/dist/pages/build-diff-default.mjs.map +1 -0
  62. package/dist/pages/build-diff-environment.mjs +34 -5
  63. package/dist/pages/build-diff-environment.mjs.map +1 -1
  64. package/dist/pages/build-diff-header.mjs +1 -2
  65. package/dist/pages/build-diff-insight.mjs +1 -2
  66. package/dist/pages/build-diff-model.mjs +20 -3
  67. package/dist/pages/build-diff-model.mjs.map +1 -1
  68. package/dist/pages/build-diff-nav.mjs +1 -2
  69. package/dist/pages/build-diff-reference.mjs +84 -0
  70. package/dist/pages/build-diff-reference.mjs.map +1 -0
  71. package/dist/pages/build-diff-shortcuts.mjs +1 -2
  72. package/dist/pages/build-diff-stale.mjs +1 -2
  73. package/dist/pages/build-diff-usage.mjs +1 -2
  74. package/dist/pages/build-diff-viewer.mjs +38 -12
  75. package/dist/pages/build-diff-viewer.mjs.map +1 -1
  76. package/dist/pages/build-diff.mjs +6 -12
  77. package/dist/pages/build-diff.mjs.map +1 -1
  78. package/dist/pages/build-tests.mjs +1 -2
  79. package/dist/pages/component-detail.mjs +1 -2
  80. package/dist/pages/component-stories.mjs +1 -2
  81. package/dist/pages/compute-jobs.mjs +1 -2
  82. package/dist/pages/design-links.mjs +1 -2
  83. package/dist/pages/environment-change.mjs +16 -4
  84. package/dist/pages/environment-change.mjs.map +1 -1
  85. package/dist/pages/health-panel.mjs +1 -2
  86. package/dist/pages/invite.mjs +1 -2
  87. package/dist/pages/label-detail.mjs +1 -2
  88. package/dist/pages/library-grid.mjs +1 -2
  89. package/dist/pages/library-model.mjs +1 -2
  90. package/dist/pages/library-snapshots.mjs +1 -2
  91. package/dist/pages/library.mjs +1 -2
  92. package/dist/pages/login.mjs +1 -2
  93. package/dist/pages/notifications-paused.mjs +1 -2
  94. package/dist/pages/passkey-ceremony.mjs +1 -2
  95. package/dist/pages/profile.mjs +1 -2
  96. package/dist/pages/project-builds-table.mjs +1 -2
  97. package/dist/pages/project-builds.mjs +1 -2
  98. package/dist/pages/project-create.mjs +1 -2
  99. package/dist/pages/project-settings.mjs +1 -2
  100. package/dist/pages/projects-card.mjs +1 -2
  101. package/dist/pages/projects.mjs +1 -2
  102. package/dist/pages/review-changeset.mjs +1 -2
  103. package/dist/pages/review-comments.mjs +1 -2
  104. package/dist/pages/review-verdict.mjs +1 -2
  105. package/dist/pages/root.mjs +1 -2
  106. package/dist/pages/settings-ai.mjs +1 -2
  107. package/dist/pages/settings-capture.mjs +1 -2
  108. package/dist/pages/settings-design-credential.mjs +1 -2
  109. package/dist/pages/settings-design-links.mjs +1 -2
  110. package/dist/pages/settings-design.mjs +1 -2
  111. package/dist/pages/settings-general.mjs +1 -2
  112. package/dist/pages/settings-labels.mjs +1 -2
  113. package/dist/pages/settings-links.mjs +1 -2
  114. package/dist/pages/settings-members.mjs +1 -2
  115. package/dist/pages/settings-notifications-git.mjs +1 -2
  116. package/dist/pages/settings-notifications.mjs +1 -2
  117. package/dist/pages/settings-tests.mjs +1 -2
  118. package/dist/pages/settings-tokens.mjs +1 -2
  119. package/dist/pages/settings-webhooks.mjs +1 -2
  120. package/dist/pages/storybook.mjs +1 -2
  121. package/dist/pages/target-choices.mjs +1 -2
  122. package/dist/publish-setup.mjs +1 -2
  123. package/dist/retention-timer.mjs +10 -11
  124. package/dist/retention-timer.mjs.map +1 -1
  125. package/dist/review-events.mjs +1 -2
  126. package/dist/routers/admin-pages.mjs +1 -2
  127. package/dist/routers/admin-public-origin.mjs +10 -3
  128. package/dist/routers/admin-public-origin.mjs.map +1 -1
  129. package/dist/routers/admin.mjs +8 -4
  130. package/dist/routers/admin.mjs.map +1 -1
  131. package/dist/routers/assets.mjs +1 -2
  132. package/dist/routers/attempts.mjs +1 -2
  133. package/dist/routers/auth-sync.mjs +1 -2
  134. package/dist/routers/auth.mjs +1 -2
  135. package/dist/routers/baseline-guard.mjs +2 -3
  136. package/dist/routers/baseline-guard.mjs.map +1 -1
  137. package/dist/routers/baseline-reference.mjs +72 -0
  138. package/dist/routers/baseline-reference.mjs.map +1 -0
  139. package/dist/routers/baselines.handlers.mjs +1 -2
  140. package/dist/routers/baselines.mjs +1 -2
  141. package/dist/routers/build-cancel.mjs +1 -2
  142. package/dist/routers/build-changeset.mjs +1 -2
  143. package/dist/routers/build-reviews.handlers.mjs +1 -2
  144. package/dist/routers/build-reviews.mjs +1 -2
  145. package/dist/routers/builds.handlers.mjs +23 -9
  146. package/dist/routers/builds.handlers.mjs.map +1 -1
  147. package/dist/routers/builds.mjs +7 -3
  148. package/dist/routers/builds.mjs.map +1 -1
  149. package/dist/routers/capture-cache.mjs +29 -0
  150. package/dist/routers/capture-cache.mjs.map +1 -0
  151. package/dist/routers/capture-config.mjs +1 -2
  152. package/dist/routers/comments.mjs +1 -2
  153. package/dist/routers/comparison-image.mjs +29 -0
  154. package/dist/routers/comparison-image.mjs.map +1 -0
  155. package/dist/routers/component-catalog.handlers.mjs +1 -2
  156. package/dist/routers/component.handlers.mjs +1 -2
  157. package/dist/routers/connections.mjs +1 -2
  158. package/dist/routers/design-connect.handlers.mjs +1 -2
  159. package/dist/routers/design.handlers.mjs +8 -2
  160. package/dist/routers/design.handlers.mjs.map +1 -1
  161. package/dist/routers/flash.mjs +1 -2
  162. package/dist/routers/health-report.mjs +1 -2
  163. package/dist/routers/health.mjs +1 -2
  164. package/dist/routers/helpers.mjs +1 -2
  165. package/dist/routers/htmx.mjs +1 -2
  166. package/dist/routers/insights-ui.mjs +1 -2
  167. package/dist/routers/insights.handlers.mjs +1 -2
  168. package/dist/routers/insights.mjs +1 -2
  169. package/dist/routers/labels.mjs +1 -2
  170. package/dist/routers/links.handlers.mjs +1 -2
  171. package/dist/routers/links.mjs +1 -2
  172. package/dist/routers/media.mjs +14 -5
  173. package/dist/routers/media.mjs.map +1 -1
  174. package/dist/routers/members.mjs +1 -2
  175. package/dist/routers/notification-channels.mjs +1 -2
  176. package/dist/routers/notification-subscriptions.mjs +1 -2
  177. package/dist/routers/oauth-state.mjs +1 -2
  178. package/dist/routers/preview-base.mjs +1 -2
  179. package/dist/routers/preview-token.mjs +1 -2
  180. package/dist/routers/profile.mjs +1 -2
  181. package/dist/routers/projects.mjs +1 -2
  182. package/dist/routers/publish-upload.mjs +19 -12
  183. package/dist/routers/publish-upload.mjs.map +1 -1
  184. package/dist/routers/published-access.mjs +1 -2
  185. package/dist/routers/published-compression.mjs +109 -0
  186. package/dist/routers/published-compression.mjs.map +1 -0
  187. package/dist/routers/published-files.mjs +26 -9
  188. package/dist/routers/published-files.mjs.map +1 -1
  189. package/dist/routers/review-forms.mjs +1 -2
  190. package/dist/routers/review-next.mjs +1 -2
  191. package/dist/routers/review-section.handlers.mjs +1 -2
  192. package/dist/routers/review-switch-off.mjs +1 -2
  193. package/dist/routers/schemas.mjs +1 -2
  194. package/dist/routers/scoped-models.mjs +1 -2
  195. package/dist/routers/settings-ai.mjs +1 -2
  196. package/dist/routers/settings-capture.mjs +1 -2
  197. package/dist/routers/settings-design.mjs +1 -2
  198. package/dist/routers/settings-general.mjs +1 -2
  199. package/dist/routers/settings-git-channel.mjs +1 -2
  200. package/dist/routers/settings-labels.mjs +1 -2
  201. package/dist/routers/settings-links.mjs +1 -2
  202. package/dist/routers/settings-members.mjs +1 -2
  203. package/dist/routers/settings-notifications.mjs +1 -2
  204. package/dist/routers/settings-tokens.mjs +1 -2
  205. package/dist/routers/settings-webhooks.mjs +1 -2
  206. package/dist/routers/settings.handlers.mjs +1 -2
  207. package/dist/routers/settings.mjs +1 -2
  208. package/dist/routers/signed-storybook.mjs +5 -3
  209. package/dist/routers/signed-storybook.mjs.map +1 -1
  210. package/dist/routers/snapshot-groups.mjs +1 -2
  211. package/dist/routers/snapshots.mjs +1 -2
  212. package/dist/routers/storybook.mjs +21 -17
  213. package/dist/routers/storybook.mjs.map +1 -1
  214. package/dist/routers/tokens.mjs +1 -2
  215. package/dist/routers/ui.mjs +4 -2
  216. package/dist/routers/ui.mjs.map +1 -1
  217. package/dist/routers/webhooks.mjs +1 -2
  218. package/dist/routers/well-known.mjs +1 -2
  219. package/dist/routes/api-routes.mjs +1 -2
  220. package/dist/routes/classification.mjs +1 -2
  221. package/dist/routes/openapi-classes.mjs +1 -2
  222. package/dist/routes/page-routes.mjs +2 -3
  223. package/dist/routes/page-routes.mjs.map +1 -1
  224. package/dist/runtime.mjs +1 -2
  225. package/dist/serverless.mjs +1 -2
  226. package/dist/store.mjs +1 -2
  227. package/dist/targets.mjs +1 -2
  228. package/dist/ui/avatar.mjs +1 -2
  229. package/dist/ui/buttons.mjs +1 -2
  230. package/dist/ui/code-block.mjs +1 -2
  231. package/dist/ui/compare-stage.mjs +86 -54
  232. package/dist/ui/compare-stage.mjs.map +1 -1
  233. package/dist/ui/csrf-field.mjs +1 -2
  234. package/dist/ui/css.mjs +1 -2
  235. package/dist/ui/design-reference.mjs +1 -2
  236. package/dist/ui/document.mjs +1 -2
  237. package/dist/ui/dropdown.mjs +1 -2
  238. package/dist/ui/feedback.mjs +1 -2
  239. package/dist/ui/filter-input.mjs +1 -2
  240. package/dist/ui/forms.mjs +1 -2
  241. package/dist/ui/icons/icon.mjs +1 -2
  242. package/dist/ui/icons/paths.mjs +1 -2
  243. package/dist/ui/icons/sprite.mjs +1 -2
  244. package/dist/ui/kbd.mjs +1 -2
  245. package/dist/ui/layout.mjs +1 -2
  246. package/dist/ui/preview-embed.mjs +1 -2
  247. package/dist/ui/progress.mjs +1 -2
  248. package/dist/ui/segmented.mjs +1 -2
  249. package/dist/ui/shell/account.mjs +1 -2
  250. package/dist/ui/shell/bare.mjs +1 -2
  251. package/dist/ui/shell/boot-script.mjs +1 -2
  252. package/dist/ui/shell/client-script.mjs +1 -2
  253. package/dist/ui/shell/nav.mjs +1 -2
  254. package/dist/ui/shell/review-script.mjs +17 -3
  255. package/dist/ui/shell/review-script.mjs.map +1 -1
  256. package/dist/ui/shell/sidebar.mjs +1 -2
  257. package/dist/ui/shell/topbar.mjs +1 -2
  258. package/dist/ui/stacks.mjs +1 -2
  259. package/dist/ui/styles/base.mjs +1 -2
  260. package/dist/ui/styles/behavior.mjs +1 -2
  261. package/dist/ui/styles/review-layout.mjs +1 -2
  262. package/dist/ui/styles/review.mjs +1 -2
  263. package/dist/ui/styles/tokens.mjs +1 -2
  264. package/dist/ui/styles.mjs +1 -2
  265. package/dist/ui/subnav.mjs +1 -2
  266. package/dist/ui/table.mjs +1 -2
  267. package/dist/ui/theme.mjs +1 -2
  268. package/dist/ui/thumbnail.mjs +1 -2
  269. package/dist/ui/time.mjs +1 -2
  270. package/package.json +9 -18
@@ -14,7 +14,7 @@ import { DiffNav } from "./build-diff-nav.mjs";
14
14
  import { ShortcutsDialog } from "./build-diff-shortcuts.mjs";
15
15
  import { DiffViewer } from "./build-diff-viewer.mjs";
16
16
  import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
17
- //#region src/pages/build-diff.tsx
17
+ // src/pages/build-diff.tsx
18
18
  /** The snapshot the review page shows: the requested one, else the first needing review. */
19
19
  function selectedSnapshot(snapshots, selectedId) {
20
20
  return snapshots.find((s) => s.id === selectedId) ?? snapshots.find((s) => s.status === "changed" || s.status === "new") ?? snapshots[0];
@@ -39,6 +39,8 @@ function DiffReviewGrid(props) {
39
39
  selected,
40
40
  siblings: groupOf(snapshots, selected.id)?.members,
41
41
  hasBaseline,
42
+ reference: props.reference,
43
+ defaultComparison: props.defaultComparison,
42
44
  drifted: drifted[selected.id],
43
45
  usage,
44
46
  design,
@@ -78,7 +80,7 @@ function reviewNav(project, build) {
78
80
  }
79
81
  /** Three-up diff review page: baseline, current, and diff with keyboard review. */
80
82
  function renderBuildDiffPage(data) {
81
- const { project, build, snapshots, comments, selectedId, canReview, hasBaseline, drifted } = data;
83
+ const { project, build, snapshots, selectedId, canReview, drifted } = data;
82
84
  const selected = selectedSnapshot(snapshots, selectedId);
83
85
  const pendingGroups = reviewProgress(snapshots).pending;
84
86
  return /* @__PURE__ */ jsxs(DocumentLayout, {
@@ -109,23 +111,15 @@ function renderBuildDiffPage(data) {
109
111
  title: "No snapshots",
110
112
  description: "This build has no snapshots yet. Capture may still be running."
111
113
  }) : /* @__PURE__ */ jsx(DiffReviewGrid, {
112
- project,
113
- build,
114
- snapshots,
115
- comments,
114
+ ...data,
116
115
  selected,
117
- canReview,
118
- hasBaseline,
119
- drifted,
120
116
  usage: data.usage ?? [],
121
- design: data.design ?? [],
122
- publishedBaseDomain: data.publishedBaseDomain
117
+ design: data.design ?? []
123
118
  }),
124
119
  /* @__PURE__ */ jsx(ShortcutsDialog, {})
125
120
  ]
126
121
  });
127
122
  }
128
- //#endregion
129
123
  export { renderBuildDiffPage, selectedSnapshot };
130
124
 
131
125
  //# sourceMappingURL=build-diff.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-diff.mjs","names":[],"sources":["../../src/pages/build-diff.tsx"],"sourcesContent":["import type { Build } from \"@storyshelf/core/schema\";\nimport type { Comment } from \"@storyshelf/core/schema\";\nimport type { Project } from \"@storyshelf/core/schema\";\nimport type { Snapshot } from \"@storyshelf/core/schema\";\nimport type { HtmlEscapedString } from \"hono/utils/html\";\nimport type { InsightPanelData } from \"../insights/panel.ts\";\nimport { EmptyState } from \"../ui/components.tsx\";\nimport { DocumentLayout, type NavConfig, type RenderedContent } from \"../ui/document.tsx\";\nimport { canvasColumn, workspace } from \"../ui/styles/review-layout.ts\";\nimport { DiffActionBar } from \"./build-diff-actions.tsx\";\nimport { DiffComments } from \"./build-diff-comments.tsx\";\nimport { ReviewNotices } from \"./build-diff-environment.tsx\";\nimport { DiffHeader } from \"./build-diff-header.tsx\";\nimport { InsightSlot } from \"./build-diff-insight.tsx\";\nimport { groupOf, reviewProgress } from \"./build-diff-model.ts\";\nimport { DiffNav } from \"./build-diff-nav.tsx\";\nimport { ShortcutsDialog } from \"./build-diff-shortcuts.tsx\";\nimport type { LinkedUsageItem } from \"./build-diff-usage.tsx\";\nimport { DiffViewer } from \"./build-diff-viewer.tsx\";\nimport type { DesignItem } from \"./design-links.tsx\";\n\n/** Data required to render the three-up build diff review page. */\nexport interface BuildDiffData {\n project: Project;\n build: Build;\n snapshots: Snapshot[];\n comments: Comment[];\n selectedId?: string;\n canReview: boolean;\n hasBaseline: Record<string, boolean>;\n /** Open snapshots whose baseline changed after their diff was computed. */\n drifted: Record<string, \"stale\" | \"removed\">;\n /** AI triage panel data; omitted/null hides the panel. */\n insight?: InsightPanelData | null;\n /** Linked packages the selected snapshot's story uses; omitted/empty hides the badges. */\n usage?: LinkedUsageItem[];\n /** Design links the selected snapshot's component resolves to; omitted/empty hides the strip. */\n design?: DesignItem[];\n /** Base domain for published Storybook deep links. */\n publishedBaseDomain?: string;\n}\n\n/* eslint-disable promise-function-async -- Hono JSX components return HtmlEscapedString | Promise<HtmlEscapedString> */\n\ninterface DiffReviewGridProps {\n project: Project;\n build: Build;\n snapshots: Snapshot[];\n comments: Comment[];\n selected?: Snapshot;\n canReview: boolean;\n hasBaseline: Record<string, boolean>;\n drifted: Record<string, \"stale\" | \"removed\">;\n usage: LinkedUsageItem[];\n design: DesignItem[];\n publishedBaseDomain?: string;\n}\n\n/** The snapshot the review page shows: the requested one, else the first needing review. */\nexport function selectedSnapshot(snapshots: Snapshot[], selectedId?: string): Snapshot | undefined {\n return (\n snapshots.find((s) => s.id === selectedId) ??\n snapshots.find((s) => s.status === \"changed\" || s.status === \"new\") ??\n snapshots[0]\n );\n}\n\n/** Snapshot nav plus the viewer/comments column for the selected snapshot. */\nfunction DiffReviewGrid(\n props: DiffReviewGridProps,\n): HtmlEscapedString | Promise<HtmlEscapedString> {\n const { project, build, snapshots, comments, selected, canReview, hasBaseline, drifted } = props;\n const { usage, design, publishedBaseDomain } = props;\n return (\n <div class={workspace}>\n <DiffNav project={project} build={build} snapshots={snapshots} selectedId={selected?.id} />\n <div class={canvasColumn}>\n {selected ? (\n <>\n <DiffViewer\n project={project}\n build={build}\n selected={selected}\n siblings={groupOf(snapshots, selected.id)?.members}\n hasBaseline={hasBaseline}\n drifted={drifted[selected.id]}\n usage={usage}\n design={design}\n publishedBaseDomain={publishedBaseDomain}\n />\n {project.reviewEnabled === false ? null : (\n <DiffComments\n project={project}\n build={build}\n selectedId={selected.id}\n selectedStoryId={selected.storyId}\n comments={comments}\n canReview={canReview}\n />\n )}\n <DiffActionBar\n project={project}\n build={build}\n snapshots={snapshots}\n selected={selected}\n canReview={canReview}\n drifted={drifted}\n />\n </>\n ) : (\n <EmptyState description=\"Select a snapshot to review.\" />\n )}\n </div>\n </div>\n );\n}\n\n/** Sidebar/breadcrumb context for the review page: Builds / <build> / Review. */\nfunction reviewNav(project: Project, build: Build): NavConfig {\n return {\n active: \"builds\",\n projectSlug: project.slug,\n projectName: project.name,\n trail: [\n {\n label: `${build.gitBranch} · ${build.gitSha.slice(0, 7)}`,\n href: `/projects/${project.slug}/builds/${build.id}`,\n },\n { label: \"Review\" },\n ],\n };\n}\n\n/** Three-up diff review page: baseline, current, and diff with keyboard review. */\nexport function renderBuildDiffPage(data: BuildDiffData): RenderedContent {\n const { project, build, snapshots, comments, selectedId, canReview, hasBaseline, drifted } = data;\n const selected = selectedSnapshot(snapshots, selectedId);\n const pendingGroups = reviewProgress(snapshots).pending;\n\n return (\n <DocumentLayout\n title={`Review · ${build.gitBranch}`}\n nav={reviewNav(project, build)}\n layout=\"wide\"\n >\n <DiffHeader\n project={project}\n build={build}\n snapshots={snapshots}\n pendingCount={pendingGroups}\n canReview={canReview}\n />\n <ReviewNotices\n project={project}\n build={build}\n snapshots={snapshots}\n drifted={drifted}\n canReview={canReview}\n />\n <InsightSlot project={project} build={build} data={data.insight} />\n\n {snapshots.length === 0 ? (\n <EmptyState\n title=\"No snapshots\"\n description=\"This build has no snapshots yet. Capture may still be running.\"\n />\n ) : (\n <DiffReviewGrid\n project={project}\n build={build}\n snapshots={snapshots}\n comments={comments}\n selected={selected}\n canReview={canReview}\n hasBaseline={hasBaseline}\n drifted={drifted}\n usage={data.usage ?? []}\n design={data.design ?? []}\n publishedBaseDomain={data.publishedBaseDomain}\n />\n )}\n <ShortcutsDialog />\n </DocumentLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA2DA,SAAgB,iBAAiB,WAAuB,YAA2C;CACjG,OACE,UAAU,MAAM,MAAM,EAAE,OAAO,UAAU,KACzC,UAAU,MAAM,MAAM,EAAE,WAAW,aAAa,EAAE,WAAW,KAAK,KAClE,UAAU;AAEd;;AAGA,SAAS,eACP,OACgD;CAChD,MAAM,EAAE,SAAS,OAAO,WAAW,UAAU,UAAU,WAAW,aAAa,YAAY;CAC3F,MAAM,EAAE,OAAO,QAAQ,wBAAwB;CAC/C,OACE,qBAAC,OAAD;EAAK,OAAO;EAAZ,UAAA,CACE,oBAAC,SAAD;GAAkB;GAAgB;GAAkB;GAAW,YAAY,UAAU;EAAK,CAAA,GAC1F,oBAAC,OAAD;GAAK,OAAO;GACT,UAAA,WACC,qBAAA,UAAA,EAAA,UAAA;IACE,oBAAC,YAAD;KACW;KACF;KACG;KACV,UAAU,QAAQ,WAAW,SAAS,EAAE,CAAC,EAAE;KAC9B;KACb,SAAS,QAAQ,SAAS;KACnB;KACC;KACa;IACtB,CAAA;IACA,QAAQ,kBAAkB,QAAQ,OACjC,oBAAC,cAAD;KACW;KACF;KACP,YAAY,SAAS;KACrB,iBAAiB,SAAS;KAChB;KACC;IACZ,CAAA;IAEH,oBAAC,eAAD;KACW;KACF;KACI;KACD;KACC;KACF;IACV,CAAA;GACD,EAAA,CAAA,IAEF,oBAAC,YAAD,EAAY,aAAY,+BAAgC,CAAA;EAEvD,CAAA,CACF;;AAET;;AAGA,SAAS,UAAU,SAAkB,OAAyB;CAC5D,OAAO;EACL,QAAQ;EACR,aAAa,QAAQ;EACrB,aAAa,QAAQ;EACrB,OAAO,CACL;GACE,OAAO,GAAG,MAAM,UAAU,KAAK,MAAM,OAAO,MAAM,GAAG,CAAC;GACtD,MAAM,aAAa,QAAQ,KAAK,UAAU,MAAM;EAClD,GACA,EAAE,OAAO,SAAS,CACpB;CACF;AACF;;AAGA,SAAgB,oBAAoB,MAAsC;CACxE,MAAM,EAAE,SAAS,OAAO,WAAW,UAAU,YAAY,WAAW,aAAa,YAAY;CAC7F,MAAM,WAAW,iBAAiB,WAAW,UAAU;CACvD,MAAM,gBAAgB,eAAe,SAAS,CAAC,CAAC;CAEhD,OACE,qBAAC,gBAAD;EACE,OAAO,YAAY,MAAM;EACzB,KAAK,UAAU,SAAS,KAAK;EAC7B,QAAO;EAHT,UAAA;GAKE,oBAAC,YAAD;IACW;IACF;IACI;IACX,cAAc;IACH;GACZ,CAAA;GACD,oBAAC,eAAD;IACW;IACF;IACI;IACF;IACE;GACZ,CAAA;GACD,oBAAC,aAAD;IAAsB;IAAgB;IAAO,MAAM,KAAK;GAAU,CAAA;GAEjE,UAAU,WAAW,IACpB,oBAAC,YAAD;IACE,OAAM;IACN,aAAY;GACb,CAAA,IAED,oBAAC,gBAAD;IACW;IACF;IACI;IACD;IACA;IACC;IACE;IACJ;IACT,OAAO,KAAK,SAAS,CAAC;IACtB,QAAQ,KAAK,UAAU,CAAC;IACxB,qBAAqB,KAAK;GAC3B,CAAA;GAEH,oBAAC,iBAAD,CAAkB,CAAA;EACJ;;AAEpB"}
1
+ {"version":3,"file":"build-diff.mjs","names":[],"sources":["../../src/pages/build-diff.tsx"],"sourcesContent":["import type { Build } from \"@storyshelf/core/schema\";\nimport type { Comment } from \"@storyshelf/core/schema\";\nimport type { Project } from \"@storyshelf/core/schema\";\nimport type { Snapshot } from \"@storyshelf/core/schema\";\nimport type { HtmlEscapedString } from \"hono/utils/html\";\nimport type { InsightPanelData } from \"../insights/panel.ts\";\nimport type { BaselineReference, DefaultComparison } from \"../routers/baseline-reference.ts\";\nimport { EmptyState } from \"../ui/components.tsx\";\nimport { DocumentLayout, type NavConfig, type RenderedContent } from \"../ui/document.tsx\";\nimport { canvasColumn, workspace } from \"../ui/styles/review-layout.ts\";\nimport { DiffActionBar } from \"./build-diff-actions.tsx\";\nimport { DiffComments } from \"./build-diff-comments.tsx\";\nimport { ReviewNotices } from \"./build-diff-environment.tsx\";\nimport { DiffHeader } from \"./build-diff-header.tsx\";\nimport { InsightSlot } from \"./build-diff-insight.tsx\";\nimport { groupOf, reviewProgress } from \"./build-diff-model.ts\";\nimport { DiffNav } from \"./build-diff-nav.tsx\";\nimport { ShortcutsDialog } from \"./build-diff-shortcuts.tsx\";\nimport type { LinkedUsageItem } from \"./build-diff-usage.tsx\";\nimport { DiffViewer } from \"./build-diff-viewer.tsx\";\nimport type { DesignItem } from \"./design-links.tsx\";\n\n/** Data required to render the three-up build diff review page. */\nexport interface BuildDiffData {\n project: Project;\n build: Build;\n snapshots: Snapshot[];\n comments: Comment[];\n selectedId?: string;\n canReview: boolean;\n hasBaseline: Record<string, boolean>;\n reference?: BaselineReference;\n defaultComparison?: DefaultComparison | null;\n /** Open snapshots whose baseline changed after their diff was computed. */\n drifted: Record<string, \"stale\" | \"removed\">;\n /** AI triage panel data; omitted/null hides the panel. */\n insight?: InsightPanelData | null;\n /** Linked packages the selected snapshot's story uses; omitted/empty hides the badges. */\n usage?: LinkedUsageItem[];\n /** Design links the selected snapshot's component resolves to; omitted/empty hides the strip. */\n design?: DesignItem[];\n /** Base domain for published Storybook deep links. */\n publishedBaseDomain?: string;\n}\n\n/* eslint-disable promise-function-async -- Hono JSX components return HtmlEscapedString | Promise<HtmlEscapedString> */\n\ninterface DiffReviewGridProps {\n project: Project;\n build: Build;\n snapshots: Snapshot[];\n comments: Comment[];\n selected?: Snapshot;\n canReview: boolean;\n hasBaseline: Record<string, boolean>;\n reference?: BaselineReference;\n defaultComparison?: DefaultComparison | null;\n drifted: Record<string, \"stale\" | \"removed\">;\n usage: LinkedUsageItem[];\n design: DesignItem[];\n publishedBaseDomain?: string;\n}\n\n/** The snapshot the review page shows: the requested one, else the first needing review. */\nexport function selectedSnapshot(snapshots: Snapshot[], selectedId?: string): Snapshot | undefined {\n return (\n snapshots.find((s) => s.id === selectedId) ??\n snapshots.find((s) => s.status === \"changed\" || s.status === \"new\") ??\n snapshots[0]\n );\n}\n\n/** Snapshot nav plus the viewer/comments column for the selected snapshot. */\nfunction DiffReviewGrid(\n props: DiffReviewGridProps,\n): HtmlEscapedString | Promise<HtmlEscapedString> {\n const { project, build, snapshots, comments, selected, canReview, hasBaseline, drifted } = props;\n const { usage, design, publishedBaseDomain } = props;\n return (\n <div class={workspace}>\n <DiffNav project={project} build={build} snapshots={snapshots} selectedId={selected?.id} />\n <div class={canvasColumn}>\n {selected ? (\n <>\n <DiffViewer\n project={project}\n build={build}\n selected={selected}\n siblings={groupOf(snapshots, selected.id)?.members}\n hasBaseline={hasBaseline}\n reference={props.reference}\n defaultComparison={props.defaultComparison}\n drifted={drifted[selected.id]}\n usage={usage}\n design={design}\n publishedBaseDomain={publishedBaseDomain}\n />\n {project.reviewEnabled === false ? null : (\n <DiffComments\n project={project}\n build={build}\n selectedId={selected.id}\n selectedStoryId={selected.storyId}\n comments={comments}\n canReview={canReview}\n />\n )}\n <DiffActionBar\n project={project}\n build={build}\n snapshots={snapshots}\n selected={selected}\n canReview={canReview}\n drifted={drifted}\n />\n </>\n ) : (\n <EmptyState description=\"Select a snapshot to review.\" />\n )}\n </div>\n </div>\n );\n}\n\n/** Sidebar/breadcrumb context for the review page: Builds / <build> / Review. */\nfunction reviewNav(project: Project, build: Build): NavConfig {\n return {\n active: \"builds\",\n projectSlug: project.slug,\n projectName: project.name,\n trail: [\n {\n label: `${build.gitBranch} · ${build.gitSha.slice(0, 7)}`,\n href: `/projects/${project.slug}/builds/${build.id}`,\n },\n { label: \"Review\" },\n ],\n };\n}\n\n/** Three-up diff review page: baseline, current, and diff with keyboard review. */\nexport function renderBuildDiffPage(data: BuildDiffData): RenderedContent {\n const { project, build, snapshots, selectedId, canReview, drifted } = data;\n const selected = selectedSnapshot(snapshots, selectedId);\n const pendingGroups = reviewProgress(snapshots).pending;\n return (\n <DocumentLayout\n title={`Review · ${build.gitBranch}`}\n nav={reviewNav(project, build)}\n layout=\"wide\"\n >\n <DiffHeader\n project={project}\n build={build}\n snapshots={snapshots}\n pendingCount={pendingGroups}\n canReview={canReview}\n />\n <ReviewNotices\n project={project}\n build={build}\n snapshots={snapshots}\n drifted={drifted}\n canReview={canReview}\n />\n <InsightSlot project={project} build={build} data={data.insight} />\n {snapshots.length === 0 ? (\n <EmptyState\n title=\"No snapshots\"\n description=\"This build has no snapshots yet. Capture may still be running.\"\n />\n ) : (\n <DiffReviewGrid\n {...data}\n selected={selected}\n usage={data.usage ?? []}\n design={data.design ?? []}\n />\n )}\n <ShortcutsDialog />\n </DocumentLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAgEA,SAAgB,iBAAiB,WAAuB,YAA2C;CACjG,OACE,UAAU,MAAM,MAAM,EAAE,OAAO,UAAU,KACzC,UAAU,MAAM,MAAM,EAAE,WAAW,aAAa,EAAE,WAAW,KAAK,KAClE,UAAU;AAEd;;AAGA,SAAS,eACP,OACgD;CAChD,MAAM,EAAE,SAAS,OAAO,WAAW,UAAU,UAAU,WAAW,aAAa,YAAY;CAC3F,MAAM,EAAE,OAAO,QAAQ,wBAAwB;CAC/C,OACE,qBAAC,OAAD;EAAK,OAAO;EAAZ,UAAA,CACE,oBAAC,SAAD;GAAkB;GAAgB;GAAkB;GAAW,YAAY,UAAU;EAAK,CAAA,GAC1F,oBAAC,OAAD;GAAK,OAAO;GACT,UAAA,WACC,qBAAA,UAAA,EAAA,UAAA;IACE,oBAAC,YAAD;KACW;KACF;KACG;KACV,UAAU,QAAQ,WAAW,SAAS,EAAE,CAAC,EAAE;KAC9B;KACb,WAAW,MAAM;KACjB,mBAAmB,MAAM;KACzB,SAAS,QAAQ,SAAS;KACnB;KACC;KACa;IACtB,CAAA;IACA,QAAQ,kBAAkB,QAAQ,OACjC,oBAAC,cAAD;KACW;KACF;KACP,YAAY,SAAS;KACrB,iBAAiB,SAAS;KAChB;KACC;IACZ,CAAA;IAEH,oBAAC,eAAD;KACW;KACF;KACI;KACD;KACC;KACF;IACV,CAAA;GACD,EAAA,CAAA,IAEF,oBAAC,YAAD,EAAY,aAAY,+BAAgC,CAAA;EAEvD,CAAA,CACF;;AAET;;AAGA,SAAS,UAAU,SAAkB,OAAyB;CAC5D,OAAO;EACL,QAAQ;EACR,aAAa,QAAQ;EACrB,aAAa,QAAQ;EACrB,OAAO,CACL;GACE,OAAO,GAAG,MAAM,UAAU,KAAK,MAAM,OAAO,MAAM,GAAG,CAAC;GACtD,MAAM,aAAa,QAAQ,KAAK,UAAU,MAAM;EAClD,GACA,EAAE,OAAO,SAAS,CACpB;CACF;AACF;;AAGA,SAAgB,oBAAoB,MAAsC;CACxE,MAAM,EAAE,SAAS,OAAO,WAAW,YAAY,WAAW,YAAY;CACtE,MAAM,WAAW,iBAAiB,WAAW,UAAU;CACvD,MAAM,gBAAgB,eAAe,SAAS,CAAC,CAAC;CAChD,OACE,qBAAC,gBAAD;EACE,OAAO,YAAY,MAAM;EACzB,KAAK,UAAU,SAAS,KAAK;EAC7B,QAAO;EAHT,UAAA;GAKE,oBAAC,YAAD;IACW;IACF;IACI;IACX,cAAc;IACH;GACZ,CAAA;GACD,oBAAC,eAAD;IACW;IACF;IACI;IACF;IACE;GACZ,CAAA;GACD,oBAAC,aAAD;IAAsB;IAAgB;IAAO,MAAM,KAAK;GAAU,CAAA;GACjE,UAAU,WAAW,IACpB,oBAAC,YAAD;IACE,OAAM;IACN,aAAY;GACb,CAAA,IAED,oBAAC,gBAAD;IACE,GAAI;IACM;IACV,OAAO,KAAK,SAAS,CAAC;IACtB,QAAQ,KAAK,UAAU,CAAC;GACzB,CAAA;GAEH,oBAAC,iBAAD,CAAkB,CAAA;EACJ;;AAEpB"}
@@ -6,7 +6,7 @@ import { Card, SectionTitle } from "../ui/layout.mjs";
6
6
  import { HStack, VStack } from "../ui/stacks.mjs";
7
7
  import { summarizeTests } from "@storyshelf/core/capture";
8
8
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
9
- //#region src/pages/build-tests.tsx
9
+ // src/pages/build-tests.tsx
10
10
  /** The line under the card title: counts, and what a failure means for the build. */
11
11
  function testsSummaryNote(results) {
12
12
  const { total, passed, failed } = summarizeTests(results);
@@ -68,7 +68,6 @@ function TestRow(props) {
68
68
  }) : null]
69
69
  });
70
70
  }
71
- //#endregion
72
71
  export { TestsCard, testsSummaryNote };
73
72
 
74
73
  //# sourceMappingURL=build-tests.mjs.map
@@ -16,7 +16,7 @@ import { ComponentBuilds, StoriesTab } from "./component-stories.mjs";
16
16
  import { worstStatus } from "@storyshelf/core/models";
17
17
  import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
18
18
  import { createUrlBuilder } from "@storyshelf/core/urls";
19
- //#region src/pages/component-detail.tsx
19
+ // src/pages/component-detail.tsx
20
20
  const TAB_LABELS = {
21
21
  stories: "Stories",
22
22
  states: "States",
@@ -243,7 +243,6 @@ function LinkedTab(props) {
243
243
  publishedBaseDomain: data.publishedBaseDomain
244
244
  })] });
245
245
  }
246
- //#endregion
247
246
  export { componentTabs, renderComponentPage };
248
247
 
249
248
  //# sourceMappingURL=component-detail.mjs.map
@@ -11,7 +11,7 @@ import { PREVIEW_TOKEN_REFRESH, isSignedPreviewBase } from "../routers/preview-b
11
11
  import { StoryComments } from "./review-comments.mjs";
12
12
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
13
13
  import { createUrlBuilder } from "@storyshelf/core/urls";
14
- //#region src/pages/component-stories.tsx
14
+ // src/pages/component-stories.tsx
15
15
  /** Stories tab: the selected story in a sandboxed preview, and every story and docs entry. */
16
16
  function StoriesTab(props) {
17
17
  const { data } = props;
@@ -162,7 +162,6 @@ function changeParts(row) {
162
162
  function storybookBase(data) {
163
163
  return createUrlBuilder("/", data.publishedBaseDomain).storybookBuild(data.project.slug, data.catalog.build.id);
164
164
  }
165
- //#endregion
166
165
  export { ComponentBuilds, StoriesTab };
167
166
 
168
167
  //# sourceMappingURL=component-stories.mjs.map
@@ -10,7 +10,7 @@ import { Table } from "../ui/table.mjs";
10
10
  import { DocumentLayout } from "../ui/document.mjs";
11
11
  import { BuildModel, ProjectModel } from "@storyshelf/core/models";
12
12
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
13
- //#region src/pages/compute-jobs.tsx
13
+ // src/pages/compute-jobs.tsx
14
14
  /** Build statuses the retry button of the jobs table offers. */
15
15
  const RETRYABLE = /* @__PURE__ */ new Set([
16
16
  "failed",
@@ -146,7 +146,6 @@ async function renderComputeJobsPage(slug, queueView, canRetry) {
146
146
  ]
147
147
  });
148
148
  }
149
- //#endregion
150
149
  export { renderActiveQueue, renderComputeJobsPage };
151
150
 
152
151
  //# sourceMappingURL=compute-jobs.mjs.map
@@ -8,7 +8,7 @@ import { Dropdown, DropdownItem } from "../ui/dropdown.mjs";
8
8
  import { DesignPreview, DesignReference } from "../ui/design-reference.mjs";
9
9
  import { csrfField } from "../ui/csrf-field.mjs";
10
10
  import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
11
- //#region src/pages/design-links.tsx
11
+ // src/pages/design-links.tsx
12
12
  /**
13
13
  * Design actions for a component's link(s). A link with a cached render opens a
14
14
  * click popover (preview + `Open in <provider>`); others are plain deep links.
@@ -176,7 +176,6 @@ function ProjectDesignLinks(props) {
176
176
  children: link.label
177
177
  }, link.url)) });
178
178
  }
179
- //#endregion
180
179
  export { DesignButtons, DesignReferences, DesignStrip, ProjectDesignLinks };
181
180
 
182
181
  //# sourceMappingURL=design-links.mjs.map
@@ -1,7 +1,7 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
- //#region src/pages/environment-change.ts
4
+ // src/pages/environment-change.ts
5
5
  /** What changed, in words a reviewer recognises. */
6
6
  const FIELD_LABELS = {
7
7
  engine: "browser engine",
@@ -25,7 +25,7 @@ function environmentChangeOf(snapshot) {
25
25
  }
26
26
  /** Summarise the build's environment migrations, or null when there were none. */
27
27
  function summariseEnvironmentChanges(snapshots) {
28
- const changes = snapshots.map((snapshot) => environmentChangeOf(snapshot)).filter((change) => change !== null);
28
+ const changes = snapshots.map((snapshot) => environmentChangeOf(snapshot)).filter((change) => change !== null && change.changed.length > 0);
29
29
  if (changes.length === 0) return null;
30
30
  const fields = [...new Set(changes.flatMap((change) => change.changed))].map((field) => labelOf(field));
31
31
  return {
@@ -34,6 +34,19 @@ function summariseEnvironmentChanges(snapshots) {
34
34
  ...browserVersionOf(changes)
35
35
  };
36
36
  }
37
+ /**
38
+ * Summarise the snapshots whose baseline was measured under another measurement version, so some
39
+ * components were compared as unknown (never as a change); null when there were none.
40
+ */
41
+ function summarisePartlyUnknown(snapshots) {
42
+ const unknown = snapshots.map((snapshot) => environmentChangeOf(snapshot)?.unknown ?? []).filter((fields) => fields.length > 0);
43
+ if (unknown.length === 0) return null;
44
+ const fields = [...new Set(unknown.flat())].map((field) => labelOf(field));
45
+ return {
46
+ count: unknown.length,
47
+ fields
48
+ };
49
+ }
37
50
  /** Human label for a changed component. */
38
51
  function labelOf(field) {
39
52
  return FIELD_LABELS[field] ?? field;
@@ -47,7 +60,6 @@ function browserVersionOf(changes) {
47
60
  to
48
61
  } } : {};
49
62
  }
50
- //#endregion
51
- export { environmentChangeOf, labelOf, summariseEnvironmentChanges };
63
+ export { environmentChangeOf, labelOf, summariseEnvironmentChanges, summarisePartlyUnknown };
52
64
 
53
65
  //# sourceMappingURL=environment-change.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"environment-change.mjs","names":[],"sources":["../../src/pages/environment-change.ts"],"sourcesContent":["/** Reads the capture-environment migrations recorded on a build's snapshots. */\nimport type { EnvironmentChange } from \"@storyshelf/core/capture\";\nimport type { Snapshot } from \"@storyshelf/core/schema\";\n\n/** What changed, in words a reviewer recognises. */\nconst FIELD_LABELS: Record<string, string> = {\n engine: \"browser engine\",\n browserVersion: \"browser version\",\n platform: \"host platform\",\n deviceScaleFactor: \"device scale factor\",\n fontsHash: \"installed fonts\",\n viewport: \"viewport size\",\n sizing: \"screenshot sizing\",\n unknown: \"capture environment\",\n};\n\n/** A snapshot's recorded change; null when it has none or the stored value is unreadable. */\nexport function environmentChangeOf(\n snapshot: Pick<Snapshot, \"envChange\">,\n): EnvironmentChange | null {\n if (!snapshot.envChange) {\n return null;\n }\n try {\n const value = JSON.parse(snapshot.envChange) as Partial<EnvironmentChange>;\n return Array.isArray(value.changed) && value.to ? (value as EnvironmentChange) : null;\n } catch {\n return null;\n }\n}\n\n/** Summary across a build's snapshots. */\nexport interface EnvironmentChangeSummary {\n /** Snapshots accepted as a migration. */\n count: number;\n /** Distinct labels of what changed, in first-seen order. */\n fields: string[];\n /** `from -> to` for the browser version when every migrated snapshot agrees on it. */\n browserVersion?: { from: string; to: string };\n}\n\n/** Summarise the build's environment migrations, or null when there were none. */\nexport function summariseEnvironmentChanges(\n snapshots: readonly Pick<Snapshot, \"envChange\">[],\n): EnvironmentChangeSummary | null {\n const changes = snapshots\n .map((snapshot) => environmentChangeOf(snapshot))\n .filter((change): change is EnvironmentChange => change !== null);\n if (changes.length === 0) {\n return null;\n }\n const fields = [...new Set(changes.flatMap((change) => change.changed))].map((field) =>\n labelOf(field),\n );\n return { count: changes.length, fields, ...browserVersionOf(changes) };\n}\n\n/** Human label for a changed component. */\nexport function labelOf(field: string): string {\n return FIELD_LABELS[field] ?? field;\n}\n\nfunction browserVersionOf(\n changes: EnvironmentChange[],\n): Pick<EnvironmentChangeSummary, \"browserVersion\"> {\n const pairs = new Set(\n changes.map(\n (change) => `${change.from?.browserVersion ?? \"\"}\\u0000${change.to.browserVersion ?? \"\"}`,\n ),\n );\n if (pairs.size !== 1) {\n return {};\n }\n const [from, to] = [...pairs][0]?.split(\"\\u0000\") ?? [];\n return from && to && from !== to ? { browserVersion: { from, to } } : {};\n}\n"],"mappings":";;;;;AAKA,MAAM,eAAuC;CAC3C,QAAQ;CACR,gBAAgB;CAChB,UAAU;CACV,mBAAmB;CACnB,WAAW;CACX,UAAU;CACV,QAAQ;CACR,SAAS;AACX;;AAGA,SAAgB,oBACd,UAC0B;CAC1B,IAAI,CAAC,SAAS,WACZ,OAAO;CAET,IAAI;EACF,MAAM,QAAQ,KAAK,MAAM,SAAS,SAAS;EAC3C,OAAO,MAAM,QAAQ,MAAM,OAAO,KAAK,MAAM,KAAM,QAA8B;CACnF,QAAQ;EACN,OAAO;CACT;AACF;;AAaA,SAAgB,4BACd,WACiC;CACjC,MAAM,UAAU,UACb,KAAK,aAAa,oBAAoB,QAAQ,CAAC,CAAC,CAChD,QAAQ,WAAwC,WAAW,IAAI;CAClE,IAAI,QAAQ,WAAW,GACrB,OAAO;CAET,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,QAAQ,SAAS,WAAW,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,UAC5E,QAAQ,KAAK,CACf;CACA,OAAO;EAAE,OAAO,QAAQ;EAAQ;EAAQ,GAAG,iBAAiB,OAAO;CAAE;AACvE;;AAGA,SAAgB,QAAQ,OAAuB;CAC7C,OAAO,aAAa,UAAU;AAChC;AAEA,SAAS,iBACP,SACkD;CAClD,MAAM,QAAQ,IAAI,IAChB,QAAQ,KACL,WAAW,GAAG,OAAO,MAAM,kBAAkB,GAAG,QAAQ,OAAO,GAAG,kBAAkB,IACvF,CACF;CACA,IAAI,MAAM,SAAS,GACjB,OAAO,CAAC;CAEV,MAAM,CAAC,MAAM,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,EAAE,MAAM,IAAQ,KAAK,CAAC;CACtD,OAAO,QAAQ,MAAM,SAAS,KAAK,EAAE,gBAAgB;EAAE;EAAM;CAAG,EAAE,IAAI,CAAC;AACzE"}
1
+ {"version":3,"file":"environment-change.mjs","names":[],"sources":["../../src/pages/environment-change.ts"],"sourcesContent":["/** Reads the capture-environment migrations recorded on a build's snapshots. */\nimport type { EnvironmentChange } from \"@storyshelf/core/capture\";\nimport type { Snapshot } from \"@storyshelf/core/schema\";\n\n/** What changed, in words a reviewer recognises. */\nconst FIELD_LABELS: Record<string, string> = {\n engine: \"browser engine\",\n browserVersion: \"browser version\",\n platform: \"host platform\",\n deviceScaleFactor: \"device scale factor\",\n fontsHash: \"installed fonts\",\n viewport: \"viewport size\",\n sizing: \"screenshot sizing\",\n unknown: \"capture environment\",\n};\n\n/** A snapshot's recorded change; null when it has none or the stored value is unreadable. */\nexport function environmentChangeOf(\n snapshot: Pick<Snapshot, \"envChange\">,\n): EnvironmentChange | null {\n if (!snapshot.envChange) {\n return null;\n }\n try {\n const value = JSON.parse(snapshot.envChange) as Partial<EnvironmentChange>;\n return Array.isArray(value.changed) && value.to ? (value as EnvironmentChange) : null;\n } catch {\n return null;\n }\n}\n\n/** Summary across a build's snapshots. */\nexport interface EnvironmentChangeSummary {\n /** Snapshots accepted as a migration. */\n count: number;\n /** Distinct labels of what changed, in first-seen order. */\n fields: string[];\n /** `from -> to` for the browser version when every migrated snapshot agrees on it. */\n browserVersion?: { from: string; to: string };\n}\n\n/** Summarise the build's environment migrations, or null when there were none. */\nexport function summariseEnvironmentChanges(\n snapshots: readonly Pick<Snapshot, \"envChange\">[],\n): EnvironmentChangeSummary | null {\n const changes = snapshots\n .map((snapshot) => environmentChangeOf(snapshot))\n .filter((change): change is EnvironmentChange => change !== null && change.changed.length > 0);\n if (changes.length === 0) {\n return null;\n }\n const fields = [...new Set(changes.flatMap((change) => change.changed))].map((field) =>\n labelOf(field),\n );\n return { count: changes.length, fields, ...browserVersionOf(changes) };\n}\n\n/** Snapshots compared with a baseline measured another way, and the components that could not be compared. */\nexport interface PartlyUnknownSummary {\n count: number;\n fields: string[];\n}\n\n/**\n * Summarise the snapshots whose baseline was measured under another measurement version, so some\n * components were compared as unknown (never as a change); null when there were none.\n */\nexport function summarisePartlyUnknown(\n snapshots: readonly Pick<Snapshot, \"envChange\">[],\n): PartlyUnknownSummary | null {\n const unknown = snapshots\n .map((snapshot) => environmentChangeOf(snapshot)?.unknown ?? [])\n .filter((fields) => fields.length > 0);\n if (unknown.length === 0) {\n return null;\n }\n const fields = [...new Set(unknown.flat())].map((field) => labelOf(field));\n return { count: unknown.length, fields };\n}\n\n/** Human label for a changed component. */\nexport function labelOf(field: string): string {\n return FIELD_LABELS[field] ?? field;\n}\n\nfunction browserVersionOf(\n changes: EnvironmentChange[],\n): Pick<EnvironmentChangeSummary, \"browserVersion\"> {\n const pairs = new Set(\n changes.map(\n (change) => `${change.from?.browserVersion ?? \"\"}\\u0000${change.to.browserVersion ?? \"\"}`,\n ),\n );\n if (pairs.size !== 1) {\n return {};\n }\n const [from, to] = [...pairs][0]?.split(\"\\u0000\") ?? [];\n return from && to && from !== to ? { browserVersion: { from, to } } : {};\n}\n"],"mappings":";;;;;AAKA,MAAM,eAAuC;CAC3C,QAAQ;CACR,gBAAgB;CAChB,UAAU;CACV,mBAAmB;CACnB,WAAW;CACX,UAAU;CACV,QAAQ;CACR,SAAS;AACX;;AAGA,SAAgB,oBACd,UAC0B;CAC1B,IAAI,CAAC,SAAS,WACZ,OAAO;CAET,IAAI;EACF,MAAM,QAAQ,KAAK,MAAM,SAAS,SAAS;EAC3C,OAAO,MAAM,QAAQ,MAAM,OAAO,KAAK,MAAM,KAAM,QAA8B;CACnF,QAAQ;EACN,OAAO;CACT;AACF;;AAaA,SAAgB,4BACd,WACiC;CACjC,MAAM,UAAU,UACb,KAAK,aAAa,oBAAoB,QAAQ,CAAC,CAAC,CAChD,QAAQ,WAAwC,WAAW,QAAQ,OAAO,QAAQ,SAAS,CAAC;CAC/F,IAAI,QAAQ,WAAW,GACrB,OAAO;CAET,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,QAAQ,SAAS,WAAW,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,UAC5E,QAAQ,KAAK,CACf;CACA,OAAO;EAAE,OAAO,QAAQ;EAAQ;EAAQ,GAAG,iBAAiB,OAAO;CAAE;AACvE;;;;;AAYA,SAAgB,uBACd,WAC6B;CAC7B,MAAM,UAAU,UACb,KAAK,aAAa,oBAAoB,QAAQ,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAC/D,QAAQ,WAAW,OAAO,SAAS,CAAC;CACvC,IAAI,QAAQ,WAAW,GACrB,OAAO;CAET,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,QAAQ,KAAK,CAAC;CACzE,OAAO;EAAE,OAAO,QAAQ;EAAQ;CAAO;AACzC;;AAGA,SAAgB,QAAQ,OAAuB;CAC7C,OAAO,aAAa,UAAU;AAChC;AAEA,SAAS,iBACP,SACkD;CAClD,MAAM,QAAQ,IAAI,IAChB,QAAQ,KACL,WAAW,GAAG,OAAO,MAAM,kBAAkB,GAAG,QAAQ,OAAO,GAAG,kBAAkB,IACvF,CACF;CACA,IAAI,MAAM,SAAS,GACjB,OAAO,CAAC;CAEV,MAAM,CAAC,MAAM,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,EAAE,MAAM,IAAQ,KAAK,CAAC;CACtD,OAAO,QAAQ,MAAM,SAAS,KAAK,EAAE,gBAAgB;EAAE;EAAM;CAAG,EAAE,IAAI,CAAC;AACzE"}
@@ -7,7 +7,7 @@ import { Card, SectionTitle } from "../ui/layout.mjs";
7
7
  import { HStack, VStack } from "../ui/stacks.mjs";
8
8
  import { csrfField } from "../ui/csrf-field.mjs";
9
9
  import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
10
- //#region src/pages/health-panel.tsx
10
+ // src/pages/health-panel.tsx
11
11
  /** Badge tone for a health verdict. */
12
12
  function healthTone(verdict) {
13
13
  if (verdict === "healthy") return "success";
@@ -120,7 +120,6 @@ function HealthSlot(props) {
120
120
  data: props.data
121
121
  }) : null;
122
122
  }
123
- //#endregion
124
123
  export { HealthPanel, HealthSlot, healthTone };
125
124
 
126
125
  //# sourceMappingURL=health-panel.mjs.map
@@ -9,7 +9,7 @@ import { VStack } from "../ui/stacks.mjs";
9
9
  import { csrfField } from "../ui/csrf-field.mjs";
10
10
  import { DocumentLayout } from "../ui/document.mjs";
11
11
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
12
- //#region src/pages/invite.tsx
12
+ // src/pages/invite.tsx
13
13
  /** Set-password page for invite acceptance (no auth required). */
14
14
  function renderInvitePage(state) {
15
15
  return /* @__PURE__ */ jsx(DocumentLayout, {
@@ -85,7 +85,6 @@ function renderInviteInvalidPage(error) {
85
85
  }) })
86
86
  });
87
87
  }
88
- //#endregion
89
88
  export { renderInviteInvalidPage, renderInvitePage };
90
89
 
91
90
  //# sourceMappingURL=invite.mjs.map
@@ -10,7 +10,7 @@ import { Table } from "../ui/table.mjs";
10
10
  import { DocumentLayout } from "../ui/document.mjs";
11
11
  import { BuildModel, LabelModel, ProjectModel } from "@storyshelf/core/models";
12
12
  import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
13
- //#region src/pages/label-detail.tsx
13
+ // src/pages/label-detail.tsx
14
14
  /** Resolve a label type's `link_template` against a build, or return null. */
15
15
  function resolveLabelLink(template, project, build, value) {
16
16
  if (!template) return null;
@@ -148,7 +148,6 @@ async function renderLabelsPage(slug) {
148
148
  ] }, labelType.id)) })] }) })]
149
149
  });
150
150
  }
151
- //#endregion
152
151
  export { renderLabelDetailPage, renderLabelsPage, resolveLabelLink };
153
152
 
154
153
  //# sourceMappingURL=label-detail.mjs.map
@@ -9,7 +9,7 @@ import { HStack, VStack } from "../ui/stacks.mjs";
9
9
  import { SnapshotCards } from "./library-snapshots.mjs";
10
10
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
11
11
  import { createUrlBuilder } from "@storyshelf/core/urls";
12
- //#region src/pages/library-grid.tsx
12
+ // src/pages/library-grid.tsx
13
13
  /** The component cards of a build; `layer` is present only with `testing` and captured snapshots. */
14
14
  function LibraryGrid(props) {
15
15
  return /* @__PURE__ */ jsx(VStack, { children: props.groups.map((group) => /* @__PURE__ */ jsx(LibraryCard, {
@@ -99,7 +99,6 @@ function StoryLinks(props) {
99
99
  })
100
100
  }, story.id)) });
101
101
  }
102
- //#endregion
103
102
  export { LibraryGrid };
104
103
 
105
104
  //# sourceMappingURL=library-grid.mjs.map
@@ -2,7 +2,7 @@ import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { normalizeImportPath } from "@storyshelf/core/models";
5
- //#region src/pages/library-model.ts
5
+ // src/pages/library-model.ts
6
6
  /** Tags Storybook adds on its own; they say nothing about the component. */
7
7
  const STORYBOOK_TAGS = /* @__PURE__ */ new Set([
8
8
  "dev",
@@ -41,7 +41,6 @@ function entriesFromSnapshots(snapshots) {
41
41
  });
42
42
  return [...seen.values()];
43
43
  }
44
- //#endregion
45
44
  export { entriesFromSnapshots, groupLibrary };
46
45
 
47
46
  //# sourceMappingURL=library-model.mjs.map
@@ -14,7 +14,7 @@ import { groupSnapshots } from "./build-diff-model.mjs";
14
14
  import { DesignButtons } from "./design-links.mjs";
15
15
  import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
16
16
  import { createUrlBuilder } from "@storyshelf/core/urls";
17
- //#region src/pages/library-snapshots.tsx
17
+ // src/pages/library-snapshots.tsx
18
18
  /** Snapshot image with library height cap, extending the shared diff pane image. */
19
19
  const snapshotImg = css`
20
20
  /* snapshot-img */
@@ -124,7 +124,6 @@ function SnapshotActions(props) {
124
124
  })
125
125
  ] });
126
126
  }
127
- //#endregion
128
127
  export { SnapshotCards, loadSnapshotLayer };
129
128
 
130
129
  //# sourceMappingURL=library-snapshots.mjs.map
@@ -18,7 +18,7 @@ import { entriesFromSnapshots, groupLibrary } from "./library-model.mjs";
18
18
  import { BuildModel, ProjectModel, SnapshotModel } from "@storyshelf/core/models";
19
19
  import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
20
20
  import { createUrlBuilder } from "@storyshelf/core/urls";
21
- //#region src/pages/library.tsx
21
+ // src/pages/library.tsx
22
22
  /**
23
23
  * Library page (ADR 0006, decision 9): the components of the latest build of the selected branch,
24
24
  * whatever its status, from the build's Storybook catalog. With `testing` the cards gain
@@ -231,7 +231,6 @@ function BranchPicker(props) {
231
231
  })] })
232
232
  });
233
233
  }
234
- //#endregion
235
234
  export { renderLibraryPage };
236
235
 
237
236
  //# sourceMappingURL=library.mjs.map
@@ -10,7 +10,7 @@ import { VStack } from "../ui/stacks.mjs";
10
10
  import { DocumentLayout } from "../ui/document.mjs";
11
11
  import { passkeyLoginScript } from "./passkey-ceremony.mjs";
12
12
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
13
- //#region src/pages/login.tsx
13
+ // src/pages/login.tsx
14
14
  /** Resolve auth UI text with defaults. */
15
15
  function authUi() {
16
16
  try {
@@ -111,7 +111,6 @@ function renderLoginPage(state = {}) {
111
111
  }) })
112
112
  });
113
113
  }
114
- //#endregion
115
114
  export { renderLoginPage };
116
115
 
117
116
  //# sourceMappingURL=login.mjs.map
@@ -3,7 +3,7 @@ import "node:url";
3
3
  import.meta.url;
4
4
  import { Alert } from "../ui/feedback.mjs";
5
5
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
6
- //#region src/pages/notifications-paused.tsx
6
+ // src/pages/notifications-paused.tsx
7
7
  /** Notifications need a public URL, so without one nothing is sent (ADR 0014, decision 11). */
8
8
  function NotificationsPausedNotice(props) {
9
9
  return props.paused ? /* @__PURE__ */ jsxs(Alert, {
@@ -16,7 +16,6 @@ function NotificationsPausedNotice(props) {
16
16
  ]
17
17
  }) : null;
18
18
  }
19
- //#endregion
20
19
  export { NotificationsPausedNotice };
21
20
 
22
21
  //# sourceMappingURL=notifications-paused.mjs.map
@@ -1,7 +1,7 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
- //#region src/pages/passkey-ceremony.ts
4
+ // src/pages/passkey-ceremony.ts
5
5
  /**
6
6
  * Page-local WebAuthn ceremony scripts (vanilla JS, no dependencies).
7
7
  *
@@ -91,7 +91,6 @@ ${SUPPORT_CHECK}
91
91
  })();
92
92
  `.trim();
93
93
  }
94
- //#endregion
95
94
  export { passkeyLoginScript, passkeyRegisterScript };
96
95
 
97
96
  //# sourceMappingURL=passkey-ceremony.mjs.map
@@ -14,7 +14,7 @@ import { NotificationsPausedNotice } from "./notifications-paused.mjs";
14
14
  import { passkeyRegisterScript } from "./passkey-ceremony.mjs";
15
15
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
16
16
  import { safeImageUrl } from "@storyshelf/core/urls";
17
- //#region src/pages/profile.tsx
17
+ // src/pages/profile.tsx
18
18
  const profileAvatar = css`
19
19
  /* profile-avatar */
20
20
  width: 64px;
@@ -363,7 +363,6 @@ function renderProfilePage(state) {
363
363
  ]
364
364
  });
365
365
  }
366
- //#endregion
367
366
  export { renderProfilePage };
368
367
 
369
368
  //# sourceMappingURL=profile.mjs.map
@@ -11,7 +11,7 @@ import { Table } from "../ui/table.mjs";
11
11
  import { RelativeTime } from "../ui/time.mjs";
12
12
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
13
13
  import { createUrlBuilder } from "@storyshelf/core/urls";
14
- //#region src/pages/project-builds-table.tsx
14
+ // src/pages/project-builds-table.tsx
15
15
  const buildCell = css`
16
16
  /* build-cell */
17
17
  display: grid;
@@ -145,7 +145,6 @@ function BuildsTable({ project, builds }) {
145
145
  build
146
146
  }, build.id)) })] }) });
147
147
  }
148
- //#endregion
149
148
  export { BuildsTable };
150
149
 
151
150
  //# sourceMappingURL=project-builds-table.mjs.map
@@ -15,7 +15,7 @@ import { BuildsTable } from "./project-builds-table.mjs";
15
15
  import { BuildModel, ProjectModel, averageInheritedRatio } from "@storyshelf/core/models";
16
16
  import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
17
17
  import { createUrlBuilder } from "@storyshelf/core/urls";
18
- //#region src/pages/project-builds.tsx
18
+ // src/pages/project-builds.tsx
19
19
  const STATUSES = [
20
20
  "reviewing",
21
21
  "approved",
@@ -167,7 +167,6 @@ async function renderProjectBuildsPage(slug, query = {}) {
167
167
  ] })]
168
168
  });
169
169
  }
170
- //#endregion
171
170
  export { renderProjectBuildsPage };
172
171
 
173
172
  //# sourceMappingURL=project-builds.mjs.map
@@ -8,7 +8,7 @@ import { Card, PageHeader } from "../ui/layout.mjs";
8
8
  import { HStack } from "../ui/stacks.mjs";
9
9
  import { DocumentLayout } from "../ui/document.mjs";
10
10
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
11
- //#region src/pages/project-create.tsx
11
+ // src/pages/project-create.tsx
12
12
  /** New-project form page (one project corresponds to one Storybook). */
13
13
  function renderProjectCreatePage(state = {}) {
14
14
  const values = state.values ?? {};
@@ -84,7 +84,6 @@ function renderProjectCreatePage(state = {}) {
84
84
  ]
85
85
  });
86
86
  }
87
- //#endregion
88
87
  export { renderProjectCreatePage };
89
88
 
90
89
  //# sourceMappingURL=project-create.mjs.map
@@ -17,7 +17,7 @@ import { renderSettingsTests } from "./settings-tests.mjs";
17
17
  import { renderSettingsTokens } from "./settings-tokens.mjs";
18
18
  import { renderSettingsWebhooks } from "./settings-webhooks.mjs";
19
19
  import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
20
- //#region src/pages/project-settings.tsx
20
+ // src/pages/project-settings.tsx
21
21
  function tabHref(project, tab) {
22
22
  return tab === "general" ? `/projects/${project.slug}/settings` : `/projects/${project.slug}/settings/${tab}`;
23
23
  }
@@ -128,7 +128,6 @@ function renderProjectSettingsPage(data, formState) {
128
128
  })]
129
129
  });
130
130
  }
131
- //#endregion
132
131
  export { renderProjectSettingsPage };
133
132
 
134
133
  //# sourceMappingURL=project-settings.mjs.map
@@ -9,7 +9,7 @@ import { Thumbnail } from "../ui/thumbnail.mjs";
9
9
  import { RelativeTime } from "../ui/time.mjs";
10
10
  import { healthTone } from "./health-panel.mjs";
11
11
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
12
- //#region src/pages/projects-card.tsx
12
+ // src/pages/projects-card.tsx
13
13
  const thumbStrip = css`
14
14
  /* project-thumbs */
15
15
  display: grid;
@@ -201,7 +201,6 @@ function ProjectCard(props) {
201
201
  ]
202
202
  });
203
203
  }
204
- //#endregion
205
204
  export { ProjectCard };
206
205
 
207
206
  //# sourceMappingURL=projects-card.mjs.map
@@ -15,7 +15,7 @@ import { ProjectCard } from "./projects-card.mjs";
15
15
  import { BuildModel, ProjectModel, SnapshotModel } from "@storyshelf/core/models";
16
16
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
17
17
  import { createUrlBuilder } from "@storyshelf/core/urls";
18
- //#region src/pages/projects.tsx
18
+ // src/pages/projects.tsx
19
19
  const projectGrid = css`
20
20
  /* project-grid */
21
21
  display: grid;
@@ -127,7 +127,6 @@ async function renderProjectsPage() {
127
127
  })]
128
128
  });
129
129
  }
130
- //#endregion
131
130
  export { renderProjectsPage };
132
131
 
133
132
  //# sourceMappingURL=projects.mjs.map
@@ -9,7 +9,7 @@ import { HStack, VStack } from "../ui/stacks.mjs";
9
9
  import { Table } from "../ui/table.mjs";
10
10
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
11
11
  import { createUrlBuilder } from "@storyshelf/core/urls";
12
- //#region src/pages/review-changeset.tsx
12
+ // src/pages/review-changeset.tsx
13
13
  /** What the build changed in the Storybook catalog, against its baseline build. */
14
14
  function ChangesetCard(props) {
15
15
  const { data } = props;
@@ -110,7 +110,6 @@ function ChangeRow(props) {
110
110
  }) : null] }) })
111
111
  ] });
112
112
  }
113
- //#endregion
114
113
  export { ChangesetCard };
115
114
 
116
115
  //# sourceMappingURL=review-changeset.mjs.map
@@ -9,7 +9,7 @@ import { VStack } from "../ui/stacks.mjs";
9
9
  import { csrfField } from "../ui/csrf-field.mjs";
10
10
  import { CommentCard } from "./build-diff-comments.mjs";
11
11
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
12
- //#region src/pages/review-comments.tsx
12
+ // src/pages/review-comments.tsx
13
13
  /** Comments on the build as a whole and on its stories, with a form for a build comment. */
14
14
  function CommentsCard(props) {
15
15
  const { data } = props;
@@ -97,7 +97,6 @@ function CommentForm(props) {
97
97
  ] })]
98
98
  });
99
99
  }
100
- //#endregion
101
100
  export { CommentsCard, StoryComments };
102
101
 
103
102
  //# sourceMappingURL=review-comments.mjs.map
@@ -10,7 +10,7 @@ import { RelativeTime } from "../ui/time.mjs";
10
10
  import { csrfField } from "../ui/csrf-field.mjs";
11
11
  import { BUILD_STATUSES } from "@storyshelf/core/types";
12
12
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
13
- //#region src/pages/review-verdict.tsx
13
+ // src/pages/review-verdict.tsx
14
14
  /** The verdict card of the build page: where the build stands, the verdicts, and the reviewer's controls. */
15
15
  /** Build-level verdicts: the approvals so far, each reviewer's latest verdict, and the controls. */
16
16
  function VerdictCard(props) {
@@ -96,7 +96,6 @@ function summary(data) {
96
96
  const needed = `${state.approvalsRequired} ${state.approvalsRequired === 1 ? "approval" : "approvals"}`;
97
97
  return `${state.approvals} of ${needed} given. Any rejection rejects the build. Open comments do not block a verdict.`;
98
98
  }
99
- //#endregion
100
99
  export { VerdictCard };
101
100
 
102
101
  //# sourceMappingURL=review-verdict.mjs.map
@@ -8,7 +8,7 @@ import { Card, SectionTitle } from "../ui/layout.mjs";
8
8
  import { HStack, VStack } from "../ui/stacks.mjs";
9
9
  import { DocumentLayout } from "../ui/document.mjs";
10
10
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
11
- //#region src/pages/root.tsx
11
+ // src/pages/root.tsx
12
12
  /** Landing hero card: card surface with centered marketing padding. */
13
13
  const heroCard = css`
14
14
  /* hero-card */
@@ -92,7 +92,6 @@ function renderRootPage() {
92
92
  })]
93
93
  });
94
94
  }
95
- //#endregion
96
95
  export { renderRootPage };
97
96
 
98
97
  //# sourceMappingURL=root.mjs.map