RevisionComparer.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import React, { useState } from 'react';
  2. import type { IRevisionHasPageId } from '@growi/core';
  3. import { pagePathUtils } from '@growi/core/dist/utils';
  4. import { useTranslation } from 'next-i18next';
  5. import { CopyToClipboard } from 'react-copy-to-clipboard';
  6. import {
  7. Dropdown, DropdownToggle, DropdownMenu, DropdownItem,
  8. } from 'reactstrap';
  9. import { RevisionDiff } from '../PageHistory/RevisionDiff';
  10. import styles from './RevisionComparer.module.scss';
  11. const { encodeSpaces } = pagePathUtils;
  12. const DropdownItemContents = ({ title, contents }) => (
  13. <>
  14. <div className="h6 mt-1 mb-2"><strong>{title}</strong></div>
  15. <div className="card mb-1 p-2">{contents}</div>
  16. </>
  17. );
  18. type RevisionComparerProps = {
  19. sourceRevision: IRevisionHasPageId
  20. targetRevision: IRevisionHasPageId
  21. currentPageId?: string
  22. currentPagePath: string
  23. onClose: () => void
  24. }
  25. export const RevisionComparer = (props: RevisionComparerProps): JSX.Element => {
  26. const { t } = useTranslation(['translation', 'commons']);
  27. const {
  28. sourceRevision, targetRevision, onClose, currentPageId, currentPagePath,
  29. } = props;
  30. const [dropdownOpen, setDropdownOpen] = useState(false);
  31. const toggleDropdown = () => {
  32. setDropdownOpen(!dropdownOpen);
  33. };
  34. const generateURL = (pathName: string) => {
  35. const { origin } = window.location;
  36. const url = new URL(pathName, origin);
  37. if (sourceRevision != null && targetRevision != null) {
  38. const urlParams = `${sourceRevision._id}...${targetRevision._id}`;
  39. url.searchParams.set('compare', urlParams);
  40. }
  41. return encodeSpaces(decodeURI(url.href));
  42. };
  43. const isNodiff = (sourceRevision == null || targetRevision == null) ? true : sourceRevision._id === targetRevision._id;
  44. if (currentPageId == null || currentPagePath == null) {
  45. return <>{ t('not_found_page.page_not_exist')}</>;
  46. }
  47. return (
  48. <div className={`${styles['revision-compare']} revision-compare`}>
  49. <div className="d-flex">
  50. <h4 className="align-self-center">{ t('page_history.comparing_revisions') }</h4>
  51. { !isNodiff && (
  52. <Dropdown
  53. className="grw-copy-dropdown align-self-center ms-auto"
  54. isOpen={dropdownOpen}
  55. toggle={() => toggleDropdown()}
  56. >
  57. <DropdownToggle className="btn-copy">
  58. <span className="material-symbols-outlined">content_paste</span>
  59. </DropdownToggle>
  60. <DropdownMenu strategy="fixed" end>
  61. {/* Page path URL */}
  62. <CopyToClipboard text={generateURL(currentPagePath)}>
  63. <DropdownItem className="px-3">
  64. <DropdownItemContents title={t('copy_to_clipboard.Page URL', { ns: 'commons' })} contents={generateURL(currentPagePath)} />
  65. </DropdownItem>
  66. </CopyToClipboard>
  67. {/* Permanent Link URL */}
  68. <CopyToClipboard text={generateURL(currentPageId)}>
  69. <DropdownItem className="px-3">
  70. <DropdownItemContents title={t('copy_to_clipboard.Permanent link', { ns: 'commons' })} contents={generateURL(currentPageId)} />
  71. </DropdownItem>
  72. </CopyToClipboard>
  73. <DropdownItem divider className="my-0"></DropdownItem>
  74. </DropdownMenu>
  75. </Dropdown>
  76. ) }
  77. </div>
  78. <div className={`revision-compare-container ${isNodiff ? 'nodiff' : ''}`}>
  79. { isNodiff
  80. ? (
  81. <span className="h3 text-muted">{t('No diff')}</span>
  82. )
  83. : (
  84. <RevisionDiff
  85. revisionDiffOpened
  86. previousRevision={sourceRevision}
  87. currentRevision={targetRevision}
  88. currentPageId={currentPageId}
  89. currentPagePath={currentPagePath}
  90. onClose={onClose}
  91. />
  92. )
  93. }
  94. </div>
  95. </div>
  96. );
  97. };