@controleonline/ui-default 1.0.272 → 1.0.274
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/.github/workflows/publish-npm.yml +91 -0
- package/AGENTS.md +1 -1
- package/docs/technical/DefaultTable.md +70 -1
- package/package.json +22 -22
- package/src/react/components/address/DefaultAddress.js +20 -9
- package/src/react/components/address/DefaultAddressCoordFields.js +59 -0
- package/src/react/components/address/LatLonReadonlyFields.js +2 -2
- package/src/react/components/address/defaultAddressStyles.js +13 -1
- package/src/react/components/files/DefaultFile.js +2 -2
- package/src/react/components/files/DefaultFileColumn.js +1 -1
- package/src/react/components/filters/DefaultColumnFilter.js +2 -7
- package/src/react/components/filters/DefaultExternalFilters.js +4 -11
- package/src/react/components/filters/filterValue.js +65 -0
- package/src/react/components/help/DefaultTooltip.js +73 -63
- package/src/react/components/help/DefaultTooltip.styles.js +23 -23
- package/src/react/components/inputs/DefaultInput.js +301 -210
- package/src/react/components/inputs/defaultInputUtils.js +193 -170
- package/src/react/components/table/DefaultColumnMenu.js +127 -109
- package/src/react/components/table/DefaultTable.js +43 -92
- package/src/react/components/table/DefaultTable.styles.js +10 -4
- package/src/react/components/table/DefaultTable.utils.js +38 -4
- package/src/react/components/table/DefaultTableRows.js +324 -153
- package/src/react/components/table/DefaultTableToolbar.js +17 -7
- package/src/react/components/table/DefaultTableView.js +118 -0
- package/src/react/components/upload/DefaultUpload.js +6 -36
- package/src/react/components/upload/DefaultUpload.styles.js +5 -5
- package/src/react/components/upload/DefaultUploadAttachmentsList.js +11 -3
- package/src/react/hooks/usePostalCodeLookup.js +15 -1
- package/src/react/services/addressFormUtils.js +104 -38
- package/src/react/services/addressGeo.js +6 -3
- package/src/react/utils/tableVisibleColumnsPreferences.js +84 -3
- package/src/tests/react/components/files/DefaultFile.test.js +16 -0
- package/src/tests/react/components/files/DefaultFileColumn.company.test.js +24 -0
- package/src/tests/react/components/help/DefaultTooltip.test.js +93 -0
- package/src/tests/react/components/table/DefaultTable.test.js +37 -0
- package/src/tests/react/components/table/DefaultTable.utils.test.js +10 -0
- package/src/tests/react/components/table/DefaultTableRowActions.test.js +23 -0
- package/src/tests/react/components/table/DefaultTableRows.rowActions.test.js +152 -0
- package/src/tests/react/components/table/DefaultTableToolbar.waiter.test.js +42 -0
- package/src/tests/react/components/upload/defaultUploadLibrary.test.js +31 -9
- package/src/tests/react/filters/filterValue.test.js +46 -0
- package/src/tests/react/hooks/usePostalCodeLookup.test.js +67 -0
- package/src/tests/react/inputs/defaultInputUtils.test.js +9 -1
- package/src/tests/react/services/addressFormUtils.test.js +6 -3
- package/src/tests/react/utils/tableVisibleColumnsPreferences.test.js +12 -1
|
@@ -4,20 +4,13 @@ import Icon from 'react-native-vector-icons/Feather';
|
|
|
4
4
|
import { useStore } from '@store';
|
|
5
5
|
import { formatStoreColumnLabel } from '@controleonline/ui-common/src/react/utils/storeColumns';
|
|
6
6
|
import { getColumnKey } from '../inputs/defaultInputUtils';
|
|
7
|
+
import DefaultColumnFilter from '../filters/DefaultColumnFilter';
|
|
7
8
|
import DefaultTableEmptyState from './DefaultTableEmptyState';
|
|
8
9
|
import DefaultTableInput from './DefaultTableInput';
|
|
9
10
|
import DefaultTableRowActions, {
|
|
10
11
|
hasDefaultTableRowActionsComponent,
|
|
11
12
|
resolveDefaultTableRowActionsWidth,
|
|
12
13
|
} from './DefaultTableRowActions';
|
|
13
|
-
import {
|
|
14
|
-
persistStoreSelection,
|
|
15
|
-
flattenGroupedTableItems,
|
|
16
|
-
isRowSelected,
|
|
17
|
-
resolveStoreSelectedIds,
|
|
18
|
-
toggleGroupSelection,
|
|
19
|
-
toggleSelectedId,
|
|
20
|
-
} from './DefaultTable.grouping';
|
|
21
14
|
import {
|
|
22
15
|
END_REACHED_THRESHOLD,
|
|
23
16
|
getColumnStyle,
|
|
@@ -32,17 +25,8 @@ import {
|
|
|
32
25
|
import styles from './DefaultTable.styles';
|
|
33
26
|
import useDefaultTableTheme from './useDefaultTableTheme';
|
|
34
27
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
/** Row stripe colors from themes-map listItemEvenRow / listItemOddRow — never status.color. */
|
|
38
|
-
export const resolveRowBackgroundColor = ({
|
|
39
|
-
selected,
|
|
40
|
-
index,
|
|
41
|
-
tableOddColor,
|
|
42
|
-
tableEvenColor,
|
|
43
|
-
selectedBackground = '#ECFEFF',
|
|
44
|
-
}) => {
|
|
45
|
-
if (selected) return selectedBackground;
|
|
28
|
+
/** Row stripes: themes-map listItemEvenRow / listItemOddRow — never status.color. */
|
|
29
|
+
export const resolveRowBackgroundColor = ({ index, tableOddColor, tableEvenColor }) => {
|
|
46
30
|
return index % 2 === 0 ? tableOddColor : tableEvenColor;
|
|
47
31
|
};
|
|
48
32
|
|
|
@@ -59,179 +43,366 @@ const DefaultTableRows = ({ storeName }) => {
|
|
|
59
43
|
liveItems: store?.getters?.items,
|
|
60
44
|
sortedData: configs.sortedData,
|
|
61
45
|
});
|
|
62
|
-
const
|
|
63
|
-
const selectable = configs.selectable === true;
|
|
64
|
-
const selectedIds = resolveStoreSelectedIds(store);
|
|
46
|
+
const resolvedFilters = store?.getters?.filters || {};
|
|
65
47
|
const isLoading = Boolean(store?.getters?.isLoadingList || store?.getters?.isLoading);
|
|
66
|
-
const emptyStateLabel = isLoading
|
|
48
|
+
const emptyStateLabel = isLoading
|
|
49
|
+
? global.t?.t(storeName, 'label', 'loading')
|
|
50
|
+
: global.t?.t(storeName, 'label', 'empty');
|
|
67
51
|
const tableBorderColor = tableBorderColors.rowBorderColor;
|
|
68
52
|
const tableHeaderBorderColor = tableBorderColors.headerBorderColor || tableBorderColor;
|
|
69
53
|
const tableEvenColor = themeTokens.listItemEvenRow || themeTokens['bg-even-light'] || palette.background;
|
|
70
54
|
const tableHeaderColor = themeTokens['bg-headers-light'] || resolvedAccentColor;
|
|
71
55
|
const tableMutedColor = palette.textSecondary;
|
|
72
56
|
const tableOddColor = themeTokens.listItemOddRow || themeTokens['bg-odd-light'] || palette.background;
|
|
57
|
+
const tableSurfaceColor = palette.background;
|
|
73
58
|
const tableTextColor = palette.text;
|
|
74
59
|
const rowStyle = configs.rowStyle;
|
|
75
60
|
const hasRowPress = typeof configs.onRowPress === 'function';
|
|
76
|
-
const
|
|
77
|
-
const hasCustomRowActions = hasDefaultTableRowActionsComponent(RowActionsComponent);
|
|
61
|
+
const hasCustomRowActions = hasDefaultTableRowActionsComponent(configs.rowActionsComponent);
|
|
78
62
|
const hasEditAction = typeof configs.onEditRow === 'function';
|
|
79
|
-
const hasRowActions =
|
|
80
|
-
|
|
81
|
-
const
|
|
63
|
+
const hasRowActions = configs.showRowActions !== false && (hasCustomRowActions || hasEditAction);
|
|
64
|
+
const shouldPinRowActions = configs.pinRowActions !== false;
|
|
65
|
+
const hasColumnFilters =
|
|
66
|
+
configs.showColumnFiltersButton !== false &&
|
|
67
|
+
configs.tableFiltersVisible === true;
|
|
82
68
|
const actionsCellWidth = hasRowActions ? resolveDefaultTableRowActionsWidth(configs) : 0;
|
|
83
|
-
const selectionWidth = selectable ? SELECTION_COLUMN_WIDTH : 0;
|
|
84
69
|
const tableMinWidth = useMemo(
|
|
85
|
-
() =>
|
|
86
|
-
|
|
70
|
+
() =>
|
|
71
|
+
tableColumns.reduce(
|
|
72
|
+
(totalWidth, column) => totalWidth + getColumnMinWidth(column),
|
|
73
|
+
actionsCellWidth,
|
|
74
|
+
),
|
|
75
|
+
[actionsCellWidth, tableColumns],
|
|
87
76
|
);
|
|
88
|
-
const [horizontalMetrics, setHorizontalMetrics] = useState({
|
|
77
|
+
const [horizontalMetrics, setHorizontalMetrics] = useState({
|
|
78
|
+
contentWidth: 0,
|
|
79
|
+
viewportWidth: 0,
|
|
80
|
+
x: 0,
|
|
81
|
+
});
|
|
89
82
|
const updateHorizontalMetrics = patch => {
|
|
90
83
|
setHorizontalMetrics(current => {
|
|
91
|
-
const next = {
|
|
92
|
-
|
|
84
|
+
const next = {
|
|
85
|
+
...current,
|
|
86
|
+
...patch,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
return next.contentWidth === current.contentWidth &&
|
|
90
|
+
next.viewportWidth === current.viewportWidth &&
|
|
91
|
+
next.x === current.x
|
|
92
|
+
? current
|
|
93
|
+
: next;
|
|
93
94
|
});
|
|
94
95
|
};
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
96
|
+
const stickyBodyTransforms = useMemo(() => {
|
|
97
|
+
const viewportWidth = Number(horizontalMetrics.viewportWidth || 0);
|
|
98
|
+
const contentWidth = Number(horizontalMetrics.contentWidth || 0);
|
|
99
|
+
const x = Number(horizontalMetrics.x || 0);
|
|
100
|
+
const canScrollHorizontally = viewportWidth > 0 && contentWidth > viewportWidth;
|
|
101
|
+
const actionsTranslateX = canScrollHorizontally
|
|
102
|
+
? x + viewportWidth - contentWidth
|
|
103
|
+
: 0;
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
openRow={hasRowPress ? () => configs.onRowPress(row) : null}
|
|
116
|
-
row={row}
|
|
117
|
-
storeName={storeName}
|
|
118
|
-
/>
|
|
119
|
-
) : null;
|
|
120
|
-
|
|
121
|
-
const editButton = hasEditAction ? (
|
|
122
|
-
<Text onPress={() => configs.onEditRow?.(row)} style={{ color: '#0284C7', fontWeight: '800', fontSize: 12 }}>
|
|
123
|
-
{global.t?.t(storeName, 'button', 'edit') || 'Editar'}
|
|
124
|
-
</Text>
|
|
125
|
-
) : null;
|
|
126
|
-
|
|
127
|
-
return (
|
|
128
|
-
<View
|
|
129
|
-
style={[
|
|
130
|
-
styles.cell,
|
|
131
|
-
styles.actionsCell,
|
|
132
|
-
pinRowActions ? styles.stickyActionsCell : null,
|
|
133
|
-
pinRowActions ? styles.pinnedActionsCell : null,
|
|
134
|
-
{
|
|
135
|
-
minWidth: actionsCellWidth,
|
|
136
|
-
width: actionsCellWidth,
|
|
137
|
-
maxWidth: actionsCellWidth,
|
|
138
|
-
flexBasis: actionsCellWidth,
|
|
139
|
-
backgroundColor: rowBackgroundColor,
|
|
140
|
-
},
|
|
141
|
-
]}
|
|
142
|
-
>
|
|
143
|
-
<View style={styles.rowActionsGroup}>
|
|
144
|
-
{customRowActions}
|
|
145
|
-
{editButton}
|
|
146
|
-
</View>
|
|
147
|
-
</View>
|
|
148
|
-
);
|
|
105
|
+
return {
|
|
106
|
+
actions:
|
|
107
|
+
shouldPinRowActions && actionsTranslateX !== 0
|
|
108
|
+
? [{ translateX: actionsTranslateX }]
|
|
109
|
+
: null,
|
|
110
|
+
};
|
|
111
|
+
}, [horizontalMetrics, shouldPinRowActions]);
|
|
112
|
+
const handleHorizontalScroll = event => {
|
|
113
|
+
updateHorizontalMetrics({
|
|
114
|
+
x: Number(event?.nativeEvent?.contentOffset?.x || 0),
|
|
115
|
+
});
|
|
149
116
|
};
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
<View
|
|
155
|
-
style={[
|
|
156
|
-
styles.cell,
|
|
157
|
-
styles.actionsCell,
|
|
158
|
-
pinRowActions ? styles.stickyActionsCell : null,
|
|
159
|
-
pinRowActions ? styles.stickyHeaderCell : null,
|
|
160
|
-
{
|
|
161
|
-
minWidth: actionsCellWidth,
|
|
162
|
-
width: actionsCellWidth,
|
|
163
|
-
maxWidth: actionsCellWidth,
|
|
164
|
-
flexBasis: actionsCellWidth,
|
|
165
|
-
backgroundColor: tableHeaderColor,
|
|
166
|
-
},
|
|
167
|
-
]}
|
|
168
|
-
>
|
|
169
|
-
<Text style={[styles.headerText, { color: tableTextColor }]} numberOfLines={1}>
|
|
170
|
-
{global.t?.t(storeName, 'label', 'actions') || 'Ações'}
|
|
171
|
-
</Text>
|
|
172
|
-
</View>
|
|
173
|
-
);
|
|
117
|
+
const handleHorizontalLayout = event => {
|
|
118
|
+
updateHorizontalMetrics({
|
|
119
|
+
viewportWidth: Number(event?.nativeEvent?.layout?.width || 0),
|
|
120
|
+
});
|
|
174
121
|
};
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
<View style={{ flex: 1, paddingHorizontal: 8 }}>
|
|
184
|
-
<Text style={[styles.headerText, { color: tableTextColor }]} numberOfLines={2}>{item.group?.label}</Text>
|
|
185
|
-
<Text style={{ color: tableMutedColor, fontSize: 12 }}>{item.group?.count} item(s)</Text>
|
|
186
|
-
</View>
|
|
187
|
-
{hasRowActions ? <View style={{ minWidth: actionsCellWidth, width: actionsCellWidth }} /> : null}
|
|
188
|
-
</View>
|
|
189
|
-
);
|
|
122
|
+
const handleHorizontalContentSizeChange = width => {
|
|
123
|
+
updateHorizontalMetrics({
|
|
124
|
+
contentWidth: Number(width || 0),
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
const handleListScroll = event => {
|
|
128
|
+
if (shouldTriggerEndReachedFromScroll(event)) {
|
|
129
|
+
configs.onEndReached?.();
|
|
190
130
|
}
|
|
131
|
+
};
|
|
132
|
+
const tableWidth = Math.max(
|
|
133
|
+
tableMinWidth,
|
|
134
|
+
Number(horizontalMetrics.viewportWidth || 0),
|
|
135
|
+
);
|
|
191
136
|
|
|
192
|
-
|
|
193
|
-
const RowComponent = hasRowPress
|
|
194
|
-
const
|
|
137
|
+
const renderTableItem = ({ item: row, index }) => {
|
|
138
|
+
const RowComponent = hasRowPress ? TouchableOpacity : View;
|
|
139
|
+
const rowStyleValue = typeof rowStyle === 'function' ? rowStyle(row, index) : rowStyle;
|
|
140
|
+
const rowPressProps = hasRowPress
|
|
141
|
+
? {
|
|
142
|
+
activeOpacity: 0.84,
|
|
143
|
+
onPress: () => configs.onRowPress(row),
|
|
144
|
+
}
|
|
145
|
+
: {};
|
|
195
146
|
const rowBackgroundColor = resolveRowBackgroundColor({
|
|
196
|
-
selected,
|
|
197
147
|
index,
|
|
198
148
|
tableOddColor,
|
|
199
149
|
tableEvenColor,
|
|
200
150
|
});
|
|
151
|
+
const RowActionsComponent = configs.rowActionsComponent;
|
|
152
|
+
|
|
201
153
|
return (
|
|
202
|
-
<RowComponent
|
|
203
|
-
{
|
|
154
|
+
<RowComponent
|
|
155
|
+
key={getRowKey(row)}
|
|
156
|
+
style={[
|
|
157
|
+
styles.row,
|
|
158
|
+
{
|
|
159
|
+
backgroundColor: rowBackgroundColor,
|
|
160
|
+
borderBottomColor: tableBorderColor,
|
|
161
|
+
borderBottomWidth: tableBorderColor ? 1 : 0,
|
|
162
|
+
minWidth: tableWidth,
|
|
163
|
+
width: tableWidth,
|
|
164
|
+
},
|
|
165
|
+
rowStyleValue,
|
|
166
|
+
]}
|
|
167
|
+
{...rowPressProps}
|
|
168
|
+
>
|
|
204
169
|
{tableColumns.map(column => (
|
|
205
170
|
<React.Fragment key={getColumnKey(column)}>
|
|
206
|
-
<DefaultTableInput
|
|
171
|
+
<DefaultTableInput
|
|
172
|
+
column={column}
|
|
173
|
+
options={column?.isIdentity ? {
|
|
174
|
+
cellStyle: [
|
|
175
|
+
styles.pinnedIdentityCell,
|
|
176
|
+
styles.stickyIdentityCell,
|
|
177
|
+
{
|
|
178
|
+
backgroundColor: rowBackgroundColor,
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
} : {
|
|
182
|
+
cellStyle: {
|
|
183
|
+
backgroundColor: rowBackgroundColor,
|
|
184
|
+
},
|
|
185
|
+
}}
|
|
186
|
+
row={row}
|
|
187
|
+
storeName={storeName}
|
|
188
|
+
variant="cell"
|
|
189
|
+
/>
|
|
207
190
|
</React.Fragment>
|
|
208
191
|
))}
|
|
209
|
-
{
|
|
192
|
+
{hasRowActions ? (
|
|
193
|
+
<View
|
|
194
|
+
testID={`default-table-row-actions-${getRowKey(row)}`}
|
|
195
|
+
style={[
|
|
196
|
+
styles.cell,
|
|
197
|
+
styles.actionsCell,
|
|
198
|
+
shouldPinRowActions ? styles.pinnedActionsCell : null,
|
|
199
|
+
shouldPinRowActions ? styles.stickyActionsCell : null,
|
|
200
|
+
{
|
|
201
|
+
minWidth: actionsCellWidth,
|
|
202
|
+
width: actionsCellWidth,
|
|
203
|
+
flexBasis: actionsCellWidth,
|
|
204
|
+
maxWidth: actionsCellWidth,
|
|
205
|
+
...(stickyBodyTransforms.actions
|
|
206
|
+
? { transform: stickyBodyTransforms.actions }
|
|
207
|
+
: {}),
|
|
208
|
+
backgroundColor: rowBackgroundColor,
|
|
209
|
+
},
|
|
210
|
+
]}
|
|
211
|
+
>
|
|
212
|
+
<View style={styles.rowActionsGroup}>
|
|
213
|
+
{hasCustomRowActions ? (
|
|
214
|
+
<DefaultTableRowActions
|
|
215
|
+
component={RowActionsComponent}
|
|
216
|
+
helpers={{
|
|
217
|
+
openEdit: () => configs.onEditRow?.(row),
|
|
218
|
+
openRow: hasRowPress ? () => configs.onRowPress(row) : null,
|
|
219
|
+
}}
|
|
220
|
+
openEdit={() => configs.onEditRow?.(row)}
|
|
221
|
+
openRow={hasRowPress ? () => configs.onRowPress(row) : null}
|
|
222
|
+
row={row}
|
|
223
|
+
storeName={storeName}
|
|
224
|
+
/>
|
|
225
|
+
) : null}
|
|
226
|
+
{hasEditAction ? (
|
|
227
|
+
<TouchableOpacity
|
|
228
|
+
style={[styles.iconButton, { borderColor: tableBorderColor, backgroundColor: tableSurfaceColor }]}
|
|
229
|
+
activeOpacity={0.82}
|
|
230
|
+
onPress={() => configs.onEditRow?.(row)}
|
|
231
|
+
>
|
|
232
|
+
<Icon name="edit-2" size={14} color={tableMutedColor} />
|
|
233
|
+
</TouchableOpacity>
|
|
234
|
+
) : null}
|
|
235
|
+
</View>
|
|
236
|
+
</View>
|
|
237
|
+
) : null}
|
|
210
238
|
</RowComponent>
|
|
211
239
|
);
|
|
212
240
|
};
|
|
213
241
|
|
|
214
242
|
return (
|
|
215
|
-
|
|
216
|
-
<
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
243
|
+
<>
|
|
244
|
+
<ScrollView
|
|
245
|
+
horizontal
|
|
246
|
+
onContentSizeChange={handleHorizontalContentSizeChange}
|
|
247
|
+
onLayout={handleHorizontalLayout}
|
|
248
|
+
onScroll={handleHorizontalScroll}
|
|
249
|
+
scrollEventThrottle={16}
|
|
250
|
+
style={styles.scroll}
|
|
251
|
+
contentContainerStyle={styles.horizontalScrollContent}
|
|
252
|
+
>
|
|
253
|
+
<View style={[styles.content, { minWidth: tableWidth, width: tableWidth }]}>
|
|
254
|
+
<View
|
|
255
|
+
style={[
|
|
256
|
+
styles.headerRow,
|
|
257
|
+
{
|
|
258
|
+
backgroundColor: tableHeaderColor,
|
|
259
|
+
borderBottomColor: tableHeaderBorderColor,
|
|
260
|
+
borderBottomWidth: tableHeaderBorderColor ? 1 : 0,
|
|
261
|
+
minWidth: tableWidth,
|
|
262
|
+
width: tableWidth,
|
|
263
|
+
},
|
|
264
|
+
]}
|
|
265
|
+
>
|
|
266
|
+
{tableColumns.map(column => {
|
|
267
|
+
const fieldName = getColumnKey(column);
|
|
268
|
+
const label = formatStoreColumnLabel({
|
|
269
|
+
columns,
|
|
270
|
+
fieldName,
|
|
271
|
+
fallbackLabel: column?.label || fieldName,
|
|
272
|
+
storeName,
|
|
273
|
+
});
|
|
274
|
+
const sortFieldName = getSortField(column);
|
|
275
|
+
|
|
276
|
+
return (
|
|
277
|
+
<TouchableOpacity
|
|
278
|
+
key={fieldName}
|
|
279
|
+
style={[
|
|
280
|
+
getColumnStyle(column),
|
|
281
|
+
column?.isIdentity
|
|
282
|
+
? [styles.stickyIdentityCell, styles.stickyHeaderCell, { backgroundColor: tableHeaderColor }]
|
|
283
|
+
: null,
|
|
284
|
+
]}
|
|
285
|
+
activeOpacity={isSortableColumn(column) ? 0.8 : 1}
|
|
286
|
+
onPress={() => configs.requestSort?.(column)}
|
|
287
|
+
>
|
|
288
|
+
<View style={styles.sortableHeader}>
|
|
289
|
+
<Text style={[styles.headerText, { color: tableTextColor }]} numberOfLines={1}>{label}</Text>
|
|
290
|
+
{isSortableColumn(column) && configs.resolvedSort?.field === sortFieldName ? (
|
|
291
|
+
<Icon name={configs.resolvedSort?.direction === 'desc' ? 'chevron-down' : 'chevron-up'} size={12} color={tableTextColor} />
|
|
292
|
+
) : isSortableColumn(column) ? (
|
|
293
|
+
<Icon name="chevrons-up" size={12} color={tableBorderColor} />
|
|
294
|
+
) : null}
|
|
295
|
+
{resolvedFilters?.[fieldName] ? <Icon name="filter" size={11} color={tableTextColor} /> : null}
|
|
296
|
+
</View>
|
|
297
|
+
</TouchableOpacity>
|
|
298
|
+
);
|
|
299
|
+
})}
|
|
300
|
+
{hasRowActions ? (
|
|
301
|
+
<View
|
|
302
|
+
testID="default-table-row-actions-header"
|
|
303
|
+
style={[
|
|
304
|
+
styles.cell,
|
|
305
|
+
styles.actionsCell,
|
|
306
|
+
shouldPinRowActions ? styles.stickyActionsCell : null,
|
|
307
|
+
shouldPinRowActions ? styles.stickyHeaderCell : null,
|
|
308
|
+
{
|
|
309
|
+
minWidth: actionsCellWidth,
|
|
310
|
+
width: actionsCellWidth,
|
|
311
|
+
flexBasis: actionsCellWidth,
|
|
312
|
+
maxWidth: actionsCellWidth,
|
|
313
|
+
backgroundColor: tableHeaderColor,
|
|
314
|
+
},
|
|
315
|
+
]}
|
|
316
|
+
>
|
|
317
|
+
<Text style={[styles.headerText, { color: tableTextColor }]}>
|
|
318
|
+
{global.t?.t(storeName, 'label', 'actions')}
|
|
319
|
+
</Text>
|
|
320
|
+
</View>
|
|
321
|
+
) : null}
|
|
322
|
+
</View>
|
|
323
|
+
{hasColumnFilters ? (
|
|
324
|
+
<View
|
|
325
|
+
style={[
|
|
326
|
+
styles.filterRow,
|
|
327
|
+
{
|
|
328
|
+
backgroundColor: tableHeaderColor,
|
|
329
|
+
borderBottomColor: tableHeaderBorderColor,
|
|
330
|
+
borderBottomWidth: tableHeaderBorderColor ? 1 : 0,
|
|
331
|
+
},
|
|
332
|
+
]}
|
|
333
|
+
>
|
|
334
|
+
{tableColumns.map(column => {
|
|
335
|
+
const fieldName = getColumnKey(column);
|
|
336
|
+
|
|
337
|
+
return (
|
|
338
|
+
<View
|
|
339
|
+
key={`${fieldName}-filter`}
|
|
340
|
+
style={[
|
|
341
|
+
getColumnStyle(column),
|
|
342
|
+
column?.isIdentity
|
|
343
|
+
? [styles.stickyIdentityCell, { backgroundColor: tableHeaderColor }]
|
|
344
|
+
: null,
|
|
345
|
+
]}
|
|
346
|
+
>
|
|
347
|
+
{column?.filter !== false && column?.filters !== false ? (
|
|
348
|
+
<DefaultColumnFilter
|
|
349
|
+
column={column}
|
|
350
|
+
filters={resolvedFilters}
|
|
351
|
+
storeName={storeName}
|
|
352
|
+
style={styles.filterCell}
|
|
353
|
+
/>
|
|
354
|
+
) : null}
|
|
355
|
+
</View>
|
|
356
|
+
);
|
|
357
|
+
})}
|
|
358
|
+
{hasRowActions ? (
|
|
359
|
+
<View
|
|
360
|
+
style={[
|
|
361
|
+
styles.cell,
|
|
362
|
+
styles.actionsCell,
|
|
363
|
+
shouldPinRowActions ? styles.stickyActionsCell : null,
|
|
364
|
+
{
|
|
365
|
+
minWidth: actionsCellWidth,
|
|
366
|
+
width: actionsCellWidth,
|
|
367
|
+
flexBasis: actionsCellWidth,
|
|
368
|
+
maxWidth: actionsCellWidth,
|
|
369
|
+
backgroundColor: tableHeaderColor,
|
|
370
|
+
},
|
|
371
|
+
]}
|
|
372
|
+
/>
|
|
373
|
+
) : null}
|
|
374
|
+
</View>
|
|
375
|
+
) : null}
|
|
376
|
+
|
|
377
|
+
<FlatList
|
|
378
|
+
data={sortedData}
|
|
379
|
+
keyExtractor={getRowKey}
|
|
380
|
+
renderItem={renderTableItem}
|
|
381
|
+
style={styles.tableList}
|
|
382
|
+
contentContainerStyle={styles.tableListContent}
|
|
383
|
+
ListEmptyComponent={(
|
|
384
|
+
<DefaultTableEmptyState
|
|
385
|
+
emptyStateLabel={emptyStateLabel}
|
|
386
|
+
isLoading={isLoading}
|
|
387
|
+
isTable
|
|
388
|
+
tableMutedColor={tableMutedColor}
|
|
389
|
+
/>
|
|
390
|
+
)}
|
|
391
|
+
ListFooterComponent={null}
|
|
392
|
+
nestedScrollEnabled
|
|
393
|
+
onMomentumScrollBegin={configs.onMomentumScrollBegin || undefined}
|
|
394
|
+
onScroll={handleListScroll}
|
|
395
|
+
onScrollBeginDrag={configs.onScrollBeginDrag || undefined}
|
|
396
|
+
onEndReached={configs.onEndReached}
|
|
397
|
+
onEndReachedThreshold={END_REACHED_THRESHOLD}
|
|
398
|
+
onRefresh={configs.onRefresh}
|
|
399
|
+
refreshing={Boolean(configs.refreshing)}
|
|
400
|
+
scrollEventThrottle={120}
|
|
401
|
+
showsVerticalScrollIndicator={false}
|
|
402
|
+
/>
|
|
231
403
|
</View>
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
</ScrollView>
|
|
404
|
+
</ScrollView>
|
|
405
|
+
</>
|
|
235
406
|
);
|
|
236
407
|
};
|
|
237
408
|
|
|
@@ -34,7 +34,11 @@ const resolveConfiguredLabel = config => {
|
|
|
34
34
|
return global.t?.t?.('defaultTable', 'button', 'import');
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
const DefaultTableToolbar = ({
|
|
37
|
+
const DefaultTableToolbar = ({
|
|
38
|
+
storeName,
|
|
39
|
+
showToolbarActions: showToolbarActionsProp,
|
|
40
|
+
showToolbarControls: showToolbarControlsProp,
|
|
41
|
+
}) => {
|
|
38
42
|
const store = useStore(storeName);
|
|
39
43
|
const [isImportModalVisible, setIsImportModalVisible] = useState(false);
|
|
40
44
|
const { width } = useWindowDimensions();
|
|
@@ -44,6 +48,14 @@ const DefaultTableToolbar = ({ storeName }) => {
|
|
|
44
48
|
const showTotalItemsInCompactToolbar = configs.showTotalItemsInCompactToolbar === true;
|
|
45
49
|
const showTotalItemsInFooter = configs.showTotalItemsInFooter !== false;
|
|
46
50
|
const toolbarActions = Array.isArray(configs.toolbarActions) ? configs.toolbarActions : [];
|
|
51
|
+
const showToolbarActions =
|
|
52
|
+
showToolbarActionsProp === null || showToolbarActionsProp === undefined
|
|
53
|
+
? configs.showToolbarActions !== false
|
|
54
|
+
: showToolbarActionsProp !== false;
|
|
55
|
+
const showToolbarControls =
|
|
56
|
+
showToolbarControlsProp === null || showToolbarControlsProp === undefined
|
|
57
|
+
? configs.showToolbarControls !== false
|
|
58
|
+
: showToolbarControlsProp !== false;
|
|
47
59
|
const buildTransferAction = (action, fallback) => {
|
|
48
60
|
if (!action) return null;
|
|
49
61
|
|
|
@@ -99,11 +111,9 @@ const DefaultTableToolbar = ({ storeName }) => {
|
|
|
99
111
|
label: global.t?.t?.('defaultTable', 'button', 'export'),
|
|
100
112
|
},
|
|
101
113
|
);
|
|
102
|
-
const resolvedToolbarActions =
|
|
103
|
-
importTableAction,
|
|
104
|
-
|
|
105
|
-
...toolbarActions,
|
|
106
|
-
].filter(Boolean);
|
|
114
|
+
const resolvedToolbarActions = showToolbarActions
|
|
115
|
+
? [importTableAction, exportTableAction, ...toolbarActions].filter(Boolean)
|
|
116
|
+
: [];
|
|
107
117
|
const { tableBorderColors, toolbarColors } = useDefaultTableTheme();
|
|
108
118
|
const {
|
|
109
119
|
backgroundColor: toolbarBackgroundColor,
|
|
@@ -178,7 +188,7 @@ const DefaultTableToolbar = ({ storeName }) => {
|
|
|
178
188
|
<DefaultTableCollapsedSearch storeName={storeName} />
|
|
179
189
|
<View style={styles.toolbarActionGroup}>
|
|
180
190
|
{!shouldRenderCompactToolbarTotalItems ? renderToolbarActions() : null}
|
|
181
|
-
<DefaultTableControls storeName={storeName} />
|
|
191
|
+
{showToolbarControls ? <DefaultTableControls storeName={storeName} /> : null}
|
|
182
192
|
</View>
|
|
183
193
|
</View>
|
|
184
194
|
<DefaultTableImportModal
|