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