mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-16 04:43:35 +00:00
76c8f8a4d5
* Update TimerService.ts * refactor: message service publishes to store * refactor: several type improvements * V2 ws store wss (#309) * refactor: shared logging types * refactor: simplify message service consumption * refactor: create discrete logging system * refactor: move socket.io > websocket
292 lines
8.7 KiB
React
292 lines
8.7 KiB
React
import { useCallback, useEffect, useState } from 'react';
|
|
import { FormControl, FormLabel, Input, ModalBody } from '@chakra-ui/react';
|
|
import { IoInformationCircleOutline } from '@react-icons/all-files/io5/IoInformationCircleOutline';
|
|
|
|
import { useEmitLog } from '@/common/stores/logger';
|
|
|
|
import { postOSC } from '../../../common/api/ontimeApi';
|
|
import EnableBtn from '../../../common/components/buttons/EnableBtn';
|
|
import useOscSettings from '../../../common/hooks-query/useOscSettings';
|
|
import { oscPlaceholderSettings } from '../../../common/models/OscSettings';
|
|
import { inputProps, portInputProps } from '../modalHelper';
|
|
import SubmitContainer from '../SubmitContainer';
|
|
|
|
import style from '../Modals.module.scss';
|
|
|
|
// currently defined endpoints
|
|
// temporary
|
|
const oscCycleEndpoints = [
|
|
{
|
|
title: 'On Event Start',
|
|
message: '/ontime/eventNumber',
|
|
value: '8 | int',
|
|
},
|
|
{
|
|
title: 'On Update',
|
|
message: '/ontime/time',
|
|
value: '10:12:12 | string',
|
|
},
|
|
{
|
|
title: 'On Update',
|
|
message: '/ontime/overtime',
|
|
value: '0-1 | int',
|
|
},
|
|
{
|
|
title: 'On Update',
|
|
message: '/ontime/title',
|
|
value: 'Title of running event | string',
|
|
},
|
|
{
|
|
title: 'On Finish',
|
|
message: '/ontime/finished',
|
|
value: '-',
|
|
},
|
|
];
|
|
const oscTriggerEndpoints = [
|
|
{
|
|
title: 'On Start',
|
|
message: '/ontime/play',
|
|
value: '-',
|
|
},
|
|
{
|
|
title: 'On Pause',
|
|
message: '/ontime/pause',
|
|
value: '-',
|
|
},
|
|
{
|
|
title: 'On Previous',
|
|
message: '/ontime/prev',
|
|
value: '-',
|
|
},
|
|
{
|
|
title: 'On Next',
|
|
message: '/ontime/next',
|
|
value: '-',
|
|
},
|
|
{
|
|
title: 'On Reload',
|
|
message: '/ontime/reload',
|
|
value: '-',
|
|
},
|
|
{
|
|
title: 'On Stop',
|
|
message: '/ontime/stop',
|
|
value: '-',
|
|
},
|
|
];
|
|
|
|
export default function OscSettingsModal() {
|
|
const { data, status, refetch } = useOscSettings();
|
|
const { emitError } = useEmitLog();
|
|
const [formData, setFormData] = useState(oscPlaceholderSettings);
|
|
const [changed, setChanged] = useState(false);
|
|
const [submitting, setSubmitting] = useState(false);
|
|
|
|
/**
|
|
* Set formdata from server state
|
|
*/
|
|
useEffect(() => {
|
|
if (data == null) return;
|
|
if (changed) return;
|
|
setFormData({ ...data });
|
|
}, [changed, data]);
|
|
|
|
/**
|
|
* Validate and submit data
|
|
*/
|
|
const submitHandler = useCallback(
|
|
async (event) => {
|
|
event.preventDefault();
|
|
setSubmitting(true);
|
|
|
|
const f = formData;
|
|
const e = { status: false, message: '' };
|
|
|
|
// Validate fields
|
|
if (f.port < 1024 || f.port > 65535) {
|
|
// Port in incorrect range
|
|
e.status = true;
|
|
e.message += 'OSC IN Port in incorrect range (1024 - 65535)';
|
|
} else if (f.portOut < 1024 || f.portOut > 65535) {
|
|
// Port in incorrect range
|
|
e.status = true;
|
|
e.message += 'OSC OUT Port in incorrect range (1024 - 65535)';
|
|
} else if (f.port === f.portOut) {
|
|
// Cant use the same port
|
|
e.status = true;
|
|
e.message += 'OSC IN and OUT Ports cant be the same';
|
|
}
|
|
|
|
// set fields with error
|
|
if (e.status) {
|
|
emitError(`Invalid Input: ${e.message}`);
|
|
} else {
|
|
try {
|
|
await postOSC(formData);
|
|
} catch (error) {
|
|
emitError(`Error setting OSC: ${error}`);
|
|
} finally {
|
|
await refetch();
|
|
setChanged(false);
|
|
}
|
|
}
|
|
setSubmitting(false);
|
|
},
|
|
[emitError, formData, refetch],
|
|
);
|
|
|
|
/**
|
|
* Reverts local state equals to server state
|
|
*/
|
|
const revert = useCallback(async () => {
|
|
setChanged(false);
|
|
await refetch();
|
|
}, [refetch]);
|
|
|
|
/**
|
|
* Handles change of input field in local state
|
|
* @param {string} field - object parameter to update
|
|
* @param {(string | number | boolean)} value - new object parameter value
|
|
*/
|
|
const handleChange = useCallback(
|
|
(field, value) => {
|
|
const temp = { ...formData };
|
|
temp[field] = value;
|
|
setFormData(temp);
|
|
setChanged(true);
|
|
},
|
|
[formData],
|
|
);
|
|
|
|
return (
|
|
<ModalBody className={style.modalBody}>
|
|
<p className={style.notes}>
|
|
Options related to Open Sound Control
|
|
<br />
|
|
🔥 Changes take effect after app restart 🔥
|
|
</p>
|
|
<form onSubmit={submitHandler}>
|
|
<div className={style.modalFields}>
|
|
<div className={style.hSeparator}>OSC Input (Control ontime over OSC)</div>
|
|
<div className={style.modalInline}>
|
|
<FormControl id='oscInEnabled'>
|
|
<FormLabel htmlFor='oscInEnabled'>
|
|
OSC Enable
|
|
<span className={style.labelNote}>
|
|
<br />
|
|
Enable / Disable control
|
|
</span>
|
|
</FormLabel>
|
|
<EnableBtn
|
|
active={formData.enabled}
|
|
text={formData.enabled ? 'OSC IN Enabled' : 'OSC IN Disabled'}
|
|
actionHandler={() => handleChange('enabled', !formData.enabled)}
|
|
/>
|
|
</FormControl>
|
|
<FormControl id='portIn'>
|
|
<FormLabel htmlFor='portIn'>
|
|
OSC In Port
|
|
<span className={style.labelNote}>
|
|
<br />
|
|
Port - Default 8888
|
|
</span>
|
|
</FormLabel>
|
|
<Input
|
|
{...portInputProps}
|
|
name='port'
|
|
placeholder='8888'
|
|
value={formData.port}
|
|
onChange={(event) => handleChange('port', parseInt(event.target.value, 10))}
|
|
style={{ width: '6em' }}
|
|
/>
|
|
</FormControl>
|
|
</div>
|
|
<div className={style.hSeparator}>OSC Output (feedback)</div>
|
|
<div className={style.modalInline}>
|
|
<FormControl id='targetIP'>
|
|
<FormLabel htmlFor='targetIP'>
|
|
OSC Out Target IP
|
|
<span className={style.labelNote}>
|
|
<br />
|
|
Default 127.0.0.1
|
|
</span>
|
|
</FormLabel>
|
|
<Input
|
|
{...inputProps}
|
|
size='sm'
|
|
name='targetIP'
|
|
placeholder='127.0.0.1'
|
|
autoComplete='off'
|
|
value={formData.targetIP}
|
|
onChange={(event) => handleChange('targetIP', event.target.value)}
|
|
isDisabled={submitting}
|
|
style={{ width: '12em', textAlign: 'right' }}
|
|
/>
|
|
</FormControl>
|
|
<FormControl id='portOut'>
|
|
<FormLabel htmlFor='portOut'>
|
|
OSC Out Port
|
|
<span className={style.labelNote}>
|
|
<br />
|
|
Default 9999
|
|
</span>
|
|
</FormLabel>
|
|
<Input
|
|
{...portInputProps}
|
|
name='portOut'
|
|
placeholder='9999'
|
|
value={formData.portOut}
|
|
onChange={(event) => handleChange('portOut', parseInt(event.target.value, 10))}
|
|
style={{ width: '6em', textAlign: 'left' }}
|
|
/>
|
|
</FormControl>
|
|
</div>
|
|
<div className={style.blockNotes}>
|
|
<span className={style.inlineFlex}>
|
|
<IoInformationCircleOutline color='#2b6cb0' fontSize='2em' />
|
|
OSC Feedback messages
|
|
</span>
|
|
<span>
|
|
In future OSC feedback will be user defined. <br />
|
|
For now this is the list of OSC messages sent from ontime
|
|
</span>
|
|
<table>
|
|
<tbody>
|
|
<tr>
|
|
<td className={style.labelNote} style={{ width: '30%' }}>
|
|
Cycle
|
|
</td>
|
|
<td className={style.labelNote}>Message</td>
|
|
<td className={style.labelNote}>Value (example | type)</td>
|
|
</tr>
|
|
{oscCycleEndpoints.map((e) => (
|
|
<tr key={e.message}>
|
|
<td>{e.title}</td>
|
|
<td>{e.message}</td>
|
|
<td>{e.value}</td>
|
|
</tr>
|
|
))}
|
|
<tr>
|
|
<td className={style.labelNote} style={{ width: '30%' }}>
|
|
Trigger
|
|
</td>
|
|
<td className={style.labelNote}>Message</td>
|
|
<td className={style.labelNote}>Value (example | type)</td>
|
|
</tr>
|
|
{oscTriggerEndpoints.map((e) => (
|
|
<tr key={e.message}>
|
|
<td>{e.title}</td>
|
|
<td>{e.message}</td>
|
|
<td>{e.value}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<SubmitContainer revert={revert} submitting={submitting} changed={changed} status={status} />
|
|
</form>
|
|
</ModalBody>
|
|
);
|
|
}
|