feat: add splashless option to suppress splash screen on start (#3110)

* Add splashless option to suppress splash screen

Fixes #1911

* Add tests for splashless option

* Update docs for splashless option
mine
Jason Tackaberry 2025-03-30 15:37:57 +00:00 committed by GitHub
parent 7b7e1b5b91
commit 88e04217a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 46 additions and 5 deletions

View File

@ -427,6 +427,8 @@ You can now override the context portForward default address configuration by se
logoless: false logoless: false
# Set to true to hide K9s crumbs. Default false # Set to true to hide K9s crumbs. Default false
crumbsless: false crumbsless: false
# Set to true to suppress the K9s splash screen on start. Default false. Note that for larger clusters or higher latency connections, there may be no resources visible initially until local caches have finished populating.
splashless: false
noIcons: false noIcons: false
# Toggles reactive UI. This option provide for watching on disk artifacts changes and update the UI live Defaults to false. # Toggles reactive UI. This option provide for watching on disk artifacts changes and update the UI live Defaults to false.
reactive: false reactive: false
@ -1055,6 +1057,7 @@ k9s:
headless: false headless: false
logoless: false logoless: false
crumbsless: false crumbsless: false
splashless: false
noIcons: false noIcons: false
# Toggles reactive UI. This option provide for watching on disk artifacts changes and update the UI live Defaults to false. # Toggles reactive UI. This option provide for watching on disk artifacts changes and update the UI live Defaults to false.
reactive: false reactive: false

View File

@ -218,6 +218,12 @@ func initK9sFlags() {
false, false,
"Turn K9s crumbs off", "Turn K9s crumbs off",
) )
rootCmd.Flags().BoolVar(
k9sFlags.Splashless,
"splashless",
false,
"Turn K9s splash screen off",
)
rootCmd.Flags().BoolVarP( rootCmd.Flags().BoolVarP(
k9sFlags.AllNamespaces, k9sFlags.AllNamespaces,
"all-namespaces", "A", "all-namespaces", "A",

View File

@ -26,6 +26,7 @@ type Flags struct {
ReadOnly *bool ReadOnly *bool
Write *bool Write *bool
Crumbsless *bool Crumbsless *bool
Splashless *bool
ScreenDumpDir *string ScreenDumpDir *string
} }
@ -42,6 +43,7 @@ func NewFlags() *Flags {
ReadOnly: boolPtr(false), ReadOnly: boolPtr(false),
Write: boolPtr(false), Write: boolPtr(false),
Crumbsless: boolPtr(false), Crumbsless: boolPtr(false),
Splashless: boolPtr(false),
ScreenDumpDir: strPtr(AppDumpsDir), ScreenDumpDir: strPtr(AppDumpsDir),
} }
} }

View File

@ -26,4 +26,5 @@ func TestNewFlags(t *testing.T) {
assert.False(t, *f.ReadOnly) assert.False(t, *f.ReadOnly)
assert.False(t, *f.Write) assert.False(t, *f.Write)
assert.False(t, *f.Crumbsless) assert.False(t, *f.Crumbsless)
assert.False(t, *f.Splashless)
} }

View File

@ -24,6 +24,7 @@
"headless": {"type": "boolean"}, "headless": {"type": "boolean"},
"logoless": {"type": "boolean"}, "logoless": {"type": "boolean"},
"crumbsless": {"type": "boolean"}, "crumbsless": {"type": "boolean"},
"splashless": {"type": "boolean"},
"noIcons": {"type": "boolean"}, "noIcons": {"type": "boolean"},
"reactive": {"type": "boolean"}, "reactive": {"type": "boolean"},
"skin": {"type": "string"}, "skin": {"type": "string"},

View File

@ -10,6 +10,7 @@ k9s:
headless: false headless: false
logoless: false logoless: false
crumbsless: false crumbsless: false
splashless: false
noIcons: false noIcons: false
skipLatestRevCheck: false skipLatestRevCheck: false
disablePodCounting: false disablePodCounting: false

View File

@ -293,6 +293,7 @@ func (k *K9s) Override(k9sFlags *Flags) {
k.UI.manualHeadless = k9sFlags.Headless k.UI.manualHeadless = k9sFlags.Headless
k.UI.manualLogoless = k9sFlags.Logoless k.UI.manualLogoless = k9sFlags.Logoless
k.UI.manualCrumbsless = k9sFlags.Crumbsless k.UI.manualCrumbsless = k9sFlags.Crumbsless
k.UI.manualSplashless = k9sFlags.Splashless
if k9sFlags.ReadOnly != nil && *k9sFlags.ReadOnly { if k9sFlags.ReadOnly != nil && *k9sFlags.ReadOnly {
k.manualReadOnly = k9sFlags.ReadOnly k.manualReadOnly = k9sFlags.ReadOnly
} }
@ -331,6 +332,15 @@ func (k *K9s) IsCrumbsless() bool {
return k.UI.Crumbsless return k.UI.Crumbsless
} }
// IsSplashless returns splashless setting.
func (k *K9s) IsSplashless() bool {
if IsBoolSet(k.UI.manualSplashless) {
return true
}
return k.UI.Splashless
}
// GetRefreshRate returns the current refresh rate. // GetRefreshRate returns the current refresh rate.
func (k *K9s) GetRefreshRate() int { func (k *K9s) GetRefreshRate() int {
if k.manualRefreshRate != 0 { if k.manualRefreshRate != 0 {

View File

@ -17,9 +17,9 @@ func Test_k9sOverrides(t *testing.T) {
) )
uu := map[string]struct { uu := map[string]struct {
k *K9s k *K9s
rate int rate int
ro, hl, cl, ll bool ro, hl, cl, sl, ll bool
}{ }{
"plain": { "plain": {
k: &K9s{ k: &K9s{
@ -47,6 +47,7 @@ func Test_k9sOverrides(t *testing.T) {
Headless: true, Headless: true,
Logoless: true, Logoless: true,
Crumbsless: true, Crumbsless: true,
Splashless: true,
}, },
SkipLatestRevCheck: false, SkipLatestRevCheck: false,
DisablePodCounting: false, DisablePodCounting: false,
@ -56,6 +57,7 @@ func Test_k9sOverrides(t *testing.T) {
hl: true, hl: true,
ll: true, ll: true,
cl: true, cl: true,
sl: true,
}, },
"overrides": { "overrides": {
k: &K9s{ k: &K9s{
@ -72,6 +74,7 @@ func Test_k9sOverrides(t *testing.T) {
manualHeadless: &true, manualHeadless: &true,
manualLogoless: &true, manualLogoless: &true,
manualCrumbsless: &true, manualCrumbsless: &true,
manualSplashless: &true,
}, },
SkipLatestRevCheck: false, SkipLatestRevCheck: false,
DisablePodCounting: false, DisablePodCounting: false,
@ -85,6 +88,7 @@ func Test_k9sOverrides(t *testing.T) {
hl: true, hl: true,
ll: true, ll: true,
cl: true, cl: true,
sl: true,
}, },
} }
@ -94,6 +98,7 @@ func Test_k9sOverrides(t *testing.T) {
assert.Equal(t, u.rate, u.k.GetRefreshRate()) assert.Equal(t, u.rate, u.k.GetRefreshRate())
assert.Equal(t, u.ro, u.k.IsReadOnly()) assert.Equal(t, u.ro, u.k.IsReadOnly())
assert.Equal(t, u.cl, u.k.IsCrumbsless()) assert.Equal(t, u.cl, u.k.IsCrumbsless())
assert.Equal(t, u.sl, u.k.IsSplashless())
assert.Equal(t, u.hl, u.k.IsHeadless()) assert.Equal(t, u.hl, u.k.IsHeadless())
assert.Equal(t, u.ll, u.k.IsLogoless()) assert.Equal(t, u.ll, u.k.IsLogoless())

View File

@ -11,6 +11,7 @@ k9s:
headless: false headless: false
logoless: false logoless: false
crumbsless: false crumbsless: false
splashless: false
reactive: false reactive: false
noIcons: false noIcons: false
defaultsToFullScreen: false defaultsToFullScreen: false

View File

@ -11,6 +11,7 @@ k9s:
headless: false headless: false
logoless: false logoless: false
crumbsless: false crumbsless: false
splashless: false
reactive: false reactive: false
noIcons: false noIcons: false
defaultsToFullScreen: false defaultsToFullScreen: false

View File

@ -11,6 +11,7 @@ k9s:
headless: false headless: false
logoless: false logoless: false
crumbsless: false crumbsless: false
splashless: false
reactive: false reactive: false
noIcons: false noIcons: false
defaultsToFullScreen: false defaultsToFullScreen: false

View File

@ -10,6 +10,7 @@ k9s:
headless: false headless: false
logoless: false logoless: false
crumbsless: false crumbsless: false
splashless: false
noIcons: false noIcons: false
skipLatestRevCheck: yes skipLatestRevCheck: yes
disablePodCounts: false disablePodCounts: false

View File

@ -22,6 +22,9 @@ type UI struct {
// Crumbsless toggles nav crumb display. // Crumbsless toggles nav crumb display.
Crumbsless bool `json:"crumbsless" yaml:"crumbsless"` Crumbsless bool `json:"crumbsless" yaml:"crumbsless"`
// Splashless disables the splash screen on startup.
Splashless bool `json:"splashless" yaml:"splashless"`
// Reactive toggles reactive ui changes. // Reactive toggles reactive ui changes.
Reactive bool `json:"reactive" yaml:"reactive"` Reactive bool `json:"reactive" yaml:"reactive"`
@ -38,4 +41,5 @@ type UI struct {
manualHeadless *bool manualHeadless *bool
manualLogoless *bool manualLogoless *bool
manualCrumbsless *bool manualCrumbsless *bool
manualSplashless *bool
} }

View File

@ -167,8 +167,10 @@ func (a *App) layout(ctx context.Context) {
main.AddItem(flash, 1, 1, false) main.AddItem(flash, 1, 1, false)
a.Main.AddPage("main", main, true, false) a.Main.AddPage("main", main, true, false)
a.Main.AddPage("splash", ui.NewSplash(a.Styles, a.version), true, true)
a.toggleHeader(!a.Config.K9s.IsHeadless(), !a.Config.K9s.IsLogoless()) a.toggleHeader(!a.Config.K9s.IsHeadless(), !a.Config.K9s.IsLogoless())
if !a.Config.K9s.IsSplashless() {
a.Main.AddPage("splash", ui.NewSplash(a.Styles, a.version), true, true)
}
} }
func (a *App) initSignals() { func (a *App) initSignals() {
@ -523,7 +525,9 @@ func (a *App) Run() error {
a.Resume() a.Resume()
go func() { go func() {
<-time.After(splashDelay) if !a.Config.K9s.IsSplashless() {
<-time.After(splashDelay)
}
a.QueueUpdateDraw(func() { a.QueueUpdateDraw(func() {
a.Main.SwitchToPage("main") a.Main.SwitchToPage("main")
// if command bar is already active, focus it // if command bar is already active, focus it