feat: 新增设备巡检模块实现完整的巡检告警功能
新增设备巡检模块核心功能,包括: - 巡检数据存储与调度系统 - 华为/H3C交换机及Linux服务器采集器 - 设备扩展配置与告警规则管理 - 主机详情页巡检配置入口 - 产品名称自定义设置功能 - 网络设备SSH exec通道兼容处理
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { ArrowUpCircle, Bug, Check, Github, Loader2, MessageCircle, Newspaper, RefreshCcw } from "lucide-react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { ArrowUpCircle, Check, Loader2, RefreshCcw } from "lucide-react";
|
||||
import AppLogo from "./AppLogo";
|
||||
import AppWordmark from "./AppWordmark";
|
||||
import { Button } from "./ui/button";
|
||||
import { cn } from "../lib/utils";
|
||||
import { useApplicationBackend } from "../application/state/useApplicationBackend";
|
||||
import type { UpdateState, UseUpdateCheckResult } from "../application/state/useUpdateCheck";
|
||||
import { useI18n } from "../application/i18n/I18nProvider";
|
||||
@@ -16,75 +15,6 @@ type AppInfo = {
|
||||
platform?: string;
|
||||
};
|
||||
|
||||
const REPO_URL = "https://github.com/binaricat/Netcatty";
|
||||
const BUG_REPORT_TEMPLATE = "bug_report.yml";
|
||||
|
||||
const mapIssuePlatform = (platform?: string) => {
|
||||
switch (platform) {
|
||||
case "darwin":
|
||||
return "macOS";
|
||||
case "win32":
|
||||
return "Windows";
|
||||
case "linux":
|
||||
return "Linux";
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
/** Opens GitHub's Bug Report issue form with fields prefilled from the running app. */
|
||||
export const buildIssueUrl = (appInfo: AppInfo) => {
|
||||
const params = new URLSearchParams({
|
||||
template: BUG_REPORT_TEMPLATE,
|
||||
title: "[Bug] ",
|
||||
});
|
||||
|
||||
if (appInfo.version) {
|
||||
params.set("version", appInfo.version);
|
||||
}
|
||||
|
||||
const platform = mapIssuePlatform(appInfo.platform);
|
||||
if (platform) {
|
||||
params.set("platform", platform);
|
||||
}
|
||||
|
||||
const installSource =
|
||||
appInfo.version === "0.0.0"
|
||||
? "Built from source (npm run dev / pack)"
|
||||
: "GitHub Release (.dmg / .exe / .AppImage / .deb / .rpm / .pacman)";
|
||||
params.set("install_source", installSource);
|
||||
|
||||
const ua = typeof navigator !== "undefined" ? navigator.userAgent : "unknown";
|
||||
params.set(
|
||||
"logs",
|
||||
`Reported from Netcatty Settings (${appInfo.name} ${appInfo.version || "unknown"}).\n\nUser-Agent: ${ua}`,
|
||||
);
|
||||
|
||||
return `${REPO_URL}/issues/new?${params.toString()}`;
|
||||
};
|
||||
|
||||
const ActionRow: React.FC<{
|
||||
icon: React.ReactNode;
|
||||
title: string;
|
||||
subtitle: string;
|
||||
onClick: () => void;
|
||||
}> = ({ icon, title, subtitle, onClick }) => (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
className={cn(
|
||||
"w-full flex items-center gap-3 rounded-lg px-3 py-3 text-left",
|
||||
"hover:bg-muted/50 transition-colors"
|
||||
)}
|
||||
>
|
||||
<div className="shrink-0 text-muted-foreground">{icon}</div>
|
||||
<div className="min-w-0">
|
||||
<div className="text-sm font-medium leading-tight">{title}</div>
|
||||
<div className="text-xs text-muted-foreground mt-0.5 truncate">{subtitle}</div>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
|
||||
interface SettingsApplicationTabProps {
|
||||
updateState: UpdateState;
|
||||
checkNow: UseUpdateCheckResult['checkNow'];
|
||||
@@ -92,9 +22,11 @@ interface SettingsApplicationTabProps {
|
||||
installUpdate: UseUpdateCheckResult['installUpdate'];
|
||||
startDownload: UseUpdateCheckResult['startDownload'];
|
||||
isUpdateDemoMode: boolean;
|
||||
productName: string;
|
||||
setProductName: (value: string) => void;
|
||||
}
|
||||
|
||||
export default function SettingsApplicationTab({ updateState, checkNow, openReleasePage, installUpdate, startDownload, isUpdateDemoMode }: SettingsApplicationTabProps) {
|
||||
export default function SettingsApplicationTab({ updateState, checkNow, openReleasePage, installUpdate, startDownload, isUpdateDemoMode, productName, setProductName }: SettingsApplicationTabProps) {
|
||||
const { t } = useI18n();
|
||||
const { openExternal, getApplicationInfo } = useApplicationBackend();
|
||||
const [appInfo, setAppInfo] = useState<AppInfo>({ name: "Netcatty", version: "" });
|
||||
@@ -163,10 +95,6 @@ export default function SettingsApplicationTab({ updateState, checkNow, openRele
|
||||
setTimeout(() => setLastCheckResult('none'), 3000);
|
||||
};
|
||||
|
||||
const issueUrl = useMemo(() => buildIssueUrl(appInfo), [appInfo]);
|
||||
const releasesUrl = `${REPO_URL}/releases`;
|
||||
const discussionsUrl = `${REPO_URL}/discussions`;
|
||||
|
||||
return (
|
||||
<SettingsTabContent value="application">
|
||||
<div className="flex flex-col lg:flex-row gap-10 lg:gap-14">
|
||||
@@ -174,7 +102,7 @@ export default function SettingsApplicationTab({ updateState, checkNow, openRele
|
||||
<div className="flex items-center gap-4">
|
||||
<AppLogo className="w-16 h-16" />
|
||||
<div>
|
||||
<AppWordmark accessibleLabel="Netcatty" className="h-8 w-auto text-foreground" />
|
||||
<AppWordmark accessibleLabel={productName} className="h-8 w-auto text-foreground" />
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{appInfo.version ? appInfo.version : " "}
|
||||
@@ -224,43 +152,35 @@ export default function SettingsApplicationTab({ updateState, checkNow, openRele
|
||||
}
|
||||
</Button>
|
||||
</SettingsAnchor>
|
||||
</div>
|
||||
|
||||
<div className="flex-1">
|
||||
<div className="space-y-2">
|
||||
<SettingsAnchor anchorId="application-report-problem">
|
||||
<ActionRow
|
||||
icon={<Bug size={18} />}
|
||||
title={t("settings.application.reportProblem")}
|
||||
subtitle={t("settings.application.reportProblem.subtitle")}
|
||||
onClick={() => void handleOpenExternal(issueUrl)}
|
||||
{/* 产品名称配置 */}
|
||||
<SettingsAnchor anchorId="application-product-name" className="mt-6">
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-sm font-medium text-foreground">
|
||||
{t('settings.application.productName') || 'Product Name'}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={productName}
|
||||
onChange={(e) => setProductName(e.target.value)}
|
||||
onBlur={() => {
|
||||
// 失焦时确保标题栏更新
|
||||
const bridge = (window as any).netcatty;
|
||||
bridge?.setWindowTitle?.(productName);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
(e.target as HTMLInputElement).blur();
|
||||
}
|
||||
}}
|
||||
placeholder="NetMesh"
|
||||
className="w-full px-3 py-2 rounded-lg border border-input bg-background text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
||||
/>
|
||||
</SettingsAnchor>
|
||||
<SettingsAnchor anchorId="application-community">
|
||||
<ActionRow
|
||||
icon={<MessageCircle size={18} />}
|
||||
title={t("settings.application.community")}
|
||||
subtitle={t("settings.application.community.subtitle")}
|
||||
onClick={() => void handleOpenExternal(discussionsUrl)}
|
||||
/>
|
||||
</SettingsAnchor>
|
||||
<SettingsAnchor anchorId="application-github">
|
||||
<ActionRow
|
||||
icon={<Github size={18} />}
|
||||
title="GitHub"
|
||||
subtitle={t("settings.application.github.subtitle")}
|
||||
onClick={() => void handleOpenExternal(REPO_URL)}
|
||||
/>
|
||||
</SettingsAnchor>
|
||||
<SettingsAnchor anchorId="application-whats-new">
|
||||
<ActionRow
|
||||
icon={<Newspaper size={18} />}
|
||||
title={t("settings.application.whatsNew")}
|
||||
subtitle={t("settings.application.whatsNew.subtitle")}
|
||||
onClick={() => void handleOpenExternal(releasesUrl)}
|
||||
/>
|
||||
</SettingsAnchor>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{t('settings.application.productNameHint') || 'Used in title bar, sidebar, and settings'}
|
||||
</p>
|
||||
</div>
|
||||
</SettingsAnchor>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user