feat(tui): wire entity cache for near-instant detail view reopens (bd-3rjw)
- Add get_mut() and clear() methods to EntityCache<V> - Add CachedIssuePayload / CachedMrPayload types to state - Wire cache check in navigate_to for instant cache hits - Populate cache on IssueDetailLoaded / MrDetailLoaded - Update cache on DiscussionsLoaded - Add 6 new entity_cache tests (get_mut, clear)
This commit is contained in:
@@ -371,7 +371,11 @@ fn render_mr_list(
|
||||
|
||||
// Inline discussion snippets (rendered beneath MRs when toggled on).
|
||||
if state.show_discussions && !result.discussions.is_empty() {
|
||||
let visible_mrs = result.merge_requests.len().saturating_sub(offset).min(height);
|
||||
let visible_mrs = result
|
||||
.merge_requests
|
||||
.len()
|
||||
.saturating_sub(offset)
|
||||
.min(height);
|
||||
let disc_start_y = start_y + visible_mrs as u16;
|
||||
let remaining = height.saturating_sub(visible_mrs);
|
||||
render_discussions(frame, result, x, disc_start_y, max_x, remaining, bp);
|
||||
|
||||
@@ -113,9 +113,7 @@ pub fn render_issue_detail(
|
||||
y = render_metadata_row(frame, meta, bp, area.x, y, max_x);
|
||||
|
||||
// --- Optional milestone / due date row (skip on Xs — too narrow) ---
|
||||
if !matches!(bp, Breakpoint::Xs)
|
||||
&& (meta.milestone.is_some() || meta.due_date.is_some())
|
||||
{
|
||||
if !matches!(bp, Breakpoint::Xs) && (meta.milestone.is_some() || meta.due_date.is_some()) {
|
||||
y = render_milestone_row(frame, meta, area.x, y, max_x);
|
||||
}
|
||||
|
||||
@@ -136,7 +134,8 @@ pub fn render_issue_detail(
|
||||
let xref_count = state.cross_refs.len();
|
||||
|
||||
let wide = detail_side_panel(bp);
|
||||
let (desc_h, disc_h, xref_h) = allocate_sections(remaining, desc_lines, disc_count, xref_count, wide);
|
||||
let (desc_h, disc_h, xref_h) =
|
||||
allocate_sections(remaining, desc_lines, disc_count, xref_count, wide);
|
||||
|
||||
// --- Description section ---
|
||||
if desc_h > 0 {
|
||||
@@ -629,7 +628,10 @@ mod tests {
|
||||
fn test_allocate_sections_wide_gives_more_description() {
|
||||
let (d_narrow, _, _) = allocate_sections(20, 10, 3, 2, false);
|
||||
let (d_wide, _, _) = allocate_sections(20, 10, 3, 2, true);
|
||||
assert!(d_wide >= d_narrow, "wide should give desc at least as much space");
|
||||
assert!(
|
||||
d_wide >= d_narrow,
|
||||
"wide should give desc at least as much space"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -102,7 +102,15 @@ pub fn render_search(frame: &mut Frame<'_>, state: &SearchState, area: Rect) {
|
||||
if state.results.is_empty() {
|
||||
render_empty_state(frame, state, area.x + 1, y, max_x);
|
||||
} else {
|
||||
render_result_list(frame, state, area.x, y, area.width, list_height, show_project);
|
||||
render_result_list(
|
||||
frame,
|
||||
state,
|
||||
area.x,
|
||||
y,
|
||||
area.width,
|
||||
list_height,
|
||||
show_project,
|
||||
);
|
||||
}
|
||||
|
||||
// -- Bottom hint bar -----------------------------------------------------
|
||||
|
||||
@@ -115,10 +115,7 @@ fn render_running(frame: &mut Frame<'_>, state: &SyncState, area: Rect) {
|
||||
let bar_start_y = area.y + 4;
|
||||
let label_width = 14u16; // "Discussions " is the longest
|
||||
let bar_x = area.x + 2 + label_width;
|
||||
let bar_width = area
|
||||
.width
|
||||
.saturating_sub(4 + label_width + 12)
|
||||
.min(max_bar); // Cap bar width for very wide terminals
|
||||
let bar_width = area.width.saturating_sub(4 + label_width + 12).min(max_bar); // Cap bar width for very wide terminals
|
||||
|
||||
for (i, lane) in SyncLane::ALL.iter().enumerate() {
|
||||
let y = bar_start_y + i as u16;
|
||||
|
||||
@@ -124,7 +124,16 @@ pub fn render_timeline(
|
||||
} else {
|
||||
let bp = classify_width(area.width);
|
||||
let time_col_width = timeline_time_width(bp);
|
||||
render_event_list(frame, state, area.x, y, area.width, list_height, clock, time_col_width);
|
||||
render_event_list(
|
||||
frame,
|
||||
state,
|
||||
area.x,
|
||||
y,
|
||||
area.width,
|
||||
list_height,
|
||||
clock,
|
||||
time_col_width,
|
||||
);
|
||||
}
|
||||
|
||||
// -- Hint bar --
|
||||
|
||||
@@ -226,13 +226,7 @@ fn render_input_bar(
|
||||
.get(cursor_pos..)
|
||||
.and_then(|s| s.chars().next())
|
||||
.unwrap_or(' ');
|
||||
frame.print_text_clipped(
|
||||
cursor_x,
|
||||
y,
|
||||
&cursor_char.to_string(),
|
||||
cursor_cell,
|
||||
max_x,
|
||||
);
|
||||
frame.print_text_clipped(cursor_x, y, &cursor_char.to_string(), cursor_cell, max_x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user