feat(rover-planning): inline per-group delete, drop standalone site list
The 'Rover sites' card no longer renders the long list of every site — each rover-location now appears once as a path-profile group heading, which carries its own delete button next to the n/m progress text. The add-site form stays in place.
This commit is contained in:
parent
c2a23d1840
commit
327b4fc561
2 changed files with 42 additions and 43 deletions
|
|
@ -374,55 +374,17 @@ defmodule MicrowavepropWeb.RoverPlanningLive.Show do
|
|||
|
||||
<div class="card bg-base-100 border border-base-300 p-4 mb-4">
|
||||
<div class="flex items-center justify-between mb-2 gap-2 flex-wrap">
|
||||
<h3 class="font-semibold">Rover sites</h3>
|
||||
<h3 class="font-semibold">Add rover site</h3>
|
||||
<span class="text-xs text-base-content/60">
|
||||
{length(@rover_sites)} site(s) — paths recompute on add/remove
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<ul :if={@rover_sites != []} class="text-sm space-y-1 mb-3">
|
||||
<%!--
|
||||
`flex` (no `flex-wrap`) + `min-w-0` on the row, plus `shrink-0`
|
||||
on the identifier columns and `truncate flex-1 min-w-0` on the
|
||||
notes cell, keeps the row to a single line: long notes get
|
||||
ellipsised instead of pushing the trash button onto a new line.
|
||||
`title={site.notes}` preserves the full text on hover.
|
||||
--%>
|
||||
<li :for={site <- @rover_sites} class="flex items-center gap-2 min-w-0">
|
||||
<span class="font-mono shrink-0">
|
||||
{Maidenhead.from_latlon(site.lat, site.lon, 10)}
|
||||
</span>
|
||||
<span class="text-base-content/60 font-mono text-xs shrink-0">
|
||||
({Float.round(site.lat, 4)}, {Float.round(site.lon, 4)})
|
||||
</span>
|
||||
<span
|
||||
:if={site.notes && site.notes != ""}
|
||||
class="text-base-content/60 text-xs truncate min-w-0 flex-1"
|
||||
title={site.notes}
|
||||
>
|
||||
· {site.notes}
|
||||
</span>
|
||||
<button
|
||||
:if={can_delete_site?(assigns, site)}
|
||||
type="button"
|
||||
phx-click="delete_rover_site"
|
||||
phx-value-id={site.id}
|
||||
data-confirm="Remove this rover site? This affects every mission that uses it."
|
||||
class="btn btn-ghost btn-xs text-error ml-auto shrink-0"
|
||||
title="Remove rover site"
|
||||
>
|
||||
<.icon name="hero-trash" class="w-4 h-4" />
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p :if={@rover_sites == []} class="text-sm text-base-content/60 mb-3">
|
||||
No rover sites match this mission's scope yet — add one below.
|
||||
</p>
|
||||
|
||||
<%!--
|
||||
The add form takes the same flexible input the station inputs use:
|
||||
callsign, Maidenhead grid, or `lat, lon`. Sign-in required.
|
||||
The site list itself is rendered inline as path-profile group
|
||||
headings below — each heading carries its own delete button.
|
||||
--%>
|
||||
<form
|
||||
:if={@current_scope && @current_scope.user}
|
||||
|
|
@ -489,8 +451,21 @@ defmodule MicrowavepropWeb.RoverPlanningLive.Show do
|
|||
· {location.notes}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-xs text-base-content/70">
|
||||
{group_progress(group_paths)}
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs text-base-content/70">
|
||||
{group_progress(group_paths)}
|
||||
</span>
|
||||
<button
|
||||
:if={location && location.id && can_delete_site?(assigns, location)}
|
||||
type="button"
|
||||
phx-click="delete_rover_site"
|
||||
phx-value-id={location.id}
|
||||
data-confirm="Remove this rover site? This affects every mission that uses it."
|
||||
class="btn btn-ghost btn-xs text-error"
|
||||
title="Remove rover site"
|
||||
>
|
||||
<.icon name="hero-trash" class="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -398,6 +398,30 @@ defmodule MicrowavepropWeb.RoverPlanningLiveTest do
|
|||
assert Repo.aggregate(Location, :count) == 0
|
||||
end
|
||||
|
||||
test "delete button lives inside the path-profile group heading, not above it",
|
||||
%{conn: conn} do
|
||||
user = AccountsFixtures.user_fixture()
|
||||
mission = create_mission(user, "Per-group delete mission")
|
||||
conn = log_in_user(conn, user)
|
||||
|
||||
[site] = Repo.all(Location)
|
||||
|
||||
{:ok, lv, html} = live(conn, ~p"/rover-planning/#{mission.id}")
|
||||
|
||||
# The standalone "Rover sites" list is gone — the heading now reads
|
||||
# "Add rover site" (still the form). Each path-profile group
|
||||
# heading carries its own per-location delete button. Asserting on
|
||||
# the structural ancestor (`[data-rover-group]`) ensures the button
|
||||
# is INSIDE the grouping, not in some legacy list above it.
|
||||
refute html =~ "Rover sites</h3>"
|
||||
assert html =~ "Add rover site</h3>"
|
||||
|
||||
assert has_element?(
|
||||
lv,
|
||||
"[data-rover-group] button[phx-click='delete_rover_site'][phx-value-id='#{site.id}']"
|
||||
)
|
||||
end
|
||||
|
||||
test "add_rover_site rejects whitespace-only input with a flash error",
|
||||
%{conn: conn} do
|
||||
user = AccountsFixtures.user_fixture()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue