From 40cf6a151f0693af6522e4305a5f4eaf65a6fba3 Mon Sep 17 00:00:00 2001 From: Alex Cantu Date: Mon, 1 Sep 2025 17:38:26 -0500 Subject: [PATCH] feat: Add context deletion functionality (#3489) * Add delete functionality for Kubernetes contexts This adds the ability to delete Kubernetes contexts using the 'd' key in the context view. The implementation includes: - New delete command bound to 'd' key - Confirmation dialog before deletion - Error handling and UI refresh after deletion * Refactor context delete dialog to use standard dialog component - Replace custom delete confirmation with dialog.ShowConfirm - Add read-only mode checks for rename and delete commands - Change delete keybinding from 'd' to 'Ctrl+d' - Remove unused deletePage constant and related functions - Simplify delete callback logic * Refactor context view key bindings to separate dangerous operations * Fix linting error --- internal/view/context.go | 26 ++++++++++++++++++++++++++ internal/view/context_test.go | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/internal/view/context.go b/internal/view/context.go index c37f88d6..afd2c34a 100644 --- a/internal/view/context.go +++ b/internal/view/context.go @@ -12,6 +12,7 @@ import ( "github.com/derailed/k9s/internal/dao" "github.com/derailed/k9s/internal/slogs" "github.com/derailed/k9s/internal/ui" + "github.com/derailed/k9s/internal/ui/dialog" "github.com/derailed/k9s/internal/view/cmd" "github.com/derailed/tcell/v2" "github.com/derailed/tview" @@ -40,7 +41,14 @@ func NewContext(gvr *client.GVR) ResourceViewer { func (c *Context) bindKeys(aa *ui.KeyActions) { aa.Delete(ui.KeyShiftA, tcell.KeyCtrlSpace, ui.KeySpace) + if !c.App().Config.IsReadOnly() { + c.bindDangerousKeys(aa) + } +} + +func (c *Context) bindDangerousKeys(aa *ui.KeyActions) { aa.Add(ui.KeyR, ui.NewKeyAction("Rename", c.renameCmd, true)) + aa.Add(tcell.KeyCtrlD, ui.NewKeyAction("Delete", c.deleteCmd, true)) } func (c *Context) renameCmd(evt *tcell.EventKey) *tcell.EventKey { @@ -54,6 +62,24 @@ func (c *Context) renameCmd(evt *tcell.EventKey) *tcell.EventKey { return nil } +func (c *Context) deleteCmd(evt *tcell.EventKey) *tcell.EventKey { + contextName := c.GetTable().GetSelectedItem() + if contextName == "" { + return evt + } + + d := c.App().Styles.Dialog() + dialog.ShowConfirm(&d, c.App().Content.Pages, "Delete", fmt.Sprintf("Delete context %q?", contextName), func() { + if err := c.App().factory.Client().Config().DelContext(contextName); err != nil { + c.App().Flash().Err(err) + return + } + c.Refresh() + }, func() {}) + + return nil +} + func (c *Context) renameDialogCallback(form *tview.Form, contextName string) error { app := c.App() input := form.GetFormItemByLabel(inputField).(*tview.InputField) diff --git a/internal/view/context_test.go b/internal/view/context_test.go index 3fac43b7..12df2044 100644 --- a/internal/view/context_test.go +++ b/internal/view/context_test.go @@ -17,5 +17,5 @@ func TestContext(t *testing.T) { require.NoError(t, ctx.Init(makeCtx(t))) assert.Equal(t, "Contexts", ctx.Name()) - assert.Len(t, ctx.Hints(), 5) + assert.Len(t, ctx.Hints(), 6) }