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

Merge pull request #6381 from weseek/support/rendering-CommentEditorLazyRenderer

support: Rendering CommentEditorLazyRenderer
Yuki Takei 3 лет назад
Родитель
Сommit
fe952a2899

+ 22 - 24
packages/app/src/components/PageComment.tsx

@@ -16,18 +16,19 @@ import { useSWRxPageComment } from '../stores/comment';
 
 import { Comment } from './PageComment/Comment';
 import { CommentEditor } from './PageComment/CommentEditor';
+import { CommentEditorLazyRenderer } from './PageComment/CommentEditorLazyRenderer';
 import DeleteCommentModal from './PageComment/DeleteCommentModal';
-import { ReplayComments } from './PageComment/ReplayComments';
+import { ReplyComments } from './PageComment/ReplyComments';
 
 type Props = {
-  pageId?: Nullable<string>, // TODO: check pageId type
-  isReadOnly : boolean,
+  pageId?: Nullable<string>
+  isReadOnly: boolean,
   titleAlign?: 'center' | 'left' | 'right',
-  highlightKeywords?:string[],
+  highlightKeywords?: string[],
   hideIfEmpty?: boolean,
 }
 
-export const PageComment:FC<Props> = memo((props:Props):JSX.Element => {
+export const PageComment: FC<Props> = memo((props:Props): JSX.Element => {
 
   const {
     pageId, highlightKeywords, isReadOnly, titleAlign, hideIfEmpty,
@@ -61,7 +62,6 @@ export const PageComment:FC<Props> = memo((props:Props):JSX.Element => {
   }, [highlightKeywords]);
 
   useEffect(() => {
-
     if (comments != null) {
       const preprocessedCommentList: string[] = comments.map((comment) => {
         const highlightedComment: string = highlightComment(comment.comment);
@@ -72,7 +72,6 @@ export const PageComment:FC<Props> = memo((props:Props):JSX.Element => {
       });
       setFormatedComments(preprocessedComments);
     }
-
   }, [comments, highlightComment]);
 
   if (commentsFromOldest != null) {
@@ -110,16 +109,6 @@ export const PageComment:FC<Props> = memo((props:Props):JSX.Element => {
     }
   }, [commentToBeDeleted, onDeleteCommentAfterOperation]);
 
-  const generateAllRepliesElement = (replyComments: ICommentHasIdList) => (
-    // TODO: need page props path
-    <ReplayComments
-      replyList={replyComments}
-      deleteBtnClicked={onClickDeleteButton}
-      rendererOptions={rendererOptions}
-      isReadOnly={isReadOnly}
-    />
-  );
-
   const removeShowEditorId = useCallback((commentId: string) => {
     setShowEditorIds((previousState) => {
       const previousShowEditorIds = new Set(...previousState);
@@ -128,32 +117,38 @@ export const PageComment:FC<Props> = memo((props:Props):JSX.Element => {
     });
   }, []);
 
-
   if (commentsFromOldest == null || commentsExceptReply == null) return <></>;
 
   if (hideIfEmpty && comments?.length === 0) {
     return <></>;
   }
-  if (rendererOptions == null || currentPagePath == null) {
+  if (rendererOptions == null || currentPagePath == null || currentPage == null) {
     return <></>;
   }
 
   const generateCommentInnerElement = (comment: ICommentHasId) => (
     <Comment
-      rendererOptions={rendererOptions}
-      deleteBtnClicked={onClickDeleteButton}
       comment={comment}
-      onComment={mutate}
       isReadOnly={isReadOnly}
+      deleteBtnClicked={onClickDeleteButton}
+      onComment={mutate}
+      rendererOptions={rendererOptions}
+      currentPagePath={currentPagePath}
+      currentRevisionId={currentPage.revision._id}
+      currentRevisionCreatedAt={currentPage.revision.createdAt}
     />
   );
 
   const generateAllRepliesElement = (replyComments: ICommentHasIdList) => (
-    <ReplayComments
+    <ReplyComments
+      isReadOnly={isReadOnly}
       replyList={replyComments}
       deleteBtnClicked={onClickDeleteButton}
-      isReadOnly={isReadOnly}
       onComment={mutate}
+      rendererOptions={rendererOptions}
+      currentPagePath={currentPagePath}
+      currentRevisionId={currentPage.revision._id}
+      currentRevisionCreatedAt={currentPage.revision.createdAt}
     />
   );
 
@@ -200,6 +195,7 @@ export const PageComment:FC<Props> = memo((props:Props):JSX.Element => {
                     {/* display reply editor */}
                     {(!isReadOnly && showEditorIds.has(comment._id)) && (
                       <CommentEditor
+                        rendererOptions={rendererOptions}
                         replyTo={comment._id}
                         onCancelButtonClicked={() => {
                           removeShowEditorId(comment._id);
@@ -215,6 +211,8 @@ export const PageComment:FC<Props> = memo((props:Props):JSX.Element => {
 
               })}
             </div>
+            {/* TODO: Check if identical-page */}
+            <CommentEditorLazyRenderer pageId={pageId} rendererOptions={rendererOptions}/>
           </div>
         </div>
       </div>

+ 0 - 259
packages/app/src/components/PageComment/Comment.jsx

@@ -1,259 +0,0 @@
-import React from 'react';
-
-import { UserPicture } from '@growi/ui';
-import { format } from 'date-fns';
-import { useTranslation } from 'next-i18next';
-import PropTypes from 'prop-types';
-import { UncontrolledTooltip } from 'reactstrap';
-
-import AppContainer from '~/client/services/AppContainer';
-import PageContainer from '~/client/services/PageContainer';
-import { RendererOptions } from '~/services/renderer/renderer';
-import { useCurrentUser } from '~/stores/context';
-
-import FormattedDistanceDate from '../FormattedDistanceDate';
-import HistoryIcon from '../Icons/HistoryIcon';
-import RevisionBody from '../Page/RevisionBody';
-import { withUnstatedContainers } from '../UnstatedUtils';
-import Username from '../User/Username';
-
-import CommentControl from './CommentControl';
-import { CommentEditor } from './CommentEditor';
-
-
-/**
- *
- * @author Yuki Takei <yuki@weseek.co.jp>
- *
- * @export
- * @class Comment
- * @extends {React.Component}
- */
-class Comment extends React.PureComponent {
-
-  constructor(props) {
-    super(props);
-
-    this.state = {
-      html: '',
-      isReEdit: false,
-    };
-
-    this.isCurrentUserIsAuthor = this.isCurrentUserEqualsToAuthor.bind(this);
-    this.isCurrentRevision = this.isCurrentRevision.bind(this);
-    this.getRootClassName = this.getRootClassName.bind(this);
-    this.deleteBtnClickedHandler = this.deleteBtnClickedHandler.bind(this);
-    this.renderText = this.renderText.bind(this);
-    this.renderHtml = this.renderHtml.bind(this);
-  }
-
-
-  initCurrentRenderingContext() {
-    this.currentRenderingContext = {
-      markdown: this.props.comment.comment,
-    };
-  }
-
-  componentDidMount() {
-    this.initCurrentRenderingContext();
-    this.renderHtml();
-  }
-
-  componentDidUpdate(prevProps) {
-    const { comment: prevComment } = prevProps;
-    const { comment } = this.props;
-
-    // render only when props.markdown is updated
-    if (comment !== prevComment) {
-      this.initCurrentRenderingContext();
-      this.renderHtml();
-      return;
-    }
-
-    const { interceptorManager } = window;
-
-    interceptorManager.process('postRenderCommentHtml', this.currentRenderingContext);
-  }
-
-  isCurrentUserEqualsToAuthor() {
-    const { comment, currentUser } = this.props;
-    const { creator } = comment;
-
-    if (creator == null || currentUser == null) {
-      return false;
-    }
-    return creator.username === currentUser.username;
-  }
-
-  isCurrentRevision() {
-    return this.props.comment.revision === this.props.pageContainer.state.revisionId;
-  }
-
-  getRootClassName(comment) {
-    let className = 'page-comment flex-column';
-
-    const { revisionId, revisionCreatedAt } = this.props.pageContainer.state;
-    if (comment.revision === revisionId) {
-      className += ' page-comment-current';
-    }
-    else if (Date.parse(comment.createdAt) / 1000 > revisionCreatedAt) {
-      className += ' page-comment-newer';
-    }
-    else {
-      className += ' page-comment-older';
-    }
-
-    if (this.isCurrentUserEqualsToAuthor()) {
-      className += ' page-comment-me';
-    }
-
-    return className;
-  }
-
-  deleteBtnClickedHandler() {
-    this.props.deleteBtnClicked(this.props.comment);
-  }
-
-  renderText(comment) {
-    return <span style={{ whiteSpace: 'pre-wrap' }}>{comment}</span>;
-  }
-
-  renderRevisionBody() {
-    const config = this.props.appContainer.getConfig();
-    const isMathJaxEnabled = !!config.env.MATHJAX;
-    return (
-      <RevisionBody
-        html={this.state.html}
-        isMathJaxEnabled={isMathJaxEnabled}
-        renderMathJaxOnInit
-        additionalClassName="comment"
-      />
-    );
-  }
-
-  async renderHtml() {
-
-    const { rendererOptions, appContainer } = this.props;
-    const { interceptorManager } = window;
-    const context = this.currentRenderingContext;
-
-    await interceptorManager.process('preRenderComment', context);
-    await interceptorManager.process('prePreProcess', context);
-    context.markdown = await rendererOptions.preProcess(context.markdown, context);
-    await interceptorManager.process('postPreProcess', context);
-    context.parsedHTML = await rendererOptions.process(context.markdown, context);
-    await interceptorManager.process('prePostProcess', context);
-    context.parsedHTML = await rendererOptions.postProcess(context.parsedHTML, context);
-    await interceptorManager.process('postPostProcess', context);
-    await interceptorManager.process('preRenderCommentHtml', context);
-    this.setState({ html: context.parsedHTML });
-    await interceptorManager.process('postRenderCommentHtml', context);
-  }
-
-  render() {
-    const {
-      t, comment, isReadOnly, onComment,
-    } = this.props;
-    const commentId = comment._id;
-    const creator = comment.creator;
-    const isMarkdown = comment.isMarkdown;
-    const createdAt = new Date(comment.createdAt);
-    const updatedAt = new Date(comment.updatedAt);
-    const isEdited = createdAt < updatedAt;
-
-    const rootClassName = this.getRootClassName(comment);
-    const commentBody = isMarkdown ? this.renderRevisionBody() : this.renderText(comment.comment);
-    const revHref = `?revision=${comment.revision}`;
-
-    const editedDateId = `editedDate-${comment._id}`;
-    const editedDateFormatted = isEdited
-      ? format(updatedAt, 'yyyy/MM/dd HH:mm')
-      : null;
-
-    return (
-      <React.Fragment>
-        {(this.state.isReEdit && !isReadOnly) ? (
-          <CommentEditor
-            rendererOptions={this.props.rendererOptions}
-            currentCommentId={commentId}
-            commentBody={comment.comment}
-            replyTo={undefined}
-            commentCreator={creator?.username}
-            onCancelButtonClicked={() => this.setState({ isReEdit: false })}
-            onCommentButtonClicked={() => {
-              this.setState({ isReEdit: false });
-              if (onComment != null) onComment();
-            }}
-          />
-        ) : (
-          <div id={commentId} className={rootClassName}>
-            <div className="page-comment-writer">
-              <UserPicture user={creator} />
-            </div>
-            <div className="page-comment-main">
-              <div className="page-comment-creator">
-                <Username user={creator} />
-              </div>
-              <div className="page-comment-body">{commentBody}</div>
-              <div className="page-comment-meta">
-                <a href={`#${commentId}`}>
-                  <FormattedDistanceDate id={commentId} date={comment.createdAt} />
-                </a>
-                { isEdited && (
-                  <>
-                    <span id={editedDateId}>&nbsp;(edited)</span>
-                    <UncontrolledTooltip placement="bottom" fade={false} target={editedDateId}>{editedDateFormatted}</UncontrolledTooltip>
-                  </>
-                )}
-                <span className="ml-2">
-                  <a id={`page-comment-revision-${commentId}`} className="page-comment-revision" href={revHref}>
-                    <HistoryIcon />
-                  </a>
-                  <UncontrolledTooltip placement="bottom" fade={false} target={`page-comment-revision-${commentId}`}>
-                    {t('page_comment.display_the_page_when_posting_this_comment')}
-                  </UncontrolledTooltip>
-                </span>
-              </div>
-              {(this.isCurrentUserEqualsToAuthor() && !isReadOnly) && (
-                <CommentControl
-                  onClickDeleteBtn={this.deleteBtnClickedHandler}
-                  onClickEditBtn={() => this.setState({ isReEdit: true })}
-                />
-              ) }
-            </div>
-          </div>
-        )
-        }
-      </React.Fragment>
-    );
-  }
-
-}
-
-Comment.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-  pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
-
-  comment: PropTypes.object.isRequired,
-  isReadOnly: PropTypes.bool.isRequired,
-  rendererOptions: PropTypes.instanceOf(RendererOptions).isRequired,
-  deleteBtnClicked: PropTypes.func.isRequired,
-  currentUser: PropTypes.object,
-  onComment: PropTypes.func,
-};
-
-const CommentWrapperFC = (props) => {
-  const { t } = useTranslation();
-
-  const { data: currentUser } = useCurrentUser();
-
-  return <Comment t={t} currentUser={currentUser} {...props} />;
-};
-
-/**
- * Wrapper component for using unstated
- */
-const CommentWrapper = withUnstatedContainers(CommentWrapperFC, [AppContainer, PageContainer]);
-
-export default CommentWrapper;

+ 9 - 14
packages/app/src/components/PageComment/Comment.tsx

@@ -1,8 +1,6 @@
 import React, { useEffect, useState } from 'react';
 
-
 import { UserPicture } from '@growi/ui';
-import { ConsoleFormattedStream } from 'browser-bunyan';
 import { format } from 'date-fns';
 import { useTranslation } from 'next-i18next';
 import { UncontrolledTooltip } from 'reactstrap';
@@ -17,7 +15,7 @@ import RevisionRenderer from '../Page/RevisionRenderer';
 import Username from '../User/Username';
 
 import CommentControl from './CommentControl';
-import CommentEditor from './CommentEditor';
+import { CommentEditor } from './CommentEditor';
 
 type CommentProps = {
   comment: ICommentHasId,
@@ -31,9 +29,12 @@ type CommentProps = {
 }
 
 export const Comment = (props: CommentProps): JSX.Element => {
+
   const {
-    comment, isReadOnly, deleteBtnClicked, onComment, rendererOptions, currentPagePath, currentRevisionId, currentRevisionCreatedAt,
+    comment, isReadOnly, deleteBtnClicked, onComment, rendererOptions,
+    currentPagePath, currentRevisionId, currentRevisionCreatedAt,
   } = props;
+
   const { t } = useTranslation();
   const { data: currentUser } = useCurrentUser();
 
@@ -66,7 +67,7 @@ export const Comment = (props: CommentProps): JSX.Element => {
     return creator.username === currentUser.username;
   };
 
-  const getRootClassName = (comment) => {
+  const getRootClassName = (comment: ICommentHasId) => {
     let className = 'page-comment flex-column';
 
     if (comment.revision === currentRevisionId) {
@@ -86,19 +87,14 @@ export const Comment = (props: CommentProps): JSX.Element => {
     return className;
   };
 
-  const deleteBtnClickedHandler = (comment) => {
+  const deleteBtnClickedHandler = () => {
     deleteBtnClicked(comment);
   };
 
-  const renderText = (comment) => {
+  const renderText = (comment: string) => {
     return <span style={{ whiteSpace: 'pre-wrap' }}>{comment}</span>;
   };
 
-  // TODO: Remove when update ReplayComments.jsx
-  if (currentPagePath == null) {
-    return <></>;
-  }
-
   const renderRevisionBody = () => {
     return (
       <RevisionRenderer
@@ -124,10 +120,9 @@ export const Comment = (props: CommentProps): JSX.Element => {
       {(isReEdit && !isReadOnly) ? (
         <CommentEditor
           rendererOptions={rendererOptions}
+          replyTo={undefined}
           currentCommentId={commentId}
           commentBody={comment.comment}
-          replyTo={undefined}
-          commentCreator={creator?.username}
           onCancelButtonClicked={() => setIsReEdit(false)}
           onCommentButtonClicked={() => {
             setIsReEdit(false);

+ 12 - 11
packages/app/src/components/PageComment/CommentEditor.tsx

@@ -10,10 +10,11 @@ import {
 import * as toastr from 'toastr';
 
 import { apiPostForm } from '~/client/util/apiv1-client';
+import { RendererOptions } from '~/services/renderer/renderer';
 import { useSWRxPageComment } from '~/stores/comment';
 import {
   useCurrentPagePath, useCurrentPageId, useCurrentUser, useRevisionId, useIsSlackConfigured,
-  useEditorConfig,
+  useIsUploadableFile, useIsUploadableImage,
 } from '~/stores/context';
 import { useSWRxSlackChannels, useIsSlackEnabled } from '~/stores/editor';
 import { useIsMobile } from '~/stores/ui';
@@ -39,6 +40,7 @@ const navTabMapping = {
 };
 
 type PropsType = {
+  rendererOptions: RendererOptions,
   isForNewComment?: boolean,
   replyTo?: string,
   currentCommentId?: string,
@@ -56,9 +58,10 @@ type EditorRef = {
 export const CommentEditor = (props: PropsType): JSX.Element => {
 
   const {
-    isForNewComment, replyTo,
+    rendererOptions, isForNewComment, replyTo,
     currentCommentId, commentBody, onCancelButtonClicked, onCommentButtonClicked,
   } = props;
+
   const { data: currentUser } = useCurrentUser();
   const { data: currentPagePath } = useCurrentPagePath();
   const { data: currentPageId } = useCurrentPageId();
@@ -68,7 +71,8 @@ export const CommentEditor = (props: PropsType): JSX.Element => {
   const { data: isSlackEnabled, mutate: mutateIsSlackEnabled } = useIsSlackEnabled();
   const { data: slackChannelsData } = useSWRxSlackChannels(currentPagePath);
   const { data: isSlackConfigured } = useIsSlackConfigured();
-  const { data: editorConfig } = useEditorConfig();
+  const { data: isUploadableFile } = useIsUploadableFile();
+  const { data: isUploadableImage } = useIsUploadableImage();
 
   const [isReadyToUse, setIsReadyToUse] = useState(!isForNewComment);
   // TODO: Refactor comment and markdown variable names or logic after presentation
@@ -209,11 +213,12 @@ export const CommentEditor = (props: PropsType): JSX.Element => {
 
     return (
       <CommentPreview
+        rendererOptions={rendererOptions}
         markdown={markdown}
         path={currentPagePath}
       />
     );
-  }, [currentPagePath, markdown]);
+  }, [currentPagePath, markdown, rendererOptions]);
 
   const renderBeforeReady = useCallback((): JSX.Element => {
     return (
@@ -256,11 +261,7 @@ export const CommentEditor = (props: PropsType): JSX.Element => {
     // TODO: typescriptize Editor
     const AnyEditor = Editor as any;
 
-    if (editorConfig === undefined) {
-      return <></>;
-    }
-    const isUploadable = editorConfig.upload.image || editorConfig.upload.file;
-    const isUploadableFile = editorConfig.upload.file;
+    const isUploadable = isUploadableImage || isUploadableFile;
 
     return (
       <>
@@ -298,7 +299,7 @@ export const CommentEditor = (props: PropsType): JSX.Element => {
             <span className="flex-grow-1" />
             <span className="d-none d-sm-inline">{ errorMessage && errorMessage }</span>
 
-            {/* { isSlackConfigured
+            { isSlackConfigured
               && (
                 <div className="form-inline align-self-center mr-md-2">
                   <SlackNotification
@@ -310,7 +311,7 @@ export const CommentEditor = (props: PropsType): JSX.Element => {
                   />
                 </div>
               )
-            } */}
+            }
             <div className="d-none d-sm-block">
               <span className="mr-2">{cancelButton}</span><span>{submitButton}</span>
             </div>

+ 9 - 12
packages/app/src/components/PageComment/CommentEditorLazyRenderer.tsx

@@ -1,24 +1,23 @@
-import React, { FC } from 'react';
+import React from 'react';
 
-import { useCommentPreviewOptions } from '~/stores/renderer';
+import { Nullable } from '@growi/core';
+
+import { RendererOptions } from '~/services/renderer/renderer';
 
 import { useSWRxPageComment } from '../../stores/comment';
 
 import { CommentEditor } from './CommentEditor';
 
 type Props = {
-  pageId: string,
+  pageId?: Nullable<string>,
+  rendererOptions: RendererOptions,
 }
 
-const CommentEditorLazyRenderer:FC<Props> = (props:Props):JSX.Element => {
+export const CommentEditorLazyRenderer = (props: Props): JSX.Element => {
 
-  const { pageId } = props;
-  const { mutate } = useSWRxPageComment(pageId);
-  const { data: rendererOptions } = useCommentPreviewOptions();
+  const { pageId, rendererOptions } = props;
 
-  if (rendererOptions == null) {
-    return <></>;
-  }
+  const { mutate } = useSWRxPageComment(pageId);
 
   return (
     <CommentEditor
@@ -29,5 +28,3 @@ const CommentEditorLazyRenderer:FC<Props> = (props:Props):JSX.Element => {
     />
   );
 };
-
-export default CommentEditorLazyRenderer;

+ 4 - 8
packages/app/src/components/PageComment/CommentPreview.tsx

@@ -1,25 +1,21 @@
-import { useCommentPreviewOptions } from '~/stores/renderer';
+import { RendererOptions } from '~/services/renderer/renderer';
 
 import RevisionRenderer from '../Page/RevisionRenderer';
 
 type CommentPreviewPorps = {
+  rendererOptions: RendererOptions,
   markdown: string,
   path: string,
 }
 
 export const CommentPreview = (props: CommentPreviewPorps): JSX.Element => {
-  const { markdown, path } = props;
 
-  const { data: commentPreviewOptions } = useCommentPreviewOptions();
-
-  if (commentPreviewOptions == null) {
-    return <></>;
-  }
+  const { markdown, path, rendererOptions } = props;
 
   return (
     <div className="page-comment-preview-body">
       <RevisionRenderer
-        rendererOptions={commentPreviewOptions}
+        rendererOptions={rendererOptions}
         markdown={markdown}
         additionalClassName="comment"
         pagePath={path}

+ 0 - 114
packages/app/src/components/PageComment/ReplayComments.jsx

@@ -1,114 +0,0 @@
-import React from 'react';
-
-import PropTypes from 'prop-types';
-import { Collapse } from 'reactstrap';
-
-import { RendererOptions } from '~/services/renderer/renderer';
-import { useRendererConfig } from '~/stores/context';
-
-import { Comment } from './Comment';
-
-
-class ReplayComments extends React.PureComponent {
-
-  constructor() {
-    super();
-
-    this.state = {
-      isOlderRepliesShown: false,
-    };
-
-    this.toggleOlderReplies = this.toggleOlderReplies.bind(this);
-  }
-
-  toggleOlderReplies() {
-    this.setState({ isOlderRepliesShown: !this.state.isOlderRepliesShown });
-  }
-
-  renderReply(reply) {
-    return (
-      <div key={reply._id} className="page-comment-reply ml-4 ml-sm-5 mr-3">
-        <Comment
-          comment={reply}
-          deleteBtnClicked={this.props.deleteBtnClicked}
-          rendererOptions={this.props.rendererOptions}
-          isReadOnly={this.props.isReadOnly}
-        />
-      </div>
-    );
-  }
-
-  render() {
-    const { config } = this.props;
-
-    const isAllReplyShown = config.isAllReplyShown || false;
-    const replyList = this.props.replyList;
-
-    if (isAllReplyShown) {
-      return (
-        <React.Fragment>
-          {replyList.map((reply) => {
-            return this.renderReply(reply);
-          })}
-        </React.Fragment>
-      );
-    }
-
-    const areThereHiddenReplies = (replyList.length > 2);
-
-    const { isOlderRepliesShown } = this.state;
-    const toggleButtonIconName = isOlderRepliesShown ? 'icon-arrow-up' : 'icon-options-vertical';
-    const toggleButtonIcon = <i className={`icon-fw ${toggleButtonIconName}`}></i>;
-    const toggleButtonLabel = isOlderRepliesShown ? '' : 'more';
-
-    const shownReplies = replyList.slice(replyList.length - 2, replyList.length);
-    const hiddenReplies = replyList.slice(0, replyList.length - 2);
-
-    const hiddenElements = hiddenReplies.map((reply) => {
-      return this.renderReply(reply);
-    });
-
-    const shownElements = shownReplies.map((reply) => {
-      return this.renderReply(reply);
-    });
-
-    return (
-      <React.Fragment>
-        {areThereHiddenReplies && (
-          <div className="page-comments-hidden-replies">
-            <Collapse isOpen={this.state.isOlderRepliesShown}>
-              <div>{hiddenElements}</div>
-            </Collapse>
-            <div className="text-center">
-              <button
-                type="button"
-                className="btn btn-link"
-                onClick={this.toggleOlderReplies}
-              >
-                {toggleButtonIcon} {toggleButtonLabel}
-              </button>
-            </div>
-          </div>
-        )}
-        {shownElements}
-
-      </React.Fragment>
-    );
-  }
-
-}
-
-ReplayComments.propTypes = {
-  rendererOptions: PropTypes.instanceOf(RendererOptions).isRequired,
-  deleteBtnClicked: PropTypes.func.isRequired,
-  isReadOnly: PropTypes.bool.isRequired,
-  replyList: PropTypes.array,
-};
-
-const ReplayCommentsWrapperFC = (props) => {
-  const { data: config } = useRendererConfig();
-
-  return <ReplayComments config={config} {...props} />;
-};
-
-export default ReplayCommentsWrapperFC;

+ 21 - 12
packages/app/src/components/PageComment/ReplayComments.tsx → packages/app/src/components/PageComment/ReplyComments.tsx

@@ -3,23 +3,31 @@ import React, { useState } from 'react';
 
 import { Collapse } from 'reactstrap';
 
+import { RendererOptions } from '~/services/renderer/renderer';
+
 import { ICommentHasId, ICommentHasIdList } from '../../interfaces/comment';
-import { useRendererConfig, useIsAllReplyShown } from '../../stores/context';
+import { useIsAllReplyShown } from '../../stores/context';
 
-import Comment from './Comment';
+import { Comment } from './Comment';
 
-type ReplaycommentsProps = {
-  deleteBtnClicked: (comment: ICommentHasId) => void,
+type ReplycommentsProps = {
   isReadOnly: boolean,
   replyList: ICommentHasIdList,
+  deleteBtnClicked: (comment: ICommentHasId) => void,
   onComment: () => void,
+  rendererOptions: RendererOptions,
+  currentPagePath: string,
+  currentRevisionId: string,
+  currentRevisionCreatedAt: Date,
 }
 
-export const ReplayComments = (props: ReplaycommentsProps): JSX.Element => {
+export const ReplyComments = (props: ReplycommentsProps): JSX.Element => {
+
   const {
-    deleteBtnClicked, isReadOnly, replyList, onComment,
+    isReadOnly, replyList, deleteBtnClicked, onComment, rendererOptions,
+    currentPagePath, currentRevisionId, currentRevisionCreatedAt,
   } = props;
-  const { data: rendererConfig } = useRendererConfig();
+
   const { data: isAllReplyShown } = useIsAllReplyShown();
 
   const [isOlderRepliesShown, setIsOlderRepliesShown] = useState(false);
@@ -27,12 +35,15 @@ export const ReplayComments = (props: ReplaycommentsProps): JSX.Element => {
   const renderReply = (reply: ICommentHasId) => {
     return (
       <div key={reply._id} className="page-comment-reply ml-4 ml-sm-5 mr-3">
-        {/* TODO: Update props */}
         <Comment
-          comment={reply}
+          rendererOptions={rendererOptions}
           deleteBtnClicked={deleteBtnClicked}
-          isReadOnly={isReadOnly}
+          comment={reply}
           onComment={onComment}
+          isReadOnly={isReadOnly}
+          currentPagePath={currentPagePath}
+          currentRevisionId={currentRevisionId}
+          currentRevisionCreatedAt={currentRevisionCreatedAt}
         />
       </div>
     );
@@ -49,11 +60,9 @@ export const ReplayComments = (props: ReplaycommentsProps): JSX.Element => {
   }
 
   const areThereHiddenReplies = (replyList.length > 2);
-
   const toggleButtonIconName = isOlderRepliesShown ? 'icon-arrow-up' : 'icon-options-vertical';
   const toggleButtonIcon = <i className={`icon-fw ${toggleButtonIconName}`}></i>;
   const toggleButtonLabel = isOlderRepliesShown ? '' : 'more';
-
   const shownReplies = replyList.slice(replyList.length - 2, replyList.length);
   const hiddenReplies = replyList.slice(0, replyList.length - 2);
 

+ 2 - 2
packages/app/src/interfaces/editor-settings.ts

@@ -32,7 +32,7 @@ export interface IEditorSettings {
 
 export type EditorConfig = {
   upload: {
-    image: boolean,
-    file: boolean,
+    isUploadableFile: boolean,
+    isUploadableImage: boolean,
   }
 }

+ 7 - 7
packages/app/src/pages/[[...path]].page.tsx

@@ -20,7 +20,6 @@ import superjson from 'superjson';
 import { PageAlerts } from '~/components/PageAlert/PageAlerts';
 import { PageComment } from '~/components/PageComment';
 // import { useTranslation } from '~/i18n';
-import CommentEditorLazyRenderer from '~/components/PageComment/CommentEditorLazyRenderer';
 import { PageContentFooter } from '~/components/PageContentFooter';
 import { CrowiRequest } from '~/interfaces/crowi-request';
 // import { renderScriptTagByName, renderHighlightJsStyleTag } from '~/service/cdn-resources-loader';
@@ -56,7 +55,6 @@ import DisplaySwitcher from '../components/Page/DisplaySwitcher';
 // import { serializeUserSecurely } from '../server/models/serializers/user-serializer';
 // import PageStatusAlert from '../client/js/components/PageStatusAlert';
 
-
 import {
   useCurrentUser, useCurrentPagePath,
   useIsLatestRevision,
@@ -67,7 +65,7 @@ import {
   useIsAclEnabled, useIsUserPage, useIsNotCreatable,
   useCsrfToken, useIsSearchScopeChildrenAsDefault, useCurrentPageId, useCurrentPathname,
   useIsSlackConfigured, useIsBlinkedHeaderAtBoot, useRendererConfig, useEditingMarkdown,
-  useEditorConfig, useIsAllReplyShown,
+  useEditorConfig, useIsAllReplyShown, useIsUploadableFile, useIsUploadableImage,
 } from '../stores/context';
 import { useXss } from '../stores/xss';
 
@@ -232,6 +230,9 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
   // useGrowiRendererConfig(props.growiRendererConfigStr != null ? JSON.parse(props.growiRendererConfigStr) : undefined);
   useIsAllReplyShown(props.isAllReplyShown);
 
+  useIsUploadableFile(props.editorConfig.upload.isUploadableFile);
+  useIsUploadableImage(props.editorConfig.upload.isUploadableImage);
+
   // const { data: editorMode } = useEditorMode();
 
   const { pageWithMeta, userUISettings } = props;
@@ -333,8 +334,7 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
         </div>
         <footer>
           {/* <PageComments /> */}
-          <PageComment pageId={useCurrentPageId().data} isReadOnly={false} titleAlign="left" />
-          {/* <CommentEditorLazyRenderer pageId={useCurrentPageId().data} /> */}
+          <PageComment pageId={pageId} isReadOnly={false} titleAlign="left" />
           <PageContentFooter />
         </footer>
 
@@ -500,8 +500,8 @@ function injectServerConfigurations(context: GetServerSidePropsContext, props: P
   props.disableLinkSharing = configManager.getConfig('crowi', 'security:disableLinkSharing');
   props.editorConfig = {
     upload: {
-      image: crowi.fileUploadService.getIsUploadable(),
-      file: crowi.fileUploadService.getFileUploadEnabled(),
+      isUploadableFile: crowi.fileUploadService.getFileUploadEnabled(),
+      isUploadableImage: crowi.fileUploadService.getIsUploadable(),
     },
   };
   // props.adminPreferredIndentSize = configManager.getConfig('markdown', 'markdown:adminPreferredIndentSize');