@webiny/app-website-builder 6.5.0-beta.1 → 6.5.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/Extension.js +3 -0
  2. package/Extension.js.map +1 -1
  3. package/domain/Page/Page.d.ts +2 -0
  4. package/domain/Page/Page.js +1 -0
  5. package/domain/Page/Page.js.map +1 -1
  6. package/domain/PageRevision/PageRevision.d.ts +11 -0
  7. package/domain/PageRevision/PageRevision.js +20 -0
  8. package/domain/PageRevision/PageRevision.js.map +1 -1
  9. package/features/pages/createPageRevisionFrom/CreatePageRevisionFrom.test.js +41 -1
  10. package/features/pages/createPageRevisionFrom/CreatePageRevisionFrom.test.js.map +1 -1
  11. package/features/pages/createPageRevisionFrom/CreatePageRevisionFromRepository.d.ts +3 -2
  12. package/features/pages/createPageRevisionFrom/CreatePageRevisionFromRepository.js +8 -2
  13. package/features/pages/createPageRevisionFrom/CreatePageRevisionFromRepository.js.map +1 -1
  14. package/features/pages/deletePageRevision/DeletePageRevision.test.d.ts +1 -0
  15. package/features/pages/deletePageRevision/DeletePageRevision.test.js +67 -0
  16. package/features/pages/deletePageRevision/DeletePageRevision.test.js.map +1 -0
  17. package/features/pages/deletePageRevision/DeletePageRevisionGateway.d.ts +1 -1
  18. package/features/pages/deletePageRevision/DeletePageRevisionGateway.js +2 -3
  19. package/features/pages/deletePageRevision/DeletePageRevisionGateway.js.map +1 -1
  20. package/features/pages/deletePageRevision/DeletePageRevisionRepository.d.ts +4 -2
  21. package/features/pages/deletePageRevision/DeletePageRevisionRepository.js +7 -3
  22. package/features/pages/deletePageRevision/DeletePageRevisionRepository.js.map +1 -1
  23. package/features/pages/deletePageRevision/DeletePageRevisionUseCase.js +1 -1
  24. package/features/pages/deletePageRevision/DeletePageRevisionUseCase.js.map +1 -1
  25. package/features/pages/deletePageRevision/abstractions.d.ts +2 -3
  26. package/features/pages/deletePageRevision/abstractions.js.map +1 -1
  27. package/features/pages/getPage/PageGatewayDto.d.ts +2 -0
  28. package/features/pages/publishPage/PublishPage.test.js +41 -1
  29. package/features/pages/publishPage/PublishPage.test.js.map +1 -1
  30. package/features/pages/publishPage/PublishPageRepository.d.ts +3 -2
  31. package/features/pages/publishPage/PublishPageRepository.js +15 -4
  32. package/features/pages/publishPage/PublishPageRepository.js.map +1 -1
  33. package/features/pages/shared/pageGraphQLFields.js +1 -0
  34. package/features/pages/shared/pageGraphQLFields.js.map +1 -1
  35. package/features/pages/unpublishPage/UnpublishPage.test.js +4 -1
  36. package/features/pages/unpublishPage/UnpublishPage.test.js.map +1 -1
  37. package/features/pages/unpublishPage/UnpublishPageRepository.d.ts +3 -2
  38. package/features/pages/unpublishPage/UnpublishPageRepository.js +12 -4
  39. package/features/pages/unpublishPage/UnpublishPageRepository.js.map +1 -1
  40. package/package.json +23 -23
  41. package/presentation/pages/PageEditor/Revisions/RevisionListDrawer.js +4 -0
  42. package/presentation/pages/PageEditor/Revisions/RevisionListDrawer.js.map +1 -1
  43. package/presentation/pages/PageEditor/Revisions/RevisionListItem.d.ts +3 -3
  44. package/presentation/pages/PageEditor/Revisions/RevisionListItem.js +9 -20
  45. package/presentation/pages/PageEditor/Revisions/RevisionListItem.js.map +1 -1
  46. package/presentation/pages/PageEditor/Revisions/RevisionsList.js +7 -19
  47. package/presentation/pages/PageEditor/Revisions/RevisionsList.js.map +1 -1
  48. package/presentation/pages/PageEditor/Revisions/useRevision.d.ts +1 -1
  49. package/presentation/pages/PageEditor/Revisions/useRevision.js +84 -14
  50. package/presentation/pages/PageEditor/Revisions/useRevision.js.map +1 -1
  51. package/presentation/pages/PageEditor/Revisions/useRevisionList.d.ts +3 -0
  52. package/presentation/pages/PageEditor/Revisions/useRevisionList.js +31 -0
  53. package/presentation/pages/PageEditor/Revisions/useRevisionList.js.map +1 -0
  54. package/presentation/pages/PageEditor/TopBar/RevisionsMenu.js +7 -19
  55. package/presentation/pages/PageEditor/TopBar/RevisionsMenu.js.map +1 -1
  56. package/presentation/pages/PageList/PageListPresenter.test.js +3 -1
  57. package/presentation/pages/PageList/PageListPresenter.test.js.map +1 -1
  58. package/presentation/pages/RevisionList/RevisionListPresenter.d.ts +27 -0
  59. package/presentation/pages/RevisionList/RevisionListPresenter.js +73 -0
  60. package/presentation/pages/RevisionList/RevisionListPresenter.js.map +1 -0
  61. package/presentation/pages/RevisionList/RevisionListPresenter.test.d.ts +1 -0
  62. package/presentation/pages/RevisionList/RevisionListPresenter.test.js +219 -0
  63. package/presentation/pages/RevisionList/RevisionListPresenter.test.js.map +1 -0
  64. package/presentation/pages/RevisionList/abstractions.d.ts +34 -0
  65. package/presentation/pages/RevisionList/abstractions.js +5 -0
  66. package/presentation/pages/RevisionList/abstractions.js.map +1 -0
  67. package/presentation/pages/RevisionList/feature.d.ts +3 -0
  68. package/presentation/pages/RevisionList/feature.js +17 -0
  69. package/presentation/pages/RevisionList/feature.js.map +1 -0
  70. package/presentation/pages/RevisionList/index.d.ts +2 -0
  71. package/presentation/pages/RevisionList/index.js +1 -0
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/pages/PageEditor/Revisions/RevisionListItem.js","sources":["../../../../../src/presentation/pages/PageEditor/Revisions/RevisionListItem.tsx"],"sourcesContent":["import React from \"react\";\nconst DateDisplay = ({ date }: { date: string }) => {\n const formatted = React.useMemo(() => {\n const d = new globalThis.Date(date);\n if (isNaN(d.getTime())) {\n return \"\";\n }\n return new Intl.DateTimeFormat(navigator.language, {\n day: \"numeric\",\n month: \"long\",\n year: \"numeric\"\n }).format(d);\n }, [date]);\n return <>{formatted}</>;\n};\nimport { DropdownMenu, Icon, IconButton, List, Text, Tooltip } from \"@webiny/admin-ui\";\nimport { ReactComponent as MoreVerticalIcon } from \"@webiny/icons/more_vert.svg\";\nimport { ReactComponent as LockIcon } from \"@webiny/icons/lock.svg\";\nimport { ReactComponent as BeenHereIcon } from \"@webiny/icons/beenhere.svg\";\nimport { ReactComponent as GestureIcon } from \"@webiny/icons/gesture.svg\";\nimport { ReactComponent as AddIcon } from \"@webiny/icons/add.svg\";\nimport { ReactComponent as EditIcon } from \"@webiny/icons/edit.svg\";\nimport { ReactComponent as PublishIcon } from \"@webiny/icons/visibility.svg\";\nimport { ReactComponent as UnpublishIcon } from \"@webiny/icons/visibility_off.svg\";\nimport { ReactComponent as DeleteIcon } from \"@webiny/icons/delete.svg\";\nimport { useRevision } from \"./useRevision.js\";\nimport type { PageRevision } from \"~/domain/PageRevision/index.js\";\nimport { i18n } from \"@webiny/app/i18n/index.js\";\nimport { HasPermission } from \"~/presentation/security/HasPermission.js\";\n\nconst t = i18n.ns(\"app-website-builder/modules/Pages/PageEditor/Revisions\");\n\nconst getIcon = (revision: PageRevision) => {\n switch (true) {\n case revision.locked && revision.status !== \"published\":\n return {\n icon: (\n <Icon\n label={\"Locked revision\"}\n icon={<LockIcon />}\n data-testid={\"page.revision.status.locked\"}\n />\n ),\n text: \"This revision is locked (it has already been published)\"\n };\n case revision.status === \"published\":\n return {\n icon: (\n <Icon\n label=\"Published revision\"\n icon={<BeenHereIcon />}\n color={\"accent\"}\n data-testid={\"page.revision.status.published\"}\n />\n ),\n text: \"This revision is currently published!\"\n };\n default:\n return {\n icon: (\n <Icon\n label={\"Draft revision\"}\n icon={<GestureIcon />}\n data-testid={\"page.revision.status.draft\"}\n />\n ),\n text: \"This is a draft\"\n };\n }\n};\n\ninterface RevisionListItemProps {\n revision: PageRevision;\n}\n\nconst RevisionListItem = ({ revision }: RevisionListItemProps) => {\n const { createRevision, editRevision, deleteRevision, unpublishRevision, publishRevision } =\n useRevision({\n revision\n });\n\n const { icon, text: tooltipText } = getIcon(revision);\n\n return (\n <List.Item\n icon={<Tooltip content={tooltipText} trigger={icon} />}\n title={revision.title || t`N/A`}\n description={\n <>\n {revision.revisionDescription ? (\n <Text as={\"div\"} size={\"md\"} className={\"mb-2\"}>\n {revision.revisionDescription}\n </Text>\n ) : null}\n <Text as={\"div\"} size={\"sm\"}>\n {t`Last modified by {author} on {time} (#{version})`({\n // Added this because revisionCreatedBy can be returned as null from GraphQL.\n author: revision.createdBy?.displayName,\n time: <DateDisplay date={revision.savedOn} />,\n version: revision.version\n })}\n </Text>\n </>\n }\n about={revision.revisionDescription}\n actions={\n <DropdownMenu\n trigger={\n <IconButton\n variant={\"ghost\"}\n size={\"sm\"}\n iconSize={\"lg\"}\n icon={<MoreVerticalIcon />}\n />\n }\n data-testid={\"page.revisions.more-options\"}\n >\n <>\n <HasPermission entity={\"page\"} action={\"edit\"}>\n <DropdownMenu.Item\n onClick={() => createRevision()}\n data-testid={\"page.revisioncreate-revision\"}\n icon={<AddIcon />}\n text={t`New revision from current`}\n />\n {!revision.locked ? (\n <DropdownMenu.Item\n onClick={() => {\n editRevision();\n }}\n icon={<EditIcon />}\n text={t`Edit revision`}\n />\n ) : null}\n </HasPermission>\n\n <HasPermission entity={\"page\"} action={\"publish\"}>\n {revision.status !== \"published\" ? (\n <DropdownMenu.Item\n onClick={() => publishRevision()}\n icon={<PublishIcon />}\n text={t`Publish revision`}\n />\n ) : null}\n </HasPermission>\n\n <HasPermission entity={\"page\"} action={\"unpublish\"}>\n {revision.status === \"published\" ? (\n <DropdownMenu.Item\n onClick={() => unpublishRevision()}\n data-testid={\"page.revisionunpublish\"}\n icon={<UnpublishIcon />}\n text={t`Unpublish revision`}\n />\n ) : null}\n </HasPermission>\n\n <HasPermission entity={\"page\"} action={\"delete\"}>\n {!revision.locked ? (\n <>\n <DropdownMenu.Separator />\n <DropdownMenu.Item\n onClick={() => deleteRevision()}\n icon={<DeleteIcon />}\n text={t`Delete revision`}\n variant={\"destructive\"}\n />\n </>\n ) : null}\n </HasPermission>\n </>\n </DropdownMenu>\n }\n />\n );\n};\n\nexport default RevisionListItem;\n"],"names":["DateDisplay","date","formatted","React","d","globalThis","isNaN","Intl","navigator","t","i18n","getIcon","revision","Icon","LockIcon","BeenHereIcon","GestureIcon","RevisionListItem","createRevision","editRevision","deleteRevision","unpublishRevision","publishRevision","useRevision","icon","tooltipText","List","Tooltip","Text","DropdownMenu","IconButton","MoreVerticalIcon","HasPermission","AddIcon","EditIcon","PublishIcon","UnpublishIcon","DeleteIcon"],"mappings":"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"}
1
+ {"version":3,"file":"presentation/pages/PageEditor/Revisions/RevisionListItem.js","sources":["../../../../../src/presentation/pages/PageEditor/Revisions/RevisionListItem.tsx"],"sourcesContent":["import React from \"react\";\nconst DateDisplay = ({ date }: { date: string }) => {\n const formatted = React.useMemo(() => {\n const d = new globalThis.Date(date);\n if (isNaN(d.getTime())) {\n return \"\";\n }\n return new Intl.DateTimeFormat(navigator.language, {\n day: \"numeric\",\n month: \"long\",\n year: \"numeric\"\n }).format(d);\n }, [date]);\n return <>{formatted}</>;\n};\nimport { DropdownMenu, Icon, IconButton, List, Text, Tooltip } from \"@webiny/admin-ui\";\nimport { ReactComponent as MoreVerticalIcon } from \"@webiny/icons/more_vert.svg\";\nimport { ReactComponent as LockIcon } from \"@webiny/icons/lock.svg\";\nimport { ReactComponent as BeenHereIcon } from \"@webiny/icons/beenhere.svg\";\nimport { ReactComponent as GestureIcon } from \"@webiny/icons/gesture.svg\";\nimport { ReactComponent as AddIcon } from \"@webiny/icons/add.svg\";\nimport { ReactComponent as EditIcon } from \"@webiny/icons/edit.svg\";\nimport { ReactComponent as PublishIcon } from \"@webiny/icons/visibility.svg\";\nimport { ReactComponent as UnpublishIcon } from \"@webiny/icons/visibility_off.svg\";\nimport { ReactComponent as DeleteIcon } from \"@webiny/icons/delete.svg\";\nimport { useRevision } from \"./useRevision.js\";\nimport type { PageRevision } from \"~/domain/PageRevision/index.js\";\nimport { i18n } from \"@webiny/app/i18n/index.js\";\nimport type { RevisionListPresenter } from \"~/presentation/pages/RevisionList/abstractions.js\";\n\nconst t = i18n.ns(\"app-website-builder/modules/Pages/PageEditor/Revisions\");\n\nconst getIcon = (revision: PageRevision) => {\n switch (true) {\n case revision.locked && revision.status !== \"published\":\n return {\n icon: (\n <Icon\n label={\"Locked revision\"}\n icon={<LockIcon />}\n data-testid={\"page.revision.status.locked\"}\n />\n ),\n text: \"This revision is locked (it has already been published)\"\n };\n case revision.status === \"published\":\n return {\n icon: (\n <Icon\n label=\"Published revision\"\n icon={<BeenHereIcon />}\n color={\"accent\"}\n data-testid={\"page.revision.status.published\"}\n />\n ),\n text: \"This revision is currently published!\"\n };\n default:\n return {\n icon: (\n <Icon\n label={\"Draft revision\"}\n icon={<GestureIcon />}\n data-testid={\"page.revision.status.draft\"}\n />\n ),\n text: \"This is a draft\"\n };\n }\n};\n\ninterface RevisionListItemProps {\n item: RevisionListPresenter.ItemViewModel;\n}\n\nconst RevisionListItem = ({ item }: RevisionListItemProps) => {\n const { revision } = item;\n const { createRevision, editRevision, deleteRevision, unpublishRevision, publishRevision } =\n useRevision({\n revision\n });\n\n const { icon, text: tooltipText } = getIcon(revision);\n\n return (\n <List.Item\n icon={<Tooltip content={tooltipText} trigger={icon} />}\n title={revision.title || t`N/A`}\n description={\n <>\n {revision.revisionDescription ? (\n <Text as={\"div\"} size={\"md\"} className={\"mb-2\"}>\n {revision.revisionDescription}\n </Text>\n ) : null}\n <Text as={\"div\"} size={\"sm\"}>\n {t`Last modified by {author} on {time} (#{version})`({\n // Added this because revisionCreatedBy can be returned as null from GraphQL.\n author: revision.createdBy?.displayName,\n time: <DateDisplay date={revision.savedOn} />,\n version: revision.version\n })}\n </Text>\n </>\n }\n about={revision.revisionDescription}\n actions={\n <DropdownMenu\n trigger={\n <IconButton\n variant={\"ghost\"}\n size={\"sm\"}\n iconSize={\"lg\"}\n icon={<MoreVerticalIcon />}\n />\n }\n data-testid={\"page.revisions.more-options\"}\n >\n <>\n {item.canCreateFrom ? (\n <DropdownMenu.Item\n onClick={() => createRevision()}\n data-testid={\"page.revisioncreate-revision\"}\n icon={<AddIcon />}\n text={t`New revision from current`}\n />\n ) : null}\n\n {item.canEdit ? (\n <DropdownMenu.Item\n onClick={() => {\n editRevision();\n }}\n icon={<EditIcon />}\n text={t`Edit revision`}\n />\n ) : null}\n\n {item.canPublish ? (\n <DropdownMenu.Item\n onClick={() => publishRevision()}\n data-testid={\"page.revisionpublish\"}\n icon={<PublishIcon />}\n text={t`Publish revision`}\n />\n ) : null}\n\n {item.canUnpublish ? (\n <DropdownMenu.Item\n onClick={() => unpublishRevision()}\n data-testid={\"page.revisionunpublish\"}\n icon={<UnpublishIcon />}\n text={t`Unpublish revision`}\n />\n ) : null}\n\n {item.canDelete ? (\n <>\n <DropdownMenu.Separator />\n <DropdownMenu.Item\n onClick={() => deleteRevision()}\n icon={<DeleteIcon />}\n text={t`Delete revision`}\n variant={\"destructive\"}\n />\n </>\n ) : null}\n </>\n </DropdownMenu>\n }\n />\n );\n};\n\nexport default RevisionListItem;\n"],"names":["DateDisplay","date","formatted","React","d","globalThis","isNaN","Intl","navigator","t","i18n","getIcon","revision","Icon","LockIcon","BeenHereIcon","GestureIcon","RevisionListItem","item","createRevision","editRevision","deleteRevision","unpublishRevision","publishRevision","useRevision","icon","tooltipText","List","Tooltip","Text","DropdownMenu","IconButton","MoreVerticalIcon","AddIcon","EditIcon","PublishIcon","UnpublishIcon","DeleteIcon"],"mappings":"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"}
@@ -1,29 +1,17 @@
1
- import react, { useEffect, useState } from "react";
1
+ import react from "react";
2
2
  import { List, OverlayLoader } from "@webiny/admin-ui";
3
3
  import RevisionListItem from "./RevisionListItem.js";
4
- import { useGetPageRevisions } from "../../hooks/useGetPageRevisions.js";
5
- import { parseIdentifier } from "@webiny/utils/parseIdentifier.js";
4
+ import { useRevisionList } from "./useRevisionList.js";
6
5
  const RevisionsList = (props)=>{
7
6
  const { page } = props;
8
- const [revisions, setRevisions] = useState([]);
9
- const { loading, getPageRevisions } = useGetPageRevisions();
10
- useEffect(()=>{
11
- const { id: entryId } = parseIdentifier(page.id);
12
- getPageRevisions({
13
- entryId
14
- }).then((revisions)=>{
15
- setRevisions(revisions.sort((a, b)=>new Date(a.savedOn).getTime() - new Date(b.savedOn).getTime()).reverse());
16
- });
17
- }, [
18
- page.id
19
- ]);
7
+ const { vm } = useRevisionList(page.id);
20
8
  return /*#__PURE__*/ react.createElement("div", {
21
9
  className: "relative"
22
- }, loading && /*#__PURE__*/ react.createElement(OverlayLoader, null), revisions?.length ? /*#__PURE__*/ react.createElement(List, {
10
+ }, (vm.isLoading || vm.isMutating) && /*#__PURE__*/ react.createElement(OverlayLoader, null), vm.revisions.length ? /*#__PURE__*/ react.createElement(List, {
23
11
  "data-testid": "cms.content-form.revisions"
24
- }, revisions.map((revision)=>/*#__PURE__*/ react.createElement(RevisionListItem, {
25
- revision: revision,
26
- key: revision.id
12
+ }, vm.revisions.map((item)=>/*#__PURE__*/ react.createElement(RevisionListItem, {
13
+ item: item,
14
+ key: item.revision.id
27
15
  }))) : /*#__PURE__*/ react.createElement("div", {
28
16
  className: "p-lg"
29
17
  }, "No revisions to show."));
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/pages/PageEditor/Revisions/RevisionsList.js","sources":["../../../../../src/presentation/pages/PageEditor/Revisions/RevisionsList.tsx"],"sourcesContent":["import React, { useEffect, useState } from \"react\";\nimport { List, OverlayLoader } from \"@webiny/admin-ui\";\nimport RevisionListItem from \"./RevisionListItem.js\";\nimport type { Page } from \"~/domain/Page/index.js\";\nimport type { PageRevision } from \"~/domain/PageRevision/index.js\";\nimport { useGetPageRevisions } from \"~/presentation/pages/hooks/useGetPageRevisions.js\";\nimport { parseIdentifier } from \"@webiny/utils/parseIdentifier.js\";\n\ninterface IRevisionsListProps {\n page: Pick<Page, \"id\">;\n}\n\nexport const RevisionsList = (props: IRevisionsListProps) => {\n const { page } = props;\n\n const [revisions, setRevisions] = useState<PageRevision[]>([]);\n const { loading, getPageRevisions } = useGetPageRevisions();\n\n useEffect(() => {\n const { id: entryId } = parseIdentifier(page.id);\n getPageRevisions({\n entryId\n }).then(revisions => {\n setRevisions(\n revisions\n .sort((a, b) => {\n return new Date(a.savedOn).getTime() - new Date(b.savedOn).getTime();\n })\n .reverse()\n );\n });\n }, [page.id]);\n\n return (\n <div className={\"relative\"}>\n {loading && <OverlayLoader />}\n {revisions?.length ? (\n <List data-testid={\"cms.content-form.revisions\"}>\n {revisions.map(revision => (\n <RevisionListItem revision={revision} key={revision.id} />\n ))}\n </List>\n ) : (\n <div className={\"p-lg\"}>No revisions to show.</div>\n )}\n </div>\n );\n};\n"],"names":["RevisionsList","props","page","revisions","setRevisions","useState","loading","getPageRevisions","useGetPageRevisions","useEffect","entryId","parseIdentifier","a","b","Date","OverlayLoader","List","revision","RevisionListItem"],"mappings":";;;;;AAYO,MAAMA,gBAAgB,CAACC;IAC1B,MAAM,EAAEC,IAAI,EAAE,GAAGD;IAEjB,MAAM,CAACE,WAAWC,aAAa,GAAGC,SAAyB,EAAE;IAC7D,MAAM,EAAEC,OAAO,EAAEC,gBAAgB,EAAE,GAAGC;IAEtCC,UAAU;QACN,MAAM,EAAE,IAAIC,OAAO,EAAE,GAAGC,gBAAgBT,KAAK,EAAE;QAC/CK,iBAAiB;YACbG;QACJ,GAAG,IAAI,CAACP,CAAAA;YACJC,aACID,UACK,IAAI,CAAC,CAACS,GAAGC,IACC,IAAIC,KAAKF,EAAE,OAAO,EAAE,OAAO,KAAK,IAAIE,KAAKD,EAAE,OAAO,EAAE,OAAO,IAErE,OAAO;QAEpB;IACJ,GAAG;QAACX,KAAK,EAAE;KAAC;IAEZ,OAAO,WAAP,GACI,oBAAC;QAAI,WAAW;OACXI,WAAW,WAAXA,GAAW,oBAACS,eAAaA,OACzBZ,WAAW,SAAS,WAAT,GACR,oBAACa,MAAIA;QAAC,eAAa;OACdb,UAAU,GAAG,CAACc,CAAAA,WAAAA,WAAAA,GACX,oBAACC,kBAAgBA;YAAC,UAAUD;YAAU,KAAKA,SAAS,EAAE;6BAI9D,oBAAC;QAAI,WAAW;OAAQ;AAIxC"}
1
+ {"version":3,"file":"presentation/pages/PageEditor/Revisions/RevisionsList.js","sources":["../../../../../src/presentation/pages/PageEditor/Revisions/RevisionsList.tsx"],"sourcesContent":["import React from \"react\";\nimport { List, OverlayLoader } from \"@webiny/admin-ui\";\nimport RevisionListItem from \"./RevisionListItem.js\";\nimport type { Page } from \"~/domain/Page/index.js\";\nimport { useRevisionList } from \"./useRevisionList.js\";\n\ninterface IRevisionsListProps {\n page: Pick<Page, \"id\">;\n}\n\nexport const RevisionsList = (props: IRevisionsListProps) => {\n const { page } = props;\n const { vm } = useRevisionList(page.id);\n\n return (\n <div className={\"relative\"}>\n {(vm.isLoading || vm.isMutating) && <OverlayLoader />}\n {vm.revisions.length ? (\n <List data-testid={\"cms.content-form.revisions\"}>\n {vm.revisions.map(item => (\n <RevisionListItem item={item} key={item.revision.id} />\n ))}\n </List>\n ) : (\n <div className={\"p-lg\"}>No revisions to show.</div>\n )}\n </div>\n );\n};\n"],"names":["RevisionsList","props","page","vm","useRevisionList","OverlayLoader","List","item","RevisionListItem"],"mappings":";;;;AAUO,MAAMA,gBAAgB,CAACC;IAC1B,MAAM,EAAEC,IAAI,EAAE,GAAGD;IACjB,MAAM,EAAEE,EAAE,EAAE,GAAGC,gBAAgBF,KAAK,EAAE;IAEtC,OAAO,WAAP,GACI,oBAAC;QAAI,WAAW;OACVC,AAAAA,CAAAA,GAAG,SAAS,IAAIA,GAAG,UAAS,mBAAM,oBAACE,eAAaA,OACjDF,GAAG,SAAS,CAAC,MAAM,GAAG,WAAH,GAChB,oBAACG,MAAIA;QAAC,eAAa;OACdH,GAAG,SAAS,CAAC,GAAG,CAACI,CAAAA,OAAAA,WAAAA,GACd,oBAACC,kBAAgBA;YAAC,MAAMD;YAAM,KAAKA,KAAK,QAAQ,CAAC,EAAE;6BAI3D,oBAAC;QAAI,WAAW;OAAQ;AAIxC"}
@@ -3,7 +3,7 @@ export interface UseRevisionProps {
3
3
  revision: PageRevision;
4
4
  }
5
5
  export declare const useRevision: (props: UseRevisionProps) => {
6
- createRevision: () => void;
6
+ createRevision: () => Promise<void>;
7
7
  editRevision: () => void;
8
8
  deleteRevision: () => void;
9
9
  publishRevision: () => void;
@@ -1,49 +1,119 @@
1
+ import react, { useCallback } from "react";
1
2
  import { useCreatePageRevisionFrom, useDeletePageRevision, usePublishPage, useUnpublishPage } from "../../../../features/pages/index.js";
2
- import { useCallback } from "react";
3
+ import { Text, useToast } from "@webiny/admin-ui";
4
+ import { useDialogs } from "@webiny/app-admin";
5
+ import { ReactComponent } from "@webiny/icons/visibility.svg";
6
+ import { ReactComponent as visibility_off_svg_ReactComponent } from "@webiny/icons/visibility_off.svg";
7
+ import { ReactComponent as delete_svg_ReactComponent } from "@webiny/icons/delete.svg";
3
8
  import { Routes } from "../../../../routes.js";
4
9
  import { useRouter } from "@webiny/app";
10
+ import { usePageEditorDrawer } from "./usePageEditorDrawer.js";
5
11
  const useRevision = (props)=>{
6
12
  const { revision } = props;
7
13
  const { goToRoute } = useRouter();
14
+ const { openRevisionList } = usePageEditorDrawer();
15
+ const { showDialog } = useDialogs();
16
+ const { showSuccessToast, showWarningToast } = useToast();
8
17
  const { createPageRevisionFrom } = useCreatePageRevisionFrom();
9
18
  const { deletePageRevision } = useDeletePageRevision();
10
19
  const { publishPage } = usePublishPage();
11
20
  const { unpublishPage } = useUnpublishPage();
12
- const createRevision = useCallback(()=>{
13
- createPageRevisionFrom({
21
+ const createRevision = useCallback(async ()=>{
22
+ await createPageRevisionFrom({
14
23
  id: revision.id
15
24
  });
16
25
  }, [
17
26
  revision.id
18
27
  ]);
19
28
  const deleteRevision = useCallback(()=>{
20
- deletePageRevision({
21
- id: revision.id,
22
- permanently: true
29
+ showDialog({
30
+ title: "Delete revision",
31
+ icon: /*#__PURE__*/ react.createElement(delete_svg_ReactComponent, null),
32
+ content: /*#__PURE__*/ react.createElement(Text, null, `You are about to delete revision #${revision.version}. This cannot be undone. Are you sure you want to continue?`),
33
+ acceptLabel: "Yes, delete this revision!",
34
+ cancelLabel: "Cancel",
35
+ onAccept: async ()=>{
36
+ try {
37
+ await deletePageRevision({
38
+ id: revision.id
39
+ });
40
+ showSuccessToast({
41
+ title: `Revision #${revision.version} was deleted successfully!`
42
+ });
43
+ } catch (ex) {
44
+ showWarningToast({
45
+ title: "Could not delete the revision.",
46
+ description: ex.message
47
+ });
48
+ }
49
+ }
23
50
  });
24
51
  }, [
25
- revision.id
52
+ revision.id,
53
+ revision.version
26
54
  ]);
27
55
  const publishRevision = useCallback(()=>{
28
- publishPage({
29
- id: revision.id
56
+ showDialog({
57
+ title: "Publish revision",
58
+ icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
59
+ content: /*#__PURE__*/ react.createElement(Text, null, `You are about to publish revision #${revision.version}. Are you sure you want to continue?`),
60
+ acceptLabel: "Yes, publish this revision!",
61
+ cancelLabel: "Cancel",
62
+ onAccept: async ()=>{
63
+ try {
64
+ await publishPage({
65
+ id: revision.id
66
+ });
67
+ showSuccessToast({
68
+ title: `Revision #${revision.version} was published successfully!`
69
+ });
70
+ } catch (ex) {
71
+ showWarningToast({
72
+ title: "Could not publish the revision.",
73
+ description: ex.message
74
+ });
75
+ }
76
+ }
30
77
  });
31
78
  }, [
32
- revision.id
79
+ revision.id,
80
+ revision.version
33
81
  ]);
34
82
  const unpublishRevision = useCallback(()=>{
35
- unpublishPage({
36
- id: revision.id
83
+ showDialog({
84
+ title: "Unpublish revision",
85
+ icon: /*#__PURE__*/ react.createElement(visibility_off_svg_ReactComponent, null),
86
+ content: /*#__PURE__*/ react.createElement(Text, null, `You are about to unpublish revision #${revision.version}, which will take the page off the live website. Are you sure you want to continue?`),
87
+ acceptLabel: "Yes, unpublish this revision!",
88
+ cancelLabel: "Cancel",
89
+ onAccept: async ()=>{
90
+ try {
91
+ await unpublishPage({
92
+ id: revision.id
93
+ });
94
+ showSuccessToast({
95
+ title: `Revision #${revision.version} was unpublished successfully!`
96
+ });
97
+ } catch (ex) {
98
+ showWarningToast({
99
+ title: "Could not unpublish the revision.",
100
+ description: ex.message
101
+ });
102
+ }
103
+ }
37
104
  });
38
105
  }, [
39
- revision.id
106
+ revision.id,
107
+ revision.version
40
108
  ]);
41
109
  const editRevision = useCallback(()=>{
110
+ openRevisionList(false);
42
111
  goToRoute(Routes.Pages.Editor, {
43
112
  id: revision.id
44
113
  });
45
114
  }, [
46
- revision.id
115
+ revision.id,
116
+ openRevisionList
47
117
  ]);
48
118
  return {
49
119
  createRevision,
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/pages/PageEditor/Revisions/useRevision.js","sources":["../../../../../src/presentation/pages/PageEditor/Revisions/useRevision.tsx"],"sourcesContent":["import type { PageRevision } from \"~/domain/PageRevision/index.js\";\nimport {\n usePublishPage,\n useUnpublishPage,\n useCreatePageRevisionFrom,\n useDeletePageRevision\n} from \"~/features/pages/index.js\";\nimport { useCallback } from \"react\";\nimport { Routes } from \"~/routes.js\";\nimport { useRouter } from \"@webiny/app\";\n\nexport interface UseRevisionProps {\n revision: PageRevision;\n}\n\nexport const useRevision = (props: UseRevisionProps) => {\n const { revision } = props;\n\n const { goToRoute } = useRouter();\n\n const { createPageRevisionFrom } = useCreatePageRevisionFrom();\n const { deletePageRevision } = useDeletePageRevision();\n const { publishPage } = usePublishPage();\n const { unpublishPage } = useUnpublishPage();\n\n const createRevision = useCallback(() => {\n createPageRevisionFrom({\n id: revision.id\n });\n }, [revision.id]);\n\n const deleteRevision = useCallback(() => {\n deletePageRevision({\n id: revision.id,\n permanently: true\n });\n }, [revision.id]);\n\n const publishRevision = useCallback(() => {\n publishPage({\n id: revision.id\n });\n }, [revision.id]);\n\n const unpublishRevision = useCallback(() => {\n unpublishPage({\n id: revision.id\n });\n }, [revision.id]);\n\n const editRevision = useCallback(() => {\n goToRoute(Routes.Pages.Editor, {\n id: revision.id\n });\n }, [revision.id]);\n\n return {\n createRevision,\n editRevision,\n deleteRevision,\n publishRevision,\n unpublishRevision\n };\n};\n"],"names":["useRevision","props","revision","goToRoute","useRouter","createPageRevisionFrom","useCreatePageRevisionFrom","deletePageRevision","useDeletePageRevision","publishPage","usePublishPage","unpublishPage","useUnpublishPage","createRevision","useCallback","deleteRevision","publishRevision","unpublishRevision","editRevision","Routes"],"mappings":";;;;AAeO,MAAMA,cAAc,CAACC;IACxB,MAAM,EAAEC,QAAQ,EAAE,GAAGD;IAErB,MAAM,EAAEE,SAAS,EAAE,GAAGC;IAEtB,MAAM,EAAEC,sBAAsB,EAAE,GAAGC;IACnC,MAAM,EAAEC,kBAAkB,EAAE,GAAGC;IAC/B,MAAM,EAAEC,WAAW,EAAE,GAAGC;IACxB,MAAM,EAAEC,aAAa,EAAE,GAAGC;IAE1B,MAAMC,iBAAiBC,YAAY;QAC/BT,uBAAuB;YACnB,IAAIH,SAAS,EAAE;QACnB;IACJ,GAAG;QAACA,SAAS,EAAE;KAAC;IAEhB,MAAMa,iBAAiBD,YAAY;QAC/BP,mBAAmB;YACf,IAAIL,SAAS,EAAE;YACf,aAAa;QACjB;IACJ,GAAG;QAACA,SAAS,EAAE;KAAC;IAEhB,MAAMc,kBAAkBF,YAAY;QAChCL,YAAY;YACR,IAAIP,SAAS,EAAE;QACnB;IACJ,GAAG;QAACA,SAAS,EAAE;KAAC;IAEhB,MAAMe,oBAAoBH,YAAY;QAClCH,cAAc;YACV,IAAIT,SAAS,EAAE;QACnB;IACJ,GAAG;QAACA,SAAS,EAAE;KAAC;IAEhB,MAAMgB,eAAeJ,YAAY;QAC7BX,UAAUgB,OAAO,KAAK,CAAC,MAAM,EAAE;YAC3B,IAAIjB,SAAS,EAAE;QACnB;IACJ,GAAG;QAACA,SAAS,EAAE;KAAC;IAEhB,OAAO;QACHW;QACAK;QACAH;QACAC;QACAC;IACJ;AACJ"}
1
+ {"version":3,"file":"presentation/pages/PageEditor/Revisions/useRevision.js","sources":["../../../../../src/presentation/pages/PageEditor/Revisions/useRevision.tsx"],"sourcesContent":["import React from \"react\";\nimport type { PageRevision } from \"~/domain/PageRevision/index.js\";\nimport {\n usePublishPage,\n useUnpublishPage,\n useCreatePageRevisionFrom,\n useDeletePageRevision\n} from \"~/features/pages/index.js\";\nimport { useCallback } from \"react\";\nimport { Text, useToast } from \"@webiny/admin-ui\";\nimport { useDialogs } from \"@webiny/app-admin\";\nimport { ReactComponent as PublishIcon } from \"@webiny/icons/visibility.svg\";\nimport { ReactComponent as UnpublishIcon } from \"@webiny/icons/visibility_off.svg\";\nimport { ReactComponent as DeleteIcon } from \"@webiny/icons/delete.svg\";\nimport { Routes } from \"~/routes.js\";\nimport { useRouter } from \"@webiny/app\";\nimport { usePageEditorDrawer } from \"./usePageEditorDrawer.js\";\n\nexport interface UseRevisionProps {\n revision: PageRevision;\n}\n\nexport const useRevision = (props: UseRevisionProps) => {\n const { revision } = props;\n\n const { goToRoute } = useRouter();\n const { openRevisionList } = usePageEditorDrawer();\n const { showDialog } = useDialogs();\n const { showSuccessToast, showWarningToast } = useToast();\n\n const { createPageRevisionFrom } = useCreatePageRevisionFrom();\n const { deletePageRevision } = useDeletePageRevision();\n const { publishPage } = usePublishPage();\n const { unpublishPage } = useUnpublishPage();\n\n const createRevision = useCallback(async () => {\n await createPageRevisionFrom({\n id: revision.id\n });\n }, [revision.id]);\n\n const deleteRevision = useCallback(() => {\n showDialog({\n title: \"Delete revision\",\n icon: <DeleteIcon />,\n content: (\n <Text>\n {`You are about to delete revision #${revision.version}. This cannot be undone. Are you sure you want to continue?`}\n </Text>\n ),\n acceptLabel: \"Yes, delete this revision!\",\n cancelLabel: \"Cancel\",\n onAccept: async () => {\n try {\n await deletePageRevision({\n id: revision.id\n });\n\n showSuccessToast({\n title: `Revision #${revision.version} was deleted successfully!`\n });\n } catch (ex) {\n showWarningToast({\n title: \"Could not delete the revision.\",\n description: ex.message\n });\n }\n }\n });\n }, [revision.id, revision.version]);\n\n const publishRevision = useCallback(() => {\n showDialog({\n title: \"Publish revision\",\n icon: <PublishIcon />,\n content: (\n <Text>\n {`You are about to publish revision #${revision.version}. Are you sure you want to continue?`}\n </Text>\n ),\n acceptLabel: \"Yes, publish this revision!\",\n cancelLabel: \"Cancel\",\n onAccept: async () => {\n try {\n await publishPage({\n id: revision.id\n });\n\n showSuccessToast({\n title: `Revision #${revision.version} was published successfully!`\n });\n } catch (ex) {\n showWarningToast({\n title: \"Could not publish the revision.\",\n description: ex.message\n });\n }\n }\n });\n }, [revision.id, revision.version]);\n\n const unpublishRevision = useCallback(() => {\n showDialog({\n title: \"Unpublish revision\",\n icon: <UnpublishIcon />,\n content: (\n <Text>\n {`You are about to unpublish revision #${revision.version}, which will take the page off the live website. Are you sure you want to continue?`}\n </Text>\n ),\n acceptLabel: \"Yes, unpublish this revision!\",\n cancelLabel: \"Cancel\",\n onAccept: async () => {\n try {\n await unpublishPage({\n id: revision.id\n });\n\n showSuccessToast({\n title: `Revision #${revision.version} was unpublished successfully!`\n });\n } catch (ex) {\n showWarningToast({\n title: \"Could not unpublish the revision.\",\n description: ex.message\n });\n }\n }\n });\n }, [revision.id, revision.version]);\n\n const editRevision = useCallback(() => {\n // The drawer lives outside the editor, so it would stay open across the navigation.\n openRevisionList(false);\n\n goToRoute(Routes.Pages.Editor, {\n id: revision.id\n });\n }, [revision.id, openRevisionList]);\n\n return {\n createRevision,\n editRevision,\n deleteRevision,\n publishRevision,\n unpublishRevision\n };\n};\n"],"names":["useRevision","props","revision","goToRoute","useRouter","openRevisionList","usePageEditorDrawer","showDialog","useDialogs","showSuccessToast","showWarningToast","useToast","createPageRevisionFrom","useCreatePageRevisionFrom","deletePageRevision","useDeletePageRevision","publishPage","usePublishPage","unpublishPage","useUnpublishPage","createRevision","useCallback","deleteRevision","DeleteIcon","Text","ex","publishRevision","PublishIcon","unpublishRevision","UnpublishIcon","editRevision","Routes"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare const useRevisionList: (pageId: string) => {
2
+ vm: import("../../RevisionList").IRevisionListVm;
3
+ };
@@ -0,0 +1,31 @@
1
+ import { useEffect, useMemo, useState } from "react";
2
+ import { autorun } from "mobx";
3
+ import { useFeature } from "@webiny/app";
4
+ import { parseIdentifier } from "@webiny/utils/parseIdentifier.js";
5
+ import { RevisionListFeature } from "../../RevisionList/feature.js";
6
+ const useRevisionList = (pageId)=>{
7
+ const { presenter } = useFeature(RevisionListFeature);
8
+ const { id: entryId } = useMemo(()=>parseIdentifier(pageId), [
9
+ pageId
10
+ ]);
11
+ useEffect(()=>{
12
+ presenter.init({
13
+ entryId
14
+ });
15
+ }, [
16
+ entryId,
17
+ presenter
18
+ ]);
19
+ const [vm, setVm] = useState(presenter.vm);
20
+ useEffect(()=>autorun(()=>{
21
+ setVm(presenter.vm);
22
+ }), [
23
+ presenter
24
+ ]);
25
+ return {
26
+ vm
27
+ };
28
+ };
29
+ export { useRevisionList };
30
+
31
+ //# sourceMappingURL=useRevisionList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/pages/PageEditor/Revisions/useRevisionList.js","sources":["../../../../../src/presentation/pages/PageEditor/Revisions/useRevisionList.ts"],"sourcesContent":["import { useEffect, useMemo, useState } from \"react\";\nimport { autorun } from \"mobx\";\nimport { useFeature } from \"@webiny/app\";\nimport { parseIdentifier } from \"@webiny/utils/parseIdentifier.js\";\nimport { RevisionListFeature } from \"~/presentation/pages/RevisionList/feature.js\";\n\nexport const useRevisionList = (pageId: string) => {\n const { presenter } = useFeature(RevisionListFeature);\n\n const { id: entryId } = useMemo(() => parseIdentifier(pageId), [pageId]);\n\n useEffect(() => {\n presenter.init({ entryId });\n }, [entryId, presenter]);\n\n const [vm, setVm] = useState(presenter.vm);\n\n useEffect(() => {\n return autorun(() => {\n setVm(presenter.vm);\n });\n }, [presenter]);\n\n return { vm };\n};\n"],"names":["useRevisionList","pageId","presenter","useFeature","RevisionListFeature","entryId","useMemo","parseIdentifier","useEffect","vm","setVm","useState","autorun"],"mappings":";;;;;AAMO,MAAMA,kBAAkB,CAACC;IAC5B,MAAM,EAAEC,SAAS,EAAE,GAAGC,WAAWC;IAEjC,MAAM,EAAE,IAAIC,OAAO,EAAE,GAAGC,QAAQ,IAAMC,gBAAgBN,SAAS;QAACA;KAAO;IAEvEO,UAAU;QACNN,UAAU,IAAI,CAAC;YAAEG;QAAQ;IAC7B,GAAG;QAACA;QAASH;KAAU;IAEvB,MAAM,CAACO,IAAIC,MAAM,GAAGC,SAAST,UAAU,EAAE;IAEzCM,UAAU,IACCI,QAAQ;YACXF,MAAMR,UAAU,EAAE;QACtB,IACD;QAACA;KAAU;IAEd,OAAO;QAAEO;IAAG;AAChB"}
@@ -1,11 +1,11 @@
1
- import react, { useCallback, useEffect, useState } from "react";
1
+ import react, { useCallback } from "react";
2
2
  import { Button, DropdownMenu, Text } from "@webiny/admin-ui";
3
3
  import { ReactComponent } from "@webiny/icons/keyboard_arrow_down.svg";
4
4
  import { ReactComponent as draw_svg_ReactComponent } from "@webiny/icons/draw.svg";
5
5
  import { ReactComponent as lock_svg_ReactComponent } from "@webiny/icons/lock.svg";
6
6
  import { ReactComponent as remove_red_eye_svg_ReactComponent } from "@webiny/icons/remove_red_eye.svg";
7
- import { useGetPageRevisions } from "../../../../features/pages/index.js";
8
7
  import { useSelectFromDocument } from "../../../../BaseEditor/hooks/useSelectFromDocument.js";
8
+ import { useRevisionList } from "../Revisions/useRevisionList.js";
9
9
  import { useRouter } from "@webiny/app-admin";
10
10
  import { Routes } from "../../../../routes.js";
11
11
  import { usePageEditorDrawer } from "../Revisions/usePageEditorDrawer.js";
@@ -17,23 +17,11 @@ const statusIcon = {
17
17
  };
18
18
  const RevisionsMenu = ()=>{
19
19
  const { getLink } = useRouter();
20
- const [revisions, setRevisions] = useState([]);
21
- const { loading, getPageRevisions } = useGetPageRevisions();
22
20
  const id = useSelectFromDocument((document)=>document.id);
23
- const status = useSelectFromDocument((document)=>document.status);
24
21
  const { openRevisionList } = usePageEditorDrawer();
25
- useEffect(()=>{
26
- const [entryId] = id.split("#");
27
- getPageRevisions({
28
- entryId
29
- }).then((revisions)=>{
30
- setRevisions(revisions.sort((a, b)=>new Date(a.savedOn).getTime() - new Date(b.savedOn).getTime()).reverse());
31
- });
32
- }, [
33
- id,
34
- status
35
- ]);
36
- const currentRevision = revisions.find((r)=>r.id === id);
22
+ const { vm } = useRevisionList(id);
23
+ const { revisions, isLoading } = vm;
24
+ const currentRevision = revisions.find((item)=>item.revision.id === id)?.revision;
37
25
  const goToRevision = useCallback((id)=>{
38
26
  window.location.pathname = getLink(Routes.Pages.Editor, {
39
27
  id
@@ -44,13 +32,13 @@ const RevisionsMenu = ()=>{
44
32
  }, []);
45
33
  return /*#__PURE__*/ react.createElement(DropdownMenu, {
46
34
  trigger: /*#__PURE__*/ react.createElement(Button, {
47
- disabled: loading,
35
+ disabled: isLoading,
48
36
  variant: "ghost",
49
37
  text: currentRevision ? currentRevision.getLabel() : "Loading...",
50
38
  icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
51
39
  iconPosition: "end"
52
40
  })
53
- }, revisions.slice(0, 5).map((revision)=>/*#__PURE__*/ react.createElement(Item, {
41
+ }, revisions.slice(0, 5).map(({ revision })=>/*#__PURE__*/ react.createElement(Item, {
54
42
  key: revision.id,
55
43
  className: "cursor-pointer",
56
44
  onClick: ()=>goToRevision(revision.id),
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/pages/PageEditor/TopBar/RevisionsMenu.js","sources":["../../../../../src/presentation/pages/PageEditor/TopBar/RevisionsMenu.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback } from \"react\";\nimport { Button, DropdownMenu, Text } from \"@webiny/admin-ui\";\nimport { ReactComponent as ArrowDown } from \"@webiny/icons/keyboard_arrow_down.svg\";\nimport { ReactComponent as Draft } from \"@webiny/icons/draw.svg\";\nimport { ReactComponent as Unpublished } from \"@webiny/icons/lock.svg\";\nimport { ReactComponent as Published } from \"@webiny/icons/remove_red_eye.svg\";\nimport { useGetPageRevisions } from \"~/features/pages/index.js\";\nimport { useSelectFromDocument } from \"~/BaseEditor/hooks/useSelectFromDocument.js\";\nimport type { PageRevision } from \"~/domain/PageRevision/index.js\";\nimport type { EditorPage } from \"@webiny/website-builder-sdk\";\nimport { useRouter } from \"@webiny/app-admin\";\nimport { Routes } from \"~/routes.js\";\nimport { usePageEditorDrawer } from \"~/presentation/pages/PageEditor/Revisions/usePageEditorDrawer.js\";\n\nconst { Item } = DropdownMenu;\n\nconst statusIcon: Record<string, React.JSX.Element> = {\n draft: <Draft />,\n published: <Published />,\n unpublished: <Unpublished />\n};\n\nexport const RevisionsMenu = () => {\n const { getLink } = useRouter();\n const [revisions, setRevisions] = useState<PageRevision[]>([]);\n const { loading, getPageRevisions } = useGetPageRevisions();\n const id = useSelectFromDocument(document => document.id);\n const status = useSelectFromDocument<string, EditorPage>(document => document.status);\n\n const { openRevisionList } = usePageEditorDrawer();\n\n useEffect(() => {\n const [entryId] = id.split(\"#\");\n getPageRevisions({ entryId }).then(revisions => {\n setRevisions(\n revisions\n .sort((a, b) => {\n return new Date(a.savedOn).getTime() - new Date(b.savedOn).getTime();\n })\n .reverse()\n );\n });\n }, [id, status]);\n\n const currentRevision = revisions.find(r => r.id === id);\n\n const goToRevision = useCallback((id: string) => {\n // TODO: make this work without a full app reload\n window.location.pathname = getLink(Routes.Pages.Editor, { id });\n }, []);\n\n const onOpenRevisionList = useCallback(() => {\n openRevisionList(true);\n }, []);\n\n return (\n <DropdownMenu\n trigger={\n <Button\n disabled={loading}\n variant=\"ghost\"\n text={currentRevision ? currentRevision.getLabel() : \"Loading...\"}\n icon={<ArrowDown />}\n iconPosition={\"end\"}\n />\n }\n >\n {revisions.slice(0, 5).map(revision => (\n <Item\n key={revision.id}\n className={\"cursor-pointer\"}\n onClick={() => goToRevision(revision.id)}\n icon={\n <Item.Icon\n label={revision.getLabel()}\n element={statusIcon[revision.status]}\n />\n }\n text={<Text size={\"sm\"}>{revision.getLabel()}</Text>}\n />\n ))}\n\n <DropdownMenu.Separator />\n <DropdownMenu.Item\n key={\"revisions-all\"}\n onClick={onOpenRevisionList}\n text={\n <>\n <Text size={\"sm\"}>Show All Revisions</Text>\n </>\n }\n />\n </DropdownMenu>\n );\n};\n"],"names":["Item","DropdownMenu","statusIcon","Draft","Published","Unpublished","RevisionsMenu","getLink","useRouter","revisions","setRevisions","useState","loading","getPageRevisions","useGetPageRevisions","id","useSelectFromDocument","document","status","openRevisionList","usePageEditorDrawer","useEffect","entryId","a","b","Date","currentRevision","r","goToRevision","useCallback","window","Routes","onOpenRevisionList","Button","ArrowDown","revision","Text"],"mappings":";;;;;;;;;;;AAcA,MAAM,EAAEA,MAAAA,IAAI,EAAE,GAAGC;AAEjB,MAAMC,aAAgD;IAClD,OAAO,WAAP,GAAO,oBAACC,yBAAKA;IACb,WAAW,WAAX,GAAW,oBAACC,mCAASA;IACrB,aAAa,WAAb,GAAa,oBAACC,yBAAWA;AAC7B;AAEO,MAAMC,gBAAgB;IACzB,MAAM,EAAEC,OAAO,EAAE,GAAGC;IACpB,MAAM,CAACC,WAAWC,aAAa,GAAGC,SAAyB,EAAE;IAC7D,MAAM,EAAEC,OAAO,EAAEC,gBAAgB,EAAE,GAAGC;IACtC,MAAMC,KAAKC,sBAAsBC,CAAAA,WAAYA,SAAS,EAAE;IACxD,MAAMC,SAASF,sBAA0CC,CAAAA,WAAYA,SAAS,MAAM;IAEpF,MAAM,EAAEE,gBAAgB,EAAE,GAAGC;IAE7BC,UAAU;QACN,MAAM,CAACC,QAAQ,GAAGP,GAAG,KAAK,CAAC;QAC3BF,iBAAiB;YAAES;QAAQ,GAAG,IAAI,CAACb,CAAAA;YAC/BC,aACID,UACK,IAAI,CAAC,CAACc,GAAGC,IACC,IAAIC,KAAKF,EAAE,OAAO,EAAE,OAAO,KAAK,IAAIE,KAAKD,EAAE,OAAO,EAAE,OAAO,IAErE,OAAO;QAEpB;IACJ,GAAG;QAACT;QAAIG;KAAO;IAEf,MAAMQ,kBAAkBjB,UAAU,IAAI,CAACkB,CAAAA,IAAKA,EAAE,EAAE,KAAKZ;IAErD,MAAMa,eAAeC,YAAY,CAACd;QAE9Be,OAAO,QAAQ,CAAC,QAAQ,GAAGvB,QAAQwB,OAAO,KAAK,CAAC,MAAM,EAAE;YAAEhB;QAAG;IACjE,GAAG,EAAE;IAEL,MAAMiB,qBAAqBH,YAAY;QACnCV,iBAAiB;IACrB,GAAG,EAAE;IAEL,OAAO,WAAP,GACI,oBAAClB,cAAYA;QACT,uBACI,oBAACgC,QAAMA;YACH,UAAUrB;YACV,SAAQ;YACR,MAAMc,kBAAkBA,gBAAgB,QAAQ,KAAK;YACrD,oBAAM,oBAACQ,gBAASA;YAChB,cAAc;;OAIrBzB,UAAU,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC0B,CAAAA,WAAAA,WAAAA,GACvB,oBAACnC,MAAIA;YACD,KAAKmC,SAAS,EAAE;YAChB,WAAW;YACX,SAAS,IAAMP,aAAaO,SAAS,EAAE;YACvC,oBACI,oBAACnC,KAAK,IAAI;gBACN,OAAOmC,SAAS,QAAQ;gBACxB,SAASjC,UAAU,CAACiC,SAAS,MAAM,CAAC;;YAG5C,oBAAM,oBAACC,MAAIA;gBAAC,MAAM;eAAOD,SAAS,QAAQ;2BAIlD,oBAAClC,aAAa,SAAS,uBACvB,oBAACA,aAAa,IAAI;QACd,KAAK;QACL,SAAS+B;QACT,oBACI,wDACI,oBAACI,MAAIA;YAAC,MAAM;WAAM;;AAM1C"}
1
+ {"version":3,"file":"presentation/pages/PageEditor/TopBar/RevisionsMenu.js","sources":["../../../../../src/presentation/pages/PageEditor/TopBar/RevisionsMenu.tsx"],"sourcesContent":["import React, { useCallback } from \"react\";\nimport { Button, DropdownMenu, Text } from \"@webiny/admin-ui\";\nimport { ReactComponent as ArrowDown } from \"@webiny/icons/keyboard_arrow_down.svg\";\nimport { ReactComponent as Draft } from \"@webiny/icons/draw.svg\";\nimport { ReactComponent as Unpublished } from \"@webiny/icons/lock.svg\";\nimport { ReactComponent as Published } from \"@webiny/icons/remove_red_eye.svg\";\nimport { useSelectFromDocument } from \"~/BaseEditor/hooks/useSelectFromDocument.js\";\nimport { useRevisionList } from \"~/presentation/pages/PageEditor/Revisions/useRevisionList.js\";\nimport { useRouter } from \"@webiny/app-admin\";\nimport { Routes } from \"~/routes.js\";\nimport { usePageEditorDrawer } from \"~/presentation/pages/PageEditor/Revisions/usePageEditorDrawer.js\";\n\nconst { Item } = DropdownMenu;\n\nconst statusIcon: Record<string, React.JSX.Element> = {\n draft: <Draft />,\n published: <Published />,\n unpublished: <Unpublished />\n};\n\nexport const RevisionsMenu = () => {\n const { getLink } = useRouter();\n const id = useSelectFromDocument(document => document.id);\n\n const { openRevisionList } = usePageEditorDrawer();\n\n // Shares the presenter with the revisions drawer, so mutations made there are reflected here.\n const { vm } = useRevisionList(id);\n const { revisions, isLoading } = vm;\n\n const currentRevision = revisions.find(item => item.revision.id === id)?.revision;\n\n const goToRevision = useCallback((id: string) => {\n // TODO: make this work without a full app reload\n window.location.pathname = getLink(Routes.Pages.Editor, { id });\n }, []);\n\n const onOpenRevisionList = useCallback(() => {\n openRevisionList(true);\n }, []);\n\n return (\n <DropdownMenu\n trigger={\n <Button\n disabled={isLoading}\n variant=\"ghost\"\n text={currentRevision ? currentRevision.getLabel() : \"Loading...\"}\n icon={<ArrowDown />}\n iconPosition={\"end\"}\n />\n }\n >\n {revisions.slice(0, 5).map(({ revision }) => (\n <Item\n key={revision.id}\n className={\"cursor-pointer\"}\n onClick={() => goToRevision(revision.id)}\n icon={\n <Item.Icon\n label={revision.getLabel()}\n element={statusIcon[revision.status]}\n />\n }\n text={<Text size={\"sm\"}>{revision.getLabel()}</Text>}\n />\n ))}\n <DropdownMenu.Separator />\n <DropdownMenu.Item\n key={\"revisions-all\"}\n onClick={onOpenRevisionList}\n text={\n <>\n <Text size={\"sm\"}>Show All Revisions</Text>\n </>\n }\n />\n </DropdownMenu>\n );\n};\n"],"names":["Item","DropdownMenu","statusIcon","Draft","Published","Unpublished","RevisionsMenu","getLink","useRouter","id","useSelectFromDocument","document","openRevisionList","usePageEditorDrawer","vm","useRevisionList","revisions","isLoading","currentRevision","item","goToRevision","useCallback","window","Routes","onOpenRevisionList","Button","ArrowDown","revision","Text"],"mappings":";;;;;;;;;;;AAYA,MAAM,EAAEA,MAAAA,IAAI,EAAE,GAAGC;AAEjB,MAAMC,aAAgD;IAClD,OAAO,WAAP,GAAO,oBAACC,yBAAKA;IACb,WAAW,WAAX,GAAW,oBAACC,mCAASA;IACrB,aAAa,WAAb,GAAa,oBAACC,yBAAWA;AAC7B;AAEO,MAAMC,gBAAgB;IACzB,MAAM,EAAEC,OAAO,EAAE,GAAGC;IACpB,MAAMC,KAAKC,sBAAsBC,CAAAA,WAAYA,SAAS,EAAE;IAExD,MAAM,EAAEC,gBAAgB,EAAE,GAAGC;IAG7B,MAAM,EAAEC,EAAE,EAAE,GAAGC,gBAAgBN;IAC/B,MAAM,EAAEO,SAAS,EAAEC,SAAS,EAAE,GAAGH;IAEjC,MAAMI,kBAAkBF,UAAU,IAAI,CAACG,CAAAA,OAAQA,KAAK,QAAQ,CAAC,EAAE,KAAKV,KAAK;IAEzE,MAAMW,eAAeC,YAAY,CAACZ;QAE9Ba,OAAO,QAAQ,CAAC,QAAQ,GAAGf,QAAQgB,OAAO,KAAK,CAAC,MAAM,EAAE;YAAEd;QAAG;IACjE,GAAG,EAAE;IAEL,MAAMe,qBAAqBH,YAAY;QACnCT,iBAAiB;IACrB,GAAG,EAAE;IAEL,OAAO,WAAP,GACI,oBAACX,cAAYA;QACT,uBACI,oBAACwB,QAAMA;YACH,UAAUR;YACV,SAAQ;YACR,MAAMC,kBAAkBA,gBAAgB,QAAQ,KAAK;YACrD,oBAAM,oBAACQ,gBAASA;YAChB,cAAc;;OAIrBV,UAAU,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,EAAEW,QAAQ,EAAE,iBACpC,oBAAC3B,MAAIA;YACD,KAAK2B,SAAS,EAAE;YAChB,WAAW;YACX,SAAS,IAAMP,aAAaO,SAAS,EAAE;YACvC,oBACI,oBAAC3B,KAAK,IAAI;gBACN,OAAO2B,SAAS,QAAQ;gBACxB,SAASzB,UAAU,CAACyB,SAAS,MAAM,CAAC;;YAG5C,oBAAM,oBAACC,MAAIA;gBAAC,MAAM;eAAOD,SAAS,QAAQ;2BAGlD,oBAAC1B,aAAa,SAAS,uBACvB,oBAACA,aAAa,IAAI;QACd,KAAK;QACL,SAASuB;QACT,oBACI,wDACI,oBAACI,MAAIA;YAAC,MAAM;WAAM;;AAM1C"}
@@ -7,10 +7,11 @@ import { FolderTreePresenter } from "@webiny/app-aco/presentation/folderTree/abs
7
7
  import { GetDescendantFoldersUseCase } from "@webiny/app-aco/features/folders/getDescendantFolders/abstractions.js";
8
8
  import { Confirmation } from "@webiny/app-admin/features/confirmation/abstractions.js";
9
9
  import { Page } from "../../../domain/Page/Page.js";
10
+ import { pageRevisionsCacheFactory } from "../../../domain/PageRevision/index.js";
10
11
  import { ListPagesGateway } from "../../../features/pages/listPages/abstractions.js";
11
12
  import { ListPagesUseCase } from "../../../features/pages/listPages/ListPagesUseCase.js";
12
13
  import { ListPagesRepository } from "../../../features/pages/listPages/ListPagesRepository.js";
13
- import { FullPageCache, PageListCache } from "../../../features/pages/shared/abstractions.js";
14
+ import { FullPageCache, PageListCache, PageRevisionsCache } from "../../../features/pages/shared/abstractions.js";
14
15
  import { PublishPageGateway } from "../../../features/pages/publishPage/abstractions.js";
15
16
  import { PublishPageUseCase } from "../../../features/pages/publishPage/PublishPageUseCase.js";
16
17
  import { PublishPageRepository } from "../../../features/pages/publishPage/PublishPageRepository.js";
@@ -153,6 +154,7 @@ describe("PageListPresenter", ()=>{
153
154
  });
154
155
  container.registerInstance(DeletePageUseCase, noopUseCase);
155
156
  container.registerInstance(FullPageCache, new ListCache("id"));
157
+ container.registerInstance(PageRevisionsCache, pageRevisionsCacheFactory.getCache());
156
158
  container.registerInstance(PublishPageGateway, publishGateway);
157
159
  container.register(PublishPageRepository).inSingletonScope();
158
160
  container.register(PublishPageUseCase);
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/pages/PageList/PageListPresenter.test.js","sources":["../../../../src/presentation/pages/PageList/PageListPresenter.test.ts"],"sourcesContent":["import { describe, it, expect, vi, beforeEach } from \"vitest\";\nimport { observable } from \"mobx\";\nimport { Container } from \"@webiny/di\";\nimport { ListCache } from \"@webiny/app-admin/features/listCache/index.js\";\nimport { ListPresenter } from \"@webiny/app-admin/presentation/listPresenter/ListPresenter.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 { Page } from \"~/domain/Page/Page.js\";\nimport {\n ListPagesGateway,\n type IListPagesGatewayParams,\n type IListPagesGatewayResult\n} from \"~/features/pages/listPages/abstractions.js\";\nimport { ListPagesUseCase } from \"~/features/pages/listPages/ListPagesUseCase.js\";\nimport { ListPagesRepository } from \"~/features/pages/listPages/ListPagesRepository.js\";\nimport { FullPageCache, PageListCache } from \"~/features/pages/shared/abstractions.js\";\nimport { PublishPageGateway } from \"~/features/pages/publishPage/abstractions.js\";\nimport { PublishPageUseCase as PublishPageUseCaseImpl } from \"~/features/pages/publishPage/PublishPageUseCase.js\";\nimport { PublishPageRepository } from \"~/features/pages/publishPage/PublishPageRepository.js\";\nimport { DeletePageUseCase } from \"~/features/pages/deletePage/abstractions.js\";\nimport { UnpublishPageUseCase } from \"~/features/pages/unpublishPage/abstractions.js\";\nimport { MovePageUseCase } from \"~/features/pages/movePage/abstractions.js\";\nimport { DuplicatePageUseCase } from \"~/features/pages/duplicatePage/abstractions.js\";\nimport { PageListPresenter as Abstraction } from \"./abstractions.js\";\nimport { PageListPresenter } from \"./PageListPresenter.js\";\n\nconst TOTAL_PAGES = 300;\nconst PAGE_SIZE = 50;\nconst BASE_TIME = Date.UTC(2026, 0, 1);\n\nconst minutes = (n: number) => new Date(BASE_TIME + n * 60_000).toISOString();\n\n/**\n * A higher index means a more recently *saved* page, but a less recently *created* one,\n * so sorting by `savedOn` and by `createdOn` produce opposite orders.\n */\nfunction createPages(count: number): Page[] {\n return Array.from({ length: count }, (_, i) =>\n Page.create({\n id: `page-${i}#0001`,\n entryId: `page-${i}`,\n location: { folderId: \"root\" },\n properties: { title: `Page ${i}` },\n createdOn: minutes(count - i),\n savedOn: minutes(i)\n })\n );\n}\n\n/**\n * Simulates the API: filters by folder, sorts by the requested field, and paginates\n * with an offset-based cursor.\n */\nfunction createGateway(pages: Page[]): ListPagesGateway.Interface {\n return {\n execute: vi.fn(\n async (params: IListPagesGatewayParams): Promise<IListPagesGatewayResult> => {\n const [sort = \"savedOn_DESC\"] = params.sort ?? [];\n const [field, direction] = sort.split(\"_\") as [keyof Page, \"ASC\" | \"DESC\"];\n const multiplier = direction === \"ASC\" ? 1 : -1;\n\n const folderId = (params.where?.location as { folderId?: string })?.folderId;\n const sorted = pages\n .filter(page => !folderId || page.location.folderId === folderId)\n .sort((a, b) => multiplier * String(a[field]).localeCompare(String(b[field])));\n\n const offset = params.after ? Number(params.after) : 0;\n const limit = params.limit ?? PAGE_SIZE;\n const data = sorted.slice(offset, offset + limit);\n const next = offset + data.length;\n const hasMoreItems = next < sorted.length;\n\n return {\n data,\n meta: {\n cursor: hasMoreItems ? String(next) : null,\n hasMoreItems,\n totalCount: sorted.length\n }\n };\n }\n )\n };\n}\n\nfunction createFolderTreePresenter(): FolderTreePresenter.Interface {\n const vm = observable({\n folders: [],\n tree: [],\n currentFolderId: null as string | null,\n currentFolder: null,\n loading: false,\n operation: { active: false, mode: null },\n isRootFolder: true,\n currentFolderTitle: \"All pages\",\n childFolders: [],\n loadingNodeIds: []\n });\n\n return {\n get vm() {\n return vm as unknown as FolderTreePresenter.Interface[\"vm\"];\n },\n selectFolder: vi.fn(),\n createFolder: vi.fn(),\n editFolder: vi.fn(),\n deleteFolder: vi.fn().mockResolvedValue(undefined),\n moveFolder: vi.fn().mockResolvedValue(undefined),\n loadChildFolders: vi.fn().mockResolvedValue(undefined),\n canManageStructure: vi.fn().mockReturnValue(true),\n getAncestorIds: vi.fn().mockReturnValue([]),\n submitOperation: vi.fn().mockResolvedValue(true),\n cancelOperation: vi.fn(),\n onFolderChange: vi.fn().mockReturnValue(() => {})\n };\n}\n\nconst noopUseCase = { execute: vi.fn() };\n\n/**\n * Expected entry IDs for a contiguous range of page indexes, in the given order.\n */\nfunction range(from: number, to: number): string[] {\n const step = from <= to ? 1 : -1;\n const ids: string[] = [];\n for (let i = from; step > 0 ? i <= to : i >= to; i += step) {\n ids.push(`page-${i}`);\n }\n return ids;\n}\n\ndescribe(\"PageListPresenter\", () => {\n let presenter: Abstraction.Interface;\n let cache: ListCache<Page>;\n\n /**\n * Simulates the publish API: publishing is not a content modification, so the page\n * comes back with its `savedOn` unchanged.\n */\n const publishGateway: PublishPageGateway.Interface = {\n execute: vi.fn(async (id: string) => {\n const page = cache.getItem(p => p.id === id)!;\n return { ...page, status: \"published\" } as any;\n })\n };\n\n const rowIds = () => presenter.list.vm.rows.map(row => row.entryId);\n\n const waitForQuery = async (field: string, direction: \"ASC\" | \"DESC\") => {\n await vi.waitFor(() => {\n const sort = presenter.list.vm.appliedQuery?.sort;\n expect(sort).toEqual({ field, direction });\n expect(presenter.list.vm.pagination.loading).toBe(false);\n });\n };\n\n const initAndWait = async () => {\n presenter.init();\n await waitForQuery(\"savedOn\", \"DESC\");\n };\n\n const loadAll = async () => {\n while (presenter.list.vm.pagination.hasMore) {\n await presenter.list.actions.loadMore();\n }\n };\n\n beforeEach(() => {\n const container = new Container();\n\n cache = new ListCache<Page>(\"entryId\");\n container.registerInstance(PageListCache, cache);\n container.registerInstance(ListPagesGateway, createGateway(createPages(TOTAL_PAGES)));\n container.register(ListPagesRepository).inSingletonScope();\n container.register(ListPagesUseCase);\n\n container.register(ListPresenter);\n container.registerInstance(FolderTreePresenter, createFolderTreePresenter());\n container.registerInstance(Confirmation, { confirm: vi.fn() } as Confirmation.Interface);\n container.registerInstance(GetDescendantFoldersUseCase, { execute: () => [] });\n container.registerInstance(DeletePageUseCase, noopUseCase as any);\n container.registerInstance(FullPageCache, new ListCache<Page>(\"id\"));\n container.registerInstance(PublishPageGateway, publishGateway);\n container.register(PublishPageRepository).inSingletonScope();\n container.register(PublishPageUseCaseImpl);\n container.registerInstance(UnpublishPageUseCase, noopUseCase as any);\n container.registerInstance(MovePageUseCase, noopUseCase as any);\n container.registerInstance(DuplicatePageUseCase, noopUseCase as any);\n\n container.register(PageListPresenter);\n\n presenter = container.resolve(Abstraction);\n });\n\n describe(\"pagination\", () => {\n it(\"should show the most recently saved pages first\", async () => {\n await initAndWait();\n\n expect(rowIds()).toEqual(range(299, 250));\n });\n\n it(\"should append the next batch of pages to the bottom of the list\", async () => {\n await initAndWait();\n\n await presenter.list.actions.loadMore();\n\n expect(rowIds()).toEqual(range(299, 200));\n });\n\n it(\"should keep all pages in order after loading everything\", async () => {\n await initAndWait();\n\n await loadAll();\n\n expect(rowIds()).toEqual(range(299, 0));\n });\n });\n\n describe(\"changing the sort\", () => {\n it(\"should show only the first batch, in the new direction\", async () => {\n await initAndWait();\n\n presenter.list.actions.sort.set(\"savedOn\", \"ASC\");\n await waitForQuery(\"savedOn\", \"ASC\");\n\n expect(rowIds()).toEqual(range(0, 49));\n });\n\n it(\"should show only the first batch, sorted by the new field\", async () => {\n await initAndWait();\n\n presenter.list.actions.sort.set(\"createdOn\", \"DESC\");\n await waitForQuery(\"createdOn\", \"DESC\");\n\n // `createdOn` runs opposite to `savedOn`, so the newest created page is page-0.\n expect(rowIds()).toEqual(range(0, 49));\n });\n\n it(\"should paginate in the new order\", async () => {\n await initAndWait();\n\n presenter.list.actions.sort.set(\"savedOn\", \"ASC\");\n await waitForQuery(\"savedOn\", \"ASC\");\n await presenter.list.actions.loadMore();\n\n expect(rowIds()).toEqual(range(0, 99));\n });\n\n it(\"should restore the original order when switching back\", async () => {\n await initAndWait();\n await presenter.list.actions.loadMore();\n\n presenter.list.actions.sort.set(\"savedOn\", \"ASC\");\n await waitForQuery(\"savedOn\", \"ASC\");\n\n presenter.list.actions.sort.set(\"savedOn\", \"DESC\");\n await waitForQuery(\"savedOn\", \"DESC\");\n\n expect(rowIds()).toEqual(range(299, 250));\n });\n });\n\n describe(\"local cache changes\", () => {\n const newPage = () =>\n Page.create({\n id: \"page-new#0001\",\n entryId: \"page-new\",\n location: { folderId: \"root\" },\n properties: { title: \"New page\" },\n createdOn: minutes(TOTAL_PAGES + 1),\n savedOn: minutes(TOTAL_PAGES + 1)\n });\n\n it(\"should show a created page at the top when it sorts first\", async () => {\n await initAndWait();\n\n cache.addItems([newPage()]);\n\n expect(rowIds()).toEqual([\"page-new\", ...range(299, 250)]);\n });\n\n it(\"should not show a created page that sorts past the loaded pages\", async () => {\n await initAndWait();\n presenter.list.actions.sort.set(\"savedOn\", \"ASC\");\n await waitForQuery(\"savedOn\", \"ASC\");\n\n cache.addItems([newPage()]);\n\n // The new page is the most recently saved, so in ASC order it belongs at the very\n // end, after 250 pages that are not loaded yet.\n expect(rowIds()).toEqual(range(0, 49));\n });\n\n it(\"should show a created page in its sort position once everything is loaded\", async () => {\n await initAndWait();\n presenter.list.actions.sort.set(\"savedOn\", \"ASC\");\n await waitForQuery(\"savedOn\", \"ASC\");\n await loadAll();\n\n cache.addItems([newPage()]);\n\n expect(rowIds()).toEqual([...range(0, 299), \"page-new\"]);\n });\n\n it(\"should move an updated page to its new sort position\", async () => {\n await initAndWait();\n\n const page = cache.getItem(p => p.entryId === \"page-260\")!;\n cache.addItems([Page.create({ ...page, savedOn: minutes(TOTAL_PAGES + 1) })]);\n\n expect(rowIds()).toEqual([\"page-260\", ...range(299, 261), ...range(259, 250)]);\n });\n });\n\n describe(\"publishing\", () => {\n it(\"should keep a published page in its position\", async () => {\n await initAndWait();\n const before = rowIds();\n\n await presenter.publishPage(\"page-260#0001\");\n\n expect(rowIds()).toEqual(before);\n const published = presenter.list.vm.rows.find(row => row.entryId === \"page-260\");\n expect(published?.status).toBe(\"published\");\n });\n\n it(\"should keep a published page in its position after loading more pages\", async () => {\n await initAndWait();\n await presenter.list.actions.loadMore();\n const before = rowIds();\n\n await presenter.publishPage(\"page-210#0001\");\n\n expect(rowIds()).toEqual(before);\n });\n });\n});\n"],"names":["TOTAL_PAGES","PAGE_SIZE","BASE_TIME","Date","minutes","n","createPages","count","Array","_","i","Page","createGateway","pages","vi","params","sort","field","direction","multiplier","folderId","sorted","page","a","b","String","offset","Number","limit","data","next","hasMoreItems","createFolderTreePresenter","vm","observable","undefined","noopUseCase","range","from","to","step","ids","describe","presenter","cache","publishGateway","id","p","rowIds","row","waitForQuery","expect","initAndWait","loadAll","beforeEach","container","Container","ListCache","PageListCache","ListPagesGateway","ListPagesRepository","ListPagesUseCase","ListPresenter","FolderTreePresenter","Confirmation","GetDescendantFoldersUseCase","DeletePageUseCase","FullPageCache","PublishPageGateway","PublishPageRepository","PublishPageUseCaseImpl","UnpublishPageUseCase","MovePageUseCase","DuplicatePageUseCase","PageListPresenter","Abstraction","it","newPage","before","published"],"mappings":"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"}
1
+ {"version":3,"file":"presentation/pages/PageList/PageListPresenter.test.js","sources":["../../../../src/presentation/pages/PageList/PageListPresenter.test.ts"],"sourcesContent":["import { describe, it, expect, vi, beforeEach } from \"vitest\";\nimport { observable } from \"mobx\";\nimport { Container } from \"@webiny/di\";\nimport { ListCache } from \"@webiny/app-admin/features/listCache/index.js\";\nimport { ListPresenter } from \"@webiny/app-admin/presentation/listPresenter/ListPresenter.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 { Page } from \"~/domain/Page/Page.js\";\nimport { pageRevisionsCacheFactory } from \"~/domain/PageRevision/index.js\";\nimport {\n ListPagesGateway,\n type IListPagesGatewayParams,\n type IListPagesGatewayResult\n} from \"~/features/pages/listPages/abstractions.js\";\nimport { ListPagesUseCase } from \"~/features/pages/listPages/ListPagesUseCase.js\";\nimport { ListPagesRepository } from \"~/features/pages/listPages/ListPagesRepository.js\";\nimport {\n FullPageCache,\n PageListCache,\n PageRevisionsCache\n} from \"~/features/pages/shared/abstractions.js\";\nimport { PublishPageGateway } from \"~/features/pages/publishPage/abstractions.js\";\nimport { PublishPageUseCase as PublishPageUseCaseImpl } from \"~/features/pages/publishPage/PublishPageUseCase.js\";\nimport { PublishPageRepository } from \"~/features/pages/publishPage/PublishPageRepository.js\";\nimport { DeletePageUseCase } from \"~/features/pages/deletePage/abstractions.js\";\nimport { UnpublishPageUseCase } from \"~/features/pages/unpublishPage/abstractions.js\";\nimport { MovePageUseCase } from \"~/features/pages/movePage/abstractions.js\";\nimport { DuplicatePageUseCase } from \"~/features/pages/duplicatePage/abstractions.js\";\nimport { PageListPresenter as Abstraction } from \"./abstractions.js\";\nimport { PageListPresenter } from \"./PageListPresenter.js\";\n\nconst TOTAL_PAGES = 300;\nconst PAGE_SIZE = 50;\nconst BASE_TIME = Date.UTC(2026, 0, 1);\n\nconst minutes = (n: number) => new Date(BASE_TIME + n * 60_000).toISOString();\n\n/**\n * A higher index means a more recently *saved* page, but a less recently *created* one,\n * so sorting by `savedOn` and by `createdOn` produce opposite orders.\n */\nfunction createPages(count: number): Page[] {\n return Array.from({ length: count }, (_, i) =>\n Page.create({\n id: `page-${i}#0001`,\n entryId: `page-${i}`,\n location: { folderId: \"root\" },\n properties: { title: `Page ${i}` },\n createdOn: minutes(count - i),\n savedOn: minutes(i)\n })\n );\n}\n\n/**\n * Simulates the API: filters by folder, sorts by the requested field, and paginates\n * with an offset-based cursor.\n */\nfunction createGateway(pages: Page[]): ListPagesGateway.Interface {\n return {\n execute: vi.fn(\n async (params: IListPagesGatewayParams): Promise<IListPagesGatewayResult> => {\n const [sort = \"savedOn_DESC\"] = params.sort ?? [];\n const [field, direction] = sort.split(\"_\") as [keyof Page, \"ASC\" | \"DESC\"];\n const multiplier = direction === \"ASC\" ? 1 : -1;\n\n const folderId = (params.where?.location as { folderId?: string })?.folderId;\n const sorted = pages\n .filter(page => !folderId || page.location.folderId === folderId)\n .sort((a, b) => multiplier * String(a[field]).localeCompare(String(b[field])));\n\n const offset = params.after ? Number(params.after) : 0;\n const limit = params.limit ?? PAGE_SIZE;\n const data = sorted.slice(offset, offset + limit);\n const next = offset + data.length;\n const hasMoreItems = next < sorted.length;\n\n return {\n data,\n meta: {\n cursor: hasMoreItems ? String(next) : null,\n hasMoreItems,\n totalCount: sorted.length\n }\n };\n }\n )\n };\n}\n\nfunction createFolderTreePresenter(): FolderTreePresenter.Interface {\n const vm = observable({\n folders: [],\n tree: [],\n currentFolderId: null as string | null,\n currentFolder: null,\n loading: false,\n operation: { active: false, mode: null },\n isRootFolder: true,\n currentFolderTitle: \"All pages\",\n childFolders: [],\n loadingNodeIds: []\n });\n\n return {\n get vm() {\n return vm as unknown as FolderTreePresenter.Interface[\"vm\"];\n },\n selectFolder: vi.fn(),\n createFolder: vi.fn(),\n editFolder: vi.fn(),\n deleteFolder: vi.fn().mockResolvedValue(undefined),\n moveFolder: vi.fn().mockResolvedValue(undefined),\n loadChildFolders: vi.fn().mockResolvedValue(undefined),\n canManageStructure: vi.fn().mockReturnValue(true),\n getAncestorIds: vi.fn().mockReturnValue([]),\n submitOperation: vi.fn().mockResolvedValue(true),\n cancelOperation: vi.fn(),\n onFolderChange: vi.fn().mockReturnValue(() => {})\n };\n}\n\nconst noopUseCase = { execute: vi.fn() };\n\n/**\n * Expected entry IDs for a contiguous range of page indexes, in the given order.\n */\nfunction range(from: number, to: number): string[] {\n const step = from <= to ? 1 : -1;\n const ids: string[] = [];\n for (let i = from; step > 0 ? i <= to : i >= to; i += step) {\n ids.push(`page-${i}`);\n }\n return ids;\n}\n\ndescribe(\"PageListPresenter\", () => {\n let presenter: Abstraction.Interface;\n let cache: ListCache<Page>;\n\n /**\n * Simulates the publish API: publishing is not a content modification, so the page\n * comes back with its `savedOn` unchanged.\n */\n const publishGateway: PublishPageGateway.Interface = {\n execute: vi.fn(async (id: string) => {\n const page = cache.getItem(p => p.id === id)!;\n return { ...page, status: \"published\" } as any;\n })\n };\n\n const rowIds = () => presenter.list.vm.rows.map(row => row.entryId);\n\n const waitForQuery = async (field: string, direction: \"ASC\" | \"DESC\") => {\n await vi.waitFor(() => {\n const sort = presenter.list.vm.appliedQuery?.sort;\n expect(sort).toEqual({ field, direction });\n expect(presenter.list.vm.pagination.loading).toBe(false);\n });\n };\n\n const initAndWait = async () => {\n presenter.init();\n await waitForQuery(\"savedOn\", \"DESC\");\n };\n\n const loadAll = async () => {\n while (presenter.list.vm.pagination.hasMore) {\n await presenter.list.actions.loadMore();\n }\n };\n\n beforeEach(() => {\n const container = new Container();\n\n cache = new ListCache<Page>(\"entryId\");\n container.registerInstance(PageListCache, cache);\n container.registerInstance(ListPagesGateway, createGateway(createPages(TOTAL_PAGES)));\n container.register(ListPagesRepository).inSingletonScope();\n container.register(ListPagesUseCase);\n\n container.register(ListPresenter);\n container.registerInstance(FolderTreePresenter, createFolderTreePresenter());\n container.registerInstance(Confirmation, { confirm: vi.fn() } as Confirmation.Interface);\n container.registerInstance(GetDescendantFoldersUseCase, { execute: () => [] });\n container.registerInstance(DeletePageUseCase, noopUseCase as any);\n container.registerInstance(FullPageCache, new ListCache<Page>(\"id\"));\n container.registerInstance(PageRevisionsCache, pageRevisionsCacheFactory.getCache());\n container.registerInstance(PublishPageGateway, publishGateway);\n container.register(PublishPageRepository).inSingletonScope();\n container.register(PublishPageUseCaseImpl);\n container.registerInstance(UnpublishPageUseCase, noopUseCase as any);\n container.registerInstance(MovePageUseCase, noopUseCase as any);\n container.registerInstance(DuplicatePageUseCase, noopUseCase as any);\n\n container.register(PageListPresenter);\n\n presenter = container.resolve(Abstraction);\n });\n\n describe(\"pagination\", () => {\n it(\"should show the most recently saved pages first\", async () => {\n await initAndWait();\n\n expect(rowIds()).toEqual(range(299, 250));\n });\n\n it(\"should append the next batch of pages to the bottom of the list\", async () => {\n await initAndWait();\n\n await presenter.list.actions.loadMore();\n\n expect(rowIds()).toEqual(range(299, 200));\n });\n\n it(\"should keep all pages in order after loading everything\", async () => {\n await initAndWait();\n\n await loadAll();\n\n expect(rowIds()).toEqual(range(299, 0));\n });\n });\n\n describe(\"changing the sort\", () => {\n it(\"should show only the first batch, in the new direction\", async () => {\n await initAndWait();\n\n presenter.list.actions.sort.set(\"savedOn\", \"ASC\");\n await waitForQuery(\"savedOn\", \"ASC\");\n\n expect(rowIds()).toEqual(range(0, 49));\n });\n\n it(\"should show only the first batch, sorted by the new field\", async () => {\n await initAndWait();\n\n presenter.list.actions.sort.set(\"createdOn\", \"DESC\");\n await waitForQuery(\"createdOn\", \"DESC\");\n\n // `createdOn` runs opposite to `savedOn`, so the newest created page is page-0.\n expect(rowIds()).toEqual(range(0, 49));\n });\n\n it(\"should paginate in the new order\", async () => {\n await initAndWait();\n\n presenter.list.actions.sort.set(\"savedOn\", \"ASC\");\n await waitForQuery(\"savedOn\", \"ASC\");\n await presenter.list.actions.loadMore();\n\n expect(rowIds()).toEqual(range(0, 99));\n });\n\n it(\"should restore the original order when switching back\", async () => {\n await initAndWait();\n await presenter.list.actions.loadMore();\n\n presenter.list.actions.sort.set(\"savedOn\", \"ASC\");\n await waitForQuery(\"savedOn\", \"ASC\");\n\n presenter.list.actions.sort.set(\"savedOn\", \"DESC\");\n await waitForQuery(\"savedOn\", \"DESC\");\n\n expect(rowIds()).toEqual(range(299, 250));\n });\n });\n\n describe(\"local cache changes\", () => {\n const newPage = () =>\n Page.create({\n id: \"page-new#0001\",\n entryId: \"page-new\",\n location: { folderId: \"root\" },\n properties: { title: \"New page\" },\n createdOn: minutes(TOTAL_PAGES + 1),\n savedOn: minutes(TOTAL_PAGES + 1)\n });\n\n it(\"should show a created page at the top when it sorts first\", async () => {\n await initAndWait();\n\n cache.addItems([newPage()]);\n\n expect(rowIds()).toEqual([\"page-new\", ...range(299, 250)]);\n });\n\n it(\"should not show a created page that sorts past the loaded pages\", async () => {\n await initAndWait();\n presenter.list.actions.sort.set(\"savedOn\", \"ASC\");\n await waitForQuery(\"savedOn\", \"ASC\");\n\n cache.addItems([newPage()]);\n\n // The new page is the most recently saved, so in ASC order it belongs at the very\n // end, after 250 pages that are not loaded yet.\n expect(rowIds()).toEqual(range(0, 49));\n });\n\n it(\"should show a created page in its sort position once everything is loaded\", async () => {\n await initAndWait();\n presenter.list.actions.sort.set(\"savedOn\", \"ASC\");\n await waitForQuery(\"savedOn\", \"ASC\");\n await loadAll();\n\n cache.addItems([newPage()]);\n\n expect(rowIds()).toEqual([...range(0, 299), \"page-new\"]);\n });\n\n it(\"should move an updated page to its new sort position\", async () => {\n await initAndWait();\n\n const page = cache.getItem(p => p.entryId === \"page-260\")!;\n cache.addItems([Page.create({ ...page, savedOn: minutes(TOTAL_PAGES + 1) })]);\n\n expect(rowIds()).toEqual([\"page-260\", ...range(299, 261), ...range(259, 250)]);\n });\n });\n\n describe(\"publishing\", () => {\n it(\"should keep a published page in its position\", async () => {\n await initAndWait();\n const before = rowIds();\n\n await presenter.publishPage(\"page-260#0001\");\n\n expect(rowIds()).toEqual(before);\n const published = presenter.list.vm.rows.find(row => row.entryId === \"page-260\");\n expect(published?.status).toBe(\"published\");\n });\n\n it(\"should keep a published page in its position after loading more pages\", async () => {\n await initAndWait();\n await presenter.list.actions.loadMore();\n const before = rowIds();\n\n await presenter.publishPage(\"page-210#0001\");\n\n expect(rowIds()).toEqual(before);\n });\n });\n});\n"],"names":["TOTAL_PAGES","PAGE_SIZE","BASE_TIME","Date","minutes","n","createPages","count","Array","_","i","Page","createGateway","pages","vi","params","sort","field","direction","multiplier","folderId","sorted","page","a","b","String","offset","Number","limit","data","next","hasMoreItems","createFolderTreePresenter","vm","observable","undefined","noopUseCase","range","from","to","step","ids","describe","presenter","cache","publishGateway","id","p","rowIds","row","waitForQuery","expect","initAndWait","loadAll","beforeEach","container","Container","ListCache","PageListCache","ListPagesGateway","ListPagesRepository","ListPagesUseCase","ListPresenter","FolderTreePresenter","Confirmation","GetDescendantFoldersUseCase","DeletePageUseCase","FullPageCache","PageRevisionsCache","pageRevisionsCacheFactory","PublishPageGateway","PublishPageRepository","PublishPageUseCaseImpl","UnpublishPageUseCase","MovePageUseCase","DuplicatePageUseCase","PageListPresenter","Abstraction","it","newPage","before","published"],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { GetPageRevisionsUseCase } from "../../../features/pages/getPageRevisions/abstractions.js";
2
+ import { PageRevisionsCache, WbPageLoadingRepository, WbPageRevisionsLoadingRepository } from "../../../features/pages/shared/abstractions.js";
3
+ import { WbPermissions } from "../../../features/permissions/abstractions.js";
4
+ import { RevisionListPresenter as PresenterAbstraction } from "./abstractions.js";
5
+ declare class RevisionListPresenterImpl implements PresenterAbstraction.Interface {
6
+ private revisionsCache;
7
+ private loadingRepository;
8
+ private pageLoadingRepository;
9
+ private permissions;
10
+ private getPageRevisions;
11
+ private entryId;
12
+ constructor(revisionsCache: PageRevisionsCache.Interface, loadingRepository: WbPageRevisionsLoadingRepository.Interface, pageLoadingRepository: WbPageLoadingRepository.Interface, permissions: WbPermissions.Interface, getPageRevisions: GetPageRevisionsUseCase.Interface);
13
+ init(params: PresenterAbstraction.Init): void;
14
+ get vm(): PresenterAbstraction.ViewModel;
15
+ private getRevisions;
16
+ private getItemVm;
17
+ private getIsLoading;
18
+ /**
19
+ * Watching named actions rather than `hasLoading()`: the `WbPage` namespace is shared with
20
+ * the pages table, so that would also react to listing and fetching.
21
+ */
22
+ private getIsMutating;
23
+ }
24
+ export declare const RevisionListPresenter: typeof RevisionListPresenterImpl & {
25
+ __abstraction: import("@webiny/di").Abstraction<import("./abstractions.js").IRevisionListPresenter>;
26
+ };
27
+ export {};