Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ The following changes are already implemented:
* 🛑 [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)
* 🎨 [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_

Expand Down
2 changes: 0 additions & 2 deletions src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ const Footer = () => {
}
}, []);

console.log(theme);

return (<Box
component="footer"
sx={{
Expand Down
8 changes: 8 additions & 0 deletions src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,14 @@ const de: SynapseTranslationMessages = {
success: "Raum/Räume erfolgreich gelöscht.",
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: {
Expand Down
10 changes: 9 additions & 1 deletion src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const en: SynapseTranslationMessages = {
members: "Members",
detail: "Details",
permission: "Permissions",
},
}
},
reports: { tabs: { basic: "Basic", detail: "Details" } },
},
Expand Down Expand Up @@ -233,6 +233,14 @@ const en: SynapseTranslationMessages = {
success: "Room/s successfully 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: {
Expand Down
8 changes: 8 additions & 0 deletions src/i18n/fa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,14 @@ const fa: SynapseTranslationMessages = {
success: "اتاق با موفقیت حذف شد.",
failure: "خطایی رخ داده است.",
},
make_admin: {
assign_admin: "مدیر انتخاب کنید",
title: "مدیر اتاق %{roomName} را انتخاب کنید",
confirm: "مدیر انتخاب کنید",
content: "کامل MXID کاربری را وارد کنید که به عنوان مدیر تنظیم شود.\nهشدار: برای این کار، اتاق باید حداقل یک اعضای محلی به عنوان مدیر داشته باشد.",
success: "کاربر به عنوان مدیر اتاق تنظیم شد.",
failure: "کاربر به عنوان مدیر اتاق تنظیم نشد. %{errMsg}",
}
},
},
reports: {
Expand Down
8 changes: 8 additions & 0 deletions src/i18n/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,14 @@ const fr: SynapseTranslationMessages = {
success: "Salle/s supprimées avec succès.",
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: {
Expand Down
8 changes: 8 additions & 0 deletions src/i18n/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,14 @@ interface SynapseTranslationMessages extends TranslationMessages {
success: string;
failure: string;
};
make_admin: {
assign_admin: string;
title: string;
confirm: string;
content: string;
success: string;
failure: string;
};
};
};
reports: {
Expand Down
8 changes: 8 additions & 0 deletions src/i18n/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,14 @@ const it: SynapseTranslationMessages = {
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!",
},
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: {
Expand Down
8 changes: 8 additions & 0 deletions src/i18n/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,14 @@ const ru: SynapseTranslationMessages = {
success: "Комната/ы успешно удалены",
failure: "Комната/ы не могут быть удалены.",
},
make_admin: {
assign_admin: "Назначить администратора",
title: "Назначить администратора комнате %{roomName}",
confirm: "Назначить администратора",
content: "Введите полную MXID пользователя, которого нужно назначить администратором.\nПредупреждение: для этого должен быть назначен хотя бы один локальный участник в качестве администратора.",
success: "Пользователь назначен администратором комнаты.",
failure: "Пользователь не может быть назначен администратором комнаты. %{errMsg}",
}
},
},
reports: {
Expand Down
4 changes: 2 additions & 2 deletions src/resources/room_directory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ import {
} from "react-admin";
import { useMutation } from "@tanstack/react-query";
import AvatarField from "../components/AvatarField";


import { MakeAdminBtn } from "./rooms";
const RoomDirectoryPagination = () => <Pagination rowsPerPageOptions={[100, 500, 1000, 2000]} />;

export const RoomDirectoryUnpublishButton = (props: DeleteButtonProps) => {
Expand Down Expand Up @@ -154,6 +153,7 @@ export const RoomDirectoryList = () => (
<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" />
<MakeAdminBtn />
</DatagridConfigurable>
</List>
);
Expand Down
151 changes: 126 additions & 25 deletions src/resources/rooms.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import Box from "@mui/material/Box";
import { useTheme } from "@mui/material/styles";
import {
BooleanField,
BulkDeleteButton,
DateField,
EditButton,
WrapperField,
Datagrid,
DatagridConfigurable,
DeleteButton,
ExportButton,
FunctionField,
List,
Expand All @@ -32,13 +32,15 @@ import {
ShowProps,
Tab,
TabbedShowLayout,
TextField,
TextField as RaTextField,
TopToolbar,
useRecordContext,
useTranslate,
useListContext,
useNotify,
} from "react-admin";

import TextField from "@mui/material/TextField";
import {
RoomDirectoryBulkUnpublishButton,
RoomDirectoryBulkPublishButton,
Expand All @@ -48,7 +50,14 @@ import {
import { DATE_FORMAT } from "../components/date";
import DeleteRoomButton from "../components/DeleteRoomButton";
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 RoomTitle = () => {
Expand Down Expand Up @@ -76,6 +85,7 @@ const RoomShowActions = () => {
return (
<TopToolbar>
{publishButton}
<MakeAdminBtn />
<DeleteRoomButton
selectedIds={[record.id]}
confirmTitle="resources.rooms.action.erase.title"
Expand All @@ -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) => {
const translate = useTranslate();
const record = useRecordContext();
return (
<Show {...props} actions={<RoomShowActions />} title={<RoomTitle />}>
<TabbedShowLayout>
Expand All @@ -96,36 +195,37 @@ export const RoomShow = (props: ShowProps) => {
sx={{ height: "120px", width: "120px" }}
label="resources.rooms.fields.avatar"
/>
<TextField source="room_id" />
<TextField source="name" />
<TextField source="topic" />
<TextField source="canonical_alias" />
<RaTextField source="room_id" />
<RaTextField source="name" />
<RaTextField source="topic" />
<RaTextField source="canonical_alias" />
<ReferenceField source="creator" reference="users">
<TextField source="id" />
<RaTextField source="id" />
</ReferenceField>
</Tab>

<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")} />
<RaTextField source="joined_members" />
<RaTextField source="joined_local_members" />
<RaTextField source="joined_local_devices" />
<RaTextField source="state_events" />
<RaTextField source="version" />
<RaTextField source="encryption" emptyText={translate("resources.rooms.enums.unencrypted")} />
</Tab>

<Tab label="synapseadmin.rooms.tabs.members" icon={<UserIcon />} path="members">
<MakeAdminBtn />
<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" />
<RaTextField source="id" sortable={false} label="resources.users.fields.id" />
<ReferenceField
label="resources.users.fields.displayname"
source="id"
reference="users"
sortable={false}
link=""
>
<TextField source="displayname" sortable={false} />
<RaTextField source="displayname" sortable={false} />
</ReferenceField>
</Datagrid>
</ReferenceManyField>
Expand Down Expand Up @@ -185,11 +285,11 @@ export const RoomShow = (props: ShowProps) => {
<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} />
<RaTextField source="type" 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)}`} />
<ReferenceField source="sender" reference="users" sortable={false}>
<TextField source="id" />
<RaTextField source="id" />
</ReferenceField>
</Datagrid>
</ReferenceManyField>
Expand All @@ -206,10 +306,10 @@ export const RoomShow = (props: ShowProps) => {
</Box>
<ReferenceManyField reference="forward_extremities" target="room_id" label={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} />
<NumberField source="depth" sortable={false} />
<TextField source="state_group" sortable={false} />
<RaTextField source="state_group" sortable={false} />
</Datagrid>
</ReferenceManyField>
</Tab>
Expand Down Expand Up @@ -270,12 +370,13 @@ export const RoomList = (props: ListProps) => {
}}
/>
<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" />
<TextField source="version" />
<RaTextField source="joined_members" />
<RaTextField source="joined_local_members" />
<RaTextField source="state_events" />
<RaTextField source="version" />
<BooleanField source="federatable" />
<BooleanField source="public" />
<MakeAdminBtn />
</DatagridConfigurable>
</List>
);
Expand Down
Loading