mirror of
https://github.com/openmhz/trunk-server.git
synced 2026-11-12 08:47:40 -05:00
trying out cursor
This commit is contained in:
@@ -8,6 +8,7 @@ var systems = require("./controllers/systems");
|
||||
var talkgroups = require("./controllers/talkgroups");
|
||||
var groups = require("./controllers/groups");
|
||||
var stats = require("./controllers/stats");
|
||||
var sys_stats = require("./sys_stats");
|
||||
var events = require("./controllers/events");
|
||||
var config = require('./config/config.json');
|
||||
let db = require('./db')
|
||||
@@ -134,6 +135,7 @@ app.get('/events/:id', events.getEvent);
|
||||
|
||||
/*------ STATS ----------*/
|
||||
app.get('/:shortName/stats', stats.get_stats);
|
||||
app.get('/stats', sys_stats.siteStats)
|
||||
|
||||
|
||||
function get_clients(req, res) {
|
||||
|
||||
@@ -9,12 +9,20 @@ var uploadErrors = {};
|
||||
let decodeErrorsFreq = {};
|
||||
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;
|
||||
function updateUploadsPerMin(totalUploads) {
|
||||
uploadsPerMin.push(totalUploads / timePeriod);
|
||||
uploadsPerMin.shift();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
async function updateActiveSystems() {
|
||||
// Go through all of the Systems
|
||||
let siteTotal = 0;
|
||||
let activeSystems = 0;
|
||||
activeSystems = 0;
|
||||
|
||||
for await (let item of System.find()) {
|
||||
// go through all the systems
|
||||
@@ -33,6 +41,7 @@ async function updateActiveSystems() {
|
||||
|
||||
await item.save();
|
||||
};
|
||||
updateUploadsPerMin(siteTotal);
|
||||
console.log("Site average uploads per minute: " + siteTotal / timePeriod);
|
||||
console.log("Active Systems: " + activeSystems);
|
||||
}
|
||||
@@ -324,6 +333,16 @@ exports.shiftStats = async function () {
|
||||
updateActiveSystems();
|
||||
console.log("Finished Updating Active Systems at: " + new Date());
|
||||
}
|
||||
|
||||
exports.siteStats = function() {
|
||||
const siteStats ={
|
||||
uploadsPerMin,
|
||||
activeSystems
|
||||
}
|
||||
res.contentType('json');
|
||||
res.send(JSON.stringify(siteStats));
|
||||
};
|
||||
|
||||
exports.callTotals = function (shortName) {
|
||||
return callTotals[shortName];
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
} from 'semantic-ui-react'
|
||||
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { useGetSystemsQuery } from "../features/api/apiSlice";
|
||||
import { useGetStatsQuery, useGetSystemsQuery } 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 */
|
||||
|
||||
@@ -213,6 +213,86 @@ const ResponsiveContainer = ({ children }) => (
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
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 <Loader size='large'>Loading</Loader>;
|
||||
}
|
||||
|
||||
const width = 500;
|
||||
const height = 250;
|
||||
const margin = { top: 20, bottom: 40, left: 40, right: 20 };
|
||||
|
||||
const xMax = width - margin.left - margin.right;
|
||||
const yMax = height - margin.top - margin.bottom;
|
||||
|
||||
const now = new Date();
|
||||
const MS_PER_MINUTE = 60000;
|
||||
|
||||
const data = siteStats.map((stat, index) => ({
|
||||
y: stat,
|
||||
x: new Date(now - index * 15 * MS_PER_MINUTE)
|
||||
})).reverse();
|
||||
|
||||
const xScale = scaleTime({
|
||||
range: [0, xMax],
|
||||
domain: [data[0].x, data[data.length - 1].x],
|
||||
});
|
||||
|
||||
const yScale = scaleLinear({
|
||||
range: [yMax, 0],
|
||||
domain: [0, Math.max(...data.map(d => d.y))],
|
||||
nice: true,
|
||||
});
|
||||
|
||||
return (
|
||||
<svg width={width} height={height}>
|
||||
<Group left={margin.left} top={margin.top}>
|
||||
<LinePath
|
||||
data={data}
|
||||
x={d => xScale(d.x)}
|
||||
y={d => yScale(d.y)}
|
||||
stroke="#1a85ff"
|
||||
strokeWidth={2}
|
||||
curve={curveStep}
|
||||
/>
|
||||
<AxisBottom
|
||||
scale={xScale}
|
||||
top={yMax}
|
||||
numTicks={5}
|
||||
tickFormat={timeFormat("%H:%M")}
|
||||
/>
|
||||
<AxisLeft scale={yScale} />
|
||||
</Group>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
const SiteStatsContainer = () => {
|
||||
const { data: siteStats, isSuccess: siteStatsSuccess } = useGetStatsQuery();
|
||||
|
||||
if (!siteStatsSuccess) {
|
||||
return <Loader size='large'>Loading Site Stats</Loader>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>Site Activity</h2>
|
||||
<SiteStatsChart siteStats={siteStats.callTotals} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------
|
||||
const Main = (props) => {
|
||||
|
||||
@@ -220,6 +300,8 @@ const Main = (props) => {
|
||||
const [currentSystem, setCurrentSystem] = useState(0);
|
||||
const navigate = useNavigate();
|
||||
const { data: systems, isSuccess } = useGetSystemsQuery(); //= selectAllSystems();
|
||||
const { data: siteStats, isSuccess: siteStatsSuccess } = useGetStatsQuery();
|
||||
|
||||
|
||||
function useInterval(callback, delay) {
|
||||
const savedCallback = useRef();
|
||||
@@ -255,7 +337,7 @@ const Main = (props) => {
|
||||
|
||||
useInterval(() => { advanceSystem() }, 3000)
|
||||
|
||||
|
||||
|
||||
|
||||
//https://stackoverflow.com/questions/36559661/how-can-i-dispatch-from-child-components-in-react-redux
|
||||
//https://stackoverflow.com/questions/42597602/react-onclick-pass-event-with-parameter
|
||||
@@ -316,6 +398,23 @@ const Main = (props) => {
|
||||
</Grid>
|
||||
</Segment>
|
||||
|
||||
<Segment style={{ padding: '0em' }} vertical>
|
||||
<Grid columns='equal' stackable>
|
||||
<Grid.Row textAlign='center'>
|
||||
<Grid.Column style={{ paddingBottom: '5em', paddingTop: '5em' }}>
|
||||
<SiteStatsContainer />
|
||||
</Grid.Column>
|
||||
<Grid.Column style={{ paddingBottom: '5em', paddingTop: '5em' }}>
|
||||
<Statistic>
|
||||
<Statistic.Value>
|
||||
{siteStats?.activeSystems || 0}
|
||||
</Statistic.Value>
|
||||
<Statistic.Label>Active Systems</Statistic.Label>
|
||||
</Statistic>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</Segment>
|
||||
|
||||
|
||||
<Segment style={{ padding: '0em' }} vertical>
|
||||
|
||||
@@ -40,6 +40,13 @@ export const apiSlice = createApi({
|
||||
return responseData;
|
||||
}
|
||||
}),
|
||||
getSiteStats: builder.query({
|
||||
query: () => ({ url: '/stats' }),
|
||||
transformResponse: responseData => {
|
||||
// You can add any data transformation here if needed
|
||||
return responseData;
|
||||
}
|
||||
}),
|
||||
getTalkgroups: builder.query({
|
||||
// The URL for the request is '/fakeApi/posts'
|
||||
query: (shortName) => ({ url: `/${shortName}/talkgroups` })
|
||||
|
||||
Reference in New Issue
Block a user