diff --git a/backend/index.js b/backend/index.js
index 1ef08f8..aa47ab9 100644
--- a/backend/index.js
+++ b/backend/index.js
@@ -95,6 +95,10 @@ function addSystemClients(req, res, next) {
next();
}
+function addTotalClients(req, res, next) {
+ req.totalClients = clients.length;
+ next();
+}
/*------ CALLS ----------*/
@@ -135,7 +139,7 @@ app.get('/events/:id', events.getEvent);
/*------ STATS ----------*/
app.get('/:shortName/stats', stats.get_stats);
-app.get('/stats', sys_stats.siteStats)
+app.get('/stats', addTotalClients, sys_stats.siteStats)
function get_clients(req, res) {
diff --git a/backend/sys_stats.js b/backend/sys_stats.js
index 490ef1a..d312a24 100644
--- a/backend/sys_stats.js
+++ b/backend/sys_stats.js
@@ -11,6 +11,7 @@ const timePeriod = 15; // in minutes
var spots = (24 * 60) / timePeriod; // the number of spots needed to keep track of 24 hours of stats
let uploadsPerMin = new Array(spots).fill(0);
let activeSystems = 0;
+let totalClients = 0;
function updateUploadsPerMin(totalUploads) {
uploadsPerMin.push(totalUploads / timePeriod);
uploadsPerMin.shift();
@@ -42,6 +43,10 @@ async function updateActiveSystems() {
await item.save();
};
updateUploadsPerMin(siteTotal);
+ // Save talkgroupStats to a JSON file
+ const filePath = "/data/stats/uploadsPerMin.json";
+ fs.writeFileSync(filePath, JSON.stringify(uploadsPerMin));
+ console.log("Saved uploadsPerMin to JSON file");
console.log("Site average uploads per minute: " + siteTotal / timePeriod);
console.log("Active Systems: " + activeSystems);
}
@@ -81,6 +86,22 @@ exports.initStats = async function () {
console.error("Decode Errors File not found: " + decodeErrorsFreqPath);
}
+ const uploadsPerMinPath = "/data/stats/uploadsPerMin.json";
+ if (fs.existsSync(uploadsPerMinPath)) {
+ // Read the contents of the file
+ const fileContents = fs.readFileSync(uploadsPerMinPath, "utf8");
+
+ // Parse the JSON data
+ try {
+ uploadsPerMin = JSON.parse(fileContents);
+ } catch (error) {
+ console.error("Decode Errors - Error parsing JSON data:", error);
+ }
+ } else {
+ console.error("Decode Errors File not found: " + uploadsPerMinPath);
+ }
+
+
/*
for await (const item of SystemStat.find()) {
const obj = item.toObject();
@@ -334,10 +355,12 @@ exports.shiftStats = async function () {
console.log("Finished Updating Active Systems at: " + new Date());
}
-exports.siteStats = function() {
+
+exports.siteStats = function(req, res) {
const siteStats ={
uploadsPerMin,
- activeSystems
+ activeSystems,
+ totalClients: req.totalClients
}
res.contentType('json');
res.send(JSON.stringify(siteStats));
diff --git a/frontend/src/Call/BetterActivityChart.js b/frontend/src/Call/BetterActivityChart.js
index a0a007e..63cc732 100644
--- a/frontend/src/Call/BetterActivityChart.js
+++ b/frontend/src/Call/BetterActivityChart.js
@@ -27,7 +27,7 @@ const tooltipStyles = {
};
// util
-const formatDate = timeFormat("%b %d, %H:%m");
+const formatDate = timeFormat("%b %d, %H:%MM");
// accessors
const getDate = (d) => {
diff --git a/frontend/src/Main/Main.js b/frontend/src/Main/Main.js
index 64269ad..bf021b7 100644
--- a/frontend/src/Main/Main.js
+++ b/frontend/src/Main/Main.js
@@ -1,4 +1,4 @@
-import React, { useState, useEffect, useRef } from "react";
+import React, { useState, useEffect, useRef, useMemo } from "react";
import { Link, useNavigate } from 'react-router-dom'
import SystemCard from "../System/SystemCard";
import SupportModal from "../Common/SupportModal";
@@ -16,12 +16,24 @@ import {
Menu,
Segment,
Sidebar,
+ Loader,
+ Statistic,
Transition,
} from 'semantic-ui-react'
-
+import { AreaClosed, Line, Bar } from '@visx/shape';
+import { curveMonotoneX } from '@visx/curve';
+import { GridRows, GridColumns } from '@visx/grid';
+import { scaleTime, scaleLinear } from '@visx/scale';
+import { withTooltip, Tooltip, TooltipWithBounds, defaultStyles } from '@visx/tooltip';
+import { useTooltip, useTooltipInPortal } from '@visx/tooltip';
+import { localPoint } from '@visx/event';
+import { LinearGradient } from '@visx/gradient';
+import { max, extent, bisector } from 'd3-array';
+import { timeFormat } from 'd3-time-format';
+import { AxisLeft } from '@visx/axis';
import { useDispatch } from 'react-redux'
-import { useGetStatsQuery, useGetSystemsQuery } from "../features/api/apiSlice";
+import { useGetStatsQuery, useGetSystemsQuery, useGetSiteStatsQuery } from "../features/api/apiSlice";
/* Responsive component was removed from Semantic UI. This is discussed here: https://github.com/Semantic-Org/Semantic-UI-React/pull/4008 */
@@ -201,6 +213,8 @@ const MobileContainer = (props) => {
)
}
+
+
/*
MobileContainer.propTypes = {
children: PropTypes.node,
@@ -214,71 +228,238 @@ const ResponsiveContainer = ({ children }) => (
)
-import React from "react";
-import { Group } from '@visx/group';
-import { curveStep } from '@visx/curve';
-import { LinePath } from '@visx/shape';
-import { scaleLinear, scaleTime } from '@visx/scale';
-import { timeParse, timeFormat } from 'd3-time-format';
-import { AxisBottom, AxisLeft } from '@visx/axis';
-import { Loader } from "semantic-ui-react";
-const SiteStatsChart = ({ siteStats }) => {
- if (!siteStats) {
- return