mirror of
https://github.com/MetaCubeX/metacubexd.git
synced 2024-12-26 19:24:12 +08:00
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:
parent
b419bed6b1
commit
916a661011
@ -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>
|
||||
|
||||
|
@ -112,4 +112,5 @@ export default {
|
||||
en: 'English',
|
||||
zh: 'Chinese',
|
||||
port: '{{ name }} Port',
|
||||
quickFilter: 'Quick Filter',
|
||||
}
|
||||
|
@ -114,4 +114,5 @@ export default {
|
||||
en: '英文',
|
||||
zh: '中文',
|
||||
port: '{{ name }} 端口',
|
||||
quickFilter: '快速过滤',
|
||||
} satisfies Dict
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
? activeConnections()
|
||||
: closedConnections()
|
||||
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)}
|
||||
|
@ -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>
|
||||
|
@ -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()}>
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user