Skip to content

Commit

Permalink
feat: add support for HTTP Send devices
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Van Camp committed May 5, 2022
1 parent b06371f commit 32a7695
Show file tree
Hide file tree
Showing 19 changed files with 264 additions and 51 deletions.
17 changes: 17 additions & 0 deletions apps/app/src/electron/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import {
TimelineObjVMixPreview,
TimelineObjOSCMessage,
TimelineContentTypeOSC,
TimelineObjHTTPRequest,
TimelineContentTypeHTTP,
} from 'timeline-state-resolver-types'
import { ResourceAny, ResourceType } from '@shared/models'
import { assertNever, literal } from '@shared/lib'
Expand Down Expand Up @@ -522,6 +524,21 @@ export function TSRTimelineObjFromResource(resource: ResourceAny): TSRTimelineOb
values: [],
},
})
} else if (resource.resourceType === ResourceType.HTTP_REQUEST) {
return literal<TimelineObjHTTPRequest>({
id: shortID(),
layer: '', // set later
enable: {
start: 0,
duration: 1 * 1000,
},
content: {
deviceType: DeviceType.HTTPSEND,
type: TimelineContentTypeHTTP.POST,
url: 'http://127.0.0.1:80',
params: {},
},
})
} else {
assertNever(resource)
// @ts-expect-error never
Expand Down
2 changes: 2 additions & 0 deletions apps/app/src/lib/TimelineObj.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ export function describeTimelineObject(obj: TSRTimelineObj, duration?: number) {
}
} else if (obj.content.deviceType === DeviceType.OSC) {
label = obj.content.path
} else if (obj.content.deviceType === DeviceType.HTTPSEND) {
label = `${obj.content.type.toUpperCase()} ${obj.content.url}`
} else {
// todo: for later:
// assertNever(obj.content)
Expand Down
3 changes: 1 addition & 2 deletions apps/app/src/lib/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -395,8 +395,7 @@ export function allowAddingResourceToLayer(project: Project, resource: ResourceA
resource.resourceType === ResourceType.CASPARCG_TEMPLATE
)
} else if (mapping.device === DeviceType.HTTPSEND) {
// @TODO
return false
return resource.resourceType === ResourceType.HTTP_REQUEST
} else if (mapping.device === DeviceType.HTTPWATCHER) {
// @TODO
return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
DeviceOptionsAny,
DeviceOptionsAtem,
DeviceOptionsCasparCG,
DeviceOptionsHTTPSend,
DeviceOptionsOBS,
DeviceOptionsOSC,
DeviceOptionsVMix,
Expand Down Expand Up @@ -97,6 +98,15 @@ export function NewDeviceDialog({ open, onAccepted, onDiscarded, bridge }: INewD
break
}

case DeviceType.HTTPSEND: {
newDevice = literal<DeviceOptionsHTTPSend>({
type: DeviceType.HTTPSEND,
options: {},
})

break
}

// @TODO: Add more device types

default:
Expand Down Expand Up @@ -163,6 +173,7 @@ export function NewDeviceDialog({ open, onAccepted, onDiscarded, bridge }: INewD
<MenuItem value={DeviceType.OBS}>OBS</MenuItem>
<MenuItem value={DeviceType.VMIX}>vMix</MenuItem>
<MenuItem value={DeviceType.OSC}>OSC</MenuItem>
<MenuItem value={DeviceType.HTTPSEND}>HTTP Send</MenuItem>
{/* @TODO: More device types */}
</TextField>
</DialogContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export const DeviceIcon: React.FC<{ type: DeviceType }> = (props) => {
case DeviceType.OSC:
iconElement = <span>OSC</span>
break
case DeviceType.HTTPSEND:
iconElement = <span>HTTP</span>
break
default:
iconElement = <span>{props.type}</span>
break
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.device-icon {
display: flex;
align-items: center;
width: 40px;

img {
max-height: 2rem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,48 +139,52 @@ export const DeviceItemContent: React.FC<{
autoFocus={!editedDeviceName}
/>
</div>
<div className="form-control">
<TextField
label="URL"
value={host}
size="small"
margin="dense"
onChange={(event) => {
setHost(event.target.value)
}}
onBlur={() => {
handleHostChange(host)
}}
onKeyUp={(e) => {
if (e.key === 'Enter') {
handleHostChange(host)
;(document.activeElement as HTMLInputElement).blur()
}
}}
/>
</div>
<div className="form-control">
<TextField
label="Port"
value={port}
size="small"
margin="dense"
type="number"
InputProps={{ inputProps: { min: MIN_PORT, max: MAX_PORT } }}
onChange={(event) => {
setPort(parseInt(event.target.value, 10))
}}
onBlur={() => {
handlePortChange(port)
}}
onKeyUp={(e) => {
if (e.key === 'Enter') {
handlePortChange(port)
;(document.activeElement as HTMLInputElement).blur()
}
}}
/>
</div>
{deviceSettings.type !== DeviceType.HTTPSEND && (
<>
<div className="form-control">
<TextField
label="URL"
value={host}
size="small"
margin="dense"
onChange={(event) => {
setHost(event.target.value)
}}
onBlur={() => {
handleHostChange(host)
}}
onKeyUp={(e) => {
if (e.key === 'Enter') {
handleHostChange(host)
;(document.activeElement as HTMLInputElement).blur()
}
}}
/>
</div>
<div className="form-control">
<TextField
label="Port"
value={port}
size="small"
margin="dense"
type="number"
InputProps={{ inputProps: { min: MIN_PORT, max: MAX_PORT } }}
onChange={(event) => {
setPort(parseInt(event.target.value, 10))
}}
onBlur={() => {
handlePortChange(port)
}}
onKeyUp={(e) => {
if (e.key === 'Enter') {
handlePortChange(port)
;(document.activeElement as HTMLInputElement).blur()
}
}}
/>
</div>
</>
)}
{deviceSettings.type === DeviceType.OBS ? (
<div className="form-control">
<TextField
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'
import { Bridge, BridgeDevice } from '../../../../../models/project/Bridge'
import { AtemOptions, CasparCGOptions } from 'timeline-state-resolver-types'
import { AtemOptions, CasparCGOptions, DeviceType } from 'timeline-state-resolver-types'

import './style.scss'
import { DeviceShortcut } from '../deviceShorcut/DeviceShortcut'
Expand All @@ -21,7 +21,10 @@ export const DeviceItemHeader: React.FC<{
if (!deviceOptions) {
return null
}
const deviceAddress = `${deviceOptions.host}:${deviceOptions.port}`
let deviceAddress = `${deviceOptions.host}:${deviceOptions.port}`
if (deviceSettings.type === DeviceType.HTTPSEND) {
deviceAddress = ''
}

return (
<div className="device-item-header openable">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ export const ResourceData: React.FC<{ resource: ResourceAny }> = ({ resource })
<></>
</SidebarInfoGroup>
)
} else if (resource.resourceType === ResourceType.HTTP_REQUEST) {
return (
<SidebarInfoGroup title="HTTP Request">
<></>
</SidebarInfoGroup>
)
} else {
assertNever(resource)
return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ export const ResourceLibraryItem = function ResourceLibraryItem({ resource, sele
resource.resourceType === ResourceType.ATEM_AUX ||
resource.resourceType === ResourceType.ATEM_DSK ||
resource.resourceType === ResourceType.ATEM_ME ||
resource.resourceType === ResourceType.CASPARCG_TEMPLATE
resource.resourceType === ResourceType.CASPARCG_TEMPLATE ||
resource.resourceType === ResourceType.HTTP_REQUEST
) {
return (
<>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,124 @@
import { Button, Stack, Typography } from '@mui/material'
import React from 'react'
import { TimelineObjHTTPSendAny } from 'timeline-state-resolver-types'
import { EditWrapper, NOT_IMPLEMENTED_SETTINGS, OnSave } from './lib'
import { TimelineContentTypeHTTP, TimelineObjHTTPSendAny } from 'timeline-state-resolver-types'
import { IntInput } from '../../../inputs/IntInput'
import { SelectEnum } from '../../../inputs/SelectEnum'
import { TextInput } from '../../../inputs/TextInput'
import { TrashBtn } from '../../../inputs/TrashBtn'
import { EditWrapper, OnSave } from './lib'

export const EditTimelineObjHTTPSendAny: React.FC<{ obj: TimelineObjHTTPSendAny; onSave: OnSave }> = ({
obj,
onSave,
}) => {
return (
<EditWrapper obj={obj} onSave={onSave}>
{NOT_IMPLEMENTED_SETTINGS}
<div className="setting">
<SelectEnum
label="Request Type"
fullWidth
currentValue={obj.content.type}
options={TimelineContentTypeHTTP}
onChange={(v: TimelineContentTypeHTTP) => {
obj.content.type = v
onSave(obj)
}}
allowUndefined={false}
/>
</div>

<div className="setting">
<TextInput
label="URL"
fullWidth
currentValue={obj.content.url}
onChange={(v) => {
obj.content.url = v
onSave(obj)
}}
allowUndefined={false}
/>
</div>

{Object.entries(obj.content.params).map(([key, value], index) => (
<React.Fragment key={index}>
<Stack direction="row" justifyContent="space-between">
<Typography variant="body2">Param #{index}</Typography>
<TrashBtn
onClick={() => {
delete obj.content.params[key]
onSave(obj)
}}
title="Delete parameter"
/>
</Stack>

<div className="setting">
<TextInput
label="Key"
fullWidth
currentValue={key}
onChange={(v) => {
obj.content.params[v] = value
delete obj.content.params[key]
onSave(obj)
}}
allowUndefined={false}
/>
</div>

<div className="setting">
<TextInput
label="Value"
fullWidth
currentValue={value}
onChange={(v) => {
obj.content.params[key] = v
onSave(obj)
}}
allowUndefined={false}
/>
</div>
</React.Fragment>
))}

<Button
style={{ marginBottom: '1rem' }}
variant="contained"
onClick={() => {
const numParams = Object.keys(obj.content.params).length
obj.content.params[`param${numParams}`] = 'value'
onSave(obj)
}}
>
Add Parameter
</Button>

<div className="setting">
<IntInput
label="Temporal Priority"
fullWidth
currentValue={obj.content.temporalPriority}
onChange={(v) => {
obj.content.temporalPriority = v
onSave(obj)
}}
allowUndefined={true}
/>
</div>

<div className="setting">
<TextInput
label="Queue ID"
fullWidth
currentValue={obj.content.queueId}
onChange={(v) => {
obj.content.queueId = v
onSave(obj)
}}
allowUndefined={true}
/>
</div>
</EditWrapper>
)
}
1 change: 1 addition & 0 deletions apps/app/src/react/styles/foundation/_colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ $fadeToBlackLayerColor: #000000;
$videoFaderLayerColor: #177400;
$previewLayerColor: $auxiliaryLayerColor;
$oscLayerColor: #554054;
$httpLayerColor: #554054;
$invalidLayerColor: #c24242;

$greenColor: #5fa852;
Expand Down
8 changes: 8 additions & 0 deletions apps/app/src/react/styles/objectTypeStyling.scss
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,12 @@
&.osc {
background: $oscLayerColor;
}

&.http_request,
&.post,
&.get,
&.put,
&.delete {
background: $httpLayerColor;
}
}
Loading

0 comments on commit 32a7695

Please sign in to comment.