mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-04-13 05:20:28 +08:00
* chore(deps): update npm dependencies * Refactor components to use function syntax instead of forwardRef for better type handling and clarity. Updated imports and adjusted prop types accordingly across multiple viewer components including TrafficGraph, ProfileViewer, BackupViewer, ClashCoreViewer, ControllerViewer, DnsViewer, LiteModeViewer, NetworkInterfaceViewer, ThemeViewer, TunViewer, UpdateViewer, and WebUIViewer. --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Tunglies <77394545+Tunglies@users.noreply.github.com>
133 lines
3.7 KiB
TypeScript
133 lines
3.7 KiB
TypeScript
import { Box, Button, Snackbar, useTheme } from "@mui/material";
|
|
import { useLockFn } from "ahooks";
|
|
import dayjs from "dayjs";
|
|
import { t } from "i18next";
|
|
import { useImperativeHandle, useState, type Ref } from "react";
|
|
|
|
import { deleteConnection } from "@/services/cmds";
|
|
import parseTraffic from "@/utils/parse-traffic";
|
|
|
|
export interface ConnectionDetailRef {
|
|
open: (detail: IConnectionsItem) => void;
|
|
}
|
|
|
|
export function ConnectionDetail({ ref }: { ref?: Ref<ConnectionDetailRef> }) {
|
|
const [open, setOpen] = useState(false);
|
|
const [detail, setDetail] = useState<IConnectionsItem>(null!);
|
|
const theme = useTheme();
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
open: (detail: IConnectionsItem) => {
|
|
if (open) return;
|
|
setOpen(true);
|
|
setDetail(detail);
|
|
},
|
|
}));
|
|
|
|
const onClose = () => setOpen(false);
|
|
|
|
return (
|
|
<Snackbar
|
|
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
|
|
open={open}
|
|
onClose={onClose}
|
|
sx={{
|
|
".MuiSnackbarContent-root": {
|
|
maxWidth: "520px",
|
|
maxHeight: "480px",
|
|
overflowY: "auto",
|
|
backgroundColor: theme.palette.background.paper,
|
|
color: theme.palette.text.primary,
|
|
},
|
|
}}
|
|
message={
|
|
detail ? (
|
|
<InnerConnectionDetail data={detail} onClose={onClose} />
|
|
) : null
|
|
}
|
|
/>
|
|
);
|
|
}
|
|
|
|
interface InnerProps {
|
|
data: IConnectionsItem;
|
|
onClose?: () => void;
|
|
}
|
|
|
|
const InnerConnectionDetail = ({ data, onClose }: InnerProps) => {
|
|
const { metadata, rulePayload } = data;
|
|
const theme = useTheme();
|
|
const chains = [...data.chains].reverse().join(" / ");
|
|
const rule = rulePayload ? `${data.rule}(${rulePayload})` : data.rule;
|
|
const host = metadata.host
|
|
? `${metadata.host}:${metadata.destinationPort}`
|
|
: `${metadata.remoteDestination}:${metadata.destinationPort}`;
|
|
const Destination = metadata.destinationIP
|
|
? metadata.destinationIP
|
|
: metadata.remoteDestination;
|
|
|
|
const information = [
|
|
{ label: t("Host"), value: host },
|
|
{ label: t("Downloaded"), value: parseTraffic(data.download).join(" ") },
|
|
{ label: t("Uploaded"), value: parseTraffic(data.upload).join(" ") },
|
|
{
|
|
label: t("DL Speed"),
|
|
value: parseTraffic(data.curDownload ?? -1).join(" ") + "/s",
|
|
},
|
|
{
|
|
label: t("UL Speed"),
|
|
value: parseTraffic(data.curUpload ?? -1).join(" ") + "/s",
|
|
},
|
|
{
|
|
label: t("Chains"),
|
|
value: chains,
|
|
},
|
|
{ label: t("Rule"), value: rule },
|
|
{
|
|
label: t("Process"),
|
|
value: `${metadata.process}${metadata.processPath ? `(${metadata.processPath})` : ""}`,
|
|
},
|
|
{ label: t("Time"), value: dayjs(data.start).fromNow() },
|
|
{
|
|
label: t("Source"),
|
|
value: `${metadata.sourceIP}:${metadata.sourcePort}`,
|
|
},
|
|
{ label: t("Destination"), value: Destination },
|
|
{ label: t("DestinationPort"), value: `${metadata.destinationPort}` },
|
|
{ label: t("Type"), value: `${metadata.type}(${metadata.network})` },
|
|
];
|
|
|
|
const onDelete = useLockFn(async () => deleteConnection(data.id));
|
|
|
|
return (
|
|
<Box sx={{ userSelect: "text", color: theme.palette.text.secondary }}>
|
|
{information.map((each) => (
|
|
<div key={each.label}>
|
|
<b>{each.label}</b>
|
|
<span
|
|
style={{
|
|
wordBreak: "break-all",
|
|
color: theme.palette.text.primary,
|
|
}}
|
|
>
|
|
: {each.value}
|
|
</span>
|
|
</div>
|
|
))}
|
|
|
|
<Box sx={{ textAlign: "right" }}>
|
|
<Button
|
|
variant="contained"
|
|
title={t("Close Connection")}
|
|
onClick={() => {
|
|
onDelete();
|
|
onClose?.();
|
|
}}
|
|
>
|
|
{t("Close Connection")}
|
|
</Button>
|
|
</Box>
|
|
</Box>
|
|
);
|
|
};
|