Skip to content

feat(sidebar): drag-and-drop connection reordering (#748) - #817

Merged
cevheri merged 5 commits into
libredb:mainfrom
Asgabani:feat/connection-reorder
Sep 15, 2026
Merged

cevheri merged 5 commits into
libredb:mainfrom
Asgabani:feat/connection-reorder

Conversation

@Asgabani

Copy link
Copy Markdown
Contributor

Closes #748.

What changed

  • StorageData.connection_order (new collection): a flat list of connection ids in the user's preferred order, mirroring the existing dismissed_seeds-style separate-list pattern rather than a field on DatabaseConnection — a managed:true connection is replaced wholesale on every load (see mergeManagedConnections), so a field on the connection object itself would be silently discarded on reload.
  • storage.getConnectionOrder() / storage.setConnectionOrder() on the storage facade, wired into useStorageSync's migrate/pull paths like every other collection.
  • applyConnectionOrder() (src/lib/connection-order.ts): sorts a connections array by the persisted order; a connection absent from the order (never dragged, or created after the user last reordered) sorts after every connection the order does know about, in its original relative position (Array.prototype.sort is spec-stable, so that fallback needs no code of its own).
  • useConnectionOrder() hook: useSyncExternalStore over the facade, same shape as the repo's other storage-backed hooks.
  • ConnectionsList / ConnectionItem: native HTML5 drag-and-drop (no new dependency) — a drag handle appears on hover once onReorderConnections is passed and the list has more than one connection; dropping persists the new order via the facade.

Note on #694

#748's "Done when" mentions #694 (favorites): if that lands first, a favorited group should keep its own drag order rather than the two features competing for one order field. Since #694 hasn't merged yet, this PR reorders the flat connections list only. connectionOrder/onReorderConnections are threaded through as plain optional props (not baked into any favorites-aware grouping), so whichever PR lands second can partition the already-ordered list into favorite/non-favorite groups without this one needing to change.

Testing

Ran locally (bun run format && bun run lint && bun run typecheck && bun run knip && bun run chart:check && bun run channels:showcase:check && bun run readme:check && bun run security:check && bun run test && bun run build, plus bun run build:lib && bun run attw):

  • format / lint / typecheck / knip: clean. Lint warning count unchanged from a clean checkout (189, compared via git stash).
  • All four drift guards (chart, channels showcase, readme, security): pass.
  • bun run test:components: 39/39 groups pass.
  • bun run test: same 13 pre-existing failures as a clean checkout (Helm binary not installed, missing built standalone zip) — verified identical via git stash before/after. No live Postgres/MySQL in this sandbox, so DB-integration tests weren't exercised beyond what's already mocked.
  • bun run test:coverage && bun run coverage:check: 100.00% line coverage on the merged lcov.
  • bun run build, bun run build:lib, bun run attw: all succeed (ConnectionsList/Sidebar are reachable from the embeddable workspace export surface).

If CI surfaces something this sandbox couldn't (Helm chart tests, live DB integration tests), happy to fix it up.

Connections render in a persisted custom order rather than storage's
natural array order. A new connection_order collection (flat id list)
is stored via the existing write-through storage facade, and
ConnectionsList gains native HTML5 drag-and-drop to reorder its rows,
persisting the new order on drop.
@codecov

codecov Bot commented Sep 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@cevheri cevheri left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good work, @Asgabani. I ran it in the app in Chromium and in Firefox: the handle on hover, dragging up and down, the order surviving a reload, a connection created afterwards appending last, and a drag never selecting the row. onDragStart does not call dataTransfer.setData, which used to stop Firefox starting a drag at all, and Firefox 155 is fine without it. Two things before I merge.

  1. storage.deleteConnection does not prune connection_order. I deleted a connection through the UI and its id was still in the stored order afterwards, and it keeps being pushed to server storage. deleteConnection is already where a sibling id list is maintained on delete: dismissed_seeds is recorded there. Same place, with a test.

  2. docs/STORAGE.md is the collection inventory and it still describes ten: the collection column enumeration, the "10 collections" line and the table under it, the localStorage key map, the facade API row for Connections (it already lists getDismissedSeeds()), and the second "10 collections" in the migration walkthrough. Two code comments count them too: encrypting-provider.ts says "the remaining six hold metadata", which is the written justification for encrypting only connections, and connection-secrets.ts says "all ten collections". #812 adds a collection as well, so whichever of the two lands second has to re-derive that number rather than write 11.

One note, no change needed: the mobile list gets the props, but HTML5 drag is pointer-only, so nothing there can fire on a phone. The handle needs hover, so nothing looks broken either.

- deleteConnection now prunes the deleted id out of connection_order
  too, mirroring the existing dismissed_seeds handling.
- docs/STORAGE.md's collection inventory (schema table, collection
  reference table, localStorage key map, facade API row, and both
  "10 collections" call-outs) now accounts for connection_order,
  along with the two code comments in encrypting-provider.ts and
  connection-secrets.ts that counted collections.
- Updated tests/components/studio/source-tab.test.tsx's storage mock,
  which predates this branch's reorder work and was missing the two
  methods useConnectionOrder calls.
@Asgabani

Copy link
Copy Markdown
Contributor Author

Addressed both:

  1. `deleteConnection` now prunes the deleted id out of `connection_order` too, mirroring the existing `dismissed_seeds` handling, with tests.
  2. `docs/STORAGE.md`'s collection inventory is updated everywhere it counted collections (schema table, collection reference table, localStorage key map, facade API row, both "10 collections" call-outs), plus the two code comments in `encrypting-provider.ts` and `connection-secrets.ts`. This PR's own count is 11 (favorites doesn't exist on this branch yet) — whichever of feat(sidebar): add a favorite/pin toggle for connections #812/feat(sidebar): drag-and-drop connection reordering (#748) #817 you merge second will need a quick recount to 12, as you flagged.

Rebased onto latest `main` — that pulled in a new `tests/components/studio/source-tab.test.tsx` whose storage mock predates this branch and was missing the two methods `useConnectionOrder` calls, so I added those too (unrelated to your feedback, just needed to keep tests green post-merge).

Ran the full local suite again: format/lint/typecheck/knip clean, all four drift guards pass, `test:components` 46/46 groups, core suite at the same pre-existing 13 environment-gap failures (Helm/standalone-zip) as a clean checkout, 100.00% coverage, build green.

…ns sections

With libredb#812 merged the list renders a Favorites section above Connections, and both are now cut from the one saved order, so each keeps the user's order within itself.

A drop onto a row in the other section is ignored and that row is not highlighted: the dragged row would stay in its own section, so accepting it would only change the saved order in a way nothing on screen shows. A row alone in its section gets no drag handle.

@cevheri cevheri left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

merging shortly, fixed conflicts

@cevheri

cevheri commented Sep 15, 2026

Copy link
Copy Markdown
Member

Thanks @Asgabani. #812 landed first, so I merged main into this branch and pushed two commits on top of yours rather than asking you for another round.

The merge keeps both sides. The collection inventory is now 12 in docs/STORAGE.md, and the two code comments say "eight" and "twelve".

The follow-up commit is where the two features meet. Favorites and Connections are both cut from the one saved order, so each section keeps your order within itself. A drop onto a row in the other section is ignored and that row is not highlighted, because the dragged row would stay in its own section and the only effect would be an invisible change to the saved order. A row alone in its section gets no handle. Tests are in ConnectionsList.test.tsx.

@cevheri
cevheri merged commit b86471f into libredb:main Sep 15, 2026
22 checks passed
cevheri added a commit that referenced this pull request Sep 15, 2026
542 files and 17,477 tests, 100% of 56,883 lines. #817's test files were also run
24 times at once each, under the per-file runner they have not met before: 24/24.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

database-provider enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No way to reorder saved connections

2 participants