RevisionComparerContainer.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import { Container } from 'unstated';
  2. import loggerFactory from '@alias/logger';
  3. import { toastError } from '../util/apiNotification';
  4. const logger = loggerFactory('growi:PageHistoryContainer');
  5. /**
  6. * Service container for personal settings page (RevisionCompare.jsx)
  7. * @extends {Container} unstated Container
  8. */
  9. export default class RevisionComparerContainer extends Container {
  10. constructor(appContainer, pageContainer) {
  11. super();
  12. this.appContainer = appContainer;
  13. this.pageContainer = pageContainer;
  14. this.state = {
  15. errMessage: null,
  16. sourceRevision: null,
  17. targetRevision: null,
  18. latestRevision: null,
  19. compareWithLatest: true,
  20. };
  21. this.initRevisions = this.initRevisions.bind(this);
  22. this.toggleCompareWithLatest = this.toggleCompareWithLatest.bind(this);
  23. }
  24. /**
  25. * Workaround for the mangling in production build to break constructor.name
  26. */
  27. static getClassName() {
  28. return 'RevisionComparerContainer';
  29. }
  30. /**
  31. * Initialize the revisions
  32. */
  33. async initRevisions() {
  34. const latestRevision = await this.fetchLatestRevision();
  35. const [sourceRevisionId, targetRevisionId] = this.getRevisionIDsToCompareAsParam();
  36. const sourceRevision = sourceRevisionId ? await this.fetchRevision(sourceRevisionId) : latestRevision;
  37. const targetRevision = targetRevisionId ? await this.fetchRevision(targetRevisionId) : latestRevision;
  38. const compareWithLatest = targetRevisionId ? false : this.state.compareWithLatest;
  39. this.setState({
  40. sourceRevision, targetRevision, latestRevision, compareWithLatest,
  41. });
  42. }
  43. /**
  44. * Get the IDs of the comparison source and target from "window.location" as an array
  45. */
  46. getRevisionIDsToCompareAsParam() {
  47. const searchParams = {};
  48. for (const param of window.location.search?.substr(1)?.split('&')) {
  49. const [k, v] = param.split('=');
  50. searchParams[k] = v;
  51. }
  52. if (!searchParams.compare) {
  53. return [];
  54. }
  55. return searchParams.compare.split('...') || [];
  56. }
  57. /**
  58. * Fetch the latest revision
  59. */
  60. async fetchLatestRevision() {
  61. const { pageId, shareLinkId } = this.pageContainer.state;
  62. try {
  63. const res = await this.appContainer.apiv3Get('/revisions/list', {
  64. pageId, shareLinkId, page: 1, limit: 1,
  65. });
  66. return res.data.docs[0];
  67. }
  68. catch (err) {
  69. toastError(err);
  70. this.setState({ errorMessage: err.message });
  71. logger.error(err);
  72. }
  73. return null;
  74. }
  75. /**
  76. * Fetch the revision of the specified ID
  77. * @param {string} revision ID
  78. */
  79. async fetchRevision(revisionId) {
  80. const { pageId, shareLinkId } = this.pageContainer.state;
  81. try {
  82. const res = await this.appContainer.apiv3Get(`/revisions/${revisionId}`, {
  83. pageId, shareLinkId,
  84. });
  85. return res.data.revision;
  86. }
  87. catch (err) {
  88. toastError(err);
  89. this.setState({ errorMessage: err.message });
  90. logger.error(err);
  91. }
  92. return null;
  93. }
  94. /**
  95. * toggle state "compareWithLatest", and if true, set "targetRevision" to the latest revision
  96. */
  97. toggleCompareWithLatest() {
  98. const { compareWithLatest } = this.state;
  99. const newCompareWithLatest = !compareWithLatest;
  100. this.setState(
  101. Object.assign(
  102. { compareWithLatest: newCompareWithLatest },
  103. (newCompareWithLatest === true ? { targetRevision: this.state.latestRevision } : {}),
  104. ),
  105. );
  106. }
  107. }