checkpoint
parent
5c21f3586e
commit
4bf67dd4e1
|
|
@ -96,7 +96,7 @@ func loadConfiguration() *config.Config {
|
|||
}
|
||||
|
||||
if err := k9sCfg.Refine(k8sFlags); err != nil {
|
||||
log.Panic().Err(err).Msg("Unable to locate K8s cluster configuration")
|
||||
log.Panic().Err(err).Msg("Unable to locate kubeconfig file")
|
||||
}
|
||||
k9sCfg.SetConnection(k8s.InitConnectionOrDie(k8sCfg, log.Logger))
|
||||
|
||||
|
|
|
|||
7
go.mod
7
go.mod
|
|
@ -26,14 +26,15 @@ replace (
|
|||
)
|
||||
|
||||
require (
|
||||
github.com/derailed/tview v0.2.0
|
||||
github.com/atotto/clipboard v0.1.2
|
||||
github.com/derailed/tview v0.2.1
|
||||
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect
|
||||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f // indirect
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f // indirect
|
||||
github.com/evanphx/json-patch v4.1.0+incompatible // indirect
|
||||
github.com/fatih/camelcase v1.0.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
github.com/gdamore/tcell v1.1.2
|
||||
github.com/gdamore/tcell v1.2.0
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/gogo/protobuf v1.2.1 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef // indirect
|
||||
|
|
@ -47,6 +48,7 @@ require (
|
|||
github.com/imdario/mergo v0.3.7 // indirect
|
||||
github.com/json-iterator/go v1.1.6 // indirect
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/ktr0731/go-fuzzyfinder v0.1.2
|
||||
github.com/mattn/go-runewidth v0.0.4
|
||||
github.com/onsi/ginkgo v1.8.0 // indirect
|
||||
github.com/onsi/gomega v1.5.0 // indirect
|
||||
|
|
@ -57,7 +59,6 @@ require (
|
|||
github.com/stretchr/testify v1.3.0
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 // indirect
|
||||
golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6 // indirect
|
||||
golang.org/x/sys v0.0.0-20190426135247-a129542de9ae // indirect
|
||||
golang.org/x/text v0.3.2
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||
|
|
|
|||
13
go.sum
13
go.sum
|
|
@ -21,6 +21,8 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdko
|
|||
github.com/Rican7/retry v0.1.0/go.mod h1:FgOROf8P5bebcC1DS0PdOQiqGUridaZvikzUmkFW6gg=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/atotto/clipboard v0.1.2 h1:YZCtFu5Ie8qX2VmVTBnrqLSiU9XOWwqNRmdT3gIQzbY=
|
||||
github.com/atotto/clipboard v0.1.2/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7/go.mod h1:LWMyo4iOLWXHGdBki7NIht1kHru/0wM179h+d3g8ATM=
|
||||
github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/bazelbuild/bazel-gazelle v0.0.0-20181012220611-c728ce9f663e/go.mod h1:uHBSeeATKpVazAACZBDPL/Nk/UhQDDsJWDlqYJo8/Us=
|
||||
|
|
@ -61,6 +63,8 @@ github.com/derailed/tview v0.1.12 h1:EVTzx+Mq3PJzbGnCDwUVu5fD479mbQU/0rabxTm7tHA
|
|||
github.com/derailed/tview v0.1.12/go.mod h1:g+ZyIsV5osK+lQ6LajiGQeLW10BQLJ6aMvy8Ldt2oa0=
|
||||
github.com/derailed/tview v0.2.0 h1:Mkc2LCy+ct+j0lBwP9Gkq0vXiuWOLufmP9A2lR36bFY=
|
||||
github.com/derailed/tview v0.2.0/go.mod h1:aDhJBLLf7pXbkaNmVroSvsjiP8ry6sfBVWNHTz6klZw=
|
||||
github.com/derailed/tview v0.2.1 h1:3UjeNni+Q94WmmVnc8tLSTZab5NuRVrwolghCiXCtSs=
|
||||
github.com/derailed/tview v0.2.1/go.mod h1:aDhJBLLf7pXbkaNmVroSvsjiP8ry6sfBVWNHTz6klZw=
|
||||
github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda h1:NyywMz59neOoVRFDz+ccfKWxn784fiHMDnZSy6T+JXY=
|
||||
github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||
|
|
@ -96,6 +100,8 @@ github.com/gdamore/tcell v1.1.1 h1:U73YL+jMem2XfhvaIUfPO6MpJawaG92B2funXVb9qLs=
|
|||
github.com/gdamore/tcell v1.1.1/go.mod h1:K1udHkiR3cOtlpKG5tZPD5XxrF7v2y7lDq7Whcj+xkQ=
|
||||
github.com/gdamore/tcell v1.1.2 h1:Afe8cU6SECC06UmvaJ55Jr3Eh0tz/ywLjqWYqjGZp3s=
|
||||
github.com/gdamore/tcell v1.1.2/go.mod h1:h3kq4HO9l2On+V9ed8w8ewqQEmGCSSHOgQ+2h8uzurE=
|
||||
github.com/gdamore/tcell v1.2.0 h1:ikixzsxc8K8o3V2/CEmyoEW8mJZaNYQQ3NP3VIQdUe4=
|
||||
github.com/gdamore/tcell v1.2.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
|
||||
github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
|
|
@ -146,6 +152,7 @@ github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
|||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/cadvisor v0.33.2-0.20190411163913-9db8c7dee20a/go.mod h1:1nql6U13uTHaLYB8rLS5x9IJc2qT6Xd/Tr1sTX6NE48=
|
||||
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
|
|
@ -206,6 +213,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||
github.com/kr/text v0.0.0-20130911015532-6807e777504f/go.mod h1:sjUstKUATFIcff4qlB53Kml0wQPtJVc/3fWrmuUmcfA=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/ktr0731/go-fuzzyfinder v0.1.2 h1:Y+Vm86X/QmE/+DitA2RrLndZU134cZtBUOtO18CTVcE=
|
||||
github.com/ktr0731/go-fuzzyfinder v0.1.2/go.mod h1:RzAqRU8h8f4uSLSP+THd87krOFnBploGlGn/8RQhd7M=
|
||||
github.com/libopenstorage/openstorage v0.0.0-20170906232338-093a0c388875/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc=
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
||||
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
|
||||
|
|
@ -254,6 +263,8 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m
|
|||
github.com/mvdan/xurls v0.0.0-20160110113200-1b768d7c393a/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
|
||||
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840=
|
||||
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
|
|
@ -423,6 +434,8 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190426135247-a129542de9ae h1:mQLHiymj/JXKnnjc62tb7nD5pZLs940/sXJu+Xp3DBA=
|
||||
golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756 h1:9nuHUbU8dRnRRfj9KjWUVrJeoexdbeMjttk6Oh1rD10=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
|
|
|
|||
|
|
@ -202,7 +202,6 @@ func (c *Config) Validate() {
|
|||
|
||||
// Dump debug...
|
||||
func (c *Config) Dump(msg string) {
|
||||
log.Debug().Msg(msg)
|
||||
log.Debug().Msgf("Current Cluster: %s\n", c.K9s.CurrentCluster)
|
||||
for k, cl := range c.K9s.Clusters {
|
||||
log.Debug().Msgf("K9s cluster: %s -- %s\n", k, cl.Namespace)
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ func TestConfigLoad(t *testing.T) {
|
|||
assert.Equal(t, "minikube", cfg.K9s.CurrentCluster)
|
||||
assert.NotNil(t, cfg.K9s.Clusters)
|
||||
assert.Equal(t, 2, len(cfg.K9s.Clusters))
|
||||
assert.Equal(t, 0, len(cfg.K9s.Aliases))
|
||||
assert.Equal(t, 1, len(cfg.K9s.Plugins))
|
||||
|
||||
nn := []string{
|
||||
"default",
|
||||
|
|
@ -293,6 +293,18 @@ var expectedConfig = `k9s:
|
|||
- kube-system
|
||||
view:
|
||||
active: ctx
|
||||
plugins:
|
||||
blah:
|
||||
shortCut: shift-s
|
||||
scopes:
|
||||
- po
|
||||
- dp
|
||||
description: blee
|
||||
command: duh
|
||||
args:
|
||||
- -n
|
||||
- $NAMESPACE
|
||||
- -boolean
|
||||
`
|
||||
|
||||
var resetConfig = `k9s:
|
||||
|
|
@ -309,4 +321,16 @@ var resetConfig = `k9s:
|
|||
- default
|
||||
view:
|
||||
active: po
|
||||
plugins:
|
||||
blah:
|
||||
shortCut: shift-s
|
||||
scopes:
|
||||
- po
|
||||
- dp
|
||||
description: blee
|
||||
command: duh
|
||||
args:
|
||||
- -n
|
||||
- $NAMESPACE
|
||||
- -boolean
|
||||
`
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ type K9s struct {
|
|||
CurrentContext string `yaml:"currentContext"`
|
||||
CurrentCluster string `yaml:"currentCluster"`
|
||||
Clusters map[string]*Cluster `yaml:"clusters,omitempty"`
|
||||
Aliases map[string]string `yaml:"aliases,omitempty"`
|
||||
Plugins map[string]*Plugin `yaml:"plugins,omitempty"`
|
||||
}
|
||||
|
||||
// NewK9s create a new K9s configuration.
|
||||
|
|
@ -28,8 +28,8 @@ func NewK9s() *K9s {
|
|||
RefreshRate: defaultRefreshRate,
|
||||
LogBufferSize: defaultLogBufferSize,
|
||||
LogRequestSize: defaultLogRequestSize,
|
||||
Clusters: map[string]*Cluster{},
|
||||
Aliases: map[string]string{},
|
||||
Clusters: make(map[string]*Cluster),
|
||||
Plugins: make(map[string]*Plugin),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ package config
|
|||
|
||||
// Plugin describes a K9s plugin
|
||||
type Plugin struct {
|
||||
ShortCut string `yaml:"shortCut"`
|
||||
Scopes []string `yaml:"scopes"`
|
||||
Args map[string]string `yaml:"args"`
|
||||
ShortCut string `yaml:"shortCut"`
|
||||
Scopes []string `yaml:"scopes"`
|
||||
Description string `yaml:"description"`
|
||||
Command string `yaml:"command"`
|
||||
Args []string `yaml:"args"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,11 +28,14 @@ k9s:
|
|||
view:
|
||||
active: po
|
||||
plugins:
|
||||
sniff:
|
||||
shortCut: ShiftS
|
||||
blah:
|
||||
shortCut: shift-s
|
||||
description: blee
|
||||
scopes:
|
||||
- po
|
||||
- dp
|
||||
command: duh
|
||||
args:
|
||||
n: $NAMESPACE
|
||||
|
||||
- -n
|
||||
- $NAMESPACE
|
||||
- -boolean
|
||||
|
|
@ -79,6 +79,5 @@ func (p *Pod) Containers(ns, n string, includeInit bool) ([]string, error) {
|
|||
|
||||
// Logs fetch container logs for a given pod and container.
|
||||
func (p *Pod) Logs(ns, n string, opts *v1.PodLogOptions) *restclient.Request {
|
||||
log.Debug().Msgf("Log Options %#v", *opts.TailLines)
|
||||
return p.DialOrDie().CoreV1().Pods(ns).GetLogs(n, opts)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,12 +97,10 @@ func (r *Endpoints) toEPs(ss []v1.EndpointSubset) string {
|
|||
for _, s := range ss {
|
||||
pp := make([]string, len(s.Ports))
|
||||
portsToStrs(s.Ports, pp)
|
||||
log.Debug().Msgf("Ports %#v", pp)
|
||||
a := make([]string, len(s.Addresses))
|
||||
proccessIPs(a, pp, s.Addresses)
|
||||
aa = append(aa, strings.Join(a, ","))
|
||||
}
|
||||
log.Debug().Msgf("AA %#v", aa)
|
||||
return strings.Join(aa, ",")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,15 +35,17 @@ const (
|
|||
NAValue = "n/a"
|
||||
)
|
||||
|
||||
func metaFQN(m metav1.ObjectMeta) string {
|
||||
// MetaFQN returns a fully qualified resource name.
|
||||
func MetaFQN(m metav1.ObjectMeta) string {
|
||||
if m.Namespace == "" {
|
||||
return m.Name
|
||||
}
|
||||
|
||||
return fqn(m.Namespace, m.Name)
|
||||
return FQN(m.Namespace, m.Name)
|
||||
}
|
||||
|
||||
func fqn(ns, n string) string {
|
||||
// FQN returns a fully qualified resource name.
|
||||
func FQN(ns, n string) string {
|
||||
if ns == "" {
|
||||
return n
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,7 +153,6 @@ func (r *HorizontalPodAutoscalerV2Beta1) checkHPAType(i int, spec autoscalingv2b
|
|||
|
||||
func (*HorizontalPodAutoscalerV2Beta1) externalMetrics(i int, spec autoscalingv2beta1.MetricSpec, statuses []autoscalingv2beta1.MetricStatus) string {
|
||||
current := "<unknown>"
|
||||
log.Debug().Msg("YO!")
|
||||
if spec.External.TargetAverageValue != nil {
|
||||
if len(statuses) > i && statuses[i].External != nil && &statuses[i].External.CurrentAverageValue != nil {
|
||||
current = statuses[i].External.CurrentAverageValue.String()
|
||||
|
|
|
|||
|
|
@ -253,13 +253,13 @@ func (l *list) fetchResource(informer *wa.Informer, r interface{}, ns string) (C
|
|||
res := l.resource.New(r)
|
||||
switch o := r.(type) {
|
||||
case *v1.Node:
|
||||
fqn := metaFQN(o.ObjectMeta)
|
||||
fqn := MetaFQN(o.ObjectMeta)
|
||||
nmx, err := informer.Get(wa.NodeMXIndex, fqn, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
res.SetNodeMetrics(nmx.(*mv1beta1.NodeMetrics))
|
||||
}
|
||||
case *v1.Pod:
|
||||
fqn := metaFQN(o.ObjectMeta)
|
||||
fqn := MetaFQN(o.ObjectMeta)
|
||||
pmx, err := informer.Get(wa.PodMXIndex, fqn, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
res.SetPodMetrics(pmx.(*mv1beta1.PodMetrics))
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ func (o LogOptions) HasContainer() bool {
|
|||
|
||||
// FQN returns resource fully qualified name.
|
||||
func (o LogOptions) FQN() string {
|
||||
return fqn(o.Namespace, o.Name)
|
||||
return FQN(o.Namespace, o.Name)
|
||||
}
|
||||
|
||||
// Path returns resource descriptor path.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package ui
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
|
@ -10,26 +10,36 @@ import (
|
|||
"github.com/derailed/k9s/internal/resource"
|
||||
"github.com/derailed/tview"
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/ktr0731/go-fuzzyfinder/matching"
|
||||
"github.com/rs/zerolog/log"
|
||||
"k8s.io/apimachinery/pkg/util/duration"
|
||||
)
|
||||
|
||||
// ColorerFunc represents a row colorer.
|
||||
type ColorerFunc func(ns string, evt *resource.RowEvent) tcell.Color
|
||||
type (
|
||||
// ColorerFunc represents a row colorer.
|
||||
ColorerFunc func(ns string, evt *resource.RowEvent) tcell.Color
|
||||
|
||||
// SelectedRowFunc a table selection callback.
|
||||
SelectedRowFunc func(r, c int)
|
||||
)
|
||||
|
||||
// Table represents tabular data.
|
||||
type Table struct {
|
||||
*tview.Table
|
||||
|
||||
baseTitle string
|
||||
data resource.TableData
|
||||
actions KeyActions
|
||||
cmdBuff *CmdBuff
|
||||
styles *config.Styles
|
||||
activeNS string
|
||||
sortCol SortColumn
|
||||
sortFn SortFn
|
||||
colorerFn ColorerFunc
|
||||
baseTitle string
|
||||
data resource.TableData
|
||||
actions KeyActions
|
||||
cmdBuff *CmdBuff
|
||||
styles *config.Styles
|
||||
activeNS string
|
||||
sortCol SortColumn
|
||||
sortFn SortFn
|
||||
colorerFn ColorerFunc
|
||||
selectedItem string
|
||||
selectedRow int
|
||||
selectedFn func(string) string
|
||||
selListeners []SelectedRowFunc
|
||||
}
|
||||
|
||||
// NewTable returns a new table view.
|
||||
|
|
@ -57,11 +67,101 @@ func NewTable(title string, styles *config.Styles) *Table {
|
|||
tcell.AttrBold,
|
||||
)
|
||||
|
||||
v.SetSelectionChangedFunc(v.selChanged)
|
||||
v.SetInputCapture(v.keyboard)
|
||||
|
||||
return &v
|
||||
}
|
||||
|
||||
// AddSelectedRowListener add a new selected row listener.
|
||||
func (v *Table) AddSelectedRowListener(f SelectedRowFunc) {
|
||||
v.selListeners = append(v.selListeners, f)
|
||||
}
|
||||
|
||||
func (v *Table) selChanged(r, c int) {
|
||||
// Changed?
|
||||
if v.selectedRow == r {
|
||||
return
|
||||
}
|
||||
|
||||
v.selectedRow = r
|
||||
v.updateSelectedItem(r)
|
||||
if r == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
cell := v.GetCell(r, c)
|
||||
v.SetSelectedStyle(
|
||||
tcell.ColorBlack,
|
||||
cell.Color,
|
||||
tcell.AttrBold,
|
||||
)
|
||||
|
||||
for _, f := range v.selListeners {
|
||||
f(r, c)
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateSelection refresh selected row.
|
||||
func (v *Table) updateSelection(broadcast bool) {
|
||||
v.SelectRow(v.selectedRow, false)
|
||||
}
|
||||
|
||||
// SelectRow select a given row by index.
|
||||
func (v *Table) SelectRow(r int, broadcast bool) {
|
||||
if !broadcast {
|
||||
v.SetSelectionChangedFunc(nil)
|
||||
}
|
||||
defer v.SetSelectionChangedFunc(v.selChanged)
|
||||
v.Select(r, 0)
|
||||
v.updateSelectedItem(r)
|
||||
}
|
||||
|
||||
func (v *Table) updateSelectedItem(r int) {
|
||||
if r == 0 || v.GetCell(r, 0) == nil {
|
||||
v.selectedItem = ""
|
||||
return
|
||||
}
|
||||
|
||||
col0 := TrimCell(v, r, 0)
|
||||
switch v.activeNS {
|
||||
case resource.NotNamespaced:
|
||||
v.selectedItem = col0
|
||||
case resource.AllNamespace, resource.AllNamespaces:
|
||||
v.selectedItem = path.Join(col0, TrimCell(v, r, 1))
|
||||
default:
|
||||
v.selectedItem = path.Join(v.activeNS, col0)
|
||||
}
|
||||
}
|
||||
|
||||
// SetSelectedFn defines a function that cleanse the current selection.
|
||||
func (v *Table) SetSelectedFn(f func(string) string) {
|
||||
v.selectedFn = f
|
||||
}
|
||||
|
||||
// RowSelected checks if there is an active row selection.
|
||||
func (v *Table) RowSelected() bool {
|
||||
return v.selectedItem != ""
|
||||
}
|
||||
|
||||
// GetSelectedCell returns the contant of a cell for the currently selected row.
|
||||
func (v *Table) GetSelectedCell(col int) string {
|
||||
return TrimCell(v, v.selectedRow, col)
|
||||
}
|
||||
|
||||
// GetSelectedRow fetch the currently selected row index.
|
||||
func (v *Table) GetSelectedRow() int {
|
||||
return v.selectedRow
|
||||
}
|
||||
|
||||
// GetSelectedItem returns the currently selected item name.
|
||||
func (v *Table) GetSelectedItem() string {
|
||||
if v.selectedFn != nil {
|
||||
return v.selectedFn(v.selectedItem)
|
||||
}
|
||||
return v.selectedItem
|
||||
}
|
||||
|
||||
func (v *Table) keyboard(evt *tcell.EventKey) *tcell.EventKey {
|
||||
key := evt.Key()
|
||||
if key == tcell.KeyRune {
|
||||
|
|
@ -114,8 +214,8 @@ func (v *Table) SetActiveNS(ns string) {
|
|||
}
|
||||
|
||||
// SetSortCol sets in sort column index and order.
|
||||
func (v *Table) SetSortCol(index int, asc bool) {
|
||||
v.sortCol.index, v.sortCol.asc = index, asc
|
||||
func (v *Table) SetSortCol(index, count int, asc bool) {
|
||||
v.sortCol.index, v.sortCol.colCount, v.sortCol.asc = index, count, asc
|
||||
}
|
||||
|
||||
// Update table content.
|
||||
|
|
@ -127,6 +227,7 @@ func (v *Table) Update(data resource.TableData) {
|
|||
v.doUpdate(v.data)
|
||||
}
|
||||
v.UpdateTitle()
|
||||
v.updateSelection(false)
|
||||
}
|
||||
|
||||
func (v *Table) doUpdate(data resource.TableData) {
|
||||
|
|
@ -173,22 +274,6 @@ func (v *Table) SortColCmd(col int) func(evt *tcell.EventKey) *tcell.EventKey {
|
|||
}
|
||||
}
|
||||
|
||||
// ActivateCmd enters filter command mode
|
||||
func (v *Table) ActivateCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
// if v.app.inCmdMode() {
|
||||
// return evt
|
||||
// }
|
||||
|
||||
// v.app.flash().Info("Filter mode activated.")
|
||||
if isLabelSelector(v.cmdBuff.String()) {
|
||||
return nil
|
||||
}
|
||||
v.cmdBuff.Reset()
|
||||
v.cmdBuff.SetActive(true)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Table) adjustSorter(data resource.TableData) {
|
||||
// Going from namespace to non namespace or vice-versa?
|
||||
switch {
|
||||
|
|
@ -283,16 +368,43 @@ func (v *Table) AddHeaderCell(numerical bool, col int, name string) {
|
|||
v.SetCell(0, col, c)
|
||||
}
|
||||
|
||||
// BOZO!! Nuke?
|
||||
// func (v *Table) depFiltered() resource.TableData {
|
||||
// if v.cmdBuff.Empty() || isLabelSelector(v.cmdBuff.String()) {
|
||||
// return v.data
|
||||
// }
|
||||
|
||||
// rx, err := regexp.Compile(`(?i)` + v.cmdBuff.String())
|
||||
// if err != nil {
|
||||
// v.cmdBuff.Clear()
|
||||
// return v.data
|
||||
// }
|
||||
|
||||
// filtered := resource.TableData{
|
||||
// Header: v.data.Header,
|
||||
// Rows: resource.RowEvents{},
|
||||
// Namespace: v.data.Namespace,
|
||||
// }
|
||||
// for k, row := range v.data.Rows {
|
||||
// f := strings.Join(row.Fields, " ")
|
||||
// if rx.MatchString(f) {
|
||||
// filtered.Rows[k] = row
|
||||
// }
|
||||
// }
|
||||
|
||||
// return filtered
|
||||
// }
|
||||
|
||||
func (v *Table) filtered() resource.TableData {
|
||||
if v.cmdBuff.Empty() || isLabelSelector(v.cmdBuff.String()) {
|
||||
return v.data
|
||||
}
|
||||
|
||||
rx, err := regexp.Compile(`(?i)` + v.cmdBuff.String())
|
||||
if err != nil {
|
||||
// v.app.flash().Err(errors.New("Invalid filter expression"))
|
||||
v.cmdBuff.Clear()
|
||||
return v.data
|
||||
q := v.cmdBuff.String()
|
||||
var ss, kk []string
|
||||
for k, row := range v.data.Rows {
|
||||
ss = append(ss, strings.Join(row.Fields, " "))
|
||||
kk = append(kk, k)
|
||||
}
|
||||
|
||||
filtered := resource.TableData{
|
||||
|
|
@ -300,11 +412,9 @@ func (v *Table) filtered() resource.TableData {
|
|||
Rows: resource.RowEvents{},
|
||||
Namespace: v.data.Namespace,
|
||||
}
|
||||
for k, row := range v.data.Rows {
|
||||
f := strings.Join(row.Fields, " ")
|
||||
if rx.MatchString(f) {
|
||||
filtered.Rows[k] = row
|
||||
}
|
||||
mm := matching.FindAll(q, ss)
|
||||
for _, m := range mm {
|
||||
filtered.Rows[kk[m.Idx]] = v.data.Rows[kk[m.Idx]]
|
||||
}
|
||||
|
||||
return filtered
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ const (
|
|||
)
|
||||
|
||||
type aliasView struct {
|
||||
*ui.Table
|
||||
*tableView
|
||||
|
||||
app *appView
|
||||
current ui.Igniter
|
||||
|
|
@ -24,8 +24,8 @@ type aliasView struct {
|
|||
|
||||
func newAliasView(app *appView, current ui.Igniter) *aliasView {
|
||||
v := aliasView{
|
||||
Table: ui.NewTable(aliasTitle, app.Styles),
|
||||
app: app,
|
||||
tableView: newTableView(app, aliasTitle),
|
||||
app: app,
|
||||
}
|
||||
v.SetBorderFocusColor(tcell.ColorFuchsia)
|
||||
v.SetSelectedStyle(tcell.ColorWhite, tcell.ColorFuchsia, tcell.AttrNone)
|
||||
|
|
@ -46,13 +46,15 @@ func (v *aliasView) Init(context.Context, string) {
|
|||
}
|
||||
|
||||
func (v *aliasView) registerActions() {
|
||||
delete(v.KeyBindings(), ui.KeyShiftA)
|
||||
v.RmAction(ui.KeyShiftA)
|
||||
|
||||
v.KeyBindings()[tcell.KeyEnter] = ui.NewKeyAction("Goto", v.gotoCmd, true)
|
||||
v.KeyBindings()[tcell.KeyEscape] = ui.NewKeyAction("Reset", v.resetCmd, false)
|
||||
v.KeyBindings()[ui.KeySlash] = ui.NewKeyAction("Filter", v.ActivateCmd, false)
|
||||
v.KeyBindings()[ui.KeyShiftR] = ui.NewKeyAction("Sort Resources", v.SortColCmd(1), true)
|
||||
v.KeyBindings()[ui.KeyShiftO] = ui.NewKeyAction("Sort Groups", v.SortColCmd(2), true)
|
||||
v.SetActions(ui.KeyActions{
|
||||
tcell.KeyEnter: ui.NewKeyAction("Goto", v.gotoCmd, true),
|
||||
tcell.KeyEscape: ui.NewKeyAction("Reset", v.resetCmd, false),
|
||||
ui.KeySlash: ui.NewKeyAction("Filter", v.activateCmd, false),
|
||||
ui.KeyShiftR: ui.NewKeyAction("Sort Resources", v.SortColCmd(1), true),
|
||||
ui.KeyShiftO: ui.NewKeyAction("Sort Groups", v.SortColCmd(2), true),
|
||||
})
|
||||
}
|
||||
|
||||
func (v *aliasView) getTitle() string {
|
||||
|
|
@ -74,9 +76,9 @@ func (v *aliasView) gotoCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
return v.runCmd(evt)
|
||||
}
|
||||
|
||||
// if v.Cmd().IsActive() {
|
||||
// return v.filterCmd(evt)
|
||||
// }
|
||||
if v.Cmd().IsActive() {
|
||||
return v.activateCmd(evt)
|
||||
}
|
||||
|
||||
return evt
|
||||
}
|
||||
|
|
@ -104,10 +106,6 @@ func (v *aliasView) runCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *aliasView) Hints() ui.Hints {
|
||||
return v.KeyBindings().Hints()
|
||||
}
|
||||
|
||||
func (v *aliasView) hydrate() resource.TableData {
|
||||
cmds := make(map[string]resCmd, 40)
|
||||
aliasCmds(v.app.Conn(), cmds)
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ func (v *benchView) Init(ctx context.Context, _ string) {
|
|||
|
||||
v.refresh()
|
||||
tv := v.getTV()
|
||||
tv.SetSortCol(tv.NameColIndex()+7, true)
|
||||
tv.SetSortCol(tv.NameColIndex()+7, 0, true)
|
||||
tv.Refresh()
|
||||
tv.Select(1, 0)
|
||||
v.app.SetFocus(tv)
|
||||
|
|
@ -122,7 +122,7 @@ func (v *benchView) selChanged(r, c int) {
|
|||
func (v *benchView) sortColCmd(col int, asc bool) func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
return func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
tv := v.getTV()
|
||||
tv.SetSortCol(tv.NameColIndex()+col, asc)
|
||||
tv.SetSortCol(tv.NameColIndex()+col, 0, asc)
|
||||
tv.Refresh()
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -54,11 +54,11 @@ func (v *containerView) extraActions(aa ui.KeyActions) {
|
|||
}
|
||||
|
||||
func (v *containerView) selectedContainer() string {
|
||||
return v.selectedItem
|
||||
return v.masterPage().GetSelectedItem()
|
||||
}
|
||||
|
||||
func (v *containerView) viewLogs(app *appView, _, res, sel string) {
|
||||
status := ui.TrimCell(v.masterPage().Table, v.selectedRow, 3)
|
||||
status := v.masterPage().GetSelectedCell(3)
|
||||
if status == "Running" || status == "Completed" {
|
||||
v.showLogs(false)
|
||||
return
|
||||
|
|
@ -69,33 +69,34 @@ func (v *containerView) viewLogs(app *appView, _, res, sel string) {
|
|||
// Handlers...
|
||||
|
||||
func (v *containerView) shellCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.rowSelected() {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
v.stopUpdates()
|
||||
shellIn(v.app, *v.path, v.selectedItem)
|
||||
shellIn(v.app, *v.path, v.masterPage().GetSelectedItem())
|
||||
v.restartUpdates()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *containerView) portFwdCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.rowSelected() {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
if _, ok := v.app.forwarders[fwFQN(*v.path, v.selectedItem)]; ok {
|
||||
sel := v.masterPage().GetSelectedItem()
|
||||
if _, ok := v.app.forwarders[fwFQN(*v.path, sel)]; ok {
|
||||
v.app.Flash().Err(fmt.Errorf("A PortForward already exist on container %s", *v.path))
|
||||
return nil
|
||||
}
|
||||
|
||||
state := ui.TrimCell(v.masterPage().Table, v.selectedRow, 3)
|
||||
state := v.masterPage().GetSelectedCell(3)
|
||||
if state != "Running" {
|
||||
v.app.Flash().Err(fmt.Errorf("Container %s is not running?", v.selectedItem))
|
||||
v.app.Flash().Err(fmt.Errorf("Container %s is not running?", sel))
|
||||
return nil
|
||||
}
|
||||
|
||||
portC := ui.TrimCell(v.masterPage().Table, v.selectedRow, 10)
|
||||
portC := v.masterPage().GetSelectedCell(10)
|
||||
ports := strings.Split(portC, ",")
|
||||
if len(ports) == 0 {
|
||||
v.app.Flash().Err(errors.New("Container exposes no ports"))
|
||||
|
|
@ -121,8 +122,7 @@ func (v *containerView) portFwdCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
}
|
||||
|
||||
func (v *containerView) portForward(lport, cport string) {
|
||||
co := strings.TrimSpace(v.masterPage().GetCell(v.selectedRow, 0).Text)
|
||||
|
||||
co := v.masterPage().GetSelectedCell(0)
|
||||
pf := k8s.NewPortForward(v.app.Conn(), &log.Logger)
|
||||
ports := []string{lport + ":" + cport}
|
||||
fw, err := pf.Start(*v.path, co, ports)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ func newContextView(title string, app *appView, list resource.List) resourceView
|
|||
v := contextView{newResourceView(title, app, list).(*resourceView)}
|
||||
v.extraActionsFn = v.extraActions
|
||||
v.enterFn = v.useCtx
|
||||
v.masterPage().cleanseFn = v.cleanser
|
||||
v.masterPage().SetSelectedFn(v.cleanser)
|
||||
|
||||
return &v
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,15 +18,16 @@ func newCronJobView(t string, app *appView, list resource.List) resourceViewer {
|
|||
}
|
||||
|
||||
func (v *cronJobView) trigger(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.rowSelected() {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
if err := v.list.Resource().(resource.Runner).Run(v.selectedItem); err != nil {
|
||||
sel := v.masterPage().GetSelectedItem()
|
||||
if err := v.list.Resource().(resource.Runner).Run(sel); err != nil {
|
||||
v.app.Flash().Errf("Cronjob trigger failed %v", err)
|
||||
return evt
|
||||
}
|
||||
v.app.Flash().Infof("Triggering %s %s", v.list.GetName(), v.selectedItem)
|
||||
v.app.Flash().Infof("Triggering %s %s", v.list.GetName(), sel)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,28 +30,21 @@ var (
|
|||
type dumpView struct {
|
||||
*tview.Pages
|
||||
|
||||
app *appView
|
||||
cancel context.CancelFunc
|
||||
selectedItem string
|
||||
selectedRow int
|
||||
actions ui.KeyActions
|
||||
app *appView
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func newDumpView(_ string, app *appView, _ resource.List) resourceViewer {
|
||||
v := dumpView{
|
||||
Pages: tview.NewPages(),
|
||||
actions: make(ui.KeyActions),
|
||||
app: app,
|
||||
Pages: tview.NewPages(),
|
||||
app: app,
|
||||
}
|
||||
|
||||
tv := newTableView(app, dumpTitle)
|
||||
{
|
||||
tv.SetSelectionChangedFunc(v.selChanged)
|
||||
tv.SetBorderFocusColor(tcell.ColorSteelBlue)
|
||||
tv.SetSelectedStyle(tcell.ColorWhite, tcell.ColorRoyalBlue, tcell.AttrNone)
|
||||
tv.SetColorerFn(dumpColorer)
|
||||
tv.SetActiveNS("")
|
||||
}
|
||||
tv.SetBorderFocusColor(tcell.ColorSteelBlue)
|
||||
tv.SetSelectedStyle(tcell.ColorWhite, tcell.ColorRoyalBlue, tcell.AttrNone)
|
||||
tv.SetColorerFn(dumpColorer)
|
||||
tv.SetActiveNS("")
|
||||
v.AddPage("table", tv, true, true)
|
||||
|
||||
details := newDetailsView(app, v.backCmd)
|
||||
|
|
@ -74,9 +67,9 @@ func (v *dumpView) Init(ctx context.Context, _ string) {
|
|||
|
||||
tv := v.getTV()
|
||||
v.refresh()
|
||||
tv.SetSortCol(tv.NameColIndex()+1, true)
|
||||
tv.SetSortCol(tv.NameColIndex()+1, 0, true)
|
||||
tv.Refresh()
|
||||
tv.Select(1, 0)
|
||||
tv.SelectRow(1, true)
|
||||
v.app.SetFocus(tv)
|
||||
}
|
||||
|
||||
|
|
@ -84,49 +77,41 @@ func (v *dumpView) refresh() {
|
|||
tv := v.getTV()
|
||||
tv.Update(v.hydrate())
|
||||
tv.UpdateTitle()
|
||||
v.selChanged(v.selectedRow, 0)
|
||||
}
|
||||
|
||||
func (v *dumpView) registerActions() {
|
||||
v.actions[ui.KeyP] = ui.NewKeyAction("Previous", v.app.prevCmd, false)
|
||||
v.actions[tcell.KeyEnter] = ui.NewKeyAction("Enter", v.enterCmd, true)
|
||||
v.actions[tcell.KeyCtrlD] = ui.NewKeyAction("Delete", v.deleteCmd, true)
|
||||
v.actions[tcell.KeyCtrlS] = ui.NewKeyAction("Save", noopCmd, false)
|
||||
aa := ui.KeyActions{
|
||||
ui.KeyP: ui.NewKeyAction("Previous", v.app.prevCmd, false),
|
||||
tcell.KeyEnter: ui.NewKeyAction("Enter", v.enterCmd, true),
|
||||
tcell.KeyCtrlD: ui.NewKeyAction("Delete", v.deleteCmd, true),
|
||||
tcell.KeyCtrlS: ui.NewKeyAction("Save", noopCmd, false),
|
||||
}
|
||||
|
||||
vu := v.getTV()
|
||||
vu.SetActions(v.actions)
|
||||
v.app.SetHints(vu.Hints())
|
||||
tv := v.getTV()
|
||||
tv.SetActions(aa)
|
||||
v.app.SetHints(tv.Hints())
|
||||
}
|
||||
|
||||
func (v *dumpView) getTitle() string {
|
||||
return dumpTitle
|
||||
}
|
||||
|
||||
func (v *dumpView) selChanged(r, c int) {
|
||||
log.Debug().Msgf("Selection changed %d:%c", r, c)
|
||||
tv := v.getTV()
|
||||
if r == 0 || tv.GetCell(r, 0) == nil {
|
||||
v.selectedItem = ""
|
||||
return
|
||||
}
|
||||
v.selectedRow = r
|
||||
v.selectedItem = ui.TrimCell(tv.Table, r, 0)
|
||||
}
|
||||
|
||||
func (v *dumpView) sortColCmd(col int, asc bool) func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
return func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
tv := v.getTV()
|
||||
tv.SetSortCol(tv.NameColIndex()+col, asc)
|
||||
tv.SetSortCol(tv.NameColIndex()+col, 0, asc)
|
||||
tv.Refresh()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (v *dumpView) enterCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if v.getTV().Cmd().IsActive() {
|
||||
return v.getTV().filterCmd(evt)
|
||||
log.Debug().Msg("Dump enter!")
|
||||
tv := v.getTV()
|
||||
if tv.Cmd().IsActive() {
|
||||
return tv.filterCmd(evt)
|
||||
}
|
||||
sel := v.selectedItem
|
||||
sel := tv.GetSelectedItem()
|
||||
if sel == "" {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -140,7 +125,7 @@ func (v *dumpView) enterCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
}
|
||||
|
||||
func (v *dumpView) deleteCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
sel := v.selectedItem
|
||||
sel := v.getTV().GetSelectedItem()
|
||||
if sel == "" {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ func execute(clear bool, bin string, args ...string) error {
|
|||
cmd := exec.Command(bin, args...)
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
err := cmd.Run()
|
||||
log.Debug().Msgf("Command return status %v", err)
|
||||
log.Debug().Msgf("Command returned error?? %v", err)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return errors.New("canceled by operator")
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ func (v *forwardView) Init(ctx context.Context, _ string) {
|
|||
|
||||
tv := v.getTV()
|
||||
v.refresh()
|
||||
tv.SetSortCol(tv.NameColIndex()+6, true)
|
||||
tv.SetSortCol(tv.NameColIndex()+6, 0, true)
|
||||
tv.Refresh()
|
||||
tv.Select(1, 0)
|
||||
v.app.SetFocus(tv)
|
||||
|
|
@ -100,7 +100,7 @@ func (v *forwardView) registerActions() {
|
|||
tcell.KeyCtrlB: ui.NewKeyAction("Bench", v.benchCmd, true),
|
||||
ui.KeyAltB: ui.NewKeyAction("Bench Stop", v.benchStopCmd, true),
|
||||
tcell.KeyCtrlD: ui.NewKeyAction("Delete", v.deleteCmd, true),
|
||||
ui.KeySlash: ui.NewKeyAction("Filter", tv.ActivateCmd, false),
|
||||
ui.KeySlash: ui.NewKeyAction("Filter", tv.activateCmd, false),
|
||||
ui.KeyP: ui.NewKeyAction("Previous", v.app.prevCmd, false),
|
||||
ui.KeyShiftP: ui.NewKeyAction("Sort Ports", v.sortColCmd(2, true), true),
|
||||
ui.KeyShiftU: ui.NewKeyAction("Sort URL", v.sortColCmd(4, true), true),
|
||||
|
|
@ -114,7 +114,7 @@ func (v *forwardView) getTitle() string {
|
|||
func (v *forwardView) sortColCmd(col int, asc bool) func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
return func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
tv := v.getTV()
|
||||
tv.SetSortCol(tv.NameColIndex()+col, asc)
|
||||
tv.SetSortCol(tv.NameColIndex()+col, 0, asc)
|
||||
v.refresh()
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ func (v *logResourceView) extraActions(aa ui.KeyActions) {
|
|||
func (v *logResourceView) sortColCmd(col int, asc bool) func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
return func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
t := v.masterPage()
|
||||
t.SetSortCol(t.NameColIndex()+col, asc)
|
||||
t.SetSortCol(t.NameColIndex()+col, 0, asc)
|
||||
t.Refresh()
|
||||
|
||||
return nil
|
||||
|
|
@ -50,7 +50,7 @@ func (v *logResourceView) getSelection() string {
|
|||
if v.path != nil {
|
||||
return *v.path
|
||||
}
|
||||
return v.selectedItem
|
||||
return v.masterPage().GetSelectedItem()
|
||||
}
|
||||
|
||||
func (v *logResourceView) prevLogsCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
|
|
@ -64,7 +64,7 @@ func (v *logResourceView) logsCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
}
|
||||
|
||||
func (v *logResourceView) showLogs(prev bool) {
|
||||
if !v.rowSelected() {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,23 +2,17 @@ package views
|
|||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
|
||||
"github.com/derailed/k9s/internal/resource"
|
||||
"github.com/derailed/k9s/internal/ui"
|
||||
"github.com/derailed/tview"
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
||||
type (
|
||||
pageView struct {
|
||||
*tview.Pages
|
||||
|
||||
app *appView
|
||||
actions ui.KeyActions
|
||||
selectedItem string
|
||||
selectedRow int
|
||||
selectedFn func() string
|
||||
app *appView
|
||||
}
|
||||
|
||||
masterDetail struct {
|
||||
|
|
@ -33,9 +27,8 @@ type (
|
|||
|
||||
func newPageView(app *appView) *pageView {
|
||||
return &pageView{
|
||||
Pages: tview.NewPages(),
|
||||
app: app,
|
||||
actions: make(ui.KeyActions),
|
||||
Pages: tview.NewPages(),
|
||||
app: app,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -45,12 +38,8 @@ func newMasterDetail(title, ns string, app *appView, backCmd ui.ActionHandler) *
|
|||
currentNS: ns,
|
||||
title: title,
|
||||
}
|
||||
tv := newTableView(v.app, v.title)
|
||||
tv.SetSelectionChangedFunc(v.selChanged)
|
||||
v.AddPage("master", tv, true, true)
|
||||
|
||||
details := newDetailsView(v.app, backCmd)
|
||||
v.AddPage("details", details, true, false)
|
||||
v.AddPage("master", newTableView(v.app, v.title), true, true)
|
||||
v.AddPage("details", newDetailsView(v.app, backCmd), true, false)
|
||||
|
||||
return &v
|
||||
}
|
||||
|
|
@ -62,33 +51,8 @@ func (v *masterDetail) init(ctx context.Context, ns string) {
|
|||
}
|
||||
|
||||
func (v *masterDetail) setExtraActionsFn(f ui.ActionsFunc) {
|
||||
f(v.actions)
|
||||
}
|
||||
|
||||
func (v *masterDetail) rowSelected() bool {
|
||||
return v.selectedItem != ""
|
||||
}
|
||||
|
||||
func (v *masterDetail) selChanged(r, c int) {
|
||||
v.selectedRow = r
|
||||
v.selectItem(r, c)
|
||||
if r == 0 {
|
||||
return
|
||||
}
|
||||
tv := v.masterPage()
|
||||
cell := tv.GetCell(r, c)
|
||||
tv.SetSelectedStyle(
|
||||
cell.BackgroundColor,
|
||||
cell.Color,
|
||||
tcell.AttrBold,
|
||||
)
|
||||
}
|
||||
|
||||
func (v *masterDetail) getSelectedItem() string {
|
||||
if v.selectedFn != nil {
|
||||
return v.selectedFn()
|
||||
}
|
||||
return v.selectedItem
|
||||
v.extraActionsFn = f
|
||||
// f(v.actions)
|
||||
}
|
||||
|
||||
// Protocol...
|
||||
|
|
@ -113,29 +77,11 @@ func (v *masterDetail) detailsPage() *detailsView {
|
|||
// ----------------------------------------------------------------------------
|
||||
// Actions...
|
||||
|
||||
func (v *masterDetail) selectItem(r, c int) {
|
||||
t := v.masterPage()
|
||||
if r == 0 || t.GetCell(r, 0) == nil {
|
||||
v.selectedItem = ""
|
||||
return
|
||||
}
|
||||
|
||||
col0 := ui.TrimCell(t.Table, r, 0)
|
||||
switch v.currentNS {
|
||||
case resource.NotNamespaced:
|
||||
v.selectedItem = col0
|
||||
case resource.AllNamespace, resource.AllNamespaces:
|
||||
v.selectedItem = path.Join(col0, ui.TrimCell(t.Table, r, 1))
|
||||
default:
|
||||
v.selectedItem = path.Join(v.currentNS, col0)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *masterDetail) defaultActions() {
|
||||
v.actions[ui.KeyHelp] = ui.NewKeyAction("Help", noopCmd, false)
|
||||
v.actions[ui.KeyP] = ui.NewKeyAction("Previous", v.app.prevCmd, false)
|
||||
func (v *masterDetail) defaultActions(aa ui.KeyActions) {
|
||||
aa[ui.KeyHelp] = ui.NewKeyAction("Help", noopCmd, false)
|
||||
aa[ui.KeyP] = ui.NewKeyAction("Previous", v.app.prevCmd, false)
|
||||
|
||||
if v.extraActionsFn != nil {
|
||||
v.extraActionsFn(v.actions)
|
||||
v.extraActionsFn(aa)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ func (v *nodeView) extraActions(aa ui.KeyActions) {
|
|||
func (v *nodeView) sortColCmd(col int, asc bool) func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
return func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
t := v.masterPage()
|
||||
t.SetSortCol(t.NameColIndex()+col, asc)
|
||||
t.SetSortCol(t.NameColIndex()+col, 0, asc)
|
||||
t.Refresh()
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
"github.com/derailed/k9s/internal/resource"
|
||||
"github.com/derailed/k9s/internal/ui"
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -25,10 +24,9 @@ type namespaceView struct {
|
|||
func newNamespaceView(t string, app *appView, list resource.List) resourceViewer {
|
||||
v := namespaceView{newResourceView(t, app, list).(*resourceView)}
|
||||
v.extraActionsFn = v.extraActions
|
||||
v.selectedFn = v.getSelectedItem
|
||||
v.masterPage().SetSelectedFn(v.cleanser)
|
||||
v.decorateFn = v.decorate
|
||||
v.enterFn = v.switchNs
|
||||
v.masterPage().cleanseFn = v.cleanser
|
||||
|
||||
return &v
|
||||
}
|
||||
|
|
@ -38,15 +36,15 @@ func (v *namespaceView) extraActions(aa ui.KeyActions) {
|
|||
}
|
||||
|
||||
func (v *namespaceView) switchNs(app *appView, _, res, sel string) {
|
||||
v.useNamespace(v.cleanser(sel))
|
||||
v.useNamespace(sel)
|
||||
app.gotoResource("po", true)
|
||||
}
|
||||
|
||||
func (v *namespaceView) useNsCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.rowSelected() {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
v.useNamespace(v.getSelectedItem())
|
||||
v.useNamespace(v.masterPage().GetSelectedItem())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -60,12 +58,7 @@ func (v *namespaceView) useNamespace(ns string) {
|
|||
v.app.Config.Save()
|
||||
}
|
||||
|
||||
func (v *namespaceView) getSelectedItem() string {
|
||||
return v.cleanser(v.selectedItem)
|
||||
}
|
||||
|
||||
func (*namespaceView) cleanser(s string) string {
|
||||
log.Debug().Msgf("SWITCHING: %s-%s", s, nsCleanser.ReplaceAllString(s, `$1`))
|
||||
return nsCleanser.ReplaceAllString(s, `$1`)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,23 +50,21 @@ func newPodView(t string, app *appView, list resource.List) resourceViewer {
|
|||
}
|
||||
|
||||
func (v *podView) extraActions(aa ui.KeyActions) {
|
||||
actions := ui.KeyActions{
|
||||
ui.KeyL: ui.NewKeyAction("Logs", v.logsCmd, true),
|
||||
ui.KeyShiftL: ui.NewKeyAction("Logs Previous", v.prevLogsCmd, true),
|
||||
ui.KeyS: ui.NewKeyAction("Shell", v.shellCmd, true),
|
||||
ui.KeyShiftR: ui.NewKeyAction("Sort Ready", v.sortColCmd(1, false), true),
|
||||
ui.KeyShiftS: ui.NewKeyAction("Sort Status", v.sortColCmd(2, true), true),
|
||||
ui.KeyShiftT: ui.NewKeyAction("Sort Restart", v.sortColCmd(3, false), true),
|
||||
ui.KeyShiftC: ui.NewKeyAction("Sort CPU", v.sortColCmd(4, false), true),
|
||||
ui.KeyShiftM: ui.NewKeyAction("Sort MEM", v.sortColCmd(5, false), true),
|
||||
ui.KeyAltC: ui.NewKeyAction("Sort CPU%", v.sortColCmd(6, false), true),
|
||||
ui.KeyAltM: ui.NewKeyAction("Sort MEM%", v.sortColCmd(7, false), true),
|
||||
ui.KeyShiftD: ui.NewKeyAction("Sort IP", v.sortColCmd(8, true), true),
|
||||
ui.KeyShiftO: ui.NewKeyAction("Sort Node", v.sortColCmd(9, true), true),
|
||||
}
|
||||
for k, v := range actions {
|
||||
aa[k] = v
|
||||
}
|
||||
aa[ui.KeyAltK] = ui.NewKeyAction("Kill", v.killCmd, true)
|
||||
aa[ui.KeyS] = ui.NewKeyAction("Shell", v.shellCmd, true)
|
||||
|
||||
aa[ui.KeyL] = ui.NewKeyAction("Logs", v.logsCmd, true)
|
||||
aa[ui.KeyShiftL] = ui.NewKeyAction("Logs Previous", v.prevLogsCmd, true)
|
||||
|
||||
aa[ui.KeyShiftR] = ui.NewKeyAction("Sort Ready", v.sortColCmd(1, false), true)
|
||||
aa[ui.KeyShiftS] = ui.NewKeyAction("Sort Status", v.sortColCmd(2, true), true)
|
||||
aa[ui.KeyShiftT] = ui.NewKeyAction("Sort Restart", v.sortColCmd(3, false), true)
|
||||
aa[ui.KeyShiftC] = ui.NewKeyAction("Sort CPU", v.sortColCmd(4, false), true)
|
||||
aa[ui.KeyShiftM] = ui.NewKeyAction("Sort MEM", v.sortColCmd(5, false), true)
|
||||
aa[ui.KeyAltC] = ui.NewKeyAction("Sort CPU%", v.sortColCmd(6, false), true)
|
||||
aa[ui.KeyAltM] = ui.NewKeyAction("Sort MEM%", v.sortColCmd(7, false), true)
|
||||
aa[ui.KeyShiftD] = ui.NewKeyAction("Sort IP", v.sortColCmd(8, true), true)
|
||||
aa[ui.KeyShiftO] = ui.NewKeyAction("Sort Node", v.sortColCmd(9, true), true)
|
||||
}
|
||||
|
||||
func (v *podView) listContainers(app *appView, _, res, sel string) {
|
||||
|
|
@ -109,15 +107,31 @@ func (v *podView) getList() resource.List {
|
|||
}
|
||||
|
||||
func (v *podView) getSelection() string {
|
||||
return v.selectedItem
|
||||
return v.masterPage().GetSelectedItem()
|
||||
}
|
||||
|
||||
func (v *podView) sniffCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.rowSelected() {
|
||||
func (v *podView) killCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
ns, n := namespaced(v.selectedItem)
|
||||
sel := v.masterPage().GetSelectedItem()
|
||||
v.masterPage().ShowDeleted()
|
||||
v.app.Flash().Infof("Delete resource %s %s", v.list.GetName(), sel)
|
||||
if err := v.list.Resource().Delete(sel, true, false); err != nil {
|
||||
v.app.Flash().Errf("Delete failed with %s", err)
|
||||
} else {
|
||||
v.refresh()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *podView) sniffCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
ns, n := namespaced(v.masterPage().GetSelectedItem())
|
||||
var args []string
|
||||
args = append(args, "sniff", n, "-n", ns)
|
||||
|
||||
|
|
@ -146,10 +160,10 @@ func (v *podView) prevLogsCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
}
|
||||
|
||||
func (v *podView) viewLogs(prev bool) bool {
|
||||
if !v.rowSelected() {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return false
|
||||
}
|
||||
v.showLogs(v.selectedItem, "", v, prev)
|
||||
v.showLogs(v.masterPage().GetSelectedItem(), "", v, prev)
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
@ -161,23 +175,24 @@ func (v *podView) showLogs(path, co string, parent loggable, prev bool) {
|
|||
}
|
||||
|
||||
func (v *podView) shellCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.rowSelected() {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
cc, err := fetchContainers(v.list, v.selectedItem, false)
|
||||
sel := v.masterPage().GetSelectedItem()
|
||||
cc, err := fetchContainers(v.list, sel, false)
|
||||
if err != nil {
|
||||
v.app.Flash().Errf("Unable to retrieve containers %s", err)
|
||||
return evt
|
||||
}
|
||||
if len(cc) == 1 {
|
||||
v.shellIn(v.selectedItem, "")
|
||||
v.shellIn(sel, "")
|
||||
return nil
|
||||
}
|
||||
p := v.GetPrimitive("picker").(*selectList)
|
||||
p.populate(cc)
|
||||
p.SetSelectedFunc(func(i int, t, d string, r rune) {
|
||||
v.shellIn(v.selectedItem, t)
|
||||
v.shellIn(sel, t)
|
||||
})
|
||||
v.switchPage("picker")
|
||||
|
||||
|
|
@ -193,7 +208,7 @@ func (v *podView) shellIn(path, co string) {
|
|||
func (v *podView) sortColCmd(col int, asc bool) func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
return func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
t := v.masterPage()
|
||||
t.SetSortCol(t.NameColIndex()+col, asc)
|
||||
t.SetSortCol(t.NameColIndex()+col, 0, asc)
|
||||
t.Refresh()
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ func newPolicyView(app *appView, subject, name string) *policyView {
|
|||
|
||||
// Init the view.
|
||||
func (v *policyView) Init(c context.Context, ns string) {
|
||||
v.SetSortCol(len(rbacHeader), false)
|
||||
v.SetSortCol(1, len(rbacHeader), false)
|
||||
|
||||
ctx, cancel := context.WithCancel(c)
|
||||
v.cancel = cancel
|
||||
|
|
@ -65,6 +65,7 @@ func (v *policyView) Init(c context.Context, ns string) {
|
|||
}(ctx)
|
||||
|
||||
v.refresh()
|
||||
v.SelectRow(1, true)
|
||||
v.app.SetFocus(v)
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +74,7 @@ func (v *policyView) bindKeys() {
|
|||
|
||||
v.SetActions(ui.KeyActions{
|
||||
tcell.KeyEscape: ui.NewKeyAction("Reset", v.resetCmd, false),
|
||||
ui.KeySlash: ui.NewKeyAction("Filter", v.ActivateCmd, false),
|
||||
ui.KeySlash: ui.NewKeyAction("Filter", v.activateCmd, false),
|
||||
ui.KeyP: ui.NewKeyAction("Previous", v.app.prevCmd, false),
|
||||
ui.KeyShiftS: ui.NewKeyAction("Sort Namespace", v.SortColCmd(0), true),
|
||||
ui.KeyShiftN: ui.NewKeyAction("Sort Name", v.SortColCmd(1), true),
|
||||
|
|
@ -254,11 +255,11 @@ func (v *policyView) parseRules(ns, binding string, rules []rbacv1.PolicyRule) r
|
|||
for _, na := range r.ResourceNames {
|
||||
n := fqn(k, na)
|
||||
m[fqn(ns, n)] = &resource.RowEvent{
|
||||
Fields: append(policyRow(ns, n, grp, binding), r.Verbs...),
|
||||
Fields: append(policyRow(ns, n, grp, binding), asVerbs(r.Verbs...)...),
|
||||
}
|
||||
}
|
||||
m[fqn(ns, k)] = &resource.RowEvent{
|
||||
Fields: append(policyRow(ns, k, grp, binding), r.Verbs...),
|
||||
Fields: append(policyRow(ns, k, grp, binding), asVerbs(r.Verbs...)...),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -267,7 +268,7 @@ func (v *policyView) parseRules(ns, binding string, rules []rbacv1.PolicyRule) r
|
|||
nres = "/" + nres
|
||||
}
|
||||
m[fqn(ns, nres)] = &resource.RowEvent{
|
||||
Fields: append(policyRow(ns, nres, resource.NAValue, binding), r.Verbs...),
|
||||
Fields: append(policyRow(ns, nres, resource.NAValue, binding), asVerbs(r.Verbs...)...),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,8 +80,11 @@ type (
|
|||
)
|
||||
|
||||
func newRBACView(app *appView, ns, name string, kind roleKind) *rbacView {
|
||||
v := rbacView{app: app}
|
||||
v.roleName, v.roleType = name, kind
|
||||
v := rbacView{
|
||||
app: app,
|
||||
roleName: name,
|
||||
roleType: kind,
|
||||
}
|
||||
v.tableView = newTableView(app, v.getTitle())
|
||||
v.SetActiveNS(ns)
|
||||
v.SetColorerFn(rbacColorer)
|
||||
|
|
@ -93,7 +96,7 @@ func newRBACView(app *appView, ns, name string, kind roleKind) *rbacView {
|
|||
|
||||
// Init the view.
|
||||
func (v *rbacView) Init(c context.Context, ns string) {
|
||||
v.SetSortCol(len(rbacHeader), true)
|
||||
v.SetSortCol(1, len(rbacHeader), true)
|
||||
|
||||
ctx, cancel := context.WithCancel(c)
|
||||
v.cancel = cancel
|
||||
|
|
@ -120,7 +123,7 @@ func (v *rbacView) bindKeys() {
|
|||
|
||||
v.SetActions(ui.KeyActions{
|
||||
tcell.KeyEscape: ui.NewKeyAction("Reset", v.resetCmd, false),
|
||||
ui.KeySlash: ui.NewKeyAction("Filter", v.ActivateCmd, false),
|
||||
ui.KeySlash: ui.NewKeyAction("Filter", v.activateCmd, false),
|
||||
ui.KeyP: ui.NewKeyAction("Previous", v.app.prevCmd, false),
|
||||
ui.KeyShiftO: ui.NewKeyAction("Sort APIGroup", v.SortColCmd(1), true),
|
||||
})
|
||||
|
|
@ -130,10 +133,6 @@ func (v *rbacView) getTitle() string {
|
|||
return skinTitle(fmt.Sprintf(rbacTitleFmt, rbacTitle, v.roleName), v.app.Styles.Frame())
|
||||
}
|
||||
|
||||
func (v *rbacView) Hints() ui.Hints {
|
||||
return v.Hints()
|
||||
}
|
||||
|
||||
func (v *rbacView) refresh() {
|
||||
data, err := v.reconcile(v.ActiveNS(), v.roleName, v.roleType)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/atotto/clipboard"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/resource"
|
||||
"github.com/derailed/k9s/internal/ui"
|
||||
|
|
@ -140,18 +142,30 @@ func (v *resourceView) switchPage(p string) {
|
|||
// ----------------------------------------------------------------------------
|
||||
// Actions...
|
||||
|
||||
func (v *resourceView) cpCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
_, n := namespaced(v.masterPage().GetSelectedItem())
|
||||
log.Debug().Msgf("Copied selection to clipboard %q", n)
|
||||
v.app.Flash().Info("Current selection copied to clipboard...")
|
||||
clipboard.WriteAll(n)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *resourceView) enterCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
log.Debug().Msg("ResourceV Got Enter")
|
||||
// If in command mode run filter otherwise enter function.
|
||||
if v.masterPage().filterCmd(evt) == nil || !v.rowSelected() {
|
||||
if v.masterPage().filterCmd(evt) == nil || !v.masterPage().RowSelected() {
|
||||
return nil
|
||||
}
|
||||
|
||||
sel := v.masterPage().GetSelectedItem()
|
||||
if v.enterFn != nil {
|
||||
log.Debug().Msg("Custom enter!!")
|
||||
v.enterFn(v.app, v.list.GetNamespace(), v.list.GetName(), v.selectedItem)
|
||||
v.enterFn(v.app, v.list.GetNamespace(), v.list.GetName(), sel)
|
||||
} else {
|
||||
v.defaultEnter(v.list.GetNamespace(), v.list.GetName(), v.selectedItem)
|
||||
v.defaultEnter(v.list.GetNamespace(), v.list.GetName(), sel)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -164,11 +178,11 @@ func (v *resourceView) refreshCmd(*tcell.EventKey) *tcell.EventKey {
|
|||
}
|
||||
|
||||
func (v *resourceView) deleteCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.rowSelected() {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
sel := v.getSelectedItem()
|
||||
sel := v.masterPage().GetSelectedItem()
|
||||
msg := fmt.Sprintf("Delete %s %s?", v.list.GetName(), sel)
|
||||
dialog.ShowDelete(v.Pages, msg, func(cascade, force bool) {
|
||||
v.masterPage().ShowDeleted()
|
||||
|
|
@ -206,20 +220,20 @@ func (v *resourceView) defaultEnter(ns, _, selection string) {
|
|||
}
|
||||
|
||||
func (v *resourceView) describeCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.rowSelected() {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
v.defaultEnter(v.list.GetNamespace(), v.list.GetName(), v.selectedItem)
|
||||
v.defaultEnter(v.list.GetNamespace(), v.list.GetName(), v.masterPage().GetSelectedItem())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *resourceView) viewCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.rowSelected() {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
sel := v.getSelectedItem()
|
||||
sel := v.masterPage().GetSelectedItem()
|
||||
raw, err := v.list.Resource().Marshal(sel)
|
||||
if err != nil {
|
||||
v.app.Flash().Errf("Unable to marshal resource %s", err)
|
||||
|
|
@ -237,14 +251,14 @@ func (v *resourceView) viewCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
}
|
||||
|
||||
func (v *resourceView) editCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.rowSelected() {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
kcfg := v.app.Conn().Config().Flags().KubeConfig
|
||||
v.stopUpdates()
|
||||
{
|
||||
ns, po := namespaced(v.selectedItem)
|
||||
ns, po := namespaced(v.masterPage().GetSelectedItem())
|
||||
args := make([]string, 0, 10)
|
||||
args = append(args, "edit")
|
||||
args = append(args, v.list.GetName())
|
||||
|
|
@ -281,8 +295,7 @@ func (v *resourceView) switchNamespaceCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
v.app.Flash().Infof("Viewing `%s namespace...", ns)
|
||||
v.refresh()
|
||||
v.masterPage().UpdateTitle()
|
||||
v.masterPage().Select(1, 0)
|
||||
v.selectItem(1, 0)
|
||||
v.masterPage().SelectRow(1, true)
|
||||
v.app.GetCmdBuff().Reset()
|
||||
v.app.Config.SetActiveNamespace(v.currentNS)
|
||||
v.app.Config.Save()
|
||||
|
|
@ -307,10 +320,9 @@ func (v *resourceView) refresh() {
|
|||
data = v.decorateFn(data)
|
||||
}
|
||||
v.masterPage().Update(data)
|
||||
v.selectItem(v.selectedRow, 0)
|
||||
}
|
||||
|
||||
func (v *resourceView) namespaceActions() {
|
||||
func (v *resourceView) namespaceActions(aa ui.KeyActions) {
|
||||
if !v.list.Access(resource.NamespaceAccess) {
|
||||
return
|
||||
}
|
||||
|
|
@ -319,40 +331,105 @@ func (v *resourceView) namespaceActions() {
|
|||
if v.app.Conn().CheckListNSAccess() != nil {
|
||||
return
|
||||
}
|
||||
v.actions[tcell.Key(ui.NumKeys[0])] = ui.NewKeyAction(resource.AllNamespace, v.switchNamespaceCmd, true)
|
||||
aa[tcell.Key(ui.NumKeys[0])] = ui.NewKeyAction(resource.AllNamespace, v.switchNamespaceCmd, true)
|
||||
v.namespaces[0] = resource.AllNamespace
|
||||
index := 1
|
||||
for _, n := range v.app.Config.FavNamespaces() {
|
||||
if n == resource.AllNamespace {
|
||||
continue
|
||||
}
|
||||
v.actions[tcell.Key(ui.NumKeys[index])] = ui.NewKeyAction(n, v.switchNamespaceCmd, true)
|
||||
aa[tcell.Key(ui.NumKeys[index])] = ui.NewKeyAction(n, v.switchNamespaceCmd, true)
|
||||
v.namespaces[index] = n
|
||||
index++
|
||||
}
|
||||
}
|
||||
|
||||
func (v *resourceView) refreshActions() {
|
||||
v.namespaceActions()
|
||||
v.defaultActions()
|
||||
|
||||
v.actions[tcell.KeyEnter] = ui.NewKeyAction("Enter", v.enterCmd, false)
|
||||
v.actions[tcell.KeyCtrlR] = ui.NewKeyAction("Refresh", v.refreshCmd, false)
|
||||
aa := ui.KeyActions{
|
||||
ui.KeyC: ui.NewKeyAction("Copy", v.cpCmd, false),
|
||||
tcell.KeyEnter: ui.NewKeyAction("Enter", v.enterCmd, false),
|
||||
tcell.KeyCtrlR: ui.NewKeyAction("Refresh", v.refreshCmd, false),
|
||||
}
|
||||
v.namespaceActions(aa)
|
||||
v.defaultActions(aa)
|
||||
|
||||
if v.list.Access(resource.EditAccess) {
|
||||
v.actions[ui.KeyE] = ui.NewKeyAction("Edit", v.editCmd, true)
|
||||
aa[ui.KeyE] = ui.NewKeyAction("Edit", v.editCmd, true)
|
||||
}
|
||||
if v.list.Access(resource.DeleteAccess) {
|
||||
v.actions[tcell.KeyCtrlD] = ui.NewKeyAction("Delete", v.deleteCmd, true)
|
||||
aa[tcell.KeyCtrlD] = ui.NewKeyAction("Delete", v.deleteCmd, true)
|
||||
}
|
||||
if v.list.Access(resource.ViewAccess) {
|
||||
v.actions[ui.KeyY] = ui.NewKeyAction("YAML", v.viewCmd, true)
|
||||
aa[ui.KeyY] = ui.NewKeyAction("YAML", v.viewCmd, true)
|
||||
}
|
||||
if v.list.Access(resource.DescribeAccess) {
|
||||
v.actions[ui.KeyD] = ui.NewKeyAction("Describe", v.describeCmd, true)
|
||||
aa[ui.KeyD] = ui.NewKeyAction("Describe", v.describeCmd, true)
|
||||
}
|
||||
v.customActions(aa)
|
||||
|
||||
t := v.masterPage()
|
||||
t.SetActions(v.actions)
|
||||
t.SetActions(aa)
|
||||
v.app.SetHints(t.Hints())
|
||||
}
|
||||
|
||||
func in(ss []string, s string) bool {
|
||||
for _, v := range ss {
|
||||
if v == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func asKey(key string) (tcell.Key, error) {
|
||||
for k, v := range tcell.KeyNames {
|
||||
if v == key {
|
||||
return k, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("No matching key found %s", key)
|
||||
}
|
||||
|
||||
func (v *resourceView) customActions(aa ui.KeyActions) {
|
||||
for _, plugin := range v.app.Config.K9s.Plugins {
|
||||
if !in(plugin.Scopes, v.list.GetName()) {
|
||||
continue
|
||||
}
|
||||
key, err := asKey(strings.ToUpper(plugin.ShortCut))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Unable to map shortcut to a key")
|
||||
continue
|
||||
}
|
||||
aa[key] = ui.NewKeyAction(
|
||||
plugin.Description,
|
||||
v.execCmd(plugin.Command, plugin.Args...),
|
||||
true)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *resourceView) execCmd(bin string, args ...string) ui.ActionHandler {
|
||||
return func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
ns, n := namespaced(v.masterPage().GetSelectedItem())
|
||||
for i, a := range args {
|
||||
switch a {
|
||||
case "$NAMESPACE":
|
||||
args[i] = ns
|
||||
case "$NAME":
|
||||
args[i] = n
|
||||
}
|
||||
}
|
||||
|
||||
if run(true, v.app, bin, args...) {
|
||||
v.app.Flash().Info("Custom CMD launched!")
|
||||
} else {
|
||||
v.app.Flash().Info("Custom CMD failed!")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ func (v *replicaSetView) extraActions(aa ui.KeyActions) {
|
|||
func (v *replicaSetView) sortColCmd(col int, asc bool) func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
return func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
t := v.masterPage()
|
||||
t.SetSortCol(t.NameColIndex()+col, asc)
|
||||
t.SetSortCol(t.NameColIndex()+col, 0, asc)
|
||||
t.Refresh()
|
||||
|
||||
return nil
|
||||
|
|
@ -72,14 +72,15 @@ func (v *replicaSetView) backCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
}
|
||||
|
||||
func (v *replicaSetView) rollbackCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.rowSelected() {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
v.showModal(fmt.Sprintf("Rollback %s %s?", v.list.GetName(), v.selectedItem), func(_ int, button string) {
|
||||
sel := v.masterPage().GetSelectedItem()
|
||||
v.showModal(fmt.Sprintf("Rollback %s %s?", v.list.GetName(), sel), func(_ int, button string) {
|
||||
if button == "OK" {
|
||||
v.app.Flash().Infof("Rolling back %s %s", v.list.GetName(), v.selectedItem)
|
||||
if res, err := rollback(v.app.Conn(), v.selectedItem); err != nil {
|
||||
v.app.Flash().Infof("Rolling back %s %s", v.list.GetName(), sel)
|
||||
if res, err := rollback(v.app.Conn(), sel); err != nil {
|
||||
v.app.Flash().Err(err)
|
||||
} else {
|
||||
v.app.Flash().Info(res)
|
||||
|
|
|
|||
|
|
@ -25,11 +25,11 @@ func (v *secretView) extraActions(aa ui.KeyActions) {
|
|||
}
|
||||
|
||||
func (v *secretView) decodeCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.rowSelected() {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
sel := v.getSelectedItem()
|
||||
sel := v.masterPage().GetSelectedItem()
|
||||
ns, n := namespaced(sel)
|
||||
sec, err := v.app.Conn().DialOrDie().CoreV1().Secrets(ns).Get(n, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -26,22 +26,19 @@ type (
|
|||
subjectView struct {
|
||||
*tableView
|
||||
|
||||
current ui.Igniter
|
||||
cancel context.CancelFunc
|
||||
subjectKind string
|
||||
selectedItem string
|
||||
cache resource.RowEvents
|
||||
current ui.Igniter
|
||||
cancel context.CancelFunc
|
||||
subjectKind string
|
||||
cache resource.RowEvents
|
||||
}
|
||||
)
|
||||
|
||||
func newSubjectView(ns string, app *appView, list resource.List) resourceViewer {
|
||||
v := subjectView{}
|
||||
{
|
||||
v.tableView = newTableView(app, v.getTitle())
|
||||
v.tableView.SetSelectionChangedFunc(v.selChanged)
|
||||
v.SetColorerFn(rbacColorer)
|
||||
v.bindKeys()
|
||||
}
|
||||
v.tableView = newTableView(app, "Subject")
|
||||
v.SetActiveNS("*")
|
||||
v.SetColorerFn(rbacColorer)
|
||||
v.bindKeys()
|
||||
|
||||
if current, ok := app.Frame().GetPrimitive("main").(ui.Igniter); ok {
|
||||
v.current = current
|
||||
|
|
@ -58,9 +55,9 @@ func (v *subjectView) Init(c context.Context, _ string) {
|
|||
v.cancel()
|
||||
}
|
||||
|
||||
v.SetSortCol(len(rbacHeader), true)
|
||||
v.SetSortCol(1, len(rbacHeader), true)
|
||||
v.subjectKind = mapCmdSubject(v.app.Config.K9s.ActiveCluster().View.Active)
|
||||
v.SetTitle(v.getTitle())
|
||||
v.SetBaseTitle(v.subjectKind)
|
||||
|
||||
ctx, cancel := context.WithCancel(c)
|
||||
v.cancel = cancel
|
||||
|
|
@ -78,13 +75,11 @@ func (v *subjectView) Init(c context.Context, _ string) {
|
|||
}(ctx)
|
||||
|
||||
v.refresh()
|
||||
v.SelectRow(1, true)
|
||||
v.app.SetFocus(v)
|
||||
}
|
||||
v.app.SetHints(v.Hints())
|
||||
|
||||
func (v *subjectView) setExtraActionsFn(f ui.ActionsFunc) {}
|
||||
func (v *subjectView) setColorerFn(f ui.ColorerFunc) {}
|
||||
func (v *subjectView) setEnterFn(f enterFn) {}
|
||||
func (v *subjectView) setDecorateFn(f decorateFn) {}
|
||||
}
|
||||
|
||||
func (v *subjectView) bindKeys() {
|
||||
// No time data or ns
|
||||
|
|
@ -92,26 +87,23 @@ func (v *subjectView) bindKeys() {
|
|||
v.RmAction(ui.KeyShiftP)
|
||||
|
||||
v.SetActions(ui.KeyActions{
|
||||
tcell.KeyEnter: ui.NewKeyAction("RBAC", v.rbackCmd, true),
|
||||
tcell.KeyEnter: ui.NewKeyAction("Policies", v.policyCmd, true),
|
||||
tcell.KeyEscape: ui.NewKeyAction("Reset", v.resetCmd, false),
|
||||
ui.KeySlash: ui.NewKeyAction("Filter", v.ActivateCmd, false),
|
||||
ui.KeySlash: ui.NewKeyAction("Filter", v.activateCmd, false),
|
||||
ui.KeyP: ui.NewKeyAction("Previous", v.app.prevCmd, false),
|
||||
ui.KeyShiftK: ui.NewKeyAction("Sort Kind", v.SortColCmd(1), true),
|
||||
})
|
||||
}
|
||||
|
||||
func (v *subjectView) setExtraActionsFn(f ui.ActionsFunc) {}
|
||||
func (v *subjectView) setColorerFn(f ui.ColorerFunc) {}
|
||||
func (v *subjectView) setEnterFn(f enterFn) {}
|
||||
func (v *subjectView) setDecorateFn(f decorateFn) {}
|
||||
|
||||
func (v *subjectView) getTitle() string {
|
||||
return fmt.Sprintf(rbacTitleFmt, "Subject", v.subjectKind)
|
||||
}
|
||||
|
||||
func (v *subjectView) selChanged(r, _ int) {
|
||||
if r == 0 {
|
||||
v.selectedItem = ""
|
||||
return
|
||||
}
|
||||
v.selectedItem = ui.TrimCell(v.tableView.Table, r, 0)
|
||||
}
|
||||
|
||||
func (v *subjectView) SetSubject(s string) {
|
||||
v.subjectKind = mapSubject(s)
|
||||
}
|
||||
|
|
@ -124,8 +116,8 @@ func (v *subjectView) refresh() {
|
|||
v.Update(data)
|
||||
}
|
||||
|
||||
func (v *subjectView) rbackCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if v.selectedItem == "" {
|
||||
func (v *subjectView) policyCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +125,7 @@ func (v *subjectView) rbackCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
v.cancel()
|
||||
}
|
||||
|
||||
_, n := namespaced(v.selectedItem)
|
||||
_, n := namespaced(v.GetSelectedItem())
|
||||
v.app.inject(newPolicyView(v.app, mapFuSubject(v.subjectKind), n))
|
||||
|
||||
return nil
|
||||
|
|
@ -163,10 +155,6 @@ func (v *subjectView) backCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *subjectView) Hints() ui.Hints {
|
||||
return v.Hints()
|
||||
}
|
||||
|
||||
func (v *subjectView) reconcile() (resource.TableData, error) {
|
||||
var table resource.TableData
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ func (v *svcView) getList() resource.List {
|
|||
}
|
||||
|
||||
func (v *svcView) getSelection() string {
|
||||
return v.selectedItem
|
||||
return v.masterPage().GetSelectedItem()
|
||||
}
|
||||
|
||||
func (v *svcView) extraActions(aa ui.KeyActions) {
|
||||
|
|
@ -50,7 +50,7 @@ func (v *svcView) extraActions(aa ui.KeyActions) {
|
|||
func (v *svcView) sortColCmd(col int, asc bool) func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
return func(evt *tcell.EventKey) *tcell.EventKey {
|
||||
t := v.masterPage()
|
||||
t.SetSortCol(t.NameColIndex()+col, asc)
|
||||
t.SetSortCol(t.NameColIndex()+col, 0, asc)
|
||||
t.Refresh()
|
||||
|
||||
return nil
|
||||
|
|
@ -72,7 +72,7 @@ func (v *svcView) showPods(app *appView, ns, res, sel string) {
|
|||
}
|
||||
|
||||
func (v *svcView) logsCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.rowSelected() {
|
||||
if !v.masterPage().RowSelected() {
|
||||
return evt
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ func (v *svcView) reloadBenchCfg() error {
|
|||
}
|
||||
|
||||
func (v *svcView) benchCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !v.rowSelected() || v.bench != nil {
|
||||
if !v.masterPage().RowSelected() || v.bench != nil {
|
||||
return evt
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +143,7 @@ func (v *svcView) benchCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
return nil
|
||||
}
|
||||
|
||||
sel := v.getSelectedItem()
|
||||
sel := v.getSelection()
|
||||
cfg, ok := v.app.Bench.Benchmarks.Services[sel]
|
||||
if !ok {
|
||||
v.app.Flash().Errf("No bench config found for service %s", sel)
|
||||
|
|
|
|||
|
|
@ -3,15 +3,13 @@ package views
|
|||
import (
|
||||
"github.com/derailed/k9s/internal/ui"
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type tableView struct {
|
||||
*ui.Table
|
||||
|
||||
app *appView
|
||||
cleanseFn cleanseFn
|
||||
filterFn func(string)
|
||||
app *appView
|
||||
filterFn func(string)
|
||||
}
|
||||
|
||||
func newTableView(app *appView, title string) *tableView {
|
||||
|
|
@ -44,7 +42,7 @@ func (v *tableView) setFilterFn(fn func(string)) {
|
|||
func (v *tableView) bindKeys() {
|
||||
v.SetActions(ui.KeyActions{
|
||||
tcell.KeyCtrlS: ui.NewKeyAction("Save", v.saveCmd, true),
|
||||
ui.KeySlash: ui.NewKeyAction("Filter Mode", v.ActivateCmd, false),
|
||||
ui.KeySlash: ui.NewKeyAction("Filter Mode", v.activateCmd, false),
|
||||
tcell.KeyEscape: ui.NewKeyAction("Filter Reset", v.resetCmd, false),
|
||||
tcell.KeyEnter: ui.NewKeyAction("Filter", v.filterCmd, false),
|
||||
tcell.KeyBackspace2: ui.NewKeyAction("Erase", v.eraseCmd, false),
|
||||
|
|
@ -57,7 +55,6 @@ func (v *tableView) bindKeys() {
|
|||
}
|
||||
|
||||
func (v *tableView) filterCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
log.Debug().Msg("YO!!")
|
||||
if !v.Cmd().IsActive() {
|
||||
return evt
|
||||
}
|
||||
|
|
@ -93,3 +90,18 @@ func (v *tableView) resetCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *tableView) activateCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if v.app.InCmdMode() {
|
||||
return evt
|
||||
}
|
||||
|
||||
v.app.Flash().Info("Filter mode activated.")
|
||||
if isLabelSelector(v.Cmd().String()) {
|
||||
return nil
|
||||
}
|
||||
v.Cmd().Reset()
|
||||
v.Cmd().SetActive(true)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue