From 1e930851ca8b8465596692e0c74fef546af7ad4d Mon Sep 17 00:00:00 2001 From: arc-alex Date: Sat, 4 Nov 2023 20:37:22 +0100 Subject: [PATCH] add http subscription to integration modal --- apps/client/src/common/api/apiConstants.ts | 1 + apps/client/src/common/api/ontimeApi.ts | 22 ++- .../src/common/hooks-query/useHttpSettings.ts | 34 ++++ .../integration-modal/HttpIntegration.tsx | 167 ++++++++++++++++++ .../integration-modal/IntegrationModal.tsx | 6 + 5 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 apps/client/src/common/hooks-query/useHttpSettings.ts create mode 100644 apps/client/src/features/modals/integration-modal/HttpIntegration.tsx diff --git a/apps/client/src/common/api/apiConstants.ts b/apps/client/src/common/api/apiConstants.ts index f3a19e46f..382f5c321 100644 --- a/apps/client/src/common/api/apiConstants.ts +++ b/apps/client/src/common/api/apiConstants.ts @@ -6,6 +6,7 @@ export const RUNDOWN_TABLE_KEY = 'rundown'; export const RUNDOWN_TABLE = [RUNDOWN_TABLE_KEY]; export const APP_INFO = ['appinfo']; export const OSC_SETTINGS = ['oscSettings']; +export const HTTP_SETTINGS = ['httpSettings']; export const APP_SETTINGS = ['appSettings']; export const VIEW_SETTINGS = ['viewSettings']; export const RUNTIME = ['runtimeStore']; diff --git a/apps/client/src/common/api/ontimeApi.ts b/apps/client/src/common/api/ontimeApi.ts index 11bef96a8..d8ed89ec6 100644 --- a/apps/client/src/common/api/ontimeApi.ts +++ b/apps/client/src/common/api/ontimeApi.ts @@ -93,6 +93,18 @@ export async function getOSC(): Promise { return res.data; } +/** + * @description HTTP request to retrieve http settings + * @return {Promise} + */ +export async function getHTTP(): Promise { + console.log('getHTTP') + const res = await axios.get(`${ontimeURL}/http`); + console.log(res) + + return res.data; +} + /** * @description HTTP request to mutate osc settings * @return {Promise} @@ -105,10 +117,18 @@ export async function postOSC(data: OSCSettings) { * @description HTTP request to mutate osc subscriptions * @return {Promise} */ -export async function postOscSubscriptions(data: OscSubscription) { +export async function postOscSubscriptions(data: Subscription) { return axios.post(`${ontimeURL}/osc-subscriptions`, data); } +/** + * @description HTTP request to mutate osc subscriptions + * @return {Promise} + */ +export async function postHttpSubscriptions(data: Subscription) { + return axios.post(`${ontimeURL}/http-subscriptions`, data); +} + /** * @description HTTP request to download db in CSV format */ diff --git a/apps/client/src/common/hooks-query/useHttpSettings.ts b/apps/client/src/common/hooks-query/useHttpSettings.ts new file mode 100644 index 000000000..8144e46bb --- /dev/null +++ b/apps/client/src/common/hooks-query/useHttpSettings.ts @@ -0,0 +1,34 @@ +import { useMutation, useQuery } from '@tanstack/react-query'; +import { HTTPSettings } from 'ontime-types'; + +import { queryRefetchIntervalSlow } from '../../ontimeConfig'; +import { HTTP_SETTINGS } from '../api/apiConstants'; +import { logAxiosError } from '../api/apiUtils'; +import { getHTTP, postHttpSubscriptions } from '../api/ontimeApi'; +import { httpPlaceholder } from '../models/Http'; +import { ontimeQueryClient } from '../queryClient'; + +export default function useHttpSettings() { + const { data, status, isFetching, isError, refetch } = useQuery({ + queryKey: HTTP_SETTINGS, + queryFn: getHTTP, + placeholderData: httpPlaceholder, + retry: 5, + retryDelay: (attempt: number) => attempt * 2500, + refetchInterval: queryRefetchIntervalSlow, + networkMode: 'always', + }); + + // we need to jump through some hoops because of the type op port + return { data: data! as unknown as HTTPSettings, status, isFetching, isError, refetch }; +} + + +export function usePostHttpSubscriptions() { + const { isLoading, mutateAsync } = useMutation({ + mutationFn: postHttpSubscriptions, + onError: (error) => logAxiosError('Error saving HTTP settings', error), + onSettled: () => ontimeQueryClient.invalidateQueries({ queryKey: HTTP_SETTINGS }), + }); + return { isLoading, mutateAsync }; +} diff --git a/apps/client/src/features/modals/integration-modal/HttpIntegration.tsx b/apps/client/src/features/modals/integration-modal/HttpIntegration.tsx new file mode 100644 index 000000000..45d5670db --- /dev/null +++ b/apps/client/src/features/modals/integration-modal/HttpIntegration.tsx @@ -0,0 +1,167 @@ +import { useEffect, useState } from 'react'; +import { useForm } from 'react-hook-form'; +import type { Subscription } from 'ontime-types'; +import { TimerLifeCycle } from 'ontime-types'; + +import useHttpSettings, { usePostHttpSubscriptions } from '../../../common/hooks-query/useHttpSettings'; +import { useEmitLog } from '../../../common/stores/logger'; +import ModalLoader from '../modal-loader/ModalLoader'; +import OntimeModalFooter from '../OntimeModalFooter'; + +import SubscriptionRow from './SubscriptionRow'; + +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 HttpIntegration() { + const { data, isFetching } = useHttpSettings(); + const { mutateAsync } = usePostHttpSubscriptions(); + const { emitError } = useEmitLog(); + const { + control, + handleSubmit, + register, + reset, + formState: { isSubmitting, isDirty, isValid }, + } = useForm({ + defaultValues: data.subscriptions, + values: data.subscriptions, + resetOptions: { + keepDirtyValues: true, + }, + }); + + const [showSection, setShowSection] = useState(TimerLifeCycle.onLoad); + + useEffect(() => { + if (data) { + reset(data.subscriptions); + } + }, [data, reset]); + + const resetForm = () => { + reset(data.subscriptions); + }; + + const onSubmit = async (values: Subscription) => { + try { + const subscriptions = { + onLoad: values.onLoad ?? [], + onStart: values.onStart ?? [], + onPause: values.onPause ?? [], + onStop: values.onStop ?? [], + onUpdate: values.onUpdate ?? [], + onFinish: values.onFinish ?? [], + }; + + await mutateAsync(subscriptions); + } catch (error) { + emitError(`Error setting HTML: ${error}`); + } + }; + + if (isFetching) { + return ; + } + const placeholder = 'http://x.x.x.x:xxxx/api/path' + + return ( +
+ + + + + + + + + ); +} diff --git a/apps/client/src/features/modals/integration-modal/IntegrationModal.tsx b/apps/client/src/features/modals/integration-modal/IntegrationModal.tsx index e71e3fb19..aa85a1af5 100644 --- a/apps/client/src/features/modals/integration-modal/IntegrationModal.tsx +++ b/apps/client/src/features/modals/integration-modal/IntegrationModal.tsx @@ -5,6 +5,8 @@ import ModalWrapper from '../ModalWrapper'; import OscIntegration from './OscIntegration'; import OscSettings from './OscSettings'; +import HttpIntegration from './HttpIntegration'; + import styles from '../Modal.module.scss'; interface IntegrationModalProps { @@ -30,6 +32,7 @@ export default function IntegrationModal(props: IntegrationModalProps) { OSC OSC Integration + HTML Integration @@ -38,6 +41,9 @@ export default function IntegrationModal(props: IntegrationModalProps) { + + +