@nivaro/react 0.1.4

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.
@@ -0,0 +1,1608 @@
1
+ import { CascadeFilterRule } from '@nivaro/sdk';
2
+ import { default as default_2 } from 'react';
3
+ import { FieldDependencyConfig } from '@nivaro/sdk';
4
+ import type { ImportParseResponse } from '@nivaro/sdk';
5
+ import { JSX } from 'react';
6
+ import { JSXElementConstructor } from 'react';
7
+ import { NivaroClient } from '@nivaro/sdk';
8
+ import { default as React_2 } from 'react';
9
+ import { ReactElement } from 'react';
10
+ import { ReactNode } from 'react';
11
+ import { ReactPortal } from 'react';
12
+ import { ReportDateRange } from '@nivaro/sdk';
13
+ import { ReportEntityFilter } from '@nivaro/sdk';
14
+ import { ReportQueryWidgetConfig } from '@nivaro/sdk';
15
+ import { UseMutationResult } from '@tanstack/react-query';
16
+ import { UserScopesInfo } from '@nivaro/sdk';
17
+
18
+ export declare function AlertManagerView({ defaultTab, hiddenTabs, onOpenReport, className }: AlertManagerViewProps): JSX.Element;
19
+
20
+ export declare interface AlertManagerViewProps {
21
+ /** Tab shown on first render. */
22
+ defaultTab?: TabKey;
23
+ /** Hide specific tabs (e.g. widget tabs when Report Studio is unused). */
24
+ hiddenTabs?: TabKey[];
25
+ /** Called when a widget alert's report name is clicked (host navigation). */
26
+ onOpenReport?: (reportId: string) => void;
27
+ className?: string;
28
+ }
29
+
30
+ export declare function BooleanField({ field, value, onChange, error, disabled, readOnly, inputId, errorId }: FieldComponentProps): JSX.Element;
31
+
32
+ export declare function canOpenDm(): boolean;
33
+
34
+ export { CascadeFilterRule }
35
+
36
+ declare interface ChannelMeta {
37
+ id: number;
38
+ visibility: 'open' | 'role' | 'private';
39
+ role: string | null;
40
+ topic: string | null;
41
+ created_by: string | null;
42
+ }
43
+
44
+ export declare function chatAvatarColor(id: string): string;
45
+
46
+ export declare interface ChatConfig {
47
+ collections: {
48
+ messages: string;
49
+ reads: string;
50
+ presence: string;
51
+ };
52
+ globalRoom: string;
53
+ globalLabel: string;
54
+ /** Entity-id pattern rendered as record links (RegExp source, global flags applied). */
55
+ entityPattern: string;
56
+ /** URL for an entity token (null = plain text). */
57
+ entityUrl: (token: string) => string | null;
58
+ /** Label for a non-global, non-dm room key (null = uppercased key). */
59
+ roomLabel?: (room: string) => string | null;
60
+ /** Host route for a resolved record (entity rooms' "Open record" action) —
61
+ * admin passes /collections/:c/:id, efp-new /records/:c/:id. Absent = the
62
+ * admin shape; return null = hide the action. */
63
+ recordUrl?: (collection: string, id: string | number) => string | null;
64
+ /** Live updates: subscribe to a collection's change feed; return unsubscribe.
65
+ * Still used for presence/typing, which remain plain /items collections. */
66
+ realtime?: (collection: string, cb: () => void) => () => void;
67
+ /**
68
+ * Live chat delivery: join the given rooms' socket rooms and call back on a
69
+ * `chat:message` event. Replaces invalidating on every chat_messages write
70
+ * anywhere — at channel scale that fan-out is a broadcast storm, and the
71
+ * server only emits to `chat:<room>` now. Without it the queries still poll.
72
+ */
73
+ subscribeRooms?: (rooms: string[], cb: (msg: ChatMessage) => void) => () => void;
74
+ me: {
75
+ id: string;
76
+ name: string;
77
+ } | null;
78
+ /** Online users (presence) — drives the Online tab + mention autocomplete. */
79
+ onlineUsers: ChatOnlineUser[];
80
+ /** Presence typing setter (userId, room|null). */
81
+ setTypingRoom?: (userId: string, room: string | null) => void | Promise<void>;
82
+ navigate?: (url: string) => void;
83
+ sound: boolean;
84
+ }
85
+
86
+ export declare function chatInitials(name: string | null): string;
87
+
88
+ /**
89
+ * Nivaro chat — data layer.
90
+ *
91
+ * Messages, rooms and watermarks go through /api/chat, NOT plain /items: room
92
+ * visibility (your DMs, the channels you belong to, entity rooms for records
93
+ * you can read) cannot be expressed as a table-level policy, and the items API
94
+ * now refuses these collections outright. Presence/typing stay on /items,
95
+ * which is per-user by nature. Live delivery comes from a host-provided
96
+ * realtime adapter, with polling fallbacks baked into every query.
97
+ *
98
+ * Ported from the EFP implementation with its semantics preserved:
99
+ * - DM room keys are 'dm:<A>:<B>' with UPPERCASED sorted uuids (MSSQL returns
100
+ * uuids uppercased — a casing mismatch forks a second room).
101
+ * - Read watermarks are serialized per room (markInFlight) because the reads
102
+ * table has UNIQUE(user, room) and the room view marks on entry AND on each
103
+ * new message — concurrent select-then-insert would 500 on duplicate key.
104
+ * - Mentions store '@[Display Name]' with no id; notifications fire only for
105
+ * users picked from the autocomplete.
106
+ */
107
+ export declare interface ChatMessage {
108
+ id: number;
109
+ sender: string;
110
+ sender_name: string | null;
111
+ room: string;
112
+ message: string;
113
+ date_created: string;
114
+ }
115
+
116
+ export declare interface ChatOnlineUser {
117
+ user_id: string;
118
+ display_name: string | null;
119
+ role_name?: string | null;
120
+ current_path?: string | null;
121
+ }
122
+
123
+ export declare function ChatPanel({ open, onClose, renderMessageBody, requestedDm }: {
124
+ open: boolean;
125
+ onClose: () => void;
126
+ renderMessageBody?: (m: ChatMessage, ctx: {
127
+ mine: boolean;
128
+ }) => React.ReactNode;
129
+ /** External DM request (UserChip "Send message" via registerDmOpener) —
130
+ * nonce bumps re-trigger even for the same user. */
131
+ requestedDm?: {
132
+ userId: string;
133
+ name?: string;
134
+ nonce: number;
135
+ } | null;
136
+ }): JSX.Element | null;
137
+
138
+ export declare function ChatProvider({ children, me, onlineUsers, collections, globalRoom, globalLabel, entityPattern, entityUrl, roomLabel, recordUrl, realtime, subscribeRooms, setTypingRoom, navigate, sound, theme }: ChatProviderProps): JSX.Element;
139
+
140
+ declare interface ChatProviderProps {
141
+ children: React.ReactNode;
142
+ me: ChatConfig['me'];
143
+ onlineUsers?: ChatOnlineUser[];
144
+ collections?: Partial<ChatConfig['collections']>;
145
+ globalRoom?: string;
146
+ globalLabel?: string;
147
+ entityPattern?: string;
148
+ entityUrl?: ChatConfig['entityUrl'];
149
+ roomLabel?: ChatConfig['roomLabel'];
150
+ recordUrl?: ChatConfig['recordUrl'];
151
+ realtime?: ChatConfig['realtime'];
152
+ subscribeRooms?: ChatConfig['subscribeRooms'];
153
+ setTypingRoom?: ChatConfig['setTypingRoom'];
154
+ navigate?: ChatConfig['navigate'];
155
+ sound?: boolean;
156
+ theme?: Partial<ChatTheme>;
157
+ }
158
+
159
+ export declare function ChatRoomList({ rooms, onOpen }: {
160
+ rooms: RoomInfo[];
161
+ onOpen: (room: RoomInfo) => void;
162
+ }): JSX.Element;
163
+
164
+ export declare function ChatRoomView({ room, label, onBack, onOpenSettings, renderMessageBody }: {
165
+ room: string;
166
+ label: string;
167
+ onBack: () => void;
168
+ /** Channel rooms only — opens members/visibility settings. */
169
+ onOpenSettings?: () => void;
170
+ renderMessageBody?: (m: ChatMessage, ctx: {
171
+ mine: boolean;
172
+ }) => React.ReactNode;
173
+ }): JSX.Element;
174
+
175
+ /**
176
+ * Nivaro chat UI — a complete team panel (Online tab, grouped rooms, live
177
+ * conversations with mentions, typing, receipts, search).
178
+ *
179
+ * Theming: every visual slot reads from `ChatTheme` (className strings) with
180
+ * nvr-cyan defaults — pass `theme` overrides on ChatProvider to restyle
181
+ * without forking. Structural hooks: `data-chat-*` attributes on every major
182
+ * element, `renderMessageBody` to override message rendering entirely.
183
+ */
184
+ export declare interface ChatTheme {
185
+ /** My message bubble. */
186
+ bubbleMine: string;
187
+ /** Others' message bubble. */
188
+ bubbleOther: string;
189
+ /** Accent text (links, read receipt, active states). */
190
+ accentText: string;
191
+ /** Soft accent fill (active tab, selected candidate, mention highlight). */
192
+ accentSoft: string;
193
+ /** Unread pill. */
194
+ pill: string;
195
+ /** Primary action (send button). */
196
+ action: string;
197
+ /** Panel/popover surface. */
198
+ surface: string;
199
+ /** Input fields. */
200
+ input: string;
201
+ /** Divider borders. */
202
+ divider: string;
203
+ }
204
+
205
+ /** Clear the schema cache (e.g. after a schema change). */
206
+ export declare function clearFormSchemaCache(collection?: string): void;
207
+
208
+ /** @deprecated Column model changed to plain field keys — kept for source
209
+ * compatibility with early adopters; maps `path` to a field key. */
210
+ export declare interface CollectionBrowserColumn {
211
+ path: string;
212
+ label?: string;
213
+ format?: 'currency' | 'date' | 'datetime' | 'text';
214
+ filterable?: boolean;
215
+ }
216
+
217
+ export declare function CollectionBrowserView({ collection, quickFilters, initialColumns, initialSort, pageSize, initialSearch, initialConditions, onOpenItem, showCreate, className }: CollectionBrowserViewProps): React_2.JSX.Element;
218
+
219
+ export declare interface CollectionBrowserViewProps {
220
+ collection: string;
221
+ /** Persistent facet dropdowns above the table (multi-select + Apply/Clear);
222
+ * selections filter server-side over the entire record set. */
223
+ quickFilters?: QuickFilterDef[];
224
+ /** Initial visible columns (plain field keys). Defaults to the first 7
225
+ * non-hidden fields. */
226
+ initialColumns?: string[];
227
+ /** Default sort until a header is clicked (e.g. '-created'). */
228
+ initialSort?: string;
229
+ pageSize?: number;
230
+ /** Initial quick-search value (deep links). */
231
+ initialSearch?: string;
232
+ /** Contextual deep-link conditions (e.g. a dashboard tile linking to "my
233
+ * drafts"): ANDed into every fetch until the user clears the context chip.
234
+ * `label` is what the chip displays for that condition. */
235
+ initialConditions?: Array<{
236
+ path: string[];
237
+ op: string;
238
+ value: unknown;
239
+ label?: string;
240
+ }>;
241
+ /** Override row-open behavior; defaults to NavigationContext itemUrl. */
242
+ onOpenItem?: (id: string | number) => void;
243
+ showCreate?: boolean;
244
+ className?: string;
245
+ }
246
+
247
+ export declare function CollectionImportPanel({ initialJobId, onJobOpen }: {
248
+ /** Deep link: open this job's detail on mount. */
249
+ initialJobId?: string | null;
250
+ onJobOpen?: (id: string | null) => void;
251
+ }): JSX.Element;
252
+
253
+ declare interface Column<T = Record<string, unknown>> {
254
+ key: string;
255
+ header: React_2.ReactNode;
256
+ sortable?: boolean;
257
+ className?: string;
258
+ headerClassName?: string;
259
+ render?: (row: T, index: number) => React_2.ReactNode;
260
+ }
261
+
262
+ declare type ColumnFormatConfig = {
263
+ type: 'datetime';
264
+ template: string;
265
+ } | {
266
+ type: 'number';
267
+ decimals?: number;
268
+ thousands?: boolean;
269
+ prefix?: string;
270
+ suffix?: string;
271
+ } | {
272
+ type: 'boolean';
273
+ true_label: string;
274
+ false_label: string;
275
+ };
276
+
277
+ export declare function CommentPanel({ collection, item, title, defaultExpanded, queuedComments, onQueueComment }: {
278
+ collection: string;
279
+ item: string | number;
280
+ title?: string;
281
+ defaultExpanded?: boolean;
282
+ queuedComments?: string[];
283
+ onQueueComment?: (text: string) => void;
284
+ }): React_2.JSX.Element;
285
+
286
+ export declare type ComponentOverrides = {
287
+ text?: default_2.ComponentType<FieldComponentProps>;
288
+ textarea?: default_2.ComponentType<FieldComponentProps>;
289
+ integer?: default_2.ComponentType<FieldComponentProps>;
290
+ float?: default_2.ComponentType<FieldComponentProps>;
291
+ decimal?: default_2.ComponentType<FieldComponentProps>;
292
+ boolean?: default_2.ComponentType<FieldComponentProps>;
293
+ date?: default_2.ComponentType<FieldComponentProps>;
294
+ datetime?: default_2.ComponentType<FieldComponentProps>;
295
+ select?: default_2.ComponentType<FieldComponentProps>;
296
+ radio?: default_2.ComponentType<FieldComponentProps>;
297
+ 'checkbox-group'?: default_2.ComponentType<FieldComponentProps>;
298
+ 'relation-m2o'?: default_2.ComponentType<FieldComponentProps>;
299
+ 'relation-o2m'?: default_2.ComponentType<FieldComponentProps>;
300
+ 'relation-m2m'?: default_2.ComponentType<FieldComponentProps>;
301
+ wysiwyg?: default_2.ComponentType<FieldComponentProps>;
302
+ file?: default_2.ComponentType<FieldComponentProps>;
303
+ json?: default_2.ComponentType<FieldComponentProps>;
304
+ uuid?: default_2.ComponentType<FieldComponentProps>;
305
+ fallback?: default_2.ComponentType<FieldComponentProps>;
306
+ };
307
+
308
+ export declare function DataTable<T = Record<string, unknown>>({ columns, rows, rowKey, total, page, limit, isLoading, isError, errorMessage, sort, onSortChange, onPageChange, onRowClick, searchValue, onSearchChange, searchPlaceholder, filterDefs, filterValues, onFilterChange, toolbarRight, emptyMessage, minBodyHeight, fillHeight, hideFilterRow, nowrapCells, pinFirstColumn, columnPins, onColumnPinChange, columnFilterRow, hScrollProxy, selectedIds, onSelectionChange, rowClassName, rowGroups, collapsedGroups, onToggleGroup }: DataTableProps<T>): React_2.JSX.Element;
309
+
310
+ declare interface DataTableProps<T = Record<string, unknown>> {
311
+ columns: Column<T>[];
312
+ rows: T[];
313
+ rowKey?: (row: T, i: number) => string;
314
+ total: number;
315
+ page: number;
316
+ limit?: number;
317
+ isLoading?: boolean;
318
+ isError?: boolean;
319
+ errorMessage?: string;
320
+ sort?: string;
321
+ onSortChange?: (sort: string) => void;
322
+ onPageChange: (page: number) => void;
323
+ onRowClick?: (row: T) => void;
324
+ searchValue?: string;
325
+ onSearchChange?: (val: string) => void;
326
+ searchPlaceholder?: string;
327
+ filterDefs?: FilterDef[];
328
+ filterValues?: Record<string, string | string[]>;
329
+ onFilterChange?: (key: string, value: string | string[]) => void;
330
+ toolbarRight?: React_2.ReactNode;
331
+ emptyMessage?: string;
332
+ /** Suppress the inline filter-control row while keeping filterDefs available
333
+ * to the host (e.g. a page rendering its own filter rail). */
334
+ hideFilterRow?: boolean;
335
+ /** Force single-line cells (whitespace-nowrap on every body cell) — hosts
336
+ * pair this with per-column truncation for dense, scannable tables. */
337
+ nowrapCells?: boolean;
338
+ /** Pin the selection checkbox (when present) and the first data column so
339
+ * they stay visible while the table scrolls horizontally. */
340
+ pinFirstColumn?: boolean;
341
+ /** Per-column pinning (CollectionBrowserView parity). When provided (even
342
+ * empty), replaces `pinFirstColumn`: left-pinned columns render first,
343
+ * right-pinned last, sticky offsets come from live header-cell width
344
+ * measurement, and (with `onColumnPinChange`) every header grows a
345
+ * hover-revealed pin button cycling none → left → right → none. */
346
+ columnPins?: Record<string, 'left' | 'right'>;
347
+ onColumnPinChange?: (key: string, pin: 'left' | 'right' | null) => void;
348
+ /** Render a compact per-column filter row under the headers — each column
349
+ * whose key matches a FilterDef gets that def's control inline (the
350
+ * CollectionBrowserView column-filter pattern). Independent of the
351
+ * toolbar/rail rendering controlled by `hideFilterRow`. */
352
+ columnFilterRow?: boolean;
353
+ /** Always-visible draggable horizontal scrollbar under the table (the
354
+ * CollectionBrowserView HScrollProxy) — the native x-scrollbar is hidden
355
+ * and trackpad panning is translated by the proxy. */
356
+ hScrollProxy?: boolean;
357
+ /** Minimum height for the table body region — keeps empty/short tables from
358
+ * collapsing to a sliver (empty message centers in the space). */
359
+ minBodyHeight?: number;
360
+ /** Fill the parent's (bounded) height: rows scroll INSIDE the card under a
361
+ * sticky header, so the h-scroll proxy and pagination stay pinned in view
362
+ * instead of sitting below a page-tall table. Parent must give the card a
363
+ * definite height (flex chain with min-h-0). */
364
+ fillHeight?: boolean;
365
+ selectedIds?: string[];
366
+ onSelectionChange?: (ids: string[]) => void;
367
+ /** Optional per-row class — e.g. at-risk background tinting. */
368
+ rowClassName?: (row: T) => string | undefined;
369
+ /** Grouped rendering: when set, `rows` is ignored for the body; each group renders
370
+ * a full-width header row followed by its rows (unless collapsed). Pagination hides. */
371
+ rowGroups?: Array<{
372
+ key: string;
373
+ header: React_2.ReactNode;
374
+ rows: T[];
375
+ }>;
376
+ collapsedGroups?: Set<string>;
377
+ onToggleGroup?: (key: string) => void;
378
+ }
379
+
380
+ export declare function DateField({ field, value, onChange, error, disabled, readOnly, inputId, errorId }: FieldComponentProps): JSX.Element;
381
+
382
+ /** The admin's route shape — the default when the host supplies no itemUrl. */
383
+ export declare function defaultItemUrl(t: ItemLinkTarget): string;
384
+
385
+ declare type DmOpener = (userId: string, displayName?: string) => void;
386
+
387
+ export declare function dmPeer(room: string, self: string): string | null;
388
+
389
+ export declare function dmRoom(a: string, b: string): string;
390
+
391
+ export declare const DrilldownContext: React_2.Context<DrilldownContextValue | null>;
392
+
393
+ declare interface DrilldownContextValue {
394
+ open: (target: DrilldownTarget) => void;
395
+ }
396
+
397
+ export declare interface DrilldownTarget {
398
+ collection: string;
399
+ itemId: string;
400
+ layoutId?: number | null;
401
+ width?: number | string | null;
402
+ title?: string;
403
+ }
404
+
405
+ /**
406
+ * The ids a filter surface should PRE-SELECT for a dimension. Restrictions are
407
+ * server-enforced regardless, so the seeded selection must reflect them:
408
+ * defaults ∩ restricted when both are set; ALL restricted values when defaults
409
+ * are empty or entirely outside the restriction; plain defaults otherwise.
410
+ */
411
+ export declare function effectiveScopeSeedIds(scopes: {
412
+ defaults: Record<string, Array<string | number>>;
413
+ restricted: Record<string, Array<string | number>>;
414
+ }, dimName: string): Array<string | number>;
415
+
416
+ export declare function fetchSchema(client: NivaroClient, collection: string, includeHidden: boolean, layoutId?: number, layoutSlug?: string): Promise<FormSchema>;
417
+
418
+ export declare type FieldArrayReturn = {
419
+ items: unknown[];
420
+ append: (item?: unknown) => void;
421
+ remove: (index: number) => void;
422
+ move: (from: number, to: number) => void;
423
+ update: (index: number, value: unknown) => void;
424
+ replace: (items: unknown[]) => void;
425
+ };
426
+
427
+ export declare type FieldComponentProps = {
428
+ field: FormFieldDescriptor;
429
+ value: unknown;
430
+ onChange: (value: unknown) => void;
431
+ error: string[] | undefined;
432
+ disabled: boolean;
433
+ readOnly: boolean;
434
+ /**
435
+ * Unique DOM id for the input element — generated by NivaroField via useId().
436
+ * Falls back to `field.field` when not provided (may collide if two forms
437
+ * with the same collection are mounted simultaneously).
438
+ */
439
+ inputId?: string;
440
+ /** id of the error container element, for aria-describedby wiring */
441
+ errorId?: string;
442
+ };
443
+
444
+ export { FieldDependencyConfig }
445
+
446
+ export declare type FieldState = {
447
+ value: unknown;
448
+ error: string[] | undefined;
449
+ visible: boolean;
450
+ locked: boolean;
451
+ required: boolean;
452
+ colSpan: number;
453
+ descriptor: FormFieldDescriptor | null;
454
+ onChange: (v: unknown) => void;
455
+ };
456
+
457
+ /**
458
+ * Unstyled file input. On selection it uploads via client.upload() (POST /files)
459
+ * and calls onChange with the returned file id. Renders the current id/url as text.
460
+ *
461
+ * On upload error the file input is reset via a key increment so the browser
462
+ * doesn't show the failed filename as if the upload succeeded.
463
+ */
464
+ export declare function FileField({ field, value, onChange, error, disabled, readOnly, inputId, errorId }: FieldComponentProps): JSX.Element;
465
+
466
+ declare interface FilterDef {
467
+ key: string;
468
+ placeholder: string;
469
+ /** Defaults to 'select' — every existing FilterDef without this field keeps its current dropdown behavior unchanged. */
470
+ type?: 'select' | 'text' | 'range' | 'combobox';
471
+ /** Required when type is 'select' or omitted; static options for 'combobox'; ignored for 'text'/'range'. */
472
+ options?: {
473
+ label: string;
474
+ value: string;
475
+ }[];
476
+ /** 'combobox' only: server-backed autocomplete. Called (debounced) with the search
477
+ * text; overrides `options` when provided. */
478
+ loadOptions?: (search: string) => Promise<{
479
+ label: string;
480
+ value: string;
481
+ }[]>;
482
+ /** 'combobox' only: allow selecting multiple values (filter matches ANY of them). */
483
+ multi?: boolean;
484
+ }
485
+
486
+ export declare type FormDirtyState = {
487
+ isDirty: boolean;
488
+ dirtyFields: string[];
489
+ isFieldDirty: (field: string) => boolean;
490
+ };
491
+
492
+ export declare type FormErrors = Record<string, string[]>;
493
+
494
+ export declare type FormFieldDescriptor = {
495
+ field: string;
496
+ /** raw DB type (string, integer, boolean, uuid, json, …) */
497
+ type: string;
498
+ /** normalized type used to pick the rendering component */
499
+ fieldType: FormFieldType;
500
+ /** CMS interface string (input, select-dropdown, many-to-one, …) */
501
+ interface: string | null;
502
+ label: string;
503
+ note: string | null;
504
+ required: boolean;
505
+ readonly: boolean;
506
+ hidden: boolean;
507
+ sort: number | null;
508
+ /** field group key (null = ungrouped) */
509
+ group: string | null;
510
+ /** interface options (e.g. { choices: [{text, value}] } for selects) */
511
+ options: Record<string, unknown> | null;
512
+ validationRules: FormValidationRule[] | null;
513
+ visibilityRules: FormVisibilityRule[] | null;
514
+ lockCondition: FormLockCondition | null;
515
+ relation?: {
516
+ type: 'o2m' | 'm2o' | 'm2m' | 'm2a';
517
+ relatedCollection: string;
518
+ /** For M2M: the junction/pivot table (e.g. workflows_divisions). relatedCollection is the far-end. */
519
+ junctionCollection?: string | null;
520
+ displayTemplate: string | null;
521
+ manyField?: string | null;
522
+ junctionField?: string | null;
523
+ } | null;
524
+ defaultValue?: unknown;
525
+ /** cascade_filters from dependency_config — each rule links a parent field to a filter column */
526
+ cascadeFilters?: Array<{
527
+ parent_field: string;
528
+ filter_column: string;
529
+ clear_on_parent_change?: boolean;
530
+ }> | null;
531
+ };
532
+
533
+ /**
534
+ * Normalized field type used by the form renderer to pick a component.
535
+ * Derived from the raw DB type + CMS interface string in `useFormSchema`.
536
+ */
537
+ export declare type FormFieldType = 'text' | 'textarea' | 'integer' | 'float' | 'decimal' | 'boolean' | 'date' | 'datetime' | 'select' | 'radio' | 'checkbox-group' | 'relation-m2o' | 'relation-o2m' | 'relation-m2m' | 'wysiwyg' | 'file' | 'json' | 'uuid' | 'unknown';
538
+
539
+ export declare type FormGroupDescriptor = {
540
+ key: string;
541
+ label: string;
542
+ type: 'section' | 'tab';
543
+ icon: string | null;
544
+ sort: number;
545
+ isCollapsed: boolean;
546
+ };
547
+
548
+ /** A client-evaluable lock condition. */
549
+ export declare type FormLockCondition = {
550
+ when: string;
551
+ op: string;
552
+ value?: unknown;
553
+ };
554
+
555
+ export declare type FormSchema = {
556
+ collection: string;
557
+ displayName: string | null;
558
+ singleton: boolean;
559
+ draftPublishEnabled: boolean;
560
+ fields: FormFieldDescriptor[];
561
+ groups: FormGroupDescriptor[];
562
+ /** index of the Ungrouped zone among groups (null = after all groups) */
563
+ ungroupedSort: number | null;
564
+ /** 'steps' for step-wizard mode, 'tabs' or null for standard tabs */
565
+ tabMode: 'tabs' | 'steps' | null;
566
+ aiEnabled: boolean;
567
+ summaryEnabled: boolean;
568
+ validateBeforeNext: boolean;
569
+ /** Slot assignments from the active layout (__pipeline__, __comments__, __tasks__) */
570
+ slotAssignments: FormSlotAssignment[];
571
+ };
572
+
573
+ export declare type FormSlotAssignment = {
574
+ slot: string;
575
+ groupKey: string | null;
576
+ sort: number;
577
+ labelOverride: string | null;
578
+ isVisible: boolean;
579
+ defaultExpanded: boolean;
580
+ };
581
+
582
+ export declare type FormStatus = {
583
+ isDirty: boolean;
584
+ isValid: boolean;
585
+ isSubmitting: boolean;
586
+ isLoading: boolean;
587
+ canSubmit: boolean;
588
+ };
589
+
590
+ /** A single validation rule attached to a field. */
591
+ export declare type FormValidationRule = {
592
+ type: string;
593
+ value?: unknown;
594
+ message?: string;
595
+ /** soft = warning only, hard (default) = blocks save */
596
+ soft?: boolean;
597
+ };
598
+
599
+ /** A client-evaluable visibility rule. */
600
+ export declare type FormVisibilityRule = {
601
+ /** key of the field this rule observes */
602
+ when: string;
603
+ /** eq | neq | null | nnull | in | contains */
604
+ op: string;
605
+ value?: unknown;
606
+ action: 'show' | 'hide';
607
+ };
608
+
609
+ export declare function getMentionQuery(text: string, cursorPos: number): string | null;
610
+
611
+ export declare const GridFlushContext: React_2.Context<GridFlushContextValue | null>;
612
+
613
+ declare type GridFlushContextValue = {
614
+ register: (key: string, fn: () => Promise<void>) => void;
615
+ unregister: (key: string) => void;
616
+ };
617
+
618
+ declare interface HeaderWidgetInfo {
619
+ field: string;
620
+ widgetId: number;
621
+ label: string | null;
622
+ inputBindings: InputBinding[];
623
+ }
624
+
625
+ export declare function ImportConsole({ realtime, defaultTab, initialJobId, onJobOpen }: ImportConsoleProps): JSX.Element;
626
+
627
+ export declare interface ImportConsoleProps {
628
+ /**
629
+ * Live `import:progress` events. Hosts own the socket; without an adapter the
630
+ * console still tracks state on its poll, just up to 5s later.
631
+ */
632
+ realtime?: ImportRealtimeAdapter;
633
+ /** Which section to open on. `definitions` is admin-only. */
634
+ defaultTab?: ImportConsoleTab;
635
+ /** Deep link into a collection-import job's detail (admin /imports/:id). */
636
+ initialJobId?: string | null;
637
+ /** Fires when a collection-import job's detail opens or closes, so a host
638
+ * can keep its own URL in step. */
639
+ onJobOpen?: (id: string | null) => void;
640
+ }
641
+
642
+ export declare type ImportConsoleTab = 'runs' | 'collection' | 'definitions';
643
+
644
+ export declare interface ImportDefinition {
645
+ id: number;
646
+ key: string;
647
+ label: string | null;
648
+ description: string | null;
649
+ staging_table: string | null;
650
+ procedure: string | null;
651
+ loader: 'bulk' | 'insert' | null;
652
+ file_types: string | null;
653
+ is_active: boolean;
654
+ sort: number;
655
+ }
656
+
657
+ export declare interface ImportJob {
658
+ id: string;
659
+ collection: string;
660
+ file_name: string;
661
+ column_map: Record<string, string> | null;
662
+ duplicate_strategy: string;
663
+ id_field: string | null;
664
+ status: ImportJobStatus;
665
+ total_rows: number | null;
666
+ processed_rows: number | null;
667
+ created_rows: number | null;
668
+ updated_rows: number | null;
669
+ skipped_rows: number | null;
670
+ error_rows: number | null;
671
+ errors: Array<{
672
+ row: number;
673
+ error: string;
674
+ }> | null;
675
+ created_by: string | null;
676
+ created_at: string;
677
+ started_at: string | null;
678
+ completed_at: string | null;
679
+ }
680
+
681
+ export declare type ImportJobStatus = 'pending' | 'processing' | 'complete' | 'failed';
682
+
683
+ /** Result of `POST /staged-imports/preview` — the worker's own parse, run
684
+ * against the file before anything is queued. */
685
+ export declare interface ImportPreview {
686
+ row_count: number;
687
+ columns: string[];
688
+ rows: Array<Record<string, string>>;
689
+ file_name: string;
690
+ staging_table: string | null;
691
+ staging_columns: string[] | null;
692
+ unknown_columns: string[];
693
+ missing_columns: string[];
694
+ }
695
+
696
+ /** Emitted by the worker on the `import:progress` socket event. */
697
+ export declare interface ImportProgressEvent {
698
+ id: number;
699
+ stage: 'row_count' | 'preparing' | 'importing' | 'completed' | 'error';
700
+ row_count?: number;
701
+ duration?: number;
702
+ error?: string;
703
+ }
704
+
705
+ /**
706
+ * Hosts own the socket (the shared package has no transport of its own — the
707
+ * same contract `QueueWorklist` uses for `collection:update`). Without an
708
+ * adapter the console still stays current on its 5s poll.
709
+ */
710
+ export declare interface ImportRealtimeAdapter {
711
+ subscribe: (onProgress: (event: ImportProgressEvent) => void) => () => void;
712
+ }
713
+
714
+ /** A row of `nivaro_import_queue`, joined with its definition, file and queuer. */
715
+ export declare interface ImportRun {
716
+ id: number;
717
+ definition: number | null;
718
+ import_key: string;
719
+ status: ImportRunStatus;
720
+ sort: number;
721
+ file: string | null;
722
+ row_count: number | null;
723
+ duration: number | null;
724
+ logs: string | null;
725
+ started_at: string | null;
726
+ finished_at: string | null;
727
+ created_by: string | null;
728
+ created_at: string | null;
729
+ updated_at: string | null;
730
+ legacy_id: number | null;
731
+ definition_label: string | null;
732
+ staging_table: string | null;
733
+ procedure: string | null;
734
+ loader: 'bulk' | 'insert' | null;
735
+ definition_active: boolean | null;
736
+ file_name: string | null;
737
+ file_size: string | number | null;
738
+ created_by_first_name: string | null;
739
+ created_by_last_name: string | null;
740
+ created_by_email: string | null;
741
+ }
742
+
743
+ /** Shared types for the Import Console (`/api/staged-imports`). */
744
+ export declare type ImportRunStatus = 'queued' | 'running' | 'completed' | 'error' | 'canceled';
745
+
746
+ /** Live queue depth is never windowed; the rest respects `window_days`. */
747
+ export declare interface ImportStats {
748
+ window_days: number;
749
+ by_status: Partial<Record<ImportRunStatus, number>>;
750
+ total: number;
751
+ /** Unwindowed — distinguishes "nothing has ever run" from "nothing recently". */
752
+ all_time_total: number;
753
+ /** Unwindowed run count per import key — a property of the definition. */
754
+ by_key: Record<string, number>;
755
+ rows_imported: number;
756
+ median_duration: number | null;
757
+ success_rate: number | null;
758
+ runs_today: number;
759
+ active: Array<{
760
+ id: number;
761
+ import_key: string;
762
+ status: 'queued' | 'running';
763
+ started_at: string | null;
764
+ created_at: string | null;
765
+ row_count: number | null;
766
+ }>;
767
+ }
768
+
769
+ declare interface InputBinding {
770
+ key: string;
771
+ binding_type: 'item_field' | 'static' | 'url_param';
772
+ binding_value: string;
773
+ }
774
+
775
+ export declare const ItemEditAuthContext: React_2.Context<ItemEditAuthContextValue>;
776
+
777
+ declare type ItemEditAuthContextValue = {
778
+ isAdmin: boolean;
779
+ userId: string;
780
+ };
781
+
782
+ export declare function ItemEditForm({ collection, itemId: itemIdProp, layoutSlug, onBack, onSaved, onDeleted, showHeader, showItemActions, showRevisions, showClone, showPipeline, showWorkflow, showComments, showTasks, showLockBanner, className, headerClassName, renderField, extraTopContent, extraBottomContent, onHeaderWidgets, initialImportResult, initialValues }: ItemEditFormProps): JSX.Element;
783
+
784
+ export declare interface ItemEditFormProps {
785
+ collection: string;
786
+ itemId?: string;
787
+ layoutSlug?: string;
788
+ onBack?: () => void;
789
+ onSaved?: (id: string) => void;
790
+ onDeleted?: () => void;
791
+ showHeader?: boolean;
792
+ /** Render extension-registered item actions (Push to Fusion etc.) in the
793
+ * header toolbar. Off by default — the admin's ItemEdit page renders its
794
+ * own copy in the page header; headless hosts opt in. */
795
+ showItemActions?: boolean;
796
+ showRevisions?: boolean;
797
+ showClone?: boolean;
798
+ showPipeline?: boolean;
799
+ showWorkflow?: boolean;
800
+ showComments?: boolean;
801
+ showTasks?: boolean;
802
+ showLockBanner?: boolean;
803
+ className?: string;
804
+ headerClassName?: string;
805
+ renderField?: (props: RenderFieldProps) => ReactNode;
806
+ extraTopContent?: ReactNode;
807
+ extraBottomContent?: ReactNode;
808
+ onHeaderWidgets?: (widgets: HeaderWidgetInfo[]) => void;
809
+ /** Consumed once, on mount, when `isNew` — prefills the draft + stages O2M
810
+ * lines from an already-parsed import result (e.g. handed off by a caller
811
+ * that ran the file picker before this form existed). */
812
+ initialImportResult?: ImportParseResponse;
813
+ /** Consumed once, on mount, when `isNew` — seeds the draft with plain field
814
+ * values (deep-link prefill, "create from common values", AI hand-offs).
815
+ * User edits made before the seed applies win over seeded keys. */
816
+ initialValues?: Record<string, unknown>;
817
+ }
818
+
819
+ /** A record the UI wants to link to / open the edit page for. */
820
+ export declare type ItemLinkTarget = {
821
+ collection: string;
822
+ itemId: string;
823
+ /** Grouped-layout slug to pin (queue item_layout etc.); null/absent = default. */
824
+ layoutSlug?: string | null;
825
+ };
826
+
827
+ export declare function ItemLockBanner({ lockHolder, onTakeOver, takingOver, isAdmin }: {
828
+ lockHolder: LockHolder | null;
829
+ onTakeOver: () => void;
830
+ takingOver: boolean;
831
+ isAdmin?: boolean;
832
+ }): JSX.Element | null;
833
+
834
+ /**
835
+ * Full layout-aware form renderer.
836
+ *
837
+ * Renders the form exactly as configured in the Layout tab:
838
+ * - Tab-type groups become clickable tabs (or step wizards when tabMode='steps')
839
+ * - Section-type groups become collapsible sections
840
+ * - Ungrouped fields appear at the position set in the Layout tab
841
+ * - Fields honour their col_span width inside a 12-column grid
842
+ * - Page slots (__pipeline__, __comments__, __tasks__) rendered via slotRenderers
843
+ *
844
+ * Zero CSS shipped — style via className props or data-* attributes.
845
+ */
846
+ export declare function LayoutForm({ form, components, className, style, sectionClassName, tabStripClassName, activeTabClassName, inactiveTabClassName, gridClassName, slotRenderers, itemId, stepperClassName, stepNavClassName, prevButtonClassName, nextButtonClassName, lastStepActions, layoutSlug: _layoutSlug }: LayoutFormProps): default_2.JSX.Element | null;
847
+
848
+ declare type LayoutFormProps = {
849
+ form: UseNivaroFormReturn;
850
+ components?: ComponentOverrides;
851
+ /** CSS class applied to the <form> element */
852
+ className?: string;
853
+ style?: default_2.CSSProperties;
854
+ /** CSS class for a section group wrapper */
855
+ sectionClassName?: string;
856
+ /** CSS class for a tab strip wrapper */
857
+ tabStripClassName?: string;
858
+ /** CSS class for the active tab button */
859
+ activeTabClassName?: string;
860
+ /** CSS class for inactive tab buttons */
861
+ inactiveTabClassName?: string;
862
+ /** CSS class for the 12-col grid row (col_span chips snap to this) */
863
+ gridClassName?: string;
864
+ /**
865
+ * Slot renderers — keyed by slot name (__pipeline__, __comments__, __tasks__).
866
+ * Called with { slot, collection, itemId, labelOverride, defaultExpanded }.
867
+ * If omitted, slots are silently skipped.
868
+ */
869
+ slotRenderers?: Record<string, (props: SlotRendererProps) => default_2.ReactNode>;
870
+ /**
871
+ * itemId of the currently-loaded item — needed for slot renderers.
872
+ * For edit mode: pass the item id. For create mode: leave undefined.
873
+ */
874
+ itemId?: string | number | null;
875
+ /** CSS class for the stepper strip wrapper (steps mode) */
876
+ stepperClassName?: string;
877
+ /** CSS class for the prev/next button bar (steps mode) */
878
+ stepNavClassName?: string;
879
+ /** CSS class for the Prev button */
880
+ prevButtonClassName?: string;
881
+ /** CSS class for the Next/Save button */
882
+ nextButtonClassName?: string;
883
+ /** Extra content rendered before the Save button on the last step (steps mode only) */
884
+ lastStepActions?: default_2.ReactNode;
885
+ /**
886
+ * Layout slug that was used to load this form's schema.
887
+ * Informational only — schema resolution happens in useNivaroForm.
888
+ */
889
+ layoutSlug?: string;
890
+ };
891
+
892
+ export declare type LayoutItem = FormGroupDescriptor | '__ungrouped__';
893
+
894
+ declare interface LockHolder {
895
+ locked_by: string;
896
+ locked_by_name: string | null;
897
+ }
898
+
899
+ /** Match a filter surface (by its own key and/or its options collection) to a
900
+ * scope dimension. Convention: key === dimension name wins, else the filter's
901
+ * options collection === the dimension's target collection. */
902
+ export declare function matchScopeDimension(scopes: UserScopesInfo | null, probe: {
903
+ key?: string;
904
+ collection?: string;
905
+ }): UserScopesInfo['dimensions'][number] | null;
906
+
907
+ declare interface MessageToken {
908
+ text: string;
909
+ entity?: string;
910
+ mention?: string;
911
+ }
912
+
913
+ export declare const NavigationContext: React_2.Context<NavigationContextValue>;
914
+
915
+ declare type NavigationContextValue = {
916
+ /** `options.state` rides along for hosts whose router supports it (e.g. react-router's
917
+ * useNavigate) — hosts that ignore the second argument still navigate correctly. */
918
+ navigate: (path: string, options?: {
919
+ state?: unknown;
920
+ }) => void;
921
+ /** Map item links onto the host app's own routes. Components fall back to
922
+ * the admin shape (/collections/:collection/:id?layout=…) when absent —
923
+ * external embeds supply one function and every open path follows. */
924
+ itemUrl?: (target: ItemLinkTarget) => string;
925
+ /** Full interception of item-opening: return true = handled (components
926
+ * skip navigation entirely — open your own modal/drawer instead). Checked
927
+ * before itemUrl/navigate. */
928
+ openItem?: (target: ItemLinkTarget) => boolean | undefined;
929
+ /** Route for a user's profile page (UserChip "View profile"). Absent = the
930
+ * admin shape `/users/:id`; return null = host has no such page, the
931
+ * action is hidden instead of navigating into the host's 404 fallback. */
932
+ userUrl?: (userId: string) => string | null;
933
+ };
934
+
935
+ /**
936
+ * Selects and renders the correct field component for a single field based on
937
+ * its normalized fieldType. Override any type via `components`; falls back to
938
+ * `components.fallback` or a basic text input for unknown types.
939
+ *
940
+ * Uses React 18's useId() to generate a unique DOM id per field instance so
941
+ * two forms with the same collection mounted simultaneously don't collide.
942
+ */
943
+ export declare function NivaroField({ field, value, onChange, error, disabled, readOnly, components, className, itemId }: NivaroFieldProps): default_2.JSX.Element;
944
+
945
+ declare type NivaroFieldProps = {
946
+ field: FormFieldDescriptor;
947
+ value: unknown;
948
+ onChange: (value: unknown) => void;
949
+ error?: string[];
950
+ disabled?: boolean;
951
+ readOnly?: boolean;
952
+ components?: ComponentOverrides;
953
+ className?: string;
954
+ /** Parent item id — passed through to inline-grid fields */
955
+ itemId?: string | number | null;
956
+ };
957
+
958
+ /**
959
+ * Optional convenience wrapper that renders a <form> driven by useNivaroForm.
960
+ * Provide `children` to fully control layout, or omit them to auto-render every
961
+ * group and its fields via NivaroField.
962
+ */
963
+ export declare function NivaroForm({ form, children, components, renderField, renderGroup, className, style }: NivaroFormProps): default_2.JSX.Element;
964
+
965
+ declare type NivaroFormProps = {
966
+ /** the object returned by useNivaroForm */
967
+ form: UseNivaroFormReturn;
968
+ /** custom render children; if omitted the form auto-renders all fields/groups */
969
+ children?: default_2.ReactNode;
970
+ /** override specific field-type renderers */
971
+ components?: ComponentOverrides;
972
+ /** wrap/replace the rendering of a single field */
973
+ renderField?: (field: FormFieldDescriptor, defaultRender: () => default_2.ReactNode) => default_2.ReactNode;
974
+ /** wrap/replace the rendering of a group + its fields */
975
+ renderGroup?: (group: FormGroupDescriptor | null, fields: default_2.ReactNode) => default_2.ReactNode;
976
+ className?: string;
977
+ style?: default_2.CSSProperties;
978
+ };
979
+
980
+ export declare function NivaroProvider({ client, children }: {
981
+ client: NivaroClient;
982
+ children: React_2.ReactNode;
983
+ }): React_2.JSX.Element;
984
+
985
+ /**
986
+ * Map a raw DB type + CMS interface string to the normalized FormFieldType
987
+ * the renderer uses to choose a component.
988
+ */
989
+ export declare function normalizeFieldType(rawType: string, iface: string | null, relation: FormFieldDescriptor['relation']): FormFieldType;
990
+
991
+ export declare function NumberField({ field, value, onChange, error, disabled, readOnly, inputId, errorId }: FieldComponentProps): JSX.Element;
992
+
993
+ declare interface O2MFieldInfo {
994
+ field: string;
995
+ label: string;
996
+ relatedCollection: string;
997
+ manyField: string;
998
+ parentId: string;
999
+ }
1000
+
1001
+ export declare function openDmWith(userId: string, displayName?: string): void;
1002
+
1003
+ export declare function OwnerAvatars({ owners, max, emptyLabel }: {
1004
+ owners: OwnerLike[];
1005
+ max?: number;
1006
+ emptyLabel?: string;
1007
+ }): JSX.Element;
1008
+
1009
+ declare interface OwnerLike {
1010
+ id: string;
1011
+ name: string;
1012
+ }
1013
+
1014
+ export declare function PageRenderer({ slug, hideHeader, className }: PageRendererProps): JSX.Element;
1015
+
1016
+ export declare interface PageRendererPage {
1017
+ slug: string;
1018
+ name: string;
1019
+ layout?: {
1020
+ columns?: number;
1021
+ widgets?: PageRendererWidget[];
1022
+ } | null;
1023
+ }
1024
+
1025
+ export declare interface PageRendererProps {
1026
+ /** nivaro_pages slug to render. */
1027
+ slug: string;
1028
+ /** Hide the page-name header row (host renders its own chrome). */
1029
+ hideHeader?: boolean;
1030
+ className?: string;
1031
+ }
1032
+
1033
+ export declare interface PageRendererWidget {
1034
+ id: string;
1035
+ type: string;
1036
+ x: number;
1037
+ y: number;
1038
+ w: number;
1039
+ h: number;
1040
+ config?: Record<string, unknown>;
1041
+ }
1042
+
1043
+ declare interface PendingTask {
1044
+ title: string;
1045
+ assignee: string | null;
1046
+ due_date: string;
1047
+ }
1048
+
1049
+ export declare function PipelinePanel({ collection, item, defaultExpanded, title, showApprovalChain, onBeforeTransition, addendumPending }: {
1050
+ collection: string;
1051
+ item: string;
1052
+ defaultExpanded?: boolean;
1053
+ title?: string;
1054
+ showApprovalChain?: boolean;
1055
+ onBeforeTransition?: () => boolean;
1056
+ addendumPending?: boolean;
1057
+ }): JSX.Element | null;
1058
+
1059
+ export declare function PipelineTransitionButtons({ collection, item, onBeforeTransition }: {
1060
+ collection: string;
1061
+ item: string;
1062
+ onBeforeTransition?: () => boolean;
1063
+ }): JSX.Element | null;
1064
+
1065
+ export declare function ProfileView({ userId, className }: {
1066
+ userId?: string | null;
1067
+ className?: string;
1068
+ }): JSX.Element;
1069
+
1070
+ export declare function QueryWidgetBody({ cfg, dateRange, entityFilters, refetchInterval, onStatus, onDrill }: {
1071
+ cfg: ReportQueryWidgetConfig;
1072
+ dateRange: ReportDateRange | null;
1073
+ entityFilters: ReportEntityFilter[];
1074
+ refetchInterval?: number;
1075
+ onStatus?: (s: {
1076
+ isFetching: boolean;
1077
+ refetch: () => void;
1078
+ }) => void;
1079
+ onDrill?: (t: {
1080
+ collection: string;
1081
+ itemId: string;
1082
+ title?: string;
1083
+ }) => void;
1084
+ }): JSX.Element;
1085
+
1086
+ export declare function QueueBulkBar({ count, states, busy, claimsEnabled, onClaim, onRelease, onTransition, onClear }: {
1087
+ count: number;
1088
+ states: Array<{
1089
+ value: string;
1090
+ label: string;
1091
+ }>;
1092
+ busy: boolean;
1093
+ claimsEnabled?: boolean;
1094
+ onClaim: () => void;
1095
+ onRelease: () => void;
1096
+ onTransition: (state: string) => void;
1097
+ onClear: () => void;
1098
+ }): JSX.Element | null;
1099
+
1100
+ declare interface QueueItemRow {
1101
+ collection: string;
1102
+ item_id: string;
1103
+ label: string;
1104
+ state: string | null;
1105
+ state_color: string | null;
1106
+ owners: QueueOwner_2[];
1107
+ sla_status: 'ok' | 'warning' | 'breached' | null;
1108
+ at_risk: boolean;
1109
+ aging_hours: number | null;
1110
+ claimed_by: QueueOwner_2 | null;
1111
+ url: string;
1112
+ }
1113
+
1114
+ export declare function QueueItemSheet({ item, onOpenChange, onClaim, onRelease, workNextActive, onNext, refetchItems, stateLabels, collectionLabel, claimsEnabled, columnFormats, width, itemLayout }: {
1115
+ item: SheetItem | null;
1116
+ onOpenChange: (open: boolean) => void;
1117
+ onClaim: (item: SheetItem) => void;
1118
+ onRelease: (item: SheetItem) => void;
1119
+ workNextActive?: boolean;
1120
+ onNext?: () => void;
1121
+ refetchItems: () => void;
1122
+ /** State key → display label (falls back to the raw key). */
1123
+ stateLabels?: Record<string, string>;
1124
+ /** Collection name → display name. */
1125
+ collectionLabel?: (name: string) => string;
1126
+ /** When false the claim/release button is hidden. */
1127
+ claimsEnabled?: boolean;
1128
+ /** Extra-field path → display format config (display-only). */
1129
+ columnFormats?: Record<string, ColumnFormatConfig>;
1130
+ /** Sidebar width: px number or 'NN%' of viewport; default 480. */
1131
+ width?: number | string | null;
1132
+ /** Layout slug the Open button pins on the full item; null = default. */
1133
+ itemLayout?: string | null;
1134
+ }): JSX.Element;
1135
+
1136
+ export declare function QueueKanbanBoard({ items, onDrop, onCardClick, onClaim, onRelease, swimlaneBy, stateLabels, laneLabel, claimsEnabled }: {
1137
+ items: QueueItemRow[];
1138
+ onDrop: (item: QueueItemRow, targetState: string) => void;
1139
+ onCardClick: (item: QueueItemRow) => void;
1140
+ onClaim: (item: QueueItemRow) => void;
1141
+ onRelease: (item: QueueItemRow) => void;
1142
+ /** Optional horizontal lanes crossed with the state columns. */
1143
+ swimlaneBy?: 'collection' | 'owners' | null;
1144
+ /** State key → display label (falls back to the raw key). */
1145
+ stateLabels?: Record<string, string>;
1146
+ /** Formats lane keys (e.g. collection names → display names). */
1147
+ laneLabel?: (key: string) => string;
1148
+ /** When false the per-card Claim/Release button is hidden. */
1149
+ claimsEnabled?: boolean;
1150
+ }): JSX.Element;
1151
+
1152
+ declare interface QueueOwner {
1153
+ id: string;
1154
+ name: string;
1155
+ }
1156
+
1157
+ declare interface QueueOwner_2 {
1158
+ id: string;
1159
+ name: string;
1160
+ }
1161
+
1162
+ export declare interface QueueRealtimeAdapter {
1163
+ /** Subscribe to update events for these collections; call onUpdate per event; return unsubscribe. */
1164
+ subscribe: (collections: string[], onUpdate: () => void) => () => void;
1165
+ }
1166
+
1167
+ export declare function QueueWorklist({ queueId, realtime, renderError }: QueueWorklistProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | ReactPortal | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | JSX.Element | null;
1168
+
1169
+ export declare interface QueueWorklistProps {
1170
+ queueId: string;
1171
+ realtime?: QueueRealtimeAdapter;
1172
+ renderError?: (status: number) => React.ReactNode;
1173
+ }
1174
+
1175
+ export declare function QueueWorkloadView({ queueId }: {
1176
+ queueId: string;
1177
+ }): JSX.Element;
1178
+
1179
+ declare interface QuickFilterDef {
1180
+ /** Unique key for this filter's selection state. */
1181
+ key: string;
1182
+ label: string;
1183
+ /** Server condition path — supports M2O chains and O2M/M2M alias hops
1184
+ * (e.g. ['funding_years'], ['project', 'project_type']). */
1185
+ path: string[];
1186
+ /** When set, the selection matches if ANY of these paths hits (server _or
1187
+ * group) — e.g. project.project_type OR car_project_type. Overrides path. */
1188
+ or_paths?: string[][];
1189
+ /** Collection the options list loads from. */
1190
+ collection: string;
1191
+ /** Option value column (default 'id'). */
1192
+ value_field?: string;
1193
+ /** Option label column. */
1194
+ label_field: string;
1195
+ sort?: string;
1196
+ }
1197
+
1198
+ export declare function RecordDrilldownSheet({ collection, itemId, layoutId, rootLayoutSlug, width, title, onClose }: {
1199
+ collection: string;
1200
+ itemId: string;
1201
+ layoutId?: number | null;
1202
+ /** Render the ROOT record with this exact layout slug (a queue's configured
1203
+ * grouped item_layout), bypassing detail-layout resolution. Nested drills
1204
+ * still use detail layouts. */
1205
+ rootLayoutSlug?: string | null;
1206
+ /** Panel width per config: px number or 'NN%' of the viewport; default 640. */
1207
+ width?: number | string | null;
1208
+ title?: string;
1209
+ onClose: () => void;
1210
+ }): JSX.Element;
1211
+
1212
+ /** Register the host's DM opener. Returns an unregister function. */
1213
+ export declare function registerDmOpener(fn: DmOpener): () => void;
1214
+
1215
+ /**
1216
+ * Unstyled relation picker.
1217
+ * - m2o: single <select> of related items
1218
+ * - o2m / m2m: multi <select> of related item ids
1219
+ *
1220
+ * Options are fetched from the related collection via useRelationOptions and
1221
+ * labelled with the relation's display template.
1222
+ *
1223
+ * If no NivaroClient is available (neither via NivaroProvider nor passed
1224
+ * directly to the field consumer), a visible error is shown instead of a
1225
+ * silently-empty picker.
1226
+ */
1227
+ export declare function RelationField({ field, value, onChange, error, disabled, readOnly, inputId, errorId }: FieldComponentProps): JSX.Element;
1228
+
1229
+ export declare type RelationOption = {
1230
+ id: string | number;
1231
+ label: string;
1232
+ raw: Record<string, unknown>;
1233
+ };
1234
+
1235
+ declare type RenderFieldProps = {
1236
+ field: any;
1237
+ value: unknown;
1238
+ onChange: (v: unknown) => void;
1239
+ disabled: boolean;
1240
+ collection: string;
1241
+ itemId: string;
1242
+ relations: any[];
1243
+ cascadeFilter?: Record<string, unknown>;
1244
+ unsatisfiedParentLabel?: string | null;
1245
+ requiredParentLabel?: string | null;
1246
+ };
1247
+
1248
+ export declare function ReportView({ reportId, showFilterBar, dateRange, initialEntityFilters, refetchInterval, className, emptyState }: ReportViewProps): JSX.Element;
1249
+
1250
+ /**
1251
+ * ReportView — the full, styled, interactive Report Studio renderer for
1252
+ * headless frontends, matching how QueueWorklist / ItemEditForm ship.
1253
+ *
1254
+ * Fully Tailwind-styled (bring the styles via `@nivaro/react/full.css` or the
1255
+ * Tailwind preset, exactly like the other shared components) and interactive:
1256
+ * a global filter bar (date-range switcher + live entity-filter chips), and
1257
+ * per-widget freshness + one-click refresh. Every widget resolves as the
1258
+ * client identity — collection read permissions apply server-side. Charts use
1259
+ * recharts (bundled into the react package). Read-only: no drag/resize edit
1260
+ * surface (that lives in the admin builder).
1261
+ */
1262
+ export declare interface ReportViewProps {
1263
+ reportId: string;
1264
+ /** Show the global filter bar (date range + entity chips). Default true. */
1265
+ showFilterBar?: boolean;
1266
+ /** Override the report's saved date range at view time. */
1267
+ dateRange?: ReportDateRange | null;
1268
+ /** Initial report-level entity filters. */
1269
+ initialEntityFilters?: ReportEntityFilter[];
1270
+ /** Poll interval (ms) for live refresh; omit for one-shot. */
1271
+ refetchInterval?: number;
1272
+ className?: string;
1273
+ emptyState?: React.ReactNode;
1274
+ }
1275
+
1276
+ export declare function RevisionsPanel({ collection, item, onRollback, triggerClassName, inlineTableFields, open, onOpenChange }: {
1277
+ collection: string;
1278
+ item: string;
1279
+ onRollback?: () => void;
1280
+ triggerClassName?: string;
1281
+ inlineTableFields?: O2MFieldInfo[];
1282
+ /** Controlled mode (no trigger button) — open the sheet programmatically,
1283
+ * e.g. from a row Actions menu. */
1284
+ open?: boolean;
1285
+ onOpenChange?: (open: boolean) => void;
1286
+ }): JSX.Element;
1287
+
1288
+ export declare interface RoomInfo {
1289
+ room: string;
1290
+ label: string;
1291
+ kind: 'global' | 'dm' | 'channel' | 'entity';
1292
+ lastMessage: ChatMessage | null;
1293
+ unread: number;
1294
+ muted: boolean;
1295
+ joined: boolean;
1296
+ channel: ChannelMeta | null;
1297
+ }
1298
+
1299
+ export declare type SectionState = {
1300
+ isCollapsed: (key: string) => boolean;
1301
+ toggle: (key: string) => void;
1302
+ collapseAll: () => void;
1303
+ expandAll: () => void;
1304
+ };
1305
+
1306
+ export declare function SelectField({ field, value, onChange, error, disabled, readOnly, inputId, errorId }: FieldComponentProps): JSX.Element;
1307
+
1308
+ /**
1309
+ * rrweb session recorder for headless frontends.
1310
+ *
1311
+ * Drop `useSessionRecorder({ app: 'customer-portal' })` anywhere inside a
1312
+ * NivaroProvider (or pass a client explicitly) and the app records itself —
1313
+ * ONLY when the Nivaro instance has session recording enabled in Settings,
1314
+ * and ONLY if the host app has `rrweb` installed (optional peer dependency;
1315
+ * without it the hook warns once and no-ops).
1316
+ *
1317
+ * Privacy defaults match the admin recorder: every input masked before
1318
+ * events leave the browser, elements with the `nvr-no-record` class blocked.
1319
+ * Events flush every 10s (or 150 events); the server enforces size caps and
1320
+ * a 7-day retention. Recordings attribute to the authenticated SDK identity
1321
+ * (usually your service token's user) with the `app` label telling replays
1322
+ * apart per frontend.
1323
+ */
1324
+ export declare interface SessionRecorderOptions {
1325
+ /** Label shown in the admin replay list — which frontend this is. */
1326
+ app?: string;
1327
+ /** Explicit client; defaults to the NivaroProvider context client. */
1328
+ client?: NivaroClient;
1329
+ /** Force-disable locally regardless of the instance setting. */
1330
+ disabled?: boolean;
1331
+ }
1332
+
1333
+ declare interface SheetItem {
1334
+ collection: string;
1335
+ item_id: string;
1336
+ label: string;
1337
+ state: string | null;
1338
+ state_color: string | null;
1339
+ owners: QueueOwner[];
1340
+ sla_status: 'ok' | 'warning' | 'breached' | null;
1341
+ at_risk: boolean;
1342
+ aging_hours: number | null;
1343
+ claimed_by: QueueOwner | null;
1344
+ extra?: Record<string, unknown>;
1345
+ url: string;
1346
+ }
1347
+
1348
+ export declare type SlotRendererProps = {
1349
+ slot: string;
1350
+ collection: string;
1351
+ itemId: string | number | null | undefined;
1352
+ labelOverride: string | null;
1353
+ defaultExpanded: boolean;
1354
+ };
1355
+
1356
+ export declare function splitMessageTokens(text: string, entityPattern: string): MessageToken[];
1357
+
1358
+ declare type TabKey = 'catalog' | 'rules' | 'subscriptions' | 'history' | 'widget_alerts' | 'widget_alert_history' | 'anomaly_rules' | 'anomaly_history';
1359
+
1360
+ export declare type TabState = {
1361
+ activeTab: string | null;
1362
+ setActiveTab: (key: string) => void;
1363
+ tabs: FormGroupDescriptor[];
1364
+ hasTabs: boolean;
1365
+ };
1366
+
1367
+ export declare function TaskPanel({ collection, item, title, defaultExpanded, queuedTasks, onQueueTask }: {
1368
+ collection: string;
1369
+ item: string;
1370
+ title?: string;
1371
+ defaultExpanded?: boolean;
1372
+ queuedTasks?: PendingTask[];
1373
+ onQueueTask?: (task: PendingTask) => void;
1374
+ }): JSX.Element | null;
1375
+
1376
+ export declare function TextareaField({ field, value, onChange, error, disabled, readOnly, inputId, errorId }: FieldComponentProps): JSX.Element;
1377
+
1378
+ export declare function TextField({ field, value, onChange, error, disabled, readOnly, inputId, errorId }: FieldComponentProps): JSX.Element;
1379
+
1380
+ /**
1381
+ * Translate scope values (target-collection IDS) into a filter's value space.
1382
+ * When the filter compares ids (valueField 'id'/undefined) this is identity;
1383
+ * otherwise the target collection is fetched once to map id → valueField.
1384
+ */
1385
+ export declare function translateScopeValues(client: {
1386
+ request: (c: unknown) => Promise<unknown>;
1387
+ }, dimension: {
1388
+ target_collection: string;
1389
+ }, ids: Array<string | number>, valueField?: string): Promise<Array<string | number>>;
1390
+
1391
+ export declare function useChatConfig(): ChatConfig;
1392
+
1393
+ export declare function useChatMessages(room: string | null): {
1394
+ messages: NoInfer<ChatMessage[]>;
1395
+ loading: boolean;
1396
+ };
1397
+
1398
+ /**
1399
+ * The sidebar. The server decides WHICH rooms (visibility) and computes unread
1400
+ * in SQL against the watermark; the client only labels them. The old version
1401
+ * pulled the last 500 messages globally and grouped them here, which both
1402
+ * leaked other people's rooms and silently dropped quiet ones once a busy room
1403
+ * filled the window.
1404
+ */
1405
+ export declare function useChatRooms(): {
1406
+ rooms: RoomInfo[];
1407
+ totalUnread: number;
1408
+ loading: boolean;
1409
+ };
1410
+
1411
+ export declare function useDrilldown(): DrilldownContextValue | null;
1412
+
1413
+ export declare function useFieldArray(form: UseNivaroFormReturn, field: string): FieldArrayReturn;
1414
+
1415
+ export declare function useFieldState(form: UseNivaroFormReturn, field: string): FieldState;
1416
+
1417
+ export declare function useFormDirty(form: UseNivaroFormReturn, initialValuesOverride?: Record<string, unknown>): FormDirtyState;
1418
+
1419
+ /**
1420
+ * Fetch + cache a collection's form schema. Caches by client URL + collection +
1421
+ * includeHidden flag so re-mounts and sibling forms share one request.
1422
+ *
1423
+ * NOTE: Pass a stable `client` reference. A new object on every render resets
1424
+ * the cache key and re-fetches. Use `useMemo` or define the client outside the
1425
+ * component tree.
1426
+ */
1427
+ export declare function useFormSchema(client: NivaroClient | null, collection: string, includeHidden?: boolean, layoutId?: number, layoutSlug?: string): {
1428
+ schema: FormSchema | null;
1429
+ loading: boolean;
1430
+ error: Error | null;
1431
+ };
1432
+
1433
+ export declare function useFormStatus(form: UseNivaroFormReturn): FormStatus;
1434
+
1435
+ export declare function useGridFlush(): GridFlushContextValue | null;
1436
+
1437
+ export declare function useItemEditAuth(): ItemEditAuthContextValue;
1438
+
1439
+ export declare function useItemLock(collection: string | undefined, item: string | undefined, enabled: boolean): {
1440
+ lockHolder: LockHolder | null;
1441
+ acquired: boolean;
1442
+ isReadOnly: boolean;
1443
+ takeOver: () => Promise<void>;
1444
+ takingOver: boolean;
1445
+ isAdmin: boolean;
1446
+ };
1447
+
1448
+ /** Resolved item-link helpers honoring the host's itemUrl/openItem overrides. */
1449
+ export declare function useItemNavigation(): {
1450
+ urlFor: (target: ItemLinkTarget) => string;
1451
+ open: (target: ItemLinkTarget) => void;
1452
+ };
1453
+
1454
+ /**
1455
+ * Mark read. The server upserts against UNIQUE(user, room), so the old
1456
+ * select-then-insert dance (and the per-room promise chain that stopped it
1457
+ * 500ing on duplicate key) is gone.
1458
+ */
1459
+ export declare function useMarkRoomRead(): UseMutationResult<unknown, Error, string, unknown>;
1460
+
1461
+ /**
1462
+ * The signed-in user's scope dimensions + default/restricted value sets
1463
+ * (User Scopes feature). Filter surfaces use this to SEED initial selections
1464
+ * from defaults and NARROW visible options to restricted values — narrowing
1465
+ * is curation; the items service enforces restrictions server-side regardless.
1466
+ */
1467
+ export declare function useMyScopes(): {
1468
+ scopes: UserScopesInfo | null;
1469
+ ready: boolean;
1470
+ };
1471
+
1472
+ export declare function useNavigation(): NavigationContextValue;
1473
+
1474
+ export declare function useNivaroClient(): NivaroClient;
1475
+
1476
+ /**
1477
+ * Primary form hook for Nivaro CMS.
1478
+ *
1479
+ * IMPORTANT: Pass a stable `client` reference (defined outside the component
1480
+ * or wrapped in useMemo). A new object on every render triggers schema
1481
+ * re-fetches and item reloads on every render cycle.
1482
+ */
1483
+ export declare function useNivaroForm(collection: string, options: UseNivaroFormOptions, client?: NivaroClient): UseNivaroFormReturn;
1484
+
1485
+ export declare type UseNivaroFormOptions = {
1486
+ mode: 'create' | 'edit';
1487
+ /** required when mode='edit' */
1488
+ itemId?: string | number;
1489
+ defaultValues?: Record<string, unknown>;
1490
+ onSuccess?: (item: Record<string, unknown>) => void;
1491
+ onError?: (error: Error) => void;
1492
+ /** custom synchronous validators; return an error string or null when valid */
1493
+ validate?: Record<string, (value: unknown, values: Record<string, unknown>) => string | null>;
1494
+ /** include hidden fields in the schema (default false) */
1495
+ includeHidden?: boolean;
1496
+ /**
1497
+ * Specific layout id to use for group/field ordering.
1498
+ * When omitted, the collection's active layout is used automatically.
1499
+ */
1500
+ layoutId?: number;
1501
+ /**
1502
+ * Layout slug to resolve a specific named layout variant.
1503
+ * When set, overrides `layoutId` and fetches the layout by its machine name.
1504
+ */
1505
+ layoutSlug?: string;
1506
+ /**
1507
+ * Debounce delay in ms for server-side field-rules evaluation (default 300).
1508
+ * Pass 0 to disable server evaluation entirely.
1509
+ */
1510
+ fieldRulesDebounce?: number;
1511
+ };
1512
+
1513
+ export declare type UseNivaroFormReturn = {
1514
+ schema: FormSchema | null;
1515
+ schemaLoading: boolean;
1516
+ schemaError: Error | null;
1517
+ values: Record<string, unknown>;
1518
+ /** Snapshot of values as last confirmed by the server (or seeded defaults). */
1519
+ initialValues: Record<string, unknown>;
1520
+ errors: FormErrors;
1521
+ isDirty: boolean;
1522
+ isSubmitting: boolean;
1523
+ /** true while loading schema or the item being edited */
1524
+ isLoading: boolean;
1525
+ isVisible: (field: string) => boolean;
1526
+ isLocked: (field: string) => boolean;
1527
+ setValue: (field: string, value: unknown) => void;
1528
+ setValues: (patch: Record<string, unknown>) => void;
1529
+ reset: (values?: Record<string, unknown>) => void;
1530
+ handleSubmit: (e?: default_2.FormEvent) => Promise<void>;
1531
+ fieldsByGroup: Map<string | null, FormFieldDescriptor[]>;
1532
+ visibleGroups: FormGroupDescriptor[];
1533
+ gridFlushersRef: default_2.MutableRefObject<Map<string, () => Promise<void>>>;
1534
+ };
1535
+
1536
+ export declare function useOrderedLayout(form: UseNivaroFormReturn): {
1537
+ items: LayoutItem[];
1538
+ hasTabs: boolean;
1539
+ tabGroups: FormGroupDescriptor[];
1540
+ sectionGroups: FormGroupDescriptor[];
1541
+ ungroupedFields: FormFieldDescriptor[];
1542
+ };
1543
+
1544
+ export declare function usePeerReadAt(room: string | null): string | null;
1545
+
1546
+ export declare function UserChip({ userId, size }: {
1547
+ userId: string;
1548
+ size?: 'default' | 'compact';
1549
+ }): React_2.JSX.Element;
1550
+
1551
+ /**
1552
+ * Fetch selectable options for a relation field's related collection.
1553
+ * Re-fetches when `search` changes. Pass `enabled: false` to skip fetching
1554
+ * (e.g. while the related collection name is still unknown).
1555
+ *
1556
+ * When `enabled` transitions to false, previously-loaded options are retained
1557
+ * so cascading pickers don't flash blank while a parent field is being cleared.
1558
+ */
1559
+ export declare function useRelationOptions(client: NivaroClient | null, relatedCollection: string, options?: {
1560
+ search?: string;
1561
+ limit?: number;
1562
+ displayTemplate?: string | null;
1563
+ enabled?: boolean;
1564
+ filter?: Record<string, unknown>;
1565
+ }): {
1566
+ options: RelationOption[];
1567
+ loading: boolean;
1568
+ error: Error | null;
1569
+ };
1570
+
1571
+ /** Stacked avatar cluster (+N) with a hover/pinnable portal roster whose rows
1572
+ * are UserChips — the single user-display primitive for owners/user lists.
1573
+ * Reused by the item-header Owners chip and the collection browser. */
1574
+ export declare function UserRosterCluster({ users, showSingleName }: {
1575
+ users: Array<{
1576
+ id: string;
1577
+ name: string;
1578
+ }>;
1579
+ showSingleName?: boolean;
1580
+ }): React_2.JSX.Element;
1581
+
1582
+ export declare function useSectionState(form: UseNivaroFormReturn, defaultCollapsed?: string[]): SectionState;
1583
+
1584
+ export declare function useSendChatMessage(room: string): UseMutationResult<void, Error, string | {
1585
+ text: string;
1586
+ mentions?: string[];
1587
+ }, unknown>;
1588
+
1589
+ export declare function useSessionRecorder(options?: SessionRecorderOptions): void;
1590
+
1591
+ export declare function useTabState(form: UseNivaroFormReturn): TabState;
1592
+
1593
+ export declare function useTypingIndicator(room: string | null): {
1594
+ onType: () => void;
1595
+ clearTyping: () => void;
1596
+ typingText: string | null;
1597
+ };
1598
+
1599
+ export declare function useUnreadChirp(totalUnread: number): void;
1600
+
1601
+ export declare function useWatchFields(form: UseNivaroFormReturn, fields: string[]): Record<string, unknown>;
1602
+
1603
+ export declare function WorkflowPanel({ collection, item }: {
1604
+ collection: string;
1605
+ item: string;
1606
+ }): JSX.Element | null;
1607
+
1608
+ export { }