@teselagen/ui 0.7.33-beta.5 → 0.7.33-beta.7

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.
@@ -31,9 +31,11 @@ export function getQueryParams({ currentParams, defaults, schema, isInfinite, en
31
31
  noOrderError: any;
32
32
  ownProps: any;
33
33
  }): {
34
- entities: any[];
35
- entitiesAcrossPages: any[];
36
- entityCount: number;
34
+ page: any;
35
+ pageSize: any;
36
+ order: any[];
37
+ filters: any;
38
+ searchTerm: any;
37
39
  } | {
38
40
  variables: {
39
41
  where: {};
package/index.cjs.js CHANGED
@@ -2951,7 +2951,18 @@ let clearMe;
2951
2951
  document.querySelectorAll(`.${id}`).forEach((elem) => {
2952
2952
  elem.classList.remove(id);
2953
2953
  });
2954
- el2.classList.add(id);
2954
+ let targetEl = el2;
2955
+ if (targetEl.disabled || targetEl.getAttribute("disabled") !== null) {
2956
+ const parent2 = targetEl.parentElement;
2957
+ if (parent2) {
2958
+ parent2.classList.add(id);
2959
+ targetEl = parent2;
2960
+ } else {
2961
+ el2.classList.add(id);
2962
+ }
2963
+ } else {
2964
+ el2.classList.add(id);
2965
+ }
2955
2966
  const inst = tippy(`.${id}`, __spreadValues(__spreadProps(__spreadValues({
2956
2967
  theme: "teselagen",
2957
2968
  plugins: [followCursor],
@@ -19414,9 +19425,8 @@ function tableQueryParamsToHasuraClauses({
19414
19425
  if (searchDisabled || field.filterDisabled || type2 === "color") return;
19415
19426
  const filterValue = searchTerm;
19416
19427
  if (type2 === "string" || type2 === "lookup") {
19417
- searchTermFilters.push({
19418
- [path2]: { _ilike: `%${filterValue}%` }
19419
- });
19428
+ const o2 = set$1({}, path2, { _ilike: `%${filterValue}%` });
19429
+ searchTermFilters.push(o2);
19420
19430
  } else if (type2 === "boolean") {
19421
19431
  let regex;
19422
19432
  try {
@@ -19425,19 +19435,16 @@ function tableQueryParamsToHasuraClauses({
19425
19435
  }
19426
19436
  if (regex) {
19427
19437
  if ("true".replace(regex, "") !== "true") {
19428
- searchTermFilters.push({
19429
- [path2]: { _eq: true }
19430
- });
19438
+ const o2 = set$1({}, path2, { _eq: true });
19439
+ searchTermFilters.push(o2);
19431
19440
  } else if ("false".replace(regex, "") !== "false") {
19432
- searchTermFilters.push({
19433
- [path2]: { _eq: false }
19434
- });
19441
+ const o2 = set$1({}, path2, { _eq: false });
19442
+ searchTermFilters.push(o2);
19435
19443
  }
19436
19444
  }
19437
19445
  } else if ((type2 === "number" || type2 === "integer") && !isNaN(filterValue)) {
19438
- searchTermFilters.push({
19439
- [path2]: { _eq: parseFloat(filterValue) }
19440
- });
19446
+ const o2 = set$1({}, path2, { _eq: parseFloat(filterValue) });
19447
+ searchTermFilters.push(o2);
19441
19448
  }
19442
19449
  });
19443
19450
  if (searchTermFilters.length > 0) {
@@ -19522,7 +19529,9 @@ function tableQueryParamsToHasuraClauses({
19522
19529
  },
19523
19530
  {
19524
19531
  [filterOn]: {
19525
- _gt: new Date(new Date(arrayFilterValue[1]).setHours(23, 59))
19532
+ _gt: new Date(
19533
+ new Date(arrayFilterValue[1]).setHours(23, 59)
19534
+ )
19526
19535
  }
19527
19536
  }
19528
19537
  ]
@@ -19565,13 +19574,21 @@ function tableQueryParamsToHasuraClauses({
19565
19574
  ]
19566
19575
  };
19567
19576
  case "equalTo":
19568
- return { [filterOn]: { _eq: parseFloat(filterValue) } };
19577
+ return {
19578
+ [filterOn]: {
19579
+ _eq: type2 === "number" || type2 === "integer" ? parseFloat(filterValue) : filterValue
19580
+ }
19581
+ };
19569
19582
  case "regex":
19570
19583
  return { [filterOn]: { _regex: filterValue } };
19571
19584
  default:
19572
19585
  console.warn(`Unsupported filter type: ${selectedFilter}`);
19573
19586
  return {};
19574
19587
  }
19588
+ }).map((filter2) => {
19589
+ const o2 = {};
19590
+ set$1(o2, Object.keys(filter2)[0], filter2[Object.keys(filter2)[0]]);
19591
+ return o2;
19575
19592
  });
19576
19593
  if (filterClauses.length > 0) {
19577
19594
  if (Object.keys(where).length > 0) {
@@ -19658,6 +19675,9 @@ function applyWhereClause(records, where) {
19658
19675
  } else {
19659
19676
  const value = record[key];
19660
19677
  const conditions = filter2[key];
19678
+ if (isObject$2(value) && isObject$2(conditions) && !hasOperator(conditions)) {
19679
+ return applyFilter(value, conditions);
19680
+ }
19661
19681
  for (const operator in conditions) {
19662
19682
  const conditionValue = conditions[operator];
19663
19683
  if (operator === "_gt" && conditions._lt) {
@@ -19755,6 +19775,10 @@ function applyWhereClause(records, where) {
19755
19775
  return true;
19756
19776
  }
19757
19777
  __name(applyFilter, "applyFilter");
19778
+ function hasOperator(obj) {
19779
+ return Object.keys(obj).some((key) => key.startsWith("_"));
19780
+ }
19781
+ __name(hasOperator, "hasOperator");
19758
19782
  return records.filter((record) => applyFilter(record, where));
19759
19783
  }
19760
19784
  __name(applyWhereClause, "applyWhereClause");
@@ -20015,7 +20039,7 @@ function getQueryParams({
20015
20039
  }
20016
20040
  });
20017
20041
  }
20018
- const toReturn = {
20042
+ let toRet = {
20019
20043
  //these are values that might be generally useful for the wrapped component
20020
20044
  page,
20021
20045
  pageSize: ownProps.controlled_pageSize || pageSize,
@@ -20034,16 +20058,16 @@ function getQueryParams({
20034
20058
  initializeHasuraWhereAndFilter(additionalFilter, where, currentParams);
20035
20059
  addCustomColumnFilters(where, schema.fields, currentParams);
20036
20060
  if (isLocalCall) {
20037
- const toRet = filterLocalEntitiesToHasura(entities, {
20061
+ toRet = __spreadValues(__spreadValues({}, toRet), filterLocalEntitiesToHasura(entities, {
20038
20062
  where,
20039
20063
  order_by,
20040
20064
  limit,
20041
20065
  offset: offset3,
20042
20066
  isInfinite
20043
- });
20067
+ }));
20044
20068
  return toRet;
20045
20069
  } else {
20046
- return __spreadProps(__spreadValues({}, toReturn), {
20070
+ return __spreadProps(__spreadValues({}, toRet), {
20047
20071
  variables: {
20048
20072
  where,
20049
20073
  order_by,
@@ -50984,10 +51008,10 @@ const RenderCell = /* @__PURE__ */ __name(({
50984
51008
  return (_c = (_b = (_a2 = state.form) == null ? void 0 : _a2[formName]) == null ? void 0 : _b.values) == null ? void 0 : _c.reduxFormEditingCell;
50985
51009
  }
50986
51010
  );
50987
- const initialValue = reactRedux.useSelector(
51011
+ const shouldEditableCellInputBeCleared = reactRedux.useSelector(
50988
51012
  (state) => {
50989
51013
  var _a2, _b, _c;
50990
- return (_c = (_b = (_a2 = state.form) == null ? void 0 : _a2[formName]) == null ? void 0 : _b.values) == null ? void 0 : _c.reduxFormInitialValue;
51014
+ return (_c = (_b = (_a2 = state.form) == null ? void 0 : _a2[formName]) == null ? void 0 : _b.values) == null ? void 0 : _c.shouldEditableCellInputBeCleared;
50991
51015
  }
50992
51016
  );
50993
51017
  const [row] = args;
@@ -51040,7 +51064,7 @@ const RenderCell = /* @__PURE__ */ __name(({
51040
51064
  dataTest,
51041
51065
  cancelEdit: cancelCellEdit,
51042
51066
  isNumeric: column.type === "number",
51043
- initialValue: initialValue || text2,
51067
+ initialValue: shouldEditableCellInputBeCleared ? void 0 : text2,
51044
51068
  finishEdit: /* @__PURE__ */ __name((newVal) => {
51045
51069
  finishCellEdit(cellId, newVal);
51046
51070
  }, "finishEdit")
@@ -56498,7 +56522,7 @@ const DataTable = /* @__PURE__ */ __name((_I) => {
56498
56522
  }) : !val;
56499
56523
  });
56500
56524
  }
56501
- if (noValsForField) {
56525
+ if (noValsForField && entities.length) {
56502
56526
  return __spreadProps(__spreadValues({}, field), {
56503
56527
  isHidden: true,
56504
56528
  isForcedHidden: true
@@ -56898,8 +56922,12 @@ const DataTable = /* @__PURE__ */ __name((_I) => {
56898
56922
  }
56899
56923
  }, [selectedCells]);
56900
56924
  const startCellEdit = React.useCallback(
56901
- (cellId, initialValue) => {
56902
- change("reduxFormInitialValue", initialValue);
56925
+ (cellId, shouldClear) => {
56926
+ if (shouldClear) {
56927
+ change("shouldEditableCellInputBeCleared", true);
56928
+ } else {
56929
+ change("shouldEditableCellInputBeCleared", false);
56930
+ }
56903
56931
  change("reduxFormEditingCell", (prev) => {
56904
56932
  if (prev === cellId) return cellId;
56905
56933
  setSelectedCells((prev2) => {
@@ -58560,12 +58588,30 @@ const DataTable = /* @__PURE__ */ __name((_I) => {
58560
58588
  const rowDisabled = isEntityDisabled(entity);
58561
58589
  const isNum = (_g = e.code) == null ? void 0 : _g.startsWith("Digit");
58562
58590
  const isLetter = (_h = e.code) == null ? void 0 : _h.startsWith("Key");
58563
- if (!isNum && !isLetter) {
58591
+ const allowedSpecialChars = [
58592
+ "Minus",
58593
+ "Equal",
58594
+ "Backquote",
58595
+ "BracketLeft",
58596
+ "BracketRight",
58597
+ "Backslash",
58598
+ "IntlBackslash",
58599
+ "Semicolon",
58600
+ "Quote",
58601
+ "Comma",
58602
+ "Period",
58603
+ "Slash",
58604
+ "IntlRo",
58605
+ "IntlYen",
58606
+ "Space"
58607
+ ];
58608
+ const isSpecialChar = allowedSpecialChars.includes(e.code);
58609
+ if (!isNum && !isLetter && !isSpecialChar) {
58564
58610
  return;
58565
58611
  }
58566
58612
  if (rowDisabled) return;
58567
58613
  e.stopPropagation();
58568
- startCellEdit(primarySelectedCellId, e.key);
58614
+ startCellEdit(primarySelectedCellId, true);
58569
58615
  }, "onKeyDown")
58570
58616
  }),
58571
58617
  isCellEditable && entities.length > 50 && // test for this!!
package/index.es.js CHANGED
@@ -2933,7 +2933,18 @@ let clearMe;
2933
2933
  document.querySelectorAll(`.${id}`).forEach((elem) => {
2934
2934
  elem.classList.remove(id);
2935
2935
  });
2936
- el2.classList.add(id);
2936
+ let targetEl = el2;
2937
+ if (targetEl.disabled || targetEl.getAttribute("disabled") !== null) {
2938
+ const parent2 = targetEl.parentElement;
2939
+ if (parent2) {
2940
+ parent2.classList.add(id);
2941
+ targetEl = parent2;
2942
+ } else {
2943
+ el2.classList.add(id);
2944
+ }
2945
+ } else {
2946
+ el2.classList.add(id);
2947
+ }
2937
2948
  const inst = tippy(`.${id}`, __spreadValues(__spreadProps(__spreadValues({
2938
2949
  theme: "teselagen",
2939
2950
  plugins: [followCursor],
@@ -19396,9 +19407,8 @@ function tableQueryParamsToHasuraClauses({
19396
19407
  if (searchDisabled || field.filterDisabled || type2 === "color") return;
19397
19408
  const filterValue = searchTerm;
19398
19409
  if (type2 === "string" || type2 === "lookup") {
19399
- searchTermFilters.push({
19400
- [path2]: { _ilike: `%${filterValue}%` }
19401
- });
19410
+ const o2 = set$1({}, path2, { _ilike: `%${filterValue}%` });
19411
+ searchTermFilters.push(o2);
19402
19412
  } else if (type2 === "boolean") {
19403
19413
  let regex;
19404
19414
  try {
@@ -19407,19 +19417,16 @@ function tableQueryParamsToHasuraClauses({
19407
19417
  }
19408
19418
  if (regex) {
19409
19419
  if ("true".replace(regex, "") !== "true") {
19410
- searchTermFilters.push({
19411
- [path2]: { _eq: true }
19412
- });
19420
+ const o2 = set$1({}, path2, { _eq: true });
19421
+ searchTermFilters.push(o2);
19413
19422
  } else if ("false".replace(regex, "") !== "false") {
19414
- searchTermFilters.push({
19415
- [path2]: { _eq: false }
19416
- });
19423
+ const o2 = set$1({}, path2, { _eq: false });
19424
+ searchTermFilters.push(o2);
19417
19425
  }
19418
19426
  }
19419
19427
  } else if ((type2 === "number" || type2 === "integer") && !isNaN(filterValue)) {
19420
- searchTermFilters.push({
19421
- [path2]: { _eq: parseFloat(filterValue) }
19422
- });
19428
+ const o2 = set$1({}, path2, { _eq: parseFloat(filterValue) });
19429
+ searchTermFilters.push(o2);
19423
19430
  }
19424
19431
  });
19425
19432
  if (searchTermFilters.length > 0) {
@@ -19504,7 +19511,9 @@ function tableQueryParamsToHasuraClauses({
19504
19511
  },
19505
19512
  {
19506
19513
  [filterOn]: {
19507
- _gt: new Date(new Date(arrayFilterValue[1]).setHours(23, 59))
19514
+ _gt: new Date(
19515
+ new Date(arrayFilterValue[1]).setHours(23, 59)
19516
+ )
19508
19517
  }
19509
19518
  }
19510
19519
  ]
@@ -19547,13 +19556,21 @@ function tableQueryParamsToHasuraClauses({
19547
19556
  ]
19548
19557
  };
19549
19558
  case "equalTo":
19550
- return { [filterOn]: { _eq: parseFloat(filterValue) } };
19559
+ return {
19560
+ [filterOn]: {
19561
+ _eq: type2 === "number" || type2 === "integer" ? parseFloat(filterValue) : filterValue
19562
+ }
19563
+ };
19551
19564
  case "regex":
19552
19565
  return { [filterOn]: { _regex: filterValue } };
19553
19566
  default:
19554
19567
  console.warn(`Unsupported filter type: ${selectedFilter}`);
19555
19568
  return {};
19556
19569
  }
19570
+ }).map((filter2) => {
19571
+ const o2 = {};
19572
+ set$1(o2, Object.keys(filter2)[0], filter2[Object.keys(filter2)[0]]);
19573
+ return o2;
19557
19574
  });
19558
19575
  if (filterClauses.length > 0) {
19559
19576
  if (Object.keys(where).length > 0) {
@@ -19640,6 +19657,9 @@ function applyWhereClause(records, where) {
19640
19657
  } else {
19641
19658
  const value = record[key];
19642
19659
  const conditions = filter2[key];
19660
+ if (isObject$2(value) && isObject$2(conditions) && !hasOperator(conditions)) {
19661
+ return applyFilter(value, conditions);
19662
+ }
19643
19663
  for (const operator in conditions) {
19644
19664
  const conditionValue = conditions[operator];
19645
19665
  if (operator === "_gt" && conditions._lt) {
@@ -19737,6 +19757,10 @@ function applyWhereClause(records, where) {
19737
19757
  return true;
19738
19758
  }
19739
19759
  __name(applyFilter, "applyFilter");
19760
+ function hasOperator(obj) {
19761
+ return Object.keys(obj).some((key) => key.startsWith("_"));
19762
+ }
19763
+ __name(hasOperator, "hasOperator");
19740
19764
  return records.filter((record) => applyFilter(record, where));
19741
19765
  }
19742
19766
  __name(applyWhereClause, "applyWhereClause");
@@ -19997,7 +20021,7 @@ function getQueryParams({
19997
20021
  }
19998
20022
  });
19999
20023
  }
20000
- const toReturn = {
20024
+ let toRet = {
20001
20025
  //these are values that might be generally useful for the wrapped component
20002
20026
  page,
20003
20027
  pageSize: ownProps.controlled_pageSize || pageSize,
@@ -20016,16 +20040,16 @@ function getQueryParams({
20016
20040
  initializeHasuraWhereAndFilter(additionalFilter, where, currentParams);
20017
20041
  addCustomColumnFilters(where, schema.fields, currentParams);
20018
20042
  if (isLocalCall) {
20019
- const toRet = filterLocalEntitiesToHasura(entities, {
20043
+ toRet = __spreadValues(__spreadValues({}, toRet), filterLocalEntitiesToHasura(entities, {
20020
20044
  where,
20021
20045
  order_by,
20022
20046
  limit,
20023
20047
  offset: offset3,
20024
20048
  isInfinite
20025
- });
20049
+ }));
20026
20050
  return toRet;
20027
20051
  } else {
20028
- return __spreadProps(__spreadValues({}, toReturn), {
20052
+ return __spreadProps(__spreadValues({}, toRet), {
20029
20053
  variables: {
20030
20054
  where,
20031
20055
  order_by,
@@ -50966,10 +50990,10 @@ const RenderCell = /* @__PURE__ */ __name(({
50966
50990
  return (_c = (_b = (_a2 = state.form) == null ? void 0 : _a2[formName]) == null ? void 0 : _b.values) == null ? void 0 : _c.reduxFormEditingCell;
50967
50991
  }
50968
50992
  );
50969
- const initialValue = useSelector(
50993
+ const shouldEditableCellInputBeCleared = useSelector(
50970
50994
  (state) => {
50971
50995
  var _a2, _b, _c;
50972
- return (_c = (_b = (_a2 = state.form) == null ? void 0 : _a2[formName]) == null ? void 0 : _b.values) == null ? void 0 : _c.reduxFormInitialValue;
50996
+ return (_c = (_b = (_a2 = state.form) == null ? void 0 : _a2[formName]) == null ? void 0 : _b.values) == null ? void 0 : _c.shouldEditableCellInputBeCleared;
50973
50997
  }
50974
50998
  );
50975
50999
  const [row] = args;
@@ -51022,7 +51046,7 @@ const RenderCell = /* @__PURE__ */ __name(({
51022
51046
  dataTest,
51023
51047
  cancelEdit: cancelCellEdit,
51024
51048
  isNumeric: column.type === "number",
51025
- initialValue: initialValue || text2,
51049
+ initialValue: shouldEditableCellInputBeCleared ? void 0 : text2,
51026
51050
  finishEdit: /* @__PURE__ */ __name((newVal) => {
51027
51051
  finishCellEdit(cellId, newVal);
51028
51052
  }, "finishEdit")
@@ -56480,7 +56504,7 @@ const DataTable = /* @__PURE__ */ __name((_I) => {
56480
56504
  }) : !val;
56481
56505
  });
56482
56506
  }
56483
- if (noValsForField) {
56507
+ if (noValsForField && entities.length) {
56484
56508
  return __spreadProps(__spreadValues({}, field), {
56485
56509
  isHidden: true,
56486
56510
  isForcedHidden: true
@@ -56880,8 +56904,12 @@ const DataTable = /* @__PURE__ */ __name((_I) => {
56880
56904
  }
56881
56905
  }, [selectedCells]);
56882
56906
  const startCellEdit = useCallback(
56883
- (cellId, initialValue) => {
56884
- change$1("reduxFormInitialValue", initialValue);
56907
+ (cellId, shouldClear) => {
56908
+ if (shouldClear) {
56909
+ change$1("shouldEditableCellInputBeCleared", true);
56910
+ } else {
56911
+ change$1("shouldEditableCellInputBeCleared", false);
56912
+ }
56885
56913
  change$1("reduxFormEditingCell", (prev) => {
56886
56914
  if (prev === cellId) return cellId;
56887
56915
  setSelectedCells((prev2) => {
@@ -58542,12 +58570,30 @@ const DataTable = /* @__PURE__ */ __name((_I) => {
58542
58570
  const rowDisabled = isEntityDisabled(entity);
58543
58571
  const isNum = (_g = e.code) == null ? void 0 : _g.startsWith("Digit");
58544
58572
  const isLetter = (_h = e.code) == null ? void 0 : _h.startsWith("Key");
58545
- if (!isNum && !isLetter) {
58573
+ const allowedSpecialChars = [
58574
+ "Minus",
58575
+ "Equal",
58576
+ "Backquote",
58577
+ "BracketLeft",
58578
+ "BracketRight",
58579
+ "Backslash",
58580
+ "IntlBackslash",
58581
+ "Semicolon",
58582
+ "Quote",
58583
+ "Comma",
58584
+ "Period",
58585
+ "Slash",
58586
+ "IntlRo",
58587
+ "IntlYen",
58588
+ "Space"
58589
+ ];
58590
+ const isSpecialChar = allowedSpecialChars.includes(e.code);
58591
+ if (!isNum && !isLetter && !isSpecialChar) {
58546
58592
  return;
58547
58593
  }
58548
58594
  if (rowDisabled) return;
58549
58595
  e.stopPropagation();
58550
- startCellEdit(primarySelectedCellId, e.key);
58596
+ startCellEdit(primarySelectedCellId, true);
58551
58597
  }, "onKeyDown")
58552
58598
  }),
58553
58599
  isCellEditable && entities.length > 50 && // test for this!!
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teselagen/ui",
3
- "version": "0.7.33-beta.5",
3
+ "version": "0.7.33-beta.7",
4
4
  "main": "./src/index.js",
5
5
  "type": "module",
6
6
  "exports": {
@@ -32,8 +32,8 @@ export const RenderCell = ({
32
32
  const editingCell = useSelector(
33
33
  state => state.form?.[formName]?.values?.reduxFormEditingCell
34
34
  );
35
- const initialValue = useSelector(
36
- state => state.form?.[formName]?.values?.reduxFormInitialValue
35
+ const shouldEditableCellInputBeCleared = useSelector(
36
+ state => state.form?.[formName]?.values?.shouldEditableCellInputBeCleared
37
37
  );
38
38
 
39
39
  const [row] = args;
@@ -85,7 +85,7 @@ export const RenderCell = ({
85
85
  dataTest={dataTest}
86
86
  cancelEdit={cancelCellEdit}
87
87
  isNumeric={column.type === "number"}
88
- initialValue={initialValue || text}
88
+ initialValue={shouldEditableCellInputBeCleared ? undefined : text}
89
89
  finishEdit={newVal => {
90
90
  finishCellEdit(cellId, newVal);
91
91
  }}
@@ -603,7 +603,7 @@ const DataTable = ({
603
603
  : !val;
604
604
  });
605
605
  }
606
- if (noValsForField) {
606
+ if (noValsForField && entities.length) {
607
607
  return {
608
608
  ...field,
609
609
  isHidden: true,
@@ -1075,11 +1075,17 @@ const DataTable = ({
1075
1075
  }, [selectedCells]);
1076
1076
 
1077
1077
  const startCellEdit = useCallback(
1078
- (cellId, initialValue) => {
1078
+ (cellId, shouldClear) => {
1079
+ // console.log(`startCellEdit initialValue:`, initialValue)
1079
1080
  // This initial value is not needed if the event is propagated accordingly.
1080
1081
  // This is directly connected to the RenderCell component, which does set
1081
1082
  // the initial value.
1082
- change("reduxFormInitialValue", initialValue);
1083
+ // change("shouldEditableCellInputBeCleared", undefined);
1084
+ if (shouldClear) {
1085
+ change("shouldEditableCellInputBeCleared", true);
1086
+ } else {
1087
+ change("shouldEditableCellInputBeCleared", false);
1088
+ }
1083
1089
  change("reduxFormEditingCell", prev => {
1084
1090
  //check if the cell is already selected and editing and if so, don't change it
1085
1091
  if (prev === cellId) return cellId;
@@ -2955,12 +2961,30 @@ const DataTable = ({
2955
2961
  const rowDisabled = isEntityDisabled(entity);
2956
2962
  const isNum = e.code?.startsWith("Digit");
2957
2963
  const isLetter = e.code?.startsWith("Key");
2958
- if (!isNum && !isLetter) {
2964
+ const allowedSpecialChars = [
2965
+ "Minus",
2966
+ "Equal",
2967
+ "Backquote",
2968
+ "BracketLeft",
2969
+ "BracketRight",
2970
+ "Backslash",
2971
+ "IntlBackslash",
2972
+ "Semicolon",
2973
+ "Quote",
2974
+ "Comma",
2975
+ "Period",
2976
+ "Slash",
2977
+ "IntlRo",
2978
+ "IntlYen",
2979
+ "Space"
2980
+ ];
2981
+ const isSpecialChar = allowedSpecialChars.includes(e.code);
2982
+ if (!isNum && !isLetter && !isSpecialChar) {
2959
2983
  return;
2960
2984
  }
2961
2985
  if (rowDisabled) return;
2962
2986
  e.stopPropagation();
2963
- startCellEdit(primarySelectedCellId, e.key);
2987
+ startCellEdit(primarySelectedCellId, true);
2964
2988
  }
2965
2989
  })}
2966
2990
  >
@@ -77,6 +77,15 @@ function applyWhereClause(records, where) {
77
77
  const value = record[key];
78
78
  const conditions = filter[key];
79
79
 
80
+ // Handle nested object properties
81
+ if (
82
+ isObject(value) &&
83
+ isObject(conditions) &&
84
+ !hasOperator(conditions)
85
+ ) {
86
+ return applyFilter(value, conditions);
87
+ }
88
+
80
89
  for (const operator in conditions) {
81
90
  const conditionValue = conditions[operator];
82
91
 
@@ -208,6 +217,11 @@ function applyWhereClause(records, where) {
208
217
  return true;
209
218
  }
210
219
 
220
+ // Helper to check if an object contains any Hasura operators
221
+ function hasOperator(obj) {
222
+ return Object.keys(obj).some(key => key.startsWith("_"));
223
+ }
224
+
211
225
  return records.filter(record => applyFilter(record, where));
212
226
  }
213
227
 
@@ -297,6 +297,55 @@ describe("filterLocalEntitiesToHasura", () => {
297
297
  expect(result.entitiesAcrossPages).toEqual([records[0]]);
298
298
  expect(result.entityCount).toBe(1);
299
299
  });
300
+ it("should filter with nested filters in _and and _or properly ", () => {
301
+ const result = filterLocalEntitiesToHasura(
302
+ [
303
+ {
304
+ id: 1,
305
+ type: {
306
+ special: "01"
307
+ }
308
+ },
309
+ {
310
+ id: 2,
311
+ type: {
312
+ special: "02"
313
+ }
314
+ }
315
+ ],
316
+ {
317
+ where: {
318
+ _and: [
319
+ {
320
+ type: {
321
+ special: {
322
+ _ilike: "%01%"
323
+ }
324
+ }
325
+ }
326
+ ],
327
+ _or: []
328
+ }
329
+ }
330
+ );
331
+ expect(result.entities).toEqual([
332
+ {
333
+ id: 1,
334
+ type: {
335
+ special: "01"
336
+ }
337
+ }
338
+ ]);
339
+ expect(result.entitiesAcrossPages).toEqual([
340
+ {
341
+ id: 1,
342
+ type: {
343
+ special: "01"
344
+ }
345
+ }
346
+ ]);
347
+ expect(result.entityCount).toBe(1);
348
+ });
300
349
 
301
350
  it("should handle empty where clause", () => {
302
351
  const result = filterLocalEntitiesToHasura(records, {});
@@ -303,7 +303,7 @@ export function getQueryParams({
303
303
  });
304
304
  }
305
305
 
306
- const toReturn = {
306
+ let toRet = {
307
307
  //these are values that might be generally useful for the wrapped component
308
308
  page,
309
309
  pageSize: ownProps.controlled_pageSize || pageSize,
@@ -325,17 +325,20 @@ export function getQueryParams({
325
325
  if (isLocalCall) {
326
326
  //if the table is local (aka not directly connected to a db) then we need to
327
327
  //handle filtering/paging/sorting all on the front end
328
- const toRet = filterLocalEntitiesToHasura(entities, {
329
- where,
330
- order_by,
331
- limit,
332
- offset,
333
- isInfinite
334
- });
328
+ toRet = {
329
+ ...toRet,
330
+ ...filterLocalEntitiesToHasura(entities, {
331
+ where,
332
+ order_by,
333
+ limit,
334
+ offset,
335
+ isInfinite
336
+ })
337
+ };
335
338
  return toRet;
336
339
  } else {
337
340
  return {
338
- ...toReturn,
341
+ ...toRet,
339
342
  variables: {
340
343
  where,
341
344
  order_by,
@@ -1,4 +1,4 @@
1
- import { camelCase } from "lodash-es";
1
+ import { camelCase, set } from "lodash-es";
2
2
 
3
3
  export function tableQueryParamsToHasuraClauses({
4
4
  page,
@@ -23,9 +23,8 @@ export function tableQueryParamsToHasuraClauses({
23
23
  const filterValue = searchTerm; // No cleaning needed here, we're using _ilike
24
24
 
25
25
  if (type === "string" || type === "lookup") {
26
- searchTermFilters.push({
27
- [path]: { _ilike: `%${filterValue}%` }
28
- });
26
+ const o = set({}, path, { _ilike: `%${filterValue}%` });
27
+ searchTermFilters.push(o);
29
28
  } else if (type === "boolean") {
30
29
  let regex;
31
30
  try {
@@ -35,22 +34,19 @@ export function tableQueryParamsToHasuraClauses({
35
34
  }
36
35
  if (regex) {
37
36
  if ("true".replace(regex, "") !== "true") {
38
- searchTermFilters.push({
39
- [path]: { _eq: true }
40
- });
37
+ const o = set({}, path, { _eq: true });
38
+ searchTermFilters.push(o);
41
39
  } else if ("false".replace(regex, "") !== "false") {
42
- searchTermFilters.push({
43
- [path]: { _eq: false }
44
- });
40
+ const o = set({}, path, { _eq: false });
41
+ searchTermFilters.push(o);
45
42
  }
46
43
  }
47
44
  } else if (
48
45
  (type === "number" || type === "integer") &&
49
46
  !isNaN(filterValue)
50
47
  ) {
51
- searchTermFilters.push({
52
- [path]: { _eq: parseFloat(filterValue) }
53
- });
48
+ const o = set({}, path, { _eq: parseFloat(filterValue) });
49
+ searchTermFilters.push(o);
54
50
  }
55
51
  });
56
52
  if (searchTermFilters.length > 0) {
@@ -63,143 +59,157 @@ export function tableQueryParamsToHasuraClauses({
63
59
  }
64
60
 
65
61
  if (filters && filters.length > 0) {
66
- const filterClauses = filters.map(filter => {
67
- let { selectedFilter, filterOn, filterValue } = filter;
68
- const fieldSchema = ccFields[filterOn] || {};
62
+ const filterClauses = filters
63
+ .map(filter => {
64
+ let { selectedFilter, filterOn, filterValue } = filter;
65
+ const fieldSchema = ccFields[filterOn] || {};
69
66
 
70
- const { path, reference, type } = fieldSchema;
71
- let stringFilterValue =
72
- filterValue && filterValue.toString
73
- ? filterValue.toString()
74
- : filterValue;
75
- if (stringFilterValue === false) {
76
- // we still want to be able to search for the string "false" which will get parsed to false
77
- stringFilterValue = "false";
78
- } else {
79
- stringFilterValue = stringFilterValue || "";
80
- }
81
- const arrayFilterValue = Array.isArray(filterValue)
82
- ? filterValue
83
- : stringFilterValue.split(";");
84
-
85
- if (type === "number" || type === "integer") {
86
- filterValue = Array.isArray(filterValue)
87
- ? filterValue.map(val => Number(val))
88
- : Number(filterValue);
89
- }
67
+ const { path, reference, type } = fieldSchema;
68
+ let stringFilterValue =
69
+ filterValue && filterValue.toString
70
+ ? filterValue.toString()
71
+ : filterValue;
72
+ if (stringFilterValue === false) {
73
+ // we still want to be able to search for the string "false" which will get parsed to false
74
+ stringFilterValue = "false";
75
+ } else {
76
+ stringFilterValue = stringFilterValue || "";
77
+ }
78
+ const arrayFilterValue = Array.isArray(filterValue)
79
+ ? filterValue
80
+ : stringFilterValue.split(";");
90
81
 
91
- if (fieldSchema.normalizeFilter) {
92
- filterValue = fieldSchema.normalizeFilter(
93
- filterValue,
94
- selectedFilter,
95
- filterOn
96
- );
97
- }
82
+ if (type === "number" || type === "integer") {
83
+ filterValue = Array.isArray(filterValue)
84
+ ? filterValue.map(val => Number(val))
85
+ : Number(filterValue);
86
+ }
98
87
 
99
- if (reference) {
100
- filterOn = reference.sourceField;
101
- } else {
102
- filterOn = path || filterOn;
103
- }
88
+ if (fieldSchema.normalizeFilter) {
89
+ filterValue = fieldSchema.normalizeFilter(
90
+ filterValue,
91
+ selectedFilter,
92
+ filterOn
93
+ );
94
+ }
104
95
 
105
- switch (selectedFilter) {
106
- case "none":
107
- return {};
108
- case "startsWith":
109
- return { [filterOn]: { _ilike: `${filterValue}%` } };
110
- case "endsWith":
111
- return { [filterOn]: { _ilike: `%${filterValue}` } };
112
- case "contains":
113
- return { [filterOn]: { _ilike: `%${filterValue}%` } };
114
- case "notContains":
115
- return { [filterOn]: { _not_ilike: `%${filterValue}%` } };
116
- case "isExactly":
117
- return { [filterOn]: { _eq: filterValue } };
118
- case "isEmpty":
119
- return {
120
- _or: [
121
- { [filterOn]: { _eq: "" } },
122
- { [filterOn]: { _is_null: true } }
123
- ]
124
- };
125
- case "notEmpty":
126
- return {
127
- _and: [
128
- { [filterOn]: { _neq: "" } },
129
- { [filterOn]: { _is_null: false } }
130
- ]
131
- };
132
- case "inList":
133
- return { [filterOn]: { _in: filterValue } };
134
- case "notInList":
135
- return { [filterOn]: { _nin: filterValue } };
136
- case "true":
137
- return { [filterOn]: { _eq: true } };
138
- case "false":
139
- return { [filterOn]: { _eq: false } };
140
- case "dateIs":
141
- return { [filterOn]: { _eq: filterValue } };
142
- case "notBetween":
143
- return {
144
- _or: [
145
- {
146
- [filterOn]: {
147
- _lt: new Date(arrayFilterValue[0])
148
- }
149
- },
150
- {
151
- [filterOn]: {
152
- _gt: new Date(new Date(arrayFilterValue[1]).setHours(23, 59))
96
+ if (reference) {
97
+ filterOn = reference.sourceField;
98
+ } else {
99
+ filterOn = path || filterOn;
100
+ }
101
+ switch (selectedFilter) {
102
+ case "none":
103
+ return {};
104
+ case "startsWith":
105
+ return { [filterOn]: { _ilike: `${filterValue}%` } };
106
+ case "endsWith":
107
+ return { [filterOn]: { _ilike: `%${filterValue}` } };
108
+ case "contains":
109
+ return { [filterOn]: { _ilike: `%${filterValue}%` } };
110
+ case "notContains":
111
+ return { [filterOn]: { _not_ilike: `%${filterValue}%` } };
112
+ case "isExactly":
113
+ return { [filterOn]: { _eq: filterValue } };
114
+ case "isEmpty":
115
+ return {
116
+ _or: [
117
+ { [filterOn]: { _eq: "" } },
118
+ { [filterOn]: { _is_null: true } }
119
+ ]
120
+ };
121
+ case "notEmpty":
122
+ return {
123
+ _and: [
124
+ { [filterOn]: { _neq: "" } },
125
+ { [filterOn]: { _is_null: false } }
126
+ ]
127
+ };
128
+ case "inList":
129
+ return { [filterOn]: { _in: filterValue } };
130
+ case "notInList":
131
+ return { [filterOn]: { _nin: filterValue } };
132
+ case "true":
133
+ return { [filterOn]: { _eq: true } };
134
+ case "false":
135
+ return { [filterOn]: { _eq: false } };
136
+ case "dateIs":
137
+ return { [filterOn]: { _eq: filterValue } };
138
+ case "notBetween":
139
+ return {
140
+ _or: [
141
+ {
142
+ [filterOn]: {
143
+ _lt: new Date(arrayFilterValue[0])
144
+ }
145
+ },
146
+ {
147
+ [filterOn]: {
148
+ _gt: new Date(
149
+ new Date(arrayFilterValue[1]).setHours(23, 59)
150
+ )
151
+ }
153
152
  }
153
+ ]
154
+ };
155
+ case "isBetween":
156
+ return {
157
+ [filterOn]: {
158
+ _gte: new Date(arrayFilterValue[0]),
159
+ _lte: new Date(new Date(arrayFilterValue[1]).setHours(23, 59))
154
160
  }
155
- ]
156
- };
157
- case "isBetween":
158
- return {
159
- [filterOn]: {
160
- _gte: new Date(arrayFilterValue[0]),
161
- _lte: new Date(new Date(arrayFilterValue[1]).setHours(23, 59))
162
- }
163
- };
164
- case "isBefore":
165
- return { [filterOn]: { _lt: new Date(filterValue) } };
166
- case "isAfter":
167
- return { [filterOn]: { _gt: new Date(filterValue) } };
168
- case "greaterThan":
169
- return { [filterOn]: { _gt: parseFloat(filterValue) } };
170
- case "lessThan":
171
- return { [filterOn]: { _lt: parseFloat(filterValue) } };
172
- case "inRange":
173
- return {
174
- [filterOn]: {
175
- _gte: parseFloat(arrayFilterValue[0]),
176
- _lte: parseFloat(arrayFilterValue[1])
177
- }
178
- };
179
- case "outsideRange":
180
- return {
181
- _or: [
182
- {
183
- [filterOn]: {
184
- _lt: parseFloat(arrayFilterValue[0])
185
- }
186
- },
187
- {
188
- [filterOn]: {
189
- _gt: parseFloat(arrayFilterValue[1])
161
+ };
162
+ case "isBefore":
163
+ return { [filterOn]: { _lt: new Date(filterValue) } };
164
+ case "isAfter":
165
+ return { [filterOn]: { _gt: new Date(filterValue) } };
166
+ case "greaterThan":
167
+ return { [filterOn]: { _gt: parseFloat(filterValue) } };
168
+ case "lessThan":
169
+ return { [filterOn]: { _lt: parseFloat(filterValue) } };
170
+ case "inRange":
171
+ return {
172
+ [filterOn]: {
173
+ _gte: parseFloat(arrayFilterValue[0]),
174
+ _lte: parseFloat(arrayFilterValue[1])
175
+ }
176
+ };
177
+ case "outsideRange":
178
+ return {
179
+ _or: [
180
+ {
181
+ [filterOn]: {
182
+ _lt: parseFloat(arrayFilterValue[0])
183
+ }
184
+ },
185
+ {
186
+ [filterOn]: {
187
+ _gt: parseFloat(arrayFilterValue[1])
188
+ }
190
189
  }
190
+ ]
191
+ };
192
+ case "equalTo":
193
+ return {
194
+ [filterOn]: {
195
+ _eq:
196
+ type === "number" || type === "integer"
197
+ ? parseFloat(filterValue)
198
+ : filterValue
191
199
  }
192
- ]
193
- };
194
- case "equalTo":
195
- return { [filterOn]: { _eq: parseFloat(filterValue) } };
196
- case "regex":
197
- return { [filterOn]: { _regex: filterValue } };
198
- default:
199
- console.warn(`Unsupported filter type: ${selectedFilter}`);
200
- return {};
201
- }
202
- });
200
+ };
201
+ case "regex":
202
+ return { [filterOn]: { _regex: filterValue } };
203
+ default:
204
+ console.warn(`Unsupported filter type: ${selectedFilter}`);
205
+ return {};
206
+ }
207
+ })
208
+ .map(filter => {
209
+ const o = {};
210
+ set(o, Object.keys(filter)[0], filter[Object.keys(filter)[0]]);
211
+ return o;
212
+ });
203
213
 
204
214
  if (filterClauses.length > 0) {
205
215
  if (Object.keys(where).length > 0) {
@@ -52,7 +52,23 @@ let clearMe;
52
52
  elem.classList.remove(id);
53
53
  });
54
54
 
55
- el.classList.add(id);
55
+ // Check if element is disabled, if so use parent instead
56
+ let targetEl = el;
57
+ if (targetEl.disabled || targetEl.getAttribute("disabled") !== null) {
58
+ const parent = targetEl.parentElement;
59
+ if (parent) {
60
+ // Use the parent as the tooltip target
61
+ parent.classList.add(id);
62
+ targetEl = parent; // Change the tooltip target to parent
63
+ } else {
64
+ // No parent, keep using the original element
65
+ el.classList.add(id);
66
+ }
67
+ } else {
68
+ // Element not disabled, use it directly
69
+ el.classList.add(id);
70
+ }
71
+
56
72
  const inst = tippy(`.${id}`, {
57
73
  theme: "teselagen",
58
74
  plugins: [followCursor],
@@ -84,19 +100,12 @@ let clearMe;
84
100
  requires: ["computeStyles"],
85
101
  requiresIfExists: ["offset"],
86
102
  fn({ state }) {
87
- // console.log(`state:`, state);
88
- // state.styles.popper.bottom = 20 + "px";
89
103
  const customBoundary =
90
104
  document.querySelector(dataAvoid) ||
91
105
  document.querySelector(dataAvoidBackup);
92
106
 
93
107
  if (!customBoundary) return;
94
108
  const a = customBoundary.getBoundingClientRect();
95
- // console.log(
96
- // `state.rects.reference.y:`,
97
- // state.rects.reference.y
98
- // );
99
- // console.log(`a.top:`, a.top);
100
109
 
101
110
  if (a.top < state.rects.reference.y) {
102
111
  const b = Math.abs(
@@ -104,16 +113,6 @@ let clearMe;
104
113
  );
105
114
  state.styles.popper.bottom = b + "px";
106
115
  }
107
-
108
- // const overflow = detectOverflow(state, {
109
- // boundary: customBoundary,
110
- // altBoundary: true
111
- // });
112
- // console.log(`overflow:`, overflow);
113
- // if (overflow.bottom > 0) {
114
- // const a = Math.abs(overflow.bottom);
115
- // state.styles.popper.bottom = a + "px";
116
- // }
117
116
  }
118
117
  }
119
118
  ]
@@ -199,3 +198,6 @@ function parentIncludesNoChildDataTip(el, count) {
199
198
  if (el.getAttribute("data-no-child-data-tip")) return true;
200
199
  return parentIncludesNoChildDataTip(el.parentElement, count + 1);
201
200
  }
201
+
202
+ // Export the function to clear parent tooltips so it can be used elsewhere
203
+ // export { clearParentTooltips };
@@ -1,4 +1,5 @@
1
1
  const keyCount = {};
2
+ // if this function is hit more than 20 times in a row in 2 seconds with the same uniqName then throw an error
2
3
  export const isBeingCalledExcessively = ({ uniqName }) => {
3
4
  if (process.env.NODE_ENV !== "development") {
4
5
  return;
@@ -6,19 +7,25 @@ export const isBeingCalledExcessively = ({ uniqName }) => {
6
7
  if (!uniqName) {
7
8
  throw new Error("uniqName is required");
8
9
  }
9
- // if this function is hit more than 10 times in a row in 2 seconds with the same uniqName then throw an error
10
- if (keyCount[uniqName + "_timeout"]) {
11
- clearTimeout(keyCount[uniqName + "_timeout"]);
12
- }
10
+ // Initialize the count if it doesn't exist
13
11
  keyCount[uniqName] = keyCount[uniqName] || 0;
14
12
  keyCount[uniqName]++;
15
13
 
16
- keyCount[uniqName + "_timeout"] = setTimeout(() => {
17
- keyCount[uniqName] = 0;
18
- }, 2000);
14
+ // Only set the timeout if it doesn't exist already to ensure it runs exactly once every 2 seconds
15
+ if (!keyCount[uniqName + "_timeout"]) {
16
+ keyCount[uniqName + "_timeout"] = setTimeout(() => {
17
+ keyCount[uniqName] = 0;
18
+ keyCount[uniqName + "_timeout"] = null;
19
+ }, 2000);
20
+ }
19
21
 
20
22
  if (keyCount[uniqName] > 20) {
21
23
  keyCount[uniqName] = 0;
24
+ // Also clear the timeout when throwing an error
25
+ if (keyCount[uniqName + "_timeout"]) {
26
+ clearTimeout(keyCount[uniqName + "_timeout"]);
27
+ keyCount[uniqName + "_timeout"] = null;
28
+ }
22
29
  throw new Error(`isBeingCalledExcessively: ${uniqName}`);
23
30
  }
24
31
  };