mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-14 20:23:26 +00:00
Bundle Copy
This commit is contained in:
661
tgui/packages/tgui_ch/interfaces/EmbeddedController.js
Normal file
661
tgui/packages/tgui_ch/interfaces/EmbeddedController.js
Normal file
@@ -0,0 +1,661 @@
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
import { createLogger } from '../logging';
|
||||
const logger = createLogger('fuck');
|
||||
|
||||
// This UI uses an internal routing system for the many different variants of
|
||||
// embedded controllers in use.
|
||||
let primaryRoutes = {};
|
||||
|
||||
/**
|
||||
* This is an all-in-one replacement for the following NanoUI Templates:
|
||||
* - advanced_airlock_console.tmpl
|
||||
* - docking_airlock_console.tmpl
|
||||
* - door_access_console.tmpl
|
||||
* - escape_pod_console.tmpl
|
||||
* - escape_pod_berth_console.tmpl
|
||||
* - multi_docking_console.tmpl
|
||||
* - phoron_airlock_console.tmpl
|
||||
* - simple_airlock_console.tmpl
|
||||
* - simple_docking_console.tmpl
|
||||
* - simple_docking_console_pod.tmpl -- Funny enough, wasn't used anywhere.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Let's cover all of the attributes of `data` for this UI right here.
|
||||
* For those unfamiliar with JSDoc syntax, [param] indicates
|
||||
* an optional parameter.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interior/Exterior Door Status
|
||||
* @typedef {Object} doorStatus
|
||||
* @property {('open'|'closed')} state
|
||||
* @property {('locked'|'unlocked')} lock
|
||||
*/
|
||||
|
||||
/**
|
||||
* Dock Status
|
||||
* @typedef {('undocked'|'undocking'|'docking'|'docked')} dockStatus
|
||||
*/
|
||||
|
||||
/**
|
||||
* All possible data attributes.
|
||||
* @typedef {Object} Data
|
||||
* @property {string} internalTemplateName - <Template> to use.
|
||||
* @property {number} chamber_pressure - The current pressure of the airlock.
|
||||
* @property {boolean} processing - Whether or not the airlock is currently
|
||||
* cycling.
|
||||
* @property {number} [external_pressure] - Pressure on the "external" side.
|
||||
* @property {number} [internal_pressure] - Pressure on the "internal" side.
|
||||
* @property {boolean} [purge] - Airlock currently purging?
|
||||
* @property {boolean} [secure] - Airlock doors locked?
|
||||
* @property {doorStatus} [exterior_status] - Describes the status of the
|
||||
* exterior-side door.
|
||||
* @property {doorStatus} [interior_status] - Describes the status of the
|
||||
* interior-side door.
|
||||
*
|
||||
* @property {dockStatus} [docking_status] - Used exclusivly for "Docking" type
|
||||
* controllers, describes the state of the dock.
|
||||
* @property {boolean} [airlock_disabled] - Airlock disabled?
|
||||
* @property {boolean} [override_enabled] - Forces the shuttle to undock.
|
||||
* @property {string} [docking_codes] - The secret codes to dock a shuttle here
|
||||
* @property {string} [name] - Name of the dock.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Entrypoint of the UI. This handles finding the correct route to use.
|
||||
*/
|
||||
export const EmbeddedController = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const { internalTemplateName } = data;
|
||||
|
||||
const Component = primaryRoutes[internalTemplateName];
|
||||
if (!Component) {
|
||||
throw Error('Unable to find Component for template name: ' + internalTemplateName);
|
||||
}
|
||||
|
||||
return (
|
||||
<Window width={450} height={340} resizable>
|
||||
<Window.Content>
|
||||
<Component />
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
/** ***************************************************************************\
|
||||
* HELPER COMPONENTS *
|
||||
\******************************************************************************/
|
||||
|
||||
/**
|
||||
* @typedef {Object} BarProp
|
||||
* @property {number} minValue - Minimum value of the bar.
|
||||
* @property {number} maxValue - Maximum value of the bar.
|
||||
* @property {number} value - Current value between min/max.
|
||||
* @property {string} label - Label next to the bar.
|
||||
* @property {string} textValue - Value in text.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} StatusDisplayProps
|
||||
* @property {array[BarProp]} bars - The bars to display.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Used for the upper status display that is used on 90% of these UIs.
|
||||
* @param {StatusDisplayProps} props
|
||||
*/
|
||||
const StatusDisplay = (props, context) => {
|
||||
const { bars } = props;
|
||||
|
||||
return (
|
||||
<Section title="Status">
|
||||
<LabeledList>
|
||||
{bars.map((bar) => (
|
||||
<LabeledList.Item key={bar.label} label={bar.label}>
|
||||
<ProgressBar color={bar.color(bar.value)} minValue={bar.minValue} maxValue={bar.maxValue} value={bar.value}>
|
||||
{bar.textValue}
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
))}
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* This is just a quick helper for most airlock controllers. They usually all
|
||||
* have the "Cycle out, cycle in, force out, force in" buttons, so we just have
|
||||
* a single component that adjusts for the mild data structure differences
|
||||
* on it's own.
|
||||
*/
|
||||
const StandardControls = (props, context) => {
|
||||
const { data, act } = useBackend(context);
|
||||
|
||||
let externalForceSafe = true;
|
||||
if (data['interior_status'] && data.interior_status.state === 'open') {
|
||||
externalForceSafe = false;
|
||||
} else if (data['external_pressure'] && data['chamber_pressure']) {
|
||||
externalForceSafe = !(Math.abs(data['external_pressure'] - data['chamber_pressure']) > 5);
|
||||
}
|
||||
|
||||
let internalForceSafe = true;
|
||||
if (data['exterior_status'] && data.exterior_status.state === 'open') {
|
||||
internalForceSafe = false;
|
||||
} else if (data['internal_pressure'] && data['chamber_pressure']) {
|
||||
internalForceSafe = !(Math.abs(data['internal_pressure'] - data['chamber_pressure']) > 5);
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Box>
|
||||
<Button
|
||||
disabled={data.airlock_disabled}
|
||||
icon="arrow-left"
|
||||
content="Cycle to Exterior"
|
||||
onClick={() => act('cycle_ext')}
|
||||
/>
|
||||
<Button
|
||||
disabled={data.airlock_disabled}
|
||||
icon="arrow-right"
|
||||
content="Cycle to Interior"
|
||||
onClick={() => act('cycle_int')}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Button.Confirm
|
||||
disabled={data.airlock_disabled}
|
||||
color={externalForceSafe ? '' : 'bad'}
|
||||
icon="exclamation-triangle"
|
||||
confirmIcon="exclamation-triangle"
|
||||
content="Force Exterior Door"
|
||||
onClick={() => act('force_ext')}
|
||||
/>
|
||||
<Button.Confirm
|
||||
disabled={data.airlock_disabled}
|
||||
color={internalForceSafe ? '' : 'bad'}
|
||||
icon="exclamation-triangle"
|
||||
confirmIcon="exclamation-triangle"
|
||||
content="Force Interior Door"
|
||||
onClick={() => act('force_int')}
|
||||
/>
|
||||
</Box>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a shared component between the EscapePodConsole
|
||||
* and the EscapePodBerthConsole. They previously had different data structures
|
||||
* but I got rid of that stupid shit.
|
||||
*/
|
||||
const EscapePodStatus = (props, context) => {
|
||||
const { data, act } = useBackend(context);
|
||||
|
||||
const statusToHtml = {
|
||||
'docked': <Armed />,
|
||||
'undocking': <Box color="average">EJECTING-STAND CLEAR!</Box>,
|
||||
'undocked': <Box color="grey">POD EJECTED</Box>,
|
||||
'docking': <Box color="good">INITIALIZING...</Box>,
|
||||
};
|
||||
|
||||
let dockHatch = <Box color="bad">ERROR</Box>;
|
||||
|
||||
if (data.exterior_status.state === 'open') {
|
||||
dockHatch = <Box color="average">OPEN</Box>;
|
||||
} else if (data.exterior_status.lock === 'unlocked') {
|
||||
dockHatch = <Box color="average">UNSECURED</Box>;
|
||||
} else if (data.exterior_status.lock === 'locked') {
|
||||
dockHatch = <Box color="good">SECURED</Box>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Section>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Escape Pod Status">{statusToHtml[data.docking_status]}</LabeledList.Item>
|
||||
<LabeledList.Item label="Docking Hatch">{dockHatch}</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sub-subcomponent for escape pods.
|
||||
* Just shows "ARMED" or "SYSTEMS OK" depending on armed status.
|
||||
* Keeps me from having to write like, two lines of code.
|
||||
*/
|
||||
const Armed = (props, context) => {
|
||||
const { data, act } = useBackend(context);
|
||||
return data.armed ? <Box color="average">ARMED</Box> : <Box color="good">SYSTEMS OK</Box>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shared controls between the berth and the pod itself.
|
||||
* Basically just external door control.
|
||||
*/
|
||||
const EscapePodControls = (props, context) => {
|
||||
const { data, act } = useBackend(context);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Button
|
||||
disabled={!data.override_enabled}
|
||||
icon="exclamation-triangle"
|
||||
content="Force Exterior Door"
|
||||
color={data.docking_status !== 'docked' ? 'bad' : ''}
|
||||
onClick={() => act('force_door')}
|
||||
/>
|
||||
<Button
|
||||
selected={data.override_enabled}
|
||||
color={data.docking_status !== 'docked' ? 'bad' : 'average'}
|
||||
icon="exclamation-triangle"
|
||||
content="Override"
|
||||
onClick={() => act('toggle_override')}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Just a neat little helper for all the different states of dock.
|
||||
*/
|
||||
const DockStatus = (props, context) => {
|
||||
const { data, act } = useBackend(context);
|
||||
|
||||
const statusToHtml = {
|
||||
'docked': <Box color="good">DOCKED</Box>,
|
||||
'docking': <Box color="average">DOCKING</Box>,
|
||||
'undocking': <Box color="average">UNDOCKING</Box>,
|
||||
'undocked': <Box color="grey">NOT IN USE</Box>,
|
||||
};
|
||||
|
||||
let dockStatus = statusToHtml[data.docking_status];
|
||||
|
||||
if (data.override_enabled) {
|
||||
dockStatus = <Box color="bad">{data.docking_status.toUpperCase()}-OVERRIDE ENABLED</Box>;
|
||||
}
|
||||
|
||||
return dockStatus;
|
||||
};
|
||||
|
||||
/** ***************************************************************************\
|
||||
* ROUTES *
|
||||
\******************************************************************************/
|
||||
|
||||
/**
|
||||
* Advanced airlock consoles display the external pressure,
|
||||
* the internal pressure, and the chamber pressure separately.
|
||||
* They also have a PURGE and SECURE option for safety.
|
||||
* Replaces advanced_airlock_console.tmpl
|
||||
*/
|
||||
const AirlockConsoleAdvanced = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const color = (value) => {
|
||||
return value < 80 || value > 120 ? 'bad' : value < 95 || value > 110 ? 'average' : 'good';
|
||||
};
|
||||
|
||||
const bars = [
|
||||
{
|
||||
minValue: 0,
|
||||
maxValue: 202,
|
||||
value: data.external_pressure,
|
||||
label: 'External Pressure',
|
||||
textValue: data.external_pressure + ' kPa',
|
||||
color: color,
|
||||
},
|
||||
{
|
||||
minValue: 0,
|
||||
maxValue: 202,
|
||||
value: data.chamber_pressure,
|
||||
label: 'Chamber Pressure',
|
||||
textValue: data.chamber_pressure + ' kPa',
|
||||
color: color,
|
||||
},
|
||||
{
|
||||
minValue: 0,
|
||||
maxValue: 202,
|
||||
value: data.internal_pressure,
|
||||
label: 'Internal Pressure',
|
||||
textValue: data.internal_pressure + ' kPa',
|
||||
color: color,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<StatusDisplay bars={bars} />
|
||||
<Section title="Controls">
|
||||
<StandardControls />
|
||||
<Box>
|
||||
<Button icon="sync" content="Purge" onClick={() => act('purge')} />
|
||||
<Button icon="lock-open" content="Secure" onClick={() => act('secure')} />
|
||||
</Box>
|
||||
<Box>
|
||||
<Button disabled={!data.processing} icon="ban" color="bad" content="Abort" onClick={() => act('abort')} />
|
||||
</Box>
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
primaryRoutes['AirlockConsoleAdvanced'] = AirlockConsoleAdvanced;
|
||||
|
||||
/**
|
||||
* Simple airlock consoles are the least complicated airlock controller.
|
||||
* They show the current chamber pressure, two cycle buttons, and two
|
||||
* force door buttons. That's it.
|
||||
* Replaces simple_airlock_console.tmpl
|
||||
*/
|
||||
const AirlockConsoleSimple = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const bars = [
|
||||
{
|
||||
minValue: 0,
|
||||
maxValue: 202,
|
||||
value: data.chamber_pressure,
|
||||
label: 'Chamber Pressure',
|
||||
textValue: data.chamber_pressure + ' kPa',
|
||||
color: (value) => {
|
||||
return value < 80 || value > 120 ? 'bad' : value < 95 || value > 110 ? 'average' : 'good';
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<StatusDisplay bars={bars} />
|
||||
<Section title="Controls">
|
||||
<StandardControls />
|
||||
<Box>
|
||||
<Button disabled={!data.processing} icon="ban" color="bad" content="Abort" onClick={() => act('abort')} />
|
||||
</Box>
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
primaryRoutes['AirlockConsoleSimple'] = AirlockConsoleSimple;
|
||||
|
||||
/**
|
||||
* Phoron airlock consoles don't actually cycle *pressure*, they cycle
|
||||
* phoron, for use on transitioning to the outside environment of a phoron
|
||||
* atmosphere planet.
|
||||
* Replaces phoron_airlock_console.tmpl
|
||||
*/
|
||||
const AirlockConsolePhoron = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const bars = [
|
||||
{
|
||||
minValue: 0,
|
||||
maxValue: 202,
|
||||
value: data.chamber_pressure,
|
||||
label: 'Chamber Pressure',
|
||||
textValue: data.chamber_pressure + ' kPa',
|
||||
color: (value) => {
|
||||
return value < 80 || value > 120 ? 'bad' : value < 95 || value > 110 ? 'average' : 'good';
|
||||
},
|
||||
},
|
||||
{
|
||||
minValue: 0,
|
||||
maxValue: 100,
|
||||
value: data.chamber_phoron,
|
||||
label: 'Chamber Phoron',
|
||||
textValue: data.chamber_phoron + ' mol',
|
||||
color: (value) => {
|
||||
return value > 5 ? 'bad' : value > 0.5 ? 'average' : 'good';
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<StatusDisplay bars={bars} />
|
||||
<Section title="Controls">
|
||||
<StandardControls />
|
||||
<Box>
|
||||
<Button disabled={!data.processing} icon="ban" color="bad" content="Abort" onClick={() => act('abort')} />
|
||||
</Box>
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
primaryRoutes['AirlockConsolePhoron'] = AirlockConsolePhoron;
|
||||
|
||||
/**
|
||||
* This is a mix airlock & docking console. It lets you control the dock status
|
||||
* as well as the attached airlock.
|
||||
* Replaces docking_airlock_console.tmpl
|
||||
*/
|
||||
const AirlockConsoleDocking = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const bars = [
|
||||
{
|
||||
minValue: 0,
|
||||
maxValue: 202,
|
||||
value: data.chamber_pressure,
|
||||
label: 'Chamber Pressure',
|
||||
textValue: data.chamber_pressure + ' kPa',
|
||||
color: (value) => {
|
||||
return value < 80 || value > 120 ? 'bad' : value < 95 || value > 110 ? 'average' : 'good';
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Section
|
||||
title="Dock"
|
||||
buttons={
|
||||
data.airlock_disabled || data.override_enabled ? (
|
||||
<Button
|
||||
icon="exclamation-triangle"
|
||||
color={data.override_enabled ? 'red' : ''}
|
||||
content="Override"
|
||||
onClick={() => act('toggle_override')}
|
||||
/>
|
||||
) : null
|
||||
}>
|
||||
<DockStatus />
|
||||
</Section>
|
||||
<StatusDisplay bars={bars} />
|
||||
<Section title="Controls">
|
||||
<StandardControls />
|
||||
<Box>
|
||||
<Button disabled={!data.processing} icon="ban" color="bad" content="Abort" onClick={() => act('abort')} />
|
||||
</Box>
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
primaryRoutes['AirlockConsoleDocking'] = AirlockConsoleDocking;
|
||||
|
||||
/**
|
||||
* Simple docking consoles do not allow you to cycle the airlock. They can
|
||||
* force the doors in an emergency, but there is no facility for cycling.
|
||||
* They're primarily just there to display the status of the dock.
|
||||
* Replaces simple_docking_console.tmpl
|
||||
*/
|
||||
const DockingConsoleSimple = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
let dockHatch = <Box color="bad">ERROR</Box>;
|
||||
|
||||
if (data.exterior_status.state === 'open') {
|
||||
dockHatch = <Box color="average">OPEN</Box>;
|
||||
} else if (data.exterior_status.lock === 'unlocked') {
|
||||
dockHatch = <Box color="average">UNSECURED</Box>;
|
||||
} else if (data.exterior_status.lock === 'locked') {
|
||||
dockHatch = <Box color="good">SECURED</Box>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Section
|
||||
title="Status"
|
||||
buttons={
|
||||
<Fragment>
|
||||
<Button
|
||||
icon="exclamation-triangle"
|
||||
disabled={!data.override_enabled}
|
||||
content="Force exterior door"
|
||||
onClick={() => act('force_door')}
|
||||
/>
|
||||
<Button
|
||||
icon="exclamation-triangle"
|
||||
color={data.override_enabled ? 'red' : ''}
|
||||
content="Override"
|
||||
onClick={() => act('toggle_override')}
|
||||
/>
|
||||
</Fragment>
|
||||
}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Dock Status">
|
||||
<DockStatus />
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Docking Hatch">{dockHatch}</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
primaryRoutes['DockingConsoleSimple'] = DockingConsoleSimple;
|
||||
|
||||
/**
|
||||
* Shockingly, the multi docking console is the simplest docking console.
|
||||
* It has no functionality except to display the status of multiple airlocks,
|
||||
* for bigger shuttles.
|
||||
* Replaces multi_docking_console.tmpl
|
||||
*/
|
||||
const DockingConsoleMulti = (props, context) => {
|
||||
const { data } = useBackend(context);
|
||||
return (
|
||||
<Fragment>
|
||||
<Section title="Docking Status">
|
||||
<DockStatus />
|
||||
</Section>
|
||||
<Section title="Airlocks">
|
||||
{data.airlocks.length ? (
|
||||
<LabeledList>
|
||||
{data.airlocks.map((airlock) => (
|
||||
<LabeledList.Item
|
||||
color={airlock.override_enabled ? 'bad' : 'good'}
|
||||
key={airlock.name}
|
||||
label={airlock.name}>
|
||||
{airlock.override_enabled ? 'OVERRIDE ENABLED' : 'STATUS OK'}
|
||||
</LabeledList.Item>
|
||||
))}
|
||||
</LabeledList>
|
||||
) : (
|
||||
<Flex height="100%" mt="0.5em">
|
||||
<Flex.Item grow="1" align="center" textAlign="center" color="bad">
|
||||
<Icon name="door-closed" mb="0.5rem" size="5" />
|
||||
<br />
|
||||
No airlocks found.
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
)}
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
primaryRoutes['DockingConsoleMulti'] = DockingConsoleMulti;
|
||||
|
||||
/**
|
||||
* Airlock but without anything other than doors. Separates clean rooms.
|
||||
* Replaces door_access_console.tmpl
|
||||
*/
|
||||
const DoorAccessConsole = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
let interiorOpen = data.interior_status.state === 'open' || data.exterior_status.state === 'closed';
|
||||
let exteriorOpen = data.exterior_status.state === 'open' || data.interior_status.state === 'closed';
|
||||
|
||||
return (
|
||||
<Section
|
||||
title="Status"
|
||||
buttons={
|
||||
<Fragment>
|
||||
{/* Interior Button */}
|
||||
<Button
|
||||
icon={interiorOpen ? 'arrow-left' : 'exclamation-triangle'}
|
||||
content={interiorOpen ? 'Cycle To Exterior' : 'Lock Exterior Door'}
|
||||
onClick={() => {
|
||||
act(interiorOpen ? 'cycle_ext_door' : 'force_ext');
|
||||
}}
|
||||
/>
|
||||
{/* Exterior Button */}
|
||||
<Button
|
||||
icon={exteriorOpen ? 'arrow-right' : 'exclamation-triangle'}
|
||||
content={exteriorOpen ? 'Cycle To Interior' : 'Lock Interior Door'}
|
||||
onClick={() => {
|
||||
act(exteriorOpen ? 'cycle_int_door' : 'force_int');
|
||||
}}
|
||||
/>
|
||||
</Fragment>
|
||||
}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Exterior Door Status">
|
||||
{data.exterior_status.state === 'closed' ? 'Locked' : 'Open'}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Interior Door Status">
|
||||
{data.interior_status.state === 'closed' ? 'Locked' : 'Open'}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
primaryRoutes['DoorAccessConsole'] = DoorAccessConsole;
|
||||
|
||||
/**
|
||||
* These are the least airlock-like UIs here, but they're "close enough".
|
||||
* Replaces escape_pod_console.tmpl
|
||||
*/
|
||||
const EscapePodConsole = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
return (
|
||||
<Fragment>
|
||||
<EscapePodStatus />
|
||||
<Section title="Controls">
|
||||
<EscapePodControls />
|
||||
<Box>
|
||||
<Button
|
||||
icon="exclamation-triangle"
|
||||
disabled={data.armed}
|
||||
color={data.armed ? 'bad' : 'average'}
|
||||
content="ARM"
|
||||
onClick={() => act('manual_arm')}
|
||||
/>
|
||||
<Button
|
||||
icon="exclamation-triangle"
|
||||
disabled={!data.can_force}
|
||||
color="bad"
|
||||
content="MANUAL EJECT"
|
||||
onClick={() => act('force_launch')}
|
||||
/>
|
||||
</Box>
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
primaryRoutes['EscapePodConsole'] = EscapePodConsole;
|
||||
|
||||
/**
|
||||
* These are the least airlock-like UIs here, but they're "close enough".
|
||||
* Replaces escape_pod_berth_console.tmpl
|
||||
*/
|
||||
const EscapePodBerthConsole = (props, context) => {
|
||||
const { data } = useBackend(context);
|
||||
return (
|
||||
<Fragment>
|
||||
<EscapePodStatus />
|
||||
<Section title="Controls">
|
||||
<EscapePodControls />
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
primaryRoutes['EscapePodBerthConsole'] = EscapePodBerthConsole;
|
||||
Reference in New Issue
Block a user