public inbox for yew-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [yew-devel] [PATCH yew-comp] rrd time frame selector: seperate time frame from mode
@ 2025-08-29 12:21 Dominik Csapak
  0 siblings, 0 replies; only message in thread
From: Dominik Csapak @ 2025-08-29 12:21 UTC (permalink / raw)
  To: yew-devel

by splitting the one combobox with many entries into a combobox for the
timeframe (hour, day, etc.) and a segmented button for maximum/average.

This makes the combobox less cluttered and sill retains all the
information.

While at it, use the `tr` macro to prepare the values for translation.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
i tried using radio buttons for the mode, but this looked weird when
using inline in pdm gui.

Using a similar mechanism as the task modes seemed better to me.

I thought about implementing the timeframe as a slider, but this
make the UX worse IMHO, since one does not know what values exist
before selecting (we don't have a range/slider component yet where
the values are labeled)

 src/rrd_timeframe_selector.rs | 125 +++++++++++++++++-----------------
 1 file changed, 61 insertions(+), 64 deletions(-)

diff --git a/src/rrd_timeframe_selector.rs b/src/rrd_timeframe_selector.rs
index 5758a04..36ded09 100644
--- a/src/rrd_timeframe_selector.rs
+++ b/src/rrd_timeframe_selector.rs
@@ -6,10 +6,12 @@ use yew::html::IntoEventCallback;
 use yew::prelude::*;
 use yew::virtual_dom::{VComp, VNode};
 
-use proxmox_rrd_api_types as rrd_types;
+use proxmox_rrd_api_types::{self as rrd_types, RrdMode, RrdTimeframe};
+use pwt::css::{AlignItems, ColorScheme};
 use pwt::prelude::*;
 use pwt::state::local_storage;
 use pwt::widget::form::Combobox;
+use pwt::widget::{Button, Row, SegmentedButton};
 use pwt_macros::builder;
 
 /// Combobox for selecting the theme density.
@@ -145,24 +147,20 @@ pub struct PwtRRDTimeframeSelector {
 
 pub enum Msg {
     SetRRDTimeframe(String),
+    SetRRDMode(RrdMode),
 }
 
-fn display_value(v: &AttrValue) -> &str {
+fn display_value(v: &AttrValue) -> Html {
     match v.as_str() {
-        "hour-AVERAGE" => "Hour (average)",
-        "hour-MAX" => "Hour (maximum)",
-        "day-AVERAGE" => "Day (average)",
-        "day-MAX" => "Day (maximum)",
-        "week-AVERAGE" => "Week (average)",
-        "week-MAX" => "Week (maximum)",
-        "month-AVERAGE" => "Month (average)",
-        "month-MAX" => "Month (maximum)",
-        "year-AVERAGE" => "Year (average)",
-        "year-MAX" => "Year (maximum)",
-        "decade-AVERAGE" => "Decade (average)",
-        "decade-MAX" => "Decade (maximum)",
-        _ => v,
-    }
+        "hour" => tr!("Hour"),
+        "day" => tr!("Day"),
+        "week" => tr!("Week"),
+        "month" => tr!("Month"),
+        "year" => tr!("Year"),
+        "decade" => tr!("Decade"),
+        _ => v.to_string(),
+    }
+    .into()
 }
 
 impl Component for PwtRRDTimeframeSelector {
@@ -170,31 +168,13 @@ impl Component for PwtRRDTimeframeSelector {
     type Properties = RRDTimeframeSelector;
 
     fn create(_ctx: &Context<Self>) -> Self {
-        use rrd_types::RrdMode::*;
-        use rrd_types::RrdTimeframe::*;
-
-        let timeframe = RRDTimeframe::load();
-
-        let values = [
-            RRDTimeframe::new(Hour, Average),
-            RRDTimeframe::new(Hour, Max),
-            RRDTimeframe::new(Day, Average),
-            RRDTimeframe::new(Day, Max),
-            RRDTimeframe::new(Week, Average),
-            RRDTimeframe::new(Week, Max),
-            RRDTimeframe::new(Month, Average),
-            RRDTimeframe::new(Month, Max),
-            RRDTimeframe::new(Year, Average),
-            RRDTimeframe::new(Year, Max),
-            RRDTimeframe::new(Decade, Average),
-            RRDTimeframe::new(Decade, Max),
-        ]
-        .iter()
-        .map(|v| AttrValue::from(v.serialize()))
-        .collect();
+        let values = ["hour", "day", "week", "month", "year", "decade"]
+            .into_iter()
+            .map(|v| v.into())
+            .collect();
 
         Self {
-            timeframe,
+            timeframe: RRDTimeframe::load(),
             items: Rc::new(values),
         }
     }
@@ -203,38 +183,55 @@ impl Component for PwtRRDTimeframeSelector {
         let props = ctx.props();
         match msg {
             Msg::SetRRDTimeframe(timeframe_str) => {
-                if let Ok(timeframe) = timeframe_str.as_str().parse::<RRDTimeframe>() {
-                    timeframe.store();
-                    self.timeframe = timeframe;
-                    if let Some(on_change) = &props.on_change {
-                        on_change.emit(timeframe);
-                    }
+                if let Ok(timeframe) = timeframe_str.as_str().parse::<RrdTimeframe>() {
+                    self.timeframe.timeframe = timeframe;
+                    self.timeframe.store();
                 }
-                true
             }
+            Msg::SetRRDMode(mode) => {
+                self.timeframe.mode = mode;
+                self.timeframe.store();
+            }
+        }
+        if let Some(on_change) = &props.on_change {
+            on_change.emit(self.timeframe);
         }
+        true
     }
 
     fn view(&self, ctx: &Context<Self>) -> Html {
         let props = ctx.props();
-
-        Combobox::new()
-            .required(true)
-            .min_width(150)
-            .class(props.class.clone())
-            .default(self.timeframe.serialize())
-            .items(self.items.clone())
-            .on_change(ctx.link().callback(Msg::SetRRDTimeframe))
-            .render_value(|v: &AttrValue| {
-                html! {display_value(v)}
-            })
-            .show_filter(false)
-            // Note: This is just for completeness. Not used because we do not show the filter...
-            .filter(|item: &AttrValue, query: &str| {
-                display_value(item)
-                    .to_lowercase()
-                    .contains(&query.to_lowercase())
-            })
+        let average = self.timeframe.mode == RrdMode::Average;
+        let max = self.timeframe.mode == RrdMode::Max;
+
+        Row::new()
+            .class(AlignItems::Center)
+            .gap(2)
+            .with_child(
+                Combobox::new()
+                    .required(true)
+                    .min_width(100)
+                    .class(props.class.clone())
+                    .default(self.timeframe.timeframe.to_string())
+                    .items(self.items.clone())
+                    .on_change(ctx.link().callback(Msg::SetRRDTimeframe))
+                    .render_value(display_value),
+            )
+            .with_child(
+                SegmentedButton::new()
+                    .with_button(
+                        Button::new(tr!("Maximum"))
+                            .on_activate(ctx.link().callback(|_| Msg::SetRRDMode(RrdMode::Max)))
+                            .class(max.then_some(ColorScheme::Primary))
+                            .pressed(max),
+                    )
+                    .with_button(
+                        Button::new(tr!("Average"))
+                            .on_activate(ctx.link().callback(|_| Msg::SetRRDMode(RrdMode::Average)))
+                            .class(average.then_some(ColorScheme::Primary))
+                            .pressed(average),
+                    ),
+            )
             .into()
     }
 }
-- 
2.47.2



_______________________________________________
yew-devel mailing list
yew-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/yew-devel


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2025-08-29 12:23 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-08-29 12:21 [yew-devel] [PATCH yew-comp] rrd time frame selector: seperate time frame from mode Dominik Csapak

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal