Просмотр исходного кода

Merge remote-tracking branch 'origin/master' into support/use-turborepo

Yuki Takei 3 лет назад
Родитель
Сommit
e21d71b0d9

+ 9 - 8
apps/app/src/components/PageEditor/CodeMirrorEditor.jsx

@@ -11,10 +11,9 @@ import { throttle, debounce } from 'throttle-debounce';
 import urljoin from 'url-join';
 
 import InterceptorManager from '~/services/interceptor-manager';
-import { useHandsontableModal, useDrawioModal } from '~/stores/modal';
+import { useHandsontableModal, useDrawioModal, useTemplateModal } from '~/stores/modal';
 import loggerFactory from '~/utils/logger';
 
-import { TemplateModal } from '../TemplateModal';
 import { UncontrolledCodeMirror } from '../UncontrolledCodeMirror';
 
 import AbstractEditor from './AbstractEditor';
@@ -873,7 +872,8 @@ class CodeMirrorEditor extends AbstractEditor {
   }
 
   showTemplateModal() {
-    this.setState({ isTemplateModalOpened: true });
+    const onSubmit = templateText => this.setValue(templateText);
+    this.props.onClickTemplateBtn(onSubmit);
   }
 
   // fold draw.io section (``` drawio ~ ```)
@@ -1158,11 +1158,6 @@ class CodeMirrorEditor extends AbstractEditor {
           ref={this.linkEditModal}
           onSave={(linkText) => { return markdownLinkUtil.replaceFocusedMarkdownLinkWithEditor(this.getCodeMirror(), linkText) }}
         />
-        <TemplateModal
-          isOpen={this.state.isTemplateModalOpened}
-          onClose={() => this.setState({ isTemplateModalOpened: false })}
-          onSubmit={templateText => this.setValue(templateText) }
-        />
       </div>
     );
   }
@@ -1187,6 +1182,7 @@ const CodeMirrorEditorMemoized = memo(CodeMirrorEditor);
 const CodeMirrorEditorFc = React.forwardRef((props, ref) => {
   const { open: openDrawioModal } = useDrawioModal();
   const { open: openHandsontableModal } = useHandsontableModal();
+  const { open: openTemplateModal } = useTemplateModal();
 
   const openDrawioModalHandler = useCallback((drawioMxFile, onSave) => {
     openDrawioModal(drawioMxFile, onSave);
@@ -1196,11 +1192,16 @@ const CodeMirrorEditorFc = React.forwardRef((props, ref) => {
     openHandsontableModal(markdownTable, editor, autoFormatMarkdownTable);
   }, [openHandsontableModal]);
 
+  const openTemplateModalHandler = useCallback((onSubmit) => {
+    openTemplateModal(onSubmit);
+  }, [openTemplateModal]);
+
   return (
     <CodeMirrorEditorMemoized
       ref={ref}
       onClickDrawioBtn={openDrawioModalHandler}
       onClickTableBtn={openTableModalHandler}
+      onClickTemplateBtn={openTemplateModalHandler}
       {...props}
     />
   );

+ 13 - 18
apps/app/src/components/TemplateModal.tsx

@@ -9,6 +9,7 @@ import {
   ModalFooter,
 } from 'reactstrap';
 
+import { useTemplateModal } from '~/stores/modal';
 import { usePreviewOptions } from '~/stores/renderer';
 import { useTemplates } from '~/stores/template';
 
@@ -40,17 +41,10 @@ const TemplateRadioButton = ({ template, onChange, isSelected }: TemplateRadioBu
   );
 };
 
-
-type Props = {
-  isOpen: boolean,
-  onClose: () => void,
-  onSubmit?: (markdown: string) => void,
-}
-
-export const TemplateModal = (props: Props): JSX.Element => {
+export const TemplateModal = (): JSX.Element => {
   const { t } = useTranslation();
 
-  const { isOpen, onClose, onSubmit } = props;
+  const { data: templateModalStatus, close } = useTemplateModal();
 
   const { data: rendererOptions } = usePreviewOptions();
   const { data: templates } = useTemplates();
@@ -58,22 +52,23 @@ export const TemplateModal = (props: Props): JSX.Element => {
   const [selectedTemplate, setSelectedTemplate] = useState<ITemplate>();
 
   const submitHandler = useCallback((template?: ITemplate) => {
-    if (onSubmit == null || template == null) {
-      onClose();
+    if (templateModalStatus == null) { return }
+    if (templateModalStatus.onSubmit == null || template == null) {
+      close();
       return;
     }
 
-    onSubmit(template.markdown);
-    onClose();
-  }, [onClose, onSubmit]);
+    templateModalStatus.onSubmit(template.markdown);
+    close();
+  }, [close, templateModalStatus]);
 
-  if (templates == null) {
+  if (templates == null || templateModalStatus == null) {
     return <></>;
   }
 
   return (
-    <Modal className="link-edit-modal" isOpen={isOpen} toggle={onClose} size="lg" autoFocus={false}>
-      <ModalHeader tag="h4" toggle={onClose} className="bg-primary text-light">
+    <Modal className="link-edit-modal" isOpen={templateModalStatus.isOpened} toggle={close} size="lg" autoFocus={false}>
+      <ModalHeader tag="h4" toggle={close} className="bg-primary text-light">
         Template
       </ModalHeader>
 
@@ -105,7 +100,7 @@ export const TemplateModal = (props: Props): JSX.Element => {
 
       </ModalBody>
       <ModalFooter>
-        <button type="button" className="btn btn-sm btn-outline-secondary mx-1" onClick={onClose}>
+        <button type="button" className="btn btn-sm btn-outline-secondary mx-1" onClick={close}>
           {t('Cancel')}
         </button>
         <button type="submit" className="btn btn-sm btn-primary mx-1" onClick={() => submitHandler(selectedTemplate)} disabled={selectedTemplate == null}>

+ 2 - 0
apps/app/src/pages/[[...path]].page.tsx

@@ -73,6 +73,7 @@ const GrowiSubNavigationSwitcher = dynamic<GrowiSubNavigationSwitcherProps>(() =
   .then(mod => mod.GrowiSubNavigationSwitcher), { ssr: false });
 const DrawioModal = dynamic(() => import('../components/PageEditor/DrawioModal').then(mod => mod.DrawioModal), { ssr: false });
 const HandsontableModal = dynamic(() => import('../components/PageEditor/HandsontableModal').then(mod => mod.HandsontableModal), { ssr: false });
+const TemplateModal = dynamic(() => import('../components/TemplateModal').then(mod => mod.TemplateModal), { ssr: false });
 const PageStatusAlert = dynamic(() => import('../components/PageStatusAlert').then(mod => mod.PageStatusAlert), { ssr: false });
 
 const logger = loggerFactory('growi:pages:all');
@@ -353,6 +354,7 @@ Page.getLayout = function getLayout(page: React.ReactElement<Props>) {
       <DescendantsPageListModal />
       <DrawioModal />
       <HandsontableModal />
+      <TemplateModal />
     </>
   );
 };

+ 4 - 1
apps/app/src/server/routes/attachment.js

@@ -468,7 +468,10 @@ module.exports = function(crowi, app) {
     if (pageId == null) {
       logger.debug('Create page before file upload');
 
-      page = await crowi.pageService.create(pagePath, `# ${pagePath}`, req.user, { grant: Page.GRANT_OWNER });
+      const isAclEnabled = crowi.aclService.isAclEnabled();
+      const grant = isAclEnabled ? Page.GRANT_OWNER : Page.GRANT_PUBLIC;
+
+      page = await crowi.pageService.create(pagePath, `# ${pagePath}`, req.user, { grant });
       pageCreated = true;
       pageId = page._id;
     }

+ 29 - 0
apps/app/src/stores/modal.tsx

@@ -579,3 +579,32 @@ export const useConflictDiffModal = (): SWRResponse<ConflictDiffModalStatus, Err
     },
   });
 };
+
+
+/*
+ * TemplateModal
+ */
+type TemplateModalStatus = {
+  isOpened: boolean,
+  onSubmit?: (templateText: string) => void
+}
+
+type TemplateModalUtils = {
+  open(onSubmit: (templateText: string) => void): void,
+  close(): void,
+}
+
+export const useTemplateModal = (): SWRResponse<TemplateModalStatus, Error> & TemplateModalUtils => {
+
+  const initialStatus: TemplateModalStatus = { isOpened: false };
+  const swrResponse = useStaticSWR<TemplateModalStatus, Error>('templateModal', undefined, { fallbackData: initialStatus });
+
+  return Object.assign(swrResponse, {
+    open: (onSubmit: (templateText: string) => void) => {
+      swrResponse.mutate({ isOpened: true, onSubmit });
+    },
+    close: () => {
+      swrResponse.mutate({ isOpened: false });
+    },
+  });
+};