Skip to content

feat(taints): add a picker for widely used taints - #565

Merged
janosmiko merged 2 commits into
mainfrom
feat/taint-presets-picker
Jul 27, 2026
Merged

feat(taints): add a picker for widely used taints#565
janosmiko merged 2 commits into
mainfrom
feat/taint-presets-picker

Conversation

@janosmiko

Copy link
Copy Markdown
Owner

Adding a taint meant typing a long key by hand — node-role.kubernetes.io/control-plane, node.kubernetes.io/out-of-service, the cloud-provider spot taints. A typo produces a taint nothing tolerates, silently.

Press p in the taint editor's list to pick from 12 real, documented taints, each with a note on what applying it does.

Common taints
  node-role.kubernetes.io/control-plane:NoSchedule          Reserve control-plane nodes
  CriticalAddonsOnly=true:NoSchedule                        System addons only (AKS, GKE, kubeadm)
  dedicated:NoSchedule                                      Dedicate nodes to one workload - set the value
  node.kubernetes.io/unschedulable:NoSchedule               Cordon: block new pods, keep running ones
  node.kubernetes.io/out-of-service=nodeshutdown:NoExecute  Shut-down node: force pod eviction and volume detach
  ...

Selecting one fills the add-row key, value and effect and focuses the key field — a preset is a starting point, not a commitment: all three fields stay editable and the taint still goes through ValidateTaint and the normal staging path.

Design notes

Why p. It mirrors a for manual add. A ctrl binding was avoidable, and the app-wide . presets key was unusable here — a taint key legitimately contains dots, so the add-row inputs must keep it. Esc backs out without adopting the highlighted preset.

What is deliberately excluded. The node-controller-managed condition taints (not-ready, unreachable, memory-pressure, disk-pressure, pid-pressure, network-unavailable) are absent: the controller adds and removes them from live node conditions, so a hand-applied copy is either redundant or fought over. A test enforces the exclusion.

Dispatcher headroom. Both taint overlays share one case in handleOverlayKeySecondary and renderOverlayContentExtended and split in handleTaintOverlayKey / renderTaintOverlay. Those dispatchers sit at the gocyclo cap (30) and view_overlays.go at the file-length cap (800) — two separate cases would breach all three.

Docs

  • Hint bar: p common taints in the editor, plus the picker's own hint bar
  • docs/keybindings.md: Node Actions entry updated

README and the in-app help do not document taint-editor internals at all (not even the existing a), so nothing was added there — the hint bar is the surface for these keys.

Test plan

  • internal/model/taint_presets_test.go — every preset passes ValidateTaint, no duplicate key+effect identities, no controller-managed condition taints, dedicated ships without a value
  • internal/app/taint_presets_test.go — open, select-fills-and-focuses, picked-preset-stages, esc-adopts-nothing, cursor clamping, render, both hint bars
  • go test -race ./... — all packages pass
  • golangci-lint run ./... — 0 issues

Adding a taint meant typing a long key by hand
(node-role.kubernetes.io/control-plane,
node.kubernetes.io/out-of-service, the cloud-provider spot taints). A
typo produces a taint nothing tolerates, silently.

Press p in the taint editor's list to pick from 12 real, documented
taints, each with a note on what applying it does. Selecting one fills
the add-row key, value and effect and focuses the key field, so a preset
is a starting point rather than a commitment: all three fields stay
editable and the taint still goes through the normal validation and
staging path.

p mirrors a for manual add. A ctrl binding was avoidable here, and the
app-wide "." presets key was unusable: a taint key legitimately contains
dots, so the add-row inputs must keep it.

The node-controller-managed condition taints (not-ready, unreachable,
memory-pressure, disk-pressure, pid-pressure, network-unavailable) are
deliberately excluded -- the controller adds and removes them from live
node conditions, so a hand-applied copy is either redundant or fought
over. A test enforces the exclusion.

Both taint overlays share one case in handleOverlayKeySecondary and
renderOverlayContentExtended and split in handleTaintOverlayKey /
renderTaintOverlay: those dispatchers sit at the gocyclo cap, and
view_overlays.go at the file-length cap.
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

Summary by CodeRabbit

  • New Features
    • Added a common taint picker to the taint editor.
    • Press p to browse available taint presets, view descriptions, and select one for editing.
    • Added keyboard navigation and clear picker guidance.
  • Documentation
    • Updated keybinding documentation to include the new p shortcut.
  • Bug Fixes
    • Preset selections are applied only after confirmation, while exiting preserves existing edits.

Walkthrough

Adds a model-level collection of common Kubernetes taint presets with validation tests. Integrates a preset picker overlay into the taint editor, including cursor and scroll state, keyboard navigation, selection application, rendering, routing, and hint bars. Adds application tests covering picker lifecycle, selection, staging, cancellation, cursor bounds, rendering, and hints. Updates keybinding documentation with the new p shortcut.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 78.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title concisely matches the main change: adding a taint preset picker.
Description check ✅ Passed The PR includes a clear summary, key changes, design notes, docs, and test plan; only a few template sections are omitted.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
internal/app/taint_presets_test.go (1)

15-32: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the picker through the top-level Bubble Tea flow.

These tests call picker internals directly, leaving the new overlay key/render dispatch paths untested. Add an integration test that opens, navigates, selects, and renders through the model update/view path using basePush80Model() and stripANSI(view).

As per coding guidelines, “Create Unit, Integration, and E2E tests for critical flows” and “For TUI tests using Bubble Tea, build a model with basePush80Model() and assert on stripANSI(view).”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/app/taint_presets_test.go` around lines 15 - 32, Extend taint preset
coverage with an integration test that uses basePush80Model() and drives the
picker through the top-level Bubble Tea update flow: open the overlay, navigate,
select an item, and verify rendering via stripANSI(view). Keep the existing
taintPresetKey helper for direct unit coverage, but assert the new overlay
dispatch and view behavior through the model’s update and view methods.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/keybindings.md`:
- Line 1059: Update the README’s taint-editor keybinding documentation to
include the new p shortcut for picking a common taint, matching the entry added
near the taint binding in docs/keybindings.md. Keep the help, hint bar, and
documentation descriptions synchronized.

In `@internal/app/taint_presets.go`:
- Around line 64-83: Update the picker motion handling around presetCursor to
consume count prefixes via the shared consumeCountPrefix flow, without manually
parsing digit keys. Apply the consumed count to j/k, g/G, and all paging
motions, preserving clamping at valid cursor bounds and existing single-step
behavior when no count is provided.

---

Nitpick comments:
In `@internal/app/taint_presets_test.go`:
- Around line 15-32: Extend taint preset coverage with an integration test that
uses basePush80Model() and drives the picker through the top-level Bubble Tea
update flow: open the overlay, navigate, select an item, and verify rendering
via stripANSI(view). Keep the existing taintPresetKey helper for direct unit
coverage, but assert the new overlay dispatch and view behavior through the
model’s update and view methods.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 904e5b47-c389-4572-85a2-1a5176e6f388

📥 Commits

Reviewing files that changed from the base of the PR and between c8c4eea and ce44d86.

📒 Files selected for processing (11)
  • docs/keybindings.md
  • internal/app/app_types.go
  • internal/app/overlay_hintbar.go
  • internal/app/taint_editor.go
  • internal/app/taint_editor_keys.go
  • internal/app/taint_presets.go
  • internal/app/taint_presets_test.go
  • internal/app/update_overlays.go
  • internal/app/view_overlays.go
  • internal/model/taint_presets.go
  • internal/model/taint_presets_test.go

Comment thread docs/keybindings.md
Comment thread internal/app/taint_presets.go
@janosmiko
janosmiko merged commit 1e3b7f1 into main Jul 27, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant