@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.
- package/README.md +28 -0
- package/dist/admin/LayerUsage.d.ts +1 -1
- package/dist/admin/LayerUsage.js +23 -11
- package/dist/admin/MetricSourceSelect.js +2 -1
- package/dist/admin/TestsNavLink.d.ts +1 -0
- package/dist/admin/TestsNavLink.js +30 -0
- package/dist/admin/allocation.model.js +1 -1
- package/dist/admin/copy/actions.d.ts +0 -2
- package/dist/admin/copy/actions.js +0 -2
- package/dist/admin/copy/advanced.d.ts +55 -0
- package/dist/admin/copy/advanced.js +55 -0
- package/dist/admin/copy/armSelect.js +1 -1
- package/dist/admin/copy/arms.d.ts +0 -13
- package/dist/admin/copy/arms.js +0 -13
- package/dist/admin/copy/{who.d.ts → audience.d.ts} +1 -9
- package/dist/admin/copy/{who.js → audience.js} +1 -9
- package/dist/admin/copy/history.d.ts +0 -4
- package/dist/admin/copy/history.js +3 -7
- package/dist/admin/copy/metrics.d.ts +2 -2
- package/dist/admin/copy/metrics.js +2 -2
- package/dist/admin/copy/newTest.d.ts +32 -0
- package/dist/admin/copy/newTest.js +32 -0
- package/dist/admin/copy/readiness.d.ts +45 -0
- package/dist/admin/copy/readiness.js +50 -0
- package/dist/admin/copy/recommendation.d.ts +26 -0
- package/dist/admin/copy/recommendation.js +25 -0
- package/dist/admin/copy/results.d.ts +0 -1
- package/dist/admin/copy/results.js +0 -1
- package/dist/admin/copy/review.d.ts +0 -17
- package/dist/admin/copy/review.js +1 -112
- package/dist/admin/copy/setting.d.ts +10 -0
- package/dist/admin/copy/setting.js +10 -0
- package/dist/admin/copy/surface.d.ts +36 -0
- package/dist/admin/copy/surface.js +47 -0
- package/dist/admin/copy/testPage.d.ts +88 -0
- package/dist/admin/copy/testPage.js +88 -0
- package/dist/admin/paths.d.ts +5 -13
- package/dist/admin/paths.js +5 -13
- package/dist/admin/review/review.model.d.ts +3 -26
- package/dist/admin/review/review.model.js +3 -30
- package/dist/admin/surface/ResultsRoute.d.ts +7 -0
- package/dist/admin/surface/ResultsRoute.js +58 -0
- package/dist/admin/surface/SurfaceShell.d.ts +6 -0
- package/dist/admin/surface/SurfaceShell.js +35 -0
- package/dist/admin/surface/TestsHome.d.ts +4 -0
- package/dist/admin/surface/TestsHome.js +212 -0
- package/dist/admin/surface/TestsSurface.d.ts +2 -0
- package/dist/admin/surface/TestsSurface.js +36 -0
- package/dist/admin/surface/contracts.d.ts +48 -0
- package/dist/admin/surface/contracts.js +8 -0
- package/dist/admin/surface/home.model.d.ts +41 -0
- package/dist/admin/surface/home.model.js +59 -0
- package/dist/admin/surface/newTest/NewTest.d.ts +7 -0
- package/dist/admin/surface/newTest/NewTest.js +355 -0
- package/dist/admin/surface/newTest/newTest.css +9 -0
- package/dist/admin/surface/pageBlock/pageBlock.model.d.ts +6 -0
- package/dist/admin/surface/pageBlock/pageBlock.model.js +8 -0
- package/dist/admin/surface/pageBlock/parts.d.ts +2 -0
- package/dist/admin/surface/pageBlock/parts.js +64 -0
- package/dist/admin/surface/readiness/ActionDialogs.d.ts +15 -0
- package/dist/admin/surface/readiness/ActionDialogs.js +274 -0
- package/dist/admin/surface/readiness/Banner.d.ts +2 -0
- package/dist/admin/surface/readiness/Banner.js +138 -0
- package/dist/admin/surface/readiness/SaveStatus.d.ts +4 -0
- package/dist/admin/surface/readiness/SaveStatus.js +50 -0
- package/dist/admin/surface/readiness/parts.d.ts +2 -0
- package/dist/admin/surface/readiness/parts.js +9 -0
- package/dist/admin/surface/readiness/readiness.model.d.ts +22 -0
- package/dist/admin/surface/readiness/readiness.model.js +107 -0
- package/dist/admin/surface/readiness/useTransition.d.ts +10 -0
- package/dist/admin/surface/readiness/useTransition.js +34 -0
- package/dist/admin/surface/results/ResultsBody.d.ts +7 -0
- package/dist/admin/surface/results/ResultsBody.js +262 -0
- package/dist/admin/surface/results/recommendation.model.d.ts +12 -0
- package/dist/admin/surface/results/recommendation.model.js +59 -0
- package/dist/admin/surface/results/useResults.d.ts +56 -0
- package/dist/admin/surface/results/useResults.js +183 -0
- package/dist/admin/surface/setting/parts.d.ts +3 -0
- package/dist/admin/surface/setting/parts.js +263 -0
- package/dist/admin/surface/setting/setting.css +29 -0
- package/dist/admin/surface/setting/setting.model.d.ts +8 -0
- package/dist/admin/surface/setting/setting.model.js +25 -0
- package/dist/admin/surface/surface.css +50 -0
- package/dist/admin/surface/test/AdvancedSection.d.ts +2 -0
- package/dist/admin/surface/test/AdvancedSection.js +153 -0
- package/dist/admin/surface/test/GoalSection.d.ts +2 -0
- package/dist/admin/surface/test/GoalSection.js +198 -0
- package/dist/admin/surface/test/LengthSection.d.ts +2 -0
- package/dist/admin/surface/test/LengthSection.js +87 -0
- package/dist/admin/surface/test/Section.d.ts +7 -0
- package/dist/admin/surface/test/Section.js +27 -0
- package/dist/admin/surface/test/TargetingSection.d.ts +2 -0
- package/dist/admin/surface/test/TargetingSection.js +164 -0
- package/dist/admin/surface/test/TestHeader.d.ts +4 -0
- package/dist/admin/surface/test/TestHeader.js +69 -0
- package/dist/admin/surface/test/TestPage.d.ts +7 -0
- package/dist/admin/surface/test/TestPage.js +84 -0
- package/dist/admin/surface/test/VersionsSection.d.ts +4 -0
- package/dist/admin/surface/test/VersionsSection.js +208 -0
- package/dist/admin/surface/test/fields.d.ts +55 -0
- package/dist/admin/surface/test/fields.js +185 -0
- package/dist/admin/surface/test/pageParts.d.ts +2 -0
- package/dist/admin/surface/test/pageParts.js +39 -0
- package/dist/admin/surface/test/testPage.css +23 -0
- package/dist/admin/surface/test/testPage.model.d.ts +17 -0
- package/dist/admin/surface/test/testPage.model.js +53 -0
- package/dist/admin/surface/testDocument.model.d.ts +39 -0
- package/dist/admin/surface/testDocument.model.js +61 -0
- package/dist/admin/surface/useTestDocument.d.ts +22 -0
- package/dist/admin/surface/useTestDocument.js +345 -0
- package/dist/admin/targeting/targeting.model.js +2 -2
- package/dist/admin/useLayerUsage.d.ts +0 -5
- package/dist/admin/useLayerUsage.js +1 -39
- package/dist/admin/views/CollectionEditRedirect.d.ts +4 -0
- package/dist/admin/views/CollectionEditRedirect.js +14 -0
- package/dist/admin/views/CollectionListRedirect.d.ts +2 -0
- package/dist/admin/views/CollectionListRedirect.js +8 -0
- package/dist/admin/views/ExperimentsRootView.d.ts +2 -0
- package/dist/admin/views/ExperimentsRootView.js +175 -0
- package/dist/admin/views/access.model.d.ts +7 -0
- package/dist/admin/views/access.model.js +5 -0
- package/dist/collections/experiments/config.js +18 -125
- package/dist/collections/experiments/createDefaults.js +6 -0
- package/dist/collections/layers.js +43 -12
- package/dist/collections/metrics.js +70 -14
- package/dist/collections/serialize.js +4 -1
- package/dist/db/snapshots.d.ts +2 -1
- package/dist/db/snapshots.js +2 -2
- package/dist/endpoints/results.js +7 -0
- package/dist/endpoints/summary.d.ts +1 -1
- package/dist/endpoints/summary.js +37 -1
- package/dist/exports/adminClient.d.ts +2 -13
- package/dist/exports/adminClient.js +2 -13
- package/dist/exports/index.d.ts +1 -1
- package/dist/exports/rsc.d.ts +3 -0
- package/dist/exports/rsc.js +3 -0
- package/dist/options.js +29 -0
- package/dist/plugin.js +25 -0
- package/dist/puck/editor/CreateExperimentDrawer.d.ts +2 -1
- package/dist/puck/editor/CreateExperimentDrawer.js +17 -57
- package/dist/puck/editor/ExperimentSlotEditor.js +6 -0
- package/dist/puck/editor/copy.d.ts +10 -9
- package/dist/puck/editor/copy.js +11 -10
- package/dist/puck/editor/createTest.d.ts +7 -0
- package/dist/puck/editor/createTest.js +50 -0
- package/dist/puck/editor/editor.model.d.ts +28 -1
- package/dist/puck/editor/editor.model.js +61 -0
- package/dist/results/analyse.js +4 -1
- package/dist/results/verdict.d.ts +1 -0
- package/dist/results/verdict.js +7 -4
- package/dist/transitions/checkStart.d.ts +1 -0
- package/dist/transitions/placements.d.ts +5 -1
- package/dist/transitions/placements.js +14 -7
- package/dist/transitions/preflightData.d.ts +7 -1
- package/dist/transitions/preflightData.js +199 -148
- package/dist/transitions/start.js +2 -2
- package/dist/types/admin.d.ts +1 -0
- package/dist/types/contracts.d.ts +17 -0
- package/dist/types/endpoints.d.ts +11 -1
- package/dist/types/snapshot.d.ts +1 -0
- package/dist/types/surface.d.ts +29 -0
- package/dist/types/surface.js +1 -0
- package/package.json +1 -1
- package/dist/access.d.ts +0 -1
- package/dist/access.js +0 -2
- package/dist/admin/AllocationField.d.ts +0 -2
- package/dist/admin/AllocationField.js +0 -80
- package/dist/admin/FlagPointSelect.d.ts +0 -2
- package/dist/admin/FlagPointSelect.js +0 -54
- package/dist/admin/LockedFieldNotice.d.ts +0 -2
- package/dist/admin/LockedFieldNotice.js +0 -26
- package/dist/admin/PhaseHistory.d.ts +0 -2
- package/dist/admin/PhaseHistory.js +0 -76
- package/dist/admin/StatusCell.d.ts +0 -3
- package/dist/admin/StatusCell.js +0 -19
- package/dist/admin/SummaryCell.d.ts +0 -2
- package/dist/admin/SummaryCell.js +0 -32
- package/dist/admin/actions/AddMetricDialog.d.ts +0 -6
- package/dist/admin/actions/AddMetricDialog.js +0 -138
- package/dist/admin/actions/AllocateDialog.d.ts +0 -6
- package/dist/admin/actions/AllocateDialog.js +0 -81
- package/dist/admin/actions/ExperimentActions.d.ts +0 -3
- package/dist/admin/actions/ExperimentActions.js +0 -110
- package/dist/admin/arms/ArmsField.d.ts +0 -2
- package/dist/admin/arms/ArmsField.js +0 -310
- package/dist/admin/arms/ParamsEditor.d.ts +0 -16
- package/dist/admin/arms/ParamsEditor.js +0 -79
- package/dist/admin/copy/tabs.d.ts +0 -7
- package/dist/admin/copy/tabs.js +0 -7
- package/dist/admin/permissions.model.d.ts +0 -10
- package/dist/admin/permissions.model.js +0 -4
- package/dist/admin/phaseHistory.model.d.ts +0 -19
- package/dist/admin/phaseHistory.model.js +0 -19
- package/dist/admin/results/ResultsView.d.ts +0 -3
- package/dist/admin/results/ResultsView.js +0 -312
- package/dist/admin/review/ReviewPanel.d.ts +0 -2
- package/dist/admin/review/ReviewPanel.js +0 -268
- package/dist/admin/summaryBatcher.d.ts +0 -8
- package/dist/admin/summaryBatcher.js +0 -33
- package/dist/admin/targeting/TargetingAttributeField.d.ts +0 -2
- package/dist/admin/targeting/TargetingAttributeField.js +0 -31
- package/dist/admin/targeting/TargetingOpField.d.ts +0 -2
- package/dist/admin/targeting/TargetingOpField.js +0 -45
- package/dist/admin/targeting/TargetingValueField.d.ts +0 -2
- package/dist/admin/targeting/TargetingValueField.js +0 -142
- package/dist/index.d.ts +0 -1
- 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
|
-
}
|
package/dist/admin/copy/tabs.js
DELETED
|
@@ -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,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
|
-
}
|