diff --git a/README.md b/README.md
index 1c02c43..5dda21d 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ This project is built using [react-admin](https://marmelab.com/react-admin/).
* [Configuration](#configuration)
* [Restricting available homeserver](#restricting-available-homeserver)
* [Protecting appservice managed users](#protecting-appservice-managed-users)
+ * [Adding custom menu items](#adding-custom-menu-items)
* [Providing support URL](#providing-support-url)
* [Usage](#usage)
* [Supported Synapse](#supported-synapse)
@@ -67,6 +68,7 @@ The following changes are already implemented:
* [Better media preview/download](https://github.com/etkecc/synapse-admin/pull/53)
* [Login with access token](https://github.com/etkecc/synapse-admin/pull/58)
* [Fix footer causing vertical scrollbar](https://github.com/etkecc/synapse-admin/pull/60)
+* [Custom Menu Items](https://github.com/etkecc/synapse-admin/pull/79)
_the list will be updated as new changes are added_
@@ -129,9 +131,29 @@ Example for [mautrix-telegram](https://github.com/mautrix/telegram)
}
```
+### Adding custom menu items
+
+You can add custom menu items to the main menu by providing a `menu` array in the `config.json`.
+
+```json
+{
+ "menu": [
+ {
+ "label": "Contact support",
+ "icon": "SupportAgent",
+ "url": "https://github.com/etkecc/synapse-admin/issues"
+ }
+ ]
+}
+```
+
+Where `icon` is one of the [preloaded icons](./src/components/icons.ts)
+
### Providing support URL
-Synapse-Admin provides a support link in the main menu - `Contact support`. By default, the link points to the GitHub issues page of the project. You can change this link by providing a `supportURL` in the `config.json`.
+**Deprecated**: use `menu` config option described above. Automatically migrated to the `menu` if the `supportURL` is present.
+
+~~Synapse-Admin provides a support link in the main menu - `Contact support`. By default, the link points to the GitHub issues page of the project. You can change this link by providing a `supportURL` in the `config.json`.~~
```json
{
diff --git a/src/App.test.tsx b/src/App.test.tsx
index d9c6394..6e34780 100644
--- a/src/App.test.tsx
+++ b/src/App.test.tsx
@@ -9,4 +9,4 @@ describe("App", () => {
render();
await screen.findAllByText("Welcome to Synapse-admin");
});
-});
\ No newline at end of file
+});
diff --git a/src/AppContext.tsx b/src/AppContext.tsx
index d7f2755..f005479 100644
--- a/src/AppContext.tsx
+++ b/src/AppContext.tsx
@@ -4,6 +4,13 @@ interface AppContextType {
restrictBaseUrl: string | string[];
asManagedUsers: string[];
supportURL: string;
+ menu: MenuItem[];
+}
+
+interface MenuItem {
+ label: string;
+ icon: string;
+ url: string;
}
export const AppContext = createContext({});
diff --git a/src/components/AdminLayout.tsx b/src/components/AdminLayout.tsx
index 72fb788..2799693 100644
--- a/src/components/AdminLayout.tsx
+++ b/src/components/AdminLayout.tsx
@@ -1,17 +1,7 @@
import { AppBar, Confirm, Layout, Logout, Menu, useLogout, UserMenu } from "react-admin";
-import LiveHelpIcon from "@mui/icons-material/LiveHelp";
import { LoginMethod } from "../pages/LoginPage";
-import { useState } from "react";
-
-const DEFAULT_SUPPORT_LINK = "https://github.com/etkecc/synapse-admin/issues";
-const supportLink = (): string => {
- try {
- new URL(localStorage.getItem("support_url") || ""); // Check if the URL is valid
- return localStorage.getItem("support_url") || DEFAULT_SUPPORT_LINK;
- } catch (e) {
- return DEFAULT_SUPPORT_LINK;
- }
-};
+import { useEffect, useState, Suspense } from "react";
+import { Icons, DefaultIcon } from "./icons";
const AdminUserMenu = () => {
const [open, setOpen] = useState(false);
@@ -56,12 +46,38 @@ const AdminUserMenu = () => {
const AdminAppBar = () => } />;
-const AdminMenu = () => (
-
-);
+const AdminMenu = (props) => {
+ const [menu, setMenu] = useState([]);
+
+ useEffect(() => {
+ const menuConfig = localStorage.getItem('menu');
+ if (menuConfig) {
+ setMenu(JSON.parse(menuConfig));
+ }
+ }, []);
+
+ return (
+
+ );
+};
export const AdminLayout = ({ children }) => (
import('@mui/icons-material/Announcement')),
+ Engineering: lazy(() => import('@mui/icons-material/Engineering')),
+ HelpCenter: lazy(() => import('@mui/icons-material/HelpCenter')),
+ SupportAgent: lazy(() => import('@mui/icons-material/SupportAgent')),
+ Default: lazy(() => import('@mui/icons-material/OpenInNew')),
+ // Add more icons as needed
+};
+
+export const DefaultIcon = Icons.Default;
diff --git a/src/index.tsx b/src/index.tsx
index 770d1d9..efa762d 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -3,7 +3,7 @@ import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
-import { AppContext } from "./AppContext";
+import { AppContext, MenuItem } from "./AppContext";
import storage from "./storage";
fetch("config.json")
@@ -12,9 +12,24 @@ fetch("config.json")
if (props.asManagedUsers) {
storage.setItem("as_managed_users", JSON.stringify(props.asManagedUsers));
}
- if (props.supportURL) {
- storage.setItem("support_url", props.supportURL);
+
+ let menu: MenuItem[] = [];
+ if (props.menu) {
+ menu = props.menu;
}
+ if (props.supportURL) {
+ const migratedSupportURL = {
+ label: "Contact support",
+ icon: "SupportAgent",
+ url: props.supportURL,
+ };
+ console.warn("supportURL config option is deprecated. Please, use the menu option instead. Automatically migrated to the new menu option:", migratedSupportURL);
+ menu.push(migratedSupportURL as MenuItem);
+ }
+ if (menu.length > 0) {
+ storage.setItem("menu", JSON.stringify(menu));
+ }
+
return createRoot(document.getElementById("root")).render(