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

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/index.d.ts +1 -1
  135. package/dist/exports/rsc.d.ts +3 -0
  136. package/dist/exports/rsc.js +3 -0
  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 +1 -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
@@ -1,310 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useEffect, useMemo, useRef } from 'react';
4
- import { Button, TextInput, useField, useForm, useFormFields } from '@payloadcms/ui';
5
- import { EDITABLE_BY_STATUS, isEditable } from '../../collections/experiments/editability.js';
6
- import { lockedReason } from '../lockedNotice.model.js';
7
- import { ARMS_COPY, GROUP_LABELS, ISSUE_COPY, issueMessage } from '../copy/arms.js';
8
- import { addHoldoutArm, addVariant, ARM_FIELDS, defaultArms, issuesByRow, readArms, removeArm, setWeight, splitEvenly, totalWeight, withSlotsFor } from './arms.model.js';
9
- import { pageTargetIssue, setPageTarget, showsPageTarget } from './pageTarget.model.js';
10
- import { paramsForArm, paramsReadOnly } from './params.model.js';
11
- import { numberInputStyle, ParamsEditor } from './ParamsEditor.js';
12
- function newRowId() {
13
- if (globalThis.crypto?.getRandomValues) {
14
- return Array.from(globalThis.crypto.getRandomValues(new Uint8Array(12)), (byte)=>byte.toString(16).padStart(2, '0')).join('');
15
- }
16
- return (Date.now().toString(16).padStart(12, '0') + Math.floor(Math.random() * 2 ** 48).toString(16).padStart(12, '0')).slice(-24);
17
- }
18
- export function ArmsField({ field, path = 'arms', readOnly }) {
19
- const form = useForm();
20
- const { showError, errorMessage } = useField({
21
- path,
22
- hasRows: true
23
- });
24
- const kind = useFormFields(([fields])=>fields.kind?.value);
25
- const status = useFormFields(([fields])=>fields.status?.value ?? 'draft');
26
- const flagPoint = useFormFields(([fields])=>fields.flagPoint?.value);
27
- const rowMetadata = useFormFields(([fields])=>fields[path]?.rows);
28
- // Payload compares selector results by identity. Retain the arm slice when
29
- // another field changes, including while a cleared weight contains NaN.
30
- const selectRows = useMemo(()=>{
31
- let previous = {
32
- arms: [],
33
- rowIds: []
34
- };
35
- return ([fields])=>{
36
- const arms = readArms(fields, path);
37
- const rowIds = arms.map((_, index)=>fields[`${path}.${index}.id`]?.value);
38
- if (arms.length !== previous.arms.length || arms.some((arm, index)=>rowIds[index] !== previous.rowIds[index] || ARM_FIELDS.some((key)=>!Object.is(arm[key], previous.arms[index]?.[key])))) previous = {
39
- arms,
40
- rowIds
41
- };
42
- return previous;
43
- };
44
- }, [
45
- path
46
- ]);
47
- const { arms, rowIds } = useFormFields(selectRows);
48
- const seeded = useRef(false);
49
- const editable = isEditable(status, 'arms') && !readOnly && !form.disabled;
50
- const reason = lockedReason(status, 'arms', EDITABLE_BY_STATUS);
51
- const points = field.admin?.custom?.flagPoints ?? [];
52
- const point = points.find((candidate)=>candidate.id === flagPoint);
53
- const issues = issuesByRow(arms, kind);
54
- const total = totalWeight(arms);
55
- const hasControl = arms.some((arm)=>arm.kind === 'control');
56
- const serverCode = [
57
- ...issues.form,
58
- ...issues.rows.flat()
59
- ].find((issue)=>issue.message === errorMessage)?.code ?? (typeof errorMessage === 'string' ? Object.keys(ISSUE_COPY).find((code)=>errorMessage.split(/[^a-z-]+/).includes(code)) : undefined);
60
- function apply(next) {
61
- if (!editable) return;
62
- // null (from Postgres) and undefined both mean "unset"; only real differences are written.
63
- const same = (a, b)=>Object.is(a, b) || a == null && b == null;
64
- let changed = false;
65
- next = withSlotsFor(next, kind);
66
- if (next === arms) return;
67
- const structureChanged = next.length !== arms.length || next.some((row, index)=>row.key !== arms[index]?.key);
68
- // Array row IDs identify existing groups in the server's immutable-key check.
69
- // Move both the hidden ID field and public row metadata with the logical key.
70
- const idsByKey = new Map(arms.map((row, index)=>[
71
- row.key,
72
- rowIds[index]
73
- ]));
74
- const nextIds = structureChanged ? next.map((row)=>idsByKey.get(row.key) ?? newRowId()) : rowIds;
75
- if (structureChanged) changed = true;
76
- for(let rowIndex = arms.length - 1; rowIndex >= next.length; rowIndex--)form.removeFieldRow({
77
- path,
78
- rowIndex
79
- });
80
- for(let rowIndex = arms.length; rowIndex < next.length; rowIndex++){
81
- const row = next[rowIndex];
82
- const subFieldState = {
83
- ...Object.fromEntries(ARM_FIELDS.filter((key)=>key !== 'params' || row.kind !== 'holdout').map((key)=>[
84
- key,
85
- {
86
- value: row[key],
87
- initialValue: undefined,
88
- valid: true
89
- }
90
- ])),
91
- id: {
92
- value: nextIds[rowIndex],
93
- initialValue: undefined,
94
- valid: true
95
- }
96
- };
97
- form.addFieldRow({
98
- path,
99
- rowIndex,
100
- schemaPath: 'arms',
101
- subFieldState
102
- });
103
- }
104
- next.forEach((row, index)=>{
105
- if (structureChanged && rowIds[index] !== nextIds[index]) form.dispatchFields({
106
- type: 'UPDATE',
107
- path: `${path}.${index}.id`,
108
- value: nextIds[index]
109
- });
110
- for (const key of ARM_FIELDS){
111
- if (key === 'params' && row.kind === 'holdout') {
112
- // Reusing a physical row for the holdout must drop the former
113
- // variant's params without assigning params to the holdout.
114
- if (arms[index]?.params != null) {
115
- changed = true;
116
- form.dispatchFields({
117
- type: 'UPDATE',
118
- path: `${path}.${index}.params`,
119
- value: undefined
120
- });
121
- }
122
- continue;
123
- }
124
- if (!same(arms[index]?.[key], row[key])) {
125
- changed = true;
126
- form.dispatchFields({
127
- type: 'UPDATE',
128
- path: `${path}.${index}.${key}`,
129
- value: row[key]
130
- });
131
- }
132
- }
133
- });
134
- if (structureChanged) form.dispatchFields({
135
- type: 'UPDATE',
136
- path,
137
- rows: nextIds.map((id)=>rowMetadata?.find((row)=>row.id === id) ?? {
138
- id: id,
139
- isLoading: true
140
- })
141
- });
142
- if (changed) form.setModified(true);
143
- }
144
- useEffect(()=>{
145
- if (!editable) return;
146
- if (!arms.length && !seeded.current) {
147
- seeded.current = true;
148
- apply(defaultArms(kind));
149
- } else if (arms.length) apply(arms);
150
- });
151
- function update(index, patch) {
152
- apply(arms.map((arm, i)=>i === index ? {
153
- ...arm,
154
- ...patch
155
- } : arm));
156
- }
157
- return /*#__PURE__*/ _jsxs("div", {
158
- className: "xp-groups",
159
- children: [
160
- reason ? /*#__PURE__*/ _jsx("p", {
161
- className: "xp-locked-notice",
162
- children: reason
163
- }) : null,
164
- arms.length ? issues.form.map((issue, i)=>/*#__PURE__*/ _jsx("p", {
165
- role: "alert",
166
- children: issueMessage(issue, total)
167
- }, i)) : null,
168
- showError && errorMessage ? /*#__PURE__*/ _jsx("p", {
169
- role: "alert",
170
- children: issueMessage({
171
- code: serverCode ?? '',
172
- message: errorMessage
173
- }, total)
174
- }) : null,
175
- /*#__PURE__*/ _jsxs("fieldset", {
176
- disabled: !editable,
177
- "aria-label": ARMS_COPY.groups,
178
- style: {
179
- border: 0,
180
- padding: 0,
181
- margin: 0
182
- },
183
- children: [
184
- arms.map((arm, index)=>{
185
- const rowPath = `${path}.${index}`;
186
- const pageIssue = kind && showsPageTarget(kind, arm.kind) ? pageTargetIssue(arm.pageTarget, arm.kind) : null;
187
- return /*#__PURE__*/ _jsxs("section", {
188
- className: "xp-group",
189
- style: {
190
- marginBottom: '1.5rem'
191
- },
192
- children: [
193
- /*#__PURE__*/ _jsx("h3", {
194
- children: GROUP_LABELS[arm.key] ?? arm.label
195
- }),
196
- /*#__PURE__*/ _jsx(TextInput, {
197
- hasMany: false,
198
- path: `${rowPath}.label`,
199
- label: ARMS_COPY.label,
200
- value: arm.label ?? '',
201
- readOnly: !editable,
202
- onChange: (event)=>update(index, {
203
- label: event.target.value
204
- })
205
- }),
206
- /*#__PURE__*/ _jsxs("label", {
207
- htmlFor: `${rowPath}.weight`,
208
- children: [
209
- ARMS_COPY.weight,
210
- /*#__PURE__*/ _jsx("input", {
211
- id: `${rowPath}.weight`,
212
- name: `${rowPath}.weight`,
213
- type: "number",
214
- min: 0,
215
- max: 100,
216
- step: 1,
217
- style: numberInputStyle,
218
- disabled: !editable,
219
- value: Number.isFinite(arm.weight) ? arm.weight : '',
220
- onChange: (event)=>apply(setWeight(arms, arm.key, event.target.value === '' ? NaN : Number(event.target.value)))
221
- })
222
- ]
223
- }),
224
- kind === 'block' && arm.kind !== 'holdout' ? /*#__PURE__*/ _jsxs("p", {
225
- children: [
226
- ARMS_COPY.slot,
227
- ": ",
228
- GROUP_LABELS[arm.key] ?? arm.label
229
- ]
230
- }) : null,
231
- kind === 'page' && arm.kind === 'holdout' ? /*#__PURE__*/ _jsx("p", {
232
- children: ARMS_COPY.holdoutPage
233
- }) : null,
234
- kind && showsPageTarget(kind, arm.kind) ? /*#__PURE__*/ _jsx(TextInput, {
235
- hasMany: false,
236
- path: `${rowPath}.pageTarget`,
237
- label: ARMS_COPY.pagePath,
238
- value: arm.pageTarget ?? '',
239
- required: true,
240
- readOnly: !editable,
241
- onChange: (event)=>{
242
- const next = setPageTarget(arm, event.target.value);
243
- update(index, {
244
- pageTarget: next.pageTarget
245
- });
246
- }
247
- }) : null,
248
- pageIssue ? /*#__PURE__*/ _jsx("p", {
249
- role: "alert",
250
- children: pageIssue
251
- }) : null,
252
- kind === 'flag' && point && arm.kind !== 'holdout' ? /*#__PURE__*/ _jsxs(_Fragment, {
253
- children: [
254
- arm.kind === 'control' ? /*#__PURE__*/ _jsx("p", {
255
- children: ARMS_COPY.controlParams
256
- }) : null,
257
- /*#__PURE__*/ _jsx(ParamsEditor, {
258
- fields: point.params,
259
- path: `${rowPath}.params`,
260
- value: paramsForArm(arm, point),
261
- readOnly: paramsReadOnly(arm, editable),
262
- onChange: (params)=>update(index, {
263
- params
264
- })
265
- })
266
- ]
267
- }) : null,
268
- issues.rows[index].map((issue, i)=>/*#__PURE__*/ _jsx("p", {
269
- role: "alert",
270
- children: issueMessage(issue, total)
271
- }, i)),
272
- arm.kind === 'holdout' ? /*#__PURE__*/ _jsxs(_Fragment, {
273
- children: [
274
- /*#__PURE__*/ _jsx("p", {
275
- children: ARMS_COPY.holdout
276
- }),
277
- /*#__PURE__*/ _jsx(Button, {
278
- onClick: ()=>apply(removeArm(arms, arm.key)),
279
- disabled: !editable,
280
- children: ARMS_COPY.removeHoldout
281
- })
282
- ]
283
- }) : arm.kind === 'variant' ? /*#__PURE__*/ _jsx(Button, {
284
- onClick: ()=>apply(removeArm(arms, arm.key)),
285
- disabled: !editable,
286
- children: ARMS_COPY.removeVariant
287
- }) : null
288
- ]
289
- }, index);
290
- }),
291
- /*#__PURE__*/ _jsx(Button, {
292
- disabled: !editable || !hasControl || arms.filter((arm)=>arm.kind === 'variant').length >= 3,
293
- onClick: ()=>apply(addVariant(arms, kind)),
294
- children: ARMS_COPY.addVariant
295
- }),
296
- !arms.some((arm)=>arm.kind === 'holdout') ? /*#__PURE__*/ _jsx(Button, {
297
- disabled: !editable || !hasControl,
298
- onClick: ()=>apply(addHoldoutArm(arms)),
299
- children: ARMS_COPY.addHoldout
300
- }) : null,
301
- /*#__PURE__*/ _jsx(Button, {
302
- disabled: !editable,
303
- onClick: ()=>apply(splitEvenly(arms)),
304
- children: ARMS_COPY.splitEvenly
305
- })
306
- ]
307
- })
308
- ]
309
- });
310
- }
@@ -1,16 +0,0 @@
1
- import type { ParamField } from '../../types/contracts.js';
2
- export declare const numberInputStyle: {
3
- readonly background: "var(--theme-input-bg)";
4
- readonly color: "var(--theme-text)";
5
- readonly border: "1px solid var(--theme-elevation-150)";
6
- readonly borderRadius: "var(--style-radius-s)";
7
- readonly padding: "0.65rem";
8
- readonly width: "100%";
9
- };
10
- export declare function ParamsEditor({ fields, value, path, readOnly, onChange }: {
11
- fields: Record<string, ParamField>;
12
- value: Record<string, unknown>;
13
- path: string;
14
- readOnly: boolean;
15
- onChange: (value: Record<string, unknown>) => void;
16
- }): import("react").JSX.Element;
@@ -1,79 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { CheckboxInput, SelectInput, TextareaInput, TextInput } from '@payloadcms/ui';
4
- import { paramIssue, setParam } from './params.model.js';
5
- export const numberInputStyle = {
6
- background: 'var(--theme-input-bg)',
7
- color: 'var(--theme-text)',
8
- border: '1px solid var(--theme-elevation-150)',
9
- borderRadius: 'var(--style-radius-s)',
10
- padding: '0.65rem',
11
- width: '100%'
12
- };
13
- export function ParamsEditor({ fields, value, path, readOnly, onChange }) {
14
- return /*#__PURE__*/ _jsx("div", {
15
- className: "xp-params-editor",
16
- children: Object.entries(fields).map(([key, field])=>{
17
- const fieldPath = `${path}.${key}`;
18
- const change = (next)=>{
19
- if (!readOnly) onChange(setParam(value, key, field, next));
20
- };
21
- const issue = paramIssue(field, value[key]);
22
- const shared = {
23
- path: fieldPath,
24
- label: field.label,
25
- required: field.required,
26
- readOnly
27
- };
28
- const text = typeof value[key] === 'string' ? value[key] : '';
29
- return /*#__PURE__*/ _jsxs("div", {
30
- children: [
31
- field.type === 'number' ? /*#__PURE__*/ _jsxs("label", {
32
- htmlFor: fieldPath,
33
- children: [
34
- field.label,
35
- /*#__PURE__*/ _jsx("input", {
36
- id: fieldPath,
37
- name: fieldPath,
38
- type: "number",
39
- style: numberInputStyle,
40
- required: field.required,
41
- disabled: readOnly,
42
- min: field.min,
43
- max: field.max,
44
- step: "any",
45
- value: typeof value[key] === 'number' && Number.isFinite(value[key]) ? value[key] : '',
46
- "aria-invalid": !!issue,
47
- onChange: (event)=>change(event.target.value)
48
- })
49
- ]
50
- }) : field.type === 'checkbox' ? /*#__PURE__*/ _jsx(CheckboxInput, {
51
- ...shared,
52
- name: fieldPath,
53
- checked: value[key] === true,
54
- onToggle: (event)=>change(event.target.checked)
55
- }) : field.type === 'select' ? /*#__PURE__*/ _jsx(SelectInput, {
56
- ...shared,
57
- name: fieldPath,
58
- options: field.options ?? [],
59
- value: text,
60
- onChange: (option)=>change(!Array.isArray(option) ? option?.value ?? '' : '')
61
- }) : field.type === 'textarea' ? /*#__PURE__*/ _jsx(TextareaInput, {
62
- ...shared,
63
- value: text,
64
- onChange: (event)=>change(event.target.value)
65
- }) : /*#__PURE__*/ _jsx(TextInput, {
66
- hasMany: false,
67
- ...shared,
68
- value: text,
69
- onChange: (event)=>change(event.target.value)
70
- }),
71
- issue ? /*#__PURE__*/ _jsx("p", {
72
- role: "alert",
73
- children: issue
74
- }) : null
75
- ]
76
- }, key);
77
- })
78
- });
79
- }
@@ -1,7 +0,0 @@
1
- export declare const TAB_DESCRIPTIONS: {
2
- What: string;
3
- Who: string;
4
- Groups: string;
5
- Metrics: string;
6
- Review: string;
7
- };
@@ -1,7 +0,0 @@
1
- export const TAB_DESCRIPTIONS = {
2
- What: "What you're testing and why.",
3
- Who: 'Who takes part and how traffic is split.',
4
- Groups: 'The Original, the variants, and an optional holdout.',
5
- Metrics: 'What decides the winner and what must not get worse.',
6
- Review: 'Check everything, see how long it will take, and start.'
7
- };
@@ -1,10 +0,0 @@
1
- export type ManagePermissions = {
2
- collections?: {
3
- 'xp-experiments'?: {
4
- update?: boolean | {
5
- permission?: boolean;
6
- };
7
- };
8
- };
9
- };
10
- export declare function canManage(permissions: ManagePermissions | null | undefined): boolean;
@@ -1,4 +0,0 @@
1
- export function canManage(permissions) {
2
- const update = permissions?.collections?.['xp-experiments']?.update;
3
- return update === true || typeof update === 'object' && update !== null && update.permission === true;
4
- }
@@ -1,19 +0,0 @@
1
- export type HistoryPhase = {
2
- phase: number;
3
- phaseKind: 'test' | 'rollout';
4
- startedAt: string;
5
- endedAt?: string | null;
6
- arms: readonly {
7
- weight: number;
8
- }[];
9
- };
10
- export declare function phaseHistory(phases: readonly HistoryPhase[], decision?: {
11
- decidedBy?: unknown;
12
- } | null): {
13
- rows: {
14
- phase: number;
15
- phaseKind: "test" | "rollout";
16
- text: string;
17
- }[];
18
- decision: string | null;
19
- };
@@ -1,19 +0,0 @@
1
- import { phaseKindLabel } from './labels.js';
2
- import { HISTORY_COPY, roundRow } from './copy/history.js';
3
- const dateFormat = new Intl.DateTimeFormat('en-US', {
4
- month: 'short',
5
- day: 'numeric',
6
- timeZone: 'UTC'
7
- });
8
- export function phaseHistory(phases, decision) {
9
- return {
10
- rows: [
11
- ...phases
12
- ].sort((a, b)=>a.phase - b.phase || new Date(a.startedAt).getTime() - new Date(b.startedAt).getTime()).map((phase)=>({
13
- phase: phase.phase,
14
- phaseKind: phase.phaseKind,
15
- text: roundRow(phase.phase, phaseKindLabel(phase.phaseKind), dateFormat.format(new Date(phase.startedAt)), phase.endedAt ? dateFormat.format(new Date(phase.endedAt)) : HISTORY_COPY.now, phase.arms.map((arm)=>arm.weight).join('/'))
16
- })),
17
- decision: decision?.decidedBy != null ? HISTORY_COPY.decided : null
18
- };
19
- }
@@ -1,3 +0,0 @@
1
- import '../styles.js';
2
- import type { DocumentViewClientProps } from 'payload';
3
- export declare function ResultsView(_props: DocumentViewClientProps): import("react").JSX.Element;