Skip to content

Commit

Permalink
Add UI option to block deleted rooms from being rejoined (#26)
Browse files Browse the repository at this point in the history
Add UI option to block deleted rooms from being rejoined
This is almost a copy of Awesome-Technologies/synapse-admin#166 PR,
authored by @jkanefendt
  • Loading branch information
beastafk authored Sep 14, 2024
1 parent 0bf3440 commit 7de9166
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
branches: [ "main" ]
env:
upstream_version: v0.10.3
etke_version: etke12
etke_version: etke13
bunny_version: v0.1.0
base_path: ./
permissions:
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
* [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)
* [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_

Expand Down
105 changes: 105 additions & 0 deletions src/components/DeleteRoomButton.tsx
Original file line number Diff line number Diff line change
@@ -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;
5 changes: 5 additions & 0 deletions src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,11 @@ const de: SynapseTranslationMessages = {
title: "Raum löschen",
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!",
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.",
},
},
},
Expand Down
5 changes: 5 additions & 0 deletions src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,11 @@ const en: SynapseTranslationMessages = {
title: "Delete room",
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!",
fields: {
block: "Block and prevent users from joining the room",
},
success: "Room/s successfully deleted.",
failure: "The room/s could not be deleted.",
},
},
},
Expand Down
5 changes: 5 additions & 0 deletions src/i18n/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@ const fr: SynapseTranslationMessages = {
title: "Supprimer le salon",
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 !",
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.",
},
},
},
Expand Down
5 changes: 5 additions & 0 deletions src/i18n/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ interface SynapseTranslationMessages extends TranslationMessages {
erase: {
title: string;
content: string;
fields: {
block: string;
},
success: string;
failure: string;
};
};
};
Expand Down
5 changes: 5 additions & 0 deletions src/i18n/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,11 @@ const ru: SynapseTranslationMessages = {
title: "Удалить комнату",
content:
"Действительно удалить эту комнату? Это действие будет невозможно отменить. Все сообщения и файлы в комнате будут удалены с сервера!",
fields: {
block: "Заблокировать и запретить пользователям присоединяться к комнате",
},
success: "Комната/ы успешно удалены",
failure: "Комната/ы не могут быть удалены.",
},
},
},
Expand Down
31 changes: 18 additions & 13 deletions src/resources/rooms.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
TopToolbar,
useRecordContext,
useTranslate,
useListContext,
} from "react-admin";

import {
Expand All @@ -45,6 +46,7 @@ import {
RoomDirectoryPublishButton,
} from "./room_directory";
import { DATE_FORMAT } from "../components/date";
import DeleteRoomButton from "../components/DeleteRoomButton";

const RoomPagination = () => <Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />;

Expand All @@ -70,8 +72,8 @@ const RoomShowActions = () => {
return (
<TopToolbar>
{publishButton}
<DeleteButton
mutationMode="pessimistic"
<DeleteRoomButton
selectedIds={[record.id]}
confirmTitle="resources.rooms.action.erase.title"
confirmContent="resources.rooms.action.erase.content"
/>
Expand Down Expand Up @@ -207,17 +209,20 @@ export const RoomShow = (props: ShowProps) => {
);
};

const RoomBulkActionButtons = () => (
<>
<RoomDirectoryBulkPublishButton />
<RoomDirectoryBulkUnpublishButton />
<BulkDeleteButton
confirmTitle="resources.rooms.action.erase.title"
confirmContent="resources.rooms.action.erase.content"
mutationMode="pessimistic"
/>
</>
);
const RoomBulkActionButtons = () => {
const record = useListContext();
return (
<>
<RoomDirectoryBulkPublishButton />
<RoomDirectoryBulkUnpublishButton />
<DeleteRoomButton
selectedIds={record.selectedIds}
confirmTitle="resources.rooms.action.erase.title"
confirmContent="resources.rooms.action.erase.content"
/>
</>
);
};

const roomFilters = [<SearchInput source="search_term" alwaysOn />];

Expand Down
3 changes: 2 additions & 1 deletion src/synapse/authProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import fetchMock from "jest-fetch-mock";

import authProvider from "./authProvider";
import storage from "../storage";
import { HttpError } from "ra-core";

fetchMock.enableMocks();

Expand Down Expand Up @@ -104,7 +105,7 @@ describe("authProvider", () => {
});

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();
});
});

Expand Down
2 changes: 1 addition & 1 deletion src/synapse/dataProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ const resourceMap = {
total: json => json.total_rooms,
delete: (params: DeleteParams) => ({
endpoint: `/_synapse/admin/v2/rooms/${params.id}`,
body: { block: false },
body: { block: params.meta?.block ?? false },
}),
},
reports: {
Expand Down

0 comments on commit 7de9166

Please sign in to comment.