@osdk/react-components 0.2.0-beta.16 → 0.2.0-beta.18

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 (206) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +91 -3
  3. package/build/browser/action-form/ActionForm.js +109 -0
  4. package/build/browser/action-form/ActionForm.js.map +1 -0
  5. package/build/browser/action-form/ActionFormApi.js.map +1 -1
  6. package/build/browser/action-form/BaseForm.js +74 -0
  7. package/build/browser/action-form/BaseForm.js.map +1 -0
  8. package/build/browser/action-form/FormFieldApi.js.map +1 -1
  9. package/build/browser/action-form/fields/FieldBridge.js +45 -0
  10. package/build/browser/action-form/fields/FieldBridge.js.map +1 -0
  11. package/build/browser/action-form/fields/FormFieldRenderer.js +68 -0
  12. package/build/browser/action-form/fields/FormFieldRenderer.js.map +1 -0
  13. package/build/browser/action-form/fields/TextInputField.js +38 -0
  14. package/build/browser/action-form/fields/TextInputField.js.map +1 -0
  15. package/build/browser/action-form/utils/coerceFieldValue.js +93 -0
  16. package/build/browser/action-form/utils/coerceFieldValue.js.map +1 -0
  17. package/build/browser/action-form/utils/getDefaultFieldComponent.js +56 -0
  18. package/build/browser/action-form/utils/getDefaultFieldComponent.js.map +1 -0
  19. package/build/browser/action-form/utils/getDefaultFieldDefinitions.js +33 -0
  20. package/build/browser/action-form/utils/getDefaultFieldDefinitions.js.map +1 -0
  21. package/build/browser/base-components/tooltip/Tooltip.js +91 -0
  22. package/build/browser/base-components/tooltip/Tooltip.js.map +1 -0
  23. package/build/browser/base-components/tooltip/Tooltip.module.css +70 -0
  24. package/build/browser/base-components/tooltip/Tooltip.module.css.js +11 -0
  25. package/build/browser/base-components/tooltip/index.js +18 -0
  26. package/build/browser/base-components/tooltip/index.js.map +1 -0
  27. package/build/browser/filter-list/base/BaseFilterList.js +23 -11
  28. package/build/browser/filter-list/base/BaseFilterList.js.map +1 -1
  29. package/build/browser/filter-list/base/FilterIcons.js +48 -13
  30. package/build/browser/filter-list/base/FilterIcons.js.map +1 -1
  31. package/build/browser/filter-list/base/FilterList.module.css +57 -13
  32. package/build/browser/filter-list/base/FilterList.module.css.js +5 -2
  33. package/build/browser/filter-list/base/FilterListHeader.js +10 -15
  34. package/build/browser/filter-list/base/FilterListHeader.js.map +1 -1
  35. package/build/browser/filter-list/base/FilterListHeader.module.css +13 -41
  36. package/build/browser/filter-list/base/FilterListHeader.module.css.js +1 -4
  37. package/build/browser/filter-list/hooks/useFilterListState.js +25 -7
  38. package/build/browser/filter-list/hooks/useFilterListState.js.map +1 -1
  39. package/build/browser/filter-list/utils/assertUnreachable.js +1 -8
  40. package/build/browser/filter-list/utils/assertUnreachable.js.map +1 -1
  41. package/build/browser/filter-list/utils/filterStateToWhereClause.js +121 -91
  42. package/build/browser/filter-list/utils/filterStateToWhereClause.js.map +1 -1
  43. package/build/browser/object-table/DefaultCellRenderer.js +6 -1
  44. package/build/browser/object-table/DefaultCellRenderer.js.map +1 -1
  45. package/build/browser/object-table/EditableCell.js +76 -9
  46. package/build/browser/object-table/EditableCell.js.map +1 -1
  47. package/build/browser/object-table/EditableCell.module.css +47 -8
  48. package/build/browser/object-table/EditableCell.module.css.js +5 -1
  49. package/build/browser/object-table/MultiColumnSortDialog.js +4 -1
  50. package/build/browser/object-table/MultiColumnSortDialog.js.map +1 -1
  51. package/build/browser/object-table/ObjectTable.js +4 -1
  52. package/build/browser/object-table/ObjectTable.js.map +1 -1
  53. package/build/browser/object-table/ObjectTableApi.js.map +1 -1
  54. package/build/browser/object-table/SelectionCells.js +1 -0
  55. package/build/browser/object-table/SelectionCells.js.map +1 -1
  56. package/build/browser/object-table/Table.js +2 -2
  57. package/build/browser/object-table/Table.js.map +1 -1
  58. package/build/browser/object-table/TableBody.js +1 -1
  59. package/build/browser/object-table/TableBody.js.map +1 -1
  60. package/build/browser/object-table/TableEditContainer.js +27 -16
  61. package/build/browser/object-table/TableEditContainer.js.map +1 -1
  62. package/build/browser/object-table/TableEditContainer.module.css +27 -0
  63. package/build/browser/object-table/TableEditContainer.module.css.js +5 -1
  64. package/build/browser/object-table/TableHeader.js +4 -1
  65. package/build/browser/object-table/TableHeader.js.map +1 -1
  66. package/build/browser/object-table/TableHeader.module.css +2 -1
  67. package/build/browser/object-table/TableHeader.module.css.js +1 -0
  68. package/build/browser/object-table/TableRow.js +2 -2
  69. package/build/browser/object-table/TableRow.js.map +1 -1
  70. package/build/browser/object-table/hooks/useColumnDefs.js +2 -1
  71. package/build/browser/object-table/hooks/useColumnDefs.js.map +1 -1
  72. package/build/browser/object-table/hooks/useEditableTable.js +21 -2
  73. package/build/browser/object-table/hooks/useEditableTable.js.map +1 -1
  74. package/build/browser/object-table/utils/types.js.map +1 -1
  75. package/build/browser/shared/assertUnreachable.js +25 -0
  76. package/build/browser/shared/assertUnreachable.js.map +1 -0
  77. package/build/browser/shared/typedMemo.js +25 -0
  78. package/build/browser/shared/typedMemo.js.map +1 -0
  79. package/build/browser/styles.css +219 -63
  80. package/build/cjs/public/experimental.cjs +1212 -966
  81. package/build/cjs/public/experimental.cjs.map +1 -1
  82. package/build/cjs/public/experimental.css +167 -55
  83. package/build/cjs/public/experimental.css.map +1 -1
  84. package/build/cjs/public/experimental.d.cts +18 -4
  85. package/build/esm/action-form/ActionForm.js +109 -0
  86. package/build/esm/action-form/ActionForm.js.map +1 -0
  87. package/build/esm/action-form/ActionFormApi.js.map +1 -1
  88. package/build/esm/action-form/BaseForm.js +74 -0
  89. package/build/esm/action-form/BaseForm.js.map +1 -0
  90. package/build/esm/action-form/FormFieldApi.js.map +1 -1
  91. package/build/esm/action-form/fields/FieldBridge.js +45 -0
  92. package/build/esm/action-form/fields/FieldBridge.js.map +1 -0
  93. package/build/esm/action-form/fields/FormFieldRenderer.js +68 -0
  94. package/build/esm/action-form/fields/FormFieldRenderer.js.map +1 -0
  95. package/build/esm/action-form/fields/TextInputField.js +38 -0
  96. package/build/esm/action-form/fields/TextInputField.js.map +1 -0
  97. package/build/esm/action-form/utils/coerceFieldValue.js +93 -0
  98. package/build/esm/action-form/utils/coerceFieldValue.js.map +1 -0
  99. package/build/esm/action-form/utils/getDefaultFieldComponent.js +56 -0
  100. package/build/esm/action-form/utils/getDefaultFieldComponent.js.map +1 -0
  101. package/build/esm/action-form/utils/getDefaultFieldDefinitions.js +33 -0
  102. package/build/esm/action-form/utils/getDefaultFieldDefinitions.js.map +1 -0
  103. package/build/esm/base-components/tooltip/Tooltip.js +91 -0
  104. package/build/esm/base-components/tooltip/Tooltip.js.map +1 -0
  105. package/build/esm/base-components/tooltip/Tooltip.module.css +70 -0
  106. package/build/esm/base-components/tooltip/index.js +18 -0
  107. package/build/esm/base-components/tooltip/index.js.map +1 -0
  108. package/build/esm/filter-list/base/BaseFilterList.js +23 -11
  109. package/build/esm/filter-list/base/BaseFilterList.js.map +1 -1
  110. package/build/esm/filter-list/base/FilterIcons.js +48 -13
  111. package/build/esm/filter-list/base/FilterIcons.js.map +1 -1
  112. package/build/esm/filter-list/base/FilterList.module.css +57 -13
  113. package/build/esm/filter-list/base/FilterListHeader.js +10 -15
  114. package/build/esm/filter-list/base/FilterListHeader.js.map +1 -1
  115. package/build/esm/filter-list/base/FilterListHeader.module.css +13 -41
  116. package/build/esm/filter-list/hooks/useFilterListState.js +25 -7
  117. package/build/esm/filter-list/hooks/useFilterListState.js.map +1 -1
  118. package/build/esm/filter-list/utils/assertUnreachable.js +1 -8
  119. package/build/esm/filter-list/utils/assertUnreachable.js.map +1 -1
  120. package/build/esm/filter-list/utils/filterStateToWhereClause.js +121 -91
  121. package/build/esm/filter-list/utils/filterStateToWhereClause.js.map +1 -1
  122. package/build/esm/object-table/DefaultCellRenderer.js +6 -1
  123. package/build/esm/object-table/DefaultCellRenderer.js.map +1 -1
  124. package/build/esm/object-table/EditableCell.js +76 -9
  125. package/build/esm/object-table/EditableCell.js.map +1 -1
  126. package/build/esm/object-table/EditableCell.module.css +47 -8
  127. package/build/esm/object-table/MultiColumnSortDialog.js +4 -1
  128. package/build/esm/object-table/MultiColumnSortDialog.js.map +1 -1
  129. package/build/esm/object-table/ObjectTable.js +4 -1
  130. package/build/esm/object-table/ObjectTable.js.map +1 -1
  131. package/build/esm/object-table/ObjectTableApi.js.map +1 -1
  132. package/build/esm/object-table/SelectionCells.js +1 -0
  133. package/build/esm/object-table/SelectionCells.js.map +1 -1
  134. package/build/esm/object-table/Table.js +2 -2
  135. package/build/esm/object-table/Table.js.map +1 -1
  136. package/build/esm/object-table/TableBody.js +1 -1
  137. package/build/esm/object-table/TableBody.js.map +1 -1
  138. package/build/esm/object-table/TableEditContainer.js +27 -16
  139. package/build/esm/object-table/TableEditContainer.js.map +1 -1
  140. package/build/esm/object-table/TableEditContainer.module.css +27 -0
  141. package/build/esm/object-table/TableHeader.js +4 -1
  142. package/build/esm/object-table/TableHeader.js.map +1 -1
  143. package/build/esm/object-table/TableHeader.module.css +2 -1
  144. package/build/esm/object-table/TableRow.js +2 -2
  145. package/build/esm/object-table/TableRow.js.map +1 -1
  146. package/build/esm/object-table/hooks/useColumnDefs.js +2 -1
  147. package/build/esm/object-table/hooks/useColumnDefs.js.map +1 -1
  148. package/build/esm/object-table/hooks/useEditableTable.js +21 -2
  149. package/build/esm/object-table/hooks/useEditableTable.js.map +1 -1
  150. package/build/esm/object-table/utils/types.js.map +1 -1
  151. package/build/esm/shared/assertUnreachable.js +25 -0
  152. package/build/esm/shared/assertUnreachable.js.map +1 -0
  153. package/build/esm/shared/typedMemo.js +25 -0
  154. package/build/esm/shared/typedMemo.js.map +1 -0
  155. package/build/types/action-form/ActionForm.d.ts +4 -0
  156. package/build/types/action-form/ActionForm.d.ts.map +1 -0
  157. package/build/types/action-form/ActionFormApi.d.ts +48 -32
  158. package/build/types/action-form/ActionFormApi.d.ts.map +1 -1
  159. package/build/types/action-form/BaseForm.d.ts +3 -0
  160. package/build/types/action-form/BaseForm.d.ts.map +1 -0
  161. package/build/types/action-form/FormFieldApi.d.ts +58 -18
  162. package/build/types/action-form/FormFieldApi.d.ts.map +1 -1
  163. package/build/types/action-form/fields/FieldBridge.d.ts +9 -0
  164. package/build/types/action-form/fields/FieldBridge.d.ts.map +1 -0
  165. package/build/types/action-form/fields/FormFieldRenderer.d.ts +8 -0
  166. package/build/types/action-form/fields/FormFieldRenderer.d.ts.map +1 -0
  167. package/build/types/action-form/fields/TextInputField.d.ts +3 -0
  168. package/build/types/action-form/fields/TextInputField.d.ts.map +1 -0
  169. package/build/types/action-form/utils/coerceFieldValue.d.ts +10 -0
  170. package/build/types/action-form/utils/coerceFieldValue.d.ts.map +1 -0
  171. package/build/types/action-form/utils/getDefaultFieldComponent.d.ts +6 -0
  172. package/build/types/action-form/utils/getDefaultFieldComponent.d.ts.map +1 -0
  173. package/build/types/action-form/utils/getDefaultFieldDefinitions.d.ts +6 -0
  174. package/build/types/action-form/utils/getDefaultFieldDefinitions.d.ts.map +1 -0
  175. package/build/types/base-components/tooltip/Tooltip.d.ts +31 -0
  176. package/build/types/base-components/tooltip/Tooltip.d.ts.map +1 -0
  177. package/build/types/base-components/tooltip/index.d.ts +1 -0
  178. package/build/types/base-components/tooltip/index.d.ts.map +1 -0
  179. package/build/types/filter-list/base/BaseFilterList.d.ts.map +1 -1
  180. package/build/types/filter-list/base/FilterIcons.d.ts +7 -0
  181. package/build/types/filter-list/base/FilterIcons.d.ts.map +1 -1
  182. package/build/types/filter-list/base/FilterListHeader.d.ts.map +1 -1
  183. package/build/types/filter-list/hooks/useFilterListState.d.ts.map +1 -1
  184. package/build/types/filter-list/utils/assertUnreachable.d.ts +1 -6
  185. package/build/types/filter-list/utils/assertUnreachable.d.ts.map +1 -1
  186. package/build/types/filter-list/utils/filterStateToWhereClause.d.ts +5 -1
  187. package/build/types/filter-list/utils/filterStateToWhereClause.d.ts.map +1 -1
  188. package/build/types/object-table/EditableCell.d.ts +8 -2
  189. package/build/types/object-table/EditableCell.d.ts.map +1 -1
  190. package/build/types/object-table/ObjectTableApi.d.ts +7 -0
  191. package/build/types/object-table/ObjectTableApi.d.ts.map +1 -1
  192. package/build/types/object-table/Table.d.ts +4 -0
  193. package/build/types/object-table/Table.d.ts.map +1 -1
  194. package/build/types/object-table/TableEditContainer.d.ts +1 -1
  195. package/build/types/object-table/TableEditContainer.d.ts.map +1 -1
  196. package/build/types/object-table/TableHeader.d.ts.map +1 -1
  197. package/build/types/object-table/TableRow.d.ts +2 -2
  198. package/build/types/object-table/TableRow.d.ts.map +1 -1
  199. package/build/types/object-table/hooks/useEditableTable.d.ts.map +1 -1
  200. package/build/types/object-table/utils/types.d.ts +7 -4
  201. package/build/types/object-table/utils/types.d.ts.map +1 -1
  202. package/build/types/shared/assertUnreachable.d.ts +6 -0
  203. package/build/types/shared/assertUnreachable.d.ts.map +1 -0
  204. package/build/types/shared/typedMemo.d.ts +6 -0
  205. package/build/types/shared/typedMemo.d.ts.map +1 -0
  206. package/package.json +6 -5
@@ -14,24 +14,56 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
+ import { formatDateForInput } from "../base/inputs/dateUtils.js";
17
18
  import { assertUnreachable } from "./assertUnreachable.js";
18
19
  import { getFilterKey } from "./getFilterKey.js";
19
- function filterStateToPropertyFilter(state) {
20
+ function isCompoundFilter(f) {
21
+ return typeof f === "object" && f != null && "__compound" in f;
22
+ }
23
+ const NUMERIC_BOUNDS = {
24
+ byte: {
25
+ min: -128,
26
+ max: 127
27
+ },
28
+ short: {
29
+ min: -32_768,
30
+ max: 32_767
31
+ },
32
+ integer: {
33
+ min: -2_147_483_648,
34
+ max: 2_147_483_647
35
+ },
36
+ long: {
37
+ min: Number.MIN_SAFE_INTEGER,
38
+ max: Number.MAX_SAFE_INTEGER
39
+ }
40
+ };
41
+ function clampToPropertyBounds(value, propertyType) {
42
+ if (propertyType === undefined) {
43
+ return value;
44
+ }
45
+ const bounds = NUMERIC_BOUNDS[propertyType];
46
+ if (bounds === undefined) {
47
+ return value;
48
+ }
49
+ return Math.max(bounds.min, Math.min(bounds.max, value));
50
+ }
51
+ function formatDateValue(date, propertyType) {
52
+ if (propertyType === "datetime") {
53
+ return formatDateForInput(date);
54
+ }
55
+ return date.toISOString();
56
+ }
57
+ function filterStateToPropertyFilter(state, propertyType) {
20
58
  switch (state.type) {
21
59
  case "CONTAINS_TEXT":
22
60
  {
23
61
  if (!state.value) {
24
62
  return undefined;
25
63
  }
26
- const filter = {
64
+ return {
27
65
  $containsAnyTerm: state.value
28
66
  };
29
- if (state.isExcluding) {
30
- return {
31
- $not: filter
32
- };
33
- }
34
- return filter;
35
67
  }
36
68
  case "TOGGLE":
37
69
  {
@@ -42,138 +74,104 @@ function filterStateToPropertyFilter(state) {
42
74
  const conditions = [];
43
75
  if (state.minValue !== undefined) {
44
76
  conditions.push({
45
- $gte: state.minValue.toISOString()
77
+ $gte: formatDateValue(state.minValue, propertyType)
46
78
  });
47
79
  }
48
80
  if (state.maxValue !== undefined) {
49
81
  conditions.push({
50
- $lte: state.maxValue.toISOString()
82
+ $lte: formatDateValue(state.maxValue, propertyType)
51
83
  });
52
84
  }
53
85
  if (conditions.length === 0 && !state.includeNull) {
54
86
  return undefined;
55
87
  }
56
- let rangeFilter;
57
- if (conditions.length === 1) {
58
- rangeFilter = conditions[0];
59
- } else if (conditions.length > 1) {
60
- rangeFilter = {
61
- $and: conditions
62
- };
63
- }
64
- if (state.includeNull) {
65
- if (rangeFilter) {
66
- return {
67
- $or: [rangeFilter, {
68
- $isNull: true
69
- }]
70
- };
71
- }
88
+ if (conditions.length === 0 && state.includeNull) {
72
89
  return {
73
90
  $isNull: true
74
91
  };
75
92
  }
76
- return rangeFilter;
93
+ if (conditions.length === 1 && !state.includeNull) {
94
+ return conditions[0];
95
+ }
96
+ return {
97
+ __compound: true,
98
+ conditions,
99
+ includeNull: state.includeNull ?? false
100
+ };
77
101
  }
78
102
  case "NUMBER_RANGE":
79
103
  {
80
104
  const conditions = [];
81
105
  if (state.minValue !== undefined) {
82
106
  conditions.push({
83
- $gte: state.minValue
107
+ $gte: clampToPropertyBounds(state.minValue, propertyType)
84
108
  });
85
109
  }
86
110
  if (state.maxValue !== undefined) {
87
111
  conditions.push({
88
- $lte: state.maxValue
112
+ $lte: clampToPropertyBounds(state.maxValue, propertyType)
89
113
  });
90
114
  }
91
115
  if (conditions.length === 0 && !state.includeNull) {
92
116
  return undefined;
93
117
  }
94
- let rangeFilter;
95
- if (conditions.length === 1) {
96
- rangeFilter = conditions[0];
97
- } else if (conditions.length > 1) {
98
- rangeFilter = {
99
- $and: conditions
100
- };
101
- }
102
- if (state.includeNull) {
103
- if (rangeFilter) {
104
- return {
105
- $or: [rangeFilter, {
106
- $isNull: true
107
- }]
108
- };
109
- }
118
+ if (conditions.length === 0 && state.includeNull) {
110
119
  return {
111
120
  $isNull: true
112
121
  };
113
122
  }
114
- return rangeFilter;
123
+ if (conditions.length === 1 && !state.includeNull) {
124
+ return conditions[0];
125
+ }
126
+ return {
127
+ __compound: true,
128
+ conditions,
129
+ includeNull: state.includeNull ?? false
130
+ };
115
131
  }
116
132
  case "EXACT_MATCH":
117
133
  {
118
134
  if (state.values.length === 0) {
119
135
  return undefined;
120
136
  }
121
- const filter = state.values.length === 1 ? state.values[0] : {
137
+ return state.values.length === 1 ? state.values[0] : {
122
138
  $in: state.values
123
139
  };
124
- if (state.isExcluding) {
125
- return {
126
- $not: filter
127
- };
128
- }
129
- return filter;
130
140
  }
131
141
  case "SELECT":
132
142
  {
133
143
  if (state.selectedValues.length === 0) {
134
144
  return undefined;
135
145
  }
136
- const values = state.selectedValues.map(v => v instanceof Date ? v.toISOString() : v);
137
- const filter = values.length === 1 ? values[0] : {
146
+ const values = state.selectedValues.map(v => v instanceof Date ? formatDateValue(v, propertyType) : v);
147
+ return values.length === 1 ? values[0] : {
138
148
  $in: values
139
149
  };
140
- if (state.isExcluding) {
141
- return {
142
- $not: filter
143
- };
144
- }
145
- return filter;
146
150
  }
147
151
  case "TIMELINE":
148
152
  {
149
153
  const conditions = [];
150
154
  if (state.startDate !== undefined) {
151
155
  conditions.push({
152
- $gte: state.startDate.toISOString()
156
+ $gte: formatDateValue(state.startDate, propertyType)
153
157
  });
154
158
  }
155
159
  if (state.endDate !== undefined) {
156
160
  conditions.push({
157
- $lte: state.endDate.toISOString()
161
+ $lte: formatDateValue(state.endDate, propertyType)
158
162
  });
159
163
  }
160
164
  if (conditions.length === 0) {
161
165
  return undefined;
162
166
  }
163
- let rangeFilter;
164
167
  if (conditions.length === 1) {
165
- rangeFilter = conditions[0];
166
- } else {
167
- rangeFilter = {
168
- $and: conditions
169
- };
168
+ return conditions[0];
170
169
  }
171
- if (state.isExcluding) {
172
- return {
173
- $not: rangeFilter
174
- };
175
- }
176
- return rangeFilter;
170
+ return {
171
+ __compound: true,
172
+ conditions,
173
+ includeNull: false
174
+ };
177
175
  }
178
176
 
179
177
  // These filter types are handled separately in buildWhereClause
@@ -200,7 +198,8 @@ function filterStateToPropertyFilter(state) {
200
198
  * cannot verify that the constructed clause structure matches the generic Q's
201
199
  * expected shape, but the structure is guaranteed to be valid by construction.
202
200
  */
203
- export function buildWhereClause(definitions, filterStates, operator, objectType, excludeFilterKey) {
201
+
202
+ export function buildWhereClause(definitions, filterStates, operator, propertyTypes, excludeFilterKey) {
204
203
  if (!definitions || definitions.length === 0) {
205
204
  return {};
206
205
  }
@@ -217,11 +216,37 @@ export function buildWhereClause(definitions, filterStates, operator, objectType
217
216
  switch (definition.type) {
218
217
  case "PROPERTY":
219
218
  {
220
- const filter = filterStateToPropertyFilter(state);
219
+ const propertyType = propertyTypes?.get(definition.key)?.type;
220
+ const filter = filterStateToPropertyFilter(state, propertyType);
221
221
  if (filter !== undefined) {
222
- clauses.push({
223
- [definition.key]: filter
224
- });
222
+ const isExcluding = "isExcluding" in state && state.isExcluding;
223
+ if (isCompoundFilter(filter)) {
224
+ const fieldClauses = filter.conditions.map(c => ({
225
+ [definition.key]: c
226
+ }));
227
+ let rangeClause = fieldClauses.length === 1 ? fieldClauses[0] : {
228
+ $and: fieldClauses
229
+ };
230
+ if (filter.includeNull) {
231
+ rangeClause = {
232
+ $or: [rangeClause, {
233
+ [definition.key]: {
234
+ $isNull: true
235
+ }
236
+ }]
237
+ };
238
+ }
239
+ clauses.push(isExcluding ? {
240
+ $not: rangeClause
241
+ } : rangeClause);
242
+ } else {
243
+ const clause = {
244
+ [definition.key]: filter
245
+ };
246
+ clauses.push(isExcluding ? {
247
+ $not: clause
248
+ } : clause);
249
+ }
225
250
  }
226
251
  break;
227
252
  }
@@ -273,12 +298,17 @@ export function buildWhereClause(definitions, filterStates, operator, objectType
273
298
  const properties = definition.properties;
274
299
  let propertiesToSearch;
275
300
  if (properties === "all") {
276
- if (objectType?.__DefinitionMetadata?.properties) {
277
- propertiesToSearch = Object.entries(objectType.__DefinitionMetadata.properties).filter(([, prop]) => prop.type === "string" && !prop.multiplicity).map(([key]) => key);
301
+ if (propertyTypes && propertyTypes.size > 0) {
302
+ propertiesToSearch = [];
303
+ for (const [key, info] of propertyTypes) {
304
+ if (info.type === "string" && !info.multiplicity) {
305
+ propertiesToSearch.push(key);
306
+ }
307
+ }
278
308
  } else {
279
309
  if (process.env.NODE_ENV !== "production") {
280
310
  // eslint-disable-next-line no-console
281
- console.warn("[FilterList] Keyword search with properties: 'all' requires objectType to be provided. Filter will be skipped.");
311
+ console.warn("[FilterList] Keyword search with properties: 'all' requires propertyTypes to be provided. Filter will be skipped.");
282
312
  }
283
313
  break;
284
314
  }
@@ -290,21 +320,21 @@ export function buildWhereClause(definitions, filterStates, operator, objectType
290
320
  }
291
321
  const containsOp = state.operator === "AND" ? "$containsAllTerms" : "$containsAnyTerm";
292
322
  const propertySearches = propertiesToSearch.map(prop => ({
293
- [prop]: state.isExcluding ? {
294
- $not: {
295
- [containsOp]: searchTerm
296
- }
297
- } : {
323
+ [prop]: {
298
324
  [containsOp]: searchTerm
299
325
  }
300
326
  }));
327
+ let searchClause;
301
328
  if (propertySearches.length === 1) {
302
- clauses.push(propertySearches[0]);
329
+ searchClause = propertySearches[0];
303
330
  } else {
304
- clauses.push({
331
+ searchClause = {
305
332
  $or: propertySearches
306
- });
333
+ };
307
334
  }
335
+ clauses.push(state.isExcluding ? {
336
+ $not: searchClause
337
+ } : searchClause);
308
338
  break;
309
339
  }
310
340
  case "CUSTOM":
@@ -1 +1 @@
1
- {"version":3,"file":"filterStateToWhereClause.js","names":["assertUnreachable","getFilterKey","filterStateToPropertyFilter","state","type","value","undefined","filter","$containsAnyTerm","isExcluding","$not","enabled","conditions","minValue","push","$gte","toISOString","maxValue","$lte","length","includeNull","rangeFilter","$and","$or","$isNull","values","$in","selectedValues","map","v","Date","startDate","endDate","buildWhereClause","definitions","filterStates","operator","objectType","excludeFilterKey","clauses","definition","key","get","process","env","NODE_ENV","console","warn","linkName","hasLink","$isNotNull","searchTerm","trim","properties","propertiesToSearch","__DefinitionMetadata","Object","entries","prop","multiplicity","containsOp","propertySearches","customClause","toWhereClause","keys"],"sources":["filterStateToWhereClause.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ObjectTypeDefinition, WhereClause } from \"@osdk/api\";\nimport type { FilterDefinitionUnion } from \"../FilterListApi.js\";\nimport type { FilterState } from \"../FilterListItemApi.js\";\nimport { assertUnreachable } from \"./assertUnreachable.js\";\nimport { getFilterKey } from \"./getFilterKey.js\";\n\ntype PropertyFilter = Record<string, unknown> | boolean | string | number;\n\nfunction filterStateToPropertyFilter(\n state: FilterState,\n): PropertyFilter | undefined {\n switch (state.type) {\n case \"CONTAINS_TEXT\": {\n if (!state.value) {\n return undefined;\n }\n const filter = { $containsAnyTerm: state.value };\n if (state.isExcluding) {\n return { $not: filter };\n }\n return filter;\n }\n\n case \"TOGGLE\": {\n return state.enabled;\n }\n\n case \"DATE_RANGE\": {\n const conditions: PropertyFilter[] = [];\n\n if (state.minValue !== undefined) {\n conditions.push({ $gte: state.minValue.toISOString() });\n }\n if (state.maxValue !== undefined) {\n conditions.push({ $lte: state.maxValue.toISOString() });\n }\n\n if (conditions.length === 0 && !state.includeNull) {\n return undefined;\n }\n\n let rangeFilter: PropertyFilter | undefined;\n if (conditions.length === 1) {\n rangeFilter = conditions[0];\n } else if (conditions.length > 1) {\n rangeFilter = { $and: conditions };\n }\n\n if (state.includeNull) {\n if (rangeFilter) {\n return { $or: [rangeFilter, { $isNull: true }] };\n }\n return { $isNull: true };\n }\n\n return rangeFilter;\n }\n\n case \"NUMBER_RANGE\": {\n const conditions: PropertyFilter[] = [];\n\n if (state.minValue !== undefined) {\n conditions.push({ $gte: state.minValue });\n }\n if (state.maxValue !== undefined) {\n conditions.push({ $lte: state.maxValue });\n }\n\n if (conditions.length === 0 && !state.includeNull) {\n return undefined;\n }\n\n let rangeFilter: PropertyFilter | undefined;\n if (conditions.length === 1) {\n rangeFilter = conditions[0];\n } else if (conditions.length > 1) {\n rangeFilter = { $and: conditions };\n }\n\n if (state.includeNull) {\n if (rangeFilter) {\n return { $or: [rangeFilter, { $isNull: true }] };\n }\n return { $isNull: true };\n }\n\n return rangeFilter;\n }\n\n case \"EXACT_MATCH\": {\n if (state.values.length === 0) {\n return undefined;\n }\n const filter = state.values.length === 1\n ? state.values[0]\n : { $in: state.values };\n if (state.isExcluding) {\n return { $not: filter };\n }\n return filter;\n }\n\n case \"SELECT\": {\n if (state.selectedValues.length === 0) {\n return undefined;\n }\n const values: (string | number | boolean)[] = state.selectedValues.map(\n (v) =>\n v instanceof Date ? v.toISOString() : v as string | number | boolean,\n );\n const filter = values.length === 1 ? values[0] : { $in: values };\n if (state.isExcluding) {\n return { $not: filter };\n }\n return filter;\n }\n\n case \"TIMELINE\": {\n const conditions: PropertyFilter[] = [];\n if (state.startDate !== undefined) {\n conditions.push({ $gte: state.startDate.toISOString() });\n }\n if (state.endDate !== undefined) {\n conditions.push({ $lte: state.endDate.toISOString() });\n }\n if (conditions.length === 0) {\n return undefined;\n }\n let rangeFilter: PropertyFilter;\n if (conditions.length === 1) {\n rangeFilter = conditions[0];\n } else {\n rangeFilter = { $and: conditions };\n }\n if (state.isExcluding) {\n return { $not: rangeFilter };\n }\n return rangeFilter;\n }\n\n // These filter types are handled separately in buildWhereClause\n // since they need access to the full definition, not just state\n case \"hasLink\":\n case \"linkedProperty\":\n case \"keywordSearch\":\n case \"custom\":\n return undefined;\n\n default:\n return assertUnreachable(state);\n }\n}\n\n/**\n * Builds a WhereClause from filter definitions and their current states.\n *\n * The filterStates map uses string keys derived from filter definitions via\n * getFilterKey(). This ensures stable state lookups even when filters are\n * reordered or definition object references change.\n *\n * Note: The `as WhereClause<Q>` casts are necessary because we're building\n * clauses dynamically from property keys determined at runtime. TypeScript\n * cannot verify that the constructed clause structure matches the generic Q's\n * expected shape, but the structure is guaranteed to be valid by construction.\n */\nexport function buildWhereClause<Q extends ObjectTypeDefinition>(\n definitions: Array<FilterDefinitionUnion<Q>> | undefined,\n filterStates: Map<string, FilterState>,\n operator: \"and\" | \"or\",\n objectType?: Q,\n excludeFilterKey?: string,\n): WhereClause<Q> {\n if (!definitions || definitions.length === 0) {\n return {} as WhereClause<Q>;\n }\n\n const clauses: Array<Record<string, unknown>> = [];\n\n for (const definition of definitions) {\n const key = getFilterKey(definition);\n if (key === excludeFilterKey) {\n continue;\n }\n const state = filterStates.get(key);\n\n if (!state) {\n continue;\n }\n\n switch (definition.type) {\n case \"PROPERTY\": {\n const filter = filterStateToPropertyFilter(state);\n if (filter !== undefined) {\n clauses.push({ [definition.key]: filter });\n }\n break;\n }\n\n case \"HAS_LINK\": {\n if (state.type !== \"hasLink\") {\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\n `[FilterList] State type mismatch for hasLink filter \"${definition.linkName}\": expected hasLink, got ${state.type}`,\n );\n }\n break;\n }\n if (!state.hasLink) {\n break;\n }\n clauses.push({ [definition.linkName]: { $isNotNull: true } });\n break;\n }\n\n case \"LINKED_PROPERTY\": {\n // OSDK WhereClause does not support filtering through links.\n // Link-based filtering requires ObjectSet operations (pivotTo/intersect).\n // LinkedProperty filters render UI for selection but cannot be included\n // in the where clause. Consumers needing linked property filtering must\n // implement it using ObjectSet.pivotTo() and intersect().\n break;\n }\n\n case \"KEYWORD_SEARCH\": {\n if (state.type !== \"keywordSearch\") {\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\n `[FilterList] State type mismatch for keywordSearch filter: expected keywordSearch, got ${state.type}`,\n );\n }\n break;\n }\n if (!state.searchTerm) {\n break;\n }\n // TypeScript narrows state to KeywordSearchFilterState\n const searchTerm = state.searchTerm.trim();\n if (!searchTerm) {\n break;\n }\n\n const properties = definition.properties;\n let propertiesToSearch: string[];\n\n if (properties === \"all\") {\n if (objectType?.__DefinitionMetadata?.properties) {\n propertiesToSearch = Object.entries(\n objectType.__DefinitionMetadata.properties,\n )\n .filter(([, prop]) =>\n prop.type === \"string\" && !prop.multiplicity\n )\n .map(([key]) => key);\n } else {\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\n \"[FilterList] Keyword search with properties: 'all' requires objectType to be provided. Filter will be skipped.\",\n );\n }\n break;\n }\n } else {\n propertiesToSearch = properties;\n }\n\n if (propertiesToSearch.length === 0) {\n break;\n }\n\n const containsOp = state.operator === \"AND\"\n ? \"$containsAllTerms\"\n : \"$containsAnyTerm\";\n\n const propertySearches = propertiesToSearch.map((prop) => ({\n [prop]: state.isExcluding\n ? { $not: { [containsOp]: searchTerm } }\n : { [containsOp]: searchTerm },\n }));\n\n if (propertySearches.length === 1) {\n clauses.push(propertySearches[0]);\n } else {\n clauses.push({ $or: propertySearches });\n }\n break;\n }\n\n case \"CUSTOM\": {\n if (state.type !== \"custom\") {\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\n `[FilterList] State type mismatch for custom filter \"${definition.key}\": expected custom, got ${state.type}`,\n );\n }\n break;\n }\n // TypeScript narrows state to CustomFilterState\n const customClause = definition.toWhereClause(state);\n if (customClause && Object.keys(customClause).length > 0) {\n clauses.push(customClause as Record<string, unknown>);\n }\n break;\n }\n\n default:\n assertUnreachable(definition);\n }\n }\n\n if (clauses.length === 0) {\n return {} as WhereClause<Q>;\n }\n\n if (clauses.length === 1) {\n return clauses[0] as WhereClause<Q>;\n }\n\n if (operator === \"and\") {\n return { $and: clauses } as WhereClause<Q>;\n }\n\n return { $or: clauses } as WhereClause<Q>;\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"filterStateToWhereClause.js","names":["formatDateForInput","assertUnreachable","getFilterKey","isCompoundFilter","f","NUMERIC_BOUNDS","byte","min","max","short","integer","long","Number","MIN_SAFE_INTEGER","MAX_SAFE_INTEGER","clampToPropertyBounds","value","propertyType","undefined","bounds","Math","formatDateValue","date","toISOString","filterStateToPropertyFilter","state","type","$containsAnyTerm","enabled","conditions","minValue","push","$gte","maxValue","$lte","length","includeNull","$isNull","__compound","values","$in","selectedValues","map","v","Date","startDate","endDate","buildWhereClause","definitions","filterStates","operator","propertyTypes","excludeFilterKey","clauses","definition","key","get","filter","isExcluding","fieldClauses","c","rangeClause","$and","$or","$not","clause","process","env","NODE_ENV","console","warn","linkName","hasLink","$isNotNull","searchTerm","trim","properties","propertiesToSearch","size","info","multiplicity","containsOp","propertySearches","prop","searchClause","customClause","toWhereClause","Object","keys"],"sources":["filterStateToWhereClause.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ObjectTypeDefinition, WhereClause } from \"@osdk/api\";\nimport { formatDateForInput } from \"../base/inputs/dateUtils.js\";\nimport type { FilterDefinitionUnion } from \"../FilterListApi.js\";\nimport type { FilterState } from \"../FilterListItemApi.js\";\nimport { assertUnreachable } from \"./assertUnreachable.js\";\nimport { getFilterKey } from \"./getFilterKey.js\";\n\ntype PropertyFilter = Record<string, unknown> | boolean | string | number;\n\ninterface CompoundFilter {\n __compound: true;\n conditions: PropertyFilter[];\n includeNull: boolean;\n}\n\nfunction isCompoundFilter(\n f: PropertyFilter | CompoundFilter,\n): f is CompoundFilter {\n return typeof f === \"object\" && f != null && \"__compound\" in f;\n}\n\nconst NUMERIC_BOUNDS: Record<string, { min: number; max: number }> = {\n byte: { min: -128, max: 127 },\n short: { min: -32_768, max: 32_767 },\n integer: { min: -2_147_483_648, max: 2_147_483_647 },\n long: { min: Number.MIN_SAFE_INTEGER, max: Number.MAX_SAFE_INTEGER },\n};\n\nfunction clampToPropertyBounds(\n value: number,\n propertyType: string | undefined,\n): number {\n if (propertyType === undefined) {\n return value;\n }\n const bounds = NUMERIC_BOUNDS[propertyType];\n if (bounds === undefined) {\n return value;\n }\n return Math.max(bounds.min, Math.min(bounds.max, value));\n}\n\nfunction formatDateValue(\n date: Date,\n propertyType: string | undefined,\n): string {\n if (propertyType === \"datetime\") {\n return formatDateForInput(date);\n }\n return date.toISOString();\n}\n\nfunction filterStateToPropertyFilter(\n state: FilterState,\n propertyType?: string,\n): PropertyFilter | CompoundFilter | undefined {\n switch (state.type) {\n case \"CONTAINS_TEXT\": {\n if (!state.value) {\n return undefined;\n }\n return { $containsAnyTerm: state.value };\n }\n\n case \"TOGGLE\": {\n return state.enabled;\n }\n\n case \"DATE_RANGE\": {\n const conditions: PropertyFilter[] = [];\n\n if (state.minValue !== undefined) {\n conditions.push({\n $gte: formatDateValue(state.minValue, propertyType),\n });\n }\n if (state.maxValue !== undefined) {\n conditions.push({\n $lte: formatDateValue(state.maxValue, propertyType),\n });\n }\n\n if (conditions.length === 0 && !state.includeNull) {\n return undefined;\n }\n\n if (conditions.length === 0 && state.includeNull) {\n return { $isNull: true };\n }\n\n if (conditions.length === 1 && !state.includeNull) {\n return conditions[0];\n }\n\n return {\n __compound: true,\n conditions,\n includeNull: state.includeNull ?? false,\n };\n }\n\n case \"NUMBER_RANGE\": {\n const conditions: PropertyFilter[] = [];\n\n if (state.minValue !== undefined) {\n conditions.push({\n $gte: clampToPropertyBounds(state.minValue, propertyType),\n });\n }\n if (state.maxValue !== undefined) {\n conditions.push({\n $lte: clampToPropertyBounds(state.maxValue, propertyType),\n });\n }\n\n if (conditions.length === 0 && !state.includeNull) {\n return undefined;\n }\n\n if (conditions.length === 0 && state.includeNull) {\n return { $isNull: true };\n }\n\n if (conditions.length === 1 && !state.includeNull) {\n return conditions[0];\n }\n\n return {\n __compound: true,\n conditions,\n includeNull: state.includeNull ?? false,\n };\n }\n\n case \"EXACT_MATCH\": {\n if (state.values.length === 0) {\n return undefined;\n }\n return state.values.length === 1\n ? state.values[0]\n : { $in: state.values };\n }\n\n case \"SELECT\": {\n if (state.selectedValues.length === 0) {\n return undefined;\n }\n const values: (string | number | boolean)[] = state.selectedValues.map(\n (v) =>\n v instanceof Date\n ? formatDateValue(v, propertyType)\n : v as string | number | boolean,\n );\n return values.length === 1 ? values[0] : { $in: values };\n }\n\n case \"TIMELINE\": {\n const conditions: PropertyFilter[] = [];\n if (state.startDate !== undefined) {\n conditions.push({\n $gte: formatDateValue(state.startDate, propertyType),\n });\n }\n if (state.endDate !== undefined) {\n conditions.push({\n $lte: formatDateValue(state.endDate, propertyType),\n });\n }\n if (conditions.length === 0) {\n return undefined;\n }\n if (conditions.length === 1) {\n return conditions[0];\n }\n return {\n __compound: true,\n conditions,\n includeNull: false,\n };\n }\n\n // These filter types are handled separately in buildWhereClause\n // since they need access to the full definition, not just state\n case \"hasLink\":\n case \"linkedProperty\":\n case \"keywordSearch\":\n case \"custom\":\n return undefined;\n\n default:\n return assertUnreachable(state);\n }\n}\n\n/**\n * Builds a WhereClause from filter definitions and their current states.\n *\n * The filterStates map uses string keys derived from filter definitions via\n * getFilterKey(). This ensures stable state lookups even when filters are\n * reordered or definition object references change.\n *\n * Note: The `as WhereClause<Q>` casts are necessary because we're building\n * clauses dynamically from property keys determined at runtime. TypeScript\n * cannot verify that the constructed clause structure matches the generic Q's\n * expected shape, but the structure is guaranteed to be valid by construction.\n */\nexport interface PropertyTypeInfo {\n type: string;\n multiplicity: boolean;\n}\n\nexport function buildWhereClause<Q extends ObjectTypeDefinition>(\n definitions: Array<FilterDefinitionUnion<Q>> | undefined,\n filterStates: Map<string, FilterState>,\n operator: \"and\" | \"or\",\n propertyTypes?: Map<string, PropertyTypeInfo>,\n excludeFilterKey?: string,\n): WhereClause<Q> {\n if (!definitions || definitions.length === 0) {\n return {} as WhereClause<Q>;\n }\n\n const clauses: Array<Record<string, unknown>> = [];\n\n for (const definition of definitions) {\n const key = getFilterKey(definition);\n if (key === excludeFilterKey) {\n continue;\n }\n const state = filterStates.get(key);\n\n if (!state) {\n continue;\n }\n\n switch (definition.type) {\n case \"PROPERTY\": {\n const propertyType = propertyTypes?.get(definition.key as string)\n ?.type;\n const filter = filterStateToPropertyFilter(state, propertyType);\n if (filter !== undefined) {\n const isExcluding = \"isExcluding\" in state && state.isExcluding;\n if (isCompoundFilter(filter)) {\n const fieldClauses = filter.conditions.map(c => ({\n [definition.key]: c,\n }));\n let rangeClause: Record<string, unknown> = fieldClauses.length === 1\n ? fieldClauses[0]\n : { $and: fieldClauses };\n if (filter.includeNull) {\n rangeClause = {\n $or: [rangeClause, { [definition.key]: { $isNull: true } }],\n };\n }\n clauses.push(isExcluding ? { $not: rangeClause } : rangeClause);\n } else {\n const clause = { [definition.key]: filter };\n clauses.push(isExcluding ? { $not: clause } : clause);\n }\n }\n break;\n }\n\n case \"HAS_LINK\": {\n if (state.type !== \"hasLink\") {\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\n `[FilterList] State type mismatch for hasLink filter \"${definition.linkName}\": expected hasLink, got ${state.type}`,\n );\n }\n break;\n }\n if (!state.hasLink) {\n break;\n }\n clauses.push({ [definition.linkName]: { $isNotNull: true } });\n break;\n }\n\n case \"LINKED_PROPERTY\": {\n // OSDK WhereClause does not support filtering through links.\n // Link-based filtering requires ObjectSet operations (pivotTo/intersect).\n // LinkedProperty filters render UI for selection but cannot be included\n // in the where clause. Consumers needing linked property filtering must\n // implement it using ObjectSet.pivotTo() and intersect().\n break;\n }\n\n case \"KEYWORD_SEARCH\": {\n if (state.type !== \"keywordSearch\") {\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\n `[FilterList] State type mismatch for keywordSearch filter: expected keywordSearch, got ${state.type}`,\n );\n }\n break;\n }\n if (!state.searchTerm) {\n break;\n }\n // TypeScript narrows state to KeywordSearchFilterState\n const searchTerm = state.searchTerm.trim();\n if (!searchTerm) {\n break;\n }\n\n const properties = definition.properties;\n let propertiesToSearch: string[];\n\n if (properties === \"all\") {\n if (propertyTypes && propertyTypes.size > 0) {\n propertiesToSearch = [];\n for (const [key, info] of propertyTypes) {\n if (info.type === \"string\" && !info.multiplicity) {\n propertiesToSearch.push(key);\n }\n }\n } else {\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\n \"[FilterList] Keyword search with properties: 'all' requires propertyTypes to be provided. Filter will be skipped.\",\n );\n }\n break;\n }\n } else {\n propertiesToSearch = properties;\n }\n\n if (propertiesToSearch.length === 0) {\n break;\n }\n\n const containsOp = state.operator === \"AND\"\n ? \"$containsAllTerms\"\n : \"$containsAnyTerm\";\n\n const propertySearches = propertiesToSearch.map((prop) => ({\n [prop]: { [containsOp]: searchTerm },\n }));\n\n let searchClause: Record<string, unknown>;\n if (propertySearches.length === 1) {\n searchClause = propertySearches[0];\n } else {\n searchClause = { $or: propertySearches };\n }\n clauses.push(\n state.isExcluding ? { $not: searchClause } : searchClause,\n );\n break;\n }\n\n case \"CUSTOM\": {\n if (state.type !== \"custom\") {\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\n `[FilterList] State type mismatch for custom filter \"${definition.key}\": expected custom, got ${state.type}`,\n );\n }\n break;\n }\n // TypeScript narrows state to CustomFilterState\n const customClause = definition.toWhereClause(state);\n if (customClause && Object.keys(customClause).length > 0) {\n clauses.push(customClause as Record<string, unknown>);\n }\n break;\n }\n\n default:\n assertUnreachable(definition);\n }\n }\n\n if (clauses.length === 0) {\n return {} as WhereClause<Q>;\n }\n\n if (clauses.length === 1) {\n return clauses[0] as WhereClause<Q>;\n }\n\n if (operator === \"and\") {\n return { $and: clauses } as WhereClause<Q>;\n }\n\n return { $or: clauses } as WhereClause<Q>;\n}\n"],"mappings":"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","ignoreList":[]}
@@ -32,15 +32,20 @@ export function renderDefaultCell(cellContext) {
32
32
  const cellEdits = meta.cellEdits;
33
33
  const editedValue = cellEdits?.[cellId];
34
34
  const currentValue = editedValue?.newValue ?? cellContext.getValue();
35
+ const validationError = meta.validationErrors?.get(cellId);
35
36
  return /*#__PURE__*/React.createElement(EditableCell, {
36
37
  initialValue: cellContext.getValue(),
37
38
  currentValue: currentValue,
38
39
  cellId: cellId,
39
40
  dataType: columnMeta?.dataType,
40
41
  onCellEdit: meta.onCellEdit,
42
+ onCellValidationError: meta.onCellValidationError,
43
+ clearCellValidationError: meta.clearCellValidationError,
41
44
  originalRowData: cellContext.row.original,
42
45
  rowId: rowId,
43
- columnId: columnId
46
+ columnId: columnId,
47
+ validateEdit: columnMeta?.validateEdit,
48
+ validationError: validationError
44
49
  });
45
50
  }
46
51
  //# sourceMappingURL=DefaultCellRenderer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultCellRenderer.js","names":["React","EditableCell","getCellId","renderDefaultCell","cellContext","meta","table","options","columnMeta","column","columnDef","editable","onCellEdit","isInEditMode","createElement","Fragment","getValue","rowId","row","id","columnId","cellId","cellEdits","editedValue","currentValue","newValue","initialValue","dataType","originalRowData","original"],"sources":["DefaultCellRenderer.tsx"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { CellContext, RowData } from \"@tanstack/react-table\";\nimport React from \"react\";\nimport { EditableCell } from \"./EditableCell.js\";\nimport { getCellId } from \"./utils/getCellId.js\";\n\nexport function renderDefaultCell<TData extends RowData>(\n cellContext: CellContext<TData, unknown>,\n): React.ReactNode {\n const meta = cellContext.table.options.meta;\n const columnMeta = cellContext.column.columnDef.meta;\n\n if (!columnMeta?.editable || !meta?.onCellEdit || !meta?.isInEditMode) {\n return <>{cellContext.getValue()}</>;\n }\n\n const rowId = cellContext.row.id;\n const columnId = cellContext.column.id;\n const cellId = getCellId({ rowId, columnId });\n\n const cellEdits = meta.cellEdits;\n const editedValue = cellEdits?.[cellId];\n const currentValue = editedValue?.newValue ?? cellContext.getValue();\n\n return (\n <EditableCell<TData>\n initialValue={cellContext.getValue()}\n currentValue={currentValue}\n cellId={cellId}\n dataType={columnMeta?.dataType}\n onCellEdit={meta.onCellEdit}\n originalRowData={cellContext.row.original}\n rowId={rowId}\n columnId={columnId}\n />\n );\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,YAAY,QAAQ,mBAAmB;AAChD,SAASC,SAAS,QAAQ,sBAAsB;AAEhD,OAAO,SAASC,iBAAiBA,CAC/BC,WAAwC,EACvB;EACjB,MAAMC,IAAI,GAAGD,WAAW,CAACE,KAAK,CAACC,OAAO,CAACF,IAAI;EAC3C,MAAMG,UAAU,GAAGJ,WAAW,CAACK,MAAM,CAACC,SAAS,CAACL,IAAI;EAEpD,IAAI,CAACG,UAAU,EAAEG,QAAQ,IAAI,CAACN,IAAI,EAAEO,UAAU,IAAI,CAACP,IAAI,EAAEQ,YAAY,EAAE;IACrE,oBAAOb,KAAA,CAAAc,aAAA,CAAAd,KAAA,CAAAe,QAAA,QAAGX,WAAW,CAACY,QAAQ,CAAC,CAAI,CAAC;EACtC;EAEA,MAAMC,KAAK,GAAGb,WAAW,CAACc,GAAG,CAACC,EAAE;EAChC,MAAMC,QAAQ,GAAGhB,WAAW,CAACK,MAAM,CAACU,EAAE;EACtC,MAAME,MAAM,GAAGnB,SAAS,CAAC;IAAEe,KAAK;IAAEG;EAAS,CAAC,CAAC;EAE7C,MAAME,SAAS,GAAGjB,IAAI,CAACiB,SAAS;EAChC,MAAMC,WAAW,GAAGD,SAAS,GAAGD,MAAM,CAAC;EACvC,MAAMG,YAAY,GAAGD,WAAW,EAAEE,QAAQ,IAAIrB,WAAW,CAACY,QAAQ,CAAC,CAAC;EAEpE,oBACEhB,KAAA,CAAAc,aAAA,CAACb,YAAY;IACXyB,YAAY,EAAEtB,WAAW,CAACY,QAAQ,CAAC,CAAE;IACrCQ,YAAY,EAAEA,YAAa;IAC3BH,MAAM,EAAEA,MAAO;IACfM,QAAQ,EAAEnB,UAAU,EAAEmB,QAAS;IAC/Bf,UAAU,EAAEP,IAAI,CAACO,UAAW;IAC5BgB,eAAe,EAAExB,WAAW,CAACc,GAAG,CAACW,QAAS;IAC1CZ,KAAK,EAAEA,KAAM;IACbG,QAAQ,EAAEA;EAAS,CACpB,CAAC;AAEN","ignoreList":[]}
1
+ {"version":3,"file":"DefaultCellRenderer.js","names":["React","EditableCell","getCellId","renderDefaultCell","cellContext","meta","table","options","columnMeta","column","columnDef","editable","onCellEdit","isInEditMode","createElement","Fragment","getValue","rowId","row","id","columnId","cellId","cellEdits","editedValue","currentValue","newValue","validationError","validationErrors","get","initialValue","dataType","onCellValidationError","clearCellValidationError","originalRowData","original","validateEdit"],"sources":["DefaultCellRenderer.tsx"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { CellContext, RowData } from \"@tanstack/react-table\";\nimport React from \"react\";\nimport { EditableCell } from \"./EditableCell.js\";\nimport { getCellId } from \"./utils/getCellId.js\";\n\nexport function renderDefaultCell<TData extends RowData>(\n cellContext: CellContext<TData, unknown>,\n): React.ReactNode {\n const meta = cellContext.table.options.meta;\n const columnMeta = cellContext.column.columnDef.meta;\n\n if (!columnMeta?.editable || !meta?.onCellEdit || !meta?.isInEditMode) {\n return <>{cellContext.getValue()}</>;\n }\n\n const rowId = cellContext.row.id;\n const columnId = cellContext.column.id;\n const cellId = getCellId({ rowId, columnId });\n\n const cellEdits = meta.cellEdits;\n const editedValue = cellEdits?.[cellId];\n const currentValue = editedValue?.newValue ?? cellContext.getValue();\n const validationError = meta.validationErrors?.get(cellId);\n\n return (\n <EditableCell<TData>\n initialValue={cellContext.getValue()}\n currentValue={currentValue}\n cellId={cellId}\n dataType={columnMeta?.dataType}\n onCellEdit={meta.onCellEdit}\n onCellValidationError={meta.onCellValidationError}\n clearCellValidationError={meta.clearCellValidationError}\n originalRowData={cellContext.row.original}\n rowId={rowId}\n columnId={columnId}\n validateEdit={columnMeta?.validateEdit}\n validationError={validationError}\n />\n );\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,YAAY,QAAQ,mBAAmB;AAChD,SAASC,SAAS,QAAQ,sBAAsB;AAEhD,OAAO,SAASC,iBAAiBA,CAC/BC,WAAwC,EACvB;EACjB,MAAMC,IAAI,GAAGD,WAAW,CAACE,KAAK,CAACC,OAAO,CAACF,IAAI;EAC3C,MAAMG,UAAU,GAAGJ,WAAW,CAACK,MAAM,CAACC,SAAS,CAACL,IAAI;EAEpD,IAAI,CAACG,UAAU,EAAEG,QAAQ,IAAI,CAACN,IAAI,EAAEO,UAAU,IAAI,CAACP,IAAI,EAAEQ,YAAY,EAAE;IACrE,oBAAOb,KAAA,CAAAc,aAAA,CAAAd,KAAA,CAAAe,QAAA,QAAGX,WAAW,CAACY,QAAQ,CAAC,CAAI,CAAC;EACtC;EAEA,MAAMC,KAAK,GAAGb,WAAW,CAACc,GAAG,CAACC,EAAE;EAChC,MAAMC,QAAQ,GAAGhB,WAAW,CAACK,MAAM,CAACU,EAAE;EACtC,MAAME,MAAM,GAAGnB,SAAS,CAAC;IAAEe,KAAK;IAAEG;EAAS,CAAC,CAAC;EAE7C,MAAME,SAAS,GAAGjB,IAAI,CAACiB,SAAS;EAChC,MAAMC,WAAW,GAAGD,SAAS,GAAGD,MAAM,CAAC;EACvC,MAAMG,YAAY,GAAGD,WAAW,EAAEE,QAAQ,IAAIrB,WAAW,CAACY,QAAQ,CAAC,CAAC;EACpE,MAAMU,eAAe,GAAGrB,IAAI,CAACsB,gBAAgB,EAAEC,GAAG,CAACP,MAAM,CAAC;EAE1D,oBACErB,KAAA,CAAAc,aAAA,CAACb,YAAY;IACX4B,YAAY,EAAEzB,WAAW,CAACY,QAAQ,CAAC,CAAE;IACrCQ,YAAY,EAAEA,YAAa;IAC3BH,MAAM,EAAEA,MAAO;IACfS,QAAQ,EAAEtB,UAAU,EAAEsB,QAAS;IAC/BlB,UAAU,EAAEP,IAAI,CAACO,UAAW;IAC5BmB,qBAAqB,EAAE1B,IAAI,CAAC0B,qBAAsB;IAClDC,wBAAwB,EAAE3B,IAAI,CAAC2B,wBAAyB;IACxDC,eAAe,EAAE7B,WAAW,CAACc,GAAG,CAACgB,QAAS;IAC1CjB,KAAK,EAAEA,KAAM;IACbG,QAAQ,EAAEA,QAAS;IACnBe,YAAY,EAAE3B,UAAU,EAAE2B,YAAa;IACvCT,eAAe,EAAEA;EAAgB,CAClC,CAAC;AAEN","ignoreList":[]}
@@ -15,8 +15,10 @@
15
15
  */
16
16
 
17
17
  import { Input } from "@base-ui/react/input";
18
+ import { Error } from "@blueprintjs/icons";
18
19
  import classNames from "classnames";
19
20
  import React, { useCallback, useEffect, useRef, useState } from "react";
21
+ import { Tooltip } from "../base-components/tooltip/Tooltip.js";
20
22
  import styles from "./EditableCell.module.css.js";
21
23
  const NUMBER_TYPES = ["double", "integer", "long", "float", "decimal", "byte", "short"];
22
24
  function valueToString(value) {
@@ -42,27 +44,49 @@ function parseValueByType(value, dataType) {
42
44
  }
43
45
  return parsedNumber;
44
46
  }
45
- export function EditableCell({
47
+ const VALIDATION_ERROR_MESSAGE = "Validation error";
48
+ function EditableCellInner({
46
49
  initialValue,
47
50
  currentValue,
48
51
  cellId,
49
52
  dataType,
50
53
  onCellEdit,
54
+ onCellValidationError,
55
+ clearCellValidationError,
51
56
  originalRowData,
52
57
  rowId,
53
- columnId
58
+ columnId,
59
+ validateEdit,
60
+ validationError
54
61
  }) {
55
62
  const [inputValue, setInputValue] = useState(valueToString(currentValue));
56
63
  const isCancelled = useRef(false);
64
+ const validationAbortControllerRef = useRef(null);
65
+ const abortController = useCallback(() => {
66
+ if (validationAbortControllerRef.current) {
67
+ validationAbortControllerRef.current.abort();
68
+ validationAbortControllerRef.current = null;
69
+ }
70
+ }, []);
71
+ const hasValidationError = validationError != null;
57
72
  useEffect(() => {
58
73
  setInputValue(valueToString(currentValue));
59
74
  }, [currentValue]);
75
+ useEffect(() => {
76
+ // Cleanup abort controller on unmount
77
+ return () => {
78
+ abortController();
79
+ };
80
+ }, [abortController]);
60
81
  const handleBlur = useCallback(() => {
61
82
  // Do not commit the edit if it was cancelled with Escape key
62
83
  if (isCancelled.current) {
63
84
  isCancelled.current = false;
64
85
  return;
65
86
  }
87
+
88
+ // Cancel any in-flight validation
89
+ abortController();
66
90
  const parsedValue = parseValueByType(inputValue, dataType);
67
91
  onCellEdit(cellId, {
68
92
  rowId,
@@ -71,10 +95,37 @@ export function EditableCell({
71
95
  oldValue: initialValue,
72
96
  originalRowData
73
97
  });
74
- }, [inputValue, initialValue, onCellEdit, cellId, dataType, rowId, columnId, originalRowData]);
98
+ if (validateEdit) {
99
+ // Create new AbortController for this validation
100
+ const abortController = new AbortController();
101
+ validationAbortControllerRef.current = abortController;
102
+ const validationPromise = validateEdit(parsedValue);
103
+
104
+ // Race between validation and abort
105
+ Promise.race([validationPromise, new Promise((_, reject) => {
106
+ abortController.signal.addEventListener("abort", () => {
107
+ reject(new DOMException("Aborted", "AbortError"));
108
+ });
109
+ })]).then(errorMessage => {
110
+ if (!abortController.signal.aborted) {
111
+ if (errorMessage) {
112
+ onCellValidationError?.(cellId, errorMessage);
113
+ } else {
114
+ clearCellValidationError?.(cellId);
115
+ }
116
+ }
117
+ }, error => {
118
+ if (!abortController.signal.aborted && error.name !== "AbortError") {
119
+ onCellValidationError?.(cellId, VALIDATION_ERROR_MESSAGE);
120
+ }
121
+ });
122
+ }
123
+ }, [abortController, inputValue, dataType, onCellEdit, cellId, rowId, columnId, initialValue, originalRowData, validateEdit, onCellValidationError, clearCellValidationError]);
75
124
  const handleChange = useCallback(value => {
125
+ // Cancel any in-flight validation
126
+ abortController();
76
127
  setInputValue(value);
77
- }, []);
128
+ }, [abortController]);
78
129
  const handleKeyDown = useCallback(e => {
79
130
  if (e.key === "Enter") {
80
131
  e.currentTarget.blur();
@@ -86,15 +137,31 @@ export function EditableCell({
86
137
  }
87
138
  }, [currentValue]);
88
139
  const inputType = dataType && NUMBER_TYPES.includes(dataType) ? "number" : "text";
89
- return /*#__PURE__*/React.createElement(Input, {
90
- className: classNames(styles.osdkEditableInput, {
140
+ return /*#__PURE__*/React.createElement(Tooltip.Provider, null, /*#__PURE__*/React.createElement(Tooltip.Root, {
141
+ disabled: !hasValidationError
142
+ }, /*#__PURE__*/React.createElement(Tooltip.Trigger, null, /*#__PURE__*/React.createElement("div", {
143
+ className: classNames(styles.osdkEditableCell, {
144
+ [styles.error]: hasValidationError,
91
145
  [styles.osdkEditedInput]: currentValue !== initialValue
92
- }),
146
+ })
147
+ }, /*#__PURE__*/React.createElement(Input, {
93
148
  type: inputType,
94
149
  value: inputValue,
150
+ className: styles.osdkEditableInput,
95
151
  onValueChange: handleChange,
96
152
  onBlur: handleBlur,
97
- onKeyDown: handleKeyDown
98
- });
153
+ onKeyDown: handleKeyDown,
154
+ "aria-invalid": hasValidationError
155
+ }), hasValidationError && /*#__PURE__*/React.createElement(Error, {
156
+ className: styles.errorIcon
157
+ }))), /*#__PURE__*/React.createElement(Tooltip.Portal, null, /*#__PURE__*/React.createElement(Tooltip.Positioner, {
158
+ sideOffset: 4,
159
+ side: "bottom"
160
+ }, /*#__PURE__*/React.createElement(Tooltip.Popup, null, /*#__PURE__*/React.createElement("div", {
161
+ className: styles.validationError
162
+ }, /*#__PURE__*/React.createElement(Error, {
163
+ className: styles.errorIcon
164
+ }), validationError), /*#__PURE__*/React.createElement(Tooltip.Arrow, null))))));
99
165
  }
166
+ export const EditableCell = /*#__PURE__*/React.memo(EditableCellInner);
100
167
  //# sourceMappingURL=EditableCell.js.map