mirror of
https://git.alemi.dev/dashboard.git
synced 2024-11-22 07:24:52 +01:00
feat: added relations, added window uis to edit them all
This commit is contained in:
parent
76772465a3
commit
32d68691a1
16 changed files with 435 additions and 78 deletions
|
@ -2,6 +2,8 @@ pub use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
mod m20220101_000001_create_table;
|
mod m20220101_000001_create_table;
|
||||||
mod m20221030_192706_add_last_update;
|
mod m20221030_192706_add_last_update;
|
||||||
|
mod m20221102_232244_add_join_table;
|
||||||
|
mod m20221102_232858_remove_unused_columns;
|
||||||
|
|
||||||
pub struct Migrator;
|
pub struct Migrator;
|
||||||
|
|
||||||
|
@ -11,6 +13,8 @@ impl MigratorTrait for Migrator {
|
||||||
vec![
|
vec![
|
||||||
Box::new(m20220101_000001_create_table::Migration),
|
Box::new(m20220101_000001_create_table::Migration),
|
||||||
Box::new(m20221030_192706_add_last_update::Migration),
|
Box::new(m20221030_192706_add_last_update::Migration),
|
||||||
|
Box::new(m20221102_232244_add_join_table::Migration),
|
||||||
|
Box::new(m20221102_232858_remove_unused_columns::Migration),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
40
migration/src/m20221102_232244_add_join_table.rs
Normal file
40
migration/src/m20221102_232244_add_join_table.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
#[derive(DeriveMigrationName)]
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(PanelMetric::Table)
|
||||||
|
.if_not_exists()
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(PanelMetric::Id)
|
||||||
|
.big_integer()
|
||||||
|
.not_null()
|
||||||
|
.auto_increment()
|
||||||
|
.primary_key(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(PanelMetric::PanelId).big_integer().not_null())
|
||||||
|
.col(ColumnDef::new(PanelMetric::MetricId).big_integer().not_null())
|
||||||
|
.to_owned(),
|
||||||
|
).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(PanelMetric::Table).to_owned())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Iden)]
|
||||||
|
enum PanelMetric {
|
||||||
|
Table,
|
||||||
|
Id,
|
||||||
|
PanelId,
|
||||||
|
MetricId,
|
||||||
|
}
|
85
migration/src/m20221102_232858_remove_unused_columns.rs
Normal file
85
migration/src/m20221102_232858_remove_unused_columns.rs
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
#[derive(DeriveMigrationName)]
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager.
|
||||||
|
alter_table(
|
||||||
|
Table::alter()
|
||||||
|
.table(Panels::Table)
|
||||||
|
.drop_column(Panels::Width)
|
||||||
|
.drop_column(Panels::LimitView)
|
||||||
|
.drop_column(Panels::ShiftView)
|
||||||
|
.to_owned()
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
manager.
|
||||||
|
alter_table(
|
||||||
|
Table::alter()
|
||||||
|
.table(Metrics::Table)
|
||||||
|
.drop_column(Metrics::PanelId)
|
||||||
|
.to_owned()
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.alter_table(
|
||||||
|
Table::alter()
|
||||||
|
.table(Panels::Table)
|
||||||
|
.add_column(
|
||||||
|
ColumnDef::new(Panels::Width)
|
||||||
|
.integer()
|
||||||
|
.not_null()
|
||||||
|
.default(100)
|
||||||
|
)
|
||||||
|
.add_column(
|
||||||
|
ColumnDef::new(Panels::LimitView)
|
||||||
|
.boolean()
|
||||||
|
.not_null()
|
||||||
|
.default(true)
|
||||||
|
)
|
||||||
|
.add_column(
|
||||||
|
ColumnDef::new(Panels::ShiftView)
|
||||||
|
.boolean()
|
||||||
|
.not_null()
|
||||||
|
.default(false)
|
||||||
|
)
|
||||||
|
.to_owned()
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
manager
|
||||||
|
.alter_table(
|
||||||
|
Table::alter()
|
||||||
|
.table(Metrics::Table)
|
||||||
|
.add_column(
|
||||||
|
ColumnDef::new(Metrics::PanelId)
|
||||||
|
.big_integer()
|
||||||
|
.not_null()
|
||||||
|
.default(0)
|
||||||
|
)
|
||||||
|
.to_owned()
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Iden)]
|
||||||
|
enum Panels {
|
||||||
|
Table,
|
||||||
|
Width,
|
||||||
|
LimitView,
|
||||||
|
ShiftView,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Iden)]
|
||||||
|
enum Metrics {
|
||||||
|
Table,
|
||||||
|
PanelId,
|
||||||
|
}
|
|
@ -15,17 +15,43 @@ pub struct Model {
|
||||||
pub source_id: i64,
|
pub source_id: i64,
|
||||||
pub query_x: String,
|
pub query_x: String,
|
||||||
pub query_y: String,
|
pub query_y: String,
|
||||||
pub panel_id: i64,
|
|
||||||
pub color: i32,
|
pub color: i32,
|
||||||
pub position: i32,
|
pub position: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {}
|
pub enum Relation {
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::sources::Entity",
|
||||||
|
from = "Column::SourceId",
|
||||||
|
to = "super::sources::Column::Id"
|
||||||
|
)]
|
||||||
|
Source,
|
||||||
|
|
||||||
|
#[sea_orm(has_many = "super::points::Entity")]
|
||||||
|
Point,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::sources::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef { Relation::Source.def() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::points::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef { Relation::Point.def() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::panels::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
super::panel_metric::Relation::Panel.def()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn via() -> Option<RelationDef> {
|
||||||
|
Some(super::panel_metric::Relation::Metric.def().rev())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
|
||||||
impl Model {
|
impl Model {
|
||||||
pub fn extract(&self, value: &serde_json::Value) -> Result<PlotPoint, FetchError> {
|
pub fn extract(&self, value: &serde_json::Value) -> Result<PlotPoint, FetchError> {
|
||||||
let x: f64;
|
let x: f64;
|
||||||
|
@ -51,7 +77,6 @@ impl Default for Model {
|
||||||
source_id: 0,
|
source_id: 0,
|
||||||
query_x: "".into(),
|
query_x: "".into(),
|
||||||
query_y: "".into(),
|
query_y: "".into(),
|
||||||
panel_id: 0,
|
|
||||||
color: 0,
|
color: 0,
|
||||||
position: 0,
|
position: 0,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
|
||||||
pub mod metrics;
|
|
||||||
pub mod panels;
|
pub mod panels;
|
||||||
|
pub mod panel_metric;
|
||||||
|
pub mod metrics;
|
||||||
pub mod points;
|
pub mod points;
|
||||||
pub mod sources;
|
pub mod sources;
|
||||||
|
|
29
src/data/entities/panel_metric.rs
Normal file
29
src/data/entities/panel_metric.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||||
|
#[sea_orm(table_name = "panel_metric")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = true)]
|
||||||
|
pub id: i64,
|
||||||
|
pub panel_id: i64,
|
||||||
|
pub metric_id: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::panels::Entity",
|
||||||
|
from = "Column::PanelId",
|
||||||
|
to = "super::panels::Column::Id"
|
||||||
|
)]
|
||||||
|
Panel,
|
||||||
|
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::metrics::Entity",
|
||||||
|
from = "Column::MetricId",
|
||||||
|
to = "super::metrics::Column::Id"
|
||||||
|
)]
|
||||||
|
Metric,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
|
@ -12,11 +12,9 @@ pub struct Model {
|
||||||
pub view_size: i32,
|
pub view_size: i32,
|
||||||
pub timeserie: bool,
|
pub timeserie: bool,
|
||||||
pub height: i32,
|
pub height: i32,
|
||||||
pub limit_view: bool,
|
|
||||||
pub position: i32,
|
pub position: i32,
|
||||||
pub reduce_view: bool,
|
pub reduce_view: bool,
|
||||||
pub view_chunks: i32,
|
pub view_chunks: i32,
|
||||||
pub shift_view: bool,
|
|
||||||
pub view_offset: i32,
|
pub view_offset: i32,
|
||||||
pub average_view: bool,
|
pub average_view: bool,
|
||||||
}
|
}
|
||||||
|
@ -24,6 +22,16 @@ pub struct Model {
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {}
|
pub enum Relation {}
|
||||||
|
|
||||||
|
impl Related<super::metrics::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
super::panel_metric::Relation::Metric.def()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn via() -> Option<RelationDef> {
|
||||||
|
Some(super::panel_metric::Relation::Panel.def().rev())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
impl Default for Model {
|
impl Default for Model {
|
||||||
|
@ -35,11 +43,9 @@ impl Default for Model {
|
||||||
view_size: 1000,
|
view_size: 1000,
|
||||||
timeserie: true,
|
timeserie: true,
|
||||||
height: 100,
|
height: 100,
|
||||||
limit_view: true,
|
|
||||||
position: 0,
|
position: 0,
|
||||||
reduce_view: false,
|
reduce_view: false,
|
||||||
view_chunks: 10,
|
view_chunks: 10,
|
||||||
shift_view: false,
|
|
||||||
view_offset: 0,
|
view_offset: 0,
|
||||||
average_view: true,
|
average_view: true,
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,18 @@ pub struct Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {}
|
pub enum Relation {
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::metrics::Entity",
|
||||||
|
from = "Column::MetricId",
|
||||||
|
to = "super::metrics::Column::Id"
|
||||||
|
)]
|
||||||
|
Metric,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::metrics::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef { Relation::Metric.def() }
|
||||||
|
}
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
|
|
@ -4,3 +4,4 @@ pub use super::metrics::Entity as Metrics;
|
||||||
pub use super::panels::Entity as Panels;
|
pub use super::panels::Entity as Panels;
|
||||||
pub use super::points::Entity as Points;
|
pub use super::points::Entity as Points;
|
||||||
pub use super::sources::Entity as Sources;
|
pub use super::sources::Entity as Sources;
|
||||||
|
pub use super::panel_metric::Entity as PanelMetric;
|
||||||
|
|
|
@ -15,7 +15,16 @@ pub struct Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {}
|
pub enum Relation {
|
||||||
|
#[sea_orm(has_many = "super::metrics::Entity")]
|
||||||
|
Metric,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::metrics::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Metric.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ use eframe::{egui::{Ui, Layout, Sense, color_picker::show_color_at, ComboBox, Te
|
||||||
|
|
||||||
use crate::{data::entities, util::unpack_color};
|
use crate::{data::entities, util::unpack_color};
|
||||||
|
|
||||||
fn _color_square(ui: &mut Ui, color:Color32) {
|
fn color_square(ui: &mut Ui, color:Color32) {
|
||||||
let size = ui.spacing().interact_size;
|
let size = ui.spacing().interact_size;
|
||||||
let (rect, response) = ui.allocate_exact_size(size, Sense::click());
|
let (rect, response) = ui.allocate_exact_size(size, Sense::click());
|
||||||
if ui.is_rect_visible(rect) {
|
if ui.is_rect_visible(rect) {
|
||||||
|
@ -19,11 +19,11 @@ fn _color_square(ui: &mut Ui, color:Color32) {
|
||||||
|
|
||||||
pub fn _metric_display_ui(ui: &mut Ui, metric: &entities::metrics::Model, _width: f32) {
|
pub fn _metric_display_ui(ui: &mut Ui, metric: &entities::metrics::Model, _width: f32) {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
_color_square(ui, unpack_color(metric.color));
|
color_square(ui, unpack_color(metric.color));
|
||||||
ui.label(&metric.name);
|
ui.label(&metric.name);
|
||||||
ui.with_layout(Layout::top_down(Align::RIGHT), |ui| {
|
ui.with_layout(Layout::top_down(Align::RIGHT), |ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label(format!("panel: {}", metric.panel_id));
|
ui.label("panel: ???");
|
||||||
ui.label(format!("y: {}", metric.query_y));
|
ui.label(format!("y: {}", metric.query_y));
|
||||||
// if let Some(query_x) = metric.query_x {
|
// if let Some(query_x) = metric.query_x {
|
||||||
// ui.label(format!("x: {}", query_x));
|
// ui.label(format!("x: {}", query_x));
|
||||||
|
@ -40,7 +40,8 @@ pub fn metric_edit_ui(ui: &mut Ui, metric: &entities::metrics::Model, panels: Op
|
||||||
let mut query_y = metric.query_y.clone();
|
let mut query_y = metric.query_y.clone();
|
||||||
let mut panel_id = 0;
|
let mut panel_id = 0;
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.color_edit_button_srgba(&mut unpack_color(metric.color));
|
// ui.color_edit_button_srgba(&mut unpack_color(metric.color));
|
||||||
|
color_square(ui, unpack_color(metric.color));
|
||||||
TextEdit::singleline(&mut name)
|
TextEdit::singleline(&mut name)
|
||||||
.interactive(false)
|
.interactive(false)
|
||||||
.desired_width(text_width / 2.0)
|
.desired_width(text_width / 2.0)
|
||||||
|
@ -62,7 +63,7 @@ pub fn metric_edit_ui(ui: &mut Ui, metric: &entities::metrics::Model, panels: Op
|
||||||
if let Some(panels) = panels {
|
if let Some(panels) = panels {
|
||||||
ComboBox::from_id_source(format!("panel-selector-{}", metric.id))
|
ComboBox::from_id_source(format!("panel-selector-{}", metric.id))
|
||||||
.width(60.0)
|
.width(60.0)
|
||||||
.selected_text(format!("panel: {:02}", metric.panel_id))
|
.selected_text("panel: ???")
|
||||||
.show_ui(ui, |ui| {
|
.show_ui(ui, |ui| {
|
||||||
ui.selectable_value(&mut panel_id, -1, "None");
|
ui.selectable_value(&mut panel_id, -1, "None");
|
||||||
for p in panels {
|
for p in panels {
|
||||||
|
|
|
@ -17,7 +17,7 @@ use scaffold::{
|
||||||
};
|
};
|
||||||
use source::source_panel;
|
use source::source_panel;
|
||||||
|
|
||||||
use self::scaffold::{footer, popup_edit_ui, EditingModel};
|
use self::scaffold::{footer, EditingModel, popup_edit_ui};
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
view: AppStateView,
|
view: AppStateView,
|
||||||
|
@ -94,7 +94,9 @@ impl eframe::App for App {
|
||||||
});
|
});
|
||||||
|
|
||||||
for m in self.editing.iter_mut() {
|
for m in self.editing.iter_mut() {
|
||||||
Window::new(m.id_repr()).show(ctx, |ui| popup_edit_ui(ui, m));
|
Window::new(m.id_repr())
|
||||||
|
.default_width(150.0)
|
||||||
|
.show(ctx, |ui| popup_edit_ui(ui, m, &self.view.sources.borrow(), &self.view.metrics.borrow()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.sidebar {
|
if self.sidebar {
|
||||||
|
@ -121,7 +123,7 @@ impl eframe::App for App {
|
||||||
|
|
||||||
for m in self.editing.iter() {
|
for m in self.editing.iter() {
|
||||||
if m.should_fetch() {
|
if m.should_fetch() {
|
||||||
self.op(m.to_msg());
|
self.op(m.to_msg(self.view.clone())); // TODO cloning is super wasteful
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ use crate::util::{timestamp_to_str, unpack_color};
|
||||||
use crate::gui::App;
|
use crate::gui::App;
|
||||||
use crate::data::entities;
|
use crate::data::entities;
|
||||||
|
|
||||||
|
use super::scaffold::EditingModel;
|
||||||
|
|
||||||
pub fn main_content(app: &mut App, ctx: &Context, ui: &mut Ui) {
|
pub fn main_content(app: &mut App, ctx: &Context, ui: &mut Ui) {
|
||||||
let mut _to_swap: Option<usize> = None;
|
let mut _to_swap: Option<usize> = None;
|
||||||
let mut _to_delete: Option<usize> = None;
|
let mut _to_delete: Option<usize> = None;
|
||||||
|
@ -39,9 +41,9 @@ pub fn main_content(app: &mut App, ctx: &Context, ui: &mut Ui) {
|
||||||
// to_delete = Some(index); // TODO kinda jank but is there a better way?
|
// to_delete = Some(index); // TODO kinda jank but is there a better way?
|
||||||
// }
|
// }
|
||||||
// ui.separator();
|
// ui.separator();
|
||||||
panel_title_ui(ui, panel, app.edit);
|
panel_title_ui(ui, panel, &mut app.editing, &app.view.metrics.borrow(), &app.view.panel_metric.borrow());
|
||||||
})
|
})
|
||||||
.body(|ui| panel_body_ui(ui, panel, &metrics, &app.view.points.borrow()));
|
.body(|ui| panel_body_ui(ui, panel, &metrics, &app.view.points.borrow(), &app.view.panel_metric.borrow()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -53,10 +55,23 @@ pub fn _panel_edit_inline_ui(_ui: &mut Ui, _panel: &entities::panels::Model) {
|
||||||
// .show(ui);
|
// .show(ui);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn panel_title_ui(ui: &mut Ui, panel: &mut entities::panels::Model, _edit: bool) { // TODO make edit UI in separate func
|
pub fn panel_title_ui(
|
||||||
|
ui: &mut Ui,
|
||||||
|
panel: &mut entities::panels::Model,
|
||||||
|
editing: &mut Vec<EditingModel>,
|
||||||
|
metrics: &Vec<entities::metrics::Model>,
|
||||||
|
panel_metric: &Vec<entities::panel_metric::Model>,
|
||||||
|
) { // TODO make edit UI in separate func
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.heading(panel.name.as_str());
|
ui.heading(panel.name.as_str());
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
if ui.small_button("#").clicked() {
|
||||||
|
// TODO don't add duplicates
|
||||||
|
editing.push(
|
||||||
|
EditingModel::make_edit_panel(panel.clone(), metrics, panel_metric)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ui.separator();
|
||||||
ui.add(Slider::new(&mut panel.height, 0..=500).text("height"));
|
ui.add(Slider::new(&mut panel.height, 0..=500).text("height"));
|
||||||
//ui.separator();
|
//ui.separator();
|
||||||
//ui.checkbox(&mut panel.timeserie, "timeserie");
|
//ui.checkbox(&mut panel.timeserie, "timeserie");
|
||||||
|
@ -93,26 +108,29 @@ pub fn panel_title_ui(ui: &mut Ui, panel: &mut entities::panels::Model, _edit: b
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn panel_body_ui(ui: &mut Ui, panel: &entities::panels::Model, metrics: &Vec<entities::metrics::Model>, points: &Vec<entities::points::Model>) {
|
pub fn panel_body_ui(
|
||||||
|
ui: &mut Ui,
|
||||||
|
panel: &entities::panels::Model,
|
||||||
|
metrics: &Vec<entities::metrics::Model>,
|
||||||
|
points: &Vec<entities::points::Model>,
|
||||||
|
panel_metric: &Vec<entities::panel_metric::Model>,
|
||||||
|
) {
|
||||||
let mut p = Plot::new(format!("plot-{}", panel.name))
|
let mut p = Plot::new(format!("plot-{}", panel.name))
|
||||||
.height(panel.height as f32)
|
.height(panel.height as f32)
|
||||||
.allow_scroll(false)
|
.allow_scroll(false)
|
||||||
.legend(Legend::default().position(Corner::LeftTop));
|
.legend(Legend::default().position(Corner::LeftTop));
|
||||||
|
|
||||||
if panel.limit_view {
|
if panel.view_scroll {
|
||||||
p = p.set_margin_fraction(Vec2 { x: 0.0, y: 0.1 });
|
p = p.set_margin_fraction(Vec2 { x: 0.0, y: 0.1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if panel.timeserie {
|
if panel.timeserie {
|
||||||
if panel.view_scroll {
|
if panel.view_scroll {
|
||||||
let _now = (Utc::now().timestamp() as f64) - (60.0 * panel.view_offset as f64);
|
let now = (Utc::now().timestamp() as f64) - (60.0 * panel.view_offset as f64);
|
||||||
p = p.include_x(_now);
|
p = p.include_x(now)
|
||||||
if panel.limit_view {
|
.include_x(now + (panel.view_size as f64 * 3.0))
|
||||||
p = p
|
.include_x(now - (panel.view_size as f64 * 60.0)); // ??? TODO
|
||||||
.include_x(_now + (panel.view_size as f64 * 3.0))
|
|
||||||
.include_x(_now - (panel.view_size as f64 * 60.0)); // ??? TODO
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
p = p
|
p = p
|
||||||
.x_axis_formatter(|x, _range| timestamp_to_str(x as i64, true, false))
|
.x_axis_formatter(|x, _range| timestamp_to_str(x as i64, true, false))
|
||||||
|
@ -165,8 +183,9 @@ pub fn panel_body_ui(ui: &mut Ui, panel: &entities::panels::Model, metrics: &Vec
|
||||||
let min_x = now - size - off;
|
let min_x = now - size - off;
|
||||||
let max_x = now - off;
|
let max_x = now - off;
|
||||||
let chunk_size = if panel.reduce_view { Some(panel.view_chunks) } else { None };
|
let chunk_size = if panel.reduce_view { Some(panel.view_chunks) } else { None };
|
||||||
|
let metric_ids : Vec<i64> = panel_metric.iter().filter(|x| x.panel_id == panel.id).map(|x| x.metric_id).collect();
|
||||||
for metric in metrics {
|
for metric in metrics {
|
||||||
if metric.panel_id == panel.id {
|
if metric_ids.contains(&metric.id) {
|
||||||
// let values = metric.values(min_x, max_x, chunk_size, panel.average_view);
|
// let values = metric.values(min_x, max_x, chunk_size, panel.average_view);
|
||||||
let mut values : Vec<[f64;2]> = points
|
let mut values : Vec<[f64;2]> = points
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use eframe::{Frame, egui::{collapsing_header::CollapsingState, Context, Ui, Layout, ScrollArea, global_dark_light_mode_switch, TextEdit, Checkbox, Slider}, emath::Align};
|
use eframe::{Frame, egui::{collapsing_header::CollapsingState, Context, Ui, Layout, ScrollArea, global_dark_light_mode_switch, TextEdit, Checkbox, Slider, ComboBox}, emath::Align};
|
||||||
use sea_orm::{Set, Unchanged, ActiveValue::NotSet};
|
use sea_orm::{Set, Unchanged, ActiveValue::NotSet};
|
||||||
use tokio::sync::watch;
|
use tokio::sync::watch;
|
||||||
|
|
||||||
use crate::{gui::App, data::entities, util::unpack_color, worker::BackgroundAction};
|
use crate::{gui::App, data::entities, util::{unpack_color, repack_color}, worker::{BackgroundAction, AppStateView}};
|
||||||
|
|
||||||
// TODO make this not super specific!
|
// TODO make this not super specific!
|
||||||
pub fn _confirmation_popup_delete_metric(_app: &mut App, ui: &mut Ui, _metric_index: usize) {
|
pub fn _confirmation_popup_delete_metric(_app: &mut App, ui: &mut Ui, _metric_index: usize) {
|
||||||
|
@ -68,7 +68,7 @@ pub struct EditingModel {
|
||||||
impl EditingModel {
|
impl EditingModel {
|
||||||
pub fn id_repr(&self) -> String {
|
pub fn id_repr(&self) -> String {
|
||||||
let prefix = match self.m {
|
let prefix = match self.m {
|
||||||
EditingModelType::EditingPanel { panel: _ } => "panel",
|
EditingModelType::EditingPanel { panel: _, opts: _ } => "panel",
|
||||||
EditingModelType::EditingSource { source: _ } => "source",
|
EditingModelType::EditingSource { source: _ } => "source",
|
||||||
EditingModelType::EditingMetric { metric: _ } => "metric",
|
EditingModelType::EditingMetric { metric: _ } => "metric",
|
||||||
};
|
};
|
||||||
|
@ -83,9 +83,30 @@ impl EditingModel {
|
||||||
return !self.ready;
|
return !self.ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_msg(&self) -> BackgroundAction {
|
pub fn make_edit_panel(
|
||||||
|
panel: entities::panels::Model,
|
||||||
|
metrics: &Vec<entities::metrics::Model>,
|
||||||
|
panel_metric: &Vec<entities::panel_metric::Model>
|
||||||
|
) -> EditingModel {
|
||||||
|
let metric_ids : Vec<i64> = panel_metric.iter().filter(|x| x.panel_id == panel.id).map(|x| x.metric_id).collect();
|
||||||
|
let mut opts = vec![false; metrics.len()];
|
||||||
|
for i in 0..metrics.len() {
|
||||||
|
if metric_ids.contains(&metrics[i].id) {
|
||||||
|
opts[i] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EditingModel {
|
||||||
|
id: panel.id,
|
||||||
|
new: if panel.id > 0 { false } else { true },
|
||||||
|
m: EditingModelType::EditingPanel { panel, opts },
|
||||||
|
valid: false,
|
||||||
|
ready: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_msg(&self, view:AppStateView) -> BackgroundAction {
|
||||||
match &self.m {
|
match &self.m {
|
||||||
EditingModelType::EditingPanel { panel } =>
|
EditingModelType::EditingPanel { panel, opts: metrics } =>
|
||||||
BackgroundAction::UpdatePanel {
|
BackgroundAction::UpdatePanel {
|
||||||
panel: entities::panels::ActiveModel {
|
panel: entities::panels::ActiveModel {
|
||||||
id: if self.new { NotSet } else { Unchanged(panel.id) },
|
id: if self.new { NotSet } else { Unchanged(panel.id) },
|
||||||
|
@ -94,14 +115,21 @@ impl EditingModel {
|
||||||
view_size: Set(panel.view_size),
|
view_size: Set(panel.view_size),
|
||||||
timeserie: Set(panel.timeserie),
|
timeserie: Set(panel.timeserie),
|
||||||
height: Set(panel.height),
|
height: Set(panel.height),
|
||||||
limit_view: Set(panel.limit_view),
|
|
||||||
position: Set(panel.position),
|
position: Set(panel.position),
|
||||||
reduce_view: Set(panel.reduce_view),
|
reduce_view: Set(panel.reduce_view),
|
||||||
view_chunks: Set(panel.view_chunks),
|
view_chunks: Set(panel.view_chunks),
|
||||||
shift_view: Set(panel.shift_view),
|
|
||||||
view_offset: Set(panel.view_offset),
|
view_offset: Set(panel.view_offset),
|
||||||
average_view: Set(panel.average_view),
|
average_view: Set(panel.average_view),
|
||||||
}
|
},
|
||||||
|
metrics: view.metrics.borrow().iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(i,x)| *metrics.get(*i).unwrap_or(&false))
|
||||||
|
.map(|(i,m)| entities::panel_metric::ActiveModel {
|
||||||
|
id: NotSet,
|
||||||
|
panel_id: Set(panel.id),
|
||||||
|
metric_id: Set(m.id),
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
},
|
},
|
||||||
EditingModelType::EditingSource { source } =>
|
EditingModelType::EditingSource { source } =>
|
||||||
BackgroundAction::UpdateSource {
|
BackgroundAction::UpdateSource {
|
||||||
|
@ -122,7 +150,6 @@ impl EditingModel {
|
||||||
name: Set(metric.name.clone()),
|
name: Set(metric.name.clone()),
|
||||||
source_id: Set(metric.source_id),
|
source_id: Set(metric.source_id),
|
||||||
color: Set(metric.color),
|
color: Set(metric.color),
|
||||||
panel_id: Set(metric.panel_id),
|
|
||||||
query_x: Set(metric.query_x.clone()),
|
query_x: Set(metric.query_x.clone()),
|
||||||
query_y: Set(metric.query_y.clone()),
|
query_y: Set(metric.query_y.clone()),
|
||||||
position: Set(metric.position),
|
position: Set(metric.position),
|
||||||
|
@ -154,24 +181,35 @@ impl From<entities::panels::Model> for EditingModel {
|
||||||
fn from(p: entities::panels::Model) -> Self {
|
fn from(p: entities::panels::Model) -> Self {
|
||||||
EditingModel {
|
EditingModel {
|
||||||
new: if p.id == 0 { true } else { false },
|
new: if p.id == 0 { true } else { false },
|
||||||
id: p.id, m: EditingModelType::EditingPanel { panel: p }, valid: false, ready: false,
|
id: p.id, m: EditingModelType::EditingPanel { panel: p , opts: vec![] }, valid: false, ready: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum EditingModelType {
|
pub enum EditingModelType {
|
||||||
EditingPanel { panel : entities::panels::Model },
|
EditingPanel { panel : entities::panels::Model, opts: Vec<bool> },
|
||||||
EditingSource { source: entities::sources::Model },
|
EditingSource { source: entities::sources::Model },
|
||||||
EditingMetric { metric: entities::metrics::Model },
|
EditingMetric { metric: entities::metrics::Model },
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn popup_edit_ui(ui: &mut Ui, model: &mut EditingModel) {
|
pub fn popup_edit_ui(
|
||||||
|
ui: &mut Ui,
|
||||||
|
model: &mut EditingModel,
|
||||||
|
sources: &Vec<entities::sources::Model>,
|
||||||
|
metrics: &Vec<entities::metrics::Model>
|
||||||
|
) {
|
||||||
match &mut model.m {
|
match &mut model.m {
|
||||||
EditingModelType::EditingPanel { panel } => {
|
EditingModelType::EditingPanel { panel, opts } => {
|
||||||
ui.heading(format!("Edit panel #{}", panel.id));
|
ui.heading(format!("Edit panel #{}", panel.id));
|
||||||
TextEdit::singleline(&mut panel.name)
|
TextEdit::singleline(&mut panel.name)
|
||||||
.hint_text("name")
|
.hint_text("name")
|
||||||
.show(ui);
|
.show(ui);
|
||||||
|
for (i, metric) in metrics.iter().enumerate() {
|
||||||
|
if i >= opts.len() { // TODO safe but jank: always starts with all off
|
||||||
|
opts.push(false);
|
||||||
|
}
|
||||||
|
ui.checkbox(&mut opts[i], &metric.name);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
EditingModelType::EditingSource { source } => {
|
EditingModelType::EditingSource { source } => {
|
||||||
ui.heading(format!("Edit source #{}", source.id));
|
ui.heading(format!("Edit source #{}", source.id));
|
||||||
|
@ -189,11 +227,21 @@ pub fn popup_edit_ui(ui: &mut Ui, model: &mut EditingModel) {
|
||||||
EditingModelType::EditingMetric { metric } => {
|
EditingModelType::EditingMetric { metric } => {
|
||||||
ui.heading(format!("Edit metric #{}", metric.id));
|
ui.heading(format!("Edit metric #{}", metric.id));
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.color_edit_button_srgba(&mut unpack_color(metric.color));
|
let mut color_buf = unpack_color(metric.color);
|
||||||
|
ui.color_edit_button_srgba(&mut color_buf);
|
||||||
|
metric.color = repack_color(color_buf);
|
||||||
TextEdit::singleline(&mut metric.name)
|
TextEdit::singleline(&mut metric.name)
|
||||||
.hint_text("name")
|
.hint_text("name")
|
||||||
.show(ui);
|
.show(ui);
|
||||||
});
|
});
|
||||||
|
ComboBox::from_id_source(format!("source-selector-{}", metric.id))
|
||||||
|
.selected_text(format!("source: {:02}", metric.source_id))
|
||||||
|
.show_ui(ui, |ui| {
|
||||||
|
ui.selectable_value(&mut metric.source_id, -1, "None");
|
||||||
|
for s in sources.iter() {
|
||||||
|
ui.selectable_value(&mut metric.source_id, s.id, s.name.as_str());
|
||||||
|
}
|
||||||
|
});
|
||||||
TextEdit::singleline(&mut metric.query_x)
|
TextEdit::singleline(&mut metric.query_x)
|
||||||
.hint_text("x")
|
.hint_text("x")
|
||||||
.show(ui);
|
.show(ui);
|
||||||
|
|
|
@ -16,6 +16,7 @@ pub fn source_panel(app: &mut App, ui: &mut Ui) {
|
||||||
// let mut to_delete: Option<usize> = None;
|
// let mut to_delete: Option<usize> = None;
|
||||||
let panels = &app.panels;
|
let panels = &app.panels;
|
||||||
let panel_width = ui.available_width();
|
let panel_width = ui.available_width();
|
||||||
|
let mut orphaned_metrics = app.view.metrics.borrow().clone();
|
||||||
ScrollArea::vertical()
|
ScrollArea::vertical()
|
||||||
.max_width(panel_width)
|
.max_width(panel_width)
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
|
@ -29,16 +30,8 @@ pub fn source_panel(app: &mut App, ui: &mut Ui) {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
ui.add_space(10.0);
|
ui.add_space(10.0);
|
||||||
if ui.small_button("+").clicked() {
|
if ui.small_button("+").clicked() { }
|
||||||
if i > 0 {
|
if ui.small_button("−").clicked() { }
|
||||||
to_swap = Some(i); // TODO kinda jank but is there a better way?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ui.small_button("−").clicked() {
|
|
||||||
if i < sources_count - 1 {
|
|
||||||
to_swap = Some(i + 1); // TODO kinda jank but is there a better way?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
ui.vertical(|ui| { // actual sources list container
|
ui.vertical(|ui| { // actual sources list container
|
||||||
let remaining_width = ui.available_width();
|
let remaining_width = ui.available_width();
|
||||||
|
@ -56,6 +49,7 @@ pub fn source_panel(app: &mut App, ui: &mut Ui) {
|
||||||
.borrow();
|
.borrow();
|
||||||
for (_j, metric) in metrics.iter().enumerate() {
|
for (_j, metric) in metrics.iter().enumerate() {
|
||||||
if metric.source_id == source.id {
|
if metric.source_id == source.id {
|
||||||
|
orphaned_metrics.retain(|m| m.id != metric.id);
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
metric_edit_ui(
|
metric_edit_ui(
|
||||||
ui,
|
ui,
|
||||||
|
@ -91,6 +85,55 @@ pub fn source_panel(app: &mut App, ui: &mut Ui) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
ui.horizontal(|ui| { // 1 more for uncategorized sources
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.add_space(10.0);
|
||||||
|
if ui.small_button("+").clicked() { }
|
||||||
|
if ui.small_button("−").clicked() { }
|
||||||
|
});
|
||||||
|
ui.vertical(|ui| { // actual sources list container
|
||||||
|
let remaining_width = ui.available_width();
|
||||||
|
ui.group(|ui| {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
source_edit_ui(ui, &app.buffer_source, remaining_width - 34.0);
|
||||||
|
if ui.small_button("×").clicked() {
|
||||||
|
app.buffer_source = entities::sources::Model::default();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for metric in orphaned_metrics.iter() {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
metric_edit_ui(
|
||||||
|
ui,
|
||||||
|
metric,
|
||||||
|
Some(&panels),
|
||||||
|
remaining_width - 53.0,
|
||||||
|
);
|
||||||
|
if ui.small_button("s").clicked() {
|
||||||
|
// let path = FileDialog::new()
|
||||||
|
// .add_filter("csv", &["csv"])
|
||||||
|
// .set_file_name(format!("{}-{}.csv", source.name, metric.name).as_str())
|
||||||
|
// .save_file();
|
||||||
|
// if let Some(_path) = path {
|
||||||
|
// // serialize_values(
|
||||||
|
// // &*metric
|
||||||
|
// // .data
|
||||||
|
// // .read()
|
||||||
|
// // .expect("Values RwLock poisoned"),
|
||||||
|
// // metric,
|
||||||
|
// // path,
|
||||||
|
// // )
|
||||||
|
// // .expect("Could not serialize data");
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
if ui.small_button("×").clicked() {
|
||||||
|
// TODO don't add duplicates
|
||||||
|
app.editing.push(metric.clone().into());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if app.edit {
|
if app.edit {
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use sea_orm::{TransactionTrait, DatabaseConnection, EntityTrait, Condition, ColumnTrait, QueryFilter, Set, QueryOrder, Order, ActiveModelTrait, ActiveValue::NotSet};
|
use sea_orm::{TransactionTrait, DatabaseConnection, EntityTrait, Condition, ColumnTrait, QueryFilter, Set, QueryOrder, Order, ActiveModelTrait, ActiveValue::{NotSet, self}};
|
||||||
use tokio::sync::{watch, mpsc};
|
use tokio::sync::{watch, mpsc};
|
||||||
use tracing::{info, error};
|
use tracing::{info, error};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
@ -11,6 +11,7 @@ pub struct AppStateView {
|
||||||
pub panels: watch::Receiver<Vec<entities::panels::Model>>,
|
pub panels: watch::Receiver<Vec<entities::panels::Model>>,
|
||||||
pub sources: watch::Receiver<Vec<entities::sources::Model>>,
|
pub sources: watch::Receiver<Vec<entities::sources::Model>>,
|
||||||
pub metrics: watch::Receiver<Vec<entities::metrics::Model>>,
|
pub metrics: watch::Receiver<Vec<entities::metrics::Model>>,
|
||||||
|
pub panel_metric: watch::Receiver<Vec<entities::panel_metric::Model>>,
|
||||||
pub points: watch::Receiver<Vec<entities::points::Model>>,
|
pub points: watch::Receiver<Vec<entities::points::Model>>,
|
||||||
pub flush: mpsc::Sender<()>,
|
pub flush: mpsc::Sender<()>,
|
||||||
pub op: mpsc::Sender<BackgroundAction>,
|
pub op: mpsc::Sender<BackgroundAction>,
|
||||||
|
@ -30,6 +31,7 @@ struct AppStateTransmitters {
|
||||||
sources: watch::Sender<Vec<entities::sources::Model>>,
|
sources: watch::Sender<Vec<entities::sources::Model>>,
|
||||||
metrics: watch::Sender<Vec<entities::metrics::Model>>,
|
metrics: watch::Sender<Vec<entities::metrics::Model>>,
|
||||||
points: watch::Sender<Vec<entities::points::Model>>,
|
points: watch::Sender<Vec<entities::points::Model>>,
|
||||||
|
panel_metric: watch::Sender<Vec<entities::panel_metric::Model>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
|
@ -38,6 +40,7 @@ pub struct AppState {
|
||||||
panels: Vec<entities::panels::Model>,
|
panels: Vec<entities::panels::Model>,
|
||||||
sources: Vec<entities::sources::Model>,
|
sources: Vec<entities::sources::Model>,
|
||||||
metrics: Vec<entities::metrics::Model>,
|
metrics: Vec<entities::metrics::Model>,
|
||||||
|
panel_metric: Vec<entities::panel_metric::Model>,
|
||||||
last_refresh: i64,
|
last_refresh: i64,
|
||||||
|
|
||||||
points: VecDeque<entities::points::Model>,
|
points: VecDeque<entities::points::Model>,
|
||||||
|
@ -70,6 +73,7 @@ impl AppState {
|
||||||
let (source_tx, source_rx) = watch::channel(vec![]);
|
let (source_tx, source_rx) = watch::channel(vec![]);
|
||||||
let (metric_tx, metric_rx) = watch::channel(vec![]);
|
let (metric_tx, metric_rx) = watch::channel(vec![]);
|
||||||
let (point_tx, point_rx) = watch::channel(vec![]);
|
let (point_tx, point_rx) = watch::channel(vec![]);
|
||||||
|
let (panel_metric_tx, panel_metric_rx) = watch::channel(vec![]);
|
||||||
// let (view_tx, view_rx) = watch::channel(0);
|
// let (view_tx, view_rx) = watch::channel(0);
|
||||||
let (flush_tx, flush_rx) = mpsc::channel(10);
|
let (flush_tx, flush_rx) = mpsc::channel(10);
|
||||||
let (op_tx, op_rx) = mpsc::channel(100);
|
let (op_tx, op_rx) = mpsc::channel(100);
|
||||||
|
@ -78,6 +82,7 @@ impl AppState {
|
||||||
panels: vec![],
|
panels: vec![],
|
||||||
sources: vec![],
|
sources: vec![],
|
||||||
metrics: vec![],
|
metrics: vec![],
|
||||||
|
panel_metric: vec![],
|
||||||
last_refresh: 0,
|
last_refresh: 0,
|
||||||
points: VecDeque::new(),
|
points: VecDeque::new(),
|
||||||
last_check: 0,
|
last_check: 0,
|
||||||
|
@ -88,6 +93,7 @@ impl AppState {
|
||||||
sources: source_rx,
|
sources: source_rx,
|
||||||
metrics: metric_rx,
|
metrics: metric_rx,
|
||||||
points: point_rx,
|
points: point_rx,
|
||||||
|
panel_metric: panel_metric_rx,
|
||||||
flush: flush_tx,
|
flush: flush_tx,
|
||||||
op: op_tx,
|
op: op_tx,
|
||||||
},
|
},
|
||||||
|
@ -96,6 +102,7 @@ impl AppState {
|
||||||
sources: source_tx,
|
sources: source_tx,
|
||||||
metrics: metric_tx,
|
metrics: metric_tx,
|
||||||
points: point_tx,
|
points: point_tx,
|
||||||
|
panel_metric: panel_metric_tx,
|
||||||
},
|
},
|
||||||
width,
|
width,
|
||||||
interval,
|
interval,
|
||||||
|
@ -130,6 +137,12 @@ impl AppState {
|
||||||
error!(target: "worker", "Could not send metrics update: {:?}", e);
|
error!(target: "worker", "Could not send metrics update: {:?}", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.panel_metric = entities::panel_metric::Entity::find()
|
||||||
|
.all(db).await?;
|
||||||
|
if let Err(e) = self.tx.panel_metric.send(self.panel_metric.clone()) {
|
||||||
|
error!(target: "worker", "Could not send panel-metric update: {:?}", e);
|
||||||
|
}
|
||||||
|
|
||||||
info!(target: "worker", "Updated panels, sources and metrics");
|
info!(target: "worker", "Updated panels, sources and metrics");
|
||||||
self.last_refresh = chrono::Utc::now().timestamp();
|
self.last_refresh = chrono::Utc::now().timestamp();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -164,11 +177,9 @@ impl AppState {
|
||||||
view_size: Set(v.view_size),
|
view_size: Set(v.view_size),
|
||||||
timeserie: Set(v.timeserie),
|
timeserie: Set(v.timeserie),
|
||||||
height: Set(v.height),
|
height: Set(v.height),
|
||||||
limit_view: Set(v.limit_view),
|
|
||||||
position: Set(v.position),
|
position: Set(v.position),
|
||||||
reduce_view: Set(v.reduce_view),
|
reduce_view: Set(v.reduce_view),
|
||||||
view_chunks: Set(v.view_chunks),
|
view_chunks: Set(v.view_chunks),
|
||||||
shift_view: Set(v.shift_view),
|
|
||||||
view_offset: Set(v.view_offset),
|
view_offset: Set(v.view_offset),
|
||||||
average_view: Set(v.average_view),
|
average_view: Set(v.average_view),
|
||||||
}).collect::<Vec<entities::panels::ActiveModel>>()
|
}).collect::<Vec<entities::panels::ActiveModel>>()
|
||||||
|
@ -184,13 +195,35 @@ impl AppState {
|
||||||
self.panels = panels;
|
self.panels = panels;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
BackgroundAction::UpdatePanel { panel } => {
|
BackgroundAction::UpdatePanel { panel, metrics } => {
|
||||||
|
let panel_id = match panel.id {
|
||||||
|
ActiveValue::Unchanged(pid) => Some(pid),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
let op = if panel.id == NotSet { panel.insert(&db) } else { panel.update(&db) };
|
let op = if panel.id == NotSet { panel.insert(&db) } else { panel.update(&db) };
|
||||||
|
// TODO chained if is trashy
|
||||||
if let Err(e) = op.await {
|
if let Err(e) = op.await {
|
||||||
error!(target: "worker", "Could not update panel: {:?}", e);
|
error!(target: "worker", "Could not update panel: {:?}", e);
|
||||||
|
} else {
|
||||||
|
if let Some(panel_id) = panel_id {
|
||||||
|
if let Err(e) = db.transaction::<_, (), sea_orm::DbErr>(|txn| {
|
||||||
|
Box::pin(async move {
|
||||||
|
entities::panel_metric::Entity::delete_many()
|
||||||
|
.filter(
|
||||||
|
Condition::all()
|
||||||
|
.add(entities::panel_metric::Column::PanelId.eq(panel_id))
|
||||||
|
)
|
||||||
|
.exec(txn).await?;
|
||||||
|
entities::panel_metric::Entity::insert_many(metrics).exec(txn).await?;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}).await {
|
||||||
|
error!(target: "worker", "Could not update panels on database: {:?}", e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.view.request_flush().await;
|
self.view.request_flush().await;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
BackgroundAction::UpdateSource { source } => {
|
BackgroundAction::UpdateSource { source } => {
|
||||||
let op = if source.id == NotSet { source.insert(&db) } else { source.update(&db) };
|
let op = if source.id == NotSet { source.insert(&db) } else { source.update(&db) };
|
||||||
|
@ -330,7 +363,7 @@ impl AppState {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum BackgroundAction {
|
pub enum BackgroundAction {
|
||||||
UpdateAllPanels { panels: Vec<entities::panels::Model> },
|
UpdateAllPanels { panels: Vec<entities::panels::Model> },
|
||||||
UpdatePanel { panel : entities::panels::ActiveModel },
|
UpdatePanel { panel : entities::panels::ActiveModel, metrics: Vec<entities::panel_metric::ActiveModel> },
|
||||||
UpdateSource { source: entities::sources::ActiveModel },
|
UpdateSource { source: entities::sources::ActiveModel },
|
||||||
UpdateMetric { metric: entities::metrics::ActiveModel },
|
UpdateMetric { metric: entities::metrics::ActiveModel },
|
||||||
// InsertPanel { panel : entities::panels::ActiveModel },
|
// InsertPanel { panel : entities::panels::ActiveModel },
|
||||||
|
|
Loading…
Reference in a new issue