2018-12-11 17:52:19 +08:00
|
|
|
import React, { Fragment } from 'react';
|
2018-11-27 14:47:19 +08:00
|
|
|
import PropTypes from 'prop-types';
|
2024-11-27 10:59:39 +08:00
|
|
|
import { UncontrolledTooltip } from 'reactstrap';
|
2022-12-29 12:21:47 +08:00
|
|
|
import { Link } from '@gatsbyjs/reach-router';
|
2024-09-14 16:31:32 +08:00
|
|
|
import DirOperationToolBar from '../../components/toolbar/dir-operation-toolbar';
|
|
|
|
import MetadataViewName from '../../metadata/components/metadata-view-name';
|
2024-11-22 17:11:55 +08:00
|
|
|
import TagViewName from '../../tag/components/tag-view-name';
|
2018-11-27 14:47:19 +08:00
|
|
|
import { siteRoot, gettext } from '../../utils/constants';
|
2019-06-04 16:18:32 +08:00
|
|
|
import { Utils } from '../../utils/utils';
|
2024-06-29 17:58:27 +08:00
|
|
|
import { PRIVATE_FILE_TYPE } from '../../constants';
|
2024-11-27 10:59:39 +08:00
|
|
|
import { debounce } from '../../metadata/utils/common';
|
2025-01-08 14:40:28 +08:00
|
|
|
import { EVENT_BUS_TYPE } from '../../metadata/constants';
|
2025-01-07 16:10:00 +08:00
|
|
|
import { ALL_TAGS_ID } from '../../tag/constants';
|
2018-11-27 14:47:19 +08:00
|
|
|
|
|
|
|
const propTypes = {
|
2024-07-27 12:04:33 +08:00
|
|
|
currentRepoInfo: PropTypes.object.isRequired,
|
2024-05-28 18:17:53 +08:00
|
|
|
repoID: PropTypes.string.isRequired,
|
2018-11-27 14:47:19 +08:00
|
|
|
repoName: PropTypes.string.isRequired,
|
|
|
|
currentPath: PropTypes.string.isRequired,
|
|
|
|
onPathClick: PropTypes.func.isRequired,
|
2018-12-13 14:40:09 +08:00
|
|
|
onTabNavClick: PropTypes.func,
|
|
|
|
pathPrefix: PropTypes.array,
|
2019-03-15 10:10:24 +08:00
|
|
|
fileTags: PropTypes.array.isRequired,
|
2024-05-28 18:17:53 +08:00
|
|
|
toggleTreePanel: PropTypes.func.isRequired,
|
|
|
|
repoEncrypted: PropTypes.bool.isRequired,
|
|
|
|
enableDirPrivateShare: PropTypes.bool.isRequired,
|
|
|
|
userPerm: PropTypes.string.isRequired,
|
|
|
|
isGroupOwnedRepo: PropTypes.bool.isRequired,
|
|
|
|
showShareBtn: PropTypes.bool.isRequired,
|
|
|
|
onAddFile: PropTypes.func.isRequired,
|
|
|
|
onAddFolder: PropTypes.func.isRequired,
|
|
|
|
onUploadFile: PropTypes.func.isRequired,
|
|
|
|
onUploadFolder: PropTypes.func.isRequired,
|
|
|
|
direntList: PropTypes.array.isRequired,
|
|
|
|
repoTags: PropTypes.array.isRequired,
|
|
|
|
filePermission: PropTypes.string,
|
|
|
|
onFileTagChanged: PropTypes.func.isRequired,
|
2024-07-27 12:04:33 +08:00
|
|
|
onItemMove: PropTypes.func.isRequired,
|
2024-09-09 15:58:33 +08:00
|
|
|
loadDirentList: PropTypes.func.isRequired,
|
2018-11-27 14:47:19 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
class DirPath extends React.Component {
|
|
|
|
|
2024-07-27 12:04:33 +08:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
dropTargetPath: '',
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-11-27 14:47:19 +08:00
|
|
|
onPathClick = (e) => {
|
2019-06-04 16:18:32 +08:00
|
|
|
let path = Utils.getEventData(e, 'path');
|
2018-11-27 14:47:19 +08:00
|
|
|
this.props.onPathClick(path);
|
2023-09-13 08:40:50 +08:00
|
|
|
};
|
2018-11-27 14:47:19 +08:00
|
|
|
|
2019-08-02 20:53:39 +08:00
|
|
|
onTabNavClick = (e, tabName, id) => {
|
2020-11-02 13:56:35 +08:00
|
|
|
if (window.uploader &&
|
|
|
|
window.uploader.isUploadProgressDialogShow &&
|
2019-08-02 20:53:39 +08:00
|
|
|
window.uploader.totalProgress !== 100) {
|
2020-11-02 13:56:35 +08:00
|
|
|
if (!window.confirm(gettext('A file is being uploaded. Are you sure you want to leave this page?'))) {
|
|
|
|
e.preventDefault();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
window.uploader.isUploadProgressDialogShow = false;
|
2019-08-02 20:53:39 +08:00
|
|
|
}
|
2018-12-13 14:40:09 +08:00
|
|
|
this.props.onTabNavClick(tabName, id);
|
2023-09-13 08:40:50 +08:00
|
|
|
};
|
2018-12-13 14:40:09 +08:00
|
|
|
|
2024-07-27 12:04:33 +08:00
|
|
|
onDragEnter = (e) => {
|
|
|
|
e.preventDefault();
|
2024-08-12 14:25:37 +08:00
|
|
|
if (Utils.isIEBrowser()) {
|
2024-07-27 12:04:33 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
this.setState({
|
|
|
|
dropTargetPath: e.target.dataset.path,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
onDragLeave = (e) => {
|
|
|
|
e.preventDefault();
|
2024-08-12 14:25:37 +08:00
|
|
|
if (Utils.isIEBrowser()) {
|
2024-07-27 12:04:33 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
this.setState({
|
|
|
|
dropTargetPath: '',
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
onDragOver = (e) => {
|
2024-08-12 14:25:37 +08:00
|
|
|
if (Utils.isIEBrowser()) {
|
2024-07-27 12:04:33 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
e.preventDefault();
|
|
|
|
e.dataTransfer.dropEffect = 'move';
|
|
|
|
};
|
|
|
|
|
|
|
|
onDrop = (e) => {
|
2024-08-12 14:25:37 +08:00
|
|
|
if (Utils.isIEBrowser()) {
|
2024-07-27 12:04:33 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e.dataTransfer.files.length) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let selectedPath = Utils.getEventData(e, 'path');
|
2024-07-31 10:09:07 +08:00
|
|
|
let dragStartItemsData = e.dataTransfer.getData('application/drag-item-info');
|
|
|
|
dragStartItemsData = JSON.parse(dragStartItemsData);
|
|
|
|
|
|
|
|
if (Array.isArray(dragStartItemsData)) {
|
|
|
|
this.props.onItemsMove(this.props.currentRepoInfo, selectedPath);
|
|
|
|
} else {
|
|
|
|
let { nodeDirent, nodeParentPath } = dragStartItemsData;
|
|
|
|
this.props.onItemMove(this.props.currentRepoInfo, nodeDirent, selectedPath, nodeParentPath);
|
|
|
|
}
|
|
|
|
|
2024-07-27 12:04:33 +08:00
|
|
|
this.setState({
|
|
|
|
dropTargetPath: '',
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2025-01-03 15:11:06 +08:00
|
|
|
handleRefresh = debounce(() => {
|
2024-11-27 10:59:39 +08:00
|
|
|
window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.RELOAD_DATA);
|
|
|
|
}, 200);
|
|
|
|
|
2025-01-03 15:11:06 +08:00
|
|
|
turnViewPathToLink = (pathList) => {
|
|
|
|
if (!Array.isArray(pathList) || pathList.length === 0) return null;
|
|
|
|
const [, , viewId, children] = pathList;
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<span className="path-split">/</span>
|
|
|
|
<span className="path-item">{gettext('Views')}</span>
|
|
|
|
<span className="path-split">/</span>
|
2025-01-08 14:40:28 +08:00
|
|
|
<span className="path-item" role={children ? 'button' : null} onClick={children ? this.handleRefresh : () => {}}>
|
2025-01-03 15:11:06 +08:00
|
|
|
<MetadataViewName id={viewId} />
|
|
|
|
</span>
|
|
|
|
{children && (
|
|
|
|
<>
|
|
|
|
<span className="path-split">/</span>
|
|
|
|
<span className="path-item">{children}</span>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
<div className="path-item-refresh" id="sf-metadata-view-refresh" onClick={this.handleRefresh}>
|
|
|
|
<i className="sf3-font sf3-font-refresh"></i>
|
|
|
|
<UncontrolledTooltip target="sf-metadata-view-refresh" placement="bottom">
|
|
|
|
{gettext('Refresh the view')}
|
|
|
|
</UncontrolledTooltip>
|
|
|
|
</div>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
turnTagPathToLink = (pathList) => {
|
|
|
|
if (!Array.isArray(pathList) || pathList.length === 0) return null;
|
2025-01-07 16:10:00 +08:00
|
|
|
const [, , tagId, children] = pathList;
|
|
|
|
const canSelectAllTags = tagId === ALL_TAGS_ID && !!children;
|
2025-01-03 15:11:06 +08:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<span className="path-split">/</span>
|
|
|
|
<span className="path-item">{gettext('Tags')}</span>
|
|
|
|
<span className="path-split">/</span>
|
2025-01-07 16:10:00 +08:00
|
|
|
<TagViewName id={tagId} canSelectAllTags={canSelectAllTags} />
|
|
|
|
{children && (
|
|
|
|
<>
|
|
|
|
<span className="path-split">/</span>
|
|
|
|
<span className="path-item">{children}</span>
|
|
|
|
</>
|
|
|
|
)}
|
2025-01-03 15:11:06 +08:00
|
|
|
</>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2018-11-27 14:47:19 +08:00
|
|
|
turnPathToLink = (path) => {
|
|
|
|
path = path[path.length - 1] === '/' ? path.slice(0, path.length - 1) : path;
|
2025-01-03 15:11:06 +08:00
|
|
|
const pathList = path.split('/');
|
|
|
|
if (pathList.includes(PRIVATE_FILE_TYPE.FILE_EXTENDED_PROPERTIES)) return this.turnViewPathToLink(pathList);
|
|
|
|
if (pathList.includes(PRIVATE_FILE_TYPE.TAGS_PROPERTIES)) return this.turnTagPathToLink(pathList);
|
2018-11-27 14:47:19 +08:00
|
|
|
let nodePath = '';
|
|
|
|
let pathElem = pathList.map((item, index) => {
|
2025-01-03 15:11:06 +08:00
|
|
|
if (item === '') return null;
|
2024-07-22 09:45:08 +08:00
|
|
|
if (index === (pathList.length - 1)) {
|
2018-11-27 14:47:19 +08:00
|
|
|
return (
|
2019-07-23 15:53:25 +08:00
|
|
|
<Fragment key={index}>
|
|
|
|
<span className="path-split">/</span>
|
2024-09-10 11:46:50 +08:00
|
|
|
<DirOperationToolBar
|
|
|
|
path={this.props.currentPath}
|
|
|
|
repoID={this.props.repoID}
|
|
|
|
repoName={this.props.repoName}
|
|
|
|
repoEncrypted={this.props.repoEncrypted}
|
|
|
|
direntList={this.props.direntList}
|
|
|
|
showShareBtn={this.props.showShareBtn}
|
|
|
|
enableDirPrivateShare={this.props.enableDirPrivateShare}
|
|
|
|
userPerm={this.props.userPerm}
|
|
|
|
isGroupOwnedRepo={this.props.isGroupOwnedRepo}
|
|
|
|
onAddFile={this.props.onAddFile}
|
|
|
|
onAddFolder={this.props.onAddFolder}
|
|
|
|
onUploadFile={this.props.onUploadFile}
|
|
|
|
onUploadFolder={this.props.onUploadFolder}
|
|
|
|
loadDirentList={this.props.loadDirentList}
|
|
|
|
>
|
|
|
|
<span className="path-file-name">{item}</span>
|
|
|
|
</DirOperationToolBar>
|
2019-07-23 15:53:25 +08:00
|
|
|
</Fragment>
|
2018-11-27 14:47:19 +08:00
|
|
|
);
|
|
|
|
} else {
|
|
|
|
nodePath += '/' + item;
|
|
|
|
return (
|
2019-07-15 14:42:18 +08:00
|
|
|
<Fragment key={index} >
|
2018-11-27 14:47:19 +08:00
|
|
|
<span className="path-split">/</span>
|
2024-07-27 12:04:33 +08:00
|
|
|
<span
|
|
|
|
className={`path-item ${nodePath === this.state.dropTargetPath ? 'path-item-drop' : ''}`}
|
|
|
|
data-path={nodePath} onClick={this.onPathClick}
|
|
|
|
onDragEnter={this.onDragEnter}
|
|
|
|
onDragLeave={this.onDragLeave}
|
|
|
|
onDragOver={this.onDragOver}
|
|
|
|
onDrop={this.onDrop}
|
|
|
|
role="button">
|
|
|
|
{item}
|
|
|
|
</span>
|
2019-07-15 14:42:18 +08:00
|
|
|
</Fragment>
|
2018-11-27 14:47:19 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return pathElem;
|
2023-09-13 08:40:50 +08:00
|
|
|
};
|
2018-11-27 14:47:19 +08:00
|
|
|
|
|
|
|
render() {
|
2025-01-03 15:11:06 +08:00
|
|
|
const { currentPath, repoName } = this.props;
|
|
|
|
const pathElem = this.turnPathToLink(currentPath);
|
2018-11-27 14:47:19 +08:00
|
|
|
return (
|
2024-05-27 16:47:19 +08:00
|
|
|
<div className="path-container dir-view-path">
|
2024-06-17 22:17:47 +08:00
|
|
|
<span className="cur-view-path-btn mr-1" onClick={this.props.toggleTreePanel}>
|
2024-06-13 15:27:20 +08:00
|
|
|
<span className="sf3-font-side-bar sf3-font"></span>
|
|
|
|
</span>
|
2018-12-13 14:40:09 +08:00
|
|
|
{this.props.pathPrefix && this.props.pathPrefix.map((item, index) => {
|
|
|
|
return (
|
|
|
|
<Fragment key={index}>
|
2024-05-27 16:47:19 +08:00
|
|
|
<Link to={item.url} className="path-item normal" onClick={(e) => this.onTabNavClick(e, item.name, item.id)}>{gettext(item.showName)}</Link>
|
2018-12-11 17:52:19 +08:00
|
|
|
<span className="path-split">/</span>
|
2018-12-13 14:40:09 +08:00
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
})}
|
|
|
|
{this.props.pathPrefix && this.props.pathPrefix.length === 0 && (
|
|
|
|
<Fragment>
|
2024-05-27 16:47:19 +08:00
|
|
|
<Link to={siteRoot + 'libraries/'} className="path-item normal" onClick={(e) => this.onTabNavClick(e, 'libraries')}>{gettext('Files')}</Link>
|
2018-12-13 14:40:09 +08:00
|
|
|
<span className="path-split">/</span>
|
|
|
|
</Fragment>
|
2019-03-15 10:10:24 +08:00
|
|
|
)}
|
2018-12-13 14:40:09 +08:00
|
|
|
{!this.props.pathPrefix && (
|
|
|
|
<Fragment>
|
2024-05-27 16:47:19 +08:00
|
|
|
<Link to={siteRoot + 'libraries/'} className="path-item normal" onClick={(e) => this.onTabNavClick(e, 'libraries')}>{gettext('Files')}</Link>
|
2018-12-13 14:40:09 +08:00
|
|
|
<span className="path-split">/</span>
|
|
|
|
</Fragment>
|
|
|
|
)}
|
2024-09-09 11:55:41 +08:00
|
|
|
{(currentPath === '/' || currentPath === '') ?
|
2024-05-27 16:47:19 +08:00
|
|
|
<DirOperationToolBar
|
|
|
|
path={this.props.currentPath}
|
|
|
|
repoID={this.props.repoID}
|
|
|
|
repoName={this.props.repoName}
|
|
|
|
repoEncrypted={this.props.repoEncrypted}
|
|
|
|
direntList={this.props.direntList}
|
|
|
|
showShareBtn={this.props.showShareBtn}
|
|
|
|
enableDirPrivateShare={this.props.enableDirPrivateShare}
|
|
|
|
userPerm={this.props.userPerm}
|
|
|
|
isGroupOwnedRepo={this.props.isGroupOwnedRepo}
|
|
|
|
onAddFile={this.props.onAddFile}
|
|
|
|
onAddFolder={this.props.onAddFolder}
|
|
|
|
onUploadFile={this.props.onUploadFile}
|
|
|
|
onUploadFolder={this.props.onUploadFolder}
|
2024-09-09 15:58:33 +08:00
|
|
|
loadDirentList={this.props.loadDirentList}
|
2024-05-27 16:47:19 +08:00
|
|
|
>
|
|
|
|
<span className="path-repo-name">{repoName}</span>
|
|
|
|
</DirOperationToolBar> :
|
2024-05-27 19:46:40 +08:00
|
|
|
<span className="path-item" data-path="/" onClick={this.onPathClick} role="button">{repoName}</span>
|
2018-11-27 14:47:19 +08:00
|
|
|
}
|
2024-09-09 11:55:41 +08:00
|
|
|
{pathElem}
|
2018-11-27 14:47:19 +08:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DirPath.propTypes = propTypes;
|
|
|
|
|
|
|
|
export default DirPath;
|