mirror of
https://github.com/MetaCubeX/metacubexd.git
synced 2024-12-27 07:34:12 +08:00
refactor: use a map for update state
This commit is contained in:
parent
6cd9ee74ba
commit
c4a7163786
@ -1,27 +1,35 @@
|
||||
import dayjs from 'dayjs'
|
||||
import { createSignal } from 'solid-js'
|
||||
import { PROXIES_ORDERING_TYPE } from '~/constants'
|
||||
|
||||
export const formatTimeFromNow = (time: number | string) => {
|
||||
return dayjs(time).fromNow()
|
||||
}
|
||||
|
||||
export const handleAnimatedBtnClickWithCallback = async (
|
||||
event: MouseEvent,
|
||||
callback: () => Promise<void>,
|
||||
className = 'animate-spin',
|
||||
) => {
|
||||
let el = event.target as HTMLElement
|
||||
event.stopPropagation()
|
||||
|
||||
while (el && !el.classList.contains('btn')) {
|
||||
el = el.parentElement!
|
||||
export const useStringBooleanMap = () => {
|
||||
const [map, setMap] = createSignal<Record<string, boolean>>({})
|
||||
const set = (name: string, value: boolean) => {
|
||||
setMap({
|
||||
...map(),
|
||||
[name]: value,
|
||||
})
|
||||
}
|
||||
|
||||
el.classList.add(className)
|
||||
try {
|
||||
await callback()
|
||||
} catch {}
|
||||
el.classList.remove(className)
|
||||
const setWithCallback = async (
|
||||
name: string,
|
||||
callback: () => Promise<void>,
|
||||
) => {
|
||||
set(name, true)
|
||||
try {
|
||||
await callback()
|
||||
} catch {}
|
||||
set(name, false)
|
||||
}
|
||||
|
||||
return {
|
||||
map,
|
||||
set,
|
||||
setWithCallback,
|
||||
}
|
||||
}
|
||||
|
||||
export const formatProxyType = (type = '') => {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { useI18n } from '@solid-primitives/i18n'
|
||||
import { IconBrandSpeedtest } from '@tabler/icons-solidjs'
|
||||
import { createSignal, Show } from 'solid-js'
|
||||
import { Show } from 'solid-js'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import {
|
||||
Button,
|
||||
Collapse,
|
||||
@ -8,10 +9,7 @@ import {
|
||||
ProxyCardGroups,
|
||||
ProxyNodePreview,
|
||||
} from '~/components'
|
||||
import {
|
||||
handleAnimatedBtnClickWithCallback,
|
||||
sortProxiesByOrderingType,
|
||||
} from '~/helpers'
|
||||
import { sortProxiesByOrderingType, useStringBooleanMap } from '~/helpers'
|
||||
import {
|
||||
proxiesOrderingType,
|
||||
renderProxiesInSamePage,
|
||||
@ -29,19 +27,19 @@ export default () => {
|
||||
latencyMap,
|
||||
} = useProxies()
|
||||
|
||||
const [collapsedMap, setCollapsedMap] = createSignal<Record<string, boolean>>(
|
||||
{},
|
||||
)
|
||||
const { map: collapsedMap, set: setCollapsedMap } = useStringBooleanMap()
|
||||
const { map: speedTestingMap, setWithCallback: setSpeedTestingMap } =
|
||||
useStringBooleanMap()
|
||||
|
||||
const onProxyNodeClick = async (proxy: Proxy, proxyName: string) => {
|
||||
void setProxyGroupByProxyName(proxy, proxyName)
|
||||
}
|
||||
|
||||
const onSpeedTestClick = (e: MouseEvent, name: string) => {
|
||||
handleAnimatedBtnClickWithCallback(
|
||||
e,
|
||||
latencyTestByProxyGroupName.bind(null, name),
|
||||
'animate-pulse',
|
||||
const onSpeedTestClick = async (e: MouseEvent, name: string) => {
|
||||
e.stopPropagation()
|
||||
setSpeedTestingMap(
|
||||
name,
|
||||
async () => await latencyTestByProxyGroupName(name),
|
||||
)
|
||||
}
|
||||
|
||||
@ -67,7 +65,11 @@ export default () => {
|
||||
class="btn-circle btn-sm"
|
||||
onClick={(e) => onSpeedTestClick(e, proxy.name)}
|
||||
>
|
||||
<IconBrandSpeedtest />
|
||||
<IconBrandSpeedtest
|
||||
class={twMerge(
|
||||
speedTestingMap()[proxy.name] && 'animate-pulse',
|
||||
)}
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<div class="text-sm text-slate-500">
|
||||
@ -98,10 +100,7 @@ export default () => {
|
||||
title={title}
|
||||
content={content}
|
||||
onCollapse={(val) =>
|
||||
setCollapsedMap({
|
||||
...collapsedMap(),
|
||||
[`group-${proxy.name}`]: val,
|
||||
})
|
||||
setCollapsedMap(`group-${proxy.name}`, val)
|
||||
}
|
||||
/>
|
||||
)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { useI18n } from '@solid-primitives/i18n'
|
||||
import { IconBrandSpeedtest, IconReload } from '@tabler/icons-solidjs'
|
||||
import { Show, createSignal } from 'solid-js'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import {
|
||||
Button,
|
||||
Collapse,
|
||||
@ -11,8 +12,8 @@ import {
|
||||
} from '~/components'
|
||||
import {
|
||||
formatTimeFromNow,
|
||||
handleAnimatedBtnClickWithCallback,
|
||||
sortProxiesByOrderingType,
|
||||
useStringBooleanMap,
|
||||
} from '~/helpers'
|
||||
import { proxiesOrderingType, useProxies } from '~/signals'
|
||||
|
||||
@ -26,27 +27,33 @@ export default () => {
|
||||
latencyMap,
|
||||
} = useProxies()
|
||||
|
||||
const [collapsedMap, setCollapsedMap] = createSignal<Record<string, boolean>>(
|
||||
{},
|
||||
)
|
||||
const { map: collapsedMap, set: setCollapsedMap } = useStringBooleanMap()
|
||||
const { map: healthCheckingMap, setWithCallback: setHealthCheckingMap } =
|
||||
useStringBooleanMap()
|
||||
const { map: updateingMap, setWithCallback: setUpdateingMap } =
|
||||
useStringBooleanMap()
|
||||
const [allProviderIsUpdating, setAllProviderIsUpdating] = createSignal(false)
|
||||
|
||||
const onHealthCheckClick = (e: MouseEvent, name: string) => {
|
||||
handleAnimatedBtnClickWithCallback(
|
||||
e,
|
||||
healthCheckByProviderName.bind(null, name),
|
||||
'animate-pulse',
|
||||
const onHealthCheckClick = async (e: MouseEvent, name: string) => {
|
||||
e.stopPropagation()
|
||||
setHealthCheckingMap(
|
||||
name,
|
||||
async () => await healthCheckByProviderName(name),
|
||||
)
|
||||
}
|
||||
|
||||
const onUpdateProviderClick = (e: MouseEvent, name: string) => {
|
||||
handleAnimatedBtnClickWithCallback(
|
||||
e,
|
||||
updateProviderByProviderName.bind(null, name),
|
||||
)
|
||||
const onUpdateProviderClick = async (e: MouseEvent, name: string) => {
|
||||
e.stopPropagation()
|
||||
setUpdateingMap(name, async () => await updateProviderByProviderName(name))
|
||||
}
|
||||
|
||||
const onUpdateAllProviderClick = (e: MouseEvent) => {
|
||||
handleAnimatedBtnClickWithCallback(e, updateAllProvider)
|
||||
const onUpdateAllProviderClick = async (e: MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
setAllProviderIsUpdating(true)
|
||||
try {
|
||||
await updateAllProvider()
|
||||
} catch {}
|
||||
setAllProviderIsUpdating(false)
|
||||
}
|
||||
|
||||
return (
|
||||
@ -58,7 +65,9 @@ export default () => {
|
||||
class="btn-circle btn-ghost btn-sm ml-2"
|
||||
onClick={(e) => onUpdateAllProviderClick(e)}
|
||||
>
|
||||
<IconReload />
|
||||
<IconReload
|
||||
class={twMerge(allProviderIsUpdating() && 'animate-spin')}
|
||||
/>
|
||||
</Button>
|
||||
</h1>
|
||||
<ForTwoColumns
|
||||
@ -80,14 +89,23 @@ export default () => {
|
||||
onUpdateProviderClick(e, proxyProvider.name)
|
||||
}
|
||||
>
|
||||
<IconReload />
|
||||
<IconReload
|
||||
class={twMerge(
|
||||
updateingMap()[proxyProvider.name] && 'animate-spin',
|
||||
)}
|
||||
/>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
class="btn btn-circle btn-sm"
|
||||
onClick={(e) => onHealthCheckClick(e, proxyProvider.name)}
|
||||
>
|
||||
<IconBrandSpeedtest />
|
||||
<IconBrandSpeedtest
|
||||
class={twMerge(
|
||||
healthCheckingMap()[proxyProvider.name] &&
|
||||
'animate-pulse',
|
||||
)}
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@ -112,10 +130,7 @@ export default () => {
|
||||
title={title}
|
||||
content={content}
|
||||
onCollapse={(val) =>
|
||||
setCollapsedMap({
|
||||
...collapsedMap(),
|
||||
[`provider-${proxyProvider.name}`]: val,
|
||||
})
|
||||
setCollapsedMap(`provider-${proxyProvider.name}`, val)
|
||||
}
|
||||
/>
|
||||
)
|
||||
|
@ -2,11 +2,9 @@ import { useI18n } from '@solid-primitives/i18n'
|
||||
import { IconReload } from '@tabler/icons-solidjs'
|
||||
import InfiniteScroll from 'solid-infinite-scroll'
|
||||
import { For, Show, createMemo, createSignal, onMount } from 'solid-js'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { Button } from '~/components'
|
||||
import {
|
||||
formatTimeFromNow,
|
||||
handleAnimatedBtnClickWithCallback,
|
||||
} from '~/helpers'
|
||||
import { formatTimeFromNow, useStringBooleanMap } from '~/helpers'
|
||||
import { useRules } from '~/signals'
|
||||
|
||||
export default () => {
|
||||
@ -23,15 +21,22 @@ export default () => {
|
||||
|
||||
onMount(updateRules)
|
||||
|
||||
const { map: updateingMap, setWithCallback: setUpdateingMap } =
|
||||
useStringBooleanMap()
|
||||
const [allProviderIsUpdating, setAllProviderIsUpdating] = createSignal(false)
|
||||
|
||||
const onUpdateProviderClick = (e: MouseEvent, name: string) => {
|
||||
handleAnimatedBtnClickWithCallback(
|
||||
e,
|
||||
updateRuleProviderByName.bind(null, name),
|
||||
)
|
||||
e.stopPropagation()
|
||||
setUpdateingMap(name, async () => await updateRuleProviderByName(name))
|
||||
}
|
||||
|
||||
const onUpdateAllProviderClick = (e: MouseEvent) => {
|
||||
handleAnimatedBtnClickWithCallback(e, updateAllRuleProvider)
|
||||
const onUpdateAllProviderClick = async (e: MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
setAllProviderIsUpdating(true)
|
||||
try {
|
||||
await updateAllRuleProvider()
|
||||
} catch {}
|
||||
setAllProviderIsUpdating(false)
|
||||
}
|
||||
|
||||
return (
|
||||
@ -68,7 +73,9 @@ export default () => {
|
||||
class="btn-circle btn-ghost btn-sm ml-2"
|
||||
onClick={(e) => onUpdateAllProviderClick(e)}
|
||||
>
|
||||
<IconReload />
|
||||
<IconReload
|
||||
class={twMerge(allProviderIsUpdating() && 'animate-spin')}
|
||||
/>
|
||||
</Button>
|
||||
</h1>
|
||||
|
||||
@ -86,7 +93,11 @@ export default () => {
|
||||
onUpdateProviderClick(e, rulesProvider.name)
|
||||
}
|
||||
>
|
||||
<IconReload />
|
||||
<IconReload
|
||||
class={twMerge(
|
||||
updateingMap()[rulesProvider.name] && 'animate-spin',
|
||||
)}
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -9,16 +9,14 @@ export const useRules = () => {
|
||||
const [rulesProviders, setRulesProviders] = createSignal<RuleProvider[]>([])
|
||||
|
||||
const updateRules = async () => {
|
||||
const { rules } = await request
|
||||
.get('rules')
|
||||
.json<{ rules: Record<string, Rule> }>()
|
||||
const [{ rules }, { providers }] = await Promise.all([
|
||||
request.get('rules').json<{ rules: Record<string, Rule> }>(),
|
||||
request
|
||||
.get('providers/rules')
|
||||
.json<{ providers: Record<string, RuleProvider> }>(),
|
||||
])
|
||||
|
||||
setRules(Object.values(rules))
|
||||
|
||||
const { providers } = await request
|
||||
.get('providers/rules')
|
||||
.json<{ providers: Record<string, RuleProvider> }>()
|
||||
|
||||
setRulesProviders(Object.values(providers))
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user