@webiny/app-headless-cms 6.5.0-beta.1 → 6.5.0-beta.11

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 (202) 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/contentEntries/form/ContentEntryFormPresenter.js +34 -29
  92. package/presentation/contentEntries/form/ContentEntryFormPresenter.js.map +1 -1
  93. package/presentation/contentEntries/form/ContentEntryFormPresenter.test.d.ts +1 -0
  94. package/presentation/contentEntries/form/ContentEntryFormPresenter.test.js +210 -0
  95. package/presentation/contentEntries/form/ContentEntryFormPresenter.test.js.map +1 -0
  96. package/presentation/contentEntries/form/toFormErrors.d.ts +7 -0
  97. package/presentation/contentEntries/form/toFormErrors.js +49 -0
  98. package/presentation/contentEntries/form/toFormErrors.js.map +1 -0
  99. package/presentation/contentEntries/form/toFormErrors.test.d.ts +1 -0
  100. package/presentation/contentEntries/form/toFormErrors.test.js +175 -0
  101. package/presentation/contentEntries/form/toFormErrors.test.js.map +1 -0
  102. package/presentation/contentEntries/list/ContentEntriesPresenter.d.ts +6 -2
  103. package/presentation/contentEntries/list/ContentEntriesPresenter.js +27 -2
  104. package/presentation/contentEntries/list/ContentEntriesPresenter.js.map +1 -1
  105. package/presentation/contentEntries/list/ContentEntriesPresenter.test.js +58 -1
  106. package/presentation/contentEntries/list/ContentEntriesPresenter.test.js.map +1 -1
  107. package/presentation/contentEntries/list/abstractions.d.ts +12 -0
  108. package/presentation/contentEntries/list/abstractions.js.map +1 -1
  109. package/presentation/contentEntries/preview/LivePreviewPresenter.d.ts +12 -1
  110. package/presentation/contentEntries/preview/LivePreviewPresenter.js +48 -5
  111. package/presentation/contentEntries/preview/LivePreviewPresenter.js.map +1 -1
  112. package/presentation/contentEntries/preview/LivePreviewPresenter.test.d.ts +1 -0
  113. package/presentation/contentEntries/preview/LivePreviewPresenter.test.js +81 -0
  114. package/presentation/contentEntries/preview/LivePreviewPresenter.test.js.map +1 -0
  115. package/presentation/contentEntries/preview/ModelEditorComponentDiscovery.js +1 -1
  116. package/presentation/contentEntries/preview/ModelEditorComponentDiscovery.js.map +1 -1
  117. package/presentation/contentEntries/preview/PreviewDecorator.js +25 -6
  118. package/presentation/contentEntries/preview/PreviewDecorator.js.map +1 -1
  119. package/presentation/contentEntries/preview/PreviewDomainStatus.d.ts +10 -0
  120. package/presentation/contentEntries/preview/PreviewDomainStatus.js +19 -0
  121. package/presentation/contentEntries/preview/PreviewDomainStatus.js.map +1 -0
  122. package/presentation/contentEntries/preview/PreviewPane.d.ts +10 -1
  123. package/presentation/contentEntries/preview/PreviewPane.js +81 -45
  124. package/presentation/contentEntries/preview/PreviewPane.js.map +1 -1
  125. package/presentation/contentEntries/preview/abstractions.d.ts +8 -0
  126. package/presentation/contentEntries/preview/abstractions.js.map +1 -1
  127. package/presentation/contentEntries/preview/resolvePreviewUrl.d.ts +21 -0
  128. package/presentation/contentEntries/preview/resolvePreviewUrl.js +50 -1
  129. package/presentation/contentEntries/preview/resolvePreviewUrl.js.map +1 -1
  130. package/presentation/contentEntries/preview/resolvePreviewUrl.test.d.ts +1 -0
  131. package/presentation/contentEntries/preview/resolvePreviewUrl.test.js +127 -0
  132. package/presentation/contentEntries/preview/resolvePreviewUrl.test.js.map +1 -0
  133. package/presentation/contentEntries/singleEntry/SingleEntryPresenter.js +9 -4
  134. package/presentation/contentEntries/singleEntry/SingleEntryPresenter.js.map +1 -1
  135. package/presentation/contentEntries/singleEntry/SingleEntryPresenter.test.d.ts +1 -0
  136. package/presentation/contentEntries/singleEntry/SingleEntryPresenter.test.js +122 -0
  137. package/presentation/contentEntries/singleEntry/SingleEntryPresenter.test.js.map +1 -0
  138. package/presentation/contentEntries/trashBin/CmsTrashBin.d.ts +2 -2
  139. package/presentation/contentEntries/views/CmsAdvancedSearch.d.ts +2 -2
  140. package/presentation/contentEntries/views/ContentEntriesListLayout.d.ts +2 -2
  141. package/presentation/contentEntries/views/ContentEntryFormView.d.ts +2 -2
  142. package/presentation/contentEntries/views/OlderRevisionAlert.d.ts +2 -2
  143. package/presentation/contentEntries/views/RevisionDrawer.d.ts +2 -2
  144. package/presentation/contentEntries/views/RevisionsList.d.ts +2 -2
  145. package/presentation/contentEntries/views/SingleEntryLayout.d.ts +2 -2
  146. package/presentation/contentEntries/views/Table/Table.d.ts +2 -2
  147. package/presentation/contentEntries/views/actions/CreateNewRevisionButton.d.ts +2 -2
  148. package/presentation/contentEntries/views/actions/DeleteEntryMenuItem.d.ts +2 -2
  149. package/presentation/contentEntries/views/actions/PublishOnlyButton.d.ts +2 -2
  150. package/presentation/contentEntries/views/actions/RevisionSelector.d.ts +2 -2
  151. package/presentation/contentEntries/views/actions/SaveAndPublishButton.d.ts +2 -2
  152. package/presentation/contentEntries/views/actions/SaveContentButton.d.ts +2 -2
  153. package/presentation/contentEntries/views/actions/ShowRevisionListMenuItem.d.ts +2 -2
  154. package/presentation/contentEntries/views/layout/ContentEntryForm.d.ts +12 -12
  155. package/presentation/contentModels/ContentModelsPresenter.d.ts +5 -5
  156. package/presentation/contentModels/ContentModelsPresenter.js +1 -1
  157. package/presentation/contentModels/ContentModelsPresenter.js.map +1 -1
  158. package/presentation/contentModels/abstractions.d.ts +7 -2
  159. package/presentation/contentModels/abstractions.js.map +1 -1
  160. package/presentation/contentModels/components/CloneContentModelDialog.d.ts +2 -2
  161. package/presentation/contentModels/components/ContentModels.d.ts +2 -2
  162. package/presentation/contentModels/components/ContentModelsDataList.d.ts +2 -2
  163. package/presentation/contentModels/components/ContentModelsDataList.js +6 -5
  164. package/presentation/contentModels/components/ContentModelsDataList.js.map +1 -1
  165. package/presentation/contentModels/components/NewContentModelDialog.d.ts +2 -2
  166. package/presentation/contentModels/components/fullDelete/dialog/Content.js +2 -2
  167. package/presentation/contentModels/components/fullDelete/dialog/Content.js.map +1 -1
  168. package/presentation/contentModels/components/fullDelete/types.js.map +1 -1
  169. package/presentation/fieldRenderers/ref/autocomplete/BaseAutocompletePresenter.d.ts +1 -0
  170. package/presentation/fieldRenderers/ref/autocomplete/BaseAutocompletePresenter.js +8 -2
  171. package/presentation/fieldRenderers/ref/autocomplete/BaseAutocompletePresenter.js.map +1 -1
  172. package/presentation/fieldRenderers/ref/autocomplete/RefAutocompletePresenters.test.d.ts +1 -0
  173. package/presentation/fieldRenderers/ref/autocomplete/RefAutocompletePresenters.test.js +185 -0
  174. package/presentation/fieldRenderers/ref/autocomplete/RefAutocompletePresenters.test.js.map +1 -0
  175. package/presentation/fieldRenderers/ref/autocomplete/multi/RefMultiAutocompletePresenter.js +1 -1
  176. package/presentation/fieldRenderers/ref/autocomplete/multi/RefMultiAutocompletePresenter.js.map +1 -1
  177. package/presentation/fieldRenderers/ref/autocomplete/single/RefSingleAutocompletePresenter.js +1 -1
  178. package/presentation/fieldRenderers/ref/autocomplete/single/RefSingleAutocompletePresenter.js.map +1 -1
  179. package/presentation/fieldRenderers/ref/components/RefFieldOptions.d.ts +2 -2
  180. package/presentation/fieldRenderers/ref/components/RefFieldOptions.js +3 -2
  181. package/presentation/fieldRenderers/ref/components/RefFieldOptions.js.map +1 -1
  182. package/presentation/importContentModels/ImportContentModelsDialog.d.ts +2 -2
  183. package/presentation/importContentModels/ImportContentModelsPresenter.js +1 -1
  184. package/presentation/importContentModels/ImportContentModelsPresenter.js.map +1 -1
  185. package/presentation/importContentModels/components/DataList.d.ts +2 -2
  186. package/presentation/importContentModels/components/FileUpload.d.ts +2 -2
  187. package/presentation/importContentModels/components/FileUpload.js +1 -1
  188. package/presentation/importContentModels/components/FileUpload.js.map +1 -1
  189. package/presentation/importContentModels/components/Model/DataListModelItem.js +3 -3
  190. package/presentation/importContentModels/components/Model/DataListModelItem.js.map +1 -1
  191. package/presentation/importContentModels/components/Model/DataListModelItemInfo.js +2 -2
  192. package/presentation/importContentModels/components/Model/DataListModelItemInfo.js.map +1 -1
  193. package/presentation/importContentModels/components/Model/DataListModels.d.ts +2 -2
  194. package/presentation/menus/ContentGroupsMenuItems.d.ts +2 -2
  195. package/presentation/modelGroup/ModelGroupPresenter.js +1 -2
  196. package/presentation/modelGroup/ModelGroupPresenter.js.map +1 -1
  197. package/presentation/modelGroup/components/ContentModelGroups.d.ts +2 -2
  198. package/presentation/modelGroup/components/ContentModelGroupsDataList.d.ts +6 -2
  199. package/presentation/modelGroup/components/ContentModelGroupsForm.d.ts +8 -2
  200. package/utils/normalizeIcon.d.ts +4 -0
  201. package/utils/normalizeIcon.js +9 -6
  202. package/utils/normalizeIcon.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/contentEntries/list/ContentEntriesPresenter.js","sources":["../../../../src/presentation/contentEntries/list/ContentEntriesPresenter.ts"],"sourcesContent":["import { computed, makeAutoObservable, reaction } from \"mobx\";\nimport type { IReactionDisposer } from \"mobx\";\nimport { ListPresenter } from \"@webiny/app-admin/presentation/listPresenter/abstractions.js\";\nimport { FolderTreePresenter } from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\nimport { GetDescendantFoldersUseCase } from \"@webiny/app-aco/features/folders/getDescendantFolders/abstractions.js\";\nimport { sortFolders } from \"@webiny/app-aco\";\nimport { Confirmation } from \"@webiny/app-admin/features/confirmation/abstractions.js\";\nimport type { CmsContentEntry } from \"~/types.js\";\nimport { ListEntriesUseCase } from \"~/features/contentEntry/listEntries/abstractions.js\";\nimport { DeleteEntryUseCase } from \"~/features/contentEntry/deleteEntry/abstractions.js\";\nimport { PublishEntryUseCase } from \"~/features/contentEntry/publishEntry/abstractions.js\";\nimport { UnpublishEntryUseCase } from \"~/features/contentEntry/unpublishEntry/abstractions.js\";\nimport { MoveEntryUseCase } from \"~/features/contentEntry/moveEntry/abstractions.js\";\nimport { UpdateRevisionDescriptionUseCase } from \"~/features/contentEntry/updateRevisionDescription/abstractions.js\";\nimport {\n ContentEntriesCacheProvider,\n CmsModelContext\n} from \"~/features/contentEntry/abstractions.js\";\nimport {\n ContentEntriesPresenter as Abstraction,\n type IContentEntriesViewModel\n} from \"./abstractions.js\";\nimport { ContentEntriesDataSource } from \"./ContentEntriesDataSource.js\";\n\nexport const TRASH_ENTRY_DIALOG = \"trash-entry\";\nexport const PUBLISH_ENTRY_DIALOG = \"publish-entry\";\nexport const UNPUBLISH_ENTRY_DIALOG = \"unpublish-entry\";\n\nclass ContentEntriesPresenterImpl implements Abstraction.Interface {\n private selectedEntryId: string | null = null;\n private disposeReaction: IReactionDisposer | null = null;\n\n constructor(\n private listPresenter: ListPresenter.Interface<CmsContentEntry>,\n private foldersPresenter: FolderTreePresenter.Interface,\n private confirmation: Confirmation.Interface,\n private modelAccessor: CmsModelContext.Interface,\n private listEntriesUseCase: ListEntriesUseCase.Interface,\n private deleteEntryUseCase: DeleteEntryUseCase.Interface,\n private publishEntryUseCase: PublishEntryUseCase.Interface,\n private unpublishEntryUseCase: UnpublishEntryUseCase.Interface,\n private moveEntryUseCase: MoveEntryUseCase.Interface,\n private updateRevisionDescriptionUseCase: UpdateRevisionDescriptionUseCase.Interface,\n private cacheProvider: ContentEntriesCacheProvider.Interface,\n private getDescendantFoldersUseCase: GetDescendantFoldersUseCase.Interface\n ) {\n makeAutoObservable<\n ContentEntriesPresenterImpl,\n | \"disposeReaction\"\n | \"confirmation\"\n | \"modelAccessor\"\n | \"listEntriesUseCase\"\n | \"deleteEntryUseCase\"\n | \"publishEntryUseCase\"\n | \"unpublishEntryUseCase\"\n | \"moveEntryUseCase\"\n | \"updateRevisionDescriptionUseCase\"\n | \"cacheProvider\"\n | \"getDescendantFoldersUseCase\"\n >(this, {\n disposeReaction: false,\n confirmation: false,\n modelAccessor: false,\n listEntriesUseCase: false,\n deleteEntryUseCase: false,\n publishEntryUseCase: false,\n unpublishEntryUseCase: false,\n moveEntryUseCase: false,\n updateRevisionDescriptionUseCase: false,\n cacheProvider: false,\n getDescendantFoldersUseCase: false,\n vm: computed\n });\n }\n\n private get model() {\n return this.modelAccessor.getModel();\n }\n\n get vm(): IContentEntriesViewModel {\n const appliedQuery = this.listPresenter.vm.appliedQuery;\n const hasSearch = !!appliedQuery?.search;\n const hasFilters = Object.keys(this.listPresenter.vm.filters).some(k => k !== \"folderId\");\n const showFolders = !hasSearch && !hasFilters;\n\n const childFolders = showFolders\n ? sortFolders(this.foldersPresenter.vm.childFolders ?? [], appliedQuery?.sort)\n : [];\n\n return {\n model: this.model,\n selectedEntryId: this.selectedEntryId,\n showingEntry: this.selectedEntryId !== null,\n showFolders,\n childFolders\n };\n }\n\n init(config: Abstraction.InitConfig = {}): void {\n const initialFolderId = config.initialFolderId ?? \"root\";\n\n const cache = this.cacheProvider.get(this.model.modelId);\n const dataSource = new ContentEntriesDataSource(\n this.model,\n this.listEntriesUseCase,\n cache,\n this.getDescendantFoldersUseCase,\n config.filterNames\n );\n\n this.listPresenter.init({\n dataSource,\n initialSort: { field: \"savedOn\", direction: \"DESC\" },\n initialFilters: { folderId: initialFolderId },\n initialSearch: config.initialSearch,\n limit: 50,\n itemLabel: { singular: \"entry\", plural: \"entries\" }\n });\n\n if (initialFolderId !== \"root\") {\n this.foldersPresenter.selectFolder(initialFolderId);\n }\n\n this.disposeReaction = reaction(\n () => this.foldersPresenter.vm.currentFolderId,\n folderId => {\n const effectiveFolderId = folderId ?? \"root\";\n this.listPresenter.actions.filter.set(\"folderId\", effectiveFolderId);\n }\n );\n }\n\n get list(): ListPresenter.Interface<CmsContentEntry> {\n return this.listPresenter;\n }\n\n get folders(): FolderTreePresenter.Interface {\n return this.foldersPresenter;\n }\n\n selectEntry(id: string): void {\n this.selectedEntryId = id;\n }\n\n deselectEntry(): void {\n this.selectedEntryId = null;\n }\n\n createEntry(): void {\n this.selectedEntryId = \"new\";\n }\n\n async deleteEntry(id: string): Promise<boolean> {\n const model = this.model;\n const result = await this.confirmation.confirm(TRASH_ENTRY_DIALOG, { entryId: id }, () =>\n this.deleteEntryUseCase.execute({ model, id })\n );\n return result !== false;\n }\n\n async publishEntry(id: string): Promise<boolean> {\n const model = this.model;\n const cache = this.cacheProvider.get(model.modelId);\n const entry = cache.getItem(item => item.id === id);\n if (!entry) {\n return false;\n }\n\n const result = await this.confirmation.confirm<{ revisionDescription: string }>(\n PUBLISH_ENTRY_DIALOG,\n { entry },\n async data => {\n if (data.revisionDescription) {\n await this.updateRevisionDescriptionUseCase.execute({\n model,\n id,\n revisionDescription: data.revisionDescription\n });\n }\n await this.publishEntryUseCase.execute({ model, revisionId: id });\n }\n );\n return result !== false;\n }\n\n async unpublishEntry(id: string): Promise<boolean> {\n const model = this.model;\n const result = await this.confirmation.confirm(\n UNPUBLISH_ENTRY_DIALOG,\n { entryId: id },\n () => this.unpublishEntryUseCase.execute({ model, revisionId: id })\n );\n return result !== false;\n }\n\n async moveEntry(id: string, folderId: string): Promise<boolean> {\n await this.moveEntryUseCase.execute({ model: this.model, id, folderId });\n return true;\n }\n\n dispose(): void {\n if (this.disposeReaction) {\n this.disposeReaction();\n this.disposeReaction = null;\n }\n }\n}\n\nexport const ContentEntriesPresenter = Abstraction.createImplementation({\n implementation: ContentEntriesPresenterImpl,\n dependencies: [\n ListPresenter,\n FolderTreePresenter,\n Confirmation,\n CmsModelContext,\n ListEntriesUseCase,\n DeleteEntryUseCase,\n PublishEntryUseCase,\n UnpublishEntryUseCase,\n MoveEntryUseCase,\n UpdateRevisionDescriptionUseCase,\n ContentEntriesCacheProvider,\n GetDescendantFoldersUseCase\n ]\n});\n"],"names":["TRASH_ENTRY_DIALOG","PUBLISH_ENTRY_DIALOG","UNPUBLISH_ENTRY_DIALOG","ContentEntriesPresenterImpl","listPresenter","foldersPresenter","confirmation","modelAccessor","listEntriesUseCase","deleteEntryUseCase","publishEntryUseCase","unpublishEntryUseCase","moveEntryUseCase","updateRevisionDescriptionUseCase","cacheProvider","getDescendantFoldersUseCase","makeAutoObservable","computed","appliedQuery","hasSearch","hasFilters","Object","k","showFolders","childFolders","sortFolders","config","initialFolderId","cache","dataSource","ContentEntriesDataSource","reaction","folderId","effectiveFolderId","id","model","result","entry","item","data","ContentEntriesPresenter","Abstraction","ListPresenter","FolderTreePresenter","Confirmation","CmsModelContext","ListEntriesUseCase","DeleteEntryUseCase","PublishEntryUseCase","UnpublishEntryUseCase","MoveEntryUseCase","UpdateRevisionDescriptionUseCase","ContentEntriesCacheProvider","GetDescendantFoldersUseCase"],"mappings":"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"}
1
+ {"version":3,"file":"presentation/contentEntries/list/ContentEntriesPresenter.js","sources":["../../../../src/presentation/contentEntries/list/ContentEntriesPresenter.ts"],"sourcesContent":["import { computed, makeAutoObservable, reaction } from \"mobx\";\nimport type { IReactionDisposer } from \"mobx\";\nimport { ListPresenter } from \"@webiny/app-admin/presentation/listPresenter/abstractions.js\";\nimport { FolderTreePresenter } from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\nimport { GetDescendantFoldersUseCase } from \"@webiny/app-aco/features/folders/getDescendantFolders/abstractions.js\";\nimport { sortFolders } from \"@webiny/app-aco\";\nimport { Confirmation } from \"@webiny/app-admin/features/confirmation/abstractions.js\";\nimport type { CmsContentEntry } from \"~/types.js\";\nimport { ListEntriesUseCase } from \"~/features/contentEntry/listEntries/abstractions.js\";\nimport { DeleteEntryUseCase } from \"~/features/contentEntry/deleteEntry/abstractions.js\";\nimport { PublishEntryUseCase } from \"~/features/contentEntry/publishEntry/abstractions.js\";\nimport { UnpublishEntryUseCase } from \"~/features/contentEntry/unpublishEntry/abstractions.js\";\nimport { MoveEntryUseCase } from \"~/features/contentEntry/moveEntry/abstractions.js\";\nimport { DuplicateEntryUseCase } from \"~/features/contentEntry/duplicateEntry/abstractions.js\";\nimport { UpdateRevisionDescriptionUseCase } from \"~/features/contentEntry/updateRevisionDescription/abstractions.js\";\nimport {\n ContentEntriesCacheProvider,\n CmsModelContext\n} from \"~/features/contentEntry/abstractions.js\";\nimport {\n ContentEntriesPresenter as Abstraction,\n type IContentEntriesViewModel,\n type IDuplicateEntryResult\n} from \"./abstractions.js\";\nimport { ContentEntriesDataSource } from \"./ContentEntriesDataSource.js\";\n\nexport const TRASH_ENTRY_DIALOG = \"trash-entry\";\nexport const PUBLISH_ENTRY_DIALOG = \"publish-entry\";\nexport const UNPUBLISH_ENTRY_DIALOG = \"unpublish-entry\";\nexport const DUPLICATE_ENTRY_DIALOG = \"duplicate-entry\";\n\nclass ContentEntriesPresenterImpl implements Abstraction.Interface {\n private selectedEntryId: string | null = null;\n private disposeReaction: IReactionDisposer | null = null;\n\n constructor(\n private listPresenter: ListPresenter.Interface<CmsContentEntry>,\n private foldersPresenter: FolderTreePresenter.Interface,\n private confirmation: Confirmation.Interface,\n private modelAccessor: CmsModelContext.Interface,\n private listEntriesUseCase: ListEntriesUseCase.Interface,\n private deleteEntryUseCase: DeleteEntryUseCase.Interface,\n private publishEntryUseCase: PublishEntryUseCase.Interface,\n private unpublishEntryUseCase: UnpublishEntryUseCase.Interface,\n private moveEntryUseCase: MoveEntryUseCase.Interface,\n private duplicateEntryUseCase: DuplicateEntryUseCase.Interface,\n private updateRevisionDescriptionUseCase: UpdateRevisionDescriptionUseCase.Interface,\n private cacheProvider: ContentEntriesCacheProvider.Interface,\n private getDescendantFoldersUseCase: GetDescendantFoldersUseCase.Interface\n ) {\n makeAutoObservable<\n ContentEntriesPresenterImpl,\n | \"disposeReaction\"\n | \"confirmation\"\n | \"modelAccessor\"\n | \"listEntriesUseCase\"\n | \"deleteEntryUseCase\"\n | \"publishEntryUseCase\"\n | \"unpublishEntryUseCase\"\n | \"moveEntryUseCase\"\n | \"duplicateEntryUseCase\"\n | \"updateRevisionDescriptionUseCase\"\n | \"cacheProvider\"\n | \"getDescendantFoldersUseCase\"\n >(this, {\n disposeReaction: false,\n confirmation: false,\n modelAccessor: false,\n listEntriesUseCase: false,\n deleteEntryUseCase: false,\n publishEntryUseCase: false,\n unpublishEntryUseCase: false,\n moveEntryUseCase: false,\n duplicateEntryUseCase: false,\n updateRevisionDescriptionUseCase: false,\n cacheProvider: false,\n getDescendantFoldersUseCase: false,\n vm: computed\n });\n }\n\n private get model() {\n return this.modelAccessor.getModel();\n }\n\n get vm(): IContentEntriesViewModel {\n const appliedQuery = this.listPresenter.vm.appliedQuery;\n const hasSearch = !!appliedQuery?.search;\n const hasFilters = Object.keys(this.listPresenter.vm.filters).some(k => k !== \"folderId\");\n const showFolders = !hasSearch && !hasFilters;\n\n const childFolders = showFolders\n ? sortFolders(this.foldersPresenter.vm.childFolders ?? [], appliedQuery?.sort)\n : [];\n\n return {\n model: this.model,\n selectedEntryId: this.selectedEntryId,\n showingEntry: this.selectedEntryId !== null,\n showFolders,\n childFolders\n };\n }\n\n init(config: Abstraction.InitConfig = {}): void {\n const initialFolderId = config.initialFolderId ?? \"root\";\n\n const cache = this.cacheProvider.get(this.model.modelId);\n const dataSource = new ContentEntriesDataSource(\n this.model,\n this.listEntriesUseCase,\n cache,\n this.getDescendantFoldersUseCase,\n config.filterNames\n );\n\n this.listPresenter.init({\n dataSource,\n initialSort: { field: \"savedOn\", direction: \"DESC\" },\n initialFilters: { folderId: initialFolderId },\n initialSearch: config.initialSearch,\n limit: 50,\n itemLabel: { singular: \"entry\", plural: \"entries\" }\n });\n\n if (initialFolderId !== \"root\") {\n this.foldersPresenter.selectFolder(initialFolderId);\n }\n\n this.disposeReaction = reaction(\n () => this.foldersPresenter.vm.currentFolderId,\n folderId => {\n const effectiveFolderId = folderId ?? \"root\";\n this.listPresenter.actions.filter.set(\"folderId\", effectiveFolderId);\n }\n );\n }\n\n get list(): ListPresenter.Interface<CmsContentEntry> {\n return this.listPresenter;\n }\n\n get folders(): FolderTreePresenter.Interface {\n return this.foldersPresenter;\n }\n\n selectEntry(id: string): void {\n this.selectedEntryId = id;\n }\n\n deselectEntry(): void {\n this.selectedEntryId = null;\n }\n\n createEntry(): void {\n this.selectedEntryId = \"new\";\n }\n\n async deleteEntry(id: string): Promise<boolean> {\n const model = this.model;\n const result = await this.confirmation.confirm(TRASH_ENTRY_DIALOG, { entryId: id }, () =>\n this.deleteEntryUseCase.execute({ model, id })\n );\n return result !== false;\n }\n\n async publishEntry(id: string): Promise<boolean> {\n const model = this.model;\n const cache = this.cacheProvider.get(model.modelId);\n const entry = cache.getItem(item => item.id === id);\n if (!entry) {\n return false;\n }\n\n const result = await this.confirmation.confirm<{ revisionDescription: string }>(\n PUBLISH_ENTRY_DIALOG,\n { entry },\n async data => {\n if (data.revisionDescription) {\n await this.updateRevisionDescriptionUseCase.execute({\n model,\n id,\n revisionDescription: data.revisionDescription\n });\n }\n await this.publishEntryUseCase.execute({ model, revisionId: id });\n }\n );\n return result !== false;\n }\n\n async unpublishEntry(id: string): Promise<boolean> {\n const model = this.model;\n const result = await this.confirmation.confirm(\n UNPUBLISH_ENTRY_DIALOG,\n { entryId: id },\n () => this.unpublishEntryUseCase.execute({ model, revisionId: id })\n );\n return result !== false;\n }\n\n async moveEntry(id: string, folderId: string): Promise<boolean> {\n await this.moveEntryUseCase.execute({ model: this.model, id, folderId });\n return true;\n }\n\n async duplicateEntry(entry: CmsContentEntry): Promise<IDuplicateEntryResult | false> {\n const model = this.model;\n return this.confirmation.confirm(\n DUPLICATE_ENTRY_DIALOG,\n { entry },\n async (): Promise<IDuplicateEntryResult> => {\n try {\n const duplicate = await this.duplicateEntryUseCase.execute({\n model,\n revisionId: entry.id\n });\n return { entry: duplicate };\n } catch (error) {\n return { error: error as Error };\n }\n }\n );\n }\n\n dispose(): void {\n if (this.disposeReaction) {\n this.disposeReaction();\n this.disposeReaction = null;\n }\n }\n}\n\nexport const ContentEntriesPresenter = Abstraction.createImplementation({\n implementation: ContentEntriesPresenterImpl,\n dependencies: [\n ListPresenter,\n FolderTreePresenter,\n Confirmation,\n CmsModelContext,\n ListEntriesUseCase,\n DeleteEntryUseCase,\n PublishEntryUseCase,\n UnpublishEntryUseCase,\n MoveEntryUseCase,\n DuplicateEntryUseCase,\n UpdateRevisionDescriptionUseCase,\n ContentEntriesCacheProvider,\n GetDescendantFoldersUseCase\n ]\n});\n"],"names":["TRASH_ENTRY_DIALOG","PUBLISH_ENTRY_DIALOG","UNPUBLISH_ENTRY_DIALOG","DUPLICATE_ENTRY_DIALOG","ContentEntriesPresenterImpl","listPresenter","foldersPresenter","confirmation","modelAccessor","listEntriesUseCase","deleteEntryUseCase","publishEntryUseCase","unpublishEntryUseCase","moveEntryUseCase","duplicateEntryUseCase","updateRevisionDescriptionUseCase","cacheProvider","getDescendantFoldersUseCase","makeAutoObservable","computed","appliedQuery","hasSearch","hasFilters","Object","k","showFolders","childFolders","sortFolders","config","initialFolderId","cache","dataSource","ContentEntriesDataSource","reaction","folderId","effectiveFolderId","id","model","result","entry","item","data","duplicate","error","ContentEntriesPresenter","Abstraction","ListPresenter","FolderTreePresenter","Confirmation","CmsModelContext","ListEntriesUseCase","DeleteEntryUseCase","PublishEntryUseCase","UnpublishEntryUseCase","MoveEntryUseCase","DuplicateEntryUseCase","UpdateRevisionDescriptionUseCase","ContentEntriesCacheProvider","GetDescendantFoldersUseCase"],"mappings":"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"}
@@ -13,12 +13,14 @@ import { DeleteEntryFeature } from "../../../features/contentEntry/deleteEntry/f
13
13
  import { PublishEntryFeature } from "../../../features/contentEntry/publishEntry/feature.js";
14
14
  import { UnpublishEntryFeature } from "../../../features/contentEntry/unpublishEntry/feature.js";
15
15
  import { MoveEntryFeature } from "../../../features/contentEntry/moveEntry/feature.js";
16
+ import { DuplicateEntryFeature } from "../../../features/contentEntry/duplicateEntry/feature.js";
16
17
  import { UpdateRevisionDescriptionFeature } from "../../../features/contentEntry/updateRevisionDescription/feature.js";
17
18
  import { ListEntriesGateway } from "../../../features/contentEntry/listEntries/abstractions.js";
18
19
  import { DeleteEntryGateway } from "../../../features/contentEntry/deleteEntry/abstractions.js";
19
20
  import { PublishEntryGateway, PublishEntryUseCase } from "../../../features/contentEntry/publishEntry/abstractions.js";
20
21
  import { UnpublishEntryGateway } from "../../../features/contentEntry/unpublishEntry/abstractions.js";
21
22
  import { MoveEntryGateway } from "../../../features/contentEntry/moveEntry/abstractions.js";
23
+ import { DuplicateEntryGateway } from "../../../features/contentEntry/duplicateEntry/abstractions.js";
22
24
  import { UpdateRevisionDescriptionGateway } from "../../../features/contentEntry/updateRevisionDescription/abstractions.js";
23
25
  import { EventPublisher } from "@webiny/app/features/eventPublisher/index.js";
24
26
  import { ContentEntriesPresenter } from "./abstractions.js";
@@ -112,7 +114,7 @@ function setup() {
112
114
  container.registerInstance(FolderTreePresenter, foldersPresenter);
113
115
  container.registerInstance(Confirmation, {
114
116
  confirm: vi.fn(async (_name, _params, execute)=>{
115
- if (execute) await execute(void 0);
117
+ if (execute) return await execute(void 0);
116
118
  return true;
117
119
  })
118
120
  });
@@ -131,6 +133,7 @@ function setup() {
131
133
  PublishEntryFeature.register(container);
132
134
  UnpublishEntryFeature.register(container);
133
135
  MoveEntryFeature.register(container);
136
+ DuplicateEntryFeature.register(container);
134
137
  UpdateRevisionDescriptionFeature.register(container);
135
138
  const listEntriesGateway = {
136
139
  execute: vi.fn()
@@ -144,6 +147,10 @@ function setup() {
144
147
  container.registerInstance(ListEntriesGateway, listEntriesGateway);
145
148
  container.registerInstance(MoveEntryGateway, moveEntryGateway);
146
149
  container.registerInstance(DeleteEntryGateway, deleteEntryGateway);
150
+ const duplicateEntryGateway = {
151
+ execute: vi.fn()
152
+ };
153
+ container.registerInstance(DuplicateEntryGateway, duplicateEntryGateway);
147
154
  const publishEntryGateway = {
148
155
  execute: vi.fn()
149
156
  };
@@ -161,6 +168,7 @@ function setup() {
161
168
  listEntriesGateway,
162
169
  moveEntryGateway,
163
170
  deleteEntryGateway,
171
+ duplicateEntryGateway,
164
172
  getDescendantFolders,
165
173
  foldersPresenter,
166
174
  publishEntryGateway,
@@ -517,6 +525,55 @@ describe("ContentEntriesPresenter", ()=>{
517
525
  });
518
526
  });
519
527
  });
528
+ describe("duplicate entry", ()=>{
529
+ it("should add the duplicated entry to the current view", async ()=>{
530
+ const entries = [
531
+ createEntry("entry-2", "root", {
532
+ savedOn: "2024-01-02T00:00:00.000Z"
533
+ }),
534
+ createEntry("entry-1", "root", {
535
+ savedOn: "2024-01-01T00:00:00.000Z"
536
+ })
537
+ ];
538
+ await initPresenter(t, {
539
+ data: entries
540
+ });
541
+ const duplicate = createEntry("entry-3", "root", {
542
+ savedOn: "2024-01-03T00:00:00.000Z"
543
+ });
544
+ t.duplicateEntryGateway.execute.mockResolvedValueOnce(duplicate);
545
+ const result = await t.presenter.duplicateEntry(entries[1]);
546
+ expect(result).toEqual({
547
+ entry: duplicate
548
+ });
549
+ expect(t.duplicateEntryGateway.execute).toHaveBeenCalledWith({
550
+ model: MODEL,
551
+ revisionId: "entry-1#0001"
552
+ });
553
+ await vi.waitFor(()=>{
554
+ expect(t.presenter.list.vm.rows.map((r)=>r.entryId)).toEqual([
555
+ "entry-3",
556
+ "entry-2",
557
+ "entry-1"
558
+ ]);
559
+ });
560
+ });
561
+ it("should return the error when duplication fails", async ()=>{
562
+ const entries = [
563
+ createEntry("entry-1", "root")
564
+ ];
565
+ await initPresenter(t, {
566
+ data: entries
567
+ });
568
+ const error = new Error("Not allowed.");
569
+ t.duplicateEntryGateway.execute.mockRejectedValueOnce(error);
570
+ const result = await t.presenter.duplicateEntry(entries[0]);
571
+ expect(result).toEqual({
572
+ error
573
+ });
574
+ expect(t.presenter.list.vm.rows).toHaveLength(1);
575
+ });
576
+ });
520
577
  describe("delete entry", ()=>{
521
578
  it("should remove entry from current view after delete", async ()=>{
522
579
  const entries = [
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/contentEntries/list/ContentEntriesPresenter.test.js","sources":["../../../../src/presentation/contentEntries/list/ContentEntriesPresenter.test.ts"],"sourcesContent":["/**\n * @vitest-environment jsdom\n */\nimport { describe, it, expect, vi, beforeEach } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { makeAutoObservable } from \"mobx\";\nimport { ListPresenterFeature } from \"@webiny/app-admin/presentation/listPresenter/index.js\";\nimport { FolderTreePresenter } from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\nimport { GetDescendantFoldersUseCase } from \"@webiny/app-aco/features/folders/getDescendantFolders/abstractions.js\";\nimport { Confirmation } from \"@webiny/app-admin/features/confirmation/abstractions.js\";\nimport type { CmsContentEntry, CmsModel } from \"~/types.js\";\nimport { ContentEntriesCacheProvider } from \"~/features/contentEntry/ContentEntriesCacheProvider.js\";\nimport { CmsModelContext } from \"~/features/contentEntry/abstractions.js\";\nimport { CmsModelContext as CmsModelContextImpl } from \"~/features/contentEntry/CmsModelContext.js\";\nimport { ListEntriesFeature } from \"~/features/contentEntry/listEntries/feature.js\";\nimport { DeleteEntryFeature } from \"~/features/contentEntry/deleteEntry/feature.js\";\nimport { PublishEntryFeature } from \"~/features/contentEntry/publishEntry/feature.js\";\nimport { UnpublishEntryFeature } from \"~/features/contentEntry/unpublishEntry/feature.js\";\nimport { MoveEntryFeature } from \"~/features/contentEntry/moveEntry/feature.js\";\nimport { UpdateRevisionDescriptionFeature } from \"~/features/contentEntry/updateRevisionDescription/feature.js\";\nimport { ListEntriesGateway } from \"~/features/contentEntry/listEntries/abstractions.js\";\nimport { DeleteEntryGateway } from \"~/features/contentEntry/deleteEntry/abstractions.js\";\nimport {\n PublishEntryGateway,\n PublishEntryUseCase\n} from \"~/features/contentEntry/publishEntry/abstractions.js\";\nimport { UnpublishEntryGateway } from \"~/features/contentEntry/unpublishEntry/abstractions.js\";\nimport { MoveEntryGateway } from \"~/features/contentEntry/moveEntry/abstractions.js\";\nimport { UpdateRevisionDescriptionGateway } from \"~/features/contentEntry/updateRevisionDescription/abstractions.js\";\nimport { EventPublisher } from \"@webiny/app/features/eventPublisher/index.js\";\nimport { ContentEntriesPresenter as Abstraction } from \"./abstractions.js\";\nimport { ContentEntriesPresenter } from \"./ContentEntriesPresenter.js\";\nimport type { IContentEntriesPresenter } from \"./abstractions.js\";\nimport type {\n IFolderTreeViewModel,\n IFolderOperationState\n} from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\n\nconst MODEL: CmsModel = {\n modelId: \"testModel\",\n name: \"Test Model\",\n singularApiName: \"TestModel\",\n pluralApiName: \"TestModels\",\n fields: [],\n layout: [],\n group: \"group-1\",\n titleFieldId: \"title\",\n descriptionFieldId: null,\n imageFieldId: null,\n tags: [],\n savedOn: \"\"\n} as unknown as CmsModel;\n\nfunction createEntry(\n entryId: string,\n folderId: string,\n overrides: Partial<CmsContentEntry> = {}\n): CmsContentEntry {\n return {\n id: `${entryId}#0001`,\n entryId,\n meta: {\n title: entryId,\n status: \"draft\",\n version: 1,\n locked: false\n },\n wbyAco_location: { folderId },\n values: {},\n createdBy: { id: \"user-1\", displayName: \"Test\", type: \"admin\" },\n createdOn: \"2024-01-01T00:00:00Z\",\n savedOn: \"2024-01-01T00:00:00Z\",\n ...overrides\n } as unknown as CmsContentEntry;\n}\n\nclass MockFolderTreePresenter implements FolderTreePresenter.Interface {\n private _currentFolderId: string | null = null;\n\n constructor() {\n makeAutoObservable(this);\n }\n\n get vm(): IFolderTreeViewModel {\n return {\n folders: [],\n tree: [],\n currentFolderId: this._currentFolderId,\n currentFolder: null,\n isRootFolder: this._currentFolderId === null,\n currentFolderTitle: \"Home\",\n childFolders: [],\n loading: false,\n loadingNodeIds: [],\n operation: { active: false, mode: null } as IFolderOperationState\n };\n }\n\n selectFolder(folderId: string | null): void {\n this._currentFolderId = folderId;\n }\n\n createFolder(): void {}\n editFolder(): void {}\n async deleteFolder(): Promise<void> {}\n async moveFolder(): Promise<void> {}\n async loadChildFolders(): Promise<void> {}\n canManageStructure(): boolean {\n return true;\n }\n getAncestorIds(): string[] {\n return [];\n }\n async submitOperation(): Promise<boolean> {\n return true;\n }\n cancelOperation(): void {}\n onFolderChange(): () => void {\n return () => {};\n }\n}\n\ninterface TestSetup {\n presenter: IContentEntriesPresenter;\n listEntriesGateway: { execute: ReturnType<typeof vi.fn> };\n moveEntryGateway: { execute: ReturnType<typeof vi.fn> };\n deleteEntryGateway: { execute: ReturnType<typeof vi.fn> };\n getDescendantFolders: ReturnType<typeof vi.fn>;\n foldersPresenter: MockFolderTreePresenter;\n publishEntryGateway: { execute: ReturnType<typeof vi.fn> };\n container: Container;\n}\n\nfunction setup(): TestSetup {\n const container = new Container();\n\n ListPresenterFeature.register(container);\n\n const foldersPresenter = new MockFolderTreePresenter();\n container.registerInstance(FolderTreePresenter, foldersPresenter);\n\n container.registerInstance(Confirmation, {\n confirm: vi.fn(async (_name, _params, execute) => {\n if (execute) {\n await execute(undefined);\n }\n return true;\n })\n } as unknown as Confirmation.Interface);\n\n const getDescendantFolders = vi.fn().mockReturnValue([]);\n container.registerInstance(GetDescendantFoldersUseCase, {\n execute: getDescendantFolders\n });\n\n container.registerInstance(EventPublisher, { publish: vi.fn() });\n container.register(ContentEntriesCacheProvider).inSingletonScope();\n container.register(CmsModelContextImpl).inSingletonScope();\n container.resolve(CmsModelContext).setModel(MODEL);\n\n ListEntriesFeature.register(container);\n DeleteEntryFeature.register(container);\n PublishEntryFeature.register(container);\n UnpublishEntryFeature.register(container);\n MoveEntryFeature.register(container);\n UpdateRevisionDescriptionFeature.register(container);\n\n const listEntriesGateway = { execute: vi.fn() };\n const moveEntryGateway = { execute: vi.fn() };\n const deleteEntryGateway = { execute: vi.fn() };\n\n container.registerInstance(ListEntriesGateway, listEntriesGateway);\n container.registerInstance(MoveEntryGateway, moveEntryGateway);\n container.registerInstance(DeleteEntryGateway, deleteEntryGateway);\n const publishEntryGateway = { execute: vi.fn() };\n container.registerInstance(PublishEntryGateway, publishEntryGateway);\n container.registerInstance(UnpublishEntryGateway, { execute: vi.fn() });\n container.registerInstance(UpdateRevisionDescriptionGateway, { execute: vi.fn() });\n\n container.register(ContentEntriesPresenter).inSingletonScope();\n const presenter = container.resolve(Abstraction);\n\n return {\n presenter,\n listEntriesGateway,\n moveEntryGateway,\n deleteEntryGateway,\n getDescendantFolders,\n foldersPresenter,\n publishEntryGateway,\n container\n };\n}\n\nasync function initPresenter(\n t: TestSetup,\n gatewayResponse: { data: CmsContentEntry[]; meta?: object }\n) {\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: gatewayResponse.data,\n meta: gatewayResponse.meta ?? {\n cursor: null,\n hasMoreItems: false,\n totalCount: gatewayResponse.data.length\n }\n });\n\n t.presenter.init();\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.pagination.loading).toBe(false);\n });\n}\n\ndescribe(\"ContentEntriesPresenter\", () => {\n let t: TestSetup;\n\n beforeEach(() => {\n t = setup();\n });\n\n describe(\"initial load\", () => {\n it(\"should show root entries after setModel\", async () => {\n const entries = [createEntry(\"entry-1\", \"root\"), createEntry(\"entry-2\", \"root\")];\n\n await initPresenter(t, { data: entries });\n\n expect(t.presenter.list.vm.rows).toHaveLength(2);\n expect(t.presenter.list.vm.rows.map(r => r.entryId)).toEqual([\"entry-1\", \"entry-2\"]);\n });\n\n it(\"should send folderId=root in the gateway query\", async () => {\n await initPresenter(t, { data: [] });\n\n expect(t.listEntriesGateway.execute).toHaveBeenCalledWith(\n expect.objectContaining({\n where: expect.objectContaining({\n wbyAco_location: { folderId: \"root\" }\n })\n })\n );\n });\n\n it(\"should set model after init\", async () => {\n await initPresenter(t, { data: [] });\n\n expect(t.presenter.vm.model).toStrictEqual(MODEL);\n });\n });\n\n describe(\"folder navigation\", () => {\n it(\"should filter to folder entries when navigating to a subfolder\", async () => {\n const rootEntries = [createEntry(\"root-1\", \"root\")];\n await initPresenter(t, { data: rootEntries });\n\n const folderEntries = [\n createEntry(\"folder-1\", \"folder-a\"),\n createEntry(\"folder-2\", \"folder-a\")\n ];\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: folderEntries,\n meta: { cursor: null, hasMoreItems: false, totalCount: 2 }\n });\n\n t.foldersPresenter.selectFolder(\"folder-a\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(2);\n });\n\n expect(t.presenter.list.vm.rows.map(r => r.entryId)).toEqual([\"folder-1\", \"folder-2\"]);\n });\n\n it(\"should show only root entries when navigating back to root\", async () => {\n const rootEntries = [createEntry(\"root-1\", \"root\")];\n await initPresenter(t, { data: rootEntries });\n\n const folderEntries = [createEntry(\"folder-1\", \"folder-a\")];\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: folderEntries,\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.foldersPresenter.selectFolder(\"folder-a\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n expect(t.presenter.list.vm.rows[0].entryId).toBe(\"folder-1\");\n });\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: rootEntries,\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.foldersPresenter.selectFolder(null);\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n expect(t.presenter.list.vm.rows[0].entryId).toBe(\"root-1\");\n });\n });\n\n it(\"should not leak subfolder entries into root view\", async () => {\n const rootEntries = [createEntry(\"root-1\", \"root\")];\n await initPresenter(t, { data: rootEntries });\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: [createEntry(\"folder-1\", \"folder-a\")],\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.foldersPresenter.selectFolder(\"folder-a\");\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n });\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: rootEntries,\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.foldersPresenter.selectFolder(null);\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n expect(t.presenter.list.vm.rows[0].entryId).toBe(\"root-1\");\n });\n });\n });\n\n describe(\"search\", () => {\n it(\"should show only search results from API\", async () => {\n const rootEntries = [createEntry(\"entry-1\", \"root\"), createEntry(\"entry-2\", \"root\")];\n await initPresenter(t, { data: rootEntries });\n\n const searchResults = [createEntry(\"entry-1\", \"root\")];\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: searchResults,\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.presenter.list.actions.search.set(\"entry-1\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n });\n\n expect(t.presenter.list.vm.rows[0].entryId).toBe(\"entry-1\");\n });\n\n it(\"should include entries from subfolders when searching from root\", async () => {\n await initPresenter(t, { data: [] });\n\n const searchResults = [\n createEntry(\"root-1\", \"root\"),\n createEntry(\"folder-1\", \"folder-a\")\n ];\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: searchResults,\n meta: { cursor: null, hasMoreItems: false, totalCount: 2 }\n });\n\n t.presenter.list.actions.search.set(\"test\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(2);\n });\n });\n\n it(\"should search with folderId_in containing all descendant folders when in a subfolder\", async () => {\n const folderEntries = [createEntry(\"folder-1\", \"folder-a\")];\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: folderEntries,\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.presenter.init({ initialFolderId: \"folder-a\" });\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.pagination.loading).toBe(false);\n });\n\n t.getDescendantFolders.mockReturnValue([\n { id: \"folder-a\" },\n { id: \"folder-a-1\" },\n { id: \"folder-a-2\" }\n ]);\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: [\n createEntry(\"folder-1\", \"folder-a\"),\n createEntry(\"sub-1\", \"folder-a-1\"),\n createEntry(\"sub-2\", \"folder-a-2\")\n ],\n meta: { cursor: null, hasMoreItems: false, totalCount: 3 }\n });\n\n t.presenter.list.actions.search.set(\"test\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(3);\n });\n\n expect(t.getDescendantFolders).toHaveBeenCalledWith(\"folder-a\");\n\n const searchCall = t.listEntriesGateway.execute.mock.calls.at(-1) ?? [];\n expect(searchCall[0].where).toEqual(\n expect.objectContaining({\n wbyAco_location: {\n folderId_in: [\"folder-a\", \"folder-a-1\", \"folder-a-2\"]\n }\n })\n );\n });\n\n it(\"should restore folder view when clearing search\", async () => {\n const rootEntries = [createEntry(\"entry-1\", \"root\"), createEntry(\"entry-2\", \"root\")];\n await initPresenter(t, { data: rootEntries });\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: [createEntry(\"entry-1\", \"root\")],\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.presenter.list.actions.search.set(\"entry-1\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n });\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: rootEntries,\n meta: { cursor: null, hasMoreItems: false, totalCount: 2 }\n });\n\n t.presenter.list.actions.search.clear();\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(2);\n });\n });\n });\n\n describe(\"status filter\", () => {\n it(\"should filter by status locally\", async () => {\n const entries = [\n createEntry(\"draft-1\", \"root\", {\n meta: {\n title: \"draft-1\",\n status: \"draft\",\n version: 1,\n locked: false\n }\n }),\n createEntry(\"published-1\", \"root\", {\n meta: {\n title: \"published-1\",\n status: \"published\",\n version: 1,\n locked: false\n }\n })\n ];\n await initPresenter(t, { data: entries });\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: entries.filter(e => (e.meta as { status: string }).status === \"published\"),\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.presenter.list.actions.filter.set(\"status\", \"published\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n expect(t.presenter.list.vm.rows[0].entryId).toBe(\"published-1\");\n });\n });\n });\n\n describe(\"move entry\", () => {\n it(\"should remove entry from current view after move\", async () => {\n const entries = [createEntry(\"entry-1\", \"root\"), createEntry(\"entry-2\", \"root\")];\n await initPresenter(t, { data: entries });\n\n t.moveEntryGateway.execute.mockResolvedValueOnce(true);\n\n await t.presenter.moveEntry(\"entry-1#0001\", \"folder-b\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n expect(t.presenter.list.vm.rows[0].entryId).toBe(\"entry-2\");\n });\n });\n });\n\n describe(\"delete entry\", () => {\n it(\"should remove entry from current view after delete\", async () => {\n const entries = [createEntry(\"entry-1\", \"root\"), createEntry(\"entry-2\", \"root\")];\n await initPresenter(t, { data: entries });\n\n t.deleteEntryGateway.execute.mockResolvedValueOnce(true);\n\n await t.presenter.deleteEntry(\"entry-1#0001\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n expect(t.presenter.list.vm.rows[0].entryId).toBe(\"entry-2\");\n });\n });\n });\n\n describe(\"vm\", () => {\n it(\"should set model on init\", () => {\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: [],\n meta: { cursor: null, hasMoreItems: false, totalCount: 0 }\n });\n t.presenter.init();\n expect(t.presenter.vm.model).toStrictEqual(MODEL);\n });\n\n it(\"should track selected entry\", async () => {\n await initPresenter(t, { data: [] });\n\n expect(t.presenter.vm.showingEntry).toBe(false);\n\n t.presenter.selectEntry(\"some-id\");\n expect(t.presenter.vm.selectedEntryId).toBe(\"some-id\");\n expect(t.presenter.vm.showingEntry).toBe(true);\n\n t.presenter.deselectEntry();\n expect(t.presenter.vm.selectedEntryId).toBeNull();\n expect(t.presenter.vm.showingEntry).toBe(false);\n });\n\n it(\"should set selectedEntryId to 'new' on createEntry\", async () => {\n await initPresenter(t, { data: [] });\n\n t.presenter.createEntry();\n expect(t.presenter.vm.selectedEntryId).toBe(\"new\");\n });\n\n it(\"should show folders when no search or non-folder filters active\", async () => {\n await initPresenter(t, { data: [] });\n\n expect(t.presenter.vm.showFolders).toBe(true);\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: [],\n meta: { cursor: null, hasMoreItems: false, totalCount: 0 }\n });\n\n t.presenter.list.actions.search.set(\"test\");\n\n await vi.waitFor(() => {\n expect(t.presenter.vm.showFolders).toBe(false);\n });\n });\n });\n\n describe(\"publish entry\", () => {\n /**\n * Publishing is not a content modification: the API returns the entry with its\n * `savedOn` unchanged, so the entry must keep its position in a list sorted by `savedOn`.\n */\n const entries = [\n createEntry(\"entry-3\", \"root\", { savedOn: \"2024-01-03T00:00:00.000Z\" }),\n createEntry(\"entry-2\", \"root\", { savedOn: \"2024-01-02T00:00:00.000Z\" }),\n createEntry(\"entry-1\", \"root\", { savedOn: \"2024-01-01T00:00:00.000Z\" })\n ];\n\n const publish = async (entry: CmsContentEntry) => {\n t.publishEntryGateway.execute.mockResolvedValueOnce({\n ...entry,\n meta: { ...entry.meta, status: \"published\", locked: true }\n });\n await t.container\n .resolve(PublishEntryUseCase)\n .execute({ model: MODEL, revisionId: entry.id });\n };\n\n it(\"should keep a published entry in its position\", async () => {\n await initPresenter(t, { data: entries });\n\n await publish(entries[1]);\n\n const rows = t.presenter.list.vm.rows;\n expect(rows.map(r => r.entryId)).toEqual([\"entry-3\", \"entry-2\", \"entry-1\"]);\n expect((rows[1].meta as { status: string }).status).toBe(\"published\");\n });\n\n it(\"should keep a published entry in its position when sorted ascending\", async () => {\n await initPresenter(t, { data: entries });\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: [...entries].reverse(),\n meta: { cursor: null, hasMoreItems: false, totalCount: entries.length }\n });\n t.presenter.list.actions.sort.set(\"savedOn\", \"ASC\");\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.appliedQuery?.sort?.direction).toBe(\"ASC\");\n });\n\n await publish(entries[1]);\n\n expect(t.presenter.list.vm.rows.map(r => r.entryId)).toEqual([\n \"entry-1\",\n \"entry-2\",\n \"entry-3\"\n ]);\n });\n });\n});\n"],"names":["MODEL","createEntry","entryId","folderId","overrides","MockFolderTreePresenter","makeAutoObservable","setup","container","Container","ListPresenterFeature","foldersPresenter","FolderTreePresenter","Confirmation","vi","_name","_params","execute","undefined","getDescendantFolders","GetDescendantFoldersUseCase","EventPublisher","ContentEntriesCacheProvider","CmsModelContextImpl","CmsModelContext","ListEntriesFeature","DeleteEntryFeature","PublishEntryFeature","UnpublishEntryFeature","MoveEntryFeature","UpdateRevisionDescriptionFeature","listEntriesGateway","moveEntryGateway","deleteEntryGateway","ListEntriesGateway","MoveEntryGateway","DeleteEntryGateway","publishEntryGateway","PublishEntryGateway","UnpublishEntryGateway","UpdateRevisionDescriptionGateway","ContentEntriesPresenter","presenter","Abstraction","initPresenter","t","gatewayResponse","expect","describe","beforeEach","it","entries","r","rootEntries","folderEntries","searchResults","searchCall","e","publish","entry","PublishEntryUseCase","rows"],"mappings":"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"}
1
+ {"version":3,"file":"presentation/contentEntries/list/ContentEntriesPresenter.test.js","sources":["../../../../src/presentation/contentEntries/list/ContentEntriesPresenter.test.ts"],"sourcesContent":["/**\n * @vitest-environment jsdom\n */\nimport { describe, it, expect, vi, beforeEach } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { makeAutoObservable } from \"mobx\";\nimport { ListPresenterFeature } from \"@webiny/app-admin/presentation/listPresenter/index.js\";\nimport { FolderTreePresenter } from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\nimport { GetDescendantFoldersUseCase } from \"@webiny/app-aco/features/folders/getDescendantFolders/abstractions.js\";\nimport { Confirmation } from \"@webiny/app-admin/features/confirmation/abstractions.js\";\nimport type { CmsContentEntry, CmsModel } from \"~/types.js\";\nimport { ContentEntriesCacheProvider } from \"~/features/contentEntry/ContentEntriesCacheProvider.js\";\nimport { CmsModelContext } from \"~/features/contentEntry/abstractions.js\";\nimport { CmsModelContext as CmsModelContextImpl } from \"~/features/contentEntry/CmsModelContext.js\";\nimport { ListEntriesFeature } from \"~/features/contentEntry/listEntries/feature.js\";\nimport { DeleteEntryFeature } from \"~/features/contentEntry/deleteEntry/feature.js\";\nimport { PublishEntryFeature } from \"~/features/contentEntry/publishEntry/feature.js\";\nimport { UnpublishEntryFeature } from \"~/features/contentEntry/unpublishEntry/feature.js\";\nimport { MoveEntryFeature } from \"~/features/contentEntry/moveEntry/feature.js\";\nimport { DuplicateEntryFeature } from \"~/features/contentEntry/duplicateEntry/feature.js\";\nimport { UpdateRevisionDescriptionFeature } from \"~/features/contentEntry/updateRevisionDescription/feature.js\";\nimport { ListEntriesGateway } from \"~/features/contentEntry/listEntries/abstractions.js\";\nimport { DeleteEntryGateway } from \"~/features/contentEntry/deleteEntry/abstractions.js\";\nimport {\n PublishEntryGateway,\n PublishEntryUseCase\n} from \"~/features/contentEntry/publishEntry/abstractions.js\";\nimport { UnpublishEntryGateway } from \"~/features/contentEntry/unpublishEntry/abstractions.js\";\nimport { MoveEntryGateway } from \"~/features/contentEntry/moveEntry/abstractions.js\";\nimport { DuplicateEntryGateway } from \"~/features/contentEntry/duplicateEntry/abstractions.js\";\nimport { UpdateRevisionDescriptionGateway } from \"~/features/contentEntry/updateRevisionDescription/abstractions.js\";\nimport { EventPublisher } from \"@webiny/app/features/eventPublisher/index.js\";\nimport { ContentEntriesPresenter as Abstraction } from \"./abstractions.js\";\nimport { ContentEntriesPresenter } from \"./ContentEntriesPresenter.js\";\nimport type { IContentEntriesPresenter } from \"./abstractions.js\";\nimport type {\n IFolderTreeViewModel,\n IFolderOperationState\n} from \"@webiny/app-aco/presentation/folderTree/abstractions.js\";\n\nconst MODEL: CmsModel = {\n modelId: \"testModel\",\n name: \"Test Model\",\n singularApiName: \"TestModel\",\n pluralApiName: \"TestModels\",\n fields: [],\n layout: [],\n group: \"group-1\",\n titleFieldId: \"title\",\n descriptionFieldId: null,\n imageFieldId: null,\n tags: [],\n savedOn: \"\"\n} as unknown as CmsModel;\n\nfunction createEntry(\n entryId: string,\n folderId: string,\n overrides: Partial<CmsContentEntry> = {}\n): CmsContentEntry {\n return {\n id: `${entryId}#0001`,\n entryId,\n meta: {\n title: entryId,\n status: \"draft\",\n version: 1,\n locked: false\n },\n wbyAco_location: { folderId },\n values: {},\n createdBy: { id: \"user-1\", displayName: \"Test\", type: \"admin\" },\n createdOn: \"2024-01-01T00:00:00Z\",\n savedOn: \"2024-01-01T00:00:00Z\",\n ...overrides\n } as unknown as CmsContentEntry;\n}\n\nclass MockFolderTreePresenter implements FolderTreePresenter.Interface {\n private _currentFolderId: string | null = null;\n\n constructor() {\n makeAutoObservable(this);\n }\n\n get vm(): IFolderTreeViewModel {\n return {\n folders: [],\n tree: [],\n currentFolderId: this._currentFolderId,\n currentFolder: null,\n isRootFolder: this._currentFolderId === null,\n currentFolderTitle: \"Home\",\n childFolders: [],\n loading: false,\n loadingNodeIds: [],\n operation: { active: false, mode: null } as IFolderOperationState\n };\n }\n\n selectFolder(folderId: string | null): void {\n this._currentFolderId = folderId;\n }\n\n createFolder(): void {}\n editFolder(): void {}\n async deleteFolder(): Promise<void> {}\n async moveFolder(): Promise<void> {}\n async loadChildFolders(): Promise<void> {}\n canManageStructure(): boolean {\n return true;\n }\n getAncestorIds(): string[] {\n return [];\n }\n async submitOperation(): Promise<boolean> {\n return true;\n }\n cancelOperation(): void {}\n onFolderChange(): () => void {\n return () => {};\n }\n}\n\ninterface TestSetup {\n presenter: IContentEntriesPresenter;\n listEntriesGateway: { execute: ReturnType<typeof vi.fn> };\n moveEntryGateway: { execute: ReturnType<typeof vi.fn> };\n deleteEntryGateway: { execute: ReturnType<typeof vi.fn> };\n duplicateEntryGateway: { execute: ReturnType<typeof vi.fn> };\n getDescendantFolders: ReturnType<typeof vi.fn>;\n foldersPresenter: MockFolderTreePresenter;\n publishEntryGateway: { execute: ReturnType<typeof vi.fn> };\n container: Container;\n}\n\nfunction setup(): TestSetup {\n const container = new Container();\n\n ListPresenterFeature.register(container);\n\n const foldersPresenter = new MockFolderTreePresenter();\n container.registerInstance(FolderTreePresenter, foldersPresenter);\n\n container.registerInstance(Confirmation, {\n confirm: vi.fn(async (_name, _params, execute) => {\n if (execute) {\n return await execute(undefined);\n }\n return true;\n })\n } as unknown as Confirmation.Interface);\n\n const getDescendantFolders = vi.fn().mockReturnValue([]);\n container.registerInstance(GetDescendantFoldersUseCase, {\n execute: getDescendantFolders\n });\n\n container.registerInstance(EventPublisher, { publish: vi.fn() });\n container.register(ContentEntriesCacheProvider).inSingletonScope();\n container.register(CmsModelContextImpl).inSingletonScope();\n container.resolve(CmsModelContext).setModel(MODEL);\n\n ListEntriesFeature.register(container);\n DeleteEntryFeature.register(container);\n PublishEntryFeature.register(container);\n UnpublishEntryFeature.register(container);\n MoveEntryFeature.register(container);\n DuplicateEntryFeature.register(container);\n UpdateRevisionDescriptionFeature.register(container);\n\n const listEntriesGateway = { execute: vi.fn() };\n const moveEntryGateway = { execute: vi.fn() };\n const deleteEntryGateway = { execute: vi.fn() };\n\n container.registerInstance(ListEntriesGateway, listEntriesGateway);\n container.registerInstance(MoveEntryGateway, moveEntryGateway);\n container.registerInstance(DeleteEntryGateway, deleteEntryGateway);\n const duplicateEntryGateway = { execute: vi.fn() };\n container.registerInstance(DuplicateEntryGateway, duplicateEntryGateway);\n const publishEntryGateway = { execute: vi.fn() };\n container.registerInstance(PublishEntryGateway, publishEntryGateway);\n container.registerInstance(UnpublishEntryGateway, { execute: vi.fn() });\n container.registerInstance(UpdateRevisionDescriptionGateway, { execute: vi.fn() });\n\n container.register(ContentEntriesPresenter).inSingletonScope();\n const presenter = container.resolve(Abstraction);\n\n return {\n presenter,\n listEntriesGateway,\n moveEntryGateway,\n deleteEntryGateway,\n duplicateEntryGateway,\n getDescendantFolders,\n foldersPresenter,\n publishEntryGateway,\n container\n };\n}\n\nasync function initPresenter(\n t: TestSetup,\n gatewayResponse: { data: CmsContentEntry[]; meta?: object }\n) {\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: gatewayResponse.data,\n meta: gatewayResponse.meta ?? {\n cursor: null,\n hasMoreItems: false,\n totalCount: gatewayResponse.data.length\n }\n });\n\n t.presenter.init();\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.pagination.loading).toBe(false);\n });\n}\n\ndescribe(\"ContentEntriesPresenter\", () => {\n let t: TestSetup;\n\n beforeEach(() => {\n t = setup();\n });\n\n describe(\"initial load\", () => {\n it(\"should show root entries after setModel\", async () => {\n const entries = [createEntry(\"entry-1\", \"root\"), createEntry(\"entry-2\", \"root\")];\n\n await initPresenter(t, { data: entries });\n\n expect(t.presenter.list.vm.rows).toHaveLength(2);\n expect(t.presenter.list.vm.rows.map(r => r.entryId)).toEqual([\"entry-1\", \"entry-2\"]);\n });\n\n it(\"should send folderId=root in the gateway query\", async () => {\n await initPresenter(t, { data: [] });\n\n expect(t.listEntriesGateway.execute).toHaveBeenCalledWith(\n expect.objectContaining({\n where: expect.objectContaining({\n wbyAco_location: { folderId: \"root\" }\n })\n })\n );\n });\n\n it(\"should set model after init\", async () => {\n await initPresenter(t, { data: [] });\n\n expect(t.presenter.vm.model).toStrictEqual(MODEL);\n });\n });\n\n describe(\"folder navigation\", () => {\n it(\"should filter to folder entries when navigating to a subfolder\", async () => {\n const rootEntries = [createEntry(\"root-1\", \"root\")];\n await initPresenter(t, { data: rootEntries });\n\n const folderEntries = [\n createEntry(\"folder-1\", \"folder-a\"),\n createEntry(\"folder-2\", \"folder-a\")\n ];\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: folderEntries,\n meta: { cursor: null, hasMoreItems: false, totalCount: 2 }\n });\n\n t.foldersPresenter.selectFolder(\"folder-a\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(2);\n });\n\n expect(t.presenter.list.vm.rows.map(r => r.entryId)).toEqual([\"folder-1\", \"folder-2\"]);\n });\n\n it(\"should show only root entries when navigating back to root\", async () => {\n const rootEntries = [createEntry(\"root-1\", \"root\")];\n await initPresenter(t, { data: rootEntries });\n\n const folderEntries = [createEntry(\"folder-1\", \"folder-a\")];\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: folderEntries,\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.foldersPresenter.selectFolder(\"folder-a\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n expect(t.presenter.list.vm.rows[0].entryId).toBe(\"folder-1\");\n });\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: rootEntries,\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.foldersPresenter.selectFolder(null);\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n expect(t.presenter.list.vm.rows[0].entryId).toBe(\"root-1\");\n });\n });\n\n it(\"should not leak subfolder entries into root view\", async () => {\n const rootEntries = [createEntry(\"root-1\", \"root\")];\n await initPresenter(t, { data: rootEntries });\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: [createEntry(\"folder-1\", \"folder-a\")],\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.foldersPresenter.selectFolder(\"folder-a\");\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n });\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: rootEntries,\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.foldersPresenter.selectFolder(null);\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n expect(t.presenter.list.vm.rows[0].entryId).toBe(\"root-1\");\n });\n });\n });\n\n describe(\"search\", () => {\n it(\"should show only search results from API\", async () => {\n const rootEntries = [createEntry(\"entry-1\", \"root\"), createEntry(\"entry-2\", \"root\")];\n await initPresenter(t, { data: rootEntries });\n\n const searchResults = [createEntry(\"entry-1\", \"root\")];\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: searchResults,\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.presenter.list.actions.search.set(\"entry-1\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n });\n\n expect(t.presenter.list.vm.rows[0].entryId).toBe(\"entry-1\");\n });\n\n it(\"should include entries from subfolders when searching from root\", async () => {\n await initPresenter(t, { data: [] });\n\n const searchResults = [\n createEntry(\"root-1\", \"root\"),\n createEntry(\"folder-1\", \"folder-a\")\n ];\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: searchResults,\n meta: { cursor: null, hasMoreItems: false, totalCount: 2 }\n });\n\n t.presenter.list.actions.search.set(\"test\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(2);\n });\n });\n\n it(\"should search with folderId_in containing all descendant folders when in a subfolder\", async () => {\n const folderEntries = [createEntry(\"folder-1\", \"folder-a\")];\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: folderEntries,\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.presenter.init({ initialFolderId: \"folder-a\" });\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.pagination.loading).toBe(false);\n });\n\n t.getDescendantFolders.mockReturnValue([\n { id: \"folder-a\" },\n { id: \"folder-a-1\" },\n { id: \"folder-a-2\" }\n ]);\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: [\n createEntry(\"folder-1\", \"folder-a\"),\n createEntry(\"sub-1\", \"folder-a-1\"),\n createEntry(\"sub-2\", \"folder-a-2\")\n ],\n meta: { cursor: null, hasMoreItems: false, totalCount: 3 }\n });\n\n t.presenter.list.actions.search.set(\"test\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(3);\n });\n\n expect(t.getDescendantFolders).toHaveBeenCalledWith(\"folder-a\");\n\n const searchCall = t.listEntriesGateway.execute.mock.calls.at(-1) ?? [];\n expect(searchCall[0].where).toEqual(\n expect.objectContaining({\n wbyAco_location: {\n folderId_in: [\"folder-a\", \"folder-a-1\", \"folder-a-2\"]\n }\n })\n );\n });\n\n it(\"should restore folder view when clearing search\", async () => {\n const rootEntries = [createEntry(\"entry-1\", \"root\"), createEntry(\"entry-2\", \"root\")];\n await initPresenter(t, { data: rootEntries });\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: [createEntry(\"entry-1\", \"root\")],\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.presenter.list.actions.search.set(\"entry-1\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n });\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: rootEntries,\n meta: { cursor: null, hasMoreItems: false, totalCount: 2 }\n });\n\n t.presenter.list.actions.search.clear();\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(2);\n });\n });\n });\n\n describe(\"status filter\", () => {\n it(\"should filter by status locally\", async () => {\n const entries = [\n createEntry(\"draft-1\", \"root\", {\n meta: {\n title: \"draft-1\",\n status: \"draft\",\n version: 1,\n locked: false\n }\n }),\n createEntry(\"published-1\", \"root\", {\n meta: {\n title: \"published-1\",\n status: \"published\",\n version: 1,\n locked: false\n }\n })\n ];\n await initPresenter(t, { data: entries });\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: entries.filter(e => (e.meta as { status: string }).status === \"published\"),\n meta: { cursor: null, hasMoreItems: false, totalCount: 1 }\n });\n\n t.presenter.list.actions.filter.set(\"status\", \"published\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n expect(t.presenter.list.vm.rows[0].entryId).toBe(\"published-1\");\n });\n });\n });\n\n describe(\"move entry\", () => {\n it(\"should remove entry from current view after move\", async () => {\n const entries = [createEntry(\"entry-1\", \"root\"), createEntry(\"entry-2\", \"root\")];\n await initPresenter(t, { data: entries });\n\n t.moveEntryGateway.execute.mockResolvedValueOnce(true);\n\n await t.presenter.moveEntry(\"entry-1#0001\", \"folder-b\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n expect(t.presenter.list.vm.rows[0].entryId).toBe(\"entry-2\");\n });\n });\n });\n\n describe(\"duplicate entry\", () => {\n it(\"should add the duplicated entry to the current view\", async () => {\n const entries = [\n createEntry(\"entry-2\", \"root\", { savedOn: \"2024-01-02T00:00:00.000Z\" }),\n createEntry(\"entry-1\", \"root\", { savedOn: \"2024-01-01T00:00:00.000Z\" })\n ];\n await initPresenter(t, { data: entries });\n\n const duplicate = createEntry(\"entry-3\", \"root\", {\n savedOn: \"2024-01-03T00:00:00.000Z\"\n });\n t.duplicateEntryGateway.execute.mockResolvedValueOnce(duplicate);\n\n const result = await t.presenter.duplicateEntry(entries[1]);\n\n expect(result).toEqual({ entry: duplicate });\n expect(t.duplicateEntryGateway.execute).toHaveBeenCalledWith({\n model: MODEL,\n revisionId: \"entry-1#0001\"\n });\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows.map(r => r.entryId)).toEqual([\n \"entry-3\",\n \"entry-2\",\n \"entry-1\"\n ]);\n });\n });\n\n it(\"should return the error when duplication fails\", async () => {\n const entries = [createEntry(\"entry-1\", \"root\")];\n await initPresenter(t, { data: entries });\n\n const error = new Error(\"Not allowed.\");\n t.duplicateEntryGateway.execute.mockRejectedValueOnce(error);\n\n const result = await t.presenter.duplicateEntry(entries[0]);\n\n expect(result).toEqual({ error });\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n });\n });\n\n describe(\"delete entry\", () => {\n it(\"should remove entry from current view after delete\", async () => {\n const entries = [createEntry(\"entry-1\", \"root\"), createEntry(\"entry-2\", \"root\")];\n await initPresenter(t, { data: entries });\n\n t.deleteEntryGateway.execute.mockResolvedValueOnce(true);\n\n await t.presenter.deleteEntry(\"entry-1#0001\");\n\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.rows).toHaveLength(1);\n expect(t.presenter.list.vm.rows[0].entryId).toBe(\"entry-2\");\n });\n });\n });\n\n describe(\"vm\", () => {\n it(\"should set model on init\", () => {\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: [],\n meta: { cursor: null, hasMoreItems: false, totalCount: 0 }\n });\n t.presenter.init();\n expect(t.presenter.vm.model).toStrictEqual(MODEL);\n });\n\n it(\"should track selected entry\", async () => {\n await initPresenter(t, { data: [] });\n\n expect(t.presenter.vm.showingEntry).toBe(false);\n\n t.presenter.selectEntry(\"some-id\");\n expect(t.presenter.vm.selectedEntryId).toBe(\"some-id\");\n expect(t.presenter.vm.showingEntry).toBe(true);\n\n t.presenter.deselectEntry();\n expect(t.presenter.vm.selectedEntryId).toBeNull();\n expect(t.presenter.vm.showingEntry).toBe(false);\n });\n\n it(\"should set selectedEntryId to 'new' on createEntry\", async () => {\n await initPresenter(t, { data: [] });\n\n t.presenter.createEntry();\n expect(t.presenter.vm.selectedEntryId).toBe(\"new\");\n });\n\n it(\"should show folders when no search or non-folder filters active\", async () => {\n await initPresenter(t, { data: [] });\n\n expect(t.presenter.vm.showFolders).toBe(true);\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: [],\n meta: { cursor: null, hasMoreItems: false, totalCount: 0 }\n });\n\n t.presenter.list.actions.search.set(\"test\");\n\n await vi.waitFor(() => {\n expect(t.presenter.vm.showFolders).toBe(false);\n });\n });\n });\n\n describe(\"publish entry\", () => {\n /**\n * Publishing is not a content modification: the API returns the entry with its\n * `savedOn` unchanged, so the entry must keep its position in a list sorted by `savedOn`.\n */\n const entries = [\n createEntry(\"entry-3\", \"root\", { savedOn: \"2024-01-03T00:00:00.000Z\" }),\n createEntry(\"entry-2\", \"root\", { savedOn: \"2024-01-02T00:00:00.000Z\" }),\n createEntry(\"entry-1\", \"root\", { savedOn: \"2024-01-01T00:00:00.000Z\" })\n ];\n\n const publish = async (entry: CmsContentEntry) => {\n t.publishEntryGateway.execute.mockResolvedValueOnce({\n ...entry,\n meta: { ...entry.meta, status: \"published\", locked: true }\n });\n await t.container\n .resolve(PublishEntryUseCase)\n .execute({ model: MODEL, revisionId: entry.id });\n };\n\n it(\"should keep a published entry in its position\", async () => {\n await initPresenter(t, { data: entries });\n\n await publish(entries[1]);\n\n const rows = t.presenter.list.vm.rows;\n expect(rows.map(r => r.entryId)).toEqual([\"entry-3\", \"entry-2\", \"entry-1\"]);\n expect((rows[1].meta as { status: string }).status).toBe(\"published\");\n });\n\n it(\"should keep a published entry in its position when sorted ascending\", async () => {\n await initPresenter(t, { data: entries });\n\n t.listEntriesGateway.execute.mockResolvedValueOnce({\n data: [...entries].reverse(),\n meta: { cursor: null, hasMoreItems: false, totalCount: entries.length }\n });\n t.presenter.list.actions.sort.set(\"savedOn\", \"ASC\");\n await vi.waitFor(() => {\n expect(t.presenter.list.vm.appliedQuery?.sort?.direction).toBe(\"ASC\");\n });\n\n await publish(entries[1]);\n\n expect(t.presenter.list.vm.rows.map(r => r.entryId)).toEqual([\n \"entry-1\",\n \"entry-2\",\n \"entry-3\"\n ]);\n });\n });\n});\n"],"names":["MODEL","createEntry","entryId","folderId","overrides","MockFolderTreePresenter","makeAutoObservable","setup","container","Container","ListPresenterFeature","foldersPresenter","FolderTreePresenter","Confirmation","vi","_name","_params","execute","undefined","getDescendantFolders","GetDescendantFoldersUseCase","EventPublisher","ContentEntriesCacheProvider","CmsModelContextImpl","CmsModelContext","ListEntriesFeature","DeleteEntryFeature","PublishEntryFeature","UnpublishEntryFeature","MoveEntryFeature","DuplicateEntryFeature","UpdateRevisionDescriptionFeature","listEntriesGateway","moveEntryGateway","deleteEntryGateway","ListEntriesGateway","MoveEntryGateway","DeleteEntryGateway","duplicateEntryGateway","DuplicateEntryGateway","publishEntryGateway","PublishEntryGateway","UnpublishEntryGateway","UpdateRevisionDescriptionGateway","ContentEntriesPresenter","presenter","Abstraction","initPresenter","t","gatewayResponse","expect","describe","beforeEach","it","entries","r","rootEntries","folderEntries","searchResults","searchCall","e","duplicate","result","error","Error","publish","entry","PublishEntryUseCase","rows"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,MAAMA,QAAkB;IACpB,SAAS;IACT,MAAM;IACN,iBAAiB;IACjB,eAAe;IACf,QAAQ,EAAE;IACV,QAAQ,EAAE;IACV,OAAO;IACP,cAAc;IACd,oBAAoB;IACpB,cAAc;IACd,MAAM,EAAE;IACR,SAAS;AACb;AAEA,SAASC,YACLC,OAAe,EACfC,QAAgB,EAChBC,YAAsC,CAAC,CAAC;IAExC,OAAO;QACH,IAAI,GAAGF,QAAQ,KAAK,CAAC;QACrBA;QACA,MAAM;YACF,OAAOA;YACP,QAAQ;YACR,SAAS;YACT,QAAQ;QACZ;QACA,iBAAiB;YAAEC;QAAS;QAC5B,QAAQ,CAAC;QACT,WAAW;YAAE,IAAI;YAAU,aAAa;YAAQ,MAAM;QAAQ;QAC9D,WAAW;QACX,SAAS;QACT,GAAGC,SAAS;IAChB;AACJ;AAEA,MAAMC;IAGF,aAAc;aAFN,gBAAgB,GAAkB;QAGtCC,mBAAmB,IAAI;IAC3B;IAEA,IAAI,KAA2B;QAC3B,OAAO;YACH,SAAS,EAAE;YACX,MAAM,EAAE;YACR,iBAAiB,IAAI,CAAC,gBAAgB;YACtC,eAAe;YACf,cAAc,AAA0B,SAA1B,IAAI,CAAC,gBAAgB;YACnC,oBAAoB;YACpB,cAAc,EAAE;YAChB,SAAS;YACT,gBAAgB,EAAE;YAClB,WAAW;gBAAE,QAAQ;gBAAO,MAAM;YAAK;QAC3C;IACJ;IAEA,aAAaH,QAAuB,EAAQ;QACxC,IAAI,CAAC,gBAAgB,GAAGA;IAC5B;IAEA,eAAqB,CAAC;IACtB,aAAmB,CAAC;IACpB,MAAM,eAA8B,CAAC;IACrC,MAAM,aAA4B,CAAC;IACnC,MAAM,mBAAkC,CAAC;IACzC,qBAA8B;QAC1B,OAAO;IACX;IACA,iBAA2B;QACvB,OAAO,EAAE;IACb;IACA,MAAM,kBAAoC;QACtC,OAAO;IACX;IACA,kBAAwB,CAAC;IACzB,iBAA6B;QACzB,OAAO,KAAO;IAClB;AACJ;AAcA,SAASI;IACL,MAAMC,YAAY,IAAIC;IAEtBC,qBAAqB,QAAQ,CAACF;IAE9B,MAAMG,mBAAmB,IAAIN;IAC7BG,UAAU,gBAAgB,CAACI,qBAAqBD;IAEhDH,UAAU,gBAAgB,CAACK,cAAc;QACrC,SAASC,GAAG,EAAE,CAAC,OAAOC,OAAOC,SAASC;YAClC,IAAIA,SACA,OAAO,MAAMA,QAAQC;YAEzB,OAAO;QACX;IACJ;IAEA,MAAMC,uBAAuBL,GAAG,EAAE,GAAG,eAAe,CAAC,EAAE;IACvDN,UAAU,gBAAgB,CAACY,6BAA6B;QACpD,SAASD;IACb;IAEAX,UAAU,gBAAgB,CAACa,gBAAgB;QAAE,SAASP,GAAG,EAAE;IAAG;IAC9DN,UAAU,QAAQ,CAACc,6BAA6B,gBAAgB;IAChEd,UAAU,QAAQ,CAACe,oCAAqB,gBAAgB;IACxDf,UAAU,OAAO,CAACgB,iBAAiB,QAAQ,CAACxB;IAE5CyB,mBAAmB,QAAQ,CAACjB;IAC5BkB,mBAAmB,QAAQ,CAAClB;IAC5BmB,oBAAoB,QAAQ,CAACnB;IAC7BoB,sBAAsB,QAAQ,CAACpB;IAC/BqB,iBAAiB,QAAQ,CAACrB;IAC1BsB,sBAAsB,QAAQ,CAACtB;IAC/BuB,iCAAiC,QAAQ,CAACvB;IAE1C,MAAMwB,qBAAqB;QAAE,SAASlB,GAAG,EAAE;IAAG;IAC9C,MAAMmB,mBAAmB;QAAE,SAASnB,GAAG,EAAE;IAAG;IAC5C,MAAMoB,qBAAqB;QAAE,SAASpB,GAAG,EAAE;IAAG;IAE9CN,UAAU,gBAAgB,CAAC2B,oBAAoBH;IAC/CxB,UAAU,gBAAgB,CAAC4B,kBAAkBH;IAC7CzB,UAAU,gBAAgB,CAAC6B,oBAAoBH;IAC/C,MAAMI,wBAAwB;QAAE,SAASxB,GAAG,EAAE;IAAG;IACjDN,UAAU,gBAAgB,CAAC+B,uBAAuBD;IAClD,MAAME,sBAAsB;QAAE,SAAS1B,GAAG,EAAE;IAAG;IAC/CN,UAAU,gBAAgB,CAACiC,qBAAqBD;IAChDhC,UAAU,gBAAgB,CAACkC,uBAAuB;QAAE,SAAS5B,GAAG,EAAE;IAAG;IACrEN,UAAU,gBAAgB,CAACmC,kCAAkC;QAAE,SAAS7B,GAAG,EAAE;IAAG;IAEhFN,UAAU,QAAQ,CAACoC,6DAAyB,gBAAgB;IAC5D,MAAMC,YAAYrC,UAAU,OAAO,CAACsC;IAEpC,OAAO;QACHD;QACAb;QACAC;QACAC;QACAI;QACAnB;QACAR;QACA6B;QACAhC;IACJ;AACJ;AAEA,eAAeuC,cACXC,CAAY,EACZC,eAA2D;IAE3DD,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;QAC/C,MAAMC,gBAAgB,IAAI;QAC1B,MAAMA,gBAAgB,IAAI,IAAI;YAC1B,QAAQ;YACR,cAAc;YACd,YAAYA,gBAAgB,IAAI,CAAC,MAAM;QAC3C;IACJ;IAEAD,EAAE,SAAS,CAAC,IAAI;IAEhB,MAAMlC,GAAG,OAAO,CAAC;QACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC;IACxD;AACJ;AAEAG,SAAS,2BAA2B;IAChC,IAAIH;IAEJI,WAAW;QACPJ,IAAIzC;IACR;IAEA4C,SAAS,gBAAgB;QACrBE,GAAG,2CAA2C;YAC1C,MAAMC,UAAU;gBAACrD,YAAY,WAAW;gBAASA,YAAY,WAAW;aAAQ;YAEhF,MAAM8C,cAAcC,GAAG;gBAAE,MAAMM;YAAQ;YAEvCJ,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC;YAC9CE,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAACO,CAAAA,IAAKA,EAAE,OAAO,GAAG,OAAO,CAAC;gBAAC;gBAAW;aAAU;QACvF;QAEAF,GAAG,kDAAkD;YACjD,MAAMN,cAAcC,GAAG;gBAAE,MAAM,EAAE;YAAC;YAElCE,OAAOF,EAAE,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,CACrDE,OAAO,gBAAgB,CAAC;gBACpB,OAAOA,OAAO,gBAAgB,CAAC;oBAC3B,iBAAiB;wBAAE,UAAU;oBAAO;gBACxC;YACJ;QAER;QAEAG,GAAG,+BAA+B;YAC9B,MAAMN,cAAcC,GAAG;gBAAE,MAAM,EAAE;YAAC;YAElCE,OAAOF,EAAE,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,CAAChD;QAC/C;IACJ;IAEAmD,SAAS,qBAAqB;QAC1BE,GAAG,kEAAkE;YACjE,MAAMG,cAAc;gBAACvD,YAAY,UAAU;aAAQ;YACnD,MAAM8C,cAAcC,GAAG;gBAAE,MAAMQ;YAAY;YAE3C,MAAMC,gBAAgB;gBAClBxD,YAAY,YAAY;gBACxBA,YAAY,YAAY;aAC3B;YAED+C,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAC/C,MAAMS;gBACN,MAAM;oBAAE,QAAQ;oBAAM,cAAc;oBAAO,YAAY;gBAAE;YAC7D;YAEAT,EAAE,gBAAgB,CAAC,YAAY,CAAC;YAEhC,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC;YAClD;YAEAE,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAACO,CAAAA,IAAKA,EAAE,OAAO,GAAG,OAAO,CAAC;gBAAC;gBAAY;aAAW;QACzF;QAEAF,GAAG,8DAA8D;YAC7D,MAAMG,cAAc;gBAACvD,YAAY,UAAU;aAAQ;YACnD,MAAM8C,cAAcC,GAAG;gBAAE,MAAMQ;YAAY;YAE3C,MAAMC,gBAAgB;gBAACxD,YAAY,YAAY;aAAY;YAC3D+C,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAC/C,MAAMS;gBACN,MAAM;oBAAE,QAAQ;oBAAM,cAAc;oBAAO,YAAY;gBAAE;YAC7D;YAEAT,EAAE,gBAAgB,CAAC,YAAY,CAAC;YAEhC,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC;gBAC9CE,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC;YACrD;YAEAA,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAC/C,MAAMQ;gBACN,MAAM;oBAAE,QAAQ;oBAAM,cAAc;oBAAO,YAAY;gBAAE;YAC7D;YAEAR,EAAE,gBAAgB,CAAC,YAAY,CAAC;YAEhC,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC;gBAC9CE,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC;YACrD;QACJ;QAEAK,GAAG,oDAAoD;YACnD,MAAMG,cAAc;gBAACvD,YAAY,UAAU;aAAQ;YACnD,MAAM8C,cAAcC,GAAG;gBAAE,MAAMQ;YAAY;YAE3CR,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAC/C,MAAM;oBAAC/C,YAAY,YAAY;iBAAY;gBAC3C,MAAM;oBAAE,QAAQ;oBAAM,cAAc;oBAAO,YAAY;gBAAE;YAC7D;YAEA+C,EAAE,gBAAgB,CAAC,YAAY,CAAC;YAChC,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC;YAClD;YAEAA,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAC/C,MAAMQ;gBACN,MAAM;oBAAE,QAAQ;oBAAM,cAAc;oBAAO,YAAY;gBAAE;YAC7D;YAEAR,EAAE,gBAAgB,CAAC,YAAY,CAAC;YAChC,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC;gBAC9CE,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC;YACrD;QACJ;IACJ;IAEAG,SAAS,UAAU;QACfE,GAAG,4CAA4C;YAC3C,MAAMG,cAAc;gBAACvD,YAAY,WAAW;gBAASA,YAAY,WAAW;aAAQ;YACpF,MAAM8C,cAAcC,GAAG;gBAAE,MAAMQ;YAAY;YAE3C,MAAME,gBAAgB;gBAACzD,YAAY,WAAW;aAAQ;YACtD+C,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAC/C,MAAMU;gBACN,MAAM;oBAAE,QAAQ;oBAAM,cAAc;oBAAO,YAAY;gBAAE;YAC7D;YAEAV,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC;YAEpC,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC;YAClD;YAEAE,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC;QACrD;QAEAK,GAAG,mEAAmE;YAClE,MAAMN,cAAcC,GAAG;gBAAE,MAAM,EAAE;YAAC;YAElC,MAAMU,gBAAgB;gBAClBzD,YAAY,UAAU;gBACtBA,YAAY,YAAY;aAC3B;YACD+C,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAC/C,MAAMU;gBACN,MAAM;oBAAE,QAAQ;oBAAM,cAAc;oBAAO,YAAY;gBAAE;YAC7D;YAEAV,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC;YAEpC,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC;YAClD;QACJ;QAEAK,GAAG,wFAAwF;YACvF,MAAMI,gBAAgB;gBAACxD,YAAY,YAAY;aAAY;YAC3D+C,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAC/C,MAAMS;gBACN,MAAM;oBAAE,QAAQ;oBAAM,cAAc;oBAAO,YAAY;gBAAE;YAC7D;YAEAT,EAAE,SAAS,CAAC,IAAI,CAAC;gBAAE,iBAAiB;YAAW;YAE/C,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC;YACxD;YAEAA,EAAE,oBAAoB,CAAC,eAAe,CAAC;gBACnC;oBAAE,IAAI;gBAAW;gBACjB;oBAAE,IAAI;gBAAa;gBACnB;oBAAE,IAAI;gBAAa;aACtB;YAEDA,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAC/C,MAAM;oBACF/C,YAAY,YAAY;oBACxBA,YAAY,SAAS;oBACrBA,YAAY,SAAS;iBACxB;gBACD,MAAM;oBAAE,QAAQ;oBAAM,cAAc;oBAAO,YAAY;gBAAE;YAC7D;YAEA+C,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC;YAEpC,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC;YAClD;YAEAE,OAAOF,EAAE,oBAAoB,EAAE,oBAAoB,CAAC;YAEpD,MAAMW,aAAaX,EAAE,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE;YACvEE,OAAOS,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAC/BT,OAAO,gBAAgB,CAAC;gBACpB,iBAAiB;oBACb,aAAa;wBAAC;wBAAY;wBAAc;qBAAa;gBACzD;YACJ;QAER;QAEAG,GAAG,mDAAmD;YAClD,MAAMG,cAAc;gBAACvD,YAAY,WAAW;gBAASA,YAAY,WAAW;aAAQ;YACpF,MAAM8C,cAAcC,GAAG;gBAAE,MAAMQ;YAAY;YAE3CR,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAC/C,MAAM;oBAAC/C,YAAY,WAAW;iBAAQ;gBACtC,MAAM;oBAAE,QAAQ;oBAAM,cAAc;oBAAO,YAAY;gBAAE;YAC7D;YAEA+C,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC;YAEpC,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC;YAClD;YAEAA,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAC/C,MAAMQ;gBACN,MAAM;oBAAE,QAAQ;oBAAM,cAAc;oBAAO,YAAY;gBAAE;YAC7D;YAEAR,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK;YAErC,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC;YAClD;QACJ;IACJ;IAEAG,SAAS,iBAAiB;QACtBE,GAAG,mCAAmC;YAClC,MAAMC,UAAU;gBACZrD,YAAY,WAAW,QAAQ;oBAC3B,MAAM;wBACF,OAAO;wBACP,QAAQ;wBACR,SAAS;wBACT,QAAQ;oBACZ;gBACJ;gBACAA,YAAY,eAAe,QAAQ;oBAC/B,MAAM;wBACF,OAAO;wBACP,QAAQ;wBACR,SAAS;wBACT,QAAQ;oBACZ;gBACJ;aACH;YACD,MAAM8C,cAAcC,GAAG;gBAAE,MAAMM;YAAQ;YAEvCN,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAC/C,MAAMM,QAAQ,MAAM,CAACM,CAAAA,IAAMA,AAAyC,gBAAzCA,EAAE,IAAI,CAAwB,MAAM;gBAC/D,MAAM;oBAAE,QAAQ;oBAAM,cAAc;oBAAO,YAAY;gBAAE;YAC7D;YAEAZ,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU;YAE9C,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC;gBAC9CE,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC;YACrD;QACJ;IACJ;IAEAG,SAAS,cAAc;QACnBE,GAAG,oDAAoD;YACnD,MAAMC,UAAU;gBAACrD,YAAY,WAAW;gBAASA,YAAY,WAAW;aAAQ;YAChF,MAAM8C,cAAcC,GAAG;gBAAE,MAAMM;YAAQ;YAEvCN,EAAE,gBAAgB,CAAC,OAAO,CAAC,qBAAqB,CAAC;YAEjD,MAAMA,EAAE,SAAS,CAAC,SAAS,CAAC,gBAAgB;YAE5C,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC;gBAC9CE,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC;YACrD;QACJ;IACJ;IAEAG,SAAS,mBAAmB;QACxBE,GAAG,uDAAuD;YACtD,MAAMC,UAAU;gBACZrD,YAAY,WAAW,QAAQ;oBAAE,SAAS;gBAA2B;gBACrEA,YAAY,WAAW,QAAQ;oBAAE,SAAS;gBAA2B;aACxE;YACD,MAAM8C,cAAcC,GAAG;gBAAE,MAAMM;YAAQ;YAEvC,MAAMO,YAAY5D,YAAY,WAAW,QAAQ;gBAC7C,SAAS;YACb;YACA+C,EAAE,qBAAqB,CAAC,OAAO,CAAC,qBAAqB,CAACa;YAEtD,MAAMC,SAAS,MAAMd,EAAE,SAAS,CAAC,cAAc,CAACM,OAAO,CAAC,EAAE;YAE1DJ,OAAOY,QAAQ,OAAO,CAAC;gBAAE,OAAOD;YAAU;YAC1CX,OAAOF,EAAE,qBAAqB,CAAC,OAAO,EAAE,oBAAoB,CAAC;gBACzD,OAAOhD;gBACP,YAAY;YAChB;YACA,MAAMc,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAACO,CAAAA,IAAKA,EAAE,OAAO,GAAG,OAAO,CAAC;oBACzD;oBACA;oBACA;iBACH;YACL;QACJ;QAEAF,GAAG,kDAAkD;YACjD,MAAMC,UAAU;gBAACrD,YAAY,WAAW;aAAQ;YAChD,MAAM8C,cAAcC,GAAG;gBAAE,MAAMM;YAAQ;YAEvC,MAAMS,QAAQ,IAAIC,MAAM;YACxBhB,EAAE,qBAAqB,CAAC,OAAO,CAAC,qBAAqB,CAACe;YAEtD,MAAMD,SAAS,MAAMd,EAAE,SAAS,CAAC,cAAc,CAACM,OAAO,CAAC,EAAE;YAE1DJ,OAAOY,QAAQ,OAAO,CAAC;gBAAEC;YAAM;YAC/Bb,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC;QAClD;IACJ;IAEAG,SAAS,gBAAgB;QACrBE,GAAG,sDAAsD;YACrD,MAAMC,UAAU;gBAACrD,YAAY,WAAW;gBAASA,YAAY,WAAW;aAAQ;YAChF,MAAM8C,cAAcC,GAAG;gBAAE,MAAMM;YAAQ;YAEvCN,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;YAEnD,MAAMA,EAAE,SAAS,CAAC,WAAW,CAAC;YAE9B,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC;gBAC9CE,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC;YACrD;QACJ;IACJ;IAEAG,SAAS,MAAM;QACXE,GAAG,4BAA4B;YAC3BL,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAC/C,MAAM,EAAE;gBACR,MAAM;oBAAE,QAAQ;oBAAM,cAAc;oBAAO,YAAY;gBAAE;YAC7D;YACAA,EAAE,SAAS,CAAC,IAAI;YAChBE,OAAOF,EAAE,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,CAAChD;QAC/C;QAEAqD,GAAG,+BAA+B;YAC9B,MAAMN,cAAcC,GAAG;gBAAE,MAAM,EAAE;YAAC;YAElCE,OAAOF,EAAE,SAAS,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC;YAEzCA,EAAE,SAAS,CAAC,WAAW,CAAC;YACxBE,OAAOF,EAAE,SAAS,CAAC,EAAE,CAAC,eAAe,EAAE,IAAI,CAAC;YAC5CE,OAAOF,EAAE,SAAS,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC;YAEzCA,EAAE,SAAS,CAAC,aAAa;YACzBE,OAAOF,EAAE,SAAS,CAAC,EAAE,CAAC,eAAe,EAAE,QAAQ;YAC/CE,OAAOF,EAAE,SAAS,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC;QAC7C;QAEAK,GAAG,sDAAsD;YACrD,MAAMN,cAAcC,GAAG;gBAAE,MAAM,EAAE;YAAC;YAElCA,EAAE,SAAS,CAAC,WAAW;YACvBE,OAAOF,EAAE,SAAS,CAAC,EAAE,CAAC,eAAe,EAAE,IAAI,CAAC;QAChD;QAEAK,GAAG,mEAAmE;YAClE,MAAMN,cAAcC,GAAG;gBAAE,MAAM,EAAE;YAAC;YAElCE,OAAOF,EAAE,SAAS,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC;YAExCA,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAC/C,MAAM,EAAE;gBACR,MAAM;oBAAE,QAAQ;oBAAM,cAAc;oBAAO,YAAY;gBAAE;YAC7D;YAEAA,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC;YAEpC,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC;YAC5C;QACJ;IACJ;IAEAG,SAAS,iBAAiB;QAKtB,MAAMG,UAAU;YACZrD,YAAY,WAAW,QAAQ;gBAAE,SAAS;YAA2B;YACrEA,YAAY,WAAW,QAAQ;gBAAE,SAAS;YAA2B;YACrEA,YAAY,WAAW,QAAQ;gBAAE,SAAS;YAA2B;SACxE;QAED,MAAMgE,UAAU,OAAOC;YACnBlB,EAAE,mBAAmB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAChD,GAAGkB,KAAK;gBACR,MAAM;oBAAE,GAAGA,MAAM,IAAI;oBAAE,QAAQ;oBAAa,QAAQ;gBAAK;YAC7D;YACA,MAAMlB,EAAE,SAAS,CACZ,OAAO,CAACmB,qBACR,OAAO,CAAC;gBAAE,OAAOnE;gBAAO,YAAYkE,MAAM,EAAE;YAAC;QACtD;QAEAb,GAAG,iDAAiD;YAChD,MAAMN,cAAcC,GAAG;gBAAE,MAAMM;YAAQ;YAEvC,MAAMW,QAAQX,OAAO,CAAC,EAAE;YAExB,MAAMc,OAAOpB,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI;YACrCE,OAAOkB,KAAK,GAAG,CAACb,CAAAA,IAAKA,EAAE,OAAO,GAAG,OAAO,CAAC;gBAAC;gBAAW;gBAAW;aAAU;YAC1EL,OAAQkB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAwB,MAAM,EAAE,IAAI,CAAC;QAC7D;QAEAf,GAAG,uEAAuE;YACtE,MAAMN,cAAcC,GAAG;gBAAE,MAAMM;YAAQ;YAEvCN,EAAE,kBAAkB,CAAC,OAAO,CAAC,qBAAqB,CAAC;gBAC/C,MAAM;uBAAIM;iBAAQ,CAAC,OAAO;gBAC1B,MAAM;oBAAE,QAAQ;oBAAM,cAAc;oBAAO,YAAYA,QAAQ,MAAM;gBAAC;YAC1E;YACAN,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW;YAC7C,MAAMlC,GAAG,OAAO,CAAC;gBACboC,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,WAAW,IAAI,CAAC;YACnE;YAEA,MAAMiB,QAAQX,OAAO,CAAC,EAAE;YAExBJ,OAAOF,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAACO,CAAAA,IAAKA,EAAE,OAAO,GAAG,OAAO,CAAC;gBACzD;gBACA;gBACA;aACH;QACL;IACJ;AACJ"}
@@ -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