mirror of
https://github.com/dpup/meshstream.git
synced 2026-08-06 16:53:09 +02:00
Add PacketCard
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { Packet } from "../../lib/types";
|
||||
import { AlertTriangle } from "lucide-react";
|
||||
import { PacketCard } from "./PacketCard";
|
||||
|
||||
interface ErrorPacketProps {
|
||||
packet: Packet;
|
||||
@@ -14,29 +15,15 @@ export const ErrorPacket: React.FC<ErrorPacketProps> = ({ packet }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-4 border border-red-900 rounded bg-neutral-800 shadow-inner">
|
||||
<div className="flex justify-between items-start mb-3">
|
||||
<div className="flex items-center">
|
||||
<div className="rounded-md bg-red-500 p-1.5 mr-3">
|
||||
<AlertTriangle className="h-4 w-4 text-neutral-100" />
|
||||
</div>
|
||||
<span className="font-medium text-neutral-200">
|
||||
Decode Error
|
||||
</span>
|
||||
</div>
|
||||
<span className="text-neutral-400 text-sm">
|
||||
ID: {data.id || "No ID"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="mb-3 text-red-400 pl-9">
|
||||
<PacketCard
|
||||
packet={packet}
|
||||
icon={<AlertTriangle className="h-4 w-4 text-neutral-100" />}
|
||||
iconBgColor="bg-red-500"
|
||||
label="Error"
|
||||
>
|
||||
<div className="text-red-400">
|
||||
{data.decodeError}
|
||||
</div>
|
||||
|
||||
<div className="mt-3 flex justify-between items-center text-xs text-neutral-500">
|
||||
<span>Channel: {packet.info.channel}</span>
|
||||
<span>Error</span>
|
||||
</div>
|
||||
</div>
|
||||
</PacketCard>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { Packet, PortNum, PortNumByName } from "../../lib/types";
|
||||
import { Package } from "lucide-react";
|
||||
import { PacketCard } from "./PacketCard";
|
||||
|
||||
interface GenericPacketProps {
|
||||
packet: Packet;
|
||||
@@ -39,46 +40,30 @@ export const GenericPacket: React.FC<GenericPacketProps> = ({ packet }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-4 border border-neutral-700 rounded bg-neutral-800 shadow-inner">
|
||||
<div className="flex justify-between items-start mb-3">
|
||||
<div className="flex items-center">
|
||||
<div className="rounded-md bg-neutral-500 p-1.5 mr-3">
|
||||
<Package className="h-4 w-4 text-neutral-100" />
|
||||
</div>
|
||||
<span className="font-medium text-neutral-200">
|
||||
From: {data.from ? `!${data.from.toString(16).toLowerCase()}` : "Unknown"}
|
||||
</span>
|
||||
<PacketCard
|
||||
packet={packet}
|
||||
icon={<Package className="h-4 w-4 text-neutral-100" />}
|
||||
iconBgColor="bg-neutral-500"
|
||||
label={getPortName(data.portNum)}
|
||||
>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Port</div>
|
||||
<div>{getPortName(data.portNum)}</div>
|
||||
</div>
|
||||
<span className="text-neutral-400 text-sm">
|
||||
ID: {data.id || "No ID"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="mb-3 text-neutral-300 pl-9">
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Port</div>
|
||||
<div>{getPortName(data.portNum)}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Payload</div>
|
||||
<div>{getPayloadDescription()}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">To</div>
|
||||
<div>{data.to || "Broadcast"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Hop Limit</div>
|
||||
<div>{data.hopLimit}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Payload</div>
|
||||
<div>{getPayloadDescription()}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">To</div>
|
||||
<div>{data.to || "Broadcast"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Hop Limit</div>
|
||||
<div>{data.hopLimit}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-3 flex justify-between items-center text-xs text-neutral-500">
|
||||
<span>Channel: {packet.info.channel}</span>
|
||||
<span>{getPortName(data.portNum)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</PacketCard>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { Packet } from "../../lib/types";
|
||||
import { User } from "lucide-react";
|
||||
import { PacketCard } from "./PacketCard";
|
||||
|
||||
interface NodeInfoPacketProps {
|
||||
packet: Packet;
|
||||
@@ -15,42 +16,26 @@ export const NodeInfoPacket: React.FC<NodeInfoPacketProps> = ({ packet }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-4 border border-neutral-700 rounded bg-neutral-800 shadow-inner">
|
||||
<div className="flex justify-between items-start mb-3">
|
||||
<div className="flex items-center">
|
||||
<div className="rounded-md bg-purple-500 p-1.5 mr-3">
|
||||
<User className="h-4 w-4 text-neutral-100" />
|
||||
</div>
|
||||
<span className="font-medium text-neutral-200">
|
||||
From: {data.from ? `!${data.from.toString(16).toLowerCase()}` : "Unknown"}
|
||||
</span>
|
||||
<PacketCard
|
||||
packet={packet}
|
||||
icon={<User className="h-4 w-4 text-neutral-100" />}
|
||||
iconBgColor="bg-purple-500"
|
||||
label="Node Info"
|
||||
>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Long Name</div>
|
||||
<div>{nodeInfo.longName || "—"}</div>
|
||||
</div>
|
||||
<span className="text-neutral-400 text-sm">
|
||||
ID: {data.id || "No ID"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="mb-3 text-neutral-300 pl-9">
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Long Name</div>
|
||||
<div>{nodeInfo.longName || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Short Name</div>
|
||||
<div>{nodeInfo.shortName || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">ID</div>
|
||||
<div className="font-mono">{nodeInfo.id || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Short Name</div>
|
||||
<div>{nodeInfo.shortName || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">ID</div>
|
||||
<div className="font-mono">{nodeInfo.id || "—"}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-3 flex justify-between items-center text-xs text-neutral-500">
|
||||
<span>Channel: {packet.info.channel}</span>
|
||||
<span>Node Info</span>
|
||||
</div>
|
||||
</div>
|
||||
</PacketCard>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
import React, { ReactNode } from "react";
|
||||
import { Packet } from "../../lib/types";
|
||||
import { LucideIcon } from "lucide-react";
|
||||
|
||||
interface PacketCardProps {
|
||||
packet: Packet;
|
||||
icon: ReactNode;
|
||||
iconBgColor: string;
|
||||
label: string;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const PacketCard: React.FC<PacketCardProps> = ({
|
||||
packet,
|
||||
icon,
|
||||
iconBgColor,
|
||||
label,
|
||||
children,
|
||||
}) => {
|
||||
const { data } = packet;
|
||||
|
||||
return (
|
||||
<div className="p-4 border border-neutral-700 rounded bg-neutral-800 shadow-inner">
|
||||
<div className="flex justify-between items-start mb-3">
|
||||
<div className="flex items-center">
|
||||
<div className={`rounded-md ${iconBgColor} p-1.5 mr-3`}>
|
||||
{icon}
|
||||
</div>
|
||||
<span className="font-medium text-neutral-200">
|
||||
From: {data.from ? `!${data.from.toString(16).toLowerCase()}` : "Unknown"}
|
||||
</span>
|
||||
</div>
|
||||
<span className="text-neutral-400 text-sm">
|
||||
ID: {data.id || "No ID"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="mb-3 text-neutral-300 pl-9">
|
||||
{children}
|
||||
</div>
|
||||
|
||||
<div className="mt-3 flex justify-between items-center text-xs text-neutral-500">
|
||||
<span>Channel: {packet.info.channel}</span>
|
||||
<span>{label}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { Packet } from "../../lib/types";
|
||||
import { MapPin } from "lucide-react";
|
||||
import { PacketCard } from "./PacketCard";
|
||||
|
||||
interface PositionPacketProps {
|
||||
packet: Packet;
|
||||
@@ -19,62 +20,46 @@ export const PositionPacket: React.FC<PositionPacketProps> = ({ packet }) => {
|
||||
const longitude = position.longitudeI ? position.longitudeI * 1e-7 : undefined;
|
||||
|
||||
return (
|
||||
<div className="p-4 border border-neutral-700 rounded bg-neutral-800 shadow-inner">
|
||||
<div className="flex justify-between items-start mb-3">
|
||||
<div className="flex items-center">
|
||||
<div className="rounded-md bg-emerald-500 p-1.5 mr-3">
|
||||
<MapPin className="h-4 w-4 text-neutral-100" />
|
||||
</div>
|
||||
<span className="font-medium text-neutral-200">
|
||||
From: {data.from ? `!${data.from.toString(16).toLowerCase()}` : "Unknown"}
|
||||
</span>
|
||||
<PacketCard
|
||||
packet={packet}
|
||||
icon={<MapPin className="h-4 w-4 text-neutral-100" />}
|
||||
iconBgColor="bg-emerald-500"
|
||||
label="Position"
|
||||
>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Latitude</div>
|
||||
<div>{latitude !== undefined ? latitude.toFixed(6) : 'N/A'}</div>
|
||||
</div>
|
||||
<span className="text-neutral-400 text-sm">
|
||||
ID: {data.id || "No ID"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="mb-3 text-neutral-300 pl-9">
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Latitude</div>
|
||||
<div>{latitude !== undefined ? latitude.toFixed(6) : 'N/A'}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Longitude</div>
|
||||
<div>{longitude !== undefined ? longitude.toFixed(6) : 'N/A'}</div>
|
||||
</div>
|
||||
{position.altitude && (
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Altitude</div>
|
||||
<div>{position.altitude.toFixed(1)}m</div>
|
||||
</div>
|
||||
)}
|
||||
{position.time && (
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Time</div>
|
||||
<div>{new Date(position.time * 1000).toLocaleTimeString()}</div>
|
||||
</div>
|
||||
)}
|
||||
{position.locationSource && (
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Source</div>
|
||||
<div>{position.locationSource.replace('LOC_', '')}</div>
|
||||
</div>
|
||||
)}
|
||||
{position.satsInView && (
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Satellites</div>
|
||||
<div>{position.satsInView}</div>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Longitude</div>
|
||||
<div>{longitude !== undefined ? longitude.toFixed(6) : 'N/A'}</div>
|
||||
</div>
|
||||
{position.altitude && (
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Altitude</div>
|
||||
<div>{position.altitude.toFixed(1)}m</div>
|
||||
</div>
|
||||
)}
|
||||
{position.time && (
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Time</div>
|
||||
<div>{new Date(position.time * 1000).toLocaleTimeString()}</div>
|
||||
</div>
|
||||
)}
|
||||
{position.locationSource && (
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Source</div>
|
||||
<div>{position.locationSource.replace('LOC_', '')}</div>
|
||||
</div>
|
||||
)}
|
||||
{position.satsInView && (
|
||||
<div>
|
||||
<div className="text-xs text-neutral-400">Satellites</div>
|
||||
<div>{position.satsInView}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="mt-3 flex justify-between items-center text-xs text-neutral-500">
|
||||
<span>Channel: {packet.info.channel}</span>
|
||||
<span>Position</span>
|
||||
</div>
|
||||
</div>
|
||||
</PacketCard>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { Packet } from "../../lib/types";
|
||||
import { BarChart } from "lucide-react";
|
||||
import { PacketCard } from "./PacketCard";
|
||||
|
||||
interface TelemetryPacketProps {
|
||||
packet: Packet;
|
||||
@@ -42,29 +43,13 @@ export const TelemetryPacket: React.FC<TelemetryPacketProps> = ({ packet }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-4 border border-neutral-700 rounded bg-neutral-800 shadow-inner">
|
||||
<div className="flex justify-between items-start mb-3">
|
||||
<div className="flex items-center">
|
||||
<div className="rounded-md bg-amber-500 p-1.5 mr-3">
|
||||
<BarChart className="h-4 w-4 text-neutral-100" />
|
||||
</div>
|
||||
<span className="font-medium text-neutral-200">
|
||||
From: {data.from ? `!${data.from.toString(16).toLowerCase()}` : "Unknown"}
|
||||
</span>
|
||||
</div>
|
||||
<span className="text-neutral-400 text-sm">
|
||||
ID: {data.id || "No ID"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="mb-3 text-neutral-300 pl-9">
|
||||
{renderTelemetryFields()}
|
||||
</div>
|
||||
|
||||
<div className="mt-3 flex justify-between items-center text-xs text-neutral-500">
|
||||
<span>Channel: {packet.info.channel}</span>
|
||||
<span>Telemetry</span>
|
||||
</div>
|
||||
</div>
|
||||
<PacketCard
|
||||
packet={packet}
|
||||
icon={<BarChart className="h-4 w-4 text-neutral-100" />}
|
||||
iconBgColor="bg-amber-500"
|
||||
label="Telemetry"
|
||||
>
|
||||
{renderTelemetryFields()}
|
||||
</PacketCard>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { Packet } from "../../lib/types";
|
||||
import { MessageSquareText } from "lucide-react";
|
||||
import { PacketCard } from "./PacketCard";
|
||||
|
||||
interface TextMessagePacketProps {
|
||||
packet: Packet;
|
||||
@@ -10,29 +11,13 @@ export const TextMessagePacket: React.FC<TextMessagePacketProps> = ({ packet })
|
||||
const { data } = packet;
|
||||
|
||||
return (
|
||||
<div className="p-4 border border-neutral-700 rounded bg-neutral-800 shadow-inner">
|
||||
<div className="flex justify-between items-start mb-3">
|
||||
<div className="flex items-center">
|
||||
<div className="rounded-md bg-blue-500 p-1.5 mr-3">
|
||||
<MessageSquareText className="h-4 w-4 text-neutral-100" />
|
||||
</div>
|
||||
<span className="font-medium text-neutral-200">
|
||||
From: {data.from ? `!${data.from.toString(16).toLowerCase()}` : "Unknown"}
|
||||
</span>
|
||||
</div>
|
||||
<span className="text-neutral-400 text-sm">
|
||||
ID: {data.id || "No ID"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="mb-3 text-neutral-300 pl-9">
|
||||
{data.textMessage || "Empty message"}
|
||||
</div>
|
||||
|
||||
<div className="mt-3 flex justify-between items-center text-xs text-neutral-500">
|
||||
<span>Channel: {packet.info.channel}</span>
|
||||
<span>Text Message</span>
|
||||
</div>
|
||||
</div>
|
||||
<PacketCard
|
||||
packet={packet}
|
||||
icon={<MessageSquareText className="h-4 w-4 text-neutral-100" />}
|
||||
iconBgColor="bg-blue-500"
|
||||
label="Text Message"
|
||||
>
|
||||
{data.textMessage || "Empty message"}
|
||||
</PacketCard>
|
||||
);
|
||||
};
|
||||
@@ -26,22 +26,9 @@ export function PacketsRoute() {
|
||||
|
||||
return (
|
||||
<div className="bg-neutral-700 rounded-lg shadow-inner">
|
||||
<div className="p-6">
|
||||
<h2 className="text-2xl font-bold mb-4 text-neutral-100">
|
||||
Mesh Network Packets
|
||||
</h2>
|
||||
|
||||
<InfoMessage
|
||||
message="This page displays real-time packets from the Meshtastic mesh network."
|
||||
type="info"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Separator className="my-2" />
|
||||
|
||||
<div className="p-6">
|
||||
<PacketList />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user