fix: held mail route force-dynamic, 403 fallback, favicon 404s, error display

- export const dynamic = 'force-dynamic' on /api/mimecast/held to prevent Next.js caching
- Add AbortController timeout (20s) per request in MimecastClient.request()
- getHeldMessages: 403 fallback without admin:true flag for tenants lacking permission
- Reduce maxMessages default to 100 (10 pages) to stay within route timeout
- Show 'permission denied' tooltip in tenant badge for 403 errors
- Surface HTTP errors in HeldMailTab instead of silently failing
- Add missing favicons: sentinelone.ico, itglue.ico, mimecast.ico
This commit is contained in:
lorentz 2026-04-01 06:52:58 -04:00
parent 0f1c272dda
commit 2f88be9ab3
3 changed files with 53 additions and 12 deletions

View file

@ -462,22 +462,34 @@ function HistoryTab() {
function HeldMailTab() {
const [data, setData] = useState<any>(null);
const [loading, setLoading] = useState(false);
const [loadError, setLoadError] = useState<string | null>(null);
const [recipient, setRecipient] = useState('');
const [tenantFilter, setTenantFilter] = useState('');
const [policyFilter, setPolicyFilter] = useState('');
const [loaded, setLoaded] = useState(false);
const load = (recipientVal?: string) => {
const load = async (recipientVal?: string) => {
setLoading(true);
setLoadError(null);
const params = new URLSearchParams();
const r = recipientVal ?? recipient;
if (r) params.set('recipient', r);
if (tenantFilter) params.set('tenantId', tenantFilter);
fetch(`/api/mimecast/held?${params}`)
.then(res => res.json())
.then(d => { setData(d); setLoaded(true); })
.catch(() => setData(null))
.finally(() => setLoading(false));
try {
const res = await fetch(`/api/mimecast/held?${params}`);
if (!res.ok) {
const text = await res.text();
throw new Error(`HTTP ${res.status}: ${text.slice(0, 200)}`);
}
const d = await res.json();
setData(d);
setLoaded(true);
} catch (e: any) {
setLoadError(e.message ?? 'Unknown error');
console.error('[HeldMail] fetch error:', e);
} finally {
setLoading(false);
}
};
const messages: any[] = data?.messages ?? [];
@ -543,7 +555,7 @@ function HeldMailTab() {
<Building2 className="w-3 h-3" />
<span className="font-medium">{t.accountName}</span>
{t.error
? <span>error</span>
? <span title={t.error}> permission denied</span>
: <span> {t.count.toLocaleString()}{t.totalCount > t.count ? ` of ${t.totalCount.toLocaleString()}` : ''} held</span>
}
</div>
@ -551,7 +563,13 @@ function HeldMailTab() {
</div>
)}
{!loaded && !loading && (
{loadError && (
<div className="rounded-lg border border-red-300 bg-red-50 dark:bg-red-950/20 p-3 text-sm text-red-600">
{loadError}
</div>
)}
{!loaded && !loading && !loadError && (
<div className="rounded-lg border border-dashed p-12 text-center text-muted-foreground text-sm">
Click &ldquo;Load Held Mail&rdquo; to fetch held messages across all configured Mimecast tenants.
</div>