mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-06 06:49:10 +00:00
refactor: subscription types and form register
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { isIPAddress, isOnlyNumbers } from '../regex';
|
import { isIPAddress, isOnlyNumbers, startsWithHttp } from '../regex';
|
||||||
|
|
||||||
describe('simple tests for regex', () => {
|
describe('simple tests for regex', () => {
|
||||||
test('isOnlyNumbers', () => {
|
test('isOnlyNumbers', () => {
|
||||||
@@ -24,4 +24,16 @@ describe('simple tests for regex', () => {
|
|||||||
expect(isIPAddress.test(t)).toBe(false);
|
expect(isIPAddress.test(t)).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('startsWithHttp', () => {
|
||||||
|
const right = ['http://test'];
|
||||||
|
const wrong = ['https://test', 'testing', '123.0.1'];
|
||||||
|
|
||||||
|
right.forEach((t) => {
|
||||||
|
expect(startsWithHttp.test(t)).toBe(true);
|
||||||
|
});
|
||||||
|
wrong.forEach((t) => {
|
||||||
|
expect(startsWithHttp.test(t)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
export const isOnlyNumbers = /^\d+$/;
|
export const isOnlyNumbers = /^\d+$/;
|
||||||
export const isIPAddress = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/;
|
export const isIPAddress = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/;
|
||||||
|
export const startsWithHttp = /^http:\/\//;
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import { ModalBody, Tab, TabList, TabPanel, TabPanels, Tabs } from '@chakra-ui/r
|
|||||||
|
|
||||||
import ModalWrapper from '../ModalWrapper';
|
import ModalWrapper from '../ModalWrapper';
|
||||||
|
|
||||||
import HttpIntegration from './HttpIntegration';
|
import HttpIntegration from './http/HttpIntegration';
|
||||||
import OscIntegration from './OscIntegration';
|
import OscIntegration from './osc/OscIntegration';
|
||||||
import OscSettings from './OscSettings';
|
import OscSettings from './osc/OscSettings';
|
||||||
|
|
||||||
import styles from '../Modal.module.scss';
|
import styles from '../Modal.module.scss';
|
||||||
|
|
||||||
|
|||||||
+17
-43
@@ -4,44 +4,15 @@ import { Switch } from '@chakra-ui/react';
|
|||||||
import type { HTTPSettings } from 'ontime-types';
|
import type { HTTPSettings } from 'ontime-types';
|
||||||
import { TimerLifeCycle } from 'ontime-types';
|
import { TimerLifeCycle } from 'ontime-types';
|
||||||
|
|
||||||
import { useHttpSettings, usePostHttpSettings } from '../../../common/hooks-query/useHttpSettings';
|
import { useHttpSettings, usePostHttpSettings } from '../../../../common/hooks-query/useHttpSettings';
|
||||||
import { useEmitLog } from '../../../common/stores/logger';
|
import { useEmitLog } from '../../../../common/stores/logger';
|
||||||
import ModalLoader from '../modal-loader/ModalLoader';
|
import ModalLoader from '../../modal-loader/ModalLoader';
|
||||||
import OntimeModalFooter from '../OntimeModalFooter';
|
import OntimeModalFooter from '../../OntimeModalFooter';
|
||||||
|
import { OntimeCycle, sectionText } from '../integration.utils';
|
||||||
|
|
||||||
import SubscriptionRow from './SubscriptionRow';
|
import HttpSubscriptionRow from './HttpSubscriptionRow';
|
||||||
|
|
||||||
import styles from '../Modal.module.scss';
|
import styles from '../../Modal.module.scss';
|
||||||
|
|
||||||
type OntimeCycle = keyof typeof TimerLifeCycle;
|
|
||||||
|
|
||||||
const placeholder = 'http://x.x.x.x:xxxx/api/path';
|
|
||||||
const sectionText: { [key in TimerLifeCycle]: { title: string; subtitle: string } } = {
|
|
||||||
onLoad: {
|
|
||||||
title: 'On Load',
|
|
||||||
subtitle: 'Triggers when a timer is loaded',
|
|
||||||
},
|
|
||||||
onStart: {
|
|
||||||
title: 'On Start',
|
|
||||||
subtitle: 'Triggers when a timer starts',
|
|
||||||
},
|
|
||||||
onPause: {
|
|
||||||
title: 'On Pause',
|
|
||||||
subtitle: 'Triggers when a running timer is paused',
|
|
||||||
},
|
|
||||||
onStop: {
|
|
||||||
title: 'On Stop',
|
|
||||||
subtitle: 'Triggers when a running timer is stopped',
|
|
||||||
},
|
|
||||||
onUpdate: {
|
|
||||||
title: 'On Every Second',
|
|
||||||
subtitle: 'Triggers when a running timer is updated (at least once a second, can be more)',
|
|
||||||
},
|
|
||||||
onFinish: {
|
|
||||||
title: 'On Finish',
|
|
||||||
subtitle: 'Triggers when a running reaches 0',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function HttpIntegration() {
|
export default function HttpIntegration() {
|
||||||
const { data, isFetching } = useHttpSettings();
|
const { data, isFetching } = useHttpSettings();
|
||||||
@@ -54,6 +25,7 @@ export default function HttpIntegration() {
|
|||||||
reset,
|
reset,
|
||||||
formState: { isSubmitting, isDirty, isValid },
|
formState: { isSubmitting, isDirty, isValid },
|
||||||
} = useForm<HTTPSettings>({
|
} = useForm<HTTPSettings>({
|
||||||
|
mode: 'onBlur',
|
||||||
defaultValues: data,
|
defaultValues: data,
|
||||||
values: data,
|
values: data,
|
||||||
resetOptions: {
|
resetOptions: {
|
||||||
@@ -87,7 +59,7 @@ export default function HttpIntegration() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('debug will submit', newSettings)
|
console.log('debug will submit', newSettings);
|
||||||
|
|
||||||
await mutateAsync(newSettings);
|
await mutateAsync(newSettings);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -98,6 +70,8 @@ export default function HttpIntegration() {
|
|||||||
if (isFetching) {
|
if (isFetching) {
|
||||||
return <ModalLoader />;
|
return <ModalLoader />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const placeholder = 'http://x.x.x.x:xxxx/api/path';
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className={styles.sectionContainer} id='http-subscriptions'>
|
<form onSubmit={handleSubmit(onSubmit)} className={styles.sectionContainer} id='http-subscriptions'>
|
||||||
<div className={styles.splitSection}>
|
<div className={styles.splitSection}>
|
||||||
@@ -107,7 +81,7 @@ export default function HttpIntegration() {
|
|||||||
</div>
|
</div>
|
||||||
<Switch {...register('enabledOut')} variant='ontime-on-light' />
|
<Switch {...register('enabledOut')} variant='ontime-on-light' />
|
||||||
</div>
|
</div>
|
||||||
<SubscriptionRow
|
<HttpSubscriptionRow
|
||||||
cycle={TimerLifeCycle.onLoad}
|
cycle={TimerLifeCycle.onLoad}
|
||||||
title={sectionText.onLoad.title}
|
title={sectionText.onLoad.title}
|
||||||
subtitle={sectionText.onLoad.subtitle}
|
subtitle={sectionText.onLoad.subtitle}
|
||||||
@@ -117,7 +91,7 @@ export default function HttpIntegration() {
|
|||||||
control={control}
|
control={control}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
<SubscriptionRow
|
<HttpSubscriptionRow
|
||||||
cycle={TimerLifeCycle.onStart}
|
cycle={TimerLifeCycle.onStart}
|
||||||
title={sectionText.onStart.title}
|
title={sectionText.onStart.title}
|
||||||
subtitle={sectionText.onStart.subtitle}
|
subtitle={sectionText.onStart.subtitle}
|
||||||
@@ -127,7 +101,7 @@ export default function HttpIntegration() {
|
|||||||
control={control}
|
control={control}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
<SubscriptionRow
|
<HttpSubscriptionRow
|
||||||
cycle={TimerLifeCycle.onPause}
|
cycle={TimerLifeCycle.onPause}
|
||||||
title={sectionText.onPause.title}
|
title={sectionText.onPause.title}
|
||||||
subtitle={sectionText.onPause.subtitle}
|
subtitle={sectionText.onPause.subtitle}
|
||||||
@@ -137,7 +111,7 @@ export default function HttpIntegration() {
|
|||||||
control={control}
|
control={control}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
<SubscriptionRow
|
<HttpSubscriptionRow
|
||||||
cycle={TimerLifeCycle.onStop}
|
cycle={TimerLifeCycle.onStop}
|
||||||
title={sectionText.onStop.title}
|
title={sectionText.onStop.title}
|
||||||
subtitle={sectionText.onStop.subtitle}
|
subtitle={sectionText.onStop.subtitle}
|
||||||
@@ -147,7 +121,7 @@ export default function HttpIntegration() {
|
|||||||
control={control}
|
control={control}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
<SubscriptionRow
|
<HttpSubscriptionRow
|
||||||
cycle={TimerLifeCycle.onUpdate}
|
cycle={TimerLifeCycle.onUpdate}
|
||||||
title={sectionText.onUpdate.title}
|
title={sectionText.onUpdate.title}
|
||||||
subtitle={sectionText.onUpdate.subtitle}
|
subtitle={sectionText.onUpdate.subtitle}
|
||||||
@@ -157,7 +131,7 @@ export default function HttpIntegration() {
|
|||||||
control={control}
|
control={control}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
<SubscriptionRow
|
<HttpSubscriptionRow
|
||||||
cycle={TimerLifeCycle.onFinish}
|
cycle={TimerLifeCycle.onFinish}
|
||||||
title={sectionText.onFinish.title}
|
title={sectionText.onFinish.title}
|
||||||
subtitle={sectionText.onFinish.subtitle}
|
subtitle={sectionText.onFinish.subtitle}
|
||||||
+11
-8
@@ -2,12 +2,13 @@ import { Control, useFieldArray, UseFormRegister } from 'react-hook-form';
|
|||||||
import { Button, IconButton, Input, Switch } from '@chakra-ui/react';
|
import { Button, IconButton, Input, Switch } from '@chakra-ui/react';
|
||||||
import { FiChevronUp } from '@react-icons/all-files/fi/FiChevronUp';
|
import { FiChevronUp } from '@react-icons/all-files/fi/FiChevronUp';
|
||||||
import { IoRemove } from '@react-icons/all-files/io5/IoRemove';
|
import { IoRemove } from '@react-icons/all-files/io5/IoRemove';
|
||||||
import { Subscription, TimerLifeCycle } from 'ontime-types';
|
import { HTTPSettings, TimerLifeCycle } from 'ontime-types';
|
||||||
|
|
||||||
import { useEmitLog } from '../../../common/stores/logger';
|
import { useEmitLog } from '../../../../common/stores/logger';
|
||||||
|
import { startsWithHttp } from '../../../../common/utils/regex';
|
||||||
|
|
||||||
import collapseStyles from '../../../common/components/collapse-bar/CollapseBar.module.scss';
|
import collapseStyles from '../../../../common/components/collapse-bar/CollapseBar.module.scss';
|
||||||
import styles from '../Modal.module.scss';
|
import styles from '../../Modal.module.scss';
|
||||||
|
|
||||||
interface SubscriptionRowProps {
|
interface SubscriptionRowProps {
|
||||||
cycle: TimerLifeCycle;
|
cycle: TimerLifeCycle;
|
||||||
@@ -15,8 +16,8 @@ interface SubscriptionRowProps {
|
|||||||
subtitle: string;
|
subtitle: string;
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
setShowSection: (cycle: TimerLifeCycle) => void;
|
setShowSection: (cycle: TimerLifeCycle) => void;
|
||||||
register: UseFormRegister<Subscription>;
|
register: UseFormRegister<HTTPSettings>;
|
||||||
control: Control<Subscription>;
|
control: Control<HTTPSettings>;
|
||||||
placeholder: string;
|
placeholder: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ export default function SubscriptionRow(props: SubscriptionRowProps) {
|
|||||||
const { cycle, title, subtitle, visible, setShowSection, register, control, placeholder } = props;
|
const { cycle, title, subtitle, visible, setShowSection, register, control, placeholder } = props;
|
||||||
const { emitError } = useEmitLog();
|
const { emitError } = useEmitLog();
|
||||||
const { fields, append, remove } = useFieldArray({
|
const { fields, append, remove } = useFieldArray({
|
||||||
name: cycle,
|
name: `subscriptions.${cycle}`,
|
||||||
control,
|
control,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -69,7 +70,9 @@ export default function SubscriptionRow(props: SubscriptionRowProps) {
|
|||||||
size='xs'
|
size='xs'
|
||||||
variant='ontime-filled-on-light'
|
variant='ontime-filled-on-light'
|
||||||
autoComplete='off'
|
autoComplete='off'
|
||||||
{...register(`subscriptions.${cycle}.${index}.message`)}
|
{...register(`subscriptions.${cycle}.${index}.message`, {
|
||||||
|
pattern: { value: startsWithHttp, message: 'Request address must start with http://' },
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
<Switch variant='ontime-on-light' {...register(`subscriptions.${cycle}.${index}.enabled`)} />
|
<Switch variant='ontime-on-light' {...register(`subscriptions.${cycle}.${index}.enabled`)} />
|
||||||
</div>
|
</div>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { TimerLifeCycle } from 'ontime-types';
|
||||||
|
|
||||||
|
export type OntimeCycle = keyof typeof TimerLifeCycle;
|
||||||
|
|
||||||
|
export const sectionText: { [key in TimerLifeCycle]: { title: string; subtitle: string } } = {
|
||||||
|
onLoad: {
|
||||||
|
title: 'On Load',
|
||||||
|
subtitle: 'Triggers when a timer is loaded',
|
||||||
|
},
|
||||||
|
onStart: {
|
||||||
|
title: 'On Start',
|
||||||
|
subtitle: 'Triggers when a timer starts',
|
||||||
|
},
|
||||||
|
onPause: {
|
||||||
|
title: 'On Pause',
|
||||||
|
subtitle: 'Triggers when a running timer is paused',
|
||||||
|
},
|
||||||
|
onStop: {
|
||||||
|
title: 'On Stop',
|
||||||
|
subtitle: 'Triggers when a running timer is stopped',
|
||||||
|
},
|
||||||
|
onUpdate: {
|
||||||
|
title: 'On Every Second',
|
||||||
|
subtitle: 'Triggers when a running timer is updated (at least once a second, can be more)',
|
||||||
|
},
|
||||||
|
onFinish: {
|
||||||
|
title: 'On Finish',
|
||||||
|
subtitle: 'Triggers when a running reaches 0',
|
||||||
|
},
|
||||||
|
};
|
||||||
+17
-44
@@ -1,45 +1,17 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import type { Subscription } from 'ontime-types';
|
import type { OscSubscription } from 'ontime-types';
|
||||||
import { TimerLifeCycle } from 'ontime-types';
|
import { TimerLifeCycle } from 'ontime-types';
|
||||||
|
|
||||||
import useOscSettings, { usePostOscSubscriptions } from '../../../common/hooks-query/useOscSettings';
|
import useOscSettings, { usePostOscSubscriptions } from '../../../../common/hooks-query/useOscSettings';
|
||||||
import { useEmitLog } from '../../../common/stores/logger';
|
import { useEmitLog } from '../../../../common/stores/logger';
|
||||||
import ModalLoader from '../modal-loader/ModalLoader';
|
import ModalLoader from '../../modal-loader/ModalLoader';
|
||||||
import OntimeModalFooter from '../OntimeModalFooter';
|
import OntimeModalFooter from '../../OntimeModalFooter';
|
||||||
|
import { type OntimeCycle, sectionText } from '../integration.utils';
|
||||||
|
|
||||||
import SubscriptionRow from './SubscriptionRow';
|
import OscSubscriptionRow from './OscSubscriptionRow';
|
||||||
|
|
||||||
import styles from '../Modal.module.scss';
|
import styles from '../../Modal.module.scss';
|
||||||
|
|
||||||
type OntimeCycle = keyof typeof TimerLifeCycle;
|
|
||||||
|
|
||||||
const sectionText: { [key in TimerLifeCycle]: { title: string; subtitle: string } } = {
|
|
||||||
onLoad: {
|
|
||||||
title: 'On Load',
|
|
||||||
subtitle: 'Triggers when a timer is loaded',
|
|
||||||
},
|
|
||||||
onStart: {
|
|
||||||
title: 'On Start',
|
|
||||||
subtitle: 'Triggers when a timer starts',
|
|
||||||
},
|
|
||||||
onPause: {
|
|
||||||
title: 'On Pause',
|
|
||||||
subtitle: 'Triggers when a running timer is paused',
|
|
||||||
},
|
|
||||||
onStop: {
|
|
||||||
title: 'On Stop',
|
|
||||||
subtitle: 'Triggers when a running timer is stopped',
|
|
||||||
},
|
|
||||||
onUpdate: {
|
|
||||||
title: 'On Every Second',
|
|
||||||
subtitle: 'Triggers when a running timer is updated (at least once a second, can be more)',
|
|
||||||
},
|
|
||||||
onFinish: {
|
|
||||||
title: 'On Finish',
|
|
||||||
subtitle: 'Triggers when a running reaches 0',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function OscIntegration() {
|
export default function OscIntegration() {
|
||||||
const { data, isFetching } = useOscSettings();
|
const { data, isFetching } = useOscSettings();
|
||||||
@@ -51,7 +23,7 @@ export default function OscIntegration() {
|
|||||||
register,
|
register,
|
||||||
reset,
|
reset,
|
||||||
formState: { isSubmitting, isDirty, isValid },
|
formState: { isSubmitting, isDirty, isValid },
|
||||||
} = useForm<Subscription>({
|
} = useForm<OscSubscription>({
|
||||||
defaultValues: data.subscriptions,
|
defaultValues: data.subscriptions,
|
||||||
values: data.subscriptions,
|
values: data.subscriptions,
|
||||||
resetOptions: {
|
resetOptions: {
|
||||||
@@ -71,7 +43,7 @@ export default function OscIntegration() {
|
|||||||
reset(data.subscriptions);
|
reset(data.subscriptions);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = async (values: Subscription) => {
|
const onSubmit = async (values: OscSubscription) => {
|
||||||
try {
|
try {
|
||||||
const subscriptions = {
|
const subscriptions = {
|
||||||
onLoad: values.onLoad ?? [],
|
onLoad: values.onLoad ?? [],
|
||||||
@@ -91,10 +63,11 @@ export default function OscIntegration() {
|
|||||||
if (isFetching) {
|
if (isFetching) {
|
||||||
return <ModalLoader />;
|
return <ModalLoader />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const placeholder = 'OSC message';
|
const placeholder = 'OSC message';
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className={styles.sectionContainer} id='osc-subscriptions'>
|
<form onSubmit={handleSubmit(onSubmit)} className={styles.sectionContainer} id='osc-subscriptions'>
|
||||||
<SubscriptionRow
|
<OscSubscriptionRow
|
||||||
cycle={TimerLifeCycle.onLoad}
|
cycle={TimerLifeCycle.onLoad}
|
||||||
title={sectionText.onLoad.title}
|
title={sectionText.onLoad.title}
|
||||||
subtitle={sectionText.onLoad.subtitle}
|
subtitle={sectionText.onLoad.subtitle}
|
||||||
@@ -104,7 +77,7 @@ export default function OscIntegration() {
|
|||||||
control={control}
|
control={control}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
<SubscriptionRow
|
<OscSubscriptionRow
|
||||||
cycle={TimerLifeCycle.onStart}
|
cycle={TimerLifeCycle.onStart}
|
||||||
title={sectionText.onStart.title}
|
title={sectionText.onStart.title}
|
||||||
subtitle={sectionText.onStart.subtitle}
|
subtitle={sectionText.onStart.subtitle}
|
||||||
@@ -114,7 +87,7 @@ export default function OscIntegration() {
|
|||||||
control={control}
|
control={control}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
<SubscriptionRow
|
<OscSubscriptionRow
|
||||||
cycle={TimerLifeCycle.onPause}
|
cycle={TimerLifeCycle.onPause}
|
||||||
title={sectionText.onPause.title}
|
title={sectionText.onPause.title}
|
||||||
subtitle={sectionText.onPause.subtitle}
|
subtitle={sectionText.onPause.subtitle}
|
||||||
@@ -124,7 +97,7 @@ export default function OscIntegration() {
|
|||||||
control={control}
|
control={control}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
<SubscriptionRow
|
<OscSubscriptionRow
|
||||||
cycle={TimerLifeCycle.onStop}
|
cycle={TimerLifeCycle.onStop}
|
||||||
title={sectionText.onStop.title}
|
title={sectionText.onStop.title}
|
||||||
subtitle={sectionText.onStop.subtitle}
|
subtitle={sectionText.onStop.subtitle}
|
||||||
@@ -134,7 +107,7 @@ export default function OscIntegration() {
|
|||||||
control={control}
|
control={control}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
<SubscriptionRow
|
<OscSubscriptionRow
|
||||||
cycle={TimerLifeCycle.onUpdate}
|
cycle={TimerLifeCycle.onUpdate}
|
||||||
title={sectionText.onUpdate.title}
|
title={sectionText.onUpdate.title}
|
||||||
subtitle={sectionText.onUpdate.subtitle}
|
subtitle={sectionText.onUpdate.subtitle}
|
||||||
@@ -144,7 +117,7 @@ export default function OscIntegration() {
|
|||||||
control={control}
|
control={control}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
<SubscriptionRow
|
<OscSubscriptionRow
|
||||||
cycle={TimerLifeCycle.onFinish}
|
cycle={TimerLifeCycle.onFinish}
|
||||||
title={sectionText.onFinish.title}
|
title={sectionText.onFinish.title}
|
||||||
subtitle={sectionText.onFinish.subtitle}
|
subtitle={sectionText.onFinish.subtitle}
|
||||||
+7
-7
@@ -4,14 +4,14 @@ import { useEffect } from 'react';
|
|||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { FormControl, Input, Switch } from '@chakra-ui/react';
|
import { FormControl, Input, Switch } from '@chakra-ui/react';
|
||||||
|
|
||||||
import useOscSettings, { useOscSettingsMutation } from '../../../common/hooks-query/useOscSettings';
|
import useOscSettings, { useOscSettingsMutation } from '../../../../common/hooks-query/useOscSettings';
|
||||||
import { PlaceholderSettings } from '../../../common/models/OscSettings';
|
import { PlaceholderSettings } from '../../../../common/models/OscSettings';
|
||||||
import { useEmitLog } from '../../../common/stores/logger';
|
import { useEmitLog } from '../../../../common/stores/logger';
|
||||||
import { isIPAddress, isOnlyNumbers } from '../../../common/utils/regex';
|
import { isIPAddress, isOnlyNumbers } from '../../../../common/utils/regex';
|
||||||
import ModalLoader from '../modal-loader/ModalLoader';
|
import ModalLoader from '../../modal-loader/ModalLoader';
|
||||||
import OntimeModalFooter from '../OntimeModalFooter';
|
import OntimeModalFooter from '../../OntimeModalFooter';
|
||||||
|
|
||||||
import styles from '../Modal.module.scss';
|
import styles from '../../Modal.module.scss';
|
||||||
|
|
||||||
export default function OscSettings() {
|
export default function OscSettings() {
|
||||||
const { data, isFetching } = useOscSettings();
|
const { data, isFetching } = useOscSettings();
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
import { Control, useFieldArray, UseFormRegister } from 'react-hook-form';
|
||||||
|
import { Button, IconButton, Input, Switch } from '@chakra-ui/react';
|
||||||
|
import { FiChevronUp } from '@react-icons/all-files/fi/FiChevronUp';
|
||||||
|
import { IoRemove } from '@react-icons/all-files/io5/IoRemove';
|
||||||
|
import type { OscSubscription, TimerLifeCycle } from 'ontime-types';
|
||||||
|
|
||||||
|
import { useEmitLog } from '../../../../common/stores/logger';
|
||||||
|
|
||||||
|
import collapseStyles from '../../../../common/components/collapse-bar/CollapseBar.module.scss';
|
||||||
|
import styles from '../../Modal.module.scss';
|
||||||
|
|
||||||
|
interface OscSubscriptionRowProps {
|
||||||
|
cycle: TimerLifeCycle;
|
||||||
|
title: string;
|
||||||
|
subtitle: string;
|
||||||
|
visible: boolean;
|
||||||
|
setShowSection: (cycle: TimerLifeCycle) => void;
|
||||||
|
register: UseFormRegister<OscSubscription>;
|
||||||
|
control: Control<OscSubscription>;
|
||||||
|
placeholder: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function OscSubscriptionRow(props: OscSubscriptionRowProps) {
|
||||||
|
const { cycle, title, subtitle, visible, setShowSection, register, control, placeholder } = props;
|
||||||
|
const { emitError } = useEmitLog();
|
||||||
|
const { fields, append, remove } = useFieldArray({
|
||||||
|
name: cycle,
|
||||||
|
control,
|
||||||
|
});
|
||||||
|
|
||||||
|
const hasTooManyOptions = fields.length >= 3;
|
||||||
|
const headerStyle = `${styles.splitSection} ${visible ? '' : styles.showPointer}`;
|
||||||
|
|
||||||
|
const sectionTitle = `${title} ${fields.length ? fields.length : '-'} / 3`;
|
||||||
|
|
||||||
|
const handleAddNew = () => {
|
||||||
|
if (hasTooManyOptions) {
|
||||||
|
emitError('Maximum amount of onLoad subscriptions reached (3)');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
append({
|
||||||
|
message: '',
|
||||||
|
enabled: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={headerStyle} onClick={() => setShowSection(cycle)}>
|
||||||
|
<div>
|
||||||
|
<span className={`${styles.sectionTitle} ${styles.main}`}>{sectionTitle}</span>
|
||||||
|
{visible && <span className={styles.sectionSubtitle}>{subtitle}</span>}
|
||||||
|
</div>
|
||||||
|
<FiChevronUp className={visible ? collapseStyles.moreCollapsed : collapseStyles.moreExpanded} />
|
||||||
|
</div>
|
||||||
|
{visible && (
|
||||||
|
<>
|
||||||
|
{fields.map((subscription, index) => (
|
||||||
|
<div key={subscription.id} className={styles.entryRow}>
|
||||||
|
<IconButton
|
||||||
|
icon={<IoRemove />}
|
||||||
|
onClick={() => remove(index)}
|
||||||
|
aria-label='delete'
|
||||||
|
size='xs'
|
||||||
|
colorScheme='red'
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
placeholder={placeholder}
|
||||||
|
size='xs'
|
||||||
|
variant='ontime-filled-on-light'
|
||||||
|
autoComplete='off'
|
||||||
|
{...register(`${cycle}.${index}.message`)}
|
||||||
|
/>
|
||||||
|
<Switch variant='ontime-on-light' {...register(`${cycle}.${index}.enabled`)} />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<Button
|
||||||
|
onClick={handleAddNew}
|
||||||
|
className={styles.shiftRight}
|
||||||
|
isDisabled={hasTooManyOptions}
|
||||||
|
size='xs'
|
||||||
|
colorScheme='blue'
|
||||||
|
variant='outline'
|
||||||
|
padding='0 2em'
|
||||||
|
>
|
||||||
|
Add new
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
import { Subscription } from './Subscription.type.js';
|
import { Subscription } from './Subscription.type.js';
|
||||||
|
|
||||||
|
type HttpSubscriptionOptions = { message: string; enabled: boolean };
|
||||||
|
export type HttpSubscription = Subscription<HttpSubscriptionOptions>;
|
||||||
|
|
||||||
export interface HTTPSettings {
|
export interface HTTPSettings {
|
||||||
enabledOut: boolean;
|
enabledOut: boolean;
|
||||||
subscriptions: Subscription;
|
subscriptions: HttpSubscription;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import { Subscription } from './Subscription.type.js';
|
import { Subscription } from './Subscription.type.js';
|
||||||
|
|
||||||
|
type OscSubscriptionOptions = { message: string; enabled: boolean };
|
||||||
|
export type OscSubscription = Subscription<OscSubscriptionOptions>;
|
||||||
|
|
||||||
export interface OSCSettings {
|
export interface OSCSettings {
|
||||||
portIn: number;
|
portIn: number;
|
||||||
portOut: number;
|
portOut: number;
|
||||||
targetIP: string;
|
targetIP: string;
|
||||||
enabledIn: boolean;
|
enabledIn: boolean;
|
||||||
enabledOut: boolean;
|
enabledOut: boolean;
|
||||||
subscriptions: Subscription;
|
subscriptions: OscSubscription;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { TimerLifeCycleKey } from './TimerLifecycle.type.js';
|
import { TimerLifeCycleKey } from './TimerLifecycle.type.js';
|
||||||
|
|
||||||
export type SubscriptionOptions = { message: string; enabled: boolean };
|
export type Subscription<T> = { [key in TimerLifeCycleKey]: T[] };
|
||||||
export type Subscription = { [key in TimerLifeCycleKey]: SubscriptionOptions[] };
|
|
||||||
|
|||||||
@@ -29,11 +29,12 @@ export type { Alias } from './definitions/core/Alias.type.js';
|
|||||||
export type { UserFields } from './definitions/core/UserFields.type.js';
|
export type { UserFields } from './definitions/core/UserFields.type.js';
|
||||||
|
|
||||||
// ---> Integration, Subscription
|
// ---> Integration, Subscription
|
||||||
export type { Subscription, SubscriptionOptions } from './definitions/core/Subscription.type.js';
|
export type { Subscription } from './definitions/core/Subscription.type.js';
|
||||||
|
|
||||||
// ---> OSC
|
// ---> OSC
|
||||||
export type { OSCSettings } from './definitions/core/OscSettings.type.js';
|
export type { OSCSettings, OscSubscription } from './definitions/core/OscSettings.type.js';
|
||||||
// ---> HTTP
|
// ---> HTTP
|
||||||
export type { HTTPSettings } from './definitions/core/HttpSettings.type.js';
|
export type { HTTPSettings, HttpSubscription } from './definitions/core/HttpSettings.type.js';
|
||||||
|
|
||||||
// SERVER RESPONSES
|
// SERVER RESPONSES
|
||||||
export type { NetworkInterface, GetInfo } from './api/ontime-controller/BackendResponse.type.js';
|
export type { NetworkInterface, GetInfo } from './api/ontime-controller/BackendResponse.type.js';
|
||||||
|
|||||||
Reference in New Issue
Block a user