Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add description text for group policies #71

Merged
merged 1 commit into from
Jun 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 22 additions & 18 deletions src/components/ConfigFormModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ export const ConfigFormDrawer = forwardRef(({ opened, onClose }: { opened: boole
<Stack>
<NumberInput
label={t('tproxyPort')}
description={t('descriptions.tproxyPort')}
description={t('descriptions.config.tproxyPort')}
withAsterisk
min={0}
max={65535}
Expand All @@ -271,7 +271,7 @@ export const ConfigFormDrawer = forwardRef(({ opened, onClose }: { opened: boole

<Checkbox
label={t('tproxyPortProtect')}
description={t('descriptions.tproxyPortProtect')}
description={t('descriptions.config.tproxyPortProtect')}
{...form.getInputProps('tproxyPortProtect', {
type: 'checkbox',
})}
Expand All @@ -294,7 +294,7 @@ export const ConfigFormDrawer = forwardRef(({ opened, onClose }: { opened: boole

<Checkbox
label={t('disableWaitingNetwork')}
description={t('descriptions.disableWaitingNetwork')}
description={t('descriptions.config.disableWaitingNetwork')}
{...form.getInputProps('disableWaitingNetwork', {
type: 'checkbox',
})}
Expand All @@ -312,22 +312,22 @@ export const ConfigFormDrawer = forwardRef(({ opened, onClose }: { opened: boole
<Stack>
<MultiSelect
label={t('lanInterface')}
description={t('descriptions.lanInterface')}
description={t('descriptions.config.lanInterface')}
data={lanInterfacesData}
{...form.getInputProps('lanInterface')}
/>

<MultiSelect
label={t('wanInterface')}
description={t('descriptions.wanInterface')}
description={t('descriptions.config.wanInterface')}
withAsterisk
data={wanInterfacesData}
{...form.getInputProps('wanInterface')}
/>

<Checkbox
label={t('autoConfigKernelParameter')}
description={t('descriptions.autoConfigKernelParameter')}
description={t('descriptions.config.autoConfigKernelParameter')}
{...form.getInputProps('autoConfigKernelParameter', {
type: 'checkbox',
})}
Expand All @@ -346,14 +346,14 @@ export const ConfigFormDrawer = forwardRef(({ opened, onClose }: { opened: boole
<InputList
form={form}
label={t('tcpCheckUrl')}
description={t('descriptions.tcpCheckUrl')}
description={t('descriptions.config.tcpCheckUrl')}
fieldName="tcpCheckUrl"
values={form.values.tcpCheckUrl}
/>

<Select
label={t('tcpCheckHttpMethod')}
description={t('descriptions.tcpCheckHttpMethod')}
description={t('descriptions.config.tcpCheckHttpMethod')}
data={Object.values(TcpCheckHttpMethod).map((tcpCheckHttpMethod) => ({
label: tcpCheckHttpMethod,
value: tcpCheckHttpMethod,
Expand All @@ -364,7 +364,7 @@ export const ConfigFormDrawer = forwardRef(({ opened, onClose }: { opened: boole
<InputList
form={form}
label={t('udpCheckDns')}
description={t('descriptions.udpCheckDns')}
description={t('descriptions.config.udpCheckDns')}
fieldName="udpCheckDns"
values={form.values.udpCheckDns}
/>
Expand All @@ -377,7 +377,7 @@ export const ConfigFormDrawer = forwardRef(({ opened, onClose }: { opened: boole

<NumberInput
label={`${t('checkTolerance')} (ms)`}
description={t('descriptions.checkTolerance')}
description={t('descriptions.config.checkTolerance')}
withAsterisk
step={500}
{...form.getInputProps('checkToleranceMS')}
Expand All @@ -395,43 +395,47 @@ export const ConfigFormDrawer = forwardRef(({ opened, onClose }: { opened: boole
<Stack>
<Radio.Group label={t('dialMode')} {...form.getInputProps('dialMode')}>
<Group mt="xs">
<Radio value={DialMode.ip} label={DialMode.ip} description={t('descriptions.dialMode.ip')} />
<Radio
value={DialMode.ip}
label={DialMode.ip}
description={t('descriptions.config.dialMode.ip')}
/>
<Radio
value={DialMode.domain}
label={DialMode.domain}
description={t('descriptions.dialMode.domain')}
description={t('descriptions.config.dialMode.domain')}
/>
<Radio
value={DialMode.domainP}
label={DialMode.domainP}
description={t('descriptions.dialMode.domain+')}
description={t('descriptions.config.dialMode.domain+')}
/>
<Radio
value={DialMode.domainPP}
label={DialMode.domainPP}
description={t('descriptions.dialMode.domain++')}
description={t('descriptions.config.dialMode.domain++')}
/>
</Group>
</Radio.Group>

<Checkbox
label={t('allowInsecure')}
description={t('descriptions.allowInsecure')}
description={t('descriptions.config.allowInsecure')}
{...form.getInputProps('allowInsecure', {
type: 'checkbox',
})}
/>

<NumberInput
label={`${t('sniffingTimeout')} (ms)`}
description={t('descriptions.sniffingTimeout')}
description={t('descriptions.config.sniffingTimeout')}
step={500}
{...form.getInputProps('sniffingTimeoutMS')}
/>

<Select
label={t('tlsImplementation')}
description={t('descriptions.tlsImplementation')}
description={t('descriptions.config.tlsImplementation')}
data={Object.values(TLSImplementation).map((tlsImplementation) => ({
label: tlsImplementation,
value: tlsImplementation,
Expand All @@ -442,7 +446,7 @@ export const ConfigFormDrawer = forwardRef(({ opened, onClose }: { opened: boole
{form.values.tlsImplementation === TLSImplementation.utls && (
<Select
label={t('utlsImitate')}
description={t('descriptions.utlsImitate')}
description={t('descriptions.config.utlsImitate')}
data={Object.values(UTLSImitate).map((utlsImitate) => ({
label: utlsImitate,
value: utlsImitate,
Expand Down
31 changes: 27 additions & 4 deletions src/components/GroupFormModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { FormActions } from '~/components/FormActions'
import { DEFAULT_GROUP_POLICY } from '~/constants'
import { Policy } from '~/schemas/gql/graphql'

import { SelectItemWithDescription } from './SelectItemWithDescription'

const schema = z.object({
name: z.string().nonempty(),
policy: z.nativeEnum(Policy),
Expand Down Expand Up @@ -46,6 +48,29 @@ export const GroupFormModal = forwardRef(({ opened, onClose }: { opened: boolean
const createGroupMutation = useCreateGroupMutation()
const groupSetPolicyMutation = useGroupSetPolicyMutation()

const policyData = [
{
label: Policy.MinMovingAvg,
value: Policy.MinMovingAvg,
description: t('descriptions.group.MinMovingAvg'),
},
{
label: Policy.MinAvg10,
value: Policy.MinAvg10,
description: t('descriptions.group.MinAvg10'),
},
{
label: Policy.Min,
value: Policy.Min,
description: t('descriptions.group.Min'),
},
{
label: Policy.Random,
value: Policy.Random,
description: t('descriptions.group.Random'),
},
]

return (
<Modal title={t('group')} opened={opened} onClose={onClose}>
<form
Expand Down Expand Up @@ -73,10 +98,8 @@ export const GroupFormModal = forwardRef(({ opened, onClose }: { opened: boolean
<Select
label={t('policy')}
dropdownPosition="bottom"
data={Object.values(Policy).map((policy) => ({
label: policy,
value: policy,
}))}
itemComponent={SelectItemWithDescription}
data={policyData}
{...form.getInputProps('policy')}
/>

Expand Down
16 changes: 16 additions & 0 deletions src/components/SelectItemWithDescription.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Input, Stack, Text } from '@mantine/core'
import { forwardRef } from 'react'

interface SelectItemWithDescriptionProps extends React.ComponentPropsWithoutRef<'div'> {
label: React.ReactNode
description: React.ReactNode
}

export const SelectItemWithDescription = forwardRef<HTMLDivElement, SelectItemWithDescriptionProps>(
({ label, description, ...props }, ref) => (
<Stack ref={ref} spacing={4} {...props}>
<Text>{label}</Text>
<Input.Description>{description}</Input.Description>
</Stack>
)
)
46 changes: 27 additions & 19 deletions src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,26 +49,34 @@
"dark mode": "Dark Mode",
"debug": "debug",
"descriptions": {
"allowInsecure": "Allow insecure TLS certificates. It is not recommended to turn it on unless you have to.",
"autoConfigKernelParameter": "Automatically configure Linux kernel parameters like ip_forward and send_redirects.",
"checkTolerance": "Group will switch node only when new_latency <= old_latency - tolerance.",
"dialMode": {
"domain": "Dial proxy using the domain from sniffing. This will relieve DNS pollution problem to a great extent if have impure DNS environment. Generally, this mode brings faster proxy response time because proxy will re-resolve the domain in remote, thus get better IP result to connect. This policy does not impact routing. That is to say, domain rewrite will be after traffic split of routing and dae will not re-route it.",
"domain+": "Based on domain mode but do not check the reality of sniffed domain. It is useful for users whose DNS requests do not go through dae but want faster proxy response time. Notice that, if DNS requests do not go through dae, dae cannot split traffic by domain.",
"domain++": "Based on domain+ mode but force to re-route traffic using sniffed domain to partially recover domain based traffic split ability. It doesn't work for direct traffic and consumes more CPU resources.",
"ip": "Dial proxy using the IP from DNS directly. This allows your ipv4, ipv6 to choose the optimal path respectively, and makes the IP version requested by the application meet expectations. For example, if you use curl -4 ip.sb, you will request IPv4 via proxy and get a IPv4 echo. And curl -6 ip.sb will request IPv6. This may solve some wierd full-cone problem if your are be your node support that. Sniffing will be disabled in this mode."
"config": {
"allowInsecure": "Allow insecure TLS certificates. It is not recommended to turn it on unless you have to.",
"autoConfigKernelParameter": "Automatically configure Linux kernel parameters like ip_forward and send_redirects.",
"checkTolerance": "Group will switch node only when new_latency <= old_latency - tolerance.",
"dialMode": {
"domain": "Dial proxy using the domain from sniffing. This will relieve DNS pollution problem to a great extent if have impure DNS environment. Generally, this mode brings faster proxy response time because proxy will re-resolve the domain in remote, thus get better IP result to connect. This policy does not impact routing. That is to say, domain rewrite will be after traffic split of routing and dae will not re-route it.",
"domain+": "Based on domain mode but do not check the reality of sniffed domain. It is useful for users whose DNS requests do not go through dae but want faster proxy response time. Notice that, if DNS requests do not go through dae, dae cannot split traffic by domain.",
"domain++": "Based on domain+ mode but force to re-route traffic using sniffed domain to partially recover domain based traffic split ability. It doesn't work for direct traffic and consumes more CPU resources.",
"ip": "Dial proxy using the IP from DNS directly. This allows your ipv4, ipv6 to choose the optimal path respectively, and makes the IP version requested by the application meet expectations. For example, if you use curl -4 ip.sb, you will request IPv4 via proxy and get a IPv4 echo. And curl -6 ip.sb will request IPv6. This may solve some wierd full-cone problem if your are be your node support that. Sniffing will be disabled in this mode."
},
"disableWaitingNetwork": "Disable waiting for network before pulling subscriptions.",
"lanInterface": "The LAN interface to bind. Use it if you want to proxy LAN.",
"sniffingTimeout": "Timeout to waiting for first data sending for sniffing. It is always 0 if dial_mode is ip. Set it higher is useful in high latency LAN network.",
"tcpCheckHttpMethod": "The HTTP request method to TCP Check HTTP Method. Use HEAD by default because some server implementations bypass accounting for this kind of traffic.",
"tcpCheckUrl": "Host of URL should have both IPv4 and IPv6 if you have double stack in local. First is URL, others are IP addresses if given. Considering traffic consumption, it is recommended to choose a site with anycast IP and less response.",
"tlsImplementation": "TLS implementation. tls is to use Go's crypto/tls. utls is to use uTLS, which can imitate browser's Client Hello.",
"tproxyPort": "Transparent Proxy Port to listen on. Valid range is 0 - 65535. It is NOT a HTTP/SOCKS port, and is just used by eBPF program. In normal case, you do not need to use it.",
"tproxyPortProtect": "Set it true to protect tproxy port from unsolicited traffic. Set it false to allow users to use self-managed iptables tproxy rules.",
"udpCheckDns": "This DNS will be used to check UDP connectivity of nodes. And if dns_upstream below contains tcp, it also be used to check TCP DNS connectivity of nodes. First is URL, others are IP addresses if given. This DNS should have both IPv4 and IPv6 if you have double stack in local.",
"utlsImitate": "The Client Hello ID for uTLS to imitate. This takes effect only if tls_implementation is utls.",
"wanInterface": "The WAN interface to bind. Use it if you want to proxy localhost."
},
"disableWaitingNetwork": "Disable waiting for network before pulling subscriptions.",
"lanInterface": "The LAN interface to bind. Use it if you want to proxy LAN.",
"sniffingTimeout": "Timeout to waiting for first data sending for sniffing. It is always 0 if dial_mode is ip. Set it higher is useful in high latency LAN network.",
"tcpCheckHttpMethod": "The HTTP request method to TCP Check HTTP Method. Use HEAD by default because some server implementations bypass accounting for this kind of traffic.",
"tcpCheckUrl": "Host of URL should have both IPv4 and IPv6 if you have double stack in local. First is URL, others are IP addresses if given. Considering traffic consumption, it is recommended to choose a site with anycast IP and less response.",
"tlsImplementation": "TLS implementation. tls is to use Go's crypto/tls. utls is to use uTLS, which can imitate browser's Client Hello.",
"tproxyPort": "Transparent Proxy Port to listen on. Valid range is 0 - 65535. It is NOT a HTTP/SOCKS port, and is just used by eBPF program. In normal case, you do not need to use it.",
"tproxyPortProtect": "Set it true to protect tproxy port from unsolicited traffic. Set it false to allow users to use self-managed iptables tproxy rules.",
"udpCheckDns": "This DNS will be used to check UDP connectivity of nodes. And if dns_upstream below contains tcp, it also be used to check TCP DNS connectivity of nodes. First is URL, others are IP addresses if given. This DNS should have both IPv4 and IPv6 if you have double stack in local.",
"utlsImitate": "The Client Hello ID for uTLS to imitate. This takes effect only if tls_implementation is utls.",
"wanInterface": "The WAN interface to bind. Use it if you want to proxy localhost."
"group": {
"Min": "Select the node with min last latency from the group for every connection",
"MinAvg10": "Select the node with min average of the last 10 latencies from the group for every connection",
"MinMovingAvg": "Select the node with min moving average of latencies from the group for every connection",
"Random": "Randomly select a node from the group for every connection"
}
},
"dialMode": "Dial Mode",
"disableWaitingNetwork": "Disable Waiting Network",
Expand Down
Loading