@picked/client 0.0.70 → 0.0.71-next.2
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/dist/.tsbuildinfo +1 -0
- package/dist/api-B0ydpQBE.js +38 -0
- package/dist/api-CObostrU.cjs +1 -0
- package/dist/cjs/form/index.js +1 -1
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/plugins/dom-observer/index.js +1 -1
- package/dist/cjs/plugins/dynamic-experiences/index.js +1 -1
- package/dist/cjs/server/index.js +1 -1
- package/dist/docs/explanation/conditions-and-the-logic-engine.md +94 -0
- package/dist/docs/explanation/feature-flag-allocation.md +176 -0
- package/dist/docs/explanation/how-picked-works.md +102 -0
- package/dist/docs/explanation/how-pickedql-works.md +76 -0
- package/dist/docs/explanation/pages-and-flows.md +64 -0
- package/dist/docs/explanation/the-content-model.md +77 -0
- package/dist/docs/explanation/the-two-apis.md +68 -0
- package/dist/docs/explanation/why-server-side-rendering.md +76 -0
- package/dist/docs/explanation/workspaces-and-versions.md +71 -0
- package/dist/docs/how-to/add-a-step-field-or-action.md +43 -0
- package/dist/docs/{pickedql/examples.md → how-to/analytics/index.md} +19 -6
- package/dist/docs/how-to/archive-or-delete-a-workspace.md +46 -0
- package/dist/docs/how-to/authenticate-with-a-magic-link.md +40 -0
- package/dist/docs/how-to/authenticate-with-a-password.md +51 -0
- package/dist/docs/how-to/authenticate-with-an-api-key.md +51 -0
- package/dist/docs/how-to/authenticate-with-oauth.md +40 -0
- package/dist/docs/{flow-builder/building-flows.md → how-to/build-a-flow.md} +13 -9
- package/dist/docs/how-to/connect-the-mcp-server.md +38 -0
- package/dist/docs/how-to/create-a-project.md +29 -0
- package/dist/docs/how-to/create-an-experience.md +42 -0
- package/dist/docs/how-to/create-and-revoke-an-api-key.md +37 -0
- package/dist/docs/how-to/debug-with-the-chrome-extension.md +57 -0
- package/dist/docs/how-to/define-a-page-layout.md +39 -0
- package/dist/docs/how-to/fill-and-publish-a-page.md +50 -0
- package/dist/docs/{gtm-template.md → how-to/install-the-gtm-template.md} +9 -3
- package/dist/docs/how-to/install-the-sdk.md +68 -0
- package/dist/docs/how-to/install-the-vite-plugin.md +56 -0
- package/dist/docs/how-to/invite-and-remove-members.md +34 -0
- package/dist/docs/how-to/preview-a-workspace.md +28 -0
- package/dist/docs/how-to/publish-a-workspace.md +30 -0
- package/dist/docs/how-to/read-a-feature-flag.md +101 -0
- package/dist/docs/how-to/register-a-component.md +55 -0
- package/dist/docs/how-to/register-an-action-handler.md +67 -0
- package/dist/docs/how-to/render-a-step-form.md +132 -0
- package/dist/docs/how-to/render-an-unpublished-preview.md +41 -0
- package/dist/docs/how-to/reuse-a-section.md +37 -0
- package/dist/docs/how-to/reuse-a-step-field-or-action.md +28 -0
- package/dist/docs/how-to/roll-back-a-published-version.md +26 -0
- package/dist/docs/how-to/run-an-ab-test.md +49 -0
- package/dist/docs/how-to/run-code-on-a-form-submission.md +125 -0
- package/dist/docs/how-to/server-render-a-page.md +81 -0
- package/dist/docs/how-to/set-a-content-security-policy.md +32 -0
- package/dist/docs/how-to/set-up-mfa.md +69 -0
- package/dist/docs/how-to/upload-and-use-an-asset.mdx +73 -0
- package/dist/docs/how-to/validate-a-field.md +52 -0
- package/dist/docs/how-to/write-a-condition.md +45 -0
- package/dist/docs/how-to/write-a-predicate.md +60 -0
- package/dist/docs/index.md +41 -70
- package/dist/docs/reference/dashboard/actions.mdx +53 -0
- package/dist/docs/{api-keys.mdx → reference/dashboard/api-keys.mdx} +7 -15
- package/dist/docs/reference/dashboard/conditions.mdx +42 -0
- package/dist/docs/reference/dashboard/content/asset-library.mdx +63 -0
- package/dist/docs/{content → reference/dashboard/content}/content-entries.mdx +11 -3
- package/dist/docs/{content → reference/dashboard/content}/layouts.mdx +11 -35
- package/dist/docs/reference/dashboard/content/pages.mdx +35 -0
- package/dist/docs/reference/dashboard/content/sections.mdx +28 -0
- package/dist/docs/{experiences.mdx → reference/dashboard/experiences.mdx} +9 -16
- package/dist/docs/{features.mdx → reference/dashboard/features.mdx} +26 -41
- package/dist/docs/{fields.mdx → reference/dashboard/fields.mdx} +26 -20
- package/dist/docs/{flow-builder/overview.mdx → reference/dashboard/flow-builder/canvas.mdx} +8 -13
- package/dist/docs/{flow-builder → reference/dashboard/flow-builder}/condition-builder.md +5 -13
- package/dist/docs/{flow-builder → reference/dashboard/flow-builder}/keyboard-shortcuts.md +7 -1
- package/dist/docs/{flow-builder → reference/dashboard/flow-builder}/nodes.md +10 -3
- package/dist/docs/reference/dashboard/projects.mdx +44 -0
- package/dist/docs/reference/dashboard/reports.mdx +43 -0
- package/dist/docs/reference/dashboard/steps.mdx +37 -0
- package/dist/docs/{team-management.md → reference/dashboard/team-management.md} +5 -22
- package/dist/docs/{workspace-versioning.mdx → reference/dashboard/workspace-versioning.mdx} +6 -10
- package/dist/docs/reference/dashboard/workspaces.mdx +76 -0
- package/dist/docs/{delivery-api → reference/delivery-api}/experience-content.md +11 -4
- package/dist/docs/reference/delivery-api/index.md +45 -0
- package/dist/docs/{delivery-api → reference/delivery-api}/preview-caching-crawling.md +12 -5
- package/dist/docs/{delivery-api → reference/delivery-api}/project-config.md +11 -4
- package/dist/docs/reference/glossary.md +173 -0
- package/dist/docs/reference/management-api/authentication.md +74 -0
- package/dist/docs/{api → reference/management-api}/authorization-and-scopes.md +10 -3
- package/dist/docs/{api → reference/management-api}/error-handling.md +9 -3
- package/dist/docs/{api → reference/management-api}/pagination.md +6 -0
- package/dist/docs/{pickedql → reference/pickedql}/data-sources.md +16 -9
- package/dist/docs/{pickedql → reference/pickedql}/dimensions.md +7 -0
- package/dist/docs/{pickedql → reference/pickedql}/filtering.md +7 -0
- package/dist/docs/reference/pickedql/index.md +18 -0
- package/dist/docs/{pickedql → reference/pickedql}/schema.md +13 -6
- package/dist/docs/{pickedql → reference/pickedql}/virtual-functions.md +7 -0
- package/dist/docs/reference/sdk/actions.md +30 -0
- package/dist/docs/{sdk → reference/sdk}/conditions.md +8 -1
- package/dist/docs/reference/sdk/content-security-policy.md +21 -0
- package/dist/docs/reference/sdk/experiences.md +51 -0
- package/dist/docs/{sdk → reference/sdk}/features.md +30 -117
- package/dist/docs/{sdk → reference/sdk}/fields.md +10 -88
- package/dist/docs/reference/sdk/index.md +68 -0
- package/dist/docs/{sdk → reference/sdk}/plugins/create-experience.md +10 -22
- package/dist/docs/reference/sdk/plugins/dynamic-experiences.md +26 -0
- package/dist/docs/reference/sdk/plugins/index.md +29 -0
- package/dist/docs/{sdk → reference/sdk}/plugins/window-object.md +6 -0
- package/dist/docs/reference/sdk/predicates.md +43 -0
- package/dist/docs/reference/sdk/ssr/index.md +33 -0
- package/dist/docs/{sdk → reference/sdk}/ssr/rendering-and-hydration.md +4 -63
- package/dist/docs/{sdk → reference/sdk}/ssr/serialize.md +6 -33
- package/dist/docs/{sdk → reference/sdk}/ssr/slots-and-placements.md +7 -1
- package/dist/docs/reference/sdk/steps.md +87 -0
- package/dist/docs/reference/tools/chrome-extension.md +16 -0
- package/dist/docs/{image-optimisation-service.md → reference/tools/image-optimisation-service.md} +8 -0
- package/dist/docs/{mcp.md → reference/tools/mcp.md} +5 -45
- package/dist/docs/{vite-plugin.md → reference/tools/vite-plugin.md} +8 -38
- package/dist/docs/{api/index.md → tutorials/first-api-call.md} +27 -15
- package/dist/docs/tutorials/first-experience-in-the-dashboard.mdx +143 -0
- package/dist/docs/tutorials/first-experience.mdx +255 -0
- package/dist/docs/tutorials/first-server-rendered-page.mdx +186 -0
- package/dist/{dom-BwmTHeT7.js → dom-BqcToNL0.js} +1 -3
- package/dist/{dom-CDrHc_j9.cjs → dom-DlLH3FxV.cjs} +1 -1
- package/dist/esm/form/index.js +2 -4
- package/dist/esm/index.js +306 -298
- package/dist/esm/plugins/dom-observer/index.js +1 -1
- package/dist/esm/plugins/dynamic-experiences/index.js +2 -2
- package/dist/esm/preview/index.js +1 -1
- package/dist/esm/server/index.js +12 -10
- package/dist/{experience-instance-DOJShRk5.js → experience-instance-DGk11d8a.js} +3 -3
- package/dist/experience-instance-Dej3P1sE.cjs +1 -0
- package/dist/plugin-CNna0UjB.cjs +1 -0
- package/dist/{plugin-ChPkTj__.js → plugin-DUOJpHaq.js} +2 -2
- package/dist/{preview-channel-DW9J8t4B.js → preview-channel-CSr96XAo.js} +1 -1
- package/dist/{protocol-DSqOlW2r.js → protocol-C5KkkiZc.js} +1 -1
- package/dist/types/client.d.ts +7 -6
- package/dist/types/entities/action/action.d.ts +5 -4
- package/dist/types/entities/action/action.d.ts.map +1 -1
- package/dist/types/entities/component/component.d.ts +6 -5
- package/dist/types/entities/component/component.d.ts.map +1 -1
- package/dist/types/entities/condition/condition.d.ts +5 -5
- package/dist/types/entities/content/content.d.ts +4 -3
- package/dist/types/entities/experience/experience.d.ts +11 -10
- package/dist/types/entities/experience/experience.d.ts.map +1 -1
- package/dist/types/entities/experience-instance/experience-instance.d.ts +10 -9
- package/dist/types/entities/feature/feature.d.ts +19 -2
- package/dist/types/entities/feature/feature.d.ts.map +1 -1
- package/dist/types/entities/field/field.d.ts +7 -6
- package/dist/types/entities/framework/framework.d.ts +7 -6
- package/dist/types/entities/framework/framework.d.ts.map +1 -1
- package/dist/types/entities/history/history.d.ts +6 -6
- package/dist/types/entities/plugin/plugin.d.ts +3 -2
- package/dist/types/entities/plugin/plugin.d.ts.map +1 -1
- package/dist/types/entities/predicate/predicate.d.ts +4 -3
- package/dist/types/entities/predicate/predicate.d.ts.map +1 -1
- package/dist/types/entities/response/response-validation.d.ts +3 -2
- package/dist/types/entities/response/response.d.ts +12 -11
- package/dist/types/entities/session/session.d.ts +2 -1
- package/dist/types/entities/step/step.d.ts +6 -5
- package/dist/types/exports.d.ts +2 -1
- package/dist/types/exports.d.ts.map +1 -1
- package/dist/types/form/build-responses.d.ts +2 -1
- package/dist/types/form/create-field-evaluator.d.ts +4 -3
- package/dist/types/form/create-field-validation.d.ts +5 -4
- package/dist/types/form/create-form.d.ts +7 -6
- package/dist/types/form/create-submit-pipeline.d.ts +7 -6
- package/dist/types/form/get-step-fields.d.ts +3 -2
- package/dist/types/lifecycle/condition-selection.d.ts +14 -4
- package/dist/types/lifecycle/lifecycle.d.ts +4 -3
- package/dist/types/lifecycle/rules-logic.d.ts +4 -3
- package/dist/types/lifecycle/state-snapshot.d.ts +4 -3
- package/dist/types/picked.d.ts +64 -62
- package/dist/types/picked.d.ts.map +1 -1
- package/dist/types/ping.d.ts +1 -1
- package/dist/types/ping.d.ts.map +1 -1
- package/dist/types/plugins/create-experience/create-experience.d.ts +9 -8
- package/dist/types/plugins/create-experience/create-experience.d.ts.map +1 -1
- package/dist/types/plugins/create-experience/plugin.d.ts +3 -2
- package/dist/types/plugins/create-experience/plugin.d.ts.map +1 -1
- package/dist/types/plugins/create-experience/serialization.d.ts.map +1 -1
- package/dist/types/plugins/dom-observer/plugin.d.ts +1 -1
- package/dist/types/plugins/dynamic-experiences/plugin.d.ts +3 -3
- package/dist/types/plugins/dynamic-experiences/types.d.ts +8 -5
- package/dist/types/plugins/experience-browser-storage/plugin.d.ts +1 -1
- package/dist/types/plugins/experience-browser-storage/plugin.d.ts.map +1 -1
- package/dist/types/plugins/history-browser-storage/plugin.d.ts +1 -1
- package/dist/types/plugins/history-browser-storage/plugin.d.ts.map +1 -1
- package/dist/types/plugins/responses-browser-storage/plugin.d.ts +1 -1
- package/dist/types/plugins/responses-browser-storage/plugin.d.ts.map +1 -1
- package/dist/types/plugins/responses-indexeddb/plugin.d.ts +1 -1
- package/dist/types/plugins/single-page-app/plugin.d.ts +1 -1
- package/dist/types/plugins/single-page-app/plugin.d.ts.map +1 -1
- package/dist/types/plugins/web-components/plugin.d.ts +2 -1
- package/dist/types/plugins/window-object/plugin.d.ts +2 -2
- package/dist/types/preview-channel.d.ts +5 -1
- package/dist/types/preview-receiver/index.d.ts +18 -1
- package/dist/types/preview-receiver/protocol.d.ts +10 -1
- package/dist/types/server/index.d.ts +3 -3
- package/dist/types/server/serialize.d.ts +2 -2
- package/dist/types/utils/dom.d.ts +2 -1
- package/dist/types/utils/events.d.ts +6 -6
- package/dist/types/utils/events.d.ts.map +1 -1
- package/dist/types/utils/global-obj.d.ts +1 -1
- package/dist/types/utils/global-obj.d.ts.map +1 -1
- package/dist/types/utils/id.d.ts.map +1 -1
- package/dist/types/utils/logger.d.ts +2 -1
- package/dist/types/utils/logger.d.ts.map +1 -1
- package/dist/types/utils/node-tree/get-next-node-from-action.d.ts +2 -1
- package/dist/types/utils/node-tree/get-next-node-from-condition.d.ts +2 -1
- package/dist/types/utils/node-tree/get-next-node.d.ts +1 -1
- package/dist/types/utils/node-tree/get-next-node.d.ts.map +1 -1
- package/dist/types/utils/node-tree/get-origin-node.d.ts +1 -1
- package/dist/types/utils/node-tree/get-origin-node.d.ts.map +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-leaf.d.ts +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-leaf.d.ts.map +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-origin.d.ts +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-origin.d.ts.map +1 -1
- package/dist/types/utils/node-tree/next-reachable-step-nodes.d.ts +1 -1
- package/dist/types/utils/node-tree/next-reachable-step-nodes.d.ts.map +1 -1
- package/dist/types/utils/nodes.d.ts +1 -1
- package/dist/types/utils/picked-config.d.ts +2 -1
- package/dist/types/utils/rules-logic.d.ts +6 -2
- package/dist/types/utils/storage.d.ts +1 -1
- package/dist/types/utils/storage.d.ts.map +1 -1
- package/package.json +22 -23
- package/dist/api-CPy9G49C.js +0 -40
- package/dist/api-Ce6xYI--.cjs +0 -1
- package/dist/docs/actions.mdx +0 -98
- package/dist/docs/api/authentication.md +0 -403
- package/dist/docs/chrome-extension.md +0 -68
- package/dist/docs/conditions.mdx +0 -72
- package/dist/docs/content/asset-library.mdx +0 -124
- package/dist/docs/content/pages.mdx +0 -82
- package/dist/docs/content/sections.mdx +0 -44
- package/dist/docs/delivery-api/index.md +0 -53
- package/dist/docs/guides/build-a-personalized-page.mdx +0 -161
- package/dist/docs/pickedql/index.md +0 -54
- package/dist/docs/projects.mdx +0 -44
- package/dist/docs/reports.mdx +0 -20
- package/dist/docs/sdk/actions.md +0 -82
- package/dist/docs/sdk/content-security-policy.md +0 -33
- package/dist/docs/sdk/experiences.md +0 -64
- package/dist/docs/sdk/feature-allocation.md +0 -161
- package/dist/docs/sdk/index.md +0 -98
- package/dist/docs/sdk/plugins/dynamic-experiences.md +0 -84
- package/dist/docs/sdk/plugins/index.md +0 -9
- package/dist/docs/sdk/predicates.md +0 -128
- package/dist/docs/sdk/ssr/index.md +0 -79
- package/dist/docs/sdk/steps.md +0 -479
- package/dist/docs/steps.mdx +0 -53
- package/dist/docs/workspaces.mdx +0 -133
- package/dist/experience-instance-DurC3pE-.cjs +0 -1
- package/dist/plugin-DHn11gn6.cjs +0 -1
package/dist/docs/sdk/steps.md
DELETED
|
@@ -1,479 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Steps
|
|
6
|
-
|
|
7
|
-
Render your steps with `<StepRouter>` and `<Step>` from `@picked/react` or
|
|
8
|
-
`@picked/svelte`. Reach the active step through `useStep()` or `getStep()`.
|
|
9
|
-
|
|
10
|
-
## How steps work
|
|
11
|
-
|
|
12
|
-
When an experience starts, its steps form a directed graph of nodes. The SDK walks
|
|
13
|
-
this graph to find which step to show:
|
|
14
|
-
|
|
15
|
-
1. **Initialization**: when the experience opens, the SDK starts at the origin node.
|
|
16
|
-
It walks the graph to find the first step.
|
|
17
|
-
2. **Step entry**: the SDK sets the active step. It sends a `step_enter` event on the
|
|
18
|
-
event bus.
|
|
19
|
-
3. **Field evaluation**: the SDK evaluates the fields of the step. It shows or hides
|
|
20
|
-
a field with a condition, and the current state decides which.
|
|
21
|
-
4. **User input**: the user fills in the fields of the step. Validation runs in the
|
|
22
|
-
browser on blur and on submit.
|
|
23
|
-
5. **Step submission**: when the user submits, a `step_submit` event fires. The SDK
|
|
24
|
-
commits the field responses to the client state.
|
|
25
|
-
6. **Navigation**: the SDK follows the edge from the current step node to the next
|
|
26
|
-
one. It walks through each condition and action on the way.
|
|
27
|
-
7. **Completion**: when no step remains, the experience flow is complete.
|
|
28
|
-
|
|
29
|
-
## Step routing
|
|
30
|
-
|
|
31
|
-
`StepRouter` watches the current step state of the experience. It activates the
|
|
32
|
-
`Step` whose `id` matches. Each `Step` registers itself on mount and unregisters on
|
|
33
|
-
unmount, so a tab or a drawer that renders lazily works with no extra code.
|
|
34
|
-
|
|
35
|
-
:::code-group
|
|
36
|
-
|
|
37
|
-
```svelte [Svelte]
|
|
38
|
-
<script lang="ts">
|
|
39
|
-
import { StepRouter, Step } from '@picked/svelte/router'
|
|
40
|
-
</script>
|
|
41
|
-
|
|
42
|
-
<StepRouter>
|
|
43
|
-
<Step id="welcome">
|
|
44
|
-
<WelcomeScreen />
|
|
45
|
-
</Step>
|
|
46
|
-
|
|
47
|
-
<Step id="contact">
|
|
48
|
-
<ContactForm />
|
|
49
|
-
</Step>
|
|
50
|
-
|
|
51
|
-
<Step id="confirmation">
|
|
52
|
-
<ConfirmationScreen />
|
|
53
|
-
</Step>
|
|
54
|
-
</StepRouter>
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
```tsx [React]
|
|
58
|
-
import { StepRouter, Step } from '@picked/react/router'
|
|
59
|
-
|
|
60
|
-
function MyExperience() {
|
|
61
|
-
return (
|
|
62
|
-
<StepRouter>
|
|
63
|
-
<Step id="welcome">
|
|
64
|
-
<WelcomeScreen />
|
|
65
|
-
</Step>
|
|
66
|
-
|
|
67
|
-
<Step id="contact">
|
|
68
|
-
<ContactForm />
|
|
69
|
-
</Step>
|
|
70
|
-
|
|
71
|
-
<Step id="confirmation">
|
|
72
|
-
<ConfirmationScreen />
|
|
73
|
-
</Step>
|
|
74
|
-
</StepRouter>
|
|
75
|
-
)
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
:::
|
|
80
|
-
|
|
81
|
-
:::note
|
|
82
|
-
A router must hold every Step, even when there is only one Step.
|
|
83
|
-
:::
|
|
84
|
-
|
|
85
|
-
### Lazy-loaded steps
|
|
86
|
-
|
|
87
|
-
For a large experience, load a step lazily with a dynamic import:
|
|
88
|
-
|
|
89
|
-
:::code-group
|
|
90
|
-
|
|
91
|
-
```svelte [Svelte]
|
|
92
|
-
<StepRouter>
|
|
93
|
-
<Step id="welcome" component={import('./WelcomeScreen.svelte')} />
|
|
94
|
-
</StepRouter>
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
```tsx [React]
|
|
98
|
-
import { lazy } from 'react'
|
|
99
|
-
|
|
100
|
-
const WelcomeScreen = lazy(() => import('./WelcomeScreen'))
|
|
101
|
-
|
|
102
|
-
<StepRouter>
|
|
103
|
-
<Step id="welcome">
|
|
104
|
-
<WelcomeScreen />
|
|
105
|
-
</Step>
|
|
106
|
-
</StepRouter>
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
:::
|
|
110
|
-
|
|
111
|
-
The `component` prop takes a `Promise<Component>`. The SDK does not load the content
|
|
112
|
-
of the step until that step becomes active.
|
|
113
|
-
|
|
114
|
-
## Reach the step context
|
|
115
|
-
|
|
116
|
-
Inside a `Step` component, or inside any component that a `Step` renders, call
|
|
117
|
-
`getStep()` or `useStep()` to reach the reactive context of the step:
|
|
118
|
-
|
|
119
|
-
:::code-group
|
|
120
|
-
|
|
121
|
-
```svelte [Svelte]
|
|
122
|
-
<script lang="ts">
|
|
123
|
-
import { getStep } from '@picked/svelte/hooks'
|
|
124
|
-
|
|
125
|
-
const { step, fields } = getStep()
|
|
126
|
-
</script>
|
|
127
|
-
|
|
128
|
-
<h1>{$step.label}</h1>
|
|
129
|
-
|
|
130
|
-
{#each $fields as field}
|
|
131
|
-
<label>{field.label}</label>
|
|
132
|
-
<input
|
|
133
|
-
name={field.id}
|
|
134
|
-
value={field.value ?? ''}
|
|
135
|
-
onchange={field.onChange}
|
|
136
|
-
onblur={field.onBlur}
|
|
137
|
-
/>
|
|
138
|
-
{#if field.error && field.touched}
|
|
139
|
-
<p class="error">{field.error.userMessage}</p>
|
|
140
|
-
{/if}
|
|
141
|
-
{/each}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
```tsx [React]
|
|
145
|
-
import { useStep } from '@picked/react/hooks'
|
|
146
|
-
import { useUnit } from 'effector-react'
|
|
147
|
-
|
|
148
|
-
function ContactForm() {
|
|
149
|
-
const { step, fields } = useStep()
|
|
150
|
-
const currentStep = useUnit(step)
|
|
151
|
-
const currentFields = useUnit(fields)
|
|
152
|
-
|
|
153
|
-
return (
|
|
154
|
-
<>
|
|
155
|
-
<h1>{currentStep.label}</h1>
|
|
156
|
-
|
|
157
|
-
{currentFields.map((field) => (
|
|
158
|
-
<div key={field.id}>
|
|
159
|
-
<label>{field.label}</label>
|
|
160
|
-
<input
|
|
161
|
-
name={field.id}
|
|
162
|
-
value={field.value ?? ''}
|
|
163
|
-
onChange={field.onChange}
|
|
164
|
-
onBlur={field.onBlur}
|
|
165
|
-
/>
|
|
166
|
-
{field.error && field.touched && <p className="error">{field.error.userMessage}</p>}
|
|
167
|
-
</div>
|
|
168
|
-
))}
|
|
169
|
-
</>
|
|
170
|
-
)
|
|
171
|
-
}
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
:::
|
|
175
|
-
|
|
176
|
-
`getStep()` in Svelte, and `useStep()` in React, return a `StepContext` with these
|
|
177
|
-
properties:
|
|
178
|
-
|
|
179
|
-
| Property | Type | Description |
|
|
180
|
-
| ---------- | --------------------------------------------- | ------------------------------------------------------------------------------ |
|
|
181
|
-
| `step` | `Store<ExperienceStep>` | A reactive store that holds the `id` and the `label` of the step |
|
|
182
|
-
| `fields` | `Store<FormField[]>` | A reactive store of the fields, with their current values, errors, and handlers |
|
|
183
|
-
| `isActive` | `Store<boolean>` (Svelte) / `boolean` (React) | Whether the router holds this step as the active one |
|
|
184
|
-
| `form` | Object | The handlers for a form submission. See [Forms](#forms). |
|
|
185
|
-
|
|
186
|
-
## Forms
|
|
187
|
-
|
|
188
|
-
When a step has fields, `getStep()` and `useStep()` give you a `form` object. Use it
|
|
189
|
-
for the submission, the validation, and the move to the next step.
|
|
190
|
-
|
|
191
|
-
Both take an optional object of callbacks, as in `getStep({ onSuccess })` or
|
|
192
|
-
`useStep({ onSuccess })`. This is the recommended way to act on a submission. The
|
|
193
|
-
slots are `onBeforeSubmit`, `onSuccess`, and `onError`. This page covers each one
|
|
194
|
-
below.
|
|
195
|
-
|
|
196
|
-
### Handle a submission
|
|
197
|
-
|
|
198
|
-
Bind `form.props` to the `onsubmit` handler of your `<form>` element:
|
|
199
|
-
|
|
200
|
-
:::code-group
|
|
201
|
-
|
|
202
|
-
```svelte [Svelte]
|
|
203
|
-
<script lang="ts">
|
|
204
|
-
import { getStep } from '@picked/svelte/hooks'
|
|
205
|
-
|
|
206
|
-
const { fields, form } = getStep()
|
|
207
|
-
const isSubmitting = form.submitting
|
|
208
|
-
</script>
|
|
209
|
-
|
|
210
|
-
<form {...form.props}>
|
|
211
|
-
{#each $fields as field}
|
|
212
|
-
<input
|
|
213
|
-
name={field.id}
|
|
214
|
-
value={field.value ?? ''}
|
|
215
|
-
onchange={field.onChange}
|
|
216
|
-
onblur={field.onBlur}
|
|
217
|
-
/>
|
|
218
|
-
{#if field.error && field.touched}
|
|
219
|
-
<p class="error">{field.error.userMessage}</p>
|
|
220
|
-
{/if}
|
|
221
|
-
{/each}
|
|
222
|
-
|
|
223
|
-
<button type="submit" disabled={$isSubmitting}>
|
|
224
|
-
{$isSubmitting ? 'Submitting…' : 'Continue'}
|
|
225
|
-
</button>
|
|
226
|
-
</form>
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
```tsx [React]
|
|
230
|
-
import { useStep } from '@picked/react/hooks'
|
|
231
|
-
import { useUnit } from 'effector-react'
|
|
232
|
-
|
|
233
|
-
function StepForm() {
|
|
234
|
-
const { fields, form } = useStep()
|
|
235
|
-
const currentFields = useUnit(fields)
|
|
236
|
-
const isSubmitting = useUnit(form.submitting)
|
|
237
|
-
|
|
238
|
-
return (
|
|
239
|
-
<form {...form.props}>
|
|
240
|
-
{currentFields.map((field) => (
|
|
241
|
-
<div key={field.id}>
|
|
242
|
-
<input
|
|
243
|
-
name={field.id}
|
|
244
|
-
value={field.value ?? ''}
|
|
245
|
-
onChange={field.onChange}
|
|
246
|
-
onBlur={field.onBlur}
|
|
247
|
-
/>
|
|
248
|
-
{field.error && field.touched && <p className="error">{field.error.userMessage}</p>}
|
|
249
|
-
</div>
|
|
250
|
-
))}
|
|
251
|
-
|
|
252
|
-
<button type="submit" disabled={isSubmitting}>
|
|
253
|
-
{isSubmitting ? 'Submitting…' : 'Continue'}
|
|
254
|
-
</button>
|
|
255
|
-
</form>
|
|
256
|
-
)
|
|
257
|
-
}
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
:::
|
|
261
|
-
|
|
262
|
-
When you submit the form, the SDK does this:
|
|
263
|
-
|
|
264
|
-
1. It collects the field values from the HTML form.
|
|
265
|
-
2. It runs each `onBeforeSubmit` callback, one after another. A throw here aborts the
|
|
266
|
-
submit and commits nothing.
|
|
267
|
-
3. It checks each required field and each validation rule.
|
|
268
|
-
4. It commits the responses to the experience state.
|
|
269
|
-
5. It fires `form_submit_success` or `form_submit_error` on the event bus.
|
|
270
|
-
6. It runs your `onSuccess` or `onError` callback.
|
|
271
|
-
7. It moves to the next step. A call to `stopNavigation` stops this. A callback that
|
|
272
|
-
failed in step 6 does not stop it.
|
|
273
|
-
|
|
274
|
-
### Transform data before a submission
|
|
275
|
-
|
|
276
|
-
Use `onBeforeSubmit` to intercept and transform the field data before the SDK stores it. The callbacks run one after another. Each one takes the output of the one before
|
|
277
|
-
it:
|
|
278
|
-
|
|
279
|
-
:::code-group
|
|
280
|
-
|
|
281
|
-
```svelte [Svelte]
|
|
282
|
-
<script lang="ts">
|
|
283
|
-
import { getStep } from '@picked/svelte/hooks'
|
|
284
|
-
|
|
285
|
-
const { form } = getStep({
|
|
286
|
-
onBeforeSubmit: async (data) => {
|
|
287
|
-
// Normalize the email address to lowercase first.
|
|
288
|
-
return {
|
|
289
|
-
...data,
|
|
290
|
-
'email-address': String(data['email-address']).toLowerCase(),
|
|
291
|
-
}
|
|
292
|
-
},
|
|
293
|
-
})
|
|
294
|
-
</script>
|
|
295
|
-
|
|
296
|
-
<form {...form.props}>{/* ... */}</form>
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
```tsx [React]
|
|
300
|
-
import { useStep } from '@picked/react/hooks'
|
|
301
|
-
|
|
302
|
-
function ContactStep() {
|
|
303
|
-
const { form } = useStep({
|
|
304
|
-
onBeforeSubmit: async (data) => {
|
|
305
|
-
// Normalize the email address to lowercase first.
|
|
306
|
-
return {
|
|
307
|
-
...data,
|
|
308
|
-
'email-address': String(data['email-address']).toLowerCase(),
|
|
309
|
-
}
|
|
310
|
-
},
|
|
311
|
-
})
|
|
312
|
-
|
|
313
|
-
return <form {...form.props}>{/* ... */}</form>
|
|
314
|
-
}
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
:::
|
|
318
|
-
|
|
319
|
-
:::warning
|
|
320
|
-
When an `onBeforeSubmit` callback throws, the SDK aborts the submit before it commits
|
|
321
|
-
anything, and the step does not advance. This is deliberate. A payload that is only
|
|
322
|
-
part transformed would store data that looks correct but is wrong. Use
|
|
323
|
-
`onBeforeSubmit` for a transform and for a validation check. Put a side effect, such as an
|
|
324
|
-
analytics call or a backend call, in `onSuccess`.
|
|
325
|
-
:::
|
|
326
|
-
|
|
327
|
-
### Success and error callbacks
|
|
328
|
-
|
|
329
|
-
Pass `onSuccess` and `onError` to act on the outcome of a submission:
|
|
330
|
-
|
|
331
|
-
:::code-group
|
|
332
|
-
|
|
333
|
-
```svelte [Svelte]
|
|
334
|
-
<script lang="ts">
|
|
335
|
-
import { getStep } from '@picked/svelte/hooks'
|
|
336
|
-
|
|
337
|
-
const { form } = getStep({
|
|
338
|
-
onSuccess: ({ data }) => {
|
|
339
|
-
analytics.track('lead_captured', data)
|
|
340
|
-
},
|
|
341
|
-
onError: (errors) => {
|
|
342
|
-
console.error('Validation errors:', errors)
|
|
343
|
-
},
|
|
344
|
-
})
|
|
345
|
-
</script>
|
|
346
|
-
|
|
347
|
-
<form {...form.props}>{/* ... */}</form>
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
```tsx [React]
|
|
351
|
-
import { useStep } from '@picked/react/hooks'
|
|
352
|
-
|
|
353
|
-
function ContactStep() {
|
|
354
|
-
const { form } = useStep({
|
|
355
|
-
onSuccess: ({ data }) => {
|
|
356
|
-
analytics.track('lead_captured', data)
|
|
357
|
-
},
|
|
358
|
-
onError: (errors) => {
|
|
359
|
-
console.error('Validation errors:', errors)
|
|
360
|
-
},
|
|
361
|
-
})
|
|
362
|
-
|
|
363
|
-
return <form {...form.props}>{/* ... */}</form>
|
|
364
|
-
}
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
:::
|
|
368
|
-
|
|
369
|
-
A callback belongs to the component that passes it. The SDK releases the callback
|
|
370
|
-
when that component unmounts, so you write no teardown code. A new inline function on
|
|
371
|
-
a re-render replaces the earlier one and does not add a second one. One submit
|
|
372
|
-
therefore runs each callback exactly one time.
|
|
373
|
-
|
|
374
|
-
An `onSuccess` or `onError` callback that throws or rejects cannot stop the flow. The
|
|
375
|
-
step still advances, and the SDK reports the failure on the client event bus as
|
|
376
|
-
`form_submit_callback_error`, so the failure stays observable.
|
|
377
|
-
|
|
378
|
-
#### Register a callback in code
|
|
379
|
-
|
|
380
|
-
`form.onSuccess`, `form.onError`, and `form.onBeforeSubmit` are an escape hatch, for
|
|
381
|
-
a callback that you must attach only when a condition holds. They return nothing. The
|
|
382
|
-
SDK releases them for you, as above.
|
|
383
|
-
|
|
384
|
-
```tsx [React]
|
|
385
|
-
function ContactStep({ trackConversions }: { trackConversions: boolean }) {
|
|
386
|
-
const { form } = useStep()
|
|
387
|
-
|
|
388
|
-
if (trackConversions) {
|
|
389
|
-
form.onSuccess(({ data }) => analytics.track('lead_captured', data))
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
return <form {...form.props}>{/* ... */}</form>
|
|
393
|
-
}
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
:::warning
|
|
397
|
-
Register from the body of the component, and not from an event handler. A
|
|
398
|
-
registration inside a click handler is added each time the handler runs, and the SDK
|
|
399
|
-
releases it only when the component unmounts. The registrations therefore accumulate.
|
|
400
|
-
Use the options object above where you can.
|
|
401
|
-
:::
|
|
402
|
-
|
|
403
|
-
### Stop the move to the next step
|
|
404
|
-
|
|
405
|
-
By default the experience advances to the next step after a successful submission.
|
|
406
|
-
Call `stopNavigation()` inside `onSuccess` to stop this. Do it when you must choose
|
|
407
|
-
the next step yourself:
|
|
408
|
-
|
|
409
|
-
:::code-group
|
|
410
|
-
|
|
411
|
-
```svelte [Svelte]
|
|
412
|
-
<script lang="ts">
|
|
413
|
-
import { getStep } from '@picked/svelte/hooks'
|
|
414
|
-
import { getExperience } from '@picked/svelte/hooks'
|
|
415
|
-
|
|
416
|
-
const experience = getExperience()
|
|
417
|
-
|
|
418
|
-
const { form } = getStep({
|
|
419
|
-
onSuccess: ({ data, stopNavigation }) => {
|
|
420
|
-
stopNavigation()
|
|
421
|
-
|
|
422
|
-
// Choose the next step from the data that the user sent.
|
|
423
|
-
if (data['plan-type'] === 'enterprise') {
|
|
424
|
-
experience.goToStepById('enterprise-contact')
|
|
425
|
-
} else {
|
|
426
|
-
experience.goToNextStep()
|
|
427
|
-
}
|
|
428
|
-
},
|
|
429
|
-
})
|
|
430
|
-
</script>
|
|
431
|
-
|
|
432
|
-
<form {...form.props}>{/* ... */}</form>
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
```tsx [React]
|
|
436
|
-
import { useStep } from '@picked/react/hooks'
|
|
437
|
-
import { useExperience } from '@picked/react/hooks'
|
|
438
|
-
|
|
439
|
-
function PlanStep() {
|
|
440
|
-
const experience = useExperience()
|
|
441
|
-
|
|
442
|
-
const { form } = useStep({
|
|
443
|
-
onSuccess: ({ data, stopNavigation }) => {
|
|
444
|
-
stopNavigation()
|
|
445
|
-
|
|
446
|
-
// Choose the next step from the data that the user sent.
|
|
447
|
-
if (data['plan-type'] === 'enterprise') {
|
|
448
|
-
experience.goToStepById('enterprise-contact')
|
|
449
|
-
} else {
|
|
450
|
-
experience.goToNextStep()
|
|
451
|
-
}
|
|
452
|
-
},
|
|
453
|
-
})
|
|
454
|
-
|
|
455
|
-
return <form {...form.props}>{/* ... */}</form>
|
|
456
|
-
}
|
|
457
|
-
```
|
|
458
|
-
|
|
459
|
-
:::
|
|
460
|
-
|
|
461
|
-
Move by step `id` with `goToStepById('<step-id>')`, or by the `key` of the step with
|
|
462
|
-
`goToStepByKey('<step-key>')`. Both jump directly to the step node that matches. When
|
|
463
|
-
no step matches, the call does nothing.
|
|
464
|
-
|
|
465
|
-
## Best practices
|
|
466
|
-
|
|
467
|
-
- **Give each step a meaningful label**: analytics events and the dashboard both show
|
|
468
|
-
the `label`. Use a name that says what the step does, such as `"Contact Details"`
|
|
469
|
-
and not `"Step 2"`.
|
|
470
|
-
- **Keep each step small**: each step must collect one small set of related
|
|
471
|
-
information. More steps with fewer fields each reduce the number of users who leave.
|
|
472
|
-
- **Use a condition to take a branch**: do not make a second copy of a step. Write the
|
|
473
|
-
branch with `nextConditional()`, so that you can reuse a shared step.
|
|
474
|
-
- **Use `stopNavigation` only when you must**: an automatic move after a submit is
|
|
475
|
-
what a user expects. Stop it only when you must choose the next step yourself.
|
|
476
|
-
- **Check a field on blur, not on change**: the SDK does this for you. A field shows
|
|
477
|
-
an error after the user leaves it, and not while the user types.
|
|
478
|
-
- **Load a large step component lazily**: use the `component` prop on `<Step>` with a
|
|
479
|
-
dynamic import, for content that only some users see.
|
package/dist/docs/steps.mdx
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
import { Screenshot } from '../../components/Screenshot'
|
|
6
|
-
|
|
7
|
-
# Steps
|
|
8
|
-
|
|
9
|
-
A step is one screen or card that a visitor sees during an experience. Each step
|
|
10
|
-
holds one or more fields. A field collects data or shows content.
|
|
11
|
-
|
|
12
|
-
<Screenshot
|
|
13
|
-
route="/{orgSlug}/{projectId}/workspaces/{workspaceId}/steps"
|
|
14
|
-
alt="The steps list for a workspace on the Picked dashboard"
|
|
15
|
-
/>
|
|
16
|
-
|
|
17
|
-
## Create a step
|
|
18
|
-
|
|
19
|
-
1. Open your project.
|
|
20
|
-
2. Click **Steps** in the sidebar.
|
|
21
|
-
3. Click **New Step**.
|
|
22
|
-
4. Enter a name and a key.
|
|
23
|
-
5. Click **Create**.
|
|
24
|
-
|
|
25
|
-
The key is a unique identifier for your application. You set it once, and you cannot
|
|
26
|
-
change it later.
|
|
27
|
-
|
|
28
|
-
## Set up a step
|
|
29
|
-
|
|
30
|
-
**Name**: The name that the dashboard shows. Your visitors do not see it.
|
|
31
|
-
|
|
32
|
-
**Key**: The identifier that your application uses for this step. Your
|
|
33
|
-
visitors do not see it.
|
|
34
|
-
|
|
35
|
-
**Layout Name**: The name of the component layout that renders this step. Examples
|
|
36
|
-
are `card`, `modal`, and `fullscreen`.
|
|
37
|
-
|
|
38
|
-
A step can also carry a **Step Layout**. A step layout is a reusable CMS schema, and
|
|
39
|
-
it gives the step a Content Entry. See [Page and Step Layouts](/content/layouts).
|
|
40
|
-
|
|
41
|
-
## Assign fields
|
|
42
|
-
|
|
43
|
-
In the flow builder, drag a field from the entity browser onto a step node. The field
|
|
44
|
-
appears in the **Assigned Fields** list of the step, in the inspector.
|
|
45
|
-
|
|
46
|
-
You can also choose the step node and expand the **Assigned Fields** section to see
|
|
47
|
-
and control the assigned fields. Click a field to open its inspector.
|
|
48
|
-
|
|
49
|
-
## Reuse steps
|
|
50
|
-
|
|
51
|
-
A step is a project-level entity. You can drag the same step into more than one
|
|
52
|
-
experience flow. A change to the options of a step applies at every place that uses
|
|
53
|
-
it.
|
package/dist/docs/workspaces.mdx
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
import { Screenshot } from '../../components/Screenshot'
|
|
6
|
-
|
|
7
|
-
# Workspaces
|
|
8
|
-
|
|
9
|
-
A workspace is one version of the options for your project. Use a workspace to hold
|
|
10
|
-
a change, to see a preview of it, and to publish it when it is ready.
|
|
11
|
-
|
|
12
|
-
<Screenshot
|
|
13
|
-
route="/{orgSlug}/{projectId}/workspaces"
|
|
14
|
-
alt="The workspaces list inside a project on the Picked dashboard"
|
|
15
|
-
hide={['[data-testid="workspace-row-relative-time"]']}
|
|
16
|
-
/>
|
|
17
|
-
|
|
18
|
-
## How workspaces work
|
|
19
|
-
|
|
20
|
-
Each project has a workspace that holds your experiences, feature flags, and entity
|
|
21
|
-
options. When you make a change in the dashboard, that change stays in the workspace
|
|
22
|
-
until you publish it. A change to a flow, to a feature flag, or to an entity all
|
|
23
|
-
behave the same way.
|
|
24
|
-
|
|
25
|
-
A workspace is in one of three states:
|
|
26
|
-
|
|
27
|
-
- **Live** — the workspace that the SDK serves to your visitors. Each project has
|
|
28
|
-
exactly one live workspace.
|
|
29
|
-
- **Draft** — a workspace that no visitor sees. You can edit a draft, see a preview
|
|
30
|
-
of it, and publish it to make it live.
|
|
31
|
-
- **Archived** — a draft that you put to one side. An archived workspace is still
|
|
32
|
-
editable, but it does not appear in the default workspaces list.
|
|
33
|
-
|
|
34
|
-
## Preview
|
|
35
|
-
|
|
36
|
-
See a preview of your workspace to learn how a change looks before you publish it.
|
|
37
|
-
|
|
38
|
-
1. Click **Preview** in the workspace toolbar.
|
|
39
|
-
2. Enter the URL of your site.
|
|
40
|
-
3. Set each feature flag to the **Default**, **On**, or **Off** value. This step is
|
|
41
|
-
optional.
|
|
42
|
-
4. Click **Open Preview**.
|
|
43
|
-
|
|
44
|
-
Your site opens in a new tab with the unpublished workspace applied. The preview
|
|
45
|
-
sends the workspace state to the SDK in the query parameters, so the visitors on
|
|
46
|
-
your live site see no change.
|
|
47
|
-
|
|
48
|
-
## Publish
|
|
49
|
-
|
|
50
|
-
When you publish, Picked makes an immutable snapshot of your workspace. The SDK then
|
|
51
|
-
serves the new options to your visitors.
|
|
52
|
-
|
|
53
|
-
1. Click **Publish** in the workspace toolbar.
|
|
54
|
-
2. Read the change preview in the publish modal.
|
|
55
|
-
3. Click **Publish** to confirm.
|
|
56
|
-
|
|
57
|
-
The publish button is active only when the workspace has an unpublished change. A
|
|
58
|
-
status badge in the toolbar shows whether the workspace has an unpublished change or
|
|
59
|
-
is up to date.
|
|
60
|
-
|
|
61
|
-
## Change previews
|
|
62
|
-
|
|
63
|
-
The publish modal shows a side-by-side change preview. It compares the current
|
|
64
|
-
workspace against the last published snapshot. Use it to see exactly what your
|
|
65
|
-
visitors get after you publish.
|
|
66
|
-
|
|
67
|
-
<Screenshot
|
|
68
|
-
route="/{orgSlug}/{projectId}/workspaces/{workspaceId}/experiences?action=publish"
|
|
69
|
-
alt="The publish modal with a change preview of added experiences, steps, and conditions"
|
|
70
|
-
selector='[role="dialog"]'
|
|
71
|
-
wait='[role="dialog"]'
|
|
72
|
-
hide={['[data-testid="publish-diff-replaces-version"]']}
|
|
73
|
-
renderWidth={720}
|
|
74
|
-
renderHeight={579}
|
|
75
|
-
/>
|
|
76
|
-
|
|
77
|
-
The preview puts the changes into groups by entity type: experiences, feature flags,
|
|
78
|
-
steps, fields, actions, and conditions. Each row shows whether the entity was
|
|
79
|
-
**added**, **removed**, or **modified**. For a modified entity, expand the row to see
|
|
80
|
-
which properties changed.
|
|
81
|
-
|
|
82
|
-
Some changes break other records. An example is a field that you remove while other
|
|
83
|
-
steps still point at it. The change preview shows a banner above the diff for these
|
|
84
|
-
entries, so that you can look at them again before you publish.
|
|
85
|
-
|
|
86
|
-
The first publish of a workspace has no earlier snapshot to compare against. The
|
|
87
|
-
publish modal shows the contents of the workspace as the first publish, with no diff.
|
|
88
|
-
|
|
89
|
-
## Unpublished changes
|
|
90
|
-
|
|
91
|
-
The workspace records whether anything changed since the last publish. If you create
|
|
92
|
-
or update an experience, a feature flag, or an entity after the last publish, the
|
|
93
|
-
toolbar shows a warning badge.
|
|
94
|
-
|
|
95
|
-
## Workspace settings
|
|
96
|
-
|
|
97
|
-
The workspace settings page (**Settings** in the workspace navigation) covers how to
|
|
98
|
-
rename, archive, and delete a workspace.
|
|
99
|
-
|
|
100
|
-
### Rename
|
|
101
|
-
|
|
102
|
-
Change the workspace name in the **Name** field and click **Save**. A name is unique
|
|
103
|
-
inside a project. The dashboard rejects a duplicate name with a validation error.
|
|
104
|
-
|
|
105
|
-
### Archive
|
|
106
|
-
|
|
107
|
-
To archive a draft workspace is to move it out of the default workspaces list, but
|
|
108
|
-
not to delete it. Use it for a draft that you want to put to one side and keep.
|
|
109
|
-
|
|
110
|
-
1. Open the workspace settings page.
|
|
111
|
-
2. Click **Archive** in the page header.
|
|
112
|
-
3. Confirm in the modal.
|
|
113
|
-
|
|
114
|
-
You cannot archive a live workspace directly. Make a different workspace live first,
|
|
115
|
-
then archive the earlier one.
|
|
116
|
-
|
|
117
|
-
### Unarchive
|
|
118
|
-
|
|
119
|
-
You can unarchive a workspace from the same page to make it a draft again. The
|
|
120
|
-
settings page finds the archived state and changes the toolbar button to
|
|
121
|
-
**Unarchive**.
|
|
122
|
-
|
|
123
|
-
### Delete
|
|
124
|
-
|
|
125
|
-
To delete a workspace is to remove it and its entities permanently. This action is
|
|
126
|
-
destructive and you cannot reverse it. Archive the workspace instead when you are not
|
|
127
|
-
certain.
|
|
128
|
-
|
|
129
|
-
1. Open the workspace settings page.
|
|
130
|
-
2. In the **Danger zone** card at the bottom, click **Delete**.
|
|
131
|
-
3. Confirm in the modal.
|
|
132
|
-
|
|
133
|
-
You cannot delete a live workspace. Publish or archive a different workspace first.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const e=require("./rules-logic-CGZIYgAI.cjs");require("./logger-CSTvAyyB.cjs");const t=require("./dom-CDrHc_j9.cjs");let n=require("effector"),r=require("@withease/factories");function i(e){return e.type===`condition`}function a(e){return e.type===`step`}function o(e){return e.type===`experience`}function s(e){return e.type===`origin`}function c(e){return e.type===`action`}var l=`conditions.`,u=(0,n.createDomain)(`condition-results`);function d(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function f(e){if(e===void 0)return null;if(Array.isArray(e))return e.map(e=>f(e));if(d(e)){let t=Object.keys(e).sort((e,t)=>e.localeCompare(t)),n={};for(let r of t)n[r]=f(e[r]);return n}return e}function p(e){return JSON.stringify(f(e))}var m=(0,r.createFactory)(()=>{let e=u.store({}),t=(0,n.createApi)(e,{set(e,t){return e[t.hash]===t.result?e:{...e,[t.hash]:t.result}},seed(e,t){return Object.keys(t).every(n=>e[n]===t[n])?e:{...e,...t}},clear(){return{}}});function r(e){t.set(e)}function i(e){t.seed(e)}function a(){t.clear()}function o(t){return e.getState()[t]}return{store:e,set:r,seed:i,peek:o,reset:a}});function h(){return(0,r.invoke)(m)}async function g(t,n,r){return n==null?!0:typeof n==`boolean`?n:e.n(n)?await e.t(t,n,r)===!0:!0}function _(e){if(typeof e==`string`)return e;if(Array.isArray(e)&&typeof e[0]==`string`)return e[0]}function v(e){if(Array.isArray(e))return e.some(v);if(d(e)){let t=_(e.var);return t!==void 0&&(t===`actions`||t.startsWith(`actions.`))?!0:Object.values(e).some(v)}return!1}function y(e){if(Array.isArray(e))return e.flatMap(y);if(d(e)){let t=_(e.var);return[...t!==void 0&&t.startsWith(l)?[t.slice(11)]:[],...Object.values(e).flatMap(y)]}return[]}function b(e,t,n=new Set){if(v(e))return!0;for(let r of y(e)){if(n.has(r))continue;n.add(r);let e=t[r];if(e!==void 0&&b(e.logic,t,n))return!0}return!1}async function x(e,t,n){let r={};for(let t of e.conditions.listStore.getState())r[t.key]=t;let i=b(t,r),a=p(t);if(!i){let t=e.conditionResults.peek(a);if(t!==void 0)return t}let o=await g(e,t,n?.context);return i||e.conditionResults.set({hash:a,result:o}),o}async function S(e,t,n){let r=n?.context,i=[n?.precondition,n?.condition,t.condition];for(let t of i)if(!await x(e,t,{context:r}))return!1;return!0}var C=(e,t,n,r,i=new Set)=>i.has(n.id)?[]:(i.add(n.id),a(n)&&!r?[n]:t.filter(e=>e.sourceNodeId===n.id).flatMap(n=>{let r=e.find(e=>e.id===n.destinationNodeId);return r?C(e,t,r,!1,i):[]})),w=(e,t,n)=>C(e,t,n,!0,new Set),T=(e,t,n,r,i=new Set)=>{if(i.has(n.id))return[-1,-1];i.add(n.id);let a=t.filter(e=>e.sourceNodeId===n.id);if(a.length===0)return[0,0];let o=1/0,s=-1/0;for(let n of a){let r=e.find(e=>e.id===n.destinationNodeId);if(!r)continue;let[a,c]=T(e,t,r,!1,new Set(i));a!==-1&&(o=Math.min(o,a+1),s=Math.max(s,c+1))}return o===1/0?[-1,-1]:[o,s]},E=(e,t,n)=>T(e,t,n,!0,new Set),D=(e,t,n,r=new Set)=>{if(r.has(n.id))return[-1,-1];if(r.add(n.id),n.type===`origin`)return[0,0];let i=t.filter(e=>e.destinationNodeId===n.id);if(i.length===0)return[-1,-1];let a=1/0,o=-1/0;for(let n of i){let i=e.find(e=>e.id===n.sourceNodeId);if(!i)continue;let[s,c]=D(e,t,i,new Set(r));s!==-1&&(a=Math.min(a,s+1),o=Math.max(o,c+1))}return a===1/0?[-1,-1]:[a,o]},ee=(e,t,n)=>D(e,t,n,new Set),O=e=>e.find(e=>e.type===`origin`)||null,k=(e,t,n)=>{if(!e)return O(t);let r=n.find(t=>t.sourceNodeId===e.id);return r&&t.find(e=>e.id===r.destinationNodeId)||null};async function A(e,t,n,r){let i=e?`true`:`false`,a=r.find(e=>e.sourceHandle===i&&e.sourceNodeId===t);return n.find(e=>e.id===a?.destinationNodeId)}function j(e,t,n,r){let i=r.filter(e=>e.sourceNodeId===t),a=e?`true`:`false`,o=i.find(e=>e.sourceHandle===a)??i.find(e=>e.sourceHandle==null);return n.find(e=>e.id===o?.destinationNodeId)}var M=(0,n.createDomain)(`experience-instance`),N=(0,r.createFactory)(({client:r,experience:l,target:u,options:d})=>{let f=(0,n.createEvent)(),p=(0,n.createEvent)(),m=(0,n.createEvent)(),h=(0,n.createEvent)(),g=(0,n.createEvent)(),_=(0,n.createEvent)(),v=(0,n.createEvent)(),y=l.componentStore,b=M.store(`transitioning`),x=r.history.entriesStore.map(e=>e.filter(e=>e.experienceId===l.id)),S=x.map(e=>e.filter(e=>a(e.node))),C=x.map(e=>e.at(-1)?.node||null),T=M.store(null);(0,n.sample)({clock:[C,r.steps.listStore,_],source:{steps:r.steps.listStore,node:C},filter:({node:e})=>e!==null&&a(e),fn:({steps:e,node:t})=>t&&a(t)?e.find(e=>e.id===t.stepId)??null:null,target:T});let D=(0,n.combine)(r.steps.listStore,S,(e,t)=>{let n=t.at(-2);if(!n||!a(n.node))return null;let r=n.node;return e.find(e=>e.id===r.stepId)||null}),N=(0,n.combine)(l.treeStore,C,({nodes:e,edges:t},n)=>n?w(e,t,n):[]),P=(0,n.combine)(l.treeStore,C,({nodes:e,edges:t},n)=>n?ee(e,t,n):[-1,-1]),F=(0,n.combine)(l.treeStore,C,({nodes:e,edges:t},n)=>n?E(e,t,n):[-1,-1]),I=M.store(!1),L=(0,n.createApi)(I,{open:()=>!0,close:()=>!1,toggle:e=>!e,set:(e,t)=>t}),R=(0,n.createEffect)(async()=>{r.history.back({experienceId:l.id})}),z=(0,n.attach)({source:l.treeStore,effect:async(e,t)=>{let n=e.nodes.find(e=>a(e)&&e.stepId===t);n&&r.history.push({experienceId:l.id,node:n})}}),B=(0,n.attach)({source:l.treeStore,effect:async(e,t)=>{let n=e.steps.find(e=>e.key===t);if(!n)return;let i=e.nodes.find(e=>a(e)&&e.stepId===n.id);i&&r.history.push({experienceId:l.id,node:i})}}),V=(0,n.attach)({source:C,effect:e=>{}}),H=(0,n.attach)({source:l.treeStore,effect:async({nodes:e})=>O(e)}),U=(0,n.attach)({source:l.treeStore,effect:async({nodes:e,edges:t},n)=>{if(s(n))return k(n,e,t)}}),W=(0,n.attach)({source:l.treeStore,effect:async({nodes:t,edges:n,conditions:a},o)=>{if(!i(o))return;let s=a.find(e=>e.id===o.conditionId)?.logic;return s?A(!!await e.t(r,s),o.id,t,n):void 0}}),G=(0,n.attach)({source:{tree:l.treeStore,actions:r.actions.listStore,snapshot:r.stateSnapshotStore},effect:async({tree:e,actions:t,snapshot:n},r)=>{let{nodes:i,edges:a}=e;if(!c(r))return;let o=r.actionKey;if(!o){`${r.id}`;return}let s=t.find(e=>e.key===o)?.action;if(typeof s!=`function`)return`${o}`,j(!1,r.id,i,a)??null;let l=!0;try{`${o}`,await s({...n,args:[]},{experience:Z})}catch{`${o}`,l=!1}let u=j(l,r.id,i,a);if(!u){let e=a.some(e=>e.sourceNodeId===r.id)?`no edge for its outcome`:`no outgoing edge`;return`${r.id}${e}`,null}return`${o}${u.id}`,u}}),K=(0,n.createEffect)(e=>{o(e)&&r.experiences.launch({key:e.experienceKey})}),q=(0,n.attach)({source:[C,l.treeStore],effect:async([e,{nodes:t,edges:n}])=>k(e,t,n)}),J=(0,n.attach)({source:[C,l.treeStore],effect:async([e,{nodes:t,edges:n}])=>k(e,t,n)}),te=(0,n.createEffect)(e=>{r.history.push({experienceId:l.id,node:e})}),Y=(0,n.attach)({source:l.configStore,effect:async({initializeOpenLogic:t})=>d?.initialiseOpen===void 0?e.n(t)?!!await e.t(r,t):t??!1:d.initialiseOpen}),X=(0,n.combine)(y,r.frameworks.listStore,(e,t)=>{if(!e)return null;let n=t.find(t=>t.name===e.component.frameworkName);return n?{component:e,framework:n}:null},{skipVoid:!1}),Z,ne=(0,n.attach)({source:X,effect:e=>{if(!e)return;if(!u){`${l.id}`;return}let n=t.n(u);try{e.framework.render(n,e.component.component,r,Z)}catch{}}});Z=Object.freeze({id:Math.random().toString(36).substring(7),experienceKey:l.key,experienceId:l.id,experienceName:l.name,configStore:l.configStore,target:u,componentStore:y,componentAndFrameworkStore:X,stateStore:b,isOpenStore:I,open:L.open,close:L.close,toggleOpen:L.toggle,setOpen:L.set,treeStore:l.treeStore,currentNodeStore:C,currentStepStore:T,previousStepStore:D,nextReachableStepNodesStore:N,stepsToOriginStore:P,stepsToLeafStore:F,goToNextStep:p,goToPreviousStep:m,goToStepById:h,goToStepByKey:g,stepsHistoryStore:S,mountFx:ne});let Q=(0,n.createEvent)(),$=(0,n.createEvent)();return(0,n.sample)({clock:C,target:Q}),(0,n.sample)({clock:Q,filter:e=>e===null,target:H}),(0,n.sample)({clock:Q,filter:e=>e!==null,target:$}),(0,n.split)({source:$,match:e=>i(e)?`condition`:a(e)?`step`:o(e)?`launchExperience`:s(e)?`origin`:c(e)?`action`:`other`,cases:{origin:U,condition:W,step:V,launchExperience:K,action:G,__:(0,n.createEvent)()}}),(0,n.sample)({clock:[W.doneData,U.doneData,H.doneData,J.doneData,q.doneData,G.doneData],filter:Boolean,target:te}),(0,n.sample)({clock:p,target:J}),(0,n.sample)({clock:p,source:T,filter:Boolean,target:r.eventBus.prepend(e=>({type:`step_submit`,step:e,experience:Z}))}),(0,n.sample)({clock:J.done,source:T,filter:Boolean,target:r.eventBus.prepend(e=>({type:`step_submit_success`,step:e,experience:Z}))}),(0,n.sample)({clock:J.fail,source:T,filter:Boolean,target:r.eventBus.prepend(e=>({type:`step_submit_error`,step:e,experience:Z}))}),(0,n.sample)({clock:m,target:R}),(0,n.sample)({clock:h,target:z}),(0,n.sample)({clock:g,target:B}),(0,n.sample)({source:(0,n.combine)([W.pending,U.pending,H.pending,J.pending,q.pending,G.pending]),fn:e=>e.some(Boolean)?`transitioning`:`ready`,target:b}),(0,n.sample)({clock:V.doneData,source:T,filter:Boolean,target:r.eventBus.prepend(e=>({type:`step_enter`,step:e,experience:Z}))}),(0,n.sample)({clock:v,target:Y}),(0,n.sample)({source:Y.doneData,fn:Boolean,target:I}),(0,n.sample)({source:C,clock:f,filter:e=>e?s(e):!0,target:q}),(0,n.sample)({source:I,filter:Boolean,target:f}),(0,n.sample)({source:I,filter:Boolean,target:r.eventBus.prepend(()=>({type:`experience_open`,experience:Z}))}),(0,n.sample)({source:I,filter:e=>!e,target:r.eventBus.prepend(()=>({type:`experience_close`,experience:Z}))}),(0,n.sample)({clock:_,target:[v]}),_(),Z});function P(e){return(0,r.invoke)(N,e)}var F=(0,r.createFactory)(({client:e})=>{let r=M.store({}),i=(0,n.createEvent)(),a=(0,n.createEvent)(),o=(0,n.createEvent)(),s=(0,n.createApi)(r,{register(e,t){let n=[...e[t.experienceId]??[]];return n.push(t),{...e,[t.experienceId]:n}},unregister(e,t){let n=t.experienceId,r=e[n]?.filter(e=>e!==t);return{...e,[n]:r??[]}}}),c=(0,n.createEffect)(({experience:t,target:n,options:r})=>P({client:e,experience:t,target:n,options:r})),l=(0,n.createEffect)(e=>{s.register(e)}),u=(0,n.createEffect)(e=>{e.target&&t.o(e.target,()=>{o(e)})}),d=(0,n.createEffect)(e=>{s.unregister(e)}),f=(0,n.createEffect)(async e=>{await e.mountFx()});(0,n.sample)({clock:i,target:c}),(0,n.sample)({clock:o,target:d}),(0,n.sample)({clock:c.doneData,target:[l,u,a]}),(0,n.sample)({clock:c.doneData,target:e.eventBus.prepend(e=>({type:`experience_initialize`,experience:e}))}),(0,n.sample)({clock:a,target:f});function p(e,t,n){i({experience:e,target:t,options:n})}let m=r.map(e=>Object.values(e).flat());function h(e){return m.map(t=>t.filter(t=>t.experienceKey===e),{skipVoid:!1})}function g(e){return r.map(t=>t[e]||[],{skipVoid:!1})}return{spawn:p,getByExperienceKey:h,getByExperienceId:g,listStore:m}});function I(e){return(0,r.invoke)(F,e)}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return I}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return a}});
|