wip: UI for integrations (#769)

This commit is contained in:
Carlos Valente
2024-02-09 13:56:04 +01:00
committed by GitHub
parent e8b5cb6750
commit 7f78fac162
7 changed files with 273 additions and 0 deletions
@@ -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>
);
}
@@ -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>
);
}