Merge tag '0.8.1' into amp.chat
Change-Id: Ice2d3474ef9284bcfea81a4e0043d798edcfaa03
This commit is contained in:
commit
364234f4f4
5
.env
Normal file
5
.env
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# This setting allows to fix the homeserver.
|
||||||
|
# If you set this setting, the user will not be able to select
|
||||||
|
# the server and have to use synapse-admin with this server.
|
||||||
|
|
||||||
|
#REACT_APP_SERVER=https://yourmatrixserver.example.com
|
@ -1,5 +1,5 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- 13
|
- lts/*
|
||||||
|
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
@ -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.27.0 for all functions to work as expected!
|
It needs at least Synapse v1.32.0 for all functions to work as expected!
|
||||||
|
|
||||||
You get your server version with the request `/_synapse/admin/v1/server_version`.
|
You get your server version with the request `/_synapse/admin/v1/server_version`.
|
||||||
See also [Synapse version API](https://github.com/matrix-org/synapse/blob/develop/docs/admin_api/version_api.rst).
|
See also [Synapse version API](https://github.com/matrix-org/synapse/blob/develop/docs/admin_api/version_api.rst).
|
||||||
@ -33,6 +33,11 @@ Steps for 1):
|
|||||||
- download dependencies: `yarn install`
|
- download dependencies: `yarn install`
|
||||||
- start web server: `yarn start`
|
- start web server: `yarn start`
|
||||||
|
|
||||||
|
You can fix the homeserver, so that the user can no longer define it himself.
|
||||||
|
Either you define it at startup (e.g. `REACT_APP_SERVER=https://yourmatrixserver.example.com yarn start`)
|
||||||
|
or by editing it in the [.env](.env) file. See also the
|
||||||
|
[documentation](https://create-react-app.dev/docs/adding-custom-environment-variables/).
|
||||||
|
|
||||||
Steps for 2):
|
Steps for 2):
|
||||||
|
|
||||||
- run the Docker container from the public docker registry: `docker run -p 8080:80 awesometechnologies/synapse-admin` or use the (docker-compose.yml)[docker-compose.yml]: `docker-compose up -d`
|
- run the Docker container from the public docker registry: `docker run -p 8080:80 awesometechnologies/synapse-admin` or use the (docker-compose.yml)[docker-compose.yml]: `docker-compose up -d`
|
||||||
|
22
package.json
22
package.json
@ -11,16 +11,14 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/jest-dom": "^5.1.1",
|
"@testing-library/jest-dom": "^5.1.1",
|
||||||
"@testing-library/react": "^10.0.2",
|
"@testing-library/react": "^11.2.6",
|
||||||
"@testing-library/user-event": "^12.0.11",
|
"@testing-library/user-event": "^13.1.8",
|
||||||
"enzyme": "^3.11.0",
|
"eslint": "^7.25.0",
|
||||||
"enzyme-adapter-react-16": "^1.15.2",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
"eslint": "^6.8.0",
|
|
||||||
"eslint-config-prettier": "^6.10.1",
|
|
||||||
"eslint-plugin-prettier": "^3.1.2",
|
"eslint-plugin-prettier": "^3.1.2",
|
||||||
"jest-fetch-mock": "^3.0.3",
|
"jest-fetch-mock": "^3.0.3",
|
||||||
"prettier": "^2.0.0",
|
"prettier": "^2.2.0",
|
||||||
"ra-test": "^3.14.0"
|
"ra-test": "^3.15.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@progress/kendo-drawing": "^1.6.0",
|
"@progress/kendo-drawing": "^1.6.0",
|
||||||
@ -30,11 +28,11 @@
|
|||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"qrcode.react": "^1.0.0",
|
"qrcode.react": "^1.0.0",
|
||||||
"ra-language-chinese": "^2.0.10",
|
"ra-language-chinese": "^2.0.10",
|
||||||
"ra-language-german": "^2.1.2",
|
"ra-language-german": "^3.13.4",
|
||||||
"react": "^17.0.0",
|
"react": "^17.0.0",
|
||||||
"react-admin": "^3.14.0",
|
"react-admin": "^3.15.0",
|
||||||
"react-dom": "^16.14.0",
|
"react-dom": "^17.0.2",
|
||||||
"react-scripts": "^3.4.4"
|
"react-scripts": "^4.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "REACT_APP_VERSION=$(git describe --tags) react-scripts start",
|
"start": "REACT_APP_VERSION=$(git describe --tags) react-scripts start",
|
||||||
|
@ -6,6 +6,7 @@ import dataProvider from "./synapse/dataProvider";
|
|||||||
import { UserList, UserCreate, UserEdit } from "./components/users";
|
import { UserList, UserCreate, UserEdit } from "./components/users";
|
||||||
import { RoomList, RoomCreate, RoomShow, RoomEdit } from "./components/rooms";
|
import { RoomList, RoomCreate, RoomShow, RoomEdit } from "./components/rooms";
|
||||||
import { ReportList, ReportShow } from "./components/EventReports";
|
import { ReportList, ReportShow } from "./components/EventReports";
|
||||||
|
import ImportFeature from "./components/ImportFeature";
|
||||||
import LoginPage from "./components/LoginPage";
|
import LoginPage from "./components/LoginPage";
|
||||||
import UserIcon from "@material-ui/icons/Group";
|
import UserIcon from "@material-ui/icons/Group";
|
||||||
import EqualizerIcon from "@material-ui/icons/Equalizer";
|
import EqualizerIcon from "@material-ui/icons/Equalizer";
|
||||||
@ -81,6 +82,7 @@ const App = () => (
|
|||||||
<Resource name="joined_rooms" />
|
<Resource name="joined_rooms" />
|
||||||
<Resource name="pushers" />
|
<Resource name="pushers" />
|
||||||
<Resource name="servernotices" />
|
<Resource name="servernotices" />
|
||||||
|
<Resource name="forward_extremities" />
|
||||||
<Resource name="room_state" />
|
<Resource name="room_state" />
|
||||||
</Admin>
|
</Admin>
|
||||||
);
|
);
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { TestContext } from "ra-test";
|
import { render } from "@testing-library/react";
|
||||||
import { shallow } from "enzyme";
|
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
|
|
||||||
describe("App", () => {
|
describe("App", () => {
|
||||||
it("renders", () => {
|
it("renders", () => {
|
||||||
shallow(
|
render(<App />);
|
||||||
<TestContext>
|
|
||||||
<App />
|
|
||||||
</TestContext>
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -82,6 +82,7 @@ const LoginPage = ({ theme }) => {
|
|||||||
const setLocale = useSetLocale();
|
const setLocale = useSetLocale();
|
||||||
const translate = useTranslate();
|
const translate = useTranslate();
|
||||||
const base_url = localStorage.getItem("base_url");
|
const base_url = localStorage.getItem("base_url");
|
||||||
|
const cfg_base_url = process.env.REACT_APP_SERVER;
|
||||||
|
|
||||||
const renderInput = ({
|
const renderInput = ({
|
||||||
meta: { touched, error } = {},
|
meta: { touched, error } = {},
|
||||||
@ -111,7 +112,9 @@ const LoginPage = ({ theme }) => {
|
|||||||
if (!values.base_url.match(/^(http|https):\/\//)) {
|
if (!values.base_url.match(/^(http|https):\/\//)) {
|
||||||
errors.base_url = translate("synapseadmin.auth.protocol_error");
|
errors.base_url = translate("synapseadmin.auth.protocol_error");
|
||||||
} else if (
|
} else if (
|
||||||
!values.base_url.match(/^(http|https):\/\/[a-zA-Z0-9\-.]+(:\d{1,5})?$/)
|
!values.base_url.match(
|
||||||
|
/^(http|https):\/\/[a-zA-Z0-9\-.]+(:\d{1,5})?[^?&\s]*$/
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
errors.base_url = translate("synapseadmin.auth.url_error");
|
errors.base_url = translate("synapseadmin.auth.url_error");
|
||||||
}
|
}
|
||||||
@ -147,7 +150,7 @@ const LoginPage = ({ theme }) => {
|
|||||||
const [serverVersion, setServerVersion] = useState("");
|
const [serverVersion, setServerVersion] = useState("");
|
||||||
|
|
||||||
const handleUsernameChange = _ => {
|
const handleUsernameChange = _ => {
|
||||||
if (formData.base_url) return;
|
if (formData.base_url || cfg_base_url) return;
|
||||||
// check if username is a full qualified userId then set base_url accordially
|
// check if username is a full qualified userId then set base_url accordially
|
||||||
const home_server = extractHomeServer(formData.username);
|
const home_server = extractHomeServer(formData.username);
|
||||||
const wellKnownUrl = `https://${home_server}/.well-known/matrix/client`;
|
const wellKnownUrl = `https://${home_server}/.well-known/matrix/client`;
|
||||||
@ -199,6 +202,7 @@ const LoginPage = ({ theme }) => {
|
|||||||
label={translate("ra.auth.username")}
|
label={translate("ra.auth.username")}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
onBlur={handleUsernameChange}
|
onBlur={handleUsernameChange}
|
||||||
|
resettable
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -209,6 +213,7 @@ const LoginPage = ({ theme }) => {
|
|||||||
label={translate("ra.auth.password")}
|
label={translate("ra.auth.password")}
|
||||||
type="password"
|
type="password"
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
|
resettable
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -217,7 +222,8 @@ const LoginPage = ({ theme }) => {
|
|||||||
name="base_url"
|
name="base_url"
|
||||||
component={renderInput}
|
component={renderInput}
|
||||||
label={translate("synapseadmin.auth.base_url")}
|
label={translate("synapseadmin.auth.base_url")}
|
||||||
disabled={loading}
|
disabled={cfg_base_url || loading}
|
||||||
|
resettable
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -228,7 +234,7 @@ const LoginPage = ({ theme }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
initialValues={{ base_url: base_url }}
|
initialValues={{ base_url: cfg_base_url || base_url }}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
validate={validate}
|
validate={validate}
|
||||||
render={({ handleSubmit }) => (
|
render={({ handleSubmit }) => (
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { render } from "@testing-library/react";
|
||||||
import { TestContext } from "ra-test";
|
import { TestContext } from "ra-test";
|
||||||
import { shallow } from "enzyme";
|
|
||||||
import LoginPage from "./LoginPage";
|
import LoginPage from "./LoginPage";
|
||||||
|
|
||||||
describe("LoginForm", () => {
|
describe("LoginForm", () => {
|
||||||
it("renders", () => {
|
it("renders", () => {
|
||||||
shallow(
|
render(
|
||||||
<TestContext>
|
<TestContext>
|
||||||
<LoginPage />
|
<LoginPage />
|
||||||
</TestContext>
|
</TestContext>
|
||||||
|
@ -171,7 +171,7 @@ const RoomDirectoryFilter = ({ ...props }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FilterableRoomDirectoryList = ({ ...props }) => {
|
export const FilterableRoomDirectoryList = ({ dispatch, ...props }) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const translate = useTranslate();
|
const translate = useTranslate();
|
||||||
const filter = props.roomDirectoryFilters;
|
const filter = props.roomDirectoryFilters;
|
||||||
@ -242,7 +242,7 @@ export const FilterableRoomDirectoryList = ({ ...props }) => {
|
|||||||
|
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state) {
|
||||||
return {
|
return {
|
||||||
roomDirectoryFilters:
|
roomdirectoryfilters:
|
||||||
state.admin.resources.room_directory.list.params.displayedFilters,
|
state.admin.resources.room_directory.list.params.displayedFilters,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
Filter,
|
Filter,
|
||||||
FormTab,
|
FormTab,
|
||||||
List,
|
List,
|
||||||
|
NumberField,
|
||||||
Pagination,
|
Pagination,
|
||||||
ReferenceArrayInput,
|
ReferenceArrayInput,
|
||||||
ReferenceField,
|
ReferenceField,
|
||||||
@ -33,10 +34,13 @@ import {
|
|||||||
Toolbar,
|
Toolbar,
|
||||||
TopToolbar,
|
TopToolbar,
|
||||||
useDataProvider,
|
useDataProvider,
|
||||||
|
useRecordContext,
|
||||||
useRefresh,
|
useRefresh,
|
||||||
useTranslate,
|
useTranslate,
|
||||||
} from "react-admin";
|
} from "react-admin";
|
||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Typography,
|
Typography,
|
||||||
@ -47,6 +51,7 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
|
import FastForwardIcon from "@material-ui/icons/FastForward";
|
||||||
import HttpsIcon from "@material-ui/icons/Https";
|
import HttpsIcon from "@material-ui/icons/Https";
|
||||||
import NoEncryptionIcon from "@material-ui/icons/NoEncryption";
|
import NoEncryptionIcon from "@material-ui/icons/NoEncryption";
|
||||||
import PageviewIcon from "@material-ui/icons/Pageview";
|
import PageviewIcon from "@material-ui/icons/Pageview";
|
||||||
@ -62,6 +67,13 @@ import {
|
|||||||
RoomDirectorySaveButton,
|
RoomDirectorySaveButton,
|
||||||
} from "./RoomDirectory";
|
} from "./RoomDirectory";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(theme => ({
|
||||||
|
helper_forward_extremities: {
|
||||||
|
fontFamily: "Roboto, Helvetica, Arial, sans-serif",
|
||||||
|
margin: "0.5em",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
const RoomPagination = props => (
|
const RoomPagination = props => (
|
||||||
<Pagination {...props} rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
|
<Pagination {...props} rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
|
||||||
);
|
);
|
||||||
@ -481,6 +493,7 @@ const RoomShowActions = ({ basePath, data, resource }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const RoomShow = props => {
|
export const RoomShow = props => {
|
||||||
|
const classes = useStyles({ props });
|
||||||
const translate = useTranslate();
|
const translate = useTranslate();
|
||||||
return (
|
return (
|
||||||
<Show {...props} actions={<RoomShowActions />} title={<RoomTitle />}>
|
<Show {...props} actions={<RoomShowActions />} title={<RoomTitle />}>
|
||||||
@ -592,6 +605,7 @@ export const RoomShow = props => {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
|
|
||||||
<Tab
|
<Tab
|
||||||
label={translate("resources.room_state.name", { smart_count: 2 })}
|
label={translate("resources.room_state.name", { smart_count: 2 })}
|
||||||
icon={<EventIcon />}
|
icon={<EventIcon />}
|
||||||
@ -628,6 +642,40 @@ export const RoomShow = props => {
|
|||||||
</Datagrid>
|
</Datagrid>
|
||||||
</ReferenceManyField>
|
</ReferenceManyField>
|
||||||
</Tab>
|
</Tab>
|
||||||
|
|
||||||
|
<Tab
|
||||||
|
label="resources.forward_extremities.name"
|
||||||
|
icon={<FastForwardIcon />}
|
||||||
|
path="forward_extremities"
|
||||||
|
>
|
||||||
|
<div className={classes.helper_forward_extremities}>
|
||||||
|
{translate("resources.rooms.helper.forward_extremities")}
|
||||||
|
</div>
|
||||||
|
<ReferenceManyField
|
||||||
|
reference="forward_extremities"
|
||||||
|
target="room_id"
|
||||||
|
addLabel={false}
|
||||||
|
>
|
||||||
|
<Datagrid style={{ width: "100%" }}>
|
||||||
|
<TextField source="id" sortable={false} />
|
||||||
|
<DateField
|
||||||
|
source="received_ts"
|
||||||
|
showTime
|
||||||
|
options={{
|
||||||
|
year: "numeric",
|
||||||
|
month: "2-digit",
|
||||||
|
day: "2-digit",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
second: "2-digit",
|
||||||
|
}}
|
||||||
|
sortable={false}
|
||||||
|
/>
|
||||||
|
<NumberField source="depth" sortable={false} />
|
||||||
|
<TextField source="state_group" sortable={false} />
|
||||||
|
</Datagrid>
|
||||||
|
</ReferenceManyField>
|
||||||
|
</Tab>
|
||||||
</TabbedShowLayout>
|
</TabbedShowLayout>
|
||||||
</Show>
|
</Show>
|
||||||
);
|
);
|
||||||
@ -679,8 +727,22 @@ const RoomFilter = ({ ...props }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const FilterableRoomList = ({ ...props }) => {
|
const RoomNameField = props => {
|
||||||
const filter = props.roomFilters;
|
const { source } = props;
|
||||||
|
const record = useRecordContext(props);
|
||||||
|
return (
|
||||||
|
<span>{record[source] || record["canonical_alias"] || record["id"]}</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
RoomNameField.propTypes = {
|
||||||
|
label: PropTypes.string,
|
||||||
|
record: PropTypes.object,
|
||||||
|
source: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
const FilterableRoomList = ({ roomFilters, dispatch, ...props }) => {
|
||||||
|
const filter = roomFilters;
|
||||||
const localMembersFilter =
|
const localMembersFilter =
|
||||||
filter && filter.joined_local_members ? true : false;
|
filter && filter.joined_local_members ? true : false;
|
||||||
const stateEventsFilter = filter && filter.state_events ? true : false;
|
const stateEventsFilter = filter && filter.state_events ? true : false;
|
||||||
@ -701,7 +763,7 @@ const FilterableRoomList = ({ ...props }) => {
|
|||||||
sortBy="encryption"
|
sortBy="encryption"
|
||||||
label={<HttpsIcon />}
|
label={<HttpsIcon />}
|
||||||
/>
|
/>
|
||||||
<TextField source="name" />
|
<RoomNameField source="name" />
|
||||||
<TextField source="joined_members" />
|
<TextField source="joined_members" />
|
||||||
{localMembersFilter && <TextField source="joined_local_members" />}
|
{localMembersFilter && <TextField source="joined_local_members" />}
|
||||||
{stateEventsFilter && <TextField source="state_events" />}
|
{stateEventsFilter && <TextField source="state_events" />}
|
||||||
|
@ -158,6 +158,7 @@ export const UserList = props => {
|
|||||||
{...props}
|
{...props}
|
||||||
filters={<UserFilter />}
|
filters={<UserFilter />}
|
||||||
filterDefaultValues={{ guests: true, deactivated: false }}
|
filterDefaultValues={{ guests: true, deactivated: false }}
|
||||||
|
sort={{ field: "name", order: "ASC" }}
|
||||||
actions={<UserListActions maxResults={10000} />}
|
actions={<UserListActions maxResults={10000} />}
|
||||||
bulkActionButtons={<UserBulkActionButtons />}
|
bulkActionButtons={<UserBulkActionButtons />}
|
||||||
pagination={<UserPagination />}
|
pagination={<UserPagination />}
|
||||||
@ -165,13 +166,13 @@ export const UserList = props => {
|
|||||||
<Datagrid rowClick="edit">
|
<Datagrid rowClick="edit">
|
||||||
<AvatarField
|
<AvatarField
|
||||||
source="avatar_src"
|
source="avatar_src"
|
||||||
sortable={false}
|
|
||||||
className={classes.small}
|
className={classes.small}
|
||||||
|
sortBy="avatar_url"
|
||||||
/>
|
/>
|
||||||
<TextField source="id" sortable={false} />
|
<TextField source="id" sortBy="name" />
|
||||||
<TextField source="displayname" />
|
<TextField source="displayname" />
|
||||||
<BooleanField source="is_guest" sortable={false} />
|
<BooleanField source="is_guest" />
|
||||||
<BooleanField source="admin" sortable={false} />
|
<BooleanField source="admin" />
|
||||||
<SelectField
|
<SelectField
|
||||||
source="user_type"
|
source="user_type"
|
||||||
choices={[
|
choices={[
|
||||||
@ -180,7 +181,7 @@ export const UserList = props => {
|
|||||||
{ id: "limited", name: "resources.users.type.limited" },
|
{ id: "limited", name: "resources.users.type.limited" },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<BooleanField source="deactivated" sortable={false} />
|
<BooleanField source="deactivated" />
|
||||||
</Datagrid>
|
</Datagrid>
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
@ -480,6 +481,7 @@ export const UserEdit = props => {
|
|||||||
addLabel={false}
|
addLabel={false}
|
||||||
pagination={<UserPagination />}
|
pagination={<UserPagination />}
|
||||||
perPage={50}
|
perPage={50}
|
||||||
|
sort={{ field: "created_ts", order: "DESC" }}
|
||||||
>
|
>
|
||||||
<Datagrid style={{ width: "100%" }}>
|
<Datagrid style={{ width: "100%" }}>
|
||||||
<DateField
|
<DateField
|
||||||
@ -493,7 +495,6 @@ export const UserEdit = props => {
|
|||||||
minute: "2-digit",
|
minute: "2-digit",
|
||||||
second: "2-digit",
|
second: "2-digit",
|
||||||
}}
|
}}
|
||||||
sortable={false}
|
|
||||||
/>
|
/>
|
||||||
<DateField
|
<DateField
|
||||||
source="last_access_ts"
|
source="last_access_ts"
|
||||||
@ -506,14 +507,13 @@ export const UserEdit = props => {
|
|||||||
minute: "2-digit",
|
minute: "2-digit",
|
||||||
second: "2-digit",
|
second: "2-digit",
|
||||||
}}
|
}}
|
||||||
sortable={false}
|
|
||||||
/>
|
/>
|
||||||
<TextField source="media_id" sortable={false} />
|
<TextField source="media_id" />
|
||||||
<NumberField source="media_length" sortable={false} />
|
<NumberField source="media_length" />
|
||||||
<TextField source="media_type" sortable={false} />
|
<TextField source="media_type" />
|
||||||
<TextField source="upload_name" sortable={false} />
|
<TextField source="upload_name" />
|
||||||
<TextField source="quarantined_by" sortable={false} />
|
<TextField source="quarantined_by" />
|
||||||
<BooleanField source="safe_from_quarantine" sortable={false} />
|
<BooleanField source="safe_from_quarantine" />
|
||||||
<DeleteButton mutationMode="pessimistic" redirect={false} />
|
<DeleteButton mutationMode="pessimistic" redirect={false} />
|
||||||
</Datagrid>
|
</Datagrid>
|
||||||
</ReferenceManyField>
|
</ReferenceManyField>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import germanMessages from "ra-language-german";
|
import germanMessages from "ra-language-german";
|
||||||
|
|
||||||
export default {
|
const de = {
|
||||||
...germanMessages,
|
...germanMessages,
|
||||||
synapseadmin: {
|
synapseadmin: {
|
||||||
auth: {
|
auth: {
|
||||||
@ -186,6 +186,10 @@ export default {
|
|||||||
topic: "Thema",
|
topic: "Thema",
|
||||||
avatar: "Avatar",
|
avatar: "Avatar",
|
||||||
},
|
},
|
||||||
|
helper: {
|
||||||
|
forward_extremities:
|
||||||
|
"Forward extremities are the leaf events at the end of a Directed acyclic graph (DAG) in a room, aka events that have no children. The more exist in a room, the more state resolution that Synapse needs to perform (hint: it's an expensive operation). While Synapse has code to prevent too many of these existing at one time in a room, bugs can sometimes make them crop up again. If a room has >10 forward extremities, it's worth checking which room is the culprit and potentially removing them using the SQL queries mentioned in #1760.",
|
||||||
|
},
|
||||||
enums: {
|
enums: {
|
||||||
join_rules: {
|
join_rules: {
|
||||||
public: "Öffentlich",
|
public: "Öffentlich",
|
||||||
@ -329,6 +333,15 @@ export default {
|
|||||||
media_length: "Größe der Dateien",
|
media_length: "Größe der Dateien",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
forward_extremities: {
|
||||||
|
name: "Vorderextremitäten",
|
||||||
|
fields: {
|
||||||
|
id: "Event-ID",
|
||||||
|
received_ts: "Zeitstempel",
|
||||||
|
depth: "Tiefe",
|
||||||
|
state_group: "Zustandsgruppe",
|
||||||
|
},
|
||||||
|
},
|
||||||
room_state: {
|
room_state: {
|
||||||
name: "Zustandsereignisse",
|
name: "Zustandsereignisse",
|
||||||
fields: {
|
fields: {
|
||||||
@ -383,5 +396,10 @@ export default {
|
|||||||
empty: "Keine Einträge vorhanden",
|
empty: "Keine Einträge vorhanden",
|
||||||
invite: "",
|
invite: "",
|
||||||
},
|
},
|
||||||
|
navigation: {
|
||||||
|
...germanMessages.ra.navigation,
|
||||||
|
skip_nav: "Zum Inhalt springen",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
export default de;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import englishMessages from "ra-language-english";
|
import englishMessages from "ra-language-english";
|
||||||
|
|
||||||
export default {
|
const en = {
|
||||||
...englishMessages,
|
...englishMessages,
|
||||||
synapseadmin: {
|
synapseadmin: {
|
||||||
auth: {
|
auth: {
|
||||||
@ -184,6 +184,10 @@ export default {
|
|||||||
topic: "Topic",
|
topic: "Topic",
|
||||||
avatar: "Avatar",
|
avatar: "Avatar",
|
||||||
},
|
},
|
||||||
|
helper: {
|
||||||
|
forward_extremities:
|
||||||
|
"Forward extremities are the leaf events at the end of a Directed acyclic graph (DAG) in a room, aka events that have no children. The more exist in a room, the more state resolution that Synapse needs to perform (hint: it's an expensive operation). While Synapse has code to prevent too many of these existing at one time in a room, bugs can sometimes make them crop up again. If a room has >10 forward extremities, it's worth checking which room is the culprit and potentially removing them using the SQL queries mentioned in #1760.",
|
||||||
|
},
|
||||||
enums: {
|
enums: {
|
||||||
join_rules: {
|
join_rules: {
|
||||||
public: "Public",
|
public: "Public",
|
||||||
@ -262,7 +266,7 @@ export default {
|
|||||||
name: "Media",
|
name: "Media",
|
||||||
fields: {
|
fields: {
|
||||||
media_id: "Media ID",
|
media_id: "Media ID",
|
||||||
media_length: "Lenght",
|
media_length: "File Size (in Bytes)",
|
||||||
media_type: "Type",
|
media_type: "Type",
|
||||||
upload_name: "File name",
|
upload_name: "File name",
|
||||||
quarantined_by: "Quarantined by",
|
quarantined_by: "Quarantined by",
|
||||||
@ -325,6 +329,15 @@ export default {
|
|||||||
media_length: "Media length",
|
media_length: "Media length",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
forward_extremities: {
|
||||||
|
name: "Forward Extremities",
|
||||||
|
fields: {
|
||||||
|
id: "Event ID",
|
||||||
|
received_ts: "Timestamp",
|
||||||
|
depth: "Depth",
|
||||||
|
state_group: "State group",
|
||||||
|
},
|
||||||
|
},
|
||||||
room_state: {
|
room_state: {
|
||||||
name: "State events",
|
name: "State events",
|
||||||
fields: {
|
fields: {
|
||||||
@ -353,3 +366,4 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
export default en;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import chineseMessages from "ra-language-chinese";
|
import chineseMessages from "ra-language-chinese";
|
||||||
|
|
||||||
export default {
|
const zh = {
|
||||||
...chineseMessages,
|
...chineseMessages,
|
||||||
synapseadmin: {
|
synapseadmin: {
|
||||||
auth: {
|
auth: {
|
||||||
@ -288,3 +288,4 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
export default zh;
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
import { configure } from "enzyme";
|
|
||||||
import Adapter from "enzyme-adapter-react-16";
|
|
||||||
import fetchMock from "jest-fetch-mock";
|
import fetchMock from "jest-fetch-mock";
|
||||||
|
|
||||||
configure({ adapter: new Adapter() });
|
|
||||||
fetchMock.enableMocks();
|
fetchMock.enableMocks();
|
||||||
|
@ -3,6 +3,9 @@ import { fetchUtils } from "react-admin";
|
|||||||
const authProvider = {
|
const authProvider = {
|
||||||
// called when the user attempts to log in
|
// called when the user attempts to log in
|
||||||
login: ({ base_url, username, password }) => {
|
login: ({ base_url, username, password }) => {
|
||||||
|
// force homeserver for protection in case the form is manipulated
|
||||||
|
base_url = process.env.REACT_APP_SERVER || base_url;
|
||||||
|
|
||||||
console.log("login ");
|
console.log("login ");
|
||||||
const options = {
|
const options = {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@ -10,6 +13,7 @@ const authProvider = {
|
|||||||
type: "m.login.password",
|
type: "m.login.password",
|
||||||
user: username,
|
user: username,
|
||||||
password: password,
|
password: password,
|
||||||
|
device_id: localStorage.getItem("device_id"),
|
||||||
initial_device_display_name: "Synapse Admin",
|
initial_device_display_name: "Synapse Admin",
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
@ -17,6 +21,7 @@ const authProvider = {
|
|||||||
// use the base_url from login instead of the well_known entry from the
|
// use the base_url from login instead of the well_known entry from the
|
||||||
// server, since the admin might want to access the admin API via some
|
// server, since the admin might want to access the admin API via some
|
||||||
// private address
|
// private address
|
||||||
|
base_url = base_url.replace(/\/+$/g, "");
|
||||||
localStorage.setItem("base_url", base_url);
|
localStorage.setItem("base_url", base_url);
|
||||||
|
|
||||||
const decoded_base_url = window.decodeURIComponent(base_url);
|
const decoded_base_url = window.decodeURIComponent(base_url);
|
||||||
@ -48,7 +53,6 @@ const authProvider = {
|
|||||||
if (typeof access_token === "string") {
|
if (typeof access_token === "string") {
|
||||||
fetchUtils.fetchJson(logout_api_url, options).then(({ json }) => {
|
fetchUtils.fetchJson(logout_api_url, options).then(({ json }) => {
|
||||||
localStorage.removeItem("access_token");
|
localStorage.removeItem("access_token");
|
||||||
localStorage.removeItem("device_id");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
@ -248,6 +248,22 @@ const resourceMap = {
|
|||||||
return json.total;
|
return json.total;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
forward_extremities: {
|
||||||
|
map: fe => ({
|
||||||
|
...fe,
|
||||||
|
id: fe.event_id,
|
||||||
|
}),
|
||||||
|
reference: id => ({
|
||||||
|
endpoint: `/_synapse/admin/v1/rooms/${id}/forward_extremities`,
|
||||||
|
}),
|
||||||
|
data: "results",
|
||||||
|
total: json => {
|
||||||
|
return json.count;
|
||||||
|
},
|
||||||
|
delete: params => ({
|
||||||
|
endpoint: `/_synapse/admin/v1/rooms/${params.id}/forward_extremities`,
|
||||||
|
}),
|
||||||
|
},
|
||||||
room_directory: {
|
room_directory: {
|
||||||
path: "/_matrix/client/r0/publicRooms",
|
path: "/_matrix/client/r0/publicRooms",
|
||||||
map: rd => ({
|
map: rd => ({
|
||||||
@ -354,10 +370,13 @@ const dataProvider = {
|
|||||||
getManyReference: (resource, params) => {
|
getManyReference: (resource, params) => {
|
||||||
console.log("getManyReference " + resource);
|
console.log("getManyReference " + resource);
|
||||||
const { page, perPage } = params.pagination;
|
const { page, perPage } = params.pagination;
|
||||||
|
const { field, order } = params.sort;
|
||||||
const from = (page - 1) * perPage;
|
const from = (page - 1) * perPage;
|
||||||
const query = {
|
const query = {
|
||||||
from: from,
|
from: from,
|
||||||
limit: perPage,
|
limit: perPage,
|
||||||
|
order_by: field,
|
||||||
|
dir: getSearchOrder(order),
|
||||||
};
|
};
|
||||||
|
|
||||||
const homeserver = localStorage.getItem("base_url");
|
const homeserver = localStorage.getItem("base_url");
|
||||||
|
Loading…
Reference in New Issue
Block a user