feat: quick filter for connections (#856)

* feat: quick filter for connections

* feat: make persisted for collapse map status

* fix: config error when tun is disabled in sing-box
This commit is contained in:
YetAnotherZephyruso 2024-07-24 20:40:21 +08:00 committed by GitHub
parent b419bed6b1
commit 916a661011
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 81 additions and 16 deletions

View File

@ -31,8 +31,10 @@ import {
allConnections,
clientSourceIPTags,
connectionsTableSize,
quickFilterRegex,
setClientSourceIPTags,
setConnectionsTableSize,
setQuickFilterRegex,
} from '~/signals'
import {
ConnectionsTableColumnOrder,
@ -205,6 +207,16 @@ export const ConnectionsSettingsModal = (props: {
}
>
<div class="flex flex-col gap-4">
<div>
<ConfigTitle withDivider>{t('quickFilter')}</ConfigTitle>
<input
type="text"
class="input input-bordered w-full"
onInput={(e) => setQuickFilterRegex(e.target.value)}
value={quickFilterRegex()}
></input>
</div>
<div>
<ConfigTitle withDivider>{t('tableSize')}</ConfigTitle>

View File

@ -112,4 +112,5 @@ export default {
en: 'English',
zh: 'Chinese',
port: '{{ name }} Port',
quickFilter: 'Quick Filter',
}

View File

@ -114,4 +114,5 @@ export default {
en: '英文',
zh: '中文',
port: '{{ name }} 端口',
quickFilter: '快速过滤',
} satisfies Dict

View File

@ -244,7 +244,7 @@ const ConfigForm: Component<{ backendVersion: Accessor<string> }> = ({
id="enable-tun-device"
type="checkbox"
class="toggle"
checked={configsData()?.tun.enable}
checked={configsData()?.tun?.enable}
onChange={(e) =>
void updateBackendConfigAPI(
'tun',
@ -263,7 +263,7 @@ const ConfigForm: Component<{ backendVersion: Accessor<string> }> = ({
<select
id="tun-ip-stack"
class="select select-bordered flex-1"
value={configsData()?.tun.stack}
value={configsData()?.tun?.stack}
onChange={(e) =>
void updateBackendConfigAPI(
'tun',
@ -287,7 +287,7 @@ const ConfigForm: Component<{ backendVersion: Accessor<string> }> = ({
<input
id="device-name"
class="input input-bordered min-w-0"
value={configsData()?.tun.device}
value={configsData()?.tun?.device}
onChange={(e) =>
void updateBackendConfigAPI(
'tun',

View File

@ -45,6 +45,7 @@ import {
connectionsTableSize,
endpoint,
formatTimeFromNow,
quickFilterRegex,
setConnectionsTableColumnOrder,
setConnectionsTableColumnVisibility,
tableSizeClassName,
@ -89,7 +90,13 @@ export default () => {
useConnections()
const [globalFilter, setGlobalFilter] = createSignal('')
const [enableQuickFilter, setEnableQuickFilter] = makePersisted(
createSignal(false),
{
name: 'enableQuickFilter',
storage: localStorage,
},
)
const [selectedConnectionID, setSelectedConnectionID] = createSignal<string>()
const columns: ColumnDef<Connection>[] = [
@ -283,9 +290,24 @@ export default () => {
},
},
get data() {
return activeTab() === ActiveTab.activeConnections
const connections =
activeTab() === ActiveTab.activeConnections
? activeConnections()
: closedConnections()
connections.sort((a, b) => {
return a.id.localeCompare(b.id)
})
if (!enableQuickFilter()) {
return connections
}
const reg = new RegExp(quickFilterRegex(), 'i')
return connections.filter(
(connection) => !reg.test(connection.chains.join('')),
)
},
sortDescFirst: true,
enableHiding: true,
@ -353,6 +375,16 @@ export default () => {
</Index>
</div>
<div class="flex items-center">
<span class="mr-2 hidden lg:inline-block">{t('quickFilter')}:</span>
<input
type="checkbox"
class="toggle"
checked={enableQuickFilter()}
onChange={(e) => setEnableQuickFilter(e.target.checked)}
/>
</div>
<select
class="select select-bordered select-primary select-sm w-full max-w-full flex-1 sm:select-md"
onChange={(e) => setSourceIPFilter(e.target.value)}

View File

@ -87,8 +87,8 @@ export default () => {
])
return (
<div class="flex flex-col gap-2">
<div class="stats stats-vertical w-full grid-cols-2 bg-primary shadow lg:stats-horizontal lg:flex">
<div class="flex flex-col gap-2 lg:h-full">
<div class="stats stats-vertical w-full flex-shrink-0 grid-cols-2 bg-gradient-to-br from-primary to-secondary shadow lg:stats-horizontal lg:flex">
<TrafficWidget label={t('upload')}>
{byteSize(traffic()?.up || 0).toString()}/s
</TrafficWidget>

View File

@ -1,3 +1,4 @@
import { makePersisted } from '@solid-primitives/storage'
import {
IconBrandSpeedtest,
IconReload,
@ -55,14 +56,24 @@ export default () => {
updateAllProvider,
proxyGroupLatencyTest,
proxyProviderLatencyTest,
collapsedMap,
setCollapsedMap,
proxyGroupLatencyTestingMap,
proxyProviderLatencyTestingMap,
isAllProviderUpdating,
updatingMap,
} = useProxies()
const [collapsedMap, setCollapsedMap] = makePersisted(
createSignal<Record<string, boolean>>({}),
{
name: 'collapsedMap',
storage: localStorage,
},
)
const setCollapsedMapByKey = (key: string, value: boolean) => {
setCollapsedMap((prev) => ({ ...prev, [key]: value }))
}
onMount(fetchProxies)
const onProxyGroupLatencyTestClick = async (
@ -221,7 +232,9 @@ export default () => {
<Collapse
isOpen={collapsedMap()[proxyGroup.name]}
title={title}
onCollapse={(val) => setCollapsedMap(proxyGroup.name, val)}
onCollapse={(val) =>
setCollapsedMapByKey(proxyGroup.name, val)
}
>
<For each={sortedProxyNames()}>
{(proxyName) => (
@ -330,7 +343,7 @@ export default () => {
isOpen={collapsedMap()[proxyProvider.name]}
title={title}
onCollapse={(val) =>
setCollapsedMap(proxyProvider.name, val)
setCollapsedMapByKey(proxyProvider.name, val)
}
>
<For each={sortedProxyNames()}>

View File

@ -1,3 +1,4 @@
import { makePersisted } from '@solid-primitives/storage'
import { differenceWith, isNumber, unionWith } from 'lodash'
import { CONNECTIONS_TABLE_MAX_CLOSED_ROWS } from '~/constants'
import { Connection, ConnectionRawMessage } from '~/types'
@ -8,6 +9,14 @@ export type WsMsg = {
downloadTotal: number
} | null
export const [quickFilterRegex, setQuickFilterRegex] = makePersisted(
createSignal<string>('Direct|direct|dns-out'),
{
name: 'quickFilterRegex',
storage: localStorage,
},
)
// we make connections global, so we can keep track of connections when user in proxy page
// when user selects proxy and close some connections they can back and check connections
// they closed

View File

@ -32,7 +32,6 @@ type ProxyInfo = {
export type ProxyWithProvider = Proxy & { provider?: string }
export type ProxyNodeWithProvider = ProxyNode & { provider?: string }
const { map: collapsedMap, set: setCollapsedMap } = useStringBooleanMap()
const {
map: proxyLatencyTestingMap,
setWithCallback: setProxyLatencyTestingMap,
@ -322,8 +321,6 @@ export const useProxies = () => {
})
return {
collapsedMap,
setCollapsedMap,
proxyIPv6SupportMap,
proxyLatencyTestingMap,
proxyGroupLatencyTestingMap,