You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
213 lines
6.6 KiB
213 lines
6.6 KiB
import React, { useContext, useEffect, useState } from 'react'; |
|
import PropTypes from 'prop-types'; |
|
import Link from 'next/link'; |
|
import Head from 'next/head' |
|
import { differenceInSeconds } from "date-fns"; |
|
import { useRouter } from 'next/router'; |
|
import { Layout, Menu, Popover } from 'antd'; |
|
|
|
import { |
|
SettingOutlined, |
|
HomeOutlined, |
|
LineChartOutlined, |
|
ToolOutlined, |
|
PlayCircleFilled, |
|
MinusSquareFilled, |
|
QuestionCircleOutlined, |
|
MessageOutlined, |
|
ExperimentOutlined, |
|
|
|
} from '@ant-design/icons'; |
|
import classNames from 'classnames'; |
|
import { upgradeVersionAvailable } from "../../utils/apis"; |
|
import { parseSecondsToDurationString } from '../../utils/format' |
|
|
|
import OwncastLogo from './logo'; |
|
import { ServerStatusContext } from '../../utils/server-status-context'; |
|
|
|
import adminStyles from '../../styles/styles.module.scss'; |
|
|
|
let performedUpgradeCheck = false; |
|
|
|
export default function MainLayout(props) { |
|
const { children } = props; |
|
|
|
const context = useContext(ServerStatusContext); |
|
const { online, broadcaster, versionNumber } = context || {}; |
|
|
|
const router = useRouter(); |
|
const { route } = router || {}; |
|
|
|
const { Header, Footer, Content, Sider } = Layout; |
|
const { SubMenu } = Menu; |
|
|
|
// status indicator items |
|
const streamDurationString = online ? parseSecondsToDurationString(differenceInSeconds(new Date(), new Date(broadcaster.time))) : ""; |
|
const currentThumbnail = online ? ( |
|
<img src="/thumbnail.jpg" className={adminStyles.onlineCurrentThumb} alt="current thumbnail" /> |
|
) : null; |
|
const statusIcon = online ? <PlayCircleFilled /> : <MinusSquareFilled />; |
|
const statusMessage = online ? `Online ${streamDurationString}` : "Offline"; |
|
const statusIndicator = ( |
|
<div className={adminStyles.statusIndicatorContainer}> |
|
<span className={adminStyles.statusLabel}>{statusMessage}</span> |
|
<span className={adminStyles.statusIcon}>{statusIcon}</span> |
|
</div> |
|
); |
|
const statusIndicatorWithThumb = online ? ( |
|
<Popover |
|
content={currentThumbnail} |
|
title="Thumbnail" |
|
trigger="hover" |
|
> |
|
{statusIndicator} |
|
</Popover> |
|
) : statusIndicator; |
|
// /////////////// |
|
|
|
const [upgradeVersion, setUpgradeVersion] = useState(null); |
|
const checkForUpgrade = async () => { |
|
try { |
|
const result = await upgradeVersionAvailable(versionNumber); |
|
setUpgradeVersion(result); |
|
} catch (error) { |
|
console.log("==== error", error); |
|
} |
|
}; |
|
|
|
useEffect(() => { |
|
if (!performedUpgradeCheck && !context.disableUpgradeChecks) { |
|
checkForUpgrade(); |
|
performedUpgradeCheck = true |
|
} |
|
}); |
|
|
|
const appClass = classNames({ |
|
"owncast-layout": true, |
|
[adminStyles.online]: online, |
|
}); |
|
|
|
const upgradeMenuItemStyle = upgradeVersion ? 'block' : 'none'; |
|
const upgradeVersionString = upgradeVersion || ''; |
|
|
|
return ( |
|
<Layout className={appClass}> |
|
<Head> |
|
<title>Owncast Admin</title> |
|
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon/favicon-32x32.png"/> |
|
</Head> |
|
|
|
<Sider |
|
width={240} |
|
className={adminStyles.sideNav} |
|
> |
|
<Menu |
|
theme="dark" |
|
defaultSelectedKeys={[route.substring(1) || "home"]} |
|
defaultOpenKeys={["current-stream-menu", "utilities-menu", "configuration"]} |
|
mode="inline" |
|
> |
|
<h1 className={adminStyles.owncastTitleContainer}> |
|
<span className={adminStyles.logoContainer}> |
|
<OwncastLogo /> |
|
</span> |
|
<span className={adminStyles.owncastTitle}>Owncast Admin</span> |
|
</h1> |
|
<Menu.Item key="home" icon={<HomeOutlined />}> |
|
<Link href="/">Home</Link> |
|
</Menu.Item> |
|
|
|
<Menu.Item |
|
key="viewer-info" |
|
icon={<LineChartOutlined />} |
|
title="Current stream" |
|
> |
|
<Link href="/viewer-info">Viewers</Link> |
|
</Menu.Item> |
|
|
|
<Menu.Item |
|
key="chat" |
|
icon={<MessageOutlined />} |
|
title="Chat utilities" |
|
> |
|
<Link href="/chat">Chat</Link> |
|
</Menu.Item> |
|
|
|
<SubMenu |
|
key="configuration" |
|
title="Configuration" |
|
icon={<SettingOutlined />} |
|
> |
|
<Menu.Item key="config-public-details"> |
|
<Link href="/config-public-details">Public Details</Link> |
|
</Menu.Item> |
|
<Menu.Item key="config-server-details"> |
|
<Link href="/config-server-details">Server Details</Link> |
|
</Menu.Item> |
|
<Menu.Item key="config-video"> |
|
<Link href="/config-video">Video Setup</Link> |
|
</Menu.Item> |
|
<Menu.Item key="config-storage"> |
|
<Link href="/config-storage">Storage</Link> |
|
</Menu.Item> |
|
<Menu.Item key="config-page-content"> |
|
<Link href="/config-page-content">Custom page content</Link> |
|
</Menu.Item> |
|
</SubMenu> |
|
|
|
<SubMenu |
|
key="utilities-menu" |
|
icon={<ToolOutlined />} |
|
title="Utilities" |
|
> |
|
<Menu.Item key="hardware-info"> |
|
<Link href="/hardware-info">Hardware</Link> |
|
</Menu.Item> |
|
<Menu.Item key="logs"> |
|
<Link href="/logs">Logs</Link> |
|
</Menu.Item> |
|
<Menu.Item key="upgrade" style={{ display: upgradeMenuItemStyle }}> |
|
<Link href="/upgrade"> |
|
<a>Upgrade to v{upgradeVersionString}</a> |
|
</Link> |
|
</Menu.Item> |
|
</SubMenu> |
|
<SubMenu |
|
key="integrations-menu" |
|
icon={<ExperimentOutlined />} |
|
title="Integrations" |
|
> |
|
<Menu.Item key="webhooks"> |
|
<Link href="/webhooks">Webhooks</Link> |
|
</Menu.Item> |
|
<Menu.Item key="access-tokens"> |
|
<Link href="/access-tokens">Access Tokens</Link> |
|
</Menu.Item> |
|
</SubMenu> |
|
<Menu.Item |
|
key="help" |
|
icon={<QuestionCircleOutlined />} |
|
title="Help" |
|
> |
|
<Link href="/help">Help</Link> |
|
</Menu.Item> |
|
</Menu> |
|
</Sider> |
|
|
|
<Layout className={adminStyles.layoutMain}> |
|
<Header className={adminStyles.header}> |
|
{statusIndicatorWithThumb} |
|
</Header> |
|
<Content className={adminStyles.contentMain}>{children}</Content> |
|
|
|
<Footer style={{ textAlign: "center" }}> |
|
<a href="https://owncast.online/">About Owncast v{versionNumber}</a> |
|
</Footer> |
|
</Layout> |
|
</Layout> |
|
); |
|
} |
|
|
|
MainLayout.propTypes = { |
|
children: PropTypes.element.isRequired, |
|
}; |