@controleonline/ui-default 1.0.280 → 1.0.282
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 +2 -2
- 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 +32 -21
- package/src/react/components/table/DefaultTable.layoutUtils.js +1 -0
- package/src/react/components/table/DefaultTableCards.js +5 -2
- package/src/react/components/table/DefaultTableCompactToolbar.js +2 -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/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 = {},
|
|
@@ -78,15 +76,18 @@ const DefaultTable = ({
|
|
|
78
76
|
showSearch = null,
|
|
79
77
|
showRowActions = true,
|
|
80
78
|
showToolbar = true,
|
|
79
|
+
showCompactCaption = true,
|
|
80
|
+
showAdministrativeTools = true,
|
|
81
81
|
showToolbarActions = null,
|
|
82
82
|
showToolbarControls = null,
|
|
83
83
|
showTotalItemsInCompactToolbar = false,
|
|
84
84
|
showTotalItemsInFooter = true,
|
|
85
85
|
sort = null,
|
|
86
86
|
storeName = '',
|
|
87
|
-
summary = undefined,
|
|
87
|
+
summary = undefined, totalItems = undefined,
|
|
88
88
|
summaryLabels = {},
|
|
89
89
|
toolbarActions = [],
|
|
90
|
+
viewMode = null,
|
|
90
91
|
visibleColumnsPreferenceKey = '',
|
|
91
92
|
}) => {
|
|
92
93
|
const { width } = useWindowDimensions();
|
|
@@ -128,13 +129,13 @@ const DefaultTable = ({
|
|
|
128
129
|
const columnsForTable = storeColumns.length > 0 ? storeColumns : columns;
|
|
129
130
|
const storeFilters = isObject(store?.getters?.filters) ? store.getters.filters : {};
|
|
130
131
|
const requestParamsSeed = isObject(requestParams) ? requestParams : {};
|
|
131
|
-
const resolvedTotalItems = store?.getters?.totalItems;
|
|
132
|
+
const resolvedTotalItems = totalItems ?? (!autoMode && paginationMode === 'pages' ? data.length : store?.getters?.totalItems);
|
|
133
|
+
useEffect(() => {if ((!autoMode && paginationMode === 'pages') || totalItems !== undefined) publishStoreValue(store, 'setTotalItems', resolvedTotalItems, 'totalItems');}, [autoMode, paginationMode, totalItems, resolvedTotalItems, storeName, store?.actions?.setTotalItems]);
|
|
132
134
|
if (storeDeclaredConfigsRef.current === null) {
|
|
133
135
|
storeDeclaredConfigsRef.current = isObject(store?.getters?.configs)
|
|
134
136
|
? store.getters.configs
|
|
135
137
|
: {};
|
|
136
138
|
}
|
|
137
|
-
|
|
138
139
|
const storeDeclaredConfigs = storeDeclaredConfigsRef.current || {};
|
|
139
140
|
const currentConfigs = {
|
|
140
141
|
...storeDeclaredConfigs,
|
|
@@ -148,11 +149,9 @@ const DefaultTable = ({
|
|
|
148
149
|
normalizeText(addLabel) ||
|
|
149
150
|
normalizeText(global.t?.t(storeName, 'button', 'add')) ||
|
|
150
151
|
'Adicionar';
|
|
151
|
-
|
|
152
152
|
if (storeColumns.length === 0 && Array.isArray(columns) && columns.length > 0) {
|
|
153
153
|
assignGetterValue(store, 'columns', columns);
|
|
154
154
|
}
|
|
155
|
-
|
|
156
155
|
if (data !== undefined && Array.isArray(data)) {
|
|
157
156
|
assignGetterValue(store, 'items', data);
|
|
158
157
|
}
|
|
@@ -167,7 +166,7 @@ const DefaultTable = ({
|
|
|
167
166
|
const {
|
|
168
167
|
buildRequestQuery,
|
|
169
168
|
currentPage,
|
|
170
|
-
pageSizeNumber,
|
|
169
|
+
pageSizeNumber, paginateData,
|
|
171
170
|
goToPage,
|
|
172
171
|
resolvedIsLoading,
|
|
173
172
|
handleEndReached,
|
|
@@ -194,12 +193,13 @@ const DefaultTable = ({
|
|
|
194
193
|
store,
|
|
195
194
|
storeName,
|
|
196
195
|
});
|
|
197
|
-
const
|
|
196
|
+
const sortedItems = useDefaultTableSortedData({
|
|
198
197
|
resolvedData,
|
|
199
198
|
resolvedSort,
|
|
200
199
|
storeName,
|
|
201
200
|
tableColumns: columnsForTable,
|
|
202
201
|
});
|
|
202
|
+
const sortedData = useMemo(() => paginateData(sortedItems), [paginateData, sortedItems]);
|
|
203
203
|
const {isCreateFormOpen, closeCreateForm, resolvedOnAdd, handleDefaultCreateSaved} =
|
|
204
204
|
useDefaultTableCreateForm({onAdd, onSaved, resolvedActions, handleRefresh});
|
|
205
205
|
const hasAddAction =
|
|
@@ -225,11 +225,11 @@ const DefaultTable = ({
|
|
|
225
225
|
const previousCompactRef = useRef(isCompactView);
|
|
226
226
|
const enteringCompact = isCompactView && !previousCompactRef.current;
|
|
227
227
|
useEffect(() => {previousCompactRef.current = isCompactView;}, [isCompactView]);
|
|
228
|
-
const effectiveViewMode =
|
|
228
|
+
const effectiveViewMode = viewMode || (
|
|
229
229
|
enteringCompact && forceCardsOnCompact !== false ? 'cards' :
|
|
230
230
|
currentConfigs.viewMode ||
|
|
231
231
|
storedViewMode ||
|
|
232
|
-
(isCompactView && forceCardsOnCompact !== false ? 'cards' : initialViewMode);
|
|
232
|
+
(isCompactView && forceCardsOnCompact !== false ? 'cards' : initialViewMode));
|
|
233
233
|
const tableFiltersVisible = Boolean(currentConfigs.tableFiltersVisible);
|
|
234
234
|
const defaultTableConfigs = useMemo(
|
|
235
235
|
() => ({
|
|
@@ -247,7 +247,7 @@ const DefaultTable = ({
|
|
|
247
247
|
compactBreakpoint,
|
|
248
248
|
debugFallbackParameters,
|
|
249
249
|
defaultColor,
|
|
250
|
-
effectiveViewMode,
|
|
250
|
+
effectiveViewMode, viewMode,
|
|
251
251
|
filters,
|
|
252
252
|
footerComponent,
|
|
253
253
|
forceCardsOnCompact,
|
|
@@ -274,6 +274,7 @@ const DefaultTable = ({
|
|
|
274
274
|
requestParams: requestParamsSeed,
|
|
275
275
|
requestSort,
|
|
276
276
|
resolvedSort,
|
|
277
|
+
presentationColumns,
|
|
277
278
|
rowActionsComponent,
|
|
278
279
|
rowActionsWidth,
|
|
279
280
|
rowStyle,
|
|
@@ -282,8 +283,10 @@ const DefaultTable = ({
|
|
|
282
283
|
selectable: storeSelectable,
|
|
283
284
|
showColumnFiltersButton,
|
|
284
285
|
showSearch,
|
|
285
|
-
showRowActions: storeDeclaredConfigs.showRowActions === false ? false : showRowActions,
|
|
286
|
+
showRowActions: presentationColumns !== null ? showRowActions : storeDeclaredConfigs.showRowActions === false ? false : showRowActions,
|
|
287
|
+
showAdministrativeTools,
|
|
286
288
|
showToolbar,
|
|
289
|
+
showCompactCaption,
|
|
287
290
|
showToolbarActions:
|
|
288
291
|
showToolbarActions === null
|
|
289
292
|
? storeDeclaredConfigs.showToolbarActions !== false
|
|
@@ -303,7 +306,8 @@ const DefaultTable = ({
|
|
|
303
306
|
refreshing: resolvedIsRefreshing,
|
|
304
307
|
tablePreferenceScope,
|
|
305
308
|
toolbarActions,
|
|
306
|
-
|
|
309
|
+
// A controlled presentation must not replace the saved list mode.
|
|
310
|
+
viewMode: viewMode ? storeDeclaredConfigs.viewMode : effectiveViewMode,
|
|
307
311
|
}),
|
|
308
312
|
[
|
|
309
313
|
appearance, paginationMode, currentPage, pageSizeNumber, goToPage, resolvedIsLoading,
|
|
@@ -314,7 +318,7 @@ const DefaultTable = ({
|
|
|
314
318
|
compactBreakpoint,
|
|
315
319
|
debugFallbackParameters,
|
|
316
320
|
defaultColor,
|
|
317
|
-
effectiveViewMode,
|
|
321
|
+
effectiveViewMode, viewMode,
|
|
318
322
|
filters,
|
|
319
323
|
footerComponent,
|
|
320
324
|
forceCardsOnCompact,
|
|
@@ -344,6 +348,7 @@ const DefaultTable = ({
|
|
|
344
348
|
requestSort,
|
|
345
349
|
resolvedIsRefreshing,
|
|
346
350
|
resolvedSort,
|
|
351
|
+
presentationColumns,
|
|
347
352
|
rowActionsComponent,
|
|
348
353
|
rowActionsWidth,
|
|
349
354
|
rowStyle,
|
|
@@ -352,7 +357,9 @@ const DefaultTable = ({
|
|
|
352
357
|
showColumnFiltersButton,
|
|
353
358
|
showSearch,
|
|
354
359
|
showRowActions,
|
|
360
|
+
showAdministrativeTools,
|
|
355
361
|
showToolbar,
|
|
362
|
+
showCompactCaption,
|
|
356
363
|
showToolbarActions,
|
|
357
364
|
showToolbarControls,
|
|
358
365
|
showTotalItemsInCompactToolbar,
|
|
@@ -384,6 +391,7 @@ const DefaultTable = ({
|
|
|
384
391
|
hasImportAction: Boolean(storeDeclaredConfigs.import || importAction || onImport),
|
|
385
392
|
initialViewMode,
|
|
386
393
|
pinRowActions,
|
|
394
|
+
presentationColumns,
|
|
387
395
|
rowActionsComponentType: rowActionsComponent ? typeof rowActionsComponent : '',
|
|
388
396
|
rowActionsWidth,
|
|
389
397
|
resolvedIsRefreshing,
|
|
@@ -394,12 +402,14 @@ const DefaultTable = ({
|
|
|
394
402
|
showColumnFiltersButton,
|
|
395
403
|
showSearch,
|
|
396
404
|
showRowActions,
|
|
405
|
+
showAdministrativeTools,
|
|
397
406
|
showToolbar,
|
|
407
|
+
showCompactCaption,
|
|
398
408
|
showToolbarActions,
|
|
399
409
|
showToolbarControls,
|
|
400
410
|
showTotalItemsInCompactToolbar,
|
|
401
411
|
showTotalItemsInFooter,
|
|
402
|
-
storedViewMode,
|
|
412
|
+
storedViewMode, controlledViewMode: viewMode,
|
|
403
413
|
tableFiltersVisible,
|
|
404
414
|
sortedData: stableSerialize(sortedData),
|
|
405
415
|
toolbarActionsLength: Array.isArray(toolbarActions) ? toolbarActions.length : 0,
|
|
@@ -413,7 +423,7 @@ const DefaultTable = ({
|
|
|
413
423
|
compactBreakpoint,
|
|
414
424
|
defaultColor,
|
|
415
425
|
debugFallbackParameters,
|
|
416
|
-
effectiveViewMode,
|
|
426
|
+
effectiveViewMode, viewMode,
|
|
417
427
|
filters,
|
|
418
428
|
forceCardsOnCompact,
|
|
419
429
|
storeDeclaredConfigs,
|
|
@@ -424,6 +434,7 @@ const DefaultTable = ({
|
|
|
424
434
|
onExport,
|
|
425
435
|
onImport,
|
|
426
436
|
pinRowActions,
|
|
437
|
+
presentationColumns,
|
|
427
438
|
rowActionsComponent,
|
|
428
439
|
rowActionsWidth,
|
|
429
440
|
resolvedIsRefreshing,
|
|
@@ -433,7 +444,9 @@ const DefaultTable = ({
|
|
|
433
444
|
showColumnFiltersButton,
|
|
434
445
|
showSearch,
|
|
435
446
|
showRowActions,
|
|
447
|
+
showAdministrativeTools,
|
|
436
448
|
showToolbar,
|
|
449
|
+
showCompactCaption,
|
|
437
450
|
showToolbarActions,
|
|
438
451
|
showToolbarControls,
|
|
439
452
|
showTotalItemsInCompactToolbar,
|
|
@@ -444,7 +457,6 @@ const DefaultTable = ({
|
|
|
444
457
|
toolbarActions,
|
|
445
458
|
],
|
|
446
459
|
);
|
|
447
|
-
|
|
448
460
|
// Do not mutate store.configs during render. A new configs object is built
|
|
449
461
|
// every pass; writing it here retriggers subscribers and React #185 when
|
|
450
462
|
// opening Adicionar on DefaultTable (categories). Sync only in the hook
|
|
@@ -490,5 +502,4 @@ const DefaultTable = ({
|
|
|
490
502
|
requestParamsSeed
|
|
491
503
|
}} />;
|
|
492
504
|
};
|
|
493
|
-
|
|
494
505
|
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}
|
|
@@ -83,12 +83,12 @@ export default function DefaultTableCompactToolbar({storeName, actions = [], sho
|
|
|
83
83
|
<Text numberOfLines={1} style={[s.small, {color: c.chipText || text, flexShrink: 1}]}>{label}</Text><Icon name="x" size={12} color={text} />
|
|
84
84
|
</TouchableOpacity>;
|
|
85
85
|
})}<TouchableOpacity accessibilityRole="button" onPress={() => apply({})}><Text style={[s.small, {color: muted}]}>Limpar filtros</Text></TouchableOpacity></View> : null}
|
|
86
|
-
<View style={s.secondary}>
|
|
86
|
+
{configs.showCompactCaption !== false && <View style={s.secondary}>
|
|
87
87
|
<Text style={[s.small, {color: muted}]}>{configs.showTotalItemsInFooter !== false ? `${store.getters?.totalItems ?? 0} ${Number(store.getters?.totalItems) === 1 ? 'resultado' : 'resultados'}` : 'Pedidos'}</Text>
|
|
88
88
|
{showControls ? <TouchableOpacity accessibilityRole="button" accessibilityLabel="Escolher ordenação" onPress={() => setModal('sort')} style={s.row}>
|
|
89
89
|
<Icon name="arrow-down" size={14} color={muted} /><Text style={[s.small, {color: text}]}>{sortColumn ? labelFor(sortColumn) : 'Ordenar'} · {configs.resolvedSort?.direction === 'asc' ? '↑' : '↓'}</Text>
|
|
90
90
|
</TouchableOpacity> : null}
|
|
91
|
-
</View>
|
|
91
|
+
</View>}
|
|
92
92
|
<DefaultFiltersModal storeName={storeName} visible={modal === 'filters'} deferred onClose={() => setModal('')} />
|
|
93
93
|
<DefaultColumnMenu storeName={storeName} visible={modal === 'columns'} onClose={() => setModal('')} />
|
|
94
94
|
<DefaultCompactDialog visible={modal === 'more' || modal === 'sort'} title={modal === 'sort' ? 'Ordenação' : 'Mais opções'}
|
|
@@ -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
|
}
|