Add PacketCard

This commit is contained in:
Daniel Pupius
2025-04-22 22:03:10 -07:00
parent 13187eb520
commit d522985d1e
8 changed files with 157 additions and 210 deletions
+9 -22
View File
@@ -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>
);
};
+23 -38
View File
@@ -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>
);
};
+19 -34
View File
@@ -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>
);
};
+48
View File
@@ -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>
);
};
+39 -54
View File
@@ -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>
);
};
+9 -24
View File
@@ -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>
);
};
+1 -14
View File
@@ -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>
);
}
}