mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-01 23:20:51 +00:00
Detail panel (#3232)
* update dirent detail btn * update icon * add animation * update
This commit is contained in:
@@ -6,6 +6,7 @@ import { Utils } from '../../utils/utils';
|
|||||||
import EditFileTagDialog from '../dialog/edit-filetag-dialog';
|
import EditFileTagDialog from '../dialog/edit-filetag-dialog';
|
||||||
import ModalPortal from '../modal-portal';
|
import ModalPortal from '../modal-portal';
|
||||||
import RelatedFileDialogs from '../dialog/related-file-dialogs';
|
import RelatedFileDialogs from '../dialog/related-file-dialogs';
|
||||||
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
repoInfo: PropTypes.object.isRequired,
|
repoInfo: PropTypes.object.isRequired,
|
||||||
@@ -27,6 +28,7 @@ class DetailListView extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
isEditFileTagShow: false,
|
isEditFileTagShow: false,
|
||||||
showRelatedFileDialog: false,
|
showRelatedFileDialog: false,
|
||||||
|
repo: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,6 +71,28 @@ class DetailListView extends React.Component {
|
|||||||
showRelatedFileDialog: false,
|
showRelatedFileDialog: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRepoInfo = (repoID) => {
|
||||||
|
seafileAPI.listRepos({type: 'mine'}).then((res) => {
|
||||||
|
let repoList = res.data.repos;
|
||||||
|
for (let i = 0, length = repoList.length; i < length; i++) {
|
||||||
|
if (repoList[i].repo_id === repoID) {
|
||||||
|
this.setState({ repo: repoList[i] });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.getRepoInfo(this.props.repoID);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
if (nextProps.repoID !== this.props.repoID) {
|
||||||
|
this.getRepoInfo(nextProps.repoID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { direntType, direntDetail, fileTagList, relatedFiles } = this.props;
|
let { direntType, direntDetail, fileTagList, relatedFiles } = this.props;
|
||||||
@@ -86,6 +110,20 @@ class DetailListView extends React.Component {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
|
} else if (direntType === 'repo') {
|
||||||
|
const repoInfo = this.props.repoInfo;
|
||||||
|
return (
|
||||||
|
<table className="table-thead-hidden">
|
||||||
|
<thead>
|
||||||
|
<tr><th width="35%"></th><th width="65%"></th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><th>{gettext('File Count')}</th><td>{repoInfo.file_count}</td></tr>
|
||||||
|
<tr><th>{gettext('Size')}</th><td>{repoInfo.size}</td></tr>
|
||||||
|
<tr><th>{gettext('Last Update')}</th><td>{moment(this.state.repo.last_modified).format('YYYY-MM-DD')}</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
|
import Dirent from '../../models/dirent';
|
||||||
import DetailListView from './detail-list-view';
|
import DetailListView from './detail-list-view';
|
||||||
import RepoInfo from '../../models/repo-info';
|
import RepoInfo from '../../models/repo-info';
|
||||||
import FileTag from '../../models/file-tag';
|
import FileTag from '../../models/file-tag';
|
||||||
@@ -25,9 +26,16 @@ class DirentDetail extends React.Component {
|
|||||||
repoInfo: null,
|
repoInfo: null,
|
||||||
fileTagList: [],
|
fileTagList: [],
|
||||||
relatedFiles: [],
|
relatedFiles: [],
|
||||||
|
currentFolderDirent: null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
if (!this.props.dirent.name) {
|
||||||
|
this.getCurrentFolderDirent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
let { dirent, path, repoID } = this.props;
|
let { dirent, path, repoID } = this.props;
|
||||||
let direntPath = Utils.joinPath(path, dirent.name);
|
let direntPath = Utils.joinPath(path, dirent.name);
|
||||||
@@ -46,7 +54,7 @@ class DirentDetail extends React.Component {
|
|||||||
|
|
||||||
updateDetailView = (dirent, direntPath) => {
|
updateDetailView = (dirent, direntPath) => {
|
||||||
let repoID = this.props.repoID;
|
let repoID = this.props.repoID;
|
||||||
if (dirent.type === 'file') {
|
if (dirent && dirent.type === 'file') {
|
||||||
seafileAPI.getFileInfo(repoID, direntPath).then(res => {
|
seafileAPI.getFileInfo(repoID, direntPath).then(res => {
|
||||||
this.setState({
|
this.setState({
|
||||||
direntType: 'file',
|
direntType: 'file',
|
||||||
@@ -76,16 +84,44 @@ class DirentDetail extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else if (this.props.path !== '/') {
|
||||||
|
const dirPath = dirent.name ? direntPath : this.props.path;
|
||||||
|
seafileAPI.getDirInfo(repoID, dirPath).then(res => {
|
||||||
|
this.setState({
|
||||||
|
direntType: 'dir',
|
||||||
|
direntDetail: res.data
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else if (this.props.path === '/' && dirent.name) {
|
||||||
seafileAPI.getDirInfo(repoID, direntPath).then(res => {
|
seafileAPI.getDirInfo(repoID, direntPath).then(res => {
|
||||||
this.setState({
|
this.setState({
|
||||||
direntType: 'dir',
|
direntType: 'dir',
|
||||||
direntDetail: res.data
|
direntDetail: res.data
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
} else if (this.props.path === '/' && !dirent.name) {
|
||||||
|
this.setState({
|
||||||
|
direntType: 'repo',
|
||||||
|
direntDetail: {},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCurrentFolderDirent = () => {
|
||||||
|
const path = this.props.path;
|
||||||
|
const parentPath = path.slice(0, path.lastIndexOf('/'));
|
||||||
|
seafileAPI.listDir(this.props.repoID, parentPath).then(res => {
|
||||||
|
try {
|
||||||
|
res.data.dirent_list.forEach((dirent) => {
|
||||||
|
if ((dirent.parent_dir + dirent.name) === path) throw dirent;
|
||||||
|
});
|
||||||
|
} catch (dirent) {
|
||||||
|
let dirent = new Dirent(dirent);
|
||||||
|
this.setState({ currentFolderDirent: dirent });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onFileTagChanged = (dirent, direntPath) => {
|
onFileTagChanged = (dirent, direntPath) => {
|
||||||
this.updateDetailView(dirent, direntPath);
|
this.updateDetailView(dirent, direntPath);
|
||||||
this.props.onFileTagChanged(dirent, direntPath);
|
this.props.onFileTagChanged(dirent, direntPath);
|
||||||
@@ -98,9 +134,26 @@ class DirentDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { dirent } = this.props;
|
let { dirent, path, currentRepoInfo } = this.props;
|
||||||
let smallIconUrl = Utils.getDirentIcon(dirent);
|
let smallIconUrl, bigIconUrl, direntName;
|
||||||
let bigIconUrl = Utils.getDirentIcon(dirent, true);
|
let folderDirent = this.state.currentFolderDirent;
|
||||||
|
|
||||||
|
if (dirent.name) {
|
||||||
|
// selected something
|
||||||
|
smallIconUrl = Utils.getDirentIcon(dirent);
|
||||||
|
bigIconUrl = Utils.getDirentIcon(dirent, true);
|
||||||
|
direntName = dirent.name;
|
||||||
|
} else if (!dirent.name && path === '/') {
|
||||||
|
// seleted nothing and parent is repo
|
||||||
|
smallIconUrl = Utils.getLibIconUrl(currentRepoInfo);
|
||||||
|
bigIconUrl = Utils.getLibIconUrl(currentRepoInfo, true);
|
||||||
|
direntName = currentRepoInfo.repo_name;
|
||||||
|
} else if (!dirent.name && path !== '/') {
|
||||||
|
// select nothing and parent is folder
|
||||||
|
smallIconUrl = folderDirent && Utils.getDirentIcon(folderDirent);
|
||||||
|
bigIconUrl = folderDirent && Utils.getDirentIcon(folderDirent, true);
|
||||||
|
direntName = folderDirent && folderDirent.name;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="detail-container">
|
<div className="detail-container">
|
||||||
@@ -108,7 +161,7 @@ class DirentDetail extends React.Component {
|
|||||||
<div className="detail-control sf2-icon-x1" onClick={this.props.onItemDetailsClose}></div>
|
<div className="detail-control sf2-icon-x1" onClick={this.props.onItemDetailsClose}></div>
|
||||||
<div className="detail-title dirent-title">
|
<div className="detail-title dirent-title">
|
||||||
<img src={smallIconUrl} width="24" height="24" alt="" />{' '}
|
<img src={smallIconUrl} width="24" height="24" alt="" />{' '}
|
||||||
<span className="name ellipsis" title={dirent.name}>{dirent.name}</span>
|
<span className="name ellipsis" title={direntName}>{direntName}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="detail-body dirent-info">
|
<div className="detail-body dirent-info">
|
||||||
@@ -121,7 +174,7 @@ class DirentDetail extends React.Component {
|
|||||||
repoInfo={this.state.repoInfo}
|
repoInfo={this.state.repoInfo}
|
||||||
path={this.props.path}
|
path={this.props.path}
|
||||||
repoID={this.props.repoID}
|
repoID={this.props.repoID}
|
||||||
dirent={this.props.dirent}
|
dirent={this.props.dirent || folderDirent}
|
||||||
direntType={this.state.direntType}
|
direntType={this.state.direntType}
|
||||||
direntDetail={this.state.direntDetail}
|
direntDetail={this.state.direntDetail}
|
||||||
fileTagList={this.state.fileTagList}
|
fileTagList={this.state.fileTagList}
|
||||||
|
@@ -21,11 +21,16 @@ class ViewModeToolbar extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
let baseClass = 'btn btn-secondary btn-icon sf-view-mode-btn ';
|
let baseClass = 'btn btn-secondary btn-icon sf-view-mode-btn ';
|
||||||
return (
|
return (
|
||||||
<div className="view-mode btn-group">
|
<React.Fragment>
|
||||||
<button className={`${baseClass} sf2-icon-list-view ${this.props.currentMode === 'list' ? 'current-mode' : ''}`} id='list' title={gettext('List')} onClick={this.switchViewMode}></button>
|
<div className="view-mode btn-group">
|
||||||
{/* <button className={`${baseClass} sf2-icon-grid-view ${this.props.currentMode === 'grid' ? 'current-mode' : ''}`} id='grid' title={gettext('Grid')} onClick={this.switchViewMode}></button> */}
|
<button className={`${baseClass} sf2-icon-list-view ${this.props.currentMode === 'list' ? 'current-mode' : ''}`} id='list' title={gettext('List')} onClick={this.switchViewMode}></button>
|
||||||
<button className={`${baseClass} sf2-icon-two-columns ${this.props.currentMode === 'column' ? 'current-mode' : ''}`} id='column' title={gettext('Column')} onClick={this.switchViewMode}></button>
|
{/* <button className={`${baseClass} sf2-icon-grid-view ${this.props.currentMode === 'grid' ? 'current-mode' : ''}`} id='grid' title={gettext('Grid')} onClick={this.switchViewMode}></button> */}
|
||||||
</div>
|
<button className={`${baseClass} sf2-icon-two-columns ${this.props.currentMode === 'column' ? 'current-mode' : ''}`} id='column' title={gettext('Column')} onClick={this.switchViewMode}></button>
|
||||||
|
</div>
|
||||||
|
<div className="dirent-detail-btn btn-group">
|
||||||
|
<button className={`${baseClass} ml-1 fas fa-info`} id='detail' title={gettext('Detail')} onClick={this.switchViewMode}></button>
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
line-height: 2.5rem;
|
line-height: 2.5rem;
|
||||||
background-color: #f9f9f9;
|
background-color: #f9f9f9;
|
||||||
border-bottom: 1px solid #e8e8e8;
|
border-bottom: 1px solid #e8e8e8;
|
||||||
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-header .detail-control {
|
.detail-header .detail-control {
|
||||||
|
@@ -52,6 +52,7 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
background: #f4f4f7;
|
background: #f4f4f7;
|
||||||
border-bottom: 1px solid #e8e8e8;
|
border-bottom: 1px solid #e8e8e8;
|
||||||
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
@@ -140,8 +141,30 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.cur-view-detail {
|
.cur-view-detail {
|
||||||
flex: 0 0 20rem;
|
display: block;
|
||||||
display: flex;
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
width: 300px;
|
||||||
|
height: calc(100% - 50px);
|
||||||
|
box-shadow: -1px 0 3px 0 #ccc;
|
||||||
|
top: 49px;
|
||||||
|
animation: move .5s ease-in-out 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes move {
|
||||||
|
from {
|
||||||
|
right: -500px;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
right: 0px;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cur-view-detail .detail-container {
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for reach/router */
|
/* for reach/router */
|
||||||
|
@@ -61,6 +61,11 @@
|
|||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dirent-detail-btn .sf-view-mode-btn {
|
||||||
|
font-size: 15px;
|
||||||
|
border-radius: 3px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.sf-view-mode-btn.current-mode {
|
.sf-view-mode-btn.current-mode {
|
||||||
background-color: #ccc !important;
|
background-color: #ccc !important;
|
||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
|
@@ -83,7 +83,7 @@ class LibContentContainer extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
currentDirent: null,
|
currentDirent: {},
|
||||||
appMenuType: 'item_op_menu',
|
appMenuType: 'item_op_menu',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -286,6 +286,7 @@ class LibContentContainer extends React.Component {
|
|||||||
repoID={repoID}
|
repoID={repoID}
|
||||||
path={this.props.path}
|
path={this.props.path}
|
||||||
dirent={this.state.currentDirent}
|
dirent={this.state.currentDirent}
|
||||||
|
currentRepoInfo={this.props.currentRepoInfo}
|
||||||
onItemDetailsClose={this.onItemDetailsClose}
|
onItemDetailsClose={this.onItemDetailsClose}
|
||||||
onFileTagChanged={this.props.onFileTagChanged}
|
onFileTagChanged={this.props.onFileTagChanged}
|
||||||
/>
|
/>
|
||||||
|
@@ -83,6 +83,10 @@ class LibContentView extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleDirentDetail = () => {
|
||||||
|
this.setState({ isDirentDetailShow: !this.state.isDirentDetailShow });
|
||||||
|
}
|
||||||
|
|
||||||
closeDirentDetail = () => {
|
closeDirentDetail = () => {
|
||||||
this.setState({ isDirentDetailShow: false });
|
this.setState({ isDirentDetailShow: false });
|
||||||
}
|
}
|
||||||
@@ -538,6 +542,10 @@ class LibContentView extends React.Component {
|
|||||||
if (mode === this.state.currentMode) {
|
if (mode === this.state.currentMode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (mode === 'detail') {
|
||||||
|
this.toggleDirentDetail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
cookie.save('seafile-view-mode', mode);
|
cookie.save('seafile-view-mode', mode);
|
||||||
let path = this.state.path;
|
let path = this.state.path;
|
||||||
if (this.state.currentMode === 'column' && this.state.isViewFile) {
|
if (this.state.currentMode === 'column' && this.state.isViewFile) {
|
||||||
|
Reference in New Issue
Block a user