metacubexd/src/pages/Setup.tsx

172 lines
4.2 KiB
TypeScript
Raw Normal View History

2023-08-24 04:20:53 +08:00
import { createForm } from '@felte/solid'
import { validator } from '@felte/validator-zod'
2023-09-02 00:32:27 +08:00
import { useI18n } from '@solid-primitives/i18n'
2023-08-24 04:20:53 +08:00
import { useNavigate } from '@solidjs/router'
import { IconX } from '@tabler/icons-solidjs'
import ky from 'ky'
import { For, onMount } from 'solid-js'
2023-08-24 04:20:53 +08:00
import { v4 as uuid } from 'uuid'
import { z } from 'zod'
import { Button } from '~/components'
2023-09-04 13:34:20 +08:00
import {
endpointList,
selectedEndpoint,
setEndpointList,
setSelectedEndpoint,
} from '~/signals'
2023-08-24 04:20:53 +08:00
const schema = z.object({
url: z.string().url().nonempty(),
secret: z.string(),
})
export default () => {
2023-09-02 00:32:27 +08:00
const [t] = useI18n()
2023-08-24 04:20:53 +08:00
const navigate = useNavigate()
const onSetupSuccess = (id: string) => {
setSelectedEndpoint(id)
navigate('/overview')
}
const checkEndpoint = (url: string, secret: string) =>
2023-08-30 18:01:48 +08:00
ky
.get(url, {
headers: secret
2023-08-30 10:55:12 +08:00
? {
Authorization: `Bearer ${secret}`,
2023-08-30 10:55:12 +08:00
}
: {},
})
2023-08-30 18:01:48 +08:00
.then(({ ok }) => ok)
.catch(() => false)
const onEndpointSelect = async (id: string) => {
const endpoint = endpointList().find((e) => e.id === id)
if (!endpoint) {
return
}
if (!(await checkEndpoint(endpoint.url, endpoint.secret))) {
return
}
onSetupSuccess(id)
}
const onSubmit = async ({ url, secret }: { url: string; secret: string }) => {
2023-09-04 13:34:20 +08:00
if (!(await checkEndpoint(url, secret))) {
return
}
const id = uuid()
const list = endpointList().slice()
const point = list.find((history) => history.url === url)
2023-09-04 13:34:20 +08:00
if (!point) {
// new host and secret
setEndpointList([{ id, url, secret }, ...list])
onSetupSuccess(id)
return
}
2023-09-04 13:55:37 +08:00
// exist host we update secret and id no matter if secret is equal or not
2023-09-04 13:34:20 +08:00
point.secret = secret
point.id = id
2023-09-04 13:34:20 +08:00
setEndpointList(list)
onSetupSuccess(id)
}
const { form } = createForm<z.infer<typeof schema>>({
extend: validator({ schema }),
onSubmit,
2023-08-24 04:20:53 +08:00
})
2023-09-04 13:34:20 +08:00
const onRemove = (id: string) => {
if (selectedEndpoint() === id) {
setSelectedEndpoint('')
}
2023-08-24 04:20:53 +08:00
setEndpointList(endpointList().filter((e) => e.id !== id))
2023-09-04 13:34:20 +08:00
}
2023-08-24 04:20:53 +08:00
onMount(() => {
const query = new URLSearchParams(window.location.search)
if (query.has('hostname')) {
void onSubmit({
url: `http://${query.get('hostname')}${
query.get('port') && ':' + query.get('port')
}`,
secret: query.get('secret') ?? '',
})
2023-09-04 13:51:29 +08:00
} else if (endpointList().length === 0) {
/**
we only try auto login when there is nothing in endpoint list
2023-09-04 13:55:37 +08:00
or user who is using default config wont be able to switch to another endpoint ever
2023-09-04 13:51:29 +08:00
*/
void onSubmit({
url: 'http://127.0.0.1:9090',
secret: '',
})
}
})
2023-08-24 04:20:53 +08:00
return (
2023-08-27 22:25:41 +08:00
<div class="mx-auto flex flex-col items-center gap-4 py-10 sm:w-2/3">
2023-08-24 04:20:53 +08:00
<form class="contents" use:form={form}>
2023-08-27 22:25:41 +08:00
<div class="flex w-full flex-col gap-4">
2023-08-24 04:20:53 +08:00
<input
name="url"
type="url"
2023-08-27 22:25:41 +08:00
class="input input-bordered"
placeholder="host url"
2023-08-24 04:20:53 +08:00
list="defaultEndpoints"
/>
<datalist id="defaultEndpoints">
2023-09-01 12:16:37 +08:00
<option value="http://127.0.0.1:9090" />
2023-08-24 04:20:53 +08:00
</datalist>
<input
name="secret"
type="password"
2023-08-27 22:25:41 +08:00
class="input input-bordered"
2023-08-24 04:20:53 +08:00
placeholder="secret"
/>
<Button type="submit" class="btn-primary join-item uppercase">
2023-09-02 00:32:27 +08:00
{t('add')}
</Button>
2023-08-24 04:20:53 +08:00
</div>
</form>
<div class="flex w-full flex-col gap-4">
<For each={endpointList()}>
{({ id, url }) => (
<div
class="badge badge-info flex w-full cursor-pointer items-center gap-4 py-4"
onClick={() => onEndpointSelect(id)}
2023-08-24 04:20:53 +08:00
>
{url}
<Button
class="btn-circle btn-ghost btn-xs text-white"
2023-08-24 04:20:53 +08:00
onClick={(e) => {
e.stopPropagation()
onRemove(id)
}}
>
<IconX />
</Button>
2023-08-24 04:20:53 +08:00
</div>
)}
</For>
</div>
</div>
)
}