@azrico/reactgrid 1.2.5 → 1.2.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.
@@ -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,6 +70,9 @@ 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
 
@@ -123,21 +130,7 @@ type DataGridWrapperProps = ModifyFields<
123
130
  }
124
131
  >;
125
132
  /* -------------------------------------------------------------------------- */
126
- // const defaultfilterTypes: FilterTypes = {
127
- // string: {
128
- // type: 'string',
129
- // emptyValue: '',
130
- // operators: [
131
- // {
132
- // name: 'contains',
133
- // fn: ({ value, filterValue, data }) => {
134
- // console.log('fn');
135
- // return !filterValue ? true : value.indexOf(filterValue) != -1;
136
- // },
137
- // },
138
- // ],
139
- // },
140
- // };
133
+
141
134
  const defaultOptions: GridOptions = {
142
135
  //filterTypes: defaultfilterTypes,
143
136
  remoteFilter: false,
@@ -155,11 +148,7 @@ const forcedOptions: GridOptions = {
155
148
  idProperty: '__table_id',
156
149
  nodesProperty: '__children',
157
150
  };
158
- const defaultColumnOptions: ColumnDefinition = {
159
- draggable: false,
160
- lockable: false,
161
- editable: false,
162
- };
151
+
163
152
  const dynamic_option_names = ['selected', 'loading', 'limit', 'skip'];
164
153
  /* -------------------------------------------------------------------------- */
165
154
  export function AzGrid(props: AzGridProps) {
@@ -187,47 +176,12 @@ export function AzGrid(props: AzGridProps) {
187
176
 
188
177
  const dataSource = React.useCallback(
189
178
  async (dt) => {
190
- let result_data: any = undefined;
191
-
192
- let isUsingCache = false;
193
-
194
- const cacheInfo = { ds: props.dataSource, skip: dt.skip, limit: dt.limit };
195
- //check if we can used cached data
196
- //if the datasource is changed since last render, we should invalidate cache
197
- if (!validateCache(last_cache_info.current, cacheInfo, props.looseCacheCheck)) {
198
- cached_data.current = undefined;
199
- last_cache_info.current = cacheInfo;
200
- }
201
-
202
- if (cached_data.current) {
203
- //cache is valid, use the cache
204
- isUsingCache = true;
205
- result_data = cached_data.current;
206
- } else {
207
- //cache is invalid, use the datasource again
208
-
209
- isUsingCache = false;
210
- if (typeof props.dataSource === 'function') {
211
- result_data = await props.dataSource(dt);
212
- } else result_data = props.dataSource;
213
- }
214
-
215
- //making sure the datasource is a valid object :
216
- if (!result_data) result_data = [];
217
- if (Array.isArray(result_data) || typeof result_data !== 'object')
218
- result_data = { data: result_data };
219
-
220
- if (!Array.isArray(result_data.data)) result_data.data = [result_data.data];
221
-
222
- //no need to fix parent/child when using cache (it should be already fixed)
223
- if (!isUsingCache && props.allowChildRows)
224
- result_data.data = fix_parent_child_relations(result_data.data);
225
-
226
- if (!result_data.count) result_data.count = (result_data.data as Array<any>).length;
227
-
228
- //update cache
229
- cached_data.current = result_data;
230
- 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
+ });
231
185
  },
232
186
  [props.dataSource]
233
187
  );
@@ -356,26 +310,88 @@ function DataGridEventsWrapper(props: DataGridWrapperProps) {
356
310
  return { ...props.static_gridOptions, ...events };
357
311
  }, [props.static_gridOptions, onRowClick]);
358
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
+
359
379
  return (
360
380
  <DataGridSizeWrapper {...props} static_gridOptions={static_gridOptions}>
361
- <ContextMenu
362
- menuAnchorEl={menuAnchorEl}
363
- set_menuAnchorEl={update_menuAnchorEl}
364
- menuRow={menuRow}
365
- menu_items={props.contextMenuItems as any}
366
- />
367
381
  {props.children}
368
382
  </DataGridSizeWrapper>
369
383
  );
370
384
  }
385
+
371
386
  function DataGridSizeWrapper(props: DataGridWrapperProps) {
372
- // console.log(props);
373
387
  if (props.delayedSize) {
374
388
  return <DataGridDelayedSize {...props} />;
375
389
  } else {
376
390
  return <DataGridFlexSize {...props} />;
377
391
  }
378
392
  }
393
+
394
+ /* -------------------------------------------------------------------------- */
379
395
  function DataGridDelayedSize(props: DataGridWrapperProps) {
380
396
  const { ref, height, width } = useComponentSize();
381
397
  return (
@@ -419,229 +435,5 @@ function DataGridFlexSize(props: DataGridWrapperProps) {
419
435
  /* -------------------------------------------------------------------------- */
420
436
  /* -------------------------------------------------------------------------- */
421
437
 
422
- /**
423
- * merges together all different props for columns
424
- * to build a single final column data array
425
- * @param props
426
- * @returns
427
- */
428
- function ApplyColumnData(props: any): ColumnDefinition[] {
429
- const final_columns: MakeWriteable<LooseColumnDefinition>[] = [];
430
- let mcols = props.columns || [];
431
- let mcolExts = props.columnExtensions || [];
432
- let rightColumns = props.rightColumns || [];
433
- let leftColumns = props.leftColumns || [];
434
- let editableColumns = props.editableColumns || [];
435
- let customColumns = props.customColumns || [];
436
-
437
- if (!Array.isArray(mcols)) return [];
438
- /* ------------------------------- fix columns ------------------------------ */
439
-
440
- mcols
441
- .map((r) => {
442
- if (r == null) return null;
443
- if (typeof r === 'string') return { field: r, header: r };
444
- if (typeof r === 'object') {
445
- let final_cl: MakeWriteable<ColumnDefinition> = {
446
- name: get_col_name(r),
447
- header: get_col_header(r),
448
- width: r.width || undefined,
449
- };
450
- final_cl = {
451
- ...defaultColumnOptions,
452
- ...r,
453
- ...final_cl,
454
- };
455
- return final_cl;
456
- }
457
- return null;
458
- })
459
- .forEach((r) => {
460
- if (r != null) final_columns.push(r);
461
- });
462
-
463
- /* ---------------------------- apply extensions ---------------------------- */
464
- if (mcolExts && Array.isArray(mcolExts))
465
- for (let index = 0; index < mcolExts.length; index++) {
466
- const ext = mcolExts[index];
467
- const ext_cl = get_col_name(ext);
468
- if (!ext_cl) {
469
- console.warn('ColumnExtension must have a name');
470
- continue;
471
- }
472
- const mcol = final_columns.find((s) => get_col_name(s) === ext_cl);
473
- if (mcol) {
474
- for (const key in ext) {
475
- if (!mcol[key] && key != 'name') mcol[key] = ext[key];
476
- }
477
- }
478
- // if (ext.widthGrow) mcol.widthGrow = ext.widthGrow;
479
- }
480
-
481
- /* ------------------------------- frozen cols ------------------------------ */
482
- if (Array.isArray(leftColumns)) {
483
- for (let index = 0; index < leftColumns.length; index++) {
484
- const r = get_col_name(leftColumns[index]);
485
- const mcol = final_columns.find((s) => get_col_name(s) === r);
486
- if (mcol) {
487
- mcol.locked = 'start';
488
- }
489
- }
490
- }
491
- if (Array.isArray(rightColumns)) {
492
- for (let index = 0; index < rightColumns.length; index++) {
493
- const r = get_col_name(rightColumns[index]);
494
- const mcol = final_columns.find((s) => get_col_name(s) === r);
495
- if (mcol) {
496
- mcol.locked = 'end';
497
- }
498
- }
499
- }
500
- /* -------------------------------- ediatable ------------------------------- */
501
- if (Array.isArray(editableColumns)) {
502
- for (let index = 0; index < editableColumns.length; index++) {
503
- const r = get_col_name(editableColumns[index]);
504
- const mcol = final_columns.find((s) => get_col_name(s) === r);
505
- if (mcol) {
506
- mcol.editable = true;
507
- }
508
- }
509
- }
510
- for (let index = 0; index < final_columns.length; index++) {
511
- const col = final_columns[index];
512
- if (col.type) {
513
- switch (col.type) {
514
- case 'combo':
515
- case 'select':
516
- //@ts-ignore
517
- col.editor = SelectEditor;
518
- break;
519
- case 'number':
520
- case 'numberic':
521
- //@ts-ignore
522
- col.editor = NumericEditor;
523
- break;
524
- case 'truefalse':
525
- case 'bool':
526
- //@ts-ignore
527
- col.editor = BoolEditor;
528
- break;
529
- }
530
- if (col.editable != false) col.editable = true;
531
- delete col.type;
532
- }
533
- //@ts-ignore
534
- if (!col.editorProps) col.editorProps = {};
535
- if (col.items) {
536
- //@ts-ignore
537
- if (!col.editorProps.idProperty) col.editorProps.idProperty = 'id';
538
- //@ts-ignore
539
- if (!col.editorProps.collapseOnSelect) col.editorProps.collapseOnSelect = true;
540
- //@ts-ignore
541
- col.editorProps.dataSource = to_datasource(col.items, col.editorProps.idProperty);
542
-
543
- delete col.items;
544
- }
545
- }
546
-
547
- /* -------------------------------------------------------------------------- */
548
- if (Array.isArray(customColumns)) {
549
- for (let index = 0; index < customColumns.length; index++) {
550
- const r = customColumns[index];
551
- const rn = get_col_name(r);
552
- const mcol = final_columns.find((s) => get_col_name(s) === rn);
553
- if (mcol) {
554
- //@ts-ignore
555
- mcol.render = r.render;
556
- }
557
- }
558
- }
559
-
560
- /* ------------------------------ apply renames ----------------------------- */
561
- for (let index = 0; index < final_columns.length; index++) {
562
- const col = final_columns[index];
563
- if (!col.name) {
564
- col.name = get_col_name(col);
565
- delete col.field;
566
- delete col.key;
567
- delete col.columnName;
568
-
569
- if (col.flex && !col.defaultFlex) col.defaultFlex = col.flex;
570
- }
571
- }
572
- /* -------------------------------------------------------------------------- */
573
- //console.log(final_columns);
574
- return final_columns;
575
- }
576
-
577
- function to_datasource(arr: any[], idProperty: string, valueAsID = true) {
578
- const res: any[] = [];
579
- let index = 0;
580
- if (Array.isArray(arr)) {
581
- arr.map((s: any) => {
582
- let elem = {};
583
- if (valueAsID) elem[idProperty] = String(s).toLowerCase();
584
- else elem[idProperty] = '_cid_' + index;
585
- if (typeof s === 'object') elem = { ...elem, ...s };
586
- else elem['label'] = s;
587
- res.push(elem);
588
- index++;
589
- });
590
- }
591
-
592
- return res;
593
- }
594
- /**
595
- * Gets name of a column from its column object
596
- * @param obj
597
- * @returns
598
- */
599
- export function get_col_name(obj: any): string {
600
- if (!obj) return '';
601
- if (typeof obj == 'string') return obj;
602
- if (typeof obj != 'object') return '';
603
- return obj.name || obj.field || obj.key || obj.columnName || '';
604
- }
605
- /**
606
- * Gets header of a column
607
- * @param obj
608
- * @returns
609
- */
610
- export function get_col_header(obj: any): string {
611
- if (!obj) return '';
612
- if (typeof obj == 'string') return obj;
613
- if (typeof obj != 'object') return '';
614
- return obj.header || obj.title || get_col_name(obj);
615
- }
616
- /**
617
- * Gets name of a column from its column object
618
- * @param obj
619
- * @returns
620
- */
621
- function get_row_id(obj: any): any {
622
- if (!obj) return '-1';
623
- if (typeof obj == 'string') return obj;
624
- if (typeof obj != 'object') return '-1';
625
- return obj.__table_id || obj.id || '-1';
626
- }
627
-
628
- /**
629
- * Gets default activation key for grid plugin
630
- * @returns
631
- */
632
- function get_default_key() {
633
- return 'ExpiryDate=2999-01-01,Z=1040577552';
634
- }
635
-
636
- //check if two cache objects are the same
637
- function validateCache(current: any, old: any, looseCheck = false) {
638
- if (!old || !object_equals(current, old)) return false;
639
-
640
- if (looseCheck) return true;
641
-
642
- if (current.ds != old.ds) return false;
643
- return true;
644
- }
645
-
646
438
  /* -------------------------------------------------------------------------- */
647
439
  export default AzGrid;
File without changes