v0.32.2
This commit is contained in:
1 parent
bb025dcf44
commit
b0f211555a
74 files changed
+6089
-556
No files matched your search
+57
-22
@@ -18,6 +18,9 @@ fn default_admin_chart_style() -> String {
|
||||
fn default_admin_button_style() -> String {
|
||||
"normal".to_owned()
|
||||
}
|
||||
fn default_admin_corner_style() -> String {
|
||||
"default".to_owned()
|
||||
}
|
||||
fn default_admin_table_density() -> String {
|
||||
"normal".to_owned()
|
||||
}
|
||||
@@ -27,29 +30,34 @@ fn default_admin_dashboard_density() -> String {
|
||||
fn default_admin_dashboard_widgets() -> Vec<String> {
|
||||
DASHBOARD_WIDGETS
|
||||
.iter()
|
||||
.map(|value| (*value).to_owned())
|
||||
.map(|widget| widget.id.clone())
|
||||
.collect()
|
||||
}
|
||||
const STREAM_DASHBOARD_WIDGETS: &[&str] = &[
|
||||
"stream_overview",
|
||||
"stream_traffic",
|
||||
"stream_sessions",
|
||||
"stream_backend_health",
|
||||
];
|
||||
fn default_hidden_dashboard_widgets() -> Vec<String> {
|
||||
STREAM_DASHBOARD_WIDGETS
|
||||
DASHBOARD_WIDGETS
|
||||
.iter()
|
||||
.map(|id| (*id).to_owned())
|
||||
.filter(|widget| widget.default_hidden)
|
||||
.map(|widget| widget.id.clone())
|
||||
.collect()
|
||||
}
|
||||
// Old accounts stored a complete 12-card order and often an explicit empty
|
||||
// hidden list. Upgrade it in memory: append opt-in Stream cards as hidden.
|
||||
fn migrate_dashboard_widgets(prefs: &mut AdminPreferences) {
|
||||
for id in STREAM_DASHBOARD_WIDGETS {
|
||||
if !prefs.dashboard_widgets.iter().any(|item| item == id) {
|
||||
prefs.dashboard_widgets.push((*id).to_owned());
|
||||
if !prefs.dashboard_hidden_widgets.iter().any(|item| item == id) {
|
||||
prefs.dashboard_hidden_widgets.push((*id).to_owned());
|
||||
|
||||
// Preserve the user's saved order/visibility, drop identifiers unknown to this
|
||||
// binary, and append new registry widgets according to their opt-in policy.
|
||||
// Stored preferences from older/newer releases are normalized on read.
|
||||
fn reconcile_dashboard_widgets(prefs: &mut AdminPreferences) {
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
prefs.dashboard_widgets.retain(|id| {
|
||||
DASHBOARD_WIDGETS.iter().any(|widget| widget.id == *id) && seen.insert(id.clone())
|
||||
});
|
||||
let mut seen_hidden = std::collections::HashSet::new();
|
||||
prefs.dashboard_hidden_widgets.retain(|id| {
|
||||
DASHBOARD_WIDGETS.iter().any(|widget| widget.id == *id) && seen_hidden.insert(id.clone())
|
||||
});
|
||||
for widget in DASHBOARD_WIDGETS.iter() {
|
||||
if !seen.contains(&widget.id) {
|
||||
prefs.dashboard_widgets.push(widget.id.clone());
|
||||
if widget.default_hidden && seen_hidden.insert(widget.id.clone()) {
|
||||
prefs.dashboard_hidden_widgets.push(widget.id.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,6 +128,8 @@ struct AdminPreferences {
|
||||
chart_style: String,
|
||||
#[serde(default = "default_admin_button_style")]
|
||||
button_style: String,
|
||||
#[serde(default = "default_admin_corner_style")]
|
||||
corner_style: String,
|
||||
#[serde(default = "default_admin_table_density")]
|
||||
table_density: String,
|
||||
#[serde(default = "default_admin_dashboard_density")]
|
||||
@@ -176,6 +186,7 @@ impl Default for AdminPreferences {
|
||||
time_format: default_admin_time_format(),
|
||||
chart_style: default_admin_chart_style(),
|
||||
button_style: default_admin_button_style(),
|
||||
corner_style: default_admin_corner_style(),
|
||||
table_density: default_admin_table_density(),
|
||||
dashboard_density: default_admin_dashboard_density(),
|
||||
dashboard_widgets: default_admin_dashboard_widgets(),
|
||||
@@ -246,7 +257,10 @@ fn validate_admin_preferences(preferences: &AdminPreferences) -> Result<(), ApiE
|
||||
"invalid stored-log sort column preference".into(),
|
||||
));
|
||||
}
|
||||
if !matches!(preferences.theme.as_str(), "dark" | "light") {
|
||||
if !matches!(
|
||||
preferences.theme.as_str(),
|
||||
"dark" | "ultra_dark" | "light" | "cream"
|
||||
) {
|
||||
return Err(ApiError(
|
||||
StatusCode::UNPROCESSABLE_ENTITY,
|
||||
"invalid administration theme preference".into(),
|
||||
@@ -293,6 +307,15 @@ fn validate_admin_preferences(preferences: &AdminPreferences) -> Result<(), ApiE
|
||||
"invalid administration chart style preference".into(),
|
||||
));
|
||||
}
|
||||
if !matches!(
|
||||
preferences.corner_style.as_str(),
|
||||
"default" | "square" | "subtle" | "rounded" | "extra"
|
||||
) {
|
||||
return Err(ApiError(
|
||||
StatusCode::UNPROCESSABLE_ENTITY,
|
||||
"invalid administration corner style preference".into(),
|
||||
));
|
||||
}
|
||||
if !matches!(preferences.button_style.as_str(), "normal" | "compact") {
|
||||
return Err(ApiError(
|
||||
StatusCode::UNPROCESSABLE_ENTITY,
|
||||
@@ -327,7 +350,9 @@ fn validate_admin_preferences(preferences: &AdminPreferences) -> Result<(), ApiE
|
||||
}
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
for widget in &preferences.dashboard_widgets {
|
||||
if !DASHBOARD_WIDGETS.contains(&widget.as_str()) || !seen.insert(widget.as_str()) {
|
||||
if !DASHBOARD_WIDGETS.iter().any(|entry| entry.id == *widget)
|
||||
|| !seen.insert(widget.as_str())
|
||||
{
|
||||
return Err(ApiError(
|
||||
StatusCode::UNPROCESSABLE_ENTITY,
|
||||
"invalid administration dashboard widget order".into(),
|
||||
@@ -342,7 +367,9 @@ fn validate_admin_preferences(preferences: &AdminPreferences) -> Result<(), ApiE
|
||||
}
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
for widget in &preferences.dashboard_hidden_widgets {
|
||||
if !DASHBOARD_WIDGETS.contains(&widget.as_str()) || !seen.insert(widget.as_str()) {
|
||||
if !DASHBOARD_WIDGETS.iter().any(|entry| entry.id == *widget)
|
||||
|| !seen.insert(widget.as_str())
|
||||
{
|
||||
return Err(ApiError(
|
||||
StatusCode::UNPROCESSABLE_ENTITY,
|
||||
"invalid administration hidden dashboard widgets".into(),
|
||||
@@ -418,7 +445,7 @@ async fn preferences(
|
||||
let preferences = match stored {
|
||||
Some(document) => match serde_json::from_str::<AdminPreferences>(&document) {
|
||||
Ok(mut preferences) => {
|
||||
migrate_dashboard_widgets(&mut preferences);
|
||||
reconcile_dashboard_widgets(&mut preferences);
|
||||
if validate_admin_preferences(&preferences).is_ok() {
|
||||
preferences
|
||||
} else {
|
||||
@@ -441,7 +468,15 @@ async fn update_preferences(
|
||||
Extension(session): Extension<Session>,
|
||||
input: Result<Json<AdminPreferences>, axum::extract::rejection::JsonRejection>,
|
||||
) -> Result<Json<AdminPreferences>, ApiError> {
|
||||
let Json(preferences) = input.map_err(public::invalid_json)?;
|
||||
let Json(mut preferences) = input.map_err(public::invalid_json)?;
|
||||
// Do not rewrite the caller's saved order on PUT; drop only stale IDs.
|
||||
// Legacy partial lists are expanded on the next GET, as before.
|
||||
preferences
|
||||
.dashboard_widgets
|
||||
.retain(|id| DASHBOARD_WIDGETS.iter().any(|widget| widget.id == *id));
|
||||
preferences
|
||||
.dashboard_hidden_widgets
|
||||
.retain(|id| DASHBOARD_WIDGETS.iter().any(|widget| widget.id == *id));
|
||||
validate_admin_preferences(&preferences)?;
|
||||
let document = serde_json::to_string(&preferences).map_err(auth::internal)?;
|
||||
if !state
|
||||
|
||||
Reference in new issue
Block a user