@onehat/ui 0.4.18 → 0.4.20
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/BooleanCombo.js +1 -0
- package/src/Components/Form/Field/Combo/Combo.js +3 -2
- package/src/Components/Form/Field/Tag/Tag.js +2 -0
- package/src/Components/Form/Field/Tag/ValueBox.js +16 -14
- package/src/Components/Form/Field/Toggle.js +3 -3
- package/src/Components/Form/Form.js +13 -6
- package/src/Components/Form/Label.js +3 -1
- package/src/Components/Hoc/withPermissions.js +17 -4
- package/src/Components/Panel/Header.js +14 -4
- package/src/Components/Panel/Panel.js +2 -0
- package/src/Components/Tree/Tree.js +51 -38
- package/src/Components/Tree/TreeNode.js +4 -5
package/package.json
CHANGED
|
@@ -56,6 +56,7 @@ export function ComboComponent(props) {
|
|
|
56
56
|
isDisabled = false,
|
|
57
57
|
isInTag = false,
|
|
58
58
|
minimizeForRow = false,
|
|
59
|
+
menuHeight,
|
|
59
60
|
tooltipPlacement = 'bottom',
|
|
60
61
|
placeholder,
|
|
61
62
|
onRowPress,
|
|
@@ -690,7 +691,7 @@ export function ComboComponent(props) {
|
|
|
690
691
|
const WhichGrid = isEditor ? WindowedGridEditor : Grid;
|
|
691
692
|
const gridStyle = {};
|
|
692
693
|
if (UiGlobals.mode === UI_MODE_WEB) {
|
|
693
|
-
gridStyle.height = styles.FORM_COMBO_MENU_HEIGHT;
|
|
694
|
+
gridStyle.height = menuHeight || styles.FORM_COMBO_MENU_HEIGHT;
|
|
694
695
|
}
|
|
695
696
|
grid = <WhichGrid
|
|
696
697
|
showHeaders={false}
|
|
@@ -882,7 +883,7 @@ export function ComboComponent(props) {
|
|
|
882
883
|
top,
|
|
883
884
|
left,
|
|
884
885
|
width,
|
|
885
|
-
height: styles.FORM_COMBO_MENU_HEIGHT + inputHeight,
|
|
886
|
+
height: (menuHeight || styles.FORM_COMBO_MENU_HEIGHT) + inputHeight,
|
|
886
887
|
minWidth: 100,
|
|
887
888
|
}}
|
|
888
889
|
>
|
|
@@ -22,6 +22,7 @@ function TagComponent(props) {
|
|
|
22
22
|
isViewOnly = false,
|
|
23
23
|
isValueAlwaysArray,
|
|
24
24
|
isValueAsStringifiedJson,
|
|
25
|
+
showEye = true,
|
|
25
26
|
minimizeForRow = false,
|
|
26
27
|
Editor,
|
|
27
28
|
_combo = {},
|
|
@@ -231,6 +232,7 @@ function TagComponent(props) {
|
|
|
231
232
|
text={val.text}
|
|
232
233
|
onView={() => onView(val)}
|
|
233
234
|
onDelete={!isViewOnly ? () => onDelete(val) : null}
|
|
235
|
+
showEye={showEye}
|
|
234
236
|
/>;
|
|
235
237
|
});
|
|
236
238
|
|
|
@@ -14,6 +14,7 @@ export default function ValueBox(props) {
|
|
|
14
14
|
text,
|
|
15
15
|
onView,
|
|
16
16
|
onDelete,
|
|
17
|
+
showEye,
|
|
17
18
|
} = props,
|
|
18
19
|
styles = UiGlobals.styles;
|
|
19
20
|
return <HStackNative
|
|
@@ -30,25 +31,26 @@ export default function ValueBox(props) {
|
|
|
30
31
|
${!onDelete && 'pr-4'}
|
|
31
32
|
`}
|
|
32
33
|
>
|
|
33
|
-
<IconButton
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
34
|
+
{showEye && <IconButton
|
|
35
|
+
{...testProps('eyeBtn')}
|
|
36
|
+
icon={Eye}
|
|
37
|
+
_icon={{
|
|
38
|
+
size: styles.FORM_TAG_VALUEBOX_ICON_SIZE,
|
|
39
|
+
className: 'text-grey-600',
|
|
40
|
+
}}
|
|
41
|
+
onPress={onView}
|
|
42
|
+
className={`
|
|
43
|
+
ValueBox-eyeBtn
|
|
44
|
+
h-full
|
|
45
|
+
${styles.FORM_TAG_BTN_CLASSNAME}
|
|
46
|
+
`}
|
|
47
|
+
/>}
|
|
47
48
|
<Text
|
|
48
49
|
className={`
|
|
49
50
|
ValueBox-Text
|
|
50
51
|
text-grey-600
|
|
51
52
|
${styles.FORM_TAG_VALUEBOX_CLASSNAME}
|
|
53
|
+
${showEye ? 'ml-0' : 'ml-1'}
|
|
52
54
|
${onDelete ? 'mr-0' : 'mr-1'}
|
|
53
55
|
`}
|
|
54
56
|
>{text}</Text>
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
Icon,
|
|
5
5
|
Pressable,
|
|
6
6
|
Switch,
|
|
7
|
-
|
|
7
|
+
TextNative,
|
|
8
8
|
} from '@project-components/Gluestack';
|
|
9
9
|
import UiGlobals from '../../../UiGlobals.js';
|
|
10
10
|
import IconButton from '../../Buttons/IconButton.js';
|
|
@@ -96,14 +96,14 @@ const
|
|
|
96
96
|
{...testProps('readoutBtn')}
|
|
97
97
|
onPress={onToggle}
|
|
98
98
|
>
|
|
99
|
-
<
|
|
99
|
+
<TextNative
|
|
100
100
|
{...testProps('readout')}
|
|
101
101
|
className={`
|
|
102
102
|
ml-1
|
|
103
103
|
mr-2
|
|
104
104
|
${styles.FORM_TOGGLE_READOUT_CLASSNAME}
|
|
105
105
|
`}
|
|
106
|
-
>{_.isNil(value) ? 'N/A' : (!!value ? onText : offText)}</
|
|
106
|
+
>{_.isNil(value) ? 'N/A' : (!!value ? onText : offText)}</TextNative>
|
|
107
107
|
</Pressable>
|
|
108
108
|
</HStack>;
|
|
109
109
|
},
|
|
@@ -471,6 +471,7 @@ function Form(props) {
|
|
|
471
471
|
isEditable = true,
|
|
472
472
|
isEditingEnabledInPlainEditor,
|
|
473
473
|
label,
|
|
474
|
+
labelWidth,
|
|
474
475
|
items,
|
|
475
476
|
onChange: onEditorChange,
|
|
476
477
|
useSelectorId = false,
|
|
@@ -647,9 +648,12 @@ function Form(props) {
|
|
|
647
648
|
if (defaults?.labelWidth) {
|
|
648
649
|
style.width = defaults.labelWidth;
|
|
649
650
|
}
|
|
651
|
+
if (labelWidth) {
|
|
652
|
+
style.width = labelWidth;
|
|
653
|
+
}
|
|
650
654
|
if (containerWidth > styles.FORM_STACK_ROW_THRESHOLD) {
|
|
651
655
|
if (!style.width) {
|
|
652
|
-
style.width = '
|
|
656
|
+
style.width = '160px';
|
|
653
657
|
}
|
|
654
658
|
element = <HStack className="Form-HStack1 w-full py-1">
|
|
655
659
|
<Label style={style}>{label}</Label>
|
|
@@ -778,7 +782,7 @@ function Form(props) {
|
|
|
778
782
|
if (message) {
|
|
779
783
|
message = <Text className="text-[#f00]">{message}</Text>;
|
|
780
784
|
}
|
|
781
|
-
element = <VStack className="Form-VStack4
|
|
785
|
+
element = <VStack className="Form-VStack4 flex-1 pt-1">
|
|
782
786
|
{element}
|
|
783
787
|
{message}
|
|
784
788
|
</VStack>;
|
|
@@ -786,14 +790,14 @@ function Form(props) {
|
|
|
786
790
|
if (item.additionalEditButtons) {
|
|
787
791
|
const buttons = buildAdditionalButtons(item.additionalEditButtons, self, { fieldState, formSetValue, formGetValues, formState });
|
|
788
792
|
if (containerWidth > styles.FORM_STACK_ROW_THRESHOLD) {
|
|
789
|
-
element = <HStack className="Form-HStack5
|
|
793
|
+
element = <HStack className="Form-HStack5 flex-1 flex-wrap">
|
|
790
794
|
{element}
|
|
791
795
|
{buttons}
|
|
792
796
|
</HStack>;
|
|
793
797
|
} else {
|
|
794
|
-
element = <VStack className="Form-VStack6
|
|
798
|
+
element = <VStack className="Form-VStack6 flex-1">
|
|
795
799
|
{element}
|
|
796
|
-
<HStack className="Form-HStack7-VStack
|
|
800
|
+
<HStack className="Form-HStack7-VStack flex-1 mt-1 flex-wrap">
|
|
797
801
|
{buttons}
|
|
798
802
|
</HStack>
|
|
799
803
|
</VStack>;
|
|
@@ -831,9 +835,12 @@ function Form(props) {
|
|
|
831
835
|
if (defaults?.labelWidth) {
|
|
832
836
|
style.width = defaults.labelWidth;
|
|
833
837
|
}
|
|
838
|
+
if (labelWidth) {
|
|
839
|
+
style.width = labelWidth;
|
|
840
|
+
}
|
|
834
841
|
if (containerWidth > styles.FORM_STACK_ROW_THRESHOLD) {
|
|
835
842
|
if (!style.width) {
|
|
836
|
-
style.width = '
|
|
843
|
+
style.width = '160px';
|
|
837
844
|
}
|
|
838
845
|
element = <HStack className="Form-HStack8 w-full">
|
|
839
846
|
<Label style={style}>
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
UPLOAD_DOWNLOAD,
|
|
13
13
|
} from '../../Constants/Commands.js';
|
|
14
14
|
import UiGlobals from '../../UiGlobals.js';
|
|
15
|
+
import oneHatData from '@onehat/data';
|
|
15
16
|
import _ from 'lodash';
|
|
16
17
|
|
|
17
18
|
/**
|
|
@@ -22,11 +23,23 @@ import _ from 'lodash';
|
|
|
22
23
|
export function checkPermission(permission) {
|
|
23
24
|
const
|
|
24
25
|
reduxState = UiGlobals.redux?.getState(),
|
|
25
|
-
permissions = reduxState?.app?.permissions;
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
permissions = reduxState?.app?.permissions || [];
|
|
27
|
+
let hasPermission = inArray(permission, permissions);
|
|
28
|
+
if (hasPermission) {
|
|
29
|
+
return true;
|
|
28
30
|
}
|
|
29
|
-
|
|
31
|
+
// check for anonymous get
|
|
32
|
+
const matches = permission.match(/^view_(.*)$/);
|
|
33
|
+
if (matches) {
|
|
34
|
+
const
|
|
35
|
+
name = Inflector.camelize(matches[1]), // 'pm_events' -> 'PmEvents'
|
|
36
|
+
repository = oneHatData.getRepository(name),
|
|
37
|
+
allowAnonymousGet = repository?.schema.repository.allowAnonymousGet;
|
|
38
|
+
if (allowAnonymousGet) {
|
|
39
|
+
hasPermission = true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return hasPermission;
|
|
30
43
|
}
|
|
31
44
|
|
|
32
45
|
/**
|
|
@@ -45,10 +45,14 @@ export default function Header(props) {
|
|
|
45
45
|
self-center
|
|
46
46
|
border
|
|
47
47
|
border-grey-400
|
|
48
|
+
h-[20px]
|
|
49
|
+
w-[20px]
|
|
50
|
+
px-[2px]
|
|
51
|
+
py-[2px]
|
|
48
52
|
${styles.PANEL_HEADER_BG}
|
|
49
53
|
`;
|
|
50
|
-
if (collapseDirection
|
|
51
|
-
closeClassName += '
|
|
54
|
+
if (collapseDirection === HORIZONTAL && isCollapsed) {
|
|
55
|
+
closeClassName += ' mb-1';
|
|
52
56
|
}
|
|
53
57
|
closeBtn = <IconButton
|
|
54
58
|
onPress={onClose}
|
|
@@ -66,10 +70,14 @@ export default function Header(props) {
|
|
|
66
70
|
self-center
|
|
67
71
|
border
|
|
68
72
|
border-grey-400
|
|
73
|
+
h-[20px]
|
|
74
|
+
w-[20px]
|
|
75
|
+
px-[2px]
|
|
76
|
+
py-[2px]
|
|
69
77
|
${styles.PANEL_HEADER_BG}
|
|
70
78
|
`;
|
|
71
|
-
if (collapseDirection
|
|
72
|
-
collapseClassName += '
|
|
79
|
+
if (collapseDirection === HORIZONTAL && isCollapsed) {
|
|
80
|
+
collapseClassName += ' mb-1';
|
|
73
81
|
}
|
|
74
82
|
collapseBtn = <IconButton
|
|
75
83
|
onPress={onToggleCollapse}
|
|
@@ -138,6 +146,7 @@ export default function Header(props) {
|
|
|
138
146
|
</div>;
|
|
139
147
|
}
|
|
140
148
|
}
|
|
149
|
+
panelClassName += ' gap-2';
|
|
141
150
|
if (closeBtn) {
|
|
142
151
|
panelClassName += ' pl-[4px] pr-3';
|
|
143
152
|
} else {
|
|
@@ -217,6 +226,7 @@ export default function Header(props) {
|
|
|
217
226
|
</Pressable>;
|
|
218
227
|
}
|
|
219
228
|
}
|
|
229
|
+
panelClassName += ' gap-2';
|
|
220
230
|
if (closeBtn) {
|
|
221
231
|
panelClassName += ' pl-[4px] pr-3';
|
|
222
232
|
} else {
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
Pressable,
|
|
5
5
|
ScrollView,
|
|
6
6
|
VStack,
|
|
7
|
+
VStackNative,
|
|
7
8
|
} from '@project-components/Gluestack';
|
|
8
9
|
import {
|
|
9
10
|
SELECTION_MODE_SINGLE,
|
|
@@ -49,6 +50,7 @@ import Collapse from '../Icons/Collapse.js';
|
|
|
49
50
|
import Expand from '../Icons/Expand.js';
|
|
50
51
|
import FolderClosed from '../Icons/FolderClosed.js';
|
|
51
52
|
import FolderOpen from '../Icons/FolderOpen.js';
|
|
53
|
+
import Gear from '../Icons/Gear.js';
|
|
52
54
|
import MagnifyingGlass from '../Icons/MagnifyingGlass.js';
|
|
53
55
|
import NoReorderRows from '../Icons/NoReorderRows.js';
|
|
54
56
|
import ReorderRows from '../Icons/ReorderRows.js';
|
|
@@ -71,6 +73,8 @@ function TreeComponent(props) {
|
|
|
71
73
|
areRootsVisible = true,
|
|
72
74
|
autoLoadRootNodes = true,
|
|
73
75
|
extraParams = {}, // Additional params to send with each request ( e.g. { order: 'Categories.name ASC' })
|
|
76
|
+
isNodeTextConfigurable = false,
|
|
77
|
+
editDisplaySettings, // fn
|
|
74
78
|
getNodeText = (item) => { // extracts model/data and decides what the row text should be
|
|
75
79
|
if (Repository) {
|
|
76
80
|
return item.displayValue;
|
|
@@ -198,8 +202,7 @@ function TreeComponent(props) {
|
|
|
198
202
|
return;
|
|
199
203
|
}
|
|
200
204
|
|
|
201
|
-
const
|
|
202
|
-
{
|
|
205
|
+
const {
|
|
203
206
|
shiftKey,
|
|
204
207
|
metaKey,
|
|
205
208
|
} = e;
|
|
@@ -467,7 +470,7 @@ function TreeComponent(props) {
|
|
|
467
470
|
</VStack>,
|
|
468
471
|
onCancel: hideModal,
|
|
469
472
|
});
|
|
470
|
-
}
|
|
473
|
+
},
|
|
471
474
|
|
|
472
475
|
// utilities
|
|
473
476
|
getNodeData = (id) => {
|
|
@@ -508,7 +511,7 @@ function TreeComponent(props) {
|
|
|
508
511
|
datum = {
|
|
509
512
|
item: treeNode,
|
|
510
513
|
text: getNodeText(treeNode),
|
|
511
|
-
content: getNodeContent(treeNode),
|
|
514
|
+
content: getNodeContent ? getNodeContent(treeNode) : null,
|
|
512
515
|
iconCollapsed: getNodeIcon(COLLAPSED, treeNode),
|
|
513
516
|
iconExpanded: getNodeIcon(EXPANDED, treeNode),
|
|
514
517
|
iconLeaf: getNodeIcon(LEAF, treeNode),
|
|
@@ -877,13 +880,13 @@ function TreeComponent(props) {
|
|
|
877
880
|
getHeaderToolbarItems = () => {
|
|
878
881
|
const
|
|
879
882
|
buttons = [
|
|
880
|
-
{
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
},
|
|
883
|
+
// {
|
|
884
|
+
// key: 'searchBtn',
|
|
885
|
+
// text: 'Search tree',
|
|
886
|
+
// handler: () => onSearchTree(treeSearchValue),
|
|
887
|
+
// icon: MagnifyingGlass,
|
|
888
|
+
// isDisabled: !treeSearchValue.length,
|
|
889
|
+
// },
|
|
887
890
|
{
|
|
888
891
|
key: 'collapseAllBtn',
|
|
889
892
|
text: 'Collapse whole tree',
|
|
@@ -910,33 +913,41 @@ function TreeComponent(props) {
|
|
|
910
913
|
isDisabled: false,
|
|
911
914
|
});
|
|
912
915
|
}
|
|
916
|
+
if (isNodeTextConfigurable && editDisplaySettings) {
|
|
917
|
+
buttons.push({
|
|
918
|
+
key: 'editNodeTextBtn',
|
|
919
|
+
text: 'Display Settings',
|
|
920
|
+
handler: () => editDisplaySettings(),
|
|
921
|
+
icon: Gear,
|
|
922
|
+
});
|
|
923
|
+
}
|
|
913
924
|
const items = _.map(buttons, (config, ix) => getIconButtonFromConfig(config, ix, self));
|
|
914
925
|
|
|
915
|
-
items.unshift(<Input // Add text input to beginning of header items
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
/>);
|
|
928
|
-
|
|
929
|
-
if (treeSearchValue.length) {
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
}
|
|
926
|
+
// items.unshift(<Input // Add text input to beginning of header items
|
|
927
|
+
// key="searchNodes"
|
|
928
|
+
// className="flex-1"
|
|
929
|
+
// placeholder="Find tree node"
|
|
930
|
+
// onChangeText={(val) => setTreeSearchValue(val)}
|
|
931
|
+
// onKeyPress={(e) => {
|
|
932
|
+
// if (e.key === 'Enter') {
|
|
933
|
+
// onSearchTree(treeSearchValue);
|
|
934
|
+
// }
|
|
935
|
+
// }}
|
|
936
|
+
// value={treeSearchValue}
|
|
937
|
+
// autoSubmit={false}
|
|
938
|
+
// />);
|
|
939
|
+
|
|
940
|
+
// if (treeSearchValue.length) {
|
|
941
|
+
// // Add 'X' button to clear search
|
|
942
|
+
// items.unshift(getIconButtonFromConfig({
|
|
943
|
+
// key: 'xBtn',
|
|
944
|
+
// handler: () => {
|
|
945
|
+
// setHighlitedDatum(null);
|
|
946
|
+
// setTreeSearchValue('');
|
|
947
|
+
// },
|
|
948
|
+
// icon: Xmark,
|
|
949
|
+
// }, 0, self));
|
|
950
|
+
// }
|
|
940
951
|
|
|
941
952
|
return items;
|
|
942
953
|
},
|
|
@@ -1310,6 +1321,8 @@ function TreeComponent(props) {
|
|
|
1310
1321
|
self.reloadTree = reloadTree;
|
|
1311
1322
|
self.expandPath = expandPath;
|
|
1312
1323
|
self.scrollToNode = scrollToNode;
|
|
1324
|
+
self.buildAndSetTreeNodeData = buildAndSetTreeNodeData;
|
|
1325
|
+
self.forceUpdate = forceUpdate;
|
|
1313
1326
|
}
|
|
1314
1327
|
|
|
1315
1328
|
const
|
|
@@ -1364,7 +1377,7 @@ function TreeComponent(props) {
|
|
|
1364
1377
|
className += ' ' + props.className;
|
|
1365
1378
|
}
|
|
1366
1379
|
|
|
1367
|
-
return <
|
|
1380
|
+
return <VStackNative
|
|
1368
1381
|
{...testProps(self)}
|
|
1369
1382
|
className={className}
|
|
1370
1383
|
>
|
|
@@ -1392,7 +1405,7 @@ function TreeComponent(props) {
|
|
|
1392
1405
|
|
|
1393
1406
|
{treeFooterComponent}
|
|
1394
1407
|
|
|
1395
|
-
</
|
|
1408
|
+
</VStackNative>;
|
|
1396
1409
|
|
|
1397
1410
|
}
|
|
1398
1411
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useMemo, } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Box,
|
|
4
|
-
|
|
4
|
+
HStackNative,
|
|
5
5
|
Icon,
|
|
6
6
|
Spinner,
|
|
7
7
|
TextNative,
|
|
@@ -68,7 +68,6 @@ export default function TreeNode(props) {
|
|
|
68
68
|
let className = `
|
|
69
69
|
TreeNode
|
|
70
70
|
items-center
|
|
71
|
-
flex
|
|
72
71
|
flex-1
|
|
73
72
|
grow-1
|
|
74
73
|
`;
|
|
@@ -76,7 +75,7 @@ export default function TreeNode(props) {
|
|
|
76
75
|
className += ' ' + props.className;
|
|
77
76
|
}
|
|
78
77
|
|
|
79
|
-
return <
|
|
78
|
+
return <HStackNative
|
|
80
79
|
{...testProps('node' + (isSelected ? '-selected' : ''))}
|
|
81
80
|
{...nodeProps}
|
|
82
81
|
key={hash}
|
|
@@ -89,7 +88,7 @@ export default function TreeNode(props) {
|
|
|
89
88
|
|
|
90
89
|
{isLoading ?
|
|
91
90
|
<Spinner className="px-2" /> :
|
|
92
|
-
(hasChildren && !isDragMode ?
|
|
91
|
+
(icon && hasChildren && !isDragMode ?
|
|
93
92
|
<IconButton
|
|
94
93
|
{...testProps('expandBtn')}
|
|
95
94
|
icon={icon}
|
|
@@ -115,7 +114,7 @@ export default function TreeNode(props) {
|
|
|
115
114
|
|
|
116
115
|
{content}
|
|
117
116
|
|
|
118
|
-
</
|
|
117
|
+
</HStackNative>;
|
|
119
118
|
}, [
|
|
120
119
|
nodeProps,
|
|
121
120
|
bg,
|