@wavemaker/app-ng-runtime 11.14.1-22.647589 → 11.14.1-23.647643

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.
Files changed (26) hide show
  1. package/components/base/bundles/index.umd.js +0 -10
  2. package/components/base/esm2022/widgets/common/base/base.component.mjs +1 -11
  3. package/components/base/fesm2022/index.mjs +0 -10
  4. package/components/base/fesm2022/index.mjs.map +1 -1
  5. package/components/data/pagination/bundles/index.umd.js +2 -1
  6. package/components/data/pagination/esm2022/pagination.component.mjs +3 -2
  7. package/components/data/pagination/fesm2022/index.mjs +2 -1
  8. package/components/data/pagination/fesm2022/index.mjs.map +1 -1
  9. package/components/data/table/bundles/index.umd.js +157 -9
  10. package/components/data/table/esm2022/table-column/table-column.directive.mjs +2 -2
  11. package/components/data/table/esm2022/table-cud.directive.mjs +14 -3
  12. package/components/data/table/esm2022/table-filter.directive.mjs +34 -5
  13. package/components/data/table/esm2022/table.component.mjs +111 -3
  14. package/components/data/table/fesm2022/index.mjs +158 -10
  15. package/components/data/table/fesm2022/index.mjs.map +1 -1
  16. package/components/data/table/table.component.d.ts +10 -0
  17. package/npm-shrinkwrap.json +2 -2
  18. package/package-lock.json +2 -2
  19. package/package.json +1 -1
  20. package/runtime/base/bundles/index.umd.js +20 -12
  21. package/runtime/base/components/base-prefab.component.d.ts +6 -4
  22. package/runtime/base/esm2022/components/base-partial.component.mjs +2 -2
  23. package/runtime/base/esm2022/components/base-prefab.component.mjs +20 -12
  24. package/runtime/base/fesm2022/index.mjs +20 -12
  25. package/runtime/base/fesm2022/index.mjs.map +1 -1
  26. package/scripts/datatable/datatable.js +185 -26
@@ -129,6 +129,19 @@
129
129
  };
130
130
  class TableComponent extends i4.StylableComponent {
131
131
  static { this.initializeProps = registerProps$5(); }
132
+ /** wm.Variable + inline or quickedit (editmode is string from markup; normalize case). */
133
+ isModelVariableInlineOrQuickEdit() {
134
+ if (lodashEs.get(this.datasource, 'category') !== 'wm.Variable') {
135
+ return false;
136
+ }
137
+ const em = String(this.editmode || '').toLowerCase();
138
+ return em === 'quickedit' || em === 'inline';
139
+ }
140
+ /** True while an inline/quickedit row save is updating the grid (incl. delayed navigator emit). */
141
+ shouldSoftRefreshAfterModelVarRowSave() {
142
+ return this.isModelVariableInlineOrQuickEdit()
143
+ && (this._isInlineEditSave || this._modelVarEditSoftRefreshActiveUntil > Date.now());
144
+ }
132
145
  set gridData(newValue) {
133
146
  this.isDataLoading = false;
134
147
  // Fix for [WMS-24012]: hide no datafound msg when variableInflight is true and dataset is empty
@@ -196,7 +209,14 @@
196
209
  console.warn('Error in beforedatarender event callback, continuing with table rendering:', error);
197
210
  }
198
211
  }
199
- this.setDataGridOption('data', i2.getClonedObject(this._gridData));
212
+ if (this.shouldSoftRefreshAfterModelVarRowSave()) {
213
+ const clonedData = i2.getClonedObject(this._gridData);
214
+ this.gridOptions.data = clonedData;
215
+ this.callDataGridMethod('softRefreshData', clonedData);
216
+ }
217
+ else {
218
+ this.setDataGridOption('data', i2.getClonedObject(this._gridData));
219
+ }
200
220
  }
201
221
  }
202
222
  get gridData() {
@@ -249,6 +269,8 @@
249
269
  this.formfields = {};
250
270
  this.enablesort = true;
251
271
  this.showviewlessbutton = false;
272
+ /** Covers async navigator/dataset updates after inline/quickedit save (wm.Variable). */
273
+ this._modelVarEditSoftRefreshActiveUntil = 0;
252
274
  this.primaryKey = [];
253
275
  this.selectedItems = [];
254
276
  this.selectedItemChange = new rxjs.Subject();
@@ -587,10 +609,24 @@
587
609
  this.prevData = i2.getClonedObject(row);
588
610
  },
589
611
  afterRowUpdate: (row, e, callBack, options) => {
612
+ const isModelVarInlineOrQuick = this.isModelVariableInlineOrQuickEdit();
613
+ if (isModelVarInlineOrQuick) {
614
+ this._isInlineEditSave = true;
615
+ // Inline save triggers navigatePage / dataset emit asynchronously; a
616
+ // microtask timeout cleared the flag before gridData ran → full rerender.
617
+ this._modelVarEditSoftRefreshActiveUntil = Date.now() + 550;
618
+ }
590
619
  i2.muteWatchers();
591
- this.updateRecord(lodashEs.extend({}, options, { row, 'prevData': options.rowindex ? options.rowindex : this.prevData, 'event': e, 'callBack': callBack }));
620
+ const v = lodashEs.get(this.datasource, 'category') === 'wm.Variable' && options && options.rowindex != null;
621
+ this.updateRecord(lodashEs.extend({}, options, { row, prevData: v ? options.rowindex : this.prevData, event: e, callBack }));
592
622
  setTimeout(() => {
593
623
  i2.unMuteWatchers();
624
+ if (isModelVarInlineOrQuick) {
625
+ setTimeout(() => {
626
+ this._isInlineEditSave = false;
627
+ this._modelVarEditSoftRefreshActiveUntil = 0;
628
+ }, 520);
629
+ }
594
630
  }, 10);
595
631
  },
596
632
  onBeforeRowUpdate: (row, e, options) => {
@@ -663,11 +699,67 @@
663
699
  this.customExprCompiledTl = {};
664
700
  this.customExprCompiledSummaryTl = {};
665
701
  },
702
+ updateCustomExpressionContexts: (preparedData) => {
703
+ const viewCount = this.customExprViewRef.length;
704
+ for (let i = 0; i < viewCount; i++) {
705
+ const viewRef = this.customExprViewRef.get(i);
706
+ if (!viewRef || !viewRef.context || !viewRef.context.row || viewRef.context.row.$index === undefined) {
707
+ continue;
708
+ }
709
+ const existingRow = viewRef.context.row;
710
+ const rowIndex = existingRow.$index - 1;
711
+ const dataRow = preparedData[rowIndex];
712
+ if (!dataRow) {
713
+ continue;
714
+ }
715
+ Object.keys(dataRow).forEach(key => {
716
+ if (key !== '$$index' && key !== '$$pk') {
717
+ existingRow[key] = dataRow[key];
718
+ }
719
+ });
720
+ existingRow.$isFirst = existingRow.$index === 1;
721
+ existingRow.$isLast = this.gridData.length === existingRow.$index;
722
+ viewRef.markForCheck();
723
+ }
724
+ },
666
725
  clearRowDetailExpression: () => {
667
726
  this.rowDetailViewRef.clear();
668
727
  this.rowDefMap = {};
669
728
  this.rowDefInstances = {};
670
729
  },
730
+ invalidateRowDetailCache: (preparedData) => {
731
+ this.rowDefMap = {};
732
+ this.rowDefInstances = {};
733
+ // Update existing row detail view contexts in-place so currently
734
+ // expanded partials pick up the new row data via change detection.
735
+ const viewCount = this.rowDetailViewRef.length;
736
+ for (let i = 0; i < viewCount; i++) {
737
+ const viewRef = this.rowDetailViewRef.get(i);
738
+ if (!viewRef || !viewRef.context || !viewRef.context.row) {
739
+ continue;
740
+ }
741
+ const existingRow = viewRef.context.row;
742
+ const rowIndex = existingRow.$index - 1;
743
+ const dataRow = preparedData[rowIndex];
744
+ if (!dataRow) {
745
+ continue;
746
+ }
747
+ Object.keys(dataRow).forEach(key => {
748
+ if (key !== '$$index' && key !== '$$pk') {
749
+ existingRow[key] = dataRow[key];
750
+ }
751
+ });
752
+ viewRef.markForCheck();
753
+ }
754
+ },
755
+ refreshSelectedItems: () => {
756
+ const selectedRows = this.callDataGridMethod('getSelectedRows');
757
+ if (selectedRows.length) {
758
+ this.items.length = 0;
759
+ selectedRows.forEach(row => this.items.push(row));
760
+ this.selectedItemChange.next(selectedRows);
761
+ }
762
+ },
671
763
  generateCustomExpressions: (rowData, index, summaryRow) => {
672
764
  const row = this.getClonedRowObject(rowData);
673
765
  const compileTemplate = (tmpl) => {
@@ -1355,6 +1447,8 @@
1355
1447
  }
1356
1448
  }
1357
1449
  ngOnDestroy() {
1450
+ this._modelVarEditSoftRefreshActiveUntil = 0;
1451
+ this._isInlineEditSave = false;
1358
1452
  // MEMORY LEAK FIX: Remove document click listener
1359
1453
  document.removeEventListener('click', this.documentClickBind);
1360
1454
  // MEMORY LEAK FIX: Unsubscribe from navigator watches
@@ -1527,6 +1621,7 @@
1527
1621
  row.$isLast = this.gridData.length === row.$index;
1528
1622
  delete row.$$index;
1529
1623
  delete row.$$pk;
1624
+ delete row.$$wmSourceListIndex;
1530
1625
  return row;
1531
1626
  }
1532
1627
  handleLoading(data) {
@@ -1768,6 +1863,14 @@
1768
1863
  // Apply filter and sort, if data is refreshed through Refresh data method
1769
1864
  if (!this.isNavigationEnabled() && this._isClientSearch) {
1770
1865
  data = i2.getClonedObject(serviceData);
1866
+ if (lodashEs.isObject(data) && !lodashEs.isArray(data)) {
1867
+ data = [data];
1868
+ }
1869
+ if (lodashEs.get(this.datasource, 'category') === 'wm.Variable' && lodashEs.isArray(data)) {
1870
+ for (let i = 0; i < data.length; i++) {
1871
+ data[i].$$wmSourceListIndex = i;
1872
+ }
1873
+ }
1771
1874
  data = this.getSearchResult(data, this.filterInfo);
1772
1875
  data = this.getSortResult(data, this.sortInfo);
1773
1876
  this.serverData = data;
@@ -2268,6 +2371,11 @@
2268
2371
  if (lodashEs.isObject(data) && !lodashEs.isArray(data)) {
2269
2372
  data = [data];
2270
2373
  }
2374
+ if (lodashEs.get(this.datasource, 'category') === 'wm.Variable' && lodashEs.isArray(data)) {
2375
+ for (let i = 0; i < data.length; i++) {
2376
+ data[i].$$wmSourceListIndex = i;
2377
+ }
2378
+ }
2271
2379
  data = this.getSearchResult(data, this.filterInfo);
2272
2380
  data = this.getSortResult(data, this.sortInfo);
2273
2381
  return data;
@@ -2695,7 +2803,11 @@
2695
2803
  if (dataSource.execute(i2.DataSource.Operation.SUPPORTS_CRUD) || !dataSource.execute(i2.DataSource.Operation.IS_API_AWARE) || dataSource.category === 'wm.CrudVariable') {
2696
2804
  if (!dataSource.execute(i2.DataSource.Operation.IS_API_AWARE)) {
2697
2805
  const extraOptions = this.generatePath(this.table.binddataset);
2698
- dataSource.execute(i2.DataSource.Operation.SET_ITEM, { prevItem: options.prevData, item: options.row, path: extraOptions.path, parentIndex: extraOptions.index });
2806
+ const item = options.row;
2807
+ if (dataSource.category === 'wm.Variable' && item) {
2808
+ delete item['$$wmSourceListIndex'];
2809
+ }
2810
+ dataSource.execute(i2.DataSource.Operation.SET_ITEM, { prevItem: options.prevData, item, path: extraOptions.path, parentIndex: extraOptions.index });
2699
2811
  this.updateSuccessHandler(options.row, options);
2700
2812
  return;
2701
2813
  }
@@ -2778,7 +2890,14 @@
2778
2890
  if (dataSource.execute(i2.DataSource.Operation.SUPPORTS_CRUD) || !dataSource.execute(i2.DataSource.Operation.IS_API_AWARE) || this.table._isDependent || dataSource.category === 'wm.CrudVariable') {
2779
2891
  if (!dataSource.execute(i2.DataSource.Operation.IS_API_AWARE)) {
2780
2892
  const extraOptions = this.generatePath(this.table.binddataset);
2781
- dataSource.execute(i2.DataSource.Operation.REMOVE_ITEM, { item: options.row, path: extraOptions.path, parentIndex: extraOptions.index });
2893
+ let item = options.row;
2894
+ if (dataSource.category === 'wm.Variable' && options.rowindex != null) {
2895
+ item = options.rowindex;
2896
+ }
2897
+ else if (dataSource.category === 'wm.Variable' && item) {
2898
+ delete item['$$wmSourceListIndex'];
2899
+ }
2900
+ dataSource.execute(i2.DataSource.Operation.REMOVE_ITEM, { item, path: extraOptions.path, parentIndex: extraOptions.index });
2782
2901
  this.deleteSuccessHandler(options.row, undefined, options.evt, options.callBack);
2783
2902
  return;
2784
2903
  }
@@ -3241,9 +3360,15 @@
3241
3360
  }
3242
3361
  // Function that checks if a given string is a valid date and returns the timestamp if it is, or NaN if it's not.
3243
3362
  parseDateString(dateString) {
3363
+ if (typeof dateString !== 'string') {
3364
+ return NaN;
3365
+ }
3366
+ const trimmed = dateString.trim();
3367
+ if (!trimmed) {
3368
+ return NaN;
3369
+ }
3244
3370
  const timestamp = Date.parse(dateString);
3245
3371
  // handling case when string starts with string and end with number
3246
- const trimmed = dateString.trim();
3247
3372
  const monthRegex = /\b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b/i;
3248
3373
  if (/^[A-Za-z]+/.test(trimmed) && /\d+$/.test(trimmed) && !monthRegex.test(trimmed)) {
3249
3374
  return NaN;
@@ -3259,20 +3384,38 @@
3259
3384
  // Returns data sorted using sortObj
3260
3385
  getSortResult(data, sortObj) {
3261
3386
  if (sortObj && sortObj.direction) {
3262
- const fieldValue = lodashEs.get(lodashEs.find(data, sortObj.field), sortObj.field);
3387
+ const sampleItem = lodashEs.find(data, (item) => {
3388
+ const v = lodashEs.get(item, sortObj.field);
3389
+ return typeof v === 'string' && !!v.trim();
3390
+ });
3391
+ const fieldValue = sampleItem ? lodashEs.get(sampleItem, sortObj.field) : undefined;
3263
3392
  const isValidDateString = typeof fieldValue === 'string' ? this.parseDateString(fieldValue) : NaN;
3264
3393
  if (!isNaN(isValidDateString)) { // if the field is a date string
3265
- data = lodashEs.orderBy(data, [(item) => this.parseDateString(lodashEs.get(item, sortObj.field))], [sortObj.direction]);
3394
+ data = lodashEs.orderBy(data, [
3395
+ (item) => {
3396
+ const v = lodashEs.get(item, sortObj.field);
3397
+ return v === null || v === undefined || v === '' ? 1 : 0;
3398
+ },
3399
+ (item) => {
3400
+ const ts = this.parseDateString(lodashEs.get(item, sortObj.field));
3401
+ return isNaN(ts) ? 1 : 0;
3402
+ },
3403
+ (item) => this.parseDateString(lodashEs.get(item, sortObj.field))
3404
+ ], ['asc', 'asc', sortObj.direction]);
3266
3405
  }
3267
3406
  else if (sortObj.sortBy ? this.table.columns[sortObj.sortBy]?.caseinsensitive : this.table.columns[sortObj.field]?.caseinsensitive) {
3268
3407
  //Fix for [WMS-27505]: Added case-insensitive sorting so that uppercase and lowercase letters are treated the same when sorting.
3269
3408
  data = lodashEs.orderBy(data, [
3409
+ (item) => {
3410
+ const val = lodashEs.get(item, sortObj.field);
3411
+ return val === null || val === undefined || val === '' ? 1 : 0;
3412
+ },
3270
3413
  (item) => {
3271
3414
  const val = lodashEs.get(item, sortObj.field);
3272
3415
  return typeof val === 'string' ? val.toLowerCase() : val;
3273
3416
  },
3274
3417
  (item) => lodashEs.get(item, sortObj.field) // fallback to original value
3275
- ], [sortObj.direction, sortObj.direction]);
3418
+ ], ['asc', sortObj.direction, sortObj.direction]);
3276
3419
  }
3277
3420
  else {
3278
3421
  data = lodashEs.orderBy(data, sortObj.field, sortObj.direction);
@@ -3294,6 +3437,11 @@
3294
3437
  if (lodashEs.isObject(data) && !lodashEs.isArray(data)) {
3295
3438
  data = [data];
3296
3439
  }
3440
+ if (lodashEs.get(this.table.datasource, 'category') === 'wm.Variable' && lodashEs.isArray(data)) {
3441
+ for (let i = 0; i < data.length; i++) {
3442
+ data[i].$$wmSourceListIndex = i;
3443
+ }
3444
+ }
3297
3445
  /*Both the functions return same 'data' if arguments are undefined*/
3298
3446
  data = this.getSearchResult(data, this.table.filterInfo);
3299
3447
  data = this.getSortResult(data, this.table.sortInfo);
@@ -4493,7 +4641,7 @@
4493
4641
  this.defaultvalue = i4.getDefaultValue(this.defaultvalue, this.type, this.editWidgetType);
4494
4642
  break;
4495
4643
  case 'show':
4496
- this.table.redraw(true);
4644
+ this.table.redraw(false);
4497
4645
  this.showinfilter = this.nativeElement.hasAttribute('showinfilter') ? this.nativeElement.getAttribute('showinfilter') : nv;
4498
4646
  break;
4499
4647
  case 'filterdataset':