Rel v0.40.7 (#3188)
* [FEAT] add readonly indicator * [FIX] Hosed cust view loading * rel notesmine
parent
1244cc518d
commit
08b8efa617
2
Makefile
2
Makefile
|
|
@ -11,7 +11,7 @@ DATE ?= $(shell TZ=UTC date -j -f "%s" ${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:
|
||||||
else
|
else
|
||||||
DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ")
|
DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ")
|
||||||
endif
|
endif
|
||||||
VERSION ?= v0.40.6
|
VERSION ?= v0.40.7
|
||||||
IMG_NAME := derailed/k9s
|
IMG_NAME := derailed/k9s
|
||||||
IMAGE := ${IMG_NAME}:${VERSION}
|
IMAGE := ${IMG_NAME}:${VERSION}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -700,6 +700,12 @@ views:
|
||||||
- AGE
|
- AGE
|
||||||
- NAMESPACE|WR
|
- NAMESPACE|WR
|
||||||
|
|
||||||
|
v1/pods@kube*: # => 🌚 New v0.40.6! You can also specify a namespace using a regular expression.
|
||||||
|
columns:
|
||||||
|
- AGE
|
||||||
|
- NAMESPACE|WR
|
||||||
|
|
||||||
|
|
||||||
v1/services:
|
v1/services:
|
||||||
columns:
|
columns:
|
||||||
- AGE
|
- AGE
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s.png" align="center" width="800" height="auto"/>
|
||||||
|
|
||||||
|
# Release v0.40.7
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Thank you to all that contributed with flushing out issues and enhancements for K9s!
|
||||||
|
I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev
|
||||||
|
and see if we're happier with some of the fixes!
|
||||||
|
If you've filed an issue please help me verify and close.
|
||||||
|
|
||||||
|
Your support, kindness and awesome suggestions to make K9s better are, as ever, very much noted and appreciated!
|
||||||
|
Also big thanks to all that have allocated their own time to help others on both slack and on this repo!!
|
||||||
|
|
||||||
|
As you may know, K9s is not pimped out by corps with deep pockets, thus if you feel K9s is helping your Kubernetes journey,
|
||||||
|
please consider joining our [sponsorship program](https://github.com/sponsors/derailed) and/or make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
|
||||||
|
|
||||||
|
On Slack? Please join us [K9slackers](https://join.slack.com/t/k9sers/shared_invite/enQtOTA5MDEyNzI5MTU0LWQ1ZGI3MzliYzZhZWEyNzYxYzA3NjE0YTk1YmFmNzViZjIyNzhkZGI0MmJjYzhlNjdlMGJhYzE2ZGU1NjkyNTM)
|
||||||
|
|
||||||
|
## Maintenance Release!
|
||||||
|
|
||||||
|
🙀 Hoy! Hosed custom view loading in v0.40.6...
|
||||||
|
|
||||||
|
## Videos Are In The Can!
|
||||||
|
|
||||||
|
Please dial [K9s Channel](https://www.youtube.com/channel/UC897uwPygni4QIjkPCpgjmw) for up coming content...
|
||||||
|
|
||||||
|
* [K9s v0.40.0 -Column Blow- Sneak peek](https://youtu.be/iy6RDozAM4A)
|
||||||
|
* [K9s v0.31.0 Configs+Sneak peek](https://youtu.be/X3444KfjguE)
|
||||||
|
* [K9s v0.30.0 Sneak peek](https://youtu.be/mVBc1XneRJ4)
|
||||||
|
* [Vulnerability Scans](https://youtu.be/ULkl0MsaidU)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Resolved Issues
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contributed PRs
|
||||||
|
|
||||||
|
Please be sure to give `Big Thanks!` and `ATTA Girls/Boys!` to all the fine contributors for making K9s better for all of us!!
|
||||||
|
|
||||||
|
* [#3186](https://github.com/derailed/k9s/pull/3186) fix: allow absolute paths for the 'dir' command
|
||||||
|
|
||||||
|
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/imhotep_logo.png" width="32" height="auto"/> © 2025 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
|
@ -34,6 +34,11 @@ func NewConfig(ks data.KubeSettings) *Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsReadOnly returns true if K9s is running in read-only mode.
|
||||||
|
func (c *Config) IsReadOnly() bool {
|
||||||
|
return c.K9s.IsReadOnly()
|
||||||
|
}
|
||||||
|
|
||||||
// ActiveClusterName returns the corresponding cluster name.
|
// ActiveClusterName returns the corresponding cluster name.
|
||||||
func (c *Config) ActiveClusterName(contextName string) (string, error) {
|
func (c *Config) ActiveClusterName(contextName string) (string, error) {
|
||||||
ct, err := c.settings.GetContext(contextName)
|
ct, err := c.settings.GetContext(contextName)
|
||||||
|
|
|
||||||
|
|
@ -142,28 +142,33 @@ func (v *CustomView) fireConfigChanged() {
|
||||||
|
|
||||||
func (v *CustomView) getVS(gvr, ns string) *ViewSetting {
|
func (v *CustomView) getVS(gvr, ns string) *ViewSetting {
|
||||||
k := gvr
|
k := gvr
|
||||||
if ns != "" {
|
kk := slices.Collect(maps.Keys(v.Views))
|
||||||
k += "@" + ns
|
slices.SortFunc(kk, func(s1, s2 string) int {
|
||||||
}
|
return strings.Compare(s1, s2)
|
||||||
|
})
|
||||||
for key := range maps.Keys(v.Views) {
|
slices.Reverse(kk)
|
||||||
|
for _, key := range kk {
|
||||||
if !strings.HasPrefix(key, gvr) {
|
if !strings.HasPrefix(key, gvr) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case key == k:
|
|
||||||
vs := v.Views[key]
|
|
||||||
return &vs
|
|
||||||
case strings.Contains(key, "@"):
|
case strings.Contains(key, "@"):
|
||||||
tt := strings.Split(key, "@")
|
tt := strings.Split(key, "@")
|
||||||
if len(tt) != 2 {
|
if len(tt) != 2 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if rx, err := regexp.Compile(tt[1]); err == nil && rx.MatchString(k) {
|
nsk := gvr
|
||||||
|
if ns != "" {
|
||||||
|
nsk += "@" + ns
|
||||||
|
}
|
||||||
|
if rx, err := regexp.Compile(tt[1]); err == nil && rx.MatchString(nsk) {
|
||||||
vs := v.Views[key]
|
vs := v.Views[key]
|
||||||
return &vs
|
return &vs
|
||||||
}
|
}
|
||||||
|
case key == k:
|
||||||
|
vs := v.Views[key]
|
||||||
|
return &vs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,9 @@ func TestCustomView_getVS(t *testing.T) {
|
||||||
"toast-no-ns": {
|
"toast-no-ns": {
|
||||||
gvr: "v1/pods",
|
gvr: "v1/pods",
|
||||||
ns: "zorg",
|
ns: "zorg",
|
||||||
|
e: &ViewSetting{
|
||||||
|
Columns: []string{"NAMESPACE", "NAME", "AGE", "IP"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
"toast-no-res": {
|
"toast-no-res": {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"github.com/derailed/k9s/internal"
|
"github.com/derailed/k9s/internal"
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
"github.com/derailed/k9s/internal/config"
|
"github.com/derailed/k9s/internal/config"
|
||||||
"github.com/derailed/k9s/internal/dao"
|
|
||||||
"github.com/derailed/k9s/internal/model"
|
"github.com/derailed/k9s/internal/model"
|
||||||
"github.com/derailed/k9s/internal/model1"
|
"github.com/derailed/k9s/internal/model1"
|
||||||
"github.com/derailed/k9s/internal/render"
|
"github.com/derailed/k9s/internal/render"
|
||||||
|
|
@ -54,6 +53,7 @@ type Table struct {
|
||||||
hasMetrics bool
|
hasMetrics bool
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
mx sync.RWMutex
|
mx sync.RWMutex
|
||||||
|
readOnly bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTable returns a new table view.
|
// NewTable returns a new table view.
|
||||||
|
|
@ -72,6 +72,13 @@ func NewTable(gvr client.GVR) *Table {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Table) SetReadOnly(ro bool) {
|
||||||
|
t.mx.Lock()
|
||||||
|
defer t.mx.Unlock()
|
||||||
|
|
||||||
|
t.readOnly = ro
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Table) setSortCol(sc model1.SortColumn) {
|
func (t *Table) setSortCol(sc model1.SortColumn) {
|
||||||
t.mx.Lock()
|
t.mx.Lock()
|
||||||
defer t.mx.Unlock()
|
defer t.mx.Unlock()
|
||||||
|
|
@ -297,17 +304,12 @@ func (t *Table) UpdateUI(cdata, data *model1.TableData) {
|
||||||
fg := t.styles.Table().Header.FgColor.Color()
|
fg := t.styles.Table().Header.FgColor.Color()
|
||||||
bg := t.styles.Table().Header.BgColor.Color()
|
bg := t.styles.Table().Header.BgColor.Color()
|
||||||
|
|
||||||
var isNamespaced bool
|
|
||||||
if m, err := dao.MetaAccess.MetaFor(t.GVR()); err == nil {
|
|
||||||
isNamespaced = m.Namespaced
|
|
||||||
}
|
|
||||||
|
|
||||||
var col int
|
var col int
|
||||||
for _, h := range cdata.Header() {
|
for _, h := range cdata.Header() {
|
||||||
if h.Hide || (!t.wide && h.Wide) {
|
if h.Hide || (!t.wide && h.Wide) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if h.Name == "NAMESPACE" && (!t.GetModel().ClusterWide() || !isNamespaced) {
|
if h.Name == "NAMESPACE" && !t.GetModel().ClusterWide() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if h.MX && !t.hasMetrics {
|
if h.MX && !t.hasMetrics {
|
||||||
|
|
@ -333,7 +335,7 @@ func (t *Table) UpdateUI(cdata, data *model1.TableData) {
|
||||||
slog.Error("Unable to find original row event", slogs.RowID, re.Row.ID)
|
slog.Error("Unable to find original row event", slogs.RowID, re.Row.ID)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
t.buildRow(row+1, re, ore, cdata.Header(), pads, isNamespaced)
|
t.buildRow(row+1, re, ore, cdata.Header(), pads)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
@ -342,7 +344,7 @@ func (t *Table) UpdateUI(cdata, data *model1.TableData) {
|
||||||
t.UpdateTitle()
|
t.UpdateTitle()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Table) buildRow(r int, re, ore model1.RowEvent, h model1.Header, pads MaxyPad, isNamespaced bool) {
|
func (t *Table) buildRow(r int, re, ore model1.RowEvent, h model1.Header, pads MaxyPad) {
|
||||||
color := model1.DefaultColorer
|
color := model1.DefaultColorer
|
||||||
if t.colorerFn != nil {
|
if t.colorerFn != nil {
|
||||||
color = t.colorerFn
|
color = t.colorerFn
|
||||||
|
|
@ -364,7 +366,7 @@ func (t *Table) buildRow(r int, re, ore model1.RowEvent, h model1.Header, pads M
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if h[c].Name == "NAMESPACE" && (!t.GetModel().ClusterWide() || !isNamespaced) {
|
if h[c].Name == "NAMESPACE" && !t.GetModel().ClusterWide() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if h[c].MX && !t.hasMetrics {
|
if h[c].MX && !t.hasMetrics {
|
||||||
|
|
@ -532,11 +534,12 @@ func (t *Table) styleTitle() string {
|
||||||
if t.Extras != "" {
|
if t.Extras != "" {
|
||||||
ns = t.Extras
|
ns = t.Extras
|
||||||
}
|
}
|
||||||
|
|
||||||
var title string
|
var title string
|
||||||
if ns == client.ClusterScope {
|
if ns == client.ClusterScope {
|
||||||
title = SkinTitle(fmt.Sprintf(TitleFmt, t.gvr, render.AsThousands(rc)), t.styles.Frame())
|
title = SkinTitle(fmt.Sprintf(TitleFmt, ROIndicator(t.readOnly), t.gvr, render.AsThousands(rc)), t.styles.Frame())
|
||||||
} else {
|
} else {
|
||||||
title = SkinTitle(fmt.Sprintf(NSTitleFmt, t.gvr, ns, render.AsThousands(rc)), t.styles.Frame())
|
title = SkinTitle(fmt.Sprintf(NSTitleFmt, ROIndicator(t.readOnly), t.gvr, ns, render.AsThousands(rc)), t.styles.Frame())
|
||||||
}
|
}
|
||||||
|
|
||||||
buff := t.cmdBuff.GetText()
|
buff := t.cmdBuff.GetText()
|
||||||
|
|
@ -552,3 +555,12 @@ func (t *Table) styleTitle() string {
|
||||||
|
|
||||||
return title + SkinTitle(fmt.Sprintf(SearchFmt, buff), t.styles.Frame())
|
return title + SkinTitle(fmt.Sprintf(SearchFmt, buff), t.styles.Frame())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ROIndicator returns an icon showing whether the session is in readonly mode or not.
|
||||||
|
func ROIndicator(ro bool) string {
|
||||||
|
if ro {
|
||||||
|
return LockedIC
|
||||||
|
}
|
||||||
|
|
||||||
|
return UnlockedIC
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,10 @@ const (
|
||||||
SearchFmt = "<[filter:bg:r]/%s[fg:bg:-]> "
|
SearchFmt = "<[filter:bg:r]/%s[fg:bg:-]> "
|
||||||
|
|
||||||
// NSTitleFmt represents a namespaced view title.
|
// NSTitleFmt represents a namespaced view title.
|
||||||
NSTitleFmt = "[fg:bg:b] %s([hilite:bg:b]%s[fg:bg:-])[fg:bg:-][[count:bg:b]%s[fg:bg:-]][fg:bg:-] "
|
NSTitleFmt = " %s [fg:bg:b]%s([hilite:bg:b]%s[fg:bg:-])[fg:bg:-][[count:bg:b]%s[fg:bg:-]][fg:bg:-] "
|
||||||
|
|
||||||
// TitleFmt represents a standard view title.
|
// TitleFmt represents a standard view title.
|
||||||
TitleFmt = "[fg:bg:b] %s[fg:bg:-][[count:bg:b]%s[fg:bg:-]][fg:bg:-] "
|
TitleFmt = " %s [fg:bg:b]%s[fg:bg:-][[count:bg:b]%s[fg:bg:-]][fg:bg:-] "
|
||||||
|
|
||||||
descIndicator = "↓"
|
descIndicator = "↓"
|
||||||
ascIndicator = "↑"
|
ascIndicator = "↑"
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,14 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// UnlockedIC represents an unlocked icon.
|
||||||
|
UnlockedIC = "🔓"
|
||||||
|
|
||||||
|
// LockedIC represents a locked icon.
|
||||||
|
LockedIC = "🔒"
|
||||||
|
)
|
||||||
|
|
||||||
// Namespaceable represents a namespaceable model.
|
// Namespaceable represents a namespaceable model.
|
||||||
type Namespaceable interface {
|
type Namespaceable interface {
|
||||||
// ClusterWide returns true if the model represents resource in all namespaces.
|
// ClusterWide returns true if the model represents resource in all namespaces.
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ func pluginActions(r Runner, aa *ui.KeyActions) error {
|
||||||
var (
|
var (
|
||||||
errs error
|
errs error
|
||||||
aliases = r.Aliases()
|
aliases = r.Aliases()
|
||||||
ro = r.App().Config.K9s.IsReadOnly()
|
ro = r.App().Config.IsReadOnly()
|
||||||
)
|
)
|
||||||
for k, plugin := range pp.Plugins {
|
for k, plugin := range pp.Plugins {
|
||||||
if !inScope(plugin.Scopes, aliases) {
|
if !inScope(plugin.Scopes, aliases) {
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,7 @@ func (b *Browser) Init(ctx context.Context) error {
|
||||||
if b.App().IsRunning() {
|
if b.App().IsRunning() {
|
||||||
b.app.CmdBuff().Reset()
|
b.app.CmdBuff().Reset()
|
||||||
}
|
}
|
||||||
|
b.Table.SetReadOnly(b.app.Config.IsReadOnly())
|
||||||
|
|
||||||
b.bindKeys(b.Actions())
|
b.bindKeys(b.Actions())
|
||||||
for _, f := range b.bindKeysFn {
|
for _, f := range b.bindKeysFn {
|
||||||
|
|
@ -537,7 +538,7 @@ func (b *Browser) refreshActions() {
|
||||||
|
|
||||||
if b.app.ConOK() {
|
if b.app.ConOK() {
|
||||||
b.namespaceActions(aa)
|
b.namespaceActions(aa)
|
||||||
if !b.app.Config.K9s.IsReadOnly() {
|
if !b.app.Config.IsReadOnly() {
|
||||||
if client.Can(b.meta.Verbs, "edit") {
|
if client.Can(b.meta.Verbs, "edit") {
|
||||||
aa.Add(ui.KeyE, ui.NewKeyActionWithOpts("Edit", b.editCmd,
|
aa.Add(ui.KeyE, ui.NewKeyActionWithOpts("Edit", b.editCmd,
|
||||||
ui.ActionOpts{
|
ui.ActionOpts{
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ func (c *Container) bindDangerousKeys(aa *ui.KeyActions) {
|
||||||
func (c *Container) bindKeys(aa *ui.KeyActions) {
|
func (c *Container) bindKeys(aa *ui.KeyActions) {
|
||||||
aa.Delete(tcell.KeyCtrlSpace, ui.KeySpace)
|
aa.Delete(tcell.KeyCtrlSpace, ui.KeySpace)
|
||||||
|
|
||||||
if !c.App().Config.K9s.IsReadOnly() {
|
if !c.App().Config.IsReadOnly() {
|
||||||
c.bindDangerousKeys(aa)
|
c.bindDangerousKeys(aa)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ func (d *Dir) bindKeys(aa *ui.KeyActions) {
|
||||||
// !!BOZO!! Lame!
|
// !!BOZO!! Lame!
|
||||||
aa.Delete(ui.KeyShiftA, tcell.KeyCtrlS, tcell.KeyCtrlSpace, ui.KeySpace)
|
aa.Delete(ui.KeyShiftA, tcell.KeyCtrlS, tcell.KeyCtrlSpace, ui.KeySpace)
|
||||||
aa.Delete(tcell.KeyCtrlW, tcell.KeyCtrlL, tcell.KeyCtrlD, tcell.KeyCtrlZ)
|
aa.Delete(tcell.KeyCtrlW, tcell.KeyCtrlL, tcell.KeyCtrlD, tcell.KeyCtrlZ)
|
||||||
if !d.App().Config.K9s.IsReadOnly() {
|
if !d.App().Config.IsReadOnly() {
|
||||||
d.bindDangerousKeys(aa)
|
d.bindDangerousKeys(aa)
|
||||||
}
|
}
|
||||||
aa.Bulk(ui.KeyMap{
|
aa.Bulk(ui.KeyMap{
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ func (h *History) HistoryContext(ctx context.Context) context.Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *History) bindKeys(aa *ui.KeyActions) {
|
func (h *History) bindKeys(aa *ui.KeyActions) {
|
||||||
if !h.App().Config.K9s.IsReadOnly() {
|
if !h.App().Config.IsReadOnly() {
|
||||||
h.bindDangerousKeys(aa)
|
h.bindDangerousKeys(aa)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ func NewImageExtender(r ResourceViewer) ResourceViewer {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ImageExtender) bindKeys(aa *ui.KeyActions) {
|
func (s *ImageExtender) bindKeys(aa *ui.KeyActions) {
|
||||||
if s.App().Config.K9s.IsReadOnly() {
|
if s.App().Config.IsReadOnly() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
aa.Add(ui.KeyI, ui.NewKeyAction("Set Image", s.setImageCmd, false))
|
aa.Add(ui.KeyI, ui.NewKeyAction("Set Image", s.setImageCmd, false))
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ func (v *LiveView) bindKeys() {
|
||||||
tcell.KeyDelete: ui.NewSharedKeyAction("Erase", v.eraseCmd, false),
|
tcell.KeyDelete: ui.NewSharedKeyAction("Erase", v.eraseCmd, false),
|
||||||
})
|
})
|
||||||
|
|
||||||
if !v.app.Config.K9s.IsReadOnly() {
|
if !v.app.Config.IsReadOnly() {
|
||||||
v.actions.Add(ui.KeyE, ui.NewKeyAction("Edit", v.editCmd, true))
|
v.actions.Add(ui.KeyE, ui.NewKeyAction("Edit", v.editCmd, true))
|
||||||
}
|
}
|
||||||
if v.title == yamlAction {
|
if v.title == yamlAction {
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ func (n *Node) bindDangerousKeys(aa *ui.KeyActions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) bindKeys(aa *ui.KeyActions) {
|
func (n *Node) bindKeys(aa *ui.KeyActions) {
|
||||||
if !n.App().Config.K9s.IsReadOnly() {
|
if !n.App().Config.IsReadOnly() {
|
||||||
n.bindDangerousKeys(aa)
|
n.bindDangerousKeys(aa)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ func (p *Pod) bindDangerousKeys(aa *ui.KeyActions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pod) bindKeys(aa *ui.KeyActions) {
|
func (p *Pod) bindKeys(aa *ui.KeyActions) {
|
||||||
if !p.App().Config.K9s.IsReadOnly() {
|
if !p.App().Config.IsReadOnly() {
|
||||||
p.bindDangerousKeys(aa)
|
p.bindDangerousKeys(aa)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ func NewRestartExtender(v ResourceViewer) ResourceViewer {
|
||||||
|
|
||||||
// BindKeys creates additional menu actions.
|
// BindKeys creates additional menu actions.
|
||||||
func (r *RestartExtender) bindKeys(aa *ui.KeyActions) {
|
func (r *RestartExtender) bindKeys(aa *ui.KeyActions) {
|
||||||
if r.App().Config.K9s.IsReadOnly() {
|
if r.App().Config.IsReadOnly() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
aa.Add(ui.KeyR, ui.NewKeyActionWithOpts("Restart", r.restartCmd,
|
aa.Add(ui.KeyR, ui.NewKeyActionWithOpts("Restart", r.restartCmd,
|
||||||
|
|
|
||||||
|
|
@ -419,9 +419,9 @@ func (s *Sanitizer) styleTitle() string {
|
||||||
|
|
||||||
var title string
|
var title string
|
||||||
if ns == client.ClusterScope {
|
if ns == client.ClusterScope {
|
||||||
title = ui.SkinTitle(fmt.Sprintf(ui.TitleFmt, base, render.AsThousands(int64(s.Count))), s.app.Styles.Frame())
|
title = ui.SkinTitle(fmt.Sprintf(ui.TitleFmt, ui.ROIndicator(s.app.Config.IsReadOnly()), base, render.AsThousands(int64(s.Count))), s.app.Styles.Frame())
|
||||||
} else {
|
} else {
|
||||||
title = ui.SkinTitle(fmt.Sprintf(ui.NSTitleFmt, base, ns, render.AsThousands(int64(s.Count))), s.app.Styles.Frame())
|
title = ui.SkinTitle(fmt.Sprintf(ui.NSTitleFmt, ui.ROIndicator(s.app.Config.IsReadOnly()), base, ns, render.AsThousands(int64(s.Count))), s.app.Styles.Frame())
|
||||||
}
|
}
|
||||||
|
|
||||||
buff := s.CmdBuff().GetText()
|
buff := s.CmdBuff().GetText()
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ func NewScaleExtender(r ResourceViewer) ResourceViewer {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ScaleExtender) bindKeys(aa *ui.KeyActions) {
|
func (s *ScaleExtender) bindKeys(aa *ui.KeyActions) {
|
||||||
if s.App().Config.K9s.IsReadOnly() {
|
if s.App().Config.IsReadOnly() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ func (w *Workload) bindDangerousKeys(aa *ui.KeyActions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Workload) bindKeys(aa *ui.KeyActions) {
|
func (w *Workload) bindKeys(aa *ui.KeyActions) {
|
||||||
if !w.App().Config.K9s.IsReadOnly() {
|
if !w.App().Config.IsReadOnly() {
|
||||||
w.bindDangerousKeys(aa)
|
w.bindDangerousKeys(aa)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -671,9 +671,9 @@ func (x *Xray) styleTitle() string {
|
||||||
|
|
||||||
var title string
|
var title string
|
||||||
if ns == client.ClusterScope {
|
if ns == client.ClusterScope {
|
||||||
title = ui.SkinTitle(fmt.Sprintf(ui.TitleFmt, base, render.AsThousands(int64(x.Count))), x.app.Styles.Frame())
|
title = ui.SkinTitle(fmt.Sprintf(ui.TitleFmt, ui.ROIndicator(x.app.Config.IsReadOnly()), base, render.AsThousands(int64(x.Count))), x.app.Styles.Frame())
|
||||||
} else {
|
} else {
|
||||||
title = ui.SkinTitle(fmt.Sprintf(ui.NSTitleFmt, base, ns, render.AsThousands(int64(x.Count))), x.app.Styles.Frame())
|
title = ui.SkinTitle(fmt.Sprintf(ui.NSTitleFmt, ui.ROIndicator(x.app.Config.IsReadOnly()), base, ns, render.AsThousands(int64(x.Count))), x.app.Styles.Frame())
|
||||||
}
|
}
|
||||||
|
|
||||||
buff := x.CmdBuff().GetText()
|
buff := x.CmdBuff().GetText()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: k9s
|
name: k9s
|
||||||
base: core22
|
base: core22
|
||||||
version: 'v0.40.6'
|
version: 'v0.40.7'
|
||||||
summary: K9s is a CLI to view and manage your Kubernetes clusters.
|
summary: K9s is a CLI to view and manage your Kubernetes clusters.
|
||||||
description: |
|
description: |
|
||||||
K9s is a CLI to view and manage your Kubernetes clusters. By leveraging a terminal UI, you can easily traverse Kubernetes resources and view the state of your clusters in a single powerful session.
|
K9s is a CLI to view and manage your Kubernetes clusters. By leveraging a terminal UI, you can easily traverse Kubernetes resources and view the state of your clusters in a single powerful session.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue