Rate fetching is optional and fails soft: any network or parse error leaves cached rates untouched and shows a message, never throwing into render. A cleared or non-positive FX rate input now calls the new removeFxRate action instead of storing 0, since toBase() silently converts a stored 0 to a 0-value conversion while an absent row correctly throws MissingRateError. Posts are archived, never deleted. Import downloads a backup of the current data before replacing it and requires confirmation showing before/after counts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
13 lines
478 B
TypeScript
13 lines
478 B
TypeScript
/** Triggers a browser download. Works only in a real page, not in tests. */
|
|
export function downloadBlob(filename: string, blob: Blob): void {
|
|
const url = URL.createObjectURL(blob);
|
|
const anchor = document.createElement("a");
|
|
anchor.href = url;
|
|
anchor.download = filename;
|
|
document.body.appendChild(anchor);
|
|
anchor.click();
|
|
anchor.remove();
|
|
// Give the browser a turn to start the download before revoking.
|
|
setTimeout(() => URL.revokeObjectURL(url), 1000);
|
|
}
|