What a playbook can reach: the project's files, its memory, and named apps with a read or write grant.
Every app starts as "Can read", and widening it is a separate deliberate act. That ordering is the whole design: granting write access should never be something that happens as a side effect of adding an app.
The files row is fixed and says "Always included" rather than being a switch that cannot move - a disabled control with no explanation reads as a bug.
The summary line says what it reads and what it writes to, and then states where consequential actions stop. A permission list without that sentence describes capability and hides the constraint.
import { AppAccess } from '@redrob-labs/ui';
| Prop | Type | Notes |
|---|---|---|
apps |
AccessApp[] |
Every app that could be added. |
value |
AccessGrant[] |
|
defaultValue |
AccessGrant[] |
|
memory |
boolean |
Whether the project's memory is readable. undefined hides the row entirely. |
label |
React.ReactNode |
|
filesLabel |
React.ReactNode |
|
filesNote |
React.ReactNode |
|
memoryLabel |
string |
|
memoryOnNote |
React.ReactNode |
|
memoryOffNote |
React.ReactNode |
|
notConnectedLabel |
string |
|
connectedLabel |
string |
|
connectsLabel |
string |
|
addLabel |
React.ReactNode |
|
dialogTitle |
string |
|
searchLabel |
string |
|
searchPlaceholder |
string |
|
emptyText |
React.ReactNode |
|
startNote |
React.ReactNode |
|
note |
React.ReactNode |
|
accessLabels |
Record<string, string> |
|
summary |
(reach: number, write: number) => string |
Compose the summary line yourself, given the counts. |
className |
string |
|
onChange |
(grants: AccessGrant[]) => void |
|
onConnect |
(id: string) => void |
|
onMemoryChange |
(on: boolean) => void |