Tint the current vision on a pythiae, and stop it crashing the page

7e1a811 · Gabriel Morell · 2026-08-11 20:19

12 files +66 -6
Message
{commit_body(@commit)}

Files changed

modified apps/room_sanctum/lib/room_sanctum_web/live/cfg_pythiae_live/show.ex
+10 −0
@@ -109,6 +109,16 @@ defmodule RoomSanctumWeb.PythiaeLive.Show do
109 109 end
110 110 end
111 111
112 + @doc """
113 + The vision with this id, or nil.
114 +
115 + get_by_id/2 hands back the id itself when the list is empty and nil when the
116 + id is not in it, so `get_by_id(...).name` raises three ways: no visions
117 + loaded, an id pointing at a deleted vision, and no current vision set at all.
118 + A pythiae that has never had one would take the whole page down.
119 + """
120 + def vision_by_id(id, visions), do: Enum.find(visions, &(&1.id == id))
121 +
112 122 def get_by_id(id, array) do
113 123 case array do
114 124 [] -> id
modified apps/room_sanctum/lib/room_sanctum_web/live/cfg_pythiae_live/show.html.heex
+14 −6
@@ -37,10 +37,10 @@
37 37 >
38 38 <i class={"fas fa-fw fa-star #{if v == @pythiae.curr_vision, do: "text-accent"}"}></i>
39 39 </button>
40 + <% vision = vision_by_id(v, @visions) %>
40 41 <a href={Routes.vision_show_path(@socket, :show, v)} class="text-sm hover:underline btn btn-sm btn-secondary gap-2">
41 − <% vision = get_by_id(v, @visions) %>
42 − <.tint_dot tint={vision.meta && vision.meta.tint} />
43 − <%= vision.name %>
42 + <.tint_dot tint={vision && vision.meta && vision.meta.tint} />
43 + <%= (vision && vision.name) || "Vision ##{v}" %>
44 44 </a>
45 45 </div>
46 46 <% end%>
@@ -86,9 +86,17 @@
86 86 <div class="card-body">
87 87 <h3 class="card-title">Current Vision</h3>
88 88 <p>
89 − <a href={Routes.vision_show_path(@socket, :show, @pythiae.curr_vision)} class="text-sm hover:underline btn btn-secondary">
90 − <%= get_by_id(@pythiae.curr_vision, @visions).name %>
91 − </a>
89 + <% current = vision_by_id(@pythiae.curr_vision, @visions) %>
90 + <%= if current do %>
91 + <a href={Routes.vision_show_path(@socket, :show, current.id)} class="text-sm hover:underline btn btn-secondary gap-2">
92 + <.tint_dot tint={current.meta && current.meta.tint} />
93 + <%= current.name %>
94 + </a>
95 + <% else %>
96 + <span class="text-sm opacity-60">
97 + <%= if @pythiae.curr_vision, do: "Vision ##{@pythiae.curr_vision} is gone", else: "None set" %>
98 + </span>
99 + <% end %>
92 100 </p>
93 101 </div>
94 102 </div>
added apps/room_sanctum/test/room_sanctum_web/live/pythiae_vision_test.exs
+42 −0
@@ -0,0 +1,42 @@
1 +defmodule RoomSanctumWeb.PythiaeVisionTest do
2 + @moduledoc """
3 + Resolving the visions a pythiae points at.
4 +
5 + The page itself cannot be rendered from this app's tests -- it reads
6 + users_rabbit, a room_hermes table that is not migrated into room_sanctum's
7 + test database -- so these cover the lookup the template depends on, which is
8 + where it was going wrong.
9 + """
10 + use ExUnit.Case, async: true
11 +
12 + alias RoomSanctumWeb.PythiaeLive.Show
13 +
14 + defp vision(id, name), do: %{id: id, name: name, meta: %{tint: "teal"}}
15 +
16 + describe "vision_by_id/2" do
17 + test "finds the vision" do
18 + assert Show.vision_by_id(7, [vision(7, "Commute")]).name == "Commute"
19 + end
20 +
21 + test "is nil when the list is empty" do
22 + # get_by_id/2 hands back the id itself here, which is an integer, and
23 + # `.name` on it takes the page down
24 + assert Show.vision_by_id(7, []) == nil
25 + assert Show.get_by_id(7, []) == 7
26 + end
27 +
28 + test "is nil for an id pointing at a vision that is gone" do
29 + assert Show.vision_by_id(99, [vision(7, "Commute")]) == nil
30 + end
31 +
32 + test "is nil when no current vision has been set" do
33 + assert Show.vision_by_id(nil, [vision(7, "Commute")]) == nil
34 + end
35 +
36 + test "picks the right one out of several" do
37 + visions = [vision(1, "A"), vision(2, "B"), vision(3, "C")]
38 +
39 + assert Show.vision_by_id(2, visions).name == "B"
40 + end
41 + end
42 +end

Parents: ae36961