HostFinalMaskForm.tsx 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. import { useEffect, useRef, useState } from 'react';
  2. import { Form } from 'antd';
  3. import { FinalMaskForm } from '@/lib/xray/forms/transport';
  4. import type { FinalMaskStreamSettings } from '@/schemas/protocols/stream/finalmask';
  5. // Per-host Final Mask editor — same shape as the sub-JSON settings one
  6. // (SubJsonFinalMaskForm) but reused for a host: reads/writes the host's
  7. // finalMask JSON string. The masks are merged into this host's JSON stream.
  8. function hasValue(v: unknown): boolean {
  9. if (v == null) return false;
  10. if (Array.isArray(v)) return v.some(hasValue);
  11. if (typeof v === 'object') return Object.values(v as Record<string, unknown>).some(hasValue);
  12. if (typeof v === 'string') return v.length > 0;
  13. return true;
  14. }
  15. function parseFinalMask(raw: string): FinalMaskStreamSettings {
  16. try {
  17. if (raw) return JSON.parse(raw) as FinalMaskStreamSettings;
  18. } catch {
  19. return { tcp: [], udp: [] };
  20. }
  21. return { tcp: [], udp: [] };
  22. }
  23. export default function HostFinalMaskForm({
  24. value = '',
  25. onChange,
  26. }: {
  27. value?: string;
  28. onChange?: (next: string) => void;
  29. }) {
  30. const [form] = Form.useForm();
  31. const [initial] = useState(() => parseFinalMask(value));
  32. const onChangeRef = useRef(onChange);
  33. useEffect(() => {
  34. onChangeRef.current = onChange;
  35. });
  36. const finalmask = Form.useWatch('finalmask', form) as FinalMaskStreamSettings | undefined;
  37. useEffect(() => {
  38. if (finalmask === undefined) return;
  39. const next = hasValue(finalmask) ? JSON.stringify(finalmask) : '';
  40. if (next !== value) onChangeRef.current?.(next);
  41. }, [finalmask, value]);
  42. return (
  43. <Form
  44. form={form}
  45. component={false}
  46. colon={false}
  47. labelCol={{ sm: { span: 8 } }}
  48. wrapperCol={{ sm: { span: 14 } }}
  49. labelWrap
  50. initialValues={{ finalmask: initial }}
  51. >
  52. <FinalMaskForm name="finalmask" network="" protocol="" form={form} showAll />
  53. </Form>
  54. );
  55. }