@gridengine/angular-datagrid-enterprise 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gridengine/angular-datagrid-enterprise",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Pro/Enterprise features for the GridEngine Angular data grid (license-gated).",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "publishConfig": {
@@ -498,5 +498,275 @@ declare class MasterDetailEngine {
498
498
  private _notify;
499
499
  }
500
500
 
501
- export { ClipboardEngine, DataGridPro, FillHandleEngine, FormulaEngine, GridLicenseWatermark, LicenseManager, MasterDetailEngine, PRODUCT_ID, PURCHASE_URL, RangeSelectionEngine, SSRMEngine, TransactionEngine, UndoRedoManager, parseTSV, provideGridEngineLicense, toNumber, toTimestamp };
502
- export type { Block, BlockState, CellEditCommand, CellRange, ClipboardEngineOptions, DeleteCommand, DetailEntry, DetailLoadState, FillCell, FillCommand, FillDirection, FillHandleEngineOptions, FillResult, FormulaEngineOptions, GridRow, MasterDetailEngineOptions, PasteCommand, RangeSelectionEngineOptions, SSRMDataSource, SSRMEngineOptions, SSRMGetRowsParams, SSRMGetRowsResult, TransactionDelta, TransactionEngineOptions, UndoRedoCommand, UndoRedoManagerOptions };
501
+ /**
502
+ * CellPermissionEngine — enforces per-cell read/edit permissions from a
503
+ * caller-supplied policy. Unreadable cells are masked ('●●●') everywhere
504
+ * (display, export, clipboard); non-editable cells can't be edited regardless
505
+ * of the column's `editable`. Results are cached per (rowId, field). Pure logic.
506
+ */
507
+
508
+ interface CellPermission {
509
+ canRead: boolean;
510
+ canEdit: boolean;
511
+ }
512
+ /** Default mask string used for unreadable cells. */
513
+ declare const DEFAULT_MASK = "\u25CF\u25CF\u25CF";
514
+ interface CellPermissionEngineOptions {
515
+ /** Policy returning permissions for a cell; called once per (rowId, field). */
516
+ policy: (row: GridRow, field: string) => CellPermission;
517
+ /** Field used as the unique row ID. Default: 'id' */
518
+ rowIdField?: string;
519
+ /** String shown in place of unreadable cell values. Default: '●●●' */
520
+ maskValue?: string;
521
+ }
522
+ declare class CellPermissionEngine {
523
+ private readonly _policy;
524
+ private readonly _rowIdField;
525
+ private readonly _maskValue;
526
+ private readonly _cache;
527
+ constructor(options: CellPermissionEngineOptions);
528
+ /** The resolved permission for a cell (cached). */
529
+ getPermission(row: GridRow, field: string): CellPermission;
530
+ canRead(row: GridRow, field: string): boolean;
531
+ canEdit(row: GridRow, field: string): boolean;
532
+ /** The display value for a cell, masked when not readable. */
533
+ getDisplayValue(row: GridRow, field: string): unknown;
534
+ /** The value for copy/export; unreadable cells return '' so data never leaks. */
535
+ getExportValue(row: GridRow, field: string): unknown;
536
+ /** True if the given value is the mask placeholder. */
537
+ isMasked(value: unknown): boolean;
538
+ get maskValue(): string;
539
+ /** Clear one row's cached permissions, or the whole cache when omitted. */
540
+ clearCache(rowId?: string | number): void;
541
+ private _key;
542
+ }
543
+
544
+ /**
545
+ * AuditTrailEngine — records an immutable log of every cell edit (who/what/when
546
+ * + prev/next values) in a bounded in-memory ring buffer, emitting each entry
547
+ * via `onEntry` for persistence. Pure logic.
548
+ */
549
+ interface AuditEntry {
550
+ timestamp: number;
551
+ userId: string | undefined;
552
+ rowId: string | number;
553
+ field: string;
554
+ prevValue: unknown;
555
+ nextValue: unknown;
556
+ }
557
+ interface AuditTrailEngineOptions {
558
+ /** User identifier stamped on every entry. */
559
+ userId?: string;
560
+ /** Called for every new entry — persist to a server here. */
561
+ onEntry?: (entry: AuditEntry) => void;
562
+ /** Maximum entries retained in memory (oldest evicted first). Default: 1000 */
563
+ maxEntries?: number;
564
+ /** Injectable clock for testing. Defaults to Date.now. */
565
+ now?: () => number;
566
+ }
567
+ declare class AuditTrailEngine {
568
+ private readonly _userId?;
569
+ private readonly _onEntry?;
570
+ private readonly _maxEntries;
571
+ private readonly _now;
572
+ private _entries;
573
+ private _onChange?;
574
+ constructor(options?: AuditTrailEngineOptions);
575
+ subscribe(listener: () => void): () => void;
576
+ /** Record a cell edit; no-op edits (prev === next) return null. */
577
+ record(rowId: string | number, field: string, prevValue: unknown, nextValue: unknown): AuditEntry | null;
578
+ /** All entries, oldest first (read-only snapshot). */
579
+ getEntries(): readonly AuditEntry[];
580
+ /** Entries for a specific row, oldest first. */
581
+ getEntriesForRow(rowId: string | number): AuditEntry[];
582
+ /** Entries for a specific cell (row + field), oldest first. */
583
+ getEntriesForCell(rowId: string | number, field: string): AuditEntry[];
584
+ get size(): number;
585
+ /** Discard all entries. */
586
+ clear(): void;
587
+ private _notify;
588
+ }
589
+
590
+ /**
591
+ * RowLockEngine — tracks which rows are locked (by other users) so the grid can
592
+ * show a lock indicator and block edits. Supports an async source of locks
593
+ * (e.g. polled from a collaboration server) plus optimistic local lock/unlock.
594
+ * Pure logic.
595
+ */
596
+
597
+ interface LockedRow {
598
+ rowId: string | number;
599
+ lockedByUserId: string;
600
+ lockedByDisplayName?: string;
601
+ lockedAt: number;
602
+ }
603
+ interface RowLockEngineOptions {
604
+ /** The current user's ID. Locks held by this user do not block editing. */
605
+ currentUserId?: string;
606
+ /** Async source of currently locked rows (server state). */
607
+ getLockedRows?: () => Promise<LockedRow[]>;
608
+ /** Called when the current user attempts to edit a row locked by someone else. */
609
+ onLockConflict?: (row: GridRow, lockedBy: string) => void;
610
+ /** Field used as the unique row ID. Default: 'id' */
611
+ rowIdField?: string;
612
+ /** Injectable clock for testing. Defaults to Date.now. */
613
+ now?: () => number;
614
+ }
615
+ declare class RowLockEngine {
616
+ private readonly _currentUserId?;
617
+ private readonly _getLockedRows?;
618
+ private readonly _onLockConflict?;
619
+ private readonly _rowIdField;
620
+ private readonly _now;
621
+ private _locks;
622
+ private _onChange?;
623
+ constructor(options?: RowLockEngineOptions);
624
+ subscribe(listener: () => void): () => void;
625
+ /** Load locks from the async source and replace local state. */
626
+ refresh(): Promise<void>;
627
+ /** Optimistically lock a row for a user. */
628
+ lockRow(rowId: string | number, userId: string, displayName?: string): void;
629
+ /** Remove a lock. */
630
+ unlockRow(rowId: string | number): void;
631
+ /** Remove all locks. */
632
+ clear(): void;
633
+ /** The lock for a row, or undefined if unlocked. */
634
+ getLock(rowId: string | number): LockedRow | undefined;
635
+ /** True if the row is locked by anyone. */
636
+ isLocked(rowId: string | number): boolean;
637
+ /** True if the row is locked by someone OTHER than the current user. */
638
+ isLockedByOther(rowId: string | number): boolean;
639
+ /** All current locks. */
640
+ getLocks(): LockedRow[];
641
+ get size(): number;
642
+ /**
643
+ * Whether the row may be edited by the current user. If it's locked by
644
+ * another user, fires `onLockConflict` and returns false.
645
+ */
646
+ canEditRow(row: GridRow): boolean;
647
+ private _rowId;
648
+ private _notify;
649
+ }
650
+
651
+ /**
652
+ * Advanced filter builder — a nestable AND/OR/NOT tree of conditions with a
653
+ * pure evaluator, URL-safe serialize/deserialize for shareable filter links,
654
+ * and a named-preset store. No React, no DOM.
655
+ */
656
+
657
+ type FilterOperator = 'equals' | 'notEquals' | 'contains' | 'notContains' | 'startsWith' | 'endsWith' | 'greaterThan' | 'greaterThanOrEqual' | 'lessThan' | 'lessThanOrEqual' | 'isEmpty' | 'isNotEmpty';
658
+ /** A single leaf filter condition. */
659
+ interface FilterCondition {
660
+ kind: 'condition';
661
+ field: string;
662
+ operator: FilterOperator;
663
+ value?: unknown;
664
+ }
665
+ /** A nestable group of conditions/groups combined with AND or OR. */
666
+ interface FilterGroup {
667
+ kind: 'group';
668
+ combinator: 'and' | 'or';
669
+ /** Negates the entire group's result. */
670
+ not?: boolean;
671
+ children: FilterNode[];
672
+ }
673
+ type FilterNode = FilterCondition | FilterGroup;
674
+ /** A named, persistable filter preset. */
675
+ interface FilterPreset {
676
+ id: string;
677
+ name: string;
678
+ filter: FilterNode;
679
+ isShared?: boolean;
680
+ }
681
+ interface FilterPresetEngineOptions {
682
+ /** Presets to seed the store with. */
683
+ presets?: FilterPreset[];
684
+ /** Called when a preset is saved. */
685
+ onSave?: (preset: FilterPreset) => void | Promise<void>;
686
+ /** ID generator (injectable for tests). */
687
+ generateId?: () => string;
688
+ }
689
+ /** Evaluate a filter node against a row. */
690
+ declare function evaluateFilter(node: FilterNode, row: GridRow): boolean;
691
+ /** Serialize a filter tree to a URL-safe string. */
692
+ declare function serializeFilter(node: FilterNode): string;
693
+ /** Deserialize a URL-safe string back into a filter tree. Throws if invalid. */
694
+ declare function deserializeFilter(encoded: string): FilterNode;
695
+ declare class FilterPresetEngine {
696
+ private readonly _onSave?;
697
+ private readonly _generateId;
698
+ private _presets;
699
+ private _seq;
700
+ private _onChange?;
701
+ constructor(options?: FilterPresetEngineOptions);
702
+ subscribe(listener: () => void): () => void;
703
+ getPresets(): readonly FilterPreset[];
704
+ getPreset(id: string): FilterPreset | undefined;
705
+ /** Save a new preset (or replace one with the same name). Returns it. */
706
+ savePreset(name: string, filter: FilterNode, isShared?: boolean): FilterPreset;
707
+ deletePreset(id: string): void;
708
+ /** Filter an array of rows through a filter tree. */
709
+ applyFilter(node: FilterNode, rows: GridRow[]): GridRow[];
710
+ private _notify;
711
+ }
712
+
713
+ /**
714
+ * SavedViewsEngine — manages named grid views (column layout, sort, filter,
715
+ * group, density, etc.) across personal + admin-shared tiers. Server sync is
716
+ * delegated to async callbacks so the engine stays pure and Node-testable.
717
+ */
718
+ interface SavedView {
719
+ id: string;
720
+ name: string;
721
+ isShared?: boolean;
722
+ layout: Record<string, unknown>;
723
+ }
724
+ interface SavedViewsEngineOptions {
725
+ /** Async loader for the user's saved views. */
726
+ getSavedViews?: () => Promise<SavedView[]>;
727
+ /** Persist a saved view. */
728
+ onSaveView?: (view: SavedView) => Promise<void> | void;
729
+ /** Delete a saved view. */
730
+ onDeleteView?: (viewId: string) => Promise<void> | void;
731
+ /** Notified when the active view changes. */
732
+ onViewChange?: (view: SavedView | null) => void;
733
+ /** Seed views (used when no async loader is supplied). */
734
+ views?: SavedView[];
735
+ /** ID generator (injectable for tests). */
736
+ generateId?: () => string;
737
+ }
738
+ declare class SavedViewsEngine {
739
+ private readonly _getSavedViews?;
740
+ private readonly _onSaveView?;
741
+ private readonly _onDeleteView?;
742
+ private readonly _onViewChange?;
743
+ private readonly _generateId;
744
+ private _views;
745
+ private _activeViewId;
746
+ private _seq;
747
+ private _onChange?;
748
+ constructor(options?: SavedViewsEngineOptions);
749
+ subscribe(listener: () => void): () => void;
750
+ /** Load views from the async source, replacing local state. */
751
+ load(): Promise<void>;
752
+ getViews(): readonly SavedView[];
753
+ getView(id: string): SavedView | undefined;
754
+ /** Personal (non-shared) views. */
755
+ getPersonalViews(): SavedView[];
756
+ /** Admin-shared views. */
757
+ getSharedViews(): SavedView[];
758
+ getActiveView(): SavedView | null;
759
+ /** Create a new view or update an existing one by name. Returns the view. */
760
+ saveView(name: string, layout: Record<string, unknown>, options?: {
761
+ isShared?: boolean;
762
+ id?: string;
763
+ }): Promise<SavedView>;
764
+ /** Delete a view. If it was active, the active view is cleared. */
765
+ deleteView(id: string): Promise<void>;
766
+ /** Activate a view (or clear with null). Fires onViewChange. */
767
+ setActiveView(id: string | null): void;
768
+ private _notify;
769
+ }
770
+
771
+ export { AuditTrailEngine, CellPermissionEngine, ClipboardEngine, DEFAULT_MASK, DataGridPro, FillHandleEngine, FilterPresetEngine, FormulaEngine, GridLicenseWatermark, LicenseManager, MasterDetailEngine, PRODUCT_ID, PURCHASE_URL, RangeSelectionEngine, RowLockEngine, SSRMEngine, SavedViewsEngine, TransactionEngine, UndoRedoManager, deserializeFilter, evaluateFilter, parseTSV, provideGridEngineLicense, serializeFilter, toNumber, toTimestamp };
772
+ export type { AuditEntry, AuditTrailEngineOptions, Block, BlockState, CellEditCommand, CellPermission, CellPermissionEngineOptions, CellRange, ClipboardEngineOptions, DeleteCommand, DetailEntry, DetailLoadState, FillCell, FillCommand, FillDirection, FillHandleEngineOptions, FillResult, FilterCondition, FilterGroup, FilterNode, FilterOperator, FilterPreset, FilterPresetEngineOptions, FormulaEngineOptions, GridRow, LockedRow, MasterDetailEngineOptions, PasteCommand, RangeSelectionEngineOptions, RowLockEngineOptions, SSRMDataSource, SSRMEngineOptions, SSRMGetRowsParams, SSRMGetRowsResult, SavedView, SavedViewsEngineOptions, TransactionDelta, TransactionEngineOptions, UndoRedoCommand, UndoRedoManagerOptions };