Skip to content

docs(spec): Content Drive grid view as an alternative to the table - #37959

Merged
rjvelazco merged 4 commits into
mainfrom
issue-37930-content-drive-grid-view
Oct 9, 2026
Merged

rjvelazco merged 4 commits into
mainfrom
issue-37930-content-drive-grid-view

Conversation

@rjvelazco

@rjvelazco rjvelazco commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Spec-Kit PR 1 of 2: this PR carries spec.md alone. It needs another dev's approval (not a merge) before /speckit-plan runs. PR 2 will branch from here with the implementation.

Spec for #37930.

Proposed Changes

The feature, in short

Content Drive only has a table. This adds a grid view beside it, matching the card view Content Search already has. A two-button switcher beside the search box toggles between the views. Switching keeps the folder, filters, sort, page and selection, and the browser remembers the choice.

Each card shows an image, or the item's type icon when it has no image or the image can't load. Below the image are the title and status badge, then the owner's avatar, the language and the content type. Titles stay on one line, every card is the same size, and the grid fits as many cards per row as the width allows.

Cards act like table rows: click to select, Shift- or Ctrl/Cmd-click to extend the selection, double-click or title click to open. The right-click menu, drag to move, drop to upload and pagination all work as they do in the table.

Decisions recorded in the spec (Clarifications, 2026-10-08)

  • Custom tool dataViewMode is out of scope. Content Drive is not opened from custom tools today, so it never receives that value. Reading it from the portlet config is a separate ticket. Until then, the Drive opens in the user's remembered view, or the table.
  • The creation date shows on hover only. Hovering the owner's avatar shows their name and the creation date, matching the reference card.
  • The avatar is the owner's Gravatar (the toolbar already shows one), with initials when they have none.
  • The grid has no sort control. It keeps the table's sort order. A grid sort control can be a follow-up.
  • Drag to move and drop to upload are in scope, for full parity with the table.
  • The Content Drive keyboard shortcuts ([FEAT] CD: Add Keybindings #32591) work in the grid. Escape, search, the folder tree toggle, the single Tab stop and Shift+Arrow ranges all carry over. Arrows move in two directions: Left/Right one card, Up/Down one row of cards (User Story 7, FR-028 to FR-033).

Worth checking before approving

  • Owner data: Drive items carry the owner as a user id only. Showing a name and Gravatar may need the Drive search to return each owner's name and email, which is backend work the plan will size.
  • Shared table component: the table is a shared component that pickers and the Action Center preview also use. The spec requires the grid to leave it unchanged everywhere, and pickers keep the table only.

🤖 Generated with Claude Code

This PR fixes: #37930

This PR fixes: #37930

…37930)

Spec-Kit PR 1 of 2: the feature spec alone, for review and approval
before planning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claude

claude Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @rjvelazco's task in 1m 36s —— View job


Spec review: Content Drive grid view (#37930)

This PR adds only specs/37930-content-drive-grid-view/spec.md, so this is a spec review. I re-read the current spec and cross-checked its technical claims against the codebase.

  • Read the updated spec
  • Verify the reviewers' 4 inline points are addressed
  • Verify spec claims against the store, the card view and the Gravatar directive

Reviewer points — now addressed

  • ✅ Lock marker + "more actions" ⋮ menu (zJaaal, line 16): added as US1 scenarios 10–11, FR-026, FR-027, and the Input paragraph. The ⋮ appears on hover/focus and is hidden in a read-only grid.
  • ✅ No modDate; hover reveals full title / editor name / full content type (zJaaal, line 22): the date is gone (FR-006 "MUST NOT show a date"), hover behavior is in US1 scenarios 8–9, FR-010, and the Editor term.
  • ✅ Preserve busy-row state and skeletons (zJaaal, line 86): FR-028 (busy item: dimmed, marked busy, spinner over preview, not selectable) and FR-029 (skeleton cards), plus the Loading/Busy edge cases.
  • ✅ Gravatar directive already exists, may need caching (zJaaal, line 398): the Clarifications now say the Drive reuses the existing directive and that it "may need a cache"; FR-007 bounds it to "at most once per user per page".

Verified against code

  • ✅ Sort is not persisted (FR-023, US6 scenario 3): confirmed. dot-content-drive.store.ts:92 initializes sort: DEFAULT_SORT, and the URL reader (:667–720) only reads path, filters and isTreeExpanded — never sort. A reload resetting the sort matches today's table, and the spec correctly declines to add persistence.
  • ✅ 260px minimum card width (FR-012, SC-002): confirmed against the parity target. dot-card-view.scss:3 is grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)). The "stretch columns evenly, no horizontal scroll" wording matches that rule.
  • ✅ Reusable Gravatar directive, email-driven (FR-007, Key Entities, Assumptions): confirmed. dot-gravatar.directive.ts takes email as a required input and builds the URL from md5(email); the toolbar user component uses it. This validates the spec's open backend question — Drive items carry the editor's name but the directive needs their email, so the Drive search likely must return it. Correctly left for the plan to size.

Worth flagging for the plan (non-blocking)

  • 🟡 "Initials" vs the directive's actual fallback. FR-007 and the Edge Cases say the avatar "MUST show their initials" when there is no Gravatar. The existing DotGravatarDirective fallback ($firstLetter, dot-gravatar.directive.ts:68–75) renders only the first letter of the email address (uppercased, or 'A'), not the user's name initials. If the card wants real initials, that's an enhancement to the shared directive the plan must size; if the single-letter fallback is acceptable, the spec wording should say "initial" to match what the reused directive does. Either way, worth reconciling before planning so the "reuse the directive unchanged" assumption holds.
  • 🟡 "Once per user per page" needs a cache that doesn't exist yet. The directive has no app-level dedup today — each p-avatar[dotGravatar] independently builds its URL and lets the browser load it (HTTP cache dedups identical URLs, but there's no in-app cache). FR-007's "at most once per user per page" is therefore new behavior for the directive, which the Clarification acknowledges ("may need a cache"). Fine as scope; just make sure the plan treats it as directive work, not something the grid gets for free.

Verdict: the spec reads cleanly, follows the Spec-Kit format (prioritized stories, numbered FRs, Legacy Considerations), and every reviewer point is resolved. The two notes above are plan-level reconciliations, not blockers. No code and no secrets in the diff.
· issue-37930-content-drive-grid-view

…#37930)

Adds User Story 7 and FR-028 to FR-033: the #32591 shortcuts apply to
the grid, with Left/Right moving one card and Up/Down one row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@nicobytes nicobytes 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.

Spec review: Content Drive grid view (#37930)

This PR only adds specs/37930-content-drive-grid-view/spec.md, so this is a review of the spec, not of code. I read it in full and cross-checked it against the keyboard shortcuts spec (#32591) and the Content Drive store.

Verdict: solid spec; a few changes requested before approval (1 Important to fix, 2 more to clarify). Prioritized stories, testable Given/When/Then scenarios, numbered FRs and edge cases are all in good shape. Nothing here changes the approach.

Critical

None.

Important

  1. spec.md:255-257 (US6 AC3 / FR-023): "after a reload the grid keeps the sort order".
    In dot-content-drive.store.ts:92 the sort starts at DEFAULT_SORT, and I found no persistence of it in the URL or in storage (only path, filters and isTreeExpanded are read from queryParams, :667-689). If that holds, the table does not keep its sort on reload either, so this AC would require new behavior or is simply false. My search was not exhaustive, so please confirm.
    Fix: if the table does not persist it, reword to "keeps the sort currently in effect, as the table does". If persistence is wanted, declare it as new scope (it affects the table, which contradicts "leave the table unchanged").

  2. spec.md:309-310 and :415 (FR-032 / US7 AC10): "Enter or Space does what it does on a focused table row".
    #32591 (:355) says Enter and Space are already claimed by row selection, so in the table they do not open the item. In the grid, US5 opens items by double-click or title click, but there is no keyboard counterpart.
    Fix: state what Enter/Space do on a card (toggle selection), and how a keyboard-only user opens an item. This also affects SC-007 ("reach, move through and select any card without the mouse").

  3. spec.md:324-329, 426-427 and the PR notes: backend dependency for the owner without a constraint.
    Items carry the owner as a user id only. Name, email and Gravatar may need backend changes to the Drive search. Resolving owners must be bounded per page (batched, never one request per card) and must never block rendering.
    Fix: add that constraint to Assumptions or Key Entities, and mark the backend work as an open question for the plan.

Suggestions

  1. Click semantics (:154-156 vs :381-384): say explicitly that a body click replaces the selection while the checkbox toggles it. A double-click also fires two selection clicks before opening; a criterion for that case would help the tests.
  2. Gravatar (FR-007): a page of cards multiplies the Gravatar lookups the toolbar does for one user. A line on de-duplicating/caching per owner, and on air-gapped installs, would help.
  3. Weak measurables: SC-001 ("1 second") names no dataset or percentile. SC-002 fixes 4 and 3 columns but the card width is not defined in the spec, so it cannot be verified. US2 AC4 (one card per row) coexists with "never wider than the shared size"; state the minimum card width.
  4. Size: 479 lines is large, but it is one logical unit and the 7 stories give a natural split for the plan. No need to divide it.
  5. Nit: the "item busy with a running bulk action" example is repeated in US3, US7 and FR-014/031; reference it once.

Verification

  • Follows the Spec-Kit format (prioritized stories, numbered FRs, Legacy Considerations).
  • No code, no secrets.
  • I did not check CI status or other reviews, only the content.

@nicobytes nicobytes 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.

Clarification questions (follow-up to the review above)

Five open questions that would change tests or UX if left unanswered. Each has a suggested answer; none are blocking if the author agrees with the suggestion.

  1. Which user is "the owner"? (spec.md FR-006/FR-007, Key Entities) Is it the item's creator, or the last editor, and is it the same field the table's user/owner column shows today?
    Why it matters: the avatar, the hover name and the Gravatar lookup all depend on it, and the grid must not disagree with the table.
    Suggested: the same field the table shows.

  2. Do non-image files (PDF, video, documents) get a preview, or the type icon? (FR-008/FR-009, Assumptions "same image as the table's thumbnail")
    US1 AC3 says "image asset, or content whose image field holds one", while the Assumptions say "whatever the table shows as a thumbnail". These can differ.
    Suggested: only what the table already treats as a thumbnail; everything else shows the type icon.

  3. Can keyboard and touch users reach the owner name and creation date? (FR-006, FR-027)
    They are shown on hover only, and nothing else on the card shows them.
    Suggested: also reveal them on keyboard focus of the avatar, and on tap for touch.

  4. What are the card's fixed width and image height (or its min/max)? (FR-011/FR-012, SC-002, US2 AC4)
    SC-002 requires at least 4 cards at 1920px and 3 at 1280px, which cannot be verified without a card size; US2 AC4 also needs a minimum width.
    Suggested: take it from Content Search's card view, so the two views match.

  5. After switching views, where do focus and scroll go? (FR-002, FR-028)
    FR-002 keeps selection, page and sort but says nothing about the focused item, the anchor, or scroll position.
    Suggested: keep the focused item (and anchor) if it is on the page, and scroll it into view; otherwise fall back to the single Tab stop.

Deferred (plan-level, not spec): how owners are resolved per page (already raised in the review), and where the remembered-view key lives in browser storage.

@rjvelazco rjvelazco changed the title docs(spec): Content Drive grid view as an alternative to the table (#37930) docs(spec): Content Drive grid view as an alternative to the table Oct 9, 2026
…37930)

The card shows the editor and last-edited date the table shows, not
owner and creation date. Videos get a still frame. Enter/Space select,
as in the table, with keyboard open left to a follow-up. A reload resets
the sort in both views. Cards are at least 260px wide, as in Content
Search. Editor lookups are batched per page and never block drawing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@rjvelazco

Copy link
Copy Markdown
Member Author

Thanks @nicobytes, all addressed in b21a10c. Each answer is also recorded in the spec's Clarifications (Session 2026-10-09, PR #37959 review).

Important

  1. Sort after reload. Confirmed: the store starts from DEFAULT_SORT and the URL only keeps path, filters and isTreeExpanded. US6 scenario 3 and FR-023 now say a reload resets the sort in both views, as the table does today. Keeping the sort across reloads is not added.
  2. Enter/Space. They select, as on a table row, and do not open (FR-032, US7 scenario 10). The table has no keyboard way to open an item today either, so the grid matches it. Adding one to both views is a follow-up. SC-007 now says it covers reaching, moving and selecting.
  3. Editor data. Added to Assumptions: editor details are fetched in one batch per page, never one request per card, and never hold up drawing the cards. Whether the Drive search must return the email is an open question for the plan.

Suggestions

  1. Clicks. A body click replaces the selection and the checkbox toggles only that card (FR-016, US3 scenario 4). There is a new double-click scenario (US3 scenario 6).
  2. Gravatar. At most one lookup per user per page. Initials show when Gravatar can't be reached, including on servers with no internet access (FR-007, Edge Cases).
  3. Measurables. SC-001 now names the data set (a full page at the largest page size) and a percentile (95% within 1s). Card width is a 260px minimum with columns stretching evenly, as in Content Search (dot-card-view.scss). SC-002 and US2 scenario 4 are based on that width.
  4. Nit. The "busy item" example now lives once, as the Unselectable item term, and the duplicate Shift-click scenario points back to US3.

Clarification questions

  1. Owner. The card now shows the same user and date as the table's Edited By / Last Edited columns: the last editor for content, the owner for folders. That replaces "owner + creation date". The name is already on the items; only the email may need backend work.
  2. Non-image files. Same preview as the table's thumbnail (image, SVG, PDF page). Videos show a still frame with no player controls, so clicks still select and open the card.
  3. Keyboard and touch. The name and date are part of the card's screen reader label, and tapping the avatar shows them.
  4. Card size. Taken from Content Search: a 260px minimum, columns stretch to fill the row.
  5. Focus after switching views. Taken as you suggested: the focused item and anchor are kept if they're on the page and scrolled into view; otherwise focus falls back to the single Tab stop (FR-002, US7 scenario 12).

Also tidied from the bot review: the Input paragraph no longer reads as if dataViewMode were in scope. That follow-up is now #37964.

🤖 Replied by Claude on behalf of @rjvelazco

@rjvelazco
rjvelazco requested a review from nicobytes October 9, 2026 19:17
Comment thread specs/37930-content-drive-grid-view/spec.md
Comment thread specs/37930-content-drive-grid-view/spec.md
Comment thread specs/37930-content-drive-grid-view/spec.md
Comment thread specs/37930-content-drive-grid-view/spec.md
…37930)

Cards drop the date and show only the last editor's avatar, with full
title, editor name and content type on hover. Cards carry the lock
marker and a hover "more actions" menu like the table, keep the busy
row treatment, and show skeleton cards while loading. The Gravatar
reuses the toolbar's directive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@rjvelazco
rjvelazco added this pull request to the merge queue Oct 9, 2026
Merged via the queue into main with commit 4f7079f Oct 9, 2026
82 checks passed
@rjvelazco
rjvelazco deleted the issue-37930-content-drive-grid-view branch October 9, 2026 19:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Add a grid view to Content Drive

3 participants