PageHistoryContainer.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import { Container } from 'unstated';
  2. import loggerFactory from '~/utils/logger';
  3. import { toastError } from '../util/apiNotification';
  4. import { apiv3Get } from '../util/apiv3-client';
  5. const logger = loggerFactory('growi:PageHistoryContainer');
  6. /**
  7. * Service container for personal settings page (PageHistory.jsx)
  8. * @extends {Container} unstated Container
  9. */
  10. export default class PageHistoryContainer extends Container {
  11. constructor(appContainer, pageContainer) {
  12. super();
  13. this.appContainer = appContainer;
  14. this.pageContainer = pageContainer;
  15. this.dummyRevisions = 0;
  16. this.state = {
  17. errorMessage: null,
  18. // set dummy rivisions for using suspense
  19. revisions: this.dummyRevisions,
  20. latestRevision: this.dummyRevisions,
  21. oldestRevision: this.dummyRevisions,
  22. diffOpened: {},
  23. totalPages: 0,
  24. activePage: 1,
  25. pagingLimit: 10,
  26. };
  27. this.retrieveRevisions = this.retrieveRevisions.bind(this);
  28. this.getPreviousRevision = this.getPreviousRevision.bind(this);
  29. this.fetchPageRevisionBody = this.fetchPageRevisionBody.bind(this);
  30. }
  31. /**
  32. * Workaround for the mangling in production build to break constructor.name
  33. */
  34. static getClassName() {
  35. return 'PageHistoryContainer';
  36. }
  37. /**
  38. * syncRevisions of selectedPage
  39. * @param {number} selectedPage
  40. */
  41. async retrieveRevisions(selectedPage) {
  42. const { pageId, shareLinkId } = this.pageContainer.state;
  43. const { pagingLimit } = this.state;
  44. const page = selectedPage;
  45. const pagingLimitForApiParam = pagingLimit + 1;
  46. if (!pageId) {
  47. return;
  48. }
  49. // Get one more for the bottom display
  50. const res = await apiv3Get('/revisions/list', {
  51. pageId, shareLinkId, page, limit: pagingLimitForApiParam,
  52. });
  53. const rev = res.data.docs;
  54. // set Pagination state
  55. this.setState({
  56. activePage: selectedPage,
  57. totalPages: res.data.totalDocs,
  58. pagingLimit,
  59. });
  60. const diffOpened = {};
  61. let lastId = rev.length - 1;
  62. // If the number of rev count is the same, the last rev is for diff display, so exclude it.
  63. if (rev.length > pagingLimit) {
  64. lastId = rev.length - 2;
  65. }
  66. res.data.docs.forEach((revision, i) => {
  67. const user = revision.author;
  68. if (user) {
  69. rev[i].author = user;
  70. }
  71. if (i === 0 || i === lastId) {
  72. diffOpened[revision._id] = true;
  73. }
  74. else {
  75. diffOpened[revision._id] = false;
  76. }
  77. });
  78. this.setState({ revisions: rev });
  79. this.setState({ diffOpened });
  80. if (selectedPage === 1) {
  81. this.setState({ latestRevision: rev[0] });
  82. }
  83. if (selectedPage === res.data.totalPages) {
  84. this.setState({ oldestRevision: rev[lastId] });
  85. }
  86. // load 0, and last default
  87. if (rev[0]) {
  88. this.fetchPageRevisionBody(rev[0]);
  89. }
  90. if (rev[1]) {
  91. this.fetchPageRevisionBody(rev[1]);
  92. }
  93. if (lastId !== 0 && lastId !== 1 && rev[lastId]) {
  94. this.fetchPageRevisionBody(rev[lastId]);
  95. }
  96. return;
  97. }
  98. getPreviousRevision(currentRevision) {
  99. let cursor = null;
  100. for (const revision of this.state.revisions) {
  101. // comparing ObjectId
  102. // eslint-disable-next-line eqeqeq
  103. if (cursor && cursor._id == currentRevision._id) {
  104. cursor = revision;
  105. break;
  106. }
  107. cursor = revision;
  108. }
  109. return cursor;
  110. }
  111. /**
  112. * fetch page revision body by revision in argument
  113. * @param {object} revision
  114. */
  115. async fetchPageRevisionBody(revision) {
  116. const { pageId, shareLinkId } = this.pageContainer.state;
  117. if (revision.body) {
  118. return;
  119. }
  120. try {
  121. const res = await apiv3Get(`/revisions/${revision._id}`, { pageId, shareLinkId });
  122. this.setState({
  123. revisions: this.state.revisions.map((rev) => {
  124. // comparing ObjectId
  125. // eslint-disable-next-line eqeqeq
  126. if (rev._id == res.data.revision._id) {
  127. return res.data.revision;
  128. }
  129. return rev;
  130. }),
  131. });
  132. }
  133. catch (err) {
  134. toastError(err);
  135. this.setState({ errorMessage: err.message });
  136. logger.error(err);
  137. }
  138. }
  139. }