Files
MujicaUI/dashboard_filter_bar.go
T

101 lines
3.6 KiB
Go

package mujica
import (
"fmt"
"log/slog"
"slices"
"time"
"github.com/egoist/mygo/ui"
"mujicaui/icons"
)
// DashboardFilters holds filters; zero uses caller defaults.
type DashboardFilters struct {
// Range is the look-back; zero uses the caller's default.
Range time.Duration
Env string
Tags []string
}
// DashboardFilterBarOptions configure a DashboardFilterBar.
type DashboardFilterBarOptions struct {
// Ranges defaults to 15m, 1h, 24h and 7d.
Ranges []time.Duration
// Envs and Tags are the offered environments and tags.
Envs, Tags []string
Disabled bool
}
var dashboardRanges = []time.Duration{15 * time.Minute, time.Hour, 24 * time.Hour, 7 * 24 * time.Hour}
// DashboardFilterBar edits time, environment and tags with clear.
func DashboardFilterBar(c *ui.Context, f *DashboardFilters, opts DashboardFilterBarOptions) ChoiceResult {
if f == nil {
panic("mujica: DashboardFilterBar needs filters")
}
ranges := opts.Ranges
if ranges == nil {
ranges = dashboardRanges
}
if f.Env != "" && !slices.Contains(opts.Envs, f.Env) {
panic("mujica: DashboardFilterBar Env is not offered")
}
for _, tag := range f.Tags {
if !slices.Contains(opts.Tags, tag) {
panic("mujica: DashboardFilterBar tag is not offered")
}
}
u := Density(c).Unit()
var r ChoiceResult
r.Element = ui.Row(c).Shrink(0).Wrap().Gap(u * 3).AlignItems(ui.Center).Disabled(opts.Disabled).
Label(msg(c, "dashboard_filter_bar.label"))
locked := r.Element.IsDisabled()
r.Element.Children(func() {
rs := []SelectOption[time.Duration]{{Value: 0, Label: msg(c, "dashboard_filter_bar.default_range")}}
for _, d := range ranges {
rs = append(rs, SelectOption[time.Duration]{Value: d, Label: fmt.Sprintf(msg(c, "dashboard_filter_bar.last"), dashboardRangeLabel(c, d))})
}
if f.Range != 0 && !slices.Contains(ranges, f.Range) {
panic("mujica: DashboardFilterBar Range is not offered")
}
r.changed = Select(c, &f.Range, rs, SelectOptions{Label: msg(c, "dashboard_filter_bar.range"), Disabled: locked}).Changed()
envs := []SelectOption[string]{{Value: "", Label: msg(c, "dashboard_filter_bar.all_envs")}}
for _, e := range opts.Envs {
envs = append(envs, SelectOption[string]{Value: e, Label: e})
}
r.changed = Select(c, &f.Env, envs, SelectOptions{Label: msg(c, "dashboard_filter_bar.env"), Disabled: locked}).Changed() || r.changed
if len(opts.Tags) > 0 {
tags := make([]SelectOption[string], len(opts.Tags))
for i, t := range opts.Tags {
tags[i] = SelectOption[string]{Value: t, Label: t}
}
r.changed = MultiSelect(c, &f.Tags, tags, MultiSelectOptions{Placeholder: msg(c, "dashboard_filter_bar.tags"),
Label: msg(c, "dashboard_filter_bar.tags"), Disabled: locked}).Changed() || r.changed
}
empty := f.Range == 0 && f.Env == "" && len(f.Tags) == 0
if Button(c, msg(c, "dashboard_filter_bar.clear"), ButtonOptions{Variant: Ghost, Icon: icons.Must("x"), Disabled: locked || empty}).Clicked() && !locked {
*f, r.changed = DashboardFilters{}, true
}
})
if r.changed {
slog.Debug("mujica: dashboard_filter_bar change", "range", f.Range, "env", f.Env, "tags", len(f.Tags))
}
return r
}
// dashboardRangeLabel names a look-back, as "15 min" or "7 d".
func dashboardRangeLabel(c *ui.Context, d time.Duration) string {
switch {
case d <= 0:
case d%(24*time.Hour) == 0:
return fmt.Sprintf(msg(c, "dashboard_filter_bar.days"), int(d/(24*time.Hour)))
case d%time.Hour == 0:
return fmt.Sprintf(msg(c, "dashboard_filter_bar.hours"), int(d/time.Hour))
case d%time.Minute == 0:
return fmt.Sprintf(msg(c, "dashboard_filter_bar.minutes"), int(d/time.Minute))
}
panic("mujica: DashboardFilterBar ranges must be positive whole minutes")
}