diff --git a/CHANGELOG.md b/CHANGELOG.md index 02592b5c..6064064d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ - **PR #TBD** by @Michaelyklam (refs #1925) — Clarify the RuntimeAdapter Slice 3c state after #2544 shipped. The RFC now distinguishes shipped `/api/goal` routing through `RuntimeAdapter.update_goal(...)` from the still-staged `queue_message(...)` protocol method, and explicitly warns not to add a new server-side queue endpoint or queue scheduler merely for adapter symmetry while `/queue` remains browser-side queue/drain behavior. +### Fixed + +- **PR #2563** by @Michaelyklam (closes #2554) — Align workspace-tree file rows with sibling directory rows by reserving the same expand/collapse toggle slot for files. Expanded directories now show child files stepped in at the same icon column as child folders, while directory toggles and file interactions stay unchanged. + + ## [v0.51.91] — 2026-05-18 — Release BO (stage-384 — 5-PR full sweep batch — reasoning-replay history fix + archive-extract per-session inbox + fallback streaming warnings + sanitized custom-provider env hints + Slice 3c queue/goal adapter routing) ### Fixed diff --git a/docs/pr-media/2554/tree-indent-after.png b/docs/pr-media/2554/tree-indent-after.png new file mode 100644 index 00000000..8137b93c Binary files /dev/null and b/docs/pr-media/2554/tree-indent-after.png differ diff --git a/docs/pr-media/2554/tree-indent-before.png b/docs/pr-media/2554/tree-indent-before.png new file mode 100644 index 00000000..13173d80 Binary files /dev/null and b/docs/pr-media/2554/tree-indent-before.png differ diff --git a/static/style.css b/static/style.css index e4714e21..6d4bacb9 100644 --- a/static/style.css +++ b/static/style.css @@ -1423,6 +1423,7 @@ .file-item:hover{background:var(--hover-bg);color:var(--text);} .file-item.active{background:var(--accent-bg);color:var(--accent-text);} .file-tree-toggle{font-size:10px;color:var(--muted);flex-shrink:0;width:10px;text-align:center;line-height:1;} + .file-tree-toggle-placeholder{display:inline-block;flex:0 0 10px;width:10px;line-height:1;} .file-item.file-empty{color:var(--muted);opacity:.5;font-style:italic;cursor:default;font-size:11px;} .file-item.file-empty:hover{background:none;color:var(--muted);} .preview-area{flex:1;overflow:auto;padding:14px;flex-direction:column;gap:8px;display:none;opacity:0;transition:opacity .15s;} diff --git a/static/ui.js b/static/ui.js index cb78ba09..380ef090 100644 --- a/static/ui.js +++ b/static/ui.js @@ -7565,6 +7565,13 @@ function _renderTreeItems(container, entries, depth){ const isExpanded=S._expandedDirs.has(item.path); arrow.textContent=isExpanded?'\u25BE':'\u25B8'; el.appendChild(arrow); + }else{ + // Keep file icons aligned with sibling directories that occupy this + // slot with the expand/collapse toggle. #2554 + const spacer=document.createElement('span'); + spacer.className='file-tree-toggle-placeholder'; + spacer.setAttribute('aria-hidden','true'); + el.appendChild(spacer); } // Icon diff --git a/tests/test_issue2554_workspace_tree_file_indent.py b/tests/test_issue2554_workspace_tree_file_indent.py new file mode 100644 index 00000000..3908f02c --- /dev/null +++ b/tests/test_issue2554_workspace_tree_file_indent.py @@ -0,0 +1,39 @@ +"""Regression coverage for #2554 — workspace tree file rows align with directories.""" + +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[1] +UI_JS = (REPO_ROOT / "static" / "ui.js").read_text(encoding="utf-8") +STYLE_CSS = (REPO_ROOT / "static" / "style.css").read_text(encoding="utf-8") + + +def _render_tree_item_toggle_block() -> str: + start = UI_JS.index("if(item.type==='dir'){\n // Toggle arrow for directories") + end = UI_JS.index("\n\n // Icon", start) + return UI_JS[start:end] + + +def test_file_rows_get_toggle_placeholder_before_icon(): + block = _render_tree_item_toggle_block() + + assert "spacer=document.createElement('span')" in block + assert "spacer.className='file-tree-toggle-placeholder'" in block + assert "spacer.setAttribute('aria-hidden','true')" in block + assert "el.appendChild(spacer);" in block + + spacer_idx = UI_JS.index("spacer.className='file-tree-toggle-placeholder'") + icon_idx = UI_JS.index("const iconEl=document.createElement('span');", spacer_idx) + assert spacer_idx < icon_idx, "file-row spacer must be appended before the file icon" + + +def test_placeholder_matches_directory_toggle_slot_width(): + assert ".file-tree-toggle{" in STYLE_CSS + assert ".file-tree-toggle-placeholder{" in STYLE_CSS + placeholder_start = STYLE_CSS.index(".file-tree-toggle-placeholder{") + placeholder_end = STYLE_CSS.index("}", placeholder_start) + placeholder = STYLE_CSS[placeholder_start:placeholder_end] + + assert "width:10px" in placeholder + assert "flex:0 0 10px" in placeholder + assert "display:inline-block" in placeholder