RSS Git Download  Clone
Raw Blame History 3kB 87 lines
/**
 * Monitoring shell — exact port of Angular monitoring-shell.component.
 * Tab container with 4 tabs: Pulse, Profiler, PubSub, Analysis.
 * Starts/stops profiler & pubsub services on mount/unmount.
 */
import { useState, useEffect } from 'react'
import { Outlet, useLocation, useNavigate } from 'react-router-dom'
import { Tabs, Tab, Box } from '@mui/material'
import { useI18nStore } from '../../stores/i18n.store'
import { useRedisStateStore } from '../../stores/redis-state.store'
import { useCommonStore } from '../../stores/common.store'
import {
    initMonitoringData, startProfiler, stopProfiler,
    startPubSub, stopPubSub, destroyMonitoringData,
} from '../../stores/monitoring-data.store'

const routes = ['/monitoring', '/monitoring/profiler', '/monitoring/pubsub', '/monitoring/analysis']

function syncTab(pathname: string): number {
    if (pathname.startsWith('/monitoring/profiler')) return 1
    if (pathname.startsWith('/monitoring/pubsub')) return 2
    if (pathname.startsWith('/monitoring/analysis')) return 3
    return 0
}

export default function MonitoringShell() {
    const strings = useI18nStore(s => s.strings)
    const currentLang = useI18nStore(s => s.currentLang)
    const connection = useRedisStateStore(s => s.connection)
    const { generalHandleError } = useCommonStore()
    const location = useLocation()
    const navigate = useNavigate()

    const [selectedTab, setSelectedTab] = useState(() => syncTab(location.pathname))

    useEffect(() => {
        setSelectedTab(syncTab(location.pathname))
    }, [location.pathname])

    // Init services when connection is available
    useEffect(() => {
        if (!connection) return

        initMonitoringData(() => useI18nStore.getState().currentLang)

        const initServices = async () => {
            try { await startProfiler() } catch (e) { generalHandleError(e) }
            try { await startPubSub() } catch (e) { generalHandleError(e) }
        }
        initServices()

        return () => {
            stopProfiler()
            stopPubSub()
            destroyMonitoringData()
        }
    }, [connection]) // eslint-disable-line react-hooks/exhaustive-deps

    const onTabChange = (_: any, index: number) => {
        if (index >= 0 && index < routes.length) {
            setSelectedTab(index)
            navigate(routes[index])
        }
    }

    return (
        <Box sx={{
            display: 'flex', flexDirection: 'column',
            flex: 1, minHeight: 0,
            // Fill the absolute-positioned layout content area
            position: 'absolute', top: 0, left: 0, right: 0, bottom: 0,
        }}>
            <Tabs value={selectedTab} onChange={onTabChange}
                variant="fullWidth"
                sx={{ bgcolor: 'background.paper', borderBottom: 1, borderColor: 'divider', flexShrink: 0 }}>
                <Tab label={strings?.intention?.pulse} />
                <Tab label={strings?.intention?.profiler} />
                <Tab label={strings?.intention?.pubsubMonitor} />
                <Tab label={strings?.intention?.memoryAnalysis} />
            </Tabs>
            <Box id="p3xr-monitoring-content" className="p3xr-monitoring-shell-content" sx={{ flex: 1, minHeight: 0, overflow: 'auto', p: '5px' }}>
                <Outlet />
            </Box>
        </Box>
    )
}