adonisjs-server-stats 1.5.4 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +351 -171
- package/dist/configure.d.ts.map +1 -1
- package/dist/core/api-client.d.ts +73 -0
- package/dist/core/api-client.d.ts.map +1 -0
- package/dist/core/config-utils.d.ts +109 -0
- package/dist/core/config-utils.d.ts.map +1 -0
- package/dist/core/constants.d.ts +11 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/dashboard-api.d.ts +65 -0
- package/dist/core/dashboard-api.d.ts.map +1 -0
- package/dist/core/dashboard-data-controller.d.ts +157 -0
- package/dist/core/dashboard-data-controller.d.ts.map +1 -0
- package/dist/core/debug-data-controller.d.ts +89 -0
- package/dist/core/debug-data-controller.d.ts.map +1 -0
- package/dist/core/feature-detect.d.ts +67 -0
- package/dist/core/feature-detect.d.ts.map +1 -0
- package/dist/core/formatters.d.ts +189 -0
- package/dist/core/formatters.d.ts.map +1 -0
- package/dist/core/history-buffer.d.ts +23 -0
- package/dist/core/history-buffer.d.ts.map +1 -0
- package/dist/core/icons.d.ts +36 -0
- package/dist/core/icons.d.ts.map +1 -0
- package/dist/core/index.d.ts +39 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +1961 -0
- package/dist/core/internals-utils.d.ts +71 -0
- package/dist/core/internals-utils.d.ts.map +1 -0
- package/dist/core/job-utils.d.ts +45 -0
- package/dist/core/job-utils.d.ts.map +1 -0
- package/dist/core/log-utils.d.ts +34 -0
- package/dist/core/log-utils.d.ts.map +1 -0
- package/dist/core/metrics.d.ts +41 -0
- package/dist/core/metrics.d.ts.map +1 -0
- package/dist/core/pagination.d.ts +128 -0
- package/dist/core/pagination.d.ts.map +1 -0
- package/dist/core/query-utils.d.ts +35 -0
- package/dist/core/query-utils.d.ts.map +1 -0
- package/dist/core/resizable-columns.d.ts +18 -0
- package/dist/core/resizable-columns.d.ts.map +1 -0
- package/dist/core/routes.d.ts +12 -0
- package/dist/core/routes.d.ts.map +1 -0
- package/dist/core/server-stats-controller.d.ts +106 -0
- package/dist/core/server-stats-controller.d.ts.map +1 -0
- package/dist/core/sparkline.d.ts +80 -0
- package/dist/core/sparkline.d.ts.map +1 -0
- package/dist/core/theme.d.ts +42 -0
- package/dist/core/theme.d.ts.map +1 -0
- package/dist/core/trace-utils.d.ts +62 -0
- package/dist/core/trace-utils.d.ts.map +1 -0
- package/dist/core/transmit-adapter.d.ts +59 -0
- package/dist/core/transmit-adapter.d.ts.map +1 -0
- package/dist/core/types.d.ts +619 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/react/CacheSection-DGxMDlWK.js +146 -0
- package/dist/react/CacheTab-CnVW5PLs.js +123 -0
- package/dist/react/ConfigContent-CnsEI4j3.js +397 -0
- package/dist/react/ConfigSection-DPcrfqXY.js +11 -0
- package/dist/react/ConfigTab-BSWq_o2p.js +15 -0
- package/dist/react/CustomPaneTab-xjkYwTvH.js +104 -0
- package/dist/react/DataTable-YyShr5B-.js +55 -0
- package/dist/react/EmailsSection-CSyTg1aX.js +262 -0
- package/dist/react/EmailsTab-Dh2YSa_f.js +131 -0
- package/dist/react/EventsSection-C1pbJDfW.js +86 -0
- package/dist/react/EventsTab-eCh02cdd.js +63 -0
- package/dist/react/FilterBar-DQRXpWrb.js +50 -0
- package/dist/react/InternalsContent-DBzsI0CG.js +346 -0
- package/dist/react/InternalsSection-t7ihcWO-.js +32 -0
- package/dist/react/InternalsTab-Oij0A2fN.js +30 -0
- package/dist/react/JobsSection-CLAin5vU.js +187 -0
- package/dist/react/JobsTab-Dl5nrj2z.js +141 -0
- package/dist/react/LogsSection-C1p81fXO.js +212 -0
- package/dist/react/LogsTab-D-kR7PjX.js +88 -0
- package/dist/react/OverviewSection-nm3xdACz.js +539 -0
- package/dist/react/Pagination-BkmzUDY8.js +64 -0
- package/dist/react/QueriesSection-DB12HMfQ.js +461 -0
- package/dist/react/QueriesTab-fyBB1u_Y.js +90 -0
- package/dist/react/RequestsSection-DTqB81ac.js +209 -0
- package/dist/react/RoutesSection-DJWa4NPV.js +74 -0
- package/dist/react/RoutesTab-D3l8TOpu.js +74 -0
- package/dist/react/TimelineSection-C4d-jRX1.js +158 -0
- package/dist/react/TimelineTab-C5TFaSmQ.js +193 -0
- package/dist/react/WaterfallChart-Cj73WdfM.js +100 -0
- package/dist/react/core/api-client.d.ts +73 -0
- package/dist/react/core/api-client.d.ts.map +1 -0
- package/dist/react/core/config-utils.d.ts +109 -0
- package/dist/react/core/config-utils.d.ts.map +1 -0
- package/dist/react/core/constants.d.ts +11 -0
- package/dist/react/core/constants.d.ts.map +1 -0
- package/dist/react/core/dashboard-api.d.ts +65 -0
- package/dist/react/core/dashboard-api.d.ts.map +1 -0
- package/dist/react/core/dashboard-data-controller.d.ts +157 -0
- package/dist/react/core/dashboard-data-controller.d.ts.map +1 -0
- package/dist/react/core/debug-data-controller.d.ts +89 -0
- package/dist/react/core/debug-data-controller.d.ts.map +1 -0
- package/dist/react/core/feature-detect.d.ts +67 -0
- package/dist/react/core/feature-detect.d.ts.map +1 -0
- package/dist/react/core/formatters.d.ts +189 -0
- package/dist/react/core/formatters.d.ts.map +1 -0
- package/dist/react/core/history-buffer.d.ts +23 -0
- package/dist/react/core/history-buffer.d.ts.map +1 -0
- package/dist/react/core/icons.d.ts +36 -0
- package/dist/react/core/icons.d.ts.map +1 -0
- package/dist/react/core/index.d.ts +39 -0
- package/dist/react/core/index.d.ts.map +1 -0
- package/dist/react/core/internals-utils.d.ts +71 -0
- package/dist/react/core/internals-utils.d.ts.map +1 -0
- package/dist/react/core/job-utils.d.ts +45 -0
- package/dist/react/core/job-utils.d.ts.map +1 -0
- package/dist/react/core/log-utils.d.ts +34 -0
- package/dist/react/core/log-utils.d.ts.map +1 -0
- package/dist/react/core/metrics.d.ts +41 -0
- package/dist/react/core/metrics.d.ts.map +1 -0
- package/dist/react/core/pagination.d.ts +128 -0
- package/dist/react/core/pagination.d.ts.map +1 -0
- package/dist/react/core/query-utils.d.ts +35 -0
- package/dist/react/core/query-utils.d.ts.map +1 -0
- package/dist/react/core/resizable-columns.d.ts +18 -0
- package/dist/react/core/resizable-columns.d.ts.map +1 -0
- package/dist/react/core/routes.d.ts +12 -0
- package/dist/react/core/routes.d.ts.map +1 -0
- package/dist/react/core/server-stats-controller.d.ts +106 -0
- package/dist/react/core/server-stats-controller.d.ts.map +1 -0
- package/dist/react/core/sparkline.d.ts +80 -0
- package/dist/react/core/sparkline.d.ts.map +1 -0
- package/dist/react/core/theme.d.ts +42 -0
- package/dist/react/core/theme.d.ts.map +1 -0
- package/dist/react/core/trace-utils.d.ts +62 -0
- package/dist/react/core/trace-utils.d.ts.map +1 -0
- package/dist/react/core/transmit-adapter.d.ts +59 -0
- package/dist/react/core/transmit-adapter.d.ts.map +1 -0
- package/dist/react/core/types.d.ts +619 -0
- package/dist/react/core/types.d.ts.map +1 -0
- package/dist/react/index-UdTfSvtO.js +1074 -0
- package/dist/react/index.js +18 -0
- package/dist/react/react/components/Dashboard/DashboardPage.d.ts +17 -0
- package/dist/react/react/components/Dashboard/DashboardPage.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/sections/CacheSection.d.ts +7 -0
- package/dist/react/react/components/Dashboard/sections/CacheSection.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/sections/ConfigSection.d.ts +7 -0
- package/dist/react/react/components/Dashboard/sections/ConfigSection.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/sections/EmailsSection.d.ts +7 -0
- package/dist/react/react/components/Dashboard/sections/EmailsSection.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/sections/EventsSection.d.ts +7 -0
- package/dist/react/react/components/Dashboard/sections/EventsSection.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/sections/InternalsSection.d.ts +14 -0
- package/dist/react/react/components/Dashboard/sections/InternalsSection.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/sections/JobsSection.d.ts +7 -0
- package/dist/react/react/components/Dashboard/sections/JobsSection.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/sections/LogsSection.d.ts +7 -0
- package/dist/react/react/components/Dashboard/sections/LogsSection.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/sections/OverviewSection.d.ts +7 -0
- package/dist/react/react/components/Dashboard/sections/OverviewSection.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/sections/QueriesSection.d.ts +7 -0
- package/dist/react/react/components/Dashboard/sections/QueriesSection.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/sections/RequestsSection.d.ts +7 -0
- package/dist/react/react/components/Dashboard/sections/RequestsSection.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/sections/RoutesSection.d.ts +7 -0
- package/dist/react/react/components/Dashboard/sections/RoutesSection.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/sections/TimelineSection.d.ts +9 -0
- package/dist/react/react/components/Dashboard/sections/TimelineSection.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/shared/DataTable.d.ts +27 -0
- package/dist/react/react/components/Dashboard/shared/DataTable.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/shared/FilterBar.d.ts +17 -0
- package/dist/react/react/components/Dashboard/shared/FilterBar.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/shared/Pagination.d.ts +13 -0
- package/dist/react/react/components/Dashboard/shared/Pagination.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/shared/TimeRangeSelector.d.ts +12 -0
- package/dist/react/react/components/Dashboard/shared/TimeRangeSelector.d.ts.map +1 -0
- package/dist/react/react/components/Dashboard/shared/WaterfallChart.d.ts +16 -0
- package/dist/react/react/components/Dashboard/shared/WaterfallChart.d.ts.map +1 -0
- package/dist/react/react/components/DebugPanel/DebugPanel.d.ts +16 -0
- package/dist/react/react/components/DebugPanel/DebugPanel.d.ts.map +1 -0
- package/dist/react/react/components/DebugPanel/tabs/CacheTab.d.ts +8 -0
- package/dist/react/react/components/DebugPanel/tabs/CacheTab.d.ts.map +1 -0
- package/dist/react/react/components/DebugPanel/tabs/ConfigTab.d.ts +8 -0
- package/dist/react/react/components/DebugPanel/tabs/ConfigTab.d.ts.map +1 -0
- package/dist/react/react/components/DebugPanel/tabs/CustomPaneTab.d.ts +14 -0
- package/dist/react/react/components/DebugPanel/tabs/CustomPaneTab.d.ts.map +1 -0
- package/dist/react/react/components/DebugPanel/tabs/EmailsTab.d.ts +7 -0
- package/dist/react/react/components/DebugPanel/tabs/EmailsTab.d.ts.map +1 -0
- package/dist/react/react/components/DebugPanel/tabs/EventsTab.d.ts +7 -0
- package/dist/react/react/components/DebugPanel/tabs/EventsTab.d.ts.map +1 -0
- package/dist/react/react/components/DebugPanel/tabs/InternalsTab.d.ts +12 -0
- package/dist/react/react/components/DebugPanel/tabs/InternalsTab.d.ts.map +1 -0
- package/dist/react/react/components/DebugPanel/tabs/JobsTab.d.ts +9 -0
- package/dist/react/react/components/DebugPanel/tabs/JobsTab.d.ts.map +1 -0
- package/dist/react/react/components/DebugPanel/tabs/LogsTab.d.ts +7 -0
- package/dist/react/react/components/DebugPanel/tabs/LogsTab.d.ts.map +1 -0
- package/dist/react/react/components/DebugPanel/tabs/QueriesTab.d.ts +7 -0
- package/dist/react/react/components/DebugPanel/tabs/QueriesTab.d.ts.map +1 -0
- package/dist/react/react/components/DebugPanel/tabs/RoutesTab.d.ts +8 -0
- package/dist/react/react/components/DebugPanel/tabs/RoutesTab.d.ts.map +1 -0
- package/dist/react/react/components/DebugPanel/tabs/TimelineTab.d.ts +7 -0
- package/dist/react/react/components/DebugPanel/tabs/TimelineTab.d.ts.map +1 -0
- package/dist/react/react/components/StatsBar/MetricCard.d.ts +21 -0
- package/dist/react/react/components/StatsBar/MetricCard.d.ts.map +1 -0
- package/dist/react/react/components/StatsBar/Sparkline.d.ts +15 -0
- package/dist/react/react/components/StatsBar/Sparkline.d.ts.map +1 -0
- package/dist/react/react/components/StatsBar/StatsBar.d.ts +22 -0
- package/dist/react/react/components/StatsBar/StatsBar.d.ts.map +1 -0
- package/dist/react/react/components/shared/Badge.d.ts +32 -0
- package/dist/react/react/components/shared/Badge.d.ts.map +1 -0
- package/dist/react/react/components/shared/ConfigContent.d.ts +13 -0
- package/dist/react/react/components/shared/ConfigContent.d.ts.map +1 -0
- package/dist/react/react/components/shared/InternalsContent.d.ts +10 -0
- package/dist/react/react/components/shared/InternalsContent.d.ts.map +1 -0
- package/dist/react/react/components/shared/JsonViewer.d.ts +12 -0
- package/dist/react/react/components/shared/JsonViewer.d.ts.map +1 -0
- package/dist/react/react/components/shared/ThemeToggle.d.ts +13 -0
- package/dist/react/react/components/shared/ThemeToggle.d.ts.map +1 -0
- package/dist/react/react/components/shared/Tooltip.d.ts +16 -0
- package/dist/react/react/components/shared/Tooltip.d.ts.map +1 -0
- package/dist/react/react/hooks/useApiClient.d.ts +10 -0
- package/dist/react/react/hooks/useApiClient.d.ts.map +1 -0
- package/dist/react/react/hooks/useDashboardApiBase.d.ts +19 -0
- package/dist/react/react/hooks/useDashboardApiBase.d.ts.map +1 -0
- package/dist/react/react/hooks/useDashboardData.d.ts +27 -0
- package/dist/react/react/hooks/useDashboardData.d.ts.map +1 -0
- package/dist/react/react/hooks/useDebugData.d.ts +17 -0
- package/dist/react/react/hooks/useDebugData.d.ts.map +1 -0
- package/dist/react/react/hooks/useFeatures.d.ts +13 -0
- package/dist/react/react/hooks/useFeatures.d.ts.map +1 -0
- package/dist/react/react/hooks/useResizableTable.d.ts +13 -0
- package/dist/react/react/hooks/useResizableTable.d.ts.map +1 -0
- package/dist/react/react/hooks/useServerStats.d.ts +21 -0
- package/dist/react/react/hooks/useServerStats.d.ts.map +1 -0
- package/dist/react/react/hooks/useTheme.d.ts +12 -0
- package/dist/react/react/hooks/useTheme.d.ts.map +1 -0
- package/dist/react/react/index.d.ts +14 -0
- package/dist/react/react/index.d.ts.map +1 -0
- package/dist/react/style.css +1 -0
- package/dist/react/useApiClient-BVtNCmnL.js +9 -0
- package/dist/react/useDashboardApiBase-Bi36pJ2L.js +14 -0
- package/dist/react/useResizableTable-CNJmACdt.js +13 -0
- package/dist/src/collectors/app_collector.d.ts.map +1 -1
- package/dist/src/collectors/app_collector.js +30 -2
- package/dist/src/collectors/auto_detect.d.ts +31 -0
- package/dist/src/collectors/auto_detect.d.ts.map +1 -0
- package/dist/src/collectors/auto_detect.js +120 -0
- package/dist/src/collectors/collector.d.ts +17 -0
- package/dist/src/collectors/collector.d.ts.map +1 -1
- package/dist/src/collectors/db_pool_collector.d.ts.map +1 -1
- package/dist/src/collectors/db_pool_collector.js +35 -1
- package/dist/src/collectors/http_collector.d.ts +4 -3
- package/dist/src/collectors/http_collector.d.ts.map +1 -1
- package/dist/src/collectors/http_collector.js +28 -11
- package/dist/src/collectors/index.d.ts +2 -0
- package/dist/src/collectors/index.d.ts.map +1 -1
- package/dist/src/collectors/index.js +1 -0
- package/dist/src/collectors/log_collector.d.ts +11 -4
- package/dist/src/collectors/log_collector.d.ts.map +1 -1
- package/dist/src/collectors/log_collector.js +51 -5
- package/dist/src/collectors/process_collector.d.ts.map +1 -1
- package/dist/src/collectors/process_collector.js +4 -0
- package/dist/src/collectors/queue_collector.d.ts.map +1 -1
- package/dist/src/collectors/queue_collector.js +55 -1
- package/dist/src/collectors/redis_collector.d.ts.map +1 -1
- package/dist/src/collectors/redis_collector.js +42 -3
- package/dist/src/collectors/system_collector.d.ts.map +1 -1
- package/dist/src/collectors/system_collector.js +4 -0
- package/dist/src/controller/api_controller.d.ts +101 -0
- package/dist/src/controller/api_controller.d.ts.map +1 -0
- package/dist/src/controller/api_controller.js +131 -0
- package/dist/src/controller/debug_controller.d.ts +19 -10
- package/dist/src/controller/debug_controller.d.ts.map +1 -1
- package/dist/src/controller/debug_controller.js +118 -101
- package/dist/src/core/theme.d.ts +42 -0
- package/dist/src/core/theme.d.ts.map +1 -0
- package/dist/src/core/theme.js +115 -0
- package/dist/src/dashboard/chart_aggregator.d.ts.map +1 -1
- package/dist/src/dashboard/chart_aggregator.js +3 -2
- package/dist/src/dashboard/dashboard_controller.d.ts +10 -14
- package/dist/src/dashboard/dashboard_controller.d.ts.map +1 -1
- package/dist/src/dashboard/dashboard_controller.js +132 -250
- package/dist/src/dashboard/dashboard_store.d.ts +62 -19
- package/dist/src/dashboard/dashboard_store.d.ts.map +1 -1
- package/dist/src/dashboard/dashboard_store.js +242 -53
- package/dist/src/dashboard/integrations/cache_inspector.d.ts +19 -1
- package/dist/src/dashboard/integrations/cache_inspector.d.ts.map +1 -1
- package/dist/src/dashboard/integrations/config_inspector.d.ts +1 -1
- package/dist/src/dashboard/integrations/config_inspector.d.ts.map +1 -1
- package/dist/src/dashboard/integrations/config_inspector.js +3 -2
- package/dist/src/dashboard/integrations/queue_inspector.d.ts +55 -10
- package/dist/src/dashboard/integrations/queue_inspector.d.ts.map +1 -1
- package/dist/src/dashboard/integrations/queue_inspector.js +70 -24
- package/dist/src/dashboard/migrator.d.ts +5 -0
- package/dist/src/dashboard/migrator.d.ts.map +1 -1
- package/dist/src/dashboard/migrator.js +44 -9
- package/dist/src/dashboard/models/stats_event.d.ts +1 -1
- package/dist/src/dashboard/models/stats_event.d.ts.map +1 -1
- package/dist/src/dashboard/models/stats_log.d.ts +1 -1
- package/dist/src/dashboard/models/stats_log.d.ts.map +1 -1
- package/dist/src/dashboard/models/stats_query.d.ts +1 -1
- package/dist/src/dashboard/models/stats_query.d.ts.map +1 -1
- package/dist/src/dashboard/models/stats_saved_filter.d.ts +1 -1
- package/dist/src/dashboard/models/stats_saved_filter.d.ts.map +1 -1
- package/dist/src/dashboard/models/stats_trace.d.ts +2 -1
- package/dist/src/dashboard/models/stats_trace.d.ts.map +1 -1
- package/dist/src/data/data_access.d.ts +105 -0
- package/dist/src/data/data_access.d.ts.map +1 -0
- package/dist/src/data/data_access.js +310 -0
- package/dist/src/data/index.d.ts +3 -0
- package/dist/src/data/index.d.ts.map +1 -0
- package/dist/src/data/index.js +1 -0
- package/dist/src/debug/debug_store.d.ts +20 -1
- package/dist/src/debug/debug_store.d.ts.map +1 -1
- package/dist/src/debug/debug_store.js +43 -15
- package/dist/src/debug/email_collector.d.ts +6 -2
- package/dist/src/debug/email_collector.d.ts.map +1 -1
- package/dist/src/debug/email_collector.js +3 -0
- package/dist/src/debug/event_collector.d.ts +6 -2
- package/dist/src/debug/event_collector.d.ts.map +1 -1
- package/dist/src/debug/event_collector.js +12 -8
- package/dist/src/debug/query_collector.d.ts +6 -2
- package/dist/src/debug/query_collector.d.ts.map +1 -1
- package/dist/src/debug/query_collector.js +3 -0
- package/dist/src/debug/ring_buffer.d.ts +1 -0
- package/dist/src/debug/ring_buffer.d.ts.map +1 -1
- package/dist/src/debug/ring_buffer.js +5 -2
- package/dist/src/debug/route_inspector.d.ts +2 -2
- package/dist/src/debug/route_inspector.d.ts.map +1 -1
- package/dist/src/debug/route_inspector.js +4 -3
- package/dist/src/debug/trace_collector.d.ts +7 -3
- package/dist/src/debug/trace_collector.d.ts.map +1 -1
- package/dist/src/debug/trace_collector.js +7 -5
- package/dist/src/debug/types.d.ts +107 -2
- package/dist/src/debug/types.d.ts.map +1 -1
- package/dist/src/debug/types.js +1 -1
- package/dist/src/define_config.d.ts +49 -5
- package/dist/src/define_config.d.ts.map +1 -1
- package/dist/src/define_config.js +361 -4
- package/dist/src/edge/bootstrap.d.ts +17 -0
- package/dist/src/edge/bootstrap.d.ts.map +1 -0
- package/dist/src/edge/bootstrap.js +29 -0
- package/dist/src/edge/client/dashboard.js +2 -3619
- package/dist/src/edge/client/debug-panel-deferred.js +1 -0
- package/dist/src/edge/client/debug-panel.js +1 -2140
- package/dist/src/edge/client/stats-bar.js +1 -801
- package/dist/src/edge/client-vue/dashboard.js +5 -0
- package/dist/src/edge/client-vue/debug-panel-deferred.js +4 -0
- package/dist/src/edge/client-vue/debug-panel.js +4 -0
- package/dist/src/edge/client-vue/stats-bar.js +4 -0
- package/dist/src/edge/plugin.d.ts +35 -2
- package/dist/src/edge/plugin.d.ts.map +1 -1
- package/dist/src/edge/plugin.js +30 -66
- package/dist/src/edge/types.d.ts +46 -0
- package/dist/src/edge/types.d.ts.map +1 -0
- package/dist/src/edge/types.js +4 -0
- package/dist/src/edge/views/dashboard.edge +1 -358
- package/dist/src/edge/views/debug-panel.edge +2 -154
- package/dist/src/edge/views/stats-bar.edge +15 -48
- package/dist/src/engine/stats_engine.d.ts +18 -0
- package/dist/src/engine/stats_engine.d.ts.map +1 -1
- package/dist/src/engine/stats_engine.js +45 -2
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/log_stream/log_stream_provider.d.ts.map +1 -1
- package/dist/src/log_stream/log_stream_provider.js +21 -4
- package/dist/src/log_stream/log_stream_service.d.ts +8 -1
- package/dist/src/log_stream/log_stream_service.d.ts.map +1 -1
- package/dist/src/log_stream/log_stream_service.js +27 -3
- package/dist/src/middleware/request_tracking_middleware.d.ts +1 -1
- package/dist/src/middleware/request_tracking_middleware.d.ts.map +1 -1
- package/dist/src/middleware/request_tracking_middleware.js +21 -6
- package/dist/src/prometheus/prometheus_collector.d.ts +2 -1
- package/dist/src/prometheus/prometheus_collector.d.ts.map +1 -1
- package/dist/src/provider/server_stats_provider.d.ts +100 -0
- package/dist/src/provider/server_stats_provider.d.ts.map +1 -1
- package/dist/src/provider/server_stats_provider.js +460 -104
- package/dist/src/routes/access_middleware.d.ts +2 -1
- package/dist/src/routes/access_middleware.d.ts.map +1 -1
- package/dist/src/routes/access_middleware.js +7 -1
- package/dist/src/routes/index.d.ts +4 -0
- package/dist/src/routes/index.d.ts.map +1 -0
- package/dist/src/routes/index.js +1 -0
- package/dist/src/routes/register_routes.d.ts +103 -0
- package/dist/src/routes/register_routes.d.ts.map +1 -0
- package/dist/src/routes/register_routes.js +356 -0
- package/dist/src/routes/router_types.d.ts +29 -0
- package/dist/src/routes/router_types.d.ts.map +1 -0
- package/dist/src/routes/router_types.js +1 -0
- package/dist/src/stubs/config.stub +12 -32
- package/dist/src/styles/components.css +1048 -0
- package/dist/src/{edge/client → styles}/dashboard.css +299 -736
- package/dist/src/{edge/client → styles}/debug-panel.css +117 -633
- package/dist/src/{edge/client → styles}/stats-bar.css +28 -10
- package/dist/src/styles/tokens.css +153 -0
- package/dist/src/styles/utilities.css +75 -0
- package/dist/src/types.d.ts +119 -16
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/app_import.d.ts +23 -0
- package/dist/src/utils/app_import.d.ts.map +1 -0
- package/dist/src/utils/app_import.js +44 -0
- package/dist/src/utils/json_helpers.d.ts +2 -2
- package/dist/src/utils/json_helpers.d.ts.map +1 -1
- package/dist/src/utils/logger.d.ts +17 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +27 -0
- package/dist/src/utils/mail_helpers.d.ts +1 -1
- package/dist/src/utils/mail_helpers.d.ts.map +1 -1
- package/dist/src/utils/mail_helpers.js +1 -1
- package/dist/vue/CacheSection-C788Yfai.js +149 -0
- package/dist/vue/CacheTab-BPisYYiQ.js +104 -0
- package/dist/vue/ConfigSection-CRzYxqW2.js +576 -0
- package/dist/vue/ConfigTab-C8cafGUj.js +361 -0
- package/dist/vue/CustomPaneTab-BJxT5Dp7.js +172 -0
- package/dist/vue/EmailsSection-C8JFMtW7.js +206 -0
- package/dist/vue/EmailsTab-DhFhoNmU.js +157 -0
- package/dist/vue/EventsSection-C4wXUgxG.js +107 -0
- package/dist/vue/EventsTab-DQ4Nd6AK.js +97 -0
- package/dist/vue/FilterBar.vue_vue_type_script_setup_true_lang-ClJ37hhT.js +62 -0
- package/dist/vue/InternalsSection-BJUXE-5F.js +468 -0
- package/dist/vue/InternalsTab-DEMjqtlw.js +471 -0
- package/dist/vue/JobsSection-CsKWTjgN.js +187 -0
- package/dist/vue/JobsTab-BCvhOARO.js +117 -0
- package/dist/vue/JsonViewer.vue_vue_type_script_setup_true_lang-Vsqar1zx.js +67 -0
- package/dist/vue/LogsSection-BFVjSZ24.js +227 -0
- package/dist/vue/LogsTab-DpEQ7euu.js +122 -0
- package/dist/vue/OverviewSection-CbMdAido.js +849 -0
- package/dist/vue/PaginationControls.vue_vue_type_script_setup_true_lang-CuN7g_8Z.js +50 -0
- package/dist/vue/QueriesSection-BPiv7u3r.js +429 -0
- package/dist/vue/QueriesTab-C8_7oprC.js +107 -0
- package/dist/vue/RequestsSection-LtImH4rD.js +243 -0
- package/dist/vue/RoutesSection-CrxOxmzx.js +106 -0
- package/dist/vue/RoutesTab-Dz0MkZuF.js +80 -0
- package/dist/vue/TimelineSection-DLxMW2J_.js +186 -0
- package/dist/vue/TimelineTab-Db6lKKsD.js +250 -0
- package/dist/vue/WaterfallChart.vue_vue_type_script_setup_true_lang-tZ13cNj1.js +118 -0
- package/dist/vue/components/Dashboard/DashboardPage.vue.d.ts +18 -0
- package/dist/vue/components/Dashboard/DashboardPage.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/sections/CacheSection.vue.d.ts +5 -0
- package/dist/vue/components/Dashboard/sections/CacheSection.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/sections/ConfigSection.vue.d.ts +3 -0
- package/dist/vue/components/Dashboard/sections/ConfigSection.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/sections/EmailsSection.vue.d.ts +5 -0
- package/dist/vue/components/Dashboard/sections/EmailsSection.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/sections/EventsSection.vue.d.ts +5 -0
- package/dist/vue/components/Dashboard/sections/EventsSection.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/sections/InternalsSection.vue.d.ts +3 -0
- package/dist/vue/components/Dashboard/sections/InternalsSection.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/sections/JobsSection.vue.d.ts +5 -0
- package/dist/vue/components/Dashboard/sections/JobsSection.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/sections/LogsSection.vue.d.ts +3 -0
- package/dist/vue/components/Dashboard/sections/LogsSection.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/sections/OverviewSection.vue.d.ts +5 -0
- package/dist/vue/components/Dashboard/sections/OverviewSection.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/sections/QueriesSection.vue.d.ts +45 -0
- package/dist/vue/components/Dashboard/sections/QueriesSection.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/sections/RequestsSection.vue.d.ts +5 -0
- package/dist/vue/components/Dashboard/sections/RequestsSection.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/sections/RoutesSection.vue.d.ts +5 -0
- package/dist/vue/components/Dashboard/sections/RoutesSection.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/sections/TimelineSection.vue.d.ts +11 -0
- package/dist/vue/components/Dashboard/sections/TimelineSection.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/shared/FilterBar.vue.d.ts +29 -0
- package/dist/vue/components/Dashboard/shared/FilterBar.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/shared/PaginationControls.vue.d.ts +12 -0
- package/dist/vue/components/Dashboard/shared/PaginationControls.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/shared/TimeRangeSelector.vue.d.ts +11 -0
- package/dist/vue/components/Dashboard/shared/TimeRangeSelector.vue.d.ts.map +1 -0
- package/dist/vue/components/Dashboard/shared/WaterfallChart.vue.d.ts +10 -0
- package/dist/vue/components/Dashboard/shared/WaterfallChart.vue.d.ts.map +1 -0
- package/dist/vue/components/DebugPanel/DebugPanel.vue.d.ts +21 -0
- package/dist/vue/components/DebugPanel/DebugPanel.vue.d.ts.map +1 -0
- package/dist/vue/components/DebugPanel/tabs/CacheTab.vue.d.ts +12 -0
- package/dist/vue/components/DebugPanel/tabs/CacheTab.vue.d.ts.map +1 -0
- package/dist/vue/components/DebugPanel/tabs/ConfigTab.vue.d.ts +11 -0
- package/dist/vue/components/DebugPanel/tabs/ConfigTab.vue.d.ts.map +1 -0
- package/dist/vue/components/DebugPanel/tabs/CustomPaneTab.vue.d.ts +11 -0
- package/dist/vue/components/DebugPanel/tabs/CustomPaneTab.vue.d.ts.map +1 -0
- package/dist/vue/components/DebugPanel/tabs/EmailsTab.vue.d.ts +12 -0
- package/dist/vue/components/DebugPanel/tabs/EmailsTab.vue.d.ts.map +1 -0
- package/dist/vue/components/DebugPanel/tabs/EventsTab.vue.d.ts +12 -0
- package/dist/vue/components/DebugPanel/tabs/EventsTab.vue.d.ts.map +1 -0
- package/dist/vue/components/DebugPanel/tabs/InternalsTab.vue.d.ts +11 -0
- package/dist/vue/components/DebugPanel/tabs/InternalsTab.vue.d.ts.map +1 -0
- package/dist/vue/components/DebugPanel/tabs/JobsTab.vue.d.ts +13 -0
- package/dist/vue/components/DebugPanel/tabs/JobsTab.vue.d.ts.map +1 -0
- package/dist/vue/components/DebugPanel/tabs/LogsTab.vue.d.ts +15 -0
- package/dist/vue/components/DebugPanel/tabs/LogsTab.vue.d.ts.map +1 -0
- package/dist/vue/components/DebugPanel/tabs/QueriesTab.vue.d.ts +12 -0
- package/dist/vue/components/DebugPanel/tabs/QueriesTab.vue.d.ts.map +1 -0
- package/dist/vue/components/DebugPanel/tabs/RoutesTab.vue.d.ts +12 -0
- package/dist/vue/components/DebugPanel/tabs/RoutesTab.vue.d.ts.map +1 -0
- package/dist/vue/components/DebugPanel/tabs/TimelineTab.vue.d.ts +15 -0
- package/dist/vue/components/DebugPanel/tabs/TimelineTab.vue.d.ts.map +1 -0
- package/dist/vue/components/StatsBar/MetricCard.vue.d.ts +19 -0
- package/dist/vue/components/StatsBar/MetricCard.vue.d.ts.map +1 -0
- package/dist/vue/components/StatsBar/Sparkline.vue.d.ts +17 -0
- package/dist/vue/components/StatsBar/Sparkline.vue.d.ts.map +1 -0
- package/dist/vue/components/StatsBar/StatsBar.vue.d.ts +22 -0
- package/dist/vue/components/StatsBar/StatsBar.vue.d.ts.map +1 -0
- package/dist/vue/components/shared/JsonViewer.vue.d.ts +13 -0
- package/dist/vue/components/shared/JsonViewer.vue.d.ts.map +1 -0
- package/dist/vue/components/shared/ThemeToggle.vue.d.ts +8 -0
- package/dist/vue/components/shared/ThemeToggle.vue.d.ts.map +1 -0
- package/dist/vue/composables/useApiClient.d.ts +9 -0
- package/dist/vue/composables/useApiClient.d.ts.map +1 -0
- package/dist/vue/composables/useDashboardData.d.ts +53 -0
- package/dist/vue/composables/useDashboardData.d.ts.map +1 -0
- package/dist/vue/composables/useDebugData.d.ts +25 -0
- package/dist/vue/composables/useDebugData.d.ts.map +1 -0
- package/dist/vue/composables/useFeatures.d.ts +80 -0
- package/dist/vue/composables/useFeatures.d.ts.map +1 -0
- package/dist/vue/composables/useResizableTable.d.ts +16 -0
- package/dist/vue/composables/useResizableTable.d.ts.map +1 -0
- package/dist/vue/composables/useServerStats.d.ts +104 -0
- package/dist/vue/composables/useServerStats.d.ts.map +1 -0
- package/dist/vue/composables/useTheme.d.ts +6 -0
- package/dist/vue/composables/useTheme.d.ts.map +1 -0
- package/dist/vue/index-qCQpBftQ.js +1233 -0
- package/dist/vue/index.d.ts +10 -0
- package/dist/vue/index.d.ts.map +1 -0
- package/dist/vue/index.js +11 -0
- package/dist/vue/style.css +1 -0
- package/dist/vue/useApiClient-BQQ9CF-q.js +10 -0
- package/dist/vue/useResizableTable-BoivAevK.js +17 -0
- package/package.json +72 -10
- package/dist/src/dashboard/dashboard_routes.d.ts +0 -16
- package/dist/src/dashboard/dashboard_routes.d.ts.map +0 -1
- package/dist/src/dashboard/dashboard_routes.js +0 -77
- package/dist/src/routes/debug_routes.d.ts +0 -14
- package/dist/src/routes/debug_routes.d.ts.map +0 -1
- package/dist/src/routes/debug_routes.js +0 -42
- package/dist/src/routes/stats_routes.d.ts +0 -14
- package/dist/src/routes/stats_routes.d.ts.map +0 -1
- package/dist/src/routes/stats_routes.js +0 -27
|
@@ -1,801 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Client-side script for the server stats bar.
|
|
3
|
-
*
|
|
4
|
-
* Handles polling, DOM updates, sparkline SVG rendering, tooltips,
|
|
5
|
-
* toggle persistence, stale detection, and formatting utils.
|
|
6
|
-
*
|
|
7
|
-
* Config is read from data-* attributes on #ss-bar:
|
|
8
|
-
* data-endpoint — polling URL
|
|
9
|
-
* data-interval — poll interval in ms
|
|
10
|
-
*/
|
|
11
|
-
;(function () {
|
|
12
|
-
const bar = document.getElementById('ss-bar')
|
|
13
|
-
const toggle = document.getElementById('ss-toggle')
|
|
14
|
-
const dot = document.getElementById('ss-dot')
|
|
15
|
-
const toggleSummary = document.getElementById('ss-toggle-summary')
|
|
16
|
-
|
|
17
|
-
if (!bar || !toggle) return
|
|
18
|
-
|
|
19
|
-
// ── Theme detection & application ───────────────────────────────
|
|
20
|
-
let themeOverride = localStorage.getItem('ss-dash-theme')
|
|
21
|
-
|
|
22
|
-
const applyBarTheme = () => {
|
|
23
|
-
if (themeOverride) {
|
|
24
|
-
bar.setAttribute('data-ss-theme', themeOverride)
|
|
25
|
-
toggle.setAttribute('data-ss-theme', themeOverride)
|
|
26
|
-
} else {
|
|
27
|
-
bar.removeAttribute('data-ss-theme')
|
|
28
|
-
toggle.removeAttribute('data-ss-theme')
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
applyBarTheme()
|
|
33
|
-
|
|
34
|
-
// Expose for debug-panel toggle to call directly
|
|
35
|
-
window.__ssApplyBarTheme = applyBarTheme
|
|
36
|
-
|
|
37
|
-
// Listen for cross-tab theme changes
|
|
38
|
-
window.addEventListener('storage', function (e) {
|
|
39
|
-
if (e.key === 'ss-dash-theme') {
|
|
40
|
-
themeOverride = e.newValue
|
|
41
|
-
applyBarTheme()
|
|
42
|
-
}
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
const ENDPOINT = bar.dataset.endpoint || '/admin/api/server-stats'
|
|
46
|
-
const INTERVAL = Number(bar.dataset.interval) || 3000
|
|
47
|
-
const MAX_HISTORY = 60
|
|
48
|
-
const STALE_MS = 10000
|
|
49
|
-
|
|
50
|
-
// ── Formatting utils ──────────────────────────────────────────────
|
|
51
|
-
|
|
52
|
-
const formatUptime = (s) => {
|
|
53
|
-
const d = Math.floor(s / 86400)
|
|
54
|
-
const h = Math.floor((s % 86400) / 3600)
|
|
55
|
-
const m = Math.floor((s % 3600) / 60)
|
|
56
|
-
if (d > 0) return d + 'd ' + h + 'h'
|
|
57
|
-
if (h > 0) return h + 'h ' + m + 'm'
|
|
58
|
-
return m + 'm'
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const formatBytes = (b) => {
|
|
62
|
-
const mb = b / (1024 * 1024)
|
|
63
|
-
if (mb >= 1024) return (mb / 1024).toFixed(1) + 'G'
|
|
64
|
-
return mb.toFixed(0) + 'M'
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const formatMb = (mb) => {
|
|
68
|
-
if (mb >= 1024) return (mb / 1024).toFixed(1) + 'G'
|
|
69
|
-
return mb.toFixed(1) + 'M'
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const formatCount = (n) => {
|
|
73
|
-
if (n >= 1e6) return (n / 1e6).toFixed(1) + 'M'
|
|
74
|
-
if (n >= 1e3) return (n / 1e3).toFixed(1) + 'K'
|
|
75
|
-
return '' + n
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const formatStatNum = (v, unit) => {
|
|
79
|
-
if (unit === '%') return v.toFixed(1) + '%'
|
|
80
|
-
if (unit === 'ms') return v.toFixed(0) + 'ms'
|
|
81
|
-
if (unit === 'MB') return v.toFixed(1) + 'M'
|
|
82
|
-
if (unit === 'bytes') return formatBytes(v)
|
|
83
|
-
if (unit === '/s' || unit === '/m') return v.toFixed(1)
|
|
84
|
-
return v.toFixed(1)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// ── Color thresholds ──────────────────────────────────────────────
|
|
88
|
-
// Unified threshold helper: returns CSS class based on warn/crit thresholds
|
|
89
|
-
const thresh = (v, warn, crit) => (v > crit ? 'ss-red' : v > warn ? 'ss-amber' : 'ss-green')
|
|
90
|
-
const threshInverse = (v, warn, crit) =>
|
|
91
|
-
v < crit ? 'ss-red' : v < warn ? 'ss-amber' : 'ss-green'
|
|
92
|
-
|
|
93
|
-
// Map color class → CSS variable for sparklines (reads themed value at render time)
|
|
94
|
-
const HEX_FALLBACK = {
|
|
95
|
-
'ss-red': '#f87171',
|
|
96
|
-
'ss-amber': '#fbbf24',
|
|
97
|
-
'ss-green': '#34d399',
|
|
98
|
-
'ss-muted': '#737373',
|
|
99
|
-
}
|
|
100
|
-
const HEX_VAR = {
|
|
101
|
-
'ss-red': '--ss-red-fg',
|
|
102
|
-
'ss-amber': '--ss-amber-fg',
|
|
103
|
-
'ss-green': '--ss-accent',
|
|
104
|
-
'ss-muted': '--ss-muted',
|
|
105
|
-
}
|
|
106
|
-
const hexFromClass = (cls) => {
|
|
107
|
-
const varName = HEX_VAR[cls]
|
|
108
|
-
if (varName) {
|
|
109
|
-
const val = getComputedStyle(bar).getPropertyValue(varName).trim()
|
|
110
|
-
if (val) return val
|
|
111
|
-
}
|
|
112
|
-
return HEX_FALLBACK[cls] || '#34d399'
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const ratioColor = (used, max) => {
|
|
116
|
-
if (max === 0) return 'ss-muted'
|
|
117
|
-
const p = used / max
|
|
118
|
-
return p > 0.8 ? 'ss-red' : p > 0.5 ? 'ss-amber' : 'ss-green'
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// ── Sparkline rendering ───────────────────────────────────────────
|
|
122
|
-
const SVG_NS = 'http://www.w3.org/2000/svg'
|
|
123
|
-
|
|
124
|
-
const renderSparkline = (container, data, color) => {
|
|
125
|
-
container.innerHTML = ''
|
|
126
|
-
const w = 120,
|
|
127
|
-
h = 32,
|
|
128
|
-
pad = 2
|
|
129
|
-
const svg = document.createElementNS(SVG_NS, 'svg')
|
|
130
|
-
svg.setAttribute('width', '' + w)
|
|
131
|
-
svg.setAttribute('height', '' + h)
|
|
132
|
-
svg.style.display = 'block'
|
|
133
|
-
|
|
134
|
-
if (data.length < 2) {
|
|
135
|
-
const txt = document.createElementNS(SVG_NS, 'text')
|
|
136
|
-
txt.setAttribute('x', '' + w / 2)
|
|
137
|
-
txt.setAttribute('y', '' + (h / 2 + 3))
|
|
138
|
-
txt.setAttribute('text-anchor', 'middle')
|
|
139
|
-
txt.setAttribute('fill', '#737373')
|
|
140
|
-
txt.setAttribute('font-size', '9')
|
|
141
|
-
txt.textContent = 'collecting\u2026'
|
|
142
|
-
svg.appendChild(txt)
|
|
143
|
-
container.appendChild(svg)
|
|
144
|
-
return
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const iw = w - pad * 2,
|
|
148
|
-
ih = h - pad * 2
|
|
149
|
-
const mn = Math.min(...data),
|
|
150
|
-
mx = Math.max(...data)
|
|
151
|
-
const range = mx - mn || 1
|
|
152
|
-
const pts = data.map((v, i) => {
|
|
153
|
-
const x = pad + (i / (data.length - 1)) * iw
|
|
154
|
-
const y = pad + ih - ((v - mn) / range) * ih
|
|
155
|
-
return x.toFixed(1) + ',' + y.toFixed(1)
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
const gradId = 'sg-' + color.replace('#', '')
|
|
159
|
-
const defs = document.createElementNS(SVG_NS, 'defs')
|
|
160
|
-
const grad = document.createElementNS(SVG_NS, 'linearGradient')
|
|
161
|
-
grad.setAttribute('id', gradId)
|
|
162
|
-
grad.setAttribute('x1', '0')
|
|
163
|
-
grad.setAttribute('y1', '0')
|
|
164
|
-
grad.setAttribute('x2', '0')
|
|
165
|
-
grad.setAttribute('y2', '1')
|
|
166
|
-
const s1 = document.createElementNS(SVG_NS, 'stop')
|
|
167
|
-
s1.setAttribute('offset', '0%')
|
|
168
|
-
s1.setAttribute('stop-color', color)
|
|
169
|
-
s1.setAttribute('stop-opacity', '0.25')
|
|
170
|
-
const s2 = document.createElementNS(SVG_NS, 'stop')
|
|
171
|
-
s2.setAttribute('offset', '100%')
|
|
172
|
-
s2.setAttribute('stop-color', color)
|
|
173
|
-
s2.setAttribute('stop-opacity', '0.02')
|
|
174
|
-
grad.appendChild(s1)
|
|
175
|
-
grad.appendChild(s2)
|
|
176
|
-
defs.appendChild(grad)
|
|
177
|
-
svg.appendChild(defs)
|
|
178
|
-
|
|
179
|
-
const lastX = (pad + iw).toFixed(1)
|
|
180
|
-
const lastY = (pad + ih).toFixed(1)
|
|
181
|
-
const firstX = pad.toFixed(1)
|
|
182
|
-
const areaD =
|
|
183
|
-
'M' +
|
|
184
|
-
pts[0] +
|
|
185
|
-
' ' +
|
|
186
|
-
pts
|
|
187
|
-
.slice(1)
|
|
188
|
-
.map((p) => 'L' + p)
|
|
189
|
-
.join(' ') +
|
|
190
|
-
' L' +
|
|
191
|
-
lastX +
|
|
192
|
-
',' +
|
|
193
|
-
lastY +
|
|
194
|
-
' L' +
|
|
195
|
-
firstX +
|
|
196
|
-
',' +
|
|
197
|
-
lastY +
|
|
198
|
-
' Z'
|
|
199
|
-
const area = document.createElementNS(SVG_NS, 'path')
|
|
200
|
-
area.setAttribute('d', areaD)
|
|
201
|
-
area.setAttribute('fill', 'url(#' + gradId + ')')
|
|
202
|
-
svg.appendChild(area)
|
|
203
|
-
|
|
204
|
-
const line = document.createElementNS(SVG_NS, 'polyline')
|
|
205
|
-
line.setAttribute('points', pts.join(' '))
|
|
206
|
-
line.setAttribute('fill', 'none')
|
|
207
|
-
line.setAttribute('stroke', color)
|
|
208
|
-
line.setAttribute('stroke-width', '1.5')
|
|
209
|
-
line.setAttribute('stroke-linejoin', 'round')
|
|
210
|
-
line.setAttribute('stroke-linecap', 'round')
|
|
211
|
-
svg.appendChild(line)
|
|
212
|
-
|
|
213
|
-
container.appendChild(svg)
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// ── Stats computation ─────────────────────────────────────────────
|
|
217
|
-
const computeStats = (data) => {
|
|
218
|
-
if (!data || data.length === 0) return null
|
|
219
|
-
const mn = Math.min(...data)
|
|
220
|
-
const mx = Math.max(...data)
|
|
221
|
-
const avg = data.reduce((a, b) => a + b, 0) / data.length
|
|
222
|
-
return { min: mn, max: mx, avg }
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// ── HTML escape ───────────────────────────────────────────────────
|
|
226
|
-
const esc = (s) => {
|
|
227
|
-
if (typeof s !== 'string') s = '' + s
|
|
228
|
-
return s
|
|
229
|
-
.replace(/&/g, '&')
|
|
230
|
-
.replace(/</g, '<')
|
|
231
|
-
.replace(/>/g, '>')
|
|
232
|
-
.replace(/"/g, '"')
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// ── Tooltip rendering ─────────────────────────────────────────────
|
|
236
|
-
let pinnedBadge = null
|
|
237
|
-
let activeTooltip = null
|
|
238
|
-
|
|
239
|
-
const positionTooltip = (tip, badge) => {
|
|
240
|
-
const badgeRect = badge.getBoundingClientRect()
|
|
241
|
-
const barRect = bar.getBoundingClientRect()
|
|
242
|
-
const leftPos = badgeRect.left - barRect.left + badgeRect.width / 2
|
|
243
|
-
tip.style.bottom = '100%'
|
|
244
|
-
tip.style.left = leftPos + 'px'
|
|
245
|
-
tip.style.transform = 'translateX(-50%)'
|
|
246
|
-
tip.style.marginBottom = '10px'
|
|
247
|
-
requestAnimationFrame(() => {
|
|
248
|
-
const tipRect = tip.getBoundingClientRect()
|
|
249
|
-
let shift = 0
|
|
250
|
-
if (tipRect.left < 8) shift = 8 - tipRect.left
|
|
251
|
-
else if (tipRect.right > window.innerWidth - 8) shift = window.innerWidth - 8 - tipRect.right
|
|
252
|
-
if (shift) tip.style.transform = 'translateX(calc(-50% + ' + shift + 'px))'
|
|
253
|
-
})
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const hideCurrentTooltip = () => {
|
|
257
|
-
if (activeTooltip) {
|
|
258
|
-
activeTooltip.remove()
|
|
259
|
-
activeTooltip = null
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
const unpinTooltip = () => {
|
|
264
|
-
if (pinnedBadge) {
|
|
265
|
-
pinnedBadge.classList.remove('ss-pinned')
|
|
266
|
-
pinnedBadge = null
|
|
267
|
-
}
|
|
268
|
-
hideCurrentTooltip()
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const showTooltip = (badge, historyData, color, title, unit, currentValue, details, pinned) => {
|
|
272
|
-
hideCurrentTooltip()
|
|
273
|
-
const tip = document.createElement('div')
|
|
274
|
-
tip.className = pinned ? 'ss-tooltip ss-pinned' : 'ss-tooltip'
|
|
275
|
-
|
|
276
|
-
let html = '<div class="ss-tooltip-inner" style="position:relative">'
|
|
277
|
-
if (pinned) {
|
|
278
|
-
html += '<button class="ss-tooltip-close" data-ss-close>\u00D7</button>'
|
|
279
|
-
}
|
|
280
|
-
html +=
|
|
281
|
-
'<div class="ss-tooltip-header"><span class="ss-tooltip-title">' + esc(title) + '</span>'
|
|
282
|
-
if (unit) html += '<span class="ss-tooltip-unit">' + esc(unit) + '</span>'
|
|
283
|
-
html += '</div>'
|
|
284
|
-
html +=
|
|
285
|
-
'<div class="ss-tooltip-current"><span class="ss-tooltip-current-label">Current: </span>'
|
|
286
|
-
html += '<span class="ss-tooltip-current-value">' + esc(currentValue) + '</span></div>'
|
|
287
|
-
|
|
288
|
-
const st = computeStats(historyData)
|
|
289
|
-
if (st) {
|
|
290
|
-
html += '<div class="ss-tooltip-stats">'
|
|
291
|
-
html += '<span>Min: ' + formatStatNum(st.min, unit) + '</span>'
|
|
292
|
-
html += '<span>Max: ' + formatStatNum(st.max, unit) + '</span>'
|
|
293
|
-
html += '<span>Avg: ' + formatStatNum(st.avg, unit) + '</span>'
|
|
294
|
-
html += '</div>'
|
|
295
|
-
}
|
|
296
|
-
if (details) {
|
|
297
|
-
html += '<div class="ss-tooltip-details">' + esc(details) + '</div>'
|
|
298
|
-
}
|
|
299
|
-
if (historyData && historyData.length > 0) {
|
|
300
|
-
html += '<div class="ss-tooltip-sparkline" data-sparkline></div>'
|
|
301
|
-
html +=
|
|
302
|
-
'<div class="ss-tooltip-samples">Last ' +
|
|
303
|
-
Math.min(historyData.length, MAX_HISTORY) +
|
|
304
|
-
' samples (~' +
|
|
305
|
-
Math.round((Math.min(historyData.length, MAX_HISTORY) * 3) / 60) +
|
|
306
|
-
' min)</div>'
|
|
307
|
-
}
|
|
308
|
-
html += '</div><div class="ss-tooltip-arrow"></div>'
|
|
309
|
-
tip.innerHTML = html
|
|
310
|
-
|
|
311
|
-
bar.appendChild(tip)
|
|
312
|
-
positionTooltip(tip, badge)
|
|
313
|
-
activeTooltip = tip
|
|
314
|
-
|
|
315
|
-
if (pinned) {
|
|
316
|
-
const closeBtn = tip.querySelector('[data-ss-close]')
|
|
317
|
-
if (closeBtn) {
|
|
318
|
-
closeBtn.addEventListener('click', (e) => {
|
|
319
|
-
e.stopPropagation()
|
|
320
|
-
unpinTooltip()
|
|
321
|
-
})
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
const sparkContainer = tip.querySelector('[data-sparkline]')
|
|
326
|
-
if (sparkContainer && historyData && historyData.length > 0) {
|
|
327
|
-
renderSparkline(sparkContainer, historyData, color || '#34d399')
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
const refreshPinnedTooltip = () => {
|
|
332
|
-
if (!pinnedBadge || !window.__ssLatest) return
|
|
333
|
-
const badgeId = pinnedBadge.id.replace('ss-b-', '')
|
|
334
|
-
const b = BADGES.find((x) => x.id === badgeId)
|
|
335
|
-
if (!b) return
|
|
336
|
-
const valEl = pinnedBadge.querySelector('.ss-value')
|
|
337
|
-
const currentVal = valEl ? valEl.textContent : ''
|
|
338
|
-
const hist = b.hist ? history[b.hist] || [] : []
|
|
339
|
-
const color = b.color ? hexFromClass(b.color(window.__ssLatest)) : '#34d399'
|
|
340
|
-
const title = typeof b.title === 'string' ? b.title : b.label
|
|
341
|
-
const details = typeof b.detail === 'function' ? b.detail(window.__ssLatest) : b.detail || ''
|
|
342
|
-
showTooltip(pinnedBadge, hist, color, title, b.unit, currentVal, details, true)
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// Close pinned tooltip on click outside
|
|
346
|
-
document.addEventListener('click', (e) => {
|
|
347
|
-
if (!pinnedBadge) return
|
|
348
|
-
if (!pinnedBadge.contains(e.target) && !(activeTooltip && activeTooltip.contains(e.target))) {
|
|
349
|
-
unpinTooltip()
|
|
350
|
-
}
|
|
351
|
-
})
|
|
352
|
-
|
|
353
|
-
// Close pinned tooltip on Escape
|
|
354
|
-
document.addEventListener('keydown', (e) => {
|
|
355
|
-
if (e.key === 'Escape' && pinnedBadge) unpinTooltip()
|
|
356
|
-
})
|
|
357
|
-
|
|
358
|
-
// ── Badge definitions ─────────────────────────────────────────────
|
|
359
|
-
// Compact badge defs: val (getValue), color (getColor→class), title, detail, hist (historyKey), unit, show (showIf), href
|
|
360
|
-
const BADGES = [
|
|
361
|
-
// Process
|
|
362
|
-
{
|
|
363
|
-
id: 'node',
|
|
364
|
-
label: 'NODE',
|
|
365
|
-
val: (s) => s.nodeVersion,
|
|
366
|
-
title: 'Node.js Runtime',
|
|
367
|
-
detail: 'Node.js version running the server process',
|
|
368
|
-
},
|
|
369
|
-
{
|
|
370
|
-
id: 'up',
|
|
371
|
-
label: 'UP',
|
|
372
|
-
val: (s) => formatUptime(s.uptime),
|
|
373
|
-
title: 'Process Uptime',
|
|
374
|
-
detail: (s) =>
|
|
375
|
-
'Process uptime: ' + formatUptime(s.uptime) + ' (' + Math.floor(s.uptime) + 's)',
|
|
376
|
-
},
|
|
377
|
-
{
|
|
378
|
-
id: 'cpu',
|
|
379
|
-
label: 'CPU',
|
|
380
|
-
val: (s) => s.cpuPercent.toFixed(1) + '%',
|
|
381
|
-
color: (s) => thresh(s.cpuPercent, 50, 80),
|
|
382
|
-
unit: '%',
|
|
383
|
-
title: 'CPU Usage',
|
|
384
|
-
detail: 'Percentage of one CPU core. >50% amber, >80% red.',
|
|
385
|
-
hist: 'cpuPercent',
|
|
386
|
-
},
|
|
387
|
-
{
|
|
388
|
-
id: 'evt',
|
|
389
|
-
label: 'EVT',
|
|
390
|
-
val: (s) => s.eventLoopLag.toFixed(1) + 'ms',
|
|
391
|
-
color: (s) => thresh(s.eventLoopLag, 20, 50),
|
|
392
|
-
unit: 'ms',
|
|
393
|
-
title: 'Event Loop Latency',
|
|
394
|
-
detail: 'Delay between scheduled and actual timer execution. >20ms amber, >50ms red.',
|
|
395
|
-
hist: 'eventLoopLag',
|
|
396
|
-
},
|
|
397
|
-
// Memory
|
|
398
|
-
{
|
|
399
|
-
id: 'mem',
|
|
400
|
-
label: 'MEM',
|
|
401
|
-
val: (s) => formatBytes(s.memHeapUsed),
|
|
402
|
-
unit: 'bytes',
|
|
403
|
-
title: 'V8 Heap Usage',
|
|
404
|
-
detail: (s) =>
|
|
405
|
-
'Heap: ' +
|
|
406
|
-
formatBytes(s.memHeapUsed) +
|
|
407
|
-
' used of ' +
|
|
408
|
-
formatBytes(s.memHeapTotal) +
|
|
409
|
-
' allocated',
|
|
410
|
-
hist: 'memHeapUsed',
|
|
411
|
-
},
|
|
412
|
-
{
|
|
413
|
-
id: 'rss',
|
|
414
|
-
label: 'RSS',
|
|
415
|
-
val: (s) => formatBytes(s.memRss),
|
|
416
|
-
unit: 'bytes',
|
|
417
|
-
title: 'Resident Set Size',
|
|
418
|
-
detail: 'Total OS memory footprint including heap, stack, and native allocations',
|
|
419
|
-
hist: 'memRss',
|
|
420
|
-
},
|
|
421
|
-
{
|
|
422
|
-
id: 'sys',
|
|
423
|
-
label: 'SYS',
|
|
424
|
-
val: (s) =>
|
|
425
|
-
formatMb(s.systemMemoryTotalMb - s.systemMemoryFreeMb) +
|
|
426
|
-
'/' +
|
|
427
|
-
formatMb(s.systemMemoryTotalMb),
|
|
428
|
-
unit: 'MB',
|
|
429
|
-
title: 'System Memory',
|
|
430
|
-
detail: (s) =>
|
|
431
|
-
formatMb(s.systemMemoryFreeMb) + ' free of ' + formatMb(s.systemMemoryTotalMb) + ' total',
|
|
432
|
-
hist: '_sysMemUsed',
|
|
433
|
-
},
|
|
434
|
-
// HTTP
|
|
435
|
-
{
|
|
436
|
-
id: 'rps',
|
|
437
|
-
label: 'REQ/s',
|
|
438
|
-
val: (s) => s.requestsPerSecond.toFixed(1),
|
|
439
|
-
unit: '/s',
|
|
440
|
-
title: 'Requests per Second',
|
|
441
|
-
detail: 'HTTP requests per second over a 60-second rolling window',
|
|
442
|
-
hist: 'requestsPerSecond',
|
|
443
|
-
},
|
|
444
|
-
{
|
|
445
|
-
id: 'avg',
|
|
446
|
-
label: 'AVG',
|
|
447
|
-
val: (s) => s.avgResponseTimeMs.toFixed(0) + 'ms',
|
|
448
|
-
color: (s) => thresh(s.avgResponseTimeMs, 200, 500),
|
|
449
|
-
unit: 'ms',
|
|
450
|
-
title: 'Avg Response Time',
|
|
451
|
-
detail: 'Average HTTP response time (60s window). >200ms amber, >500ms red.',
|
|
452
|
-
hist: 'avgResponseTimeMs',
|
|
453
|
-
},
|
|
454
|
-
{
|
|
455
|
-
id: 'err',
|
|
456
|
-
label: 'ERR',
|
|
457
|
-
val: (s) => s.errorRate.toFixed(1) + '%',
|
|
458
|
-
color: (s) => thresh(s.errorRate, 1, 5),
|
|
459
|
-
unit: '%',
|
|
460
|
-
title: 'Error Rate',
|
|
461
|
-
detail: '5xx error rate (60s window). >1% amber, >5% red.',
|
|
462
|
-
hist: 'errorRate',
|
|
463
|
-
},
|
|
464
|
-
{
|
|
465
|
-
id: 'conn',
|
|
466
|
-
label: 'CONN',
|
|
467
|
-
val: (s) => '' + s.activeHttpConnections,
|
|
468
|
-
title: 'Active Connections',
|
|
469
|
-
detail: 'Currently open HTTP connections',
|
|
470
|
-
hist: 'activeHttpConnections',
|
|
471
|
-
},
|
|
472
|
-
// DB
|
|
473
|
-
{
|
|
474
|
-
id: 'db',
|
|
475
|
-
label: 'DB',
|
|
476
|
-
val: (s) => s.dbPoolUsed + '/' + s.dbPoolFree + '/' + s.dbPoolMax,
|
|
477
|
-
color: (s) => ratioColor(s.dbPoolUsed, s.dbPoolMax),
|
|
478
|
-
title: 'Database Pool',
|
|
479
|
-
detail: (s) =>
|
|
480
|
-
'Used: ' +
|
|
481
|
-
s.dbPoolUsed +
|
|
482
|
-
', Free: ' +
|
|
483
|
-
s.dbPoolFree +
|
|
484
|
-
', Pending: ' +
|
|
485
|
-
s.dbPoolPending +
|
|
486
|
-
', Max: ' +
|
|
487
|
-
s.dbPoolMax,
|
|
488
|
-
hist: 'dbPoolUsed',
|
|
489
|
-
},
|
|
490
|
-
// Redis
|
|
491
|
-
{
|
|
492
|
-
id: 'redis',
|
|
493
|
-
label: 'REDIS',
|
|
494
|
-
val: (s) => (s.redisOk ? '\u2713' : '\u2717'),
|
|
495
|
-
color: (s) => (s.redisOk ? 'ss-green' : 'ss-red'),
|
|
496
|
-
title: 'Redis Status',
|
|
497
|
-
detail: (s) => (s.redisOk ? 'Redis is connected and responding' : 'Redis is not responding!'),
|
|
498
|
-
},
|
|
499
|
-
{
|
|
500
|
-
id: 'rmem',
|
|
501
|
-
label: 'MEM',
|
|
502
|
-
val: (s) => s.redisMemoryUsedMb.toFixed(1) + 'M',
|
|
503
|
-
unit: 'MB',
|
|
504
|
-
title: 'Redis Memory',
|
|
505
|
-
detail: (s) => 'Redis server memory usage: ' + s.redisMemoryUsedMb.toFixed(1) + ' MB',
|
|
506
|
-
hist: 'redisMemoryUsedMb',
|
|
507
|
-
show: (s) => s.redisOk,
|
|
508
|
-
},
|
|
509
|
-
{
|
|
510
|
-
id: 'rkeys',
|
|
511
|
-
label: 'KEYS',
|
|
512
|
-
val: (s) => formatCount(s.redisKeysCount),
|
|
513
|
-
title: 'Redis Keys',
|
|
514
|
-
detail: (s) => 'Total keys in Redis: ' + s.redisKeysCount,
|
|
515
|
-
hist: 'redisKeysCount',
|
|
516
|
-
show: (s) => s.redisOk,
|
|
517
|
-
},
|
|
518
|
-
{
|
|
519
|
-
id: 'rhit',
|
|
520
|
-
label: 'HIT',
|
|
521
|
-
val: (s) => s.redisHitRate.toFixed(0) + '%',
|
|
522
|
-
color: (s) => threshInverse(s.redisHitRate, 90, 70),
|
|
523
|
-
unit: '%',
|
|
524
|
-
title: 'Redis Hit Rate',
|
|
525
|
-
detail: 'Cache hit rate. <90% amber, <70% red.',
|
|
526
|
-
hist: 'redisHitRate',
|
|
527
|
-
show: (s) => s.redisOk,
|
|
528
|
-
},
|
|
529
|
-
// Queue
|
|
530
|
-
{
|
|
531
|
-
id: 'q',
|
|
532
|
-
label: 'Q',
|
|
533
|
-
val: (s) => s.queueActive + '/' + s.queueWaiting + '/' + s.queueDelayed,
|
|
534
|
-
color: (s) => (s.queueFailed > 0 ? 'ss-amber' : 'ss-green'),
|
|
535
|
-
title: 'Job Queue',
|
|
536
|
-
detail: (s) =>
|
|
537
|
-
'Active: ' +
|
|
538
|
-
s.queueActive +
|
|
539
|
-
', Waiting: ' +
|
|
540
|
-
s.queueWaiting +
|
|
541
|
-
', Delayed: ' +
|
|
542
|
-
s.queueDelayed +
|
|
543
|
-
', Failed: ' +
|
|
544
|
-
s.queueFailed,
|
|
545
|
-
hist: 'queueActive',
|
|
546
|
-
},
|
|
547
|
-
{
|
|
548
|
-
id: 'workers',
|
|
549
|
-
label: 'WORKERS',
|
|
550
|
-
val: (s) => '' + s.queueWorkerCount,
|
|
551
|
-
title: 'Queue Workers',
|
|
552
|
-
detail: (s) => 'Connected queue worker processes: ' + s.queueWorkerCount,
|
|
553
|
-
},
|
|
554
|
-
// App
|
|
555
|
-
{
|
|
556
|
-
id: 'users',
|
|
557
|
-
label: 'USERS',
|
|
558
|
-
val: (s) => '' + s.onlineUsers,
|
|
559
|
-
title: 'Online Users',
|
|
560
|
-
detail: 'Active user sessions (via Transmit)',
|
|
561
|
-
hist: 'onlineUsers',
|
|
562
|
-
},
|
|
563
|
-
{
|
|
564
|
-
id: 'hooks',
|
|
565
|
-
label: 'HOOKS',
|
|
566
|
-
val: (s) => '' + s.pendingWebhooks,
|
|
567
|
-
color: (s) => (s.pendingWebhooks > 100 ? 'ss-amber' : 'ss-green'),
|
|
568
|
-
title: 'Pending Webhooks',
|
|
569
|
-
detail: 'Webhook events awaiting delivery. >100 amber.',
|
|
570
|
-
hist: 'pendingWebhooks',
|
|
571
|
-
},
|
|
572
|
-
{
|
|
573
|
-
id: 'mail',
|
|
574
|
-
label: 'MAIL',
|
|
575
|
-
val: (s) => '' + s.pendingEmails,
|
|
576
|
-
color: (s) => (s.pendingEmails > 100 ? 'ss-amber' : 'ss-green'),
|
|
577
|
-
title: 'Pending Emails',
|
|
578
|
-
detail: 'Scheduled emails awaiting send. >100 amber.',
|
|
579
|
-
hist: 'pendingEmails',
|
|
580
|
-
},
|
|
581
|
-
// Logs
|
|
582
|
-
{
|
|
583
|
-
id: 'logerr',
|
|
584
|
-
label: 'LOG ERR',
|
|
585
|
-
val: (s) => '' + s.logErrorsLast5m,
|
|
586
|
-
color: (s) =>
|
|
587
|
-
s.logErrorsLast5m > 0 ? 'ss-red' : s.logWarningsLast5m > 0 ? 'ss-amber' : 'ss-green',
|
|
588
|
-
title: 'Log Errors (5m)',
|
|
589
|
-
detail: (s) =>
|
|
590
|
-
s.logErrorsLast5m +
|
|
591
|
-
' error/fatal entries and ' +
|
|
592
|
-
s.logWarningsLast5m +
|
|
593
|
-
' warnings in the last 5 minutes',
|
|
594
|
-
hist: 'logErrorsLast5m',
|
|
595
|
-
href: '/admin/logs?hasError=true',
|
|
596
|
-
},
|
|
597
|
-
{
|
|
598
|
-
id: 'lograte',
|
|
599
|
-
label: 'LOG/m',
|
|
600
|
-
val: (s) => '' + s.logEntriesPerMinute,
|
|
601
|
-
unit: '/m',
|
|
602
|
-
title: 'Log Rate',
|
|
603
|
-
detail: (s) => s.logEntriesLast5m + ' total entries in the last 5 minutes',
|
|
604
|
-
hist: 'logEntriesPerMinute',
|
|
605
|
-
href: '/admin/logs',
|
|
606
|
-
},
|
|
607
|
-
]
|
|
608
|
-
|
|
609
|
-
// ── State ─────────────────────────────────────────────────────────
|
|
610
|
-
const history = {}
|
|
611
|
-
let lastSuccess = 0
|
|
612
|
-
let visible = localStorage.getItem('admin:stats-bar') !== 'hidden'
|
|
613
|
-
|
|
614
|
-
// Apply initial visibility
|
|
615
|
-
applyVisibility()
|
|
616
|
-
|
|
617
|
-
function applyVisibility() {
|
|
618
|
-
bar.className = visible ? 'ss-bar' : 'ss-bar ss-hidden'
|
|
619
|
-
toggle.className = visible ? 'ss-toggle ss-visible' : 'ss-toggle ss-collapsed'
|
|
620
|
-
toggle.title = visible ? 'Hide stats bar' : 'Show stats bar'
|
|
621
|
-
const arrow = toggle.querySelector('.ss-toggle-arrow')
|
|
622
|
-
if (arrow) arrow.textContent = visible ? '\u25BC' : '\u25B2'
|
|
623
|
-
const label = toggle.querySelector('.ss-toggle-label')
|
|
624
|
-
if (label) label.textContent = visible ? 'hide stats' : ''
|
|
625
|
-
if (toggleSummary) toggleSummary.style.display = visible ? 'none' : 'flex'
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
toggle.addEventListener('click', () => {
|
|
629
|
-
visible = !visible
|
|
630
|
-
localStorage.setItem('admin:stats-bar', visible ? 'visible' : 'hidden')
|
|
631
|
-
applyVisibility()
|
|
632
|
-
})
|
|
633
|
-
|
|
634
|
-
// ── Fetch & Update ────────────────────────────────────────────────
|
|
635
|
-
const updateDom = (stats) => {
|
|
636
|
-
window.__ssLatest = stats
|
|
637
|
-
lastSuccess = Date.now()
|
|
638
|
-
if (dot) dot.className = 'ss-dot'
|
|
639
|
-
|
|
640
|
-
BADGES.forEach((b) => {
|
|
641
|
-
const el = document.getElementById('ss-b-' + b.id)
|
|
642
|
-
if (!el) return
|
|
643
|
-
|
|
644
|
-
// Conditional visibility
|
|
645
|
-
if (b.show) {
|
|
646
|
-
el.style.display = b.show(stats) ? 'flex' : 'none'
|
|
647
|
-
if (!b.show(stats)) return
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
// Update value
|
|
651
|
-
const valEl = el.querySelector('.ss-value')
|
|
652
|
-
if (valEl) {
|
|
653
|
-
valEl.textContent = b.val(stats)
|
|
654
|
-
|
|
655
|
-
// Update color
|
|
656
|
-
if (b.color) {
|
|
657
|
-
valEl.classList.remove('ss-green', 'ss-amber', 'ss-red', 'ss-muted')
|
|
658
|
-
valEl.classList.add(b.color(stats))
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
// Push history
|
|
663
|
-
if (b.hist) {
|
|
664
|
-
let val
|
|
665
|
-
if (b.hist === '_sysMemUsed') {
|
|
666
|
-
val = stats.systemMemoryTotalMb - stats.systemMemoryFreeMb
|
|
667
|
-
} else {
|
|
668
|
-
val = stats[b.hist]
|
|
669
|
-
}
|
|
670
|
-
if (typeof val === 'number') {
|
|
671
|
-
if (!history[b.hist]) history[b.hist] = []
|
|
672
|
-
history[b.hist].push(val)
|
|
673
|
-
if (history[b.hist].length > MAX_HISTORY) history[b.hist].shift()
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
})
|
|
677
|
-
|
|
678
|
-
// Update toggle summary for collapsed state
|
|
679
|
-
if (toggleSummary) {
|
|
680
|
-
const cpuEl = toggleSummary.querySelector('[data-ts=cpu]')
|
|
681
|
-
const memEl = toggleSummary.querySelector('[data-ts=mem]')
|
|
682
|
-
const redisEl = toggleSummary.querySelector('[data-ts=redis]')
|
|
683
|
-
if (cpuEl) {
|
|
684
|
-
cpuEl.textContent = stats.cpuPercent.toFixed(0) + '%'
|
|
685
|
-
cpuEl.className = 'ss-value ' + thresh(stats.cpuPercent, 50, 80)
|
|
686
|
-
}
|
|
687
|
-
if (memEl) {
|
|
688
|
-
memEl.textContent = formatBytes(stats.memHeapUsed)
|
|
689
|
-
memEl.className = 'ss-value ss-green'
|
|
690
|
-
}
|
|
691
|
-
if (redisEl) {
|
|
692
|
-
redisEl.textContent = stats.redisOk ? '\u2713' : '\u2717'
|
|
693
|
-
redisEl.className = 'ss-value ' + (stats.redisOk ? 'ss-green' : 'ss-red')
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
refreshPinnedTooltip()
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
const doFetch = () => {
|
|
701
|
-
fetch(ENDPOINT, { credentials: 'same-origin' })
|
|
702
|
-
.then((r) => {
|
|
703
|
-
if (r.status === 403 || r.status === 401) {
|
|
704
|
-
bar.className = 'ss-bar ss-hidden'
|
|
705
|
-
toggle.style.display = 'none'
|
|
706
|
-
return null
|
|
707
|
-
}
|
|
708
|
-
return r.json()
|
|
709
|
-
})
|
|
710
|
-
.then((data) => {
|
|
711
|
-
if (data) updateDom(data)
|
|
712
|
-
})
|
|
713
|
-
.catch(() => {
|
|
714
|
-
// network error — mark stale
|
|
715
|
-
})
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
// Stale detection
|
|
719
|
-
setInterval(() => {
|
|
720
|
-
if (lastSuccess > 0 && Date.now() - lastSuccess > STALE_MS && dot) {
|
|
721
|
-
dot.className = 'ss-dot ss-stale'
|
|
722
|
-
}
|
|
723
|
-
}, 2000)
|
|
724
|
-
|
|
725
|
-
// ── Tooltip event binding ─────────────────────────────────────────
|
|
726
|
-
const getBadgeTooltipData = (b, el) => {
|
|
727
|
-
const valEl = el.querySelector('.ss-value')
|
|
728
|
-
const currentVal = valEl ? valEl.textContent : ''
|
|
729
|
-
const hist = b.hist ? history[b.hist] || [] : []
|
|
730
|
-
let color = '#34d399'
|
|
731
|
-
if (b.color && window.__ssLatest) {
|
|
732
|
-
color = hexFromClass(b.color(window.__ssLatest))
|
|
733
|
-
}
|
|
734
|
-
const title = typeof b.title === 'string' ? b.title : b.label
|
|
735
|
-
let details = ''
|
|
736
|
-
if (b.detail) {
|
|
737
|
-
details =
|
|
738
|
-
typeof b.detail === 'function'
|
|
739
|
-
? window.__ssLatest
|
|
740
|
-
? b.detail(window.__ssLatest)
|
|
741
|
-
: b.detail({})
|
|
742
|
-
: b.detail
|
|
743
|
-
}
|
|
744
|
-
return { hist, color, title, details, currentVal, unit: b.unit }
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
BADGES.forEach((b) => {
|
|
748
|
-
const el = document.getElementById('ss-b-' + b.id)
|
|
749
|
-
if (!el) return
|
|
750
|
-
|
|
751
|
-
// Hover: show tooltip preview (non-pinned)
|
|
752
|
-
el.addEventListener('mouseenter', () => {
|
|
753
|
-
if (pinnedBadge) return
|
|
754
|
-
const d = getBadgeTooltipData(b, el)
|
|
755
|
-
showTooltip(el, d.hist, d.color, d.title, d.unit, d.currentVal, d.details, false)
|
|
756
|
-
})
|
|
757
|
-
el.addEventListener('mouseleave', () => {
|
|
758
|
-
if (pinnedBadge) return
|
|
759
|
-
hideCurrentTooltip()
|
|
760
|
-
})
|
|
761
|
-
|
|
762
|
-
// Click: pin/unpin tooltip
|
|
763
|
-
el.addEventListener('click', (e) => {
|
|
764
|
-
e.stopPropagation()
|
|
765
|
-
if (b.href && pinnedBadge === el) {
|
|
766
|
-
window.location.href = b.href
|
|
767
|
-
return
|
|
768
|
-
}
|
|
769
|
-
if (pinnedBadge === el) {
|
|
770
|
-
unpinTooltip()
|
|
771
|
-
return
|
|
772
|
-
}
|
|
773
|
-
unpinTooltip()
|
|
774
|
-
pinnedBadge = el
|
|
775
|
-
el.classList.add('ss-pinned')
|
|
776
|
-
const d = getBadgeTooltipData(b, el)
|
|
777
|
-
showTooltip(el, d.hist, d.color, d.title, d.unit, d.currentVal, d.details, true)
|
|
778
|
-
})
|
|
779
|
-
})
|
|
780
|
-
|
|
781
|
-
// ── Horizontal wheel scroll on the bar ──────────────────────────────
|
|
782
|
-
const scrollEl = document.getElementById('ss-bar-scroll')
|
|
783
|
-
if (scrollEl) {
|
|
784
|
-
scrollEl.addEventListener(
|
|
785
|
-
'wheel',
|
|
786
|
-
(e) => {
|
|
787
|
-
if (Math.abs(e.deltaX) > Math.abs(e.deltaY)) return
|
|
788
|
-
e.preventDefault()
|
|
789
|
-
scrollEl.scrollLeft += e.deltaY
|
|
790
|
-
},
|
|
791
|
-
{ passive: false }
|
|
792
|
-
)
|
|
793
|
-
scrollEl.addEventListener('scroll', () => {
|
|
794
|
-
if (pinnedBadge && activeTooltip) positionTooltip(activeTooltip, pinnedBadge)
|
|
795
|
-
})
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
// ── Start polling ─────────────────────────────────────────────────
|
|
799
|
-
doFetch()
|
|
800
|
-
setInterval(doFetch, INTERVAL)
|
|
801
|
-
})()
|
|
1
|
+
(function(){"use strict";var Y,p,we,F,Ce,Te,Se,Ee,ie,le,ae,X={},Q=[],pt=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,z=Array.isArray;function L(e,t){for(var n in t)e[n]=t[n];return e}function ue(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function K(e,t,n){var r,s,o,i={};for(o in t)o=="key"?r=t[o]:o=="ref"?s=t[o]:i[o]=t[o];if(arguments.length>2&&(i.children=arguments.length>3?Y.call(arguments,2):n),typeof e=="function"&&e.defaultProps!=null)for(o in e.defaultProps)i[o]===void 0&&(i[o]=e.defaultProps[o]);return J(e,i,r,s,null)}function J(e,t,n,r,s){var o={type:e,props:t,key:n,ref:r,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:s??++we,__i:-1,__u:0};return s==null&&p.vnode!=null&&p.vnode(o),o}function N(e){return e.children}function R(e,t){this.props=e,this.context=t}function W(e,t){if(t==null)return e.__?W(e.__,e.__i+1):null;for(var n;t<e.__k.length;t++)if((n=e.__k[t])!=null&&n.__e!=null)return n.__e;return typeof e.type=="function"?W(e):null}function mt(e){if(e.__P&&e.__d){var t=e.__v,n=t.__e,r=[],s=[],o=L({},t);o.__v=t.__v+1,p.vnode&&p.vnode(o),ce(e.__P,o,t,e.__n,e.__P.namespaceURI,32&t.__u?[n]:null,r,n??W(t),!!(32&t.__u),s),o.__v=t.__v,o.__.__k[o.__i]=o,He(r,o,s),t.__e=t.__=null,o.__e!=n&&$e(o)}}function $e(e){if((e=e.__)!=null&&e.__c!=null)return e.__e=e.__c.base=null,e.__k.some(function(t){if(t!=null&&t.__e!=null)return e.__e=e.__c.base=t.__e}),$e(e)}function xe(e){(!e.__d&&(e.__d=!0)&&F.push(e)&&!Z.__r++||Ce!=p.debounceRendering)&&((Ce=p.debounceRendering)||Te)(Z)}function Z(){for(var e,t=1;F.length;)F.length>t&&F.sort(Se),e=F.shift(),t=F.length,mt(e);Z.__r=0}function Pe(e,t,n,r,s,o,i,a,c,u,d){var l,f,_,m,k,b,v,g=r&&r.__k||Q,y=t.length;for(c=gt(n,t,g,c,y),l=0;l<y;l++)(_=n.__k[l])!=null&&(f=_.__i!=-1&&g[_.__i]||X,_.__i=l,b=ce(e,_,f,s,o,i,a,c,u,d),m=_.__e,_.ref&&f.ref!=_.ref&&(f.ref&&de(f.ref,null,_),d.push(_.ref,_.__c||m,_)),k==null&&m!=null&&(k=m),(v=!!(4&_.__u))||f.__k===_.__k?c=Me(_,c,e,v):typeof _.type=="function"&&b!==void 0?c=b:m&&(c=m.nextSibling),_.__u&=-7);return n.__e=k,c}function gt(e,t,n,r,s){var o,i,a,c,u,d=n.length,l=d,f=0;for(e.__k=new Array(s),o=0;o<s;o++)(i=t[o])!=null&&typeof i!="boolean"&&typeof i!="function"?(typeof i=="string"||typeof i=="number"||typeof i=="bigint"||i.constructor==String?i=e.__k[o]=J(null,i,null,null,null):z(i)?i=e.__k[o]=J(N,{children:i},null,null,null):i.constructor===void 0&&i.__b>0?i=e.__k[o]=J(i.type,i.props,i.key,i.ref?i.ref:null,i.__v):e.__k[o]=i,c=o+f,i.__=e,i.__b=e.__b+1,a=null,(u=i.__i=vt(i,n,c,l))!=-1&&(l--,(a=n[u])&&(a.__u|=2)),a==null||a.__v==null?(u==-1&&(s>d?f--:s<d&&f++),typeof i.type!="function"&&(i.__u|=4)):u!=c&&(u==c-1?f--:u==c+1?f++:(u>c?f--:f++,i.__u|=4))):e.__k[o]=null;if(l)for(o=0;o<d;o++)(a=n[o])!=null&&(2&a.__u)==0&&(a.__e==r&&(r=W(a)),Re(a,a));return r}function Me(e,t,n,r){var s,o;if(typeof e.type=="function"){for(s=e.__k,o=0;s&&o<s.length;o++)s[o]&&(s[o].__=e,t=Me(s[o],t,n,r));return t}e.__e!=t&&(r&&(t&&e.type&&!t.parentNode&&(t=W(e)),n.insertBefore(e.__e,t||null)),t=e.__e);do t=t&&t.nextSibling;while(t!=null&&t.nodeType==8);return t}function ee(e,t){return t=t||[],e==null||typeof e=="boolean"||(z(e)?e.some(function(n){ee(n,t)}):t.push(e)),t}function vt(e,t,n,r){var s,o,i,a=e.key,c=e.type,u=t[n],d=u!=null&&(2&u.__u)==0;if(u===null&&a==null||d&&a==u.key&&c==u.type)return n;if(r>(d?1:0)){for(s=n-1,o=n+1;s>=0||o<t.length;)if((u=t[i=s>=0?s--:o++])!=null&&(2&u.__u)==0&&a==u.key&&c==u.type)return i}return-1}function Ue(e,t,n){t[0]=="-"?e.setProperty(t,n??""):e[t]=n==null?"":typeof n!="number"||pt.test(t)?n:n+"px"}function te(e,t,n,r,s){var o,i;e:if(t=="style")if(typeof n=="string")e.style.cssText=n;else{if(typeof r=="string"&&(e.style.cssText=r=""),r)for(t in r)n&&t in n||Ue(e.style,t,"");if(n)for(t in n)r&&n[t]==r[t]||Ue(e.style,t,n[t])}else if(t[0]=="o"&&t[1]=="n")o=t!=(t=t.replace(Ee,"$1")),i=t.toLowerCase(),t=i in e||t=="onFocusOut"||t=="onFocusIn"?i.slice(2):t.slice(2),e.l||(e.l={}),e.l[t+o]=n,n?r?n.u=r.u:(n.u=ie,e.addEventListener(t,o?ae:le,o)):e.removeEventListener(t,o?ae:le,o);else{if(s=="http://www.w3.org/2000/svg")t=t.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(t!="width"&&t!="height"&&t!="href"&&t!="list"&&t!="form"&&t!="tabIndex"&&t!="download"&&t!="rowSpan"&&t!="colSpan"&&t!="role"&&t!="popover"&&t in e)try{e[t]=n??"";break e}catch{}typeof n=="function"||(n==null||n===!1&&t[4]!="-"?e.removeAttribute(t):e.setAttribute(t,t=="popover"&&n==1?"":n))}}function Ne(e){return function(t){if(this.l){var n=this.l[t.type+e];if(t.t==null)t.t=ie++;else if(t.t<n.u)return;return n(p.event?p.event(t):t)}}}function ce(e,t,n,r,s,o,i,a,c,u){var d,l,f,_,m,k,b,v,g,y,E,H,w,$,P,U=t.type;if(t.constructor!==void 0)return null;128&n.__u&&(c=!!(32&n.__u),o=[a=t.__e=n.__e]),(d=p.__b)&&d(t);e:if(typeof U=="function")try{if(v=t.props,g="prototype"in U&&U.prototype.render,y=(d=U.contextType)&&r[d.__c],E=d?y?y.props.value:d.__:r,n.__c?b=(l=t.__c=n.__c).__=l.__E:(g?t.__c=l=new U(v,E):(t.__c=l=new R(v,E),l.constructor=U,l.render=yt),y&&y.sub(l),l.state||(l.state={}),l.__n=r,f=l.__d=!0,l.__h=[],l._sb=[]),g&&l.__s==null&&(l.__s=l.state),g&&U.getDerivedStateFromProps!=null&&(l.__s==l.state&&(l.__s=L({},l.__s)),L(l.__s,U.getDerivedStateFromProps(v,l.__s))),_=l.props,m=l.state,l.__v=t,f)g&&U.getDerivedStateFromProps==null&&l.componentWillMount!=null&&l.componentWillMount(),g&&l.componentDidMount!=null&&l.__h.push(l.componentDidMount);else{if(g&&U.getDerivedStateFromProps==null&&v!==_&&l.componentWillReceiveProps!=null&&l.componentWillReceiveProps(v,E),t.__v==n.__v||!l.__e&&l.shouldComponentUpdate!=null&&l.shouldComponentUpdate(v,l.__s,E)===!1){t.__v!=n.__v&&(l.props=v,l.state=l.__s,l.__d=!1),t.__e=n.__e,t.__k=n.__k,t.__k.some(function(q){q&&(q.__=t)}),Q.push.apply(l.__h,l._sb),l._sb=[],l.__h.length&&i.push(l);break e}l.componentWillUpdate!=null&&l.componentWillUpdate(v,l.__s,E),g&&l.componentDidUpdate!=null&&l.__h.push(function(){l.componentDidUpdate(_,m,k)})}if(l.context=E,l.props=v,l.__P=e,l.__e=!1,H=p.__r,w=0,g)l.state=l.__s,l.__d=!1,H&&H(t),d=l.render(l.props,l.state,l.context),Q.push.apply(l.__h,l._sb),l._sb=[];else do l.__d=!1,H&&H(t),d=l.render(l.props,l.state,l.context),l.state=l.__s;while(l.__d&&++w<25);l.state=l.__s,l.getChildContext!=null&&(r=L(L({},r),l.getChildContext())),g&&!f&&l.getSnapshotBeforeUpdate!=null&&(k=l.getSnapshotBeforeUpdate(_,m)),$=d!=null&&d.type===N&&d.key==null?Le(d.props.children):d,a=Pe(e,z($)?$:[$],t,n,r,s,o,i,a,c,u),l.base=t.__e,t.__u&=-161,l.__h.length&&i.push(l),b&&(l.__E=l.__=null)}catch(q){if(t.__v=null,c||o!=null)if(q.then){for(t.__u|=c?160:128;a&&a.nodeType==8&&a.nextSibling;)a=a.nextSibling;o[o.indexOf(a)]=null,t.__e=a}else{for(P=o.length;P--;)ue(o[P]);_e(t)}else t.__e=n.__e,t.__k=n.__k,q.then||_e(t);p.__e(q,t,n)}else o==null&&t.__v==n.__v?(t.__k=n.__k,t.__e=n.__e):a=t.__e=bt(n.__e,t,n,r,s,o,i,c,u);return(d=p.diffed)&&d(t),128&t.__u?void 0:a}function _e(e){e&&(e.__c&&(e.__c.__e=!0),e.__k&&e.__k.some(_e))}function He(e,t,n){for(var r=0;r<n.length;r++)de(n[r],n[++r],n[++r]);p.__c&&p.__c(t,e),e.some(function(s){try{e=s.__h,s.__h=[],e.some(function(o){o.call(s)})}catch(o){p.__e(o,s.__v)}})}function Le(e){return typeof e!="object"||e==null||e.__b>0?e:z(e)?e.map(Le):L({},e)}function bt(e,t,n,r,s,o,i,a,c){var u,d,l,f,_,m,k,b=n.props||X,v=t.props,g=t.type;if(g=="svg"?s="http://www.w3.org/2000/svg":g=="math"?s="http://www.w3.org/1998/Math/MathML":s||(s="http://www.w3.org/1999/xhtml"),o!=null){for(u=0;u<o.length;u++)if((_=o[u])&&"setAttribute"in _==!!g&&(g?_.localName==g:_.nodeType==3)){e=_,o[u]=null;break}}if(e==null){if(g==null)return document.createTextNode(v);e=document.createElementNS(s,g,v.is&&v),a&&(p.__m&&p.__m(t,o),a=!1),o=null}if(g==null)b===v||a&&e.data==v||(e.data=v);else{if(o=o&&Y.call(e.childNodes),!a&&o!=null)for(b={},u=0;u<e.attributes.length;u++)b[(_=e.attributes[u]).name]=_.value;for(u in b)_=b[u],u=="dangerouslySetInnerHTML"?l=_:u=="children"||u in v||u=="value"&&"defaultValue"in v||u=="checked"&&"defaultChecked"in v||te(e,u,null,_,s);for(u in v)_=v[u],u=="children"?f=_:u=="dangerouslySetInnerHTML"?d=_:u=="value"?m=_:u=="checked"?k=_:a&&typeof _!="function"||b[u]===_||te(e,u,_,b[u],s);if(d)a||l&&(d.__html==l.__html||d.__html==e.innerHTML)||(e.innerHTML=d.__html),t.__k=[];else if(l&&(e.innerHTML=""),Pe(t.type=="template"?e.content:e,z(f)?f:[f],t,n,r,g=="foreignObject"?"http://www.w3.org/1999/xhtml":s,o,i,o?o[0]:n.__k&&W(n,0),a,c),o!=null)for(u=o.length;u--;)ue(o[u]);a||(u="value",g=="progress"&&m==null?e.removeAttribute("value"):m!=null&&(m!==e[u]||g=="progress"&&!m||g=="option"&&m!=b[u])&&te(e,u,m,b[u],s),u="checked",k!=null&&k!=e[u]&&te(e,u,k,b[u],s))}return e}function de(e,t,n){try{if(typeof e=="function"){var r=typeof e.__u=="function";r&&e.__u(),r&&t==null||(e.__u=e(t))}else e.current=t}catch(s){p.__e(s,n)}}function Re(e,t,n){var r,s;if(p.unmount&&p.unmount(e),(r=e.ref)&&(r.current&&r.current!=e.__e||de(r,null,t)),(r=e.__c)!=null){if(r.componentWillUnmount)try{r.componentWillUnmount()}catch(o){p.__e(o,t)}r.base=r.__P=null}if(r=e.__k)for(s=0;s<r.length;s++)r[s]&&Re(r[s],t,n||typeof e.type!="function");n||ue(e.__e),e.__c=e.__=e.__e=void 0}function yt(e,t,n){return this.constructor(e,n)}function he(e,t,n){var r,s,o,i;t==document&&(t=document.documentElement),p.__&&p.__(e,t),s=(r=!1)?null:t.__k,o=[],i=[],ce(t,e=t.__k=K(N,null,[e]),s||X,X,t.namespaceURI,s?null:t.firstChild?Y.call(t.childNodes):null,o,s?s.__e:t.firstChild,r,i),He(o,e,i)}Y=Q.slice,p={__e:function(e,t,n,r){for(var s,o,i;t=t.__;)if((s=t.__c)&&!s.__)try{if((o=s.constructor)&&o.getDerivedStateFromError!=null&&(s.setState(o.getDerivedStateFromError(e)),i=s.__d),s.componentDidCatch!=null&&(s.componentDidCatch(e,r||{}),i=s.__d),i)return s.__E=s}catch(a){e=a}throw e}},we=0,R.prototype.setState=function(e,t){var n;n=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=L({},this.state),typeof e=="function"&&(e=e(L({},n),this.props)),e&&L(n,e),e!=null&&this.__v&&(t&&this._sb.push(t),xe(this))},R.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),xe(this))},R.prototype.render=N,F=[],Te=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,Se=function(e,t){return e.__v.__b-t.__v.__b},Z.__r=0,Ee=/(PointerCapture)$|Capture$/i,ie=0,le=Ne(!1),ae=Ne(!0);var kt=0;function h(e,t,n,r,s,o){t||(t={});var i,a,c=t;if("ref"in c)for(a in c={},t)a=="ref"?i=t[a]:c[a]=t[a];var u={type:e,props:c,key:n,ref:i,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--kt,__i:-1,__u:0,__source:s,__self:o};if(typeof e=="function"&&(i=e.defaultProps))for(a in i)c[a]===void 0&&(c[a]=i[a]);return p.vnode&&p.vnode(u),u}var j,T,fe,Ae,V=0,Oe=[],S=p,Fe=S.__b,De=S.__r,Ie=S.diffed,Be=S.__c,We=S.unmount,qe=S.__;function pe(e,t){S.__h&&S.__h(T,e,V||t),V=0;var n=T.__H||(T.__H={__:[],__h:[]});return e>=n.__.length&&n.__.push({}),n.__[e]}function x(e){return V=1,wt(je,e)}function wt(e,t,n){var r=pe(j++,2);if(r.t=e,!r.__c&&(r.__=[n?n(t):je(void 0,t),function(a){var c=r.__N?r.__N[0]:r.__[0],u=r.t(c,a);c!==u&&(r.__N=[u,r.__[1]],r.__c.setState({}))}],r.__c=T,!T.__f)){var s=function(a,c,u){if(!r.__c.__H)return!0;var d=r.__c.__H.__.filter(function(f){return f.__c});if(d.every(function(f){return!f.__N}))return!o||o.call(this,a,c,u);var l=r.__c.props!==a;return d.some(function(f){if(f.__N){var _=f.__[0];f.__=f.__N,f.__N=void 0,_!==f.__[0]&&(l=!0)}}),o&&o.call(this,a,c,u)||l};T.__f=!0;var o=T.shouldComponentUpdate,i=T.componentWillUpdate;T.componentWillUpdate=function(a,c,u){if(this.__e){var d=o;o=void 0,s(a,c,u),o=d}i&&i.call(this,a,c,u)},T.shouldComponentUpdate=s}return r.__N||r.__}function A(e,t){var n=pe(j++,3);!S.__s&&Ke(n.__H,t)&&(n.__=e,n.u=t,T.__H.__h.push(n))}function D(e){return V=5,O(function(){return{current:e}},[])}function O(e,t){var n=pe(j++,7);return Ke(n.__H,t)&&(n.__=e(),n.__H=t,n.__h=e),n.__}function G(e,t){return V=8,O(function(){return e},t)}function Ct(){for(var e;e=Oe.shift();){var t=e.__H;if(e.__P&&t)try{t.__h.some(ne),t.__h.some(me),t.__h=[]}catch(n){t.__h=[],S.__e(n,e.__v)}}}S.__b=function(e){T=null,Fe&&Fe(e)},S.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),qe&&qe(e,t)},S.__r=function(e){De&&De(e),j=0;var t=(T=e.__c).__H;t&&(fe===T?(t.__h=[],T.__h=[],t.__.some(function(n){n.__N&&(n.__=n.__N),n.u=n.__N=void 0})):(t.__h.some(ne),t.__h.some(me),t.__h=[],j=0)),fe=T},S.diffed=function(e){Ie&&Ie(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(Oe.push(t)!==1&&Ae===S.requestAnimationFrame||((Ae=S.requestAnimationFrame)||Tt)(Ct)),t.__H.__.some(function(n){n.u&&(n.__H=n.u),n.u=void 0})),fe=T=null},S.__c=function(e,t){t.some(function(n){try{n.__h.some(ne),n.__h=n.__h.filter(function(r){return!r.__||me(r)})}catch(r){t.some(function(s){s.__h&&(s.__h=[])}),t=[],S.__e(r,n.__v)}}),Be&&Be(e,t)},S.unmount=function(e){We&&We(e);var t,n=e.__c;n&&n.__H&&(n.__H.__.some(function(r){try{ne(r)}catch(s){t=s}}),n.__H=void 0,t&&S.__e(t,n.__v))};var ze=typeof requestAnimationFrame=="function";function Tt(e){var t,n=function(){clearTimeout(r),ze&&cancelAnimationFrame(t),setTimeout(e)},r=setTimeout(n,35);ze&&(t=requestAnimationFrame(n))}function ne(e){var t=T,n=e.__c;typeof n=="function"&&(e.__c=void 0,n()),T=t}function me(e){var t=T;e.__c=e.__(),T=t}function Ke(e,t){return!e||e.length!==t.length||t.some(function(n,r){return n!==e[r]})}function je(e,t){return typeof t=="function"?t(e):t}function St(e,t){for(var n in t)e[n]=t[n];return e}function Ve(e,t){for(var n in e)if(n!=="__source"&&!(n in t))return!0;for(var r in t)if(r!=="__source"&&e[r]!==t[r])return!0;return!1}function Ge(e,t){this.props=e,this.context=t}(Ge.prototype=new R).isPureReactComponent=!0,Ge.prototype.shouldComponentUpdate=function(e,t){return Ve(this.props,e)||Ve(this.state,t)};var Ye=p.__b;p.__b=function(e){e.type&&e.type.__f&&e.ref&&(e.props.ref=e.ref,e.ref=null),Ye&&Ye(e)};var Et=p.__e;p.__e=function(e,t,n,r){if(e.then){for(var s,o=t;o=o.__;)if((s=o.__c)&&s.__c)return t.__e==null&&(t.__e=n.__e,t.__k=n.__k),s.__c(e,t)}Et(e,t,n,r)};var Xe=p.unmount;function Qe(e,t,n){return e&&(e.__c&&e.__c.__H&&(e.__c.__H.__.forEach(function(r){typeof r.__c=="function"&&r.__c()}),e.__c.__H=null),(e=St({},e)).__c!=null&&(e.__c.__P===n&&(e.__c.__P=t),e.__c.__e=!0,e.__c=null),e.__k=e.__k&&e.__k.map(function(r){return Qe(r,t,n)})),e}function Je(e,t,n){return e&&n&&(e.__v=null,e.__k=e.__k&&e.__k.map(function(r){return Je(r,t,n)}),e.__c&&e.__c.__P===t&&(e.__e&&n.appendChild(e.__e),e.__c.__e=!0,e.__c.__P=n)),e}function ge(){this.__u=0,this.o=null,this.__b=null}function Ze(e){if(!e.__)return null;var t=e.__.__c;return t&&t.__a&&t.__a(e)}function re(){this.i=null,this.l=null}p.unmount=function(e){var t=e.__c;t&&(t.__z=!0),t&&t.__R&&t.__R(),t&&32&e.__u&&(e.type=null),Xe&&Xe(e)},(ge.prototype=new R).__c=function(e,t){var n=t.__c,r=this;r.o==null&&(r.o=[]),r.o.push(n);var s=Ze(r.__v),o=!1,i=function(){o||r.__z||(o=!0,n.__R=null,s?s(c):c())};n.__R=i;var a=n.__P;n.__P=null;var c=function(){if(!--r.__u){if(r.state.__a){var u=r.state.__a;r.__v.__k[0]=Je(u,u.__c.__P,u.__c.__O)}var d;for(r.setState({__a:r.__b=null});d=r.o.pop();)d.__P=a,d.forceUpdate()}};r.__u++||32&t.__u||r.setState({__a:r.__b=r.__v.__k[0]}),e.then(i,i)},ge.prototype.componentWillUnmount=function(){this.o=[]},ge.prototype.render=function(e,t){if(this.__b){if(this.__v.__k){var n=document.createElement("div"),r=this.__v.__k[0].__c;this.__v.__k[0]=Qe(this.__b,n,r.__O=r.__P)}this.__b=null}var s=t.__a&&K(N,null,e.fallback);return s&&(s.__u&=-33),[K(N,null,t.__a?null:e.children),s]};var et=function(e,t,n){if(++n[1]===n[0]&&e.l.delete(t),e.props.revealOrder&&(e.props.revealOrder[0]!=="t"||!e.l.size))for(n=e.i;n;){for(;n.length>3;)n.pop()();if(n[1]<n[0])break;e.i=n=n[2]}};function $t(e){return this.getChildContext=function(){return e.context},e.children}function xt(e){var t=this,n=e.h;if(t.componentWillUnmount=function(){he(null,t.v),t.v=null,t.h=null},t.h&&t.h!==n&&t.componentWillUnmount(),!t.v){for(var r=t.__v;r!==null&&!r.__m&&r.__!==null;)r=r.__;t.h=n,t.v={nodeType:1,parentNode:n,childNodes:[],__k:{__m:r.__m},contains:function(){return!0},namespaceURI:n.namespaceURI,insertBefore:function(s,o){this.childNodes.push(s),t.h.insertBefore(s,o)},removeChild:function(s){this.childNodes.splice(this.childNodes.indexOf(s)>>>1,1),t.h.removeChild(s)}}}he(K($t,{context:t.context},e.__v),t.v)}function Pt(e,t){var n=K(xt,{__v:e,h:t});return n.containerInfo=t,n}(re.prototype=new R).__a=function(e){var t=this,n=Ze(t.__v),r=t.l.get(e);return r[0]++,function(s){var o=function(){t.props.revealOrder?(r.push(s),et(t,e,r)):s()};n?n(o):o()}},re.prototype.render=function(e){this.i=null,this.l=new Map;var t=ee(e.children);e.revealOrder&&e.revealOrder[0]==="b"&&t.reverse();for(var n=t.length;n--;)this.l.set(t[n],this.i=[1,0,this.i]);return e.children},re.prototype.componentDidUpdate=re.prototype.componentDidMount=function(){var e=this;this.l.forEach(function(t,n){et(e,n,t)})};var Mt=typeof Symbol<"u"&&Symbol.for&&Symbol.for("react.element")||60103,Ut=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|dominant|fill|flood|font|glyph(?!R)|horiz|image(!S)|letter|lighting|marker(?!H|W|U)|overline|paint|pointer|shape|stop|strikethrough|stroke|text(?!L)|transform|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,Nt=/^on(Ani|Tra|Tou|BeforeInp|Compo)/,Ht=/[A-Z0-9]/g,Lt=typeof document<"u",Rt=function(e){return(typeof Symbol<"u"&&typeof Symbol()=="symbol"?/fil|che|rad/:/fil|che|ra/).test(e)};R.prototype.isReactComponent={},["componentWillMount","componentWillReceiveProps","componentWillUpdate"].forEach(function(e){Object.defineProperty(R.prototype,e,{configurable:!0,get:function(){return this["UNSAFE_"+e]},set:function(t){Object.defineProperty(this,e,{configurable:!0,writable:!0,value:t})}})});var tt=p.event;function At(){}function Ot(){return this.cancelBubble}function Ft(){return this.defaultPrevented}p.event=function(e){return tt&&(e=tt(e)),e.persist=At,e.isPropagationStopped=Ot,e.isDefaultPrevented=Ft,e.nativeEvent=e};var Dt={enumerable:!1,configurable:!0,get:function(){return this.class}},nt=p.vnode;p.vnode=function(e){typeof e.type=="string"&&(function(t){var n=t.props,r=t.type,s={},o=r.indexOf("-")===-1;for(var i in n){var a=n[i];if(!(i==="value"&&"defaultValue"in n&&a==null||Lt&&i==="children"&&r==="noscript"||i==="class"||i==="className")){var c=i.toLowerCase();i==="defaultValue"&&"value"in n&&n.value==null?i="value":i==="download"&&a===!0?a="":c==="translate"&&a==="no"?a=!1:c[0]==="o"&&c[1]==="n"?c==="ondoubleclick"?i="ondblclick":c!=="onchange"||r!=="input"&&r!=="textarea"||Rt(n.type)?c==="onfocus"?i="onfocusin":c==="onblur"?i="onfocusout":Nt.test(i)&&(i=c):c=i="oninput":o&&Ut.test(i)?i=i.replace(Ht,"-$&").toLowerCase():a===null&&(a=void 0),c==="oninput"&&s[i=c]&&(i="oninputCapture"),s[i]=a}}r=="select"&&s.multiple&&Array.isArray(s.value)&&(s.value=ee(n.children).forEach(function(u){u.props.selected=s.value.indexOf(u.props.value)!=-1})),r=="select"&&s.defaultValue!=null&&(s.value=ee(n.children).forEach(function(u){u.props.selected=s.multiple?s.defaultValue.indexOf(u.props.value)!=-1:s.defaultValue==u.props.value})),n.class&&!n.className?(s.class=n.class,Object.defineProperty(s,"className",Dt)):n.className&&(s.class=s.className=n.className),t.props=s})(e),e.$$typeof=Mt,nt&&nt(e)};var rt=p.__r;p.__r=function(e){rt&&rt(e),e.__c};var ot=p.diffed;p.diffed=function(e){ot&&ot(e);var t=e.props,n=e.__e;n!=null&&e.type==="textarea"&&"value"in t&&t.value!==n.value&&(n.value=t.value==null?"":t.value)};var It={Fragment:N};class st extends Error{status;constructor(t=403){super(`Unauthorized (HTTP ${t})`),this.name="UnauthorizedError",this.status=t}}class Bt extends Error{status;body;constructor(t,n){super(`API error (HTTP ${t})`),this.name="ApiError",this.status=t,this.body=n}}class it{baseUrl;authToken;constructor(t){this.baseUrl=t.baseUrl.replace(/\/+$/,""),this.authToken=t.authToken}async fetch(t,n){const s={...{Accept:"application/json",...this.authToken?{Authorization:`Bearer ${this.authToken}`}:{}},...n?.headers},o=await globalThis.fetch(`${this.baseUrl}${t}`,{...n,headers:s,credentials:this.authToken?"omit":"include"});if(o.status===401||o.status===403)throw new st(o.status);if(!o.ok){const i=await o.text().catch(()=>"");throw new Bt(o.status,i)}return o.json()}async get(t,n){const r=n?`${t}?${n}`:t;return this.fetch(r)}async post(t,n){const r={method:"POST",...n!==void 0?{body:JSON.stringify(n),headers:{"Content-Type":"application/json"}}:{}};return this.fetch(t,r)}async delete(t){return this.fetch(t,{method:"DELETE"})}}const lt="/admin/api/debug",at={tracing:!1,process:!1,system:!1,http:!1,db:!1,redis:!1,queues:!1,cache:!1,app:!1,log:!1,emails:!1,dashboard:!1,customPanes:[]};function Wt(e){return{tracing:e.features?.tracing??!1,process:e.features?.process??!1,system:e.features?.system??!1,http:e.features?.http??!1,db:e.features?.db??!1,redis:e.features?.redis??!1,queues:e.features?.queues??!1,cache:e.features?.cache??!1,app:e.features?.app??!1,log:e.features?.log??!1,emails:e.features?.emails??!1,dashboard:e.features?.dashboard??!1,customPanes:e.customPanes??[]}}async function qt(e,t=lt){const n=`${t.replace(/\/+$/,"")}/config`;return e.fetch(n)}async function zt(e){const{baseUrl:t="",debugEndpoint:n=lt,authToken:r}=e,s=new it({baseUrl:t,authToken:r});try{const o=await qt(s,n);return Wt(o)}catch{return at}}function Kt(e){const t=new Set,n="features"in e&&typeof e.features=="object"&&e.features!==null?e.features:e;return"process"in n&&n.process&&t.add("process"),("process"in n&&n.process||"system"in n&&n.system)&&t.add("memory"),"http"in n&&n.http&&t.add("http"),"db"in n&&n.db&&t.add("db"),"redis"in n&&n.redis&&t.add("redis"),"queues"in n&&n.queues&&t.add("queue"),"app"in n&&n.app&&t.add("app"),"log"in n&&n.log&&t.add("log"),t}function jt(e){const t=new Set;return(C(e.cpuPercent)||C(e.uptime)||Vt(e.nodeVersion))&&t.add("process"),(C(e.memHeapUsed)||C(e.memRss))&&t.add("memory"),(C(e.systemMemoryTotalMb)||C(e.systemMemoryFreeMb))&&t.add("memory"),(C(e.requestsPerSecond)||C(e.avgResponseTimeMs)||C(e.errorRate)||C(e.activeHttpConnections))&&t.add("http"),(C(e.dbPoolMax)||C(e.dbPoolUsed)||C(e.dbPoolFree)||C(e.dbPoolPending))&&t.add("db"),e.redisOk!==void 0&&e.redisOk!==null&&t.add("redis"),(C(e.queueActive)||C(e.queueWaiting)||C(e.queueWorkerCount))&&t.add("queue"),(C(e.onlineUsers)||C(e.pendingWebhooks)||C(e.pendingEmails))&&t.add("app"),(C(e.logErrorsLast5m)||C(e.logEntriesPerMinute))&&t.add("log"),t}function C(e){return typeof e=="number"&&!Number.isNaN(e)}function Vt(e){return typeof e=="string"&&e.length>0}const ut={wrench:{viewBox:"0 0 24 24",elements:['<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>']}};function Gt(e){if(!e&&e!==0)return"-";const t=Math.floor(e),n=Math.floor(t/86400),r=Math.floor(t%86400/3600),s=Math.floor(t%3600/60);return n>0?`${n}d ${r}h`:r>0?`${r}h ${s}m`:s>0?`${s}m ${t%60}s`:`${t}s`}function ve(e){const t=e/1048576;return t>=1024?`${(t/1024).toFixed(1)}G`:`${t.toFixed(0)}M`}function ct(e){return e>=1024?`${(e/1024).toFixed(1)}G`:`${e.toFixed(1)}M`}function Yt(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}K`:`${e}`}function be(e,t){switch(t){case"%":return`${e.toFixed(1)}%`;case"ms":return`${e.toFixed(0)}ms`;case"MB":return`${e.toFixed(1)}M`;case"bytes":return ve(e);case"/s":case"/m":return e.toFixed(1);default:return e.toFixed(1)}}function oe(e,t,n){return e>n?"red":e>t?"amber":"green"}function Xt(e,t,n){return e<n?"red":e<t?"amber":"green"}function _t(e,t){if(t===0)return"green";const n=e/t;return n>.8?"red":n>.5?"amber":"green"}const Qt={green:"ss-green",amber:"ss-amber",red:"ss-red"};function I(e){return Qt[e]||""}const dt=[{id:"node",label:"NODE",title:"Node.js Runtime",unit:"",group:"process",extract:e=>0,format:e=>e.nodeVersion,color:()=>""},{id:"uptime",label:"UP",title:"Process Uptime",unit:"",group:"process",extract:e=>e.uptime,format:e=>Gt(e.uptime),color:()=>""},{id:"cpu",label:"CPU",title:"CPU Usage",unit:"%",group:"process",warnThreshold:50,critThreshold:80,extract:e=>e.cpuPercent,format:e=>`${e.cpuPercent.toFixed(1)}%`,color:e=>I(oe(e.cpuPercent,50,80)),historyKey:"cpuPercent"},{id:"eventLoop",label:"EVT",title:"Event Loop Latency",unit:"ms",group:"process",warnThreshold:20,critThreshold:50,extract:e=>e.eventLoopLag,format:e=>`${e.eventLoopLag.toFixed(1)}ms`,color:e=>I(oe(e.eventLoopLag,20,50)),historyKey:"eventLoopLag"},{id:"memory",label:"HEAP",title:"V8 Heap Usage",unit:"bytes",group:"memory",extract:e=>e.memHeapUsed,format:e=>ve(e.memHeapUsed),color:()=>"",historyKey:"memHeapUsed"},{id:"rss",label:"RSS",title:"Resident Set Size",unit:"bytes",group:"memory",extract:e=>e.memRss,format:e=>ve(e.memRss),color:()=>"",historyKey:"memRss"},{id:"systemMemory",label:"SYS",title:"System Memory",unit:"MB",group:"memory",extract:e=>e.systemMemoryTotalMb-e.systemMemoryFreeMb,format:e=>`${ct(e.systemMemoryTotalMb-e.systemMemoryFreeMb)}/${ct(e.systemMemoryTotalMb)}`,color:e=>{const t=e.systemMemoryTotalMb;if(t===0)return"";const n=t-e.systemMemoryFreeMb;return I(_t(n,t))},historyKey:"_sysMemUsed",show:e=>e.systemMemoryTotalMb!==null&&e.systemMemoryTotalMb!==void 0},{id:"reqPerSec",label:"REQ/s",title:"Requests per Second",unit:"/s",group:"http",extract:e=>e.requestsPerSecond,format:e=>e.requestsPerSecond.toFixed(1),color:()=>"",historyKey:"requestsPerSecond"},{id:"avgResponse",label:"AVG",title:"Avg Response Time",unit:"ms",group:"http",warnThreshold:200,critThreshold:500,extract:e=>e.avgResponseTimeMs,format:e=>`${e.avgResponseTimeMs.toFixed(0)}ms`,color:e=>I(oe(e.avgResponseTimeMs,200,500)),historyKey:"avgResponseTimeMs"},{id:"errorRate",label:"ERR",title:"Error Rate",unit:"%",group:"http",warnThreshold:1,critThreshold:5,extract:e=>e.errorRate,format:e=>`${e.errorRate.toFixed(1)}%`,color:e=>I(oe(e.errorRate,1,5)),historyKey:"errorRate"},{id:"connections",label:"CONN",title:"Active Connections",unit:"",group:"http",extract:e=>e.activeHttpConnections,format:e=>`${e.activeHttpConnections}`,color:()=>"",historyKey:"activeHttpConnections"},{id:"dbPool",label:"DB",title:"Database Pool",unit:"",group:"db",extract:e=>e.dbPoolUsed,format:e=>`${e.dbPoolUsed}/${e.dbPoolFree}/${e.dbPoolMax}`,color:e=>I(_t(e.dbPoolUsed,e.dbPoolMax)),historyKey:"dbPoolUsed"},{id:"redis",label:"REDIS",title:"Redis Status",unit:"",group:"redis",extract:e=>e.redisOk?1:0,format:e=>e.redisOk?"✓":"✗",color:e=>e.redisOk?"ss-green":"ss-red"},{id:"redisMem",label:"MEM",title:"Redis Memory",unit:"MB",group:"redis",extract:e=>e.redisMemoryUsedMb,format:e=>`${e.redisMemoryUsedMb.toFixed(1)}M`,color:()=>"",historyKey:"redisMemoryUsedMb",show:e=>e.redisOk},{id:"redisKeys",label:"KEYS",title:"Redis Keys",unit:"",group:"redis",extract:e=>e.redisKeysCount,format:e=>Yt(e.redisKeysCount),color:()=>"",historyKey:"redisKeysCount",show:e=>e.redisOk},{id:"redisHitRate",label:"HIT",title:"Redis Hit Rate",unit:"%",group:"redis",warnThreshold:90,critThreshold:70,inverseThreshold:!0,extract:e=>e.redisHitRate,format:e=>`${e.redisHitRate.toFixed(0)}%`,color:e=>I(Xt(e.redisHitRate,90,70)),historyKey:"redisHitRate",show:e=>e.redisOk},{id:"queue",label:"Q",title:"Job Queue",unit:"",group:"queue",extract:e=>e.queueActive,format:e=>`${e.queueActive}/${e.queueWaiting}/${e.queueDelayed}`,color:e=>e.queueFailed>0?"ss-amber":"ss-green",historyKey:"queueActive"},{id:"queueWorkers",label:"WORKERS",title:"Queue Workers",unit:"",group:"queue",extract:e=>e.queueWorkerCount,format:e=>`${e.queueWorkerCount}`,color:()=>""},{id:"onlineUsers",label:"USERS",title:"Online Users",unit:"",group:"app",extract:e=>e.onlineUsers,format:e=>`${e.onlineUsers}`,color:()=>"",historyKey:"onlineUsers"},{id:"pendingWebhooks",label:"HOOKS",title:"Pending Webhooks",unit:"",group:"app",extract:e=>e.pendingWebhooks,format:e=>`${e.pendingWebhooks}`,color:e=>e.pendingWebhooks>0?"ss-amber":"",historyKey:"pendingWebhooks"},{id:"pendingEmails",label:"MAIL",title:"Pending Emails",unit:"",group:"app",extract:e=>e.pendingEmails,format:e=>`${e.pendingEmails}`,color:e=>e.pendingEmails>0?"ss-amber":"",historyKey:"pendingEmails"},{id:"logErrors",label:"LOG ERR",title:"Log Errors (5m)",unit:"",group:"log",extract:e=>e.logErrorsLast5m,format:e=>`${e.logErrorsLast5m}`,color:e=>e.logErrorsLast5m>0?"ss-red":e.logWarningsLast5m>0?"ss-amber":"",historyKey:"logErrorsLast5m"},{id:"logRate",label:"LOG/m",title:"Log Entries / Minute",unit:"/m",group:"log",extract:e=>e.logEntriesPerMinute,format:e=>`${e.logEntriesPerMinute}`,color:()=>"",historyKey:"logEntriesPerMinute"}],Jt=60,Zt=1e4;function en(e={}){const{baseUrl:t="",debugEndpoint:n="/admin/api/debug",authToken:r}=e,[s,o]=x(at),[i,a]=x(!0),[c,u]=x(null),d=D(!1);return A(()=>{if(d.current)return;d.current=!0;let l=!1;return(async()=>{try{const _=await zt({baseUrl:t,debugEndpoint:n,authToken:r});l||(o(_),a(!1))}catch(_){l||(u(_ instanceof Error?_:new Error(String(_))),a(!1))}})(),()=>{l=!0}},[t,n,r]),{features:s,isLoading:i,error:c}}function tn(e=Jt){const t={};return{push(n){for(const r of dt){const s=r.historyKey;if(!s)continue;const o=r.extract(n);typeof o=="number"&&(t[s]||(t[s]=[]),t[s].push(o),t[s].length>e&&t[s].shift())}},get(n){return t[n]||[]},getAll(){return t}}}async function nn(){if(typeof window<"u"&&window.Transmit&&typeof window.Transmit=="function")return window.Transmit;try{const e=await import("@adonisjs/transmit-client");return e.Transmit??e.default??null}catch{return null}}function rn(e){let t=null,n=null,r=!1;return{subscribe:async()=>{try{const i=await nn();if(!i)throw new Error("Transmit client not available (neither window.Transmit nor @adonisjs/transmit-client)");if(r)return;t=new i({baseUrl:e.baseUrl||window.location.origin,...e.authToken?{beforeSubscribe(a){return{headers:{Authorization:`Bearer ${e.authToken}`}}},beforeUnsubscribe(a){return{headers:{Authorization:`Bearer ${e.authToken}`}}}}:{}}),n=t.subscription(e.channelName),n.onMessage(a=>{r||e.onMessage(a)}),await n.create()}catch(i){e.onError&&e.onError(i)}},unsubscribe:async()=>{r=!0;try{n&&(await n.delete(),n=null),t&&(t=null)}catch{}}}}function on(e){let t=!1;const n=rn({baseUrl:e.baseUrl,channelName:e.channelName,authToken:e.authToken,onMessage:e.onMessage,onError:r=>{t=!0,e.onError?.(r),e.onDisconnect?.()}});return n.subscribe().then(()=>{t||e.onConnect?.()}).catch(r=>{e.onError?.(r),e.onDisconnect?.()}),{unsubscribe:()=>{n.unsubscribe().catch(()=>{})}}}class sn{baseUrl;endpoint;channelName;authToken;pollInterval;onStatsUpdate;onConnectionChange;onStaleChange;onError;onUnauthorizedChange;onHistoryChange;onSseActiveChange;onPollActiveChange;historyBuffer;client=null;sseHandle=null;pollTimer=null;staleTimer=null;lastSuccess=0;unauthorized=!1;sseActive=!1;isConnected=!1;isStale=!1;constructor(t={}){this.baseUrl=t.baseUrl??"",this.endpoint=t.endpoint??"/admin/api/server-stats",this.channelName=t.channelName??"admin/server-stats",this.authToken=t.authToken,this.pollInterval=t.pollInterval??3e3,this.onStatsUpdate=t.onStatsUpdate,this.onConnectionChange=t.onConnectionChange,this.onStaleChange=t.onStaleChange,this.onError=t.onError,this.onUnauthorizedChange=t.onUnauthorizedChange,this.onHistoryChange=t.onHistoryChange,this.onSseActiveChange=t.onSseActiveChange,this.onPollActiveChange=t.onPollActiveChange,this.historyBuffer=tn()}start(){if(this.unauthorized)return;let t=!1;try{const n=on({baseUrl:this.baseUrl,channelName:this.channelName,authToken:this.authToken,onMessage:r=>{r&&typeof r=="object"&&"timestamp"in r&&this.processStats(r)},onConnect:()=>{this.setSseActive(!0),this.setConnected(!0),this.stopPolling()},onDisconnect:()=>{this.setSseActive(!1),this.setConnected(!1),!this.pollTimer&&!this.unauthorized&&this.startPollInterval()},onError:()=>{t=!0}});this.sseHandle=n}catch{t=!0}if(this.poll(),t||!this.sseHandle)this.startPollInterval();else{const n=setTimeout(()=>{!this.isConnected&&!this.pollTimer&&this.startPollInterval()},3e3),r=this.sseHandle?.unsubscribe;this.sseHandle&&(this.sseHandle.unsubscribe=()=>{clearTimeout(n),r?.()})}this.staleTimer=setInterval(()=>{this.lastSuccess>0&&Date.now()-this.lastSuccess>Zt&&this.setStale(!0)},2e3)}stop(){this.sseHandle?.unsubscribe(),this.sseHandle=null,this.stopPolling(),this.staleTimer&&(clearInterval(this.staleTimer),this.staleTimer=null)}getHistory(t){return this.historyBuffer.get(t)}getAllHistory(){return this.historyBuffer.getAll()}getConnectionMode(){return this.unauthorized?"disconnected":this.sseActive?"live":this.pollTimer?"polling":"disconnected"}processStats(t){this.onStatsUpdate?.(t),this.onError?.(null),this.lastSuccess=Date.now(),this.setStale(!1),this.historyBuffer.push(t),this.onHistoryChange?.(this.historyBuffer.getAll())}async poll(){if(!this.unauthorized){this.client||(this.client=new it({baseUrl:this.baseUrl,authToken:this.authToken}));try{const t=await this.client.get(this.endpoint);this.processStats(t)}catch(t){t instanceof st&&(this.unauthorized=!0,this.onUnauthorizedChange?.(!0),this.onError?.(t),this.stopPolling())}}}startPollInterval(){this.pollTimer||(this.pollTimer=setInterval(()=>this.poll(),this.pollInterval),this.onPollActiveChange?.(!0))}stopPolling(){this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=null,this.onPollActiveChange?.(!1))}setSseActive(t){this.sseActive!==t&&(this.sseActive=t,this.onSseActiveChange?.(t))}setConnected(t){this.isConnected!==t&&(this.isConnected=t,this.onConnectionChange?.(t))}setStale(t){this.isStale!==t&&(this.isStale=t,this.onStaleChange?.(t))}}function ln(e={}){const{baseUrl:t="",endpoint:n="/admin/api/server-stats",channelName:r="admin/server-stats",authToken:s,pollInterval:o=3e3}=e,[i,a]=x(null),[c,u]=x(!1),[d,l]=x(!1),[f,_]=x(null),[m,k]=x(!1),b=D(null);A(()=>{if(m)return;const g=new sn({baseUrl:t,endpoint:n,channelName:r,authToken:s,pollInterval:o,onStatsUpdate:y=>a(y),onConnectionChange:y=>u(y),onStaleChange:y=>l(y),onError:y=>_(y),onUnauthorizedChange:y=>k(y)});return b.current=g,g.start(),()=>{g.stop(),b.current=null}},[t,r,s,o,m]);const v=G(g=>b.current?.getHistory(g)??[],[]);return{stats:i,history:b.current?.getAllHistory()??{},getHistory:v,isConnected:c,isStale:d,error:f,unauthorized:m}}const se="ss-dash-theme",ye="ss-theme-change";function ke(){if(typeof window>"u")return"light";const e=localStorage.getItem(se);return e==="dark"||e==="light"?e:window.matchMedia?.("(prefers-color-scheme: dark)").matches?"dark":"light"}function an(e){typeof window>"u"||(localStorage.setItem(se,e),window.dispatchEvent(new CustomEvent(ye,{detail:e})))}function un(){const t=ke()==="dark"?"light":"dark";return an(t),t}function cn(e){if(typeof window>"u")return()=>{};const t=o=>{const i=o.detail;(i==="dark"||i==="light")&&e(i)},n=o=>{if(o.key===se){const i=o.newValue;e(i==="dark"||i==="light"?i:ke())}},r=window.matchMedia("(prefers-color-scheme: dark)"),s=o=>{localStorage.getItem(se)||e(o.matches?"dark":"light")};return window.addEventListener(ye,t),window.addEventListener("storage",n),r.addEventListener("change",s),()=>{window.removeEventListener(ye,t),window.removeEventListener("storage",n),r.removeEventListener("change",s)}}function _n(){const[e,t]=x(()=>ke());A(()=>cn(s=>{t(s)}),[]);const n=G(()=>{const r=un();return t(r),r},[]);return{theme:e,toggleTheme:n}}const B={color:"#34d399",fillOpacityTop:.25,fillOpacityBottom:.02,strokeWidth:1.5,width:120,height:32,padding:2};function dn(e){return{...B,...e}}function hn(e,t=B.width,n=B.height,r=B.padding){if(e.length<2)return null;const s=t-r*2,o=n-r*2,i=Math.min(...e),c=Math.max(...e)-i||1;return e.map((d,l)=>{const f=r+l/(e.length-1)*s,_=r+o-(d-i)/c*o;return`${f.toFixed(1)},${_.toFixed(1)}`}).join(" ")}function fn(e,t=B.width,n=B.height,r=B.padding){if(e.length<2)return null;const s=t-r*2,o=n-r*2,i=Math.min(...e),c=Math.max(...e)-i||1,u=e.map((_,m)=>{const k=r+m/(e.length-1)*s,b=r+o-(_-i)/c*o;return`${k.toFixed(1)},${b.toFixed(1)}`}),d=(r+s).toFixed(1),l=(r+o).toFixed(1),f=r.toFixed(1);return`M${u[0]} `+u.slice(1).map(_=>`L${_}`).join(" ")+` L${d},${l} L${f},${l} Z`}let pn=0;function mn(){return`ss-grad-${pn++}`}function ht(e){if(e.length===0)return null;const t=Math.min(...e),n=Math.max(...e),r=e.reduce((s,o)=>s+o,0)/e.length;return{min:t,max:n,avg:r}}function gn(e,t){const n=dn(t),r=hn(e,n.width,n.height,n.padding),s=fn(e,n.width,n.height,n.padding);return!r||!s?null:{points:r,areaPath:s,gradientId:mn(),options:n,stats:ht(e)}}function vn({data:e,color:t="#34d399",width:n=120,height:r=32,className:s=""}){const o=O(()=>gn(e,{width:n,height:r}),[e,n,r]),i=O(()=>"ss-grad-"+Math.random().toString(36).slice(2,8),[]),a={"--ss-accent":t};if(!o)return h("div",{className:`ss-dash-sparkline ${s}`,style:a,children:h("svg",{width:n,height:r,viewBox:`0 0 ${n} ${r}`,style:{display:"block"},children:h("text",{x:n/2,y:r/2+3,textAnchor:"middle",fill:"#737373",fontSize:"9",children:["collecting","…"]})})});const c=t||"var(--ss-accent)";return h("div",{className:`ss-dash-sparkline ${s}`,style:a,children:h("svg",{width:n,height:r,viewBox:`0 0 ${n} ${r}`,style:{display:"block"},children:[h("defs",{children:h("linearGradient",{id:i,x1:"0",y1:"0",x2:"0",y2:"1",children:[h("stop",{offset:"0%",stopColor:c,stopOpacity:"0.25"}),h("stop",{offset:"100%",stopColor:c,stopOpacity:"0.02"})]})}),h("path",{d:o.areaPath,fill:`url(#${i})`}),h("path",{className:"ss-dash-sparkline-line",d:"M"+o.points.replace(/ /g," L"),fill:"none",stroke:c,strokeWidth:"1.5",strokeLinejoin:"round",strokeLinecap:"round"})]})})}const bn={"ss-red":"#f87171","ss-amber":"#fbbf24","ss-green":"#34d399","ss-muted":"#737373"};function yn(e,t,n){const[r,s]=x({position:"absolute",bottom:"100%",left:0,marginBottom:"10px",zIndex:180});return A(()=>{if(!n)return;const o=()=>{const a=e.current,c=t.current;if(!a||!c)return;const u=a.closest(".ss-bar");if(!u)return;const d=a.getBoundingClientRect(),l=u.getBoundingClientRect(),f=d.left-l.left+d.width/2;s({position:"absolute",bottom:"100%",left:`${f}px`,transform:"translateX(-50%)",marginBottom:"10px",zIndex:180}),requestAnimationFrame(()=>{const _=c.getBoundingClientRect();let m=0;_.left<8?m=8-_.left:_.right>window.innerWidth-8&&(m=window.innerWidth-8-_.right),m&&s(k=>({...k,transform:`translateX(calc(-50% + ${m}px))`}))})};o();const i=e.current?.closest(".ss-bar-scroll");return i?.addEventListener("scroll",o),window.addEventListener("resize",o),()=>{i?.removeEventListener("scroll",o),window.removeEventListener("resize",o)}},[n,e,t]),r}function kn({metric:e,stats:t,history:n,className:r=""}){const[s,o]=x(!1),[i,a]=x(!1),c=D(null),u=D(null);if(e.show&&!e.show(t))return null;const d=e.value?e.value(t):e.format(t),l=e.color?e.color(t):"",f=l&&bn[l]||"#34d399",_=typeof e.detail=="function"?e.detail(t):e.detail,m=O(()=>ht(n),[n]),k=s||i,b=yn(c,u,k),v=G(E=>{E.stopPropagation(),o(H=>!H)},[]);A(()=>{if(!s)return;const E=w=>{const $=w.target;c.current&&!c.current.contains($)&&u.current&&!u.current.contains($)&&o(!1)},H=w=>{w.key==="Escape"&&o(!1)};return document.addEventListener("click",E),document.addEventListener("keydown",H),()=>{document.removeEventListener("click",E),document.removeEventListener("keydown",H)}},[s]);const g=c.current?.closest(".ss-bar"),y=k&&g?Pt(h("div",{ref:u,className:`ss-tooltip ${s?"ss-pinned":""}`,style:b,children:[h("div",{className:"ss-tooltip-inner",style:{position:"relative"},children:[s&&h("button",{className:"ss-tooltip-close",onClick:E=>{E.stopPropagation(),o(!1)},type:"button",children:"×"}),h("div",{className:"ss-tooltip-header",children:[h("span",{className:"ss-tooltip-title",children:e.title}),e.unit&&h("span",{className:"ss-tooltip-unit",children:e.unit})]}),h("div",{className:"ss-tooltip-current",children:[h("span",{className:"ss-tooltip-current-label",children:"Current: "}),h("span",{className:"ss-tooltip-current-value",children:d})]}),m&&h("div",{className:"ss-tooltip-stats",children:[h("span",{children:["Min: ",be(m.min,e.unit)]}),h("span",{children:["Max: ",be(m.max,e.unit)]}),h("span",{children:["Avg: ",be(m.avg,e.unit)]})]}),_&&h("div",{className:"ss-tooltip-details",children:_}),n.length>0&&h(N,{children:[h("div",{className:"ss-tooltip-sparkline",children:h(vn,{data:n,color:f})}),h("div",{className:"ss-tooltip-samples",children:["Last ",Math.min(n.length,60)," samples (~",Math.round(Math.min(n.length,60)*3/60)," min)"]})]})]}),h("div",{className:"ss-tooltip-arrow"})]}),g):null;return h(N,{children:[h("div",{ref:c,className:`ss-badge ${s?"ss-pinned":""} ${r}`,onClick:v,onMouseEnter:()=>!s&&a(!0),onMouseLeave:()=>a(!1),role:"button",tabIndex:0,onKeyDown:E=>E.key==="Enter"&&v(E),children:[h("span",{className:"ss-label",children:e.label}),h("span",{className:`ss-value ${l}`,children:d})]}),y]})}function wn(e){const{featureOptions:t,autoHideOnUnauthorized:n=!0,onOpenDebugPanel:r,debugPanelOpen:s=!1,onConnectionChange:o,...i}=e,{stats:a,getHistory:c,isConnected:u,isStale:d,unauthorized:l}=ln(i);A(()=>{o?.(u)},[u,o]);const{features:f}=en(t),{theme:_}=_n(),[m,k]=x(()=>typeof window>"u"?!0:localStorage.getItem("admin:stats-bar")!=="hidden"),b=D(null),v=D(null);A(()=>{n&&l&&k(!1)},[n,l]);const g=G(()=>{k(w=>{const $=!w;return localStorage.setItem("admin:stats-bar",$?"visible":"hidden"),$})},[]);A(()=>{const w=v.current;if(!w)return;const $=P=>{Math.abs(P.deltaX)>Math.abs(P.deltaY)||(P.preventDefault(),w.scrollLeft+=P.deltaY)};return w.addEventListener("wheel",$,{passive:!1}),()=>w.removeEventListener("wheel",$)},[]);const y=O(()=>a?jt(a):Kt(f),[a,f]),E=O(()=>dt.filter(w=>y.has(w.group||"core")),[y]),H=O(()=>{const w=[];let $="";for(const P of E){const U=P.group||"core";U!==$&&($=U,w.push({group:$,metrics:[]})),w[w.length-1].metrics.push(P)}return w},[E]);return n&&l?null:h(N,{children:[h("button",{type:"button",className:`ss-toggle ${m?"ss-visible":"ss-collapsed"}`,onClick:g,title:m?"Hide stats bar":"Show stats bar","data-ss-theme":_,children:[!m&&a&&h("span",{className:"ss-toggle-summary",style:{display:"flex"},children:[y.has("process")&&h(N,{children:[h("span",{className:`ss-value ${a.cpuPercent>80?"ss-red":a.cpuPercent>50?"ss-amber":"ss-green"}`,children:[a.cpuPercent.toFixed(0),"%"]}),h("span",{className:"ss-value ss-green",children:a.memHeapUsed!==void 0?Math.round(a.memHeapUsed/(1024*1024))+"M":"-"})]}),y.has("redis")&&a.redisOk!==void 0&&h("span",{className:`ss-value ${a.redisOk?"ss-green":"ss-red"}`,children:a.redisOk?"✓":"✗"})]}),m&&h("span",{className:"ss-toggle-label",style:{color:"#737373"},children:"hide stats"}),h("span",{className:"ss-toggle-arrow",children:m?"▼":"▲"})]}),h("div",{ref:b,className:m?"ss-bar":"ss-bar ss-hidden","data-ss-theme":_,children:[h("div",{className:"ss-bar-left",children:[r&&h("button",{type:"button",className:`ss-dbg-btn ${s?"ss-dbg-active":""}`,onClick:r,title:"Toggle debug panel",id:"ss-dbg-wrench",children:h("svg",{width:"14",height:"14",viewBox:ut.wrench.viewBox,fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:ut.wrench.elements.join("")}})}),h("div",{className:d?"ss-dot ss-stale":"ss-dot"})]}),h("div",{ref:v,className:"ss-bar-scroll",id:"ss-bar-scroll",children:a&&H.map((w,$)=>h(It.Fragment,{children:[$>0&&h("div",{className:"ss-group-sep"}),h("div",{className:"ss-group",children:w.metrics.map(P=>h(kn,{metric:P,stats:a,history:c(P.historyKey||"")},P.id))})]},w.group))})]})]})}function Cn(e){const t=document.getElementById(e);return t?JSON.parse(t.textContent||"{}"):{}}const M=Cn("ss-bar-config");function Tn(){if(window.__ssDebugPanel)return!0;const e=document.querySelector('script[type="text/plain"][data-ss-deferred="debug-panel"]');if(!e)return console.error("[server-stats] Deferred debug panel script not found"),!1;try{const t=document.createElement("script");t.textContent=e.textContent,document.head.appendChild(t)}catch(t){return console.error("[server-stats] Debug panel script evaluation failed:",t),!1}return window.__ssDebugPanel?!0:(console.error("[server-stats] Debug panel failed to register after script evaluation"),!1)}function Sn(){let e=document.getElementById("ss-dbg-deferred");if(!e){e=document.createElement("div"),e.id="ss-dbg-deferred";const t=document.getElementById("ss-bar");t?.parentNode?t.parentNode.insertBefore(e,t.nextSibling):document.body.appendChild(e)}return e}function En(){const[e,t]=x(!1),[n,r]=x(!1),s=D(!1),o=M.showDebug?{debugEndpoint:M.debugEndpoint,authToken:M.authToken,dashboardPath:M.dashboardPath}:void 0,i=M.showDebug?{debugEndpoint:M.debugEndpoint,authToken:M.authToken}:void 0,a=G(()=>{t(c=>!c)},[]);return A(()=>{if(M.showDebug)if(e){if(s.current||(s.current=Tn()),!window.__ssDebugPanel){console.error("[server-stats] Debug panel not available after load attempt");return}if(!o){console.error("[server-stats] Debug config is undefined");return}const c=Sn();try{window.__ssDebugPanel.mount(c,o,n)}catch(u){console.error("[server-stats] Debug panel mount failed:",u)}}else{const c=document.getElementById("ss-dbg-deferred");if(window.__ssDebugPanel&&c)try{window.__ssDebugPanel.unmount(c)}catch(u){console.error("[server-stats] Debug panel unmount failed:",u)}}},[e,n,o]),h(N,{children:h(wn,{endpoint:M.endpoint,pollInterval:M.pollInterval,channelName:M.channelName,authToken:M.authToken,featureOptions:i,autoHideOnUnauthorized:!1,onOpenDebugPanel:M.showDebug?a:void 0,debugPanelOpen:e,onConnectionChange:r})})}const ft=document.getElementById("ss-bar");ft&&he(h(En,{}),ft)})();
|