@delmaredigital/payload-experiments 0.2.0-rc.7 → 0.3.0-rc.4

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 (336) hide show
  1. package/README.md +202 -26
  2. package/dist/admin/PreviewLinks.d.ts +2 -1
  3. package/dist/admin/PreviewLinks.js +50 -21
  4. package/dist/admin/TestsNavLink.d.ts +3 -1
  5. package/dist/admin/TestsNavLink.js +2 -2
  6. package/dist/admin/actions/ConfirmDialog.d.ts +7 -4
  7. package/dist/admin/actions/ConfirmDialog.js +37 -82
  8. package/dist/admin/actions/DecideDialog.d.ts +3 -1
  9. package/dist/admin/actions/DecideDialog.js +30 -13
  10. package/dist/admin/actions/MakeContentResult.d.ts +13 -2
  11. package/dist/admin/actions/MakeContentResult.js +115 -16
  12. package/dist/admin/actions/actions.model.d.ts +2 -4
  13. package/dist/admin/actions/actions.model.js +2 -3
  14. package/dist/admin/allocation.model.js +3 -5
  15. package/dist/admin/api.d.ts +10 -4
  16. package/dist/admin/api.js +11 -7
  17. package/dist/admin/armSelect/ArmSelectField.js +14 -22
  18. package/dist/admin/arms/arms.model.d.ts +1 -21
  19. package/dist/admin/arms/arms.model.js +1 -153
  20. package/dist/admin/copy/actions.d.ts +39 -3
  21. package/dist/admin/copy/actions.js +40 -4
  22. package/dist/admin/copy/armSelect.js +5 -5
  23. package/dist/admin/copy/arms.d.ts +1 -6
  24. package/dist/admin/copy/arms.js +1 -16
  25. package/dist/admin/copy/audience.d.ts +2 -1
  26. package/dist/admin/copy/audience.js +3 -2
  27. package/dist/admin/copy/common.d.ts +13 -6
  28. package/dist/admin/copy/common.js +14 -8
  29. package/dist/admin/copy/goals.d.ts +21 -6
  30. package/dist/admin/copy/goals.js +27 -6
  31. package/dist/admin/copy/readiness.d.ts +22 -0
  32. package/dist/admin/copy/readiness.js +21 -0
  33. package/dist/admin/copy/recommendation.d.ts +0 -3
  34. package/dist/admin/copy/recommendation.js +0 -3
  35. package/dist/admin/copy/results.d.ts +43 -2
  36. package/dist/admin/copy/results.js +44 -3
  37. package/dist/admin/copy/review.d.ts +2 -2
  38. package/dist/admin/copy/review.js +2 -2
  39. package/dist/admin/copy/setting.d.ts +2 -0
  40. package/dist/admin/copy/setting.js +2 -0
  41. package/dist/admin/copy/surface.d.ts +7 -5
  42. package/dist/admin/copy/surface.js +9 -5
  43. package/dist/admin/copy/testPage.d.ts +10 -0
  44. package/dist/admin/copy/testPage.js +10 -0
  45. package/dist/admin/format/date.d.ts +2 -0
  46. package/dist/admin/format/date.js +10 -0
  47. package/dist/admin/paths.d.ts +2 -1
  48. package/dist/admin/paths.js +2 -1
  49. package/dist/admin/previewLinks.model.d.ts +4 -2
  50. package/dist/admin/previewLinks.model.js +8 -7
  51. package/dist/admin/results/CiChart.js +11 -21
  52. package/dist/admin/results/DataQualityPanel.d.ts +4 -2
  53. package/dist/admin/results/DataQualityPanel.js +30 -17
  54. package/dist/admin/results/DataTable.d.ts +16 -0
  55. package/dist/admin/results/DataTable.js +152 -0
  56. package/dist/admin/results/StatTile.d.ts +7 -0
  57. package/dist/admin/results/StatTile.js +22 -0
  58. package/dist/admin/results/VerdictHero.d.ts +13 -0
  59. package/dist/admin/results/{VerdictCard.js → VerdictHero.js} +15 -12
  60. package/dist/admin/results/legacy.d.ts +16 -0
  61. package/dist/admin/results/legacy.js +27 -0
  62. package/dist/admin/results/releasePages.model.d.ts +17 -0
  63. package/dist/admin/results/releasePages.model.js +10 -0
  64. package/dist/admin/results/results.css +64 -0
  65. package/dist/admin/results/results.model.d.ts +11 -7
  66. package/dist/admin/results/results.model.js +24 -7
  67. package/dist/admin/results/snapshot.d.ts +14 -0
  68. package/dist/admin/results/snapshot.js +3 -0
  69. package/dist/admin/surface/ResultsRoute.d.ts +1 -1
  70. package/dist/admin/surface/ResultsRoute.js +59 -34
  71. package/dist/admin/surface/SurfaceShell.d.ts +11 -2
  72. package/dist/admin/surface/SurfaceShell.js +49 -14
  73. package/dist/admin/surface/TestsHome.d.ts +6 -1
  74. package/dist/admin/surface/TestsHome.js +182 -114
  75. package/dist/admin/surface/TestsSurface.js +56 -16
  76. package/dist/admin/surface/goals/GoalForm.js +341 -308
  77. package/dist/admin/surface/goals/GoalsList.js +123 -89
  78. package/dist/admin/surface/goals/data.d.ts +8 -2
  79. package/dist/admin/surface/goals/data.js +24 -16
  80. package/dist/admin/surface/goals/goals.css +10 -13
  81. package/dist/admin/surface/home.model.d.ts +8 -8
  82. package/dist/admin/surface/home.model.js +23 -12
  83. package/dist/admin/surface/newTest/NewTest.js +9 -9
  84. package/dist/admin/surface/pageBlock/parts.js +31 -26
  85. package/dist/admin/surface/readiness/ActionDialogs.js +47 -19
  86. package/dist/admin/surface/readiness/Banner.d.ts +3 -0
  87. package/dist/admin/surface/readiness/Banner.js +58 -33
  88. package/dist/admin/surface/readiness/SaveStatus.d.ts +1 -0
  89. package/dist/admin/surface/readiness/SaveStatus.js +6 -3
  90. package/dist/admin/surface/readiness/readiness.model.d.ts +2 -0
  91. package/dist/admin/surface/readiness/readiness.model.js +25 -9
  92. package/dist/admin/surface/readiness/useTransition.d.ts +1 -0
  93. package/dist/admin/surface/readiness/useTransition.js +2 -1
  94. package/dist/admin/surface/results/ReleasePages.d.ts +14 -0
  95. package/dist/admin/surface/results/ReleasePages.js +116 -0
  96. package/dist/admin/surface/results/ResultsBody.d.ts +11 -1
  97. package/dist/admin/surface/results/ResultsBody.js +277 -105
  98. package/dist/admin/surface/results/ResultsHeader.d.ts +10 -0
  99. package/dist/admin/surface/results/ResultsHeader.js +177 -0
  100. package/dist/admin/surface/results/recommendation.model.d.ts +3 -2
  101. package/dist/admin/surface/results/recommendation.model.js +12 -9
  102. package/dist/admin/surface/results/useResults.d.ts +21 -3
  103. package/dist/admin/surface/results/useResults.js +2 -1
  104. package/dist/admin/surface/setting/parts.js +75 -88
  105. package/dist/admin/surface/setting/setting.css +3 -15
  106. package/dist/admin/surface/surface.css +61 -47
  107. package/dist/admin/surface/test/AdvancedSection.js +55 -48
  108. package/dist/admin/surface/test/GoalSection.js +46 -47
  109. package/dist/admin/surface/test/LengthSection.js +46 -34
  110. package/dist/admin/surface/test/Rail.d.ts +4 -0
  111. package/dist/admin/surface/test/Rail.js +83 -0
  112. package/dist/admin/surface/test/ReadinessBar.d.ts +5 -0
  113. package/dist/admin/surface/test/ReadinessBar.js +33 -0
  114. package/dist/admin/surface/test/Section.d.ts +1 -1
  115. package/dist/admin/surface/test/Section.js +36 -16
  116. package/dist/admin/surface/test/TargetingSection.js +168 -142
  117. package/dist/admin/surface/test/TestPage.d.ts +2 -1
  118. package/dist/admin/surface/test/TestPage.js +146 -68
  119. package/dist/admin/surface/test/VersionsSection.js +151 -120
  120. package/dist/admin/surface/test/fields.d.ts +11 -4
  121. package/dist/admin/surface/test/fields.js +84 -85
  122. package/dist/admin/surface/test/jumpToSection.d.ts +3 -0
  123. package/dist/admin/surface/test/jumpToSection.js +10 -0
  124. package/dist/admin/surface/test/pageParts.js +9 -3
  125. package/dist/admin/surface/test/testPage.css +81 -14
  126. package/dist/admin/surface/test/testPage.model.d.ts +2 -3
  127. package/dist/admin/surface/test/testPage.model.js +1 -21
  128. package/dist/admin/surface/useTestDocument.js +12 -5
  129. package/dist/admin/targeting/targeting.model.d.ts +1 -3
  130. package/dist/admin/targeting/targeting.model.js +3 -8
  131. package/dist/admin/theme.css +115 -36
  132. package/dist/admin/theme.d.ts +38 -0
  133. package/dist/admin/theme.js +38 -1
  134. package/dist/admin/useApi.d.ts +17 -2
  135. package/dist/admin/useLayerUsage.js +14 -23
  136. package/dist/admin/views/ExperimentsRootView.js +12 -2
  137. package/dist/admin/views/TestsNavLinkServer.d.ts +2 -0
  138. package/dist/admin/views/TestsNavLinkServer.js +43 -0
  139. package/dist/arms/copy.d.ts +6 -0
  140. package/dist/arms/copy.js +16 -0
  141. package/dist/arms/model.d.ts +23 -0
  142. package/dist/arms/model.js +173 -0
  143. package/dist/collections/experiments/config.js +25 -0
  144. package/dist/collections/experiments/lockHook.js +3 -1
  145. package/dist/collections/identities.js +6 -1
  146. package/dist/collections/metrics.js +7 -0
  147. package/dist/collections/metricsGuards.d.ts +9 -0
  148. package/dist/collections/metricsGuards.js +33 -0
  149. package/dist/contentDone.d.ts +4 -0
  150. package/dist/contentDone.js +5 -0
  151. package/dist/db/appends.d.ts +6 -2
  152. package/dist/db/appends.js +10 -4
  153. package/dist/db/identities.d.ts +8 -7
  154. package/dist/db/identities.js +9 -6
  155. package/dist/db/locks.d.ts +6 -0
  156. package/dist/db/locks.js +13 -1
  157. package/dist/db/metricUsage.d.ts +19 -0
  158. package/dist/db/metricUsage.js +54 -0
  159. package/dist/db/names.d.ts +5 -0
  160. package/dist/db/names.js +5 -0
  161. package/dist/db/pageOccupancy.d.ts +12 -0
  162. package/dist/db/pageOccupancy.js +45 -0
  163. package/dist/db/publishedContent.d.ts +10 -0
  164. package/dist/db/publishedContent.js +43 -0
  165. package/dist/db/results.d.ts +2 -0
  166. package/dist/db/results.js +6 -2
  167. package/dist/db/snapshots.d.ts +18 -6
  168. package/dist/db/snapshots.js +25 -8
  169. package/dist/db/sweep.js +11 -6
  170. package/dist/endpoints/index.js +19 -1
  171. package/dist/endpoints/results.js +5 -0
  172. package/dist/endpoints/sanitizeReadinessDetail.d.ts +1 -0
  173. package/dist/endpoints/sanitizeReadinessDetail.js +2 -0
  174. package/dist/endpoints/summary.js +20 -2
  175. package/dist/endpoints/transitions.d.ts +15 -0
  176. package/dist/endpoints/transitions.js +36 -0
  177. package/dist/errors.d.ts +8 -0
  178. package/dist/errors.js +28 -0
  179. package/dist/exports/adminRsc.d.ts +1 -0
  180. package/dist/exports/adminRsc.js +1 -0
  181. package/dist/exports/index.d.ts +2 -1
  182. package/dist/exports/index.js +1 -0
  183. package/dist/exports/puck.d.ts +2 -1
  184. package/dist/exports/puck.js +1 -1
  185. package/dist/exports/puckEditor.d.ts +4 -1
  186. package/dist/exports/puckEditor.js +3 -1
  187. package/dist/exports/rsc.d.ts +6 -1
  188. package/dist/exports/rsc.js +2 -0
  189. package/dist/hooks/pageGuard.d.ts +5 -0
  190. package/dist/hooks/pageGuard.js +139 -0
  191. package/dist/lib/fetchAllDocs.d.ts +16 -0
  192. package/dist/lib/fetchAllDocs.js +56 -0
  193. package/dist/log.js +6 -3
  194. package/dist/manifest/compile.d.ts +5 -0
  195. package/dist/manifest/compile.js +5 -1
  196. package/dist/options.js +16 -0
  197. package/dist/plugin.js +30 -2
  198. package/dist/puck/ExperimentPicker.js +47 -16
  199. package/dist/puck/ExperimentSlot.d.ts +51 -1
  200. package/dist/puck/ExperimentSlot.js +23 -12
  201. package/dist/puck/copy.d.ts +6 -5
  202. package/dist/puck/copy.js +6 -5
  203. package/dist/puck/editor/CreateExperimentDrawer.js +46 -56
  204. package/dist/puck/editor/ExperimentSlotEditor.d.ts +52 -1
  205. package/dist/puck/editor/ExperimentSlotEditor.js +292 -137
  206. package/dist/puck/editor/ResultsReadout.d.ts +6 -0
  207. package/dist/puck/editor/ResultsReadout.js +99 -0
  208. package/dist/puck/editor/VersionBuilder.d.ts +34 -0
  209. package/dist/puck/editor/VersionBuilder.js +317 -0
  210. package/dist/puck/editor/armWrites.d.ts +7 -0
  211. package/dist/puck/editor/armWrites.js +71 -0
  212. package/dist/puck/editor/armsCache.d.ts +14 -0
  213. package/dist/puck/editor/armsCache.js +78 -0
  214. package/dist/puck/editor/copy.d.ts +33 -1
  215. package/dist/puck/editor/copy.js +45 -8
  216. package/dist/puck/editor/createTest.d.ts +1 -1
  217. package/dist/puck/editor/createTest.js +25 -14
  218. package/dist/puck/editor/editor.chrome.css +121 -0
  219. package/dist/puck/editor/editor.css +288 -204
  220. package/dist/puck/editor/editor.model.d.ts +4 -1
  221. package/dist/puck/editor/editor.model.js +10 -7
  222. package/dist/puck/editor/experimentOutlinePlugin.d.ts +3 -0
  223. package/dist/puck/editor/experimentOutlinePlugin.js +89 -0
  224. package/dist/puck/experimentSlotField.d.ts +2 -0
  225. package/dist/puck/experimentSlotField.js +11 -3
  226. package/dist/puck/hostContext.d.ts +10 -0
  227. package/dist/puck/hostContext.js +12 -0
  228. package/dist/puck/routes.d.ts +12 -0
  229. package/dist/puck/routes.js +11 -0
  230. package/dist/puck/slotConfig.d.ts +1 -1
  231. package/dist/puck/slotConfig.js +2 -2
  232. package/dist/results/aggregate.js +4 -3
  233. package/dist/results/analyse.d.ts +4 -1
  234. package/dist/results/analyse.js +27 -11
  235. package/dist/results/cuped.js +3 -2
  236. package/dist/results/identityCredit.d.ts +15 -7
  237. package/dist/results/identityCredit.js +32 -33
  238. package/dist/results/rolloutUnits.js +2 -1
  239. package/dist/results/snapshot.js +8 -2
  240. package/dist/results/srm.js +2 -1
  241. package/dist/sanitizeReadinessDetail.d.ts +7 -0
  242. package/dist/sanitizeReadinessDetail.js +63 -0
  243. package/dist/server/linkIdentity.d.ts +10 -1
  244. package/dist/server/linkIdentity.js +17 -15
  245. package/dist/server/metadata.d.ts +5 -0
  246. package/dist/server/metadata.js +18 -3
  247. package/dist/server/normaliseContentRelationships.d.ts +7 -0
  248. package/dist/server/normaliseContentRelationships.js +62 -0
  249. package/dist/server/recordContentChange.d.ts +1 -1
  250. package/dist/server/recordContentChange.js +17 -8
  251. package/dist/server/runResults.d.ts +3 -2
  252. package/dist/server/runResults.js +157 -35
  253. package/dist/targeting/values.d.ts +4 -0
  254. package/dist/targeting/values.js +10 -0
  255. package/dist/transitions/addMetric.js +8 -0
  256. package/dist/transitions/archive.js +2 -3
  257. package/dist/transitions/checkStart.d.ts +10 -3
  258. package/dist/transitions/checkStart.js +25 -0
  259. package/dist/transitions/contentFields.d.ts +7 -0
  260. package/dist/transitions/contentFields.js +20 -0
  261. package/dist/transitions/decide.js +22 -2
  262. package/dist/transitions/dismissContentEntry.d.ts +8 -0
  263. package/dist/transitions/dismissContentEntry.js +45 -0
  264. package/dist/transitions/makeContent.d.ts +5 -2
  265. package/dist/transitions/makeContent.js +217 -118
  266. package/dist/transitions/phaseRecord.d.ts +8 -2
  267. package/dist/transitions/placements.d.ts +3 -6
  268. package/dist/transitions/placements.js +12 -1
  269. package/dist/transitions/preflightData.d.ts +9 -1
  270. package/dist/transitions/preflightData.js +138 -20
  271. package/dist/transitions/releasePages.d.ts +8 -0
  272. package/dist/transitions/releasePages.js +26 -0
  273. package/dist/transitions/restoreContentEntry.d.ts +8 -0
  274. package/dist/transitions/restoreContentEntry.js +47 -0
  275. package/dist/transitions/start.js +62 -7
  276. package/dist/types/contracts.d.ts +24 -4
  277. package/dist/types/endpoints.d.ts +34 -3
  278. package/dist/types/index.d.ts +1 -0
  279. package/dist/types/index.js +1 -0
  280. package/dist/types/reasons.d.ts +3 -0
  281. package/dist/types/reasons.js +1 -0
  282. package/dist/types/snapshot.d.ts +6 -1
  283. package/dist/ui/Banner.d.ts +2 -0
  284. package/dist/ui/Banner.js +2 -0
  285. package/dist/ui/Breadcrumb.d.ts +7 -0
  286. package/dist/ui/Breadcrumb.js +25 -0
  287. package/dist/ui/Button.d.ts +15 -0
  288. package/dist/ui/Button.js +32 -0
  289. package/dist/ui/Card.d.ts +12 -0
  290. package/dist/ui/Card.js +40 -0
  291. package/dist/ui/Checkbox.d.ts +2 -0
  292. package/dist/ui/Checkbox.js +2 -0
  293. package/dist/{admin/components → ui}/ChipsInput.d.ts +4 -3
  294. package/dist/{admin/components → ui}/ChipsInput.js +20 -12
  295. package/dist/ui/Dialog.d.ts +13 -0
  296. package/dist/ui/Dialog.js +85 -0
  297. package/dist/ui/EmptyState.d.ts +2 -0
  298. package/dist/ui/EmptyState.js +2 -0
  299. package/dist/ui/Feedback.d.ts +24 -0
  300. package/dist/ui/Feedback.js +40 -0
  301. package/dist/ui/Inputs.d.ts +34 -0
  302. package/dist/ui/Inputs.js +225 -0
  303. package/dist/ui/NumberInput.d.ts +2 -0
  304. package/dist/ui/NumberInput.js +2 -0
  305. package/dist/ui/Range.d.ts +2 -0
  306. package/dist/ui/Range.js +2 -0
  307. package/dist/ui/SearchInput.d.ts +2 -0
  308. package/dist/ui/SearchInput.js +2 -0
  309. package/dist/ui/SectionCard.d.ts +2 -0
  310. package/dist/ui/SectionCard.js +2 -0
  311. package/dist/ui/Select.d.ts +2 -0
  312. package/dist/ui/Select.js +2 -0
  313. package/dist/ui/StatusChip.d.ts +2 -0
  314. package/dist/ui/StatusChip.js +2 -0
  315. package/dist/ui/Tabs.d.ts +16 -0
  316. package/dist/ui/Tabs.js +61 -0
  317. package/dist/ui/TextInput.d.ts +2 -0
  318. package/dist/ui/TextInput.js +2 -0
  319. package/dist/ui/Textarea.d.ts +2 -0
  320. package/dist/ui/Textarea.js +2 -0
  321. package/dist/ui/Toggle.d.ts +2 -0
  322. package/dist/ui/Toggle.js +2 -0
  323. package/dist/ui/accent.d.ts +40 -0
  324. package/dist/ui/accent.js +139 -0
  325. package/dist/ui/index.d.ts +9 -0
  326. package/dist/ui/index.js +9 -0
  327. package/dist/ui/ui.css +92 -0
  328. package/package.json +5 -2
  329. package/dist/admin/components/chipsInput.css +0 -11
  330. package/dist/admin/results/ArmTable.d.ts +0 -8
  331. package/dist/admin/results/ArmTable.js +0 -113
  332. package/dist/admin/results/VerdictCard.d.ts +0 -9
  333. package/dist/admin/surface/goals/GoalsBreadcrumb.d.ts +0 -5
  334. package/dist/admin/surface/goals/GoalsBreadcrumb.js +0 -47
  335. package/dist/admin/surface/test/TestHeader.d.ts +0 -4
  336. package/dist/admin/surface/test/TestHeader.js +0 -70
@@ -3,16 +3,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { theme } from '../theme.js';
4
4
  import { RESULTS_COPY as C, chartSummary, contentChangeTitle } from '../copy/results.js';
5
5
  import { chartModel } from './chart.model.js';
6
+ import { formatDate } from '../format/date.js';
6
7
  import { formatPercent } from './format.js';
7
- const colors = [
8
- theme.color.textStrong,
9
- theme.color.textMuted,
10
- theme.color.borderAccent
11
- ];
12
- const date = (t)=>new Intl.DateTimeFormat('en-US', {
13
- dateStyle: 'medium',
14
- timeZone: 'UTC'
15
- }).format(t);
8
+ import { seriesColor } from './DataTable.js';
16
9
  export function CiChart({ series, metricId, metricName, phase, contentChanges }) {
17
10
  const model = chartModel({
18
11
  series,
@@ -32,9 +25,6 @@ export function CiChart({ series, metricId, metricName, phase, contentChanges })
32
25
  color: theme.color.text
33
26
  },
34
27
  children: [
35
- /*#__PURE__*/ _jsx("h2", {
36
- children: C.chart
37
- }),
38
28
  /*#__PURE__*/ _jsxs("svg", {
39
29
  viewBox: "0 0 760 280",
40
30
  style: {
@@ -42,8 +32,8 @@ export function CiChart({ series, metricId, metricName, phase, contentChanges })
42
32
  height: 'auto'
43
33
  },
44
34
  role: "img",
45
- "aria-label": chartSummary(metricName, model.variants.map((variant)=>variant.label).join(', '), date(from), date(to), [
46
- ...new Set(model.markers.map((marker)=>date(marker.t)))
35
+ "aria-label": chartSummary(metricName, model.variants.map((variant)=>variant.label).join(', '), formatDate(from), formatDate(to), [
36
+ ...new Set(model.markers.map((marker)=>formatDate(marker.t)))
47
37
  ]),
48
38
  children: [
49
39
  /*#__PURE__*/ _jsx("line", {
@@ -70,7 +60,7 @@ export function CiChart({ series, metricId, metricName, phase, contentChanges })
70
60
  y: 260,
71
61
  fill: "currentColor",
72
62
  fontSize: 12,
73
- children: date(from)
63
+ children: formatDate(from)
74
64
  }),
75
65
  /*#__PURE__*/ _jsx("text", {
76
66
  x: 680,
@@ -78,9 +68,9 @@ export function CiChart({ series, metricId, metricName, phase, contentChanges })
78
68
  textAnchor: "end",
79
69
  fill: "currentColor",
80
70
  fontSize: 12,
81
- children: date(to)
71
+ children: formatDate(to)
82
72
  }),
83
- model.variants.map((variant, index)=>{
73
+ model.variants.map((variant)=>{
84
74
  const path = (points)=>{
85
75
  let connected = false;
86
76
  return points.map((point)=>{
@@ -93,7 +83,7 @@ export function CiChart({ series, metricId, metricName, phase, contentChanges })
93
83
  return `${command}${x(point.t)},${y(point.value)}`;
94
84
  }).join(' ');
95
85
  };
96
- const color = colors[index % colors.length];
86
+ const color = seriesColor(variant.arm);
97
87
  const upper = variant.points.map((point)=>`${x(point.t)},${y(point.hi ?? high)}`);
98
88
  const lower = [
99
89
  ...variant.points
@@ -140,7 +130,7 @@ export function CiChart({ series, metricId, metricName, phase, contentChanges })
140
130
  model.markers.map((marker, index)=>/*#__PURE__*/ _jsxs("g", {
141
131
  children: [
142
132
  /*#__PURE__*/ _jsx("title", {
143
- children: contentChangeTitle(date(marker.t))
133
+ children: contentChangeTitle(formatDate(marker.t))
144
134
  }),
145
135
  /*#__PURE__*/ _jsx("line", {
146
136
  x1: x(marker.t),
@@ -155,7 +145,7 @@ export function CiChart({ series, metricId, metricName, phase, contentChanges })
155
145
  ]
156
146
  }),
157
147
  /*#__PURE__*/ _jsx("ul", {
158
- children: model.variants.map((variant, index)=>/*#__PURE__*/ _jsxs("li", {
148
+ children: model.variants.map((variant)=>/*#__PURE__*/ _jsxs("li", {
159
149
  style: {
160
150
  color: theme.color.text
161
151
  },
@@ -167,7 +157,7 @@ export function CiChart({ series, metricId, metricName, phase, contentChanges })
167
157
  width: '1em',
168
158
  height: '0.5em',
169
159
  marginRight: '0.5em',
170
- backgroundColor: colors[index % colors.length]
160
+ backgroundColor: seriesColor(variant.arm)
171
161
  }
172
162
  }),
173
163
  variant.label
@@ -1,4 +1,6 @@
1
1
  import type { DataQualityItem } from './results.model.js';
2
- export declare function DataQualityPanel({ items }: {
2
+ import './results.css';
3
+ export declare function DataQualityPanel({ items, problem }: {
3
4
  items: DataQualityItem[];
4
- }): import("react").JSX.Element | null;
5
+ problem?: boolean;
6
+ }): import("react").JSX.Element;
@@ -1,28 +1,37 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { theme } from '../theme.js';
4
- import { RESULTS_COPY } from '../copy/results.js';
5
- export function DataQualityPanel({ items }) {
6
- if (items.length === 0) return null;
7
- return /*#__PURE__*/ _jsxs("section", {
8
- className: "xp-data-quality",
9
- "aria-label": RESULTS_COPY.quality,
10
- style: {
11
- color: theme.color.text,
12
- background: theme.color.surface,
13
- padding: '1rem'
14
- },
3
+ import { RESULTS_COPY as C } from '../copy/results.js';
4
+ import './results.css';
5
+ const quality = (item)=>item.id === 'srm' || item.id.startsWith('version-page-unavailable') ? 'problem' : 'watch';
6
+ export function DataQualityPanel({ items, problem = false }) {
7
+ const overall = problem || items.some((item)=>quality(item) === 'problem') ? 'problem' : items.length ? 'watch' : 'ok';
8
+ return /*#__PURE__*/ _jsxs("details", {
9
+ className: "xp-results-panel xp-data-quality",
10
+ open: overall !== 'ok',
15
11
  children: [
16
- /*#__PURE__*/ _jsx("h2", {
17
- children: RESULTS_COPY.quality
12
+ /*#__PURE__*/ _jsxs("summary", {
13
+ children: [
14
+ C.quality,
15
+ /*#__PURE__*/ _jsx("span", {
16
+ className: `xp-quality-chip xp-quality-chip--${overall}`,
17
+ children: C.qualityStates[overall]
18
+ })
19
+ ]
18
20
  }),
19
- /*#__PURE__*/ _jsx("ul", {
20
- children: items.map((item)=>/*#__PURE__*/ _jsxs("li", {
21
+ /*#__PURE__*/ _jsx("section", {
22
+ "aria-label": C.quality,
23
+ children: items.length ? items.map((item)=>/*#__PURE__*/ _jsxs("div", {
24
+ className: "xp-quality-row",
21
25
  children: [
26
+ /*#__PURE__*/ _jsx("span", {
27
+ className: `xp-quality-chip xp-quality-chip--${quality(item)}`,
28
+ children: C.qualityStates[quality(item)]
29
+ }),
22
30
  /*#__PURE__*/ _jsx("p", {
23
31
  children: item.message
24
32
  }),
25
33
  item.detail ? /*#__PURE__*/ _jsx("p", {
34
+ className: "xp-quality-detail",
26
35
  children: item.detail
27
36
  }) : null,
28
37
  item.shares ? /*#__PURE__*/ _jsx("ul", {
@@ -31,10 +40,14 @@ export function DataQualityPanel({ items }) {
31
40
  }, index))
32
41
  }) : null,
33
42
  /*#__PURE__*/ _jsx("p", {
43
+ className: "xp-quality-next",
34
44
  children: item.nextStep
35
45
  })
36
46
  ]
37
- }, item.id))
47
+ }, item.id)) : /*#__PURE__*/ _jsx("p", {
48
+ className: "xp-quality-row",
49
+ children: C.qualityOK
50
+ })
38
51
  })
39
52
  ]
40
53
  });
@@ -0,0 +1,16 @@
1
+ import type { ArmRow } from './results.model.js';
2
+ export interface DataTableProps {
3
+ rows: ArmRow[];
4
+ caption: string;
5
+ method: 'sequential' | 'bayesian';
6
+ metricKind: 'binomial' | 'count' | 'revenue';
7
+ }
8
+ import './results.css';
9
+ export declare const seriesColor: (key: string) => "var(--xp-series-a)" | "var(--xp-series-b)" | "var(--xp-series-muted)" | "var(--xp-series-c)";
10
+ export declare function Swatch({ arm }: {
11
+ arm: string;
12
+ }): import("react").JSX.Element;
13
+ export declare function DataTable({ rows, caption, metricKind, leader, primary }: DataTableProps & {
14
+ leader?: string | null;
15
+ primary?: boolean;
16
+ }): import("react").JSX.Element;
@@ -0,0 +1,152 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useRef } from 'react';
4
+ import { RESULTS_COPY as C } from '../copy/results.js';
5
+ import { CappedCell } from './CappedCell.js';
6
+ import './results.css';
7
+ export const seriesColor = (key)=>key === 'variantA' ? 'var(--xp-series-a)' : key === 'variantB' ? 'var(--xp-series-b)' : key === 'variantC' ? 'var(--xp-series-c)' : 'var(--xp-series-muted)';
8
+ export function Swatch({ arm }) {
9
+ return /*#__PURE__*/ _jsx("span", {
10
+ className: "xp-results-swatch",
11
+ style: {
12
+ background: seriesColor(arm)
13
+ },
14
+ "aria-hidden": "true"
15
+ });
16
+ }
17
+ function updateScrollCues(wrap) {
18
+ wrap.parentElement?.classList.toggle('has-left', wrap.scrollLeft > 0);
19
+ wrap.parentElement?.classList.toggle('has-right', wrap.scrollLeft + wrap.clientWidth < wrap.scrollWidth - 1);
20
+ }
21
+ export function DataTable({ rows, caption, metricKind, leader, primary = false }) {
22
+ const scrollRef = useRef(null);
23
+ useEffect(()=>{
24
+ const wrap = scrollRef.current;
25
+ if (!wrap) return;
26
+ const update = ()=>updateScrollCues(wrap);
27
+ update();
28
+ const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(update);
29
+ observer?.observe(wrap);
30
+ if (wrap.firstElementChild) observer?.observe(wrap.firstElementChild);
31
+ window.addEventListener('resize', update);
32
+ return ()=>{
33
+ observer?.disconnect();
34
+ window.removeEventListener('resize', update);
35
+ };
36
+ }, [
37
+ rows
38
+ ]);
39
+ return /*#__PURE__*/ _jsx("div", {
40
+ className: "xp-data-table-frame",
41
+ children: /*#__PURE__*/ _jsx("div", {
42
+ ref: scrollRef,
43
+ className: "xp-data-table-wrap",
44
+ tabIndex: 0,
45
+ role: "region",
46
+ "aria-label": caption,
47
+ onScroll: (event)=>updateScrollCues(event.currentTarget),
48
+ children: /*#__PURE__*/ _jsxs("table", {
49
+ className: "xp-data-table",
50
+ children: [
51
+ /*#__PURE__*/ _jsx("caption", {
52
+ children: caption
53
+ }),
54
+ /*#__PURE__*/ _jsx("thead", {
55
+ children: /*#__PURE__*/ _jsxs("tr", {
56
+ children: [
57
+ /*#__PURE__*/ _jsx("th", {
58
+ scope: "col",
59
+ children: C.group
60
+ }),
61
+ /*#__PURE__*/ _jsx("th", {
62
+ scope: "col",
63
+ className: "num",
64
+ children: C.people
65
+ }),
66
+ primary && metricKind === 'binomial' ? /*#__PURE__*/ _jsx("th", {
67
+ scope: "col",
68
+ className: "num",
69
+ children: C.conversions
70
+ }) : null,
71
+ /*#__PURE__*/ _jsx("th", {
72
+ scope: "col",
73
+ className: "num",
74
+ children: metricKind === 'binomial' ? C.rate : C.average
75
+ }),
76
+ /*#__PURE__*/ _jsx("th", {
77
+ scope: "col",
78
+ className: "num",
79
+ children: C.lift
80
+ }),
81
+ /*#__PURE__*/ _jsx("th", {
82
+ scope: "col",
83
+ className: "num",
84
+ children: C.ci
85
+ }),
86
+ primary ? /*#__PURE__*/ _jsx("th", {
87
+ scope: "col",
88
+ className: "num",
89
+ children: C.chanceToWin
90
+ }) : null
91
+ ]
92
+ })
93
+ }),
94
+ /*#__PURE__*/ _jsx("tbody", {
95
+ children: rows.map((row)=>/*#__PURE__*/ _jsxs("tr", {
96
+ className: primary && leader && row.key === leader ? 'is-lead' : undefined,
97
+ children: [
98
+ /*#__PURE__*/ _jsxs("th", {
99
+ scope: "row",
100
+ children: [
101
+ /*#__PURE__*/ _jsxs("span", {
102
+ className: "xp-results-group",
103
+ children: [
104
+ /*#__PURE__*/ _jsx(Swatch, {
105
+ arm: row.key
106
+ }),
107
+ row.label
108
+ ]
109
+ }),
110
+ row.key === 'holdout' && row.baseline ? /*#__PURE__*/ _jsx("div", {
111
+ className: "muted",
112
+ children: row.baseline
113
+ }) : null
114
+ ]
115
+ }),
116
+ /*#__PURE__*/ _jsx("td", {
117
+ className: "num",
118
+ children: row.n
119
+ }),
120
+ primary && metricKind === 'binomial' ? /*#__PURE__*/ _jsx("td", {
121
+ className: "num",
122
+ children: row.value
123
+ }) : null,
124
+ /*#__PURE__*/ _jsx("td", {
125
+ className: "num",
126
+ children: metricKind === 'revenue' ? /*#__PURE__*/ _jsx(CappedCell, {
127
+ model: {
128
+ ...row.capped,
129
+ notice: undefined
130
+ }
131
+ }) : row.rate ?? row.capped.statistic
132
+ }),
133
+ /*#__PURE__*/ _jsx("td", {
134
+ className: `num${row.baseline ? ' muted' : ''}`,
135
+ children: row.baseline ? '—' : row.lift ?? '—'
136
+ }),
137
+ /*#__PURE__*/ _jsx("td", {
138
+ className: `num${row.baseline ? ' muted' : ''}`,
139
+ children: row.baseline ? '—' : row.comparison?.method === 'sequential' ? row.comparison.adjustedCI ?? row.comparison.ci : row.comparison?.ci ?? '—'
140
+ }),
141
+ primary ? /*#__PURE__*/ _jsx("td", {
142
+ className: "num",
143
+ children: row.baseline ? '—' : row.chanceToWin ?? '—'
144
+ }) : null
145
+ ]
146
+ }, row.key))
147
+ })
148
+ ]
149
+ })
150
+ })
151
+ });
152
+ }
@@ -0,0 +1,7 @@
1
+ import type { ReactNode } from 'react';
2
+ import './results.css';
3
+ export declare function StatTile({ label, value, detail }: {
4
+ label: string;
5
+ value: ReactNode;
6
+ detail?: ReactNode;
7
+ }): import("react").JSX.Element;
@@ -0,0 +1,22 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import './results.css';
4
+ export function StatTile({ label, value, detail }) {
5
+ return /*#__PURE__*/ _jsxs("div", {
6
+ className: "xp-stat-tile",
7
+ children: [
8
+ /*#__PURE__*/ _jsx("div", {
9
+ className: "xp-stat-tile-label",
10
+ children: label
11
+ }),
12
+ /*#__PURE__*/ _jsx("div", {
13
+ className: "xp-stat-tile-value",
14
+ children: value
15
+ }),
16
+ detail ? /*#__PURE__*/ _jsx("div", {
17
+ className: "xp-stat-tile-detail",
18
+ children: detail
19
+ }) : null
20
+ ]
21
+ });
22
+ }
@@ -0,0 +1,13 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { VerdictCardModel, guardrailChips } from './results.model.js';
3
+ export interface VerdictHeroProps {
4
+ model: VerdictCardModel;
5
+ guardrails?: ReturnType<typeof guardrailChips>;
6
+ power?: string | null;
7
+ collecting?: string | null;
8
+ sinceShipping?: string | null;
9
+ meta?: ReactNode;
10
+ recommendation?: string;
11
+ }
12
+ import './results.css';
13
+ export declare function VerdictHero({ model, guardrails, power, collecting, sinceShipping, meta, recommendation }: VerdictHeroProps): import("react").JSX.Element;
@@ -1,14 +1,9 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { theme } from '../theme.js';
4
- export function VerdictCard({ model, guardrails = [], power, collecting, sinceShipping }) {
3
+ import './results.css';
4
+ export function VerdictHero({ model, guardrails = [], power, collecting, sinceShipping, meta, recommendation }) {
5
5
  return /*#__PURE__*/ _jsxs("section", {
6
- className: "xp-verdict-card",
7
- style: {
8
- color: theme.color.text,
9
- background: theme.color.surface,
10
- padding: '1rem'
11
- },
6
+ className: "xp-verdict-hero",
12
7
  children: [
13
8
  sinceShipping ? /*#__PURE__*/ _jsx("p", {
14
9
  className: "xp-since-shipping",
@@ -30,10 +25,14 @@ export function VerdictCard({ model, guardrails = [], power, collecting, sinceSh
30
25
  className: "xp-collecting",
31
26
  children: collecting
32
27
  }) : null,
33
- guardrails.length > 0 ? /*#__PURE__*/ _jsx("ul", {
34
- className: "xp-guardrails",
28
+ recommendation ? /*#__PURE__*/ _jsx("p", {
29
+ className: "xp-recommendation",
30
+ children: recommendation
31
+ }) : null,
32
+ guardrails.length ? /*#__PURE__*/ _jsx("ul", {
33
+ className: "xp-results-chips",
35
34
  children: guardrails.map((item, index)=>/*#__PURE__*/ _jsxs("li", {
36
- className: "xp-chip",
35
+ className: "xp-tests-kind",
37
36
  children: [
38
37
  item.name,
39
38
  ": ",
@@ -44,7 +43,11 @@ export function VerdictCard({ model, guardrails = [], power, collecting, sinceSh
44
43
  !('title' in model) && power ? /*#__PURE__*/ _jsx("p", {
45
44
  className: "xp-power",
46
45
  children: power
47
- }) : null
46
+ }) : null,
47
+ /*#__PURE__*/ _jsx("div", {
48
+ className: "xp-verdict-meta",
49
+ children: meta
50
+ })
48
51
  ]
49
52
  });
50
53
  }
@@ -0,0 +1,16 @@
1
+ import type { PhaseSummary } from '../../types/endpoints.js';
2
+ import type { ResultsContext } from './results.model.js';
3
+ import type { LegacySnapshot } from './snapshot.js';
4
+ /** Stands in for CORE-15a winnerArm, borrowing the live decision only for the newest rollout. */
5
+ export declare function legacyRolloutLine(snapshot: LegacySnapshot, phase: PhaseSummary, phases: PhaseSummary[], decision?: {
6
+ winnerArm?: string;
7
+ }): string;
8
+ /** Stands in for CORE-15a minExposuresPerArm; absent historical minima keep the old dash. */
9
+ export declare function legacyMinimum(snapshot: LegacySnapshot, ctx: ResultsContext): number | undefined;
10
+ /** Stands in for CORE-15a minExposuresPerArm by deriving the old notice from the frozen verdict. */
11
+ export declare function legacyTooFew(snapshot: LegacySnapshot): boolean;
12
+ /** Stands in for CORE-15a winnerArm in rollout recommendations using the old recommended arm and label. */
13
+ export declare function legacyRecommendationWinner(snapshot: LegacySnapshot, phase?: PhaseSummary): {
14
+ key: string | null;
15
+ label: string;
16
+ };
@@ -0,0 +1,27 @@
1
+ import { RESULTS_COPY, shippingTitle } from '../copy/results.js';
2
+ import { armLabel } from '../labels.js';
3
+ /** Stands in for CORE-15a winnerArm, borrowing the live decision only for the newest rollout. */ export function legacyRolloutLine(snapshot, phase, phases, decision) {
4
+ const newestRollout = phases.filter((phase)=>phase.phaseKind === 'rollout').reduce((latest, phase)=>latest === null || phase.phase > latest ? phase.phase : latest, null);
5
+ const winner = snapshot.winnerArm ?? (snapshot.phase === newestRollout ? decision?.winnerArm : undefined);
6
+ return shippingTitle(winner ? phase.arms.find((arm)=>arm.key === winner)?.label ?? armLabel(winner) : RESULTS_COPY.shippedGroup);
7
+ }
8
+ /** Stands in for CORE-15a minExposuresPerArm; absent historical minima keep the old dash. */ export function legacyMinimum(snapshot, ctx) {
9
+ return snapshot.minExposuresPerArm ?? ctx.minExposuresPerArm;
10
+ }
11
+ /** Stands in for CORE-15a minExposuresPerArm by deriving the old notice from the frozen verdict. */ export function legacyTooFew(snapshot) {
12
+ return snapshot.verdict.code === 'collecting' || snapshot.verdict.code === 'rollout-collecting';
13
+ }
14
+ /** Stands in for CORE-15a winnerArm in rollout recommendations using the old recommended arm and label. */ export function legacyRecommendationWinner(snapshot, phase) {
15
+ const key = snapshot.winnerArm ?? snapshot.verdict.recommendedArm;
16
+ const stored = phase?.arms.find((arm)=>arm.key === key)?.label.trim();
17
+ return {
18
+ key,
19
+ label: stored || (key && [
20
+ 'control',
21
+ 'variantA',
22
+ 'variantB',
23
+ 'variantC',
24
+ 'holdout'
25
+ ].includes(key) ? armLabel(key) : RESULTS_COPY.shippedGroup)
26
+ };
27
+ }
@@ -0,0 +1,17 @@
1
+ import type { DocId } from '../../types/contracts.js';
2
+ export interface PageReleaseDecision {
3
+ winnerArm?: string | null;
4
+ discardedAt?: string | null;
5
+ pagesReleasedAt?: string | null;
6
+ pagesReleasedBy?: string | null;
7
+ }
8
+ /** Mirrors the release-pages transition's gate; permission is checked by the caller. */
9
+ export declare function canReleasePages(doc: {
10
+ kind?: string;
11
+ status: string;
12
+ decision?: PageReleaseDecision | null;
13
+ }): boolean;
14
+ export declare function pagesReleasedBy(by: string | null | undefined, currentUserId?: DocId | null, author?: {
15
+ name?: string | null;
16
+ email?: string | null;
17
+ } | null): string | undefined;
@@ -0,0 +1,10 @@
1
+ import { RESULTS_COPY } from '../copy/results.js';
2
+ /** Mirrors the release-pages transition's gate; permission is checked by the caller. */ export function canReleasePages(doc) {
3
+ const decision = doc.decision;
4
+ return doc.kind === 'page' && doc.status === 'archived' && Boolean(decision?.winnerArm) && !decision?.discardedAt && !decision?.pagesReleasedAt;
5
+ }
6
+ export function pagesReleasedBy(by, currentUserId, author) {
7
+ if (by == null) return undefined;
8
+ if (currentUserId != null && by === String(currentUserId)) return RESULTS_COPY.you;
9
+ return author?.name ?? author?.email ?? undefined;
10
+ }
@@ -0,0 +1,64 @@
1
+ .xp-results { max-width: 1120px; display: grid; gap: var(--xp-space-8); min-width: 0; }
2
+ .xp-results h2, .xp-results h3, .xp-results p { margin: 0; }
3
+ .xp-verdict-hero { background: var(--xp-surface); border: 1px solid var(--xp-border); border-radius: var(--xp-radius-card); padding: 28px; min-width: 0; }
4
+ .xp-verdict-hero h2 { font: var(--xp-text-display); letter-spacing: -0.01em; max-width: 36ch; }
5
+ .xp-verdict-hero p { margin-top: var(--xp-space-2); color: var(--xp-text-2); }
6
+ .xp-verdict-meta { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--xp-space-3); margin-top: var(--xp-space-5); padding-top: var(--xp-space-4); border-top: 1px solid var(--xp-border); color: var(--xp-text-3); font: var(--xp-text-small); }
7
+ .xp-round-meta { display: flex; align-items: center; flex-wrap: wrap; gap: var(--xp-space-2); min-width: 0; }
8
+ .xp-round-meta .xp-ui-field { display: flex; align-items: center; gap: var(--xp-space-2); margin: 0; min-width: 0; }
9
+ .xp-round-meta select { width: auto; max-width: 100%; }
10
+ .xp-results-chips { display: flex; flex-wrap: wrap; gap: var(--xp-space-2); list-style: none; padding: 0; margin-bottom: 0; }
11
+ .xp-stat-tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border: 1px solid var(--xp-border); border-radius: var(--xp-radius-card); background: var(--xp-surface); overflow: hidden; }
12
+ .xp-stat-tile { padding: 20px; min-width: 0; }
13
+ .xp-stat-tile + .xp-stat-tile { border-left: 1px solid var(--xp-border); }
14
+ .xp-stat-tile-label, .xp-stat-tile-detail { font: var(--xp-text-small); color: var(--xp-text-2); }
15
+ .xp-stat-tile-value { margin-top: 6px; font: 600 32px/36px var(--xp-font); font-variant-numeric: tabular-nums; }
16
+ .xp-stat-tile-detail { display: flex; align-items: center; gap: 6px; margin-top: 4px; }
17
+ .xp-results-block { min-width: 0; }
18
+ .xp-results-block-head { display: flex; align-items: baseline; flex-wrap: wrap; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
19
+ .xp-results-block-head h2 { font: var(--xp-text-title); }
20
+ .xp-results-block-meta { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 8px; color: var(--xp-text-2); }
21
+ .xp-data-table-frame { position: relative; min-width: 0; border-radius: var(--xp-radius-card); }
22
+ .xp-data-table-wrap { overflow-x: auto; overflow-y: auto; max-height: 70vh; border: 1px solid var(--xp-border); border-radius: var(--xp-radius-card); background: var(--xp-surface); }
23
+ .xp-data-table-wrap:focus-visible { outline: 2px solid var(--xp-focus); outline-offset: 2px; }
24
+ /* Overlays stay visible above opaque sticky headers and the highlighted row. */
25
+ .xp-data-table-frame::before, .xp-data-table-frame::after { content: ''; position: absolute; top: 1px; bottom: 1px; width: var(--xp-space-6); z-index: 3; pointer-events: none; opacity: 0; }
26
+ .xp-data-table-frame::before { left: 1px; border-radius: var(--xp-radius-card) 0 0 var(--xp-radius-card); background: linear-gradient(to right, var(--xp-border-strong), transparent); }
27
+ .xp-data-table-frame::after { right: 1px; border-radius: 0 var(--xp-radius-card) var(--xp-radius-card) 0; background: linear-gradient(to left, var(--xp-border-strong), transparent); }
28
+ .xp-data-table-frame.has-left::before, .xp-data-table-frame.has-right::after { opacity: 1; }
29
+ .xp-data-table { width: 100%; border-collapse: separate; border-spacing: 0; font: 400 14px/20px var(--xp-font); }
30
+ .xp-data-table caption { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
31
+ .xp-data-table th, .xp-data-table td { padding: 12px 14px; white-space: nowrap; border-bottom: 1px solid var(--xp-border); text-align: left; }
32
+ .xp-data-table thead th { position: sticky; top: 0; z-index: 1; background: var(--xp-surface); font: var(--xp-text-small); color: var(--xp-text-2); }
33
+ .xp-data-table tr > :first-child { position: sticky; left: 0; z-index: 1; background: var(--xp-surface); }
34
+ .xp-data-table thead tr > :first-child { z-index: 2; }
35
+ .xp-data-table tbody th { font-weight: 400; }
36
+ .xp-data-table .num { text-align: right; font-variant-numeric: tabular-nums; }
37
+ .xp-data-table .muted { color: var(--xp-text-3); }
38
+ .xp-data-table tr:last-child > * { border-bottom: 0; }
39
+ .xp-data-table tr.is-lead > * { background: var(--xp-surface-2); font-weight: 600; }
40
+ .xp-results-group { display: inline-flex; align-items: center; gap: 8px; }
41
+ .xp-results-swatch { display: inline-block; width: 10px; height: 10px; border-radius: 3px; flex: none; }
42
+ .xp-results-panel { border: 1px solid var(--xp-border); border-radius: var(--xp-radius-card); background: var(--xp-surface); min-width: 0; }
43
+ .xp-results-panel > summary { padding: 16px 20px; cursor: pointer; font: var(--xp-text-title); }
44
+ .xp-results-panel > summary:focus-visible { outline: 2px solid var(--xp-focus); outline-offset: 2px; }
45
+ .xp-results-panel > summary .xp-quality-chip { margin-left: 12px; }
46
+ .xp-quality-row { padding: 14px 20px; border-top: 1px solid var(--xp-border); display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 4px 14px; }
47
+ .xp-quality-row > :not(:first-child) { grid-column: 2; }
48
+ .xp-quality-row ul { margin: 0; padding-left: 20px; }
49
+ .xp-quality-detail, .xp-quality-next, .xp-results-cap-help { color: var(--xp-text-2); font: var(--xp-text-small); }
50
+ .xp-quality-chip { display: inline-flex; align-self: start; padding: 2px 8px; border-radius: var(--xp-radius-chip); font: var(--xp-text-small); color: var(--xp-success); background: var(--xp-success-bg); }
51
+ .xp-quality-chip--watch { color: var(--xp-warning); background: var(--xp-warning-bg); }
52
+ .xp-quality-chip--problem { color: var(--xp-error); background: var(--xp-error-bg); }
53
+ .xp-ci-chart { padding: 20px; overflow-x: auto; }
54
+ .xp-ci-chart svg { display: block; min-width: 560px; }
55
+ .xp-ci-chart ul { display: flex; flex-wrap: wrap; gap: 16px; list-style: none; margin: 0; padding: 0; font: var(--xp-text-small); }
56
+ .xp-preview-links { display: grid; gap: 12px; }
57
+ .xp-preview-row { display: flex; align-items: center; flex-wrap: wrap; justify-content: space-between; gap: 12px; border-bottom: 1px solid var(--xp-border); padding-bottom: 12px; }
58
+ @media (max-width: 720px) {
59
+ .xp-stat-tiles { grid-template-columns: minmax(0, 1fr); }
60
+ .xp-stat-tile + .xp-stat-tile { border-left: 0; border-top: 1px solid var(--xp-border); }
61
+ .xp-verdict-hero { padding: 20px; }
62
+ .xp-verdict-hero h2 { font-size: 24px; line-height: 30px; }
63
+ }
64
+ .xp-results-as-of { color: var(--xp-text-2); }
@@ -1,13 +1,13 @@
1
1
  import type { DocId, Status } from '../../types/contracts.js';
2
2
  import type { PhaseSummary, ResultsResponse } from '../../types/endpoints.js';
3
3
  import type { Snapshot } from '../../types/snapshot.js';
4
+ import { type DisplaySnapshot } from './snapshot.js';
4
5
  type Metric = Snapshot['metrics'][number];
5
6
  type Arm = Metric['perArm'][number];
6
7
  type Decision = {
7
8
  phase: number;
8
9
  winnerArm?: string;
9
10
  };
10
- type DisplaySnapshot = Snapshot;
11
11
  export declare function defaultRound({ phases, decision, status }: Pick<ResultsResponse, 'phases'> & {
12
12
  decision?: Decision | null;
13
13
  status: Status;
@@ -26,8 +26,8 @@ export type VerdictCardModel = {
26
26
  guardrailLine?: string;
27
27
  };
28
28
  export declare function verdictCard({ snapshot, decisionSnapshot, isDecidedTestRound, winnerLabel }: {
29
- snapshot: Snapshot;
30
- decisionSnapshot?: Snapshot;
29
+ snapshot: DisplaySnapshot;
30
+ decisionSnapshot?: DisplaySnapshot;
31
31
  isDecidedTestRound: boolean;
32
32
  winnerLabel: string;
33
33
  }): VerdictCardModel;
@@ -66,17 +66,20 @@ export interface ArmRow {
66
66
  n: string;
67
67
  value: string;
68
68
  capped: CappedCellModel;
69
+ rate?: string;
70
+ lift?: string;
71
+ chanceToWin?: string;
69
72
  baseline?: string;
70
73
  comparison?: ComparisonModel;
71
74
  }
72
75
  export declare function armRows({ snapshot, phase, metricId }: {
73
- snapshot: Snapshot;
76
+ snapshot: DisplaySnapshot;
74
77
  phase: PhaseSummary;
75
78
  metricId: DocId;
76
79
  }): ArmRow[];
77
- export declare function guardrailChips(snapshot: Snapshot): {
80
+ export declare function guardrailChips(snapshot: DisplaySnapshot): {
78
81
  name: string;
79
- status: "Failing" | "OK" | "Watch" | "Too little data";
82
+ status: "OK" | "Watch" | "Failing" | "Too little data";
80
83
  }[];
81
84
  interface RoundLineInput {
82
85
  snapshot: DisplaySnapshot;
@@ -85,6 +88,7 @@ interface RoundLineInput {
85
88
  }
86
89
  export declare function powerLine({ snapshot, phaseKind, status }: RoundLineInput): string | null;
87
90
  export interface ResultsContext {
91
+ status?: string;
88
92
  phase?: PhaseSummary;
89
93
  minExposuresPerArm?: number;
90
94
  inLayer?: boolean;
@@ -101,5 +105,5 @@ export interface DataQualityItem {
101
105
  shares?: string[];
102
106
  }
103
107
  export declare function dataQuality(snapshot: DisplaySnapshot, ctx?: ResultsContext): DataQualityItem[];
104
- export declare function verdictLabel(snapshot: Snapshot): string;
108
+ export declare function verdictLabel(snapshot: DisplaySnapshot): string;
105
109
  export {};