diff --git a/src/components/media.js b/src/components/media.js index a628b79..cc1dc6f 100644 --- a/src/components/media.js +++ b/src/components/media.js @@ -13,6 +13,7 @@ import { Toolbar, useCreate, useDelete, + useDeleteMany, useNotify, useRefresh, useTranslate, @@ -325,3 +326,39 @@ export const QuarantineMediaButton = props => { ); }; + +export const DeleteMediaBulkButton = ({ selectedIds }) => { + const classes = useStyles(false); + const notify = useNotify(); + const refresh = useRefresh(); + const [deleteMany, { loading }] = useDeleteMany("users_media"); + + const handleSend = values => { + deleteMany( + { + payload: { ids: selectedIds }, + }, + { + onSuccess: () => { + notify("resources.delete_media.action.send_success"); + refresh(); + }, + onFailure: () => + notify("resources.delete_media.action.send_failure", "error"), + } + ); + }; + + return ( + + + + ); +}; diff --git a/src/components/users.js b/src/components/users.js index 750fb76..9b00101 100644 --- a/src/components/users.js +++ b/src/components/users.js @@ -46,12 +46,29 @@ import { TopToolbar, sanitizeListRestProps, NumberField, + BulkActionsToolbar, + DatagridHeaderCell, + useListContext, + FunctionField, } from "react-admin"; import { Link } from "react-router-dom"; import { ServerNoticeButton, ServerNoticeBulkButton } from "./ServerNotices"; import { DeviceRemoveButton } from "./devices"; -import { ProtectMediaButton, QuarantineMediaButton } from "./media"; +import { + ProtectMediaButton, + QuarantineMediaButton, + DeleteMediaBulkButton, +} from "./media"; import { makeStyles } from "@material-ui/core/styles"; +import { + TableHead, + TableRow, + TableCell, + Checkbox, + Tooltip, +} from "@material-ui/core"; +import classnames from "classnames"; +import BrokenImageIcon from "@material-ui/icons/BrokenImage"; const redirect = () => { return { @@ -322,6 +339,109 @@ const UserTitle = ({ record }) => { ); }; +const UserMediaDatagridHeader = props => { + const { + children, + classes, + className, + hasExpand = false, + hasBulkActions = false, + isRowSelectable, + } = props; + const translate = useTranslate(); + const { currentSort, data, ids, onSelect, selectedIds, setSort } = + useListContext(props); + + const updateSortCallback = React.useCallback( + event => { + event.stopPropagation(); + const newField = event.currentTarget.dataset.field; + const newOrder = + currentSort.field === newField + ? currentSort.order === "ASC" + ? "DESC" + : "ASC" + : event.currentTarget.dataset.order; + + setSort(newField, newOrder); + }, + [currentSort.field, currentSort.order, setSort] + ); + + const updateSort = setSort ? updateSortCallback : null; + + const handleSelectAll = React.useCallback( + event => { + onSelect( + event.target.checked + ? ids + .filter(id => + isRowSelectable ? isRowSelectable(data[id]) : true + ) + .concat(selectedIds.filter(id => !ids.includes(id))) + : [] + ); + }, + [data, ids, onSelect, isRowSelectable, selectedIds] + ); + + const selectableIds = isRowSelectable + ? ids.filter(id => isRowSelectable(data[id])) + : ids; + + return ( + + + + + + + + + + {hasExpand && ( + + )} + {hasBulkActions && selectedIds && ( + + 0 && + selectableIds.length > 0 && + selectableIds.every(id => selectedIds.includes(id)) + } + onChange={handleSelectAll} + /> + + )} + {React.Children.map(children, (field, index) => + React.isValidElement(field) ? ( + + ) : null + )} + + + ); +}; + export const UserEdit = props => { const classes = useStyles(); const translate = useTranslate(); @@ -456,7 +576,62 @@ export const UserEdit = props => { perPage={50} sort={{ field: "created_ts", order: "DESC" }} > - + } + > + { + let data = { + title: + record.media_type.startsWith("image") && + record.media_length + ? record.upload_name || record.media_id + : translate( + "resources.users_media.preview_unavailable" + ), + imgURL: record.media_type.startsWith("image") + ? `${localStorage.getItem( + "base_url" + )}/_matrix/media/v1/thumbnail/${localStorage.getItem( + "home_server" + )}/${record.media_id}?width=40&height=40&method=crop` + : null, + downloadURL: `${localStorage.getItem( + "base_url" + )}/_matrix/media/r0/download/${localStorage.getItem( + "home_server" + )}/${record.media_id}`, + }; + + return ( + + window.open(data["downloadURL"])} + variant="square" + > + + + + ); + }} + /> + +