Add UI option to block deleted rooms from being rejoined (#26)

Add UI option to block deleted rooms from being rejoined
This is almost a copy of https://github.com/Awesome-Technologies/synapse-admin/pull/166 PR,
authored by @jkanefendt
This commit is contained in:
Borislav Pantaleev 2024-09-14 11:03:51 +03:00 committed by GitHub
parent 0bf3440fc8
commit 7de9166648
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 153 additions and 16 deletions

View file

@ -4,7 +4,7 @@ on:
branches: [ "main" ] branches: [ "main" ]
env: env:
upstream_version: v0.10.3 upstream_version: v0.10.3
etke_version: etke12 etke_version: etke13
bunny_version: v0.1.0 bunny_version: v0.1.0
base_path: ./ base_path: ./
permissions: permissions:

View file

@ -35,6 +35,7 @@ The following changes are already implemented:
* [Fix base_url being undefined on unsuccessful login](https://github.com/etkecc/synapse-admin/pull/18) * [Fix base_url being undefined on unsuccessful login](https://github.com/etkecc/synapse-admin/pull/18)
* [Put the version into manifest.json](https://github.com/Awesome-Technologies/synapse-admin/issues/507) (CI only) * [Put the version into manifest.json](https://github.com/Awesome-Technologies/synapse-admin/issues/507) (CI only)
* [Federation page improvements](https://github.com/Awesome-Technologies/synapse-admin/pull/583) (using theme colors) * [Federation page improvements](https://github.com/Awesome-Technologies/synapse-admin/pull/583) (using theme colors)
* [Add UI option to block deleted rooms from being rejoined](https://github.com/etkecc/synapse-admin/pull/26)
_the list will be updated as new changes are added_ _the list will be updated as new changes are added_

View file

@ -0,0 +1,105 @@
import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from "@mui/material";
import { Fragment, useState } from "react";
import { SimpleForm, BooleanInput, useTranslate, RaRecord, useNotify, useRedirect, useDelete, NotificationType, useDeleteMany, Identifier, useUnselectAll } from "react-admin";
import ActionDelete from "@mui/icons-material/Delete";
import ActionCheck from "@mui/icons-material/CheckCircle";
import AlertError from "@mui/icons-material/ErrorOutline";
interface DeleteRoomButtonProps {
selectedIds: Identifier[];
confirmTitle: string;
confirmContent: string;
}
const resourceName = "rooms";
const DeleteRoomButton: React.FC<DeleteRoomButtonProps> = (props) => {
const translate = useTranslate();
const [open, setOpen] = useState(false);
const [block, setBlock] = useState(true);
const notify = useNotify();
const redirect = useRedirect();
const [deleteMany, { isLoading }] = useDeleteMany();
const unselectAll = useUnselectAll(resourceName);
const recordIds = props.selectedIds;
const handleDialogOpen = () => setOpen(true);
const handleDialogClose = () => setOpen(false);
const handleDelete = (values: {block: boolean}) => {
deleteMany(
resourceName,
{ ids: recordIds, meta: values },
{
onSuccess: () => {
notify("resources.rooms.action.erase.success");
handleDialogClose();
unselectAll();
redirect("/rooms");
},
onError: (error) =>
notify("resources.rooms.action.erase.failure", { type: 'error' as NotificationType }),
}
);
};
const handleConfirm = () => {
setOpen(false);
handleDelete({ block: block });
};
return (
<Fragment>
<Button
onClick={handleDialogOpen}
disabled={isLoading}
className={"ra-delete-button"}
key="button"
size="small"
sx={{
"&.MuiButton-sizeSmall": {
lineHeight: 1.5,
},
}}
color={"error"}
startIcon={<ActionDelete />}
>
{translate("ra.action.delete")}
</Button>
<Dialog open={open} onClose={handleDialogClose}>
<DialogTitle>{translate(props.confirmTitle)}</DialogTitle>
<DialogContent>
<DialogContentText>{translate(props.confirmContent)}</DialogContentText>
<SimpleForm toolbar={false}>
<BooleanInput
fullWidth
source="block"
value={block}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => setBlock(event.target.checked)}
label="resources.rooms.action.erase.fields.block"
defaultValue={true}
/>
</SimpleForm>
</DialogContent>
<DialogActions>
<Button disabled={false} onClick={handleDialogClose} startIcon={<AlertError />}>
{translate("ra.action.cancel")}
</Button>
<Button
disabled={false}
onClick={handleConfirm}
className={"ra-confirm RaConfirm-confirmPrimary"}
autoFocus
startIcon={<ActionCheck />}
>
{translate("ra.action.confirm")}
</Button>
</DialogActions>
</Dialog>
</Fragment>
);
};
export default DeleteRoomButton;

View file

@ -199,6 +199,11 @@ const de: SynapseTranslationMessages = {
title: "Raum löschen", title: "Raum löschen",
content: content:
"Sind Sie sicher dass Sie den Raum löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden. Alle Nachrichten und Medien, die der Raum beinhaltet werden vom Server gelöscht!", "Sind Sie sicher dass Sie den Raum löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden. Alle Nachrichten und Medien, die der Raum beinhaltet werden vom Server gelöscht!",
fields: {
block: "Benutzer blockieren und daran hindern, dem Raum beizutreten",
},
success: "Raum/Räume erfolgreich gelöscht.",
failure: "Der/die Raum/Räume konnten nicht gelöscht werden.",
}, },
}, },
}, },

View file

@ -198,6 +198,11 @@ const en: SynapseTranslationMessages = {
title: "Delete room", title: "Delete room",
content: content:
"Are you sure you want to delete the room? This cannot be undone. All messages and shared media in the room will be deleted from the server!", "Are you sure you want to delete the room? This cannot be undone. All messages and shared media in the room will be deleted from the server!",
fields: {
block: "Block and prevent users from joining the room",
},
success: "Room/s successfully deleted.",
failure: "The room/s could not be deleted.",
}, },
}, },
}, },

View file

@ -196,6 +196,11 @@ const fr: SynapseTranslationMessages = {
title: "Supprimer le salon", title: "Supprimer le salon",
content: content:
"Voulez-vous vraiment supprimer le salon ? Cette opération ne peut être annulée. Tous les messages et médias partagés du salon seront supprimés du serveur !", "Voulez-vous vraiment supprimer le salon ? Cette opération ne peut être annulée. Tous les messages et médias partagés du salon seront supprimés du serveur !",
fields: {
block: "Bloquer et empêcher les utilisateurs de rejoindre la salle",
},
success: "Salle/s supprimées avec succès.",
failure: "La/les salle/s n'ont pas pu être supprimées.",
}, },
}, },
}, },

5
src/i18n/index.d.ts vendored
View file

@ -192,6 +192,11 @@ interface SynapseTranslationMessages extends TranslationMessages {
erase: { erase: {
title: string; title: string;
content: string; content: string;
fields: {
block: string;
},
success: string;
failure: string;
}; };
}; };
}; };

View file

@ -210,6 +210,11 @@ const ru: SynapseTranslationMessages = {
title: "Удалить комнату", title: "Удалить комнату",
content: content:
"Действительно удалить эту комнату? Это действие будет невозможно отменить. Все сообщения и файлы в комнате будут удалены с сервера!", "Действительно удалить эту комнату? Это действие будет невозможно отменить. Все сообщения и файлы в комнате будут удалены с сервера!",
fields: {
block: "Заблокировать и запретить пользователям присоединяться к комнате",
},
success: "Комната/ы успешно удалены",
failure: "Комната/ы не могут быть удалены.",
}, },
}, },
}, },

View file

@ -36,6 +36,7 @@ import {
TopToolbar, TopToolbar,
useRecordContext, useRecordContext,
useTranslate, useTranslate,
useListContext,
} from "react-admin"; } from "react-admin";
import { import {
@ -45,6 +46,7 @@ import {
RoomDirectoryPublishButton, RoomDirectoryPublishButton,
} from "./room_directory"; } from "./room_directory";
import { DATE_FORMAT } from "../components/date"; import { DATE_FORMAT } from "../components/date";
import DeleteRoomButton from "../components/DeleteRoomButton";
const RoomPagination = () => <Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />; const RoomPagination = () => <Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />;
@ -70,8 +72,8 @@ const RoomShowActions = () => {
return ( return (
<TopToolbar> <TopToolbar>
{publishButton} {publishButton}
<DeleteButton <DeleteRoomButton
mutationMode="pessimistic" selectedIds={[record.id]}
confirmTitle="resources.rooms.action.erase.title" confirmTitle="resources.rooms.action.erase.title"
confirmContent="resources.rooms.action.erase.content" confirmContent="resources.rooms.action.erase.content"
/> />
@ -207,17 +209,20 @@ export const RoomShow = (props: ShowProps) => {
); );
}; };
const RoomBulkActionButtons = () => ( const RoomBulkActionButtons = () => {
const record = useListContext();
return (
<> <>
<RoomDirectoryBulkPublishButton /> <RoomDirectoryBulkPublishButton />
<RoomDirectoryBulkUnpublishButton /> <RoomDirectoryBulkUnpublishButton />
<BulkDeleteButton <DeleteRoomButton
selectedIds={record.selectedIds}
confirmTitle="resources.rooms.action.erase.title" confirmTitle="resources.rooms.action.erase.title"
confirmContent="resources.rooms.action.erase.content" confirmContent="resources.rooms.action.erase.content"
mutationMode="pessimistic"
/> />
</> </>
); );
};
const roomFilters = [<SearchInput source="search_term" alwaysOn />]; const roomFilters = [<SearchInput source="search_term" alwaysOn />];

View file

@ -2,6 +2,7 @@ import fetchMock from "jest-fetch-mock";
import authProvider from "./authProvider"; import authProvider from "./authProvider";
import storage from "../storage"; import storage from "../storage";
import { HttpError } from "ra-core";
fetchMock.enableMocks(); fetchMock.enableMocks();
@ -104,7 +105,7 @@ describe("authProvider", () => {
}); });
it("should reject if error.status is 403", async () => { it("should reject if error.status is 403", async () => {
await expect(authProvider.checkError({ status: 403 })).rejects.toBeUndefined(); await expect(authProvider.checkError(new HttpError("test-error", 403, {errcode: "test-errcode", error: "test-error"}))).rejects.toBeDefined();
}); });
}); });

View file

@ -270,7 +270,7 @@ const resourceMap = {
total: json => json.total_rooms, total: json => json.total_rooms,
delete: (params: DeleteParams) => ({ delete: (params: DeleteParams) => ({
endpoint: `/_synapse/admin/v2/rooms/${params.id}`, endpoint: `/_synapse/admin/v2/rooms/${params.id}`,
body: { block: false }, body: { block: params.meta?.block ?? false },
}), }),
}, },
reports: { reports: {