@webiny/app-headless-cms 6.5.0-beta.0 → 6.5.0-beta.10

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 (208) hide show
  1. package/ContentEntriesModule.js +14 -2
  2. package/ContentEntriesModule.js.map +1 -1
  3. package/admin/components/ContentEntries/BulkActions/ActionDelete.d.ts +2 -2
  4. package/admin/components/ContentEntries/BulkActions/ActionDelete.js.map +1 -1
  5. package/admin/components/ContentEntries/BulkActions/ActionMove.d.ts +2 -2
  6. package/admin/components/ContentEntries/BulkActions/ActionMove.js.map +1 -1
  7. package/admin/components/ContentEntries/BulkActions/ActionPublish.d.ts +2 -2
  8. package/admin/components/ContentEntries/BulkActions/ActionPublish.js.map +1 -1
  9. package/admin/components/ContentEntries/BulkActions/ActionUnpublish.d.ts +2 -2
  10. package/admin/components/ContentEntries/BulkActions/ActionUnpublish.js.map +1 -1
  11. package/admin/components/ContentEntries/Filters/RefFieldRenderer.d.ts +2 -0
  12. package/admin/components/ContentEntries/Filters/RefFieldRenderer.js +84 -0
  13. package/admin/components/ContentEntries/Filters/RefFieldRenderer.js.map +1 -0
  14. package/admin/components/ContentEntries/Table/Actions/DuplicateEntry.d.ts +2 -0
  15. package/admin/components/ContentEntries/Table/Actions/DuplicateEntry.js +34 -0
  16. package/admin/components/ContentEntries/Table/Actions/DuplicateEntry.js.map +1 -0
  17. package/admin/components/ContentEntries/Table/Actions/index.d.ts +1 -0
  18. package/admin/components/ContentEntries/Table/Actions/index.js +1 -0
  19. package/admin/components/ContentModelEditor/ContentModelEditor.js +1 -1
  20. package/admin/components/ContentModelEditor/ContentModelEditor.js.map +1 -1
  21. package/admin/components/Dialogs/DuplicateEntryConfirmDialog.d.ts +2 -0
  22. package/admin/components/Dialogs/DuplicateEntryConfirmDialog.js +22 -0
  23. package/admin/components/Dialogs/DuplicateEntryConfirmDialog.js.map +1 -0
  24. package/admin/components/FieldEditor/EditFieldDialog.d.ts +2 -2
  25. package/admin/components/FieldEditor/Field.js +4 -4
  26. package/admin/components/FieldEditor/Field.js.map +1 -1
  27. package/features/contentEntry/CmsEntryError.d.ts +10 -0
  28. package/features/contentEntry/CmsEntryError.js +11 -0
  29. package/features/contentEntry/CmsEntryError.js.map +1 -0
  30. package/features/contentEntry/createEntry/CreateEntryGateway.d.ts +0 -1
  31. package/features/contentEntry/createEntry/CreateEntryGateway.js +3 -10
  32. package/features/contentEntry/createEntry/CreateEntryGateway.js.map +1 -1
  33. package/features/contentEntry/createRevisionFrom/CreateRevisionFromGateway.d.ts +3 -1
  34. package/features/contentEntry/createRevisionFrom/CreateRevisionFromGateway.js +8 -3
  35. package/features/contentEntry/createRevisionFrom/CreateRevisionFromGateway.js.map +1 -1
  36. package/features/contentEntry/duplicateEntry/DuplicateEntryGateway.d.ts +14 -0
  37. package/features/contentEntry/duplicateEntry/DuplicateEntryGateway.js +43 -0
  38. package/features/contentEntry/duplicateEntry/DuplicateEntryGateway.js.map +1 -0
  39. package/features/contentEntry/duplicateEntry/DuplicateEntryRepository.d.ts +15 -0
  40. package/features/contentEntry/duplicateEntry/DuplicateEntryRepository.js +34 -0
  41. package/features/contentEntry/duplicateEntry/DuplicateEntryRepository.js.map +1 -0
  42. package/features/contentEntry/duplicateEntry/DuplicateEntryUseCase.d.ts +11 -0
  43. package/features/contentEntry/duplicateEntry/DuplicateEntryUseCase.js +18 -0
  44. package/features/contentEntry/duplicateEntry/DuplicateEntryUseCase.js.map +1 -0
  45. package/features/contentEntry/duplicateEntry/abstractions.d.ts +26 -0
  46. package/features/contentEntry/duplicateEntry/abstractions.js +7 -0
  47. package/features/contentEntry/duplicateEntry/abstractions.js.map +1 -0
  48. package/features/contentEntry/duplicateEntry/feature.d.ts +3 -0
  49. package/features/contentEntry/duplicateEntry/feature.js +21 -0
  50. package/features/contentEntry/duplicateEntry/feature.js.map +1 -0
  51. package/features/contentEntry/entryValueGateways.test.d.ts +1 -0
  52. package/features/contentEntry/entryValueGateways.test.js +106 -0
  53. package/features/contentEntry/entryValueGateways.test.js.map +1 -0
  54. package/features/contentEntry/feature.js +2 -0
  55. package/features/contentEntry/feature.js.map +1 -1
  56. package/features/contentEntry/singletonEntry/UpdateSingletonEntryGateway.d.ts +0 -1
  57. package/features/contentEntry/singletonEntry/UpdateSingletonEntryGateway.js +3 -10
  58. package/features/contentEntry/singletonEntry/UpdateSingletonEntryGateway.js.map +1 -1
  59. package/features/contentEntry/updateEntry/UpdateEntryGateway.d.ts +0 -1
  60. package/features/contentEntry/updateEntry/UpdateEntryGateway.js +3 -10
  61. package/features/contentEntry/updateEntry/UpdateEntryGateway.js.map +1 -1
  62. package/features/contentEntry/valueTransformers/EntryDataPreparer.d.ts +9 -0
  63. package/features/contentEntry/valueTransformers/EntryDataPreparer.js +8 -0
  64. package/features/contentEntry/valueTransformers/EntryDataPreparer.js.map +1 -1
  65. package/features/contentEntry/valueTransformers/EntryDataPreparer.test.d.ts +1 -0
  66. package/features/contentEntry/valueTransformers/EntryDataPreparer.test.js +113 -0
  67. package/features/contentEntry/valueTransformers/EntryDataPreparer.test.js.map +1 -0
  68. package/features/contentEntry/valueTransformers/entryValueFixtures.d.ts +146 -0
  69. package/features/contentEntry/valueTransformers/entryValueFixtures.js +171 -0
  70. package/features/contentEntry/valueTransformers/entryValueFixtures.js.map +1 -0
  71. package/features/formModel/CmsFormModelBuilder.d.ts +9 -1
  72. package/features/formModel/CmsFormModelBuilder.js +26 -15
  73. package/features/formModel/CmsFormModelBuilder.js.map +1 -1
  74. package/features/formModel/CmsFormModelBuilder.test.d.ts +1 -0
  75. package/features/formModel/CmsFormModelBuilder.test.js +252 -0
  76. package/features/formModel/CmsFormModelBuilder.test.js.map +1 -0
  77. package/features/formModel/CmsLayoutMapper.d.ts +8 -1
  78. package/features/formModel/CmsLayoutMapper.js +23 -1
  79. package/features/formModel/CmsLayoutMapper.js.map +1 -1
  80. package/features/formModel/mappers/DynamicZoneFieldMapper.js +4 -0
  81. package/features/formModel/mappers/DynamicZoneFieldMapper.js.map +1 -1
  82. package/features/formModel/mappers/ObjectFieldMapper.js +11 -6
  83. package/features/formModel/mappers/ObjectFieldMapper.js.map +1 -1
  84. package/features/model/exportModels/ExportModelsGateway.d.ts +1 -1
  85. package/features/model/exportModels/ExportModelsGateway.js.map +1 -1
  86. package/features/model/exportModels/ExportModelsUseCase.js +7 -1
  87. package/features/model/exportModels/ExportModelsUseCase.js.map +1 -1
  88. package/features/model/exportModels/abstractions.d.ts +8 -2
  89. package/features/model/exportModels/abstractions.js.map +1 -1
  90. package/package.json +26 -26
  91. package/presentation/cloneContentModel/CloneContentModelPresenter.d.ts +1 -0
  92. package/presentation/cloneContentModel/CloneContentModelPresenter.js +8 -6
  93. package/presentation/cloneContentModel/CloneContentModelPresenter.js.map +1 -1
  94. package/presentation/contentEntries/form/ContentEntryFormPresenter.js +34 -29
  95. package/presentation/contentEntries/form/ContentEntryFormPresenter.js.map +1 -1
  96. package/presentation/contentEntries/form/ContentEntryFormPresenter.test.d.ts +1 -0
  97. package/presentation/contentEntries/form/ContentEntryFormPresenter.test.js +210 -0
  98. package/presentation/contentEntries/form/ContentEntryFormPresenter.test.js.map +1 -0
  99. package/presentation/contentEntries/form/toFormErrors.d.ts +7 -0
  100. package/presentation/contentEntries/form/toFormErrors.js +49 -0
  101. package/presentation/contentEntries/form/toFormErrors.js.map +1 -0
  102. package/presentation/contentEntries/form/toFormErrors.test.d.ts +1 -0
  103. package/presentation/contentEntries/form/toFormErrors.test.js +175 -0
  104. package/presentation/contentEntries/form/toFormErrors.test.js.map +1 -0
  105. package/presentation/contentEntries/list/ContentEntriesDataSource.d.ts +5 -0
  106. package/presentation/contentEntries/list/ContentEntriesDataSource.js +11 -2
  107. package/presentation/contentEntries/list/ContentEntriesDataSource.js.map +1 -1
  108. package/presentation/contentEntries/list/ContentEntriesPresenter.d.ts +6 -2
  109. package/presentation/contentEntries/list/ContentEntriesPresenter.js +27 -2
  110. package/presentation/contentEntries/list/ContentEntriesPresenter.js.map +1 -1
  111. package/presentation/contentEntries/list/ContentEntriesPresenter.test.js +130 -5
  112. package/presentation/contentEntries/list/ContentEntriesPresenter.test.js.map +1 -1
  113. package/presentation/contentEntries/list/abstractions.d.ts +12 -0
  114. package/presentation/contentEntries/list/abstractions.js.map +1 -1
  115. package/presentation/contentEntries/preview/LivePreviewPresenter.d.ts +12 -1
  116. package/presentation/contentEntries/preview/LivePreviewPresenter.js +48 -5
  117. package/presentation/contentEntries/preview/LivePreviewPresenter.js.map +1 -1
  118. package/presentation/contentEntries/preview/LivePreviewPresenter.test.d.ts +1 -0
  119. package/presentation/contentEntries/preview/LivePreviewPresenter.test.js +81 -0
  120. package/presentation/contentEntries/preview/LivePreviewPresenter.test.js.map +1 -0
  121. package/presentation/contentEntries/preview/ModelEditorComponentDiscovery.js +1 -1
  122. package/presentation/contentEntries/preview/ModelEditorComponentDiscovery.js.map +1 -1
  123. package/presentation/contentEntries/preview/PreviewDecorator.js +25 -6
  124. package/presentation/contentEntries/preview/PreviewDecorator.js.map +1 -1
  125. package/presentation/contentEntries/preview/PreviewDomainStatus.d.ts +10 -0
  126. package/presentation/contentEntries/preview/PreviewDomainStatus.js +19 -0
  127. package/presentation/contentEntries/preview/PreviewDomainStatus.js.map +1 -0
  128. package/presentation/contentEntries/preview/PreviewPane.d.ts +10 -1
  129. package/presentation/contentEntries/preview/PreviewPane.js +81 -45
  130. package/presentation/contentEntries/preview/PreviewPane.js.map +1 -1
  131. package/presentation/contentEntries/preview/abstractions.d.ts +8 -0
  132. package/presentation/contentEntries/preview/abstractions.js.map +1 -1
  133. package/presentation/contentEntries/preview/resolvePreviewUrl.d.ts +21 -0
  134. package/presentation/contentEntries/preview/resolvePreviewUrl.js +50 -1
  135. package/presentation/contentEntries/preview/resolvePreviewUrl.js.map +1 -1
  136. package/presentation/contentEntries/preview/resolvePreviewUrl.test.d.ts +1 -0
  137. package/presentation/contentEntries/preview/resolvePreviewUrl.test.js +127 -0
  138. package/presentation/contentEntries/preview/resolvePreviewUrl.test.js.map +1 -0
  139. package/presentation/contentEntries/singleEntry/SingleEntryPresenter.js +9 -4
  140. package/presentation/contentEntries/singleEntry/SingleEntryPresenter.js.map +1 -1
  141. package/presentation/contentEntries/singleEntry/SingleEntryPresenter.test.d.ts +1 -0
  142. package/presentation/contentEntries/singleEntry/SingleEntryPresenter.test.js +122 -0
  143. package/presentation/contentEntries/singleEntry/SingleEntryPresenter.test.js.map +1 -0
  144. package/presentation/contentEntries/trashBin/CmsTrashBin.d.ts +2 -2
  145. package/presentation/contentEntries/views/CmsAdvancedSearch.d.ts +2 -2
  146. package/presentation/contentEntries/views/ContentEntriesListLayout.d.ts +2 -2
  147. package/presentation/contentEntries/views/ContentEntryFormView.d.ts +2 -2
  148. package/presentation/contentEntries/views/OlderRevisionAlert.d.ts +2 -2
  149. package/presentation/contentEntries/views/RevisionDrawer.d.ts +2 -2
  150. package/presentation/contentEntries/views/RevisionsList.d.ts +2 -2
  151. package/presentation/contentEntries/views/SingleEntryLayout.d.ts +2 -2
  152. package/presentation/contentEntries/views/Table/Table.d.ts +2 -2
  153. package/presentation/contentEntries/views/actions/CreateNewRevisionButton.d.ts +2 -2
  154. package/presentation/contentEntries/views/actions/DeleteEntryMenuItem.d.ts +2 -2
  155. package/presentation/contentEntries/views/actions/PublishOnlyButton.d.ts +2 -2
  156. package/presentation/contentEntries/views/actions/RevisionSelector.d.ts +2 -2
  157. package/presentation/contentEntries/views/actions/SaveAndPublishButton.d.ts +2 -2
  158. package/presentation/contentEntries/views/actions/SaveContentButton.d.ts +2 -2
  159. package/presentation/contentEntries/views/actions/ShowRevisionListMenuItem.d.ts +2 -2
  160. package/presentation/contentEntries/views/layout/ContentEntryForm.d.ts +12 -12
  161. package/presentation/contentModels/ContentModelsPresenter.d.ts +5 -5
  162. package/presentation/contentModels/ContentModelsPresenter.js +1 -1
  163. package/presentation/contentModels/ContentModelsPresenter.js.map +1 -1
  164. package/presentation/contentModels/abstractions.d.ts +7 -2
  165. package/presentation/contentModels/abstractions.js.map +1 -1
  166. package/presentation/contentModels/components/CloneContentModelDialog.d.ts +2 -2
  167. package/presentation/contentModels/components/ContentModels.d.ts +2 -2
  168. package/presentation/contentModels/components/ContentModelsDataList.d.ts +2 -2
  169. package/presentation/contentModels/components/ContentModelsDataList.js +6 -5
  170. package/presentation/contentModels/components/ContentModelsDataList.js.map +1 -1
  171. package/presentation/contentModels/components/NewContentModelDialog.d.ts +2 -2
  172. package/presentation/contentModels/components/fullDelete/dialog/Content.js +2 -2
  173. package/presentation/contentModels/components/fullDelete/dialog/Content.js.map +1 -1
  174. package/presentation/contentModels/components/fullDelete/types.js.map +1 -1
  175. package/presentation/fieldRenderers/ref/autocomplete/RefAutocompletePresenters.test.d.ts +1 -0
  176. package/presentation/fieldRenderers/ref/autocomplete/RefAutocompletePresenters.test.js +133 -0
  177. package/presentation/fieldRenderers/ref/autocomplete/RefAutocompletePresenters.test.js.map +1 -0
  178. package/presentation/fieldRenderers/ref/autocomplete/multi/RefMultiAutocompletePresenter.js +1 -1
  179. package/presentation/fieldRenderers/ref/autocomplete/multi/RefMultiAutocompletePresenter.js.map +1 -1
  180. package/presentation/fieldRenderers/ref/autocomplete/single/RefSingleAutocompletePresenter.js +1 -1
  181. package/presentation/fieldRenderers/ref/autocomplete/single/RefSingleAutocompletePresenter.js.map +1 -1
  182. package/presentation/fieldRenderers/ref/components/RefFieldOptions.d.ts +2 -2
  183. package/presentation/fieldRenderers/ref/components/RefFieldOptions.js +3 -2
  184. package/presentation/fieldRenderers/ref/components/RefFieldOptions.js.map +1 -1
  185. package/presentation/importContentModels/ImportContentModelsDialog.d.ts +2 -2
  186. package/presentation/importContentModels/ImportContentModelsPresenter.js +1 -1
  187. package/presentation/importContentModels/ImportContentModelsPresenter.js.map +1 -1
  188. package/presentation/importContentModels/components/DataList.d.ts +2 -2
  189. package/presentation/importContentModels/components/FileUpload.d.ts +2 -2
  190. package/presentation/importContentModels/components/FileUpload.js +1 -1
  191. package/presentation/importContentModels/components/FileUpload.js.map +1 -1
  192. package/presentation/importContentModels/components/Model/DataListModelItem.js +3 -3
  193. package/presentation/importContentModels/components/Model/DataListModelItem.js.map +1 -1
  194. package/presentation/importContentModels/components/Model/DataListModelItemInfo.js +2 -2
  195. package/presentation/importContentModels/components/Model/DataListModelItemInfo.js.map +1 -1
  196. package/presentation/importContentModels/components/Model/DataListModels.d.ts +2 -2
  197. package/presentation/menus/ContentGroupsMenuItems.d.ts +2 -2
  198. package/presentation/modelGroup/ModelGroupPresenter.js +1 -2
  199. package/presentation/modelGroup/ModelGroupPresenter.js.map +1 -1
  200. package/presentation/modelGroup/components/ContentModelGroups.d.ts +2 -2
  201. package/presentation/modelGroup/components/ContentModelGroupsDataList.d.ts +6 -2
  202. package/presentation/modelGroup/components/ContentModelGroupsForm.d.ts +8 -2
  203. package/presentation/newContentModel/NewContentModelPresenter.d.ts +1 -0
  204. package/presentation/newContentModel/NewContentModelPresenter.js +8 -6
  205. package/presentation/newContentModel/NewContentModelPresenter.js.map +1 -1
  206. package/utils/normalizeIcon.d.ts +4 -0
  207. package/utils/normalizeIcon.js +9 -6
  208. package/utils/normalizeIcon.js.map +1 -1
@@ -14,6 +14,13 @@ export interface IContentEntriesViewModel {
14
14
  showFolders: boolean;
15
15
  childFolders: FolderDto[];
16
16
  }
17
+ export type IDuplicateEntryResult = {
18
+ entry: CmsContentEntry;
19
+ error?: never;
20
+ } | {
21
+ entry?: never;
22
+ error: Error;
23
+ };
17
24
  export interface IContentEntriesPresenter {
18
25
  readonly vm: IContentEntriesViewModel;
19
26
  readonly list: IListPresenter<CmsContentEntry>;
@@ -25,6 +32,10 @@ export interface IContentEntriesPresenter {
25
32
  publishEntry(id: string): Promise<boolean>;
26
33
  unpublishEntry(id: string): Promise<boolean>;
27
34
  moveEntry(id: string, folderId: string): Promise<boolean>;
35
+ /**
36
+ * Resolves to `false` when the user cancels the confirmation dialog.
37
+ */
38
+ duplicateEntry(entry: CmsContentEntry): Promise<IDuplicateEntryResult | false>;
28
39
  init(config?: IContentEntriesInitConfig): void;
29
40
  dispose(): void;
30
41
  }
@@ -33,4 +44,5 @@ export declare namespace ContentEntriesPresenter {
33
44
  type Interface = IContentEntriesPresenter;
34
45
  type ViewModel = IContentEntriesViewModel;
35
46
  type InitConfig = IContentEntriesInitConfig;
47
+ type DuplicateEntryResult = IDuplicateEntryResult;
36
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/contentEntries/list/abstractions.js","sources":["../../../../src/presentation/contentEntries/list/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/admin\";\nimport type { IListPresenter } from \"@webiny/app-admin/presentation/listPresenter/abstractions.js\";\nimport type { IFolderTreePresenter } from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\nimport type { FolderDto } from \"@webiny/app-aco\";\nimport type { CmsContentEntry, CmsModel } from \"~/types.js\";\n\nexport interface IContentEntriesInitConfig {\n initialFolderId?: string;\n initialSearch?: string;\n filterNames?: string[];\n}\n\nexport interface IContentEntriesViewModel {\n model: CmsModel;\n selectedEntryId: string | null;\n showingEntry: boolean;\n showFolders: boolean;\n childFolders: FolderDto[];\n}\n\nexport interface IContentEntriesPresenter {\n readonly vm: IContentEntriesViewModel;\n readonly list: IListPresenter<CmsContentEntry>;\n readonly folders: IFolderTreePresenter;\n\n selectEntry(id: string): void;\n deselectEntry(): void;\n createEntry(): void;\n deleteEntry(id: string): Promise<boolean>;\n publishEntry(id: string): Promise<boolean>;\n unpublishEntry(id: string): Promise<boolean>;\n moveEntry(id: string, folderId: string): Promise<boolean>;\n\n init(config?: IContentEntriesInitConfig): void;\n dispose(): void;\n}\n\nexport const ContentEntriesPresenter =\n createAbstraction<IContentEntriesPresenter>(\"ContentEntriesPresenter\");\n\nexport namespace ContentEntriesPresenter {\n export type Interface = IContentEntriesPresenter;\n export type ViewModel = IContentEntriesViewModel;\n export type InitConfig = IContentEntriesInitConfig;\n}\n"],"names":["ContentEntriesPresenter","createAbstraction"],"mappings":";AAqCO,MAAMA,0BACTC,kBAA4C"}
1
+ {"version":3,"file":"presentation/contentEntries/list/abstractions.js","sources":["../../../../src/presentation/contentEntries/list/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/admin\";\nimport type { IListPresenter } from \"@webiny/app-admin/presentation/listPresenter/abstractions.js\";\nimport type { IFolderTreePresenter } from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\nimport type { FolderDto } from \"@webiny/app-aco\";\nimport type { CmsContentEntry, CmsModel } from \"~/types.js\";\n\nexport interface IContentEntriesInitConfig {\n initialFolderId?: string;\n initialSearch?: string;\n filterNames?: string[];\n}\n\nexport interface IContentEntriesViewModel {\n model: CmsModel;\n selectedEntryId: string | null;\n showingEntry: boolean;\n showFolders: boolean;\n childFolders: FolderDto[];\n}\n\nexport type IDuplicateEntryResult =\n | { entry: CmsContentEntry; error?: never }\n | { entry?: never; error: Error };\n\nexport interface IContentEntriesPresenter {\n readonly vm: IContentEntriesViewModel;\n readonly list: IListPresenter<CmsContentEntry>;\n readonly folders: IFolderTreePresenter;\n\n selectEntry(id: string): void;\n deselectEntry(): void;\n createEntry(): void;\n deleteEntry(id: string): Promise<boolean>;\n publishEntry(id: string): Promise<boolean>;\n unpublishEntry(id: string): Promise<boolean>;\n moveEntry(id: string, folderId: string): Promise<boolean>;\n /**\n * Resolves to `false` when the user cancels the confirmation dialog.\n */\n duplicateEntry(entry: CmsContentEntry): Promise<IDuplicateEntryResult | false>;\n\n init(config?: IContentEntriesInitConfig): void;\n dispose(): void;\n}\n\nexport const ContentEntriesPresenter =\n createAbstraction<IContentEntriesPresenter>(\"ContentEntriesPresenter\");\n\nexport namespace ContentEntriesPresenter {\n export type Interface = IContentEntriesPresenter;\n export type ViewModel = IContentEntriesViewModel;\n export type InitConfig = IContentEntriesInitConfig;\n export type DuplicateEntryResult = IDuplicateEntryResult;\n}\n"],"names":["ContentEntriesPresenter","createAbstraction"],"mappings":";AA6CO,MAAMA,0BACTC,kBAA4C"}
@@ -1,12 +1,23 @@
1
+ import { GetModelUseCase } from "../../../features/model/getModel/abstractions.js";
2
+ import { GetEntryUseCase } from "../../../features/contentEntry/getEntry/abstractions.js";
3
+ import type { CmsReferenceValue } from "../../../features/contentEntry/refTypes.js";
1
4
  import { type ILivePreviewPresenter, type PreviewComponent } from "./abstractions.js";
5
+ import type { RefValuesMap } from "./resolvePreviewUrl.js";
2
6
  declare class LivePreviewPresenterImpl implements ILivePreviewPresenter {
7
+ private readonly getModelUseCase;
8
+ private readonly getEntryUseCase;
3
9
  private components;
4
- constructor();
10
+ private refValues;
11
+ private requestedRefs;
12
+ constructor(getModelUseCase: GetModelUseCase.Interface, getEntryUseCase: GetEntryUseCase.Interface);
5
13
  get vm(): {
6
14
  components: PreviewComponent[];
15
+ refValues: RefValuesMap;
7
16
  };
8
17
  addComponent(component: PreviewComponent): void;
9
18
  clearComponents(): void;
19
+ loadRefValues(refs: CmsReferenceValue[]): void;
20
+ private loadRef;
10
21
  }
11
22
  export declare const LivePreviewPresenter: typeof LivePreviewPresenterImpl & {
12
23
  __abstraction: import("@webiny/di").Abstraction<ILivePreviewPresenter>;
@@ -1,15 +1,25 @@
1
- import { computed, makeAutoObservable } from "mobx";
1
+ import { computed, makeAutoObservable, runInAction } from "mobx";
2
+ import { GetModelUseCase } from "../../../features/model/getModel/abstractions.js";
3
+ import { GetEntryUseCase } from "../../../features/contentEntry/getEntry/abstractions.js";
2
4
  import { LivePreviewPresenter } from "./abstractions.js";
3
5
  class LivePreviewPresenterImpl {
4
- constructor(){
6
+ constructor(getModelUseCase, getEntryUseCase){
7
+ this.getModelUseCase = getModelUseCase;
8
+ this.getEntryUseCase = getEntryUseCase;
5
9
  this.components = [];
10
+ this.refValues = {};
11
+ this.requestedRefs = new Set();
6
12
  makeAutoObservable(this, {
7
- vm: computed
13
+ vm: computed,
14
+ getModelUseCase: false,
15
+ getEntryUseCase: false,
16
+ requestedRefs: false
8
17
  });
9
18
  }
10
19
  get vm() {
11
20
  return {
12
- components: this.components
21
+ components: this.components,
22
+ refValues: this.refValues
13
23
  };
14
24
  }
15
25
  addComponent(component) {
@@ -23,10 +33,43 @@ class LivePreviewPresenterImpl {
23
33
  clearComponents() {
24
34
  this.components = [];
25
35
  }
36
+ loadRefValues(refs) {
37
+ for (const ref of refs)if (!this.requestedRefs.has(ref.id)) {
38
+ this.requestedRefs.add(ref.id);
39
+ this.loadRef(ref);
40
+ }
41
+ }
42
+ async loadRef(ref) {
43
+ try {
44
+ const model = await this.getModelUseCase.execute({
45
+ modelId: ref.modelId
46
+ });
47
+ const entry = await this.getEntryUseCase.execute({
48
+ model,
49
+ id: ref.id
50
+ });
51
+ runInAction(()=>{
52
+ this.refValues = {
53
+ ...this.refValues,
54
+ [ref.id]: entry.values ?? {}
55
+ };
56
+ });
57
+ } catch {
58
+ runInAction(()=>{
59
+ this.refValues = {
60
+ ...this.refValues,
61
+ [ref.id]: null
62
+ };
63
+ });
64
+ }
65
+ }
26
66
  }
27
67
  const LivePreviewPresenter_LivePreviewPresenter = LivePreviewPresenter.createImplementation({
28
68
  implementation: LivePreviewPresenterImpl,
29
- dependencies: []
69
+ dependencies: [
70
+ GetModelUseCase,
71
+ GetEntryUseCase
72
+ ]
30
73
  });
31
74
  export { LivePreviewPresenter_LivePreviewPresenter as LivePreviewPresenter };
32
75
 
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/contentEntries/preview/LivePreviewPresenter.js","sources":["../../../../src/presentation/contentEntries/preview/LivePreviewPresenter.ts"],"sourcesContent":["import { makeAutoObservable, computed } from \"mobx\";\nimport {\n LivePreviewPresenter as Abstraction,\n type ILivePreviewPresenter,\n type PreviewComponent\n} from \"./abstractions.js\";\n\nclass LivePreviewPresenterImpl implements ILivePreviewPresenter {\n private components: PreviewComponent[] = [];\n\n constructor() {\n makeAutoObservable(this, { vm: computed });\n }\n\n get vm() {\n return {\n components: this.components\n };\n }\n\n addComponent(component: PreviewComponent): void {\n const exists = this.components.some(c => c.name === component.name);\n if (exists) {\n this.components = this.components.map(c => (c.name === component.name ? component : c));\n } else {\n this.components = [...this.components, component];\n }\n }\n\n clearComponents(): void {\n this.components = [];\n }\n}\n\nexport const LivePreviewPresenter = Abstraction.createImplementation({\n implementation: LivePreviewPresenterImpl,\n dependencies: []\n});\n"],"names":["LivePreviewPresenterImpl","makeAutoObservable","computed","component","exists","c","LivePreviewPresenter","Abstraction"],"mappings":";;AAOA,MAAMA;IAGF,aAAc;aAFN,UAAU,GAAuB,EAAE;QAGvCC,mBAAmB,IAAI,EAAE;YAAE,IAAIC;QAAS;IAC5C;IAEA,IAAI,KAAK;QACL,OAAO;YACH,YAAY,IAAI,CAAC,UAAU;QAC/B;IACJ;IAEA,aAAaC,SAA2B,EAAQ;QAC5C,MAAMC,SAAS,IAAI,CAAC,UAAU,CAAC,IAAI,CAACC,CAAAA,IAAKA,EAAE,IAAI,KAAKF,UAAU,IAAI;QAClE,IAAIC,QACA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAACC,CAAAA,IAAMA,EAAE,IAAI,KAAKF,UAAU,IAAI,GAAGA,YAAYE;aAEpF,IAAI,CAAC,UAAU,GAAG;eAAI,IAAI,CAAC,UAAU;YAAEF;SAAU;IAEzD;IAEA,kBAAwB;QACpB,IAAI,CAAC,UAAU,GAAG,EAAE;IACxB;AACJ;AAEO,MAAMG,4CAAuBC,qBAAAA,oBAAgC,CAAC;IACjE,gBAAgBP;IAChB,cAAc,EAAE;AACpB"}
1
+ {"version":3,"file":"presentation/contentEntries/preview/LivePreviewPresenter.js","sources":["../../../../src/presentation/contentEntries/preview/LivePreviewPresenter.ts"],"sourcesContent":["import { makeAutoObservable, computed, runInAction } from \"mobx\";\nimport { GetModelUseCase } from \"~/features/model/getModel/abstractions.js\";\nimport { GetEntryUseCase } from \"~/features/contentEntry/getEntry/abstractions.js\";\nimport type { CmsReferenceValue } from \"~/features/contentEntry/refTypes.js\";\nimport {\n LivePreviewPresenter as Abstraction,\n type ILivePreviewPresenter,\n type PreviewComponent\n} from \"./abstractions.js\";\nimport type { RefValuesMap } from \"./resolvePreviewUrl.js\";\n\nclass LivePreviewPresenterImpl implements ILivePreviewPresenter {\n private components: PreviewComponent[] = [];\n private refValues: RefValuesMap = {};\n private requestedRefs = new Set<string>();\n\n constructor(\n private readonly getModelUseCase: GetModelUseCase.Interface,\n private readonly getEntryUseCase: GetEntryUseCase.Interface\n ) {\n makeAutoObservable<\n LivePreviewPresenterImpl,\n \"getModelUseCase\" | \"getEntryUseCase\" | \"requestedRefs\"\n >(this, {\n vm: computed,\n getModelUseCase: false,\n getEntryUseCase: false,\n requestedRefs: false\n });\n }\n\n get vm() {\n return {\n components: this.components,\n refValues: this.refValues\n };\n }\n\n addComponent(component: PreviewComponent): void {\n const exists = this.components.some(c => c.name === component.name);\n if (exists) {\n this.components = this.components.map(c => (c.name === component.name ? component : c));\n } else {\n this.components = [...this.components, component];\n }\n }\n\n clearComponents(): void {\n this.components = [];\n }\n\n loadRefValues(refs: CmsReferenceValue[]): void {\n for (const ref of refs) {\n if (this.requestedRefs.has(ref.id)) {\n continue;\n }\n this.requestedRefs.add(ref.id);\n void this.loadRef(ref);\n }\n }\n\n private async loadRef(ref: CmsReferenceValue): Promise<void> {\n try {\n const model = await this.getModelUseCase.execute({ modelId: ref.modelId });\n const entry = await this.getEntryUseCase.execute({ model, id: ref.id });\n runInAction(() => {\n this.refValues = { ...this.refValues, [ref.id]: entry.values ?? {} };\n });\n } catch {\n runInAction(() => {\n this.refValues = { ...this.refValues, [ref.id]: null };\n });\n }\n }\n}\n\nexport const LivePreviewPresenter = Abstraction.createImplementation({\n implementation: LivePreviewPresenterImpl,\n dependencies: [GetModelUseCase, GetEntryUseCase]\n});\n"],"names":["LivePreviewPresenterImpl","getModelUseCase","getEntryUseCase","Set","makeAutoObservable","computed","component","exists","c","refs","ref","model","entry","runInAction","LivePreviewPresenter","Abstraction","GetModelUseCase","GetEntryUseCase"],"mappings":";;;;AAWA,MAAMA;IAKF,YACqBC,eAA0C,EAC1CC,eAA0C,CAC7D;aAFmBD,eAAe,GAAfA;aACAC,eAAe,GAAfA;aANb,UAAU,GAAuB,EAAE;aACnC,SAAS,GAAiB,CAAC;aAC3B,aAAa,GAAG,IAAIC;QAMxBC,mBAGE,IAAI,EAAE;YACJ,IAAIC;YACJ,iBAAiB;YACjB,iBAAiB;YACjB,eAAe;QACnB;IACJ;IAEA,IAAI,KAAK;QACL,OAAO;YACH,YAAY,IAAI,CAAC,UAAU;YAC3B,WAAW,IAAI,CAAC,SAAS;QAC7B;IACJ;IAEA,aAAaC,SAA2B,EAAQ;QAC5C,MAAMC,SAAS,IAAI,CAAC,UAAU,CAAC,IAAI,CAACC,CAAAA,IAAKA,EAAE,IAAI,KAAKF,UAAU,IAAI;QAClE,IAAIC,QACA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAACC,CAAAA,IAAMA,EAAE,IAAI,KAAKF,UAAU,IAAI,GAAGA,YAAYE;aAEpF,IAAI,CAAC,UAAU,GAAG;eAAI,IAAI,CAAC,UAAU;YAAEF;SAAU;IAEzD;IAEA,kBAAwB;QACpB,IAAI,CAAC,UAAU,GAAG,EAAE;IACxB;IAEA,cAAcG,IAAyB,EAAQ;QAC3C,KAAK,MAAMC,OAAOD,KACd,KAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAACC,IAAI,EAAE;YAGjC,IAAI,CAAC,aAAa,CAAC,GAAG,CAACA,IAAI,EAAE;YACxB,IAAI,CAAC,OAAO,CAACA;;IAE1B;IAEA,MAAc,QAAQA,GAAsB,EAAiB;QACzD,IAAI;YACA,MAAMC,QAAQ,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;gBAAE,SAASD,IAAI,OAAO;YAAC;YACxE,MAAME,QAAQ,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;gBAAED;gBAAO,IAAID,IAAI,EAAE;YAAC;YACrEG,YAAY;gBACR,IAAI,CAAC,SAAS,GAAG;oBAAE,GAAG,IAAI,CAAC,SAAS;oBAAE,CAACH,IAAI,EAAE,CAAC,EAAEE,MAAM,MAAM,IAAI,CAAC;gBAAE;YACvE;QACJ,EAAE,OAAM;YACJC,YAAY;gBACR,IAAI,CAAC,SAAS,GAAG;oBAAE,GAAG,IAAI,CAAC,SAAS;oBAAE,CAACH,IAAI,EAAE,CAAC,EAAE;gBAAK;YACzD;QACJ;IACJ;AACJ;AAEO,MAAMI,4CAAuBC,qBAAAA,oBAAgC,CAAC;IACjE,gBAAgBf;IAChB,cAAc;QAACgB;QAAiBC;KAAgB;AACpD"}
@@ -0,0 +1,81 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { Container } from "@webiny/di";
3
+ import { GetModelUseCase } from "../../../features/model/getModel/abstractions.js";
4
+ import { GetEntryUseCase } from "../../../features/contentEntry/getEntry/abstractions.js";
5
+ import { LivePreviewPresenter } from "./abstractions.js";
6
+ import { LivePreviewPresenter as external_LivePreviewPresenter_js_LivePreviewPresenter } from "./LivePreviewPresenter.js";
7
+ const setup = ()=>{
8
+ const getModel = vi.fn(async ({ modelId })=>({
9
+ modelId,
10
+ fields: []
11
+ }));
12
+ const getEntry = vi.fn(async ({ id })=>{
13
+ if ("missing#0001" === id) throw new Error("Entry not found.");
14
+ return {
15
+ id,
16
+ values: {
17
+ slug: "baker"
18
+ }
19
+ };
20
+ });
21
+ const container = new Container();
22
+ container.registerInstance(GetModelUseCase, {
23
+ execute: getModel
24
+ });
25
+ container.registerInstance(GetEntryUseCase, {
26
+ execute: getEntry
27
+ });
28
+ container.register(external_LivePreviewPresenter_js_LivePreviewPresenter);
29
+ return {
30
+ presenter: container.resolve(LivePreviewPresenter),
31
+ getModel,
32
+ getEntry
33
+ };
34
+ };
35
+ describe("LivePreviewPresenter", ()=>{
36
+ it("should load each referenced entry once and expose its values", async ()=>{
37
+ const { presenter, getEntry } = setup();
38
+ const ref = {
39
+ id: "loc1#0001",
40
+ modelId: "location"
41
+ };
42
+ presenter.loadRefValues([
43
+ ref
44
+ ]);
45
+ presenter.loadRefValues([
46
+ ref
47
+ ]);
48
+ await vi.waitFor(()=>{
49
+ expect(presenter.vm.refValues[ref.id]).toEqual({
50
+ slug: "baker"
51
+ });
52
+ });
53
+ expect(getEntry).toHaveBeenCalledTimes(1);
54
+ expect(getEntry).toHaveBeenCalledWith({
55
+ model: {
56
+ modelId: "location",
57
+ fields: []
58
+ },
59
+ id: ref.id
60
+ });
61
+ });
62
+ it("should mark a ref that fails to load and not request it again", async ()=>{
63
+ const { presenter, getEntry } = setup();
64
+ const ref = {
65
+ id: "missing#0001",
66
+ modelId: "location"
67
+ };
68
+ presenter.loadRefValues([
69
+ ref
70
+ ]);
71
+ await vi.waitFor(()=>{
72
+ expect(presenter.vm.refValues[ref.id]).toBeNull();
73
+ });
74
+ presenter.loadRefValues([
75
+ ref
76
+ ]);
77
+ expect(getEntry).toHaveBeenCalledTimes(1);
78
+ });
79
+ });
80
+
81
+ //# sourceMappingURL=LivePreviewPresenter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/contentEntries/preview/LivePreviewPresenter.test.js","sources":["../../../../src/presentation/contentEntries/preview/LivePreviewPresenter.test.ts"],"sourcesContent":["import { describe, it, expect, vi } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { GetModelUseCase } from \"~/features/model/getModel/abstractions.js\";\nimport { GetEntryUseCase } from \"~/features/contentEntry/getEntry/abstractions.js\";\nimport { LivePreviewPresenter as Abstraction } from \"./abstractions.js\";\nimport { LivePreviewPresenter } from \"./LivePreviewPresenter.js\";\n\nconst setup = () => {\n const getModel = vi.fn(async ({ modelId }: { modelId: string }) => ({ modelId, fields: [] }));\n const getEntry = vi.fn(async ({ id }: { id: string }) => {\n if (id === \"missing#0001\") {\n throw new Error(\"Entry not found.\");\n }\n return { id, values: { slug: \"baker\" } };\n });\n\n const container = new Container();\n container.registerInstance(GetModelUseCase, {\n execute: getModel\n } as unknown as GetModelUseCase.Interface);\n container.registerInstance(GetEntryUseCase, {\n execute: getEntry\n } as unknown as GetEntryUseCase.Interface);\n container.register(LivePreviewPresenter);\n\n return { presenter: container.resolve(Abstraction), getModel, getEntry };\n};\n\ndescribe(\"LivePreviewPresenter\", () => {\n it(\"should load each referenced entry once and expose its values\", async () => {\n const { presenter, getEntry } = setup();\n const ref = { id: \"loc1#0001\", modelId: \"location\" };\n\n presenter.loadRefValues([ref]);\n presenter.loadRefValues([ref]);\n\n await vi.waitFor(() => {\n expect(presenter.vm.refValues[ref.id]).toEqual({ slug: \"baker\" });\n });\n expect(getEntry).toHaveBeenCalledTimes(1);\n expect(getEntry).toHaveBeenCalledWith({\n model: { modelId: \"location\", fields: [] },\n id: ref.id\n });\n });\n\n it(\"should mark a ref that fails to load and not request it again\", async () => {\n const { presenter, getEntry } = setup();\n const ref = { id: \"missing#0001\", modelId: \"location\" };\n\n presenter.loadRefValues([ref]);\n\n await vi.waitFor(() => {\n expect(presenter.vm.refValues[ref.id]).toBeNull();\n });\n\n presenter.loadRefValues([ref]);\n expect(getEntry).toHaveBeenCalledTimes(1);\n });\n});\n"],"names":["setup","getModel","vi","modelId","getEntry","id","Error","container","Container","GetModelUseCase","GetEntryUseCase","LivePreviewPresenter","Abstraction","describe","it","presenter","ref","expect"],"mappings":";;;;;;AAOA,MAAMA,QAAQ;IACV,MAAMC,WAAWC,GAAG,EAAE,CAAC,OAAO,EAAEC,OAAO,EAAuB,GAAM;YAAEA;YAAS,QAAQ,EAAE;QAAC;IAC1F,MAAMC,WAAWF,GAAG,EAAE,CAAC,OAAO,EAAEG,EAAE,EAAkB;QAChD,IAAIA,AAAO,mBAAPA,IACA,MAAM,IAAIC,MAAM;QAEpB,OAAO;YAAED;YAAI,QAAQ;gBAAE,MAAM;YAAQ;QAAE;IAC3C;IAEA,MAAME,YAAY,IAAIC;IACtBD,UAAU,gBAAgB,CAACE,iBAAiB;QACxC,SAASR;IACb;IACAM,UAAU,gBAAgB,CAACG,iBAAiB;QACxC,SAASN;IACb;IACAG,UAAU,QAAQ,CAACI;IAEnB,OAAO;QAAE,WAAWJ,UAAU,OAAO,CAACK;QAAcX;QAAUG;IAAS;AAC3E;AAEAS,SAAS,wBAAwB;IAC7BC,GAAG,gEAAgE;QAC/D,MAAM,EAAEC,SAAS,EAAEX,QAAQ,EAAE,GAAGJ;QAChC,MAAMgB,MAAM;YAAE,IAAI;YAAa,SAAS;QAAW;QAEnDD,UAAU,aAAa,CAAC;YAACC;SAAI;QAC7BD,UAAU,aAAa,CAAC;YAACC;SAAI;QAE7B,MAAMd,GAAG,OAAO,CAAC;YACbe,OAAOF,UAAU,EAAE,CAAC,SAAS,CAACC,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC;gBAAE,MAAM;YAAQ;QACnE;QACAC,OAAOb,UAAU,qBAAqB,CAAC;QACvCa,OAAOb,UAAU,oBAAoB,CAAC;YAClC,OAAO;gBAAE,SAAS;gBAAY,QAAQ,EAAE;YAAC;YACzC,IAAIY,IAAI,EAAE;QACd;IACJ;IAEAF,GAAG,iEAAiE;QAChE,MAAM,EAAEC,SAAS,EAAEX,QAAQ,EAAE,GAAGJ;QAChC,MAAMgB,MAAM;YAAE,IAAI;YAAgB,SAAS;QAAW;QAEtDD,UAAU,aAAa,CAAC;YAACC;SAAI;QAE7B,MAAMd,GAAG,OAAO,CAAC;YACbe,OAAOF,UAAU,EAAE,CAAC,SAAS,CAACC,IAAI,EAAE,CAAC,EAAE,QAAQ;QACnD;QAEAD,UAAU,aAAa,CAAC;YAACC;SAAI;QAC7BC,OAAOb,UAAU,qBAAqB,CAAC;IAC3C;AACJ"}
@@ -20,7 +20,7 @@ const ModelEditorComponentDiscovery = ContentModelEditor.createDecorator((Origin
20
20
  }, [
21
21
  presenter
22
22
  ]);
23
- return /*#__PURE__*/ react.createElement(react.Fragment, null, previewPath ? /*#__PURE__*/ react.createElement(ComponentDiscoveryIframe, {
23
+ return /*#__PURE__*/ react.createElement(react.Fragment, null, previewPath && previewDomain ? /*#__PURE__*/ react.createElement(ComponentDiscoveryIframe, {
24
24
  domain: previewDomain,
25
25
  previewPath: previewPath
26
26
  }) : null, /*#__PURE__*/ react.createElement(Original, null));
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/contentEntries/preview/ModelEditorComponentDiscovery.js","sources":["../../../../src/presentation/contentEntries/preview/ModelEditorComponentDiscovery.tsx"],"sourcesContent":["import React, { useEffect } from \"react\";\nimport { ContentModelEditor } from \"~/admin/components/ContentModelEditor/ContentModelEditor.js\";\nimport { useModelEditor } from \"~/admin/components/ContentModelEditor/useModelEditor.js\";\nimport { usePreviewDomain } from \"@webiny/frontend-settings/exports/admin.js\";\nimport { ComponentDiscoveryIframe } from \"./ComponentDiscoveryIframe.js\";\nimport { useLivePreviewPresenter } from \"./useLivePreviewPresenter.js\";\n\nexport const ModelEditorComponentDiscovery = ContentModelEditor.createDecorator(Original => {\n return function ModelEditorWithDiscovery() {\n const { data } = useModelEditor();\n const presenter = useLivePreviewPresenter();\n const previewPath = data?.settings?.previewPath as string | undefined;\n const { previewDomain } = usePreviewDomain();\n\n useEffect(() => {\n if (!previewPath) {\n presenter.clearComponents();\n }\n }, [previewPath, presenter]);\n\n useEffect(() => {\n return () => {\n presenter.clearComponents();\n };\n }, [presenter]);\n\n return (\n <>\n {previewPath ? (\n <ComponentDiscoveryIframe domain={previewDomain} previewPath={previewPath} />\n ) : null}\n <Original />\n </>\n );\n };\n});\n"],"names":["ModelEditorComponentDiscovery","ContentModelEditor","Original","data","useModelEditor","presenter","useLivePreviewPresenter","previewPath","previewDomain","usePreviewDomain","useEffect","ComponentDiscoveryIframe"],"mappings":";;;;;;AAOO,MAAMA,gCAAgCC,mBAAmB,eAAe,CAACC,CAAAA,WACrE;QACH,MAAM,EAAEC,IAAI,EAAE,GAAGC;QACjB,MAAMC,YAAYC;QAClB,MAAMC,cAAcJ,MAAM,UAAU;QACpC,MAAM,EAAEK,aAAa,EAAE,GAAGC;QAE1BC,UAAU;YACN,IAAI,CAACH,aACDF,UAAU,eAAe;QAEjC,GAAG;YAACE;YAAaF;SAAU;QAE3BK,UAAU,IACC;gBACHL,UAAU,eAAe;YAC7B,GACD;YAACA;SAAU;QAEd,OAAO,WAAP,GACI,0CACKE,cAAc,WAAdA,GACG,oBAACI,0BAAwBA;YAAC,QAAQH;YAAe,aAAaD;aAC9D,oBACJ,oBAACL,UAAAA;IAGb"}
1
+ {"version":3,"file":"presentation/contentEntries/preview/ModelEditorComponentDiscovery.js","sources":["../../../../src/presentation/contentEntries/preview/ModelEditorComponentDiscovery.tsx"],"sourcesContent":["import React, { useEffect } from \"react\";\nimport { ContentModelEditor } from \"~/admin/components/ContentModelEditor/ContentModelEditor.js\";\nimport { useModelEditor } from \"~/admin/components/ContentModelEditor/useModelEditor.js\";\nimport { usePreviewDomain } from \"@webiny/frontend-settings/exports/admin.js\";\nimport { ComponentDiscoveryIframe } from \"./ComponentDiscoveryIframe.js\";\nimport { useLivePreviewPresenter } from \"./useLivePreviewPresenter.js\";\n\nexport const ModelEditorComponentDiscovery = ContentModelEditor.createDecorator(Original => {\n return function ModelEditorWithDiscovery() {\n const { data } = useModelEditor();\n const presenter = useLivePreviewPresenter();\n const previewPath = data?.settings?.previewPath as string | undefined;\n const { previewDomain } = usePreviewDomain();\n\n useEffect(() => {\n if (!previewPath) {\n presenter.clearComponents();\n }\n }, [previewPath, presenter]);\n\n useEffect(() => {\n return () => {\n presenter.clearComponents();\n };\n }, [presenter]);\n\n return (\n <>\n {previewPath && previewDomain ? (\n <ComponentDiscoveryIframe domain={previewDomain} previewPath={previewPath} />\n ) : null}\n <Original />\n </>\n );\n };\n});\n"],"names":["ModelEditorComponentDiscovery","ContentModelEditor","Original","data","useModelEditor","presenter","useLivePreviewPresenter","previewPath","previewDomain","usePreviewDomain","useEffect","ComponentDiscoveryIframe"],"mappings":";;;;;;AAOO,MAAMA,gCAAgCC,mBAAmB,eAAe,CAACC,CAAAA,WACrE;QACH,MAAM,EAAEC,IAAI,EAAE,GAAGC;QACjB,MAAMC,YAAYC;QAClB,MAAMC,cAAcJ,MAAM,UAAU;QACpC,MAAM,EAAEK,aAAa,EAAE,GAAGC;QAE1BC,UAAU;YACN,IAAI,CAACH,aACDF,UAAU,eAAe;QAEjC,GAAG;YAACE;YAAaF;SAAU;QAE3BK,UAAU,IACC;gBACHL,UAAU,eAAe;YAC7B,GACD;YAACA;SAAU;QAEd,OAAO,WAAP,GACI,0CACKE,eAAeC,gBAAgB,WAAhBA,GACZ,oBAACG,0BAAwBA;YAAC,QAAQH;YAAe,aAAaD;aAC9D,oBACJ,oBAACL,UAAAA;IAGb"}
@@ -1,16 +1,19 @@
1
- import react from "react";
1
+ import react, { useEffect } from "react";
2
2
  import { createReactiveComponent } from "@webiny/app-admin";
3
3
  import { LeftPanel, RightPanel, SplitView } from "@webiny/app-admin/components/SplitView/SplitView.js";
4
4
  import { usePreviewDomain } from "@webiny/frontend-settings/exports/admin.js";
5
5
  import { ContentEntryFormContent } from "../views/layout/ContentEntryFormContent.js";
6
6
  import { useContentEntryFormPresenter } from "../form/useContentEntryFormPresenter.js";
7
7
  import { PreviewPane } from "./PreviewPane.js";
8
+ import { PreviewDomainStatus } from "./PreviewDomainStatus.js";
9
+ import { useLivePreviewPresenter } from "./useLivePreviewPresenter.js";
10
+ import { getPatternRefFieldIds, getRefValues, withRefValues } from "./resolvePreviewUrl.js";
8
11
  const PreviewDecorator = ContentEntryFormContent.createDecorator((Original)=>createReactiveComponent((props)=>{
9
12
  const presenter = useContentEntryFormPresenter();
13
+ const livePreview = useLivePreviewPresenter();
10
14
  const model = presenter.vm.model;
11
15
  const previewPath = model?.settings?.previewPath;
12
- const { previewDomain } = usePreviewDomain();
13
- if (!previewPath) return /*#__PURE__*/ react.createElement(Original, props);
16
+ const domain = usePreviewDomain();
14
17
  const form = presenter.vm.form;
15
18
  const entry = presenter.vm.entry;
16
19
  const formValues = form ? form.getData() : null;
@@ -18,6 +21,16 @@ const PreviewDecorator = ContentEntryFormContent.createDecorator((Original)=>cre
18
21
  ...entry,
19
22
  values: formValues
20
23
  } : null;
24
+ const refFieldIds = previewPath && model ? getPatternRefFieldIds(previewPath, model.fields) : [];
25
+ const refs = formValues ? getRefValues(formValues, refFieldIds) : [];
26
+ const refsKey = refs.map((ref)=>ref.id).join(",");
27
+ useEffect(()=>{
28
+ if (refs.length > 0) livePreview.loadRefValues(refs);
29
+ }, [
30
+ refsKey
31
+ ]);
32
+ if (!previewPath) return /*#__PURE__*/ react.createElement(Original, props);
33
+ const urlEntryData = entryData ? withRefValues(entryData, refFieldIds, livePreview.vm.refValues) : null;
21
34
  const entryId = entry?.id || "new";
22
35
  return /*#__PURE__*/ react.createElement(SplitView, {
23
36
  namespace: "cms-live-preview",
@@ -37,11 +50,17 @@ const PreviewDecorator = ContentEntryFormContent.createDecorator((Original)=>cre
37
50
  style: {
38
51
  overflowY: "hidden"
39
52
  }
40
- }, /*#__PURE__*/ react.createElement(PreviewPane, {
41
- domain: previewDomain,
53
+ }, domain.previewDomain ? /*#__PURE__*/ react.createElement(PreviewPane, {
54
+ domain: domain.previewDomain,
55
+ settingsDomain: domain.isOverridden ? domain.settingsDomain : null,
56
+ onResetDomain: domain.unsetPreviewDomain,
42
57
  previewPath: previewPath,
43
58
  entryId: entryId,
44
- entryData: entryData
59
+ entryData: entryData,
60
+ urlEntryData: urlEntryData
61
+ }) : /*#__PURE__*/ react.createElement(PreviewDomainStatus, {
62
+ error: domain.error,
63
+ onRetry: domain.retry
45
64
  })));
46
65
  }));
47
66
  export { PreviewDecorator };
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/contentEntries/preview/PreviewDecorator.js","sources":["../../../../src/presentation/contentEntries/preview/PreviewDecorator.tsx"],"sourcesContent":["import React from \"react\";\nimport { createReactiveComponent } from \"@webiny/app-admin\";\nimport {\n SplitView,\n LeftPanel,\n RightPanel\n} from \"@webiny/app-admin/components/SplitView/SplitView.js\";\nimport { usePreviewDomain } from \"@webiny/frontend-settings/exports/admin.js\";\nimport { ContentEntryFormContent } from \"~/presentation/contentEntries/views/layout/ContentEntryFormContent.js\";\nimport { useContentEntryFormPresenter } from \"~/presentation/contentEntries/form/useContentEntryFormPresenter.js\";\nimport { PreviewPane } from \"./PreviewPane.js\";\n\nexport const PreviewDecorator = ContentEntryFormContent.createDecorator(Original => {\n return createReactiveComponent(\n (props: React.HTMLAttributes<HTMLDivElement> & { width?: string }) => {\n const presenter = useContentEntryFormPresenter();\n const model = presenter.vm.model;\n const previewPath = model?.settings?.previewPath as string | undefined;\n const { previewDomain } = usePreviewDomain();\n\n if (!previewPath) {\n return <Original {...props} />;\n }\n\n const form = presenter.vm.form;\n const entry = presenter.vm.entry;\n const formValues = form ? form.getData() : null;\n const entryData = formValues\n ? { ...entry, values: formValues as Record<string, unknown> }\n : null;\n\n const entryId = entry?.id || \"new\";\n\n return (\n <SplitView namespace={\"cms-live-preview\"} className=\"h-full\">\n <LeftPanel span={5} minSize={20} className=\"bg-white overflow-y-auto\">\n <Original\n {...props}\n width={\"100%\"}\n className={\"!pt-0 [&>div]:!rounded-none\"}\n />\n </LeftPanel>\n <RightPanel\n span={7}\n minSize={20}\n className=\"overflow-hidden p-md\"\n style={{ overflowY: \"hidden\" }}\n >\n <PreviewPane\n domain={previewDomain}\n previewPath={previewPath}\n entryId={entryId}\n entryData={entryData}\n />\n </RightPanel>\n </SplitView>\n );\n }\n );\n});\n"],"names":["PreviewDecorator","ContentEntryFormContent","Original","createReactiveComponent","props","presenter","useContentEntryFormPresenter","model","previewPath","previewDomain","usePreviewDomain","form","entry","formValues","entryData","entryId","SplitView","LeftPanel","RightPanel","PreviewPane"],"mappings":";;;;;;;AAYO,MAAMA,mBAAmBC,wBAAwB,eAAe,CAACC,CAAAA,WAC7DC,wBACH,CAACC;QACG,MAAMC,YAAYC;QAClB,MAAMC,QAAQF,UAAU,EAAE,CAAC,KAAK;QAChC,MAAMG,cAAcD,OAAO,UAAU;QACrC,MAAM,EAAEE,aAAa,EAAE,GAAGC;QAE1B,IAAI,CAACF,aACD,OAAO,WAAP,GAAO,oBAACN,UAAaE;QAGzB,MAAMO,OAAON,UAAU,EAAE,CAAC,IAAI;QAC9B,MAAMO,QAAQP,UAAU,EAAE,CAAC,KAAK;QAChC,MAAMQ,aAAaF,OAAOA,KAAK,OAAO,KAAK;QAC3C,MAAMG,YAAYD,aACZ;YAAE,GAAGD,KAAK;YAAE,QAAQC;QAAsC,IAC1D;QAEN,MAAME,UAAUH,OAAO,MAAM;QAE7B,OAAO,WAAP,GACI,oBAACI,WAASA;YAAC,WAAW;YAAoB,WAAU;yBAChD,oBAACC,WAASA;YAAC,MAAM;YAAG,SAAS;YAAI,WAAU;yBACvC,oBAACf,UAAAA;YACI,GAAGE,KAAK;YACT,OAAO;YACP,WAAW;2BAGnB,oBAACc,YAAUA;YACP,MAAM;YACN,SAAS;YACT,WAAU;YACV,OAAO;gBAAE,WAAW;YAAS;yBAE7B,oBAACC,aAAWA;YACR,QAAQV;YACR,aAAaD;YACb,SAASO;YACT,WAAWD;;IAK/B"}
1
+ {"version":3,"file":"presentation/contentEntries/preview/PreviewDecorator.js","sources":["../../../../src/presentation/contentEntries/preview/PreviewDecorator.tsx"],"sourcesContent":["import React, { useEffect } from \"react\";\nimport { createReactiveComponent } from \"@webiny/app-admin\";\nimport {\n SplitView,\n LeftPanel,\n RightPanel\n} from \"@webiny/app-admin/components/SplitView/SplitView.js\";\nimport { usePreviewDomain } from \"@webiny/frontend-settings/exports/admin.js\";\nimport { ContentEntryFormContent } from \"~/presentation/contentEntries/views/layout/ContentEntryFormContent.js\";\nimport { useContentEntryFormPresenter } from \"~/presentation/contentEntries/form/useContentEntryFormPresenter.js\";\nimport { PreviewPane } from \"./PreviewPane.js\";\nimport { PreviewDomainStatus } from \"./PreviewDomainStatus.js\";\nimport { useLivePreviewPresenter } from \"./useLivePreviewPresenter.js\";\nimport { getPatternRefFieldIds, getRefValues, withRefValues } from \"./resolvePreviewUrl.js\";\n\nexport const PreviewDecorator = ContentEntryFormContent.createDecorator(Original => {\n return createReactiveComponent(\n (props: React.HTMLAttributes<HTMLDivElement> & { width?: string }) => {\n const presenter = useContentEntryFormPresenter();\n const livePreview = useLivePreviewPresenter();\n const model = presenter.vm.model;\n const previewPath = model?.settings?.previewPath as string | undefined;\n const domain = usePreviewDomain();\n\n const form = presenter.vm.form;\n const entry = presenter.vm.entry;\n const formValues = form ? (form.getData() as Record<string, unknown>) : null;\n const entryData = formValues ? { ...entry, values: formValues } : null;\n\n const refFieldIds =\n previewPath && model ? getPatternRefFieldIds(previewPath, model.fields) : [];\n const refs = formValues ? getRefValues(formValues, refFieldIds) : [];\n const refsKey = refs.map(ref => ref.id).join(\",\");\n\n useEffect(() => {\n if (refs.length > 0) {\n livePreview.loadRefValues(refs);\n }\n }, [refsKey]);\n\n if (!previewPath) {\n return <Original {...props} />;\n }\n\n // Only the preview URL gets the referenced values; the iframe receives the raw form data.\n const urlEntryData = entryData\n ? withRefValues(entryData, refFieldIds, livePreview.vm.refValues)\n : null;\n\n const entryId = entry?.id || \"new\";\n\n return (\n <SplitView namespace={\"cms-live-preview\"} className=\"h-full\">\n <LeftPanel span={5} minSize={20} className=\"bg-white overflow-y-auto\">\n <Original\n {...props}\n width={\"100%\"}\n className={\"!pt-0 [&>div]:!rounded-none\"}\n />\n </LeftPanel>\n <RightPanel\n span={7}\n minSize={20}\n className=\"overflow-hidden p-md\"\n style={{ overflowY: \"hidden\" }}\n >\n {domain.previewDomain ? (\n <PreviewPane\n domain={domain.previewDomain}\n settingsDomain={domain.isOverridden ? domain.settingsDomain : null}\n onResetDomain={domain.unsetPreviewDomain}\n previewPath={previewPath}\n entryId={entryId}\n entryData={entryData}\n urlEntryData={urlEntryData}\n />\n ) : (\n <PreviewDomainStatus error={domain.error} onRetry={domain.retry} />\n )}\n </RightPanel>\n </SplitView>\n );\n }\n );\n});\n"],"names":["PreviewDecorator","ContentEntryFormContent","Original","createReactiveComponent","props","presenter","useContentEntryFormPresenter","livePreview","useLivePreviewPresenter","model","previewPath","domain","usePreviewDomain","form","entry","formValues","entryData","refFieldIds","getPatternRefFieldIds","refs","getRefValues","refsKey","ref","useEffect","urlEntryData","withRefValues","entryId","SplitView","LeftPanel","RightPanel","PreviewPane","PreviewDomainStatus"],"mappings":";;;;;;;;;;AAeO,MAAMA,mBAAmBC,wBAAwB,eAAe,CAACC,CAAAA,WAC7DC,wBACH,CAACC;QACG,MAAMC,YAAYC;QAClB,MAAMC,cAAcC;QACpB,MAAMC,QAAQJ,UAAU,EAAE,CAAC,KAAK;QAChC,MAAMK,cAAcD,OAAO,UAAU;QACrC,MAAME,SAASC;QAEf,MAAMC,OAAOR,UAAU,EAAE,CAAC,IAAI;QAC9B,MAAMS,QAAQT,UAAU,EAAE,CAAC,KAAK;QAChC,MAAMU,aAAaF,OAAQA,KAAK,OAAO,KAAiC;QACxE,MAAMG,YAAYD,aAAa;YAAE,GAAGD,KAAK;YAAE,QAAQC;QAAW,IAAI;QAElE,MAAME,cACFP,eAAeD,QAAQS,sBAAsBR,aAAaD,MAAM,MAAM,IAAI,EAAE;QAChF,MAAMU,OAAOJ,aAAaK,aAAaL,YAAYE,eAAe,EAAE;QACpE,MAAMI,UAAUF,KAAK,GAAG,CAACG,CAAAA,MAAOA,IAAI,EAAE,EAAE,IAAI,CAAC;QAE7CC,UAAU;YACN,IAAIJ,KAAK,MAAM,GAAG,GACdZ,YAAY,aAAa,CAACY;QAElC,GAAG;YAACE;SAAQ;QAEZ,IAAI,CAACX,aACD,OAAO,WAAP,GAAO,oBAACR,UAAaE;QAIzB,MAAMoB,eAAeR,YACfS,cAAcT,WAAWC,aAAaV,YAAY,EAAE,CAAC,SAAS,IAC9D;QAEN,MAAMmB,UAAUZ,OAAO,MAAM;QAE7B,OAAO,WAAP,GACI,oBAACa,WAASA;YAAC,WAAW;YAAoB,WAAU;yBAChD,oBAACC,WAASA;YAAC,MAAM;YAAG,SAAS;YAAI,WAAU;yBACvC,oBAAC1B,UAAAA;YACI,GAAGE,KAAK;YACT,OAAO;YACP,WAAW;2BAGnB,oBAACyB,YAAUA;YACP,MAAM;YACN,SAAS;YACT,WAAU;YACV,OAAO;gBAAE,WAAW;YAAS;WAE5BlB,OAAO,aAAa,GAAG,WAAH,GACjB,oBAACmB,aAAWA;YACR,QAAQnB,OAAO,aAAa;YAC5B,gBAAgBA,OAAO,YAAY,GAAGA,OAAO,cAAc,GAAG;YAC9D,eAAeA,OAAO,kBAAkB;YACxC,aAAaD;YACb,SAASgB;YACT,WAAWV;YACX,cAAcQ;2BAGlB,oBAACO,qBAAmBA;YAAC,OAAOpB,OAAO,KAAK;YAAE,SAASA,OAAO,KAAK;;IAKnF"}
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ interface PreviewDomainStatusProps {
3
+ error: string | null;
4
+ onRetry: () => void;
5
+ }
6
+ /**
7
+ * Shown in place of the preview while the Frontend Domain setting loads, or when it fails to load.
8
+ */
9
+ export declare const PreviewDomainStatus: ({ error, onRetry }: PreviewDomainStatusProps) => React.JSX.Element;
10
+ export {};
@@ -0,0 +1,19 @@
1
+ import react from "react";
2
+ import { Alert, OverlayLoader } from "@webiny/admin-ui";
3
+ const PreviewDomainStatus = ({ error, onRetry })=>/*#__PURE__*/ react.createElement("div", {
4
+ className: "relative border border-neutral-dimmed rounded-t-lg flex flex-col flex-1 h-full overflow-hidden fill-grid"
5
+ }, error ? /*#__PURE__*/ react.createElement("div", {
6
+ className: "p-md"
7
+ }, /*#__PURE__*/ react.createElement(Alert, {
8
+ type: "danger",
9
+ variant: "subtle",
10
+ actions: /*#__PURE__*/ react.createElement(Alert.Action, {
11
+ text: "Retry",
12
+ onClick: onRetry
13
+ })
14
+ }, "Could not load the Frontend Domain setting, so the live preview cannot start. ", error)) : /*#__PURE__*/ react.createElement(OverlayLoader, {
15
+ text: "Loading preview settings..."
16
+ }));
17
+ export { PreviewDomainStatus };
18
+
19
+ //# sourceMappingURL=PreviewDomainStatus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/contentEntries/preview/PreviewDomainStatus.js","sources":["../../../../src/presentation/contentEntries/preview/PreviewDomainStatus.tsx"],"sourcesContent":["import React from \"react\";\nimport { Alert, OverlayLoader } from \"@webiny/admin-ui\";\n\ninterface PreviewDomainStatusProps {\n error: string | null;\n onRetry: () => void;\n}\n\n/**\n * Shown in place of the preview while the Frontend Domain setting loads, or when it fails to load.\n */\nexport const PreviewDomainStatus = ({ error, onRetry }: PreviewDomainStatusProps) => {\n return (\n <div className=\"relative border border-neutral-dimmed rounded-t-lg flex flex-col flex-1 h-full overflow-hidden fill-grid\">\n {error ? (\n <div className=\"p-md\">\n <Alert\n type={\"danger\"}\n variant={\"subtle\"}\n actions={<Alert.Action text={\"Retry\"} onClick={onRetry} />}\n >\n Could not load the Frontend Domain setting, so the live preview cannot\n start. {error}\n </Alert>\n </div>\n ) : (\n <OverlayLoader text=\"Loading preview settings...\" />\n )}\n </div>\n );\n};\n"],"names":["PreviewDomainStatus","error","onRetry","Alert","OverlayLoader"],"mappings":";;AAWO,MAAMA,sBAAsB,CAAC,EAAEC,KAAK,EAAEC,OAAO,EAA4B,GACrE,WAAP,GACI,oBAAC;QAAI,WAAU;OACVD,QAAQ,WAARA,GACG,oBAAC;QAAI,WAAU;qBACX,oBAACE,OAAKA;QACF,MAAM;QACN,SAAS;QACT,uBAAS,oBAACA,MAAM,MAAM;YAAC,MAAM;YAAS,SAASD;;OAClD,kFAEWD,UAAAA,WAAAA,GAIhB,oBAACG,eAAaA;QAAC,MAAK"}
@@ -1,9 +1,18 @@
1
1
  import React from "react";
2
2
  interface PreviewPaneProps {
3
3
  domain: string;
4
+ /**
5
+ * The Frontend Domain setting, passed only when the user overrides it with their own preview domain.
6
+ */
7
+ settingsDomain: string | null;
8
+ onResetDomain: () => void;
4
9
  previewPath: string;
5
10
  entryId: string;
6
11
  entryData: Record<string, unknown> | null;
12
+ /**
13
+ * Entry data used to resolve the preview path, with referenced entries' values filled in.
14
+ */
15
+ urlEntryData: Record<string, unknown> | null;
7
16
  }
8
- export declare const PreviewPane: ({ domain, previewPath, entryId, entryData }: PreviewPaneProps) => React.JSX.Element;
17
+ export declare const PreviewPane: ({ domain, settingsDomain, onResetDomain, previewPath, entryId, entryData, urlEntryData }: PreviewPaneProps) => React.JSX.Element;
9
18
  export {};
@@ -1,32 +1,29 @@
1
1
  import react, { useCallback, useEffect, useRef, useState } from "react";
2
2
  import { MessageOrigin, Messenger } from "@webiny/cms-sdk/messenger";
3
3
  import { jsonPatch } from "@webiny/cms-sdk";
4
- import { IconButton, Input, OverlayLoader, SegmentedControl } from "@webiny/admin-ui";
4
+ import { Alert, CopyButton, IconButton, OverlayLoader, SegmentedControl, Text, Tooltip, useToast } from "@webiny/admin-ui";
5
5
  import { ReactComponent } from "@webiny/icons/refresh.svg";
6
- import { ReactComponent as content_copy_svg_ReactComponent } from "@webiny/icons/content_copy.svg";
7
6
  import { ReactComponent as laptop_svg_ReactComponent } from "@webiny/icons/laptop.svg";
8
7
  import { ReactComponent as smartphone_svg_ReactComponent } from "@webiny/icons/smartphone.svg";
9
8
  import { ReactComponent as open_in_new_svg_ReactComponent } from "@webiny/icons/open_in_new.svg";
9
+ import { PreviewDomainMenu } from "@webiny/frontend-settings/exports/admin.js";
10
10
  import { useLivePreviewPresenter } from "./useLivePreviewPresenter.js";
11
11
  import { buildDisplayUrl, buildEditorUrl } from "./resolvePreviewUrl.js";
12
- const PreviewPane = ({ domain, previewPath, entryId, entryData })=>{
12
+ const READY_TIMEOUT_MS = 20000;
13
+ const PreviewPane = ({ domain, settingsDomain, onResetDomain, previewPath, entryId, entryData, urlEntryData })=>{
13
14
  const iframeRef = useRef(null);
14
15
  const messengerRef = useRef(null);
15
16
  const entryDataRef = useRef(entryData);
16
17
  const lastSentDataRef = useRef(null);
17
18
  const [ready, setReady] = useState(false);
18
19
  const [loading, setLoading] = useState(true);
20
+ const [timedOut, setTimedOut] = useState(false);
19
21
  const [iframeKey, setIframeKey] = useState(0);
20
22
  const [viewport, setViewport] = useState("desktop");
21
23
  const presenter = useLivePreviewPresenter();
24
+ const { showToast } = useToast();
22
25
  entryDataRef.current = entryData;
23
- const displayUrl = buildDisplayUrl(domain, previewPath, entryData || {});
24
- const [address, setAddress] = useState(displayUrl);
25
- useEffect(()=>{
26
- setAddress(displayUrl);
27
- }, [
28
- displayUrl
29
- ]);
26
+ const displayUrl = buildDisplayUrl(domain, previewPath, urlEntryData || {});
30
27
  const iframeSrc = (()=>{
31
28
  const editorPath = buildEditorUrl(domain, previewPath);
32
29
  const url = new URL(editorPath);
@@ -52,15 +49,21 @@ const PreviewPane = ({ domain, previewPath, entryId, entryData })=>{
52
49
  const previewTarget = new MessageOrigin(()=>iframe.contentWindow, targetOrigin);
53
50
  const messenger = new Messenger(editorOrigin, previewTarget, "wb.editor.*");
54
51
  messengerRef.current = messenger;
52
+ setLoading(true);
53
+ setTimedOut(false);
54
+ const timeout = setTimeout(()=>setTimedOut(true), READY_TIMEOUT_MS);
55
55
  messenger.on("preview.ready", ()=>{
56
+ clearTimeout(timeout);
56
57
  setReady(true);
57
58
  setLoading(false);
59
+ setTimedOut(false);
58
60
  sendEntryData();
59
61
  });
60
62
  messenger.on("preview.component.register", (manifest)=>{
61
63
  presenter.addComponent(manifest);
62
64
  });
63
65
  return ()=>{
66
+ clearTimeout(timeout);
64
67
  messenger.dispose();
65
68
  messengerRef.current = null;
66
69
  lastSentDataRef.current = null;
@@ -102,11 +105,11 @@ const PreviewPane = ({ domain, previewPath, entryId, entryData })=>{
102
105
  displayUrl,
103
106
  entryId
104
107
  ]);
105
- const copyUrl = useCallback(()=>{
106
- navigator.clipboard.writeText(getDraftUrl());
107
- }, [
108
- getDraftUrl
109
- ]);
108
+ const confirmCopy = useCallback(()=>{
109
+ showToast({
110
+ title: "Preview link copied to clipboard!"
111
+ });
112
+ }, []);
110
113
  const openInNewTab = useCallback(()=>{
111
114
  window.open(getDraftUrl(), "_blank");
112
115
  }, [
@@ -115,34 +118,51 @@ const PreviewPane = ({ domain, previewPath, entryId, entryData })=>{
115
118
  return /*#__PURE__*/ react.createElement("div", {
116
119
  className: "relative border border-neutral-dimmed rounded-t-lg flex flex-col flex-1 h-full overflow-hidden"
117
120
  }, /*#__PURE__*/ react.createElement("div", {
118
- className: "flex p-md items-center bg-white border-b border-neutral-dimmed"
121
+ className: "flex flex-row items-center gap-sm p-sm bg-neutral-base border-b-sm border-neutral-dimmed"
119
122
  }, /*#__PURE__*/ react.createElement("div", {
120
- className: "w-full"
121
- }, /*#__PURE__*/ react.createElement(Input, {
122
- value: address,
123
- onChange: setAddress,
124
- readOnly: true,
125
- size: "md",
126
- variant: "secondary",
127
- className: "bg-gray-100"
128
- })), /*#__PURE__*/ react.createElement("div", {
129
- className: "flex items-center gap-xxs ml-sm"
130
- }, /*#__PURE__*/ react.createElement(IconButton, {
131
- onClick: openInNewTab,
132
- icon: /*#__PURE__*/ react.createElement(open_in_new_svg_ReactComponent, null),
133
- variant: "ghost",
134
- size: "md"
135
- }), /*#__PURE__*/ react.createElement(IconButton, {
136
- onClick: copyUrl,
137
- icon: /*#__PURE__*/ react.createElement(content_copy_svg_ReactComponent, null),
138
- variant: "ghost",
139
- size: "sm"
140
- }), /*#__PURE__*/ react.createElement(IconButton, {
141
- onClick: reload,
142
- icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
143
- variant: "ghost",
144
- size: "sm"
145
- }), /*#__PURE__*/ react.createElement(SegmentedControl, {
123
+ className: "relative flex-auto min-w-0 h-[32px]"
124
+ }, /*#__PURE__*/ react.createElement("div", {
125
+ className: "w-full absolute -top-px py-xs-plus pl-xl pr-[112px] border-sm text-md truncate cursor-not-allowed rounded-md border-neutral-subtle bg-neutral-disabled text-neutral-disabled"
126
+ }, /*#__PURE__*/ react.createElement(PreviewDomainMenu, {
127
+ className: "absolute left-0 top-0"
128
+ }), displayUrl), /*#__PURE__*/ react.createElement("div", {
129
+ className: "absolute right-0 top-0 flex"
130
+ }, /*#__PURE__*/ react.createElement(Tooltip, {
131
+ content: /*#__PURE__*/ react.createElement(Text, {
132
+ size: "md"
133
+ }, "Refresh preview"),
134
+ side: "bottom",
135
+ trigger: /*#__PURE__*/ react.createElement(IconButton, {
136
+ icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
137
+ size: "md",
138
+ onClick: reload,
139
+ variant: "ghost"
140
+ })
141
+ }), /*#__PURE__*/ react.createElement(Tooltip, {
142
+ content: /*#__PURE__*/ react.createElement(Text, {
143
+ size: "md"
144
+ }, "Copy preview link"),
145
+ side: "bottom",
146
+ trigger: /*#__PURE__*/ react.createElement(CopyButton, {
147
+ size: "md",
148
+ value: getDraftUrl(),
149
+ onCopy: confirmCopy,
150
+ variant: "ghost"
151
+ })
152
+ }), /*#__PURE__*/ react.createElement(Tooltip, {
153
+ content: /*#__PURE__*/ react.createElement(Text, {
154
+ size: "md"
155
+ }, "Preview entry in a new tab"),
156
+ side: "bottom",
157
+ trigger: /*#__PURE__*/ react.createElement(IconButton, {
158
+ icon: /*#__PURE__*/ react.createElement(open_in_new_svg_ReactComponent, null),
159
+ size: "md",
160
+ onClick: openInNewTab,
161
+ variant: "ghost"
162
+ })
163
+ }))), /*#__PURE__*/ react.createElement("div", {
164
+ className: "shrink-0"
165
+ }, /*#__PURE__*/ react.createElement(SegmentedControl, {
146
166
  value: viewport,
147
167
  onChange: (value)=>setViewport(value),
148
168
  items: [
@@ -157,9 +177,25 @@ const PreviewPane = ({ domain, previewPath, entryId, entryData })=>{
157
177
  icon: /*#__PURE__*/ react.createElement(smartphone_svg_ReactComponent, null)
158
178
  }
159
179
  ]
160
- }))), /*#__PURE__*/ react.createElement("div", {
161
- className: "block box-border h-full w-full overflow-auto fill-grid"
162
- }, loading ? /*#__PURE__*/ react.createElement(OverlayLoader, {
180
+ }))), settingsDomain ? /*#__PURE__*/ react.createElement(Alert, {
181
+ type: "warning",
182
+ variant: "subtle",
183
+ className: "rounded-none",
184
+ actions: /*#__PURE__*/ react.createElement(Alert.Action, {
185
+ text: "Use Frontend Domain",
186
+ onClick: onResetDomain
187
+ })
188
+ }, "Previewing on your custom domain ", domain, " instead of the Frontend Domain", " ", settingsDomain, ".") : null, loading && timedOut ? /*#__PURE__*/ react.createElement(Alert, {
189
+ type: "warning",
190
+ variant: "subtle",
191
+ className: "rounded-none",
192
+ actions: /*#__PURE__*/ react.createElement(Alert.Action, {
193
+ text: "Reload",
194
+ onClick: reload
195
+ })
196
+ }, new URL(iframeSrc).origin, " is not responding to the live preview. Check that the frontend app is running at that address, that it initializes the Webiny SDK in editing mode, and that it allows this admin app as a referrer.") : null, /*#__PURE__*/ react.createElement("div", {
197
+ className: "relative block box-border h-full w-full overflow-auto fill-grid"
198
+ }, loading && !timedOut ? /*#__PURE__*/ react.createElement(OverlayLoader, {
163
199
  text: "Connecting to Live Preview..."
164
200
  }) : null, /*#__PURE__*/ react.createElement("div", {
165
201
  className: `mx-auto h-full transition-all duration-300 ${"mobile" === viewport ? "p-md" : ""}`,