Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ require (
github.com/beevik/etree v1.4.1
github.com/buildkite/bintest/v3 v3.3.0
github.com/charlievieth/strcase v0.0.5
github.com/charmbracelet/bubbles v0.20.0
github.com/charmbracelet/bubbletea v1.1.0
github.com/charmbracelet/bubbles v0.21.0
github.com/charmbracelet/bubbletea v1.3.4
github.com/charmbracelet/huh v0.6.0
github.com/charmbracelet/lipgloss v0.13.0
github.com/charmbracelet/lipgloss v1.1.0
Comment thread
okraport marked this conversation as resolved.
github.com/coreos/go-oidc v2.2.1+incompatible // replaced
github.com/coreos/go-oidc/v3 v3.12.0
github.com/coreos/go-semver v0.3.1
Expand Down Expand Up @@ -312,9 +312,11 @@ require (
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect
github.com/charmbracelet/x/ansi v0.2.3 // indirect
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
github.com/charmbracelet/x/ansi v0.8.0 // indirect
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect
github.com/charmbracelet/x/term v0.2.0 // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/cloudflare/cfssl v1.6.4 // indirect
github.com/cncf/xds/go v0.0.0-20241223141626-cff3c89139a3 // indirect
github.com/containerd/containerd v1.7.27 // indirect
Expand Down Expand Up @@ -470,7 +472,7 @@ require (
github.com/mtibben/percent v0.2.1 // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/muhlemmer/gu v0.3.1 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
Expand Down Expand Up @@ -505,6 +507,7 @@ require (
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sahilm/fuzzy v0.1.1 // indirect
github.com/sassoftware/relic v7.2.1+incompatible // indirect
github.com/secure-systems-lab/go-securesystemslib v0.9.0 // indirect
github.com/segmentio/asm v1.2.0 // indirect
Expand Down Expand Up @@ -542,6 +545,7 @@ require (
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
github.com/yuin/gopher-lua v1.1.1 // indirect
github.com/zeebo/errs v1.4.0 // indirect
Expand Down
36 changes: 24 additions & 12 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,8 @@ github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.9.1 h1:50sS0RWhGpW/
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.9.1/go.mod h1:ErZOtbzuHabipRTDTor0inoRlYwbsV1ovwSxjGs/uJo=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
github.com/beevik/etree v1.4.1 h1:PmQJDDYahBGNKDcpdX8uPy1xRCwoCGVUiW669MEirVI=
github.com/beevik/etree v1.4.1/go.mod h1:gPNJNaBGVZ9AwsidazFZyygnd+0pAU38N4D+WemwKNs=
Expand Down Expand Up @@ -1025,20 +1027,26 @@ github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNS
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
github.com/charlievieth/strcase v0.0.5 h1:gV4iXVyD6eI5KdfOV+/vIVCKXZwtCWOmDMcu7Uy00Rs=
github.com/charlievieth/strcase v0.0.5/go.mod h1:FIOYY1aDBMSIOFqmVomHBpoK+bteGlESRsgsdWjrhx8=
github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE=
github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU=
github.com/charmbracelet/bubbletea v1.1.0 h1:FjAl9eAL3HBCHenhz/ZPjkKdScmaS5SK69JAK2YJK9c=
github.com/charmbracelet/bubbletea v1.1.0/go.mod h1:9Ogk0HrdbHolIKHdjfFpyXJmiCzGwy+FesYkZr7hYU4=
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI=
github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo=
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
github.com/charmbracelet/huh v0.6.0 h1:mZM8VvZGuE0hoDXq6XLxRtgfWyTI3b2jZNKh0xWmax8=
github.com/charmbracelet/huh v0.6.0/go.mod h1:GGNKeWCeNzKpEOh/OJD8WBwTQjV3prFAtQPpLv+AVwU=
github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw=
github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY=
github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY=
github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 h1:qko3AQ4gK1MTS/de7F5hPGx6/k1u0w4TeYmBFwzYVP4=
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0=
github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM=
github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY=
github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 h1:krfRl01rzPzxSxyLyrChD+U+MzsBXbm0OwYYB67uF+4=
Expand Down Expand Up @@ -1913,8 +1921,8 @@ github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg=
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ=
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM=
github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM=
github.com/muhlemmer/httpforwarded v0.1.0 h1:x4DLrzXdliq8mprgUMR0olDvHGkou5BJsK/vWUetyzY=
Expand Down Expand Up @@ -2097,6 +2105,8 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
github.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGqpgjJU3DYAZeI05A=
github.com/sassoftware/relic v7.2.1+incompatible/go.mod h1:CWfAxv73/iLZ17rbyhIEq3K9hs5w6FpNMdUT//qR+zk=
github.com/sassoftware/relic/v7 v7.6.2 h1:rS44Lbv9G9eXsukknS4mSjIAuuX+lMq/FnStgmZlUv4=
Expand Down Expand Up @@ -2270,6 +2280,8 @@ github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yashtewari/glob-intersection v0.2.0 h1:8iuHdN88yYuCzCdjt0gDe+6bAhUwBeEWqThExu54RFg=
Expand Down
7 changes: 5 additions & 2 deletions tool/tctl/common/top/box.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ import (
// │ Hello │
// ╰────────────────────╯
func boxedView(title string, content string, width int) string {
return boxedViewWithStyle(title, content, width, lipgloss.NewStyle().Faint(true))
}

func boxedViewWithStyle(title string, content string, width int, style lipgloss.Style) string {
rounderBorder := lipgloss.RoundedBorder()

const borderCorners = 2
Expand All @@ -55,11 +59,10 @@ func boxedView(title string, content string, width int) string {
rounderBorder.Top = ""
rounderBorder.TopRight = ""

contentStyle := lipgloss.NewStyle().
contentStyle := style.
BorderStyle(rounderBorder).
PaddingLeft(1).
PaddingRight(1).
Faint(true).
Width(width)

return renderedTitle + contentStyle.Render(content)
Expand Down
104 changes: 104 additions & 0 deletions tool/tctl/common/top/keys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Teleport
// Copyright (C) 2025 Gravitational, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package top

import "github.com/charmbracelet/bubbles/key"

type keyMap struct {
Quit key.Binding

// Movement
Right key.Binding
Left key.Binding
Up key.Binding
Down key.Binding
Filter key.Binding

// Tabs
Common key.Binding
Backend key.Binding
Cache key.Binding
Watcher key.Binding
Audit key.Binding
Raw key.Binding
}

// newDefaultKeymap returns default keybinds used by top
func newDefaultKeymap() *keyMap {
return &keyMap{
Quit: key.NewBinding(
key.WithKeys("q", "ctrl+c"),
key.WithHelp("q", "quit"),
),
Left: key.NewBinding(
key.WithKeys("left", "esc", "shift+tab", "h"),
key.WithHelp("←", "previous"),
),
Right: key.NewBinding(
key.WithKeys("right", "tab", "l"),
key.WithHelp("→", "next"),
),
Up: key.NewBinding(
key.WithKeys("up", "k"),
key.WithHelp("↑", "up"),
),
Down: key.NewBinding(
key.WithKeys("down", "j"),
key.WithHelp("↓", "down"),
),
Common: key.NewBinding(
key.WithKeys("1"),
key.WithHelp("1", "common"),
),
Backend: key.NewBinding(
key.WithKeys("2"),
key.WithHelp("2", "backend"),
),
Cache: key.NewBinding(
key.WithKeys("3"),
key.WithHelp("3", "cache"),
),
Watcher: key.NewBinding(
key.WithKeys("4"),
key.WithHelp("4", "watcher"),
),
Audit: key.NewBinding(
key.WithKeys("5"),
key.WithHelp("5", "audit"),
),
Raw: key.NewBinding(
key.WithKeys("6"),
key.WithHelp("6", "raw"),
),

Filter: key.NewBinding(
key.WithKeys("/"),
key.WithHelp("/", "filter"),
),
}
}

func (k keyMap) ShortHelp() []key.Binding {
return []key.Binding{k.Left, k.Right, k.Quit}
}

func (k keyMap) FullHelp() [][]key.Binding {
return [][]key.Binding{
{k.Left, k.Right},
{k.Quit},
}
}
115 changes: 115 additions & 0 deletions tool/tctl/common/top/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Teleport
// Copyright (C) 2025 Gravitational, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package top

import (
"cmp"
"fmt"
"slices"

"github.com/charmbracelet/bubbles/list"
"github.com/dustin/go-humanize"
dto "github.com/prometheus/client_model/go"
)

// metricItem implements [list.DefaultItem] interface to allow rendering via [list.DefaultDelegate]
type metricItem struct {
name string
value string
}

func (m metricItem) Title() string { return m.name }
func (m metricItem) Description() string { return m.value }
func (m metricItem) FilterValue() string { return m.name }

// getMetricLabelString formats prometheus labels into a readable string.
//
// Example for multiple labels:
//
// "{label_key1=\"value1\",labelkey2=\"value2\"}"
//
// Empty slice will return:
//
// ""
func getMetricLabelString(labels []*dto.LabelPair) string {
var out string

if len(labels) == 0 {
return ""
}

for i, label := range labels {
if i > 0 {
out += ","
}
out += label.GetName() + "=\"" + label.GetValue() + "\""
}

return "{" + out + "}"
}

// metricItemFromPromMetric returns a single [list.Item] from a prometheus metric family and a single metric.
func metricItemFromPromMetric(mf *dto.MetricFamily, m *dto.Metric) list.Item {
value := "n/a"

switch mf.GetType() {
case dto.MetricType_COUNTER:
value = humanize.FormatFloat("", m.GetCounter().GetValue())
case dto.MetricType_GAUGE:
value = humanize.FormatFloat("", m.GetGauge().GetValue())
case dto.MetricType_SUMMARY:
value = fmt.Sprintf("count: %d sum: %s",
m.GetSummary().GetSampleCount(),
humanize.FormatFloat("", m.GetSummary().GetSampleSum()),
)
case dto.MetricType_HISTOGRAM:
// List view does not allow enough space to make historgram buckets meaningful, only show sum and count.
value = fmt.Sprintf("count: %d sum: %s",
m.GetHistogram().GetSampleCount(),
humanize.FormatFloat("", m.GetHistogram().GetSampleSum()),
)
}

return metricItem{
name: mf.GetName() + getMetricLabelString(m.GetLabel()),
value: value,
}
}

// convertMetricsToItems converts a [metricsMsg] into a sorted slice of [list.Item] to be used in a list view.
func convertMetricsToItems(msg metricsMsg) []list.Item {

var itemCount int
for _, mf := range msg {
itemCount += len(mf.GetMetric())
}

items := make([]list.Item, 0, itemCount)

for _, mf := range msg {
for _, m := range mf.GetMetric() {
items = append(items, metricItemFromPromMetric(mf, m))
}
}

// Sort the item list to keep the display order consistent.
slices.SortFunc(items, func(i, j list.Item) int {
return cmp.Compare(i.FilterValue(), j.FilterValue())
})

return items
}
Loading
Loading