Docs

Tree View Hover Row Actions — Delivery Notes

Hover rename and delete buttons on every tree-view file/folder row, so those don’t require the right-click context menu — plus a fix so the folder-count pill (and the new buttons) stay visible at the panel’s right edge instead of scrolling off with long filenames. No ADR: this is a UI affordance, not an architectural decision. All in tranquil-automations.

Status

Implemented and iterated to final in a running window. Toggle: Settings → tranquil-automations → Show Rename/Delete Buttons on Tree View Rows (showRowActions, default on).

What shipped

  • lib/row-actions.js (new) — on hover, injects a small .tq-row-actions group (pencil + trash, inline SVGs) into the hovered row and removes it on leave (only one row decorated at a time). Buttons reuse the native tree-view:rename / tree-view:remove commands (so the real rename dialog and delete confirmation come for free) after selecting the row on mousedown.
  • lib/folder-counts.js — the count pill is now pinned to the visible right edge too, and yields (hides) while a row shows its action buttons.
  • lib/tranquil-automations.jsshowRowActions config + conditional activation (mirrors showFolderCounts).
  • styles/tranquil-automations.less — the chip + button styling.

The hard parts (and why)

  • Positioning: position: fixed + JS, not CSS. The tree-view scrolls horizontally (rows are min-content wide) and rows are not flex — so a row-relative right: runs off-screen for long names, and position: sticky won’t pin (a short row’s natural end is right after the name). Both the buttons and the pill are therefore placed by JS from the tree-view’s viewport rect (getBoundingClientRect), re-run on hover/scroll/resize. The button group stays a DOM child of the row so it inherits the row’s text color and hovering it still counts as hovering the row.
  • One injector owns the tree observer. An early version gave row-actions its own MutationObserver; it cross-triggered folder-counts’ observer (each one’s writes woke the other), corrupting both on expand/collapse. Fixed by making row-actions injection hover-driven (a delegated mouseover, no observer) and letting folder-counts remain the single tree observer. Pill-vs-buttons overlap is resolved in folder-counts (it hides its badge when a .tq-row-actions is present in the header), so there’s one authority, no opacity race.
  • Theme quirks ([[theme-development]]):
    • The business themes don’t export ui-variables, so the chip’s opaque backdrop is read at runtime via getComputedStyle(treeView).backgroundColor (theme-agnostic, keeps the filename from showing through), and the icons use color: inherit.
    • The business base.less styles bare button { background: … !important } / button:hover { … !important }, so the button fills need !important to win — the usual “avoid !important” guideline is overridden here because we’re beating a theme’s own !important.

Behaviour notes

  • Project roots are skipped (no rename/delete on a root). A file with no pill just gets buttons.
  • Delete keeps the native “Move to Trash” confirmation; rename opens the native dialog.
  • Hover fills: blue = rename, red = delete (white icon, slight pop + coloured glow); the two are spaced so a hovered button’s glow doesn’t reach its neighbour.