diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 741f3a56ab..74c8b10a29 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -37,7 +37,6 @@ "react-cookies": "^0.1.0", "react-dom": "17.0.0", "react-i18next": "12.1.1", - "react-mentions": "4.4.7", "react-responsive": "9.0.2", "react-select": "5.7.0", "react-transition-group": "4.4.5", @@ -21136,34 +21135,6 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, - "node_modules/react-mentions": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/react-mentions/-/react-mentions-4.4.7.tgz", - "integrity": "sha512-VNriu2h/uOB+RS0mwZgPG2Vf+UtdDvRh5zbXa2TNc1WqacKuNDgTdhlbo9LEOZRBxRzIeTUYQmYJ7p9M9rDHqQ==", - "dependencies": { - "@babel/runtime": "7.4.5", - "invariant": "^2.2.4", - "prop-types": "^15.5.8", - "substyle": "^9.1.0" - }, - "peerDependencies": { - "react": ">=16.8.3", - "react-dom": ">=16.8.3" - } - }, - "node_modules/react-mentions/node_modules/@babel/runtime": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz", - "integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==", - "dependencies": { - "regenerator-runtime": "^0.13.2" - } - }, - "node_modules/react-mentions/node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, "node_modules/react-modal": { "version": "3.16.1", "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.1.tgz", @@ -23633,18 +23604,6 @@ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" }, - "node_modules/substyle": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/substyle/-/substyle-9.4.1.tgz", - "integrity": "sha512-VOngeq/W1/UkxiGzeqVvDbGDPM8XgUyJVWjrqeh+GgKqspEPiLYndK+XRcsKUHM5Muz/++1ctJ1QCF/OqRiKWA==", - "dependencies": { - "@babel/runtime": "^7.3.4", - "invariant": "^2.2.4" - }, - "peerDependencies": { - "react": ">=16.8.3" - } - }, "node_modules/sucrase": { "version": "3.34.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", @@ -42384,32 +42343,6 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, - "react-mentions": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/react-mentions/-/react-mentions-4.4.7.tgz", - "integrity": "sha512-VNriu2h/uOB+RS0mwZgPG2Vf+UtdDvRh5zbXa2TNc1WqacKuNDgTdhlbo9LEOZRBxRzIeTUYQmYJ7p9M9rDHqQ==", - "requires": { - "@babel/runtime": "7.4.5", - "invariant": "^2.2.4", - "prop-types": "^15.5.8", - "substyle": "^9.1.0" - }, - "dependencies": { - "@babel/runtime": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz", - "integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==", - "requires": { - "regenerator-runtime": "^0.13.2" - } - }, - "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - } - } - }, "react-modal": { "version": "3.16.1", "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.1.tgz", @@ -44379,15 +44312,6 @@ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" }, - "substyle": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/substyle/-/substyle-9.4.1.tgz", - "integrity": "sha512-VOngeq/W1/UkxiGzeqVvDbGDPM8XgUyJVWjrqeh+GgKqspEPiLYndK+XRcsKUHM5Muz/++1ctJ1QCF/OqRiKWA==", - "requires": { - "@babel/runtime": "^7.3.4", - "invariant": "^2.2.4" - } - }, "sucrase": { "version": "3.34.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 3cc7ef29e2..2f8a9adbd9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -32,7 +32,6 @@ "react-cookies": "^0.1.0", "react-dom": "17.0.0", "react-i18next": "12.1.1", - "react-mentions": "4.4.7", "react-responsive": "9.0.2", "react-select": "5.7.0", "react-transition-group": "4.4.5", diff --git a/frontend/src/components/common/notice-item.js b/frontend/src/components/common/notice-item.js index 4406fe1305..ab349db123 100644 --- a/frontend/src/components/common/notice-item.js +++ b/frontend/src/components/common/notice-item.js @@ -15,8 +15,6 @@ const MSG_TYPE_REPO_SHARE = 'repo_share'; const MSG_TYPE_REPO_SHARE_TO_GROUP = 'repo_share_to_group'; const MSG_TYPE_REPO_TRANSFER = 'repo_transfer'; const MSG_TYPE_FILE_UPLOADED = 'file_uploaded'; -const MSG_TYPE_FILE_COMMENT = 'file_comment'; -const MSG_TYPE_DRAFT_COMMENT = 'draft_comment'; const MSG_TYPE_DRAFT_REVIEWER = 'draft_reviewer'; // const MSG_TYPE_GUEST_INVITATION_ACCEPTED = 'guest_invitation_accepted'; const MSG_TYPE_REPO_MONITOR = 'repo_monitor'; @@ -171,45 +169,6 @@ class NoticeItem extends React.Component { return {avatar_url, notice}; } - if (noticeType === MSG_TYPE_FILE_COMMENT) { - - let avatar_url = detail.author_avatar_url; - - let author = detail.author_name; - - let fileName = detail.file_name; - let fileUrl = siteRoot + 'lib/' + detail.repo_id + '/' + 'file' + detail.file_path; - - // 1. handle translate - let notice = gettext('File {file_link} has a new comment form user {author}.'); - - // 2. handle xss(cross-site scripting) - notice = notice.replace('{file_link}', `{tagA}${fileName}{/tagA}`); - notice = notice.replace('{author}', author); - notice = Utils.HTMLescape(notice); - - // 3. add jump link - notice = notice.replace('{tagA}', ``); - notice = notice.replace('{/tagA}', ''); - return {avatar_url, notice}; - } - - if (noticeType === MSG_TYPE_DRAFT_COMMENT) { - - let avatar_url = detail.author_avatar_url; - - let author = detail.author_name; - - let draftId = detail.draft_id; - let draftUrl = siteRoot + 'drafts/' + draftId + '/'; - - let notice = gettext('{draft_link} has a new comment from user {author}.'); - let draftLink = '' + gettext('Draft') + '#' + draftId + ''; - notice = notice.replace('{draft_link}', draftLink); - notice = notice.replace('{author}', author); - return {avatar_url, notice}; - } - if (noticeType === MSG_TYPE_DRAFT_REVIEWER) { let avatar_url = detail.request_user_avatat_url; diff --git a/frontend/src/components/dirent-detail/detail-comments-list.js b/frontend/src/components/dirent-detail/detail-comments-list.js deleted file mode 100644 index d829dbec86..0000000000 --- a/frontend/src/components/dirent-detail/detail-comments-list.js +++ /dev/null @@ -1,318 +0,0 @@ -import React, { Fragment } from 'react'; -import PropTypes from 'prop-types'; -import moment from 'moment'; -import { processor } from '@seafile/seafile-editor'; -import { Button, Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap'; -import { gettext, username } from '../../utils/constants'; -import { seafileAPI } from '../../utils/seafile-api'; -import { Utils } from '../../utils/utils'; -import toaster from '../toast'; -import { MentionsInput, Mention } from 'react-mentions'; -import { defaultStyle, defaultMentionStyle } from '../../css/react-mentions-default-style'; -import '../../css/comments-list.css'; - -const DetailCommentListPropTypes = { - repoID: PropTypes.string.isRequired, - filePath: PropTypes.string.isRequired, - onParticipantsChange: PropTypes.func.isRequired, - fileParticipantList: PropTypes.array.isRequired, -}; - -class DetailCommentList extends React.Component { - - constructor(props) { - super(props); - this.state = { - commentsList: [], - relatedUsers: null, - comment: '', - }; - this.toBeAddedParticipant = []; - } - - componentDidMount() { - this.listComments(); - this.checkParticipant(); - this.listRepoRelatedUsers(); - } - - componentWillReceiveProps(nextProps) { - if (nextProps.filePath !== this.props.filePath) { - this.listComments(nextProps.filePath); - } - } - - handleCommentChange = (event) => { - this.setState({ comment: event.target.value }); - }; - - listComments = (filePath) => { - seafileAPI.listComments(this.props.repoID, (filePath || this.props.filePath)).then((res) => { - this.setState({ commentsList: res.data.comments }); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - }; - - addComment = () => { - const { repoID, filePath } = this.props; - if (!this.state.comment.trim()) return; - seafileAPI.postComment(repoID, filePath, this.state.comment.trim()).then(() => { - this.listComments(); - }).catch(err => { - toaster.danger(Utils.getErrorMsg(err)); - }); - this.setState({ comment: '' }); - }; - - onSubmit = () => { - this.addParticipant(username); - if (this.toBeAddedParticipant.length === 0) { - this.addComment(); - } else { - const { repoID, filePath } = this.props; - seafileAPI.addFileParticipants(repoID, filePath, this.toBeAddedParticipant).then((res) => { - this.props.onParticipantsChange(repoID, filePath); - this.toBeAddedParticipant = []; - this.addComment(); - }).catch((err) => { - toaster.danger(Utils.getErrorMsg(err)); - }); - } - }; - - resolveComment = (event) => { - const { repoID } = this.props; - seafileAPI.updateComment(repoID, event.target.id, 'true').then(() => { - this.listComments(); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - }; - - deleteComment = (event) => { - const { repoID } = this.props; - seafileAPI.deleteComment(repoID, event.target.id).then(() => { - this.listComments(); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - }; - - editComment = (commentID, newComment) => { - const { repoID } = this.props; - seafileAPI.updateComment(repoID, commentID, null, null, newComment).then(() => { - this.listComments(); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - }; - - listRepoRelatedUsers = () => { - const { repoID } = this.props; - seafileAPI.listRepoRelatedUsers(repoID).then((res) => { - let users = res.data.user_list.map((item) => { - return { id: item.email, display: item.name}; - }); - this.setState({ relatedUsers: users }); - }); - }; - - checkParticipant = (email) => { - return this.props.fileParticipantList.map((participant) => {return participant.email;}).includes(email); - }; - - addParticipant = (email) => { - if (this.checkParticipant(email)) return; - this.toBeAddedParticipant.push(email); - }; - - renderUserSuggestion = (entry, search, highlightedDisplay, index, focused) => { - return
{highlightedDisplay}
; - }; - - render() { - const { commentsList } = this.state; - return ( -
-
- {commentsList.length > 0 ? ( - ) : -

{gettext('No comment yet.')}

- } -
-
- - `@${display}`} - data={this.state.relatedUsers} - renderSuggestion={this.renderUserSuggestion} - style={defaultMentionStyle} - onAdd={(id, display) => {this.addParticipant(id);}} - appendSpaceOnAdd={true} - /> - -
- -
-
-
- ); - } -} - -DetailCommentList.propTypes = DetailCommentListPropTypes; - -const commentItemPropTypes = { - time: PropTypes.string.isRequired, - item: PropTypes.object.isRequired, - deleteComment: PropTypes.func.isRequired, - resolveComment: PropTypes.func.isRequired, - editComment: PropTypes.func.isRequired, -}; - -class CommentItem extends React.Component { - - constructor(props) { - super(props); - this.state = { - dropdownOpen: false, - html: '', - newComment: this.props.item.comment, - editable: false, - }; - } - - componentWillMount() { - this.convertComment(this.props.item.comment); - } - - componentWillReceiveProps(nextProps) { - this.convertComment(nextProps.item.comment); - } - - convertComment = (mdFile) => { - processor.process(mdFile).then((result) => { - let html = String(result); - this.setState({ html: html }); - }); - }; - - toggleDropDownMenu = () => { - this.setState({ dropdownOpen: !this.state.dropdownOpen }); - }; - - toggleEditComment = () => { - this.setState({ editable: !this.state.editable }); - }; - - updateComment = (event) => { - const newComment = this.state.newComment; - if (this.props.item.comment !== newComment) { - this.props.editComment(event.target.id, newComment); - } - this.toggleEditComment(); - }; - - handleCommentChange = (event) => { - this.setState({ newComment: event.target.value }); - }; - - onCommentClick = (e) => { - // click participant link, page shouldn't jump - if (e.target.nodeName !== 'A') return; - const preNode = e.target.previousSibling; - if (preNode && preNode.nodeType === 3 && preNode.nodeValue.slice(-1) === '@') { - e.preventDefault(); - } - }; - - renderInfo = (item) => { - return ( - - -
-
{item.user_name}
-
{this.props.time}
-
-
- ); - }; - - render() { - const item = this.props.item; - if (this.state.editable) { - return( -
  • -
    - {this.renderInfo(item)} -
    -
    - - {' '} - -
    -
  • - ); - } - return ( -
  • -
    - {this.renderInfo(item)} - - - - {item.user_email === username && - {gettext('Delete')} - } - {item.user_email === username && - {gettext('Edit')} - } - {!item.resolved && - {gettext('Mark as resolved')} - } - - -
    -
    this.onCommentClick(e)} - >
    -
  • - ); - } -} - -CommentItem.propTypes = commentItemPropTypes; - -export default DetailCommentList; diff --git a/frontend/src/components/dirent-detail/dirent-details.js b/frontend/src/components/dirent-detail/dirent-details.js index 5fb8995b51..3fa2cbc372 100644 --- a/frontend/src/components/dirent-detail/dirent-details.js +++ b/frontend/src/components/dirent-detail/dirent-details.js @@ -1,8 +1,5 @@ -import React, { Fragment } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; -import classnames from 'classnames'; -import { Nav, NavItem, NavLink, TabContent, TabPane } from 'reactstrap'; -import DetailCommentList from './detail-comments-list'; import { siteRoot, enableVideoThumbnail } from '../../utils/constants'; import { seafileAPI } from '../../utils/seafile-api'; import { Utils } from '../../utils/utils'; @@ -31,7 +28,6 @@ class DirentDetail extends React.Component { direntType: '', direntDetail: '', folderDirent: null, - activeTab: 'info', fileParticipantList: [], }; } @@ -118,33 +114,6 @@ class DirentDetail extends React.Component { this.listParticipants(repoID, filePath); }; - tabItemClick = (tab) => { - if (this.state.activeTab !== tab) { - this.setState({ activeTab: tab }); - } - }; - - renderNavItem = (showTab) => { - switch(showTab) { - case 'info': - return ( - - { this.tabItemClick('info');}}> - - - - ); - case 'comments': - return ( - - {this.tabItemClick('comments');}}> - - - - ); - } - }; - renderHeader = (smallIconUrl, direntName) => { return (
    @@ -160,25 +129,23 @@ class DirentDetail extends React.Component { renderDetailBody = (bigIconUrl, folderDirent) => { const { dirent, fileTags } = this.props; return ( - -
    -
    - {this.state.direntDetail && -
    - -
    - } -
    -
    +
    +
    + {this.state.direntDetail && +
    + +
    + } +
    ); }; @@ -196,33 +163,12 @@ class DirentDetail extends React.Component { bigIconUrl = `${siteRoot}thumbnail/${repoID}/1024` + Utils.encodePath(`${path === '/' ? '' : path}/${dirent.name}`); } let direntName = dirent ? dirent.name : folderDirent.name; - - if ((dirent && dirent.type === 'file') || path.lastIndexOf('.') > -1) { - return ( -
    - {this.renderHeader(smallIconUrl, direntName)} - - - {this.renderDetailBody(bigIconUrl, folderDirent)} - - - - -
    - ); - } else { - return ( -
    - {this.renderHeader(smallIconUrl, direntName)} - {this.renderDetailBody(bigIconUrl, folderDirent)} -
    - ); - } + return ( +
    + {this.renderHeader(smallIconUrl, direntName)} + {this.renderDetailBody(bigIconUrl, folderDirent)} +
    + ); } } diff --git a/frontend/src/components/dirent-grid-view/dirent-grid-view.js b/frontend/src/components/dirent-grid-view/dirent-grid-view.js index c9be322c9b..7a0c19bfb5 100644 --- a/frontend/src/components/dirent-grid-view/dirent-grid-view.js +++ b/frontend/src/components/dirent-grid-view/dirent-grid-view.js @@ -166,9 +166,6 @@ class DirentGridView extends React.Component { case 'Unmark as draft': this.onUnmarkAsDraft(currentObject); break; - case 'Comment': - this.onCommentItem(); - break; case 'History': this.onHistory(currentObject); break; @@ -303,10 +300,6 @@ class DirentGridView extends React.Component { }); }; - onCommentItem = () => { - this.props.showDirentDetail('comments'); - }; - onHistory = (currentObject) => { let repoID = this.props.repoID; let filePath = this.getDirentPath(currentObject); diff --git a/frontend/src/components/dirent-list-view/dirent-list-item.js b/frontend/src/components/dirent-list-view/dirent-list-item.js index f7dba7e5d0..9042105489 100644 --- a/frontend/src/components/dirent-list-view/dirent-list-item.js +++ b/frontend/src/components/dirent-list-view/dirent-list-item.js @@ -281,10 +281,6 @@ class DirentListItem extends React.Component { case 'Unmark as draft': this.onUnmarkAsDraft(); break; - case 'Comment': - this.props.onDirentClick(this.props.dirent); - this.props.showDirentDetail('comments'); - break; case 'History': this.onHistory(); break; diff --git a/frontend/src/components/file-view/comment-panel.js b/frontend/src/components/file-view/comment-panel.js deleted file mode 100644 index 135c8440a6..0000000000 --- a/frontend/src/components/file-view/comment-panel.js +++ /dev/null @@ -1,355 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import moment from 'moment'; -import { processor } from '@seafile/seafile-editor'; -import { Button, Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap'; -import { gettext } from '../../utils/constants'; -import { seafileAPI } from '../../utils/seafile-api'; -import { Utils } from '../../utils/utils'; -import toaster from '../toast'; -import { MentionsInput, Mention } from 'react-mentions'; -import { defaultStyle, defaultMentionStyle } from '../../css/react-mentions-default-style'; - -import '../../css/comments-list.css'; - -const { username, repoID, filePath } = window.app.pageOptions; - -const CommentPanelPropTypes = { - toggleCommentPanel: PropTypes.func.isRequired, - commentsNumber: PropTypes.number, - participants: PropTypes.array, - onParticipantsChange: PropTypes.func, -}; - -class CommentPanel extends React.Component { - - constructor(props) { - super(props); - this.state = { - commentsList: [], - showResolvedComment: true, - participants: null, - relatedUsers: null, - comment: '', - }; - this.toBeAddedParticipant = []; - } - - listComments = () => { - seafileAPI.listComments(repoID, filePath).then((res) => { - this.setState({ - commentsList: res.data.comments - }); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - }; - - listRepoRelatedUsers = () => { - seafileAPI.listRepoRelatedUsers(repoID).then((res) => { - let users = res.data.user_list.map((item) => { - return { id: item.email, display: item.name}; - }); - this.setState({ relatedUsers: users }); - }); - }; - - handleCommentChange = (event) => { - this.setState({ comment: event.target.value }); - }; - - addComment = () => { - if (!this.state.comment.trim()) return; - seafileAPI.postComment(repoID, filePath, this.state.comment.trim()).then(() => { - this.listComments(); - }).catch(err => { - toaster.danger(Utils.getErrorMsg(err)); - }); - this.setState({ comment: '' }); - }; - - onSubmit = () => { - this.addParticipant(username); - if (this.toBeAddedParticipant.length === 0) { - this.addComment(); - } else { - seafileAPI.addFileParticipants(repoID, filePath, this.toBeAddedParticipant).then((res) => { - this.onParticipantsChange(repoID, filePath); - this.toBeAddedParticipant = []; - this.addComment(); - }).catch((err) => { - toaster.danger(Utils.getErrorMsg(err)); - }); - } - }; - - resolveComment = (event) => { - seafileAPI.updateComment(repoID, event.target.id, 'true').then(() => { - this.listComments(); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - }; - - deleteComment = (event) => { - seafileAPI.deleteComment(repoID, event.target.id).then(() => { - this.listComments(); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - }; - - editComment = (commentID, newComment) => { - seafileAPI.updateComment(repoID, commentID, null, null, newComment).then((res) => { - this.listComments(); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - }; - - onParticipantsChange = () => { - if (this.props.onParticipantsChange) { - this.props.onParticipantsChange(); - } else { - this.getParticipants(); - } - }; - - getParticipants = () => { - if (this.props.participants) { - this.setState({ participants: this.props.participants }); - } else { - seafileAPI.listFileParticipants(repoID, filePath).then((res) => { - this.setState({ participants: res.data.participant_list }); - }); - } - }; - - checkParticipant = (email) => { - return this.state.participants.map((participant) => {return participant.email;}).includes(email); - }; - - addParticipant = (email) => { - if (this.checkParticipant(email)) return; - this.toBeAddedParticipant.push(email); - }; - - renderUserSuggestion = (entry, search, highlightedDisplay, index, focused) => { - return
    {highlightedDisplay}
    ; - }; - - componentDidMount() { - this.listComments(); - this.getParticipants(); - this.listRepoRelatedUsers(); - } - - componentWillReceiveProps(nextProps) { - if (this.props.commentsNumber !== nextProps.commentsNumber) { - this.listComments(); - } - if (this.props.participants !== nextProps.participants) { - this.setState({ participants: nextProps.participants }); - } - } - - render() { - const { commentsList } = this.state; - return ( -
    -
    -
    - -
    -
    {gettext('Comments')}
    -
    -
    - {commentsList.length > 0 ? ( -
      - {commentsList.map((item, index = 0, arr) => { - let oldTime = (new Date(item.created_at)).getTime(); - let time = moment(oldTime).format('YYYY-MM-DD HH:mm'); - return ( - - ); - })} -
    ) : -

    {gettext('No comment yet.')}

    - } -
    -
    - - `@${display}`} - data={this.state.relatedUsers} - renderSuggestion={this.renderUserSuggestion} - style={defaultMentionStyle} - onAdd={(id, display) => {this.addParticipant(id);}} - appendSpaceOnAdd={true} - /> - -
    - -
    -
    -
    - ); - } -} - -CommentPanel.propTypes = CommentPanelPropTypes; - - -const commentItemPropTypes = { - time: PropTypes.string.isRequired, - item: PropTypes.object.isRequired, - deleteComment: PropTypes.func.isRequired, - resolveComment: PropTypes.func.isRequired, - showResolvedComment: PropTypes.bool.isRequired, - editComment: PropTypes.func.isRequired, -}; - -class CommentItem extends React.Component { - - constructor(props) { - super(props); - this.state = { - dropdownOpen: false, - html: '', - newComment: this.props.item.comment, - editable: false, - }; - } - - toggleDropDownMenu = () => { - this.setState({ - dropdownOpen: !this.state.dropdownOpen, - }); - }; - - convertComment = (mdFile) => { - processor.process(mdFile).then((result) => { - let html = String(result); - this.setState({ html: html }); - }); - }; - - toggleEditComment = () => { - this.setState({ - editable: !this.state.editable - }); - }; - - updateComment = (event) => { - const newComment = this.state.newComment; - if (this.props.item.comment !== newComment) { - this.props.editComment(event.target.id, newComment); - } - this.toggleEditComment(); - }; - - handleCommentChange = (event) => { - this.setState({ - newComment: event.target.value, - }); - }; - - onCommentClick = (e) => { - // click participant link, page shouldn't jump - if (e.target.nodeName !== 'A') return; - const preNode = e.target.previousSibling; - if (preNode && preNode.nodeType === 3 && preNode.nodeValue.slice(-1) === '@') { - e.preventDefault(); - } - }; - - componentWillMount() { - this.convertComment(this.props.item.comment); - } - - componentWillReceiveProps(nextProps) { - this.convertComment(nextProps.item.comment); - } - - render() { - const item = this.props.item; - if (item.resolved && !this.props.showResolvedComment) { - return null; - } - if (this.state.editable) { - return( -
  • -
    - -
    -
    {item.user_name}
    -
    {this.props.time}
    -
    -
    -
    - - {' '} - -
    -
  • - ); - } - return ( -
  • -
    - -
    -
    {item.user_name}
    -
    {this.props.time}
    -
    - - - - - - {(item.user_email === username) && - {gettext('Delete')}} - {(item.user_email === username) && - {gettext('Edit')} - } - {!item.resolved && - {gettext('Mark as resolved')} - } - - -
    -
    this.onCommentClick(e)} - >
    -
  • - ); - } -} - -CommentItem.propTypes = commentItemPropTypes; - -export default CommentPanel; diff --git a/frontend/src/components/file-view/file-toolbar.js b/frontend/src/components/file-view/file-toolbar.js index 17af52b69c..99f2a879c8 100644 --- a/frontend/src/components/file-view/file-toolbar.js +++ b/frontend/src/components/file-view/file-toolbar.js @@ -16,7 +16,6 @@ const propTypes = { isSaving: PropTypes.bool, needSave: PropTypes.bool, toggleLockFile: PropTypes.func.isRequired, - toggleCommentPanel: PropTypes.func.isRequired, toggleDetailsPanel: PropTypes.func.isRequired }; @@ -27,7 +26,7 @@ const { fileName, canEditFile, err, // fileEnc, // for 'edit', not undefined only for some kinds of files (e.g. text file) - canDownloadFile, enableComment + canDownloadFile, } = window.app.pageOptions; class FileToolbar extends React.Component { @@ -106,12 +105,10 @@ class FileToolbar extends React.Component { showShareBtn = true; } - let canComment = enableComment; const { isCustomPermission, customPermission } = this; if (isCustomPermission) { const { download_external_link } = customPermission.permission; showShareBtn = download_external_link; - canComment = false; } return ( @@ -196,11 +193,6 @@ class FileToolbar extends React.Component { - {canComment && ( - - {gettext('Comment')} - - )} {filePerm == 'rw' && ( {gettext('History')} @@ -264,11 +256,6 @@ class FileToolbar extends React.Component { )} - {canComment && ( - - {gettext('Comment')} - - )} {gettext('Details')} diff --git a/frontend/src/components/file-view/file-view.js b/frontend/src/components/file-view/file-view.js index 4a2ae05a1a..7267363290 100644 --- a/frontend/src/components/file-view/file-view.js +++ b/frontend/src/components/file-view/file-view.js @@ -7,7 +7,6 @@ import { Utils } from '../../utils/utils'; import toaster from '../toast'; import FileInfo from './file-info'; import FileToolbar from './file-toolbar'; -import CommentPanel from './comment-panel'; import FileDetails from '../dirent-detail/file-details'; import '../../css/file-view.css'; @@ -35,7 +34,6 @@ class FileView extends React.Component { isStarred: isStarred, isLocked: isLocked, lockedByMe: lockedByMe, - isCommentPanelOpen: false, isDetailsPanelOpen: false }; } @@ -44,12 +42,6 @@ class FileView extends React.Component { this.setState({isDetailsPanelOpen: !this.state.isDetailsPanelOpen}); }; - toggleCommentPanel = () => { - this.setState({ - isCommentPanelOpen: !this.state.isCommentPanelOpen - }); - }; - toggleStar = () => { if (this.state.isStarred) { seafileAPI.unstarItem(repoID, filePath).then((res) => { @@ -113,19 +105,11 @@ class FileView extends React.Component { isSaving={this.props.isSaving} needSave={this.props.needSave} toggleLockFile={this.toggleLockFile} - toggleCommentPanel={this.toggleCommentPanel} toggleDetailsPanel={this.toggleDetailsPanel} />
    {this.props.content} - {this.state.isCommentPanelOpen && - - } {isDetailsPanelOpen && { - let comment = event.target.value; - this.setState({ - comment: comment - }); - }; - - submitComment = () => { - let comment = this.state.comment.trim(); - if (comment.length > 0 && this.props.quote.length > 0) { - let detail = { - quote: this.props.quote, - position: this.props.commentPosition, - }; - let detailJSON = JSON.stringify(detail); - this.props.editorApi.postComment(comment, detailJSON).then((res) => { - this.props.onCommentAdded(); - }); - } - }; - - setQuoteText = (mdQuote) => { - processor.process(mdQuote).then( - (result) => { - let quote = String(result); - this.setState({ - quote: quote - }); - } - ); - }; - - componentDidMount() { - this.setQuoteText(this.props.quote); - } - - componentWillReceiveProps(nextProps) { - if (this.props.quote !== nextProps.quote) { - this.setQuoteText(nextProps.quote); - } - } - - render() { - return ( -
    -
    {this.props.editorApi.name}
    -
    -
    -
    - -
    - - -
    - -
    - ); - } -} - -CommentDialog.propTypes = propTypes; - -export default CommentDialog; diff --git a/frontend/src/components/review-list-view/review-comment-dialog.js b/frontend/src/components/review-list-view/review-comment-dialog.js deleted file mode 100644 index 97921678d7..0000000000 --- a/frontend/src/components/review-list-view/review-comment-dialog.js +++ /dev/null @@ -1,101 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { Button } from 'reactstrap'; -import { seafileAPI } from '../../utils/seafile-api'; -import { gettext, name, draftRepoID, draftFilePath } from '../../utils/constants'; -import { processor } from '../../utils/seafile-markdown2html'; -import { Utils } from '../../utils/utils'; -import toaster from '../toast'; - -import '../../css/review-comment-dialog.css'; - -const commentDialogPropTypes = { - onCommentAdded: PropTypes.func.isRequired, - toggleCommentDialog: PropTypes.func.isRequired, - quote: PropTypes.string, - newIndex: PropTypes.number, - oldIndex: PropTypes.number, -}; - -class ReviewCommentDialog extends React.Component { - - constructor(props) { - super(props); - this.state = { - comment: '', - quote: '', - }; - } - - handleCommentChange = (event) => { - let comment = event.target.value; - this.setState({ comment: comment }); - }; - - submitComment = () => { - const { quote, newIndex, oldIndex } = this.props; - const comment = this.state.comment.trim(); - if (comment.length === 0) return; - if (quote.length > 0) { - let detail = { - quote: quote, - newIndex: newIndex, - oldIndex: oldIndex - }; - seafileAPI.postComment(draftRepoID, draftFilePath, comment, JSON.stringify(detail)).then(() => { - this.props.onCommentAdded(); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - } else { - seafileAPI.postComment(draftRepoID, draftFilePath, comment).then(() => { - this.props.onCommentAdded(); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - } - this.setState({ comment: '' }); - }; - - setQuoteText = (mdQuote) => { - processor.process(mdQuote).then( - (result) => { - let quote = String(result); - this.setState({ quote: quote }); - } - ); - }; - - componentDidMount() { - this.setQuoteText(this.props.quote); - } - - componentWillReceiveProps(nextProps) { - if (this.props.quote !== nextProps.quote) { - this.setQuoteText(nextProps.quote); - } - } - - render() { - return ( -
    -
    {name}
    -
    -
    -
    - -
    - - -
    - -
    - ); - } -} - -ReviewCommentDialog.propTypes = commentDialogPropTypes; - -export default ReviewCommentDialog; diff --git a/frontend/src/components/review-list-view/review-comments.js b/frontend/src/components/review-list-view/review-comments.js deleted file mode 100644 index 7b82d95438..0000000000 --- a/frontend/src/components/review-list-view/review-comments.js +++ /dev/null @@ -1,266 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { processor } from '../../utils/seafile-markdown2html'; -import { Button, Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap'; -import { seafileAPI } from '../../utils/seafile-api'; -import { gettext, draftFilePath, draftRepoID } from '../../utils/constants'; -import { username } from '../../utils/constants'; -import { Utils } from '../../utils/utils'; -import toaster from '../toast'; - -import '../../css/comments-list.css'; - -const commentPropTypes = { - listComments: PropTypes.func.isRequired, - commentsList: PropTypes.array.isRequired, - scrollToQuote: PropTypes.func.isRequired -}; - -class ReviewComments extends React.Component { - - constructor(props) { - super(props); - this.state = { - showResolvedComment: true, - comment: '', - }; - } - - handleCommentChange = (event) => { - this.setState({ comment: event.target.value }); - }; - - submitComment = () => { - let comment = this.state.comment.trim(); - if (comment.length > 0) { - seafileAPI.postComment(draftRepoID, draftFilePath, comment).then(() => { - this.props.listComments(); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - this.setState({ comment: '' }); - } - }; - - resolveComment = (event) => { - seafileAPI.updateComment(draftRepoID, event.target.id, 'true').then((res) => { - this.props.listComments(); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - }; - - editComment = (commentID, newComment) => { - seafileAPI.updateComment(draftRepoID, commentID, null, null, newComment).then((res) => { - this.props.listComments(); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - }; - - deleteComment = (event) => { - seafileAPI.deleteComment(draftRepoID, event.target.id).then((res) => { - this.props.listComments(); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - }; - - scrollToQuote = (newIndex, oldIndex, quote) => { - this.props.scrollToQuote(newIndex, oldIndex, quote); - this.setState({ comment: '' }); - }; - - componentWillReceiveProps(nextProps) { - if (this.props.commentsList.length < nextProps.commentsList.length) { - let that = this; - setTimeout(() => { - that.refs.commentsList.scrollTo(0, 10000); - }, 100); - } - } - - render() { - const { commentsList } = this.props; - return ( -
    -
    - {commentsList.length > 0 ? ( -
      - {commentsList.map((item, index) => { - return ( - - ); - })} -
    - ) : -

    {gettext('No comment yet.')}

    - } -
    -
    - -
    - -
    -
    -
    - ); - } -} - -ReviewComments.propTypes = commentPropTypes; - -const commentItemPropTypes = { - item: PropTypes.object.isRequired, - deleteComment: PropTypes.func.isRequired, - resolveComment: PropTypes.func.isRequired, - editComment: PropTypes.func.isRequired, - showResolvedComment: PropTypes.bool.isRequired, - scrollToQuote: PropTypes.func.isRequired -}; - -class CommentItem extends React.Component { - - constructor(props) { - super(props); - this.state = { - dropdownOpen: false, - comment: '', - quote: '', - newComment: this.props.item.comment, - editable: false, - }; - } - - toggleDropDownMenu = () => { - this.setState({ dropdownOpen: !this.state.dropdownOpen }); - }; - - convertComment = (item) => { - processor.process(item.comment).then((result) => { - let comment = String(result); - this.setState({ comment: comment }); - }); - processor.process(item.quote).then((result) => { - let quote = String(result); - this.setState({ quote: quote }); - }); - }; - - scrollToQuote = () => { - const item = this.props.item; - this.props.scrollToQuote(item.newIndex, item.oldIndex, item.quote); - }; - - toggleEditComment = () => { - this.setState({ editable: !this.state.editable }); - }; - - updateComment = (event) => { - const newComment = this.state.newComment; - if (this.props.item.comment !== newComment) { - this.props.editComment(event.target.id, newComment); - } - this.toggleEditComment(); - }; - - handleCommentChange = (event) => { - this.setState({ newComment: event.target.value }); - }; - - componentWillMount() { - this.convertComment(this.props.item); - } - - componentWillReceiveProps(nextProps) { - this.convertComment(nextProps.item); - } - - render() { - const item = this.props.item; - if (item.resolved && !this.props.showResolvedComment) return null; - if (this.state.editable) { - return( -
  • -
    - -
    -
    {item.name}
    -
    {item.time}
    -
    -
    -
    - - {' '} - -
    -
  • - ); - } - return ( -
  • -
    - -
    -
    {item.name}
    -
    {item.time}
    -
    - {!item.resolved && - - - - - - {(item.userEmail === username) && - {gettext('Delete')}} - {(item.userEmail === username) && - {gettext('Edit')}} - {gettext('Mark as resolved')} - - - } -
    - {(item.newIndex >= -1 && item.oldIndex >= -1) && -
    -
    -
    - } -
    -
  • - ); - } -} - -CommentItem.propTypes = commentItemPropTypes; - -export default ReviewComments; diff --git a/frontend/src/components/toolbar/multiple-dir-operation-toolbar.js b/frontend/src/components/toolbar/multiple-dir-operation-toolbar.js index c741b86416..3d93c08011 100644 --- a/frontend/src/components/toolbar/multiple-dir-operation-toolbar.js +++ b/frontend/src/components/toolbar/multiple-dir-operation-toolbar.js @@ -159,10 +159,6 @@ class MultipleDirOperationToolbar extends React.Component { }); }; - onCommentItem = () => { - this.props.showDirentDetail('comments'); - }; - getDirentMenuList = (dirent) => { const isRepoOwner = this.props.isRepoOwner; const currentRepoInfo = this.props.currentRepoInfo; @@ -215,9 +211,6 @@ class MultipleDirOperationToolbar extends React.Component { case 'Unmark as draft': this.onUnmarkAsDraft(dirent); break; - case 'Comment': - this.onCommentItem(); - break; case 'History': this.onHistory(dirent); break; diff --git a/frontend/src/css/comments-list.css b/frontend/src/css/comments-list.css deleted file mode 100644 index 1aa59916d6..0000000000 --- a/frontend/src/css/comments-list.css +++ /dev/null @@ -1,132 +0,0 @@ -.seafile-comment { - background-color: #f5f5f5; - display: flex; - flex-direction: column; -} -.seafile-comment-title { - border-bottom: 1px solid #e5e5e5; - min-height: 3em; - line-height: 3em; - padding: 0 1em; - display: flex; - background-color: #fff; -} -.seafile-comment-title .seafile-comment-title-text { - width: 100%; - text-align: center; - font-weight: 700; -} -.seafile-comment-title .seafile-comment-title-close { - color: #b9b9b9; -} -.seafile-comment-title .seafile-comment-title-close:hover { - color: #888; -} -.seafile-comment-item { - padding: 15px 10px; - margin-bottom: 0; -} -.seafile-comment-item .seafile-comment-info { - padding-bottom: 0.5em; - height: 3em; - display: flex; - justify-content: flex-start; -} -.seafile-comment-item .seafile-comment-info .reviewer-info { - padding-left: 10px; - max-width: 75%; -} -.seafile-comment-item .seafile-comment-info .review-time { - font-size: 10px; - color: #777; -} -.seafile-comment-item .seafile-comment-info .seafile-comment-dropdown { - margin-left: auto; -} -.seafile-comment-item .seafile-comment-info .seafile-comment-dropdown button { - border: none; - box-shadow: none; - background-color: #fff; -} -.seafile-comment-item .seafile-comment-info .seafile-comment-dropdown .seafile-comment-dropdown-btn { - color: #999; - background-color: transparent; -} -.seafile-comment-item .seafile-comment-info .seafile-comment-dropdown:hover .seafile-comment-dropdown-btn { - color: #555; -} -.seafile-comment-item .seafile-comment-info .seafile-comment-dropdown button:hover, -.seafile-comment-item .seafile-comment-info .seafile-comment-dropdown button:focus { - border: none; - box-shadow: none; - background-color: #eee; -} -.seafile-comment-item .seafile-comment-content { - margin-left: 42px; - padding: 5px 10px; - border-radius: 4px; - background: #fff; -} -.seafile-comment-item .seafile-comment-content p { - word-break: break-all; - margin: 0; -} -.seafile-comment-item .seafile-comment-content ol, -.seafile-comment-item .seafile-comment-content ul, -.seafile-comment-item .seafile-comment-content li { - margin-left: 10px; -} -.seafile-comment-item .seafile-comment-content table, -.seafile-comment-item .seafile-comment-content th, -.seafile-comment-item .seafile-comment-content td { - border: 1px solid #333; -} -.seafile-comment-item-resolved { - background-color: #e6ffed; -} -.seafile-comment-footer { - padding: 10px; - border-top: 1px solid #e5e5e5; - display: flex; - flex-direction: column; -} -.seafile-comment-footer .add-comment-input, -.seafile-edit-comment .edit-comment-input { - border: 1px solid #e6e6dd; - padding: 5px; - width: 100%; - min-height: 90px; - border-radius: 5px; - background-color: #fff; -} - -.seafile-comment-footer .add-comment-input { - border-bottom: none; - border-radius: 5px 5px 0 0; -} -.seafile-comment-footer .add-comment-input:focus { - outline: none; -} -.seafile-comment-footer .comment-submit-container { - border: 1px solid #e6e6dd; - border-top: none; - border-radius: 0 0 5px 5px; - padding: 5px; - background: #fff; - text-align: right; - position: relative; -} -.seafile-comment-footer .comment-submit-container::before { - border-top: 1px solid #e6e6dd; - content: ''; - position: absolute; - left: 5px; - right: 5px; - top: 0; -} -.seafile-comment-footer .submit-comment { - height: 28px; -} -.seafile-edit-comment .comment-btn { - height: 28px; -} diff --git a/frontend/src/css/draft.css b/frontend/src/css/draft.css index c39d83062b..a7bbce3a81 100644 --- a/frontend/src/css/draft.css +++ b/frontend/src/css/draft.css @@ -59,12 +59,10 @@ display: flex; margin-right: 10px; } -.seafile-toggle-diff .custom-switch .custom-switch-indicator, -.seafile-comment-title-toggle .custom-switch .custom-switch-indicator { +.seafile-toggle-diff .custom-switch .custom-switch-indicator { border: 1px solid #e9ecef; } -.seafile-toggle-diff .custom-switch-input:checked ~ .custom-switch-indicator, -.seafile-comment-title-toggle .custom-switch-input:checked ~ .custom-switch-indicator { +.seafile-toggle-diff .custom-switch-input:checked ~ .custom-switch-indicator { background-color: #f19645; } @@ -143,35 +141,6 @@ background-color: #fff; } -.review-comment-btn { - position: absolute; - top: -1000px; - right: 0; - border: 1px solid rgba(0, 40, 100, 0.12); - box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); - border-radius: 3px; - background-color: #fff; - padding: 5px; -} -.review-comment-btn:hover { - cursor: pointer; - background-color: #eee; -} -.comments-number { - font-size: 12px; - width: 16px; - height: 16px; - border-radius: 8px; - text-align: center; - line-height: 16px; - font-weight: 600; - background-color: #f19645; - position: absolute; - top: 10%; - right: 30%; - color: #fff; -} - .review-side-panel-nav { margin: 0; } @@ -194,7 +163,6 @@ .review-side-panel .tab-content { height: calc(100% - 38px); } -.review-side-panel .tab-content .comments, .review-side-panel .tab-content .tab-pane { height: 100%; } diff --git a/frontend/src/css/markdown-viewer/comment-dialog.css b/frontend/src/css/markdown-viewer/comment-dialog.css deleted file mode 100644 index 36abd2604f..0000000000 --- a/frontend/src/css/markdown-viewer/comment-dialog.css +++ /dev/null @@ -1,45 +0,0 @@ -.comment-dialog { - width: 500px; - position: absolute; - top: 30%; - right: 0; - padding: 15px; - background-color: #fafafa; - border: 1px solid rgba(0,0,0,.2); - border-radius: .3rem; - box-shadow: 0 0 3px #ccc; - z-index: 1000; -} -.comment-dialog-triangle { - position: absolute; - left: -5px; - top: 50%; - transform: rotate(45deg); - border: 1px solid rgba(0,0,0,.2); - border-top: none; - border-right: none; - width: 10px; - height: 10px; - background-color: #fafafa; - box-shadow: -1px 1px #ccc; -} -.comment-dialog textarea { - width: 100%; - min-height: 100px; - max-height: 300px; - padding: 5px; - background-color: #fff; -} -.comment-dialog .button-group .btn { - margin-right: 10px; -} -.comment-dialog .comment-dialog-quote { - margin-top: 10px; - max-height: 6rem; - overflow: auto; - padding-left: 1rem; -} -.comment-dialog .comment-dialog-quote ul, -.comment-dialog .comment-dialog-quote ol { - padding-left: 1rem; -} diff --git a/frontend/src/css/markdown-viewer/markdown-editor.css b/frontend/src/css/markdown-viewer/markdown-editor.css index c42ed55a54..5ddaa0b8c7 100644 --- a/frontend/src/css/markdown-viewer/markdown-editor.css +++ b/frontend/src/css/markdown-viewer/markdown-editor.css @@ -37,9 +37,6 @@ margin: 20px 0px 20px 5%; max-width: calc(90% - 260px); } -.seafile-md-viewer-slate.comment-on { - max-width: calc(90% - 360px); -} .seafile-md-viewer-main { flex: auto; overflow: auto; @@ -102,44 +99,9 @@ width: 100%; height: 100%; } -.seafile-md-viewer .seafile-comment .add-comment-input, -.seafile-md-viewer .seafile-comment .edit-comment-input { - background-color: #fff; - width: 100%; -} .seafile-md-viewer-side-panel .seafile-history-side-panel { border-left: 1px solid #e6e6dd; } -.seafile-md-viewer .seafile-comment { - background-color: #fff; - min-height: 18.5em; - z-index: 3; - width: 380px; - height: 100%; - position: fixed; - right: 0; -} -.seafile-viewer-comment-btn { - position: absolute; - top: 0; - right: 5000px; - border: 1px solid rgba(0, 40, 100, 0.12); - box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); - border-radius: 3px; - background-color: #fff; - padding: 5px; -} -.seafile-viewer-comment-btn:hover { - cursor: pointer; - background-color: #eee; -} -.seafile-md-viewer .seafile-comment .seafile-comment-footer { - min-height: 230px; -} -.seafile-md-viewer .seafile-comment-toggle-resolved { - width: 100%; - z-index: 1; -} @media (max-width:991.8px) { .seafile-editor-outline { display: none; @@ -150,20 +112,6 @@ max-width: 100%; } } -.seafile-md-comment { - background-color: #fff; - position: absolute; - right: 1px; - height: calc(100% - 56px); - width: 30%; -} -.seafile-md-comment .seafile-comment { - height: 100%; - width: 100%; -} -.seafile-md-comment .seafile-comment .seafile-comment-toggle-resolved { - width: 100%; -} @media (max-width: 768px) { .sf-md-viewer-topbar-first { @@ -176,10 +124,6 @@ } } -.seafile-editor-side-panel .seafile-comment { - width: 100%; -} - /* toolbar */ .topbar-file-info { display: inline-block; diff --git a/frontend/src/css/react-mentions-default-style.js b/frontend/src/css/react-mentions-default-style.js deleted file mode 100644 index 9c8c5807ce..0000000000 --- a/frontend/src/css/react-mentions-default-style.js +++ /dev/null @@ -1,81 +0,0 @@ -const defaultStyle = { - control: { - backgroundColor: '#fff', - fontSize: 14, - fontWeight: 'normal', - }, - highlighter: { - overflow: 'hidden', - }, - input: { - margin: 0, - }, - '&singleLine': { - control: { - display: 'inline-block', - width: 130, - }, - highlighter: { - padding: 1, - border: '2px inset transparent', - }, - input: { - padding: 1, - border: '2px inset', - }, - }, - '&multiLine': { - control: { - }, - highlighter: { - padding: 9, - }, - input: { - padding: '8px 6px', - minHeight: 90, - height: 90, - border: '1px solid #e6e6dd', - borderBottom: 'none', - borderRadius: '5px 5px 0 0', - overfflowY: 'auto', - outline: 'none', - '&focused': { - /* - backgroundColor: '#cee4e5', - outlineOffset: '-2px', - outlineColor: '-webkit-focus-ring-color', - outlineStyle: 'auto', - outlineWidth: '5px', - */ - }, - }, - }, - suggestions: { - list: { - backgroundColor: 'white', - border: '1px solid rgba(0,0,0,0.15)', - fontSize: 14, - maxHeight: 200, - overflow: 'auto', - position: 'absolute', - bottom: 14, - width: '150px', - }, - item: { - width: 'auto', - padding: '5px 15px', - overflowX: 'auto', - borderBottom: '1px solid rgba(0,0,0,0.15)', - '&focused': { - backgroundColor: '#f19654', - color: '#fff', - fontWeight: '400', - }, - }, - }, -}; - -const defaultMentionStyle = { -}; - -export { defaultStyle, defaultMentionStyle }; diff --git a/frontend/src/css/review-comment-dialog.css b/frontend/src/css/review-comment-dialog.css deleted file mode 100644 index d8955ef566..0000000000 --- a/frontend/src/css/review-comment-dialog.css +++ /dev/null @@ -1,44 +0,0 @@ -.review-comment-dialog { - width: 500px; - position: absolute; - top: 30%; - right: 0; - padding: 15px; - background-color: #fafafa; - border: 1px solid rgba(0,0,0,.2); - border-radius: .3rem; - box-shadow: 0 0 3px #ccc; - z-index: 1000; -} -.review-comment-dialog-triangle { - position: absolute; - left: -5px; - top: 50%; - transform: rotate(45deg); - border: 1px solid rgba(0,0,0,.2); - border-top: none; - border-right: none; - width: 10px; - height: 10px; - background-color: #fafafa; - box-shadow: -1px 1px #ccc; -} -.review-comment-dialog textarea { - width: 100%; - min-height: 100px; - max-height: 300px; - padding: 5px; -} -.review-comment-dialog .button-group .btn { - margin-right: 10px; -} -.review-comment-dialog .review-comment-dialog-quote { - margin-top: 10px; - max-height: 6rem; - overflow: auto; - padding-left: 1rem; -} -.review-comment-dialog .review-comment-dialog-quote ul, -.review-comment-dialog .review-comment-dialog-quote ol { - padding-left: 1rem; -} diff --git a/frontend/src/draft.js b/frontend/src/draft.js index fd1b35d132..2e98d97d46 100644 --- a/frontend/src/draft.js +++ b/frontend/src/draft.js @@ -1,25 +1,19 @@ import React from 'react'; import ReactDom from 'react-dom'; import PropTypes from 'prop-types'; -import { Button } from 'reactstrap'; +import axios from 'axios'; +import classnames from 'classnames'; +import { Button, Tooltip, Nav, NavItem, NavLink, TabContent, TabPane } from 'reactstrap'; /* eslint-disable */ import Prism from 'prismjs'; /* eslint-enable */ -import { ReactEditor, DiffViewer, serialize } from '@seafile/seafile-editor'; +import { ReactEditor, DiffViewer } from '@seafile/seafile-editor'; import { siteRoot, gettext, draftOriginFilePath, draftFilePath, author, authorAvatar, originFileExists, draftFileExists, draftID, draftFileName, draftRepoID, draftStatus, draftPublishVersion, originFileVersion, filePermission, serviceURL, mediaUrl } from './utils/constants'; import { seafileAPI } from './utils/seafile-api'; -import axios from 'axios'; import Loading from './components/loading'; -import ReviewComments from './components/review-list-view/review-comments'; -import ReviewCommentDialog from './components/review-list-view/review-comment-dialog'; -import { Tooltip } from 'reactstrap'; import AddReviewerDialog from './components/dialog/add-reviewer-dialog'; -import { Nav, NavItem, NavLink, TabContent, TabPane } from 'reactstrap'; -import classnames from 'classnames'; import HistoryList from './pages/review/history-list'; -import { Range, Editor } from 'slate'; import ModalPortal from './components/modal-portal'; -import reviewComment from './models/review-comment'; import './css/layout.css'; import './css/toolbar.css'; @@ -29,7 +23,7 @@ import './css/draft.css'; const URL = require('url-parse'); var moment = require('moment'); -const { toSlateRange: findRange, toDOMNode } = ReactEditor; +const { toDOMNode } = ReactEditor; class Draft extends React.Component { constructor(props) { @@ -42,10 +36,8 @@ class Draft extends React.Component { isShowDiff: true, showDiffTip: false, activeTab: 'reviewInfo', - commentsList: [], changedNodes: [], originRepoName: '', - isShowCommentDialog: false, activeItem: null, historyList: [], showReviewerDialog: false, @@ -195,34 +187,6 @@ class Draft extends React.Component { this.setState({historyList: historyList }); }; - listComments = () => { - seafileAPI.listComments(draftRepoID, draftFilePath).then((res) => { - let commentsList = []; - res.data.comments.forEach((item) => { - commentsList.push(new reviewComment(item)); - }); - this.setState({ commentsList: commentsList }); - }); - }; - - addComment = (e) => { - e.stopPropagation(); - this.getQuote(); - if (!this.quote) return; - this.setState({ isShowCommentDialog: true }); - }; - - onCommentAdded = () => { - this.listComments(); - this.toggleCommentDialog(); - }; - - toggleCommentDialog = () => { - this.setState({ - isShowCommentDialog: !this.state.isShowCommentDialog - }); - }; - getOriginRepoInfo = () => { seafileAPI.getRepoInfo(draftRepoID).then((res) => { this.setState({ originRepoName: res.data.repo_name }); @@ -303,28 +267,6 @@ class Draft extends React.Component { return scroller; }; - scrollToQuote = (newIndex, oldIndex, quote) => { - const nodes = this.refs.diffViewer.value; - let commentNode = nodes.find((node) => { - if (node.data['old_index'] == oldIndex && node.data['new_index'] == newIndex) { - return node; - } - return null; - }); - if (commentNode) { - const element = toDOMNode(window.viewer, commentNode); - if (!element) return; - const win = window; - const scroller = this.findScrollContainer(element, win); - const isWindow = scroller == win.document.body || scroller == win.document.documentElement; - if (isWindow) { - win.scrollTo(0, element.offsetTop); - } else { - scroller.scrollTop = element.offsetTop; - } - } - }; - showDiffViewer = () => { return (
    @@ -342,7 +284,6 @@ class Draft extends React.Component { ref="diffViewer" /> } -
    ); }; @@ -468,7 +409,6 @@ class Draft extends React.Component { }; showNavItem = (showTab) => { - const commentsNumber = this.state.commentsList.length; switch(showTab) { case 'info': return ( @@ -481,18 +421,6 @@ class Draft extends React.Component { ); - case 'comments': - return ( - - {this.tabItemClick('comments');}} - > - - {commentsNumber > 0 &&
    {commentsNumber}
    } -
    -
    - ); case 'history': return ( @@ -507,69 +435,11 @@ class Draft extends React.Component { } }; - getDomNodeByPath = (path) => { - let node, parent = document.querySelector('.viewer-component'); - while(typeof path[0] === 'number' && parent) { - node = parent.children[path[0]]; - if (!node.getAttribute('data-slate-node')) { - node = node.children[0]; - } - path.shift(); - parent = node; - } - return node; - }; - - setBtnPosition = () => { - const nativeSelection = window.getSelection(); - if (!nativeSelection.rangeCount) { - return; - } - const nativeRange = nativeSelection.getRangeAt(0); - let selection = null; - let style = this.refs.commentbtn.style; - try { - selection = findRange(window.viewer, nativeRange); - } catch (err) { - style.top = '-1000px'; - return; - } - if (!selection || Range.isCollapsed(selection)) { - style.top = '-1000px'; - return; - } - this.range = selection; - const focusNodePath = selection.anchor.path.slice(); - focusNodePath.pop(); - const focusNode = this.getDomNodeByPath(focusNodePath); - style.right = '0px'; - - if (focusNode) { - style.top = `${focusNode.offsetTop}px`; - } else { - style.top = '-1000px'; - } - }; - - getQuote = () => { - if (!this.range) return; - this.quote = serialize(Editor.fragment(window.viewer, this.range)); - const node = window.viewer.children[this.range.anchor.path[0]]; - this.newIndex = node.data['new_index']; - this.oldIndex = node.data['old_index']; - }; - componentDidMount() { this.getOriginRepoInfo(); this.getDraftInfo(); this.listReviewers(); - this.listComments(); this.initialContent(); - document.addEventListener('selectionchange', this.setBtnPosition); - } - - componentWillUnmount() { - document.removeEventListener('selectionchange', this.setBtnPosition); } renderDiffButton = () => { @@ -601,7 +471,6 @@ class Draft extends React.Component { return ( ); @@ -616,7 +485,6 @@ class Draft extends React.Component { return ( ); } @@ -706,7 +574,6 @@ class Draft extends React.Component { reviewers={reviewers} toggleAddReviewerDialog={this.toggleAddReviewerDialog}/> - {draftFileExists && } {(this.state.isShowDiff === true && this.state.changedNodes.length > 0) &&
    - - - } - {this.state.isShowCommentDialog && - - - - } ); } @@ -854,41 +702,6 @@ const SidePanelOriginPropTypes = { SidePanelOrigin.propTypes = SidePanelOriginPropTypes; - -class UnresolvedComments extends React.Component { - - constructor(props) { - super(props); - } - - render() { - const { commentsList } = this.props; - let unresolvedNumber = 0; - if (commentsList) { - for (let i = 0, count = commentsList.length; i < count; i++) { - if (commentsList[i].resolved === false) { - unresolvedNumber++; - } - } - } - return ( -
    -
    {gettext('Comments')}
    -
    - {gettext('Unresolved comments:')}{' '}{unresolvedNumber} -
    -
    - ); - } -} - -const UnresolvedCommentsPropTypes = { - commentsList: PropTypes.array.isRequired, -}; - -UnresolvedComments.propTypes = UnresolvedCommentsPropTypes; - - class SidePanelChanges extends React.Component { constructor(props) { diff --git a/frontend/src/models/review-comment.js b/frontend/src/models/review-comment.js deleted file mode 100644 index fc5447f67e..0000000000 --- a/frontend/src/models/review-comment.js +++ /dev/null @@ -1,24 +0,0 @@ -import moment from 'moment'; - -class reviewComment { - - constructor(item) { - let oldTime = (new Date(item.created_at)).getTime(); - this.time = moment(oldTime).format('YYYY-MM-DD HH:mm'); - this.id = item.id; - this.avatarUrl = item.avatar_url; - this.comment = item.comment; - this.name = item.user_name; - this.userEmail = item.user_email; - this.resolved = item.resolved; - if (item.detail) { - let detail = JSON.parse(item.detail); - this.newIndex = detail.newIndex; - this.oldIndex = detail.oldIndex; - this.quote = detail.quote; - } - } - -} - -export default reviewComment; diff --git a/frontend/src/pages/markdown-editor/css/comments-list.css b/frontend/src/pages/markdown-editor/css/comments-list.css deleted file mode 100644 index ef0b796cae..0000000000 --- a/frontend/src/pages/markdown-editor/css/comments-list.css +++ /dev/null @@ -1,136 +0,0 @@ -.seafile-comment { - display: flex; - flex-direction: column; - height: 100%; -} -.seafile-comment-list .comment-vacant { - padding: 1em; - text-align: center; -} -.seafile-comment-item { - padding: 15px 10px; - margin-bottom: 0; -} -.seafile-comment-item .seafile-comment-info { - padding-bottom: 0.5em; - height: 3em; - display: flex; - justify-content: flex-start; -} -.seafile-comment-item .seafile-comment-info .reviewer-info { - padding-left: 10px; - max-width: 75%; -} -.seafile-comment-item .seafile-comment-info .review-time { - font-size: 10px; - color: #777; -} -.seafile-comment-item .seafile-comment-info .seafile-comment-dropdown { - margin-left: auto; -} -.seafile-comment-item .seafile-comment-info .seafile-comment-dropdown button { - border: none; - box-shadow: none; - background-color: #fff; -} -.seafile-comment-item .seafile-comment-info .seafile-comment-dropdown .seafile-comment-dropdown-btn { - color: #999; - background-color: transparent; -} -.seafile-comment-item .seafile-comment-info .seafile-comment-dropdown:hover .seafile-comment-dropdown-btn { - color: #555; -} -.seafile-comment-item .seafile-comment-info .seafile-comment-dropdown button:hover, -.seafile-comment-item .seafile-comment-info .seafile-comment-dropdown button:focus { - border: none; - box-shadow: none; - background-color: #eee; -} -.seafile-comment-item .seafile-comment-content { - margin-left: 42px; - padding: 5px 10px; - border-radius: 4px; - background: #fff; -} -.seafile-comment-item .seafile-comment-content p { - word-break: break-all; -} -.seafile-comment-item blockquote { - cursor: pointer; -} -.seafile-comment-item .seafile-comment-content ol, -.seafile-comment-item .seafile-comment-content ul, -.seafile-comment-item .seafile-comment-content li { - margin-left: 10px; -} -.seafile-comment-item .seafile-comment-content table, -.seafile-comment-item .seafile-comment-content th, -.seafile-comment-item .seafile-comment-content td { - border: 1px solid #333; -} -.seafile-comment-item-resolved { - background-color: #e6ffed; -} -.seafile-comment-footer { - padding: 10px 10px; - border-top: 1px solid #e5e5e5; - display: flex; - flex-direction: column; - min-height: 150px; - max-height: 300px; -} -.seafile-comment-footer .add-comment-input, -.seafile-edit-comment .edit-comment-input { - border: 1px solid #e6e6dd; - padding: 5px; - min-height: 90px; - border-radius: 5px; - background-color: #fff; - width: 100%; -} -.seafile-comment-footer .add-comment-input { - border-bottom: none; - border-radius: 5px 5px 0 0; -} -.seafile-comment-footer .add-comment-input:focus { - outline: none; -} -.seafile-comment-footer .comment-submit-container { - border: 1px solid #e6e6dd; - border-top: none; - border-radius: 0 0 5px 5px; - padding: 5px; - background: #fff; - text-align: right; - position: relative; -} -.seafile-comment-footer .comment-submit-container::before { - border-top: 1px solid #e6e6dd; - content: ''; - position: absolute; - left: 5px; - right: 5px; - top: 0; -} -.seafile-comment-footer .submit-comment { - height: 28px; -} -.seafile-edit-comment .comment-btn { - height: 28px; -} - -.seafile-viewer-comment-btn { - position: absolute; - top: 0; - right: 5000px; - border: 1px solid rgba(0, 40, 100, 0.12); - box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); - border-radius: 3px; - background-color: #fff; - padding: 5px; -} -.seafile-viewer-comment-btn:hover { - cursor: pointer; - background-color: #eee; -} - diff --git a/frontend/src/pages/markdown-editor/editor-api.js b/frontend/src/pages/markdown-editor/editor-api.js index 81464446b0..7864bf6872 100644 --- a/frontend/src/pages/markdown-editor/editor-api.js +++ b/frontend/src/pages/markdown-editor/editor-api.js @@ -157,26 +157,6 @@ class EditorApi { return seafileAPI.getFileRevision(repoID, commitID, filePath); } - getCommentsNumber() { - return seafileAPI.getCommentsNumber(this.repoID, filePath); - } - - postComment(comment, detail) { - return seafileAPI.postComment(this.repoID, this.filePath, comment, detail); - } - - listComments() { - return seafileAPI.listComments(this.repoID, this.filePath); - } - - updateComment(commentID, resolved, detail, newComment) { - return seafileAPI.updateComment(this.repoID, commentID, resolved, detail, newComment); - } - - deleteComment(commentID) { - return seafileAPI.deleteComment(this.repoID, commentID); - } - getUserAvatar(size) { return seafileAPI.getUserAvatar(userName, size); } diff --git a/frontend/src/pages/markdown-editor/rich-markdown-editor/comment-item.js b/frontend/src/pages/markdown-editor/rich-markdown-editor/comment-item.js deleted file mode 100644 index 45ea5cc9fa..0000000000 --- a/frontend/src/pages/markdown-editor/rich-markdown-editor/comment-item.js +++ /dev/null @@ -1,151 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { processor } from '@seafile/seafile-editor'; -import { Button, Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap'; -import { gettext } from '../../../utils/constants'; - -const userInfo = window.app.userInfo; -const username = userInfo.username; - -const commentItemPropTypes = { - time: PropTypes.string.isRequired, - item: PropTypes.object.isRequired, - deleteComment: PropTypes.func.isRequired, - resolveComment: PropTypes.func.isRequired, - showResolvedComment: PropTypes.bool.isRequired, - editComment: PropTypes.func.isRequired, - scrollToQuote: PropTypes.func.isRequired, -}; - -class CommentItem extends React.Component { - - constructor(props) { - super(props); - this.state = { - dropdownOpen: false, - html: '', - newComment: this.props.item.comment, - editable: false, - quote: '', - position: null, - }; - } - - toggleDropDownMenu = () => { - this.setState({dropdownOpen: !this.state.dropdownOpen}); - }; - - convertComment = (item) => { - processor.process(item.comment).then((result) => { - let html = String(result); - this.setState({ - html: html - }); - }); - if (item.detail) { - const detail = JSON.parse(item.detail); - processor.process(detail.quote).then((result) => { - let quote = String(result); - this.setState({ - quote: quote, - position: detail.position, - }); - }); - } - }; - - toggleEditComment = () => { - this.setState({editable: !this.state.editable}); - }; - - updateComment = (event) => { - const newComment = this.state.newComment; - if (this.props.item.comment !== newComment) { - this.props.editComment(event.target.id, newComment); - } - this.toggleEditComment(); - }; - - handleCommentChange = (event) => { - this.setState({newComment: event.target.value}); - }; - - onScrollToQuote = () => { - const { position } = this.state; - this.props.scrollToQuote(position); - }; - - componentWillMount() { - this.convertComment(this.props.item); - } - - componentWillReceiveProps(nextProps) { - this.convertComment(nextProps.item); - } - - render() { - const item = this.props.item; - if (item.resolved && !this.props.showResolvedComment) { - return null; - } - if (this.state.editable) { - return( -
  • -
    - -
    -
    {item.user_name}
    -
    {this.props.time}
    -
    -
    -
    - - {' '} - -
    -
  • - ); - } - return ( -
  • -
    - -
    -
    {item.user_name}
    -
    {this.props.time}
    -
    - - - - - - {(item.user_email === username) && - {gettext('Delete')}} - {(item.user_email === username) && - {gettext('Edit')} - } - {!item.resolved && - {gettext('Mark as resolved')} - } - - -
    - {item.detail && -
    -
    -
    - } -
    -
  • - ); - } -} - -CommentItem.propTypes = commentItemPropTypes; - -export default CommentItem; diff --git a/frontend/src/pages/markdown-editor/rich-markdown-editor/comment-panel.js b/frontend/src/pages/markdown-editor/rich-markdown-editor/comment-panel.js deleted file mode 100644 index e3ebf61040..0000000000 --- a/frontend/src/pages/markdown-editor/rich-markdown-editor/comment-panel.js +++ /dev/null @@ -1,231 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import moment from 'moment'; -import { Button } from 'reactstrap'; -import { MentionsInput, Mention } from 'react-mentions'; -import { EditorContext } from '@seafile/seafile-editor'; -import { gettext } from '../../../utils/constants'; -import { Utils } from '../../../utils/utils'; -import { seafileAPI } from '../../../utils/seafile-api'; -import toaster from '../../../components/toast'; -import CommentItem from './comment-item'; - -import { defaultStyle, defaultMentionStyle } from '../../../css/react-mentions-default-style'; - -import '../css/comments-list.css'; - -const { repoID, filePath } = window.app.pageOptions; -const userInfo = window.app.userInfo; -const username = userInfo.username; - -const CommentPanelPropTypes = { - relistComment: PropTypes.number, - participants: PropTypes.array, - onParticipantsChange: PropTypes.func, -}; - -class CommentPanel extends React.Component { - - constructor(props) { - super(props); - this.state = { - commentsList: [], - showResolvedComment: true, - participants: null, - relatedUsers: null, - comment: '', - }; - this.toBeAddedParticipant = []; - } - - listComments = (isScroll) => { - seafileAPI.listComments(repoID, filePath).then((res) => { - this.setState({commentsList: res.data.comments}); - if (isScroll) { - let that = this; - setTimeout(() => { - that.commentsListRef.scrollTo(0, 10000); - }, 100); - } - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - }; - - listRepoRelatedUsers = () => { - seafileAPI.listRepoRelatedUsers(repoID).then((res) => { - let users = res.data.user_list.map((item) => { - return { id: item.email, display: item.name}; - }); - this.setState({ relatedUsers: users }); - }); - }; - - handleCommentChange = (event) => { - this.setState({ comment: event.target.value }); - }; - - addComment = () => { - if (!this.state.comment.trim()) return; - seafileAPI.postComment(repoID, filePath, this.state.comment.trim()).then(() => { - this.listComments(true); - }).catch(err => { - toaster.danger(Utils.getErrorMsg(err)); - }); - this.setState({ comment: '' }); - }; - - onSubmit = () => { - this.addParticipant(username); - if (this.toBeAddedParticipant.length === 0) { - this.addComment(); - } else { - seafileAPI.addFileParticipants(repoID, filePath, this.toBeAddedParticipant).then((res) => { - this.onParticipantsChange(repoID, filePath); - this.toBeAddedParticipant = []; - this.addComment(); - }).catch((err) => { - toaster.danger(Utils.getErrorMsg(err)); - }); - } - }; - - resolveComment = (event) => { - seafileAPI.updateComment(repoID, event.target.id, 'true').then(() => { - this.listComments(); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - }; - - deleteComment = (event) => { - seafileAPI.deleteComment(repoID, event.target.id).then(() => { - this.listComments(); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - }; - - editComment = (commentID, newComment) => { - seafileAPI.updateComment(repoID, commentID, null, null, newComment).then((res) => { - this.listComments(); - }).catch(error => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - }; - - onParticipantsChange = () => { - if (this.props.onParticipantsChange) { - this.props.onParticipantsChange(); - } else { - this.getParticipants(); - } - }; - - getParticipants = () => { - if (this.props.participants) { - this.setState({ participants: this.props.participants }); - } else { - seafileAPI.listFileParticipants(repoID, filePath).then((res) => { - this.setState({ participants: res.data.participant_list }); - }); - } - }; - - checkParticipant = (email) => { - return this.state.participants.map((participant) => {return participant.email;}).includes(email); - }; - - addParticipant = (email) => { - if (this.checkParticipant(email)) return; - this.toBeAddedParticipant.push(email); - }; - - renderUserSuggestion = (entry, search, highlightedDisplay, index, focused) => { - return
    {highlightedDisplay}
    ; - }; - - componentDidMount() { - this.listComments(); - this.getParticipants(); - this.listRepoRelatedUsers(); - } - - componentWillReceiveProps(nextProps) { - if (this.props.relistComment !== nextProps.relistComment) { - this.listComments(true); - } - if (this.props.participants !== nextProps.participants) { - this.setState({ participants: nextProps.participants }); - } - } - - scrollToQuote = (path) => { - const editorRef = EditorContext.getEditorRef(); - editorRef.scrollToQuote(path); - }; - - setCommentsListRef = (ref) => { - this.commentsListRef = ref; - }; - - render() { - const { commentsList } = this.state; - return ( -
    -
    - {commentsList.length > 0 ? ( -
      - {commentsList.map((item, index = 0, arr) => { - let oldTime = (new Date(item.created_at)).getTime(); - let time = moment(oldTime).format('YYYY-MM-DD HH:mm'); - return ( - - ); - })} -
    ) : -

    {gettext('No comment yet.')}

    - } -
    -
    - - `@${display}`} - data={this.state.relatedUsers} - renderSuggestion={this.renderUserSuggestion} - style={defaultMentionStyle} - onAdd={(id, display) => {this.addParticipant(id);}} - appendSpaceOnAdd={true} - /> - -
    - -
    -
    -
    - ); - } -} - -CommentPanel.propTypes = CommentPanelPropTypes; - -export default CommentPanel; diff --git a/frontend/src/pages/markdown-editor/rich-markdown-editor/index.js b/frontend/src/pages/markdown-editor/rich-markdown-editor/index.js index 44e6a1eafa..90fb0917ac 100644 --- a/frontend/src/pages/markdown-editor/rich-markdown-editor/index.js +++ b/frontend/src/pages/markdown-editor/rich-markdown-editor/index.js @@ -30,8 +30,6 @@ class RichMarkdownEditor extends React.Component { this.state = { isShowSidePanel: false, isShowHelpPanel: false, - isSupportComment: false, - relistComment: 0, }; window.richMarkdownEditor = this; } @@ -51,14 +49,6 @@ class RichMarkdownEditor extends React.Component { this.setState({isShowHelpPanel: false}); }; - toggleCommentBtn = (isSupport = false) => { - this.setState({isSupportComment: isSupport}); - }; - - onAddComment = () => { - this.setState({relistComment: this.state.relistComment + 1}); - }; - insertRepoFile = () => { if (this.props.readOnly) return; this.props.openDialogs && this.props.openDialogs('insert_file'); @@ -96,8 +86,8 @@ class RichMarkdownEditor extends React.Component { editorApi={this.props.editorApi} onChange={this.props.onChange} resetRichValue={this.props.resetRichValue} - isSupportComment={this.state.isSupportComment} - onAddComment={this.onAddComment} + isSupportComment={false} + onAddComment={() => {}} />
    @@ -105,12 +95,10 @@ class RichMarkdownEditor extends React.Component { )} {isShowHelpPanel && } diff --git a/frontend/src/pages/markdown-editor/rich-markdown-editor/side-panel.js b/frontend/src/pages/markdown-editor/rich-markdown-editor/side-panel.js index ee3e6804af..4d4dfb1406 100644 --- a/frontend/src/pages/markdown-editor/rich-markdown-editor/side-panel.js +++ b/frontend/src/pages/markdown-editor/rich-markdown-editor/side-panel.js @@ -3,19 +3,16 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Outline as OutlineView } from '@seafile/seafile-editor'; import DetailListView from './detail-list-view'; -import CommentPanel from './comment-panel'; import '../css/side-panel.css'; const propTypes = { document: PropTypes.array, fileInfo: PropTypes.object.isRequired, - relistComment: PropTypes.number, fileTagList: PropTypes.array, onFileTagChanged: PropTypes.func.isRequired, participants: PropTypes.array, onParticipantsChange: PropTypes.func.isRequired, - toggleCommentBtn: PropTypes.func.isRequired, }; class SidePanel extends React.PureComponent { @@ -26,30 +23,19 @@ class SidePanel extends React.PureComponent { onOutlineClick = (event) => { event.preventDefault(); - this.props.toggleCommentBtn(false); this.setState({navItem: 'outline'}); }; onDetailClick = (event) => { event.preventDefault(); - this.props.toggleCommentBtn(false); this.setState({navItem: 'detail'}); }; - onCommentsPanelClick = (event) => { - event.preventDefault(); - this.props.toggleCommentBtn(true); - this.setState({navItem: 'commentsPanel'}); - }; - render() { var outlineActive = ''; - var commentsPanel = ''; var detailList = ''; if (this.state.navItem === 'outline') { outlineActive = 'active'; - } else if (this.state.navItem === 'commentsPanel') { - commentsPanel = 'active'; } else if (this.state.navItem === 'detail') { detailList = 'active'; } @@ -63,23 +49,11 @@ class SidePanel extends React.PureComponent {
  • -
  • - - - -
  • {this.state.navItem === 'outline' && } - {this.state.navItem === 'commentsPanel' && - - } {this.state.navItem === 'detail' &&