the big refactor 2: ObjID
This commit is contained in:
parent
dc4133a705
commit
3e8fbb01bb
@ -10,7 +10,10 @@ generates:
|
||||
- "typescript"
|
||||
- "typescript-operations"
|
||||
- "typescript-react-apollo"
|
||||
- add:
|
||||
content: "import ObjID from './../types/ObjID'"
|
||||
config:
|
||||
withHooks: true
|
||||
scalars:
|
||||
DateTime: string
|
||||
objID: ObjID
|
@ -41,6 +41,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@craco/craco": "^6.2.0",
|
||||
"@graphql-codegen/add": "^3.1.0",
|
||||
"@graphql-codegen/cli": "1.21.7",
|
||||
"@graphql-codegen/introspection": "1.18.2",
|
||||
"@graphql-codegen/typescript": "^1.23.0",
|
||||
|
@ -1,25 +1,36 @@
|
||||
import React from "react"
|
||||
import ObjID from "../types/ObjID"
|
||||
import { ReactComponent as BreadcrumImage } from "./../assets/breadcrum.svg"
|
||||
|
||||
interface Props{
|
||||
path: string
|
||||
onDirClick?: (path: string) => void
|
||||
path: ObjID
|
||||
onDirClick?: (path: ObjID) => void
|
||||
}
|
||||
|
||||
const Breadcrum: React.FC<Props> = (props) => {
|
||||
const parts = props.path.split("/").filter(e=>e.length > 0)
|
||||
const keyParts = props.path.key.split("/").filter(e=>e.length > 0)
|
||||
|
||||
return (
|
||||
<ul className="flex text-gray-500 dark:text-gray-400 text-lg">
|
||||
<li className="inline-flex items-center cursor-pointer">
|
||||
<a onClick={()=>{
|
||||
props.onDirClick?.("/")
|
||||
}}>
|
||||
Root
|
||||
<ul className="flex text-gray-500 dark:text-gray-400 text-lg ">
|
||||
<div className="inline-flex items-center cursor-pointer">
|
||||
<li>
|
||||
<a>
|
||||
{props.path.bucket}
|
||||
</a>
|
||||
</li>
|
||||
</div>
|
||||
<div className="inline-flex items-center cursor-pointer">
|
||||
<BreadcrumImage className="h-5 w-auto text-gray-400" />
|
||||
<li>
|
||||
<a onClick={()=>{
|
||||
props.onDirClick?.(new ObjID(props.path.bucket,"/"))
|
||||
}}>
|
||||
root
|
||||
</a>
|
||||
</li>
|
||||
</div>
|
||||
|
||||
{parts.map((e,i,arr)=>{
|
||||
{keyParts.map((e,i,arr)=>{
|
||||
const last = i == arr.length - 1
|
||||
return <div key={e} className="inline-flex items-center cursor-pointer">
|
||||
<BreadcrumImage className="h-5 w-auto text-gray-400" />
|
||||
@ -28,7 +39,7 @@ const Breadcrum: React.FC<Props> = (props) => {
|
||||
className={`${last?"text-blue-500":""}`}
|
||||
onClick={()=>{
|
||||
if (!last){
|
||||
props.onDirClick?.("/"+arr.slice(0,i-1).join("/"))
|
||||
props.onDirClick?.(new ObjID(props.path.bucket,"/"+arr.slice(0,i-1).join("/")))
|
||||
}
|
||||
}}>{e}</a>
|
||||
</li>
|
||||
|
@ -4,7 +4,6 @@ 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"
|
||||
@ -15,31 +14,17 @@ import FileOpen from "./FileOpen"
|
||||
import FileUploadButton from "./FileUploadButton"
|
||||
import { ReactComponent as Spinner } from "./../assets/spinner.svg"
|
||||
import FileBrowserList from "./FileBrowserList"
|
||||
import pathRename from "../functions/pathRename"
|
||||
import MoreMenu from "./MoreMenu"
|
||||
|
||||
function uriToPath(pathname:string) {
|
||||
// strip the "/f" from e.g. "/f/dir1/dir2"
|
||||
const path = pathname.substr(2)
|
||||
if (!path.endsWith("/")){
|
||||
return path + "/"
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
function pathToUri(path:string) {
|
||||
return (path.startsWith("/")?"/f":"/f/") + path
|
||||
}
|
||||
import ObjID from "../types/ObjID"
|
||||
|
||||
const FileBrowser: React.FC<RouteComponentProps> = (props) => {
|
||||
const path = uriToPath(props.location.pathname)
|
||||
|
||||
const [openFileId, setOpenFileId] = useState("")
|
||||
const path = ObjID.fromURI(props.location.pathname)
|
||||
const [openFileId, setOpenFileId] = useState<ObjID>()
|
||||
const [showFile, setShowFile] = useState(false)
|
||||
|
||||
const [srcID,setSrcID] = useState("")
|
||||
const [srcID,setSrcID] = useState<ObjID>(path)
|
||||
const [pasteAction,setPasteAction] = useState<Action>()
|
||||
const [editID,setEditID] = useState("")
|
||||
const [editID,setEditID] = useState<ObjID>(path)
|
||||
const [editEnable,setEditEnable] = useState(false)
|
||||
|
||||
const [deleteMutation] = useDeleteFileMutation()
|
||||
@ -58,7 +43,7 @@ const FileBrowser: React.FC<RouteComponentProps> = (props) => {
|
||||
|
||||
const { data, loading, refetch: refetchDir } = useOpenDirQuery({
|
||||
variables:{
|
||||
path
|
||||
path: path
|
||||
}
|
||||
})
|
||||
|
||||
@ -66,14 +51,14 @@ const FileBrowser: React.FC<RouteComponentProps> = (props) => {
|
||||
const wait: Promise<boolean>[] = []
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i]
|
||||
wait.push(uploadFile(file, path + file.name))
|
||||
wait.push(uploadFile(file, new ObjID(path.bucket,path.key + file.name)))
|
||||
}
|
||||
|
||||
await Promise.all(wait)
|
||||
refetchDir()
|
||||
}
|
||||
|
||||
async function onContextSelect(action:Action, id: string) {
|
||||
async function onContextSelect(action:Action, id: ObjID) {
|
||||
switch (action) {
|
||||
case Action.FileDelete:
|
||||
await deleteMutation({variables:{id}})
|
||||
@ -124,13 +109,13 @@ const FileBrowser: React.FC<RouteComponentProps> = (props) => {
|
||||
>
|
||||
<div className="flex justify-between">
|
||||
<Breadcrum path={path} onDirClick={(newPath)=>{
|
||||
props.history.push(pathToUri(newPath))
|
||||
props.history.push(newPath.toURI())
|
||||
}}/>
|
||||
<div className="ml-auto">
|
||||
<CreateDirButton
|
||||
onPressed={async (dirName)=>{
|
||||
const fullPath = normalizeDirPath(path + dirName)
|
||||
await createDirMutation({variables:{path: fullPath}})
|
||||
const dirID = new ObjID(path.bucket,path.key + dirName)
|
||||
await createDirMutation({variables:{path: dirID}})
|
||||
refetchDir()
|
||||
}}
|
||||
/>
|
||||
@ -147,11 +132,11 @@ const FileBrowser: React.FC<RouteComponentProps> = (props) => {
|
||||
</div>
|
||||
<div>
|
||||
<FileBrowserList
|
||||
directorys={data?.directorys || []}
|
||||
directorys={data?.directories || []}
|
||||
files={data?.files || []}
|
||||
|
||||
onDirClick={(e,path)=>{
|
||||
props.history.push(pathToUri(path))
|
||||
props.history.push(path.toURI())
|
||||
}}
|
||||
|
||||
onDirContext={(e,path)=>{
|
||||
@ -179,7 +164,7 @@ const FileBrowser: React.FC<RouteComponentProps> = (props) => {
|
||||
// TODO: input check & error handling
|
||||
await moveMutation({variables:{
|
||||
src:id,
|
||||
dest: pathRename(id,newName)
|
||||
dest: id.rename(newName)
|
||||
}})
|
||||
refetchDir()
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from "react"
|
||||
import { Item, ItemParams, Menu, Separator } from "react-contexify"
|
||||
|
||||
import ObjID from "../types/ObjID"
|
||||
|
||||
export const CONTEXT_MENU_FILE = "CONTEXT_MENU_FILE"
|
||||
export const CONTEXT_MENU_DIR = "CONTEXT_MENU_DIR"
|
||||
@ -16,12 +16,12 @@ export enum Action {
|
||||
}
|
||||
|
||||
interface Props {
|
||||
onSelect?: (action: Action, id: string)=>void
|
||||
onSelect?: (action: Action, id: ObjID)=>void
|
||||
pasteActive?: boolean
|
||||
}
|
||||
|
||||
const FileBrowserContextMenu: React.FC<Props> = (props) => {
|
||||
function onClick({ props: itemProps, data }: ItemParams<{id:string}, Action>) {
|
||||
function onClick({ props: itemProps, data }: ItemParams<{id:ObjID}, Action>) {
|
||||
if (itemProps?.id && data != null){
|
||||
props.onSelect?.(data,itemProps.id)
|
||||
}
|
||||
|
@ -1,19 +1,20 @@
|
||||
import React from "react"
|
||||
import { Directory, File } from "../generated/graphql"
|
||||
import ObjID from "../types/ObjID"
|
||||
import FileBrowserElement from "./FileBrowserElement"
|
||||
|
||||
interface Props{
|
||||
directorys: Directory[]
|
||||
files: File[]
|
||||
|
||||
onFileContext?: (event: React.MouseEvent, id: string)=>void
|
||||
onDirContext?: (event: React.MouseEvent, path: string)=>void
|
||||
onFileClick?: (event: React.MouseEvent,id: string)=>void
|
||||
onDirClick?: (event: React.MouseEvent,path: string)=>void
|
||||
onFileContext?: (event: React.MouseEvent, id: ObjID)=>void
|
||||
onDirContext?: (event: React.MouseEvent, path: ObjID)=>void
|
||||
onFileClick?: (event: React.MouseEvent,id: ObjID)=>void
|
||||
onDirClick?: (event: React.MouseEvent,path: ObjID)=>void
|
||||
|
||||
editId: string
|
||||
editId?: ObjID
|
||||
editEnable: boolean
|
||||
onRenameDone?: (id: string, changed: boolean, newName: string)=>void
|
||||
onRenameDone?: (id: ObjID, changed: boolean, newName: string)=>void
|
||||
}
|
||||
|
||||
const FileBrowserList: React.FC<Props> = (props) => {
|
||||
@ -28,7 +29,7 @@ const FileBrowserList: React.FC<Props> = (props) => {
|
||||
</thead>
|
||||
<tbody className="divide-y dark:divide-gray-900">
|
||||
{ props.directorys.map(v => (<FileBrowserElement
|
||||
key={v.id}
|
||||
key={v.id.toString()}
|
||||
dir={v}
|
||||
onClick={(e,dir)=>{
|
||||
props.onDirClick?.(e,dir.id)
|
||||
@ -51,7 +52,7 @@ const FileBrowserList: React.FC<Props> = (props) => {
|
||||
/>))}
|
||||
|
||||
{ props.files.map(v => (<FileBrowserElement
|
||||
key={v.id}
|
||||
key={v.id.toString()}
|
||||
file={v}
|
||||
onClick={(e,file)=>{
|
||||
props.onFileClick?.(e,file.id)
|
||||
|
@ -4,9 +4,10 @@ import ImageOpener from "./ImageOpener"
|
||||
import TextOpener from "./TextOpener"
|
||||
import Modal from "./Modal"
|
||||
import AudioOpener from "./AudioOpener"
|
||||
import ObjID from "../types/ObjID"
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
id?: ObjID
|
||||
show: boolean
|
||||
onCloseClick?: ()=>void
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
function genDownloadLink(id:string): string {
|
||||
return `/api/file?id=${encodeURIComponent(id)}`
|
||||
import ObjID from "../types/ObjID"
|
||||
|
||||
function genDownloadLink(id:ObjID): string {
|
||||
return `/api/file?id=${encodeURIComponent(id.toString())}`
|
||||
}
|
||||
|
||||
export default genDownloadLink
|
||||
|
@ -1,11 +0,0 @@
|
||||
function pathRename(id:string, newFilename: string): string {
|
||||
const isDir = id.endsWith("/")
|
||||
const parts = id.split("/")
|
||||
if (!parts.length)
|
||||
throw new Error("Maleformed id")
|
||||
parts[parts.length - (isDir?2:1)] = newFilename
|
||||
|
||||
return parts.join("/")
|
||||
}
|
||||
|
||||
export default pathRename
|
@ -1,5 +1,7 @@
|
||||
async function uploadFile(file:File,id: string): Promise<boolean> {
|
||||
const res = await fetch(`/api/file?${new URLSearchParams({id:id}).toString()}`,{
|
||||
import ObjID from "../types/ObjID"
|
||||
|
||||
async function uploadFile(file:File,id: ObjID): Promise<boolean> {
|
||||
const res = await fetch(`/api/file?${new URLSearchParams({id:id.toString()}).toString()}`,{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": file.type
|
||||
|
@ -1,3 +1,4 @@
|
||||
import ObjID from "./../types/ObjID"
|
||||
import { gql } from "@apollo/client"
|
||||
import * as Apollo from "@apollo/client"
|
||||
export type Maybe<T> = T | null;
|
||||
@ -14,6 +15,11 @@ export type Scalars = {
|
||||
Float: number;
|
||||
/** DateTime is a DateTime in ISO 8601 format */
|
||||
DateTime: string;
|
||||
/**
|
||||
* String representing a bucket, key and version combination.
|
||||
* Looks like this: "bucketName:/name/of/key" or "bucketName@version:/name/of/key"
|
||||
*/
|
||||
objID: ObjID;
|
||||
};
|
||||
|
||||
|
||||
@ -22,7 +28,7 @@ export type Directory = {
|
||||
__typename?: "Directory";
|
||||
directorys?: Maybe<Array<Maybe<Directory>>>;
|
||||
files?: Maybe<Array<Maybe<File>>>;
|
||||
id: Scalars["ID"];
|
||||
id: Scalars["objID"];
|
||||
name?: Maybe<Scalars["String"]>;
|
||||
parent?: Maybe<Directory>;
|
||||
};
|
||||
@ -33,7 +39,7 @@ export type File = {
|
||||
contentType?: Maybe<Scalars["String"]>;
|
||||
etag?: Maybe<Scalars["String"]>;
|
||||
/** The uniqe ID of the file. Represents the path and the s3 key. */
|
||||
id: Scalars["ID"];
|
||||
id: Scalars["objID"];
|
||||
lastModified?: Maybe<Scalars["DateTime"]>;
|
||||
name?: Maybe<Scalars["String"]>;
|
||||
parent?: Maybe<Directory>;
|
||||
@ -61,64 +67,65 @@ export type RootMutation = {
|
||||
|
||||
|
||||
export type RootMutationCopyArgs = {
|
||||
src: Scalars["ID"];
|
||||
dest: Scalars["ID"];
|
||||
src: Scalars["objID"];
|
||||
dest: Scalars["objID"];
|
||||
};
|
||||
|
||||
|
||||
export type RootMutationCreateDirArgs = {
|
||||
path: Scalars["ID"];
|
||||
path: Scalars["objID"];
|
||||
};
|
||||
|
||||
|
||||
export type RootMutationDeleteArgs = {
|
||||
id: Scalars["ID"];
|
||||
id: Scalars["objID"];
|
||||
};
|
||||
|
||||
|
||||
export type RootMutationDeleteDirArgs = {
|
||||
path: Scalars["ID"];
|
||||
path: Scalars["objID"];
|
||||
};
|
||||
|
||||
|
||||
export type RootMutationLoginArgs = {
|
||||
password: Scalars["String"];
|
||||
username: Scalars["String"];
|
||||
password: Scalars["String"];
|
||||
};
|
||||
|
||||
|
||||
export type RootMutationMoveArgs = {
|
||||
src: Scalars["ID"];
|
||||
dest: Scalars["ID"];
|
||||
src: Scalars["objID"];
|
||||
dest: Scalars["objID"];
|
||||
};
|
||||
|
||||
export type RootQuery = {
|
||||
__typename?: "RootQuery";
|
||||
/** True if the user is authorized */
|
||||
authorized: Scalars["Boolean"];
|
||||
directorys: Array<Directory>;
|
||||
directories: Array<Directory>;
|
||||
file?: Maybe<File>;
|
||||
files: Array<File>;
|
||||
};
|
||||
|
||||
|
||||
export type RootQueryDirectorysArgs = {
|
||||
path: Scalars["String"];
|
||||
export type RootQueryDirectoriesArgs = {
|
||||
path: Scalars["objID"];
|
||||
};
|
||||
|
||||
|
||||
export type RootQueryFileArgs = {
|
||||
id: Scalars["ID"];
|
||||
id: Scalars["objID"];
|
||||
};
|
||||
|
||||
|
||||
export type RootQueryFilesArgs = {
|
||||
path: Scalars["String"];
|
||||
path: Scalars["objID"];
|
||||
};
|
||||
|
||||
|
||||
export type CopyMutationVariables = Exact<{
|
||||
src: Scalars["ID"];
|
||||
dest: Scalars["ID"];
|
||||
src: Scalars["objID"];
|
||||
dest: Scalars["objID"];
|
||||
}>;
|
||||
|
||||
|
||||
@ -131,7 +138,7 @@ export type CopyMutation = (
|
||||
);
|
||||
|
||||
export type CreateDirMutationVariables = Exact<{
|
||||
path: Scalars["ID"];
|
||||
path: Scalars["objID"];
|
||||
}>;
|
||||
|
||||
|
||||
@ -144,7 +151,7 @@ export type CreateDirMutation = (
|
||||
);
|
||||
|
||||
export type DeleteDirMutationVariables = Exact<{
|
||||
path: Scalars["ID"];
|
||||
path: Scalars["objID"];
|
||||
}>;
|
||||
|
||||
|
||||
@ -154,7 +161,7 @@ export type DeleteDirMutation = (
|
||||
);
|
||||
|
||||
export type DeleteFileMutationVariables = Exact<{
|
||||
id: Scalars["ID"];
|
||||
id: Scalars["objID"];
|
||||
}>;
|
||||
|
||||
|
||||
@ -164,7 +171,7 @@ export type DeleteFileMutation = (
|
||||
);
|
||||
|
||||
export type GetFileQueryVariables = Exact<{
|
||||
id: Scalars["ID"];
|
||||
id: Scalars["objID"];
|
||||
}>;
|
||||
|
||||
|
||||
@ -199,8 +206,8 @@ export type LoginMutation = (
|
||||
);
|
||||
|
||||
export type MoveMutationVariables = Exact<{
|
||||
src: Scalars["ID"];
|
||||
dest: Scalars["ID"];
|
||||
src: Scalars["objID"];
|
||||
dest: Scalars["objID"];
|
||||
}>;
|
||||
|
||||
|
||||
@ -213,7 +220,7 @@ export type MoveMutation = (
|
||||
);
|
||||
|
||||
export type OpenDirQueryVariables = Exact<{
|
||||
path: Scalars["String"];
|
||||
path: Scalars["objID"];
|
||||
}>;
|
||||
|
||||
|
||||
@ -222,7 +229,7 @@ export type OpenDirQuery = (
|
||||
& { files: Array<(
|
||||
{ __typename?: "File" }
|
||||
& Pick<File, "id" | "name" | "size" | "lastModified">
|
||||
)>, directorys: Array<(
|
||||
)>, directories: Array<(
|
||||
{ __typename?: "Directory" }
|
||||
& Pick<Directory, "id" | "name">
|
||||
)> }
|
||||
@ -230,7 +237,7 @@ export type OpenDirQuery = (
|
||||
|
||||
|
||||
export const CopyDocument = gql`
|
||||
mutation copy($src: ID!, $dest: ID!) {
|
||||
mutation copy($src: objID!, $dest: objID!) {
|
||||
copy(src: $src, dest: $dest) {
|
||||
id
|
||||
}
|
||||
@ -264,7 +271,7 @@ export type CopyMutationHookResult = ReturnType<typeof useCopyMutation>;
|
||||
export type CopyMutationResult = Apollo.MutationResult<CopyMutation>;
|
||||
export type CopyMutationOptions = Apollo.BaseMutationOptions<CopyMutation, CopyMutationVariables>;
|
||||
export const CreateDirDocument = gql`
|
||||
mutation createDir($path: ID!) {
|
||||
mutation createDir($path: objID!) {
|
||||
createDir(path: $path) {
|
||||
id
|
||||
}
|
||||
@ -297,7 +304,7 @@ export type CreateDirMutationHookResult = ReturnType<typeof useCreateDirMutation
|
||||
export type CreateDirMutationResult = Apollo.MutationResult<CreateDirMutation>;
|
||||
export type CreateDirMutationOptions = Apollo.BaseMutationOptions<CreateDirMutation, CreateDirMutationVariables>;
|
||||
export const DeleteDirDocument = gql`
|
||||
mutation deleteDir($path: ID!) {
|
||||
mutation deleteDir($path: objID!) {
|
||||
deleteDir(path: $path)
|
||||
}
|
||||
`
|
||||
@ -328,7 +335,7 @@ export type DeleteDirMutationHookResult = ReturnType<typeof useDeleteDirMutation
|
||||
export type DeleteDirMutationResult = Apollo.MutationResult<DeleteDirMutation>;
|
||||
export type DeleteDirMutationOptions = Apollo.BaseMutationOptions<DeleteDirMutation, DeleteDirMutationVariables>;
|
||||
export const DeleteFileDocument = gql`
|
||||
mutation deleteFile($id: ID!) {
|
||||
mutation deleteFile($id: objID!) {
|
||||
delete(id: $id)
|
||||
}
|
||||
`
|
||||
@ -359,7 +366,7 @@ export type DeleteFileMutationHookResult = ReturnType<typeof useDeleteFileMutati
|
||||
export type DeleteFileMutationResult = Apollo.MutationResult<DeleteFileMutation>;
|
||||
export type DeleteFileMutationOptions = Apollo.BaseMutationOptions<DeleteFileMutation, DeleteFileMutationVariables>;
|
||||
export const GetFileDocument = gql`
|
||||
query getFile($id: ID!) {
|
||||
query getFile($id: objID!) {
|
||||
file(id: $id) {
|
||||
id
|
||||
name
|
||||
@ -465,7 +472,7 @@ export type LoginMutationHookResult = ReturnType<typeof useLoginMutation>;
|
||||
export type LoginMutationResult = Apollo.MutationResult<LoginMutation>;
|
||||
export type LoginMutationOptions = Apollo.BaseMutationOptions<LoginMutation, LoginMutationVariables>;
|
||||
export const MoveDocument = gql`
|
||||
mutation move($src: ID!, $dest: ID!) {
|
||||
mutation move($src: objID!, $dest: objID!) {
|
||||
move(src: $src, dest: $dest) {
|
||||
id
|
||||
}
|
||||
@ -499,14 +506,14 @@ export type MoveMutationHookResult = ReturnType<typeof useMoveMutation>;
|
||||
export type MoveMutationResult = Apollo.MutationResult<MoveMutation>;
|
||||
export type MoveMutationOptions = Apollo.BaseMutationOptions<MoveMutation, MoveMutationVariables>;
|
||||
export const OpenDirDocument = gql`
|
||||
query openDir($path: String!) {
|
||||
query openDir($path: objID!) {
|
||||
files(path: $path) {
|
||||
id
|
||||
name
|
||||
size
|
||||
lastModified
|
||||
}
|
||||
directorys(path: $path) {
|
||||
directories(path: $path) {
|
||||
id
|
||||
name
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
mutation copy($src: ID!, $dest: ID!) {
|
||||
mutation copy($src: objID!, $dest: objID!) {
|
||||
copy(src: $src,dest: $dest){
|
||||
id
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
mutation createDir($path: ID!){
|
||||
mutation createDir($path: objID!){
|
||||
createDir(path:$path){
|
||||
id
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
mutation deleteDir($path: ID!){
|
||||
mutation deleteDir($path: objID!){
|
||||
deleteDir(path:$path)
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
mutation deleteFile($id: ID!) {
|
||||
mutation deleteFile($id: objID!) {
|
||||
delete(id:$id)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
query getFile($id: ID!){
|
||||
query getFile($id: objID!){
|
||||
file(id: $id){
|
||||
id
|
||||
name
|
||||
|
@ -1,4 +1,4 @@
|
||||
mutation move($src: ID!, $dest: ID!) {
|
||||
mutation move($src: objID!, $dest: objID!) {
|
||||
move(src: $src,dest: $dest){
|
||||
id
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
query openDir($path: String!) {
|
||||
query openDir($path: objID!) {
|
||||
files(path:$path){
|
||||
id
|
||||
name
|
||||
size
|
||||
lastModified
|
||||
}
|
||||
directorys(path: $path){
|
||||
directories(path: $path){
|
||||
id
|
||||
name
|
||||
}
|
||||
|
@ -4,11 +4,44 @@ import "./index.scss"
|
||||
import App from "./App"
|
||||
import { ApolloClient, ApolloProvider, InMemoryCache } from "@apollo/client"
|
||||
import "react-contexify/dist/ReactContexify.css"
|
||||
import ObjID from "./types/ObjID"
|
||||
|
||||
const client = new ApolloClient({
|
||||
uri: "/api/graphql",
|
||||
cache: new InMemoryCache({
|
||||
typePolicies:{
|
||||
File:{
|
||||
fields:{
|
||||
id:{
|
||||
merge(_,incomming){
|
||||
// HACK: i use the merge function to change the id from a string to ObjID object.
|
||||
// afaik apollo does not yet support custom scalar types.
|
||||
if (!incomming){
|
||||
return incomming
|
||||
}else if (incomming instanceof ObjID){
|
||||
return incomming
|
||||
}else{
|
||||
return ObjID.fromString(incomming as string)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Directory:{
|
||||
fields:{
|
||||
id:{
|
||||
merge(_,incomming){
|
||||
if (!incomming){
|
||||
return incomming
|
||||
}else if (incomming instanceof ObjID){
|
||||
return incomming
|
||||
}else{
|
||||
return ObjID.fromString(incomming as string)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Query: {
|
||||
fields: {
|
||||
files: {
|
||||
|
82
src/types/ObjID.ts
Normal file
82
src/types/ObjID.ts
Normal file
@ -0,0 +1,82 @@
|
||||
const stringRegex = /(.*?)(@(.*))?:(.*)/
|
||||
|
||||
class ObjID {
|
||||
public bucket: string
|
||||
public key: string
|
||||
public version?: string
|
||||
|
||||
constructor(bucket: string, key: string, version?: string) {
|
||||
this.bucket = bucket
|
||||
if(!key){
|
||||
this.key = "/"
|
||||
}else{
|
||||
this.key = key
|
||||
}
|
||||
if (version){
|
||||
this.version = version
|
||||
}
|
||||
|
||||
this.normalize()
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
if (this.version) {
|
||||
return `${this.bucket}@${this.version}:${this.key}`
|
||||
}else{
|
||||
return `${this.bucket}:${this.key}`
|
||||
}
|
||||
}
|
||||
|
||||
public normalize(): void{
|
||||
if (!this.key.startsWith("/")){
|
||||
this.key = "/" + this.key
|
||||
}
|
||||
}
|
||||
|
||||
public isDirectory(): boolean {
|
||||
return this.key.endsWith("/")
|
||||
}
|
||||
|
||||
public toURI(): string {
|
||||
return `/f/${this.bucket}${this.key}`
|
||||
}
|
||||
|
||||
public toJSON(): string{
|
||||
// HACK: toJSON is required so that apollo can parse the ObjID back to a string
|
||||
// that can be used in gql query
|
||||
return this.toString()
|
||||
}
|
||||
|
||||
public rename(name: string): ObjID{
|
||||
const parts = this.key.split("/")
|
||||
parts[parts.length - (this.isDirectory()?2:1)] = name
|
||||
return new ObjID(this.bucket,parts.join("/"))
|
||||
}
|
||||
|
||||
public static fromString(from: string): ObjID{
|
||||
const match = stringRegex.exec(from)
|
||||
|
||||
if (!match){
|
||||
throw new Error("Failed to parse ObjID")
|
||||
}
|
||||
|
||||
return new ObjID(match[1],match[4],match[3])
|
||||
}
|
||||
|
||||
public static fromURI(uri: string): ObjID{
|
||||
let uri2 = uri
|
||||
|
||||
if (!uri2.endsWith("/")){
|
||||
uri2 += "/"
|
||||
}
|
||||
|
||||
const parts = uri2.split("/")
|
||||
|
||||
const bucket = parts[2]
|
||||
const key = parts.slice(3).join("/")
|
||||
|
||||
return new ObjID(bucket,key)
|
||||
}
|
||||
}
|
||||
|
||||
export default ObjID
|
27
yarn.lock
27
yarn.lock
@ -1392,6 +1392,14 @@
|
||||
minimatch "^3.0.4"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@graphql-codegen/add@^3.1.0":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@graphql-codegen/add/-/add-3.1.0.tgz#cd02fd6d80a7f62839cb27160b62e48366a237c5"
|
||||
integrity sha512-vRRHpuUFadYXnPrb5RNiIzm3Ao39UxjvrdX760lEfXh2qeG7YddM5QFC+ev2BH3X452R15gv/gf/rXy0+Hqm1A==
|
||||
dependencies:
|
||||
"@graphql-codegen/plugin-helpers" "^2.1.0"
|
||||
tslib "~2.3.0"
|
||||
|
||||
"@graphql-codegen/cli@1.21.7":
|
||||
version "1.21.7"
|
||||
resolved "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-1.21.7.tgz"
|
||||
@ -1466,6 +1474,18 @@
|
||||
lodash "~4.17.0"
|
||||
tslib "~2.3.0"
|
||||
|
||||
"@graphql-codegen/plugin-helpers@^2.1.0":
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-2.1.1.tgz#fc13e735763574ef308045bbb95c3e7201ec0027"
|
||||
integrity sha512-7jjN9fekMQkpd7cRTbaBxgqt/hkR3CXeOUSsEyHFDDHKtvCrnev3iyc75IeWXpO9tOwDE8mVPTzEZnu4QukrNA==
|
||||
dependencies:
|
||||
"@graphql-tools/utils" "^8.1.1"
|
||||
change-case-all "1.0.14"
|
||||
common-tags "1.8.0"
|
||||
import-from "4.0.0"
|
||||
lodash "~4.17.0"
|
||||
tslib "~2.3.0"
|
||||
|
||||
"@graphql-codegen/typescript-operations@1.18.4":
|
||||
version "1.18.4"
|
||||
resolved "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-1.18.4.tgz"
|
||||
@ -1720,6 +1740,13 @@
|
||||
camel-case "4.1.2"
|
||||
tslib "~2.2.0"
|
||||
|
||||
"@graphql-tools/utils@^8.1.1":
|
||||
version "8.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.2.3.tgz#9d7b9e7e116d11d26c2687f4d9cfb2b54568838b"
|
||||
integrity sha512-RR+aiusf2gIfnPmrDIH1uA45QuPiHB54RD+BmWyMcl88tWAjeJtqZeWPqUTq/1EXrNeocJAJQqogHV4Fbbzx3A==
|
||||
dependencies:
|
||||
tslib "~2.3.0"
|
||||
|
||||
"@graphql-tools/wrap@^7.0.4":
|
||||
version "7.0.8"
|
||||
resolved "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-7.0.8.tgz"
|
||||
|
Loading…
Reference in New Issue
Block a user