diff --git a/frontend/src/screens/Inbox.jsx b/frontend/src/screens/Inbox.jsx index d69c17a..62e798a 100644 --- a/frontend/src/screens/Inbox.jsx +++ b/frontend/src/screens/Inbox.jsx @@ -1389,6 +1389,9 @@ export default function Inbox() { queryFn: () => (selectedKind === 'form' ? fetchFormDetail(selectedId) : fetchMessageDetail(selectedId)), enabled: Boolean(selectedId), }) + // List rows paint immediately; GET-by-id is the full application. Block every + // control in the detail pane until that fetch succeeds. The queue stays live. + const detailLocked = Boolean(selectedId) && !detailQuery.isError && !detailQuery.isSuccess const sidebar = useMemo(() => { if (!isForms) return list @@ -1959,32 +1962,40 @@ export default function Inbox() { {friendlyAuthError(detailQuery.error, 'Request failed')} - ) : selected?.kind === 'form' ? ( - importItem(selected)} - onMove={() => moveToPipeline(selected)} - onNote={() => setNoting(selected)} - onReject={() => reject(selected)} - onToggleDuplicate={() => toggleDuplicate(selected)} - /> ) : ( - importItem(selected)} - onMove={() => moveToPipeline(selected)} - onNote={() => setNoting(selected)} - onReject={() => reject(selected)} - onToggleDuplicate={() => toggleDuplicate(selected)} - /> +
+ {selected?.kind === 'form' ? ( + importItem(selected)} + onMove={() => moveToPipeline(selected)} + onNote={() => setNoting(selected)} + onReject={() => reject(selected)} + onToggleDuplicate={() => toggleDuplicate(selected)} + /> + ) : ( + importItem(selected)} + onMove={() => moveToPipeline(selected)} + onNote={() => setNoting(selected)} + onReject={() => reject(selected)} + onToggleDuplicate={() => toggleDuplicate(selected)} + /> + )} +
)} diff --git a/frontend/src/styles/styles.css b/frontend/src/styles/styles.css index fdaadb5..b74a459 100644 --- a/frontend/src/styles/styles.css +++ b/frontend/src/styles/styles.css @@ -1032,6 +1032,14 @@ canvas { width: 100%; max-width: 100%; display: block; } .inbox-split { grid-template-columns: minmax(280px, 34%) minmax(0, 1fr); } /* Desktop keeps the two-pane split; only the phone layout below shows it. */ .inbox-back { display: none; } +/* Detail pane is painted from the list row before GET-by-id returns. Block + every control inside it until that payload lands — the queue list stays live. */ +.inbox-detail-pending { + pointer-events: none; + user-select: none; + opacity: 0.55; + cursor: wait; +} /* Phones: the stacked split nested two scroll wells inside the page scroll. Instead: one page scroll, and a selected application takes over from the list — the Back button returns to it (standard master-detail collapse). */