@docyrus/docyrus 0.0.67 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docyrus/docyrus",
3
- "version": "0.0.67",
3
+ "version": "0.0.68",
4
4
  "private": false,
5
5
  "description": "Docyrus API CLI",
6
6
  "main": "./main.js",
@@ -14,8 +14,8 @@
14
14
  "@clack/prompts": "^0.11.0",
15
15
  "@ff-labs/fff-node": "0.6.4",
16
16
  "@hono/node-server": "^1.19.13",
17
- "@mariozechner/pi-ai": "0.70.2",
18
- "@mariozechner/pi-coding-agent": "0.70.2",
17
+ "@mariozechner/pi-ai": "0.70.6",
18
+ "@mariozechner/pi-coding-agent": "0.70.6",
19
19
  "@modelcontextprotocol/ext-apps": "^1.2.2",
20
20
  "@modelcontextprotocol/sdk": "^1.25.1",
21
21
  "@mozilla/readability": "^0.6.0",
@@ -1,4 +1,5 @@
1
1
  import type { ExtensionContext } from '@mariozechner/pi-coding-agent';
2
+ import { truncateToWidth } from '@mariozechner/pi-tui';
2
3
  import { snapshotToAnsiContentLines } from './terminal-emulator.ts';
3
4
  import type { PtyTerminalSession } from './pty-session.ts';
4
5
 
@@ -37,23 +38,7 @@ export function buildTopBorder(title: string, innerWidth: number, elapsedMs: num
37
38
  }
38
39
 
39
40
  function fitAnsiLine(line: string, width: number): string {
40
- let out = '';
41
- let visible = 0;
42
- let i = 0;
43
- while (i < line.length && visible < width) {
44
- if (line[i] === '\x1b' && line[i + 1] === '[') {
45
- const match = line.slice(i).match(/^\x1b\[[0-9;]*m/);
46
- if (match) {
47
- out += match[0];
48
- i += match[0].length;
49
- continue;
50
- }
51
- }
52
- out += line[i];
53
- visible += 1;
54
- i += 1;
55
- }
56
- return `${out}\x1b[0m${' '.repeat(Math.max(0, width - visible))}`;
41
+ return `${truncateToWidth(line, width, '', true)}\x1b[0m`;
57
42
  }
58
43
 
59
44
  export function buildWidgetAnsiLines({
@@ -30,6 +30,7 @@ Mobile-first form → container="drawer" side="bottom"
30
30
  ```
31
31
 
32
32
  **AwesomeDialog** props reference:
33
+
33
34
  - `container`: `'modal'` | `'sheet'` | `'drawer'` — determines the dialog presentation
34
35
  - `side`: `'left'` | `'right'` | `'top'` | `'bottom'` — positioning for sheet/drawer
35
36
  - `size`: `'sm'` | `'default'` | `'lg'` | `'xl'` | `'full'` — size preset
@@ -43,6 +44,7 @@ Mobile-first form → container="drawer" side="bottom"
43
44
  **Sub-components**: `AwesomeDialogHeader`, `AwesomeDialogBody`, `AwesomeDialogFooter`, `AwesomeDialogToolbar`
44
45
 
45
46
  **Example — Small create form (task):**
47
+
46
48
  ```tsx
47
49
  <AwesomeDialog open={open} onOpenChange={setOpen} container="sheet" side="right">
48
50
  <AwesomeDialogHeader title="Create Task" icon="far-plus" />
@@ -55,6 +57,7 @@ Mobile-first form → container="drawer" side="bottom"
55
57
  ```
56
58
 
57
59
  **Example — Large create form (project):**
60
+
58
61
  ```tsx
59
62
  <AwesomeDialog open={open} onOpenChange={setOpen} container="modal" size="lg" fullscreenable>
60
63
  <AwesomeDialogHeader title="Create Project" icon="far-folder-plus" />
@@ -78,6 +81,7 @@ Small items (tasks, contacts, comments) → AwesomeDialog with container="s
78
81
  ```
79
82
 
80
83
  **Decision tree:**
84
+
81
85
  ```
82
86
  Does the item have:
83
87
  - Multiple tabs/sections?
@@ -92,6 +96,7 @@ Does the item have:
92
96
  ```
93
97
 
94
98
  **Example — Task detail in AwesomeDialog:**
99
+
95
100
  ```tsx
96
101
  <AwesomeDialog open={open} onOpenChange={setOpen} container="sheet" side="right" size="lg" fullscreenable>
97
102
  <AwesomeDialogHeader
@@ -117,11 +122,13 @@ Does the item have:
117
122
  **All forms must use** TanStack Form with the Docyrus form field system. Never use plain HTML forms or React Hook Form directly.
118
123
 
119
124
  **Key components:**
125
+
120
126
  - `DynamicFormField` — Auto-dispatches to the correct field type based on `IField.type`
121
127
  - 47+ field types: text, number, email, url, phone, date, dateTime, time, select, multiSelect, status, relation, file, image, code, docEditor, and more
122
128
  - Each field type has a dedicated `*FormField` component (e.g., `TextFormField`, `SelectFormField`, `DateFormField`)
123
129
 
124
130
  **Form field pattern:**
131
+
125
132
  ```tsx
126
133
  import { useForm } from '@tanstack/react-form'
127
134
  import { TextFormField, SelectFormField, DateFormField } from '@docyrus/ui/components/form-fields'
@@ -141,12 +148,14 @@ const form = useForm({ defaultValues: { title: '', status: '', dueDate: '' } })
141
148
  Use `EditableRecordDetail` for detail views where users can edit individual fields inline without opening a full form page. **Always enable `trackChanges`** to highlight changed fields and show a floating ActionBar. Always include an **"Edit All"** button in the header to switch to a full form editing experience.
142
149
 
143
150
  **Key components:**
151
+
144
152
  - `EditableRecordDetail` — Provider/wrapper that manages field state, change tracking, and save/cancel
145
153
  - `EditableRecordDetailField` — Individual field that reads config from context, renders label + inline-editable value
146
154
  - `EditableValue` — Lower-level single-field inline editor (used internally by EditableRecordDetailField)
147
155
  - `useEditableRecordDetail()` — Hook to access form, values, changes, and save/cancel from within the provider
148
156
 
149
157
  **How it works (with `trackChanges` enabled):**
158
+
150
159
  1. Fields render as read-only `DynamicValue` display
151
160
  2. Click a field → switches to `DynamicFormField` editor inline
152
161
  3. Changed fields get highlighted with amber background
@@ -156,6 +165,7 @@ Use `EditableRecordDetail` for detail views where users can edit individual fiel
156
165
  **Important:** Always pass `trackChanges` prop when using `EditableRecordDetail` or `DataGrid` with cell editing. Without it, users have no visual feedback about which fields they've modified and no centralized Save/Cancel flow.
157
166
 
158
167
  **Field change tracking types:**
168
+
159
169
  ```tsx
160
170
  interface RecordDetailField {
161
171
  field: IField // Field configuration (name, slug, type)
@@ -174,6 +184,7 @@ interface FieldChange {
174
184
  ```
175
185
 
176
186
  **Example — Detail view with inline editing and "Edit All" button:**
187
+
177
188
  ```tsx
178
189
  <AwesomeDialogHeader
179
190
  title="Task Detail"
@@ -368,9 +379,11 @@ When using **Data Grid View Select**, back its `views`, `onViewCreate`, `onViewS
368
379
  ## Library-Specific Strengths
369
380
 
370
381
  ### shadcn (43 components)
382
+
371
383
  **Best for**: Core UI primitives, forms, basic layout
372
384
 
373
385
  **Strengths**:
386
+
374
387
  - Well-tested, accessible components
375
388
  - Great documentation
376
389
  - Broad browser support
@@ -379,9 +392,11 @@ When using **Data Grid View Select**, back its `views`, `onViewCreate`, `onViewS
379
392
  **Use when**: You need a standard, reliable component without special features
380
393
 
381
394
  ### diceui (42 components)
395
+
382
396
  **Best for**: Advanced interactions, specialized data components
383
397
 
384
398
  **Strengths**:
399
+
385
400
  - Rich feature sets (filtering, sorting, virtualization)
386
401
  - Advanced input types (phone, color, mask)
387
402
  - Drag-drop capabilities
@@ -390,9 +405,11 @@ When using **Data Grid View Select**, back its `views`, `onViewCreate`, `onViewS
390
405
  **Use when**: You need advanced functionality beyond basic components
391
406
 
392
407
  ### animate-ui (21 components)
408
+
393
409
  **Best for**: Animated transitions, polished UX
394
410
 
395
411
  **Strengths**:
412
+
396
413
  - Smooth, professional animations
397
414
  - Enhanced visual feedback
398
415
  - Composable animated patterns
@@ -400,9 +417,11 @@ When using **Data Grid View Select**, back its `views`, `onViewCreate`, `onViewS
400
417
  **Use when**: Animation/transitions are important to the UX
401
418
 
402
419
  ### docyrus (51 components)
420
+
403
421
  **Best for**: Docyrus-specific data handling, forms, dialogs, inline editing, scheduling, chat, AI agents, and business logic
404
422
 
405
423
  **Strengths**:
424
+
406
425
  - Deep Docyrus platform integration
407
426
  - AwesomeDialog system for item creation and detail views
408
427
  - EditableRecordDetail for inline field editing with change tracking
@@ -419,9 +438,11 @@ When using **Data Grid View Select**, back its `views`, `onViewCreate`, `onViewS
419
438
  **Use when**: Working with Docyrus data sources, building item create/detail flows, forms, scheduling, chat, AI features, or queries
420
439
 
421
440
  ### reui (2 components)
441
+
422
442
  **Best for**: Specific utility needs
423
443
 
424
444
  **Strengths**:
445
+
425
446
  - Focused implementations
426
447
  - Lightweight alternatives
427
448
 
@@ -466,25 +487,29 @@ These are the **recommended defaults** unless the user specifies otherwise:
466
487
 
467
488
  ## When to Use Each Library
468
489
 
469
- ### Use shadcn when:
490
+ ### Use shadcn when
491
+
470
492
  - Building basic forms with standard inputs
471
493
  - Creating simple layouts with cards, buttons, badges
472
494
  - Need reliable, accessible primitives
473
495
  - No special animation or advanced features required
474
496
 
475
- ### Use diceui when:
497
+ ### Use diceui when
498
+
476
499
  - Building complex data tables with sorting/filtering
477
500
  - Need advanced input types (phone, color, tags)
478
501
  - Implementing drag-drop (kanban, sortable lists)
479
502
  - Creating rich data visualizations (gauges, timelines)
480
503
 
481
- ### Use animate-ui when:
504
+ ### Use animate-ui when
505
+
482
506
  - Animation/transitions are important to the design
483
507
  - Building navigation with smooth interactions
484
508
  - Creating polished dialog/overlay experiences
485
509
  - Need animated feedback for user actions
486
510
 
487
- ### Use docyrus when:
511
+ ### Use docyrus when
512
+
488
513
  - Building item create forms (AwesomeDialog, Create Record Dialog)
489
514
  - Building item detail views (AwesomeDialog + EditableRecordDetail)
490
515
  - Working directly with Docyrus data sources
@@ -499,7 +524,8 @@ These are the **recommended defaults** unless the user specifies otherwise:
499
524
  - Need rich item selectors (Mega Select, Kanban)
500
525
  - Need Docyrus-specific components (query builder, activity panel, notifications)
501
526
 
502
- ### Use reui when:
527
+ ### Use reui when
528
+
503
529
  - The specific component (file upload or sortable) matches your exact need
504
530
  - Want a lightweight alternative to diceui versions
505
531
 
@@ -524,6 +550,7 @@ These are the **recommended defaults** unless the user specifies otherwise:
524
550
  - Use for: Fallback when neither hugeicons nor fontawesome have the icon
525
551
 
526
552
  **Example**:
553
+
527
554
  ```tsx
528
555
  import { HugeIconDollarCircle } from '@/components/icons/hugeicons'
529
556
  import { FaLightChartLine } from '@/components/icons/fontawesome'
@@ -544,6 +571,7 @@ import { LucideActivity } from 'lucide-react'
544
571
  ## Quick Reference: Component Categories
545
572
 
546
573
  ### Dialogs & Item Flows
574
+
547
575
  - Item create forms: **docyrus AwesomeDialog** (sheet for small, modal for large)
548
576
  - Quick record create: **docyrus Create Record Dialog** (popover with subject/mentions)
549
577
  - Item detail (small): **docyrus AwesomeDialog** (sheet right)
@@ -553,6 +581,7 @@ import { LucideActivity } from 'lucide-react'
553
581
  - Responsive: diceui Responsive Dialog
554
582
 
555
583
  ### Data & Display
584
+
556
585
  - Tables: docyrus Data Grid, diceui Data Table, shadcn Table
557
586
  - Pivot table: docyrus PivotGrid (hierarchies, subtotals, drilldown, export)
558
587
  - Grid saved views: docyrus Data Grid View Select + `DataViews` from `@docyrus/app-utils`
@@ -564,6 +593,7 @@ import { LucideActivity } from 'lucide-react'
564
593
  - Tree: docyrus TreeView
565
594
 
566
595
  ### Forms & Input
596
+
567
597
  - Dynamic forms: **docyrus Form Fields + TanStack Form** (always use)
568
598
  - Inline editing: docyrus EditableRecordDetail, EditableValue
569
599
  - Text: shadcn Input, Textarea
@@ -576,17 +606,20 @@ import { LucideActivity } from 'lucide-react'
576
606
  - Special: diceui Phone Input, Color Picker, Tags Input
577
607
 
578
608
  ### Navigation
609
+
579
610
  - Sidebar: animate-ui Sidebar
580
611
  - Menus: animate-ui Dropdown Menu, shadcn Menubar
581
612
  - Breadcrumbs: shadcn Breadcrumb
582
613
  - Tabs: animate-ui Tabs
583
614
 
584
615
  ### Overlays
616
+
585
617
  - Item forms/details: **docyrus AwesomeDialog** (preferred)
586
618
  - Popovers: animate-ui Popover, Tooltip, Hover Card
587
619
  - Drawers: shadcn Drawer, animate-ui Sheet
588
620
 
589
621
  ### Communication
622
+
590
623
  - Team chat: docyrus Team Chat Channel (threads, reactions, mentions)
591
624
  - Email composing: docyrus Email Composer (To/Cc/Bcc, toolbar, attachments)
592
625
  - Comments: docyrus Comments Panel (threaded conversations)
@@ -594,21 +627,25 @@ import { LucideActivity } from 'lucide-react'
594
627
  - Activity logging: docyrus Log Activity Form (calls, emails, meetings, tasks, statuses)
595
628
 
596
629
  ### Scheduling
630
+
597
631
  - Project timelines: docyrus Gantt
598
632
  - Resource scheduling: docyrus Resource Scheduler Panel (horizontal timeline)
599
633
  - Appointment booking: docyrus Time Slot Scheduler (columns/month views)
600
634
  - Calendar events: docyrus Calendar (month/week/day views)
601
635
 
602
636
  ### AI & Agents
637
+
603
638
  - AI chat: docyrus Docyrus Agent (chat mode)
604
639
  - AI actions: docyrus Docyrus Agent (action-panel mode)
605
640
  - AI trigger: docyrus Docyrus Agent (floating trigger button)
606
641
 
607
642
  ### Business Logic
643
+
608
644
  - Pricing/quoting: docyrus Pricing Engine Panel (line items, VAT, discounts)
609
645
  - Record sharing: docyrus Record Sharing (permissions, users/teams/roles)
610
646
 
611
647
  ### Specialized
648
+
612
649
  - Kanban: docyrus Kanban (drag-drop columns)
613
650
  - Timeline: diceui Timeline
614
651
  - Stepper / wizard: docyrus Stepper (6 variants, horizontal/vertical, animated)
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: docyrus-data-grid-page-design
3
+ description: Build Docyrus React data-grid and record-list pages with `DataGrid`, `DataGridViewSelect`, `useDataGrid`, `useDocyrusDataViewSelect`, and `useDocyrusDataGrid`. Use when asked to build or refactor a list page, records table, CRM or ERP grid, saved-view tabs, row actions, manual DataGrid toolbar composition, or Docyrus data-source grid queries with filtering, sorting, grouping, search, display modes, paging, and reload behavior.
4
+ ---
5
+
6
+ # Docyrus Data Grid Page Design
7
+
8
+ Build full Docyrus list pages around the web `DataGrid` stack.
9
+
10
+ ## Choose the build mode
11
+
12
+ 1. **Standard Docyrus page** → use `useDocyrusDataGrid`.
13
+ - Best when rows come from a Docyrus data source or generated collection.
14
+ - Gives you metadata-driven columns, saved views, toolbar wiring, search, filters (with async option search for relation/user fields), grouping, sorting, row-height, display mode, paging, and reload.
15
+ - Auto-wires reference field expansion, tenant-aware formatters, and a shared users list when supplied.
16
+ - Read `references/hook-pages.md`.
17
+
18
+ 2. **Custom layout or custom row-query lifecycle** → use `useDocyrusDataViewSelect` + `useDataGrid`.
19
+ - Best when you need a custom toolbar arrangement, local/demo data, or a non-standard fetch cycle.
20
+ - Read `references/manual-pages.md`.
21
+
22
+ 3. **No backend saved views** → use `useDataGrid` with local `SavedDataGridView[]` or `DataGridViewMenu`.
23
+ - Also covered in `references/manual-pages.md`.
24
+
25
+ 4. **Complex Docyrus query payloads** → also load the `docyrus-api-dev` skill.
26
+ 5. **Advanced saved-view persistence or manual view-driven queries** → read `references/advanced-saved-view-query-patterns.md`.
27
+ 6. **Tenant-aware formatters and shared users list** → read `references/tenant-and-users-providers.md`.
28
+
29
+ ## Default page workflow
30
+
31
+ 1. Confirm the `appSlug`, `dataSourceSlug`, and whether a generated collection already exists.
32
+ 2. Pick hook mode or manual mode.
33
+ 3. App-level: ensure a `TenantProvider` (preferences → date/number utils) and `UsersProvider` (`/v1/users` cache) wrap the route, and pull `formatDate` / `formatDateTime` / `formatNumber` / `users` into the grid hook from those contexts.
34
+ 4. Add reserved columns in this order: select first, actions second. They are pinned left automatically by `useDocyrusDataGrid`.
35
+ 5. Keep the page in a flex column layout with the grid body wrapped in `min-h-0 flex-1`.
36
+ 6. Add create/edit/view/delete dialogs around row actions.
37
+ 7. Verify initial saved view, search, filters, grouping, sorting, paging, and reload behavior.
38
+
39
+ ## Non-negotiables
40
+
41
+ - Render page-sized grids with the toolbar in a shrink-0 row and the grid inside `min-h-0 flex-1`.
42
+ - Prefer `<DataGrid table={table} {...gridProps} height="auto" />` for full-page layouts.
43
+ - Pass the TanStack `table` instance to every grid menu and to `DataGridViewSelect`.
44
+ - `useDocyrusDataViewSelect` manages view metadata only. It does **not** fetch rows and does **not** accept `table`.
45
+ - Manual Docyrus item queries must always send `columns`. Reference fields (`field-userSelect`, `field-userMultiSelect`, `field-relation`, `field-relatedField`, `field-select`, `field-radioGroup`, `field-enum`, `field-systemEnum`, `field-multiSelect`, `field-tagSelect`, `field-status`, `field-approvalStatus`) must also be added to the `expand` array so the API returns `{ id, name, ... }` payloads instead of bare IDs.
46
+ - Backend saved-view filters need enum options; `useDocyrusDataViewSelect` already fetches the data source with `expand=enums`.
47
+ - Manual pages must apply the initial active view with `applyViewToTable(table, activeView)` after views and columns are ready. User-triggered view switches through `DataGridViewSelect` are applied automatically.
48
+ - Prefer `useDocyrusDataGrid` unless you truly need custom row fetching or custom toolbar composition. The hook handles auto-expand, async filter options, formatters, and reserved-column pinning for you.
49
+ - When you wire manual view CRUD into `DataGridViewSelect`, pass `isSaving` and `isLoading` so the editor UX stays correct during saves and background fetches.
50
+ - For tenant-aware date/datetime/number formatting, fetch `getTenantPreferences(client)` once at app boot and pass the resulting `formatDate` / `formatDateTime` / `formatNumber` callbacks into `useDocyrusDataGrid`.
51
+ - For instant avatar + label rendering on user-typed cells, fetch `/v1/users` once at app boot and pass the resulting `CellUserOption[]` into `useDocyrusDataGrid` via the `users` option.
52
+
53
+ ## References
54
+
55
+ - `references/hook-pages.md` — one-call Docyrus grid pages with direct API mode, collection mode, extension points, formatters, and shared-users wiring.
56
+ - `references/manual-pages.md` — local/manual grid composition, local views, backend view-select wiring, and initial-view handling.
57
+ - `references/advanced-saved-view-query-patterns.md` — saved-view persistence, system views, hidden views, paging ownership, and translating active views into manual server queries.
58
+ - `references/tenant-and-users-providers.md` — app-level providers for tenant preferences and the shared users list, plus how to plug them into `useDocyrusDataGrid`.
@@ -0,0 +1,158 @@
1
+ # Advanced Saved-View and Query Patterns
2
+
3
+ ## Read this when
4
+
5
+ - You need backend-saved views but do not want `useDocyrusDataGrid` to own row fetching.
6
+ - You want system views plus user-saved views in one selector.
7
+ - You need to debug why a saved view, grouping rule, or paging setting is not reflected in the grid.
8
+ - You need to translate `SavedDataGridView` into a custom Docyrus items query.
9
+
10
+ ## Saved-view ownership model
11
+
12
+ - `DataGridViewSelect` applies the selected view to the TanStack table when the user clicks a tab or dropdown item.
13
+ - `useDocyrusDataGrid` also reapplies the active view on mount and whenever the active view changes, so the initial view works without extra code.
14
+ - Manual pages using `useDocyrusDataViewSelect` plus `useDataGrid` must still apply the initial active view with `applyViewToTable(table, activeView)`.
15
+
16
+ ## System views, hidden views, and persistence
17
+
18
+ `useDocyrusDataViewSelect` supports three useful layers of view state:
19
+
20
+ 1. `systemViews`
21
+ - Developer-defined static views.
22
+ - Automatically marked `isSystem: true`.
23
+ - Render before saved backend views.
24
+ - Cannot be edited or deleted through `DataGridViewSelect`, but can still be hidden.
25
+
26
+ 2. active-view persistence
27
+ - Controlled by `persistActiveView` and `persistKey`.
28
+ - Default storage namespace: `docyrus:data-grid-view:appSlug:dataSourceSlug[:appId]`.
29
+ - Initial resolution order: current in-memory value, stored value, backend `is_default`, then first available view.
30
+
31
+ 3. hidden-view persistence
32
+ - Managed through `hiddenViewIds`, `onViewHide`, and `onViewUnhide` in `gridViewSelectProps`.
33
+ - Stored separately from the active-view key.
34
+ - Useful when system views should exist but not always stay visible in the tab strip.
35
+
36
+ ## Manual server-query translation from a saved view
37
+
38
+ If you keep custom row fetching, derive request params from the active view yourself. Don't forget the toolbar filter merge — `DataGridFilterMenu` writes to TanStack `columnFilters`, and a manual page must AND-merge those into the saved-view filter payload.
39
+
40
+ ```ts
41
+ const activeView = views.find(view => view.id === activeViewId);
42
+
43
+ const columns = buildColumnsFromView(fields, activeView);
44
+ const orderBy = (activeView?.sorting ?? []).map(sort => ({
45
+ field: sort.id,
46
+ direction: sort.desc ? 'desc' : 'asc'
47
+ }));
48
+
49
+ // Auto-expand reference-type fields so the API returns `{ id, name, ... }` payloads.
50
+ const EXPANDABLE_FIELD_TYPES = new Set([
51
+ 'field-userSelect', 'field-userMultiSelect',
52
+ 'field-relation', 'field-relatedField',
53
+ 'field-select', 'field-radioGroup',
54
+ 'field-enum', 'field-systemEnum',
55
+ 'field-multiSelect', 'field-tagSelect',
56
+ 'field-status', 'field-approvalStatus'
57
+ ]);
58
+ const expand = fields
59
+ .filter(field => columns.includes(field.slug) && EXPANDABLE_FIELD_TYPES.has(field.type))
60
+ .map(field => field.slug);
61
+
62
+ // Merge saved-view filters with toolbar filter state.
63
+ const viewFilter = activeView?.filterQuery?.rules?.length ? activeView.filterQuery : undefined;
64
+ const toolbarRules = (table.getState().columnFilters ?? [])
65
+ .map(filter => toServerRule(filter)) // import from @docyrus/ui/components/data-grid/lib/data-grid-server
66
+ .filter(Boolean);
67
+
68
+ let filters;
69
+
70
+ if (viewFilter && toolbarRules.length > 0) {
71
+ filters = { combinator: 'and', rules: [viewFilter, ...toolbarRules] };
72
+ } else if (viewFilter) {
73
+ filters = viewFilter;
74
+ } else if (toolbarRules.length > 0) {
75
+ filters = { combinator: 'and', rules: toolbarRules };
76
+ }
77
+
78
+ const params = {
79
+ columns,
80
+ orderBy: orderBy.length > 0 ? orderBy : undefined,
81
+ filters,
82
+ filterKeyword: keyword || undefined,
83
+ expand: expand.length > 0 ? expand : undefined,
84
+ limit: 50,
85
+ offset: 0
86
+ };
87
+ ```
88
+
89
+ Rules to preserve from the built-in hook behavior:
90
+
91
+ - Always include `id` in `columns`.
92
+ - When `columnOrder` is present, treat it as the ordered whitelist of visible field slugs.
93
+ - Otherwise use `columnVisibility` entries with `true` values.
94
+ - With no explicit saved-view visibility config, fetch all field slugs.
95
+ - If the active view groups by a field, make sure that field stays in `columns` even if the saved view hides it.
96
+ - Add reference-type field slugs to `expand` so user / relation / status / select / multi-select cells render with full data.
97
+ - AND-merge `view.filterQuery` with the toolbar filter rules; reset `pageIndex` to 0 when the merged filter changes.
98
+ - If you merge app-specific overrides, apply them last so they win.
99
+
100
+ ## Reserved columns versus backend field slugs
101
+
102
+ There are two different conventions:
103
+
104
+ - Local/manual views can include reserved table columns like `select` and `actions` inside `columnOrder`.
105
+ - Backend Docyrus-saved views only know real data-source field slugs.
106
+
107
+ That difference matters when you build a hybrid page. If you manually persist local views, reserved columns are safe. If you round-trip views through Docyrus backend APIs, assume only real field slugs are persisted and prepend reserved UI columns in the page code.
108
+
109
+ ## Paging ownership
110
+
111
+ Saved views can carry:
112
+
113
+ - `pagingEnabled`
114
+ - `pagingMode`
115
+ - `pageSize`
116
+
117
+ `useDocyrusDataGrid` reads those values and forwards them into `useDataGrid`, and `gridProps` then carries the resolved paging mode.
118
+
119
+ If you build the page manually and want the active view to own paging:
120
+
121
+ - read the values from `activeView`
122
+ - pass `pagingMode` and `pageSize` into `useDataGrid`
123
+ - ensure your own row query or pagination model stays compatible with that page size
124
+
125
+ If you ignore these properties in manual mode, the view editor can save paging settings that never affect the rendered grid.
126
+
127
+ ## Good advanced combinations
128
+
129
+ ### System starter views + backend user views
130
+
131
+ Use `systemViews` for non-editable defaults like:
132
+
133
+ - All records
134
+ - My records
135
+ - Needs attention
136
+ - Recently updated
137
+
138
+ Then let users create their own backend-saved views beside them.
139
+
140
+ ### Hook-owned metadata + app-owned data fetching
141
+
142
+ Use `useDocyrusDataViewSelect` when you want:
143
+
144
+ - backend view CRUD
145
+ - field metadata for the filter editor
146
+ - active-view persistence
147
+ - hidden-view persistence
148
+
149
+ but you still want the page's existing query hook, export pipeline, or analytics request builder to own row fetching.
150
+
151
+ ## Debug checklist
152
+
153
+ - **Wrong initial view?** Check `persistActiveView`, `persistKey`, and whether a stale value is still in local storage.
154
+ - **Grouping not working?** Make sure the grouping field is included in fetched `columns` and remains visible enough for the row model.
155
+ - **Filter builder missing?** Pass `fields` into `DataGridViewSelect`.
156
+ - **View tabs empty during loading?** Pass `isLoading` so the selector can render its loading state.
157
+ - **Editor closes too early on save?** Pass `isSaving` when the host owns async create or update.
158
+ - **Backend returns incomplete rows?** You probably forgot `columns`.