Team View: mailto: link for non-admin members in 'E-mail an Auswahl senden' #75

Open
opened 2026-05-25 11:23:24 +00:00 by mAi · 1 comment
Collaborator

m's report (2026-05-25 12:33)

On the "Team View" We should change the E-mail an Auswahl senden logic. We currently have two: one in the bottom once i select some manually, once for all the filtered items. And it opens a form for emails - its okay because I am admin but other members should just get the link directly for their mailclient.

Scope

The Team View currently exposes two "E-Mail an Auswahl senden" actions:

  1. Bottom action bar — appears when the user manually selects rows; sends to the manually selected subset.
  2. Filter bar — sends to all currently filtered rows.

Both currently open an in-app compose form (admin-only mail sender). For non-admin users this is the wrong affordance — they should get a regular mailto: link that opens their own mail client with the recipient list pre-filled.

What to do

  • Detect the current user's admin status (existing helper / context).
  • Admin path stays as-is: open the compose form for both buttons.
  • Non-admin path: replace the form trigger with a mailto: link.
    • to: = the comma-joined recipient e-mails (URL-encoded), respecting the same source (manual selection vs. filter set) that drives each button.
    • Subject / body left empty (or a sensible firm-agnostic default — coder picks).
    • Use <a href="mailto:..."> rather than JS-opening a window.location — the native handler is the more reliable affordance and respects the user's default mail client.
  • Both buttons (bottom + filter) must behave the same way for the non-admin path.
  • Keep the existing labels ("E-Mail an Auswahl senden" / "E-Mail an Auswahl senden"), DE primary; existing EN i18n stays.

Files most likely touched

  • frontend/src/projects-detail.tsx → Team tab section, or wherever the Team View bottom + filter bars live (might be a dedicated frontend/src/team-view.* — verify before editing).
  • frontend/src/client/team-view.ts (or equivalent client file).
  • The existing compose-form modal stays untouched for the admin path.

Hard rules

  • Don't gut the admin compose flow.
  • Don't add a separate "toggle" — the role check picks the path automatically.
  • mailto: recipient list URL-encoded correctly (commas, ? if subject added).
  • go build ./... && go test ./internal/... && cd frontend && bun run build clean.
  • Branch: mai/<worker>/team-view-mailto-non-admin.

Out of scope

  • Adding subject/body templating beyond a static default.
  • BCC vs To choice (default to To unless the existing admin form does something different — match it).
  • Recipient list trimming when there are too many (mailto: URL length limits) — flag in completion report if you hit it; don't block on it.

Reporting

mai report completed with branch + SHAs + the exact UX path: open a project → Team tab → as non-admin, click either "E-Mail an Auswahl senden" button → see mail client open with recipients pre-filled.

## m's report (2026-05-25 12:33) > On the "Team View" We should change the E-mail an Auswahl senden logic. We currently have two: one in the bottom once i select some manually, once for all the filtered items. And it opens a form for emails - its okay because I am admin but other members should just get the link directly for their mailclient. ## Scope The Team View currently exposes two "E-Mail an Auswahl senden" actions: 1. **Bottom action bar** — appears when the user manually selects rows; sends to the manually selected subset. 2. **Filter bar** — sends to all currently filtered rows. Both currently open an in-app compose form (admin-only mail sender). For non-admin users this is the wrong affordance — they should get a regular `mailto:` link that opens their own mail client with the recipient list pre-filled. ## What to do - Detect the current user's admin status (existing helper / context). - **Admin path** stays as-is: open the compose form for both buttons. - **Non-admin path**: replace the form trigger with a `mailto:` link. - `to:` = the comma-joined recipient e-mails (URL-encoded), respecting the same source (manual selection vs. filter set) that drives each button. - Subject / body left empty (or a sensible firm-agnostic default — coder picks). - Use `<a href="mailto:...">` rather than JS-opening a `window.location` — the native handler is the more reliable affordance and respects the user's default mail client. - Both buttons (bottom + filter) must behave the same way for the non-admin path. - Keep the existing labels ("E-Mail an Auswahl senden" / "E-Mail an Auswahl senden"), DE primary; existing EN i18n stays. ## Files most likely touched - `frontend/src/projects-detail.tsx` → Team tab section, or wherever the Team View bottom + filter bars live (might be a dedicated `frontend/src/team-view.*` — verify before editing). - `frontend/src/client/team-view.ts` (or equivalent client file). - The existing compose-form modal stays untouched for the admin path. ## Hard rules - Don't gut the admin compose flow. - Don't add a separate "toggle" — the role check picks the path automatically. - `mailto:` recipient list URL-encoded correctly (commas, `?` if subject added). - `go build ./... && go test ./internal/... && cd frontend && bun run build` clean. - Branch: `mai/<worker>/team-view-mailto-non-admin`. ## Out of scope - Adding subject/body templating beyond a static default. - BCC vs To choice (default to To unless the existing admin form does something different — match it). - Recipient list trimming when there are too many (mailto: URL length limits) — flag in completion report if you hit it; don't block on it. ## Reporting `mai report completed` with branch + SHAs + the exact UX path: open a project → Team tab → as non-admin, click either "E-Mail an Auswahl senden" button → see mail client open with recipients pre-filled.
mAi self-assigned this 2026-05-25 11:23:24 +00:00
Author
Collaborator

Branch: mai/hermes/gitster-team-view-mailto
Commit: 5589cbb

What changed

Both E-Mail an Auswahl senden actions on /team now branch on the existing canBroadcast() helper:

  • Admin path (global_admin or project-lead on the selected projects) — keeps the in-app compose modal exactly as before (POST /api/team/broadcast).
  • Non-admin path — renders a native <a href="mailto:..."> with the recipient list pre-filled. Subject and body intentionally left empty per scope. Recipient emails URL-encoded (encodeURIComponent) and comma-joined via the existing buildMailtoHref helper from broadcast.ts (RFC 6068).

Filter-bar button used to hide for non-admins (early-return in buildBroadcastButton()); it now renders as the mailto: anchor and its href is refreshed in updateBroadcastButton() on every filter change so the link always reflects the currently visible recipients. Empty visible set disables the affordance visually (aria-disabled + pointer-events: none + 0.5 opacity) so a stray click can't open an empty composer.

Bottom selection footer mirrors the same shape — renderSelectionFooter() emits either a <button> (admin) or an <a> (non-admin), and only registers the modal click-handler on the admin path. The anchor uses its native href to open the user's mail client.

Files touched

  • frontend/src/client/team.tsbuildBroadcastButton, updateBroadcastButton, renderSelectionFooter; added buildMailtoHref to the existing ./broadcast import.

team.tsx, the compose modal, openBroadcastModal, and the server /api/team/broadcast flow are all untouched.

UX path

  1. Open Paliad as a non-admin user (anyone who is not global_admin and not lead on the selected projects).
  2. Navigate to Team (/team).
  3. Apply any filter (office / role / project) — the E-Mail an Auswahl pill in the filter bar renders as a button-styled <a> whose href is mailto:<comma-joined emails>. Click → native mail client opens with all visible recipients in To, subject & body empty.
  4. Or: tick ≥ 1 row checkbox. Bottom sticky footer appears with the same E-Mail an Auswahl button styled identically; it is also a mailto: anchor pre-filled with only the selected emails.
  5. As an global_admin or project-lead, both buttons still open the compose modal (no regression on admin path).

Build hygiene

  • cd frontend && bun run build — clean (i18n scan clean, branding HLC, no new keys, dist contains the mailto path).
  • go build ./... — clean.
  • go test ./internal/... — clean (handlers / services / auth / branding / calc / changelog / db / offices all PASS).

Notes / follow-ups

  • mailto URL length: each address is ~30 chars + ,. The mailto: URL stays comfortably below typical mail-client limits (~2 kB) for the current firm directory (~60 users → ~1.9 kB). Did not trim recipients; flagging here per the issue's request rather than blocking. If the directory ever grows past ~70 active users, we'll want a soft cap with a "too many recipients, use the compose form" hint.
  • The pre-existing project-detail /team tab mailto path (buildMailtoHref via window.location.href, t-paliad-231) was deliberately left as-is — the issue's <a href> preference is local to this task's two buttons.
  • No new i18n keys; existing team.broadcast.button and team.selection.send are reused so the DE primary / EN secondary labels stay consistent.
## Done — Team View mailto: link for non-admin members **Branch:** `mai/hermes/gitster-team-view-mailto` **Commit:** [5589cbb](https://mgit.msbls.de/m/paliad/commit/5589cbb47740958feb3d7d5f5d1a7da3b18cbf5f) ### What changed Both `E-Mail an Auswahl senden` actions on `/team` now branch on the existing `canBroadcast()` helper: - **Admin path (`global_admin` or project-lead on the selected projects)** — keeps the in-app compose modal exactly as before (`POST /api/team/broadcast`). - **Non-admin path** — renders a native `<a href="mailto:...">` with the recipient list pre-filled. Subject and body intentionally left empty per scope. Recipient emails URL-encoded (`encodeURIComponent`) and comma-joined via the existing `buildMailtoHref` helper from `broadcast.ts` (RFC 6068). Filter-bar button used to **hide** for non-admins (early-return in `buildBroadcastButton()`); it now renders as the `mailto:` anchor and its `href` is refreshed in `updateBroadcastButton()` on every filter change so the link always reflects the currently visible recipients. Empty visible set disables the affordance visually (`aria-disabled` + `pointer-events: none` + 0.5 opacity) so a stray click can't open an empty composer. Bottom selection footer mirrors the same shape — `renderSelectionFooter()` emits either a `<button>` (admin) or an `<a>` (non-admin), and only registers the modal click-handler on the admin path. The anchor uses its native `href` to open the user's mail client. ### Files touched - `frontend/src/client/team.ts` — `buildBroadcastButton`, `updateBroadcastButton`, `renderSelectionFooter`; added `buildMailtoHref` to the existing `./broadcast` import. `team.tsx`, the compose modal, `openBroadcastModal`, and the server `/api/team/broadcast` flow are all untouched. ### UX path 1. Open Paliad as a non-admin user (anyone who is not `global_admin` and not lead on the selected projects). 2. Navigate to **Team** (`/team`). 3. Apply any filter (office / role / project) — the `E-Mail an Auswahl` pill in the filter bar renders as a button-styled `<a>` whose `href` is `mailto:<comma-joined emails>`. Click → native mail client opens with all visible recipients in **To**, subject & body empty. 4. Or: tick ≥ 1 row checkbox. Bottom sticky footer appears with the same `E-Mail an Auswahl` button styled identically; it is also a `mailto:` anchor pre-filled with only the selected emails. 5. As an `global_admin` or project-lead, both buttons still open the compose modal (no regression on admin path). ### Build hygiene - `cd frontend && bun run build` — clean (i18n scan clean, branding HLC, no new keys, dist contains the mailto path). - `go build ./...` — clean. - `go test ./internal/...` — clean (handlers / services / auth / branding / calc / changelog / db / offices all PASS). ### Notes / follow-ups - **mailto URL length**: each address is ~30 chars + `,`. The `mailto:` URL stays comfortably below typical mail-client limits (~2 kB) for the current firm directory (~60 users → ~1.9 kB). Did **not** trim recipients; flagging here per the issue's request rather than blocking. If the directory ever grows past ~70 active users, we'll want a soft cap with a "too many recipients, use the compose form" hint. - The pre-existing project-detail `/team` tab mailto path (`buildMailtoHref` via `window.location.href`, t-paliad-231) was deliberately left as-is — the issue's `<a href>` preference is local to this task's two buttons. - No new i18n keys; existing `team.broadcast.button` and `team.selection.send` are reused so the DE primary / EN secondary labels stay consistent.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: m/paliad#75
No description provided.