@azrico/reactgrid 1.2.4 → 1.2.6

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.
@@ -4,6 +4,14 @@ import '@inovua/reactdatagrid-enterprise/theme/amber-dark.css';
4
4
  import '../themes/base_styles.css';
5
5
  import '../themes/grid.css';
6
6
 
7
+ import {
8
+ ApplyColumnData,
9
+ ApplyDataSource,
10
+ ModifyFields,
11
+ get_default_key,
12
+ get_row_id,
13
+ validateCache,
14
+ } from '../func/func_grid';
7
15
  import { ContextMenu, ConvertableToMenuItem } from '@azrico/controls';
8
16
  import React, { useCallback, useState } from 'react';
9
17
  import {
@@ -12,26 +20,21 @@ import {
12
20
  TypeDataSource,
13
21
  TypeEditInfo,
14
22
  TypeFilterTypes,
23
+ TypeFilterValue,
15
24
  TypeRowDetailsInfo,
16
25
  TypeRowProps,
17
26
  TypeRowSelection,
18
27
  } from '@inovua/reactdatagrid-community/types';
19
- import { fix_parent_child_relations, func_selection } from '../func/helpers';
28
+ import { fix_parent_child_relations, func_selection } from '../func/func_child';
20
29
 
21
- import BoolEditor from '@inovua/reactdatagrid-community/BoolEditor';
22
- import NumericEditor from '@inovua/reactdatagrid-community/NumericEditor';
23
30
  import ReactDataGrid from '@inovua/reactdatagrid-enterprise';
24
- import SelectEditor from '@inovua/reactdatagrid-community/SelectEditor';
25
31
  import { TypeOnSelectionChangeArg } from '@inovua/reactdatagrid-community/types/TypeDataGridProps';
26
32
  import clsx from 'clsx';
27
33
  import { object_equals } from '@azrico/object';
28
34
  import { useComponentSize } from 'react-use-size';
29
35
 
30
36
  /* -------------------------------------------------------------------------- */
31
- type ModifyFields<T, R> = Omit<T, keyof R> & R;
32
- type MakeWriteable<Type> = {
33
- -readonly [Key in keyof Type]: Type[Key];
34
- };
37
+
35
38
  /* -------------------------------------------------------------------------- */
36
39
  export type ColumnDefinition = TypeColumn;
37
40
  export type CellDefinition = any;
@@ -40,6 +43,7 @@ export type RowProps = TypeRowProps;
40
43
  export type RowSelectionValue = TypeRowSelection;
41
44
  export type DataRowDefinition = any;
42
45
  export type FilterTypes = TypeFilterTypes;
46
+ export type FilterValues = TypeFilterValue;
43
47
  export type DataSourceDefinition = TypeDataSource;
44
48
  export type OnSelectionChangeFunc = (config: TypeOnSelectionChangeArg) => void;
45
49
  export type RowDetailsFunc = (rowDetailsInfo: TypeRowDetailsInfo) => React.ReactNode;
@@ -66,9 +70,13 @@ type GridOptions = Partial<TypeDataGridProps>;
66
70
  /* -------------------------------------------------------------------------- */
67
71
  export type AzGridProps = {
68
72
  dataSource?: any[] | ((args: any) => any[] | Promise<any[] | any>);
73
+ details_dataSource?: any[] | ((args: any) => any[] | Promise<any[] | any>);
74
+ details_columns?: LooseColumnDefinition[];
75
+ details_filter?: FilterValues;
69
76
 
70
77
  licenseKey?: string;
71
78
 
79
+ gridRef?: any;
72
80
  gridOptions?: GridOptions;
73
81
 
74
82
  columns?: LooseColumnDefinition[];
@@ -122,21 +130,7 @@ type DataGridWrapperProps = ModifyFields<
122
130
  }
123
131
  >;
124
132
  /* -------------------------------------------------------------------------- */
125
- // const defaultfilterTypes: FilterTypes = {
126
- // string: {
127
- // type: 'string',
128
- // emptyValue: '',
129
- // operators: [
130
- // {
131
- // name: 'contains',
132
- // fn: ({ value, filterValue, data }) => {
133
- // console.log('fn');
134
- // return !filterValue ? true : value.indexOf(filterValue) != -1;
135
- // },
136
- // },
137
- // ],
138
- // },
139
- // };
133
+
140
134
  const defaultOptions: GridOptions = {
141
135
  //filterTypes: defaultfilterTypes,
142
136
  remoteFilter: false,
@@ -154,14 +148,12 @@ const forcedOptions: GridOptions = {
154
148
  idProperty: '__table_id',
155
149
  nodesProperty: '__children',
156
150
  };
157
- const defaultColumnOptions: ColumnDefinition = {
158
- draggable: false,
159
- lockable: false,
160
- editable: false,
161
- };
151
+
162
152
  const dynamic_option_names = ['selected', 'loading', 'limit', 'skip'];
163
153
  /* -------------------------------------------------------------------------- */
164
154
  export function AzGrid(props: AzGridProps) {
155
+ const gridRefBackup = React.useRef<any>(null);
156
+ const gridRef = props.gridRef || gridRefBackup;
165
157
  /* -------------------------------------------------------------------------- */
166
158
  /* Columns */
167
159
  /* -------------------------------------------------------------------------- */
@@ -184,47 +176,12 @@ export function AzGrid(props: AzGridProps) {
184
176
 
185
177
  const dataSource = React.useCallback(
186
178
  async (dt) => {
187
- let result_data: any = undefined;
188
-
189
- let isUsingCache = false;
190
-
191
- const cacheInfo = { ds: props.dataSource, skip: dt.skip, limit: dt.limit };
192
- //check if we can used cached data
193
- //if the datasource is changed since last render, we should invalidate cache
194
- if (!validateCache(last_cache_info.current, cacheInfo, props.looseCacheCheck)) {
195
- cached_data.current = undefined;
196
- last_cache_info.current = cacheInfo;
197
- }
198
-
199
- if (cached_data.current) {
200
- //cache is valid, use the cache
201
- isUsingCache = true;
202
- result_data = cached_data.current;
203
- } else {
204
- //cache is invalid, use the datasource again
205
-
206
- isUsingCache = false;
207
- if (typeof props.dataSource === 'function') {
208
- result_data = await props.dataSource(dt);
209
- } else result_data = props.dataSource;
210
- }
211
-
212
- //making sure the datasource is a valid object :
213
- if (!result_data) result_data = [];
214
- if (Array.isArray(result_data) || typeof result_data !== 'object')
215
- result_data = { data: result_data };
216
-
217
- if (!Array.isArray(result_data.data)) result_data.data = [result_data.data];
218
-
219
- //no need to fix parent/child when using cache (it should be already fixed)
220
- if (!isUsingCache && props.allowChildRows)
221
- result_data.data = fix_parent_child_relations(result_data.data);
222
-
223
- if (!result_data.count) result_data.count = (result_data.data as Array<any>).length;
224
-
225
- //update cache
226
- cached_data.current = result_data;
227
- return result_data;
179
+ return await ApplyDataSource(props.dataSource, {
180
+ skip: dt.skip,
181
+ limit: dt.limit,
182
+ cached_data: cached_data,
183
+ last_cache_info: last_cache_info,
184
+ });
228
185
  },
229
186
  [props.dataSource]
230
187
  );
@@ -272,6 +229,7 @@ export function AzGrid(props: AzGridProps) {
272
229
  return (
273
230
  <DataGridEventsWrapper
274
231
  {...props}
232
+ gridRef={gridRef}
275
233
  static_gridOptions={static_gridOptions}
276
234
  dynamic_gridOptions={dynamic_gridOptions}
277
235
  columns={cached_columns}
@@ -352,28 +310,89 @@ function DataGridEventsWrapper(props: DataGridWrapperProps) {
352
310
  return { ...props.static_gridOptions, ...events };
353
311
  }, [props.static_gridOptions, onRowClick]);
354
312
 
313
+ const contextMenu = (
314
+ <ContextMenu
315
+ menuAnchorEl={menuAnchorEl}
316
+ set_menuAnchorEl={update_menuAnchorEl}
317
+ menuRow={menuRow}
318
+ menu_items={props.contextMenuItems as any}
319
+ />
320
+ );
321
+
322
+ if (props.details_dataSource) {
323
+ return (
324
+ <DataGridDetailsWrapper {...props} static_gridOptions={static_gridOptions}>
325
+ {contextMenu}
326
+ {props.children}
327
+ </DataGridDetailsWrapper>
328
+ );
329
+ } else {
330
+ return (
331
+ <DataGridSizeWrapper {...props} static_gridOptions={static_gridOptions}>
332
+ {contextMenu}
333
+ {props.children}
334
+ </DataGridSizeWrapper>
335
+ );
336
+ }
337
+ }
338
+
339
+ function DataGridDetailsWrapper(props: DataGridWrapperProps) {
340
+ const cached_details_columns = React.useMemo(() => {
341
+ return ApplyColumnData(props.details_columns);
342
+ }, [props.details_columns]);
343
+
344
+ const cached_data = React.useRef<any>();
345
+ const last_cache_info = React.useRef<any>();
346
+
347
+ const dataSource = React.useCallback(
348
+ async (dt) => {
349
+ const res = await ApplyDataSource(props.details_dataSource, {
350
+ skip: dt.skip,
351
+ limit: dt.limit,
352
+ cached_data: cached_data,
353
+ last_cache_info: last_cache_info,
354
+ });
355
+ console.log('ds', res);
356
+ return res;
357
+ },
358
+ [props.dataSource]
359
+ );
360
+ const renderDetailsGrid = ({ data }) => {
361
+ return (
362
+ <ReactDataGrid
363
+ defaultFilterValue={props.details_filter}
364
+ dataSource={dataSource}
365
+ columns={cached_details_columns}
366
+ />
367
+ );
368
+ };
369
+
370
+ /**
371
+ * Merge details into grid
372
+ */
373
+ const static_gridOptions = React.useMemo<GridOptions>(() => {
374
+ const finalresult = props.static_gridOptions || {};
375
+ finalresult['renderDetailsGrid'] = renderDetailsGrid;
376
+ return finalresult;
377
+ }, [props.static_gridOptions]);
378
+
355
379
  return (
356
380
  <DataGridSizeWrapper {...props} static_gridOptions={static_gridOptions}>
357
- <ContextMenu
358
- menuAnchorEl={menuAnchorEl}
359
- set_menuAnchorEl={update_menuAnchorEl}
360
- menuRow={menuRow}
361
- menu_items={props.contextMenuItems as any}
362
- />
363
381
  {props.children}
364
382
  </DataGridSizeWrapper>
365
383
  );
366
384
  }
385
+
367
386
  function DataGridSizeWrapper(props: DataGridWrapperProps) {
368
- // console.log(props);
369
387
  if (props.delayedSize) {
370
388
  return <DataGridDelayedSize {...props} />;
371
389
  } else {
372
390
  return <DataGridFlexSize {...props} />;
373
391
  }
374
392
  }
393
+
394
+ /* -------------------------------------------------------------------------- */
375
395
  function DataGridDelayedSize(props: DataGridWrapperProps) {
376
- const gridRef = React.useRef<any>(null);
377
396
  const { ref, height, width } = useComponentSize();
378
397
  return (
379
398
  <div
@@ -383,7 +402,7 @@ function DataGridDelayedSize(props: DataGridWrapperProps) {
383
402
  <ReactDataGrid
384
403
  {...props.static_gridOptions}
385
404
  {...props.dynamic_gridOptions}
386
- handle={(ref) => (gridRef.current = ref ? ref.current : null)}
405
+ handle={(ref) => (props.gridRef.current = ref ? ref.current : null)}
387
406
  className={'azgrid-delayedresize'}
388
407
  style={{
389
408
  height: height,
@@ -397,13 +416,12 @@ function DataGridDelayedSize(props: DataGridWrapperProps) {
397
416
  );
398
417
  }
399
418
  function DataGridFlexSize(props: DataGridWrapperProps) {
400
- const gridRef = React.useRef<any>(null);
401
419
  return (
402
420
  <div className={clsx(props.className, 'azgrid-nooverflow', 'azgrid-filler')}>
403
421
  <ReactDataGrid
404
422
  {...props.static_gridOptions}
405
423
  {...props.dynamic_gridOptions}
406
- handle={(ref) => (gridRef.current = ref ? ref.current : null)}
424
+ handle={(ref) => (props.gridRef.current = ref ? ref.current : null)}
407
425
  className={'azgrid-filler'}
408
426
  columns={props.columns}
409
427
  dataSource={props.dataSource}
@@ -417,229 +435,5 @@ function DataGridFlexSize(props: DataGridWrapperProps) {
417
435
  /* -------------------------------------------------------------------------- */
418
436
  /* -------------------------------------------------------------------------- */
419
437
 
420
- /**
421
- * merges together all different props for columns
422
- * to build a single final column data array
423
- * @param props
424
- * @returns
425
- */
426
- function ApplyColumnData(props: any): ColumnDefinition[] {
427
- const final_columns: MakeWriteable<LooseColumnDefinition>[] = [];
428
- let mcols = props.columns || [];
429
- let mcolExts = props.columnExtensions || [];
430
- let rightColumns = props.rightColumns || [];
431
- let leftColumns = props.leftColumns || [];
432
- let editableColumns = props.editableColumns || [];
433
- let customColumns = props.customColumns || [];
434
-
435
- if (!Array.isArray(mcols)) return [];
436
- /* ------------------------------- fix columns ------------------------------ */
437
-
438
- mcols
439
- .map((r) => {
440
- if (r == null) return null;
441
- if (typeof r === 'string') return { field: r, header: r };
442
- if (typeof r === 'object') {
443
- let final_cl: MakeWriteable<ColumnDefinition> = {
444
- name: get_col_name(r),
445
- header: get_col_header(r),
446
- width: r.width || undefined,
447
- };
448
- final_cl = {
449
- ...defaultColumnOptions,
450
- ...r,
451
- ...final_cl,
452
- };
453
- return final_cl;
454
- }
455
- return null;
456
- })
457
- .forEach((r) => {
458
- if (r != null) final_columns.push(r);
459
- });
460
-
461
- /* ---------------------------- apply extensions ---------------------------- */
462
- if (mcolExts && Array.isArray(mcolExts))
463
- for (let index = 0; index < mcolExts.length; index++) {
464
- const ext = mcolExts[index];
465
- const ext_cl = get_col_name(ext);
466
- if (!ext_cl) {
467
- console.warn('ColumnExtension must have a name');
468
- continue;
469
- }
470
- const mcol = final_columns.find((s) => get_col_name(s) === ext_cl);
471
- if (mcol) {
472
- for (const key in ext) {
473
- if (!mcol[key] && key != 'name') mcol[key] = ext[key];
474
- }
475
- }
476
- // if (ext.widthGrow) mcol.widthGrow = ext.widthGrow;
477
- }
478
-
479
- /* ------------------------------- frozen cols ------------------------------ */
480
- if (Array.isArray(leftColumns)) {
481
- for (let index = 0; index < leftColumns.length; index++) {
482
- const r = get_col_name(leftColumns[index]);
483
- const mcol = final_columns.find((s) => get_col_name(s) === r);
484
- if (mcol) {
485
- mcol.locked = 'start';
486
- }
487
- }
488
- }
489
- if (Array.isArray(rightColumns)) {
490
- for (let index = 0; index < rightColumns.length; index++) {
491
- const r = get_col_name(rightColumns[index]);
492
- const mcol = final_columns.find((s) => get_col_name(s) === r);
493
- if (mcol) {
494
- mcol.locked = 'end';
495
- }
496
- }
497
- }
498
- /* -------------------------------- ediatable ------------------------------- */
499
- if (Array.isArray(editableColumns)) {
500
- for (let index = 0; index < editableColumns.length; index++) {
501
- const r = get_col_name(editableColumns[index]);
502
- const mcol = final_columns.find((s) => get_col_name(s) === r);
503
- if (mcol) {
504
- mcol.editable = true;
505
- }
506
- }
507
- }
508
- for (let index = 0; index < final_columns.length; index++) {
509
- const col = final_columns[index];
510
- if (col.type) {
511
- switch (col.type) {
512
- case 'combo':
513
- case 'select':
514
- //@ts-ignore
515
- col.editor = SelectEditor;
516
- break;
517
- case 'number':
518
- case 'numberic':
519
- //@ts-ignore
520
- col.editor = NumericEditor;
521
- break;
522
- case 'truefalse':
523
- case 'bool':
524
- //@ts-ignore
525
- col.editor = BoolEditor;
526
- break;
527
- }
528
- if (col.editable != false) col.editable = true;
529
- delete col.type;
530
- }
531
- //@ts-ignore
532
- if (!col.editorProps) col.editorProps = {};
533
- if (col.items) {
534
- //@ts-ignore
535
- if (!col.editorProps.idProperty) col.editorProps.idProperty = 'id';
536
- //@ts-ignore
537
- if (!col.editorProps.collapseOnSelect) col.editorProps.collapseOnSelect = true;
538
- //@ts-ignore
539
- col.editorProps.dataSource = to_datasource(col.items, col.editorProps.idProperty);
540
-
541
- delete col.items;
542
- }
543
- }
544
-
545
- /* -------------------------------------------------------------------------- */
546
- if (Array.isArray(customColumns)) {
547
- for (let index = 0; index < customColumns.length; index++) {
548
- const r = customColumns[index];
549
- const rn = get_col_name(r);
550
- const mcol = final_columns.find((s) => get_col_name(s) === rn);
551
- if (mcol) {
552
- //@ts-ignore
553
- mcol.render = r.render;
554
- }
555
- }
556
- }
557
-
558
- /* ------------------------------ apply renames ----------------------------- */
559
- for (let index = 0; index < final_columns.length; index++) {
560
- const col = final_columns[index];
561
- if (!col.name) {
562
- col.name = get_col_name(col);
563
- delete col.field;
564
- delete col.key;
565
- delete col.columnName;
566
-
567
- if (col.flex && !col.defaultFlex) col.defaultFlex = col.flex;
568
- }
569
- }
570
- /* -------------------------------------------------------------------------- */
571
- //console.log(final_columns);
572
- return final_columns;
573
- }
574
-
575
- function to_datasource(arr: any[], idProperty: string, valueAsID = true) {
576
- const res: any[] = [];
577
- let index = 0;
578
- if (Array.isArray(arr)) {
579
- arr.map((s: any) => {
580
- let elem = {};
581
- if (valueAsID) elem[idProperty] = String(s).toLowerCase();
582
- else elem[idProperty] = '_cid_' + index;
583
- if (typeof s === 'object') elem = { ...elem, ...s };
584
- else elem['label'] = s;
585
- res.push(elem);
586
- index++;
587
- });
588
- }
589
-
590
- return res;
591
- }
592
- /**
593
- * Gets name of a column from its column object
594
- * @param obj
595
- * @returns
596
- */
597
- export function get_col_name(obj: any): string {
598
- if (!obj) return '';
599
- if (typeof obj == 'string') return obj;
600
- if (typeof obj != 'object') return '';
601
- return obj.name || obj.field || obj.key || obj.columnName || '';
602
- }
603
- /**
604
- * Gets header of a column
605
- * @param obj
606
- * @returns
607
- */
608
- export function get_col_header(obj: any): string {
609
- if (!obj) return '';
610
- if (typeof obj == 'string') return obj;
611
- if (typeof obj != 'object') return '';
612
- return obj.header || obj.title || get_col_name(obj);
613
- }
614
- /**
615
- * Gets name of a column from its column object
616
- * @param obj
617
- * @returns
618
- */
619
- function get_row_id(obj: any): any {
620
- if (!obj) return '-1';
621
- if (typeof obj == 'string') return obj;
622
- if (typeof obj != 'object') return '-1';
623
- return obj.__table_id || obj.id || '-1';
624
- }
625
-
626
- /**
627
- * Gets default activation key for grid plugin
628
- * @returns
629
- */
630
- function get_default_key() {
631
- return 'ExpiryDate=2999-01-01,Z=1040577552';
632
- }
633
-
634
- //check if two cache objects are the same
635
- function validateCache(current: any, old: any, looseCheck = false) {
636
- if (!old || !object_equals(current, old)) return false;
637
-
638
- if (looseCheck) return true;
639
-
640
- if (current.ds != old.ds) return false;
641
- return true;
642
- }
643
-
644
438
  /* -------------------------------------------------------------------------- */
645
439
  export default AzGrid;
File without changes