@nivaro/react 0.1.302 → 0.1.303

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/dist/index.d.ts CHANGED
@@ -292,6 +292,46 @@ export declare interface ApiVersionInfo {
292
292
 
293
293
  export declare function applyValidationRule(rule: FormValidationRule_2, value: unknown, label: string, record?: Record<string, unknown>): string | null;
294
294
 
295
+ /**
296
+ * "Fill from a document" — a person drops a statement of work, a quote, a
297
+ * spreadsheet on a NEW record and reviews what the model read out of it
298
+ * before any of it lands in the form. Server contract: POST /ai/extract-record
299
+ * (background=1) answers a proposal id; GET /ai/extract-record/result/:id
300
+ * carries the DocumentProposal (values + confidence + the sentence each came
301
+ * from) once the run lands. This dialog is the review. Nothing is written
302
+ * until Apply, and Apply only stages — the record still needs Create.
303
+ *
304
+ * The run always goes through the background path so the same proposal id
305
+ * serves three doors: this button, a list's "New from document…" (which
306
+ * opens the form on `?autofill=<id>`), and "tell me when it's ready" (the
307
+ * notification opens the same form on the same id).
308
+ */
309
+ declare type AskInput = AskRelationInput | {
310
+ type: 'choices';
311
+ choices: Array<{
312
+ value: string;
313
+ text: string;
314
+ }>;
315
+ } | {
316
+ type: 'boolean';
317
+ } | {
318
+ type: 'number';
319
+ } | {
320
+ type: 'date';
321
+ } | {
322
+ type: 'text';
323
+ };
324
+
325
+ /** What a relation ask in the document-autofill review carries from the
326
+ * field's own picker configuration. */
327
+ declare type AskRelationInput = {
328
+ type: 'relation';
329
+ collection: string;
330
+ template: string | null;
331
+ cascades?: CascadeRule[] | null;
332
+ option_filter?: Record<string, unknown> | null;
333
+ };
334
+
295
335
  declare type AutoAllocateConfig = {
296
336
  /** Button label; defaults to 'Auto allocate'. */
297
337
  label?: string;
@@ -317,6 +357,35 @@ declare type AutoAllocateConfig = {
317
357
  };
318
358
  };
319
359
 
360
+ export declare type AutofillRun = {
361
+ id: string;
362
+ collection: string;
363
+ /** What the person picked, or what the server says once it answers. */
364
+ documentName: string;
365
+ layoutId?: number | null;
366
+ status: AutofillRunStatus;
367
+ proposal: unknown | null;
368
+ error: string | null;
369
+ startedAt: number;
370
+ /** A form is showing this run's dialog right now — the shell chip hides it. */
371
+ presented: boolean;
372
+ };
373
+
374
+ /**
375
+ * The document-autofill runs the app is watching, as small chips in the
376
+ * corner of EVERY page — mount once in the app shell. A reading run shows
377
+ * its progress; a landed one becomes a Review button; a failed one says so.
378
+ * Clicking hands the run to the host, which opens the new-record form on
379
+ * `?autofill=<id>` (the form then shows the run's dialog and this chip
380
+ * steps aside). Portals to <body>: a `fixed` element under an animated page
381
+ * wrapper anchors to the wrapper, not the viewport.
382
+ */
383
+ export declare function AutofillRunsChip({ onOpen }: {
384
+ onOpen: (run: AutofillRun) => void;
385
+ }): ReactPortal | null;
386
+
387
+ declare type AutofillRunStatus = 'reading' | 'ready' | 'failed';
388
+
320
389
  export declare function AutolinkedText({ text, plain }: {
321
390
  text: string;
322
391
  plain?: boolean;
@@ -477,6 +546,30 @@ export declare function captureErrorClip(): Promise<ErrorReplayLink | null>;
477
546
  export { CascadeFilterRule }
478
547
 
479
548
  declare type CascadeRule = {
549
+ parent_field: string;
550
+ /** Column on the picker's target collection — may be a dotted relation path
551
+ * ('regions.region'); the first hop is wrapped in _some when filter_via_many. */
552
+ filter_column: string;
553
+ filter_is_m2m?: boolean;
554
+ /** Dotted filter_column's first hop is a to-many alias (O2M/M2M) — wrap in _some. */
555
+ filter_via_many?: boolean;
556
+ /** Derive the filter value(s) from the parent's value instead of using it
557
+ * directly: {parentValue: filterValue | filterValue[]}. Missing keys fall
558
+ * back to value_map_default, then the raw parent value. Arrays become _in.
559
+ * (e.g. a parent-type hierarchy: tier A → tier B ids, tier B → tier C id, …) */
560
+ value_map?: Record<string, unknown>;
561
+ value_map_default?: unknown;
562
+ clear_on_parent_change?: boolean;
563
+ clear_on_unavailable?: boolean;
564
+ /** Reverse the cascade on PICK: choosing this field resolves filter_column
565
+ * on the picked record and fills parent_field from it (a Region pick fills
566
+ * its Zone). Scalar parents fill only when exactly one value resolves;
567
+ * alias parents stage every resolved link (additive). */
568
+ upstream?: boolean;
569
+ show_all_if_no_parent?: boolean;
570
+ };
571
+
572
+ declare type CascadeRule_2 = {
480
573
  parent_field: string;
481
574
  child_field: string;
482
575
  on_unavailable?: CascadeSwapConfig;
@@ -637,6 +730,8 @@ export declare interface ChatMessage {
637
730
  deleted_at?: string | null;
638
731
  attachments?: string[];
639
732
  reactions?: ChatReaction[];
733
+ /** The admin who was masquerading as the sender when it was sent. */
734
+ masquerade_admin_name?: string | null;
640
735
  }
641
736
 
642
737
  export declare interface ChatOnlineUser {
@@ -1295,6 +1390,9 @@ declare interface DirectoryChannel {
1295
1390
  members: number;
1296
1391
  }
1297
1392
 
1393
+ /** Forget a run: stops watching it (the server run continues on its own). */
1394
+ export declare function dismissAutofillRun(id: string): void;
1395
+
1298
1396
  export declare function DisplayPrefsCard(): JSX.Element;
1299
1397
 
1300
1398
  declare type DmOpener = (userId: string, displayName?: string) => void;
@@ -1312,24 +1410,27 @@ declare type DocumentApplySelection = {
1312
1410
  file_id: string | null;
1313
1411
  summary: string;
1314
1412
  document_name: string;
1413
+ proposal_id: string;
1315
1414
  };
1316
1415
 
1317
- export declare function DocumentAutofillButton({ collection, onApply, className }: {
1416
+ export declare function DocumentAutofillButton({ collection, onApply, className, layoutId, initialProposalId, label, onProposalConsumed }: {
1318
1417
  collection: string;
1319
1418
  onApply: (selection: DocumentApplySelection, proposal: DocumentProposal) => void | Promise<void>;
1320
1419
  className?: string;
1420
+ /** Restrict the proposal to this layout's fields (an addendum layout). */
1421
+ layoutId?: number | null;
1422
+ /** Open straight onto a stored proposal (`?autofill=<id>` from a list or a notification). */
1423
+ initialProposalId?: string | null;
1424
+ label?: string;
1425
+ /** The initial proposal was shown — the host can drop `?autofill=` from the URL. */
1426
+ onProposalConsumed?: () => void;
1321
1427
  }): JSX.Element | null;
1322
1428
 
1323
- /**
1324
- * "Fill from a document" — a person drops a statement of work, a quote, a
1325
- * spreadsheet on a NEW record and reviews what the model read out of it
1326
- * before any of it lands in the form. Server contract: POST /ai/extract-record
1327
- * returns a DocumentProposal (values + confidence + the sentence each came
1328
- * from); this dialog is the review. Nothing is written until Apply, and Apply
1329
- * only stages — the record still needs Create.
1330
- */
1331
1429
  declare type DocumentProposal = {
1430
+ id: string;
1431
+ request_id?: string | null;
1332
1432
  collection: string;
1433
+ layout_id?: number | null;
1333
1434
  summary: string;
1334
1435
  fields: Array<{
1335
1436
  field: string;
@@ -1338,6 +1439,10 @@ declare type DocumentProposal = {
1338
1439
  display: string | null;
1339
1440
  confidence: number;
1340
1441
  source: string | null;
1442
+ derived?: {
1443
+ by: 'field_rule' | 'cross_record_defaults';
1444
+ from: string;
1445
+ } | null;
1341
1446
  }>;
1342
1447
  children: Array<{
1343
1448
  alias: string;
@@ -1363,6 +1468,13 @@ declare type DocumentProposal = {
1363
1468
  field: string;
1364
1469
  label: string;
1365
1470
  reason: string;
1471
+ candidate?: {
1472
+ value: unknown;
1473
+ display: string | null;
1474
+ confidence: number;
1475
+ source: string | null;
1476
+ } | null;
1477
+ input?: AskInput | null;
1366
1478
  }>;
1367
1479
  warnings: string[];
1368
1480
  prefill: {
@@ -1372,6 +1484,8 @@ declare type DocumentProposal = {
1372
1484
  }>>;
1373
1485
  m2m: Record<string, Array<string | number>>;
1374
1486
  file_id: string | null;
1487
+ /** Every stored document, in the order given (the first is `file_id`). */
1488
+ file_ids?: string[];
1375
1489
  attach_alias: string | null;
1376
1490
  };
1377
1491
  document: {
@@ -1380,9 +1494,24 @@ declare type DocumentProposal = {
1380
1494
  pages: number | null;
1381
1495
  truncated: boolean;
1382
1496
  chars: number;
1497
+ /** One entry per document when several were read together. */
1498
+ documents?: Array<{
1499
+ name: string;
1500
+ method: string;
1501
+ pages: number | null;
1502
+ truncated: boolean;
1503
+ chars: number;
1504
+ file_id: string | null;
1505
+ }>;
1383
1506
  };
1384
1507
  model: string;
1385
1508
  rounds: number;
1509
+ latency_ms?: number;
1510
+ condensed?: {
1511
+ chunks: number;
1512
+ excerpt_chars: number;
1513
+ } | null;
1514
+ hints_used?: string[];
1386
1515
  };
1387
1516
 
1388
1517
  /** One dot per partner, worst outcome winning — a red dot must never be
@@ -1643,6 +1772,12 @@ export declare function extractExpressionTokens(src: string): string[];
1643
1772
  /** Extract the slot key from an assignment field name, or null. */
1644
1773
  export declare function extSlotKey(field: string): string | null;
1645
1774
 
1775
+ declare type FetchCfg = {
1776
+ apiBase: string;
1777
+ authHeaders: Record<string, string>;
1778
+ credentials: RequestCredentials;
1779
+ };
1780
+
1646
1781
  declare type Fetcher = () => Promise<ApiVersionInfo | null>;
1647
1782
 
1648
1783
  export declare function fetchSchema(client: NivaroClient, collection: string, includeHidden: boolean, layoutId?: number, layoutSlug?: string): Promise<FormSchema>;
@@ -2087,6 +2222,8 @@ export declare interface GatedClient extends NivaroClient {
2087
2222
  /** The newer API build being served, or null while this tab is current. */
2088
2223
  export declare function getApiUpdate(): ApiVersionInfo | null;
2089
2224
 
2225
+ export declare function getAutofillRuns(): AutofillRun[];
2226
+
2090
2227
  export declare function getFieldInterface(name: string | null | undefined): FieldInterfacePlugin | null;
2091
2228
 
2092
2229
  export declare function getFiscalStartMonth(): number;
@@ -2564,7 +2701,7 @@ export declare function InlineTableField({ relatedCollection, manyField, parentI
2564
2701
  saveMode?: 'immediate' | 'pending';
2565
2702
  showLineNumbers?: boolean;
2566
2703
  enableReorder?: boolean;
2567
- parentCascades?: CascadeRule[];
2704
+ parentCascades?: CascadeRule_2[];
2568
2705
  rowRules?: RowRule[];
2569
2706
  columnPresets?: ColumnPreset[];
2570
2707
  /** Initial view before the user picks one: a preset name or '__all__'. */
@@ -2973,7 +3110,7 @@ export declare type ItemEditAuthContextValue = {
2973
3110
  userId: string;
2974
3111
  };
2975
3112
 
2976
- export declare function ItemEditForm({ collection, itemId: itemIdProp, layoutSlug: layoutSlugProp, initialAddendumViewId, onAddendumViewChange, onBack, onSaved, onDeleted, showHeader, headerExtra, focusField, showItemActions, onDirtyChange, documentTitle, registerSaveHandler, onDuplicate, showRevisions, showClone, showPipeline, showWorkflow, showComments, showTasks, showLockBanner, className, headerClassName, renderField, extraTopContent, extraBottomContent, onHeaderWidgets, initialImportResult, initialValues, initialLinks, initialRows }: ItemEditFormProps): JSX.Element;
3113
+ export declare function ItemEditForm({ collection, itemId: itemIdProp, layoutSlug: layoutSlugProp, initialAddendumViewId, onAddendumViewChange, onBack, onSaved, onDeleted, showHeader, headerExtra, focusField, showItemActions, onDirtyChange, documentTitle, registerSaveHandler, onDuplicate, showRevisions, showClone, showPipeline, showWorkflow, showComments, showTasks, showLockBanner, className, headerClassName, renderField, extraTopContent, extraBottomContent, onHeaderWidgets, autofillProposalId, onAutofillConsumed, initialImportResult, initialValues, initialLinks, initialRows }: ItemEditFormProps): JSX.Element;
2977
3114
 
2978
3115
  export declare interface ItemEditFormProps {
2979
3116
  collection: string;
@@ -3035,6 +3172,11 @@ export declare interface ItemEditFormProps {
3035
3172
  extraTopContent?: ReactNode;
3036
3173
  extraBottomContent?: ReactNode;
3037
3174
  onHeaderWidgets?: (widgets: HeaderWidgetInfo[]) => void;
3175
+ /** Open the new-record form on a stored document proposal (`?autofill=<id>`
3176
+ * from a list's "New from document…" or the ready notification). */
3177
+ autofillProposalId?: string | null;
3178
+ /** The proposal was picked up — the host may drop `?autofill=` from the URL. */
3179
+ onAutofillConsumed?: () => void;
3038
3180
  /** Consumed once, on mount, when `isNew` — prefills the draft + stages O2M
3039
3181
  * lines from an already-parsed import result (e.g. handed off by a caller
3040
3182
  * that ran the file picker before this form existed). */
@@ -3067,6 +3209,8 @@ export declare type ItemLinkTarget = {
3067
3209
  * keyed by staging key). Rides the URL as `?prefill=<base64 JSON>`, the
3068
3210
  * shape both hosts already consume. */
3069
3211
  prefill?: Record<string, unknown> | null;
3212
+ /** Extra query parameters the target page reads (`autofill=<proposal id>`). */
3213
+ query?: Record<string, string> | null;
3070
3214
  };
3071
3215
 
3072
3216
  export declare function ItemLockBanner({ lockHolder, onTakeOver, takingOver, isAdmin, onRequestLock, requesting, queue, myPosition, onJoinQueue, onLeaveQueue, joining }: {
@@ -4412,6 +4556,15 @@ export declare function PipelineTransitionButtons({ collection, item, onBeforeTr
4412
4556
  /** Play the configured notification sound. No-op for 'off'/unknown/unavailable audio. */
4413
4557
  export declare function playNotificationSound(kind: NotificationSound | string | null | undefined): void;
4414
4558
 
4559
+ declare function pollProposal(opts: {
4560
+ fetchResult: () => Promise<ProposalPollAnswer>;
4561
+ onRunning?: (documentName?: string) => void;
4562
+ onDone: (data: any) => void;
4563
+ onError: (message: string) => void;
4564
+ onSettled: () => void;
4565
+ intervalMs?: number;
4566
+ }): () => void;
4567
+
4415
4568
  /**
4416
4569
  * How many decimal places a numeric field wants, from its `precision` option.
4417
4570
  *
@@ -4476,6 +4629,21 @@ export declare function ProfileView({ userId, className, initialTab, extra }: {
4476
4629
  extra?: React.ReactNode;
4477
4630
  }): JSX.Element;
4478
4631
 
4632
+ /**
4633
+ * Polls a running document-autofill proposal until it lands or fails.
4634
+ *
4635
+ * The API answers 202 while the run is still going, 200 with the proposal
4636
+ * once it has landed, and a 4xx/5xx when it failed. `onSettled` fires exactly
4637
+ * once, after `onDone` or `onError` — never on a 202, which only keeps the
4638
+ * loop (and the caller's waiting state) alive. Returns a stop function; after
4639
+ * it is called no callback fires again.
4640
+ */
4641
+ declare type ProposalPollAnswer = {
4642
+ status: number;
4643
+ ok: boolean;
4644
+ json: any;
4645
+ };
4646
+
4479
4647
  export declare function QualityRulesView({ className }: {
4480
4648
  className?: string;
4481
4649
  }): JSX.Element;
@@ -4724,6 +4892,11 @@ declare type QueryWidgetFilter = {
4724
4892
  /** Pre-selected values on load. '$current_year' resolves to the current
4725
4893
  * calendar year (default-year behavior). */
4726
4894
  default_values?: Array<string | number>;
4895
+ /** Query-string key that pre-selects this filter when the page URL carries
4896
+ * it (`?fy=2026`, a comma list for several values, compared on
4897
+ * value_field). Beats default_values and the user-scope seeding; when the
4898
+ * URL lacks it, those apply as before. */
4899
+ url_param?: string;
4727
4900
  };
4728
4901
 
4729
4902
  declare interface QueryWidgetStat {
@@ -5860,6 +6033,20 @@ declare type SpreadPreset = 'even' | 'front' | 'back' | 'shape';
5860
6033
  */
5861
6034
  export declare function startApiVersionWatch(fetchVersion: Fetcher): void;
5862
6035
 
6036
+ /**
6037
+ * Start watching a run (idempotent — a known id is left alone). Polls until
6038
+ * the proposal lands or fails; the run stays in the store until it is
6039
+ * dismissed or its proposal is consumed by a form.
6040
+ */
6041
+ export declare function startAutofillRun(cfg: FetchCfg, run: {
6042
+ id: string;
6043
+ collection: string;
6044
+ documentName?: string;
6045
+ layoutId?: number | null;
6046
+ }, deps?: {
6047
+ poll?: typeof pollProposal;
6048
+ }): AutofillRun;
6049
+
5863
6050
  export declare function startRum(opts?: {
5864
6051
  app?: string;
5865
6052
  routePattern?: (path: string) => string;
@@ -6058,6 +6245,9 @@ export declare function useApiFetchConfig(): {
6058
6245
 
6059
6246
  export declare function useApiUpdate(): ApiVersionInfo | null;
6060
6247
 
6248
+ /** Every run the shell should show or a form may pick up. */
6249
+ export declare function useAutofillRuns(): AutofillRun[];
6250
+
6061
6251
  /** Available actions per collection, for the viewer. */
6062
6252
  export declare function useAvailableBulkActions(collections: string[]): UseQueryResult<NoInfer<Record<string, AvailableBulkAction[]>>, Error>;
6063
6253