Fix item deletion issue on view panels
This commit is contained in:
parent
857362b558
commit
f10c1ddfff
1 changed files with 40 additions and 18 deletions
58
src/app.rs
58
src/app.rs
|
|
@ -58,6 +58,7 @@ pub struct App {
|
||||||
pub log_view_selection_level: LogViewSelection,
|
pub log_view_selection_level: LogViewSelection,
|
||||||
pub log_view_frames: Vec<WatsonFrame>,
|
pub log_view_frames: Vec<WatsonFrame>,
|
||||||
pub log_view_content: Vec<String>,
|
pub log_view_content: Vec<String>,
|
||||||
|
pub log_view_frame_indices: Vec<usize>, // Maps display order to frame index
|
||||||
pub log_view_scroll: usize,
|
pub log_view_scroll: usize,
|
||||||
pub log_view_selected: usize,
|
pub log_view_selected: usize,
|
||||||
pub help_scroll: usize,
|
pub help_scroll: usize,
|
||||||
|
|
@ -96,6 +97,7 @@ impl App {
|
||||||
log_view_selection_level: LogViewSelection::Entry,
|
log_view_selection_level: LogViewSelection::Entry,
|
||||||
log_view_frames: Vec::new(),
|
log_view_frames: Vec::new(),
|
||||||
log_view_content: Vec::new(),
|
log_view_content: Vec::new(),
|
||||||
|
log_view_frame_indices: Vec::new(),
|
||||||
log_view_scroll: 0,
|
log_view_scroll: 0,
|
||||||
log_view_selected: 0,
|
log_view_selected: 0,
|
||||||
help_scroll: 0,
|
help_scroll: 0,
|
||||||
|
|
@ -414,7 +416,7 @@ impl App {
|
||||||
match self.log_view_selection_level {
|
match self.log_view_selection_level {
|
||||||
LogViewSelection::Entry => {
|
LogViewSelection::Entry => {
|
||||||
// Move to next entry
|
// Move to next entry
|
||||||
if self.log_view_selected < self.log_view_frames.len().saturating_sub(1) {
|
if self.log_view_selected < self.log_view_frame_indices.len().saturating_sub(1) {
|
||||||
self.log_view_selected += 1;
|
self.log_view_selected += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -501,7 +503,7 @@ impl App {
|
||||||
}
|
}
|
||||||
KeyCode::PageDown => {
|
KeyCode::PageDown => {
|
||||||
self.log_view_selected = (self.log_view_selected + 10)
|
self.log_view_selected = (self.log_view_selected + 10)
|
||||||
.min(self.log_view_frames.len().saturating_sub(1));
|
.min(self.log_view_frame_indices.len().saturating_sub(1));
|
||||||
}
|
}
|
||||||
KeyCode::PageUp => {
|
KeyCode::PageUp => {
|
||||||
self.log_view_selected = self.log_view_selected.saturating_sub(10);
|
self.log_view_selected = self.log_view_selected.saturating_sub(10);
|
||||||
|
|
@ -529,23 +531,24 @@ impl App {
|
||||||
use chrono::{DateTime, Local, Timelike};
|
use chrono::{DateTime, Local, Timelike};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
// Group frames by date
|
// Group frames by date, tracking their original indices
|
||||||
let mut by_date: BTreeMap<String, Vec<&WatsonFrame>> = BTreeMap::new();
|
let mut by_date: BTreeMap<String, Vec<(usize, &WatsonFrame)>> = BTreeMap::new();
|
||||||
|
|
||||||
for frame in &self.log_view_frames {
|
for (idx, frame) in self.log_view_frames.iter().enumerate() {
|
||||||
if let Ok(start_dt) = DateTime::parse_from_rfc3339(&frame.start) {
|
if let Ok(start_dt) = DateTime::parse_from_rfc3339(&frame.start) {
|
||||||
let local_dt: DateTime<Local> = start_dt.into();
|
let local_dt: DateTime<Local> = start_dt.into();
|
||||||
let date_key = local_dt.format("%A %d %B %Y").to_string();
|
let date_key = local_dt.format("%A %d %B %Y").to_string();
|
||||||
by_date.entry(date_key).or_insert_with(Vec::new).push(frame);
|
by_date.entry(date_key).or_insert_with(Vec::new).push((idx, frame));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut lines = Vec::new();
|
let mut lines = Vec::new();
|
||||||
|
let mut frame_indices = Vec::new();
|
||||||
|
|
||||||
for (date, frames) in by_date.iter().rev() {
|
for (date, frames) in by_date.iter().rev() {
|
||||||
lines.push(date.clone());
|
lines.push(date.clone());
|
||||||
|
|
||||||
for frame in frames {
|
for (idx, frame) in frames {
|
||||||
if let (Ok(start_dt), Ok(stop_dt)) = (
|
if let (Ok(start_dt), Ok(stop_dt)) = (
|
||||||
DateTime::parse_from_rfc3339(&frame.start),
|
DateTime::parse_from_rfc3339(&frame.start),
|
||||||
DateTime::parse_from_rfc3339(&frame.stop),
|
DateTime::parse_from_rfc3339(&frame.stop),
|
||||||
|
|
@ -566,22 +569,24 @@ impl App {
|
||||||
"\t{} to {} {}{}",
|
"\t{} to {} {}{}",
|
||||||
start_time, stop_time, frame.project, tags_str
|
start_time, stop_time, frame.project, tags_str
|
||||||
));
|
));
|
||||||
|
frame_indices.push(*idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lines.push(String::new()); // Empty line between dates
|
lines.push(String::new()); // Empty line between dates
|
||||||
}
|
}
|
||||||
|
|
||||||
self.log_view_content = lines;
|
self.log_view_content = lines;
|
||||||
|
self.log_view_frame_indices = frame_indices;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_by_project(&mut self) {
|
fn format_by_project(&mut self) {
|
||||||
use chrono::{DateTime, Local, Timelike};
|
use chrono::{DateTime, Local, Timelike};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
// Group frames by date, then by project within each date
|
// Group frames by date, then by project within each date, tracking indices
|
||||||
let mut by_date: BTreeMap<String, BTreeMap<String, Vec<&WatsonFrame>>> = BTreeMap::new();
|
let mut by_date: BTreeMap<String, BTreeMap<String, Vec<(usize, &WatsonFrame)>>> = BTreeMap::new();
|
||||||
|
|
||||||
for frame in &self.log_view_frames {
|
for (idx, frame) in self.log_view_frames.iter().enumerate() {
|
||||||
if let Ok(start_dt) = DateTime::parse_from_rfc3339(&frame.start) {
|
if let Ok(start_dt) = DateTime::parse_from_rfc3339(&frame.start) {
|
||||||
let local_dt: DateTime<Local> = start_dt.into();
|
let local_dt: DateTime<Local> = start_dt.into();
|
||||||
let date_key = local_dt.format("%A %d %B %Y").to_string();
|
let date_key = local_dt.format("%A %d %B %Y").to_string();
|
||||||
|
|
@ -590,11 +595,12 @@ impl App {
|
||||||
.or_insert_with(BTreeMap::new)
|
.or_insert_with(BTreeMap::new)
|
||||||
.entry(frame.project.clone())
|
.entry(frame.project.clone())
|
||||||
.or_insert_with(Vec::new)
|
.or_insert_with(Vec::new)
|
||||||
.push(frame);
|
.push((idx, frame));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut lines = Vec::new();
|
let mut lines = Vec::new();
|
||||||
|
let mut frame_indices = Vec::new();
|
||||||
|
|
||||||
for (date, projects) in by_date.iter().rev() {
|
for (date, projects) in by_date.iter().rev() {
|
||||||
lines.push(date.clone());
|
lines.push(date.clone());
|
||||||
|
|
@ -602,7 +608,7 @@ impl App {
|
||||||
for (project, frames) in projects.iter() {
|
for (project, frames) in projects.iter() {
|
||||||
lines.push(format!(" {}", project)); // Project header with indent
|
lines.push(format!(" {}", project)); // Project header with indent
|
||||||
|
|
||||||
for frame in frames {
|
for (idx, frame) in frames {
|
||||||
if let (Ok(start_dt), Ok(stop_dt)) = (
|
if let (Ok(start_dt), Ok(stop_dt)) = (
|
||||||
DateTime::parse_from_rfc3339(&frame.start),
|
DateTime::parse_from_rfc3339(&frame.start),
|
||||||
DateTime::parse_from_rfc3339(&frame.stop),
|
DateTime::parse_from_rfc3339(&frame.stop),
|
||||||
|
|
@ -623,6 +629,7 @@ impl App {
|
||||||
"\t\t{} to {}{}",
|
"\t\t{} to {}{}",
|
||||||
start_time, stop_time, tags_str
|
start_time, stop_time, tags_str
|
||||||
));
|
));
|
||||||
|
frame_indices.push(*idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -630,14 +637,22 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.log_view_content = lines;
|
self.log_view_content = lines;
|
||||||
|
self.log_view_frame_indices = frame_indices;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn edit_selected_frame(&mut self) -> anyhow::Result<()> {
|
fn edit_selected_frame(&mut self) -> anyhow::Result<()> {
|
||||||
if self.log_view_frames.is_empty() || self.log_view_selected >= self.log_view_frames.len() {
|
// Check if selection is valid
|
||||||
|
if self.log_view_selected >= self.log_view_frame_indices.len() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the actual frame index from the display index
|
||||||
|
let frame_idx = self.log_view_frame_indices[self.log_view_selected];
|
||||||
|
if frame_idx >= self.log_view_frames.len() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let frame_id = &self.log_view_frames[self.log_view_selected].id;
|
let frame_id = &self.log_view_frames[frame_idx].id;
|
||||||
|
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
execute,
|
execute,
|
||||||
|
|
@ -668,11 +683,18 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_selected_frame(&mut self) -> anyhow::Result<()> {
|
fn delete_selected_frame(&mut self) -> anyhow::Result<()> {
|
||||||
if self.log_view_frames.is_empty() || self.log_view_selected >= self.log_view_frames.len() {
|
// Check if selection is valid
|
||||||
|
if self.log_view_selected >= self.log_view_frame_indices.len() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the actual frame index from the display index
|
||||||
|
let frame_idx = self.log_view_frame_indices[self.log_view_selected];
|
||||||
|
if frame_idx >= self.log_view_frames.len() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let frame_id = self.log_view_frames[self.log_view_selected].id.clone();
|
let frame_id = self.log_view_frames[frame_idx].id.clone();
|
||||||
|
|
||||||
// Run watson remove with --force flag (no confirmation)
|
// Run watson remove with --force flag (no confirmation)
|
||||||
let output = Command::new("watson")
|
let output = Command::new("watson")
|
||||||
|
|
@ -686,8 +708,8 @@ impl App {
|
||||||
self.load_log_content()?;
|
self.load_log_content()?;
|
||||||
|
|
||||||
// Adjust selection if we deleted the last item
|
// Adjust selection if we deleted the last item
|
||||||
if self.log_view_selected >= self.log_view_frames.len() && !self.log_view_frames.is_empty() {
|
if self.log_view_selected >= self.log_view_frame_indices.len() && !self.log_view_frame_indices.is_empty() {
|
||||||
self.log_view_selected = self.log_view_frames.len() - 1;
|
self.log_view_selected = self.log_view_frame_indices.len() - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue