Compare commits

..

1 commit

Author SHA1 Message Date
a92bf0a8c3
run migrations via entrypoint script
All checks were successful
continuous-integration/drone/push Build is passing
2025-12-04 18:02:47 +01:00
7 changed files with 53 additions and 35 deletions

View file

@ -90,4 +90,4 @@ USER nobody
# above and adding an entrypoint. See https://github.com/krallin/tini for details # above and adding an entrypoint. See https://github.com/krallin/tini for details
# ENTRYPOINT ["/tini", "--"] # ENTRYPOINT ["/tini", "--"]
CMD ["/app/bin/server"] ENTRYPOINT ["/app/bin/docker-entrypoint.sh"]

View file

@ -255,7 +255,7 @@ For testing the production Docker build locally:
docker compose -f docker-compose.prod.yml up docker compose -f docker-compose.prod.yml up
``` ```
5. **Run database migrations:** 5. **Database migrations run automatically** on app start. For manual migration:
```bash ```bash
docker compose -f docker-compose.prod.yml exec app /app/bin/mv eval "Mv.Release.migrate" docker compose -f docker-compose.prod.yml exec app /app/bin/mv eval "Mv.Release.migrate"
``` ```

View file

@ -474,7 +474,6 @@ defmodule MvWeb.CoreComponents do
slot :col, required: true do slot :col, required: true do
attr :label, :string attr :label, :string
attr :col_click, :any, doc: "optional column-specific click handler that overrides row_click"
end end
slot :action, doc: "the slot for showing user actions in the last table column" slot :action, doc: "the slot for showing user actions in the last table column"
@ -510,11 +509,8 @@ defmodule MvWeb.CoreComponents do
<tr :for={row <- @rows} id={@row_id && @row_id.(row)}> <tr :for={row <- @rows} id={@row_id && @row_id.(row)}>
<td <td
:for={col <- @col} :for={col <- @col}
phx-click={ phx-click={@row_click && @row_click.(row)}
(col[:col_click] && col[:col_click].(@row_item.(row))) || class={["max-w-xs truncate", @row_click && "hover:cursor-pointer"]}
(@row_click && @row_click.(row))
}
class={["max-w-xs truncate", (col[:col_click] || @row_click) && "hover:cursor-pointer"]}
> >
{render_slot(col, @row_item.(row))} {render_slot(col, @row_item.(row))}
</td> </td>

View file

@ -1082,16 +1082,6 @@ defmodule MvWeb.MemberLive.Index do
|> Enum.map(&format_member_email/1) |> Enum.map(&format_member_email/1)
end end
@doc """
Returns a JS command to toggle member selection when clicking the checkbox column.
Used as `col_click` handler to ensure clicking anywhere in the checkbox column
toggles the checkbox instead of navigating to the member details.
"""
def checkbox_column_click(member) do
JS.push("select_member", value: %{id: member.id})
end
# Formats a member's email in the format "First Last <email>" # Formats a member's email in the format "First Last <email>"
# Used for copy_emails feature and mailto links to create email-client-friendly format. # Used for copy_emails feature and mailto links to create email-client-friendly format.
def format_member_email(member) do def format_member_email(member) do

View file

@ -65,7 +65,6 @@
<!-- <:col :let={member} label="Id">{member.id}</:col> --> <!-- <:col :let={member} label="Id">{member.id}</:col> -->
<:col <:col
:let={member} :let={member}
col_click={&MvWeb.MemberLive.Index.checkbox_column_click/1}
label={ label={
~H""" ~H"""
<.input <.input
@ -82,7 +81,11 @@
<.input <.input
type="checkbox" type="checkbox"
name={member.id} name={member.id}
phx-click="select_member"
phx-value-id={member.id}
checked={MapSet.member?(@selected_members, member.id)} checked={MapSet.member?(@selected_members, member.id)}
phx-capture-click
phx-stop-propagation
aria-label={gettext("Select member")} aria-label={gettext("Select member")}
role="checkbox" role="checkbox"
/> />

View file

@ -0,0 +1,9 @@
#!/bin/sh
set -e
echo "==> Running database migrations..."
/app/bin/migrate
echo "==> Starting application..."
exec /app/bin/server

View file

@ -285,9 +285,14 @@ defmodule MvWeb.MemberLive.IndexTest do
conn = conn_with_oidc_user(conn) conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members") {:ok, view, _html} = live(conn, "/members")
# Select two members by sending the select_member event directly # Select two members
render_click(view, "select_member", %{"id" => member1.id}) view
render_click(view, "select_member", %{"id" => member2.id}) |> element("[phx-click='select_member'][phx-value-id='#{member1.id}']")
|> render_click()
view
|> element("[phx-click='select_member'][phx-value-id='#{member2.id}']")
|> render_click()
# Trigger copy_emails event # Trigger copy_emails event
view |> element("#copy-emails-btn") |> render_click() view |> element("#copy-emails-btn") |> render_click()
@ -331,8 +336,10 @@ defmodule MvWeb.MemberLive.IndexTest do
conn = conn_with_oidc_user(conn) conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members") {:ok, view, _html} = live(conn, "/members")
# Select member with umlauts by sending the select_member event directly # Select member with umlauts
render_click(view, "select_member", %{"id" => member3.id}) view
|> element("[phx-click='select_member'][phx-value-id='#{member3.id}']")
|> render_click()
# Trigger copy_emails event - should not crash # Trigger copy_emails event - should not crash
view |> element("#copy-emails-btn") |> render_click() view |> element("#copy-emails-btn") |> render_click()
@ -348,8 +355,10 @@ defmodule MvWeb.MemberLive.IndexTest do
conn = conn_with_oidc_user(conn) conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members") {:ok, view, _html} = live(conn, "/members")
# Select a member by sending the select_member event directly # Select a member
render_click(view, "select_member", %{"id" => member1.id}) view
|> element("[phx-click='select_member'][phx-value-id='#{member1.id}']")
|> render_click()
# Delete the member from the database # Delete the member from the database
Ash.destroy!(member1) Ash.destroy!(member1)
@ -370,9 +379,14 @@ defmodule MvWeb.MemberLive.IndexTest do
conn = conn_with_oidc_user(conn) conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members") {:ok, view, _html} = live(conn, "/members")
# Select two members by sending the select_member event directly # Select two members
render_click(view, "select_member", %{"id" => member1.id}) view
render_click(view, "select_member", %{"id" => member2.id}) |> element("[phx-click='select_member'][phx-value-id='#{member1.id}']")
|> render_click()
view
|> element("[phx-click='select_member'][phx-value-id='#{member2.id}']")
|> render_click()
# Get the socket state to verify the formatted email string # Get the socket state to verify the formatted email string
state = :sys.get_state(view.pid) state = :sys.get_state(view.pid)
@ -401,8 +415,10 @@ defmodule MvWeb.MemberLive.IndexTest do
{:ok, view, _html} = live(conn, "/members") {:ok, view, _html} = live(conn, "/members")
# Select the test member by sending the select_member event directly # Select the test member
render_click(view, "select_member", %{"id" => test_member.id}) view
|> element("[phx-click='select_member'][phx-value-id='#{test_member.id}']")
|> render_click()
# The format should be "Test Format <test.format@example.com>" # The format should be "Test Format <test.format@example.com>"
# We verify this by checking the flash shows 1 email was copied # We verify this by checking the flash shows 1 email was copied
@ -425,8 +441,10 @@ defmodule MvWeb.MemberLive.IndexTest do
conn = conn_with_oidc_user(conn) conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members") {:ok, view, _html} = live(conn, "/members")
# Select a member by sending the select_member event directly # Select a member
render_click(view, "select_member", %{"id" => member1.id}) view
|> element("[phx-click='select_member'][phx-value-id='#{member1.id}']")
|> render_click()
# Button should now be visible # Button should now be visible
assert has_element?(view, "#copy-emails-btn") assert has_element?(view, "#copy-emails-btn")
@ -439,8 +457,10 @@ defmodule MvWeb.MemberLive.IndexTest do
conn = conn_with_oidc_user(conn) conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members") {:ok, view, _html} = live(conn, "/members")
# Select a member by sending the select_member event directly # Select a member
render_click(view, "select_member", %{"id" => member1.id}) view
|> element("[phx-click='select_member'][phx-value-id='#{member1.id}']")
|> render_click()
# Click copy button # Click copy button
view |> element("#copy-emails-btn") |> render_click() view |> element("#copy-emails-btn") |> render_click()