mirror of
https://github.com/karatektus/pl_mail.git
synced 2026-10-25 01:54:10 +00:00
Two kinds of report — a mail an extractor should have understood and did not, and a mail somebody found in the wrong tab — were two tables behind two panels with two export buttons. That split made sense to whoever wrote them and to nobody using them: an admin opening this section is asking "what is still mine to do", and that question does not have two answers. The tables stay apart, because the evidence really is different: a wrong tab is a disagreement between three classifiers, a missed insight is a mail body a parser could not read, and making them inherit would put a dozen always-null columns on each row and tie a schema change on one to the other for ever. What is unified is everything above them. ReportedMail carries the handful of fields a triage list is built from and the entity alongside for the fold and the export; ReportedMailProvider is the only place that knows there are two tables; the panel, the buttons and the file are written against the pair. Category reports gained handledAt, which is what makes them belong in the same list — a worklist you cannot cross anything off is not a worklist. Before this the only way to stop looking at one was to delete every one of them, taking the evidence for a rule away at the moment somebody might want to check it again. The export's scope becomes the selection. "Everything, or only the unhandled part" answers the question an admin has on their first visit and none of the ones they have afterwards; the one that comes up is "these six, the ones about the shop". So the list filters — by status, and by the problem itself, with the chips derived from the rows because for a wrong tab the problem IS a pair of categories and only this install knows which pairs it has produced — and the export takes what is ticked. Filtering never unticks anything: a row hidden by a chip is out of the selection while it is hidden and comes back ticked, so a selection built across two chips survives. An empty post still means everything, which is what a browser without JavaScript sends. Each record now carries its kind, every field its kind has, and the same one-line rendering the panel shows and the copy button copies. The document is plmail.reported-mail version 2 — a new name rather than a bumped version alone, so a consumer written against version 1 fails on the name instead of half-reading a file whose records it only understands some of. The row is a <div> and not a <label>, though a label around the whole row would give the checkbox a better hit target: a label may not contain a <form> or a <details> and both are there. Chromium happens not to forward label activation from a nested button, which means the invalid version works right up until the row is read by something that is not Chromium. Verified on a running stack: six reports of both kinds in one list, the status chip hiding the handled one, select-all writing five keys into the export form, a problem chip narrowing that to one without losing the other four, and the export returning scope:selection with the full record and its line. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>