@wavemaker/react-runtime 11.14.2-rc.6311 → 11.15.0-1.246

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 (245) hide show
  1. package/actions/base-action.js +5 -7
  2. package/actions/login-action.js +7 -8
  3. package/actions/logout-action.js +5 -7
  4. package/actions/navigation-action.js +73 -18
  5. package/actions/notification-action.js +22 -8
  6. package/actions/timer-action.js +13 -15
  7. package/actions/toast.js +4 -2
  8. package/actions/toast.service.js +1 -2
  9. package/components/advanced/carousel/index.js +1 -1
  10. package/components/advanced/carousel/template.js +1 -1
  11. package/components/basic/anchor/index.js +31 -11
  12. package/components/basic/html/index.js +115 -24
  13. package/components/basic/icon/index.js +2 -1
  14. package/components/basic/iframe/index.js +2 -1
  15. package/components/basic/label/index.js +12 -9
  16. package/components/basic/message/index.js +12 -3
  17. package/components/basic/picture/index.js +11 -4
  18. package/components/basic/progress-bar/index.js +4 -1
  19. package/components/basic/progress-circle/index.js +34 -28
  20. package/components/basic/progress-circle/props.js +10 -2
  21. package/components/basic/richtexteditor/index.js +95 -94
  22. package/components/basic/search/index.js +401 -156
  23. package/components/basic/search/providers.js +126 -61
  24. package/components/basic/spinner/index.js +2 -1
  25. package/components/basic/tree/index.js +34 -34
  26. package/components/basic/tree/utils.js +10 -4
  27. package/components/chart/components/barColumnChart/index.js +36 -33
  28. package/components/chart/components/bubbleChart/index.js +35 -25
  29. package/components/chart/components/chartLegend/utils.js +2 -1
  30. package/components/chart/components/cumulativeLineChart/index.js +30 -26
  31. package/components/chart/components/lineAreaChart/index.js +50 -32
  32. package/components/chart/components/pieDonutChart/index.js +13 -4
  33. package/components/chart/hooks/useXAxisConfig.js +15 -8
  34. package/components/chart/index.js +223 -53
  35. package/components/chart/utils.js +12 -1
  36. package/components/constants.js +5 -2
  37. package/components/container/accordion/accordion-pane/index.js +17 -12
  38. package/components/container/accordion/index.js +9 -4
  39. package/components/container/alignment-utils.js +56 -1
  40. package/components/container/index.js +49 -20
  41. package/components/container/panel/components/panel-header/index.js +3 -4
  42. package/components/container/panel/index.js +15 -10
  43. package/components/container/repeat-template/index.js +33 -0
  44. package/components/container/tabs/index.js +83 -14
  45. package/components/container/tabs/tab-pane/index.js +33 -10
  46. package/components/container/tabs/utils.js +51 -0
  47. package/components/container/wizard/components/StepComponents.js +2 -1
  48. package/components/container/wizard/components/WizardStep.js +2 -1
  49. package/components/container/wizard/index.js +64 -35
  50. package/components/container/wizard/utils.js +46 -1
  51. package/components/container/wizard/wizard-step/index.js +11 -1
  52. package/components/data/card/card-content/index.js +1 -1
  53. package/components/data/form/base-form/index.js +985 -183
  54. package/components/data/form/base-form/props.js +3 -1
  55. package/components/data/form/base-form/utils.js +159 -1
  56. package/components/data/form/dynamic-fields/constant.js +53 -0
  57. package/components/data/form/dynamic-fields/index.js +10 -45
  58. package/components/data/form/dynamic-fields/utils.js +37 -2
  59. package/components/data/form/form-action/index.js +5 -4
  60. package/components/data/form/form-context.js +5 -1
  61. package/components/data/form/form-controller/utils.js +84 -0
  62. package/components/data/form/form-controller/validation-contrustor.js +402 -189
  63. package/components/data/form/form-controller/withFormController.js +191 -52
  64. package/components/data/form/form-field/base-field.js +67 -45
  65. package/components/data/form/form-field/index.js +28 -5
  66. package/components/data/form/form-header/index.js +3 -4
  67. package/components/data/form/index.js +20 -1
  68. package/components/data/list/components/ListDND.js +2 -1
  69. package/components/data/list/components/ListItem.js +6 -2
  70. package/components/data/list/components/ListItemWithTemplate.js +46 -2
  71. package/components/data/list/components/ListItems.js +17 -26
  72. package/components/data/list/components/ListPagination.js +3 -3
  73. package/components/data/list/components/StandardListItems.js +3 -4
  74. package/components/data/list/hooks/useListEffects.js +55 -14
  75. package/components/data/list/hooks/useListEventHandlers.js +3 -1
  76. package/components/data/list/hooks/useListState.js +3 -1
  77. package/components/data/list/hooks/usePaginatedGroupedData.js +18 -5
  78. package/components/data/list/index.js +74 -55
  79. package/components/data/list/utils/list-helpers.js +73 -35
  80. package/components/data/list/utils/list-widget-methods.js +138 -95
  81. package/components/data/live-filter/index.js +26 -15
  82. package/components/data/live-form/index.js +51 -18
  83. package/components/data/live-form/props.js +1 -1
  84. package/components/data/pagination/components/BasicPagination.js +71 -16
  85. package/components/data/pagination/components/PageSizeSelector.js +8 -3
  86. package/components/data/pagination/components/TotalRecords.js +1 -5
  87. package/components/data/pagination/hooks/usePagination.js +349 -66
  88. package/components/data/pagination/index.js +137 -19
  89. package/components/data/table/components/AddNewRow.js +5 -1
  90. package/components/data/table/components/EditableCell.js +2 -2
  91. package/components/data/table/components/RowCells.js +64 -0
  92. package/components/data/table/components/RowExpansionButton.js +2 -2
  93. package/components/data/table/components/SummaryCell.js +111 -0
  94. package/components/data/table/components/SummaryRow.js +54 -0
  95. package/components/data/table/components/SummaryRowFooter.js +46 -0
  96. package/components/data/table/components/TableBody.js +61 -59
  97. package/components/data/table/components/TableDataRow.js +109 -0
  98. package/components/data/table/components/TableFilters.js +225 -121
  99. package/components/data/table/components/TableHeader.js +291 -23
  100. package/components/data/table/components/TablePanelHeading.js +139 -8
  101. package/components/data/table/components/index.js +22 -1
  102. package/components/data/table/hooks/use-edited-rows.js +141 -0
  103. package/components/data/table/hooks/useCellState.js +5 -12
  104. package/components/data/table/hooks/useFormWidget.js +58 -52
  105. package/components/data/table/hooks/usePaginationState.js +45 -24
  106. package/components/data/table/hooks/usePanelStructure.js +4 -4
  107. package/components/data/table/hooks/useRowHandlers.js +39 -5
  108. package/components/data/table/hooks/useRowSelection.js +244 -50
  109. package/components/data/table/hooks/useServerSideSorting.js +81 -37
  110. package/components/data/table/hooks/useTableColumns.js +211 -118
  111. package/components/data/table/hooks/useTableData.js +54 -9
  112. package/components/data/table/hooks/useTableEdit.js +272 -97
  113. package/components/data/table/hooks/useTableEffects.js +31 -13
  114. package/components/data/table/hooks/useTableFilter.js +1 -1
  115. package/components/data/table/hooks/useTableInitialization.js +23 -22
  116. package/components/data/table/hooks/useTableState.js +11 -5
  117. package/components/data/table/hooks/useTableStateManager.js +140 -65
  118. package/components/data/table/index.js +637 -274
  119. package/components/data/table/live-table/index.js +54 -22
  120. package/components/data/table/table-action/index.js +1 -1
  121. package/components/data/table/table-group/index.js +26 -0
  122. package/components/data/table/table-row-action/index.js +32 -18
  123. package/components/data/table/utils/buildSelectionColumns.js +12 -21
  124. package/components/data/table/utils/columnBuilder.js +29 -14
  125. package/components/data/table/utils/columnProxy.js +68 -1
  126. package/components/data/table/utils/constants.js +6 -2
  127. package/components/data/table/utils/crud-handlers.js +68 -63
  128. package/components/data/table/utils/groupHeaderUtils.js +102 -0
  129. package/components/data/table/utils/index.js +210 -21
  130. package/components/data/table/utils/renderDisplayCell.js +6 -6
  131. package/components/data/table/utils/selectionUtils.js +25 -26
  132. package/components/data/table/utils/validation.js +1 -0
  133. package/components/data/utils/filter-field-util.js +3 -3
  134. package/components/dialogs/alert-dialog/index.js +1 -1
  135. package/components/dialogs/confirm-dialog/index.js +1 -1
  136. package/components/dialogs/dialog/index.js +4 -1
  137. package/components/dialogs/dialog-content/index.js +3 -1
  138. package/components/dialogs/dialog-header/index.js +2 -2
  139. package/components/dialogs/iframe-dialog/index.js +11 -5
  140. package/components/dialogs/index.js +1 -1
  141. package/components/dialogs/login-dialog/index.js +1 -1
  142. package/components/dialogs/page-dialog/index.js +1 -1
  143. package/components/form/button/index.js +33 -7
  144. package/components/input/calendar/index.js +18 -6
  145. package/components/input/chips/index.js +99 -28
  146. package/components/input/chips/utils.js +34 -4
  147. package/components/input/color-picker/index.js +74 -25
  148. package/components/input/composite/index.js +3 -3
  149. package/components/input/currency/index.js +35 -49
  150. package/components/input/default/checkbox/index.js +23 -28
  151. package/components/input/default/checkboxset/index.js +38 -18
  152. package/components/input/default/checkboxset/utils.js +30 -0
  153. package/components/input/default/radioset/index.js +36 -39
  154. package/components/input/default/switch/index.js +30 -13
  155. package/components/input/epoch/date/index.js +130 -69
  156. package/components/input/epoch/date/utils.js +94 -1
  157. package/components/input/epoch/datetime/index.js +72 -22
  158. package/components/input/epoch/datetime/utils.js +49 -10
  159. package/components/input/epoch/time/index.js +68 -19
  160. package/components/input/epoch/time/utils.js +62 -14
  161. package/components/input/fileupload/Utils.js +12 -7
  162. package/components/input/fileupload/components/MultiUpload.js +2 -6
  163. package/components/input/fileupload/components/SingleUpload.js +3 -7
  164. package/components/input/fileupload/index.js +6 -10
  165. package/components/input/fileupload/useFileUpload.js +16 -5
  166. package/components/input/number/index.js +158 -43
  167. package/components/input/rating/index.js +90 -7
  168. package/components/input/select/index.js +209 -72
  169. package/components/input/slider/index.js +84 -26
  170. package/components/input/text/index.js +38 -18
  171. package/components/input/text/util.js +283 -130
  172. package/components/input/textarea/index.js +13 -10
  173. package/components/input/upload/index.js +124 -0
  174. package/components/input/upload/props.js +5 -0
  175. package/components/input/util/index.js +11 -0
  176. package/components/navbar/index.js +51 -3
  177. package/components/navbar/nav/index.js +46 -16
  178. package/components/navbar/nav-item/index.js +11 -5
  179. package/components/navigation/menu/components/ListItems.js +3 -0
  180. package/components/navigation/menu/constants.js +2 -1
  181. package/components/navigation/menu/hooks/useHoverState.hook.js +48 -0
  182. package/components/navigation/menu/hooks/useKeyboardMovements.hook.js +37 -0
  183. package/components/navigation/menu/hooks/useTransformedDataset.hook.js +15 -0
  184. package/components/navigation/menu/index.js +326 -188
  185. package/components/navigation/menu/utils/action-task.js +14 -0
  186. package/components/navigation/menu/utils/role-filter.js +76 -0
  187. package/components/navigation/popover/index.js +105 -32
  188. package/components/page/partial-container/index.js +34 -5
  189. package/components/prefab/index.js +2 -4
  190. package/context/PrefabContext.js +10 -6
  191. package/context/WidgetProvider.js +30 -31
  192. package/core/app.service.js +1 -1
  193. package/core/constants/events.js +57 -1
  194. package/core/dialog.service.js +1 -2
  195. package/core/event-notifier.js +1 -2
  196. package/core/formatter/array-formatters.js +33 -0
  197. package/core/formatter/date-formatters.js +2 -4
  198. package/core/formatter/index.js +2 -1
  199. package/core/formatter/number-formatters.js +5 -10
  200. package/core/formatter/security-formatters.js +2 -4
  201. package/core/formatter/string-formatters.js +3 -6
  202. package/core/proxy-service.js +85 -13
  203. package/core/script-registry.js +108 -48
  204. package/core/util/common.js +4 -4
  205. package/core/util/compare.js +30 -0
  206. package/core/util/dom.js +8 -8
  207. package/core/util/index.js +16 -6
  208. package/core/util/safe-is-equal.js +156 -0
  209. package/core/util/security.js +1 -2
  210. package/core/util/utils.js +16 -7
  211. package/higherOrder/BaseApp.js +108 -65
  212. package/higherOrder/BaseDateTime.js +31 -13
  213. package/higherOrder/BasePage.js +268 -144
  214. package/higherOrder/BasePartial.js +1 -1
  215. package/higherOrder/BasePrefab.js +33 -15
  216. package/higherOrder/DataNav.js +99 -16
  217. package/higherOrder/helper.js +41 -3
  218. package/higherOrder/withBaseWrapper.js +41 -28
  219. package/hooks/useAuth.js +11 -5
  220. package/hooks/useHttp.js +280 -94
  221. package/mui-config/theme-provider.js +1 -1
  222. package/mui-config/theme.js +1 -1
  223. package/package-lock.json +840 -740
  224. package/package.json +8 -8
  225. package/store/bindActions/i18nActions.js +18 -0
  226. package/store/index.js +3 -1
  227. package/store/slices/appConfigSlice.js +2 -2
  228. package/store/slices/authSlice.js +31 -28
  229. package/store/slices/i18nSlice.js +2 -2
  230. package/store/slices/navigationSlice.js +35 -0
  231. package/store/viewport.service.js +255 -0
  232. package/utils/attr.js +35 -0
  233. package/utils/dataset-util.js +1 -2
  234. package/utils/form-state.util.js +43 -12
  235. package/utils/form-utils.js +47 -2
  236. package/utils/format-util.js +28 -13
  237. package/utils/page-params-util.js +33 -1
  238. package/utils/state-persistance.js +72 -13
  239. package/utils/transformedDataset-utils.js +35 -24
  240. package/variables/base-variable.js +12 -14
  241. package/variables/crud-variable.js +225 -0
  242. package/variables/live-variable.js +56 -20
  243. package/variables/metadata.service.js +123 -0
  244. package/variables/model-variable.js +21 -15
  245. package/variables/service-variable.js +88 -83
@@ -9,6 +9,7 @@ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers
9
9
  var _react = require("react");
10
10
  var _selectionUtils = require("../utils/selectionUtils");
11
11
  var _tableHelpers = require("../utils/table-helpers");
12
+ var _utils = require("../utils");
12
13
  var useRowSelection = exports.useRowSelection = function useRowSelection(_ref) {
13
14
  var _ref$radioselect = _ref.radioselect,
14
15
  radioselect = _ref$radioselect === void 0 ? false : _ref$radioselect,
@@ -21,21 +22,33 @@ var useRowSelection = exports.useRowSelection = function useRowSelection(_ref) {
21
22
  name = _ref.name,
22
23
  statehandler = _ref.statehandler,
23
24
  initialActualPageSize = _ref.initialActualPageSize,
24
- getTableCurrentState = _ref.getTableState;
25
+ getTableCurrentState = _ref.getTableState,
26
+ onRowselect = _ref.onRowselect,
27
+ onRowdeselect = _ref.onRowdeselect,
28
+ listener = _ref.listener,
29
+ _ref$navigation = _ref.navigation,
30
+ navigation = _ref$navigation === void 0 ? "Basic" : _ref$navigation;
25
31
  // Keep a ref to always have the latest dataset
26
32
  var datasetRef = (0, _react.useRef)(internalDataset);
27
33
  (0, _react.useEffect)(function () {
28
34
  datasetRef.current = internalDataset;
29
35
  }, [internalDataset]);
30
36
 
37
+ // Track if initial first row selection has been done (for gridfirstrowselect)
38
+ var initialSelectionDoneRef = (0, _react.useRef)(false);
39
+
31
40
  // State only for forcing updates when needed
32
41
  var _useState = (0, _react.useState)({}),
42
+ updateTrigger = _useState[0],
33
43
  forceUpdate = _useState[1];
34
44
 
35
45
  // Priority rule: If both radioselect and multiselect are true, multiselect takes precedence
36
46
  var useMultiSelect = multiselect;
37
47
  var useRadioSelect = radioselect && !multiselect;
38
48
 
49
+ // Determine if any selection mode is active
50
+ var hasSelectionMode = useRadioSelect || useMultiSelect;
51
+
39
52
  // Helper function to save state immediately
40
53
  var saveStateImmediate = (0, _react.useCallback)(function () {
41
54
  if (!statehandler || !getTableCurrentState) {
@@ -45,9 +58,8 @@ var useRowSelection = exports.useRowSelection = function useRowSelection(_ref) {
45
58
  currentPage = _getTableCurrentState.currentPage,
46
59
  currentPageSize = _getTableCurrentState.currentPageSize;
47
60
 
48
- // Get current selections
49
- // If not multiselect, treat as radio select (single selection)
50
- var selectedIds = useMultiSelect ? _selectionUtils.selectionStateHelpers.getMultiSelection(cellState) : _selectionUtils.selectionStateHelpers.getRadioSelection(cellState) ? [_selectionUtils.selectionStateHelpers.getRadioSelection(cellState)] : [];
61
+ // Get current selections from the unified array
62
+ var selectedIds = _selectionUtils.selectionStateHelpers.getSelection(cellState);
51
63
 
52
64
  // Find selected indices in current dataset
53
65
  var selectedIndices = [];
@@ -86,12 +98,10 @@ var useRowSelection = exports.useRowSelection = function useRowSelection(_ref) {
86
98
  // Get existing state
87
99
  var existingState = (0, _tableHelpers.getTableState)(name, statehandler);
88
100
 
89
- // For radio select or default mode (when neither multi nor radio is explicitly enabled),
90
- // don't merge - just replace with current selection
91
- if (useRadioSelect || !useMultiSelect) {
92
- // Radio select or default mode should only have one item selected at a time
101
+ // For radio select, don't merge - just replace with current selection
102
+ if (useRadioSelect) {
93
103
  stateToSave.selectedItem = selectedItemsWithPage;
94
- } else {
104
+ } else if (useMultiSelect) {
95
105
  // For multi-select, merge selected items from different pages
96
106
  if (existingState && existingState.selectedItem) {
97
107
  var otherPageSelections = existingState.selectedItem.filter(function (item) {
@@ -114,92 +124,276 @@ var useRowSelection = exports.useRowSelection = function useRowSelection(_ref) {
114
124
  }
115
125
  }, [statehandler, getTableCurrentState, name, useMultiSelect, useRadioSelect, cellState, internalDataset, initialActualPageSize]);
116
126
 
117
- // Handle radio selection changes
127
+ // Helper to get widget reference
128
+ var getWidgetRef = (0, _react.useCallback)(function () {
129
+ var _listener$Widgets;
130
+ return listener === null || listener === void 0 || (_listener$Widgets = listener.Widgets) === null || _listener$Widgets === void 0 ? void 0 : _listener$Widgets[name];
131
+ }, [name]);
132
+
133
+ // Helper to trigger selection callbacks
134
+ var triggerSelectionCallback = (0, _react.useCallback)(function (event, rowData, callback) {
135
+ if (callback && rowData) {
136
+ var cleanedRow = (0, _utils.cleanRowData)([rowData])[0];
137
+ callback(event, getWidgetRef(), cleanedRow);
138
+ }
139
+ }, [getWidgetRef]);
140
+
141
+ // Handle selection for radio mode (replaces previous selection)
118
142
  var handleRadioSelection = (0, _react.useCallback)(function (rowId, rowData) {
119
- _selectionUtils.selectionStateHelpers.setRadioSelection(cellState, rowId);
143
+ // Get the currently selected row (if any) before changing selection
144
+ var previousSelection = _selectionUtils.selectionStateHelpers.getSelection(cellState);
145
+ var previousRowId = previousSelection.length > 0 ? previousSelection[0] : null;
146
+
147
+ // Find the previously selected row data if it exists and is different
148
+ var previousRowData = null;
149
+ if (previousRowId && previousRowId !== rowId && onRowdeselect) {
150
+ previousRowData = internalDataset.find(function (row) {
151
+ return row._wmTableRowId === previousRowId || row.id === previousRowId;
152
+ });
153
+ }
154
+
155
+ // Set the new selection
156
+ _selectionUtils.selectionStateHelpers.setSelection(cellState, rowId);
120
157
  forceUpdate({});
121
- saveStateImmediate(); // Save state immediately
122
- }, [cellState, saveStateImmediate]);
158
+ saveStateImmediate();
123
159
 
124
- // Handle multiselect checkbox changes
160
+ // Trigger callbacks in order: deselect previous, then select new
161
+ if (previousRowData) {
162
+ triggerSelectionCallback(null, previousRowData, onRowdeselect);
163
+ }
164
+ triggerSelectionCallback(null, rowData, onRowselect);
165
+ }, [cellState, saveStateImmediate, onRowselect, onRowdeselect, internalDataset, triggerSelectionCallback]);
166
+
167
+ // Handle selection for multiselect mode (add/remove from selection)
125
168
  var handleMultiSelection = (0, _react.useCallback)(function (rowId, rowData, isSelected) {
126
169
  if (isSelected) {
127
- _selectionUtils.selectionStateHelpers.addToMultiSelection(cellState, rowId);
170
+ _selectionUtils.selectionStateHelpers.addToSelection(cellState, rowId);
128
171
  } else {
129
- _selectionUtils.selectionStateHelpers.removeFromMultiSelection(cellState, rowId);
172
+ _selectionUtils.selectionStateHelpers.removeFromSelection(cellState, rowId);
130
173
  }
131
174
  forceUpdate({});
132
- saveStateImmediate(); // Save state immediately
133
- }, [cellState, saveStateImmediate]);
175
+ saveStateImmediate();
176
+
177
+ // Trigger appropriate callback
178
+ triggerSelectionCallback(null, rowData, isSelected ? onRowselect : onRowdeselect);
179
+ }, [cellState, saveStateImmediate, onRowselect, onRowdeselect, triggerSelectionCallback]);
134
180
 
135
181
  // Toggle all rows selection for multiselect
136
182
  var handleSelectAll = (0, _react.useCallback)(function (isSelected) {
137
183
  if (isSelected) {
138
184
  // Use ref to ensure we always have the latest dataset
139
185
  var allRowIds = (0, _selectionUtils.getRowIdsFromDataset)(datasetRef.current);
140
- _selectionUtils.selectionStateHelpers.setAllMultiSelection(cellState, allRowIds);
186
+ _selectionUtils.selectionStateHelpers.setAllSelection(cellState, allRowIds);
141
187
  } else {
142
- _selectionUtils.selectionStateHelpers.clearMultiSelection(cellState);
188
+ _selectionUtils.selectionStateHelpers.clearSelection(cellState);
143
189
  }
144
190
  forceUpdate({});
145
- saveStateImmediate(); // Save state immediately
191
+ saveStateImmediate();
146
192
  }, [cellState, saveStateImmediate]);
147
193
 
148
- // Handle row selection on click
194
+ // Handle row selection on click - unified handler
149
195
  var handleRowSelectionClick = (0, _react.useCallback)(function (event, rowId, rowData) {
150
196
  // If clicking on an interactive element, don't handle row selection
151
197
  if ((0, _selectionUtils.isInteractiveElement)(event)) {
152
198
  return false;
153
199
  }
154
200
 
155
- // Handle multiselect if enabled
201
+ // Handle based on selection mode
156
202
  if (useMultiSelect) {
157
- _selectionUtils.selectionStateHelpers.toggleMultiSelection(cellState, rowId);
158
- saveStateImmediate(); // Save state immediately
203
+ // Check if row is currently selected and toggle
204
+ var isCurrentlySelected = _selectionUtils.selectionStateHelpers.isRowSelected(cellState, rowId);
205
+ var willBeSelected = !isCurrentlySelected;
206
+ _selectionUtils.selectionStateHelpers.toggleSelection(cellState, rowId);
207
+ forceUpdate({});
208
+ saveStateImmediate();
209
+
210
+ // Trigger appropriate callback based on new selection state
211
+ triggerSelectionCallback(event, rowData, willBeSelected ? onRowselect : onRowdeselect);
159
212
  return true;
160
- }
161
- // Handle radio selection if enabled (and multiselect is not)
162
- else {
213
+ } else {
214
+ // Replace selection for radio select (or default mode)
163
215
  handleRadioSelection(rowId, rowData);
164
- // No need to call saveStateImmediate here as handleRadioSelection already does it
165
216
  return true;
166
217
  }
167
- }, [useMultiSelect, useRadioSelect, handleRadioSelection, cellState, saveStateImmediate]);
218
+ }, [useMultiSelect, handleRadioSelection, cellState, saveStateImmediate, triggerSelectionCallback, onRowselect, onRowdeselect]);
168
219
 
169
- // First row selection logic
220
+ // First row selection logic - only runs once on initial render
170
221
  (0, _react.useEffect)(function () {
222
+ // Skip if initial selection has already been done
223
+ if (initialSelectionDoneRef.current) {
224
+ return;
225
+ }
226
+
171
227
  // Only proceed if gridfirstrowselect is true and we have data
172
228
  if (gridfirstrowselect && internalDataset.length > 0) {
173
229
  var firstRowData = internalDataset[0];
174
230
  var firstRowId = firstRowData._wmTableRowId || String(firstRowData.id) || String(0);
175
- if (useMultiSelect) {
176
- // For multiselect, only add to selection if no rows are currently selected
177
- var selectedIds = _selectionUtils.selectionStateHelpers.getMultiSelection(cellState);
178
- if (selectedIds.length === 0) {
179
- _selectionUtils.selectionStateHelpers.addToMultiSelection(cellState, firstRowId);
231
+
232
+ // Check if any row is currently selected
233
+ var currentSelection = _selectionUtils.selectionStateHelpers.getSelection(cellState);
234
+ if (currentSelection.length === 0) {
235
+ // No selection - select the first row
236
+ if (useMultiSelect) {
237
+ _selectionUtils.selectionStateHelpers.addToSelection(cellState, firstRowId);
238
+ } else {
239
+ _selectionUtils.selectionStateHelpers.setSelection(cellState, firstRowId);
180
240
  }
181
- } else {
182
- // For radio select or default mode (when neither is explicitly enabled),
183
- // only select the first row if no row is currently selected
184
- // or if the currently selected row no longer exists in the dataset
185
- var currentSelectedId = _selectionUtils.selectionStateHelpers.getRadioSelection(cellState);
186
- if (!currentSelectedId || !(0, _selectionUtils.rowExistsInDataset)(currentSelectedId, internalDataset)) {
187
- handleRadioSelection(firstRowId, firstRowData);
241
+ forceUpdate({});
242
+ initialSelectionDoneRef.current = true;
243
+ } else if (!useMultiSelect) {
244
+ // For radio select, check if the selected row still exists
245
+ var selectedId = currentSelection[0];
246
+ if (!(0, _selectionUtils.rowExistsInDataset)(selectedId, internalDataset)) {
247
+ _selectionUtils.selectionStateHelpers.setSelection(cellState, firstRowId);
248
+ forceUpdate({});
249
+ initialSelectionDoneRef.current = true;
188
250
  }
189
251
  }
190
252
  }
191
- }, [gridfirstrowselect, internalDataset, useMultiSelect, useRadioSelect, handleRadioSelection, cellState]);
253
+ }, [gridfirstrowselect, internalDataset, useMultiSelect, cellState]);
254
+
255
+ // Page change selection logic - runs when page changes
256
+ (0, _react.useEffect)(function () {
257
+ var _savedState$selectedI;
258
+ // Only proceed if gridfirstrowselect is true and we have data
259
+ if (!gridfirstrowselect || internalDataset.length === 0 || !initialSelectionDoneRef.current) {
260
+ return;
261
+ }
262
+
263
+ // Get current page number
264
+ var currentPage = (getTableCurrentState === null || getTableCurrentState === void 0 ? void 0 : getTableCurrentState().currentPage) || 1;
265
+
266
+ // Check if there are already selected items on the current page
267
+ var savedState = (0, _tableHelpers.getTableState)(name, statehandler);
268
+ var selectedIdsInCurrentPage = (savedState === null || savedState === void 0 || (_savedState$selectedI = savedState.selectedItem) === null || _savedState$selectedI === void 0 ? void 0 : _savedState$selectedI.filter(function (item) {
269
+ return item.page === currentPage;
270
+ }).map(function (item) {
271
+ return item.index;
272
+ })) || [];
273
+ if (selectedIdsInCurrentPage.length > 0) {
274
+ return;
275
+ }
276
+
277
+ // Check if there's a selection for this page in current dataset
278
+ var currentSelection = _selectionUtils.selectionStateHelpers.getSelection(cellState);
279
+ var hasSelectionInCurrentPage = currentSelection.some(function (selectedId) {
280
+ return (0, _selectionUtils.rowExistsInDataset)(selectedId, internalDataset);
281
+ });
282
+
283
+ // Select first row if no selection exists on this page
284
+ if (!hasSelectionInCurrentPage) {
285
+ var firstRowData = internalDataset[0];
286
+ var firstRowId = firstRowData._wmTableRowId || String(firstRowData.id) || String(0);
287
+ if (useMultiSelect) {
288
+ _selectionUtils.selectionStateHelpers.addToSelection(cellState, firstRowId);
289
+ } else {
290
+ _selectionUtils.selectionStateHelpers.setSelection(cellState, firstRowId);
291
+ }
292
+ forceUpdate({});
293
+
294
+ // Trigger onRowselect callback for the first row
295
+ if (onRowselect) {
296
+ triggerSelectionCallback(null, firstRowData, onRowselect);
297
+ }
298
+ }
299
+ }, [gridfirstrowselect, internalDataset, useMultiSelect, cellState, getTableCurrentState, name, statehandler, onRowselect, triggerSelectionCallback]);
192
300
 
193
301
  // Check if a row is selected - memoized
194
302
  var isRowSelected = (0, _react.useCallback)(function (rowId) {
195
- return _selectionUtils.selectionStateHelpers.isRowSelected(cellState, rowId, useMultiSelect, useRadioSelect);
196
- }, [useMultiSelect, useRadioSelect, cellState]);
303
+ return _selectionUtils.selectionStateHelpers.isRowSelected(cellState, rowId);
304
+ }, [cellState]);
305
+
306
+ // Get selected row IDs - unified array that works for both modes
307
+ // For radio select: contains at most 1 item
308
+ // For multiselect: can contain multiple items
309
+ // Always track selections regardless of selection mode for state persistence purposes
310
+ // (internally treat as radioselect if no mode is specified)
311
+ var selectedRowIds = (0, _react.useMemo)(function () {
312
+ return _selectionUtils.selectionStateHelpers.getSelection(cellState);
313
+ }, [cellState, updateTrigger]);
314
+
315
+ // Restore selections when page changes (after initial restoration)
316
+ (0, _react.useEffect)(function () {
317
+ // Skip if no state handler or unsupported navigation
318
+ if (!statehandler || _utils.UNSUPPORTED_STATE_PERSISTENCE_TYPES.includes(navigation)) {
319
+ return;
320
+ }
321
+
322
+ // Skip if not yet initialized (wait for initial selection logic to complete)
323
+ if (!initialSelectionDoneRef.current) {
324
+ return;
325
+ }
326
+
327
+ // Get current page
328
+ var currentPage = (getTableCurrentState === null || getTableCurrentState === void 0 ? void 0 : getTableCurrentState().currentPage) || 1;
197
329
 
198
- // Get selected values without forcing re-renders
199
- var selectedRowId = useRadioSelect ? _selectionUtils.selectionStateHelpers.getRadioSelection(cellState) : null;
200
- var selectedRowIds = useMultiSelect ? _selectionUtils.selectionStateHelpers.getMultiSelection(cellState) : [];
330
+ // Get saved state
331
+ var savedState = (0, _tableHelpers.getTableState)(name, statehandler);
332
+ if (!savedState || !savedState.selectedItem || savedState.selectedItem.length === 0) {
333
+ return;
334
+ }
335
+
336
+ // Check if there's an active filter - don't restore if filtering
337
+ var hasActiveFilter = savedState.search && savedState.search.length > 0;
338
+ if (hasActiveFilter) {
339
+ return;
340
+ }
341
+
342
+ // Get selections for current page from saved state
343
+ var currentPageSelections = savedState.selectedItem.filter(function (item) {
344
+ return item.page === currentPage;
345
+ }).map(function (item) {
346
+ return item.index;
347
+ });
348
+
349
+ // If there are selections for this page, restore them
350
+ if (currentPageSelections.length > 0 && internalDataset.length > 0) {
351
+ // Check if these selections are already applied
352
+ var currentSelection = _selectionUtils.selectionStateHelpers.getSelection(cellState);
353
+
354
+ // Build expected row IDs from indices
355
+ var expectedRowIds = [];
356
+ currentPageSelections.forEach(function (index) {
357
+ if (index >= 0 && index < internalDataset.length) {
358
+ var row = internalDataset[index];
359
+ if (row && row._wmTableRowId) {
360
+ expectedRowIds.push(row._wmTableRowId);
361
+ }
362
+ }
363
+ });
364
+
365
+ // Check if current selection matches expected
366
+ var isAlreadyRestored = expectedRowIds.length === currentSelection.length && expectedRowIds.every(function (id) {
367
+ return currentSelection.includes(id);
368
+ });
369
+ if (!isAlreadyRestored && expectedRowIds.length > 0) {
370
+ // Apply restored selections
371
+ if (useMultiSelect) {
372
+ // For multiselect, clear and add all restored items
373
+ _selectionUtils.selectionStateHelpers.clearSelection(cellState);
374
+ currentPageSelections.forEach(function (index) {
375
+ if (index >= 0 && index < internalDataset.length) {
376
+ var row = internalDataset[index];
377
+ if (row && row._wmTableRowId) {
378
+ _selectionUtils.selectionStateHelpers.addToSelection(cellState, row._wmTableRowId);
379
+ }
380
+ }
381
+ });
382
+ } else {
383
+ // For radio select, only restore the first selection
384
+ var firstIndex = currentPageSelections[0];
385
+ if (firstIndex >= 0 && firstIndex < internalDataset.length) {
386
+ var row = internalDataset[firstIndex];
387
+ if (row && row._wmTableRowId) {
388
+ _selectionUtils.selectionStateHelpers.setSelection(cellState, row._wmTableRowId);
389
+ }
390
+ }
391
+ }
392
+ forceUpdate({});
393
+ }
394
+ }
395
+ }, [getTableCurrentState, name, statehandler, navigation, internalDataset, cellState, useMultiSelect]);
201
396
  return {
202
- selectedRowId: selectedRowId,
203
397
  selectedRowIds: selectedRowIds,
204
398
  useMultiSelect: useMultiSelect,
205
399
  useRadioSelect: useRadioSelect,
@@ -10,6 +10,7 @@ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/
10
10
  var _react = require("react");
11
11
  var _crudHandlers = require("../utils/crud-handlers");
12
12
  var _utils = require("../utils");
13
+ var _useDebounce = require("@wavemaker/react-runtime/hooks/useDebounce");
13
14
  /**
14
15
  * Hook to handle server-side sorting for table data
15
16
  */
@@ -21,14 +22,16 @@ var useServerSideSorting = exports.useServerSideSorting = function useServerSide
21
22
  isServerSidePagination = _ref.isServerSidePagination,
22
23
  pageIndex = _ref.pageIndex,
23
24
  onError = _ref.onError,
25
+ onBeforefilter = _ref.onBeforefilter,
24
26
  filterFields = _ref.filterFields,
25
27
  logicalOp = _ref.logicalOp,
26
- setLoading = _ref.setLoading;
28
+ setLoading = _ref.setLoading,
29
+ listener = _ref.listener,
30
+ name = _ref.name;
27
31
  var prevSortingRef = (0, _react.useRef)(sorting);
28
32
  var prevPageRef = (0, _react.useRef)(pageIndex);
29
33
  var prevFilterRef = (0, _react.useRef)("");
30
34
  var isMountedRef = (0, _react.useRef)(false);
31
- var isFetchingRef = (0, _react.useRef)(false);
32
35
 
33
36
  // Determine if we should use server-side sorting
34
37
  var isServerSideSorting = !!(datasource && isServerSidePagination);
@@ -46,69 +49,70 @@ var useServerSideSorting = exports.useServerSideSorting = function useServerSide
46
49
  }, []);
47
50
 
48
51
  // Fetch data with sorting
49
- var fetchSortedData = (0, _react.useCallback)(/*#__PURE__*/function () {
52
+ var fetchSortedDataImpl = (0, _react.useCallback)(/*#__PURE__*/function () {
50
53
  var _ref2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee(forcePage) {
51
- var orderBy, currentPage, response, responseData, dataWithIds;
54
+ var orderBy, currentPage, response, responseData, dataWithIds, _listener$Widgets, widget;
52
55
  return _regenerator["default"].wrap(function _callee$(_context) {
53
56
  while (1) switch (_context.prev = _context.next) {
54
57
  case 0:
55
- if (!(!datasource || !isServerSideSorting || isFetchingRef.current)) {
58
+ if (!(!datasource || !isServerSideSorting)) {
56
59
  _context.next = 2;
57
60
  break;
58
61
  }
59
62
  return _context.abrupt("return");
60
63
  case 2:
61
- // Prevent duplicate fetches
62
- isFetchingRef.current = true;
63
64
  setLoading(true);
64
- _context.prev = 4;
65
+ _context.prev = 3;
65
66
  orderBy = convertSortingToOrderBy(sorting); // Use forcePage if provided (for sorting changes), otherwise use current page
66
67
  currentPage = forcePage !== undefined ? forcePage : pageIndex + 1; // Convert 0-based to 1-based
67
- _context.next = 9;
68
+ _context.next = 8;
68
69
  return (0, _crudHandlers.refreshDataSource)(datasource, {
69
70
  orderBy: orderBy,
70
71
  page: currentPage || 1,
71
72
  filterFields: filterFields || {},
72
73
  condition: logicalOp || ""
73
74
  });
74
- case 9:
75
+ case 8:
75
76
  response = _context.sent;
76
- if (response) {
77
- responseData = []; // Handle different response formats
78
- if (response.data) {
79
- responseData = response.data;
80
- }
81
- // Add unique row IDs to the server response data
82
- dataWithIds = (0, _utils.addUniqueRowIds)(responseData);
83
- setInternalDataset(dataWithIds);
77
+ // Handle response data - always update dataset even if empty
78
+ responseData = []; // Handle different response formats
79
+ if (response && response.data) {
80
+ responseData = Array.isArray(response.data) ? response.data : [];
84
81
  }
85
- _context.next = 18;
82
+
83
+ // Add unique row IDs to the server response data
84
+ dataWithIds = (0, _utils.addUniqueRowIds)(responseData);
85
+ setInternalDataset(dataWithIds);
86
+ _context.next = 20;
86
87
  break;
87
- case 13:
88
- _context.prev = 13;
89
- _context.t0 = _context["catch"](4);
88
+ case 15:
89
+ _context.prev = 15;
90
+ _context.t0 = _context["catch"](3);
90
91
  console.error("Error fetching sorted data:", _context.t0);
91
92
  if (showToast) {
92
93
  showToast("Failed to sort data", "Error");
93
94
  }
94
95
  if (onError) {
95
- onError("sort", _context.t0);
96
+ widget = name ? listener === null || listener === void 0 || (_listener$Widgets = listener.Widgets) === null || _listener$Widgets === void 0 ? void 0 : _listener$Widgets[name] : undefined;
97
+ onError(null, widget, _context.t0, "sort");
96
98
  }
97
- case 18:
98
- _context.prev = 18;
99
- isFetchingRef.current = false;
99
+ case 20:
100
+ _context.prev = 20;
100
101
  setLoading(false);
101
- return _context.finish(18);
102
- case 22:
102
+ return _context.finish(20);
103
+ case 23:
103
104
  case "end":
104
105
  return _context.stop();
105
106
  }
106
- }, _callee, null, [[4, 13, 18, 22]]);
107
+ }, _callee, null, [[3, 15, 20, 23]]);
107
108
  }));
108
109
  return function (_x) {
109
110
  return _ref2.apply(this, arguments);
110
111
  };
111
- }(), [datasource, isServerSideSorting, sorting, pageIndex, convertSortingToOrderBy, setInternalDataset, showToast, onError, filterFields, logicalOp]);
112
+ }(), [datasource, isServerSideSorting, sorting, pageIndex, convertSortingToOrderBy, setInternalDataset, showToast, onError, filterFields, logicalOp, setLoading, listener, name]);
113
+
114
+ // Debounced version to handle rapid successive calls
115
+ var fetchSortedData = (0, _useDebounce.useDebounceCallback)(fetchSortedDataImpl, 100);
112
116
 
113
117
  // Combined effect to handle sorting, pagination, and filter changes
114
118
  (0, _react.useEffect)(function () {
@@ -142,15 +146,55 @@ var useServerSideSorting = exports.useServerSideSorting = function useServerSide
142
146
 
143
147
  // Only fetch if something actually changed
144
148
  if (sortingChanged || filterChanged) {
145
- // Update refs before fetching to prevent duplicate calls
146
- prevSortingRef.current = sorting;
147
- prevPageRef.current = pageIndex;
148
- prevFilterRef.current = filterString;
149
+ // If filter changed, call onBeforefilter callback
150
+ if (filterChanged && onBeforefilter) {
151
+ var handleFilterChange = /*#__PURE__*/function () {
152
+ var _ref3 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee2() {
153
+ var _listener$Widgets2;
154
+ var widget, result;
155
+ return _regenerator["default"].wrap(function _callee2$(_context2) {
156
+ while (1) switch (_context2.prev = _context2.next) {
157
+ case 0:
158
+ widget = name ? listener === null || listener === void 0 || (_listener$Widgets2 = listener.Widgets) === null || _listener$Widgets2 === void 0 ? void 0 : _listener$Widgets2[name] : undefined;
159
+ _context2.next = 3;
160
+ return onBeforefilter(widget, filterFields);
161
+ case 3:
162
+ result = _context2.sent;
163
+ if (!(result === false)) {
164
+ _context2.next = 6;
165
+ break;
166
+ }
167
+ return _context2.abrupt("return");
168
+ case 6:
169
+ // Update refs before fetching to prevent duplicate calls
170
+ prevSortingRef.current = sorting;
171
+ prevPageRef.current = pageIndex;
172
+ prevFilterRef.current = filterString;
173
+
174
+ // When sorting or filter changes, fetch from page 1
175
+ fetchSortedData(1);
176
+ case 10:
177
+ case "end":
178
+ return _context2.stop();
179
+ }
180
+ }, _callee2);
181
+ }));
182
+ return function handleFilterChange() {
183
+ return _ref3.apply(this, arguments);
184
+ };
185
+ }();
186
+ handleFilterChange();
187
+ } else {
188
+ // Update refs before fetching to prevent duplicate calls
189
+ prevSortingRef.current = sorting;
190
+ prevPageRef.current = pageIndex;
191
+ prevFilterRef.current = filterString;
149
192
 
150
- // When sorting or filter changes, fetch from page 1
151
- fetchSortedData(1);
193
+ // When sorting or filter changes, fetch from page 1
194
+ fetchSortedData(1);
195
+ }
152
196
  }
153
- }, [sorting, pageIndex, filterFields, logicalOp, isServerSideSorting, fetchSortedData]);
197
+ }, [sorting, pageIndex, filterFields, logicalOp, isServerSideSorting, fetchSortedData, onBeforefilter, listener, name]);
154
198
 
155
199
  // Custom sorting change handler
156
200
  var handleSortingChange = (0, _react.useCallback)(function (updaterOrValue) {