Skip to content

Commit e4bbe40

Browse files
committed
Merge branch 'dev-media' of github.com:OpenListTeam/OpenList-Frontend into dev-media
# Conflicts: # src/types/index.ts resolved by dev-media version
2 parents 6723935 + 0daa6ca commit e4bbe40

8 files changed

Lines changed: 276 additions & 0 deletions

File tree

src/lang/en/entry.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import shares from "./shares.json"
1313
import storages from "./storages.json"
1414
import tasks from "./tasks.json"
1515
import users from "./users.json"
16+
import virtual_hosts from "./virtual_hosts.json"
1617

1718
export const dict = {
1819
br,
@@ -30,4 +31,5 @@ export const dict = {
3031
storages,
3132
tasks,
3233
users,
34+
virtual_hosts,
3335
}

src/lang/en/manage.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"storages": "Storages",
1212
"shares": "Shares",
1313
"metas": "Metas",
14+
"virtual_hosts": "Virtual Hosts",
1415
"profile": "Profile",
1516
"about": "About",
1617
"tasks": "Tasks",

src/lang/en/virtual_hosts.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"domain": "Domain",
3+
"domain_help": "The domain name to bind (e.g. blog.example.com)",
4+
"path": "Path",
5+
"path_help": "The OpenList path to map this domain to",
6+
"enabled": "Enabled",
7+
"web_hosting": "Web Hosting",
8+
"web_hosting_help": "If enabled, HTML files will be served directly instead of the file browser"
9+
}

src/pages/manage/routes.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ const hide_routes: Route[] = [
3939
to: "/metas/edit/:id",
4040
component: lazy(() => import("./metas/AddOrEdit")),
4141
},
42+
{
43+
to: "/virtual_hosts/add",
44+
component: lazy(() => import("./virtual_hosts/AddOrEdit")),
45+
},
46+
{
47+
to: "/virtual_hosts/edit/:id",
48+
component: lazy(() => import("./virtual_hosts/AddOrEdit")),
49+
},
4250
{
4351
to: "/2fa",
4452
component: lazy(() => import("./users/2fa")),

src/pages/manage/sidemenu_items.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
BsBucket,
1515
BsHddNetwork,
1616
BsArrowLeftRight,
17+
BsGlobe,
1718
} from "solid-icons/bs"
1819
import { FiLogIn } from "solid-icons/fi"
1920
import { SiMetabase } from "solid-icons/si"
@@ -187,6 +188,12 @@ export const side_menu_items: SideMenuItem[] = [
187188
to: "/@manage/metas",
188189
component: lazy(() => import("./metas/Metas")),
189190
},
191+
{
192+
title: "manage.sidemenu.virtual_hosts",
193+
icon: BsGlobe,
194+
to: "/@manage/virtual_hosts",
195+
component: lazy(() => import("./virtual_hosts/VirtualHosts")),
196+
},
190197
{
191198
title: "manage.sidemenu.indexes",
192199
icon: BsSearch,
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import {
2+
Button,
3+
Switch as HopeSwitch,
4+
FormControl,
5+
FormHelperText,
6+
FormLabel,
7+
Heading,
8+
Input,
9+
VStack,
10+
} from "@hope-ui/solid"
11+
import { MaybeLoading, FolderChooseInput } from "~/components"
12+
import { useFetch, useRouter, useT } from "~/hooks"
13+
import { handleResp, notify, r } from "~/utils"
14+
import { VirtualHost, PEmptyResp, PResp } from "~/types"
15+
import { createStore } from "solid-js/store"
16+
17+
const AddOrEdit = () => {
18+
const t = useT()
19+
const { params, back } = useRouter()
20+
const { id } = params
21+
const [vhost, setVhost] = createStore<VirtualHost>({
22+
id: 0,
23+
enabled: true,
24+
domain: "",
25+
path: "",
26+
web_hosting: false,
27+
})
28+
const [vhostLoading, loadVhost] = useFetch(
29+
(): PResp<VirtualHost> => r.get(`/admin/vhost/get?id=${id}`),
30+
)
31+
32+
const initEdit = async () => {
33+
const resp = await loadVhost()
34+
handleResp<VirtualHost>(resp, setVhost)
35+
}
36+
if (id) {
37+
initEdit()
38+
}
39+
const [okLoading, ok] = useFetch((): PEmptyResp => {
40+
return r.post(`/admin/vhost/${id ? "update" : "create"}`, vhost)
41+
})
42+
return (
43+
<MaybeLoading loading={vhostLoading()}>
44+
<VStack w="$full" alignItems="start" spacing="$4">
45+
<Heading>{t(`global.${id ? "edit" : "add"}`)}</Heading>
46+
47+
{/* 启用开关 */}
48+
<FormControl
49+
w="$full"
50+
display="flex"
51+
flexDirection="row"
52+
alignItems="center"
53+
gap="$3"
54+
>
55+
<FormLabel for="enabled" mb="0">
56+
{t("virtual_hosts.enabled")}
57+
</FormLabel>
58+
<HopeSwitch
59+
id="enabled"
60+
checked={vhost.enabled}
61+
onChange={(e: any) => setVhost("enabled", e.currentTarget.checked)}
62+
/>
63+
</FormControl>
64+
65+
{/* 域名 */}
66+
<FormControl w="$full" display="flex" flexDirection="column" required>
67+
<FormLabel for="domain">{t("virtual_hosts.domain")}</FormLabel>
68+
<Input
69+
id="domain"
70+
placeholder="example.com"
71+
value={vhost.domain}
72+
onInput={(e) => setVhost("domain", e.currentTarget.value)}
73+
/>
74+
<FormHelperText>{t("virtual_hosts.domain_help")}</FormHelperText>
75+
</FormControl>
76+
77+
{/* 路径 */}
78+
<FormControl w="$full" display="flex" flexDirection="column" required>
79+
<FormLabel for="path">{t("virtual_hosts.path")}</FormLabel>
80+
<FolderChooseInput
81+
id="path"
82+
value={vhost.path}
83+
onChange={(path) => setVhost("path", path)}
84+
/>
85+
<FormHelperText>{t("virtual_hosts.path_help")}</FormHelperText>
86+
</FormControl>
87+
88+
{/* Web 托管开关 */}
89+
<FormControl w="$full" display="flex" flexDirection="column">
90+
<FormControl
91+
display="flex"
92+
flexDirection="row"
93+
alignItems="center"
94+
gap="$3"
95+
>
96+
<FormLabel for="web_hosting" mb="0">
97+
{t("virtual_hosts.web_hosting")}
98+
</FormLabel>
99+
<HopeSwitch
100+
id="web_hosting"
101+
checked={vhost.web_hosting}
102+
onChange={(e: any) =>
103+
setVhost("web_hosting", e.currentTarget.checked)
104+
}
105+
/>
106+
</FormControl>
107+
<FormHelperText>{t("virtual_hosts.web_hosting_help")}</FormHelperText>
108+
</FormControl>
109+
110+
<Button
111+
loading={okLoading()}
112+
onClick={async () => {
113+
const resp = await ok()
114+
handleResp(resp, () => {
115+
notify.success(t("global.save_success"))
116+
back()
117+
})
118+
}}
119+
>
120+
{t(`global.${id ? "save" : "add"}`)}
121+
</Button>
122+
</VStack>
123+
</MaybeLoading>
124+
)
125+
}
126+
127+
export default AddOrEdit
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import {
2+
Box,
3+
Button,
4+
HStack,
5+
Table,
6+
Tbody,
7+
Td,
8+
Th,
9+
Thead,
10+
Tr,
11+
VStack,
12+
} from "@hope-ui/solid"
13+
import { createSignal, For } from "solid-js"
14+
import {
15+
useFetch,
16+
useListFetch,
17+
useManageTitle,
18+
useRouter,
19+
useT,
20+
} from "~/hooks"
21+
import { handleResp, notify, r } from "~/utils"
22+
import { VirtualHost, PEmptyResp, PPageResp } from "~/types"
23+
import { DeletePopover } from "../common/DeletePopover"
24+
import { Wether } from "~/components"
25+
26+
const VirtualHosts = () => {
27+
const t = useT()
28+
useManageTitle("manage.sidemenu.virtual_hosts")
29+
const { to } = useRouter()
30+
const [getVhostsLoading, getVhosts] = useFetch(
31+
(): PPageResp<VirtualHost> => r.get("/admin/vhost/list"),
32+
)
33+
const [vhosts, setVhosts] = createSignal<VirtualHost[]>([])
34+
const refresh = async () => {
35+
const resp = await getVhosts()
36+
handleResp(resp, (data) => setVhosts(data.content))
37+
}
38+
refresh()
39+
40+
const [deleting, deleteVhost] = useListFetch(
41+
(id: number): PEmptyResp => r.post(`/admin/vhost/delete?id=${id}`),
42+
)
43+
return (
44+
<VStack spacing="$2" alignItems="start" w="$full">
45+
<HStack spacing="$2">
46+
<Button
47+
colorScheme="accent"
48+
loading={getVhostsLoading()}
49+
onClick={refresh}
50+
>
51+
{t("global.refresh")}
52+
</Button>
53+
<Button
54+
onClick={() => {
55+
to("/@manage/virtual_hosts/add")
56+
}}
57+
>
58+
{t("global.add")}
59+
</Button>
60+
</HStack>
61+
<Box w="$full" overflowX="auto">
62+
<Table highlightOnHover dense>
63+
<Thead>
64+
<Tr>
65+
<For each={["domain", "path", "enabled", "web_hosting"]}>
66+
{(title) => <Th>{t(`virtual_hosts.${title}`)}</Th>}
67+
</For>
68+
<Th>{t("global.operations")}</Th>
69+
</Tr>
70+
</Thead>
71+
<Tbody>
72+
<For each={vhosts()}>
73+
{(vhost) => (
74+
<Tr>
75+
<Td>{vhost.domain}</Td>
76+
<Td>{vhost.path}</Td>
77+
<Td>
78+
<Wether yes={vhost.enabled} />
79+
</Td>
80+
<Td>
81+
<Wether yes={vhost.web_hosting} />
82+
</Td>
83+
<Td>
84+
<HStack spacing="$2">
85+
<Button
86+
onClick={() => {
87+
to(`/@manage/virtual_hosts/edit/${vhost.id}`)
88+
}}
89+
>
90+
{t("global.edit")}
91+
</Button>
92+
<DeletePopover
93+
name={vhost.domain}
94+
loading={deleting() === vhost.id}
95+
onClick={async () => {
96+
const resp = await deleteVhost(vhost.id)
97+
handleResp(resp, () => {
98+
notify.success(t("global.delete_success"))
99+
refresh()
100+
})
101+
}}
102+
/>
103+
</HStack>
104+
</Td>
105+
</Tr>
106+
)}
107+
</For>
108+
</Tbody>
109+
</Table>
110+
</Box>
111+
</VStack>
112+
)
113+
}
114+
115+
export default VirtualHosts

src/types/virtual_host.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export interface VirtualHost {
2+
id: number
3+
enabled: boolean
4+
domain: string
5+
path: string
6+
web_hosting: boolean
7+
}

0 commit comments

Comments
 (0)