mirror of
https://git.alemi.dev/dashboard.git
synced 2024-11-14 11:59:18 +01:00
feat!: made sources reorderable and panels deletable
Added in sources a position field which works just like the one in panels. Added in sources an "enabled" flag which now governs wether or not data is fetched. Added a button to delete panels. Tweaked UI a little
This commit is contained in:
parent
3408a74731
commit
c5a9cf12c6
8 changed files with 141 additions and 90 deletions
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "dashboard"
|
name = "dashboard"
|
||||||
version = "0.1.3"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
|
|
@ -99,11 +99,13 @@ impl ApplicationState {
|
||||||
.new_source(
|
.new_source(
|
||||||
source.panel_id,
|
source.panel_id,
|
||||||
source.name.as_str(),
|
source.name.as_str(),
|
||||||
|
source.enabled,
|
||||||
source.url.as_str(),
|
source.url.as_str(),
|
||||||
|
source.interval,
|
||||||
source.query_x.as_str(),
|
source.query_x.as_str(),
|
||||||
source.query_y.as_str(),
|
source.query_y.as_str(),
|
||||||
source.color,
|
source.color,
|
||||||
source.visible,
|
self.sources.read().expect("Sources RwLock poisoned").len() as i32,
|
||||||
)?;
|
)?;
|
||||||
self.sources
|
self.sources
|
||||||
.write()
|
.write()
|
||||||
|
|
|
@ -33,10 +33,10 @@ impl Default for Panel {
|
||||||
pub struct Source {
|
pub struct Source {
|
||||||
pub(crate) id: i32,
|
pub(crate) id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
pub enabled: bool,
|
||||||
pub url: String,
|
pub url: String,
|
||||||
pub interval: i32,
|
pub interval: i32,
|
||||||
pub color: Color32,
|
pub color: Color32,
|
||||||
pub visible: bool,
|
|
||||||
pub(crate) last_fetch: RwLock<DateTime<Utc>>,
|
pub(crate) last_fetch: RwLock<DateTime<Utc>>,
|
||||||
pub query_x: String,
|
pub query_x: String,
|
||||||
// pub(crate) compiled_query_x: Arc<Mutex<jq_rs::JqProgram>>,
|
// pub(crate) compiled_query_x: Arc<Mutex<jq_rs::JqProgram>>,
|
||||||
|
@ -51,10 +51,10 @@ impl Default for Source {
|
||||||
Source {
|
Source {
|
||||||
id: -1,
|
id: -1,
|
||||||
name: "".to_string(),
|
name: "".to_string(),
|
||||||
|
enabled: false,
|
||||||
url: "".to_string(),
|
url: "".to_string(),
|
||||||
interval: 60,
|
interval: 60,
|
||||||
color: Color32::TRANSPARENT,
|
color: Color32::TRANSPARENT,
|
||||||
visible: false,
|
|
||||||
last_fetch: RwLock::new(Utc::now()),
|
last_fetch: RwLock::new(Utc::now()),
|
||||||
query_x: "".to_string(),
|
query_x: "".to_string(),
|
||||||
query_y: "".to_string(),
|
query_y: "".to_string(),
|
||||||
|
|
|
@ -39,13 +39,14 @@ impl SQLiteDataStore {
|
||||||
"CREATE TABLE IF NOT EXISTS sources (
|
"CREATE TABLE IF NOT EXISTS sources (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
|
enabled BOOL NOT NULL,
|
||||||
url TEXT NOT NULL,
|
url TEXT NOT NULL,
|
||||||
interval INT NOT NULL,
|
interval INT NOT NULL,
|
||||||
query_x TEXT NOT NULL,
|
query_x TEXT NOT NULL,
|
||||||
query_y TEXT NOT NULL,
|
query_y TEXT NOT NULL,
|
||||||
panel_id INT NOT NULL,
|
panel_id INT NOT NULL,
|
||||||
color INT NULL,
|
color INT NULL,
|
||||||
visible BOOL NOT NULL
|
position INT NOT NULL
|
||||||
);",
|
);",
|
||||||
[],
|
[],
|
||||||
)?;
|
)?;
|
||||||
|
@ -93,19 +94,19 @@ impl SQLiteDataStore {
|
||||||
|
|
||||||
pub fn load_sources(&self) -> rusqlite::Result<Vec<Source>> {
|
pub fn load_sources(&self) -> rusqlite::Result<Vec<Source>> {
|
||||||
let mut sources: Vec<Source> = Vec::new();
|
let mut sources: Vec<Source> = Vec::new();
|
||||||
let mut statement = self.conn.prepare("SELECT * FROM sources")?;
|
let mut statement = self.conn.prepare("SELECT * FROM sources ORDER BY position")?;
|
||||||
let sources_iter = statement.query_map([], |row| {
|
let sources_iter = statement.query_map([], |row| {
|
||||||
Ok(Source {
|
Ok(Source {
|
||||||
id: row.get(0)?,
|
id: row.get(0)?,
|
||||||
name: row.get(1)?,
|
name: row.get(1)?,
|
||||||
url: row.get(2)?,
|
enabled: row.get(2)?,
|
||||||
interval: row.get(3)?,
|
url: row.get(3)?,
|
||||||
|
interval: row.get(4)?,
|
||||||
last_fetch: RwLock::new(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0)),
|
last_fetch: RwLock::new(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0)),
|
||||||
query_x: row.get(4)?,
|
query_x: row.get(5)?,
|
||||||
query_y: row.get(5)?,
|
query_y: row.get(6)?,
|
||||||
panel_id: row.get(6)?,
|
panel_id: row.get(7)?,
|
||||||
color: unpack_color(row.get(7).unwrap_or(0)),
|
color: unpack_color(row.get(8).unwrap_or(0)),
|
||||||
visible: row.get(8)?,
|
|
||||||
data: RwLock::new(Vec::new()),
|
data: RwLock::new(Vec::new()),
|
||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
|
@ -125,11 +126,13 @@ impl SQLiteDataStore {
|
||||||
&self,
|
&self,
|
||||||
panel_id: i32,
|
panel_id: i32,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
enabled: bool,
|
||||||
url: &str,
|
url: &str,
|
||||||
|
interval: i32,
|
||||||
query_x: &str,
|
query_x: &str,
|
||||||
query_y: &str,
|
query_y: &str,
|
||||||
color: Color32,
|
color: Color32,
|
||||||
visible: bool,
|
position: i32,
|
||||||
) -> rusqlite::Result<Source> {
|
) -> rusqlite::Result<Source> {
|
||||||
let color_u32: Option<u32> = if color == Color32::TRANSPARENT {
|
let color_u32: Option<u32> = if color == Color32::TRANSPARENT {
|
||||||
None
|
None
|
||||||
|
@ -137,8 +140,8 @@ impl SQLiteDataStore {
|
||||||
Some(repack_color(color))
|
Some(repack_color(color))
|
||||||
};
|
};
|
||||||
self.conn.execute(
|
self.conn.execute(
|
||||||
"INSERT INTO sources(name, url, interval, query_x, query_y, panel_id, color, visible) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
"INSERT INTO sources(name, enabled, url, interval, query_x, query_y, panel_id, color, position) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
params![name, url, 60i32, query_x, query_y, panel_id, color_u32, visible],
|
params![name, enabled, url, interval, query_x, query_y, panel_id, color_u32, position],
|
||||||
)?;
|
)?;
|
||||||
let mut statement = self
|
let mut statement = self
|
||||||
.conn
|
.conn
|
||||||
|
@ -147,14 +150,14 @@ impl SQLiteDataStore {
|
||||||
Ok(Source {
|
Ok(Source {
|
||||||
id: row.get(0)?,
|
id: row.get(0)?,
|
||||||
name: row.get(1)?,
|
name: row.get(1)?,
|
||||||
url: row.get(2)?,
|
enabled: row.get(2)?,
|
||||||
interval: row.get(3)?,
|
url: row.get(3)?,
|
||||||
|
interval: row.get(4)?,
|
||||||
last_fetch: RwLock::new(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0)),
|
last_fetch: RwLock::new(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0)),
|
||||||
query_x: row.get(4)?,
|
query_x: row.get(5)?,
|
||||||
query_y: row.get(5)?,
|
query_y: row.get(6)?,
|
||||||
panel_id: row.get(6)?,
|
panel_id: row.get(7)?,
|
||||||
color: unpack_color(row.get(7).unwrap_or(0)),
|
color: unpack_color(row.get(8).unwrap_or(0)),
|
||||||
visible: row.get(8)?,
|
|
||||||
data: RwLock::new(Vec::new()),
|
data: RwLock::new(Vec::new()),
|
||||||
})
|
})
|
||||||
})? {
|
})? {
|
||||||
|
@ -171,12 +174,13 @@ impl SQLiteDataStore {
|
||||||
source_id: i32,
|
source_id: i32,
|
||||||
panel_id: i32,
|
panel_id: i32,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
enabled: bool,
|
||||||
url: &str,
|
url: &str,
|
||||||
interval: i32,
|
interval: i32,
|
||||||
query_x: &str,
|
query_x: &str,
|
||||||
query_y: &str,
|
query_y: &str,
|
||||||
color: Color32,
|
color: Color32,
|
||||||
visible: bool,
|
position: i32,
|
||||||
) -> rusqlite::Result<usize> {
|
) -> rusqlite::Result<usize> {
|
||||||
let color_u32: Option<u32> = if color == Color32::TRANSPARENT {
|
let color_u32: Option<u32> = if color == Color32::TRANSPARENT {
|
||||||
None
|
None
|
||||||
|
@ -184,8 +188,8 @@ impl SQLiteDataStore {
|
||||||
Some(repack_color(color))
|
Some(repack_color(color))
|
||||||
};
|
};
|
||||||
self.conn.execute(
|
self.conn.execute(
|
||||||
"UPDATE sources SET name = ?, url = ?, interval = ?, query_x = ?, query_y = ?, panel_id = ?, color = ?, visible = ? WHERE id = ?",
|
"UPDATE sources SET name = ?, enabled = ?, url = ?, interval = ?, query_x = ?, query_y = ?, panel_id = ?, color = ?, position = ? WHERE id = ?",
|
||||||
params![name, url, interval, query_x, query_y, panel_id, color_u32, visible, source_id],
|
params![name, enabled, url, interval, query_x, query_y, panel_id, color_u32, position, source_id],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +275,7 @@ impl SQLiteDataStore {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn delete_panel(&self, id:i32) -> rusqlite::Result<usize> {
|
pub fn delete_panel(&self, id:i32) -> rusqlite::Result<usize> {
|
||||||
// self.conn.execute("DELETE FROM panels WHERE id = ?", params![id])
|
self.conn.execute("DELETE FROM panels WHERE id = ?", params![id])
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,15 +47,16 @@ pub fn panel_body_ui(ui: &mut Ui, panel: &mut Panel, sources: &Vec<Source>) {
|
||||||
.allow_scroll(false)
|
.allow_scroll(false)
|
||||||
.legend(Legend::default().position(Corner::LeftTop));
|
.legend(Legend::default().position(Corner::LeftTop));
|
||||||
|
|
||||||
|
if panel.limit {
|
||||||
|
p = p.set_margin_fraction(Vec2 { x: 0.0, y: 0.1 });
|
||||||
|
}
|
||||||
|
|
||||||
if panel.view_scroll {
|
if panel.view_scroll {
|
||||||
p = p.include_x(Utc::now().timestamp() as f64);
|
p = p.include_x(Utc::now().timestamp() as f64);
|
||||||
if panel.limit {
|
if panel.limit {
|
||||||
p = p
|
p = p
|
||||||
.set_margin_fraction(Vec2 { x: 0.0, y: 0.1 })
|
.include_x((Utc::now().timestamp() + (panel.view_size as i64 * 3)) as f64)
|
||||||
.include_x((Utc::now().timestamp() + (panel.view_size as i64 * 3)) as f64);
|
.include_x((Utc::now().timestamp() - (panel.view_size as i64 * 60)) as f64); // ??? TODO
|
||||||
}
|
|
||||||
if panel.limit {
|
|
||||||
p = p.include_x((Utc::now().timestamp() - (panel.view_size as i64 * 60)) as f64);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +107,7 @@ pub fn panel_body_ui(ui: &mut Ui, panel: &mut Panel, sources: &Vec<Source>) {
|
||||||
|
|
||||||
p.show(ui, |plot_ui| {
|
p.show(ui, |plot_ui| {
|
||||||
for source in &*sources {
|
for source in &*sources {
|
||||||
if source.visible && source.panel_id == panel.id {
|
if source.panel_id == panel.id {
|
||||||
let line = if panel.limit {
|
let line = if panel.limit {
|
||||||
Line::new(source.values_filter(
|
Line::new(source.values_filter(
|
||||||
(Utc::now().timestamp() - (panel.view_size as i64 * 60)) as f64,
|
(Utc::now().timestamp() - (panel.view_size as i64 * 60)) as f64,
|
||||||
|
|
|
@ -28,51 +28,54 @@ pub fn source_edit_inline_ui(ui: &mut Ui, source: &mut Source, panels: &Vec<Pane
|
||||||
ui.selectable_value(&mut source.panel_id, p.id, p.name.as_str());
|
ui.selectable_value(&mut source.panel_id, p.id, p.name.as_str());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ui.checkbox(&mut source.visible, "visible");
|
ui.checkbox(&mut source.enabled, "enabled");
|
||||||
ui.add(Slider::new(&mut source.interval, 1..=60));
|
ui.add(Slider::new(&mut source.interval, 1..=60));
|
||||||
ui.color_edit_button_srgba(&mut source.color);
|
ui.color_edit_button_srgba(&mut source.color);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn source_edit_ui(ui: &mut Ui, source: &mut Source, panels: &Vec<Panel>, width: f32) {
|
pub fn source_edit_ui(ui: &mut Ui, source: &mut Source, panels: &Vec<Panel>, width: f32) {
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.vertical(|ui| {
|
||||||
let text_width = width - 25.0;
|
ui.horizontal(|ui| {
|
||||||
ui.checkbox(&mut source.visible, "");
|
let text_width = width - 25.0;
|
||||||
TextEdit::singleline(&mut source.name)
|
ui.checkbox(&mut source.enabled, "");
|
||||||
.desired_width(text_width / 4.0)
|
TextEdit::singleline(&mut source.name)
|
||||||
.hint_text("name")
|
.desired_width(text_width / 4.0)
|
||||||
.show(ui);
|
.hint_text("name")
|
||||||
TextEdit::singleline(&mut source.url)
|
.show(ui);
|
||||||
.desired_width(text_width * 3.0 / 4.0)
|
TextEdit::singleline(&mut source.url)
|
||||||
.hint_text("url")
|
.desired_width(text_width * 3.0 / 4.0)
|
||||||
.show(ui);
|
.hint_text("url")
|
||||||
});
|
.show(ui);
|
||||||
ui.horizontal(|ui| {
|
});
|
||||||
let text_width : f32 ;
|
ui.horizontal(|ui| {
|
||||||
if width > 400.0 {
|
let text_width : f32 ;
|
||||||
ui.add(Slider::new(&mut source.interval, 1..=120));
|
if width > 400.0 {
|
||||||
text_width = width - 330.0
|
ui.add(Slider::new(&mut source.interval, 1..=120));
|
||||||
} else {
|
text_width = width - 330.0
|
||||||
ui.add(DragValue::new(&mut source.interval).clamp_range(1..=120));
|
} else {
|
||||||
text_width = width - 225.0
|
ui.add(DragValue::new(&mut source.interval).clamp_range(1..=120));
|
||||||
}
|
text_width = width - 225.0
|
||||||
TextEdit::singleline(&mut source.query_x)
|
}
|
||||||
.desired_width(text_width / 2.0)
|
TextEdit::singleline(&mut source.query_x)
|
||||||
.hint_text("x")
|
.desired_width(text_width / 2.0)
|
||||||
.show(ui);
|
.hint_text("x")
|
||||||
TextEdit::singleline(&mut source.query_y)
|
.show(ui);
|
||||||
.desired_width(text_width / 2.0)
|
TextEdit::singleline(&mut source.query_y)
|
||||||
.hint_text("y")
|
.desired_width(text_width / 2.0)
|
||||||
.show(ui);
|
.hint_text("y")
|
||||||
ComboBox::from_id_source(format!("panel-{}", source.id))
|
.show(ui);
|
||||||
.width(60.0)
|
ComboBox::from_id_source(format!("panel-{}", source.id))
|
||||||
.selected_text(format!("panel [{}]", source.panel_id))
|
.width(60.0)
|
||||||
.show_ui(ui, |ui| {
|
.selected_text(format!("panel: {}", source.panel_id))
|
||||||
for p in panels {
|
.show_ui(ui, |ui| {
|
||||||
ui.selectable_value(&mut source.panel_id, p.id, p.name.as_str());
|
ui.selectable_value(&mut source.panel_id, -1, "None");
|
||||||
}
|
for p in panels {
|
||||||
});
|
ui.selectable_value(&mut source.panel_id, p.id, p.name.as_str());
|
||||||
ui.color_edit_button_srgba(&mut source.color);
|
}
|
||||||
|
});
|
||||||
|
ui.color_edit_button_srgba(&mut source.color);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,7 @@ impl eframe::App for App {
|
||||||
)
|
)
|
||||||
.show_header(ui, |ui| {
|
.show_header(ui, |ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
ui.separator();
|
||||||
ui.label(self.data.file_path.to_str().unwrap()); // TODO maybe calculate it just once?
|
ui.label(self.data.file_path.to_str().unwrap()); // TODO maybe calculate it just once?
|
||||||
ui.separator();
|
ui.separator();
|
||||||
ui.label(human_size(
|
ui.label(human_size(
|
||||||
|
@ -118,17 +119,36 @@ impl eframe::App for App {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if self.edit {
|
if self.edit {
|
||||||
|
let mut to_swap: Option<usize> = None;
|
||||||
|
// let mut to_delete: Option<usize> = None;
|
||||||
SidePanel::left("sources-bar")
|
SidePanel::left("sources-bar")
|
||||||
.width_range(240.0..=800.0)
|
.width_range(280.0..=800.0)
|
||||||
.default_width(500.0)
|
.default_width(500.0)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui| {
|
||||||
let panels = self.data.panels.read().expect("Panels RwLock poisoned");
|
let panels = self.data.panels.read().expect("Panels RwLock poisoned");
|
||||||
ScrollArea::vertical().show(ui, |ui| {
|
ScrollArea::vertical().show(ui, |ui| {
|
||||||
let width = ui.available_width();
|
let panel_width = ui.available_width();
|
||||||
{
|
{
|
||||||
let mut sources = self.data.sources.write().expect("Sources RwLock poisoned");
|
let mut sources = self.data.sources.write().expect("Sources RwLock poisoned");
|
||||||
for source in &mut *sources {
|
let sources_count = sources.len();
|
||||||
source_edit_ui(ui, source, &panels, width);
|
for (index, source) in sources.iter_mut().enumerate() {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
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 ui.small_button("−").clicked() {
|
||||||
|
if index < sources_count - 1 {
|
||||||
|
to_swap = Some(index + 1); // TODO kinda jank but is there a better way?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let remaining_width = ui.available_width();
|
||||||
|
source_edit_ui(ui, source, &panels, remaining_width);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ui.add_space(20.0);
|
ui.add_space(20.0);
|
||||||
|
@ -148,14 +168,25 @@ impl eframe::App for App {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
source_edit_ui(ui, &mut self.input_source, &panels, width);
|
source_edit_ui(ui, &mut self.input_source, &panels, panel_width);
|
||||||
if self.padding {
|
if self.padding {
|
||||||
ui.add_space(300.0);
|
ui.add_space(300.0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
//if let Some(i) = to_delete {
|
||||||
|
// // TODO can this be done in background? idk
|
||||||
|
// let mut panels = self.data.panels.write().expect("Panels RwLock poisoned");
|
||||||
|
// panels.remove(i);
|
||||||
|
// } else
|
||||||
|
if let Some(i) = to_swap {
|
||||||
|
// TODO can this be done in background? idk
|
||||||
|
let mut sources = self.data.sources.write().expect("Sources RwLock poisoned");
|
||||||
|
sources.swap(i - 1, i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let mut to_swap: Vec<usize> = Vec::new();
|
let mut to_swap: Option<usize> = None;
|
||||||
|
let mut to_delete: Option<usize> = None;
|
||||||
CentralPanel::default().show(ctx, |ui| {
|
CentralPanel::default().show(ctx, |ui| {
|
||||||
ScrollArea::vertical().show(ui, |ui| {
|
ScrollArea::vertical().show(ui, |ui| {
|
||||||
let mut panels = self.data.panels.write().expect("Panels RwLock poisoned"); // TODO only lock as write when editing
|
let mut panels = self.data.panels.write().expect("Panels RwLock poisoned"); // TODO only lock as write when editing
|
||||||
|
@ -174,14 +205,17 @@ impl eframe::App for App {
|
||||||
if self.edit {
|
if self.edit {
|
||||||
if ui.small_button(" + ").clicked() {
|
if ui.small_button(" + ").clicked() {
|
||||||
if index > 0 {
|
if index > 0 {
|
||||||
to_swap.push(index); // TODO kinda jank but is there a better way?
|
to_swap = Some(index); // TODO kinda jank but is there a better way?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ui.small_button(" - ").clicked() {
|
if ui.small_button(" − ").clicked() {
|
||||||
if index < panels_count - 1 {
|
if index < panels_count - 1 {
|
||||||
to_swap.push(index + 1); // TODO kinda jank but is there a better way?
|
to_swap = Some(index + 1); // TODO kinda jank but is there a better way?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ui.small_button(" × ").clicked() {
|
||||||
|
to_delete = Some(index); // TODO kinda jank but is there a better way?
|
||||||
|
}
|
||||||
ui.separator();
|
ui.separator();
|
||||||
}
|
}
|
||||||
panel_title_ui(ui, panel, self.edit);
|
panel_title_ui(ui, panel, self.edit);
|
||||||
|
@ -190,12 +224,18 @@ impl eframe::App for App {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if !to_swap.is_empty() {
|
if let Some(i) = to_delete {
|
||||||
// TODO can this be done in background? idk
|
// TODO can this be done in background? idk
|
||||||
let mut panels = self.data.panels.write().expect("Panels RwLock poisoned");
|
let mut panels = self.data.panels.write().expect("Panels RwLock poisoned");
|
||||||
for index in to_swap {
|
if let Err(e) = self.data.storage.lock().expect("Storage Mutex poisoned").delete_panel(panels[i].id) {
|
||||||
panels.swap(index - 1, index);
|
error!(target: "ui", "Could not delete panel : {:?}", e);
|
||||||
|
} else {
|
||||||
|
panels.remove(i);
|
||||||
}
|
}
|
||||||
|
} else if let Some(i) = to_swap {
|
||||||
|
// TODO can this be done in background? idk
|
||||||
|
let mut panels = self.data.panels.write().expect("Panels RwLock poisoned");
|
||||||
|
panels.swap(i - 1, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,17 +23,18 @@ pub fn native_save(state: Arc<ApplicationState>) {
|
||||||
warn!(target: "native-save", "Could not update panel #{} : {:?}", panel.id, e);
|
warn!(target: "native-save", "Could not update panel #{} : {:?}", panel.id, e);
|
||||||
}
|
}
|
||||||
let sources = state.sources.read().expect("Sources RwLock poisoned");
|
let sources = state.sources.read().expect("Sources RwLock poisoned");
|
||||||
for source in &*sources {
|
for (index, source) in sources.iter().enumerate() {
|
||||||
if let Err(e) = storage.update_source(
|
if let Err(e) = storage.update_source(
|
||||||
source.id,
|
source.id,
|
||||||
source.panel_id,
|
source.panel_id,
|
||||||
source.name.as_str(),
|
source.name.as_str(),
|
||||||
|
source.enabled,
|
||||||
source.url.as_str(),
|
source.url.as_str(),
|
||||||
source.interval,
|
source.interval,
|
||||||
source.query_x.as_str(),
|
source.query_x.as_str(),
|
||||||
source.query_y.as_str(),
|
source.query_y.as_str(),
|
||||||
source.color,
|
source.color,
|
||||||
source.visible,
|
index as i32,
|
||||||
) {
|
) {
|
||||||
warn!(target: "native-save", "Could not update source #{} : {:?}", source.id, e);
|
warn!(target: "native-save", "Could not update source #{} : {:?}", source.id, e);
|
||||||
}
|
}
|
||||||
|
@ -65,7 +66,7 @@ impl BackgroundWorker for NativeBackgroundWorker {
|
||||||
let sources = state.sources.read().expect("Sources RwLock poisoned");
|
let sources = state.sources.read().expect("Sources RwLock poisoned");
|
||||||
for j in 0..sources.len() {
|
for j in 0..sources.len() {
|
||||||
let s_id = sources[j].id;
|
let s_id = sources[j].id;
|
||||||
if !sources[j].valid() {
|
if sources[j].enabled && !sources[j].valid() {
|
||||||
let mut last_update = sources[j]
|
let mut last_update = sources[j]
|
||||||
.last_fetch
|
.last_fetch
|
||||||
.write()
|
.write()
|
||||||
|
|
Loading…
Reference in a new issue