PageDuplicateModal.jsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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 ApiErrorMessageList from './PageManagement/ApiErrorMessageList';
  12. const PageDuplicateModal = (props) => {
  13. const { t, appContainer, pageContainer } = props;
  14. const config = appContainer.getConfig();
  15. const isReachable = config.isSearchServiceReachable;
  16. const { pageId, path } = pageContainer.state;
  17. const { crowi } = appContainer.config;
  18. const [pageNameInput, setPageNameInput] = useState(path);
  19. const [errs, setErrs] = useState(null);
  20. const [getSubordinatedError] = useState(null);
  21. const [isDuplicateRecursively, setIsDuplicateRecursively] = useState(true);
  22. const [isDuplicateRecursivelyWithoutExistPath, setIsDuplicateRecursivelyWithoutExistPath] = useState(true);
  23. const [isDuplicateExist, setIsDuplicateExist] = useState([]);
  24. function createSubordinatedList(value) {
  25. // ToDo: get the duplicated list from sever
  26. // below is psuedo code
  27. // let duplicatedList = get.apiv3......
  28. // duplicatedList = duplicatedList.map((value) =>
  29. // <li className="duplicate-exist" key={value}> {value}: { t('modal_duplicate.label.Same page already exists') } </li>; )
  30. // setIsDuplicateExist(duplicatedList);
  31. // for now we use dummy path
  32. setIsDuplicateExist(['/test146/test147', value]);
  33. }
  34. /**
  35. * change pageNameInput for PagePathAutoComplete
  36. * @param {string} value
  37. */
  38. function ppacInputChangeHandler(value) {
  39. createSubordinatedList(value);
  40. setPageNameInput(value);
  41. }
  42. /**
  43. * change pageNameInput
  44. * @param {string} value
  45. */
  46. function inputChangeHandler(value) {
  47. createSubordinatedList(value);
  48. setPageNameInput(value);
  49. }
  50. function changeIsDuplicateRecursivelyHandler() {
  51. setIsDuplicateRecursively(!isDuplicateRecursively);
  52. }
  53. function changeIsDuplicateRecursivelyWithoutExistPathHandler() {
  54. setIsDuplicateRecursivelyWithoutExistPath(!isDuplicateRecursivelyWithoutExistPath);
  55. }
  56. // function changeIsExistHandler() {
  57. // setIsExist(true);
  58. // }
  59. async function duplicate() {
  60. setErrs(null);
  61. try {
  62. const res = await appContainer.apiv3Post('/pages/duplicate', { pageId, pageNameInput });
  63. const { page } = res.data;
  64. window.location.href = encodeURI(`${page.path}?duplicated=${path}`);
  65. }
  66. catch (err) {
  67. setErrs(err);
  68. }
  69. }
  70. function ppacSubmitHandler() {
  71. duplicate();
  72. }
  73. return (
  74. <Modal size="lg" isOpen={props.isOpen} toggle={props.onClose} className="grw-duplicate-page">
  75. <ModalHeader tag="h4" toggle={props.onClose} className="bg-primary text-light">
  76. { t('modal_duplicate.label.Duplicate page') }
  77. </ModalHeader>
  78. <ModalBody>
  79. <div className="form-group"><label>{t('modal_duplicate.label.Current page name')}</label><br />
  80. <code>{path}</code>
  81. </div>
  82. <div className="form-group">
  83. <label htmlFor="duplicatePageName">{ t('modal_duplicate.label.New page name') }</label><br />
  84. <div className="input-group">
  85. <div className="input-group-prepend">
  86. <span className="input-group-text">{crowi.url}</span>
  87. </div>
  88. <div className="flex-fill">
  89. {isReachable
  90. ? (
  91. <PagePathAutoComplete
  92. initializedPath={path}
  93. onSubmit={ppacSubmitHandler}
  94. onInputChange={ppacInputChangeHandler}
  95. />
  96. )
  97. : (
  98. <input
  99. type="text"
  100. value={pageNameInput}
  101. className="form-control"
  102. onChange={e => inputChangeHandler(e.target.value)}
  103. required
  104. />
  105. )}
  106. </div>
  107. </div>
  108. </div>
  109. <div className="custom-control custom-checkbox custom-checkbox-warning">
  110. <input
  111. className="custom-control-input"
  112. name="recursively"
  113. id="cbDuplicateRecursively"
  114. type="checkbox"
  115. checked={isDuplicateRecursively}
  116. onChange={changeIsDuplicateRecursivelyHandler}
  117. />
  118. <label className="custom-control-label" htmlFor="cbDuplicateRecursively">
  119. { t('modal_duplicate.label.Duplicate with child') }
  120. </label>
  121. </div>
  122. <div
  123. className="custom-control custom-checkbox custom-checkbox-warning"
  124. style={{ display: (isDuplicateExist.length !== 0) && isDuplicateRecursively ? '' : 'none' }}
  125. >
  126. <input
  127. className="custom-control-input"
  128. name="withoutExistRecursively"
  129. id="cbDuplicatewithoutExistRecursively"
  130. type="checkbox"
  131. checked={isDuplicateRecursivelyWithoutExistPath}
  132. onChange={changeIsDuplicateRecursivelyWithoutExistPathHandler}
  133. />
  134. <label className="custom-control-label" htmlFor="cbDuplicatewithoutExistRecursively">
  135. { t('modal_duplicate.label.Duplicate without exist path') }
  136. </label>
  137. </div>
  138. <div>
  139. <ul className="duplicate-name">
  140. {isDuplicateRecursively && isDuplicateExist.length !== 0 && isDuplicateExist}
  141. </ul>
  142. </div>
  143. <div> {getSubordinatedError} </div>
  144. </ModalBody>
  145. <ModalFooter>
  146. <ApiErrorMessageList errs={errs} targetPath={pageNameInput} />
  147. <button type="button" className="btn btn-primary" onClick={duplicate}>Duplicate page</button>
  148. </ModalFooter>
  149. </Modal>
  150. );
  151. };
  152. /**
  153. * Wrapper component for using unstated
  154. */
  155. const PageDuplicateModallWrapper = withUnstatedContainers(PageDuplicateModal, [AppContainer, PageContainer]);
  156. PageDuplicateModal.propTypes = {
  157. t: PropTypes.func.isRequired, // i18next
  158. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  159. pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
  160. isOpen: PropTypes.bool.isRequired,
  161. onClose: PropTypes.func.isRequired,
  162. };
  163. export default withTranslation()(PageDuplicateModallWrapper);