Update eslint for typescript
Change-Id: I39ad44666fe958dd4f6c8f0d88b3dc960d7cb6c7
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { RecordContextProvider } from "react-admin";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { RecordContextProvider } from "react-admin";
|
||||
|
||||
import AvatarField from "./AvatarField";
|
||||
|
||||
describe("AvatarField", () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { get } from "lodash";
|
||||
|
||||
import { Avatar } from "@mui/material";
|
||||
import { useRecordContext } from "react-admin";
|
||||
|
||||
@@ -6,16 +7,7 @@ const AvatarField = ({ source, ...rest }) => {
|
||||
const record = useRecordContext(rest);
|
||||
const src = get(record, source)?.toString();
|
||||
const { alt, classes, sizes, sx, variant } = rest;
|
||||
return (
|
||||
<Avatar
|
||||
alt={alt}
|
||||
classes={classes}
|
||||
sizes={sizes}
|
||||
src={src}
|
||||
sx={sx}
|
||||
variant={variant}
|
||||
/>
|
||||
);
|
||||
return <Avatar alt={alt} classes={classes} sizes={sizes} src={src} sx={sx} variant={variant} />;
|
||||
};
|
||||
|
||||
export default AvatarField;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import PageviewIcon from "@mui/icons-material/Pageview";
|
||||
import ViewListIcon from "@mui/icons-material/ViewList";
|
||||
import ReportIcon from "@mui/icons-material/Warning";
|
||||
import {
|
||||
Datagrid,
|
||||
DateField,
|
||||
@@ -17,15 +20,11 @@ import {
|
||||
useRecordContext,
|
||||
useTranslate,
|
||||
} from "react-admin";
|
||||
import { MXCField } from "./media";
|
||||
import PageviewIcon from "@mui/icons-material/Pageview";
|
||||
import ReportIcon from "@mui/icons-material/Warning";
|
||||
import ViewListIcon from "@mui/icons-material/ViewList";
|
||||
import { date_format } from "./date";
|
||||
|
||||
const ReportPagination = () => (
|
||||
<Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
|
||||
);
|
||||
import { DATE_FORMAT } from "./date";
|
||||
import { MXCField } from "./media";
|
||||
|
||||
const ReportPagination = () => <Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />;
|
||||
|
||||
export const ReportShow = (props: ShowProps) => {
|
||||
const translate = useTranslate();
|
||||
@@ -38,43 +37,21 @@ export const ReportShow = (props: ShowProps) => {
|
||||
})}
|
||||
icon={<ViewListIcon />}
|
||||
>
|
||||
<DateField
|
||||
source="received_ts"
|
||||
showTime
|
||||
options={date_format}
|
||||
sortable={true}
|
||||
/>
|
||||
<DateField source="received_ts" showTime options={DATE_FORMAT} sortable={true} />
|
||||
<ReferenceField source="user_id" reference="users">
|
||||
<TextField source="id" />
|
||||
</ReferenceField>
|
||||
<NumberField source="score" />
|
||||
<TextField source="reason" />
|
||||
<TextField source="name" />
|
||||
<TextField
|
||||
source="canonical_alias"
|
||||
label="resources.rooms.fields.canonical_alias"
|
||||
/>
|
||||
<ReferenceField
|
||||
source="room_id"
|
||||
reference="rooms"
|
||||
link="show"
|
||||
label="resources.rooms.fields.room_id"
|
||||
>
|
||||
<TextField source="canonical_alias" label="resources.rooms.fields.canonical_alias" />
|
||||
<ReferenceField source="room_id" reference="rooms" link="show" label="resources.rooms.fields.room_id">
|
||||
<TextField source="id" />
|
||||
</ReferenceField>
|
||||
</Tab>
|
||||
|
||||
<Tab
|
||||
label="synapseadmin.reports.tabs.detail"
|
||||
icon={<PageviewIcon />}
|
||||
path="detail"
|
||||
>
|
||||
<DateField
|
||||
source="event_json.origin_server_ts"
|
||||
showTime
|
||||
options={date_format}
|
||||
sortable={true}
|
||||
/>
|
||||
<Tab label="synapseadmin.reports.tabs.detail" icon={<PageviewIcon />} path="detail">
|
||||
<DateField source="event_json.origin_server_ts" showTime options={DATE_FORMAT} sortable={true} />
|
||||
<ReferenceField source="sender" reference="users">
|
||||
<TextField source="id" />
|
||||
</ReferenceField>
|
||||
@@ -89,10 +66,7 @@ export const ReportShow = (props: ShowProps) => {
|
||||
<TextField source="event_json.content.format" />
|
||||
<TextField source="event_json.content.formatted_body" />
|
||||
<TextField source="event_json.content.algorithm" />
|
||||
<TextField
|
||||
source="event_json.content.device_id"
|
||||
label="resources.devices.fields.device_id"
|
||||
/>
|
||||
<TextField source="event_json.content.device_id" label="resources.devices.fields.device_id" />
|
||||
</Tab>
|
||||
</TabbedShowLayout>
|
||||
</Show>
|
||||
@@ -115,19 +89,10 @@ const ReportShowActions = () => {
|
||||
};
|
||||
|
||||
export const ReportList = (props: ListProps) => (
|
||||
<List
|
||||
{...props}
|
||||
pagination={<ReportPagination />}
|
||||
sort={{ field: "received_ts", order: "DESC" }}
|
||||
>
|
||||
<List {...props} pagination={<ReportPagination />} sort={{ field: "received_ts", order: "DESC" }}>
|
||||
<Datagrid rowClick="show" bulkActionButtons={false}>
|
||||
<TextField source="id" sortable={false} />
|
||||
<DateField
|
||||
source="received_ts"
|
||||
showTime
|
||||
options={date_format}
|
||||
sortable={true}
|
||||
/>
|
||||
<DateField source="received_ts" showTime options={DATE_FORMAT} sortable={true} />
|
||||
<TextField sortable={false} source="user_id" />
|
||||
<TextField sortable={false} source="name" />
|
||||
<TextField sortable={false} source="score" />
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { parse as parseCsv, unparse as unparseCsv, ParseResult } from "papaparse";
|
||||
import { ChangeEvent, useState } from "react";
|
||||
import { useDataProvider, useNotify, RaRecord, Title } from "react-admin";
|
||||
import {
|
||||
parse as parseCsv,
|
||||
unparse as unparseCsv,
|
||||
ParseResult,
|
||||
} from "papaparse";
|
||||
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
@@ -17,6 +13,8 @@ import {
|
||||
NativeSelect,
|
||||
} from "@mui/material";
|
||||
import { DataProvider, useTranslate } from "ra-core";
|
||||
import { useDataProvider, useNotify, RaRecord, Title } from "react-admin";
|
||||
|
||||
import { generateRandomMxId, generateRandomPassword } from "../synapse/synapse";
|
||||
|
||||
const LOGGING = true;
|
||||
@@ -121,21 +119,12 @@ const FilePicker = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const verifyCsv = (
|
||||
{ data, meta, errors }: ParseResult<ImportLine>,
|
||||
{ setValues, setStats, setError }
|
||||
) => {
|
||||
const verifyCsv = ({ data, meta, errors }: ParseResult<ImportLine>, { setValues, setStats, setError }) => {
|
||||
/* First, verify the presence of required fields */
|
||||
const missingFields = expectedFields.filter(eF =>
|
||||
meta.fields?.find(mF => eF === mF)
|
||||
);
|
||||
const missingFields = expectedFields.filter(eF => meta.fields?.find(mF => eF === mF));
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
setError(
|
||||
translate("import_users.error.required_field", {
|
||||
field: missingFields[0],
|
||||
})
|
||||
);
|
||||
setError(translate("import_users.error.required_field", { field: missingFields[0] }));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -157,7 +146,7 @@ const FilePicker = () => {
|
||||
total: data.length,
|
||||
};
|
||||
|
||||
var errorMessages = errors.map(e => e.message);
|
||||
const errorMessages = errors.map(e => e.message);
|
||||
data.forEach((line, idx) => {
|
||||
if (line.user_type === undefined || line.user_type === "") {
|
||||
stats.user_types.default++;
|
||||
@@ -305,10 +294,7 @@ const FilePicker = () => {
|
||||
* We do a simple retry loop so that an accidental hit on an existing ID
|
||||
* doesn't trip us up.
|
||||
*/
|
||||
if (LOGGING)
|
||||
console.log(
|
||||
"will check for existence of record " + JSON.stringify(userRecord)
|
||||
);
|
||||
if (LOGGING) console.log("will check for existence of record " + JSON.stringify(userRecord));
|
||||
let retries = 0;
|
||||
const submitRecord = (recordData: ImportLine) => {
|
||||
return dataProvider.getOne("users", { id: recordData.id }).then(
|
||||
@@ -337,14 +323,7 @@ const FilePicker = () => {
|
||||
}
|
||||
},
|
||||
async () => {
|
||||
if (LOGGING)
|
||||
console.log(
|
||||
"OK to create record " +
|
||||
recordData.id +
|
||||
" (" +
|
||||
recordData.displayname +
|
||||
")."
|
||||
);
|
||||
if (LOGGING) console.log("OK to create record " + recordData.id + " (" + recordData.displayname + ").");
|
||||
|
||||
if (!dryRun) {
|
||||
await dataProvider.create("users", { data: recordData });
|
||||
@@ -429,28 +408,11 @@ const FilePicker = () => {
|
||||
const statsCards = stats &&
|
||||
!importResults && [
|
||||
<Container>
|
||||
<CardHeader
|
||||
title={translate("import_users.cards.importstats.header")}
|
||||
/>
|
||||
<CardHeader title={translate("import_users.cards.importstats.header")} />
|
||||
<CardContent>
|
||||
<div>
|
||||
{translate(
|
||||
"import_users.cards.importstats.users_total",
|
||||
stats.total
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{translate(
|
||||
"import_users.cards.importstats.guest_count",
|
||||
stats.is_guest
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{translate(
|
||||
"import_users.cards.importstats.admin_count",
|
||||
stats.admin
|
||||
)}
|
||||
</div>
|
||||
<div>{translate("import_users.cards.importstats.users_total", stats.total)}</div>
|
||||
<div>{translate("import_users.cards.importstats.guest_count", stats.is_guest)}</div>
|
||||
<div>{translate("import_users.cards.importstats.admin_count", stats.admin)}</div>
|
||||
</CardContent>
|
||||
</Container>,
|
||||
<Container>
|
||||
@@ -463,19 +425,9 @@ const FilePicker = () => {
|
||||
</div>
|
||||
{stats.id > 0 ? (
|
||||
<div>
|
||||
<NativeSelect
|
||||
onChange={onUseridModeChanged}
|
||||
value={useridMode}
|
||||
disabled={progress !== null}
|
||||
>
|
||||
<TranslatableOption
|
||||
value="ignore"
|
||||
text="import_users.cards.ids.mode.ignore"
|
||||
/>
|
||||
<TranslatableOption
|
||||
value="update"
|
||||
text="import_users.cards.ids.mode.update"
|
||||
/>
|
||||
<NativeSelect onChange={onUseridModeChanged} value={useridMode} disabled={progress !== null}>
|
||||
<TranslatableOption value="ignore" text="import_users.cards.ids.mode.ignore" />
|
||||
<TranslatableOption value="update" text="import_users.cards.ids.mode.update" />
|
||||
</NativeSelect>
|
||||
</div>
|
||||
) : (
|
||||
@@ -489,20 +441,13 @@ const FilePicker = () => {
|
||||
<div>
|
||||
{stats.password === stats.total
|
||||
? translate("import_users.cards.passwords.all_passwords_present")
|
||||
: translate(
|
||||
"import_users.cards.passwords.count_passwords_present",
|
||||
stats.password
|
||||
)}
|
||||
: translate("import_users.cards.passwords.count_passwords_present", stats.password)}
|
||||
</div>
|
||||
{stats.password > 0 ? (
|
||||
<div>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={passwordMode}
|
||||
disabled={progress !== null}
|
||||
onChange={onPasswordModeChange}
|
||||
/>
|
||||
<Checkbox checked={passwordMode} disabled={progress !== null} onChange={onPasswordModeChange} />
|
||||
}
|
||||
label={translate("import_users.cards.passwords.use_passwords")}
|
||||
/>
|
||||
@@ -519,19 +464,9 @@ const FilePicker = () => {
|
||||
<CardHeader title={translate("import_users.cards.conflicts.header")} />
|
||||
<CardContent>
|
||||
<div>
|
||||
<NativeSelect
|
||||
onChange={onConflictModeChanged}
|
||||
value={conflictMode}
|
||||
disabled={progress !== null}
|
||||
>
|
||||
<TranslatableOption
|
||||
value="stop"
|
||||
text="import_users.cards.conflicts.mode.stop"
|
||||
/>
|
||||
<TranslatableOption
|
||||
value="skip"
|
||||
text="import_users.cards.conflicts.mode.skip"
|
||||
/>
|
||||
<NativeSelect onChange={onConflictModeChanged} value={conflictMode} disabled={progress !== null}>
|
||||
<TranslatableOption value="stop" text="import_users.cards.conflicts.mode.stop" />
|
||||
<TranslatableOption value="skip" text="import_users.cards.conflicts.mode.skip" />
|
||||
</NativeSelect>
|
||||
</div>
|
||||
</CardContent>
|
||||
@@ -557,11 +492,7 @@ const FilePicker = () => {
|
||||
<a href="./data/example.csv">example.csv</a>
|
||||
<br />
|
||||
<br />
|
||||
<input
|
||||
type="file"
|
||||
onChange={onFileChange}
|
||||
disabled={progress !== null}
|
||||
/>
|
||||
<input type="file" onChange={onFileChange} disabled={progress !== null} />
|
||||
</CardContent>
|
||||
</Container>
|
||||
);
|
||||
@@ -570,22 +501,13 @@ const FilePicker = () => {
|
||||
<CardContent>
|
||||
<CardHeader title={translate("import_users.cards.results.header")} />
|
||||
<div>
|
||||
{translate(
|
||||
"import_users.cards.results.total",
|
||||
importResults.totalRecordCount
|
||||
)}
|
||||
{translate("import_users.cards.results.total", importResults.totalRecordCount)}
|
||||
<br />
|
||||
{translate(
|
||||
"import_users.cards.results.successful",
|
||||
importResults.succeededRecords.length
|
||||
)}
|
||||
{translate("import_users.cards.results.successful", importResults.succeededRecords.length)}
|
||||
<br />
|
||||
{importResults.skippedRecords.length
|
||||
? [
|
||||
translate(
|
||||
"import_users.cards.results.skipped",
|
||||
importResults.skippedRecords.length
|
||||
),
|
||||
translate("import_users.cards.results.skipped", importResults.skippedRecords.length),
|
||||
<div>
|
||||
<button onClick={downloadSkippedRecords}>
|
||||
{translate("import_users.cards.results.download_skipped")}
|
||||
@@ -595,19 +517,10 @@ const FilePicker = () => {
|
||||
]
|
||||
: ""}
|
||||
{importResults.erroredRecords.length
|
||||
? [
|
||||
translate(
|
||||
"import_users.cards.results.skipped",
|
||||
importResults.erroredRecords.length
|
||||
),
|
||||
<br />,
|
||||
]
|
||||
? [translate("import_users.cards.results.skipped", importResults.erroredRecords.length), <br />]
|
||||
: ""}
|
||||
<br />
|
||||
{importResults.wasDryRun && [
|
||||
translate("import_users.cards.results.simulated_only"),
|
||||
<br />,
|
||||
]}
|
||||
{importResults.wasDryRun && [translate("import_users.cards.results.simulated_only"), <br />]}
|
||||
</div>
|
||||
</CardContent>
|
||||
);
|
||||
@@ -616,13 +529,7 @@ const FilePicker = () => {
|
||||
!values || values.length === 0 || importResults ? undefined : (
|
||||
<CardActions>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={dryRun}
|
||||
onChange={onDryRunModeChanged}
|
||||
disabled={progress !== null}
|
||||
/>
|
||||
}
|
||||
control={<Checkbox checked={dryRun} onChange={onDryRunModeChanged} disabled={progress !== null} />}
|
||||
label={translate("import_users.cards.startImport.simulate_only")}
|
||||
/>
|
||||
<Button size="large" onClick={runImport} disabled={progress !== null}>
|
||||
@@ -646,10 +553,7 @@ const FilePicker = () => {
|
||||
|
||||
const cardContainer = <Card>{allCards}</Card>;
|
||||
|
||||
return [
|
||||
<Title defaultTitle={translate("import_users.title")} />,
|
||||
cardContainer,
|
||||
];
|
||||
return [<Title defaultTitle={translate("import_users.title")} />, cardContainer];
|
||||
};
|
||||
|
||||
export const ImportFeature = FilePicker;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import polyglotI18nProvider from "ra-i18n-polyglot";
|
||||
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { AdminContext } from "react-admin";
|
||||
import polyglotI18nProvider from "ra-i18n-polyglot";
|
||||
|
||||
import LoginPage from "./LoginPage";
|
||||
import { AppContext } from "../AppContext";
|
||||
import englishMessages from "../i18n/en";
|
||||
|
||||
const i18nProvider = polyglotI18nProvider(() => englishMessages, "en", [
|
||||
{ locale: "en", name: "English" },
|
||||
]);
|
||||
const i18nProvider = polyglotI18nProvider(() => englishMessages, "en", [{ locale: "en", name: "English" }]);
|
||||
|
||||
describe("LoginForm", () => {
|
||||
it("renders with no restriction to homeserver", () => {
|
||||
@@ -30,9 +30,7 @@ describe("LoginForm", () => {
|
||||
|
||||
it("renders with single restricted homeserver", () => {
|
||||
render(
|
||||
<AppContext.Provider
|
||||
value={{ restrictBaseUrl: "https://matrix.example.com" }}
|
||||
>
|
||||
<AppContext.Provider value={{ restrictBaseUrl: "https://matrix.example.com" }}>
|
||||
<AdminContext i18nProvider={i18nProvider}>
|
||||
<LoginPage />
|
||||
</AdminContext>
|
||||
@@ -54,10 +52,7 @@ describe("LoginForm", () => {
|
||||
render(
|
||||
<AppContext.Provider
|
||||
value={{
|
||||
restrictBaseUrl: [
|
||||
"https://matrix.example.com",
|
||||
"https://matrix.example.org",
|
||||
],
|
||||
restrictBaseUrl: ["https://matrix.example.com", "https://matrix.example.org"],
|
||||
}}
|
||||
>
|
||||
<AdminContext i18nProvider={i18nProvider}>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
import LockIcon from "@mui/icons-material/Lock";
|
||||
import { Avatar, Box, Button, Card, CardActions, CircularProgress, MenuItem, Select, Typography } from "@mui/material";
|
||||
import { styled } from "@mui/material/styles";
|
||||
import {
|
||||
Form,
|
||||
FormDataConsumer,
|
||||
@@ -13,19 +17,6 @@ import {
|
||||
useLocales,
|
||||
} from "react-admin";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
CardActions,
|
||||
CircularProgress,
|
||||
MenuItem,
|
||||
Select,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { styled } from "@mui/material/styles";
|
||||
import LockIcon from "@mui/icons-material/Lock";
|
||||
|
||||
import { useAppContext } from "../AppContext";
|
||||
import {
|
||||
@@ -103,9 +94,7 @@ const LoginPage = () => {
|
||||
const [locale, setLocale] = useLocaleState();
|
||||
const locales = useLocales();
|
||||
const translate = useTranslate();
|
||||
const base_url = allowSingleBaseUrl
|
||||
? restrictBaseUrl
|
||||
: localStorage.getItem("base_url");
|
||||
const base_url = allowSingleBaseUrl ? restrictBaseUrl : localStorage.getItem("base_url");
|
||||
const [ssoBaseUrl, setSSOBaseUrl] = useState("");
|
||||
const loginToken = /\?loginToken=([a-zA-Z0-9_-]+)/.exec(window.location.href);
|
||||
|
||||
@@ -113,11 +102,7 @@ const LoginPage = () => {
|
||||
const ssoToken = loginToken[1];
|
||||
console.log("SSO token is", ssoToken);
|
||||
// Prevent further requests
|
||||
window.history.replaceState(
|
||||
{},
|
||||
"",
|
||||
window.location.href.replace(loginToken[0], "#").split("#")[0]
|
||||
);
|
||||
window.history.replaceState({}, "", window.location.href.replace(loginToken[0], "#").split("#")[0]);
|
||||
const baseUrl = localStorage.getItem("sso_base_url");
|
||||
localStorage.removeItem("sso_base_url");
|
||||
if (baseUrl) {
|
||||
@@ -146,9 +131,7 @@ const LoginPage = () => {
|
||||
const validateBaseUrl = value => {
|
||||
if (!value.match(/^(http|https):\/\//)) {
|
||||
return translate("synapseadmin.auth.protocol_error");
|
||||
} else if (
|
||||
!value.match(/^(http|https):\/\/[a-zA-Z0-9\-.]+(:\d{1,5})?[^?&\s]*$/)
|
||||
) {
|
||||
} else if (!value.match(/^(http|https):\/\/[a-zA-Z0-9\-.]+(:\d{1,5})?[^?&\s]*$/)) {
|
||||
return translate("synapseadmin.auth.url_error");
|
||||
} else {
|
||||
return undefined;
|
||||
@@ -189,10 +172,7 @@ const LoginPage = () => {
|
||||
const domain = splitMxid(formData.username)?.domain;
|
||||
if (domain) {
|
||||
getWellKnownUrl(domain).then(url => {
|
||||
if (
|
||||
allowAnyBaseUrl ||
|
||||
(allowMultipleBaseUrls && restrictBaseUrl.includes(url))
|
||||
)
|
||||
if (allowAnyBaseUrl || (allowMultipleBaseUrls && restrictBaseUrl.includes(url)))
|
||||
form.setValue("base_url", url);
|
||||
});
|
||||
}
|
||||
@@ -205,28 +185,20 @@ const LoginPage = () => {
|
||||
if (!isValidBaseUrl(formData.base_url)) return;
|
||||
|
||||
getServerVersion(formData.base_url)
|
||||
.then(serverVersion =>
|
||||
setServerVersion(
|
||||
`${translate("synapseadmin.auth.server_version")} ${serverVersion}`
|
||||
)
|
||||
)
|
||||
.then(serverVersion => setServerVersion(`${translate("synapseadmin.auth.server_version")} ${serverVersion}`))
|
||||
.catch(() => setServerVersion(""));
|
||||
|
||||
getSupportedFeatures(formData.base_url)
|
||||
.then(features =>
|
||||
setMatrixVersions(
|
||||
`${translate("synapseadmin.auth.supports_specs")} ${features.versions.join(", ")}`
|
||||
)
|
||||
setMatrixVersions(`${translate("synapseadmin.auth.supports_specs")} ${features.versions.join(", ")}`)
|
||||
)
|
||||
.catch(() => setMatrixVersions(""));
|
||||
|
||||
// Set SSO Url
|
||||
getSupportedLoginFlows(formData.base_url)
|
||||
.then(loginFlows => {
|
||||
const supportPass =
|
||||
loginFlows.find(f => f.type === "m.login.password") !== undefined;
|
||||
const supportSSO =
|
||||
loginFlows.find(f => f.type === "m.login.sso") !== undefined;
|
||||
const supportPass = loginFlows.find(f => f.type === "m.login.password") !== undefined;
|
||||
const supportSSO = loginFlows.find(f => f.type === "m.login.sso") !== undefined;
|
||||
setSupportPassAuth(supportPass);
|
||||
setSSOBaseUrl(supportSSO ? formData.base_url : "");
|
||||
})
|
||||
@@ -287,11 +259,7 @@ const LoginPage = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
defaultValues={{ base_url: base_url }}
|
||||
onSubmit={handleSubmit}
|
||||
mode="onTouched"
|
||||
>
|
||||
<Form defaultValues={{ base_url: base_url }} onSubmit={handleSubmit} mode="onTouched">
|
||||
<FormBox>
|
||||
<Card className="card">
|
||||
<Box className="avatar">
|
||||
@@ -318,9 +286,7 @@ const LoginPage = () => {
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<FormDataConsumer>
|
||||
{formDataProps => <UserData {...formDataProps} />}
|
||||
</FormDataConsumer>
|
||||
<FormDataConsumer>{formDataProps => <UserData {...formDataProps} />}</FormDataConsumer>
|
||||
<CardActions className="actions">
|
||||
<Button
|
||||
variant="contained"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import RegistrationTokenIcon from "@mui/icons-material/ConfirmationNumber";
|
||||
import {
|
||||
BooleanInput,
|
||||
Create,
|
||||
@@ -21,8 +22,8 @@ import {
|
||||
TextField,
|
||||
Toolbar,
|
||||
} from "react-admin";
|
||||
import RegistrationTokenIcon from "@mui/icons-material/ConfirmationNumber";
|
||||
import { date_format, dateFormatter, dateParser } from "./date";
|
||||
|
||||
import { DATE_FORMAT, dateFormatter, dateParser } from "./date";
|
||||
|
||||
const validateToken = [regex(/^[A-Za-z0-9._~-]{0,64}$/)];
|
||||
const validateUsesAllowed = [number()];
|
||||
@@ -43,12 +44,7 @@ export const RegistrationTokenList = (props: ListProps) => (
|
||||
<NumberField source="uses_allowed" sortable={false} />
|
||||
<NumberField source="pending" sortable={false} />
|
||||
<NumberField source="completed" sortable={false} />
|
||||
<DateField
|
||||
source="expiry_time"
|
||||
showTime
|
||||
options={date_format}
|
||||
sortable={false}
|
||||
/>
|
||||
<DateField source="expiry_time" showTime options={DATE_FORMAT} sortable={false} />
|
||||
</Datagrid>
|
||||
</List>
|
||||
);
|
||||
@@ -63,23 +59,14 @@ export const RegistrationTokenCreate = (props: CreateProps) => (
|
||||
</Toolbar>
|
||||
}
|
||||
>
|
||||
<TextInput
|
||||
source="token"
|
||||
autoComplete="off"
|
||||
validate={validateToken}
|
||||
resettable
|
||||
/>
|
||||
<TextInput source="token" autoComplete="off" validate={validateToken} resettable />
|
||||
<NumberInput
|
||||
source="length"
|
||||
validate={validateLength}
|
||||
helperText="resources.registration_tokens.helper.length"
|
||||
step={1}
|
||||
/>
|
||||
<NumberInput
|
||||
source="uses_allowed"
|
||||
validate={validateUsesAllowed}
|
||||
step={1}
|
||||
/>
|
||||
<NumberInput source="uses_allowed" validate={validateUsesAllowed} step={1} />
|
||||
<DateTimeInput source="expiry_time" parse={dateParser} />
|
||||
</SimpleForm>
|
||||
</Create>
|
||||
@@ -91,16 +78,8 @@ export const RegistrationTokenEdit = (props: EditProps) => (
|
||||
<TextInput source="token" disabled />
|
||||
<NumberInput source="pending" disabled />
|
||||
<NumberInput source="completed" disabled />
|
||||
<NumberInput
|
||||
source="uses_allowed"
|
||||
validate={validateUsesAllowed}
|
||||
step={1}
|
||||
/>
|
||||
<DateTimeInput
|
||||
source="expiry_time"
|
||||
parse={dateParser}
|
||||
format={dateFormatter}
|
||||
/>
|
||||
<NumberInput source="uses_allowed" validate={validateUsesAllowed} step={1} />
|
||||
<DateTimeInput source="expiry_time" parse={dateParser} format={dateFormatter} />
|
||||
</SimpleForm>
|
||||
</Edit>
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import RoomDirectoryIcon from "@mui/icons-material/FolderShared";
|
||||
import {
|
||||
BooleanField,
|
||||
BulkDeleteButton,
|
||||
@@ -25,12 +26,10 @@ import {
|
||||
useUnselectAll,
|
||||
} from "react-admin";
|
||||
import { useMutation } from "react-query";
|
||||
import RoomDirectoryIcon from "@mui/icons-material/FolderShared";
|
||||
|
||||
import AvatarField from "./AvatarField";
|
||||
|
||||
const RoomDirectoryPagination = () => (
|
||||
<Pagination rowsPerPageOptions={[100, 500, 1000, 2000]} />
|
||||
);
|
||||
const RoomDirectoryPagination = () => <Pagination rowsPerPageOptions={[100, 500, 1000, 2000]} />;
|
||||
|
||||
export const RoomDirectoryUnpublishButton = (props: DeleteButtonProps) => {
|
||||
const translate = useTranslate();
|
||||
@@ -53,9 +52,7 @@ export const RoomDirectoryUnpublishButton = (props: DeleteButtonProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const RoomDirectoryBulkUnpublishButton = (
|
||||
props: BulkDeleteButtonProps
|
||||
) => (
|
||||
export const RoomDirectoryBulkUnpublishButton = (props: BulkDeleteButtonProps) => (
|
||||
<BulkDeleteButton
|
||||
{...props}
|
||||
label="resources.room_directory.action.erase"
|
||||
@@ -93,12 +90,7 @@ export const RoomDirectoryBulkPublishButton = (props: ButtonProps) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<Button
|
||||
{...props}
|
||||
label="resources.room_directory.action.create"
|
||||
onClick={mutate}
|
||||
disabled={isLoading}
|
||||
>
|
||||
<Button {...props} label="resources.room_directory.action.create" onClick={mutate} disabled={isLoading}>
|
||||
<RoomDirectoryIcon />
|
||||
</Button>
|
||||
);
|
||||
@@ -128,12 +120,7 @@ export const RoomDirectoryPublishButton = (props: ButtonProps) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
{...props}
|
||||
label="resources.room_directory.action.create"
|
||||
onClick={handleSend}
|
||||
disabled={isLoading}
|
||||
>
|
||||
<Button {...props} label="resources.room_directory.action.create" onClick={handleSend} disabled={isLoading}>
|
||||
<RoomDirectoryIcon />
|
||||
</Button>
|
||||
);
|
||||
@@ -147,11 +134,7 @@ const RoomDirectoryListActions = () => (
|
||||
);
|
||||
|
||||
export const RoomDirectoryList = () => (
|
||||
<List
|
||||
pagination={<RoomDirectoryPagination />}
|
||||
perPage={100}
|
||||
actions={<RoomDirectoryListActions />}
|
||||
>
|
||||
<List pagination={<RoomDirectoryPagination />} perPage={100} actions={<RoomDirectoryListActions />}>
|
||||
<DatagridConfigurable
|
||||
rowClick={id => "/rooms/" + id + "/show"}
|
||||
bulkActionButtons={<RoomDirectoryBulkUnpublishButton />}
|
||||
@@ -163,41 +146,13 @@ export const RoomDirectoryList = () => (
|
||||
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"
|
||||
/>
|
||||
<TextField
|
||||
source="topic"
|
||||
sortable={false}
|
||||
label="resources.rooms.fields.topic"
|
||||
/>
|
||||
<NumberField
|
||||
source="num_joined_members"
|
||||
sortable={false}
|
||||
label="resources.rooms.fields.joined_members"
|
||||
/>
|
||||
<BooleanField
|
||||
source="world_readable"
|
||||
sortable={false}
|
||||
label="resources.room_directory.fields.world_readable"
|
||||
/>
|
||||
<BooleanField
|
||||
source="guest_can_join"
|
||||
sortable={false}
|
||||
label="resources.room_directory.fields.guest_can_join"
|
||||
/>
|
||||
<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" />
|
||||
<TextField source="topic" sortable={false} label="resources.rooms.fields.topic" />
|
||||
<NumberField source="num_joined_members" sortable={false} label="resources.rooms.fields.joined_members" />
|
||||
<BooleanField source="world_readable" sortable={false} label="resources.room_directory.fields.world_readable" />
|
||||
<BooleanField source="guest_can_join" sortable={false} label="resources.room_directory.fields.guest_can_join" />
|
||||
</DatagridConfigurable>
|
||||
</List>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import IconCancel from "@mui/icons-material/Cancel";
|
||||
import MessageIcon from "@mui/icons-material/Message";
|
||||
import { Dialog, DialogContent, DialogContentText, DialogTitle } from "@mui/material";
|
||||
import {
|
||||
Button,
|
||||
RaRecord,
|
||||
@@ -17,26 +21,13 @@ import {
|
||||
useUnselectAll,
|
||||
} from "react-admin";
|
||||
import { useMutation } from "react-query";
|
||||
import MessageIcon from "@mui/icons-material/Message";
|
||||
import IconCancel from "@mui/icons-material/Cancel";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
} from "@mui/material";
|
||||
|
||||
const ServerNoticeDialog = ({ open, onClose, onSubmit }) => {
|
||||
const translate = useTranslate();
|
||||
|
||||
const ServerNoticeToolbar = (
|
||||
props: ToolbarProps & { pristine?: boolean }
|
||||
) => (
|
||||
const ServerNoticeToolbar = (props: ToolbarProps & { pristine?: boolean }) => (
|
||||
<Toolbar {...props}>
|
||||
<SaveButton
|
||||
label="resources.servernotices.action.send"
|
||||
disabled={props.pristine}
|
||||
/>
|
||||
<SaveButton label="resources.servernotices.action.send" disabled={props.pristine} />
|
||||
<Button label="ra.action.cancel" onClick={onClose}>
|
||||
<IconCancel />
|
||||
</Button>
|
||||
@@ -45,13 +36,9 @@ const ServerNoticeDialog = ({ open, onClose, onSubmit }) => {
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={onClose}>
|
||||
<DialogTitle>
|
||||
{translate("resources.servernotices.action.send")}
|
||||
</DialogTitle>
|
||||
<DialogTitle>{translate("resources.servernotices.action.send")}</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
{translate("resources.servernotices.helper.send")}
|
||||
</DialogContentText>
|
||||
<DialogContentText>{translate("resources.servernotices.helper.send")}</DialogContentText>
|
||||
<SimpleForm toolbar={<ServerNoticeToolbar />} onSubmit={onSubmit}>
|
||||
<TextInput
|
||||
source="body"
|
||||
@@ -96,18 +83,10 @@ export const ServerNoticeButton = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
label="resources.servernotices.send"
|
||||
onClick={handleDialogOpen}
|
||||
disabled={isLoading}
|
||||
>
|
||||
<Button label="resources.servernotices.send" onClick={handleDialogOpen} disabled={isLoading}>
|
||||
<MessageIcon />
|
||||
</Button>
|
||||
<ServerNoticeDialog
|
||||
open={open}
|
||||
onClose={handleDialogClose}
|
||||
onSubmit={handleSend}
|
||||
/>
|
||||
<ServerNoticeDialog open={open} onClose={handleDialogClose} onSubmit={handleSend} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -142,18 +121,10 @@ export const ServerNoticeBulkButton = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
label="resources.servernotices.send"
|
||||
onClick={openDialog}
|
||||
disabled={isLoading}
|
||||
>
|
||||
<Button label="resources.servernotices.send" onClick={openDialog} disabled={isLoading}>
|
||||
<MessageIcon />
|
||||
</Button>
|
||||
<ServerNoticeDialog
|
||||
open={open}
|
||||
onClose={closeDialog}
|
||||
onSubmit={sendNotices}
|
||||
/>
|
||||
<ServerNoticeDialog open={open} onClose={closeDialog} onSubmit={sendNotices} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const date_format: Intl.DateTimeFormatOptions = {
|
||||
export const DATE_FORMAT: Intl.DateTimeFormatOptions = {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
@@ -12,9 +12,7 @@ export const dateParser = (v: string | number | Date): number => {
|
||||
return d.getTime();
|
||||
};
|
||||
|
||||
export const dateFormatter = (
|
||||
v: string | number | Date | undefined | null
|
||||
): string => {
|
||||
export const dateFormatter = (v: string | number | Date | undefined | null): string => {
|
||||
if (v === undefined || v === null) return "";
|
||||
const d = new Date(v);
|
||||
|
||||
|
||||
@@ -29,11 +29,9 @@ import {
|
||||
useTranslate,
|
||||
} from "react-admin";
|
||||
|
||||
import { date_format } from "./date";
|
||||
import { DATE_FORMAT } from "./date";
|
||||
|
||||
const DestinationPagination = () => (
|
||||
<Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
|
||||
);
|
||||
const DestinationPagination = () => <Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />;
|
||||
|
||||
const destinationRowSx = (record: RaRecord) => ({
|
||||
backgroundColor: record.retry_last_ts > 0 ? "#ffcccc" : "white",
|
||||
@@ -72,11 +70,7 @@ export const DestinationReconnectButton = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
label="resources.destinations.action.reconnect"
|
||||
onClick={handleClick}
|
||||
disabled={isLoading}
|
||||
>
|
||||
<Button label="resources.destinations.action.reconnect" onClick={handleClick} disabled={isLoading}>
|
||||
<AutorenewIcon />
|
||||
</Button>
|
||||
);
|
||||
@@ -106,14 +100,10 @@ export const DestinationList = (props: ListProps) => {
|
||||
pagination={<DestinationPagination />}
|
||||
sort={{ field: "destination", order: "ASC" }}
|
||||
>
|
||||
<Datagrid
|
||||
rowSx={destinationRowSx}
|
||||
rowClick={id => `${id}/show/rooms`}
|
||||
bulkActionButtons={false}
|
||||
>
|
||||
<Datagrid rowSx={destinationRowSx} rowClick={id => `${id}/show/rooms`} bulkActionButtons={false}>
|
||||
<TextField source="destination" />
|
||||
<DateField source="failure_ts" showTime options={date_format} />
|
||||
<DateField source="retry_last_ts" showTime options={date_format} />
|
||||
<DateField source="failure_ts" showTime options={DATE_FORMAT} />
|
||||
<DateField source="retry_last_ts" showTime options={DATE_FORMAT} />
|
||||
<TextField source="retry_interval" />
|
||||
<TextField source="last_successful_stream_ordering" />
|
||||
<DestinationReconnectButton />
|
||||
@@ -125,25 +115,17 @@ export const DestinationList = (props: ListProps) => {
|
||||
export const DestinationShow = (props: ShowProps) => {
|
||||
const translate = useTranslate();
|
||||
return (
|
||||
<Show
|
||||
actions={<DestinationShowActions />}
|
||||
title={<DestinationTitle />}
|
||||
{...props}
|
||||
>
|
||||
<Show actions={<DestinationShowActions />} title={<DestinationTitle />} {...props}>
|
||||
<TabbedShowLayout>
|
||||
<Tab label="status" icon={<ViewListIcon />}>
|
||||
<TextField source="destination" />
|
||||
<DateField source="failure_ts" showTime options={date_format} />
|
||||
<DateField source="retry_last_ts" showTime options={date_format} />
|
||||
<DateField source="failure_ts" showTime options={DATE_FORMAT} />
|
||||
<DateField source="retry_last_ts" showTime options={DATE_FORMAT} />
|
||||
<TextField source="retry_interval" />
|
||||
<TextField source="last_successful_stream_ordering" />
|
||||
</Tab>
|
||||
|
||||
<Tab
|
||||
label={translate("resources.rooms.name", { smart_count: 2 })}
|
||||
icon={<FolderSharedIcon />}
|
||||
path="rooms"
|
||||
>
|
||||
<Tab label={translate("resources.rooms.name", { smart_count: 2 })} icon={<FolderSharedIcon />} path="rooms">
|
||||
<ReferenceManyField
|
||||
reference="destination_rooms"
|
||||
target="destination"
|
||||
@@ -151,14 +133,8 @@ export const DestinationShow = (props: ShowProps) => {
|
||||
pagination={<DestinationPagination />}
|
||||
perPage={50}
|
||||
>
|
||||
<Datagrid
|
||||
style={{ width: "100%" }}
|
||||
rowClick={id => `/rooms/${id}/show`}
|
||||
>
|
||||
<TextField
|
||||
source="room_id"
|
||||
label="resources.rooms.fields.room_id"
|
||||
/>
|
||||
<Datagrid style={{ width: "100%" }} rowClick={id => `/rooms/${id}/show`}>
|
||||
<TextField source="room_id" label="resources.rooms.fields.room_id" />
|
||||
<TextField source="stream_ordering" sortable={false} />
|
||||
<ReferenceField
|
||||
label="resources.rooms.fields.name"
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
DeleteWithConfirmButton,
|
||||
DeleteWithConfirmButtonProps,
|
||||
useRecordContext,
|
||||
} from "react-admin";
|
||||
import { DeleteWithConfirmButton, DeleteWithConfirmButtonProps, useRecordContext } from "react-admin";
|
||||
|
||||
export const DeviceRemoveButton = (props: DeleteWithConfirmButtonProps) => {
|
||||
const record = useRecordContext();
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
import { useState } from "react";
|
||||
import { get } from "lodash";
|
||||
import { useState } from "react";
|
||||
|
||||
import BlockIcon from "@mui/icons-material/Block";
|
||||
import IconCancel from "@mui/icons-material/Cancel";
|
||||
import ClearIcon from "@mui/icons-material/Clear";
|
||||
import DeleteSweepIcon from "@mui/icons-material/DeleteSweep";
|
||||
import FileOpenIcon from "@mui/icons-material/FileOpen";
|
||||
import LockIcon from "@mui/icons-material/Lock";
|
||||
import LockOpenIcon from "@mui/icons-material/LockOpen";
|
||||
import { Box, Dialog, DialogContent, DialogContentText, DialogTitle, Tooltip } from "@mui/material";
|
||||
import { alpha, useTheme } from "@mui/material/styles";
|
||||
import {
|
||||
BooleanInput,
|
||||
Button,
|
||||
@@ -18,22 +28,7 @@ import {
|
||||
useTranslate,
|
||||
} from "react-admin";
|
||||
import { Link } from "react-router-dom";
|
||||
import BlockIcon from "@mui/icons-material/Block";
|
||||
import ClearIcon from "@mui/icons-material/Clear";
|
||||
import DeleteSweepIcon from "@mui/icons-material/DeleteSweep";
|
||||
import {
|
||||
Box,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
Tooltip,
|
||||
} from "@mui/material";
|
||||
import IconCancel from "@mui/icons-material/Cancel";
|
||||
import LockIcon from "@mui/icons-material/Lock";
|
||||
import LockOpenIcon from "@mui/icons-material/LockOpen";
|
||||
import FileOpenIcon from "@mui/icons-material/FileOpen";
|
||||
import { alpha, useTheme } from "@mui/material/styles";
|
||||
|
||||
import { dateParser } from "./date";
|
||||
import { getMediaUrl } from "../synapse/synapse";
|
||||
|
||||
@@ -42,10 +37,7 @@ const DeleteMediaDialog = ({ open, onClose, onSubmit }) => {
|
||||
|
||||
const DeleteMediaToolbar = (props: ToolbarProps) => (
|
||||
<Toolbar {...props}>
|
||||
<SaveButton
|
||||
label="resources.delete_media.action.send"
|
||||
icon={<DeleteSweepIcon />}
|
||||
/>
|
||||
<SaveButton label="resources.delete_media.action.send" icon={<DeleteSweepIcon />} />
|
||||
<Button label="ra.action.cancel" onClick={onClose}>
|
||||
<IconCancel />
|
||||
</Button>
|
||||
@@ -54,13 +46,9 @@ const DeleteMediaDialog = ({ open, onClose, onSubmit }) => {
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={onClose}>
|
||||
<DialogTitle>
|
||||
{translate("resources.delete_media.action.send")}
|
||||
</DialogTitle>
|
||||
<DialogTitle>{translate("resources.delete_media.action.send")}</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
{translate("resources.delete_media.helper.send")}
|
||||
</DialogContentText>
|
||||
<DialogContentText>{translate("resources.delete_media.helper.send")}</DialogContentText>
|
||||
<SimpleForm toolbar={<DeleteMediaToolbar />} onSubmit={onSubmit}>
|
||||
<DateTimeInput
|
||||
fullWidth
|
||||
@@ -98,11 +86,7 @@ export const DeleteMediaButton = (props: ButtonProps) => {
|
||||
const openDialog = () => setOpen(true);
|
||||
const closeDialog = () => setOpen(false);
|
||||
|
||||
const deleteMedia = (values: {
|
||||
before_ts: string;
|
||||
size_gt: number;
|
||||
keep_profiles: boolean;
|
||||
}) => {
|
||||
const deleteMedia = (values: { before_ts: string; size_gt: number; keep_profiles: boolean }) => {
|
||||
deleteOne(
|
||||
"delete_media",
|
||||
// needs meta.before_ts, meta.size_gt and meta.keep_profiles
|
||||
@@ -140,11 +124,7 @@ export const DeleteMediaButton = (props: ButtonProps) => {
|
||||
>
|
||||
<DeleteSweepIcon />
|
||||
</Button>
|
||||
<DeleteMediaDialog
|
||||
open={open}
|
||||
onClose={closeDialog}
|
||||
onSubmit={deleteMedia}
|
||||
/>
|
||||
<DeleteMediaDialog open={open} onClose={closeDialog} onSubmit={deleteMedia} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -313,11 +293,7 @@ export const QuarantineMediaButton = (props: ButtonProps) => {
|
||||
})}
|
||||
>
|
||||
<div>
|
||||
<Button
|
||||
{...props}
|
||||
onClick={handleRemoveQuarantaine}
|
||||
disabled={isLoading}
|
||||
>
|
||||
<Button {...props} onClick={handleRemoveQuarantaine} disabled={isLoading}>
|
||||
<BlockIcon color="error" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
import EventIcon from "@mui/icons-material/Event";
|
||||
import FastForwardIcon from "@mui/icons-material/FastForward";
|
||||
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 ViewListIcon from "@mui/icons-material/ViewList";
|
||||
import RoomIcon from "@mui/icons-material/ViewList";
|
||||
import VisibilityIcon from "@mui/icons-material/Visibility";
|
||||
import Box from "@mui/material/Box";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import {
|
||||
BooleanField,
|
||||
BulkDeleteButton,
|
||||
@@ -26,28 +37,16 @@ import {
|
||||
useRecordContext,
|
||||
useTranslate,
|
||||
} from "react-admin";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import Box from "@mui/material/Box";
|
||||
import FastForwardIcon from "@mui/icons-material/FastForward";
|
||||
import HttpsIcon from "@mui/icons-material/Https";
|
||||
import NoEncryptionIcon from "@mui/icons-material/NoEncryption";
|
||||
import PageviewIcon from "@mui/icons-material/Pageview";
|
||||
import UserIcon from "@mui/icons-material/Group";
|
||||
import ViewListIcon from "@mui/icons-material/ViewList";
|
||||
import VisibilityIcon from "@mui/icons-material/Visibility";
|
||||
import EventIcon from "@mui/icons-material/Event";
|
||||
import RoomIcon from "@mui/icons-material/ViewList";
|
||||
|
||||
import {
|
||||
RoomDirectoryBulkUnpublishButton,
|
||||
RoomDirectoryBulkPublishButton,
|
||||
RoomDirectoryUnpublishButton,
|
||||
RoomDirectoryPublishButton,
|
||||
} from "./RoomDirectory";
|
||||
import { date_format } from "./date";
|
||||
import { DATE_FORMAT } from "./date";
|
||||
|
||||
const RoomPagination = () => (
|
||||
<Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
|
||||
);
|
||||
const RoomPagination = () => <Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />;
|
||||
|
||||
const RoomTitle = () => {
|
||||
const record = useRecordContext();
|
||||
@@ -66,11 +65,7 @@ const RoomTitle = () => {
|
||||
|
||||
const RoomShowActions = () => {
|
||||
const record = useRecordContext();
|
||||
const publishButton = record.public ? (
|
||||
<RoomDirectoryUnpublishButton />
|
||||
) : (
|
||||
<RoomDirectoryPublishButton />
|
||||
);
|
||||
const publishButton = record.public ? <RoomDirectoryUnpublishButton /> : <RoomDirectoryPublishButton />;
|
||||
// FIXME: refresh after (un)publish
|
||||
return (
|
||||
<TopToolbar>
|
||||
@@ -99,42 +94,19 @@ export const RoomShow = (props: ShowProps) => {
|
||||
</ReferenceField>
|
||||
</Tab>
|
||||
|
||||
<Tab
|
||||
label="synapseadmin.rooms.tabs.detail"
|
||||
icon={<PageviewIcon />}
|
||||
path="detail"
|
||||
>
|
||||
<Tab label="synapseadmin.rooms.tabs.detail" icon={<PageviewIcon />} path="detail">
|
||||
<TextField source="joined_members" />
|
||||
<TextField source="joined_local_members" />
|
||||
<TextField source="joined_local_devices" />
|
||||
<TextField source="state_events" />
|
||||
<TextField source="version" />
|
||||
<TextField
|
||||
source="encryption"
|
||||
emptyText={translate("resources.rooms.enums.unencrypted")}
|
||||
/>
|
||||
<TextField source="encryption" emptyText={translate("resources.rooms.enums.unencrypted")} />
|
||||
</Tab>
|
||||
|
||||
<Tab
|
||||
label="synapseadmin.rooms.tabs.members"
|
||||
icon={<UserIcon />}
|
||||
path="members"
|
||||
>
|
||||
<ReferenceManyField
|
||||
reference="room_members"
|
||||
target="room_id"
|
||||
label={false}
|
||||
>
|
||||
<Datagrid
|
||||
style={{ width: "100%" }}
|
||||
rowClick={id => "/users/" + id}
|
||||
bulkActionButtons={false}
|
||||
>
|
||||
<TextField
|
||||
source="id"
|
||||
sortable={false}
|
||||
label="resources.users.fields.id"
|
||||
/>
|
||||
<Tab label="synapseadmin.rooms.tabs.members" icon={<UserIcon />} path="members">
|
||||
<ReferenceManyField reference="room_members" target="room_id" label={false}>
|
||||
<Datagrid style={{ width: "100%" }} rowClick={id => "/users/" + id} bulkActionButtons={false}>
|
||||
<TextField source="id" sortable={false} label="resources.users.fields.id" />
|
||||
<ReferenceField
|
||||
label="resources.users.fields.displayname"
|
||||
source="id"
|
||||
@@ -148,11 +120,7 @@ export const RoomShow = (props: ShowProps) => {
|
||||
</ReferenceManyField>
|
||||
</Tab>
|
||||
|
||||
<Tab
|
||||
label="synapseadmin.rooms.tabs.permission"
|
||||
icon={<VisibilityIcon />}
|
||||
path="permission"
|
||||
>
|
||||
<Tab label="synapseadmin.rooms.tabs.permission" icon={<VisibilityIcon />} path="permission">
|
||||
<BooleanField source="federatable" />
|
||||
<BooleanField source="public" />
|
||||
<SelectField
|
||||
@@ -203,41 +171,20 @@ export const RoomShow = (props: ShowProps) => {
|
||||
/>
|
||||
</Tab>
|
||||
|
||||
<Tab
|
||||
label={translate("resources.room_state.name", { smart_count: 2 })}
|
||||
icon={<EventIcon />}
|
||||
path="state"
|
||||
>
|
||||
<ReferenceManyField
|
||||
reference="room_state"
|
||||
target="room_id"
|
||||
label={false}
|
||||
>
|
||||
<Tab label={translate("resources.room_state.name", { smart_count: 2 })} icon={<EventIcon />} path="state">
|
||||
<ReferenceManyField reference="room_state" target="room_id" label={false}>
|
||||
<Datagrid style={{ width: "100%" }} bulkActionButtons={false}>
|
||||
<TextField source="type" sortable={false} />
|
||||
<DateField
|
||||
source="origin_server_ts"
|
||||
showTime
|
||||
options={date_format}
|
||||
sortable={false}
|
||||
/>
|
||||
<DateField source="origin_server_ts" showTime options={DATE_FORMAT} sortable={false} />
|
||||
<TextField source="content" sortable={false} />
|
||||
<ReferenceField
|
||||
source="sender"
|
||||
reference="users"
|
||||
sortable={false}
|
||||
>
|
||||
<ReferenceField source="sender" reference="users" sortable={false}>
|
||||
<TextField source="id" />
|
||||
</ReferenceField>
|
||||
</Datagrid>
|
||||
</ReferenceManyField>
|
||||
</Tab>
|
||||
|
||||
<Tab
|
||||
label="resources.forward_extremities.name"
|
||||
icon={<FastForwardIcon />}
|
||||
path="forward_extremities"
|
||||
>
|
||||
<Tab label="resources.forward_extremities.name" icon={<FastForwardIcon />} path="forward_extremities">
|
||||
<Box
|
||||
sx={{
|
||||
fontFamily: "Roboto, Helvetica, Arial, sans-serif",
|
||||
@@ -246,19 +193,10 @@ export const RoomShow = (props: ShowProps) => {
|
||||
>
|
||||
{translate("resources.rooms.helper.forward_extremities")}
|
||||
</Box>
|
||||
<ReferenceManyField
|
||||
reference="forward_extremities"
|
||||
target="room_id"
|
||||
label={false}
|
||||
>
|
||||
<ReferenceManyField reference="forward_extremities" target="room_id" label={false}>
|
||||
<Datagrid style={{ width: "100%" }} bulkActionButtons={false}>
|
||||
<TextField source="id" sortable={false} />
|
||||
<DateField
|
||||
source="received_ts"
|
||||
showTime
|
||||
options={date_format}
|
||||
sortable={false}
|
||||
/>
|
||||
<DateField source="received_ts" showTime options={DATE_FORMAT} sortable={false} />
|
||||
<NumberField source="depth" sortable={false} />
|
||||
<TextField source="state_group" sortable={false} />
|
||||
</Datagrid>
|
||||
@@ -304,12 +242,7 @@ export const RoomList = (props: ListProps) => {
|
||||
<DatagridConfigurable
|
||||
rowClick="show"
|
||||
bulkActionButtons={<RoomBulkActionButtons />}
|
||||
omit={[
|
||||
"joined_local_members",
|
||||
"state_events",
|
||||
"version",
|
||||
"federatable",
|
||||
]}
|
||||
omit={["joined_local_members", "state_events", "version", "federatable"]}
|
||||
>
|
||||
<BooleanField
|
||||
source="is_encrypted"
|
||||
@@ -322,12 +255,7 @@ export const RoomList = (props: ListProps) => {
|
||||
[`& [data-testid="false"]`]: { color: theme.palette.error.main },
|
||||
}}
|
||||
/>
|
||||
<FunctionField
|
||||
source="name"
|
||||
render={record =>
|
||||
record["name"] || record["canonical_alias"] || record["id"]
|
||||
}
|
||||
/>
|
||||
<FunctionField source="name" render={record => record["name"] || record["canonical_alias"] || record["id"]} />
|
||||
<TextField source="joined_members" />
|
||||
<TextField source="joined_local_members" />
|
||||
<TextField source="state_events" />
|
||||
|
||||
@@ -25,9 +25,7 @@ const ListActions = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const UserMediaStatsPagination = () => (
|
||||
<Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
|
||||
);
|
||||
const UserMediaStatsPagination = () => <Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />;
|
||||
|
||||
const userMediaStatsFilters = [<SearchInput source="search_term" alwaysOn />];
|
||||
|
||||
@@ -39,15 +37,9 @@ export const UserMediaStatsList = (props: ListProps) => (
|
||||
pagination={<UserMediaStatsPagination />}
|
||||
sort={{ field: "media_length", order: "DESC" }}
|
||||
>
|
||||
<Datagrid
|
||||
rowClick={id => "/users/" + id + "/media"}
|
||||
bulkActionButtons={false}
|
||||
>
|
||||
<Datagrid rowClick={id => "/users/" + id + "/media"} bulkActionButtons={false}>
|
||||
<TextField source="user_id" label="resources.users.fields.id" />
|
||||
<TextField
|
||||
source="displayname"
|
||||
label="resources.users.fields.displayname"
|
||||
/>
|
||||
<TextField source="displayname" label="resources.users.fields.displayname" />
|
||||
<NumberField source="media_count" />
|
||||
<NumberField source="media_length" />
|
||||
</Datagrid>
|
||||
|
||||
@@ -2,11 +2,11 @@ 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 UserIcon from "@mui/icons-material/Group";
|
||||
import ViewListIcon from "@mui/icons-material/ViewList";
|
||||
import {
|
||||
ArrayInput,
|
||||
@@ -49,15 +49,12 @@ import {
|
||||
useListContext,
|
||||
} from "react-admin";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import AvatarField from "./AvatarField";
|
||||
import { ServerNoticeButton, ServerNoticeBulkButton } from "./ServerNotices";
|
||||
import { DATE_FORMAT } from "./date";
|
||||
import { DeviceRemoveButton } from "./devices";
|
||||
import {
|
||||
MediaIDField,
|
||||
ProtectMediaButton,
|
||||
QuarantineMediaButton,
|
||||
} from "./media";
|
||||
import { date_format } from "./date";
|
||||
import { MediaIDField, ProtectMediaButton, QuarantineMediaButton } from "./media";
|
||||
|
||||
const choices_medium = [
|
||||
{ id: "email", name: "resources.users.email" },
|
||||
@@ -87,18 +84,12 @@ UserListActions.defaultProps = {
|
||||
onUnselectItems: () => null,
|
||||
};
|
||||
|
||||
const UserPagination = () => (
|
||||
<Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
|
||||
);
|
||||
const UserPagination = () => <Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />;
|
||||
|
||||
const userFilters = [
|
||||
<SearchInput source="name" alwaysOn />,
|
||||
<BooleanInput source="guests" alwaysOn />,
|
||||
<BooleanInput
|
||||
label="resources.users.fields.show_deactivated"
|
||||
source="deactivated"
|
||||
alwaysOn
|
||||
/>,
|
||||
<BooleanInput label="resources.users.fields.show_deactivated" source="deactivated" alwaysOn />,
|
||||
];
|
||||
|
||||
const UserBulkActionButtons = () => (
|
||||
@@ -122,22 +113,13 @@ export const UserList = (props: ListProps) => (
|
||||
pagination={<UserPagination />}
|
||||
>
|
||||
<Datagrid rowClick="edit" bulkActionButtons={<UserBulkActionButtons />}>
|
||||
<AvatarField
|
||||
source="avatar_src"
|
||||
sx={{ height: "40px", width: "40px" }}
|
||||
sortBy="avatar_url"
|
||||
/>
|
||||
<AvatarField source="avatar_src" sx={{ height: "40px", width: "40px" }} sortBy="avatar_url" />
|
||||
<TextField source="id" sortBy="name" />
|
||||
<TextField source="displayname" />
|
||||
<BooleanField source="is_guest" />
|
||||
<BooleanField source="admin" />
|
||||
<BooleanField source="deactivated" />
|
||||
<DateField
|
||||
source="creation_ts"
|
||||
label="resources.users.fields.creation_ts_ms"
|
||||
showTime
|
||||
options={date_format}
|
||||
/>
|
||||
<DateField source="creation_ts" label="resources.users.fields.creation_ts_ms" showTime options={DATE_FORMAT} />
|
||||
</Datagrid>
|
||||
</List>
|
||||
);
|
||||
@@ -146,11 +128,7 @@ export const UserList = (props: ListProps) => (
|
||||
// here only local part of user_id
|
||||
// maxLength = 255 - "@" - ":" - localStorage.getItem("home_server").length
|
||||
// localStorage.getItem("home_server").length is not valid here
|
||||
const validateUser = [
|
||||
required(),
|
||||
maxLength(253),
|
||||
regex(/^[a-z0-9._=\-/]+$/, "synapseadmin.users.invalid_user_id"),
|
||||
];
|
||||
const validateUser = [required(), maxLength(253), regex(/^[a-z0-9._=\-/]+$/, "synapseadmin.users.invalid_user_id")];
|
||||
|
||||
const validateAddress = [required(), maxLength(255)];
|
||||
|
||||
@@ -177,36 +155,19 @@ export const UserCreate = (props: CreateProps) => (
|
||||
<SimpleForm>
|
||||
<TextInput source="id" autoComplete="off" validate={validateUser} />
|
||||
<TextInput source="displayname" validate={maxLength(256)} />
|
||||
<PasswordInput
|
||||
source="password"
|
||||
autoComplete="new-password"
|
||||
validate={maxLength(512)}
|
||||
/>
|
||||
<SelectInput
|
||||
source="user_type"
|
||||
choices={choices_type}
|
||||
translateChoice={false}
|
||||
resettable
|
||||
/>
|
||||
<PasswordInput source="password" autoComplete="new-password" validate={maxLength(512)} />
|
||||
<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()}
|
||||
/>
|
||||
<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()}
|
||||
/>
|
||||
<TextInput source="external_id" label="resources.users.fields.id" validate={required()} />
|
||||
</SimpleFormIterator>
|
||||
</ArrayInput>
|
||||
</SimpleForm>
|
||||
@@ -231,42 +192,19 @@ export const UserEdit = (props: EditProps) => {
|
||||
return (
|
||||
<Edit {...props} title={<UserTitle />} actions={<UserEditActions />}>
|
||||
<TabbedForm>
|
||||
<FormTab
|
||||
label={translate("resources.users.name", { smart_count: 1 })}
|
||||
icon={<PersonPinIcon />}
|
||||
>
|
||||
<AvatarField
|
||||
source="avatar_src"
|
||||
sortable={false}
|
||||
sx={{ height: "120px", width: "120px", float: "right" }}
|
||||
/>
|
||||
<FormTab label={translate("resources.users.name", { smart_count: 1 })} icon={<PersonPinIcon />}>
|
||||
<AvatarField source="avatar_src" sortable={false} sx={{ height: "120px", width: "120px", float: "right" }} />
|
||||
<TextInput source="id" disabled />
|
||||
<TextInput source="displayname" />
|
||||
<PasswordInput
|
||||
source="password"
|
||||
autoComplete="new-password"
|
||||
helperText="resources.users.helper.password"
|
||||
/>
|
||||
<SelectInput
|
||||
source="user_type"
|
||||
choices={choices_type}
|
||||
translateChoice={false}
|
||||
resettable
|
||||
/>
|
||||
<PasswordInput source="password" autoComplete="new-password" helperText="resources.users.helper.password" />
|
||||
<SelectInput source="user_type" choices={choices_type} translateChoice={false} resettable />
|
||||
<BooleanInput source="admin" />
|
||||
<BooleanInput
|
||||
source="deactivated"
|
||||
helperText="resources.users.helper.deactivate"
|
||||
/>
|
||||
<DateField source="creation_ts_ms" showTime options={date_format} />
|
||||
<BooleanInput source="deactivated" helperText="resources.users.helper.deactivate" />
|
||||
<DateField source="creation_ts_ms" showTime options={DATE_FORMAT} />
|
||||
<TextField source="consent_version" />
|
||||
</FormTab>
|
||||
|
||||
<FormTab
|
||||
label="resources.users.threepid"
|
||||
icon={<ContactMailIcon />}
|
||||
path="threepid"
|
||||
>
|
||||
<FormTab label="resources.users.threepid" icon={<ContactMailIcon />} path="threepid">
|
||||
<ArrayInput source="threepids">
|
||||
<SimpleFormIterator disableReordering>
|
||||
<SelectInput source="medium" choices={choices_medium} />
|
||||
@@ -275,76 +213,34 @@ export const UserEdit = (props: EditProps) => {
|
||||
</ArrayInput>
|
||||
</FormTab>
|
||||
|
||||
<FormTab
|
||||
label="synapseadmin.users.tabs.sso"
|
||||
icon={<AssignmentIndIcon />}
|
||||
path="sso"
|
||||
>
|
||||
<FormTab label="synapseadmin.users.tabs.sso" icon={<AssignmentIndIcon />} path="sso">
|
||||
<ArrayInput source="external_ids" label={false}>
|
||||
<SimpleFormIterator disableReordering>
|
||||
<TextInput source="auth_provider" validate={required()} />
|
||||
<TextInput
|
||||
source="external_id"
|
||||
label="resources.users.fields.id"
|
||||
validate={required()}
|
||||
/>
|
||||
<TextInput source="external_id" label="resources.users.fields.id" validate={required()} />
|
||||
</SimpleFormIterator>
|
||||
</ArrayInput>
|
||||
</FormTab>
|
||||
|
||||
<FormTab
|
||||
label={translate("resources.devices.name", { smart_count: 2 })}
|
||||
icon={<DevicesIcon />}
|
||||
path="devices"
|
||||
>
|
||||
<ReferenceManyField
|
||||
reference="devices"
|
||||
target="user_id"
|
||||
label={false}
|
||||
>
|
||||
<FormTab label={translate("resources.devices.name", { smart_count: 2 })} icon={<DevicesIcon />} path="devices">
|
||||
<ReferenceManyField reference="devices" target="user_id" label={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={date_format}
|
||||
sortable={false}
|
||||
/>
|
||||
<DateField source="last_seen_ts" showTime options={DATE_FORMAT} sortable={false} />
|
||||
<DeviceRemoveButton />
|
||||
</Datagrid>
|
||||
</ReferenceManyField>
|
||||
</FormTab>
|
||||
|
||||
<FormTab
|
||||
label="resources.connections.name"
|
||||
icon={<SettingsInputComponentIcon />}
|
||||
path="connections"
|
||||
>
|
||||
<ReferenceField
|
||||
reference="connections"
|
||||
source="id"
|
||||
label={false}
|
||||
link={false}
|
||||
>
|
||||
<ArrayField
|
||||
source="devices[].sessions[0].connections"
|
||||
label="resources.connections.name"
|
||||
>
|
||||
<FormTab label="resources.connections.name" icon={<SettingsInputComponentIcon />} path="connections">
|
||||
<ReferenceField reference="connections" source="id" label={false} link={false}>
|
||||
<ArrayField source="devices[].sessions[0].connections" label="resources.connections.name">
|
||||
<Datagrid style={{ width: "100%" }} bulkActionButtons={false}>
|
||||
<TextField source="ip" sortable={false} />
|
||||
<DateField
|
||||
source="last_seen"
|
||||
showTime
|
||||
options={date_format}
|
||||
sortable={false}
|
||||
/>
|
||||
<TextField
|
||||
source="user_agent"
|
||||
sortable={false}
|
||||
style={{ width: "100%" }}
|
||||
/>
|
||||
<DateField source="last_seen" showTime options={DATE_FORMAT} sortable={false} />
|
||||
<TextField source="user_agent" sortable={false} style={{ width: "100%" }} />
|
||||
</Datagrid>
|
||||
</ArrayField>
|
||||
</ReferenceField>
|
||||
@@ -365,12 +261,8 @@ export const UserEdit = (props: EditProps) => {
|
||||
>
|
||||
<Datagrid style={{ width: "100%" }}>
|
||||
<MediaIDField source="media_id" />
|
||||
<DateField source="created_ts" showTime options={date_format} />
|
||||
<DateField
|
||||
source="last_access_ts"
|
||||
showTime
|
||||
options={date_format}
|
||||
/>
|
||||
<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" />
|
||||
<TextField source="upload_name" />
|
||||
@@ -382,26 +274,10 @@ export const UserEdit = (props: EditProps) => {
|
||||
</ReferenceManyField>
|
||||
</FormTab>
|
||||
|
||||
<FormTab
|
||||
label={translate("resources.rooms.name", { smart_count: 2 })}
|
||||
icon={<ViewListIcon />}
|
||||
path="rooms"
|
||||
>
|
||||
<ReferenceManyField
|
||||
reference="joined_rooms"
|
||||
target="user_id"
|
||||
label={false}
|
||||
>
|
||||
<Datagrid
|
||||
style={{ width: "100%" }}
|
||||
rowClick={id => "/rooms/" + id + "/show"}
|
||||
bulkActionButtons={false}
|
||||
>
|
||||
<TextField
|
||||
source="id"
|
||||
sortable={false}
|
||||
label="resources.rooms.fields.room_id"
|
||||
/>
|
||||
<FormTab label={translate("resources.rooms.name", { smart_count: 2 })} icon={<ViewListIcon />} path="rooms">
|
||||
<ReferenceManyField reference="joined_rooms" target="user_id" label={false}>
|
||||
<Datagrid style={{ width: "100%" }} rowClick={id => "/rooms/" + id + "/show"} bulkActionButtons={false}>
|
||||
<TextField source="id" sortable={false} label="resources.rooms.fields.room_id" />
|
||||
<ReferenceField
|
||||
label="resources.rooms.fields.name"
|
||||
source="id"
|
||||
@@ -420,11 +296,7 @@ export const UserEdit = (props: EditProps) => {
|
||||
icon={<NotificationsIcon />}
|
||||
path="pushers"
|
||||
>
|
||||
<ReferenceManyField
|
||||
reference="pushers"
|
||||
target="user_id"
|
||||
label={false}
|
||||
>
|
||||
<ReferenceManyField reference="pushers" target="user_id" label={false}>
|
||||
<Datagrid style={{ width: "100%" }} bulkActionButtons={false}>
|
||||
<TextField source="kind" sortable={false} />
|
||||
<TextField source="app_display_name" sortable={false} />
|
||||
|
||||
Reference in New Issue
Block a user