add oban tables

This commit is contained in:
Graham McIntire 2025-06-15 21:32:37 -05:00
parent 7a57739ed7
commit f9fa765e32
No known key found for this signature in database
3 changed files with 16 additions and 246 deletions

View file

@ -73,26 +73,6 @@ Hooks.APRSMap = {
console.log("Map initialized");
// Handle geolocation requests from server
this.handleEvent("request_geolocation", () => {
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition(
(position) => {
const { latitude, longitude } = position.coords;
console.log("User location:", latitude, longitude);
map.setView([latitude, longitude], 12);
// Notify server of new location
this.pushEvent("set_location", { lat: latitude, lng: longitude });
},
(error) => {
console.warn("Geolocation error:", error.message);
},
);
} else {
console.warn("Geolocation not available in this browser");
}
});
// Add OpenStreetMap tile layer
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution:
@ -149,12 +129,10 @@ Hooks.APRSMap = {
// Store markers to avoid duplicates
this.markers = new Map();
this.historicalMarkers = new Map();
this.packetCount = 0;
// Store map instance and initialize state
this.map = map;
this.mapReady = false;
this.userLocationMarker = null;
// Send initial bounds to server
this.sendBoundsToServer();
@ -211,23 +189,6 @@ Hooks.APRSMap = {
console.log("Map view updated after delay");
console.log("New map center:", this.map.getCenter());
console.log("New map zoom:", this.map.getZoom());
// Add a marker at the user's location
if (this.userLocationMarker) {
this.map.removeLayer(this.userLocationMarker);
}
this.userLocationMarker = L.marker([lat, lng], {
icon: L.divIcon({
html: '<div style="background-color: #4299e1; width: 12px; height: 12px; border-radius: 50%; border: 2px solid white; box-shadow: 0 1px 3px rgba(0,0,0,0.4);"></div>',
className: "user-location-marker",
iconSize: [16, 16],
iconAnchor: [8, 8],
}),
})
.addTo(this.map)
.bindPopup("Your location")
.openPopup();
}, 300);
} else {
console.error("Invalid coordinates in zoom_to_location event:", data);
@ -312,11 +273,6 @@ Hooks.APRSMap = {
}
this.markers.clear();
this.historicalMarkers.clear();
this.packetCount = 0;
const counterElement = document.getElementById("packet-count");
if (counterElement) {
counterElement.textContent = this.packetCount;
}
},
refreshMarkers() {
@ -345,13 +301,6 @@ Hooks.APRSMap = {
this.markers.delete(callsign);
}
});
// Update counter
this.packetCount = this.markers.size;
const counterElement = document.getElementById("packet-count");
if (counterElement) {
counterElement.textContent = this.packetCount;
}
},
clearHistoricalMarkers() {
@ -370,10 +319,7 @@ Hooks.APRSMap = {
},
removeMarkersOutsideBounds(bounds) {
// Let LiveView handle the packet count
// The cluster handles marker visibility automatically
const visibleCount = this.markers.size;
this.pushEvent("update_packet_count", { count: visibleCount });
},
addPacketMarker(packet, isHistorical = false) {
@ -473,15 +419,6 @@ Hooks.APRSMap = {
// Store the marker
markerCollection.set(markerId, marker);
// Update packet counter (only for live packets)
if (!isHistorical) {
this.packetCount++;
const counterElement = document.getElementById("packet-count");
if (counterElement) {
counterElement.textContent = this.packetCount;
}
}
}
},

View file

@ -22,7 +22,6 @@ defmodule AprsWeb.MapLive.Index do
socket =
assign(socket,
packets: [],
packet_count: 0,
page_title: "APRS Map",
# Track visible packets by callsign
visible_packets: %{},
@ -117,8 +116,6 @@ defmodule AprsWeb.MapLive.Index do
end)
|> Map.new()
packet_count = map_size(visible_packets)
# If replay is not active, update the replay packets based on the new bounds
socket =
if socket.assigns.replay_active do
@ -138,13 +135,7 @@ defmodule AprsWeb.MapLive.Index do
socket
end
{:noreply, assign(socket, map_bounds: map_bounds, visible_packets: visible_packets, packet_count: packet_count)}
end
@impl true
def handle_event("update_packet_count", %{"count" => count}, socket) do
# Update packet count from client after markers are removed
{:noreply, assign(socket, packet_count: count)}
{:noreply, assign(socket, map_bounds: map_bounds, visible_packets: visible_packets)}
end
@impl true
@ -337,13 +328,12 @@ defmodule AprsWeb.MapLive.Index do
# Update visible packets tracking
visible_packets = Map.put(socket.assigns.visible_packets, callsign_key, sanitized_packet)
packet_count = map_size(visible_packets)
# Push the packet to the client-side JavaScript
socket =
socket
|> push_event("new_packet", packet_data)
|> assign(visible_packets: visible_packets, packet_count: packet_count)
|> assign(visible_packets: visible_packets)
{:noreply, socket}
else
@ -458,18 +448,6 @@ defmodule AprsWeb.MapLive.Index do
z-index: 1;
}
.map-overlay {
position: absolute;
top: 10px;
right: 10px;
background: rgba(255, 255, 255, 0.9);
padding: 10px 15px;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
z-index: 1000;
max-width: 300px;
}
.locate-button {
position: absolute;
left: 10px;
@ -486,112 +464,6 @@ defmodule AprsWeb.MapLive.Index do
background: #f4f4f4;
}
.packet-counter {
font-size: 14px;
font-weight: 600;
color: #333;
margin-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.replay-badge {
background-color: #3498db;
color: white;
padding: 2px 6px;
border-radius: 10px;
font-size: 10px;
font-weight: bold;
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { opacity: 0.7; }
50% { opacity: 1; }
100% { opacity: 0.7; }
}
.replay-controls {
margin-top: 10px;
display: flex;
flex-direction: column;
gap: 8px;
}
.control-buttons {
display: flex;
gap: 8px;
}
.replay-controls button {
padding: 5px 10px;
border-radius: 4px;
font-size: 12px;
cursor: pointer;
font-weight: 600;
border: none;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
}
.btn-action {
background-color: #3498db;
color: white;
}
.btn-danger {
background-color: #e74c3c;
color: white;
}
.btn-secondary {
background-color: #7f8c8d;
color: white;
}
.icon {
font-weight: bold;
}
.speed-control {
font-size: 12px;
margin-top: 5px;
}
.speed-control input {
width: 100%;
margin-top: 5px;
}
.replay-progress {
font-size: 12px;
margin-top: 5px;
text-align: center;
}
.progress-bar {
height: 6px;
background-color: #eee;
border-radius: 3px;
overflow: hidden;
margin-bottom: 5px;
}
.progress-fill {
height: 100%;
background-color: #3498db;
transition: width 0.5s ease-in-out;
}
.progress-text {
font-size: 10px;
color: #666;
}
.aprs-marker {
background: transparent !important;
border: none !important;
@ -613,55 +485,6 @@ defmodule AprsWeb.MapLive.Index do
>
</div>
<div class="map-overlay">
<div class="packet-counter">
<span id="packet-count">{@packet_count}</span>
&nbsp;packets in view
<%= if @replay_active do %>
<div class="replay-status">
<span class="replay-badge">Replaying historical packets</span>
</div>
<% end %>
</div>
<div class="replay-controls">
<%= if @replay_active do %>
<div class="control-buttons">
<button phx-click="toggle_replay" class="btn-action">
<span class="icon"></span> Restart
</button>
<button phx-click="pause_replay" class="btn-secondary">
<span class="icon">{if @replay_paused, do: "", else: ""}</span>
{if @replay_paused, do: "Resume", else: "Pause"}
</button>
</div>
<div class="speed-control">
<label>Speed: {@replay_speed}x</label>
<input
type="range"
min="1"
max="20"
step="1"
value={@replay_speed}
phx-change="adjust_replay_speed"
name="speed"
/>
</div>
<div class="replay-progress">
<div class="progress-bar">
<div
class="progress-fill"
style={"width: #{if length(@replay_packets) > 0, do: @replay_index * 100 / length(@replay_packets), else: 0}%"}
>
</div>
</div>
<div class="progress-text">
{@replay_index} of {length(@replay_packets)} packets
</div>
</div>
<% end %>
</div>
</div>
<button class="locate-button" phx-click="locate_me" title="Find my location">
<svg
xmlns="http://www.w3.org/2000/svg"
@ -695,16 +518,12 @@ defmodule AprsWeb.MapLive.Index do
end)
|> Map.new()
# Get updated packet count
packet_count = map_size(visible_packets)
# Push event to remove old markers from the map
socket =
socket
|> push_event("refresh_markers", %{})
|> assign(
visible_packets: visible_packets,
packet_count: packet_count,
packet_age_threshold: one_hour_ago
)

View file

@ -0,0 +1,14 @@
defmodule Aprs.Repo.Migrations.UpgradeObanToLatest do
use Ecto.Migration
def up do
# First, drop the existing migration and start fresh
# This ensures we get all the latest schema changes
Oban.Migrations.up()
end
def down do
# This will rollback to the previous state
Oban.Migrations.down()
end
end