2020-02-29 09:02:11 +00:00
import React , { Fragment } from 'react' ;
2019-02-20 03:54:25 +00:00
import PropTypes from 'prop-types' ;
import cookie from 'react-cookies' ;
import moment from 'moment' ;
2022-12-29 04:21:47 +00:00
import { navigate } from '@gatsbyjs/reach-router' ;
2021-07-19 06:46:17 +00:00
import { gettext , siteRoot , username , isDocs , enableVideoThumbnail } from '../../utils/constants' ;
2019-02-20 03:54:25 +00:00
import { seafileAPI } from '../../utils/seafile-api' ;
import { Utils } from '../../utils/utils' ;
import collabServer from '../../utils/collab-server' ;
import Dirent from '../../models/dirent' ;
import FileTag from '../../models/file-tag' ;
import RepoTag from '../../models/repo-tag' ;
import RepoInfo from '../../models/repo-info' ;
import TreeNode from '../../components/tree-view/tree-node' ;
import treeHelper from '../../components/tree-view/tree-helper' ;
import toaster from '../../components/toast' ;
import ModalPortal from '../../components/modal-portal' ;
import LibDecryptDialog from '../../components/dialog/lib-decrypt-dialog' ;
2019-02-21 09:37:04 +00:00
import LibContentToolbar from './lib-content-toolbar' ;
import LibContentContainer from './lib-content-container' ;
import FileUploader from '../../components/file-uploader/file-uploader' ;
2020-02-29 09:02:11 +00:00
import CopyMoveDirentProgressDialog from '../../components/dialog/copy-move-dirent-progress-dialog' ;
2022-11-28 01:27:17 +00:00
import DeleteFolderDialog from '../../components/dialog/delete-folder-dialog' ;
2019-02-20 03:54:25 +00:00
const propTypes = {
pathPrefix : PropTypes . array . isRequired ,
onTabNavClick : PropTypes . func . isRequired ,
onMenuClick : PropTypes . func . isRequired ,
2019-02-21 09:37:04 +00:00
repoID : PropTypes . string ,
2019-02-20 03:54:25 +00:00
} ;
class LibContentView extends React . Component {
constructor ( props ) {
super ( props ) ;
this . state = {
2019-04-13 03:56:44 +00:00
currentMode : cookie . load ( 'seafile_view_mode' ) || 'list' ,
2019-02-20 03:54:25 +00:00
path : '' ,
pathExist : true ,
isViewFile : false ,
hash : '' ,
currentRepoInfo : null ,
repoName : '' ,
repoEncrypted : false ,
libNeedDecrypt : false ,
isGroupOwnedRepo : false ,
userPerm : '' ,
selectedDirentList : [ ] ,
isDraft : false ,
hasDraft : false ,
2019-03-15 02:10:24 +00:00
fileTags : [ ] ,
2019-03-05 07:37:51 +00:00
draftID : '' ,
2019-02-20 03:54:25 +00:00
draftCounts : 0 ,
usedRepoTags : [ ] ,
isTreeDataLoading : true ,
treeData : treeHelper . buildTree ( ) ,
currentNode : null ,
isFileLoading : true ,
2019-02-21 09:37:04 +00:00
isFileLoadedErr : false ,
2019-04-19 07:50:27 +00:00
filePermission : '' ,
2019-02-20 03:54:25 +00:00
content : '' ,
lastModified : '' ,
latestContributor : '' ,
isDirentListLoading : true ,
direntList : [ ] ,
isDirentSelected : false ,
2019-05-29 05:57:12 +00:00
sortBy : cookie . load ( 'seafile-repo-dir-sort-by' ) || 'name' , // 'name' or 'time' or 'size'
2019-04-12 06:30:08 +00:00
sortOrder : cookie . load ( 'seafile-repo-dir-sort-order' ) || 'asc' , // 'asc' or 'desc'
2019-02-20 03:54:25 +00:00
isAllDirentSelected : false ,
2019-02-21 09:37:04 +00:00
dirID : '' , // for update dir list
2019-02-20 03:54:25 +00:00
errorMsg : '' ,
2019-03-18 09:32:49 +00:00
isDirentDetailShow : false ,
2019-05-29 04:02:07 +00:00
direntDetailPanelTab : '' ,
2019-04-18 05:39:42 +00:00
updateDetail : false ,
2019-04-24 05:37:48 +00:00
itemsShowLength : 100 ,
2019-05-12 07:05:53 +00:00
isSessionExpired : false ,
2020-02-29 09:02:11 +00:00
isCopyMoveProgressDialogShow : false ,
2022-11-28 01:27:17 +00:00
isDeleteFolderDialogOpen : false ,
2020-02-29 09:02:11 +00:00
asyncCopyMoveTaskId : '' ,
2020-03-31 05:45:36 +00:00
asyncOperationType : 'move' ,
2020-02-29 09:02:11 +00:00
asyncOperationProgress : 0 ,
2020-03-02 08:44:39 +00:00
asyncOperatedFilesLength : 0 ,
2019-02-20 03:54:25 +00:00
} ;
2019-04-22 10:05:18 +00:00
this . oldonpopstate = window . onpopstate ;
2019-02-20 03:54:25 +00:00
window . onpopstate = this . onpopstate ;
this . lastModifyTime = new Date ( ) ;
2019-02-23 03:59:26 +00:00
this . isNeedUpdateHistoryState = true ; // Load, refresh page, switch mode for the first time, no need to set historyState
2020-04-10 10:08:27 +00:00
this . currentMoveItemName = '' ;
this . currentMoveItemPath = '' ;
2019-02-20 03:54:25 +00:00
}
2019-05-29 04:02:07 +00:00
showDirentDetail = ( direntDetailPanelTab ) => {
if ( direntDetailPanelTab ) {
this . setState ( { direntDetailPanelTab : direntDetailPanelTab } , ( ) => {
this . setState ( { isDirentDetailShow : true } ) ;
} ) ;
} else {
this . setState ( {
direntDetailPanelTab : '' ,
isDirentDetailShow : true
} ) ;
}
2023-09-13 00:40:50 +00:00
} ;
2019-03-18 09:32:49 +00:00
2019-04-10 08:04:26 +00:00
toggleDirentDetail = ( ) => {
2019-05-29 04:02:07 +00:00
this . setState ( {
direntDetailPanelTab : '' ,
isDirentDetailShow : ! this . state . isDirentDetailShow
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-10 08:04:26 +00:00
2019-03-19 10:20:45 +00:00
closeDirentDetail = ( ) => {
2019-05-29 04:02:07 +00:00
this . setState ( {
isDirentDetailShow : false ,
direntDetailPanelTab : '' ,
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-03-19 10:20:45 +00:00
2023-12-06 09:24:05 +00:00
UNSAFE _componentWillMount ( ) {
2019-02-20 03:54:25 +00:00
const hash = window . location . hash ;
if ( hash . slice ( 0 , 1 ) === '#' ) {
2019-02-21 09:37:04 +00:00
this . setState ( { hash : hash } ) ;
2019-02-20 03:54:25 +00:00
}
}
2021-09-13 02:37:07 +00:00
async componentDidMount ( ) {
2019-02-20 03:54:25 +00:00
// eg: http://127.0.0.1:8000/library/repo_id/repo_name/**/**/\
let repoID = this . props . repoID ;
2023-12-26 06:48:59 +00:00
let location = window . location . href . split ( '?' ) [ 0 ] ; // '?': to remove the effect of '?notifications=all', which is added to the URL when the 'view all notifications' dialog is open.
2019-02-20 03:54:25 +00:00
location = decodeURIComponent ( location ) ;
2021-09-13 02:37:07 +00:00
let path = location . slice ( location . indexOf ( repoID ) + repoID . length + 1 ) ; // get the string after repoID
path = path . slice ( path . indexOf ( '/' ) ) ; // get current path
2023-11-01 07:10:43 +00:00
// If the path isn't a root path and ends with '/', delete the ending '/'
if ( path . length > 1 && path [ path . length - 1 ] === '/' ) {
path = path . slice ( 0 , path . length - 1 ) ;
}
2021-09-13 02:37:07 +00:00
try {
const repoRes = await seafileAPI . getRepoInfo ( repoID ) ;
const repoInfo = new RepoInfo ( repoRes . data ) ;
const isGroupOwnedRepo = repoInfo . owner _email . indexOf ( '@seafile_group' ) > - 1 ;
2022-08-17 03:20:19 +00:00
this . setState ( {
currentRepoInfo : repoInfo ,
} ) ;
2021-09-13 02:37:07 +00:00
if ( repoInfo . permission . startsWith ( 'custom-' ) ) {
const permissionID = repoInfo . permission . split ( '-' ) [ 1 ] ;
const permissionRes = await seafileAPI . getCustomPermission ( repoID , permissionID ) ;
window . custom _permission = permissionRes . data . permission ;
}
this . isNeedUpdateHistoryState = false ;
2019-02-20 03:54:25 +00:00
this . setState ( {
repoName : repoInfo . repo _name ,
2020-11-02 05:56:35 +00:00
libNeedDecrypt : repoInfo . lib _need _decrypt ,
2019-02-20 03:54:25 +00:00
repoEncrypted : repoInfo . encrypted ,
2019-05-17 07:53:51 +00:00
isGroupOwnedRepo : isGroupOwnedRepo ,
2021-09-13 02:37:07 +00:00
path : path
2019-02-20 03:54:25 +00:00
} ) ;
2022-08-17 03:20:19 +00:00
2019-02-27 05:53:36 +00:00
if ( ! repoInfo . lib _need _decrypt ) {
2019-02-20 03:54:25 +00:00
this . loadDirData ( path ) ;
}
2021-09-13 02:37:07 +00:00
} catch ( error ) {
2019-02-20 03:54:25 +00:00
if ( error . response ) {
if ( error . response . status == 403 ) {
this . setState ( {
isDirentListLoading : false ,
errorMsg : gettext ( 'Permission denied' )
} ) ;
2020-11-02 05:56:35 +00:00
2019-05-17 06:47:06 +00:00
let errorMsg = gettext ( 'Permission denied' ) ;
toaster . danger ( errorMsg ) ;
2022-08-17 03:20:19 +00:00
} else if ( error . response . status == 404 ) {
this . setState ( {
isDirentListLoading : false ,
errorMsg : gettext ( 'Library share permission not found.' )
} ) ;
2019-02-20 03:54:25 +00:00
} else {
this . setState ( {
isDirentListLoading : false ,
errorMsg : gettext ( 'Error' )
} ) ;
}
} else {
this . setState ( {
isDirentListLoading : false ,
errorMsg : gettext ( 'Please check the network.' )
} ) ;
}
2021-09-13 02:37:07 +00:00
}
2019-02-20 03:54:25 +00:00
}
componentWillUnmount ( ) {
2019-04-22 10:05:18 +00:00
window . onpopstate = this . oldonpopstate ;
2019-02-20 03:54:25 +00:00
collabServer . unwatchRepo ( this . props . repoID , this . onRepoUpdateEvent ) ;
}
componentDidUpdate ( ) {
this . lastModifyTime = new Date ( ) ;
}
onpopstate = ( event ) => {
2019-03-29 10:27:43 +00:00
if ( event . state && event . state . key ) { // root path
if ( this . state . path === '/' ) {
return ;
} else {
let path = '/' ;
this . loadDirentList ( path ) ;
this . setState ( {
path : path ,
isViewFile : false
} ) ;
}
} else if ( event . state && event . state . path ) { // file path
2019-02-20 03:54:25 +00:00
let path = event . state . path ;
if ( this . state . currentMode === 'column' ) {
if ( Utils . isMarkdownFile ( path ) ) { // Judging not strict
this . showFile ( path ) ;
return ;
}
}
this . loadDirentList ( path ) ;
this . setState ( {
path : path ,
isViewFile : false
} ) ;
}
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
onRepoUpdateEvent = ( ) => {
let currentTime = new Date ( ) ;
if ( ( parseFloat ( currentTime - this . lastModifyTime ) / 1000 ) <= 5 ) {
return ;
}
let repoID = this . props . repoID ;
let { path , dirID } = this . state ;
2019-05-10 07:40:01 +00:00
if ( this . state . currentMode === 'column' ) {
if ( this . state . isViewFile ) {
2022-04-11 09:27:02 +00:00
this . updateColumnMarkdownData ( path ) ;
2019-05-10 07:40:01 +00:00
} else {
seafileAPI . dirMetaData ( repoID , path ) . then ( ( res ) => {
if ( res . data . id !== dirID ) {
this . loadDirentList ( path ) ;
}
2019-07-16 02:01:09 +00:00
} ) . catch ( error => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
2019-05-14 02:15:09 +00:00
} ) ;
2019-02-20 03:54:25 +00:00
}
2019-05-10 07:40:01 +00:00
} else {
seafileAPI . dirMetaData ( repoID , path ) . then ( ( res ) => {
if ( res . data . id !== dirID ) {
this . loadDirentList ( path ) ;
}
2019-07-16 02:01:09 +00:00
} ) . catch ( error => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
2019-05-14 02:15:09 +00:00
} ) ;
2019-05-10 07:40:01 +00:00
}
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
updateUsedRepoTags = ( ) => {
let repoID = this . props . repoID ;
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 } ) ;
2019-07-16 02:01:09 +00:00
} ) . catch ( error => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
2022-04-11 09:27:02 +00:00
updateColumnMarkdownData = ( filePath ) => {
2019-05-10 07:40:01 +00:00
let repoID = this . props . repoID ;
// update state
this . setState ( {
path : filePath ,
isViewFile : true
} ) ;
// update data
seafileAPI . getFileInfo ( repoID , filePath ) . then ( ( res ) => {
let { mtime , permission , last _modifier _name , is _draft , has _draft , draft _id } = res . data ;
seafileAPI . getFileDownloadLink ( repoID , filePath ) . then ( ( res ) => {
seafileAPI . getFileContent ( res . data ) . then ( ( res ) => {
if ( this . state . content !== res . data ) {
2019-05-14 02:15:09 +00:00
this . setState ( { isFileLoading : true } ) ;
2019-05-10 07:40:01 +00:00
}
this . setState ( {
content : res . data ,
filePermission : permission ,
latestContributor : last _modifier _name ,
lastModified : moment . unix ( mtime ) . fromNow ( ) ,
isFileLoading : false ,
isFileLoadedErr : false ,
isDraft : is _draft ,
hasDraft : has _draft ,
draftID : draft _id
} ) ;
} ) ;
} ) ;
} ) . catch ( ( ) => {
this . setState ( {
isFileLoading : false ,
isFileLoadedErr : true ,
} ) ;
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-05-10 07:40:01 +00:00
2019-02-20 03:54:25 +00:00
// load data
loadDirData = ( path ) => {
let repoID = this . props . repoID ;
// listen current repo
collabServer . watchRepo ( repoID , this . onRepoUpdateEvent ) ;
// list used FileTags
this . updateUsedRepoTags ( ) ;
2022-04-11 09:27:02 +00:00
// list draft counts and review counts
2019-04-17 05:08:47 +00:00
if ( isDocs ) {
seafileAPI . getRepoDraftCounts ( repoID ) . then ( res => {
this . setState ( {
draftCounts : res . data . draft _counts ,
} ) ;
2019-07-16 02:01:09 +00:00
} ) . catch ( error => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
2019-04-17 05:08:47 +00:00
}
2020-11-02 05:56:35 +00:00
2019-02-28 07:36:14 +00:00
if ( Utils . isMarkdownFile ( path ) ) {
seafileAPI . getFileInfo ( this . props . repoID , path ) . then ( ( ) => {
if ( this . state . currentMode !== 'column' ) {
2019-04-13 03:56:44 +00:00
cookie . save ( 'seafile_view_mode' , 'column' ) ;
2019-02-28 07:36:14 +00:00
this . setState ( { currentMode : 'column' } ) ;
}
this . loadSidePanel ( path ) ;
this . showFile ( path ) ;
} ) . catch ( ( ) => {
if ( this . state . currentMode === 'column' ) { // After an error occurs, follow dir
this . loadSidePanel ( path ) ;
this . showDir ( path ) ;
} else {
this . showDir ( path ) ;
}
} ) ;
} else {
if ( this . state . currentMode === 'column' ) {
this . loadSidePanel ( path ) ;
this . showDir ( path ) ;
2019-02-20 03:54:25 +00:00
} else {
this . showDir ( path ) ;
}
}
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
loadSidePanel = ( path ) => {
let repoID = this . props . repoID ;
if ( path === '/' ) {
seafileAPI . listDir ( repoID , '/' ) . then ( res => {
2022-04-11 09:52:07 +00:00
const { dirent _list , user _perm } = res . data ;
2019-02-20 03:54:25 +00:00
let tree = this . state . treeData ;
2022-04-11 09:52:07 +00:00
this . addResponseListToNode ( dirent _list , tree . root ) ;
2019-02-20 03:54:25 +00:00
this . setState ( {
isTreeDataLoading : false ,
2022-04-11 09:52:07 +00:00
treeData : tree ,
userPerm : user _perm ,
2019-02-20 03:54:25 +00:00
} ) ;
} ) . catch ( ( ) => {
this . setState ( { isTreeDataLoading : false } ) ;
} ) ;
} else {
this . loadNodeAndParentsByPath ( path ) ;
}
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
showDir = ( path ) => {
let repoID = this . props . repoID ;
2019-05-12 07:05:53 +00:00
if ( ! this . state . isSessionExpired ) {
// update stste
this . setState ( {
isDirentListLoading : true ,
isViewFile : false ,
selectedDirentList : [ ] ,
} ) ;
}
2019-02-20 03:54:25 +00:00
// update data
2019-02-23 03:59:26 +00:00
this . loadDirentList ( path ) ;
2019-05-05 09:20:37 +00:00
this . resetShowLength ( ) ;
2019-02-20 03:54:25 +00:00
2019-02-23 03:59:26 +00:00
if ( ! this . isNeedUpdateHistoryState ) {
this . isNeedUpdateHistoryState = true ;
return ;
}
2019-02-20 03:54:25 +00:00
// update location
let repoInfo = this . state . currentRepoInfo ;
let url = siteRoot + 'library/' + repoID + '/' + encodeURIComponent ( repoInfo . repo _name ) + Utils . encodePath ( path ) ;
window . history . pushState ( { url : url , path : path } , path , url ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
showFile = ( filePath ) => {
let repoID = this . props . repoID ;
2019-03-15 02:10:24 +00:00
if ( this . state . currentMode === 'column' ) {
seafileAPI . listFileTags ( repoID , filePath ) . then ( res => {
let fileTags = res . data . file _tags . map ( item => {
return new FileTag ( item ) ;
} ) ;
this . setState ( { fileTags : fileTags } ) ;
2019-07-16 02:01:09 +00:00
} ) . catch ( error => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
2019-03-15 02:10:24 +00:00
} ) ;
}
2019-02-20 03:54:25 +00:00
// update state
this . setState ( {
isFileLoading : true ,
path : filePath ,
isViewFile : true
} ) ;
// update data
seafileAPI . getFileInfo ( repoID , filePath ) . then ( ( res ) => {
2019-03-05 07:37:51 +00:00
let { mtime , permission , last _modifier _name , is _draft , has _draft , draft _id } = res . data ;
2019-02-20 03:54:25 +00:00
seafileAPI . getFileDownloadLink ( repoID , filePath ) . then ( ( res ) => {
seafileAPI . getFileContent ( res . data ) . then ( ( res ) => {
this . setState ( {
content : res . data ,
2019-04-19 07:50:27 +00:00
filePermission : permission ,
2019-02-20 03:54:25 +00:00
latestContributor : last _modifier _name ,
lastModified : moment . unix ( mtime ) . fromNow ( ) ,
isFileLoading : false ,
2019-02-21 09:37:04 +00:00
isFileLoadedErr : false ,
2019-02-20 03:54:25 +00:00
isDraft : is _draft ,
hasDraft : has _draft ,
2019-03-05 07:37:51 +00:00
draftID : draft _id
2019-02-20 03:54:25 +00:00
} ) ;
} ) ;
} ) ;
2019-05-12 07:05:53 +00:00
} ) . catch ( ( err ) => {
2019-12-19 05:44:30 +00:00
let errMsg = Utils . getErrorMsg ( err , true ) ;
if ( ! err . response || err . response . status !== 403 ) {
toaster . danger ( errMsg ) ;
2019-05-12 07:05:53 +00:00
}
2019-02-21 09:37:04 +00:00
this . setState ( {
isFileLoading : false ,
isFileLoadedErr : true ,
} ) ;
2019-02-20 03:54:25 +00:00
} ) ;
// update location
let repoInfo = this . state . currentRepoInfo ;
let url = siteRoot + 'library/' + repoID + '/' + encodeURIComponent ( repoInfo . repo _name ) + Utils . encodePath ( filePath ) ;
window . history . pushState ( { url : url , path : filePath } , filePath , url ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
2019-02-23 03:59:26 +00:00
loadDirentList = ( path ) => {
2019-03-19 10:20:45 +00:00
let repoID = this . props . repoID ;
2019-02-20 03:54:25 +00:00
seafileAPI . listDir ( repoID , path , { 'with_thumbnail' : true } ) . then ( res => {
let direntList = [ ] ;
res . data . dirent _list . forEach ( item => {
let dirent = new Dirent ( item ) ;
direntList . push ( dirent ) ;
} ) ;
this . setState ( {
pathExist : true ,
userPerm : res . data . user _perm ,
isDirentListLoading : false ,
direntList : Utils . sortDirents ( direntList , this . state . sortBy , this . state . sortOrder ) ,
2019-03-06 06:59:24 +00:00
dirID : res . data . dir _id ,
2019-05-12 07:05:53 +00:00
path : path ,
isSessionExpired : false ,
2019-02-20 03:54:25 +00:00
} ) ;
if ( ! this . state . repoEncrypted && direntList . length ) {
this . getThumbnails ( repoID , path , this . state . direntList ) ;
}
2023-11-15 09:01:50 +00:00
if ( this . state . currentRepoInfo . is _admin ) {
if ( this . foldersSharedOut ) {
this . identifyFoldersSharedOut ( ) ;
} else {
this . foldersSharedOut = [ ] ;
seafileAPI . getAllRepoFolderShareInfo ( repoID ) . then ( res => {
res . data . share _info _list . forEach ( item => {
if ( this . foldersSharedOut . indexOf ( item . path ) === - 1 ) {
this . foldersSharedOut . push ( item . path ) ;
}
} ) ;
this . identifyFoldersSharedOut ( ) ;
} ) ;
}
}
2019-05-12 07:05:53 +00:00
} ) . catch ( ( err ) => {
2019-12-19 05:44:30 +00:00
Utils . getErrorMsg ( err , true ) ;
if ( err . response && err . response . status === 403 ) {
2019-05-14 02:15:09 +00:00
this . setState ( { isDirentListLoading : false } ) ;
2019-05-12 07:05:53 +00:00
return ;
}
2019-02-20 03:54:25 +00:00
this . setState ( {
isDirentListLoading : false ,
pathExist : false ,
} ) ;
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
2023-11-15 09:01:50 +00:00
identifyFoldersSharedOut = ( ) => {
const { path , direntList } = this . state ;
if ( this . foldersSharedOut . length == 0 ) {
return ;
}
direntList . forEach ( dirent => {
if ( dirent . type == 'dir' && this . foldersSharedOut . indexOf ( Utils . joinPath ( path , dirent . name ) + '/' ) !== - 1 ) {
dirent . has _been _shared _out = true ;
}
} ) ;
this . setState ( {
direntList : direntList
} ) ;
} ;
2019-04-24 07:16:26 +00:00
onListContainerScroll = ( ) => {
2019-04-24 07:24:27 +00:00
let itemsShowLength = this . state . itemsShowLength + 100 ;
2019-04-24 05:37:48 +00:00
this . setState ( { itemsShowLength : itemsShowLength } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-23 06:43:47 +00:00
2019-04-24 07:16:26 +00:00
resetShowLength = ( ) => {
2019-04-24 05:37:48 +00:00
this . setState ( { itemsShowLength : 100 } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-23 06:43:47 +00:00
2019-02-20 03:54:25 +00:00
getThumbnails = ( repoID , path , direntList ) => {
let items = direntList . filter ( ( item ) => {
2021-07-19 06:46:17 +00:00
return ( Utils . imageCheck ( item . name ) || ( enableVideoThumbnail && Utils . videoCheck ( item . name ) ) ) && ! item . encoded _thumbnail _src ;
2019-02-20 03:54:25 +00:00
} ) ;
if ( items . length == 0 ) {
return ;
}
const _this = this ;
const len = items . length ;
const thumbnailSize = 48 ;
let getThumbnail = ( i ) => {
const curItem = items [ i ] ;
const curItemPath = [ path , curItem . name ] . join ( '/' ) ;
seafileAPI . createThumbnail ( repoID , curItemPath , thumbnailSize ) . then ( ( res ) => {
curItem . encoded _thumbnail _src = res . data . encoded _thumbnail _src ;
} ) . catch ( ( error ) => {
// do nothing
} ) . then ( ( ) => {
if ( i < len - 1 ) {
getThumbnail ( ++ i ) ;
} else {
_this . setState ( {
2020-11-02 05:56:35 +00:00
direntList : direntList
2019-02-20 03:54:25 +00:00
} ) ;
}
} ) ;
} ;
getThumbnail ( 0 ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
2019-06-12 12:50:12 +00:00
updateMoveCopyTreeNode = ( path ) => {
2019-06-12 09:50:55 +00:00
let repoID = this . props . repoID ;
2019-06-12 12:50:12 +00:00
let tree = this . state . treeData . clone ( ) ;
let node = tree . getNodeByPath ( path ) ;
2023-09-07 07:39:48 +00:00
// for node not loaded, such as a deep folder '/vv/aa'
if ( ! node ) { // node: null
return false ;
}
2019-06-12 13:43:33 +00:00
let nodeChildren = node . children . map ( item => item . object ) ;
let nodeChildrenNames = nodeChildren . map ( item => item . name ) ;
2019-06-12 12:50:12 +00:00
2019-06-12 09:50:55 +00:00
seafileAPI . listDir ( repoID , path ) . then ( res => {
2019-06-12 13:43:33 +00:00
let newDirentList = res . data . dirent _list ;
let newAddedDirents = newDirentList . filter ( item => {
2019-06-21 05:59:17 +00:00
return ! nodeChildrenNames . includes ( item . name ) ;
} ) ;
2023-09-13 00:40:50 +00:00
newAddedDirents . forEach ( item => {
2019-06-12 09:50:55 +00:00
this . addNodeToTree ( item . name , path , item . type ) ;
2019-06-21 05:59:17 +00:00
} ) ;
2019-07-16 02:01:09 +00:00
} ) . catch ( error => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
2019-06-12 09:50:55 +00:00
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-06-12 12:50:12 +00:00
2020-02-29 09:02:11 +00:00
async getAsyncCopyMoveProgress ( ) {
let { asyncOperationType , asyncCopyMoveTaskId } = this . state ;
try {
let res = await seafileAPI . queryAsyncOperationProgress ( asyncCopyMoveTaskId ) ;
let data = res . data ;
if ( data . failed ) {
2020-03-02 08:44:39 +00:00
let message = gettext ( 'Failed to move files to another library.' ) ;
2020-02-29 09:02:11 +00:00
if ( asyncOperationType === 'copy' ) {
2020-03-02 08:44:39 +00:00
message = gettext ( 'Failed to copy files to another library.' ) ;
2020-02-29 09:02:11 +00:00
}
toaster . danger ( message ) ;
this . setState ( {
asyncOperationProgress : 0 ,
isCopyMoveProgressDialogShow : false ,
} ) ;
return ;
}
2020-11-02 05:56:35 +00:00
2020-02-29 09:02:11 +00:00
if ( data . successful ) {
2020-04-02 07:45:33 +00:00
if ( asyncOperationType === 'move' ) {
2020-04-10 10:08:27 +00:00
if ( this . currentMoveItemName && this . currentMoveItemPath ) {
if ( this . state . currentMode === 'column' ) {
this . deleteTreeNode ( this . currentMoveItemPath ) ;
}
this . moveDirent ( this . currentMoveItemName ) ;
2020-04-11 09:54:52 +00:00
this . currentMoveItemName = '' ;
this . currentMoveItemPath = '' ;
2020-04-10 10:08:27 +00:00
} else {
if ( this . state . currentMode === 'column' ) {
let direntPaths = this . getSelectedDirentPaths ( ) ;
this . deleteTreeNodes ( direntPaths ) ;
}
let direntNames = this . getSelectedDirentNames ( ) ;
this . moveDirents ( direntNames ) ;
2020-04-02 07:45:33 +00:00
}
}
2020-02-29 09:02:11 +00:00
this . setState ( { isCopyMoveProgressDialogShow : false } ) ;
2020-03-02 08:44:39 +00:00
let message = gettext ( 'Successfully moved files to another library.' ) ;
2020-02-29 09:02:11 +00:00
if ( asyncOperationType === 'copy' ) {
2020-03-02 09:47:34 +00:00
message = gettext ( 'Successfully copied files to another library.' ) ;
2020-02-29 09:02:11 +00:00
}
toaster . success ( message ) ;
return ;
}
2020-04-02 07:45:33 +00:00
// init state: total is 0
let asyncOperationProgress = ! data . total ? 0 : parseInt ( ( data . done / data . total * 100 ) . toFixed ( 2 ) ) ;
2020-02-29 09:02:11 +00:00
this . getAsyncCopyMoveProgress ( ) ;
2020-04-02 07:45:33 +00:00
this . setState ( { asyncOperationProgress : asyncOperationProgress } ) ;
2020-02-29 09:02:11 +00:00
} catch ( error ) {
this . setState ( {
asyncOperationProgress : 0 ,
isCopyMoveProgressDialogShow : false ,
2020-11-02 05:56:35 +00:00
} ) ;
2020-02-29 09:02:11 +00:00
}
}
cancelCopyMoveDirent = ( ) => {
2020-04-11 10:03:45 +00:00
let taskId = this . state . asyncCopyMoveTaskId ;
2020-02-29 09:02:11 +00:00
seafileAPI . cancelCopyMoveOperation ( taskId ) ;
2020-04-11 10:09:39 +00:00
this . currentMoveItemName = '' ;
this . currentMoveItemPath = '' ;
2020-04-11 10:03:45 +00:00
let direntList = this . state . direntList ;
2020-04-11 09:54:52 +00:00
this . setState ( { direntList : direntList . slice ( 0 ) } ) ;
2023-09-13 00:40:50 +00:00
} ;
2020-02-29 09:02:11 +00:00
onMoveProgressDialogToggle = ( ) => {
let { asyncOperationProgress } = this . state ;
2020-04-02 07:45:33 +00:00
if ( asyncOperationProgress !== 100 ) {
2020-02-29 09:02:11 +00:00
this . cancelCopyMoveDirent ( ) ;
}
this . setState ( {
asyncOperationProgress : 0 ,
isCopyMoveProgressDialogShow : false ,
2020-11-02 05:56:35 +00:00
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2020-02-29 09:02:11 +00:00
2019-02-20 03:54:25 +00:00
// toolbar operations
onMoveItems = ( destRepo , destDirentPath ) => {
let repoID = this . props . repoID ;
2020-03-31 05:45:36 +00:00
let selectedDirentList = this . state . selectedDirentList ;
2020-02-29 09:02:11 +00:00
if ( repoID !== destRepo . repo _id ) {
2020-03-31 05:45:36 +00:00
this . setState ( ( ) => ( {
asyncOperatedFilesLength : selectedDirentList . length ,
2020-02-29 09:02:11 +00:00
asyncOperationProgress : 0 ,
asyncOperationType : 'move' ,
isCopyMoveProgressDialogShow : true
2020-03-31 05:45:36 +00:00
} ) ) ;
2020-02-29 09:02:11 +00:00
}
2020-11-02 05:56:35 +00:00
2020-03-31 05:45:36 +00:00
let dirNames = this . getSelectedDirentNames ( ) ;
let direntPaths = this . getSelectedDirentPaths ( ) ;
2019-06-12 06:59:33 +00:00
seafileAPI . moveDir ( repoID , destRepo . repo _id , destDirentPath , this . state . path , dirNames ) . then ( res => {
2019-07-23 01:42:09 +00:00
if ( repoID !== destRepo . repo _id ) {
2020-02-29 09:02:11 +00:00
this . setState ( {
asyncCopyMoveTaskId : res . data . task _id ,
} , ( ) => {
2020-04-02 07:45:33 +00:00
// After moving successfully, delete related files
2020-02-29 09:02:11 +00:00
this . getAsyncCopyMoveProgress ( ) ;
2019-07-23 01:42:09 +00:00
} ) ;
2020-02-29 09:02:11 +00:00
}
2020-04-02 07:45:33 +00:00
if ( repoID === destRepo . repo _id ) {
2019-06-12 06:59:33 +00:00
if ( this . state . currentMode === 'column' ) {
2020-04-02 07:45:33 +00:00
this . deleteTreeNodes ( direntPaths ) ;
2019-06-12 06:59:33 +00:00
}
2020-11-02 05:56:35 +00:00
2020-04-02 07:45:33 +00:00
this . moveDirents ( dirNames ) ;
2020-02-29 09:02:11 +00:00
2020-04-02 07:45:33 +00:00
// 2. tow columns mode need update left tree
if ( this . state . currentMode === 'column' ) {
this . updateMoveCopyTreeNode ( destDirentPath ) ;
}
2020-02-29 09:02:11 +00:00
2020-04-02 07:45:33 +00:00
// show tip message if move to current repo
2019-07-23 01:42:09 +00:00
let message = Utils . getMoveSuccessMessage ( dirNames ) ;
toaster . success ( message ) ;
2019-06-12 06:59:33 +00:00
}
2020-04-02 07:45:33 +00:00
2019-07-16 02:01:09 +00:00
} ) . catch ( ( error ) => {
let errMessage = Utils . getErrorMsg ( error ) ;
if ( errMessage === gettext ( 'Error' ) ) {
errMessage = Utils . getMoveFailedMessage ( dirNames ) ;
}
2020-04-02 07:45:33 +00:00
this . setState ( {
asyncOperationProgress : 0 ,
isCopyMoveProgressDialogShow : false ,
} ) ;
2019-07-16 02:01:09 +00:00
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
onCopyItems = ( destRepo , destDirentPath ) => {
let repoID = this . props . repoID ;
2020-03-31 05:45:36 +00:00
let selectedDirentList = this . state . selectedDirentList ;
2020-11-02 05:56:35 +00:00
2020-02-29 09:02:11 +00:00
if ( repoID !== destRepo . repo _id ) {
this . setState ( {
2020-03-31 05:45:36 +00:00
asyncOperatedFilesLength : selectedDirentList . length ,
2020-02-29 09:02:11 +00:00
asyncOperationProgress : 0 ,
asyncOperationType : 'copy' ,
isCopyMoveProgressDialogShow : true
} ) ;
}
2020-11-02 05:56:35 +00:00
2020-03-31 05:45:36 +00:00
let dirNames = this . getSelectedDirentNames ( ) ;
2019-06-12 06:59:33 +00:00
seafileAPI . copyDir ( repoID , destRepo . repo _id , destDirentPath , this . state . path , dirNames ) . then ( res => {
2019-07-23 01:42:09 +00:00
if ( repoID !== destRepo . repo _id ) {
2020-02-29 09:02:11 +00:00
this . setState ( {
asyncCopyMoveTaskId : res . data . task _id ,
} , ( ) => {
this . getAsyncCopyMoveProgress ( ) ;
2019-07-23 01:42:09 +00:00
} ) ;
2019-02-20 03:54:25 +00:00
}
2020-02-29 09:02:11 +00:00
2020-04-02 07:45:33 +00:00
if ( repoID === destRepo . repo _id ) {
if ( this . state . currentMode === 'column' ) {
this . updateMoveCopyTreeNode ( destDirentPath ) ;
}
2020-02-29 09:02:11 +00:00
2020-04-02 07:45:33 +00:00
if ( destDirentPath === this . state . path ) {
this . loadDirentList ( this . state . path ) ;
}
// show tip message if copy to current repo
let message = Utils . getCopySuccessfulMessage ( dirNames ) ;
toaster . success ( message ) ;
2020-02-29 09:02:11 +00:00
}
2019-07-16 02:01:09 +00:00
} ) . catch ( ( error ) => {
let errMessage = Utils . getErrorMsg ( error ) ;
if ( errMessage === gettext ( 'Error' ) ) {
errMessage = Utils . getCopyFailedMessage ( dirNames ) ;
}
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
2023-04-22 00:03:58 +00:00
restoreDeletedDirents = ( commitID , paths , e ) => {
const { repoID } = this . props ;
e . preventDefault ( ) ;
toaster . closeAll ( ) ;
seafileAPI . restoreDirents ( repoID , commitID , paths ) . then ( res => {
const { success , failed } = res . data ;
success . forEach ( dirent => {
let name = Utils . getFileName ( dirent . path ) ;
let parentPath = Utils . getDirName ( dirent . path ) ;
if ( ! dirent . is _dir ) {
if ( this . state . currentMode === 'column' ) {
this . addNodeToTree ( name , parentPath , 'file' ) ;
}
if ( parentPath === this . state . path && ! this . state . isViewFile ) {
this . addDirent ( name , 'file' ) ;
}
} else {
if ( this . state . currentMode === 'column' ) {
this . addNodeToTree ( name , parentPath , 'dir' ) ;
}
if ( parentPath === this . state . path && ! this . state . isViewFile ) {
this . addDirent ( name , 'dir' ) ;
}
}
} ) ;
if ( success . length ) {
let msg = success . length > 1 ? gettext ( 'Restored {name} and {n} other items' ) :
gettext ( 'Restored {name}' ) ;
msg = msg . replace ( '{name}' , success [ 0 ] . path . split ( '/' ) . pop ( ) )
. replace ( '{n}' , success . length - 1 ) ;
toaster . success ( msg ) ;
}
if ( failed . length ) {
let msg = failed . length > 1 ? gettext ( 'Failed to restore {name} and {n} other items' ) :
gettext ( 'Failed to restore {name}' ) ;
msg = msg . replace ( '{name}' , failed [ 0 ] . path . split ( '/' ) . pop ( ) )
. replace ( '{n}' , failed . length - 1 ) ;
toaster . danger ( msg ) ;
}
} ) . catch ( ( error ) => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2023-04-22 00:03:58 +00:00
2019-02-20 03:54:25 +00:00
onDeleteItems = ( ) => {
let repoID = this . props . repoID ;
let direntPaths = this . getSelectedDirentPaths ( ) ;
let dirNames = this . getSelectedDirentNames ( ) ;
2019-04-18 05:39:42 +00:00
this . setState ( { updateDetail : ! this . state . updateDetail } ) ;
2019-02-20 03:54:25 +00:00
seafileAPI . deleteMutipleDirents ( repoID , this . state . path , dirNames ) . then ( res => {
2020-04-02 07:45:33 +00:00
if ( this . state . currentMode === 'column' ) {
this . deleteTreeNodes ( direntPaths ) ;
}
this . deleteDirents ( dirNames ) ;
2019-06-05 13:10:42 +00:00
let msg = '' ;
if ( direntPaths . length > 1 ) {
2023-04-22 00:03:58 +00:00
msg = gettext ( 'Successfully deleted {name} and {n} other items.' ) ;
2019-06-05 13:10:42 +00:00
msg = msg . replace ( '{name}' , dirNames [ 0 ] ) ;
msg = msg . replace ( '{n}' , dirNames . length - 1 ) ;
} else {
msg = gettext ( 'Successfully deleted {name}.' ) ;
msg = msg . replace ( '{name}' , dirNames [ 0 ] ) ;
}
2023-04-22 00:03:58 +00:00
const successTipWithUndo = (
< >
< span > { msg } < / s p a n >
< a className = "action-link p-0 ml-1" href = "#" onClick = { this . restoreDeletedDirents . bind ( this , res . data . commit _id , direntPaths ) } > { gettext ( 'Undo' ) } < / a >
< / >
) ;
toaster . success ( successTipWithUndo , { duration : 5 } ) ;
2019-07-16 02:01:09 +00:00
} ) . catch ( ( error ) => {
let errMessage = Utils . getErrorMsg ( error ) ;
if ( errMessage === gettext ( 'Error' ) ) {
2023-04-22 00:03:58 +00:00
errMessage = gettext ( 'Failed to delete {name} and {n} other items.' ) ;
2019-07-16 02:01:09 +00:00
errMessage = errMessage . replace ( '{name}' , dirNames [ 0 ] ) ;
errMessage = errMessage . replace ( '{n}' , dirNames . length - 1 ) ;
}
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
onAddFolder = ( dirPath ) => {
let repoID = this . props . repoID ;
seafileAPI . createDir ( repoID , dirPath ) . then ( ( ) => {
let name = Utils . getFileName ( dirPath ) ;
let parentPath = Utils . getDirName ( dirPath ) ;
if ( this . state . currentMode === 'column' ) {
this . addNodeToTree ( name , parentPath , 'dir' ) ;
}
if ( parentPath === this . state . path && ! this . state . isViewFile ) {
this . addDirent ( name , 'dir' ) ;
}
2019-07-16 02:01:09 +00:00
} ) . catch ( ( error ) => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
2023-07-22 07:54:25 +00:00
onAddFile = ( filePath , isMarkdownDraft , isSdocDraft ) => {
2019-02-20 03:54:25 +00:00
let repoID = this . props . repoID ;
2023-07-22 07:54:25 +00:00
seafileAPI . createFile ( repoID , filePath , isMarkdownDraft ) . then ( res => {
2019-02-20 03:54:25 +00:00
let name = Utils . getFileName ( filePath ) ;
let parentPath = Utils . getDirName ( filePath ) ;
if ( this . state . currentMode === 'column' ) {
this . addNodeToTree ( name , parentPath , 'file' ) ;
}
if ( parentPath === this . state . path && ! this . state . isViewFile ) {
2023-07-22 07:54:25 +00:00
if ( isSdocDraft ) { // the new file is marked to be draft
seafileAPI . sdocMarkAsDraft ( repoID , filePath ) . then ( ( res ) => {
this . addDirent ( name , 'file' , res . data . size , isSdocDraft ) ;
} ) . catch ( error => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
this . addDirent ( name , 'file' , res . data . size ) ;
} ) ;
return ;
}
2019-02-20 03:54:25 +00:00
this . addDirent ( name , 'file' , res . data . size ) ;
}
2019-07-16 02:01:09 +00:00
} ) . catch ( ( error ) => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
switchViewMode = ( mode ) => {
if ( mode === this . state . currentMode ) {
return ;
}
2019-04-10 08:04:26 +00:00
if ( mode === 'detail' ) {
this . toggleDirentDetail ( ) ;
return ;
}
2019-04-13 03:56:44 +00:00
cookie . save ( 'seafile_view_mode' , mode ) ;
2019-02-20 03:54:25 +00:00
let path = this . state . path ;
if ( this . state . currentMode === 'column' && this . state . isViewFile ) {
path = Utils . getDirName ( path ) ;
this . setState ( {
path : path ,
isViewFile : false ,
} ) ;
let repoInfo = this . state . currentRepoInfo ;
let url = siteRoot + 'library/' + repoInfo . repo _id + '/' + encodeURIComponent ( repoInfo . repo _name ) + Utils . encodePath ( path ) ;
window . history . pushState ( { url : url , path : path } , path , url ) ;
}
if ( mode === 'column' ) {
this . loadSidePanel ( this . state . path ) ;
}
2019-02-23 03:59:26 +00:00
this . isNeedUpdateHistoryState = false ;
2019-02-20 03:54:25 +00:00
this . setState ( { currentMode : mode } ) ;
2019-02-21 10:09:17 +00:00
this . showDir ( path ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
onSearchedClick = ( item ) => {
2020-11-02 05:56:35 +00:00
let path = item . is _dir ? item . path . slice ( 0 , item . path . length - 1 ) : item . path ;
2019-02-20 03:54:25 +00:00
if ( this . state . currentPath === path ) {
return ;
}
if ( this . state . currentMode === 'column' ) {
// load sidePanel
let index = - 1 ;
let paths = Utils . getPaths ( path ) ;
for ( let i = 0 ; i < paths . length ; i ++ ) {
2023-09-13 00:40:50 +00:00
// eslint-disable-next-line
2019-02-20 03:54:25 +00:00
let node = this . state . treeData . getNodeByPath ( node ) ;
if ( ! node ) {
index = i ;
break ;
2020-11-02 05:56:35 +00:00
}
2019-02-20 03:54:25 +00:00
}
if ( index === - 1 ) { // all the data has been loaded already.
let node = this . state . treeData . getNodeByPath ( path ) ;
this . setState ( { currentNode : node } ) ;
} else {
this . loadNodeAndParentsByPath ( path ) ;
}
2019-04-13 03:56:44 +00:00
// load mainPanel
if ( item . is _dir ) {
this . showDir ( path ) ;
} else {
if ( Utils . isMarkdownFile ( path ) ) {
this . showFile ( path ) ;
} else {
let url = siteRoot + 'lib/' + item . repo _id + '/file' + Utils . encodePath ( path ) ;
2019-10-22 04:01:00 +00:00
let isWeChat = Utils . isWeChat ( ) ;
if ( ! isWeChat ) {
let newWindow = window . open ( 'about:blank' ) ;
newWindow . location . href = url ;
} else {
location . href = url ;
}
2019-04-13 03:56:44 +00:00
}
}
2019-02-20 03:54:25 +00:00
} else {
2019-04-13 03:56:44 +00:00
if ( item . is _dir ) {
this . showDir ( path ) ;
2019-02-20 03:54:25 +00:00
} else {
let url = siteRoot + 'lib/' + item . repo _id + '/file' + Utils . encodePath ( path ) ;
2019-10-22 04:01:00 +00:00
let isWeChat = Utils . isWeChat ( ) ;
if ( ! isWeChat ) {
let newWindow = window . open ( 'about:blank' ) ;
newWindow . location . href = url ;
} else {
location . href = url ;
}
2019-02-20 03:54:25 +00:00
}
}
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
onMainNavBarClick = ( nodePath ) => {
//just for dir
this . resetSelected ( ) ;
if ( this . state . currentMode === 'column' ) {
let tree = this . state . treeData . clone ( ) ;
let node = tree . getNodeByPath ( nodePath ) ;
tree . expandNode ( node ) ;
this . setState ( { treeData : tree , currentNode : node } ) ;
}
this . showDir ( nodePath ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
onLinkClick = ( link ) => {
const url = link ;
let repoID = this . props . repoID ;
if ( Utils . isInternalMarkdownLink ( url , repoID ) ) {
let path = Utils . getPathFromInternalMarkdownLink ( url , repoID ) ;
this . showFile ( path ) ;
} else if ( Utils . isInternalDirLink ( url , repoID ) ) {
let path = Utils . getPathFromInternalDirLink ( url , repoID ) ;
this . showDir ( path ) ;
} else {
window . open ( url ) ;
}
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
// list&tree operations
onMainPanelItemRename = ( dirent , newName ) => {
let path = Utils . joinPath ( this . state . path , dirent . name ) ;
this . renameItem ( path , dirent . isDir ( ) , newName ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
onMainPanelItemDelete = ( dirent ) => {
let path = Utils . joinPath ( this . state . path , dirent . name ) ;
this . deleteItem ( path , dirent . isDir ( ) ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
onRenameTreeNode = ( node , newName ) => {
this . renameItem ( node . path , node . object . isDir ( ) , newName ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
onDeleteTreeNode = ( node ) => {
this . deleteItem ( node . path , node . object . isDir ( ) ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
renameItem = ( path , isDir , newName ) => {
let repoID = this . props . repoID ;
if ( isDir ) {
seafileAPI . renameDir ( repoID , path , newName ) . then ( ( ) => {
this . renameItemAjaxCallback ( path , newName ) ;
2019-07-16 02:01:09 +00:00
} ) . catch ( ( error ) => {
let errMessage = Utils . getErrorMsg ( error ) ;
if ( errMessage === gettext ( 'Error' ) ) {
let name = Utils . getFileName ( path ) ;
errMessage = gettext ( 'Renaming {name} failed' ) . replace ( '{name}' , name ) ;
}
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
} else {
seafileAPI . renameFile ( repoID , path , newName ) . then ( ( ) => {
this . renameItemAjaxCallback ( path , newName ) ;
2019-07-16 02:01:09 +00:00
} ) . catch ( ( error ) => {
2023-11-15 07:39:47 +00:00
let errMessage = '' ;
2023-11-11 09:17:41 +00:00
if ( error . response . status == 403 && error . response . data && error . response . data [ 'error_msg' ] ) {
errMessage = error . response . data [ 'error_msg' ] ;
} else {
errMessage = Utils . getErrorMsg ( error ) ;
2023-11-15 07:39:47 +00:00
}
2019-07-16 02:01:09 +00:00
if ( errMessage === gettext ( 'Error' ) ) {
let name = Utils . getFileName ( path ) ;
errMessage = gettext ( 'Renaming {name} failed' ) . replace ( '{name}' , name ) ;
}
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
}
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
renameItemAjaxCallback ( path , newName ) {
if ( this . state . currentMode === 'column' ) {
this . renameTreeNode ( path , newName ) ;
}
this . renameDirent ( path , newName ) ;
}
2022-11-28 01:27:17 +00:00
toggleDeleteFolderDialog = ( ) => {
this . setState ( { isDeleteFolderDialogOpen : ! this . state . isDeleteFolderDialogOpen } ) ;
2023-09-13 00:40:50 +00:00
} ;
2022-11-28 01:27:17 +00:00
deleteFolder = ( ) => {
const { repoID } = this . props ;
const { folderToDelete : path } = this . state ;
2023-05-16 07:46:38 +00:00
seafileAPI . deleteDir ( repoID , path ) . then ( ( res ) => {
2022-11-28 01:27:17 +00:00
this . deleteItemAjaxCallback ( path , true ) ;
let name = Utils . getFileName ( path ) ;
var msg = gettext ( 'Successfully deleted {name}' ) . replace ( '{name}' , name ) ;
2023-05-16 07:46:38 +00:00
const successTipWithUndo = (
< >
< span > { msg } < / s p a n >
< a className = "action-link p-0 ml-1" href = "#" onClick = { this . restoreDeletedDirents . bind ( this , res . data . commit _id , [ path ] ) } > { gettext ( 'Undo' ) } < / a >
< / >
) ;
toaster . success ( successTipWithUndo , { duration : 5 } ) ;
2022-11-28 01:27:17 +00:00
} ) . catch ( ( error ) => {
let errMessage = Utils . getErrorMsg ( error ) ;
if ( errMessage === gettext ( 'Error' ) ) {
let name = Utils . getFileName ( path ) ;
errMessage = gettext ( 'Failed to delete {name}' ) . replace ( '{name}' , name ) ;
}
toaster . danger ( errMessage ) ;
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2022-11-28 01:27:17 +00:00
2019-02-20 03:54:25 +00:00
deleteItem ( path , isDir ) {
let repoID = this . props . repoID ;
if ( isDir ) {
2022-11-28 01:27:17 +00:00
this . setState ( { folderToDelete : path } , ( ) => {
this . toggleDeleteFolderDialog ( ) ;
2019-02-20 03:54:25 +00:00
} ) ;
} else {
2023-05-16 07:46:38 +00:00
seafileAPI . deleteFile ( repoID , path ) . then ( ( res ) => {
2019-02-20 03:54:25 +00:00
this . deleteItemAjaxCallback ( path , isDir ) ;
2019-05-28 09:48:44 +00:00
let name = Utils . getFileName ( path ) ;
2019-05-29 04:02:07 +00:00
var msg = gettext ( 'Successfully deleted {name}' ) . replace ( '{name}' , name ) ;
2023-05-16 07:46:38 +00:00
const successTipWithUndo = (
< >
< span > { msg } < / s p a n >
< a className = "action-link p-0 ml-1" href = "#" onClick = { this . restoreDeletedDirents . bind ( this , res . data . commit _id , [ path ] ) } > { gettext ( 'Undo' ) } < / a >
< / >
) ;
toaster . success ( successTipWithUndo , { duration : 5 } ) ;
2019-07-16 02:01:09 +00:00
} ) . catch ( ( error ) => {
let errMessage = Utils . getErrorMsg ( error ) ;
if ( errMessage === gettext ( 'Error' ) ) {
let name = Utils . getFileName ( path ) ;
errMessage = gettext ( 'Failed to delete {name}' ) . replace ( '{name}' , name ) ;
}
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
}
}
deleteItemAjaxCallback ( path ) {
if ( this . state . currentMode === 'column' ) {
this . deleteTreeNode ( path ) ;
}
this . deleteDirent ( path ) ;
}
// list operations
2019-03-20 03:04:36 +00:00
onMoveItem = ( destRepo , dirent , moveToDirentPath , nodeParentPath ) => {
2019-02-20 03:54:25 +00:00
let repoID = this . props . repoID ;
//just for view list state
let dirName = dirent . name ;
2019-03-20 03:04:36 +00:00
if ( ! nodeParentPath ) {
nodeParentPath = this . state . path ;
}
let direntPath = Utils . joinPath ( nodeParentPath , dirName ) ;
2020-02-29 09:02:11 +00:00
if ( repoID !== destRepo . repo _id ) {
this . setState ( {
2020-03-02 08:44:39 +00:00
asyncOperatedFilesLength : 1 ,
2020-02-29 09:02:11 +00:00
asyncOperationProgress : 0 ,
asyncOperationType : 'move' ,
isCopyMoveProgressDialogShow : true ,
} ) ;
}
2019-05-05 09:20:37 +00:00
seafileAPI . moveDir ( repoID , destRepo . repo _id , moveToDirentPath , nodeParentPath , dirName ) . then ( res => {
2019-07-23 01:42:09 +00:00
if ( repoID !== destRepo . repo _id ) {
2020-04-10 10:08:27 +00:00
this . setState ( { asyncCopyMoveTaskId : res . data . task _id } , ( ) => {
this . currentMoveItemName = dirName ;
this . currentMoveItemPath = direntPath ;
this . getAsyncCopyMoveProgress ( dirName , direntPath ) ;
2019-07-23 01:42:09 +00:00
} ) ;
2020-02-29 09:02:11 +00:00
}
if ( this . state . currentMode === 'column' ) {
this . deleteTreeNode ( direntPath ) ;
}
2020-11-02 05:56:35 +00:00
// 1. move to current repo
2020-02-29 09:02:11 +00:00
// 2. tow columns mode need update left tree
if ( repoID === destRepo . repo _id && this . state . currentMode === 'column' ) {
this . updateMoveCopyTreeNode ( moveToDirentPath ) ;
}
this . moveDirent ( direntPath , moveToDirentPath ) ;
// show tip message if move to current repo
if ( repoID === destRepo . repo _id ) {
2019-07-24 23:55:52 +00:00
let message = gettext ( 'Successfully moved {name}.' ) ;
message = message . replace ( '{name}' , dirName ) ;
2019-07-23 01:42:09 +00:00
toaster . success ( message ) ;
2019-02-20 03:54:25 +00:00
}
2019-07-16 02:01:09 +00:00
} ) . catch ( ( error ) => {
let errMessage = Utils . getErrorMsg ( error ) ;
if ( errMessage === gettext ( 'Error' ) ) {
2019-07-24 23:55:52 +00:00
errMessage = gettext ( 'Failed to move {name}.' ) ;
errMessage = errMessage . replace ( '{name}' , dirName ) ;
2019-07-16 02:01:09 +00:00
}
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
2019-03-20 03:04:36 +00:00
onCopyItem = ( destRepo , dirent , copyToDirentPath , nodeParentPath ) => {
2019-02-20 03:54:25 +00:00
let repoID = this . props . repoID ;
//just for view list state
let dirName = dirent . name ;
2019-03-20 03:04:36 +00:00
if ( ! nodeParentPath ) {
nodeParentPath = this . state . path ;
}
2020-02-29 09:02:11 +00:00
if ( repoID !== destRepo . repo _id ) {
this . setState ( {
2020-03-02 08:44:39 +00:00
asyncOperatedFilesLength : 1 ,
2020-02-29 09:02:11 +00:00
asyncOperationProgress : 0 ,
asyncOperationType : 'copy' ,
isCopyMoveProgressDialogShow : true
} ) ;
}
2019-06-12 06:59:33 +00:00
2019-03-20 03:04:36 +00:00
seafileAPI . copyDir ( repoID , destRepo . repo _id , copyToDirentPath , nodeParentPath , dirName ) . then ( res => {
2020-11-02 05:56:35 +00:00
2019-07-23 01:42:09 +00:00
if ( repoID !== destRepo . repo _id ) {
2020-02-29 09:02:11 +00:00
this . setState ( {
asyncCopyMoveTaskId : res . data . task _id ,
} , ( ) => {
this . getAsyncCopyMoveProgress ( ) ;
2019-07-23 01:42:09 +00:00
} ) ;
2020-02-29 09:02:11 +00:00
}
2020-04-10 10:08:27 +00:00
if ( repoID === destRepo . repo _id ) {
if ( this . state . currentMode === 'column' ) {
this . updateMoveCopyTreeNode ( copyToDirentPath ) ;
}
2020-02-29 09:02:11 +00:00
2020-04-10 10:08:27 +00:00
if ( copyToDirentPath === nodeParentPath ) {
this . loadDirentList ( this . state . path ) ;
}
2020-02-29 09:02:11 +00:00
2019-07-23 01:42:09 +00:00
let message = gettext ( 'Successfully copied %(name)s.' ) ;
message = message . replace ( '%(name)s' , dirName ) ;
toaster . success ( message ) ;
2019-02-20 03:54:25 +00:00
}
2019-07-16 02:01:09 +00:00
} ) . catch ( ( error ) => {
let errMessage = Utils . getErrorMsg ( error ) ;
if ( errMessage === gettext ( 'Error' ) ) {
errMessage = gettext ( 'Failed to copy %(name)s' ) ;
errMessage = errMessage . replace ( '%(name)s' , dirName ) ;
}
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
2023-09-14 06:36:58 +00:00
onConvertItem = ( dirent , dstType ) => {
let path = Utils . joinPath ( this . state . path , dirent . name ) ;
let repoID = this . props . repoID ;
2023-12-11 10:19:23 +00:00
toaster . notifyInProgress ( gettext ( 'Converting, please wait...' ) ) ;
2023-09-14 06:36:58 +00:00
seafileAPI . convertFile ( repoID , path , dstType ) . then ( ( res ) => {
2023-09-25 13:56:00 +00:00
let newFileName = res . data . obj _name ;
2023-09-14 06:36:58 +00:00
let parentDir = res . data . parent _dir ;
2023-09-25 13:56:00 +00:00
let new _path = parentDir + '/' + newFileName ;
let parentPath = Utils . getDirName ( new _path ) ;
2023-09-14 06:36:58 +00:00
if ( this . state . currentMode === 'column' ) {
2023-09-25 13:56:00 +00:00
this . addNodeToTree ( newFileName , parentPath , 'file' ) ;
2023-09-18 02:20:47 +00:00
}
2023-09-25 13:56:00 +00:00
this . addDirent ( newFileName , 'file' , res . data . size ) ;
2023-10-08 06:20:14 +00:00
let message = gettext ( 'Successfully converted the file.' ) ;
2023-09-25 13:56:00 +00:00
toaster . success ( message ) ;
2023-09-14 06:36:58 +00:00
} ) . catch ( ( error ) => {
let errMessage = Utils . getErrorMsg ( error ) ;
if ( errMessage === gettext ( 'Error' ) ) {
let name = Utils . getFileName ( path ) ;
2023-10-08 06:20:14 +00:00
errMessage = gettext ( 'Failed to convert {name}.' ) . replace ( '{name}' , name ) ;
2023-09-14 06:36:58 +00:00
}
toaster . danger ( errMessage ) ;
} ) ;
2023-09-25 13:56:00 +00:00
2023-09-18 02:20:47 +00:00
} ;
2023-09-14 06:36:58 +00:00
2019-02-20 03:54:25 +00:00
onDirentClick = ( dirent ) => {
2019-04-12 12:21:54 +00:00
let direntList = this . state . direntList . map ( dirent => {
dirent . isSelected = false ;
return dirent ;
} ) ;
2019-04-13 01:57:44 +00:00
if ( dirent ) {
2019-04-13 02:45:11 +00:00
// dirent.isSelected = true;
2019-04-13 01:57:44 +00:00
this . setState ( {
direntList : direntList ,
isDirentSelected : true ,
selectedDirentList : [ dirent ] ,
} ) ;
} else {
this . setState ( {
direntList : direntList ,
isDirentSelected : false ,
selectedDirentList : [ ] ,
} ) ;
}
2023-09-13 00:40:50 +00:00
} ;
2019-04-12 12:21:54 +00:00
onItemClick = ( dirent ) => {
2019-02-20 03:54:25 +00:00
this . resetSelected ( ) ;
let repoID = this . props . repoID ;
let direntPath = Utils . joinPath ( this . state . path , dirent . name ) ;
if ( dirent . isDir ( ) ) { // is dir
if ( this . state . currentMode === 'column' ) {
this . loadTreeNodeByPath ( direntPath ) ;
}
this . showDir ( direntPath ) ;
} else { // is file
if ( this . state . currentMode === 'column' && Utils . isMarkdownFile ( direntPath ) ) {
2019-05-14 08:58:59 +00:00
this . showColumnMarkdownFile ( direntPath ) ;
2019-02-20 03:54:25 +00:00
} else {
2023-07-24 02:47:12 +00:00
let url = siteRoot + 'lib/' + repoID + '/file' + Utils . encodePath ( direntPath ) ;
if ( dirent . is _sdoc _revision && dirent . revision _id ) {
url = siteRoot + 'lib/' + repoID + '/revisions/' + dirent . revision _id + '/' ;
}
2020-11-02 05:56:35 +00:00
2019-10-15 02:16:48 +00:00
let isWeChat = Utils . isWeChat ( ) ;
if ( ! isWeChat ) {
2020-12-10 03:30:16 +00:00
window . open ( url ) ;
2019-10-15 02:16:48 +00:00
} else {
location . href = url ;
}
2019-02-20 03:54:25 +00:00
}
}
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
onDirentSelected = ( dirent ) => {
let direntList = this . state . direntList . map ( item => {
if ( item . name === dirent . name ) {
item . isSelected = ! item . isSelected ;
}
return item ;
} ) ;
let selectedDirentList = direntList . filter ( item => {
return item . isSelected ;
} ) ;
if ( selectedDirentList . length ) {
this . setState ( { isDirentSelected : true } ) ;
if ( selectedDirentList . length === direntList . length ) {
this . setState ( {
isAllDirentSelected : true ,
direntList : direntList ,
selectedDirentList : selectedDirentList ,
} ) ;
} else {
this . setState ( {
isAllDirentSelected : false ,
direntList : direntList ,
selectedDirentList : selectedDirentList
} ) ;
}
} else {
this . setState ( {
isDirentSelected : false ,
isAllDirentSelected : false ,
direntList : direntList ,
selectedDirentList : [ ]
} ) ;
}
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
onAllDirentSelected = ( ) => {
if ( this . state . isAllDirentSelected ) {
let direntList = this . state . direntList . map ( item => {
item . isSelected = false ;
return item ;
} ) ;
this . setState ( {
isDirentSelected : false ,
isAllDirentSelected : false ,
direntList : direntList ,
selectedDirentList : [ ] ,
} ) ;
} else {
let direntList = this . state . direntList . map ( item => {
item . isSelected = true ;
return item ;
} ) ;
this . setState ( {
isDirentSelected : true ,
isAllDirentSelected : true ,
direntList : direntList ,
selectedDirentList : direntList ,
} ) ;
}
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
onFileTagChanged = ( dirent , direntPath ) => {
let repoID = this . props . repoID ;
seafileAPI . listFileTags ( repoID , direntPath ) . then ( res => {
let fileTags = res . data . file _tags . map ( item => {
return new FileTag ( item ) ;
} ) ;
2023-06-07 12:41:12 +00:00
if ( this . state . isViewFile ) {
this . setState ( { fileTags : fileTags } ) ;
} else {
this . updateDirent ( dirent , 'file_tags' , fileTags ) ;
}
2019-07-16 02:01:09 +00:00
} ) . catch ( error => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
this . updateUsedRepoTags ( ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
onFileUploadSuccess = ( direntObject ) => {
2020-11-02 05:56:35 +00:00
let isExist = this . state . direntList . some ( item => {
2019-02-20 03:54:25 +00:00
return item . name === direntObject . name && item . type === direntObject . type ;
} ) ;
if ( isExist ) {
let direntList = this . state . direntList ;
for ( let i = 0 ; i < direntList . length ; i ++ ) {
let dirent = direntList [ i ] ;
if ( dirent . name === direntObject . name && dirent . type === direntObject . type ) {
let mtime = moment . unix ( direntObject . mtime ) . fromNow ( ) ;
this . updateDirent ( dirent , 'mtime' , mtime ) ; // todo file size is need update too, api is not return;
break ;
}
}
} else {
2021-09-13 02:37:07 +00:00
// use current dirent parent's permission as it's permission
direntObject . permission = this . state . userPerm ;
2019-02-20 03:54:25 +00:00
let dirent = new Dirent ( direntObject ) ;
if ( this . state . currentMode === 'column' ) {
this . addNodeToTree ( dirent . name , this . state . path , dirent . type ) ;
}
if ( direntObject . type === 'dir' ) {
this . setState ( { direntList : [ dirent , ... this . state . direntList ] } ) ;
} else {
this . setState ( { direntList : [ ... this . state . direntList , dirent ] } ) ;
}
}
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
2023-07-22 07:54:25 +00:00
addDirent = ( name , type , size , isSdocDraft ) => {
let item = this . createDirent ( name , type , size , isSdocDraft ) ;
2019-02-20 03:54:25 +00:00
let direntList = this . state . direntList ;
if ( type === 'dir' ) {
direntList . unshift ( item ) ;
} else {
// there will be there conditions;
// first: direntList.length === 0;
// second: all the direntList's items are dir;
// third: direntList has dir and file;
let length = direntList . length ;
if ( length === 0 || direntList [ length - 1 ] . type === 'dir' ) {
direntList . push ( item ) ;
} else {
let index = 0 ;
for ( let i = 0 ; i <= length ; i ++ ) {
if ( direntList [ i ] . type === 'file' ) {
index = i ;
break ;
}
}
direntList . splice ( index , 0 , item ) ;
}
}
this . setState ( { direntList : direntList } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
renameDirent = ( direntPath , newName ) => {
let repoID = this . props . repoID ;
let parentPath = Utils . getDirName ( direntPath ) ;
let newDirentPath = Utils . joinPath ( parentPath , newName ) ;
if ( direntPath === this . state . path ) {
// the renamed item is current viewed item
// example: direntPath = /A/B/C, state.path = /A/B/C
this . setState ( { path : newDirentPath } ) ;
2019-03-05 05:36:31 +00:00
let repoInfo = this . state . currentRepoInfo ;
let url = siteRoot + 'library/' + repoID + '/' + encodeURIComponent ( repoInfo . repo _name ) + newDirentPath ;
2019-02-20 03:54:25 +00:00
window . history . replaceState ( { url : url , path : newDirentPath } , newDirentPath , url ) ;
} else if ( Utils . isChildPath ( direntPath , this . state . path ) ) {
// example: direntPath = /A/B/C/D, state.path = /A/B/C
let oldName = Utils . getFileName ( direntPath ) ;
let direntList = this . state . direntList . map ( item => {
if ( item . name === oldName ) {
item . name = newName ;
}
return item ;
} ) ;
this . setState ( { direntList : direntList } ) ;
} else if ( Utils . isAncestorPath ( direntPath , this . state . path ) ) {
// example: direntPath = /A/B, state.path = /A/B/C
let newPath = Utils . renameAncestorPath ( this . state . path , direntPath , newDirentPath ) ;
this . setState ( { path : newPath } ) ;
2019-03-05 05:36:31 +00:00
let repoInfo = this . state . currentRepoInfo ;
let url = siteRoot + 'library/' + repoID + '/' + encodeURIComponent ( repoInfo . repo _name ) + newPath ;
2019-02-20 03:54:25 +00:00
window . history . replaceState ( { url : url , path : newPath } , newPath , url ) ;
}
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
deleteDirent ( direntPath ) {
if ( direntPath === this . state . path ) {
// The deleted item is current item
let parentPath = Utils . getDirName ( direntPath ) ;
this . showDir ( parentPath ) ;
} else if ( Utils . isChildPath ( direntPath , this . state . path ) ) {
// The deleted item is inside current path
let name = Utils . getFileName ( direntPath ) ;
let direntList = this . state . direntList . filter ( item => {
return item . name !== name ;
} ) ;
2019-12-25 02:16:09 +00:00
// Recalculate the state of the selection
this . recaculateSelectedStateAfterDirentDeleted ( name , direntList ) ;
this . setState ( { direntList : direntList } ) ;
2019-02-20 03:54:25 +00:00
} else if ( Utils . isAncestorPath ( direntPath , this . state . path ) ) {
// the deleted item is ancester of the current item
let parentPath = Utils . getDirName ( direntPath ) ;
this . showDir ( parentPath ) ;
}
// else do nothing
}
2020-04-02 07:45:33 +00:00
// only one scence: The deleted items are inside current path
deleteDirents = ( direntNames ) => {
let direntList = this . state . direntList . filter ( item => {
return direntNames . indexOf ( item . name ) === - 1 ;
} ) ;
// Recalculate the state of the selection
this . recaculateSelectedStateAfterDirentDeleted ( name , direntList ) ;
this . setState ( { direntList : direntList } ) ;
2023-09-13 00:40:50 +00:00
} ;
2020-04-02 07:45:33 +00:00
2019-05-07 02:06:24 +00:00
moveDirent = ( direntPath , moveToDirentPath = null ) => {
let name = Utils . getFileName ( direntPath ) ;
2019-05-05 09:20:37 +00:00
if ( moveToDirentPath === this . state . path ) {
2019-05-07 02:14:29 +00:00
this . loadDirentList ( this . state . path ) ;
2019-05-05 09:20:37 +00:00
return ;
}
2019-02-20 03:54:25 +00:00
let direntList = this . state . direntList . filter ( item => {
return item . name !== name ;
} ) ;
2019-12-25 02:16:09 +00:00
// Recalculate the state of the selection
this . recaculateSelectedStateAfterDirentDeleted ( name , direntList ) ;
2019-02-20 03:54:25 +00:00
this . setState ( { direntList : direntList } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
2020-04-02 07:45:33 +00:00
// only one scence: The moved items are inside current path
moveDirents = ( direntNames ) => {
let direntList = this . state . direntList . filter ( item => {
return direntNames . indexOf ( item . name ) === - 1 ;
} ) ;
// Recalculate the state of the selection
2023-09-20 00:07:51 +00:00
//this.recaculateSelectedStateAfterDirentDeleted(name, direntList);
2020-04-02 07:45:33 +00:00
2023-09-20 00:07:51 +00:00
this . setState ( {
direntList : direntList ,
selectedDirentList : [ ] ,
isDirentSelected : false ,
isAllDirentSelected : false ,
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2020-04-02 07:45:33 +00:00
2019-02-20 03:54:25 +00:00
updateDirent = ( dirent , paramKey , paramValue ) => {
let newDirentList = this . state . direntList . map ( item => {
if ( item . name === dirent . name ) {
item [ paramKey ] = paramValue ;
}
return item ;
} ) ;
this . setState ( { direntList : newDirentList } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
// tree operations
loadTreeNodeByPath = ( path ) => {
let repoID = this . props . repoID ;
let tree = this . state . treeData . clone ( ) ;
let node = tree . getNodeByPath ( path ) ;
if ( ! node . isLoaded ) {
seafileAPI . listDir ( repoID , node . path ) . then ( res => {
this . addResponseListToNode ( res . data . dirent _list , node ) ;
let parentNode = tree . getNodeByPath ( node . parentNode . path ) ;
parentNode . isExpanded = true ;
this . setState ( {
treeData : tree ,
currentNode : node
} ) ;
2019-07-16 02:01:09 +00:00
} ) . catch ( error => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
} else {
let parentNode = tree . getNodeByPath ( node . parentNode . path ) ;
parentNode . isExpanded = true ;
this . setState ( { treeData : tree , currentNode : node } ) ; //tree
}
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
loadNodeAndParentsByPath = ( path ) => {
let repoID = this . props . repoID ;
let tree = this . state . treeData . clone ( ) ;
if ( Utils . isMarkdownFile ( path ) ) {
path = Utils . getDirName ( path ) ;
}
seafileAPI . listDir ( repoID , path , { with _parents : true } ) . then ( res => {
2022-04-11 09:52:07 +00:00
const { dirent _list : direntList , user _perm } = res . data ;
2019-02-20 03:54:25 +00:00
let results = { } ;
for ( let i = 0 ; i < direntList . length ; i ++ ) {
let object = direntList [ i ] ;
2019-04-17 02:48:44 +00:00
let parentDir = object . parent _dir ;
let key = parentDir === '/' ? '/' : parentDir . slice ( 0 , parentDir . length - 1 ) ;
2019-02-20 03:54:25 +00:00
if ( ! results [ key ] ) {
results [ key ] = [ ] ;
}
results [ key ] . push ( object ) ;
}
for ( let key in results ) {
let node = tree . getNodeByPath ( key ) ;
if ( ! node . isLoaded ) {
this . addResponseListToNode ( results [ key ] , node ) ;
}
}
this . setState ( {
isTreeDataLoading : false ,
2022-04-11 09:52:07 +00:00
treeData : tree ,
userPerm : user _perm ,
2019-02-20 03:54:25 +00:00
} ) ;
} ) . catch ( ( ) => {
this . setState ( { isLoadFailed : true } ) ;
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
onTreeNodeClick = ( node ) => {
this . resetSelected ( ) ;
let repoID = this . props . repoID ;
if ( ! this . state . pathExist ) {
this . setState ( { pathExist : true } ) ;
}
if ( node . object . isDir ( ) ) {
2019-02-21 09:37:04 +00:00
let isLoaded = node . isLoaded ;
2019-02-20 03:54:25 +00:00
if ( ! node . isLoaded ) {
let tree = this . state . treeData . clone ( ) ;
node = tree . getNodeByPath ( node . path ) ;
seafileAPI . listDir ( repoID , node . path ) . then ( res => {
this . addResponseListToNode ( res . data . dirent _list , node ) ;
tree . collapseNode ( node ) ;
this . setState ( { treeData : tree } ) ;
2019-07-16 02:01:09 +00:00
} ) . catch ( error => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
}
2019-02-21 09:37:04 +00:00
if ( isLoaded && node . path === this . state . path ) {
2019-02-20 03:54:25 +00:00
if ( node . isExpanded ) {
let tree = treeHelper . collapseNode ( this . state . treeData , node ) ;
this . setState ( { treeData : tree } ) ;
} else {
let tree = this . state . treeData . clone ( ) ;
node = tree . getNodeByPath ( node . path ) ;
tree . expandNode ( node ) ;
this . setState ( { treeData : tree } ) ;
}
}
}
if ( node . path === this . state . path ) {
return ;
}
if ( node . object . isDir ( ) ) { // isDir
this . showDir ( node . path ) ;
} else {
if ( Utils . isMarkdownFile ( node . path ) ) {
if ( node . path !== this . state . path ) {
2019-05-14 08:58:59 +00:00
this . showColumnMarkdownFile ( node . path ) ;
2019-02-20 03:54:25 +00:00
}
} else {
2023-07-24 02:47:12 +00:00
let url = siteRoot + 'lib/' + repoID + '/file' + Utils . encodePath ( node . path ) ;
let dirent = node . object ;
if ( dirent . is _sdoc _revision && dirent . revision _id ) {
url = siteRoot + 'lib/' + repoID + '/revisions/' + dirent . revision _id + '/' ;
}
2020-12-10 03:30:16 +00:00
window . open ( url ) ;
2019-02-20 03:54:25 +00:00
}
}
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
2019-05-14 08:58:59 +00:00
showColumnMarkdownFile = ( filePath ) => {
let repoID = this . props . repoID ;
seafileAPI . getFileInfo ( repoID , filePath ) . then ( ( res ) => {
if ( res . data . size === 0 ) {
2020-12-10 03:30:16 +00:00
// loading of asynchronously obtained data may be blocked
2019-05-14 08:58:59 +00:00
const w = window . open ( 'about:blank' ) ;
const url = siteRoot + 'lib/' + repoID + '/file' + Utils . encodePath ( filePath ) ;
w . location . href = url ;
} else {
this . showFile ( filePath ) ;
}
2019-07-16 02:01:09 +00:00
} ) . catch ( error => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
2019-05-14 08:58:59 +00:00
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-05-14 08:58:59 +00:00
2019-02-20 03:54:25 +00:00
onTreeNodeCollapse = ( node ) => {
let tree = treeHelper . collapseNode ( this . state . treeData , node ) ;
this . setState ( { treeData : tree } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
onTreeNodeExpanded = ( node ) => {
let repoID = this . props . repoID ;
let tree = this . state . treeData . clone ( ) ;
node = tree . getNodeByPath ( node . path ) ;
if ( ! node . isLoaded ) {
seafileAPI . listDir ( repoID , node . path ) . then ( res => {
this . addResponseListToNode ( res . data . dirent _list , node ) ;
this . setState ( { treeData : tree } ) ;
2019-07-16 02:01:09 +00:00
} ) . catch ( error => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
2019-02-20 03:54:25 +00:00
} ) ;
} else {
tree . expandNode ( node ) ;
this . setState ( { treeData : tree } ) ;
}
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
addNodeToTree = ( name , parentPath , type ) => {
let node = this . createTreeNode ( name , type ) ;
let tree = treeHelper . addNodeToParentByPath ( this . state . treeData , node , parentPath ) ;
this . setState ( { treeData : tree } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
renameTreeNode = ( path , newName ) => {
let tree = treeHelper . renameNodeByPath ( this . state . treeData , path , newName ) ;
this . setState ( { treeData : tree } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
deleteTreeNode = ( path ) => {
let tree = treeHelper . deleteNodeByPath ( this . state . treeData , path ) ;
this . setState ( { treeData : tree } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
2020-04-02 07:45:33 +00:00
deleteTreeNodes = ( paths ) => {
let tree = treeHelper . deleteNodeListByPaths ( this . state . treeData , paths ) ;
this . setState ( { treeData : tree } ) ;
2023-09-13 00:40:50 +00:00
} ;
2020-04-02 07:45:33 +00:00
2019-02-20 03:54:25 +00:00
moveTreeNode = ( nodePath , moveToPath , moveToRepo , nodeName ) => {
let repoID = this . props . repoID ;
if ( repoID !== moveToRepo . repo _id ) {
let tree = treeHelper . deleteNodeByPath ( this . state . treeData , nodePath ) ;
this . setState ( { treeData : tree } ) ;
return ;
}
let tree = treeHelper . moveNodeByPath ( this . state . treeData , nodePath , moveToPath , nodeName ) ;
this . setState ( { treeData : tree } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
copyTreeNode = ( nodePath , copyToPath , destRepo , nodeName ) => {
let repoID = this . props . repoID ;
if ( repoID !== destRepo . repo _id ) {
return ;
}
let tree = treeHelper . copyNodeByPath ( this . state . treeData , nodePath , copyToPath , nodeName ) ;
this . setState ( { treeData : tree } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
createTreeNode ( name , type ) {
let object = this . createDirent ( name , type ) ;
return new TreeNode ( { object } ) ;
}
2023-07-22 07:54:25 +00:00
createDirent ( name , type , size , isSdocDraft ) {
2021-09-13 02:37:07 +00:00
// use current dirent parent's permission as it's permission
const { userPerm : permission } = this . state ;
2023-07-22 07:54:25 +00:00
const mtime = new Date ( ) . getTime ( ) / 1000 ;
const obj = { name , type , mtime , size , permission } ;
if ( isSdocDraft ) {
obj . is _sdoc _draft = isSdocDraft ;
}
const dirent = new Dirent ( obj ) ;
2019-02-20 03:54:25 +00:00
return dirent ;
}
addResponseListToNode = ( list , node ) => {
node . isLoaded = true ;
node . isExpanded = true ;
let direntList = list . map ( item => {
return new Dirent ( item ) ;
} ) ;
direntList = Utils . sortDirents ( direntList , 'name' , 'asc' ) ;
let nodeList = direntList . map ( object => {
return new TreeNode ( { object } ) ;
} ) ;
node . addChildren ( nodeList ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
getSelectedDirentPaths = ( ) => {
let paths = [ ] ;
this . state . selectedDirentList . forEach ( selectedDirent => {
paths . push ( Utils . joinPath ( this . state . path , selectedDirent . name ) ) ;
} ) ;
return paths ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
getSelectedDirentNames = ( ) => {
let names = [ ] ;
this . state . selectedDirentList . forEach ( selectedDirent => {
names . push ( selectedDirent . name ) ;
} ) ;
return names ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
resetSelected = ( ) => {
this . setState ( {
isDirentSelected : false ,
isAllDirentSelected : false ,
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
2019-12-25 02:16:09 +00:00
recaculateSelectedStateAfterDirentDeleted = ( name , newDirentList ) => {
let selectedDirentList = this . state . selectedDirentList . slice ( 0 ) ;
if ( selectedDirentList . length > 0 ) {
selectedDirentList = selectedDirentList . filter ( item => {
return item . name !== name ;
} ) ;
}
2020-11-02 05:56:35 +00:00
this . setState ( {
2019-12-25 02:16:09 +00:00
selectedDirentList : selectedDirentList ,
isDirentSelected : selectedDirentList . length > 0 ,
isAllDirentSelected : selectedDirentList . length === newDirentList . length ,
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-12-25 02:16:09 +00:00
2019-02-20 03:54:25 +00:00
onLibDecryptDialog = ( ) => {
this . setState ( { libNeedDecrypt : false } ) ;
this . loadDirData ( this . state . path ) ;
2023-09-13 00:40:50 +00:00
} ;
2020-11-02 05:56:35 +00:00
2019-02-20 03:54:25 +00:00
goDraftPage = ( ) => {
2019-04-26 09:08:16 +00:00
window . open ( siteRoot + 'drafts/' + this . state . draftID + '/' ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
sortItems = ( sortBy , sortOrder ) => {
2019-04-12 06:30:08 +00:00
cookie . save ( 'seafile-repo-dir-sort-by' , sortBy ) ;
cookie . save ( 'seafile-repo-dir-sort-order' , sortOrder ) ;
2019-02-20 03:54:25 +00:00
this . setState ( {
sortBy : sortBy ,
sortOrder : sortOrder ,
items : Utils . sortDirents ( this . state . direntList , sortBy , sortOrder )
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-20 03:54:25 +00:00
2019-02-21 09:37:04 +00:00
onUploadFile = ( e ) => {
e . nativeEvent . stopImmediatePropagation ( ) ;
this . uploader . onFileUpload ( ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-21 09:37:04 +00:00
onUploadFolder = ( e ) => {
e . nativeEvent . stopImmediatePropagation ( ) ;
this . uploader . onFolderUpload ( ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-02-21 09:37:04 +00:00
2019-03-15 02:10:24 +00:00
onToolbarFileTagChanged = ( ) => {
let repoID = this . props . repoID ;
let filePath = this . state . path ;
seafileAPI . listFileTags ( repoID , filePath ) . then ( res => {
let fileTags = res . data . file _tags . map ( item => {
return new FileTag ( item ) ;
} ) ;
this . setState ( { fileTags : fileTags } ) ;
2019-07-16 02:01:09 +00:00
} ) . catch ( error => {
let errMessage = Utils . getErrorMsg ( error ) ;
toaster . danger ( errMessage ) ;
2019-03-15 02:10:24 +00:00
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-03-15 02:10:24 +00:00
2019-03-18 09:32:49 +00:00
unSelectDirent = ( ) => {
this . setState ( {
isDirentSelected : false ,
selectedDirentList : [ ]
} ) ;
const dirent = { } ;
this . onDirentSelected ( dirent ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-03-18 09:32:49 +00:00
2019-03-25 07:23:37 +00:00
onDeleteRepoTag = ( deletedTagID ) => {
let direntList = this . state . direntList . map ( dirent => {
if ( dirent . file _tags ) {
let fileTags = dirent . file _tags . filter ( item => {
return item . repo _tag _id !== deletedTagID ;
} ) ;
dirent . file _tags = fileTags ;
}
return dirent ;
} ) ;
this . setState ( { direntList : direntList } ) ;
this . updateUsedRepoTags ( ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-03-25 07:23:37 +00:00
2022-08-17 03:20:19 +00:00
handleSubmit = ( e ) => {
let options = {
'share_type' : 'personal' ,
'from' : this . state . currentRepoInfo . owner _email
} ;
seafileAPI . leaveShareRepo ( this . props . repoID , options ) . then ( res => {
navigate ( siteRoot + 'shared-libs/' ) ;
} ) . catch ( ( error ) => {
let errorMsg = Utils . getErrorMsg ( error , true ) ;
toaster . danger ( errorMsg ) ;
} ) ;
e . preventDefault ( ) ;
2023-09-13 00:40:50 +00:00
} ;
2022-08-17 03:20:19 +00:00
2019-02-20 03:54:25 +00:00
render ( ) {
if ( this . state . libNeedDecrypt ) {
return (
< ModalPortal >
2020-11-02 05:56:35 +00:00
< LibDecryptDialog
2019-02-20 03:54:25 +00:00
repoID = { this . props . repoID }
onLibDecryptDialog = { this . onLibDecryptDialog }
/ >
< / M o d a l P o r t a l >
) ;
}
2022-08-17 03:20:19 +00:00
if ( this . state . errorMsg ) {
return (
< Fragment >
< p className = "error mt-6 text-center" > { this . state . errorMsg } < / p >
< button type = "submit" className = "btn btn-primary submit" onClick = { this . handleSubmit } > { gettext ( 'Leave Share' ) } < / b u t t o n >
< / F r a g m e n t >
2022-11-28 01:27:17 +00:00
) ;
2022-08-17 03:20:19 +00:00
}
2019-02-21 09:37:04 +00:00
if ( ! this . state . currentRepoInfo ) {
return '' ;
}
2019-02-20 03:54:25 +00:00
let enableDirPrivateShare = false ;
2023-12-11 10:19:23 +00:00
let { currentRepoInfo , userPerm , isCopyMoveProgressDialogShow , isDeleteFolderDialogOpen } = this . state ;
2019-06-21 09:54:06 +00:00
let showShareBtn = Utils . isHasPermissionToShare ( currentRepoInfo , userPerm ) ;
2019-02-27 05:53:36 +00:00
let isRepoOwner = currentRepoInfo . owner _email === username ;
2019-06-27 03:48:41 +00:00
let isVirtual = currentRepoInfo . is _virtual ;
let isAdmin = currentRepoInfo . is _admin ;
if ( ! isVirtual && ( isRepoOwner || isAdmin ) ) {
enableDirPrivateShare = true ;
}
2019-04-24 05:52:09 +00:00
let direntItemsList = this . state . direntList . filter ( ( item , index ) => {
return index < this . state . itemsShowLength ;
2019-05-14 02:15:09 +00:00
} ) ;
2019-04-24 05:52:09 +00:00
2021-09-13 02:37:07 +00:00
let canUpload = true ;
const { isCustomPermission , customPermission } = Utils . getUserPermission ( userPerm ) ;
if ( isCustomPermission ) {
const { upload } = customPermission . permission ;
canUpload = upload ;
}
2019-02-20 03:54:25 +00:00
return (
2020-02-29 09:02:11 +00:00
< Fragment >
2022-11-28 01:27:17 +00:00
< div className = "main-panel-north border-left-show" >
< LibContentToolbar
isViewFile = { this . state . isViewFile }
filePermission = { this . state . filePermission }
isDraft = { this . state . isDraft }
hasDraft = { this . state . hasDraft }
fileTags = { this . state . fileTags }
onFileTagChanged = { this . onToolbarFileTagChanged }
onSideNavMenuClick = { this . props . onMenuClick }
repoID = { this . props . repoID }
path = { this . state . path }
isDirentSelected = { this . state . isDirentSelected }
selectedDirentList = { this . state . selectedDirentList }
onItemsMove = { this . onMoveItems }
onItemsCopy = { this . onCopyItems }
onItemsDelete = { this . onDeleteItems }
onItemRename = { this . onMainPanelItemRename }
direntList = { this . state . direntList }
repoName = { this . state . repoName }
repoEncrypted = { this . state . repoEncrypted }
isGroupOwnedRepo = { this . state . isGroupOwnedRepo }
userPerm = { this . state . userPerm }
showShareBtn = { showShareBtn }
enableDirPrivateShare = { enableDirPrivateShare }
onAddFile = { this . onAddFile }
onAddFolder = { this . onAddFolder }
onUploadFile = { this . onUploadFile }
onUploadFolder = { this . onUploadFolder }
currentMode = { this . state . currentMode }
switchViewMode = { this . switchViewMode }
onSearchedClick = { this . onSearchedClick }
isRepoOwner = { isRepoOwner }
currentRepoInfo = { this . state . currentRepoInfo }
updateDirent = { this . updateDirent }
onDirentSelected = { this . onDirentSelected }
showDirentDetail = { this . showDirentDetail }
unSelectDirent = { this . unSelectDirent }
onFilesTagChanged = { this . onFileTagChanged }
/ >
< / d i v >
< div className = "main-panel-center flex-row" >
< LibContentContainer
pathPrefix = { this . props . pathPrefix }
currentMode = { this . state . currentMode }
path = { this . state . path }
pathExist = { this . state . pathExist }
currentRepoInfo = { this . state . currentRepoInfo }
repoID = { this . props . repoID }
enableDirPrivateShare = { enableDirPrivateShare }
userPerm = { userPerm }
isGroupOwnedRepo = { this . state . isGroupOwnedRepo }
onTabNavClick = { this . props . onTabNavClick }
onMainNavBarClick = { this . onMainNavBarClick }
isViewFile = { this . state . isViewFile }
hash = { this . state . hash }
isDraft = { this . state . isDraft }
hasDraft = { this . state . hasDraft }
fileTags = { this . state . fileTags }
goDraftPage = { this . goDraftPage }
isFileLoading = { this . state . isFileLoading }
isFileLoadedErr = { this . state . isFileLoadedErr }
filePermission = { this . state . filePermission }
content = { this . state . content }
lastModified = { this . state . lastModified }
latestContributor = { this . state . latestContributor }
onLinkClick = { this . onLinkClick }
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 }
draftCounts = { this . state . draftCounts }
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 }
updateDirent = { this . updateDirent }
onDirentClick = { this . onDirentClick }
onItemClick = { this . onItemClick }
onItemSelected = { this . onDirentSelected }
onItemDelete = { this . onMainPanelItemDelete }
onItemRename = { this . onMainPanelItemRename }
onItemMove = { this . onMoveItem }
onItemCopy = { this . onCopyItem }
2023-09-14 06:36:58 +00:00
onItemConvert = { this . onConvertItem }
2022-11-28 01:27:17 +00:00
onAddFolder = { this . onAddFolder }
onAddFile = { this . onAddFile }
onFileTagChanged = { this . onFileTagChanged }
isDirentSelected = { this . state . isDirentSelected }
isAllDirentSelected = { this . state . isAllDirentSelected }
onAllDirentSelected = { this . onAllDirentSelected }
isDirentDetailShow = { this . state . isDirentDetailShow }
selectedDirent = { this . state . selectedDirentList && this . state . selectedDirentList [ 0 ] }
selectedDirentList = { this . state . selectedDirentList }
onItemsMove = { this . onMoveItems }
onItemsCopy = { this . onCopyItems }
onItemsDelete = { this . onDeleteItems }
closeDirentDetail = { this . closeDirentDetail }
showDirentDetail = { this . showDirentDetail }
direntDetailPanelTab = { this . state . direntDetailPanelTab }
onDeleteRepoTag = { this . onDeleteRepoTag }
onToolbarFileTagChanged = { this . onToolbarFileTagChanged }
updateDetail = { this . state . updateDetail }
onListContainerScroll = { this . onListContainerScroll }
loadDirentList = { this . loadDirentList }
/ >
{ canUpload && this . state . pathExist && ! this . state . isViewFile && (
< FileUploader
ref = { uploader => this . uploader = uploader }
dragAndDrop = { true }
2020-02-29 09:02:11 +00:00
path = { this . state . path }
repoID = { this . props . repoID }
2022-11-28 01:27:17 +00:00
direntList = { this . state . direntList }
onFileUploadSuccess = { this . onFileUploadSuccess }
isCustomPermission = { isCustomPermission }
2020-02-29 09:02:11 +00:00
/ >
2022-11-28 01:27:17 +00:00
) }
< / d i v >
2020-03-31 05:45:36 +00:00
{ isCopyMoveProgressDialogShow && (
2020-02-29 09:02:11 +00:00
< CopyMoveDirentProgressDialog
type = { this . state . asyncOperationType }
2020-03-02 08:44:39 +00:00
asyncOperatedFilesLength = { this . state . asyncOperatedFilesLength }
2020-02-29 09:02:11 +00:00
asyncOperationProgress = { this . state . asyncOperationProgress }
toggleDialog = { this . onMoveProgressDialogToggle }
/ >
) }
2022-11-28 01:27:17 +00:00
{ isDeleteFolderDialogOpen && (
< DeleteFolderDialog
repoID = { this . props . repoID }
path = { this . state . folderToDelete }
deleteFolder = { this . deleteFolder }
toggleDialog = { this . toggleDeleteFolderDialog }
/ >
) }
2020-02-29 09:02:11 +00:00
< / F r a g m e n t >
2019-02-20 03:54:25 +00:00
) ;
}
}
LibContentView . propTypes = propTypes ;
2019-02-21 09:37:04 +00:00
export default LibContentView ;