1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-06 01:12:03 +00:00

Watch file changes (#5364)

* [my libraries] redesigned 'watch/unwatch file changes'

- added 'watch file changes' & 'unwatch file changes' to the operation
menu
- added icon & tooltip for monitored libraries
- added support for mobile

* [my libs] updated 'watch/unwatch file changes'

* [notifications] update for 'watch/unwatch file changes'
This commit is contained in:
llj
2023-02-03 09:51:18 +08:00
committed by GitHub
parent 2f958cdd6b
commit 4c62d5086f
11 changed files with 1524 additions and 138 deletions

View File

@@ -165,7 +165,7 @@ class NoticeItem extends React.Component {
// 2. handle xss(cross-site scripting)
notice = notice.replace('{upload_file_link}', `${fileName}`);
notice = Utils.HTMLescape(notice);
notice = notice.replace('{uploaded_link}', `<strong>Deleted Library</strong>`);
notice = notice.replace('{uploaded_link}', '<strong>Deleted Library</strong>');
}
return {avatar_url, notice};
}
@@ -226,69 +226,85 @@ class NoticeItem extends React.Component {
}
if (noticeType === MSG_TYPE_REPO_MONITOR) {
let avatar_url = detail.op_user_avatar_url;
let repoLink = siteRoot + 'library/' + detail.repo_id + '/' + detail.repo_name + '/';
let notice = '';
const {
op_user_avatar_url: avatar_url,
op_user_email,
op_user_name,
op_type,
repo_id, repo_name,
obj_type,
obj_path_list,
old_obj_path_list
} = detail;
let op = '';
if (detail.obj_type == 'file') {
switch (detail.op_type) {
const userProfileURL = `${siteRoot}profile/${encodeURIComponent(op_user_email)}`;
const userLink = `<a href=${userProfileURL} target="_blank">${Utils.HTMLescape(op_user_name)}</a>`;
const repoURL = `${siteRoot}library/${repo_id}/${encodeURIComponent(repo_name)}/`;
const repoLink = `<a href=${repoURL} target="_blank">${Utils.HTMLescape(repo_name)}</a>`;
let notice = '';
if (obj_type == 'file') {
const fileName = Utils.getFileName(obj_path_list[0]);
const fileURL = `${siteRoot}lib/${repo_id}/file${Utils.encodePath(obj_path_list[0])}`;
const fileLink = `<a href=${fileURL} target="_blank">${Utils.HTMLescape(fileName)}</a>`;
switch (op_type) {
case 'create':
op = gettext('created file');
notice = obj_path_list.length == 1 ? gettext('{user} created file {fileName} in library {libraryName}.') : gettext('{user} created file {fileName} and {fileCount} other file(s) in library {libraryName}.');
break;
case 'delete':
op = gettext('deleted file');
notice = obj_path_list.length == 1 ? gettext('{user} deleted file {fileName} in library {libraryName}.') : gettext('{user} deleted file {fileName} and {fileCount} other file(s) in library {libraryName}.');
notice = notice.replace('{fileName}', fileName);
break;
case 'recover':
op = gettext('restored file');
notice = gettext('{user} restored file {fileName} in library {libraryName}.');
break;
case 'rename':
op = gettext('renamed file');
notice = gettext('{user} renamed file {oldFileName} {fileName} in library {libraryName}.');
notice = notice.replace('{oldFileName}', Utils.getFileName(old_obj_path_list[0]));
break;
case 'move':
op = gettext('moved file');
notice = obj_path_list.length == 1 ? gettext('{user} moved file {fileName} in library {libraryName}.') : gettext('{user} moved file {fileName} and {fileCount} other file(s) in library {libraryName}.');
break;
case 'edit':
op = gettext('updated file');
notice = gettext('{user} updated file {fileName} in library {libraryName}.');
break;
// no default
}
notice = notice.replace('{fileName}', fileLink);
notice = notice.replace('{fileCount}', obj_path_list.length - 1);
} else { // dir
const folderName = Utils.getFolderName(obj_path_list[0]);
const folderURL = `${siteRoot}library/${repo_id}/${encodeURIComponent(repo_name)}${Utils.encodePath(obj_path_list[0])}`;
const folderLink = `<a href=${folderURL} target="_blank">${Utils.HTMLescape(folderName)}</a>`;
switch (detail.op_type) {
case 'create':
op = gettext('created folder');
notice = obj_path_list.length == 1 ? gettext('{user} created folder {folderName} in library {libraryName}.') : gettext('{user} created folder {folderName} and {folderCount} other folder(s) in library {libraryName}.');
break;
case 'delete':
op = gettext('deleted folder');
notice = obj_path_list.length == 1 ? gettext('{user} deleted folder {folderName} in library {libraryName}.') : gettext('{user} deleted folder {folderName} and {folderCount} other folder(s) in library {libraryName}.');
notice = notice.replace('{folderName}', folderName);
break;
case 'recover':
op = gettext('restored folder');
notice = gettext('{user} restored folder {folderName} in library {libraryName}.');
break;
case 'rename':
op = gettext('renamed folder');
notice = gettext('{user} renamed folder {oldFolderName} {folderName} in library {libraryName}.');
notice = notice.replace('{oldFolderName}', Utils.getFolderName(old_obj_path_list[0]));
break;
case 'move':
op = gettext('moved folder');
notice = obj_path_list.length == 1 ? gettext('{user} moved folder {folderName} in library {libraryName}.') : gettext('{user} moved folder {folderName} and {folderCount} other folder(s) in library {libraryName}.');
break;
// no default
}
notice = notice.replace('{folderName}', folderLink);
notice = notice.replace('{folderCount}', obj_path_list.length - 1);
}
// 1. handle translate
notice = gettext('{op_user} {op_type} {obj_name} in {repo_link}.');
notice = notice.replace('{user}', userLink);
notice = notice.replace('{libraryName}', repoLink);
let obj_name = Utils.getFileName(detail.obj_path_list[0]);
// 2. handle xss(cross-site scripting)
notice = notice.replace('{op_user}', `${detail.op_user_name}`);
notice = notice.replace('{op_type}', `${op}`);
notice = notice.replace('{obj_name}', `${obj_name}`);
notice = notice.replace('{repo_link}', `{tagA}${detail.repo_name}{/tagA}`);
notice = Utils.HTMLescape(notice);
// 3. add jump link
notice = notice.replace('{tagA}', `<a href=${Utils.encodePath(repoLink)}>`);
notice = notice.replace('{/tagA}', '</a>');
return {avatar_url, notice};
return { avatar_url, notice };
}
// if (noticeType === MSG_TYPE_GUEST_INVITATION_ACCEPTED) {

View File

@@ -0,0 +1,30 @@
import React from 'react';
import PropTypes from 'prop-types';
import '../css/icon.css';
const importAll = (requireContext) => {
requireContext.keys().forEach(requireContext);
};
try {
importAll(require.context('../assets/icons', true, /\.svg$/));
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
const Icon = (props) => {
const { className, symbol } = props;
const iconClass = `seafile-multicolor-icon seafile-multicolor-icon-${symbol} ${className || ''}`;
return (
<svg className={iconClass}>
<use xlinkHref={`#${symbol}`} />
</svg>
);
};
Icon.propTypes = {
symbol: PropTypes.string.isRequired,
className: PropTypes.string,
};
export default Icon;