DRY pass #2, batch 5, F16: one way an action reports its failure (#5372)
CI & Build / Build now, or wait for Android? (push) Successful in 3s
CI & Build / Python lint (push) Successful in 4s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 4s
Android / Build, or is the channel already serving this? (push) Successful in 8s
CI & Build / Web typecheck and unit tests (push) Failing after 11s
CI & Build / Python tests (push) Successful in 19s
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Failing after 29s
Desktop (Tauri) / Tauri desktop (Linux) (push) Skipped
Desktop (Tauri) / Windows installer (cross-compiled) (push) Skipped
Desktop (Tauri) / Update manifest (push) Skipped
Android / Core and FFI clippy and tests (push) Successful in 44s
CI & Build / integration (push) Successful in 1m32s
CI & Build / Build & push image (push) Skipped
Android / Kotlin + Rust (APK) (push) Failing after 4m11s
Android / Build the server image (push) Successful in 1s

composables/useAction.ts: toastOnFailure runs an action and toasts the
server's reason or a fallback; useAction adds the busy flag a button
waits on; useRowAction keeps the id of the row whose action is running.
Import, export, the menu entry, the integration prompt, sign out
elsewhere, the account reset link, the group actions (whose local act()
it replaces), invite revoke and sync disconnect each wrote that
try/catch/finally out.

Kept: AccountView's device revoke. It shows a fixed message rather than
the server's reason, and moving it would change the text. ShareDialog
shows its errors inline, not in a toast.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 14:44:43 -04:00
co-authored by Claude Opus 5.5
parent fe1b61fa4d
commit ebbe4a678a
10 changed files with 85 additions and 81 deletions
+3 -4
View File
@@ -24,6 +24,7 @@ import {
} from "../desktop/bridge";
import { errorMessage } from "../api/errors";
import { formatDateTime } from "../notes/datetime";
import { toastOnFailure } from "../composables/useAction";
// Opt-in server sync for the desktop app. Being UNLINKED is the normal resting
// state, not an incomplete setup — the app is local-first and fully usable having
@@ -319,7 +320,7 @@ async function disconnect() {
) {
return;
}
try {
await toastOnFailure(async () => {
const result = await syncBridge.unlink();
status.value = result.status;
linkedAs.value = "";
@@ -331,9 +332,7 @@ async function disconnect() {
? "Disconnected, and this device is signed out on the server."
: "Disconnected. This device now works offline only.",
);
} catch (e) {
ui.showToast(errorMessage(e, "Couldn't disconnect."));
}
}, "Couldn't disconnect.");
}
// A background cycle finished — redraw from it, so this screen is never staler