feat: export parser sessions from the browser

This commit is contained in:
2026-07-22 19:50:19 +02:00
parent 239bb3c465
commit f21d97de21
7 changed files with 355 additions and 18 deletions

View File

@@ -3,6 +3,10 @@ import { AppShell } from '@add-ideas/toolbox-shell-react';
import '@add-ideas/toolbox-shell-react/styles.css';
import { DiagnosticsPanel } from './components/DiagnosticsPanel.js';
import {
ExportControls,
type OneNoteExportFormat,
} from './components/ExportControls.js';
import { FileDropZone } from './components/FileDropZone.js';
import { HelpDialog } from './components/HelpDialog.js';
import { PackageInspector } from './components/PackageInspector.js';
@@ -337,21 +341,39 @@ export function OneNoteApplication({
suggestedName ??
`onenote-resource.${resource.extension ?? 'bin'}`
);
const url = URL.createObjectURL(
new Blob([resource.bytes], { type: resource.mediaType })
);
const anchor = document.createElement('a');
anchor.href = url;
anchor.download = filename;
anchor.rel = 'noopener';
document.body.append(anchor);
anchor.click();
anchor.remove();
window.setTimeout(() => URL.revokeObjectURL(url), 1_000);
downloadBrowserFile(resource.bytes, resource.mediaType, filename);
},
[loadSelectedResource]
);
const exportLoadedSource = useCallback(
async (format: OneNoteExportFormat): Promise<void> => {
const client = activeClient.current;
if (!client || state.phase !== 'loaded') {
throw new WorkerClientError(
'session-not-available',
'The local parser session is no longer available.'
);
}
const response = await client.exportSession(
state.source.sessionId,
format
);
if (response.type === 'failure') {
throw new WorkerClientError(
response.error.code,
response.error.message
);
}
downloadBrowserFile(
response.artifact.bytes,
response.artifact.mediaType,
safeDownloadFilename(response.artifact.filename)
);
},
[state]
);
const visibleDiagnostics = uniqueDiagnostics(
(() => {
if (state.phase !== 'loaded') return [];
@@ -409,6 +431,8 @@ export function OneNoteApplication({
<PackageInspector notebook={state.source.notebook} />
) : null}
<ExportControls onExport={exportLoadedSource} />
<div className="reader-workspace">
{state.source.kind === 'one' ? (
<SingleSectionNavigation
@@ -486,6 +510,22 @@ function safeDownloadFilename(value: string): string {
return (cleaned || 'onenote-resource.bin').slice(0, 180);
}
function downloadBrowserFile(
bytes: ArrayBuffer,
mediaType: string,
filename: string
): void {
const url = URL.createObjectURL(new Blob([bytes], { type: mediaType }));
const anchor = document.createElement('a');
anchor.href = url;
anchor.download = filename;
anchor.rel = 'noopener';
document.body.append(anchor);
anchor.click();
anchor.remove();
window.setTimeout(() => URL.revokeObjectURL(url), 1_000);
}
export function App() {
const [helpOpen, setHelpOpen] = useState(false);