Complete staff translations and release verification

This commit is contained in:
SimpleTest 2026-08-03 13:35:45 +03:00
parent cf283db350
commit 4c52c8bf3d
12 changed files with 7565 additions and 4440 deletions

View File

@ -1978,3 +1978,14 @@ complete.
- Production capacity, minimum CPU/RAM, database HA topology, and autoscaling
thresholds remain unknown until representative target-environment
measurements exist.
# 2026-08-03 release-candidate quality gate
The isolated full repository quality run completed successfully on 2026-08-03.
It covered shell, Compose, Helm, source-secret and infrastructure checks; Elixir
format, compilation with warnings as errors, Gettext catalog freshness, xref,
Credo, Sobelow, Dialyzer, Hex audit and the full ExUnit suite; pinned runtime
image smoke tests and vulnerability scans; and production release, rollback and
migration-policy drills. The transient Compose project, database volume and
audit images were removed by the run's cleanup trap. This verifies the local
candidate only; production browser E2E must be repeated after that candidate is
promoted.

View File

@ -974,8 +974,10 @@ defmodule WhoNeedHelpWeb.ModerationLive do
</div>
<span class="badge badge-outline">{status_label(proposal.mode)}</span>
<span class={["badge", status_class(proposal.status)]}>{status_label(proposal.status)}</span>
<span class="text-sm text-base-content/60">{gettext("%{count} votes",
count: proposal.vote_count
<span class="text-sm text-base-content/60">{ngettext(
"%{count} vote",
"%{count} votes",
proposal.vote_count
)}</span>
<.icon name="hero-chevron-down" class="size-5 transition group-open:rotate-180" />
</summary>

View File

@ -112,9 +112,15 @@ defmodule WhoNeedHelpWeb.SupportOperationLive do
end
defp assignment_options(users) do
[{gettext("Unassigned"), ""} | Enum.map(users, &{&1.display_name || &1.email, &1.id})]
[{gettext("Unassigned"), ""} | Enum.map(users, &{staff_identity_label(&1), &1.id})]
end
defp staff_identity_label(%{display_name: name, email: email})
when is_binary(name) and name != "" and name != email,
do: gettext("%{name} — %{email}", name: name, email: email)
defp staff_identity_label(%{email: email}), do: email
defp queue_path(:support), do: ~p"/support/operations?queue=support"
defp queue_path(:legal), do: ~p"/support/operations?queue=legal"

View File

@ -231,10 +231,16 @@ defmodule WhoNeedHelpWeb.SupportOperationsLive do
{gettext("Any assignee"), ""},
{gettext("Unassigned"), "unassigned"},
{gettext("Assigned to me"), "mine"}
| Enum.map(users, fn user -> {user.display_name || user.email, user.id} end)
| Enum.map(users, fn user -> {staff_identity_label(user), user.id} end)
]
end
defp staff_identity_label(%{display_name: name, email: email})
when is_binary(name) and name != "" and name != email,
do: gettext("%{name} — %{email}", name: name, email: email)
defp staff_identity_label(%{email: email}), do: email
defp support_kind(:account_access), do: gettext("Account access")
defp support_kind(:technical_issue), do: gettext("Technical issue")
defp support_kind(:safety_concern), do: gettext("Safety concern")

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -167,16 +167,19 @@ git cat-file -e "$commit^{commit}" 2>/dev/null || {
exit 1
}
while IFS= read -r changed_path; do
case "$changed_path" in
lib/mix/tasks/wnh.staging_full_e2e.ex | e2e/tests/activity-moderation.spec.ts | e2e/tests/helpers.ts | test/who_need_help/trust_safety_test.exs)
;;
*)
echo "Production E2E refused: unexpected local change relative to $commit: $changed_path" >&2
# The deployed application is always archived from its exact remote commit.
# Local development may legitimately be ahead of production; those files never
# enter either runner image. Only these explicit verifier overlays are copied
# below, and their hashes are retained with the evidence bundle.
for verifier_path in \
lib/mix/tasks/wnh.staging_full_e2e.ex \
e2e/tests/activity-moderation.spec.ts \
e2e/tests/helpers.ts; do
if [[ ! -f "$ROOT/$verifier_path" ]]; then
echo "Production E2E verifier is unavailable: $verifier_path" >&2
exit 1
;;
esac
done < <(git diff --name-only "$commit")
fi
done
confirmation="whoneedhelp.com:${commit}:${database}:${RUN_ID}:full-browser-e2e"

View File

@ -1463,6 +1463,7 @@ echo "Running Elixir format, compiler, xref, Credo, Sobelow, Dialyzer, and Hex a
docker run --rm "$quality_image" sh -euc '
mix format --check-formatted
mix compile --force --warnings-as-errors
mix gettext.extract --check-up-to-date
mix xref graph --label compile-connected --fail-above 0
mix credo --strict --min-priority high
mix sobelow --exit --strict --private --skip

View File

@ -407,6 +407,18 @@ defmodule WhoNeedHelpWeb.SupportControllerTest do
test "renders separate support and removal queues for a moderator", %{conn: conn} do
moderator = staff_user_fixture([:support, :legal])
first_duplicate =
staff_user_fixture([:support, :legal],
display_name: "Same operator",
email: unique_user_email()
)
second_duplicate =
staff_user_fixture([:support, :legal],
display_name: "Same operator",
email: unique_user_email()
)
{:ok, support_request} =
WhoNeedHelp.Support.create_request(nil, %{
"kind" => "technical_issue",
@ -447,6 +459,8 @@ defmodule WhoNeedHelpWeb.SupportControllerTest do
assert response =~ "Support requests"
assert response =~ "Legal and removal"
assert response =~ "Same operator — #{first_duplicate.email}"
assert response =~ "Same operator — #{second_duplicate.email}"
assert has_element?(queue_view, "#support-row-#{support_request.id}")
refute response =~ "Operator action"
@ -471,6 +485,8 @@ defmodule WhoNeedHelpWeb.SupportControllerTest do
) == 1
assert has_element?(removal_view, "#removal-moderation-#{removal_notice.id}")
assert removal_response =~ "Same operator — #{first_duplicate.email}"
assert removal_response =~ "Same operator — #{second_duplicate.email}"
assert Enum.count(
LazyHTML.query(

View File

@ -1556,12 +1556,14 @@ defmodule WhoNeedHelpWeb.MutualAidLiveTest do
"message_id" => message.id
})
{:ok, _proposal} =
{:ok, proposal} =
Catalog.propose(user_scope_fixture(requester), %{
"proposed_name" => "Bicycle repair",
"reason" => "Urgent roadside bicycle repairs need a reusable category."
})
{:ok, _vote} = Catalog.vote(user_scope_fixture(requester), proposal.id)
{:ok, view, html} = live(conn, ~p"/moderation")
assert html =~ "Trust and safety"
assert html =~ "Reports"
@ -1592,6 +1594,8 @@ defmodule WhoNeedHelpWeb.MutualAidLiveTest do
proposal_html = render_patch(view, ~p"/moderation?queue=proposals")
assert proposal_html =~ "Bicycle repair"
assert proposal_html =~ "1 vote"
refute proposal_html =~ "1 votes"
end
test "message reports expose parent activity moderation and switch to restore", %{