ryoji-s 2 лет назад
Родитель
Сommit
b4c28d906f

+ 14 - 10
apps/app/src/components/CreateTemplateModal.jsx

@@ -4,18 +4,15 @@ import { pathUtils } from '@growi/core/dist/utils';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import PropTypes from 'prop-types';
 import PropTypes from 'prop-types';
 import { Modal, ModalHeader, ModalBody } from 'reactstrap';
 import { Modal, ModalHeader, ModalBody } from 'reactstrap';
-import urljoin from 'url-join';
 
 
 const CreateTemplateModal = (props) => {
 const CreateTemplateModal = (props) => {
   const { t } = useTranslation();
   const { t } = useTranslation();
-  const { path } = props;
+  const {
+    path, isCreating, onClickTemplateForChildrenButtonHandler, onClickTemplateForDescendantsButtonHandler,
+  } = props;
 
 
   const parentPath = pathUtils.addTrailingSlash(path);
   const parentPath = pathUtils.addTrailingSlash(path);
 
 
-  function generateUrl(label) {
-    return encodeURI(urljoin(parentPath, label, '#edit'));
-  }
-
   /**
   /**
    * @param {string} target Which hierarchy to create [children, descendants]
    * @param {string} target Which hierarchy to create [children, descendants]
    */
    */
@@ -28,14 +25,18 @@ const CreateTemplateModal = (props) => {
           <p className="form-text text-muted text-center"><small>{t(`template.${target}.desc`) }</small></p>
           <p className="form-text text-muted text-center"><small>{t(`template.${target}.desc`) }</small></p>
         </div>
         </div>
         <div className="card-footer text-center">
         <div className="card-footer text-center">
-          <a
+          <button
+            disabled={isCreating}
             data-testid={`template-button-${target}`}
             data-testid={`template-button-${target}`}
-            href={generateUrl(label)}
-            className="btn btn-sm btn-primary"
+            className="btn-sm btn-primary"
             id={`template-button-${target}`}
             id={`template-button-${target}`}
+            onClick={target === 'children'
+              ? onClickTemplateForChildrenButtonHandler
+              : onClickTemplateForDescendantsButtonHandler}
+            type="button"
           >
           >
             { t('Edit') }
             { t('Edit') }
-          </a>
+          </button>
         </div>
         </div>
       </div>
       </div>
     );
     );
@@ -71,6 +72,9 @@ CreateTemplateModal.propTypes = {
   path: PropTypes.string.isRequired,
   path: PropTypes.string.isRequired,
   isOpen: PropTypes.bool.isRequired,
   isOpen: PropTypes.bool.isRequired,
   onClose: PropTypes.func.isRequired,
   onClose: PropTypes.func.isRequired,
+  isCreating: PropTypes.bool.isRequired,
+  onClickTemplateForChildrenButtonHandler: PropTypes.func.isRequired,
+  onClickTemplateForDescendantsButtonHandler: PropTypes.func.isRequired,
 };
 };
 
 
 export default CreateTemplateModal;
 export default CreateTemplateModal;

+ 74 - 1
apps/app/src/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -11,7 +11,10 @@ import dynamic from 'next/dynamic';
 import { useRouter } from 'next/router';
 import { useRouter } from 'next/router';
 import { DropdownItem } from 'reactstrap';
 import { DropdownItem } from 'reactstrap';
 
 
-import { exportAsMarkdown, updateContentWidth } from '~/client/services/page-operation';
+import {
+  createPage, exist, exportAsMarkdown, updateContentWidth,
+} from '~/client/services/page-operation';
+import { toastError } from '~/client/util/toastr';
 import type { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction } from '~/interfaces/ui';
 import type { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction } from '~/interfaces/ui';
 import {
 import {
   useCurrentPathname,
   useCurrentPathname,
@@ -30,6 +33,7 @@ import {
   useIsAbleToChangeEditorMode,
   useIsAbleToChangeEditorMode,
   useSelectedGrant,
   useSelectedGrant,
 } from '~/stores/ui';
 } from '~/stores/ui';
+import loggerFactory from '~/utils/logger';
 
 
 import CreateTemplateModal from '../CreateTemplateModal';
 import CreateTemplateModal from '../CreateTemplateModal';
 import AttachmentIcon from '../Icons/AttachmentIcon';
 import AttachmentIcon from '../Icons/AttachmentIcon';
@@ -175,12 +179,16 @@ type GrowiContextualSubNavigationProps = {
   isLinkSharingDisabled?: boolean,
   isLinkSharingDisabled?: boolean,
 };
 };
 
 
+const logger = loggerFactory('growi:cli:GrowiContextualSubNavigation');
+
 const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps): JSX.Element => {
 const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps): JSX.Element => {
 
 
   const { currentPage } = props;
   const { currentPage } = props;
 
 
   const router = useRouter();
   const router = useRouter();
 
 
+  const [isCreating, setIsCreating] = useState<boolean>(false);
+
   const { data: shareLinkId } = useShareLinkId();
   const { data: shareLinkId } = useShareLinkId();
   const { trigger: mutateCurrentPage } = useSWRMUTxCurrentPage();
   const { trigger: mutateCurrentPage } = useSWRMUTxCurrentPage();
 
 
@@ -261,6 +269,68 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
     }
     }
   }, [isSharedPage, mutateCurrentPage]);
   }, [isSharedPage, mutateCurrentPage]);
 
 
+  const onClickTemplateForChildrenButtonHandler = useCallback(async() => {
+    try {
+      setIsCreating(true);
+
+      const path = currentPage == null || currentPage.path === '/'
+        ? '/_template'
+        : `${currentPage.path}/_template`;
+
+      const params = {
+        isSlackEnabled: false,
+        slackChannels: '',
+        grant: currentPage?.grant || 1,
+        grantUserGroupId: currentPage?.grantedGroup?._id,
+      };
+
+      const res = await exist(JSON.stringify([path]));
+      if (!res.pages[path]) {
+        await createPage(path, '', params);
+      }
+
+      router.push(`${path}#edit`);
+    }
+    catch (err) {
+      logger.warn(err);
+      toastError(err);
+    }
+    finally {
+      setIsCreating(false);
+    }
+  }, [currentPage, router]);
+
+  const onClickTemplateForDescendantsButtonHandler = useCallback(async() => {
+    try {
+      setIsCreating(true);
+
+      const path = currentPage == null || currentPage.path === '/'
+        ? '/__template'
+        : `${currentPage.path}/__template`;
+
+      const params = {
+        isSlackEnabled: false,
+        slackChannels: '',
+        grant: currentPage?.grant || 1,
+        grantUserGroupId: currentPage?.grantedGroup?._id,
+      };
+
+      const res = await exist(JSON.stringify([path]));
+      if (!res.pages[path]) {
+        await createPage(path, '', params);
+      }
+
+      router.push(`${path}#edit`);
+    }
+    catch (err) {
+      logger.warn(err);
+      toastError(err);
+    }
+    finally {
+      setIsCreating(false);
+    }
+  }, [currentPage, router]);
+
   const additionalMenuItemsRenderer = useCallback(() => {
   const additionalMenuItemsRenderer = useCallback(() => {
     if (revisionId == null || pageId == null) {
     if (revisionId == null || pageId == null) {
       return (
       return (
@@ -336,6 +406,9 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
           path={path}
           path={path}
           isOpen={isPageTemplateModalShown}
           isOpen={isPageTemplateModalShown}
           onClose={() => setIsPageTempleteModalShown(false)}
           onClose={() => setIsPageTempleteModalShown(false)}
+          isCreating={isCreating}
+          onClickTemplateForChildrenButtonHandler={onClickTemplateForChildrenButtonHandler}
+          onClickTemplateForDescendantsButtonHandler={onClickTemplateForDescendantsButtonHandler}
         />
         />
       )}
       )}
     </>
     </>