Compare commits
48 Commits
v0.10.4-et
...
add-some-t
Author | SHA1 | Date | |
---|---|---|---|
![]() |
319c7aa33a | ||
![]() |
5bec4c71ea | ||
![]() |
245dadc470 | ||
![]() |
08cde13fd4 | ||
![]() |
765456d233 | ||
![]() |
b6bc4a2d43 | ||
![]() |
851478bbcb | ||
![]() |
ff8e43631a | ||
![]() |
7b8a43b835 | ||
![]() |
bc0c186242 | ||
![]() |
d5b9981bf0 | ||
![]() |
7a8977a00c | ||
![]() |
5297e56eca | ||
![]() |
82ff610b89 | ||
![]() |
263f25303e | ||
![]() |
2aa7cdcb97 | ||
![]() |
e3e8f028f4 | ||
![]() |
f18523e0f2 | ||
![]() |
3533cbed93 | ||
![]() |
bf1cec2796 | ||
![]() |
7005d08c7e | ||
![]() |
e15b45bcf9 | ||
![]() |
603737b2ad | ||
![]() |
eebc7a4fab | ||
![]() |
3725b01fe5 | ||
![]() |
6c41aab463 | ||
![]() |
e8987607ff | ||
![]() |
9c440024bb | ||
![]() |
aa10df711e | ||
![]() |
51aca16e2f | ||
![]() |
4f1b9c2bfa | ||
![]() |
a801957194 | ||
![]() |
8f527eeb85 | ||
![]() |
92632f81f8 | ||
![]() |
e76809fb37 | ||
![]() |
03d142a47c | ||
![]() |
f589427b3c | ||
![]() |
16d78b577e | ||
![]() |
649450f7ee | ||
![]() |
a64705c28c | ||
![]() |
5d775ca08b | ||
![]() |
b2289e5776 | ||
![]() |
607abc003b | ||
![]() |
210623b39e | ||
![]() |
8c72dbbd9a | ||
![]() |
5779ce6301 | ||
![]() |
664573d65e | ||
![]() |
cfcc3f5a73 |
2
.github/workflows/workflow.yml
vendored
2
.github/workflows/workflow.yml
vendored
@@ -72,7 +72,7 @@ jobs:
|
|||||||
type=raw,value=latest,enable=${{ github.ref_name == 'main' }}
|
type=raw,value=latest,enable=${{ github.ref_name == 'main' }}
|
||||||
type=semver,pattern={{raw}}
|
type=semver,pattern={{raw}}
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0
|
uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0
|
||||||
with:
|
with:
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
context: .
|
context: .
|
||||||
|
32
package.json
32
package.json
@@ -18,28 +18,28 @@
|
|||||||
"@testing-library/user-event": "^14.6.1",
|
"@testing-library/user-event": "^14.6.1",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
"@types/lodash": "^4.17.16",
|
"@types/lodash": "^4.17.16",
|
||||||
"@types/node": "^22.15.3",
|
"@types/node": "^22.15.19",
|
||||||
"@types/papaparse": "^5.3.15",
|
"@types/papaparse": "^5.3.16",
|
||||||
"@types/react": "^19.1.2",
|
"@types/react": "^19.1.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.32.0",
|
"@typescript-eslint/eslint-plugin": "^8.32.0",
|
||||||
"@typescript-eslint/parser": "^8.32.0",
|
"@typescript-eslint/parser": "^8.32.0",
|
||||||
"@vitejs/plugin-react": "^4.4.1",
|
"@vitejs/plugin-react": "^4.4.1",
|
||||||
"eslint": "^9.26.0",
|
"eslint": "^9.27.0",
|
||||||
"eslint-config-prettier": "^10.1.2",
|
"eslint-config-prettier": "^10.1.5",
|
||||||
"eslint-plugin-import": "^2.31.0",
|
"eslint-plugin-import": "^2.31.0",
|
||||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||||
"eslint-plugin-prettier": "^5.3.1",
|
"eslint-plugin-prettier": "^5.4.0",
|
||||||
"eslint-plugin-unused-imports": "^4.1.4",
|
"eslint-plugin-unused-imports": "^4.1.4",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-environment-jsdom": "^29.7.0",
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
"jest-fetch-mock": "^3.0.3",
|
"jest-fetch-mock": "^3.0.3",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"react-test-renderer": "^19.1.0",
|
"react-test-renderer": "^19.1.0",
|
||||||
"ts-jest": "^29.3.2",
|
"ts-jest": "^29.3.4",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"typescript-eslint": "^8.31.1",
|
"typescript-eslint": "^8.32.1",
|
||||||
"vite": "^6.3.4",
|
"vite": "^6.3.5",
|
||||||
"vite-plugin-version-mark": "^0.1.4"
|
"vite-plugin-version-mark": "^0.1.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -49,8 +49,8 @@
|
|||||||
"@haxqer/ra-language-chinese": "^4.16.2",
|
"@haxqer/ra-language-chinese": "^4.16.2",
|
||||||
"@mui/icons-material": "^6.4.8",
|
"@mui/icons-material": "^6.4.8",
|
||||||
"@mui/material": "^6.4.8",
|
"@mui/material": "^6.4.8",
|
||||||
"@mui/utils": "^6.4.9",
|
"@mui/utils": "^7.1.0",
|
||||||
"@tanstack/react-query": "^5.75.4",
|
"@tanstack/react-query": "^5.76.1",
|
||||||
"history": "^5.3.0",
|
"history": "^5.3.0",
|
||||||
"jest-fixed-jsdom": "^0.0.9",
|
"jest-fixed-jsdom": "^0.0.9",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
@@ -59,17 +59,17 @@
|
|||||||
"ra-i18n-polyglot": "^5.4.4",
|
"ra-i18n-polyglot": "^5.4.4",
|
||||||
"ra-language-english": "^5.4.4",
|
"ra-language-english": "^5.4.4",
|
||||||
"ra-language-farsi": "^5.1.0",
|
"ra-language-farsi": "^5.1.0",
|
||||||
"ra-language-french": "^5.8.0",
|
"ra-language-french": "^5.8.2",
|
||||||
"ra-language-italian": "^3.13.1",
|
"ra-language-italian": "^3.13.1",
|
||||||
"ra-language-russian": "^5.4.3",
|
"ra-language-russian": "^5.4.3",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-admin": "^5.8.0",
|
"react-admin": "^5.8.2",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-hook-form": "^7.56.2",
|
"react-hook-form": "^7.56.4",
|
||||||
"react-is": "^19.1.0",
|
"react-is": "^19.1.0",
|
||||||
"ts-jest-mock-import-meta": "^1.3.0",
|
"ts-jest-mock-import-meta": "^1.3.0",
|
||||||
"react-router": "^7.5.2",
|
"react-router": "^7.6.0",
|
||||||
"react-router-dom": "^7.5.3"
|
"react-router-dom": "^7.6.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "vite serve",
|
"start": "vite serve",
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import ActionCheck from "@mui/icons-material/CheckCircle";
|
import ActionCheck from "@mui/icons-material/CheckCircle";
|
||||||
import ActionDelete from "@mui/icons-material/Delete";
|
import ActionDelete from "@mui/icons-material/Delete";
|
||||||
import AlertError from "@mui/icons-material/ErrorOutline";
|
import AlertError from "@mui/icons-material/ErrorOutline";
|
||||||
import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from "@mui/material";
|
import { Button, Tooltip, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from "@mui/material";
|
||||||
import { Fragment, useState } from "react";
|
import { Fragment, useState } from "react";
|
||||||
import {
|
import {
|
||||||
SimpleForm,
|
SimpleForm,
|
||||||
@@ -63,22 +63,24 @@ const DeleteRoomButton: React.FC<DeleteRoomButtonProps> = props => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Button
|
<Tooltip title={translate("ra.action.delete")}>
|
||||||
onClick={handleDialogOpen}
|
<Button
|
||||||
disabled={isLoading}
|
onClick={handleDialogOpen}
|
||||||
className={"ra-delete-button"}
|
disabled={isLoading}
|
||||||
key="button"
|
className={"ra-delete-button"}
|
||||||
size="small"
|
key="button"
|
||||||
sx={{
|
size="small"
|
||||||
"&.MuiButton-sizeSmall": {
|
sx={{
|
||||||
lineHeight: 1.5,
|
"&.MuiButton-sizeSmall": {
|
||||||
},
|
lineHeight: 1.5,
|
||||||
}}
|
},
|
||||||
color={"error"}
|
}}
|
||||||
startIcon={<ActionDelete />}
|
color={"error"}
|
||||||
>
|
startIcon={<ActionDelete />}
|
||||||
{translate("ra.action.delete")}
|
>
|
||||||
</Button>
|
{translate("ra.action.delete")}
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
<Dialog open={open} onClose={handleDialogClose}>
|
<Dialog open={open} onClose={handleDialogClose}>
|
||||||
<DialogTitle>{translate(props.confirmTitle)}</DialogTitle>
|
<DialogTitle>{translate(props.confirmTitle)}</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import ActionCheck from "@mui/icons-material/CheckCircle";
|
import ActionCheck from "@mui/icons-material/CheckCircle";
|
||||||
import ActionDelete from "@mui/icons-material/Delete";
|
import ActionDelete from "@mui/icons-material/Delete";
|
||||||
import AlertError from "@mui/icons-material/ErrorOutline";
|
import AlertError from "@mui/icons-material/ErrorOutline";
|
||||||
import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from "@mui/material";
|
import { Tooltip, Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from "@mui/material";
|
||||||
import { Fragment, useState } from "react";
|
import { Fragment, useState } from "react";
|
||||||
import {
|
import {
|
||||||
SimpleForm,
|
SimpleForm,
|
||||||
@@ -69,22 +69,24 @@ const DeleteUserButton: React.FC<DeleteUserButtonProps> = props => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Button
|
<Tooltip title={translate("ra.action.delete")}>
|
||||||
onClick={handleDialogOpen}
|
<Button
|
||||||
disabled={isLoading}
|
onClick={handleDialogOpen}
|
||||||
className={"ra-delete-button"}
|
disabled={isLoading}
|
||||||
key="button"
|
className={"ra-delete-button"}
|
||||||
size="small"
|
key="button"
|
||||||
sx={{
|
size="small"
|
||||||
"&.MuiButton-sizeSmall": {
|
sx={{
|
||||||
lineHeight: 1.5,
|
"&.MuiButton-sizeSmall": {
|
||||||
},
|
lineHeight: 1.5,
|
||||||
}}
|
},
|
||||||
color={"error"}
|
}}
|
||||||
startIcon={<ActionDelete />}
|
color={"error"}
|
||||||
>
|
startIcon={<ActionDelete />}
|
||||||
{translate("ra.action.delete")}
|
>
|
||||||
</Button>
|
{translate("ra.action.delete")}
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
<Dialog open={open} onClose={handleDialogClose}>
|
<Dialog open={open} onClose={handleDialogClose}>
|
||||||
<DialogTitle>{translate(props.confirmTitle)}</DialogTitle>
|
<DialogTitle>{translate(props.confirmTitle)}</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
|
@@ -1,8 +1,11 @@
|
|||||||
|
import { Tooltip } from "@mui/material";
|
||||||
import { DeleteWithConfirmButton, DeleteWithConfirmButtonProps, useRecordContext } from "react-admin";
|
import { DeleteWithConfirmButton, DeleteWithConfirmButtonProps, useRecordContext } from "react-admin";
|
||||||
|
import { useTranslate } from "react-admin";
|
||||||
|
|
||||||
import { isASManaged } from "../utils/mxid";
|
import { isASManaged } from "../utils/mxid";
|
||||||
|
|
||||||
export const DeviceRemoveButton = (props: DeleteWithConfirmButtonProps) => {
|
export const DeviceRemoveButton = (props: DeleteWithConfirmButtonProps) => {
|
||||||
|
const translate = useTranslate();
|
||||||
const record = useRecordContext();
|
const record = useRecordContext();
|
||||||
if (!record) return null;
|
if (!record) return null;
|
||||||
|
|
||||||
@@ -12,19 +15,23 @@ export const DeviceRemoveButton = (props: DeleteWithConfirmButtonProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DeleteWithConfirmButton
|
<Tooltip
|
||||||
{...props}
|
title={isASManagedUser ? translate("resources.devices.action.erase.disabled") : translate("ra.action.delete")}
|
||||||
label="ra.action.remove"
|
>
|
||||||
confirmTitle="resources.devices.action.erase.title"
|
<DeleteWithConfirmButton
|
||||||
confirmContent="resources.devices.action.erase.content"
|
{...props}
|
||||||
mutationMode="pessimistic"
|
label="ra.action.remove"
|
||||||
redirect={false}
|
confirmTitle="resources.devices.action.erase.title"
|
||||||
disabled={isASManagedUser}
|
confirmContent="resources.devices.action.erase.content"
|
||||||
translateOptions={{
|
mutationMode="pessimistic"
|
||||||
id: record.id,
|
redirect={false}
|
||||||
name: record.display_name ? record.display_name : record.id,
|
disabled={isASManagedUser}
|
||||||
}}
|
translateOptions={{
|
||||||
/>
|
id: record.id,
|
||||||
|
name: record.display_name ? record.display_name : record.id,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
import { Stack, Switch, Typography } from "@mui/material";
|
import { Tooltip, Stack, Switch, Typography } from "@mui/material";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useRecordContext } from "react-admin";
|
import { useRecordContext, useTranslate, useNotify, useDataProvider } from "react-admin";
|
||||||
import { useNotify } from "react-admin";
|
|
||||||
import { useDataProvider } from "react-admin";
|
|
||||||
|
|
||||||
import { ExperimentalFeaturesModel, SynapseDataProvider } from "../synapse/dataProvider";
|
import { ExperimentalFeaturesModel, SynapseDataProvider } from "../synapse/dataProvider";
|
||||||
|
|
||||||
@@ -15,6 +13,7 @@ const ExperimentalFeatureRow = (props: {
|
|||||||
featureValue: boolean;
|
featureValue: boolean;
|
||||||
updateFeature: (feature_name: string, feature_value: boolean) => void;
|
updateFeature: (feature_name: string, feature_value: boolean) => void;
|
||||||
}) => {
|
}) => {
|
||||||
|
const translate = useTranslate();
|
||||||
const featureKey = props.featureKey;
|
const featureKey = props.featureKey;
|
||||||
const featureValue = props.featureValue;
|
const featureValue = props.featureValue;
|
||||||
const featureDescription = experimentalFeaturesMap[featureKey] ?? "";
|
const featureDescription = experimentalFeaturesMap[featureKey] ?? "";
|
||||||
@@ -34,7 +33,9 @@ const ExperimentalFeatureRow = (props: {
|
|||||||
padding: 2,
|
padding: 2,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Switch checked={checked} onChange={handleChange} />
|
<Tooltip title={translate("resources.experimental_features.action.toggle")}>
|
||||||
|
<Switch checked={checked} onChange={handleChange} />
|
||||||
|
</Tooltip>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Typography
|
<Typography
|
||||||
variant="subtitle1"
|
variant="subtitle1"
|
||||||
|
@@ -50,10 +50,14 @@ const DeleteMediaDialog = ({ open, onClose, onSubmit }) => {
|
|||||||
|
|
||||||
const DeleteMediaToolbar = (props: ToolbarProps) => (
|
const DeleteMediaToolbar = (props: ToolbarProps) => (
|
||||||
<Toolbar {...props}>
|
<Toolbar {...props}>
|
||||||
<SaveButton label="delete_media.action.send" icon={<DeleteSweepIcon />} />
|
<Tooltip title={translate("delete_media.helper.send")}>
|
||||||
<Button label="ra.action.cancel" onClick={onClose}>
|
<SaveButton label="delete_media.action.send" icon={<DeleteSweepIcon />} />
|
||||||
<IconCancel />
|
</Tooltip>
|
||||||
</Button>
|
<Tooltip title={translate("ra.action.cancel")}>
|
||||||
|
<Button label="ra.action.cancel" onClick={onClose}>
|
||||||
|
<IconCancel />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -63,9 +67,20 @@ const DeleteMediaDialog = ({ open, onClose, onSubmit }) => {
|
|||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText>{translate("delete_media.helper.send")}</DialogContentText>
|
<DialogContentText>{translate("delete_media.helper.send")}</DialogContentText>
|
||||||
<SimpleForm toolbar={<DeleteMediaToolbar />} onSubmit={onSubmit}>
|
<SimpleForm toolbar={<DeleteMediaToolbar />} onSubmit={onSubmit}>
|
||||||
<DateTimeInput source="before_ts" label="delete_media.fields.before_ts" defaultValue={0} parse={dateParser} />
|
<Tooltip title={translate("delete_media.helper.before_ts")}>
|
||||||
<NumberInput source="size_gt" label="delete_media.fields.size_gt" defaultValue={0} min={0} step={1024} />
|
<DateTimeInput
|
||||||
<BooleanInput source="keep_profiles" label="delete_media.fields.keep_profiles" defaultValue={true} />
|
source="before_ts"
|
||||||
|
label="delete_media.fields.before_ts"
|
||||||
|
defaultValue={0}
|
||||||
|
parse={dateParser}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title={translate("delete_media.helper.size_gt")}>
|
||||||
|
<NumberInput source="size_gt" label="delete_media.fields.size_gt" defaultValue={0} min={0} step={1024} />
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title={translate("delete_media.helper.keep_profiles")}>
|
||||||
|
<BooleanInput source="keep_profiles" label="delete_media.fields.keep_profiles" defaultValue={true} />
|
||||||
|
</Tooltip>
|
||||||
</SimpleForm>
|
</SimpleForm>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@@ -76,6 +91,7 @@ export const DeleteMediaButton = (props: ButtonProps) => {
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const notify = useNotify();
|
const notify = useNotify();
|
||||||
|
const translate = useTranslate();
|
||||||
const dataProvider = useDataProvider<SynapseDataProvider>();
|
const dataProvider = useDataProvider<SynapseDataProvider>();
|
||||||
const { mutate: deleteMedia, isPending } = useMutation({
|
const { mutate: deleteMedia, isPending } = useMutation({
|
||||||
mutationFn: (values: DeleteMediaParams) => dataProvider.deleteMedia(values),
|
mutationFn: (values: DeleteMediaParams) => dataProvider.deleteMedia(values),
|
||||||
@@ -95,24 +111,26 @@ export const DeleteMediaButton = (props: ButtonProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Tooltip title={translate("delete_media.helper.send")}>
|
||||||
{...props}
|
<Button
|
||||||
label="delete_media.action.send"
|
{...props}
|
||||||
onClick={openDialog}
|
label="delete_media.action.send"
|
||||||
disabled={isPending}
|
onClick={openDialog}
|
||||||
sx={{
|
disabled={isPending}
|
||||||
color: theme.palette.error.main,
|
sx={{
|
||||||
"&:hover": {
|
color: theme.palette.error.main,
|
||||||
backgroundColor: alpha(theme.palette.error.main, 0.12),
|
"&:hover": {
|
||||||
// Reset on mouse devices
|
backgroundColor: alpha(theme.palette.error.main, 0.12),
|
||||||
"@media (hover: none)": {
|
// Reset on mouse devices
|
||||||
backgroundColor: "transparent",
|
"@media (hover: none)": {
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<DeleteSweepIcon />
|
||||||
<DeleteSweepIcon />
|
</Button>
|
||||||
</Button>
|
</Tooltip>
|
||||||
<DeleteMediaDialog open={open} onClose={closeDialog} onSubmit={deleteMedia} />
|
<DeleteMediaDialog open={open} onClose={closeDialog} onSubmit={deleteMedia} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -123,10 +141,14 @@ const PurgeRemoteMediaDialog = ({ open, onClose, onSubmit }) => {
|
|||||||
|
|
||||||
const PurgeRemoteMediaToolbar = (props: ToolbarProps) => (
|
const PurgeRemoteMediaToolbar = (props: ToolbarProps) => (
|
||||||
<Toolbar {...props}>
|
<Toolbar {...props}>
|
||||||
<SaveButton label="purge_remote_media.action.send" icon={<DeleteSweepIcon />} />
|
<Tooltip title={translate("purge_remote_media.helper.send")}>
|
||||||
<Button label="ra.action.cancel" onClick={onClose}>
|
<SaveButton label="purge_remote_media.action.send" icon={<DeleteSweepIcon />} />
|
||||||
<IconCancel />
|
</Tooltip>
|
||||||
</Button>
|
<Tooltip title={translate("ra.action.cancel")}>
|
||||||
|
<Button label="ra.action.cancel" onClick={onClose}>
|
||||||
|
<IconCancel />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -152,6 +174,7 @@ export const PurgeRemoteMediaButton = (props: ButtonProps) => {
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const notify = useNotify();
|
const notify = useNotify();
|
||||||
|
const translate = useTranslate();
|
||||||
const dataProvider = useDataProvider<SynapseDataProvider>();
|
const dataProvider = useDataProvider<SynapseDataProvider>();
|
||||||
const { mutate: purgeRemoteMedia, isPending } = useMutation({
|
const { mutate: purgeRemoteMedia, isPending } = useMutation({
|
||||||
mutationFn: (values: DeleteMediaParams) => dataProvider.purgeRemoteMedia(values),
|
mutationFn: (values: DeleteMediaParams) => dataProvider.purgeRemoteMedia(values),
|
||||||
@@ -171,22 +194,24 @@ export const PurgeRemoteMediaButton = (props: ButtonProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Tooltip title={translate("purge_remote_media.helper.send")}>
|
||||||
{...props}
|
<Button
|
||||||
label="purge_remote_media.action.send"
|
{...props}
|
||||||
onClick={openDialog}
|
label="purge_remote_media.action.send"
|
||||||
disabled={isPending}
|
onClick={openDialog}
|
||||||
sx={{
|
disabled={isPending}
|
||||||
"&:hover": {
|
sx={{
|
||||||
// Reset on mouse devices
|
"&:hover": {
|
||||||
"@media (hover: none)": {
|
// Reset on mouse devices
|
||||||
backgroundColor: "transparent",
|
"@media (hover: none)": {
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<DeleteSweepIcon />
|
||||||
<DeleteSweepIcon />
|
</Button>
|
||||||
</Button>
|
</Tooltip>
|
||||||
<PurgeRemoteMediaDialog open={open} onClose={closeDialog} onSubmit={purgeRemoteMedia} />
|
<PurgeRemoteMediaDialog open={open} onClose={closeDialog} onSubmit={purgeRemoteMedia} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -462,6 +487,7 @@ export const ViewMediaButton = ({ mxcURL, label, uploadName, mimetype }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const MediaIDField = ({ source }) => {
|
export const MediaIDField = ({ source }) => {
|
||||||
|
const translate = useTranslate();
|
||||||
const record = useRecordContext();
|
const record = useRecordContext();
|
||||||
if (!record) {
|
if (!record) {
|
||||||
return null;
|
return null;
|
||||||
@@ -484,10 +510,15 @@ export const MediaIDField = ({ source }) => {
|
|||||||
mxcURL = `mxc://${homeserver}/${mediaID}`;
|
mxcURL = `mxc://${homeserver}/${mediaID}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <ViewMediaButton mxcURL={mxcURL} label={mediaID} uploadName={uploadName} mimetype={record.media_type} />;
|
return (
|
||||||
|
<Tooltip title={translate("resources.users_media.action.open")}>
|
||||||
|
<ViewMediaButton mxcURL={mxcURL} label={mediaID} uploadName={uploadName} mimetype={record.media_type} />
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ReportMediaContent = ({ source }) => {
|
export const ReportMediaContent = ({ source }) => {
|
||||||
|
const translate = useTranslate();
|
||||||
const record = useRecordContext();
|
const record = useRecordContext();
|
||||||
if (!record) {
|
if (!record) {
|
||||||
return null;
|
return null;
|
||||||
@@ -503,5 +534,9 @@ export const ReportMediaContent = ({ source }) => {
|
|||||||
uploadName = decodeURLComponent(get(record, "event_json.content.body")?.toString());
|
uploadName = decodeURLComponent(get(record, "event_json.content.body")?.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return <ViewMediaButton mxcURL={mxcURL} label={mxcURL} uploadName={uploadName} mimetype={record.media_type} />;
|
return (
|
||||||
|
<Tooltip title={translate("resources.users_media.action.open")}>
|
||||||
|
<ViewMediaButton mxcURL={mxcURL} label={mxcURL} uploadName={uploadName} mimetype={record.media_type} />
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import { render, screen } from "@testing-library/react";
|
import { render, screen } from "@testing-library/react";
|
||||||
import polyglotI18nProvider from "ra-i18n-polyglot";
|
import polyglotI18nProvider from "ra-i18n-polyglot";
|
||||||
import { AdminContext } from "react-admin";
|
import { AdminContext } from "react-admin";
|
||||||
import { BrowserRouter } from "react-router-dom";
|
|
||||||
|
|
||||||
import LoginPage from "./LoginPage";
|
import LoginPage from "./LoginPage";
|
||||||
import { AppContext } from "../Context";
|
import { AppContext } from "../Context";
|
||||||
@@ -14,11 +13,9 @@ describe("LoginForm", () => {
|
|||||||
it("renders with no restriction to homeserver", async () => {
|
it("renders with no restriction to homeserver", async () => {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
render(
|
render(
|
||||||
<BrowserRouter>
|
<AdminContext i18nProvider={i18nProvider}>
|
||||||
<AdminContext i18nProvider={i18nProvider}>
|
<LoginPage />
|
||||||
<LoginPage />
|
</AdminContext>
|
||||||
</AdminContext>
|
|
||||||
</BrowserRouter>
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -35,20 +32,18 @@ describe("LoginForm", () => {
|
|||||||
|
|
||||||
it("renders with single restricted homeserver", () => {
|
it("renders with single restricted homeserver", () => {
|
||||||
render(
|
render(
|
||||||
<BrowserRouter>
|
<AppContext.Provider
|
||||||
<AppContext.Provider
|
value={{
|
||||||
value={{
|
restrictBaseUrl: "https://matrix.example.com",
|
||||||
restrictBaseUrl: "https://matrix.example.com",
|
asManagedUsers: [],
|
||||||
asManagedUsers: [],
|
menu: [],
|
||||||
menu: [],
|
corsCredentials: "include",
|
||||||
corsCredentials: "include",
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<AdminContext i18nProvider={i18nProvider}>
|
||||||
<AdminContext i18nProvider={i18nProvider}>
|
<LoginPage />
|
||||||
<LoginPage />
|
</AdminContext>
|
||||||
</AdminContext>
|
</AppContext.Provider>
|
||||||
</AppContext.Provider>
|
|
||||||
</BrowserRouter>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
screen.getByText(englishMessages.synapseadmin.auth.welcome);
|
screen.getByText(englishMessages.synapseadmin.auth.welcome);
|
||||||
@@ -73,9 +68,7 @@ describe("LoginForm", () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AdminContext i18nProvider={i18nProvider}>
|
<AdminContext i18nProvider={i18nProvider}>
|
||||||
<BrowserRouter>
|
<LoginPage />
|
||||||
<LoginPage />
|
|
||||||
</BrowserRouter>
|
|
||||||
</AdminContext>
|
</AdminContext>
|
||||||
</AppContext.Provider>
|
</AppContext.Provider>
|
||||||
);
|
);
|
||||||
|
@@ -171,7 +171,7 @@ export const UserList = (props: ListProps) => (
|
|||||||
<List
|
<List
|
||||||
{...props}
|
{...props}
|
||||||
filters={userFilters}
|
filters={userFilters}
|
||||||
filterDefaultValues={{ deactivated: false, locked: false, suspended: false }}
|
filterDefaultValues={{ guests: false, deactivated: false, locked: false, suspended: false }}
|
||||||
sort={{ field: "name", order: "ASC" }}
|
sort={{ field: "name", order: "ASC" }}
|
||||||
actions={<UserListActions />}
|
actions={<UserListActions />}
|
||||||
pagination={<UserPagination />}
|
pagination={<UserPagination />}
|
||||||
|
Reference in New Issue
Block a user