remove unused eslint plugin, run eslint --fix, rollback node memory workaround in ci
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import { MouseEvent } from "react";
|
||||
|
||||
import AutorenewIcon from "@mui/icons-material/Autorenew";
|
||||
import DestinationsIcon from "@mui/icons-material/CloudQueue";
|
||||
import ErrorIcon from "@mui/icons-material/Error";
|
||||
import FolderSharedIcon from "@mui/icons-material/FolderShared";
|
||||
import ViewListIcon from "@mui/icons-material/ViewList";
|
||||
import ErrorIcon from '@mui/icons-material/Error';
|
||||
import { get } from "lodash";
|
||||
import { MouseEvent } from "react";
|
||||
import {
|
||||
Button,
|
||||
Datagrid,
|
||||
@@ -34,7 +34,6 @@ import {
|
||||
} from "react-admin";
|
||||
|
||||
import { DATE_FORMAT } from "../utils/date";
|
||||
import { get } from "lodash";
|
||||
|
||||
const DestinationPagination = () => <Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />;
|
||||
|
||||
@@ -101,19 +100,18 @@ const RetryDateField = (props: DateFieldProps) => {
|
||||
return <DateField {...props} />;
|
||||
};
|
||||
|
||||
|
||||
const destinationFieldRender = (record: RaRecord) => {
|
||||
if (record.retry_last_ts > 0) {
|
||||
return (
|
||||
<>
|
||||
<ErrorIcon fontSize="inherit" color="error" sx={{verticalAlign: "middle"}}/>
|
||||
<ErrorIcon fontSize="inherit" color="error" sx={{ verticalAlign: "middle" }} />
|
||||
|
||||
{record.destination}
|
||||
</>
|
||||
);
|
||||
}
|
||||
return <> {record.destination} </>;
|
||||
}
|
||||
};
|
||||
|
||||
export const DestinationList = (props: ListProps) => {
|
||||
const record = useRecordContext(props);
|
||||
@@ -126,11 +124,28 @@ export const DestinationList = (props: ListProps) => {
|
||||
perPage={50}
|
||||
>
|
||||
<DatagridConfigurable rowClick={id => `${id}/show/rooms`} bulkActionButtons={false}>
|
||||
<FunctionField source="destination" render={destinationFieldRender} label="resources.destinations.fields.destination" />
|
||||
<DateField source="failure_ts" showTime options={DATE_FORMAT} label="resources.destinations.fields.failure_ts" />
|
||||
<RetryDateField source="retry_last_ts" showTime options={DATE_FORMAT} label="resources.destinations.fields.retry_last_ts" />
|
||||
<FunctionField
|
||||
source="destination"
|
||||
render={destinationFieldRender}
|
||||
label="resources.destinations.fields.destination"
|
||||
/>
|
||||
<DateField
|
||||
source="failure_ts"
|
||||
showTime
|
||||
options={DATE_FORMAT}
|
||||
label="resources.destinations.fields.failure_ts"
|
||||
/>
|
||||
<RetryDateField
|
||||
source="retry_last_ts"
|
||||
showTime
|
||||
options={DATE_FORMAT}
|
||||
label="resources.destinations.fields.retry_last_ts"
|
||||
/>
|
||||
<TextField source="retry_interval" label="resources.destinations.fields.retry_interval" />
|
||||
<TextField source="last_successful_stream_ordering" label="resources.destinations.fields.last_successful_stream_ordering" />
|
||||
<TextField
|
||||
source="last_successful_stream_ordering"
|
||||
label="resources.destinations.fields.last_successful_stream_ordering"
|
||||
/>
|
||||
<DestinationReconnectButton />
|
||||
</DatagridConfigurable>
|
||||
</List>
|
||||
|
||||
@@ -41,11 +41,17 @@ export const RegistrationTokenList = (props: ListProps) => (
|
||||
perPage={50}
|
||||
>
|
||||
<DatagridConfigurable rowClick="edit">
|
||||
<TextField source="token" sortable={false} label="resources.registration_tokens.fields.token"/>
|
||||
<TextField source="token" sortable={false} label="resources.registration_tokens.fields.token" />
|
||||
<NumberField source="uses_allowed" sortable={false} label="resources.registration_tokens.fields.uses_allowed" />
|
||||
<NumberField source="pending" sortable={false} label="resources.registration_tokens.fields.pending" />
|
||||
<NumberField source="completed" sortable={false} label="resources.registration_tokens.fields.completed" />
|
||||
<DateField source="expiry_time" showTime options={DATE_FORMAT} sortable={false} label="resources.registration_tokens.fields.expiry_time" />
|
||||
<DateField
|
||||
source="expiry_time"
|
||||
showTime
|
||||
options={DATE_FORMAT}
|
||||
sortable={false}
|
||||
label="resources.registration_tokens.fields.expiry_time"
|
||||
/>
|
||||
</DatagridConfigurable>
|
||||
</List>
|
||||
);
|
||||
|
||||
@@ -22,8 +22,8 @@ import {
|
||||
useTranslate,
|
||||
} from "react-admin";
|
||||
|
||||
import { DATE_FORMAT } from "../utils/date";
|
||||
import { ReportMediaContent } from "../components/media";
|
||||
import { DATE_FORMAT } from "../utils/date";
|
||||
|
||||
const ReportPagination = () => <Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />;
|
||||
|
||||
@@ -93,7 +93,13 @@ export const ReportList = (props: ListProps) => (
|
||||
<List {...props} pagination={<ReportPagination />} perPage={50} sort={{ field: "received_ts", order: "DESC" }}>
|
||||
<DatagridConfigurable rowClick="show" bulkActionButtons={false}>
|
||||
<TextField source="id" sortable={false} label="resources.reports.fields.id" />
|
||||
<DateField source="received_ts" showTime options={DATE_FORMAT} sortable={true} label="resources.reports.fields.received_ts" />
|
||||
<DateField
|
||||
source="received_ts"
|
||||
showTime
|
||||
options={DATE_FORMAT}
|
||||
sortable={true}
|
||||
label="resources.reports.fields.received_ts"
|
||||
/>
|
||||
<TextField sortable={false} source="user_id" label="resources.reports.fields.user_id" />
|
||||
<TextField sortable={false} source="name" label="resources.reports.fields.name" />
|
||||
<TextField sortable={false} source="score" label="resources.reports.fields.score" />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import RoomDirectoryIcon from "@mui/icons-material/FolderShared";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import {
|
||||
BooleanField,
|
||||
BulkDeleteButton,
|
||||
@@ -25,9 +26,9 @@ import {
|
||||
useRefresh,
|
||||
useUnselectAll,
|
||||
} from "react-admin";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import AvatarField from "../components/AvatarField";
|
||||
|
||||
import { MakeAdminBtn } from "./rooms";
|
||||
import AvatarField from "../components/AvatarField";
|
||||
const RoomDirectoryPagination = () => <Pagination rowsPerPageOptions={[100, 500, 1000, 2000]} />;
|
||||
|
||||
export const RoomDirectoryUnpublishButton = (props: DeleteButtonProps) => {
|
||||
@@ -141,11 +142,7 @@ export const RoomDirectoryList = () => (
|
||||
bulkActionButtons={<RoomDirectoryBulkUnpublishButton />}
|
||||
omit={["room_id", "canonical_alias", "topic"]}
|
||||
>
|
||||
<AvatarField
|
||||
source="avatar_src"
|
||||
sx={{ height: "40px", width: "40px" }}
|
||||
label="resources.rooms.fields.avatar"
|
||||
/>
|
||||
<AvatarField source="avatar_src" sx={{ height: "40px", width: "40px" }} label="resources.rooms.fields.avatar" />
|
||||
<TextField source="name" sortable={false} label="resources.rooms.fields.name" />
|
||||
<TextField source="room_id" sortable={false} label="resources.rooms.fields.room_id" />
|
||||
<TextField source="canonical_alias" sortable={false} label="resources.rooms.fields.canonical_alias" />
|
||||
|
||||
@@ -4,12 +4,19 @@ import UserIcon from "@mui/icons-material/Group";
|
||||
import HttpsIcon from "@mui/icons-material/Https";
|
||||
import NoEncryptionIcon from "@mui/icons-material/NoEncryption";
|
||||
import PageviewIcon from "@mui/icons-material/Pageview";
|
||||
import PermMediaIcon from "@mui/icons-material/PermMedia";
|
||||
import PersonIcon from "@mui/icons-material/Person";
|
||||
import ViewListIcon from "@mui/icons-material/ViewList";
|
||||
import RoomIcon from "@mui/icons-material/ViewList";
|
||||
import VisibilityIcon from "@mui/icons-material/Visibility";
|
||||
import PermMediaIcon from "@mui/icons-material/PermMedia";
|
||||
import Alert from "@mui/material/Alert";
|
||||
import Box from "@mui/material/Box";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
BooleanField,
|
||||
DateField,
|
||||
@@ -40,27 +47,20 @@ import {
|
||||
useNotify,
|
||||
DeleteButton,
|
||||
} from "react-admin";
|
||||
import { useDataProvider } from "react-admin";
|
||||
import { Confirm } from "react-admin";
|
||||
|
||||
import TextField from "@mui/material/TextField";
|
||||
import {
|
||||
RoomDirectoryBulkUnpublishButton,
|
||||
RoomDirectoryBulkPublishButton,
|
||||
RoomDirectoryUnpublishButton,
|
||||
RoomDirectoryPublishButton,
|
||||
} from "./room_directory";
|
||||
import { DATE_FORMAT } from "../utils/date";
|
||||
import AvatarField from "../components/AvatarField";
|
||||
import DeleteRoomButton from "../components/DeleteRoomButton";
|
||||
import { MediaIDField } from "../components/media";
|
||||
import AvatarField from "../components/AvatarField";
|
||||
import { Room } from "../synapse/dataProvider";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { useDataProvider } from "react-admin";
|
||||
import { Confirm } from "react-admin";
|
||||
import { useState } from "react";
|
||||
import Button from "@mui/material/Button";
|
||||
import PersonIcon from '@mui/icons-material/Person';
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Alert from "@mui/material/Alert";
|
||||
import { DATE_FORMAT } from "../utils/date";
|
||||
|
||||
const RoomPagination = () => <Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />;
|
||||
|
||||
@@ -110,7 +110,6 @@ export const MakeAdminBtn = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
const ownMXID = localStorage.getItem("user_id") || "";
|
||||
const [open, setOpen] = useState(false);
|
||||
const [userIdValue, setUserIdValue] = useState(ownMXID);
|
||||
@@ -134,12 +133,12 @@ export const MakeAdminBtn = () => {
|
||||
setOpen(false);
|
||||
setUserIdValue("");
|
||||
},
|
||||
onError: (err) => {
|
||||
onError: err => {
|
||||
const errorMessage = err instanceof Error ? err.message : "Unknown error";
|
||||
notify("resources.rooms.action.make_admin.failure", { type: "error", messageArgs: { errMsg: errorMessage } });
|
||||
setOpen(false);
|
||||
setUserIdValue("");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@@ -161,8 +160,16 @@ export const MakeAdminBtn = () => {
|
||||
}
|
||||
};
|
||||
|
||||
return (<>
|
||||
<Button size="small" onClick={(e) => { e.stopPropagation(); setOpen(true); }} disabled={isPending}>
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
setOpen(true);
|
||||
}}
|
||||
disabled={isPending}
|
||||
>
|
||||
<PersonIcon /> {translate("resources.rooms.action.make_admin.assign_admin")}
|
||||
</Button>
|
||||
<Confirm
|
||||
@@ -171,20 +178,27 @@ export const MakeAdminBtn = () => {
|
||||
onClose={handleDialogClose}
|
||||
confirm="resources.rooms.action.make_admin.confirm"
|
||||
cancel="ra.action.cancel"
|
||||
title={translate("resources.rooms.action.make_admin.title", { roomName: record.name ? record.name : record.room_id })}
|
||||
content={<>
|
||||
<Typography sx={{ marginBottom: 2, whiteSpace: "pre-line"}}>{translate("resources.rooms.action.make_admin.content")}</Typography>
|
||||
<TextField
|
||||
type="text"
|
||||
variant="filled"
|
||||
value={userIdValue}
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
label={"Matrix ID"}
|
||||
/>
|
||||
</>}
|
||||
title={translate("resources.rooms.action.make_admin.title", {
|
||||
roomName: record.name ? record.name : record.room_id,
|
||||
})}
|
||||
content={
|
||||
<>
|
||||
<Typography sx={{ marginBottom: 2, whiteSpace: "pre-line" }}>
|
||||
{translate("resources.rooms.action.make_admin.content")}
|
||||
</Typography>
|
||||
<TextField
|
||||
type="text"
|
||||
variant="filled"
|
||||
value={userIdValue}
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
label={"Matrix ID"}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</>);
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const RoomShow = (props: ShowProps) => {
|
||||
@@ -194,11 +208,7 @@ export const RoomShow = (props: ShowProps) => {
|
||||
<Show {...props} actions={<RoomShowActions />} title={<RoomTitle />}>
|
||||
<TabbedShowLayout>
|
||||
<Tab label="synapseadmin.rooms.tabs.basic" icon={<ViewListIcon />}>
|
||||
<AvatarField
|
||||
source="avatar"
|
||||
sx={{ height: "120px", width: "120px" }}
|
||||
label="resources.rooms.fields.avatar"
|
||||
/>
|
||||
<AvatarField source="avatar" sx={{ height: "120px", width: "120px" }} label="resources.rooms.fields.avatar" />
|
||||
<RaTextField source="room_id" />
|
||||
<RaTextField source="name" />
|
||||
<RaTextField source="topic" />
|
||||
@@ -301,7 +311,11 @@ export const RoomShow = (props: ShowProps) => {
|
||||
<Datagrid sx={{ width: "100%" }} bulkActionButtons={false}>
|
||||
<RaTextField source="type" sortable={false} />
|
||||
<DateField source="origin_server_ts" showTime options={DATE_FORMAT} sortable={false} />
|
||||
<FunctionField source="content" sortable={false} render={record => `${JSON.stringify(record.content, null, 2)}`} />
|
||||
<FunctionField
|
||||
source="content"
|
||||
sortable={false}
|
||||
render={record => `${JSON.stringify(record.content, null, 2)}`}
|
||||
/>
|
||||
<ReferenceField source="sender" reference="users" sortable={false}>
|
||||
<RaTextField source="id" />
|
||||
</ReferenceField>
|
||||
@@ -373,7 +387,13 @@ export const RoomList = (props: ListProps) => {
|
||||
bulkActionButtons={<RoomBulkActionButtons />}
|
||||
omit={["joined_local_members", "state_events", "version", "federatable"]}
|
||||
>
|
||||
<ReferenceField reference="rooms" source="id" label="resources.users.fields.avatar" link={false} sortable={false}>
|
||||
<ReferenceField
|
||||
reference="rooms"
|
||||
source="id"
|
||||
label="resources.users.fields.avatar"
|
||||
link={false}
|
||||
sortable={false}
|
||||
>
|
||||
<AvatarField source="avatar" sx={{ height: "40px", width: "40px" }} />
|
||||
</ReferenceField>
|
||||
<RaTextField source="id" label="resources.rooms.fields.room_id" sortable={false} />
|
||||
@@ -390,7 +410,11 @@ export const RoomList = (props: ListProps) => {
|
||||
}}
|
||||
/>
|
||||
</WrapperField>
|
||||
<FunctionField source="name" render={record => record["name"] || record["canonical_alias"] || record["id"]} label="resources.rooms.fields.name" />
|
||||
<FunctionField
|
||||
source="name"
|
||||
render={record => record["name"] || record["canonical_alias"] || record["id"]}
|
||||
label="resources.rooms.fields.name"
|
||||
/>
|
||||
<RaTextField source="joined_members" label="resources.rooms.fields.joined_members" />
|
||||
<RaTextField source="joined_local_members" label="resources.rooms.fields.joined_local_members" />
|
||||
<RaTextField source="state_events" label="resources.rooms.fields.state_events" />
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import AssignmentIndIcon from "@mui/icons-material/AssignmentInd";
|
||||
import ContactMailIcon from "@mui/icons-material/ContactMail";
|
||||
import DevicesIcon from "@mui/icons-material/Devices";
|
||||
import DocumentScannerIcon from "@mui/icons-material/DocumentScanner";
|
||||
import GetAppIcon from "@mui/icons-material/GetApp";
|
||||
import UserIcon from "@mui/icons-material/Group";
|
||||
import LockClockIcon from "@mui/icons-material/LockClock";
|
||||
import NotificationsIcon from "@mui/icons-material/Notifications";
|
||||
import PermMediaIcon from "@mui/icons-material/PermMedia";
|
||||
import PersonPinIcon from "@mui/icons-material/PersonPin";
|
||||
import SettingsInputComponentIcon from "@mui/icons-material/SettingsInputComponent";
|
||||
import ScienceIcon from "@mui/icons-material/Science";
|
||||
import LockClockIcon from '@mui/icons-material/LockClock';
|
||||
import SettingsInputComponentIcon from "@mui/icons-material/SettingsInputComponent";
|
||||
import ViewListIcon from "@mui/icons-material/ViewList";
|
||||
import DocumentScannerIcon from "@mui/icons-material/DocumentScanner";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Alert, Typography } from "@mui/material";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
ArrayInput,
|
||||
ArrayField,
|
||||
@@ -67,23 +67,23 @@ import {
|
||||
useCreate,
|
||||
useRedirect,
|
||||
} from "react-admin";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import { MakeAdminBtn } from "./rooms";
|
||||
import AvatarField from "../components/AvatarField";
|
||||
import DeleteUserButton from "../components/DeleteUserButton";
|
||||
import { isASManaged } from "../utils/mxid";
|
||||
import { ServerNoticeButton, ServerNoticeBulkButton } from "../components/ServerNotices";
|
||||
import { DATE_FORMAT } from "../utils/date";
|
||||
import DeviceRemoveButton from "../components/DeviceRemoveButton";
|
||||
import { MediaIDField, ProtectMediaButton, QuarantineMediaButton } from "../components/media";
|
||||
import { generateRandomPassword } from "../utils/password";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import ExperimentalFeaturesList from "../components/ExperimentalFeatures";
|
||||
import UserRateLimits from "../components/UserRateLimits";
|
||||
import { User, UsernameAvailabilityResult } from "../synapse/dataProvider";
|
||||
import { MakeAdminBtn } from "./rooms";
|
||||
import { ServerNoticeButton, ServerNoticeBulkButton } from "../components/ServerNotices";
|
||||
import UserAccountData from "../components/UserAccountData";
|
||||
import UserRateLimits from "../components/UserRateLimits";
|
||||
import { MediaIDField, ProtectMediaButton, QuarantineMediaButton } from "../components/media";
|
||||
import { User, UsernameAvailabilityResult } from "../synapse/dataProvider";
|
||||
import { DATE_FORMAT } from "../utils/date";
|
||||
import decodeURLComponent from "../utils/decodeURLComponent";
|
||||
import { isASManaged } from "../utils/mxid";
|
||||
import { generateRandomPassword } from "../utils/password";
|
||||
|
||||
const choices_medium = [
|
||||
{ id: "email", name: "resources.users.email" },
|
||||
@@ -118,7 +118,11 @@ const userFilters = [
|
||||
<BooleanInput label="resources.users.fields.show_suspended" source="suspended" alwaysOn />,
|
||||
];
|
||||
|
||||
const UserPreventSelfDelete: React.FC<{ children: React.ReactNode; ownUserIsSelected: boolean; asManagedUserIsSelected: boolean }> = props => {
|
||||
const UserPreventSelfDelete: React.FC<{
|
||||
children: React.ReactNode;
|
||||
ownUserIsSelected: boolean;
|
||||
asManagedUserIsSelected: boolean;
|
||||
}> = props => {
|
||||
const ownUserIsSelected = props.ownUserIsSelected;
|
||||
const asManagedUserIsSelected = props.asManagedUserIsSelected;
|
||||
const notify = useNotify();
|
||||
@@ -177,7 +181,12 @@ export const UserList = (props: ListProps) => (
|
||||
rowClick={(id: Identifier, resource: string) => `/${resource}/${id}`}
|
||||
bulkActionButtons={<UserBulkActionButtons />}
|
||||
>
|
||||
<AvatarField source="avatar_src" sx={{ height: "40px", width: "40px" }} sortBy="avatar_url" label="resources.users.fields.avatar" />
|
||||
<AvatarField
|
||||
source="avatar_src"
|
||||
sx={{ height: "40px", width: "40px" }}
|
||||
sortBy="avatar_url"
|
||||
label="resources.users.fields.avatar"
|
||||
/>
|
||||
<TextField source="id" sortBy="name" label="resources.users.fields.id" />
|
||||
<TextField source="displayname" label="resources.users.fields.displayname" />
|
||||
<BooleanField source="is_guest" label="resources.users.fields.is_guest" />
|
||||
@@ -214,13 +223,13 @@ const UserEditActions = () => {
|
||||
<TopToolbar>
|
||||
{!record?.deactivated && <ServerNoticeButton />}
|
||||
{record && record.id && (
|
||||
<UserPreventSelfDelete ownUserIsSelected={ownUserIsSelected} asManagedUserIsSelected={asManagedUserIsSelected}>
|
||||
<DeleteUserButton
|
||||
selectedIds={[record?.id]}
|
||||
confirmTitle="resources.users.helper.erase"
|
||||
confirmContent="resources.users.helper.erase_text"
|
||||
/>
|
||||
</UserPreventSelfDelete>
|
||||
<UserPreventSelfDelete ownUserIsSelected={ownUserIsSelected} asManagedUserIsSelected={asManagedUserIsSelected}>
|
||||
<DeleteUserButton
|
||||
selectedIds={[record?.id]}
|
||||
confirmTitle="resources.users.helper.erase"
|
||||
confirmContent="resources.users.helper.erase_text"
|
||||
/>
|
||||
</UserPreventSelfDelete>
|
||||
)}
|
||||
</TopToolbar>
|
||||
);
|
||||
@@ -235,18 +244,28 @@ export const UserCreate = (props: CreateProps) => {
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [userIsAvailable, setUserIsAvailable] = useState<boolean | undefined>();
|
||||
const [userAvailabilityEl, setUserAvailabilityEl] = useState<React.ReactElement | false>(<Typography component="span"></Typography>);
|
||||
const [userAvailabilityEl, setUserAvailabilityEl] = useState<React.ReactElement | false>(
|
||||
<Typography component="span"></Typography>
|
||||
);
|
||||
const [formData, setFormData] = useState<Record<string, any>>({});
|
||||
const [create] = useCreate();
|
||||
|
||||
const checkAvailability = async(event: React.FocusEvent<HTMLInputElement>) => {
|
||||
const checkAvailability = async (event: React.FocusEvent<HTMLInputElement>) => {
|
||||
const username = event.target.value;
|
||||
const result: UsernameAvailabilityResult = await dataProvider.checkUsernameAvailability(username);
|
||||
setUserIsAvailable(!!result?.available);
|
||||
if (result?.available) {
|
||||
setUserAvailabilityEl(<Typography component="span" variant="body2" sx={{ color: theme.palette.success.main }}>✔️ {translate("resources.users.helper.username_available")}</Typography>);
|
||||
setUserAvailabilityEl(
|
||||
<Typography component="span" variant="body2" sx={{ color: theme.palette.success.main }}>
|
||||
✔️ {translate("resources.users.helper.username_available")}
|
||||
</Typography>
|
||||
);
|
||||
} else {
|
||||
setUserAvailabilityEl(<Typography component="span" variant="body2" sx={{ color: theme.palette.warning.main }}>⚠️ {result?.error || "unknown error"}</Typography>);
|
||||
setUserAvailabilityEl(
|
||||
<Typography component="span" variant="body2" sx={{ color: theme.palette.warning.main }}>
|
||||
⚠️ {result?.error || "unknown error"}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -257,12 +276,18 @@ export const UserCreate = (props: CreateProps) => {
|
||||
return;
|
||||
}
|
||||
|
||||
create("users", { data: data }, {
|
||||
onSuccess: (resource: User) => {
|
||||
notify("ra.notification.created", { messageArgs: { smart_count: 1 } });
|
||||
redirect(() => { return `users/${resource.id}` });
|
||||
create(
|
||||
"users",
|
||||
{ data: data },
|
||||
{
|
||||
onSuccess: (resource: User) => {
|
||||
notify("ra.notification.created", { messageArgs: { smart_count: 1 } });
|
||||
redirect(() => {
|
||||
return `users/${resource.id}`;
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
@@ -275,39 +300,48 @@ export const UserCreate = (props: CreateProps) => {
|
||||
};
|
||||
|
||||
const updateUser = () => {
|
||||
create("users", { data: formData }, {
|
||||
onSuccess: (resource: User) => {
|
||||
notify("ra.notification.updated", { messageArgs: { smart_count: 1 } });
|
||||
redirect(() => { return `users/${resource.id}` });
|
||||
create(
|
||||
"users",
|
||||
{ data: formData },
|
||||
{
|
||||
onSuccess: (resource: User) => {
|
||||
notify("ra.notification.updated", { messageArgs: { smart_count: 1 } });
|
||||
redirect(() => {
|
||||
return `users/${resource.id}`;
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return <Create
|
||||
{...props}
|
||||
>
|
||||
<SimpleForm
|
||||
onSubmit={postSave}
|
||||
>
|
||||
<TextInput source="id" autoComplete="off" validate={validateUser} onBlur={checkAvailability} helperText={userAvailabilityEl}/>
|
||||
<TextInput source="displayname" validate={maxLength(256)} />
|
||||
<UserPasswordInput source="password" autoComplete="new-password" helperText="resources.users.helper.password" />
|
||||
<SelectInput source="user_type" choices={choices_type} translateChoice={false} resettable />
|
||||
<BooleanInput source="admin" />
|
||||
<ArrayInput source="threepids">
|
||||
<SimpleFormIterator disableReordering>
|
||||
<SelectInput source="medium" choices={choices_medium} validate={required()} />
|
||||
<TextInput source="address" validate={validateAddress} />
|
||||
</SimpleFormIterator>
|
||||
</ArrayInput>
|
||||
<ArrayInput source="external_ids" label="synapseadmin.users.tabs.sso">
|
||||
<SimpleFormIterator disableReordering>
|
||||
<TextInput source="auth_provider" validate={required()} />
|
||||
<TextInput source="external_id" label="resources.users.fields.id" validate={required()} />
|
||||
</SimpleFormIterator>
|
||||
</ArrayInput>
|
||||
</SimpleForm>
|
||||
<Confirm
|
||||
return (
|
||||
<Create {...props}>
|
||||
<SimpleForm onSubmit={postSave}>
|
||||
<TextInput
|
||||
source="id"
|
||||
autoComplete="off"
|
||||
validate={validateUser}
|
||||
onBlur={checkAvailability}
|
||||
helperText={userAvailabilityEl}
|
||||
/>
|
||||
<TextInput source="displayname" validate={maxLength(256)} />
|
||||
<UserPasswordInput source="password" autoComplete="new-password" helperText="resources.users.helper.password" />
|
||||
<SelectInput source="user_type" choices={choices_type} translateChoice={false} resettable />
|
||||
<BooleanInput source="admin" />
|
||||
<ArrayInput source="threepids">
|
||||
<SimpleFormIterator disableReordering>
|
||||
<SelectInput source="medium" choices={choices_medium} validate={required()} />
|
||||
<TextInput source="address" validate={validateAddress} />
|
||||
</SimpleFormIterator>
|
||||
</ArrayInput>
|
||||
<ArrayInput source="external_ids" label="synapseadmin.users.tabs.sso">
|
||||
<SimpleFormIterator disableReordering>
|
||||
<TextInput source="auth_provider" validate={required()} />
|
||||
<TextInput source="external_id" label="resources.users.fields.id" validate={required()} />
|
||||
</SimpleFormIterator>
|
||||
</ArrayInput>
|
||||
</SimpleForm>
|
||||
<Confirm
|
||||
isOpen={open}
|
||||
title="resources.users.action.overwrite_title"
|
||||
content="resources.users.action.overwrite_content"
|
||||
@@ -316,7 +350,8 @@ export const UserCreate = (props: CreateProps) => {
|
||||
confirm="resources.users.action.overwrite_confirm"
|
||||
cancel="resources.users.action.overwrite_cancel"
|
||||
/>
|
||||
</Create>
|
||||
</Create>
|
||||
);
|
||||
};
|
||||
|
||||
const UserTitle = () => {
|
||||
@@ -326,7 +361,7 @@ const UserTitle = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
let username = record ? (record.displayname ? `"${record.displayname}"` : `"${record.name}"`) : ""
|
||||
const username = record ? (record.displayname ? `"${record.displayname}"` : `"${record.name}"`) : "";
|
||||
return (
|
||||
<span>
|
||||
{translate("resources.users.name", {
|
||||
@@ -352,7 +387,10 @@ const UserEditToolbar = () => {
|
||||
<div className={ToolbarClasses.defaultToolbar}>
|
||||
<Toolbar sx={{ justifyContent: "space-between" }}>
|
||||
<SaveButton />
|
||||
<UserPreventSelfDelete ownUserIsSelected={ownUserIsSelected} asManagedUserIsSelected={asManagedUserIsSelected}>
|
||||
<UserPreventSelfDelete
|
||||
ownUserIsSelected={ownUserIsSelected}
|
||||
asManagedUserIsSelected={asManagedUserIsSelected}
|
||||
>
|
||||
<DeleteButton />
|
||||
</UserPreventSelfDelete>
|
||||
</Toolbar>
|
||||
@@ -395,8 +433,18 @@ const UserPasswordInput = props => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<PasswordInput {...props} helperText={asManagedUserIsSelected ? "resources.users.helper.modify_managed_user_error" : (record ? "resources.users.helper.password" : "resources.users.helper.create_password")} disabled={asManagedUserIsSelected} />
|
||||
<Button
|
||||
<PasswordInput
|
||||
{...props}
|
||||
helperText={
|
||||
asManagedUserIsSelected
|
||||
? "resources.users.helper.modify_managed_user_error"
|
||||
: record
|
||||
? "resources.users.helper.password"
|
||||
: "resources.users.helper.create_password"
|
||||
}
|
||||
disabled={asManagedUserIsSelected}
|
||||
/>
|
||||
<Button
|
||||
variant="outlined"
|
||||
label="resources.users.action.generate_password"
|
||||
onClick={generatePassword}
|
||||
@@ -411,11 +459,17 @@ export const UserEdit = (props: EditProps) => {
|
||||
const translate = useTranslate();
|
||||
|
||||
return (
|
||||
<Edit {...props} title={<UserTitle />} actions={<UserEditActions />} mutationMode="pessimistic" queryOptions={{
|
||||
meta: {
|
||||
include: ["features"] // Tell your dataProvider to include features
|
||||
}
|
||||
}}>
|
||||
<Edit
|
||||
{...props}
|
||||
title={<UserTitle />}
|
||||
actions={<UserEditActions />}
|
||||
mutationMode="pessimistic"
|
||||
queryOptions={{
|
||||
meta: {
|
||||
include: ["features"], // Tell your dataProvider to include features
|
||||
},
|
||||
}}
|
||||
>
|
||||
<TabbedForm toolbar={<UserEditToolbar />}>
|
||||
<FormTab label={translate("resources.users.name", { smart_count: 1 })} icon={<PersonPinIcon />}>
|
||||
<AvatarField source="avatar_src" sx={{ height: "120px", width: "120px" }} />
|
||||
@@ -425,16 +479,26 @@ export const UserEdit = (props: EditProps) => {
|
||||
label="resources.users.fields.avatar"
|
||||
accept={{ "image/*": [".png", ".jpg"] }}
|
||||
>
|
||||
<ImageField source="src" title="Avatar" sx={{ '& img': {
|
||||
width: "120px !important",
|
||||
height: "120px !important",
|
||||
objectFit: "cover !important",
|
||||
borderRadius: '50% !important',
|
||||
}}} />
|
||||
<ImageField
|
||||
source="src"
|
||||
title="Avatar"
|
||||
sx={{
|
||||
"& img": {
|
||||
width: "120px !important",
|
||||
height: "120px !important",
|
||||
objectFit: "cover !important",
|
||||
borderRadius: "50% !important",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</ImageInput>
|
||||
<TextInput source="id" readOnly />
|
||||
<TextInput source="displayname" />
|
||||
<UserPasswordInput source="password" autoComplete="new-password" helperText="resources.users.helper.password" />
|
||||
<UserPasswordInput
|
||||
source="password"
|
||||
autoComplete="new-password"
|
||||
helperText="resources.users.helper.password"
|
||||
/>
|
||||
<SelectInput source="user_type" choices={choices_type} translateChoice={false} resettable />
|
||||
<BooleanInput source="admin" />
|
||||
<UserBooleanInput source="locked" />
|
||||
@@ -500,13 +564,16 @@ export const UserEdit = (props: EditProps) => {
|
||||
perPage={10}
|
||||
sort={{ field: "created_ts", order: "DESC" }}
|
||||
>
|
||||
<Datagrid sx={{ width: "100%" }} bulkActionButtons={<BulkDeleteButton/>}>
|
||||
<Datagrid sx={{ width: "100%" }} bulkActionButtons={<BulkDeleteButton />}>
|
||||
<MediaIDField source="media_id" />
|
||||
<DateField source="created_ts" showTime options={DATE_FORMAT} />
|
||||
<DateField source="last_access_ts" showTime options={DATE_FORMAT} />
|
||||
<NumberField source="media_length" />
|
||||
<TextField source="media_type" sx={{ display: "block", width: 200, wordBreak: "break-word" }} />
|
||||
<FunctionField source="upload_name" render={record => record.upload_name ? decodeURLComponent(record.upload_name) : ""} />
|
||||
<FunctionField
|
||||
source="upload_name"
|
||||
render={record => (record.upload_name ? decodeURLComponent(record.upload_name) : "")}
|
||||
/>
|
||||
<TextField source="quarantined_by" />
|
||||
<QuarantineMediaButton label="resources.quarantine_media.action.name" />
|
||||
<ProtectMediaButton label="resources.users_media.fields.safe_from_quarantine" />
|
||||
@@ -516,22 +583,40 @@ export const UserEdit = (props: EditProps) => {
|
||||
</FormTab>
|
||||
|
||||
<FormTab label={translate("resources.rooms.name", { smart_count: 2 })} icon={<ViewListIcon />} path="rooms">
|
||||
<ReferenceManyField reference="joined_rooms" target="user_id" label={false} perPage={10} pagination={<Pagination />}>
|
||||
<Datagrid sx={{ width: "100%" }} rowClick={id => "/rooms/" + id + "/show"} bulkActionButtons={false}>
|
||||
<ReferenceField reference="rooms" source="id" label={false} link={false} sortable={false}>
|
||||
<AvatarField source="avatar" sx={{ height: "40px", width: "40px" }} />
|
||||
</ReferenceField>
|
||||
<TextField source="id" label="resources.rooms.fields.room_id" sortable={false}/>
|
||||
<ReferenceField reference="rooms" source="id" label="resources.rooms.fields.name" link={false} sortable={false}>
|
||||
<TextField source="name" />
|
||||
</ReferenceField>
|
||||
<ReferenceField reference="rooms" source="id" label="resources.rooms.fields.joined_members" link={false} sortable={false}>
|
||||
<TextField source="joined_members" sortable={false} />
|
||||
</ReferenceField>
|
||||
<ReferenceField reference="rooms" source="id" label={false} link={false} sortable={false}>
|
||||
<MakeAdminBtn />
|
||||
</ReferenceField>
|
||||
</Datagrid>
|
||||
<ReferenceManyField
|
||||
reference="joined_rooms"
|
||||
target="user_id"
|
||||
label={false}
|
||||
perPage={10}
|
||||
pagination={<Pagination />}
|
||||
>
|
||||
<Datagrid sx={{ width: "100%" }} rowClick={id => "/rooms/" + id + "/show"} bulkActionButtons={false}>
|
||||
<ReferenceField reference="rooms" source="id" label={false} link={false} sortable={false}>
|
||||
<AvatarField source="avatar" sx={{ height: "40px", width: "40px" }} />
|
||||
</ReferenceField>
|
||||
<TextField source="id" label="resources.rooms.fields.room_id" sortable={false} />
|
||||
<ReferenceField
|
||||
reference="rooms"
|
||||
source="id"
|
||||
label="resources.rooms.fields.name"
|
||||
link={false}
|
||||
sortable={false}
|
||||
>
|
||||
<TextField source="name" />
|
||||
</ReferenceField>
|
||||
<ReferenceField
|
||||
reference="rooms"
|
||||
source="id"
|
||||
label="resources.rooms.fields.joined_members"
|
||||
link={false}
|
||||
sortable={false}
|
||||
>
|
||||
<TextField source="joined_members" sortable={false} />
|
||||
</ReferenceField>
|
||||
<ReferenceField reference="rooms" source="id" label={false} link={false} sortable={false}>
|
||||
<MakeAdminBtn />
|
||||
</ReferenceField>
|
||||
</Datagrid>
|
||||
</ReferenceManyField>
|
||||
</FormTab>
|
||||
|
||||
@@ -563,7 +648,7 @@ export const UserEdit = (props: EditProps) => {
|
||||
</FormTab>
|
||||
|
||||
<FormTab label="synapseadmin.users.tabs.account_data" icon={<DocumentScannerIcon />} path="accountdata">
|
||||
<UserAccountData />
|
||||
<UserAccountData />
|
||||
</FormTab>
|
||||
</TabbedForm>
|
||||
</Edit>
|
||||
|
||||
Reference in New Issue
Block a user