diff --git a/core/modules/WebServer/webSocket.ts b/core/modules/WebServer/webSocket.ts index 1771cf82d..cf8d7604f 100644 --- a/core/modules/WebServer/webSocket.ts +++ b/core/modules/WebServer/webSocket.ts @@ -200,6 +200,9 @@ export default class WebSocket { socket.emit(room.eventName, room.initialData()); } + //Standalone events (not tied to a room) + socket.emit('banTemplatesUpdate', txConfig.banlist.templates); + //General events socket.on('disconnect', (reason) => { // console.verbose.debug('SocketIO', `Client disconnected with reason: ${reason}`); diff --git a/core/routes/banTemplates/saveBanTemplates.ts b/core/routes/banTemplates/saveBanTemplates.ts index 84fdc8c1d..e66c055c9 100644 --- a/core/routes/banTemplates/saveBanTemplates.ts +++ b/core/routes/banTemplates/saveBanTemplates.ts @@ -48,6 +48,9 @@ export default async function SaveBanTemplates(ctx: AuthedCtx) { }); } + //Pushing update to all connected clients + txCore.webServer.webSocket.pushEvent('banTemplatesUpdate', txConfig.banlist.templates); + //Sending output return sendTypedResp({ success: true }); }; diff --git a/core/routes/player/modal.ts b/core/routes/player/modal.ts index 967dbf493..db3e433c4 100644 --- a/core/routes/player/modal.ts +++ b/core/routes/player/modal.ts @@ -91,7 +91,7 @@ export default async function PlayerModal(ctx: AuthedCtx) { // console.dir(playerData); return sendTypedResp({ serverTime: now(), - banTemplates: txConfig.banlist.templates, //TODO: move this to websocket push + banTemplates: txConfig.banlist.templates, //NOTE: kept for NUI compatibility, panel uses websocket push player: playerData }); }; diff --git a/panel/src/components/BanForm.tsx b/panel/src/components/BanForm.tsx index 7dcdcf83c..94bb2fef4 100644 --- a/panel/src/components/BanForm.tsx +++ b/panel/src/components/BanForm.tsx @@ -7,7 +7,7 @@ import { forwardRef, useImperativeHandle, useMemo, useRef, useState } from "reac import { DropDownSelect, DropDownSelectContent, DropDownSelectItem, DropDownSelectTrigger } from "@/components/dropDownSelect"; import { banDurationToShortString, banDurationToString, cn } from "@/lib/utils"; import { Link, useLocation } from "wouter"; -import type { BanTemplatesDataType } from "@shared/otherTypes"; +import { useBanTemplates } from "@/hooks/banTemplates"; // Consts const reasonTruncateLength = 150; @@ -25,7 +25,6 @@ export type BanFormType = HTMLDivElement & { getData: () => BanFormRespType; } type BanFormProps = { - banTemplates?: BanTemplatesDataType[]; //undefined = loading disabled?: boolean; onNavigateAway?: () => void; }; @@ -33,7 +32,8 @@ type BanFormProps = { /** * A form to set ban reason and duration. */ -export default forwardRef(function BanForm({ banTemplates, disabled, onNavigateAway }: BanFormProps, ref) { +export default forwardRef(function BanForm({ disabled, onNavigateAway }: BanFormProps, ref) { + const banTemplates = useBanTemplates(); const reasonRef = useRef(null); const customMultiplierRef = useRef(null); const setLocation = useLocation()[1]; diff --git a/panel/src/hooks/banTemplates.ts b/panel/src/hooks/banTemplates.ts new file mode 100644 index 000000000..1ec8feb65 --- /dev/null +++ b/panel/src/hooks/banTemplates.ts @@ -0,0 +1,20 @@ +import { BanTemplatesDataType } from "@shared/otherTypes"; +import { atom, useAtomValue, useSetAtom } from "jotai"; + + +/** + * Atoms + */ +const banTemplatesAtom = atom(undefined); + + +/** + * Hooks + */ +export const useSetBanTemplates = () => { + return useSetAtom(banTemplatesAtom); +}; + +export const useBanTemplates = () => { + return useAtomValue(banTemplatesAtom); +}; diff --git a/panel/src/layout/MainSocket.tsx b/panel/src/layout/MainSocket.tsx index c7c83fa0e..8a3920370 100644 --- a/panel/src/layout/MainSocket.tsx +++ b/panel/src/layout/MainSocket.tsx @@ -4,6 +4,7 @@ import { useExpireAuthData, useSetAuthData } from '@/hooks/auth'; import { useSetGlobalStatus } from '@/hooks/status'; import { useProcessUpdateAvailableEvent, useSetOfflineWarning } from '@/hooks/useWarningBar'; import { useProcessPlayerlistEvents } from '@/hooks/playerlist'; +import { useSetBanTemplates } from '@/hooks/banTemplates'; import { LogoutReasonHash } from '@/pages/auth/Login'; @@ -19,6 +20,7 @@ export default function MainSocket() { const setGlobalStatus = useSetGlobalStatus(); const processPlayerlistEvents = useProcessPlayerlistEvents(); const processUpdateAvailableEvent = useProcessUpdateAvailableEvent(); + const setBanTemplates = useSetBanTemplates(); //Runing on mount only useEffect(() => { @@ -67,11 +69,15 @@ export default function MainSocket() { console.warn('Got updateAuthData from websocket', authData); setAuthData(authData); }); + socket.on('banTemplatesUpdate', function (templates) { + setBanTemplates(templates); + }); return () => { socket.removeAllListeners(); socket.disconnect(); setGlobalStatus(null); + setBanTemplates(undefined); } }, []); diff --git a/panel/src/layout/PlayerModal/PlayerBanTab.tsx b/panel/src/layout/PlayerModal/PlayerBanTab.tsx index f39c50a4e..4c9016236 100644 --- a/panel/src/layout/PlayerModal/PlayerBanTab.tsx +++ b/panel/src/layout/PlayerModal/PlayerBanTab.tsx @@ -6,17 +6,15 @@ import { useRef, useState } from "react"; import { useBackendApi } from "@/hooks/fetch"; import { GenericApiOkResp } from "@shared/genericApiTypes"; import ModalCentralMessage from "@/components/ModalCentralMessage"; -import type { BanTemplatesDataType } from "@shared/otherTypes"; import BanForm, { BanFormType } from "@/components/BanForm"; import { txToast } from "@/components/TxToaster"; type PlayerBanTabProps = { - banTemplates: BanTemplatesDataType[]; playerRef: PlayerModalRefType; }; -export default function PlayerBanTab({ playerRef, banTemplates }: PlayerBanTabProps) { +export default function PlayerBanTab({ playerRef }: PlayerBanTabProps) { const banFormRef = useRef(null); const [isSaving, setIsSaving] = useState(false); const { hasPerm } = useAdminPerms(); @@ -65,7 +63,6 @@ export default function PlayerBanTab({ playerRef, banTemplates }: PlayerBanTabPr
{ closeModal(); }} /> diff --git a/panel/src/layout/PlayerModal/PlayerModal.tsx b/panel/src/layout/PlayerModal/PlayerModal.tsx index cf46a3e4f..3b281ccaf 100644 --- a/panel/src/layout/PlayerModal/PlayerModal.tsx +++ b/panel/src/layout/PlayerModal/PlayerModal.tsx @@ -198,7 +198,6 @@ export default function PlayerModal() { refreshModalData={refreshModalData} />} {selectedTab === 'Ban' && } diff --git a/panel/src/pages/AddLegacyBanPage.tsx b/panel/src/pages/AddLegacyBanPage.tsx index f663a1c89..cc97f7527 100644 --- a/panel/src/pages/AddLegacyBanPage.tsx +++ b/panel/src/pages/AddLegacyBanPage.tsx @@ -1,7 +1,7 @@ import InlineCode from "@/components/InlineCode"; import { useAdminPerms } from "@/hooks/auth"; import { useRef, useState } from "react"; -import { ApiAddLegacyBanReqSchema, GetBanTemplatesSuccessResp, SaveBanTemplatesReq } from "@shared/otherTypes"; +import { ApiAddLegacyBanReqSchema } from "@shared/otherTypes"; import { useBackendApi } from "@/hooks/fetch"; import { Loader2Icon } from "lucide-react"; import { Button } from "@/components/ui/button"; @@ -10,7 +10,6 @@ import { Textarea } from "@/components/ui/textarea"; import BanForm, { BanFormType } from "@/components/BanForm"; import { txToast } from "@/components/TxToaster"; import { GenericApiOkResp } from "@shared/genericApiTypes"; -import useSWR from "swr"; export default function AddLegacyBanPage() { @@ -19,12 +18,6 @@ export default function AddLegacyBanPage() { const [isSaving, setIsSaving] = useState(false); const { hasPerm } = useAdminPerms(); - const getBanTemplatesApi = useBackendApi({ - method: 'GET', - path: `/settings/banTemplates`, - throwGenericErrors: true, - }); - const legacyBanApi = useBackendApi({ method: 'POST', path: `/history/addLegacyBan`, @@ -77,12 +70,6 @@ export default function AddLegacyBanPage() { }); }; - const swrBanTemplates = useSWR('/settings/banTemplates', async () => { - const data = await getBanTemplatesApi({}); - if (!data) throw new Error('No data returned'); - return data; - }); - const canBan = hasPerm('players.ban'); return (
@@ -112,7 +99,6 @@ export default function AddLegacyBanPage() {
diff --git a/shared/playerApiTypes.ts b/shared/playerApiTypes.ts index c38f8ab82..fac749e15 100644 --- a/shared/playerApiTypes.ts +++ b/shared/playerApiTypes.ts @@ -41,7 +41,7 @@ export type PlayerModalPlayerData = { export type PlayerModalSuccess = { serverTime: number; //required to calculate if bans have expired on frontend - banTemplates: BanTemplatesDataType[]; //TODO: move this to websocket push + banTemplates: BanTemplatesDataType[]; //NOTE: kept for NUI compatibility, panel uses websocket push player: PlayerModalPlayerData; } export type PlayerModalResp = PlayerModalSuccess | GenericApiErrorResp; diff --git a/shared/socketioTypes.ts b/shared/socketioTypes.ts index c007da56a..7c97ca8d4 100644 --- a/shared/socketioTypes.ts +++ b/shared/socketioTypes.ts @@ -1,7 +1,7 @@ import { SvRtPerfThreadNamesType } from "@core/modules/Metrics/svRuntime/config"; import { SvRtNodeMemoryType, SvRtPerfBoundariesType } from "@core/modules/Metrics/svRuntime/perfSchemas"; import type { ReactAuthDataType } from "./authApiTypes"; -import type { UpdateDataType } from "./otherTypes"; +import type { BanTemplatesDataType, UpdateDataType } from "./otherTypes"; import { DiscordBotStatus, TxConfigState, type FxMonitorHealth } from "./enums"; /** @@ -115,5 +115,6 @@ export type ListenEventsMap = { dashboard: (data: DashboardDataEventType) => void; //Standalone events - updateAvailable: (event: UpdateAvailableEventType) => void + updateAvailable: (event: UpdateAvailableEventType) => void; + banTemplatesUpdate: (templates: BanTemplatesDataType[]) => void; };