Skip to content

feat(web): redesign files, sources, and staged deletions - #1588

Open
rodboev wants to merge 57 commits into
pr/redesign-4-messagesfrom
pr/redesign-5-files
Open

rodboev wants to merge 57 commits into
pr/redesign-4-messagesfrom
pr/redesign-5-files

Conversation

@rodboev

@rodboev rodboev commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Files now uses the Messages toolbar, one Filter menu, and a viewer with Add to task. Sources keeps mail and Contacts sync independent, shows schedules and runs, and opens repair Settings on the selected account. This slice extends the toolbar from #1579. Before, Files split its filters, Contacts lived in Settings, and staged deletions showed manifest IDs.

Staged deletions lists each batch by date, message count, and account. The Messages selection bar opens a review dialog before staging; msgvault delete-staged runs deletion. The sidebar shows Staged deletions while a batch is pending, running, or failed.

The deletion list API now returns each batch's account. Screenshots use synthetic data in dark mode at 1280×720. The People list and page build on this in #1611.

Before After
Files Files: separate filename and Type controls Files: one Filter menu and Set up action
Sources Sources: schedule and sync columns Sources: Contacts group and account panel
Contacts Contacts in Settings Contacts in Sources with sync recovery
Contacts repair Contacts repair before: Settings opens the default account Contacts repair after: Settings opens the selected account
Staged deletions Deletions with manifest IDs Staged deletions with date, count, and account

Refs #1552, slice 5 (Files, Sources, and Staged deletions)
Stacks on #1579

@rodboev
rodboev added this pull request to stack #1561 October 30, 2026 07:11
@roborev-ci

roborev-ci Bot commented Oct 30, 2026

Copy link
Copy Markdown

roborev: Combined Review (ce8bebc)

Verdict: Changes require fixes for 3 findings.

Medium

  • web/src/lib/components/sources/SourcesWorkspace.svelte:241: If the initial mail-status request fails while contacts report an active run, polling stops. Contacts remain stuck showing Running, with Sync now unavailable after completion until manual refresh or remount.

    Fix: Continue polling active contacts independently of mail-status loading success. Cover a contacts run completing after the initial mail-status failure.

  • web/src/lib/components/sources/SourcesWorkspace.svelte:162: In a contacts-only archive, every background poll sets loading=true because sources is empty. This replaces populated rows with Loading, removes focused controls, and disrupts keyboard navigation.

    Fix: Show initial loading only when both sources and contacts are empty; retain existing rows during refresh.

  • web/src/lib/sources/contacts.ts:34: Partial contacts runs can contain an error_message when some address books succeed and another fails, but the failed-only condition discards that diagnostic. The panel shows Partial and counters without explaining the failure.

    Fix: Display the latest run's error_message for partial as well as failed results, preserving repair-reason precedence. Cover a partially successful contacts sync.


Reviewers: 2x codex, codex (security), codex (test-value) | Synthesis: codex, 15s | Total: 24m40s

@rodboev
rodboev force-pushed the pr/redesign-5-files branch from ce8bebc to 5d00bcb Compare October 30, 2026 09:31
@roborev-ci

roborev-ci Bot commented Oct 30, 2026

Copy link
Copy Markdown

roborev: Combined Review (5d00bcb)

Verdict: Changes require fixes for 2 findings.

Medium

  • web/src/lib/deletions/controller.svelte.ts:65: Refreshing an open in-progress batch on browser focus deletes its cached details even when its status is unchanged, unmounting the panel. If the replacement request fails or times out, the panel stays closed without explanation, hiding progress and the Cancel batch action.

    Fix: Keep existing details visible during refresh, replace them only after a successful response, and surface refresh failures. Add a regression test for this failure path.

  • web/src/lib/deletions/controller.svelte.ts:84: Closing and reopening a batch returns cached execution details even through getDetail(id, true). If a CLI deletion advances or finishes while the browser remains focused, progress and cancellation availability can remain stale indefinitely because no polling refreshes the cache.

    Fix: Fetch fresh details when explicitly reopening a mutable batch, or periodically refresh active batches and reconcile their summary status.


Reviewers: 2x codex, codex (security), codex (test-value) | Synthesis: codex, 13s | Total: 16m24s

@roborev-ci

roborev-ci Bot commented Oct 30, 2026

Copy link
Copy Markdown

roborev: Combined Review (9b6183a)

Verdict: Changes require fixes for 2 findings.

Medium

  • web/src/lib/components/deletions/DeletionsWorkspace.svelte:68: Successful focus refreshes fetch final deletion details, but the open panel retains its original snapshot, leaving counts and failed message IDs stale while status updates.

    Fix: Update the open panel after successful detail refreshes, retaining previous details while refreshes are pending or fail. Cover successful focus refresh in a regression test.

  • web/src/lib/deletions/controller.svelte.ts:105; web/src/lib/components/deletions/DeletionsWorkspace.svelte:68: Reopening a completed deletion batch fetches fresh details but derives status and cancellation availability from the stale list summary, so the panel can continue showing Deleting and offering Cancel batch.

    Fix: Reconcile successful detail responses into the list summary so fresh status controls the status display and cancellation availability. Cover reopening a completed batch in a regression test.


Reviewers: 2x codex, codex (security), codex (test-value) | Synthesis: codex, 17s | Total: 15m50s

@roborev-ci

roborev-ci Bot commented Oct 30, 2026

Copy link
Copy Markdown

roborev: Combined Review (01c3ed4)

Verdict: Changes require fixes for 1 finding.

Medium

  • web/src/lib/components/deletions/DeletionsWorkspace.svelte:69: A status-changing focus refresh can supersede the detail request awaited by open(), which returns undefined. The workspace treats this as a failure and clears selectedID, closing the panel even when the replacement request succeeds.

    Fix: Distinguish superseded requests from failures and await the replacement detail request without clearing the selected batch. Cover a status-changing refresh during an outstanding open request.


Reviewers: 2x codex, codex (security), codex (test-value) | Synthesis: codex, 13s | Total: 14m26s

@roborev-ci

roborev-ci Bot commented Oct 30, 2026

Copy link
Copy Markdown

roborev: Combined Review (74f7253)

Verdict: No findings at or above medium severity.


Reviewers: 2x codex, codex (security), codex (test-value) | Synthesis: codex, 9s | Total: 13m55s

@roborev-ci

roborev-ci Bot commented Oct 30, 2026

Copy link
Copy Markdown

roborev: Combined Review (313004a)

Verdict: No findings at or above medium severity.


Reviewers: 2x codex, codex (security), codex (test-value) | Synthesis: codex, 8s | Total: 13m13s

@roborev-ci

roborev-ci Bot commented Oct 30, 2026

Copy link
Copy Markdown

roborev: Combined Review (d4efb4b)

Verdict: No findings at or above medium severity.


Reviewers: 2x codex, codex (security), codex (test-value) | Synthesis: codex, 10s | Total: 14m59s

@rodboev
rodboev force-pushed the pr/redesign-5-files branch from d4efb4b to be1889b Compare October 30, 2026 18:14
@roborev-ci

roborev-ci Bot commented Oct 30, 2026

Copy link
Copy Markdown

roborev: Combined Review (be1889b)

Verdict: Changes require fixes for 1 finding.

Medium

  • web/src/lib/components/sources/SourcesWorkspace.svelte:558: Table wrappers using flex: none cannot shrink when rows exceed the viewport, clipping lower source rows. The same issue at web/src/lib/components/deletions/DeletionsWorkspace.svelte:236 hides older deletion batches and the footer because neither workspace nor its height-constrained parent scrolls.

    Fix: Allow both table wrappers to shrink with min-height: 0, or make their workspace containers scroll vertically.


Reviewers: 2x codex, codex (security), codex (test-value) | Synthesis: codex, 16s | Total: 13m49s

@roborev-ci

roborev-ci Bot commented Oct 30, 2026

Copy link
Copy Markdown

roborev: Combined Review (f9400d9)

Verdict: No findings at or above medium severity.


Reviewers: 2x codex, codex (security), codex (test-value) | Synthesis: codex, 10s | Total: 15m16s

@rodboev
rodboev force-pushed the pr/redesign-5-files branch from f9400d9 to 41e245c Compare October 30, 2026 19:22
@roborev-ci

roborev-ci Bot commented Oct 30, 2026

Copy link
Copy Markdown

roborev: Combined Review (41e245c)

Verdict: Changes require fixes for 2 findings.

Medium

  • web/src/lib/components/sources/ContactPanel.svelte:54: Active source panels hide sync request failures and status retry controls. ContactPanel omits controller.syncError and statusError, while SourcePanel never receives triggerError. On narrow screens, the panel obscures these errors on the underlying page.

    Fix: Render controller.syncError and statusError with appropriate retry controls in ContactPanel, and pass triggerError into SourcePanel for display.

  • web/src/lib/components/deletions/DeletionReview.test.ts:39: The zero-eligible-messages test checks that staging is disabled during initial loading, before awaiting the preflight reason. It can pass even if the completed review incorrectly enables staging.

    Fix: Await 'No deletable messages.' before asserting that the 'Stage 0 messages' button is disabled. Retain the reason-display assertion.


Reviewers: 2x codex, codex (security), codex (test-value) | Synthesis: codex, 12s | Total: 14m45s

@roborev-ci

roborev-ci Bot commented Oct 30, 2026

Copy link
Copy Markdown

roborev: Combined Review (0204971)

Verdict: Changes require fixes for 1 finding.

Medium

  • web/src/lib/components/tasks/TaskLinks.test.ts:149: The Tasks fixture returns a successful integration status of 'unavailable', which production evaluators do not produce and TaskIntegrationStatusResponse excludes. MessageCard.test.ts:258 repeats this unsupported state. The Tasks fixture also fails to exercise recovery of cached links after a status-request failure.

    Fix: Make the Tasks status request return HTTP 503 while retaining the cached lookup response. Replace the Kata 'unavailable' case with a supported terminal state such as 'disabled'.


Reviewers: 2x codex, codex (security), codex (test-value) | Synthesis: codex, 13s | Total: 19m43s

@roborev-ci

roborev-ci Bot commented Oct 30, 2026

Copy link
Copy Markdown

roborev: Combined Review (2317135)

Verdict: No findings at or above medium severity.


Reviewers: 2x codex, codex (security), codex (test-value) | Synthesis: codex, 12s | Total: 17m43s

@rodboev
rodboev force-pushed the pr/redesign-5-files branch from 2317135 to 9a1b35d Compare October 30, 2026 20:06
@roborev-ci

roborev-ci Bot commented Oct 30, 2026

Copy link
Copy Markdown

roborev: Combined Review (9a1b35d)

Verdict: No findings at or above medium severity.


Reviewers: 2x codex, codex (security), codex (test-value) | Synthesis: codex, 7s | Total: 13m7s

@rodboev
rodboev marked this pull request as ready for review October 30, 2026 20:23
@rodboev
rodboev removed this pull request from stack #1561 October 31, 2026 16:18
@rodboev
rodboev added this pull request to stack #1624 October 31, 2026 16:18
@rodboev
rodboev marked this pull request as draft October 31, 2026 17:26
rodboev and others added 22 commits November 2, 2026 01:04
Visual indexing can finish without a daemon restart, so an unfinished
generation must remain eligible for another readiness check.

A deletion batch can finish between listing it and opening its panel.
The later detail response should determine its status and whether the
user can cancel it.
The source panels need the same schedule and sync diagnostics as the
parent table. Keep the cron expression, full next-sync date, and raw
unavailability reason available in tooltips.

The parent supplies operation status through a shared controller. The
contacts settings regression must receive that controller, and source
coverage must follow the panel workflow while retaining the parent checks.
Duplicate assertions across workspace layers obscure which component owns
a regression. Keep setup and connection selection checks with their owners,
and limit browser coverage to the panel and list layout.

Cancellation fixtures must reflect the daemon's completed response so the
result cannot depend on asserting before a stale detail read finishes.
The daemon returns the same 503 while visual search initializes as it does
when setup is missing. Caching that response hides Visual search for the
rest of the page, even after initialization succeeds.

The late deletion lookup regression must wait for response parsing before
checking the selected batch. Removing the stale-response guard now makes
that check fail.
A failed first list request leaves the staged batches unknown. Showing
"Nothing staged" alongside Retry gives users conflicting information.
A failed inspection left the batch panel showing an unavailable account
without explaining why its details were missing. Users need a visible
error and a way to recover while keeping the batch open.
Opening a batch briefly claimed its account was unavailable while the
request was still pending. Keep that state distinct from a loaded batch
without an account and from a failed request.
Visual setup completed outside the app can outlast the automatic retry
while Files stays open. Returning to the window should reveal search
once the generation is ready.

A source drawer can cover page-level status errors on a phone. Keep the
failure and its recovery action accessible inside the open drawer.
Accepting Sync now leaves no trigger error, but later status requests can
still fail. Keep the error and Refresh visible in the open source panel
so users can recover without closing it.
Incremental Gmail sync requires history from an earlier full sync.
Unscheduled sources need a command that can complete their first download.
Microsoft mail uses the same sync command for initial and later downloads.
Repeated retry and error cases obscure which component owns a regression.
Keep recovery checks with the user action that triggers them, and preserve
workspace coverage of source states and file labels during consolidation.
On narrow screens, the source panel covers page notices. A queued source
could keep showing its last status after automatic polling stopped,
leaving users without a visible warning or a way to refresh it.

Keep manual-sync examples within the combinations the server can emit.
Impossible server responses and missing readiness context let workspace
checks exercise fallback behavior instead of the paths users reach.
Repeated checks also obscured which test owns each regression.
Idle Contacts accounts showed "Not scheduled" in Sources even when the
scheduler had a next sync. Both status endpoints need the same runtime
schedule information so users can see when their contacts will sync.

Keep visual readiness examples within states production can produce.
Directory kept its Filters button while Messages and Files moved to
Filter. The shared command needs to reach each workspace's button so
keyboard and command palette users can open Directory filters again.
An older list response could restore a cancelled batch to staged or deleting.
If the next refresh failed, the table and sidebar kept that stale status.
Keep the successful cancellation authoritative while that list finishes.
The Files changes carried older Settings code over the shared status and People
profile refreshes. Restore the parent layer's reload behavior so saved profiles,
Contacts status, and failed index refreshes remain accurate. People writes keep
the revision returned with the profile they display.

Generated with Codex (gpt-6.1-sol)
Returning to Sources can leave an older connections snapshot in flight
while Sync now finishes. That snapshot restored stale failure details and
last-good timestamps after the idle controller had stopped polling.

Cancel the competing list refresh through its existing request controller
so the completed sync remains visible in both the row and account panel.
A connections refresh can start while contacts sync is still waiting and
return an old failure after sync completes. Terminal syncs stop polling,
so that response can leave the row and account panel stale indefinitely.

Cancel the competing request when sync finishes so refreshes started
during the sync also preserve its reconciled result.
…redesign-5-files

# Conflicts:
#	web/src/lib/components/settings/SettingsWorkspace.svelte
#	web/src/lib/components/settings/SettingsWorkspace.test.ts
Renaming a saved view or saving its description could leave the editor
busy after the save succeeded. A slow staged-deletion request held up
the shared refresh even though saved views had already loaded.

Saved-view edits need to wait only for their own refreshed list.
The Files branch lost Past runs coverage while archive navigation behavior
stayed the same. Restore those checks so history regressions remain visible.

Duplicate cases and unrealistic fetch behavior obscured what the remaining
tests protected. Keep each scenario focused on distinct, reachable behavior.
@rodboev
rodboev marked this pull request as ready for review November 2, 2026 01:09
Most source-label rows supply only the type and display name. Mark the
mailbox arguments optional so the shared callback accepts both fixture
shapes during TypeScript validation.

Generated with Codex
@roborev-ci

roborev-ci Bot commented Nov 2, 2026

Copy link
Copy Markdown

roborev: Combined Review (ba82c51)

Verdict: No findings at or above medium severity.


Reviewers: 2x codex, codex (security), codex (test-value) | Synthesis: codex | Total: 24m19s

Batches from different mailboxes can share a date and message count.
Show their accounts in the list so users can distinguish them without
opening each panel or fetching details for every row.
Repeated list scenarios increased maintenance without protecting another behavior. Realistic API fixtures and independent consent and row-count checks make failures point to reachable regressions.
@roborev-ci

roborev-ci Bot commented Nov 2, 2026

Copy link
Copy Markdown

roborev: Combined Review (ea50e26)

Verdict: No findings at or above medium severity.


Reviewers: 2x codex, codex (security), codex (test-value) | Synthesis: codex | Total: 18m45s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants