From b03aef4f7450f003eed86e5037ce46afaa7417e3 Mon Sep 17 00:00:00 2001 From: ajvpot <553597+ajvpot@users.noreply.github.com> Date: Mon, 1 Sep 2025 10:16:41 +0200 Subject: [PATCH] First seen time --- src/components/MapIcons.tsx | 20 +++++++++----------- src/components/MapView.tsx | 12 +----------- src/lib/clickhouse/actions.ts | 3 ++- src/types/map.ts | 11 +++++++++++ 4 files changed, 23 insertions(+), 23 deletions(-) create mode 100644 src/types/map.ts diff --git a/src/components/MapIcons.tsx b/src/components/MapIcons.tsx index e7d1602..118c988 100644 --- a/src/components/MapIcons.tsx +++ b/src/components/MapIcons.tsx @@ -2,17 +2,7 @@ import React from 'react'; import moment from "moment"; import { formatPublicKey } from '../lib/meshcore'; import { getNameIconLabel } from '../lib/meshcore-map-nodeutils'; - -type NodePosition = { - node_id: string; - latitude: number; - longitude: number; - altitude?: number; - last_seen?: string; - type?: string; - short_name?: string; - name?: string | null; -}; +import { NodePosition } from '../types/map'; interface NodeMarkerProps { node: NodePosition; @@ -163,6 +153,14 @@ export function PopupContent({ node }: PopupContentProps) { ) : (
Last seen: -
)} + {node.first_seen ? ( +
+ First seen: {moment.utc(node.first_seen).format('YYYY-MM-DD HH:mm:ss')} (UTC)
+ {moment.utc(node.first_seen).local().fromNow()} +
+ ) : ( +
First seen: -
+ )} ); } diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index c038ab6..58816d4 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -12,6 +12,7 @@ import RefreshButton from "@/components/RefreshButton"; import { NodeMarker, ClusterMarker, PopupContent } from "./MapIcons"; import { renderToString } from "react-dom/server"; import { buildApiUrl } from "../lib/api"; +import { NodePosition } from "../types/map"; const DEFAULT = { lat: 46.56, // Center between Seattle and Portland @@ -19,17 +20,6 @@ const DEFAULT = { zoom: 7, // Zoom level to show both cities }; -type NodePosition = { - node_id: string; - latitude: number; - longitude: number; - altitude?: number; - last_seen?: string; - type?: string; - short_name?: string; - name?: string | null; -}; - type ClusteredMarkersProps = { nodes: NodePosition[] }; // Individual marker component diff --git a/src/lib/clickhouse/actions.ts b/src/lib/clickhouse/actions.ts index 55638a5..c6d2e2e 100644 --- a/src/lib/clickhouse/actions.ts +++ b/src/lib/clickhouse/actions.ts @@ -33,7 +33,7 @@ export async function getNodePositions({ minLat, maxLat, minLng, maxLng, nodeTyp where.push(`last_seen >= now() - INTERVAL {lastSeen:UInt32} SECOND`); params.lastSeen = Number(lastSeen); } - const query = `SELECT node_id, name, short_name, latitude, longitude, last_seen, type FROM unified_latest_nodeinfo WHERE ${where.join(" AND ")}`; + const query = `SELECT node_id, name, short_name, latitude, longitude, last_seen, first_seen, type FROM unified_latest_nodeinfo WHERE ${where.join(" AND ")}`; const resultSet = await clickhouse.query({ query, query_params: params, format: 'JSONEachRow' }); const rows = await resultSet.json(); return rows as Array<{ @@ -43,6 +43,7 @@ export async function getNodePositions({ minLat, maxLat, minLng, maxLng, nodeTyp latitude: number; longitude: number; last_seen: string; + first_seen?: string; type: string; }>; } catch (error) { diff --git a/src/types/map.ts b/src/types/map.ts new file mode 100644 index 0000000..2ac685d --- /dev/null +++ b/src/types/map.ts @@ -0,0 +1,11 @@ +export type NodePosition = { + node_id: string; + latitude: number; + longitude: number; + altitude?: number; + last_seen?: string; + first_seen?: string; + type?: string; + short_name?: string; + name?: string | null; +};