feat(rules): tab style for rules page #163 (#187)

Co-authored-by: nb5p <nb5p@users.noreply.github.com>
Co-authored-by: kunish <kunish.butt@gmail.com>
This commit is contained in:
nb5p 2023-09-09 17:16:18 +08:00 committed by GitHub
parent 8fa51e5639
commit a9aa8e540e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 3908 additions and 1731 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -47,7 +47,7 @@ export default {
autoSwitchTheme: 'Automatically switch theme',
favDayTheme: 'Favorite light theme',
favNightTheme: 'Favorite dark theme',
renderInTwoColumns: 'Render proxies in two columns',
renderInTwoColumns: 'Render in two columns',
updateGEODatabases: 'Update GEO Databases',
restartCore: 'Restart Core',
upgradeCore: 'Upgrade Core',
@ -60,8 +60,6 @@ export default {
ms: 'ms',
updated: 'Updated',
renderProxiesInSamePage: 'Render proxies and proxy provider in same page',
renderRulesAndProviderInTwoColumns:
'Render rules and rule provider in two columns',
tableSize: 'Table size',
xs: 'Extra small size',
sm: 'Small size',

View File

@ -47,7 +47,7 @@ export default {
autoSwitchTheme: '自动切换主题',
favDayTheme: '浅色主题偏好',
favNightTheme: '深色主题偏好',
renderInTwoColumns: '节点双列渲染',
renderInTwoColumns: '双列渲染',
updateGEODatabases: '更新 GEO 数据库文件',
restartCore: '重启核心',
upgradeCore: '更新核心',
@ -60,7 +60,6 @@ export default {
ms: '毫秒',
updated: '更新于',
renderProxiesInSamePage: '将代理和代理提供者显示在同一页',
renderRulesAndProviderInTwoColumns: '规则和规则提供者双列渲染',
tableSize: '表格大小',
xs: '超小尺寸',
sm: '小尺寸',

View File

@ -30,7 +30,6 @@ import {
proxiesOrderingType,
proxiesPreviewType,
renderInTwoColumns,
renderRulesAndProviderInTwoColumns,
setAutoCloseConns,
setAutoSwitchTheme,
setFavDayTheme,
@ -39,7 +38,6 @@ import {
setProxiesOrderingType,
setProxiesPreviewType,
setRenderInTwoColumns,
setRenderRulesAndProviderInTwoColumns,
setSelectedEndpoint,
setTableSize,
setTwemoji,
@ -319,11 +317,6 @@ const ConfigForXd = () => {
value: renderInTwoColumns,
onChange: setRenderInTwoColumns,
},
{
label: 'renderRulesAndProviderInTwoColumns',
value: renderRulesAndProviderInTwoColumns,
onChange: setRenderRulesAndProviderInTwoColumns,
},
{
label: 'autoSwitchTheme',
value: autoSwitchTheme,

View File

@ -3,15 +3,20 @@ 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 { Button, ForTwoColumns } from '~/components'
import { formatTimeFromNow, useStringBooleanMap } from '~/helpers'
import { renderRulesAndProviderInTwoColumns, useRules } from '~/signals'
import { useRules } from '~/signals'
enum ActiveTab {
ruleProviders = 'ruleProviders',
rules = 'rules',
}
export default () => {
const [t] = useI18n()
const {
rules,
rulesProviders,
ruleProviders,
updateRules,
updateAllRuleProvider,
updateRuleProviderByName,
@ -39,43 +44,45 @@ export default () => {
setAllProviderIsUpdating(false)
}
const [activeTab, setActiveTab] = createSignal(ActiveTab.rules)
const tabs = () => [
{
type: ActiveTab.rules,
name: t('rules'),
count: rules().length,
},
{
type: ActiveTab.ruleProviders,
name: t('ruleProviders'),
count: ruleProviders().length,
},
]
return (
<div
class={twMerge(
'flex w-full flex-col gap-4',
renderRulesAndProviderInTwoColumns() && 'flex-row',
)}
>
<div class="flex-1">
<h1 class="pb-4 text-lg font-semibold">{t('rules')}</h1>
<div class="flex h-full flex-col gap-2">
<Show when={ruleProviders().length > 0}>
<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 gap-2 px-2',
)}
onClick={() => setActiveTab(tab.type)}
>
<span>{tab.name}</span>
<div class="badge badge-sm">{tab.count}</div>
</button>
)}
</For>
</div>
<InfiniteScroll
each={renderRules()}
hasMore={renderRules().length < rules().length}
next={() => setMaxRuleRender(maxRuleRender() + 100)}
>
{(rule) => (
<div class="card card-bordered card-compact mb-2 bg-base-200 p-4">
<div class="flex items-center gap-2">
<span class="break-all">{rule.payload}</span>
<Show when={typeof rule.size === 'number' && rule.size !== -1}>
<div class="badge badge-sm">{rule.size}</div>
</Show>
</div>
<div class="text-xs text-slate-500">
{rule.type} :: {rule.proxy}
</div>
</div>
)}
</InfiniteScroll>
</div>
<Show when={rulesProviders().length > 0}>
<div class="flex-1">
<h1 class="flex items-center gap-2 pb-4 text-lg font-semibold">
{t('ruleProviders')}
<Show when={activeTab() === ActiveTab.ruleProviders}>
<Button
class="btn-circle btn-sm"
class="btn btn-circle btn-sm"
disabled={allProviderIsUpdating()}
onClick={(e) => onUpdateAllProviderClick(e)}
>
@ -85,38 +92,66 @@ export default () => {
)}
/>
</Button>
</h1>
<For each={rulesProviders()}>
{(rulesProvider) => (
<div class="card card-bordered card-compact mb-2 bg-base-200 p-4">
<div class="flex items-center gap-2 pr-8">
<span class="break-all">{rulesProvider.name}</span>
<div class="badge badge-sm">{rulesProvider.ruleCount}</div>
</div>
<div class="text-xs text-slate-500">
{rulesProvider.vehicleType} / {rulesProvider.behavior} /
{t('updated')} {formatTimeFromNow(rulesProvider.updatedAt)}
</div>
<Button
class="btn-circle btn-sm absolute right-2 top-2 mr-2 h-4"
disabled={updatingMap()[rulesProvider.name]}
onClick={(e) => onUpdateProviderClick(e, rulesProvider.name)}
>
<IconReload
class={twMerge(
updatingMap()[rulesProvider.name] &&
'animate-spin text-success',
)}
/>
</Button>
</div>
)}
</For>
</Show>
</div>
</Show>
<div class="flex-1 overflow-y-auto">
<Show when={activeTab() === ActiveTab.ruleProviders}>
<ForTwoColumns
subChild={ruleProviders().map((ruleProvider) => {
return (
<div class="card card-bordered card-compact mb-2 bg-base-200 p-4">
<div class="flex items-center gap-2 pr-8">
<span class="break-all">{ruleProvider.name}</span>
<div class="badge badge-sm">{ruleProvider.ruleCount}</div>
</div>
<div class="text-xs text-slate-500">
{ruleProvider.vehicleType} / {ruleProvider.behavior} /
{t('updated')} {formatTimeFromNow(ruleProvider.updatedAt)}
</div>
<Button
class="btn-circle btn-sm absolute right-2 top-2 mr-2 h-4"
disabled={updatingMap()[ruleProvider.name]}
onClick={(e) => onUpdateProviderClick(e, ruleProvider.name)}
>
<IconReload
class={twMerge(
updatingMap()[ruleProvider.name] &&
'animate-spin text-success',
)}
/>
</Button>
</div>
)
})}
/>
</Show>
<Show when={activeTab() === ActiveTab.rules}>
<InfiniteScroll
each={renderRules()}
hasMore={renderRules().length < rules().length}
next={() => setMaxRuleRender(maxRuleRender() + 100)}
>
{(rule) => (
<div class="card card-bordered card-compact mb-2 bg-base-200 p-4">
<div class="flex items-center gap-2">
<span class="break-all">{rule.payload}</span>
<Show
when={typeof rule.size === 'number' && rule.size !== -1}
>
<div class="badge badge-sm">{rule.size}</div>
</Show>
</div>
<div class="text-xs text-slate-500">
{rule.type} :: {rule.proxy}
</div>
</div>
)}
</InfiniteScroll>
</Show>
</div>
</div>
)
}

View File

@ -45,13 +45,6 @@ export const [renderInTwoColumns, setRenderInTwoColumns] = makePersisted(
createSignal(true),
{ name: 'renderInTwoColumn', storage: localStorage },
)
export const [
renderRulesAndProviderInTwoColumns,
setRenderRulesAndProviderInTwoColumns,
] = makePersisted(createSignal(true), {
name: 'renderRulesAndProviderInTwoColumns',
storage: localStorage,
})
export const [tableSize, setTableSize] = makePersisted(
createSignal<TAILWINDCSS_SIZE>(TAILWINDCSS_SIZE.XS),
{ name: 'tableSize', storage: localStorage },

View File

@ -5,7 +5,7 @@ import type { Rule, RuleProvider } from '~/types'
export const useRules = () => {
const request = useRequest()
const [rules, setRules] = createSignal<Rule[]>([])
const [rulesProviders, setRulesProviders] = createSignal<RuleProvider[]>([])
const [ruleProviders, setRuleProviders] = createSignal<RuleProvider[]>([])
const updateRules = async () => {
const [{ rules }, { providers }] = await Promise.all([
@ -16,12 +16,12 @@ export const useRules = () => {
])
setRules(Object.values(rules))
setRulesProviders(Object.values(providers))
setRuleProviders(Object.values(providers))
}
const updateAllRuleProvider = async () => {
await Promise.all(
rulesProviders().map((provider) => {
ruleProviders().map((provider) => {
return request.put(`providers/rules/${provider.name}`)
}),
)
@ -35,7 +35,7 @@ export const useRules = () => {
return {
rules,
rulesProviders,
ruleProviders,
updateRules,
updateAllRuleProvider,
updateRuleProviderByName,