fix(activity): a run's quota reads with its unit, its outcome keeps room at a large text size, a token's audit rows read in Hungarian

The run list showed the quota spend as a bare figure and, at the largest text size on a 1024-wide
screen, its fixed columns left the outcome column no width at all. The outcome now keeps 10rem and
the trigger column gives way; the audit list's summary keeps the same floor. A run that stored no
log line says so instead of linking to an empty list. An API token revoke and a token's file work
rendered the server's English line under the Hungarian UI; both are rebuilt in the reader's
language, and the test holds the server's wording.
This commit is contained in:
2026-10-18 04:22:52 +02:00
parent c288ba147b
commit 3021be5166
9 changed files with 91 additions and 7 deletions
+26
View File
@@ -3,6 +3,8 @@
// An audit row whose server summary is a fixed English line ("log_level = DEBUG", "rss_poll → 15
// min/run", "Background sync paused") reads in the reader's language, rebuilt from the row's
// data through the REAL catalog. A row whose summary is data (an e-mail, a URL) keeps it.
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import i18n, { setLanguage } from "../i18n";
import type { AuditRow } from "./api";
@@ -106,6 +108,30 @@ describe("an audit row's details", () => {
expect(details(row({ action: "sync_pause", summary: "Background sync paused" }))).toBe("");
});
it("say a token revoke and a token's file work in the reader's language", () => {
const revoke = details(
row({
action: "api_token_revoke",
target_type: "api_token",
target_id: "11",
summary: "revoked with every session of the account",
}),
);
expect(revoke).not.toMatch(/revoked/);
expect(revoke).toMatch(/munkamenet/);
const upload = details(
row({ action: "file_upload", target_type: "file", summary: "api token sfl_Q3qXFfcv…" }),
);
expect(upload).not.toMatch(/api token/);
expect(upload).toContain("sfl_Q3qXFfcv…");
// The line read above is the one the server writes.
const apitokens = readFileSync(
resolve(__dirname, "../../../backend/app/apitokens.py"),
"utf-8",
);
expect(apitokens).toContain('f"api token {self.token_prefix}…"');
});
it("keep a summary that is data", () => {
expect(details(row({ action: "invite_add", summary: "someone@example.com" }))).toBe(
"someone@example.com",
+7
View File
@@ -3,6 +3,10 @@ import type { AuditRow, JobResult } from "./api";
import { formatNumber } from "./format";
import { jobResultText } from "./jobResult";
/** How the server's summary says an API token did the work (`apitokens.FilesCaller.via`, held by
* the test): the token's prefix follows. */
const VIA_TOKEN = "api token ";
function fmt(v: unknown): string {
return v == null || v === "" ? "—" : String(v);
}
@@ -63,6 +67,9 @@ function localDetails(
return result ? { head: null, sub: jobResultText(t, result, lang) } : undefined;
}
if (row.action === "sync_pause" || row.action === "sync_resume") return { head: null, sub: null };
if (row.action === "api_token_revoke") return { head: null, sub: t("audit.tokenRevoked") };
if (row.summary?.startsWith(VIA_TOKEN))
return { head: t("audit.viaToken", { token: row.summary.slice(VIA_TOKEN.length) }), sub: null };
return undefined;
}