Skip to content

Commit 8e20b31

Browse files
Dashboard graph configs (#938)
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
1 parent a5468b0 commit 8e20b31

File tree

4 files changed

+152
-34
lines changed

4 files changed

+152
-34
lines changed

server/src/handlers/http/users/dashboards.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,14 @@ pub async fn get(req: HttpRequest) -> Result<impl Responder, DashboardError> {
5252
}
5353

5454
pub async fn post(req: HttpRequest, body: Bytes) -> Result<impl Responder, DashboardError> {
55-
let user_id = get_user_from_request(&req)?;
55+
let mut user_id = get_user_from_request(&req)?;
56+
user_id = get_hash(&user_id);
5657
let mut dashboard: Dashboard = serde_json::from_slice(&body)?;
5758
let dashboard_id = get_hash(Utc::now().timestamp_micros().to_string().as_str());
5859
dashboard.dashboard_id = Some(dashboard_id.clone());
5960
dashboard.version = Some(CURRENT_DASHBOARD_VERSION.to_string());
60-
dashboard.user_id = Some(get_hash(&user_id));
61+
62+
dashboard.user_id = Some(user_id.clone());
6163
for tile in dashboard.tiles.iter_mut() {
6264
tile.tile_id = Some(get_hash(Utc::now().timestamp_micros().to_string().as_str()));
6365
}
@@ -75,19 +77,19 @@ pub async fn post(req: HttpRequest, body: Bytes) -> Result<impl Responder, Dashb
7577
}
7678

7779
pub async fn update(req: HttpRequest, body: Bytes) -> Result<impl Responder, DashboardError> {
78-
let user_id = get_user_from_request(&req)?;
80+
let mut user_id = get_user_from_request(&req)?;
81+
user_id = get_hash(&user_id);
7982
let dashboard_id = req
8083
.match_info()
8184
.get("dashboard_id")
8285
.ok_or(DashboardError::Metadata("No Dashboard Id Provided"))?;
83-
if DASHBOARDS
84-
.get_dashboard(dashboard_id, &get_hash(&user_id))
85-
.is_none()
86-
{
86+
87+
if DASHBOARDS.get_dashboard(dashboard_id, &user_id).is_none() {
8788
return Err(DashboardError::Metadata("Dashboard does not exist"));
8889
}
8990
let mut dashboard: Dashboard = serde_json::from_slice(&body)?;
9091
dashboard.dashboard_id = Some(dashboard_id.to_string());
92+
dashboard.user_id = Some(user_id.clone());
9193
dashboard.version = Some(CURRENT_DASHBOARD_VERSION.to_string());
9294
for tile in dashboard.tiles.iter_mut() {
9395
if tile.tile_id.is_none() {
@@ -108,15 +110,13 @@ pub async fn update(req: HttpRequest, body: Bytes) -> Result<impl Responder, Das
108110
}
109111

110112
pub async fn delete(req: HttpRequest) -> Result<HttpResponse, DashboardError> {
111-
let user_id = get_user_from_request(&req)?;
113+
let mut user_id = get_user_from_request(&req)?;
114+
user_id = get_hash(&user_id);
112115
let dashboard_id = req
113116
.match_info()
114117
.get("dashboard_id")
115118
.ok_or(DashboardError::Metadata("No Dashboard Id Provided"))?;
116-
if DASHBOARDS
117-
.get_dashboard(dashboard_id, &get_hash(&user_id))
118-
.is_none()
119-
{
119+
if DASHBOARDS.get_dashboard(dashboard_id, &user_id).is_none() {
120120
return Err(DashboardError::Metadata("Dashboard does not exist"));
121121
}
122122
let path = dashboard_path(&user_id, &format!("{}.json", dashboard_id));

server/src/handlers/http/users/filters.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,12 @@ pub async fn get(req: HttpRequest) -> Result<impl Responder, FiltersError> {
5050
}
5151

5252
pub async fn post(req: HttpRequest, body: Bytes) -> Result<impl Responder, FiltersError> {
53-
let user_id = get_user_from_request(&req)?;
53+
let mut user_id = get_user_from_request(&req)?;
54+
user_id = get_hash(&user_id);
5455
let mut filter: Filter = serde_json::from_slice(&body)?;
5556
let filter_id = get_hash(Utc::now().timestamp_micros().to_string().as_str());
5657
filter.filter_id = Some(filter_id.clone());
57-
filter.user_id = Some(get_hash(&user_id));
58+
filter.user_id = Some(user_id.clone());
5859
filter.version = Some(CURRENT_FILTER_VERSION.to_string());
5960
FILTERS.update(&filter);
6061

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

74-
pub async fn update(req: HttpRequest, body: Bytes) -> Result<HttpResponse, FiltersError> {
75-
let user_id = get_user_from_request(&req)?;
75+
pub async fn update(req: HttpRequest, body: Bytes) -> Result<impl Responder, FiltersError> {
76+
let mut user_id = get_user_from_request(&req)?;
77+
user_id = get_hash(&user_id);
7678
let filter_id = req
7779
.match_info()
7880
.get("filter_id")
7981
.ok_or(FiltersError::Metadata("No Filter Id Provided"))?;
80-
if FILTERS.get_filter(filter_id, &get_hash(&user_id)).is_none() {
82+
if FILTERS.get_filter(filter_id, &user_id).is_none() {
8183
return Err(FiltersError::Metadata("Filter does not exist"));
8284
}
8385
let mut filter: Filter = serde_json::from_slice(&body)?;
8486
filter.filter_id = Some(filter_id.to_string());
87+
filter.user_id = Some(user_id.clone());
8588
filter.version = Some(CURRENT_FILTER_VERSION.to_string());
8689
FILTERS.update(&filter);
8790

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

98-
Ok(HttpResponse::Ok().finish())
101+
Ok((web::Json(filter), StatusCode::OK))
99102
}
100103

101104
pub async fn delete(req: HttpRequest) -> Result<HttpResponse, FiltersError> {
102-
let user_id = get_user_from_request(&req)?;
105+
let mut user_id = get_user_from_request(&req)?;
106+
user_id = get_hash(&user_id);
103107
let filter_id = req
104108
.match_info()
105109
.get("filter_id")
106110
.ok_or(FiltersError::Metadata("No Filter Id Provided"))?;
107111
let filter = FILTERS
108-
.get_filter(filter_id, &get_hash(&user_id))
112+
.get_filter(filter_id, &user_id)
109113
.ok_or(FiltersError::Metadata("Filter does not exist"))?;
110114

111115
let path = filter_path(

server/src/users/dashboards.rs

Lines changed: 108 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use crate::{
3030
use super::TimeFilter;
3131

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

3535
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
3636
pub struct Tiles {
@@ -62,6 +62,25 @@ pub struct CircularChartConfig {
6262
pub struct GraphConfig {
6363
x_key: String,
6464
y_keys: Vec<String>,
65+
graph_type: Option<GraphType>,
66+
orientation: Option<Orientation>,
67+
}
68+
69+
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
70+
#[serde(rename_all = "lowercase")]
71+
pub enum GraphType {
72+
#[default]
73+
Default,
74+
Stacked,
75+
Percent,
76+
}
77+
78+
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
79+
#[serde(rename_all = "lowercase")]
80+
pub enum Orientation {
81+
#[default]
82+
Horizontal,
83+
Vertical,
6584
}
6685

6786
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
@@ -96,32 +115,62 @@ impl Dashboards {
96115
let mut this = vec![];
97116
let store = CONFIG.storage().get_object_store();
98117
let dashboards = store.get_all_dashboards().await.unwrap_or_default();
99-
100118
for dashboard in dashboards {
101119
if dashboard.is_empty() {
102120
continue;
103121
}
104122
let mut dashboard_value = serde_json::from_slice::<serde_json::Value>(&dashboard)?;
105123
if let Some(meta) = dashboard_value.clone().as_object() {
106124
let version = meta.get("version").and_then(|version| version.as_str());
107-
let user_id = meta.get("user_id").and_then(|user_id| user_id.as_str());
108125
let dashboard_id = meta
109126
.get("dashboard_id")
110127
.and_then(|dashboard_id| dashboard_id.as_str());
111-
112-
if version == Some("v1") {
113-
dashboard_value = migrate_v1_v2(dashboard_value);
114-
if let (Some(user_id), Some(dashboard_id)) = (user_id, dashboard_id) {
115-
let path = dashboard_path(user_id, &format!("{}.json", dashboard_id));
128+
match version {
129+
Some("v1") => {
130+
dashboard_value = migrate_v1_v2(dashboard_value);
131+
dashboard_value = migrate_v2_v3(dashboard_value);
132+
let user_id = dashboard_value
133+
.as_object()
134+
.unwrap()
135+
.get("user_id")
136+
.and_then(|user_id| user_id.as_str());
137+
let path = dashboard_path(
138+
user_id.unwrap(),
139+
&format!("{}.json", dashboard_id.unwrap()),
140+
);
116141
let dashboard_bytes = to_bytes(&dashboard_value);
117142
store.put_object(&path, dashboard_bytes.clone()).await?;
118143
if let Ok(dashboard) = serde_json::from_slice::<Dashboard>(&dashboard_bytes)
119144
{
145+
this.retain(|d: &Dashboard| d.dashboard_id != dashboard.dashboard_id);
146+
this.push(dashboard);
147+
}
148+
}
149+
Some("v2") => {
150+
dashboard_value = migrate_v2_v3(dashboard_value);
151+
let user_id = dashboard_value
152+
.as_object()
153+
.unwrap()
154+
.get("user_id")
155+
.and_then(|user_id| user_id.as_str());
156+
let path = dashboard_path(
157+
user_id.unwrap(),
158+
&format!("{}.json", dashboard_id.unwrap()),
159+
);
160+
let dashboard_bytes = to_bytes(&dashboard_value);
161+
store.put_object(&path, dashboard_bytes.clone()).await?;
162+
if let Ok(dashboard) = serde_json::from_slice::<Dashboard>(&dashboard_bytes)
163+
{
164+
this.retain(|d| d.dashboard_id != dashboard.dashboard_id);
165+
this.push(dashboard);
166+
}
167+
}
168+
_ => {
169+
if let Ok(dashboard) = serde_json::from_slice::<Dashboard>(&dashboard) {
170+
this.retain(|d| d.dashboard_id != dashboard.dashboard_id);
120171
this.push(dashboard);
121172
}
122173
}
123-
} else if let Ok(dashboard) = serde_json::from_slice::<Dashboard>(&dashboard) {
124-
this.push(dashboard);
125174
}
126175
}
127176
}
@@ -176,6 +225,55 @@ fn migrate_v1_v2(mut dashboard_meta: Value) -> Value {
176225
"version".to_owned(),
177226
Value::String(CURRENT_DASHBOARD_VERSION.into()),
178227
);
228+
let tiles = dashboard_meta_map
229+
.get_mut("tiles")
230+
.unwrap()
231+
.as_array_mut()
232+
.unwrap();
233+
for tile in tiles.iter_mut() {
234+
let tile_map = tile.as_object_mut().unwrap();
235+
let visualization = tile_map
236+
.get_mut("visualization")
237+
.unwrap()
238+
.as_object_mut()
239+
.unwrap();
240+
visualization.insert("tick_config".to_owned(), Value::Array(vec![]));
241+
}
242+
243+
dashboard_meta
244+
}
245+
246+
fn migrate_v2_v3(mut dashboard_meta: Value) -> Value {
247+
let dashboard_meta_map = dashboard_meta.as_object_mut().unwrap();
248+
249+
dashboard_meta_map.insert(
250+
"version".to_owned(),
251+
Value::String(CURRENT_DASHBOARD_VERSION.into()),
252+
);
253+
let tiles = dashboard_meta_map
254+
.get_mut("tiles")
255+
.unwrap()
256+
.as_array_mut()
257+
.unwrap();
258+
for tile in tiles {
259+
let tile_map = tile.as_object_mut().unwrap();
260+
let visualization = tile_map
261+
.get_mut("visualization")
262+
.unwrap()
263+
.as_object_mut()
264+
.unwrap();
265+
if visualization.get("graph_config").is_some()
266+
&& !visualization.get("graph_config").unwrap().is_null()
267+
{
268+
let graph_config = visualization
269+
.get_mut("graph_config")
270+
.unwrap()
271+
.as_object_mut()
272+
.unwrap();
273+
graph_config.insert("orientation".to_owned(), Value::String("horizontal".into()));
274+
graph_config.insert("graph_type".to_owned(), Value::String("default".into()));
275+
}
276+
}
179277

180278
dashboard_meta
181279
}

server/src/users/filters.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,32 @@ impl Filters {
9999
if let (Some(user_id), Some(stream_name), Some(filter_id)) =
100100
(user_id, stream_name, filter_id)
101101
{
102-
let path =
103-
filter_path(user_id, stream_name, &format!("{}.json", filter_id));
102+
let path = filter_path(
103+
&get_hash(user_id),
104+
stream_name,
105+
&format!("{}.json", filter_id),
106+
);
104107
let filter_bytes = to_bytes(&filter_value);
105108
store.put_object(&path, filter_bytes.clone()).await?;
106109
if let Ok(filter) = serde_json::from_slice::<Filter>(&filter_bytes) {
110+
this.retain(|f: &Filter| f.filter_id != filter.filter_id);
107111
this.push(filter);
108112
}
109113
}
110-
} else if let Ok(filter) = serde_json::from_slice::<Filter>(&filter) {
111-
this.push(filter);
114+
} else if let (Some(user_id), Some(stream_name), Some(filter_id)) =
115+
(user_id, stream_name, filter_id)
116+
{
117+
let path = filter_path(
118+
&get_hash(user_id),
119+
stream_name,
120+
&format!("{}.json", filter_id),
121+
);
122+
let filter_bytes = to_bytes(&filter_value);
123+
store.put_object(&path, filter_bytes.clone()).await?;
124+
if let Ok(filter) = serde_json::from_slice::<Filter>(&filter) {
125+
this.retain(|f: &Filter| f.filter_id != filter.filter_id);
126+
this.push(filter);
127+
}
112128
}
113129
}
114130
}

0 commit comments

Comments
 (0)