import AssignmentIndIcon from "@mui/icons-material/AssignmentInd"; import ContactMailIcon from "@mui/icons-material/ContactMail"; import DevicesIcon from "@mui/icons-material/Devices"; import GetAppIcon from "@mui/icons-material/GetApp"; import UserIcon from "@mui/icons-material/Group"; 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 ViewListIcon from "@mui/icons-material/ViewList"; import { useEffect, useState } from "react"; import { Alert, Typography } from "@mui/material"; import { useTheme } from "@mui/material/styles"; import { ArrayInput, ArrayField, Button, Datagrid, DatagridConfigurable, DateField, Create, CreateProps, Edit, EditProps, List, ListProps, SimpleForm, SimpleFormIterator, TabbedForm, FormTab, BooleanField, BooleanInput, PasswordInput, TextField, TextInput, ReferenceField, ReferenceManyField, ResourceProps, SearchInput, SelectInput, DeleteButton, maxLength, regex, required, useRecordContext, useTranslate, Pagination, SaveButton, CreateButton, ExportButton, TopToolbar, Toolbar, NumberField, useListContext, useNotify, Identifier, ToolbarClasses, ImageInput, ImageField, FunctionField, useDataProvider, Confirm, useCreate, useRedirect, } from "react-admin"; import { Link } from "react-router-dom"; 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"; const choices_medium = [ { id: "email", name: "resources.users.email" }, { id: "msisdn", name: "resources.users.msisdn" }, ]; const choices_type = [ { id: "bot", name: "bot" }, { id: "support", name: "support" }, ]; const UserListActions = () => { const { isLoading, total } = useListContext(); return ( ); }; const UserPagination = () => ; const userFilters = [ , , , , ]; const UserPreventSelfDelete: React.FC<{ children: React.ReactNode; ownUserIsSelected: boolean; asManagedUserIsSelected: boolean }> = props => { const ownUserIsSelected = props.ownUserIsSelected; const asManagedUserIsSelected = props.asManagedUserIsSelected; const notify = useNotify(); const translate = useTranslate(); const handleDeleteClick = (ev: React.MouseEvent) => { if (ownUserIsSelected) { notify({translate("resources.users.helper.erase_admin_error")}); ev.stopPropagation(); } else if (asManagedUserIsSelected) { notify({translate("resources.users.helper.modify_managed_user_error")}); ev.stopPropagation(); } }; return
{props.children}
; }; const UserBulkActionButtons = () => { const record = useListContext(); const [ownUserIsSelected, setOwnUserIsSelected] = useState(false); const [asManagedUserIsSelected, setAsManagedUserIsSelected] = useState(false); const selectedIds = record.selectedIds; const ownUserId = localStorage.getItem("user_id"); useEffect(() => { setOwnUserIsSelected(selectedIds.includes(ownUserId)); setAsManagedUserIsSelected(selectedIds.some(id => isASManaged(id))); }, [selectedIds]); return ( <> ); }; export const UserList = (props: ListProps) => ( } pagination={} > `/${resource}/${id}`} bulkActionButtons={} > ); // https://matrix.org/docs/spec/appendices#user-identifiers // here only local part of user_id // maxLength = 255 - "@" - ":" - storage.getItem("home_server").length // storage.getItem("home_server").length is not valid here const validateUser = [required(), maxLength(253), regex(/^[a-z0-9._=\-/]+$/, "synapseadmin.users.invalid_user_id")]; const validateAddress = [required(), maxLength(255)]; const UserEditActions = () => { const record = useRecordContext(); const translate = useTranslate(); const ownUserId = localStorage.getItem("user_id"); let ownUserIsSelected = false; let asManagedUserIsSelected = false; if (record && record.id) { ownUserIsSelected = record.id === ownUserId; asManagedUserIsSelected = isASManaged(record.id); } return ( {!record?.deactivated && } {record && record.id && ( )} ); }; export const UserCreate = (props: CreateProps) => { const dataProvider = useDataProvider(); const translate = useTranslate(); const redirect = useRedirect(); const notify = useNotify(); const theme = useTheme(); const [open, setOpen] = useState(false); const [userIsAvailable, setUserIsAvailable] = useState(); const [userAvailabilityEl, setUserAvailabilityEl] = useState(); const [formData, setFormData] = useState>({}); const [create] = useCreate(); const checkAvailability = async(event: React.FocusEvent) => { const username = event.target.value; const result: UsernameAvailabilityResult = await dataProvider.checkUsernameAvailability(username); setUserIsAvailable(!!result?.available); if (result?.available) { setUserAvailabilityEl(✔️ {translate("resources.users.helper.username_available")}); } else { setUserAvailabilityEl(⚠️ {result?.error || "unknown error"}); } }; const postSave = (data: Record) => { setFormData(data); if (!userIsAvailable) { setOpen(true); return; } create("users", { data: data }, { onSuccess: (resource: User) => { notify("ra.notification.created", { messageArgs: { smart_count: 1 } }); redirect(() => { return `users/${resource.id}` }); } }); }; const handleConfirm = () => { setOpen(false); updateUser(); }; const handleDialogClose = () => { setOpen(false); }; const updateUser = () => { create("users", { data: formData }, { onSuccess: (resource: User) => { notify("ra.notification.updated", { messageArgs: { smart_count: 1 } }); redirect(() => { return `users/${resource.id}` }); } }); } return }; const UserTitle = () => { const record = useRecordContext(); const translate = useTranslate(); if (!record) { return null; } let username = record ? (record.displayname ? `"${record.displayname}"` : `"${record.name}"`) : "" return ( {translate("resources.users.name", { smart_count: 1, })}{" "} {username} ); }; const UserEditToolbar = () => { const record = useRecordContext(); const ownUserId = localStorage.getItem("user_id"); let ownUserIsSelected = false; let asManagedUserIsSelected = false; if (record && record.id) { ownUserIsSelected = record.id === ownUserId; asManagedUserIsSelected = isASManaged(record.id); } return ( <>
); }; const UserBooleanInput = props => { const record = useRecordContext(); const ownUserId = localStorage.getItem("user_id"); let ownUserIsSelected = false; let asManagedUserIsSelected = false; if (record) { ownUserIsSelected = record.id === ownUserId; asManagedUserIsSelected = isASManaged(record.id); } return ( ); }; const UserPasswordInput = props => { const record = useRecordContext(); let asManagedUserIsSelected = false; // Get form context to update field value const form = useFormContext(); if (record) { asManagedUserIsSelected = isASManaged(record.id); } const generatePassword = () => { const password = generateRandomPassword(); form.setValue("password", password, { shouldDirty: true }); }; return ( <>