import React , { useCallback , useMemo , useState } from "react" ; import orderBy from "lodash/orderBy" ; import { i18n } from "@webiny/app/i18n" ; import { DataList , ScrollList , ListItem , ListItemText , ListItemTextSecondary , ListItemMeta , ListActions , DataListModalOverlayAction , DataListModalOverlay } from "@webiny/ui/List" ; import { DeleteIcon } from "@webiny/ui/List/DataList/icons" ; import { useRouter } from "@webiny/react-router" ; import { useSnackbar } from "@webiny/app-admin/hooks/useSnackbar" ; import { useQuery , useMutation } from "@apollo/react-hooks" ; import { useConfirmationDialog } from "@webiny/app-admin/hooks/useConfirmationDialog" ; import { LIST_GROUPS , DELETE_GROUP } from "./graphql" ; import { Tooltip } from "@webiny/ui/Tooltip" ; import { ButtonIcon , ButtonSecondary } from "@webiny/ui/Button" ; import { Cell , Grid } from "@webiny/ui/Grid" ; import { Select } from "@webiny/ui/Select" ; import SearchUI from "@webiny/app-admin/components/SearchUI" ; import { ReactComponent as AddIcon } from "@webiny/app-admin/assets/icons/add-18px.svg" ; import { ReactComponent as FilterIcon } from "@webiny/app-admin/assets/icons/filter-24px.svg" ; import { deserializeSorters , serializeSorters } from "../utils" ; const t = i18n . ns ( "app-security/admin/groups/data-list" ) ; const SORTERS = [ { label : t `Newest to oldest` , sorters : { createdOn : "desc" } } , { label : t `Oldest to newest` , sorters : { createdOn : "asc" } } , { label : t `Name A-Z` , sorters : { name : "asc" } } , { label : t `Name Z-A` , sorters : { name : "desc" } } ] ; const GroupsDataList = ( ) => { const [ filter , setFilter ] = useState ( "" ) ; const [ sort , setSort ] = useState ( serializeSorters ( SORTERS [ 0 ] . sorters ) ) ; const { history , location } = useRouter ( ) ; const { showSnackbar } = useSnackbar ( ) ; const { showConfirmation } = useConfirmationDialog ( { dataTestId : "default-data-list.delete-dialog" } ) ; const { data : listResponse , loading : listLoading } = useQuery ( LIST_GROUPS ) ; const [ deleteIt , { loading : deleteLoading } ] = useMutation ( DELETE_GROUP , { refetchQueries : [ { query : LIST_GROUPS } ] } ) ; const data = listLoading && ! listResponse ? [ ] : listResponse . security . groups . data ; const id = new URLSearchParams ( location . search ) . get ( "id" ) ; const filterGroup = useCallback ( ( { name , slug , description } ) => { return ( name . toLowerCase ( ) . includes ( filter ) || slug . toLowerCase ( ) . includes ( filter ) || ( description && description . toLowerCase ( ) . includes ( filter ) ) ) ; } , [ filter ] ) ; const sortGroups = useCallback ( groups => { if ( ! sort ) { return groups ; } const [ [ key , value ] ] = Object . entries ( deserializeSorters ( sort ) ) ; return orderBy ( groups , [ key ] , [ value ] ) ; } , [ sort ] ) ; const deleteItem = useCallback ( item => { showConfirmation ( async ( ) => { const { data } = await deleteIt ( { variables : item } ) ; const { error } = data . security . deleteGroup ; if ( error ) { return showSnackbar ( error . message ) ; } showSnackbar ( t `Group "{slug}" deleted.` ( { slug : item . slug } ) ) ; if ( id === item . id ) { history . push ( `/access-management/groups` ) ; } } ) ; } , [ id ] ) ; const groupsDataListModalOverlay = useMemo ( ( ) => ( < DataListModalOverlay > < Grid > < Cell span = { 12 } > < Select value = { sort } onChange = { setSort } label = { t `Sort by` } > { SORTERS . map ( ( { label , sorters } ) => { return ( < option key = { label } value = { serializeSorters ( sorters ) } > { label } < /option>); } ) } < /Select> < /Cell> < /Grid> < /DataListModalOverlay>), [sort]); const filteredData = filter === "" ? data : data . filter ( filterGroup ) ; const groupList = sortGroups ( filteredData ) ; return ( < DataList title = { t `Groups` } actions = { < ButtonSecondary data - testid = "new-record-button" onClick = { ( ) => history . push ( "/access-management/groups?new=true" ) } > < ButtonIcon icon = { < AddIcon />}/ > { t `New Group` } < /ButtonSecondary>} data={groupList} loading={listLoading || deleteLoading} search={<SearchUI value={filter} onChange={setFilter} inputPlaceholder={t `Search Groups`}/ > } modalOverlay = { groupsDataListModalOverlay } modalOverlayAction = { < DataListModalOverlayAction icon = { < FilterIcon / > } data - testid = { "default-data-list.filter" } />}> { ( { data } ) => ( < ScrollList data - testid = "default-data-list" > { data . map ( item => ( < ListItem key = { item . id } selected = { item . id === id } > < ListItemText onClick = { ( ) => history . push ( `/access-management/groups?id=${ item . id }` ) } > { item . name } < ListItemTextSecondary > { item . description } < /ListItemTextSecondary> < /ListItemText> < ListItemMeta > < ListActions > { item . slug !== "full-access" ? ( < DeleteIcon onClick = { ( ) => deleteItem ( item ) } data - testid = { "default-data-list.delete" } />) : (<Tooltip placement={"bottom"} content={<span>{t `You can't delete this group.`}</span > } > < DeleteIcon disabled / > < /Tooltip>)} < /ListActions> < /ListItemMeta> < /ListItem>))} < /ScrollList>)} < /DataList>); } ; export default GroupsDataList ;