From b97f8058507ac055d287b56b6542eb746c066774 Mon Sep 17 00:00:00 2001 From: Gabe Kangas Date: Sun, 6 Mar 2022 19:49:42 -0800 Subject: [PATCH] Display windowed time series viewer metrics (#454) * WIP displaying windowed time series viewer metrics. Closes https://github.com/owncast/owncast/issues/1478 * Remove unused import --- web/pages/viewer-info.tsx | 76 ++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/web/pages/viewer-info.tsx b/web/pages/viewer-info.tsx index 3956c4831..a334dd5a3 100644 --- a/web/pages/viewer-info.tsx +++ b/web/pages/viewer-info.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect, useContext } from 'react'; -import { Row, Col, Typography } from 'antd'; -import { UserOutlined } from '@ant-design/icons'; +import { Row, Col, Typography, Menu, Dropdown, Spin, Alert } from 'antd'; +import { DownOutlined, UserOutlined } from '@ant-design/icons'; +import { getUnixTime, sub } from 'date-fns'; import Chart from '../components/chart'; import StatisticItem from '../components/statistic'; import ViewerTable from '../components/viewer-table'; @@ -13,15 +14,34 @@ const FETCH_INTERVAL = 60 * 1000; // 1 min export default function ViewersOverTime() { const context = useContext(ServerStatusContext); - const { online, viewerCount, overallPeakViewerCount, sessionPeakViewerCount } = context || {}; + const { online, broadcaster, viewerCount, overallPeakViewerCount, sessionPeakViewerCount } = + context || {}; + let streamStart; + if (broadcaster && broadcaster.time) { + streamStart = new Date(broadcaster.time); + } + + const times = [ + { title: 'Current stream', start: streamStart }, + { title: 'Last 12 hours', start: sub(new Date(), { hours: 12 }) }, + { title: 'Last 24 hours', start: sub(new Date(), { hours: 24 }) }, + { title: 'Last 7 days', start: sub(new Date(), { days: 7 }) }, + { title: 'Last 30 days', start: sub(new Date(), { days: 30 }) }, + { title: 'Last 3 months', start: sub(new Date(), { months: 3 }) }, + { title: 'Last 6 months', start: sub(new Date(), { months: 6 }) }, + ]; + const [loadingChart, setLoadingChart] = useState(true); const [viewerInfo, setViewerInfo] = useState([]); const [viewerDetails, setViewerDetails] = useState([]); + const [timeWindowStart, setTimeWindowStart] = useState(times[1]); const getInfo = async () => { try { - const result = await fetchData(VIEWERS_OVER_TIME); + const url = `${VIEWERS_OVER_TIME}?windowStart=${getUnixTime(timeWindowStart.start)}`; + const result = await fetchData(url); setViewerInfo(result); + setLoadingChart(false); } catch (error) { console.log('==== error', error); } @@ -47,11 +67,28 @@ export default function ViewersOverTime() { } return () => []; - }, [online]); + }, [online, timeWindowStart]); - if (!viewerInfo.length) { - return 'no info'; - } + const onTimeWindowSelect = ({ key }) => { + setTimeWindowStart(times[key]); + }; + + const menu = ( + + {online && streamStart && ( + + {times[0].title} + + )} + {times.slice(1).map((time, index) => ( + // The array is hard coded, so it's safe to use the index as a key. + // eslint-disable-next-line react/no-array-index-key + + {time.title} + + ))} + + ); return ( <> @@ -82,9 +119,30 @@ export default function ViewersOverTime() { /> + + + + {viewerInfo.length > 0 && ( + + )} - + + + {viewerInfo.length === 0 && ( + + )} + ); }