code formatting with prettier
This commit is contained in:
@@ -34,7 +34,6 @@ import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { AlertTriangle, RotateCcw, Code } from "lucide-react";
|
||||
|
||||
|
||||
const DEFAULT_DNS_CONFIG = {
|
||||
enable: true,
|
||||
listen: ":53",
|
||||
@@ -46,15 +45,44 @@ const DEFAULT_DNS_CONFIG = {
|
||||
"use-hosts": false,
|
||||
"use-system-hosts": false,
|
||||
ipv6: true,
|
||||
"fake-ip-filter": ["*.lan", "*.local", "*.arpa", "time.*.com", "ntp.*.com", "+.market.xiaomi.com", "localhost.ptlogin2.qq.com", "*.msftncsi.com", "www.msftconnecttest.com"],
|
||||
"default-nameserver": ["system", "223.6.6.6", "8.8.8.8", "2400:3200::1", "2001:4860:4860::8888"],
|
||||
nameserver: ["8.8.8.8", "https://doh.pub/dns-query", "https://dns.alidns.com/dns-query"],
|
||||
"fake-ip-filter": [
|
||||
"*.lan",
|
||||
"*.local",
|
||||
"*.arpa",
|
||||
"time.*.com",
|
||||
"ntp.*.com",
|
||||
"+.market.xiaomi.com",
|
||||
"localhost.ptlogin2.qq.com",
|
||||
"*.msftncsi.com",
|
||||
"www.msftconnecttest.com",
|
||||
],
|
||||
"default-nameserver": [
|
||||
"system",
|
||||
"223.6.6.6",
|
||||
"8.8.8.8",
|
||||
"2400:3200::1",
|
||||
"2001:4860:4860::8888",
|
||||
],
|
||||
nameserver: [
|
||||
"8.8.8.8",
|
||||
"https://doh.pub/dns-query",
|
||||
"https://dns.alidns.com/dns-query",
|
||||
],
|
||||
fallback: [],
|
||||
"nameserver-policy": {},
|
||||
"proxy-server-nameserver": ["https://doh.pub/dns-query", "https://dns.alidns.com/dns-query", "tls://223.5.5.5"],
|
||||
"proxy-server-nameserver": [
|
||||
"https://doh.pub/dns-query",
|
||||
"https://dns.alidns.com/dns-query",
|
||||
"tls://223.5.5.5",
|
||||
],
|
||||
"direct-nameserver": [],
|
||||
"direct-nameserver-follow-policy": false,
|
||||
"fallback-filter": { geoip: true, "geoip-code": "CN", ipcidr: ["240.0.0.0/4", "0.0.0.0/32"], domain: ["+.google.com", "+.facebook.com", "+.youtube.com"] },
|
||||
"fallback-filter": {
|
||||
geoip: true,
|
||||
"geoip-code": "CN",
|
||||
ipcidr: ["240.0.0.0/4", "0.0.0.0/32"],
|
||||
domain: ["+.google.com", "+.facebook.com", "+.youtube.com"],
|
||||
},
|
||||
};
|
||||
|
||||
interface Props {
|
||||
@@ -63,74 +91,193 @@ interface Props {
|
||||
|
||||
// Функция-помощник, которая всегда возвращает состояние в правильном формате (со строками)
|
||||
const formatValues = (config: any = {}): any => {
|
||||
const dnsConfig = config.dns || {};
|
||||
const hostsConfig = config.hosts || {};
|
||||
const formatList = (arr: any[] | undefined = []): string => (arr || []).join(", ");
|
||||
const formatHosts = (hosts: any): string => !hosts ? "" : Object.entries(hosts).map(([domain, value]) => `${domain}=${Array.isArray(value) ? value.join(';') : value}`).join(", ");
|
||||
const formatNameserverPolicy = (policy: any): string => !policy ? "" : Object.entries(policy).map(([domain, servers]) => `${domain}=${Array.isArray(servers) ? servers.join(';') : servers}`).join(", ");
|
||||
const dnsConfig = config.dns || {};
|
||||
const hostsConfig = config.hosts || {};
|
||||
const formatList = (arr: any[] | undefined = []): string =>
|
||||
(arr || []).join(", ");
|
||||
const formatHosts = (hosts: any): string =>
|
||||
!hosts
|
||||
? ""
|
||||
: Object.entries(hosts)
|
||||
.map(
|
||||
([domain, value]) =>
|
||||
`${domain}=${Array.isArray(value) ? value.join(";") : value}`,
|
||||
)
|
||||
.join(", ");
|
||||
const formatNameserverPolicy = (policy: any): string =>
|
||||
!policy
|
||||
? ""
|
||||
: Object.entries(policy)
|
||||
.map(
|
||||
([domain, servers]) =>
|
||||
`${domain}=${Array.isArray(servers) ? servers.join(";") : servers}`,
|
||||
)
|
||||
.join(", ");
|
||||
|
||||
const enhancedMode = dnsConfig["enhanced-mode"];
|
||||
const validEnhancedMode = ["fake-ip", "redir-host"].includes(enhancedMode) ? enhancedMode : DEFAULT_DNS_CONFIG["enhanced-mode"];
|
||||
const fakeIpFilterMode = dnsConfig["fake-ip-filter-mode"];
|
||||
const validFakeIpFilterMode = ["blacklist", "whitelist"].includes(fakeIpFilterMode) ? fakeIpFilterMode : DEFAULT_DNS_CONFIG["fake-ip-filter-mode"];
|
||||
const enhancedMode = dnsConfig["enhanced-mode"];
|
||||
const validEnhancedMode = ["fake-ip", "redir-host"].includes(enhancedMode)
|
||||
? enhancedMode
|
||||
: DEFAULT_DNS_CONFIG["enhanced-mode"];
|
||||
const fakeIpFilterMode = dnsConfig["fake-ip-filter-mode"];
|
||||
const validFakeIpFilterMode = ["blacklist", "whitelist"].includes(
|
||||
fakeIpFilterMode,
|
||||
)
|
||||
? fakeIpFilterMode
|
||||
: DEFAULT_DNS_CONFIG["fake-ip-filter-mode"];
|
||||
|
||||
return {
|
||||
enable: dnsConfig.enable ?? DEFAULT_DNS_CONFIG.enable,
|
||||
listen: dnsConfig.listen ?? DEFAULT_DNS_CONFIG.listen,
|
||||
enhancedMode: validEnhancedMode,
|
||||
fakeIpRange: dnsConfig["fake-ip-range"] ?? DEFAULT_DNS_CONFIG["fake-ip-range"],
|
||||
fakeIpFilterMode: validFakeIpFilterMode,
|
||||
preferH3: dnsConfig["prefer-h3"] ?? DEFAULT_DNS_CONFIG["prefer-h3"],
|
||||
respectRules: dnsConfig["respect-rules"] ?? DEFAULT_DNS_CONFIG["respect-rules"],
|
||||
useHosts: dnsConfig["use-hosts"] ?? DEFAULT_DNS_CONFIG["use-hosts"],
|
||||
useSystemHosts: dnsConfig["use-system-hosts"] ?? DEFAULT_DNS_CONFIG["use-system-hosts"],
|
||||
ipv6: dnsConfig.ipv6 ?? DEFAULT_DNS_CONFIG.ipv6,
|
||||
fakeIpFilter: formatList(dnsConfig["fake-ip-filter"] ?? DEFAULT_DNS_CONFIG["fake-ip-filter"]),
|
||||
defaultNameserver: formatList(dnsConfig["default-nameserver"] ?? DEFAULT_DNS_CONFIG["default-nameserver"]),
|
||||
nameserver: formatList(dnsConfig.nameserver ?? DEFAULT_DNS_CONFIG.nameserver),
|
||||
fallback: formatList(dnsConfig.fallback ?? DEFAULT_DNS_CONFIG.fallback),
|
||||
proxyServerNameserver: formatList(dnsConfig["proxy-server-nameserver"] ?? DEFAULT_DNS_CONFIG["proxy-server-nameserver"]),
|
||||
directNameserver: formatList(dnsConfig["direct-nameserver"] ?? DEFAULT_DNS_CONFIG["direct-nameserver"]),
|
||||
directNameserverFollowPolicy: dnsConfig["direct-nameserver-follow-policy"] ?? DEFAULT_DNS_CONFIG["direct-nameserver-follow-policy"],
|
||||
fallbackGeoip: dnsConfig["fallback-filter"]?.geoip ?? DEFAULT_DNS_CONFIG["fallback-filter"].geoip,
|
||||
fallbackGeoipCode: dnsConfig["fallback-filter"]?.["geoip-code"] ?? DEFAULT_DNS_CONFIG["fallback-filter"]["geoip-code"],
|
||||
fallbackIpcidr: formatList(dnsConfig["fallback-filter"]?.ipcidr) ?? formatList(DEFAULT_DNS_CONFIG["fallback-filter"].ipcidr),
|
||||
fallbackDomain: formatList(dnsConfig["fallback-filter"]?.domain) ?? formatList(DEFAULT_DNS_CONFIG["fallback-filter"].domain),
|
||||
nameserverPolicy: formatNameserverPolicy(dnsConfig["nameserver-policy"]) || "",
|
||||
hosts: formatHosts(hostsConfig) || "",
|
||||
};
|
||||
return {
|
||||
enable: dnsConfig.enable ?? DEFAULT_DNS_CONFIG.enable,
|
||||
listen: dnsConfig.listen ?? DEFAULT_DNS_CONFIG.listen,
|
||||
enhancedMode: validEnhancedMode,
|
||||
fakeIpRange:
|
||||
dnsConfig["fake-ip-range"] ?? DEFAULT_DNS_CONFIG["fake-ip-range"],
|
||||
fakeIpFilterMode: validFakeIpFilterMode,
|
||||
preferH3: dnsConfig["prefer-h3"] ?? DEFAULT_DNS_CONFIG["prefer-h3"],
|
||||
respectRules:
|
||||
dnsConfig["respect-rules"] ?? DEFAULT_DNS_CONFIG["respect-rules"],
|
||||
useHosts: dnsConfig["use-hosts"] ?? DEFAULT_DNS_CONFIG["use-hosts"],
|
||||
useSystemHosts:
|
||||
dnsConfig["use-system-hosts"] ?? DEFAULT_DNS_CONFIG["use-system-hosts"],
|
||||
ipv6: dnsConfig.ipv6 ?? DEFAULT_DNS_CONFIG.ipv6,
|
||||
fakeIpFilter: formatList(
|
||||
dnsConfig["fake-ip-filter"] ?? DEFAULT_DNS_CONFIG["fake-ip-filter"],
|
||||
),
|
||||
defaultNameserver: formatList(
|
||||
dnsConfig["default-nameserver"] ??
|
||||
DEFAULT_DNS_CONFIG["default-nameserver"],
|
||||
),
|
||||
nameserver: formatList(
|
||||
dnsConfig.nameserver ?? DEFAULT_DNS_CONFIG.nameserver,
|
||||
),
|
||||
fallback: formatList(dnsConfig.fallback ?? DEFAULT_DNS_CONFIG.fallback),
|
||||
proxyServerNameserver: formatList(
|
||||
dnsConfig["proxy-server-nameserver"] ??
|
||||
DEFAULT_DNS_CONFIG["proxy-server-nameserver"],
|
||||
),
|
||||
directNameserver: formatList(
|
||||
dnsConfig["direct-nameserver"] ?? DEFAULT_DNS_CONFIG["direct-nameserver"],
|
||||
),
|
||||
directNameserverFollowPolicy:
|
||||
dnsConfig["direct-nameserver-follow-policy"] ??
|
||||
DEFAULT_DNS_CONFIG["direct-nameserver-follow-policy"],
|
||||
fallbackGeoip:
|
||||
dnsConfig["fallback-filter"]?.geoip ??
|
||||
DEFAULT_DNS_CONFIG["fallback-filter"].geoip,
|
||||
fallbackGeoipCode:
|
||||
dnsConfig["fallback-filter"]?.["geoip-code"] ??
|
||||
DEFAULT_DNS_CONFIG["fallback-filter"]["geoip-code"],
|
||||
fallbackIpcidr:
|
||||
formatList(dnsConfig["fallback-filter"]?.ipcidr) ??
|
||||
formatList(DEFAULT_DNS_CONFIG["fallback-filter"].ipcidr),
|
||||
fallbackDomain:
|
||||
formatList(dnsConfig["fallback-filter"]?.domain) ??
|
||||
formatList(DEFAULT_DNS_CONFIG["fallback-filter"].domain),
|
||||
nameserverPolicy:
|
||||
formatNameserverPolicy(dnsConfig["nameserver-policy"]) || "",
|
||||
hosts: formatHosts(hostsConfig) || "",
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
export const DnsViewer = forwardRef<DialogRef, Props>(({ onSave }, ref) => {
|
||||
const { t } = useTranslation();
|
||||
const themeMode = useThemeMode();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [visualization, setVisualization] = useState(true);
|
||||
const [values, setValues] = useState(() => formatValues({ dns: DEFAULT_DNS_CONFIG, hosts: {} }));
|
||||
const [values, setValues] = useState(() =>
|
||||
formatValues({ dns: DEFAULT_DNS_CONFIG, hosts: {} }),
|
||||
);
|
||||
const [yamlContent, setYamlContent] = useState("");
|
||||
const [prevData, setPrevData] = useState("");
|
||||
|
||||
const parseList = (str: string = ""): string[] => str ? str.split(",").map(s => s.trim()).filter(Boolean) : [];
|
||||
const parseHosts = (str: string): Record<string, any> => str.split(",").reduce((acc, item) => { const parts = item.trim().split("="); if (parts.length >= 2) { const domain = parts[0].trim(); const valueStr = parts.slice(1).join("=").trim(); acc[domain] = valueStr.includes(";") ? valueStr.split(";").map(s => s.trim()).filter(Boolean) : valueStr; } return acc; }, {} as Record<string, any>);
|
||||
const parseNameserverPolicy = (str: string): Record<string, any> => str.split(",").reduce((acc, item) => { const parts = item.trim().split("="); if (parts.length >= 2) { const domain = parts[0].trim(); const serversStr = parts.slice(1).join("=").trim(); acc[domain] = serversStr.includes(";") ? serversStr.split(";").map(s => s.trim()).filter(Boolean) : serversStr; } return acc; }, {} as Record<string, any>);
|
||||
const parseList = (str: string = ""): string[] =>
|
||||
str
|
||||
? str
|
||||
.split(",")
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean)
|
||||
: [];
|
||||
const parseHosts = (str: string): Record<string, any> =>
|
||||
str.split(",").reduce(
|
||||
(acc, item) => {
|
||||
const parts = item.trim().split("=");
|
||||
if (parts.length >= 2) {
|
||||
const domain = parts[0].trim();
|
||||
const valueStr = parts.slice(1).join("=").trim();
|
||||
acc[domain] = valueStr.includes(";")
|
||||
? valueStr
|
||||
.split(";")
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean)
|
||||
: valueStr;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, any>,
|
||||
);
|
||||
const parseNameserverPolicy = (str: string): Record<string, any> =>
|
||||
str.split(",").reduce(
|
||||
(acc, item) => {
|
||||
const parts = item.trim().split("=");
|
||||
if (parts.length >= 2) {
|
||||
const domain = parts[0].trim();
|
||||
const serversStr = parts.slice(1).join("=").trim();
|
||||
acc[domain] = serversStr.includes(";")
|
||||
? serversStr
|
||||
.split(";")
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean)
|
||||
: serversStr;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, any>,
|
||||
);
|
||||
|
||||
const generateDnsConfig = () => {
|
||||
const dnsConfig: any = { enable: values.enable, listen: values.listen, "enhanced-mode": values.enhancedMode, "fake-ip-range": values.fakeIpRange, "fake-ip-filter-mode": values.fakeIpFilterMode, "prefer-h3": values.preferH3, "respect-rules": values.respectRules, "use-hosts": values.useHosts, "use-system-hosts": values.useSystemHosts, ipv6: values.ipv6, "fake-ip-filter": parseList(values.fakeIpFilter), "default-nameserver": parseList(values.defaultNameserver), nameserver: parseList(values.nameserver), "direct-nameserver-follow-policy": values.directNameserverFollowPolicy, "fallback-filter": { geoip: values.fallbackGeoip, "geoip-code": values.fallbackGeoipCode, ipcidr: parseList(values.fallbackIpcidr), domain: parseList(values.fallbackDomain) }};
|
||||
const dnsConfig: any = {
|
||||
enable: values.enable,
|
||||
listen: values.listen,
|
||||
"enhanced-mode": values.enhancedMode,
|
||||
"fake-ip-range": values.fakeIpRange,
|
||||
"fake-ip-filter-mode": values.fakeIpFilterMode,
|
||||
"prefer-h3": values.preferH3,
|
||||
"respect-rules": values.respectRules,
|
||||
"use-hosts": values.useHosts,
|
||||
"use-system-hosts": values.useSystemHosts,
|
||||
ipv6: values.ipv6,
|
||||
"fake-ip-filter": parseList(values.fakeIpFilter),
|
||||
"default-nameserver": parseList(values.defaultNameserver),
|
||||
nameserver: parseList(values.nameserver),
|
||||
"direct-nameserver-follow-policy": values.directNameserverFollowPolicy,
|
||||
"fallback-filter": {
|
||||
geoip: values.fallbackGeoip,
|
||||
"geoip-code": values.fallbackGeoipCode,
|
||||
ipcidr: parseList(values.fallbackIpcidr),
|
||||
domain: parseList(values.fallbackDomain),
|
||||
},
|
||||
};
|
||||
if (values.fallback) dnsConfig["fallback"] = parseList(values.fallback);
|
||||
const policy = parseNameserverPolicy(values.nameserverPolicy);
|
||||
if (Object.keys(policy).length > 0) dnsConfig["nameserver-policy"] = policy;
|
||||
if (values.proxyServerNameserver) dnsConfig["proxy-server-nameserver"] = parseList(values.proxyServerNameserver);
|
||||
if (values.directNameserver) dnsConfig["direct-nameserver"] = parseList(values.directNameserver);
|
||||
if (values.proxyServerNameserver)
|
||||
dnsConfig["proxy-server-nameserver"] = parseList(
|
||||
values.proxyServerNameserver,
|
||||
);
|
||||
if (values.directNameserver)
|
||||
dnsConfig["direct-nameserver"] = parseList(values.directNameserver);
|
||||
return dnsConfig;
|
||||
};
|
||||
|
||||
const updateYamlFromValues = () => {
|
||||
const config: Record<string, any> = {};
|
||||
const dnsConfig = generateDnsConfig();
|
||||
if (Object.keys(dnsConfig).length > 0) { config.dns = dnsConfig; }
|
||||
if (Object.keys(dnsConfig).length > 0) {
|
||||
config.dns = dnsConfig;
|
||||
}
|
||||
const hosts = parseHosts(values.hosts);
|
||||
if (Object.keys(hosts).length > 0) { config.hosts = hosts; }
|
||||
if (Object.keys(hosts).length > 0) {
|
||||
config.hosts = hosts;
|
||||
}
|
||||
setYamlContent(yaml.dump(config, { forceQuotes: true }));
|
||||
};
|
||||
|
||||
@@ -162,20 +309,30 @@ export const DnsViewer = forwardRef<DialogRef, Props>(({ onSave }, ref) => {
|
||||
try {
|
||||
let finalConfig: Record<string, any>;
|
||||
if (visualization) {
|
||||
finalConfig = { dns: generateDnsConfig(), hosts: parseHosts(values.hosts) };
|
||||
finalConfig = {
|
||||
dns: generateDnsConfig(),
|
||||
hosts: parseHosts(values.hosts),
|
||||
};
|
||||
} else {
|
||||
const parsed = yaml.load(yamlContent);
|
||||
if (typeof parsed !== "object" || parsed === null) throw new Error(t("Invalid configuration"));
|
||||
if (typeof parsed !== "object" || parsed === null)
|
||||
throw new Error(t("Invalid configuration"));
|
||||
finalConfig = parsed as Record<string, any>;
|
||||
}
|
||||
|
||||
const currentData = yaml.dump(finalConfig, { forceQuotes: true });
|
||||
await invoke("save_dns_config", { dnsConfig: finalConfig });
|
||||
|
||||
const [isValid, errorMsg] = await invoke<[boolean, string]>("validate_dns_config", {});
|
||||
const [isValid, errorMsg] = await invoke<[boolean, string]>(
|
||||
"validate_dns_config",
|
||||
{},
|
||||
);
|
||||
if (!isValid) {
|
||||
const cleanErrorMsg = errorMsg.split(/msg="([^"]+)"/)[1] || errorMsg;
|
||||
showNotice("error", t("DNS configuration error") + ": " + cleanErrorMsg);
|
||||
showNotice(
|
||||
"error",
|
||||
t("DNS configuration error") + ": " + cleanErrorMsg,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -187,21 +344,32 @@ export const DnsViewer = forwardRef<DialogRef, Props>(({ onSave }, ref) => {
|
||||
}
|
||||
});
|
||||
|
||||
const handleChange = (field: keyof typeof values) => (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement> | string) => {
|
||||
const value = typeof e === 'string' ? e : (e.target.type === "checkbox" ? (e.target as any).checked : e.target.value);
|
||||
setValues((prev: any) => ({ ...prev, [field]: value }));
|
||||
};
|
||||
const handleChange =
|
||||
(field: keyof typeof values) =>
|
||||
(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement> | string) => {
|
||||
const value =
|
||||
typeof e === "string"
|
||||
? e
|
||||
: e.target.type === "checkbox"
|
||||
? (e.target as any).checked
|
||||
: e.target.value;
|
||||
setValues((prev: any) => ({ ...prev, [field]: value }));
|
||||
};
|
||||
|
||||
const handleSwitchChange = (field: keyof typeof values) => (checked: boolean) => {
|
||||
setValues((prev: any) => ({ ...prev, [field]: checked }));
|
||||
};
|
||||
const handleSwitchChange =
|
||||
(field: keyof typeof values) => (checked: boolean) => {
|
||||
setValues((prev: any) => ({ ...prev, [field]: checked }));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (visualization && open) updateYamlFromValues();
|
||||
}, [values, visualization, open]);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
open: () => { setOpen(true); initDnsConfig(); },
|
||||
open: () => {
|
||||
setOpen(true);
|
||||
initDnsConfig();
|
||||
},
|
||||
close: () => setOpen(false),
|
||||
}));
|
||||
|
||||
@@ -214,8 +382,18 @@ export const DnsViewer = forwardRef<DialogRef, Props>(({ onSave }, ref) => {
|
||||
<div className="flex flex-wrap items-center justify-between gap-x-4 gap-y-2 pr-12">
|
||||
<DialogTitle>{t("DNS Overwrite")}</DialogTitle>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="outline" size="sm" onClick={resetToDefaults}><RotateCcw className="mr-2 h-4 w-4"/>{t("Reset to Default")}</Button>
|
||||
<Button variant="secondary" size="sm" onClick={() => setVisualization(prev => !prev)}><Code className="mr-2 h-4 w-4"/>{visualization ? t("Advanced") : t("Visualization")}</Button>
|
||||
<Button variant="outline" size="sm" onClick={resetToDefaults}>
|
||||
<RotateCcw className="mr-2 h-4 w-4" />
|
||||
{t("Reset to Default")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onClick={() => setVisualization((prev) => !prev)}
|
||||
>
|
||||
<Code className="mr-2 h-4 w-4" />
|
||||
{visualization ? t("Advanced") : t("Visualization")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{/* --- КОНЕЦ ИЗМЕНЕНИЙ --- */}
|
||||
@@ -224,61 +402,289 @@ export const DnsViewer = forwardRef<DialogRef, Props>(({ onSave }, ref) => {
|
||||
<div className="flex-1 min-h-0 py-4">
|
||||
{visualization ? (
|
||||
<div className="h-full pr-4 -mr-4 space-y-6 overflow-y-auto">
|
||||
<Alert variant="destructive" className="bg-amber-500/10 border-amber-500/50 text-amber-700 dark:text-amber-400">
|
||||
<Alert
|
||||
variant="destructive"
|
||||
className="bg-amber-500/10 border-amber-500/50 text-amber-700 dark:text-amber-400"
|
||||
>
|
||||
<AlertTriangle className="h-4 w-4 !text-amber-500" />
|
||||
<AlertTitle>{t("Warning")}</AlertTitle>
|
||||
<AlertDescription>{t("DNS Settings Warning")}</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<div className="space-y-4">
|
||||
<h4 className="font-semibold">{t("DNS Settings")}</h4>
|
||||
<div className="flex items-center justify-between"><Label htmlFor="dns-enable">{t("Enable DNS")}</Label><Switch id="dns-enable" checked={values.enable} onCheckedChange={handleSwitchChange("enable")} /></div>
|
||||
<div className="grid gap-2"><Label htmlFor="dns-listen">{t("DNS Listen")}</Label><Input id="dns-listen" value={values.listen || ''} onChange={handleChange("listen")} /></div>
|
||||
<div className="grid gap-2"><Label>{t("Enhanced Mode")}</Label><Select value={values.enhancedMode} onValueChange={handleChange("enhancedMode")}><SelectTrigger><SelectValue/></SelectTrigger><SelectContent><SelectItem value="fake-ip">fake-ip</SelectItem><SelectItem value="redir-host">redir-host</SelectItem></SelectContent></Select></div>
|
||||
<div className="grid gap-2"><Label htmlFor="dns-fake-ip-range">{t("Fake IP Range")}</Label><Input id="dns-fake-ip-range" value={values.fakeIpRange || ''} onChange={handleChange("fakeIpRange")} /></div>
|
||||
<div className="grid gap-2"><Label>{t("Fake IP Filter Mode")}</Label><Select value={values.fakeIpFilterMode} onValueChange={handleChange("fakeIpFilterMode")}><SelectTrigger><SelectValue/></SelectTrigger><SelectContent><SelectItem value="blacklist">blacklist</SelectItem><SelectItem value="whitelist">whitelist</SelectItem></SelectContent></Select></div>
|
||||
<div className="flex items-center justify-between"><Label>{t("IPv6")}</Label><Switch checked={values.ipv6} onCheckedChange={handleSwitchChange("ipv6")} /></div>
|
||||
<div className="flex items-center justify-between"><Label>{t("Prefer H3")}</Label><Switch checked={values.preferH3} onCheckedChange={handleSwitchChange("preferH3")} /></div>
|
||||
<div className="flex items-center justify-between"><Label>{t("Respect Rules")}</Label><Switch checked={values.respectRules} onCheckedChange={handleSwitchChange("respectRules")} /></div>
|
||||
<div className="flex items-center justify-between"><Label>{t("Use Hosts")}</Label><Switch checked={values.useHosts} onCheckedChange={handleSwitchChange("useHosts")} /></div>
|
||||
<div className="flex items-center justify-between"><Label>{t("Use System Hosts")}</Label><Switch checked={values.useSystemHosts} onCheckedChange={handleSwitchChange("useSystemHosts")} /></div>
|
||||
<div className="flex items-center justify-between"><Label>{t("Direct Nameserver Follow Policy")}</Label><Switch checked={values.directNameserverFollowPolicy} onCheckedChange={handleSwitchChange("directNameserverFollowPolicy")} /></div>
|
||||
<div className="grid gap-2"><Label htmlFor="dns-default-nameserver">{t("Default Nameserver")}</Label><Textarea id="dns-default-nameserver" value={values.defaultNameserver || ''} onChange={handleChange("defaultNameserver")} rows={3} /></div>
|
||||
<div className="grid gap-2"><Label htmlFor="dns-nameserver">{t("Nameserver")}</Label><Textarea id="dns-nameserver" value={values.nameserver || ''} onChange={handleChange("nameserver")} rows={3} /></div>
|
||||
<div className="grid gap-2"><Label htmlFor="dns-fallback">{t("Fallback")}</Label><Textarea id="dns-fallback" value={values.fallback || ''} onChange={handleChange("fallback")} rows={3} /></div>
|
||||
<div className="grid gap-2"><Label htmlFor="dns-proxy-server">{t("Proxy Server Nameserver")}</Label><Textarea id="dns-proxy-server" value={values.proxyServerNameserver || ''} onChange={handleChange("proxyServerNameserver")} rows={3} /></div>
|
||||
<div className="grid gap-2"><Label htmlFor="dns-direct-server">{t("Direct Nameserver")}</Label><Textarea id="dns-direct-server" value={values.directNameserver || ''} onChange={handleChange("directNameserver")} rows={3} /></div>
|
||||
<div className="grid gap-2"><Label htmlFor="dns-fake-ip-filter">{t("Fake IP Filter")}</Label><Textarea id="dns-fake-ip-filter" value={values.fakeIpFilter || ''} onChange={handleChange("fakeIpFilter")} rows={3} /></div>
|
||||
<div className="grid gap-2"><Label htmlFor="dns-policy">{t("Nameserver Policy")}</Label><Textarea id="dns-policy" value={values.nameserverPolicy || ''} onChange={handleChange("nameserverPolicy")} rows={3} /></div>
|
||||
<h4 className="font-semibold">{t("DNS Settings")}</h4>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="dns-enable">{t("Enable DNS")}</Label>
|
||||
<Switch
|
||||
id="dns-enable"
|
||||
checked={values.enable}
|
||||
onCheckedChange={handleSwitchChange("enable")}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="dns-listen">{t("DNS Listen")}</Label>
|
||||
<Input
|
||||
id="dns-listen"
|
||||
value={values.listen || ""}
|
||||
onChange={handleChange("listen")}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label>{t("Enhanced Mode")}</Label>
|
||||
<Select
|
||||
value={values.enhancedMode}
|
||||
onValueChange={handleChange("enhancedMode")}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="fake-ip">fake-ip</SelectItem>
|
||||
<SelectItem value="redir-host">redir-host</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="dns-fake-ip-range">
|
||||
{t("Fake IP Range")}
|
||||
</Label>
|
||||
<Input
|
||||
id="dns-fake-ip-range"
|
||||
value={values.fakeIpRange || ""}
|
||||
onChange={handleChange("fakeIpRange")}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label>{t("Fake IP Filter Mode")}</Label>
|
||||
<Select
|
||||
value={values.fakeIpFilterMode}
|
||||
onValueChange={handleChange("fakeIpFilterMode")}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="blacklist">blacklist</SelectItem>
|
||||
<SelectItem value="whitelist">whitelist</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label>{t("IPv6")}</Label>
|
||||
<Switch
|
||||
checked={values.ipv6}
|
||||
onCheckedChange={handleSwitchChange("ipv6")}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label>{t("Prefer H3")}</Label>
|
||||
<Switch
|
||||
checked={values.preferH3}
|
||||
onCheckedChange={handleSwitchChange("preferH3")}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label>{t("Respect Rules")}</Label>
|
||||
<Switch
|
||||
checked={values.respectRules}
|
||||
onCheckedChange={handleSwitchChange("respectRules")}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label>{t("Use Hosts")}</Label>
|
||||
<Switch
|
||||
checked={values.useHosts}
|
||||
onCheckedChange={handleSwitchChange("useHosts")}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label>{t("Use System Hosts")}</Label>
|
||||
<Switch
|
||||
checked={values.useSystemHosts}
|
||||
onCheckedChange={handleSwitchChange("useSystemHosts")}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label>{t("Direct Nameserver Follow Policy")}</Label>
|
||||
<Switch
|
||||
checked={values.directNameserverFollowPolicy}
|
||||
onCheckedChange={handleSwitchChange(
|
||||
"directNameserverFollowPolicy",
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="dns-default-nameserver">
|
||||
{t("Default Nameserver")}
|
||||
</Label>
|
||||
<Textarea
|
||||
id="dns-default-nameserver"
|
||||
value={values.defaultNameserver || ""}
|
||||
onChange={handleChange("defaultNameserver")}
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="dns-nameserver">{t("Nameserver")}</Label>
|
||||
<Textarea
|
||||
id="dns-nameserver"
|
||||
value={values.nameserver || ""}
|
||||
onChange={handleChange("nameserver")}
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="dns-fallback">{t("Fallback")}</Label>
|
||||
<Textarea
|
||||
id="dns-fallback"
|
||||
value={values.fallback || ""}
|
||||
onChange={handleChange("fallback")}
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="dns-proxy-server">
|
||||
{t("Proxy Server Nameserver")}
|
||||
</Label>
|
||||
<Textarea
|
||||
id="dns-proxy-server"
|
||||
value={values.proxyServerNameserver || ""}
|
||||
onChange={handleChange("proxyServerNameserver")}
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="dns-direct-server">
|
||||
{t("Direct Nameserver")}
|
||||
</Label>
|
||||
<Textarea
|
||||
id="dns-direct-server"
|
||||
value={values.directNameserver || ""}
|
||||
onChange={handleChange("directNameserver")}
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="dns-fake-ip-filter">
|
||||
{t("Fake IP Filter")}
|
||||
</Label>
|
||||
<Textarea
|
||||
id="dns-fake-ip-filter"
|
||||
value={values.fakeIpFilter || ""}
|
||||
onChange={handleChange("fakeIpFilter")}
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="dns-policy">{t("Nameserver Policy")}</Label>
|
||||
<Textarea
|
||||
id="dns-policy"
|
||||
value={values.nameserverPolicy || ""}
|
||||
onChange={handleChange("nameserverPolicy")}
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="space-y-4">
|
||||
<h4 className="font-semibold">{t("Fallback Filter Settings")}</h4>
|
||||
<div className="flex items-center justify-between"><Label htmlFor="fallback-geoip">{t("GeoIP Filtering")}</Label><Switch id="fallback-geoip" checked={values.fallbackGeoip} onCheckedChange={handleSwitchChange("fallbackGeoip")} /></div>
|
||||
<div className="grid gap-2"><Label htmlFor="fallback-geoip-code">{t("GeoIP Code")}</Label><Input id="fallback-geoip-code" value={values.fallbackGeoipCode || ''} onChange={handleChange("fallbackGeoipCode")} /></div>
|
||||
<div className="grid gap-2"><Label htmlFor="fallback-ip-cidr">{t("Fallback IP CIDR")}</Label><Textarea id="fallback-ip-cidr" value={values.fallbackIpcidr || ''} onChange={handleChange("fallbackIpcidr")} rows={3} /></div>
|
||||
<div className="grid gap-2"><Label htmlFor="fallback-domain">{t("Fallback Domain")}</Label><Textarea id="fallback-domain" value={values.fallbackDomain || ''} onChange={handleChange("fallbackDomain")} rows={3} /></div>
|
||||
<h4 className="font-semibold">
|
||||
{t("Fallback Filter Settings")}
|
||||
</h4>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="fallback-geoip">{t("GeoIP Filtering")}</Label>
|
||||
<Switch
|
||||
id="fallback-geoip"
|
||||
checked={values.fallbackGeoip}
|
||||
onCheckedChange={handleSwitchChange("fallbackGeoip")}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="fallback-geoip-code">{t("GeoIP Code")}</Label>
|
||||
<Input
|
||||
id="fallback-geoip-code"
|
||||
value={values.fallbackGeoipCode || ""}
|
||||
onChange={handleChange("fallbackGeoipCode")}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="fallback-ip-cidr">
|
||||
{t("Fallback IP CIDR")}
|
||||
</Label>
|
||||
<Textarea
|
||||
id="fallback-ip-cidr"
|
||||
value={values.fallbackIpcidr || ""}
|
||||
onChange={handleChange("fallbackIpcidr")}
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="fallback-domain">
|
||||
{t("Fallback Domain")}
|
||||
</Label>
|
||||
<Textarea
|
||||
id="fallback-domain"
|
||||
value={values.fallbackDomain || ""}
|
||||
onChange={handleChange("fallbackDomain")}
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="space-y-4">
|
||||
<h4 className="font-semibold">{t("Hosts Settings")}</h4>
|
||||
<div className="grid gap-2"><Label htmlFor="hosts-settings">{t("Hosts")}</Label><Textarea id="hosts-settings" value={values.hosts || ''} onChange={handleChange("hosts")} rows={4} /></div>
|
||||
<h4 className="font-semibold">{t("Hosts Settings")}</h4>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="hosts-settings">{t("Hosts")}</Label>
|
||||
<Textarea
|
||||
id="hosts-settings"
|
||||
value={values.hosts || ""}
|
||||
onChange={handleChange("hosts")}
|
||||
rows={4}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="h-full rounded-md border">
|
||||
<MonacoEditor height="100%" language="yaml" value={yamlContent} theme={themeMode === "light" ? "vs" : "vs-dark"} options={{ tabSize: 2, minimap: { enabled: document.documentElement.clientWidth >= 1500 }, mouseWheelZoom: true, quickSuggestions: { strings: true, comments: true, other: true }, padding: { top: 16 }, fontFamily: `Fira Code, JetBrains Mono, Roboto Mono, "Source Code Pro", Consolas, Menlo, Monaco, monospace, "Courier New", "Apple Color Emoji"${getSystem() === "windows" ? ", twemoji mozilla" : ""}`, fontLigatures: false, smoothScrolling: true }} onChange={(value) => setYamlContent(value || "")} />
|
||||
<MonacoEditor
|
||||
height="100%"
|
||||
language="yaml"
|
||||
value={yamlContent}
|
||||
theme={themeMode === "light" ? "vs" : "vs-dark"}
|
||||
options={{
|
||||
tabSize: 2,
|
||||
minimap: {
|
||||
enabled: document.documentElement.clientWidth >= 1500,
|
||||
},
|
||||
mouseWheelZoom: true,
|
||||
quickSuggestions: {
|
||||
strings: true,
|
||||
comments: true,
|
||||
other: true,
|
||||
},
|
||||
padding: { top: 16 },
|
||||
fontFamily: `Fira Code, JetBrains Mono, Roboto Mono, "Source Code Pro", Consolas, Menlo, Monaco, monospace, "Courier New", "Apple Color Emoji"${getSystem() === "windows" ? ", twemoji mozilla" : ""}`,
|
||||
fontLigatures: false,
|
||||
smoothScrolling: true,
|
||||
}}
|
||||
onChange={(value) => setYamlContent(value || "")}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<DialogFooter className="mt-4">
|
||||
<DialogClose asChild><Button type="button" variant="outline">{t("Cancel")}</Button></DialogClose>
|
||||
<Button type="button" onClick={handleSave}>{t("Save")}</Button>
|
||||
<DialogClose asChild>
|
||||
<Button type="button" variant="outline">
|
||||
{t("Cancel")}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<Button type="button" onClick={handleSave}>
|
||||
{t("Save")}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
Reference in New Issue
Block a user