neiam
/apollos_crib
It's Apollo's Crib
public · Issues · Pulls 1 · Labels · Forks · Compare · Actions failure · Badges · Packages
Log in to mark this repository.
Fix the vision form, and let it pick queries by name
c065e44 · Gabriel Morell · 2026-09-01 15:32
Message
{commit_body(@commit)}
Files changed
modified
apps/room_hermes/lib/room_hermes_web/views/error_view.ex
+6
−4
| 7 | 7 | # "Internal Server Error" |
| 8 | 8 | # end |
| 9 | 9 | |
| 10 | − # By default, Phoenix returns the status message from | |
| 11 | − # the template name. For example, "404.html" becomes | |
| 12 | − # "Not Found". | |
| 13 | − def template_not_found(template, _assigns) do | |
| 10 | + # By default, Phoenix returns the status message from the template name. For | |
| 11 | + # example, "404.html" becomes "Not Found". | |
| 12 | + # | |
| 13 | + # render/2 rather than template_not_found/2, which was Phoenix 1.6's fallback | |
| 14 | + # and is not on the path the endpoint takes -- see RoomSanctumWeb.ErrorView. | |
| 15 | + def render(template, _assigns) do | |
| 14 | 16 | Phoenix.Controller.status_message_from_template(template) |
| 15 | 17 | end |
| 16 | 18 | end |
modified
apps/room_sanctum/lib/room_sanctum/configuration/vision.ex
+19
−0
| 26 | 26 | |> foreign_key_constraint(:user_id) |
| 27 | 27 | |> validate_required([:name, :user_id]) |
| 28 | 28 | |> validate_queries_have_valid_ids() |
| 29 | + |> validate_queries_are_distinct() | |
| 30 | + end | |
| 31 | + | |
| 32 | + # A query belongs on a vision once. Twice is never deliberate -- the same | |
| 33 | + # arrivals drawn twice on the board and two identical markers on the map -- | |
| 34 | + # and the form now takes the queries that are spoken for out of every other | |
| 35 | + # row's picker, so reaching here means something got past that. | |
| 36 | + defp validate_queries_are_distinct(changeset) do | |
| 37 | + ids = | |
| 38 | + changeset | |
| 39 | + |> get_field(:queries) | |
| 40 | + |> List.wrap() | |
| 41 | + |> Enum.map(fn query -> query.data && Map.get(query.data, :query) end) | |
| 42 | + |> Enum.reject(&is_nil/1) | |
| 43 | + | |
| 44 | + case ids -- Enum.uniq(ids) do | |
| 45 | + [] -> changeset | |
| 46 | + _repeated -> add_error(changeset, :queries, "each query can only be on a vision once") | |
| 47 | + end | |
| 29 | 48 | end |
| 30 | 49 | |
| 31 | 50 | def meta_changeset(meta, attrs \\ %{}) do |
modified
apps/room_sanctum/lib/room_sanctum_web/components/core_components.ex
+18
−15
| 139 | 139 | {@rest} |
| 140 | 140 | > |
| 141 | 141 | <p :if={@title} class="flex items-center gap-1.5 text-sm font-semibold leading-6"> |
| 142 | − <.icon :if={@kind == :info} name="hero-information-circle-mini" class="h-4 w-4" /> | |
| 143 | − <.icon :if={@kind == :error} name="hero-exclamation-circle-mini" class="h-4 w-4" /> | |
| 142 | + <.icon :if={@kind == :info} name="fa-circle-info" class="h-4 w-4" /> | |
| 143 | + <.icon :if={@kind == :error} name="fa-circle-exclamation" class="h-4 w-4" /> | |
| 144 | 144 | <%= @title %> |
| 145 | 145 | </p> |
| 146 | 146 | <p class="mt-2 text-sm leading-5"><%= msg %></p> |
| 147 | 147 | <button type="button" class="group absolute top-1 right-1 p-2" aria-label={gettext("close")}> |
| 148 | − <.icon name="hero-x-mark-solid" class="h-5 w-5 opacity-40 group-hover:opacity-70" /> | |
| 148 | + <.icon name="fa-xmark" class="h-5 w-5 opacity-40 group-hover:opacity-70" /> | |
| 149 | 149 | </button> |
| 150 | 150 | </div> |
| 151 | 151 | """ |
| 172 | 172 | phx-connected={hide("#disconnected")} |
| 173 | 173 | hidden |
| 174 | 174 | > |
| 175 | − Attempting to reconnect <.icon name="hero-arrow-path" class="ml-1 h-3 w-3 animate-spin" /> | |
| 175 | + Attempting to reconnect <.icon name="fa-arrows-rotate" class="ml-1 h-3 w-3 animate-spin" /> | |
| 176 | 176 | </.flash> |
| 177 | 177 | """ |
| 178 | 178 | end |
| 295 | 295 | attr :multiple, :boolean, default: false, doc: "the multiple flag for select inputs" |
| 296 | 296 | |
| 297 | 297 | attr :checked_value, :string, doc: "the currently checked value" |
| 298 | + | |
| 298 | 299 | attr :rest, :global, |
| 299 | 300 | include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength |
| 300 | 301 | multiple pattern placeholder readonly required rows size step) |
| 375 | 376 | |
| 376 | 377 | # checked={(@checked_value == opt) || (@field.value == String.to_atom(opt))} |
| 377 | 378 | |
| 378 | − | |
| 379 | 379 | # A card grid instead of a <select>: same single form field, but every choice |
| 380 | 380 | # is visible at once with room for a line explaining what it pulls in. |
| 381 | 381 | # Options are {value, label, description} tuples; the icon is looked up from |
| 601 | 601 | def error(assigns) do |
| 602 | 602 | ~H""" |
| 603 | 603 | <p class="mt-3 flex gap-3 text-sm leading-6 text-rose-600 phx-no-feedback:hidden"> |
| 604 | − <.icon name="hero-exclamation-circle-mini" class="mt-0.5 h-5 w-5 flex-none" /> | |
| 604 | + <.icon name="fa-circle-exclamation" class="mt-0.5 h-5 w-5 flex-none" /> | |
| 605 | 605 | <%= render_slot(@inner_block) %> |
| 606 | 606 | </p> |
| 607 | 607 | """ |
| 752 | 752 | navigate={@navigate} |
| 753 | 753 | class="text-sm font-semibold leading-6 text-zinc-900 hover:text-zinc-700" |
| 754 | 754 | > |
| 755 | − <.icon name="hero-arrow-left-solid" class="h-3 w-3" /> | |
| 755 | + <.icon name="fa-arrow-left" class="h-3 w-3" /> | |
| 756 | 756 | <%= render_slot(@inner_block) %> |
| 757 | 757 | </.link> |
| 758 | 758 | </div> |
| 767 | 767 | be applied by using the `-solid` and `-mini` suffix. |
| 768 | 768 | |
| 769 | 769 | You can customize the size and colors of the icons by setting |
| 770 | − width, height, and background color classes. | |
| 770 | + size and colour classes. | |
| 771 | 771 | |
| 772 | − Icons are extracted from your `assets/vendor/heroicons` directory and bundled | |
| 773 | − within your compiled app.css by the plugin in your `assets/tailwind.config.js`. | |
| 772 | + Font Awesome, which is what this app loads: `<.icon name="fa-trash" />`. The | |
| 773 | + generated code this replaced took heroicon names -- `hero-trash` -- and drew | |
| 774 | + them as `<span class="hero-trash">`, which needs a heroicons dependency and a | |
| 775 | + Tailwind plugin to become an SVG. This app has never had either, so every | |
| 776 | + icon rendered as an empty span: the vision form's add and remove buttons, the | |
| 777 | + flash messages' close and status marks, all of them. | |
| 774 | 778 | |
| 775 | 779 | ## Examples |
| 776 | 780 | |
| 777 | − <.icon name="hero-x-mark-solid" /> | |
| 778 | − <.icon name="hero-arrow-path" class="ml-1 w-3 h-3 animate-spin" /> | |
| 781 | + <.icon name="fa-xmark" /> | |
| 782 | + <.icon name="fa-arrows-rotate" class="ml-1 w-3 h-3 animate-spin" /> | |
| 779 | 783 | """ |
| 780 | 784 | attr :name, :string, required: true |
| 781 | 785 | attr :class, :string, default: nil |
| 782 | 786 | |
| 783 | − def icon(%{name: "hero-" <> _} = assigns) do | |
| 787 | + def icon(assigns) do | |
| 784 | 788 | ~H""" |
| 785 | − <span class={[@name, @class]} /> | |
| 789 | + <span class={["fa-solid fa-fw", @name, @class]} /> | |
| 786 | 790 | """ |
| 787 | 791 | end |
| 788 | 792 |
| 915 | 919 | <i :if={@tint not in [nil, ""]} class={"fa-solid fa-circle text-#{@tint}-500 #{@class}"}></i> |
| 916 | 920 | """ |
| 917 | 921 | end |
| 918 | − | |
| 919 | 922 | end |
modified
apps/room_sanctum/lib/room_sanctum_web/components/layouts/root_public.html.heex
+1
−0
| 4 | 4 | <meta http-equiv="X-UA-Compatible" content="IE=edge"/> |
| 5 | 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0"/> |
| 6 | 6 | <%= csrf_meta_tag() %> |
| 7 | + <.basemap_meta /> | |
| 7 | 8 | <%= live_title_tag assigns[:page_title] || "RoomSanctum", suffix: " · Apollos Crib" %> |
| 8 | 9 | <link phx-track-static rel="stylesheet" href={Routes.static_path(@conn, "/assets/app.css")}/> |
| 9 | 10 | <script defer phx-track-static type="text/javascript" src={Routes.static_path(@conn, "/assets/app.js")}></script> |
modified
apps/room_sanctum/lib/room_sanctum_web/components/layouts/root_public_afterdark.html.heex
+1
−0
| 4 | 4 | <meta http-equiv="X-UA-Compatible" content="IE=edge"/> |
| 5 | 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0"/> |
| 6 | 6 | <%= csrf_meta_tag() %> |
| 7 | + <.basemap_meta /> | |
| 7 | 8 | <%= live_title_tag assigns[:page_title] || "RoomSanctum", suffix: " · Apollos Crib" %> |
| 8 | 9 | <link phx-track-static rel="stylesheet" href={Routes.static_path(@conn, "/assets/app.css")}/> |
| 9 | 10 | <script defer phx-track-static type="text/javascript" src={Routes.static_path(@conn, "/assets/app.js")}></script> |
modified
apps/room_sanctum/lib/room_sanctum_web/components/layouts/root_public_her.html.heex
+1
−0
Click to load diff…
modified
apps/room_sanctum/lib/room_sanctum_web/components/layouts/root_public_inky.html.heex
+1
−0
Click to load diff…
added
apps/room_sanctum/lib/room_sanctum_web/components/layouts/root_public_map.html.heex
+19
−0
Click to load diff…
modified
apps/room_sanctum/lib/room_sanctum_web/components/query_geospatial_map.ex
+10
−1
Click to load diff…
added
apps/room_sanctum/lib/room_sanctum_web/live/cfg_pythiae_live/public_map.ex
+92
−0
Click to load diff…
added
apps/room_sanctum/lib/room_sanctum_web/live/cfg_pythiae_live/public_map.html.heex
+27
−0
Click to load diff…
modified
apps/room_sanctum/lib/room_sanctum_web/live/cfg_pythiae_live/show.html.heex
+2
−0
Click to load diff…
modified
apps/room_sanctum/lib/room_sanctum_web/live/cfg_vision_live/form_component.ex
+196
−88
Click to load diff…
modified
apps/room_sanctum/lib/room_sanctum_web/live/cfg_vision_live/form_component.html.heex
+2
−2
Click to load diff…
modified
apps/room_sanctum/lib/room_sanctum_web/router.ex
+5
−0
Click to load diff…
modified
apps/room_sanctum/lib/room_sanctum_web/views/error_view.ex
+8
−4
Click to load diff…
added
apps/room_sanctum/test/room_sanctum/vision_distinct_queries_test.exs
+44
−0
Click to load diff…
added
apps/room_sanctum/test/room_sanctum_web/components/icon_test.exs
+38
−0
Click to load diff…
added
apps/room_sanctum/test/room_sanctum_web/live/pythiae_public_map_test.exs
+69
−0
Click to load diff…
added
apps/room_sanctum/test/room_sanctum_web/live/vision_form_queries_test.exs
+288
−0
Click to load diff…
modified
apps/room_sanctum/test/room_sanctum_web/views/error_view_test.exs
+12
−0
Click to load diff…
Parents: 31a0a77