101 lines
3.6 KiB
Go
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")
|
|
}
|