@onehat/ui 0.3.313 → 0.3.315

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/ui",
3
- "version": "0.3.313",
3
+ "version": "0.3.315",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -48,6 +48,8 @@ import getIconButtonFromConfig from '../../Functions/getIconButtonFromConfig.js'
48
48
  import nbToRgb from '../../Functions/nbToRgb.js';
49
49
  import testProps from '../../Functions/testProps.js';
50
50
  import Loading from '../Messages/Loading.js';
51
+ import isSerializable from '../../Functions/isSerializable.js';
52
+ import inArray from '../../Functions/inArray.js';
51
53
  import ReloadPageButton from '../Buttons/ReloadPageButton.js';
52
54
  import GridHeaderRow from './GridHeaderRow.js';
53
55
  import GridRow, { DragSourceDropTargetGridRow, DragSourceGridRow, DropTargetGridRow } from './GridRow.js';
@@ -191,17 +193,9 @@ function GridComponent(props) {
191
193
  styles = UiGlobals.styles,
192
194
  id = props.id || props.self?.path,
193
195
  localColumnsConfigKey = id && id + '-localColumnsConfig',
194
- [hasFunctionColumn, setHasActionColumns] = useState((() => {
195
- // We can't save localColumnsConfig when there's a function column, so we need to determine if this is the case (only run once per Grid)
196
- let ret = false;
197
- _.each(columnsConfig, (column) => {
198
- if (column.renderer || _.isFunction(column)) {
199
- ret = true;
200
- return false;
201
- }
202
- });
203
- return ret;
204
- })()),
196
+ [hasUnserializableColumns] = useState(() => {
197
+ return !isSerializable(columnsConfig); // (runs only once, when the component is first created)
198
+ }),
205
199
  forceUpdate = useForceUpdate(),
206
200
  containerRef = useRef(),
207
201
  gridRef = useRef(),
@@ -224,8 +218,23 @@ function GridComponent(props) {
224
218
  forceUpdate();
225
219
  },
226
220
  setLocalColumnsConfig = (config) => {
227
- if (localColumnsConfigKey && !hasFunctionColumn) {
228
- setSaved(localColumnsConfigKey, config);
221
+ if (localColumnsConfigKey) {
222
+ const localConfig = _.clone(config); // clone it so we don't alter the original
223
+ if (hasUnserializableColumns) {
224
+ // just save the data needed to later reconstruct the columns
225
+ const usedIds = [];
226
+ _.each(localConfig, (column, ix) => {
227
+ if (!column.id || inArray(column.id, usedIds)) {
228
+ throw Error('When using unserializable columns, each column must have a unique id. First invalid column: ' + JSON.stringify(column));
229
+ }
230
+ usedIds.push(column.id);
231
+ localConfig[ix] = {
232
+ id: column.id,
233
+ isHidden: !!column.isHidden,
234
+ };
235
+ });
236
+ }
237
+ setSaved(localColumnsConfigKey, localConfig);
229
238
  }
230
239
 
231
240
  setLocalColumnsConfigRaw(config);
@@ -791,19 +800,18 @@ function GridComponent(props) {
791
800
 
792
801
  // second call -- do other necessary setup
793
802
 
794
- // calculate localColumnsConfig
795
- let localColumnsConfig = [];
796
- let savedLocalColumnsConfig;
797
- if (localColumnsConfigKey && !hasFunctionColumn && !UiGlobals.disableSavedColumnsConfig) {
803
+
804
+ let localColumnsConfig = [],
805
+ savedLocalColumnsConfig,
806
+ calculateLocalColumnsConfig = false;
807
+ if (localColumnsConfigKey && !UiGlobals.disableSavedColumnsConfig) {
798
808
  savedLocalColumnsConfig = await getSaved(localColumnsConfigKey);
799
809
  }
800
- if (savedLocalColumnsConfig) {
801
- // use saved
802
- localColumnsConfig = savedLocalColumnsConfig;
803
- } else {
804
- // calculate new
805
810
 
806
- // convert json config into actual elements
811
+ if (!savedLocalColumnsConfig || hasUnserializableColumns) {
812
+ calculateLocalColumnsConfig = true;
813
+ }
814
+ if (calculateLocalColumnsConfig) {
807
815
  if (_.isEmpty(columnsConfig)) {
808
816
  if (Repository) {
809
817
  // create a column for the displayProperty
@@ -821,10 +829,9 @@ function GridComponent(props) {
821
829
  localColumnsConfig.push(columnConfig);
822
830
  return;
823
831
  }
824
-
832
+
825
833
  const
826
834
  defaults = {
827
- columnId: uuid(),
828
835
  isEditable: false,
829
836
  reorderable: true,
830
837
  resizable: true,
@@ -841,11 +848,29 @@ function GridComponent(props) {
841
848
  // Both are set. Width overrules flex.
842
849
  delete config.flex;
843
850
  }
844
-
851
+
845
852
  localColumnsConfig.push(config);
846
853
  });
847
854
  }
848
855
  }
856
+
857
+ if (savedLocalColumnsConfig) {
858
+ if (!hasUnserializableColumns) {
859
+ // just use the saved config without any further processing
860
+ localColumnsConfig = savedLocalColumnsConfig;
861
+
862
+ } else {
863
+ // Conform the calculated localColumnsConfig to the saved config.
864
+ // This should allow us to continue using non-serializable configurations after a refresh
865
+ const reconstructedLocalColumnsConfig = savedLocalColumnsConfig.map((savedConfig) => { // foreach saved column, in the order it was saved...
866
+ const columnConfig = localColumnsConfig.find(localConfig => localConfig.id === savedConfig.id); // find the corresponding column in localColumnsConfig
867
+ columnConfig.isHidden = savedConfig.isHidden;
868
+ return columnConfig;
869
+ });
870
+ localColumnsConfig = reconstructedLocalColumnsConfig;
871
+ }
872
+ }
873
+
849
874
  setLocalColumnsConfig(localColumnsConfig);
850
875
 
851
876
  setIsReady(true);
@@ -294,7 +294,6 @@ export default function GridHeaderRow(props) {
294
294
  // so we can drag/drop them to control the columns.
295
295
  const headerColumns = _.map(localColumnsConfig, (config, ix, all) => {
296
296
  let {
297
- columnId,
298
297
  fieldName,
299
298
  header = _.upperFirst(fieldName),
300
299
  reorderable,
@@ -78,7 +78,6 @@ function GridRow(props) {
78
78
  if (_.isPlainObject(config)) {
79
79
  if (config.renderer) {
80
80
  const extraProps = _.omit(config, [
81
- 'columnId',
82
81
  'header',
83
82
  'fieldName',
84
83
  'type',
@@ -0,0 +1,26 @@
1
+ export default function isSerializable(value, seen = new WeakSet()) {
2
+ // Handle primitive types that are serializable or explicitly unserializable
3
+ if (value === null || typeof value === 'boolean' || typeof value === 'string' || typeof value === 'number') {
4
+ return true;
5
+ }
6
+ if (typeof value === 'undefined' || typeof value === 'function' || typeof value === 'symbol' || typeof value === 'bigint') {
7
+ return false;
8
+ }
9
+
10
+ // Handle objects (including arrays)
11
+ if (typeof value === 'object') {
12
+ // Check for circular references
13
+ if (seen.has(value)) {
14
+ return false;
15
+ }
16
+ seen.add(value);
17
+
18
+ for (const key in value) {
19
+ if (!isSerializable(value[key], seen)) {
20
+ return false;
21
+ }
22
+ }
23
+ }
24
+
25
+ return true;
26
+ }