Bläddra i källkod

feat(frontend): protocol tab Shadowsocks section (Pattern A)

Adds the Shadowsocks sub-form: method picker (from SSMethodSchema's
seven schema-aligned options), conditional password input gated on
isSS2022, network picker (tcp/udp/tcp,udp), ivCheck toggle.

Method change cascades through the Select's onChange — regenerating
the inbound-level password via RandomUtil.randomShadowsocksPassword.
The shadowsockses[] multi-user list reset is deferred until the
clients-management section lands.

Uses isSS2022 from lib/xray/protocol-capabilities to gate the password
field exactly the way the legacy modal did — keeps the form behavior
identical without referencing the legacy class.

SSMethodSchema.options drives the Select rather than the legacy
SSMethods const (which the inbound modal pulled from models/inbound.ts).
This commits to the schema-aligned 7-entry list for inbound; the
outbound divergence (9 entries with legacy aliases) is still pending
in OutboundFormModal — defer the UX decision to that rewrite.
MHSanaei 23 timmar sedan
förälder
incheckning
591a03ff96
1 ändrade filer med 64 tillägg och 1 borttagningar
  1. 64 1
      frontend/src/pages/inbounds/InboundFormModal.new.tsx

+ 64 - 1
frontend/src/pages/inbounds/InboundFormModal.new.tsx

@@ -16,6 +16,7 @@ import {
   Typography,
   message,
 } from 'antd';
+import { SyncOutlined } from '@ant-design/icons';
 
 import { HttpUtil, NumberFormatter, RandomUtil, SizeFormatter } from '@/utils';
 import {
@@ -23,6 +24,8 @@ import {
   formValuesToWirePayload,
 } from '@/lib/xray/inbound-form-adapter';
 import { createDefaultInboundSettings } from '@/lib/xray/inbound-defaults';
+import { isSS2022 } from '@/lib/xray/protocol-capabilities';
+import { SSMethodSchema } from '@/schemas/protocols/inbound/shadowsocks';
 import {
   InboundFormBaseSchema,
   InboundFormSchema,
@@ -95,6 +98,11 @@ export default function InboundFormModalNew({
   const isNodeEligible = NODE_ELIGIBLE_PROTOCOLS.has(protocol);
   const sniffingEnabled = Form.useWatch(['sniffing', 'enabled'], form) ?? false;
   const vlessEncryption = Form.useWatch(['settings', 'encryption'], form) ?? '';
+  const ssMethod = Form.useWatch(['settings', 'method'], form);
+  const isSSWith2022 = isSS2022({
+    protocol,
+    settings: typeof ssMethod === 'string' ? { method: ssMethod } : {},
+  });
 
   const matchesVlessAuth = (
     block: { id?: string; label?: string } | undefined | null,
@@ -326,6 +334,61 @@ export default function InboundFormModalNew({
 
   const protocolTab = (
     <>
+      {protocol === Protocols.SHADOWSOCKS && (
+        <>
+          <Form.Item name={['settings', 'method']} label="Encryption method">
+            <Select
+              onChange={(v) => {
+                form.setFieldValue(
+                  ['settings', 'password'],
+                  RandomUtil.randomShadowsocksPassword(v as string),
+                );
+              }}
+            >
+              {SSMethodSchema.options.map((m) => (
+                <Select.Option key={m} value={m}>{m}</Select.Option>
+              ))}
+            </Select>
+          </Form.Item>
+          {isSSWith2022 && (
+            <Form.Item
+              name={['settings', 'password']}
+              label={
+                <>
+                  Password{' '}
+                  <SyncOutlined
+                    className="random-icon"
+                    onClick={() => {
+                      const method = form.getFieldValue(['settings', 'method']);
+                      form.setFieldValue(
+                        ['settings', 'password'],
+                        RandomUtil.randomShadowsocksPassword(method as string),
+                      );
+                    }}
+                  />
+                </>
+              }
+            >
+              <Input />
+            </Form.Item>
+          )}
+          <Form.Item name={['settings', 'network']} label="Network">
+            <Select style={{ width: 120 }}>
+              <Select.Option value="tcp,udp">TCP, UDP</Select.Option>
+              <Select.Option value="tcp">TCP</Select.Option>
+              <Select.Option value="udp">UDP</Select.Option>
+            </Select>
+          </Form.Item>
+          <Form.Item
+            name={['settings', 'ivCheck']}
+            label="ivCheck"
+            valuePropName="checked"
+          >
+            <Switch />
+          </Form.Item>
+        </>
+      )}
+
       {protocol === Protocols.VLESS && (
         <>
           <Form.Item name={['settings', 'decryption']} label={t('pages.inbounds.decryption')}>
@@ -437,7 +500,7 @@ export default function InboundFormModalNew({
         >
           <Tabs items={[
             { key: 'basic', label: t('pages.xray.basicTemplate'), children: basicTab },
-            ...(protocol === Protocols.VLESS
+            ...(protocol === Protocols.VLESS || protocol === Protocols.SHADOWSOCKS
               ? [{ key: 'protocol', label: t('pages.inbounds.protocol'), children: protocolTab }]
               : []),
             { key: 'sniffing', label: t('pages.inbounds.sniffingTab'), children: sniffingTab },