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