@zeedhi/teknisa-components-common 1.107.0 → 1.107.1

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.
@@ -1508,6 +1508,22 @@ class GridController {
1508
1508
  }
1509
1509
  }
1510
1510
 
1511
+ /**
1512
+ * Extracts properties from an object based on a list of properties
1513
+ * @param obj object whose properties will be extracted
1514
+ * @param props array of strings with the properties to be extracted
1515
+ * @returns object containing the extracted properties
1516
+ */
1517
+ const extractProperties = (obj, props) => {
1518
+ const result = {};
1519
+ props.forEach((prop) => {
1520
+ if (obj[prop] !== undefined) {
1521
+ result[prop] = obj[prop];
1522
+ }
1523
+ });
1524
+ return result;
1525
+ };
1526
+
1511
1527
  const DynamicFilterOperations = {
1512
1528
  CONTAINS: true,
1513
1529
  NOT_CONTAINS: true,
@@ -1597,6 +1613,14 @@ class TekMemoryDatasource extends MemoryDatasource {
1597
1613
  }
1598
1614
  return superQueryString + dynamicFilterQuerystring + searchJoinQuerystring;
1599
1615
  }
1616
+ /**
1617
+ * Allows the comunication between the base filter and the dynamic filter
1618
+ * @param filtroDinamico
1619
+ * @returns
1620
+ */
1621
+ setBaseFilter(filtroDinamico) {
1622
+ return this.setDynamicFilter(filtroDinamico);
1623
+ }
1600
1624
  /**
1601
1625
  * Adds a new dynamic filter position or replace if exists
1602
1626
  * @param column Dynamic Filter column name
@@ -1674,12 +1698,15 @@ class TekMemoryDatasource extends MemoryDatasource {
1674
1698
  * @returns Is valid filter value
1675
1699
  */
1676
1700
  isValidDynamicFilterValue(column, value) {
1701
+ if (!Array.isArray(value))
1702
+ return false;
1677
1703
  return !this.reservedKeys[column]
1678
- && value
1679
1704
  && value.length > 0
1680
- && value.every((filterValue) => this.dynamicFilterOperations[filterValue.operation]
1705
+ && value.every((filterValue) => filterValue
1706
+ && this.dynamicFilterOperations[filterValue.operation]
1681
1707
  && this.dynamicFilterRelations[filterValue.relation]
1682
- && filterValue.value !== '' && filterValue.value !== null);
1708
+ && filterValue.value !== ''
1709
+ && filterValue.value !== null);
1683
1710
  }
1684
1711
  clone() {
1685
1712
  return Object.assign(Object.assign({}, super.clone()), { dynamicFilter: this.dynamicFilter, searchJoin: this.searchJoin, type: 'tek-memory' });
@@ -1866,6 +1893,14 @@ class TekRestDatasource extends RestDatasource {
1866
1893
  }
1867
1894
  return superQueryString + dynamicFilterQuerystring + searchJoinQuerystring;
1868
1895
  }
1896
+ /**
1897
+ * Allows the comunication between the base filter and the dynamic filter
1898
+ * @param filtroDinamico
1899
+ * @returns
1900
+ */
1901
+ setBaseFilter(filtroDinamico) {
1902
+ return this.setDynamicFilter(filtroDinamico);
1903
+ }
1869
1904
  /**
1870
1905
  * Adds a new dynamic filter position or replace if exists
1871
1906
  * @param column Dynamic Filter column name
@@ -1943,12 +1978,15 @@ class TekRestDatasource extends RestDatasource {
1943
1978
  * @returns Is valid filter value
1944
1979
  */
1945
1980
  isValidDynamicFilterValue(column, value) {
1981
+ if (!Array.isArray(value))
1982
+ return false;
1946
1983
  return !this.reservedKeys[column]
1947
- && value
1948
1984
  && value.length > 0
1949
- && value.every((filterValue) => this.dynamicFilterOperations[filterValue.operation]
1985
+ && value.every((filterValue) => filterValue
1986
+ && this.dynamicFilterOperations[filterValue.operation]
1950
1987
  && this.dynamicFilterRelations[filterValue.relation]
1951
- && filterValue.value !== '' && filterValue.value !== null);
1988
+ && filterValue.value !== ''
1989
+ && filterValue.value !== null);
1952
1990
  }
1953
1991
  /**
1954
1992
  * Retrieves request params
@@ -2157,6 +2195,19 @@ class TekGridColumn extends GridColumnEditable {
2157
2195
  }
2158
2196
  }
2159
2197
 
2198
+ /**
2199
+ * Thrown when a row has incomplete group information.
2200
+ * Provides details about the missing groups and the problematic row.
2201
+ */
2202
+ class IncompleteGroupsError extends Error {
2203
+ constructor(row, missingGroups) {
2204
+ const rowPreview = JSON.stringify(row);
2205
+ const message = `Row groups are incomplete. Missing groups: ${missingGroups.join(', ')}.\nRow data:\n${rowPreview}`;
2206
+ super(message);
2207
+ this.name = 'IncompleteGroupsError';
2208
+ }
2209
+ }
2210
+
2160
2211
  /* TekGrid Class */
2161
2212
  class TekGrid extends GridEditable {
2162
2213
  /**
@@ -2602,9 +2653,10 @@ class TekGrid extends GridEditable {
2602
2653
  this.groups.forEach((group) => {
2603
2654
  group.lastGroupHeaderRow.children.push(row);
2604
2655
  });
2605
- this.groupedData.push(Object.assign(Object.assign({}, row), { groupHeaders: this.groups
2606
- .map((group) => group.lastGroupHeaderRow)
2607
- .filter(Boolean) }));
2656
+ const groupHeaders = this.groups
2657
+ .map((group) => group.lastGroupHeaderRow)
2658
+ .filter(Boolean);
2659
+ this.groupedData.push(Object.assign(Object.assign({}, row), { groupHeaders }));
2608
2660
  this.calcSummary(row);
2609
2661
  });
2610
2662
  if (this.groupedData.length > 0) {
@@ -2660,14 +2712,14 @@ class TekGrid extends GridEditable {
2660
2712
  return;
2661
2713
  }
2662
2714
  for (let i = this.groups.length - 1; i >= groupIndex; i -= 1) {
2663
- if (this.groups[i].initialized) {
2664
- const groupFooterRow = Object.assign({ groupFooter: true, groupIndex: i, groupHeaders: [], groupLabel: this.groups[i].lastGroupHeaderRow.groupLabel, groupValue: this.groups[i].lastGroupHeaderRow.groupValue }, this.summaryData(this.groups[i].footer));
2665
- // add header for outer groups
2666
- for (let g = 0; g < i; g += 1) {
2667
- groupFooterRow.groupHeaders.push(this.groups[g].lastGroupHeaderRow);
2668
- }
2669
- this.groupedData.push(groupFooterRow);
2715
+ if (!this.groups[i].initialized)
2716
+ return;
2717
+ const groupFooterRow = Object.assign({ groupFooter: true, groupIndex: i, groupHeaders: [], groupLabel: this.groups[i].lastGroupHeaderRow.groupLabel, groupValue: this.groups[i].lastGroupHeaderRow.groupValue }, this.summaryData(this.groups[i].footer));
2718
+ // add header for outer groups
2719
+ for (let g = 0; g < i; g += 1) {
2720
+ groupFooterRow.groupHeaders.push(this.groups[g].lastGroupHeaderRow);
2670
2721
  }
2722
+ this.groupedData.push(groupFooterRow);
2671
2723
  }
2672
2724
  }
2673
2725
  resetFooterVariables(group) {
@@ -2917,6 +2969,7 @@ class TekGrid extends GridEditable {
2917
2969
  */
2918
2970
  groupRowClick(row, event, element) {
2919
2971
  if (!this.preventRowClick) {
2972
+ this.datasource.currentRow = row;
2920
2973
  this.callEvent('groupRowClick', {
2921
2974
  event,
2922
2975
  element,
@@ -2929,6 +2982,7 @@ class TekGrid extends GridEditable {
2929
2982
  }
2930
2983
  groupRowDoubleClick(row, event, element) {
2931
2984
  if (!this.preventRowDoubleClick) {
2985
+ this.datasource.currentRow = row;
2932
2986
  this.callEvent('groupRowDoubleClick', {
2933
2987
  event,
2934
2988
  element,
@@ -2978,6 +3032,157 @@ class TekGrid extends GridEditable {
2978
3032
  getColumn(name) {
2979
3033
  return super.getColumn(name);
2980
3034
  }
3035
+ /**
3036
+ * Adds new row to the datasource data and pushes it to the editedRows
3037
+ * @param row Row
3038
+ * @param position whether the new Row will be inserted at the beginning or end of the data array
3039
+ */
3040
+ addNewRow(row, position = 'end') {
3041
+ const _super = Object.create(null, {
3042
+ addNewRow: { get: () => super.addNewRow }
3043
+ });
3044
+ return __awaiter(this, void 0, void 0, function* () {
3045
+ if (!this.groupColumns.length) {
3046
+ yield _super.addNewRow.call(this, row, position);
3047
+ return;
3048
+ }
3049
+ this.insertRowInDatasource(row, position);
3050
+ this.saveRowReference(row);
3051
+ this.addGroupedRow(row, position);
3052
+ this.editing = true;
3053
+ });
3054
+ }
3055
+ /**
3056
+ * Takes a row and adds it to the selected group (datasource.currentRow)
3057
+ * @param row the new row to be added
3058
+ * @param position the position, at the beginning of the group or at the end
3059
+ */
3060
+ addToSelection(row, position = 'end') {
3061
+ const { currentRow } = this.datasource;
3062
+ // if the currentRow is a group, use the groupRow as reference
3063
+ const referenceRow = this.isGroupHeader(currentRow) ? currentRow.groupRow : currentRow;
3064
+ // extract the group properties from the referenceRow to add to the new row
3065
+ const groupProperties = extractProperties(referenceRow, this.groupColumnNames);
3066
+ const rowWithGroups = Object.assign(Object.assign({}, row), groupProperties);
3067
+ return this.addNewRow(rowWithGroups, position);
3068
+ }
3069
+ /**
3070
+ * Adds a new row to the groupedData array
3071
+ * @param row the new row to be added
3072
+ * @param position the position, at the beginning of the group or at the end
3073
+ */
3074
+ addGroupedRow(row, position) {
3075
+ const missingGroups = this.findMissingGroups(row);
3076
+ if (missingGroups.length > 0) {
3077
+ throw new IncompleteGroupsError(row, missingGroups);
3078
+ }
3079
+ const { index, group } = this.findLastGroupingIndex(row);
3080
+ const groupHeaders = [...group.groupHeaders, group];
3081
+ const newGroupedRow = Object.assign(Object.assign({}, row), { groupHeaders });
3082
+ if (position === 'end') {
3083
+ const childrenLength = group.children.length;
3084
+ this.groupedData.splice(index + childrenLength + 1, 0, newGroupedRow);
3085
+ }
3086
+ else {
3087
+ this.groupedData.splice(index + 1, 0, newGroupedRow);
3088
+ }
3089
+ groupHeaders.forEach((groupHeader) => {
3090
+ // open all groups, making the new row visible to the user
3091
+ groupHeader.groupOpened = true;
3092
+ this.addRowToGroupChildren(row, groupHeader, position);
3093
+ });
3094
+ }
3095
+ findMissingGroups(row) {
3096
+ return this.groupColumnNames.filter((group) => row[group] === undefined);
3097
+ }
3098
+ /**
3099
+ * Finds the last group (most internal group) where a row should be inserted
3100
+ * @param row to be inserted
3101
+ * @returns the index and the group where the row should be inserted
3102
+ */
3103
+ findLastGroupingIndex(row) {
3104
+ const index = this.groupedData.findIndex((groupRow) => {
3105
+ // ignore rows that are not headers or not the last grouping (most internal groping)
3106
+ if (!this.isGroupHeader(groupRow) || !this.isLastGrouping(groupRow))
3107
+ return false;
3108
+ // if the new added row is not part of the group, ignore it
3109
+ if (groupRow.groupValue !== row[groupRow.groupColumnName])
3110
+ return false;
3111
+ if (this.groupColumns.length === 1)
3112
+ return true;
3113
+ const matchHeaders = groupRow.groupHeaders.every((groupHeader) => (groupHeader.groupValue === row[groupHeader.groupColumnName]));
3114
+ return matchHeaders;
3115
+ });
3116
+ if (index === -1) {
3117
+ // No existing group found, so we create the full group hierarchy
3118
+ return this.createGroupHierarchyForRow(row);
3119
+ }
3120
+ const group = this.groupedData[index];
3121
+ return { index, group };
3122
+ }
3123
+ /**
3124
+ * Creates a group hierarchy for a new row, creating intermediate groups if needed
3125
+ * @param row to be inserted
3126
+ * @returns the index and the group where the row should be inserted
3127
+ */
3128
+ createGroupHierarchyForRow(row) {
3129
+ let groupHeaders = [];
3130
+ let insertionIndex = this.groupedData.length; // default to end
3131
+ this.groups.forEach((column) => {
3132
+ const groupValue = row[column.name];
3133
+ const existingGroupIndex = this.groupedData.findIndex((groupRow) => this.isGroupHeader(groupRow)
3134
+ && groupRow.groupColumnName === column.name
3135
+ && groupRow.groupValue === groupValue
3136
+ && groupRow.groupHeaders.every((h, j) => h.groupValue === groupHeaders[j].groupValue));
3137
+ if (existingGroupIndex !== -1) {
3138
+ const existingGroup = this.groupedData[existingGroupIndex];
3139
+ groupHeaders = [...existingGroup.groupHeaders, existingGroup];
3140
+ insertionIndex = existingGroupIndex;
3141
+ return;
3142
+ }
3143
+ // Create new group header
3144
+ const newGroup = {
3145
+ group: true,
3146
+ groupHeader: true,
3147
+ groupValue,
3148
+ groupColumnName: column.name,
3149
+ groupHeaders: [...groupHeaders],
3150
+ children: [],
3151
+ groupRow: row,
3152
+ groupIndex: groupHeaders.length,
3153
+ groupLabel: I18n.translate(column.label),
3154
+ groupOpened: true,
3155
+ };
3156
+ // Insert right after last insertionIndex
3157
+ insertionIndex += 1;
3158
+ this.groupedData.splice(insertionIndex, 0, newGroup);
3159
+ groupHeaders.push(newGroup);
3160
+ });
3161
+ const group = groupHeaders[groupHeaders.length - 1]; // the most inner group
3162
+ return { index: insertionIndex, group };
3163
+ }
3164
+ /**
3165
+ * Adds a row to the children of a group
3166
+ */
3167
+ addRowToGroupChildren(row, group, position) {
3168
+ if (position === 'end') {
3169
+ group.children.push(row);
3170
+ return;
3171
+ }
3172
+ group.children.unshift(row);
3173
+ }
3174
+ /**
3175
+ * Checks if a row is a group header, adding typescript type-checking
3176
+ */
3177
+ isGroupHeader(row) {
3178
+ return row.groupHeader;
3179
+ }
3180
+ /**
3181
+ * Checks if a row is the last grouping of the grid (the most internal grouping)
3182
+ */
3183
+ isLastGrouping(group) {
3184
+ return group.groupColumnName === this.groupColumns[this.groupColumns.length - 1].name;
3185
+ }
2981
3186
  }
2982
3187
 
2983
3188
  class TekGridColumnsButtonController extends IterableColumnsButtonController {
@@ -3321,7 +3526,7 @@ class TekGridFilterButton extends Button {
3321
3526
  }
3322
3527
  });
3323
3528
  datasource.dynamicFilter = filter;
3324
- this.setFilter(filter, event, datasource.setDynamicFilter.bind(datasource));
3529
+ this.setFilter(filter, event, datasource.setBaseFilter.bind(datasource));
3325
3530
  }
3326
3531
  else {
3327
3532
  Object.keys(formValue).forEach((item) => {
@@ -3332,7 +3537,7 @@ class TekGridFilterButton extends Button {
3332
3537
  }
3333
3538
  });
3334
3539
  datasource.filter = filter;
3335
- this.setFilter(filter, event, datasource.setFilter.bind(datasource));
3540
+ this.setFilter(filter, event, datasource.setBaseFilter.bind(datasource));
3336
3541
  }
3337
3542
  this.grid.changeLayout(event);
3338
3543
  }
@@ -1512,6 +1512,22 @@
1512
1512
  }
1513
1513
  }
1514
1514
 
1515
+ /**
1516
+ * Extracts properties from an object based on a list of properties
1517
+ * @param obj object whose properties will be extracted
1518
+ * @param props array of strings with the properties to be extracted
1519
+ * @returns object containing the extracted properties
1520
+ */
1521
+ const extractProperties = (obj, props) => {
1522
+ const result = {};
1523
+ props.forEach((prop) => {
1524
+ if (obj[prop] !== undefined) {
1525
+ result[prop] = obj[prop];
1526
+ }
1527
+ });
1528
+ return result;
1529
+ };
1530
+
1515
1531
  const DynamicFilterOperations = {
1516
1532
  CONTAINS: true,
1517
1533
  NOT_CONTAINS: true,
@@ -1601,6 +1617,14 @@
1601
1617
  }
1602
1618
  return superQueryString + dynamicFilterQuerystring + searchJoinQuerystring;
1603
1619
  }
1620
+ /**
1621
+ * Allows the comunication between the base filter and the dynamic filter
1622
+ * @param filtroDinamico
1623
+ * @returns
1624
+ */
1625
+ setBaseFilter(filtroDinamico) {
1626
+ return this.setDynamicFilter(filtroDinamico);
1627
+ }
1604
1628
  /**
1605
1629
  * Adds a new dynamic filter position or replace if exists
1606
1630
  * @param column Dynamic Filter column name
@@ -1678,12 +1702,15 @@
1678
1702
  * @returns Is valid filter value
1679
1703
  */
1680
1704
  isValidDynamicFilterValue(column, value) {
1705
+ if (!Array.isArray(value))
1706
+ return false;
1681
1707
  return !this.reservedKeys[column]
1682
- && value
1683
1708
  && value.length > 0
1684
- && value.every((filterValue) => this.dynamicFilterOperations[filterValue.operation]
1709
+ && value.every((filterValue) => filterValue
1710
+ && this.dynamicFilterOperations[filterValue.operation]
1685
1711
  && this.dynamicFilterRelations[filterValue.relation]
1686
- && filterValue.value !== '' && filterValue.value !== null);
1712
+ && filterValue.value !== ''
1713
+ && filterValue.value !== null);
1687
1714
  }
1688
1715
  clone() {
1689
1716
  return Object.assign(Object.assign({}, super.clone()), { dynamicFilter: this.dynamicFilter, searchJoin: this.searchJoin, type: 'tek-memory' });
@@ -1870,6 +1897,14 @@
1870
1897
  }
1871
1898
  return superQueryString + dynamicFilterQuerystring + searchJoinQuerystring;
1872
1899
  }
1900
+ /**
1901
+ * Allows the comunication between the base filter and the dynamic filter
1902
+ * @param filtroDinamico
1903
+ * @returns
1904
+ */
1905
+ setBaseFilter(filtroDinamico) {
1906
+ return this.setDynamicFilter(filtroDinamico);
1907
+ }
1873
1908
  /**
1874
1909
  * Adds a new dynamic filter position or replace if exists
1875
1910
  * @param column Dynamic Filter column name
@@ -1947,12 +1982,15 @@
1947
1982
  * @returns Is valid filter value
1948
1983
  */
1949
1984
  isValidDynamicFilterValue(column, value) {
1985
+ if (!Array.isArray(value))
1986
+ return false;
1950
1987
  return !this.reservedKeys[column]
1951
- && value
1952
1988
  && value.length > 0
1953
- && value.every((filterValue) => this.dynamicFilterOperations[filterValue.operation]
1989
+ && value.every((filterValue) => filterValue
1990
+ && this.dynamicFilterOperations[filterValue.operation]
1954
1991
  && this.dynamicFilterRelations[filterValue.relation]
1955
- && filterValue.value !== '' && filterValue.value !== null);
1992
+ && filterValue.value !== ''
1993
+ && filterValue.value !== null);
1956
1994
  }
1957
1995
  /**
1958
1996
  * Retrieves request params
@@ -2161,6 +2199,19 @@
2161
2199
  }
2162
2200
  }
2163
2201
 
2202
+ /**
2203
+ * Thrown when a row has incomplete group information.
2204
+ * Provides details about the missing groups and the problematic row.
2205
+ */
2206
+ class IncompleteGroupsError extends Error {
2207
+ constructor(row, missingGroups) {
2208
+ const rowPreview = JSON.stringify(row);
2209
+ const message = `Row groups are incomplete. Missing groups: ${missingGroups.join(', ')}.\nRow data:\n${rowPreview}`;
2210
+ super(message);
2211
+ this.name = 'IncompleteGroupsError';
2212
+ }
2213
+ }
2214
+
2164
2215
  /* TekGrid Class */
2165
2216
  class TekGrid extends common.GridEditable {
2166
2217
  /**
@@ -2606,9 +2657,10 @@
2606
2657
  this.groups.forEach((group) => {
2607
2658
  group.lastGroupHeaderRow.children.push(row);
2608
2659
  });
2609
- this.groupedData.push(Object.assign(Object.assign({}, row), { groupHeaders: this.groups
2610
- .map((group) => group.lastGroupHeaderRow)
2611
- .filter(Boolean) }));
2660
+ const groupHeaders = this.groups
2661
+ .map((group) => group.lastGroupHeaderRow)
2662
+ .filter(Boolean);
2663
+ this.groupedData.push(Object.assign(Object.assign({}, row), { groupHeaders }));
2612
2664
  this.calcSummary(row);
2613
2665
  });
2614
2666
  if (this.groupedData.length > 0) {
@@ -2664,14 +2716,14 @@
2664
2716
  return;
2665
2717
  }
2666
2718
  for (let i = this.groups.length - 1; i >= groupIndex; i -= 1) {
2667
- if (this.groups[i].initialized) {
2668
- const groupFooterRow = Object.assign({ groupFooter: true, groupIndex: i, groupHeaders: [], groupLabel: this.groups[i].lastGroupHeaderRow.groupLabel, groupValue: this.groups[i].lastGroupHeaderRow.groupValue }, this.summaryData(this.groups[i].footer));
2669
- // add header for outer groups
2670
- for (let g = 0; g < i; g += 1) {
2671
- groupFooterRow.groupHeaders.push(this.groups[g].lastGroupHeaderRow);
2672
- }
2673
- this.groupedData.push(groupFooterRow);
2719
+ if (!this.groups[i].initialized)
2720
+ return;
2721
+ const groupFooterRow = Object.assign({ groupFooter: true, groupIndex: i, groupHeaders: [], groupLabel: this.groups[i].lastGroupHeaderRow.groupLabel, groupValue: this.groups[i].lastGroupHeaderRow.groupValue }, this.summaryData(this.groups[i].footer));
2722
+ // add header for outer groups
2723
+ for (let g = 0; g < i; g += 1) {
2724
+ groupFooterRow.groupHeaders.push(this.groups[g].lastGroupHeaderRow);
2674
2725
  }
2726
+ this.groupedData.push(groupFooterRow);
2675
2727
  }
2676
2728
  }
2677
2729
  resetFooterVariables(group) {
@@ -2921,6 +2973,7 @@
2921
2973
  */
2922
2974
  groupRowClick(row, event, element) {
2923
2975
  if (!this.preventRowClick) {
2976
+ this.datasource.currentRow = row;
2924
2977
  this.callEvent('groupRowClick', {
2925
2978
  event,
2926
2979
  element,
@@ -2933,6 +2986,7 @@
2933
2986
  }
2934
2987
  groupRowDoubleClick(row, event, element) {
2935
2988
  if (!this.preventRowDoubleClick) {
2989
+ this.datasource.currentRow = row;
2936
2990
  this.callEvent('groupRowDoubleClick', {
2937
2991
  event,
2938
2992
  element,
@@ -2982,6 +3036,157 @@
2982
3036
  getColumn(name) {
2983
3037
  return super.getColumn(name);
2984
3038
  }
3039
+ /**
3040
+ * Adds new row to the datasource data and pushes it to the editedRows
3041
+ * @param row Row
3042
+ * @param position whether the new Row will be inserted at the beginning or end of the data array
3043
+ */
3044
+ addNewRow(row, position = 'end') {
3045
+ const _super = Object.create(null, {
3046
+ addNewRow: { get: () => super.addNewRow }
3047
+ });
3048
+ return __awaiter(this, void 0, void 0, function* () {
3049
+ if (!this.groupColumns.length) {
3050
+ yield _super.addNewRow.call(this, row, position);
3051
+ return;
3052
+ }
3053
+ this.insertRowInDatasource(row, position);
3054
+ this.saveRowReference(row);
3055
+ this.addGroupedRow(row, position);
3056
+ this.editing = true;
3057
+ });
3058
+ }
3059
+ /**
3060
+ * Takes a row and adds it to the selected group (datasource.currentRow)
3061
+ * @param row the new row to be added
3062
+ * @param position the position, at the beginning of the group or at the end
3063
+ */
3064
+ addToSelection(row, position = 'end') {
3065
+ const { currentRow } = this.datasource;
3066
+ // if the currentRow is a group, use the groupRow as reference
3067
+ const referenceRow = this.isGroupHeader(currentRow) ? currentRow.groupRow : currentRow;
3068
+ // extract the group properties from the referenceRow to add to the new row
3069
+ const groupProperties = extractProperties(referenceRow, this.groupColumnNames);
3070
+ const rowWithGroups = Object.assign(Object.assign({}, row), groupProperties);
3071
+ return this.addNewRow(rowWithGroups, position);
3072
+ }
3073
+ /**
3074
+ * Adds a new row to the groupedData array
3075
+ * @param row the new row to be added
3076
+ * @param position the position, at the beginning of the group or at the end
3077
+ */
3078
+ addGroupedRow(row, position) {
3079
+ const missingGroups = this.findMissingGroups(row);
3080
+ if (missingGroups.length > 0) {
3081
+ throw new IncompleteGroupsError(row, missingGroups);
3082
+ }
3083
+ const { index, group } = this.findLastGroupingIndex(row);
3084
+ const groupHeaders = [...group.groupHeaders, group];
3085
+ const newGroupedRow = Object.assign(Object.assign({}, row), { groupHeaders });
3086
+ if (position === 'end') {
3087
+ const childrenLength = group.children.length;
3088
+ this.groupedData.splice(index + childrenLength + 1, 0, newGroupedRow);
3089
+ }
3090
+ else {
3091
+ this.groupedData.splice(index + 1, 0, newGroupedRow);
3092
+ }
3093
+ groupHeaders.forEach((groupHeader) => {
3094
+ // open all groups, making the new row visible to the user
3095
+ groupHeader.groupOpened = true;
3096
+ this.addRowToGroupChildren(row, groupHeader, position);
3097
+ });
3098
+ }
3099
+ findMissingGroups(row) {
3100
+ return this.groupColumnNames.filter((group) => row[group] === undefined);
3101
+ }
3102
+ /**
3103
+ * Finds the last group (most internal group) where a row should be inserted
3104
+ * @param row to be inserted
3105
+ * @returns the index and the group where the row should be inserted
3106
+ */
3107
+ findLastGroupingIndex(row) {
3108
+ const index = this.groupedData.findIndex((groupRow) => {
3109
+ // ignore rows that are not headers or not the last grouping (most internal groping)
3110
+ if (!this.isGroupHeader(groupRow) || !this.isLastGrouping(groupRow))
3111
+ return false;
3112
+ // if the new added row is not part of the group, ignore it
3113
+ if (groupRow.groupValue !== row[groupRow.groupColumnName])
3114
+ return false;
3115
+ if (this.groupColumns.length === 1)
3116
+ return true;
3117
+ const matchHeaders = groupRow.groupHeaders.every((groupHeader) => (groupHeader.groupValue === row[groupHeader.groupColumnName]));
3118
+ return matchHeaders;
3119
+ });
3120
+ if (index === -1) {
3121
+ // No existing group found, so we create the full group hierarchy
3122
+ return this.createGroupHierarchyForRow(row);
3123
+ }
3124
+ const group = this.groupedData[index];
3125
+ return { index, group };
3126
+ }
3127
+ /**
3128
+ * Creates a group hierarchy for a new row, creating intermediate groups if needed
3129
+ * @param row to be inserted
3130
+ * @returns the index and the group where the row should be inserted
3131
+ */
3132
+ createGroupHierarchyForRow(row) {
3133
+ let groupHeaders = [];
3134
+ let insertionIndex = this.groupedData.length; // default to end
3135
+ this.groups.forEach((column) => {
3136
+ const groupValue = row[column.name];
3137
+ const existingGroupIndex = this.groupedData.findIndex((groupRow) => this.isGroupHeader(groupRow)
3138
+ && groupRow.groupColumnName === column.name
3139
+ && groupRow.groupValue === groupValue
3140
+ && groupRow.groupHeaders.every((h, j) => h.groupValue === groupHeaders[j].groupValue));
3141
+ if (existingGroupIndex !== -1) {
3142
+ const existingGroup = this.groupedData[existingGroupIndex];
3143
+ groupHeaders = [...existingGroup.groupHeaders, existingGroup];
3144
+ insertionIndex = existingGroupIndex;
3145
+ return;
3146
+ }
3147
+ // Create new group header
3148
+ const newGroup = {
3149
+ group: true,
3150
+ groupHeader: true,
3151
+ groupValue,
3152
+ groupColumnName: column.name,
3153
+ groupHeaders: [...groupHeaders],
3154
+ children: [],
3155
+ groupRow: row,
3156
+ groupIndex: groupHeaders.length,
3157
+ groupLabel: core.I18n.translate(column.label),
3158
+ groupOpened: true,
3159
+ };
3160
+ // Insert right after last insertionIndex
3161
+ insertionIndex += 1;
3162
+ this.groupedData.splice(insertionIndex, 0, newGroup);
3163
+ groupHeaders.push(newGroup);
3164
+ });
3165
+ const group = groupHeaders[groupHeaders.length - 1]; // the most inner group
3166
+ return { index: insertionIndex, group };
3167
+ }
3168
+ /**
3169
+ * Adds a row to the children of a group
3170
+ */
3171
+ addRowToGroupChildren(row, group, position) {
3172
+ if (position === 'end') {
3173
+ group.children.push(row);
3174
+ return;
3175
+ }
3176
+ group.children.unshift(row);
3177
+ }
3178
+ /**
3179
+ * Checks if a row is a group header, adding typescript type-checking
3180
+ */
3181
+ isGroupHeader(row) {
3182
+ return row.groupHeader;
3183
+ }
3184
+ /**
3185
+ * Checks if a row is the last grouping of the grid (the most internal grouping)
3186
+ */
3187
+ isLastGrouping(group) {
3188
+ return group.groupColumnName === this.groupColumns[this.groupColumns.length - 1].name;
3189
+ }
2985
3190
  }
2986
3191
 
2987
3192
  class TekGridColumnsButtonController extends common.IterableColumnsButtonController {
@@ -3325,7 +3530,7 @@
3325
3530
  }
3326
3531
  });
3327
3532
  datasource.dynamicFilter = filter;
3328
- this.setFilter(filter, event, datasource.setDynamicFilter.bind(datasource));
3533
+ this.setFilter(filter, event, datasource.setBaseFilter.bind(datasource));
3329
3534
  }
3330
3535
  else {
3331
3536
  Object.keys(formValue).forEach((item) => {
@@ -3336,7 +3541,7 @@
3336
3541
  }
3337
3542
  });
3338
3543
  datasource.filter = filter;
3339
- this.setFilter(filter, event, datasource.setFilter.bind(datasource));
3544
+ this.setFilter(filter, event, datasource.setBaseFilter.bind(datasource));
3340
3545
  }
3341
3546
  this.grid.changeLayout(event);
3342
3547
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeedhi/teknisa-components-common",
3
- "version": "1.107.0",
3
+ "version": "1.107.1",
4
4
  "description": "Teknisa Components Common",
5
5
  "author": "Zeedhi <zeedhi@teknisa.com>",
6
6
  "license": "ISC",
@@ -32,5 +32,5 @@
32
32
  "peerDependencies": {
33
33
  "@zeedhi/core": "^1.97.0"
34
34
  },
35
- "gitHead": "1123e6f810f91d3dbff16805911d4558caf9d6b2"
35
+ "gitHead": "ce6aeb7a4ebfca43f9ecb85ed411037f6032d214"
36
36
  }