@onehat/ui 0.3.94 → 0.3.96
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 +1 -1
- package/src/Components/Form/Field/Combo/Combo.js +5 -5
- package/src/Components/Form/Field/Tag/Tag.js +5 -0
- package/src/Components/Form/Form.js +12 -3
- package/src/Components/Grid/Grid.js +109 -57
- package/src/Components/Grid/GridHeaderRow.js +1 -1
- package/src/Components/Viewer/Viewer.js +1 -0
- package/src/Constants/Styles.js +1 -0
package/package.json
CHANGED
|
@@ -332,10 +332,8 @@ export function ComboComponent(props) {
|
|
|
332
332
|
const filterName = getFilterName();
|
|
333
333
|
if (Repository.hasFilter(filterName)) {
|
|
334
334
|
Repository.clearFilters(filterName);
|
|
335
|
-
if (Repository.isRemote) {
|
|
336
|
-
|
|
337
|
-
await Repository.reload();
|
|
338
|
-
}
|
|
335
|
+
if (Repository.isRemote && !Repository.isAutoLoad) {
|
|
336
|
+
await Repository.reload();
|
|
339
337
|
}
|
|
340
338
|
}
|
|
341
339
|
} else {
|
|
@@ -371,7 +369,7 @@ export function ComboComponent(props) {
|
|
|
371
369
|
// remote
|
|
372
370
|
const filterValue = _.isEmpty(value) ? null : value + '%';
|
|
373
371
|
await Repository.filter(filterName, filterValue);
|
|
374
|
-
if (!
|
|
372
|
+
if (!Repository.isAutoLoad) {
|
|
375
373
|
await Repository.reload();
|
|
376
374
|
}
|
|
377
375
|
} else {
|
|
@@ -597,6 +595,8 @@ export function ComboComponent(props) {
|
|
|
597
595
|
'disableCopy',
|
|
598
596
|
'disableDuplicate',
|
|
599
597
|
'disablePrint',
|
|
598
|
+
'selectorId',
|
|
599
|
+
'selectorSelected',
|
|
600
600
|
]);
|
|
601
601
|
const WhichGrid = isEditor ? WindowedGridEditor : Grid;
|
|
602
602
|
grid = <WhichGrid
|
|
@@ -164,6 +164,11 @@ function TagComponent(props) {
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
if (isEditor && propsToPass.selectorId) {
|
|
168
|
+
_combo.selectorId = propsToPass.selectorId;
|
|
169
|
+
_combo.selectorSelected = propsToPass.selectorSelected;
|
|
170
|
+
}
|
|
171
|
+
|
|
167
172
|
return <>
|
|
168
173
|
<Column
|
|
169
174
|
{...props}
|
|
@@ -453,9 +453,11 @@ function Form(props) {
|
|
|
453
453
|
throw new Error('Should not yet be valid React element. Did you use <Element> instead of () => <Element> when defining it?')
|
|
454
454
|
}
|
|
455
455
|
|
|
456
|
-
if (useSelectorId) {
|
|
456
|
+
if (useSelectorId) { // This causes the whole form to use selectorId
|
|
457
457
|
editorTypeProps.selectorId = selectorId;
|
|
458
|
-
|
|
458
|
+
}
|
|
459
|
+
if (propsToPass.selectorId || editorTypeProps.selectorId) { // editorTypeProps.selectorId causes just this one field to use selectorId
|
|
460
|
+
editorTypeProps.selectorSelected = record;
|
|
459
461
|
}
|
|
460
462
|
let element = <Element
|
|
461
463
|
name={name}
|
|
@@ -552,6 +554,7 @@ function Form(props) {
|
|
|
552
554
|
let {
|
|
553
555
|
type,
|
|
554
556
|
title = null,
|
|
557
|
+
description = null,
|
|
555
558
|
selectorId,
|
|
556
559
|
...propsToPass
|
|
557
560
|
} = item;
|
|
@@ -577,7 +580,13 @@ function Form(props) {
|
|
|
577
580
|
fontWeight="bold"
|
|
578
581
|
>{title}</Text>;
|
|
579
582
|
}
|
|
580
|
-
|
|
583
|
+
if (description) {
|
|
584
|
+
description = <Text
|
|
585
|
+
fontSize={styles.FORM_ANCILLARY_DESCRIPTION_FONTSIZE}
|
|
586
|
+
fontStyle="italic"
|
|
587
|
+
>{description}</Text>;
|
|
588
|
+
}
|
|
589
|
+
components.push(<Column key={'ancillary-' + ix} mx={2} my={5}>{title}{description}{element}</Column>);
|
|
581
590
|
});
|
|
582
591
|
}
|
|
583
592
|
return components;
|
|
@@ -45,6 +45,7 @@ import withInlineEditor from '../Hoc/withInlineEditor.js';
|
|
|
45
45
|
import getIconButtonFromConfig from '../../Functions/getIconButtonFromConfig.js';
|
|
46
46
|
import testProps from '../../Functions/testProps.js';
|
|
47
47
|
import nbToRgb from '../../Functions/nbToRgb.js';
|
|
48
|
+
import Loading from '../Messages/Loading.js';
|
|
48
49
|
import GridHeaderRow from './GridHeaderRow.js';
|
|
49
50
|
import GridRow, { ReorderableGridRow } from './GridRow.js';
|
|
50
51
|
import IconButton from '../Buttons/IconButton.js';
|
|
@@ -56,15 +57,33 @@ import ReorderRows from '../Icons/ReorderRows.js';
|
|
|
56
57
|
import _ from 'lodash';
|
|
57
58
|
|
|
58
59
|
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
60
|
+
// This fn gets called many times per component
|
|
61
|
+
// First call
|
|
62
|
+
// !isInited
|
|
63
|
+
// render a placeholder, to get container dimensions
|
|
64
|
+
// onInitialLayout()
|
|
65
|
+
// set initial pageSize
|
|
66
|
+
// setIsInited(true)
|
|
67
|
+
// Second call
|
|
68
|
+
// !isReady
|
|
69
|
+
// set selectorSelected
|
|
70
|
+
// load Repo
|
|
71
|
+
// Third call
|
|
72
|
+
// isReady
|
|
73
|
+
// render Grid,
|
|
74
|
+
// subsequent calls due to changes of selectorSelected
|
|
75
|
+
// re-apply selectorSelected
|
|
76
|
+
// subsequent calls due to changes changes in onLayout
|
|
77
|
+
// adjust pageSize if needed
|
|
78
|
+
|
|
79
|
+
// TODO: account for various environments (mainly for optimization):
|
|
80
|
+
// RN vs web
|
|
81
|
+
// Repository vs data
|
|
62
82
|
|
|
63
83
|
function GridComponent(props) {
|
|
64
84
|
const {
|
|
65
85
|
|
|
66
86
|
columnsConfig = [], // json configurations for each column
|
|
67
|
-
|
|
68
87
|
columnProps = {},
|
|
69
88
|
getRowProps = (item) => {
|
|
70
89
|
return {
|
|
@@ -153,7 +172,7 @@ function GridComponent(props) {
|
|
|
153
172
|
gridRef = useRef(),
|
|
154
173
|
gridContainerRef = useRef(),
|
|
155
174
|
isAddingRef = useRef(),
|
|
156
|
-
|
|
175
|
+
[isInited, setIsInited] = useState(false),
|
|
157
176
|
[isReady, setIsReady] = useState(false),
|
|
158
177
|
[isLoading, setIsLoading] = useState(false),
|
|
159
178
|
[localColumnsConfig, setLocalColumnsConfigRaw] = useState([]),
|
|
@@ -639,56 +658,68 @@ function GridComponent(props) {
|
|
|
639
658
|
}
|
|
640
659
|
setDragRowSlot(null);
|
|
641
660
|
},
|
|
661
|
+
calculatePageSize = (containerHeight) => {
|
|
662
|
+
const
|
|
663
|
+
headerHeight = showHeaders ? 50 : 0,
|
|
664
|
+
footerHeight = !disablePagination ? 50 : 0,
|
|
665
|
+
height = containerHeight - headerHeight - footerHeight,
|
|
666
|
+
rowHeight = 48,
|
|
667
|
+
rowsPerContainer = Math.floor(height / rowHeight);
|
|
668
|
+
let pageSize = rowsPerContainer;
|
|
669
|
+
if (showHeaders) {
|
|
670
|
+
pageSize--;
|
|
671
|
+
}
|
|
672
|
+
return pageSize;
|
|
673
|
+
},
|
|
642
674
|
adjustPageSizeToHeight = (e) => {
|
|
643
|
-
if (CURRENT_MODE
|
|
675
|
+
if (CURRENT_MODE !== UI_MODE_WEB) { // TODO: Remove this conditional, and don't even do the double render for RN
|
|
644
676
|
return;
|
|
645
677
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
isRenderedRef.current = true;
|
|
649
|
-
if (loadOnRender && Repository && !Repository.isLoaded && !Repository.isLoading && !Repository.isAutoLoad) {
|
|
650
|
-
doLoad = true; // first time in onLayout only!
|
|
651
|
-
}
|
|
678
|
+
if (!Repository) {
|
|
679
|
+
return;
|
|
652
680
|
}
|
|
653
681
|
|
|
654
|
-
let
|
|
655
|
-
if (!
|
|
656
|
-
|
|
682
|
+
let doAdjustment = autoAdjustPageSizeToHeight;
|
|
683
|
+
if (!_.isNil(UiGlobals.autoAdjustPageSizeToHeight) && !UiGlobals.autoAdjustPageSizeToHeight) {
|
|
684
|
+
// allow global override to prevent this auto adjustment
|
|
685
|
+
doAdjustment = false;
|
|
657
686
|
}
|
|
658
|
-
if (
|
|
659
|
-
const
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
rowsPerContainer = Math.floor(height / rowHeight);
|
|
666
|
-
let pageSize = rowsPerContainer;
|
|
667
|
-
if (showHeaders) {
|
|
668
|
-
pageSize--;
|
|
669
|
-
}
|
|
670
|
-
if (pageSize !== Repository.pageSize) {
|
|
671
|
-
Repository.setPageSize(pageSize);
|
|
687
|
+
if (doAdjustment) {
|
|
688
|
+
const containerHeight = e.nativeEvent.layout.height;
|
|
689
|
+
if (containerHeight > 0) {
|
|
690
|
+
const pageSize = calculatePageSize(containerHeight);
|
|
691
|
+
if (pageSize !== Repository.pageSize) {
|
|
692
|
+
Repository.setPageSize(pageSize);
|
|
693
|
+
}
|
|
672
694
|
}
|
|
673
695
|
}
|
|
674
|
-
if (doLoad) {
|
|
675
|
-
Repository.load();
|
|
676
|
-
}
|
|
677
696
|
},
|
|
678
697
|
debouncedAdjustPageSizeToHeight = useCallback(_.debounce(adjustPageSizeToHeight, 200), []),
|
|
679
|
-
|
|
680
|
-
if (!
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
698
|
+
applySelectorSelected = () => {
|
|
699
|
+
if (disableSelectorSelected || !selectorId) {
|
|
700
|
+
return
|
|
701
|
+
}
|
|
702
|
+
let id = selectorSelected?.id;
|
|
703
|
+
if (_.isEmpty(selectorSelected)) {
|
|
704
|
+
id = noSelectorMeansNoResults ? 'NO_MATCHES' : null;
|
|
686
705
|
}
|
|
706
|
+
Repository.filter(selectorId, id, false); // so it doesn't clear existing filters
|
|
687
707
|
};
|
|
688
708
|
|
|
689
709
|
useEffect(() => {
|
|
710
|
+
if (!isInited) {
|
|
711
|
+
// first call -- meant to render placeholder so we get container dimensions
|
|
712
|
+
if (Repository) {
|
|
713
|
+
if (Repository.isRemote) {
|
|
714
|
+
Repository.isAutoLoad = false;
|
|
715
|
+
}
|
|
716
|
+
Repository.pauseEvents();
|
|
717
|
+
}
|
|
718
|
+
return () => {};
|
|
719
|
+
}
|
|
690
720
|
|
|
691
|
-
|
|
721
|
+
// second call -- do other necessary setup
|
|
722
|
+
function calculateLocalColumnsConfig() {
|
|
692
723
|
// convert json config into actual elements
|
|
693
724
|
const localColumnsConfig = [];
|
|
694
725
|
if (_.isEmpty(columnsConfig)) {
|
|
@@ -756,12 +787,11 @@ function GridComponent(props) {
|
|
|
756
787
|
});
|
|
757
788
|
}
|
|
758
789
|
return localColumnsConfig;
|
|
759
|
-
};
|
|
760
|
-
|
|
761
|
-
if (!isReady) {
|
|
762
|
-
setLocalColumnsConfig(calculateLocalColumnsConfig());
|
|
763
|
-
setIsReady(true);
|
|
764
790
|
}
|
|
791
|
+
setLocalColumnsConfig(calculateLocalColumnsConfig());
|
|
792
|
+
|
|
793
|
+
setIsReady(true);
|
|
794
|
+
|
|
765
795
|
if (!Repository) {
|
|
766
796
|
return () => {};
|
|
767
797
|
}
|
|
@@ -791,6 +821,13 @@ function GridComponent(props) {
|
|
|
791
821
|
Repository.on('changeSorters', onChangeSorters);
|
|
792
822
|
|
|
793
823
|
|
|
824
|
+
applySelectorSelected();
|
|
825
|
+
Repository.resumeEvents();
|
|
826
|
+
|
|
827
|
+
if (Repository.isRemote) {
|
|
828
|
+
Repository.load();
|
|
829
|
+
}
|
|
830
|
+
|
|
794
831
|
return () => {
|
|
795
832
|
Repository.off('beforeLoad', setTrue);
|
|
796
833
|
Repository.off('load', setFalse);
|
|
@@ -801,21 +838,16 @@ function GridComponent(props) {
|
|
|
801
838
|
Repository.off('changeFilters', onChangeFilters);
|
|
802
839
|
Repository.off('changeSorters', onChangeSorters);
|
|
803
840
|
};
|
|
804
|
-
}, []);
|
|
841
|
+
}, [isInited]);
|
|
805
842
|
|
|
806
843
|
useEffect(() => {
|
|
807
|
-
if (!Repository) {
|
|
844
|
+
if (!Repository || !isReady) {
|
|
808
845
|
return () => {};
|
|
809
846
|
}
|
|
810
|
-
if (!disableSelectorSelected && selectorId) {
|
|
811
|
-
let id = selectorSelected?.id;
|
|
812
|
-
if (_.isEmpty(selectorSelected)) {
|
|
813
|
-
id = noSelectorMeansNoResults ? 'NO_MATCHES' : null;
|
|
814
|
-
}
|
|
815
|
-
Repository.filter(selectorId, id, false); // so it doesn't clear existing filters
|
|
816
|
-
}
|
|
817
847
|
|
|
818
|
-
|
|
848
|
+
applySelectorSelected();
|
|
849
|
+
|
|
850
|
+
}, [selectorSelected]);
|
|
819
851
|
|
|
820
852
|
if (self) {
|
|
821
853
|
self.ref = containerRef;
|
|
@@ -825,7 +857,19 @@ function GridComponent(props) {
|
|
|
825
857
|
|
|
826
858
|
const footerToolbarItemComponents = useMemo(() => getFooterToolbarItems(), [additionalToolbarButtons, isDragMode]);
|
|
827
859
|
|
|
860
|
+
if (!isInited) {
|
|
861
|
+
// first time through, render a placeholder so we can get container dimensions
|
|
862
|
+
return <Column
|
|
863
|
+
flex={1}
|
|
864
|
+
w="100%"
|
|
865
|
+
onLayout={(e) => {
|
|
866
|
+
adjustPageSizeToHeight(e);
|
|
867
|
+
setIsInited(true);
|
|
868
|
+
}}
|
|
869
|
+
/>;
|
|
870
|
+
}
|
|
828
871
|
if (!isReady) {
|
|
872
|
+
// second time through, render nothing, as we are still setting up the Repository
|
|
829
873
|
return null;
|
|
830
874
|
}
|
|
831
875
|
|
|
@@ -905,6 +949,14 @@ function GridComponent(props) {
|
|
|
905
949
|
grid = <ScrollView flex={1} w="100%">{grid}</ScrollView>
|
|
906
950
|
}
|
|
907
951
|
|
|
952
|
+
// placeholders in case no entities yet
|
|
953
|
+
if (!entities?.length) {
|
|
954
|
+
if (Repository?.isLoading) {
|
|
955
|
+
grid = <Loading isScreen={true} />;
|
|
956
|
+
} else {
|
|
957
|
+
grid = <NoRecordsFound text={noneFoundText} onRefresh={onRefresh} />;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
908
960
|
|
|
909
961
|
return <Column
|
|
910
962
|
{...testProps('Grid')}
|
|
@@ -913,7 +965,7 @@ function GridComponent(props) {
|
|
|
913
965
|
bg={bg}
|
|
914
966
|
borderWidth={styles.GRID_BORDER_WIDTH}
|
|
915
967
|
borderColor={styles.GRID_BORDER_COLOR}
|
|
916
|
-
onLayout={
|
|
968
|
+
onLayout={(e) => debouncedAdjustPageSizeToHeight(e)}
|
|
917
969
|
{...sizeProps}
|
|
918
970
|
>
|
|
919
971
|
{topToolbar}
|
|
@@ -923,7 +975,7 @@ function GridComponent(props) {
|
|
|
923
975
|
deselectAll();
|
|
924
976
|
}
|
|
925
977
|
}}>
|
|
926
|
-
{
|
|
978
|
+
{grid}
|
|
927
979
|
</Column>
|
|
928
980
|
|
|
929
981
|
{listFooterComponent}
|
|
@@ -396,7 +396,7 @@ export default function GridHeaderRow(props) {
|
|
|
396
396
|
{...textProps}
|
|
397
397
|
>{header}</Text>
|
|
398
398
|
|
|
399
|
-
{isSorter && <Icon key="Icon" as={isSortDirectionAsc ?
|
|
399
|
+
{isSorter && <Icon key="Icon" as={isSortDirectionAsc ? SortUp : SortDown} textAlign="center" size="sm" mt={3} mr={2} color="trueGray.500" />}
|
|
400
400
|
|
|
401
401
|
{isResizable && showDragHandles &&
|
|
402
402
|
<HeaderResizeHandle
|
package/src/Constants/Styles.js
CHANGED
|
@@ -9,6 +9,7 @@ const defaults = {
|
|
|
9
9
|
ATTACHMENTS_MAX_FILESIZE: 1024 * 1024 * 5, // 5MB
|
|
10
10
|
FILTER_LABEL_FONTSIZE: DEFAULT_FONTSIZE,
|
|
11
11
|
FORM_ANCILLARY_TITLE_FONTSIZE: 22,
|
|
12
|
+
FORM_ANCILLARY_DESCRIPTION_FONTSIZE: 16,
|
|
12
13
|
FORM_COLOR_READOUT_FONTSIZE: DEFAULT_FONTSIZE,
|
|
13
14
|
FORM_COLOR_INPUT_BG: WHITE,
|
|
14
15
|
FORM_COLOR_INPUT_FOCUS_BG: FOCUS,
|