@controleonline/ui-default 1.0.279 → 1.0.281
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/react/components/cards/DefaultEntityCard.js +13 -0
- package/src/react/components/files/DefaultFile.js +11 -24
- package/src/react/components/inputs/DefaultInput.js +417 -414
- package/src/react/components/table/DefaultColumnMenu.js +1 -1
- package/src/react/components/table/DefaultSearchModal.js +14 -5
- package/src/react/components/table/DefaultTable.js +28 -22
- package/src/react/components/table/DefaultTable.layoutUtils.js +1 -0
- package/src/react/components/table/DefaultTableCards.js +5 -2
- package/src/react/components/table/DefaultTableControls.js +2 -2
- package/src/react/components/table/DefaultTableInput.js +1 -1
- package/src/react/components/table/DefaultTableRows.js +1 -1
- package/src/react/components/table/DefaultTableToolbar.js +1 -1
- package/src/react/components/table/useDefaultTablePagination.js +48 -6
- package/src/react/components/table/useDefaultTableStoreSync.js +18 -6
- package/src/store/default/actions.js +117 -116
- package/src/tests/react/components/table/DefaultTable.defaultAppearance.test.js +14 -0
- package/src/tests/react/components/table/DefaultTable.group1.test.js +12 -0
- package/src/tests/react/components/table/DefaultTable.group2.test.js +11 -0
- package/src/tests/react/components/table/DefaultTable.group3.test.js +7 -0
- package/src/tests/react/components/table/DefaultTableCards.layout.test.js +1 -0
- package/src/tests/react/components/table/defaultTableTestSetup.cjs +1 -0
|
@@ -19,7 +19,7 @@ import DefaultCompactDialog from './DefaultCompactDialog';
|
|
|
19
19
|
|
|
20
20
|
const DefaultColumnMenu = ({ storeName, visible = false, onClose }) => {
|
|
21
21
|
const store = useStore(storeName);
|
|
22
|
-
const columns = Array.isArray(store?.getters?.columns) ? store.getters.columns : [];
|
|
22
|
+
const columns = Array.isArray(store?.getters?.configs?.presentationColumns) ? store.getters.configs.presentationColumns : Array.isArray(store?.getters?.columns) ? store.getters.columns : [];
|
|
23
23
|
const visibleColumns = store?.getters?.visibleColumns || {};
|
|
24
24
|
const configs = store?.getters?.configs || {};
|
|
25
25
|
const tablePreferenceScope =
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Modal, Text, TouchableOpacity, View } from 'react-native';
|
|
2
|
+
import { KeyboardAvoidingView, Modal, Platform, Text, TouchableOpacity, View } from 'react-native';
|
|
3
3
|
import Icon from 'react-native-vector-icons/Feather';
|
|
4
4
|
import DefaultSearch from '../filters/DefaultSearch';
|
|
5
5
|
import styles from './DefaultTable.styles';
|
|
@@ -11,6 +11,11 @@ const DefaultSearchModal = ({
|
|
|
11
11
|
storeName,
|
|
12
12
|
visible = false,
|
|
13
13
|
onClose,
|
|
14
|
+
onSearch,
|
|
15
|
+
filters,
|
|
16
|
+
onChangeFilters,
|
|
17
|
+
value,
|
|
18
|
+
title,
|
|
14
19
|
}) => {
|
|
15
20
|
const { modalColors } = useDefaultTableTheme();
|
|
16
21
|
if (!visible) return null;
|
|
@@ -25,11 +30,12 @@ const DefaultSearchModal = ({
|
|
|
25
30
|
|
|
26
31
|
return (
|
|
27
32
|
<Modal visible transparent animationType="fade" onRequestClose={onClose}>
|
|
28
|
-
<
|
|
33
|
+
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : Platform.OS === 'android' ? 'height' : undefined}
|
|
34
|
+
style={[styles.modalOverlay, { backgroundColor: overlayColor }]}>
|
|
29
35
|
<View style={[styles.modalCard, styles.searchModalCard, { borderColor, backgroundColor }]}>
|
|
30
36
|
<View style={[styles.modalHeader, { borderBottomColor: borderColor }]}>
|
|
31
37
|
<Text style={[styles.modalTitle, { color: headerTextColor }]} numberOfLines={1}>
|
|
32
|
-
{global.t?.t(storeName, 'label', 'search')}
|
|
38
|
+
{title || global.t?.t(storeName, 'label', 'search')}
|
|
33
39
|
</Text>
|
|
34
40
|
<TouchableOpacity
|
|
35
41
|
style={[styles.modalCloseButton, { borderColor, backgroundColor }]}
|
|
@@ -45,11 +51,14 @@ const DefaultSearchModal = ({
|
|
|
45
51
|
placeholder={searchPlaceholder}
|
|
46
52
|
searchKey={searchKey}
|
|
47
53
|
storeName={storeName}
|
|
48
|
-
|
|
54
|
+
filters={filters}
|
|
55
|
+
onChangeFilters={onChangeFilters}
|
|
56
|
+
value={value}
|
|
57
|
+
onSearch={query => {onSearch?.(query); onClose?.();}}
|
|
49
58
|
/>
|
|
50
59
|
</View>
|
|
51
60
|
</View>
|
|
52
|
-
</
|
|
61
|
+
</KeyboardAvoidingView>
|
|
53
62
|
</Modal>
|
|
54
63
|
);
|
|
55
64
|
};
|
|
@@ -17,18 +17,15 @@ import {
|
|
|
17
17
|
import useDefaultTableTheme from './useDefaultTableTheme';
|
|
18
18
|
import DefaultTableView from './DefaultTableView';
|
|
19
19
|
import useDefaultTableCreateForm from './useDefaultTableCreateForm';
|
|
20
|
-
|
|
21
20
|
import {
|
|
22
|
-
assignGetterValue,
|
|
21
|
+
assignGetterValue, publishStoreValue,
|
|
23
22
|
useDefaultTableStoreSync,
|
|
24
23
|
} from './useDefaultTableStoreSync';
|
|
25
|
-
|
|
26
24
|
export {
|
|
27
25
|
mergeSortedDataWithLiveItems,
|
|
28
26
|
resolveColumnListLoadParams,
|
|
29
27
|
shouldTriggerEndReachedFromScroll,
|
|
30
28
|
} from './DefaultTable.utils';
|
|
31
|
-
|
|
32
29
|
const DefaultTable = ({
|
|
33
30
|
accentColor = null,
|
|
34
31
|
actions = {},
|
|
@@ -38,6 +35,7 @@ const DefaultTable = ({
|
|
|
38
35
|
compactBreakpoint = DEFAULT_COMPACT_BREAKPOINT,
|
|
39
36
|
cardListProps = {},
|
|
40
37
|
columns = [],
|
|
38
|
+
presentationColumns = null,
|
|
41
39
|
data = undefined,
|
|
42
40
|
defaultColor = '',
|
|
43
41
|
filters = {},
|
|
@@ -64,7 +62,7 @@ const DefaultTable = ({
|
|
|
64
62
|
onSelectionChange = null,
|
|
65
63
|
onSortChange = null,
|
|
66
64
|
pageSize = null,
|
|
67
|
-
appearance = '
|
|
65
|
+
appearance = 'compact',
|
|
68
66
|
paginationMode = 'infinite',
|
|
69
67
|
pinRowActions = true,
|
|
70
68
|
renderCard = null,
|
|
@@ -78,15 +76,17 @@ const DefaultTable = ({
|
|
|
78
76
|
showSearch = null,
|
|
79
77
|
showRowActions = true,
|
|
80
78
|
showToolbar = true,
|
|
79
|
+
showAdministrativeTools = true,
|
|
81
80
|
showToolbarActions = null,
|
|
82
81
|
showToolbarControls = null,
|
|
83
82
|
showTotalItemsInCompactToolbar = false,
|
|
84
83
|
showTotalItemsInFooter = true,
|
|
85
84
|
sort = null,
|
|
86
85
|
storeName = '',
|
|
87
|
-
summary = undefined,
|
|
86
|
+
summary = undefined, totalItems = undefined,
|
|
88
87
|
summaryLabels = {},
|
|
89
88
|
toolbarActions = [],
|
|
89
|
+
viewMode = null,
|
|
90
90
|
visibleColumnsPreferenceKey = '',
|
|
91
91
|
}) => {
|
|
92
92
|
const { width } = useWindowDimensions();
|
|
@@ -128,13 +128,13 @@ const DefaultTable = ({
|
|
|
128
128
|
const columnsForTable = storeColumns.length > 0 ? storeColumns : columns;
|
|
129
129
|
const storeFilters = isObject(store?.getters?.filters) ? store.getters.filters : {};
|
|
130
130
|
const requestParamsSeed = isObject(requestParams) ? requestParams : {};
|
|
131
|
-
const resolvedTotalItems = store?.getters?.totalItems;
|
|
131
|
+
const resolvedTotalItems = totalItems ?? (!autoMode && paginationMode === 'pages' ? data.length : store?.getters?.totalItems);
|
|
132
|
+
useEffect(() => {if ((!autoMode && paginationMode === 'pages') || totalItems !== undefined) publishStoreValue(store, 'setTotalItems', resolvedTotalItems, 'totalItems');}, [autoMode, paginationMode, totalItems, resolvedTotalItems, storeName, store?.actions?.setTotalItems]);
|
|
132
133
|
if (storeDeclaredConfigsRef.current === null) {
|
|
133
134
|
storeDeclaredConfigsRef.current = isObject(store?.getters?.configs)
|
|
134
135
|
? store.getters.configs
|
|
135
136
|
: {};
|
|
136
137
|
}
|
|
137
|
-
|
|
138
138
|
const storeDeclaredConfigs = storeDeclaredConfigsRef.current || {};
|
|
139
139
|
const currentConfigs = {
|
|
140
140
|
...storeDeclaredConfigs,
|
|
@@ -148,11 +148,9 @@ const DefaultTable = ({
|
|
|
148
148
|
normalizeText(addLabel) ||
|
|
149
149
|
normalizeText(global.t?.t(storeName, 'button', 'add')) ||
|
|
150
150
|
'Adicionar';
|
|
151
|
-
|
|
152
151
|
if (storeColumns.length === 0 && Array.isArray(columns) && columns.length > 0) {
|
|
153
152
|
assignGetterValue(store, 'columns', columns);
|
|
154
153
|
}
|
|
155
|
-
|
|
156
154
|
if (data !== undefined && Array.isArray(data)) {
|
|
157
155
|
assignGetterValue(store, 'items', data);
|
|
158
156
|
}
|
|
@@ -167,7 +165,7 @@ const DefaultTable = ({
|
|
|
167
165
|
const {
|
|
168
166
|
buildRequestQuery,
|
|
169
167
|
currentPage,
|
|
170
|
-
pageSizeNumber,
|
|
168
|
+
pageSizeNumber, paginateData,
|
|
171
169
|
goToPage,
|
|
172
170
|
resolvedIsLoading,
|
|
173
171
|
handleEndReached,
|
|
@@ -194,12 +192,13 @@ const DefaultTable = ({
|
|
|
194
192
|
store,
|
|
195
193
|
storeName,
|
|
196
194
|
});
|
|
197
|
-
const
|
|
195
|
+
const sortedItems = useDefaultTableSortedData({
|
|
198
196
|
resolvedData,
|
|
199
197
|
resolvedSort,
|
|
200
198
|
storeName,
|
|
201
199
|
tableColumns: columnsForTable,
|
|
202
200
|
});
|
|
201
|
+
const sortedData = useMemo(() => paginateData(sortedItems), [paginateData, sortedItems]);
|
|
203
202
|
const {isCreateFormOpen, closeCreateForm, resolvedOnAdd, handleDefaultCreateSaved} =
|
|
204
203
|
useDefaultTableCreateForm({onAdd, onSaved, resolvedActions, handleRefresh});
|
|
205
204
|
const hasAddAction =
|
|
@@ -225,11 +224,11 @@ const DefaultTable = ({
|
|
|
225
224
|
const previousCompactRef = useRef(isCompactView);
|
|
226
225
|
const enteringCompact = isCompactView && !previousCompactRef.current;
|
|
227
226
|
useEffect(() => {previousCompactRef.current = isCompactView;}, [isCompactView]);
|
|
228
|
-
const effectiveViewMode =
|
|
227
|
+
const effectiveViewMode = viewMode || (
|
|
229
228
|
enteringCompact && forceCardsOnCompact !== false ? 'cards' :
|
|
230
229
|
currentConfigs.viewMode ||
|
|
231
230
|
storedViewMode ||
|
|
232
|
-
(isCompactView && forceCardsOnCompact !== false ? 'cards' : initialViewMode);
|
|
231
|
+
(isCompactView && forceCardsOnCompact !== false ? 'cards' : initialViewMode));
|
|
233
232
|
const tableFiltersVisible = Boolean(currentConfigs.tableFiltersVisible);
|
|
234
233
|
const defaultTableConfigs = useMemo(
|
|
235
234
|
() => ({
|
|
@@ -247,7 +246,7 @@ const DefaultTable = ({
|
|
|
247
246
|
compactBreakpoint,
|
|
248
247
|
debugFallbackParameters,
|
|
249
248
|
defaultColor,
|
|
250
|
-
effectiveViewMode,
|
|
249
|
+
effectiveViewMode, viewMode,
|
|
251
250
|
filters,
|
|
252
251
|
footerComponent,
|
|
253
252
|
forceCardsOnCompact,
|
|
@@ -274,6 +273,7 @@ const DefaultTable = ({
|
|
|
274
273
|
requestParams: requestParamsSeed,
|
|
275
274
|
requestSort,
|
|
276
275
|
resolvedSort,
|
|
276
|
+
presentationColumns,
|
|
277
277
|
rowActionsComponent,
|
|
278
278
|
rowActionsWidth,
|
|
279
279
|
rowStyle,
|
|
@@ -282,7 +282,8 @@ const DefaultTable = ({
|
|
|
282
282
|
selectable: storeSelectable,
|
|
283
283
|
showColumnFiltersButton,
|
|
284
284
|
showSearch,
|
|
285
|
-
showRowActions: storeDeclaredConfigs.showRowActions === false ? false : showRowActions,
|
|
285
|
+
showRowActions: presentationColumns !== null ? showRowActions : storeDeclaredConfigs.showRowActions === false ? false : showRowActions,
|
|
286
|
+
showAdministrativeTools,
|
|
286
287
|
showToolbar,
|
|
287
288
|
showToolbarActions:
|
|
288
289
|
showToolbarActions === null
|
|
@@ -303,7 +304,8 @@ const DefaultTable = ({
|
|
|
303
304
|
refreshing: resolvedIsRefreshing,
|
|
304
305
|
tablePreferenceScope,
|
|
305
306
|
toolbarActions,
|
|
306
|
-
|
|
307
|
+
// A controlled presentation must not replace the saved list mode.
|
|
308
|
+
viewMode: viewMode ? storeDeclaredConfigs.viewMode : effectiveViewMode,
|
|
307
309
|
}),
|
|
308
310
|
[
|
|
309
311
|
appearance, paginationMode, currentPage, pageSizeNumber, goToPage, resolvedIsLoading,
|
|
@@ -314,7 +316,7 @@ const DefaultTable = ({
|
|
|
314
316
|
compactBreakpoint,
|
|
315
317
|
debugFallbackParameters,
|
|
316
318
|
defaultColor,
|
|
317
|
-
effectiveViewMode,
|
|
319
|
+
effectiveViewMode, viewMode,
|
|
318
320
|
filters,
|
|
319
321
|
footerComponent,
|
|
320
322
|
forceCardsOnCompact,
|
|
@@ -344,6 +346,7 @@ const DefaultTable = ({
|
|
|
344
346
|
requestSort,
|
|
345
347
|
resolvedIsRefreshing,
|
|
346
348
|
resolvedSort,
|
|
349
|
+
presentationColumns,
|
|
347
350
|
rowActionsComponent,
|
|
348
351
|
rowActionsWidth,
|
|
349
352
|
rowStyle,
|
|
@@ -352,6 +355,7 @@ const DefaultTable = ({
|
|
|
352
355
|
showColumnFiltersButton,
|
|
353
356
|
showSearch,
|
|
354
357
|
showRowActions,
|
|
358
|
+
showAdministrativeTools,
|
|
355
359
|
showToolbar,
|
|
356
360
|
showToolbarActions,
|
|
357
361
|
showToolbarControls,
|
|
@@ -384,6 +388,7 @@ const DefaultTable = ({
|
|
|
384
388
|
hasImportAction: Boolean(storeDeclaredConfigs.import || importAction || onImport),
|
|
385
389
|
initialViewMode,
|
|
386
390
|
pinRowActions,
|
|
391
|
+
presentationColumns,
|
|
387
392
|
rowActionsComponentType: rowActionsComponent ? typeof rowActionsComponent : '',
|
|
388
393
|
rowActionsWidth,
|
|
389
394
|
resolvedIsRefreshing,
|
|
@@ -394,12 +399,13 @@ const DefaultTable = ({
|
|
|
394
399
|
showColumnFiltersButton,
|
|
395
400
|
showSearch,
|
|
396
401
|
showRowActions,
|
|
402
|
+
showAdministrativeTools,
|
|
397
403
|
showToolbar,
|
|
398
404
|
showToolbarActions,
|
|
399
405
|
showToolbarControls,
|
|
400
406
|
showTotalItemsInCompactToolbar,
|
|
401
407
|
showTotalItemsInFooter,
|
|
402
|
-
storedViewMode,
|
|
408
|
+
storedViewMode, controlledViewMode: viewMode,
|
|
403
409
|
tableFiltersVisible,
|
|
404
410
|
sortedData: stableSerialize(sortedData),
|
|
405
411
|
toolbarActionsLength: Array.isArray(toolbarActions) ? toolbarActions.length : 0,
|
|
@@ -413,7 +419,7 @@ const DefaultTable = ({
|
|
|
413
419
|
compactBreakpoint,
|
|
414
420
|
defaultColor,
|
|
415
421
|
debugFallbackParameters,
|
|
416
|
-
effectiveViewMode,
|
|
422
|
+
effectiveViewMode, viewMode,
|
|
417
423
|
filters,
|
|
418
424
|
forceCardsOnCompact,
|
|
419
425
|
storeDeclaredConfigs,
|
|
@@ -424,6 +430,7 @@ const DefaultTable = ({
|
|
|
424
430
|
onExport,
|
|
425
431
|
onImport,
|
|
426
432
|
pinRowActions,
|
|
433
|
+
presentationColumns,
|
|
427
434
|
rowActionsComponent,
|
|
428
435
|
rowActionsWidth,
|
|
429
436
|
resolvedIsRefreshing,
|
|
@@ -433,6 +440,7 @@ const DefaultTable = ({
|
|
|
433
440
|
showColumnFiltersButton,
|
|
434
441
|
showSearch,
|
|
435
442
|
showRowActions,
|
|
443
|
+
showAdministrativeTools,
|
|
436
444
|
showToolbar,
|
|
437
445
|
showToolbarActions,
|
|
438
446
|
showToolbarControls,
|
|
@@ -444,7 +452,6 @@ const DefaultTable = ({
|
|
|
444
452
|
toolbarActions,
|
|
445
453
|
],
|
|
446
454
|
);
|
|
447
|
-
|
|
448
455
|
// Do not mutate store.configs during render. A new configs object is built
|
|
449
456
|
// every pass; writing it here retriggers subscribers and React #185 when
|
|
450
457
|
// opening Adicionar on DefaultTable (categories). Sync only in the hook
|
|
@@ -490,5 +497,4 @@ const DefaultTable = ({
|
|
|
490
497
|
requestParamsSeed
|
|
491
498
|
}} />;
|
|
492
499
|
};
|
|
493
|
-
|
|
494
500
|
export default DefaultTable;
|
|
@@ -214,6 +214,7 @@ export const getColumnStyle = column => {
|
|
|
214
214
|
if (Number.isFinite(columnWidth) && columnWidth > 0) {
|
|
215
215
|
customSize.width = columnWidth;
|
|
216
216
|
customSize.flexBasis = columnWidth;
|
|
217
|
+
if(column?.cellComponent){customSize.flexGrow=0;customSize.maxWidth=columnWidth;}
|
|
217
218
|
}
|
|
218
219
|
|
|
219
220
|
if (Number.isFinite(columnMinWidth) && columnMinWidth > 0) {
|
|
@@ -66,6 +66,8 @@ const DefaultTableCards = ({ storeName }) => {
|
|
|
66
66
|
key: cardListKey,
|
|
67
67
|
listKey,
|
|
68
68
|
numColumns: _ignoredNumColumns,
|
|
69
|
+
transformData,
|
|
70
|
+
unframedCards,
|
|
69
71
|
...flatListProps
|
|
70
72
|
} = cardListProps;
|
|
71
73
|
const isLoading = Boolean(store?.getters?.isLoadingList || store?.getters?.isLoading);
|
|
@@ -137,6 +139,7 @@ const DefaultTableCards = ({ storeName }) => {
|
|
|
137
139
|
hasRowActions ? styles.cardItemWithActions : null,
|
|
138
140
|
rowStyleValue,
|
|
139
141
|
compact ? [compactStyles.cardItem, {flex: 0, flexGrow: 0, flexShrink: 0, flexBasis: 'auto', width: compactCardWidth, maxWidth: compactCardWidth, backgroundColor: palette.cardBackground || palette.panelBackground, borderColor: palette.cardBorder || palette.inputBorder}] : null,
|
|
142
|
+
unframedCards ? {borderWidth:0,backgroundColor:'transparent',shadowOpacity:0,elevation:0} : null,
|
|
140
143
|
]}
|
|
141
144
|
>
|
|
142
145
|
<View style={[styles.cardContent, hasRowActions ? null : intrinsicHeight, compact ? {flex: 0, flexBasis: 'auto', flexGrow: 0} : null]}>
|
|
@@ -206,11 +209,11 @@ const DefaultTableCards = ({ storeName }) => {
|
|
|
206
209
|
return (
|
|
207
210
|
<FlatList
|
|
208
211
|
{...flatListProps}
|
|
209
|
-
key={resolvedListKey}
|
|
212
|
+
key={`${resolvedListKey}:columns-${resolvedNumColumns}`}
|
|
210
213
|
numColumns={resolvedNumColumns}
|
|
211
214
|
onLayout={event => {flatListProps.onLayout?.(event); setListWidth(event.nativeEvent.layout.width);}}
|
|
212
215
|
columnWrapperStyle={compact && gridColumns > 1 ? {gap: 12} : flatListProps.columnWrapperStyle}
|
|
213
|
-
data={sortedData}
|
|
216
|
+
data={typeof transformData === 'function' ? transformData(sortedData) : sortedData}
|
|
214
217
|
keyExtractor={getRowKey}
|
|
215
218
|
renderItem={({ item, index }) => renderCardItem(item, index)}
|
|
216
219
|
style={styles.cardsScroll}
|
|
@@ -43,7 +43,7 @@ const DefaultTableControls = ({ storeName }) => {
|
|
|
43
43
|
const addConfig = store?.getters?.add;
|
|
44
44
|
const addButtonPlacement = normalizeText(configs.addButtonPlacement) || 'toolbar';
|
|
45
45
|
const shouldRenderAddButton =
|
|
46
|
-
addButtonPlacement === 'toolbar' &&
|
|
46
|
+
configs.add !== false && addButtonPlacement === 'toolbar' &&
|
|
47
47
|
(addConfig === true || configs.add === true) &&
|
|
48
48
|
(typeof configs.onAdd === 'function' || typeof store?.actions?.save === 'function');
|
|
49
49
|
const { tableButtonColors } = useDefaultTableTheme();
|
|
@@ -78,7 +78,7 @@ const DefaultTableControls = ({ storeName }) => {
|
|
|
78
78
|
|
|
79
79
|
return (
|
|
80
80
|
<>
|
|
81
|
-
<DefaultDebug storeName={storeName} />
|
|
81
|
+
{configs.showAdministrativeTools !== false ? <DefaultDebug storeName={storeName} /> : null}
|
|
82
82
|
{/* app-community#811: LISTA (table) e CARD abrem o mesmo DefaultFiltersModal */}
|
|
83
83
|
{hasFilterableColumns ? (
|
|
84
84
|
<DefaultModalButton
|
|
@@ -83,7 +83,7 @@ const DefaultTableInput = ({
|
|
|
83
83
|
const compactDisplay = compact && storeName === 'orders' ? (resolvedFieldName === 'price' ? Formatter.formatMoney(rawValue || 0) : dateField && rawValue ? `${Formatter.formatDateYmdTodmY(rawValue, false)}${time && (time !== '00:00' || resolvedFieldName === 'alterDate') ? '\n' + time : ''}` : compactType) : undefined;
|
|
84
84
|
const compactTextStyle = compact ? {fontSize: 13, fontWeight: column.isIdentity ? '600' : '400', ...(resolvedFieldName === 'status' ? {color: statusColor} : {color: themeColors.textPrimary})} : null;
|
|
85
85
|
const statusStyle = compact && resolvedFieldName === 'status' ? {width: 'auto', alignSelf: 'flex-start', borderWidth: 1, borderColor: statusColor, borderRadius: 18, paddingHorizontal: 8, paddingVertical: 3, backgroundColor: /^#[0-9a-f]{6}$/i.test(statusColor) ? statusColor + '10' : themeColors.panelBackground} : null;
|
|
86
|
-
const input = (
|
|
86
|
+
const input = column.cellComponent ? React.createElement(column.cellComponent,{row,column}) : (
|
|
87
87
|
<DefaultInput
|
|
88
88
|
accentColor={options.accentColor || resolvedAccentColor}
|
|
89
89
|
column={column}
|
|
@@ -37,7 +37,7 @@ const DefaultTableRows = ({ storeName }) => {
|
|
|
37
37
|
const store = useStore(storeName);
|
|
38
38
|
const configs = store?.getters?.configs || {};
|
|
39
39
|
const { palette, resolvedAccentColor, tableBorderColors, themeTokens } = useDefaultTableTheme();
|
|
40
|
-
const columns = Array.isArray(store?.getters?.columns) ? store.getters.columns : [];
|
|
40
|
+
const columns = Array.isArray(configs.presentationColumns) ? configs.presentationColumns : Array.isArray(store?.getters?.columns) ? store.getters.columns : [];
|
|
41
41
|
const visibleColumns = store?.getters?.visibleColumns || {};
|
|
42
42
|
const tableColumns = columns.filter(
|
|
43
43
|
column => shouldIncludeColumn(column) && visibleColumns[getColumnKey(column)] !== false,
|
|
@@ -76,7 +76,7 @@ const DefaultTableToolbar = ({
|
|
|
76
76
|
|
|
77
77
|
return null;
|
|
78
78
|
};
|
|
79
|
-
const importConfig = configs.import || null;
|
|
79
|
+
const importConfig = configs.showAdministrativeTools === false ? null : configs.import || null;
|
|
80
80
|
const importActionOverrides =
|
|
81
81
|
configs.importAction && typeof configs.importAction === 'object'
|
|
82
82
|
? configs.importAction
|
|
@@ -75,6 +75,7 @@ const useAutoPageLoader = ({
|
|
|
75
75
|
resolvedActions,
|
|
76
76
|
showError,
|
|
77
77
|
storeName,
|
|
78
|
+
store,
|
|
78
79
|
}) => {
|
|
79
80
|
const [currentPage, setCurrentPage] = useState(1);
|
|
80
81
|
const [autoHasLoaded, setAutoHasLoaded] = useState(false);
|
|
@@ -84,6 +85,7 @@ const useAutoPageLoader = ({
|
|
|
84
85
|
const [autoLastPageCount, setAutoLastPageCount] = useState(0);
|
|
85
86
|
const autoRequestIdRef = useRef(0);
|
|
86
87
|
const autoLoadedQueryKeyRef = useRef('');
|
|
88
|
+
const autoLoadedStoreKeyRef = useRef(null);
|
|
87
89
|
const autoErroredQueryKeyRef = useRef('');
|
|
88
90
|
const autoPageRef = useRef(0);
|
|
89
91
|
const isFetchingRef = useRef(false);
|
|
@@ -116,13 +118,22 @@ const useAutoPageLoader = ({
|
|
|
116
118
|
const query = buildRequestQuery(page, append);
|
|
117
119
|
if (refresh && resolvedActions.catalogCache) query.__storeMeta = {catalogRefresh: true};
|
|
118
120
|
|
|
119
|
-
|
|
121
|
+
const request = resolvedActions.getItems(query);
|
|
122
|
+
const owningRequestKey = store?.getters?.activeRequestKey;
|
|
123
|
+
return Promise.resolve(request)
|
|
120
124
|
.then(response => {
|
|
121
125
|
if (autoRequestIdRef.current !== requestId) {
|
|
122
126
|
return response;
|
|
123
127
|
}
|
|
124
128
|
|
|
125
129
|
const pageItems = normalizeCollectionItems(response);
|
|
130
|
+
// A retained screen must not present another screen's shared-store result.
|
|
131
|
+
if (owningRequestKey && store?.getters?.lastCompletedRequest?.requestKey !== owningRequestKey) {
|
|
132
|
+
autoLoadedQueryKeyRef.current = '';
|
|
133
|
+
setAutoHasLoaded(false);
|
|
134
|
+
return pageItems;
|
|
135
|
+
}
|
|
136
|
+
autoLoadedStoreKeyRef.current = owningRequestKey || store?.getters?.lastCompletedRequest?.requestKey || null;
|
|
126
137
|
autoPageRef.current = Number(response?.catalogPage) || page;
|
|
127
138
|
setCurrentPage(autoPageRef.current);
|
|
128
139
|
autoLoadedQueryKeyRef.current = autoQuerySignature;
|
|
@@ -159,6 +170,7 @@ const useAutoPageLoader = ({
|
|
|
159
170
|
resolvedActions,
|
|
160
171
|
showError,
|
|
161
172
|
storeName,
|
|
173
|
+
store,
|
|
162
174
|
],
|
|
163
175
|
);
|
|
164
176
|
|
|
@@ -168,6 +180,7 @@ const useAutoPageLoader = ({
|
|
|
168
180
|
autoHasLoaded,
|
|
169
181
|
autoLastPageCount,
|
|
170
182
|
autoLoadedQueryKeyRef,
|
|
183
|
+
autoLoadedStoreKeyRef,
|
|
171
184
|
autoLoading,
|
|
172
185
|
autoLoadingMore,
|
|
173
186
|
autoRefreshing,
|
|
@@ -188,21 +201,30 @@ const useAutoPageEffect = ({
|
|
|
188
201
|
isFocused,
|
|
189
202
|
loadAutoPage,
|
|
190
203
|
resolvedActions,
|
|
204
|
+
ownsStoreResult,
|
|
205
|
+
autoPageRef,
|
|
191
206
|
}) => {
|
|
207
|
+
const wasFocused = useRef(false);
|
|
192
208
|
useEffect(() => {
|
|
209
|
+
const entering = isFocused && !wasFocused.current;
|
|
210
|
+
wasFocused.current = isFocused;
|
|
193
211
|
if (!autoMode || !isFocused) return;
|
|
194
212
|
if (typeof resolvedActions.getItems !== 'function') return;
|
|
213
|
+
// A failed visit may retry on the next focus, but never spin while still focused.
|
|
214
|
+
if (entering) autoErroredQueryKeyRef.current = '';
|
|
195
215
|
if (
|
|
196
216
|
autoLoading ||
|
|
197
217
|
autoLoadingMore ||
|
|
198
|
-
autoLoadedQueryKeyRef.current === autoQuerySignature ||
|
|
218
|
+
(autoLoadedQueryKeyRef.current === autoQuerySignature && ownsStoreResult && !(entering && resolvedActions.catalogCache)) ||
|
|
199
219
|
autoErroredQueryKeyRef.current === autoQuerySignature
|
|
200
220
|
) {
|
|
201
221
|
return;
|
|
202
222
|
}
|
|
203
223
|
|
|
204
224
|
endReachedLockRef.current = false;
|
|
205
|
-
|
|
225
|
+
const retainedPage = autoLoadedQueryKeyRef.current === autoQuerySignature && (!ownsStoreResult || resolvedActions.catalogCache)
|
|
226
|
+
? Math.max(1, autoPageRef.current) : 1;
|
|
227
|
+
loadAutoPage(retainedPage, { append: false });
|
|
206
228
|
}, [
|
|
207
229
|
autoErroredQueryKeyRef,
|
|
208
230
|
autoLoadedQueryKeyRef,
|
|
@@ -214,6 +236,8 @@ const useAutoPageEffect = ({
|
|
|
214
236
|
isFocused,
|
|
215
237
|
loadAutoPage,
|
|
216
238
|
resolvedActions,
|
|
239
|
+
ownsStoreResult,
|
|
240
|
+
autoPageRef,
|
|
217
241
|
]);
|
|
218
242
|
};
|
|
219
243
|
|
|
@@ -245,6 +269,10 @@ export const useDefaultTablePagination = ({
|
|
|
245
269
|
sortField: resolvedSort?.field,
|
|
246
270
|
});
|
|
247
271
|
const pageSizeNumber = Number(requestParams.itemsPerPage || pageSize || 50) || 50;
|
|
272
|
+
const [localPage, setLocalPage] = useState({key: '', page: 1});
|
|
273
|
+
const localQueryKey = stableSerialize([storeName, pageSizeNumber, filters, resolvedSort,
|
|
274
|
+
Array.isArray(data) ? data.map(item => item?.['@id'] ?? item?.id) : []]);
|
|
275
|
+
const localPages = Math.max(1, Math.ceil((Array.isArray(data) ? data.length : 0) / pageSizeNumber));
|
|
248
276
|
const resourceEndpoint = store?.getters?.resourceEndpoint || '';
|
|
249
277
|
const storeReload = store?.getters?.reload;
|
|
250
278
|
const buildRequestQuery = useCallback(
|
|
@@ -279,11 +307,12 @@ export const useDefaultTablePagination = ({
|
|
|
279
307
|
[columnsForTable, filters, pageSizeNumber, requestParams, resolvedSort, resourceEndpoint, storeName, storeReload],
|
|
280
308
|
);
|
|
281
309
|
const {
|
|
282
|
-
currentPage,
|
|
310
|
+
currentPage: autoCurrentPage,
|
|
283
311
|
autoErroredQueryKeyRef,
|
|
284
312
|
autoHasLoaded,
|
|
285
313
|
autoLastPageCount,
|
|
286
314
|
autoLoadedQueryKeyRef,
|
|
315
|
+
autoLoadedStoreKeyRef,
|
|
287
316
|
autoLoading,
|
|
288
317
|
autoLoadingMore,
|
|
289
318
|
autoRefreshing,
|
|
@@ -298,8 +327,17 @@ export const useDefaultTablePagination = ({
|
|
|
298
327
|
resolvedActions,
|
|
299
328
|
showError,
|
|
300
329
|
storeName,
|
|
330
|
+
store,
|
|
301
331
|
});
|
|
302
332
|
|
|
333
|
+
const currentPage = autoMode ? autoCurrentPage : Math.min(localPages, localPage.key === localQueryKey ? localPage.page : 1);
|
|
334
|
+
const paginateData = useCallback(items => !autoMode && paginationMode === 'pages'
|
|
335
|
+
? items.slice((currentPage - 1) * pageSizeNumber, currentPage * pageSizeNumber) : items,
|
|
336
|
+
[autoMode, paginationMode, currentPage, pageSizeNumber]);
|
|
337
|
+
|
|
338
|
+
const ownsStoreResult = !autoLoadedStoreKeyRef.current ||
|
|
339
|
+
autoLoadedStoreKeyRef.current === store?.getters?.lastCompletedRequest?.requestKey;
|
|
340
|
+
|
|
303
341
|
useAutoPageEffect({
|
|
304
342
|
autoErroredQueryKeyRef,
|
|
305
343
|
autoLoadedQueryKeyRef,
|
|
@@ -311,6 +349,8 @@ export const useDefaultTablePagination = ({
|
|
|
311
349
|
isFocused,
|
|
312
350
|
loadAutoPage,
|
|
313
351
|
resolvedActions,
|
|
352
|
+
ownsStoreResult,
|
|
353
|
+
autoPageRef,
|
|
314
354
|
});
|
|
315
355
|
|
|
316
356
|
useEffect(() => {
|
|
@@ -326,7 +366,7 @@ export const useDefaultTablePagination = ({
|
|
|
326
366
|
? autoRefreshing
|
|
327
367
|
: false;
|
|
328
368
|
const resolvedData = autoMode
|
|
329
|
-
? (autoHasLoaded && Array.isArray(store?.getters?.items) ? store.getters.items : [])
|
|
369
|
+
? (autoHasLoaded && ownsStoreResult && Array.isArray(store?.getters?.items) ? store.getters.items : [])
|
|
330
370
|
: (Array.isArray(data) ? data : []);
|
|
331
371
|
const resolvedHasMore = useMemo(
|
|
332
372
|
() => {
|
|
@@ -416,8 +456,10 @@ export const useDefaultTablePagination = ({
|
|
|
416
456
|
return {
|
|
417
457
|
buildRequestQuery,
|
|
418
458
|
currentPage,
|
|
459
|
+
paginateData,
|
|
419
460
|
goToPage: page => {
|
|
420
|
-
const totalPages = Math.max(1, Math.ceil(Number(resolvedTotalItems || 0) / pageSizeNumber));
|
|
461
|
+
const totalPages = autoMode ? Math.max(1, Math.ceil(Number(resolvedTotalItems || 0) / pageSizeNumber)) : localPages;
|
|
462
|
+
if (!autoMode && paginationMode === 'pages' && Number.isInteger(page) && page >= 1 && page <= totalPages && !resolvedIsLoading) setLocalPage({key: localQueryKey, page});
|
|
421
463
|
if (autoMode && paginationMode === 'pages' && Number.isInteger(page) && page >= 1 && page <= totalPages && !resolvedIsLoading) {
|
|
422
464
|
return loadAutoPage(page, {append: false});
|
|
423
465
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useRef } from 'react';
|
|
1
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
persistTableFiltersPreference,
|
|
4
4
|
resolveStoredTableFiltersPreference,
|
|
@@ -65,7 +65,15 @@ export function useDefaultTableStoreSync({
|
|
|
65
65
|
const storeRef = useRef(store);
|
|
66
66
|
storeRef.current = store;
|
|
67
67
|
const lastPublishedItemsRef = useRef(undefined);
|
|
68
|
-
|
|
68
|
+
// Keep custom presentation closures current (for example after a theme switch)
|
|
69
|
+
// without publishing configs for every new callback identity and reintroducing #185.
|
|
70
|
+
const cardOwner = useMemo(() => {
|
|
71
|
+
const owner = {current: null, signature: ''};
|
|
72
|
+
owner.render = (...args) => owner.current?.(...args);
|
|
73
|
+
return owner;
|
|
74
|
+
}, [storeName, store?.actions?.setConfigs]);
|
|
75
|
+
cardOwner.current = defaultTableConfigs.renderCard;
|
|
76
|
+
const hasRenderCard = typeof defaultTableConfigs.renderCard === 'function';
|
|
69
77
|
const lastHydratedFiltersKeyRef = useRef('');
|
|
70
78
|
const storeFiltersRef = useRef(storeFilters);
|
|
71
79
|
storeFiltersRef.current = storeFilters;
|
|
@@ -163,11 +171,15 @@ export function useDefaultTableStoreSync({
|
|
|
163
171
|
}, [filters]);
|
|
164
172
|
|
|
165
173
|
useEffect(() => {
|
|
166
|
-
|
|
174
|
+
const signature = `${storeName}:${defaultTableConfigsSignature}:render-card:${hasRenderCard}`;
|
|
175
|
+
if (cardOwner.signature === signature) {
|
|
167
176
|
return;
|
|
168
177
|
}
|
|
169
178
|
|
|
170
|
-
|
|
171
|
-
publishStoreValue(storeRef.current, 'setConfigs',
|
|
172
|
-
|
|
179
|
+
cardOwner.signature = signature;
|
|
180
|
+
publishStoreValue(storeRef.current, 'setConfigs', {
|
|
181
|
+
...defaultTableConfigs,
|
|
182
|
+
renderCard: hasRenderCard ? cardOwner.render : defaultTableConfigs.renderCard,
|
|
183
|
+
}, 'configs');
|
|
184
|
+
}, [defaultTableConfigs, defaultTableConfigsSignature, storeName, hasRenderCard, cardOwner]);
|
|
173
185
|
}
|