feat: melhorar popup delete com contexto e adicionar logs CRUD

This commit is contained in:
2026-06-22 21:42:56 +01:00
parent 6fd5b82941
commit 5cfad78ef8
4 changed files with 115 additions and 14 deletions
+86 -9
View File
@@ -224,6 +224,10 @@ impl App {
}
let task = &mut self.tasks[self.selected_task];
task.due = Some(due);
crate::log_msg(&format!(
"[task_app] TASK UPDATE: title=\"{}\" id={} due={}",
task.title, task.id, due
));
self.db.update_task(task).ok();
self.db.push_sync(
SyncAction::Update,
@@ -441,7 +445,25 @@ impl App {
}
KeyCode::Char('d') | KeyCode::Char('D') => {
if !self.needs_auth {
self.show_popup = Some(Popup::ConfirmDelete);
let context = match self.focus {
Focus::Tabs => {
if self.selected_list < self.lists.len() {
format!("Delete list: \"{}\"?", self.lists[self.selected_list].title)
} else {
"Delete this list?".to_string()
}
}
_ => {
if !self.tasks.is_empty() && self.selected_task < self.tasks.len() {
let title = &self.tasks[self.selected_task].title;
let preview: String = title.chars().take(40).collect();
format!("Delete task: \"{}\"?", preview)
} else {
"Delete this task?".to_string()
}
}
};
self.show_popup = Some(Popup::ConfirmDelete { context });
}
}
KeyCode::Char('e') | KeyCode::Char('E') => {
@@ -470,10 +492,15 @@ impl App {
self.show_popup = Some(Popup::BulkAction);
} else {
let task = &mut self.tasks[self.selected_task];
let old_status = task.status.clone();
task.status = match task.status {
TaskStatus::Completed => TaskStatus::NeedsAction,
TaskStatus::NeedsAction => TaskStatus::Completed,
};
crate::log_msg(&format!(
"[task_app] TASK UPDATE: title=\"{}\" id={} status={:?}->{:?}",
task.title, task.id, old_status, task.status
));
self.db.update_task(task).ok();
self.db.push_sync(
SyncAction::Update,
@@ -538,11 +565,15 @@ impl App {
self.pending_bulk_move = false;
self.bulk_move_to_new_list(&input);
self.show_popup = None;
} else if !input.is_empty() {
} else if !input.is_empty() {
let list = TaskList {
id: uuid_v4(),
title: input,
};
crate::log_msg(&format!(
"[task_app] LIST CREATE: title=\"{}\" id={}",
list.title, list.id
));
self.db.insert_list(&list).ok();
self.db.push_sync(
SyncAction::CreateList,
@@ -655,6 +686,10 @@ impl App {
if let Some(d) = due {
task.due = Some(d);
}
crate::log_msg(&format!(
"[task_app] TASK UPDATE: title=\"{}\" id={} has_notes={} has_due={}",
task.title, task.id, task.notes.is_some(), task.due.is_some()
));
self.db.update_task(task).ok();
self.db.push_sync(
SyncAction::Update,
@@ -678,6 +713,10 @@ impl App {
created_at: None,
updated_at: None,
};
crate::log_msg(&format!(
"[task_app] TASK CREATE: title=\"{}\" id={} list={}",
task.title, task.id, list_id
));
self.db.insert_task(&task).ok();
self.db.push_sync(
SyncAction::Create,
@@ -783,6 +822,10 @@ impl App {
if !self.tasks.is_empty() {
let task = &mut self.tasks[self.selected_task];
task.due = Some(self.draft_date);
crate::log_msg(&format!(
"[task_app] TASK UPDATE: title=\"{}\" id={} due={}",
task.title, task.id, self.draft_date
));
self.db.update_task(task).ok();
self.db.push_sync(
SyncAction::Update,
@@ -803,7 +846,7 @@ impl App {
}
_ => {}
},
Popup::ConfirmDelete => match key.code {
Popup::ConfirmDelete { context: _ } => match key.code {
KeyCode::Esc => {
self.show_popup = None;
}
@@ -812,13 +855,18 @@ impl App {
Focus::Tabs => {
if self.selected_list < self.lists.len() {
let list_id = self.lists[self.selected_list].id.clone();
let title = self.lists[self.selected_list].title.clone();
self.db.delete_list(&list_id).ok();
self.db.push_sync(
SyncAction::DeleteList,
&list_id,
&list_id,
"",
).ok();
self.db.push_sync(
SyncAction::DeleteList,
&list_id,
&list_id,
"",
).ok();
crate::log_msg(&format!(
"[task_app] LIST DELETE: title=\"{}\" id={}",
title, list_id
));
self.trigger_sync();
self.load_lists();
if self.selected_list >= self.lists.len() {
@@ -832,6 +880,7 @@ impl App {
let task = &self.tasks[self.selected_task];
let task_id = task.id.clone();
let list_id = task.list_id.clone();
let title = task.title.clone();
self.db.delete_task(&task_id).ok();
if !list_id.contains('-') {
self.db.push_sync(
@@ -841,6 +890,10 @@ impl App {
"",
).ok();
}
crate::log_msg(&format!(
"[task_app] TASK DELETE: title=\"{}\" id={} list={}",
title, task_id, list_id
));
self.trigger_sync();
self.load_tasks();
if self.selected_task >= self.tasks.len() {
@@ -923,6 +976,10 @@ impl App {
&serde_json::to_string(task).unwrap_or_default(),
).ok();
}
crate::log_msg(&format!(
"[task_app] BULK COMPLETED: {} tasks",
indices.len()
));
self.clear_selection();
self.trigger_sync();
self.load_tasks();
@@ -943,6 +1000,10 @@ impl App {
&serde_json::to_string(task).unwrap_or_default(),
).ok();
}
crate::log_msg(&format!(
"[task_app] BULK DUE: {} tasks -> today",
indices.len()
));
self.clear_selection();
self.trigger_sync();
self.load_tasks();
@@ -1021,6 +1082,10 @@ impl App {
&serde_json::to_string(task).unwrap_or_default(),
).ok();
}
crate::log_msg(&format!(
"[task_app] BULK UNCOMPLETE: {} tasks",
indices.len()
));
self.clear_selection();
self.trigger_sync();
self.load_tasks();
@@ -1043,6 +1108,10 @@ impl App {
&serde_json::to_string(task).unwrap_or_default(),
).ok();
}
crate::log_msg(&format!(
"[task_app] BULK DUE: {} tasks -> tomorrow",
indices.len()
));
self.clear_selection();
self.trigger_sync();
self.load_tasks();
@@ -1065,6 +1134,10 @@ impl App {
&serde_json::to_string(task).unwrap_or_default(),
).ok();
}
crate::log_msg(&format!(
"[task_app] BULK DUE: {} tasks -> next week",
indices.len()
));
self.clear_selection();
self.trigger_sync();
self.load_tasks();
@@ -1163,6 +1236,10 @@ impl App {
let new_pos = self.tasks[new_index as usize].position;
if self.db.reorder_task(&task_id, new_pos).is_ok() {
crate::log_msg(&format!(
"[task_app] TASK REORDER: id={} list={} new_pos={}",
task_id, list_id, new_pos
));
let payload = serde_json::json!({
"task_id": task_id,
"new_position": new_pos
+24
View File
@@ -238,11 +238,21 @@ async fn run_initial_sync(
Ok(lists) => {
total_lists = lists.len();
for list in &lists {
log_msg(&format!(
"[task_app] LIST SYNC: title=\"{}\" id={}",
list.title, list.id
));
db.insert_list(list).ok();
}
for list in &lists {
if let Ok(tasks) = api.fetch_tasks(&list.id).await {
total_tasks += tasks.len();
log_msg(&format!(
"[task_app] TASK SYNC: {} tasks in list=\"{}\" id={}",
tasks.len(),
list.title,
list.id
));
db.replace_all_tasks(&list.id, &tasks).ok();
}
}
@@ -482,6 +492,10 @@ async fn pull_sync(
Ok(lists) => {
total_lists = lists.len();
for list in &lists {
log_msg(&format!(
"[task_app] LIST SYNC: title=\"{}\" id={}",
list.title, list.id
));
db.insert_list(list).ok();
}
for list in &lists {
@@ -493,10 +507,20 @@ async fn pull_sync(
if let Ok(tasks) = result {
total_tasks += tasks.len();
if use_incremental {
log_msg(&format!(
"[task_app] TASK SYNC (incremental): {} tasks in list=\"{}\"",
tasks.len(),
list.title
));
for task in &tasks {
db.insert_task(task).ok();
}
} else {
log_msg(&format!(
"[task_app] TASK SYNC (full): {} tasks in list=\"{}\"",
tasks.len(),
list.title
));
db.replace_all_tasks(&list.id, &tasks).ok();
}
}
+3 -3
View File
@@ -477,8 +477,8 @@ pub fn render_date_picker(
frame.render_widget(paragraph, popup_area);
}
pub fn render_confirm_popup(frame: &mut Frame, area: Rect) {
let popup_area = centered_rect(50, 5, area);
pub fn render_confirm_popup(frame: &mut Frame, area: Rect, context: &str) {
let popup_area = centered_rect(60, 6, area);
frame.render_widget(Clear, popup_area);
let block = Block::default()
.borders(Borders::ALL)
@@ -490,7 +490,7 @@ pub fn render_confirm_popup(frame: &mut Frame, area: Rect) {
let text = Text::from(vec![
Line::from(""),
Line::from(Span::styled(
" Delete this item? ",
format!(" {} ", context),
Style::default().fg(Color::Red).add_modifier(Modifier::BOLD),
)),
Line::from(""),
+2 -2
View File
@@ -22,7 +22,7 @@ pub enum Popup {
Input,
EditTask { field: usize },
DatePicker,
ConfirmDelete,
ConfirmDelete { context: String },
BulkAction,
PickList,
DeviceAuth { url: String, code: String },
@@ -129,7 +129,7 @@ pub fn draw(frame: &mut Frame, view: AppView) {
view.notes_scroll, *field,
),
Popup::DatePicker => render_date_picker(frame, area, view.draft_date),
Popup::ConfirmDelete => render_confirm_popup(frame, area),
Popup::ConfirmDelete { context } => render_confirm_popup(frame, area, context),
Popup::BulkAction => render_bulk_action_popup(frame, area, view.selected_tasks.len(), view.bulk_action_selected),
Popup::PickList => render_pick_list_popup(frame, area, view.popup_list_indices, view.popup_list_selected),
Popup::DeviceAuth { url, code } => render_device_auth_popup(frame, area, url, code, view.auth_error),