Skip to content

Commit

Permalink
feat: empty folder clear, recursive move, regular rename (#78)
Browse files Browse the repository at this point in the history
* 页面增加递归移动和正则重命名按钮

* 正则重命名操作样式变更

* 增加清理空文件夹按钮

* 正则重命名文件添加提示语

* 技术债

* chore: change ui

* fix codefactor

---------

Co-authored-by: Andy Hsu <[email protected]>
  • Loading branch information
varg1714 and xhofe authored Apr 14, 2023
1 parent 46224cb commit 0992b7b
Show file tree
Hide file tree
Showing 10 changed files with 326 additions and 1 deletion.
125 changes: 125 additions & 0 deletions src/components/ModalTwoInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import {
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalBody,
ModalFooter,
Button,
Input,
Textarea,
FormHelperText,
VStack,
} from "@hope-ui/solid"
import { createSignal, JSXElement, Show } from "solid-js"
import { useT } from "~/hooks"
import { notify } from "~/utils"
export type ModalTwoInputProps = {
opened: boolean
onClose: () => void
title: string
onSubmit?: (text1: string, text2: string) => void // Update onSubmit to accept two input texts
type?: string
defaultValue1?: string // Update defaultValue to defaultValue1
defaultValue2?: string // Add defaultValue2 for second input
loading?: boolean
tips?: string
topSlot?: JSXElement
}
export const ModalTwoInput = (props: ModalTwoInputProps) => {
const [value1, setValue1] = createSignal(props.defaultValue1 ?? "") // Update value and setValue to value1 and setValue1
const [value2, setValue2] = createSignal(props.defaultValue2 ?? "") // Add value2 and setValue2 for second input
const t = useT()
const submit = () => {
if (!value1() || !value2()) {
// Check if both input values are not empty
notify.warning(t("global.empty_input"))
return
}
props.onSubmit?.(value1(), value2()) // Update onSubmit to pass both input values
setValue1("")
setValue2("")
}
return (
<Modal
blockScrollOnMount={false}
opened={props.opened}
onClose={props.onClose}
initialFocus="#modal-input1"
>
<ModalOverlay />
<ModalContent>
{/* <ModalCloseButton /> */}
<ModalHeader>{t(props.title)}</ModalHeader>
<ModalBody>
<Show when={props.topSlot}>{props.topSlot}</Show>
<Show
when={props.type === "text"}
fallback={
<VStack spacing="$2">
<Input
id="modal-input1" // Update id to "modal-input1" for first input
type={props.type}
value={value1()} // Update value to value1 for first input
onInput={(e) => {
setValue1(e.currentTarget.value)
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
submit()
}
}}
/>
<Input
id="modal-input2" // Add second input with id "modal-input2"
type={props.type}
value={value2()} // Bind value to value2 for second input
onInput={(e) => {
setValue2(e.currentTarget.value)
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
submit()
}
}}
/>
</VStack>
}
>
<div>
<Textarea
id="modal-input1" // Update id to "modal-input1" for first input
value={value1()} // Update value to value1 for first input
onInput={(e) => {
setValue1(e.currentTarget.value)
}}
/>
<Textarea
id="modal-input2" // Add second input with id "modal-input2"
value={value2()} // Bind value to value2 for second input
onInput={(e) => {
setValue2(e.currentTarget.value)
}}
/>
</div>
</Show>
<Show when={props.tips}>
<FormHelperText>{props.tips}</FormHelperText>
</Show>
</ModalBody>
<ModalFooter display="flex" gap="$2">
<Button onClick={props.onClose} colorScheme="neutral">
{t("global.cancel")}
</Button>
<Button
loading={props.loading}
onClick={() => submit()}
disabled={!value1() || !value2()}
>
{t("global.ok")}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
)
}
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ export * from "./LinkWithBase"
export * from "./ImageWithError"
export * from "./Markdown"
export * from "./ModalInput"
export * from "./ModalTwoInput"
export * from "./Base"
export * from "./Paginator"
7 changes: 6 additions & 1 deletion src/lang/en/home.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,12 @@
"pre_package_download-tips": "Using streamsaver in the browser instead of the server for package download requires the corresponding storage to support cors, and the unsupported storage will fail.",
"package_download-tips": "Downloading, please wait don't close the page",
"upload": "Upload",
"local_settings": "Local Settings"
"local_settings": "Local Settings",
"recursive_move": "Recursive Move",
"remove_empty_directory": "Remove Empty Folder",
"remove_empty_directory-tips": "Are you sure to delete all its empty subfolders?",
"regex_rename": "Regex Rename",
"regular_rename": "Regular expression file renaming. Input the source file name regular expression on the first line, and input the new file name regular expression on the second line."
},
"upload": {
"add_as_task": "Add as task",
Expand Down
35 changes: 35 additions & 0 deletions src/pages/home/toolbar/RecursiveMove.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { createDisclosure } from "@hope-ui/solid"
import { ModalFolderChoose } from "~/components"
import { useFetch, usePath, useRouter } from "~/hooks"
import { bus, fsRecursiveMove, handleRespWithNotifySuccess } from "~/utils"
import { onCleanup } from "solid-js"

export const RecursiveMove = () => {
const { isOpen, onOpen, onClose } = createDisclosure()
const [loading, ok] = useFetch(fsRecursiveMove)
const { pathname } = useRouter()
const { refresh } = usePath()
const handler = (name: string) => {
if (name === "recursiveMove") {
onOpen()
}
}
bus.on("tool", handler)
onCleanup(() => {
bus.off("tool", handler)
})
return (
<ModalFolderChoose
opened={isOpen()}
onClose={onClose}
loading={loading()}
onSubmit={async (dst) => {
const resp = await ok(pathname(), dst)
handleRespWithNotifySuccess(resp, () => {
refresh()
onClose()
})
}}
/>
)
}
36 changes: 36 additions & 0 deletions src/pages/home/toolbar/RegexRename.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { createDisclosure } from "@hope-ui/solid"
import { ModalTwoInput } from "~/components"
import { useFetch, usePath, useRouter } from "~/hooks"
import { bus, fsRegexRename, handleRespWithNotifySuccess } from "~/utils"
import { onCleanup } from "solid-js"

export const RegexRename = () => {
const { isOpen, onOpen, onClose } = createDisclosure()
const [loading, ok] = useFetch(fsRegexRename)
const { pathname } = useRouter()
const { refresh } = usePath()
const handler = (name: string) => {
if (name === "regexRename") {
onOpen()
}
}
bus.on("tool", handler)
onCleanup(() => {
bus.off("tool", handler)
})
return (
<ModalTwoInput
title="home.toolbar.regular_rename"
opened={isOpen()}
onClose={onClose}
loading={loading()}
onSubmit={async (srcName, newName) => {
const resp = await ok(pathname(), srcName, newName)
handleRespWithNotifySuccess(resp, () => {
refresh()
onClose()
})
}}
/>
)
}
71 changes: 71 additions & 0 deletions src/pages/home/toolbar/RemoveEmptyDirectory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {
Button,
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
createDisclosure,
} from "@hope-ui/solid"
import { useFetch, usePath, useRouter, useT } from "~/hooks"
import {
bus,
fsRemoveEmptyDirectory,
handleRespWithNotifySuccess,
} from "~/utils"
import { onCleanup } from "solid-js"

export const RemoveEmptyDirectory = () => {
const { isOpen, onOpen, onClose } = createDisclosure()
const { pathname } = useRouter()
const [loading, ok] = useFetch(fsRemoveEmptyDirectory)
const { refresh } = usePath()
const handler = (name: string) => {
if (name === "removeEmptyDirectory") {
onOpen()
}
}
bus.on("tool", handler)
onCleanup(() => {
bus.off("tool", handler)
})
const t = useT()
return (
<Modal
blockScrollOnMount={false}
opened={isOpen()}
onClose={onClose}
size={{
"@initial": "xs",
"@md": "md",
}}
>
<ModalOverlay />
<ModalContent>
<ModalHeader>{t("home.toolbar.remove_empty_directory")}</ModalHeader>
<ModalBody>
<p>{t("home.toolbar.remove_empty_directory-tips")}</p>
</ModalBody>
<ModalFooter display="flex" gap="$2">
<Button onClick={onClose} colorScheme="neutral">
{t("global.cancel")}
</Button>
<Button
colorScheme="danger"
loading={loading()}
onClick={async () => {
const resp = await ok(pathname())
handleRespWithNotifySuccess(resp, () => {
refresh()
onClose()
})
}}
>
{t("global.confirm")}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
)
}
21 changes: 21 additions & 0 deletions src/pages/home/toolbar/Right.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,27 @@ export const Right = () => {
bus.emit("tool", "mkdir")
}}
/>
<RightIcon
as={operations.recursive_move.icon}
tips="recursive_move"
onClick={() => {
bus.emit("tool", "recursiveMove")
}}
/>
<RightIcon
as={operations.remove_empty_directory.icon}
tips="remove_empty_directory"
onClick={() => {
bus.emit("tool", "removeEmptyDirectory")
}}
/>
<RightIcon
as={operations.regex_rename.icon}
tips="regex_rename"
onClick={() => {
bus.emit("tool", "regexRename")
}}
/>
<RightIcon
as={AiOutlineCloudUpload}
tips="upload"
Expand Down
6 changes: 6 additions & 0 deletions src/pages/home/toolbar/Toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { Delete } from "./Delete"
import { Rename } from "./Rename"
import { NewFile } from "./NewFile"
import { Mkdir } from "./Mkdir"
import { RecursiveMove } from "./RecursiveMove"
import { RemoveEmptyDirectory } from "./RemoveEmptyDirectory"
import { RegexRename } from "./RegexRename"
import { OfflineDownload } from "./OfflineDownload"
import { PackageDownloadModal } from "./Download"
import { lazy } from "solid-js"
Expand All @@ -22,6 +25,9 @@ export const Modal = () => {
<Delete />
<NewFile />
<Mkdir />
<RecursiveMove />
<RemoveEmptyDirectory />
<RegexRename />
<OfflineDownload />
<PackageDownloadModal />
<ModalWrapper name="upload" title="home.toolbar.upload">
Expand Down
6 changes: 6 additions & 0 deletions src/pages/home/toolbar/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { TbCopy, TbLink } from "solid-icons/tb"
import { AiTwotoneDelete } from "solid-icons/ai"
import { CgFileAdd, CgFolderAdd } from "solid-icons/cg"
import { AiOutlineCloudDownload } from "solid-icons/ai"
import { ImMoveUp } from "solid-icons/im"
import { BiRegularRename } from "solid-icons/bi"
import { HiOutlineFolderRemove } from "solid-icons/hi"

interface Operations {
[key: string]: {
Expand All @@ -21,6 +24,9 @@ export const operations: Operations = {
delete: { icon: AiTwotoneDelete, color: "$danger9" },
copy_link: { icon: TbLink, color: "$info9" },
mkdir: { icon: CgFolderAdd, p: true },
recursive_move: { icon: ImMoveUp, p: true },
remove_empty_directory: { icon: HiOutlineFolderRemove, p: true },
regex_rename: { icon: BiRegularRename, p: true },
new_file: { icon: CgFileAdd, p: true },
cancel_select: { icon: TiDeleteOutline },
download: { icon: AiOutlineCloudDownload, color: "$primary9" },
Expand Down
19 changes: 19 additions & 0 deletions src/utils/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ export const fsRename = (path: string, name: string): PEmptyResp => {
return r.post("/fs/rename", { path, name })
}

export const fsRegexRename = (
src_dir: string,
src_name_regex: string,
new_name_regex: string
): PEmptyResp => {
return r.post("/fs/regex_rename", { src_dir, src_name_regex, new_name_regex })
}

export const fsMove = (
src_dir: string,
dst_dir: string,
Expand All @@ -65,6 +73,13 @@ export const fsMove = (
return r.post("/fs/move", { src_dir, dst_dir, names })
}

export const fsRecursiveMove = (
src_dir: string,
dst_dir: string
): PEmptyResp => {
return r.post("/fs/recursive_move", { src_dir, dst_dir })
}

export const fsCopy = (
src_dir: string,
dst_dir: string,
Expand All @@ -77,6 +92,10 @@ export const fsRemove = (dir: string, names: string[]): PEmptyResp => {
return r.post("/fs/remove", { dir, names })
}

export const fsRemoveEmptyDirectory = (src_dir: string): PEmptyResp => {
return r.post("/fs/remove_empty_directory", { src_dir })
}

export const fsNewFile = (path: string, password: string): PEmptyResp => {
return r.put("/fs/put", undefined, {
headers: {
Expand Down

0 comments on commit 0992b7b

Please sign in to comment.