mirror of
https://github.com/etkecc/synapse-admin.git
synced 2024-11-24 00:25:31 +03:00
Better media preview/download implementation (#53)
* Add download option for non image media * make view media button change the icon during the loading; update readme
This commit is contained in:
parent
a15dad4a31
commit
31d3712dbb
2 changed files with 49 additions and 27 deletions
|
@ -62,6 +62,7 @@ The following changes are already implemented:
|
||||||
* [Add `Contact support` menu item](https://github.com/etkecc/synapse-admin/pull/45)
|
* [Add `Contact support` menu item](https://github.com/etkecc/synapse-admin/pull/45)
|
||||||
* [Provide options to delete media and redact events on user erase](https://github.com/etkecc/synapse-admin/pull/49)
|
* [Provide options to delete media and redact events on user erase](https://github.com/etkecc/synapse-admin/pull/49)
|
||||||
* [Authenticated Media support](https://github.com/etkecc/synapse-admin/pull/51)
|
* [Authenticated Media support](https://github.com/etkecc/synapse-admin/pull/51)
|
||||||
|
* [Better media preview/download](https://github.com/etkecc/synapse-admin/pull/53)
|
||||||
|
|
||||||
_the list will be updated as new changes are added_
|
_the list will be updated as new changes are added_
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { get } from "lodash";
|
import { get } from "lodash";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import BlockIcon from "@mui/icons-material/Block";
|
import BlockIcon from "@mui/icons-material/Block";
|
||||||
import IconCancel from "@mui/icons-material/Cancel";
|
import IconCancel from "@mui/icons-material/Cancel";
|
||||||
import ClearIcon from "@mui/icons-material/Clear";
|
import ClearIcon from "@mui/icons-material/Clear";
|
||||||
|
@ -9,10 +8,9 @@ import DeleteSweepIcon from "@mui/icons-material/DeleteSweep";
|
||||||
import FileOpenIcon from "@mui/icons-material/FileOpen";
|
import FileOpenIcon from "@mui/icons-material/FileOpen";
|
||||||
import LockIcon from "@mui/icons-material/Lock";
|
import LockIcon from "@mui/icons-material/Lock";
|
||||||
import LockOpenIcon from "@mui/icons-material/LockOpen";
|
import LockOpenIcon from "@mui/icons-material/LockOpen";
|
||||||
import IconButton from '@mui/material/IconButton';
|
import DownloadIcon from '@mui/icons-material/Download';
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import DownloadingIcon from '@mui/icons-material/Downloading';
|
||||||
import ZoomInIcon from '@mui/icons-material/ZoomIn';
|
import { Grid2 as Grid, Box, Dialog, DialogContent, DialogContentText, DialogTitle, Tooltip, Link } from "@mui/material";
|
||||||
import { Box, Dialog, DialogContent, DialogContentText, DialogTitle, Tooltip, Link } from "@mui/material";
|
|
||||||
import { alpha, useTheme } from "@mui/material/styles";
|
import { alpha, useTheme } from "@mui/material/styles";
|
||||||
import {
|
import {
|
||||||
BooleanInput,
|
BooleanInput,
|
||||||
|
@ -314,17 +312,10 @@ export const QuarantineMediaButton = (props: ButtonProps) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ViewMediaButton = ({ mxcURL, label, mimetype }) => {
|
export const ViewMediaButton = ({ mxcURL, label, uploadName, mimetype }) => {
|
||||||
if (!mimetype.startsWith("image/")) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Box style={{ whiteSpace: "pre" }}>
|
|
||||||
{label}
|
|
||||||
</Box>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const translate = useTranslate();
|
const translate = useTranslate();
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const isImage = mimetype && mimetype.startsWith("image/");
|
||||||
|
|
||||||
const openFileInNewTab = (blobURL: string) => {
|
const openFileInNewTab = (blobURL: string) => {
|
||||||
const anchorElement = document.createElement("a");
|
const anchorElement = document.createElement("a");
|
||||||
|
@ -336,27 +327,54 @@ export const ViewMediaButton = ({ mxcURL, label, mimetype }) => {
|
||||||
setTimeout(() => URL.revokeObjectURL(blobURL), 10);
|
setTimeout(() => URL.revokeObjectURL(blobURL), 10);
|
||||||
};
|
};
|
||||||
|
|
||||||
const previewFile = async () => {
|
const downloadFile = async (blobURL: string) => {
|
||||||
|
console.log("downloadFile", blobURL, uploadName);
|
||||||
|
const anchorElement = document.createElement("a");
|
||||||
|
anchorElement.href = blobURL;
|
||||||
|
anchorElement.download = uploadName;
|
||||||
|
document.body.appendChild(anchorElement);
|
||||||
|
anchorElement.click();
|
||||||
|
document.body.removeChild(anchorElement);
|
||||||
|
setTimeout(() => URL.revokeObjectURL(blobURL), 10);;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFile = async (preview: boolean) => {
|
||||||
|
setLoading(true);
|
||||||
const response = await fetchAuthenticatedMedia(mxcURL, "original");
|
const response = await fetchAuthenticatedMedia(mxcURL, "original");
|
||||||
const blob = await response.blob();
|
const blob = await response.blob();
|
||||||
const blobURL = URL.createObjectURL(blob);
|
const blobURL = URL.createObjectURL(blob);
|
||||||
|
if (preview) {
|
||||||
openFileInNewTab(blobURL);
|
openFileInNewTab(blobURL);
|
||||||
|
} else {
|
||||||
|
downloadFile(blobURL);
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box style={{ whiteSpace: "pre" }}>
|
<Box display="flex" alignItems="center">
|
||||||
<Tooltip title={translate("resources.users_media.action.open")}>
|
<Tooltip title={translate("resources.users_media.action.open")}>
|
||||||
<span>
|
<span>
|
||||||
|
{isImage && (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => previewFile()}
|
disabled={loading}
|
||||||
style={{ minWidth: 0, paddingLeft: 0, paddingRight: 0 }}
|
onClick={() => handleFile(true)}
|
||||||
|
style={{ minWidth: 0, padding: 0, marginRight: 8 }}
|
||||||
>
|
>
|
||||||
<FileOpenIcon />
|
{loading ? <DownloadingIcon /> : <FileOpenIcon />}
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{label}
|
<Button
|
||||||
|
disabled={loading}
|
||||||
|
onClick={() => handleFile(false)}
|
||||||
|
style={{ minWidth: 0, padding: 0, marginRight: 8 }}
|
||||||
|
>
|
||||||
|
{loading ? <DownloadingIcon /> : <DownloadIcon />}
|
||||||
|
</Button>
|
||||||
|
<span>{label}</span>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -374,9 +392,10 @@ export const MediaIDField = ({ source }) => {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uploadName = decodeURIComponent(get(record, "upload_name")?.toString());
|
||||||
const mxcURL = `mxc://${homeserver}/${mediaID}`;
|
const mxcURL = `mxc://${homeserver}/${mediaID}`;
|
||||||
|
|
||||||
return <ViewMediaButton mxcURL={mxcURL} label={mediaID} mimetype={record.media_type}/>;
|
return <ViewMediaButton mxcURL={mxcURL} label={mediaID} uploadName={uploadName} mimetype={record.media_type}/>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ReportMediaContent = ({ source }) => {
|
export const ReportMediaContent = ({ source }) => {
|
||||||
|
@ -390,5 +409,7 @@ export const ReportMediaContent = ({ source }) => {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <ViewMediaButton mxcURL={mxcURL} label={mxcURL} mimetype={record.media_type}/>;
|
const uploadName = decodeURIComponent(get(record, "event_json.content.body")?.toString());
|
||||||
|
|
||||||
|
return <ViewMediaButton mxcURL={mxcURL} label={mxcURL} uploadName={uploadName} mimetype={record.media_type}/>;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue