@updog/data-editor 0.1.10 → 0.1.11
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/index.d.ts +1792 -1787
- package/index.js +2672 -2444
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -372,37 +372,63 @@ declare var export_default = {
|
|
|
372
372
|
redo: "Redo",
|
|
373
373
|
},
|
|
374
374
|
validation: {
|
|
375
|
-
required: "This field is required",
|
|
376
|
-
invalidNumber: "Invalid number",
|
|
377
|
-
invalidEmail: "Invalid email address",
|
|
378
|
-
invalidDate: "Invalid date",
|
|
379
375
|
endDateBeforeStart: "End date must be after start date",
|
|
376
|
+
invalidDate: "Invalid date",
|
|
377
|
+
invalidEmail: "Invalid email address",
|
|
378
|
+
invalidFormat: "Invalid format",
|
|
379
|
+
invalidNumber: "Invalid number",
|
|
380
|
+
invalidOption: "Invalid option",
|
|
381
|
+
outOfRange: "Out of range",
|
|
382
|
+
required: "This field is required",
|
|
380
383
|
valueMustBeUnique: "Value must be unique",
|
|
381
384
|
},
|
|
382
385
|
license: {
|
|
383
386
|
loading: "Loading data editor",
|
|
384
|
-
|
|
385
|
-
|
|
387
|
+
},
|
|
388
|
+
connecting: {
|
|
389
|
+
label: "Connecting to server…",
|
|
390
|
+
},
|
|
391
|
+
errors: {
|
|
392
|
+
RENDER_ERROR: {
|
|
393
|
+
title: "Something went wrong",
|
|
394
|
+
text: "Please close this window and try again",
|
|
395
|
+
},
|
|
396
|
+
license: {
|
|
397
|
+
invalid: {
|
|
386
398
|
title: "Invalid license",
|
|
387
399
|
text: "Please contact support for assistance.",
|
|
388
400
|
},
|
|
389
|
-
|
|
401
|
+
missing: {
|
|
390
402
|
title: "Missing API key",
|
|
391
403
|
text: "No API key was provided. Please configure a valid API key.",
|
|
392
404
|
},
|
|
393
|
-
|
|
405
|
+
domain_not_allowed: {
|
|
394
406
|
title: "Domain not allowed",
|
|
395
407
|
text: "This domain is not authorized for this license. Please check your domain settings.",
|
|
396
408
|
},
|
|
397
|
-
|
|
409
|
+
subscription_inactive: {
|
|
398
410
|
title: "Subscription inactive",
|
|
399
411
|
text: "Your subscription is no longer active. Please renew to continue.",
|
|
400
412
|
},
|
|
401
413
|
},
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
414
|
+
scale: {
|
|
415
|
+
bootstrap_failed: {
|
|
416
|
+
title: "Couldn't connect to the server",
|
|
417
|
+
text: "The server returned an error. Please refresh the page or contact support.",
|
|
418
|
+
},
|
|
419
|
+
workspace_lost: {
|
|
420
|
+
title: "Connection lost",
|
|
421
|
+
text: "The session ended unexpectedly. Refresh the page to reconnect.",
|
|
422
|
+
},
|
|
423
|
+
unreachable: {
|
|
424
|
+
title: "Server unreachable",
|
|
425
|
+
text: "Check your connection and refresh the page.",
|
|
426
|
+
},
|
|
427
|
+
server_error: {
|
|
428
|
+
title: "Server error",
|
|
429
|
+
text: "The server returned an error. Please refresh the page or contact support.",
|
|
430
|
+
},
|
|
431
|
+
},
|
|
406
432
|
},
|
|
407
433
|
uploader: {
|
|
408
434
|
steps: {
|
|
@@ -519,1100 +545,1702 @@ type ExpandPluralKeys<T> = T extends Record<string, unknown>
|
|
|
519
545
|
type DataEditorTranslations = DeepPartial<ExpandPluralKeys<typeof export_default>>;
|
|
520
546
|
|
|
521
547
|
/**
|
|
522
|
-
*
|
|
523
|
-
* with
|
|
548
|
+
* Base row shape. Each key is a column ID, each value is the cell data.
|
|
549
|
+
* Extend this with your own type via the `<DataEditor<TRow>>` generic for
|
|
550
|
+
* type-safe column access. When the generic is omitted, rows are typed as
|
|
551
|
+
* `Record<string, unknown>`.
|
|
524
552
|
*
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
*
|
|
528
|
-
*
|
|
553
|
+
* @example
|
|
554
|
+
* ```ts
|
|
555
|
+
* type Employee = { id: string; name: string; email: string };
|
|
556
|
+
* <DataEditor<Employee> columns={...} primaryKey="id" />
|
|
557
|
+
* ```
|
|
558
|
+
*/
|
|
559
|
+
type DataEditorRow = Record<string, unknown>;
|
|
560
|
+
/** Sort direction. */
|
|
561
|
+
type SortDirection = "asc" | "desc";
|
|
562
|
+
/** Current sort state. `null` means no active sort. */
|
|
563
|
+
type SortState = {
|
|
564
|
+
columnId: string;
|
|
565
|
+
direction: SortDirection;
|
|
566
|
+
} | null;
|
|
567
|
+
type Filters = {
|
|
568
|
+
search: string;
|
|
569
|
+
matchCase: boolean;
|
|
570
|
+
matchEntireCell: boolean;
|
|
571
|
+
errorMessageFilters: string[];
|
|
572
|
+
showOnlyNewRows: boolean;
|
|
573
|
+
showOnlyEditedRows: boolean;
|
|
574
|
+
showOnlyEmptyCells: boolean;
|
|
575
|
+
/** When true, show only rows flagged for deletion (bin mode). All other filters are bypassed. */
|
|
576
|
+
showOnlyDeletedRows: boolean;
|
|
577
|
+
filterColumns: string[] | null;
|
|
578
|
+
/** Per-column value filters. Key = column ID, value = allowed display-formatted strings. */
|
|
579
|
+
columnValueFilters: Record<string, string[]>;
|
|
580
|
+
/** Per-column numeric range filters. Key = column ID. */
|
|
581
|
+
columnRangeFilters: Record<string, {
|
|
582
|
+
min?: number;
|
|
583
|
+
max?: number;
|
|
584
|
+
}>;
|
|
585
|
+
/** Per-column date range filters. Key = column ID, values are ISO date strings (YYYY-MM-DD). */
|
|
586
|
+
columnDateRangeFilters: Record<string, {
|
|
587
|
+
min?: string;
|
|
588
|
+
max?: string;
|
|
589
|
+
}>;
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* A built-in declarative validator. Mode-symmetric: the SDK ships a TS
|
|
594
|
+
* interpreter, the Updog Scale Go binary ships a Go interpreter, and both
|
|
595
|
+
* agree on pass/fail outcomes per `api/validators.json`.
|
|
596
|
+
*/
|
|
597
|
+
type BuiltInValidator = {
|
|
598
|
+
type: "required";
|
|
599
|
+
message?: string;
|
|
600
|
+
} | {
|
|
601
|
+
type: "regex";
|
|
602
|
+
pattern: string;
|
|
603
|
+
flags?: string;
|
|
604
|
+
message?: string;
|
|
605
|
+
} | {
|
|
606
|
+
type: "oneOf";
|
|
607
|
+
values: string[];
|
|
608
|
+
message?: string;
|
|
609
|
+
} | {
|
|
610
|
+
type: "range";
|
|
611
|
+
min?: number;
|
|
612
|
+
max?: number;
|
|
613
|
+
message?: string;
|
|
614
|
+
} | {
|
|
615
|
+
type: "email";
|
|
616
|
+
message?: string;
|
|
617
|
+
} | {
|
|
618
|
+
type: "date";
|
|
619
|
+
format?: "YYYY-MM-DD" | "DD/MM/YYYY";
|
|
620
|
+
message?: string;
|
|
621
|
+
} | {
|
|
622
|
+
type: "numeric";
|
|
623
|
+
message?: string;
|
|
624
|
+
};
|
|
625
|
+
/**
|
|
626
|
+
* Server-mode-only escape hatch: an expression evaluated by the Go binary
|
|
627
|
+
* via expr-lang. Skipped at runtime in client mode (warned at mount).
|
|
628
|
+
*/
|
|
629
|
+
type ExpressionValidator = {
|
|
630
|
+
type: "expression";
|
|
631
|
+
expr: string;
|
|
632
|
+
message?: string;
|
|
633
|
+
};
|
|
634
|
+
/**
|
|
635
|
+
* Client-mode-only escape hatch: a JS predicate run inline. Dropped (with
|
|
636
|
+
* one warn per column) when the SDK serializes the schema for server mode.
|
|
637
|
+
*/
|
|
638
|
+
type FunctionValidator = {
|
|
639
|
+
type: "function";
|
|
640
|
+
fn: CellValidator;
|
|
641
|
+
};
|
|
642
|
+
/**
|
|
643
|
+
* The validator-rule union accepted by `DataEditorColumn.validators`.
|
|
644
|
+
* - Built-ins and `expression` are declarative objects (cross the wire).
|
|
645
|
+
* - `function` wraps a `CellValidator`; client-mode-only, dropped+warned in server mode.
|
|
529
646
|
*
|
|
530
|
-
*
|
|
531
|
-
*
|
|
532
|
-
|
|
647
|
+
* Named `ValidatorRule` (not `Validator`) so it doesn't clash with the
|
|
648
|
+
* runtime `Validator` class in `core/Validator.ts`.
|
|
649
|
+
*/
|
|
650
|
+
type ValidatorRule = BuiltInValidator | ExpressionValidator | FunctionValidator;
|
|
651
|
+
|
|
652
|
+
/** Severity level for a validation message. */
|
|
653
|
+
type ValidationLevel = "error";
|
|
654
|
+
/**
|
|
655
|
+
* A single validation message attached to a cell.
|
|
656
|
+
* Return this from a `CellValidator` to flag a problem.
|
|
657
|
+
*/
|
|
658
|
+
type ValidationError = {
|
|
659
|
+
level: ValidationLevel;
|
|
660
|
+
/** Human-readable message shown in the cell tooltip. */
|
|
661
|
+
message: string;
|
|
662
|
+
};
|
|
663
|
+
type ValidationResult = ValidationError[] | null;
|
|
664
|
+
/**
|
|
665
|
+
* A function that validates a single cell value.
|
|
666
|
+
* Return a `ValidationError` to flag a problem, or `null` if the value is valid.
|
|
533
667
|
*
|
|
534
|
-
*
|
|
535
|
-
*
|
|
536
|
-
*
|
|
537
|
-
* their generation is stale.
|
|
668
|
+
* A `ValidationError` with `level: "error"` flags the cell in the grid but
|
|
669
|
+
* does not block submission — invalid rows are delivered to `onComplete`
|
|
670
|
+
* alongside valid ones, tagged via the `isValid` flag.
|
|
538
671
|
*
|
|
539
|
-
*
|
|
672
|
+
* To use a `CellValidator` in the `validators` array, wrap it as
|
|
673
|
+
* `{ type: "function", fn: (value, row) => ... }`. For declarative rules,
|
|
674
|
+
* pass a built-in object literal — e.g. `{ type: "required" }`,
|
|
675
|
+
* `{ type: "email" }`. See `ValidatorRule` for the full union.
|
|
676
|
+
*
|
|
677
|
+
* @param value - The current cell value.
|
|
678
|
+
* @param row - The full row, useful for cross-field checks.
|
|
540
679
|
*/
|
|
541
|
-
type
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
priority: T[];
|
|
546
|
-
/** Called for each batch of items (priority batch first, then chunks). */
|
|
547
|
-
onChunk: (items: T[]) => void;
|
|
548
|
-
/** Called after each chunk with (processed so far, total). */
|
|
549
|
-
onProgress: (processed: number, total: number) => void;
|
|
550
|
-
/** Called once when all items have been processed. */
|
|
551
|
-
onComplete: () => void;
|
|
552
|
-
/** Called when processing is cancelled via cancel(). */
|
|
553
|
-
onCancel: () => void;
|
|
680
|
+
type CellValidator = (value: unknown, row: DataEditorRow) => ValidationError | null;
|
|
681
|
+
/** Text input cell. This is the default editor when no `editor` is specified. */
|
|
682
|
+
type TextEditorCell = {
|
|
683
|
+
type: "text";
|
|
554
684
|
};
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
constructor(chunkSize?: number);
|
|
563
|
-
get isRunning(): boolean;
|
|
564
|
-
get chunkSize(): number;
|
|
565
|
-
run(params: ChunkedProcessorCallbacks<T>): void;
|
|
566
|
-
cancel(): void;
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
type RegisterSourceOptions = {
|
|
570
|
-
name: string;
|
|
571
|
-
id?: DataSourceId;
|
|
572
|
-
isDeletable?: boolean;
|
|
573
|
-
isInitialData?: boolean;
|
|
685
|
+
/** Date picker cell. Optionally restrict the selectable date range. */
|
|
686
|
+
type DateEditorCell = {
|
|
687
|
+
type: "date";
|
|
688
|
+
/** Earliest selectable date. */
|
|
689
|
+
minDate?: Date;
|
|
690
|
+
/** Latest selectable date. */
|
|
691
|
+
maxDate?: Date;
|
|
574
692
|
};
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
693
|
+
/** Dropdown select cell. The user picks from a fixed list of options. */
|
|
694
|
+
type SelectEditorCell = {
|
|
695
|
+
type: "select";
|
|
696
|
+
/** The list of options shown in the dropdown. Each string is both the stored value and the display label. */
|
|
697
|
+
options: string[];
|
|
580
698
|
};
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
699
|
+
/** Number input cell with locale-aware formatting. */
|
|
700
|
+
type NumberEditorCell = {
|
|
701
|
+
type: "number";
|
|
702
|
+
/** Maximum number of decimal digits allowed. When omitted, decimals are unrestricted. */
|
|
703
|
+
decimalPlaces?: number;
|
|
704
|
+
/** Character used as the decimal point (e.g. `"."` or `","`). Defaults to the browser locale. */
|
|
705
|
+
decimalSeparator?: string;
|
|
706
|
+
/** Character inserted between groups of three digits (e.g. `","` or `"."`). Defaults to the browser locale. */
|
|
707
|
+
thousandsSeparator?: string;
|
|
708
|
+
/** Extra characters to allow beyond digits, decimal separator, and minus sign (e.g. `"%-"`). When defined, minus is only kept if explicitly included. */
|
|
709
|
+
allowChars?: string;
|
|
590
710
|
};
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
711
|
+
/**
|
|
712
|
+
* Controls how a cell is edited.
|
|
713
|
+
*
|
|
714
|
+
* - `"text"` — plain text input (default).
|
|
715
|
+
* - `"date"` — date picker with optional min/max bounds.
|
|
716
|
+
* - `"select"` — dropdown with a fixed list of options.
|
|
717
|
+
* - `"number"` — number input with locale-aware formatting.
|
|
718
|
+
*/
|
|
719
|
+
type CellEditor = TextEditorCell | DateEditorCell | SelectEditorCell | NumberEditorCell;
|
|
720
|
+
/** Dropdown filter shown in the sidebar Filters panel. */
|
|
721
|
+
type SelectColumnFilter = {
|
|
722
|
+
type: "select";
|
|
723
|
+
/** Label displayed above the filter. */
|
|
724
|
+
label?: string;
|
|
725
|
+
/** Placeholder text when nothing is selected. */
|
|
726
|
+
placeholder?: string;
|
|
727
|
+
/** Fixed list of filter options. When omitted, options are derived from column values. */
|
|
728
|
+
options?: string[];
|
|
729
|
+
/** Allow selecting multiple values at once. */
|
|
730
|
+
multiple?: boolean;
|
|
599
731
|
};
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
getSourceId(rowId: TRowId): DataSourceId;
|
|
606
|
-
setSourceId(rowId: TRowId, sourceId: DataSourceId): void;
|
|
607
|
-
deleteSourceId(rowId: TRowId): void;
|
|
608
|
-
getOverrides(): ReadonlyMap<TRowId, DataSourceId>;
|
|
609
|
-
register(options: RegisterSourceOptions): DataSourceId;
|
|
610
|
-
/**
|
|
611
|
-
* Re-insert a source using a full captured state, preserving
|
|
612
|
-
* isVisible, isLoading, rowCount, etc. Used by SourceLifecycle.restore.
|
|
613
|
-
* If the source already exists, overwrites its state.
|
|
614
|
-
*/
|
|
615
|
-
restoreState(state: DataSourceState): void;
|
|
616
|
-
has(sourceId: DataSourceId): boolean;
|
|
617
|
-
get(sourceId: DataSourceId): DataSourceState | undefined;
|
|
618
|
-
delete(sourceId: DataSourceId): void;
|
|
619
|
-
setLoading(sourceId: DataSourceId, isLoading: boolean): void;
|
|
620
|
-
finalizeAllSources(): void;
|
|
621
|
-
values(): IterableIterator<DataSourceState>;
|
|
622
|
-
getHiddenSourceIds(): Set<DataSourceId>;
|
|
623
|
-
saveMergeSnapshot(sourceId: DataSourceId, rowId: TRowId, existingRow: TRow, previousSourceId: DataSourceId, isNew: boolean, isEdited: boolean): void;
|
|
624
|
-
/**
|
|
625
|
-
* Public so commands can re-install merge entries during undo of a remove.
|
|
626
|
-
*/
|
|
627
|
-
restoreMergeEntry(sourceId: DataSourceId, rowId: TRowId, entry: MergeEntry<TRow>): void;
|
|
628
|
-
/**
|
|
629
|
-
* Pure — computes the full removal plan without mutating any state.
|
|
630
|
-
* Callers run applyRemovalPlan(plan) to commit.
|
|
631
|
-
*/
|
|
632
|
-
planRemoval(sourceId: DataSourceId): ExtendedRemovalPlan<TRow> | null;
|
|
633
|
-
/**
|
|
634
|
-
* Mutates internal state per plan produced by planRemoval.
|
|
635
|
-
*/
|
|
636
|
-
applyRemovalPlan(plan: ExtendedRemovalPlan<TRow>): void;
|
|
637
|
-
clear(): void;
|
|
638
|
-
private getUniqueName;
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
type ServerDataManagerDeps<TRow extends DataEditorRow = DataEditorRow> = {
|
|
642
|
-
clear(): void;
|
|
643
|
-
setLoading(isLoading: boolean): void;
|
|
644
|
-
registerSource(options: RegisterSourceOptions): DataSourceId;
|
|
645
|
-
setSourceLoading(sourceId: DataSourceId, isLoading: boolean): void;
|
|
646
|
-
getLocalRowCount(): number;
|
|
647
|
-
replaceServerRows(sourceId: DataSourceId, rows: ServerRow<TRow>[], offset: number, counts?: ServerQueryCounts): void;
|
|
648
|
-
appendServerRows(rows: ServerRow<TRow>[], counts?: ServerQueryCounts): void;
|
|
649
|
-
prependServerRows(rows: ServerRow<TRow>[], offset: number, counts?: ServerQueryCounts): void;
|
|
650
|
-
applyServerRowMeta(rows: ServerRow<TRow>[], counts?: ServerQueryCounts): void;
|
|
732
|
+
/** Numeric min/max range filter shown in the sidebar Filters panel. */
|
|
733
|
+
type NumberRangeColumnFilter = {
|
|
734
|
+
type: "number-range";
|
|
735
|
+
/** Label displayed above the filter. */
|
|
736
|
+
label?: string;
|
|
651
737
|
};
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
private readonly _pageSize;
|
|
658
|
-
private readonly _maxBufferRows;
|
|
659
|
-
private _filters;
|
|
660
|
-
private _sources;
|
|
661
|
-
private _sort;
|
|
662
|
-
private _filterOptions;
|
|
663
|
-
private _filterOptionsFetched;
|
|
664
|
-
private _abortController;
|
|
665
|
-
private _syncAbort;
|
|
666
|
-
private _lastVisibleStart;
|
|
667
|
-
private _debouncedFetch;
|
|
668
|
-
private readonly _config;
|
|
669
|
-
private readonly _dataStoreRef;
|
|
670
|
-
private readonly _sourceLabel;
|
|
671
|
-
private _onChanged;
|
|
672
|
-
constructor(config: DataEditorServer<TRow>, dataStoreRef: ServerDataManagerDeps<TRow>, sourceLabel: string);
|
|
673
|
-
get offset(): number;
|
|
674
|
-
get totalCount(): number | null;
|
|
675
|
-
get isFetching(): boolean;
|
|
676
|
-
get pageSize(): number;
|
|
677
|
-
get maxBufferRows(): number;
|
|
678
|
-
setOnChanged(callback: () => void): void;
|
|
679
|
-
setOffset(offset: number): void;
|
|
680
|
-
setTotalCount(count: number): void;
|
|
681
|
-
private setFetching;
|
|
682
|
-
getExcess(currentCount: number, newCount: number): number;
|
|
683
|
-
shouldFetch(visibleStart: number, visibleEnd: number, loadedCount: number): FetchDirection | null;
|
|
684
|
-
/**
|
|
685
|
-
* Full reload — abort in-flight, clear store, fetch first page.
|
|
686
|
-
* Called on initial load, search/filter/sort changes, and resetFilters.
|
|
687
|
-
*/
|
|
688
|
-
reload(): void;
|
|
689
|
-
/**
|
|
690
|
-
* Scroll-driven pagination with velocity-based debouncing.
|
|
691
|
-
* Called from CanvasGrid on every scroll event.
|
|
692
|
-
*/
|
|
693
|
-
handleScroll(visibleStart: number, visibleEnd: number): void;
|
|
694
|
-
/**
|
|
695
|
-
* Fetch a single page based on scroll position and current window state.
|
|
696
|
-
*/
|
|
697
|
-
private fetchPage;
|
|
698
|
-
/**
|
|
699
|
-
* Re-query the current viewport and replace row data, metadata, and counts.
|
|
700
|
-
* Called after successful edits and find-and-replace mutations.
|
|
701
|
-
* Each call aborts the previous in-flight sync.
|
|
702
|
-
*/
|
|
703
|
-
syncCurrentView(): void;
|
|
704
|
-
/**
|
|
705
|
-
* Merge filter keys into server filter state and reload.
|
|
706
|
-
* Called by DataStore.setFilters() in server mode and by filter components.
|
|
707
|
-
*/
|
|
708
|
-
setFilters(filters: Partial<Filters>): void;
|
|
709
|
-
/**
|
|
710
|
-
* Set sort state and reload.
|
|
711
|
-
*/
|
|
712
|
-
setSort(sort: SortState): void;
|
|
713
|
-
/**
|
|
714
|
-
* Restrict query to visible sources and reload.
|
|
715
|
-
* Pass `undefined` to include all sources.
|
|
716
|
-
*/
|
|
717
|
-
setSources(sources: string[] | undefined): void;
|
|
718
|
-
/**
|
|
719
|
-
* Clear all filters and sort, then reload.
|
|
720
|
-
*/
|
|
721
|
-
resetFilters(): void;
|
|
722
|
-
/**
|
|
723
|
-
* One-time fetch of filter option dictionaries for sidebar filter controls.
|
|
724
|
-
*/
|
|
725
|
-
fetchFilterOptions(): void;
|
|
726
|
-
getFilterOptions(): FilterOptionsResponse | null;
|
|
727
|
-
get onEdit(): (params: EditParams, options?: ServerCallOptions) => Promise<EditResponse | void>;
|
|
728
|
-
get filters(): Record<string, unknown>;
|
|
729
|
-
get sort(): SortState;
|
|
730
|
-
get sources(): string[] | undefined;
|
|
731
|
-
get onSourceRemove(): ((params: SourceRemoveParams) => Promise<void>) | undefined;
|
|
732
|
-
get onColumnDelete(): ((params: ColumnDeleteParams) => Promise<EditResponse | void>) | undefined;
|
|
733
|
-
get onColumnEdit(): ((params: ColumnEditParams) => Promise<EditResponse | void>) | undefined;
|
|
734
|
-
get hasExport(): boolean;
|
|
735
|
-
private _exportAbortController;
|
|
736
|
-
export(format: DataEditorFormat, allRows: boolean, rtl: boolean): Promise<void>;
|
|
737
|
-
clear(): void;
|
|
738
|
-
destroy(): void;
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
/**
|
|
742
|
-
* A post-resolution selection rectangle in stable coordinate space.
|
|
743
|
-
* Produced by grid-layer resolvers from CellRange[] in grid-index space.
|
|
744
|
-
* Consumed by DataStore operations and server sync.
|
|
745
|
-
*/
|
|
746
|
-
type SelectionRect = {
|
|
747
|
-
readonly fields: readonly string[];
|
|
748
|
-
readonly rowIds: readonly TRowId[];
|
|
738
|
+
/** Date min/max range filter shown in the sidebar Filters panel. */
|
|
739
|
+
type DateRangeColumnFilter = {
|
|
740
|
+
type: "date-range";
|
|
741
|
+
/** Label displayed above the filter. */
|
|
742
|
+
label?: string;
|
|
749
743
|
};
|
|
750
|
-
|
|
751
744
|
/**
|
|
752
|
-
*
|
|
753
|
-
*
|
|
754
|
-
* Converts frontend coordinates (TRowId, column index, grid ranges) into
|
|
755
|
-
* `EditParams` with `Region[]` that the server can interpret.
|
|
745
|
+
* Filter control shown in the sidebar Filters panel for a column.
|
|
756
746
|
*
|
|
757
|
-
*
|
|
758
|
-
*
|
|
747
|
+
* - `"select"` — dropdown to pick one or more values.
|
|
748
|
+
* - `"number-range"` — two inputs for min and max number.
|
|
749
|
+
* - `"date-range"` — two date pickers for start and end date.
|
|
750
|
+
*/
|
|
751
|
+
type ColumnFilter = SelectColumnFilter | NumberRangeColumnFilter | DateRangeColumnFilter;
|
|
752
|
+
/** Lock mode for a column. `"all"` locks for every row; `"default"` locks only default-source rows. */
|
|
753
|
+
type ColumnLockMode = "all" | "default";
|
|
754
|
+
/**
|
|
755
|
+
* Defines a column in the editor grid.
|
|
759
756
|
*
|
|
760
|
-
*
|
|
761
|
-
*
|
|
762
|
-
*
|
|
763
|
-
*
|
|
757
|
+
* @example
|
|
758
|
+
* ```ts
|
|
759
|
+
* const columns: DataEditorColumn[] = [
|
|
760
|
+
* { id: "name", title: "Full Name", size: 200, validators: [{ type: "required", message: "Name is required" }] },
|
|
761
|
+
* { id: "email", title: "Email", size: 250, validators: [{ type: "required", message: "Email is required" }, { type: "email", message: "Invalid email" }], unique: true },
|
|
762
|
+
* { id: "role", title: "Role", editor: { type: "select", options: ["Admin", "Editor", "Viewer"] } },
|
|
763
|
+
* { id: "salary", title: "Salary", validators: [{ type: "numeric", message: "Must be a number" }], formatter: (v) => v ? `$${v}` : "" },
|
|
764
|
+
* ];
|
|
765
|
+
* ```
|
|
764
766
|
*/
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
getFilters: () => Record<string, unknown>;
|
|
771
|
-
getSort: () => SortState;
|
|
772
|
-
getLockedColumns: () => ReadonlyMap<string, ColumnLockMode>;
|
|
773
|
-
};
|
|
774
|
-
declare class ServerEditBuilder<TRow extends DataEditorRow = DataEditorRow> {
|
|
775
|
-
private readonly _deps;
|
|
776
|
-
constructor(deps: ServerEditDeps<TRow>);
|
|
777
|
-
resolveServerRowId(rowId: TRowId): ServerRowId | undefined;
|
|
778
|
-
buildRegion(rowIds: TRowId[], columnIds: string[]): Region;
|
|
767
|
+
type DataEditorColumn = {
|
|
768
|
+
/** Unique column identifier. Must match the keys in your row data. */
|
|
769
|
+
id: string;
|
|
770
|
+
/** Column header text shown to the user. */
|
|
771
|
+
title: string;
|
|
779
772
|
/**
|
|
780
|
-
*
|
|
781
|
-
* -
|
|
782
|
-
* -
|
|
783
|
-
* -
|
|
784
|
-
*
|
|
773
|
+
* One or more validators run on every edit. Accepts:
|
|
774
|
+
* - Built-in object literals: `{ type: "required" | "email" | "regex" | "range" | "oneOf" | "date" | "numeric", ... }`.
|
|
775
|
+
* - `{ type: "expression", expr }` — server-mode only. Warned in client mode.
|
|
776
|
+
* - `{ type: "function", fn }` — client-mode only. Dropped+warned in server mode.
|
|
777
|
+
*
|
|
778
|
+
* See `_specs/VALIDATIONS.md` §4.5 for the per-mode support matrix.
|
|
785
779
|
*/
|
|
786
|
-
|
|
780
|
+
validators?: ValidatorRule[];
|
|
787
781
|
/**
|
|
788
|
-
*
|
|
789
|
-
*
|
|
790
|
-
*
|
|
791
|
-
* - Non-contiguous → one region per contiguous group.
|
|
782
|
+
* When `true`, the editor flags duplicate values in this column as errors.
|
|
783
|
+
* The error message is localized via the `translations` prop
|
|
784
|
+
* (`dataEditor.validation.valueMustBeUnique`).
|
|
792
785
|
*/
|
|
793
|
-
|
|
786
|
+
unique?: boolean;
|
|
794
787
|
/**
|
|
795
|
-
*
|
|
796
|
-
*
|
|
788
|
+
* Column IDs to revalidate when this column changes. Use for cross-field
|
|
789
|
+
* rules like "end date must be after start date".
|
|
797
790
|
*/
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
buildRowRegion(fromRowId: TRowId, toRowId: TRowId): Region;
|
|
802
|
-
cellEdit(rowId: TRowId, field: string, value: unknown): EditParams;
|
|
803
|
-
clear(target: Region[]): EditParams;
|
|
804
|
-
paste(source: Region[], target: Region[], cut?: boolean): EditParams;
|
|
805
|
-
pasteExternal(target: Region[], values: unknown[][]): EditParams;
|
|
806
|
-
fill(source: Region[], target: Region[]): EditParams;
|
|
807
|
-
transform(target: Region[], transform: TransformParams): EditParams;
|
|
808
|
-
deleteRows(rowRanges: [TRowId, TRowId][]): EditParams;
|
|
809
|
-
restoreRows(rowRanges: [TRowId, TRowId][]): EditParams;
|
|
810
|
-
deleteAllRows(): EditParams;
|
|
811
|
-
restoreAllRows(): EditParams;
|
|
812
|
-
insertRow(anchorRowId: TRowId | undefined, position: InsertParams["position"], values: unknown[][], columnIds: string[]): EditParams;
|
|
791
|
+
dependentFields?: string[];
|
|
792
|
+
/** Format the display value without changing stored data. E.g. add `$` prefix. */
|
|
793
|
+
formatter?: (value: string) => string;
|
|
813
794
|
/**
|
|
814
|
-
*
|
|
815
|
-
*
|
|
795
|
+
* Transform a value before it enters the store. Runs when rows are uploaded
|
|
796
|
+
* to the data editor.
|
|
816
797
|
*/
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
* @example
|
|
839
|
-
* ```ts
|
|
840
|
-
* onError={(error) => {
|
|
841
|
-
* Sentry.captureException(error.originalError ?? error, {
|
|
842
|
-
* tags: { code: error.code, source: error.source },
|
|
843
|
-
* });
|
|
844
|
-
* }}
|
|
845
|
-
* ```
|
|
846
|
-
*/
|
|
847
|
-
type UpdogError = {
|
|
848
|
-
/** The error category. */
|
|
849
|
-
code: UpdogErrorCode;
|
|
850
|
-
/** Human-readable description. */
|
|
851
|
-
message: string;
|
|
852
|
-
/** Module or subsystem that raised the error. */
|
|
853
|
-
source: string;
|
|
854
|
-
/** The underlying thrown value, when available. */
|
|
855
|
-
originalError?: unknown;
|
|
798
|
+
transformer?: (value: unknown) => unknown;
|
|
799
|
+
/** How the cell is edited. Defaults to text input. */
|
|
800
|
+
editor?: CellEditor;
|
|
801
|
+
/** Adds a filter control for this column in the sidebar Filters panel. */
|
|
802
|
+
filter?: ColumnFilter;
|
|
803
|
+
/**
|
|
804
|
+
* Whether this column can be pinned to the left (right in RTL) via the
|
|
805
|
+
* header context menu. @default true
|
|
806
|
+
*/
|
|
807
|
+
pinnable?: boolean;
|
|
808
|
+
/** Column width in pixels. @default 150 */
|
|
809
|
+
size?: number;
|
|
810
|
+
/**
|
|
811
|
+
* Controls whether cells in this column are locked. A column locked via
|
|
812
|
+
* configuration cannot be unlocked from the UI.
|
|
813
|
+
* - `true` | `"all"` — locked for every row.
|
|
814
|
+
* - `"default"` — locked only for default-source rows; rows added manually,
|
|
815
|
+
* duplicated, or imported remain editable.
|
|
816
|
+
* - `false` | `undefined` — not locked.
|
|
817
|
+
*/
|
|
818
|
+
locked?: boolean | ColumnLockMode;
|
|
856
819
|
};
|
|
857
820
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
821
|
+
/** Params passed to `findAndReplace.onFind` when the user types a search query. */
|
|
822
|
+
type FindParams = {
|
|
823
|
+
/** The search string. */
|
|
824
|
+
search: string;
|
|
825
|
+
/** When `true`, matching is case-sensitive. */
|
|
826
|
+
matchCase?: boolean;
|
|
827
|
+
/** When `true`, the entire cell value must equal the search string. */
|
|
828
|
+
matchEntireCell?: boolean;
|
|
829
|
+
/** Restrict search to these columns. `null` or omitted = all columns. */
|
|
830
|
+
columnIds?: string[] | null;
|
|
831
|
+
/** Current view filters so the server can scope matches to the active filter set. */
|
|
832
|
+
filters?: QueryFilters;
|
|
833
|
+
/** Current sort state so match ordering follows the visual row order. */
|
|
834
|
+
sort?: SortState;
|
|
835
|
+
};
|
|
836
|
+
/** A single match location returned by the server. */
|
|
837
|
+
type FindMatch = {
|
|
838
|
+
/** Row position in the current filtered+sorted view (for grid scrolling). */
|
|
839
|
+
rowIndex: number;
|
|
840
|
+
/** Column ID where the match occurs. */
|
|
841
|
+
columnId: string;
|
|
842
|
+
/** Character offset within the cell value (for inline highlight). */
|
|
843
|
+
startIndex: number;
|
|
844
|
+
/** 0-based position in the ordered match list (for counter display). */
|
|
845
|
+
matchIndex: number;
|
|
846
|
+
};
|
|
847
|
+
/** Response from `findAndReplace.onFind`. */
|
|
848
|
+
type FindResponse = {
|
|
849
|
+
/** Total number of matches across all rows. */
|
|
850
|
+
totalCount: number;
|
|
851
|
+
/** The first match. Omit when `totalCount` is 0. */
|
|
852
|
+
current?: FindMatch;
|
|
853
|
+
};
|
|
854
|
+
/** Params passed to `findAndReplace.onNavigate` when the user clicks prev/next. */
|
|
855
|
+
type FindNavigateParams = FindParams & {
|
|
856
|
+
/** Navigation direction. */
|
|
857
|
+
direction: "next" | "prev";
|
|
858
|
+
/** Current match position so the server knows where to navigate from. */
|
|
859
|
+
currentMatchIndex: number;
|
|
860
|
+
};
|
|
861
|
+
/** Params passed to `findAndReplace.onReplace`. */
|
|
862
|
+
type ReplaceParams = FindParams & {
|
|
863
|
+
/** The replacement text. */
|
|
864
|
+
replacement: string;
|
|
865
|
+
/** When `true`, replace all matches. When omitted or `false`, replace only `target`. */
|
|
866
|
+
all?: boolean;
|
|
867
|
+
/** The specific match to replace. Required when `all` is not `true`. */
|
|
868
|
+
target?: FindMatch;
|
|
869
|
+
};
|
|
870
|
+
/** Response from `findAndReplace.onReplace`. */
|
|
871
|
+
type ReplaceResponse = {
|
|
872
|
+
/** Remaining match count after replacement. */
|
|
873
|
+
totalCount: number;
|
|
874
|
+
/** Next match to navigate to after replacement. Omit when none left. */
|
|
875
|
+
current?: FindMatch;
|
|
876
|
+
};
|
|
877
|
+
/** Server-side find and replace configuration. */
|
|
878
|
+
type FindAndReplaceConfig = {
|
|
879
|
+
/** Called when the user types a search query. Returns total count and first match. */
|
|
880
|
+
onFind: (params: FindParams) => Promise<FindResponse>;
|
|
881
|
+
/** Called when the user clicks prev/next arrows. Returns the target match. */
|
|
882
|
+
onNavigate: (params: FindNavigateParams) => Promise<FindMatch>;
|
|
883
|
+
/** Called when the user clicks Replace or Replace All. */
|
|
884
|
+
onReplace: (params: ReplaceParams) => Promise<ReplaceResponse>;
|
|
885
|
+
};
|
|
886
|
+
type StoreMode = "client" | "server";
|
|
887
|
+
type ServerRowId = string | number;
|
|
888
|
+
/** Row-level status flags returned by the server. Drive row filters and sidebar counts. */
|
|
889
|
+
type ServerRowStatus = {
|
|
890
|
+
edited?: boolean;
|
|
891
|
+
new?: boolean;
|
|
892
|
+
deleted?: boolean;
|
|
893
|
+
hasErrors?: boolean;
|
|
894
|
+
hasEmptyCells?: boolean;
|
|
895
|
+
};
|
|
896
|
+
/** Server-reported change for a single cell. The current value lives in `fields`. */
|
|
897
|
+
type ServerCellChange = {
|
|
898
|
+
original: unknown;
|
|
899
|
+
};
|
|
900
|
+
/** Server-reported validation error for a single cell. */
|
|
901
|
+
type ServerCellError = {
|
|
902
|
+
message: string;
|
|
903
|
+
code?: number | string;
|
|
904
|
+
};
|
|
905
|
+
/** Per-row metadata returned by the server in server-delegated mode. */
|
|
906
|
+
type ServerRowMeta = {
|
|
907
|
+
/** Row-level status flags — drive row filters and sidebar counts. */
|
|
908
|
+
status?: ServerRowStatus;
|
|
909
|
+
/** Cell-level change tracking. Key = field name. */
|
|
910
|
+
changes?: Record<string, ServerCellChange>;
|
|
911
|
+
/** Cell-level validation errors. Key = field name. */
|
|
912
|
+
errors?: Record<string, ServerCellError[]>;
|
|
913
|
+
};
|
|
914
|
+
/** Per-source row count returned by the server. Drives the Data Sources sidebar. */
|
|
915
|
+
type ServerSourceCount = {
|
|
916
|
+
id: string;
|
|
917
|
+
name: string;
|
|
918
|
+
count: number;
|
|
919
|
+
};
|
|
920
|
+
/** Aggregate row counts returned alongside a query page. Drive sidebar indicators. */
|
|
921
|
+
type ServerQueryCounts = {
|
|
922
|
+
edited?: number;
|
|
923
|
+
new?: number;
|
|
924
|
+
deleted?: number;
|
|
925
|
+
errors?: number;
|
|
926
|
+
emptyCells?: number;
|
|
927
|
+
sources?: ServerSourceCount[];
|
|
928
|
+
};
|
|
929
|
+
type ServerRow<T extends DataEditorRow = DataEditorRow> = {
|
|
930
|
+
id: ServerRowId;
|
|
931
|
+
fields: T;
|
|
932
|
+
meta?: ServerRowMeta;
|
|
933
|
+
};
|
|
934
|
+
type ServerResponse<T> = {
|
|
935
|
+
data: T;
|
|
936
|
+
meta?: Record<string, unknown>;
|
|
937
|
+
};
|
|
938
|
+
type QueryFilters<F = Record<string, unknown>> = Partial<Filters> & F;
|
|
939
|
+
type QueryParams<F = Record<string, unknown>> = {
|
|
940
|
+
filters?: QueryFilters<F>;
|
|
941
|
+
sort?: SortState;
|
|
942
|
+
/** When present, only rows belonging to these source IDs are returned. Omit to include all sources. */
|
|
943
|
+
sources?: string[];
|
|
944
|
+
offset?: number;
|
|
945
|
+
limit: number;
|
|
946
|
+
signal?: AbortSignal;
|
|
947
|
+
};
|
|
948
|
+
type QueryResponse<T extends DataEditorRow = DataEditorRow> = ServerResponse<{
|
|
949
|
+
rows: ServerRow<T>[];
|
|
950
|
+
totalCount: number;
|
|
951
|
+
filteredCount?: number;
|
|
952
|
+
counts?: ServerQueryCounts;
|
|
953
|
+
}>;
|
|
864
954
|
/**
|
|
865
|
-
*
|
|
955
|
+
* Filter options returned by `onFilterOptions` for populating sidebar filter controls in server mode.
|
|
956
|
+
* Keys are column IDs. Only include columns that have a `filter` configured.
|
|
957
|
+
*/
|
|
958
|
+
type FilterOptionsResponse = {
|
|
959
|
+
[columnId: string]: {
|
|
960
|
+
/** Values for `"select"` filters. Raw display strings — no formatter is applied. */
|
|
961
|
+
options?: string[];
|
|
962
|
+
/** Bounds for `"number-range"` filters. */
|
|
963
|
+
range?: {
|
|
964
|
+
min: number;
|
|
965
|
+
max: number;
|
|
966
|
+
};
|
|
967
|
+
/** Bounds for `"date-range"` filters. Values are ISO date strings (YYYY-MM-DD). */
|
|
968
|
+
dateRange?: {
|
|
969
|
+
min: string;
|
|
970
|
+
max: string;
|
|
971
|
+
};
|
|
972
|
+
};
|
|
973
|
+
};
|
|
974
|
+
type ServerCallOptions = {
|
|
975
|
+
signal: AbortSignal;
|
|
976
|
+
};
|
|
977
|
+
/**
|
|
978
|
+
* Coordinate rectangle within the server's data view.
|
|
979
|
+
* Uses ServerRowId (primary key) for rows and column ID strings for columns.
|
|
866
980
|
*
|
|
867
|
-
*
|
|
868
|
-
*
|
|
869
|
-
*
|
|
870
|
-
*
|
|
981
|
+
* Convention:
|
|
982
|
+
* - Both row fields omitted → all rows.
|
|
983
|
+
* - Both column fields omitted → all columns.
|
|
984
|
+
* - Single row: `fromRow` AND `toRow` both set, `toRow === fromRow`.
|
|
985
|
+
* - Single column: `fromColumn` AND `toColumn` both set, `toColumn === fromColumn`.
|
|
986
|
+
* - Range: both `from` and `to` set, `to !== from`.
|
|
987
|
+
* - `allSelected: true` → all rows and all columns.
|
|
988
|
+
* - Empty `{}` → used only for insert operations.
|
|
871
989
|
*
|
|
872
|
-
*
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
990
|
+
* INVALID: `from` present without `to`, or vice versa.
|
|
991
|
+
*/
|
|
992
|
+
type Region = {
|
|
993
|
+
fromRow?: ServerRowId;
|
|
994
|
+
toRow?: ServerRowId;
|
|
995
|
+
fromColumn?: string;
|
|
996
|
+
toColumn?: string;
|
|
997
|
+
allSelected?: boolean;
|
|
998
|
+
};
|
|
999
|
+
/** Describes where and how to insert a new row. */
|
|
1000
|
+
type InsertParams = {
|
|
1001
|
+
/** Existing row to anchor the insert relative to. Omitted when appending to the end. */
|
|
1002
|
+
anchorRow?: ServerRowId;
|
|
1003
|
+
/** Insert before or after the anchor row. */
|
|
1004
|
+
position: "above" | "below";
|
|
1005
|
+
/** Column IDs matching the order of `values` entries. */
|
|
1006
|
+
columns: string[];
|
|
1007
|
+
};
|
|
1008
|
+
/**
|
|
1009
|
+
* Unified edit params for all data mutations in server-delegated mode.
|
|
878
1010
|
*
|
|
879
|
-
*
|
|
880
|
-
*
|
|
881
|
-
*
|
|
882
|
-
*
|
|
1011
|
+
* The combination of fields determines the operation:
|
|
1012
|
+
* - `target` + `values` → cell edit, clear, or external paste
|
|
1013
|
+
* - `target` + `source` → internal paste (+ `cut` for cut-paste)
|
|
1014
|
+
* - `target` + `source` (fill) → fill handle
|
|
1015
|
+
* - `target` + `transform` → transform / revert
|
|
1016
|
+
* - `target` + `delete: true` → mark rows for deletion
|
|
1017
|
+
* - `target` + `delete: false` → restore rows (unmark deletion)
|
|
1018
|
+
* - `insert` + `values` → create a new row
|
|
883
1019
|
*
|
|
884
|
-
*
|
|
885
|
-
*
|
|
1020
|
+
* `values` is always a 2D array. For a single cell edit: `[["newValue"]]`.
|
|
1021
|
+
* For clearing: `[[""]]`. The server interprets dimensions relative to `target`:
|
|
1022
|
+
* a 1×1 `values` applied to a multi-cell target means "fill all cells with this value".
|
|
1023
|
+
*
|
|
1024
|
+
* `filters` and `sort` provide the view context so the server can resolve
|
|
1025
|
+
* which rows fall between `fromRow` and `toRow` in the current view.
|
|
1026
|
+
* Omitted for single-cell edits where `fromRow` is a direct row ID.
|
|
886
1027
|
*/
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
markNew(id: TRowId): void;
|
|
903
|
-
markEdited(id: TRowId): void;
|
|
904
|
-
snapshotOriginal(id: TRowId, row: TRow): void;
|
|
905
|
-
classifyOnFirstEdit(id: TRowId, row: TRow): void;
|
|
906
|
-
checkRevert(id: TRowId, currentRow: TRow): {
|
|
907
|
-
wasNew: boolean;
|
|
908
|
-
wasEdited: boolean;
|
|
909
|
-
};
|
|
910
|
-
removeTracking(id: TRowId): void;
|
|
911
|
-
getNewRowIds(): ReadonlySet<TRowId>;
|
|
912
|
-
getEditedRowIds(): ReadonlySet<TRowId>;
|
|
913
|
-
getMergeSnapshot(id: TRowId): {
|
|
914
|
-
isNew: boolean;
|
|
915
|
-
isEdited: boolean;
|
|
916
|
-
};
|
|
917
|
-
restoreMergeClassification(id: TRowId, isNew: boolean, isEdited: boolean): void;
|
|
918
|
-
clear(): void;
|
|
1028
|
+
type EditParams = {
|
|
1029
|
+
target: Region[];
|
|
1030
|
+
source?: Region[];
|
|
1031
|
+
values?: unknown[][];
|
|
1032
|
+
transform?: TransformParams;
|
|
1033
|
+
cut?: boolean;
|
|
1034
|
+
delete?: boolean;
|
|
1035
|
+
insert?: InsertParams;
|
|
1036
|
+
undo?: boolean;
|
|
1037
|
+
filters?: QueryFilters;
|
|
1038
|
+
sort?: SortState;
|
|
1039
|
+
lockedColumns?: Array<{
|
|
1040
|
+
columnId: string;
|
|
1041
|
+
mode: "all" | "default";
|
|
1042
|
+
}>;
|
|
919
1043
|
};
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1044
|
+
type ExportParams$1<F = Record<string, unknown>> = {
|
|
1045
|
+
format: "csv" | "tsv" | "xlsx" | "json" | "xml";
|
|
1046
|
+
allRows: boolean;
|
|
1047
|
+
rtl?: boolean;
|
|
1048
|
+
filters?: QueryFilters<F>;
|
|
1049
|
+
sort?: SortState;
|
|
1050
|
+
signal?: AbortSignal;
|
|
1051
|
+
};
|
|
1052
|
+
/** Transform operation descriptor. `type` identifies the operation, optional fields carry parameters. */
|
|
1053
|
+
type TransformParams = {
|
|
1054
|
+
type: string;
|
|
1055
|
+
separator?: string;
|
|
1056
|
+
/** When `true`, the server should delete the dynamic source columns after applying the transform. */
|
|
1057
|
+
deleteSource?: boolean;
|
|
1058
|
+
};
|
|
1059
|
+
/** Params passed to `onColumnDelete` when the user deletes a dynamic column. */
|
|
1060
|
+
type ColumnDeleteParams = {
|
|
1061
|
+
/** ID of the dynamic column to delete. */
|
|
1062
|
+
columnId: string;
|
|
1063
|
+
/** `true` when the server should reverse this operation (undo). Omitted on initial call and redo. */
|
|
1064
|
+
undo?: boolean;
|
|
1065
|
+
};
|
|
1066
|
+
/** Params passed to `onColumnEdit` when the user renames a dynamic column. */
|
|
1067
|
+
type ColumnEditParams = {
|
|
1068
|
+
/** ID of the dynamic column being edited. */
|
|
1069
|
+
columnId: string;
|
|
1070
|
+
/** New title for the column. */
|
|
1071
|
+
title: string;
|
|
1072
|
+
/** `true` when the server should reverse this operation (undo). Omitted on initial call and redo. */
|
|
1073
|
+
undo?: boolean;
|
|
1074
|
+
};
|
|
1075
|
+
/** Server's response after applying a mutation. */
|
|
1076
|
+
type EditResponse = {
|
|
1077
|
+
counts?: ServerQueryCounts;
|
|
1078
|
+
/** Business-logic rejection. SDK reverts the optimistic update and shows `reason` in a toast. */
|
|
1079
|
+
rejected?: boolean;
|
|
1080
|
+
/** Why the server rejected. Shown to the user as-is. */
|
|
1081
|
+
reason?: string;
|
|
1082
|
+
/** The full row created by the server. Returned for insert operations. */
|
|
1083
|
+
row?: ServerRow;
|
|
1084
|
+
/** Updated column list. When present, the SDK replaces its columns with this list. */
|
|
1085
|
+
columns?: Array<{
|
|
1086
|
+
id: string;
|
|
1087
|
+
title: string;
|
|
1088
|
+
}>;
|
|
1089
|
+
};
|
|
1090
|
+
/**
|
|
1091
|
+
* Every decision the user made during the import wizard, packed into one object.
|
|
1092
|
+
* You get the raw file and the full mapping config. Parse it however you want —
|
|
1093
|
+
* stream it, bulk-load it, hand it to a background job. Your call.
|
|
1094
|
+
*/
|
|
1095
|
+
type ImportMappings = {
|
|
1096
|
+
/** CSV header → column ID. Headers the user left unmatched are `undefined`. */
|
|
1097
|
+
columnMapping: Record<string, string | undefined>;
|
|
1098
|
+
/**
|
|
1099
|
+
* Value substitutions for select columns.
|
|
1100
|
+
* Outer key = column ID, inner key = imported value, inner value = target option.
|
|
1101
|
+
* Only present when at least one select column was matched.
|
|
1102
|
+
*/
|
|
1103
|
+
valueMapping: Record<string, Record<string, string | undefined>>;
|
|
1104
|
+
/** Column ID used to match imported rows against existing data. Same value as `DataEditorProps.primaryKey`. */
|
|
1105
|
+
primaryKey: string;
|
|
1106
|
+
/** Sheet name the user selected. Only present for multi-sheet XLSX files. */
|
|
1107
|
+
selectedSheet?: string;
|
|
1108
|
+
/** Zero-based index of the row the SDK detected as the header row. */
|
|
1109
|
+
headerRowIndex: number;
|
|
1110
|
+
/** Number format detected from the file contents. Affects how `"1.234,56"` vs `"1,234.56"` is read. */
|
|
1111
|
+
numberFormat: "EU" | "US";
|
|
1112
|
+
/**
|
|
1113
|
+
* Per-column date disambiguation. Key = CSV header (not column ID).
|
|
1114
|
+
* `"EU"` = day-first, `"US"` = month-first.
|
|
1115
|
+
* Only includes columns where the format was ambiguous and had to be resolved.
|
|
1116
|
+
*/
|
|
1117
|
+
dateFormats: Record<string, "EU" | "US">;
|
|
1118
|
+
/**
|
|
1119
|
+
* Columns the user created during import for unmatched headers.
|
|
1120
|
+
* These don't exist in your schema yet — you decide whether to persist them.
|
|
1121
|
+
*/
|
|
1122
|
+
newColumns: DataEditorColumn[];
|
|
1123
|
+
};
|
|
1124
|
+
/** Params passed to `onFileImport`. The original file, unchanged, plus everything the wizard collected. */
|
|
1125
|
+
type FileImportParams = {
|
|
1126
|
+
/** The original file. Same bytes the user dropped into the browser. */
|
|
1127
|
+
file: File;
|
|
1128
|
+
/** All mapping decisions from the import wizard. */
|
|
1129
|
+
mappings: ImportMappings;
|
|
1130
|
+
/** Display name for this import source. Typically the file name. */
|
|
1131
|
+
sourceName: string;
|
|
1132
|
+
/** Fires when the user cancels the import. */
|
|
1133
|
+
signal?: AbortSignal;
|
|
1134
|
+
};
|
|
1135
|
+
/**
|
|
1136
|
+
* Params passed to `onRowsImport` once per chunk.
|
|
1137
|
+
* The SDK already parsed the file, applied column mappings, normalized dates
|
|
1138
|
+
* and numbers, and resolved value mappings. You get clean, schema-conformant rows.
|
|
1139
|
+
*/
|
|
1140
|
+
type RowsImportParams = {
|
|
1141
|
+
/** Stable ID for this import session. Use it for idempotency or correlation. */
|
|
1142
|
+
importId: string;
|
|
1143
|
+
/** Display name for this import source. Typically the file name. */
|
|
1144
|
+
sourceName: string;
|
|
1145
|
+
/** Zero-based chunk index. Together with `importId`, uniquely identifies each chunk. */
|
|
1146
|
+
chunkIndex: number;
|
|
1147
|
+
/** `true` on the last chunk. Safe to finalize, run post-import hooks, or trigger validation. */
|
|
1148
|
+
isLastChunk: boolean;
|
|
1149
|
+
/** Transformed rows, keyed by column ID. Ready to store. */
|
|
1150
|
+
rows: Record<string, unknown>[];
|
|
1151
|
+
/** Columns the user created during import. Only present on the first chunk (`chunkIndex === 0`). */
|
|
1152
|
+
newColumns?: DataEditorColumn[];
|
|
1153
|
+
/** Column ID used to match imported rows against existing data. */
|
|
1154
|
+
primaryKey: string;
|
|
1155
|
+
/** Fires when the user cancels mid-import. Clean up any partial state. */
|
|
1156
|
+
signal?: AbortSignal;
|
|
1157
|
+
};
|
|
1158
|
+
/** Your response after processing a chunk. */
|
|
1159
|
+
type RowsImportResponse = {
|
|
1160
|
+
/** How many rows you accepted from this chunk. Drives progress reporting. */
|
|
1161
|
+
accepted: number;
|
|
1162
|
+
/** Per-row errors. `rowIndex` is relative to the chunk (0-based). Surfaced in the UI after import. */
|
|
1163
|
+
errors?: Array<{
|
|
1164
|
+
rowIndex: number;
|
|
1165
|
+
message: string;
|
|
1166
|
+
}>;
|
|
1167
|
+
};
|
|
1168
|
+
/** Params passed to `onSourceRemove` when the user deletes a data source. */
|
|
1169
|
+
type SourceRemoveParams = {
|
|
1170
|
+
/** The source ID to remove. Matches the `id` from `ServerQueryCounts.sources`. */
|
|
1171
|
+
sourceId: string;
|
|
1172
|
+
/** Fires when the user cancels. */
|
|
1173
|
+
signal?: AbortSignal;
|
|
975
1174
|
};
|
|
976
1175
|
|
|
977
1176
|
/**
|
|
978
|
-
*
|
|
1177
|
+
* ChunkedProcessor — Generic utility for processing items in prioritized chunks
|
|
1178
|
+
* with cancellation support via generation counter.
|
|
979
1179
|
*
|
|
980
|
-
*
|
|
981
|
-
*
|
|
982
|
-
*
|
|
1180
|
+
* Used to break O(N) synchronous operations into non-blocking background work:
|
|
1181
|
+
* 1. Priority items are processed synchronously first (e.g. viewport rows)
|
|
1182
|
+
* 2. Remaining items are processed in chunks via MessageChannel
|
|
1183
|
+
* 3. Between chunks the browser can paint frames and handle events
|
|
983
1184
|
*
|
|
984
|
-
*
|
|
985
|
-
*
|
|
986
|
-
*
|
|
1185
|
+
* Uses MessageChannel instead of setTimeout(0) to avoid the browser's ~4ms
|
|
1186
|
+
* minimum delay imposed on nested setTimeouts, reducing scheduling overhead
|
|
1187
|
+
* from ~6ms/chunk to ~1ms/chunk.
|
|
987
1188
|
*
|
|
988
|
-
*
|
|
989
|
-
*
|
|
1189
|
+
* Cancellation uses the same generation counter pattern as FilterEngine:
|
|
1190
|
+
* calling cancel() or run() again increments the generation, and any
|
|
1191
|
+
* in-flight MessageChannel callbacks silently exit when they detect
|
|
1192
|
+
* their generation is stale.
|
|
990
1193
|
*
|
|
991
|
-
*
|
|
992
|
-
* Using a plain array indexed by ID eliminates Map hash table overhead
|
|
993
|
-
* (~10MB saved at 1M rows). Deleted slots are set to undefined (not delete)
|
|
994
|
-
* to keep V8 in HOLEY_ELEMENTS mode.
|
|
1194
|
+
* This class has zero domain knowledge — it works with any item type.
|
|
995
1195
|
*/
|
|
1196
|
+
type ChunkedProcessorCallbacks<T> = {
|
|
1197
|
+
/** All items to process (excluding priority items). */
|
|
1198
|
+
all: T[];
|
|
1199
|
+
/** Items processed synchronously before any chunking begins. */
|
|
1200
|
+
priority: T[];
|
|
1201
|
+
/** Called for each batch of items (priority batch first, then chunks). */
|
|
1202
|
+
onChunk: (items: T[]) => void;
|
|
1203
|
+
/** Called after each chunk with (processed so far, total). */
|
|
1204
|
+
onProgress: (processed: number, total: number) => void;
|
|
1205
|
+
/** Called once when all items have been processed. */
|
|
1206
|
+
onComplete: () => void;
|
|
1207
|
+
/** Called when processing is cancelled via cancel(). */
|
|
1208
|
+
onCancel: () => void;
|
|
1209
|
+
};
|
|
1210
|
+
declare class ChunkedProcessor<T> {
|
|
1211
|
+
private _generation;
|
|
1212
|
+
private _isRunning;
|
|
1213
|
+
private _chunkSize;
|
|
1214
|
+
private _activeOnCancel;
|
|
1215
|
+
private _channel;
|
|
1216
|
+
private _pendingChunkFn;
|
|
1217
|
+
constructor(chunkSize?: number);
|
|
1218
|
+
get isRunning(): boolean;
|
|
1219
|
+
get chunkSize(): number;
|
|
1220
|
+
run(params: ChunkedProcessorCallbacks<T>): void;
|
|
1221
|
+
cancel(): void;
|
|
1222
|
+
}
|
|
996
1223
|
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1224
|
+
type RegisterSourceOptions = {
|
|
1225
|
+
name: string;
|
|
1226
|
+
id?: DataSourceId;
|
|
1227
|
+
isDeletable?: boolean;
|
|
1228
|
+
isInitialData?: boolean;
|
|
1229
|
+
};
|
|
1230
|
+
type MergeEntry<TRow> = {
|
|
1231
|
+
row: TRow;
|
|
1232
|
+
sourceId: DataSourceId;
|
|
1233
|
+
isNew: boolean;
|
|
1234
|
+
isEdited: boolean;
|
|
1235
|
+
};
|
|
1236
|
+
type RemovalPlan<TRow> = {
|
|
1237
|
+
rowsToDelete: Set<TRowId>;
|
|
1238
|
+
rowsToRestore: Array<{
|
|
1239
|
+
rowId: TRowId;
|
|
1240
|
+
row: TRow;
|
|
1241
|
+
originalSourceId: DataSourceId;
|
|
1242
|
+
isNew: boolean;
|
|
1243
|
+
isEdited: boolean;
|
|
1244
|
+
}>;
|
|
1245
|
+
};
|
|
1246
|
+
type ExtendedRemovalPlan<TRow> = RemovalPlan<TRow> & {
|
|
1247
|
+
sourceId: DataSourceId;
|
|
1248
|
+
repairedEntries: Array<{
|
|
1249
|
+
sourceId: DataSourceId;
|
|
1250
|
+
rowId: TRowId;
|
|
1251
|
+
before: MergeEntry<TRow>;
|
|
1252
|
+
after: MergeEntry<TRow> | null;
|
|
1253
|
+
}>;
|
|
1254
|
+
};
|
|
1255
|
+
declare class SourceManager<TRow extends DataEditorRow = DataEditorRow> {
|
|
1256
|
+
private readonly _defaultSourceId;
|
|
1257
|
+
private readonly overrides;
|
|
1258
|
+
private readonly sources;
|
|
1259
|
+
private readonly mergedRows;
|
|
1260
|
+
getSourceId(rowId: TRowId): DataSourceId;
|
|
1261
|
+
setSourceId(rowId: TRowId, sourceId: DataSourceId): void;
|
|
1262
|
+
deleteSourceId(rowId: TRowId): void;
|
|
1263
|
+
getOverrides(): ReadonlyMap<TRowId, DataSourceId>;
|
|
1264
|
+
register(options: RegisterSourceOptions): DataSourceId;
|
|
1265
|
+
/**
|
|
1266
|
+
* Re-insert a source using a full captured state, preserving
|
|
1267
|
+
* isVisible, isLoading, rowCount, etc. Used by SourceLifecycle.restore.
|
|
1268
|
+
* If the source already exists, overwrites its state.
|
|
1269
|
+
*/
|
|
1270
|
+
restoreState(state: DataSourceState): void;
|
|
1271
|
+
has(sourceId: DataSourceId): boolean;
|
|
1272
|
+
get(sourceId: DataSourceId): DataSourceState | undefined;
|
|
1273
|
+
delete(sourceId: DataSourceId): void;
|
|
1274
|
+
setLoading(sourceId: DataSourceId, isLoading: boolean): void;
|
|
1275
|
+
finalizeAllSources(): void;
|
|
1276
|
+
values(): IterableIterator<DataSourceState>;
|
|
1277
|
+
getHiddenSourceIds(): Set<DataSourceId>;
|
|
1278
|
+
saveMergeSnapshot(sourceId: DataSourceId, rowId: TRowId, existingRow: TRow, previousSourceId: DataSourceId, isNew: boolean, isEdited: boolean): void;
|
|
1279
|
+
/**
|
|
1280
|
+
* Public so commands can re-install merge entries during undo of a remove.
|
|
1281
|
+
*/
|
|
1282
|
+
restoreMergeEntry(sourceId: DataSourceId, rowId: TRowId, entry: MergeEntry<TRow>): void;
|
|
1283
|
+
/**
|
|
1284
|
+
* Pure — computes the full removal plan without mutating any state.
|
|
1285
|
+
* Callers run applyRemovalPlan(plan) to commit.
|
|
1286
|
+
*/
|
|
1287
|
+
planRemoval(sourceId: DataSourceId): ExtendedRemovalPlan<TRow> | null;
|
|
1288
|
+
/**
|
|
1289
|
+
* Mutates internal state per plan produced by planRemoval.
|
|
1290
|
+
*/
|
|
1291
|
+
applyRemovalPlan(plan: ExtendedRemovalPlan<TRow>): void;
|
|
1022
1292
|
clear(): void;
|
|
1023
|
-
private
|
|
1293
|
+
private getUniqueName;
|
|
1024
1294
|
}
|
|
1025
1295
|
|
|
1026
1296
|
/**
|
|
1027
|
-
*
|
|
1028
|
-
*
|
|
1029
|
-
*
|
|
1030
|
-
*
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1297
|
+
* Internal contract: the surface a Scale client exposes to the SDK's data
|
|
1298
|
+
* layer. Implemented by `ScaleClient`. Not part of the public SDK API —
|
|
1299
|
+
* customers configure server mode via `server: { url }` and never see this
|
|
1300
|
+
* type.
|
|
1301
|
+
*/
|
|
1302
|
+
type ScaleClientApi<TRow extends DataEditorRow = DataEditorRow, TFilters = Record<string, unknown>> = {
|
|
1303
|
+
onQuery: (params: QueryParams<TFilters>) => Promise<QueryResponse<TRow>>;
|
|
1304
|
+
onFilterOptions?: () => Promise<FilterOptionsResponse>;
|
|
1305
|
+
onExport?: (params: ExportParams$1<TFilters>) => Promise<void>;
|
|
1306
|
+
onEdit: (params: EditParams, options?: ServerCallOptions) => Promise<EditResponse | void>;
|
|
1307
|
+
onFileImport?: (params: FileImportParams) => Promise<void>;
|
|
1308
|
+
onRowsImport?: (params: RowsImportParams) => Promise<RowsImportResponse | void>;
|
|
1309
|
+
importChunkSize?: number;
|
|
1310
|
+
onSourceRemove?: (params: SourceRemoveParams) => Promise<void>;
|
|
1311
|
+
onColumnDelete?: (params: ColumnDeleteParams) => Promise<EditResponse | void>;
|
|
1312
|
+
onColumnEdit?: (params: ColumnEditParams) => Promise<EditResponse | void>;
|
|
1313
|
+
findAndReplace?: FindAndReplaceConfig;
|
|
1314
|
+
pageSize?: number;
|
|
1315
|
+
scrollSensitivity?: number;
|
|
1316
|
+
};
|
|
1317
|
+
|
|
1318
|
+
type ServerDataManagerDeps<TRow extends DataEditorRow = DataEditorRow> = {
|
|
1319
|
+
clear(): void;
|
|
1320
|
+
setLoading(isLoading: boolean): void;
|
|
1321
|
+
registerSource(options: RegisterSourceOptions): DataSourceId;
|
|
1322
|
+
setSourceLoading(sourceId: DataSourceId, isLoading: boolean): void;
|
|
1323
|
+
getLocalRowCount(): number;
|
|
1324
|
+
replaceServerRows(sourceId: DataSourceId, rows: ServerRow<TRow>[], offset: number, counts?: ServerQueryCounts): void;
|
|
1325
|
+
appendServerRows(rows: ServerRow<TRow>[], counts?: ServerQueryCounts): void;
|
|
1326
|
+
prependServerRows(rows: ServerRow<TRow>[], offset: number, counts?: ServerQueryCounts): void;
|
|
1327
|
+
applyServerRowMeta(rows: ServerRow<TRow>[], counts?: ServerQueryCounts): void;
|
|
1328
|
+
};
|
|
1329
|
+
type FetchDirection = "forward" | "backward" | "jump";
|
|
1330
|
+
declare class ServerDataManager<TRow extends DataEditorRow = DataEditorRow> {
|
|
1331
|
+
private _offset;
|
|
1332
|
+
private _totalCount;
|
|
1333
|
+
private _isFetching;
|
|
1334
|
+
private readonly _pageSize;
|
|
1335
|
+
private readonly _maxBufferRows;
|
|
1336
|
+
private _filters;
|
|
1337
|
+
private _sources;
|
|
1338
|
+
private _sort;
|
|
1339
|
+
private _filterOptions;
|
|
1340
|
+
private _filterOptionsFetched;
|
|
1341
|
+
private _abortController;
|
|
1342
|
+
private _syncAbort;
|
|
1343
|
+
private _lastVisibleStart;
|
|
1344
|
+
private _debouncedFetch;
|
|
1345
|
+
private readonly _config;
|
|
1346
|
+
private readonly _dataStoreRef;
|
|
1347
|
+
private readonly _sourceLabel;
|
|
1348
|
+
private _onChanged;
|
|
1349
|
+
constructor(config: ScaleClientApi<TRow>, dataStoreRef: ServerDataManagerDeps<TRow>, sourceLabel: string);
|
|
1350
|
+
get offset(): number;
|
|
1351
|
+
get totalCount(): number | null;
|
|
1352
|
+
get isFetching(): boolean;
|
|
1353
|
+
get pageSize(): number;
|
|
1354
|
+
get maxBufferRows(): number;
|
|
1355
|
+
setOnChanged(callback: () => void): void;
|
|
1356
|
+
setOffset(offset: number): void;
|
|
1357
|
+
setTotalCount(count: number): void;
|
|
1358
|
+
private setFetching;
|
|
1359
|
+
getExcess(currentCount: number, newCount: number): number;
|
|
1360
|
+
shouldFetch(visibleStart: number, visibleEnd: number, loadedCount: number): FetchDirection | null;
|
|
1361
|
+
/**
|
|
1362
|
+
* Full reload — abort in-flight, clear store, fetch first page.
|
|
1363
|
+
* Called on initial load, search/filter/sort changes, and resetFilters.
|
|
1364
|
+
*/
|
|
1365
|
+
reload(): void;
|
|
1366
|
+
/**
|
|
1367
|
+
* Scroll-driven pagination with velocity-based debouncing.
|
|
1368
|
+
* Called from CanvasGrid on every scroll event.
|
|
1369
|
+
*/
|
|
1370
|
+
handleScroll(visibleStart: number, visibleEnd: number): void;
|
|
1371
|
+
/**
|
|
1372
|
+
* Fetch a single page based on scroll position and current window state.
|
|
1373
|
+
*/
|
|
1374
|
+
private fetchPage;
|
|
1375
|
+
/**
|
|
1376
|
+
* Re-query the current viewport and replace row data, metadata, and counts.
|
|
1377
|
+
* Called after successful edits and find-and-replace mutations.
|
|
1378
|
+
* Each call aborts the previous in-flight sync.
|
|
1379
|
+
*/
|
|
1380
|
+
syncCurrentView(): void;
|
|
1381
|
+
/**
|
|
1382
|
+
* Merge filter keys into server filter state and reload.
|
|
1383
|
+
* Called by DataStore.setFilters() in server mode and by filter components.
|
|
1384
|
+
*/
|
|
1385
|
+
setFilters(filters: Partial<Filters>): void;
|
|
1386
|
+
/**
|
|
1387
|
+
* Set sort state and reload.
|
|
1388
|
+
*/
|
|
1389
|
+
setSort(sort: SortState): void;
|
|
1390
|
+
/**
|
|
1391
|
+
* Restrict query to visible sources and reload.
|
|
1392
|
+
* Pass `undefined` to include all sources.
|
|
1393
|
+
*/
|
|
1394
|
+
setSources(sources: string[] | undefined): void;
|
|
1395
|
+
/**
|
|
1396
|
+
* Clear all filters and sort, then reload.
|
|
1397
|
+
*/
|
|
1398
|
+
resetFilters(): void;
|
|
1399
|
+
/**
|
|
1400
|
+
* One-time fetch of filter option dictionaries for sidebar filter controls.
|
|
1401
|
+
*/
|
|
1402
|
+
fetchFilterOptions(): void;
|
|
1403
|
+
getFilterOptions(): FilterOptionsResponse | null;
|
|
1404
|
+
get onEdit(): (params: EditParams, options?: ServerCallOptions) => Promise<EditResponse | void>;
|
|
1405
|
+
get filters(): Record<string, unknown>;
|
|
1406
|
+
get sort(): SortState;
|
|
1407
|
+
get sources(): string[] | undefined;
|
|
1408
|
+
get onSourceRemove(): ((params: SourceRemoveParams) => Promise<void>) | undefined;
|
|
1409
|
+
get onColumnDelete(): ((params: ColumnDeleteParams) => Promise<EditResponse | void>) | undefined;
|
|
1410
|
+
get onColumnEdit(): ((params: ColumnEditParams) => Promise<EditResponse | void>) | undefined;
|
|
1411
|
+
get hasExport(): boolean;
|
|
1412
|
+
private _exportAbortController;
|
|
1413
|
+
export(format: DataEditorFormat, allRows: boolean, rtl: boolean): Promise<void>;
|
|
1414
|
+
clear(): void;
|
|
1415
|
+
destroy(): void;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
/**
|
|
1419
|
+
* A post-resolution selection rectangle in stable coordinate space.
|
|
1420
|
+
* Produced by grid-layer resolvers from CellRange[] in grid-index space.
|
|
1421
|
+
* Consumed by DataStore operations and server sync.
|
|
1422
|
+
*/
|
|
1423
|
+
type SelectionRect = {
|
|
1424
|
+
readonly fields: readonly string[];
|
|
1425
|
+
readonly rowIds: readonly TRowId[];
|
|
1426
|
+
};
|
|
1427
|
+
|
|
1428
|
+
/**
|
|
1429
|
+
* ServerEditBuilder — Stateless coordinate translator for server-delegated edits.
|
|
1034
1430
|
*
|
|
1035
|
-
*
|
|
1036
|
-
*
|
|
1037
|
-
* Updated incrementally via adjust*() methods on single-row edits, or
|
|
1038
|
-
* recomputed in bulk when _countsDirty is set (after deletes, source changes, etc.).
|
|
1039
|
-
* - Filtered counts: subset of visible counts restricted to filteredRowIds.
|
|
1040
|
-
* Recomputed when _filteredCountsDirty is set (after filter changes).
|
|
1431
|
+
* Converts frontend coordinates (TRowId, column index, grid ranges) into
|
|
1432
|
+
* `EditParams` with `Region[]` that the server can interpret.
|
|
1041
1433
|
*
|
|
1042
|
-
*
|
|
1043
|
-
*
|
|
1044
|
-
* triggers a single notification, preventing intermediate snapshots from
|
|
1045
|
-
* reaching React during multi-step operations (fill handle, batch delete, etc.).
|
|
1434
|
+
* Does NOT call `onEdit`. Only builds params.
|
|
1435
|
+
* DataStore calls the builder, then sends the result to the server.
|
|
1046
1436
|
*
|
|
1047
|
-
*
|
|
1048
|
-
*
|
|
1049
|
-
*
|
|
1437
|
+
* Responsibilities:
|
|
1438
|
+
* - TRowId → ServerRowId translation via primaryKey
|
|
1439
|
+
* - Grid index → column ID translation via columns array
|
|
1440
|
+
* - Filter/sort context attachment from ServerDataManager
|
|
1050
1441
|
*/
|
|
1051
1442
|
|
|
1052
|
-
type
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
/**
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1443
|
+
type ServerEditDeps<TRow extends DataEditorRow = DataEditorRow> = {
|
|
1444
|
+
getPrimaryKey: () => string;
|
|
1445
|
+
getRowById: (id: TRowId) => TRow | undefined;
|
|
1446
|
+
getColumnIds: () => string[];
|
|
1447
|
+
getFilters: () => Record<string, unknown>;
|
|
1448
|
+
getSort: () => SortState;
|
|
1449
|
+
getLockedColumns: () => ReadonlyMap<string, ColumnLockMode>;
|
|
1450
|
+
};
|
|
1451
|
+
declare class ServerEditBuilder<TRow extends DataEditorRow = DataEditorRow> {
|
|
1452
|
+
private readonly _deps;
|
|
1453
|
+
constructor(deps: ServerEditDeps<TRow>);
|
|
1454
|
+
resolveServerRowId(rowId: TRowId): ServerRowId | undefined;
|
|
1455
|
+
buildRegion(rowIds: TRowId[], columnIds: string[]): Region;
|
|
1456
|
+
/**
|
|
1457
|
+
* Collapse rowIds × columnIds into minimal Region[].
|
|
1458
|
+
* - All columns → omit column fields (row-only regions).
|
|
1459
|
+
* - Contiguous columns in schema order → single fromColumn/toColumn span.
|
|
1460
|
+
* - Non-contiguous → one region per contiguous column group.
|
|
1461
|
+
* Rows are expressed as fromRow/toRow using first/last of the provided array.
|
|
1462
|
+
*/
|
|
1463
|
+
buildRegions(rowIds: TRowId[], columnIds: string[]): Region[];
|
|
1464
|
+
/**
|
|
1465
|
+
* Collapse columnIds into minimal column-only Region[] (all rows implied).
|
|
1466
|
+
* - All columns → `{ allSelected: true }`.
|
|
1467
|
+
* - Contiguous in schema order → single `{ fromColumn, toColumn }`.
|
|
1468
|
+
* - Non-contiguous → one region per contiguous group.
|
|
1469
|
+
*/
|
|
1470
|
+
buildColumnRegions(columnIds: string[]): Region[];
|
|
1471
|
+
/**
|
|
1472
|
+
* Build minimal Region[] from multiple selection rectangles.
|
|
1473
|
+
* Each rect is collapsed independently, preserving disjoint selections.
|
|
1474
|
+
*/
|
|
1475
|
+
buildRegionsFromRects(rects: SelectionRect[]): Region[];
|
|
1476
|
+
buildAllSelectedRegion(): Region;
|
|
1477
|
+
buildColumnRegion(columnId: string): Region;
|
|
1478
|
+
buildRowRegion(fromRowId: TRowId, toRowId: TRowId): Region;
|
|
1479
|
+
cellEdit(rowId: TRowId, field: string, value: unknown): EditParams;
|
|
1480
|
+
clear(target: Region[]): EditParams;
|
|
1481
|
+
paste(source: Region[], target: Region[], cut?: boolean): EditParams;
|
|
1482
|
+
pasteExternal(target: Region[], values: unknown[][]): EditParams;
|
|
1483
|
+
fill(source: Region[], target: Region[]): EditParams;
|
|
1484
|
+
transform(target: Region[], transform: TransformParams): EditParams;
|
|
1485
|
+
deleteRows(rowRanges: [TRowId, TRowId][]): EditParams;
|
|
1486
|
+
restoreRows(rowRanges: [TRowId, TRowId][]): EditParams;
|
|
1487
|
+
deleteAllRows(): EditParams;
|
|
1488
|
+
restoreAllRows(): EditParams;
|
|
1489
|
+
insertRow(anchorRowId: TRowId | undefined, position: InsertParams["position"], values: unknown[][], columnIds: string[]): EditParams;
|
|
1490
|
+
/**
|
|
1491
|
+
* Returns null when all columns are selected (caller decides representation).
|
|
1492
|
+
* Otherwise returns contiguous column spans as `{ fromColumn, toColumn }` regions.
|
|
1493
|
+
*/
|
|
1494
|
+
private collapseColumns;
|
|
1495
|
+
private viewContext;
|
|
1086
1496
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
private recomputeFilteredCounts;
|
|
1497
|
+
|
|
1498
|
+
/**
|
|
1499
|
+
* Categories of internal errors surfaced through the `onError` callback.
|
|
1500
|
+
*
|
|
1501
|
+
* Existing categories cover client-side failures. `scale.*` codes cover
|
|
1502
|
+
* server-mode (Updog Scale) failures. `license.*` codes cover license
|
|
1503
|
+
* validation failures (previously a separate `LicenseErrorCode` enum).
|
|
1504
|
+
*/
|
|
1505
|
+
type UpdogErrorCode = "PARSE_ERROR" | "RENDER_ERROR" | "TRANSFORM_ERROR" | "VALIDATION_ERROR" | "WORKER_ERROR" | "COMMAND_ERROR" | "OPERATION_ERROR" | "license.invalid" | "license.missing" | "license.domain_not_allowed" | "license.subscription_inactive" | "license.trial_expired" | "scale.bootstrap_failed" | "scale.workspace_lost" | "scale.unreachable" | "scale.server_error";
|
|
1506
|
+
/**
|
|
1507
|
+
* An internal error caught by the SDK and passed to `onError`. The SDK
|
|
1508
|
+
* recovers gracefully where possible — `onError` is for your logging and
|
|
1509
|
+
* monitoring (Sentry, Datadog, etc.).
|
|
1510
|
+
*
|
|
1511
|
+
* @example
|
|
1512
|
+
* ```ts
|
|
1513
|
+
* onError={(error) => {
|
|
1514
|
+
* Sentry.captureException(error.originalError ?? error, {
|
|
1515
|
+
* tags: { code: error.code, source: error.source },
|
|
1516
|
+
* });
|
|
1517
|
+
* }}
|
|
1518
|
+
* ```
|
|
1519
|
+
*/
|
|
1520
|
+
type UpdogError = {
|
|
1521
|
+
/** The error category. */
|
|
1522
|
+
code: UpdogErrorCode;
|
|
1523
|
+
/** Human-readable description. */
|
|
1524
|
+
message: string;
|
|
1525
|
+
/** Module or subsystem that raised the error. */
|
|
1526
|
+
source: string;
|
|
1527
|
+
/** The underlying thrown value, when available. */
|
|
1528
|
+
originalError?: unknown;
|
|
1529
|
+
};
|
|
1530
|
+
|
|
1531
|
+
declare class ErrorHandler {
|
|
1532
|
+
private onError?;
|
|
1533
|
+
constructor(onError?: (error: UpdogError) => void);
|
|
1534
|
+
handleError(error: UpdogError): void;
|
|
1126
1535
|
}
|
|
1127
1536
|
|
|
1128
1537
|
/**
|
|
1129
|
-
*
|
|
1538
|
+
* DirtyTracker — Change classification and revert detection for rows.
|
|
1130
1539
|
*
|
|
1131
|
-
*
|
|
1132
|
-
*
|
|
1133
|
-
* (
|
|
1540
|
+
* Every row falls into one of three categories:
|
|
1541
|
+
* - Clean — matches the backend; not tracked here at all
|
|
1542
|
+
* - New — created locally (CSV import or manual add), never existed on the backend
|
|
1543
|
+
* - Edited — exists on the backend but has been modified locally
|
|
1134
1544
|
*
|
|
1135
|
-
*
|
|
1136
|
-
*
|
|
1137
|
-
*
|
|
1138
|
-
*
|
|
1139
|
-
*
|
|
1545
|
+
* Classification uses inverted tracking via `nonBackendRowIds`: only non-backend
|
|
1546
|
+
* rows (CSV imports, manual adds) are stored in the set. Since backend rows are
|
|
1547
|
+
* the vast majority (~1M), this inverted approach saves ~50MB by assuming any
|
|
1548
|
+
* row NOT in the set is a backend row.
|
|
1549
|
+
* - First edit of a backend row → "edited", original row is snapshotted
|
|
1550
|
+
* - First edit of a non-backend row → "new"
|
|
1140
1551
|
*
|
|
1141
|
-
*
|
|
1142
|
-
*
|
|
1143
|
-
* "
|
|
1552
|
+
* Smart revert: after every edit, the current row is compared field-by-field
|
|
1553
|
+
* against the snapshot. If all fields match the original, the row silently
|
|
1554
|
+
* reverts to "clean" — no dirty flag, no undo entry needed. This lets users
|
|
1555
|
+
* fix typos by simply typing the original value back.
|
|
1556
|
+
*
|
|
1557
|
+
* Merge snapshots: when a CSV import overwrites an existing row, the original
|
|
1558
|
+
* data + classification is saved so it can be restored if the source is removed.
|
|
1144
1559
|
*/
|
|
1145
1560
|
|
|
1146
|
-
type
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1561
|
+
type IDirtyTracker<TRow extends DataEditorRow = DataEditorRow> = {
|
|
1562
|
+
markDeleted(id: TRowId): void;
|
|
1563
|
+
unmarkDeleted(id: TRowId): void;
|
|
1564
|
+
isDeleted(id: TRowId): boolean;
|
|
1565
|
+
getDeletedRowIds(): ReadonlySet<TRowId>;
|
|
1566
|
+
deletedCount(): number;
|
|
1567
|
+
isDefaultSourceRow(id: TRowId): boolean;
|
|
1568
|
+
isNew(id: TRowId): boolean;
|
|
1569
|
+
isEdited(id: TRowId): boolean;
|
|
1570
|
+
isCellDirty(id: TRowId, field: string, currentRow: TRow | undefined): boolean;
|
|
1571
|
+
getOriginalCellValue(id: TRowId, field: string): unknown | undefined;
|
|
1572
|
+
getOriginalRow(id: TRowId): TRow | undefined;
|
|
1573
|
+
hasOriginalRow(id: TRowId): boolean;
|
|
1574
|
+
trackNonBackendRow(id: TRowId): void;
|
|
1575
|
+
markNew(id: TRowId): void;
|
|
1576
|
+
markEdited(id: TRowId): void;
|
|
1577
|
+
snapshotOriginal(id: TRowId, row: TRow): void;
|
|
1578
|
+
classifyOnFirstEdit(id: TRowId, row: TRow): void;
|
|
1579
|
+
checkRevert(id: TRowId, currentRow: TRow): {
|
|
1580
|
+
wasNew: boolean;
|
|
1581
|
+
wasEdited: boolean;
|
|
1582
|
+
};
|
|
1583
|
+
removeTracking(id: TRowId): void;
|
|
1584
|
+
getNewRowIds(): ReadonlySet<TRowId>;
|
|
1585
|
+
getEditedRowIds(): ReadonlySet<TRowId>;
|
|
1586
|
+
getMergeSnapshot(id: TRowId): {
|
|
1587
|
+
isNew: boolean;
|
|
1588
|
+
isEdited: boolean;
|
|
1589
|
+
};
|
|
1590
|
+
restoreMergeClassification(id: TRowId, isNew: boolean, isEdited: boolean): void;
|
|
1163
1591
|
clear(): void;
|
|
1164
1592
|
};
|
|
1165
1593
|
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
rebuild(rows: Iterable<TRow>): void;
|
|
1184
|
-
getValues(field: string): ReadonlyMap<string, number>;
|
|
1185
|
-
getVersion(): number;
|
|
1186
|
-
isTracked(field: string): boolean;
|
|
1187
|
-
getMinMax(field: string): {
|
|
1188
|
-
min: number;
|
|
1189
|
-
max: number;
|
|
1190
|
-
} | null;
|
|
1191
|
-
getDateMinMax(field: string): {
|
|
1192
|
-
min: string;
|
|
1193
|
-
max: string;
|
|
1194
|
-
} | null;
|
|
1195
|
-
bumpVersion(): void;
|
|
1196
|
-
};
|
|
1197
|
-
|
|
1198
|
-
type RowEntry<TRow extends DataEditorRow> = {
|
|
1199
|
-
rowId: TRowId;
|
|
1200
|
-
row: TRow;
|
|
1201
|
-
sourceId: DataSourceId;
|
|
1202
|
-
isNew: boolean;
|
|
1203
|
-
isEdited: boolean;
|
|
1204
|
-
isDeleted: boolean;
|
|
1205
|
-
originalRow?: TRow;
|
|
1206
|
-
};
|
|
1207
|
-
type OverlayEntry<TRow extends DataEditorRow> = {
|
|
1208
|
-
rowId: TRowId;
|
|
1209
|
-
displayValue: TRow;
|
|
1210
|
-
};
|
|
1211
|
-
type SourceSnapshot<TRow extends DataEditorRow> = {
|
|
1212
|
-
state: DataSourceState;
|
|
1213
|
-
ownedRows: RowEntry<TRow>[];
|
|
1214
|
-
overlayRows: OverlayEntry<TRow>[];
|
|
1215
|
-
rowIds: TRowId[];
|
|
1216
|
-
plan: ExtendedRemovalPlan<TRow>;
|
|
1217
|
-
};
|
|
1218
|
-
type SourceLifecycleHost<TRow extends DataEditorRow> = {
|
|
1219
|
-
getValidator: () => IValidator<TRow> | null;
|
|
1220
|
-
pushCommand: (cmd: Command<TRow>, cost?: number) => number;
|
|
1221
|
-
notify: () => void;
|
|
1222
|
-
isServerStrategy: () => boolean;
|
|
1223
|
-
checkRowEmptyCells: (rowId: TRowId) => void;
|
|
1224
|
-
clearRowValidations: (rowId: TRowId) => void;
|
|
1225
|
-
};
|
|
1226
|
-
declare class SourceLifecycle<TRow extends DataEditorRow = DataEditorRow> {
|
|
1227
|
-
private readonly sourceManager;
|
|
1228
|
-
private readonly rowStore;
|
|
1229
|
-
private readonly dirtyTracker;
|
|
1230
|
-
private readonly filterEngine;
|
|
1231
|
-
private readonly valueIndex;
|
|
1232
|
-
private readonly validationStore;
|
|
1233
|
-
private readonly snapshotManager;
|
|
1234
|
-
private readonly host;
|
|
1235
|
-
private readonly importTrackers;
|
|
1236
|
-
constructor(sourceManager: SourceManager<TRow>, rowStore: RowStore<TRow>, dirtyTracker: IDirtyTracker<TRow>, filterEngine: IFilterEngine<TRow>, valueIndex: IValueIndex<TRow>, validationStore: IValidationStore, snapshotManager: SnapshotManager, host: SourceLifecycleHost<TRow>);
|
|
1237
|
-
plan(sourceId: DataSourceId): ExtendedRemovalPlan<TRow> | null;
|
|
1238
|
-
capture(sourceId: DataSourceId): SourceSnapshot<TRow> | null;
|
|
1239
|
-
apply(plan: ExtendedRemovalPlan<TRow>): void;
|
|
1240
|
-
private applyToStores;
|
|
1241
|
-
restore(snapshot: SourceSnapshot<TRow>): void;
|
|
1242
|
-
register(options: RegisterSourceOptions): DataSourceId;
|
|
1243
|
-
trackAppend(sourceId: DataSourceId, rowIds: TRowId[], rows: TRow[], usedIdMap: boolean): void;
|
|
1244
|
-
trackPrimaryKey(sourceId: DataSourceId, primaryKey: keyof TRow): void;
|
|
1245
|
-
finalize(sourceId: DataSourceId): Promise<void>;
|
|
1246
|
-
private pushImportCommandIfTracked;
|
|
1247
|
-
private removeInternal;
|
|
1248
|
-
remove(sourceId: DataSourceId): Promise<SourceSnapshot<TRow> | null>;
|
|
1249
|
-
finalizeAllSources(): void;
|
|
1594
|
+
interface FlagReader {
|
|
1595
|
+
hasError(id: TRowId): boolean;
|
|
1596
|
+
isNew(id: TRowId): boolean;
|
|
1597
|
+
isEdited(id: TRowId): boolean;
|
|
1598
|
+
hasEmptyCells(id: TRowId): boolean;
|
|
1599
|
+
isDeleted(id: TRowId): boolean;
|
|
1600
|
+
hasDeletedRows(): boolean;
|
|
1601
|
+
getSourceId(id: TRowId): string;
|
|
1602
|
+
getErrorBitmask(id: TRowId, fieldOrder: string[], wordIdx: number): number;
|
|
1603
|
+
getEditedBitmask(id: TRowId, fieldOrder: string[], wordIdx: number): number;
|
|
1604
|
+
getErrorMessageToRows(): ReadonlyMap<string, ReadonlySet<TRowId>>;
|
|
1605
|
+
getRowValidations(id: TRowId): Map<string, NonNullable<ValidationResult>> | undefined;
|
|
1606
|
+
}
|
|
1607
|
+
interface FilterRowReader<TRow extends DataEditorRow = DataEditorRow> {
|
|
1608
|
+
getRowIds(): TRowId[];
|
|
1609
|
+
getRowById(id: TRowId): TRow | undefined;
|
|
1610
|
+
getHiddenSourceIds(): Set<DataSourceId>;
|
|
1250
1611
|
}
|
|
1612
|
+
type IFilterEngine<TRow extends DataEditorRow = DataEditorRow> = {
|
|
1613
|
+
getFilteredRowIds(): TRowId[] | null;
|
|
1614
|
+
getBaseFilteredRowIds(): TRowId[] | null;
|
|
1615
|
+
getFilterVersion(): number;
|
|
1616
|
+
getFilterCriteriaVersion(): number;
|
|
1617
|
+
isFiltering(): boolean;
|
|
1618
|
+
getFilters(): Filters;
|
|
1619
|
+
getFieldOrder(): string[];
|
|
1620
|
+
getWordsPerRow(): number;
|
|
1621
|
+
getShowOnlyDeletedRows(): boolean;
|
|
1622
|
+
getSortState(): SortState;
|
|
1623
|
+
setReaders(rowReader: FilterRowReader<TRow>, flagReader: FlagReader): void;
|
|
1624
|
+
setColumns(columns: DataEditorColumn[]): void;
|
|
1625
|
+
setFilters(filters: Partial<Filters>): void;
|
|
1626
|
+
setSortState(state: SortState, sortType?: SortType, locales?: string[]): Promise<void>;
|
|
1627
|
+
updateRowText(rowId: TRowId, row: TRow): void;
|
|
1628
|
+
updateRowsText(rows: {
|
|
1629
|
+
id: TRowId;
|
|
1630
|
+
row: TRow;
|
|
1631
|
+
}[]): void;
|
|
1632
|
+
deleteRowTextCache(rowId: TRowId): void;
|
|
1633
|
+
clearRowTextCacheAll(): void;
|
|
1634
|
+
setRowTextCache(rowId: TRowId, row: TRow): void;
|
|
1635
|
+
rebuild(): void;
|
|
1636
|
+
refilterAfterColumnsChange(): void;
|
|
1637
|
+
notifyRowsAdded(ids: TRowId[]): void;
|
|
1638
|
+
notifyRowsDeleted(deletedIds: TRowId[]): void;
|
|
1639
|
+
notifyRowsInserted(restoredIds: TRowId[], positions: number[]): void;
|
|
1640
|
+
refilterAfterSourceToggle(sourceId: DataSourceId, isVisible: boolean): void;
|
|
1641
|
+
refilterAfterFlagChange(): void;
|
|
1642
|
+
flushPendingFlags(): void;
|
|
1643
|
+
markFlagsDirty(): void;
|
|
1644
|
+
testRowAgainstFilters(rowId: TRowId, row: TRow, flagReader: FlagReader, hiddenSourceIds: Set<DataSourceId>): boolean;
|
|
1645
|
+
getAllRowIdsSorted(rowReader: FilterRowReader<TRow>): Promise<TRowId[]>;
|
|
1646
|
+
clear(): void;
|
|
1647
|
+
destroy(): void;
|
|
1648
|
+
};
|
|
1251
1649
|
|
|
1252
1650
|
/**
|
|
1253
|
-
*
|
|
1651
|
+
* RowStore — Row storage with dual-access pattern for the grid engine.
|
|
1254
1652
|
*
|
|
1255
|
-
*
|
|
1256
|
-
*
|
|
1653
|
+
* Maintains two parallel structures:
|
|
1654
|
+
* - (TRow | undefined)[] → O(1) lookup by stable internal ID (rows[id])
|
|
1655
|
+
* - TRowId[] → O(1) lookup by visual index (required by the grid)
|
|
1257
1656
|
*
|
|
1258
|
-
*
|
|
1259
|
-
*
|
|
1657
|
+
* The grid calls getRow(index) on every frame, so index-based access must be
|
|
1658
|
+
* instant. Filtered views are supported by passing an alternate ID array
|
|
1659
|
+
* (filteredIds) to the access methods — the store itself is unaware of filters.
|
|
1260
1660
|
*
|
|
1261
|
-
*
|
|
1262
|
-
*
|
|
1263
|
-
*
|
|
1661
|
+
* An inverted index (rowId → visual index) is lazily rebuilt on demand for
|
|
1662
|
+
* O(1) reverse lookups (e.g., scrolling to a specific row after undo).
|
|
1663
|
+
*
|
|
1664
|
+
* Internal row IDs are auto-generated as sequential numbers (1, 2, 3, …).
|
|
1665
|
+
* Using a plain array indexed by ID eliminates Map hash table overhead
|
|
1666
|
+
* (~10MB saved at 1M rows). Deleted slots are set to undefined (not delete)
|
|
1667
|
+
* to keep V8 in HOLEY_ELEMENTS mode.
|
|
1264
1668
|
*/
|
|
1265
1669
|
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
label: string;
|
|
1294
|
-
type: FormulaParamType;
|
|
1295
|
-
required?: boolean;
|
|
1296
|
-
defaultValue?: unknown;
|
|
1297
|
-
options?: Array<{
|
|
1298
|
-
id: string;
|
|
1299
|
-
text: string;
|
|
1300
|
-
}>;
|
|
1301
|
-
};
|
|
1302
|
-
type ColumnInputKind = "single" | "multiple";
|
|
1303
|
-
type ColumnInput = {
|
|
1304
|
-
name: string;
|
|
1305
|
-
label: string;
|
|
1306
|
-
kind: ColumnInputKind;
|
|
1307
|
-
required?: boolean;
|
|
1308
|
-
};
|
|
1309
|
-
type FormulaCategory = "text" | "number" | "logic" | "custom";
|
|
1310
|
-
type FormulaArity = {
|
|
1311
|
-
/** Minimum number of positional arguments. 0 means "callable with no args". */
|
|
1312
|
-
min: number;
|
|
1313
|
-
/** Maximum number of positional arguments. Use Number.POSITIVE_INFINITY for variadic. */
|
|
1314
|
-
max: number;
|
|
1315
|
-
};
|
|
1316
|
-
type FormulaBase = {
|
|
1317
|
-
name: string;
|
|
1318
|
-
label: string;
|
|
1319
|
-
category: FormulaCategory;
|
|
1320
|
-
description?: string;
|
|
1321
|
-
columns?: ColumnInput[];
|
|
1322
|
-
params: FormulaParam[];
|
|
1323
|
-
/**
|
|
1324
|
-
* The call signature of this formula when invoked from the expression
|
|
1325
|
-
* language. Required. For shortcut formulas (UPPER, TRIM, ...) use
|
|
1326
|
-
* { min: 1, max: 1 }. For CLEAR use { min: 0, max: 0 }. For MERGE use
|
|
1327
|
-
* { min: 2, max: Number.POSITIVE_INFINITY }.
|
|
1328
|
-
*/
|
|
1329
|
-
arity: FormulaArity;
|
|
1330
|
-
/** Parameter signature shown in autocomplete, without the function name. e.g. "(text, count)" */
|
|
1331
|
-
syntax?: string;
|
|
1332
|
-
/**
|
|
1333
|
-
* Whether this formula may be invoked from the expression parser.
|
|
1334
|
-
* Defaults to true when omitted. MERGE and SPLIT set this to false
|
|
1335
|
-
* because they have dedicated modals that supply their non-expression
|
|
1336
|
-
* params (column lists, separator, ...).
|
|
1337
|
-
*/
|
|
1338
|
-
expressionCallable?: boolean;
|
|
1339
|
-
};
|
|
1340
|
-
type CellFormula = FormulaBase & {
|
|
1341
|
-
kind: "cell";
|
|
1342
|
-
compute: (ctx: FormulaCellContext, params: Record<string, unknown>) => unknown;
|
|
1343
|
-
};
|
|
1344
|
-
type RowFormula = FormulaBase & {
|
|
1345
|
-
kind: "row";
|
|
1346
|
-
targetFields: (params: Record<string, unknown>) => string[];
|
|
1347
|
-
compute: (ctx: FormulaCellContext, params: Record<string, unknown>) => Record<string, unknown>;
|
|
1348
|
-
};
|
|
1349
|
-
type FormulaDefinition = CellFormula | RowFormula;
|
|
1350
|
-
|
|
1351
|
-
declare class FormulaRegistry {
|
|
1352
|
-
private readonly formulas;
|
|
1353
|
-
register(formula: FormulaDefinition): void;
|
|
1354
|
-
get(name: string): FormulaDefinition | undefined;
|
|
1355
|
-
getAll(): FormulaDefinition[];
|
|
1356
|
-
getByCategory(category: string): FormulaDefinition[];
|
|
1357
|
-
getExpressionCallable(): FormulaDefinition[];
|
|
1670
|
+
declare class RowStore<TRow extends DataEditorRow = DataEditorRow> {
|
|
1671
|
+
private rows;
|
|
1672
|
+
private rowIds;
|
|
1673
|
+
private rowIdCounter;
|
|
1674
|
+
private rowIdToIndex;
|
|
1675
|
+
private _rowIndexDirty;
|
|
1676
|
+
nextRowId(): TRowId;
|
|
1677
|
+
getRow(index: number, filteredIds: TRowId[] | null): TRow | undefined;
|
|
1678
|
+
getRowById(id: TRowId): TRow | undefined;
|
|
1679
|
+
getRowId(index: number, filteredIds: TRowId[] | null): TRowId | undefined;
|
|
1680
|
+
getRowIndex(rowId: TRowId, filteredIds: TRowId[] | null): number;
|
|
1681
|
+
getRowIds(): TRowId[];
|
|
1682
|
+
getRowCount(): number;
|
|
1683
|
+
allRows(): IterableIterator<TRow>;
|
|
1684
|
+
hasRow(id: TRowId): boolean;
|
|
1685
|
+
setRow(id: TRowId, row: TRow): void;
|
|
1686
|
+
deleteRow(id: TRowId): void;
|
|
1687
|
+
pushRowId(id: TRowId): void;
|
|
1688
|
+
spliceRowId(pos: number, id: TRowId): void;
|
|
1689
|
+
removeRowId(id: TRowId): void;
|
|
1690
|
+
filterRowIds(predicate: (id: TRowId) => boolean): void;
|
|
1691
|
+
trimFromStart(count: number): TRowId[];
|
|
1692
|
+
trimFromEnd(count: number): TRowId[];
|
|
1693
|
+
unshiftRowIds(ids: TRowId[]): void;
|
|
1694
|
+
invalidateIndex(): void;
|
|
1695
|
+
clear(): void;
|
|
1696
|
+
private rebuildRowIdToIndex;
|
|
1358
1697
|
}
|
|
1359
1698
|
|
|
1360
1699
|
/**
|
|
1361
|
-
*
|
|
1700
|
+
* SnapshotManager — Immutable snapshot construction and listener notification
|
|
1701
|
+
* for React's useSyncExternalStore integration.
|
|
1362
1702
|
*
|
|
1363
|
-
*
|
|
1364
|
-
*
|
|
1703
|
+
* Builds a DataStoreSnapshot object that React components subscribe to via
|
|
1704
|
+
* useSyncExternalStore(subscribe, getSnapshot). A new snapshot object is
|
|
1705
|
+
* created on every notify() call, which triggers React's shallow comparison
|
|
1706
|
+
* and re-renders only when values actually change.
|
|
1365
1707
|
*
|
|
1366
|
-
*
|
|
1367
|
-
*
|
|
1708
|
+
* Count tracking has two tiers:
|
|
1709
|
+
* - Visible counts: new/edited/error/empty rows from visible sources only.
|
|
1710
|
+
* Updated incrementally via adjust*() methods on single-row edits, or
|
|
1711
|
+
* recomputed in bulk when _countsDirty is set (after deletes, source changes, etc.).
|
|
1712
|
+
* - Filtered counts: subset of visible counts restricted to filteredRowIds.
|
|
1713
|
+
* Recomputed when _filteredCountsDirty is set (after filter changes).
|
|
1368
1714
|
*
|
|
1369
|
-
*
|
|
1370
|
-
*
|
|
1371
|
-
*
|
|
1372
|
-
*
|
|
1715
|
+
* Batching: multiple operations can be grouped via beginBatch()/endBatch().
|
|
1716
|
+
* While batching, notify() calls are deferred — only the outermost endBatch()
|
|
1717
|
+
* triggers a single notification, preventing intermediate snapshots from
|
|
1718
|
+
* reaching React during multi-step operations (fill handle, batch delete, etc.).
|
|
1719
|
+
*
|
|
1720
|
+
* The SnapshotStateReader interface decouples this module from all other modules.
|
|
1721
|
+
* DataStore implements the interface by delegating to RowStore, DirtyTracker,
|
|
1722
|
+
* FilterEngine, and ValidationStore, so SnapshotManager never imports them directly.
|
|
1373
1723
|
*/
|
|
1374
1724
|
|
|
1375
|
-
type
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1725
|
+
type Listener = () => void;
|
|
1726
|
+
interface SnapshotStateReader {
|
|
1727
|
+
getRowCount(): number;
|
|
1728
|
+
getFilteredRowIds(): TRowId[] | null;
|
|
1729
|
+
getBaseFilteredRowIds(): TRowId[] | null;
|
|
1730
|
+
getNewRowIds(): ReadonlySet<TRowId>;
|
|
1731
|
+
getEditedRowIds(): ReadonlySet<TRowId>;
|
|
1732
|
+
getRowsWithErrors(): ReadonlySet<TRowId>;
|
|
1733
|
+
getRowsWithEmptyCells(): ReadonlySet<TRowId>;
|
|
1734
|
+
getDeletedCount(): number;
|
|
1735
|
+
isDeleted(id: TRowId): boolean;
|
|
1736
|
+
getSources(): DataSourceState[];
|
|
1737
|
+
isRowVisible(id: TRowId): boolean;
|
|
1738
|
+
canUndo(): boolean;
|
|
1739
|
+
canRedo(): boolean;
|
|
1740
|
+
isLoading(): boolean;
|
|
1741
|
+
isFiltering(): boolean;
|
|
1742
|
+
getVersion(): number;
|
|
1743
|
+
getFilterCriteriaVersion(): number;
|
|
1744
|
+
getFilteredNewCount(ids: TRowId[] | null): number;
|
|
1745
|
+
getFilteredEditedCount(ids: TRowId[] | null): number;
|
|
1746
|
+
getFilteredDirtyCount(ids: TRowId[] | null): number;
|
|
1747
|
+
getFilteredErrorCount(ids: TRowId[] | null): number;
|
|
1748
|
+
getFilteredEmptyCount(ids: TRowId[] | null): number;
|
|
1749
|
+
getErrorMessageCounts(filteredRowIds: TRowId[] | null): Record<string, number>;
|
|
1750
|
+
hasColumnScoping(): boolean;
|
|
1751
|
+
getSortState(): SortState;
|
|
1752
|
+
getShowOnlyDeletedRows(): boolean;
|
|
1753
|
+
/** Server-provided aggregate counts. Present only in server mode. */
|
|
1754
|
+
getServerEditedCount?(): number;
|
|
1755
|
+
getServerNewCount?(): number;
|
|
1756
|
+
getServerErrorCount?(): number;
|
|
1757
|
+
getServerEmptyCount?(): number;
|
|
1758
|
+
getServerDeletedCount?(): number;
|
|
1759
|
+
}
|
|
1760
|
+
declare class SnapshotManager {
|
|
1761
|
+
private _visibleNewCount;
|
|
1762
|
+
private _visibleEditedCount;
|
|
1763
|
+
private _visibleDirtyCount;
|
|
1764
|
+
private _visibleErrorCount;
|
|
1765
|
+
private _visibleEmptyCount;
|
|
1766
|
+
private _countsDirty;
|
|
1767
|
+
private _filteredDirtyCount;
|
|
1768
|
+
private _filteredNewCount;
|
|
1769
|
+
private _filteredEditedCount;
|
|
1770
|
+
private _filteredErrorCount;
|
|
1771
|
+
private _filteredEmptyCount;
|
|
1772
|
+
private _errorMessageCounts;
|
|
1773
|
+
private _filteredCountsDirty;
|
|
1774
|
+
private _phase;
|
|
1775
|
+
private _processingInfo;
|
|
1776
|
+
private snapshot;
|
|
1777
|
+
private listeners;
|
|
1778
|
+
private batchDepth;
|
|
1779
|
+
private pendingNotify;
|
|
1780
|
+
get countsDirty(): boolean;
|
|
1781
|
+
markCountsDirty(): void;
|
|
1782
|
+
markFilteredCountsDirty(): void;
|
|
1783
|
+
adjustVisibleErrorCount(delta: number): void;
|
|
1784
|
+
adjustVisibleNewCount(delta: number): void;
|
|
1785
|
+
adjustVisibleEditedCount(delta: number): void;
|
|
1786
|
+
adjustVisibleDirtyCount(delta: number): void;
|
|
1787
|
+
subscribe: (listener: Listener) => (() => void);
|
|
1788
|
+
getSnapshot: () => DataStoreSnapshot;
|
|
1789
|
+
isBatching(): boolean;
|
|
1790
|
+
beginBatch(): boolean;
|
|
1791
|
+
endBatch(): boolean;
|
|
1792
|
+
setPhase(phase: ProcessingPhase, info?: ProcessingInfo): void;
|
|
1793
|
+
getPhase(): ProcessingPhase;
|
|
1794
|
+
notify(reader: SnapshotStateReader): void;
|
|
1795
|
+
clear(): void;
|
|
1796
|
+
clearListeners(): void;
|
|
1797
|
+
private recomputeVisibleCounts;
|
|
1798
|
+
private recomputeFilteredCounts;
|
|
1799
|
+
}
|
|
1383
1800
|
|
|
1384
1801
|
/**
|
|
1385
|
-
*
|
|
1386
|
-
* Extend this with your own type via the `<DataEditor<TRow>>` generic for
|
|
1387
|
-
* type-safe column access. When the generic is omitted, rows are typed as
|
|
1388
|
-
* `Record<string, unknown>`.
|
|
1802
|
+
* ValidationStore — Cell-level validation state with incremental count tracking.
|
|
1389
1803
|
*
|
|
1390
|
-
*
|
|
1391
|
-
*
|
|
1392
|
-
*
|
|
1393
|
-
* <DataEditor<Employee> columns={...} primaryKey="id" />
|
|
1394
|
-
* ```
|
|
1395
|
-
*/
|
|
1396
|
-
type DataEditorRow = Record<string, unknown>;
|
|
1397
|
-
/** Sort direction. */
|
|
1398
|
-
type SortDirection = "asc" | "desc";
|
|
1399
|
-
/** Current sort state. `null` means no active sort. */
|
|
1400
|
-
type SortState = {
|
|
1401
|
-
columnId: string;
|
|
1402
|
-
direction: SortDirection;
|
|
1403
|
-
} | null;
|
|
1404
|
-
type Filters = {
|
|
1405
|
-
search: string;
|
|
1406
|
-
matchCase: boolean;
|
|
1407
|
-
matchEntireCell: boolean;
|
|
1408
|
-
errorMessageFilters: string[];
|
|
1409
|
-
showOnlyNewRows: boolean;
|
|
1410
|
-
showOnlyEditedRows: boolean;
|
|
1411
|
-
showOnlyEmptyCells: boolean;
|
|
1412
|
-
/** When true, show only rows flagged for deletion (bin mode). All other filters are bypassed. */
|
|
1413
|
-
showOnlyDeletedRows: boolean;
|
|
1414
|
-
filterColumns: string[] | null;
|
|
1415
|
-
/** Per-column value filters. Key = column ID, value = allowed display-formatted strings. */
|
|
1416
|
-
columnValueFilters: Record<string, string[]>;
|
|
1417
|
-
/** Per-column numeric range filters. Key = column ID. */
|
|
1418
|
-
columnRangeFilters: Record<string, {
|
|
1419
|
-
min?: number;
|
|
1420
|
-
max?: number;
|
|
1421
|
-
}>;
|
|
1422
|
-
/** Per-column date range filters. Key = column ID, values are ISO date strings (YYYY-MM-DD). */
|
|
1423
|
-
columnDateRangeFilters: Record<string, {
|
|
1424
|
-
min?: string;
|
|
1425
|
-
max?: string;
|
|
1426
|
-
}>;
|
|
1427
|
-
};
|
|
1428
|
-
|
|
1429
|
-
/**
|
|
1430
|
-
* A single operation the LLM wants to apply to rows in the current filtered view.
|
|
1804
|
+
* Stores validation results in a two-level map: rowId → fieldId → ValidationResult[].
|
|
1805
|
+
* Maintains a running error count and a pre-computed row-level set
|
|
1806
|
+
* (_rowsWithErrors) for O(1) "does this row have errors?" checks.
|
|
1431
1807
|
*
|
|
1432
|
-
*
|
|
1433
|
-
*
|
|
1434
|
-
*
|
|
1435
|
-
*
|
|
1436
|
-
|
|
1437
|
-
type ChatOp = {
|
|
1438
|
-
action: "edit";
|
|
1439
|
-
fn: string;
|
|
1440
|
-
} | {
|
|
1441
|
-
action: "delete";
|
|
1442
|
-
fn: string;
|
|
1443
|
-
};
|
|
1444
|
-
/**
|
|
1445
|
-
* A single chunk in the stream returned from `DataEditorChat.onMessage`.
|
|
1808
|
+
* The key design decision is the ValidationDelta return type from setCellValidation().
|
|
1809
|
+
* Instead of directly triggering notifications, it returns a delta object describing
|
|
1810
|
+
* what changed (error count +/- 1, row-level error membership flipped).
|
|
1811
|
+
* The caller (DataStore) uses this delta for incremental snapshot count updates,
|
|
1812
|
+
* avoiding a full recount on every validation change.
|
|
1446
1813
|
*
|
|
1447
|
-
*
|
|
1448
|
-
*
|
|
1449
|
-
*
|
|
1450
|
-
* - `ops` — array of per-row operations (edits and/or deletes) to apply in order.
|
|
1814
|
+
* Empty cell tracking (_rowsWithEmptyCells) is separate from validation — it
|
|
1815
|
+
* tracks rows where any visible column has a null/empty value, used by the
|
|
1816
|
+
* "show only rows with empty cells" filter.
|
|
1451
1817
|
*/
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
type: "message";
|
|
1457
|
-
content: string;
|
|
1458
|
-
} | {
|
|
1459
|
-
type: "rows";
|
|
1460
|
-
content: TRow[];
|
|
1461
|
-
} | {
|
|
1462
|
-
type: "ops";
|
|
1463
|
-
content: ChatOp[];
|
|
1818
|
+
|
|
1819
|
+
type ValidationDelta = {
|
|
1820
|
+
errorDelta: number;
|
|
1821
|
+
rowErrorChanged: boolean;
|
|
1464
1822
|
};
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1823
|
+
type IValidationStore = {
|
|
1824
|
+
setCellValidation(rowId: TRowId, field: string, result: ValidationResult): ValidationDelta;
|
|
1825
|
+
getCellValidation(rowId: TRowId, field: string): ValidationResult;
|
|
1826
|
+
clearRowValidations(rowId: TRowId): void;
|
|
1827
|
+
hasRowErrors(rowId: TRowId): boolean;
|
|
1828
|
+
getRowsWithErrors(): ReadonlySet<TRowId>;
|
|
1829
|
+
getRowsWithEmptyCells(): ReadonlySet<TRowId>;
|
|
1830
|
+
hasEmptyCells(rowId: TRowId): boolean;
|
|
1831
|
+
checkRowEmptyCells(rowId: TRowId, row: Record<string, unknown> | undefined, fieldOrder: string[]): boolean;
|
|
1832
|
+
deleteRowTracking(rowId: TRowId): void;
|
|
1833
|
+
getErrorCount(): number;
|
|
1834
|
+
getRowValidations(rowId: TRowId): Map<string, NonNullable<ValidationResult>> | undefined;
|
|
1835
|
+
getErrorMessageToRows(): ReadonlyMap<string, ReadonlySet<TRowId>>;
|
|
1836
|
+
clear(): void;
|
|
1477
1837
|
};
|
|
1478
|
-
|
|
1479
|
-
type
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1838
|
+
|
|
1839
|
+
type IValidator<TRow extends DataEditorRow = DataEditorRow> = {
|
|
1840
|
+
validateRow(rowId: TRowId): void;
|
|
1841
|
+
validateRows(rows: TRow[], rowIds: TRowId[]): void;
|
|
1842
|
+
validateUniqueness(): Promise<void>;
|
|
1843
|
+
validateCell(rowId: TRowId, field: string, oldValue?: unknown, _visited?: Set<string>): void;
|
|
1844
|
+
revalidateColumn(field: string): void;
|
|
1845
|
+
validateColumn(field: string, oldValues: ReadonlyMap<TRowId, unknown>): void;
|
|
1846
|
+
revalidateColumnChunked(field: string, oldValues: ReadonlyMap<TRowId, unknown>, newValues: ReadonlyMap<TRowId, unknown>, processor: ChunkedProcessor<TRowId>, onComplete: () => void): void;
|
|
1847
|
+
removeRow(rowId: TRowId): void;
|
|
1848
|
+
destroy(): void;
|
|
1488
1849
|
};
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1850
|
+
|
|
1851
|
+
type IValueIndex<TRow extends DataEditorRow = DataEditorRow> = {
|
|
1852
|
+
setTrackedFields(fields: Set<string>): void;
|
|
1853
|
+
addRow(row: TRow): void;
|
|
1854
|
+
removeRow(row: TRow): void;
|
|
1855
|
+
updateField(field: string, oldValue: unknown, newValue: unknown): void;
|
|
1856
|
+
rebuild(rows: Iterable<TRow>): void;
|
|
1857
|
+
getValues(field: string): ReadonlyMap<string, number>;
|
|
1858
|
+
getVersion(): number;
|
|
1859
|
+
isTracked(field: string): boolean;
|
|
1860
|
+
getMinMax(field: string): {
|
|
1861
|
+
min: number;
|
|
1862
|
+
max: number;
|
|
1863
|
+
} | null;
|
|
1864
|
+
getDateMinMax(field: string): {
|
|
1865
|
+
min: string;
|
|
1866
|
+
max: string;
|
|
1867
|
+
} | null;
|
|
1868
|
+
bumpVersion(): void;
|
|
1508
1869
|
};
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1870
|
+
|
|
1871
|
+
type RowEntry<TRow extends DataEditorRow> = {
|
|
1872
|
+
rowId: TRowId;
|
|
1873
|
+
row: TRow;
|
|
1874
|
+
sourceId: DataSourceId;
|
|
1875
|
+
isNew: boolean;
|
|
1876
|
+
isEdited: boolean;
|
|
1877
|
+
isDeleted: boolean;
|
|
1878
|
+
originalRow?: TRow;
|
|
1879
|
+
};
|
|
1880
|
+
type OverlayEntry<TRow extends DataEditorRow> = {
|
|
1881
|
+
rowId: TRowId;
|
|
1882
|
+
displayValue: TRow;
|
|
1516
1883
|
};
|
|
1884
|
+
type SourceSnapshot<TRow extends DataEditorRow> = {
|
|
1885
|
+
state: DataSourceState;
|
|
1886
|
+
ownedRows: RowEntry<TRow>[];
|
|
1887
|
+
overlayRows: OverlayEntry<TRow>[];
|
|
1888
|
+
rowIds: TRowId[];
|
|
1889
|
+
plan: ExtendedRemovalPlan<TRow>;
|
|
1890
|
+
};
|
|
1891
|
+
type SourceLifecycleHost<TRow extends DataEditorRow> = {
|
|
1892
|
+
getValidator: () => IValidator<TRow> | null;
|
|
1893
|
+
pushCommand: (cmd: Command<TRow>, cost?: number) => number;
|
|
1894
|
+
notify: () => void;
|
|
1895
|
+
isServerStrategy: () => boolean;
|
|
1896
|
+
checkRowEmptyCells: (rowId: TRowId) => void;
|
|
1897
|
+
clearRowValidations: (rowId: TRowId) => void;
|
|
1898
|
+
};
|
|
1899
|
+
declare class SourceLifecycle<TRow extends DataEditorRow = DataEditorRow> {
|
|
1900
|
+
private readonly sourceManager;
|
|
1901
|
+
private readonly rowStore;
|
|
1902
|
+
private readonly dirtyTracker;
|
|
1903
|
+
private readonly filterEngine;
|
|
1904
|
+
private readonly valueIndex;
|
|
1905
|
+
private readonly validationStore;
|
|
1906
|
+
private readonly snapshotManager;
|
|
1907
|
+
private readonly host;
|
|
1908
|
+
private readonly importTrackers;
|
|
1909
|
+
constructor(sourceManager: SourceManager<TRow>, rowStore: RowStore<TRow>, dirtyTracker: IDirtyTracker<TRow>, filterEngine: IFilterEngine<TRow>, valueIndex: IValueIndex<TRow>, validationStore: IValidationStore, snapshotManager: SnapshotManager, host: SourceLifecycleHost<TRow>);
|
|
1910
|
+
plan(sourceId: DataSourceId): ExtendedRemovalPlan<TRow> | null;
|
|
1911
|
+
capture(sourceId: DataSourceId): SourceSnapshot<TRow> | null;
|
|
1912
|
+
apply(plan: ExtendedRemovalPlan<TRow>): void;
|
|
1913
|
+
private applyToStores;
|
|
1914
|
+
restore(snapshot: SourceSnapshot<TRow>): void;
|
|
1915
|
+
register(options: RegisterSourceOptions): DataSourceId;
|
|
1916
|
+
trackAppend(sourceId: DataSourceId, rowIds: TRowId[], rows: TRow[], usedIdMap: boolean): void;
|
|
1917
|
+
trackPrimaryKey(sourceId: DataSourceId, primaryKey: keyof TRow): void;
|
|
1918
|
+
finalize(sourceId: DataSourceId): Promise<void>;
|
|
1919
|
+
private pushImportCommandIfTracked;
|
|
1920
|
+
private removeInternal;
|
|
1921
|
+
remove(sourceId: DataSourceId): Promise<SourceSnapshot<TRow> | null>;
|
|
1922
|
+
finalizeAllSources(): void;
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1517
1925
|
/**
|
|
1518
|
-
*
|
|
1519
|
-
* the editor shows a chat panel alongside the grid. You own the AI
|
|
1520
|
-
* integration; the SDK hands you dataset context and renders the streamed
|
|
1521
|
-
* response.
|
|
1926
|
+
* Fill-level delta computations.
|
|
1522
1927
|
*
|
|
1523
|
-
*
|
|
1524
|
-
*
|
|
1525
|
-
*
|
|
1526
|
-
*
|
|
1527
|
-
*
|
|
1528
|
-
*
|
|
1529
|
-
*
|
|
1530
|
-
*
|
|
1531
|
-
*
|
|
1532
|
-
* prompt: context.message,
|
|
1533
|
-
* columns: context.columns,
|
|
1534
|
-
* sample: context.sample.map(r => r.data),
|
|
1535
|
-
* errors: context.errorSummary,
|
|
1536
|
-
* }),
|
|
1537
|
-
* }).then(r => r.json());
|
|
1538
|
-
* yield { type: "rows", content: res.updatedRows };
|
|
1539
|
-
* yield { type: "ops", content: res.ops };
|
|
1540
|
-
* yield { type: "message", content: res.reply };
|
|
1541
|
-
* },
|
|
1542
|
-
* }}
|
|
1543
|
-
* ```
|
|
1928
|
+
* Pure functions that compute ColumnDelta[] for fill handle operations.
|
|
1929
|
+
* Zero side effects — take a spec + row reader, return deltas.
|
|
1930
|
+
*
|
|
1931
|
+
* buildFillSpec() — reads source values once, builds tiling index
|
|
1932
|
+
* computeFillDeltas() — processes a chunk of target rows against the spec
|
|
1933
|
+
*
|
|
1934
|
+
* Fill uses a tiling pattern: source values repeat cyclically.
|
|
1935
|
+
* For row r in fill range: srcRow = r % sourceHeight.
|
|
1936
|
+
* For col c in fill range: srcCol = c % sourceWidth.
|
|
1544
1937
|
*/
|
|
1545
|
-
|
|
1938
|
+
|
|
1939
|
+
type FillSpec = {
|
|
1940
|
+
/** 2D source grid: sourceValues[row][col]. Read once — source region is always small. */
|
|
1941
|
+
sourceValues: unknown[][];
|
|
1942
|
+
sourceHeight: number;
|
|
1943
|
+
sourceWidth: number;
|
|
1944
|
+
/** Column IDs for the fill target columns. */
|
|
1945
|
+
fields: string[];
|
|
1946
|
+
/** Target rowId → position within the fill range, for tiling modulo. */
|
|
1947
|
+
rowIdToFillIndex: ReadonlyMap<TRowId, number>;
|
|
1948
|
+
};
|
|
1949
|
+
|
|
1950
|
+
type FormulaCellContext = {
|
|
1951
|
+
value: unknown;
|
|
1952
|
+
field: string;
|
|
1953
|
+
rowId: TRowId;
|
|
1954
|
+
getField: (field: string) => unknown;
|
|
1546
1955
|
/**
|
|
1547
|
-
*
|
|
1548
|
-
*
|
|
1956
|
+
* Positional arguments for expression-compiled formulas.
|
|
1957
|
+
* Populated by the expression evaluator when invoking multi-arg function
|
|
1958
|
+
* calls. Single-arg formulas (UPPER, TRIM, etc.) still read from `value`.
|
|
1959
|
+
* Undefined for all non-expression call sites — existing code is unaffected.
|
|
1549
1960
|
*/
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1961
|
+
args?: readonly unknown[];
|
|
1962
|
+
};
|
|
1963
|
+
type FormulaParamType = "string" | "number" | "boolean" | "select";
|
|
1964
|
+
type FormulaParam = {
|
|
1965
|
+
name: string;
|
|
1966
|
+
label: string;
|
|
1967
|
+
type: FormulaParamType;
|
|
1968
|
+
required?: boolean;
|
|
1969
|
+
defaultValue?: unknown;
|
|
1970
|
+
options?: Array<{
|
|
1971
|
+
id: string;
|
|
1972
|
+
text: string;
|
|
1973
|
+
}>;
|
|
1974
|
+
};
|
|
1975
|
+
type ColumnInputKind = "single" | "multiple";
|
|
1976
|
+
type ColumnInput = {
|
|
1977
|
+
name: string;
|
|
1978
|
+
label: string;
|
|
1979
|
+
kind: ColumnInputKind;
|
|
1980
|
+
required?: boolean;
|
|
1981
|
+
};
|
|
1982
|
+
type FormulaCategory = "text" | "number" | "logic" | "custom";
|
|
1983
|
+
type FormulaArity = {
|
|
1984
|
+
/** Minimum number of positional arguments. 0 means "callable with no args". */
|
|
1985
|
+
min: number;
|
|
1986
|
+
/** Maximum number of positional arguments. Use Number.POSITIVE_INFINITY for variadic. */
|
|
1987
|
+
max: number;
|
|
1988
|
+
};
|
|
1989
|
+
type FormulaBase = {
|
|
1990
|
+
name: string;
|
|
1991
|
+
label: string;
|
|
1992
|
+
category: FormulaCategory;
|
|
1993
|
+
description?: string;
|
|
1994
|
+
columns?: ColumnInput[];
|
|
1995
|
+
params: FormulaParam[];
|
|
1557
1996
|
/**
|
|
1558
|
-
*
|
|
1559
|
-
*
|
|
1560
|
-
*
|
|
1997
|
+
* The call signature of this formula when invoked from the expression
|
|
1998
|
+
* language. Required. For shortcut formulas (UPPER, TRIM, ...) use
|
|
1999
|
+
* { min: 1, max: 1 }. For CLEAR use { min: 0, max: 0 }. For MERGE use
|
|
2000
|
+
* { min: 2, max: Number.POSITIVE_INFINITY }.
|
|
1561
2001
|
*/
|
|
1562
|
-
|
|
1563
|
-
/**
|
|
1564
|
-
|
|
1565
|
-
};
|
|
1566
|
-
|
|
1567
|
-
type ApplyFormulaOptions = {
|
|
2002
|
+
arity: FormulaArity;
|
|
2003
|
+
/** Parameter signature shown in autocomplete, without the function name. e.g. "(text, count)" */
|
|
2004
|
+
syntax?: string;
|
|
1568
2005
|
/**
|
|
1569
|
-
*
|
|
1570
|
-
*
|
|
1571
|
-
*
|
|
1572
|
-
*
|
|
1573
|
-
* every change, regardless of how many columns were listed.
|
|
2006
|
+
* Whether this formula may be invoked from the expression parser.
|
|
2007
|
+
* Defaults to true when omitted. MERGE and SPLIT set this to false
|
|
2008
|
+
* because they have dedicated modals that supply their non-expression
|
|
2009
|
+
* params (column lists, separator, ...).
|
|
1574
2010
|
*/
|
|
1575
|
-
|
|
2011
|
+
expressionCallable?: boolean;
|
|
1576
2012
|
};
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
private
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
2013
|
+
type CellFormula = FormulaBase & {
|
|
2014
|
+
kind: "cell";
|
|
2015
|
+
compute: (ctx: FormulaCellContext, params: Record<string, unknown>) => unknown;
|
|
2016
|
+
};
|
|
2017
|
+
type RowFormula = FormulaBase & {
|
|
2018
|
+
kind: "row";
|
|
2019
|
+
targetFields: (params: Record<string, unknown>) => string[];
|
|
2020
|
+
compute: (ctx: FormulaCellContext, params: Record<string, unknown>) => Record<string, unknown>;
|
|
2021
|
+
};
|
|
2022
|
+
type FormulaDefinition = CellFormula | RowFormula;
|
|
2023
|
+
|
|
2024
|
+
declare class FormulaRegistry {
|
|
2025
|
+
private readonly formulas;
|
|
2026
|
+
register(formula: FormulaDefinition): void;
|
|
2027
|
+
get(name: string): FormulaDefinition | undefined;
|
|
2028
|
+
getAll(): FormulaDefinition[];
|
|
2029
|
+
getByCategory(category: string): FormulaDefinition[];
|
|
2030
|
+
getExpressionCallable(): FormulaDefinition[];
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
/**
|
|
2034
|
+
* Paste-level delta computations.
|
|
2035
|
+
*
|
|
2036
|
+
* Pure functions that compute ColumnDelta[] for paste operations.
|
|
2037
|
+
* Zero side effects — take a spec + row reader, return deltas.
|
|
2038
|
+
*
|
|
2039
|
+
* buildPasteSpec() — pre-resolves the source→target row mapping and column metadata
|
|
2040
|
+
* computePasteDeltas() — processes a chunk of target rows against the spec
|
|
2041
|
+
*
|
|
2042
|
+
* Designed for the same chunked execution pattern as columnTransforms:
|
|
2043
|
+
* - DataStore builds the spec once
|
|
2044
|
+
* - Small datasets: call computePasteDeltas() once with all target rows
|
|
2045
|
+
* - Large datasets: orchestrator calls computePasteDeltas() per chunk
|
|
2046
|
+
*/
|
|
2047
|
+
|
|
2048
|
+
type PasteSpec = {
|
|
2049
|
+
sourceColumnIds: string[];
|
|
2050
|
+
targetColumnIds: string[];
|
|
2051
|
+
targetToSource: ReadonlyMap<TRowId, TRowId>;
|
|
2052
|
+
selectOptionsMap: ReadonlyMap<string, ReadonlySet<string>>;
|
|
2053
|
+
skipColumnIndices: ReadonlySet<number>;
|
|
2054
|
+
isCut: boolean;
|
|
2055
|
+
};
|
|
2056
|
+
|
|
2057
|
+
/**
|
|
2058
|
+
* A single operation the LLM wants to apply to rows in the current filtered view.
|
|
2059
|
+
*
|
|
2060
|
+
* - `edit` — `fn` is `(r, ctx) => void`. Mutates `r` in place. Changed fields
|
|
2061
|
+
* become column deltas. Rows with no changes are no-ops.
|
|
2062
|
+
* - `delete` — `fn` is `(r, ctx) => boolean`. Truthy means "flag this row for
|
|
2063
|
+
* deletion". Soft delete via `DeleteRowCommand`.
|
|
2064
|
+
*/
|
|
2065
|
+
type ChatOp = {
|
|
2066
|
+
action: "edit";
|
|
2067
|
+
fn: string;
|
|
2068
|
+
} | {
|
|
2069
|
+
action: "delete";
|
|
2070
|
+
fn: string;
|
|
2071
|
+
};
|
|
2072
|
+
/**
|
|
2073
|
+
* A single chunk in the stream returned from `DataEditorChat.onMessage`.
|
|
2074
|
+
*
|
|
2075
|
+
* - `status` — progress message shown while processing (e.g. "Analyzing 500 rows...").
|
|
2076
|
+
* - `message` — chat reply shown to the user.
|
|
2077
|
+
* - `rows` — updated rows to apply to the grid. Matched by `primaryKey`.
|
|
2078
|
+
* - `ops` — array of per-row operations (edits and/or deletes) to apply in order.
|
|
2079
|
+
*/
|
|
2080
|
+
type ChatResponseChunk<TRow extends DataEditorRow = DataEditorRow> = {
|
|
2081
|
+
type: "status";
|
|
2082
|
+
content: string;
|
|
2083
|
+
} | {
|
|
2084
|
+
type: "message";
|
|
2085
|
+
content: string;
|
|
2086
|
+
} | {
|
|
2087
|
+
type: "rows";
|
|
2088
|
+
content: TRow[];
|
|
2089
|
+
} | {
|
|
2090
|
+
type: "ops";
|
|
2091
|
+
content: ChatOp[];
|
|
2092
|
+
};
|
|
2093
|
+
/** Status of a row in the chat sample, relative to its origin snapshot. */
|
|
2094
|
+
type ChatRowStatus = "new" | "edited" | "original";
|
|
2095
|
+
/** A sample row handed to the chat callback, with its current status and validation errors. */
|
|
2096
|
+
type ChatRow<TRow extends DataEditorRow = DataEditorRow> = {
|
|
2097
|
+
/** Row data keyed by column ID. */
|
|
2098
|
+
data: TRow;
|
|
2099
|
+
/** Whether the row was newly added, edited, or is unchanged. */
|
|
2100
|
+
status: ChatRowStatus;
|
|
2101
|
+
/** Validation errors keyed by column ID. */
|
|
2102
|
+
errors: Record<string, string[]>;
|
|
2103
|
+
/** The source this row belongs to. */
|
|
2104
|
+
source: string;
|
|
2105
|
+
};
|
|
2106
|
+
/** Aggregated error count across the current view, grouped by field and message. */
|
|
2107
|
+
type ChatErrorSummary = {
|
|
2108
|
+
/** Column ID where the error occurred. */
|
|
2109
|
+
field: string;
|
|
2110
|
+
/** The validation message. */
|
|
2111
|
+
message: string;
|
|
2112
|
+
/** How many rows hit this error. */
|
|
2113
|
+
count: number;
|
|
2114
|
+
/** A few example values that triggered the error. */
|
|
2115
|
+
examples: string[];
|
|
2116
|
+
};
|
|
2117
|
+
/**
|
|
2118
|
+
* Context about the current dataset, passed to `loadSuggestions` and extended
|
|
2119
|
+
* into `ChatContext` for `onMessage`.
|
|
2120
|
+
*/
|
|
2121
|
+
type ChatDataContext<TRow extends DataEditorRow = DataEditorRow> = {
|
|
2122
|
+
/** Full column definitions. */
|
|
2123
|
+
columns: DataEditorColumn[];
|
|
2124
|
+
/** Row identifier field. */
|
|
2125
|
+
primaryKey: keyof TRow;
|
|
2126
|
+
/** Total rows in the dataset. */
|
|
2127
|
+
totalRowCount: number;
|
|
2128
|
+
/** Rows in the current filtered view. */
|
|
2129
|
+
filteredRowCount: number;
|
|
2130
|
+
/** Sample rows, with status and errors. Size controlled by `sampleSize`. */
|
|
2131
|
+
sample: ChatRow<TRow>[];
|
|
2132
|
+
/** Aggregated error counts by field and message. */
|
|
2133
|
+
errorSummary: ChatErrorSummary[];
|
|
2134
|
+
/** Access all rows. Use for full-dataset operations. */
|
|
2135
|
+
getRows: () => ChatRow<TRow>[];
|
|
2136
|
+
};
|
|
2137
|
+
/**
|
|
2138
|
+
* The full context passed to `DataEditorChat.onMessage` when the user sends
|
|
2139
|
+
* a prompt. Includes the prompt itself and all dataset context.
|
|
2140
|
+
*/
|
|
2141
|
+
type ChatContext<TRow extends DataEditorRow = DataEditorRow> = ChatDataContext<TRow> & {
|
|
2142
|
+
/** The user's chat prompt. */
|
|
2143
|
+
message: string;
|
|
2144
|
+
};
|
|
2145
|
+
/**
|
|
2146
|
+
* Bring-your-own-AI chat configuration. When provided via the `chat` prop,
|
|
2147
|
+
* the editor shows a chat panel alongside the grid. You own the AI
|
|
2148
|
+
* integration; the SDK hands you dataset context and renders the streamed
|
|
2149
|
+
* response.
|
|
2150
|
+
*
|
|
2151
|
+
* @example
|
|
2152
|
+
* ```ts
|
|
2153
|
+
* chat={{
|
|
2154
|
+
* sampleSize: 50,
|
|
2155
|
+
* onMessage: async function* (context) {
|
|
2156
|
+
* yield { type: "status", content: "Thinking..." };
|
|
2157
|
+
* const res = await fetch("/api/ai", {
|
|
2158
|
+
* method: "POST",
|
|
2159
|
+
* body: JSON.stringify({
|
|
2160
|
+
* prompt: context.message,
|
|
2161
|
+
* columns: context.columns,
|
|
2162
|
+
* sample: context.sample.map(r => r.data),
|
|
2163
|
+
* errors: context.errorSummary,
|
|
2164
|
+
* }),
|
|
2165
|
+
* }).then(r => r.json());
|
|
2166
|
+
* yield { type: "rows", content: res.updatedRows };
|
|
2167
|
+
* yield { type: "ops", content: res.ops };
|
|
2168
|
+
* yield { type: "message", content: res.reply };
|
|
2169
|
+
* },
|
|
2170
|
+
* }}
|
|
2171
|
+
* ```
|
|
2172
|
+
*/
|
|
2173
|
+
type DataEditorChat<TRow extends DataEditorRow = DataEditorRow> = {
|
|
2174
|
+
/**
|
|
2175
|
+
* How many rows to include in the context sample. The SDK picks a
|
|
2176
|
+
* representative slice including rows with errors. When omitted, the SDK decides.
|
|
2177
|
+
*/
|
|
2178
|
+
sampleSize?: number;
|
|
2179
|
+
/** Title shown above the suggestion list when the chat is empty. */
|
|
2180
|
+
emptyTitle?: string;
|
|
2181
|
+
/** How many suggestions to request from `loadSuggestions`. */
|
|
2182
|
+
suggestionsCount?: number;
|
|
2183
|
+
/** Optional prompt generator for the empty-state suggestion chips. */
|
|
2184
|
+
loadSuggestions?: (context: ChatDataContext<TRow>) => Promise<string[]>;
|
|
2185
|
+
/**
|
|
2186
|
+
* Called when the user sends a message. Receives full dataset context.
|
|
2187
|
+
* Returns an async iterable of response chunks — the SDK streams them
|
|
2188
|
+
* into the UI.
|
|
2189
|
+
*/
|
|
2190
|
+
onMessage: (context: ChatContext<TRow>) => AsyncIterable<ChatResponseChunk<TRow>>;
|
|
2191
|
+
/** Called when the user cancels a pending request. Use to abort your API call. */
|
|
2192
|
+
onCancel?: () => void;
|
|
2193
|
+
};
|
|
2194
|
+
|
|
2195
|
+
type ApplyFormulaOptions = {
|
|
2196
|
+
/**
|
|
2197
|
+
* Column IDs to delete AFTER the formula has been applied.
|
|
2198
|
+
* Only dynamic (user-added) columns are actually deleted; schema columns
|
|
2199
|
+
* in this list are silently ignored. All operations (formula + deletes)
|
|
2200
|
+
* are wrapped in a single CompoundCommand so that one Undo call restores
|
|
2201
|
+
* every change, regardless of how many columns were listed.
|
|
2202
|
+
*/
|
|
2203
|
+
readonly deleteColumnsAfter?: readonly string[];
|
|
2204
|
+
};
|
|
2205
|
+
declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
|
|
2206
|
+
private readonly _mode;
|
|
2207
|
+
isServer(): boolean;
|
|
2208
|
+
isClient(): boolean;
|
|
2209
|
+
private rowStore;
|
|
2210
|
+
readonly formulaRegistry: FormulaRegistry;
|
|
2211
|
+
private _isLoading;
|
|
2212
|
+
private sourceManager;
|
|
2213
|
+
readonly sourceLifecycle: SourceLifecycle<TRow>;
|
|
2214
|
+
private dirtyTracker;
|
|
2215
|
+
private filterEngine;
|
|
2216
|
+
private validationStore;
|
|
2217
|
+
private snapshotManager;
|
|
2218
|
+
private history;
|
|
2219
|
+
private validator;
|
|
2220
|
+
private valueIndex;
|
|
2221
|
+
private serverCounts;
|
|
2222
|
+
private editBuilder;
|
|
2223
|
+
private isUndoRedoing;
|
|
2224
|
+
private pendingBatchCommands;
|
|
2225
|
+
private _version;
|
|
2226
|
+
private _skipNotify;
|
|
2227
|
+
private _bulkMode;
|
|
2228
|
+
private _editedCells;
|
|
2229
|
+
private _primaryKey;
|
|
2230
|
+
/** Columns that are currently locked (pre-locked from schema + user-locked at runtime). */
|
|
2231
|
+
private _lockedColumns;
|
|
2232
|
+
/** Columns locked via schema definition — user cannot unlock these. */
|
|
2233
|
+
private _preLockedColumns;
|
|
2234
|
+
/** Last-known visible row range reported by the canvas scroll handler. */
|
|
2235
|
+
private _viewportStart;
|
|
2236
|
+
private _viewportEnd;
|
|
2237
|
+
private pendingMutations;
|
|
2238
|
+
private editParamsHistory;
|
|
2239
|
+
readonly errorHandler: ErrorHandler;
|
|
2240
|
+
readonly server: ServerDataManager<TRow> | null;
|
|
2241
|
+
private readonly strategy;
|
|
2242
|
+
private readonly serverStrategy;
|
|
2243
|
+
private snapshotReader;
|
|
1616
2244
|
private flagReader;
|
|
1617
2245
|
private buildErrorBitmask;
|
|
1618
2246
|
private buildEditedBitmask;
|
|
@@ -1627,7 +2255,7 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
|
|
|
1627
2255
|
private bulkMutationHost;
|
|
1628
2256
|
private orchestrator;
|
|
1629
2257
|
constructor(mode?: StoreMode, serverInit?: {
|
|
1630
|
-
config:
|
|
2258
|
+
config: ScaleClientApi<TRow>;
|
|
1631
2259
|
sourceLabel: string;
|
|
1632
2260
|
}, errorHandler?: ErrorHandler);
|
|
1633
2261
|
get mode(): StoreMode;
|
|
@@ -1803,726 +2431,164 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
|
|
|
1803
2431
|
* from `meta.changes` so that `isCellDirty()` and `getOriginalCellValue()`
|
|
1804
2432
|
* work through the existing DirtyTracker comparison logic.
|
|
1805
2433
|
*/
|
|
1806
|
-
private hydrateServerMeta;
|
|
1807
|
-
private hydrateRowMeta;
|
|
1808
|
-
applyServerRowMeta(serverRows: ServerRow<TRow>[], counts?: ServerQueryCounts): void;
|
|
1809
|
-
clear(): void;
|
|
1810
|
-
destroy(): void;
|
|
1811
|
-
setFilters(filters: Partial<Filters>): void;
|
|
1812
|
-
getFilters(): Filters;
|
|
1813
|
-
setSort(sortState: SortState, sortType?: SortType, locales?: string[]): Promise<void>;
|
|
1814
|
-
handleServerScroll(visibleStart: number, visibleEnd: number): void;
|
|
1815
|
-
reloadServerData(): void;
|
|
1816
|
-
resetFilters(): void;
|
|
1817
|
-
fetchFilterOptions(): void;
|
|
1818
|
-
getFilterOptions(): FilterOptionsResponse | null;
|
|
1819
|
-
get hasServerExport(): boolean;
|
|
1820
|
-
serverExport(format: DataEditorFormat, allRows: boolean, rtl: boolean): Promise<void>;
|
|
1821
|
-
syncWorkerFlags(): void;
|
|
1822
|
-
setCellValidation(rowId: TRowId, field: string, result: ValidationResult): void;
|
|
1823
|
-
getCellValidation(rowId: TRowId, field: string): ValidationResult;
|
|
1824
|
-
private clearRowValidations;
|
|
1825
|
-
updateRow(rowId: TRowId, field: string, value: unknown): void;
|
|
1826
|
-
updateRowDirect(rowId: TRowId, field: string, value: unknown): void;
|
|
1827
|
-
/**
|
|
1828
|
-
* Bulk-write a single column for many rows in one pass.
|
|
1829
|
-
* Skips per-row validation, notification, and snapshot adjustments.
|
|
1830
|
-
* Caller must handle validation (via Validator.revalidateColumn) and notification.
|
|
1831
|
-
*/
|
|
1832
|
-
updateColumnDirect(field: string, values: ReadonlyMap<TRowId, unknown>): void;
|
|
1833
|
-
batch(fn: () => void): number | undefined;
|
|
1834
|
-
canUndo(): boolean;
|
|
1835
|
-
getAllRowIds(): readonly TRowId[];
|
|
1836
|
-
undo(): Promise<UndoRedoResult>;
|
|
1837
|
-
private _undoSync;
|
|
1838
|
-
pushCommand(cmd: Command<TRow>, cost?: number): number;
|
|
1839
|
-
removeCommandById(id: number): void;
|
|
1840
|
-
/**
|
|
1841
|
-
* Delegate to ServerStrategy. Called by ActionsDispatcher and ClipboardManager
|
|
1842
|
-
* for non-cell edits (clear, paste, fill, transform).
|
|
1843
|
-
*/
|
|
1844
|
-
syncServerEdit(params: EditParams, cmdId: number, revertFn: () => void): void;
|
|
1845
|
-
fireServerEditParams(params: EditParams): void;
|
|
1846
|
-
syncColumnEdit(params: ColumnEditParams, cmdId: number, revertFn: () => void): void;
|
|
1847
|
-
redo(): Promise<UndoRedoResult>;
|
|
1848
|
-
private _redoSync;
|
|
1849
|
-
getOriginalCellValue(rowId: TRowId, field: string): unknown | undefined;
|
|
1850
|
-
isCellDirty(rowId: TRowId, field: string): boolean;
|
|
1851
|
-
hasRowErrors(rowId: TRowId): boolean;
|
|
1852
|
-
hasEmptyCells(rowId: TRowId): boolean;
|
|
1853
|
-
private checkRowEmptyCells;
|
|
1854
|
-
getValidAndInvalidRows(): {
|
|
1855
|
-
valid: TRow[];
|
|
1856
|
-
invalid: TRow[];
|
|
1857
|
-
};
|
|
1858
|
-
getValidRows(): TRow[];
|
|
1859
|
-
getInvalidRows(): TRow[];
|
|
1860
|
-
getResultBySource(): DataEditorResult<TRow>;
|
|
1861
|
-
private isRowVisible;
|
|
1862
|
-
applyFormula(formulaOrName: string | CellFormula, params: Record<string, unknown>, rects: SelectionRect[], options?: ApplyFormulaOptions): Promise<void>;
|
|
1863
|
-
private applyFormulaCompound;
|
|
1864
|
-
private runFormulaWithReturnCommand;
|
|
1865
|
-
private _runFormulaOperation;
|
|
1866
|
-
private captureDeleteColumnSnapshots;
|
|
1867
|
-
private applyDeleteColumnSnapshots;
|
|
1868
|
-
private syncFormulaToServer;
|
|
1869
|
-
private transformWorker;
|
|
1870
|
-
private initTransformWorker;
|
|
1871
|
-
private buildChatOpsCommand;
|
|
1872
|
-
applyChatOps(ops: ChatOp[], ctx: {
|
|
1873
|
-
opts: Record<string, Set<string>>;
|
|
1874
|
-
}, enableDeleteRow: 'all' | 'new' | false): Promise<void>;
|
|
1875
|
-
private filterDeleteIdsByPolicy;
|
|
1876
|
-
private _applyChatOpsViaWorker;
|
|
1877
|
-
private _applyChatOpsSync;
|
|
1878
|
-
private _commitChatOps;
|
|
1879
|
-
applyChatRows(incomingRows: Record<string, unknown>[], primaryKey: string): Promise<void>;
|
|
1880
|
-
private syncChatTransformToServer;
|
|
1881
|
-
private get revertRowReader();
|
|
1882
|
-
revertColumns(fields: string[]): Promise<void>;
|
|
1883
|
-
revertRange(rects: SelectionRect[]): Promise<void>;
|
|
1884
|
-
private _revertInternal;
|
|
1885
|
-
private _buildRevertCommand;
|
|
1886
|
-
private syncRevertToServer;
|
|
1887
|
-
clearColumn(field: string): Promise<void>;
|
|
1888
|
-
clearColumns(fields: string[]): Promise<void>;
|
|
1889
|
-
private syncClearToServer;
|
|
1890
|
-
deleteColumn(columnId: string): Promise<void>;
|
|
1891
|
-
deleteColumns(columnIds: readonly string[]): Promise<void>;
|
|
1892
|
-
clearRange(rects: SelectionRect[]): Promise<void>;
|
|
1893
|
-
private syncRangeClearToServer;
|
|
1894
|
-
pasteChunked(spec: PasteSpec, targetRowIds: TRowId[], targetCell: {
|
|
1895
|
-
rowId: TRowId;
|
|
1896
|
-
field: string;
|
|
1897
|
-
}, onComplete?: (cmdId: number) => void): void;
|
|
1898
|
-
/**
|
|
1899
|
-
* Store-owned paste: cost-gated sync path or chunked orchestrator.
|
|
1900
|
-
* Replaces executePasteWithOverlay + pasteChunked for internal-clipboard paste.
|
|
1901
|
-
*/
|
|
1902
|
-
pasteInternal(spec: PasteSpec, targetRowIds: TRowId[], targetCell: {
|
|
1903
|
-
rowId: TRowId;
|
|
1904
|
-
field: string;
|
|
1905
|
-
}, validator?: IValidator<TRow>): Promise<{
|
|
1906
|
-
cmdId: number;
|
|
1907
|
-
} | null>;
|
|
1908
|
-
/**
|
|
1909
|
-
* Store-owned external paste from TSV text (OS clipboard).
|
|
1910
|
-
* Replaces the pasteFromText helper in pasteUtils.
|
|
1911
|
-
*/
|
|
1912
|
-
pasteFromText(text: string, pasteRow: number, pasteCol: number, validator?: IValidator<TRow>): Promise<{
|
|
1913
|
-
cmdId: number;
|
|
1914
|
-
} | null>;
|
|
1915
|
-
/**
|
|
1916
|
-
* Store-owned fill: cost-gated sync path or chunked orchestrator.
|
|
1917
|
-
* Replaces fillChunked + the per-caller isHeavy heuristic in ActionsDispatcher.
|
|
1918
|
-
*/
|
|
1919
|
-
fillInternal(spec: FillSpec, targetRowIds: TRowId[], targetCell: {
|
|
1920
|
-
rowId: TRowId;
|
|
1921
|
-
field: string;
|
|
1922
|
-
}, onComplete?: (cmdId: number) => void): Promise<{
|
|
1923
|
-
cmdId: number;
|
|
1924
|
-
} | null>;
|
|
1925
|
-
notify(): void;
|
|
1926
|
-
}
|
|
1927
|
-
|
|
1928
|
-
/**
|
|
1929
|
-
* Command interface for undo/redo operations.
|
|
1930
|
-
* Each command knows how to apply and revert its changes.
|
|
1931
|
-
*/
|
|
1932
|
-
interface Command<TRow extends DataEditorRow = DataEditorRow> {
|
|
1933
|
-
/** Assigned by CommandHistory.push(). Used by removeById() to target specific commands. */
|
|
1934
|
-
id?: number;
|
|
1935
|
-
redo(store: DataStore<TRow>, validator: IValidator<TRow>): void;
|
|
1936
|
-
undo(store: DataStore<TRow>, validator: IValidator<TRow>): void;
|
|
1937
|
-
readonly description: string;
|
|
1938
|
-
/** Target cell for selection restoration on undo/redo */
|
|
1939
|
-
readonly targetCell: CellLocation;
|
|
1940
|
-
}
|
|
1941
|
-
|
|
1942
|
-
/**
|
|
1943
|
-
* BulkMutationOrchestrator — Viewport-first chunked execution for heavy
|
|
1944
|
-
* column operations (split, merge, clear, paste, fill, backspace).
|
|
1945
|
-
*
|
|
1946
|
-
* When operation cost >= LARGE_OP_CELLS:
|
|
1947
|
-
* 1. Viewport rows are applied synchronously (instant visual result)
|
|
1948
|
-
* 2. Remaining rows are processed in chunks via requestIdleCallback
|
|
1949
|
-
* 3. Validation runs chunked after all mutations complete
|
|
1950
|
-
* 4. Command is pushed to history only after everything finishes
|
|
1951
|
-
*
|
|
1952
|
-
* Communicates with DataStore via BulkMutationHost interface to avoid
|
|
1953
|
-
* circular imports. DataStore constructs the host from its own methods.
|
|
1954
|
-
*/
|
|
1955
|
-
|
|
1956
|
-
type ColumnDelta = {
|
|
1957
|
-
field: string;
|
|
1958
|
-
oldValues: Map<TRowId, unknown>;
|
|
1959
|
-
newValues: Map<TRowId, unknown>;
|
|
1960
|
-
};
|
|
1961
|
-
|
|
1962
|
-
/** Severity level for a validation message. */
|
|
1963
|
-
type ValidationLevel = "error";
|
|
1964
|
-
/**
|
|
1965
|
-
* A single validation message attached to a cell.
|
|
1966
|
-
* Return this from a `CellValidator` to flag a problem.
|
|
1967
|
-
*/
|
|
1968
|
-
type ValidationError = {
|
|
1969
|
-
level: ValidationLevel;
|
|
1970
|
-
/** Human-readable message shown in the cell tooltip. */
|
|
1971
|
-
message: string;
|
|
1972
|
-
};
|
|
1973
|
-
type ValidationResult = ValidationError[] | null;
|
|
1974
|
-
/**
|
|
1975
|
-
* A function that validates a single cell value.
|
|
1976
|
-
* Return a `ValidationError` to flag a problem, or `null` if the value is valid.
|
|
1977
|
-
*
|
|
1978
|
-
* A `ValidationError` with `level: "error"` flags the cell in the grid but
|
|
1979
|
-
* does not block submission — invalid rows are delivered to `onComplete`
|
|
1980
|
-
* alongside valid ones, tagged via the `isValid` flag.
|
|
1981
|
-
*
|
|
1982
|
-
* Built-in validator factories: `required(msg)`, `numeric(msg)`, `email(msg)`,
|
|
1983
|
-
* `date(msg)`, `oneOf(values, msg)`, `endDateAfterStart(startField, msg)`.
|
|
1984
|
-
* Import them from the package root.
|
|
1985
|
-
*
|
|
1986
|
-
* @param value - The current cell value.
|
|
1987
|
-
* @param row - The full row, useful for cross-field checks.
|
|
1988
|
-
*/
|
|
1989
|
-
type CellValidator = (value: unknown, row: DataEditorRow) => ValidationError | null;
|
|
1990
|
-
/** Text input cell. This is the default editor when no `editor` is specified. */
|
|
1991
|
-
type TextEditorCell = {
|
|
1992
|
-
type: "text";
|
|
1993
|
-
};
|
|
1994
|
-
/** Date picker cell. Optionally restrict the selectable date range. */
|
|
1995
|
-
type DateEditorCell = {
|
|
1996
|
-
type: "date";
|
|
1997
|
-
/** Earliest selectable date. */
|
|
1998
|
-
minDate?: Date;
|
|
1999
|
-
/** Latest selectable date. */
|
|
2000
|
-
maxDate?: Date;
|
|
2001
|
-
};
|
|
2002
|
-
/** Dropdown select cell. The user picks from a fixed list of options. */
|
|
2003
|
-
type SelectEditorCell = {
|
|
2004
|
-
type: "select";
|
|
2005
|
-
/** The list of options shown in the dropdown. Each string is both the stored value and the display label. */
|
|
2006
|
-
options: string[];
|
|
2007
|
-
};
|
|
2008
|
-
/** Number input cell with locale-aware formatting. */
|
|
2009
|
-
type NumberEditorCell = {
|
|
2010
|
-
type: "number";
|
|
2011
|
-
/** Maximum number of decimal digits allowed. When omitted, decimals are unrestricted. */
|
|
2012
|
-
decimalPlaces?: number;
|
|
2013
|
-
/** Character used as the decimal point (e.g. `"."` or `","`). Defaults to the browser locale. */
|
|
2014
|
-
decimalSeparator?: string;
|
|
2015
|
-
/** Character inserted between groups of three digits (e.g. `","` or `"."`). Defaults to the browser locale. */
|
|
2016
|
-
thousandsSeparator?: string;
|
|
2017
|
-
/** Extra characters to allow beyond digits, decimal separator, and minus sign (e.g. `"%-"`). When defined, minus is only kept if explicitly included. */
|
|
2018
|
-
allowChars?: string;
|
|
2019
|
-
};
|
|
2020
|
-
/**
|
|
2021
|
-
* Controls how a cell is edited.
|
|
2022
|
-
*
|
|
2023
|
-
* - `"text"` — plain text input (default).
|
|
2024
|
-
* - `"date"` — date picker with optional min/max bounds.
|
|
2025
|
-
* - `"select"` — dropdown with a fixed list of options.
|
|
2026
|
-
* - `"number"` — number input with locale-aware formatting.
|
|
2027
|
-
*/
|
|
2028
|
-
type CellEditor = TextEditorCell | DateEditorCell | SelectEditorCell | NumberEditorCell;
|
|
2029
|
-
/** Dropdown filter shown in the sidebar Filters panel. */
|
|
2030
|
-
type SelectColumnFilter = {
|
|
2031
|
-
type: "select";
|
|
2032
|
-
/** Label displayed above the filter. */
|
|
2033
|
-
label?: string;
|
|
2034
|
-
/** Placeholder text when nothing is selected. */
|
|
2035
|
-
placeholder?: string;
|
|
2036
|
-
/** Fixed list of filter options. When omitted, options are derived from column values. */
|
|
2037
|
-
options?: string[];
|
|
2038
|
-
/** Allow selecting multiple values at once. */
|
|
2039
|
-
multiple?: boolean;
|
|
2040
|
-
};
|
|
2041
|
-
/** Numeric min/max range filter shown in the sidebar Filters panel. */
|
|
2042
|
-
type NumberRangeColumnFilter = {
|
|
2043
|
-
type: "number-range";
|
|
2044
|
-
/** Label displayed above the filter. */
|
|
2045
|
-
label?: string;
|
|
2046
|
-
};
|
|
2047
|
-
/** Date min/max range filter shown in the sidebar Filters panel. */
|
|
2048
|
-
type DateRangeColumnFilter = {
|
|
2049
|
-
type: "date-range";
|
|
2050
|
-
/** Label displayed above the filter. */
|
|
2051
|
-
label?: string;
|
|
2052
|
-
};
|
|
2053
|
-
/**
|
|
2054
|
-
* Filter control shown in the sidebar Filters panel for a column.
|
|
2055
|
-
*
|
|
2056
|
-
* - `"select"` — dropdown to pick one or more values.
|
|
2057
|
-
* - `"number-range"` — two inputs for min and max number.
|
|
2058
|
-
* - `"date-range"` — two date pickers for start and end date.
|
|
2059
|
-
*/
|
|
2060
|
-
type ColumnFilter = SelectColumnFilter | NumberRangeColumnFilter | DateRangeColumnFilter;
|
|
2061
|
-
/** Lock mode for a column. `"all"` locks for every row; `"default"` locks only default-source rows. */
|
|
2062
|
-
type ColumnLockMode = "all" | "default";
|
|
2063
|
-
/**
|
|
2064
|
-
* Defines a column in the editor grid.
|
|
2065
|
-
*
|
|
2066
|
-
* @example
|
|
2067
|
-
* ```ts
|
|
2068
|
-
* import { required, email, numeric } from "@updog/data-editor";
|
|
2069
|
-
*
|
|
2070
|
-
* const columns: DataEditorColumn[] = [
|
|
2071
|
-
* { id: "name", title: "Full Name", size: 200, validate: required("Name is required") },
|
|
2072
|
-
* { id: "email", title: "Email", size: 250, validate: [required("Email is required"), email("Invalid email")], unique: true },
|
|
2073
|
-
* { id: "role", title: "Role", editor: { type: "select", options: ["Admin", "Editor", "Viewer"] } },
|
|
2074
|
-
* { id: "salary", title: "Salary", validate: numeric("Must be a number"), formatter: (v) => v ? `$${v}` : "" },
|
|
2075
|
-
* ];
|
|
2076
|
-
* ```
|
|
2077
|
-
*/
|
|
2078
|
-
type DataEditorColumn = {
|
|
2079
|
-
/** Unique column identifier. Must match the keys in your row data. */
|
|
2080
|
-
id: string;
|
|
2081
|
-
/** Column header text shown to the user. */
|
|
2082
|
-
title: string;
|
|
2083
|
-
/**
|
|
2084
|
-
* One or more validators run on every edit. Each receives the cell value and
|
|
2085
|
-
* the full row, and returns a `ValidationError` to flag a problem or `null`
|
|
2086
|
-
* if valid. Errors do not block submission — see `CellValidator`.
|
|
2087
|
-
*/
|
|
2088
|
-
validate?: CellValidator | CellValidator[];
|
|
2089
|
-
/**
|
|
2090
|
-
* When `true`, the editor flags duplicate values in this column as errors.
|
|
2091
|
-
* The error message is localized via the `translations` prop
|
|
2092
|
-
* (`dataEditor.validation.valueMustBeUnique`).
|
|
2093
|
-
*/
|
|
2094
|
-
unique?: boolean;
|
|
2095
|
-
/**
|
|
2096
|
-
* Column IDs to revalidate when this column changes. Use for cross-field
|
|
2097
|
-
* rules like "end date must be after start date".
|
|
2098
|
-
*/
|
|
2099
|
-
dependentFields?: string[];
|
|
2100
|
-
/** Format the display value without changing stored data. E.g. add `$` prefix. */
|
|
2101
|
-
formatter?: (value: string) => string;
|
|
2102
|
-
/**
|
|
2103
|
-
* Transform a value before it enters the store. Runs when rows are uploaded
|
|
2104
|
-
* to the data editor.
|
|
2105
|
-
*/
|
|
2106
|
-
transformer?: (value: unknown) => unknown;
|
|
2107
|
-
/** How the cell is edited. Defaults to text input. */
|
|
2108
|
-
editor?: CellEditor;
|
|
2109
|
-
/** Adds a filter control for this column in the sidebar Filters panel. */
|
|
2110
|
-
filter?: ColumnFilter;
|
|
2111
|
-
/**
|
|
2112
|
-
* Whether this column can be pinned to the left (right in RTL) via the
|
|
2113
|
-
* header context menu. @default true
|
|
2114
|
-
*/
|
|
2115
|
-
pinnable?: boolean;
|
|
2116
|
-
/** Column width in pixels. @default 150 */
|
|
2117
|
-
size?: number;
|
|
2118
|
-
/**
|
|
2119
|
-
* Controls whether cells in this column are locked. A column locked via
|
|
2120
|
-
* configuration cannot be unlocked from the UI.
|
|
2121
|
-
* - `true` | `"all"` — locked for every row.
|
|
2122
|
-
* - `"default"` — locked only for default-source rows; rows added manually,
|
|
2123
|
-
* duplicated, or imported remain editable.
|
|
2124
|
-
* - `false` | `undefined` — not locked.
|
|
2125
|
-
*/
|
|
2126
|
-
locked?: boolean | ColumnLockMode;
|
|
2127
|
-
};
|
|
2128
|
-
|
|
2129
|
-
/** Params passed to `findAndReplace.onFind` when the user types a search query. */
|
|
2130
|
-
type FindParams = {
|
|
2131
|
-
/** The search string. */
|
|
2132
|
-
search: string;
|
|
2133
|
-
/** When `true`, matching is case-sensitive. */
|
|
2134
|
-
matchCase?: boolean;
|
|
2135
|
-
/** When `true`, the entire cell value must equal the search string. */
|
|
2136
|
-
matchEntireCell?: boolean;
|
|
2137
|
-
/** Restrict search to these columns. `null` or omitted = all columns. */
|
|
2138
|
-
columnIds?: string[] | null;
|
|
2139
|
-
/** Current view filters so the server can scope matches to the active filter set. */
|
|
2140
|
-
filters?: QueryFilters;
|
|
2141
|
-
/** Current sort state so match ordering follows the visual row order. */
|
|
2142
|
-
sort?: SortState;
|
|
2143
|
-
};
|
|
2144
|
-
/** A single match location returned by the server. */
|
|
2145
|
-
type FindMatch = {
|
|
2146
|
-
/** Row position in the current filtered+sorted view (for grid scrolling). */
|
|
2147
|
-
rowIndex: number;
|
|
2148
|
-
/** Column ID where the match occurs. */
|
|
2149
|
-
columnId: string;
|
|
2150
|
-
/** Character offset within the cell value (for inline highlight). */
|
|
2151
|
-
startIndex: number;
|
|
2152
|
-
/** 0-based position in the ordered match list (for counter display). */
|
|
2153
|
-
matchIndex: number;
|
|
2154
|
-
};
|
|
2155
|
-
/** Response from `findAndReplace.onFind`. */
|
|
2156
|
-
type FindResponse = {
|
|
2157
|
-
/** Total number of matches across all rows. */
|
|
2158
|
-
totalCount: number;
|
|
2159
|
-
/** The first match. Omit when `totalCount` is 0. */
|
|
2160
|
-
current?: FindMatch;
|
|
2161
|
-
};
|
|
2162
|
-
/** Params passed to `findAndReplace.onNavigate` when the user clicks prev/next. */
|
|
2163
|
-
type FindNavigateParams = FindParams & {
|
|
2164
|
-
/** Navigation direction. */
|
|
2165
|
-
direction: "next" | "prev";
|
|
2166
|
-
/** Current match position so the server knows where to navigate from. */
|
|
2167
|
-
currentMatchIndex: number;
|
|
2168
|
-
};
|
|
2169
|
-
/** Params passed to `findAndReplace.onReplace`. */
|
|
2170
|
-
type ReplaceParams = FindParams & {
|
|
2171
|
-
/** The replacement text. */
|
|
2172
|
-
replacement: string;
|
|
2173
|
-
/** When `true`, replace all matches. When omitted or `false`, replace only `target`. */
|
|
2174
|
-
all?: boolean;
|
|
2175
|
-
/** The specific match to replace. Required when `all` is not `true`. */
|
|
2176
|
-
target?: FindMatch;
|
|
2177
|
-
};
|
|
2178
|
-
/** Response from `findAndReplace.onReplace`. */
|
|
2179
|
-
type ReplaceResponse = {
|
|
2180
|
-
/** Remaining match count after replacement. */
|
|
2181
|
-
totalCount: number;
|
|
2182
|
-
/** Next match to navigate to after replacement. Omit when none left. */
|
|
2183
|
-
current?: FindMatch;
|
|
2184
|
-
};
|
|
2185
|
-
/** Server-side find and replace configuration. */
|
|
2186
|
-
type FindAndReplaceConfig = {
|
|
2187
|
-
/** Called when the user types a search query. Returns total count and first match. */
|
|
2188
|
-
onFind: (params: FindParams) => Promise<FindResponse>;
|
|
2189
|
-
/** Called when the user clicks prev/next arrows. Returns the target match. */
|
|
2190
|
-
onNavigate: (params: FindNavigateParams) => Promise<FindMatch>;
|
|
2191
|
-
/** Called when the user clicks Replace or Replace All. */
|
|
2192
|
-
onReplace: (params: ReplaceParams) => Promise<ReplaceResponse>;
|
|
2193
|
-
};
|
|
2194
|
-
type StoreMode = "client" | "server";
|
|
2195
|
-
type ServerRowId = string | number;
|
|
2196
|
-
/** Row-level status flags returned by the server. Drive row filters and sidebar counts. */
|
|
2197
|
-
type ServerRowStatus = {
|
|
2198
|
-
edited?: boolean;
|
|
2199
|
-
new?: boolean;
|
|
2200
|
-
deleted?: boolean;
|
|
2201
|
-
hasErrors?: boolean;
|
|
2202
|
-
hasEmptyCells?: boolean;
|
|
2203
|
-
};
|
|
2204
|
-
/** Server-reported change for a single cell. The current value lives in `fields`. */
|
|
2205
|
-
type ServerCellChange = {
|
|
2206
|
-
original: unknown;
|
|
2207
|
-
};
|
|
2208
|
-
/** Server-reported validation error for a single cell. */
|
|
2209
|
-
type ServerCellError = {
|
|
2210
|
-
message: string;
|
|
2211
|
-
code?: number | string;
|
|
2212
|
-
};
|
|
2213
|
-
/** Per-row metadata returned by the server in server-delegated mode. */
|
|
2214
|
-
type ServerRowMeta = {
|
|
2215
|
-
/** Row-level status flags — drive row filters and sidebar counts. */
|
|
2216
|
-
status?: ServerRowStatus;
|
|
2217
|
-
/** Cell-level change tracking. Key = field name. */
|
|
2218
|
-
changes?: Record<string, ServerCellChange>;
|
|
2219
|
-
/** Cell-level validation errors. Key = field name. */
|
|
2220
|
-
errors?: Record<string, ServerCellError[]>;
|
|
2221
|
-
};
|
|
2222
|
-
/** Per-source row count returned by the server. Drives the Data Sources sidebar. */
|
|
2223
|
-
type ServerSourceCount = {
|
|
2224
|
-
id: string;
|
|
2225
|
-
name: string;
|
|
2226
|
-
count: number;
|
|
2227
|
-
};
|
|
2228
|
-
/** Aggregate row counts returned alongside a query page. Drive sidebar indicators. */
|
|
2229
|
-
type ServerQueryCounts = {
|
|
2230
|
-
edited?: number;
|
|
2231
|
-
new?: number;
|
|
2232
|
-
deleted?: number;
|
|
2233
|
-
errors?: number;
|
|
2234
|
-
emptyCells?: number;
|
|
2235
|
-
sources?: ServerSourceCount[];
|
|
2236
|
-
};
|
|
2237
|
-
type ServerRow<T extends DataEditorRow = DataEditorRow> = {
|
|
2238
|
-
id: ServerRowId;
|
|
2239
|
-
fields: T;
|
|
2240
|
-
meta?: ServerRowMeta;
|
|
2241
|
-
};
|
|
2242
|
-
type ServerResponse<T> = {
|
|
2243
|
-
data: T;
|
|
2244
|
-
meta?: Record<string, unknown>;
|
|
2245
|
-
};
|
|
2246
|
-
type QueryFilters<F = Record<string, unknown>> = Partial<Filters> & F;
|
|
2247
|
-
type QueryParams<F = Record<string, unknown>> = {
|
|
2248
|
-
filters?: QueryFilters<F>;
|
|
2249
|
-
sort?: SortState;
|
|
2250
|
-
/** When present, only rows belonging to these source IDs are returned. Omit to include all sources. */
|
|
2251
|
-
sources?: string[];
|
|
2252
|
-
offset?: number;
|
|
2253
|
-
limit: number;
|
|
2254
|
-
signal?: AbortSignal;
|
|
2255
|
-
};
|
|
2256
|
-
type QueryResponse<T extends DataEditorRow = DataEditorRow> = ServerResponse<{
|
|
2257
|
-
rows: ServerRow<T>[];
|
|
2258
|
-
totalCount: number;
|
|
2259
|
-
filteredCount?: number;
|
|
2260
|
-
counts?: ServerQueryCounts;
|
|
2261
|
-
}>;
|
|
2262
|
-
/**
|
|
2263
|
-
* Filter options returned by `onFilterOptions` for populating sidebar filter controls in server mode.
|
|
2264
|
-
* Keys are column IDs. Only include columns that have a `filter` configured.
|
|
2265
|
-
*/
|
|
2266
|
-
type FilterOptionsResponse = {
|
|
2267
|
-
[columnId: string]: {
|
|
2268
|
-
/** Values for `"select"` filters. Raw display strings — no formatter is applied. */
|
|
2269
|
-
options?: string[];
|
|
2270
|
-
/** Bounds for `"number-range"` filters. */
|
|
2271
|
-
range?: {
|
|
2272
|
-
min: number;
|
|
2273
|
-
max: number;
|
|
2274
|
-
};
|
|
2275
|
-
/** Bounds for `"date-range"` filters. Values are ISO date strings (YYYY-MM-DD). */
|
|
2276
|
-
dateRange?: {
|
|
2277
|
-
min: string;
|
|
2278
|
-
max: string;
|
|
2279
|
-
};
|
|
2280
|
-
};
|
|
2281
|
-
};
|
|
2282
|
-
type ServerCallOptions = {
|
|
2283
|
-
signal: AbortSignal;
|
|
2284
|
-
};
|
|
2285
|
-
/**
|
|
2286
|
-
* Coordinate rectangle within the server's data view.
|
|
2287
|
-
* Uses ServerRowId (primary key) for rows and column ID strings for columns.
|
|
2288
|
-
*
|
|
2289
|
-
* Convention:
|
|
2290
|
-
* - Both row fields omitted → all rows.
|
|
2291
|
-
* - Both column fields omitted → all columns.
|
|
2292
|
-
* - Single row: `fromRow` AND `toRow` both set, `toRow === fromRow`.
|
|
2293
|
-
* - Single column: `fromColumn` AND `toColumn` both set, `toColumn === fromColumn`.
|
|
2294
|
-
* - Range: both `from` and `to` set, `to !== from`.
|
|
2295
|
-
* - `allSelected: true` → all rows and all columns.
|
|
2296
|
-
* - Empty `{}` → used only for insert operations.
|
|
2297
|
-
*
|
|
2298
|
-
* INVALID: `from` present without `to`, or vice versa.
|
|
2299
|
-
*/
|
|
2300
|
-
type Region = {
|
|
2301
|
-
fromRow?: ServerRowId;
|
|
2302
|
-
toRow?: ServerRowId;
|
|
2303
|
-
fromColumn?: string;
|
|
2304
|
-
toColumn?: string;
|
|
2305
|
-
allSelected?: boolean;
|
|
2306
|
-
};
|
|
2307
|
-
/** Describes where and how to insert a new row. */
|
|
2308
|
-
type InsertParams = {
|
|
2309
|
-
/** Existing row to anchor the insert relative to. Omitted when appending to the end. */
|
|
2310
|
-
anchorRow?: ServerRowId;
|
|
2311
|
-
/** Insert before or after the anchor row. */
|
|
2312
|
-
position: "above" | "below";
|
|
2313
|
-
/** Column IDs matching the order of `values` entries. */
|
|
2314
|
-
columns: string[];
|
|
2315
|
-
};
|
|
2316
|
-
/**
|
|
2317
|
-
* Unified edit params for all data mutations in server-delegated mode.
|
|
2318
|
-
*
|
|
2319
|
-
* The combination of fields determines the operation:
|
|
2320
|
-
* - `target` + `values` → cell edit, clear, or external paste
|
|
2321
|
-
* - `target` + `source` → internal paste (+ `cut` for cut-paste)
|
|
2322
|
-
* - `target` + `source` (fill) → fill handle
|
|
2323
|
-
* - `target` + `transform` → transform / revert
|
|
2324
|
-
* - `target` + `delete: true` → mark rows for deletion
|
|
2325
|
-
* - `target` + `delete: false` → restore rows (unmark deletion)
|
|
2326
|
-
* - `insert` + `values` → create a new row
|
|
2327
|
-
*
|
|
2328
|
-
* `values` is always a 2D array. For a single cell edit: `[["newValue"]]`.
|
|
2329
|
-
* For clearing: `[[""]]`. The server interprets dimensions relative to `target`:
|
|
2330
|
-
* a 1×1 `values` applied to a multi-cell target means "fill all cells with this value".
|
|
2331
|
-
*
|
|
2332
|
-
* `filters` and `sort` provide the view context so the server can resolve
|
|
2333
|
-
* which rows fall between `fromRow` and `toRow` in the current view.
|
|
2334
|
-
* Omitted for single-cell edits where `fromRow` is a direct row ID.
|
|
2335
|
-
*/
|
|
2336
|
-
type EditParams = {
|
|
2337
|
-
target: Region[];
|
|
2338
|
-
source?: Region[];
|
|
2339
|
-
values?: unknown[][];
|
|
2340
|
-
transform?: TransformParams;
|
|
2341
|
-
cut?: boolean;
|
|
2342
|
-
delete?: boolean;
|
|
2343
|
-
insert?: InsertParams;
|
|
2344
|
-
undo?: boolean;
|
|
2345
|
-
filters?: QueryFilters;
|
|
2346
|
-
sort?: SortState;
|
|
2347
|
-
lockedColumns?: Array<{
|
|
2348
|
-
columnId: string;
|
|
2349
|
-
mode: "all" | "default";
|
|
2350
|
-
}>;
|
|
2351
|
-
};
|
|
2352
|
-
type ExportParams$1<F = Record<string, unknown>> = {
|
|
2353
|
-
format: "csv" | "tsv" | "xlsx" | "json" | "xml";
|
|
2354
|
-
allRows: boolean;
|
|
2355
|
-
rtl?: boolean;
|
|
2356
|
-
filters?: QueryFilters<F>;
|
|
2357
|
-
sort?: SortState;
|
|
2358
|
-
signal?: AbortSignal;
|
|
2359
|
-
};
|
|
2360
|
-
/** Transform operation descriptor. `type` identifies the operation, optional fields carry parameters. */
|
|
2361
|
-
type TransformParams = {
|
|
2362
|
-
type: string;
|
|
2363
|
-
separator?: string;
|
|
2364
|
-
/** When `true`, the server should delete the dynamic source columns after applying the transform. */
|
|
2365
|
-
deleteSource?: boolean;
|
|
2366
|
-
};
|
|
2367
|
-
type FormulaParams = {
|
|
2368
|
-
formula: string;
|
|
2369
|
-
params: Record<string, unknown>;
|
|
2370
|
-
};
|
|
2371
|
-
/** Params passed to `onColumnDelete` when the user deletes a dynamic column. */
|
|
2372
|
-
type ColumnDeleteParams = {
|
|
2373
|
-
/** ID of the dynamic column to delete. */
|
|
2374
|
-
columnId: string;
|
|
2375
|
-
/** `true` when the server should reverse this operation (undo). Omitted on initial call and redo. */
|
|
2376
|
-
undo?: boolean;
|
|
2377
|
-
};
|
|
2378
|
-
/** Params passed to `onColumnEdit` when the user renames a dynamic column. */
|
|
2379
|
-
type ColumnEditParams = {
|
|
2380
|
-
/** ID of the dynamic column being edited. */
|
|
2381
|
-
columnId: string;
|
|
2382
|
-
/** New title for the column. */
|
|
2383
|
-
title: string;
|
|
2384
|
-
/** `true` when the server should reverse this operation (undo). Omitted on initial call and redo. */
|
|
2385
|
-
undo?: boolean;
|
|
2386
|
-
};
|
|
2387
|
-
/** Server's response after applying a mutation. */
|
|
2388
|
-
type EditResponse = {
|
|
2389
|
-
counts?: ServerQueryCounts;
|
|
2390
|
-
/** Business-logic rejection. SDK reverts the optimistic update and shows `reason` in a toast. */
|
|
2391
|
-
rejected?: boolean;
|
|
2392
|
-
/** Why the server rejected. Shown to the user as-is. */
|
|
2393
|
-
reason?: string;
|
|
2394
|
-
/** The full row created by the server. Returned for insert operations. */
|
|
2395
|
-
row?: ServerRow;
|
|
2396
|
-
/** Updated column list. When present, the SDK replaces its columns with this list. */
|
|
2397
|
-
columns?: Array<{
|
|
2398
|
-
id: string;
|
|
2399
|
-
title: string;
|
|
2400
|
-
}>;
|
|
2401
|
-
};
|
|
2402
|
-
/**
|
|
2403
|
-
* Every decision the user made during the import wizard, packed into one object.
|
|
2404
|
-
* You get the raw file and the full mapping config. Parse it however you want —
|
|
2405
|
-
* stream it, bulk-load it, hand it to a background job. Your call.
|
|
2406
|
-
*/
|
|
2407
|
-
type ImportMappings = {
|
|
2408
|
-
/** CSV header → column ID. Headers the user left unmatched are `undefined`. */
|
|
2409
|
-
columnMapping: Record<string, string | undefined>;
|
|
2410
|
-
/**
|
|
2411
|
-
* Value substitutions for select columns.
|
|
2412
|
-
* Outer key = column ID, inner key = imported value, inner value = target option.
|
|
2413
|
-
* Only present when at least one select column was matched.
|
|
2414
|
-
*/
|
|
2415
|
-
valueMapping: Record<string, Record<string, string | undefined>>;
|
|
2416
|
-
/** Column ID used to match imported rows against existing data. Same value as `DataEditorProps.primaryKey`. */
|
|
2417
|
-
primaryKey: string;
|
|
2418
|
-
/** Sheet name the user selected. Only present for multi-sheet XLSX files. */
|
|
2419
|
-
selectedSheet?: string;
|
|
2420
|
-
/** Zero-based index of the row the SDK detected as the header row. */
|
|
2421
|
-
headerRowIndex: number;
|
|
2422
|
-
/** Number format detected from the file contents. Affects how `"1.234,56"` vs `"1,234.56"` is read. */
|
|
2423
|
-
numberFormat: "EU" | "US";
|
|
2434
|
+
private hydrateServerMeta;
|
|
2435
|
+
private hydrateRowMeta;
|
|
2436
|
+
applyServerRowMeta(serverRows: ServerRow<TRow>[], counts?: ServerQueryCounts): void;
|
|
2437
|
+
clear(): void;
|
|
2438
|
+
destroy(): void;
|
|
2439
|
+
setFilters(filters: Partial<Filters>): void;
|
|
2440
|
+
getFilters(): Filters;
|
|
2441
|
+
setSort(sortState: SortState, sortType?: SortType, locales?: string[]): Promise<void>;
|
|
2442
|
+
handleServerScroll(visibleStart: number, visibleEnd: number): void;
|
|
2443
|
+
reloadServerData(): void;
|
|
2444
|
+
resetFilters(): void;
|
|
2445
|
+
fetchFilterOptions(): void;
|
|
2446
|
+
getFilterOptions(): FilterOptionsResponse | null;
|
|
2447
|
+
get hasServerExport(): boolean;
|
|
2448
|
+
serverExport(format: DataEditorFormat, allRows: boolean, rtl: boolean): Promise<void>;
|
|
2449
|
+
syncWorkerFlags(): void;
|
|
2450
|
+
setCellValidation(rowId: TRowId, field: string, result: ValidationResult): void;
|
|
2451
|
+
getCellValidation(rowId: TRowId, field: string): ValidationResult;
|
|
2452
|
+
private clearRowValidations;
|
|
2453
|
+
updateRow(rowId: TRowId, field: string, value: unknown): void;
|
|
2454
|
+
updateRowDirect(rowId: TRowId, field: string, value: unknown): void;
|
|
2424
2455
|
/**
|
|
2425
|
-
*
|
|
2426
|
-
*
|
|
2427
|
-
*
|
|
2456
|
+
* Bulk-write a single column for many rows in one pass.
|
|
2457
|
+
* Skips per-row validation, notification, and snapshot adjustments.
|
|
2458
|
+
* Caller must handle validation (via Validator.revalidateColumn) and notification.
|
|
2428
2459
|
*/
|
|
2429
|
-
|
|
2460
|
+
updateColumnDirect(field: string, values: ReadonlyMap<TRowId, unknown>): void;
|
|
2461
|
+
batch(fn: () => void): number | undefined;
|
|
2462
|
+
canUndo(): boolean;
|
|
2463
|
+
getAllRowIds(): readonly TRowId[];
|
|
2464
|
+
undo(): Promise<UndoRedoResult>;
|
|
2465
|
+
private _undoSync;
|
|
2466
|
+
pushCommand(cmd: Command<TRow>, cost?: number): number;
|
|
2467
|
+
removeCommandById(id: number): void;
|
|
2430
2468
|
/**
|
|
2431
|
-
*
|
|
2432
|
-
*
|
|
2469
|
+
* Delegate to ServerStrategy. Called by ActionsDispatcher and ClipboardManager
|
|
2470
|
+
* for non-cell edits (clear, paste, fill, transform).
|
|
2433
2471
|
*/
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
onQuery: (params: QueryParams<TFilters>) => Promise<QueryResponse<TRow>>;
|
|
2489
|
-
/** Fetches filter dictionaries for all filterable columns. Called once after license validation. */
|
|
2490
|
-
onFilterOptions?: () => Promise<FilterOptionsResponse>;
|
|
2491
|
-
/** Called when the user triggers an export. The consumer handles file generation and download. */
|
|
2492
|
-
onExport?: (params: ExportParams$1<TFilters>) => Promise<void>;
|
|
2493
|
-
/** Called after optimistic local apply. Return `{ rejected: true }` for business-logic errors; throw for infra failures. */
|
|
2494
|
-
onEdit: (params: EditParams, options?: ServerCallOptions) => Promise<EditResponse | void>;
|
|
2472
|
+
syncServerEdit(params: EditParams, cmdId: number, revertFn: () => void): void;
|
|
2473
|
+
fireServerEditParams(params: EditParams): void;
|
|
2474
|
+
syncColumnEdit(params: ColumnEditParams, cmdId: number, revertFn: () => void): void;
|
|
2475
|
+
redo(): Promise<UndoRedoResult>;
|
|
2476
|
+
private _redoSync;
|
|
2477
|
+
getOriginalCellValue(rowId: TRowId, field: string): unknown | undefined;
|
|
2478
|
+
isCellDirty(rowId: TRowId, field: string): boolean;
|
|
2479
|
+
hasRowErrors(rowId: TRowId): boolean;
|
|
2480
|
+
hasEmptyCells(rowId: TRowId): boolean;
|
|
2481
|
+
private checkRowEmptyCells;
|
|
2482
|
+
getValidAndInvalidRows(): {
|
|
2483
|
+
valid: TRow[];
|
|
2484
|
+
invalid: TRow[];
|
|
2485
|
+
};
|
|
2486
|
+
getValidRows(): TRow[];
|
|
2487
|
+
getInvalidRows(): TRow[];
|
|
2488
|
+
getResultBySource(): DataEditorResult<TRow>;
|
|
2489
|
+
private isRowVisible;
|
|
2490
|
+
applyFormula(formulaOrName: string | CellFormula, params: Record<string, unknown>, rects: SelectionRect[], options?: ApplyFormulaOptions): Promise<void>;
|
|
2491
|
+
private applyFormulaCompound;
|
|
2492
|
+
private runFormulaWithReturnCommand;
|
|
2493
|
+
private _runFormulaOperation;
|
|
2494
|
+
private captureDeleteColumnSnapshots;
|
|
2495
|
+
private applyDeleteColumnSnapshots;
|
|
2496
|
+
private syncFormulaToServer;
|
|
2497
|
+
private transformWorker;
|
|
2498
|
+
private initTransformWorker;
|
|
2499
|
+
private buildChatOpsCommand;
|
|
2500
|
+
applyChatOps(ops: ChatOp[], ctx: {
|
|
2501
|
+
opts: Record<string, Set<string>>;
|
|
2502
|
+
}, enableDeleteRow: 'all' | 'new' | false): Promise<void>;
|
|
2503
|
+
private filterDeleteIdsByPolicy;
|
|
2504
|
+
private _applyChatOpsViaWorker;
|
|
2505
|
+
private _applyChatOpsSync;
|
|
2506
|
+
private _commitChatOps;
|
|
2507
|
+
applyChatRows(incomingRows: Record<string, unknown>[], primaryKey: string): Promise<void>;
|
|
2508
|
+
private syncChatTransformToServer;
|
|
2509
|
+
private get revertRowReader();
|
|
2510
|
+
revertColumns(fields: string[]): Promise<void>;
|
|
2511
|
+
revertRange(rects: SelectionRect[]): Promise<void>;
|
|
2512
|
+
private _revertInternal;
|
|
2513
|
+
private _buildRevertCommand;
|
|
2514
|
+
private syncRevertToServer;
|
|
2515
|
+
clearColumn(field: string): Promise<void>;
|
|
2516
|
+
clearColumns(fields: string[]): Promise<void>;
|
|
2517
|
+
private syncClearToServer;
|
|
2518
|
+
deleteColumn(columnId: string): Promise<void>;
|
|
2519
|
+
deleteColumns(columnIds: readonly string[]): Promise<void>;
|
|
2520
|
+
clearRange(rects: SelectionRect[]): Promise<void>;
|
|
2521
|
+
private syncRangeClearToServer;
|
|
2522
|
+
pasteChunked(spec: PasteSpec, targetRowIds: TRowId[], targetCell: {
|
|
2523
|
+
rowId: TRowId;
|
|
2524
|
+
field: string;
|
|
2525
|
+
}, onComplete?: (cmdId: number) => void): void;
|
|
2495
2526
|
/**
|
|
2496
|
-
*
|
|
2497
|
-
*
|
|
2498
|
-
* Mutually exclusive with `onRowsImport`.
|
|
2527
|
+
* Store-owned paste: cost-gated sync path or chunked orchestrator.
|
|
2528
|
+
* Replaces executePasteWithOverlay + pasteChunked for internal-clipboard paste.
|
|
2499
2529
|
*/
|
|
2500
|
-
|
|
2530
|
+
pasteInternal(spec: PasteSpec, targetRowIds: TRowId[], targetCell: {
|
|
2531
|
+
rowId: TRowId;
|
|
2532
|
+
field: string;
|
|
2533
|
+
}, validator?: IValidator<TRow>): Promise<{
|
|
2534
|
+
cmdId: number;
|
|
2535
|
+
} | null>;
|
|
2501
2536
|
/**
|
|
2502
|
-
*
|
|
2503
|
-
*
|
|
2504
|
-
* Called once per chunk. Awaited before sending the next chunk.
|
|
2505
|
-
* Mutually exclusive with `onFileImport`.
|
|
2537
|
+
* Store-owned external paste from TSV text (OS clipboard).
|
|
2538
|
+
* Replaces the pasteFromText helper in pasteUtils.
|
|
2506
2539
|
*/
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
/** Called when the user removes a data source. Delete all rows belonging to this source. */
|
|
2511
|
-
onSourceRemove?: (params: SourceRemoveParams) => Promise<void>;
|
|
2512
|
-
/** Called when the user deletes, undoes, or redoes a dynamic column deletion. */
|
|
2513
|
-
onColumnDelete?: (params: ColumnDeleteParams) => Promise<EditResponse | void>;
|
|
2514
|
-
/** Called when the user edits a dynamic column (e.g. renames it). */
|
|
2515
|
-
onColumnEdit?: (params: ColumnEditParams) => Promise<EditResponse | void>;
|
|
2540
|
+
pasteFromText(text: string, pasteRow: number, pasteCol: number, validator?: IValidator<TRow>): Promise<{
|
|
2541
|
+
cmdId: number;
|
|
2542
|
+
} | null>;
|
|
2516
2543
|
/**
|
|
2517
|
-
*
|
|
2518
|
-
*
|
|
2519
|
-
* handles counts, navigation, and highlighting.
|
|
2544
|
+
* Store-owned fill: cost-gated sync path or chunked orchestrator.
|
|
2545
|
+
* Replaces fillChunked + the per-caller isHeavy heuristic in ActionsDispatcher.
|
|
2520
2546
|
*/
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2547
|
+
fillInternal(spec: FillSpec, targetRowIds: TRowId[], targetCell: {
|
|
2548
|
+
rowId: TRowId;
|
|
2549
|
+
field: string;
|
|
2550
|
+
}, onComplete?: (cmdId: number) => void): Promise<{
|
|
2551
|
+
cmdId: number;
|
|
2552
|
+
} | null>;
|
|
2553
|
+
notify(): void;
|
|
2554
|
+
}
|
|
2555
|
+
|
|
2556
|
+
/**
|
|
2557
|
+
* Command interface for undo/redo operations.
|
|
2558
|
+
* Each command knows how to apply and revert its changes.
|
|
2559
|
+
*/
|
|
2560
|
+
interface Command<TRow extends DataEditorRow = DataEditorRow> {
|
|
2561
|
+
/** Assigned by CommandHistory.push(). Used by removeById() to target specific commands. */
|
|
2562
|
+
id?: number;
|
|
2563
|
+
redo(store: DataStore<TRow>, validator: IValidator<TRow>): void;
|
|
2564
|
+
undo(store: DataStore<TRow>, validator: IValidator<TRow>): void;
|
|
2565
|
+
readonly description: string;
|
|
2566
|
+
/** Target cell for selection restoration on undo/redo */
|
|
2567
|
+
readonly targetCell: CellLocation;
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
/**
|
|
2571
|
+
* BulkMutationOrchestrator — Viewport-first chunked execution for heavy
|
|
2572
|
+
* column operations (split, merge, clear, paste, fill, backspace).
|
|
2573
|
+
*
|
|
2574
|
+
* When operation cost >= LARGE_OP_CELLS:
|
|
2575
|
+
* 1. Viewport rows are applied synchronously (instant visual result)
|
|
2576
|
+
* 2. Remaining rows are processed in chunks via requestIdleCallback
|
|
2577
|
+
* 3. Validation runs chunked after all mutations complete
|
|
2578
|
+
* 4. Command is pushed to history only after everything finishes
|
|
2579
|
+
*
|
|
2580
|
+
* Communicates with DataStore via BulkMutationHost interface to avoid
|
|
2581
|
+
* circular imports. DataStore constructs the host from its own methods.
|
|
2582
|
+
*/
|
|
2583
|
+
|
|
2584
|
+
type ColumnDelta = {
|
|
2585
|
+
field: string;
|
|
2586
|
+
oldValues: Map<TRowId, unknown>;
|
|
2587
|
+
newValues: Map<TRowId, unknown>;
|
|
2588
|
+
};
|
|
2589
|
+
|
|
2590
|
+
type ScaleServerConfig = {
|
|
2591
|
+
url: string;
|
|
2526
2592
|
};
|
|
2527
2593
|
|
|
2528
2594
|
/** Numeric row identifier. V8 stores small integers (Smi) inline — no heap allocation. */
|
|
@@ -2779,12 +2845,6 @@ type DataEditorBaseProps<TRow extends DataEditorRow = DataEditorRow> = {
|
|
|
2779
2845
|
* ```
|
|
2780
2846
|
*/
|
|
2781
2847
|
loadData?: (onChunk: (rows: TRow[], options?: ChunkSourceOptions) => void) => Promise<void>;
|
|
2782
|
-
/**
|
|
2783
|
-
* Server-delegated mode. When provided, the SDK acts as a rendering head
|
|
2784
|
-
* and delegates data operations (fetching, filtering, sorting, mutations)
|
|
2785
|
-
* to the client's backend via callbacks.
|
|
2786
|
-
*/
|
|
2787
|
-
server?: DataEditorServer<TRow>;
|
|
2788
2848
|
/**
|
|
2789
2849
|
* Called when the user clicks "Submit". Receives the edited data grouped
|
|
2790
2850
|
* by source. Use `actions.reset()` to clear changes after a successful save.
|
|
@@ -2944,6 +3004,11 @@ type DataEditorMode = "modal" | "inline";
|
|
|
2944
3004
|
type DataEditorCommonProps<TRow extends DataEditorRow = DataEditorRow> = DataEditorBaseProps<TRow> & {
|
|
2945
3005
|
/** Your Updog license key. Validated on each open. */
|
|
2946
3006
|
apiKey: string;
|
|
3007
|
+
/**
|
|
3008
|
+
* Connect to a self-hosted Updog Scale binary. When provided, the SDK
|
|
3009
|
+
* delegates all data operations to the Scale server at the given URL.
|
|
3010
|
+
*/
|
|
3011
|
+
server?: ScaleServerConfig;
|
|
2947
3012
|
/**
|
|
2948
3013
|
* Controls what the editor stores in `localStorage`. Set to `false` to
|
|
2949
3014
|
* disable all local storage usage.
|
|
@@ -3050,67 +3115,6 @@ declare function downloadExampleFile(columns: DataEditorColumn[], format: DataEd
|
|
|
3050
3115
|
*/
|
|
3051
3116
|
declare function exportDataEditor<TRow extends DataEditorRow>(params: ExportParams<TRow>): Promise<void>;
|
|
3052
3117
|
|
|
3053
|
-
/**
|
|
3054
|
-
* Creates a validator that rejects empty values.
|
|
3055
|
-
*
|
|
3056
|
-
* @param message - Error message shown when the cell is empty.
|
|
3057
|
-
*
|
|
3058
|
-
* @example
|
|
3059
|
-
* ```ts
|
|
3060
|
-
* const columns = [
|
|
3061
|
-
* { id: "name", title: "Name", validate: [required("Name is required")] },
|
|
3062
|
-
* ];
|
|
3063
|
-
* ```
|
|
3064
|
-
*/
|
|
3065
|
-
declare function required(message: string): CellValidator;
|
|
3066
|
-
/**
|
|
3067
|
-
* Creates a validator that rejects non-numeric values.
|
|
3068
|
-
*
|
|
3069
|
-
* @param message - Error message shown when the value is not a valid number.
|
|
3070
|
-
*/
|
|
3071
|
-
declare function numeric(message: string): CellValidator;
|
|
3072
|
-
/**
|
|
3073
|
-
* Creates a validator that rejects invalid email addresses.
|
|
3074
|
-
*
|
|
3075
|
-
* @param message - Error message shown when the value is not a valid email.
|
|
3076
|
-
*/
|
|
3077
|
-
declare function email(message: string): CellValidator;
|
|
3078
|
-
/**
|
|
3079
|
-
* Creates a validator that rejects values not matching `YYYY-MM-DD` or `DD/MM/YYYY`.
|
|
3080
|
-
*
|
|
3081
|
-
* @param message - Error message shown when the value is not a valid date.
|
|
3082
|
-
*/
|
|
3083
|
-
declare function date(message: string): CellValidator;
|
|
3084
|
-
/**
|
|
3085
|
-
* Creates a validator that ensures this date is on or after the date in another column.
|
|
3086
|
-
*
|
|
3087
|
-
* @param startDateField - Column ID of the start-date field to compare against.
|
|
3088
|
-
* @param message - Error message shown when the end date is before the start date.
|
|
3089
|
-
*
|
|
3090
|
-
* @example
|
|
3091
|
-
* ```ts
|
|
3092
|
-
* const columns = [
|
|
3093
|
-
* { id: "startDate", title: "Start", dependentFields: ["endDate"] },
|
|
3094
|
-
* { id: "endDate", title: "End", validate: [endDateAfterStart("startDate", "End must be after start")] },
|
|
3095
|
-
* ];
|
|
3096
|
-
* ```
|
|
3097
|
-
*/
|
|
3098
|
-
/**
|
|
3099
|
-
* Creates a validator that rejects values not in the allowed set.
|
|
3100
|
-
*
|
|
3101
|
-
* @param values - Array of allowed values (matched by strict equality).
|
|
3102
|
-
* @param message - Error message shown when the value is not in the set.
|
|
3103
|
-
*
|
|
3104
|
-
* @example
|
|
3105
|
-
* ```ts
|
|
3106
|
-
* const columns = [
|
|
3107
|
-
* { id: "status", title: "Status", validate: [oneOf(["active", "inactive"], "Invalid status")] },
|
|
3108
|
-
* ];
|
|
3109
|
-
* ```
|
|
3110
|
-
*/
|
|
3111
|
-
declare function oneOf(values: string[], message: string): CellValidator;
|
|
3112
|
-
declare function endDateAfterStart(startDateField: string, message: string): CellValidator;
|
|
3113
|
-
|
|
3114
3118
|
/**
|
|
3115
3119
|
* Full-screen modal spreadsheet editor for large datasets.
|
|
3116
3120
|
*
|
|
@@ -3127,6 +3131,7 @@ declare function endDateAfterStart(startDateField: string, message: string): Cel
|
|
|
3127
3131
|
* onClose={() => setIsOpen(false)}
|
|
3128
3132
|
* columns={columns}
|
|
3129
3133
|
* primaryKey="id"
|
|
3134
|
+
* server={{ url: scaleUrl }}
|
|
3130
3135
|
* loadData={async (onChunk) => onChunk(await fetchRows())}
|
|
3131
3136
|
* onComplete={(result, actions) => { saveChanges(result); actions.reset(); }}
|
|
3132
3137
|
* />
|
|
@@ -3134,5 +3139,5 @@ declare function endDateAfterStart(startDateField: string, message: string): Cel
|
|
|
3134
3139
|
*/
|
|
3135
3140
|
declare function DataEditor<TRow extends DataEditorRow = DataEditorRow>(allProps: DataEditorProps<TRow>): react_jsx_runtime.JSX.Element;
|
|
3136
3141
|
|
|
3137
|
-
export { DataEditor,
|
|
3138
|
-
export type { CellValidator, ChatContext, ChatErrorSummary, ChatResponseChunk, ChatRow, ChatRowStatus, ChunkSourceOptions,
|
|
3142
|
+
export { DataEditor, downloadExampleFile, exportDataEditor };
|
|
3143
|
+
export type { CellValidator, ChatContext, ChatErrorSummary, ChatResponseChunk, ChatRow, ChatRowStatus, ChunkSourceOptions, DataEditorChat, DataEditorColumn, DataEditorFormat, DataEditorInlineProps, DataEditorLocalStorage, DataEditorModalProps, DataEditorMode, DataEditorProps, DataEditorResult, DataEditorRow, DataEditorSourceResult, DataEditorTranslations, DataEditorVariant, RemoteSource, ResultRow, ScaleServerConfig, UpdogError, UpdogErrorCode, ValidationError, ValueMatchInput, ValueMatchOutput };
|