import { Box, Table } from '@rocket.chat/fuselage'; import { useDebouncedValue, useMediaQuery } from '@rocket.chat/fuselage-hooks'; import React, { useMemo, useCallback, useState } from 'react'; import UserAvatar from '../../../components/avatar/UserAvatar'; import GenericTable from '../../../components/GenericTable'; import { capitalize } from '../../../lib/capitalize'; import { useTranslation } from '../../../contexts/TranslationContext'; import { useRoute } from '../../../contexts/RouterContext'; import { useEndpointData } from '../../../hooks/useEndpointData'; import FilterByText from '../../../components/FilterByText'; const style = { whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden', }; const sortDir = (sortDir) => (sortDir === 'asc' ? 1 : -1); const UserRow = ({ emails, _id, username, name, roles, status, avatarETag, onClick, mediaQuery, active }) => { const t = useTranslation(); const statusText = active ? t(capitalize(status)) : t('Disabled'); return {name || username} {!mediaQuery && name && {`@${ username }`} } {mediaQuery && { username } } {emails && emails.length && emails[0].address} {mediaQuery && {roles && roles.join(', ')}} {statusText} ; }; const useQuery = ({ text, itemsPerPage, current }, sortFields) => useMemo(() => ({ fields: JSON.stringify({ name: 1, username: 1, emails: 1, roles: 1, status: 1, avatarETag: 1, active: 1 }), query: JSON.stringify({ $or: [ { 'emails.address': { $regex: text || '', $options: 'i' } }, { username: { $regex: text || '', $options: 'i' } }, { name: { $regex: text || '', $options: 'i' } }, ], }), sort: JSON.stringify(sortFields.reduce((agg, [column, direction]) => { agg[column] = sortDir(direction); return agg; }, {})), ...itemsPerPage && { count: itemsPerPage }, ...current && { offset: current }, }), [text, itemsPerPage, current, sortFields]); export function UsersTable() { const t = useTranslation(); const [params, setParams] = useState({ text: '', current: 0, itemsPerPage: 25 }); const [sort, setSort] = useState([['name', 'asc'], ['usernames', 'asc']]); const debouncedParams = useDebouncedValue(params, 500); const debouncedSort = useDebouncedValue(sort, 500); const query = useQuery(debouncedParams, debouncedSort); const { value: data = {} } = useEndpointData('users.list', query); const usersRoute = useRoute('admin-users'); const onClick = useCallback((username) => () => usersRoute.push({ context: 'info', id: username, }), [usersRoute]); const onHeaderClick = useCallback((id) => { const preparedSort = []; const [[sortBy, sortDirection]] = sort; if (sortBy === id) { preparedSort.push([id, sortDirection === 'asc' ? 'desc' : 'asc']); } else { preparedSort.push([id, 'asc']); } // // Special cases // If the sortable field is `name`, we should also add `usernames` if (id === 'name') { preparedSort.push(['usernames', sortDirection]); } // If the sortable field is `name`, we should also add `usernames` if (id === 'status') { preparedSort.push(['active', sortDirection === 'asc' ? 'desc' : 'asc']); } setSort(preparedSort); }, [sort]); const mediaQuery = useMediaQuery('(min-width: 1024px)'); return {t('Name')} {mediaQuery && {t('Username')} } {t('Email')} {mediaQuery && {t('Roles')} } {t('Status')} } results={data.users} total={data.total} setParams={setParams} params={params} renderFilter={({ onChange, ...props }) => } > {(props) => } ; } export default UsersTable;