import React, { Fragment } from "react"; import { connect } from "react-redux"; import { Route, Link } from "react-router-dom"; import { AutocompleteArrayInput, AutocompleteInput, BooleanInput, BooleanField, BulkDeleteWithConfirmButton, Button, Create, Edit, Datagrid, DeleteButton, Filter, FormTab, List, Pagination, ReferenceArrayInput, ReferenceField, ReferenceInput, ReferenceManyField, SearchInput, SelectField, Show, SimpleForm, Tab, TabbedForm, TabbedShowLayout, TextField, TextInput, Toolbar, TopToolbar, useDataProvider, useRefresh, useTranslate, } from "react-admin"; import get from "lodash/get"; import { Tooltip, Typography, Chip, Drawer, styled, withStyles, Select, MenuItem, } from "@material-ui/core"; import HttpsIcon from "@material-ui/icons/Https"; import NoEncryptionIcon from "@material-ui/icons/NoEncryption"; import PageviewIcon from "@material-ui/icons/Pageview"; import UserIcon from "@material-ui/icons/Group"; import ViewListIcon from "@material-ui/icons/ViewList"; import VisibilityIcon from "@material-ui/icons/Visibility"; import ContentSave from "@material-ui/icons/Save"; const RoomPagination = props => ( ); const EncryptionField = ({ source, record = {}, emptyText }) => { const translate = useTranslate(); const value = get(record, source); let ariaLabel = value === false ? "ra.boolean.false" : "ra.boolean.true"; if (value === false || value === true) { return ( {value === true ? ( ) : ( )} ); } return ( {emptyText} ); }; const validateDisplayName = fieldval => { return fieldval == null ? "synapseadmin.rooms.room_name_required" : fieldval.length === 0 ? "synapseadmin.rooms.room_name_required" : undefined; }; function approximateAliasLength(alias, homeserver) { /* TODO maybe handle punycode in homeserver name */ var te; // Support for TextEncoder is quite widespread, but the polyfill is // pretty large; We will only underestimate the size with the regular // length attribute of String, so we never prevent the user from using // an alias that is short enough for the server, but too long for our // heuristic. try { te = new TextEncoder(); } catch (err) { if (err instanceof ReferenceError) { te = undefined; } } const aliasLength = te === undefined ? alias.length : te.encode(alias).length; return "#".length + aliasLength + ":".length + homeserver.length; } const validateAlias = fieldval => { if (fieldval === undefined) { return undefined; } const homeserver = localStorage.getItem("home_server"); if (approximateAliasLength(fieldval, homeserver) > 255) { return "synapseadmin.rooms.alias_too_long"; } }; const removeLeadingWhitespace = fieldVal => fieldVal === undefined ? undefined : fieldVal.trimStart(); const replaceAllWhitespace = fieldVal => fieldVal === undefined ? undefined : fieldVal.replace(/\s/, "_"); const removeLeadingSigil = fieldVal => fieldVal === undefined ? undefined : fieldVal.startsWith("#") ? fieldVal.substr(1) : fieldVal; const validateHasAliasIfPublic = formdata => { let errors = {}; if (formdata.public) { if ( formdata.canonical_alias === undefined || formdata.canonical_alias.trim().length === 0 ) { errors.canonical_alias = "synapseadmin.rooms.alias_required_if_public"; } } return errors; }; export const RoomCreate = props => ( }> replaceAllWhitespace(removeLeadingSigil(fv))} validate={validateAlias} placeholder="#" /> ({ user_id: searchText })} > } > ({ user_id: searchText })} > ); const RoomTitle = ({ record }) => { const translate = useTranslate(); return ( {translate("resources.rooms.name", 1)} {record ? `"${record.name}"` : ""} ); }; // Explicitely passing "to" prop // Toolbar adds all kinds of unsupported props to its children :( const StyledLink = styles => { const Styled = styled(Link)(styles); return ({ to, children }) => {children}; }; const RoomMemberEditToolbar = ({ backLink, translate, onSave, ...props }) => { const SaveLink = StyledLink({ textDecoration: "none", }); const CancelLink = StyledLink({ textDecoration: "none", marginLeft: "1em", }); const SaveIcon = styled(ContentSave)({ width: "1rem", marginRight: "0.25em", }); return ( ); }; const RoomMemberIdField = ({ memberId, data = {} }) => { const value = get(data[memberId], "id"); return ( {value} ); }; const RoomMemberRoleInput = ({ memberId, data = {}, translate, onChange }) => { const roleValue = get(data[memberId], "role"); const [role, setRole] = React.useState(roleValue); React.useEffect(() => { onChange(roleValue); }, [onChange, roleValue]); return ( ); }; const RoomMemberEdit = ({ backLink, memberId, ...props }) => { const translate = useTranslate(); const refresh = useRefresh(); const dataProvider = useDataProvider(); const [role, setRole] = React.useState(); const { id } = props; return ( { dataProvider .update("rooms", { data: { id, member_roles: [{ member_id: memberId, role }], }, }) .then(() => { refresh(); }); }} /> } > ); }; const drawerStyles = { paper: { width: 300, }, }; const StyledDrawer = withStyles(drawerStyles)(({ classes, ...props }) => ( )); export const RoomEdit = props => { const translate = useTranslate(); return ( }> }> ({ user_id: searchText })} > `/rooms/${encodeURIComponent( record.parentId )}/${encodeURIComponent(id)}` } > {({ match }) => { const isMatch = !!match && !!match.params; return ( {isMatch ? ( ) : (
)} ); }} ); }; const RoomShowActions = ({ basePath, data, resource }) => { const translate = useTranslate(); return ( ); }; export const RoomShow = props => { const translate = useTranslate(); return ( } title={}> }> } path="detail" > }> "/users/" + id} > } path="permission" > ); }; const RoomBulkActionButtons = props => ( ); const RoomFilter = ({ ...props }) => { const translate = useTranslate(); return ( ); }; const FilterableRoomList = ({ ...props }) => { const filter = props.roomFilters; const localMembersFilter = filter && filter.joined_local_members ? true : false; 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 ( } sort={{ field: "name", order: "ASC" }} filters={} bulkActionButtons={ } > } /> {localMembersFilter && } {stateEventsFilter && } {versionFilter && } {federateableFilter && } ); }; function mapStateToProps(state) { return { roomFilters: state.admin.resources.rooms.list.params.displayedFilters, }; } export const RoomList = connect(mapStateToProps)(FilterableRoomList);