172 lines
4.4 KiB
TypeScript
172 lines
4.4 KiB
TypeScript
import React from "react"
|
|
import { useState } from "react"
|
|
import { useContextMenu } from "react-contexify"
|
|
import { RouteComponentProps } from "react-router-dom"
|
|
import downloadFile from "../functions/downloadFile"
|
|
import genDownloadLink from "../functions/genDownloadLink"
|
|
import normalizeDirPath from "../functions/normalizeDirPath"
|
|
import uploadFile from "../functions/uploadFile"
|
|
import { useCopyMutation, useCreateDirMutation, useDeleteDirMutation, useDeleteFileMutation, useMoveMutation, useOpenDirQuery } from "../generated/graphql"
|
|
import Breadcrum from "./Breadcrum"
|
|
import CreateDirButton from "./CreateDirButton"
|
|
import DragAndDrop from "./DragAndDrop"
|
|
import FileBrowserContextMenu, { Action, CONTEXT_MENU_DIR, CONTEXT_MENU_FILE } from "./FileBrowserContextMenu"
|
|
import FileOpen from "./FileOpen"
|
|
import FileUploadButton from "./FileUploadButton"
|
|
import { ReactComponent as Spinner } from "./../assets/spinner.svg"
|
|
import FileBrowserList from "./FileBrowserList"
|
|
|
|
function uriToPath(pathname:string) {
|
|
// strip the "/f" from e.g. "/f/dir1/dir2"
|
|
return pathname.substr(2)
|
|
}
|
|
|
|
function pathToUri(path:string) {
|
|
return (path.startsWith("/")?"/f":"/f/") + path
|
|
}
|
|
|
|
const FileBrowser: React.FC<RouteComponentProps> = (props) => {
|
|
const path = uriToPath(props.location.pathname)
|
|
|
|
const [openFileId, setOpenFileId] = useState("")
|
|
const [showFile, setShowFile] = useState(false)
|
|
|
|
const [srcID,setSrcID] = useState("")
|
|
const [pasteAction,setPasteAction] = useState<Action>()
|
|
|
|
const [deleteMutation] = useDeleteFileMutation()
|
|
const [copyMutation] = useCopyMutation()
|
|
const [moveMutation] = useMoveMutation()
|
|
const [createDirMutation] = useCreateDirMutation()
|
|
const [deleteDirMutation] = useDeleteDirMutation()
|
|
|
|
const { show: showFileContext } = useContextMenu({
|
|
id: CONTEXT_MENU_FILE,
|
|
})
|
|
|
|
const { show: showDirContext } = useContextMenu({
|
|
id: CONTEXT_MENU_DIR,
|
|
})
|
|
|
|
const { data, loading, refetch: refetchDir } = useOpenDirQuery({
|
|
variables:{
|
|
path
|
|
}
|
|
})
|
|
|
|
async function handleDrop(files:FileList) {
|
|
const wait: Promise<boolean>[] = []
|
|
for (let i = 0; i < files.length; i++) {
|
|
const file = files[i]
|
|
wait.push(uploadFile(file, path + file.name))
|
|
}
|
|
|
|
await Promise.all(wait)
|
|
refetchDir()
|
|
}
|
|
|
|
async function onContextSelect(action:Action, id: string) {
|
|
switch (action) {
|
|
case Action.FileDelete:
|
|
await deleteMutation({variables:{id}})
|
|
refetchDir()
|
|
break
|
|
case Action.FileCopy:
|
|
case Action.FileMove:
|
|
setSrcID(id)
|
|
setPasteAction(action)
|
|
break
|
|
case Action.FilePaste:
|
|
if (pasteAction === Action.FileCopy){
|
|
await copyMutation({variables:{src:srcID,dest:path}})
|
|
refetchDir()
|
|
}
|
|
|
|
if (pasteAction === Action.FileMove){
|
|
await moveMutation({variables:{src:srcID,dest:path}})
|
|
refetchDir()
|
|
}
|
|
break
|
|
case Action.DirDelete:
|
|
await deleteDirMutation({variables:{path:id}})
|
|
refetchDir()
|
|
break
|
|
case Action.FileDownload:
|
|
downloadFile(genDownloadLink(id))
|
|
break
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="dark:text-gray-300">
|
|
<FileBrowserContextMenu
|
|
onSelect={onContextSelect}
|
|
pasteActive={!!srcID}
|
|
/>
|
|
<DragAndDrop
|
|
handleDrop={async (files)=>{
|
|
await handleDrop(files)
|
|
}}
|
|
>
|
|
<div className="flex justify-between">
|
|
<Breadcrum path={path} onDirClick={(newPath)=>{
|
|
props.history.push(pathToUri(newPath))
|
|
}}/>
|
|
<div className="ml-auto">
|
|
<CreateDirButton
|
|
onPressed={async (dirName)=>{
|
|
const fullPath = normalizeDirPath(path + dirName)
|
|
await createDirMutation({variables:{path: fullPath}})
|
|
refetchDir()
|
|
}}
|
|
/>
|
|
</div>
|
|
<div>
|
|
<FileUploadButton
|
|
onUpload={(files)=>handleDrop(files)}
|
|
/>
|
|
</div>
|
|
|
|
</div>
|
|
<div>
|
|
<FileBrowserList
|
|
directorys={data?.directorys || []}
|
|
files={data?.files || []}
|
|
|
|
onDirClick={(e,path)=>{
|
|
props.history.push(pathToUri(path))
|
|
}}
|
|
|
|
onDirContext={(e,path)=>{
|
|
e.preventDefault()
|
|
showDirContext(e,{props:{id:path}})
|
|
}}
|
|
|
|
onFileClick={(e,id)=>{
|
|
setOpenFileId(id)
|
|
setShowFile(true)
|
|
}}
|
|
|
|
onFileContext={(e,id)=>{
|
|
e.preventDefault()
|
|
showFileContext(e,{props:{id}})
|
|
}}
|
|
/>
|
|
{loading &&
|
|
<div className="flex justify-center mt-4">
|
|
<Spinner />
|
|
</div>
|
|
}
|
|
</div>
|
|
<FileOpen id={openFileId} show={showFile} onCloseClick={()=>{
|
|
setShowFile(false)
|
|
}} />
|
|
</DragAndDrop>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default FileBrowser
|