Add devices tab to UserEdit component

Allows to view user devices.
API was added by synapse v1.15.0.

Change-Id: Id0693bf6cd6f6182c657412cf8036537e2db9df7
This commit is contained in:
Manuel Stahl 2020-07-08 10:58:57 +02:00
parent 12447b7708
commit 352ab1290a
6 changed files with 67 additions and 17 deletions

View file

@ -4,7 +4,7 @@
This project is built using [react-admin](https://marmelab.com/react-admin/). This project is built using [react-admin](https://marmelab.com/react-admin/).
It needs at least Synapse v1.14.0 for all functions to work as expected! It needs at least Synapse v1.15.0 for all functions to work as expected!
## Step-By-Step install: ## Step-By-Step install:

View file

@ -37,6 +37,7 @@ const App = () => (
/> />
<Resource name="rooms" list={RoomList} show={RoomShow} icon={RoomIcon} /> <Resource name="rooms" list={RoomList} show={RoomShow} icon={RoomIcon} />
<Resource name="connections" /> <Resource name="connections" />
<Resource name="devices" />
<Resource name="servernotices" /> <Resource name="servernotices" />
</Admin> </Admin>
); );

View file

@ -2,6 +2,7 @@ import React, { cloneElement, Fragment } from "react";
import Avatar from "@material-ui/core/Avatar"; import Avatar from "@material-ui/core/Avatar";
import PersonPinIcon from "@material-ui/icons/PersonPin"; import PersonPinIcon from "@material-ui/icons/PersonPin";
import ContactMailIcon from "@material-ui/icons/ContactMail"; import ContactMailIcon from "@material-ui/icons/ContactMail";
import DevicesIcon from "@material-ui/icons/Devices";
import SettingsInputComponentIcon from "@material-ui/icons/SettingsInputComponent"; import SettingsInputComponentIcon from "@material-ui/icons/SettingsInputComponent";
import { import {
ArrayInput, ArrayInput,
@ -23,6 +24,7 @@ import {
TextField, TextField,
TextInput, TextInput,
ReferenceField, ReferenceField,
ReferenceManyField,
SelectInput, SelectInput,
BulkDeleteButton, BulkDeleteButton,
DeleteButton, DeleteButton,
@ -205,6 +207,7 @@ const UserTitle = ({ record }) => {
}; };
export const UserEdit = props => { export const UserEdit = props => {
const classes = useStyles(); const classes = useStyles();
const translate = useTranslate();
return ( return (
<Edit {...props} title={<UserTitle />}> <Edit {...props} title={<UserTitle />}>
<TabbedForm toolbar={<UserEditToolbar />}> <TabbedForm toolbar={<UserEditToolbar />}>
@ -254,6 +257,36 @@ export const UserEdit = props => {
</SimpleFormIterator> </SimpleFormIterator>
</ArrayInput> </ArrayInput>
</FormTab> </FormTab>
<FormTab
label={translate("resources.devices.name", { smart_count: 2 })}
icon={<DevicesIcon />}
path="devices"
>
<ReferenceManyField
reference="devices"
target="user_id"
addLabel={false}
>
<Datagrid style={{ width: "100%" }}>
<TextField source="device_id" sortable={false} />
<TextField source="display_name" sortable={false} />
<TextField source="last_seen_ip" sortable={false} />
<DateField
source="last_seen_ts"
showTime
options={{
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
}}
sortable={false}
/>
</Datagrid>
</ReferenceManyField>
</FormTab>
<FormTab <FormTab
label="resources.connections.name" label="resources.connections.name"
icon={<SettingsInputComponentIcon />} icon={<SettingsInputComponentIcon />}

View file

@ -107,6 +107,15 @@ export default {
user_agent: "User Agent", user_agent: "User Agent",
}, },
}, },
devices: {
name: "Gerät |||| Geräte",
fields: {
device_id: "Geräte-ID",
display_name: "Anzeigename",
last_seen_ts: "Zeitstempel",
last_seen_ip: "IP-Adresse",
},
},
servernotices: { servernotices: {
name: "Serverbenachrichtigungen", name: "Serverbenachrichtigungen",
send: "Servernachricht versenden", send: "Servernachricht versenden",

View file

@ -105,6 +105,15 @@ export default {
user_agent: "User agent", user_agent: "User agent",
}, },
}, },
devices: {
name: "Device |||| Devices",
fields: {
device_id: "Device-ID",
display_name: "Displayname",
last_seen_ts: "Timestamp",
last_seen_ip: "IP address",
},
},
servernotices: { servernotices: {
name: "Server Notices", name: "Server Notices",
send: "Send server notices", send: "Send server notices",

View file

@ -67,6 +67,16 @@ const resourceMap = {
return json.total_rooms; return json.total_rooms;
}, },
}, },
devices: {
map: d => ({
...d,
id: d.device_id,
}),
data: "devices",
reference: id => ({
endpoint: `/_synapse/admin/v2/users/${id}/devices`,
}),
},
connections: { connections: {
path: "/_synapse/admin/v1/whois", path: "/_synapse/admin/v1/whois",
map: c => ({ map: c => ({
@ -166,30 +176,18 @@ const dataProvider = {
}, },
getManyReference: (resource, params) => { getManyReference: (resource, params) => {
// FIXME
console.log("getManyReference " + resource); console.log("getManyReference " + resource);
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: JSON.stringify([field, order]),
range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
filter: JSON.stringify({
...params.filter,
[params.target]: params.id,
}),
};
const homeserver = localStorage.getItem("base_url"); const homeserver = localStorage.getItem("base_url");
if (!homeserver || !(resource in resourceMap)) return Promise.reject(); if (!homeserver || !(resource in resourceMap)) return Promise.reject();
const res = resourceMap[resource]; const res = resourceMap[resource];
const endpoint_url = homeserver + res.path; const ref = res["reference"](params.id);
const url = `${endpoint_url}?${stringify(query)}`; const endpoint_url = homeserver + ref.endpoint;
return jsonClient(url).then(({ headers, json }) => ({ return jsonClient(endpoint_url).then(({ headers, json }) => ({
data: json, data: json[res.data].map(res.map),
total: parseInt(headers.get("content-range").split("/").pop(), 10),
})); }));
}, },