0

It builds

This commit is contained in:
Gabe Kangas 2020-11-01 00:01:37 -07:00
parent 27f4b8b158
commit 9b89955bb7
17 changed files with 107 additions and 84 deletions

3
web/.env.production Normal file
View File

@ -0,0 +1,3 @@
NEXT_PUBLIC_ADMIN_USERNAME=admin
NEXT_PUBLIC_ADMIN_STREAMKEY=abc123
NEXT_PUBLIC_API_HOST=/

3
web/.gitignore vendored
View File

@ -1,4 +1,5 @@
node_modules
.env*.local
.next
.next
out

View File

@ -3,7 +3,7 @@ import 'antd/dist/antd.compact.css';
import "../styles/globals.scss";
import { AppProps } from 'next/app';
import BroadcastStatusProvider from './utils/broadcast-status-context';
import BroadcastStatusProvider from '../utils/broadcast-status-context';
import MainLayout from './components/main-layout';

View File

@ -1,5 +1,5 @@
import React, { useContext } from 'react';
import { BroadcastStatusContext } from './utils/broadcast-status-context';
import { BroadcastStatusContext } from '../utils/broadcast-status-context';
export default function BroadcastInfo() {

View File

@ -9,20 +9,23 @@ interface ToolTipProps {
const defaultProps = {
active: false,
payload: {},
unit: ""
payload: Object,
unit: "",
};
interface ChartProps {
data: [{
time: string,
}],
color: string,
unit: string,
dataCollections?: any,
interface TimedValue {
time: Date;
value: Number;
}
interface ChartProps {
// eslint-disable-next-line react/require-default-props
data?: TimedValue[],
color: string,
unit: string,
// eslint-disable-next-line react/require-default-props
dataCollections?: any[],
}
function CustomizedTooltip(props: ToolTipProps) {
const { active, payload, unit } = props;
@ -41,13 +44,23 @@ function CustomizedTooltip(props: ToolTipProps) {
CustomizedTooltip.defaultProps = defaultProps;
export default function Chart({ data, color, unit, dataCollections }: ChartProps) {
if (!data && !dataCollections) {
return null;
}
const timeFormatter = (tick: string) => {
return timeFormat("%I:%M")(new Date(tick));
};
let ticks = data.map((item) => item?.time);
if (dataCollections) {
ticks = dataCollections[0].data?.map((collection) => collection?.time);
let ticks
if (dataCollections.length > 0) {
ticks = dataCollections[0].data?.map(function (collection) {
return collection?.time;
})
} else if (data?.length > 0){
ticks = data?.map(function (item) {
return item?.time;
});
}
return (

View File

@ -19,13 +19,18 @@ function renderColumnLevel(text, entry) {
return <div style={style}>{text}</div>;
}
function renderMessage(text, entry) {
function renderMessage(text) {
return (
<Linkify>{text}</Linkify>
)
}
export default function LogTable({ logs, pageSize }) {
interface Props {
logs: object[],
pageSize: number
}
export default function LogTable({ logs, pageSize }: Props) {
const columns = [
{
title: "Level",

View File

@ -9,14 +9,13 @@ import {
LineChartOutlined,
CloseCircleOutlined,
PlayCircleFilled,
StopFilled,
MinusSquareFilled,
} from '@ant-design/icons';
import classNames from 'classnames';
import OwncastLogo from './logo';
import { BroadcastStatusContext } from '../utils/broadcast-status-context';
import { BroadcastStatusContext } from '../../utils/broadcast-status-context';
import adminStyles from '../../styles/styles.module.css';

View File

@ -1,16 +1,22 @@
/* eslint-disable no-array-constructor */
import React, { useState, useEffect } from 'react';
import { Row, Skeleton, Empty, Typography } from "antd";
import { Row } from "antd";
import {LaptopOutlined, BulbOutlined, SaveOutlined} from "@ant-design/icons"
import { HARDWARE_STATS, fetchData, FETCH_INTERVAL } from './utils/apis';
import { HARDWARE_STATS, fetchData, FETCH_INTERVAL } from '../utils/apis';
import Chart from './components/chart';
import StatisticItem from "./components/statistic";
interface TimedValue {
time: Date,
value: Number
}
export default function HardwareInfo() {
const [hardwareStatus, setHardwareStatus] = useState({
cpu: 0,
memory: 0,
disk: 0,
message: '',
cpu: Array<TimedValue>(),
memory: Array<TimedValue>(),
disk: Array<TimedValue>(),
message: "",
});
const getHardwareStatus = async () => {

View File

@ -11,7 +11,7 @@ import React, { useState, useEffect, useContext } from "react";
import { Row, Skeleton, Empty, Typography } from "antd";
import { UserOutlined, ClockCircleOutlined } from "@ant-design/icons";
import { formatDistanceToNow, formatRelative } from "date-fns";
import { BroadcastStatusContext } from "./utils/broadcast-status-context";
import { BroadcastStatusContext } from "../utils/broadcast-status-context";
import StatisticItem from "./components/statistic"
import LogTable from "./components/log-table";
@ -21,8 +21,8 @@ import {
LOGS_WARN,
fetchData,
FETCH_INTERVAL,
} from "./utils/apis";
import { formatIPAddress, isEmptyObject } from "./utils/format";
} from "../utils/apis";
import { formatIPAddress, isEmptyObject } from "../utils/format";
const { Title } = Typography;
@ -60,7 +60,22 @@ export default function Stats() {
// Pull in the server config so we can show config overview.
const [config, setConfig] = useState([]);
const [config, setConfig] = useState({
streamKey: "",
yp: {
enabled: false,
},
videoSettings: {
videoQualityVariants: [
{
audioPassthrough: false,
videoBitrate: 0,
audioBitrate: 0,
framerate: 0,
},
],
},
});
const [logs, setLogs] = useState([]);
const getConfig = async () => {
@ -108,6 +123,7 @@ export default function Stats() {
: `${setting.audioBitrate} kbps`;
return (
// eslint-disable-next-line react/no-array-index-key
<Row gutter={[16, 16]} key={index}>
<StatisticItem
title="Outbound Video Stream"

View File

@ -4,7 +4,7 @@ import LogTable from "./components/log-table"
import {
LOGS_ALL,
fetchData,
} from "./utils/apis";
} from "../utils/apis";
const FETCH_INTERVAL = 5 * 1000; // 5 sec

View File

@ -1,9 +1,10 @@
/* eslint-disable react/prop-types */
import React, { useState, useEffect } from "react";
import { SERVER_CONFIG, fetchData, FETCH_INTERVAL } from "./utils/apis";
import { SERVER_CONFIG, fetchData, FETCH_INTERVAL } from "../utils/apis";
import KeyValueTable from "./components/key-value-table";
function Storage({ config }) {
if (!config) {
if (!config || !config.s3) {
return null;
}
@ -46,7 +47,7 @@ function Storage({ config }) {
}
export default function ServerConfig() {
const [config, setConfig] = useState();
const [config, setConfig] = useState({});
const getInfo = async () => {
try {

View File

@ -1,7 +1,8 @@
/* eslint-disable react/prop-types */
import React, { useState, useEffect } from 'react';
import { Table, Typography, Input } from 'antd';
import { SERVER_CONFIG, fetchData, FETCH_INTERVAL } from './utils/apis';
import { isEmptyObject } from './utils/format';
import { SERVER_CONFIG, fetchData, FETCH_INTERVAL } from '../utils/apis';
import { isEmptyObject } from '../utils/format';
import KeyValueTable from "./components/key-value-table";
const { Title } = Typography;
@ -27,20 +28,23 @@ function SocialHandles({ config }) {
},
];
return (
<div>
<Title>Social Handles</Title>
<Table
pagination={false}
columns={columns}
dataSource={config.instanceDetails.socialHandles}
/>
</div>
);
if (!config.instanceDetails?.socialHandles) {
return null;
}
return (
<div>
<Title>Social Handles</Title>
<Table
pagination={false}
columns={columns}
dataSource={config.instanceDetails.socialHandles}
/>
</div>
);
}
function InstanceDetails({ config }) {
console.log(config)
if (!config || isEmptyObject(config)) {
return null;
}
@ -102,7 +106,7 @@ function InstanceDetails({ config }) {
}
function PageContent({ config }) {
if (!config) {
if (!config?.instanceDetails?.extraPageContent) {
return null;
}
return (
@ -117,7 +121,7 @@ function PageContent({ config }) {
}
export default function ServerConfig() {
const [config, setConfig] = useState();
const [config, setConfig] = useState({});
const getInfo = async () => {
try {

View File

@ -1,12 +1,13 @@
/* eslint-disable react/prop-types */
import React, { useState, useEffect } from 'react';
import { Table, Typography } from 'antd';
import { SERVER_CONFIG, fetchData, FETCH_INTERVAL } from './utils/apis';
import { SERVER_CONFIG, fetchData, FETCH_INTERVAL } from '../utils/apis';
const { Title } = Typography;
function VideoVariants({ config }) {
if (!config) {
if (!config || !config.videoSettings) {
return null;
}
@ -80,7 +81,7 @@ function VideoVariants({ config }) {
}
export default function VideoConfig() {
const [config, setConfig] = useState();
const [config, setConfig] = useState({});
const getInfo = async () => {
try {

View File

@ -1,18 +1,20 @@
/* eslint-disable react/prop-types */
import React, { useState, useEffect, useContext } from 'react';
import { timeFormat } from "d3-time-format";
import { Table, Row } from "antd";
import { formatDistanceToNow } from "date-fns";
import { UserOutlined} from "@ant-design/icons";
import { SortOrder } from "antd/lib/table/interface";
import Chart from "./components/chart";
import StatisticItem from "./components/statistic";
import { BroadcastStatusContext } from './utils/broadcast-status-context';
import { BroadcastStatusContext } from '../utils/broadcast-status-context';
import {
CONNECTED_CLIENTS,
STREAM_STATUS, VIEWERS_OVER_TIME,
fetchData,
} from "./utils/apis";
} from "../utils/apis";
const FETCH_INTERVAL = 5 * 60 * 1000; // 5 mins
@ -78,14 +80,14 @@ export default function ViewersOverTime() {
key: "username",
render: (username) => username || "-",
sorter: (a, b) => a.username - b.username,
sortDirections: ["descend", "ascend"],
sortDirections: ["descend", "ascend"] as SortOrder[],
},
{
title: "Messages sent",
dataIndex: "messageCount",
key: "messageCount",
sorter: (a, b) => a.messageCount - b.messageCount,
sortDirections: ["descend", "ascend"],
sortDirections: ["descend", "ascend"] as SortOrder[],
},
{
title: "Connected Time",
@ -106,34 +108,6 @@ export default function ViewersOverTime() {
},
];
const timeFormatter = (tick) => {
return timeFormat("%H:%M")(new Date(tick));
};
const CustomizedTooltip = (props) => {
const { active, payload, label } = props;
if (active) {
const numViewers = payload && payload[0] && payload[0].value;
const time = timeFormatter(label);
const message = `${numViewers} viewer(s) at ${time}`;
return (
<div className="custom-tooltip">
<p className="label">{message}</p>
</div>
);
}
return null;
};
/*
geo data looks like this
"geo": {
"countryCode": "US",
"regionName": "California",
"timeZone": "America/Los_Angeles"
}
*/
return (
<div>
<h2>Current Viewers</h2>