@delmaredigital/payload-experiments 0.3.0-rc.1 → 0.3.0-rc.4
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 +74 -16
- package/dist/admin/PreviewLinks.js +45 -24
- package/dist/admin/TestsNavLink.d.ts +3 -1
- package/dist/admin/TestsNavLink.js +2 -2
- package/dist/admin/armSelect/ArmSelectField.js +14 -22
- package/dist/admin/arms/arms.model.d.ts +1 -21
- package/dist/admin/arms/arms.model.js +1 -153
- package/dist/admin/copy/arms.d.ts +1 -6
- package/dist/admin/copy/arms.js +1 -16
- package/dist/admin/copy/readiness.d.ts +4 -1
- package/dist/admin/copy/readiness.js +3 -1
- package/dist/admin/copy/results.d.ts +2 -0
- package/dist/admin/copy/results.js +3 -1
- package/dist/admin/copy/review.d.ts +1 -1
- package/dist/admin/copy/review.js +1 -1
- package/dist/admin/copy/surface.d.ts +0 -1
- package/dist/admin/copy/surface.js +0 -1
- package/dist/admin/paths.d.ts +2 -1
- package/dist/admin/paths.js +2 -1
- package/dist/admin/previewLinks.model.d.ts +2 -0
- package/dist/admin/previewLinks.model.js +3 -0
- package/dist/admin/results/legacy.d.ts +16 -0
- package/dist/admin/results/legacy.js +27 -0
- package/dist/admin/results/results.model.d.ts +6 -6
- package/dist/admin/results/results.model.js +14 -5
- package/dist/admin/results/snapshot.d.ts +14 -0
- package/dist/admin/results/snapshot.js +3 -0
- package/dist/admin/surface/TestsHome.js +6 -9
- package/dist/admin/surface/goals/data.js +16 -16
- package/dist/admin/surface/home.model.d.ts +1 -0
- package/dist/admin/surface/newTest/NewTest.js +4 -4
- package/dist/admin/surface/readiness/ActionDialogs.js +4 -5
- package/dist/admin/surface/readiness/readiness.model.js +8 -1
- package/dist/admin/surface/results/ResultsBody.js +2 -1
- package/dist/admin/surface/results/recommendation.model.d.ts +3 -2
- package/dist/admin/surface/results/recommendation.model.js +10 -3
- package/dist/admin/surface/surface.css +0 -1
- package/dist/admin/surface/test/GoalSection.js +7 -15
- package/dist/admin/surface/test/testPage.model.d.ts +2 -3
- package/dist/admin/surface/test/testPage.model.js +1 -21
- package/dist/admin/surface/useTestDocument.js +2 -1
- package/dist/admin/useLayerUsage.js +14 -23
- package/dist/admin/views/TestsNavLinkServer.d.ts +2 -0
- package/dist/admin/views/TestsNavLinkServer.js +43 -0
- package/dist/arms/copy.d.ts +6 -0
- package/dist/arms/copy.js +16 -0
- package/dist/arms/model.d.ts +23 -0
- package/dist/arms/model.js +173 -0
- package/dist/db/appends.d.ts +6 -2
- package/dist/db/appends.js +10 -4
- package/dist/db/locks.d.ts +6 -0
- package/dist/db/locks.js +13 -1
- package/dist/db/pageOccupancy.d.ts +12 -0
- package/dist/db/pageOccupancy.js +45 -0
- package/dist/db/snapshots.js +4 -3
- package/dist/exports/adminRsc.d.ts +1 -0
- package/dist/exports/adminRsc.js +1 -0
- package/dist/exports/index.d.ts +1 -1
- package/dist/exports/puck.d.ts +2 -1
- package/dist/exports/puck.js +1 -1
- package/dist/exports/puckEditor.d.ts +3 -1
- package/dist/exports/puckEditor.js +2 -1
- package/dist/exports/rsc.d.ts +1 -0
- package/dist/hooks/pageGuard.js +21 -3
- package/dist/lib/fetchAllDocs.d.ts +16 -0
- package/dist/lib/fetchAllDocs.js +56 -0
- package/dist/options.js +2 -9
- package/dist/plugin.js +4 -0
- package/dist/puck/ExperimentPicker.js +47 -16
- package/dist/puck/ExperimentSlot.d.ts +51 -1
- package/dist/puck/ExperimentSlot.js +23 -12
- package/dist/puck/copy.d.ts +5 -4
- package/dist/puck/copy.js +5 -4
- package/dist/puck/editor/CreateExperimentDrawer.js +46 -56
- package/dist/puck/editor/ExperimentSlotEditor.d.ts +52 -1
- package/dist/puck/editor/ExperimentSlotEditor.js +292 -137
- package/dist/puck/editor/ResultsReadout.d.ts +6 -0
- package/dist/puck/editor/ResultsReadout.js +99 -0
- package/dist/puck/editor/VersionBuilder.d.ts +34 -0
- package/dist/puck/editor/VersionBuilder.js +317 -0
- package/dist/puck/editor/armWrites.d.ts +7 -0
- package/dist/puck/editor/armWrites.js +71 -0
- package/dist/puck/editor/armsCache.d.ts +14 -0
- package/dist/puck/editor/armsCache.js +78 -0
- package/dist/puck/editor/copy.d.ts +33 -1
- package/dist/puck/editor/copy.js +45 -8
- package/dist/puck/editor/createTest.d.ts +1 -1
- package/dist/puck/editor/createTest.js +25 -14
- package/dist/puck/editor/editor.chrome.css +47 -161
- package/dist/puck/editor/editor.css +47 -161
- package/dist/puck/editor/editor.model.d.ts +4 -1
- package/dist/puck/editor/editor.model.js +10 -7
- package/dist/puck/editor/experimentOutlinePlugin.d.ts +3 -0
- package/dist/puck/editor/experimentOutlinePlugin.js +89 -0
- package/dist/puck/experimentSlotField.d.ts +2 -0
- package/dist/puck/experimentSlotField.js +11 -3
- package/dist/puck/hostContext.d.ts +10 -0
- package/dist/puck/hostContext.js +12 -0
- package/dist/puck/routes.d.ts +12 -0
- package/dist/puck/routes.js +11 -0
- package/dist/puck/slotConfig.d.ts +1 -1
- package/dist/puck/slotConfig.js +2 -2
- package/dist/sanitizeReadinessDetail.js +10 -1
- package/dist/server/metadata.js +9 -2
- package/dist/server/normaliseContentRelationships.d.ts +7 -0
- package/dist/server/normaliseContentRelationships.js +62 -0
- package/dist/server/recordContentChange.d.ts +1 -1
- package/dist/server/recordContentChange.js +17 -8
- package/dist/server/runResults.js +36 -4
- package/dist/transitions/checkStart.d.ts +5 -1
- package/dist/transitions/checkStart.js +10 -0
- package/dist/transitions/decide.js +16 -1
- package/dist/transitions/placements.d.ts +2 -6
- package/dist/transitions/placements.js +8 -1
- package/dist/transitions/preflightData.d.ts +8 -0
- package/dist/transitions/preflightData.js +116 -36
- package/dist/transitions/start.js +33 -3
- package/dist/types/contracts.d.ts +19 -13
- package/dist/types/endpoints.d.ts +1 -1
- package/dist/ui/Tabs.d.ts +4 -2
- package/dist/ui/Tabs.js +33 -26
- package/dist/ui/accent.d.ts +22 -3
- package/dist/ui/accent.js +74 -16
- package/package.json +5 -2
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** A successful REST response did not contain a readable document list. */ export class DocsResponseError extends Error {
|
|
2
|
+
}
|
|
3
|
+
/** Read every Payload REST page with the caller's credentials and cancellation. Transport,
|
|
4
|
+
* invalid successful responses and aborts throw; HTTP refusals retain their status/body. Keeps the first document per id; refuses
|
|
5
|
+
* incomplete lists after 1000 pages with page-limit-exceeded. */ export async function fetchAllDocs(url, options = {}) {
|
|
6
|
+
const [path, query] = url.split('?');
|
|
7
|
+
const params = new URLSearchParams(query);
|
|
8
|
+
params.set('limit', '100');
|
|
9
|
+
const docs = [];
|
|
10
|
+
const seen = new Set();
|
|
11
|
+
for(let page = 1; page <= 1000; page++){
|
|
12
|
+
options.signal?.throwIfAborted();
|
|
13
|
+
params.set('page', String(page));
|
|
14
|
+
const response = await fetch(`${path}?${params}`, options);
|
|
15
|
+
const body = await response.json().catch(()=>{
|
|
16
|
+
if (response.ok) throw new DocsResponseError();
|
|
17
|
+
return undefined;
|
|
18
|
+
});
|
|
19
|
+
options.signal?.throwIfAborted();
|
|
20
|
+
if (!response.ok) return {
|
|
21
|
+
ok: false,
|
|
22
|
+
status: response.status,
|
|
23
|
+
body
|
|
24
|
+
};
|
|
25
|
+
const data = body;
|
|
26
|
+
if (!Array.isArray(data?.docs)) throw new DocsResponseError();
|
|
27
|
+
for (const doc of data.docs){
|
|
28
|
+
const id = doc && typeof doc === 'object' && 'id' in doc ? doc.id : undefined;
|
|
29
|
+
if (typeof id === 'string' || typeof id === 'number') {
|
|
30
|
+
if (seen.has(id)) continue;
|
|
31
|
+
seen.add(id);
|
|
32
|
+
}
|
|
33
|
+
docs.push(doc);
|
|
34
|
+
}
|
|
35
|
+
if (data.docs.length === 0) return {
|
|
36
|
+
ok: true,
|
|
37
|
+
docs
|
|
38
|
+
};
|
|
39
|
+
if (typeof data.totalPages === 'number' && page >= data.totalPages) return {
|
|
40
|
+
ok: true,
|
|
41
|
+
docs
|
|
42
|
+
};
|
|
43
|
+
if (data.hasNextPage === false || data.hasNextPage !== true && !(typeof data.totalPages === 'number' && page < data.totalPages)) {
|
|
44
|
+
return {
|
|
45
|
+
ok: true,
|
|
46
|
+
docs
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
ok: false,
|
|
52
|
+
status: 0,
|
|
53
|
+
body: undefined,
|
|
54
|
+
reason: 'page-limit-exceeded'
|
|
55
|
+
};
|
|
56
|
+
}
|
package/dist/options.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { validateAccent } from './ui/accent.js';
|
|
2
2
|
import { DEFAULT_MAX_BODY_BYTES } from './constants.js';
|
|
3
3
|
const normalisedCollections = new WeakMap();
|
|
4
4
|
/** Resolve once per registration list; every consumer shares the same field defaults. */ export function puckCollections(options) {
|
|
@@ -68,14 +68,7 @@ export function resolveOptions(input) {
|
|
|
68
68
|
if (input.theme !== undefined) {
|
|
69
69
|
if (!input.theme || typeof input.theme !== 'object' || Array.isArray(input.theme)) throw new Error('Experiments theme must be an object');
|
|
70
70
|
for (const key of Object.keys(input.theme))if (key !== 'accent') throw new Error(`Unknown experiments theme option: ${key}`);
|
|
71
|
-
|
|
72
|
-
if (accent !== undefined && accent !== '') {
|
|
73
|
-
if (typeof accent !== 'string' || !/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(accent)) throw new Error('Experiments theme.accent must be a CSS hex colour (#rgb or #rrggbb)');
|
|
74
|
-
for (const [mode, set] of Object.entries(deriveAccent(accent))){
|
|
75
|
-
const ratio = contrast(set.accent, set.fg);
|
|
76
|
-
if (ratio < 4.5) throw new Error(`Experiments theme.accent ${accent}: ${mode} foreground contrast ${ratio.toFixed(2)}:1 is below 4.5:1`);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
71
|
+
validateAccent(input.theme.accent);
|
|
79
72
|
}
|
|
80
73
|
const ids = new Set();
|
|
81
74
|
for (const point of input.flagPoints ?? []){
|
package/dist/plugin.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect, useState } from 'react';
|
|
3
|
+
import { useEffect, useId, useState } from 'react';
|
|
4
|
+
import { fetchAllDocs } from '../lib/fetchAllDocs.js';
|
|
5
|
+
import { usePuckRoutes } from './hostContext.js';
|
|
4
6
|
import { pickerCopy } from './copy.js';
|
|
5
7
|
function isExperimentOption(value) {
|
|
6
8
|
if (!value || typeof value !== 'object') return false;
|
|
@@ -8,14 +10,17 @@ function isExperimentOption(value) {
|
|
|
8
10
|
return (typeof doc.id === 'string' || typeof doc.id === 'number') && typeof doc.slug === 'string' && typeof doc.name === 'string' && typeof doc.status === 'string' && Object.hasOwn(pickerCopy.statuses, doc.status);
|
|
9
11
|
}
|
|
10
12
|
export function ExperimentPicker({ value, onChange }) {
|
|
13
|
+
const { api } = usePuckRoutes();
|
|
14
|
+
const id = useId();
|
|
11
15
|
const [experiments, setExperiments] = useState([]);
|
|
16
|
+
const [search, setSearch] = useState('');
|
|
12
17
|
const [state, setState] = useState('loading');
|
|
13
18
|
useEffect(()=>{
|
|
14
19
|
let active = true;
|
|
15
20
|
const controller = new AbortController();
|
|
16
21
|
async function load() {
|
|
17
22
|
try {
|
|
18
|
-
const response = await
|
|
23
|
+
const response = await fetchAllDocs(`${api}/xp-experiments?where[kind][equals]=block&depth=0&sort=id`, {
|
|
19
24
|
credentials: 'include',
|
|
20
25
|
signal: controller.signal
|
|
21
26
|
});
|
|
@@ -24,13 +29,7 @@ export function ExperimentPicker({ value, onChange }) {
|
|
|
24
29
|
setState(response.status === 403 ? 'forbidden' : 'error');
|
|
25
30
|
return;
|
|
26
31
|
}
|
|
27
|
-
|
|
28
|
-
if (!active) return;
|
|
29
|
-
if (!data || typeof data !== 'object' || !('docs' in data) || !Array.isArray(data.docs)) {
|
|
30
|
-
setState('error');
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
setExperiments(data.docs.filter(isExperimentOption));
|
|
32
|
+
setExperiments(response.docs.filter(isExperimentOption).sort((a, b)=>(Date.parse(b.updatedAt ?? '') || 0) - (Date.parse(a.updatedAt ?? '') || 0)));
|
|
34
33
|
setState('ready');
|
|
35
34
|
} catch {
|
|
36
35
|
if (active) setState('error');
|
|
@@ -41,12 +40,38 @@ export function ExperimentPicker({ value, onChange }) {
|
|
|
41
40
|
active = false;
|
|
42
41
|
controller.abort();
|
|
43
42
|
};
|
|
44
|
-
}, [
|
|
43
|
+
}, [
|
|
44
|
+
api
|
|
45
|
+
]);
|
|
45
46
|
const selected = value ? String(value.id) : '';
|
|
47
|
+
const query = search.trim().toLocaleLowerCase('en-US');
|
|
48
|
+
const visible = experiments.filter((doc)=>String(doc.id) === selected || doc.name.toLocaleLowerCase('en-US').includes(query) || doc.slug.toLocaleLowerCase('en-US').includes(query));
|
|
46
49
|
return /*#__PURE__*/ _jsxs("div", {
|
|
50
|
+
className: "xp-ui-field",
|
|
47
51
|
children: [
|
|
52
|
+
experiments.length > 8 ? /*#__PURE__*/ _jsxs("div", {
|
|
53
|
+
className: "xp-ui-field",
|
|
54
|
+
children: [
|
|
55
|
+
/*#__PURE__*/ _jsx("label", {
|
|
56
|
+
htmlFor: `${id}-search`,
|
|
57
|
+
children: pickerCopy.search
|
|
58
|
+
}),
|
|
59
|
+
/*#__PURE__*/ _jsx("input", {
|
|
60
|
+
id: `${id}-search`,
|
|
61
|
+
type: "search",
|
|
62
|
+
className: "xp-ui-input",
|
|
63
|
+
value: search,
|
|
64
|
+
onChange: (event)=>setSearch(event.currentTarget.value)
|
|
65
|
+
})
|
|
66
|
+
]
|
|
67
|
+
}) : null,
|
|
68
|
+
/*#__PURE__*/ _jsx("label", {
|
|
69
|
+
htmlFor: id,
|
|
70
|
+
children: pickerCopy.label
|
|
71
|
+
}),
|
|
48
72
|
/*#__PURE__*/ _jsxs("select", {
|
|
49
|
-
|
|
73
|
+
id: id,
|
|
74
|
+
className: "xp-ui-input xp-ui-select",
|
|
50
75
|
value: selected,
|
|
51
76
|
disabled: state === 'loading',
|
|
52
77
|
onChange: (event)=>{
|
|
@@ -65,7 +90,7 @@ export function ExperimentPicker({ value, onChange }) {
|
|
|
65
90
|
value: selected,
|
|
66
91
|
children: value.slug
|
|
67
92
|
}) : null,
|
|
68
|
-
|
|
93
|
+
visible.map((doc)=>/*#__PURE__*/ _jsxs("option", {
|
|
69
94
|
value: String(doc.id),
|
|
70
95
|
children: [
|
|
71
96
|
doc.name,
|
|
@@ -75,13 +100,19 @@ export function ExperimentPicker({ value, onChange }) {
|
|
|
75
100
|
}, doc.id))
|
|
76
101
|
]
|
|
77
102
|
}),
|
|
78
|
-
state === 'loading' ? /*#__PURE__*/ _jsx("
|
|
103
|
+
state === 'loading' ? /*#__PURE__*/ _jsx("div", {
|
|
104
|
+
className: "xp-ui-banner",
|
|
79
105
|
role: "status",
|
|
80
|
-
children:
|
|
106
|
+
children: /*#__PURE__*/ _jsx("p", {
|
|
107
|
+
children: pickerCopy.loading
|
|
108
|
+
})
|
|
81
109
|
}) : null,
|
|
82
|
-
state === 'error' || state === 'forbidden' ? /*#__PURE__*/ _jsx("
|
|
110
|
+
state === 'error' || state === 'forbidden' ? /*#__PURE__*/ _jsx("div", {
|
|
111
|
+
className: "xp-ui-banner xp-ui-banner--error",
|
|
83
112
|
role: "alert",
|
|
84
|
-
children:
|
|
113
|
+
children: /*#__PURE__*/ _jsx("p", {
|
|
114
|
+
children: pickerCopy[state]
|
|
115
|
+
})
|
|
85
116
|
}) : null
|
|
86
117
|
]
|
|
87
118
|
});
|
|
@@ -1,3 +1,53 @@
|
|
|
1
1
|
import type { ComponentConfig } from '@puckeditor/core';
|
|
2
2
|
import type { ExperimentSlotProps } from '../types/puck.js';
|
|
3
|
-
|
|
3
|
+
import { type PuckRoutes } from './routes.js';
|
|
4
|
+
export declare function createExperimentSlot({ routes: inputRoutes }?: {
|
|
5
|
+
routes?: PuckRoutes;
|
|
6
|
+
}): ComponentConfig<ExperimentSlotProps>;
|
|
7
|
+
export declare const ExperimentSlot: {
|
|
8
|
+
render: import("@puckeditor/core").PuckComponent<ExperimentSlotProps>;
|
|
9
|
+
label?: string;
|
|
10
|
+
defaultProps?: ExperimentSlotProps | undefined;
|
|
11
|
+
fields?: import("@puckeditor/core").Fields<ExperimentSlotProps, {}> | undefined;
|
|
12
|
+
renderFields?: ((props: {
|
|
13
|
+
fields: Partial<Record<keyof ExperimentSlotProps, import("react").ReactNode>>;
|
|
14
|
+
}) => import("react").ReactElement) | undefined;
|
|
15
|
+
permissions?: Partial<import("@puckeditor/core").Permissions>;
|
|
16
|
+
inline?: boolean;
|
|
17
|
+
resolveFields?: ((data: Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type">, params: {
|
|
18
|
+
changed: Partial<Record<keyof ExperimentSlotProps, boolean> & {
|
|
19
|
+
id: string;
|
|
20
|
+
}>;
|
|
21
|
+
fields: import("@puckeditor/core").Fields<ExperimentSlotProps, {}>;
|
|
22
|
+
lastFields: import("@puckeditor/core").Fields<ExperimentSlotProps, {}>;
|
|
23
|
+
lastData: Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type"> | null;
|
|
24
|
+
metadata: import("@puckeditor/core").ComponentMetadata;
|
|
25
|
+
appState: import("@puckeditor/core").AppState;
|
|
26
|
+
parent: import("@puckeditor/core").ComponentData | null;
|
|
27
|
+
}) => import("@puckeditor/core").Fields<ExperimentSlotProps, {}> | Promise<import("@puckeditor/core").Fields<ExperimentSlotProps, {}>>) | undefined;
|
|
28
|
+
resolveData?: ((data: Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type">, params: {
|
|
29
|
+
changed: Partial<Record<keyof ExperimentSlotProps, boolean> & {
|
|
30
|
+
id: string;
|
|
31
|
+
}>;
|
|
32
|
+
lastData: Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type"> | null;
|
|
33
|
+
metadata: import("@puckeditor/core").ComponentMetadata;
|
|
34
|
+
trigger: import("@puckeditor/core").ResolveDataTrigger;
|
|
35
|
+
parent: import("@puckeditor/core").ComponentData | null;
|
|
36
|
+
root: import("@puckeditor/core").RootData;
|
|
37
|
+
}) => (Omit<Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type">, "props"> & {
|
|
38
|
+
props?: Partial<ExperimentSlotProps> | undefined;
|
|
39
|
+
}) | Promise<Omit<Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type">, "props"> & {
|
|
40
|
+
props?: Partial<ExperimentSlotProps> | undefined;
|
|
41
|
+
}>) | undefined;
|
|
42
|
+
resolvePermissions?: ((data: Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type">, params: {
|
|
43
|
+
changed: Partial<Record<keyof ExperimentSlotProps, boolean> & {
|
|
44
|
+
id: string;
|
|
45
|
+
}>;
|
|
46
|
+
lastPermissions: Partial<import("@puckeditor/core").Permissions>;
|
|
47
|
+
permissions: Partial<import("@puckeditor/core").Permissions>;
|
|
48
|
+
appState: import("@puckeditor/core").AppState;
|
|
49
|
+
lastData: Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type"> | null;
|
|
50
|
+
parent: import("@puckeditor/core").ComponentData | null;
|
|
51
|
+
}) => Promise<Partial<import("@puckeditor/core").Permissions>> | Partial<import("@puckeditor/core").Permissions>) | undefined;
|
|
52
|
+
metadata?: import("@puckeditor/core").ComponentMetadata;
|
|
53
|
+
} & import("@puckeditor/core").ComponentConfigExtensions;
|
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { ViewportExposure } from '../client/ViewportExposure.js';
|
|
3
3
|
import { experimentSlotDefaultProps, experimentSlotFields, experimentSlotLabel } from './slotConfig.js';
|
|
4
|
+
import { createExperimentSlotField } from './experimentSlotField.js';
|
|
5
|
+
import { resolvePuckRoutes } from './routes.js';
|
|
4
6
|
import { slotToRender } from './slot.model.js';
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
export function createExperimentSlot({ routes: inputRoutes } = {}) {
|
|
8
|
+
const routes = resolvePuckRoutes(inputRoutes);
|
|
9
|
+
return {
|
|
10
|
+
label: experimentSlotLabel,
|
|
11
|
+
fields: {
|
|
12
|
+
...experimentSlotFields,
|
|
13
|
+
experiment: createExperimentSlotField({
|
|
14
|
+
routes
|
|
15
|
+
})
|
|
16
|
+
},
|
|
17
|
+
defaultProps: experimentSlotDefaultProps,
|
|
18
|
+
render: (props)=>{
|
|
19
|
+
const Slot = props[slotToRender(props)];
|
|
20
|
+
return /*#__PURE__*/ _jsx(ViewportExposure, {
|
|
21
|
+
expose: props.xpExpose,
|
|
22
|
+
children: /*#__PURE__*/ _jsx(Slot, {})
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export const ExperimentSlot = createExperimentSlot();
|
package/dist/puck/copy.d.ts
CHANGED
|
@@ -5,10 +5,11 @@ export declare const slotLabels: {
|
|
|
5
5
|
readonly variantC: "Variant C";
|
|
6
6
|
};
|
|
7
7
|
export declare const pickerCopy: {
|
|
8
|
-
readonly label: "
|
|
9
|
-
readonly none: "No
|
|
10
|
-
readonly
|
|
11
|
-
readonly
|
|
8
|
+
readonly label: "Test";
|
|
9
|
+
readonly none: "No test";
|
|
10
|
+
readonly search: "Search tests";
|
|
11
|
+
readonly loading: "Loading tests…";
|
|
12
|
+
readonly error: "Couldn't load tests.";
|
|
12
13
|
readonly forbidden: "You can't see tests. Ask an admin.";
|
|
13
14
|
readonly statuses: {
|
|
14
15
|
readonly draft: "Draft";
|
package/dist/puck/copy.js
CHANGED
|
@@ -6,10 +6,11 @@ export const slotLabels = {
|
|
|
6
6
|
variantC: ARM_LABELS.variantC
|
|
7
7
|
};
|
|
8
8
|
export const pickerCopy = {
|
|
9
|
-
label: '
|
|
10
|
-
none: 'No
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
label: 'Test',
|
|
10
|
+
none: 'No test',
|
|
11
|
+
search: 'Search tests',
|
|
12
|
+
loading: 'Loading tests…',
|
|
13
|
+
error: "Couldn't load tests.",
|
|
13
14
|
forbidden: "You can't see tests. Ask an admin.",
|
|
14
15
|
statuses: {
|
|
15
16
|
draft: 'Draft',
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useId, useRef, useState } from 'react';
|
|
4
|
+
import { Dialog } from '../../ui/Dialog.js';
|
|
5
|
+
import { TextInput } from '../../ui/TextInput.js';
|
|
6
|
+
import { Button } from '../../ui/Button.js';
|
|
7
|
+
import { Banner } from '../../ui/Banner.js';
|
|
8
|
+
import { usePuckRoutes } from '../hostContext.js';
|
|
4
9
|
import { CreateRefused, createTest } from './createTest.js';
|
|
5
10
|
import { editorCopy } from './copy.js';
|
|
6
11
|
import './editor.css';
|
|
7
12
|
export function CreateExperimentDrawer({ onCreate, onClose, initialName = '' }) {
|
|
8
|
-
const
|
|
13
|
+
const { api } = usePuckRoutes();
|
|
9
14
|
const nameId = useId();
|
|
10
15
|
const [name, setName] = useState(initialName);
|
|
11
16
|
const inFlight = useRef(false);
|
|
@@ -17,7 +22,7 @@ export function CreateExperimentDrawer({ onCreate, onClose, initialName = '' })
|
|
|
17
22
|
setPending(true);
|
|
18
23
|
setError('');
|
|
19
24
|
try {
|
|
20
|
-
const experiment = await createTest(
|
|
25
|
+
const experiment = await createTest(api, {
|
|
21
26
|
name,
|
|
22
27
|
kind: 'block',
|
|
23
28
|
unitType: 'visitor'
|
|
@@ -31,59 +36,44 @@ export function CreateExperimentDrawer({ onCreate, onClose, initialName = '' })
|
|
|
31
36
|
setPending(false);
|
|
32
37
|
}
|
|
33
38
|
}
|
|
34
|
-
return /*#__PURE__*/
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
onClick: ()=>{
|
|
74
|
-
void submitNew();
|
|
75
|
-
},
|
|
76
|
-
children: pending ? editorCopy.creating : editorCopy.createLabel
|
|
77
|
-
}),
|
|
78
|
-
/*#__PURE__*/ _jsx("button", {
|
|
79
|
-
className: "xp-slot-button",
|
|
80
|
-
type: "button",
|
|
81
|
-
disabled: pending,
|
|
82
|
-
onClick: onClose,
|
|
83
|
-
children: editorCopy.cancel
|
|
84
|
-
})
|
|
85
|
-
]
|
|
86
|
-
})
|
|
87
|
-
]
|
|
39
|
+
return /*#__PURE__*/ _jsx(Dialog, {
|
|
40
|
+
open: true,
|
|
41
|
+
title: editorCopy.createLabel,
|
|
42
|
+
onClose: onClose,
|
|
43
|
+
dismissible: !pending,
|
|
44
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
45
|
+
className: "xp-slot-drawer",
|
|
46
|
+
children: [
|
|
47
|
+
/*#__PURE__*/ _jsx(TextInput, {
|
|
48
|
+
id: nameId,
|
|
49
|
+
label: editorCopy.name,
|
|
50
|
+
value: name,
|
|
51
|
+
disabled: pending,
|
|
52
|
+
onChange: (event)=>setName(event.currentTarget.value)
|
|
53
|
+
}),
|
|
54
|
+
error ? /*#__PURE__*/ _jsx(Banner, {
|
|
55
|
+
tone: "error",
|
|
56
|
+
children: error
|
|
57
|
+
}) : null,
|
|
58
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
59
|
+
className: "xp-ui-button-group",
|
|
60
|
+
children: [
|
|
61
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
62
|
+
variant: "primary",
|
|
63
|
+
disabled: pending || !name.trim(),
|
|
64
|
+
onClick: ()=>{
|
|
65
|
+
void submitNew();
|
|
66
|
+
},
|
|
67
|
+
children: pending ? editorCopy.creating : editorCopy.createLabel
|
|
68
|
+
}),
|
|
69
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
70
|
+
disabled: pending,
|
|
71
|
+
onClick: onClose,
|
|
72
|
+
children: editorCopy.cancel
|
|
73
|
+
})
|
|
74
|
+
]
|
|
75
|
+
})
|
|
76
|
+
]
|
|
77
|
+
})
|
|
88
78
|
});
|
|
89
79
|
}
|
|
@@ -1,4 +1,55 @@
|
|
|
1
1
|
import { type ComponentConfig } from '@puckeditor/core';
|
|
2
2
|
import type { ExperimentSlotProps } from '../../types/puck.js';
|
|
3
|
+
import { type PuckRoutes } from '../routes.js';
|
|
3
4
|
import './editor.css';
|
|
4
|
-
export declare
|
|
5
|
+
export declare function createExperimentSlotEditor({ routes: inputRoutes, accent }?: {
|
|
6
|
+
routes?: PuckRoutes;
|
|
7
|
+
accent?: string;
|
|
8
|
+
}): ComponentConfig<ExperimentSlotProps>;
|
|
9
|
+
export declare const ExperimentSlotEditor: {
|
|
10
|
+
render: import("@puckeditor/core").PuckComponent<ExperimentSlotProps>;
|
|
11
|
+
label?: string;
|
|
12
|
+
defaultProps?: ExperimentSlotProps | undefined;
|
|
13
|
+
fields?: import("@puckeditor/core").Fields<ExperimentSlotProps, {}> | undefined;
|
|
14
|
+
renderFields?: ((props: {
|
|
15
|
+
fields: Partial<Record<keyof ExperimentSlotProps, import("react").ReactNode>>;
|
|
16
|
+
}) => import("react").ReactElement) | undefined;
|
|
17
|
+
permissions?: Partial<import("@puckeditor/core").Permissions>;
|
|
18
|
+
inline?: boolean;
|
|
19
|
+
resolveFields?: ((data: Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type">, params: {
|
|
20
|
+
changed: Partial<Record<keyof ExperimentSlotProps, boolean> & {
|
|
21
|
+
id: string;
|
|
22
|
+
}>;
|
|
23
|
+
fields: import("@puckeditor/core").Fields<ExperimentSlotProps, {}>;
|
|
24
|
+
lastFields: import("@puckeditor/core").Fields<ExperimentSlotProps, {}>;
|
|
25
|
+
lastData: Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type"> | null;
|
|
26
|
+
metadata: import("@puckeditor/core").ComponentMetadata;
|
|
27
|
+
appState: import("@puckeditor/core").AppState;
|
|
28
|
+
parent: import("@puckeditor/core").ComponentData | null;
|
|
29
|
+
}) => import("@puckeditor/core").Fields<ExperimentSlotProps, {}> | Promise<import("@puckeditor/core").Fields<ExperimentSlotProps, {}>>) | undefined;
|
|
30
|
+
resolveData?: ((data: Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type">, params: {
|
|
31
|
+
changed: Partial<Record<keyof ExperimentSlotProps, boolean> & {
|
|
32
|
+
id: string;
|
|
33
|
+
}>;
|
|
34
|
+
lastData: Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type"> | null;
|
|
35
|
+
metadata: import("@puckeditor/core").ComponentMetadata;
|
|
36
|
+
trigger: import("@puckeditor/core").ResolveDataTrigger;
|
|
37
|
+
parent: import("@puckeditor/core").ComponentData | null;
|
|
38
|
+
root: import("@puckeditor/core").RootData;
|
|
39
|
+
}) => (Omit<Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type">, "props"> & {
|
|
40
|
+
props?: Partial<ExperimentSlotProps> | undefined;
|
|
41
|
+
}) | Promise<Omit<Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type">, "props"> & {
|
|
42
|
+
props?: Partial<ExperimentSlotProps> | undefined;
|
|
43
|
+
}>) | undefined;
|
|
44
|
+
resolvePermissions?: ((data: Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type">, params: {
|
|
45
|
+
changed: Partial<Record<keyof ExperimentSlotProps, boolean> & {
|
|
46
|
+
id: string;
|
|
47
|
+
}>;
|
|
48
|
+
lastPermissions: Partial<import("@puckeditor/core").Permissions>;
|
|
49
|
+
permissions: Partial<import("@puckeditor/core").Permissions>;
|
|
50
|
+
appState: import("@puckeditor/core").AppState;
|
|
51
|
+
lastData: Omit<import("@puckeditor/core").ComponentData<ExperimentSlotProps, string, Record<string, import("@puckeditor/core").DefaultComponentProps>>, "type"> | null;
|
|
52
|
+
parent: import("@puckeditor/core").ComponentData | null;
|
|
53
|
+
}) => Promise<Partial<import("@puckeditor/core").Permissions>> | Partial<import("@puckeditor/core").Permissions>) | undefined;
|
|
54
|
+
metadata?: import("@puckeditor/core").ComponentMetadata;
|
|
55
|
+
} & import("@puckeditor/core").ComponentConfigExtensions;
|