Merge branch 'master' into room_state
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { TestContext } from "react-admin";
|
||||
import { TestContext } from "ra-test";
|
||||
import { shallow } from "enzyme";
|
||||
import LoginPage from "./LoginPage";
|
||||
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
import React, { Fragment } from "react";
|
||||
import Avatar from "@material-ui/core/Avatar";
|
||||
import { Chip } from "@material-ui/core";
|
||||
import { connect } from "react-redux";
|
||||
import FolderSharedIcon from "@material-ui/icons/FolderShared";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import {
|
||||
BooleanField,
|
||||
BulkDeleteButton,
|
||||
Button,
|
||||
Datagrid,
|
||||
DeleteButton,
|
||||
Filter,
|
||||
List,
|
||||
NumberField,
|
||||
Pagination,
|
||||
TextField,
|
||||
useCreate,
|
||||
useMutation,
|
||||
useNotify,
|
||||
useTranslate,
|
||||
useRefresh,
|
||||
useUnselectAll,
|
||||
} from "react-admin";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
small: {
|
||||
height: "40px",
|
||||
width: "40px",
|
||||
},
|
||||
});
|
||||
|
||||
const RoomDirectoryPagination = props => (
|
||||
<Pagination {...props} rowsPerPageOptions={[100, 500, 1000, 2000]} />
|
||||
);
|
||||
|
||||
export const RoomDirectoryDeleteButton = props => {
|
||||
const translate = useTranslate();
|
||||
|
||||
return (
|
||||
<DeleteButton
|
||||
{...props}
|
||||
label="resources.room_directory.action.erase"
|
||||
redirect={false}
|
||||
mutationMode="pessimistic"
|
||||
confirmTitle={translate("resources.room_directory.action.title", {
|
||||
smart_count: 1,
|
||||
})}
|
||||
confirmContent={translate("resources.room_directory.action.content", {
|
||||
smart_count: 1,
|
||||
})}
|
||||
resource="room_directory"
|
||||
icon={<FolderSharedIcon />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const RoomDirectoryBulkDeleteButton = props => (
|
||||
<BulkDeleteButton
|
||||
{...props}
|
||||
label="resources.room_directory.action.erase"
|
||||
undoable={false}
|
||||
confirmTitle="resources.room_directory.action.title"
|
||||
confirmContent="resources.room_directory.action.content"
|
||||
resource="room_directory"
|
||||
icon={<FolderSharedIcon />}
|
||||
/>
|
||||
);
|
||||
|
||||
export const RoomDirectoryBulkSaveButton = ({ selectedIds }) => {
|
||||
const notify = useNotify();
|
||||
const refresh = useRefresh();
|
||||
const unselectAll = useUnselectAll();
|
||||
const [createMany, { loading }] = useMutation();
|
||||
|
||||
const handleSend = values => {
|
||||
createMany(
|
||||
{
|
||||
type: "createMany",
|
||||
resource: "room_directory",
|
||||
payload: { ids: selectedIds, data: {} },
|
||||
},
|
||||
{
|
||||
onSuccess: ({ data }) => {
|
||||
notify("resources.room_directory.action.send_success");
|
||||
unselectAll("rooms");
|
||||
refresh();
|
||||
},
|
||||
onFailure: error =>
|
||||
notify("resources.room_directory.action.send_failure", "error"),
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
label="resources.room_directory.action.create"
|
||||
onClick={handleSend}
|
||||
disabled={loading}
|
||||
>
|
||||
<FolderSharedIcon />
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export const RoomDirectorySaveButton = ({ record }) => {
|
||||
const notify = useNotify();
|
||||
const refresh = useRefresh();
|
||||
const [create, { loading }] = useCreate("room_directory");
|
||||
|
||||
const handleSend = values => {
|
||||
create(
|
||||
{
|
||||
payload: { data: { id: record.id } },
|
||||
},
|
||||
{
|
||||
onSuccess: ({ data }) => {
|
||||
notify("resources.room_directory.action.send_success");
|
||||
refresh();
|
||||
},
|
||||
onFailure: error =>
|
||||
notify("resources.room_directory.action.send_failure", "error"),
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
label="resources.room_directory.action.create"
|
||||
onClick={handleSend}
|
||||
disabled={loading}
|
||||
>
|
||||
<FolderSharedIcon />
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
const RoomDirectoryBulkActionButtons = props => (
|
||||
<Fragment>
|
||||
<RoomDirectoryBulkDeleteButton {...props} />
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
const AvatarField = ({ source, className, record = {} }) => (
|
||||
<Avatar src={record[source]} className={className} />
|
||||
);
|
||||
|
||||
const RoomDirectoryFilter = ({ ...props }) => {
|
||||
const translate = useTranslate();
|
||||
return (
|
||||
<Filter {...props}>
|
||||
<Chip
|
||||
label={translate("resources.rooms.fields.room_id")}
|
||||
source="room_id"
|
||||
defaultValue={false}
|
||||
style={{ marginBottom: 8 }}
|
||||
/>
|
||||
<Chip
|
||||
label={translate("resources.rooms.fields.topic")}
|
||||
source="topic"
|
||||
defaultValue={false}
|
||||
style={{ marginBottom: 8 }}
|
||||
/>
|
||||
<Chip
|
||||
label={translate("resources.rooms.fields.canonical_alias")}
|
||||
source="canonical_alias"
|
||||
defaultValue={false}
|
||||
style={{ marginBottom: 8 }}
|
||||
/>
|
||||
</Filter>
|
||||
);
|
||||
};
|
||||
|
||||
export const FilterableRoomDirectoryList = ({ ...props }) => {
|
||||
const classes = useStyles();
|
||||
const translate = useTranslate();
|
||||
const filter = props.roomDirectoryFilters;
|
||||
const roomIdFilter = filter && filter.room_id ? true : false;
|
||||
const topicFilter = filter && filter.topic ? true : false;
|
||||
const canonicalAliasFilter = filter && filter.canonical_alias ? true : false;
|
||||
|
||||
return (
|
||||
<List
|
||||
{...props}
|
||||
pagination={<RoomDirectoryPagination />}
|
||||
bulkActionButtons={<RoomDirectoryBulkActionButtons />}
|
||||
filters={<RoomDirectoryFilter />}
|
||||
perPage={100}
|
||||
>
|
||||
<Datagrid>
|
||||
<AvatarField
|
||||
source="avatar_src"
|
||||
sortable={false}
|
||||
className={classes.small}
|
||||
label={translate("resources.rooms.fields.avatar")}
|
||||
/>
|
||||
<TextField
|
||||
source="name"
|
||||
sortable={false}
|
||||
label={translate("resources.rooms.fields.name")}
|
||||
/>
|
||||
{roomIdFilter && (
|
||||
<TextField
|
||||
source="room_id"
|
||||
sortable={false}
|
||||
label={translate("resources.rooms.fields.room_id")}
|
||||
/>
|
||||
)}
|
||||
{canonicalAliasFilter && (
|
||||
<TextField
|
||||
source="canonical_alias"
|
||||
sortable={false}
|
||||
label={translate("resources.rooms.fields.canonical_alias")}
|
||||
/>
|
||||
)}
|
||||
{topicFilter && (
|
||||
<TextField
|
||||
source="topic"
|
||||
sortable={false}
|
||||
label={translate("resources.rooms.fields.topic")}
|
||||
/>
|
||||
)}
|
||||
<NumberField
|
||||
source="num_joined_members"
|
||||
sortable={false}
|
||||
label={translate("resources.rooms.fields.joined_members")}
|
||||
/>
|
||||
<BooleanField
|
||||
source="world_readable"
|
||||
sortable={false}
|
||||
label={translate("resources.room_directory.fields.world_readable")}
|
||||
/>
|
||||
<BooleanField
|
||||
source="guest_can_join"
|
||||
sortable={false}
|
||||
label={translate("resources.room_directory.fields.guest_can_join")}
|
||||
/>
|
||||
</Datagrid>
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
roomDirectoryFilters:
|
||||
state.admin.resources.room_directory.list.params.displayedFilters,
|
||||
};
|
||||
}
|
||||
|
||||
export const RoomDirectoryList = connect(mapStateToProps)(
|
||||
FilterableRoomDirectoryList
|
||||
);
|
||||
@@ -0,0 +1,145 @@
|
||||
import React, { Fragment, useState } from "react";
|
||||
import classnames from "classnames";
|
||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import {
|
||||
BooleanInput,
|
||||
Button,
|
||||
DateTimeInput,
|
||||
NumberInput,
|
||||
SaveButton,
|
||||
SimpleForm,
|
||||
Toolbar,
|
||||
useDelete,
|
||||
useNotify,
|
||||
useTranslate,
|
||||
} from "react-admin";
|
||||
import IconCancel from "@material-ui/icons/Cancel";
|
||||
import Dialog from "@material-ui/core/Dialog";
|
||||
import DialogContent from "@material-ui/core/DialogContent";
|
||||
import DialogContentText from "@material-ui/core/DialogContentText";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import DeleteSweepIcon from "@material-ui/icons/DeleteSweep";
|
||||
|
||||
const useStyles = makeStyles(
|
||||
theme => ({
|
||||
deleteButton: {
|
||||
color: theme.palette.error.main,
|
||||
"&:hover": {
|
||||
backgroundColor: fade(theme.palette.error.main, 0.12),
|
||||
// Reset on mouse devices
|
||||
"@media (hover: none)": {
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
{ name: "RaDeleteDeviceButton" }
|
||||
);
|
||||
|
||||
const DeleteMediaDialog = ({ open, loading, onClose, onSend }) => {
|
||||
const translate = useTranslate();
|
||||
|
||||
const dateParser = v => {
|
||||
const d = new Date(v);
|
||||
if (isNaN(d)) return 0;
|
||||
return d.getTime();
|
||||
};
|
||||
|
||||
const DeleteMediaToolbar = props => {
|
||||
return (
|
||||
<Toolbar {...props}>
|
||||
<SaveButton
|
||||
label="resources.delete_media.action.send"
|
||||
icon={<DeleteSweepIcon />}
|
||||
/>
|
||||
<Button label="ra.action.cancel" onClick={onClose}>
|
||||
<IconCancel />
|
||||
</Button>
|
||||
</Toolbar>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={onClose} loading={loading}>
|
||||
<DialogTitle>
|
||||
{translate("resources.delete_media.action.send")}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
{translate("resources.delete_media.helper.send")}
|
||||
</DialogContentText>
|
||||
<SimpleForm
|
||||
toolbar={<DeleteMediaToolbar />}
|
||||
submitOnEnter={false}
|
||||
redirect={false}
|
||||
save={onSend}
|
||||
>
|
||||
<DateTimeInput
|
||||
fullWidth
|
||||
source="before_ts"
|
||||
label="resources.delete_media.fields.before_ts"
|
||||
defaultValue={0}
|
||||
parse={dateParser}
|
||||
/>
|
||||
<NumberInput
|
||||
fullWidth
|
||||
source="size_gt"
|
||||
label="resources.delete_media.fields.size_gt"
|
||||
defaultValue={0}
|
||||
min={0}
|
||||
step={1024}
|
||||
/>
|
||||
<BooleanInput
|
||||
fullWidth
|
||||
source="keep_profiles"
|
||||
label="resources.delete_media.fields.keep_profiles"
|
||||
defaultValue={true}
|
||||
/>
|
||||
</SimpleForm>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export const DeleteMediaButton = props => {
|
||||
const classes = useStyles(props);
|
||||
const [open, setOpen] = useState(false);
|
||||
const notify = useNotify();
|
||||
const [deleteOne, { loading }] = useDelete("delete_media");
|
||||
|
||||
const handleDialogOpen = () => setOpen(true);
|
||||
const handleDialogClose = () => setOpen(false);
|
||||
|
||||
const handleSend = values => {
|
||||
deleteOne(
|
||||
{ payload: { ...values } },
|
||||
{
|
||||
onSuccess: () => {
|
||||
notify("resources.delete_media.action.send_success");
|
||||
handleDialogClose();
|
||||
},
|
||||
onFailure: () =>
|
||||
notify("resources.delete_media.action.send_failure", "error"),
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Button
|
||||
label="resources.delete_media.action.send"
|
||||
onClick={handleDialogOpen}
|
||||
disabled={loading}
|
||||
className={classnames("ra-delete-button", classes.deleteButton)}
|
||||
>
|
||||
<DeleteSweepIcon />
|
||||
</Button>
|
||||
<DeleteMediaDialog
|
||||
open={open}
|
||||
onClose={handleDialogClose}
|
||||
onSend={handleSend}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
+31
-12
@@ -2,6 +2,7 @@ import React, { Fragment } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
BooleanField,
|
||||
BulkDeleteButton,
|
||||
BulkDeleteWithConfirmButton,
|
||||
DateField,
|
||||
Datagrid,
|
||||
@@ -29,6 +30,12 @@ import UserIcon from "@material-ui/icons/Group";
|
||||
import ViewListIcon from "@material-ui/icons/ViewList";
|
||||
import VisibilityIcon from "@material-ui/icons/Visibility";
|
||||
import EventIcon from "@material-ui/icons/Event";
|
||||
import {
|
||||
RoomDirectoryBulkDeleteButton,
|
||||
RoomDirectoryBulkSaveButton,
|
||||
RoomDirectoryDeleteButton,
|
||||
RoomDirectorySaveButton,
|
||||
} from "./RoomDirectory";
|
||||
|
||||
const RoomPagination = props => (
|
||||
<Pagination {...props} rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
|
||||
@@ -75,16 +82,26 @@ const RoomTitle = ({ record }) => {
|
||||
};
|
||||
|
||||
const RoomShowActions = ({ basePath, data, resource }) => {
|
||||
const translate = useTranslate();
|
||||
var roomDirectoryStatus = "";
|
||||
if (data) {
|
||||
roomDirectoryStatus = data.public;
|
||||
}
|
||||
|
||||
return (
|
||||
<TopToolbar>
|
||||
{roomDirectoryStatus === false && (
|
||||
<RoomDirectorySaveButton record={data} />
|
||||
)}
|
||||
{roomDirectoryStatus === true && (
|
||||
<RoomDirectoryDeleteButton record={data} />
|
||||
)}
|
||||
<DeleteButton
|
||||
basePath={basePath}
|
||||
record={data}
|
||||
resource={resource}
|
||||
undoable={false}
|
||||
confirmTitle={translate("synapseadmin.rooms.delete.title")}
|
||||
confirmContent={translate("synapseadmin.rooms.delete.message")}
|
||||
mutationMode="pessimistic"
|
||||
confirmTitle="resources.rooms.action.erase.title"
|
||||
confirmContent="resources.rooms.action.erase.content"
|
||||
/>
|
||||
</TopToolbar>
|
||||
);
|
||||
@@ -111,6 +128,7 @@ export const RoomShow = props => {
|
||||
>
|
||||
<TextField source="joined_members" />
|
||||
<TextField source="joined_local_members" />
|
||||
<TextField source="joined_local_devices" />
|
||||
<TextField source="state_events" />
|
||||
<TextField source="version" />
|
||||
<TextField
|
||||
@@ -244,7 +262,14 @@ export const RoomShow = props => {
|
||||
|
||||
const RoomBulkActionButtons = props => (
|
||||
<Fragment>
|
||||
<BulkDeleteWithConfirmButton {...props} />
|
||||
<RoomDirectoryBulkSaveButton {...props} />
|
||||
<RoomDirectoryBulkDeleteButton {...props} />
|
||||
<BulkDeleteButton
|
||||
{...props}
|
||||
confirmTitle="resources.rooms.action.erase.title"
|
||||
confirmContent="resources.rooms.action.erase.content"
|
||||
undoable={false}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
@@ -288,7 +313,6 @@ const FilterableRoomList = ({ ...props }) => {
|
||||
const stateEventsFilter = filter && filter.state_events ? true : false;
|
||||
const versionFilter = filter && filter.version ? true : false;
|
||||
const federateableFilter = filter && filter.federatable ? true : false;
|
||||
const translate = useTranslate();
|
||||
|
||||
return (
|
||||
<List
|
||||
@@ -296,12 +320,7 @@ const FilterableRoomList = ({ ...props }) => {
|
||||
pagination={<RoomPagination />}
|
||||
sort={{ field: "name", order: "ASC" }}
|
||||
filters={<RoomFilter />}
|
||||
bulkActionButtons={
|
||||
<RoomBulkActionButtons
|
||||
confirmTitle={translate("synapseadmin.rooms.delete.title")}
|
||||
confirmContent={translate("synapseadmin.rooms.delete.message")}
|
||||
/>
|
||||
}
|
||||
bulkActionButtons={<RoomBulkActionButtons />}
|
||||
>
|
||||
<Datagrid rowClick="show">
|
||||
<EncryptionField
|
||||
|
||||
@@ -1,13 +1,51 @@
|
||||
import React from "react";
|
||||
import { cloneElement } from "react";
|
||||
import {
|
||||
Datagrid,
|
||||
ExportButton,
|
||||
Filter,
|
||||
List,
|
||||
NumberField,
|
||||
TextField,
|
||||
SearchInput,
|
||||
Pagination,
|
||||
sanitizeListRestProps,
|
||||
SearchInput,
|
||||
TextField,
|
||||
TopToolbar,
|
||||
useListContext,
|
||||
} from "react-admin";
|
||||
import { DeleteMediaButton } from "./media";
|
||||
|
||||
const ListActions = props => {
|
||||
const { className, exporter, filters, maxResults, ...rest } = props;
|
||||
const {
|
||||
currentSort,
|
||||
resource,
|
||||
displayedFilters,
|
||||
filterValues,
|
||||
showFilter,
|
||||
total,
|
||||
} = useListContext();
|
||||
return (
|
||||
<TopToolbar className={className} {...sanitizeListRestProps(rest)}>
|
||||
{filters &&
|
||||
cloneElement(filters, {
|
||||
resource,
|
||||
showFilter,
|
||||
displayedFilters,
|
||||
filterValues,
|
||||
context: "button",
|
||||
})}
|
||||
<DeleteMediaButton />
|
||||
<ExportButton
|
||||
disabled={total === 0}
|
||||
resource={resource}
|
||||
sort={currentSort}
|
||||
filterValues={filterValues}
|
||||
maxResults={maxResults}
|
||||
/>
|
||||
</TopToolbar>
|
||||
);
|
||||
};
|
||||
|
||||
const UserMediaStatsPagination = props => (
|
||||
<Pagination {...props} rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
|
||||
@@ -23,6 +61,7 @@ export const UserMediaStatsList = props => {
|
||||
return (
|
||||
<List
|
||||
{...props}
|
||||
actions={<ListActions />}
|
||||
filters={<UserMediaStatsFilter />}
|
||||
pagination={<UserMediaStatsPagination />}
|
||||
sort={{ field: "media_length", order: "DESC" }}
|
||||
|
||||
+16
-15
@@ -139,19 +139,17 @@ const UserFilter = props => (
|
||||
</Filter>
|
||||
);
|
||||
|
||||
const UserBulkActionButtons = props => {
|
||||
const translate = useTranslate();
|
||||
return (
|
||||
<Fragment>
|
||||
<ServerNoticeBulkButton {...props} />
|
||||
<BulkDeleteButton
|
||||
{...props}
|
||||
label="resources.users.action.erase"
|
||||
title={translate("resources.users.helper.erase")}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
const UserBulkActionButtons = props => (
|
||||
<Fragment>
|
||||
<ServerNoticeBulkButton {...props} />
|
||||
<BulkDeleteButton
|
||||
{...props}
|
||||
label="resources.users.action.erase"
|
||||
confirmTitle="resources.users.helper.erase"
|
||||
undoable={false}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
const AvatarField = ({ source, className, record = {} }) => (
|
||||
<Avatar src={record[source]} className={className} />
|
||||
@@ -238,7 +236,10 @@ const UserEditToolbar = props => {
|
||||
<SaveButton submitOnEnter={true} />
|
||||
<DeleteButton
|
||||
label="resources.users.action.erase"
|
||||
title={translate("resources.users.helper.erase")}
|
||||
confirmTitle={translate("resources.users.helper.erase", {
|
||||
smart_count: 1,
|
||||
})}
|
||||
mutationMode="pessimistic"
|
||||
/>
|
||||
<ServerNoticeButton />
|
||||
</Toolbar>
|
||||
@@ -453,7 +454,7 @@ export const UserEdit = props => {
|
||||
<TextField source="upload_name" sortable={false} />
|
||||
<TextField source="quarantined_by" sortable={false} />
|
||||
<BooleanField source="safe_from_quarantine" sortable={false} />
|
||||
<DeleteButton undoable={false} redirect={false} />
|
||||
<DeleteButton mutationMode="pessimistic" redirect={false} />
|
||||
</Datagrid>
|
||||
</ReferenceManyField>
|
||||
</FormTab>
|
||||
|
||||
Reference in New Issue
Block a user