feat(messages): search bar + Archive/Delete with Archived & Deleted folders

- Search box in the header filters the current folder's list (sender/subject),
  client-side; works across the merged Archived/Deleted views too.
- Archive and Delete are now implemented as soft moves: migration 157 adds
  mailbox_state ('active'|'archived'|'deleted') to email_queue + received_emails.
  Archive → 'archived', Delete → 'deleted' (trash). Restore → 'active'. Deleting
  FROM the Deleted folder is permanent (hard row delete).
- New cross-account system folders Archived + Deleted (merge sent + received of
  that state, sorted by date). Normal folders now exclude archived/deleted.
- Backend: /queue + /received gain a `state` filter (default active + legacy
  NULL); new POST /item/:kind/:id/state (archive/delete/restore) and DELETE
  /item/:kind/:id (purge, email.edit).
- Toolbar Archive/Delete wired; Restore + "Delete permanently" shown in the
  system folders.

Frontend build + migration boot (157) verified.
This commit is contained in:
Luca
2026-07-07 16:16:51 +02:00
parent c8cb4c88ca
commit 99d5996561
4 changed files with 230 additions and 41 deletions
+10 -1
View File
@@ -220,10 +220,18 @@ export const emailService = {
const response = await api.post<ImapPollResult>('/admin/email/incoming-config/poll', {});
return response.data;
},
async listReceived(params: { page?: number; pageSize?: number; account?: string } = {}): Promise<ReceivedEmailsResponse> {
async listReceived(params: { page?: number; pageSize?: number; account?: string; state?: 'active' | 'archived' | 'deleted' } = {}): Promise<ReceivedEmailsResponse> {
const response = await api.get<ReceivedEmailsResponse>('/admin/email/received', { params });
return response.data;
},
/** Archive / Delete (soft) / Restore an email. kind = 'queue' | 'received'. */
async setItemState(kind: 'queue' | 'received', id: number, state: 'active' | 'archived' | 'deleted'): Promise<void> {
await api.post(`/admin/email/item/${kind}/${id}/state`, { state });
},
/** Permanently delete an email (only from the Deleted folder). */
async deleteItem(kind: 'queue' | 'received', id: number): Promise<void> {
await api.delete(`/admin/email/item/${kind}/${id}`);
},
async getReceivedItem(id: number): Promise<ReceivedEmailDetail> {
const response = await api.get<ReceivedEmailDetail>(`/admin/email/received/${id}`);
return response.data;
@@ -262,6 +270,7 @@ export const emailService = {
status?: EmailQueueStatus;
emailType?: string;
origin?: 'system' | 'manual';
state?: 'active' | 'archived' | 'deleted';
q?: string;
from?: string;
to?: string;