@delmaredigital/payload-experiments 0.1.0-rc.7 → 0.2.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/README.md +28 -0
  2. package/dist/admin/LayerUsage.d.ts +1 -1
  3. package/dist/admin/LayerUsage.js +23 -11
  4. package/dist/admin/MetricSourceSelect.js +2 -1
  5. package/dist/admin/TestsNavLink.d.ts +1 -0
  6. package/dist/admin/TestsNavLink.js +30 -0
  7. package/dist/admin/allocation.model.js +1 -1
  8. package/dist/admin/copy/actions.d.ts +0 -2
  9. package/dist/admin/copy/actions.js +0 -2
  10. package/dist/admin/copy/advanced.d.ts +55 -0
  11. package/dist/admin/copy/advanced.js +55 -0
  12. package/dist/admin/copy/armSelect.js +1 -1
  13. package/dist/admin/copy/arms.d.ts +0 -13
  14. package/dist/admin/copy/arms.js +0 -13
  15. package/dist/admin/copy/{who.d.ts → audience.d.ts} +1 -9
  16. package/dist/admin/copy/{who.js → audience.js} +1 -9
  17. package/dist/admin/copy/history.d.ts +0 -4
  18. package/dist/admin/copy/history.js +3 -7
  19. package/dist/admin/copy/metrics.d.ts +2 -2
  20. package/dist/admin/copy/metrics.js +2 -2
  21. package/dist/admin/copy/newTest.d.ts +32 -0
  22. package/dist/admin/copy/newTest.js +32 -0
  23. package/dist/admin/copy/readiness.d.ts +45 -0
  24. package/dist/admin/copy/readiness.js +50 -0
  25. package/dist/admin/copy/recommendation.d.ts +26 -0
  26. package/dist/admin/copy/recommendation.js +25 -0
  27. package/dist/admin/copy/results.d.ts +0 -1
  28. package/dist/admin/copy/results.js +0 -1
  29. package/dist/admin/copy/review.d.ts +0 -17
  30. package/dist/admin/copy/review.js +1 -112
  31. package/dist/admin/copy/setting.d.ts +10 -0
  32. package/dist/admin/copy/setting.js +10 -0
  33. package/dist/admin/copy/surface.d.ts +36 -0
  34. package/dist/admin/copy/surface.js +47 -0
  35. package/dist/admin/copy/testPage.d.ts +88 -0
  36. package/dist/admin/copy/testPage.js +88 -0
  37. package/dist/admin/paths.d.ts +5 -13
  38. package/dist/admin/paths.js +5 -13
  39. package/dist/admin/review/review.model.d.ts +3 -26
  40. package/dist/admin/review/review.model.js +3 -30
  41. package/dist/admin/surface/ResultsRoute.d.ts +7 -0
  42. package/dist/admin/surface/ResultsRoute.js +58 -0
  43. package/dist/admin/surface/SurfaceShell.d.ts +6 -0
  44. package/dist/admin/surface/SurfaceShell.js +35 -0
  45. package/dist/admin/surface/TestsHome.d.ts +4 -0
  46. package/dist/admin/surface/TestsHome.js +212 -0
  47. package/dist/admin/surface/TestsSurface.d.ts +2 -0
  48. package/dist/admin/surface/TestsSurface.js +36 -0
  49. package/dist/admin/surface/contracts.d.ts +48 -0
  50. package/dist/admin/surface/contracts.js +8 -0
  51. package/dist/admin/surface/home.model.d.ts +41 -0
  52. package/dist/admin/surface/home.model.js +59 -0
  53. package/dist/admin/surface/newTest/NewTest.d.ts +7 -0
  54. package/dist/admin/surface/newTest/NewTest.js +355 -0
  55. package/dist/admin/surface/newTest/newTest.css +9 -0
  56. package/dist/admin/surface/pageBlock/pageBlock.model.d.ts +6 -0
  57. package/dist/admin/surface/pageBlock/pageBlock.model.js +8 -0
  58. package/dist/admin/surface/pageBlock/parts.d.ts +2 -0
  59. package/dist/admin/surface/pageBlock/parts.js +64 -0
  60. package/dist/admin/surface/readiness/ActionDialogs.d.ts +15 -0
  61. package/dist/admin/surface/readiness/ActionDialogs.js +274 -0
  62. package/dist/admin/surface/readiness/Banner.d.ts +2 -0
  63. package/dist/admin/surface/readiness/Banner.js +138 -0
  64. package/dist/admin/surface/readiness/SaveStatus.d.ts +4 -0
  65. package/dist/admin/surface/readiness/SaveStatus.js +50 -0
  66. package/dist/admin/surface/readiness/parts.d.ts +2 -0
  67. package/dist/admin/surface/readiness/parts.js +9 -0
  68. package/dist/admin/surface/readiness/readiness.model.d.ts +22 -0
  69. package/dist/admin/surface/readiness/readiness.model.js +107 -0
  70. package/dist/admin/surface/readiness/useTransition.d.ts +10 -0
  71. package/dist/admin/surface/readiness/useTransition.js +34 -0
  72. package/dist/admin/surface/results/ResultsBody.d.ts +7 -0
  73. package/dist/admin/surface/results/ResultsBody.js +262 -0
  74. package/dist/admin/surface/results/recommendation.model.d.ts +12 -0
  75. package/dist/admin/surface/results/recommendation.model.js +59 -0
  76. package/dist/admin/surface/results/useResults.d.ts +56 -0
  77. package/dist/admin/surface/results/useResults.js +183 -0
  78. package/dist/admin/surface/setting/parts.d.ts +3 -0
  79. package/dist/admin/surface/setting/parts.js +263 -0
  80. package/dist/admin/surface/setting/setting.css +29 -0
  81. package/dist/admin/surface/setting/setting.model.d.ts +8 -0
  82. package/dist/admin/surface/setting/setting.model.js +25 -0
  83. package/dist/admin/surface/surface.css +50 -0
  84. package/dist/admin/surface/test/AdvancedSection.d.ts +2 -0
  85. package/dist/admin/surface/test/AdvancedSection.js +153 -0
  86. package/dist/admin/surface/test/GoalSection.d.ts +2 -0
  87. package/dist/admin/surface/test/GoalSection.js +198 -0
  88. package/dist/admin/surface/test/LengthSection.d.ts +2 -0
  89. package/dist/admin/surface/test/LengthSection.js +87 -0
  90. package/dist/admin/surface/test/Section.d.ts +7 -0
  91. package/dist/admin/surface/test/Section.js +27 -0
  92. package/dist/admin/surface/test/TargetingSection.d.ts +2 -0
  93. package/dist/admin/surface/test/TargetingSection.js +164 -0
  94. package/dist/admin/surface/test/TestHeader.d.ts +4 -0
  95. package/dist/admin/surface/test/TestHeader.js +69 -0
  96. package/dist/admin/surface/test/TestPage.d.ts +7 -0
  97. package/dist/admin/surface/test/TestPage.js +84 -0
  98. package/dist/admin/surface/test/VersionsSection.d.ts +4 -0
  99. package/dist/admin/surface/test/VersionsSection.js +208 -0
  100. package/dist/admin/surface/test/fields.d.ts +55 -0
  101. package/dist/admin/surface/test/fields.js +185 -0
  102. package/dist/admin/surface/test/pageParts.d.ts +2 -0
  103. package/dist/admin/surface/test/pageParts.js +39 -0
  104. package/dist/admin/surface/test/testPage.css +23 -0
  105. package/dist/admin/surface/test/testPage.model.d.ts +17 -0
  106. package/dist/admin/surface/test/testPage.model.js +53 -0
  107. package/dist/admin/surface/testDocument.model.d.ts +39 -0
  108. package/dist/admin/surface/testDocument.model.js +61 -0
  109. package/dist/admin/surface/useTestDocument.d.ts +22 -0
  110. package/dist/admin/surface/useTestDocument.js +345 -0
  111. package/dist/admin/targeting/targeting.model.js +2 -2
  112. package/dist/admin/useLayerUsage.d.ts +0 -5
  113. package/dist/admin/useLayerUsage.js +1 -39
  114. package/dist/admin/views/CollectionEditRedirect.d.ts +4 -0
  115. package/dist/admin/views/CollectionEditRedirect.js +14 -0
  116. package/dist/admin/views/CollectionListRedirect.d.ts +2 -0
  117. package/dist/admin/views/CollectionListRedirect.js +8 -0
  118. package/dist/admin/views/ExperimentsRootView.d.ts +2 -0
  119. package/dist/admin/views/ExperimentsRootView.js +175 -0
  120. package/dist/admin/views/access.model.d.ts +7 -0
  121. package/dist/admin/views/access.model.js +5 -0
  122. package/dist/collections/experiments/config.js +18 -125
  123. package/dist/collections/experiments/createDefaults.js +6 -0
  124. package/dist/collections/layers.js +43 -12
  125. package/dist/collections/metrics.js +70 -14
  126. package/dist/collections/serialize.js +4 -1
  127. package/dist/db/snapshots.d.ts +2 -1
  128. package/dist/db/snapshots.js +2 -2
  129. package/dist/endpoints/results.js +7 -0
  130. package/dist/endpoints/summary.d.ts +1 -1
  131. package/dist/endpoints/summary.js +37 -1
  132. package/dist/exports/adminClient.d.ts +2 -13
  133. package/dist/exports/adminClient.js +2 -13
  134. package/dist/exports/adminRsc.d.ts +3 -0
  135. package/dist/exports/adminRsc.js +3 -0
  136. package/dist/exports/index.d.ts +1 -1
  137. package/dist/options.js +29 -0
  138. package/dist/plugin.js +25 -0
  139. package/dist/puck/editor/CreateExperimentDrawer.d.ts +2 -1
  140. package/dist/puck/editor/CreateExperimentDrawer.js +17 -57
  141. package/dist/puck/editor/ExperimentSlotEditor.js +6 -0
  142. package/dist/puck/editor/copy.d.ts +10 -9
  143. package/dist/puck/editor/copy.js +11 -10
  144. package/dist/puck/editor/createTest.d.ts +7 -0
  145. package/dist/puck/editor/createTest.js +50 -0
  146. package/dist/puck/editor/editor.model.d.ts +28 -1
  147. package/dist/puck/editor/editor.model.js +61 -0
  148. package/dist/results/analyse.js +4 -1
  149. package/dist/results/verdict.d.ts +1 -0
  150. package/dist/results/verdict.js +7 -4
  151. package/dist/transitions/checkStart.d.ts +1 -0
  152. package/dist/transitions/placements.d.ts +5 -1
  153. package/dist/transitions/placements.js +14 -7
  154. package/dist/transitions/preflightData.d.ts +7 -1
  155. package/dist/transitions/preflightData.js +199 -148
  156. package/dist/transitions/start.js +2 -2
  157. package/dist/types/admin.d.ts +1 -0
  158. package/dist/types/contracts.d.ts +17 -0
  159. package/dist/types/endpoints.d.ts +11 -1
  160. package/dist/types/snapshot.d.ts +1 -0
  161. package/dist/types/surface.d.ts +29 -0
  162. package/dist/types/surface.js +1 -0
  163. package/package.json +7 -1
  164. package/dist/access.d.ts +0 -1
  165. package/dist/access.js +0 -2
  166. package/dist/admin/AllocationField.d.ts +0 -2
  167. package/dist/admin/AllocationField.js +0 -80
  168. package/dist/admin/FlagPointSelect.d.ts +0 -2
  169. package/dist/admin/FlagPointSelect.js +0 -54
  170. package/dist/admin/LockedFieldNotice.d.ts +0 -2
  171. package/dist/admin/LockedFieldNotice.js +0 -26
  172. package/dist/admin/PhaseHistory.d.ts +0 -2
  173. package/dist/admin/PhaseHistory.js +0 -76
  174. package/dist/admin/StatusCell.d.ts +0 -3
  175. package/dist/admin/StatusCell.js +0 -19
  176. package/dist/admin/SummaryCell.d.ts +0 -2
  177. package/dist/admin/SummaryCell.js +0 -32
  178. package/dist/admin/actions/AddMetricDialog.d.ts +0 -6
  179. package/dist/admin/actions/AddMetricDialog.js +0 -138
  180. package/dist/admin/actions/AllocateDialog.d.ts +0 -6
  181. package/dist/admin/actions/AllocateDialog.js +0 -81
  182. package/dist/admin/actions/ExperimentActions.d.ts +0 -3
  183. package/dist/admin/actions/ExperimentActions.js +0 -110
  184. package/dist/admin/arms/ArmsField.d.ts +0 -2
  185. package/dist/admin/arms/ArmsField.js +0 -310
  186. package/dist/admin/arms/ParamsEditor.d.ts +0 -16
  187. package/dist/admin/arms/ParamsEditor.js +0 -79
  188. package/dist/admin/copy/tabs.d.ts +0 -7
  189. package/dist/admin/copy/tabs.js +0 -7
  190. package/dist/admin/permissions.model.d.ts +0 -10
  191. package/dist/admin/permissions.model.js +0 -4
  192. package/dist/admin/phaseHistory.model.d.ts +0 -19
  193. package/dist/admin/phaseHistory.model.js +0 -19
  194. package/dist/admin/results/ResultsView.d.ts +0 -3
  195. package/dist/admin/results/ResultsView.js +0 -312
  196. package/dist/admin/review/ReviewPanel.d.ts +0 -2
  197. package/dist/admin/review/ReviewPanel.js +0 -268
  198. package/dist/admin/summaryBatcher.d.ts +0 -8
  199. package/dist/admin/summaryBatcher.js +0 -33
  200. package/dist/admin/targeting/TargetingAttributeField.d.ts +0 -2
  201. package/dist/admin/targeting/TargetingAttributeField.js +0 -31
  202. package/dist/admin/targeting/TargetingOpField.d.ts +0 -2
  203. package/dist/admin/targeting/TargetingOpField.js +0 -45
  204. package/dist/admin/targeting/TargetingValueField.d.ts +0 -2
  205. package/dist/admin/targeting/TargetingValueField.js +0 -142
  206. package/dist/index.d.ts +0 -1
  207. package/dist/index.js +0 -4
@@ -0,0 +1,6 @@
1
+ import type { ReactNode } from 'react';
2
+ import './surface.css';
3
+ export declare function SurfaceShell({ adminRoute, children }: {
4
+ adminRoute: string;
5
+ children: ReactNode;
6
+ }): import("react").JSX.Element;
@@ -0,0 +1,35 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Link } from '@payloadcms/ui';
4
+ import { formatAdminURL } from 'payload/shared';
5
+ import { SURFACE_COPY } from '../copy/surface.js';
6
+ import './surface.css';
7
+ export function SurfaceShell({ adminRoute, children }) {
8
+ return /*#__PURE__*/ _jsxs("div", {
9
+ className: "xp-tests-surface",
10
+ children: [
11
+ /*#__PURE__*/ _jsxs("header", {
12
+ className: "xp-tests-shell-header",
13
+ children: [
14
+ /*#__PURE__*/ _jsx(Link, {
15
+ href: formatAdminURL({
16
+ adminRoute,
17
+ path: '/experiments'
18
+ }),
19
+ children: SURFACE_COPY.title
20
+ }),
21
+ /*#__PURE__*/ _jsx(Link, {
22
+ href: formatAdminURL({
23
+ adminRoute
24
+ }),
25
+ children: SURFACE_COPY.backToAdmin
26
+ })
27
+ ]
28
+ }),
29
+ /*#__PURE__*/ _jsx("main", {
30
+ className: "xp-tests-main",
31
+ children: children
32
+ })
33
+ ]
34
+ });
35
+ }
@@ -0,0 +1,4 @@
1
+ export declare function TestsHome({ adminRoute, apiRoute }: {
2
+ adminRoute: string;
3
+ apiRoute: string;
4
+ }): import("react").JSX.Element;
@@ -0,0 +1,212 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useEffect, useMemo, useState } from 'react';
4
+ import { Link, Pill } from '@payloadcms/ui';
5
+ import { formatAdminURL } from 'payload/shared';
6
+ import { createApi } from '../api.js';
7
+ import { SURFACE_COPY } from '../copy/surface.js';
8
+ import { groupTests, homeCard } from './home.model.js';
9
+ export function TestsHome({ adminRoute, apiRoute }) {
10
+ const api = useMemo(()=>createApi(apiRoute), [
11
+ apiRoute
12
+ ]);
13
+ const [state, setState] = useState({
14
+ loading: true
15
+ });
16
+ const [search, setSearch] = useState('');
17
+ const [attempt, setAttempt] = useState(0);
18
+ useEffect(()=>{
19
+ let active = true;
20
+ const controller = new AbortController();
21
+ setState({
22
+ loading: true
23
+ });
24
+ async function load() {
25
+ try {
26
+ const response = await fetch(`${apiRoute.replace(/\/$/, '')}/xp-experiments?depth=0&sort=-updatedAt&limit=200`, {
27
+ credentials: 'include',
28
+ signal: controller.signal
29
+ });
30
+ if (!response.ok) throw new Error('list');
31
+ const { docs, totalDocs } = await response.json();
32
+ if (!active) return;
33
+ const summary = await api.summary(docs.map((doc)=>doc.id));
34
+ if (active) setState({
35
+ loading: false,
36
+ error: false,
37
+ tests: docs,
38
+ limited: totalDocs > docs.length,
39
+ summaries: summary.ok ? summary.data ?? {} : {},
40
+ summaryError: !summary.ok
41
+ });
42
+ } catch {
43
+ if (active) setState({
44
+ loading: false,
45
+ error: true
46
+ });
47
+ }
48
+ }
49
+ void load();
50
+ return ()=>{
51
+ active = false;
52
+ controller.abort();
53
+ };
54
+ }, [
55
+ api,
56
+ apiRoute,
57
+ attempt
58
+ ]);
59
+ const retry = /*#__PURE__*/ _jsx("button", {
60
+ type: "button",
61
+ onClick: ()=>setAttempt((value)=>value + 1),
62
+ children: SURFACE_COPY.retry
63
+ });
64
+ const newTest = /*#__PURE__*/ _jsx(Link, {
65
+ className: "xp-tests-primary",
66
+ href: formatAdminURL({
67
+ adminRoute,
68
+ path: '/experiments/new'
69
+ }),
70
+ children: SURFACE_COPY.newTest
71
+ });
72
+ return /*#__PURE__*/ _jsxs(_Fragment, {
73
+ children: [
74
+ /*#__PURE__*/ _jsxs("div", {
75
+ className: "xp-tests-toolbar",
76
+ children: [
77
+ /*#__PURE__*/ _jsx("h1", {
78
+ children: SURFACE_COPY.title
79
+ }),
80
+ /*#__PURE__*/ _jsxs("label", {
81
+ children: [
82
+ SURFACE_COPY.search,
83
+ /*#__PURE__*/ _jsx("input", {
84
+ type: "search",
85
+ value: search,
86
+ onChange: (event)=>setSearch(event.target.value)
87
+ })
88
+ ]
89
+ }),
90
+ newTest,
91
+ /*#__PURE__*/ _jsx(Link, {
92
+ href: formatAdminURL({
93
+ adminRoute,
94
+ path: '/collections/xp-metrics'
95
+ }),
96
+ children: SURFACE_COPY.goals
97
+ })
98
+ ]
99
+ }),
100
+ state.loading ? /*#__PURE__*/ _jsx("p", {
101
+ role: "status",
102
+ children: SURFACE_COPY.loading
103
+ }) : state.error ? /*#__PURE__*/ _jsxs("div", {
104
+ role: "alert",
105
+ children: [
106
+ SURFACE_COPY.loadError,
107
+ " ",
108
+ retry
109
+ ]
110
+ }) : /*#__PURE__*/ _jsxs(_Fragment, {
111
+ children: [
112
+ state.limited ? /*#__PURE__*/ _jsx("p", {
113
+ children: SURFACE_COPY.limitedList
114
+ }) : null,
115
+ state.summaryError ? /*#__PURE__*/ _jsxs("div", {
116
+ role: "alert",
117
+ children: [
118
+ SURFACE_COPY.summaryError,
119
+ " ",
120
+ retry
121
+ ]
122
+ }) : null,
123
+ state.tests.length === 0 ? /*#__PURE__*/ _jsxs("div", {
124
+ children: [
125
+ /*#__PURE__*/ _jsx("p", {
126
+ children: SURFACE_COPY.empty
127
+ }),
128
+ newTest
129
+ ]
130
+ }) : /*#__PURE__*/ _jsx(TestGroups, {
131
+ tests: state.tests,
132
+ summaries: state.summaries,
133
+ adminRoute: adminRoute,
134
+ search: search
135
+ })
136
+ ]
137
+ })
138
+ ]
139
+ });
140
+ }
141
+ function TestGroups({ tests, summaries, adminRoute, search }) {
142
+ const groups = groupTests(tests, summaries, search);
143
+ if (!groups.some((group)=>group.tests.length)) return /*#__PURE__*/ _jsx("p", {
144
+ children: SURFACE_COPY.noMatches
145
+ });
146
+ return /*#__PURE__*/ _jsx(_Fragment, {
147
+ children: groups.map((group, index)=>{
148
+ if (!group.tests.length) return null;
149
+ const cards = /*#__PURE__*/ _jsx("div", {
150
+ className: "xp-tests-cards",
151
+ children: group.tests.map((test)=>{
152
+ const card = homeCard(test, summaries[test.id], adminRoute);
153
+ return /*#__PURE__*/ _jsxs("article", {
154
+ className: "xp-tests-card",
155
+ children: [
156
+ /*#__PURE__*/ _jsxs("div", {
157
+ className: "xp-tests-card-heading",
158
+ children: [
159
+ /*#__PURE__*/ _jsx("h3", {
160
+ children: test.name
161
+ }),
162
+ /*#__PURE__*/ _jsx("span", {
163
+ children: card.kind
164
+ }),
165
+ /*#__PURE__*/ _jsx("span", {
166
+ title: card.pill.tooltip,
167
+ children: /*#__PURE__*/ _jsx(Pill, {
168
+ children: card.pill.label
169
+ })
170
+ }),
171
+ test.status === 'running' && card.health ? /*#__PURE__*/ _jsx("span", {
172
+ role: "img",
173
+ "aria-label": SURFACE_COPY.health[card.health],
174
+ className: `xp-tests-health xp-tests-health--${card.health}`
175
+ }) : null
176
+ ]
177
+ }),
178
+ /*#__PURE__*/ _jsx("p", {
179
+ children: card.line
180
+ }),
181
+ card.headline ? /*#__PURE__*/ _jsx("p", {
182
+ children: card.headline
183
+ }) : null,
184
+ /*#__PURE__*/ _jsx(Link, {
185
+ href: card.href,
186
+ children: card.action
187
+ })
188
+ ]
189
+ }, test.id);
190
+ })
191
+ });
192
+ return index === 5 ? /*#__PURE__*/ _jsxs("details", {
193
+ className: "xp-tests-group",
194
+ children: [
195
+ /*#__PURE__*/ _jsx("summary", {
196
+ children: group.label
197
+ }),
198
+ cards
199
+ ]
200
+ }, group.label) : /*#__PURE__*/ _jsxs("section", {
201
+ className: "xp-tests-group",
202
+ "aria-label": group.label,
203
+ children: [
204
+ /*#__PURE__*/ _jsx("h2", {
205
+ children: group.label
206
+ }),
207
+ cards
208
+ ]
209
+ }, group.label);
210
+ })
211
+ });
212
+ }
@@ -0,0 +1,2 @@
1
+ import type { TestsSurfaceProps } from '../../types/surface.js';
2
+ export declare function TestsSurface(props: TestsSurfaceProps): import("react").JSX.Element;
@@ -0,0 +1,36 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { NewTest } from './newTest/NewTest.js';
4
+ import { TestPage } from './test/TestPage.js';
5
+ import { ResultsRoute } from './ResultsRoute.js';
6
+ import { SurfaceShell } from './SurfaceShell.js';
7
+ import { TestsHome } from './TestsHome.js';
8
+ export function TestsSurface(props) {
9
+ const surface = {
10
+ adminRoute: props.adminRoute,
11
+ apiRoute: props.apiRoute,
12
+ canManage: props.canManage,
13
+ canReadResults: props.canReadResults,
14
+ isAdmin: props.isAdmin,
15
+ flagPoints: props.flagPoints,
16
+ attributeKeys: props.attributeKeys,
17
+ metricSources: props.metricSources,
18
+ descriptions: props.admin?.descriptions
19
+ };
20
+ return /*#__PURE__*/ _jsx(SurfaceShell, {
21
+ adminRoute: props.adminRoute,
22
+ children: props.route === 'home' ? /*#__PURE__*/ _jsx(TestsHome, {
23
+ adminRoute: props.adminRoute,
24
+ apiRoute: props.apiRoute
25
+ }) : props.route === 'new' ? /*#__PURE__*/ _jsx(NewTest, {
26
+ surface: surface,
27
+ pages: props.pages
28
+ }) : props.id === undefined ? null : props.route === 'test' ? /*#__PURE__*/ _jsx(TestPage, {
29
+ id: props.id,
30
+ surface: surface
31
+ }, props.id) : /*#__PURE__*/ _jsx(ResultsRoute, {
32
+ id: props.id,
33
+ surface: surface
34
+ }, props.id)
35
+ });
36
+ }
@@ -0,0 +1,48 @@
1
+ import type { ComponentType } from 'react';
2
+ import type { SerializedAttributeKeys, SerializedFlagPoint, SerializedMetricSource } from '../../types/admin.js';
3
+ import type { useTestDocument } from './useTestDocument.js';
4
+ /** Sections of the test page, in readiness order (surface spec §6.2, §8). */
5
+ export type SectionId = 'what' | 'versions' | 'win' | 'who' | 'length' | 'advanced';
6
+ export declare const SECTION_ORDER: readonly SectionId[];
7
+ /** The data layer's return value; every section takes it as `test`. */
8
+ export type TestDocApi = ReturnType<typeof useTestDocument>;
9
+ /** Serialisable props the server root view passes to the surface (ADM-20). */
10
+ export interface SurfaceProps {
11
+ adminRoute: string;
12
+ apiRoute: string;
13
+ canManage: boolean;
14
+ canReadResults: boolean;
15
+ isAdmin: boolean;
16
+ flagPoints: SerializedFlagPoint[];
17
+ attributeKeys: SerializedAttributeKeys;
18
+ metricSources: SerializedMetricSource[];
19
+ descriptions?: {
20
+ block?: string;
21
+ document?: string;
22
+ setting?: string;
23
+ };
24
+ }
25
+ export interface SectionProps {
26
+ test: TestDocApi;
27
+ surface: SurfaceProps;
28
+ }
29
+ /** Kind-specific pieces the generic test page composes (Setting kind: ADM-22). */
30
+ export interface KindParts {
31
+ /** Section 1 body for this kind. */
32
+ Binding: ComponentType<SectionProps>;
33
+ /** The content cell of one version row in Section 2. */
34
+ VersionContent: ComponentType<SectionProps & {
35
+ armIndex: number;
36
+ }>;
37
+ }
38
+ /** Readiness pieces (ADM-23). */
39
+ export interface ReadinessParts {
40
+ /** Sticky-header banner incl. Start / status sentence. */
41
+ Banner: ComponentType<SectionProps>;
42
+ /** "Saving…" / "Saved" / error indicator for the header. */
43
+ SaveStatus: ComponentType<{
44
+ test: TestDocApi;
45
+ }>;
46
+ /** Check-circle state per section, from preflight. */
47
+ sectionDone(test: TestDocApi): Record<SectionId, boolean>;
48
+ }
@@ -0,0 +1,8 @@
1
+ export const SECTION_ORDER = [
2
+ 'what',
3
+ 'versions',
4
+ 'win',
5
+ 'who',
6
+ 'length',
7
+ 'advanced'
8
+ ];
@@ -0,0 +1,41 @@
1
+ import type { DocId, ExperimentKind, Status } from '../../types/contracts.js';
2
+ import type { SummaryResponse } from '../../types/endpoints.js';
3
+ export interface HomeTest {
4
+ id: DocId;
5
+ name: string;
6
+ kind: ExperimentKind;
7
+ status: Status;
8
+ analysis?: {
9
+ plannedDurationDays?: number | null;
10
+ } | null;
11
+ arms?: Array<{
12
+ key: string;
13
+ label?: string;
14
+ }> | null;
15
+ decidedAt?: string | null;
16
+ decision?: {
17
+ winnerArm?: string | null;
18
+ holdoutReleasedAt?: string | null;
19
+ } | null;
20
+ }
21
+ type Summary = SummaryResponse[DocId] | undefined;
22
+ export type Health = 'red' | 'amber' | 'green';
23
+ export declare function healthDot(test: HomeTest, summary: Summary): Health | undefined;
24
+ export declare function groupTests(tests: readonly HomeTest[], summaries: SummaryResponse, search?: string): {
25
+ label: "Draft" | "Running" | "Decided" | "Archived" | "Needs attention" | "Ready to start";
26
+ tests: HomeTest[];
27
+ }[];
28
+ export declare function homeCard(test: HomeTest, summary: Summary, adminRoute: string): {
29
+ kind: "Whole page" | "Page block" | "Setting";
30
+ pill: {
31
+ label: string;
32
+ tone: import("../status.model.js").PillTone;
33
+ tooltip: string;
34
+ };
35
+ line: string;
36
+ headline: string | undefined;
37
+ health: Health | undefined;
38
+ href: string;
39
+ action: "Continue setup" | "View results" | "Open";
40
+ };
41
+ export {};
@@ -0,0 +1,59 @@
1
+ import { formatAdminURL } from 'payload/shared';
2
+ import { armLabel } from '../labels.js';
3
+ import { statusPill } from '../status.model.js';
4
+ import { decidedLine, runningLine, SURFACE_COPY } from '../copy/surface.js';
5
+ export function healthDot(test, summary) {
6
+ const code = summary?.verdict?.code;
7
+ if (!code) return undefined;
8
+ if (code === 'data-problem' || code === 'guardrail-failing') return 'red';
9
+ if (code === 'unavailable' || code === 'collecting' && test.analysis?.plannedDurationDays != null && summary.days > test.analysis.plannedDurationDays) return 'amber';
10
+ return 'green';
11
+ }
12
+ export function groupTests(tests, summaries, search = '') {
13
+ const groups = SURFACE_COPY.groups.map((label)=>({
14
+ label,
15
+ tests: []
16
+ }));
17
+ const query = search.trim().toLocaleLowerCase('en-US');
18
+ for (const test of tests){
19
+ if (!test.name.toLocaleLowerCase('en-US').includes(query)) continue;
20
+ const summary = summaries[test.id];
21
+ const health = healthDot(test, summary);
22
+ const index = test.status === 'running' ? health === 'red' || health === 'amber' ? 0 : 1 : test.status === 'decided' ? 4 : test.status === 'archived' ? 5 : summary?.ready === true ? 2 : 3;
23
+ groups[index].tests.push(test);
24
+ }
25
+ return groups;
26
+ }
27
+ const number = (value)=>value != null && Number.isFinite(value) ? new Intl.NumberFormat('en-US', {
28
+ maximumFractionDigits: 0
29
+ }).format(value) : '—';
30
+ export function homeCard(test, summary, adminRoute) {
31
+ const results = [
32
+ 'running',
33
+ 'stopped',
34
+ 'decided'
35
+ ].includes(test.status);
36
+ const href = formatAdminURL({
37
+ adminRoute,
38
+ path: `/experiments/${encodeURIComponent(test.id)}${results ? '/results' : ''}`
39
+ });
40
+ let line = summary?.ready ? SURFACE_COPY.ready : SURFACE_COPY.next;
41
+ if (test.status === 'running') line = runningLine(number(summary?.days), number(test.analysis?.plannedDurationDays), number(summary?.exposures));
42
+ if (test.status === 'decided') {
43
+ const date = test.decidedAt ? new Date(test.decidedAt) : undefined;
44
+ const winner = test.decision?.winnerArm;
45
+ line = decidedLine(date && Number.isFinite(date.valueOf()) ? date.toLocaleDateString('en-US', {
46
+ timeZone: 'UTC'
47
+ }) : '—', winner ? armLabel(winner, test.arms?.find((arm)=>arm.key === winner)?.label) : '—');
48
+ }
49
+ if (test.status === 'archived') line = statusPill(test).label;
50
+ return {
51
+ kind: SURFACE_COPY.kinds[test.kind],
52
+ pill: statusPill(test),
53
+ line,
54
+ headline: test.status === 'running' ? summary?.verdict?.headline : undefined,
55
+ health: healthDot(test, summary),
56
+ href,
57
+ action: results ? SURFACE_COPY.results : test.status === 'draft' || test.status === 'stopped' ? SURFACE_COPY.continue : SURFACE_COPY.open
58
+ };
59
+ }
@@ -0,0 +1,7 @@
1
+ import type { TestsSurfaceProps } from '../../../types/surface.js';
2
+ import type { SurfaceProps } from '../contracts.js';
3
+ import './newTest.css';
4
+ export declare function NewTest({ surface, pages }: {
5
+ surface: SurfaceProps;
6
+ pages?: TestsSurfaceProps['pages'];
7
+ }): import("react").JSX.Element;