Add "Assign Admin" button to the rooms (#156)
* wip on make admin button * Finish assign admin button * fixes from pr * update readme; remove unnecessary console.log; add assign admin to room directory and room view; rename user_id label; set own MXID by default; fix room name display when there is no name
This commit is contained in:
parent
dae6872fe8
commit
cb1314ab1d
@ -97,6 +97,7 @@ The following changes are already implemented:
|
|||||||
* 🛑 [Prevent accidental user overwrites](https://github.com/etkecc/synapse-admin/pull/139)
|
* 🛑 [Prevent accidental user overwrites](https://github.com/etkecc/synapse-admin/pull/139)
|
||||||
* 🔍 [Allow providing login form details via GET params](https://github.com/etkecc/synapse-admin/pull/140)
|
* 🔍 [Allow providing login form details via GET params](https://github.com/etkecc/synapse-admin/pull/140)
|
||||||
* 🎨 [Add preferred theme colors to login page and footer](https://github.com/etkecc/synapse-admin/pull/155)
|
* 🎨 [Add preferred theme colors to login page and footer](https://github.com/etkecc/synapse-admin/pull/155)
|
||||||
|
* 🔰 [Add "Assign Admin" button to the rooms](https://github.com/etkecc/synapse-admin/pull/156)
|
||||||
|
|
||||||
_the list will be updated as new changes are added_
|
_the list will be updated as new changes are added_
|
||||||
|
|
||||||
|
@ -13,8 +13,6 @@ const Footer = () => {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
console.log(theme);
|
|
||||||
|
|
||||||
return (<Box
|
return (<Box
|
||||||
component="footer"
|
component="footer"
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -260,6 +260,14 @@ const de: SynapseTranslationMessages = {
|
|||||||
success: "Raum/Räume erfolgreich gelöscht.",
|
success: "Raum/Räume erfolgreich gelöscht.",
|
||||||
failure: "Der/die Raum/Räume konnten nicht gelöscht werden.",
|
failure: "Der/die Raum/Räume konnten nicht gelöscht werden.",
|
||||||
},
|
},
|
||||||
|
make_admin: {
|
||||||
|
assign_admin: "Raumadministrator zuweisen",
|
||||||
|
title: "Raumadministrator zu %{roomName} zuweisen",
|
||||||
|
confirm: "Raumadministrator zuweisen",
|
||||||
|
content: "Geben Sie die vollständige MXID des Benutzers an, der als Administrator gesetzt werden soll.\nWarnung: Damit dies funktioniert, muss der Raum mindestens einen lokalen Mitglied als Administrator haben.",
|
||||||
|
success: "Der/die Benutzer wurde/n als Raumadministrator gesetzt.",
|
||||||
|
failure: "Der/die Benutzer konnte/n nicht als Raumadministrator gesetzt werden. %{errMsg}",
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
reports: {
|
reports: {
|
||||||
|
@ -38,7 +38,7 @@ const en: SynapseTranslationMessages = {
|
|||||||
members: "Members",
|
members: "Members",
|
||||||
detail: "Details",
|
detail: "Details",
|
||||||
permission: "Permissions",
|
permission: "Permissions",
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
reports: { tabs: { basic: "Basic", detail: "Details" } },
|
reports: { tabs: { basic: "Basic", detail: "Details" } },
|
||||||
},
|
},
|
||||||
@ -233,6 +233,14 @@ const en: SynapseTranslationMessages = {
|
|||||||
success: "Room/s successfully deleted.",
|
success: "Room/s successfully deleted.",
|
||||||
failure: "The room/s could not be deleted.",
|
failure: "The room/s could not be deleted.",
|
||||||
},
|
},
|
||||||
|
make_admin: {
|
||||||
|
assign_admin: "Assign admin",
|
||||||
|
title: "Assign a room admin to %{roomName}",
|
||||||
|
confirm: "Make admin",
|
||||||
|
content: "Put the full MXID of the user which will be set as admin.\nWarning: for this to work, the room needs to have at least one local member as admin.",
|
||||||
|
success: "The user has been set as room admin.",
|
||||||
|
failure: "The user could not be set as room admin. %{errMsg}",
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
reports: {
|
reports: {
|
||||||
|
@ -225,6 +225,14 @@ const fa: SynapseTranslationMessages = {
|
|||||||
success: "اتاق با موفقیت حذف شد.",
|
success: "اتاق با موفقیت حذف شد.",
|
||||||
failure: "خطایی رخ داده است.",
|
failure: "خطایی رخ داده است.",
|
||||||
},
|
},
|
||||||
|
make_admin: {
|
||||||
|
assign_admin: "مدیر انتخاب کنید",
|
||||||
|
title: "مدیر اتاق %{roomName} را انتخاب کنید",
|
||||||
|
confirm: "مدیر انتخاب کنید",
|
||||||
|
content: "کامل MXID کاربری را وارد کنید که به عنوان مدیر تنظیم شود.\nهشدار: برای این کار، اتاق باید حداقل یک اعضای محلی به عنوان مدیر داشته باشد.",
|
||||||
|
success: "کاربر به عنوان مدیر اتاق تنظیم شد.",
|
||||||
|
failure: "کاربر به عنوان مدیر اتاق تنظیم نشد. %{errMsg}",
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
reports: {
|
reports: {
|
||||||
|
@ -227,6 +227,14 @@ const fr: SynapseTranslationMessages = {
|
|||||||
success: "Salle/s supprimées avec succès.",
|
success: "Salle/s supprimées avec succès.",
|
||||||
failure: "La/les salle/s n'ont pas pu être supprimées.",
|
failure: "La/les salle/s n'ont pas pu être supprimées.",
|
||||||
},
|
},
|
||||||
|
make_admin: {
|
||||||
|
assign_admin: "Assigner un administrateur",
|
||||||
|
title: "Assigner un administrateur au salon %{roomName}",
|
||||||
|
confirm: "Assigner un administrateur",
|
||||||
|
content: "Entrez la MXID complète de l'utilisateur qui sera désigné comme administrateur.\nAttention : pour que cela fonctionne, la salle doit avoir au moins un membre local en tant qu'administrateur.",
|
||||||
|
success: "L'utilisateur a été désigné comme administrateur de la salle.",
|
||||||
|
failure: "L'utilisateur n'a pas pu être désigné comme administrateur de la salle. %{errMsg}",
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
reports: {
|
reports: {
|
||||||
|
8
src/i18n/index.d.ts
vendored
8
src/i18n/index.d.ts
vendored
@ -223,6 +223,14 @@ interface SynapseTranslationMessages extends TranslationMessages {
|
|||||||
success: string;
|
success: string;
|
||||||
failure: string;
|
failure: string;
|
||||||
};
|
};
|
||||||
|
make_admin: {
|
||||||
|
assign_admin: string;
|
||||||
|
title: string;
|
||||||
|
confirm: string;
|
||||||
|
content: string;
|
||||||
|
success: string;
|
||||||
|
failure: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
reports: {
|
reports: {
|
||||||
|
@ -221,6 +221,14 @@ const it: SynapseTranslationMessages = {
|
|||||||
content:
|
content:
|
||||||
"Sei sicuro di voler eliminare questa stanza? Questa azione è definitiva. Tutti i messaggi e i media condivisi in questa stanza verranno eliminati dal server!",
|
"Sei sicuro di voler eliminare questa stanza? Questa azione è definitiva. Tutti i messaggi e i media condivisi in questa stanza verranno eliminati dal server!",
|
||||||
},
|
},
|
||||||
|
make_admin: {
|
||||||
|
assign_admin: "Assegna un amministratore",
|
||||||
|
title: "Assegna un amministratore alla stanza %{roomName}",
|
||||||
|
confirm: "Assegna un amministratore",
|
||||||
|
content: "Inserisci la MXID completa dell'utente che sarà designato come amministratore.\nAttenzione: per questo funzionare, la stanza deve avere almeno un membro locale come amministratore.",
|
||||||
|
success: "L'utente è stato designato come amministratore della stanza.",
|
||||||
|
failure: "L'utente non può essere designato come amministratore della stanza. %{errMsg}",
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
reports: {
|
reports: {
|
||||||
|
@ -266,6 +266,14 @@ const ru: SynapseTranslationMessages = {
|
|||||||
success: "Комната/ы успешно удалены",
|
success: "Комната/ы успешно удалены",
|
||||||
failure: "Комната/ы не могут быть удалены.",
|
failure: "Комната/ы не могут быть удалены.",
|
||||||
},
|
},
|
||||||
|
make_admin: {
|
||||||
|
assign_admin: "Назначить администратора",
|
||||||
|
title: "Назначить администратора комнате %{roomName}",
|
||||||
|
confirm: "Назначить администратора",
|
||||||
|
content: "Введите полную MXID пользователя, которого нужно назначить администратором.\nПредупреждение: для этого должен быть назначен хотя бы один локальный участник в качестве администратора.",
|
||||||
|
success: "Пользователь назначен администратором комнаты.",
|
||||||
|
failure: "Пользователь не может быть назначен администратором комнаты. %{errMsg}",
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
reports: {
|
reports: {
|
||||||
|
@ -27,8 +27,7 @@ import {
|
|||||||
} from "react-admin";
|
} from "react-admin";
|
||||||
import { useMutation } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import AvatarField from "../components/AvatarField";
|
import AvatarField from "../components/AvatarField";
|
||||||
|
import { MakeAdminBtn } from "./rooms";
|
||||||
|
|
||||||
const RoomDirectoryPagination = () => <Pagination rowsPerPageOptions={[100, 500, 1000, 2000]} />;
|
const RoomDirectoryPagination = () => <Pagination rowsPerPageOptions={[100, 500, 1000, 2000]} />;
|
||||||
|
|
||||||
export const RoomDirectoryUnpublishButton = (props: DeleteButtonProps) => {
|
export const RoomDirectoryUnpublishButton = (props: DeleteButtonProps) => {
|
||||||
@ -154,6 +153,7 @@ export const RoomDirectoryList = () => (
|
|||||||
<NumberField source="num_joined_members" sortable={false} label="resources.rooms.fields.joined_members" />
|
<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="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" />
|
<BooleanField source="guest_can_join" sortable={false} label="resources.room_directory.fields.guest_can_join" />
|
||||||
|
<MakeAdminBtn />
|
||||||
</DatagridConfigurable>
|
</DatagridConfigurable>
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
|
@ -11,11 +11,11 @@ import Box from "@mui/material/Box";
|
|||||||
import { useTheme } from "@mui/material/styles";
|
import { useTheme } from "@mui/material/styles";
|
||||||
import {
|
import {
|
||||||
BooleanField,
|
BooleanField,
|
||||||
BulkDeleteButton,
|
|
||||||
DateField,
|
DateField,
|
||||||
|
EditButton,
|
||||||
|
WrapperField,
|
||||||
Datagrid,
|
Datagrid,
|
||||||
DatagridConfigurable,
|
DatagridConfigurable,
|
||||||
DeleteButton,
|
|
||||||
ExportButton,
|
ExportButton,
|
||||||
FunctionField,
|
FunctionField,
|
||||||
List,
|
List,
|
||||||
@ -32,13 +32,15 @@ import {
|
|||||||
ShowProps,
|
ShowProps,
|
||||||
Tab,
|
Tab,
|
||||||
TabbedShowLayout,
|
TabbedShowLayout,
|
||||||
TextField,
|
TextField as RaTextField,
|
||||||
TopToolbar,
|
TopToolbar,
|
||||||
useRecordContext,
|
useRecordContext,
|
||||||
useTranslate,
|
useTranslate,
|
||||||
useListContext,
|
useListContext,
|
||||||
|
useNotify,
|
||||||
} from "react-admin";
|
} from "react-admin";
|
||||||
|
|
||||||
|
import TextField from "@mui/material/TextField";
|
||||||
import {
|
import {
|
||||||
RoomDirectoryBulkUnpublishButton,
|
RoomDirectoryBulkUnpublishButton,
|
||||||
RoomDirectoryBulkPublishButton,
|
RoomDirectoryBulkPublishButton,
|
||||||
@ -48,7 +50,14 @@ import {
|
|||||||
import { DATE_FORMAT } from "../components/date";
|
import { DATE_FORMAT } from "../components/date";
|
||||||
import DeleteRoomButton from "../components/DeleteRoomButton";
|
import DeleteRoomButton from "../components/DeleteRoomButton";
|
||||||
import AvatarField from "../components/AvatarField";
|
import AvatarField from "../components/AvatarField";
|
||||||
|
import { Room } from "../synapse/dataProvider";
|
||||||
|
import { useMutation } from "@tanstack/react-query";
|
||||||
|
import { useDataProvider } from "react-admin";
|
||||||
|
import { Confirm } from "react-admin";
|
||||||
|
import { useState } from "react";
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
import PersonIcon from '@mui/icons-material/Person';
|
||||||
|
import Typography from "@mui/material/Typography";
|
||||||
const RoomPagination = () => <Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />;
|
const RoomPagination = () => <Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />;
|
||||||
|
|
||||||
const RoomTitle = () => {
|
const RoomTitle = () => {
|
||||||
@ -76,6 +85,7 @@ const RoomShowActions = () => {
|
|||||||
return (
|
return (
|
||||||
<TopToolbar>
|
<TopToolbar>
|
||||||
{publishButton}
|
{publishButton}
|
||||||
|
<MakeAdminBtn />
|
||||||
<DeleteRoomButton
|
<DeleteRoomButton
|
||||||
selectedIds={[record.id]}
|
selectedIds={[record.id]}
|
||||||
confirmTitle="resources.rooms.action.erase.title"
|
confirmTitle="resources.rooms.action.erase.title"
|
||||||
@ -85,8 +95,97 @@ const RoomShowActions = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const MakeAdminBtn = () => {
|
||||||
|
const record = useRecordContext() as Room;
|
||||||
|
|
||||||
|
if (!record) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record.joined_local_members < 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ownMXID = localStorage.getItem("user_id") || "";
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [userIdValue, setUserIdValue] = useState(ownMXID);
|
||||||
|
const dataProvider = useDataProvider();
|
||||||
|
const notify = useNotify();
|
||||||
|
const translate = useTranslate();
|
||||||
|
|
||||||
|
const { mutate, isPending } = useMutation({
|
||||||
|
mutationFn: async () => {
|
||||||
|
try {
|
||||||
|
const result = await dataProvider.makeRoomAdmin(record.room_id, userIdValue);
|
||||||
|
if (!result.success) {
|
||||||
|
throw new Error(result.error);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSuccess: () => {
|
||||||
|
notify("resources.rooms.action.make_admin.success", { type: "success" });
|
||||||
|
setOpen(false);
|
||||||
|
setUserIdValue("");
|
||||||
|
},
|
||||||
|
onError: (err) => {
|
||||||
|
const errorMessage = err instanceof Error ? err.message : "Unknown error";
|
||||||
|
notify("resources.rooms.action.make_admin.failure", { type: "error", messageArgs: { errMsg: errorMessage } });
|
||||||
|
setOpen(false);
|
||||||
|
setUserIdValue("");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setUserIdValue(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleConfirm = async () => {
|
||||||
|
mutate();
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDialogClose = () => {
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
if (event.key === "Enter") {
|
||||||
|
handleConfirm();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (<>
|
||||||
|
<Button size="small" onClick={(e) => { e.stopPropagation(); setOpen(true); }} disabled={isPending}>
|
||||||
|
<PersonIcon /> {translate("resources.rooms.action.make_admin.assign_admin")}
|
||||||
|
</Button>
|
||||||
|
<Confirm
|
||||||
|
isOpen={open}
|
||||||
|
onConfirm={handleConfirm}
|
||||||
|
onClose={handleDialogClose}
|
||||||
|
confirm="resources.rooms.action.make_admin.confirm"
|
||||||
|
cancel="ra.action.cancel"
|
||||||
|
title={translate("resources.rooms.action.make_admin.title", { roomName: record.name ? record.name : record.room_id })}
|
||||||
|
content={<>
|
||||||
|
<Typography sx={{ marginBottom: 2, whiteSpace: "pre-line"}}>{translate("resources.rooms.action.make_admin.content")}</Typography>
|
||||||
|
<TextField
|
||||||
|
type="text"
|
||||||
|
variant="filled"
|
||||||
|
value={userIdValue}
|
||||||
|
onChange={handleChange}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
label={"Matrix ID"}
|
||||||
|
/>
|
||||||
|
</>}
|
||||||
|
/>
|
||||||
|
</>);
|
||||||
|
};
|
||||||
|
|
||||||
export const RoomShow = (props: ShowProps) => {
|
export const RoomShow = (props: ShowProps) => {
|
||||||
const translate = useTranslate();
|
const translate = useTranslate();
|
||||||
|
const record = useRecordContext();
|
||||||
return (
|
return (
|
||||||
<Show {...props} actions={<RoomShowActions />} title={<RoomTitle />}>
|
<Show {...props} actions={<RoomShowActions />} title={<RoomTitle />}>
|
||||||
<TabbedShowLayout>
|
<TabbedShowLayout>
|
||||||
@ -96,28 +195,29 @@ export const RoomShow = (props: ShowProps) => {
|
|||||||
sx={{ height: "120px", width: "120px" }}
|
sx={{ height: "120px", width: "120px" }}
|
||||||
label="resources.rooms.fields.avatar"
|
label="resources.rooms.fields.avatar"
|
||||||
/>
|
/>
|
||||||
<TextField source="room_id" />
|
<RaTextField source="room_id" />
|
||||||
<TextField source="name" />
|
<RaTextField source="name" />
|
||||||
<TextField source="topic" />
|
<RaTextField source="topic" />
|
||||||
<TextField source="canonical_alias" />
|
<RaTextField source="canonical_alias" />
|
||||||
<ReferenceField source="creator" reference="users">
|
<ReferenceField source="creator" reference="users">
|
||||||
<TextField source="id" />
|
<RaTextField source="id" />
|
||||||
</ReferenceField>
|
</ReferenceField>
|
||||||
</Tab>
|
</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" />
|
<RaTextField source="joined_members" />
|
||||||
<TextField source="joined_local_members" />
|
<RaTextField source="joined_local_members" />
|
||||||
<TextField source="joined_local_devices" />
|
<RaTextField source="joined_local_devices" />
|
||||||
<TextField source="state_events" />
|
<RaTextField source="state_events" />
|
||||||
<TextField source="version" />
|
<RaTextField source="version" />
|
||||||
<TextField source="encryption" emptyText={translate("resources.rooms.enums.unencrypted")} />
|
<RaTextField source="encryption" emptyText={translate("resources.rooms.enums.unencrypted")} />
|
||||||
</Tab>
|
</Tab>
|
||||||
|
|
||||||
<Tab label="synapseadmin.rooms.tabs.members" icon={<UserIcon />} path="members">
|
<Tab label="synapseadmin.rooms.tabs.members" icon={<UserIcon />} path="members">
|
||||||
|
<MakeAdminBtn />
|
||||||
<ReferenceManyField reference="room_members" target="room_id" label={false}>
|
<ReferenceManyField reference="room_members" target="room_id" label={false}>
|
||||||
<Datagrid style={{ width: "100%" }} rowClick={id => "/users/" + id} bulkActionButtons={false}>
|
<Datagrid style={{ width: "100%" }} rowClick={id => "/users/" + id} bulkActionButtons={false}>
|
||||||
<TextField source="id" sortable={false} label="resources.users.fields.id" />
|
<RaTextField source="id" sortable={false} label="resources.users.fields.id" />
|
||||||
<ReferenceField
|
<ReferenceField
|
||||||
label="resources.users.fields.displayname"
|
label="resources.users.fields.displayname"
|
||||||
source="id"
|
source="id"
|
||||||
@ -125,7 +225,7 @@ export const RoomShow = (props: ShowProps) => {
|
|||||||
sortable={false}
|
sortable={false}
|
||||||
link=""
|
link=""
|
||||||
>
|
>
|
||||||
<TextField source="displayname" sortable={false} />
|
<RaTextField source="displayname" sortable={false} />
|
||||||
</ReferenceField>
|
</ReferenceField>
|
||||||
</Datagrid>
|
</Datagrid>
|
||||||
</ReferenceManyField>
|
</ReferenceManyField>
|
||||||
@ -185,11 +285,11 @@ export const RoomShow = (props: ShowProps) => {
|
|||||||
<Tab label={translate("resources.room_state.name", { smart_count: 2 })} icon={<EventIcon />} path="state">
|
<Tab label={translate("resources.room_state.name", { smart_count: 2 })} icon={<EventIcon />} path="state">
|
||||||
<ReferenceManyField reference="room_state" target="room_id" label={false}>
|
<ReferenceManyField reference="room_state" target="room_id" label={false}>
|
||||||
<Datagrid style={{ width: "100%" }} bulkActionButtons={false}>
|
<Datagrid style={{ width: "100%" }} bulkActionButtons={false}>
|
||||||
<TextField source="type" sortable={false} />
|
<RaTextField 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} />
|
||||||
<FunctionField source="content" sortable={false} render={record => `${JSON.stringify(record.content, null, 2)}`} />
|
<FunctionField source="content" sortable={false} render={record => `${JSON.stringify(record.content, null, 2)}`} />
|
||||||
<ReferenceField source="sender" reference="users" sortable={false}>
|
<ReferenceField source="sender" reference="users" sortable={false}>
|
||||||
<TextField source="id" />
|
<RaTextField source="id" />
|
||||||
</ReferenceField>
|
</ReferenceField>
|
||||||
</Datagrid>
|
</Datagrid>
|
||||||
</ReferenceManyField>
|
</ReferenceManyField>
|
||||||
@ -206,10 +306,10 @@ export const RoomShow = (props: ShowProps) => {
|
|||||||
</Box>
|
</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}>
|
<Datagrid style={{ width: "100%" }} bulkActionButtons={false}>
|
||||||
<TextField source="id" sortable={false} />
|
<RaTextField 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} />
|
<NumberField source="depth" sortable={false} />
|
||||||
<TextField source="state_group" sortable={false} />
|
<RaTextField source="state_group" sortable={false} />
|
||||||
</Datagrid>
|
</Datagrid>
|
||||||
</ReferenceManyField>
|
</ReferenceManyField>
|
||||||
</Tab>
|
</Tab>
|
||||||
@ -270,12 +370,13 @@ export const RoomList = (props: ListProps) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<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" />
|
<RaTextField source="joined_members" />
|
||||||
<TextField source="joined_local_members" />
|
<RaTextField source="joined_local_members" />
|
||||||
<TextField source="state_events" />
|
<RaTextField source="state_events" />
|
||||||
<TextField source="version" />
|
<RaTextField source="version" />
|
||||||
<BooleanField source="federatable" />
|
<BooleanField source="federatable" />
|
||||||
<BooleanField source="public" />
|
<BooleanField source="public" />
|
||||||
|
<MakeAdminBtn />
|
||||||
</DatagridConfigurable>
|
</DatagridConfigurable>
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
|
@ -79,6 +79,7 @@ import { useFormContext } from "react-hook-form";
|
|||||||
import { ExperimentalFeaturesList } from "../components/ExperimentalFeatures";
|
import { ExperimentalFeaturesList } from "../components/ExperimentalFeatures";
|
||||||
import { UserRateLimits } from "../components/UserRateLimits";
|
import { UserRateLimits } from "../components/UserRateLimits";
|
||||||
import { User, UsernameAvailabilityResult } from "../synapse/dataProvider";
|
import { User, UsernameAvailabilityResult } from "../synapse/dataProvider";
|
||||||
|
import { MakeAdminBtn } from "./rooms";
|
||||||
|
|
||||||
const choices_medium = [
|
const choices_medium = [
|
||||||
{ id: "email", name: "resources.users.email" },
|
{ id: "email", name: "resources.users.email" },
|
||||||
@ -526,6 +527,7 @@ export const UserEdit = (props: EditProps) => {
|
|||||||
>
|
>
|
||||||
<TextField source="name" sortable={false} />
|
<TextField source="name" sortable={false} />
|
||||||
</ReferenceField>
|
</ReferenceField>
|
||||||
|
<MakeAdminBtn />
|
||||||
</Datagrid>
|
</Datagrid>
|
||||||
</ReferenceManyField>
|
</ReferenceManyField>
|
||||||
</FormTab>
|
</FormTab>
|
||||||
|
@ -52,7 +52,7 @@ interface Action {
|
|||||||
body?: Record<string, any>;
|
body?: Record<string, any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Room {
|
export interface Room {
|
||||||
room_id: string;
|
room_id: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
canonical_alias?: string;
|
canonical_alias?: string;
|
||||||
@ -273,6 +273,7 @@ export interface SynapseDataProvider extends DataProvider {
|
|||||||
getRateLimits: (id: Identifier) => Promise<RateLimitsModel>;
|
getRateLimits: (id: Identifier) => Promise<RateLimitsModel>;
|
||||||
setRateLimits: (id: Identifier, rateLimits: RateLimitsModel) => Promise<void>;
|
setRateLimits: (id: Identifier, rateLimits: RateLimitsModel) => Promise<void>;
|
||||||
checkUsernameAvailability: (username: string) => Promise<UsernameAvailabilityResult>;
|
checkUsernameAvailability: (username: string) => Promise<UsernameAvailabilityResult>;
|
||||||
|
makeRoomAdmin: (room_id: string, user_id: string) => Promise<{ success: boolean; error?: string; errcode?: string }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resourceMap = {
|
const resourceMap = {
|
||||||
@ -866,6 +867,20 @@ const baseDataProvider: SynapseDataProvider = {
|
|||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
makeRoomAdmin: async (room_id: string, user_id: string) => {
|
||||||
|
const base_url = storage.getItem("base_url");
|
||||||
|
|
||||||
|
const endpoint_url = `${base_url}/_synapse/admin/v1/rooms/${encodeURIComponent(room_id)}/make_room_admin`;
|
||||||
|
try {
|
||||||
|
const { json } = await jsonClient(endpoint_url, { method: "POST", body: JSON.stringify({ user_id }) });
|
||||||
|
return { success: true };
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof HttpError) {
|
||||||
|
return { success: false, error: error.body.error, errcode: error.body.errcode };
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user