Docker set up and fixes for build

This commit is contained in:
Daniel Pupius
2025-05-01 15:34:16 -07:00
parent 68fc353673
commit e9fa0104e3
27 changed files with 7035 additions and 151 deletions
+1 -20
View File
@@ -27,19 +27,6 @@ const calculateZoomFromPrecisionBits = (precisionBits?: number): number => {
return Math.min(18, baseZoom + (additionalZoom / 2)); // Cap at zoom 18
};
// Function to calculate accuracy in meters from precision bits
const calculateAccuracyFromPrecisionBits = (precisionBits?: number): number => {
if (!precisionBits) return 300; // Default accuracy of 300m
// Each precision bit halves the accuracy radius
// Starting with Earth's circumference (~40075km), calculate the precision
const earthCircumference = 40075000; // in meters
const accuracy = earthCircumference / (2 ** precisionBits) / 2;
// Limit to reasonable values
return Math.max(1, Math.min(accuracy, 10000));
};
export const Map: React.FC<MapProps> = ({
latitude,
longitude,
@@ -55,11 +42,6 @@ export const Map: React.FC<MapProps> = ({
// Calculate zoom level based on precision bits if zoom is not provided
const effectiveZoom = zoom || calculateZoomFromPrecisionBits(precisionBits);
// Calculate accuracy in meters if we have precision bits
const accuracyMeters = precisionBits !== undefined
? calculateAccuracyFromPrecisionBits(precisionBits)
: undefined;
const mapUrl = getStaticMapUrl(
latitude,
longitude,
@@ -67,8 +49,7 @@ export const Map: React.FC<MapProps> = ({
width,
height,
nightMode,
precisionBits,
accuracyMeters
precisionBits
);
const googleMapsUrl = getGoogleMapsUrl(latitude, longitude);
-45
View File
@@ -1,45 +0,0 @@
import React from "react";
import { Packet } from "../lib/types";
interface MessageDisplayProps {
message: Packet;
}
export const MessageDisplay: React.FC<MessageDisplayProps> = ({ message }) => {
const { data } = message;
const getMessageContent = () => {
if (data.text_message) {
return data.text_message;
} else if (data.position) {
return `Position: ${data.position.latitude}, ${data.position.longitude}`;
} else if (data.node_info) {
return `Node Info: ${data.node_info.longName || data.node_info.shortName}`;
} else if (data.telemetry) {
return "Telemetry data";
} else if (data.decode_error) {
return `Error: ${data.decode_error}`;
}
return "Unknown message type";
};
return (
<div className="p-4 border border-neutral-700 rounded bg-neutral-800 shadow-inner">
<div className="flex justify-between mb-2">
<span className="font-medium text-neutral-200">
From: {data.from || "Unknown"}
</span>
<span className="text-neutral-400 text-sm">
ID: {data.id || "No ID"}
</span>
</div>
<div className="mb-2 text-neutral-300">{getMessageContent()}</div>
<div className="mt-3 flex justify-between items-center">
<span className="text-xs text-neutral-500">
Channel: {message.info.channel}
</span>
<span className="text-xs text-neutral-500">Type: {data.port_num}</span>
</div>
</div>
);
};
+8 -21
View File
@@ -144,7 +144,7 @@ export const NetworkMap = React.forwardRef<{ resetAutoZoom: () => void }, Networ
}
// Update markers and fit the map
updateNodeMarkers(nodesWithPosition, navigate);
updateNodeMarkers(nodesWithPosition);
return true;
} catch (error) {
console.error("Error initializing map:", error);
@@ -153,7 +153,7 @@ export const NetworkMap = React.forwardRef<{ resetAutoZoom: () => void }, Networ
}
console.warn("Cannot initialize map - prerequisites not met");
return false;
}, [nodesWithPosition, navigate, updateNodeMarkers, initializeMap]);
}, [nodesWithPosition, updateNodeMarkers, initializeMap]);
// Check for Google Maps API loading - make sure all required objects are available
useEffect(() => {
@@ -274,7 +274,7 @@ export const NetworkMap = React.forwardRef<{ resetAutoZoom: () => void }, Networ
}
// Helper function to update node markers on the map
function updateNodeMarkers(nodes: MapNode[], navigate: ReturnType<typeof useNavigate>): void {
function updateNodeMarkers(nodes: MapNode[]): void {
if (!mapInstanceRef.current) return;
// Clear the bounds for recalculation
@@ -306,7 +306,7 @@ export const NetworkMap = React.forwardRef<{ resetAutoZoom: () => void }, Networ
// Create or update marker
if (!markersRef.current[key]) {
createMarker(node, position, nodeName, navigate);
createMarker(node, position, nodeName);
} else {
updateMarker(node, position);
}
@@ -330,8 +330,7 @@ export const NetworkMap = React.forwardRef<{ resetAutoZoom: () => void }, Networ
function createMarker(
node: MapNode,
position: google.maps.LatLngLiteral,
nodeName: string,
navigate: ReturnType<typeof useNavigate>
nodeName: string
): void {
if (!mapInstanceRef.current || !infoWindowRef.current) return;
@@ -369,7 +368,7 @@ export const NetworkMap = React.forwardRef<{ resetAutoZoom: () => void }, Networ
// Add click listener to show info window
marker.addListener('gmp-click', () => {
showInfoWindow(node, marker, navigate);
showInfoWindow(node, marker);
});
markersRef.current[key] = marker;
@@ -412,8 +411,7 @@ export const NetworkMap = React.forwardRef<{ resetAutoZoom: () => void }, Networ
// Show info window for a node
function showInfoWindow(
node: MapNode,
marker: google.maps.marker.AdvancedMarkerElement,
navigate: ReturnType<typeof useNavigate>
marker: google.maps.marker.AdvancedMarkerElement
): void {
if (!infoWindowRef.current || !mapInstanceRef.current) return;
@@ -445,8 +443,7 @@ export const NetworkMap = React.forwardRef<{ resetAutoZoom: () => void }, Networ
<div style="font-size: 12px; margin-bottom: 8px; color: #333;">
Packets: ${node.messageCount || 0} · Text: ${node.textMessageCount || 0}
</div>
<a href="javascript:void(0);"
id="view-node-${node.id}"
<a href="/node/${node.id.toString(16)}"
style="font-size: 13px; color: #3b82f6; text-decoration: none; font-weight: 500; display: inline-block; padding: 4px 8px; background-color: #f1f5f9; border-radius: 4px;">
View details →
</a>
@@ -455,16 +452,6 @@ export const NetworkMap = React.forwardRef<{ resetAutoZoom: () => void }, Networ
infoWindowRef.current.setContent(infoContent);
infoWindowRef.current.open(mapInstanceRef.current, marker);
// Add listener for the "View details" link with a delay to allow DOM to update
setTimeout(() => {
const link = document.getElementById(`view-node-${node.id}`);
if (link) {
link.addEventListener('gmp-click', () => {
navigate({ to: `/node/$nodeId`, params: { nodeId: node.id.toString(16) } });
});
}
}, 100);
}
// Prepare the styling for the map container
@@ -27,7 +27,6 @@ import { Separator } from "../Separator";
import { KeyValuePair } from "../ui/KeyValuePair";
import { Section } from "../ui/Section";
import { BatteryLevel } from "./BatteryLevel";
import { NetworkStrength } from "./NetworkStrength";
import { GoogleMap } from "./GoogleMap";
import { NodePositionData } from "./NodePositionData";
import { EnvironmentMetrics } from "./EnvironmentMetrics";
-1
View File
@@ -1,5 +1,4 @@
export * from './PacketList';
export * from './MessageDisplay';
export * from './PacketDetails';
export * from './Filter';
export * from './InfoMessage';
@@ -43,7 +43,6 @@ export const DeviceMetricsPacket: React.FC<DeviceMetricsPacketProps> = ({
icon={<Gauge />}
iconBgColor="bg-amber-500"
label="Device Telemetry"
backgroundColor="bg-amber-950/5"
>
<div className="space-y-3">
<div className="grid grid-cols-2 gap-3">
@@ -121,7 +121,6 @@ export const EnvironmentMetricsPacket: React.FC<
icon={<Thermometer />}
iconBgColor="bg-emerald-700"
label="Environment Telemetry"
backgroundColor="bg-green-950/5"
>
<div className="space-y-3">
<div className="grid grid-cols-2 gap-3">
@@ -20,7 +20,6 @@ export const ErrorPacket: React.FC<ErrorPacketProps> = ({ packet }) => {
icon={<AlertTriangle />}
iconBgColor="bg-red-500"
label="Error"
backgroundColor="bg-red-950/5"
>
<div className="max-w-md">
<div className="text-red-400 mb-2 font-medium">
@@ -46,7 +46,6 @@ export const GenericPacket: React.FC<GenericPacketProps> = ({ packet }) => {
icon={<Package />}
iconBgColor="bg-slate-500"
label={portName.replace("_APP", "")}
backgroundColor="bg-slate-950/5"
>
<div className="max-w-md">
<KeyValueGrid>
@@ -21,7 +21,6 @@ export const NodeInfoPacket: React.FC<NodeInfoPacketProps> = ({ packet }) => {
icon={<User />}
iconBgColor="bg-purple-500"
label="Node Info"
backgroundColor="bg-purple-950/5"
>
<div className="flex flex-col gap-1.5">
{/* First row: Long name and short name */}
+1 -1
View File
@@ -35,7 +35,7 @@ export const PacketCard: React.FC<PacketCardProps> = ({
>
{React.cloneElement(icon as React.ReactElement, {
className: "h-3.5 w-3.5 text-white",
})}
} as React.HTMLAttributes<HTMLElement>)}
</div>
{data.from ? (
<Link
@@ -57,7 +57,6 @@ export const TelemetryPacket: React.FC<TelemetryPacketProps> = ({ packet }) => {
icon={<BarChart />}
iconBgColor="bg-neutral-500"
label="Unknown Telemetry"
backgroundColor="bg-neutral-950/5"
>
<div className="text-neutral-400 text-sm">
Unknown telemetry data received at{' '}
@@ -16,7 +16,6 @@ export const TextMessagePacket: React.FC<TextMessagePacketProps> = ({ packet })
icon={<MessageSquareText />}
iconBgColor="bg-blue-500"
label="Text Message"
backgroundColor="bg-blue-950/5"
>
<div className="max-w-lg bg-neutral-800/30 p-3 rounded-md tracking-tight break-words">
{data.textMessage || "Empty message"}
@@ -40,7 +40,6 @@ export const WaypointPacket: React.FC<WaypointPacketProps> = ({ packet }) => {
icon={<MapPin />}
iconBgColor="bg-violet-500"
label="Waypoint"
backgroundColor="bg-violet-950/5"
>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-4">
+3 -3
View File
@@ -1,7 +1,7 @@
/**
* API client functions for interacting with the Meshstream server
*/
import { API_ENDPOINTS } from "./config";
import { getStreamEndpoint } from "./config";
import {
Packet,
StreamEvent,
@@ -204,8 +204,8 @@ export function streamPackets(
}
try {
// Create a new EventSource connection
source = new EventSource(API_ENDPOINTS.STREAM);
// Create a new EventSource connection using dynamic endpoint
source = new EventSource(getStreamEndpoint());
// Log connection attempt
if (reconnectAttempt === 0) {
+9 -15
View File
@@ -12,24 +12,18 @@ export const SITE_TITLE = import.meta.env.VITE_SITE_TITLE || "My Mesh";
export const SITE_DESCRIPTION =
import.meta.env.VITE_SITE_DESCRIPTION ||
"Realtime Meshtastic activity via MQTT.";
// API URL configuration
const getApiBaseUrl = (): string => {
// In production, use the same domain (empty string base URL)
if (IS_PROD) {
return import.meta.env.VITE_API_BASE_URL || "";
}
// In development, use the configured base URL with fallback
return import.meta.env.VITE_API_BASE_URL || "http://localhost:8080";
};
export const API_BASE_URL = getApiBaseUrl();
export const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || "";
export const GOOGLE_MAPS_ID = import.meta.env.VITE_GOOGLE_MAPS_ID || "demo-map-id";
export const GOOGLE_MAPS_API_KEY = import.meta.env.VITE_GOOGLE_MAPS_API_KEY || "";
// API endpoints
export const API_ENDPOINTS = {
STREAM: `${API_BASE_URL}/api/stream`,
};
// Google Maps configuration
export const GOOGLE_MAPS_ID = import.meta.env.VITE_GOOGLE_MAPS_ID || "demo-map-id";
/**
* Get the API endpoint for the stream
*/
export function getStreamEndpoint(): string {
return API_ENDPOINTS.STREAM;
}
+2 -1
View File
@@ -48,7 +48,7 @@ declare namespace google {
class InfoWindow {
constructor(opts?: InfoWindowOptions);
setContent(content: string): void;
open(map?: Map, anchor?: Marker): void;
open(map?: Map, anchor?: any): void;
close(): void;
}
@@ -101,6 +101,7 @@ declare namespace google {
// Event-related functionality
const event: {
addListener(instance: object, event: string, listener: (Event) => void): MapsEventListener;
/**
* Removes the given listener, which should have been returned by
* google.maps.event.addListener.