mirror of https://github.com/buster-so/buster.git
BUS-1453: Implement color fallback logic for metric handlers
Co-Authored-By: Dallin Bentley <dallinbentley98@gmail.com>
This commit is contained in:
parent
2de702f425
commit
d5beb5edeb
|
@ -0,0 +1,125 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use database::pool::get_pg_pool;
|
||||
use diesel::{ExpressionMethods, QueryDsl};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use serde_json::Value;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub const DEFAULT_COLOR_PALETTE: [&str; 10] = [
|
||||
"#B399FD", "#FC8497", "#FBBC30", "#279EFF",
|
||||
"#E83562", "#41F8FF", "#F3864F", "#C82184",
|
||||
"#31FCB4", "#E83562"
|
||||
];
|
||||
|
||||
pub async fn get_organization_color_palette(organization_id: &Uuid) -> Result<Option<Vec<String>>> {
|
||||
let mut conn = get_pg_pool().get().await?;
|
||||
|
||||
let config_result = diesel::sql_query(
|
||||
"SELECT config FROM users
|
||||
INNER JOIN users_to_organizations ON users.id = users_to_organizations.user_id
|
||||
WHERE users_to_organizations.organization_id = $1
|
||||
AND users_to_organizations.deleted_at IS NULL
|
||||
LIMIT 1"
|
||||
)
|
||||
.bind::<diesel::sql_types::Uuid, _>(organization_id)
|
||||
.get_result::<ConfigResult>(&mut conn)
|
||||
.await;
|
||||
|
||||
match config_result {
|
||||
Ok(config_row) => {
|
||||
if let Some(config_value) = config_row.config {
|
||||
if let Some(selected_palette) = config_value.get("selectedDictionaryPalette") {
|
||||
if let Some(colors) = selected_palette.get("colors") {
|
||||
if let Some(colors_array) = colors.as_array() {
|
||||
let palette: Vec<String> = colors_array
|
||||
.iter()
|
||||
.filter_map(|c| c.as_str().map(|s| s.to_string()))
|
||||
.collect();
|
||||
|
||||
if !palette.is_empty() {
|
||||
return Ok(Some(palette));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(last_used) = config_value.get("last_used_color_palette") {
|
||||
if let Some(colors_array) = last_used.as_array() {
|
||||
let palette: Vec<String> = colors_array
|
||||
.iter()
|
||||
.filter_map(|c| c.as_str().map(|s| s.to_string()))
|
||||
.collect();
|
||||
|
||||
if !palette.is_empty() {
|
||||
return Ok(Some(palette));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
},
|
||||
Err(_) => {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_default_color_palette() -> Vec<String> {
|
||||
DEFAULT_COLOR_PALETTE.iter().map(|&s| s.to_string()).collect()
|
||||
}
|
||||
|
||||
pub async fn apply_color_fallback(
|
||||
chart_config: &mut database::types::ChartConfig,
|
||||
organization_id: &Uuid,
|
||||
) -> Result<()> {
|
||||
let colors_already_set = match chart_config {
|
||||
database::types::ChartConfig::Bar(config) => config.base.colors.is_some(),
|
||||
database::types::ChartConfig::Line(config) => config.base.colors.is_some(),
|
||||
database::types::ChartConfig::Scatter(config) => config.base.colors.is_some(),
|
||||
database::types::ChartConfig::Pie(config) => config.base.colors.is_some(),
|
||||
database::types::ChartConfig::Combo(config) => config.base.colors.is_some(),
|
||||
database::types::ChartConfig::Metric(_) => true, // Metric doesn't use colors
|
||||
database::types::ChartConfig::Table(_) => true, // Table doesn't use colors
|
||||
};
|
||||
|
||||
if colors_already_set {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let org_palette = get_organization_color_palette(organization_id).await?;
|
||||
|
||||
let palette = if let Some(palette) = org_palette {
|
||||
palette
|
||||
} else {
|
||||
get_default_color_palette()
|
||||
};
|
||||
|
||||
match chart_config {
|
||||
database::types::ChartConfig::Bar(config) => {
|
||||
config.base.colors = Some(palette);
|
||||
},
|
||||
database::types::ChartConfig::Line(config) => {
|
||||
config.base.colors = Some(palette);
|
||||
},
|
||||
database::types::ChartConfig::Scatter(config) => {
|
||||
config.base.colors = Some(palette);
|
||||
},
|
||||
database::types::ChartConfig::Pie(config) => {
|
||||
config.base.colors = Some(palette);
|
||||
},
|
||||
database::types::ChartConfig::Combo(config) => {
|
||||
config.base.colors = Some(palette);
|
||||
},
|
||||
database::types::ChartConfig::Metric(_) => {}, // No colors to set
|
||||
database::types::ChartConfig::Table(_) => {}, // No colors to set
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(diesel::QueryableByName, Debug)]
|
||||
struct ConfigResult {
|
||||
#[diesel(sql_type = diesel::sql_types::Jsonb)]
|
||||
config: Option<Value>,
|
||||
}
|
|
@ -9,6 +9,7 @@ use serde_yaml;
|
|||
use sharing::asset_access_checks::check_metric_collection_access;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::metrics::color_palette_helpers::apply_color_fallback;
|
||||
use crate::metrics::types::{AssociatedCollection, AssociatedDashboard, BusterMetric, BusterShareIndividual, Dataset};
|
||||
use crate::utils::workspace::count_workspace_members;
|
||||
use database::enums::{AssetPermissionRole, AssetType, IdentityType};
|
||||
|
@ -448,6 +449,11 @@ pub async fn get_metric_for_dashboard_handler(
|
|||
}
|
||||
};
|
||||
|
||||
let mut final_chart_config = resolved_chart_config.clone();
|
||||
if let Err(e) = apply_color_fallback(&mut final_chart_config, &metric_file.organization_id).await {
|
||||
tracing::warn!(metric_id = %metric_id, error = %e, "Failed to apply color fallback logic, continuing with original chart config");
|
||||
}
|
||||
|
||||
// Get workspace sharing enabled by email if set
|
||||
let workspace_sharing_enabled_by = if let Some(enabled_by_id) = metric_file.workspace_sharing_enabled_by {
|
||||
users::table
|
||||
|
@ -488,7 +494,7 @@ pub async fn get_metric_for_dashboard_handler(
|
|||
datasets,
|
||||
data_source_id: metric_file.data_source_id,
|
||||
error: None,
|
||||
chart_config: Some(resolved_chart_config),
|
||||
chart_config: Some(final_chart_config), // Use chart config with color fallback applied
|
||||
data_metadata,
|
||||
status: metric_file.verification,
|
||||
evaluation_score,
|
||||
|
@ -517,4 +523,4 @@ pub async fn get_metric_for_dashboard_handler(
|
|||
// Workspace member count
|
||||
workspace_member_count,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ use serde_yaml;
|
|||
use sharing::asset_access_checks::check_metric_collection_access;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::metrics::color_palette_helpers::apply_color_fallback;
|
||||
use crate::metrics::types::{AssociatedCollection, AssociatedDashboard, BusterMetric, Dataset};
|
||||
use crate::utils::workspace::count_workspace_members;
|
||||
use database::enums::{AssetPermissionRole, AssetType, IdentityType};
|
||||
|
@ -304,6 +305,11 @@ pub async fn get_metric_handler(
|
|||
tracing::debug!(metric_id = %metric_id, latest_version = resolved_version_num, "Determined latest version number");
|
||||
}
|
||||
|
||||
let mut final_chart_config = resolved_chart_config.clone();
|
||||
if let Err(e) = apply_color_fallback(&mut final_chart_config, &metric_file.organization_id).await {
|
||||
tracing::warn!(metric_id = %metric_id, error = %e, "Failed to apply color fallback logic, continuing with original chart config");
|
||||
}
|
||||
|
||||
// Convert the selected content to pretty YAML for the 'file' field
|
||||
let file = match serde_yaml::to_string(&resolved_content_for_yaml) {
|
||||
Ok(yaml) => yaml,
|
||||
|
@ -494,7 +500,7 @@ pub async fn get_metric_handler(
|
|||
datasets, // Fetched based on resolved_dataset_ids (for display purposes only)
|
||||
data_source_id: metric_file.data_source_id, // Use canonical ID (Uuid) from main record
|
||||
error: None, // Assume ok
|
||||
chart_config: Some(resolved_chart_config), // Use resolved chart config
|
||||
chart_config: Some(final_chart_config), // Use chart config with color fallback applied
|
||||
data_metadata, // Not versioned
|
||||
status: metric_file.verification, // Not versioned
|
||||
evaluation_score, // Not versioned
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
pub mod bulk_update_metrics_handler;
|
||||
pub mod color_palette_helpers;
|
||||
pub mod delete_metric_handler;
|
||||
pub mod get_metric_data_handler;
|
||||
pub mod get_metric_handler;
|
||||
|
|
Loading…
Reference in New Issue