Repository navigation
feat(desktop): the Import form says which program is missing, with Try again, and an import waits for a download (#1053) - #2003
Conversation
…y again, and an import waits for a download (#1053) A WhatsApp import needs wtsexporter, and Convert and Compress need ffmpeg and ffprobe. When one is missing, can't be used or failed to download, the Import form names it, gives the reason and offers Try again, which runs the check and download now through the new retry_tool_downloads command. A WhatsApp import can't start without wtsexporter; Convert and Compress still start, and the Staging Review keeps its message, now with Try again beside it and read from the live status. An import started while its program is still downloading waits in the Rust run path on the ToolDownloads state, which now carries a condition variable, and its progress line reads "Waiting for the wtsexporter download (12.0 MB of 30.0 MB)". A failed download fails the run with its reason. Part of #1053 (step 4). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
mbeisser1
left a comment
There was a problem hiding this comment.
Review of f03f803 (up to date with main). Findings whose line is outside the diff follow; the rest are line comments.
docs/src/content/docs/docs/user/features/owner/troubleshooting.md— Standards · rule — Docs follow behaviour: the notice links totroubleshooting.md:97and:107, but neither section mentions Try again.settings/system.md:75still says "A failed download is tried again the next time the app starts", andSystemSection.tsx:58DOWNLOAD_RETRIEDsays the same; both are now incomplete (Try again on the Import form runs it now).src-tauri/src/tool_downloads.rs— Standards · judgement —waiting_line: two byte formats in one flow. The form says "12 MB of 30 MB (40%)" and the progress line "12.0 MB of 30.0 MB", because one comes frommedia::format_bytesand the other from the webformatBytes. Pick one format for both.docs/src/content/docs/docs/user/import-sources/whatsapp.md— Standards · judgement —whatsapp.md:11says nothing new: neither that the import can't start without wtsexporter nor that it waits for a download in progress, both of which the CHANGELOG states. One sentence each.
…the window polls while a check runs (#1053) A check's thread now owns a guard. While it exists, tools_status reports checking: true, and the web hook keeps polling. A program the check has not looked at yet shows as missing, and the form no longer stops polling on that answer. When the guard drops, at the end of the check or on a panic, every program the check marked as downloading that still is becomes failed ("The download was interrupted."). A waiting import wakes and the form offers Try again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…that arrived (#1053) A program fails only when the lookup does not find it. When the download arrived and runs but manifest.json could not be written, the check now writes a line to the process log and leaves the program found. Before, the check set it to failed. A waiting WhatsApp import or Media stage could then fail, depending on timing, for a program that works, while the form offered no Try again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…rograms it marked (#1053) When the check's thread fails to start, the programs Try again marked as downloading now fail with "The download could not be started: ...". These are the programs in not_found that have a pin on this platform, the same filter as the marking loop. Before, every program in not_found failed with "could not be written to the Tools Directory". That reason was false, and it also covered a program with no download for this computer. retry_tool_downloads and invokeRetryToolDownloads now name all three cases that return false. download_missing is private now and takes the check's run. The tests call it through check_now. The previous commit left it public with no caller outside the tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…ith no Try again (#1053) Linux on ARM has no wtsexporter file. tools_status now reports a program that is missing and has no pin for this computer as "unavailable". The Import form says the app has no download of it for this computer and links to the troubleshooting section without offering Try again, because Try again can't bring it. Settings says to put a copy in the Tools Directory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
retry_tool_downloads returns false when another check holds the lock, and the notice ignored the result: Try again did nothing and said nothing. When the result is false and the status reports checking, the notice now says a check of the Tools Directory is already running. The status keeps polling while checking is true, so the form takes the result when that check ends. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…ies bytes, and the window formats them (#1053) The waiting progress event now names the program in an explicit waiting field and carries the bytes in bytes_done and bytes_total. Before, the web took any event with 0/0 counts and a status as a wait. The web writes the line with the same downloadProgress the Import form and Settings use: "Waiting for the wtsexporter download: 12 MB of 30 MB (40%)". Before, the progress line used media::format_bytes ("12.0 MB", base 1000) and the form used formatBytes ("12 MB", base 1024). The desktop process sends a wait event when the wait starts, when the program or the size changes, and when the download moves by 256 KiB. The new tests: - programs_run_by for every source; - the JSON shape of waiting_event; - the Setup-row line and the Media-row line, built from that JSON. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…shooting section (#1053) The run's error for a failed download now ends with the sentence the app already used for a wtsexporter that doesn't run: See "Import can't find wtsexporter" (or "ffmpeg or ffprobe not found") in Troubleshooting at messagecrate.app. Settings' failed-download line ends with the same sentence, and the section's name links to it. The sentence for a wtsexporter that doesn't run now comes from those two places only, so nothing names the section twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
… Import form, and the notice names the programs (#1053) toolStatusLine in lib/toolStatusCopy.ts is now the only per-state switch. Settings and the Import form's notice both use it. Settings adds its own fixes after the line: where a missing program goes, and, for a failed download, that it is tried again and the troubleshooting section. One ToolName type in lib/tauri.ts replaces Settings' ToolName and the notice's ProgramName. downloadProgress moved beside its two callers and is no longer exported. useToolsStatus.ts now holds only the two hooks. The notice names the programs: "A WhatsApp import can't start without wtsexporter.", "The import waits for wtsexporter.", "Media waits for ffmpeg." Before, "it" had no clear referent when both ffmpeg and ffprobe downloaded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…reached mid-download stays open (#1053) Two tests at the review read the live tools status: - Try again there downloads the missing ffprobe and enables Convert media once ffprobe arrives; - with ffmpeg downloading, Convert media is enabled and no Try again shows, although the run found ffmpeg missing when it reached the review. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…Settings and the WhatsApp page (#1053) - Troubleshooting, "Import can't find wtsexporter" and "ffmpeg or ffprobe not found": Try again on the Import form downloads the program at once. A computer the app has no wtsexporter download for takes a copy put in the Tools Directory by hand. - Settings -> System, on the page and in DOWNLOAD_RETRIED: a failed download is tried again at the next start or with Try again on the Import form. The page also gains the unavailable line, the interrupted and could-not-start reasons, and the troubleshooting link. - Attachments and media: the review paragraph says one idea per sentence, and its last sentence no longer says "again". - WhatsApp: the import can't start without wtsexporter, and it waits for a download in progress. - CHANGELOG: the progress line in the new byte format. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
… Directory, and asks until it ends (#1053) `retry_tool_downloads` returns what it did: started, alreadyRunning, noToolsDirectory or couldNotStart. `checking` counts only this process's checks, so the Import form showed nothing and stopped asking when another app held the lock. The form now shows the "already running" line for alreadyRunning whatever `checking` says, and asks for the status every 2 s for two minutes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…ograms as interrupted (#1053) The check's run went into the thread's closure, so a failed start dropped it there: its drop marked each program interrupted and woke a waiting import before `retry` set the real reason. The run now goes to the thread over a channel once the thread has started. On a failed start each program fails with CouldNotStart first, and the run's drop leaves them. `retry_with` takes the spawner, so a test makes the start fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
… drop said plainly (#1053) `check` takes `&run.downloads.clone()` in one line, with the reason for the clone: `run` is borrowed mutably later to mark programs downloading. The `CheckRun` doc says every program it marked that is still downloading becomes failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…bleshootingSentence (#1053) `troubleshootingSentence` returns the sentence split around the section's heading, so Settings sets the heading as a link and builds the label from the same parts, instead of writing the sentence a second time by hand. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
… on its type (#1053) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
After Try again answered "already running", the line stayed for good: not `checking` going false, nor the two-minute deadline, took it away. Now it goes once this process's check has been seen and ends, or when the two minutes for another app's check are up, with a timer to re-render then. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
mbeisser1
left a comment
There was a problem hiding this comment.
Re-review of the fix commits (Standards and Correctness, step 4 of the review), pinned to 5be1a49. Every finding below is fixed in this push.
Correctness · bug web/src/screens/import/MissingProgramNotice.tsx:51: when another process held the Tools Directory lock, Try again returned false, checking stayed false, and nothing showed or polled. Fixed in 0c8d078: retry_tool_downloads returns started | alreadyRunning | noToolsDirectory | couldNotStart; on alreadyRunning the notice says a check is already running whatever checking says and the status is asked every 2 s for two minutes. Both doc comments say checking counts this process's checks only.
Correctness · bug (low) src-tauri/src/tool_downloads.rs:855: on a spawn failure the dropped guard marked programs interrupted and woke waiters before the real cause was set. Fixed in df63696: the run reaches its thread over a channel only after the thread starts; on a start failure each program is set to could-not-start before the run drops, and the drop leaves failed programs alone; a test with a failing spawner.
Correctness · bug MissingProgramNotice.tsx:56: the "already running" line never went away. Fixed in f86693e: it goes once this process's check has been seen and ends, or when the two minutes for another app's check are up; test.
Standards · judgement commands/tools.rs:137, tauri.ts:531: the doc claimed checking follows another app's check. Fixed in 0c8d078.
Standards · judgement tauri.ts:509: ToolName sat between a doc comment and its type. Fixed in f657f17.
Standards · judgement SystemSection.tsx:135: the troubleshooting sentence written by hand beside troubleshootingSentence. Fixed in 2d46755: the function returns the parts and Settings builds the label and the link from them.
Standards · judgement tool_downloads.rs:876: the downloads shadow. Fixed in 8a9ca6b, with the reason for the clone.
Standards · judgement tool_downloads.rs:856: the hard-to-follow comment. Fixed in df63696.
Standards · judgement tool_downloads.rs:587: the garden-path sentence. Fixed in 8a9ca6b.
Standards · judgement PR body stale. Fixed: rewritten for the final progress-line format, the waiting event field, the checking and unavailable states, the retry result, and the docs pages changed.
Also in this push: 5be1a49 merges origin/main (#2004, the docs lockfile) with no conflict.
|
Review summary for 5be1a49.
|
Feature Description
Step 4 of #1053: the Import form says which program the chosen import needs and can't use, with Try again, and an import started while its program is still downloading waits for it.
#import-cant-find-wtsexporter).unavailable: "not found, and the app has no download of it for this computer". The form offers no Try again for it, because only a copy put in the Tools Directory by hand is used.#ffmpeg-or-ffprobe-not-found. Nothing is blocked: the import still runs. The Staging Review keeps its existing message. It now has Try again beside it, and it reads the live status, so the review unblocks once the programs arrive.foundthe run goes on. When it fails, the run fails with the reason and names the troubleshooting section.User Story
As a person importing a WhatsApp backup on a computer where the wtsexporter download failed, I want the Import form to say so and let me download it again from there, so that I don't have to restart the app or read Settings to find out why the import can't start.
Implementation Details
ToolDownloadsnow holds aCondvarbeside itsMutex. Everysetandclearnotifies it.ToolDownloads::wait_for(programs, cancelled, waiting)blocks while any ofprogramsisDownloading. It wakes on each change, or every 250 ms to read the cancel flag, and it reports progress throughwaiting. It returnsOkwhen no program it waited for is downloading,WaitError::Failed { reason }when a download it waited for ended failed, andCancelledon Cancel. A program that wasn't downloading when the run started isn't waited for. The lookup then reports it as before.commands::tools::wait_for_downloadssends the wait asextract:progressevents with no counts, the program in a newwaitingfield, and the bytes inbytes_doneandbytes_total: one when the wait starts, and one each time the program changes or its download moves by 256 KiB. The window writes the line from them (waitingLineinweb/src/lib/toolStatusCopy.ts).extractwaits for wtsexporter on a WhatsApp source (stepsetup), andtranscode_stagingwaits for ffmpeg and ffprobe when Media converts (stepmedia).CheckRunowned by its thread. When the run is dropped, at the end of the check or on a panic, every program it marked that is still downloading becomes failed, so an import waiting for it wakes.retry_tool_downloadsreturns at once, with what it did:started,alreadyRunning(another check holds the lock: the start-up check, an earlier Try again, or another app's check),noToolsDirectory, orcouldNotStart(the check's thread could not be started, and each program it would have downloaded fails with that reason).tool_downloads::retrytakes the.check.lockon the calling thread. Otherwise it marks the programs the window reports as not found asDownloading, then runs the same check as at start on its own thread, with the lock moved in. The check's run goes to that thread only once it has started, so a failed start never shows the programs as interrupted.download_missingandretryshare onecheck. That check now clears the state of a program it finds in place (kept, adopted, or ffmpeg onPATH), so a stale failure or a mark from a retry never sticks.checking: whether a check runs in this process now. A program the check has not looked at yet shows as missing, so the window keeps asking whilecheckingis true. Another app's check is not counted.useToolsStatus/useRetryToolDownloads(web/src/lib/useToolsStatus.ts) are the one query onkeys.desktopToolsStatus.all, polled each second while checking or downloading. After Try again answersalreadyRunningthe form says a check is already running, whatevercheckingsays, and the status is also asked for every 2 s for two minutes, because another app's check is not counted inchecking. Settings now uses the same hook and is otherwise unchanged.ffmpegMissingno longer counts a program that is downloading, because Media waits for it.Key Files Changed
src-tauri/src/tool_downloads.rs- Condvar,wait_for,WaitError,CheckRun,retryand itsRetryresult, sharedchecksrc-tauri/src/commands/tools.rs-retry_tool_downloadsandRetryResult,wait_for_downloads, thecheckingandunavailablestatussrc-tauri/src/commands/events.rs,web/src/lib/types.ts- thewaitingfield onextract:progressweb/src/lib/toolStatusCopy.ts- one status line per program state, the progress format,waitingLine, the troubleshooting sentencesrc-tauri/src/commands/extract.rs,staging.rs- the waitsweb/src/screens/import/MissingProgramNotice.tsx- the message and Try againweb/src/screens/import/ImportFormFields.tsx- the WhatsApp block and the noticesweb/src/screens/import/ImportRunView.tsx- Try again at the Staging Review, live statusweb/src/screens/settings/SystemSection.tsx- the same status lines as the formdocs/src/content/docs/docs/user/features/owner/troubleshooting.md,features/settings/system.md,import-sources/whatsapp.md,features/messages/attachments-and-media.md- Try againHTTP API Changes
retry_tool_downloads.Database Changes
schema/sql/*.sqlchanged (every database rebuilds empty and re-imports; the fingerprint is computed, nothing to bump)How to Test
cargo test --manifest-path src-tauri/Cargo.toml tool_downloads. The new tests cover: a wait that goes on when the state is cleared; a wait that fails with the reason; no wait when nothing downloads; Cancel ending the wait; Try again running the check once and returning before a 500 ms download; Try again while the lock is held starting nothing; a Try again whose thread can't start failing with that reason and never as interrupted; a check that panics mid-download failing the download; and a program found in place clearing an earlier failure.cd web && npx vitest run src/screens/import. Form tests covermissing,downloadFailed,unusableanddownloadingfor wtsexporter, the ffmpeg notice that doesn't block, and Try again calling the command and polling until the program is found, including when another app's check holds the Tools Directory andcheckingis false. A useImportJob test covers the Media row's waiting line.~/message-crate/tools/wtsexporter, start the app offline, choose WhatsApp, and see the message and the disabled Import. Go online, select Try again, and see the progress, then Import enabled.Checklist
./scripts/check-pr.shpasses and formatter rewrites are committedRelated Issues
Part of #1053 (step 4). Step 5 (the user guide) stays open. Four guide pages changed here, because the behaviour they describe changed: troubleshooting.md, system.md, whatsapp.md and attachments-and-media.md each name Try again.
Screenshots / Demo
No browser check was run. The Vitest tests render the form with
isTauriand the Tauri commands mocked.Deployment Notes
None.
🤖 Generated with Claude Code
https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1