Repository navigation
feat(ui): add Data Rooms template - #47
Conversation
- Secure document rooms owned by an organization and its sub-organizations, with access that carries down the hierarchy, expiring folder shares, agreements before entry, view-only and watermarked documents, Q&A, reading insights, an access map, and a room assistant that only cites documents the reader can open - Pure, cached access helpers (effectiveAccess, visibleDocuments, visibleQuestions, visibleActivity, describeGrant) drive UI gating, the "Why can they?" trace, and Preview as - data + onCommand + onAction contract with optimistic local updates via applyDataRoomsCommand - Registry item, Storybook stories, flow/SSR/access tests, docs page and preview, and agent skill routing
|
Review complete. 🟡 2 medium 💬 Inline comments (2)
The change introduces a complete
Reviewed commit: db8350b |
There was a problem hiding this comment.
This PR adds a self-installable data-rooms application block (rooms, access model, Q&A, insights, settings) to the @constructive registry plus docs-app integration, and two medium-severity logic bugs were found in the demo command/insight helpers.
Key findings
- 🟡 Fix
niceMaxchart axis scale overshoot — insights-tab.tsx:42 - 🟡 Re-inviting a suspended or expired member silently no-ops — commands.ts:55
| function niceMax(value: number) { | ||
| if (value <= 5) return 5; | ||
| const magnitude = 10 ** Math.floor(Math.log10(value)); | ||
| const step = [1, 2, 2.5, 5, 10].map((factor) => factor * magnitude).find((candidate) => candidate * 4 >= value) ?? magnitude * 10; | ||
| return step * 4; | ||
| } |
There was a problem hiding this comment.
🟡 bug · medium
Fix niceMax chart axis scale overshoot
niceMax returns an axis top far above its documented values: it computes magnitude from the raw value (10 ** Math.floor(Math.log10(value)), insights-tab.tsx:44) and then returns step * 4, where step is the smallest nice number whose quadruple already covers the value. For the comment's own examples the function returns niceMax(13) = 40 (promised 15), niceMax(42) = 80 (promised 50), and even niceMax(6) = 40 (promised 10), because for any value above 5 the magnitude is at least 10. The y-axis of the "Views and downloads per day" chart ends up 3-8x taller than the tallest bar, squashing every bar toward the baseline whenever the 14-day peak is between 6 and 39 events.
📋 Prompt for AI Agents
In packages/ui/src/components/data-rooms/insights-tab.tsx at lines 42-47, fix niceMax so it returns the documented axis tops (4 → 5, 13 → 15, 42 → 50). The bug is that magnitude is computed from the raw value, so step * 4 overshoots by 3-8x. Change the magnitude to be based on value/4, e.g. const magnitude = 10 ** Math.floor(Math.log10(value / 4)), keeping the existing candidate list and the step * 4 return; verify niceMax(4)=5, niceMax(6)=10, niceMax(13)=15, niceMax(42)=50.
| const existing = memberships.find((membership) => membership.personId === known.id && membership.scope.kind === 'room' && membership.scope.id === command.roomId); | ||
| if (existing) continue; |
There was a problem hiding this comment.
🟡 bug · medium
Re-inviting a suspended or expired member silently no-ops
The invite handler in applyDataRoomsCommand skips a known person whenever any room membership already exists, without checking status or expiresAt (commands.ts:55-56). A suspended or expired member is therefore never re-added, no RoomInvite row is created, and no activity event is logged — the optimistic apply, which hosts are told mirrors server behavior, silently does nothing. Re-inviting an expired guest appears to succeed in the UI but grants no access.
📋 Prompt for AI Agents
In packages/ui/src/components/data-rooms/commands.ts around lines 53-66, change the invite case so the existing membership check only skips people with an active, unexpired membership. When the existing membership is 'suspended', 'invited', or past its expiresAt, update it back to active (refreshing roleId/expiresAt) rather than continue-ing, so a re-invite grants access and logs an invite activity event.
Adds Data Rooms, a new application template next to Agents Builder and Billing: secure document rooms for an organization and its sub-organizations.
Contract: one
dataobject, every change throughonCommand(reject to keep the dialog open), host-owned controls throughonAction, optionalrenderPreviewandonAskAssistant.The access helpers (
effectiveAccess,visibleDocuments,visibleQuestions,visibleActivity,describeGrant) andapplyDataRoomsCommandare exported, pure, and cached per data snapshot; they drive the UI and can run on the server, which still decides every request.Wiring: registry item
data-roomswith smoke-install case, Storybook (Templates/DataRooms), flow, SSR and access tests, docs page at/blocks/data-roomswith live preview, and agent skill routing.Source:
packages/ui/src/components/data-rooms🤖 Generated with Claude Code
https://claude.ai/code/session_01GPTLDuvMBGBawVLKL42yYV