diff --git a/web/.eslintrc.js b/web/.eslintrc.js
index 02acbf71d..48efb824c 100644
--- a/web/.eslintrc.js
+++ b/web/.eslintrc.js
@@ -4,48 +4,49 @@ module.exports = {
es2021: true,
},
extends: [
- "plugin:react/recommended",
- "airbnb",
- "prettier",
- "prettier/@typescript-eslint",
- "prettier/react",
+ 'plugin:react/recommended',
+ 'airbnb',
+ 'prettier',
+ 'prettier/@typescript-eslint',
+ 'prettier/react',
],
- parser: "@typescript-eslint/parser",
+ parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
- sourceType: "module",
+ sourceType: 'module',
},
- plugins: ["react", "@typescript-eslint"],
+ plugins: ['react', 'prettier', '@typescript-eslint'],
rules: {
- "react/react-in-jsx-scope": "off",
- "react/jsx-filename-extension": [1, { extensions: [".js", ".jsx", ".tsx"] }],
- "react/jsx-props-no-spreading": "off",
-
+ 'prettier/prettier': 'error',
+ 'react/react-in-jsx-scope': 'off',
+ 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx', '.tsx'] }],
+ 'react/jsx-props-no-spreading': 'off',
+
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'error',
-
+
'no-use-before-define': [0],
'@typescript-eslint/no-use-before-define': [1],
-
- "import/extensions": [
- "error",
- "ignorePackages",
+
+ 'import/extensions': [
+ 'error',
+ 'ignorePackages',
{
- "js": "never",
- "jsx": "never",
- "ts": "never",
- "tsx": "never"
- }
- ]
+ js: 'never',
+ jsx: 'never',
+ ts: 'never',
+ tsx: 'never',
+ },
+ ],
},
settings: {
- "import/resolver": {
- "node": {
- "extensions": [".js", ".jsx", ".ts", ".tsx"]
- }
- }
+ 'import/resolver': {
+ node: {
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
+ },
+ },
},
};
diff --git a/web/.prettierrc b/web/.prettierrc
index 222861c34..b4745cdab 100644
--- a/web/.prettierrc
+++ b/web/.prettierrc
@@ -1,4 +1,9 @@
{
+ "useTabs": false,
+ "printWidth": 100,
"tabWidth": 2,
- "useTabs": false
+ "singleQuote": true,
+ "trailingComma": "all",
+ "jsxBracketSameLine": false,
+ "arrowParens": "avoid"
}
diff --git a/web/pages/_app.tsx b/web/pages/_app.tsx
index ee1c34dfe..f9e46c81c 100644
--- a/web/pages/_app.tsx
+++ b/web/pages/_app.tsx
@@ -11,7 +11,6 @@ import { AppProps } from 'next/app';
import ServerStatusProvider from '../utils/server-status-context';
import MainLayout from './components/main-layout';
-
function App({ Component, pageProps }: AppProps) {
return (
@@ -19,8 +18,7 @@ function App({ Component, pageProps }: AppProps) {
-
- )
+ );
}
-export default App;
\ No newline at end of file
+export default App;
diff --git a/web/pages/components/config/constants.tsx b/web/pages/components/config/constants.tsx
index 71ab10a50..1de2f3fe2 100644
--- a/web/pages/components/config/constants.tsx
+++ b/web/pages/components/config/constants.tsx
@@ -15,7 +15,7 @@ export const SUCCESS_STATES = {
},
error: {
icon: ,
- message: 'An error occurred.',
+ message: 'An error occurred.',
},
};
@@ -39,14 +39,8 @@ export const API_VIDEO_VARIANTS = '/video/streamoutputvariants';
export const API_WEB_PORT = '/webserverport';
export const API_YP_SWITCH = '/directoryenabled';
-
export async function postConfigUpdateToAPI(args: ApiPostArgs) {
- const {
- apiPath,
- data,
- onSuccess,
- onError,
- } = args;
+ const { apiPath, data, onSuccess, onError } = args;
const result = await fetchData(`${SERVER_CONFIG_UPDATE_URL}${apiPath}`, {
data,
method: 'POST',
@@ -59,7 +53,6 @@ export async function postConfigUpdateToAPI(args: ApiPostArgs) {
}
}
-
// Some default props to help build out a TextField
export const TEXTFIELD_PROPS_USERNAME = {
apiPath: API_USERNAME,
@@ -95,7 +88,8 @@ export const TEXTFIELD_PROPS_LOGO = {
maxLength: 255,
placeholder: '/img/mylogo.png',
label: 'Logo',
- tip: 'Path to your logo from website root. We recommend that you use a square image that is at least 256x256. (upload functionality coming soon)',
+ tip:
+ 'Path to your logo from website root. We recommend that you use a square image that is at least 256x256. (upload functionality coming soon)',
};
export const TEXTFIELD_PROPS_STREAM_KEY = {
apiPath: API_STREAM_KEY,
@@ -163,17 +157,19 @@ export const FIELD_PROPS_NSFW = {
apiPath: API_NSFW_SWITCH,
configPath: 'instanceDetails',
label: 'NSFW?',
- tip: "Turn this ON if you plan to steam explicit or adult content. You may want to respectfully set this flag so that unexpecting eyes won't accidentally see it from the Directory.",
+ tip:
+ "Turn this ON if you plan to steam explicit or adult content. You may want to respectfully set this flag so that unexpecting eyes won't accidentally see it from the Directory.",
};
export const FIELD_PROPS_YP = {
apiPath: API_YP_SWITCH,
configPath: 'yp',
label: 'Display in the Owncast Directory?',
- tip: 'Turn this ON if you want to show up in the Owncast directory at https://directory.owncast.online.',
+ tip:
+ 'Turn this ON if you want to show up in the Owncast directory at https://directory.owncast.online.',
};
-export const DEFAULT_VARIANT_STATE:VideoVariant = {
+export const DEFAULT_VARIANT_STATE: VideoVariant = {
framerate: 24,
videoPassthrough: false,
videoBitrate: 800,
@@ -182,7 +178,7 @@ export const DEFAULT_VARIANT_STATE:VideoVariant = {
cpuUsageLevel: 3,
};
-export const DEFAULT_SOCIAL_HANDLE:SocialHandle = {
+export const DEFAULT_SOCIAL_HANDLE: SocialHandle = {
url: '',
platform: '',
};
diff --git a/web/pages/components/config/cpu-usage.tsx b/web/pages/components/config/cpu-usage.tsx
index 08a404928..1f79cc04c 100644
--- a/web/pages/components/config/cpu-usage.tsx
+++ b/web/pages/components/config/cpu-usage.tsx
@@ -1,5 +1,5 @@
import React, { useContext, useState, useEffect } from 'react';
-import { Typography, Slider, } from 'antd';
+import { Typography, Slider } from 'antd';
import { ServerStatusContext } from '../../../utils/server-status-context';
const { Title } = Typography;
@@ -12,8 +12,7 @@ const SLIDER_MARKS = {
5: 'highest',
};
-
-export default function CPUUsageSelector({defaultValue, onChange}) {
+export default function CPUUsageSelector({ defaultValue, onChange }) {
const [selectedOption, setSelectedOption] = useState(null);
const serverStatusData = useContext(ServerStatusContext);
@@ -27,21 +26,20 @@ export default function CPUUsageSelector({defaultValue, onChange}) {
useEffect(() => {
setSelectedOption(defaultValue);
}, [videoSettings]);
-
+
const handleChange = value => {
- setSelectedOption(value);
- onChange(value);
+ setSelectedOption(value);
+ onChange(value);
};
return (
CPU Usage
-
- There are trade-offs when considering CPU usage blah blah more wording here.
-
-
+
There are trade-offs when considering CPU usage blah blah more wording here.
+
+
-
);
-}
\ No newline at end of file
+}
diff --git a/web/pages/components/config/edit-directory.tsx b/web/pages/components/config/edit-directory.tsx
index 08608cf10..fa8e81382 100644
--- a/web/pages/components/config/edit-directory.tsx
+++ b/web/pages/components/config/edit-directory.tsx
@@ -19,7 +19,6 @@ export default function EditYPDetails() {
const { nsfw } = instanceDetails;
const { enabled, instanceUrl } = yp;
-
useEffect(() => {
setFormDataValues({
...yp,
@@ -35,10 +34,21 @@ export default function EditYPDetails() {
return (
Owncast Directory Settings
-
-
Would you like to appear in the Owncast Directory ?
-
NOTE: You will need to have a URL specified in the Instance URL
field to be able to use this.
+
+ Would you like to appear in the{' '}
+
+ Owncast Directory
+
+ ?
+
+
+
+
+ NOTE: You will need to have a URL specified in the Instance URL
field to be
+ able to use this.
+
+
-
+
- );
+ );
}
-
-
diff --git a/web/pages/components/config/edit-instance-details.tsx b/web/pages/components/config/edit-instance-details.tsx
index af2821836..bc84616ea 100644
--- a/web/pages/components/config/edit-instance-details.tsx
+++ b/web/pages/components/config/edit-instance-details.tsx
@@ -1,8 +1,20 @@
import React, { useState, useContext, useEffect } from 'react';
-import TextFieldWithSubmit, { TEXTFIELD_TYPE_TEXTAREA, TEXTFIELD_TYPE_URL } from './form-textfield-with-submit';
+import TextFieldWithSubmit, {
+ TEXTFIELD_TYPE_TEXTAREA,
+ TEXTFIELD_TYPE_URL,
+} from './form-textfield-with-submit';
import { ServerStatusContext } from '../../../utils/server-status-context';
-import { postConfigUpdateToAPI, TEXTFIELD_PROPS_USERNAME, TEXTFIELD_PROPS_INSTANCE_URL, TEXTFIELD_PROPS_SERVER_TITLE, TEXTFIELD_PROPS_STREAM_TITLE, TEXTFIELD_PROPS_SERVER_SUMMARY, TEXTFIELD_PROPS_LOGO, API_YP_SWITCH } from './constants';
+import {
+ postConfigUpdateToAPI,
+ TEXTFIELD_PROPS_USERNAME,
+ TEXTFIELD_PROPS_INSTANCE_URL,
+ TEXTFIELD_PROPS_SERVER_TITLE,
+ TEXTFIELD_PROPS_STREAM_TITLE,
+ TEXTFIELD_PROPS_SERVER_SUMMARY,
+ TEXTFIELD_PROPS_LOGO,
+ API_YP_SWITCH,
+} from './constants';
import configStyles from '../../../styles/config-pages.module.scss';
import { UpdateArgs } from '../../../types/config-section';
@@ -35,16 +47,16 @@ export default function EditInstanceDetails() {
});
}
}
- }
+ };
const handleFieldChange = ({ fieldName, value }: UpdateArgs) => {
setFormDataValues({
...formDataValues,
[fieldName]: value,
});
- }
+ };
- return (
+ return (
- );
+
+ );
}
-
-
diff --git a/web/pages/components/config/edit-server-details.tsx b/web/pages/components/config/edit-server-details.tsx
index d052c7bb1..1159bd4dd 100644
--- a/web/pages/components/config/edit-server-details.tsx
+++ b/web/pages/components/config/edit-server-details.tsx
@@ -6,7 +6,12 @@ import { TEXTFIELD_TYPE_NUMBER, TEXTFIELD_TYPE_PASSWORD } from './form-textfield
import TextFieldWithSubmit from './form-textfield-with-submit';
import { ServerStatusContext } from '../../../utils/server-status-context';
-import { TEXTFIELD_PROPS_FFMPEG, TEXTFIELD_PROPS_RTMP_PORT, TEXTFIELD_PROPS_STREAM_KEY, TEXTFIELD_PROPS_WEB_PORT, } from './constants';
+import {
+ TEXTFIELD_PROPS_FFMPEG,
+ TEXTFIELD_PROPS_RTMP_PORT,
+ TEXTFIELD_PROPS_STREAM_KEY,
+ TEXTFIELD_PROPS_WEB_PORT,
+} from './constants';
import configStyles from '../../../styles/config-pages.module.scss';
import { UpdateArgs } from '../../../types/config-section';
@@ -18,13 +23,16 @@ export default function EditInstanceDetails() {
const { streamKey, ffmpegPath, rtmpServerPort, webServerPort } = serverConfig;
- const [copyIsVisible, setCopyVisible] = useState(false);
+ const [copyIsVisible, setCopyVisible] = useState(false);
const COPY_TOOLTIP_TIMEOUT = 3000;
useEffect(() => {
setFormDataValues({
- streamKey, ffmpegPath, rtmpServerPort, webServerPort
+ streamKey,
+ ffmpegPath,
+ rtmpServerPort,
+ webServerPort,
});
}, [serverConfig]);
@@ -37,26 +45,25 @@ export default function EditInstanceDetails() {
...formDataValues,
[fieldName]: value,
});
- }
+ };
- function generateStreamKey () {
+ function generateStreamKey() {
let key = '';
- for (let i = 0; i < 3; i+=1) {
+ for (let i = 0; i < 3; i += 1) {
key += Math.random().toString(36).substring(2);
}
handleFieldChange({ fieldName: 'streamKey', value: key });
}
- function copyStreamKey () {
- navigator.clipboard.writeText(formDataValues.streamKey)
- .then(() => {
- setCopyVisible(true);
- setTimeout(() => setCopyVisible(false), COPY_TOOLTIP_TIMEOUT);
- });
+ function copyStreamKey() {
+ navigator.clipboard.writeText(formDataValues.streamKey).then(() => {
+ setCopyVisible(true);
+ setTimeout(() => setCopyVisible(false), COPY_TOOLTIP_TIMEOUT);
+ });
}
- return (
+ return (
-
- Save this key somewhere safe,
- you will need it to stream or login to the admin dashboard!
+
+ Save this key somewhere safe, you will need it to stream or login to the admin
+ dashboard!
-
- }
- size="small"
- onClick={copyStreamKey}
- />
+
+ } size="small" onClick={copyStreamKey} />
- }
- size="small"
- onClick={generateStreamKey}
- />
+ } size="small" onClick={generateStreamKey} />
-
- );
+
+ );
}
-
-
diff --git a/web/pages/components/config/edit-social-links.tsx b/web/pages/components/config/edit-social-links.tsx
index bdec63965..2f918a313 100644
--- a/web/pages/components/config/edit-social-links.tsx
+++ b/web/pages/components/config/edit-social-links.tsx
@@ -5,7 +5,14 @@ import { DeleteOutlined } from '@ant-design/icons';
import SocialDropdown from './social-icons-dropdown';
import { fetchData, NEXT_PUBLIC_API_HOST, SOCIAL_PLATFORMS_LIST } from '../../../utils/apis';
import { ServerStatusContext } from '../../../utils/server-status-context';
-import { API_SOCIAL_HANDLES, postConfigUpdateToAPI, RESET_TIMEOUT, SUCCESS_STATES, DEFAULT_SOCIAL_HANDLE, OTHER_SOCIAL_HANDLE_OPTION } from './constants';
+import {
+ API_SOCIAL_HANDLES,
+ postConfigUpdateToAPI,
+ RESET_TIMEOUT,
+ SUCCESS_STATES,
+ DEFAULT_SOCIAL_HANDLE,
+ OTHER_SOCIAL_HANDLE_OPTION,
+} from './constants';
import { SocialHandle } from '../../../types/config-section';
import { isValidUrl } from '../../../utils/urls';
@@ -21,7 +28,7 @@ export default function EditSocialLinks() {
const [displayOther, setDisplayOther] = useState(false);
const [modalProcessing, setModalProcessing] = useState(false);
const [editId, setEditId] = useState(-1);
-
+
// current data inside modal
const [modalDataState, setModalDataState] = useState(DEFAULT_SOCIAL_HANDLE);
@@ -44,15 +51,15 @@ export default function EditSocialLinks() {
...result[item],
}));
setAvailableIconsList(list);
-
} catch (error) {
- console.log(error)
+ console.log(error);
// do nothing
}
};
- const selectedOther = modalDataState.platform !== '' && !availableIconsList.find(item => item.key === modalDataState.platform);
-
+ const selectedOther =
+ modalDataState.platform !== '' &&
+ !availableIconsList.find(item => item.key === modalDataState.platform);
useEffect(() => {
getAvailableIcons();
@@ -64,7 +71,6 @@ export default function EditSocialLinks() {
}
}, [instanceDetails]);
-
const resetStates = () => {
setSubmitStatus(null);
setSubmitStatusMessage('');
@@ -76,7 +82,7 @@ export default function EditSocialLinks() {
setEditId(-1);
setDisplayOther(false);
setModalProcessing(false);
- setModalDataState({...DEFAULT_SOCIAL_HANDLE});
+ setModalDataState({ ...DEFAULT_SOCIAL_HANDLE });
};
const handleModalCancel = () => {
@@ -106,7 +112,6 @@ export default function EditSocialLinks() {
const { value } = event.target;
updateModalState('url', value);
};
-
// posts all the variants at once as an array obj
const postUpdateToAPI = async (postValue: any) => {
@@ -114,7 +119,11 @@ export default function EditSocialLinks() {
apiPath: API_SOCIAL_HANDLES,
data: { value: postValue },
onSuccess: () => {
- setFieldInConfigState({ fieldName: 'socialHandles', value: postValue, path: 'instanceDetails' });
+ setFieldInConfigState({
+ fieldName: 'socialHandles',
+ value: postValue,
+ path: 'instanceDetails',
+ });
// close modal
setModalProcessing(false);
@@ -132,15 +141,12 @@ export default function EditSocialLinks() {
});
};
-
// on Ok, send all of dataState to api
// show loading
// close modal when api is done
const handleModalOk = () => {
- setModalProcessing(true);
- const postData = currentSocialHandles.length ? [
- ...currentSocialHandles,
- ]: [];
+ setModalProcessing(true);
+ const postData = currentSocialHandles.length ? [...currentSocialHandles] : [];
if (editId === -1) {
postData.push(modalDataState);
} else {
@@ -150,23 +156,21 @@ export default function EditSocialLinks() {
};
const handleDeleteItem = index => {
- const postData = [
- ...currentSocialHandles,
- ];
+ const postData = [...currentSocialHandles];
postData.splice(index, 1);
postUpdateToAPI(postData);
};
- const socialHandlesColumns: ColumnsType = [
+ const socialHandlesColumns: ColumnsType = [
{
- title: "#",
- dataIndex: "key",
- key: "key"
+ title: '#',
+ dataIndex: 'key',
+ key: 'key',
},
{
- title: "Platform",
- dataIndex: "platform",
- key: "platform",
+ title: 'Platform',
+ dataIndex: 'platform',
+ key: 'platform',
render: (platform: string) => {
const platformInfo = availableIconsList.find(item => item.key === platform);
if (!platformInfo) {
@@ -185,9 +189,9 @@ export default function EditSocialLinks() {
},
{
- title: "Url Link",
- dataIndex: "url",
- key: "url",
+ title: 'Url Link',
+ dataIndex: 'url',
+ key: 'url',
},
{
title: '',
@@ -196,28 +200,31 @@ export default function EditSocialLinks() {
render: (data, record, index) => {
return (
- {
- setEditId(index);
- setModalDataState({...currentSocialHandles[index]});
- setDisplayModal(true);
- }}>
+ {
+ setEditId(index);
+ setModalDataState({ ...currentSocialHandles[index] });
+ setDisplayModal(true);
+ }}
+ >
Edit
}
size="small"
- onClick={() => handleDeleteItem(index)}
- />
+ onClick={() => handleDeleteItem(index)}
+ />
- )},
+ );
},
- ];
-
- const {
- icon: newStatusIcon = null,
- message: newStatusMessage = '',
- } = SUCCESS_STATES[submitStatus] || {};
+ },
+ ];
+
+ const { icon: newStatusIcon = null, message: newStatusMessage = '' } =
+ SUCCESS_STATES[submitStatus] || {};
const statusMessage = (
{newStatusIcon} {newStatusMessage} {submitStatusMessage}
@@ -225,9 +232,8 @@ export default function EditSocialLinks() {
);
const okButtonProps = {
- disabled: !isValidUrl(modalDataState.url)
-};
-
+ disabled: !isValidUrl(modalDataState.url),
+ };
return (
@@ -258,21 +264,17 @@ export default function EditSocialLinks() {
selectedOption={selectedOther ? OTHER_SOCIAL_HANDLE_OPTION : modalDataState.platform}
onSelected={handleDropdownSelect}
/>
- {
- displayOther
- ? (
- <>
-
-
- >
- ) : null
- }
-
-
+ {displayOther ? (
+ <>
+
+
+ >
+ ) : null}
+
URL
-
{statusMessage}
- {
+ {
resetModal();
setDisplayModal(true);
- }}>
+ }}
+ >
Add a new social link
- );
+ );
}
-
diff --git a/web/pages/components/config/edit-tags.tsx b/web/pages/components/config/edit-tags.tsx
index d1382bfef..cc978ef17 100644
--- a/web/pages/components/config/edit-tags.tsx
+++ b/web/pages/components/config/edit-tags.tsx
@@ -6,7 +6,14 @@ import { ServerStatusContext } from '../../../utils/server-status-context';
import { FIELD_PROPS_TAGS, RESET_TIMEOUT, postConfigUpdateToAPI } from './constants';
import TextField from './form-textfield';
import { UpdateArgs } from '../../../types/config-section';
-import { createInputStatus, StatusState, STATUS_ERROR, STATUS_PROCESSING, STATUS_SUCCESS, STATUS_WARNING } from '../../../utils/input-statuses';
+import {
+ createInputStatus,
+ StatusState,
+ STATUS_ERROR,
+ STATUS_PROCESSING,
+ STATUS_SUCCESS,
+ STATUS_WARNING,
+} from '../../../utils/input-statuses';
const { Title } = Typography;
@@ -21,19 +28,14 @@ export default function EditInstanceTags() {
const { instanceDetails } = serverConfig;
const { tags = [] } = instanceDetails;
- const {
- apiPath,
- maxLength,
- placeholder,
- configPath,
- } = FIELD_PROPS_TAGS;
+ const { apiPath, maxLength, placeholder, configPath } = FIELD_PROPS_TAGS;
let resetTimer = null;
useEffect(() => {
return () => {
clearTimeout(resetTimer);
- }
+ };
}, []);
const resetStates = () => {
@@ -42,7 +44,7 @@ export default function EditInstanceTags() {
setFieldStatus(null);
resetTimer = null;
clearTimeout(resetTimer);
- }
+ };
// posts all the tags at once as an array obj
const postUpdateToAPI = async (postValue: any) => {
@@ -89,7 +91,7 @@ export default function EditInstanceTags() {
// setSubmitStatusMessage('Please enter a tag');
return;
- }
+ }
if (tags.some(tag => tag.toLowerCase() === newTag.toLowerCase())) {
setFieldStatus(createInputStatus(STATUS_WARNING, 'This tag is already used!'));
@@ -106,7 +108,7 @@ export default function EditInstanceTags() {
const updatedTags = [...tags];
updatedTags.splice(index, 1);
postUpdateToAPI(updatedTags);
- }
+ };
// const {
// icon: newStatusIcon = null,
@@ -115,7 +117,6 @@ export default function EditInstanceTags() {
return (
-
Add Tags
This is a great way to categorize your Owncast server on the Directory!
@@ -125,7 +126,9 @@ export default function EditInstanceTags() {
handleDeleteTag(index);
};
return (
-
{tag}
+
+ {tag}
+
);
})}
diff --git a/web/pages/components/config/form-textfield-with-submit.tsx b/web/pages/components/config/form-textfield-with-submit.tsx
index 5044225b3..050381bc4 100644
--- a/web/pages/components/config/form-textfield-with-submit.tsx
+++ b/web/pages/components/config/form-textfield-with-submit.tsx
@@ -5,7 +5,13 @@ import { RESET_TIMEOUT, postConfigUpdateToAPI } from './constants';
import { ServerStatusContext } from '../../../utils/server-status-context';
import TextField, { TextFieldProps } from './form-textfield';
-import { createInputStatus, StatusState, STATUS_ERROR, STATUS_PROCESSING, STATUS_SUCCESS } from '../../../utils/input-statuses';
+import {
+ createInputStatus,
+ StatusState,
+ STATUS_ERROR,
+ STATUS_PROCESSING,
+ STATUS_SUCCESS,
+} from '../../../utils/input-statuses';
import { UpdateArgs } from '../../../types/config-section';
export const TEXTFIELD_TYPE_TEXT = 'default';
@@ -114,11 +120,11 @@ export default function TextFieldWithSubmit(props: TextFieldWithSubmitProps) {
onSubmit();
}
}
- }
+ };
return (
-
- { hasChanged ? Update : null }
+ {hasChanged ? (
+
+ Update
+
+ ) : null}
- );
+ );
}
TextFieldWithSubmit.defaultProps = {
diff --git a/web/pages/components/config/form-textfield.tsx b/web/pages/components/config/form-textfield.tsx
index cdb6e6ca1..dd78123bd 100644
--- a/web/pages/components/config/form-textfield.tsx
+++ b/web/pages/components/config/form-textfield.tsx
@@ -12,7 +12,7 @@ export const TEXTFIELD_TYPE_URL = 'url';
export interface TextFieldProps {
fieldName: string;
-
+
onSubmit?: () => void;
onPressEnter?: () => void;
@@ -30,7 +30,6 @@ export interface TextFieldProps {
onChange?: FieldUpdaterFunc;
}
-
export default function TextField(props: TextFieldProps) {
const {
className,
@@ -70,11 +69,14 @@ export default function TextField(props: TextFieldProps) {
if (onPressEnter) {
onPressEnter();
}
- }
-
+ };
// display the appropriate Ant text field
- let Field = Input as typeof Input | typeof InputNumber | typeof Input.TextArea | typeof Input.Password;
+ let Field = Input as
+ | typeof Input
+ | typeof InputNumber
+ | typeof Input.TextArea
+ | typeof Input.Password;
let fieldProps = {};
if (type === TEXTFIELD_TYPE_TEXTAREA) {
Field = Input.TextArea;
@@ -91,12 +93,11 @@ export default function TextField(props: TextFieldProps) {
fieldProps = {
type: 'number',
min: 1,
- max: (10**maxLength) - 1,
+ max: 10 ** maxLength - 1,
onKeyDown: (e: React.KeyboardEvent) => {
- if (e.target.value.length > maxLength - 1 )
- e.preventDefault();
+ if (e.target.value.length > maxLength - 1) e.preventDefault();
return false;
- }
+ },
};
} else if (type === TEXTFIELD_TYPE_URL) {
fieldProps = {
@@ -110,8 +111,10 @@ export default function TextField(props: TextFieldProps) {
return (
- { required ?
* : null }
-
{label}
+ {required ?
* : null}
+
+ {label}
+
- { status ? statusMessage : null }
- { status ? statusIcon : null }
+ {status ? statusMessage : null}
+ {status ? statusIcon : null}
- );
+ );
}
TextField.defaultProps = {
diff --git a/web/pages/components/config/form-toggleswitch-with-submit.tsx b/web/pages/components/config/form-toggleswitch-with-submit.tsx
index bcf5427b5..f0710fa3f 100644
--- a/web/pages/components/config/form-toggleswitch-with-submit.tsx
+++ b/web/pages/components/config/form-toggleswitch-with-submit.tsx
@@ -26,22 +26,14 @@ export default function ToggleSwitch(props: ToggleSwitchProps) {
const serverStatusData = useContext(ServerStatusContext);
const { setFieldInConfigState } = serverStatusData || {};
-
- const {
- apiPath,
- checked,
- configPath = '',
- disabled = false,
- fieldName,
- label,
- tip,
- } = props;
+
+ const { apiPath, checked, configPath = '', disabled = false, fieldName, label, tip } = props;
const resetStates = () => {
setSubmitStatus('');
clearTimeout(resetTimer);
resetTimer = null;
- }
+ };
const handleChange = async (isChecked: boolean) => {
setSubmitStatus('validating');
@@ -58,12 +50,10 @@ export default function ToggleSwitch(props: ToggleSwitchProps) {
},
});
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
- }
+ };
- const {
- icon: newStatusIcon = null,
- message: newStatusMessage = '',
- } = SUCCESS_STATES[submitStatus] || {};
+ const { icon: newStatusIcon = null, message: newStatusMessage = '' } =
+ SUCCESS_STATES[submitStatus] || {};
return (
@@ -74,18 +64,20 @@ export default function ToggleSwitch(props: ToggleSwitchProps) {
onChange={handleChange}
defaultChecked={checked}
checked={checked}
- checkedChildren="ON"
+ checkedChildren="ON"
unCheckedChildren="OFF"
disabled={disabled}
/>
- {label}
+
+ {label}
+
{submitStatus}
{newStatusIcon} {newStatusMessage} {submitStatusMessage}
- );
+ );
}
ToggleSwitch.defaultProps = {
diff --git a/web/pages/components/config/social-icons-dropdown.tsx b/web/pages/components/config/social-icons-dropdown.tsx
index 14bf6ec0f..fac0c5374 100644
--- a/web/pages/components/config/social-icons-dropdown.tsx
+++ b/web/pages/components/config/social-icons-dropdown.tsx
@@ -1,10 +1,9 @@
import React from 'react';
-import { Select } from "antd";
-import { SocialHandleDropdownItem } from "../../../types/config-section";
+import { Select } from 'antd';
+import { SocialHandleDropdownItem } from '../../../types/config-section';
import { NEXT_PUBLIC_API_HOST } from '../../../utils/apis';
import { OTHER_SOCIAL_HANDLE_OPTION } from './constants';
-
interface DropdownProps {
iconList: SocialHandleDropdownItem[];
selectedOption: string;
@@ -12,7 +11,6 @@ interface DropdownProps {
}
export default function SocialDropdown({ iconList, selectedOption, onSelected }: DropdownProps) {
-
const handleSelected = value => {
if (onSelected) {
onSelected(value);
@@ -21,9 +19,16 @@ export default function SocialDropdown({ iconList, selectedOption, onSelected }:
const inititalSelected = selectedOption === '' ? null : selectedOption;
return (
-
If you are looking for a platform name not on this list, please select Other and type in your own name. A logo will not be provided.
-
If you DO have a logo, drop it in to the /webroot/img/platformicons
directory and update the /socialHandle.go
list. Then restart the server and it will show up in the list.
-
+
+ If you are looking for a platform name not on this list, please select Other and type in
+ your own name. A logo will not be provided.
+
+
+ If you DO have a logo, drop it in to the /webroot/img/platformicons
directory
+ and update the /socialHandle.go
list. Then restart the server and it will show
+ up in the list.
+
+
{iconList.map(item => {
- const { platform, icon, key } = item;
+ const { platform, icon, key } = item;
return (
@@ -42,9 +47,12 @@ export default function SocialDropdown({ iconList, selectedOption, onSelected }:
{platform}
);
- })
- }
-
+ })}
+
Other...
diff --git a/web/pages/components/config/video-latency.tsx b/web/pages/components/config/video-latency.tsx
index f451b24ed..216c2a77d 100644
--- a/web/pages/components/config/video-latency.tsx
+++ b/web/pages/components/config/video-latency.tsx
@@ -1,7 +1,12 @@
import React, { useContext, useState, useEffect } from 'react';
-import { Typography, Slider, } from 'antd';
+import { Typography, Slider } from 'antd';
import { ServerStatusContext } from '../../../utils/server-status-context';
-import { API_VIDEO_SEGMENTS, SUCCESS_STATES, RESET_TIMEOUT,postConfigUpdateToAPI } from './constants';
+import {
+ API_VIDEO_SEGMENTS,
+ SUCCESS_STATES,
+ RESET_TIMEOUT,
+ postConfigUpdateToAPI,
+} from './constants';
const { Title } = Typography;
@@ -28,9 +33,7 @@ interface SegmentToolTipProps {
}
function SegmentToolTip({ value }: SegmentToolTipProps) {
- return (
-
{value}
- );
+ return
{value} ;
}
export default function VideoLatency() {
@@ -57,8 +60,8 @@ export default function VideoLatency() {
setSubmitStatusMessage('');
resetTimer = null;
clearTimeout(resetTimer);
- }
-
+ };
+
// posts all the variants at once as an array obj
const postUpdateToAPI = async (postValue: any) => {
await postConfigUpdateToAPI({
@@ -66,9 +69,9 @@ export default function VideoLatency() {
data: { value: postValue },
onSuccess: () => {
setFieldInConfigState({
- fieldName: 'latencyLevel',
- value: postValue,
- path: 'videoSettings'
+ fieldName: 'latencyLevel',
+ value: postValue,
+ path: 'videoSettings',
});
setSubmitStatus('success');
@@ -83,17 +86,15 @@ export default function VideoLatency() {
});
};
- const {
- icon: newStatusIcon = null,
- message: newStatusMessage = '',
- } = SUCCESS_STATES[submitStatus] || {};
-
+ const { icon: newStatusIcon = null, message: newStatusMessage = '' } =
+ SUCCESS_STATES[submitStatus] || {};
+
const statusMessage = (
{newStatusIcon} {newStatusMessage} {submitStatusMessage}
);
-
+
const handleChange = value => {
postUpdateToAPI(value);
};
@@ -102,11 +103,13 @@ export default function VideoLatency() {
Latency Buffer
- There are trade-offs when cosidering video latency and reliability. Blah blah .. better wording here needed.
+ There are trade-offs when cosidering video latency and reliability. Blah blah .. better
+ wording here needed.
-
+
+
- }
onChange={handleChange}
@@ -120,4 +123,4 @@ export default function VideoLatency() {
{statusMessage}
);
-}
\ No newline at end of file
+}
diff --git a/web/pages/components/config/video-variant-form.tsx b/web/pages/components/config/video-variant-form.tsx
index e80943d1d..c5a7020bf 100644
--- a/web/pages/components/config/video-variant-form.tsx
+++ b/web/pages/components/config/video-variant-form.tsx
@@ -32,13 +32,13 @@ const VIDEO_VARIANT_DEFAULTS = {
defaultValue: 800,
unit: 'kbps',
incrementBy: 100,
- tip: 'nothing to see here'
+ tip: 'nothing to see here',
},
videoPassthrough: {
- tip: 'If No is selected, then you should set your desired Video Bitrate.'
+ tip: 'If No is selected, then you should set your desired Video Bitrate.',
},
audioPassthrough: {
- tip: 'If No is selected, then you should set your desired Audio Bitrate.'
+ tip: 'If No is selected, then you should set your desired Audio Bitrate.',
},
};
@@ -47,8 +47,10 @@ interface VideoVariantFormProps {
onUpdateField: FieldUpdaterFunc;
}
-export default function VideoVariantForm({ dataState = DEFAULT_VARIANT_STATE, onUpdateField }: VideoVariantFormProps) {
-
+export default function VideoVariantForm({
+ dataState = DEFAULT_VARIANT_STATE,
+ onUpdateField,
+}: VideoVariantFormProps) {
const handleFramerateChange = (value: number) => {
onUpdateField({ fieldName: 'framerate', value });
};
@@ -65,8 +67,8 @@ export default function VideoVariantForm({ dataState = DEFAULT_VARIANT_STATE, on
onUpdateField({ fieldName: 'videoPassthrough', value });
};
const handleVideoCpuUsageLevelChange = (value: number) => {
- onUpdateField({ fieldName: 'cpuUsageLevel', value })
- }
+ onUpdateField({ fieldName: 'cpuUsageLevel', value });
+ };
const framerateDefaults = VIDEO_VARIANT_DEFAULTS.framerate;
const framerateMin = framerateDefaults.min;
@@ -91,24 +93,27 @@ export default function VideoVariantForm({ dataState = DEFAULT_VARIANT_STATE, on
return (
- Say a thing here about how this all works.
-
- Read more
here .
-
+ Say a thing here about how this all works. Read more{' '}
+
here .
+
+
{/* ENCODER PRESET FIELD */}
-
- {selectedPresetNote ? {selectedPresetNote} : null }
+
+ {selectedPresetNote ? (
+ {selectedPresetNote}
+ ) : null}
-
-
{/* VIDEO PASSTHROUGH FIELD */}
-
+
@@ -147,19 +152,20 @@ export default function VideoVariantForm({ dataState = DEFAULT_VARIANT_STATE, on
[videoBRMax]: `${videoBRMax} ${videoBRUnit}`,
}}
/>
- {selectedVideoBRnote ? {selectedVideoBRnote} : null }
-
+ {selectedVideoBRnote ? (
+ {selectedVideoBRnote}
+ ) : null}
+
+
+
+
-
-
-
- Touch if you dare.
-
+ Touch if you dare.
{/* FRAME RATE FIELD */}
@@ -182,8 +188,9 @@ export default function VideoVariantForm({ dataState = DEFAULT_VARIANT_STATE, on
[framerateMax]: `${framerateMax} ${framerateUnit}`,
}}
/>
- {selectedFramerateNote ? {selectedFramerateNote} : null }
-
+ {selectedFramerateNote ? (
+ {selectedFramerateNote}
+ ) : null}
@@ -203,7 +210,7 @@ export default function VideoVariantForm({ dataState = DEFAULT_VARIANT_STATE, on
checkedChildren="Yes"
unCheckedChildren="No"
/>
- {dataState.audioPassthrough ?
Same as source : null}
+ {dataState.audioPassthrough ?
Same as source : null}
@@ -230,13 +237,13 @@ export default function VideoVariantForm({ dataState = DEFAULT_VARIANT_STATE, on
}}
/>
- {selectedAudioBRnote ?
{selectedAudioBRnote} : null }
+ {selectedAudioBRnote ? (
+
{selectedAudioBRnote}
+ ) : null}
-
);
-
-}
\ No newline at end of file
+}
diff --git a/web/pages/components/config/video-variants-table.tsx b/web/pages/components/config/video-variants-table.tsx
index cca815805..8a396aa8c 100644
--- a/web/pages/components/config/video-variants-table.tsx
+++ b/web/pages/components/config/video-variants-table.tsx
@@ -8,7 +8,13 @@ import { DeleteOutlined } from '@ant-design/icons';
import { ServerStatusContext } from '../../../utils/server-status-context';
import { UpdateArgs, VideoVariant } from '../../../types/config-section';
import VideoVariantForm from './video-variant-form';
-import { API_VIDEO_VARIANTS, DEFAULT_VARIANT_STATE, SUCCESS_STATES, RESET_TIMEOUT, postConfigUpdateToAPI } from './constants';
+import {
+ API_VIDEO_VARIANTS,
+ DEFAULT_VARIANT_STATE,
+ SUCCESS_STATES,
+ RESET_TIMEOUT,
+ postConfigUpdateToAPI,
+} from './constants';
const { Title } = Typography;
@@ -19,7 +25,7 @@ export default function CurrentVariantsTable() {
// current data inside modal
const [modalDataState, setModalDataState] = useState(DEFAULT_VARIANT_STATE);
-
+
const [submitStatus, setSubmitStatus] = useState(null);
const [submitStatusMessage, setSubmitStatusMessage] = useState('');
@@ -39,13 +45,13 @@ export default function CurrentVariantsTable() {
setSubmitStatusMessage('');
resetTimer = null;
clearTimeout(resetTimer);
- }
+ };
const handleModalCancel = () => {
setDisplayModal(false);
setEditId(-1);
setModalDataState(DEFAULT_VARIANT_STATE);
- }
+ };
// posts all the variants at once as an array obj
const postUpdateToAPI = async (postValue: any) => {
@@ -53,7 +59,11 @@ export default function CurrentVariantsTable() {
apiPath: API_VIDEO_VARIANTS,
data: { value: postValue },
onSuccess: () => {
- setFieldInConfigState({ fieldName: 'videoQualityVariants', value: postValue, path: 'videoSettings' });
+ setFieldInConfigState({
+ fieldName: 'videoQualityVariants',
+ value: postValue,
+ path: 'videoSettings',
+ });
// close modal
setModalProcessing(false);
@@ -76,10 +86,8 @@ export default function CurrentVariantsTable() {
// close modal when api is done
const handleModalOk = () => {
setModalProcessing(true);
-
- const postData = [
- ...videoQualityVariants,
- ];
+
+ const postData = [...videoQualityVariants];
if (editId === -1) {
postData.push(modalDataState);
} else {
@@ -89,11 +97,9 @@ export default function CurrentVariantsTable() {
};
const handleDeleteVariant = index => {
- const postData = [
- ...videoQualityVariants,
- ];
+ const postData = [...videoQualityVariants];
postData.splice(index, 1);
- postUpdateToAPI(postData)
+ postUpdateToAPI(postData);
};
const handleUpdateField = ({ fieldName, value }: UpdateArgs) => {
@@ -101,41 +107,37 @@ export default function CurrentVariantsTable() {
...modalDataState,
[fieldName]: value,
});
- }
+ };
+
+ const { icon: newStatusIcon = null, message: newStatusMessage = '' } =
+ SUCCESS_STATES[submitStatus] || {};
- const {
- icon: newStatusIcon = null,
- message: newStatusMessage = '',
- } = SUCCESS_STATES[submitStatus] || {};
-
const cpuUsageLevelLabelMap = {
1: 'lowest',
2: 'low',
3: 'medium',
4: 'high',
- 5: 'highest'
+ 5: 'highest',
};
- const videoQualityColumns: ColumnsType = [
+ const videoQualityColumns: ColumnsType = [
{
- title: "#",
- dataIndex: "key",
- key: "key"
+ title: '#',
+ dataIndex: 'key',
+ key: 'key',
},
{
- title: "Video bitrate",
- dataIndex: "videoBitrate",
- key: "videoBitrate",
- render: (bitrate: number) =>
- !bitrate ? "Same as source" : `${bitrate} kbps`,
+ title: 'Video bitrate',
+ dataIndex: 'videoBitrate',
+ key: 'videoBitrate',
+ render: (bitrate: number) => (!bitrate ? 'Same as source' : `${bitrate} kbps`),
},
{
- title: "CPU Usage",
- dataIndex: "cpuUsageLevel",
- key: "cpuUsageLevel",
- render: (level: string) =>
- !level ? "n/a" : cpuUsageLevelLabelMap[level],
+ title: 'CPU Usage',
+ dataIndex: 'cpuUsageLevel',
+ key: 'cpuUsageLevel',
+ render: (level: string) => (!level ? 'n/a' : cpuUsageLevelLabelMap[level]),
},
{
title: '',
@@ -145,11 +147,15 @@ export default function CurrentVariantsTable() {
const index = data.key - 1;
return (
- {
- setEditId(index);
- setModalDataState(videoQualityVariants[index]);
- setDisplayModal(true);
- }}>
+ {
+ setEditId(index);
+ setModalDataState(videoQualityVariants[index]);
+ setDisplayModal(true);
+ }}
+ >
Edit
{
handleDeleteVariant(index);
}}
- />
+ />
- )},
+ );
},
- ];
+ },
+ ];
const statusMessage = (
@@ -172,12 +179,15 @@ export default function CurrentVariantsTable() {
);
- const videoQualityVariantData = videoQualityVariants.map((variant, index) => ({ key: index + 1, ...variant }));
+ const videoQualityVariantData = videoQualityVariants.map((variant, index) => ({
+ key: index + 1,
+ ...variant,
+ }));
return (
<>
Current Variants
-
+
{statusMessage}
-
-
+
+
{statusMessage}
- {
+ {
setEditId(-1);
setModalDataState(DEFAULT_VARIANT_STATE);
setDisplayModal(true);
- }}>
+ }}
+ >
Add a new variant
-
>
);
-}
\ No newline at end of file
+}
diff --git a/web/pages/config-page-content.tsx b/web/pages/config-page-content.tsx
index d676d1198..88b6137dd 100644
--- a/web/pages/config-page-content.tsx
+++ b/web/pages/config-page-content.tsx
@@ -1,11 +1,16 @@
import React, { useState, useEffect, useContext } from 'react';
-import { Typography, Button } from "antd";
+import { Typography, Button } from 'antd';
import { FormItemProps } from 'antd/lib/form';
import dynamic from 'next/dynamic';
import MarkdownIt from 'markdown-it';
import { ServerStatusContext } from '../utils/server-status-context';
-import { postConfigUpdateToAPI, RESET_TIMEOUT, SUCCESS_STATES, API_CUSTOM_CONTENT} from './components/config/constants';
+import {
+ postConfigUpdateToAPI,
+ RESET_TIMEOUT,
+ SUCCESS_STATES,
+ API_CUSTOM_CONTENT,
+} from './components/config/constants';
import 'react-markdown-editor-lite/lib/index.css';
@@ -14,91 +19,98 @@ const { Title } = Typography;
const mdParser = new MarkdownIt(/* Markdown-it options */);
const MdEditor = dynamic(() => import('react-markdown-editor-lite'), {
- ssr: false,
+ ssr: false,
});
export default function PageContentEditor() {
- const [content, setContent] = useState('');
- const [submitStatus, setSubmitStatus] = useState('');
- const [submitStatusMessage, setSubmitStatusMessage] = useState('');
- const [hasChanged, setHasChanged] = useState(false);
-
- const serverStatusData = useContext(ServerStatusContext);
- const { serverConfig, setFieldInConfigState } = serverStatusData || {};
-
- const { instanceDetails } = serverConfig;
- const { extraPageContent: initialContent } = instanceDetails;
-
+ const [content, setContent] = useState('');
+ const [submitStatus, setSubmitStatus] = useState('');
+ const [submitStatusMessage, setSubmitStatusMessage] = useState('');
+ const [hasChanged, setHasChanged] = useState(false);
- let resetTimer = null;
+ const serverStatusData = useContext(ServerStatusContext);
+ const { serverConfig, setFieldInConfigState } = serverStatusData || {};
- function handleEditorChange({ text }) {
- setContent(text);
- if (text !== initialContent && !hasChanged) {
- setHasChanged(true);
- } else if (text === initialContent && hasChanged) {
- setHasChanged(false);
- }
- }
+ const { instanceDetails } = serverConfig;
+ const { extraPageContent: initialContent } = instanceDetails;
- // Clear out any validation states and messaging
- const resetStates = () => {
- setSubmitStatus('');
+ let resetTimer = null;
+
+ function handleEditorChange({ text }) {
+ setContent(text);
+ if (text !== initialContent && !hasChanged) {
+ setHasChanged(true);
+ } else if (text === initialContent && hasChanged) {
setHasChanged(false);
- clearTimeout(resetTimer);
- resetTimer = null;
- };
-
- // posts all the tags at once as an array obj
- async function handleSave() {
- setSubmitStatus('validating');
- await postConfigUpdateToAPI({
- apiPath: API_CUSTOM_CONTENT,
- data: { value: content },
- onSuccess: () => {
- setFieldInConfigState({ fieldName: 'extraPageContent', value: content, path: 'instanceDetails' });
- setSubmitStatus('success');
- },
- onError: (message: string) => {
- setSubmitStatus('error');
- setSubmitStatusMessage(`There was an error: ${message}`);
- },
- });
- resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
}
-
- useEffect(() => {
- setContent(initialContent);
- }, [instanceDetails]);
+ }
- const {
- icon: newStatusIcon = null,
- message: newStatusMessage = '',
- } = SUCCESS_STATES[submitStatus] || {};
+ // Clear out any validation states and messaging
+ const resetStates = () => {
+ setSubmitStatus('');
+ setHasChanged(false);
+ clearTimeout(resetTimer);
+ resetTimer = null;
+ };
+ // posts all the tags at once as an array obj
+ async function handleSave() {
+ setSubmitStatus('validating');
+ await postConfigUpdateToAPI({
+ apiPath: API_CUSTOM_CONTENT,
+ data: { value: content },
+ onSuccess: () => {
+ setFieldInConfigState({
+ fieldName: 'extraPageContent',
+ value: content,
+ path: 'instanceDetails',
+ });
+ setSubmitStatus('success');
+ },
+ onError: (message: string) => {
+ setSubmitStatus('error');
+ setSubmitStatusMessage(`There was an error: ${message}`);
+ },
+ });
+ resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
+ }
- return (
-
-
Edit custom content
+ useEffect(() => {
+ setContent(initialContent);
+ }, [instanceDetails]);
-
Add some content about your site with the Markdown editor below. This content shows up at the bottom half of your Owncast page.
+ const { icon: newStatusIcon = null, message: newStatusMessage = '' } =
+ SUCCESS_STATES[submitStatus] || {};
-
mdParser.render(c)}
- onChange={handleEditorChange}
- config={{
- htmlClass: 'markdown-editor-preview-pane',
- markdownClass: 'markdown-editor-pane',
- }}
- />
-
- { hasChanged ?
Save : null }
-
- {newStatusIcon} {newStatusMessage} {submitStatusMessage}
-
+ return (
+
+
Edit custom content
+
+
+ Add some content about your site with the Markdown editor below. This content shows up at
+ the bottom half of your Owncast page.
+
+
+
mdParser.render(c)}
+ onChange={handleEditorChange}
+ config={{
+ htmlClass: 'markdown-editor-preview-pane',
+ markdownClass: 'markdown-editor-pane',
+ }}
+ />
+
+ {hasChanged ? (
+
+ Save
+
+ ) : null}
+
+ {newStatusIcon} {newStatusMessage} {submitStatusMessage}
- );
+
+ );
}
diff --git a/web/pages/config-public-details.tsx b/web/pages/config-public-details.tsx
index a8560ce3d..fb965301a 100644
--- a/web/pages/config-public-details.tsx
+++ b/web/pages/config-public-details.tsx
@@ -15,15 +15,12 @@ export default function PublicFacingDetails() {
+
>
- );
+ );
}
-
-
diff --git a/web/pages/config-server-details.tsx b/web/pages/config-server-details.tsx
index f01571fff..72c7d92c8 100644
--- a/web/pages/config-server-details.tsx
+++ b/web/pages/config-server-details.tsx
@@ -11,10 +11,7 @@ export default function ConfigServerDetails() {
-
-
+
- );
+ );
}
-
-
diff --git a/web/pages/config-social-items.tsx b/web/pages/config-social-items.tsx
index 6161ba5f8..05b5c6055 100644
--- a/web/pages/config-social-items.tsx
+++ b/web/pages/config-social-items.tsx
@@ -11,10 +11,9 @@ export default function ConfigSocialThings() {
Social Items
-
+
- );
+ );
}
-
diff --git a/web/pages/config-video.tsx b/web/pages/config-video.tsx
index 4222295e4..c5102d636 100644
--- a/web/pages/config-video.tsx
+++ b/web/pages/config-video.tsx
@@ -10,14 +10,17 @@ export default function ConfigVideoSettings() {
return (
- );
+ );
}
-
diff --git a/web/pages/help.tsx b/web/pages/help.tsx
index f21d9b193..18d9083d0 100644
--- a/web/pages/help.tsx
+++ b/web/pages/help.tsx
@@ -1,167 +1,210 @@
-import { Button, Card, Col, Divider, Result, Row } from 'antd'
-import Meta from 'antd/lib/card/Meta'
-import Title from 'antd/lib/typography/Title'
+import { Button, Card, Col, Divider, Result, Row } from 'antd';
+import Meta from 'antd/lib/card/Meta';
+import Title from 'antd/lib/typography/Title';
import {
- AlertOutlined,
- ApiTwoTone,
- BookOutlined,
- BugTwoTone,
- CameraTwoTone,
- DatabaseTwoTone,
- EditTwoTone,
- Html5TwoTone,
- LinkOutlined,
- QuestionCircleTwoTone,
- SettingTwoTone,
- SlidersTwoTone,
-} from '@ant-design/icons'
-import React from 'react'
+ AlertOutlined,
+ ApiTwoTone,
+ BookOutlined,
+ BugTwoTone,
+ CameraTwoTone,
+ DatabaseTwoTone,
+ EditTwoTone,
+ Html5TwoTone,
+ LinkOutlined,
+ QuestionCircleTwoTone,
+ SettingTwoTone,
+ SlidersTwoTone,
+} from '@ant-design/icons';
+import React from 'react';
-interface Props { }
+interface Props {}
export default function Help(props: Props) {
- const questions = [
- {
- icon: ,
- title: "I want to configure my owncast instance",
- content: (
-
- )
- },
- {
- icon: ,
- title: "I need help configuring my broadcasting software",
- content: (
-
- )
- },
- {
- icon: ,
- title: "I want to embed my stream into another site",
- content: (
-
- )
- },
- {
- icon: ,
- title: "I want to customize my website",
- content: (
-
- )
- },
- {
- icon: ,
- title: "I want to tweak my encoding quality or performance",
- content: (
-
- )
- },
- {
- icon: ,
- title: "I want to offload my video to an external storage provider",
- content: (
-
- )
- },
- ]
-
- const otherResources = [
- {
- icon: ,
- title: "I found a bug",
- content: (
-
- )
- },
- {
- icon: ,
- title: "I have a general question",
- content: (
-
- Most general questions are answered in our
-
FAQ or exist in our
discussions
-
- )
- },
- {
- icon: ,
- title: "I want to use the API",
- content: (
-
- You can view the API documentation for either the
-
latest
- or
-
development
- release.
-
- )
- }
- ]
-
- return (
+ const questions = [
+ {
+ icon: ,
+ title: 'I want to configure my owncast instance',
+ content: (
-
How can we help you?
-
-
-
- Troubleshooting
- } type="primary">Read Troubleshoting
-
-
-
- Documentation
- } type="primary">Read the Docs
-
-
-
-
Common tasks
-
- {
- questions.map(question => (
-
-
-
-
-
- ))
- }
-
-
-
Other
-
- {
- otherResources.map(question => (
-
-
-
-
-
- ))
- }
-
+
+ Learn more
+
- )
+ ),
+ },
+ {
+ icon: ,
+ title: 'I need help configuring my broadcasting software',
+ content: (
+
+ ),
+ },
+ {
+ icon: ,
+ title: 'I want to embed my stream into another site',
+ content: (
+
+ ),
+ },
+ {
+ icon: ,
+ title: 'I want to customize my website',
+ content: (
+
+ ),
+ },
+ {
+ icon: ,
+ title: 'I want to tweak my encoding quality or performance',
+ content: (
+
+ ),
+ },
+ {
+ icon: ,
+ title: 'I want to offload my video to an external storage provider',
+ content: (
+
+ ),
+ },
+ ];
+
+ const otherResources = [
+ {
+ icon: ,
+ title: 'I found a bug',
+ content: (
+
+ ),
+ },
+ {
+ icon: ,
+ title: 'I have a general question',
+ content: (
+
+ ),
+ },
+ {
+ icon: ,
+ title: 'I want to use the API',
+ content: (
+
+ ),
+ },
+ ];
+
+ return (
+
+
How can we help you?
+
+
+
+ Troubleshooting
+ }
+ type="primary"
+ >
+ Read Troubleshoting
+
+
+
+
+ Documentation
+ }
+ type="primary"
+ >
+ Read the Docs
+
+
+
+
+
Common tasks
+
+ {questions.map(question => (
+
+
+
+
+
+ ))}
+
+
+
Other
+
+ {otherResources.map(question => (
+
+
+
+
+
+ ))}
+
+
+ );
}
diff --git a/web/pages/viewer-info.tsx b/web/pages/viewer-info.tsx
index 5786e887f..9dbdfd677 100644
--- a/web/pages/viewer-info.tsx
+++ b/web/pages/viewer-info.tsx
@@ -1,29 +1,20 @@
import React, { useState, useEffect, useContext } from 'react';
-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 { 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 { ServerStatusContext } from '../utils/server-status-context';
-import {
- CONNECTED_CLIENTS,
- VIEWERS_OVER_TIME,
- fetchData,
-} from "../utils/apis";
+import { CONNECTED_CLIENTS, VIEWERS_OVER_TIME, fetchData } from '../utils/apis';
const FETCH_INTERVAL = 60 * 1000; // 1 min
export default function ViewersOverTime() {
const context = useContext(ServerStatusContext);
- const {
- online,
- viewerCount,
- overallPeakViewerCount,
- sessionPeakViewerCount,
- } = context || {};
+ const { online, viewerCount, overallPeakViewerCount, sessionPeakViewerCount } = context || {};
const [viewerInfo, setViewerInfo] = useState([]);
const [clients, setClients] = useState([]);
@@ -33,14 +24,14 @@ export default function ViewersOverTime() {
const result = await fetchData(VIEWERS_OVER_TIME);
setViewerInfo(result);
} catch (error) {
- console.log("==== error", error);
+ console.log('==== error', error);
}
try {
const result = await fetchData(CONNECTED_CLIENTS);
setClients(result);
} catch (error) {
- console.log("==== error", error);
+ console.log('==== error', error);
}
};
@@ -62,43 +53,43 @@ export default function ViewersOverTime() {
// todo - check to see if broadcast active has changed. if so, start polling.
if (!viewerInfo.length) {
- return "no info";
+ return 'no info';
}
const columns = [
{
- title: "User name",
- dataIndex: "username",
- key: "username",
- render: (username) => username || "-",
+ title: 'User name',
+ dataIndex: 'username',
+ key: 'username',
+ render: username => username || '-',
sorter: (a, b) => a.username - b.username,
- sortDirections: ["descend", "ascend"] as SortOrder[],
+ sortDirections: ['descend', 'ascend'] as SortOrder[],
},
{
- title: "Messages sent",
- dataIndex: "messageCount",
- key: "messageCount",
+ title: 'Messages sent',
+ dataIndex: 'messageCount',
+ key: 'messageCount',
sorter: (a, b) => a.messageCount - b.messageCount,
- sortDirections: ["descend", "ascend"] as SortOrder[],
+ sortDirections: ['descend', 'ascend'] as SortOrder[],
},
{
- title: "Connected Time",
- dataIndex: "connectedAt",
- key: "connectedAt",
- render: (time) => formatDistanceToNow(new Date(time)),
+ title: 'Connected Time',
+ dataIndex: 'connectedAt',
+ key: 'connectedAt',
+ render: time => formatDistanceToNow(new Date(time)),
sorter: (a, b) => new Date(a.connectedAt).getTime() - new Date(b.connectedAt).getTime(),
- sortDirections: ["descend", "ascend"] as SortOrder[],
+ sortDirections: ['descend', 'ascend'] as SortOrder[],
},
{
- title: "User Agent",
- dataIndex: "userAgent",
- key: "userAgent",
+ title: 'User Agent',
+ dataIndex: 'userAgent',
+ key: 'userAgent',
},
{
- title: "Location",
- dataIndex: "geo",
- key: "geo",
- render: (geo) => geo ? `${geo.regionName}, ${geo.countryCode}` : '-',
+ title: 'Location',
+ dataIndex: 'geo',
+ key: 'geo',
+ render: geo => (geo ? `${geo.regionName}, ${geo.countryCode}` : '-'),
},
];
@@ -122,7 +113,7 @@ export default function ViewersOverTime() {
/>
-