Skip to content

feat: workspace drag-to-reorder (#492)#1233

Closed
bergeouss wants to merge 2 commits intonesquena:masterfrom
bergeouss:feat/492-workspace-drag-reorder
Closed

feat: workspace drag-to-reorder (#492)#1233
bergeouss wants to merge 2 commits intonesquena:masterfrom
bergeouss:feat/492-workspace-drag-reorder

Conversation

@bergeouss
Copy link
Copy Markdown
Contributor

Summary

Implements drag-and-drop reordering for workspaces in the sidebar panel.

Changes

Backend ()

  • New endpoint: — accepts and rewrites in the given order
  • Unmentioned workspaces are preserved and appended (safety net)
  • Input validation: rejects empty/missing paths, deduplicates, strips whitespace, ignores unknown paths

Frontend ()

  • Added HTML5 drag-and-drop to workspace rows in
  • Drag handle (grip-vertical icon) on the left of each row
  • Drop indicator: target row highlighted when dragging over it
  • On drop: DOM reorder + API call to persist the new order
  • Cursor-only reorder on touch devices (fallback via cursor: grab)

Icon ()

  • Added Lucide icon (6-dot grip handle)

Styles ()

  • — grab cursor, muted color, opacity on hover
  • — reduced opacity while dragging
  • — highlighted drop target
  • Light/dark mode variants

i18n ()

  • Added workspace_drag_hint and workspace_reorder_failed in all 7 locales (en, ru, es, de, zh, zh-Hant, ko)

Tests (11)

  • 7 backend tests: order change, whitespace stripping, preserve unmentioned, empty/missing paths rejection, deduplication, unknown path handling
  • 4 frontend tests: i18n key parity across locales, icon existence, drag attributes in JS, CSS classes

All pass: 2847 passed (1 pre-existing failure in test_sprint31).

Closes #492

- Add POST /api/workspaces/reorder endpoint to reorder workspace list
- Implement HTML5 drag-and-drop in workspace panel (panels.js)
- Add grip-vertical drag handle icon (icons.js)
- Add drag visual states: dragging, drag-over, cursor styles (style.css)
- Add i18n keys (workspace_drag_hint, workspace_reorder_failed) in all 7 locales
- 11 tests: 7 backend (order, strip, preserve, dedup, unknown, validation) + 4 frontend

Closes nesquena#492
@nesquena-hermes
Copy link
Copy Markdown
Collaborator

Thanks for this PR! Drag-to-reorder for workspaces is a clean UX improvement, and the backend endpoint with proper input validation (dedup, whitespace stripping, unknown path handling) is the right approach.

A few things to confirm before merge:

API endpoint conflict
The PR body mentions PUT /api/workspaces/reorder but the formatting was stripped — confirming the actual endpoint path. Is this a new endpoint, or does it extend an existing workspace management endpoint?

Unmentioned workspaces appended
"Unmentioned workspaces are preserved and appended" — this is a sensible safety net. One edge case: if a workspace was deleted on disk between the drag event and the API call, does the backend silently skip the missing path or return an error? The frontend might be holding a stale list.

Touch device fallback
"Cursor-only reorder on touch devices (fallback via cursor: grab)" — confirming this means drag-to-reorder is not functional on touch (no touch event handlers), just visually indicated as draggable. This is fine as a v1, but worth noting explicitly in the PR so reviewers don't expect touch support.

Optimistic vs. confirmed reorder
Does the DOM reorder happen before or after the API call confirms? If it's optimistic (DOM first, API second), what happens if the API call fails — is the order reverted, or does the UI stay in the new (unsaved) order?

11 tests with 7 backend + 4 frontend, including drag attribute and CSS class coverage, looks thorough. This looks close to ready once the above are confirmed!

…1233)

- Remove raw err.message from error toast to prevent leaking internal error
  details to the UI (Path Trust Boundary Rule)
- Use i18n key workspace_reorder_failed for the sanitized message
- Addresses reviewer concern about optimistic vs confirmed reorder:
  the reorder is confirmed (API-first), not optimistic
@bergeouss
Copy link
Copy Markdown
Contributor Author

@nesquena-hermes: confirmed reorder, not optimistic. Visual re-render only after API res.ok. Backend _handle_workspace_reorder (routes.py:3317) preserves unmentioned workspaces (appends at end, lines 3337-3340). Path-based ordering (not index). Synchronous backend, no race condition. Last-write-wins for concurrent clients. Ready for merge!

@nesquena-hermes
Copy link
Copy Markdown
Collaborator

Thanks for the clear confirmation, @bergeouss!

Confirmed reorder (not optimistic): Visual re-render only after res.ok is the right call — no stale state on API failure.

Backend path-based ordering with appended unmentioned workspaces: Lines 3337-3340 preserving unmentioned workspaces at the end is the correct safe behavior.

Race condition / concurrent clients: Synchronous backend with last-write-wins is acceptable for this use case — workspace reordering is a low-frequency user action.

The drag-to-reorder endpoint is clearly scoped and the backend implementation handles all the edge cases flagged in review. This looks ready to merge! 🎉

🤖 Automated triage via nesquena-hermes

nesquena added a commit that referenced this pull request Apr 29, 2026
… them going forward

Two artifacts from a contributor's local graphify (code-graph) tooling
slipped into PR #1233 (workspace drag-to-reorder):

  .graphify_cached.json    (3.5MB)
  .graphify_uncached.txt   (refs /home/fr33m1nd/hermes-webui-src/...)

Neither belongs in source control: the .json is an autogenerated cache
of node IDs for a graph visualisation tool, and the .txt is a
file-discovery index pointing at the contributor's local workspace
(/home/fr33m1nd/hermes-webui-src/) — paths that aren't valid for any
other developer.

The repo already ignores graphify-out/ but these two top-level dotfiles
weren't covered. Add explicit ignore entries and remove the tracked
copies.

No code change. CI remains green on 3.11/3.12/3.13.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@nesquena-hermes
Copy link
Copy Markdown
Collaborator

Merged in v0.50.237 via #1243. Thank you @bergeouss! 🎉

GeoffBao pushed a commit to GeoffBao/hermes-webui that referenced this pull request Apr 29, 2026
…1233)

- Remove raw err.message from error toast to prevent leaking internal error
  details to the UI (Path Trust Boundary Rule)
- Use i18n key workspace_reorder_failed for the sanitized message
- Addresses reviewer concern about optimistic vs confirmed reorder:
  the reorder is confirmed (API-first), not optimistic
JKJameson pushed a commit to JKJameson/hermes-webui that referenced this pull request Apr 29, 2026
…1233)

- Remove raw err.message from error toast to prevent leaking internal error
  details to the UI (Path Trust Boundary Rule)
- Use i18n key workspace_reorder_failed for the sanitized message
- Addresses reviewer concern about optimistic vs confirmed reorder:
  the reorder is confirmed (API-first), not optimistic
JKJameson pushed a commit to JKJameson/hermes-webui that referenced this pull request Apr 29, 2026
… them going forward

Two artifacts from a contributor's local graphify (code-graph) tooling
slipped into PR nesquena#1233 (workspace drag-to-reorder):

  .graphify_cached.json    (3.5MB)
  .graphify_uncached.txt   (refs /home/fr33m1nd/hermes-webui-src/...)

Neither belongs in source control: the .json is an autogenerated cache
of node IDs for a graph visualisation tool, and the .txt is a
file-discovery index pointing at the contributor's local workspace
(/home/fr33m1nd/hermes-webui-src/) — paths that aren't valid for any
other developer.

The repo already ignores graphify-out/ but these two top-level dotfiles
weren't covered. Add explicit ignore entries and remove the tracked
copies.

No code change. CI remains green on 3.11/3.12/3.13.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
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.

feat(workspace): drag-to-reorder workspaces in the workspace list

2 participants