add oban tables
This commit is contained in:
parent
7a57739ed7
commit
f9fa765e32
3 changed files with 16 additions and 246 deletions
|
|
@ -73,26 +73,6 @@ Hooks.APRSMap = {
|
||||||
|
|
||||||
console.log("Map initialized");
|
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
|
// Add OpenStreetMap tile layer
|
||||||
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||||
attribution:
|
attribution:
|
||||||
|
|
@ -149,12 +129,10 @@ Hooks.APRSMap = {
|
||||||
// Store markers to avoid duplicates
|
// Store markers to avoid duplicates
|
||||||
this.markers = new Map();
|
this.markers = new Map();
|
||||||
this.historicalMarkers = new Map();
|
this.historicalMarkers = new Map();
|
||||||
this.packetCount = 0;
|
|
||||||
|
|
||||||
// Store map instance and initialize state
|
// Store map instance and initialize state
|
||||||
this.map = map;
|
this.map = map;
|
||||||
this.mapReady = false;
|
this.mapReady = false;
|
||||||
this.userLocationMarker = null;
|
|
||||||
|
|
||||||
// Send initial bounds to server
|
// Send initial bounds to server
|
||||||
this.sendBoundsToServer();
|
this.sendBoundsToServer();
|
||||||
|
|
@ -211,23 +189,6 @@ Hooks.APRSMap = {
|
||||||
console.log("Map view updated after delay");
|
console.log("Map view updated after delay");
|
||||||
console.log("New map center:", this.map.getCenter());
|
console.log("New map center:", this.map.getCenter());
|
||||||
console.log("New map zoom:", this.map.getZoom());
|
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);
|
}, 300);
|
||||||
} else {
|
} else {
|
||||||
console.error("Invalid coordinates in zoom_to_location event:", data);
|
console.error("Invalid coordinates in zoom_to_location event:", data);
|
||||||
|
|
@ -312,11 +273,6 @@ Hooks.APRSMap = {
|
||||||
}
|
}
|
||||||
this.markers.clear();
|
this.markers.clear();
|
||||||
this.historicalMarkers.clear();
|
this.historicalMarkers.clear();
|
||||||
this.packetCount = 0;
|
|
||||||
const counterElement = document.getElementById("packet-count");
|
|
||||||
if (counterElement) {
|
|
||||||
counterElement.textContent = this.packetCount;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
refreshMarkers() {
|
refreshMarkers() {
|
||||||
|
|
@ -345,13 +301,6 @@ Hooks.APRSMap = {
|
||||||
this.markers.delete(callsign);
|
this.markers.delete(callsign);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update counter
|
|
||||||
this.packetCount = this.markers.size;
|
|
||||||
const counterElement = document.getElementById("packet-count");
|
|
||||||
if (counterElement) {
|
|
||||||
counterElement.textContent = this.packetCount;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
clearHistoricalMarkers() {
|
clearHistoricalMarkers() {
|
||||||
|
|
@ -370,10 +319,7 @@ Hooks.APRSMap = {
|
||||||
},
|
},
|
||||||
|
|
||||||
removeMarkersOutsideBounds(bounds) {
|
removeMarkersOutsideBounds(bounds) {
|
||||||
// Let LiveView handle the packet count
|
|
||||||
// The cluster handles marker visibility automatically
|
// The cluster handles marker visibility automatically
|
||||||
const visibleCount = this.markers.size;
|
|
||||||
this.pushEvent("update_packet_count", { count: visibleCount });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addPacketMarker(packet, isHistorical = false) {
|
addPacketMarker(packet, isHistorical = false) {
|
||||||
|
|
@ -473,15 +419,6 @@ Hooks.APRSMap = {
|
||||||
|
|
||||||
// Store the marker
|
// Store the marker
|
||||||
markerCollection.set(markerId, 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ defmodule AprsWeb.MapLive.Index do
|
||||||
socket =
|
socket =
|
||||||
assign(socket,
|
assign(socket,
|
||||||
packets: [],
|
packets: [],
|
||||||
packet_count: 0,
|
|
||||||
page_title: "APRS Map",
|
page_title: "APRS Map",
|
||||||
# Track visible packets by callsign
|
# Track visible packets by callsign
|
||||||
visible_packets: %{},
|
visible_packets: %{},
|
||||||
|
|
@ -117,8 +116,6 @@ defmodule AprsWeb.MapLive.Index do
|
||||||
end)
|
end)
|
||||||
|> Map.new()
|
|> Map.new()
|
||||||
|
|
||||||
packet_count = map_size(visible_packets)
|
|
||||||
|
|
||||||
# If replay is not active, update the replay packets based on the new bounds
|
# If replay is not active, update the replay packets based on the new bounds
|
||||||
socket =
|
socket =
|
||||||
if socket.assigns.replay_active do
|
if socket.assigns.replay_active do
|
||||||
|
|
@ -138,13 +135,7 @@ defmodule AprsWeb.MapLive.Index do
|
||||||
socket
|
socket
|
||||||
end
|
end
|
||||||
|
|
||||||
{:noreply, assign(socket, map_bounds: map_bounds, visible_packets: visible_packets, packet_count: packet_count)}
|
{:noreply, assign(socket, map_bounds: map_bounds, visible_packets: visible_packets)}
|
||||||
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)}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
|
@ -337,13 +328,12 @@ defmodule AprsWeb.MapLive.Index do
|
||||||
|
|
||||||
# Update visible packets tracking
|
# Update visible packets tracking
|
||||||
visible_packets = Map.put(socket.assigns.visible_packets, callsign_key, sanitized_packet)
|
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
|
# Push the packet to the client-side JavaScript
|
||||||
socket =
|
socket =
|
||||||
socket
|
socket
|
||||||
|> push_event("new_packet", packet_data)
|
|> push_event("new_packet", packet_data)
|
||||||
|> assign(visible_packets: visible_packets, packet_count: packet_count)
|
|> assign(visible_packets: visible_packets)
|
||||||
|
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
else
|
else
|
||||||
|
|
@ -458,18 +448,6 @@ defmodule AprsWeb.MapLive.Index do
|
||||||
z-index: 1;
|
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 {
|
.locate-button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 10px;
|
left: 10px;
|
||||||
|
|
@ -486,112 +464,6 @@ defmodule AprsWeb.MapLive.Index do
|
||||||
background: #f4f4f4;
|
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 {
|
.aprs-marker {
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
border: none !important;
|
border: none !important;
|
||||||
|
|
@ -613,55 +485,6 @@ defmodule AprsWeb.MapLive.Index do
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="map-overlay">
|
|
||||||
<div class="packet-counter">
|
|
||||||
<span id="packet-count">{@packet_count}</span>
|
|
||||||
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">
|
<button class="locate-button" phx-click="locate_me" title="Find my location">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|
@ -695,16 +518,12 @@ defmodule AprsWeb.MapLive.Index do
|
||||||
end)
|
end)
|
||||||
|> Map.new()
|
|> Map.new()
|
||||||
|
|
||||||
# Get updated packet count
|
|
||||||
packet_count = map_size(visible_packets)
|
|
||||||
|
|
||||||
# Push event to remove old markers from the map
|
# Push event to remove old markers from the map
|
||||||
socket =
|
socket =
|
||||||
socket
|
socket
|
||||||
|> push_event("refresh_markers", %{})
|
|> push_event("refresh_markers", %{})
|
||||||
|> assign(
|
|> assign(
|
||||||
visible_packets: visible_packets,
|
visible_packets: visible_packets,
|
||||||
packet_count: packet_count,
|
|
||||||
packet_age_threshold: one_hour_ago
|
packet_age_threshold: one_hour_ago
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
Loading…
Add table
Reference in a new issue