metacubexd/src/pages/Proxies.tsx

329 lines
10 KiB
TypeScript
Raw Normal View History

2023-09-15 23:43:55 +08:00
import {
IconBrandSpeedtest,
IconReload,
IconSettings,
} from '@tabler/icons-solidjs'
import { For, Show, createMemo, createSignal, onMount } from 'solid-js'
2023-09-05 15:38:42 +08:00
import { twMerge } from 'tailwind-merge'
import {
Button,
Collapse,
2023-09-15 23:43:55 +08:00
ProxiesSettingsModal,
ProxyNodeCard,
ProxyNodePreview,
RenderInTwoColumns,
SubscriptionInfo,
} from '~/components'
import {
filterProxiesByAvailability,
sortProxiesByOrderingType,
} from '~/helpers'
2023-09-22 17:14:35 +08:00
import { useI18n } from '~/i18n'
import {
formatTimeFromNow,
hideUnAvailableProxies,
proxiesOrderingType,
useProxies,
} from '~/signals'
enum ActiveTab {
proxyProviders = 'proxyProviders',
proxies = 'proxies',
}
2023-08-24 04:20:53 +08:00
export default () => {
let proxiesSettingsModalRef: HTMLDialogElement | undefined
const [t] = useI18n()
const {
fetchProxies,
proxies,
2023-09-17 14:55:03 +08:00
selectProxyInGroup,
latencyMap,
proxyProviders,
updateProviderByProviderName,
updateAllProvider,
proxyGroupLatencyTest,
proxyProviderLatencyTest,
collapsedMap,
setCollapsedMap,
proxyGroupLatencyTestingMap,
proxyProviderLatencyTestingMap,
isAllProviderUpdating,
updatingMap,
} = useProxies()
2023-08-30 23:02:55 +08:00
onMount(fetchProxies)
const onProxyGroupLatencyTestClick = async (
e: MouseEvent,
groupName: string,
) => {
e.stopPropagation()
void proxyGroupLatencyTest(groupName)
}
const onProxyProviderLatencyTestClick = (
e: MouseEvent,
providerName: string,
) => {
e.stopPropagation()
void proxyProviderLatencyTest(providerName)
}
const onUpdateProxyProviderClick = (e: MouseEvent, providerName: string) => {
e.stopPropagation()
void updateProviderByProviderName(providerName)
}
const onUpdateAllProviderClick = async (e: MouseEvent) => {
2023-09-05 15:38:42 +08:00
e.stopPropagation()
void updateAllProvider()
2023-08-30 11:01:19 +08:00
}
const [activeTab, setActiveTab] = createSignal(ActiveTab.proxies)
const tabs = () => [
{
type: ActiveTab.proxies,
name: t('proxies'),
count: proxies().length,
},
{
type: ActiveTab.proxyProviders,
name: t('proxyProviders'),
count: proxyProviders().length,
},
]
2023-08-24 04:20:53 +08:00
return (
2023-09-06 22:47:02 +08:00
<div class="flex h-full flex-col gap-2">
<div class="flex items-center gap-2">
<div class="tabs-boxed tabs gap-2">
<For each={tabs()}>
{(tab) => (
<button
class={twMerge(
activeTab() === tab.type && 'tab-active',
'tab tab-sm gap-2 px-2 sm:tab-md',
)}
onClick={() => setActiveTab(tab.type)}
>
<span>{tab.name}</span>
<div class="badge badge-sm">{tab.count}</div>
</button>
)}
</For>
</div>
2023-09-15 23:43:55 +08:00
<Show when={activeTab() === ActiveTab.proxyProviders}>
<Button
class="btn btn-circle btn-sm"
disabled={isAllProviderUpdating()}
onClick={(e) => onUpdateAllProviderClick(e)}
2023-09-22 16:05:36 +08:00
icon={
<IconReload
class={twMerge(
isAllProviderUpdating() && 'animate-spin text-success',
)}
/>
}
/>
</Show>
<div class="ml-auto">
<Button
class="btn-circle btn-sm sm:btn-md"
onClick={() => proxiesSettingsModalRef?.showModal()}
2023-09-22 16:05:36 +08:00
icon={<IconSettings />}
/>
</div>
</div>
2023-09-06 22:47:02 +08:00
<div class="flex-1 overflow-y-auto">
<Show when={activeTab() === ActiveTab.proxies}>
<RenderInTwoColumns>
2023-09-16 01:00:30 +08:00
<For each={proxies()}>
2023-09-17 14:55:03 +08:00
{(proxyGroup) => {
const sortedProxyNames = createMemo(() =>
filterProxiesByAvailability(
sortProxiesByOrderingType(
2023-09-17 14:55:03 +08:00
proxyGroup.all ?? [],
latencyMap(),
proxiesOrderingType(),
),
2023-09-16 01:00:30 +08:00
latencyMap(),
hideUnAvailableProxies(),
2023-09-16 01:00:30 +08:00
),
)
2023-09-16 01:00:30 +08:00
const title = (
<>
<div class="flex items-center justify-between pr-8">
2023-09-16 01:00:30 +08:00
<div class="flex items-center gap-2">
2023-09-17 14:55:03 +08:00
<span>{proxyGroup.name}</span>
<div class="badge badge-sm">
{proxyGroup.all?.length}
</div>
2023-09-16 01:00:30 +08:00
</div>
2023-09-16 01:00:30 +08:00
<Button
class="btn-circle btn-sm"
disabled={
proxyGroupLatencyTestingMap()[proxyGroup.name]
}
onClick={(e) =>
onProxyGroupLatencyTestClick(e, proxyGroup.name)
}
2023-09-22 16:05:36 +08:00
icon={
<IconBrandSpeedtest
class={twMerge(
proxyGroupLatencyTestingMap()[proxyGroup.name] &&
2023-09-22 16:05:36 +08:00
'animate-pulse text-success',
)}
/>
}
/>
2023-09-16 01:00:30 +08:00
</div>
2023-09-16 01:00:30 +08:00
<div class="text-sm text-slate-500">
2023-09-17 14:55:03 +08:00
{proxyGroup.type}{' '}
{proxyGroup.now?.length > 0 && ` :: ${proxyGroup.now}`}
2023-09-16 01:00:30 +08:00
</div>
2023-09-17 14:55:03 +08:00
<Show when={!collapsedMap()[proxyGroup.name]}>
2023-09-16 01:00:30 +08:00
<ProxyNodePreview
proxyNameList={sortedProxyNames()}
2023-09-17 14:55:03 +08:00
now={proxyGroup.now}
2023-09-16 01:00:30 +08:00
/>
</Show>
</>
)
2023-09-16 01:00:30 +08:00
return (
<Collapse
2023-09-17 14:55:03 +08:00
isOpen={collapsedMap()[proxyGroup.name]}
2023-09-16 01:00:30 +08:00
title={title}
2023-09-17 14:55:03 +08:00
onCollapse={(val) => setCollapsedMap(proxyGroup.name, val)}
2023-09-16 01:28:58 +08:00
>
<For each={sortedProxyNames()}>
{(proxyName) => (
<ProxyNodeCard
proxyName={proxyName}
isSelected={proxyGroup.now === proxyName}
onClick={() =>
void selectProxyInGroup(proxyGroup, proxyName)
}
/>
)}
</For>
2023-09-16 01:28:58 +08:00
</Collapse>
2023-09-16 01:00:30 +08:00
)
}}
</For>
</RenderInTwoColumns>
</Show>
<Show when={activeTab() === ActiveTab.proxyProviders}>
<RenderInTwoColumns>
2023-09-16 01:00:30 +08:00
<For each={proxyProviders()}>
{(proxyProvider) => {
const sortedProxyNames = createMemo(() =>
2023-09-16 01:00:30 +08:00
sortProxiesByOrderingType(
proxyProvider.proxies.map((i) => i.name) ?? [],
latencyMap(),
proxiesOrderingType(),
),
)
2023-09-16 01:00:30 +08:00
const title = (
<>
<div class="flex items-center justify-between pr-8">
2023-09-16 01:00:30 +08:00
<div class="flex items-center gap-2">
<span>{proxyProvider.name}</span>
<div class="badge badge-sm">
{proxyProvider.proxies.length}
</div>
2023-09-06 22:47:02 +08:00
</div>
2023-09-22 16:05:36 +08:00
<div class="flex items-center gap-2">
2023-09-16 01:00:30 +08:00
<Button
2023-09-22 16:05:36 +08:00
class="btn btn-circle btn-sm"
2023-09-16 01:00:30 +08:00
disabled={updatingMap()[proxyProvider.name]}
onClick={(e) =>
onUpdateProxyProviderClick(e, proxyProvider.name)
2023-09-16 01:00:30 +08:00
}
2023-09-22 16:05:36 +08:00
icon={
<IconReload
class={twMerge(
updatingMap()[proxyProvider.name] &&
'animate-spin text-success',
)}
/>
}
/>
2023-09-06 22:47:02 +08:00
2023-09-16 01:00:30 +08:00
<Button
class="btn btn-circle btn-sm"
disabled={
proxyProviderLatencyTestingMap()[proxyProvider.name]
}
2023-09-16 01:00:30 +08:00
onClick={(e) =>
onProxyProviderLatencyTestClick(
e,
proxyProvider.name,
)
2023-09-16 01:00:30 +08:00
}
2023-09-22 16:05:36 +08:00
icon={
<IconBrandSpeedtest
class={twMerge(
proxyProviderLatencyTestingMap()[
proxyProvider.name
] && 'animate-pulse text-success',
2023-09-22 16:05:36 +08:00
)}
/>
}
/>
2023-09-16 01:00:30 +08:00
</div>
</div>
2023-09-16 01:00:30 +08:00
<SubscriptionInfo
subscriptionInfo={proxyProvider.subscriptionInfo}
/>
2023-09-06 22:47:02 +08:00
2023-09-16 01:00:30 +08:00
<div class="text-sm text-slate-500">
{proxyProvider.vehicleType} :: {t('updated')}{' '}
{formatTimeFromNow(proxyProvider.updatedAt)}
</div>
2023-09-06 22:47:02 +08:00
2023-09-16 01:00:30 +08:00
<Show when={!collapsedMap()[proxyProvider.name]}>
<ProxyNodePreview proxyNameList={sortedProxyNames()} />
2023-09-16 01:00:30 +08:00
</Show>
</>
)
2023-09-06 22:47:02 +08:00
2023-09-16 01:00:30 +08:00
return (
<Collapse
isOpen={collapsedMap()[proxyProvider.name]}
title={title}
onCollapse={(val) =>
setCollapsedMap(proxyProvider.name, val)
}
2023-09-16 01:28:58 +08:00
>
<For each={sortedProxyNames()}>
{(proxyName) => <ProxyNodeCard proxyName={proxyName} />}
</For>
2023-09-16 01:28:58 +08:00
</Collapse>
2023-09-16 01:00:30 +08:00
)
}}
</For>
</RenderInTwoColumns>
2023-09-06 22:47:02 +08:00
</Show>
</div>
2023-09-15 23:43:55 +08:00
<ProxiesSettingsModal ref={(el) => (proxiesSettingsModalRef = el)} />
</div>
2023-08-24 04:20:53 +08:00
)
}