@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
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare const BLOCK_COPY: {
|
|
2
|
+
testBlock: string;
|
|
3
|
+
pick: string;
|
|
4
|
+
empty: string;
|
|
5
|
+
blockChanged: string;
|
|
6
|
+
replace: string;
|
|
7
|
+
cancel: string;
|
|
8
|
+
retry: string;
|
|
9
|
+
saveFirst: string;
|
|
10
|
+
setup: string;
|
|
11
|
+
copy: string;
|
|
12
|
+
confirmCopy: string;
|
|
13
|
+
unwrap: string;
|
|
14
|
+
deleted: string;
|
|
15
|
+
discarded: string;
|
|
16
|
+
running: string;
|
|
17
|
+
stopped: string;
|
|
18
|
+
slotLabels: Record<string, string>;
|
|
19
|
+
wrapRefusals: Record<string, string>;
|
|
20
|
+
};
|
|
21
|
+
export declare const blockPosition: (label: string, position: number) => string;
|
|
22
|
+
export declare const blockTestName: (title: string, label: string) => string;
|
|
23
|
+
export declare const blockDraftStatus: (name: string) => string;
|
|
24
|
+
export declare const blockDecidedStatus: (winner: string, rollout: boolean) => string;
|
|
25
|
+
export declare const blockFinishedStatus: (winner: string) => string;
|
|
26
|
+
export declare const blockSaveNotice: (drafts: boolean) => "Save a draft of this page to add the test." | "Save this page to add the test.";
|
|
27
|
+
export declare const blockSyncNotice: (drafts: boolean) => "Versions were updated to match the test. Save draft to keep them." | "Versions were updated to match the test. Save to keep them.";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export const BLOCK_COPY = {
|
|
2
|
+
testBlock: 'Test a block on this page',
|
|
3
|
+
pick: 'Choose a block',
|
|
4
|
+
empty: 'There are no blocks on this page to test yet. Add one, save, then come back.',
|
|
5
|
+
blockChanged: 'This block changed while you were working. Nothing was replaced. Try again.',
|
|
6
|
+
replace: 'Replace',
|
|
7
|
+
cancel: 'Cancel',
|
|
8
|
+
retry: 'Try again',
|
|
9
|
+
saveFirst: 'Save your changes, then try again.',
|
|
10
|
+
setup: 'Set up the test',
|
|
11
|
+
copy: 'Copy the Original into this version',
|
|
12
|
+
confirmCopy: 'Replace this version’s content with a copy of the Original? Edits you made to this version will be lost.',
|
|
13
|
+
unwrap: 'Unwrap',
|
|
14
|
+
deleted: "This block's test was deleted; the page shows the Original.",
|
|
15
|
+
discarded: 'This test has ended; the page shows the Original.',
|
|
16
|
+
running: "Running: visitors see different versions. Edit a version's tab to change it; the change is noted on the results.",
|
|
17
|
+
stopped: 'Stopped: visitors see the Original.',
|
|
18
|
+
slotLabels: {
|
|
19
|
+
control: 'Original',
|
|
20
|
+
variantA: 'Variant A',
|
|
21
|
+
variantB: 'Variant B',
|
|
22
|
+
variantC: 'Variant C'
|
|
23
|
+
},
|
|
24
|
+
wrapRefusals: {
|
|
25
|
+
'wrap-target-missing': 'Reload the page and try again.',
|
|
26
|
+
'locked-placement': 'Another editor has this page open. Try again when it is unlocked.',
|
|
27
|
+
'invalid-status': 'This action is not available in the current status.',
|
|
28
|
+
'unknown-collection': "That page type isn't set up for tests.",
|
|
29
|
+
'invalid-body': 'Choose a block test.'
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
export const blockPosition = (label, position)=>`${label} (block ${position})`;
|
|
33
|
+
export const blockTestName = (title, label)=>`${title}: ${label}`;
|
|
34
|
+
export const blockDraftStatus = (name)=>`This block is being tested in the draft test ${name}. Visitors see the Original until it starts.`;
|
|
35
|
+
export const blockDecidedStatus = (winner, rollout)=>`Decided: visitors see ${winner}${rollout ? '; a holdout still sees the Original' : ''}.`;
|
|
36
|
+
export const blockFinishedStatus = (winner)=>`Finished: visitors see ${winner}. Use "Make it the content" on the test to replace this block.`;
|
|
37
|
+
export const blockSaveNotice = (drafts)=>drafts ? 'Save a draft of this page to add the test.' : 'Save this page to add the test.';
|
|
38
|
+
export const blockSyncNotice = (drafts)=>drafts ? 'Versions were updated to match the test. Save draft to keep them.' : 'Versions were updated to match the test. Save to keep them.';
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export declare const GOALS_COPY: {
|
|
2
|
+
readonly slugRule: "Use 1–64 lowercase letters, numbers, underscores or hyphens, starting with a letter or number.";
|
|
3
|
+
readonly duplicateSlug: "Another goal already uses this short name. Change it under Advanced.";
|
|
2
4
|
readonly title: "Goals";
|
|
3
5
|
readonly goal: "Goal";
|
|
4
6
|
readonly newGoal: "New goal";
|
package/dist/admin/copy/goals.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { CLICK_GOAL_COPY } from '../../goals/picker/copy.js';
|
|
1
2
|
export const GOALS_COPY = {
|
|
3
|
+
slugRule: CLICK_GOAL_COPY.slugRule,
|
|
4
|
+
duplicateSlug: CLICK_GOAL_COPY.duplicateSlug,
|
|
2
5
|
title: 'Goals',
|
|
3
6
|
goal: 'Goal',
|
|
4
7
|
newGoal: 'New goal',
|
|
@@ -38,7 +41,7 @@ export const GOALS_COPY = {
|
|
|
38
41
|
remove: 'Delete goal',
|
|
39
42
|
thresholdError: 'Enter a percentage of zero or more, or leave blank for 5%.',
|
|
40
43
|
deleting: 'Deleting…',
|
|
41
|
-
saveError:
|
|
44
|
+
saveError: CLICK_GOAL_COPY.saveError,
|
|
42
45
|
deleteError: "Couldn't delete the goal. Try again.",
|
|
43
46
|
breadcrumb: 'Breadcrumb',
|
|
44
47
|
missing: 'This goal no longer exists.',
|
|
@@ -2,6 +2,16 @@ export declare const NEW_TEST_COPY: {
|
|
|
2
2
|
readonly question: "What do you want to test?";
|
|
3
3
|
readonly block: "A block on a page";
|
|
4
4
|
readonly setting: "A setting";
|
|
5
|
+
readonly page: "A whole page";
|
|
6
|
+
readonly pageMeaning: "Show different versions of a whole page at the same address, and see which one works better.";
|
|
7
|
+
readonly collection: "Collection";
|
|
8
|
+
readonly original: "Original";
|
|
9
|
+
readonly originalHelp: "Choose the page visitors see today.";
|
|
10
|
+
readonly review: "Review";
|
|
11
|
+
readonly backToTest: "Back to the test";
|
|
12
|
+
readonly finishSetup: "Finish setup";
|
|
13
|
+
readonly start: "Start";
|
|
14
|
+
readonly blocksHandoff: "Pick the block to test with 'Test a block on this page'.";
|
|
5
15
|
readonly blockMeaning: "Compare different versions of content on a page.";
|
|
6
16
|
readonly settingMeaning: "Compare different choices for a setting on your site.";
|
|
7
17
|
readonly unavailable: "A developer needs to set up pages or settings before you can create a test.";
|
|
@@ -2,6 +2,16 @@ export const NEW_TEST_COPY = {
|
|
|
2
2
|
question: 'What do you want to test?',
|
|
3
3
|
block: 'A block on a page',
|
|
4
4
|
setting: 'A setting',
|
|
5
|
+
page: 'A whole page',
|
|
6
|
+
pageMeaning: 'Show different versions of a whole page at the same address, and see which one works better.',
|
|
7
|
+
collection: 'Collection',
|
|
8
|
+
original: 'Original',
|
|
9
|
+
originalHelp: 'Choose the page visitors see today.',
|
|
10
|
+
review: 'Review',
|
|
11
|
+
backToTest: 'Back to the test',
|
|
12
|
+
finishSetup: 'Finish setup',
|
|
13
|
+
start: 'Start',
|
|
14
|
+
blocksHandoff: "Pick the block to test with 'Test a block on this page'.",
|
|
5
15
|
blockMeaning: 'Compare different versions of content on a page.',
|
|
6
16
|
settingMeaning: 'Compare different choices for a setting on your site.',
|
|
7
17
|
unavailable: 'A developer needs to set up pages or settings before you can create a test.',
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare const PAGE_COPY: {
|
|
2
|
+
readonly search: "Search pages by title";
|
|
3
|
+
readonly more: "More";
|
|
4
|
+
readonly loading: "Loading pages…";
|
|
5
|
+
readonly empty: "There are no pages here yet.";
|
|
6
|
+
readonly error: "Couldn't load pages. Try again.";
|
|
7
|
+
readonly retry: "Try again";
|
|
8
|
+
readonly draft: "Draft";
|
|
9
|
+
readonly noPath: "This page has no address yet.";
|
|
10
|
+
readonly choose: "Choose a page";
|
|
11
|
+
readonly change: "Change";
|
|
12
|
+
readonly close: "Close";
|
|
13
|
+
readonly where: "Where it shows";
|
|
14
|
+
readonly open: "Open";
|
|
15
|
+
readonly preview: "Preview";
|
|
16
|
+
readonly contentChecksOff: "Content checks are off for this page type.";
|
|
17
|
+
readonly duplicateStep: "Choose Duplicate from the document's actions. Keep the Original's title on the copy, unless the title is what you're testing.";
|
|
18
|
+
readonly ownAddress: "Give the copy its own address and save it as a draft. Publish it when it's ready; the test can't start until it is.";
|
|
19
|
+
readonly thenChoose: "Then choose the page you made.";
|
|
20
|
+
readonly noPage: "No page chosen yet.";
|
|
21
|
+
};
|
|
22
|
+
export declare const usedPageCopy: (label: string) => string;
|
|
23
|
+
export declare const usedAddressCopy: (label: string, path: string, collection: string) => string;
|
|
24
|
+
export declare const openOriginalCopy: (collection: string) => string;
|
|
25
|
+
export declare const openCollectionCopy: (collection: string) => string;
|
|
26
|
+
export declare const pageStepCopy: (label: string) => string;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const PAGE_COPY = {
|
|
2
|
+
search: 'Search pages by title',
|
|
3
|
+
more: 'More',
|
|
4
|
+
loading: 'Loading pages…',
|
|
5
|
+
empty: 'There are no pages here yet.',
|
|
6
|
+
error: "Couldn't load pages. Try again.",
|
|
7
|
+
retry: 'Try again',
|
|
8
|
+
draft: 'Draft',
|
|
9
|
+
noPath: 'This page has no address yet.',
|
|
10
|
+
choose: 'Choose a page',
|
|
11
|
+
change: 'Change',
|
|
12
|
+
close: 'Close',
|
|
13
|
+
where: 'Where it shows',
|
|
14
|
+
open: 'Open',
|
|
15
|
+
preview: 'Preview',
|
|
16
|
+
contentChecksOff: 'Content checks are off for this page type.',
|
|
17
|
+
duplicateStep: "Choose Duplicate from the document's actions. Keep the Original's title on the copy, unless the title is what you're testing.",
|
|
18
|
+
ownAddress: "Give the copy its own address and save it as a draft. Publish it when it's ready; the test can't start until it is.",
|
|
19
|
+
thenChoose: 'Then choose the page you made.',
|
|
20
|
+
noPage: 'No page chosen yet.'
|
|
21
|
+
};
|
|
22
|
+
export const usedPageCopy = (label)=>`This is ${label}.`;
|
|
23
|
+
export const usedAddressCopy = (label, path, collection)=>`Same address as ${label} (${path}). Change this page's address in ${collection}, publish it, then choose it.`;
|
|
24
|
+
export const openOriginalCopy = (collection)=>`Open the Original in ${collection}.`;
|
|
25
|
+
export const openCollectionCopy = (collection)=>`Open ${collection}`;
|
|
26
|
+
export const pageStepCopy = (label)=>`A page for ${label}`;
|
|
@@ -35,7 +35,8 @@ export declare const READINESS_COPY: {
|
|
|
35
35
|
readonly differentPeople: "This test's group counts different people. Create the test again without the group.";
|
|
36
36
|
readonly uncheckedPages: "Version pages aren't checked; make sure each one is published.";
|
|
37
37
|
readonly chooseDifferentPage: "Choose a different page";
|
|
38
|
-
readonly
|
|
38
|
+
readonly choosePages: "Choose pages";
|
|
39
|
+
readonly noTargets: "Choose a page for each version.";
|
|
39
40
|
readonly pageVisitors: "Whole-page tests count visitors. Create the test again counting visitors.";
|
|
40
41
|
readonly blockPathRule: "Remove the page-path rule in Who takes part; page block tests run on their page.";
|
|
41
42
|
readonly removeRule: "Remove rule";
|
|
@@ -46,8 +47,12 @@ export declare const READINESS_COPY: {
|
|
|
46
47
|
readonly attributeFallback: "this attribute";
|
|
47
48
|
};
|
|
48
49
|
export declare const unsupportedContentCopy: (page: string) => string;
|
|
49
|
-
export declare const pageInUseCopy: (path: string) => string;
|
|
50
|
-
export declare const unpublishedPageCopy: (path: string
|
|
50
|
+
export declare const pageInUseCopy: (path: string, version?: boolean) => string;
|
|
51
|
+
export declare const unpublishedPageCopy: (path: string, context?: {
|
|
52
|
+
original: boolean;
|
|
53
|
+
found: boolean;
|
|
54
|
+
collection: string;
|
|
55
|
+
}) => string;
|
|
51
56
|
/** Old responses may include raw host errors; unknown strings use authored copy. */
|
|
52
57
|
export declare const placementFailureCopy: (reason: unknown) => "Couldn't check where this test is used. Try again." | "You don't have permission to check where this test is used." | "A page used by this test no longer exists. Choose another page.";
|
|
53
58
|
export declare const nextCopy: (sentence: string) => string;
|
|
@@ -65,3 +70,17 @@ export declare const runningCopy: (date: string | null, people: number | null, d
|
|
|
65
70
|
export declare const pageGuardCopy: (name: string, status: "running" | "decided" | "archived", role?: "winner" | "original") => string;
|
|
66
71
|
export declare const versionPageUnavailableCopy: (path: string, status?: string) => string;
|
|
67
72
|
export declare const versionPageUncheckedCopy: (path: string, status?: string) => string;
|
|
73
|
+
export declare const sameAddressCopy: (label: string, other: string, path: string, collection?: string) => string;
|
|
74
|
+
export declare const identicalVersionCopy: (version: string) => string;
|
|
75
|
+
/** Keep named actions aligned with the actual transition buttons. */
|
|
76
|
+
export declare function placementGuardCopy(page: {
|
|
77
|
+
name: string;
|
|
78
|
+
status: string;
|
|
79
|
+
}, block: {
|
|
80
|
+
name: string;
|
|
81
|
+
status: string;
|
|
82
|
+
}, preExisting: boolean): string;
|
|
83
|
+
export declare function interactingTestsCopy(page: string, state: string, name: string, version?: boolean): string;
|
|
84
|
+
export declare const goalInSomeVersionsCopy: (name?: string) => string;
|
|
85
|
+
export declare function asymmetricGoalsCopy(detail: unknown): string;
|
|
86
|
+
export declare const placementUncheckedCopy: (page: string) => string;
|
|
@@ -35,7 +35,8 @@ export const READINESS_COPY = {
|
|
|
35
35
|
differentPeople: "This test's group counts different people. Create the test again without the group.",
|
|
36
36
|
uncheckedPages: "Version pages aren't checked; make sure each one is published.",
|
|
37
37
|
chooseDifferentPage: 'Choose a different page',
|
|
38
|
-
|
|
38
|
+
choosePages: 'Choose pages',
|
|
39
|
+
noTargets: 'Choose a page for each version.',
|
|
39
40
|
pageVisitors: 'Whole-page tests count visitors. Create the test again counting visitors.',
|
|
40
41
|
blockPathRule: 'Remove the page-path rule in Who takes part; page block tests run on their page.',
|
|
41
42
|
// Next steps repeat the button label verbatim (testPage.ts removeRule).
|
|
@@ -47,8 +48,8 @@ export const READINESS_COPY = {
|
|
|
47
48
|
attributeFallback: 'this attribute'
|
|
48
49
|
};
|
|
49
50
|
export const unsupportedContentCopy = (page)=>`${page} has more than one language, so Make it the content isn't available for it; you'll copy the winning version by hand.`;
|
|
50
|
-
export const pageInUseCopy = (path)
|
|
51
|
-
export const unpublishedPageCopy = (path)
|
|
51
|
+
export const pageInUseCopy = (path, version = false)=>version ? `${path} is already in another running or decided test. Make a new copy of the Original for this version, or finish that test first.` : `Another running or decided test already uses ${path}. Choose a different page, or finish that test first.`;
|
|
52
|
+
export const unpublishedPageCopy = (path, context)=>!context ? `${path} isn't a published page yet. Publish it, or choose another page.` : context.original ? `${path} isn't published, so it can't be the Original. Publish it, or choose another page.` : context.found ? `${path} is still a draft. Publish it in ${context.collection}, then start the test.` : `${path} isn't published yet, or no page has that address. Publish it in ${context.collection}, or choose another page.`;
|
|
52
53
|
/** Old responses may include raw host errors; unknown strings use authored copy. */ export const placementFailureCopy = (reason)=>PLACEMENT_FAILURE_COPY[typeof reason === 'string' && Object.hasOwn(PLACEMENT_FAILURE_COPY, reason) ? reason : 'placements-failed'];
|
|
53
54
|
const withoutPeriod = (value)=>value.trim().replace(/[.!?]+$/, '');
|
|
54
55
|
export const nextCopy = (sentence)=>`Next: ${sentence}`;
|
|
@@ -69,3 +70,22 @@ export const runningCopy = (date, people, days)=>[
|
|
|
69
70
|
/** After archive the guard protects the winner and the Original; only the winner page is "the winner". */ export const pageGuardCopy = (name, status, role = 'winner')=>status === 'archived' ? role === 'original' ? `This page's address now shows the winner of the finished test "${name}". To free it, open the test and choose "Release pages".` : `This page is shown at other addresses because the finished test "${name}" made it the winner. To free it, open the test and choose "Release pages".` : status === 'decided' ? `This page is part of the decided test "${name}". Choose "Make it the content" or "Discard winner" on the test before you delete, rename or unpublish it.` : `This page is part of the running test "${name}". Stop the test before you delete, rename or unpublish it.`;
|
|
70
71
|
export const versionPageUnavailableCopy = (path, status = 'running')=>`${path} isn't published, so visitors assigned to it see an error. Republish it, or ${status === 'decided' ? 'discard the winner' : 'stop the test'}.`;
|
|
71
72
|
export const versionPageUncheckedCopy = (path, status = 'running')=>`Couldn't check whether ${path} is published. Check that it is still published, or ${status === 'decided' ? 'discard the winner' : 'stop the test'}.`;
|
|
73
|
+
export const sameAddressCopy = (label, other, path, collection)=>`${label} has the same address (${path}) as ${other}. Choose a different page.${collection ? ` Give the copy its own address in ${collection}, publish it, then choose it.` : ''}`;
|
|
74
|
+
export const identicalVersionCopy = (version)=>`${version} looks the same as the Original, so the test would compare nothing. Change it before you start.`;
|
|
75
|
+
/** Keep named actions aligned with the actual transition buttons. */ export function placementGuardCopy(page, block, preExisting) {
|
|
76
|
+
const action = (test)=>test.status === 'running' ? `stop ${test.name}` : `choose "Make it the content" or "Discard winner" on ${test.name}`;
|
|
77
|
+
return preExisting ? `This page is in two tests that change it, ${page.name} and ${block.name}. Before you publish, ${action(page)} or ${action(block)}.` : `This page is part of the ${page.status} test ${page.name}, so a block from another test can't be added to it. Finish one of the tests first.`;
|
|
78
|
+
}
|
|
79
|
+
export function interactingTestsCopy(page, state, name, version = false) {
|
|
80
|
+
return `This test uses ${page}, which the ${state} test ${name} also changes. Finish one of them first${version ? `, or remove its block from ${page}` : ''}.`;
|
|
81
|
+
}
|
|
82
|
+
export const goalInSomeVersionsCopy = (name = 'This goal')=>`${name} appears in some versions but not all, so the comparison wouldn't be fair. Add it to every version, or choose another goal.`;
|
|
83
|
+
export function asymmetricGoalsCopy(detail) {
|
|
84
|
+
return (Array.isArray(detail) && detail.length ? detail : [
|
|
85
|
+
detail
|
|
86
|
+
]).map((item)=>{
|
|
87
|
+
const name = item && typeof item === 'object' && 'name' in item ? item.name : undefined;
|
|
88
|
+
return goalInSomeVersionsCopy(typeof name === 'string' && name.trim() ? name.trim() : undefined);
|
|
89
|
+
}).join('\n');
|
|
90
|
+
}
|
|
91
|
+
export const placementUncheckedCopy = (page)=>`${page} couldn't be checked, so the test can't confirm every version shows the same goals. Check that you can open it.`;
|
|
@@ -22,6 +22,7 @@ export declare const RESULTS_COPY: {
|
|
|
22
22
|
};
|
|
23
23
|
readonly qualityOK: "No data quality problems found.";
|
|
24
24
|
readonly previews: "Preview links";
|
|
25
|
+
readonly clickPrimary: "A click shows interest, not the result you want. Add that result, like a sign-up or a gift, as another goal to check that more clicks lead to more of it.";
|
|
25
26
|
readonly releasePages: "Release pages";
|
|
26
27
|
readonly releasePagesBody: "Every address shows its own page again. The result stays recorded.";
|
|
27
28
|
readonly you: "you";
|
|
@@ -22,6 +22,7 @@ export const RESULTS_COPY = {
|
|
|
22
22
|
},
|
|
23
23
|
qualityOK: 'No data quality problems found.',
|
|
24
24
|
previews: 'Preview links',
|
|
25
|
+
clickPrimary: 'A click shows interest, not the result you want. Add that result, like a sign-up or a gift, as another goal to check that more clicks lead to more of it.',
|
|
25
26
|
releasePages: 'Release pages',
|
|
26
27
|
releasePagesBody: 'Every address shows its own page again. The result stays recorded.',
|
|
27
28
|
you: 'you',
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export declare const TEST_PAGE: {
|
|
2
|
+
readonly clickPageGroup: "On this test's page";
|
|
3
|
+
readonly clickGoalsNote: "Goals inside linked documents aren't shown. Goals added in code (data-xp-goal) work but aren't listed here.";
|
|
4
|
+
readonly clickGoalHelp: "A click shows interest, not the result you want.";
|
|
2
5
|
readonly staleEdit: "Someone else changed this test. Reload to see their changes.";
|
|
3
6
|
readonly reload: "Reload";
|
|
4
7
|
readonly loading: "Loading test…";
|
|
@@ -54,6 +57,7 @@ export declare const TEST_PAGE: {
|
|
|
54
57
|
readonly split: "Split evenly";
|
|
55
58
|
readonly remove: "Remove version";
|
|
56
59
|
readonly invalidShare: "Use a whole number from 0 to 100.";
|
|
60
|
+
readonly holdoutPrefix: "Holdout: ";
|
|
57
61
|
readonly allocation: "How many people take part";
|
|
58
62
|
readonly traffic: "How people are split";
|
|
59
63
|
readonly goal: "Goal";
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export const TEST_PAGE = {
|
|
2
|
+
clickPageGroup: "On this test's page",
|
|
3
|
+
clickGoalsNote: "Goals inside linked documents aren't shown. Goals added in code (data-xp-goal) work but aren't listed here.",
|
|
4
|
+
clickGoalHelp: 'A click shows interest, not the result you want.',
|
|
2
5
|
staleEdit: 'Someone else changed this test. Reload to see their changes.',
|
|
3
6
|
reload: 'Reload',
|
|
4
7
|
loading: 'Loading test…',
|
|
@@ -54,6 +57,7 @@ export const TEST_PAGE = {
|
|
|
54
57
|
split: 'Split evenly',
|
|
55
58
|
remove: 'Remove version',
|
|
56
59
|
invalidShare: 'Use a whole number from 0 to 100.',
|
|
60
|
+
holdoutPrefix: 'Holdout: ',
|
|
57
61
|
allocation: 'How many people take part',
|
|
58
62
|
traffic: 'How people are split',
|
|
59
63
|
goal: 'Goal',
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { Button, FieldError, FieldLabel, TextInput, useAuth, useConfig, useField } from '@payloadcms/ui';
|
|
4
|
+
import { useId } from 'react';
|
|
5
|
+
import { useClickGoalPicker } from '../../goals/picker/useClickGoalPicker.js';
|
|
6
|
+
import { CLICK_GOAL_COPY as C } from '../../goals/picker/copy.js';
|
|
7
|
+
export function XpGoalField({ path, field, readOnly }) {
|
|
8
|
+
const { value, setValue, showError } = useField({
|
|
9
|
+
path
|
|
10
|
+
});
|
|
11
|
+
const { permissions } = useAuth();
|
|
12
|
+
const { config } = useConfig();
|
|
13
|
+
const access = permissions?.collections?.['xp-experiments'];
|
|
14
|
+
const locked = Boolean(readOnly || field.admin?.readOnly);
|
|
15
|
+
const picker = useClickGoalPicker(config.routes.api, {
|
|
16
|
+
enabled: access?.update === true,
|
|
17
|
+
onSelect: setValue
|
|
18
|
+
});
|
|
19
|
+
const id = useId(), namePath = `${id}-name`, slugPath = `${id}-slug`;
|
|
20
|
+
const stopEnter = (event)=>{
|
|
21
|
+
if (event.key === 'Enter') {
|
|
22
|
+
event.preventDefault();
|
|
23
|
+
event.stopPropagation();
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
27
|
+
children: [
|
|
28
|
+
/*#__PURE__*/ _jsx(TextInput, {
|
|
29
|
+
path: path,
|
|
30
|
+
label: field.label ?? C.label,
|
|
31
|
+
description: field.admin?.description,
|
|
32
|
+
required: field.required,
|
|
33
|
+
readOnly: locked,
|
|
34
|
+
value: value ?? '',
|
|
35
|
+
showError: showError,
|
|
36
|
+
Error: /*#__PURE__*/ _jsx(FieldError, {
|
|
37
|
+
path: path,
|
|
38
|
+
showError: showError
|
|
39
|
+
}),
|
|
40
|
+
onChange: (event)=>{
|
|
41
|
+
if (!locked) setValue(event.currentTarget.value);
|
|
42
|
+
}
|
|
43
|
+
}),
|
|
44
|
+
picker.canManage && !locked ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
45
|
+
children: [
|
|
46
|
+
/*#__PURE__*/ _jsx("label", {
|
|
47
|
+
htmlFor: `${id}-picker`,
|
|
48
|
+
children: C.choose
|
|
49
|
+
}),
|
|
50
|
+
/*#__PURE__*/ _jsxs("select", {
|
|
51
|
+
id: `${id}-picker`,
|
|
52
|
+
value: picker.goals.some((goal)=>goal.slug === value) ? value : '',
|
|
53
|
+
onChange: (event)=>{
|
|
54
|
+
if (event.currentTarget.value) setValue(event.currentTarget.value);
|
|
55
|
+
},
|
|
56
|
+
children: [
|
|
57
|
+
/*#__PURE__*/ _jsx("option", {
|
|
58
|
+
value: "",
|
|
59
|
+
children: C.choose
|
|
60
|
+
}),
|
|
61
|
+
picker.goals.map((goal)=>/*#__PURE__*/ _jsx("option", {
|
|
62
|
+
value: goal.slug,
|
|
63
|
+
children: goal.name
|
|
64
|
+
}, goal.id))
|
|
65
|
+
]
|
|
66
|
+
}),
|
|
67
|
+
picker.undefinedKey(value ?? '') ? /*#__PURE__*/ _jsx("p", {
|
|
68
|
+
role: "status",
|
|
69
|
+
children: C.undefinedKey
|
|
70
|
+
}) : null,
|
|
71
|
+
!picker.panel.open ? /*#__PURE__*/ _jsx(Button, {
|
|
72
|
+
type: "button",
|
|
73
|
+
onClick: picker.open,
|
|
74
|
+
children: C.newGoal
|
|
75
|
+
}) : /*#__PURE__*/ _jsxs("section", {
|
|
76
|
+
"aria-labelledby": `${id}-title`,
|
|
77
|
+
children: [
|
|
78
|
+
/*#__PURE__*/ _jsx("h3", {
|
|
79
|
+
id: `${id}-title`,
|
|
80
|
+
children: C.title
|
|
81
|
+
}),
|
|
82
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
83
|
+
className: "field-type text",
|
|
84
|
+
children: [
|
|
85
|
+
/*#__PURE__*/ _jsx(FieldLabel, {
|
|
86
|
+
path: namePath,
|
|
87
|
+
label: C.name
|
|
88
|
+
}),
|
|
89
|
+
/*#__PURE__*/ _jsx("input", {
|
|
90
|
+
id: `field-${namePath}`,
|
|
91
|
+
value: picker.panel.name,
|
|
92
|
+
disabled: picker.panel.pending,
|
|
93
|
+
onKeyDown: stopEnter,
|
|
94
|
+
onChange: (event)=>picker.setName(event.currentTarget.value)
|
|
95
|
+
})
|
|
96
|
+
]
|
|
97
|
+
}),
|
|
98
|
+
/*#__PURE__*/ _jsxs("details", {
|
|
99
|
+
open: picker.panel.advanced,
|
|
100
|
+
onToggle: (event)=>picker.setAdvanced(event.currentTarget.open),
|
|
101
|
+
children: [
|
|
102
|
+
/*#__PURE__*/ _jsx("summary", {
|
|
103
|
+
children: C.advanced
|
|
104
|
+
}),
|
|
105
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
106
|
+
className: "field-type text",
|
|
107
|
+
children: [
|
|
108
|
+
/*#__PURE__*/ _jsx(FieldLabel, {
|
|
109
|
+
path: slugPath,
|
|
110
|
+
label: C.slug
|
|
111
|
+
}),
|
|
112
|
+
/*#__PURE__*/ _jsx("input", {
|
|
113
|
+
id: `field-${slugPath}`,
|
|
114
|
+
value: picker.panel.slug,
|
|
115
|
+
disabled: picker.panel.pending,
|
|
116
|
+
onKeyDown: stopEnter,
|
|
117
|
+
"aria-invalid": Boolean(picker.panel.errors.slug) || undefined,
|
|
118
|
+
"aria-describedby": picker.panel.errors.slug ? `${id}-slug-error` : undefined,
|
|
119
|
+
onChange: (event)=>picker.setSlug(event.currentTarget.value)
|
|
120
|
+
}),
|
|
121
|
+
picker.panel.errors.slug ? /*#__PURE__*/ _jsx("p", {
|
|
122
|
+
id: `${id}-slug-error`,
|
|
123
|
+
role: "alert",
|
|
124
|
+
children: picker.panel.errors.slug
|
|
125
|
+
}) : null
|
|
126
|
+
]
|
|
127
|
+
})
|
|
128
|
+
]
|
|
129
|
+
}),
|
|
130
|
+
picker.panel.errors.general ? /*#__PURE__*/ _jsx("p", {
|
|
131
|
+
role: "alert",
|
|
132
|
+
children: picker.panel.errors.general
|
|
133
|
+
}) : null,
|
|
134
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
135
|
+
type: "button",
|
|
136
|
+
disabled: picker.panel.pending || !picker.panel.name.trim(),
|
|
137
|
+
onClick: ()=>void picker.create(),
|
|
138
|
+
children: C.createGoal
|
|
139
|
+
}),
|
|
140
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
141
|
+
type: "button",
|
|
142
|
+
disabled: picker.panel.pending,
|
|
143
|
+
onClick: picker.cancel,
|
|
144
|
+
children: C.cancel
|
|
145
|
+
})
|
|
146
|
+
]
|
|
147
|
+
})
|
|
148
|
+
]
|
|
149
|
+
}) : null
|
|
150
|
+
]
|
|
151
|
+
});
|
|
152
|
+
}
|
|
@@ -5,3 +5,5 @@ export declare function metricSourceOptions(sources: readonly SerializedMetricSo
|
|
|
5
5
|
badge: "count" | "yes/no" | "amount";
|
|
6
6
|
}[];
|
|
7
7
|
export declare function metricSourceHint(source?: SerializedMetricSource): string | null;
|
|
8
|
+
/** Click goal definitions share the serialized click-source option. */
|
|
9
|
+
export declare function sourceFor(sourceId: string | undefined, metricSources: readonly SerializedMetricSource[]): SerializedMetricSource | undefined;
|
|
@@ -9,3 +9,7 @@ export function metricSourceOptions(sources) {
|
|
|
9
9
|
export function metricSourceHint(source) {
|
|
10
10
|
return source?.kind === 'revenue' ? METRICS_COPY.revenueHint : null;
|
|
11
11
|
}
|
|
12
|
+
/** Click goal definitions share the serialized click-source option. */ export function sourceFor(sourceId, metricSources) {
|
|
13
|
+
const id = sourceId?.startsWith('click:') ? 'click:' : sourceId;
|
|
14
|
+
return metricSources.find((source)=>source.id === id);
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PayloadRequest } from 'payload';
|
|
2
|
+
import type { ExperimentsPageCollection } from '../types/contracts.js';
|
|
3
|
+
export declare function serializePageCollections(collections: ExperimentsPageCollection[], req: PayloadRequest): {
|
|
4
|
+
copyUrl: string;
|
|
5
|
+
copyLabel: string;
|
|
6
|
+
copyHint?: string | undefined;
|
|
7
|
+
slug: string;
|
|
8
|
+
label: string;
|
|
9
|
+
contentChecks: boolean;
|
|
10
|
+
}[];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { formatAdminURL } from 'payload/shared';
|
|
2
|
+
import { collectionLabel } from '../collections/labels.js';
|
|
3
|
+
export function serializePageCollections(collections, req) {
|
|
4
|
+
return collections.map((entry)=>{
|
|
5
|
+
const label = collectionLabel(req.payload.config.collections.find((collection)=>collection.slug === entry.slug)?.labels.plural, entry.slug, req);
|
|
6
|
+
return {
|
|
7
|
+
slug: entry.slug,
|
|
8
|
+
label,
|
|
9
|
+
contentChecks: typeof entry.contentOf === 'function',
|
|
10
|
+
...entry.copyHint ? {
|
|
11
|
+
copyHint: entry.copyHint
|
|
12
|
+
} : {},
|
|
13
|
+
copyUrl: entry.copyUrl ?? formatAdminURL({
|
|
14
|
+
adminRoute: req.payload.config.routes.admin,
|
|
15
|
+
path: `/collections/${entry.slug}`
|
|
16
|
+
}),
|
|
17
|
+
copyLabel: entry.copyLabel ?? `Open ${label}`
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
}
|
package/dist/admin/paths.d.ts
CHANGED
|
@@ -8,3 +8,9 @@ export declare const XP_TESTS_NAV_LINK = "@delmaredigital/payload-experiments/ad
|
|
|
8
8
|
export declare const XP_TESTS_NAV_CLIENT = "@delmaredigital/payload-experiments/admin/client#TestsNavLink";
|
|
9
9
|
export declare const XP_TESTS_SURFACE = "@delmaredigital/payload-experiments/admin/client#TestsSurface";
|
|
10
10
|
export declare const XP_TESTS_DASHBOARD_CARDS = "@delmaredigital/payload-experiments/admin/client#TestsDashboardCards";
|
|
11
|
+
export declare const XP_PLACEMENT_STATUS = "@delmaredigital/payload-experiments/admin/client#PlacementStatus";
|
|
12
|
+
export declare const XP_TEST_BLOCK = "@delmaredigital/payload-experiments/admin/client#TestBlockField";
|
|
13
|
+
export declare const XP_BLOCK_STATUS = "@delmaredigital/payload-experiments/admin/client#BlockStatusField";
|
|
14
|
+
export declare const XP_BLOCK_ROW_LABEL = "@delmaredigital/payload-experiments/admin/client#BlockSlotRowLabel";
|
|
15
|
+
export declare const XP_COPY_ORIGINAL = "@delmaredigital/payload-experiments/admin/client#CopyOriginalField";
|
|
16
|
+
export declare const XP_GOAL_FIELD = "@delmaredigital/payload-experiments/admin/client#XpGoalField";
|
package/dist/admin/paths.js
CHANGED
|
@@ -8,3 +8,9 @@ export const XP_TESTS_NAV_LINK = '@delmaredigital/payload-experiments/admin/rsc#
|
|
|
8
8
|
export const XP_TESTS_NAV_CLIENT = '@delmaredigital/payload-experiments/admin/client#TestsNavLink';
|
|
9
9
|
export const XP_TESTS_SURFACE = '@delmaredigital/payload-experiments/admin/client#TestsSurface';
|
|
10
10
|
export const XP_TESTS_DASHBOARD_CARDS = '@delmaredigital/payload-experiments/admin/client#TestsDashboardCards';
|
|
11
|
+
export const XP_PLACEMENT_STATUS = '@delmaredigital/payload-experiments/admin/client#PlacementStatus';
|
|
12
|
+
export const XP_TEST_BLOCK = '@delmaredigital/payload-experiments/admin/client#TestBlockField';
|
|
13
|
+
export const XP_BLOCK_STATUS = '@delmaredigital/payload-experiments/admin/client#BlockStatusField';
|
|
14
|
+
export const XP_BLOCK_ROW_LABEL = '@delmaredigital/payload-experiments/admin/client#BlockSlotRowLabel';
|
|
15
|
+
export const XP_COPY_ORIGINAL = '@delmaredigital/payload-experiments/admin/client#CopyOriginalField';
|
|
16
|
+
export const XP_GOAL_FIELD = '@delmaredigital/payload-experiments/admin/client#XpGoalField';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function pageStatusCopy(test) {
|
|
2
|
+
if (test.pagesReleased) return null;
|
|
3
|
+
const winner = `${test.winnerLabel ?? 'the winner'}${test.winnerTitle ? ` (${test.winnerTitle})` : ''}`;
|
|
4
|
+
switch(test.status){
|
|
5
|
+
case 'draft':
|
|
6
|
+
return `This page is ${test.armLabel} in the draft test ${test.name}.`;
|
|
7
|
+
case 'stopped':
|
|
8
|
+
{
|
|
9
|
+
const visitors = test.role === 'original' ? 'Visitors see this page.' : !test.originalPath ? 'Visitors see the Original.' : `Visitors to ${test.originalPath === '/' ? 'the homepage (/)' : test.originalPath} see the Original.`;
|
|
10
|
+
return `This page is ${test.armLabel} in the stopped test ${test.name}. ${visitors}`;
|
|
11
|
+
}
|
|
12
|
+
case 'running':
|
|
13
|
+
return `This page is the ${test.armLabel} of a running test: ${test.name}.`;
|
|
14
|
+
case 'decided':
|
|
15
|
+
return `This page is ${test.armLabel} of a decided test; ${test.rollout ? `most visitors see ${winner}; a holdout still sees the Original` : `visitors see ${winner}`}.`;
|
|
16
|
+
case 'archived':
|
|
17
|
+
return test.winner ? `This page is also shown at the other versions' addresses because test ${test.name} made it the winner. To free it, open the test and choose "Release pages".` : test.role === 'original' ? `This page's address now shows the winner of test ${test.name}. To free it, open the test and choose "Release pages".` : `This page's address now shows ${winner}. To show this page again, open the test and choose "Release pages".`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DocId } from '../../types/contracts.js';
|
|
2
|
+
import type { PreflightResult } from '../../types/endpoints.js';
|
|
3
|
+
export { placementDetailKey, placementDetail, fallbackPlacementLabel } from './placementLabels.model.js';
|
|
4
|
+
export type { PlacementLabel } from './placementLabels.model.js';
|
|
5
|
+
import type { PlacementLabel } from './placementLabels.model.js';
|
|
6
|
+
export declare function resolvedPlacementLabel(value: unknown, match: {
|
|
7
|
+
id?: DocId | null;
|
|
8
|
+
title?: string;
|
|
9
|
+
editorUrl?: string;
|
|
10
|
+
} | undefined, adminRoute: string): PlacementLabel;
|
|
11
|
+
export declare function preflightPlacementLabel(value: unknown, preflight: PreflightResult, adminRoute: string): PlacementLabel;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { formatAdminURL } from 'payload/shared';
|
|
2
|
+
import { placementDetail } from './placementLabels.model.js';
|
|
3
|
+
export { placementDetailKey, placementDetail, fallbackPlacementLabel } from './placementLabels.model.js';
|
|
4
|
+
export function resolvedPlacementLabel(value, match, adminRoute) {
|
|
5
|
+
const detail = placementDetail(value);
|
|
6
|
+
const id = match?.id ?? detail.id;
|
|
7
|
+
return {
|
|
8
|
+
title: match?.title?.trim() || detail.path || 'This page',
|
|
9
|
+
...id != null && detail.collection ? {
|
|
10
|
+
href: match?.editorUrl || formatAdminURL({
|
|
11
|
+
adminRoute,
|
|
12
|
+
path: `/collections/${encodeURIComponent(detail.collection)}/${encodeURIComponent(String(id))}`
|
|
13
|
+
})
|
|
14
|
+
} : {}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function preflightPlacementLabel(value, preflight, adminRoute) {
|
|
18
|
+
const detail = placementDetail(value);
|
|
19
|
+
const match = detail.collection ? detail.id != null ? preflight.placements.find((item)=>item.collection === detail.collection && String(item.id) === String(detail.id)) : typeof detail.path === 'string' ? preflight.pagePlacements?.find((item)=>item.collection === detail.collection && item.path === detail.path) : undefined : undefined;
|
|
20
|
+
return resolvedPlacementLabel(value, match, adminRoute);
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DocId } from '../../types/contracts.js';
|
|
2
|
+
export type PlacementDetail = {
|
|
3
|
+
collection?: string;
|
|
4
|
+
id?: DocId;
|
|
5
|
+
path?: string;
|
|
6
|
+
};
|
|
7
|
+
export type PlacementLabel = {
|
|
8
|
+
title: string;
|
|
9
|
+
href?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare const placementDetail: (detail: unknown) => PlacementDetail;
|
|
12
|
+
export declare function placementDetailKey(value: unknown): string;
|
|
13
|
+
export declare const fallbackPlacementLabel: (value: unknown) => PlacementLabel;
|