Repository navigation
feat(lineage): refresh button and data age on the Compliance Map - #358
Conversation
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
gusfcarvalho
left a comment
There was a problem hiding this comment.
ccf-review: REQUEST_CHANGES
3 Must-fix, 1 Nit.
Stack (gh stack 359): #357 → #358
Outside the diff
- [Must-fix]
src/composables/useLineage/index.ts:186A request in flight when Refresh is clicked writes pre-refresh data back into the cleared cache:refresh()clears the module cache, but agetChildren(orgetRoots) call already awaiting the API still runscache.set(ck, nodes)andnoteGeneratedAt(...)when it resolves. Because Refresh doesn't change the scope, the cache key is the same, so the stale result lands in the fresh cache. Reachable: expand a large node, then click Refresh before its children arrive. The node-expand fetch doesn't disable the button. The old response then fills the cache under the same key. When the view replays its expanded nodes after the refresh, it gets those pre-refresh children from the cache, and the label moves back to the old time. Before this PR the only cache reset was a scope change, and the key includes the scope, so a late response could never land in the new cache. (2af4f09a72f0)
|
Review body item (Outside the diff, Must-fix, src/composables/useLineage/index.ts): fixed in 3676dd6. |
|
PR approved. Marking ready for e2e. |
The API now shares built Compliance Map data across requests for a few minutes (CCF_LINEAGE_CACHE_TTL), so expanding nodes and opening the drawer no longer rebuild everything. This adds the controls for that cache: - The scope bar shows "Updated <time> ago", from the X-Lineage-Generated-At header (the oldest response since the cache was cleared). - A Refresh button clears the client cache and sends refresh=true on the next roots fetch. The tree keeps its expanded nodes and the graph replays its drill-down path. - After a refresh in an SSP- or component-scoped view, the drawer's per-SSP table rebuilds the unscoped data it reads, so it is not left stale. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Self-review pass 1. The scope bar's refreshing state followed loading, which clears once the roots land, so a second click during the graph's path replay started a second replay pushing onto the same columns. Both views now hold a refreshing flag across the whole reload. Adds a graph refresh test and a drawer test pinning that a refreshed node object reloads the drawer's panels. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A getRoots/getChildren request in flight when refresh() cleared the cache used to store its pre-refresh nodes under the same key and move the data age back. clearCache() now bumps a generation; a response from an older generation is returned to its caller but not cached, and does not touch the data age or the pending refresh flags. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
takeUnscopedRefresh() cleared the flag before the /ssps request, so a failed request lost the pending rebuild and the next open read stale unscoped data. The drawer now puts it back with restoreUnscopedRefresh() when its request fails. Specs cover the one-time refresh=true after a view refresh and the retry after a failed request. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
31af6fd to
2556b9c
Compare
Stacked on #357 (
poc/menu-reorg). Depends on compliance-framework/api#513.Why
Heavy Compliance Map users click a lot, and every click used to rebuild the whole lineage graph on the API: 320–400 ms per expand or drill-down. api#513 shares built engines across requests behind a TTL, so warm clicks take about 1 ms. Cached data can now be a few minutes old, so the UI has to say how old it is and let people rebuild it.
What changed
useLineage(src/composables/useLineage/index.ts)generatedAt: the oldestX-Lineage-Generated-Atseen since the client cache was last cleared, so the label never claims fresher data than some node on screen. Missing or malformed headers are ignored.refresh(): clears the client cache and sendsrefresh=trueon the next roots fetch. Later requests reuse that rebuild.takeUnscopedRefresh(): the drawer's per-SSP table always reads the unscoped engine. After a refresh in an SSP- or component-scoped view, the drawer's next/sspsrequest sendsrefresh=trueso that engine is rebuilt too. An unscoped refresh already rebuilt it, so the flag is cleared.LineageScopeBargets a Refresh button and an "Updated X ago" label (useTimeAgo; the full time is in the tooltip).generatedAtand the busy state, and handlerefresh. The tree keeps its expanded nodes and selection, and the graph replays its drill-down path. The button stays disabled until the whole reload is done, roots plus replay, so a second click can't start an overlapping replay.Without api#513 it degrades gracefully: no header means no label, and the API ignores the unknown
refreshparam, so Refresh just refetches.Testing
make reviewable(formatcheck, typecheck, lint, unit tests): 1,832 tests pass.useLineage.spec: refresh param on the next roots fetch only, oldest generated-at, bad headers, scoped vs unscoped follow-up.LineageScopeBar.spec: emit, disabled state, label.LineageTreeView.spec: refresh keeps the expanded nodes.LineageGraphView.spec: refresh replays the path and stays busy until the replay is done.LineageNodeDrawer.spec: a refreshed node object reloads the drawer's panels.Open questions for reviewers
None.
🤖 Generated with Claude Code