zephyr-sdk 0.2.4

Rust SDK for building Zephyr programs.
Documentation
#![allow(missing_docs)]

use charming_fork_zephyr::{
    component::{Axis, Legend},
    element::{AreaStyle, AxisType, Color, ColorStop, Tooltip, Trigger},
    series::{Bar, Line},
    Chart,
};
use serde::Serialize;
pub use table::Table;

mod table;

#[derive(Serialize, Default)]
pub struct Dashboard {
    title: Option<Title>,
    description: Option<String>,
    data: Vec<DashboardEntry>,
}

#[derive(Serialize)]
pub enum ChartType {
    #[serde(rename = "chart")]
    Chart,
    #[serde(rename = "table")]
    Table,
}

#[derive(Serialize)]
pub enum ChartTypeWrapped {
    #[serde(rename = "inner")]
    Chart(Chart),

    #[serde(rename = "inner")]
    Table(Table),
}

#[derive(Serialize, Default)]
struct Title {
    text: String,
}

#[derive(Serialize, Default)]
pub struct DashboardEntry {
    #[serde(rename = "type")]
    chart_type: Option<ChartType>,
    title: Title,
    height: String,
    width: String,
    #[serde(flatten)]
    inner: Option<ChartTypeWrapped>,
}

impl Dashboard {
    pub fn title(mut self, title: &impl ToString) -> Self {
        self.title = Some(Title {
            text: title.to_string(),
        });
        self
    }

    pub fn description(mut self, description: &impl ToString) -> Self {
        self.description = Some(description.to_string());
        self
    }

    pub fn entry(mut self, entry: DashboardEntry) -> Self {
        self.data.push(entry);
        self
    }

    pub fn new() -> Self {
        Self::default()
    }
}

impl DashboardEntry {
    pub fn new() -> Self {
        Self {
            chart_type: None,
            title: Title {
                text: String::new(),
            },
            height: String::from("300px"),
            width: String::from("1000px"),
            inner: None,
        }
    }

    pub fn title(mut self, title: impl ToString) -> Self {
        self.title = Title {
            text: title.to_string(),
        };
        self
    }

    pub fn chart(mut self, chart: Chart) -> Self {
        self.chart_type = Some(ChartType::Chart);
        self.inner = Some(ChartTypeWrapped::Chart(chart));

        self
    }

    pub fn table(mut self, table: Table) -> Self {
        self.chart_type = Some(ChartType::Table);
        self.inner = Some(ChartTypeWrapped::Table(table));

        self
    }
}

pub struct DashboardBuilder {
    dashboard: Dashboard,
}

impl DashboardBuilder {
    pub fn new(title: &str, desc: &str) -> Self {
        let dashboard = Dashboard::new();
        let dashboard = dashboard.title(&title.to_string());
        let dashboard = dashboard.description(&desc.to_string());

        Self { dashboard }
    }

    pub fn add_table(mut self, title: &str, columns: Vec<String>, rows: Vec<Vec<String>>) -> Self {
        let mut table = Table::new().columns(columns);
        for row in rows {
            table = table.row(row);
        }
        self.dashboard = self
            .dashboard
            .entry(DashboardEntry::new().title(title).table(table));
        self
    }

    pub fn add_bar_chart(
        mut self,
        title: &str,
        hover_title: &str,
        categories: Vec<&str>,
        data: Vec<i64>,
    ) -> Self {
        let chart = Chart::new()
            .legend(Legend::new().show(true))
            .tooltip(Tooltip::new().trigger(Trigger::Axis))
            .x_axis(Axis::new().type_(AxisType::Category).data(categories))
            .y_axis(Axis::new().type_(AxisType::Value))
            .series(Bar::new().name(hover_title).data(data));

        self.dashboard = self
            .dashboard
            .entry(DashboardEntry::new().title(title).chart(chart));
        self
    }

    pub fn add_line_chart(
        mut self,
        title: &str,
        categories: Vec<String>,
        series: Vec<(&str, Vec<i64>)>,
    ) -> Self {
        let mut chart = Chart::new()
            .legend(Legend::new().show(true).left("150px").top("3%"))
            .tooltip(Tooltip::new().trigger(Trigger::Axis))
            .x_axis(Axis::new().type_(AxisType::Category).data(categories))
            .y_axis(Axis::new().type_(AxisType::Value));

        for (name, data) in series {
            chart = chart.series(Line::new().name(name).data(data).area_style(
                AreaStyle::new().color(Color::LinearGradient {
                    x: 0,
                    y: 0,
                    x2: 0,
                    y2: 1,
                    color_stops: vec![
                        ColorStop::new(0, "rgb(84, 112, 198)"),
                        ColorStop::new(1, "rgb(79, 209, 242)"),
                    ],
                }),
            ));
        }

        self.dashboard = self
            .dashboard
            .entry(DashboardEntry::new().title(title).chart(chart));
        self
    }

    pub fn build(self) -> Dashboard {
        self.dashboard
    }
}