Skip to content

Commit

Permalink
feat(connections): tag client source ip with name, closes #181
Browse files Browse the repository at this point in the history
  • Loading branch information
kunish committed Sep 16, 2023
1 parent b2aa358 commit e538f9d
Show file tree
Hide file tree
Showing 10 changed files with 201 additions and 53 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@solid-primitives/clipboard": "^1.5.7",
"@solid-primitives/event-listener": "^2.3.0",
"@solid-primitives/i18n": "^1.4.1",
"@solid-primitives/keyed": "^1.2.0",
"@solid-primitives/media": "^2.2.5",
"@solid-primitives/resize-observer": "^2.0.22",
"@solid-primitives/storage": "^2.1.1",
Expand Down
19 changes: 13 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

125 changes: 117 additions & 8 deletions src/components/ConnectionsSettingsModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { createForm } from '@felte/solid'
import { validator } from '@felte/validator-zod'
import { useI18n } from '@solid-primitives/i18n'
import { IconX } from '@tabler/icons-solidjs'
import type {
DragEventHandler,
Draggable,
Expand All @@ -13,7 +16,9 @@ import {
createSortable,
useDragDropContext,
} from '@thisbeyond/solid-dnd'
import { Component, For, Show, createSignal } from 'solid-js'
import { uniq } from 'lodash'
import { Component, For, Index, Show, createSignal } from 'solid-js'
import { z } from 'zod'
import { Button, ConfigTitle } from '~/components'
import {
CONNECTIONS_TABLE_ACCESSOR_KEY,
Expand All @@ -22,16 +27,87 @@ import {
MODAL,
TAILWINDCSS_SIZE,
} from '~/constants'
import { connectionsTableSize, setConnectionsTableSize } from '~/signals'
import {
allConnections,
clientSourceIPTags,
connectionsTableSize,
setClientSourceIPTags,
setConnectionsTableSize,
} from '~/signals'
import {
ConnectionsTableColumnOrder,
ConnectionsTableColumnVisibility,
} from '~/types'

const TagClientSourceIPWithNameForm: Component = () => {
const schema = z.object({
tagName: z.string().nonempty(),
sourceIP: z.string().nonempty(),
})

const [t] = useI18n()

const { form } = createForm<z.infer<typeof schema>>({
extend: validator({ schema }),
onSubmit: ({ tagName, sourceIP }) =>
setClientSourceIPTags((tags) => {
if (
tags.some(
(tag) => tag.tagName === tagName || tag.sourceIP === sourceIP,
)
) {
return tags
}

return [...tags, { tagName, sourceIP }]
}),
})

return (
<form use:form={form}>
<div class="join flex">
<select name="sourceIP" class="select join-item select-bordered">
<option />

<Index
each={uniq(
allConnections().map(({ metadata: { sourceIP } }) => sourceIP),
)
.sort()
.filter(
(sourceIP) =>
!clientSourceIPTags().some(
({ sourceIP: tagSourceIP }) => tagSourceIP === sourceIP,
),
)}
>
{(sourceIP) => (
<option class="badge" value={sourceIP()}>
{sourceIP()}
</option>
)}
</Index>
</select>

type ColumnVisibility = Partial<Record<CONNECTIONS_TABLE_ACCESSOR_KEY, boolean>>
type ColumnOrder = CONNECTIONS_TABLE_ACCESSOR_KEY[]
<input
name="tagName"
class="input join-item input-bordered min-w-0 flex-1"
placeholder="name"
/>

<Button type="submit" class="join-item">
{t('tag')}
</Button>
</div>
</form>
)
}

export const ConnectionsSettingsModal = (props: {
order: ColumnOrder
visible: ColumnVisibility
onOrderChange: (value: ColumnOrder) => void
onVisibleChange: (value: ColumnVisibility) => void
order: ConnectionsTableColumnOrder
visible: ConnectionsTableColumnVisibility
onOrderChange: (value: ConnectionsTableColumnOrder) => void
onVisibleChange: (value: ConnectionsTableColumnVisibility) => void
}) => {
const [t] = useI18n()
const [activeKey, setActiveKey] =
Expand Down Expand Up @@ -123,6 +199,39 @@ export const ConnectionsSettingsModal = (props: {
</select>
</div>

<div>
<ConfigTitle withDivider>
{t('tagClientSourceIPWithName')}
</ConfigTitle>

<div class="flex flex-col gap-4">
<TagClientSourceIPWithNameForm />

<div class="flex flex-wrap gap-2">
<For each={clientSourceIPTags()}>
{({ tagName, sourceIP }) => (
<div class="badge badge-primary badge-lg items-center gap-2">
<span>
{tagName} - {sourceIP}
</span>

<Button
class="btn-circle btn-ghost btn-xs"
onClick={() =>
setClientSourceIPTags((tags) =>
tags.filter((tag) => tag.tagName !== tagName),
)
}
>
<IconX size={12} />
</Button>
</div>
)}
</For>
</div>
</div>
</div>

<div>
<ConfigTitle withDivider>{t('sort')}</ConfigTitle>

Expand Down
2 changes: 1 addition & 1 deletion src/components/ConnectionsTableDetailsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const ConnectionsTableDetailsModal: Component<{
<pre>
<code>
{JSON.stringify(
allConnections.find(
allConnections().find(
({ id }) => id === props.selectedConnectionID,
),
null,
Expand Down
2 changes: 2 additions & 0 deletions src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,6 @@ export default {
hideUnAvailableProxies: 'Hide UnAvailable Proxies',
reloadConfigFile: 'Reload Config File',
flushFakeIPData: 'Flush Fake-IP Data',
tagClientSourceIPWithName: 'Tag Client Source IP With Name',
tag: 'Tag',
}
2 changes: 2 additions & 0 deletions src/i18n/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,6 @@ export default {
hideUnAvailableProxies: '隐藏不可用节点',
reloadConfigFile: '重新加载配置文件',
flushFakeIPData: '清空 Fake-IP 数据',
tagClientSourceIPWithName: '为客户端源 IP 地址添加名称标记',
tag: '标记',
}
51 changes: 20 additions & 31 deletions src/pages/Connections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,20 @@ import {
ConnectionsSettingsModal,
ConnectionsTableDetailsModal,
} from '~/components'
import {
CONNECTIONS_TABLE_ACCESSOR_KEY,
CONNECTIONS_TABLE_INITIAL_COLUMN_ORDER,
CONNECTIONS_TABLE_INITIAL_COLUMN_VISIBILITY,
MODAL,
} from '~/constants'
import { CONNECTIONS_TABLE_ACCESSOR_KEY, MODAL } from '~/constants'
import { formatTimeFromNow } from '~/helpers'
import {
clientSourceIPTags,
connectionsTableColumnOrder,
connectionsTableColumnVisibility,
connectionsTableSize,
setConnectionsTableColumnOrder,
setConnectionsTableColumnVisibility,
tableSizeClassName,
useConnections,
} from '~/signals'
import type { Connection } from '~/types'

type ColumnVisibility = Partial<Record<CONNECTIONS_TABLE_ACCESSOR_KEY, boolean>>
type ColumnOrder = CONNECTIONS_TABLE_ACCESSOR_KEY[]

enum ActiveTab {
activeConnections,
closedConnections,
Expand All @@ -79,20 +76,6 @@ export default () => {
useConnections()

const [globalFilter, setGlobalFilter] = createSignal('')
const [columnVisibility, setColumnVisibility] = makePersisted(
createSignal<ColumnVisibility>(CONNECTIONS_TABLE_INITIAL_COLUMN_VISIBILITY),
{
name: 'columnVisibility',
storage: localStorage,
},
)
const [columnOrder, setColumnOrder] = makePersisted(
createSignal<ColumnOrder>(CONNECTIONS_TABLE_INITIAL_COLUMN_ORDER),
{
name: 'columnOrder',
storage: localStorage,
},
)

const [selectedConnectionID, setSelectedConnectionID] = createSignal<string>()

Expand Down Expand Up @@ -227,7 +210,13 @@ export default () => {
{
header: () => t('sourceIP'),
accessorKey: CONNECTIONS_TABLE_ACCESSOR_KEY.SourceIP,
accessorFn: (original) => original.metadata.sourceIP,
accessorFn: (original) => {
const tag = clientSourceIPTags().find(
(tag) => tag.sourceIP === original.metadata.sourceIP,
)

return tag ? tag.tagName : original.metadata.sourceIP
},
},
{
header: () => t('sourcePort'),
Expand Down Expand Up @@ -258,7 +247,7 @@ export default () => {
},
state: {
get columnOrder() {
return columnOrder()
return connectionsTableColumnOrder()
},
get grouping() {
return grouping()
Expand All @@ -267,7 +256,7 @@ export default () => {
return sorting()
},
get columnVisibility() {
return columnVisibility()
return connectionsTableColumnVisibility()
},
get globalFilter() {
return globalFilter()
Expand Down Expand Up @@ -494,11 +483,11 @@ export default () => {
</div>

<ConnectionsSettingsModal
order={columnOrder()}
visible={columnVisibility()}
onOrderChange={(data: ColumnOrder) => setColumnOrder(data)}
onVisibleChange={(data: ColumnVisibility) =>
setColumnVisibility({ ...data })
order={connectionsTableColumnOrder()}
visible={connectionsTableColumnVisibility()}
onOrderChange={(data) => setConnectionsTableColumnOrder(data)}
onVisibleChange={(data) =>
setConnectionsTableColumnVisibility({ ...data })
}
/>

Expand Down
35 changes: 35 additions & 0 deletions src/signals/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { usePrefersDark } from '@solid-primitives/media'
import { makePersisted } from '@solid-primitives/storage'
import { createEffect, createSignal } from 'solid-js'
import {
CONNECTIONS_TABLE_INITIAL_COLUMN_ORDER,
CONNECTIONS_TABLE_INITIAL_COLUMN_VISIBILITY,
LATENCY_QUALITY_MAP_HTTP,
LATENCY_QUALITY_MAP_HTTPS,
LOG_LEVEL,
Expand All @@ -10,6 +12,10 @@ import {
TAILWINDCSS_SIZE,
} from '~/constants'
import { setCurTheme } from '~/signals'
import {
ConnectionsTableColumnOrder,
ConnectionsTableColumnVisibility,
} from '~/types'

export const [proxiesPreviewType, setProxiesPreviewType] = makePersisted(
createSignal(PROXIES_PREVIEW_TYPE.Auto),
Expand Down Expand Up @@ -54,6 +60,35 @@ export const [connectionsTableSize, setConnectionsTableSize] = makePersisted(
createSignal<TAILWINDCSS_SIZE>(TAILWINDCSS_SIZE.XS),
{ name: 'connectionsTableSize', storage: localStorage },
)
export const [
connectionsTableColumnVisibility,
setConnectionsTableColumnVisibility,
] = makePersisted(
createSignal<ConnectionsTableColumnVisibility>(
CONNECTIONS_TABLE_INITIAL_COLUMN_VISIBILITY,
),
{
name: 'connectionsTableColumnVisibility',
storage: localStorage,
},
)
export const [connectionsTableColumnOrder, setConnectionsTableColumnOrder] =
makePersisted(
createSignal<ConnectionsTableColumnOrder>(
CONNECTIONS_TABLE_INITIAL_COLUMN_ORDER,
),
{
name: 'connectionsTableColumnOrder',
storage: localStorage,
},
)
export const [clientSourceIPTags, setClientSourceIPTags] = makePersisted(
createSignal<{ tagName: string; sourceIP: string }[]>([]),
{
name: 'clientSourceIPTags',
storage: localStorage,
},
)
export const [logsTableSize, setLogsTableSize] = makePersisted(
createSignal<TAILWINDCSS_SIZE>(TAILWINDCSS_SIZE.XS),
{ name: 'logsTableSize', storage: localStorage },
Expand Down
Loading

0 comments on commit e538f9d

Please sign in to comment.