From d3c8a7c6a51140b41e3377886a3c3c101569285b Mon Sep 17 00:00:00 2001 From: nesquena-hermes Date: Tue, 5 May 2026 16:40:06 +0000 Subject: [PATCH] fix(workspace): hide 'Double-click to rename' tooltip on folders (#1710) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The file-tree row tooltip says 'Double-click to rename' on every entry, but folders don't actually rename on double-click — they navigate via loadDir(). The tooltip is therefore misleading on directory rows. Reported by @Deor in the WebUI Discord testers thread (May 5 2026): 'Ah that works yeah. May want to change the popup text as it also says double click at the moment.' Fix: gate the tooltip on item.type !== 'dir' so it only attaches to file rows, where double-click does what the hint advertises. Folder rename still reachable via the right-click context menu (unchanged). Companion to #1698/#1702/#1707 — completes the rename-affordance triage: - #1698 fixed: dblclick rename was unreachable on files (preview hijacked) - #1707 fixed: single-click on filename did nothing (over-aggressive guard) - #1710 (this PR): tooltip claimed dblclick-rename on folders too Closes #1710 Tests: 4 source-level regression tests in tests/test_1710_folder_tooltip.py guard the gate, the unchanged dir-dblclick navigate behaviour, the i18n key, and that files still receive the tooltip. All 13 file-tree handler tests (4 new + 9 from #1707) pass. --- static/ui.js | 6 ++- tests/test_1710_folder_tooltip.py | 76 +++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 tests/test_1710_folder_tooltip.py diff --git a/static/ui.js b/static/ui.js index 2f00298c..5dd2fe93 100644 --- a/static/ui.js +++ b/static/ui.js @@ -5701,7 +5701,11 @@ function _renderTreeItems(container, entries, depth){ // Name const nameEl=document.createElement('span'); - nameEl.className='file-name';nameEl.textContent=item.name;nameEl.title=t('double_click_rename'); + nameEl.className='file-name';nameEl.textContent=item.name; + // Tooltip only on FILES — dblclick renames them. On directories, dblclick + // navigates into the folder; rename lives in the right-click context menu + // (the "Double-click to rename" hint here would be misleading). #1710. + if(item.type!=='dir')nameEl.title=t('double_click_rename'); // Single-click opens (file) or expand-toggles (dir) but is debounced 300ms so a // double-click can cancel it and trigger rename instead. Without the debounce, the // click bubbles to el.onclick before dblclick can fire — that's #1698. Without the diff --git a/tests/test_1710_folder_tooltip.py b/tests/test_1710_folder_tooltip.py new file mode 100644 index 00000000..4ced9853 --- /dev/null +++ b/tests/test_1710_folder_tooltip.py @@ -0,0 +1,76 @@ +"""Tests for #1710 — file-tree tooltip says "Double-click to rename" on folders too, +but folders don't rename on double-click; they navigate via loadDir(). The tooltip +is therefore misleading on directory rows. + +Fix: gate the tooltip on `item.type !== 'dir'` so it appears only on files. +Folder rename is still reachable via the right-click context menu. +""" +from pathlib import Path + +import pytest + + +REPO_ROOT = Path(__file__).resolve().parents[1] +UI_JS_PATH = REPO_ROOT / "static" / "ui.js" + + +def _read_ui_js() -> str: + with open(UI_JS_PATH, encoding="utf-8") as f: + return f.read() + + +def _name_block() -> str: + """Source slice covering the file-tree row's name span construction.""" + src = _read_ui_js() + start = src.find("// Name\n const nameEl=document.createElement('span');") + assert start >= 0, "name span construction marker not found in static/ui.js" + end = src.find("el.appendChild(nameEl);", start) + assert end >= 0, "el.appendChild(nameEl) not found after name span" + return src[start:end] + + +class TestFolderTooltipGated: + """The 'Double-click to rename' tooltip must only attach to files, not dirs.""" + + def test_tooltip_assignment_is_guarded_by_item_type(self): + block = _name_block() + # We expect the tooltip line to be wrapped in an `if(item.type!=='dir')` guard. + # The pre-fix shape was `nameEl.title=t('double_click_rename');` unconditionally. + # Find every line that assigns nameEl.title and confirm at least one is gated. + gated = "if(item.type!=='dir')nameEl.title=t('double_click_rename')" + unguarded = " nameEl.className='file-name';nameEl.textContent=item.name;nameEl.title=t('double_click_rename');" + assert gated in block, ( + "tooltip assignment must be guarded by `if(item.type!=='dir')` so directories " + "do not show the misleading 'Double-click to rename' hint (#1701)" + ) + assert unguarded not in block, ( + "the pre-fix unguarded tooltip assignment is still present — folders will " + "still show the misleading hint" + ) + + def test_dir_dblclick_still_navigates_not_renames(self): + """Sanity: directory dblclick path is unchanged — must still call loadDir().""" + block = _name_block() + assert "if(item.type==='dir'){loadDir(item.path);return;}" in block, ( + "directory dblclick must still navigate (call loadDir); the rename-only " + "tooltip gating depends on this contract being unchanged" + ) + + def test_files_still_get_tooltip(self): + """Sanity: the tooltip text is still defined for files via the i18n key.""" + block = _name_block() + assert "t('double_click_rename')" in block, ( + "tooltip i18n key must still be referenced — the gate hides it for dirs, " + "not for files" + ) + + def test_i18n_key_still_defined_in_all_locales(self): + """The i18n key must remain defined in every locale block in static/i18n.js.""" + i18n = (REPO_ROOT / "static" / "i18n.js").read_text(encoding="utf-8") + # i18n.js has 9 locale blocks with the same key. Lock that the key still exists + # at least 5 times (en, plus a quorum of locales) — exact count is i18n maintenance. + count = i18n.count("double_click_rename:") + assert count >= 5, ( + f"i18n key 'double_click_rename' should be defined in multiple locales; " + f"found {count} occurrences — did this PR accidentally drop translations?" + )