Files
pl_mail/templates/_partials/_toast.stream.html.twig
Paul LütznerandClaude Opus 5.5 464df70473 Move a conversation to a label, and take it out of the list it was in
Issue #25. Filing mail the way Gmail does took two actions here: the
label button adds a label and leaves the mail where it is, and a drop on
a folder needs a pointer and a sidebar in reach. "Move to" is one click,
beside the label button, in the list toolbar and in the reading pane:
the target goes on and the label of the list being looked at comes off.

The client names the view; the server decides what that removes. A body
that lists labels to strip is not an instruction the route has.

  Inbox            target on, archived (Archive on, Inbox off) — or
                   into the folder, where the target is one
  a label          that label swapped for the target
  Trash, Spam      target on, out of the bin, not into the inbox
  anywhere else    target on, Inbox off where it was on
  to Inbox         restore(), then the view's label off
  to Trash, Spam   the existing trash and spam paths, not a label swap

MoveToService composes ThreadStatusUpdater's operations rather than
writing labels itself, inside one transaction, because each of those
carries provider behaviour that took a bug report to get right. Only
the messages that carry the leaving label lose it: a sent reply in an
inbox thread gains the target and is not archived.

The issue asks for "tag(s)", plural. This is Gmail's single target;
several labels are still what the label button is for.

Undo came with it, for archive and labels as the issue asks, and for
the drag onto a folder since the mechanism was there. It remembers each
message's labels before the action, in the session, and puts exactly
those back — not the inverse of the action, which is wrong for a mixed
selection. A whole-view action runs in a worker and has none.

Three things fell out:

  - The toolbar's label menu posted once per ticked row. With a toast
    and an Undo on the answer that was five of each, so it posts the
    selection once now, to /status/bulk/label, which learned `attach`.
  - Inbox, Spam and Trash are asked for by role. Their labels are made
    lazily, so a picker that carried ids had no Trash row for anybody
    who had never deleted anything.
  - Font Awesome keeps its folder-with-arrow in Pro, so the button is
    an inline SVG.

Not verified against a live Gmail or Exchange account: the tests pin
local label state and the IMAP jobs that are queued.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 13:56:35 +02:00

18 lines
632 B
Twig

{#
One toast, appended to the toast region.
The five lines nearly every stream response carries beside the fragment it
replaces; written once here so the target id and the wrapper cannot drift apart
between them.
message already translated
type success | error | info (default success)
extra optional, see _toast.html.twig (hide_after, undo_url, undo_label,
undo_controller)
#}
<turbo-stream action="append" target="toast-region">
<template>
{% include '_partials/_toast.html.twig' with { message: message, type: type ?? 'success', extra: extra ?? {} } only %}
</template>
</turbo-stream>