The hook was called on every search, but nothing showed its entries,
the list waited for it, and an entry's onClick could not cross from the
plugin's sandbox. Its entries are now drawn as a block above the
search's message list, a group per plugin and source.
Each plugin is asked on its own (HookBus.collect) beside the search, so
the list no longer waits, and the answer to a search that was replaced
is dropped. The answer is checked: at most 20 entries, a key and a
title, plain text cut to its limits. A click goes to the plugin that
gave the entry as onAction with surface "search-results", the entry's
key and the query; ExternalSearchResult loses onClick.
Closes#1336
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Expanding a conversation in the message list (row click, expand chevron,
or the `x` shortcut) and clicking a row in a Pro folder tab marked the
messages read straight away. They ignored "Mark as read: Never" and any
delay, which the reading pane and the conversation view follow.
Route them through one helper, scheduleAutoMarkAsRead: -1 never marks,
0 marks at once, any other value marks after that many milliseconds and
returns a cancel function.
- New store action autoMarkExpandedThreadAsRead keeps one pending timer
per thread key. Collapsing the thread, or collapsing all threads, drops
it. Both expansion paths (EmailList and the `x` handler in MailApp) use
it.
- MailApp's handleEmailSelect drops the pending mark of every expanded
thread other than the one the newly opened message belongs to, through
cancelAutoMarkThreadAsRead. Moving on with `j`/`k` or a click no longer
lets the delayed mark land on a conversation the user has left. The
thread stays expanded.
- ProFolderTabBody schedules the row mark through the helper and drops a
pending one when another row is opened or the tab unmounts.
markThreadAsRead resolved each message through resolveEmailActionContext
but kept only the client and dropped the accountId, so batchMarkAsRead
always wrote to the reaching client's own account.
That hit two cases where the client and the owning account differ:
- a shared mailbox opened directly from the "Shared" sidebar section,
whose owner comes from the selected shared folder;
- a shared source in the unified view, whose messages are stamped with
sourceAccountId but reached through the login client.
The Email/set then went to the login's own account. The shared messages
stayed unread, and since JMAP ids are only unique within an account, a
message in the user's own account with the same id could be marked read
instead.
Group the ids by client and owning account, and pass the accountId to
batchMarkAsRead, as the batch and single-message paths already do.
When creating a recurring event, the calendar store previously only added
the base event returned by the server to its state. The server-expanded
recurrence instances (synthetic IDs) were not loaded until the next manual
page refresh or visible range query.
Refetch the active visible range immediately after creating an event when
recurrenceRules are present, matching the behavior used when mutating
recurring occurrences.