@onehat/ui 0.4.81 → 0.4.82
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/Container.js +4 -4
- package/src/Components/Form/Field/Combo/Combo.js +5 -2
- package/src/Components/Form/Field/Combo/MeterTypesCombo.js +1 -0
- package/src/Components/Form/Field/Date.js +1 -1
- package/src/Components/Form/Field/Select/PageSizeSelect.js +6 -1
- package/src/Components/Form/Field/Select/Select.js +14 -38
- package/src/Components/Form/Field/Tag/Tag.js +215 -13
- package/src/Components/Form/Field/Tag/ValueBox.js +20 -1
- package/src/Components/Form/Form.js +25 -13
- package/src/Components/Grid/Grid.js +312 -106
- package/src/Components/Grid/GridHeaderRow.js +42 -22
- package/src/Components/Grid/GridRow.js +13 -6
- package/src/Components/Grid/RowHandle.js +16 -4
- package/src/Components/Hoc/withData.js +7 -0
- package/src/Components/Hoc/withEditor.js +19 -4
- package/src/Components/Hoc/withPresetButtons.js +1 -1
- package/src/Components/Hoc/withSideEditor.js +1 -1
- package/src/Components/Icons/Join.js +10 -0
- package/src/Components/Layout/AsyncOperation.js +61 -14
- package/src/Components/Layout/CenterBox.js +1 -1
- package/src/Components/Screens/Manager.js +1 -1
- package/src/Components/Toolbar/PaginationToolbar.js +3 -1
- package/src/Components/Toolbar/Toolbar.js +10 -6
- package/src/Components/Tree/TreeNode.js +38 -9
- package/src/Components/Viewer/Viewer.js +10 -2
- package/src/Constants/Progress.js +2 -1
|
@@ -105,12 +105,19 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
105
105
|
columnHeaders = _.filter(columnHeader.parentElement.children, (childNode) => {
|
|
106
106
|
return childNode.getBoundingClientRect().width !== 0; // Skip zero-width children
|
|
107
107
|
}),
|
|
108
|
-
currentX = proxyRect.left
|
|
108
|
+
currentX = proxyRect.left, // left position of pointer
|
|
109
|
+
rowHandleOffset = showRowHandle ? 1 : 0; // Account for RowHandleSpacer
|
|
109
110
|
|
|
110
111
|
// Figure out which index the user wants
|
|
111
112
|
let newIx = 0;
|
|
112
113
|
_.each(columnHeaders, (child, ix, all) => {
|
|
114
|
+
// Skip the row handle spacer if present
|
|
115
|
+
if (showRowHandle && ix === 0) {
|
|
116
|
+
return true; // continue to next iteration
|
|
117
|
+
}
|
|
118
|
+
|
|
113
119
|
const
|
|
120
|
+
adjustedIx = ix - rowHandleOffset, // Adjust index for row handle offset
|
|
114
121
|
rect = child.getBoundingClientRect(), // rect of the columnHeader of this iteration
|
|
115
122
|
{
|
|
116
123
|
left,
|
|
@@ -119,8 +126,8 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
119
126
|
} = rect,
|
|
120
127
|
halfWidth = width /2;
|
|
121
128
|
|
|
122
|
-
if (
|
|
123
|
-
// first column
|
|
129
|
+
if (adjustedIx === 0) {
|
|
130
|
+
// first actual data column
|
|
124
131
|
if (currentX < left + halfWidth) {
|
|
125
132
|
newIx = 0;
|
|
126
133
|
return false;
|
|
@@ -128,22 +135,22 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
128
135
|
newIx = 1;
|
|
129
136
|
return false;
|
|
130
137
|
}
|
|
131
|
-
} else if (
|
|
132
|
-
// last column
|
|
138
|
+
} else if (adjustedIx === all.length - 1 - rowHandleOffset) {
|
|
139
|
+
// last actual data column (account for nav column and row handle)
|
|
133
140
|
if (currentX < left + halfWidth) {
|
|
134
|
-
newIx =
|
|
141
|
+
newIx = adjustedIx;
|
|
135
142
|
return false;
|
|
136
143
|
}
|
|
137
|
-
newIx =
|
|
144
|
+
newIx = adjustedIx + 1;
|
|
138
145
|
return false;
|
|
139
146
|
}
|
|
140
147
|
|
|
141
148
|
// all other columns
|
|
142
149
|
if (left <= currentX && currentX < left + halfWidth) {
|
|
143
|
-
newIx =
|
|
150
|
+
newIx = adjustedIx;
|
|
144
151
|
return false;
|
|
145
152
|
} else if (currentX < right) {
|
|
146
|
-
newIx =
|
|
153
|
+
newIx = adjustedIx + 1;
|
|
147
154
|
return false;
|
|
148
155
|
}
|
|
149
156
|
});
|
|
@@ -155,7 +162,8 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
155
162
|
|
|
156
163
|
// Render marker showing destination location (can't use regular render cycle because this div is absolutely positioned on page)
|
|
157
164
|
const
|
|
158
|
-
|
|
165
|
+
targetColumnIndex = newIx + rowHandleOffset, // Add back offset for visual positioning
|
|
166
|
+
columnHeaderRect = columnHeaders[targetColumnIndex].getBoundingClientRect(),
|
|
159
167
|
left = columnHeaderRect.left,
|
|
160
168
|
gridRowsContainer = gridRef.current._listRef._scrollRef.childNodes[0],
|
|
161
169
|
gridRowsContainerRect = gridRowsContainer.getBoundingClientRect(),
|
|
@@ -180,12 +188,19 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
180
188
|
columnHeaders = _.filter(columnHeader.parentElement.children, (childNode) => {
|
|
181
189
|
return childNode.getBoundingClientRect().width !== 0; // Skip zero-width children
|
|
182
190
|
}),
|
|
183
|
-
currentX = proxyRect.left
|
|
191
|
+
currentX = proxyRect.left, // left position of pointer
|
|
192
|
+
rowHandleOffset = showRowHandle ? 1 : 0; // Account for RowHandleSpacer
|
|
184
193
|
|
|
185
194
|
// Figure out which index the user wants
|
|
186
195
|
let newIx = 0;
|
|
187
196
|
_.each(columnHeaders, (child, ix, all) => {
|
|
197
|
+
// Skip the row handle spacer if present
|
|
198
|
+
if (showRowHandle && ix === 0) {
|
|
199
|
+
return true; // continue to next iteration
|
|
200
|
+
}
|
|
201
|
+
|
|
188
202
|
const
|
|
203
|
+
adjustedIx = ix - rowHandleOffset, // Adjust index for row handle offset
|
|
189
204
|
rect = child.getBoundingClientRect(), // rect of the columnHeader of this iteration
|
|
190
205
|
{
|
|
191
206
|
left,
|
|
@@ -194,8 +209,8 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
194
209
|
} = rect,
|
|
195
210
|
halfWidth = width /2;
|
|
196
211
|
|
|
197
|
-
if (
|
|
198
|
-
// first column
|
|
212
|
+
if (adjustedIx === 0) {
|
|
213
|
+
// first actual data column
|
|
199
214
|
if (currentX < left + halfWidth) {
|
|
200
215
|
newIx = 0;
|
|
201
216
|
return false;
|
|
@@ -203,22 +218,22 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
203
218
|
newIx = 1;
|
|
204
219
|
return false;
|
|
205
220
|
}
|
|
206
|
-
} else if (
|
|
207
|
-
// last column
|
|
221
|
+
} else if (adjustedIx === all.length - 1 - rowHandleOffset) {
|
|
222
|
+
// last actual data column (account for nav column and row handle)
|
|
208
223
|
if (currentX < left + halfWidth) {
|
|
209
|
-
newIx =
|
|
224
|
+
newIx = adjustedIx;
|
|
210
225
|
return false;
|
|
211
226
|
}
|
|
212
|
-
newIx =
|
|
227
|
+
newIx = adjustedIx + 1;
|
|
213
228
|
return false;
|
|
214
229
|
}
|
|
215
230
|
|
|
216
231
|
// all other columns
|
|
217
232
|
if (left <= currentX && currentX < left + halfWidth) {
|
|
218
|
-
newIx =
|
|
233
|
+
newIx = adjustedIx;
|
|
219
234
|
return false;
|
|
220
235
|
} else if (currentX < right) {
|
|
221
|
-
newIx =
|
|
236
|
+
newIx = adjustedIx + 1;
|
|
222
237
|
return false;
|
|
223
238
|
}
|
|
224
239
|
});
|
|
@@ -230,7 +245,8 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
230
245
|
|
|
231
246
|
// Render marker showing destination location (can't use regular render cycle because this div is absolutely positioned on page)
|
|
232
247
|
const
|
|
233
|
-
|
|
248
|
+
targetColumnIndex = newIx + rowHandleOffset, // Add back offset for visual positioning
|
|
249
|
+
columnHeaderRect = columnHeaders[targetColumnIndex].getBoundingClientRect(),
|
|
234
250
|
left = columnHeaderRect.left;
|
|
235
251
|
let marker = dragColumnSlot && dragColumnSlot.marker;
|
|
236
252
|
if (marker) {
|
|
@@ -468,7 +484,12 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
468
484
|
if (showRowHandle) {
|
|
469
485
|
headerColumns.unshift(<Box
|
|
470
486
|
key="RowHandleSpacer"
|
|
471
|
-
className=
|
|
487
|
+
className={clsx(
|
|
488
|
+
'Spacer-RowHandle',
|
|
489
|
+
'w-[40px]',
|
|
490
|
+
'flex-none',
|
|
491
|
+
styles.ROW_HANDLE_CLASSNAME,
|
|
492
|
+
)}
|
|
472
493
|
/>);
|
|
473
494
|
}
|
|
474
495
|
if (!hideNavColumn) {
|
|
@@ -510,4 +531,3 @@ export default forwardRef(function GridHeaderRow(props, ref) {
|
|
|
510
531
|
showRowHandle,
|
|
511
532
|
]);
|
|
512
533
|
});
|
|
513
|
-
|
|
@@ -29,7 +29,7 @@ let getEmptyImage = null;
|
|
|
29
29
|
|
|
30
30
|
// This was broken out from Grid simply so we can memoize it
|
|
31
31
|
|
|
32
|
-
const GridRow = forwardRef(
|
|
32
|
+
const GridRow = forwardRef((props, ref) => {
|
|
33
33
|
const {
|
|
34
34
|
columnsConfig,
|
|
35
35
|
columnProps,
|
|
@@ -37,6 +37,7 @@ const GridRow = forwardRef(function GridRow(props, ref) {
|
|
|
37
37
|
rowProps,
|
|
38
38
|
hideNavColumn,
|
|
39
39
|
showRowHandle,
|
|
40
|
+
areCellsScrollable,
|
|
40
41
|
rowCanSelect,
|
|
41
42
|
rowCanDrag,
|
|
42
43
|
isRowHoverable,
|
|
@@ -141,7 +142,7 @@ const GridRow = forwardRef(function GridRow(props, ref) {
|
|
|
141
142
|
'justify-center',
|
|
142
143
|
'border-r-black-100',
|
|
143
144
|
'block',
|
|
144
|
-
'overflow-auto',
|
|
145
|
+
areCellsScrollable ? 'overflow-auto' : 'overflow-hidden',
|
|
145
146
|
whichCursor,
|
|
146
147
|
styles.GRID_ROW_MAX_HEIGHT_EXTRA,
|
|
147
148
|
);
|
|
@@ -207,7 +208,7 @@ const GridRow = forwardRef(function GridRow(props, ref) {
|
|
|
207
208
|
let textClassName = clsx(
|
|
208
209
|
'GridRow-TextNative',
|
|
209
210
|
'self-center',
|
|
210
|
-
'overflow-hidden',
|
|
211
|
+
areCellsScrollable ? 'overflow-auto' : 'overflow-hidden',
|
|
211
212
|
colClassName,
|
|
212
213
|
styles.GRID_CELL_CLASSNAME,
|
|
213
214
|
styles.GRID_ROW_MAX_HEIGHT_EXTRA,
|
|
@@ -216,7 +217,7 @@ const GridRow = forwardRef(function GridRow(props, ref) {
|
|
|
216
217
|
textClassName += ' ' + config.className;
|
|
217
218
|
}
|
|
218
219
|
const rendererProps = {
|
|
219
|
-
...testProps('rendererCol-' + config.fieldName),
|
|
220
|
+
...testProps('rendererCol-' + (config.fieldName || config.id || key)),
|
|
220
221
|
className: textClassName,
|
|
221
222
|
...propsToPass,
|
|
222
223
|
...extraProps,
|
|
@@ -283,7 +284,7 @@ const GridRow = forwardRef(function GridRow(props, ref) {
|
|
|
283
284
|
'px-2',
|
|
284
285
|
'py-3',
|
|
285
286
|
'block',
|
|
286
|
-
'overflow-
|
|
287
|
+
areCellsScrollable ? 'overflow-auto' : 'overflow-hidden',
|
|
287
288
|
colClassName,
|
|
288
289
|
styles.GRID_CELL_CLASSNAME,
|
|
289
290
|
styles.GRID_ROW_MAX_HEIGHT_NORMAL,
|
|
@@ -291,6 +292,9 @@ const GridRow = forwardRef(function GridRow(props, ref) {
|
|
|
291
292
|
if (config.className) {
|
|
292
293
|
elementClassName += ' ' + config.className;
|
|
293
294
|
}
|
|
295
|
+
if (rowProps?._cell?.className) {
|
|
296
|
+
elementClassName += ' ' + rowProps._cell.className;
|
|
297
|
+
}
|
|
294
298
|
if (cellProps.className) {
|
|
295
299
|
elementClassName += ' ' + cellProps.className;
|
|
296
300
|
}
|
|
@@ -346,11 +350,14 @@ const GridRow = forwardRef(function GridRow(props, ref) {
|
|
|
346
350
|
let textClassName = clsx(
|
|
347
351
|
'GridRow-TextNative',
|
|
348
352
|
'self-center',
|
|
349
|
-
'overflow-hidden',
|
|
353
|
+
areCellsScrollable ? 'overflow-auto' : 'overflow-hidden',
|
|
350
354
|
colClassName,
|
|
351
355
|
styles.GRID_CELL_CLASSNAME,
|
|
352
356
|
styles.GRID_ROW_MAX_HEIGHT_EXTRA,
|
|
353
357
|
);
|
|
358
|
+
if (rowProps?._cell?.className) {
|
|
359
|
+
textClassName += ' ' + rowProps._cell.className;
|
|
360
|
+
}
|
|
354
361
|
if (config.className) {
|
|
355
362
|
textClassName += ' ' + config.className;
|
|
356
363
|
}
|
|
@@ -3,15 +3,17 @@ import {
|
|
|
3
3
|
Icon,
|
|
4
4
|
VStack,
|
|
5
5
|
} from '@project-components/Gluestack';
|
|
6
|
-
import withTooltip from '
|
|
6
|
+
import withTooltip from '../Hoc/withTooltip';
|
|
7
7
|
import clsx from 'clsx';
|
|
8
|
+
import UiGlobals from '../../UiGlobals.js';
|
|
8
9
|
import Arcs from '../Icons/Arcs.js';
|
|
9
10
|
|
|
10
11
|
const RowHandle = forwardRef((props, ref) => {
|
|
11
12
|
const {
|
|
12
13
|
isDragSource,
|
|
13
14
|
isDraggable
|
|
14
|
-
} = props
|
|
15
|
+
} = props,
|
|
16
|
+
styles = UiGlobals.styles;
|
|
15
17
|
let className = clsx(
|
|
16
18
|
'RowHandle',
|
|
17
19
|
'h-full',
|
|
@@ -20,13 +22,23 @@ const RowHandle = forwardRef((props, ref) => {
|
|
|
20
22
|
'items-center',
|
|
21
23
|
'justify-center',
|
|
22
24
|
'select-none',
|
|
23
|
-
'cursor-pointer'
|
|
25
|
+
'cursor-pointer',
|
|
26
|
+
styles.ROW_HANDLE_CLASSNAME,
|
|
24
27
|
);
|
|
25
28
|
return <VStack
|
|
26
29
|
ref={isDragSource || isDraggable ? ref : undefined}
|
|
27
30
|
className={className}
|
|
28
31
|
>
|
|
29
|
-
<Icon
|
|
32
|
+
<Icon
|
|
33
|
+
as={Arcs}
|
|
34
|
+
size="xs"
|
|
35
|
+
className={clsx(
|
|
36
|
+
'w-full',
|
|
37
|
+
'h-full',
|
|
38
|
+
'text-[#ddd]',
|
|
39
|
+
styles.ROW_HANDLE_ICON_CLASSNAME,
|
|
40
|
+
)}
|
|
41
|
+
/>
|
|
30
42
|
</VStack>;
|
|
31
43
|
});
|
|
32
44
|
|
|
@@ -130,6 +130,13 @@ export default function withData(WrappedComponent) {
|
|
|
130
130
|
displayField={displayField}
|
|
131
131
|
idIx={localIdIx}
|
|
132
132
|
displayIx={localDisplayIx}
|
|
133
|
+
setBaseParams={(baseParams) => {
|
|
134
|
+
// This allows components down the hierarchy to dynamically set the baseParams
|
|
135
|
+
LocalRepository.setBaseParams(baseParams);
|
|
136
|
+
if (LocalRepository.isRemote) {
|
|
137
|
+
LocalRepository.load();
|
|
138
|
+
}
|
|
139
|
+
}}
|
|
133
140
|
/>;
|
|
134
141
|
});
|
|
135
142
|
}
|
|
@@ -86,10 +86,10 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
86
86
|
newEntityDisplayValueRef = useRef(),
|
|
87
87
|
editorModeRef = useRef(initialEditorMode),
|
|
88
88
|
isIgnoreNextSelectionChangeRef = useRef(false),
|
|
89
|
+
isEditorShownRef = useRef(false),
|
|
89
90
|
[currentRecord, setCurrentRecord] = useState(null),
|
|
90
91
|
[isAdding, setIsAdding] = useState(false),
|
|
91
92
|
[isSaving, setIsSaving] = useState(false),
|
|
92
|
-
[isEditorShown, setIsEditorShownRaw] = useState(false),
|
|
93
93
|
[isEditorViewOnly, setIsEditorViewOnly] = useState(canEditorViewOnly), // current state of whether editor is in view-only mode
|
|
94
94
|
[lastSelection, setLastSelection] = useState(),
|
|
95
95
|
setIsIgnoreNextSelectionChange = (bool) => {
|
|
@@ -99,11 +99,15 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
99
99
|
return isIgnoreNextSelectionChangeRef.current;
|
|
100
100
|
},
|
|
101
101
|
setIsEditorShown = (bool) => {
|
|
102
|
-
|
|
102
|
+
isEditorShownRef.current = bool;
|
|
103
|
+
forceUpdate();
|
|
103
104
|
if (!bool && onEditorClose) {
|
|
104
105
|
onEditorClose();
|
|
105
106
|
}
|
|
106
107
|
},
|
|
108
|
+
getIsEditorShown = () => {
|
|
109
|
+
return isEditorShownRef.current;
|
|
110
|
+
},
|
|
107
111
|
setIsWaitModalShown = (bool) => {
|
|
108
112
|
const
|
|
109
113
|
dispatch = UiGlobals.redux?.dispatch,
|
|
@@ -685,8 +689,18 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
685
689
|
};
|
|
686
690
|
|
|
687
691
|
useEffect(() => {
|
|
688
|
-
setEditorMode(calculateEditorMode());
|
|
689
692
|
|
|
693
|
+
if (editorType === EDITOR_TYPE__SIDE) {
|
|
694
|
+
if (selection?.length) { // || isAdding
|
|
695
|
+
// there is a selection, so show the editor
|
|
696
|
+
setIsEditorShown(true);
|
|
697
|
+
} else {
|
|
698
|
+
// no selection, so close the editor
|
|
699
|
+
setIsEditorShown(false);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
setEditorMode(calculateEditorMode());
|
|
690
704
|
setLastSelection(selection);
|
|
691
705
|
|
|
692
706
|
// Push isIgnoreNextSelectionChange until after a microtask to ensure all
|
|
@@ -722,7 +736,8 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
722
736
|
alreadyHasWithEditor={true}
|
|
723
737
|
currentRecord={currentRecord}
|
|
724
738
|
setCurrentRecord={setCurrentRecord}
|
|
725
|
-
isEditorShown={
|
|
739
|
+
isEditorShown={getIsEditorShown()}
|
|
740
|
+
getIsEditorShown={getIsEditorShown}
|
|
726
741
|
isEditorViewOnly={isEditorViewOnly}
|
|
727
742
|
isAdding={isAdding}
|
|
728
743
|
isSaving={isSaving}
|
|
@@ -300,7 +300,7 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
|
|
|
300
300
|
isEmptySelection() ||
|
|
301
301
|
isMultiSelection() ||
|
|
302
302
|
isProtectedValue() ||
|
|
303
|
-
(
|
|
303
|
+
(canRecordBeDeleted && !canRecordBeDeleted(selection))
|
|
304
304
|
) {
|
|
305
305
|
isDisabled = true;
|
|
306
306
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createIcon } from "../Gluestack/icon";
|
|
2
|
+
import { Path, Svg } from 'react-native-svg';
|
|
3
|
+
|
|
4
|
+
const SvgComponent = createIcon({
|
|
5
|
+
Root: Svg,
|
|
6
|
+
viewBox: '0 0 77.88 66.87',
|
|
7
|
+
path: <Path d="M65.2 0c-7 0-12.68 5.68-12.68 12.68 0 2.66.82 5.13 2.23 7.17L40.94 41.67c-.65-.1-1.32-.17-2-.17s-1.35.07-2 .17L23.13 19.85c1.4-2.04 2.23-4.51 2.23-7.17C25.37 5.68 19.69 0 12.68 0S0 5.68 0 12.68s5.68 12.68 12.68 12.68c.68 0 1.35-.07 2-.17l13.81 21.82c-1.4 2.04-2.23 4.51-2.23 7.17 0 7 5.68 12.68 12.68 12.68s12.68-5.68 12.68-12.68c0-2.66-.82-5.13-2.23-7.17L63.2 25.19c.65.1 1.32.17 2 .17 7 0 12.68-5.68 12.68-12.68S72.21 0 65.2 0z"/>,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export default SvgComponent
|
|
@@ -8,13 +8,14 @@ import {
|
|
|
8
8
|
} from '@project-components/Gluestack';
|
|
9
9
|
import clsx from 'clsx';
|
|
10
10
|
import * as Progress from 'react-native-progress';
|
|
11
|
-
import useForceUpdate from '
|
|
11
|
+
import useForceUpdate from '../../Hooks/useForceUpdate';
|
|
12
12
|
import {
|
|
13
13
|
PROGRESS__NONE_FOUND,
|
|
14
14
|
PROGRESS__IN_PROCESS,
|
|
15
15
|
PROGRESS__COMPLETED,
|
|
16
16
|
PROGRESS__FAILED,
|
|
17
17
|
PROGRESS__STUCK,
|
|
18
|
+
PROGRESS__UNSTUCK,
|
|
18
19
|
} from '../../Constants/Progress.js';
|
|
19
20
|
import {
|
|
20
21
|
MOMENT_DATE_FORMAT_2,
|
|
@@ -27,6 +28,7 @@ import withAlert from '../Hoc/withAlert.js';
|
|
|
27
28
|
import Loading from '../Messages/Loading.js';
|
|
28
29
|
import ChevronLeft from '../Icons/ChevronLeft.js';
|
|
29
30
|
import ChevronRight from '../Icons/ChevronRight.js';
|
|
31
|
+
import RotateLeft from '../Icons/RotateLeft.js';
|
|
30
32
|
import Play from '../Icons/Play.js';
|
|
31
33
|
import EllipsisHorizontal from '../Icons/EllipsisHorizontal.js';
|
|
32
34
|
import Stop from '../Icons/Stop.js';
|
|
@@ -63,6 +65,7 @@ function AsyncOperation(props) {
|
|
|
63
65
|
getProgressUpdates = false,
|
|
64
66
|
parseProgress, // optional fn, accepts 'response' as arg and returns an object like this: { status, errors, started, lastUpdated, timeElapsed, count, current, total, percentage }
|
|
65
67
|
updateInterval = 10000, // ms
|
|
68
|
+
progressColor = '#666',
|
|
66
69
|
|
|
67
70
|
// withComponent
|
|
68
71
|
self,
|
|
@@ -101,6 +104,13 @@ function AsyncOperation(props) {
|
|
|
101
104
|
setFormValues = (values) => {
|
|
102
105
|
formValuesRef.current = values;
|
|
103
106
|
},
|
|
107
|
+
isStuckRef = useRef(false),
|
|
108
|
+
getIsStuck = () => {
|
|
109
|
+
return isStuckRef.current;
|
|
110
|
+
},
|
|
111
|
+
setIsStuck = (bool) => {
|
|
112
|
+
isStuckRef.current = bool;
|
|
113
|
+
},
|
|
104
114
|
getFooter = () => {
|
|
105
115
|
switch(getMode()) {
|
|
106
116
|
case INIT:
|
|
@@ -126,19 +136,28 @@ function AsyncOperation(props) {
|
|
|
126
136
|
// />
|
|
127
137
|
// </Toolbar>;
|
|
128
138
|
case RESULTS:
|
|
129
|
-
|
|
130
|
-
|
|
139
|
+
let button;
|
|
140
|
+
if (getIsStuck()) {
|
|
141
|
+
button = <Button
|
|
142
|
+
text="Unstick"
|
|
143
|
+
icon={RotateLeft}
|
|
144
|
+
onPress={() => unstick()}
|
|
145
|
+
/>;
|
|
146
|
+
} else {
|
|
147
|
+
button = <Button
|
|
131
148
|
text="Reset"
|
|
132
149
|
icon={ChevronLeft}
|
|
133
150
|
onPress={() => resetToInitialState()}
|
|
134
|
-
|
|
151
|
+
/>;
|
|
152
|
+
}
|
|
153
|
+
return <Toolbar>
|
|
154
|
+
{button}
|
|
135
155
|
</Toolbar>;
|
|
136
156
|
}
|
|
137
157
|
},
|
|
138
158
|
[footer, setFooter] = useState(getFooter()),
|
|
139
159
|
[results, setResults] = useState(null),
|
|
140
160
|
[progress, setProgress] = useState(null),
|
|
141
|
-
[isStuck, setIsStuck] = useState(false),
|
|
142
161
|
[isReady, setIsReady] = useState(false),
|
|
143
162
|
showResults = (results) => {
|
|
144
163
|
setMode(RESULTS);
|
|
@@ -193,7 +212,6 @@ function AsyncOperation(props) {
|
|
|
193
212
|
<Text>{message}</Text>;
|
|
194
213
|
}
|
|
195
214
|
showResults(results);
|
|
196
|
-
|
|
197
215
|
},
|
|
198
216
|
getProgress = (immediately = false) => {
|
|
199
217
|
if (!getProgressUpdates) {
|
|
@@ -266,17 +284,17 @@ function AsyncOperation(props) {
|
|
|
266
284
|
|
|
267
285
|
const className = 'text-lg';
|
|
268
286
|
renderItems.push(<Text className={className + ' ' + color} key="status">Status: {statusMessage}</Text>);
|
|
269
|
-
if (!_.isNil(percentage)) {
|
|
270
|
-
renderItems.push(<
|
|
287
|
+
if (!_.isNil(percentage) && status !== PROGRESS__COMPLETED) {
|
|
288
|
+
renderItems.push(<VStack key="progress">
|
|
271
289
|
<Progress.Bar
|
|
272
290
|
animated={true}
|
|
273
291
|
progress={percentage / 100}
|
|
274
292
|
width={175}
|
|
275
|
-
height={
|
|
276
|
-
color=
|
|
293
|
+
height={15}
|
|
294
|
+
color={progressColor}
|
|
277
295
|
/>
|
|
278
|
-
<Text className={className
|
|
279
|
-
</
|
|
296
|
+
<Text className={className}>{percentage}%</Text>
|
|
297
|
+
</VStack>);
|
|
280
298
|
}
|
|
281
299
|
if (started) {
|
|
282
300
|
const startedMoment = moment(started);
|
|
@@ -296,10 +314,10 @@ function AsyncOperation(props) {
|
|
|
296
314
|
if (!_.isNil(count) && count !== 0) {
|
|
297
315
|
renderItems.push(<Text className={className} key="count">Count: {count}</Text>);
|
|
298
316
|
}
|
|
299
|
-
if (!_.isNil(current) && !_.isNil(total)
|
|
317
|
+
if (!_.isNil(current) && !_.isNil(total)) {
|
|
300
318
|
renderItems.push(<Text className={className} key="currentTotal">Current/Total: {current} / {total}</Text>);
|
|
301
319
|
}
|
|
302
|
-
if (!_.isNil(message)) {
|
|
320
|
+
if (!_.isNil(message) && !_.isEmpty(message)) {
|
|
303
321
|
renderItems.push(<Text className={className} key="message">{message}</Text>);
|
|
304
322
|
}
|
|
305
323
|
if (!_.isNil(errors)) {
|
|
@@ -331,6 +349,35 @@ function AsyncOperation(props) {
|
|
|
331
349
|
fetchProgress(true); // isInitial
|
|
332
350
|
}
|
|
333
351
|
},
|
|
352
|
+
unstick = async () => {
|
|
353
|
+
stopGettingProgress();
|
|
354
|
+
setMode(PROCESSING);
|
|
355
|
+
setFooter(getFooter());
|
|
356
|
+
|
|
357
|
+
const
|
|
358
|
+
method = Repository.methods.edit,
|
|
359
|
+
uri = Repository.getModel() + '/unstickProcess',
|
|
360
|
+
data = {
|
|
361
|
+
process
|
|
362
|
+
};
|
|
363
|
+
const
|
|
364
|
+
result = await Repository._send(method, uri, data);
|
|
365
|
+
|
|
366
|
+
const response = Repository._processServerResponse(result);
|
|
367
|
+
if (!response?.success) {
|
|
368
|
+
alert(response.message || 'Error unsticking process on server.');
|
|
369
|
+
resetToInitialState();
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (response.root?.status !== PROGRESS__UNSTUCK) {
|
|
374
|
+
alert('Process could not be unstuck.');
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
alert('Process unstuck.');
|
|
379
|
+
resetToInitialState();
|
|
380
|
+
},
|
|
334
381
|
resetToInitialState = () => {
|
|
335
382
|
setMode(START);
|
|
336
383
|
setFooter(getFooter());
|
|
@@ -29,7 +29,7 @@ function ManagerScreen(props) {
|
|
|
29
29
|
[isRendered, setIsRendered] = useState(false),
|
|
30
30
|
[isModeSet, setIsModeSet] = useState(false),
|
|
31
31
|
[allowSideBySide, setAllowSideBySide] = useState(false),
|
|
32
|
-
[mode, setModeRaw] = useState(
|
|
32
|
+
[mode, setModeRaw] = useState(SCREEN_MODES__SIDE),
|
|
33
33
|
actualMode = (!allowSideBySide || mode === SCREEN_MODES__FULL) ? SCREEN_MODES__FULL : SCREEN_MODES__SIDE,
|
|
34
34
|
setMode = (newMode) => {
|
|
35
35
|
if (!allowSideBySide && newMode === SCREEN_MODES__SIDE) {
|
|
@@ -7,7 +7,7 @@ import Pagination from './Pagination.js'
|
|
|
7
7
|
import Toolbar from './Toolbar.js'
|
|
8
8
|
import _ from 'lodash';
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
const PaginationToolbar = forwardRef((props, ref) => {
|
|
11
11
|
const {
|
|
12
12
|
toolbarItems = [],
|
|
13
13
|
disablePageSize = false,
|
|
@@ -65,3 +65,5 @@ export default forwardRef(function PaginationToolbar(props, ref) {
|
|
|
65
65
|
/>
|
|
66
66
|
</Toolbar>;
|
|
67
67
|
});
|
|
68
|
+
|
|
69
|
+
export default PaginationToolbar;
|
|
@@ -10,9 +10,12 @@ import {
|
|
|
10
10
|
} from '../../Constants/UiModes.js';
|
|
11
11
|
import UiGlobals from '../../UiGlobals.js';
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
const Toolbar = forwardRef((props, ref) => {
|
|
14
|
+
const {
|
|
15
|
+
children,
|
|
16
|
+
...propsToPass
|
|
17
|
+
} = props,
|
|
18
|
+
styles = UiGlobals.styles;
|
|
16
19
|
|
|
17
20
|
let className = clsx(
|
|
18
21
|
'Toolbar',
|
|
@@ -34,11 +37,10 @@ export default forwardRef(function Toolbar(props, ref) {
|
|
|
34
37
|
}
|
|
35
38
|
let toolbar = <HStackNative
|
|
36
39
|
ref={ref}
|
|
40
|
+
{...propsToPass}
|
|
37
41
|
className={className}
|
|
38
|
-
style={props.style || {}}
|
|
39
|
-
onLayout={props.onLayout}
|
|
40
42
|
>
|
|
41
|
-
{
|
|
43
|
+
{children}
|
|
42
44
|
</HStackNative>;
|
|
43
45
|
|
|
44
46
|
if (CURRENT_MODE === UI_MODE_NATIVE) {
|
|
@@ -53,3 +55,5 @@ export default forwardRef(function Toolbar(props, ref) {
|
|
|
53
55
|
|
|
54
56
|
return toolbar;
|
|
55
57
|
});
|
|
58
|
+
|
|
59
|
+
export default Toolbar;
|