Skip to content

Commit

Permalink
feat: search index manage
Browse files Browse the repository at this point in the history
  • Loading branch information
xhofe committed Nov 28, 2022
1 parent 4c95a71 commit aa0db01
Show file tree
Hide file tree
Showing 13 changed files with 405 additions and 90 deletions.
9 changes: 9 additions & 0 deletions src/lang/en/indexes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"search_index": "Search index",
"current": "Current indexes",
"build": "Build indexes",
"rebuild": "Rebuild indexes",
"obj_count": "Object count",
"last_done_time": "Last done time",
"error": "Error"
}
3 changes: 2 additions & 1 deletion src/lang/en/manage.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"upload": "Upload",
"copy": "Copy",
"backup-restore": "Backup & Restore",
"home": "Home"
"home": "Home",
"indexes": "Indexes"
},
"title": "AList Manage",
"not_admin": "You are not admin user, please login with admin account.",
Expand Down
51 changes: 33 additions & 18 deletions src/pages/home/folder/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,22 @@ import {
VStack,
} from "@hope-ui/solid"
import { BsSearch } from "solid-icons/bs"
import { createSignal, For, onCleanup, Show } from "solid-js"
import { LinkWithBase } from "~/components"
import { createSignal, For, Match, onCleanup, Show, Switch } from "solid-js"
import { FullLoading, LinkWithBase } from "~/components"
import { useFetch, useRouter, useT } from "~/hooks"
import { getMainColor, me } from "~/store"
import { Obj } from "~/types"
import { bus, fsSearch, getFileSize, handleResp, hoverColor } from "~/utils"
import { SearchNode } from "~/types"
import {
bus,
fsSearch,
getFileSize,
handleResp,
hoverColor,
pathJoin,
} from "~/utils"
import { getIconByObj } from "~/utils/icon"

const SearchResult = (props: Obj) => {
const SearchResult = (props: SearchNode) => {
return (
<HStack
w="$full"
Expand Down Expand Up @@ -51,20 +58,20 @@ const SearchResult = (props: Obj) => {
}}
>
{props.name}
<Show when={!props.is_dir}>
<Show when={props.size > 0 || !props.is_dir}>
<Badge colorScheme="info" ml="$2">
{getFileSize(props.size)}
</Badge>
</Show>
</Text>
<Text
color="$neutral9"
color="$neutral10"
size="xs"
css={{
wordBreak: "break-all",
}}
>
{props.path}
{props.parent}
</Text>
</VStack>
</HStack>
Expand Down Expand Up @@ -94,17 +101,20 @@ const Search = () => {
const [keywords, setKeywords] = createSignal("")
const { pathname } = useRouter()
const [loading, searchReq] = useFetch(fsSearch)
const [data, setData] = createSignal<Obj[]>([])
const [data, setData] = createSignal<SearchNode[]>([])
const search = async () => {
if (loading()) return
setData([])
const resp = await searchReq(pathname(), keywords())
handleResp(resp, (data) => {
if (!data) {
const content = data.content
if (!content) {
return
}
data.forEach((obj) => {
obj.path = obj.path.replace(me().base_path, "")
content.forEach((node) => {
node.path = pathJoin(node.parent, node.name).replace(me().base_path, "")
})
setData(data)
setData(content)
})
}
return (
Expand Down Expand Up @@ -147,11 +157,16 @@ const Search = () => {
loading={loading()}
/>
</HStack>
<Show when={data().length === 0}>
<Text size="2xl" my="$8">
{t("home.search.no_result")}
</Text>
</Show>
<Switch>
<Match when={loading()}>
<FullLoading />
</Match>
<Match when={data().length === 0}>
<Text size="2xl" my="$8">
{t("home.search.no_result")}
</Text>
</Match>
</Switch>
<VStack w="$full">
<For each={data()}>{(item) => <SearchResult {...item} />}</For>
</VStack>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/manage/backup-restore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ const BackupRestore = () => {
onClick={() => {
backup()
}}
colorScheme="accent"
>
{t("br.backup")}
</Button>
Expand All @@ -239,7 +240,6 @@ const BackupRestore = () => {
onClick={() => {
restore()
}}
colorScheme="accent"
>
{t("br.restore")}
</Button>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/manage/common/ResponsiveGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const ResponsiveGrid = (props: { children: JSXElement }) => {
gap="$2"
templateColumns={{
"@initial": "1fr",
"@lg": "repeat(auto-fit, minmax(424px, 1fr))",
"@lg": "repeat(auto-fill, minmax(424px, 1fr))",
}}
>
{props.children}
Expand Down
100 changes: 100 additions & 0 deletions src/pages/manage/indexes/icons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { JSX } from "solid-js"

export function LineMdLoadingTwotoneLoop(
props: JSX.SvgSVGAttributes<SVGSVGElement>
) {
return (
<svg width="1em" height="1em" viewBox="0 0 24 24" {...props}>
<g
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-width="2"
>
<path
stroke-dasharray="60"
stroke-dashoffset="60"
stroke-opacity=".3"
d="M12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3Z"
>
<animate
fill="freeze"
attributeName="stroke-dashoffset"
dur="1.3s"
values="60;0"
></animate>
</path>
<path
stroke-dasharray="15"
stroke-dashoffset="15"
d="M12 3C16.9706 3 21 7.02944 21 12"
>
<animate
fill="freeze"
attributeName="stroke-dashoffset"
dur="0.3s"
values="15;0"
></animate>
<animateTransform
attributeName="transform"
dur="1.5s"
repeatCount="indefinite"
type="rotate"
values="0 12 12;360 12 12"
></animateTransform>
</path>
</g>
</svg>
)
}

export function LineMdConfirmCircleTwotone(
props: JSX.SvgSVGAttributes<SVGSVGElement>
) {
return (
<svg width="1em" height="1em" viewBox="0 0 24 24" {...props}>
<g
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
>
<path
fill="currentColor"
fill-opacity="0"
stroke-dasharray="60"
stroke-dashoffset="60"
d="M3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12Z"
>
<animate
fill="freeze"
attributeName="stroke-dashoffset"
dur="0.5s"
values="60;0"
></animate>
<animate
fill="freeze"
attributeName="fill-opacity"
begin="0.8s"
dur="0.15s"
values="0;0.3"
></animate>
</path>
<path
fill="none"
stroke-dasharray="14"
stroke-dashoffset="14"
d="M8 12L11 15L16 10"
>
<animate
fill="freeze"
attributeName="stroke-dashoffset"
begin="0.6s"
dur="0.2s"
values="14;0"
></animate>
</path>
</g>
</svg>
)
}
147 changes: 147 additions & 0 deletions src/pages/manage/indexes/indexes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import {
Badge,
Button,
Heading,
HStack,
Icon,
Text,
useColorModeValue,
VStack,
} from "@hope-ui/solid"
import { createSignal, For, Show } from "solid-js"
import { createStore } from "solid-js/store"
import { useFetch, useT } from "~/hooks"
import { PEmptyResp, PResp, SettingItem } from "~/types"
import {
buildIndex,
formatDate,
getTarget,
handleResp,
handleRespWithNotifySuccess,
r,
} from "~/utils"
import { Item } from "../settings/SettingItem"
import { LineMdConfirmCircleTwotone, LineMdLoadingTwotoneLoop } from "./icons"

type Progress = {
obj_count: number
is_done: boolean
last_done_time: string
error: string
}

const Indexes = () => {
const t = useT()
const [searchIndex, setSearchIndex] = createStore<SettingItem>(
{} as SettingItem
)
const [searchIndexLoading, searchIndexDataReq] = useFetch(
(): PResp<SettingItem> => r.get("/admin/setting/get?key=search_index")
)
const refreshSearchIndex = async () => {
const resp = await searchIndexDataReq()
handleResp(resp, (data) => {
setSearchIndex(data)
})
}
refreshSearchIndex()
const [saveSearchIndexLoading, saveSearchIndexReq] = useFetch(
(): PEmptyResp => r.post("/admin/setting/save", [getTarget(searchIndex)])
)
const saveSearchIndex = async () => {
const resp = await saveSearchIndexReq()
handleRespWithNotifySuccess(resp, () => {
refreshProgress()
})
}
const [progress, setProgress] = createSignal<Progress>()
const [progressLoading, getProgressReq] = useFetch(
(): PResp<Progress> => r.get("/admin/index/progress")
)
const refreshProgress = async () => {
const resp = await getProgressReq()
handleResp(resp, (data) => {
setProgress(data)
})
}
refreshProgress()
const [reBuildLoading, rebuildReq] = useFetch(buildIndex)
const rebuild = async () => {
const resp = await rebuildReq()
handleRespWithNotifySuccess(resp)
}
return (
<VStack spacing="$2" w="$full" alignItems="start">
<Heading>{t("indexes.search_index")}</Heading>
<Item
hideLabel
w="min($sm, 100%)"
{...searchIndex}
onChange={(str) => setSearchIndex("value", str)}
/>
<Button
onClick={[saveSearchIndex, undefined]}
loading={saveSearchIndexLoading()}
>
{t("global.save")}
</Button>
<Heading>{t("indexes.current")}</Heading>
<Show when={progress()}>
<HStack
spacing="$2"
// w="$full"
w="fit-content"
shadow="$md"
rounded="$lg"
bg={useColorModeValue("", "$neutral3")()}
>
<Icon
boxSize="$28"
color="$accent9"
as={
progress()?.is_done
? LineMdConfirmCircleTwotone
: LineMdLoadingTwotoneLoop
}
/>
<VStack spacing="$2" flex="1" alignItems="start" mr="$2">
<Text>
{t("indexes.obj_count")}:
<Badge colorScheme="info" ml="$2">
{progress()?.obj_count}
</Badge>
</Text>
<Text>
{t("indexes.obj_count")}:
<Badge colorScheme="accent" ml="$2">
{formatDate(progress()!.last_done_time)}
</Badge>
</Text>
<Show when={progress()?.error}>
<Text css={{ wordBreak: "break-all" }}>
{t("indexes.obj_count")}:
<Badge colorScheme="danger" ml="$2">
{progress()!.error}
</Badge>
</Text>
</Show>
</VStack>
</HStack>
</Show>
<HStack spacing="$2">
<Button
colorScheme="accent"
onClick={[refreshProgress, undefined]}
loading={progressLoading()}
>
{t("global.refresh")}
</Button>
<Button onClick={[rebuild, undefined]} loading={reBuildLoading()}>
{t(`indexes.${progress()?.is_done ? "rebuild" : "build"}`)}
</Button>
</HStack>
</VStack>
)
}

export default Indexes
Loading

0 comments on commit aa0db01

Please sign in to comment.