Compare commits

5 Commits

5 changed files with 35 additions and 25 deletions

View File

@@ -25,11 +25,15 @@ run-dev:
stop-dev: stop-dev:
@docker-compose -f docker-compose-dev.yml stop @docker-compose -f docker-compose-dev.yml stop
# register a user in the dev stack
register-user localpart password *admin: register-user localpart password *admin:
docker-compose exec synapse register_new_matrix_user {{ if admin == "1" {"--admin"} else {"--no-admin"} }} -u {{ localpart }} -p {{ password }} -c /config/homeserver.yaml http://localhost:8008 docker-compose exec synapse register_new_matrix_user {{ if admin == "1" {"--admin"} else {"--no-admin"} }} -u {{ localpart }} -p {{ password }} -c /config/homeserver.yaml http://localhost:8008
# run yarn {fix,lint,test} commands
test:
@-yarn run fix
@-yarn run lint
@-yarn run test
# run the app in a production mode # run the app in a production mode
run-prod: build run-prod: build

View File

@@ -1,12 +1,11 @@
import { get } from "lodash"; import { get } from "lodash";
import { Avatar, AvatarProps } from "@mui/material"; import { Avatar, AvatarProps } from "@mui/material";
import { useRecordContext } from "react-admin"; import { FieldProps, useRecordContext } from "react-admin";
import { useState, useEffect, useCallback } from "react"; import { useState, useEffect, useCallback } from "react";
import { fetchAuthenticatedMedia } from "../utils/fetchMedia"; import { fetchAuthenticatedMedia } from "../utils/fetchMedia";
const AvatarField = ({ source, ...rest }: AvatarProps & { source: string, label?: string }) => { const AvatarField = ({ source, ...rest }: AvatarProps & FieldProps) => {
const { alt, classes, sizes, sx, variant } = rest; const { alt, classes, sizes, sx, variant } = rest;
const record = useRecordContext(rest); const record = useRecordContext(rest);
const mxcURL = get(record, source)?.toString(); const mxcURL = get(record, source)?.toString();

View File

@@ -88,7 +88,7 @@ const LoginPage = () => {
const notify = useNotify(); const notify = useNotify();
const { restrictBaseUrl } = useAppContext(); const { restrictBaseUrl } = useAppContext();
const allowSingleBaseUrl = typeof restrictBaseUrl === "string"; const allowSingleBaseUrl = typeof restrictBaseUrl === "string";
const allowMultipleBaseUrls = Array.isArray(restrictBaseUrl); const allowMultipleBaseUrls = (Array.isArray(restrictBaseUrl) && restrictBaseUrl.length > 0 && restrictBaseUrl[0] !== "" && restrictBaseUrl[0] !== null);
const allowAnyBaseUrl = !(allowSingleBaseUrl || allowMultipleBaseUrls); const allowAnyBaseUrl = !(allowSingleBaseUrl || allowMultipleBaseUrls);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [supportPassAuth, setSupportPassAuth] = useState(true); const [supportPassAuth, setSupportPassAuth] = useState(true);

View File

@@ -4,6 +4,7 @@ import AutorenewIcon from "@mui/icons-material/Autorenew";
import DestinationsIcon from "@mui/icons-material/CloudQueue"; import DestinationsIcon from "@mui/icons-material/CloudQueue";
import FolderSharedIcon from "@mui/icons-material/FolderShared"; import FolderSharedIcon from "@mui/icons-material/FolderShared";
import ViewListIcon from "@mui/icons-material/ViewList"; import ViewListIcon from "@mui/icons-material/ViewList";
import ErrorIcon from '@mui/icons-material/Error';
import { import {
Button, Button,
Datagrid, Datagrid,
@@ -21,6 +22,7 @@ import {
Tab, Tab,
TabbedShowLayout, TabbedShowLayout,
TextField, TextField,
FunctionField,
TopToolbar, TopToolbar,
useRecordContext, useRecordContext,
useDelete, useDelete,
@@ -35,13 +37,6 @@ import { get } from "lodash";
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 ? "warning.light" : "primary.contrastText",
"& .MuiButtonBase-root": {
color: "primary.dark",
},
});
const destinationFilters = [<SearchInput source="destination" alwaysOn />]; const destinationFilters = [<SearchInput source="destination" alwaysOn />];
export const DestinationReconnectButton = () => { export const DestinationReconnectButton = () => {
@@ -105,7 +100,22 @@ const RetryDateField = (props: DateFieldProps) => {
return <DateField {...props} />; return <DateField {...props} />;
}; };
const destinationFieldRender = (record: RaRecord) => {
if (record.retry_last_ts > 0) {
return (
<>
<ErrorIcon fontSize="inherit" color="error" sx={{verticalAlign: "middle"}}/>
{record.destination}
</>
);
}
return <> {record.destination} </>;
}
export const DestinationList = (props: ListProps) => { export const DestinationList = (props: ListProps) => {
const record = useRecordContext(props);
return ( return (
<List <List
{...props} {...props}
@@ -113,8 +123,8 @@ export const DestinationList = (props: ListProps) => {
pagination={<DestinationPagination />} pagination={<DestinationPagination />}
sort={{ field: "destination", order: "ASC" }} sort={{ field: "destination", order: "ASC" }}
> >
<Datagrid rowSx={destinationRowSx} rowClick={id => `${id}/show/rooms`} bulkActionButtons={false}> <Datagrid rowClick={id => `${id}/show/rooms`} bulkActionButtons={false}>
<TextField source="destination" /> <FunctionField source="destination" render={destinationFieldRender} />
<DateField source="failure_ts" showTime options={DATE_FORMAT} /> <DateField source="failure_ts" showTime options={DATE_FORMAT} />
<RetryDateField source="retry_last_ts" showTime options={DATE_FORMAT} /> <RetryDateField source="retry_last_ts" showTime options={DATE_FORMAT} />
<TextField source="retry_interval" /> <TextField source="retry_interval" />

View File

@@ -51,8 +51,8 @@ import {
NumberField, NumberField,
useListContext, useListContext,
useNotify, useNotify,
ToolbarClasses,
Identifier, Identifier,
ToolbarClasses,
RaRecord, RaRecord,
ImageInput, ImageInput,
ImageField, ImageField,
@@ -147,10 +147,6 @@ const UserBulkActionButtons = () => {
); );
}; };
const usersRowClick = (id: Identifier, resource: string, record: RaRecord): string => {
return `/users/${id}`;
};
export const UserList = (props: ListProps) => ( export const UserList = (props: ListProps) => (
<List <List
{...props} {...props}
@@ -160,8 +156,11 @@ export const UserList = (props: ListProps) => (
actions={<UserListActions />} actions={<UserListActions />}
pagination={<UserPagination />} pagination={<UserPagination />}
> >
<Datagrid rowClick={usersRowClick} bulkActionButtons={<UserBulkActionButtons />}> <Datagrid
<AvatarField source="avatar_src" sx={{ height: "40px", width: "40px" }} /> rowClick={(id: Identifier, resource: string) => `/${resource}/${id}`}
bulkActionButtons={<UserBulkActionButtons />}
>
<AvatarField source="avatar_src" sx={{ height: "40px", width: "40px" }} sortBy="avatar_url" />
<TextField source="id" sortBy="name" /> <TextField source="id" sortBy="name" />
<TextField source="displayname" /> <TextField source="displayname" />
<BooleanField source="is_guest" /> <BooleanField source="is_guest" />
@@ -212,9 +211,7 @@ const UserEditActions = () => {
export const UserCreate = (props: CreateProps) => ( export const UserCreate = (props: CreateProps) => (
<Create <Create
{...props} {...props}
redirect={(resource, id, data) => { redirect={(resource: string | undefined, id: Identifier | undefined) => `${resource}/${id}`}
return `users/${id}`;
}}
> >
<SimpleForm> <SimpleForm>
<TextInput source="id" autoComplete="off" validate={validateUser} /> <TextInput source="id" autoComplete="off" validate={validateUser} />