@gridengine/angular-datagrid-enterprise 0.9.0 → 0.11.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.
@@ -1,6 +1,6 @@
1
1
  export * from '@gridengine/angular-datagrid';
2
2
  import * as i0 from '@angular/core';
3
- import { input, ChangeDetectionStrategy, Component, computed, effect, makeEnvironmentProviders, provideEnvironmentInitializer, output, inject, ElementRef, HostListener, Directive } from '@angular/core';
3
+ import { input, ChangeDetectionStrategy, Component, computed, effect, makeEnvironmentProviders, provideEnvironmentInitializer, signal, output, inject, ElementRef, HostListener, Directive } from '@angular/core';
4
4
  import { validateLicense, resolveFeatures as resolveFeatures$1, TIER_FEATURES } from '@gridengine/license-core';
5
5
  export { TIER_FEATURES } from '@gridengine/license-core';
6
6
  import { DOCUMENT } from '@angular/common';
@@ -1380,6 +1380,92 @@ class TransactionEngine {
1380
1380
  }
1381
1381
  }
1382
1382
 
1383
+ /**
1384
+ * TransactionController — a reactive (signals) wrapper around `TransactionEngine`
1385
+ * for the open-source `<gd-data-grid>`. Bind `displayRows()` to `[rowData]` and
1386
+ * pipe `(cellValueChanged)` into `onCellValueChanged` to stage inline edits
1387
+ * without mutating the base data; then `commit()` / `rollback()`:
1388
+ *
1389
+ * ```html
1390
+ * <gd-data-grid [rowData]="txn.displayRows()" [columnDefs]="cols" [getRowId]="byId"
1391
+ * (cellValueChanged)="txn.onCellValueChanged($event)" />
1392
+ * <button [disabled]="!txn.isDirty()" (click)="txn.commit()">Save</button>
1393
+ * ```
1394
+ *
1395
+ * `displayRows()` returns shallow clones, so the grid's in-place cell edits
1396
+ * change the copy while the base stays clean (rollback restores it). Use a
1397
+ * field-based `getRowId` so row identity survives cloning.
1398
+ */
1399
+ class TransactionController {
1400
+ _engine;
1401
+ _rowIdField;
1402
+ _version = signal(0, /* @ts-ignore */
1403
+ ...(ngDevMode ? [{ debugName: "_version" }] : /* istanbul ignore next */ []));
1404
+ /** The current merged rows (base + staged changes) as shallow clones. */
1405
+ displayRows;
1406
+ /** Whether there are uncommitted staged changes. */
1407
+ isDirty;
1408
+ constructor(initialRows, options = {}) {
1409
+ this._rowIdField = options.rowIdField ?? 'id';
1410
+ this._engine = new TransactionEngine({
1411
+ initialRows,
1412
+ rowIdField: this._rowIdField,
1413
+ onTransactionCommit: options.onCommit,
1414
+ onTransactionRollback: options.onRollback,
1415
+ });
1416
+ this.displayRows = computed(() => {
1417
+ this._version();
1418
+ return this._engine.getDisplayRows().map((r) => ({ ...r }));
1419
+ }, /* @ts-ignore */
1420
+ ...(ngDevMode ? [{ debugName: "displayRows" }] : /* istanbul ignore next */ []));
1421
+ this.isDirty = computed(() => {
1422
+ this._version();
1423
+ return this._engine.isDirty();
1424
+ }, /* @ts-ignore */
1425
+ ...(ngDevMode ? [{ debugName: "isDirty" }] : /* istanbul ignore next */ []));
1426
+ }
1427
+ /** Stage an inline edit emitted by the grid's `(cellValueChanged)`. */
1428
+ onCellValueChanged(event) {
1429
+ if (!event.field)
1430
+ return;
1431
+ const id = event.row[this._rowIdField];
1432
+ this._engine.updateRows([{ [this._rowIdField]: id, [event.field]: event.newValue }]);
1433
+ this._bump();
1434
+ }
1435
+ addRows(rows) {
1436
+ this._engine.addRows(rows);
1437
+ this._bump();
1438
+ }
1439
+ updateRows(rows) {
1440
+ this._engine.updateRows(rows);
1441
+ this._bump();
1442
+ }
1443
+ removeRows(ids) {
1444
+ this._engine.removeRows(ids);
1445
+ this._bump();
1446
+ }
1447
+ /** All current staged changes, grouped by kind. */
1448
+ getDirtyRows() {
1449
+ return this._engine.getDirtyRows();
1450
+ }
1451
+ commit() {
1452
+ this._engine.commitTransaction();
1453
+ this._bump();
1454
+ }
1455
+ rollback() {
1456
+ this._engine.rollbackTransaction();
1457
+ this._bump();
1458
+ }
1459
+ /** Replace the base rows (e.g. after a server refresh); staged changes are kept. */
1460
+ resetRows(rows) {
1461
+ this._engine.resetRows(rows);
1462
+ this._bump();
1463
+ }
1464
+ _bump() {
1465
+ this._version.update((v) => v + 1);
1466
+ }
1467
+ }
1468
+
1383
1469
  class MasterDetailEngine {
1384
1470
  _getDetailRowData;
1385
1471
  _onExpand;
@@ -2465,11 +2551,13 @@ function toPdfColumns(columnDefs) {
2465
2551
  * </div>
2466
2552
  * ```
2467
2553
  *
2468
- * Drag across cells to select a block, then Ctrl/Cmd+C to copy it to the
2469
- * clipboard as TSV (paste-ready into Excel / Sheets). It reads cell coordinates
2470
- * from the grid's ARIA attributes (`role="gridcell"` + `aria-colindex`, and the
2471
- * row's `aria-rowindex`), so it needs no changes to the base grid. Selection
2472
- * state is driven by the Pro `RangeSelectionEngine`.
2554
+ * Drag across cells to select a block, then Ctrl/Cmd+C to copy it as TSV
2555
+ * (paste-ready into Excel / Sheets). Ctrl/Cmd+V emits `(rangePaste)` with the
2556
+ * parsed matrix and Delete/Backspace emits `(rangeClear)` — the consumer writes
2557
+ * those back into its own data (one-way binding, like the grid's other events).
2558
+ * Cell coordinates come from the grid's ARIA attributes (`role="gridcell"` +
2559
+ * `aria-colindex`, and the row's `aria-rowindex`), so no base-grid changes are
2560
+ * needed. Selection state is driven by the Pro `RangeSelectionEngine`.
2473
2561
  */
2474
2562
  const STYLE_ID = 'gd-range-selection-styles';
2475
2563
  const SELECTED_CLASS = 'gd-range-selected';
@@ -2477,6 +2565,10 @@ const NON_DATA_ROW = ['gd-row--header', 'gd-row--filter', 'gd-row--group', 'gd-r
2477
2565
  class RangeSelectionDirective {
2478
2566
  /** Emits the copied cell matrix (rows × cols of displayed text) on Ctrl/Cmd+C. */
2479
2567
  rangeCopy = output();
2568
+ /** Emits the parsed clipboard matrix on Ctrl/Cmd+V for the consumer to write back. */
2569
+ rangePaste = output();
2570
+ /** Emits the selected range on Delete/Backspace for the consumer to clear. */
2571
+ rangeClear = output();
2480
2572
  _host = inject(ElementRef);
2481
2573
  _doc = inject(DOCUMENT);
2482
2574
  _engine = new RangeSelectionEngine({ onChange: () => this._paint() });
@@ -2506,9 +2598,18 @@ class RangeSelectionDirective {
2506
2598
  this._engine.extendSelection(pos.row, pos.col);
2507
2599
  }
2508
2600
  onKeyDown(event) {
2509
- if ((event.ctrlKey || event.metaKey) && (event.key === 'c' || event.key === 'C')) {
2601
+ const mod = event.ctrlKey || event.metaKey;
2602
+ if (mod && (event.key === 'c' || event.key === 'C')) {
2603
+ if (this._engine.getSelection())
2604
+ event.preventDefault();
2510
2605
  this._copy();
2511
2606
  }
2607
+ else if (mod && (event.key === 'v' || event.key === 'V')) {
2608
+ this._paste();
2609
+ }
2610
+ else if (event.key === 'Delete' || event.key === 'Backspace') {
2611
+ this._clear(event);
2612
+ }
2512
2613
  }
2513
2614
  /** The current selection engine (for advanced consumers / testing). */
2514
2615
  get engine() {
@@ -2560,6 +2661,28 @@ class RangeSelectionDirective {
2560
2661
  void navigator.clipboard?.writeText?.(tsv);
2561
2662
  this.rangeCopy.emit(matrix);
2562
2663
  }
2664
+ _paste() {
2665
+ const read = navigator.clipboard?.readText?.();
2666
+ if (!read)
2667
+ return;
2668
+ void read.then((text) => {
2669
+ if (!text)
2670
+ return;
2671
+ const selection = this._engine.getSelection();
2672
+ this.rangePaste.emit({
2673
+ startRow: selection?.startRowIndex ?? 0,
2674
+ startCol: selection?.startColIndex ?? 0,
2675
+ data: parseTSV(text),
2676
+ });
2677
+ });
2678
+ }
2679
+ _clear(event) {
2680
+ const selection = this._engine.getSelection();
2681
+ if (!selection)
2682
+ return;
2683
+ event.preventDefault();
2684
+ this.rangeClear.emit(selection);
2685
+ }
2563
2686
  _ensureStyles() {
2564
2687
  if (this._doc.getElementById(STYLE_ID))
2565
2688
  return;
@@ -2569,7 +2692,7 @@ class RangeSelectionDirective {
2569
2692
  this._doc.head.appendChild(style);
2570
2693
  }
2571
2694
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: RangeSelectionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2572
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.2", type: RangeSelectionDirective, isStandalone: true, selector: "[gdRangeSelection]", outputs: { rangeCopy: "rangeCopy" }, host: { listeners: { "mousedown": "onMouseDown($event)", "mousemove": "onMouseMove($event)", "keydown": "onKeyDown($event)" } }, ngImport: i0 });
2695
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.2", type: RangeSelectionDirective, isStandalone: true, selector: "[gdRangeSelection]", outputs: { rangeCopy: "rangeCopy", rangePaste: "rangePaste", rangeClear: "rangeClear" }, host: { listeners: { "mousedown": "onMouseDown($event)", "mousemove": "onMouseMove($event)", "keydown": "onKeyDown($event)" } }, ngImport: i0 });
2573
2696
  }
2574
2697
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: RangeSelectionDirective, decorators: [{
2575
2698
  type: Directive,
@@ -2577,7 +2700,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
2577
2700
  selector: '[gdRangeSelection]',
2578
2701
  standalone: true,
2579
2702
  }]
2580
- }], ctorParameters: () => [], propDecorators: { rangeCopy: [{ type: i0.Output, args: ["rangeCopy"] }], onMouseDown: [{
2703
+ }], ctorParameters: () => [], propDecorators: { rangeCopy: [{ type: i0.Output, args: ["rangeCopy"] }], rangePaste: [{ type: i0.Output, args: ["rangePaste"] }], rangeClear: [{ type: i0.Output, args: ["rangeClear"] }], onMouseDown: [{
2581
2704
  type: HostListener,
2582
2705
  args: ['mousedown', ['$event']]
2583
2706
  }], onMouseMove: [{
@@ -2600,5 +2723,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
2600
2723
  * Generated bundle index. Do not edit.
2601
2724
  */
2602
2725
 
2603
- export { AuditTrailEngine, CellPermissionEngine, ClipboardEngine, DEFAULT_MASK, DataGridPro, ExcelImportEngine, FillHandleEngine, FilterPresetEngine, FormEditorEngine, FormulaEngine, GridLicenseWatermark, LicenseManager, MasterDetailEngine, PDFExportEngine, PRODUCT_ID, PURCHASE_URL, RangeSelectionDirective, RangeSelectionEngine, RowLockEngine, SSRMEngine, SavedViewsEngine, TransactionEngine, UndoRedoManager, applyCellPermissions, deserializeFilter, evaluateFilter, parseCSV, parseTSV, provideGridEngineLicense, serializeFilter, toNumber, toPdfColumns, toTimestamp };
2726
+ export { AuditTrailEngine, CellPermissionEngine, ClipboardEngine, DEFAULT_MASK, DataGridPro, ExcelImportEngine, FillHandleEngine, FilterPresetEngine, FormEditorEngine, FormulaEngine, GridLicenseWatermark, LicenseManager, MasterDetailEngine, PDFExportEngine, PRODUCT_ID, PURCHASE_URL, RangeSelectionDirective, RangeSelectionEngine, RowLockEngine, SSRMEngine, SavedViewsEngine, TransactionController, TransactionEngine, UndoRedoManager, applyCellPermissions, deserializeFilter, evaluateFilter, parseCSV, parseTSV, provideGridEngineLicense, serializeFilter, toNumber, toPdfColumns, toTimestamp };
2604
2727
  //# sourceMappingURL=gridengine-angular-datagrid-enterprise.mjs.map