refactor: use a map for update state

This commit is contained in:
Zephyruso 2023-09-05 15:38:42 +08:00
parent 6cd9ee74ba
commit c4a7163786
6 changed files with 108 additions and 77 deletions

View File

@ -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 = '') => {

View File

@ -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)
}
/>
)

View File

@ -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)
}
/>
)

View File

@ -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>

View File

@ -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))
}