Add searchable and flattened export, history re-export and diagnostics self-test

issueAndArchive keeps an issued invoice even when rendering or archiving
fails (Issued - not archived, with a Render & archive action). The export
menu offers a searchable PDF or a 300 DPI image-only PDF whose metadata is
the invoice number alone; flatten failures offer Retry or searchable export
and never silently lower the resolution. History re-exports the original
as issued by default and warns when a re-render's layout fingerprint
differs. The render client gains a FIFO assemble lane that previews cannot
supersede. A Diagnostics panel runs fixtures in the real worker and
compares against goldens generated from Node.
This commit is contained in:
2026-10-04 06:11:23 +05:30
parent 2ade618fb5
commit 98e9e5860f
30 changed files with 2727 additions and 154 deletions
+17
View File
@@ -4,6 +4,7 @@ import {
Column,
Grid,
InlineNotification,
Link,
NumberInput,
RadioButton,
RadioButtonGroup,
@@ -32,6 +33,7 @@ import {
} from "../lib/types";
import { emailError, ifscError, panError, phoneError, vendorGstinError } from "../lib/validators";
import { ImagePicker } from "../components/ImagePicker";
import DiagnosticsPanel from "../components/DiagnosticsPanel";
const blankBank = (): BankAccount => ({
id: null,
@@ -52,6 +54,7 @@ export default function AppSettings({
onSaved: () => void;
}) {
const [form, setForm] = useState<Settings>({ ...settings });
const [diagnosticsOpen, setDiagnosticsOpen] = useState(false);
const [banks, setBanks] = useState<BankAccount[]>([]);
const [editing, setEditing] = useState<BankAccount | null>(null);
const [busy, setBusy] = useState(false);
@@ -474,6 +477,20 @@ export default function AppSettings({
<Button renderIcon={Save} onClick={saveAll} disabled={busy}>
{busy ? "Saving…" : "Save settings"}
</Button>
<p className="voiced-muted" style={{ marginTop: "3rem", fontSize: "0.75rem" }}>
<Link
href="#"
size="sm"
onClick={(e: { preventDefault: () => void }) => {
e.preventDefault();
setDiagnosticsOpen(true);
}}
>
Diagnostics
</Link>
</p>
<DiagnosticsPanel open={diagnosticsOpen} onClose={() => setDiagnosticsOpen(false)} />
</div>
);
}