revise Storage forms, and add basic validation to it; misc field cleanup
This commit is contained in:
parent
05167f77e5
commit
7501cfc548
@ -184,3 +184,69 @@ export const DEFAULT_SOCIAL_HANDLE: SocialHandle = {
|
||||
};
|
||||
|
||||
export const OTHER_SOCIAL_HANDLE_OPTION = 'OTHER_SOCIAL_HANDLE_OPTION';
|
||||
|
||||
|
||||
export const TEXTFIELD_PROPS_S3_COMMON = {
|
||||
maxLength: 255,
|
||||
}
|
||||
|
||||
|
||||
// export const FIELD_PROPS_CUSTOM_CONTENT = {
|
||||
// apiPath: API_CUSTOM_CONTENT,
|
||||
// configPath: 'instanceDetails',
|
||||
// placeholder: '',
|
||||
// label: 'Extra page content',
|
||||
// tip: 'Custom markup about yourself',
|
||||
// };
|
||||
|
||||
export const S3_TEXT_FIELDS_INFO = {
|
||||
accessKey: {
|
||||
fieldName: 'accessKey',
|
||||
label: 'Access Key',
|
||||
maxLength: 255,
|
||||
placeholder: 'access key 123',
|
||||
tip: '',
|
||||
},
|
||||
acl: {
|
||||
fieldName: 'acl',
|
||||
label: 'ACL',
|
||||
maxLength: 255,
|
||||
placeholder: 'acl thing',
|
||||
tip: '',
|
||||
},
|
||||
bucket: {
|
||||
fieldName: 'bucket',
|
||||
label: 'Bucket',
|
||||
maxLength: 255,
|
||||
placeholder: 'bucket 123',
|
||||
tip: '',
|
||||
},
|
||||
endpoint: {
|
||||
fieldName: 'endpoint',
|
||||
label: 'Endpoint',
|
||||
maxLength: 255,
|
||||
placeholder: 'endpoint 123',
|
||||
tip: 'This field has a some info',
|
||||
},
|
||||
region: {
|
||||
fieldName: 'region',
|
||||
label: 'Region',
|
||||
maxLength: 255,
|
||||
placeholder: 'region 123',
|
||||
tip: '',
|
||||
},
|
||||
secret: {
|
||||
fieldName: 'secret',
|
||||
label: 'Secret key',
|
||||
maxLength: 255,
|
||||
placeholder: 'secret key 123',
|
||||
tip: '',
|
||||
},
|
||||
servingEndpoint: {
|
||||
fieldName: 'servingEndpoint',
|
||||
label: 'Serving Endpoint',
|
||||
maxLength: 255,
|
||||
placeholder: 'servingEndpoint 123',
|
||||
tip: '',
|
||||
},
|
||||
};
|
||||
|
@ -63,50 +63,48 @@ export default function EditInstanceDetails() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`publicDetailsContainer`}>
|
||||
<div className={`textFieldsSection`}>
|
||||
<TextFieldWithSubmit
|
||||
fieldName="streamKey"
|
||||
{...TEXTFIELD_PROPS_STREAM_KEY}
|
||||
value={formDataValues.streamKey}
|
||||
initialValue={streamKey}
|
||||
type={TEXTFIELD_TYPE_PASSWORD}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
<div>
|
||||
<span style={{ fontSize: '0.75em', color: '#ff7777', marginRight: '0.5em' }}>
|
||||
Save this key somewhere safe, you will need it to stream or login to the admin
|
||||
dashboard!
|
||||
</span>
|
||||
<Tooltip className="copy-tooltip" title="Copied!" trigger="" visible={copyIsVisible}>
|
||||
<Button type="primary" icon={<CopyOutlined />} size="small" onClick={copyStreamKey} />
|
||||
</Tooltip>
|
||||
<Button type="primary" icon={<RedoOutlined />} size="small" onClick={generateStreamKey} />
|
||||
</div>
|
||||
<TextFieldWithSubmit
|
||||
fieldName="ffmpegPath"
|
||||
{...TEXTFIELD_PROPS_FFMPEG}
|
||||
value={formDataValues.ffmpegPath}
|
||||
initialValue={ffmpegPath}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
<TextFieldWithSubmit
|
||||
fieldName="webServerPort"
|
||||
{...TEXTFIELD_PROPS_WEB_PORT}
|
||||
value={formDataValues.webServerPort}
|
||||
initialValue={webServerPort}
|
||||
type={TEXTFIELD_TYPE_NUMBER}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
<TextFieldWithSubmit
|
||||
fieldName="rtmpServerPort"
|
||||
{...TEXTFIELD_PROPS_RTMP_PORT}
|
||||
value={formDataValues.rtmpServerPort}
|
||||
initialValue={rtmpServerPort}
|
||||
type={TEXTFIELD_TYPE_NUMBER}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
<div className="edit-public-details-container">
|
||||
<TextFieldWithSubmit
|
||||
fieldName="streamKey"
|
||||
{...TEXTFIELD_PROPS_STREAM_KEY}
|
||||
value={formDataValues.streamKey}
|
||||
initialValue={streamKey}
|
||||
type={TEXTFIELD_TYPE_PASSWORD}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
<div>
|
||||
<span style={{ fontSize: '0.75em', color: '#ff7777', marginRight: '0.5em' }}>
|
||||
Save this key somewhere safe, you will need it to stream or login to the admin
|
||||
dashboard!
|
||||
</span>
|
||||
<Tooltip className="copy-tooltip" title="Copied!" trigger="" visible={copyIsVisible}>
|
||||
<Button type="primary" icon={<CopyOutlined />} size="small" onClick={copyStreamKey} />
|
||||
</Tooltip>
|
||||
<Button type="primary" icon={<RedoOutlined />} size="small" onClick={generateStreamKey} />
|
||||
</div>
|
||||
<TextFieldWithSubmit
|
||||
fieldName="ffmpegPath"
|
||||
{...TEXTFIELD_PROPS_FFMPEG}
|
||||
value={formDataValues.ffmpegPath}
|
||||
initialValue={ffmpegPath}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
<TextFieldWithSubmit
|
||||
fieldName="webServerPort"
|
||||
{...TEXTFIELD_PROPS_WEB_PORT}
|
||||
value={formDataValues.webServerPort}
|
||||
initialValue={webServerPort}
|
||||
type={TEXTFIELD_TYPE_NUMBER}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
<TextFieldWithSubmit
|
||||
fieldName="rtmpServerPort"
|
||||
{...TEXTFIELD_PROPS_RTMP_PORT}
|
||||
value={formDataValues.rtmpServerPort}
|
||||
initialValue={rtmpServerPort}
|
||||
type={TEXTFIELD_TYPE_NUMBER}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ const { Title } = Typography;
|
||||
|
||||
export default function EditInstanceTags() {
|
||||
const [newTagInput, setNewTagInput] = useState<string | number>('');
|
||||
const [fieldStatus, setFieldStatus] = useState<StatusState>(null);
|
||||
const [submitStatus, setSubmitStatus] = useState<StatusState>(null);
|
||||
|
||||
const serverStatusData = useContext(ServerStatusContext);
|
||||
const { serverConfig, setFieldInConfigState } = serverStatusData || {};
|
||||
@ -38,34 +38,34 @@ export default function EditInstanceTags() {
|
||||
}, []);
|
||||
|
||||
const resetStates = () => {
|
||||
setFieldStatus(null);
|
||||
setSubmitStatus(null);
|
||||
resetTimer = null;
|
||||
clearTimeout(resetTimer);
|
||||
};
|
||||
|
||||
// posts all the tags at once as an array obj
|
||||
const postUpdateToAPI = async (postValue: any) => {
|
||||
setFieldStatus(createInputStatus(STATUS_PROCESSING));
|
||||
setSubmitStatus(createInputStatus(STATUS_PROCESSING));
|
||||
|
||||
await postConfigUpdateToAPI({
|
||||
apiPath,
|
||||
data: { value: postValue },
|
||||
onSuccess: () => {
|
||||
setFieldInConfigState({ fieldName: 'tags', value: postValue, path: configPath });
|
||||
setFieldStatus(createInputStatus(STATUS_SUCCESS, 'Tags updated.'));
|
||||
setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Tags updated.'));
|
||||
setNewTagInput('');
|
||||
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
|
||||
},
|
||||
onError: (message: string) => {
|
||||
setFieldStatus(createInputStatus(STATUS_ERROR, message));
|
||||
setSubmitStatus(createInputStatus(STATUS_ERROR, message));
|
||||
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleInputChange = ({ value }: UpdateArgs) => {
|
||||
if (!fieldStatus) {
|
||||
setFieldStatus(null);
|
||||
if (!submitStatus) {
|
||||
setSubmitStatus(null);
|
||||
}
|
||||
setNewTagInput(value);
|
||||
};
|
||||
@ -75,11 +75,11 @@ export default function EditInstanceTags() {
|
||||
resetStates();
|
||||
const newTag = newTagInput.trim();
|
||||
if (newTag === '') {
|
||||
setFieldStatus(createInputStatus(STATUS_WARNING, 'Please enter a tag'));
|
||||
setSubmitStatus(createInputStatus(STATUS_WARNING, 'Please enter a tag'));
|
||||
return;
|
||||
}
|
||||
if (tags.some(tag => tag.toLowerCase() === newTag.toLowerCase())) {
|
||||
setFieldStatus(createInputStatus(STATUS_WARNING, 'This tag is already used!'));
|
||||
setSubmitStatus(createInputStatus(STATUS_WARNING, 'This tag is already used!'));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ export default function EditInstanceTags() {
|
||||
onPressEnter={handleSubmitNewTag}
|
||||
maxLength={maxLength}
|
||||
placeholder={placeholder}
|
||||
status={fieldStatus}
|
||||
status={submitStatus}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -11,14 +11,12 @@ export default function PublicFacingDetails() {
|
||||
<>
|
||||
<Title level={2}>Edit your public facing instance details</Title>
|
||||
|
||||
<div className={`publicDetailsContainer`}>
|
||||
<div className={`textFieldsSection`}>
|
||||
<EditInstanceDetails />
|
||||
<div className="edit-public-details-container">
|
||||
<EditInstanceDetails />
|
||||
|
||||
<Link href="/admin/config-page-content">
|
||||
<a>Edit your extra page content here.</a>
|
||||
</Link>
|
||||
</div>
|
||||
<Link href="/admin/config-page-content">
|
||||
<a>Edit your extra page content here.</a>
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
@ -1,111 +1,230 @@
|
||||
import { Typography, Switch, Button, Collapse } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import React, { useContext, useState, useEffect } from 'react';
|
||||
import { UpdateArgs } from '../types/config-section';
|
||||
import { ServerStatusContext } from '../utils/server-status-context';
|
||||
import { Typography, Switch, Input, Button } from 'antd';
|
||||
import {
|
||||
postConfigUpdateToAPI,
|
||||
API_S3_INFO,
|
||||
RESET_TIMEOUT,
|
||||
S3_TEXT_FIELDS_INFO,
|
||||
} from './components/config/constants';
|
||||
const { Title } = Typography;
|
||||
import {
|
||||
createInputStatus,
|
||||
StatusState,
|
||||
STATUS_ERROR,
|
||||
STATUS_PROCESSING,
|
||||
STATUS_SUCCESS,
|
||||
} from '../utils/input-statuses';
|
||||
import TextField from './components/config/form-textfield';
|
||||
import InputStatusInfo from './components/config/input-status-info';
|
||||
|
||||
function Storage({ config }) {
|
||||
if (!config || !config.s3) {
|
||||
const { Title } = Typography;
|
||||
const { Panel } = Collapse;
|
||||
|
||||
// we could probably add more detailed checks here
|
||||
// `currentValues` is what's currently in the global store and in the db
|
||||
function checkSaveable(formValues: any, currentValues: any) {
|
||||
const { endpoint, accessKey, secret, bucket, region, enabled, servingEndpoint, acl } = formValues;
|
||||
// if fields are filled out and different from what's in store, then return true
|
||||
if (enabled) {
|
||||
if (endpoint !== '' && accessKey !== '' && secret !== '' && bucket !== '' && region !== '') {
|
||||
if (
|
||||
endpoint !== currentValues.endpoint ||
|
||||
accessKey !== currentValues.accessKey ||
|
||||
secret !== currentValues.bucket ||
|
||||
region !== currentValues.region ||
|
||||
servingEndpoint !== currentValues.servingEndpoint ||
|
||||
acl !== currentValues.acl
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (enabled !== currentValues.enabled) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function EditStorage() {
|
||||
const [formDataValues, setFormDataValues] = useState(null);
|
||||
const [submitStatus, setSubmitStatus] = useState<StatusState>(null);
|
||||
|
||||
const [shouldDisplayForm, setShouldDisplayForm] = useState(false);
|
||||
const serverStatusData = useContext(ServerStatusContext);
|
||||
const { serverConfig, setFieldInConfigState } = serverStatusData || {};
|
||||
|
||||
const { s3 } = serverConfig;
|
||||
const {
|
||||
accessKey = '',
|
||||
acl = '',
|
||||
bucket = '',
|
||||
enabled = false,
|
||||
endpoint = '',
|
||||
region = '',
|
||||
secret = '',
|
||||
servingEndpoint = '',
|
||||
} = s3;
|
||||
|
||||
useEffect(() => {
|
||||
setFormDataValues({
|
||||
accessKey,
|
||||
acl,
|
||||
bucket,
|
||||
enabled,
|
||||
endpoint,
|
||||
region,
|
||||
secret,
|
||||
servingEndpoint,
|
||||
});
|
||||
setShouldDisplayForm(enabled);
|
||||
}, [s3]);
|
||||
|
||||
if (!formDataValues) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [endpoint, setEndpoint] = useState(config.s3.endpoint);
|
||||
const [accessKey, setAccessKey] = useState(config.s3.accessKey);
|
||||
const [secret, setSecret] = useState(config.s3.secret);
|
||||
const [bucket, setBucket] = useState(config.s3.bucket);
|
||||
const [region, setRegion] = useState(config.s3.region);
|
||||
const [acl, setAcl] = useState(config.s3.acl);
|
||||
const [servingEndpoint, setServingEndpoint] = useState(config.s3.servingEndpoint);
|
||||
const [enabled, setEnabled] = useState(config.s3.enabled);
|
||||
let resetTimer = null;
|
||||
const resetStates = () => {
|
||||
setSubmitStatus(null);
|
||||
resetTimer = null;
|
||||
clearTimeout(resetTimer);
|
||||
};
|
||||
|
||||
function storageEnabledChanged(storageEnabled) {
|
||||
setEnabled(storageEnabled);
|
||||
}
|
||||
// update individual values in state
|
||||
const handleFieldChange = ({ fieldName, value }: UpdateArgs) => {
|
||||
setFormDataValues({
|
||||
...formDataValues,
|
||||
[fieldName]: value,
|
||||
});
|
||||
};
|
||||
|
||||
function endpointChanged(e) {
|
||||
setEndpoint(e.target.value)
|
||||
}
|
||||
// posts the whole state
|
||||
const handleSave = async () => {
|
||||
setSubmitStatus(createInputStatus(STATUS_PROCESSING));
|
||||
const postValue = formDataValues;
|
||||
|
||||
function accessKeyChanged(e) {
|
||||
setAccessKey(e.target.value)
|
||||
}
|
||||
await postConfigUpdateToAPI({
|
||||
apiPath: API_S3_INFO,
|
||||
data: { value: postValue },
|
||||
onSuccess: () => {
|
||||
setFieldInConfigState({ fieldName: 's3', value: postValue, path: '' });
|
||||
setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Updated.'));
|
||||
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
|
||||
},
|
||||
onError: (message: string) => {
|
||||
setSubmitStatus(createInputStatus(STATUS_ERROR, message));
|
||||
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
function secretChanged(e) {
|
||||
setSecret(e.target.value)
|
||||
}
|
||||
// toggle switch.
|
||||
const handleSwitchChange = (storageEnabled: boolean) => {
|
||||
setShouldDisplayForm(storageEnabled);
|
||||
handleFieldChange({ fieldName: 'enabled', value: storageEnabled });
|
||||
|
||||
function bucketChanged(e) {
|
||||
setBucket(e.target.value)
|
||||
}
|
||||
// if current data in current store says s3 is enabled,
|
||||
// we should save this state
|
||||
// if (!storageEnabled && s3.enabled) {
|
||||
// handleSave();
|
||||
// }
|
||||
};
|
||||
|
||||
function regionChanged(e) {
|
||||
setRegion(e.target.value)
|
||||
}
|
||||
const containerClass = classNames({
|
||||
'edit-storage-container': true,
|
||||
enabled: shouldDisplayForm,
|
||||
});
|
||||
|
||||
function aclChanged(e) {
|
||||
setAcl(e.target.value)
|
||||
}
|
||||
|
||||
function servingEndpointChanged(e) {
|
||||
setServingEndpoint(e.target.value)
|
||||
}
|
||||
|
||||
async function save() {
|
||||
const payload = {
|
||||
value: {
|
||||
enabled: enabled,
|
||||
endpoint: endpoint,
|
||||
accessKey: accessKey,
|
||||
secret: secret,
|
||||
bucket: bucket,
|
||||
region: region,
|
||||
acl: acl,
|
||||
servingEndpoint: servingEndpoint,
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
await postConfigUpdateToAPI({apiPath: API_S3_INFO, data: payload});
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
const table = enabled ? (
|
||||
<>
|
||||
<br></br>
|
||||
endpoint <Input defaultValue={endpoint} value={endpoint} onChange={endpointChanged} />
|
||||
access key<Input label="Access key" defaultValue={accessKey} value={accessKey} onChange={accessKeyChanged} />
|
||||
secret <Input label="Secret" defaultValue={secret} value={secret} onChange={secretChanged} />
|
||||
bucket <Input label="Bucket" defaultValue={bucket} value={bucket} onChange={bucketChanged} />
|
||||
region <Input label="Region" defaultValue={region} value={region} onChange={regionChanged} />
|
||||
advanced<br></br>
|
||||
acl <Input label="ACL" defaultValue={acl} value={acl} onChange={aclChanged} />
|
||||
serving endpoint <Input label="Serving endpoint" defaultValue={servingEndpoint} value={servingEndpoint} onChange={servingEndpointChanged} />
|
||||
<Button onClick={save}>Save</Button>
|
||||
</>
|
||||
): null;
|
||||
const isSaveable = checkSaveable(formDataValues, s3);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title level={2}>Storage</Title>
|
||||
Enabled:
|
||||
<Switch checked={enabled} onChange={storageEnabledChanged} />
|
||||
{ table }
|
||||
</>
|
||||
);
|
||||
}
|
||||
<div className={containerClass}>
|
||||
<div className="enable-switch">
|
||||
<Switch
|
||||
checked={formDataValues.enabled}
|
||||
defaultChecked={formDataValues.enabled}
|
||||
onChange={handleSwitchChange}
|
||||
checkedChildren="ON"
|
||||
unCheckedChildren="OFF"
|
||||
/>{' '}
|
||||
Enabled
|
||||
</div>
|
||||
|
||||
export default function ServerConfig() {
|
||||
const serverStatusData = useContext(ServerStatusContext);
|
||||
const { serverConfig: config } = serverStatusData || {};
|
||||
<div className="form-fields">
|
||||
<div className="field-container">
|
||||
<TextField
|
||||
{...S3_TEXT_FIELDS_INFO.endpoint}
|
||||
value={formDataValues.endpoint}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="field-container">
|
||||
<TextField
|
||||
{...S3_TEXT_FIELDS_INFO.accessKey}
|
||||
value={formDataValues.accessKey}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="field-container">
|
||||
<TextField
|
||||
{...S3_TEXT_FIELDS_INFO.secret}
|
||||
value={formDataValues.secret}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="field-container">
|
||||
<TextField
|
||||
{...S3_TEXT_FIELDS_INFO.bucket}
|
||||
value={formDataValues.bucket}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="field-container">
|
||||
<TextField
|
||||
{...S3_TEXT_FIELDS_INFO.region}
|
||||
value={formDataValues.region}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Storage config={config} />
|
||||
<Collapse>
|
||||
<Panel header="Advanced Settings" key="1">
|
||||
<Title level={4}>Advanced</Title>
|
||||
|
||||
<div className="field-container">
|
||||
<TextField
|
||||
{...S3_TEXT_FIELDS_INFO.acl}
|
||||
value={formDataValues.acl}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="field-container">
|
||||
<TextField
|
||||
{...S3_TEXT_FIELDS_INFO.servingEndpoint}
|
||||
value={formDataValues.servingEndpoint}
|
||||
onChange={handleFieldChange}
|
||||
/>
|
||||
</div>
|
||||
</Panel>
|
||||
</Collapse>
|
||||
</div>
|
||||
|
||||
<div className="button-container">
|
||||
<Button onClick={handleSave} disabled={!isSaveable}>
|
||||
Save
|
||||
</Button>
|
||||
<InputStatusInfo status={submitStatus} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function ConfigStorageInfo() {
|
||||
return (
|
||||
<>
|
||||
<Title level={2}>Storage</Title>
|
||||
<EditStorage />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -169,3 +169,30 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TOGGLE SWITCH-WITH-SUBMIT-CONTAINER BASE */
|
||||
.toggleswitch-container {
|
||||
.status-container {
|
||||
margin-top: .25rem;
|
||||
}
|
||||
|
||||
.toggleswitch {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
.label {
|
||||
font-weight: bold;
|
||||
color: var(--owncast-purple);
|
||||
}
|
||||
.info-tip {
|
||||
margin-left: .5rem;
|
||||
svg {
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
.ant-form-item {
|
||||
margin: 0 .75rem 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,30 +98,30 @@
|
||||
|
||||
// form-toggleswitch
|
||||
// form-toggleswitch
|
||||
.toggleswitch-container {
|
||||
.status-message {
|
||||
margin-top: .25rem;
|
||||
}
|
||||
}
|
||||
.toggleswitch {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
.label {
|
||||
font-weight: bold;
|
||||
color: var(--owncast-purple);
|
||||
}
|
||||
.info-tip {
|
||||
margin-left: .5rem;
|
||||
svg {
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
.ant-form-item {
|
||||
margin: 0 .75rem 0 0;
|
||||
}
|
||||
}
|
||||
// .toggleswitch-container {
|
||||
// .status-message {
|
||||
// margin-top: .25rem;
|
||||
// }
|
||||
// }
|
||||
// .toggleswitch {
|
||||
// display: flex;
|
||||
// flex-direction: row;
|
||||
// align-items: center;
|
||||
// justify-content: flex-start;
|
||||
// .label {
|
||||
// font-weight: bold;
|
||||
// color: var(--owncast-purple);
|
||||
// }
|
||||
// .info-tip {
|
||||
// margin-left: .5rem;
|
||||
// svg {
|
||||
// fill: white;
|
||||
// }
|
||||
// }
|
||||
// .ant-form-item {
|
||||
// margin: 0 .75rem 0 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
// TAGS STUFF
|
||||
// TAGS STUFF
|
||||
@ -321,3 +321,23 @@
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
// EDIT STORAGE
|
||||
.edit-storage-container {
|
||||
.form-fields {
|
||||
display: none;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
&.enabled {
|
||||
.form-fields {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.button-container {
|
||||
margin: 1em 0;
|
||||
}
|
||||
}
|
||||
|
@ -63,11 +63,22 @@ export interface VideoSettingsFields {
|
||||
cpuUsageLevel: CpuUsageLevel;
|
||||
}
|
||||
|
||||
export interface S3Field {
|
||||
acl?: string;
|
||||
accessKey: string;
|
||||
bucket: string;
|
||||
enabled: boolean;
|
||||
endpoint: string;
|
||||
region: string;
|
||||
secret: string;
|
||||
servingEndpoint?: string;
|
||||
}
|
||||
|
||||
export interface ConfigDetails {
|
||||
ffmpegPath: string;
|
||||
instanceDetails: ConfigInstanceDetailsFields;
|
||||
rtmpServerPort: string;
|
||||
s3: any; // tbd
|
||||
s3: S3Field;
|
||||
streamKey: string;
|
||||
webServerPort: string;
|
||||
yp: ConfigDirectoryFields;
|
||||
|
@ -23,7 +23,16 @@ export const initialServerConfigState: ConfigDetails = {
|
||||
ffmpegPath: '',
|
||||
rtmpServerPort: '',
|
||||
webServerPort: '',
|
||||
s3: {},
|
||||
s3: {
|
||||
accessKey: '',
|
||||
acl: '',
|
||||
bucket: '',
|
||||
enabled: false,
|
||||
endpoint: '',
|
||||
region: '',
|
||||
secret: '',
|
||||
servingEndpoint: '',
|
||||
},
|
||||
yp: {
|
||||
enabled: false,
|
||||
instanceUrl: '',
|
||||
@ -32,7 +41,7 @@ export const initialServerConfigState: ConfigDetails = {
|
||||
latencyLevel: 4,
|
||||
cpuUsageLevel: 3,
|
||||
videoQualityVariants: [DEFAULT_VARIANT_STATE],
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const initialServerStatusState = {
|
||||
@ -51,7 +60,9 @@ export const ServerStatusContext = React.createContext({
|
||||
...initialServerStatusState,
|
||||
serverConfig: initialServerConfigState,
|
||||
|
||||
setFieldInConfigState: (args: UpdateArgs) => { return args },
|
||||
setFieldInConfigState: (args: UpdateArgs) => {
|
||||
return args;
|
||||
},
|
||||
});
|
||||
|
||||
const ServerStatusProvider = ({ children }) => {
|
||||
@ -62,7 +73,6 @@ const ServerStatusProvider = ({ children }) => {
|
||||
try {
|
||||
const result = await fetchData(STATUS);
|
||||
setStatus({ ...result });
|
||||
|
||||
} catch (error) {
|
||||
// todo
|
||||
}
|
||||
@ -77,22 +87,21 @@ const ServerStatusProvider = ({ children }) => {
|
||||
};
|
||||
|
||||
const setFieldInConfigState = ({ fieldName, value, path }: UpdateArgs) => {
|
||||
const updatedConfig = path ?
|
||||
{
|
||||
...config,
|
||||
[path]: {
|
||||
...config[path],
|
||||
[fieldName]: value,
|
||||
},
|
||||
} :
|
||||
{
|
||||
...config,
|
||||
[fieldName]: value,
|
||||
};
|
||||
const updatedConfig = path
|
||||
? {
|
||||
...config,
|
||||
[path]: {
|
||||
...config[path],
|
||||
[fieldName]: value,
|
||||
},
|
||||
}
|
||||
: {
|
||||
...config,
|
||||
[fieldName]: value,
|
||||
};
|
||||
setConfig(updatedConfig);
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
let getStatusIntervalId = null;
|
||||
|
||||
@ -101,27 +110,25 @@ const ServerStatusProvider = ({ children }) => {
|
||||
|
||||
getConfig();
|
||||
|
||||
// returned function will be called on component unmount
|
||||
// returned function will be called on component unmount
|
||||
return () => {
|
||||
clearInterval(getStatusIntervalId);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const providerValue = {
|
||||
...status,
|
||||
serverConfig: config,
|
||||
...status,
|
||||
serverConfig: config,
|
||||
|
||||
setFieldInConfigState,
|
||||
setFieldInConfigState,
|
||||
};
|
||||
return (
|
||||
<ServerStatusContext.Provider value={providerValue}>
|
||||
{children}
|
||||
</ServerStatusContext.Provider>
|
||||
<ServerStatusContext.Provider value={providerValue}>{children}</ServerStatusContext.Provider>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
ServerStatusProvider.propTypes = {
|
||||
children: PropTypes.element.isRequired,
|
||||
};
|
||||
|
||||
export default ServerStatusProvider;
|
||||
export default ServerStatusProvider;
|
||||
|
Loading…
x
Reference in New Issue
Block a user