RevisionComparer.jsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import React, { useState } from 'react';
  2. import PropTypes from 'prop-types';
  3. import { withTranslation } from 'react-i18next';
  4. import { CopyToClipboard } from 'react-copy-to-clipboard';
  5. import {
  6. Dropdown, DropdownToggle, DropdownMenu, DropdownItem,
  7. } from 'reactstrap';
  8. import { encodeSpaces } from '@commons/util/path-utils';
  9. import { withUnstatedContainers } from '../UnstatedUtils';
  10. import RevisionComparerContainer from '../../services/RevisionComparerContainer';
  11. import RevisionDiff from '../PageHistory/RevisionDiff';
  12. /* eslint-disable react/prop-types */
  13. const DropdownItemContents = ({ title, contents }) => (
  14. <>
  15. <div className="h6 mt-1 mb-2"><strong>{title}</strong></div>
  16. <div className="card well mb-1 p-2">{contents}</div>
  17. </>
  18. );
  19. /* eslint-enable react/prop-types */
  20. const RevisionComparer = (props) => {
  21. const [dropdownOpen, setDropdownOpen] = useState(false);
  22. const { t, revisionComparerContainer } = props;
  23. function toggleDropdown() {
  24. setDropdownOpen(!dropdownOpen);
  25. }
  26. const pagePathUrl = () => {
  27. const { origin } = window.location;
  28. const { path } = revisionComparerContainer.pageContainer.state;
  29. const { sourceRevision, targetRevision } = revisionComparerContainer.state;
  30. const url = new URL(path, origin);
  31. if (sourceRevision != null && targetRevision != null) {
  32. const urlParams = `${sourceRevision._id}...${targetRevision._id}`;
  33. url.searchParams.set('compare', urlParams);
  34. }
  35. return encodeSpaces(decodeURI(url));
  36. };
  37. const { sourceRevision, targetRevision } = revisionComparerContainer.state;
  38. if (sourceRevision == null || targetRevision == null) {
  39. return null;
  40. }
  41. const isNodiff = sourceRevision._id === targetRevision._id;
  42. return (
  43. <div className="revision-compare">
  44. <div className="d-flex">
  45. <h4 className="align-self-center">{ t('page_history.comparing_revisions') }</h4>
  46. <Dropdown
  47. className="grw-copy-dropdown align-self-center ml-auto"
  48. isOpen={dropdownOpen}
  49. toggle={() => toggleDropdown()}
  50. >
  51. <DropdownToggle
  52. caret
  53. className="d-block text-muted bg-transparent btn-copy border-0 py-0"
  54. >
  55. <i className="ti-clipboard"></i>
  56. </DropdownToggle>
  57. <DropdownMenu positionFixed right modifiers={{ preventOverflow: { boundariesElement: null } }}>
  58. {/* Page path URL */}
  59. <CopyToClipboard text={pagePathUrl()}>
  60. <DropdownItem className="px-3">
  61. <DropdownItemContents title={t('copy_to_clipboard.Page URL')} contents={pagePathUrl()} />
  62. </DropdownItem>
  63. </CopyToClipboard>
  64. <DropdownItem divider className="my-0"></DropdownItem>
  65. </DropdownMenu>
  66. </Dropdown>
  67. </div>
  68. <div className={`revision-compare-container ${isNodiff ? 'nodiff' : ''}`}>
  69. { isNodiff
  70. ? (
  71. <span className="h3 text-muted">{t('No diff')}</span>
  72. )
  73. : (
  74. <RevisionDiff
  75. revisionDiffOpened
  76. previousRevision={sourceRevision}
  77. currentRevision={targetRevision}
  78. />
  79. )
  80. }
  81. </div>
  82. </div>
  83. );
  84. };
  85. /**
  86. * Wrapper component for using unstated
  87. */
  88. const RevisionComparerWrapper = withUnstatedContainers(RevisionComparer, [RevisionComparerContainer]);
  89. RevisionComparer.propTypes = {
  90. t: PropTypes.func.isRequired, // i18next
  91. revisionComparerContainer: PropTypes.instanceOf(RevisionComparerContainer).isRequired,
  92. revisions: PropTypes.array,
  93. };
  94. export default withTranslation()(RevisionComparerWrapper);