Documentation source
Entity Detail v2 — Information Taxonomy + Unified Edit
Second pass on the entity detail redesign. Progressive disclosure, unified click-to-edit, merged activity, relocated task actions, and coherent sidebar rhythm.
# Entity Detail v2 — Information Taxonomy + Unified Edit
## Problem
PR #747 (Entity Detail v1) fixed typography and visual hierarchy but kept structural debt:
1. **Two edit models, no cancel.** Fields require the pencil icon or "Edit fields" button; body uses click-to-edit. The pencil has no inline cancel. The "Edit fields" label is misleading because it opens _respond mode_ (submits a response), not a direct entity update. Users can't tell whether they're editing the entity or proposing a response.
2. **Sidebar card soup.** Session, Tasks, Documents, MiniGraph, Activity, Changes each render as a distinct Card with different headers, actions, and empty states. Most are empty most of the time — the page feels like placeholder rubble.
3. **Action inconsistency.** Populate, +Add task, +Link record, comment composer, Run task all look different. There's no coherent "how do I add something to this record" affordance.
4. **Hero layout wastes the image.** Image is small and left; tags drop below the image — so tags visually belong to nothing. The content column doesn't fill the image height.
5. **Task action button cramped.** `EntityTaskActions` lives in the top-right cluster and grows unpredictably wide when a task has a long label.
6. **Activity duplicated.** `EntityHistoryTab` (user-driven activity) and `EntityChangeHistory` (audit log diffs) are separate collapsibles side-by-side. They're answering the same user question: "what happened to this record?"
7. **View switcher ambiguous.** The "+" sits in an awkward position outside the tab list; there's no visible affordance for the respond-mode toggle ("Edit fields") except through a menu.
## Solution
Fix structure, not paint. Six coordinated changes, one PR.
### 1. Hero: image-anchored content column, tags promoted
```
[ IMAGE ] Title · score chip · layout-editing chip
[ 128- TypeName · Created date · Updated date · Owner · Source
160sq ] [ tag ] [ tag ] [ tag ]
[ ☐ Run next task ▾ ] (new meta-row position)
```
- Image column: `size-32 sm:size-36 lg:size-40` square, object-cover, anchored left.
- Content column: flex-1, min-w-0, stacks title → meta → tags → task-action button.
- Tags live **inside** the content column immediately under the meta line, not below the whole block.
- When `entity.image_url` is null → **no placeholder**, content column fills full width. Image upload moves to the Actions menu.
### 2. Task action relocated into meta row
`EntityTaskActions` moves from the top-right icon cluster to the meta row under the title.
- Wrap in `max-w-[160px] truncate` so long task labels ellipsise (tooltip preserves full text).
- Ghost button style so it reads like meta, not a primary CTA.
- Only renders when a runnable task exists (`tasks.length > 0`).
### 3. Top-right cluster simplified
Only: Realtime status (already there) · Favorite · Visibility · Share · **Actions ▾**
Actions dropdown groups discoveries:
```
Agent work
├─ ⚡ Populate with agent
├─ ▶ Run task…
└─ + Attach agent
Add content
├─ 📎 Attach document
├─ 🔗 Link existing record
├─ ✓ Add task
└─ 💬 Add comment
Admin
├─ ⧉ Duplicate
├─ ↗ Export
└─ ✕ Delete
```
Favorite / Visibility / Share stay as dedicated icons (frequent + spatial). MoreActionsDropdown absorbs the new groups.
### 4. Views row restructured
```
[ Default ][ View A ][ View B ][ + ] [ ✎ Edit fields ]
↑ scrollable tab list, + sits at end ↑ toggles respond-mode
```
- The Plus button moves **inside** the `role=tablist` container, positioned after the last view tab. Scrolls with the tab list.
- Outside the scroll container, a new "Edit fields" button replaces the old Plus slot. Toggles `respond` mode (writes responses in batch via existing `useViewResponse` + `ResponseToolbar`). Only visible when `canEditEntity` and at least one field is response-enabled.
- Rationale: both views and edit modes operate on the same fields; putting them adjacent makes discovery obvious.
### 5. Sidebar: progressive disclosure, one rhythm
Kill Card wrappers for idle/empty panels. One header style everywhere:
```
ACTIVITY [ 12 ▸ ]
(click to expand → tabs: Actions | Changes | unified timeline)
TASKS [ + ]
• Follow up Thursday [Run]
• Send contract [Run]
2 completed ▸
DOCUMENTS ← hidden when empty
📄 contract-v3.pdf · 142 KB
📄 signed-moa.pdf · 88 KB
SESSIONS ← hidden when empty
⚡ extract-fields · 2m ago · running
COMMENTS
[ inline composer — always visible ]
(thread)
```
- Section labels: `text-[10px] font-semibold uppercase tracking-wider text-muted-foreground` followed by optional inline action (ghost Plus / count badge / Run icon).
- Separators: `border-t border-border/60 pt-4` between sections — no boxes.
- **Empty-state policy**:
- Documents empty → section hidden. Adding lives in Actions menu.
- Sessions empty → section hidden. Populate lives in Actions menu.
- Tasks empty → section shown with a single "+ Add task" row; tasks are lightweight and Tyler adds them often.
- Comments empty → composer always visible; comments ARE the interaction.
- MiniGraph only renders when `related.length > 0` (already true).
### 6. Activity merge
New component `features/entities/components/entity-activity-panel.tsx`:
- Single collapsible, closed by default.
- Count badge combines `activities.length + audit.entries.length`.
- Two tabs inside: **Actions** (user-driven activity, current `EntityHistoryTab` timeline) and **Changes** (audit diffs, current `EntityChangeHistory` timeline). Tab state persists per session via `sessionStorage`.
- Keep the underlying data fetchers (`/api/entities/[id]/activities` and `/api/entities/[id]/audit`) unchanged. Only the shell changes.
- `EntityHistoryTab` and `EntityChangeHistory` get refactored: their render logic becomes the tab bodies. Their outer Collapsible shells get deleted.
### 7. Unified edit model — click-to-edit everywhere
The core inconsistency: body writes directly to `entities.description`; fields write to `entity_responses` (audit-preserving). Users don't need to see that difference, but they shouldn't be punished by two different interaction patterns.
**Decision: keep the storage difference, unify the interaction.**
- **Click any field value** → enters edit mode. No pencil icon.
- Inline **Save** + **Cancel** buttons appear beneath the input.
- `Esc` cancels, `⌘↵` / `Ctrl↵` saves.
- Interactive elements inside the value (relation chips, link pills) call `e.stopPropagation()` on click so they navigate instead of triggering edit.
- Hover reveals a subtle edit affordance (1px border brighten + cursor:text) so the interaction is discoverable.
- `saveInlineFieldEdit` pipeline unchanged — fields still go through the response system for audit/versioning. The user just doesn't see the difference at the interaction layer.
- Per field, show auto-promote policy as a tiny chip beneath the label: "Goes live immediately" (always / if_confident) vs "Awaiting review" (never). Visible to everyone — builds trust in what's canonical vs proposed.
**"Edit fields" button behavior** (moved to views row, step 4):
- Toggles respond-mode: all fields switch to edit inputs simultaneously, sticky `ResponseToolbar` at the bottom shows "N fields changed · Discard · Submit response".
- Still single-field click-to-edit works in read mode. Respond-mode is the batch variant.
**Body editor**: keeps existing behavior (click-to-edit writing to `entities.description` via `useUpdateEntity`). The _interaction pattern_ matches field click-to-edit; the _storage target_ differs. That's an architectural fact, not a UX inconsistency.
### 8. Field card polish
- Labels: 10px uppercase, left-aligned to value (not above).
- Numeric values: `text-xl` semibold tabular-nums.
- Text values: `text-base` regular.
- Status indicators: row of tiny chips below value — `🔒 locked`, `● pending review`, `✨ extracted by {agent}` — dismissible / clickable for context.
- Section groupings (via `fieldLayout`) get a thin `border-t border-border/60 pt-3 mt-3` with a small-caps section header. No card wrappers around groups.
## Trade-offs
- **Progressive disclosure hides Documents when empty.** Power users who expect "I can attach a doc from here" must learn the Actions menu. Mitigation: the menu is always visible and labeled. This is worth the visual decluttering.
- **Click-to-edit risks accidental edit on wide click targets.** Mitigation: Cancel and Esc; no save happens until user explicitly clicks Save. Same risk already exists for body editor and hasn't been a reported problem.
- **Activity merge loses the "at-a-glance" count of Actions vs Changes.** Combined count badge is a minor regression for users who cared about the split. Trade: the whole sidebar rhythm improves, which benefits every user on every visit.
- **Moving EntityTaskActions to meta row makes it less prominent.** Intentional — currently it dominates the top-right cluster. Primary actions (Populate, Run) live in the Actions menu now; the meta-row button is for the _next queued task_ only.
## Acceptance Criteria
- [ ] Hero: image + title + meta + tags in a single 2-column row; tags under meta, not under image. No image placeholder when `image_url` is null.
- [ ] `EntityTaskActions` renders in meta row, max-width 160px, ellipsised with tooltip.
- [ ] Top-right cluster shows: Realtime · Favorite · Visibility · Share · Actions. No EntityTaskActions there.
- [ ] Actions dropdown has grouped menu items (Agent / Add content / Admin).
- [ ] Views tab row: `+` button is the last item inside the scrollable tablist. `Edit fields` button sits to the right of the scroll container.
- [ ] `Edit fields` toggles respond-mode; sticky ResponseToolbar appears when in that mode.
- [ ] Sidebar renders with borderless section headers, no Card wrappers for idle panels.
- [ ] Documents section hidden when `documents.length === 0`.
- [ ] Sessions section hidden when `sessions.length === 0`.
- [ ] Tasks section shows "+ Add task" row when tasks empty.
- [ ] Activity panel is a single collapsible with Actions / Changes tabs. Closed by default. Count badge shows combined total.
- [ ] Every field value is clickable to enter edit mode; pencil icon removed from `field-card-block.tsx`.
- [ ] Edit mode shows inline Save + Cancel buttons. Esc cancels. ⌘↵ saves.
- [ ] Auto-promote policy chip visible under each editable field label.
- [ ] Links/relation chips inside field values navigate on click without triggering edit.
- [ ] `pnpm lint`, `pnpm typecheck`, `pnpm test`, `pnpm build` all pass.
- [ ] qa-tester verifies desktop + mobile viewports, reports PASS.
## Out of Scope
- Rewriting the response submission backend (the pipeline is correct; only UX changes).
- MiniGraph redesign (keeps current behavior).
- Entity detail for custom views (only default view is redesigned; custom views continue using WorkspaceEditor).
- Comments redesign (keep current thread component; only remove its card wrapper).
- Document picker / upload flow redesign (only changes where the entry point lives).
## Implementation Order
1. Spec review + approval (this doc).
2. Reconcile body-vs-fields edit semantics (decision captured above; no code change).
3. Build `entity-activity-panel.tsx` and refactor `EntityHistoryTab` + `EntityChangeHistory` into sub-components.
4. Rework `entity-detail-hero.tsx` layout + relocate `EntityTaskActions`.
5. Move view-tabs "+" and add "Edit fields" button.
6. Rewrite `entity-detail-sidebar.tsx` for progressive disclosure + unified rhythm.
7. Build `entity-actions-menu.tsx` and wire into hero cluster.
8. Refactor `field-card-block.tsx` for click-to-edit pattern + Save/Cancel.
9. Verify (lint, typecheck, tests, build, qa-tester, visual diff screenshots).
10. Commit, push, open PR into `dev`.