Skip to content

feat(drive): list view on frappe-ui/list, inline folder tree, derived breadcrumbs - #378

Merged
safwansamsudeen merged 11 commits into
developfrom
fix/frappe-ui-typography
Jul 30, 2026
Merged

feat(drive): list view on frappe-ui/list, inline folder tree, derived breadcrumbs#378
safwansamsudeen merged 11 commits into
developfrom
fix/frappe-ui-typography

Conversation

@safwansamsudeen

@safwansamsudeen safwansamsudeen commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Drive's list view now runs on frappe-ui/list, folders expand inline as a tree, and breadcrumbs are derived from the route instead of a mutable global. Plus Writer list-numbering and tab fixes.

Changes

List view on frappe-ui/list — real column tracks, inset dividers, a sticky sortable header, and the typography/dialog cleanups that came with it.

Folders expand inline. Hovering a row swaps the folder icon for a chevron; clicking it expands the folder underneath. Clicking elsewhere in the row still navigates in. Nested rows behave like any other row — selection, context menu, rename, move, delete, drag-and-drop in and out of a subtree.

Breadcrumbs are derived. The trail was a mutable global written from eight places, and it doubled as ambient state — the sidebar highlight and the personal flag on upload both read crumb 0, so a missed writer left it stale or empty. It is now computed from the route plus the entity the open page publishes. This fixes the navbar vanishing mid-navigation, and moving a folder updating its trail (which never worked; a loading placeholder hid it).

Writer — list numbering no longer restarts when you edit around a list, and reordering tabs can't duplicate them.

Notable fixes along the way

  • Rename surfaced an empty error toast and left the new name on screen after a failure.
  • MoveDialog closed before awaiting the move, so its @complete refetch never ran.
  • Presentations crashed the list view: the API returns title, not file_name.
  • Inline rename was unreadable in dark mode (bg-surface-white is a retired token, so the background was dropped).
  • Keyboard shortcuts lived in two divergent copies, one per view.

Testing

  • folderTree.test.ts — 16 cases covering fetch params, the stale-response race, collapse-drops-subtree, path keys, skeleton counts.
  • breadcrumbs.spec.ts — 7 e2e cases: section names, nested trails, ancestor navigation, deep links, browser back, rename, move.
  • rename.spec.ts, tabs.spec.ts — breadcrumb rename persistence; tab reordering preserves content.

Full suite: 1057 unit tests, 34 e2e.

Known limits

⌘A and the filter chips apply to top-level rows only, socket updates patch just the current folder, and the chevron isn't keyboard-reachable yet. The navbar still flashes on navigation because DriveLayout keys its router-view on $route.fullPath, remounting the page and navbar on every route change — the skeleton makes it read as loading, but the remount itself is untouched.

🤖 Generated with Claude Code

@safwansamsudeen

safwansamsudeen commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator Author

Also redoes list view, adds infinite scrolling, removes rename dialog, and a couple more long pending issues.

safwansamsudeen and others added 2 commits July 29, 2026 14:38
…er fixes

fix(writer): join adjacent same-type list nodes after each transaction so
  deleting a block between two lists (or Enter-lifting an item out) no longer
  restarts numbering; map boundaries through tr.mapping, require matching list
  types, and collect top-level boundaries since descendants() skips the doc node
fix(drive): let an open dialog's own Escape handler run instead of clearing the
  selection in GridView/ListView (preventDefault was blocking Reka's dismiss)
fix(writer): focus the comment editor without scrolling, on mount and when it
  flips into edit mode
refactor(drive): use the Button component for UploadTracker controls and
  MoveDialog breadcrumbs; tidy ConfirmDialog markup and use a solid trash button
refactor(writer): drop the watermark logic from PDF and print export
style(writer): sentence-case the settings labels
style(drive): add gap in the UserListSettings avatar row

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… typography

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@safwansamsudeen
safwansamsudeen force-pushed the fix/frappe-ui-typography branch from fd60996 to c4d46ae Compare July 29, 2026 09:09
Clicking a folder's icon in the list view opens it as a tree in place
instead of navigating: hovering a row swaps the icon for a chevron, and
children render indented under the folder with the full row behaviour
(selection, shift-range, context menu, rename, share, move, delete,
drag-and-drop in and out).

- data/folderTree.js holds the expansion state and per-folder children,
  fetched with the parent's sort. Collapsing drops the subtree and
  returns the hidden names so ListView can deselect them; a per-folder
  token discards responses a newer fetch has superseded.
- Rows carry path-based keys, since a folder and its child can both be
  top-level rows in Favourites/Recents/search.
- GenericPage resolves selections and actions against children too, so
  the toolbar operates on nested rows; the tree resets on navigation and
  re-fetches open subtrees on a sort change.
- Loading shows one skeleton row per known child (capped at 20) so the
  layout doesn't shift when children land.

Also in this branch:
- inline rename: select the base name on focus, reclaim focus for the
  whole grace window after opening, roll the title back if the rename
  request fails, and surface the server message instead of the raw error
- sortEntities: folders sink below files on a size sort and order by
  child count; nullish values sort last; smart sort only for name
- move the list/grid keyboard shortcuts up to GenericPage
- dark-mode scrollbar colours, stable scrollbar gutter, toolbar filter
  placement, sort button hugs its label, grid rows top-aligned
- e2e coverage for renaming a document from the breadcrumb

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@safwansamsudeen safwansamsudeen changed the title fix(writer): keep list numbering continuous, plus assorted drive/writer fixes feat(drive): inline folder tree in the list view, plus list-view migration and writer/drive fixes Jul 30, 2026
safwansamsudeen and others added 8 commits July 30, 2026 10:32
Tab lookups scanned the doc with `descendants` and returned false to stop,
which only skips a node's children, not its siblings — so with two same-id
tabs every lookup silently used the last match (print emitted only the
second half) while the node view unhid both. Route all lookups through
tabsIn/findTab, and refuse transactions that introduce a duplicate id.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The breadcrumb trail was a mutable global written from eight places
(route hooks, openEntity, rename, move dialog, and four pages), and it
doubled as ambient app state: the sidebar highlight, isHomeContext, and
the personal flag on image upload all read crumb 0. Any writer that
missed left a stale or empty trail, which is why the navbar kept
disappearing.

pageBreadcrumbs is now computed from the route plus a single crumbEntity
published by the page that owns it. Every setter is gone; what remains
acts on the entity, never on a trail.

Also fixed along the way:
- Navbar no longer unmounts when the trail is empty; the bar keeps its
  actions and gets shrink-0 so a tall list can't squash it.
- MoveDialog emitted `success` before awaiting the move, so
  EntityDialogs reset the dialog and its `@complete` refetch never ran —
  moving the open folder left the old parent in the trail. Refetch and
  close now both happen on `@complete`.
- MoveDialog rows had no hover surface: frappe-ui's Tree drops its own
  when a consumer overrides #item.
- drive-Teams gained the page-title hook it never had.

Covered by e2e/drive-backed-apps/specs/drive/breadcrumbs.spec.ts: section
names, nested trails, ancestor navigation, deep links, browser back,
rename, and move.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reordering deleted the tab node and re-inserted a copy. Yjs has no move
operation, so that destroys the element and creates a new one with the same
id: a concurrent peer or an undo leaves both alive, with the content split
between them, and it also drops edits made inside the moved tab.

Tab order now lives in a `data-tab-order` attribute that reorder rewrites in
place, so nodes never move. Documents without the attribute keep falling back
to document order. Since document order is no longer display order, getHTML
serialises the tab slots in display order — patched in onBeforeCreate because
tiptap emits `create` a tick late.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…lures

The list view lost its grid in production builds: `frappe-ui/list` imports
list-style.css from a module the bundler treats as side-effect-free, so the
stylesheet was tree-shaken away and every header and row cell stacked. Import
it from the app entry.

- restore `data-testid="drive-entity-<name>"` on list rows (dropped in the
  frappe-ui/list migration, so every e2e row locator missed) and add
  `drive-expand-<name>` for the inline folder toggle
- confirmRemove/confirmRestore and toggleFav spread a resource's `data` that is
  null until that list is first fetched — trashing a file before opening Trash
  threw "d is not iterable", leaving the dialog open with the file already
  trashed server-side
- surface the server's message when a move fails, and refetch the list plus
  open subtrees so optimistically removed rows come back
- e2e: drive and drive-writer specs drive the inline rename instead of the
  removed Rename dialog; new tree-expand spec covers expanding a folder in
  place and dragging a subfile into another folder

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Everything in it was either global or dead: the scroll-shadow helper and the
fade-in transition classes had no users, `html { scrollbar-width: auto }` set
the default, and `body { overflow: hidden }` is already implied by the shell's
height: 100% chain. The theme-switching transition freeze belongs next to
setupTheme's own class, so it moves to the root stylesheet.

Scrollbars now follow `color-scheme` per theme instead of hardcoded hexes —
nothing declared it, which is why dark mode drew a light scrollbar (and light
native controls) in the first place.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
An empty or placeholder trail rendered as a blank bar, which read as the
breadcrumbs disappearing when navigating. EditableBreadcrumbs now owns
the loading state — two bars and a separator, so it has the shape of a
real trail — which also gives Writer's navbar the same treatment, since
it uses the same component.

The e2e trail helper now targets the breadcrumbs test id instead of the
first div in the navbar, and waits for the loading state to clear; the
positional lookup raced with the skeleton.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@safwansamsudeen safwansamsudeen changed the title feat(drive): inline folder tree in the list view, plus list-view migration and writer/drive fixes feat(drive): list view on frappe-ui/list, inline folder tree, derived breadcrumbs Jul 30, 2026
@safwansamsudeen
safwansamsudeen merged commit 35217e2 into develop Jul 30, 2026
5 checks passed
@safwansamsudeen
safwansamsudeen deleted the fix/frappe-ui-typography branch July 30, 2026 06:04
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.

1 participant