/** * ExecRedirect — wraps the standalone task page (`MeshPage`) at `/exec/:id` * so that, when the user has document-mode enabled AND the task is attached * to a directive, we forward them to `/directives/?task=` * (the doc-mode task surface). For orphan tasks or non-doc-mode users we * just render the existing MeshPage. * * Why a wrapper rather than a redirect at route level: we need the task's * `directiveId` field, which only the API returns. We optimistically render * a loading shim while the lookup happens, then either replace the URL or * mount the legacy page. */ import { useEffect, useState } from "react"; import { useNavigate, useParams } from "react-router"; import { getTask, type Task } from "../lib/api"; import { useUserSettings } from "../hooks/useUserSettings"; import MeshPage from "./mesh"; export default function ExecRedirect() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const { settings, loading: settingsLoading } = useUserSettings(); const [decided, setDecided] = useState<"redirect" | "stay" | null>(null); useEffect(() => { if (!id || settingsLoading) return; let cancelled = false; getTask(id) .then((task: Task) => { if (cancelled) return; const documentMode = settings?.documentModeEnabled ?? false; const directiveId = (task as Task & { directiveId?: string | null }) .directiveId ?? null; if (documentMode && directiveId) { navigate(`/directives/${directiveId}?task=${id}`, { replace: true }); return; } setDecided("stay"); }) .catch(() => { // If we can't read the task (404, network, etc.), just let the // legacy MeshPage handle the error display. if (!cancelled) setDecided("stay"); }); return () => { cancelled = true; }; }, [id, settingsLoading, settings?.documentModeEnabled, navigate]); if (decided === null) { return (

Loading…

); } return ; }