import { Badge, Checkbox, Group, ScrollArea, Table, Text, TextInput, createStyles, } from '@mantine/core'; import { useDebouncedValue, useElementSize } from '@mantine/hooks'; import { IconSearch } from '@tabler/icons-react'; import Dockerode, { ContainerInfo } from 'dockerode'; import { useTranslation } from 'next-i18next'; import { Dispatch, SetStateAction, useEffect, useMemo, useState } from 'react'; import { MIN_WIDTH_MOBILE } from '../../constants/constants'; import ContainerState from './ContainerState'; const useStyles = createStyles((theme) => ({ rowSelected: { backgroundColor: theme.colorScheme === 'dark' ? theme.fn.rgba(theme.colors[theme.primaryColor][7], 0.2) : theme.colors[theme.primaryColor][0], }, })); export default function DockerTable({ containers, selection, setSelection, }: { setSelection: Dispatch>; containers: ContainerInfo[]; selection: ContainerInfo[]; }) { const { t } = useTranslation('modules/docker'); const [search, setSearch] = useState(''); const { classes, cx } = useStyles(); const { ref, width } = useElementSize(); const filteredContainers = useMemo( () => filterContainers(containers, search), [containers, search] ); const handleSearchChange = (event: React.ChangeEvent) => { setSearch(event.currentTarget.value); }; const toggleRow = (container: ContainerInfo) => setSelection((selected: ContainerInfo[]) => selected.includes(container) ? selected.filter((c) => c !== container) : [...selected, container] ); const toggleAll = () => setSelection((selected: ContainerInfo[]) => selected.length === filteredContainers.length ? [] : filteredContainers.map((c) => c) ); return ( } value={search} autoFocus onChange={handleSearchChange} /> {width > MIN_WIDTH_MOBILE ? : null} {width > MIN_WIDTH_MOBILE ? : null} {filteredContainers.map((container) => { const selected = selection.includes(container); return ( ); })}
0} indeterminate={ selection.length > 0 && selection.length !== filteredContainers.length } transitionDuration={0} disabled={filteredContainers.length === 0} /> {t('table.header.name')}{t('table.header.image')}{t('table.header.ports')}{t('table.header.state')}
); } type RowProps = { container: ContainerInfo; selected: boolean; toggleRow: (container: ContainerInfo) => void; width: number; }; const Row = ({ container, selected, toggleRow, width }: RowProps) => { const { t } = useTranslation('modules/docker'); const { classes, cx } = useStyles(); return ( toggleRow(container)} transitionDuration={0} /> {container.Names[0].replace('/', '')} {width > MIN_WIDTH_MOBILE && ( {container.Image} )} {width > MIN_WIDTH_MOBILE && ( {container.Ports.sort((a, b) => a.PrivatePort - b.PrivatePort) // Remove duplicates with filter function .filter( (port, index, self) => index === self.findIndex((t) => t.PrivatePort === port.PrivatePort) ) .slice(-3) .map((port) => ( {port.PrivatePort}:{port.PublicPort} ))} {container.Ports.length > 3 && ( {t('table.body.portCollapse', { ports: container.Ports.length - 3 })} )} )} ); }; function filterContainers(data: Dockerode.ContainerInfo[], search: string) { const query = search.toLowerCase().trim(); return data.filter((item) => item.Names.some((name) => name.toLowerCase().includes(query) || item.Image.includes(query)) ); }