PageHistoryContainer.js 4.1 KB

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