mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-11 18:33:53 +00:00
wip: UI for integrations (#769)
This commit is contained in:
@@ -3,6 +3,7 @@ import { ErrorBoundary } from '@sentry/react';
|
||||
import { useKeyDown } from '../../common/hooks/useKeyDown';
|
||||
|
||||
import AboutPanel from './panel/about-panel/AboutPanel';
|
||||
import IntegrationsPanel from './panel/integrations-panel/IntegrationsPanel';
|
||||
import LogPanel from './panel/log-panel/LogPanel';
|
||||
import ProjectPanel from './panel/project-panel/ProjectPanel';
|
||||
import ProjectSettingsPanel from './panel/project-settings-panel/ProjectSettingsPanel';
|
||||
@@ -27,6 +28,7 @@ export default function AppSettings() {
|
||||
<PanelList />
|
||||
<PanelContent onClose={closeSettings}>
|
||||
{selectedPanel === 'project' && <ProjectPanel />}
|
||||
{selectedPanel === 'integrations' && <IntegrationsPanel />}
|
||||
{selectedPanel === 'project_settings' && <ProjectSettingsPanel />}
|
||||
{selectedPanel === 'about' && <AboutPanel />}
|
||||
{selectedPanel === 'log' && <LogPanel />}
|
||||
|
||||
@@ -62,3 +62,28 @@
|
||||
background-color: $white-1;
|
||||
}
|
||||
}
|
||||
|
||||
.listGroup {
|
||||
padding: 1rem 0;
|
||||
|
||||
> li:not(:last-child) {
|
||||
border-bottom: 1px solid $white-10;
|
||||
}
|
||||
}
|
||||
|
||||
.listItem {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
align-items: center;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.fieldTitle {
|
||||
color: $ui-white;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.fieldDescription {
|
||||
font-size: calc(1rem - 2px);
|
||||
color: $gray-400;
|
||||
}
|
||||
|
||||
@@ -25,3 +25,20 @@ export function Card({ children }: { children: ReactNode }) {
|
||||
export function Table({ children }: { children: ReactNode }) {
|
||||
return <table className={style.table}>{children}</table>;
|
||||
}
|
||||
|
||||
export function ListGroup({ children }: { children: ReactNode }) {
|
||||
return <ul className={style.listGroup}>{children}</ul>;
|
||||
}
|
||||
|
||||
export function ListItem({ children }: { children: ReactNode }) {
|
||||
return <li className={style.listItem}>{children}</li>;
|
||||
}
|
||||
|
||||
export function Field({ title, description }: { title: string; description: string }) {
|
||||
return (
|
||||
<div className={style.fieldTitle}>
|
||||
{title}
|
||||
{description && <div className={style.fieldDescription}>{description}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import { Button, IconButton, Input, Select, Switch } from '@chakra-ui/react';
|
||||
import { IoAdd } from '@react-icons/all-files/io5/IoAdd';
|
||||
import { IoTrash } from '@react-icons/all-files/io5/IoTrash';
|
||||
|
||||
import * as Panel from '../PanelUtils';
|
||||
|
||||
import { cycles } from './IntegrationsPanel';
|
||||
|
||||
import style from './IntegrationsPanel.module.css';
|
||||
|
||||
const demoIntegrations = [
|
||||
{ id: 1, enabled: true, cycle: 'onLoad', message: '/ontime/scene/1' },
|
||||
{ id: 2, enabled: true, cycle: 'onLoad', message: '/ontime/scene/2' },
|
||||
{ id: 3, enabled: true, cycle: 'onLoad', message: '/ontime/scene/3' },
|
||||
{ id: 4, enabled: true, cycle: 'onLoad', message: '/ontime/scene/4' },
|
||||
];
|
||||
|
||||
export default function HttpIntegrations() {
|
||||
return (
|
||||
<Panel.Section>
|
||||
<Panel.Section>
|
||||
<Panel.SubHeader>HTTP integrations</Panel.SubHeader>
|
||||
<Panel.ListGroup>
|
||||
<Panel.ListItem>
|
||||
<Panel.Field title='HTTP Output' description='Provide feedback from Ontime through HTTP' />
|
||||
<Switch variant='ontime' size='lg' />
|
||||
</Panel.ListItem>
|
||||
</Panel.ListGroup>
|
||||
</Panel.Section>
|
||||
|
||||
<Panel.Section>
|
||||
<Panel.Card>
|
||||
<Panel.SubHeader>
|
||||
HTTP Integration
|
||||
<Button variant='ontime-subtle' size='sm' rightIcon={<IoAdd />} onClick={() => undefined}>
|
||||
New
|
||||
</Button>
|
||||
</Panel.SubHeader>
|
||||
<Panel.Paragraph>Integration Settings for OSC protocol</Panel.Paragraph>
|
||||
<Panel.Table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Enabled</th>
|
||||
<th>Cycle</th>
|
||||
<th className={style.fullWidth}>Message</th>
|
||||
<th />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{demoIntegrations.map((integration) => (
|
||||
<tr key={integration.id}>
|
||||
<td>
|
||||
<Switch variant='ontime' />
|
||||
</td>
|
||||
<td className={style.autoWidth}>
|
||||
<Select size='sm' variant='ontime' className={style.fitContents}>
|
||||
{cycles.map((cycle) => (
|
||||
<option key={cycle.id} value={cycle.value}>
|
||||
{cycle.label}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</td>
|
||||
<td className={style.fullWidth}>
|
||||
<Input size='sm' variant='ontime-filled' value={integration.message} />
|
||||
</td>
|
||||
<td>
|
||||
<IconButton
|
||||
size='sm'
|
||||
variant='ontime-ghosted'
|
||||
color='#FA5656' // $red-500
|
||||
icon={<IoTrash />}
|
||||
aria-label='Delete entry'
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</Panel.Table>
|
||||
</Panel.Card>
|
||||
</Panel.Section>
|
||||
</Panel.Section>
|
||||
);
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
.fullWidth {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fitContents {
|
||||
width: max-content !important; /* override chakra */
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import * as Panel from '../PanelUtils';
|
||||
|
||||
import HttpIntegrations from './HttpIntegrations';
|
||||
import OscIntegrations from './OscIntegrations';
|
||||
|
||||
export const cycles = [
|
||||
{ id: 1, label: 'On Load', value: 'onLoad' },
|
||||
{ id: 2, label: 'On Start', value: 'onStart' },
|
||||
{ id: 3, label: 'On Pause', value: 'onPause' },
|
||||
{ id: 4, label: 'On Stop', value: 'onStop' },
|
||||
{ id: 5, label: 'Every second', value: 'onUpdate' },
|
||||
{ id: 6, label: 'On Finish', value: 'onFinish' },
|
||||
];
|
||||
|
||||
export default function IntegrationsPanel() {
|
||||
return (
|
||||
<>
|
||||
<Panel.Header>Integration settings</Panel.Header>
|
||||
<OscIntegrations />
|
||||
<HttpIntegrations />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import { Button, IconButton, Input, Select, Switch } from '@chakra-ui/react';
|
||||
import { IoAdd } from '@react-icons/all-files/io5/IoAdd';
|
||||
import { IoTrash } from '@react-icons/all-files/io5/IoTrash';
|
||||
|
||||
import * as Panel from '../PanelUtils';
|
||||
|
||||
import { cycles } from './IntegrationsPanel';
|
||||
|
||||
import style from './IntegrationsPanel.module.css';
|
||||
|
||||
const demoIntegrations = [
|
||||
{ id: 1, enabled: true, cycle: 'onLoad', message: '/ontime/scene/1' },
|
||||
{ id: 2, enabled: true, cycle: 'onLoad', message: '/ontime/scene/2' },
|
||||
{ id: 3, enabled: true, cycle: 'onLoad', message: '/ontime/scene/3' },
|
||||
{ id: 4, enabled: true, cycle: 'onLoad', message: '/ontime/scene/4' },
|
||||
];
|
||||
|
||||
export default function OscIntegrations() {
|
||||
return (
|
||||
<Panel.Section>
|
||||
<Panel.Section>
|
||||
<Panel.SubHeader>Open Sound Control integrations</Panel.SubHeader>
|
||||
<Panel.ListGroup>
|
||||
<Panel.ListItem>
|
||||
<Panel.Field title='OSC input' description='Allow control of Ontime through OSC' />
|
||||
<Switch variant='ontime' size='lg' />
|
||||
</Panel.ListItem>
|
||||
<Panel.ListItem>
|
||||
<Panel.Field title='Listen on port' description='Port for incoming OSC. Default: 8888' />
|
||||
<Input
|
||||
id='portIn'
|
||||
placeholder='8888'
|
||||
width='75px'
|
||||
size='sm'
|
||||
textAlign='right'
|
||||
maxLength={5}
|
||||
variant='ontime-filled'
|
||||
/>
|
||||
</Panel.ListItem>
|
||||
</Panel.ListGroup>
|
||||
<Panel.ListGroup>
|
||||
<Panel.ListItem>
|
||||
<Panel.Field title='OSC output' description='Provide feedback from Ontime with OSC' />
|
||||
<Switch variant='ontime' size='lg' />
|
||||
</Panel.ListItem>
|
||||
<Panel.ListItem>
|
||||
<Panel.Field title='OSC target IP' description='IP address Ontime will send OSC messages to' />
|
||||
<Input
|
||||
id='portIn'
|
||||
placeholder='8888'
|
||||
width='75px'
|
||||
size='sm'
|
||||
textAlign='right'
|
||||
maxLength={5}
|
||||
variant='ontime-filled'
|
||||
/>
|
||||
</Panel.ListItem>
|
||||
<Panel.ListItem>
|
||||
<Panel.Field title='OSC target port' description='Port number Ontime will send OSC messages to' />
|
||||
<Input id='portIn' placeholder='8888' width='75px' size='sm' textAlign='right' variant='ontime-filled' />
|
||||
</Panel.ListItem>
|
||||
</Panel.ListGroup>
|
||||
</Panel.Section>
|
||||
|
||||
<Panel.Card>
|
||||
<Panel.SubHeader>
|
||||
OSC Integration
|
||||
<Button variant='ontime-subtle' size='sm' rightIcon={<IoAdd />} onClick={() => undefined}>
|
||||
New
|
||||
</Button>
|
||||
</Panel.SubHeader>
|
||||
<Panel.Table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Enabled</th>
|
||||
<th>Cycle</th>
|
||||
<th className={style.fullWidth}>Message</th>
|
||||
<th />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{demoIntegrations.map((integration) => (
|
||||
<tr key={integration.id}>
|
||||
<td>
|
||||
<Switch variant='ontime' />
|
||||
</td>
|
||||
<td className={style.autoWidth}>
|
||||
<Select size='sm' variant='ontime' className={style.fitContents}>
|
||||
{cycles.map((cycle) => (
|
||||
<option key={cycle.id} value={cycle.value}>
|
||||
{cycle.label}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</td>
|
||||
<td className={style.fullWidth}>
|
||||
<Input size='sm' variant='ontime-filled' value={integration.message} />
|
||||
</td>
|
||||
<td>
|
||||
<IconButton
|
||||
size='sm'
|
||||
variant='ontime-ghosted'
|
||||
color='#FA5656' // $red-500
|
||||
icon={<IoTrash />}
|
||||
aria-label='Delete entry'
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</Panel.Table>
|
||||
</Panel.Card>
|
||||
</Panel.Section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user