mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 06:32:03 +00:00
Finish the wiring polish: verbosity gate, upload flash, /about links, dead settings slugs
- The Coach verbosity picker is disabled while the concise tone forces brief, with a hint saying so, instead of a live control that silently does nothing. - A fresh document upload flashes its new row like the duplicate path always did; the settle decision is a pure exported helper with a test. - /about gains its two inbound links: the /privacy footer and a Settings→About credits row (the GeoLite2 EULA wants the attribution reachable from the running app). - The eight settings slugs shadowed by permanent redirects (the seven layout children + sharing) leave the slug registry: no more prerendering unreachable pages, no dead component wirings, and the SectionPlaceholder fallback that could never render is gone. The redirects, section components, and layout-hub subpages are unchanged.
This commit is contained in:
1 parent
3b1314d1b0
commit
542ca91be5
25 files changed
+181
-223
No files matched your search
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* The upload manager's settle decision (§3.2 + the fresh-upload flash).
|
||||
*
|
||||
* Watched red: with `settleDecision` returning `flashId: null` on the
|
||||
* non-duplicate branch (the pre-v1.37.19 behaviour — only the duplicate
|
||||
* path flashed the row), the fresh-upload case below fails. A fresh upload
|
||||
* used to give no feedback beyond its queue row disappearing.
|
||||
*/
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { settleDecision } from "../use-document-upload";
|
||||
import type { UploadResult } from "../vault-utils";
|
||||
|
||||
function success(duplicate: boolean): UploadResult {
|
||||
return {
|
||||
ok: true,
|
||||
duplicate,
|
||||
document: { id: "doc-1" },
|
||||
} as unknown as UploadResult;
|
||||
}
|
||||
|
||||
describe("settleDecision", () => {
|
||||
it("flashes the NEW row on a fresh upload (no toast)", () => {
|
||||
expect(settleDecision(success(false))).toEqual({
|
||||
removeFromQueue: true,
|
||||
toastDuplicate: false,
|
||||
flashId: "doc-1",
|
||||
});
|
||||
});
|
||||
|
||||
it("flashes the EXISTING row and toasts on a duplicate", () => {
|
||||
expect(settleDecision(success(true))).toEqual({
|
||||
removeFromQueue: true,
|
||||
toastDuplicate: true,
|
||||
flashId: "doc-1",
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps a failed upload in the queue with no flash", () => {
|
||||
expect(
|
||||
settleDecision({ ok: false, reason: "generic" } as UploadResult),
|
||||
).toEqual({ removeFromQueue: false, toastDuplicate: false, flashId: null });
|
||||
});
|
||||
});
|
||||
@@ -136,6 +136,29 @@ function uploadViaXhr(
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The pure settle decision — what a finished upload does to the UI.
|
||||
*
|
||||
* Every success flashes the row (fresh upload → the new row, duplicate →
|
||||
* the existing row); only the duplicate additionally toasts. Exported for
|
||||
* the unit test: until v1.37.19 only the duplicate branch flashed, so a
|
||||
* fresh upload gave no feedback beyond its queue row disappearing.
|
||||
*/
|
||||
export function settleDecision(result: UploadResult): {
|
||||
removeFromQueue: boolean;
|
||||
toastDuplicate: boolean;
|
||||
flashId: string | null;
|
||||
} {
|
||||
if (!result.ok) {
|
||||
return { removeFromQueue: false, toastDuplicate: false, flashId: null };
|
||||
}
|
||||
return {
|
||||
removeFromQueue: true,
|
||||
toastDuplicate: result.duplicate,
|
||||
flashId: result.document.id,
|
||||
};
|
||||
}
|
||||
|
||||
export interface DocumentUploadManager {
|
||||
/** Live queue — uploading entries first-in-first, then error entries. */
|
||||
items: UploadQueueItem[];
|
||||
@@ -196,16 +219,17 @@ export function useDocumentUpload(
|
||||
|
||||
const settle = useCallback(
|
||||
(localId: string, result: UploadResult) => {
|
||||
if (result.ok) {
|
||||
removeItem(localId);
|
||||
void invalidateKeys(queryClient, [queryKeys.documents()]);
|
||||
if (result.duplicate) {
|
||||
toast.info(t("documents.toast.duplicate"));
|
||||
flashHighlight(result.document.id);
|
||||
}
|
||||
if (!result.ok) {
|
||||
patchItem(localId, { status: "error", failure: result, progress: 0 });
|
||||
return;
|
||||
}
|
||||
patchItem(localId, { status: "error", failure: result, progress: 0 });
|
||||
const decision = settleDecision(result);
|
||||
removeItem(localId);
|
||||
void invalidateKeys(queryClient, [queryKeys.documents()]);
|
||||
if (decision.toastDuplicate) {
|
||||
toast.info(t("documents.toast.duplicate"));
|
||||
}
|
||||
if (decision.flashId) flashHighlight(decision.flashId);
|
||||
},
|
||||
[flashHighlight, patchItem, queryClient, removeItem, t],
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user