@delmaredigital/payload-experiments 0.3.0-rc.4 → 0.4.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 +113 -20
- package/dist/admin/MetricSourceSelect.js +3 -3
- package/dist/admin/PlacementStatus.d.ts +3 -0
- package/dist/admin/PlacementStatus.js +54 -0
- package/dist/admin/PreviewLinks.d.ts +2 -1
- package/dist/admin/PreviewLinks.js +2 -2
- package/dist/admin/actions/ConfirmDialog.d.ts +2 -1
- package/dist/admin/actions/ConfirmDialog.js +2 -2
- package/dist/admin/actions/DecideDialog.d.ts +2 -1
- package/dist/admin/actions/DecideDialog.js +2 -2
- package/dist/admin/api.d.ts +11 -2
- package/dist/admin/api.js +20 -2
- package/dist/admin/blocks/BlockPanel.d.ts +4 -0
- package/dist/admin/blocks/BlockPanel.js +153 -0
- package/dist/admin/blocks/TestBlockField.d.ts +5 -0
- package/dist/admin/blocks/TestBlockField.js +163 -0
- package/dist/admin/blocks/formApi.d.ts +43 -0
- package/dist/admin/blocks/formApi.js +153 -0
- package/dist/admin/blocks/inject.d.ts +7 -0
- package/dist/admin/blocks/inject.js +41 -0
- package/dist/admin/blocks/model.d.ts +17 -0
- package/dist/admin/blocks/model.js +45 -0
- package/dist/admin/blocks/statusCache.d.ts +7 -0
- package/dist/admin/blocks/statusCache.js +83 -0
- package/dist/admin/blocks/useBlockForm.d.ts +17 -0
- package/dist/admin/blocks/useBlockForm.js +46 -0
- package/dist/admin/copy/actions.d.ts +2 -0
- package/dist/admin/copy/actions.js +9 -0
- package/dist/admin/copy/blocks.d.ts +27 -0
- package/dist/admin/copy/blocks.js +38 -0
- package/dist/admin/copy/goals.d.ts +2 -0
- package/dist/admin/copy/goals.js +4 -1
- package/dist/admin/copy/newTest.d.ts +10 -0
- package/dist/admin/copy/newTest.js +10 -0
- package/dist/admin/copy/pages.d.ts +26 -0
- package/dist/admin/copy/pages.js +26 -0
- package/dist/admin/copy/readiness.d.ts +22 -3
- package/dist/admin/copy/readiness.js +23 -3
- package/dist/admin/copy/results.d.ts +1 -0
- package/dist/admin/copy/results.js +1 -0
- package/dist/admin/copy/testPage.d.ts +4 -0
- package/dist/admin/copy/testPage.js +4 -0
- package/dist/admin/goals/XpGoalField.d.ts +2 -0
- package/dist/admin/goals/XpGoalField.js +152 -0
- package/dist/admin/metricSource.model.d.ts +2 -0
- package/dist/admin/metricSource.model.js +4 -0
- package/dist/admin/pageCollections.d.ts +10 -0
- package/dist/admin/pageCollections.js +20 -0
- package/dist/admin/paths.d.ts +6 -0
- package/dist/admin/paths.js +6 -0
- package/dist/admin/placementStatus.model.d.ts +2 -0
- package/dist/admin/placementStatus.model.js +19 -0
- package/dist/admin/placements/placementLabels.d.ts +11 -0
- package/dist/admin/placements/placementLabels.js +21 -0
- package/dist/admin/placements/placementLabels.model.d.ts +13 -0
- package/dist/admin/placements/placementLabels.model.js +12 -0
- package/dist/admin/placements/usePlacementLabels.d.ts +12 -0
- package/dist/admin/placements/usePlacementLabels.js +102 -0
- package/dist/admin/results/DataQualityPanel.js +4 -1
- package/dist/admin/results/results.model.d.ts +3 -0
- package/dist/admin/results/results.model.js +8 -4
- package/dist/admin/surface/TestsHome.js +37 -6
- package/dist/admin/surface/TestsSurface.js +5 -1
- package/dist/admin/surface/contracts.d.ts +6 -5
- package/dist/admin/surface/goals/GoalForm.js +67 -34
- package/dist/admin/surface/goals/GoalsList.js +3 -3
- package/dist/admin/surface/goals/data.js +4 -1
- package/dist/admin/surface/goals/goals.model.d.ts +1 -2
- package/dist/admin/surface/goals/goals.model.js +1 -3
- package/dist/admin/surface/home.model.d.ts +1 -1
- package/dist/admin/surface/home.model.js +8 -4
- package/dist/admin/surface/newTest/NewTest.js +54 -13
- package/dist/admin/surface/newTest/PageWizard.d.ts +7 -0
- package/dist/admin/surface/newTest/PageWizard.js +209 -0
- package/dist/admin/surface/pagePicker/CopyRoute.d.ts +6 -0
- package/dist/admin/surface/pagePicker/CopyRoute.js +53 -0
- package/dist/admin/surface/pagePicker/PagePicker.d.ts +10 -0
- package/dist/admin/surface/pagePicker/PagePicker.js +172 -0
- package/dist/admin/surface/pagePicker/pagePicker.model.d.ts +25 -0
- package/dist/admin/surface/pagePicker/pagePicker.model.js +25 -0
- package/dist/admin/surface/readiness/ActionDialogs.js +99 -64
- package/dist/admin/surface/readiness/Banner.js +30 -6
- package/dist/admin/surface/readiness/readiness.model.d.ts +8 -1
- package/dist/admin/surface/readiness/readiness.model.js +91 -9
- package/dist/admin/surface/results/ReleasePages.d.ts +3 -1
- package/dist/admin/surface/results/ReleasePages.js +3 -7
- package/dist/admin/surface/results/ResultsBody.js +21 -2
- package/dist/admin/surface/results/ResultsHeader.js +2 -5
- package/dist/admin/surface/results/useResults.d.ts +10 -1
- package/dist/admin/surface/test/AdvancedSection.js +111 -104
- package/dist/admin/surface/test/GoalSection.js +90 -7
- package/dist/admin/surface/test/LengthSection.js +1 -1
- package/dist/admin/surface/test/PageHoldout.d.ts +3 -0
- package/dist/admin/surface/test/PageHoldout.js +67 -0
- package/dist/admin/surface/test/TestPage.js +2 -1
- package/dist/admin/surface/test/VersionsSection.js +12 -5
- package/dist/admin/surface/test/fields.d.ts +13 -4
- package/dist/admin/surface/test/fields.js +46 -14
- package/dist/admin/surface/test/jumpToSection.d.ts +1 -1
- package/dist/admin/surface/test/jumpToSection.js +4 -3
- package/dist/admin/surface/test/pageParts.d.ts +4 -1
- package/dist/admin/surface/test/pageParts.js +79 -2
- package/dist/admin/surface/test/testPage.css +8 -1
- package/dist/admin/surface/testDocument.model.d.ts +1 -0
- package/dist/admin/surface/testDocument.model.js +2 -1
- package/dist/admin/surface/useTestDocument.d.ts +11 -2
- package/dist/admin/surface/useTestDocument.js +53 -15
- package/dist/admin/useApi.d.ts +11 -2
- package/dist/admin/useApi.js +3 -5
- package/dist/admin/views/ExperimentsRootView.js +58 -16
- package/dist/blocks/bindings.d.ts +3 -0
- package/dist/blocks/bindings.js +34 -0
- package/dist/blocks/createExperimentBlock.d.ts +6 -0
- package/dist/blocks/createExperimentBlock.js +77 -0
- package/dist/blocks/formState.d.ts +31 -0
- package/dist/blocks/formState.js +146 -0
- package/dist/blocks/model.d.ts +41 -0
- package/dist/blocks/model.js +34 -0
- package/dist/client/ExperimentGroup.d.ts +6 -0
- package/dist/client/ExperimentGroup.js +9 -0
- package/dist/client/ExperimentsProvider.js +20 -4
- package/dist/client/clickGoals.d.ts +4 -0
- package/dist/client/clickGoals.js +43 -0
- package/dist/collections/experiments/config.js +12 -2
- package/dist/collections/experiments/deleteGuard.d.ts +2 -1
- package/dist/collections/experiments/deleteGuard.js +12 -1
- package/dist/collections/experiments/editability.js +4 -2
- package/dist/collections/experiments/pickSlug.d.ts +2 -0
- package/dist/collections/experiments/pickSlug.js +8 -0
- package/dist/collections/labels.d.ts +3 -0
- package/dist/collections/labels.js +20 -0
- package/dist/collections/metrics.js +12 -2
- package/dist/collections/phases.js +1 -0
- package/dist/collections/serialize.js +7 -0
- package/dist/db/clickGoals.d.ts +9 -0
- package/dist/db/clickGoals.js +22 -0
- package/dist/db/delete.d.ts +1 -0
- package/dist/db/delete.js +1 -0
- package/dist/db/locks.d.ts +8 -0
- package/dist/db/locks.js +27 -4
- package/dist/db/names.d.ts +4 -0
- package/dist/db/names.js +4 -0
- package/dist/db/pageBindings.d.ts +4 -0
- package/dist/db/pageBindings.js +17 -0
- package/dist/db/pageBusy.d.ts +2 -0
- package/dist/db/pageBusy.js +10 -0
- package/dist/db/pageContent.d.ts +10 -0
- package/dist/db/pageContent.js +79 -0
- package/dist/db/placements.d.ts +33 -0
- package/dist/db/placements.js +54 -0
- package/dist/db/slugs.d.ts +8 -0
- package/dist/db/slugs.js +40 -0
- package/dist/db/snapshots.d.ts +6 -0
- package/dist/db/snapshots.js +8 -5
- package/dist/endpoints/clickKeys.d.ts +5 -0
- package/dist/endpoints/clickKeys.js +17 -0
- package/dist/endpoints/events.js +4 -1
- package/dist/endpoints/index.js +28 -0
- package/dist/endpoints/pages.d.ts +5 -0
- package/dist/endpoints/pages.js +120 -0
- package/dist/endpoints/placementStatus.d.ts +6 -0
- package/dist/endpoints/placementStatus.js +238 -0
- package/dist/endpoints/readBody.d.ts +2 -0
- package/dist/endpoints/readBody.js +24 -0
- package/dist/endpoints/results.js +5 -1
- package/dist/endpoints/summary.js +11 -4
- package/dist/endpoints/wrapBlock.d.ts +6 -0
- package/dist/endpoints/wrapBlock.js +76 -0
- package/dist/errors.d.ts +3 -3
- package/dist/errors.js +4 -4
- package/dist/events/rows.d.ts +1 -1
- package/dist/events/rows.js +5 -3
- package/dist/exports/adminClient.d.ts +5 -0
- package/dist/exports/adminClient.js +5 -0
- package/dist/exports/blocks.d.ts +2 -0
- package/dist/exports/blocks.js +1 -0
- package/dist/exports/client.d.ts +1 -0
- package/dist/exports/client.js +1 -0
- package/dist/exports/index.d.ts +6 -1
- package/dist/exports/index.js +3 -0
- package/dist/exports/puck.d.ts +3 -1
- package/dist/exports/puck.js +2 -0
- package/dist/exports/puckEditor.d.ts +3 -0
- package/dist/exports/puckEditor.js +2 -0
- package/dist/exports/rsc.d.ts +3 -0
- package/dist/exports/rsc.js +2 -0
- package/dist/fields/xpGoal.d.ts +3 -0
- package/dist/fields/xpGoal.js +28 -0
- package/dist/globals/state.js +10 -0
- package/dist/goals/cache.d.ts +3 -0
- package/dist/goals/cache.js +35 -0
- package/dist/goals/fairness.d.ts +40 -0
- package/dist/goals/fairness.js +200 -0
- package/dist/goals/key.d.ts +4 -0
- package/dist/goals/key.js +3 -0
- package/dist/goals/picker/clickGoalPicker.model.d.ts +29 -0
- package/dist/goals/picker/clickGoalPicker.model.js +45 -0
- package/dist/goals/picker/copy.d.ts +16 -0
- package/dist/goals/picker/copy.js +15 -0
- package/dist/goals/picker/useClickGoalPicker.d.ts +30 -0
- package/dist/goals/picker/useClickGoalPicker.js +220 -0
- package/dist/hooks/pageGuard.d.ts +5 -1
- package/dist/hooks/pageGuard.js +157 -95
- package/dist/onInit.js +29 -0
- package/dist/options.d.ts +2 -0
- package/dist/options.js +41 -1
- package/dist/plugin.js +41 -28
- package/dist/puck/copy.d.ts +1 -0
- package/dist/puck/copy.js +1 -0
- package/dist/puck/editor/editor.chrome.css +1 -0
- package/dist/puck/editor/editor.css +1 -0
- package/dist/puck/editor/editor.model.d.ts +4 -2
- package/dist/puck/editor/editor.model.js +6 -3
- package/dist/puck/editor/integration.d.ts +10 -0
- package/dist/puck/editor/integration.js +30 -0
- package/dist/puck/editor/xpGoalPuckEditorField.d.ts +7 -0
- package/dist/puck/editor/xpGoalPuckEditorField.js +134 -0
- package/dist/puck/integration.d.ts +6 -0
- package/dist/puck/integration.js +21 -0
- package/dist/puck/xpGoalField.d.ts +3 -0
- package/dist/puck/xpGoalField.js +6 -0
- package/dist/results/health.d.ts +4 -0
- package/dist/results/health.js +27 -0
- package/dist/results/snapshot.js +15 -2
- package/dist/sanitizeReadinessDetail.js +41 -0
- package/dist/server/pageKindSeoContract.d.ts +27 -0
- package/dist/server/pageKindSeoContract.js +80 -0
- package/dist/server/recordContentChange.js +58 -8
- package/dist/server/resolveExperimentBlocks.d.ts +5 -0
- package/dist/server/resolveExperimentBlocks.js +54 -0
- package/dist/server/runResults.js +56 -15
- package/dist/server/toClientAssignments.js +2 -1
- package/dist/transitions/addMetric.d.ts +2 -1
- package/dist/transitions/addMetric.js +28 -1
- package/dist/transitions/checkStart.d.ts +13 -1
- package/dist/transitions/checkStart.js +89 -7
- package/dist/transitions/decide.js +24 -0
- package/dist/transitions/deleteExperiment.d.ts +3 -1
- package/dist/transitions/deleteExperiment.js +27 -1
- package/dist/transitions/kernel.js +4 -0
- package/dist/transitions/makeContent.d.ts +5 -0
- package/dist/transitions/makeContent.js +39 -11
- package/dist/transitions/pageCollection.d.ts +10 -0
- package/dist/transitions/pageCollection.js +20 -0
- package/dist/transitions/pageVersions.d.ts +10 -0
- package/dist/transitions/pageVersions.js +44 -0
- package/dist/transitions/phaseRecord.d.ts +1 -0
- package/dist/transitions/placementInteractions.d.ts +40 -0
- package/dist/transitions/placementInteractions.js +94 -0
- package/dist/transitions/placements.d.ts +8 -0
- package/dist/transitions/placements.js +148 -1
- package/dist/transitions/preflightData.d.ts +2 -2
- package/dist/transitions/preflightData.js +137 -5
- package/dist/transitions/resolveCaps.d.ts +1 -0
- package/dist/transitions/resolveCaps.js +6 -2
- package/dist/transitions/start.js +45 -1
- package/dist/types/admin.d.ts +1 -1
- package/dist/types/assignments.d.ts +1 -0
- package/dist/types/contracts.d.ts +15 -0
- package/dist/types/endpoints.d.ts +92 -5
- package/dist/types/index.d.ts +3 -0
- package/dist/types/puck.d.ts +7 -1
- package/dist/types/snapshot.d.ts +17 -4
- package/dist/types/surface.d.ts +13 -0
- package/package.json +8 -1
|
@@ -3,7 +3,7 @@ import { formatDate } from '../format/date.js';
|
|
|
3
3
|
import { armLabel } from '../labels.js';
|
|
4
4
|
import { statusPill } from '../status.model.js';
|
|
5
5
|
import { decidedLine, runningLine, SURFACE_COPY } from '../copy/surface.js';
|
|
6
|
-
import { nextCopy } from '../copy/readiness.js';
|
|
6
|
+
import { asymmetricGoalsCopy, nextCopy, READINESS_COPY } from '../copy/readiness.js';
|
|
7
7
|
import { READINESS } from './readiness/readiness.model.js';
|
|
8
8
|
import { sanitizeReadinessDetail } from '../../sanitizeReadinessDetail.js';
|
|
9
9
|
export function healthDot(test, summary) {
|
|
@@ -30,7 +30,7 @@ export function groupTests(tests, summaries, search = '') {
|
|
|
30
30
|
const number = (value)=>value != null && Number.isFinite(value) ? new Intl.NumberFormat('en-US', {
|
|
31
31
|
maximumFractionDigits: 0
|
|
32
32
|
}).format(value) : '—';
|
|
33
|
-
export function homeCard(test, summary, adminRoute, flagPoints) {
|
|
33
|
+
export function homeCard(test, summary, adminRoute, flagPoints, goalNames = {}) {
|
|
34
34
|
const results = [
|
|
35
35
|
'running',
|
|
36
36
|
'stopped',
|
|
@@ -45,12 +45,16 @@ export function homeCard(test, summary, adminRoute, flagPoints) {
|
|
|
45
45
|
const next = summary?.next;
|
|
46
46
|
if ((test.status === 'draft' || test.status === 'stopped') && summary?.ready !== true && next && Object.hasOwn(READINESS, next.code)) {
|
|
47
47
|
// Keep unexpected text out of authored copy, including responses from older servers.
|
|
48
|
-
const
|
|
48
|
+
const detail = sanitizeReadinessDetail(next.code, next.detail);
|
|
49
|
+
const first = Array.isArray(detail) ? detail[0] : undefined;
|
|
50
|
+
const sentence = next.code === 'goal-in-some-versions' ? asymmetricGoalsCopy({
|
|
51
|
+
name: first?.metricId == null ? undefined : goalNames[String(first.metricId)]
|
|
52
|
+
}) : READINESS[next.code].next(detail, {
|
|
49
53
|
...test,
|
|
50
54
|
arms: test.arms ?? [],
|
|
51
55
|
flagPoints
|
|
52
56
|
});
|
|
53
|
-
if (sentence) line = nextCopy(sentence);
|
|
57
|
+
if (sentence) line = nextCopy(next.code === 'page-no-targets' ? READINESS_COPY.choosePages : sentence);
|
|
54
58
|
}
|
|
55
59
|
if (test.status === 'running') line = runningLine(number(summary?.days), number(test.analysis?.plannedDurationDays), number(summary?.exposures));
|
|
56
60
|
if (test.status === 'decided') {
|
|
@@ -6,10 +6,13 @@ import { useRouter } from 'next/navigation.js';
|
|
|
6
6
|
import { formatAdminURL } from 'payload/shared';
|
|
7
7
|
import { NEW_TEST_COPY as C } from '../../copy/newTest.js';
|
|
8
8
|
import { CreateRefused, createTest } from '../../../puck/editor/createTest.js';
|
|
9
|
+
import { PageWizard } from './PageWizard.js';
|
|
9
10
|
import './newTest.css';
|
|
10
11
|
export function NewTest({ surface, pages }) {
|
|
11
12
|
const router = useRouter();
|
|
12
13
|
const [step, setStep] = useState('kind');
|
|
14
|
+
const [kind, setKind] = useState('flag');
|
|
15
|
+
const [created, setCreated] = useState();
|
|
13
16
|
const [pointId, setPointId] = useState('');
|
|
14
17
|
const point = surface.flagPoints.find((item)=>item.id === pointId);
|
|
15
18
|
const [unitType, setUnitType] = useState('visitor');
|
|
@@ -50,23 +53,32 @@ export function NewTest({ surface, pages }) {
|
|
|
50
53
|
layerRetry
|
|
51
54
|
]);
|
|
52
55
|
async function submit() {
|
|
53
|
-
if (inFlight.current || !point || !name.trim()) return;
|
|
56
|
+
if (inFlight.current || kind === 'flag' && !point || !name.trim()) return;
|
|
54
57
|
inFlight.current = true;
|
|
55
58
|
setPending(true);
|
|
56
59
|
setError('');
|
|
57
60
|
try {
|
|
58
61
|
const { id } = await createTest(surface.apiRoute, {
|
|
59
|
-
kind
|
|
60
|
-
unitType,
|
|
62
|
+
kind,
|
|
63
|
+
unitType: kind === 'page' ? 'visitor' : unitType,
|
|
61
64
|
name,
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
...kind === 'flag' ? {
|
|
66
|
+
flagPoint: point.id
|
|
67
|
+
} : surface.pageCollections?.length === 1 ? {
|
|
68
|
+
pageCollection: surface.pageCollections[0].slug
|
|
69
|
+
} : {},
|
|
70
|
+
...kind !== 'flag' || layer === undefined ? {} : {
|
|
64
71
|
layer
|
|
65
72
|
},
|
|
66
73
|
...hypothesis.trim() ? {
|
|
67
74
|
hypothesis
|
|
68
75
|
} : {}
|
|
69
76
|
});
|
|
77
|
+
if (kind === 'page') {
|
|
78
|
+
setCreated(id);
|
|
79
|
+
setPending(false);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
70
82
|
router.push(formatAdminURL({
|
|
71
83
|
adminRoute: surface.adminRoute,
|
|
72
84
|
path: `/experiments/${encodeURIComponent(String(id))}`
|
|
@@ -77,6 +89,10 @@ export function NewTest({ surface, pages }) {
|
|
|
77
89
|
setPending(false);
|
|
78
90
|
}
|
|
79
91
|
}
|
|
92
|
+
if (created !== undefined) return /*#__PURE__*/ _jsx(PageWizard, {
|
|
93
|
+
id: created,
|
|
94
|
+
surface: surface
|
|
95
|
+
});
|
|
80
96
|
const collections = [
|
|
81
97
|
...new Set(pages?.map((page)=>page.collection))
|
|
82
98
|
];
|
|
@@ -102,15 +118,37 @@ export function NewTest({ surface, pages }) {
|
|
|
102
118
|
/*#__PURE__*/ _jsx("span", {
|
|
103
119
|
children: C.blockMeaning
|
|
104
120
|
}),
|
|
105
|
-
surface.descriptions?.block ? /*#__PURE__*/ _jsx("span", {
|
|
106
|
-
children: surface.descriptions
|
|
121
|
+
surface.admin?.descriptions?.block ? /*#__PURE__*/ _jsx("span", {
|
|
122
|
+
children: surface.admin?.descriptions?.block
|
|
123
|
+
}) : null
|
|
124
|
+
]
|
|
125
|
+
}) : null,
|
|
126
|
+
surface.pageCollections?.length ? /*#__PURE__*/ _jsxs("button", {
|
|
127
|
+
type: "button",
|
|
128
|
+
className: "xp-new-test-card",
|
|
129
|
+
onClick: ()=>{
|
|
130
|
+
setKind('page');
|
|
131
|
+
setStep('name');
|
|
132
|
+
},
|
|
133
|
+
children: [
|
|
134
|
+
/*#__PURE__*/ _jsx("strong", {
|
|
135
|
+
children: C.page
|
|
136
|
+
}),
|
|
137
|
+
/*#__PURE__*/ _jsx("span", {
|
|
138
|
+
children: C.pageMeaning
|
|
139
|
+
}),
|
|
140
|
+
surface.admin?.descriptions?.page ? /*#__PURE__*/ _jsx("span", {
|
|
141
|
+
children: surface.admin?.descriptions?.page
|
|
107
142
|
}) : null
|
|
108
143
|
]
|
|
109
144
|
}) : null,
|
|
110
145
|
surface.flagPoints.length > 0 ? /*#__PURE__*/ _jsxs("button", {
|
|
111
146
|
type: "button",
|
|
112
147
|
className: "xp-new-test-card",
|
|
113
|
-
onClick: ()=>
|
|
148
|
+
onClick: ()=>{
|
|
149
|
+
setKind('flag');
|
|
150
|
+
setStep('setting');
|
|
151
|
+
},
|
|
114
152
|
children: [
|
|
115
153
|
/*#__PURE__*/ _jsx("strong", {
|
|
116
154
|
children: C.setting
|
|
@@ -118,14 +156,14 @@ export function NewTest({ surface, pages }) {
|
|
|
118
156
|
/*#__PURE__*/ _jsx("span", {
|
|
119
157
|
children: C.settingMeaning
|
|
120
158
|
}),
|
|
121
|
-
surface.descriptions?.setting ? /*#__PURE__*/ _jsx("span", {
|
|
122
|
-
children: surface.descriptions.setting
|
|
159
|
+
surface.admin?.descriptions?.setting ? /*#__PURE__*/ _jsx("span", {
|
|
160
|
+
children: surface.admin?.descriptions.setting
|
|
123
161
|
}) : null
|
|
124
162
|
]
|
|
125
163
|
}) : null
|
|
126
164
|
]
|
|
127
165
|
}),
|
|
128
|
-
pages === undefined && !surface.flagPoints.length ? /*#__PURE__*/ _jsx("p", {
|
|
166
|
+
pages === undefined && !surface.flagPoints.length && !surface.pageCollections?.length ? /*#__PURE__*/ _jsx("p", {
|
|
129
167
|
children: C.unavailable
|
|
130
168
|
}) : null
|
|
131
169
|
]
|
|
@@ -156,7 +194,10 @@ export function NewTest({ surface, pages }) {
|
|
|
156
194
|
/*#__PURE__*/ _jsx("a", {
|
|
157
195
|
href: page.editorUrl,
|
|
158
196
|
children: C.open
|
|
159
|
-
})
|
|
197
|
+
}),
|
|
198
|
+
page.editor === 'blocks' ? /*#__PURE__*/ _jsx("p", {
|
|
199
|
+
children: C.blocksHandoff
|
|
200
|
+
}) : null
|
|
160
201
|
]
|
|
161
202
|
}, `${typeof page.id}:${page.id}`))
|
|
162
203
|
}),
|
|
@@ -337,7 +378,7 @@ export function NewTest({ surface, pages }) {
|
|
|
337
378
|
}));
|
|
338
379
|
else {
|
|
339
380
|
setError('');
|
|
340
|
-
setStep(step === 'name' ? 'setting' : 'kind');
|
|
381
|
+
setStep(step === 'name' && kind === 'flag' ? 'setting' : 'kind');
|
|
341
382
|
}
|
|
342
383
|
},
|
|
343
384
|
children: C.back
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DocId } from '../../../types/contracts.js';
|
|
2
|
+
import type { SurfaceProps } from '../contracts.js';
|
|
3
|
+
/** One session stays mounted across Collection, all page steps and Review. */
|
|
4
|
+
export declare function PageWizard({ id, surface }: {
|
|
5
|
+
id: DocId;
|
|
6
|
+
surface: SurfaceProps;
|
|
7
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { useRouter } from 'next/navigation.js';
|
|
5
|
+
import { formatAdminURL } from 'payload/shared';
|
|
6
|
+
import { useTestDocument } from '../useTestDocument.js';
|
|
7
|
+
import { CopyRoute } from '../pagePicker/CopyRoute.js';
|
|
8
|
+
import { PagePicker } from '../pagePicker/PagePicker.js';
|
|
9
|
+
import { testPageCollection, controlFirst } from '../pagePicker/pagePicker.model.js';
|
|
10
|
+
import { NEW_TEST_COPY as C } from '../../copy/newTest.js';
|
|
11
|
+
import { READINESS_COPY } from '../../copy/readiness.js';
|
|
12
|
+
import { TEST_PAGE } from '../../copy/testPage.js';
|
|
13
|
+
import { SURFACE_COPY } from '../../copy/surface.js';
|
|
14
|
+
import { pageStepCopy } from '../../copy/pages.js';
|
|
15
|
+
import { READINESS, nextStep, pageReadinessContext, readinessArm } from '../readiness/readiness.model.js';
|
|
16
|
+
import { SaveStatus } from '../readiness/SaveStatus.js';
|
|
17
|
+
import { createApi } from '../../api.js';
|
|
18
|
+
import { useTransition } from '../readiness/useTransition.js';
|
|
19
|
+
/** One session stays mounted across Collection, all page steps and Review. */ export function PageWizard({ id, surface }) {
|
|
20
|
+
const router = useRouter();
|
|
21
|
+
const collections = surface.pageCollections ?? [];
|
|
22
|
+
const [step, setStep] = useState(collections.length > 1 ? 'collection' : 'control');
|
|
23
|
+
const test = useTestDocument(id, {
|
|
24
|
+
apiRoute: surface.apiRoute,
|
|
25
|
+
refetchPreflightOnFocus: step === 'review'
|
|
26
|
+
});
|
|
27
|
+
const testUrl = formatAdminURL({
|
|
28
|
+
adminRoute: surface.adminRoute,
|
|
29
|
+
path: `/experiments/${encodeURIComponent(String(id))}`
|
|
30
|
+
});
|
|
31
|
+
const transition = useTransition(test, ()=>router.push(testUrl));
|
|
32
|
+
useEffect(()=>{
|
|
33
|
+
if (step === 'review') void test.refreshPreflight();
|
|
34
|
+
}, [
|
|
35
|
+
step,
|
|
36
|
+
test.refreshPreflight
|
|
37
|
+
]);
|
|
38
|
+
const leave = ()=>router.push(testUrl);
|
|
39
|
+
if (test.loadState === 'loading') return /*#__PURE__*/ _jsx("p", {
|
|
40
|
+
role: "status",
|
|
41
|
+
children: TEST_PAGE.loading
|
|
42
|
+
});
|
|
43
|
+
if (!test.doc || test.loadState !== 'ready') return /*#__PURE__*/ _jsxs("div", {
|
|
44
|
+
children: [
|
|
45
|
+
/*#__PURE__*/ _jsx("p", {
|
|
46
|
+
role: "alert",
|
|
47
|
+
children: test.loadState === 'forbidden' ? TEST_PAGE.forbidden : test.loadState === 'missing' ? TEST_PAGE.missing : TEST_PAGE.error
|
|
48
|
+
}),
|
|
49
|
+
/*#__PURE__*/ _jsx("button", {
|
|
50
|
+
type: "button",
|
|
51
|
+
onClick: ()=>void test.reload(),
|
|
52
|
+
children: TEST_PAGE.retry
|
|
53
|
+
}),
|
|
54
|
+
/*#__PURE__*/ _jsx("button", {
|
|
55
|
+
type: "button",
|
|
56
|
+
onClick: leave,
|
|
57
|
+
children: C.backToTest
|
|
58
|
+
})
|
|
59
|
+
]
|
|
60
|
+
});
|
|
61
|
+
const doc = test.doc;
|
|
62
|
+
const collection = testPageCollection(collections, doc, test.preflight?.pagePlacements);
|
|
63
|
+
const arms = controlFirst(doc.arms).filter((arm)=>arm.kind !== 'holdout');
|
|
64
|
+
const steps = [
|
|
65
|
+
...collections.length > 1 ? [
|
|
66
|
+
'collection'
|
|
67
|
+
] : [],
|
|
68
|
+
...arms.map((arm)=>arm.key),
|
|
69
|
+
'review'
|
|
70
|
+
];
|
|
71
|
+
const arm = arms.find((item)=>item.key === step);
|
|
72
|
+
const ctx = pageReadinessContext(doc, test.preflight, surface);
|
|
73
|
+
const next = nextStep(test.preflight, ctx);
|
|
74
|
+
const ready = Boolean(test.preflight && !test.preflightPending && !test.preflightError && test.preflight.checks.every((check)=>check.ok));
|
|
75
|
+
const busy = test.hasUnsaved || test.saving === 'saving' || transition.busy;
|
|
76
|
+
const jump = (section, key)=>{
|
|
77
|
+
if (section === 'versions') setStep(key ?? arms.find((item)=>!item.pageTarget)?.key ?? 'control');
|
|
78
|
+
else router.push(`${testUrl}#section-${section}`);
|
|
79
|
+
};
|
|
80
|
+
const picker = arm && collection ? /*#__PURE__*/ _jsx(PagePicker, {
|
|
81
|
+
collection: collection,
|
|
82
|
+
test: test,
|
|
83
|
+
armKey: arm.key,
|
|
84
|
+
apiRoute: surface.apiRoute
|
|
85
|
+
}, `${collection.slug}/${arm.key}`) : null;
|
|
86
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
87
|
+
className: "xp-new-test xp-page-wizard",
|
|
88
|
+
children: [
|
|
89
|
+
/*#__PURE__*/ _jsx("h2", {
|
|
90
|
+
children: step === 'collection' ? C.collection : step === 'review' ? C.review : arm?.kind === 'control' ? C.original : pageStepCopy(arm?.label ?? '')
|
|
91
|
+
}),
|
|
92
|
+
/*#__PURE__*/ _jsx(SaveStatus, {
|
|
93
|
+
test: test
|
|
94
|
+
}),
|
|
95
|
+
test.errors._section ? /*#__PURE__*/ _jsx("p", {
|
|
96
|
+
role: "alert",
|
|
97
|
+
children: test.errors._section
|
|
98
|
+
}) : null,
|
|
99
|
+
step === 'collection' ? /*#__PURE__*/ _jsxs("fieldset", {
|
|
100
|
+
children: [
|
|
101
|
+
/*#__PURE__*/ _jsx("legend", {
|
|
102
|
+
children: C.collection
|
|
103
|
+
}),
|
|
104
|
+
collections.map((entry)=>/*#__PURE__*/ _jsxs("label", {
|
|
105
|
+
children: [
|
|
106
|
+
/*#__PURE__*/ _jsx("input", {
|
|
107
|
+
type: "radio",
|
|
108
|
+
name: "page-collection",
|
|
109
|
+
checked: doc.pageCollection === entry.slug,
|
|
110
|
+
disabled: busy,
|
|
111
|
+
onChange: ()=>{
|
|
112
|
+
test.stage({
|
|
113
|
+
pageCollection: entry.slug
|
|
114
|
+
});
|
|
115
|
+
void test.commit();
|
|
116
|
+
}
|
|
117
|
+
}),
|
|
118
|
+
entry.label
|
|
119
|
+
]
|
|
120
|
+
}, entry.slug))
|
|
121
|
+
]
|
|
122
|
+
}) : step === 'review' ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
123
|
+
children: [
|
|
124
|
+
test.preflightError ? /*#__PURE__*/ _jsx("p", {
|
|
125
|
+
role: "alert",
|
|
126
|
+
children: test.preflightError
|
|
127
|
+
}) : null,
|
|
128
|
+
/*#__PURE__*/ _jsx("ul", {
|
|
129
|
+
children: test.preflight?.checks.map((check, index)=>{
|
|
130
|
+
if (!Object.hasOwn(READINESS, check.code)) return check.ok ? null : /*#__PURE__*/ _jsx("li", {
|
|
131
|
+
children: SURFACE_COPY.next
|
|
132
|
+
}, `${check.code}/${index}`);
|
|
133
|
+
const row = READINESS[check.code];
|
|
134
|
+
const sentence = row.next(check.detail, ctx);
|
|
135
|
+
const label = typeof row.nextStep === 'function' ? row.nextStep(check.detail, ctx) : row.nextStep;
|
|
136
|
+
return sentence && !check.ok ? /*#__PURE__*/ _jsxs("li", {
|
|
137
|
+
children: [
|
|
138
|
+
sentence,
|
|
139
|
+
label ? /*#__PURE__*/ _jsx("button", {
|
|
140
|
+
type: "button",
|
|
141
|
+
onClick: ()=>jump(row.section, readinessArm(check.code, check.detail, ctx)),
|
|
142
|
+
children: label
|
|
143
|
+
}) : null
|
|
144
|
+
]
|
|
145
|
+
}, `${check.code}/${index}`) : null;
|
|
146
|
+
})
|
|
147
|
+
}),
|
|
148
|
+
ready ? /*#__PURE__*/ _jsx("p", {
|
|
149
|
+
children: READINESS_COPY.ready
|
|
150
|
+
}) : null,
|
|
151
|
+
/*#__PURE__*/ _jsx("button", {
|
|
152
|
+
type: "button",
|
|
153
|
+
disabled: busy || test.preflightPending || !test.preflight,
|
|
154
|
+
onClick: ()=>{
|
|
155
|
+
if (ready) void transition.run(()=>createApi(surface.apiRoute).start(id));
|
|
156
|
+
else if (next) jump(next.section, next.arm);
|
|
157
|
+
},
|
|
158
|
+
children: ready ? C.start : C.finishSetup
|
|
159
|
+
}),
|
|
160
|
+
transition.error ? /*#__PURE__*/ _jsx("p", {
|
|
161
|
+
role: "alert",
|
|
162
|
+
children: transition.error
|
|
163
|
+
}) : null
|
|
164
|
+
]
|
|
165
|
+
}) : arm?.kind === 'control' ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
166
|
+
children: [
|
|
167
|
+
/*#__PURE__*/ _jsx("p", {
|
|
168
|
+
children: C.originalHelp
|
|
169
|
+
}),
|
|
170
|
+
picker
|
|
171
|
+
]
|
|
172
|
+
}) : collection ? /*#__PURE__*/ _jsx(CopyRoute, {
|
|
173
|
+
collection: collection,
|
|
174
|
+
children: picker
|
|
175
|
+
}) : null,
|
|
176
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
177
|
+
className: "xp-new-test-actions",
|
|
178
|
+
children: [
|
|
179
|
+
/*#__PURE__*/ _jsx("button", {
|
|
180
|
+
type: "button",
|
|
181
|
+
disabled: busy,
|
|
182
|
+
onClick: ()=>{
|
|
183
|
+
const previous = steps[steps.indexOf(step) - 1];
|
|
184
|
+
if (previous) setStep(previous);
|
|
185
|
+
else leave();
|
|
186
|
+
},
|
|
187
|
+
children: C.back
|
|
188
|
+
}),
|
|
189
|
+
/*#__PURE__*/ _jsx("button", {
|
|
190
|
+
type: "button",
|
|
191
|
+
disabled: busy,
|
|
192
|
+
onClick: leave,
|
|
193
|
+
children: C.backToTest
|
|
194
|
+
}),
|
|
195
|
+
step !== 'review' ? /*#__PURE__*/ _jsx("button", {
|
|
196
|
+
type: "button",
|
|
197
|
+
disabled: busy || step === 'collection' && !collection,
|
|
198
|
+
onClick: ()=>setStep(steps[steps.indexOf(step) + 1] ?? 'review'),
|
|
199
|
+
children: C.next
|
|
200
|
+
}) : null
|
|
201
|
+
]
|
|
202
|
+
}),
|
|
203
|
+
test.errors.pageCollection ? /*#__PURE__*/ _jsx("p", {
|
|
204
|
+
role: "alert",
|
|
205
|
+
children: test.errors.pageCollection
|
|
206
|
+
}) : null
|
|
207
|
+
]
|
|
208
|
+
});
|
|
209
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { PAGE_COPY as C, openCollectionCopy, openOriginalCopy } from '../../copy/pages.js';
|
|
4
|
+
export function CopyRoute({ collection, children }) {
|
|
5
|
+
const link = /*#__PURE__*/ _jsx("a", {
|
|
6
|
+
href: collection.copyUrl,
|
|
7
|
+
target: "_blank",
|
|
8
|
+
rel: "noopener",
|
|
9
|
+
children: collection.copyLabel ?? openCollectionCopy(collection.label)
|
|
10
|
+
});
|
|
11
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
12
|
+
className: "xp-copy-route",
|
|
13
|
+
children: [
|
|
14
|
+
/*#__PURE__*/ _jsx("div", {
|
|
15
|
+
className: "xp-copy-route-action"
|
|
16
|
+
}),
|
|
17
|
+
collection.copyHint ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
18
|
+
children: [
|
|
19
|
+
/*#__PURE__*/ _jsxs("p", {
|
|
20
|
+
children: [
|
|
21
|
+
collection.copyHint,
|
|
22
|
+
' ',
|
|
23
|
+
link
|
|
24
|
+
]
|
|
25
|
+
}),
|
|
26
|
+
/*#__PURE__*/ _jsx("p", {
|
|
27
|
+
children: C.ownAddress
|
|
28
|
+
})
|
|
29
|
+
]
|
|
30
|
+
}) : /*#__PURE__*/ _jsxs("ol", {
|
|
31
|
+
children: [
|
|
32
|
+
/*#__PURE__*/ _jsxs("li", {
|
|
33
|
+
children: [
|
|
34
|
+
openOriginalCopy(collection.label),
|
|
35
|
+
' ',
|
|
36
|
+
link
|
|
37
|
+
]
|
|
38
|
+
}),
|
|
39
|
+
/*#__PURE__*/ _jsx("li", {
|
|
40
|
+
children: C.duplicateStep
|
|
41
|
+
}),
|
|
42
|
+
/*#__PURE__*/ _jsx("li", {
|
|
43
|
+
children: C.ownAddress
|
|
44
|
+
})
|
|
45
|
+
]
|
|
46
|
+
}),
|
|
47
|
+
/*#__PURE__*/ _jsx("p", {
|
|
48
|
+
children: C.thenChoose
|
|
49
|
+
}),
|
|
50
|
+
children
|
|
51
|
+
]
|
|
52
|
+
});
|
|
53
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TestDocApi } from '../contracts.js';
|
|
2
|
+
import type { PageCollection } from './pagePicker.model.js';
|
|
3
|
+
/** Mount on open; every reopen and return from another tab refreshes the current query. */
|
|
4
|
+
export declare function PagePicker({ collection, test, armKey, apiRoute, onChoose }: {
|
|
5
|
+
collection: PageCollection;
|
|
6
|
+
test: TestDocApi;
|
|
7
|
+
armKey: string;
|
|
8
|
+
apiRoute: string;
|
|
9
|
+
onChoose?: () => void;
|
|
10
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useId, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { createApi } from '../../api.js';
|
|
5
|
+
import { PAGE_COPY as C } from '../../copy/pages.js';
|
|
6
|
+
import { reasonFor } from '../test/fields.js';
|
|
7
|
+
import { disabledPageReason, isLatestPageRequest } from './pagePicker.model.js';
|
|
8
|
+
/** Mount on open; every reopen and return from another tab refreshes the current query. */ export function PagePicker({ collection, test, armKey, apiRoute, onChoose }) {
|
|
9
|
+
const api = useMemo(()=>createApi(apiRoute), [
|
|
10
|
+
apiRoute
|
|
11
|
+
]);
|
|
12
|
+
const id = useId();
|
|
13
|
+
const [search, setSearch] = useState('');
|
|
14
|
+
const [q, setQuery] = useState('');
|
|
15
|
+
const [page, setPage] = useState(1);
|
|
16
|
+
const [refresh, setRefresh] = useState(0);
|
|
17
|
+
const [rows, setRows] = useState([]);
|
|
18
|
+
const [more, setMore] = useState(false);
|
|
19
|
+
const [loading, setLoading] = useState(true);
|
|
20
|
+
const [error, setError] = useState('');
|
|
21
|
+
const revision = useRef(0);
|
|
22
|
+
const reload = ()=>{
|
|
23
|
+
setPage(1);
|
|
24
|
+
setRefresh((value)=>value + 1);
|
|
25
|
+
};
|
|
26
|
+
useEffect(()=>{
|
|
27
|
+
if (search === q) return;
|
|
28
|
+
const timer = setTimeout(()=>{
|
|
29
|
+
setQuery(search);
|
|
30
|
+
setPage(1);
|
|
31
|
+
setRows([]);
|
|
32
|
+
setMore(false);
|
|
33
|
+
setLoading(true);
|
|
34
|
+
setError('');
|
|
35
|
+
}, 250);
|
|
36
|
+
return ()=>clearTimeout(timer);
|
|
37
|
+
}, [
|
|
38
|
+
search,
|
|
39
|
+
q
|
|
40
|
+
]);
|
|
41
|
+
useEffect(()=>{
|
|
42
|
+
let lastReturn = -Infinity;
|
|
43
|
+
const focus = ()=>{
|
|
44
|
+
if (document.visibilityState !== 'visible' || Date.now() - lastReturn < 100) return;
|
|
45
|
+
lastReturn = Date.now();
|
|
46
|
+
setPage(1);
|
|
47
|
+
setRefresh((value)=>value + 1);
|
|
48
|
+
};
|
|
49
|
+
const visible = ()=>{
|
|
50
|
+
if (document.visibilityState === 'visible') focus();
|
|
51
|
+
};
|
|
52
|
+
window.addEventListener('focus', focus);
|
|
53
|
+
document.addEventListener('visibilitychange', visible);
|
|
54
|
+
return ()=>{
|
|
55
|
+
window.removeEventListener('focus', focus);
|
|
56
|
+
document.removeEventListener('visibilitychange', visible);
|
|
57
|
+
};
|
|
58
|
+
}, []);
|
|
59
|
+
useEffect(()=>{
|
|
60
|
+
const controller = new AbortController();
|
|
61
|
+
const request = ++revision.current;
|
|
62
|
+
setLoading(true);
|
|
63
|
+
setError('');
|
|
64
|
+
void api.pages({
|
|
65
|
+
collection: collection.slug,
|
|
66
|
+
q,
|
|
67
|
+
page
|
|
68
|
+
}, controller.signal).then((result)=>{
|
|
69
|
+
if (controller.signal.aborted || !isLatestPageRequest(request, revision.current)) return;
|
|
70
|
+
if (result.ok && result.data) {
|
|
71
|
+
const docs = result.data.docs;
|
|
72
|
+
setRows((current)=>{
|
|
73
|
+
const combined = page === 1 ? docs : [
|
|
74
|
+
...current,
|
|
75
|
+
...docs
|
|
76
|
+
];
|
|
77
|
+
return combined.filter((row, index)=>combined.findIndex((item)=>item.id === row.id) === index);
|
|
78
|
+
});
|
|
79
|
+
setMore(result.data.hasNextPage);
|
|
80
|
+
} else {
|
|
81
|
+
setMore(false);
|
|
82
|
+
setError(C.error);
|
|
83
|
+
}
|
|
84
|
+
setLoading(false);
|
|
85
|
+
});
|
|
86
|
+
return ()=>controller.abort();
|
|
87
|
+
}, [
|
|
88
|
+
api,
|
|
89
|
+
collection.slug,
|
|
90
|
+
q,
|
|
91
|
+
page,
|
|
92
|
+
refresh
|
|
93
|
+
]);
|
|
94
|
+
const reason = reasonFor(test, 'arms');
|
|
95
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
96
|
+
className: "xp-page-picker",
|
|
97
|
+
children: [
|
|
98
|
+
/*#__PURE__*/ _jsx("label", {
|
|
99
|
+
htmlFor: id,
|
|
100
|
+
children: C.search
|
|
101
|
+
}),
|
|
102
|
+
/*#__PURE__*/ _jsx("input", {
|
|
103
|
+
id: id,
|
|
104
|
+
type: "search",
|
|
105
|
+
value: search,
|
|
106
|
+
onChange: (event)=>setSearch(event.currentTarget.value)
|
|
107
|
+
}),
|
|
108
|
+
loading && !rows.length ? /*#__PURE__*/ _jsx("p", {
|
|
109
|
+
role: "status",
|
|
110
|
+
children: C.loading
|
|
111
|
+
}) : null,
|
|
112
|
+
error ? /*#__PURE__*/ _jsxs("p", {
|
|
113
|
+
role: "alert",
|
|
114
|
+
children: [
|
|
115
|
+
error,
|
|
116
|
+
" ",
|
|
117
|
+
/*#__PURE__*/ _jsx("button", {
|
|
118
|
+
type: "button",
|
|
119
|
+
onClick: reload,
|
|
120
|
+
children: C.retry
|
|
121
|
+
})
|
|
122
|
+
]
|
|
123
|
+
}) : null,
|
|
124
|
+
!rows.length ? !loading && !error ? /*#__PURE__*/ _jsx("p", {
|
|
125
|
+
children: C.empty
|
|
126
|
+
}) : null : /*#__PURE__*/ _jsx("ul", {
|
|
127
|
+
children: rows.map((row)=>{
|
|
128
|
+
const disabled = reason ?? disabledPageReason(row, armKey, test.doc?.arms ?? [], test.preflight?.pagePlacements, test.chosenPages, collection.label, collection.slug);
|
|
129
|
+
return /*#__PURE__*/ _jsxs("li", {
|
|
130
|
+
children: [
|
|
131
|
+
/*#__PURE__*/ _jsxs("button", {
|
|
132
|
+
type: "button",
|
|
133
|
+
disabled: !!disabled || test.saving === 'saving',
|
|
134
|
+
onClick: ()=>{
|
|
135
|
+
const arm = test.doc?.arms.find((item)=>item.key === armKey);
|
|
136
|
+
if (!arm || row.path === null || disabled) return;
|
|
137
|
+
void test.choosePage(arm.key, {
|
|
138
|
+
id: row.id,
|
|
139
|
+
path: row.path
|
|
140
|
+
});
|
|
141
|
+
onChoose?.();
|
|
142
|
+
},
|
|
143
|
+
children: [
|
|
144
|
+
/*#__PURE__*/ _jsx("strong", {
|
|
145
|
+
children: row.title
|
|
146
|
+
}),
|
|
147
|
+
' ',
|
|
148
|
+
row.path,
|
|
149
|
+
!row.published ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
150
|
+
children: [
|
|
151
|
+
" · ",
|
|
152
|
+
C.draft
|
|
153
|
+
]
|
|
154
|
+
}) : null
|
|
155
|
+
]
|
|
156
|
+
}),
|
|
157
|
+
disabled ? /*#__PURE__*/ _jsx("p", {
|
|
158
|
+
children: disabled
|
|
159
|
+
}) : null
|
|
160
|
+
]
|
|
161
|
+
}, row.id);
|
|
162
|
+
})
|
|
163
|
+
}),
|
|
164
|
+
more ? /*#__PURE__*/ _jsx("button", {
|
|
165
|
+
type: "button",
|
|
166
|
+
disabled: loading,
|
|
167
|
+
onClick: ()=>setPage((value)=>value + 1),
|
|
168
|
+
children: C.more
|
|
169
|
+
}) : null
|
|
170
|
+
]
|
|
171
|
+
});
|
|
172
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Arm, DocId } from '../../../types/contracts.js';
|
|
2
|
+
import type { PagesResult, PreflightResult } from '../../../types/endpoints.js';
|
|
3
|
+
import type { TestsSurfaceProps } from '../../../types/surface.js';
|
|
4
|
+
export type PageRow = PagesResult['docs'][number];
|
|
5
|
+
export type PageCollection = NonNullable<TestsSurfaceProps['pageCollections']>[number];
|
|
6
|
+
export type PageSelections = Partial<Record<Arm['key'], {
|
|
7
|
+
id: DocId;
|
|
8
|
+
path: string;
|
|
9
|
+
}>>;
|
|
10
|
+
/** The server resolves legacy collections; the client consumes its placements verbatim. */
|
|
11
|
+
export declare function testPageCollection(collections: readonly PageCollection[] | undefined, doc: {
|
|
12
|
+
pageCollection?: string | null;
|
|
13
|
+
}, placements: PreflightResult['pagePlacements']): {
|
|
14
|
+
slug: string;
|
|
15
|
+
label: string;
|
|
16
|
+
contentChecks: boolean;
|
|
17
|
+
copyHint?: string;
|
|
18
|
+
copyUrl?: string;
|
|
19
|
+
copyLabel?: string;
|
|
20
|
+
} | undefined;
|
|
21
|
+
export declare const controlFirst: (arms: readonly Arm[]) => Arm[];
|
|
22
|
+
/** Identity wins over address, so distinct documents sharing an address get actionable copy. */
|
|
23
|
+
export declare function disabledPageReason(row: PageRow, ownKey: string, arms: readonly Arm[], placements: PreflightResult['pagePlacements'], chosen: PageSelections, collection: string, collectionSlug?: string): string | null;
|
|
24
|
+
/** Pure request revision comparison, also used after an aborted transport resolves. */
|
|
25
|
+
export declare const isLatestPageRequest: (response: number, latest: number) => boolean;
|