start organizing nav; start on Tags editing

This commit is contained in:
gingervitis 2020-12-30 18:07:15 -08:00 committed by Gabe Kangas
parent f9b7a0d8e0
commit 624ab72eb3
11 changed files with 177 additions and 177 deletions

View File

@ -58,22 +58,42 @@ export const TEXTFIELD_DEFAULTS = {
label: 'Stream Title',
tip: 'A brief blurb about what your stream is about.',
},
streamKey: {
apiPath: '/key',
defaultValue: DEFAULT_NAME,
maxLength: TEXT_MAXLENGTH,
placeholder: DEFAULT_NAME,
configPath: 'instanceDetails',
label: 'Stream Key',
tip: 'Secret stream key',
},
pageContent: {
extraPageContent: {
apiPath: '/pagecontent',
placeholder: '',
configPath: 'instanceDetails',
label: 'Stream Key',
tip: 'Custom markup about yourself',
}
},
streamKey: {
apiPath: '/key',
defaultValue: DEFAULT_NAME,
maxLength: TEXT_MAXLENGTH,
placeholder: DEFAULT_NAME,
configPath: '',
label: 'Stream Key',
tip: 'Secret stream key',
},
ffmpegPath: {
// apiPath: '/key',
defaultValue: DEFAULT_NAME,
maxLength: TEXT_MAXLENGTH,
placeholder: DEFAULT_NAME,
configPath: '',
label: 'FFmpeg Path',
tip: 'Absolute file path of the FFMPEG application on your server',
},
webServerPort: {
apiPath: '/port',
defaultValue: '',
maxLength: 6,
placeholder: DEFAULT_NAME,
configPath: '',
label: 'Server port',
tip: 'What port are you serving Owncast from? Default is :8080',
},
}

View File

@ -80,15 +80,15 @@ export default function TextField(props: TextFieldProps) {
if (result.success) {
setConfigField({ fieldName, value: postValue, path: configPath });
setSubmitStatus('success');
resetTimer = setTimeout(resetStates, 3000);
} else {
setSubmitStatus('warning');
setSubmitStatus('error');
setSubmitStatusMessage(`There was an error: ${result.message}`);
}
resetTimer = setTimeout(resetStates, 3000);
};
const handleChange = e => {
const val = e.target.value;
const val = type === TEXTFIELD_TYPE_NUMBER ? e : e.target.value;
if (val === '' || val === initialValue) {
setHasChanged(false);
} else {
@ -102,7 +102,6 @@ export default function TextField(props: TextFieldProps) {
const val = e.target.value;
if (val === '') {
handleResetValue(fieldName);
// todo: find a way to reset to initial value
}
};
@ -140,7 +139,7 @@ export default function TextField(props: TextFieldProps) {
<Form.Item
label={label}
name={fieldName}
hasFeedback
// hasFeedback
validateStatus={submitStatus}
help={submitStatusMessage}
>

View File

@ -0,0 +1,43 @@
/* eslint-disable react/no-array-index-key */
import React, { useContext, useEffect } from 'react';
import { Typography, Button, Tooltip } from 'antd';
import { CloseCircleOutlined } from '@ant-design/icons';
import { ServerStatusContext } from '../../../utils/server-status-context';
const { Title } = Typography;
function Tag({ label }) {
return (
<Button className="tag" type="text" shape="round">
{label}
<Tooltip title="Delete this tag.">
<Button type="link" size="small" className="tag-delete">
<CloseCircleOutlined />
</Button>
</Tooltip>
</Button>
);
}
export default function EditInstanceTags() {
const serverStatusData = useContext(ServerStatusContext);
const { serverConfig } = serverStatusData || {};
const { instanceDetails } = serverConfig;
const { tags = [] } = instanceDetails;
console.log(tags)
return (
<div className="tag-editor-container">
<Title level={3}>Add Tags</Title>
<p>This is a great way to categorize your Owncast server on the Directory!</p>
<div className="tag-current-tags">
{tags.map((tag, index) => <Tag label={tag} key={`tag-${tag}-${index}`} />)}
</div>
</div>
);
}

View File

@ -138,14 +138,17 @@ export default function MainLayout(props) {
title="Configuration"
icon={<SettingOutlined />}
>
<Menu.Item key="update-server-config">
<Link href="/update-server-config">Server</Link>
<Menu.Item key="config-public-details">
<Link href="/config-public-details">Public Details</Link>
</Menu.Item>
<Menu.Item key="video-config">
<Link href="/video-config">Video</Link>
<Menu.Item key="config-server-details">
<Link href="/config-server-details">Server Details</Link>
</Menu.Item>
<Menu.Item key="storage">
<Link href="/storage">Storage</Link>
<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>
</SubMenu>

View File

@ -1,9 +1,11 @@
import React, { useContext, useEffect } from 'react';
import { Typography, Form } from 'antd';
import TextField, { TEXTFIELD_TYPE_TEXTAREA } from './form-textfield';
import TextField, { TEXTFIELD_TYPE_TEXTAREA } from './components/config/form-textfield';
import { ServerStatusContext } from '../../../utils/server-status-context';
import EditInstanceTags from './components/config/tags';
import { ServerStatusContext } from '../utils/server-status-context';
const { Title } = Typography;
@ -14,6 +16,7 @@ export default function PublicFacingDetails() {
const { serverConfig } = serverStatusData || {};
const { instanceDetails = {} } = serverConfig;
console.log(serverConfig)
useEffect(() => {
form.setFieldsValue({...instanceDetails});
@ -46,9 +49,11 @@ export default function PublicFacingDetails() {
</Form>
</div>
<div className="misc-fields">
add social handles comp
{/* add social handles comp
<br/>
add tags comp
add tags comp */}
<EditInstanceTags />
</div>
</div>
@ -56,3 +61,4 @@ export default function PublicFacingDetails() {
);
}

View File

@ -0,0 +1,55 @@
import React, { useContext, useEffect } from 'react';
import { Typography, Form } from 'antd';
import TextField, { TEXTFIELD_TYPE_NUMBER, TEXTFIELD_TYPE_PASSWORD, TEXTFIELD_TYPE_TEXTAREA } from './components/config/form-textfield';
import { ServerStatusContext } from '../utils/server-status-context';
const { Title } = Typography;
export default function ConfigServerDetails() {
const [form] = Form.useForm();
const serverStatusData = useContext(ServerStatusContext);
const { serverConfig } = serverStatusData || {};
const { ffmpegPath, streamKey, webServerPort } = serverConfig;
const streamDetails = {
ffmpegPath, streamKey, webServerPort
};
useEffect(() => {
form.setFieldsValue({...streamDetails});
}, [serverStatusData]);
const handleResetValue = (fieldName: string) => {
form.setFieldsValue({ [fieldName]: streamDetails[fieldName]});
}
const extraProps = {
handleResetValue,
initialValues: streamDetails,
};
console.log(streamDetails)
return (
<>
<Title level={2}>Edit your Server&apos;s details</Title>
<div className="config-public-details-container">
<Form
form={form}
layout="vertical"
>
<TextField fieldName="streamKey" type={TEXTFIELD_TYPE_PASSWORD} {...extraProps} />
<TextField fieldName="ffmpegPath" type={TEXTFIELD_TYPE_TEXTAREA} {...extraProps} />
<TextField fieldName="webServerPort" type={TEXTFIELD_TYPE_NUMBER} {...extraProps} />
</Form>
</div>
</>
);
}

View File

@ -1,147 +0,0 @@
import React, { useContext } from 'react';
import { Table, Typography, Input } from 'antd';
import { isEmptyObject } from '../utils/format';
import KeyValueTable from "./components/key-value-table";
import { ServerStatusContext } from '../utils/server-status-context';
import PublicFacingDetails from './components/config/public-facing-details';
import adminStyles from '../styles/styles.module.scss';
const { Title } = Typography;
const { TextArea } = Input;
function SocialHandles({ config }) {
if (!config) {
return null;
}
const columns = [
{
title: "Platform",
dataIndex: "platform",
key: "platform",
},
{
title: "URL",
dataIndex: "url",
key: "url",
render: (url) => <a href={url}>{url}</a>
},
];
if (!config.instanceDetails?.socialHandles) {
return null;
}
return (
<div className={adminStyles.configSection}>
<Title level={2}>Social Handles</Title>
<Table
pagination={false}
columns={columns}
dataSource={config.instanceDetails.socialHandles}
rowKey="platform"
/>
</div>
);
}
function InstanceDetails({ config }) {
if (!config || isEmptyObject(config)) {
return null;
}
const { instanceDetails = {}, yp, streamKey, ffmpegPath, webServerPort } = config;
const data = [
{
name: "Server name",
value: instanceDetails.name,
},
{
name: "Title",
value: instanceDetails.title,
},
{
name: "Summary",
value: instanceDetails.summary,
},
{
name: "Logo",
value: instanceDetails.logo,
},
{
name: "Tags",
value: instanceDetails.tags?.join(", "),
},
{
name: "NSFW",
value: instanceDetails.nsfw?.toString(),
},
{
name: "Shows in Owncast directory",
value: yp.enabled.toString(),
},
];
const configData = [
{
name: "Stream key",
value: streamKey,
},
{
name: "ffmpeg path",
value: ffmpegPath,
},
{
name: "Web server port",
value: webServerPort,
},
];
return (
<>
<div className={adminStyles.configSection}>
<KeyValueTable title="Server details" data={data} />
</div>
<div className={adminStyles.configSection}>
<KeyValueTable title="Server configuration" data={configData} />
</div>
</>
);
}
function PageContent({ config }) {
if (!config?.instanceDetails?.extraPageContent) {
return null;
}
return (
<div className={adminStyles.configSection}>
<Title level={2}>Page content</Title>
<TextArea
disabled rows={4}
value={config.instanceDetails.extraPageContent}
/>
</div>
);
}
export default function ServerConfig() {
const serverStatusData = useContext(ServerStatusContext);
const { serverConfig: config } = serverStatusData || {};
return (
<>
<PublicFacingDetails />
<InstanceDetails config={config} />
<SocialHandles config={config} />
<PageContent config={config} />
<Title level={5}>Learn more about configuring Owncast <a href="https://owncast.online/docs/configuration">by visiting the documentation.</a></Title>
</>
);
}

View File

@ -47,6 +47,12 @@
.info {
margin-right: .75rem;
}
.ant-form-item {
margin-bottom: 16px;
&.ant-form-item-with-help {
margin-bottom: 16px;
}
}
.ant-form-item-label label {
font-weight: bold;
color: var(--owncast-purple);
@ -58,5 +64,18 @@
.submit-button {
position: absolute;
right: 0;
bottom: 1em;
bottom: .5em;
}
.tag {
background-color: white;
border-color: gray;
.tag-delete {
padding: 0 0 0 .3rem;
margin-top: -4px;
}
}
.tag-current-tags {
.tag {
margin: .25rem ;
}
}

View File

@ -1,12 +1,14 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import PropTypes, { any } from 'prop-types';
import { STATUS, fetchData, FETCH_INTERVAL, SERVER_CONFIG } from './apis';
import { UpdateArgs } from '../types/config-section';
export const initialServerConfigState = {
streamKey: '',
instanceDetails: {},
instanceDetails: {
tags: [],
},
yp: {
enabled: false,
},
@ -39,7 +41,7 @@ export const ServerStatusContext = React.createContext({
...initialServerStatusState,
serverConfig: initialServerConfigState,
setConfigField: () => {},
setConfigField: any,
});
const ServerStatusProvider = ({ children }) => {