1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-24 04:48:03 +00:00

refactor: download (#7388)

* refactor: download

* feat: update code

* feat: rebase bug

* feat: rebase bug

---------

Co-authored-by: 杨国璇 <ygx@Hello-word.local>
Co-authored-by: 杨国璇 <ygx@192.168.1.9>
Co-authored-by: 杨国璇 <ygx@MacBookPro.lan>
This commit is contained in:
杨国璇
2025-05-29 16:20:20 +08:00
committed by GitHub
parent d7b10849da
commit 12840046cd
12 changed files with 346 additions and 476 deletions

View File

@@ -20,4 +20,7 @@ export const EVENT_BUS_TYPE = {
TAGS_DATA: 'tags_data', TAGS_DATA: 'tags_data',
SELECT_TAG: 'select_tag', SELECT_TAG: 'select_tag',
UPDATE_SELECTED_TAG: 'update_selected_tag', UPDATE_SELECTED_TAG: 'update_selected_tag',
// download file
DOWNLOAD_FILE: 'download_file',
}; };

View File

@@ -1,6 +1,6 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { siteRoot, username, enableSeadoc, thumbnailDefaultSize, thumbnailSizeForOriginal, gettext, fileServerRoot, enableWhiteboard, useGoFileserver, enableExcalidraw } from '../../utils/constants'; import { siteRoot, username, enableSeadoc, thumbnailDefaultSize, thumbnailSizeForOriginal, gettext, fileServerRoot, enableWhiteboard, enableExcalidraw } from '../../utils/constants';
import { Utils } from '../../utils/utils'; import { Utils } from '../../utils/utils';
import { seafileAPI } from '../../utils/seafile-api'; import { seafileAPI } from '../../utils/seafile-api';
import URLDecorator from '../../utils/url-decorator'; import URLDecorator from '../../utils/url-decorator';
@@ -14,7 +14,6 @@ import TextTranslation from '../../utils/text-translation';
import MoveDirentDialog from '../dialog/move-dirent-dialog'; import MoveDirentDialog from '../dialog/move-dirent-dialog';
import CopyDirentDialog from '../dialog/copy-dirent-dialog'; import CopyDirentDialog from '../dialog/copy-dirent-dialog';
import ShareDialog from '../dialog/share-dialog'; import ShareDialog from '../dialog/share-dialog';
import ZipDownloadDialog from '../dialog/zip-download-dialog';
import Rename from '../../components/dialog/rename-dirent'; import Rename from '../../components/dialog/rename-dirent';
import CreateFile from '../dialog/create-file-dialog'; import CreateFile from '../dialog/create-file-dialog';
import CreateFolder from '../dialog/create-folder-dialog'; import CreateFolder from '../dialog/create-folder-dialog';
@@ -24,6 +23,7 @@ import imageAPI from '../../utils/image-api';
import FileAccessLog from '../dialog/file-access-log'; import FileAccessLog from '../dialog/file-access-log';
import { EVENT_BUS_TYPE } from '../common/event-bus-type'; import { EVENT_BUS_TYPE } from '../common/event-bus-type';
import EmptyTip from '../empty-tip'; import EmptyTip from '../empty-tip';
import { Dirent } from '../../models';
import '../../css/grid-view.css'; import '../../css/grid-view.css';
@@ -78,7 +78,6 @@ class DirentGridView extends React.Component {
isShareDialogShow: false, isShareDialogShow: false,
isMoveDialogShow: false, isMoveDialogShow: false,
isCopyDialogShow: false, isCopyDialogShow: false,
isZipDialogOpen: false,
isRenameDialogShow: false, isRenameDialogShow: false,
isCreateFolderDialogShow: false, isCreateFolderDialogShow: false,
isCreateFileDialogShow: false, isCreateFileDialogShow: false,
@@ -458,39 +457,10 @@ class DirentGridView extends React.Component {
return path === '/' ? path + dirent.name : path + '/' + dirent.name; return path === '/' ? path + dirent.name : path + '/' + dirent.name;
}; };
closeZipDialog = () => {
this.setState({
isZipDialogOpen: false
});
};
onItemsDownload = () => { onItemsDownload = () => {
let { path, repoID, selectedDirentList } = this.props; const { path, selectedDirentList, eventBus } = this.props;
if (selectedDirentList.length === 1 && !selectedDirentList[0].isDir()) { const direntList = selectedDirentList.map(dirent => dirent instanceof Dirent ? dirent.toJson() : dirent);
let direntPath = Utils.joinPath(path, selectedDirentList[0].name); eventBus.dispatch(EVENT_BUS_TYPE.DOWNLOAD_FILE, path, direntList);
let url = URLDecorator.getUrl({ type: 'download_file_url', repoID: repoID, filePath: direntPath });
location.href = url;
return;
}
let selectedDirentNames = selectedDirentList.map(dirent => {
return dirent.name;
});
if (useGoFileserver) {
seafileAPI.zipDownload(repoID, path, selectedDirentNames).then((res) => {
const zipToken = res.data['zip_token'];
location.href = `${fileServerRoot}zip/${zipToken}`;
}).catch((error) => {
let errorMsg = Utils.getErrorMsg(error);
toaster.danger(errorMsg);
});
} else {
this.setState({
isZipDialogOpen: true,
downloadItems: selectedDirentNames
});
}
}; };
onCreateFolderToggle = () => { onCreateFolderToggle = () => {
@@ -999,16 +969,6 @@ class DirentGridView extends React.Component {
onAddFolder={this.props.onAddFolder} onAddFolder={this.props.onAddFolder}
/> />
} }
{this.state.isZipDialogOpen &&
<ModalPortal>
<ZipDownloadDialog
repoID={this.props.repoID}
path={this.props.path}
target={this.state.downloadItems}
toggleDialog={this.closeZipDialog}
/>
</ModalPortal>
}
{this.state.isCopyDialogShow && {this.state.isCopyDialogShow &&
<CopyDirentDialog <CopyDirentDialog
path={this.props.path} path={this.props.path}

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { DropdownItem } from 'reactstrap'; import { DropdownItem } from 'reactstrap';
import { gettext, siteRoot, mediaUrl, username, useGoFileserver, fileServerRoot, enableVideoThumbnail, enablePDFThumbnail } from '../../utils/constants'; import { gettext, siteRoot, mediaUrl, username, enableVideoThumbnail, enablePDFThumbnail } from '../../utils/constants';
import { Utils } from '../../utils/utils'; import { Utils } from '../../utils/utils';
import { seafileAPI } from '../../utils/seafile-api'; import { seafileAPI } from '../../utils/seafile-api';
import URLDecorator from '../../utils/url-decorator'; import URLDecorator from '../../utils/url-decorator';
@@ -14,11 +14,12 @@ import ModalPortal from '../modal-portal';
import MoveDirentDialog from '../dialog/move-dirent-dialog'; import MoveDirentDialog from '../dialog/move-dirent-dialog';
import CopyDirentDialog from '../dialog/copy-dirent-dialog'; import CopyDirentDialog from '../dialog/copy-dirent-dialog';
import ShareDialog from '../dialog/share-dialog'; import ShareDialog from '../dialog/share-dialog';
import ZipDownloadDialog from '../dialog/zip-download-dialog';
import LibSubFolderPermissionDialog from '../dialog/lib-sub-folder-permission-dialog'; import LibSubFolderPermissionDialog from '../dialog/lib-sub-folder-permission-dialog';
import FileAccessLog from '../dialog/file-access-log'; import FileAccessLog from '../dialog/file-access-log';
import toaster from '../toast'; import toaster from '../toast';
import MobileItemMenu from '../../components/mobile-item-menu'; import MobileItemMenu from '../../components/mobile-item-menu';
import { EVENT_BUS_TYPE } from '../common/event-bus-type';
import { Dirent } from '../../models';
import '../../css/dirent-list-item.css'; import '../../css/dirent-list-item.css';
@@ -27,6 +28,7 @@ const propTypes = {
repoID: PropTypes.string.isRequired, repoID: PropTypes.string.isRequired,
isItemFreezed: PropTypes.bool.isRequired, isItemFreezed: PropTypes.bool.isRequired,
dirent: PropTypes.object.isRequired, dirent: PropTypes.object.isRequired,
eventBus: PropTypes.object.isRequired,
onItemClick: PropTypes.func.isRequired, onItemClick: PropTypes.func.isRequired,
freezeItem: PropTypes.func.isRequired, freezeItem: PropTypes.func.isRequired,
unfreezeItem: PropTypes.func.isRequired, unfreezeItem: PropTypes.func.isRequired,
@@ -80,7 +82,6 @@ class DirentListItem extends React.Component {
dirent, dirent,
isOperationShow: false, isOperationShow: false,
highlight: false, highlight: false,
isZipDialogOpen: false,
isFileAccessLogDialogOpen: false, isFileAccessLogDialogOpen: false,
isMoveDialogShow: false, isMoveDialogShow: false,
isCopyDialogShow: false, isCopyDialogShow: false,
@@ -524,36 +525,10 @@ class DirentListItem extends React.Component {
onItemDownload = (e) => { onItemDownload = (e) => {
e.preventDefault(); e.preventDefault();
e.nativeEvent.stopImmediatePropagation(); e.nativeEvent.stopImmediatePropagation();
let dirent = this.state.dirent; const { path, eventBus } = this.props;
let repoID = this.props.repoID; const { dirent } = this.state;
let direntPath = this.getDirentPath(dirent); const direntList = dirent instanceof Dirent ? [dirent.toJson()] : [dirent];
if (dirent.type === 'dir') { eventBus.dispatch(EVENT_BUS_TYPE.DOWNLOAD_FILE, path, direntList);
if (!useGoFileserver) {
this.setState({
isZipDialogOpen: true
});
} else {
seafileAPI.zipDownload(repoID, this.props.path, this.state.dirent.name).then((res) => {
const zipToken = res.data['zip_token'];
location.href = `${fileServerRoot}zip/${zipToken}`;
}).catch((error) => {
let errorMsg = Utils.getErrorMsg(error);
this.setState({
isLoading: false,
errorMsg: errorMsg
});
});
}
} else {
let url = URLDecorator.getUrl({ type: 'download_file_url', repoID: repoID, filePath: direntPath });
location.href = url;
}
};
closeZipDialog = () => {
this.setState({
isZipDialogOpen: false
});
}; };
getDirentPath = (dirent) => { getDirentPath = (dirent) => {
@@ -973,16 +948,6 @@ class DirentListItem extends React.Component {
/> />
</ModalPortal> </ModalPortal>
} }
{this.state.isZipDialogOpen &&
<ModalPortal>
<ZipDownloadDialog
repoID={this.props.repoID}
path={this.props.path}
target={this.state.dirent.name}
toggleDialog={this.closeZipDialog}
/>
</ModalPortal>
}
{this.state.isShareDialogShow && {this.state.isShareDialogShow &&
<ModalPortal> <ModalPortal>
<ShareDialog <ShareDialog

View File

@@ -1,16 +1,14 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import { siteRoot, gettext, username, enableSeadoc, thumbnailSizeForOriginal, thumbnailDefaultSize, fileServerRoot, enableWhiteboard, useGoFileserver, enableExcalidraw } from '../../utils/constants'; import { siteRoot, gettext, username, enableSeadoc, thumbnailSizeForOriginal, thumbnailDefaultSize, fileServerRoot, enableWhiteboard, enableExcalidraw } from '../../utils/constants';
import { Utils } from '../../utils/utils'; import { Utils } from '../../utils/utils';
import TextTranslation from '../../utils/text-translation'; import TextTranslation from '../../utils/text-translation';
import URLDecorator from '../../utils/url-decorator';
import toaster from '../toast'; import toaster from '../toast';
import ModalPortal from '../modal-portal'; import ModalPortal from '../modal-portal';
import CreateFile from '../dialog/create-file-dialog'; import CreateFile from '../dialog/create-file-dialog';
import CreateFolder from '../dialog/create-folder-dialog'; import CreateFolder from '../dialog/create-folder-dialog';
import ImageDialog from '../dialog/image-dialog'; import ImageDialog from '../dialog/image-dialog';
import ZipDownloadDialog from '../dialog/zip-download-dialog';
import MoveDirentDialog from '../dialog/move-dirent-dialog'; import MoveDirentDialog from '../dialog/move-dirent-dialog';
import CopyDirentDialog from '../dialog/copy-dirent-dialog'; import CopyDirentDialog from '../dialog/copy-dirent-dialog';
import DirentListItem from './dirent-list-item'; import DirentListItem from './dirent-list-item';
@@ -22,6 +20,7 @@ import EmptyTip from '../empty-tip';
import imageAPI from '../../utils/image-api'; import imageAPI from '../../utils/image-api';
import { seafileAPI } from '../../utils/seafile-api'; import { seafileAPI } from '../../utils/seafile-api';
import FixedWidthTable from '../common/fixed-width-table'; import FixedWidthTable from '../common/fixed-width-table';
import { Dirent } from '../../models';
const propTypes = { const propTypes = {
path: PropTypes.string.isRequired, path: PropTypes.string.isRequired,
@@ -76,7 +75,6 @@ class DirentListView extends React.Component {
isCreateFolderDialogShow: false, isCreateFolderDialogShow: false,
isMoveDialogShow: false, isMoveDialogShow: false,
isCopyDialogShow: false, isCopyDialogShow: false,
isProgressDialogShow: false,
downloadItems: [], downloadItems: [],
isMultipleOperation: true, isMultipleOperation: true,
activeDirent: null, activeDirent: null,
@@ -329,38 +327,9 @@ class DirentListView extends React.Component {
}; };
onItemsDownload = () => { onItemsDownload = () => {
let { path, repoID, selectedDirentList } = this.props; const { path, selectedDirentList, eventBus } = this.props;
if (selectedDirentList.length) { const direntList = selectedDirentList.map(dirent => dirent instanceof Dirent ? dirent.toJson() : dirent);
if (selectedDirentList.length === 1 && !selectedDirentList[0].isDir()) { eventBus.dispatch(EVENT_BUS_TYPE.DOWNLOAD_FILE, path, direntList);
let direntPath = Utils.joinPath(path, selectedDirentList[0].name);
let url = URLDecorator.getUrl({ type: 'download_file_url', repoID: repoID, filePath: direntPath });
location.href = url;
return;
}
let selectedDirentNames = selectedDirentList.map(dirent => {
return dirent.name;
});
if (useGoFileserver) {
seafileAPI.zipDownload(repoID, path, selectedDirentNames).then((res) => {
const zipToken = res.data['zip_token'];
location.href = `${fileServerRoot}zip/${zipToken}`;
}).catch((error) => {
let errorMsg = Utils.getErrorMsg(error);
toaster.danger(errorMsg);
});
} else {
this.setState({
isProgressDialogShow: true,
downloadItems: selectedDirentNames
});
}
}
};
onCloseZipDownloadDialog = () => {
this.setState({ isProgressDialogShow: false });
}; };
// common contextmenu handle // common contextmenu handle
@@ -813,6 +782,7 @@ class DirentListView extends React.Component {
path={this.props.path} path={this.props.path}
repoID={this.props.repoID} repoID={this.props.repoID}
currentRepoInfo={this.props.currentRepoInfo} currentRepoInfo={this.props.currentRepoInfo}
eventBus={this.props.eventBus}
isAdmin={this.isAdmin} isAdmin={this.isAdmin}
isRepoOwner={this.isRepoOwner} isRepoOwner={this.isRepoOwner}
repoEncrypted={this.repoEncrypted} repoEncrypted={this.repoEncrypted}
@@ -941,14 +911,6 @@ class DirentListView extends React.Component {
onAddFolder={this.props.onAddFolder} onAddFolder={this.props.onAddFolder}
/> />
} }
{this.state.isProgressDialogShow &&
<ZipDownloadDialog
repoID={this.props.repoID}
path={this.props.path}
target={this.state.downloadItems}
toggleDialog={this.onCloseZipDownloadDialog}
/>
}
</Fragment> </Fragment>
</div> </div>
); );

View File

@@ -1,12 +1,11 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { gettext, siteRoot, name, fileServerRoot, useGoFileserver } from '../../utils/constants'; import { gettext, siteRoot, name } from '../../utils/constants';
import { Utils } from '../../utils/utils'; import { Utils } from '../../utils/utils';
import { seafileAPI } from '../../utils/seafile-api'; import { seafileAPI } from '../../utils/seafile-api';
import URLDecorator from '../../utils/url-decorator'; import URLDecorator from '../../utils/url-decorator';
import MoveDirentDialog from '../dialog/move-dirent-dialog'; import MoveDirentDialog from '../dialog/move-dirent-dialog';
import CopyDirentDialog from '../dialog/copy-dirent-dialog'; import CopyDirentDialog from '../dialog/copy-dirent-dialog';
import ZipDownloadDialog from '../dialog/zip-download-dialog';
import ShareDialog from '../dialog/share-dialog'; import ShareDialog from '../dialog/share-dialog';
import Rename from '../dialog/rename-dirent'; import Rename from '../dialog/rename-dirent';
import LibSubFolderPermissionDialog from '../dialog/lib-sub-folder-permission-dialog'; import LibSubFolderPermissionDialog from '../dialog/lib-sub-folder-permission-dialog';
@@ -14,6 +13,8 @@ import ModalPortal from '../modal-portal';
import ItemDropdownMenu from '../dropdown-menu/item-dropdown-menu'; import ItemDropdownMenu from '../dropdown-menu/item-dropdown-menu';
import toaster from '../toast'; import toaster from '../toast';
import FileAccessLog from '../dialog/file-access-log'; import FileAccessLog from '../dialog/file-access-log';
import { Dirent } from '../../models';
import { EVENT_BUS_TYPE } from '../common/event-bus-type';
import '../../css/selected-dirents-toolbar.css'; import '../../css/selected-dirents-toolbar.css';
@@ -23,6 +24,7 @@ const propTypes = {
repoID: PropTypes.string.isRequired, repoID: PropTypes.string.isRequired,
repoEncrypted: PropTypes.bool.isRequired, repoEncrypted: PropTypes.bool.isRequired,
selectedDirentList: PropTypes.array.isRequired, selectedDirentList: PropTypes.array.isRequired,
eventBus: PropTypes.object.isRequired,
onItemsMove: PropTypes.func.isRequired, onItemsMove: PropTypes.func.isRequired,
onItemsCopy: PropTypes.func.isRequired, onItemsCopy: PropTypes.func.isRequired,
onItemsDelete: PropTypes.func.isRequired, onItemsDelete: PropTypes.func.isRequired,
@@ -45,7 +47,6 @@ class SelectedDirentsToolbar extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
isZipDialogOpen: false,
isFileAccessLogDialogOpen: false, isFileAccessLogDialogOpen: false,
isMoveDialogShow: false, isMoveDialogShow: false,
isCopyDialogShow: false, isCopyDialogShow: false,
@@ -71,38 +72,9 @@ class SelectedDirentsToolbar extends React.Component {
}; };
onItemsDownload = () => { onItemsDownload = () => {
let { path, repoID, selectedDirentList } = this.props; const { path, selectedDirentList, eventBus } = this.props;
if (selectedDirentList.length) { const direntList = selectedDirentList.map(dirent => dirent instanceof Dirent ? dirent.toJson() : dirent);
if (selectedDirentList.length === 1 && !selectedDirentList[0].isDir()) { eventBus.dispatch(EVENT_BUS_TYPE.DOWNLOAD_FILE, path, direntList);
let direntPath = Utils.joinPath(path, selectedDirentList[0].name);
let url = URLDecorator.getUrl({ type: 'download_file_url', repoID: repoID, filePath: direntPath });
location.href = url;
return;
}
if (useGoFileserver) {
const target = this.props.selectedDirentList.map(dirent => dirent.name);
seafileAPI.zipDownload(repoID, path, target).then((res) => {
const zipToken = res.data['zip_token'];
location.href = `${fileServerRoot}zip/${zipToken}`;
}).catch((error) => {
let errorMsg = Utils.getErrorMsg(error);
this.setState({
isLoading: false,
errorMsg: errorMsg
});
});
} else {
this.setState({
isZipDialogOpen: true
});
}
}
};
closeZipDialog = () => {
this.setState({
isZipDialogOpen: false
});
}; };
checkDuplicatedName = (newName) => { checkDuplicatedName = (newName) => {
@@ -433,16 +405,6 @@ class SelectedDirentsToolbar extends React.Component {
onAddFolder={this.props.onAddFolder} onAddFolder={this.props.onAddFolder}
/> />
} }
{this.state.isZipDialogOpen &&
<ModalPortal>
<ZipDownloadDialog
repoID={this.props.repoID}
path={this.props.path}
target={this.props.selectedDirentList.map(dirent => dirent.name)}
toggleDialog={this.closeZipDialog}
/>
</ModalPortal>
}
{this.state.showLibContentViewDialogs && ( {this.state.showLibContentViewDialogs && (
<Fragment> <Fragment>
{this.state.showShareDialog && {this.state.showShareDialog &&

View File

@@ -0,0 +1,83 @@
import React, { useContext, useEffect, useCallback, useState, useRef } from 'react';
import { useGoFileserver, fileServerRoot } from '../utils/constants';
import { Utils } from '../utils/utils';
import { seafileAPI } from '../utils/seafile-api';
import URLDecorator from '../utils/url-decorator';
import ModalPortal from '../components/modal-portal';
import ZipDownloadDialog from '../components/dialog/zip-download-dialog';
import toaster from '../components/toast';
import { EVENT_BUS_TYPE } from '../components/common/event-bus-type';
// This hook provides content about download
const DownloadFileContext = React.createContext(null);
export const DownloadFileProvider = ({ repoID, eventBus, children }) => {
const [isZipDialogOpen, setZipDialogOpen] = useState();
const pathRef = useRef('');
const direntListRef = useRef([]);
const handelDownload = useCallback((path, direntList = []) => {
const direntCount = direntList.length;
if (direntCount === 0) return;
if (direntCount === 1 && !direntList[0].is_dir) {
const direntPath = Utils.joinPath(path, direntList[0].name);
const url = URLDecorator.getUrl({ type: 'download_file_url', repoID: repoID, filePath: direntPath });
location.href = url;
return;
}
direntListRef.current = direntList.map(dirent => dirent.name);
if (!useGoFileserver) {
pathRef.current = path;
setZipDialogOpen(true);
return;
}
seafileAPI.zipDownload(repoID, path, direntListRef.current).then((res) => {
const zipToken = res.data['zip_token'];
location.href = `${fileServerRoot}zip/${zipToken}`;
}).catch((error) => {
const errorMsg = Utils.getErrorMsg(error);
toaster.danger(errorMsg);
});
}, [repoID]);
const cancelDownload = useCallback(() => {
setZipDialogOpen(false);
pathRef.current = '';
direntListRef.current = [];
}, []);
useEffect(() => {
const unsubscribeDownloadFile = eventBus.subscribe(EVENT_BUS_TYPE.DOWNLOAD_FILE, handelDownload);
return () => {
unsubscribeDownloadFile();
};
}, [eventBus, handelDownload]);
return (
<DownloadFileContext.Provider value={{ eventBus, handelDownload }}>
{children}
{isZipDialogOpen && (
<ModalPortal>
<ZipDownloadDialog
repoID={repoID}
path={pathRef.current}
target={direntListRef.current}
toggleDialog={cancelDownload}
/>
</ModalPortal>
)}
</DownloadFileContext.Provider>
);
};
export const useDownloadFile = () => {
const context = useContext(DownloadFileContext);
if (!context) {
throw new Error('\'DownloadFileContext\' is null');
}
return context;
};

View File

@@ -1 +1,2 @@
export { MetadataStatusProvider, useMetadataStatus } from './metadata-status'; export { MetadataStatusProvider, useMetadataStatus } from './metadata-status';
export { DownloadFileProvider } from './download-file';

View File

@@ -2,7 +2,6 @@ import { getFileNameFromRecord, getParentDirFromRecord } from './cell';
import { checkIsDir } from './row'; import { checkIsDir } from './row';
import { Utils } from '../../utils/utils'; import { Utils } from '../../utils/utils';
import { siteRoot } from '../../utils/constants'; import { siteRoot } from '../../utils/constants';
import URLDecorator from '../../utils/url-decorator';
const FILE_TYPE = { const FILE_TYPE = {
FOLDER: 'folder', FOLDER: 'folder',
@@ -116,13 +115,3 @@ export const openParentFolder = (record) => {
const url = window.location.origin + window.location.pathname + Utils.encodePath(parentDir); const url = window.location.origin + window.location.pathname + Utils.encodePath(parentDir);
window.open(url, '_blank'); window.open(url, '_blank');
}; };
export const downloadFile = (repoID, record) => {
if (!repoID || !record) return;
if (checkIsDir(record)) return;
const parentDir = _getParentDir(record);
const name = getFileNameFromRecord(record);
const direntPath = Utils.joinPath(parentDir, name);
const url = URLDecorator.getUrl({ type: 'download_file_url', repoID: repoID, filePath: direntPath });
location.href = url;
};

View File

@@ -2,16 +2,11 @@ import React, { useMemo, useCallback, useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ContextMenu from '../../../components/context-menu'; import ContextMenu from '../../../components/context-menu';
import ModalPortal from '../../../../components/modal-portal'; import ModalPortal from '../../../../components/modal-portal';
import toaster from '../../../../components/toast';
import ZipDownloadDialog from '../../../../components/dialog/zip-download-dialog';
import CopyDirent from '../../../../components/dialog/copy-dirent-dialog'; import CopyDirent from '../../../../components/dialog/copy-dirent-dialog';
import PeoplesDialog from '../../../components/dialog/peoples-dialog'; import PeoplesDialog from '../../../components/dialog/peoples-dialog';
import { gettext, useGoFileserver, fileServerRoot } from '../../../../utils/constants'; import { gettext } from '../../../../utils/constants';
import { getRowById } from '../../../../components/sf-table/utils/table';
import { downloadFile } from '../../../utils/file';
import metadataAPI from '../../../api';
import { Utils } from '../../../../utils/utils';
import { Dirent } from '../../../../models'; import { Dirent } from '../../../../models';
import { useDownloadFile } from '../../../../hooks/download-file';
const CONTEXT_MENU_KEY = { const CONTEXT_MENU_KEY = {
DOWNLOAD: 'download', DOWNLOAD: 'download',
@@ -22,11 +17,12 @@ const CONTEXT_MENU_KEY = {
ADD_PHOTO_TO_GROUPS: 'add_photo_to_groups', ADD_PHOTO_TO_GROUPS: 'add_photo_to_groups',
}; };
const GalleryContextMenu = ({ metadata, selectedImages, onDelete, onDuplicate, addFolder, onRemoveImage, onAddImage, onSetPeoplePhoto }) => { const GalleryContextMenu = ({ selectedImages, onDelete, onDuplicate, addFolder, onRemoveImage, onAddImage, onSetPeoplePhoto }) => {
const [isZipDialogOpen, setIsZipDialogOpen] = useState(false);
const [isCopyDialogOpen, setIsCopyDialogOpen] = useState(false); const [isCopyDialogOpen, setIsCopyDialogOpen] = useState(false);
const [isPeoplesDialogShow, setPeoplesDialogShow] = useState(false); const [isPeoplesDialogShow, setPeoplesDialogShow] = useState(false);
const { handelDownload: handelDownloadAPI } = useDownloadFile();
const repoID = window.sfMetadataContext.getSetting('repoID'); const repoID = window.sfMetadataContext.getSetting('repoID');
const checkCanDeleteRow = window.sfMetadataContext.checkCanDeleteRow(); const checkCanDeleteRow = window.sfMetadataContext.checkCanDeleteRow();
const canDuplicateRow = window.sfMetadataContext.canDuplicateRow(); const canDuplicateRow = window.sfMetadataContext.canDuplicateRow();
@@ -54,10 +50,6 @@ const GalleryContextMenu = ({ metadata, selectedImages, onDelete, onDuplicate, a
return validOptions; return validOptions;
}, [checkCanDeleteRow, canDuplicateRow, canRemovePhotoFromPeople, canAddPhotoToPeople, selectedImages, onDuplicate, onDelete, onRemoveImage, onAddImage, canSetPeoplePhoto, onSetPeoplePhoto]); }, [checkCanDeleteRow, canDuplicateRow, canRemovePhotoFromPeople, canAddPhotoToPeople, selectedImages, onDuplicate, onDelete, onRemoveImage, onAddImage, canSetPeoplePhoto, onSetPeoplePhoto]);
const closeZipDialog = () => {
setIsZipDialogOpen(false);
};
const toggleCopyDialog = useCallback(() => { const toggleCopyDialog = useCallback(() => {
setIsCopyDialogOpen(!isCopyDialogOpen); setIsCopyDialogOpen(!isCopyDialogOpen);
}, [isCopyDialogOpen]); }, [isCopyDialogOpen]);
@@ -69,28 +61,12 @@ const GalleryContextMenu = ({ metadata, selectedImages, onDelete, onDuplicate, a
const handleDownload = useCallback(() => { const handleDownload = useCallback(() => {
if (!selectedImages.length) return; if (!selectedImages.length) return;
if (selectedImages.length === 1) { const direntList = selectedImages.map(image => {
const image = selectedImages[0]; const name = image.parentDir === '/' ? image.name : `${image.parentDir}/${image.name}`;
const record = getRowById(metadata, image.id); return { name };
downloadFile(repoID, record);
return;
}
if (!useGoFileserver) {
setIsZipDialogOpen(true);
return;
}
const dirents = selectedImages.map(image => {
const value = image.parentDir === '/' ? image.name : `${image.parentDir}/${image.name}`;
return value;
}); });
metadataAPI.zipDownload(repoID, '/', dirents).then((res) => { handelDownloadAPI('/', direntList);
const zipToken = res.data['zip_token']; }, [handelDownloadAPI, selectedImages]);
location.href = `${fileServerRoot}zip/${zipToken}`;
}).catch(error => {
const errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
}, [repoID, metadata, selectedImages]);
const handleOptionClick = useCallback(option => { const handleOptionClick = useCallback(option => {
switch (option.value) { switch (option.value) {
@@ -135,16 +111,6 @@ const GalleryContextMenu = ({ metadata, selectedImages, onDelete, onDuplicate, a
ignoredTriggerElements={['.metadata-gallery-image-item', '.metadata-gallery-grid-image']} ignoredTriggerElements={['.metadata-gallery-image-item', '.metadata-gallery-grid-image']}
onOptionClick={handleOptionClick} onOptionClick={handleOptionClick}
/> />
{isZipDialogOpen && (
<ModalPortal>
<ZipDownloadDialog
repoID={repoID}
path="/"
target={selectedImages.map(image => image.parentDir === '/' ? image.name : `${image.parentDir}/${image.name}`)}
toggleDialog={closeZipDialog}
/>
</ModalPortal>
)}
{isCopyDialogOpen && ( {isCopyDialogOpen && (
<ModalPortal> <ModalPortal>
<CopyDirent <CopyDirent

View File

@@ -2,17 +2,14 @@ import React, { useCallback, useMemo, useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ContextMenu from '../../../components/context-menu'; import ContextMenu from '../../../components/context-menu';
import RenameDialog from '../../../components/dialog/rename-dialog'; import RenameDialog from '../../../components/dialog/rename-dialog';
import ZipDownloadDialog from '../../../../components/dialog/zip-download-dialog';
import { getRowById } from '../../../../components/sf-table/utils/table'; import { getRowById } from '../../../../components/sf-table/utils/table';
import { checkIsDir } from '../../../utils/row'; import { checkIsDir } from '../../../utils/row';
import { getFileNameFromRecord, getParentDirFromRecord } from '../../../utils/cell'; import { getFileNameFromRecord, getParentDirFromRecord } from '../../../utils/cell';
import { gettext, useGoFileserver, fileServerRoot } from '../../../../utils/constants'; import { gettext } from '../../../../utils/constants';
import { openInNewTab, openParentFolder, downloadFile } from '../../../utils/file'; import { openInNewTab, openParentFolder } from '../../../utils/file';
import { useMetadataView } from '../../../hooks/metadata-view'; import { useMetadataView } from '../../../hooks/metadata-view';
import { PRIVATE_COLUMN_KEY } from '../../../constants'; import { PRIVATE_COLUMN_KEY } from '../../../constants';
import { Utils } from '../../../../utils/utils'; import { useDownloadFile } from '../../../../hooks/download-file';
import toaster from '../../../../components/toast';
import metadataAPI from '../../../api';
const CONTEXT_MENU_KEY = { const CONTEXT_MENU_KEY = {
OPEN_IN_NEW_TAB: 'open_in_new_tab', OPEN_IN_NEW_TAB: 'open_in_new_tab',
@@ -24,9 +21,9 @@ const CONTEXT_MENU_KEY = {
const KanbanContextMenu = ({ selectedCard, onDelete, onRename }) => { const KanbanContextMenu = ({ selectedCard, onDelete, onRename }) => {
const [isRenameDialogShow, setIsRenameDialogShow] = useState(false); const [isRenameDialogShow, setIsRenameDialogShow] = useState(false);
const [isZipDialogOpen, setIsZipDialogOpen] = useState(false);
const { metadata } = useMetadataView(); const { metadata } = useMetadataView();
const { handelDownload: handelDownloadAPI } = useDownloadFile();
const selectedRecord = useMemo(() => getRowById(metadata, selectedCard), [metadata, selectedCard]); const selectedRecord = useMemo(() => getRowById(metadata, selectedCard), [metadata, selectedCard]);
const isDir = useMemo(() => checkIsDir(selectedRecord), [selectedRecord]); const isDir = useMemo(() => checkIsDir(selectedRecord), [selectedRecord]);
@@ -53,10 +50,6 @@ const KanbanContextMenu = ({ selectedCard, onDelete, onRename }) => {
return validOptions; return validOptions;
}, [isDir, checkCanDeleteRow, canModifyRow]); }, [isDir, checkCanDeleteRow, canModifyRow]);
const closeZipDialog = useCallback(() => {
setIsZipDialogOpen(false);
}, []);
const openRenameDialog = useCallback(() => { const openRenameDialog = useCallback(() => {
setIsRenameDialogShow(true); setIsRenameDialogShow(true);
}, []); }, []);
@@ -74,24 +67,9 @@ const KanbanContextMenu = ({ selectedCard, onDelete, onRename }) => {
}); });
}, [metadata, selectedCard, onRename]); }, [metadata, selectedCard, onRename]);
const handelDownload = useCallback((record) => { const handelDownload = useCallback(() => {
if (!isDir) { handelDownloadAPI(parentDir, [{ name: oldName, is_dir: isDir }]);
downloadFile(repoID, record); }, [handelDownloadAPI, parentDir, oldName, isDir]);
return;
}
if (!useGoFileserver) {
setIsZipDialogOpen(true);
return;
}
const fileName = getFileNameFromRecord(record);
metadataAPI.zipDownload(repoID, parentDir, [fileName]).then((res) => {
const zipToken = res.data['zip_token'];
location.href = `${fileServerRoot}zip/${zipToken}`;
}).catch(error => {
const errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
}, [repoID, isDir, parentDir]);
const handleOptionClick = useCallback((option) => { const handleOptionClick = useCallback((option) => {
if (!selectedCard) return; if (!selectedCard) return;
@@ -140,9 +118,6 @@ const KanbanContextMenu = ({ selectedCard, onDelete, onRename }) => {
onCancel={() => setIsRenameDialogShow(false)} onCancel={() => setIsRenameDialogShow(false)}
/> />
)} )}
{isZipDialogOpen && (
<ZipDownloadDialog repoID={repoID} path={parentDir} target={[oldName]} toggleDialog={closeZipDialog}/>
)}
</> </>
); );
}; };

View File

@@ -65,6 +65,7 @@ class Dirent {
name: this.name, name: this.name,
mtime: this.mtime, mtime: this.mtime,
type: this.type, type: this.type,
is_dir: this.type !== 'file',
size: this.size, size: this.size,
modifier_name: this.modifier_name, modifier_name: this.modifier_name,
modifier_email: this.modifier_email, modifier_email: this.modifier_email,

View File

@@ -23,7 +23,7 @@ import CopyMoveDirentProgressDialog from '../../components/dialog/copy-move-dire
import DeleteFolderDialog from '../../components/dialog/delete-folder-dialog'; import DeleteFolderDialog from '../../components/dialog/delete-folder-dialog';
import { EVENT_BUS_TYPE } from '../../components/common/event-bus-type'; import { EVENT_BUS_TYPE } from '../../components/common/event-bus-type';
import { PRIVATE_FILE_TYPE, DIRENT_DETAIL_SHOW_KEY, TREE_PANEL_STATE_KEY, RECENTLY_USED_LIST_KEY } from '../../constants'; import { PRIVATE_FILE_TYPE, DIRENT_DETAIL_SHOW_KEY, TREE_PANEL_STATE_KEY, RECENTLY_USED_LIST_KEY } from '../../constants';
import { MetadataStatusProvider } from '../../hooks'; import { MetadataStatusProvider, DownloadFileProvider } from '../../hooks';
import { MetadataProvider, CollaboratorsProvider } from '../../metadata/hooks'; import { MetadataProvider, CollaboratorsProvider } from '../../metadata/hooks';
import { TagsProvider } from '../../tag/hooks'; import { TagsProvider } from '../../tag/hooks';
import { LIST_MODE, METADATA_MODE, TAGS_MODE } from '../../components/dir-view-mode/constants'; import { LIST_MODE, METADATA_MODE, TAGS_MODE } from '../../components/dir-view-mode/constants';
@@ -2356,239 +2356,242 @@ class LibContentView extends React.Component {
const detailDirent = currentDirent || currentNode?.object || null; const detailDirent = currentDirent || currentNode?.object || null;
return ( return (
<DndProvider backend={HTML5Backend}> <DownloadFileProvider repoID={repoID} eventBus={this.props.eventBus}>
<MetadataStatusProvider repoID={repoID} repoInfo={currentRepoInfo} hideMetadataView={this.hideMetadataView} statusCallback={this.metadataStatusCallback} > <DndProvider backend={HTML5Backend}>
<TagsProvider repoID={repoID} currentPath={path} repoInfo={currentRepoInfo} selectTagsView={this.onTreeNodeClick} tagsChangedCallback={this.tagsChangedCallback} > <MetadataStatusProvider repoID={repoID} repoInfo={currentRepoInfo} hideMetadataView={this.hideMetadataView} statusCallback={this.metadataStatusCallback} >
<MetadataProvider repoID={repoID} currentPath={path} repoInfo={currentRepoInfo} selectMetadataView={this.onTreeNodeClick} > <TagsProvider repoID={repoID} currentPath={path} repoInfo={currentRepoInfo} selectTagsView={this.onTreeNodeClick} tagsChangedCallback={this.tagsChangedCallback} >
<CollaboratorsProvider repoID={repoID}> <MetadataProvider repoID={repoID} currentPath={path} repoInfo={currentRepoInfo} selectMetadataView={this.onTreeNodeClick} >
<div className="main-panel-center flex-row"> <CollaboratorsProvider repoID={repoID}>
<div className="cur-view-container"> <div className="main-panel-center flex-row">
{this.state.currentRepoInfo.status === 'read-only' && <div className="cur-view-container">
<div className="readonly-tip-message"> {this.state.currentRepoInfo.status === 'read-only' &&
{gettext('This library has been set to read-only by admin and cannot be updated.')} <div className="readonly-tip-message">
</div> {gettext('This library has been set to read-only by admin and cannot be updated.')}
} </div>
<div className="cur-view-path lib-cur-view-path"> }
<div className={classnames( <div className="cur-view-path lib-cur-view-path">
'cur-view-path-left', { <div className={classnames(
'w-100': !isDesktop, 'cur-view-path-left', {
'animation-children': isDirentSelected 'w-100': !isDesktop,
})}> 'animation-children': isDirentSelected
{isDirentSelected ? ( })}>
currentMode === TAGS_MODE || currentMode === METADATA_MODE ? ( {isDirentSelected ? (
<MetadataPathToolbar repoID={repoID} repoInfo={currentRepoInfo} mode={currentMode} path={path} /> currentMode === TAGS_MODE || currentMode === METADATA_MODE ? (
<MetadataPathToolbar repoID={repoID} repoInfo={currentRepoInfo} mode={currentMode} path={path} />
) : (
<SelectedDirentsToolbar
repoID={this.props.repoID}
eventBus={this.props.eventBus}
path={this.state.path}
userPerm={userPerm}
repoEncrypted={this.state.repoEncrypted}
repoTags={this.state.repoTags}
selectedDirentList={this.state.selectedDirentList}
direntList={direntItemsList}
onItemsMove={this.onMoveItems}
onItemsCopy={this.onCopyItems}
onItemsDelete={this.onDeleteItems}
onItemRename={this.onMainPanelItemRename}
isRepoOwner={isRepoOwner}
currentRepoInfo={this.state.currentRepoInfo}
enableDirPrivateShare={enableDirPrivateShare}
updateDirent={this.updateDirent}
unSelectDirent={this.unSelectDirent}
onFilesTagChanged={this.onFileTagChanged}
showShareBtn={showShareBtn}
isGroupOwnedRepo={this.state.isGroupOwnedRepo}
showDirentDetail={this.showDirentDetail}
currentMode={this.state.currentMode}
onItemConvert={this.onConvertItem}
onAddFolder={this.onAddFolder}
/>
)
) : ( ) : (
<SelectedDirentsToolbar <CurDirPath
repoID={this.props.repoID}
path={this.state.path}
userPerm={userPerm}
repoEncrypted={this.state.repoEncrypted}
repoTags={this.state.repoTags}
selectedDirentList={this.state.selectedDirentList}
direntList={direntItemsList}
onItemsMove={this.onMoveItems}
onItemsCopy={this.onCopyItems}
onItemsDelete={this.onDeleteItems}
onItemRename={this.onMainPanelItemRename}
isRepoOwner={isRepoOwner}
currentRepoInfo={this.state.currentRepoInfo} currentRepoInfo={this.state.currentRepoInfo}
enableDirPrivateShare={enableDirPrivateShare} repoID={this.props.repoID}
updateDirent={this.updateDirent} repoName={this.state.currentRepoInfo.repo_name}
unSelectDirent={this.unSelectDirent} repoEncrypted={this.state.repoEncrypted}
onFilesTagChanged={this.onFileTagChanged}
showShareBtn={showShareBtn}
isGroupOwnedRepo={this.state.isGroupOwnedRepo} isGroupOwnedRepo={this.state.isGroupOwnedRepo}
showDirentDetail={this.showDirentDetail} pathPrefix={this.props.pathPrefix}
currentMode={this.state.currentMode} currentPath={this.state.path}
onItemConvert={this.onConvertItem} userPerm={userPerm}
onTabNavClick={this.props.onTabNavClick}
onPathClick={this.onMainNavBarClick}
fileTags={this.state.fileTags}
direntList={direntItemsList}
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}
sortItems={this.sortItems}
toggleTreePanel={this.toggleTreePanel}
enableDirPrivateShare={enableDirPrivateShare}
showShareBtn={showShareBtn}
onAddFolder={this.onAddFolder} onAddFolder={this.onAddFolder}
onAddFile={this.onAddFile}
onUploadFile={this.onUploadFile}
onUploadFolder={this.onUploadFolder}
fullDirentList={this.state.direntList}
filePermission={this.state.filePermission}
onFileTagChanged={this.onToolbarFileTagChanged}
repoTags={this.state.repoTags}
onItemMove={this.onMoveItem}
isDesktop={isDesktop}
loadDirentList={this.loadDirentList}
onAddFolderNode={this.onAddFolder}
/> />
) )}
) : ( </div>
<CurDirPath {isDesktop &&
currentRepoInfo={this.state.currentRepoInfo} <div className="cur-view-path-right py-1">
<DirTool
repoID={this.props.repoID} repoID={this.props.repoID}
repoName={this.state.currentRepoInfo.repo_name} repoName={this.state.currentRepoInfo.repo_name}
repoEncrypted={this.state.repoEncrypted}
isGroupOwnedRepo={this.state.isGroupOwnedRepo}
pathPrefix={this.props.pathPrefix}
currentPath={this.state.path}
userPerm={userPerm} userPerm={userPerm}
onTabNavClick={this.props.onTabNavClick} currentPath={path}
onPathClick={this.onMainNavBarClick} currentMode={this.state.currentMode}
fileTags={this.state.fileTags} switchViewMode={this.switchViewMode}
direntList={direntItemsList} isCustomPermission={isCustomPermission}
sortBy={this.state.sortBy} sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder} sortOrder={this.state.sortOrder}
sortItems={this.sortItems} sortItems={this.sortItems}
toggleTreePanel={this.toggleTreePanel} viewId={this.state.viewId}
viewType={this.props.viewType}
onToggleDetail={this.toggleDirentDetail}
onCloseDetail={this.closeDirentDetail}
/>
</div>
}
</div>
<div className='cur-view-content lib-content-container' onScroll={this.onItemsScroll}>
{this.state.pathExist ?
<DirColumnView
isSidePanelFolded={this.props.isSidePanelFolded}
isTreePanelShown={this.state.isTreePanelShown}
isDirentDetailShow={this.state.isDirentDetailShow}
currentMode={this.state.currentMode}
path={this.state.path}
repoID={this.props.repoID}
currentRepoInfo={this.state.currentRepoInfo}
updateRepoInfo={this.updateRepoInfo}
isGroupOwnedRepo={this.state.isGroupOwnedRepo}
userPerm={userPerm}
enableDirPrivateShare={enableDirPrivateShare} enableDirPrivateShare={enableDirPrivateShare}
showShareBtn={showShareBtn} isTreeDataLoading={this.state.isTreeDataLoading}
treeData={this.state.treeData}
currentNode={this.state.currentNode}
onNodeClick={this.onTreeNodeClick}
onNodeCollapse={this.onTreeNodeCollapse}
onNodeExpanded={this.onTreeNodeExpanded}
onAddFolderNode={this.onAddFolder}
onAddFileNode={this.onAddFile}
onRenameNode={this.onRenameTreeNode}
onDeleteNode={this.onDeleteTreeNode}
isViewFile={this.state.isViewFile}
isFileLoading={this.state.isFileLoading}
filePermission={this.state.filePermission}
content={this.state.content}
viewId={this.state.viewId}
tagId={this.state.tagId}
lastModified={this.state.lastModified}
latestContributor={this.state.latestContributor}
onLinkClick={this.onLinkClick}
isRepoInfoBarShow={isRepoInfoBarShow}
repoTags={this.state.repoTags}
usedRepoTags={this.state.usedRepoTags}
updateUsedRepoTags={this.updateUsedRepoTags}
isDirentListLoading={this.state.isDirentListLoading}
direntList={direntItemsList}
fullDirentList={this.state.direntList}
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}
sortItems={this.sortItems}
onAddFolder={this.onAddFolder} onAddFolder={this.onAddFolder}
onAddFile={this.onAddFile} onAddFile={this.onAddFile}
onUploadFile={this.onUploadFile} onItemClick={this.onItemClick}
onUploadFolder={this.onUploadFolder} onItemSelected={this.onDirentSelected}
fullDirentList={this.state.direntList} onItemDelete={this.onMainPanelItemDelete}
filePermission={this.state.filePermission} onItemRename={this.onMainPanelItemRename}
onFileTagChanged={this.onToolbarFileTagChanged} deleteFilesCallback={this.deleteItemsAjaxCallback}
repoTags={this.state.repoTags} renameFileCallback={this.renameItemAjaxCallback}
onItemMove={this.onMoveItem} onItemMove={this.onMoveItem}
isDesktop={isDesktop} moveFileCallback={this.moveItemsAjaxCallback}
loadDirentList={this.loadDirentList} onItemCopy={this.onCopyItem}
onAddFolderNode={this.onAddFolder} copyFileCallback={this.copyItemsAjaxCallback}
convertFileCallback={this.convertFileAjaxCallback}
onItemConvert={this.onConvertItem}
onDirentClick={this.onDirentClick}
updateDirent={this.updateDirent}
isAllItemSelected={this.state.isAllDirentSelected}
onAllItemSelected={this.onAllDirentSelected}
selectedDirentList={this.state.selectedDirentList}
onSelectedDirentListUpdate={this.onSelectedDirentListUpdate}
onItemsMove={this.onMoveItems}
onItemsCopy={this.onCopyItems}
onItemsDelete={this.onDeleteItems}
onFileTagChanged={this.onFileTagChanged}
showDirentDetail={this.showDirentDetail}
onItemsScroll={this.onItemsScroll}
eventBus={this.props.eventBus}
updateCurrentDirent={this.updateCurrentDirent}
updateCurrentPath={this.updatePath}
toggleShowDirentToolbar={this.toggleShowDirentToolbar}
updateTreeNode={this.updateTreeNode}
/>
:
<div className="message err-tip">{gettext('Folder does not exist.')}</div>
}
{!isCustomPermission && this.state.isDirentDetailShow && (
<Detail
path={detailPath}
repoID={this.props.repoID}
currentRepoInfo={{ ...this.state.currentRepoInfo }}
dirent={detailDirent}
repoTags={this.state.repoTags}
fileTags={this.state.isViewFile ? this.state.fileTags : []}
onFileTagChanged={this.onFileTagChanged}
onClose={this.closeDirentDetail}
currentMode={this.state.currentMode}
/> />
)} )}
</div> </div>
{isDesktop &&
<div className="cur-view-path-right py-1">
<DirTool
repoID={this.props.repoID}
repoName={this.state.currentRepoInfo.repo_name}
userPerm={userPerm}
currentPath={path}
currentMode={this.state.currentMode}
switchViewMode={this.switchViewMode}
isCustomPermission={isCustomPermission}
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}
sortItems={this.sortItems}
viewId={this.state.viewId}
viewType={this.props.viewType}
onToggleDetail={this.toggleDirentDetail}
onCloseDetail={this.closeDirentDetail}
/>
</div>
}
</div>
<div className='cur-view-content lib-content-container' onScroll={this.onItemsScroll}>
{this.state.pathExist ?
<DirColumnView
isSidePanelFolded={this.props.isSidePanelFolded}
isTreePanelShown={this.state.isTreePanelShown}
isDirentDetailShow={this.state.isDirentDetailShow}
currentMode={this.state.currentMode}
path={this.state.path}
repoID={this.props.repoID}
currentRepoInfo={this.state.currentRepoInfo}
updateRepoInfo={this.updateRepoInfo}
isGroupOwnedRepo={this.state.isGroupOwnedRepo}
userPerm={userPerm}
enableDirPrivateShare={enableDirPrivateShare}
isTreeDataLoading={this.state.isTreeDataLoading}
treeData={this.state.treeData}
currentNode={this.state.currentNode}
onNodeClick={this.onTreeNodeClick}
onNodeCollapse={this.onTreeNodeCollapse}
onNodeExpanded={this.onTreeNodeExpanded}
onAddFolderNode={this.onAddFolder}
onAddFileNode={this.onAddFile}
onRenameNode={this.onRenameTreeNode}
onDeleteNode={this.onDeleteTreeNode}
isViewFile={this.state.isViewFile}
isFileLoading={this.state.isFileLoading}
filePermission={this.state.filePermission}
content={this.state.content}
viewId={this.state.viewId}
tagId={this.state.tagId}
lastModified={this.state.lastModified}
latestContributor={this.state.latestContributor}
onLinkClick={this.onLinkClick}
isRepoInfoBarShow={isRepoInfoBarShow}
repoTags={this.state.repoTags}
usedRepoTags={this.state.usedRepoTags}
updateUsedRepoTags={this.updateUsedRepoTags}
isDirentListLoading={this.state.isDirentListLoading}
direntList={direntItemsList}
fullDirentList={this.state.direntList}
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}
sortItems={this.sortItems}
onAddFolder={this.onAddFolder}
onAddFile={this.onAddFile}
onItemClick={this.onItemClick}
onItemSelected={this.onDirentSelected}
onItemDelete={this.onMainPanelItemDelete}
onItemRename={this.onMainPanelItemRename}
deleteFilesCallback={this.deleteItemsAjaxCallback}
renameFileCallback={this.renameItemAjaxCallback}
onItemMove={this.onMoveItem}
moveFileCallback={this.moveItemsAjaxCallback}
onItemCopy={this.onCopyItem}
copyFileCallback={this.copyItemsAjaxCallback}
convertFileCallback={this.convertFileAjaxCallback}
onItemConvert={this.onConvertItem}
onDirentClick={this.onDirentClick}
updateDirent={this.updateDirent}
isAllItemSelected={this.state.isAllDirentSelected}
onAllItemSelected={this.onAllDirentSelected}
selectedDirentList={this.state.selectedDirentList}
onSelectedDirentListUpdate={this.onSelectedDirentListUpdate}
onItemsMove={this.onMoveItems}
onItemsCopy={this.onCopyItems}
onItemsDelete={this.onDeleteItems}
onFileTagChanged={this.onFileTagChanged}
showDirentDetail={this.showDirentDetail}
onItemsScroll={this.onItemsScroll}
eventBus={this.props.eventBus}
updateCurrentDirent={this.updateCurrentDirent}
updateCurrentPath={this.updatePath}
toggleShowDirentToolbar={this.toggleShowDirentToolbar}
updateTreeNode={this.updateTreeNode}
/>
:
<div className="message err-tip">{gettext('Folder does not exist.')}</div>
}
{!isCustomPermission && this.state.isDirentDetailShow && (
<Detail
path={detailPath}
repoID={this.props.repoID}
currentRepoInfo={{ ...this.state.currentRepoInfo }}
dirent={detailDirent}
repoTags={this.state.repoTags}
fileTags={this.state.isViewFile ? this.state.fileTags : []}
onFileTagChanged={this.onFileTagChanged}
onClose={this.closeDirentDetail}
currentMode={this.state.currentMode}
/>
)}
</div> </div>
{canUpload && this.state.pathExist && !this.state.isViewFile && ![METADATA_MODE, TAGS_MODE].includes(this.state.currentMode) && (
<FileUploader
ref={uploader => this.uploader = uploader}
dragAndDrop={true}
path={this.state.path}
repoID={this.props.repoID}
direntList={this.state.direntList}
onFileUploadSuccess={this.onFileUploadSuccess}
isCustomPermission={isCustomPermission}
/>
)}
</div> </div>
{canUpload && this.state.pathExist && !this.state.isViewFile && ![METADATA_MODE, TAGS_MODE].includes(this.state.currentMode) && ( {isCopyMoveProgressDialogShow && (
<FileUploader <CopyMoveDirentProgressDialog
ref={uploader => this.uploader = uploader} type={this.state.asyncOperationType}
dragAndDrop={true} asyncOperatedFilesLength={this.state.asyncOperatedFilesLength}
path={this.state.path} asyncOperationProgress={this.state.asyncOperationProgress}
repoID={this.props.repoID} toggleDialog={this.onMoveProgressDialogToggle}
direntList={this.state.direntList}
onFileUploadSuccess={this.onFileUploadSuccess}
isCustomPermission={isCustomPermission}
/> />
)} )}
</div> {isDeleteFolderDialogOpen && (
{isCopyMoveProgressDialogShow && ( <DeleteFolderDialog
<CopyMoveDirentProgressDialog repoID={this.props.repoID}
type={this.state.asyncOperationType} path={this.state.folderToDelete}
asyncOperatedFilesLength={this.state.asyncOperatedFilesLength} deleteFolder={this.deleteFolder}
asyncOperationProgress={this.state.asyncOperationProgress} toggleDialog={this.toggleDeleteFolderDialog}
toggleDialog={this.onMoveProgressDialogToggle} />
/> )}
)} <MediaQuery query="(max-width: 767.8px)">
{isDeleteFolderDialogOpen && ( <Modal zIndex="1030" isOpen={!isDesktop && this.state.isTreePanelShown} toggle={this.toggleTreePanel} contentClassName="d-none"></Modal>
<DeleteFolderDialog </MediaQuery>
repoID={this.props.repoID} </CollaboratorsProvider>
path={this.state.folderToDelete} </MetadataProvider>
deleteFolder={this.deleteFolder} </TagsProvider>
toggleDialog={this.toggleDeleteFolderDialog} </MetadataStatusProvider>
/> </DndProvider>
)} </DownloadFileProvider>
<MediaQuery query="(max-width: 767.8px)">
<Modal zIndex="1030" isOpen={!isDesktop && this.state.isTreePanelShown} toggle={this.toggleTreePanel} contentClassName="d-none"></Modal>
</MediaQuery>
</CollaboratorsProvider>
</MetadataProvider>
</TagsProvider>
</MetadataStatusProvider>
</DndProvider>
); );
} }
} }