Skip to content

Commit

Permalink
Dashboard graph configs (#938)
Browse files Browse the repository at this point in the history
enhancement: graph config for tiles in dashboards
add fields -
graph_type: enum - Default (default), Stacked, Percent
orientation: enum - Horizontal (default), Vertical

- migration from version v2 to v3
- fixed migration from v1 to v3 and null check
  • Loading branch information
nikhilsinhaparseable authored Sep 24, 2024
1 parent a5468b0 commit 8e20b31
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 34 deletions.
24 changes: 12 additions & 12 deletions server/src/handlers/http/users/dashboards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,14 @@ pub async fn get(req: HttpRequest) -> Result<impl Responder, DashboardError> {
}

pub async fn post(req: HttpRequest, body: Bytes) -> Result<impl Responder, DashboardError> {
let user_id = get_user_from_request(&req)?;
let mut user_id = get_user_from_request(&req)?;
user_id = get_hash(&user_id);
let mut dashboard: Dashboard = serde_json::from_slice(&body)?;
let dashboard_id = get_hash(Utc::now().timestamp_micros().to_string().as_str());
dashboard.dashboard_id = Some(dashboard_id.clone());
dashboard.version = Some(CURRENT_DASHBOARD_VERSION.to_string());
dashboard.user_id = Some(get_hash(&user_id));

dashboard.user_id = Some(user_id.clone());
for tile in dashboard.tiles.iter_mut() {
tile.tile_id = Some(get_hash(Utc::now().timestamp_micros().to_string().as_str()));
}
Expand All @@ -75,19 +77,19 @@ pub async fn post(req: HttpRequest, body: Bytes) -> Result<impl Responder, Dashb
}

pub async fn update(req: HttpRequest, body: Bytes) -> Result<impl Responder, DashboardError> {
let user_id = get_user_from_request(&req)?;
let mut user_id = get_user_from_request(&req)?;
user_id = get_hash(&user_id);
let dashboard_id = req
.match_info()
.get("dashboard_id")
.ok_or(DashboardError::Metadata("No Dashboard Id Provided"))?;
if DASHBOARDS
.get_dashboard(dashboard_id, &get_hash(&user_id))
.is_none()
{

if DASHBOARDS.get_dashboard(dashboard_id, &user_id).is_none() {
return Err(DashboardError::Metadata("Dashboard does not exist"));
}
let mut dashboard: Dashboard = serde_json::from_slice(&body)?;
dashboard.dashboard_id = Some(dashboard_id.to_string());
dashboard.user_id = Some(user_id.clone());
dashboard.version = Some(CURRENT_DASHBOARD_VERSION.to_string());
for tile in dashboard.tiles.iter_mut() {
if tile.tile_id.is_none() {
Expand All @@ -108,15 +110,13 @@ pub async fn update(req: HttpRequest, body: Bytes) -> Result<impl Responder, Das
}

pub async fn delete(req: HttpRequest) -> Result<HttpResponse, DashboardError> {
let user_id = get_user_from_request(&req)?;
let mut user_id = get_user_from_request(&req)?;
user_id = get_hash(&user_id);
let dashboard_id = req
.match_info()
.get("dashboard_id")
.ok_or(DashboardError::Metadata("No Dashboard Id Provided"))?;
if DASHBOARDS
.get_dashboard(dashboard_id, &get_hash(&user_id))
.is_none()
{
if DASHBOARDS.get_dashboard(dashboard_id, &user_id).is_none() {
return Err(DashboardError::Metadata("Dashboard does not exist"));
}
let path = dashboard_path(&user_id, &format!("{}.json", dashboard_id));
Expand Down
20 changes: 12 additions & 8 deletions server/src/handlers/http/users/filters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,12 @@ pub async fn get(req: HttpRequest) -> Result<impl Responder, FiltersError> {
}

pub async fn post(req: HttpRequest, body: Bytes) -> Result<impl Responder, FiltersError> {
let user_id = get_user_from_request(&req)?;
let mut user_id = get_user_from_request(&req)?;
user_id = get_hash(&user_id);
let mut filter: Filter = serde_json::from_slice(&body)?;
let filter_id = get_hash(Utc::now().timestamp_micros().to_string().as_str());
filter.filter_id = Some(filter_id.clone());
filter.user_id = Some(get_hash(&user_id));
filter.user_id = Some(user_id.clone());
filter.version = Some(CURRENT_FILTER_VERSION.to_string());
FILTERS.update(&filter);

Expand All @@ -71,17 +72,19 @@ pub async fn post(req: HttpRequest, body: Bytes) -> Result<impl Responder, Filte
Ok((web::Json(filter), StatusCode::OK))
}

pub async fn update(req: HttpRequest, body: Bytes) -> Result<HttpResponse, FiltersError> {
let user_id = get_user_from_request(&req)?;
pub async fn update(req: HttpRequest, body: Bytes) -> Result<impl Responder, FiltersError> {
let mut user_id = get_user_from_request(&req)?;
user_id = get_hash(&user_id);
let filter_id = req
.match_info()
.get("filter_id")
.ok_or(FiltersError::Metadata("No Filter Id Provided"))?;
if FILTERS.get_filter(filter_id, &get_hash(&user_id)).is_none() {
if FILTERS.get_filter(filter_id, &user_id).is_none() {
return Err(FiltersError::Metadata("Filter does not exist"));
}
let mut filter: Filter = serde_json::from_slice(&body)?;
filter.filter_id = Some(filter_id.to_string());
filter.user_id = Some(user_id.clone());
filter.version = Some(CURRENT_FILTER_VERSION.to_string());
FILTERS.update(&filter);

Expand All @@ -95,17 +98,18 @@ pub async fn update(req: HttpRequest, body: Bytes) -> Result<HttpResponse, Filte
let filter_bytes = serde_json::to_vec(&filter)?;
store.put_object(&path, Bytes::from(filter_bytes)).await?;

Ok(HttpResponse::Ok().finish())
Ok((web::Json(filter), StatusCode::OK))
}

pub async fn delete(req: HttpRequest) -> Result<HttpResponse, FiltersError> {
let user_id = get_user_from_request(&req)?;
let mut user_id = get_user_from_request(&req)?;
user_id = get_hash(&user_id);
let filter_id = req
.match_info()
.get("filter_id")
.ok_or(FiltersError::Metadata("No Filter Id Provided"))?;
let filter = FILTERS
.get_filter(filter_id, &get_hash(&user_id))
.get_filter(filter_id, &user_id)
.ok_or(FiltersError::Metadata("Filter does not exist"))?;

let path = filter_path(
Expand Down
118 changes: 108 additions & 10 deletions server/src/users/dashboards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use crate::{
use super::TimeFilter;

pub static DASHBOARDS: Lazy<Dashboards> = Lazy::new(Dashboards::default);
pub const CURRENT_DASHBOARD_VERSION: &str = "v2";
pub const CURRENT_DASHBOARD_VERSION: &str = "v3";

#[derive(Debug, Serialize, Deserialize, Default, Clone)]
pub struct Tiles {
Expand Down Expand Up @@ -62,6 +62,25 @@ pub struct CircularChartConfig {
pub struct GraphConfig {
x_key: String,
y_keys: Vec<String>,
graph_type: Option<GraphType>,
orientation: Option<Orientation>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone)]
#[serde(rename_all = "lowercase")]
pub enum GraphType {
#[default]
Default,
Stacked,
Percent,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone)]
#[serde(rename_all = "lowercase")]
pub enum Orientation {
#[default]
Horizontal,
Vertical,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone)]
Expand Down Expand Up @@ -96,32 +115,62 @@ impl Dashboards {
let mut this = vec![];
let store = CONFIG.storage().get_object_store();
let dashboards = store.get_all_dashboards().await.unwrap_or_default();

for dashboard in dashboards {
if dashboard.is_empty() {
continue;
}
let mut dashboard_value = serde_json::from_slice::<serde_json::Value>(&dashboard)?;
if let Some(meta) = dashboard_value.clone().as_object() {
let version = meta.get("version").and_then(|version| version.as_str());
let user_id = meta.get("user_id").and_then(|user_id| user_id.as_str());
let dashboard_id = meta
.get("dashboard_id")
.and_then(|dashboard_id| dashboard_id.as_str());

if version == Some("v1") {
dashboard_value = migrate_v1_v2(dashboard_value);
if let (Some(user_id), Some(dashboard_id)) = (user_id, dashboard_id) {
let path = dashboard_path(user_id, &format!("{}.json", dashboard_id));
match version {
Some("v1") => {
dashboard_value = migrate_v1_v2(dashboard_value);
dashboard_value = migrate_v2_v3(dashboard_value);
let user_id = dashboard_value
.as_object()
.unwrap()
.get("user_id")
.and_then(|user_id| user_id.as_str());
let path = dashboard_path(
user_id.unwrap(),
&format!("{}.json", dashboard_id.unwrap()),
);
let dashboard_bytes = to_bytes(&dashboard_value);
store.put_object(&path, dashboard_bytes.clone()).await?;
if let Ok(dashboard) = serde_json::from_slice::<Dashboard>(&dashboard_bytes)
{
this.retain(|d: &Dashboard| d.dashboard_id != dashboard.dashboard_id);
this.push(dashboard);
}
}
Some("v2") => {
dashboard_value = migrate_v2_v3(dashboard_value);
let user_id = dashboard_value
.as_object()
.unwrap()
.get("user_id")
.and_then(|user_id| user_id.as_str());
let path = dashboard_path(
user_id.unwrap(),
&format!("{}.json", dashboard_id.unwrap()),
);
let dashboard_bytes = to_bytes(&dashboard_value);
store.put_object(&path, dashboard_bytes.clone()).await?;
if let Ok(dashboard) = serde_json::from_slice::<Dashboard>(&dashboard_bytes)
{
this.retain(|d| d.dashboard_id != dashboard.dashboard_id);
this.push(dashboard);
}
}
_ => {
if let Ok(dashboard) = serde_json::from_slice::<Dashboard>(&dashboard) {
this.retain(|d| d.dashboard_id != dashboard.dashboard_id);
this.push(dashboard);
}
}
} else if let Ok(dashboard) = serde_json::from_slice::<Dashboard>(&dashboard) {
this.push(dashboard);
}
}
}
Expand Down Expand Up @@ -176,6 +225,55 @@ fn migrate_v1_v2(mut dashboard_meta: Value) -> Value {
"version".to_owned(),
Value::String(CURRENT_DASHBOARD_VERSION.into()),
);
let tiles = dashboard_meta_map
.get_mut("tiles")
.unwrap()
.as_array_mut()
.unwrap();
for tile in tiles.iter_mut() {
let tile_map = tile.as_object_mut().unwrap();
let visualization = tile_map
.get_mut("visualization")
.unwrap()
.as_object_mut()
.unwrap();
visualization.insert("tick_config".to_owned(), Value::Array(vec![]));
}

dashboard_meta
}

fn migrate_v2_v3(mut dashboard_meta: Value) -> Value {
let dashboard_meta_map = dashboard_meta.as_object_mut().unwrap();

dashboard_meta_map.insert(
"version".to_owned(),
Value::String(CURRENT_DASHBOARD_VERSION.into()),
);
let tiles = dashboard_meta_map
.get_mut("tiles")
.unwrap()
.as_array_mut()
.unwrap();
for tile in tiles {
let tile_map = tile.as_object_mut().unwrap();
let visualization = tile_map
.get_mut("visualization")
.unwrap()
.as_object_mut()
.unwrap();
if visualization.get("graph_config").is_some()
&& !visualization.get("graph_config").unwrap().is_null()
{
let graph_config = visualization
.get_mut("graph_config")
.unwrap()
.as_object_mut()
.unwrap();
graph_config.insert("orientation".to_owned(), Value::String("horizontal".into()));
graph_config.insert("graph_type".to_owned(), Value::String("default".into()));
}
}

dashboard_meta
}
24 changes: 20 additions & 4 deletions server/src/users/filters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,32 @@ impl Filters {
if let (Some(user_id), Some(stream_name), Some(filter_id)) =
(user_id, stream_name, filter_id)
{
let path =
filter_path(user_id, stream_name, &format!("{}.json", filter_id));
let path = filter_path(
&get_hash(user_id),
stream_name,
&format!("{}.json", filter_id),
);
let filter_bytes = to_bytes(&filter_value);
store.put_object(&path, filter_bytes.clone()).await?;
if let Ok(filter) = serde_json::from_slice::<Filter>(&filter_bytes) {
this.retain(|f: &Filter| f.filter_id != filter.filter_id);
this.push(filter);
}
}
} else if let Ok(filter) = serde_json::from_slice::<Filter>(&filter) {
this.push(filter);
} else if let (Some(user_id), Some(stream_name), Some(filter_id)) =
(user_id, stream_name, filter_id)
{
let path = filter_path(
&get_hash(user_id),
stream_name,
&format!("{}.json", filter_id),
);
let filter_bytes = to_bytes(&filter_value);
store.put_object(&path, filter_bytes.clone()).await?;
if let Ok(filter) = serde_json::from_slice::<Filter>(&filter) {
this.retain(|f: &Filter| f.filter_id != filter.filter_id);
this.push(filter);
}
}
}
}
Expand Down

0 comments on commit 8e20b31

Please sign in to comment.