import { useEffect, type ReactNode } from "react";
import { ArrowSyncRegular, SaveRegular } from "@fluentui/react-icons";
import { cx } from "../../lib/utils";
import { Button, Input, Modal, Select, Spinner, Tag } from "../ui";
import { isQmiControl } from "./shared";
import { DiscoveredDeviceRow } from "./DiscoveredDeviceRow";
import type { DiscoveredDevice } from "../../types";
import type { AddDeviceForm } from "./types";
import { useI18n } from "../../lib/i18n";
import { DEVICE_TYPES, deviceTypeImage } from "../../lib/deviceTypes";
export interface DeviceAddDialogProps {
open: boolean;
discovering: boolean;
unconfiguredDiscovered: DiscoveredDevice[];
addSelected: DiscoveredDevice | null;
addConfig: AddDeviceForm;
addSaving: boolean;
onClose: () => void;
onRefresh: () => void;
onSelectDevice: (d: DiscoveredDevice) => void;
onConfigChange: (next: AddDeviceForm) => void;
onSave: () => void;
}
function discoveryKey(d?: DiscoveredDevice | null): string {
return d ? String(d.discoveryKey || `${d.usbPath || ""}|${d.atPort || ""}`) : "";
}
function isQmiMode(d?: DiscoveredDevice | null): boolean {
return String(d?.mode || "").toLowerCase() === "qmi";
}
function modeLabel(d?: DiscoveredDevice | null): string {
const m = String(d?.mode || "unknown").toLowerCase();
return m === "pcsc" ? "PC/SC" : m === "qmi" ? "QMI" : m === "mbim" ? "MBIM" : m === "ecm" ? "ECM" : m === "rndis" ? "RNDIS" : m === "ncm" ? "NCM" : "UNKNOWN";
}
function Field({ label, children }: { label: ReactNode; children: ReactNode }) {
return (
{children}
);
}
export function DeviceAddDialog(props: DeviceAddDialogProps) {
const { t } = useI18n();
const { addSelected, addConfig } = props;
const fixedQmi = isQmiControl(addSelected?.controlPath || addConfig?.controlDevice);
const isMbim = String(addSelected?.mode || "").toLowerCase() === "mbim";
const isReader = addSelected?.hardwareKind === "pcsc" || String(addSelected?.mode || "").toLowerCase() === "pcsc";
useEffect(() => {
if (fixedQmi && addConfig.deviceBackend !== "qmi") props.onConfigChange({ ...addConfig, deviceBackend: "qmi" });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [fixedQmi]);
useEffect(() => {
if (isMbim && addConfig.deviceBackend !== "mbim") props.onConfigChange({ ...addConfig, deviceBackend: "mbim" });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isMbim]);
const backendOptions = isReader ? [{ value: "pcsc", label: "PC/SC" }] : [
...(isMbim
? []
: [
{ value: "at", label: "AT", disabled: fixedQmi },
{ value: "qmi", label: "QMI", disabled: !addConfig.controlDevice },
]),
...(isMbim ? [{ value: "mbim", label: "MBIM" }] : []),
];
const set = (patch: Partial) => props.onConfigChange({ ...addConfig, ...patch });
return (
}>
{t("保存")}
}
>
{t("选择一个“未配置”的设备,系统将自动填充 AT 端口与识别信息。")}
}>
{t("刷新设备")}
{props.discovering ? (
) : (
<>
{props.unconfiguredDiscovered.map((d) => (
))}
{props.unconfiguredDiscovered.length === 0 ? (
{t("暂无可添加设备(或系统未发现新的模组)")}
) : null}
>
)}
{addSelected ? (
{t("选定设备状态")}
{t("模式:")}
{modeLabel(addSelected)}
{fixedQmi ? {t("仅 QMI 后端")} : null}
{isMbim ? {t("仅 MBIM 后端")} : null}
{fixedQmi ?
{t("此类 WWAN QMI 设备运行后端固定为 QMI;AT 口仍会保留给 AT 终端。")}
: null}
) : null}
);
}