From 3470654fc5478c83138babca5266f391f6458d39 Mon Sep 17 00:00:00 2001 From: Antti Kettunen Date: Sat, 2 May 2026 20:27:42 +0300 Subject: [PATCH] Move issue detail query into modal - let the issue detail modal own its selected-issue query and loading states - keep the issues page focused on route state and modal orchestration - preserve the loader prefetch so the modal still opens from warm cache --- .../routes/issues/-ui/issue-detail-modal.tsx | 31 ++++++++++--------- webui/src/routes/issues/-ui/issues-page.tsx | 14 ++------- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/webui/src/routes/issues/-ui/issue-detail-modal.tsx b/webui/src/routes/issues/-ui/issue-detail-modal.tsx index 6c1f5215..4a11d63e 100644 --- a/webui/src/routes/issues/-ui/issue-detail-modal.tsx +++ b/webui/src/routes/issues/-ui/issue-detail-modal.tsx @@ -1,4 +1,4 @@ -import { useMutation } from '@tanstack/react-query'; +import { useMutation, useQuery } from '@tanstack/react-query'; import { useEffect, useMemo, useState, type ReactNode } from 'react'; import { DialogBody, DialogFooter, DialogFrame, DialogHeader } from '@/components/dialog'; @@ -10,7 +10,7 @@ import { import type { IssueRecord } from '../-issues.types'; -import { deleteIssue, updateIssue } from '../-issues.api'; +import { deleteIssue, issueDetailQueryOptions, updateIssue } from '../-issues.api'; import { formatIssueDate, formatStatusLabel, @@ -22,24 +22,27 @@ import { import styles from './issue-detail-modal.module.css'; export function IssueDetailModal({ - error, isAdmin, - isLoading, - issue, + issueId, onClose, onMutationSuccess, profileId, }: { - error: unknown; isAdmin: boolean; - isLoading: boolean; - issue: IssueRecord | null; + issueId: number | null; onClose: () => void; onMutationSuccess: () => void; profileId: number; }) { + const selectedIssueQuery = useQuery({ + ...issueDetailQueryOptions(profileId, issueId ?? 0), + enabled: profileId > 0 && issueId !== null, + }); + const issue = selectedIssueQuery.data ?? null; + const queryError = selectedIssueQuery.error; + const queryLoading = selectedIssueQuery.isLoading; const [adminResponse, setAdminResponse] = useState(''); - const isOpen = Boolean(issue || isLoading || error); + const isOpen = Boolean(issueId || queryLoading || queryError); useEffect(() => { setAdminResponse(issue?.admin_response || ''); @@ -171,7 +174,7 @@ export function IssueDetailModal({ return null; }, [adminResponse, deleteMutation, isAdmin, issue, updateMutation]); - if (!issue && !isLoading && !error) { + if (!issue && !queryLoading && !queryError) { return null; } @@ -210,16 +213,16 @@ export function IssueDetailModal({ closeLabel="Close issue detail" /> - {isLoading ? ( + {queryLoading ? (
Loading issue details...
- ) : error ? ( + ) : queryError ? (
Failed to load issue
- {error instanceof Error ? error.message : 'Unknown error'} + {queryError instanceof Error ? queryError.message : 'Unknown error'}
) : issue ? ( @@ -414,7 +417,7 @@ export function IssueDetailModal({ - {!isLoading && !error && issue && ( + {issue && ( <> {statusButtons} {isAdmin && ( diff --git a/webui/src/routes/issues/-ui/issues-page.tsx b/webui/src/routes/issues/-ui/issues-page.tsx index f480f9fc..2d90b0ef 100644 --- a/webui/src/routes/issues/-ui/issues-page.tsx +++ b/webui/src/routes/issues/-ui/issues-page.tsx @@ -8,11 +8,7 @@ import { useReactPageShell } from '@/platform/shell/route-controllers'; import type { IssueCounts, IssueRecord, IssueStatus } from '../-issues.types'; -import { - issueCountsQueryOptions, - issueDetailQueryOptions, - issueListQueryOptions, -} from '../-issues.api'; +import { issueCountsQueryOptions, issueListQueryOptions } from '../-issues.api'; import { CLOSE_EVENT, REFRESH_EVENT, @@ -85,10 +81,6 @@ export function IssuesPage() { ...issueListQueryOptions(profileId, normalizedSearch), enabled: profileId > 0, }); - const selectedIssueQuery = useQuery({ - ...issueDetailQueryOptions(profileId, selectedIssueId ?? 0), - enabled: profileId > 0 && selectedIssueId !== null, - }); if (!bridge || !profile || !bridge.isPageAllowed('issues')) { return null; @@ -130,9 +122,7 @@ export function IssuesPage() { /> clearIssueSelection(navigate)} onMutationSuccess={() => { clearIssueSelection(navigate);