From 6f99fdb18bf034ad7e3fbfe44fa32546467530c0 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Thu, 16 Jul 2026 13:34:54 -0700 Subject: [PATCH] FN-8137: add PR checks refresh control Let GitHub pull request previews refresh their current check status and comments. - Add an accessible refresh action that bypasses the selected PR detail cache - Prevent stale refresh responses from overwriting cached or visible PR details - Cover refresh behavior across modal and embedded views, and document the control - Add a minor changeset for the new GitHub import capability Files changed: .changeset/fn-8137-refresh-pr-checks.md | 7 ++ docs/dashboard-guide.md | 2 +- .../dashboard/app/components/GitHubImportModal.css | 29 ++++++ .../dashboard/app/components/GitHubImportModal.tsx | 48 +++++++-- .../__tests__/GitHubImportModal.test.tsx | 115 +++++++++++++++++++++ 5 files changed, 191 insertions(+), 10 deletions(-) Fusion-Task-Id: FN-8137 Fusion-Task-Lineage: 1d4ffa9d-635c-4d59-b17c-63075f6d8c5e Co-authored-by: Fusion (runfusion.ai) --- .changeset/fn-8137-refresh-pr-checks.md | 7 ++ docs/dashboard-guide.md | 2 +- .../app/components/GitHubImportModal.css | 29 +++++ .../app/components/GitHubImportModal.tsx | 48 ++++++-- .../__tests__/GitHubImportModal.test.tsx | 115 ++++++++++++++++++ 5 files changed, 191 insertions(+), 10 deletions(-) create mode 100644 .changeset/fn-8137-refresh-pr-checks.md diff --git a/.changeset/fn-8137-refresh-pr-checks.md b/.changeset/fn-8137-refresh-pr-checks.md new file mode 100644 index 0000000000..7d2d91fd66 --- /dev/null +++ b/.changeset/fn-8137-refresh-pr-checks.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": minor +--- + +summary: Add a Refresh checks button to GitHub import PR previews for fresh CI status. +category: feature +dev: Refresh evicts the selected pull-detail cache entry and guards stale cache writes (FN-8137). diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index 08d4e52d25..0152372d32 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -312,7 +312,7 @@ Use Import Tasks on desktop/tablet: 3. Stay on **Issues** or switch to **Pull Requests**, then optionally enter issue label filters before loading results. Expected outcome: the list pane shows matching open issues or pull requests and marks entries that already exist on the board. Use **Hide imported** beside the imported count to remove those unavailable rows from the current Issues, Pull Requests, or GitLab list; turning it off restores the greyed **Imported** rows. After a successful GitHub or GitLab import, the source row is marked **Imported** and made unavailable immediately, without waiting for the board list to refresh. 4. Select an issue or pull request row. - Expected outcome: the full-width candidate list stays visible while its title, source link, body, labels or PR metadata, and import controls open in a draggable and resizable detail window. On mobile, that detail is a full-screen sheet. When selected title/body content is in another language, the detail offers **Translate**, **Show original** / **Show translation**, and **Dismiss**; translation is display-only. A pull request preview also shows its checks; each failed check has a **Create fix task** action that creates a new task prefilled with the repository, PR, branches, check status, and check-details link. + Expected outcome: the full-width candidate list stays visible while its title, source link, body, labels or PR metadata, and import controls open in a draggable and resizable detail window. On mobile, that detail is a full-screen sheet. When selected title/body content is in another language, the detail offers **Translate**, **Show original** / **Show translation**, and **Dismiss**; translation is display-only. A pull request preview also shows its checks; use **Refresh checks** to fetch current GitHub check status and comments without reopening the detail. Each failed check has a **Create fix task** action that creates a new task prefilled with the repository, PR, branches, check status, and check-details link. 5. Select the import action in the detail window. Pull requests use **Resolve feedback**, which creates a task to resolve reviewer feedback and address failed CI checks; issues keep **Import**. Each GitHub issue and pull-request comment also has **Import as task**, which creates a separate resolve-feedback task quoting that comment and linking its source without closing the detail window. Expected outcome: Fusion creates the requested task, preserves GitHub provenance/tracking metadata, and returns the completed PR/issue import to the list while leaving comment imports available for further feedback. diff --git a/packages/dashboard/app/components/GitHubImportModal.css b/packages/dashboard/app/components/GitHubImportModal.css index 83c6d97e72..cef0f4aa69 100644 --- a/packages/dashboard/app/components/GitHubImportModal.css +++ b/packages/dashboard/app/components/GitHubImportModal.css @@ -1081,6 +1081,27 @@ Checks + Comments sections live below the PR body in the scrollable preview pane color: var(--text-muted); } +/* +FNXC:GitHubImport 2026-07-16-19:00: +FN-8137 keeps the PR checks refresh control in the section heading so changing CI state is discoverable without competing with individual check actions. +*/ +.github-import-pr-checks__heading-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-sm); + margin-bottom: var(--space-sm); +} + +.github-import-pr-checks__heading-row .preview-section-heading { + margin-bottom: 0; +} + +.github-import-pr-checks-refresh { + flex: 0 0 auto; + color: var(--text-muted); +} + .preview-detail-loading { display: flex; align-items: center; @@ -1675,6 +1696,14 @@ Import Tasks embedded header now adopts the canonical ViewHeader chrome — edge grid-template-columns: 1fr; } + .github-import-pr-checks__heading-row { + flex-wrap: wrap; + } + + .github-import-pr-checks__heading-row .preview-section-heading { + flex: 1 1 auto; + } + .github-import-pr-check-row { flex-wrap: wrap; align-items: center; diff --git a/packages/dashboard/app/components/GitHubImportModal.tsx b/packages/dashboard/app/components/GitHubImportModal.tsx index a75e2f83fd..b51a0a0596 100644 --- a/packages/dashboard/app/components/GitHubImportModal.tsx +++ b/packages/dashboard/app/components/GitHubImportModal.tsx @@ -497,6 +497,9 @@ export function GitHubImportModal({ isOpen, onClose, onImport, tasks, projectId, The PR preview pane shows the full comment thread + per-check status for the SELECTED PR only. `gh pr list` returns just comment COUNT + no per-check detail, so the full thread/checks are fetched ON SELECTION via apiFetchGitHubPullDetail — never for the whole list (too expensive). Detail is cached by PR number in a ref so re-selecting a PR does not refetch; the body renders immediately while checks/comments stream in (loading/error tracked separately, never blocking the body). + + FNXC:GitHubImport 2026-07-16-19:00: + FN-8137 adds an explicit force-refresh path for changing GitHub CI and comments. It evicts only the selected PR cache entry before refetching while normal selection remains cache-first. */ const pullDetailCacheRef = useRef>(new Map()); const [pullDetail, setPullDetail] = useState(null); @@ -1129,12 +1132,8 @@ export function GitHubImportModal({ isOpen, onClose, onImport, tasks, projectId, } }, [activeTab, selectedIssueNumber, selectedPullNumber, issues, pulls, owner, repo, projectId, onImport, returnToIssueListAfterSuccess]); - /* - FNXC:GitHubImport 2026-06-23-01:00: - Fetch the selected PR's detail (comments + checks) on selection. Serves from the per-number cache on re-select; otherwise fetches and caches. - Body render is never blocked on this — the body shows immediately and checks/comments populate when this resolves. - */ - useEffect(() => { + const fetchPullDetail = useCallback((force: boolean) => { + const requestId = ++pullDetailRequestRef.current; if (activeTab !== "pulls" || selectedPullNumber === null || !owner.trim() || !repo.trim()) { setPullDetail(null); setPullDetailLoading(false); @@ -1142,6 +1141,10 @@ export function GitHubImportModal({ isOpen, onClose, onImport, tasks, projectId, return; } + if (force) { + pullDetailCacheRef.current.delete(selectedPullNumber); + } + const cached = pullDetailCacheRef.current.get(selectedPullNumber); if (cached) { setPullDetail(cached); @@ -1150,15 +1153,15 @@ export function GitHubImportModal({ isOpen, onClose, onImport, tasks, projectId, return; } - const requestId = ++pullDetailRequestRef.current; setPullDetail(null); setPullDetailLoading(true); setPullDetailError(null); apiFetchGitHubPullDetail(`${owner.trim()}/${repo.trim()}`, selectedPullNumber) .then((detail) => { - pullDetailCacheRef.current.set(selectedPullNumber, detail); + // FNXC:GitHubImport 2026-07-16-19:00: FN-8137 requires stale detail requests to be unable to poison the cache as well as the currently visible checks and comments. if (pullDetailRequestRef.current !== requestId) return; + pullDetailCacheRef.current.set(selectedPullNumber, detail); setPullDetail(detail); setPullDetailLoading(false); }) @@ -1169,6 +1172,20 @@ export function GitHubImportModal({ isOpen, onClose, onImport, tasks, projectId, }); }, [activeTab, selectedPullNumber, owner, repo]); + /* + FNXC:GitHubImport 2026-06-23-01:00: + Fetch the selected PR's detail (comments + checks) on selection. Serves from the per-number cache on re-select; otherwise fetches and caches. + Body render is never blocked on this — the body shows immediately and checks/comments populate when this resolves. + */ + useEffect(() => { + fetchPullDetail(false); + }, [fetchPullDetail]); + + const handleRefreshChecks = useCallback(() => { + if (selectedPullNumber === null || pullDetailLoading) return; + fetchPullDetail(true); + }, [fetchPullDetail, pullDetailLoading, selectedPullNumber]); + /* FNXC:GitHubImport 2026-06-23-03:15: Fetch the selected issue's comments on selection. Serves from the per-number cache on re-select; otherwise fetches and caches. @@ -2001,7 +2018,20 @@ export function GitHubImportModal({ isOpen, onClose, onImport, tasks, projectId, Check status maps to a theme-token pill class (success/failure/pending/neutral); the rollup conclusion is preferred over the in-progress status for color. */}
-
{t("git.checksHeading", "Checks")}
+
+
{t("git.checksHeading", "Checks")}
+ +
{pullDetailLoading ? (