PageDuplicateModal.jsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import React, { useState } from 'react';
  2. import PropTypes from 'prop-types';
  3. import {
  4. Modal, ModalHeader, ModalBody, ModalFooter,
  5. } from 'reactstrap';
  6. import { withTranslation } from 'react-i18next';
  7. import { withUnstatedContainers } from './UnstatedUtils';
  8. import AppContainer from '../services/AppContainer';
  9. import PageContainer from '../services/PageContainer';
  10. import PagePathAutoComplete from './PagePathAutoComplete';
  11. import ApiErrorMessage from './PageManagement/ApiErrorMessage';
  12. const PageDuplicateModal = (props) => {
  13. const {
  14. t, appContainer, pageContainer,
  15. } = props;
  16. const config = appContainer.getConfig();
  17. const isReachable = config.isSearchServiceReachable;
  18. const { pageId, path } = pageContainer.state;
  19. const { crowi } = appContainer.config;
  20. const [pageNameInput, setPageNameInput] = useState(path);
  21. const [errorCode, setErrorCode] = useState(null);
  22. const [errorMessage, setErrorMessage] = useState(null);
  23. const [isDuplicateRecursively, setIsDuplicateRecursively] = useState(true);
  24. /**
  25. * change pageNameInput for PagePathAutoComplete
  26. * @param {string} value
  27. */
  28. function ppacInputChangeHandler(value) {
  29. setPageNameInput(value);
  30. }
  31. /**
  32. * change pageNameInput
  33. * @param {string} value
  34. */
  35. function inputChangeHandler(value) {
  36. setPageNameInput(value);
  37. }
  38. function changeIsDuplicateRecursivelyHandler() {
  39. setIsDuplicateRecursively(!isDuplicateRecursively);
  40. }
  41. async function duplicate() {
  42. try {
  43. setErrorCode(null);
  44. setErrorMessage(null);
  45. const res = await appContainer.apiPost('/pages.duplicate', { page_id: pageId, new_path: pageNameInput });
  46. const { page } = res;
  47. window.location.href = encodeURI(`${page.path}?duplicated=${path}`);
  48. }
  49. catch (err) {
  50. setErrorCode(err.code);
  51. setErrorMessage(err.message);
  52. }
  53. }
  54. function ppacSubmitHandler() {
  55. duplicate();
  56. }
  57. return (
  58. <Modal size="lg" isOpen={props.isOpen} toggle={props.onClose} className="grw-duplicate-page">
  59. <ModalHeader tag="h4" toggle={props.onClose} className="bg-primary text-light">
  60. {t('modal_duplicate.label.Duplicate page')}
  61. </ModalHeader>
  62. <ModalBody>
  63. <div className="form-group">
  64. <label>{t('modal_duplicate.label.Current page name')}</label>
  65. <br />
  66. <code>{path}</code>
  67. </div>
  68. <div className="form-group">
  69. <label htmlFor="duplicatePageName">{t('modal_duplicate.label.New page name')}</label>
  70. <br />
  71. <div className="input-group">
  72. <div className="input-group-prepend">
  73. <span className="input-group-text">{crowi.url}</span>
  74. </div>
  75. <div className="flex-fill">
  76. {isReachable ? (
  77. <PagePathAutoComplete crowi={appContainer} initializedPath={path} onSubmit={ppacSubmitHandler} onInputChange={ppacInputChangeHandler} />
  78. ) : (
  79. <input type="text" value={pageNameInput} className="form-control" onChange={e => inputChangeHandler(e.target.value)} required />
  80. )}
  81. </div>
  82. </div>
  83. </div>
  84. <div className="custom-control custom-checkbox custom-checkbox-warning">
  85. <input
  86. className="custom-control-input"
  87. name="recursively"
  88. id="cbDuplicateRecursively"
  89. type="checkbox"
  90. checked={isDuplicateRecursively}
  91. onChange={changeIsDuplicateRecursivelyHandler}
  92. />
  93. <label className="custom-control-label" htmlFor="cbDuplicateRecursively">
  94. {t('modal_duplicate.label.Duplicate with child')}
  95. </label>
  96. <div>
  97. <ul>
  98. {isDuplicateRecursively && props.pageDuplicateModalPaths.map(
  99. duplicatedNewPath => <li key={duplicatedNewPath}>{duplicatedNewPath}</li>,
  100. )}
  101. </ul>
  102. </div>
  103. <div> {props.duplicateError} </div>
  104. </div>
  105. </ModalBody>
  106. <ModalFooter>
  107. <ApiErrorMessage errorCode={errorCode} errorMessage={errorMessage} targetPath={pageNameInput} />
  108. <button type="button" className="btn btn-primary" onClick={duplicate}>
  109. Duplicate page
  110. </button>
  111. </ModalFooter>
  112. </Modal>
  113. );
  114. };
  115. /**
  116. * Wrapper component for using unstated
  117. */
  118. const PageDuplicateModallWrapper = withUnstatedContainers(PageDuplicateModal, [AppContainer, PageContainer]);
  119. PageDuplicateModal.propTypes = {
  120. t: PropTypes.func.isRequired, // i18next
  121. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  122. pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
  123. isOpen: PropTypes.bool.isRequired,
  124. onClose: PropTypes.func.isRequired,
  125. pageDuplicateModalPaths: PropTypes.array,
  126. duplicateError: PropTypes.string,
  127. };
  128. export default withTranslation()(PageDuplicateModallWrapper);