PageHistory.jsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import React, { Suspense, useState } from 'react';
  2. import PropTypes from 'prop-types';
  3. import loggerFactory from '@alias/logger';
  4. import { withUnstatedContainers } from './UnstatedUtils';
  5. import { toastError } from '../util/apiNotification';
  6. import PageRevisionList from './PageHistory/PageRevisionList';
  7. import AppContainer from '../services/AppContainer';
  8. import PageContainer from '../services/PageContainer';
  9. const logger = loggerFactory('growi:PageHistory');
  10. // set dummy value tile for using suspense
  11. let isLoaded = false;
  12. function AppSettingsPage(props) {
  13. return (
  14. <Suspense
  15. fallback={(
  16. <div className="my-5 text-center">
  17. <i className="fa fa-lg fa-spinner fa-pulse mx-auto text-muted"></i>
  18. </div>
  19. )}
  20. >
  21. <RenderPageHistoryWrapper props={props} />
  22. </Suspense>
  23. );
  24. }
  25. function PageHistory(props) {
  26. const [errorMessage, setErrorMessage] = useState(null);
  27. const [revisions, setRevisions] = useState([]);
  28. const [diffOpened, setDiffOpened] = useState(null);
  29. function fetchPageRevisionBody(revision) {
  30. const { appContainer, pageContainer } = props;
  31. const { pageId, shareLinkId } = pageContainer.state;
  32. if (revision.body) {
  33. return;
  34. }
  35. appContainer.apiGet('/revisions.get', { page_id: pageId, revision_id: revision._id, share_link_id: shareLinkId })
  36. .then((res) => {
  37. if (res.ok) {
  38. this.setState({
  39. revisions: this.state.revisions.map((rev) => {
  40. // comparing ObjectId
  41. // eslint-disable-next-line eqeqeq
  42. if (rev._id == res.revision._id) {
  43. return res.revision;
  44. }
  45. return rev;
  46. }),
  47. });
  48. }
  49. })
  50. .catch((err) => {
  51. });
  52. }
  53. async function retrieveRevisions() {
  54. const { appContainer, pageContainer } = props;
  55. const { shareLinkId, pageId } = pageContainer.state;
  56. if (!pageId) {
  57. return;
  58. }
  59. const res = await appContainer.apiv3Get('/revisions/list', { pageId, share_link_id: shareLinkId });
  60. const rev = res.data.revisions;
  61. console.log(rev);
  62. const diffOpened = {};
  63. const lastId = rev.length - 1;
  64. res.data.revisions.forEach((revision, i) => {
  65. const user = revision.author;
  66. if (user) {
  67. rev[i].author = user;
  68. }
  69. if (i === 0 || i === lastId) {
  70. diffOpened[revision._id] = true;
  71. }
  72. else {
  73. diffOpened[revision._id] = false;
  74. }
  75. });
  76. setRevisions(rev);
  77. setDiffOpened(diffOpened);
  78. // load 0, and last default
  79. if (rev[0]) {
  80. fetchPageRevisionBody(rev[0]);
  81. }
  82. if (rev[1]) {
  83. fetchPageRevisionBody(rev[1]);
  84. }
  85. if (lastId !== 0 && lastId !== 1 && rev[lastId]) {
  86. fetchPageRevisionBody(rev[lastId]);
  87. }
  88. return;
  89. }
  90. function getPreviousRevision(currentRevision) {
  91. let cursor = null;
  92. for (const revision of revisions) {
  93. // comparing ObjectId
  94. // eslint-disable-next-line eqeqeq
  95. if (cursor && cursor._id == currentRevision._id) {
  96. cursor = revision;
  97. break;
  98. }
  99. cursor = revision;
  100. }
  101. return cursor;
  102. }
  103. function onDiffOpenClicked(revision) {
  104. const revisionId = revision._id;
  105. diffOpened[revisionId] = !(diffOpened[revisionId]);
  106. setDiffOpened(diffOpened);
  107. fetchPageRevisionBody(revision);
  108. fetchPageRevisionBody(getPreviousRevision(revision));
  109. }
  110. if (!isLoaded) {
  111. throw new Promise(async() => {
  112. try {
  113. await retrieveRevisions();
  114. isLoaded = true;
  115. return;
  116. }
  117. catch (err) {
  118. toastError(err);
  119. logger.error(err);
  120. setErrorMessage(err);
  121. }
  122. });
  123. }
  124. return (
  125. <div className="mt-4">
  126. {errorMessage && (
  127. <div className="my-5">
  128. <div className="text-danger">{errorMessage}</div>
  129. </div>
  130. ) }
  131. <PageRevisionList
  132. revisions={revisions}
  133. diffOpened={diffOpened}
  134. getPreviousRevision={getPreviousRevision}
  135. onDiffOpenClicked={onDiffOpenClicked}
  136. />
  137. </div>
  138. );
  139. }
  140. const RenderPageHistoryWrapper = withUnstatedContainers(PageHistory, [AppContainer, PageContainer]);
  141. PageHistory.propTypes = {
  142. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  143. pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
  144. };
  145. export default AppSettingsPage;