Files
matrix_admin_panel/frontend/src/App.tsx
T
Egutierrez 0e3c5f5e84 feat: scaffold matrix_admin_panel v0.1.0 (issue 0163)
Wails + React + Mantine v7 admin panel for Matrix/Synapse. Replaces the
removed synapse-admin container. MAS OIDC PKCE login (loopback :8766) +
Synapse Admin API (users/rooms/sessions).

- MAS client: XSFD2SWA394DXRVJFTREAMY6J6 (public PKCE, no auth method).
- Backend: AdminService (Go) with Login/SetAdminToken/ListUsers/
  DeactivateUser/ResetUserPassword/ListRooms/DeleteRoom/GetUserDevices.
- Vendored helpers in internal/infra/ from registry:
  mas_oidc_loopback_go_infra, keyring_token_store_go_infra,
  synapse_admin_client_go_infra.
- Frontend: AppShell + sidebar tabs (Users/Rooms/Sessions). Sessions
  placeholder pending MAS admin API.
- Build verified: Linux + Windows.
2026-05-25 01:05:43 +02:00

92 lines
2.5 KiB
TypeScript

import { useEffect, useState } from "react";
import { Box, LoadingOverlay } from "@mantine/core";
import LoginScreen from "./LoginScreen";
import HomeScreen from "./HomeScreen";
import AdminTokenModal from "./AdminTokenModal";
import { GetSession } from "../wailsjs/go/main/AdminService";
const LAST_USER_KEY = "matrix_admin_panel.last_user_id";
interface Session {
user_id: string;
homeserver_url: string;
has_oidc_token: boolean;
has_admin_token: boolean;
expires_at?: string;
}
export default function App() {
const [userID, setUserID] = useState<string | null>(null);
const [session, setSession] = useState<Session | null>(null);
const [loading, setLoading] = useState(true);
const [tokenModalOpen, setTokenModalOpen] = useState(false);
useEffect(() => {
const last = localStorage.getItem(LAST_USER_KEY);
if (!last) {
setLoading(false);
return;
}
GetSession(last)
.then((s) => {
const sess = s as Session | null;
if (sess && sess.has_oidc_token) {
setUserID(sess.user_id);
setSession(sess);
if (!sess.has_admin_token) {
setTokenModalOpen(true);
}
}
})
.finally(() => setLoading(false));
}, []);
async function refreshSession(uid: string) {
const s = (await GetSession(uid)) as Session | null;
if (s) setSession(s);
}
const handleLogin = async (uid: string) => {
localStorage.setItem(LAST_USER_KEY, uid);
setUserID(uid);
await refreshSession(uid);
// After OIDC login, ALWAYS prompt for admin token unless already saved.
const s = (await GetSession(uid)) as Session | null;
if (s && !s.has_admin_token) setTokenModalOpen(true);
};
const handleLogout = () => {
localStorage.removeItem(LAST_USER_KEY);
setUserID(null);
setSession(null);
};
const handleTokenSaved = async () => {
setTokenModalOpen(false);
if (userID) await refreshSession(userID);
};
return (
<Box pos="relative" mih="100vh">
<LoadingOverlay visible={loading} />
{userID ? (
<>
<HomeScreen
userID={userID}
session={session}
onLogout={handleLogout}
onRequestAdminToken={() => setTokenModalOpen(true)}
/>
<AdminTokenModal
opened={tokenModalOpen}
onClose={() => setTokenModalOpen(false)}
onSaved={handleTokenSaved}
/>
</>
) : (
<LoginScreen onLogin={handleLogin} />
)}
</Box>
);
}