1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-12 21:30:39 +00:00

Change participants UI and API (#3889)

* change tooltip ID

* change dialog API

* change mention style

* change comment panel API

change detail panel API

* change Tooltip

* change mention color

update seafile-api

change comment content click
This commit is contained in:
Michael An
2019-07-26 16:51:47 +08:00
committed by Daniel Pan
parent f7d226bf95
commit ec87c48002
7 changed files with 133 additions and 97 deletions

View File

@@ -8,7 +8,6 @@ import { seafileAPI } from '../../utils/seafile-api';
import ParticipantsList from './participants-list';
import { Utils } from '../../utils/utils';
import toaster from '../toast';
import { siteRoot } from '../../utils/constants';
import { MentionsInput, Mention } from 'react-mentions';
import { defaultStyle, defaultMentionStyle } from '../../css/react-mentions-default-style';
import '../../css/comments-list.css';
@@ -33,6 +32,7 @@ class CommentPanel extends React.Component {
relatedUsers: null,
comment: '',
};
this.toBeAddedParticipant = [];
}
toggleResolvedComment = () => {
@@ -53,7 +53,7 @@ class CommentPanel extends React.Component {
listRepoRelatedUsers = () => {
seafileAPI.listRepoRelatedUsers(repoID).then((res) => {
let users = res.data.user_list.map((item) => {
return { id: (siteRoot + 'profile/' + item.email), display: item.name};
return { id: item.email, display: item.name};
});
this.setState({ relatedUsers: users });
});
@@ -63,18 +63,29 @@ class CommentPanel extends React.Component {
this.setState({ comment: event.target.value });
}
submitComment = () => {
let comment = this.state.comment;
if (comment.trim()) {
seafileAPI.postComment(repoID, filePath, comment).then(() => {
this.listComments();
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
this.addParticipant(username);
}
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) => {
@@ -128,23 +139,13 @@ class CommentPanel extends React.Component {
addParticipant = (email) => {
if (this.checkParticipant(email)) return;
seafileAPI.addFileParticipant(repoID, filePath, email).then((res) => {
this.onParticipantsChange(repoID, filePath);
}).catch((err) => {
let errMessage = Utils.getErrorMsg(err);
toaster.danger(errMessage);
});
this.toBeAddedParticipant.push(email);
}
renderUserSuggestion = (entry, search, highlightedDisplay, index, focused) => {
return <div className={`user ${focused ? 'focused' : ''}`}>{highlightedDisplay}</div>;
}
handleMention = (id, display) => {
const email = id.slice(id.lastIndexOf('/') + 1);
this.addParticipant(email);
}
componentDidMount() {
this.listComments();
this.getParticipants();
@@ -221,15 +222,14 @@ class CommentPanel extends React.Component {
>
<Mention
trigger="@"
displayTransform={(username, display) => `@${display}`}
data={this.state.relatedUsers}
renderSuggestion={this.renderUserSuggestion}
style={defaultMentionStyle}
onAdd={this.handleMention}
onAdd={(id, display) => {this.addParticipant(id);}}
/>
</MentionsInput>
<Button
className="submit-comment" color="primary"
size="sm" onClick={this.submitComment} >
<Button className="submit-comment" color="primary" size="sm" onClick={this.onSubmit}>
{gettext('Submit')}</Button>
</div>
</div>
@@ -268,14 +268,10 @@ class CommentItem extends React.Component {
}
convertComment = (mdFile) => {
processor.process(mdFile).then(
(result) => {
let html = String(result);
this.setState({
html: html
});
}
);
processor.process(mdFile).then((result) => {
let html = String(result);
this.setState({ html: html });
});
}
toggleEditComment = () => {
@@ -298,6 +294,15 @@ class CommentItem extends React.Component {
});
}
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);
}
@@ -324,7 +329,7 @@ class CommentItem extends React.Component {
<div className="seafile-edit-comment">
<textarea className="edit-comment-input" value={this.state.newComment} onChange={this.handleCommentChange} clos="100" rows="3" warp="virtual"></textarea>
<Button className="comment-btn" color="success" size="sm" onClick={this.updateComment} id={item.id}>{gettext('Update')}</Button>{' '}
<Button className="comment-btn" color="secondary" size="sm" onClick={this.toggleEditComment}> {gettext('Cancel')}</Button>
<Button className="comment-btn" color="secondary" size="sm" onClick={this.toggleEditComment}>{gettext('Cancel')}</Button>
</div>
</li>
);
@@ -344,24 +349,25 @@ class CommentItem extends React.Component {
<i className="fas fa-ellipsis-v"></i>
</DropdownToggle>
<DropdownMenu>
{
(item.user_email === username) &&
{(item.user_email === username) &&
<DropdownItem onClick={this.props.deleteComment} className="delete-comment"
id={item.id}>{gettext('Delete')}</DropdownItem>}
{
(item.user_email === username) &&
<DropdownItem onClick={this.toggleEditComment}
className="edit-comment" id={item.id}>{gettext('Edit')}</DropdownItem>
{(item.user_email === username) &&
<DropdownItem onClick={this.toggleEditComment}
className="edit-comment" id={item.id}>{gettext('Edit')}</DropdownItem>
}
{
!item.resolved &&
{!item.resolved &&
<DropdownItem onClick={this.props.resolveComment} className="seafile-comment-resolved"
id={item.id}>{gettext('Mark as resolved')}</DropdownItem>
}
</DropdownMenu>
</Dropdown>
</div>
<div className="seafile-comment-content" dangerouslySetInnerHTML={{ __html: this.state.html }}></div>
<div
className="seafile-comment-content"
dangerouslySetInnerHTML={{ __html: this.state.html }}
onClick={e => this.onCommentClick(e)}
></div>
</li>
);
}

View File

@@ -22,6 +22,7 @@ class ParticipantsList extends React.Component {
showDialog : false,
tooltipOpen: false,
};
this.targetID = 'add-participant-icon';
}
toggleDialog = () => {
@@ -32,6 +33,10 @@ class ParticipantsList extends React.Component {
this.setState({ tooltipOpen: !this.state.tooltipOpen });
}
componentWillMount() {
this.targetID = this.targetID + Math.floor(Math.random() * 1000);
}
render() {
const { participants, repoID, filePath, showIconTip } = this.props;
return (
@@ -39,11 +44,11 @@ class ParticipantsList extends React.Component {
{participants.map((item, index) => {
return <Participant item={item} index={index} key={index}/>;
})}
<span className="add-participants" onClick={this.toggleDialog} id="add-participant-icon">
<span className="add-participants" onClick={this.toggleDialog} id={this.targetID}>
<i className="fas fa-plus-circle"></i>
</span>
{showIconTip &&
<Tooltip toggle={this.tooltipToggle} delay={{show: 0, hide: 0}} target="add-participant-icon" placement='bottom' isOpen={this.state.tooltipOpen}>
<Tooltip toggle={this.tooltipToggle} delay={{show: 0, hide: 0}} target={this.targetID} placement='bottom' isOpen={this.state.tooltipOpen}>
{gettext('Add participants')}
</Tooltip>
}
@@ -77,19 +82,23 @@ class Participant extends React.Component {
this.state = {
showAvatarTooltip: false,
};
this.targetID = 'participant-avatar-';
}
toggleAvatarTooltip = () => {
this.setState({ showAvatarTooltip: !this.state.showAvatarTooltip });
}
componentWillMount() {
this.targetID = this.targetID + this.props.index + Math.floor(Math.random() * 1000);
}
render() {
const { item, index } = this.props;
const target = 'participant-avatar-' + index;
return (
<span className="participant-avatar">
<img src={item.avatar_url} className="avatar" id={target} alt="avatar" key={index}/>
<Tooltip toggle={this.toggleAvatarTooltip} delay={{show: 0, hide: 0}} target={target} placement='bottom' isOpen={this.state.showAvatarTooltip}>
<img src={item.avatar_url} className="avatar" id={this.targetID} alt="avatar" key={index}/>
<Tooltip toggle={this.toggleAvatarTooltip} delay={{show: 0, hide: 0}} target={this.targetID} placement='bottom' isOpen={this.state.showAvatarTooltip}>
{item.name}
</Tooltip>
</span>