mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-03 16:16:59 +00:00
Organisation > Devices now sets policy.json `organisation.devices`, each
switch off by default and scoped per domain or group:
- No downloads: attachments and files only preview (reader, conversation
view, Pro tab, list chips, .eml previews, the Files app). Download,
Download all, Open in new tab, Save to Files, drag-out, the browser's
PDF viewer (pdf.js instead) and media download controls go away.
- No export: no .eml export, View source, message drag-out, or folder and
account export; a running export stops and its file is deleted when
the switch turns on. Import stays.
- No printing: no Print buttons in mail, calendar and contacts; Ctrl+P
prints a note; the reader frame prints blank.
- No install prompt: no card, and the browser's own banner is held back.
- Watermark: the user's address and the date over the reader,
previews and every printout (mail, calendar, contacts, plugins).
A message follows its own account's policy; what isn't about one message
follows the strictest signed-in account. Every user path hides its
button, and the anchor and new-tab helpers refuse as a backstop
(lib/download-guard.ts), never the blob readers. The plugin APIs
`ui.downloadFile` and `ui.print` refuse too, and the office editor frame
loses `allow-downloads`.
Two assertions in components/mail/__tests__/blob-routing.test.tsx now
expect `{ kind: 'export' }` as the fifth argument of downloadBlob for an
.eml export: the export says what it is, so the backstop checks "No
export" rather than "No downloads" for it.
52 lines
1.8 KiB
TypeScript
52 lines
1.8 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useLayoutEffect, type ReactNode } from "react";
|
|
import { createPortal } from "react-dom";
|
|
import { listenForPrinting, usePrintStore } from "@/stores/print-store";
|
|
import { Watermark, useWatermarkText } from "@/components/device/watermark";
|
|
|
|
export type PrintOrientation = "portrait" | "landscape";
|
|
|
|
/** Prints this page's copy on Ctrl+P while the page is mounted. */
|
|
export function usePrintListener(): void {
|
|
useEffect(() => listenForPrinting(), []);
|
|
}
|
|
|
|
/** True while the browser prints (or is about to): the page renders its print copy then. */
|
|
export function usePrinting(): boolean {
|
|
return usePrintStore((s) => s.printing);
|
|
}
|
|
|
|
interface PrintRootProps {
|
|
/** The paper orientation the copy is laid out for; the dialog may still change it. */
|
|
orientation: PrintOrientation;
|
|
/** The document title while printing: browsers use it as the PDF's file name and page header. */
|
|
title?: string;
|
|
children: ReactNode;
|
|
}
|
|
|
|
/**
|
|
* The print copy of a page. It sits next to the app in <body> and, in print
|
|
* media, replaces it (app/print.css), so no app chrome, open menu or toast
|
|
* reaches the paper. On screen it is never shown.
|
|
*/
|
|
export function PrintRoot({ orientation, title, children }: PrintRootProps) {
|
|
// Organisation > Devices > Watermark: on every printed page.
|
|
const watermark = useWatermarkText(undefined, { strictest: true });
|
|
useLayoutEffect(() => {
|
|
if (!title) return;
|
|
const previous = document.title;
|
|
document.title = title;
|
|
return () => { document.title = previous; };
|
|
}, [title]);
|
|
|
|
return createPortal(
|
|
<div data-print-root="" data-orientation={orientation} className="pr-root">
|
|
<style>{`@page { size: ${orientation}; margin: 12mm; }`}</style>
|
|
<Watermark text={watermark} fixed />
|
|
{children}
|
|
</div>,
|
|
document.body,
|
|
);
|
|
}
|