fix(notifications): a notice keeps what to say and says it in the reader's language when shown

This commit is contained in:
2026-10-29 22:37:14 +01:00
parent 6986eb1937
commit 4ef772d37b
125 changed files with 973 additions and 674 deletions
@@ -18,7 +18,7 @@ import {
} from "../../lib/debugRecorder";
import { formatDateTimeSec, formatDuration } from "../../lib/format";
import { useLayer } from "../../lib/layerStack";
import { notify } from "../../lib/notifications";
import { msg, notify } from "../../lib/notifications";
import { qk } from "../../lib/queryKeys";
import { dockUnderToasts } from "../../lib/toastDock";
import { useMe } from "../../lib/useMe";
@@ -73,7 +73,7 @@ export default function DebugRecorder() {
if (!id || !until) return;
const wait = Math.min(Date.parse(until) - Date.now(), 2 ** 31 - 1);
const timer = window.setTimeout(() => {
notify({ level: "warning", message: t("recorder.pill.expired", { count: minutes ?? 0 }) });
notify({ level: "warning", message: msg("recorder.pill.expired", { count: minutes ?? 0 }) });
openComposer(id);
void qc.invalidateQueries({ queryKey: qk.me() });
}, wait);
@@ -6,7 +6,7 @@ import { ExternalLink, FileText, Plus, Server, X } from "lucide-react";
import { api, type DebugScreenshot, type DebugSession, type ServerLogRow } from "../../lib/api";
import { closeComposer } from "../../lib/debugRecorder";
import { formatBytes, formatDateTimeSec, formatUnit } from "../../lib/format";
import { notify } from "../../lib/notifications";
import { msg, notify } from "../../lib/notifications";
import { useMe } from "../../lib/useMe";
import {
draftSteps,
@@ -217,7 +217,7 @@ function ComposerBody({
meta: { failTitle: "recorder.composer.sendFailed" },
onSuccess: (r) => {
qc.setQueryData(qk.debugSession(session.id), r.session);
notify({ level: "success", message: t("recorder.composer.sentOk") });
notify({ level: "success", message: msg("recorder.composer.sentOk") });
},
// A failure half-way still created the issue: show what the server now has.
onSettled: async () => {
@@ -1,6 +1,5 @@
import { useCallback } from "react";
import { useIsMutating, useMutation, useQueryClient } from "@tanstack/react-query";
import { useTranslation } from "react-i18next";
import { api, type DebugSession, type DebugSessionLevel } from "../../lib/api";
import { notifyActionError } from "../../lib/actionErrors";
@@ -14,7 +13,7 @@ import {
} from "../../lib/debugRecorder";
import { flushNow, liveSession } from "../../lib/diagnostics";
import { log } from "../../lib/log";
import { notify } from "../../lib/notifications";
import { msg, notify } from "../../lib/notifications";
import { qk } from "../../lib/queryKeys";
import { updateMeCache, useMe } from "../../lib/useMe";
@@ -22,7 +21,6 @@ import { updateMeCache, useMe } from "../../lib/useMe";
* Diagnosztika and the command palette. The session itself is `me.debug_session` — the server's
* answer, so a reload, another tab or the cap all show the same thing. */
export function useDebugRecording() {
const { t } = useTranslation();
const qc = useQueryClient();
const me = useMe();
const session = liveSession(me?.debug_session);
@@ -54,7 +52,7 @@ export function useDebugRecording() {
meta: { failTitle: "recorder.pill.stopFailed" },
onSuccess: (r) => {
setSession(null);
notify({ level: "success", message: t("recorder.pill.stopped") });
notify({ level: "success", message: msg("recorder.pill.stopped") });
openComposer(r.session.id);
},
});
@@ -78,7 +76,7 @@ export function useDebugRecording() {
);
// In the evidence too, where the step list is drafted from: which step it belongs to.
log.info("debug.screenshot", "screenshot taken", { screenshot: r.screenshot.id });
notify({ level: "success", message: t("recorder.pill.shotSaved") });
notify({ level: "success", message: msg("recorder.pill.shotSaved") });
},
});
@@ -95,9 +93,9 @@ export function useDebugRecording() {
const n = nextStep(sessionId);
const text = label.trim();
log.info("debug.step", text || `step ${n}`, { n, ...(text ? { label: text } : {}) });
notify({ level: "info", message: t("recorder.pill.stepMarked", { n }) });
notify({ level: "info", message: msg("recorder.pill.stepMarked", { n }) });
},
[sessionId, t],
[sessionId],
);
/** Capture this tab and attach it. `hide` runs around the capture so the pill is not in the
@@ -111,7 +109,7 @@ export function useDebugRecording() {
await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
image = await captureTab();
} catch (err) {
notifyActionError(err, t("recorder.pill.shotFailed"));
notifyActionError(err, msg("recorder.pill.shotFailed"));
}
hide(false);
if (image) shoot.mutate({ id: session.id, image });