Adds a new globally-scoped, owner-mutable rover-mission tracker: - /rover-planning paginated table (LiveTable) with View/Edit/Delete - /rover-planning/new + /:id/edit form: name, band, antenna heights, notes, "only check against known good locations" toggle (default on), and a dynamic list of stationary stations entered as callsigns, Maidenhead grids, or lat,lon pairs (Station changeset geocodes via LocationResolver, lat/lon stays editable after add) - /rover-planning/:id show page renders the station list, scope, and a matrix of computed path profiles (distance, min clearance, diffraction, verdict) populated as the worker completes each pairing After save, RoverPlanning enqueues one RoverPathProfileWorker job per (rover-location × station) pairing. The worker mirrors PathLive's synchronous compute (ElevationClient + TerrainAnalysis at the mission's band + heights) and stores the result on the matching path row. PubSub broadcast on completion lets the show page live-refresh. Admins can edit/delete any mission; owners can edit their own.
56 lines
1.5 KiB
Elixir
56 lines
1.5 KiB
Elixir
defmodule Microwaveprop.RoverPlanning.Path do
|
|
@moduledoc """
|
|
A computed (or pending) path-profile result for one rover-location
|
|
→ station pairing inside a mission. `result` holds the same shape
|
|
produced by `MicrowavepropWeb.PathLive`'s synchronous compute, so
|
|
the show page can render it identically.
|
|
"""
|
|
use Ecto.Schema
|
|
|
|
import Ecto.Changeset
|
|
|
|
alias Microwaveprop.Rover.Location
|
|
alias Microwaveprop.RoverPlanning.Mission
|
|
alias Microwaveprop.RoverPlanning.Station
|
|
|
|
@statuses [:pending, :computing, :complete, :failed]
|
|
|
|
@primary_key {:id, :binary_id, autogenerate: true}
|
|
@foreign_key_type :binary_id
|
|
schema "rover_mission_paths" do
|
|
field :status, Ecto.Enum, values: @statuses, default: :pending
|
|
field :result, :map
|
|
field :error, :string
|
|
field :computed_at, :utc_datetime
|
|
|
|
belongs_to :mission, Mission
|
|
belongs_to :rover_location, Location
|
|
belongs_to :station, Station
|
|
|
|
timestamps(type: :utc_datetime)
|
|
end
|
|
|
|
@type t :: %__MODULE__{}
|
|
|
|
@spec statuses() :: [atom()]
|
|
def statuses, do: @statuses
|
|
|
|
@spec changeset(t() | Ecto.Changeset.t(), map()) :: Ecto.Changeset.t()
|
|
def changeset(path, attrs) do
|
|
path
|
|
|> cast(attrs, [
|
|
:status,
|
|
:result,
|
|
:error,
|
|
:computed_at,
|
|
:mission_id,
|
|
:rover_location_id,
|
|
:station_id
|
|
])
|
|
|> validate_required([:mission_id, :rover_location_id, :station_id, :status])
|
|
|> validate_inclusion(:status, @statuses)
|
|
|> unique_constraint([:mission_id, :rover_location_id, :station_id],
|
|
name: :rover_mission_paths_unique
|
|
)
|
|
end
|
|
end
|