gitscope
https://dev.kronoz.win/r/marzneshin.git
app/dashboard/src/pages/nodes/table/index.tsx · v0.1.2
Source
1 5bb2712 Mardin 2y ago
2 5bb2712 Mardin 2y ago import {
3 5bb2712 Mardin 2y ago Accordion,
4 5bb2712 Mardin 2y ago AccordionButton,
5 5bb2712 Mardin 2y ago AccordionItem,
6 5bb2712 Mardin 2y ago AccordionPanel,
7 5bb2712 Mardin 2y ago Box,
8 5bb2712 Mardin 2y ago HStack,
9 5bb2712 Mardin 2y ago IconButton,
10 5bb2712 Mardin 2y ago Table,
11 5bb2712 Mardin 2y ago TableProps,
12 5bb2712 Mardin 2y ago Tbody,
13 5bb2712 Mardin 2y ago Td,
14 5bb2712 Mardin 2y ago Text,
15 5bb2712 Mardin 2y ago Th,
16 5bb2712 Mardin 2y ago Thead,
17 5bb2712 Mardin 2y ago Tooltip,
18 5bb2712 Mardin 2y ago Tr,
19 5bb2712 Mardin 2y ago useBreakpointValue,
20 5bb2712 Mardin 2y ago VStack,
21 5bb2712 Mardin 2y ago } from '@chakra-ui/react';
22 5bb2712 Mardin 2y ago import classNames from 'classnames';
23 63b702d Mardin 2y ago import { ActionButtons } from './action-buttons';
24 6aab6f0 Mrdn 2y ago import { pageSizeManagers } from 'utils/userPreferenceStorage';
25 5825ea4 Mardin 2y ago import { FC, Fragment, useState } from 'react';
26 5bb2712 Mardin 2y ago import { useTranslation } from 'react-i18next';
27 5825ea4 Mardin 2y ago import { StatusBadge } from 'components/status-badge';
28 5bb2712 Mardin 2y ago import {
29 89f8f93 Mardin 2y ago Pagination,
30 89f8f93 Mardin 2y ago EmptySection,
31 5bb2712 Mardin 2y ago AccordionArrowIcon,
32 5bb2712 Mardin 2y ago EditIcon,
33 89f8f93 Mardin 2y ago Sort,
34 89f8f93 Mardin 2y ago StatusSortSelect,
35 63b702d Mardin 2y ago handleSort,
36 89f8f93 Mardin 2y ago } from 'components/table';
37 a61ba53 Mrdn 2y ago import { fetchNodes, useNodes } from 'stores';
38 a61ba53 Mrdn 2y ago import { useQuery } from 'react-query';
39 a61ba53 Mrdn 2y ago import { queryIds } from 'constants/query-ids';
40 5bb2712 Mardin 2y ago
41 5bb2712 Mardin 2y ago type ExpandedIndex = number | number[];
42 5bb2712 Mardin 2y ago
43 5bb2712 Mardin 2y ago type NodesTableProps = {} & TableProps;
44 5bb2712 Mardin 2y ago
45 5bb2712 Mardin 2y ago export const NodesTable: FC<NodesTableProps> = (props) => {
46 5bb2712 Mardin 2y ago const {
47 5bb2712 Mardin 2y ago nodesFilters: filters,
48 5825ea4 Mardin 2y ago onEditingNode,
49 5825ea4 Mardin 2y ago onAddingNode,
50 5bb2712 Mardin 2y ago onFilterChange,
51 5bb2712 Mardin 2y ago } = useNodes();
52 a61ba53 Mrdn 2y ago const { data: nodes } = useQuery(queryIds.nodes, () => { return fetchNodes() })
53 a61ba53 Mrdn 2y ago const total = nodes?.length || 0;
54 5bb2712 Mardin 2y ago
55 5bb2712 Mardin 2y ago const { t } = useTranslation();
56 5bb2712 Mardin 2y ago const [selectedRow, setSelectedRow] = useState<ExpandedIndex | undefined>(
57 5bb2712 Mardin 2y ago undefined
58 5bb2712 Mardin 2y ago );
59 5bb2712 Mardin 2y ago
60 5825ea4 Mardin 2y ago const useTable = useBreakpointValue({ base: false, md: true });
61 5bb2712 Mardin 2y ago
62 5bb2712 Mardin 2y ago // TODO: Find a different mechancism to to detect ftiler
63 5bb2712 Mardin 2y ago // const isFiltered = users.length !== total;
64 5bb2712 Mardin 2y ago
65 5bb2712 Mardin 2y ago const handleStatusFilter = (e: any) => {
66 5bb2712 Mardin 2y ago onFilterChange({
67 5bb2712 Mardin 2y ago status: e.target.value.length > 0 ? e.target.value : undefined,
68 5bb2712 Mardin 2y ago });
69 5bb2712 Mardin 2y ago };
70 5bb2712 Mardin 2y ago
71 5bb2712 Mardin 2y ago const toggleAccordion = (index: number) => {
72 5bb2712 Mardin 2y ago setSelectedRow(index === selectedRow ? undefined : index);
73 5bb2712 Mardin 2y ago };
74 5bb2712 Mardin 2y ago
75 5825ea4 Mardin 2y ago const StatusSortSelectNodes = () => (
76 5825ea4 Mardin 2y ago <StatusSortSelect
77 5825ea4 Mardin 2y ago filters={filters}
78 5825ea4 Mardin 2y ago options={['healthy', 'unhealthy', 'disabled']}
79 5825ea4 Mardin 2y ago handleStatusFilter={handleStatusFilter}
80 5825ea4 Mardin 2y ago />
81 5825ea4 Mardin 2y ago );
82 5bb2712 Mardin 2y ago
83 5bb2712 Mardin 2y ago return (
84 5bb2712 Mardin 2y ago <Box id="node-table" overflowX={{ base: 'unset', md: 'unset' }} >
85 5bb2712 Mardin 2y ago <Accordion
86 5bb2712 Mardin 2y ago allowMultiple
87 5bb2712 Mardin 2y ago display={{ base: 'block', md: 'none' }}
88 5bb2712 Mardin 2y ago index={selectedRow}
89 5bb2712 Mardin 2y ago >
90 5bb2712 Mardin 2y ago <Table orientation="vertical" zIndex="docked" {...props}>
91 5bb2712 Mardin 2y ago <Thead zIndex="docked" position="relative">
92 5bb2712 Mardin 2y ago <Tr>
93 5bb2712 Mardin 2y ago <Th
94 5825ea4 Mardin 2y ago position="fixed"
95 5bb2712 Mardin 2y ago minW="120px"
96 5bb2712 Mardin 2y ago pl={4}
97 5bb2712 Mardin 2y ago pr={4}
98 5bb2712 Mardin 2y ago cursor={'pointer'}
99 63b702d Mardin 2y ago onClick={handleSort.bind(null, filters, 'name', onFilterChange)}
100 5bb2712 Mardin 2y ago >
101 5bb2712 Mardin 2y ago <HStack>
102 5bb2712 Mardin 2y ago <span>{t('name')}</span>
103 5bb2712 Mardin 2y ago <Sort sort={filters.sort} column="name" />
104 5bb2712 Mardin 2y ago </HStack>
105 5bb2712 Mardin 2y ago </Th>
106 5bb2712 Mardin 2y ago <Th
107 5825ea4 Mardin 2y ago position="fixed"
108 5bb2712 Mardin 2y ago minW="50px"
109 5bb2712 Mardin 2y ago pl={0}
110 5bb2712 Mardin 2y ago pr={0}
111 5bb2712 Mardin 2y ago w="140px"
112 5bb2712 Mardin 2y ago cursor={'pointer'}
113 5bb2712 Mardin 2y ago >
114 5bb2712 Mardin 2y ago <HStack spacing={0} position="relative">
115 5bb2712 Mardin 2y ago <Text
116 5bb2712 Mardin 2y ago position="absolute"
117 5bb2712 Mardin 2y ago _dark={{
118 5bb2712 Mardin 2y ago bg: 'gray.750',
119 5bb2712 Mardin 2y ago }}
120 5bb2712 Mardin 2y ago _light={{
121 5bb2712 Mardin 2y ago bg: '#F9FAFB',
122 5bb2712 Mardin 2y ago }}
123 5bb2712 Mardin 2y ago userSelect="none"
124 5bb2712 Mardin 2y ago pointerEvents="none"
125 5bb2712 Mardin 2y ago zIndex={1}
126 5bb2712 Mardin 2y ago w="100%"
127 5bb2712 Mardin 2y ago >
128 5bb2712 Mardin 2y ago {t('nodesTable.status')}
129 5bb2712 Mardin 2y ago {filters.status ? ': ' + filters.status : ''}
130 5bb2712 Mardin 2y ago </Text>
131 5bb2712 Mardin 2y ago <StatusSortSelectNodes />
132 5bb2712 Mardin 2y ago </HStack>
133 5bb2712 Mardin 2y ago </Th>
134 5bb2712 Mardin 2y ago <Th
135 5825ea4 Mardin 2y ago position="fixed"
136 5bb2712 Mardin 2y ago minW="100px"
137 5bb2712 Mardin 2y ago cursor={'pointer'}
138 5bb2712 Mardin 2y ago pr={0}
139 63b702d Mardin 2y ago onClick={handleSort.bind(null, filters, 'xray_version', onFilterChange)}
140 5bb2712 Mardin 2y ago >
141 5bb2712 Mardin 2y ago <HStack>
142 5bb2712 Mardin 2y ago <span>{t('nodesTable.xrayVersion')}</span>
143 5bb2712 Mardin 2y ago <Sort sort={filters.sort} column="xray_version" />
144 5bb2712 Mardin 2y ago </HStack>
145 5bb2712 Mardin 2y ago </Th>
146 5bb2712 Mardin 2y ago <Th
147 5825ea4 Mardin 2y ago position="fixed"
148 5bb2712 Mardin 2y ago minW="100px"
149 5bb2712 Mardin 2y ago cursor={'pointer'}
150 5bb2712 Mardin 2y ago pr={0}
151 5bb2712 Mardin 2y ago >
152 5bb2712 Mardin 2y ago <span>{t('nodesTable.ipPort')}</span>
153 5bb2712 Mardin 2y ago </Th>
154 5bb2712 Mardin 2y ago {/* Action buttons (certificate, core settings)*/}
155 5bb2712 Mardin 2y ago <Th
156 5825ea4 Mardin 2y ago position="fixed"
157 5bb2712 Mardin 2y ago minW="32px"
158 5bb2712 Mardin 2y ago w="32px"
159 5bb2712 Mardin 2y ago p={0}
160 5bb2712 Mardin 2y ago cursor={'pointer'}
161 5bb2712 Mardin 2y ago ></Th>
162 5bb2712 Mardin 2y ago </Tr>
163 5bb2712 Mardin 2y ago </Thead>
164 5bb2712 Mardin 2y ago <Tbody>
165 5bb2712 Mardin 2y ago {!useTable &&
166 5bb2712 Mardin 2y ago nodes?.map((node, i) => {
167 5bb2712 Mardin 2y ago return (
168 5bb2712 Mardin 2y ago <Fragment key={node.name}>
169 5bb2712 Mardin 2y ago <Tr
170 5bb2712 Mardin 2y ago onClick={toggleAccordion.bind(null, i)}
171 5bb2712 Mardin 2y ago cursor="pointer"
172 5bb2712 Mardin 2y ago >
173 5bb2712 Mardin 2y ago <Td borderBottom={0} minW="100px" pl={4} pr={4}>
174 5bb2712 Mardin 2y ago {node.name}
175 5bb2712 Mardin 2y ago </Td>
176 5bb2712 Mardin 2y ago <Td borderBottom={0} minW="50px" pl={0} pr={0}>
177 5bb2712 Mardin 2y ago <StatusBadge
178 5bb2712 Mardin 2y ago compact
179 5bb2712 Mardin 2y ago showDetail={false}
180 5bb2712 Mardin 2y ago status={node.status}
181 5bb2712 Mardin 2y ago />
182 5bb2712 Mardin 2y ago </Td>
183 5bb2712 Mardin 2y ago <Td borderBottom={0} minW="100px" pr={0}>
184 5bb2712 Mardin 2y ago {node.xray_version}
185 5bb2712 Mardin 2y ago </Td>
186 5bb2712 Mardin 2y ago <Td p={0} borderBottom={0} w="32px" minW="32px">
187 5bb2712 Mardin 2y ago <AccordionArrowIcon
188 5bb2712 Mardin 2y ago color="gray.600"
189 5bb2712 Mardin 2y ago _dark={{
190 5bb2712 Mardin 2y ago color: 'gray.400',
191 5bb2712 Mardin 2y ago }}
192 5bb2712 Mardin 2y ago transition="transform .2s ease-out"
193 5bb2712 Mardin 2y ago transform={
194 5bb2712 Mardin 2y ago selectedRow === i ? 'rotate(180deg)' : '0deg'
195 5bb2712 Mardin 2y ago }
196 5bb2712 Mardin 2y ago />
197 5bb2712 Mardin 2y ago </Td>
198 5bb2712 Mardin 2y ago </Tr>
199 5bb2712 Mardin 2y ago <Tr
200 5bb2712 Mardin 2y ago className="collapsible"
201 5bb2712 Mardin 2y ago onClick={toggleAccordion.bind(null, i)}
202 5bb2712 Mardin 2y ago >
203 5bb2712 Mardin 2y ago <Td p={0} colSpan={4}>
204 5bb2712 Mardin 2y ago <AccordionItem border={0}>
205 5bb2712 Mardin 2y ago <AccordionButton display="none"></AccordionButton>
206 5bb2712 Mardin 2y ago <AccordionPanel
207 5bb2712 Mardin 2y ago border={0}
208 5bb2712 Mardin 2y ago cursor="pointer"
209 5bb2712 Mardin 2y ago px={6}
210 5bb2712 Mardin 2y ago py={3}
211 5bb2712 Mardin 2y ago >
212 5bb2712 Mardin 2y ago <VStack justifyContent="space-between" spacing="4">
213 5bb2712 Mardin 2y ago <VStack
214 5bb2712 Mardin 2y ago alignItems="flex-start"
215 5bb2712 Mardin 2y ago w="full"
216 5bb2712 Mardin 2y ago spacing={-1}
217 5bb2712 Mardin 2y ago >
218 5bb2712 Mardin 2y ago <Text
219 5bb2712 Mardin 2y ago textTransform="capitalize"
220 5bb2712 Mardin 2y ago fontSize="xs"
221 5bb2712 Mardin 2y ago fontWeight="bold"
222 5bb2712 Mardin 2y ago color="gray.600"
223 5bb2712 Mardin 2y ago _dark={{
224 5bb2712 Mardin 2y ago color: 'gray.400',
225 5bb2712 Mardin 2y ago }}
226 5bb2712 Mardin 2y ago >
227 5bb2712 Mardin 2y ago {t('nodesTable.ipPort')}
228 5bb2712 Mardin 2y ago </Text>
229 5bb2712 Mardin 2y ago <Box width="full" minW="230px">
230 5bb2712 Mardin 2y ago {node.address}:{node.port}
231 5bb2712 Mardin 2y ago </Box>
232 5bb2712 Mardin 2y ago </VStack>
233 5bb2712 Mardin 2y ago <HStack w="full" justifyContent="space-between">
234 5bb2712 Mardin 2y ago <HStack>
235 5bb2712 Mardin 2y ago <ActionButtons />
236 5bb2712 Mardin 2y ago <Tooltip
237 5bb2712 Mardin 2y ago label={t('nodesDialog.editNode')}
238 5bb2712 Mardin 2y ago placement="top"
239 5bb2712 Mardin 2y ago >
240 5bb2712 Mardin 2y ago <IconButton
241 5bb2712 Mardin 2y ago p="0 !important"
242 5bb2712 Mardin 2y ago aria-label="Edit user"
243 5bb2712 Mardin 2y ago bg="transparent"
244 5bb2712 Mardin 2y ago _dark={{
245 5bb2712 Mardin 2y ago _hover: {
246 5bb2712 Mardin 2y ago bg: 'gray.700',
247 5bb2712 Mardin 2y ago },
248 5bb2712 Mardin 2y ago }}
249 5bb2712 Mardin 2y ago size={{
250 5bb2712 Mardin 2y ago base: 'sm',
251 5bb2712 Mardin 2y ago md: 'md',
252 5bb2712 Mardin 2y ago }}
253 5bb2712 Mardin 2y ago onClick={(e) => {
254 5bb2712 Mardin 2y ago e.stopPropagation();
255 5825ea4 Mardin 2y ago onEditingNode(node);
256 5bb2712 Mardin 2y ago }}
257 5bb2712 Mardin 2y ago >
258 5bb2712 Mardin 2y ago <EditIcon />
259 5bb2712 Mardin 2y ago </IconButton>
260 5bb2712 Mardin 2y ago </Tooltip>
261 5bb2712 Mardin 2y ago </HStack>
262 5bb2712 Mardin 2y ago </HStack>
263 5bb2712 Mardin 2y ago </VStack>
264 5bb2712 Mardin 2y ago </AccordionPanel>
265 5bb2712 Mardin 2y ago </AccordionItem>
266 5bb2712 Mardin 2y ago </Td>
267 5bb2712 Mardin 2y ago </Tr>
268 5bb2712 Mardin 2y ago </Fragment>
269 5bb2712 Mardin 2y ago );
270 5bb2712 Mardin 2y ago })}
271 5bb2712 Mardin 2y ago </Tbody>
272 5bb2712 Mardin 2y ago </Table>
273 5bb2712 Mardin 2y ago </Accordion>
274 5bb2712 Mardin 2y ago <Table
275 5bb2712 Mardin 2y ago orientation="vertical"
276 5bb2712 Mardin 2y ago display={{ base: 'none', md: 'table' }}
277 5bb2712 Mardin 2y ago {...props}
278 5bb2712 Mardin 2y ago >
279 5bb2712 Mardin 2y ago <Thead zIndex="docked" position="relative">
280 5bb2712 Mardin 2y ago <Tr>
281 5bb2712 Mardin 2y ago <Th
282 63b702d Mardin 2y ago minW="200px"
283 5bb2712 Mardin 2y ago cursor={'pointer'}
284 63b702d Mardin 2y ago onClick={handleSort.bind(null, filters, 'name', onFilterChange)}
285 5bb2712 Mardin 2y ago >
286 5bb2712 Mardin 2y ago <HStack>
287 5bb2712 Mardin 2y ago <span>{t('name')}</span>
288 5bb2712 Mardin 2y ago <Sort sort={filters.sort} column="name" />
289 5bb2712 Mardin 2y ago </HStack>
290 5bb2712 Mardin 2y ago </Th>
291 5bb2712 Mardin 2y ago <Th
292 63b702d Mardin 2y ago width="100px"
293 63b702d Mardin 2y ago minW="70px"
294 5bb2712 Mardin 2y ago cursor={'pointer'}
295 5bb2712 Mardin 2y ago >
296 5bb2712 Mardin 2y ago <HStack spacing={0} position="relative">
297 5bb2712 Mardin 2y ago <Text
298 5bb2712 Mardin 2y ago position="absolute"
299 5bb2712 Mardin 2y ago _dark={{
300 5bb2712 Mardin 2y ago bg: 'gray.750',
301 5bb2712 Mardin 2y ago }}
302 5bb2712 Mardin 2y ago _light={{
303 5bb2712 Mardin 2y ago bg: '#F9FAFB',
304 5bb2712 Mardin 2y ago }}
305 5bb2712 Mardin 2y ago userSelect="none"
306 5bb2712 Mardin 2y ago pointerEvents="none"
307 5bb2712 Mardin 2y ago zIndex={1}
308 5bb2712 Mardin 2y ago w="100%"
309 5bb2712 Mardin 2y ago >
310 5bb2712 Mardin 2y ago {t('nodesTable.status')}
311 5bb2712 Mardin 2y ago {filters.status ? ': ' + filters.status : ''}
312 5bb2712 Mardin 2y ago </Text>
313 5bb2712 Mardin 2y ago <StatusSortSelectNodes />
314 5bb2712 Mardin 2y ago </HStack>
315 5bb2712 Mardin 2y ago </Th>
316 5bb2712 Mardin 2y ago <Th
317 63b702d Mardin 2y ago width="100px"
318 63b702d Mardin 2y ago minW="70px"
319 5bb2712 Mardin 2y ago cursor={'pointer'}
320 63b702d Mardin 2y ago onClick={handleSort.bind(null, filters, 'xray_version', onFilterChange)}
321 5bb2712 Mardin 2y ago >
322 5bb2712 Mardin 2y ago <HStack>
323 5bb2712 Mardin 2y ago <span>{t('nodesTable.xrayVersion')}</span>
324 5bb2712 Mardin 2y ago <Sort sort={filters.sort} column="xray_version" />
325 5bb2712 Mardin 2y ago </HStack>
326 5bb2712 Mardin 2y ago </Th>
327 5bb2712 Mardin 2y ago <Th
328 63b702d Mardin 2y ago width="100px"
329 63b702d Mardin 2y ago minW="70px"
330 5bb2712 Mardin 2y ago cursor={'pointer'}
331 63b702d Mardin 2y ago onClick={handleSort.bind(null, filters, 'address', onFilterChange)}
332 5bb2712 Mardin 2y ago >
333 5bb2712 Mardin 2y ago <HStack>
334 5bb2712 Mardin 2y ago <span>{t('nodesTable.ipPort')}</span>
335 5bb2712 Mardin 2y ago <Sort sort={filters.sort} column="address" />
336 5bb2712 Mardin 2y ago </HStack>
337 5bb2712 Mardin 2y ago </Th>
338 5bb2712 Mardin 2y ago <Th
339 63b702d Mardin 2y ago width="60px"
340 63b702d Mardin 2y ago minW="50px"
341 5bb2712 Mardin 2y ago />
342 5bb2712 Mardin 2y ago </Tr>
343 5bb2712 Mardin 2y ago </Thead>
344 5825ea4 Mardin 2y ago <Tbody overflowY="auto">
345 5bb2712 Mardin 2y ago {useTable &&
346 5bb2712 Mardin 2y ago nodes?.map((node, i) => {
347 5bb2712 Mardin 2y ago return (
348 5bb2712 Mardin 2y ago <Tr
349 5bb2712 Mardin 2y ago key={node.name}
350 5bb2712 Mardin 2y ago className={classNames('interactive', {
351 5bb2712 Mardin 2y ago 'last-row': i === nodes.length - 1,
352 5bb2712 Mardin 2y ago })}
353 5825ea4 Mardin 2y ago onClick={() => onEditingNode(node)}
354 5bb2712 Mardin 2y ago >
355 5bb2712 Mardin 2y ago <Td minW="140px">
356 5bb2712 Mardin 2y ago <div className="flex-status">
357 5bb2712 Mardin 2y ago {node.name}
358 5bb2712 Mardin 2y ago </div>
359 5bb2712 Mardin 2y ago </Td>
360 5bb2712 Mardin 2y ago <Td width="400px" minW="150px">
361 5bb2712 Mardin 2y ago <StatusBadge
362 5bb2712 Mardin 2y ago status={node.status}
363 5bb2712 Mardin 2y ago />
364 5bb2712 Mardin 2y ago </Td>
365 5bb2712 Mardin 2y ago <Td width="350px" minW="150px">
366 5bb2712 Mardin 2y ago {node.xray_version}
367 5bb2712 Mardin 2y ago </Td>
368 5bb2712 Mardin 2y ago <Td width="350px" minW="150px">
369 5bb2712 Mardin 2y ago {node.address}:{node.port}
370 5bb2712 Mardin 2y ago </Td>
371 5bb2712 Mardin 2y ago <Td width="200px" minW="180px">
372 5bb2712 Mardin 2y ago <ActionButtons />
373 5bb2712 Mardin 2y ago </Td>
374 5bb2712 Mardin 2y ago </Tr>
375 5bb2712 Mardin 2y ago );
376 5bb2712 Mardin 2y ago })}
377 a61ba53 Mrdn 2y ago {nodes?.length == 0 && (
378 5bb2712 Mardin 2y ago <Tr>
379 5bb2712 Mardin 2y ago <Td colSpan={5}>
380 5bb2712 Mardin 2y ago <EmptySection
381 5bb2712 Mardin 2y ago isFiltered={/* isFiltered */ false}
382 5bb2712 Mardin 2y ago noObjectT="nodesTable.noNode"
383 5bb2712 Mardin 2y ago noObjectMatchedT='nodesTable.noNodeMatched'
384 5bb2712 Mardin 2y ago createObjectT="addNode"
385 5825ea4 Mardin 2y ago onCreateObject={onAddingNode}
386 5bb2712 Mardin 2y ago />
387 5bb2712 Mardin 2y ago </Td>
388 5bb2712 Mardin 2y ago </Tr>
389 5bb2712 Mardin 2y ago )}
390 5bb2712 Mardin 2y ago </Tbody>
391 5bb2712 Mardin 2y ago </Table>
392 6aab6f0 Mrdn 2y ago <Pagination filters={filters} total={total} onFilterChange={onFilterChange} pageSizeManager={pageSizeManagers.nodes} />
393 5bb2712 Mardin 2y ago </Box>
394 5bb2712 Mardin 2y ago );
395 5bb2712 Mardin 2y ago };