mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-11 03:41:12 +00:00
[update] review info (#2940)
This commit is contained in:
@@ -6,6 +6,7 @@ import { seafileAPI } from '../../utils/seafile-api';
|
|||||||
import { reviewID, gettext } from '../../utils/constants';
|
import { reviewID, gettext } from '../../utils/constants';
|
||||||
import Loading from '../../components/loading.js';
|
import Loading from '../../components/loading.js';
|
||||||
import reviewComment from '../../models/review-comment.js';
|
import reviewComment from '../../models/review-comment.js';
|
||||||
|
import { username } from '../../utils/constants.js';
|
||||||
|
|
||||||
import '../../css/review-comments.css';
|
import '../../css/review-comments.css';
|
||||||
|
|
||||||
@@ -27,7 +28,6 @@ class ReviewComments extends React.Component {
|
|||||||
showResolvedComment: true,
|
showResolvedComment: true,
|
||||||
comment: '',
|
comment: '',
|
||||||
};
|
};
|
||||||
this.accountInfo = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
listComments = (scroll) => {
|
listComments = (scroll) => {
|
||||||
@@ -68,6 +68,7 @@ class ReviewComments extends React.Component {
|
|||||||
|
|
||||||
resolveComment = (event) => {
|
resolveComment = (event) => {
|
||||||
seafileAPI.updateReviewComment(reviewID, event.target.id, 'true').then((res) => {
|
seafileAPI.updateReviewComment(reviewID, event.target.id, 'true').then((res) => {
|
||||||
|
this.props.getCommentsNumber();
|
||||||
this.listComments();
|
this.listComments();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -172,7 +173,7 @@ class ReviewComments extends React.Component {
|
|||||||
this.state.commentsList.map((item, index) => {
|
this.state.commentsList.map((item, index) => {
|
||||||
return (
|
return (
|
||||||
<CommentItem item={item} showResolvedComment={this.state.showResolvedComment}
|
<CommentItem item={item} showResolvedComment={this.state.showResolvedComment}
|
||||||
resolveComment={this.resolveComment} accountInfo={this.accountInfo} key={index}
|
resolveComment={this.resolveComment} key={index}
|
||||||
scrollToQuote={this.scrollToQuote} deleteComment={this.deleteComment}/>
|
scrollToQuote={this.scrollToQuote} deleteComment={this.deleteComment}/>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@@ -202,7 +203,6 @@ const commentItemPropTypes = {
|
|||||||
item: PropTypes.object.isRequired,
|
item: PropTypes.object.isRequired,
|
||||||
deleteComment: PropTypes.func.isRequired,
|
deleteComment: PropTypes.func.isRequired,
|
||||||
resolveComment: PropTypes.func.isRequired,
|
resolveComment: PropTypes.func.isRequired,
|
||||||
accountInfo: PropTypes.object.isRequired,
|
|
||||||
showResolvedComment: PropTypes.bool.isRequired,
|
showResolvedComment: PropTypes.bool.isRequired,
|
||||||
scrollToQuote: PropTypes.func.isRequired
|
scrollToQuote: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
@@ -277,7 +277,7 @@ class CommentItem extends React.Component {
|
|||||||
<i className="fas fa-ellipsis-v"></i>
|
<i className="fas fa-ellipsis-v"></i>
|
||||||
</DropdownToggle>
|
</DropdownToggle>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
{ (item.userEmail === this.props.accountInfo.email) &&
|
{ (item.userEmail === username) &&
|
||||||
<DropdownItem onClick={this.props.deleteComment}
|
<DropdownItem onClick={this.props.deleteComment}
|
||||||
className="delete-comment" id={item.id}>{gettext('Delete')}</DropdownItem>}
|
className="delete-comment" id={item.id}>{gettext('Delete')}</DropdownItem>}
|
||||||
<DropdownItem onClick={this.props.resolveComment}
|
<DropdownItem onClick={this.props.resolveComment}
|
||||||
|
@@ -90,10 +90,16 @@
|
|||||||
.review-side-panel-body {
|
.review-side-panel-body {
|
||||||
padding: 1rem 2rem;
|
padding: 1rem 2rem;
|
||||||
}
|
}
|
||||||
|
.review-side-panel-body .dirent-table-container {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
.review-side-panel-item {
|
.review-side-panel-item {
|
||||||
border-bottom: 1px solid #e6e6dd;
|
border-bottom: 1px solid #e6e6dd;
|
||||||
padding: 1em 0;
|
padding: 1em 0;
|
||||||
}
|
}
|
||||||
|
.review-side-panel-item:last-child {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
.reviewer-info, .author-info {
|
.reviewer-info, .author-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { Button } from 'reactstrap';
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import Prism from 'prismjs';
|
import Prism from 'prismjs';
|
||||||
/* eslint-enable */
|
/* eslint-enable */
|
||||||
@@ -28,6 +29,7 @@ import './assets/css/fa-regular.css';
|
|||||||
import './assets/css/fontawesome.css';
|
import './assets/css/fontawesome.css';
|
||||||
import './css/layout.css';
|
import './css/layout.css';
|
||||||
import './css/toolbar.css';
|
import './css/toolbar.css';
|
||||||
|
import './css/dirent-detail.css';
|
||||||
import './css/draft-review.css';
|
import './css/draft-review.css';
|
||||||
|
|
||||||
const URL = require('url-parse');
|
const URL = require('url-parse');
|
||||||
@@ -42,6 +44,7 @@ class DraftReview extends React.Component {
|
|||||||
reviewStatus: opStatus,
|
reviewStatus: opStatus,
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
commentsNumber: null,
|
commentsNumber: null,
|
||||||
|
unresolvedComments: 0,
|
||||||
inResizing: false,
|
inResizing: false,
|
||||||
commentWidth: 30,
|
commentWidth: 30,
|
||||||
isShowDiff: true,
|
isShowDiff: true,
|
||||||
@@ -54,6 +57,7 @@ class DraftReview extends React.Component {
|
|||||||
changedNodes: [],
|
changedNodes: [],
|
||||||
isShowCommentDialog: false,
|
isShowCommentDialog: false,
|
||||||
activeItem: null,
|
activeItem: null,
|
||||||
|
originRepoName: '',
|
||||||
};
|
};
|
||||||
this.quote = '';
|
this.quote = '';
|
||||||
this.newIndex = null;
|
this.newIndex = null;
|
||||||
@@ -245,8 +249,16 @@ class DraftReview extends React.Component {
|
|||||||
getCommentsNumber = () => {
|
getCommentsNumber = () => {
|
||||||
seafileAPI.listReviewComments(reviewID).then((res) => {
|
seafileAPI.listReviewComments(reviewID).then((res) => {
|
||||||
let number = res.data.total_count;
|
let number = res.data.total_count;
|
||||||
|
let comments = res.data.comments;
|
||||||
|
let unresolvedComments = 0;
|
||||||
|
for (let i = 0; i < res.data.total_count; i++) {
|
||||||
|
if (comments[i].resolved === false) {
|
||||||
|
unresolvedComments++;
|
||||||
|
}
|
||||||
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
commentsNumber: number,
|
commentsNumber: number,
|
||||||
|
unresolvedComments: unresolvedComments,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -379,8 +391,6 @@ class DraftReview extends React.Component {
|
|||||||
const focusText = document.getNode(focus.key);
|
const focusText = document.getNode(focus.key);
|
||||||
const anchorInline = document.getClosestInline(anchor.key);
|
const anchorInline = document.getClosestInline(anchor.key);
|
||||||
const focusInline = document.getClosestInline(focus.key);
|
const focusInline = document.getClosestInline(focus.key);
|
||||||
const focusBlock = document.getClosestBlock(focus.key);
|
|
||||||
const anchorBlock = document.getClosestBlock(anchor.key);
|
|
||||||
// COMPAT: If the selection is at the end of a non-void inline node, and
|
// COMPAT: If the selection is at the end of a non-void inline node, and
|
||||||
// there is a node after it, put it in the node after instead. This
|
// there is a node after it, put it in the node after instead. This
|
||||||
// standardizes the behavior, since it's indistinguishable to the user.
|
// standardizes the behavior, since it's indistinguishable to the user.
|
||||||
@@ -571,6 +581,15 @@ class DraftReview extends React.Component {
|
|||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.getCommentsNumber();
|
this.getCommentsNumber();
|
||||||
this.listReviewers();
|
this.listReviewers();
|
||||||
|
this.getOriginRepoInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
getOriginRepoInfo = () => {
|
||||||
|
seafileAPI.getRepoInfo(draftOriginRepoID).then((res) => {
|
||||||
|
this.setState({
|
||||||
|
originRepoName: res.data.repo_name
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
initialDiffViewerContent = () => {
|
initialDiffViewerContent = () => {
|
||||||
@@ -867,11 +886,18 @@ class DraftReview extends React.Component {
|
|||||||
reviewers={this.state.reviewers}
|
reviewers={this.state.reviewers}
|
||||||
toggleAddReviewerDialog={this.toggleAddReviewerDialog}/>
|
toggleAddReviewerDialog={this.toggleAddReviewerDialog}/>
|
||||||
<SidePanelAuthor/>
|
<SidePanelAuthor/>
|
||||||
|
<UnresolvedComments number={this.state.unresolvedComments}/>
|
||||||
{ this.state.isShowDiff &&
|
{ this.state.isShowDiff &&
|
||||||
<SidePanelChanges
|
<SidePanelChanges
|
||||||
changedNumber={this.state.changedNodes.length}
|
changedNumber={this.state.changedNodes.length}
|
||||||
scrollToChangedNode={this.scrollToChangedNode}/>
|
scrollToChangedNode={this.scrollToChangedNode}/>
|
||||||
}
|
}
|
||||||
|
<SidePanelOrigin originRepoName={this.state.originRepoName}/>
|
||||||
|
<div className="review-side-panel-item">
|
||||||
|
<a href={draftLink}>
|
||||||
|
<Button color="secondary" size="sm">{gettext('Edit Draft')}</Button>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TabPane>
|
</TabPane>
|
||||||
<TabPane tabId="comments" className="comments">
|
<TabPane tabId="comments" className="comments">
|
||||||
@@ -970,6 +996,61 @@ class SidePanelAuthor extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SidePanelOrigin extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="dirent-table-container">
|
||||||
|
<table className="table-thead-hidden">
|
||||||
|
<thead>
|
||||||
|
<tr><th width="25%"></th><th width="75%"></th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><th>{gettext('Library')}</th><td>{this.props.originRepoName}</td></tr>
|
||||||
|
<tr><th>{gettext('Position')}</th><td>{draftOriginFilePath}</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SidePanelOriginPropTypes = {
|
||||||
|
originRepoName: PropTypes.string.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
SidePanelOrigin.propTypes = SidePanelOriginPropTypes;
|
||||||
|
|
||||||
|
|
||||||
|
class UnresolvedComments extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="review-side-panel-item">
|
||||||
|
<div className="review-side-panel-header">{gettext('Comments')}</div>
|
||||||
|
<div className="changes-info">
|
||||||
|
<span>{gettext('Unresolved comments:')}{' '}{this.props.number}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const UnresolvedCommentsPropTypes = {
|
||||||
|
number: PropTypes.number.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
UnresolvedComments.propTypes = UnresolvedCommentsPropTypes;
|
||||||
|
|
||||||
|
|
||||||
class SidePanelChanges extends React.Component {
|
class SidePanelChanges extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
Reference in New Issue
Block a user