@docyrus/docyrus 0.0.66 → 0.0.68

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.
Files changed (23) hide show
  1. package/main.js +136 -136
  2. package/main.js.map +3 -3
  3. package/package.json +3 -3
  4. package/resources/pi-agent/extensions/context.ts +22 -16
  5. package/resources/pi-agent/extensions/control.ts +43 -27
  6. package/resources/pi-agent/extensions/knowledge.ts +42 -16
  7. package/resources/pi-agent/extensions/loop.ts +44 -27
  8. package/resources/pi-agent/extensions/pi-bash-live-view/widget.ts +2 -17
  9. package/resources/pi-agent/extensions/plan.ts +79 -40
  10. package/resources/pi-agent/extensions/prompt-url-widget.ts +39 -18
  11. package/resources/pi-agent/extensions/review.ts +13 -2
  12. package/resources/pi-agent/shared/extensionLifecycle.ts +11 -0
  13. package/resources/pi-agent/skills/docyrus-app-dev-react/references/component-selection-guide.md +42 -5
  14. package/resources/pi-agent/skills/docyrus-data-grid-page-design/SKILL.md +58 -0
  15. package/resources/pi-agent/skills/docyrus-data-grid-page-design/references/advanced-saved-view-query-patterns.md +158 -0
  16. package/resources/pi-agent/skills/docyrus-data-grid-page-design/references/hook-pages.md +183 -0
  17. package/resources/pi-agent/skills/docyrus-data-grid-page-design/references/manual-pages.md +145 -0
  18. package/resources/pi-agent/skills/docyrus-data-grid-page-design/references/tenant-and-users-providers.md +290 -0
  19. package/resources/pi-agent/skills/docyrus-record-detail-form-design/SKILL.md +54 -0
  20. package/resources/pi-agent/skills/docyrus-record-detail-form-design/references/advanced-inline-edit-and-renderers.md +140 -0
  21. package/resources/pi-agent/skills/docyrus-record-detail-form-design/references/field-type-mapping-and-fallbacks.md +150 -0
  22. package/resources/pi-agent/skills/docyrus-record-detail-form-design/references/hook-form-view.md +127 -0
  23. package/resources/pi-agent/skills/docyrus-record-detail-form-design/references/manual-form-detail-patterns.md +125 -0
@@ -0,0 +1,150 @@
1
+ # Field-Type Mapping and Unsupported-Field Strategy
2
+
3
+ ## Read this when
4
+
5
+ - You need to decide which component stack should render a Docyrus field.
6
+ - A field type has no editable component yet.
7
+ - You are building manual metadata-driven UIs and want safe fallback behavior.
8
+ - You need to extend Docyrus UI for a new field type without breaking forms, details, and inline editing.
9
+
10
+ ## Single source of truth
11
+
12
+ Docyrus field rendering should flow through the shared field maps exposed by `useDocyrusFieldComponent`:
13
+
14
+ - `FORM_FIELD_MAP`
15
+ - `VALUE_RENDERER_MAP`
16
+ - `CELL_COMPONENT_MAP`
17
+
18
+ Use these indirectly through:
19
+
20
+ - `DynamicFormField`
21
+ - `DynamicValue`
22
+ - `useDocyrusFormView`
23
+ - `useDocyrusFieldComponent`
24
+
25
+ Do **not** create a parallel local switch statement unless there is a very strong reason.
26
+
27
+ ## Render-context lookup matrix
28
+
29
+ `useDocyrusFieldComponent(field.type, kind)` supports five render kinds:
30
+
31
+ | kind | Typical use | Unknown / unsupported fallback |
32
+ |------|-------------|--------------------------------|
33
+ | `form-field` | editable forms | `null` |
34
+ | `value-renderer` | read-only detail | `TextValue` |
35
+ | `data-grid-cell-variant` | grid cells | `ShortTextCell` |
36
+ | `editable-value` | single-field inline edit | `EditableValue` |
37
+ | `tanstack-column-def` | dynamic table columns | builder with short-text cell fallback |
38
+
39
+ This fallback behavior is the baseline for every manual page and hook-first page.
40
+
41
+ ## What each dispatcher does
42
+
43
+ ### `DynamicFormField`
44
+
45
+ - resolves `form-field`
46
+ - returns `null` when the field type has no registered editable component
47
+ - best for metadata-driven editable forms
48
+
49
+ ### `DynamicValue`
50
+
51
+ - resolves `value-renderer`
52
+ - always returns a renderable component because the fallback is `TextValue`
53
+ - best for metadata-driven read-only layouts
54
+
55
+ ### `EditableValue`
56
+
57
+ - is the inline-edit dispatcher
58
+ - returned for the `editable-value` kind regardless of field type
59
+ - internally decides whether the field behaves like inline edit, instant save, explicit save, popover edit, or read-only display
60
+
61
+ ### `useDocyrusFormView`
62
+
63
+ - uses `form-field` in editable mode
64
+ - uses `value-renderer` in read-only mode
65
+ - handles unsupported editable fields differently by mode:
66
+ - create mode default: `unsupportedFieldBehavior = 'skip'`
67
+ - edit/view mode default: `unsupportedFieldBehavior = 'value'`
68
+
69
+ That default is usually correct because create screens should not tease unusable inputs, while edit/view screens can still show existing values safely.
70
+
71
+ ## Recommended unsupported-field strategy
72
+
73
+ ### Create mode
74
+
75
+ Prefer skipping unsupported editable fields unless the page explicitly designs a read-only preview row.
76
+
77
+ Why:
78
+
79
+ - users expect every visible field in a create form to be fillable
80
+ - showing a read-only renderer inside create mode can be confusing
81
+ - the hook default already follows this rule
82
+
83
+ ### Edit mode
84
+
85
+ Prefer value-render fallback when the field cannot be edited.
86
+
87
+ Why:
88
+
89
+ - users can still review the field
90
+ - the record detail stays complete
91
+ - you avoid broken partial editors
92
+
93
+ ### View mode
94
+
95
+ Always prefer value renderers.
96
+
97
+ That is the natural mode for detail pages, approval reviews, summaries, and read-only sheets.
98
+
99
+ ## Safe manual pattern
100
+
101
+ When building a manual dynamic page, use this decision order:
102
+
103
+ ```tsx
104
+ const FormField = useDocyrusFieldComponent(field.type, 'form-field');
105
+ const Value = useDocyrusFieldComponent(field.type, 'value-renderer');
106
+
107
+ if (mode === 'view') {
108
+ return <Value field={field} value={value} record={record} enumOptions={options} />;
109
+ }
110
+
111
+ if (FormField) {
112
+ return <FormField field={field} form={form} enumOptions={options} />;
113
+ }
114
+
115
+ return mode === 'create'
116
+ ? null
117
+ : <Value field={field} value={value} record={record} enumOptions={options} />;
118
+ ```
119
+
120
+ This keeps manual pages aligned with hook-first Docyrus behavior.
121
+
122
+ ## When a field type needs more than mapping
123
+
124
+ Some field types require more than just selecting a component:
125
+
126
+ - enum/select-like fields need `enumOptions`
127
+ - user and relation editors need hydrated option lists
128
+ - status fields may need companion values like description and follow-up date
129
+ - money and phone fields need companion currency/country keys
130
+ - avatar-like fields can require companion image or color keys
131
+
132
+ A field can be “supported” in the map but still render weakly if its supporting data is missing.
133
+
134
+ ## Adding support for a new field type
135
+
136
+ When extending Docyrus UI, check all relevant layers:
137
+
138
+ 1. add the editable component to `FORM_FIELD_MAP` if the type is editable
139
+ 2. add the read-only renderer to `VALUE_RENDERER_MAP`
140
+ 3. add the grid cell component or fallback strategy if the type should appear richly in grids
141
+ 4. update any companion read/write logic if the field stores secondary keys
142
+ 5. verify `useDocyrusFormView`, `DynamicFormField`, `DynamicValue`, and `EditableValue` behavior
143
+
144
+ ## Debug checklist
145
+
146
+ - **Field disappears in manual edit mode?** `form-field` likely resolved to `null`.
147
+ - **Field shows raw text instead of richer UI?** You are hitting the `value-renderer` fallback or missing supporting props.
148
+ - **Create form unexpectedly shows read-only rows?** Your unsupported strategy is too permissive for create mode.
149
+ - **Inline field never edits?** The field may be effectively read-only in `EditableValue` or missing required option data.
150
+ - **New field type works in forms but not in details or grids?** You updated one map but not the others.
@@ -0,0 +1,127 @@
1
+ # Hook-first Record Forms and Detail Views
2
+
3
+ ## Use this path when
4
+
5
+ - The page is a standard Docyrus create, edit, or read-only record screen.
6
+ - You want field metadata, item loading, option hydration, and submit behavior handled in one place.
7
+ - You want the same field list to render as editable inputs in one mode and value renderers in another.
8
+
9
+ ## Minimal create form
10
+
11
+ ```tsx
12
+ 'use client';
13
+
14
+ import { useDocyrusAuth } from '@docyrus/signin';
15
+ import { useDocyrusFormView } from '@docyrus/ui/library/hooks/use-docyrus-form-view';
16
+ import { Button } from '@docyrus/ui/primitives/ui/button';
17
+
18
+ export function CreateContactForm() {
19
+ const { client } = useDocyrusAuth();
20
+
21
+ if (!client) return null;
22
+
23
+ const formView = useDocyrusFormView({
24
+ client,
25
+ appSlug: 'crm',
26
+ dataSourceSlug: 'contacts',
27
+ mode: 'create',
28
+ gridColumns: 2,
29
+ defaultValues: { status: 'lead' },
30
+ fieldOrder: ['full_name', 'email', 'phone', 'status', 'notes'],
31
+ fieldLayout: {
32
+ notes: { colSpan: 'full' }
33
+ }
34
+ });
35
+
36
+ return (
37
+ <form
38
+ className="space-y-4"
39
+ onSubmit={async (event) => {
40
+ event.preventDefault();
41
+ await formView.submit();
42
+ }}>
43
+ {formView.renderLayout()}
44
+ <div className="flex items-center gap-2">
45
+ <Button type="submit" disabled={formView.isSubmitting || formView.isLoading}>Create</Button>
46
+ <Button type="button" variant="outline" onClick={formView.reset}>Reset</Button>
47
+ </div>
48
+ </form>
49
+ );
50
+ }
51
+ ```
52
+
53
+ ## Minimal edit and view patterns
54
+
55
+ - **edit**: pass `mode: 'edit'` and `itemId`.
56
+ - **view**: pass `mode: 'view'` and `itemId`.
57
+ - **prefetched record**: pass `item` to skip the item query.
58
+ - **generated collection**: pass `collection` so the hook uses `collection.get`, `collection.create`, and `collection.update`.
59
+
60
+ ## Click-to-edit detail mode
61
+
62
+ In `view` mode, `clickToEdit: true` swaps the plain value layout for `EditableRecordDetail` while still using the normal Docyrus submit pipeline.
63
+
64
+ ```tsx
65
+ const detailView = useDocyrusFormView({
66
+ client,
67
+ appSlug: 'crm',
68
+ dataSourceSlug: 'contacts',
69
+ itemId: contactId,
70
+ mode: 'view',
71
+ clickToEdit: true,
72
+ fieldOrder: ['full_name', 'email', 'phone', 'status', 'notes']
73
+ });
74
+
75
+ return detailView.renderLayout();
76
+ ```
77
+
78
+ Use this when the page should feel like a detail sheet first, but still allow inline field edits.
79
+
80
+ ## High-value options
81
+
82
+ - `fieldOrder`: impose explicit field ordering.
83
+ - `fieldSlugs`: whitelist fields.
84
+ - `hiddenFieldSlugs`: hard-hide fields.
85
+ - `fieldLayout`: override hidden, required, readOnly, disabled, colSpan, label, description, and per-field props.
86
+ - `layout`: build nested `fieldset`, `tabpanel`, and `tab` sections.
87
+ - `mapField`: transform normalized field metadata or drop a field entirely.
88
+ - `includeReadOnlyFields`: keep read-only rows in the rendered layout.
89
+ - `unsupportedFieldBehavior`: choose whether unsupported editable fields are skipped or rendered as values.
90
+ - `resolveUserOptions`, `resolveRelationOptions`, `enumOptions`: control option hydration.
91
+ - `transformSubmit`: final payload transform before create/update.
92
+ - `onSubmit`: replace default submit behavior entirely.
93
+ - `onSubmitSuccess`, `onSubmitError`: react to mutation outcomes.
94
+
95
+ ## How render mode is decided
96
+
97
+ The hook resolves components from the shared field-component registry:
98
+
99
+ - editable mode → `form-field`
100
+ - read-only mode → `value-renderer`
101
+
102
+ It does not keep a separate form/detail mapping system. That means `useDocyrusFormView`, `DynamicFormField`, `DynamicValue`, and data-grid field behavior stay aligned when the registry changes.
103
+
104
+ ## Why this hook is usually the default
105
+
106
+ It handles three difficult layers together:
107
+
108
+ 1. data-source metadata
109
+ 2. current item loading
110
+ 3. dynamic option hydration for enum, user, and relation fields
111
+
112
+ It also derives the required backend `columns`, including companion columns for composite fields.
113
+
114
+ ## Important behavior
115
+
116
+ - `renderField(slug)` renders a single resolved field.
117
+ - `renderLayout()` renders the full layout grid and is usually the fastest path.
118
+ - `reset()` restores the latest committed baseline.
119
+ - successful `submit()` updates the clean baseline, so the page stops being dirty.
120
+ - in `view` mode, `submit()` returns current values and skips normal validation.
121
+
122
+ ## Default recommendation
123
+
124
+ Start with `useDocyrusFormView` unless the page already has its own form state, its own item query lifecycle, or a heavily custom layout system that would fight the hook.
125
+
126
+ For deeper inline editing and renderer behavior, also read `advanced-inline-edit-and-renderers.md`.
127
+ For shared field-map behavior and unsupported-field defaults, also read `field-type-mapping-and-fallbacks.md`.
@@ -0,0 +1,125 @@
1
+ # Manual Form and Detail Patterns
2
+
3
+ ## Use this path when
4
+
5
+ - The page already owns its form state.
6
+ - You want a completely custom layout.
7
+ - The record is already loaded elsewhere.
8
+ - You need precise control over when editable inputs versus read-only renderers appear.
9
+
10
+ ## Manual editable form with `DynamicFormField`
11
+
12
+ ```tsx
13
+ 'use client';
14
+
15
+ import { useForm } from '@tanstack/react-form';
16
+ import { DynamicFormField, type IField, type EnumOption } from '@docyrus/ui/components/form-fields';
17
+
18
+ const fields: IField[] = [
19
+ { id: '1', name: 'Full Name', slug: 'full_name', type: 'field-text' },
20
+ { id: '2', name: 'Status', slug: 'status', type: 'field-select' }
21
+ ];
22
+
23
+ const statusOptions: EnumOption[] = [
24
+ { id: 'lead', slug: 'lead', name: 'Lead', color: '#64748b' },
25
+ { id: 'customer', slug: 'customer', name: 'Customer', color: '#22c55e' }
26
+ ];
27
+
28
+ export function ContactForm() {
29
+ const form = useForm({
30
+ defaultValues: {
31
+ full_name: '',
32
+ status: 'lead'
33
+ },
34
+ onSubmit: async ({ value }) => {
35
+ void value;
36
+ }
37
+ });
38
+
39
+ return (
40
+ <form onSubmit={(event) => { event.preventDefault(); void form.handleSubmit(); }}>
41
+ {fields.map((field) => (
42
+ <DynamicFormField
43
+ key={field.id}
44
+ field={field}
45
+ form={form}
46
+ enumOptions={field.slug === 'status' ? statusOptions : undefined} />
47
+ ))}
48
+ </form>
49
+ );
50
+ }
51
+ ```
52
+
53
+ Use the specific form-field components directly when you want more explicit imports or field-specific props. Use `DynamicFormField` when the field list is metadata-driven.
54
+
55
+ ## Manual read-only detail with `DynamicValue`
56
+
57
+ ```tsx
58
+ import { DynamicValue } from '@docyrus/ui/components/value-renderers';
59
+
60
+ function ContactDetail({ fields, record, statusOptions }: {
61
+ fields: IField[];
62
+ record: Record<string, unknown>;
63
+ statusOptions: EnumOption[];
64
+ }) {
65
+ return (
66
+ <div className="grid gap-4 md:grid-cols-2">
67
+ {fields.map((field) => (
68
+ <div key={field.id} className="space-y-1">
69
+ <div className="text-sm font-medium">{field.name}</div>
70
+ <DynamicValue
71
+ field={field}
72
+ value={record[field.slug]}
73
+ record={record}
74
+ enumOptions={field.slug === 'status' ? statusOptions : undefined} />
75
+ </div>
76
+ ))}
77
+ </div>
78
+ );
79
+ }
80
+ ```
81
+
82
+ Use this when the page is read-only or when some fields are intentionally not editable.
83
+
84
+ ## Shared registry pattern with `useDocyrusFieldComponent`
85
+
86
+ When you need total control, use the registry hook directly instead of writing a per-type switch.
87
+
88
+ ```tsx
89
+ const FormField = useDocyrusFieldComponent(field.type, 'form-field');
90
+ const Value = useDocyrusFieldComponent(field.type, 'value-renderer');
91
+
92
+ if (isEditing && FormField) {
93
+ return <FormField field={field} form={form} enumOptions={options} />;
94
+ }
95
+
96
+ return <Value field={field} value={value} record={record} enumOptions={options} />;
97
+ ```
98
+
99
+ This is the safest manual pattern because it stays aligned with the Docyrus UI field maps.
100
+
101
+ ## When to choose which primitive
102
+
103
+ - `DynamicFormField`: metadata-driven editable inputs.
104
+ - specific form-field component: explicit field type, custom props, or smaller import surface.
105
+ - `DynamicValue`: metadata-driven read-only display.
106
+ - specific value renderer: explicit display control for a known field type.
107
+ - `useDocyrusFieldComponent`: custom render orchestration that still stays on the shared registry.
108
+
109
+ ## Manual option requirements
110
+
111
+ Manual pages must supply the option data that the renderer or field needs:
112
+
113
+ - select-like fields need `enumOptions`
114
+ - relation renderers usually need `record` context
115
+ - user and relation field editors often need hydrated options upstream
116
+ - composite renderers such as status, money, phone, and avatar depend on companion values in the record object
117
+
118
+ If those values are absent, the component may render a weaker fallback.
119
+
120
+ ## Common manual pattern
121
+
122
+ Use editable inputs in edit mode and read-only renderers in view mode, but keep the same field list and the same metadata source. That keeps create, edit, and detail pages consistent even when the layout differs.
123
+
124
+ For inline editing and change tracking, also read `advanced-inline-edit-and-renderers.md`.
125
+ For field-type dispatch rules and unsupported-field fallback strategy, also read `field-type-mapping-and-fallbacks.md`.