@webiny/app-website-builder 6.6.0-alpha.0 → 6.6.0-alpha.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.
Files changed (234) hide show
  1. package/BaseEditor/commandHandlers/CloneElement.d.ts +1 -0
  2. package/BaseEditor/commandHandlers/CloneElement.js +17 -0
  3. package/BaseEditor/commandHandlers/CloneElement.js.map +1 -0
  4. package/BaseEditor/commandHandlers/index.js +2 -1
  5. package/BaseEditor/commandHandlers/index.js.map +1 -1
  6. package/BaseEditor/commands.d.ts +3 -0
  7. package/BaseEditor/commands.js +2 -0
  8. package/BaseEditor/commands.js.map +1 -1
  9. package/BaseEditor/defaultConfig/Content/AddressBar/usePreviewLink.js +4 -1
  10. package/BaseEditor/defaultConfig/Content/AddressBar/usePreviewLink.js.map +1 -1
  11. package/BaseEditor/defaultConfig/Content/Preview/DropZoneManager.js.map +1 -1
  12. package/BaseEditor/defaultConfig/Content/Preview/Iframe.d.ts +2 -2
  13. package/BaseEditor/defaultConfig/Content/Preview/Overlays/ElementOverlays.d.ts +2 -2
  14. package/BaseEditor/defaultConfig/DefaultEditorConfig.js +9 -0
  15. package/BaseEditor/defaultConfig/DefaultEditorConfig.js.map +1 -1
  16. package/BaseEditor/defaultConfig/DocumentStateEditor/DocumentStateEditor.d.ts +2 -2
  17. package/BaseEditor/defaultConfig/ElementInputRenderers.js +4 -0
  18. package/BaseEditor/defaultConfig/ElementInputRenderers.js.map +1 -1
  19. package/BaseEditor/defaultConfig/Sidebar/ElementActions/CloneElementAction.d.ts +2 -0
  20. package/BaseEditor/defaultConfig/Sidebar/ElementActions/CloneElementAction.js +25 -0
  21. package/BaseEditor/defaultConfig/Sidebar/ElementActions/CloneElementAction.js.map +1 -0
  22. package/BaseEditor/defaultConfig/Sidebar/ElementActions/DeleteElementAction.d.ts +2 -0
  23. package/BaseEditor/defaultConfig/Sidebar/ElementActions/DeleteElementAction.js +26 -0
  24. package/BaseEditor/defaultConfig/Sidebar/ElementActions/DeleteElementAction.js.map +1 -0
  25. package/BaseEditor/defaultConfig/Sidebar/ElementPreview.js +12 -2
  26. package/BaseEditor/defaultConfig/Sidebar/ElementPreview.js.map +1 -1
  27. package/BaseEditor/defaultConfig/Sidebar/ElementSettings/ElementInputs.js +1 -6
  28. package/BaseEditor/defaultConfig/Sidebar/ElementSettings/ElementInputs.js.map +1 -1
  29. package/BaseEditor/defaultConfig/Sidebar/ElementSettings/ElementSettings.js +11 -2
  30. package/BaseEditor/defaultConfig/Sidebar/ElementSettings/ElementSettings.js.map +1 -1
  31. package/BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/Background/BackgroundColor.d.ts +6 -2
  32. package/BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/Background/BackgroundImage.d.ts +6 -2
  33. package/BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/Background/BackgroundPosition.d.ts +6 -2
  34. package/BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/Background/BackgroundScaling.d.ts +6 -2
  35. package/BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/Border/BorderColor.d.ts +2 -2
  36. package/BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/Border/BorderRadius.d.ts +2 -2
  37. package/BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/Border/BorderStyle.d.ts +2 -2
  38. package/BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/Border/BorderWidth.d.ts +2 -2
  39. package/BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/Layout/Alignment.d.ts +6 -2
  40. package/BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/Layout/LengthWithUnitInput.d.ts +2 -2
  41. package/BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/MarginPadding/Margin.d.ts +2 -2
  42. package/BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/MarginPadding/Padding.d.ts +2 -2
  43. package/BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/Visibility/Visibility.d.ts +2 -2
  44. package/BaseEditor/defaultConfig/Sidebar/StyleSettings/StyleProperties.js +7 -7
  45. package/BaseEditor/defaultConfig/Sidebar/StyleSettings/StyleProperties.js.map +1 -1
  46. package/BaseEditor/defaultConfig/Toolbar/Navigator/Navigator.d.ts +2 -2
  47. package/DocumentEditor/DocumentEditor.d.ts +14 -5
  48. package/DocumentEditor/DocumentEditor.js +10 -6
  49. package/DocumentEditor/DocumentEditor.js.map +1 -1
  50. package/DocumentEditor/StateInspector.d.ts +4 -2
  51. package/Extension.js +7 -1
  52. package/Extension.js.map +1 -1
  53. package/ecommerce/components/ResourcePage.d.ts +6 -2
  54. package/ecommerce/components/ResourcesList.d.ts +4 -4
  55. package/ecommerce/components/ResourcesPicker.d.ts +9 -4
  56. package/editorSdk/CommandBus.js.map +1 -1
  57. package/editorSdk/utils/$cloneElement.d.ts +2 -0
  58. package/editorSdk/utils/$cloneElement.js +112 -0
  59. package/editorSdk/utils/$cloneElement.js.map +1 -0
  60. package/editorSdk/utils/index.d.ts +1 -0
  61. package/editorSdk/utils/index.js +1 -0
  62. package/features/experiments/ExperimentsGateway.d.ts +30 -0
  63. package/features/experiments/ExperimentsGateway.js +326 -0
  64. package/features/experiments/ExperimentsGateway.js.map +1 -0
  65. package/features/experiments/abstractions.d.ts +25 -0
  66. package/features/experiments/abstractions.js +5 -0
  67. package/features/experiments/abstractions.js.map +1 -0
  68. package/features/experiments/feature.d.ts +3 -0
  69. package/features/experiments/feature.js +17 -0
  70. package/features/experiments/feature.js.map +1 -0
  71. package/features/experiments/index.d.ts +3 -0
  72. package/features/experiments/index.js +2 -0
  73. package/features/experiments/types.d.ts +61 -0
  74. package/features/experiments/types.js +0 -0
  75. package/inputRenderers/ColorPickerInput.d.ts +3 -0
  76. package/inputRenderers/ColorPickerInput.js +29 -0
  77. package/inputRenderers/ColorPickerInput.js.map +1 -0
  78. package/inputRenderers/FileInput.js +93 -8
  79. package/inputRenderers/FileInput.js.map +1 -1
  80. package/inputRenderers/LexicalInput/LexicalEditor.js +15 -8
  81. package/inputRenderers/LexicalInput/LexicalEditor.js.map +1 -1
  82. package/inputRenderers/LexicalInput/TypographyDropDown.js +3 -2
  83. package/inputRenderers/LexicalInput/TypographyDropDown.js.map +1 -1
  84. package/inputRenderers/LexicalInput/wbStaticToolbar.css +72 -103
  85. package/modules/AbTesting.d.ts +2 -0
  86. package/modules/AbTesting.js +19 -0
  87. package/modules/AbTesting.js.map +1 -0
  88. package/package.json +28 -28
  89. package/presentation/components/LanguageCodeTag.js +5 -4
  90. package/presentation/components/LanguageCodeTag.js.map +1 -1
  91. package/presentation/experiments/ExperimentForm/ExperimentFormPresenter.d.ts +30 -0
  92. package/presentation/experiments/ExperimentForm/ExperimentFormPresenter.js +202 -0
  93. package/presentation/experiments/ExperimentForm/ExperimentFormPresenter.js.map +1 -0
  94. package/presentation/experiments/ExperimentForm/abstractions/ExperimentFormPresenter.d.ts +65 -0
  95. package/presentation/experiments/ExperimentForm/abstractions/ExperimentFormPresenter.js +5 -0
  96. package/presentation/experiments/ExperimentForm/abstractions/ExperimentFormPresenter.js.map +1 -0
  97. package/presentation/experiments/ExperimentForm/components/ExperimentFormView.d.ts +12 -0
  98. package/presentation/experiments/ExperimentForm/components/ExperimentFormView.js +149 -0
  99. package/presentation/experiments/ExperimentForm/components/ExperimentFormView.js.map +1 -0
  100. package/presentation/experiments/ExperimentForm/components/VariantSplitRow.d.ts +17 -0
  101. package/presentation/experiments/ExperimentForm/components/VariantSplitRow.js +122 -0
  102. package/presentation/experiments/ExperimentForm/components/VariantSplitRow.js.map +1 -0
  103. package/presentation/experiments/ExperimentForm/feature.d.ts +3 -0
  104. package/presentation/experiments/ExperimentForm/feature.js +17 -0
  105. package/presentation/experiments/ExperimentForm/feature.js.map +1 -0
  106. package/presentation/experiments/ExperimentForm/index.d.ts +3 -0
  107. package/presentation/experiments/ExperimentForm/index.js +3 -0
  108. package/presentation/experiments/ExperimentsEditor/ExperimentsEditorDataSource.d.ts +18 -0
  109. package/presentation/experiments/ExperimentsEditor/ExperimentsEditorDataSource.js +25 -0
  110. package/presentation/experiments/ExperimentsEditor/ExperimentsEditorDataSource.js.map +1 -0
  111. package/presentation/experiments/ExperimentsEditor/ExperimentsEditorPresenter.d.ts +67 -0
  112. package/presentation/experiments/ExperimentsEditor/ExperimentsEditorPresenter.js +224 -0
  113. package/presentation/experiments/ExperimentsEditor/ExperimentsEditorPresenter.js.map +1 -0
  114. package/presentation/experiments/ExperimentsEditor/abstractions/ExperimentsEditorDataSource.d.ts +10 -0
  115. package/presentation/experiments/ExperimentsEditor/abstractions/ExperimentsEditorDataSource.js +5 -0
  116. package/presentation/experiments/ExperimentsEditor/abstractions/ExperimentsEditorDataSource.js.map +1 -0
  117. package/presentation/experiments/ExperimentsEditor/abstractions/ExperimentsEditorPresenter.d.ts +58 -0
  118. package/presentation/experiments/ExperimentsEditor/abstractions/ExperimentsEditorPresenter.js +5 -0
  119. package/presentation/experiments/ExperimentsEditor/abstractions/ExperimentsEditorPresenter.js.map +1 -0
  120. package/presentation/experiments/ExperimentsEditor/components/ExperimentIndicator.d.ts +15 -0
  121. package/presentation/experiments/ExperimentsEditor/components/ExperimentIndicator.js +110 -0
  122. package/presentation/experiments/ExperimentsEditor/components/ExperimentIndicator.js.map +1 -0
  123. package/presentation/experiments/ExperimentsEditor/components/ExperimentPreviewToolbar.d.ts +9 -0
  124. package/presentation/experiments/ExperimentsEditor/components/ExperimentPreviewToolbar.js +178 -0
  125. package/presentation/experiments/ExperimentsEditor/components/ExperimentPreviewToolbar.js.map +1 -0
  126. package/presentation/experiments/ExperimentsEditor/components/ExperimentsButton.d.ts +11 -0
  127. package/presentation/experiments/ExperimentsEditor/components/ExperimentsButton.js +51 -0
  128. package/presentation/experiments/ExperimentsEditor/components/ExperimentsButton.js.map +1 -0
  129. package/presentation/experiments/ExperimentsEditor/components/ExperimentsSwitcher.d.ts +14 -0
  130. package/presentation/experiments/ExperimentsEditor/components/ExperimentsSwitcher.js +147 -0
  131. package/presentation/experiments/ExperimentsEditor/components/ExperimentsSwitcher.js.map +1 -0
  132. package/presentation/experiments/ExperimentsEditor/feature.d.ts +3 -0
  133. package/presentation/experiments/ExperimentsEditor/feature.js +21 -0
  134. package/presentation/experiments/ExperimentsEditor/feature.js.map +1 -0
  135. package/presentation/experiments/ExperimentsEditor/index.d.ts +4 -0
  136. package/presentation/experiments/ExperimentsEditor/index.js +3 -0
  137. package/presentation/experiments/ExperimentsManager/ExperimentsManagerPresenter.d.ts +39 -0
  138. package/presentation/experiments/ExperimentsManager/ExperimentsManagerPresenter.js +219 -0
  139. package/presentation/experiments/ExperimentsManager/ExperimentsManagerPresenter.js.map +1 -0
  140. package/presentation/experiments/ExperimentsManager/abstractions/ExperimentsManagerPresenter.d.ts +52 -0
  141. package/presentation/experiments/ExperimentsManager/abstractions/ExperimentsManagerPresenter.js +5 -0
  142. package/presentation/experiments/ExperimentsManager/abstractions/ExperimentsManagerPresenter.js.map +1 -0
  143. package/presentation/experiments/ExperimentsManager/components/ExperimentCard.d.ts +10 -0
  144. package/presentation/experiments/ExperimentsManager/components/ExperimentCard.js +296 -0
  145. package/presentation/experiments/ExperimentsManager/components/ExperimentCard.js.map +1 -0
  146. package/presentation/experiments/ExperimentsManager/components/ExperimentsDrawerView.d.ts +2 -0
  147. package/presentation/experiments/ExperimentsManager/components/ExperimentsDrawerView.js +92 -0
  148. package/presentation/experiments/ExperimentsManager/components/ExperimentsDrawerView.js.map +1 -0
  149. package/presentation/experiments/ExperimentsManager/components/ExperimentsEmptyState.d.ts +6 -0
  150. package/presentation/experiments/ExperimentsManager/components/ExperimentsEmptyState.js +103 -0
  151. package/presentation/experiments/ExperimentsManager/components/ExperimentsEmptyState.js.map +1 -0
  152. package/presentation/experiments/ExperimentsManager/components/ExperimentsListView.d.ts +9 -0
  153. package/presentation/experiments/ExperimentsManager/components/ExperimentsListView.js +58 -0
  154. package/presentation/experiments/ExperimentsManager/components/ExperimentsListView.js.map +1 -0
  155. package/presentation/experiments/ExperimentsManager/feature.d.ts +3 -0
  156. package/presentation/experiments/ExperimentsManager/feature.js +17 -0
  157. package/presentation/experiments/ExperimentsManager/feature.js.map +1 -0
  158. package/presentation/experiments/ExperimentsManager/index.d.ts +4 -0
  159. package/presentation/experiments/ExperimentsManager/index.js +3 -0
  160. package/presentation/experiments/VariantPageEditorConfig.d.ts +7 -0
  161. package/presentation/experiments/VariantPageEditorConfig.js +26 -0
  162. package/presentation/experiments/VariantPageEditorConfig.js.map +1 -0
  163. package/presentation/experiments/config/ExperimentsEditorConfig.d.ts +8 -0
  164. package/presentation/experiments/config/ExperimentsEditorConfig.js +21 -0
  165. package/presentation/experiments/config/ExperimentsEditorConfig.js.map +1 -0
  166. package/presentation/experiments/config/VariantAutoSave.d.ts +5 -0
  167. package/presentation/experiments/config/VariantAutoSave.js +41 -0
  168. package/presentation/experiments/config/VariantAutoSave.js.map +1 -0
  169. package/presentation/experiments/shared/variantColors.d.ts +11 -0
  170. package/presentation/experiments/shared/variantColors.js +13 -0
  171. package/presentation/experiments/shared/variantColors.js.map +1 -0
  172. package/presentation/experiments/shared/variantDocument.d.ts +16 -0
  173. package/presentation/experiments/shared/variantDocument.js +31 -0
  174. package/presentation/experiments/shared/variantDocument.js.map +1 -0
  175. package/presentation/navigation/Extension.js +9 -5
  176. package/presentation/navigation/Extension.js.map +1 -1
  177. package/presentation/navigation/NextjsConfig/NextjsConfigDialog.d.ts +2 -2
  178. package/presentation/navigation/StarterKitConfigDialog.js +1 -1
  179. package/presentation/navigation/StarterKitConfigDialog.js.map +1 -1
  180. package/presentation/pages/CreatePage/CreatePageDialog.d.ts +2 -2
  181. package/presentation/pages/CreatePage/CreatePagePresenter.js +1 -1
  182. package/presentation/pages/CreatePage/CreatePagePresenter.js.map +1 -1
  183. package/presentation/pages/CreatePage/WithLanguageSelector.js +3 -3
  184. package/presentation/pages/CreatePage/WithLanguageSelector.js.map +1 -1
  185. package/presentation/pages/CreatePage/feature.js +3 -3
  186. package/presentation/pages/CreatePage/feature.js.map +1 -1
  187. package/presentation/pages/PageEditor/PageEditor.experiments.d.ts +2 -0
  188. package/presentation/pages/PageEditor/PageEditor.experiments.js +54 -0
  189. package/presentation/pages/PageEditor/PageEditor.experiments.js.map +1 -0
  190. package/presentation/pages/PageEditor/PageEditorSurface.d.ts +15 -0
  191. package/presentation/pages/PageEditor/PageEditorSurface.js +63 -0
  192. package/presentation/pages/PageEditor/PageEditorSurface.js.map +1 -0
  193. package/presentation/pages/PageEditor/TopBar/PageSettingsDrawer.d.ts +2 -2
  194. package/presentation/pages/PageEditor/pageDocument.d.ts +4 -0
  195. package/presentation/pages/PageEditor/pageDocument.js +15 -0
  196. package/presentation/pages/PageEditor/pageDocument.js.map +1 -0
  197. package/presentation/pages/PageList/components/BulkActions/BulkActionDelete.d.ts +2 -2
  198. package/presentation/pages/PageList/components/BulkActions/BulkActionDuplicate.d.ts +2 -2
  199. package/presentation/pages/PageList/components/BulkActions/BulkActionMovePage.d.ts +2 -2
  200. package/presentation/pages/PageList/components/BulkActions/BulkActionPublish.d.ts +2 -2
  201. package/presentation/pages/PageList/components/BulkActions/BulkActionUnpublish.d.ts +2 -2
  202. package/presentation/pages/PageList/components/DocumentList.d.ts +2 -2
  203. package/presentation/pages/PageList/components/PagesList.js +2 -1
  204. package/presentation/pages/PageList/components/PagesList.js.map +1 -1
  205. package/presentation/pages/PageList/components/Table/Table.d.ts +2 -2
  206. package/presentation/pages/PageList/components/WbPagesBreadcrumbs.d.ts +9 -0
  207. package/presentation/pages/PageList/components/WbPagesBreadcrumbs.js +40 -0
  208. package/presentation/pages/PageList/components/WbPagesBreadcrumbs.js.map +1 -0
  209. package/presentation/pages/TranslatePage/TranslatePageConfig.d.ts +1 -1
  210. package/presentation/pages/TranslatePage/TranslatePageConfig.js +6 -2
  211. package/presentation/pages/TranslatePage/TranslatePageConfig.js.map +1 -1
  212. package/presentation/pages/TranslatePage/TranslatePageDialog.js +22 -10
  213. package/presentation/pages/TranslatePage/TranslatePageDialog.js.map +1 -1
  214. package/presentation/pages/TranslatePage/translatePageSchema.d.ts +1 -1
  215. package/presentation/pages/TranslatePage/translatePageSchema.js +1 -1
  216. package/presentation/pages/TranslatePage/translatePageSchema.js.map +1 -1
  217. package/presentation/pages/TrashBin/WbTrashBin.d.ts +2 -2
  218. package/presentation/redirects/RedirectList/components/BulkActionDelete.d.ts +2 -2
  219. package/presentation/redirects/RedirectList/components/BulkActionMove.d.ts +2 -2
  220. package/presentation/redirects/RedirectList/components/CreateRedirectDialog.d.ts +2 -2
  221. package/presentation/redirects/RedirectList/components/DocumentList.d.ts +2 -2
  222. package/presentation/redirects/RedirectList/components/EditRedirectDialog.d.ts +2 -2
  223. package/presentation/redirects/RedirectList/components/Table/Table.d.ts +2 -2
  224. package/shared/fileManagerItemToValue.d.ts +8 -9
  225. package/shared/fileManagerItemToValue.js +22 -7
  226. package/shared/fileManagerItemToValue.js.map +1 -1
  227. package/inputRenderers/LexicalInput/icons/list-ol.js +0 -20
  228. package/inputRenderers/LexicalInput/icons/list-ol.js.map +0 -1
  229. package/inputRenderers/LexicalInput/icons/list-ol.svg +0 -1
  230. package/inputRenderers/LexicalInput/icons/list-ul.js +0 -18
  231. package/inputRenderers/LexicalInput/icons/list-ul.js.map +0 -1
  232. package/inputRenderers/LexicalInput/icons/list-ul.svg +0 -1
  233. package/static/svg/list-ol.d64946f3.svg +0 -1
  234. package/static/svg/list-ul.1d54da3f.svg +0 -1
@@ -0,0 +1,58 @@
1
+ import type { ExperimentDto, UpdateExperimentInput, VariantContentDto, VariantDto } from "../../../../features/experiments/index.js";
2
+ import type { NewExperimentPayload } from "../../ExperimentForm/abstractions/ExperimentFormPresenter.js";
3
+ /** A single "thing you can edit" within an experiment: the control, or one of its variants. */
4
+ export interface VariantOption {
5
+ id: string | null;
6
+ name: string;
7
+ weight: number;
8
+ isControl: boolean;
9
+ color: string;
10
+ }
11
+ /** A row in the top-bar experiment switcher. */
12
+ export interface SwitcherItem {
13
+ id: string;
14
+ name: string;
15
+ status: "active" | "inactive";
16
+ }
17
+ export interface IExperimentsEditorViewModel {
18
+ baselineRevisionId: string;
19
+ pageEntryId: string;
20
+ experiments: ExperimentDto[];
21
+ selectedExperimentId: string | null;
22
+ selectedExperiment: ExperimentDto | null;
23
+ selectedVariantId: string | null;
24
+ selectedVariant: VariantDto | null;
25
+ variantOptions: VariantOption[];
26
+ currentBucket: VariantOption | null;
27
+ runningExperiment: ExperimentDto | null;
28
+ switcherItems: SwitcherItem[];
29
+ paused: boolean;
30
+ drawerOpen: boolean;
31
+ editTarget: ExperimentDto | null;
32
+ }
33
+ export interface IExperimentsEditorPresenter {
34
+ readonly vm: IExperimentsEditorViewModel;
35
+ init(pageRevisionId: string): void;
36
+ reload(): Promise<void>;
37
+ selectExperiment(id: string | null): void;
38
+ selectVariant(variantId: string | null): void;
39
+ syncReadOnlySelection(isReadOnly: boolean): void;
40
+ openManage(): void;
41
+ editExperiment(experiment: ExperimentDto): void;
42
+ closeDrawer(): void;
43
+ pause(): Promise<void>;
44
+ resume(): Promise<void>;
45
+ activate(experimentId: string): Promise<ExperimentDto>;
46
+ deactivate(experimentId: string): Promise<ExperimentDto>;
47
+ createExperiment(payload: NewExperimentPayload): Promise<ExperimentDto>;
48
+ updateExperiment(id: string, input: UpdateExperimentInput): Promise<ExperimentDto>;
49
+ deleteExperiment(experimentId: string): Promise<boolean>;
50
+ getVariant(id: string): Promise<VariantContentDto | null>;
51
+ saveVariant(revisionId: string, doc: Record<string, any>): Promise<VariantDto>;
52
+ }
53
+ export declare const ExperimentsEditorPresenter: import("@webiny/di").Abstraction<IExperimentsEditorPresenter>;
54
+ export declare namespace ExperimentsEditorPresenter {
55
+ type Interface = IExperimentsEditorPresenter;
56
+ type ViewModel = IExperimentsEditorViewModel;
57
+ type Option = VariantOption;
58
+ }
@@ -0,0 +1,5 @@
1
+ import { createAbstraction } from "@webiny/feature/admin";
2
+ const ExperimentsEditorPresenter = createAbstraction("WebsiteBuilder/ExperimentsEditor/Presenter");
3
+ export { ExperimentsEditorPresenter };
4
+
5
+ //# sourceMappingURL=ExperimentsEditorPresenter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/experiments/ExperimentsEditor/abstractions/ExperimentsEditorPresenter.js","sources":["../../../../../src/presentation/experiments/ExperimentsEditor/abstractions/ExperimentsEditorPresenter.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/admin\";\nimport type {\n ExperimentDto,\n UpdateExperimentInput,\n VariantContentDto,\n VariantDto\n} from \"~/features/experiments/index.js\";\nimport type { NewExperimentPayload } from \"../../ExperimentForm/abstractions/ExperimentFormPresenter.js\";\n\n/** A single \"thing you can edit\" within an experiment: the control, or one of its variants. */\nexport interface VariantOption {\n // `null` identifies the control (the baseline page); otherwise the variant entry id.\n id: string | null;\n name: string;\n weight: number;\n isControl: boolean;\n // Palette colour for the bucket, assigned by index (control neutral, variants cycle).\n color: string;\n}\n\n/** A row in the top-bar experiment switcher. */\nexport interface SwitcherItem {\n id: string;\n name: string;\n status: \"active\" | \"inactive\";\n}\n\nexport interface IExperimentsEditorViewModel {\n // Revision id of the page being edited; the baseline for its experiments.\n baselineRevisionId: string;\n // Entry id of the page being edited (derived from the baseline revision id).\n pageEntryId: string;\n experiments: ExperimentDto[];\n selectedExperimentId: string | null;\n selectedExperiment: ExperimentDto | null;\n // Currently edited bucket: `null` = control, otherwise a variant entry id.\n selectedVariantId: string | null;\n // The variant DTO matching `selectedVariantId` (null when editing the control).\n selectedVariant: VariantDto | null;\n variantOptions: VariantOption[];\n // The bucket currently being previewed/edited (control or the selected variant).\n currentBucket: VariantOption | null;\n // The single running experiment on the page, if any (drives the read-only indicator).\n runningExperiment: ExperimentDto | null;\n // Experiments as switcher rows (id + name + active/inactive status).\n switcherItems: SwitcherItem[];\n // Kill-switch state of the selected experiment.\n paused: boolean;\n // Manage/edit drawer UI state.\n drawerOpen: boolean;\n editTarget: ExperimentDto | null;\n}\n\nexport interface IExperimentsEditorPresenter {\n readonly vm: IExperimentsEditorViewModel;\n init(pageRevisionId: string): void;\n reload(): Promise<void>;\n selectExperiment(id: string | null): void;\n selectVariant(variantId: string | null): void;\n // On a published (read-only) page, keep the running experiment selected so the preview tracks it.\n syncReadOnlySelection(isReadOnly: boolean): void;\n openManage(): void;\n editExperiment(experiment: ExperimentDto): void;\n closeDrawer(): void;\n pause(): Promise<void>;\n resume(): Promise<void>;\n activate(experimentId: string): Promise<ExperimentDto>;\n deactivate(experimentId: string): Promise<ExperimentDto>;\n createExperiment(payload: NewExperimentPayload): Promise<ExperimentDto>;\n updateExperiment(id: string, input: UpdateExperimentInput): Promise<ExperimentDto>;\n deleteExperiment(experimentId: string): Promise<boolean>;\n getVariant(id: string): Promise<VariantContentDto | null>;\n saveVariant(revisionId: string, doc: Record<string, any>): Promise<VariantDto>;\n}\n\nexport const ExperimentsEditorPresenter = createAbstraction<IExperimentsEditorPresenter>(\n \"WebsiteBuilder/ExperimentsEditor/Presenter\"\n);\n\nexport namespace ExperimentsEditorPresenter {\n export type Interface = IExperimentsEditorPresenter;\n export type ViewModel = IExperimentsEditorViewModel;\n export type Option = VariantOption;\n}\n"],"names":["ExperimentsEditorPresenter","createAbstraction"],"mappings":";AA2EO,MAAMA,6BAA6BC,kBACtC"}
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+ import type { ExperimentDto } from "../../../../features/experiments/index.js";
3
+ /**
4
+ * Top-bar indicator shown on a published (read-only) page: names the running experiment, shows
5
+ * whether it's live (Active) or paused (Inactive), and lets the editor toggle the kill-switch.
6
+ */
7
+ export declare const ExperimentIndicator: (({ experiment }: {
8
+ experiment: ExperimentDto;
9
+ }) => React.JSX.Element) & React.NamedExoticComponent<{
10
+ experiment: ExperimentDto;
11
+ }> & {
12
+ readonly type: ({ experiment }: {
13
+ experiment: ExperimentDto;
14
+ }) => React.JSX.Element;
15
+ };
@@ -0,0 +1,110 @@
1
+ import react, { useState } from "react";
2
+ import { observer } from "mobx-react-lite";
3
+ import { useFeature } from "@webiny/app";
4
+ import { ReactComponent } from "@webiny/icons/science.svg";
5
+ import { ReactComponent as pause_svg_ReactComponent } from "@webiny/icons/pause.svg";
6
+ import { ReactComponent as play_arrow_svg_ReactComponent } from "@webiny/icons/play_arrow.svg";
7
+ import { ExperimentsEditorPresenterFeature } from "../feature.js";
8
+ const ExperimentIndicator_ExperimentIndicator = observer(function({ experiment }) {
9
+ const { presenter } = useFeature(ExperimentsEditorPresenterFeature);
10
+ const { paused } = presenter.vm;
11
+ const [busy, setBusy] = useState(false);
12
+ const active = !paused;
13
+ const toggle = async ()=>{
14
+ setBusy(true);
15
+ try {
16
+ await (paused ? presenter.resume() : presenter.pause());
17
+ } finally{
18
+ setBusy(false);
19
+ }
20
+ };
21
+ const toggleStyle = {
22
+ display: "inline-flex",
23
+ alignItems: "center",
24
+ gap: 6,
25
+ borderRadius: 8,
26
+ padding: "6px 12px",
27
+ fontWeight: 600,
28
+ fontSize: 13,
29
+ cursor: busy ? "default" : "pointer",
30
+ opacity: busy ? 0.6 : 1,
31
+ ...active ? {
32
+ border: "1px solid #d5d7db",
33
+ background: "#fff",
34
+ color: "#1f2937"
35
+ } : {
36
+ border: "none",
37
+ background: "#10b981",
38
+ color: "#fff"
39
+ }
40
+ };
41
+ return /*#__PURE__*/ react.createElement("div", {
42
+ style: {
43
+ display: "inline-flex",
44
+ alignItems: "center",
45
+ gap: 12,
46
+ border: "1px solid #e5e7eb",
47
+ borderRadius: 8,
48
+ padding: "4px 4px 4px 12px",
49
+ background: "#fff"
50
+ }
51
+ }, /*#__PURE__*/ react.createElement("span", {
52
+ style: {
53
+ display: "inline-flex",
54
+ alignItems: "center",
55
+ gap: 8,
56
+ minWidth: 0
57
+ }
58
+ }, /*#__PURE__*/ react.createElement(ReactComponent, {
59
+ style: {
60
+ width: 18,
61
+ height: 18,
62
+ color: "#e2572a",
63
+ fill: "currentColor"
64
+ }
65
+ }), /*#__PURE__*/ react.createElement("span", {
66
+ style: {
67
+ fontWeight: 600,
68
+ whiteSpace: "nowrap",
69
+ overflow: "hidden",
70
+ textOverflow: "ellipsis"
71
+ }
72
+ }, experiment.name), /*#__PURE__*/ react.createElement("span", {
73
+ style: {
74
+ display: "inline-flex",
75
+ alignItems: "center",
76
+ gap: 5,
77
+ fontSize: 12,
78
+ fontWeight: 500,
79
+ color: active ? "#0f9d58" : "#6b7280",
80
+ whiteSpace: "nowrap"
81
+ }
82
+ }, /*#__PURE__*/ react.createElement("span", {
83
+ style: {
84
+ width: 8,
85
+ height: 8,
86
+ borderRadius: "50%",
87
+ background: active ? "#10b981" : "#9ca3af"
88
+ }
89
+ }), active ? "Active" : "Inactive")), /*#__PURE__*/ react.createElement("button", {
90
+ type: "button",
91
+ onClick: toggle,
92
+ disabled: busy,
93
+ style: toggleStyle
94
+ }, active ? /*#__PURE__*/ react.createElement(pause_svg_ReactComponent, {
95
+ style: {
96
+ width: 16,
97
+ height: 16,
98
+ fill: "currentColor"
99
+ }
100
+ }) : /*#__PURE__*/ react.createElement(play_arrow_svg_ReactComponent, {
101
+ style: {
102
+ width: 16,
103
+ height: 16,
104
+ fill: "currentColor"
105
+ }
106
+ }), active ? "Pause" : "Resume"));
107
+ });
108
+ export { ExperimentIndicator_ExperimentIndicator as ExperimentIndicator };
109
+
110
+ //# sourceMappingURL=ExperimentIndicator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/experiments/ExperimentsEditor/components/ExperimentIndicator.js","sources":["../../../../../src/presentation/experiments/ExperimentsEditor/components/ExperimentIndicator.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { useFeature } from \"@webiny/app\";\nimport { ReactComponent as ScienceIcon } from \"@webiny/icons/science.svg\";\nimport { ReactComponent as PauseIcon } from \"@webiny/icons/pause.svg\";\nimport { ReactComponent as PlayIcon } from \"@webiny/icons/play_arrow.svg\";\nimport { ExperimentsEditorPresenterFeature } from \"../feature.js\";\nimport type { ExperimentDto } from \"~/features/experiments/index.js\";\n\n/**\n * Top-bar indicator shown on a published (read-only) page: names the running experiment, shows\n * whether it's live (Active) or paused (Inactive), and lets the editor toggle the kill-switch.\n */\nexport const ExperimentIndicator = observer(function ExperimentIndicator({\n experiment\n}: {\n experiment: ExperimentDto;\n}) {\n const { presenter } = useFeature(ExperimentsEditorPresenterFeature);\n const { paused } = presenter.vm;\n const [busy, setBusy] = useState(false);\n const active = !paused;\n\n const toggle = async () => {\n setBusy(true);\n try {\n await (paused ? presenter.resume() : presenter.pause());\n } finally {\n setBusy(false);\n }\n };\n\n const toggleStyle: React.CSSProperties = {\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 6,\n borderRadius: 8,\n padding: \"6px 12px\",\n fontWeight: 600,\n fontSize: 13,\n cursor: busy ? \"default\" : \"pointer\",\n opacity: busy ? 0.6 : 1,\n ...(active\n ? { border: \"1px solid #d5d7db\", background: \"#fff\", color: \"#1f2937\" }\n : { border: \"none\", background: \"#10b981\", color: \"#fff\" })\n };\n\n return (\n <div\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 12,\n border: \"1px solid #e5e7eb\",\n borderRadius: 8,\n padding: \"4px 4px 4px 12px\",\n background: \"#fff\"\n }}\n >\n <span style={{ display: \"inline-flex\", alignItems: \"center\", gap: 8, minWidth: 0 }}>\n <ScienceIcon\n style={{ width: 18, height: 18, color: \"#e2572a\", fill: \"currentColor\" }}\n />\n <span\n style={{\n fontWeight: 600,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\"\n }}\n >\n {experiment.name}\n </span>\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 5,\n fontSize: 12,\n fontWeight: 500,\n color: active ? \"#0f9d58\" : \"#6b7280\",\n whiteSpace: \"nowrap\"\n }}\n >\n <span\n style={{\n width: 8,\n height: 8,\n borderRadius: \"50%\",\n background: active ? \"#10b981\" : \"#9ca3af\"\n }}\n />\n {active ? \"Active\" : \"Inactive\"}\n </span>\n </span>\n <button type=\"button\" onClick={toggle} disabled={busy} style={toggleStyle}>\n {active ? (\n <PauseIcon style={{ width: 16, height: 16, fill: \"currentColor\" }} />\n ) : (\n <PlayIcon style={{ width: 16, height: 16, fill: \"currentColor\" }} />\n )}\n {active ? \"Pause\" : \"Resume\"}\n </button>\n </div>\n );\n});\n"],"names":["ExperimentIndicator","observer","experiment","presenter","useFeature","ExperimentsEditorPresenterFeature","paused","busy","setBusy","useState","active","toggle","toggleStyle","ScienceIcon","PauseIcon","PlayIcon"],"mappings":";;;;;;;AAaO,MAAMA,0CAAsBC,SAAS,SAA6B,EACrEC,UAAU,EAGb;IACG,MAAM,EAAEC,SAAS,EAAE,GAAGC,WAAWC;IACjC,MAAM,EAAEC,MAAM,EAAE,GAAGH,UAAU,EAAE;IAC/B,MAAM,CAACI,MAAMC,QAAQ,GAAGC,SAAS;IACjC,MAAMC,SAAS,CAACJ;IAEhB,MAAMK,SAAS;QACXH,QAAQ;QACR,IAAI;YACA,MAAOF,CAAAA,SAASH,UAAU,MAAM,KAAKA,UAAU,KAAK,EAAC;QACzD,SAAU;YACNK,QAAQ;QACZ;IACJ;IAEA,MAAMI,cAAmC;QACrC,SAAS;QACT,YAAY;QACZ,KAAK;QACL,cAAc;QACd,SAAS;QACT,YAAY;QACZ,UAAU;QACV,QAAQL,OAAO,YAAY;QAC3B,SAASA,OAAO,MAAM;QACtB,GAAIG,SACE;YAAE,QAAQ;YAAqB,YAAY;YAAQ,OAAO;QAAU,IACpE;YAAE,QAAQ;YAAQ,YAAY;YAAW,OAAO;QAAO,CAAC;IAClE;IAEA,OAAO,WAAP,GACI,oBAAC;QACG,OAAO;YACH,SAAS;YACT,YAAY;YACZ,KAAK;YACL,QAAQ;YACR,cAAc;YACd,SAAS;YACT,YAAY;QAChB;qBAEA,oBAAC;QAAK,OAAO;YAAE,SAAS;YAAe,YAAY;YAAU,KAAK;YAAG,UAAU;QAAE;qBAC7E,oBAACG,gBAAWA;QACR,OAAO;YAAE,OAAO;YAAI,QAAQ;YAAI,OAAO;YAAW,MAAM;QAAe;sBAE3E,oBAAC;QACG,OAAO;YACH,YAAY;YACZ,YAAY;YACZ,UAAU;YACV,cAAc;QAClB;OAECX,WAAW,IAAI,iBAEpB,oBAAC;QACG,OAAO;YACH,SAAS;YACT,YAAY;YACZ,KAAK;YACL,UAAU;YACV,YAAY;YACZ,OAAOQ,SAAS,YAAY;YAC5B,YAAY;QAChB;qBAEA,oBAAC;QACG,OAAO;YACH,OAAO;YACP,QAAQ;YACR,cAAc;YACd,YAAYA,SAAS,YAAY;QACrC;QAEHA,SAAS,WAAW,4BAG7B,oBAAC;QAAO,MAAK;QAAS,SAASC;QAAQ,UAAUJ;QAAM,OAAOK;OACzDF,SAAS,WAATA,GACG,oBAACI,0BAASA;QAAC,OAAO;YAAE,OAAO;YAAI,QAAQ;YAAI,MAAM;QAAe;uBAEhE,oBAACC,+BAAQA;QAAC,OAAO;YAAE,OAAO;YAAI,QAAQ;YAAI,MAAM;QAAe;QAElEL,SAAS,UAAU;AAIpC"}
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ /**
3
+ * A bar shown between the address bar and the canvas while an experiment is selected. It names the
4
+ * experiment, shows its status and the bucket currently being edited, and lets the editor switch
5
+ * between the control and each variant or jump to editing the experiment.
6
+ */
7
+ export declare const ExperimentPreviewToolbar: (() => React.JSX.Element | null) & React.NamedExoticComponent<unknown> & {
8
+ readonly type: () => React.JSX.Element | null;
9
+ };
@@ -0,0 +1,178 @@
1
+ import react, { useState } from "react";
2
+ import { observer } from "mobx-react-lite";
3
+ import { useFeature } from "@webiny/app";
4
+ import { DropdownMenu } from "@webiny/admin-ui";
5
+ import { ReactComponent } from "@webiny/icons/science.svg";
6
+ import { ReactComponent as swap_horiz_svg_ReactComponent } from "@webiny/icons/swap_horiz.svg";
7
+ import { ReactComponent as check_svg_ReactComponent } from "@webiny/icons/check.svg";
8
+ import { ReactComponent as edit_svg_ReactComponent } from "@webiny/icons/edit.svg";
9
+ import { ExperimentsEditorPresenterFeature } from "../feature.js";
10
+ import { useSelectFromEditor } from "../../../../BaseEditor/hooks/useSelectFromEditor.js";
11
+ const Dot = ({ color })=>/*#__PURE__*/ react.createElement("span", {
12
+ style: {
13
+ width: 8,
14
+ height: 8,
15
+ borderRadius: "50%",
16
+ background: color,
17
+ flexShrink: 0
18
+ }
19
+ });
20
+ const ExperimentPreviewToolbar_ExperimentPreviewToolbar = observer(function() {
21
+ const { presenter } = useFeature(ExperimentsEditorPresenterFeature);
22
+ const { selectedExperiment, variantOptions: options, currentBucket: current } = presenter.vm;
23
+ const isReadOnly = useSelectFromEditor((state)=>state.isReadOnly);
24
+ const [open, setOpen] = useState(false);
25
+ if (!selectedExperiment || !current) return null;
26
+ const active = "running" === selectedExperiment.status;
27
+ const trigger = /*#__PURE__*/ react.createElement("button", {
28
+ type: "button",
29
+ style: {
30
+ display: "inline-flex",
31
+ alignItems: "center",
32
+ gap: 8,
33
+ border: "1px solid #d5d7db",
34
+ background: "#fff",
35
+ borderRadius: 8,
36
+ padding: "6px 12px",
37
+ fontWeight: 600,
38
+ fontSize: 13,
39
+ cursor: "pointer"
40
+ }
41
+ }, /*#__PURE__*/ react.createElement(swap_horiz_svg_ReactComponent, {
42
+ style: {
43
+ width: 18,
44
+ height: 18
45
+ }
46
+ }), "Switch variant");
47
+ return /*#__PURE__*/ react.createElement("div", {
48
+ className: "w-full bg-neutral-base border-solid border-b-sm border-neutral-dimmed",
49
+ "data-affects-preview": "height",
50
+ style: {
51
+ display: "flex",
52
+ alignItems: "center",
53
+ justifyContent: "space-between",
54
+ gap: 12,
55
+ padding: "8px 16px",
56
+ minHeight: 48
57
+ }
58
+ }, /*#__PURE__*/ react.createElement("div", {
59
+ style: {
60
+ display: "flex",
61
+ alignItems: "center",
62
+ gap: 12,
63
+ minWidth: 0
64
+ }
65
+ }, isReadOnly ? null : /*#__PURE__*/ react.createElement(react.Fragment, null, /*#__PURE__*/ react.createElement(ReactComponent, {
66
+ style: {
67
+ width: 18,
68
+ height: 18,
69
+ color: "#e2572a",
70
+ flexShrink: 0
71
+ }
72
+ }), /*#__PURE__*/ react.createElement("span", {
73
+ style: {
74
+ fontWeight: 600,
75
+ whiteSpace: "nowrap",
76
+ overflow: "hidden",
77
+ textOverflow: "ellipsis"
78
+ }
79
+ }, selectedExperiment.name), /*#__PURE__*/ react.createElement("span", {
80
+ style: {
81
+ display: "inline-flex",
82
+ alignItems: "center",
83
+ gap: 5,
84
+ fontSize: 12,
85
+ fontWeight: 500,
86
+ color: active ? "#0f9d58" : "#6b7280",
87
+ whiteSpace: "nowrap"
88
+ }
89
+ }, /*#__PURE__*/ react.createElement(Dot, {
90
+ color: active ? "#10b981" : "#9ca3af"
91
+ }), active ? "Active" : "Inactive"), /*#__PURE__*/ react.createElement("span", {
92
+ style: {
93
+ width: 1,
94
+ height: 20,
95
+ background: "#e5e7eb",
96
+ flexShrink: 0
97
+ }
98
+ })), /*#__PURE__*/ react.createElement("span", {
99
+ style: {
100
+ fontSize: 13,
101
+ color: "#6b7280",
102
+ whiteSpace: "nowrap"
103
+ }
104
+ }, isReadOnly ? "Previewing" : "You're editing"), /*#__PURE__*/ react.createElement("span", {
105
+ style: {
106
+ display: "inline-flex",
107
+ alignItems: "center",
108
+ gap: 8,
109
+ background: "#3c4043",
110
+ color: "#fff",
111
+ borderRadius: 8,
112
+ padding: "4px 10px",
113
+ fontSize: 13,
114
+ fontWeight: 600,
115
+ whiteSpace: "nowrap"
116
+ }
117
+ }, /*#__PURE__*/ react.createElement(Dot, {
118
+ color: current.color
119
+ }), current.name, /*#__PURE__*/ react.createElement("span", {
120
+ style: {
121
+ opacity: 0.7,
122
+ fontWeight: 500
123
+ }
124
+ }, current.weight, "%"))), /*#__PURE__*/ react.createElement(DropdownMenu, {
125
+ open: open,
126
+ onOpenChange: setOpen,
127
+ trigger: trigger,
128
+ style: {
129
+ minWidth: 260
130
+ }
131
+ }, /*#__PURE__*/ react.createElement(DropdownMenu.Label, {
132
+ text: "Switch variant"
133
+ }), options.map((option)=>/*#__PURE__*/ react.createElement(DropdownMenu.Item, {
134
+ key: option.id ?? "control",
135
+ icon: /*#__PURE__*/ react.createElement(Dot, {
136
+ color: option.color
137
+ }),
138
+ text: /*#__PURE__*/ react.createElement("span", {
139
+ style: {
140
+ display: "flex",
141
+ alignItems: "center",
142
+ justifyContent: "space-between",
143
+ width: "100%",
144
+ gap: 8
145
+ }
146
+ }, /*#__PURE__*/ react.createElement("span", null, option.name), /*#__PURE__*/ react.createElement("span", {
147
+ style: {
148
+ display: "flex",
149
+ alignItems: "center",
150
+ gap: 8
151
+ }
152
+ }, /*#__PURE__*/ react.createElement("span", {
153
+ style: {
154
+ fontSize: 12,
155
+ color: "#6b7280"
156
+ }
157
+ }, option.weight, "%"), option.id === current.id ? /*#__PURE__*/ react.createElement(check_svg_ReactComponent, {
158
+ style: {
159
+ width: 16,
160
+ height: 16,
161
+ color: option.color
162
+ }
163
+ }) : null)),
164
+ onClick: ()=>presenter.selectVariant(option.id)
165
+ })), isReadOnly ? null : /*#__PURE__*/ react.createElement(react.Fragment, null, /*#__PURE__*/ react.createElement(DropdownMenu.Separator, null), /*#__PURE__*/ react.createElement(DropdownMenu.Item, {
166
+ icon: /*#__PURE__*/ react.createElement(edit_svg_ReactComponent, {
167
+ style: {
168
+ width: 18,
169
+ height: 18
170
+ }
171
+ }),
172
+ text: "Edit experiment",
173
+ onClick: ()=>presenter.editExperiment(selectedExperiment)
174
+ }))));
175
+ });
176
+ export { ExperimentPreviewToolbar_ExperimentPreviewToolbar as ExperimentPreviewToolbar };
177
+
178
+ //# sourceMappingURL=ExperimentPreviewToolbar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/experiments/ExperimentsEditor/components/ExperimentPreviewToolbar.js","sources":["../../../../../src/presentation/experiments/ExperimentsEditor/components/ExperimentPreviewToolbar.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { useFeature } from \"@webiny/app\";\nimport { DropdownMenu } from \"@webiny/admin-ui\";\nimport { ReactComponent as ScienceIcon } from \"@webiny/icons/science.svg\";\nimport { ReactComponent as SwapIcon } from \"@webiny/icons/swap_horiz.svg\";\nimport { ReactComponent as CheckIcon } from \"@webiny/icons/check.svg\";\nimport { ReactComponent as EditIcon } from \"@webiny/icons/edit.svg\";\nimport { ExperimentsEditorPresenterFeature } from \"../feature.js\";\nimport { useSelectFromEditor } from \"~/BaseEditor/hooks/useSelectFromEditor.js\";\n\nconst Dot = ({ color }: { color: string }) => (\n <span style={{ width: 8, height: 8, borderRadius: \"50%\", background: color, flexShrink: 0 }} />\n);\n\n/**\n * A bar shown between the address bar and the canvas while an experiment is selected. It names the\n * experiment, shows its status and the bucket currently being edited, and lets the editor switch\n * between the control and each variant or jump to editing the experiment.\n */\nexport const ExperimentPreviewToolbar = observer(function ExperimentPreviewToolbar() {\n const { presenter } = useFeature(ExperimentsEditorPresenterFeature);\n const { selectedExperiment, variantOptions: options, currentBucket: current } = presenter.vm;\n const isReadOnly = useSelectFromEditor(state => state.isReadOnly);\n const [open, setOpen] = useState(false);\n\n if (!selectedExperiment || !current) {\n return null;\n }\n\n const active = selectedExperiment.status === \"running\";\n\n const trigger = (\n <button\n type=\"button\"\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 8,\n border: \"1px solid #d5d7db\",\n background: \"#fff\",\n borderRadius: 8,\n padding: \"6px 12px\",\n fontWeight: 600,\n fontSize: 13,\n cursor: \"pointer\"\n }}\n >\n <SwapIcon style={{ width: 18, height: 18 }} />\n Switch variant\n </button>\n );\n\n return (\n <div\n className=\"w-full bg-neutral-base border-solid border-b-sm border-neutral-dimmed\"\n data-affects-preview={\"height\"}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 12,\n padding: \"8px 16px\",\n minHeight: 48\n }}\n >\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 12, minWidth: 0 }}>\n {/* On a published (read-only) page the experiment name/status live in the top-bar\n indicator, so the toolbar just shows what's being previewed. */}\n {!isReadOnly ? (\n <>\n <ScienceIcon\n style={{ width: 18, height: 18, color: \"#e2572a\", flexShrink: 0 }}\n />\n <span\n style={{\n fontWeight: 600,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\"\n }}\n >\n {selectedExperiment.name}\n </span>\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 5,\n fontSize: 12,\n fontWeight: 500,\n color: active ? \"#0f9d58\" : \"#6b7280\",\n whiteSpace: \"nowrap\"\n }}\n >\n <Dot color={active ? \"#10b981\" : \"#9ca3af\"} />\n {active ? \"Active\" : \"Inactive\"}\n </span>\n <span\n style={{ width: 1, height: 20, background: \"#e5e7eb\", flexShrink: 0 }}\n />\n </>\n ) : null}\n\n <span style={{ fontSize: 13, color: \"#6b7280\", whiteSpace: \"nowrap\" }}>\n {isReadOnly ? \"Previewing\" : \"You're editing\"}\n </span>\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 8,\n background: \"#3c4043\",\n color: \"#fff\",\n borderRadius: 8,\n padding: \"4px 10px\",\n fontSize: 13,\n fontWeight: 600,\n whiteSpace: \"nowrap\"\n }}\n >\n <Dot color={current.color} />\n {current.name}\n <span style={{ opacity: 0.7, fontWeight: 500 }}>{current.weight}%</span>\n </span>\n </div>\n\n <DropdownMenu\n open={open}\n onOpenChange={setOpen}\n trigger={trigger}\n style={{ minWidth: 260 }}\n >\n <DropdownMenu.Label text=\"Switch variant\" />\n {options.map(option => (\n <DropdownMenu.Item\n key={option.id ?? \"control\"}\n icon={<Dot color={option.color} />}\n text={\n <span\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n width: \"100%\",\n gap: 8\n }}\n >\n <span>{option.name}</span>\n <span style={{ display: \"flex\", alignItems: \"center\", gap: 8 }}>\n <span style={{ fontSize: 12, color: \"#6b7280\" }}>\n {option.weight}%\n </span>\n {option.id === current.id ? (\n <CheckIcon\n style={{ width: 16, height: 16, color: option.color }}\n />\n ) : null}\n </span>\n </span>\n }\n onClick={() => presenter.selectVariant(option.id)}\n />\n ))}\n {!isReadOnly ? (\n <>\n <DropdownMenu.Separator />\n <DropdownMenu.Item\n icon={<EditIcon style={{ width: 18, height: 18 }} />}\n text=\"Edit experiment\"\n onClick={() => presenter.editExperiment(selectedExperiment)}\n />\n </>\n ) : null}\n </DropdownMenu>\n </div>\n );\n});\n"],"names":["Dot","color","ExperimentPreviewToolbar","observer","presenter","useFeature","ExperimentsEditorPresenterFeature","selectedExperiment","options","current","isReadOnly","useSelectFromEditor","state","open","setOpen","useState","active","trigger","SwapIcon","ScienceIcon","DropdownMenu","option","CheckIcon","EditIcon"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ /**
3
+ * Top-bar entry point for A/B experiments.
4
+ *
5
+ * On an editable (draft) page it's a switcher for picking an experiment to edit; on a published
6
+ * (read-only) page it's an indicator for the running experiment with a pause/resume kill-switch.
7
+ * State is shared through the editor-wide presenter so the in-preview toolbar tracks the selection.
8
+ */
9
+ export declare const ExperimentsButton: (() => React.JSX.Element | null) & React.NamedExoticComponent<unknown> & {
10
+ readonly type: () => React.JSX.Element | null;
11
+ };
@@ -0,0 +1,51 @@
1
+ import react, { useEffect } from "react";
2
+ import { observer } from "mobx-react-lite";
3
+ import { useFeature } from "@webiny/app";
4
+ import { Button } from "@webiny/admin-ui";
5
+ import { ReactComponent } from "@webiny/icons/science.svg";
6
+ import { useSelectFromEditor } from "../../../../BaseEditor/hooks/useSelectFromEditor.js";
7
+ import { ExperimentsSwitcher } from "./ExperimentsSwitcher.js";
8
+ import { ExperimentIndicator } from "./ExperimentIndicator.js";
9
+ import { ExperimentsEditorPresenterFeature } from "../feature.js";
10
+ const ExperimentsButton_ExperimentsButton = observer(function() {
11
+ const { presenter } = useFeature(ExperimentsEditorPresenterFeature);
12
+ const isReadOnly = useSelectFromEditor((state)=>state.isReadOnly);
13
+ const { runningExperiment, switcherItems, selectedExperimentId } = presenter.vm;
14
+ useEffect(()=>{
15
+ presenter.syncReadOnlySelection(isReadOnly);
16
+ }, [
17
+ presenter,
18
+ isReadOnly,
19
+ runningExperiment,
20
+ selectedExperimentId
21
+ ]);
22
+ if (isReadOnly) {
23
+ if (!runningExperiment) return null;
24
+ return /*#__PURE__*/ react.createElement("div", {
25
+ style: {
26
+ display: "flex"
27
+ }
28
+ }, /*#__PURE__*/ react.createElement(ExperimentIndicator, {
29
+ experiment: runningExperiment
30
+ }));
31
+ }
32
+ const items = switcherItems;
33
+ return /*#__PURE__*/ react.createElement("div", {
34
+ style: {
35
+ display: "flex"
36
+ }
37
+ }, 0 === items.length ? /*#__PURE__*/ react.createElement(Button, {
38
+ variant: "secondary",
39
+ icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
40
+ text: "Experiments",
41
+ onClick: ()=>presenter.openManage()
42
+ }) : /*#__PURE__*/ react.createElement(ExperimentsSwitcher, {
43
+ experiments: items,
44
+ selectedId: selectedExperimentId,
45
+ onSelect: (id)=>presenter.selectExperiment(id),
46
+ onManage: ()=>presenter.openManage()
47
+ }));
48
+ });
49
+ export { ExperimentsButton_ExperimentsButton as ExperimentsButton };
50
+
51
+ //# sourceMappingURL=ExperimentsButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/experiments/ExperimentsEditor/components/ExperimentsButton.js","sources":["../../../../../src/presentation/experiments/ExperimentsEditor/components/ExperimentsButton.tsx"],"sourcesContent":["import React, { useEffect } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { useFeature } from \"@webiny/app\";\nimport { Button } from \"@webiny/admin-ui\";\nimport { ReactComponent as ScienceIcon } from \"@webiny/icons/science.svg\";\nimport { useSelectFromEditor } from \"~/BaseEditor/hooks/useSelectFromEditor.js\";\nimport { ExperimentsSwitcher, type ExperimentItem } from \"./ExperimentsSwitcher.js\";\nimport { ExperimentIndicator } from \"./ExperimentIndicator.js\";\nimport { ExperimentsEditorPresenterFeature } from \"../feature.js\";\n\n/**\n * Top-bar entry point for A/B experiments.\n *\n * On an editable (draft) page it's a switcher for picking an experiment to edit; on a published\n * (read-only) page it's an indicator for the running experiment with a pause/resume kill-switch.\n * State is shared through the editor-wide presenter so the in-preview toolbar tracks the selection.\n */\nexport const ExperimentsButton = observer(function ExperimentsButton() {\n const { presenter } = useFeature(ExperimentsEditorPresenterFeature);\n const isReadOnly = useSelectFromEditor(state => state.isReadOnly);\n\n const { runningExperiment, switcherItems, selectedExperimentId } = presenter.vm;\n\n // On the published (read-only) view, surface the running experiment and keep it selected so the\n // preview toolbar tracks it. Forwards the editor read-only selector into the presenter.\n useEffect(() => {\n presenter.syncReadOnlySelection(isReadOnly);\n }, [presenter, isReadOnly, runningExperiment, selectedExperimentId]);\n\n if (isReadOnly) {\n if (!runningExperiment) {\n return null;\n }\n return (\n <div style={{ display: \"flex\" }}>\n <ExperimentIndicator experiment={runningExperiment} />\n </div>\n );\n }\n\n const items: ExperimentItem[] = switcherItems;\n\n return (\n <div style={{ display: \"flex\" }}>\n {items.length === 0 ? (\n <Button\n variant=\"secondary\"\n icon={<ScienceIcon />}\n text=\"Experiments\"\n onClick={() => presenter.openManage()}\n />\n ) : (\n <ExperimentsSwitcher\n experiments={items}\n selectedId={selectedExperimentId}\n onSelect={id => presenter.selectExperiment(id)}\n onManage={() => presenter.openManage()}\n />\n )}\n </div>\n );\n});\n"],"names":["ExperimentsButton","observer","presenter","useFeature","ExperimentsEditorPresenterFeature","isReadOnly","useSelectFromEditor","state","runningExperiment","switcherItems","selectedExperimentId","useEffect","ExperimentIndicator","items","Button","ScienceIcon","ExperimentsSwitcher","id"],"mappings":";;;;;;;;;AAiBO,MAAMA,sCAAoBC,SAAS;IACtC,MAAM,EAAEC,SAAS,EAAE,GAAGC,WAAWC;IACjC,MAAMC,aAAaC,oBAAoBC,CAAAA,QAASA,MAAM,UAAU;IAEhE,MAAM,EAAEC,iBAAiB,EAAEC,aAAa,EAAEC,oBAAoB,EAAE,GAAGR,UAAU,EAAE;IAI/ES,UAAU;QACNT,UAAU,qBAAqB,CAACG;IACpC,GAAG;QAACH;QAAWG;QAAYG;QAAmBE;KAAqB;IAEnE,IAAIL,YAAY;QACZ,IAAI,CAACG,mBACD,OAAO;QAEX,OAAO,WAAP,GACI,oBAAC;YAAI,OAAO;gBAAE,SAAS;YAAO;yBAC1B,oBAACI,qBAAmBA;YAAC,YAAYJ;;IAG7C;IAEA,MAAMK,QAA0BJ;IAEhC,OAAO,WAAP,GACI,oBAAC;QAAI,OAAO;YAAE,SAAS;QAAO;OACzBI,AAAiB,MAAjBA,MAAM,MAAM,GAAS,WAAJ,GACd,oBAACC,QAAMA;QACH,SAAQ;QACR,oBAAM,oBAACC,gBAAWA;QAClB,MAAK;QACL,SAAS,IAAMb,UAAU,UAAU;uBAGvC,oBAACc,qBAAmBA;QAChB,aAAaH;QACb,YAAYH;QACZ,UAAUO,CAAAA,KAAMf,UAAU,gBAAgB,CAACe;QAC3C,UAAU,IAAMf,UAAU,UAAU;;AAKxD"}
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+ export interface ExperimentItem {
3
+ id: string;
4
+ name: string;
5
+ status: "active" | "inactive";
6
+ }
7
+ interface Props {
8
+ experiments: ExperimentItem[];
9
+ selectedId: string | null;
10
+ onSelect: (id: string | null) => void;
11
+ onManage: () => void;
12
+ }
13
+ export declare const ExperimentsSwitcher: ({ experiments, selectedId, onSelect, onManage }: Props) => React.JSX.Element;
14
+ export {};