mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-17 15:53:28 +00:00
change UI 1
This commit is contained in:
@@ -5,6 +5,7 @@ import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import { gettext, siteRoot } from '../../utils/constants';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import { processor } from '@seafile/seafile-editor';
|
||||
import '../../css/notice-item.css';
|
||||
|
||||
const propTypes = {
|
||||
noticeItem: PropTypes.object.isRequired,
|
||||
@@ -38,35 +39,26 @@ class NoticeItem extends React.Component {
|
||||
let detail = noticeItem.detail;
|
||||
|
||||
if (noticeType === MSG_TYPE_ADD_USER_TO_GROUP) {
|
||||
|
||||
let avatar_url = detail.group_staff_avatar_url;
|
||||
|
||||
let groupStaff = detail.group_staff_name;
|
||||
|
||||
// group name does not support special characters
|
||||
let userHref = siteRoot + 'profile/' + detail.group_staff_email + '/';
|
||||
let groupHref = siteRoot + 'group/' + detail.group_id + '/';
|
||||
let groupName = detail.group_name;
|
||||
|
||||
let username = detail.group_staff_name;
|
||||
let notice = gettext('User {user_link} has added you to {group_link}');
|
||||
let userLink = '<a href=' + userHref + '>' + groupStaff + '</a>';
|
||||
let groupLink = '<a href=' + groupHref + '>' + groupName + '</a>';
|
||||
|
||||
notice = notice.replace('{user_link}', userLink);
|
||||
notice = notice.replace('{group_link}', groupLink);
|
||||
|
||||
return { avatar_url, notice };
|
||||
return { avatar_url, notice, username };
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_REPO_SHARE) {
|
||||
|
||||
let avatar_url = detail.share_from_user_avatar_url;
|
||||
|
||||
let shareFrom = detail.share_from_user_name;
|
||||
|
||||
let repoName = detail.repo_name;
|
||||
let repoUrl = siteRoot + 'library/' + detail.repo_id + '/' + repoName + '/';
|
||||
|
||||
let path = detail.path;
|
||||
let notice = '';
|
||||
// 1. handle translate
|
||||
@@ -75,21 +67,17 @@ class NoticeItem extends React.Component {
|
||||
} else { // share folder
|
||||
notice = gettext('{share_from} has shared a folder named {repo_link} to you.');
|
||||
}
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{share_from}', shareFrom);
|
||||
notice = notice.replace('{repo_link}', `{tagA}${repoName}{/tagA}`);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
|
||||
// 3. add jump link
|
||||
notice = notice.replace('{tagA}', `<a href='${Utils.encodePath(repoUrl)}'>`);
|
||||
notice = notice.replace('{/tagA}', '</a>');
|
||||
|
||||
return { avatar_url, notice };
|
||||
return { avatar_url, notice, username: shareFrom };
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_REPO_SHARE_PERM_CHANGE) {
|
||||
|
||||
let avatar_url = detail.share_from_user_avatar_url;
|
||||
let shareFrom = detail.share_from_user_name;
|
||||
let permission = detail.permission;
|
||||
@@ -103,22 +91,18 @@ class NoticeItem extends React.Component {
|
||||
} else { // share folder
|
||||
notice = gettext('{share_from} has changed the permission of folder {repo_link} to {permission}.');
|
||||
}
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{share_from}', shareFrom);
|
||||
notice = notice.replace('{repo_link}', `{tagA}${repoName}{/tagA}`);
|
||||
notice = notice.replace('{permission}', permission);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
|
||||
// 3. add jump link
|
||||
notice = notice.replace('{tagA}', `<a href='${Utils.encodePath(repoUrl)}'>`);
|
||||
notice = notice.replace('{/tagA}', '</a>');
|
||||
|
||||
return { avatar_url, notice };
|
||||
return { avatar_url, notice, username: shareFrom };
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_REPO_SHARE_PERM_DELETE) {
|
||||
|
||||
let avatar_url = detail.share_from_user_avatar_url;
|
||||
let shareFrom = detail.share_from_user_name;
|
||||
let repoName = detail.repo_name;
|
||||
@@ -130,26 +114,20 @@ class NoticeItem extends React.Component {
|
||||
} else { // share folder
|
||||
notice = gettext('{share_from} has cancelled the sharing of folder {repo_name}.');
|
||||
}
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{share_from}', shareFrom);
|
||||
notice = notice.replace('{repo_name}', repoName);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
return { avatar_url, notice };
|
||||
return { avatar_url, notice, username: shareFrom };
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_REPO_SHARE_TO_GROUP) {
|
||||
|
||||
let avatar_url = detail.share_from_user_avatar_url;
|
||||
|
||||
let shareFrom = detail.share_from_user_name;
|
||||
|
||||
let repoName = detail.repo_name;
|
||||
let repoUrl = siteRoot + 'library/' + detail.repo_id + '/' + repoName + '/';
|
||||
|
||||
let groupUrl = siteRoot + 'group/' + detail.group_id + '/';
|
||||
let groupName = detail.group_name;
|
||||
|
||||
let path = detail.path;
|
||||
let notice = '';
|
||||
// 1. handle translate
|
||||
@@ -158,60 +136,50 @@ class NoticeItem extends React.Component {
|
||||
} else {
|
||||
notice = gettext('{share_from} has shared a folder named {repo_link} to group {group_link}.');
|
||||
}
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{share_from}', shareFrom);
|
||||
notice = notice.replace('{repo_link}', `{tagA}${repoName}{/tagA}`);
|
||||
notice = notice.replace('{group_link}', `{tagB}${groupName}{/tagB}`);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
|
||||
// 3. add jump link
|
||||
notice = notice.replace('{tagA}', `<a href='${Utils.encodePath(repoUrl)}'>`);
|
||||
notice = notice.replace('{/tagA}', '</a>');
|
||||
notice = notice.replace('{tagB}', `<a href='${Utils.encodePath(groupUrl)}'>`);
|
||||
notice = notice.replace('{/tagB}', '</a>');
|
||||
return { avatar_url, notice };
|
||||
return { avatar_url, notice, username: shareFrom };
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_REPO_TRANSFER) {
|
||||
|
||||
let avatar_url = detail.transfer_from_user_avatar_url;
|
||||
|
||||
let repoOwner = detail.transfer_from_user_name;
|
||||
|
||||
let repoName = detail.repo_name;
|
||||
let repoUrl = siteRoot + 'library/' + detail.repo_id + '/' + repoName + '/';
|
||||
// 1. handle translate
|
||||
let notice = gettext('{user} has transfered a library named {repo_link} to you.');
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{user}', repoOwner);
|
||||
notice = notice.replace('{repo_link}', `{tagA}${repoName}{/tagA}`);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
|
||||
// 3. add jump link
|
||||
notice = notice.replace('{tagA}', `<a href=${Utils.encodePath(repoUrl)}>`);
|
||||
notice = notice.replace('{/tagA}', '</a>');
|
||||
return { avatar_url, notice };
|
||||
return { avatar_url, notice, username: repoOwner };
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_FILE_UPLOADED) {
|
||||
let avatar_url = detail.uploaded_user_avatar_url;
|
||||
let fileName = detail.file_name;
|
||||
let fileLink = siteRoot + 'lib/' + detail.repo_id + '/' + 'file' + detail.file_path;
|
||||
|
||||
let folderName = detail.folder_name;
|
||||
let folderLink = siteRoot + 'library/' + detail.repo_id + '/' + detail.repo_name + detail.folder_path;
|
||||
let notice = '';
|
||||
if (detail.repo_id) { // todo is repo exist ?
|
||||
// 1. handle translate
|
||||
notice = gettext('A file named {upload_file_link} is uploaded to {uploaded_link}.');
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{upload_file_link}', `{tagA}${fileName}{/tagA}`);
|
||||
notice = notice.replace('{uploaded_link}', `{tagB}${folderName}{/tagB}`);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
|
||||
// 3. add jump link
|
||||
notice = notice.replace('{tagA}', `<a href=${Utils.encodePath(fileLink)}>`);
|
||||
notice = notice.replace('{/tagA}', '</a>');
|
||||
@@ -220,7 +188,6 @@ class NoticeItem extends React.Component {
|
||||
} else {
|
||||
// 1. handle translate
|
||||
notice = gettext('A file named {upload_file_link} is uploaded.');
|
||||
|
||||
// 2. handle xss(cross-site scripting)
|
||||
notice = notice.replace('{upload_file_link}', `${fileName}`);
|
||||
notice = Utils.HTMLescape(notice);
|
||||
@@ -344,17 +311,11 @@ class NoticeItem extends React.Component {
|
||||
}
|
||||
|
||||
if (noticeType === MSG_TYPE_DELETED_FILES) {
|
||||
const {
|
||||
repo_id,
|
||||
repo_name,
|
||||
} = detail;
|
||||
|
||||
const { repo_id, repo_name } = detail;
|
||||
const repoURL = `${siteRoot}library/${repo_id}/${encodeURIComponent(repo_name)}/`;
|
||||
const repoLink = `<a href=${repoURL} target="_blank">${Utils.HTMLescape(repo_name)}</a>`;
|
||||
|
||||
let notice = gettext('Your library {libraryName} has recently deleted a large number of files.');
|
||||
notice = notice.replace('{libraryName}', repoLink);
|
||||
|
||||
return { avatar_url: null, notice };
|
||||
}
|
||||
|
||||
@@ -374,7 +335,6 @@ class NoticeItem extends React.Component {
|
||||
if (noticeType === MSG_TYPE_SAML_SSO_FAILED) {
|
||||
const { error_msg } = detail;
|
||||
let notice = gettext(error_msg);
|
||||
|
||||
return { avatar_url: null, notice };
|
||||
}
|
||||
|
||||
@@ -424,7 +384,7 @@ class NoticeItem extends React.Component {
|
||||
|
||||
// }
|
||||
|
||||
return { avatar_url: null, notice: null };
|
||||
return { avatar_url: null, notice: null, username: null };
|
||||
}
|
||||
|
||||
onNoticeItemClick = () => {
|
||||
@@ -455,18 +415,21 @@ class NoticeItem extends React.Component {
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
<li onClick={this.onNoticeItemClick} className={noticeItem.seen ? 'read' : 'unread'}>
|
||||
<div className="notice-item">
|
||||
<div className="main-info">
|
||||
<div className="auther-info">
|
||||
<img src={avatar_url} width="32" height="32" className="avatar" alt=""/>
|
||||
<p>{username}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="brief" dangerouslySetInnerHTML={{ __html: notice }}></p>
|
||||
<li className='notification-item' onClick={this.onNoticeItemClick}>
|
||||
<div className="notification-item-header">
|
||||
{!noticeItem.seen &&
|
||||
<span className="notification-point" onClick={this.onMarkNotificationRead}></span>
|
||||
}
|
||||
<div className="notification-header-info">
|
||||
<div className="notification-user-detail">
|
||||
<img className="notification-user-avatar" src={avatar_url} alt="" />
|
||||
<span className="ml-2 notification-user-name">{username || gettext('System')}</span>
|
||||
</div>
|
||||
<span className="notification-time">{dayjs(noticeItem.time).fromNow()}</span>
|
||||
</div>
|
||||
<p className="time">{dayjs(noticeItem.time).fromNow()}</p>
|
||||
</div>
|
||||
<div className="notification-content-wrapper">
|
||||
<div dangerouslySetInnerHTML={{ __html: notice }}></div>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
|
@@ -66,7 +66,7 @@
|
||||
}
|
||||
|
||||
.notification-container .mark-all-read {
|
||||
color: #b4b4b4;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -187,6 +187,9 @@
|
||||
|
||||
.notification-container .notification-body .mark-notifications {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #ededed;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.notification-container .notification-body .mark-notifications .mark-all-read:hover {
|
||||
@@ -198,8 +201,9 @@
|
||||
margin-right: 15px;
|
||||
margin-left: 15px;
|
||||
font-size: 14px;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.notification-container .notification-body .nav .nav-item .nav-link.active {
|
||||
color: #ED7109 !important;
|
||||
}
|
||||
color: #ED7109;
|
||||
}
|
||||
|
@@ -18,6 +18,8 @@ export default class NotificationPopover extends React.Component {
|
||||
tabItemClick: PropTypes.func,
|
||||
children: PropTypes.any,
|
||||
currentTab: PropTypes.string,
|
||||
generalNoticeListUnseen: PropTypes.number,
|
||||
discussionNoticeListUnseen: PropTypes.number,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
@@ -56,7 +58,7 @@ export default class NotificationPopover extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { headerText, bodyText, footerText, currentTab } = this.props;
|
||||
const { headerText, bodyText, footerText, currentTab, generalNoticeListUnseen, discussionNoticeListUnseen } = this.props;
|
||||
return (
|
||||
<Popover
|
||||
className="notification-wrapper"
|
||||
@@ -77,11 +79,13 @@ export default class NotificationPopover extends React.Component {
|
||||
<li className="nav-item" onClick={() => this.tabItemClick('general')}>
|
||||
<span className={`nav-link ${currentTab === 'general' ? 'active' : ''}`}>
|
||||
{gettext('General')}
|
||||
{generalNoticeListUnseen > 0 && <span>({generalNoticeListUnseen})</span>}
|
||||
</span>
|
||||
</li>
|
||||
<li className="nav-item" onClick={() => this.tabItemClick('discussion')}>
|
||||
<span className={`nav-link ${currentTab === 'discussion' ? 'active' : ''}`}>
|
||||
{gettext('Discussion')}
|
||||
{discussionNoticeListUnseen > 0 && <span>({discussionNoticeListUnseen})</span>}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -103,23 +107,6 @@ export default class NotificationPopover extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
{/* <div className="mark-notifications" onClick={this.props.onMarkAllNotifications}>
|
||||
<ul className="nav dtable-external-links-tab">
|
||||
<li className="nav-item">
|
||||
<span className="nav-link">General</span>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<span className="nav-link">Discussion</span>
|
||||
</li>
|
||||
</ul>
|
||||
<span className="mark-all-read">{bodyText}</span>
|
||||
</div>
|
||||
<div className="notification-list-container" onScroll={this.onHandleScroll} ref={ref => this.notificationListRef = ref}>
|
||||
<div ref={ref => this.notificationsWrapperRef = ref}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="notification-footer" onClick={this.onNotificationDialogToggle}>{footerText}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -123,7 +123,9 @@ class Notification extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { unseenCount, currentTab } = this.state;
|
||||
const { unseenCount, currentTab, generalNoticeList, discussionNoticeList } = this.state;
|
||||
const generalNoticeListUnseen = generalNoticeList.filter(item => !item.seen).length;
|
||||
const discussionNoticeListUnseen = discussionNoticeList.filter(item => !item.seen).length;
|
||||
return (
|
||||
<div id="notifications">
|
||||
<a href="#" onClick={this.onClick} className="no-deco" id="notice-icon" title={gettext('Notifications')} aria-label={gettext('Notifications')}>
|
||||
@@ -140,25 +142,35 @@ class Notification extends React.Component {
|
||||
onNotificationDialogToggle={this.onNotificationDialogToggle}
|
||||
onMarkAllNotifications={this.onMarkAllNotifications}
|
||||
tabItemClick={this.tabItemClick}
|
||||
generalNoticeListUnseen={generalNoticeListUnseen}
|
||||
discussionNoticeListUnseen={discussionNoticeListUnseen}
|
||||
>
|
||||
{this.state.currentTab === 'general' &&
|
||||
{currentTab === 'general' &&
|
||||
<ul className="notice-list list-unstyled" id="notice-popover">
|
||||
{this.state.generalNoticeList.map(item => {
|
||||
return (<NoticeItem key={item.id} noticeItem={item} onNoticeItemClick={this.onNoticeItemClick}/>);
|
||||
{generalNoticeList.map(item => {
|
||||
return (
|
||||
<NoticeItem key={item.id} noticeItem={item} onNoticeItemClick={this.onNoticeItemClick}/>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
}
|
||||
{this.state.currentTab === 'discussion' &&
|
||||
{currentTab === 'discussion' &&
|
||||
<ul className="notice-list list-unstyled" id="notice-popover">
|
||||
{this.state.discussionNoticeList.map(item => {
|
||||
return (<NoticeItem key={item.id} noticeItem={item} onNoticeItemClick={this.onNoticeItemClick}/>);
|
||||
{discussionNoticeList.map(item => {
|
||||
return (
|
||||
<NoticeItem key={item.id} noticeItem={item} onNoticeItemClick={this.onNoticeItemClick}/>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
}
|
||||
</NotificationPopover>
|
||||
}
|
||||
{this.state.isShowNotificationDialog &&
|
||||
<UserNotificationsDialog onNotificationDialogToggle={this.onNotificationDialogToggle} />
|
||||
<UserNotificationsDialog
|
||||
onNotificationDialogToggle={this.onNotificationDialogToggle}
|
||||
generalNoticeListUnseen={generalNoticeListUnseen}
|
||||
discussionNoticeListUnseen={discussionNoticeListUnseen}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
Reference in New Issue
Block a user