@docyrus/docyrus 0.0.30 → 0.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/main.js +3 -3
- package/main.js.map +1 -1
- package/package.json +3 -3
- package/resources/pi-agent/skills/docyrus-api-dev/SKILL.md +161 -0
- package/resources/pi-agent/skills/docyrus-api-dev/references/api-client.md +349 -0
- package/resources/pi-agent/skills/docyrus-api-dev/references/authentication.md +299 -0
- package/resources/pi-agent/skills/docyrus-api-dev/references/data-source-query-guide.md +2063 -0
- package/resources/pi-agent/skills/docyrus-api-dev/references/formula-design-guide-llm.md +312 -0
- package/resources/pi-agent/skills/docyrus-api-dev/references/query-and-formulas.md +592 -0
- package/resources/pi-agent/skills/docyrus-app-dev-react/SKILL.md +334 -0
- package/resources/pi-agent/skills/docyrus-app-dev-react/references/README.md +28 -0
- package/resources/pi-agent/skills/docyrus-app-dev-react/references/api-client-and-auth.md +326 -0
- package/resources/pi-agent/skills/docyrus-app-dev-react/references/collections-and-patterns.md +352 -0
- package/resources/pi-agent/skills/docyrus-app-dev-react/references/component-selection-guide.md +602 -0
- package/resources/pi-agent/skills/docyrus-app-dev-react/references/icon-usage-guide.md +463 -0
- package/resources/pi-agent/skills/docyrus-app-dev-react/references/preferred-components-catalog.md +242 -0
- package/resources/pi-agent/skills/docyrus-platform/SKILL.md +2 -2
- package/resources/pi-agent/skills/docyrus-platform/references/auth-and-multi-tenancy.md +9 -1
- package/resources/pi-agent/skills/docyrus-platform/references/developer-tools.md +3 -2
- package/resources/pi-agent/extensions/multi-edit.ts +0 -835
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: docyrus-app-dev-react
|
|
3
|
+
description: Build Docyrus React TypeScript web applications end-to-end, combining authentication, API access, generated collections, TanStack Query/Form patterns, and production-grade UI implementation with preferred component libraries. Use when creating or modifying Docyrus-backed apps that use @docyrus/api-client, @docyrus/signin, Docyrus collections, queries, dashboards, forms, tables, layouts, or Docyrus UI components.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Docyrus App Dev React
|
|
7
|
+
|
|
8
|
+
Build Docyrus React TypeScript applications end-to-end. This skill combines app architecture, authentication, data access, query patterns, and production-grade UI guidance in one place.
|
|
9
|
+
|
|
10
|
+
## Tech Stack
|
|
11
|
+
|
|
12
|
+
- React 19 + TypeScript + Vite
|
|
13
|
+
- TanStack Router (code-based), TanStack Query (server state), TanStack Form
|
|
14
|
+
- Tailwind CSS v4, shadcn/ui components
|
|
15
|
+
- `@docyrus/api-client` + `@docyrus/signin`
|
|
16
|
+
- Auto-generated collections from OpenAPI spec
|
|
17
|
+
- Preferred UI libraries: shadcn, diceui, animate-ui, docyrus-ui, reui
|
|
18
|
+
|
|
19
|
+
## When to Use This Skill
|
|
20
|
+
|
|
21
|
+
Use this skill when you are:
|
|
22
|
+
|
|
23
|
+
- Building or modifying a Docyrus-backed React app
|
|
24
|
+
- Setting up authentication with `@docyrus/signin`
|
|
25
|
+
- Fetching or mutating data with generated collections or `@docyrus/api-client`
|
|
26
|
+
- Designing feature UIs such as dashboards, forms, tables, layouts, dialogs, analytics, or detail pages
|
|
27
|
+
- Selecting between shadcn, diceui, animate-ui, docyrus-ui, and reui components
|
|
28
|
+
- Implementing complete feature flows that combine data access and polished UI
|
|
29
|
+
|
|
30
|
+
## End-to-End Feature Workflow
|
|
31
|
+
|
|
32
|
+
1. Set up app auth, routing, and query providers.
|
|
33
|
+
2. Use generated Docyrus collection hooks or the REST client for data access.
|
|
34
|
+
3. Define `columns`, filters, formulas, child queries, and mutations correctly.
|
|
35
|
+
4. Check preferred UI components before building anything custom.
|
|
36
|
+
5. Use Docyrus form and detail patterns for create, edit, and item detail flows.
|
|
37
|
+
6. Connect UI actions to TanStack Query mutations and invalidate relevant queries.
|
|
38
|
+
|
|
39
|
+
## Quick Start: App Bootstrap
|
|
40
|
+
|
|
41
|
+
### Root provider setup
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { DocyrusAuthProvider } from '@docyrus/signin'
|
|
45
|
+
|
|
46
|
+
<DocyrusAuthProvider
|
|
47
|
+
apiUrl={import.meta.env.VITE_API_BASE_URL}
|
|
48
|
+
clientId={import.meta.env.VITE_OAUTH2_CLIENT_ID}
|
|
49
|
+
redirectUri={import.meta.env.VITE_OAUTH2_REDIRECT_URI}
|
|
50
|
+
scopes={['offline_access', 'Read.All', 'DS.ReadWrite.All', 'Users.Read']}
|
|
51
|
+
callbackPath="/auth/callback"
|
|
52
|
+
>
|
|
53
|
+
<QueryClientProvider client={queryClient}>
|
|
54
|
+
<RouterProvider router={router} />
|
|
55
|
+
</QueryClientProvider>
|
|
56
|
+
</DocyrusAuthProvider>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Auth gate and current-user access
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
const { status, user, hasRole, hasPermission } = useDocyrusAuth()
|
|
63
|
+
|
|
64
|
+
if (status === 'loading') return <Spinner />
|
|
65
|
+
if (status === 'unauthenticated') return <SignInButton />
|
|
66
|
+
|
|
67
|
+
// user is auto-fetched from /v1/users/me after authentication
|
|
68
|
+
// hasRole('super_admin') — check role by slug or uid
|
|
69
|
+
// hasPermission('edit', dataSourceId) — check ACL permission on a data source
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Data fetching with generated collections
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
const { list } = useBaseProjectCollection()
|
|
76
|
+
const { data: projects } = useQuery({
|
|
77
|
+
queryKey: ['projects'],
|
|
78
|
+
queryFn: () =>
|
|
79
|
+
list({
|
|
80
|
+
columns: ['name', 'status', 'record_owner(firstname,lastname)'],
|
|
81
|
+
filters: { rules: [{ field: 'status', operator: '!=', value: 'archived' }] },
|
|
82
|
+
orderBy: 'created_on DESC',
|
|
83
|
+
limit: 50,
|
|
84
|
+
}),
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Common Docyrus Asset URL Templates
|
|
89
|
+
|
|
90
|
+
- `User avatar path template`: `https://api.docyrus.app/storage/v1/object/tenant-public/:tenantId/users/:userId/:user.photo`
|
|
91
|
+
- `Tenant logo path template`: `https://api.docyrus.app/storage/v1/object/tenant-public/:tenantId/:tenant.logo`
|
|
92
|
+
|
|
93
|
+
Use these templates when wiring user chips, assignee avatars, comments, activity feeds, app shell branding, workspace switchers, and any `DataGrid` user option payload that needs `avatarUrl`.
|
|
94
|
+
|
|
95
|
+
## Critical App/Data Rules
|
|
96
|
+
|
|
97
|
+
1. **Always send `columns`** in `.list()` and `.get()` calls. Without it, only `id` is returned.
|
|
98
|
+
2. **Collections are React hooks** — call `useBaseProjectCollection()`, `useUsersCollection()`, and similar hooks inside React components.
|
|
99
|
+
3. **Data source endpoints are dynamic** — they only exist if the data source is defined in the tenant OpenAPI spec.
|
|
100
|
+
4. **Use `id` for `count` calculations**. Use actual field slugs for `sum`, `avg`, `min`, and `max`.
|
|
101
|
+
5. **Child query keys must appear in `columns`**.
|
|
102
|
+
6. **Formula keys must appear in `columns`**.
|
|
103
|
+
7. **Use `useUsersCollection().getMyInfo()`** for current user profile instead of making a direct profile call.
|
|
104
|
+
8. **Regenerate collections after schema changes** by rebuilding the tenant OpenAPI spec, downloading the latest `openapi.json`, and re-running the collection generator.
|
|
105
|
+
|
|
106
|
+
## Critical UI/UX Rules
|
|
107
|
+
|
|
108
|
+
1. **Always check preferred components first** before creating anything custom.
|
|
109
|
+
2. **Use `AwesomeCard` for dashboards** unless the user explicitly wants a different card style.
|
|
110
|
+
3. **Use animate-ui `Sidebar` for app layouts** unless another layout is requested.
|
|
111
|
+
4. **Prefer Recharts for charts**. shadcn chart primitives are the default wrapper.
|
|
112
|
+
5. **Use icons in this order**: hugeicons, then fontawesome light, then lucide.
|
|
113
|
+
6. **Use `AwesomeDialog` for item create forms**.
|
|
114
|
+
- Small/simple forms: `container="sheet"` with `side="right"`
|
|
115
|
+
- Long/complex forms: `container="modal"` or `container="drawer"`
|
|
116
|
+
7. **Choose detail containers based on item complexity**.
|
|
117
|
+
- Large items: dedicated page
|
|
118
|
+
- Small items: `AwesomeDialog` right sheet
|
|
119
|
+
8. **All forms must use TanStack Form + the Docyrus form system**. Do not build feature forms with plain HTML forms or React Hook Form directly.
|
|
120
|
+
9. **Use `EditableRecordDetail` for inline editing** in item detail views.
|
|
121
|
+
10. **Always enable `trackChanges`** for editable detail and grid experiences.
|
|
122
|
+
11. **When using Docyrus `DataGrid`, always set the correct `meta.cell` variant for the field type**. Do not reuse a generic text cell for typed Docyrus data.
|
|
123
|
+
12. **When rendering data source records in tables, cards, or lists, prefer the matching Docyrus value renderer** instead of handwritten display JSX.
|
|
124
|
+
13. **When editing inline, pass the real `IField` metadata into `EditableRecordDetailField` or `EditableValue`** so Docyrus can dispatch the correct editor and display pair from `field.type`.
|
|
125
|
+
14. **If a field type has no dedicated `DataGrid` cell variant, keep the grid cell read-only and move editing to a sheet, dialog, or detail page**.
|
|
126
|
+
|
|
127
|
+
## Default UI Choices
|
|
128
|
+
|
|
129
|
+
| Use Case | Default Component | Library |
|
|
130
|
+
|----------|-------------------|---------|
|
|
131
|
+
| Item create form | `AwesomeDialog` | docyrus |
|
|
132
|
+
| Quick record create | `CreateRecordDialog` | docyrus |
|
|
133
|
+
| Item detail (small) | `AwesomeDialog` sheet right | docyrus |
|
|
134
|
+
| Item detail (large) | Dedicated page | — |
|
|
135
|
+
| Inline editing | `EditableRecordDetail` | docyrus |
|
|
136
|
+
| Dashboard card | `AwesomeCard` | docyrus |
|
|
137
|
+
| Stat dashboards | `AwesomeStats` | docyrus |
|
|
138
|
+
| App navigation | `Sidebar` | animate-ui |
|
|
139
|
+
| Data table | `DataTable` | diceui |
|
|
140
|
+
| Editable grid | `Data Grid` | docyrus |
|
|
141
|
+
| Grid saved views | `DataGridViewSelect` | docyrus |
|
|
142
|
+
| Forms | Docyrus form fields + TanStack Form | docyrus |
|
|
143
|
+
| Charts | shadcn chart + Recharts | shadcn |
|
|
144
|
+
| File upload | File Upload | diceui |
|
|
145
|
+
| Gantt/project scheduling | `Gantt` | docyrus |
|
|
146
|
+
| Resource scheduling | `ResourceSchedulerPanel` | docyrus |
|
|
147
|
+
| Team chat | `TeamChatChannel` | docyrus |
|
|
148
|
+
| AI interface | `DocyrusAgent` | docyrus |
|
|
149
|
+
| Pricing / quoting | `PricingEnginePanel` | docyrus |
|
|
150
|
+
| Analytics / pivot | `PivotGrid` | docyrus |
|
|
151
|
+
|
|
152
|
+
## Data Source Field Type UI Mapping
|
|
153
|
+
|
|
154
|
+
If you already have Docyrus field metadata, prefer explicit Docyrus field-specific primitives over custom UI glue:
|
|
155
|
+
|
|
156
|
+
- Forms: use the specific `*FormField` for the field type
|
|
157
|
+
- Read-only display: matching value renderer / `DynamicValue`
|
|
158
|
+
- Inline editing: `EditableRecordDetailField` or `EditableValue`
|
|
159
|
+
- Editable grids: `DataGrid` with the matching `meta.cell` variant
|
|
160
|
+
|
|
161
|
+
Use the table below as the default mapping guide.
|
|
162
|
+
|
|
163
|
+
| Field type(s) | `DataGrid` cell variant | Form field | Inline edit | Value renderer | Notes |
|
|
164
|
+
|---------------|-------------------------|------------|-------------|----------------|-------|
|
|
165
|
+
| `field-text` | `short-text` | `TextFormField` | `EditableValue` with `field-text` | `TextValue` | Default single-line text |
|
|
166
|
+
| `field-textarea` | `long-text` | `TextareaFormField` | `EditableValue` with `field-textarea` | `TextValue` | Multi-line content |
|
|
167
|
+
| `field-email` | `email` | `EmailFormField` | `EditableValue` with `field-email` | `EmailValue` | Use for clickable email cells |
|
|
168
|
+
| `field-url` | `url` | `UrlFormField` | `EditableValue` with `field-url` | `UrlValue` | Prefer typed URL rendering over plain text |
|
|
169
|
+
| `field-phone` | `phone` | `PhoneFormField` | `EditableValue` with `field-phone` | `PhoneValue` | Supports phone-specific display and editing |
|
|
170
|
+
| `field-number` | `number` | `NumberFormField` | `EditableValue` with `field-number` | `NumberValue` | Standard numeric input |
|
|
171
|
+
| `field-money` | `currency` | `MoneyFormField` | `EditableValue` with `field-money` | `MoneyValue` | Use money-specific formatting |
|
|
172
|
+
| `field-currency` | `currency-code` | `CurrencyCodeFormField` | `EditableValue` with `field-currency` | `CurrencyCodeValue` | ISO currency codes |
|
|
173
|
+
| `field-duration` | `duration` | `DurationFormField` | `EditableValue` with `field-duration` | `DurationValue` | Duration editing/display |
|
|
174
|
+
| `field-rating` | `rating` | `RatingFormField` | `EditableValue` with `field-rating` | `RatingValue` | Star rating |
|
|
175
|
+
| `field-select` | `select` | `SelectFormField` | `EditableValue` with `field-select` | `SelectValue` | Single select with Docyrus enum options |
|
|
176
|
+
| `field-radioGroup` | `select` | `RadioGroupFormField` | `EditableValue` with `field-radioGroup` | `SelectValue` | In grids, use a select-style cell |
|
|
177
|
+
| `field-enum` | `enum` | `EnumFormField` | `EditableValue` with `field-enum` | `SelectValue` | Backend-driven enum values |
|
|
178
|
+
| `field-status` | `status` | `StatusFormField` | `EditableValue` with `field-status` | `StatusValue` | Preserves status metadata such as description/follow-up |
|
|
179
|
+
| `field-multiSelect` | `multi-select` | `MultiSelectFormField` | `EditableValue` with `field-multiSelect` | `MultiSelectValue` | Multi-badge selection |
|
|
180
|
+
| `field-tagSelect` | `tag-select` | `TagSelectFormField` | `EditableValue` with `field-tagSelect` | `MultiSelectValue` | Colored tag chips |
|
|
181
|
+
| `field-userSelect` | `user` | `UserSelectFormField` | `EditableValue` with `field-userSelect` | `UserValue` | Populate `CellUserOption.avatarUrl` using the user avatar template |
|
|
182
|
+
| `field-userMultiSelect` | `user-multi-select` | `UserMultiSelectFormField` | `EditableValue` with `field-userMultiSelect` | `UserMultiValue` | Use the avatar template for each selected user |
|
|
183
|
+
| `field-relation` | `relation` | `RelationFormField` | `EditableValue` with `field-relation` | `RelationValue` | Prefer Docyrus relation lookup behavior |
|
|
184
|
+
| `field-date` | `date` | `DateFormField` | `EditableValue` with `field-date` | `DateValue` | Date-only |
|
|
185
|
+
| `field-dateTime` | `datetime` | `DateTimeFormField` | `EditableValue` with `field-dateTime` | `DateTimeValue` | Date + time |
|
|
186
|
+
| `field-time` | `time` | `TimeFormField` | `EditableValue` with `field-time` | `TimeValue` | Time-only |
|
|
187
|
+
| `field-dateRange` | `date-range` | `DateRangeFormField` | `EditableValue` with `field-dateRange` | `DateRangeValue` | Start/end pairs |
|
|
188
|
+
| `field-checkbox` | `checkbox` | `CheckboxFormField` | `EditableValue` with `field-checkbox` | `CheckboxValue` | Boolean checkbox |
|
|
189
|
+
| `field-switch` | `switch` | `SwitchFormField` | `EditableValue` with `field-switch` | `SwitchValue` | Boolean toggle |
|
|
190
|
+
| `field-color` | `color` | `ColorFormField` | `EditableValue` with `field-color` | `ColorValue` | Use the swatch-aware UI |
|
|
191
|
+
| `field-icon` | `icon` | `IconFormField` | `EditableValue` with `field-icon` | `IconValue` | Keep icon selection/rendering typed |
|
|
192
|
+
| `field-file` | `file` | `FileFormField` | `EditableValue` with `field-file` when inline file editing is acceptable | `FileValue` | Grid editing is fine only when upload UX fits the workflow |
|
|
193
|
+
| `field-image` | `image` | `ImageFormField` | `EditableValue` with `field-image` when inline image editing is acceptable | `ImageValue` | Prefer preview-aware image handling |
|
|
194
|
+
| `field-locationSelect` | `—` | `LocationSelectFormField` | `EditableValue` with `field-locationSelect` | `LocationValue` | No dedicated `DataGrid` cell variant in current docs; prefer detail editing |
|
|
195
|
+
| `field-docEditor` | `—` | `DocEditorFormField` | `EditableValue` with `field-docEditor` | `DocEditorValue` | Avoid dense grid editing; use a detail view or sheet |
|
|
196
|
+
| `field-htmlEditor` | `—` | `HtmlEditorFormField` | `EditableValue` with `field-htmlEditor` | `RichTextValue` | Prefer detail editing over grid editing |
|
|
197
|
+
| `field-emailEditor` | `—` | `EmailEditorFormField` | `EditableValue` with `field-emailEditor` | `RichTextValue` | Better in a drawer/modal editor |
|
|
198
|
+
| `field-codeEditor` | `long-text` or `—` | `CodeEditorFormField` | `EditableValue` with `field-codeEditor` | `CodeValue` | Prefer a detail editor if syntax-aware editing matters |
|
|
199
|
+
| `field-taskList` | `—` | `TaskListFormField` | `EditableValue` with `field-taskList` | `TaskListValue` | Better in detail surfaces than grids |
|
|
200
|
+
| `field-queryBuilder` | `—` | `QueryBuilderFormField` | `EditableValue` with `field-queryBuilder` | `—` | Use dedicated query-builder UI |
|
|
201
|
+
| `field-dynamic` | `—` | `DynamicConfigFormField` | `EditableValue` with `field-dynamic` | `—` | Specialized config UX |
|
|
202
|
+
| `field-schemaRepeater` | `—` | `SchemaRepeaterFormField` | `EditableValue` with `field-schemaRepeater` | `—` | Repeater editing belongs in a form/detail surface |
|
|
203
|
+
| `field-approvalStatus` | `—` | `ApprovalStatusFormField` | `EditableValue` with `field-approvalStatus` | `ApprovalStatusValue` | No dedicated `DataGrid` cell variant in current docs |
|
|
204
|
+
| `field-inlineData`, `field-inlineForm`, `field-todo` | `—` | `—` | Use `EditableValue` only if the field has a supported dedicated inline experience | `InlineDataValue`, `TodoValue` | Prefer specialized detail UI over grid editing |
|
|
205
|
+
| `field-display`, `field-formula`, `field-relatedField`, `field-button`, `field-identity`, `field-autonumber`, `field-list` | `—` | `—` | Keep read-only by default | `TextValue`, `FormulaValue`, `RelatedFieldValue`, `ButtonValue`, `IdentityValue`, `ListValue` | These are commonly display/virtual/system-driven rather than user-editable |
|
|
206
|
+
| `field-code` | `—` | `—` | Keep read-only or build a custom feature-specific editor intentionally | `TextValue` | Do not force this into a generic grid editor unless the simplification is intentional |
|
|
207
|
+
|
|
208
|
+
### Field-Type Mapping Notes
|
|
209
|
+
|
|
210
|
+
- `EditableValue` is the low-level inline editor. The important choice is the `field.type` you pass in; Docyrus uses that metadata to choose the correct inline form/display behavior.
|
|
211
|
+
- If a field type does not have a documented `DataGrid` cell variant, do not approximate it with a text cell unless the simplification is intentional and acceptable for the feature.
|
|
212
|
+
- For large rich-content or structured fields, prefer `AwesomeDialog`, dedicated detail pages, or `EditableRecordDetail` instead of dense grid editing.
|
|
213
|
+
- The current shared `FIELD_TYPES` list in the platform is the authoritative source. If UI docs mention a field type not present in the tenant schema/runtime, do not assume it is available.
|
|
214
|
+
- Reference docs:
|
|
215
|
+
- `https://ui.docy.app/docs/web/docyrus/value-renderers/llms.txt`
|
|
216
|
+
- `https://ui.docy.app/docs/web/docyrus/form-fields/llms.txt`
|
|
217
|
+
- `https://ui.docy.app/docs/web/docyrus/editable-value/llms.txt`
|
|
218
|
+
- `https://ui.docy.app/docs/web/docyrus/data-grid/llms.txt`
|
|
219
|
+
|
|
220
|
+
## Quick UI Patterns
|
|
221
|
+
|
|
222
|
+
### Item create form
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
<AwesomeDialog open={open} onOpenChange={setOpen} container="sheet" side="right" size="default">
|
|
226
|
+
<AwesomeDialogHeader title="Create Task" icon="far-plus" />
|
|
227
|
+
<AwesomeDialogBody>
|
|
228
|
+
<form.Field name="title">{(field) => <TextFormField field={field} label="Title" />}</form.Field>
|
|
229
|
+
<form.Field name="status">{(field) => <SelectFormField field={field} label="Status" />}</form.Field>
|
|
230
|
+
</AwesomeDialogBody>
|
|
231
|
+
<AwesomeDialogFooter>
|
|
232
|
+
<Button variant="outline" onClick={() => setOpen(false)}>Cancel</Button>
|
|
233
|
+
<Button onClick={handleSubmit}>Create</Button>
|
|
234
|
+
</AwesomeDialogFooter>
|
|
235
|
+
</AwesomeDialog>
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Item detail with inline editing
|
|
239
|
+
|
|
240
|
+
```tsx
|
|
241
|
+
<AwesomeDialog open={open} onOpenChange={setOpen} container="sheet" side="right" size="lg" fullscreenable>
|
|
242
|
+
<AwesomeDialogHeader
|
|
243
|
+
title="Task Detail"
|
|
244
|
+
description="Review and edit task fields inline"
|
|
245
|
+
headerButtons={<Button variant="outline" size="sm" onClick={switchToFullForm}>Edit All</Button>}
|
|
246
|
+
/>
|
|
247
|
+
<AwesomeDialogBody>
|
|
248
|
+
<EditableRecordDetail fields={fields} record={record} onSave={handleSave} trackChanges>
|
|
249
|
+
<EditableRecordDetailField slug="title" />
|
|
250
|
+
<EditableRecordDetailField slug="status" />
|
|
251
|
+
<EditableRecordDetailField slug="assignee" />
|
|
252
|
+
<EditableRecordDetailField slug="due_date" />
|
|
253
|
+
</EditableRecordDetail>
|
|
254
|
+
</AwesomeDialogBody>
|
|
255
|
+
</AwesomeDialog>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## TanStack Query Pattern
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
function useProjects(params?: ICollectionListParams) {
|
|
262
|
+
const { list } = useBaseProjectCollection()
|
|
263
|
+
return useQuery({
|
|
264
|
+
queryKey: ['projects', 'list', params],
|
|
265
|
+
queryFn: () => list({ columns: PROJECT_COLUMNS, ...params }),
|
|
266
|
+
})
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function useCreateProject() {
|
|
270
|
+
const { create } = useBaseProjectCollection()
|
|
271
|
+
const qc = useQueryClient()
|
|
272
|
+
return useMutation({
|
|
273
|
+
mutationFn: (data: Record<string, unknown>) => create(data),
|
|
274
|
+
onSuccess: () => {
|
|
275
|
+
void qc.invalidateQueries({ queryKey: ['projects'] })
|
|
276
|
+
},
|
|
277
|
+
})
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Collection CRUD Methods
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
const { list, get, create, update, delete: deleteOne, deleteMany } = useBaseProjectCollection()
|
|
285
|
+
|
|
286
|
+
list(params?: ICollectionListParams)
|
|
287
|
+
get(id, { columns })
|
|
288
|
+
create(data)
|
|
289
|
+
update(id, data)
|
|
290
|
+
deleteOne(id)
|
|
291
|
+
deleteMany({ recordIds })
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
API endpoint pattern: `/v1/apps/{appSlug}/data-sources/{slug}/items`
|
|
295
|
+
|
|
296
|
+
## Query Capabilities Summary
|
|
297
|
+
|
|
298
|
+
The `.list()` method supports:
|
|
299
|
+
|
|
300
|
+
- `columns`
|
|
301
|
+
- `filters`
|
|
302
|
+
- `filterKeyword`
|
|
303
|
+
- `orderBy`
|
|
304
|
+
- `limit` and `offset`
|
|
305
|
+
- `fullCount`
|
|
306
|
+
- `calculations`
|
|
307
|
+
- `formulas`
|
|
308
|
+
- `childQueries`
|
|
309
|
+
- `pivot`
|
|
310
|
+
- `expand`
|
|
311
|
+
|
|
312
|
+
## Component Installation Pattern
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
pnpm dlx shadcn@latest add button
|
|
316
|
+
pnpm dlx shadcn@latest add @diceui/data-table
|
|
317
|
+
pnpm dlx shadcn@latest add @animate-ui/sidebar
|
|
318
|
+
pnpm dlx @docyrus/cli add @docyrus/ui-awesome-card
|
|
319
|
+
pnpm dlx shadcn@latest add @reui/file-upload-default
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## References
|
|
323
|
+
|
|
324
|
+
For deep dives, read:
|
|
325
|
+
|
|
326
|
+
- `references/README.md` — merged reference map for app development and UI design
|
|
327
|
+
- `references/api-client-and-auth.md`
|
|
328
|
+
- `references/collections-and-patterns.md`
|
|
329
|
+
- `../docyrus-api-dev/references/data-source-query-guide.md`
|
|
330
|
+
- `../docyrus-api-dev/references/formula-design-guide-llm.md`
|
|
331
|
+
- `../docyrus-api-dev/references/query-guide.md`
|
|
332
|
+
- `references/preferred-components-catalog.md`
|
|
333
|
+
- `references/component-selection-guide.md`
|
|
334
|
+
- `references/icon-usage-guide.md`
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Docyrus App Dev React Reference Map
|
|
2
|
+
|
|
3
|
+
This directory contains the full reference set for `docyrus-app-dev-react`.
|
|
4
|
+
|
|
5
|
+
## App Development References
|
|
6
|
+
|
|
7
|
+
Read these files for data access, auth, query design, and collection patterns:
|
|
8
|
+
|
|
9
|
+
- `api-client-and-auth.md`
|
|
10
|
+
- `collections-and-patterns.md`
|
|
11
|
+
- `../../docyrus-api-dev/references/data-source-query-guide.md`
|
|
12
|
+
- `../../docyrus-api-dev/references/formula-design-guide-llm.md`
|
|
13
|
+
- `../../docyrus-api-dev/references/query-guide.md`
|
|
14
|
+
|
|
15
|
+
## UI Design References
|
|
16
|
+
|
|
17
|
+
Read these files for component selection, design patterns, and UI library guidance:
|
|
18
|
+
|
|
19
|
+
- `preferred-components-catalog.md`
|
|
20
|
+
- `component-selection-guide.md`
|
|
21
|
+
- `icon-usage-guide.md`
|
|
22
|
+
|
|
23
|
+
## How to Use This Skill
|
|
24
|
+
|
|
25
|
+
1. Start with `../SKILL.md` for the merged operating guidance.
|
|
26
|
+
2. Use the app-development references when working on auth, queries, collections, routing, and mutations.
|
|
27
|
+
3. Use the UI-design references when selecting components, designing layouts, or implementing polished feature flows.
|
|
28
|
+
4. Combine both when building end-to-end Docyrus React features.
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# @docyrus/api-client & @docyrus/signin Reference
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
1. [RestApiClient](#restapiclient)
|
|
6
|
+
2. [Authentication with @docyrus/signin](#authentication-with-docyrussignin)
|
|
7
|
+
3. [Authorization (Roles & Permissions)](#authorization-roles--permissions)
|
|
8
|
+
4. [API Client Access Pattern](#api-client-access-pattern)
|
|
9
|
+
5. [Interceptors](#interceptors)
|
|
10
|
+
6. [Error Handling](#error-handling)
|
|
11
|
+
7. [Advanced Features](#advanced-features)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## RestApiClient
|
|
16
|
+
|
|
17
|
+
Type-safe REST API client from `@docyrus/api-client`.
|
|
18
|
+
|
|
19
|
+
### HTTP Methods
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { RestApiClient } from '@docyrus/api-client'
|
|
23
|
+
|
|
24
|
+
client.get<T>(endpoint, params?) // GET
|
|
25
|
+
client.post<T>(endpoint, data) // POST
|
|
26
|
+
client.patch<T>(endpoint, data) // PATCH
|
|
27
|
+
client.put(endpoint, data) // PUT
|
|
28
|
+
client.delete(endpoint, data?) // DELETE
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Typed Responses
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
interface User { id: string; name: string; email: string }
|
|
35
|
+
const response = await client.get<User[]>('/v1/users')
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Config Options
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
interface ApiClientConfig {
|
|
42
|
+
baseURL?: string
|
|
43
|
+
tokenManager?: TokenManager
|
|
44
|
+
headers?: Record<string, string>
|
|
45
|
+
timeout?: number
|
|
46
|
+
fetch?: typeof fetch
|
|
47
|
+
FormData?: typeof FormData
|
|
48
|
+
AbortController?: typeof AbortController
|
|
49
|
+
storage?: Storage
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Authentication with @docyrus/signin
|
|
56
|
+
|
|
57
|
+
Package: `@docyrus/signin` (peer dep: `@docyrus/api-client >= 0.0.10`, `react >= 18`)
|
|
58
|
+
|
|
59
|
+
### DocyrusAuthProvider Setup
|
|
60
|
+
|
|
61
|
+
Wrap application root:
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { DocyrusAuthProvider } from '@docyrus/signin'
|
|
65
|
+
|
|
66
|
+
<DocyrusAuthProvider
|
|
67
|
+
apiUrl={import.meta.env.VITE_API_BASE_URL}
|
|
68
|
+
clientId={import.meta.env.VITE_OAUTH2_CLIENT_ID}
|
|
69
|
+
redirectUri={import.meta.env.VITE_OAUTH2_REDIRECT_URI}
|
|
70
|
+
scopes={['offline_access', 'Read.All', 'DS.ReadWrite.All', 'Users.Read']}
|
|
71
|
+
callbackPath="/auth/callback"
|
|
72
|
+
>
|
|
73
|
+
<App />
|
|
74
|
+
</DocyrusAuthProvider>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Provider Props
|
|
78
|
+
|
|
79
|
+
| Prop | Type | Default | Description |
|
|
80
|
+
|------|------|---------|-------------|
|
|
81
|
+
| `apiUrl` | `string` | `https://alpha-api.docyrus.com` | API base URL |
|
|
82
|
+
| `clientId` | `string` | Built-in default | OAuth2 client ID |
|
|
83
|
+
| `redirectUri` | `string` | `origin + callbackPath` | OAuth2 redirect URI |
|
|
84
|
+
| `scopes` | `string[]` | `['offline_access', 'Read.All', ...]` | OAuth2 scopes |
|
|
85
|
+
| `callbackPath` | `string` | `/auth/callback` | OAuth callback route |
|
|
86
|
+
| `forceMode` | `'standalone' \| 'iframe'` | Auto-detected | Force auth mode |
|
|
87
|
+
| `storageKeyPrefix` | `string` | `docyrus_oauth2_` | localStorage prefix |
|
|
88
|
+
| `allowedHostOrigins` | `string[]` | `undefined` | Extra trusted iframe origins |
|
|
89
|
+
|
|
90
|
+
### Auth Modes
|
|
91
|
+
|
|
92
|
+
- **Standalone**: OAuth2 Authorization Code + PKCE via page redirect. Tokens stored in localStorage, auto-refreshed.
|
|
93
|
+
- **Iframe**: Receives tokens via `window.postMessage` from `*.docyrus.app` hosts. Requests refresh from host when expired.
|
|
94
|
+
|
|
95
|
+
### useDocyrusAuth() Hook
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
const {
|
|
99
|
+
status, // 'loading' | 'authenticated' | 'unauthenticated'
|
|
100
|
+
mode, // 'standalone' | 'iframe'
|
|
101
|
+
client, // RestApiClient | null
|
|
102
|
+
tokens, // { accessToken, refreshToken, ... } | null
|
|
103
|
+
user, // DocyrusUser | null — auto-fetched from /v1/users/me
|
|
104
|
+
signIn, // () => void — redirects to Docyrus login
|
|
105
|
+
signOut, // () => void — logout and clear tokens
|
|
106
|
+
hasRole, // (role: string | string[]) => boolean — check role by slug or uid
|
|
107
|
+
hasPermission, // (operation: string, dataSourceId?: string) => boolean — check ACL permission
|
|
108
|
+
refreshUser, // () => Promise<void> — re-fetch user from API
|
|
109
|
+
error, // Error | null
|
|
110
|
+
} = useDocyrusAuth()
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### useDocyrusClient() Hook
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
const client = useDocyrusClient() // RestApiClient | null
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### SignInButton Component
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
// Basic
|
|
123
|
+
<SignInButton />
|
|
124
|
+
|
|
125
|
+
// Styled
|
|
126
|
+
<SignInButton className="btn" label="Log in with Docyrus" />
|
|
127
|
+
|
|
128
|
+
// Render prop
|
|
129
|
+
<SignInButton>
|
|
130
|
+
{({ signIn, isLoading }) => (
|
|
131
|
+
<button onClick={signIn} disabled={isLoading}>
|
|
132
|
+
{isLoading ? 'Redirecting...' : 'Sign in'}
|
|
133
|
+
</button>
|
|
134
|
+
)}
|
|
135
|
+
</SignInButton>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Environment Variables (.env)
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
VITE_API_BASE_URL=https://localhost:3366
|
|
142
|
+
VITE_OAUTH2_CLIENT_ID=your-client-id
|
|
143
|
+
VITE_OAUTH2_REDIRECT_URI=http://localhost:3000/auth/callback
|
|
144
|
+
VITE_OAUTH2_SCOPES=openid profile offline_access Users.Read DS.ReadWrite.All
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Authorization (Roles & Permissions)
|
|
150
|
+
|
|
151
|
+
The provider auto-fetches the current user from `/v1/users/me` after authentication. The `user`, `hasRole`, and `hasPermission` are available on the `useDocyrusAuth()` hook.
|
|
152
|
+
|
|
153
|
+
### Role-Based UI Gating
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
function Dashboard({ dataSourceId }: { dataSourceId: string }) {
|
|
157
|
+
const { user, hasRole, hasPermission } = useDocyrusAuth()
|
|
158
|
+
|
|
159
|
+
if (!user) return <Spinner />
|
|
160
|
+
|
|
161
|
+
const canEdit = hasPermission('edit', dataSourceId)
|
|
162
|
+
const canDelete = hasPermission('delete', dataSourceId)
|
|
163
|
+
const isAdmin = hasRole('super_admin')
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<div>
|
|
167
|
+
{canEdit && <Button>Edit</Button>}
|
|
168
|
+
{canDelete && <Button variant="destructive">Delete</Button>}
|
|
169
|
+
{isAdmin && <AdminPanel />}
|
|
170
|
+
</div>
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Permission Resolution Order
|
|
176
|
+
|
|
177
|
+
1. `super_admin` role → always granted
|
|
178
|
+
2. `global_editor` role → granted for: view, create, edit, delete, create_bulk, export, import, print
|
|
179
|
+
3. `global_viewer` role → granted only for: view
|
|
180
|
+
4. Always-permitted system data sources (reports, todos, notes, etc.)
|
|
181
|
+
5. User's `aclRules` array (merged from all roles by the server)
|
|
182
|
+
|
|
183
|
+
### Pure Functions (No React)
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
import { hasRole, hasPermission } from '@docyrus/signin/core'
|
|
187
|
+
import type { DocyrusUser } from '@docyrus/signin/core'
|
|
188
|
+
|
|
189
|
+
hasRole(user, 'super_admin')
|
|
190
|
+
hasPermission(user, 'edit', 'some-ds-id')
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## API Client Access Pattern
|
|
196
|
+
|
|
197
|
+
Generated collections are React hooks that use `useDocyrusClient()` internally to get the authenticated `RestApiClient` from `DocyrusAuthProvider`. No manual client syncing is needed.
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
// Collections get the client automatically via useDocyrusClient()
|
|
201
|
+
function useBaseProjectCollection() {
|
|
202
|
+
const client = useDocyrusClient()
|
|
203
|
+
return {
|
|
204
|
+
list: (params?) => client!.get('/v1/apps/base/data-sources/project/items', params),
|
|
205
|
+
// ... other CRUD methods
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// In your component — just call the collection hook
|
|
210
|
+
function ProjectList() {
|
|
211
|
+
const { list } = useBaseProjectCollection()
|
|
212
|
+
const { data } = useQuery({
|
|
213
|
+
queryKey: ['projects'],
|
|
214
|
+
queryFn: () => list({ columns: ['name', 'status'] }),
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
For direct API access outside collections, use the `useDocyrusClient()` hook:
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
const client = useDocyrusClient()
|
|
223
|
+
const data = await client!.get<MyType>('/v1/custom-endpoint')
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Interceptors
|
|
229
|
+
|
|
230
|
+
Add request/response interceptors via `client.use()`:
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
client.use({
|
|
234
|
+
request: (config) => {
|
|
235
|
+
// Transform columns array to comma-separated string
|
|
236
|
+
if (config.params?.columns && Array.isArray(config.params.columns)) {
|
|
237
|
+
config.params.columns = config.params.columns.join(',')
|
|
238
|
+
}
|
|
239
|
+
return config
|
|
240
|
+
},
|
|
241
|
+
response: (response) => {
|
|
242
|
+
// Unwrap nested .data property
|
|
243
|
+
if (response.data?.data && !Array.isArray(response.data)) {
|
|
244
|
+
response.data = response.data.data
|
|
245
|
+
}
|
|
246
|
+
return response
|
|
247
|
+
},
|
|
248
|
+
error: (error, request, response) => {
|
|
249
|
+
if (error.status === 401) { /* handle auth error */ }
|
|
250
|
+
return { error, request, response }
|
|
251
|
+
},
|
|
252
|
+
})
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Error Handling
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import {
|
|
261
|
+
ApiError, NetworkError, TimeoutError,
|
|
262
|
+
AuthenticationError, AuthorizationError,
|
|
263
|
+
NotFoundError, RateLimitError, ValidationError,
|
|
264
|
+
OAuth2Error, InvalidGrantError,
|
|
265
|
+
} from '@docyrus/api-client'
|
|
266
|
+
|
|
267
|
+
try {
|
|
268
|
+
await client.get('/resource')
|
|
269
|
+
} catch (error) {
|
|
270
|
+
if (error instanceof AuthenticationError) { /* 401 */ }
|
|
271
|
+
else if (error instanceof AuthorizationError) { /* 403 */ }
|
|
272
|
+
else if (error instanceof NotFoundError) { /* 404 */ }
|
|
273
|
+
else if (error instanceof RateLimitError) { /* 429 - error.retryAfter */ }
|
|
274
|
+
else if (error instanceof NetworkError) { /* network issue */ }
|
|
275
|
+
else if (error instanceof TimeoutError) { /* timeout */ }
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Advanced Features
|
|
282
|
+
|
|
283
|
+
### SSE (Server-Sent Events)
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
const eventSource = client.sse('/events', {
|
|
287
|
+
onMessage(data) { console.log(data) },
|
|
288
|
+
onError(error) { console.error(error) },
|
|
289
|
+
onComplete() { console.log('done') },
|
|
290
|
+
})
|
|
291
|
+
eventSource.close()
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### File Upload
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
const formData = new FormData()
|
|
298
|
+
formData.append('file', fileInput.files[0])
|
|
299
|
+
await client.post('/upload', formData)
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### File Download
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
const response = await client.get('/download/file.pdf', { responseType: 'blob' })
|
|
306
|
+
const url = URL.createObjectURL(response.data)
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### HTML to PDF
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
await client.html2pdf({
|
|
313
|
+
html: '<html><body>Content</body></html>',
|
|
314
|
+
options: { format: 'A4', margin: { top: 10, bottom: 10 } },
|
|
315
|
+
})
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Retry Logic
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
import { withRetry } from '@docyrus/api-client'
|
|
322
|
+
const response = await withRetry(() => client.get('/endpoint'), {
|
|
323
|
+
retries: 3, retryDelay: 1000,
|
|
324
|
+
retryCondition: (error) => error.status >= 500,
|
|
325
|
+
})
|
|
326
|
+
```
|