@onehat/ui 0.4.62 → 0.4.65
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/Container/ContainerColumn.js +21 -0
- package/src/Components/Form/Field/Combo/Combo.js +1 -0
- package/src/Components/Form/Field/Json.js +3 -3
- package/src/Components/Form/Field/Tag/Tag.js +2 -2
- package/src/Components/Form/Form.js +3 -2
- package/src/Components/Grid/Grid.js +5 -2
- package/src/Components/Grid/GridHeaderRow.js +10 -0
- package/src/Components/Grid/GridRow.js +4 -0
- package/src/Components/Grid/RowDragHandle.js +4 -5
- package/src/Components/Grid/RowSelectHandle.js +18 -0
- package/src/Components/Hoc/withEditor.js +16 -0
- package/src/Components/Hoc/withPresetButtons.js +31 -13
- package/src/Components/Icons/ArrowPointer.js +11 -0
- package/src/Components/Layout/AsyncOperation.js +36 -6
- package/src/Components/Report/Report.js +54 -0
- package/src/Components/Window/UploadsDownloadsWindow.js +57 -52
- package/src/Components/index.js +4 -0
- package/src/Constants/Commands.js +1 -0
package/package.json
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VStack,
|
|
3
|
+
} from '@project-components/Gluestack';
|
|
4
|
+
import _ from 'lodash';
|
|
5
|
+
|
|
6
|
+
// This component allows us to stack multiple children in a Container slot (e.g. east)
|
|
7
|
+
// such that the ContainerColumn can be passed props like isResizable,
|
|
8
|
+
// which the Container will translate into classNames for the VStack component.
|
|
9
|
+
|
|
10
|
+
export default function ContainerColumn(props) {
|
|
11
|
+
let className = `
|
|
12
|
+
ContainerColumn
|
|
13
|
+
`;
|
|
14
|
+
if (props.className) {
|
|
15
|
+
className += ` ${props.className}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return <VStack className={className}>
|
|
19
|
+
{props.children}
|
|
20
|
+
</VStack>;
|
|
21
|
+
}
|
|
@@ -767,6 +767,7 @@ export const ComboComponent = forwardRef((props, ref) => {
|
|
|
767
767
|
newEntityDisplayProperty={newEntityDisplayProperty}
|
|
768
768
|
disablePresetButtons={!isEditor}
|
|
769
769
|
alternateRowBackgrounds={false}
|
|
770
|
+
showSelectHandle={false}
|
|
770
771
|
onChangeSelection={(selection) => {
|
|
771
772
|
|
|
772
773
|
if (Repository && selection[0]?.isPhantom) {
|
|
@@ -46,12 +46,12 @@ export function JsonElement(props) {
|
|
|
46
46
|
${testID}
|
|
47
47
|
`;
|
|
48
48
|
if (props.className) {
|
|
49
|
-
className += ' ' +
|
|
49
|
+
className += ' ' + propsToPass.className;
|
|
50
50
|
}
|
|
51
51
|
// if (UiGlobals.mode === UI_MODE_WEB) {
|
|
52
52
|
const src = value ? JSON.parse(value) : {};
|
|
53
53
|
assembledComponents =
|
|
54
|
-
<HStack style={
|
|
54
|
+
<HStack style={propsToPass.style} className={className}>
|
|
55
55
|
<JsonEditor
|
|
56
56
|
width="100%"
|
|
57
57
|
editable={!isViewOnly}
|
|
@@ -61,7 +61,7 @@ export function JsonElement(props) {
|
|
|
61
61
|
onEdit={(obj) => {
|
|
62
62
|
setValue(JSON.stringify(obj.updated_src));
|
|
63
63
|
}}
|
|
64
|
-
{...
|
|
64
|
+
{...propsToPass}
|
|
65
65
|
/>
|
|
66
66
|
</HStack>;
|
|
67
67
|
// }
|
|
@@ -61,8 +61,8 @@ function TagComponent(props) {
|
|
|
61
61
|
await repository.waitUntilDoneLoading();
|
|
62
62
|
}
|
|
63
63
|
let record = repository.getById(id); // first try to get from entities in memory
|
|
64
|
-
if (!record && repository.
|
|
65
|
-
record = await repository.
|
|
64
|
+
if (!record && repository.loadOneAdditionalEntity) {
|
|
65
|
+
record = await repository.loadOneAdditionalEntity(id);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
if (!record) {
|
|
@@ -83,6 +83,7 @@ function Form(props) {
|
|
|
83
83
|
editorType = EDITOR_TYPE__WINDOWED, // EDITOR_TYPE__INLINE | EDITOR_TYPE__WINDOWED | EDITOR_TYPE__SIDE | EDITOR_TYPE__SMART | EDITOR_TYPE__PLAIN
|
|
84
84
|
startingValues = {},
|
|
85
85
|
items = [], // Columns, FieldSets, Fields, etc to define the form
|
|
86
|
+
isItemsCustomLayout = false,
|
|
86
87
|
ancillaryItems = [], // additional items which are not controllable form elements, but should appear in the form
|
|
87
88
|
showAncillaryButtons = false,
|
|
88
89
|
columnDefaults = {}, // defaults for each Column defined in items (above)
|
|
@@ -1187,8 +1188,8 @@ function Form(props) {
|
|
|
1187
1188
|
formComponents = buildFromItems();
|
|
1188
1189
|
const formAncillaryComponents = buildAncillary();
|
|
1189
1190
|
editor = <>
|
|
1190
|
-
{containerWidth >= styles.FORM_ONE_COLUMN_THRESHOLD ? <HStack className="Form-formComponents-HStack p-4 gap-4 justify-center">{formComponents}</HStack> : null}
|
|
1191
|
-
{containerWidth < styles.FORM_ONE_COLUMN_THRESHOLD ? <VStack className="Form-formComponents-VStack p-4">{formComponents}</VStack> : null}
|
|
1191
|
+
{containerWidth >= styles.FORM_ONE_COLUMN_THRESHOLD && !isItemsCustomLayout ? <HStack className="Form-formComponents-HStack p-4 gap-4 justify-center">{formComponents}</HStack> : null}
|
|
1192
|
+
{containerWidth < styles.FORM_ONE_COLUMN_THRESHOLD || isItemsCustomLayout ? <VStack className="Form-formComponents-VStack p-4">{formComponents}</VStack> : null}
|
|
1192
1193
|
{formAncillaryComponents.length ? <VStack className="Form-AncillaryComponents m-2 pt-4 px-2">{formAncillaryComponents}</VStack> : null}
|
|
1193
1194
|
</>;
|
|
1194
1195
|
|
|
@@ -132,6 +132,7 @@ function GridComponent(props) {
|
|
|
132
132
|
getExpandedRowContent,
|
|
133
133
|
showHeaders = true,
|
|
134
134
|
showHovers = true,
|
|
135
|
+
showSelectHandle = true,
|
|
135
136
|
canColumnsSort = true,
|
|
136
137
|
canColumnsReorder = true,
|
|
137
138
|
canColumnsResize = true,
|
|
@@ -424,10 +425,10 @@ function GridComponent(props) {
|
|
|
424
425
|
} else {
|
|
425
426
|
let canDoEdit = false,
|
|
426
427
|
canDoView = false;
|
|
427
|
-
if (onEdit && canUser && canUser(EDIT) && (!canRecordBeEdited || canRecordBeEdited(selection))) {
|
|
428
|
+
if (onEdit && canUser && canUser(EDIT) && (!canRecordBeEdited || canRecordBeEdited(selection)) && !props.disableEdit) {
|
|
428
429
|
canDoEdit = true;
|
|
429
430
|
} else
|
|
430
|
-
if (onView && canUser && canUser(VIEW)) {
|
|
431
|
+
if (onView && canUser && canUser(VIEW) && !props.disableView) {
|
|
431
432
|
canDoView = true;
|
|
432
433
|
}
|
|
433
434
|
|
|
@@ -493,6 +494,7 @@ function GridComponent(props) {
|
|
|
493
494
|
isInlineEditorShown={isInlineEditorShown}
|
|
494
495
|
areRowsDragSource={areRowsDragSource}
|
|
495
496
|
showColumnsSelector={showColumnsSelector}
|
|
497
|
+
showSelectHandle={showSelectHandle}
|
|
496
498
|
/>;
|
|
497
499
|
if (showRowExpander) {
|
|
498
500
|
// align the header row to content rows by adding a spacer that matches the width of the Grid-rowExpander-expandBtn
|
|
@@ -570,6 +572,7 @@ function GridComponent(props) {
|
|
|
570
572
|
isSelected={isSelected}
|
|
571
573
|
isHovered={hovered}
|
|
572
574
|
showHovers={showHovers}
|
|
575
|
+
showSelectHandle={showSelectHandle}
|
|
573
576
|
index={index}
|
|
574
577
|
alternatingInterval={alternatingInterval}
|
|
575
578
|
alternateRowBackgrounds={alternateRowBackgrounds}
|
|
@@ -20,6 +20,7 @@ import UiGlobals from '../../UiGlobals.js';
|
|
|
20
20
|
import useBlocking from '../../Hooks/useBlocking.js';
|
|
21
21
|
import testProps from '../../Functions/testProps.js';
|
|
22
22
|
import AngleRight from '../Icons/AngleRight.js';
|
|
23
|
+
import ArrowPointer from '../Icons/ArrowPointer.js';
|
|
23
24
|
import HeaderReorderHandle from './HeaderReorderHandle.js';
|
|
24
25
|
import HeaderResizeHandle from './HeaderResizeHandle.js';
|
|
25
26
|
import HeaderColumnSelectorHandle from './HeaderColumnSelectorHandle.js';
|
|
@@ -46,6 +47,7 @@ export default function GridHeaderRow(props) {
|
|
|
46
47
|
isInlineEditorShown,
|
|
47
48
|
areRowsDragSource,
|
|
48
49
|
showColumnsSelector,
|
|
50
|
+
showSelectHandle,
|
|
49
51
|
} = props,
|
|
50
52
|
styles = UiGlobals.styles,
|
|
51
53
|
sortFn = Repository && Repository.getSortFn(),
|
|
@@ -462,6 +464,14 @@ export default function GridHeaderRow(props) {
|
|
|
462
464
|
/>}
|
|
463
465
|
</Pressable>;
|
|
464
466
|
});
|
|
467
|
+
if (showSelectHandle) {
|
|
468
|
+
headerColumns.unshift(<Box
|
|
469
|
+
key="RowSelectHandle"
|
|
470
|
+
className="Spacer-RowSelectHandle px-2 items-center justify-center flex-none w-[40px]"
|
|
471
|
+
>
|
|
472
|
+
<Icon as={ArrowPointer} className={`ArrowPointer w-[20px] h-[20px] text-[#aaa]`} />
|
|
473
|
+
</Box>);
|
|
474
|
+
}
|
|
465
475
|
if (areRowsDragSource) {
|
|
466
476
|
headerColumns.unshift(<Box
|
|
467
477
|
key="spacer"
|
|
@@ -16,6 +16,7 @@ import { withDragSource, withDropTarget } from '../Hoc/withDnd.js';
|
|
|
16
16
|
import testProps from '../../Functions/testProps.js';
|
|
17
17
|
import AngleRight from '../Icons/AngleRight.js';
|
|
18
18
|
import RowDragHandle from './RowDragHandle.js';
|
|
19
|
+
import RowSelectHandle from './RowSelectHandle.js';
|
|
19
20
|
import _ from 'lodash';
|
|
20
21
|
|
|
21
22
|
// This was broken out from Grid simply so we can memoize it
|
|
@@ -27,6 +28,7 @@ function GridRow(props) {
|
|
|
27
28
|
fields,
|
|
28
29
|
rowProps,
|
|
29
30
|
hideNavColumn,
|
|
31
|
+
showSelectHandle,
|
|
30
32
|
isSelected,
|
|
31
33
|
isHovered,
|
|
32
34
|
bg,
|
|
@@ -265,6 +267,8 @@ function GridRow(props) {
|
|
|
265
267
|
|
|
266
268
|
let rowContents = <>
|
|
267
269
|
{(isDragSource || isDraggable) && <RowDragHandle />}
|
|
270
|
+
{showSelectHandle && <RowSelectHandle />}
|
|
271
|
+
|
|
268
272
|
{isPhantom &&
|
|
269
273
|
<Box
|
|
270
274
|
className={`
|
|
@@ -5,11 +5,10 @@ import {
|
|
|
5
5
|
import styles from '../../Styles/StyleSheets.js';
|
|
6
6
|
import GripVertical from '../Icons/GripVertical.js';
|
|
7
7
|
|
|
8
|
-
function RowDragHandle(props) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
>
|
|
8
|
+
function RowDragHandle(props) { return <VStack
|
|
9
|
+
style={styles.ewResize}
|
|
10
|
+
className="RowDragHandle bg-grey-100 w-[3px] items-center justify-center select-none"
|
|
11
|
+
>
|
|
13
12
|
<Icon
|
|
14
13
|
as={GripVertical}
|
|
15
14
|
size="xs"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Icon,
|
|
3
|
+
VStack,
|
|
4
|
+
} from '@project-components/Gluestack';
|
|
5
|
+
import ArrowPointer from '../Icons/ArrowPointer.js';
|
|
6
|
+
|
|
7
|
+
function RowSelectHandle(props) {
|
|
8
|
+
return <VStack
|
|
9
|
+
className="RowSelectHandle w-[40px] px-2 items-center justify-center select-none cursor-grab"
|
|
10
|
+
>
|
|
11
|
+
<Icon
|
|
12
|
+
as={ArrowPointer}
|
|
13
|
+
size="xs"
|
|
14
|
+
className="w-[20px] h-[20px] text-[#ddd]" />
|
|
15
|
+
</VStack>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default RowSelectHandle;
|
|
@@ -29,6 +29,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
29
29
|
userCanEdit = true, // not permissions, but capability
|
|
30
30
|
userCanView = true,
|
|
31
31
|
canEditorViewOnly = false, // whether the editor can *ever* change state out of 'View' mode
|
|
32
|
+
canProceedWithCrud, // fn returns bool on if the CRUD operation can proceed
|
|
32
33
|
disableAdd = false,
|
|
33
34
|
disableEdit = false,
|
|
34
35
|
disableDelete = false,
|
|
@@ -153,6 +154,9 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
153
154
|
showPermissionsError(ADD);
|
|
154
155
|
return;
|
|
155
156
|
}
|
|
157
|
+
if (canProceedWithCrud && !canProceedWithCrud()) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
156
160
|
|
|
157
161
|
const selection = getSelection();
|
|
158
162
|
let addValues = values;
|
|
@@ -252,6 +256,9 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
252
256
|
showPermissionsError(EDIT);
|
|
253
257
|
return;
|
|
254
258
|
}
|
|
259
|
+
if (canProceedWithCrud && !canProceedWithCrud()) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
255
262
|
const selection = getSelection();
|
|
256
263
|
if (_.isEmpty(selection) || (_.isArray(selection) && (selection.length > 1 || selection[0]?.isDestroyed))) {
|
|
257
264
|
return;
|
|
@@ -271,6 +278,9 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
271
278
|
showPermissionsError(DELETE);
|
|
272
279
|
return;
|
|
273
280
|
}
|
|
281
|
+
if (canProceedWithCrud && !canProceedWithCrud()) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
274
284
|
let cb = null;
|
|
275
285
|
if (_.isFunction(args)) {
|
|
276
286
|
cb = args;
|
|
@@ -368,6 +378,9 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
368
378
|
showPermissionsError(VIEW);
|
|
369
379
|
return;
|
|
370
380
|
}
|
|
381
|
+
if (canProceedWithCrud && !canProceedWithCrud()) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
371
384
|
if (editorType === EDITOR_TYPE__INLINE) {
|
|
372
385
|
alert('Cannot view in inline editor.');
|
|
373
386
|
return; // inline editor doesn't have a view mode
|
|
@@ -395,6 +408,9 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
395
408
|
showPermissionsError(DUPLICATE);
|
|
396
409
|
return;
|
|
397
410
|
}
|
|
411
|
+
if (canProceedWithCrud && !canProceedWithCrud()) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
398
414
|
|
|
399
415
|
const selection = getSelection();
|
|
400
416
|
if (selection.length !== 1) {
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
DUPLICATE,
|
|
9
9
|
PRINT,
|
|
10
10
|
UPLOAD_DOWNLOAD,
|
|
11
|
+
DOWNLOAD,
|
|
11
12
|
} from '../../Constants/Commands.js';
|
|
12
13
|
import Clipboard from '../Icons/Clipboard.js';
|
|
13
14
|
import Duplicate from '../Icons/Duplicate.js';
|
|
@@ -17,6 +18,7 @@ import Trash from '../Icons/Trash.js';
|
|
|
17
18
|
import Plus from '../Icons/Plus.js';
|
|
18
19
|
import Print from '../Icons/Print.js';
|
|
19
20
|
import UploadDownload from '../Icons/UploadDownload.js';
|
|
21
|
+
import Download from '../Icons/Download.js';
|
|
20
22
|
import inArray from '../../Functions/inArray.js';
|
|
21
23
|
import UploadsDownloadsWindow from '../Window/UploadsDownloadsWindow.js';
|
|
22
24
|
import _ from 'lodash';
|
|
@@ -33,6 +35,7 @@ const presetButtons = [
|
|
|
33
35
|
DUPLICATE,
|
|
34
36
|
// PRINT,
|
|
35
37
|
UPLOAD_DOWNLOAD,
|
|
38
|
+
DOWNLOAD,
|
|
36
39
|
];
|
|
37
40
|
|
|
38
41
|
export default function withPresetButtons(WrappedComponent, isGrid = false) {
|
|
@@ -48,6 +51,7 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
|
|
|
48
51
|
contextMenuItems = [],
|
|
49
52
|
additionalToolbarButtons = [],
|
|
50
53
|
useUploadDownload = false,
|
|
54
|
+
useDownload = false,
|
|
51
55
|
uploadHeaders,
|
|
52
56
|
uploadParams,
|
|
53
57
|
onUpload,
|
|
@@ -57,7 +61,6 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
|
|
|
57
61
|
canRecordBeEdited,
|
|
58
62
|
canRecordBeDeleted,
|
|
59
63
|
canRecordBeDuplicated,
|
|
60
|
-
canProceedWithCrud, // fn returns bool on if the CRUD operation can proceed
|
|
61
64
|
...propsToPass
|
|
62
65
|
} = props,
|
|
63
66
|
{
|
|
@@ -177,6 +180,13 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
|
|
|
177
180
|
isDisabled = true;
|
|
178
181
|
}
|
|
179
182
|
break;
|
|
183
|
+
case DOWNLOAD:
|
|
184
|
+
if (!useDownload) {
|
|
185
|
+
isDisabled = true;
|
|
186
|
+
} else if (canUser && !(canUser(DOWNLOAD) || canUser(UPLOAD_DOWNLOAD))) { // check Permissions
|
|
187
|
+
isDisabled = true;
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
180
190
|
default:
|
|
181
191
|
}
|
|
182
192
|
return isDisabled;
|
|
@@ -211,9 +221,6 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
|
|
|
211
221
|
key = 'addBtn';
|
|
212
222
|
text = 'Add';
|
|
213
223
|
handler = (parent, e) => {
|
|
214
|
-
if (canProceedWithCrud && !canProceedWithCrud()) {
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
224
|
onAdd();
|
|
218
225
|
};
|
|
219
226
|
icon = Plus;
|
|
@@ -227,9 +234,6 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
|
|
|
227
234
|
key = 'editBtn';
|
|
228
235
|
text = 'Edit';
|
|
229
236
|
handler = (parent, e) => {
|
|
230
|
-
if (canProceedWithCrud && !canProceedWithCrud()) {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
237
|
onEdit();
|
|
234
238
|
};
|
|
235
239
|
icon = Edit;
|
|
@@ -247,9 +251,6 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
|
|
|
247
251
|
text = 'Delete';
|
|
248
252
|
handler = onDelete;
|
|
249
253
|
handler = (parent, e) => {
|
|
250
|
-
if (canProceedWithCrud && !canProceedWithCrud()) {
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
254
|
onDelete();
|
|
254
255
|
};
|
|
255
256
|
icon = Trash;
|
|
@@ -297,9 +298,6 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
|
|
|
297
298
|
key = 'duplicateBtn';
|
|
298
299
|
text = 'Duplicate';
|
|
299
300
|
handler = (parent, e) => {
|
|
300
|
-
if (canProceedWithCrud && !canProceedWithCrud()) {
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
301
|
onDuplicate();
|
|
304
302
|
};
|
|
305
303
|
icon = Duplicate;
|
|
@@ -323,6 +321,12 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
|
|
|
323
321
|
handler = (parent, e) => onUploadDownload();
|
|
324
322
|
icon = UploadDownload;
|
|
325
323
|
break;
|
|
324
|
+
case DOWNLOAD:
|
|
325
|
+
key = 'downloadBtn';
|
|
326
|
+
text = 'Download';
|
|
327
|
+
handler = (parent, e) => onDownload();
|
|
328
|
+
icon = Download;
|
|
329
|
+
break;
|
|
326
330
|
default:
|
|
327
331
|
}
|
|
328
332
|
return {
|
|
@@ -397,6 +401,20 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
|
|
|
397
401
|
/>,
|
|
398
402
|
onCancel: hideModal,
|
|
399
403
|
});
|
|
404
|
+
},
|
|
405
|
+
onDownload = () => {
|
|
406
|
+
showModal({
|
|
407
|
+
body: <UploadsDownloadsWindow
|
|
408
|
+
reference="downloads"
|
|
409
|
+
onClose={hideModal}
|
|
410
|
+
isDownloadOnly={true}
|
|
411
|
+
Repository={Repository}
|
|
412
|
+
columnsConfig={props.columnsConfig}
|
|
413
|
+
downloadHeaders={downloadHeaders}
|
|
414
|
+
downloadParams={downloadParams}
|
|
415
|
+
/>,
|
|
416
|
+
onCancel: hideModal,
|
|
417
|
+
});
|
|
400
418
|
};
|
|
401
419
|
// onPrint = () => {
|
|
402
420
|
// debugger;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createIcon } from "../Gluestack/icon";
|
|
2
|
+
// Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc.
|
|
3
|
+
import Svg, { Path } from "react-native-svg"
|
|
4
|
+
|
|
5
|
+
const SvgComponent = createIcon({
|
|
6
|
+
Root: Svg,
|
|
7
|
+
viewBox: '0 0 320 512',
|
|
8
|
+
path: <Path d="M0 55.2V426c0 12.2 9.9 22 22 22 6.3 0 12.4-2.7 16.6-7.5l82.6-94.5 58.1 116.3c7.9 15.8 27.1 22.2 42.9 14.3s22.2-27.1 14.3-42.9L179.8 320h118.1c12.2 0 22.1-9.9 22.1-22.1 0-6.3-2.7-12.3-7.4-16.5L38.6 37.9c-4.3-3.8-9.7-5.9-15.4-5.9C10.4 32 0 42.4 0 55.2z" />,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export default SvgComponent
|
|
@@ -23,6 +23,11 @@ import Panel from '../Panel/Panel.js';
|
|
|
23
23
|
import Toolbar from '../Toolbar/Toolbar.js';
|
|
24
24
|
import _ from 'lodash';
|
|
25
25
|
|
|
26
|
+
const
|
|
27
|
+
INITIATE = 'INITIATE',
|
|
28
|
+
PROCESSING = 'PROCESSING',
|
|
29
|
+
RESULTS = 'RESULTS';
|
|
30
|
+
|
|
26
31
|
// NOTE: This component assumes you have an AppSlice, that has
|
|
27
32
|
// an 'operationsInProgress' state var and a 'setOperationsInProgress' action.
|
|
28
33
|
|
|
@@ -37,6 +42,7 @@ function AsyncOperation(props) {
|
|
|
37
42
|
Repository,
|
|
38
43
|
formItems = [],
|
|
39
44
|
formStartingValues = {},
|
|
45
|
+
_form = {},
|
|
40
46
|
getProgressUpdates = false,
|
|
41
47
|
parseProgress, // optional fn, accepts 'response' as arg and returns progress string
|
|
42
48
|
progressStuckThreshold = null, // e.g. 3, if left blank, doesn't check for stuck state
|
|
@@ -49,10 +55,25 @@ function AsyncOperation(props) {
|
|
|
49
55
|
alert,
|
|
50
56
|
} = props,
|
|
51
57
|
dispatch = useDispatch(),
|
|
58
|
+
isValid = useRef(true),
|
|
59
|
+
setIsValid = (valid) => {
|
|
60
|
+
isValid.current = valid;
|
|
61
|
+
},
|
|
62
|
+
getIsValid = () => {
|
|
63
|
+
return isValid.current;
|
|
64
|
+
},
|
|
65
|
+
mode = useRef(INITIATE),
|
|
66
|
+
setMode = (newMode) => {
|
|
67
|
+
mode.current = newMode;
|
|
68
|
+
},
|
|
69
|
+
getMode = () => {
|
|
70
|
+
return mode.current;
|
|
71
|
+
},
|
|
52
72
|
initiate = async () => {
|
|
53
73
|
|
|
54
74
|
clearProgress();
|
|
55
|
-
|
|
75
|
+
setMode(PROCESSING);
|
|
76
|
+
setFooter(getFooter());
|
|
56
77
|
setIsInProgress(true);
|
|
57
78
|
|
|
58
79
|
const
|
|
@@ -85,17 +106,18 @@ function AsyncOperation(props) {
|
|
|
85
106
|
}
|
|
86
107
|
showResults(results);
|
|
87
108
|
},
|
|
88
|
-
getFooter = (which =
|
|
109
|
+
getFooter = (which = getMode()) => {
|
|
89
110
|
switch(which) {
|
|
90
|
-
case
|
|
111
|
+
case INITIATE:
|
|
91
112
|
return <Toolbar>
|
|
92
113
|
<Button
|
|
93
114
|
text="Start"
|
|
94
115
|
rightIcon={ChevronRight}
|
|
95
116
|
onPress={() => initiate()}
|
|
117
|
+
isDisabled={!getIsValid()}
|
|
96
118
|
/>
|
|
97
119
|
</Toolbar>;
|
|
98
|
-
case
|
|
120
|
+
case PROCESSING:
|
|
99
121
|
return <Toolbar>
|
|
100
122
|
<Button
|
|
101
123
|
text="Please wait"
|
|
@@ -103,7 +125,7 @@ function AsyncOperation(props) {
|
|
|
103
125
|
variant="link"
|
|
104
126
|
/>
|
|
105
127
|
</Toolbar>;
|
|
106
|
-
case
|
|
128
|
+
case RESULTS:
|
|
107
129
|
return <Toolbar>
|
|
108
130
|
<Button
|
|
109
131
|
text="Reset"
|
|
@@ -152,7 +174,8 @@ function AsyncOperation(props) {
|
|
|
152
174
|
},
|
|
153
175
|
showResults = (results) => {
|
|
154
176
|
setCurrentTab(1);
|
|
155
|
-
|
|
177
|
+
setMode(RESULTS);
|
|
178
|
+
setFooter(getFooter());
|
|
156
179
|
setResults(results);
|
|
157
180
|
getProgress();
|
|
158
181
|
},
|
|
@@ -206,6 +229,7 @@ function AsyncOperation(props) {
|
|
|
206
229
|
},
|
|
207
230
|
resetToInitialState = () => {
|
|
208
231
|
setCurrentTab(0);
|
|
232
|
+
setMode(INITIATE);
|
|
209
233
|
setFooter(getFooter());
|
|
210
234
|
clearProgress();
|
|
211
235
|
},
|
|
@@ -227,6 +251,10 @@ function AsyncOperation(props) {
|
|
|
227
251
|
},
|
|
228
252
|
});
|
|
229
253
|
},
|
|
254
|
+
onValidityChange = (isValid) => {
|
|
255
|
+
setIsValid(isValid);
|
|
256
|
+
setFooter(getFooter());
|
|
257
|
+
},
|
|
230
258
|
unchangedProgressCount = getUnchangedProgressCount();
|
|
231
259
|
|
|
232
260
|
useEffect(() => {
|
|
@@ -255,6 +283,8 @@ function AsyncOperation(props) {
|
|
|
255
283
|
disableFooter={true}
|
|
256
284
|
items={formItems}
|
|
257
285
|
startingValues={formStartingValues}
|
|
286
|
+
onValidityChange={onValidityChange}
|
|
287
|
+
{..._form}
|
|
258
288
|
/>,
|
|
259
289
|
},
|
|
260
290
|
{
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
Box,
|
|
4
4
|
HStack,
|
|
5
5
|
Icon,
|
|
6
|
+
Pressable,
|
|
6
7
|
Text,
|
|
7
8
|
VStack,
|
|
8
9
|
VStackNative,
|
|
@@ -17,6 +18,7 @@ import {
|
|
|
17
18
|
REPORT_TYPES__PDF,
|
|
18
19
|
} from '../../Constants/ReportTypes.js';
|
|
19
20
|
import Form from '../Form/Form.js';
|
|
21
|
+
import IconButton from '../Buttons/IconButton.js';
|
|
20
22
|
import withComponent from '../Hoc/withComponent.js';
|
|
21
23
|
import withAlert from '../Hoc/withAlert.js';
|
|
22
24
|
import testProps from '../../Functions/testProps.js';
|
|
@@ -37,9 +39,19 @@ function Report(props) {
|
|
|
37
39
|
disablePdf = false,
|
|
38
40
|
disableExcel = false,
|
|
39
41
|
showReportHeaders = true,
|
|
42
|
+
isQuickReport = false,
|
|
43
|
+
quickReportData = {},
|
|
40
44
|
alert,
|
|
41
45
|
} = props,
|
|
42
46
|
buttons = [],
|
|
47
|
+
onPressQuickReport = () => {
|
|
48
|
+
downloadReport({
|
|
49
|
+
reportId,
|
|
50
|
+
reportType: REPORT_TYPES__EXCEL,
|
|
51
|
+
showReportHeaders,
|
|
52
|
+
data: quickReportData,
|
|
53
|
+
});
|
|
54
|
+
},
|
|
43
55
|
downloadReport = (args) => {
|
|
44
56
|
getReport(args);
|
|
45
57
|
alert('Download started');
|
|
@@ -59,6 +71,48 @@ function Report(props) {
|
|
|
59
71
|
icon = <Icon as={icon} {...propsIcon} />;
|
|
60
72
|
}
|
|
61
73
|
|
|
74
|
+
if (isQuickReport) {
|
|
75
|
+
let className = `
|
|
76
|
+
Report
|
|
77
|
+
max-w-[100px]
|
|
78
|
+
m-2
|
|
79
|
+
`;
|
|
80
|
+
if (props.className) {
|
|
81
|
+
className += ' ' + props.className;
|
|
82
|
+
}
|
|
83
|
+
return <VStackNative
|
|
84
|
+
{...testProps('QuickReport-' + reportId)}
|
|
85
|
+
className={className}
|
|
86
|
+
>
|
|
87
|
+
<Pressable
|
|
88
|
+
onPress={onPressQuickReport}
|
|
89
|
+
className={`
|
|
90
|
+
flex-1
|
|
91
|
+
items-center
|
|
92
|
+
justify-center
|
|
93
|
+
flex-col
|
|
94
|
+
bg-white
|
|
95
|
+
p-3
|
|
96
|
+
rounded-lg
|
|
97
|
+
border
|
|
98
|
+
border-primary-300
|
|
99
|
+
hover:bg-primary-300
|
|
100
|
+
`}
|
|
101
|
+
>
|
|
102
|
+
{icon}
|
|
103
|
+
<Text
|
|
104
|
+
className={`
|
|
105
|
+
text-black
|
|
106
|
+
text-center
|
|
107
|
+
text-[17px]
|
|
108
|
+
leading-tight
|
|
109
|
+
mt-2
|
|
110
|
+
`}
|
|
111
|
+
>{title}</Text>
|
|
112
|
+
</Pressable>
|
|
113
|
+
</VStackNative>;
|
|
114
|
+
}
|
|
115
|
+
|
|
62
116
|
if (!disableExcel) {
|
|
63
117
|
buttons.push({
|
|
64
118
|
...testProps('excelBtn'),
|
|
@@ -25,6 +25,7 @@ function UploadsDownloadsWindow(props) {
|
|
|
25
25
|
downloadHeaders,
|
|
26
26
|
uploadParams = {},
|
|
27
27
|
downloadParams = {},
|
|
28
|
+
isDownloadOnly = false,
|
|
28
29
|
onUpload,
|
|
29
30
|
|
|
30
31
|
// withComponent
|
|
@@ -124,6 +125,61 @@ function UploadsDownloadsWindow(props) {
|
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
127
|
};
|
|
128
|
+
|
|
129
|
+
const items = [
|
|
130
|
+
{
|
|
131
|
+
type: 'DisplayField',
|
|
132
|
+
text: 'Download an Excel file of the current grid contents.',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
type: 'Button',
|
|
136
|
+
text: 'Download',
|
|
137
|
+
isEditable: false,
|
|
138
|
+
icon: Excel,
|
|
139
|
+
_icon: {
|
|
140
|
+
size: 'md',
|
|
141
|
+
},
|
|
142
|
+
onPress: () => onDownload(),
|
|
143
|
+
className: 'mb-5',
|
|
144
|
+
},
|
|
145
|
+
];
|
|
146
|
+
if (!isDownloadOnly) {
|
|
147
|
+
items.push({
|
|
148
|
+
type: 'DisplayField',
|
|
149
|
+
text: 'Upload an Excel file to the current grid.',
|
|
150
|
+
});
|
|
151
|
+
items.push({
|
|
152
|
+
type: 'File',
|
|
153
|
+
name: 'file',
|
|
154
|
+
onChangeValue: setImportFile,
|
|
155
|
+
accept: '.xlsx',
|
|
156
|
+
});
|
|
157
|
+
items.push({
|
|
158
|
+
type: 'Row',
|
|
159
|
+
className: 'mt-2',
|
|
160
|
+
items: [
|
|
161
|
+
{
|
|
162
|
+
type: 'Button',
|
|
163
|
+
text: 'Upload',
|
|
164
|
+
isEditable: false,
|
|
165
|
+
icon: Upload,
|
|
166
|
+
_icon: {
|
|
167
|
+
size: 'md',
|
|
168
|
+
},
|
|
169
|
+
isDisabled: !importFile,
|
|
170
|
+
onPress: onUploadLocal,
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
type: 'Button',
|
|
174
|
+
text: 'Get Template',
|
|
175
|
+
icon: Download,
|
|
176
|
+
isEditable: false,
|
|
177
|
+
onPress: onDownloadTemplate,
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
],
|
|
181
|
+
});
|
|
182
|
+
}
|
|
127
183
|
|
|
128
184
|
return <Panel
|
|
129
185
|
{...props}
|
|
@@ -151,58 +207,7 @@ function UploadsDownloadsWindow(props) {
|
|
|
151
207
|
"type": "Column",
|
|
152
208
|
"flex": 1,
|
|
153
209
|
"defaults": {},
|
|
154
|
-
"items":
|
|
155
|
-
{
|
|
156
|
-
type: 'DisplayField',
|
|
157
|
-
text: 'Download an Excel file of the current grid contents.',
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
type: 'Button',
|
|
161
|
-
text: 'Download',
|
|
162
|
-
isEditable: false,
|
|
163
|
-
icon: Excel,
|
|
164
|
-
_icon: {
|
|
165
|
-
size: 'md',
|
|
166
|
-
},
|
|
167
|
-
onPress: () => onDownload(),
|
|
168
|
-
className: 'mb-5',
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
type: 'DisplayField',
|
|
172
|
-
text: 'Upload an Excel file to the current grid.',
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
type: 'File',
|
|
176
|
-
name: 'file',
|
|
177
|
-
onChangeValue: setImportFile,
|
|
178
|
-
accept: '.xlsx',
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
type: 'Row',
|
|
182
|
-
className: 'mt-2',
|
|
183
|
-
items: [
|
|
184
|
-
{
|
|
185
|
-
type: 'Button',
|
|
186
|
-
text: 'Upload',
|
|
187
|
-
isEditable: false,
|
|
188
|
-
icon: Upload,
|
|
189
|
-
_icon: {
|
|
190
|
-
size: 'md',
|
|
191
|
-
},
|
|
192
|
-
isDisabled: !importFile,
|
|
193
|
-
onPress: onUploadLocal,
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
type: 'Button',
|
|
197
|
-
text: 'Get Template',
|
|
198
|
-
icon: Download,
|
|
199
|
-
isEditable: false,
|
|
200
|
-
onPress: onDownloadTemplate,
|
|
201
|
-
},
|
|
202
|
-
|
|
203
|
-
],
|
|
204
|
-
},
|
|
205
|
-
]
|
|
210
|
+
"items": items,
|
|
206
211
|
},
|
|
207
212
|
]}
|
|
208
213
|
// record={selection}
|
package/src/Components/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import AngleRight from './Icons/AngleRight.js';
|
|
|
9
9
|
import AnglesLeft from './Icons/AnglesLeft.js';
|
|
10
10
|
import AnglesRight from './Icons/AnglesRight.js';
|
|
11
11
|
import Asterisk from './Icons/Asterisk.js';
|
|
12
|
+
import ArrowPointer from './Icons/ArrowPointer.js';
|
|
12
13
|
import ArrowUp from './Icons/ArrowUp.js';
|
|
13
14
|
import Ban from './Icons/Ban.js';
|
|
14
15
|
import Bars from './Icons/Bars.js';
|
|
@@ -204,6 +205,7 @@ import Color from './Form/Field/Color.js';
|
|
|
204
205
|
import Combo from './Form/Field/Combo/Combo.js';
|
|
205
206
|
// import { ComboEditor } from './Form/Field/Combo/Combo.js';
|
|
206
207
|
import Container from './Container/Container.js';
|
|
208
|
+
import ContainerColumn from './Container/ContainerColumn.js';
|
|
207
209
|
import DataMgt from './Screens/DataMgt.js';
|
|
208
210
|
import Date from './Form/Field/Date.js';
|
|
209
211
|
import DateRange from './Filter/DateRange.js';
|
|
@@ -254,6 +256,7 @@ const components = {
|
|
|
254
256
|
AnglesLeft,
|
|
255
257
|
AnglesRight,
|
|
256
258
|
Asterisk,
|
|
259
|
+
ArrowPointer,
|
|
257
260
|
ArrowUp,
|
|
258
261
|
Ban,
|
|
259
262
|
Bars,
|
|
@@ -449,6 +452,7 @@ const components = {
|
|
|
449
452
|
Combo,
|
|
450
453
|
// ComboEditor,
|
|
451
454
|
Container,
|
|
455
|
+
ContainerColumn,
|
|
452
456
|
DataMgt,
|
|
453
457
|
Date,
|
|
454
458
|
DateRange,
|