-
-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
merge with automation service
- Loading branch information
Showing
18 changed files
with
1,234 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import axios from 'axios'; | ||
import type { | ||
Automation, | ||
AutomationBlueprint, | ||
AutomationBlueprintDTO, | ||
AutomationDTO, | ||
AutomationOutput, | ||
AutomationSettings, | ||
} from 'ontime-types'; | ||
|
||
import { apiEntryUrl } from './constants'; | ||
|
||
const automationsPath = `${apiEntryUrl}/automations`; | ||
|
||
/** | ||
* HTTP request to get the automations settings | ||
*/ | ||
export async function getAutomationSettings(): Promise<AutomationSettings> { | ||
const res = await axios.get(automationsPath); | ||
return res.data; | ||
} | ||
|
||
/** | ||
* HTTP request to edit the automations settings | ||
*/ | ||
export async function editAutomationSettings( | ||
automationSettings: Partial<AutomationSettings>, | ||
): Promise<AutomationSettings> { | ||
const res = await axios.post(automationsPath, automationSettings); | ||
return res.data; | ||
} | ||
|
||
/** | ||
* HTTP request to create a new automation | ||
*/ | ||
export async function addAutomation(automation: AutomationDTO): Promise<Automation> { | ||
const res = await axios.post(`${automationsPath}/automation`, automation); | ||
return res.data; | ||
} | ||
|
||
/** | ||
* HTTP request to update an automation | ||
*/ | ||
export async function editAutomation(id: string, automation: Automation): Promise<Automation> { | ||
const res = await axios.put(`${automationsPath}/automation/${id}`, automation); | ||
return res.data; | ||
} | ||
|
||
/** | ||
* HTTP request to delete an automation | ||
*/ | ||
export function deleteAutomation(id: string): Promise<void> { | ||
return axios.delete(`${automationsPath}/automation/${id}`); | ||
} | ||
|
||
/** | ||
* HTTP request to create a new blueprint | ||
*/ | ||
export async function addBlueprint(blueprint: AutomationBlueprintDTO): Promise<AutomationBlueprint> { | ||
const res = await axios.post(`${automationsPath}/blueprint`, blueprint); | ||
return res.data; | ||
} | ||
|
||
/** | ||
* HTTP request to update a blueprint | ||
*/ | ||
export async function editBlueprint(id: string, blueprint: AutomationBlueprint): Promise<AutomationBlueprint> { | ||
const res = await axios.put(`${automationsPath}/blueprint/${id}`, blueprint); | ||
return res.data; | ||
} | ||
|
||
/** | ||
* HTTP request to delete a blueprint | ||
*/ | ||
export function deleteBlueprint(id: string): Promise<void> { | ||
return axios.delete(`${automationsPath}/blueprint/${id}`); | ||
} | ||
|
||
/** | ||
* HTTP request to test automation output | ||
* The return is irrelevant as we care for the resolution of the promise | ||
*/ | ||
export async function testOutput(output: AutomationOutput): Promise<void> { | ||
return axios.post(automationsPath, output); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
...client/src/features/app-settings/panel/automations-panel/AutomationManagement.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.list { | ||
display: flex; | ||
flex-direction: column; | ||
gap: 3rem; | ||
} |
36 changes: 36 additions & 0 deletions
36
apps/client/src/features/app-settings/panel/automations-panel/AutomationPanel.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import useScrollIntoView from '../../../../common/hooks/useScrollIntoView'; | ||
import useAutomationSettings from '../../../../common/hooks-query/useAutomationSettings'; | ||
import type { PanelBaseProps } from '../../panel-list/PanelList'; | ||
import * as Panel from '../../panel-utils/PanelUtils'; | ||
|
||
import AutomationSettingsForm from './AutomationSettingsForm'; | ||
import AutomationsList from './AutomationsList'; | ||
import BlueprintsList from './BlueprintsList'; | ||
|
||
export default function AutomationPanel({ location }: PanelBaseProps) { | ||
const { data } = useAutomationSettings(); | ||
const settingsRef = useScrollIntoView<HTMLDivElement>('settings', location); | ||
const automationRef = useScrollIntoView<HTMLDivElement>('automations', location); | ||
const blueprintsRef = useScrollIntoView<HTMLDivElement>('blueprints', location); | ||
|
||
return ( | ||
<> | ||
<Panel.Header>Automation</Panel.Header> | ||
<Panel.Section> | ||
<div ref={settingsRef}> | ||
<AutomationSettingsForm | ||
enabledAutomations={data.enabledAutomations} | ||
enabledOscIn={data.enabledOscIn} | ||
oscPortIn={data.oscPortIn} | ||
/> | ||
</div> | ||
<div ref={automationRef}> | ||
<AutomationsList automations={data.automations} blueprints={data.blueprints} /> | ||
</div> | ||
<div ref={blueprintsRef}> | ||
<BlueprintsList blueprints={data.blueprints} /> | ||
</div> | ||
</Panel.Section> | ||
</> | ||
); | ||
} |
157 changes: 157 additions & 0 deletions
157
apps/client/src/features/app-settings/panel/automations-panel/AutomationSettingsForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import { Controller, useForm } from 'react-hook-form'; | ||
import { Alert, AlertDescription, AlertIcon, Button, Input, Switch } from '@chakra-ui/react'; | ||
|
||
import { editAutomationSettings } from '../../../../common/api/automation'; | ||
import { maybeAxiosError } from '../../../../common/api/utils'; | ||
import ExternalLink from '../../../../common/components/external-link/ExternalLink'; | ||
import { preventEscape } from '../../../../common/utils/keyEvent'; | ||
import { isOnlyNumbers } from '../../../../common/utils/regex'; | ||
import * as Panel from '../../panel-utils/PanelUtils'; | ||
|
||
const oscApiDocsUrl = 'https://docs.getontime.no/api/protocols/osc/'; | ||
|
||
interface AutomationSettingsProps { | ||
enabledAutomations: boolean; | ||
enabledOscIn: boolean; | ||
oscPortIn: number; | ||
} | ||
|
||
export default function AutomationSettingsForm(props: AutomationSettingsProps) { | ||
const { enabledAutomations, enabledOscIn, oscPortIn } = props; | ||
|
||
const { | ||
control, | ||
handleSubmit, | ||
reset, | ||
register, | ||
setError, | ||
formState: { errors, isSubmitting, isDirty, isValid }, | ||
} = useForm<AutomationSettingsProps>({ | ||
mode: 'onChange', | ||
defaultValues: { enabledAutomations, enabledOscIn, oscPortIn }, | ||
values: { enabledAutomations, enabledOscIn, oscPortIn }, | ||
resetOptions: { | ||
keepDirtyValues: true, | ||
}, | ||
}); | ||
|
||
const onSubmit = async (formData: AutomationSettingsProps) => { | ||
try { | ||
await editAutomationSettings(formData); | ||
} catch (error) { | ||
const message = maybeAxiosError(error); | ||
setError('root', { message }); | ||
} | ||
}; | ||
|
||
const onReset = () => { | ||
reset({ enabledAutomations, enabledOscIn, oscPortIn }); | ||
}; | ||
|
||
const canSubmit = !isSubmitting && isDirty && isValid; | ||
|
||
return ( | ||
<Panel.Card> | ||
<Panel.SubHeader> | ||
Automation settings | ||
<Panel.InlineSiblings> | ||
<Button variant='ontime-ghosted' size='sm' onClick={onReset} isDisabled={!canSubmit}> | ||
Revert to saved | ||
</Button> | ||
<Button | ||
variant='ontime-filled' | ||
size='sm' | ||
type='submit' | ||
form='automation-form' | ||
isDisabled={!canSubmit} | ||
isLoading={isSubmitting} | ||
> | ||
Save | ||
</Button> | ||
</Panel.InlineSiblings> | ||
</Panel.SubHeader> | ||
{errors?.root && <Panel.Error>{errors.root.message}</Panel.Error>} | ||
|
||
<Panel.Divider /> | ||
|
||
<Panel.Section> | ||
<Alert status='info' variant='ontime-on-dark-info'> | ||
<AlertIcon /> | ||
<AlertDescription> | ||
Control Ontime and share its data with external systems in your workflow. <br /> | ||
<br /> | ||
- Automations allow Ontime to send its data on lifecycle triggers. <br />- OSC Input tells Ontime to listen | ||
to messages on the specific port. <ExternalLink href={oscApiDocsUrl}>See the docs</ExternalLink> | ||
</AlertDescription> | ||
</Alert> | ||
</Panel.Section> | ||
|
||
<Panel.Section as='form' id='automation-form' onSubmit={handleSubmit(onSubmit)} onKeyDown={preventEscape}> | ||
<Panel.Loader isLoading={false} /> | ||
|
||
<Panel.Title>Automation</Panel.Title> | ||
<Panel.ListGroup> | ||
<Panel.ListItem> | ||
<Panel.Field | ||
title='Enable automations' | ||
description='Allow Ontime to send messages on lifecycle triggers' | ||
error={errors.enabledAutomations?.message} | ||
/> | ||
<Controller | ||
control={control} | ||
name='enabledAutomations' | ||
render={({ field: { onChange, value, ref } }) => ( | ||
<Switch variant='ontime' size='lg' isChecked={value} onChange={onChange} ref={ref} /> | ||
)} | ||
/> | ||
</Panel.ListItem> | ||
</Panel.ListGroup> | ||
|
||
<Panel.Title>OSC Input</Panel.Title> | ||
<Panel.ListGroup> | ||
<Panel.ListItem> | ||
<Panel.Field | ||
title='OSC input' | ||
description='Allow control of Ontime through OSC' | ||
error={errors.enabledOscIn?.message} | ||
/> | ||
<Controller | ||
control={control} | ||
name='enabledOscIn' | ||
render={({ field: { onChange, value, ref } }) => ( | ||
<Switch variant='ontime' size='lg' isChecked={value} onChange={onChange} ref={ref} /> | ||
)} | ||
/> | ||
</Panel.ListItem> | ||
<Panel.ListItem> | ||
<Panel.Field | ||
title='Listen on port' | ||
description='Port for incoming OSC. Default: 8888' | ||
error={errors.oscPortIn?.message} | ||
/> | ||
<Input | ||
id='oscPortIn' | ||
placeholder='8888' | ||
width='5rem' | ||
maxLength={5} | ||
size='sm' | ||
textAlign='right' | ||
variant='ontime-filled' | ||
type='number' | ||
autoComplete='off' | ||
{...register('oscPortIn', { | ||
required: { value: true, message: 'Required field' }, | ||
max: { value: 65535, message: 'Port must be within range 1024 - 65535' }, | ||
min: { value: 1024, message: 'Port must be within range 1024 - 65535' }, | ||
pattern: { | ||
value: isOnlyNumbers, | ||
message: 'Value should be numeric', | ||
}, | ||
})} | ||
/> | ||
</Panel.ListItem> | ||
</Panel.ListGroup> | ||
</Panel.Section> | ||
</Panel.Card> | ||
); | ||
} |
Oops, something went wrong.