dce-reactkit 3.2.2-beta.4 → 3.2.2-beta.41
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/dist/cjs/index.js +404 -201
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/ButtonInputGroup.d.ts +1 -0
- package/dist/cjs/types/components/Drawer.d.ts +1 -0
- package/dist/cjs/types/components/ItemPicker/NestableItemList.d.ts +1 -0
- package/dist/cjs/types/components/ItemPicker/index.d.ts +1 -0
- package/dist/cjs/types/types/LogAction.d.ts +16 -16
- package/dist/cjs/types/types/LogBuiltInMetadata.d.ts +1 -1
- package/dist/esm/index.js +405 -202
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/ButtonInputGroup.d.ts +1 -0
- package/dist/esm/types/components/Drawer.d.ts +1 -0
- package/dist/esm/types/components/ItemPicker/NestableItemList.d.ts +1 -0
- package/dist/esm/types/components/ItemPicker/index.d.ts +1 -0
- package/dist/esm/types/types/LogAction.d.ts +16 -16
- package/dist/esm/types/types/LogBuiltInMetadata.d.ts +1 -1
- package/dist/index.d.ts +20 -17
- package/package.json +1 -1
- package/src/components/ButtonInputGroup.tsx +5 -2
- package/src/components/CSVDownloadButton.tsx +1 -1
- package/src/components/Drawer.tsx +9 -1
- package/src/components/IntelliTable.tsx +95 -23
- package/src/components/ItemPicker/NestableItemList.tsx +32 -14
- package/src/components/ItemPicker/index.tsx +4 -0
- package/src/components/LogReviewer.tsx +301 -147
- package/src/components/SimpleDateChooser.tsx +20 -7
- package/src/helpers/genCSV.ts +21 -4
- package/src/helpers/genRouteHandler.ts +2 -2
- package/src/helpers/logClientEvent.tsx +6 -1
- package/src/server/initServer.ts +11 -4
- package/src/types/LogAction.ts +16 -16
- package/src/types/LogBuiltInMetadata.ts +5 -5
|
@@ -3,21 +3,21 @@
|
|
|
3
3
|
* @author Gabe Abrams
|
|
4
4
|
*/
|
|
5
5
|
declare enum LogAction {
|
|
6
|
-
Open = "
|
|
7
|
-
Close = "
|
|
8
|
-
Cancel = "
|
|
9
|
-
Expand = "
|
|
10
|
-
Collapse = "
|
|
11
|
-
View = "
|
|
12
|
-
Interrupt = "
|
|
13
|
-
Create = "
|
|
14
|
-
Edit = "
|
|
15
|
-
Delete = "
|
|
16
|
-
Add = "
|
|
17
|
-
Remove = "
|
|
18
|
-
Activate = "
|
|
19
|
-
Deactivate = "
|
|
20
|
-
Peek = "
|
|
21
|
-
Unknown = "
|
|
6
|
+
Open = "Open",
|
|
7
|
+
Close = "Close",
|
|
8
|
+
Cancel = "Cancel",
|
|
9
|
+
Expand = "Expand",
|
|
10
|
+
Collapse = "Collapse",
|
|
11
|
+
View = "View",
|
|
12
|
+
Interrupt = "Interrupt",
|
|
13
|
+
Create = "Create",
|
|
14
|
+
Edit = "Edit",
|
|
15
|
+
Delete = "Delete",
|
|
16
|
+
Add = "Add",
|
|
17
|
+
Remove = "Remove",
|
|
18
|
+
Activate = "Activate",
|
|
19
|
+
Deactivate = "Deactivate",
|
|
20
|
+
Peek = "Peek",
|
|
21
|
+
Unknown = "Unknown"
|
|
22
22
|
}
|
|
23
23
|
export default LogAction;
|
package/dist/index.d.ts
CHANGED
|
@@ -242,6 +242,7 @@ declare type Props$a = {
|
|
|
242
242
|
label: string;
|
|
243
243
|
minLabelWidth?: string;
|
|
244
244
|
children: React.ReactNode;
|
|
245
|
+
className?: string;
|
|
245
246
|
};
|
|
246
247
|
declare const ButtonInputGroup: React.FC<Props$a>;
|
|
247
248
|
|
|
@@ -274,6 +275,7 @@ declare const SimpleDateChooser: React.FC<Props$9>;
|
|
|
274
275
|
*/
|
|
275
276
|
|
|
276
277
|
declare type Props$8 = {
|
|
278
|
+
customBackgroundColor?: string;
|
|
277
279
|
children: React.ReactNode;
|
|
278
280
|
};
|
|
279
281
|
declare const Drawer: React.FC<Props$8>;
|
|
@@ -363,6 +365,7 @@ declare type Props$3 = {
|
|
|
363
365
|
* values updated
|
|
364
366
|
*/
|
|
365
367
|
onChanged: (updatedItems: PickableItem[]) => void;
|
|
368
|
+
noBottomMargin?: boolean;
|
|
366
369
|
};
|
|
367
370
|
declare const ItemPicker: React.FC<Props$3>;
|
|
368
371
|
|
|
@@ -667,22 +670,22 @@ declare type LogSourceSpecificInfo = ({
|
|
|
667
670
|
* @author Gabe Abrams
|
|
668
671
|
*/
|
|
669
672
|
declare enum LogAction {
|
|
670
|
-
Open = "
|
|
671
|
-
Close = "
|
|
672
|
-
Cancel = "
|
|
673
|
-
Expand = "
|
|
674
|
-
Collapse = "
|
|
675
|
-
View = "
|
|
676
|
-
Interrupt = "
|
|
677
|
-
Create = "
|
|
678
|
-
Edit = "
|
|
679
|
-
Delete = "
|
|
680
|
-
Add = "
|
|
681
|
-
Remove = "
|
|
682
|
-
Activate = "
|
|
683
|
-
Deactivate = "
|
|
684
|
-
Peek = "
|
|
685
|
-
Unknown = "
|
|
673
|
+
Open = "Open",
|
|
674
|
+
Close = "Close",
|
|
675
|
+
Cancel = "Cancel",
|
|
676
|
+
Expand = "Expand",
|
|
677
|
+
Collapse = "Collapse",
|
|
678
|
+
View = "View",
|
|
679
|
+
Interrupt = "Interrupt",
|
|
680
|
+
Create = "Create",
|
|
681
|
+
Edit = "Edit",
|
|
682
|
+
Delete = "Delete",
|
|
683
|
+
Add = "Add",
|
|
684
|
+
Remove = "Remove",
|
|
685
|
+
Activate = "Activate",
|
|
686
|
+
Deactivate = "Deactivate",
|
|
687
|
+
Peek = "Peek",
|
|
688
|
+
Unknown = "Unknown"
|
|
686
689
|
}
|
|
687
690
|
|
|
688
691
|
/**
|
|
@@ -1026,7 +1029,7 @@ declare const LogBuiltInMetadata: {
|
|
|
1026
1029
|
ClientFatalError: string;
|
|
1027
1030
|
};
|
|
1028
1031
|
Target: {
|
|
1029
|
-
|
|
1032
|
+
NoTarget: string;
|
|
1030
1033
|
};
|
|
1031
1034
|
};
|
|
1032
1035
|
|
package/package.json
CHANGED
|
@@ -18,6 +18,8 @@ type Props = {
|
|
|
18
18
|
minLabelWidth?: string,
|
|
19
19
|
// Buttons
|
|
20
20
|
children: React.ReactNode,
|
|
21
|
+
// Additional class names to add to the outer container
|
|
22
|
+
className?: string,
|
|
21
23
|
};
|
|
22
24
|
|
|
23
25
|
/*------------------------------------------------------------------------*/
|
|
@@ -36,6 +38,7 @@ const ButtonInputGroup: React.FC<Props> = (props) => {
|
|
|
36
38
|
label,
|
|
37
39
|
minLabelWidth,
|
|
38
40
|
children,
|
|
41
|
+
className,
|
|
39
42
|
} = props;
|
|
40
43
|
|
|
41
44
|
/*------------------------------------------------------------------------*/
|
|
@@ -47,7 +50,7 @@ const ButtonInputGroup: React.FC<Props> = (props) => {
|
|
|
47
50
|
/*----------------------------------------*/
|
|
48
51
|
|
|
49
52
|
return (
|
|
50
|
-
<div className=
|
|
53
|
+
<div className={`input-group ${className ?? ''}`}>
|
|
51
54
|
<div className="input-group-prepend d-flex w-100">
|
|
52
55
|
{/* Label */}
|
|
53
56
|
<span
|
|
@@ -66,7 +69,7 @@ const ButtonInputGroup: React.FC<Props> = (props) => {
|
|
|
66
69
|
|
|
67
70
|
{/* Contents */}
|
|
68
71
|
<span
|
|
69
|
-
className="input-group-text flex-grow-1 rounded-right"
|
|
72
|
+
className="input-group-text flex-grow-1 rounded-right d-flex flex-wrap"
|
|
70
73
|
style={{
|
|
71
74
|
backgroundColor: 'white',
|
|
72
75
|
borderTopLeftRadius: 0,
|
|
@@ -12,6 +12,8 @@ import React from 'react';
|
|
|
12
12
|
|
|
13
13
|
// Props definition
|
|
14
14
|
type Props = {
|
|
15
|
+
// Custom background color
|
|
16
|
+
customBackgroundColor?: string,
|
|
15
17
|
// Children to display
|
|
16
18
|
children: React.ReactNode,
|
|
17
19
|
};
|
|
@@ -49,6 +51,7 @@ const Drawer: React.FC<Props> = (props) => {
|
|
|
49
51
|
|
|
50
52
|
// Destructure all props
|
|
51
53
|
const {
|
|
54
|
+
customBackgroundColor,
|
|
52
55
|
children,
|
|
53
56
|
} = props;
|
|
54
57
|
|
|
@@ -61,7 +64,12 @@ const Drawer: React.FC<Props> = (props) => {
|
|
|
61
64
|
/*----------------------------------------*/
|
|
62
65
|
|
|
63
66
|
return (
|
|
64
|
-
<div
|
|
67
|
+
<div
|
|
68
|
+
className="Drawer-container"
|
|
69
|
+
style={{
|
|
70
|
+
backgroundColor: (customBackgroundColor ?? undefined),
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
65
73
|
<style>{style}</style>
|
|
66
74
|
{children}
|
|
67
75
|
</div>
|
|
@@ -30,6 +30,7 @@ import Modal from './Modal';
|
|
|
30
30
|
import ModalType from '../types/ModalType';
|
|
31
31
|
import CheckboxButton from './CheckboxButton';
|
|
32
32
|
import CSVDownloadButton from './CSVDownloadButton';
|
|
33
|
+
import Variant from '../types/Variant';
|
|
33
34
|
|
|
34
35
|
/*------------------------------------------------------------------------*/
|
|
35
36
|
/* Types */
|
|
@@ -86,7 +87,7 @@ enum ActionType {
|
|
|
86
87
|
// Toggle sort column param
|
|
87
88
|
ToggleSortColumn = 'toggle-sort-column',
|
|
88
89
|
// Toggle the visibility of a column
|
|
89
|
-
|
|
90
|
+
UpdateColumnVisibility = 'update-column-visibility',
|
|
90
91
|
// Toggle the column visibility customization modal
|
|
91
92
|
ToggleColVisCusModalVisibility = 'toggle-col-vis-cus-modal-visibility',
|
|
92
93
|
}
|
|
@@ -101,9 +102,11 @@ type Action = (
|
|
|
101
102
|
}
|
|
102
103
|
| {
|
|
103
104
|
// Action type
|
|
104
|
-
type: ActionType.
|
|
105
|
-
// Param for the column to
|
|
105
|
+
type: ActionType.UpdateColumnVisibility,
|
|
106
|
+
// Param for the column to update
|
|
106
107
|
param: string,
|
|
108
|
+
// If true, make the column visible
|
|
109
|
+
visible: boolean,
|
|
107
110
|
}
|
|
108
111
|
| {
|
|
109
112
|
// Action type
|
|
@@ -144,9 +147,9 @@ const reducer = (state: State, action: Action): State => {
|
|
|
144
147
|
sortType: SortType.Ascending,
|
|
145
148
|
};
|
|
146
149
|
}
|
|
147
|
-
case ActionType.
|
|
150
|
+
case ActionType.UpdateColumnVisibility: {
|
|
148
151
|
const { columnVisibilityMap } = state;
|
|
149
|
-
columnVisibilityMap[action.param] =
|
|
152
|
+
columnVisibilityMap[action.param] = action.visible;
|
|
150
153
|
return {
|
|
151
154
|
...state,
|
|
152
155
|
columnVisibilityMap,
|
|
@@ -179,10 +182,16 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
179
182
|
const {
|
|
180
183
|
title,
|
|
181
184
|
id,
|
|
182
|
-
data,
|
|
183
185
|
columns,
|
|
184
186
|
} = props;
|
|
185
187
|
|
|
188
|
+
// Get data, show empty row if none
|
|
189
|
+
const data = (
|
|
190
|
+
(props.data && props.data.length > 0)
|
|
191
|
+
? props.data
|
|
192
|
+
: [{ id: 'empty-row' }]
|
|
193
|
+
);
|
|
194
|
+
|
|
186
195
|
/* -------------- State ------------- */
|
|
187
196
|
|
|
188
197
|
// Initial state
|
|
@@ -234,6 +243,7 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
234
243
|
type: ActionType.ToggleColVisCusModalVisibility,
|
|
235
244
|
});
|
|
236
245
|
}}
|
|
246
|
+
okayVariant={Variant.Light}
|
|
237
247
|
>
|
|
238
248
|
{
|
|
239
249
|
columns.map((column) => {
|
|
@@ -241,15 +251,19 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
241
251
|
<CheckboxButton
|
|
242
252
|
key={column.param}
|
|
243
253
|
id={`IntelliTable-${id}-toggle-visibility-${column.param}`}
|
|
254
|
+
className="mb-2"
|
|
244
255
|
text={column.title}
|
|
245
|
-
onChanged={() => {
|
|
256
|
+
onChanged={(checked) => {
|
|
246
257
|
dispatch({
|
|
247
|
-
type: ActionType.
|
|
258
|
+
type: ActionType.UpdateColumnVisibility,
|
|
248
259
|
param: column.param,
|
|
260
|
+
visible: checked,
|
|
249
261
|
});
|
|
250
262
|
}}
|
|
251
263
|
checked={columnVisibilityMap[column.param]}
|
|
252
264
|
ariaLabel={`show "${column.title}" column`}
|
|
265
|
+
checkedVariant={Variant.Light}
|
|
266
|
+
uncheckedVariant={Variant.Secondary}
|
|
253
267
|
/>
|
|
254
268
|
);
|
|
255
269
|
})
|
|
@@ -272,12 +286,14 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
272
286
|
// Custom info based on current sort type
|
|
273
287
|
let sortButtonAriaLabel;
|
|
274
288
|
let sortIcon = faSort;
|
|
289
|
+
let sortingByThisColumn = false;
|
|
275
290
|
if (!sortColumnParam) {
|
|
276
291
|
// Not being sorted yet
|
|
277
292
|
sortButtonAriaLabel = `sort ascending by ${column.title}`;
|
|
278
293
|
sortIcon = faSort;
|
|
279
294
|
} else if (column.param === sortColumnParam) {
|
|
280
295
|
// Already sorted by this column
|
|
296
|
+
sortingByThisColumn = true;
|
|
281
297
|
if (sortType === SortType.Ascending) {
|
|
282
298
|
// Sorted ascending
|
|
283
299
|
sortButtonAriaLabel = `sort descending by ${column.title}`;
|
|
@@ -299,17 +315,23 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
299
315
|
key={column.param}
|
|
300
316
|
scope="col"
|
|
301
317
|
id={`IntelliTable-${id}-header-${column.param}`}
|
|
318
|
+
className="text-start"
|
|
319
|
+
style={{
|
|
320
|
+
borderRight: '0.05rem solid #555',
|
|
321
|
+
borderLeft: '0.05rem solid #555',
|
|
322
|
+
}}
|
|
302
323
|
>
|
|
303
|
-
<div className="d-flex align-items-center justify-content-
|
|
324
|
+
<div className="d-flex align-items-center justify-content-start flex-row h-100">
|
|
304
325
|
{/* Title */}
|
|
305
|
-
<
|
|
326
|
+
<span className="text-nowrap">
|
|
306
327
|
{column.title}
|
|
307
|
-
</
|
|
328
|
+
</span>
|
|
308
329
|
{/* Buttons */}
|
|
309
330
|
<div>
|
|
310
331
|
<button
|
|
311
332
|
type="button"
|
|
312
|
-
|
|
333
|
+
id={`IntelliTable-${id}-sort-by-${column.param}-button`}
|
|
334
|
+
className={`btn btn-${sortingByThisColumn ? 'light' : 'secondary'} btn-sm ms-1 ps-1 pe-1 pt-0 pb-0`}
|
|
313
335
|
aria-label={sortButtonAriaLabel}
|
|
314
336
|
onClick={() => {
|
|
315
337
|
dispatch({
|
|
@@ -347,6 +369,33 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
347
369
|
const aVal = a[sortColumnParam];
|
|
348
370
|
const bVal = b[sortColumnParam];
|
|
349
371
|
|
|
372
|
+
// Tiebreaker sort by timestamp, most recent first (used if tied)
|
|
373
|
+
const tiebreaker = (
|
|
374
|
+
(b.timestamp ?? 0)
|
|
375
|
+
- (a.timestamp ?? 0)
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
// Auto-sort undefined and null to end of list
|
|
379
|
+
if (
|
|
380
|
+
(aVal === undefined || aVal === null)
|
|
381
|
+
|| (bVal === undefined || bVal === null)
|
|
382
|
+
) {
|
|
383
|
+
// At least one was undefined
|
|
384
|
+
if (
|
|
385
|
+
(aVal === undefined || aVal === null)
|
|
386
|
+
&& (bVal === undefined || bVal === null)
|
|
387
|
+
) {
|
|
388
|
+
// Both undefined
|
|
389
|
+
return tiebreaker;
|
|
390
|
+
}
|
|
391
|
+
if (aVal === undefined || aVal === null) {
|
|
392
|
+
// First was undefined
|
|
393
|
+
return 1;
|
|
394
|
+
}
|
|
395
|
+
// Second was undefined
|
|
396
|
+
return -1;
|
|
397
|
+
}
|
|
398
|
+
|
|
350
399
|
// Sort differently based on the data type
|
|
351
400
|
// > Boolean
|
|
352
401
|
if (paramType === ParamType.Boolean) {
|
|
@@ -356,7 +405,7 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
356
405
|
if (!aVal && bVal) {
|
|
357
406
|
return (descending ? 1 : -1);
|
|
358
407
|
}
|
|
359
|
-
return
|
|
408
|
+
return tiebreaker;
|
|
360
409
|
}
|
|
361
410
|
// > Number
|
|
362
411
|
if (
|
|
@@ -372,12 +421,12 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
372
421
|
// > String
|
|
373
422
|
if (paramType === ParamType.String) {
|
|
374
423
|
if (aVal < bVal) {
|
|
375
|
-
return (descending ?
|
|
424
|
+
return (descending ? 1 : -1);
|
|
376
425
|
}
|
|
377
426
|
if (aVal > bVal) {
|
|
378
|
-
return (descending ? 1 :
|
|
427
|
+
return (descending ? -1 : 1);
|
|
379
428
|
}
|
|
380
|
-
return
|
|
429
|
+
return tiebreaker;
|
|
381
430
|
}
|
|
382
431
|
// > JSON
|
|
383
432
|
if (paramType === ParamType.JSON) {
|
|
@@ -399,7 +448,7 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
399
448
|
}
|
|
400
449
|
|
|
401
450
|
// No sort
|
|
402
|
-
return
|
|
451
|
+
return tiebreaker;
|
|
403
452
|
});
|
|
404
453
|
}
|
|
405
454
|
|
|
@@ -431,16 +480,19 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
431
480
|
noValue
|
|
432
481
|
? (
|
|
433
482
|
<FontAwesomeIcon
|
|
434
|
-
icon={
|
|
483
|
+
icon={faMinus}
|
|
435
484
|
/>
|
|
436
485
|
)
|
|
437
486
|
: (
|
|
438
487
|
<FontAwesomeIcon
|
|
439
|
-
icon={faXmarkCircle}
|
|
488
|
+
icon={fullValue ? faCheckCircle : faXmarkCircle}
|
|
440
489
|
/>
|
|
441
490
|
)
|
|
442
491
|
);
|
|
443
492
|
title = (fullValue ? 'True' : 'False');
|
|
493
|
+
if (noValue) {
|
|
494
|
+
title = 'Empty Cell';
|
|
495
|
+
}
|
|
444
496
|
} else if (column.type === ParamType.Int) {
|
|
445
497
|
fullValue = Number.parseInt(value, 10);
|
|
446
498
|
const noValue = Number.isNaN(fullValue);
|
|
@@ -454,6 +506,9 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
454
506
|
: fullValue
|
|
455
507
|
);
|
|
456
508
|
title = String(fullValue);
|
|
509
|
+
if (noValue) {
|
|
510
|
+
title = 'Empty Cell';
|
|
511
|
+
}
|
|
457
512
|
} else if (column.type === ParamType.Float) {
|
|
458
513
|
fullValue = Number.parseFloat(value);
|
|
459
514
|
const noValue = Number.isNaN(fullValue);
|
|
@@ -467,9 +522,16 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
467
522
|
: roundToNumDecimals(fullValue as number, 2)
|
|
468
523
|
);
|
|
469
524
|
title = String(fullValue);
|
|
525
|
+
if (noValue) {
|
|
526
|
+
title = 'Empty Cell';
|
|
527
|
+
}
|
|
470
528
|
} else if (column.type === ParamType.String) {
|
|
471
529
|
fullValue = String(value).trim();
|
|
472
|
-
const noValue = (
|
|
530
|
+
const noValue = (
|
|
531
|
+
value === undefined
|
|
532
|
+
|| value === null
|
|
533
|
+
|| String(fullValue).trim().length === 0
|
|
534
|
+
);
|
|
473
535
|
visibleValue = (
|
|
474
536
|
noValue
|
|
475
537
|
? (
|
|
@@ -480,6 +542,9 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
480
542
|
: fullValue
|
|
481
543
|
);
|
|
482
544
|
title = `"${value}"`;
|
|
545
|
+
if (noValue) {
|
|
546
|
+
title = 'Empty Cell';
|
|
547
|
+
}
|
|
483
548
|
} else if (column.type === ParamType.JSON) {
|
|
484
549
|
fullValue = JSON.stringify(value);
|
|
485
550
|
const noValue = (
|
|
@@ -496,6 +561,7 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
496
561
|
)
|
|
497
562
|
: fullValue
|
|
498
563
|
);
|
|
564
|
+
title="JSON Object"
|
|
499
565
|
}
|
|
500
566
|
|
|
501
567
|
// Create UI
|
|
@@ -503,6 +569,10 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
503
569
|
<td
|
|
504
570
|
key={`${datum.id}-${column.param}`}
|
|
505
571
|
title={title}
|
|
572
|
+
style={{
|
|
573
|
+
borderRight: '0.05rem solid #555',
|
|
574
|
+
borderLeft: '0.05rem solid #555',
|
|
575
|
+
}}
|
|
506
576
|
>
|
|
507
577
|
{visibleValue}
|
|
508
578
|
</td>
|
|
@@ -549,8 +619,10 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
549
619
|
// Build main UI
|
|
550
620
|
return (
|
|
551
621
|
<div className={`IntelliTable-container-${id}`}>
|
|
622
|
+
{/* Modal */}
|
|
623
|
+
{modal}
|
|
552
624
|
{/* Header */}
|
|
553
|
-
<div className="d-flex align-items-center justify-content-
|
|
625
|
+
<div className="d-flex align-items-center justify-content-start">
|
|
554
626
|
{/* Title */}
|
|
555
627
|
<h3 className="m-0">
|
|
556
628
|
{title}
|
|
@@ -567,7 +639,7 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
567
639
|
{/* Show/Hide Columns */}
|
|
568
640
|
<button
|
|
569
641
|
type="button"
|
|
570
|
-
className="btn btn-secondary"
|
|
642
|
+
className="btn btn-secondary ms-2"
|
|
571
643
|
aria-label={`show panel for customizing which columns show in table ${title}`}
|
|
572
644
|
id={`IntelliTable-${id}-show-column-customization-modal`}
|
|
573
645
|
onClick={() => {
|
|
@@ -591,7 +663,7 @@ const IntelliTable: React.FC<Props> = (props) => {
|
|
|
591
663
|
</div>
|
|
592
664
|
{/* Table */}
|
|
593
665
|
<div
|
|
594
|
-
className={`IntelliTable-table-${id}`}
|
|
666
|
+
className={`IntelliTable-table-${id} mt-2`}
|
|
595
667
|
style={{
|
|
596
668
|
overflowX: 'auto',
|
|
597
669
|
}}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Reusable nested item picker
|
|
3
3
|
* @author Yuen Ler Chow
|
|
4
|
+
* @author Gabe Abrams
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
// Import React
|
|
@@ -43,36 +44,46 @@ type Props = {
|
|
|
43
44
|
/* -------- State Definition -------- */
|
|
44
45
|
|
|
45
46
|
type State = {
|
|
46
|
-
//
|
|
47
|
-
|
|
47
|
+
// Map of children that are expanded
|
|
48
|
+
childExpanded: {
|
|
49
|
+
[k: string]: boolean
|
|
50
|
+
},
|
|
48
51
|
};
|
|
49
52
|
|
|
50
53
|
/* ------------- Actions ------------ */
|
|
51
54
|
|
|
52
55
|
// Types of actions
|
|
53
56
|
enum ActionType {
|
|
54
|
-
// Toggle whether
|
|
55
|
-
|
|
57
|
+
// Toggle whether a child are being shown
|
|
58
|
+
ToggleChild = 'toggle-child',
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
// Action definitions
|
|
59
62
|
type Action = (
|
|
60
63
|
| {
|
|
61
64
|
// Action type
|
|
62
|
-
type: ActionType.
|
|
65
|
+
type: ActionType.ToggleChild,
|
|
66
|
+
// Id of the child to show
|
|
67
|
+
id: (string | number),
|
|
63
68
|
}
|
|
64
69
|
);
|
|
65
70
|
|
|
66
71
|
/**
|
|
67
72
|
* Reducer that executes actions
|
|
68
|
-
* @author
|
|
73
|
+
* @author Gabe Abrams
|
|
69
74
|
* @param state current state
|
|
70
75
|
* @param action action to execute
|
|
71
76
|
*/
|
|
72
77
|
const reducer = (state: State, action: Action): State => {
|
|
73
78
|
switch (action.type) {
|
|
74
|
-
case ActionType.
|
|
75
|
-
return {
|
|
79
|
+
case ActionType.ToggleChild: {
|
|
80
|
+
return {
|
|
81
|
+
...state,
|
|
82
|
+
childExpanded: {
|
|
83
|
+
...state.childExpanded,
|
|
84
|
+
[String(action.id)]: !state.childExpanded[String(action.id)],
|
|
85
|
+
},
|
|
86
|
+
};
|
|
76
87
|
}
|
|
77
88
|
default: {
|
|
78
89
|
return state;
|
|
@@ -99,9 +110,15 @@ const NestableItemList: React.FC<Props> = (props) => {
|
|
|
99
110
|
|
|
100
111
|
/* -------------- State ------------- */
|
|
101
112
|
|
|
113
|
+
// Create initial map of child expanded booleans
|
|
114
|
+
const initChildExpanded: { [k: string]: boolean } = {};
|
|
115
|
+
items.forEach((item) => {
|
|
116
|
+
initChildExpanded[String(item.id)] = false;
|
|
117
|
+
});
|
|
118
|
+
|
|
102
119
|
// Initial state
|
|
103
120
|
const initialState: State = {
|
|
104
|
-
|
|
121
|
+
childExpanded: initChildExpanded,
|
|
105
122
|
};
|
|
106
123
|
|
|
107
124
|
// Initialize state
|
|
@@ -109,7 +126,7 @@ const NestableItemList: React.FC<Props> = (props) => {
|
|
|
109
126
|
|
|
110
127
|
// Destructure common state
|
|
111
128
|
const {
|
|
112
|
-
|
|
129
|
+
childExpanded,
|
|
113
130
|
} = state;
|
|
114
131
|
|
|
115
132
|
/*------------------------------------------------------------------------*/
|
|
@@ -231,13 +248,14 @@ const NestableItemList: React.FC<Props> = (props) => {
|
|
|
231
248
|
type="button"
|
|
232
249
|
onClick={() => {
|
|
233
250
|
dispatch({
|
|
234
|
-
type: ActionType.
|
|
251
|
+
type: ActionType.ToggleChild,
|
|
252
|
+
id: item.id,
|
|
235
253
|
});
|
|
236
254
|
}}
|
|
237
|
-
aria-label={`${
|
|
255
|
+
aria-label={`${childExpanded[item.id] ? 'Hide' : 'Show'} items in ${item.name}`}
|
|
238
256
|
>
|
|
239
257
|
<FontAwesomeIcon
|
|
240
|
-
icon={
|
|
258
|
+
icon={childExpanded[item.id] ? faChevronDown : faChevronRight}
|
|
241
259
|
/>
|
|
242
260
|
</button>
|
|
243
261
|
)}
|
|
@@ -257,7 +275,7 @@ const NestableItemList: React.FC<Props> = (props) => {
|
|
|
257
275
|
/>
|
|
258
276
|
|
|
259
277
|
{/* Children */}
|
|
260
|
-
{item.isGroup &&
|
|
278
|
+
{(item.isGroup && childExpanded[item.id]) && (
|
|
261
279
|
<div
|
|
262
280
|
className="NestableItemList-children-container"
|
|
263
281
|
style={{
|
|
@@ -31,6 +31,8 @@ type Props = {
|
|
|
31
31
|
* values updated
|
|
32
32
|
*/
|
|
33
33
|
onChanged: (updatedItems: PickableItem[]) => void,
|
|
34
|
+
// If true, don't add margin to bottom of item picker
|
|
35
|
+
noBottomMargin?: boolean,
|
|
34
36
|
};
|
|
35
37
|
|
|
36
38
|
/*------------------------------------------------------------------------*/
|
|
@@ -49,6 +51,7 @@ const ItemPicker: React.FC<Props> = (props) => {
|
|
|
49
51
|
title,
|
|
50
52
|
items,
|
|
51
53
|
onChanged,
|
|
54
|
+
noBottomMargin,
|
|
52
55
|
} = props;
|
|
53
56
|
|
|
54
57
|
/*------------------------------------------------------------------------*/
|
|
@@ -66,6 +69,7 @@ const ItemPicker: React.FC<Props> = (props) => {
|
|
|
66
69
|
return (
|
|
67
70
|
<TabBox
|
|
68
71
|
title={title}
|
|
72
|
+
noBottomMargin={noBottomMargin}
|
|
69
73
|
>
|
|
70
74
|
<div style={{ overflowX: 'auto' }}>
|
|
71
75
|
<NestableItemList
|