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"
+ >
+
+
+
+ );
+ }}
+ />
+
+