From eb11b75af6f35f95a2dae4bba8df71600f513380 Mon Sep 17 00:00:00 2001 From: alemidev Date: Fri, 24 Jun 2022 15:04:34 +0200 Subject: [PATCH] feat: added ways to delete metrics and sources Deleting a metric or a source will prompt you for confirmation. No way I'm letting you delete data from archive without asking for confirmation --- src/app/data/store.rs | 19 +++++-- src/app/gui/source.rs | 20 +------ src/app/mod.rs | 126 +++++++++++++++++++++++++++++++++--------- 3 files changed, 117 insertions(+), 48 deletions(-) diff --git a/src/app/data/store.rs b/src/app/data/store.rs index 0a4d6aa..31c7dbe 100644 --- a/src/app/data/store.rs +++ b/src/app/data/store.rs @@ -117,6 +117,13 @@ impl SQLiteDataStore { ) } + pub fn delete_values(&self, metric_id: i32) -> rusqlite::Result { + self.conn.execute( + "DELETE FROM points WHERE metric_id = ?", + params![metric_id] + ) + } + pub fn load_sources(&self) -> rusqlite::Result> { let mut sources: Vec = Vec::new(); let mut statement = self.conn.prepare("SELECT * FROM sources ORDER BY position")?; @@ -190,9 +197,9 @@ impl SQLiteDataStore { ) } - // pub fn delete_source(&self, id:i32) -> rusqlite::Result { - // self.conn.execute("DELETE FROM sources WHERE id = ?", params![id]) - // } + pub fn delete_source(&self, id:i32) -> rusqlite::Result { + self.conn.execute("DELETE FROM sources WHERE id = ?", params![id]) + } pub fn load_metrics(&self) -> rusqlite::Result> { let mut metrics: Vec = Vec::new(); @@ -277,9 +284,9 @@ impl SQLiteDataStore { ) } - // pub fn delete_metric(&self, id:i32) -> rusqlite::Result { - // self.conn.execute("DELETE FROM metrics WHERE id = ?", params![id]) - // } + pub fn delete_metric(&self, id:i32) -> rusqlite::Result { + self.conn.execute("DELETE FROM metrics WHERE id = ?", params![id]) + } pub fn load_panels(&self) -> rusqlite::Result> { let mut panels: Vec = Vec::new(); diff --git a/src/app/gui/source.rs b/src/app/gui/source.rs index 29c78e9..9112204 100644 --- a/src/app/gui/source.rs +++ b/src/app/gui/source.rs @@ -1,23 +1,16 @@ use eframe::{egui::{Ui, TextEdit, DragValue, Checkbox}}; -use crate::app::data::source::{Panel, Source, Metric}; +use crate::app::data::source::Source; -use super::metric::{metric_edit_ui, metric_display_ui}; - -pub fn source_display_ui(ui: &mut Ui, source: &mut Source, metrics: &Vec, _width: f32) { +pub fn source_display_ui(ui: &mut Ui, source: &mut Source, _width: f32) { ui.horizontal(|ui| { ui.add_enabled(false, Checkbox::new(&mut source.enabled, "")); ui.add_enabled(false, DragValue::new(&mut source.interval).clamp_range(1..=120)); ui.heading(&source.name).on_hover_text(&source.url); }); - for metric in metrics.iter() { - if metric.source_id == source.id { - metric_display_ui(ui, metric, ui.available_width()); - } - } } -pub fn source_edit_ui(ui: &mut Ui, source: &mut Source, metrics: Option<&mut Vec>, panels: &Vec, width: f32) { +pub fn source_edit_ui(ui: &mut Ui, source: &mut Source, width: f32) { ui.horizontal(|ui| { let text_width = width - 100.0; ui.checkbox(&mut source.enabled, ""); @@ -31,11 +24,4 @@ pub fn source_edit_ui(ui: &mut Ui, source: &mut Source, metrics: Option<&mut Vec .hint_text("url") .show(ui); }); - if let Some(metrics) = metrics { - for metric in metrics.iter_mut() { - if metric.source_id == source.id { - metric_edit_ui(ui, metric, Some(panels), width - 10.0); - } - } - } } diff --git a/src/app/mod.rs b/src/app/mod.rs index f22e13c..e42c9e5 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -3,17 +3,19 @@ pub mod gui; pub mod util; pub mod worker; +use eframe::egui::Window; use eframe::egui::{ collapsing_header::CollapsingState, global_dark_light_mode_switch, CentralPanel, Context, Layout, ScrollArea, SidePanel, TopBottomPanel, }; -use eframe::emath::Align; +use eframe::emath::{Align, Pos2}; +use std::ops::Index; use std::sync::Arc; use tracing::error; use self::data::source::{Metric, Panel, Source}; use self::data::ApplicationState; -use self::gui::metric::metric_edit_ui; +use self::gui::metric::{metric_edit_ui, metric_display_ui}; use self::gui::panel::{panel_body_ui, panel_edit_inline_ui, panel_title_ui}; use self::gui::source::{source_display_ui, source_edit_ui}; use self::util::human_size; @@ -24,6 +26,8 @@ pub struct App { input_metric: Metric, input_source: Source, input_panel: Panel, + deleting_metric: Option, + deleting_source: Option, edit: bool, sources: bool, padding: bool, @@ -36,6 +40,8 @@ impl App { input_metric: Metric::default(), input_panel: Panel::default(), input_source: Source::default(), + deleting_metric: None, + deleting_source: None, edit: false, sources: true, padding: false, @@ -125,6 +131,60 @@ impl eframe::App for App { }); }); }); + if let Some(index) = self.deleting_metric { + Window::new(format!("Delete Metric #{}", index)) + .show(ctx, |ui| { + ui.heading("Are you sure you want to delete this metric?"); + ui.label("This will remove all its metrics and delete all points from archive. This action CANNOT BE UNDONE!"); + ui.with_layout(Layout::top_down(Align::RIGHT), |ui| { + ui.horizontal(|ui| { + if ui.button("yes").clicked() { + let store = self.data.storage.lock().expect("Storage Mutex poisoned"); + let mut metrics = self.data.metrics.write().expect("Metrics RwLock poisoned"); + store.delete_metric(metrics[index].id).expect("Failed deleting metric"); + store.delete_values(metrics[index].id).expect("Failed deleting values"); + metrics.remove(index); + self.deleting_metric = None; + } + if ui.button(" no ").clicked() { + self.deleting_metric = None; + } + }); + }); + }); + } + if let Some(index) = self.deleting_source { + Window::new(format!("Delete Source #{}", index)).show(ctx, |ui| { + ui.heading("Are you sure you want to delete this source?"); + ui.label("This will remove all its metrics and delete all points from archive. This action CANNOT BE UNDONE!"); + ui.with_layout(Layout::top_down(Align::RIGHT), |ui| { + ui.horizontal(|ui| { + if ui.button("YEAH").clicked() { + let store = self.data.storage.lock().expect("Storage Mutex poisoned"); + let mut sources = self.data.sources.write().expect("sources RwLock poisoned"); + let mut metrics = self.data.metrics.write().expect("Metrics RwLock poisoned"); + let mut to_remove = Vec::new(); + for j in 0..metrics.len() { + if metrics[j].source_id == self.input_source.id { + store.delete_values(metrics[j].id).expect("Failed deleting values"); + store.delete_metric(metrics[j].id).expect("Failed deleting Metric"); + to_remove.push(j); + } + } + for index in to_remove { + metrics.remove(index); + } + store.delete_source(sources[index].id).expect("Failed deleting source"); + sources.remove(index); + self.deleting_source = None; + } + if ui.button(" NO WAY ").clicked() { + self.deleting_source = None; + } + }); + }); + }); + } if self.sources { let mut to_swap: Option = None; // let mut to_delete: Option = None; @@ -142,19 +202,19 @@ impl eframe::App for App { let sources_count = sources.len(); ui.heading("Sources"); ui.separator(); - for (index, source) in sources.iter_mut().enumerate() { + for (i, source) in sources.iter_mut().enumerate() { ui.horizontal(|ui| { if self.edit { ui.vertical(|ui| { ui.add_space(10.0); if ui.small_button("+").clicked() { - if index > 0 { - to_swap = Some(index); // TODO kinda jank but is there a better way? + if i > 0 { + to_swap = Some(i); // TODO kinda jank but is there a better way? } } if ui.small_button("−").clicked() { - if index < sources_count - 1 { - to_swap = Some(index + 1); // TODO kinda jank but is there a better way? + if i < sources_count - 1 { + to_swap = Some(i + 1); // TODO kinda jank but is there a better way? } } }); @@ -163,26 +223,36 @@ impl eframe::App for App { let remaining_width = ui.available_width(); if self.edit { ui.group(|ui| { - source_edit_ui( - ui, - source, - Some(&mut *self.data.metrics.write().expect("Metrics RwLock poisoned")), - &panels, - remaining_width, - ); + ui.horizontal(|ui| { + source_edit_ui( + ui, + source, + remaining_width - 34.0, + ); + if ui.small_button("×").clicked() { + self.deleting_metric = None; + self.deleting_source = Some(i); + } + }); + for (j, metric) in self.data.metrics.write().expect("Metrics RwLock poisoned").iter_mut().enumerate() { + if metric.source_id == source.id { + ui.horizontal(|ui| { + metric_edit_ui(ui, metric, Some(&panels), remaining_width - 31.0); + if ui.small_button("×").clicked() { + self.deleting_source = None; + self.deleting_metric = Some(j); + } + }); + } + } ui.horizontal(|ui| { metric_edit_ui( ui, &mut self.input_metric, None, - remaining_width - 10.0, + remaining_width - 30.0, ); - ui.add_space(5.0); - if ui.button(" × ").clicked() { - self.input_metric = Metric::default(); - } - ui.separator(); - if ui.button(" + ").clicked() { + if ui.small_button(" + ").clicked() { // TODO find a better if let Err(e) = self .data .add_metric(&self.input_metric, source) @@ -190,6 +260,10 @@ impl eframe::App for App { error!(target: "ui", "Error adding metric : {:?}", e); } } + ui.add_space(1.0); // DAMN! + if ui.small_button("×").clicked() { + self.input_metric = Metric::default(); + } }) }); } else { @@ -198,9 +272,13 @@ impl eframe::App for App { source_display_ui( ui, source, - &metrics, remaining_width, ); + for metric in metrics.iter() { + if metric.source_id == source.id { + metric_display_ui(ui, metric, ui.available_width()); + } + } ui.separator(); } }); @@ -227,9 +305,7 @@ impl eframe::App for App { source_edit_ui( ui, &mut self.input_source, - None, - &panels, - panel_width, + panel_width - 10.0, ); ui.add_space(5.0); if self.padding {