mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-09 19:01:42 +00:00
root path show file_tag && tagged_files_count (#2715)
This commit is contained in:
@@ -12,6 +12,7 @@ import DirentDetail from '../dirent-detail/dirent-details';
|
||||
import FileUploader from '../file-uploader/file-uploader';
|
||||
import ModalPortal from '../modal-portal';
|
||||
import LibDecryptDialog from '../dialog/lib-decrypt-dialog';
|
||||
import FileTagsViewer from '../../components/filetags-viewer';
|
||||
|
||||
const propTypes = {
|
||||
currentRepoInfo: PropTypes.object,
|
||||
@@ -46,6 +47,7 @@ const propTypes = {
|
||||
updateDirent: PropTypes.func.isRequired,
|
||||
onSearchedClick: PropTypes.func.isRequired,
|
||||
onFileUploadSuccess: PropTypes.func.isRequired,
|
||||
usedRepoTags: PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
class DirPanel extends React.Component {
|
||||
@@ -171,6 +173,15 @@ class DirPanel extends React.Component {
|
||||
onTabNavClick={this.props.onTabNavClick}
|
||||
/>
|
||||
</div>
|
||||
{(this.props.usedRepoTags.length > 0 && this.props.path === '/') && (
|
||||
<div className="tags-summary-bar">
|
||||
<FileTagsViewer
|
||||
repoID={this.props.repoID}
|
||||
currentPath={this.props.path}
|
||||
usedRepoTags={this.props.usedRepoTags}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="cur-view-content">
|
||||
{this.props.errorMsg ?
|
||||
<p className="error text-center">{this.props.errorMsg}</p> :
|
||||
|
@@ -9,6 +9,7 @@ import toaster from '../toast';
|
||||
import DirPanel from './dir-panel';
|
||||
import Dirent from '../../models/dirent';
|
||||
import FileTag from '../../models/file-tag';
|
||||
import RepoTag from '../../models/repo-tag';
|
||||
import RepoInfo from '../../models/repo-info';
|
||||
|
||||
const propTypes = {
|
||||
@@ -37,6 +38,7 @@ class DirView extends React.Component {
|
||||
selectedDirentList: [],
|
||||
dirID: '',
|
||||
errorMsg: '',
|
||||
usedRepoTags: [],
|
||||
};
|
||||
window.onpopstate = this.onpopstate;
|
||||
this.lastModifyTime = new Date();
|
||||
@@ -54,6 +56,16 @@ class DirView extends React.Component {
|
||||
let location = decodeURIComponent(window.location.href);
|
||||
let repoID = this.props.repoID;
|
||||
collabServer.watchRepo(repoID, this.onRepoUpdateEvent);
|
||||
seafileAPI.listRepoTags(repoID).then(res => {
|
||||
let usedRepoTags = [];
|
||||
res.data.repo_tags.forEach(item => {
|
||||
let usedRepoTag = new RepoTag(item);
|
||||
if (usedRepoTag.fileCount > 0) {
|
||||
usedRepoTags.push(usedRepoTag);
|
||||
}
|
||||
});
|
||||
this.setState({usedRepoTags: usedRepoTags});
|
||||
});
|
||||
seafileAPI.getRepoInfo(repoID).then(res => {
|
||||
let repoInfo = new RepoInfo(res.data);
|
||||
this.setState({
|
||||
@@ -122,6 +134,10 @@ class DirView extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
updateUsedRepoTags = (newUsedRepoTags) => {
|
||||
this.setState({usedRepoTags: newUsedRepoTags});
|
||||
}
|
||||
|
||||
updateDirentList = (filePath) => {
|
||||
let repoID = this.state.repoID;
|
||||
this.setState({isDirentListLoading: true});
|
||||
@@ -368,6 +384,17 @@ class DirView extends React.Component {
|
||||
});
|
||||
this.updateDirent(dirent, 'file_tags', fileTags);
|
||||
});
|
||||
|
||||
seafileAPI.listRepoTags(repoID).then(res => {
|
||||
let usedRepoTags = [];
|
||||
res.data.repo_tags.forEach(item => {
|
||||
let usedRepoTag = new RepoTag(item);
|
||||
if (usedRepoTag.fileCount > 0) {
|
||||
usedRepoTags.push(usedRepoTag);
|
||||
}
|
||||
});
|
||||
this.updateUsedRepoTags(usedRepoTags);
|
||||
});
|
||||
}
|
||||
|
||||
onMenuClick = () => {
|
||||
@@ -549,6 +576,7 @@ class DirView extends React.Component {
|
||||
onFileUploadSuccess={this.onFileUploadSuccess}
|
||||
libNeedDecrypt={this.state.libNeedDecrypt}
|
||||
onLibDecryptDialog={this.onLibDecryptDialog}
|
||||
usedRepoTags={this.state.usedRepoTags}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@@ -426,7 +426,7 @@ class DirentListItem extends React.Component {
|
||||
<a href={dirent.type === 'dir' ? dirHref : fileHref} onClick={this.onItemClick}>{dirent.name}</a>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
<td className="tag-list-title">
|
||||
{(dirent.type !== 'dir' && dirent.file_tags) && (
|
||||
<Fragment>
|
||||
<div id={`tag-list-title-${toolTipID}`} className="dirent-item tag-list tag-list-stacked">
|
||||
|
74
frontend/src/components/filetags-viewer.js
Normal file
74
frontend/src/components/filetags-viewer.js
Normal file
@@ -0,0 +1,74 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ModalPortal from './modal-portal';
|
||||
import { Modal } from 'reactstrap';
|
||||
import ListTaggedFilesDialog from './dialog/list-taggedfiles-dialog';
|
||||
|
||||
const propTypes = {
|
||||
repoID: PropTypes.string.isRequired,
|
||||
currentPath: PropTypes.string.isRequired,
|
||||
usedRepoTags: PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
class FileTagsViewer extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
usedRepoTags: [],
|
||||
currentTag: null,
|
||||
isListTaggedFileShow: false,
|
||||
};
|
||||
}
|
||||
|
||||
onListTaggedFiles = (currentTag) => {
|
||||
this.setState({
|
||||
currentTag: currentTag,
|
||||
isListTaggedFileShow: !this.state.isListTaggedFileShow,
|
||||
});
|
||||
}
|
||||
|
||||
onCloseDialog = () => {
|
||||
this.setState({
|
||||
isListTaggedFileShow: false
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let {usedRepoTags, repoID} = this.props;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<ul className="used-tag-list">
|
||||
{usedRepoTags.map((usedRepoTag) => {
|
||||
return (
|
||||
<li key={usedRepoTag.id} className="used-tag-item">
|
||||
<span className={`used-tag bg-${usedRepoTag.color}`}></span>
|
||||
<span className="used-tag-name" title={usedRepoTag.name}>{usedRepoTag.name}</span>
|
||||
<span className="used-tag-files" onClick={this.onListTaggedFiles.bind(this, usedRepoTag)}>
|
||||
{usedRepoTag.fileCount > 1 ? usedRepoTag.fileCount + ' files' : usedRepoTag.fileCount + ' file'}
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
{this.state.isListTaggedFileShow && (
|
||||
<ModalPortal>
|
||||
<Modal isOpen={true}>
|
||||
<ListTaggedFilesDialog
|
||||
repoID={repoID}
|
||||
currentTag={this.state.currentTag}
|
||||
onClose={this.onCloseDialog}
|
||||
toggleCancel={this.onListTaggedFiles}
|
||||
/>
|
||||
</Modal>
|
||||
</ModalPortal>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FileTagsViewer.propTypes = propTypes;
|
||||
|
||||
export default FileTagsViewer;
|
@@ -44,6 +44,8 @@
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.dirent-info .img {
|
||||
@@ -103,11 +105,16 @@
|
||||
.file-tag-list li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: 180px;
|
||||
}
|
||||
|
||||
.file-tag-list .tag-name {
|
||||
display: inline-block;
|
||||
margin-left: 0.5rem;
|
||||
margin-left: 5px;
|
||||
width: 100px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.file-related-files th {
|
||||
|
@@ -23,3 +23,7 @@
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.tag-list-title {
|
||||
overflow: hidden;
|
||||
}
|
@@ -31,6 +31,7 @@
|
||||
align-items: center;
|
||||
color: #ffffff;
|
||||
overflow: hidden;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.show-tag-selected {
|
||||
@@ -92,3 +93,35 @@
|
||||
.tag-dialog-back:focus {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.tags-summary-bar {
|
||||
margin: 16px 16px 4px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid #e6e6dd;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.used-tag-list {
|
||||
list-style: none;
|
||||
line-height: 40px;
|
||||
}
|
||||
.used-tag-item {
|
||||
display: inline-block;
|
||||
margin: auto 15px;
|
||||
}
|
||||
.used-tag {
|
||||
display: inline-block;
|
||||
width: 0.8rem;
|
||||
height: 0.8rem;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.used-tag-name {
|
||||
margin: 0 0.25rem;
|
||||
}
|
||||
.used-tag-files {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
.used-tag-files:hover {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@ import MarkdownContentViewer from '../../components/markdown-viewer';
|
||||
import DirentListView from '../../components/dirent-list-view/dirent-list-view';
|
||||
import DirentDetail from '../../components/dirent-detail/dirent-details';
|
||||
import FileUploader from '../../components/file-uploader/file-uploader';
|
||||
import FileTagsViewer from '../../components/filetags-viewer';
|
||||
|
||||
const propTypes = {
|
||||
content: PropTypes.string,
|
||||
@@ -55,6 +56,7 @@ const propTypes = {
|
||||
goReviewPage: PropTypes.func,
|
||||
goDraftPage: PropTypes.func,
|
||||
reviewID: PropTypes.any,
|
||||
usedRepoTags: PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
class MainPanel extends Component {
|
||||
@@ -229,6 +231,15 @@ class MainPanel extends Component {
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{(this.props.usedRepoTags.length > 0 && this.props.path === '/') && (
|
||||
<div className="tags-summary-bar">
|
||||
<FileTagsViewer
|
||||
repoID={repoID}
|
||||
currentPath={this.props.path}
|
||||
usedRepoTags={this.props.usedRepoTags}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="cur-view-content" onScroll={this.handlePageScroll} ref="curViewContent">
|
||||
{!this.props.pathExist ?
|
||||
ErrMessage :
|
||||
|
@@ -14,6 +14,7 @@ import LibDecryptDialog from './components/dialog/lib-decrypt-dialog';
|
||||
import ModalPortal from './components/modal-portal';
|
||||
import Dirent from './models/dirent';
|
||||
import FileTag from './models/file-tag';
|
||||
import RepoTag from './models/repo-tag';
|
||||
import './assets/css/fa-solid.css';
|
||||
import './assets/css/fa-regular.css';
|
||||
import './assets/css/fontawesome.css';
|
||||
@@ -50,6 +51,7 @@ class Wiki extends Component {
|
||||
reviewID: '',
|
||||
draftFilePath: '',
|
||||
dirID: '',
|
||||
usedRepoTags: [],
|
||||
};
|
||||
window.onpopstate = this.onpopstate;
|
||||
this.hash = '';
|
||||
@@ -65,6 +67,16 @@ class Wiki extends Component {
|
||||
|
||||
componentDidMount() {
|
||||
collabServer.watchRepo(repoID, this.onRepoUpdateEvent);
|
||||
seafileAPI.listRepoTags(repoID).then(res => {
|
||||
let usedRepoTags = [];
|
||||
res.data.repo_tags.forEach(item => {
|
||||
let usedRepoTag = new RepoTag(item);
|
||||
if (usedRepoTag.fileCount > 0) {
|
||||
usedRepoTags.push(usedRepoTag);
|
||||
}
|
||||
});
|
||||
this.setState({usedRepoTags: usedRepoTags});
|
||||
});
|
||||
seafileAPI.getRepoInfo(repoID).then(res => {
|
||||
this.setState({
|
||||
libNeedDecrypt: res.data.lib_need_decrypt,
|
||||
@@ -325,6 +337,10 @@ class Wiki extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
updateUsedRepoTags = (newUsedRepoTags) => {
|
||||
this.setState({usedRepoTags: newUsedRepoTags});
|
||||
}
|
||||
|
||||
updateDirent = (dirent, paramKey, paramValue) => {
|
||||
let newDirentList = this.state.direntList.map(item => {
|
||||
if (item.name === dirent.name) {
|
||||
@@ -595,6 +611,17 @@ class Wiki extends Component {
|
||||
});
|
||||
this.updateDirent(dirent, 'file_tags', fileTags);
|
||||
});
|
||||
|
||||
seafileAPI.listRepoTags(repoID).then(res => {
|
||||
let usedRepoTags = [];
|
||||
res.data.repo_tags.forEach(item => {
|
||||
let usedRepoTag = new RepoTag(item);
|
||||
if (usedRepoTag.fileCount > 0) {
|
||||
usedRepoTags.push(usedRepoTag);
|
||||
}
|
||||
});
|
||||
this.updateUsedRepoTags(usedRepoTags);
|
||||
});
|
||||
}
|
||||
|
||||
onTreeNodeClick = (node) => {
|
||||
@@ -904,6 +931,7 @@ class Wiki extends Component {
|
||||
reviewID={this.state.reviewID}
|
||||
goDraftPage={this.goDraftPage}
|
||||
goReviewPage={this.goReviewPage}
|
||||
usedRepoTags={this.state.usedRepoTags}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
Reference in New Issue
Block a user