Skip to content

Commit

Permalink
Merge branch 'dev' into j-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
Jdelpizz authored Apr 17, 2023
2 parents b87713c + a751304 commit 971a602
Show file tree
Hide file tree
Showing 32 changed files with 591 additions and 237 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ A modern lightweight mission system used to support TV events. It provides MDTs

### Dashboard (`./dashboard`)

This exposes a dashbaord UI (`5173` by default) that connects to the two API servers via websockets. The valid routes are:
This exposes a dashboard UI (`5173` by default) that connects to the two API servers via websockets. The valid routes are:

- `/` - Displays links to the two available dashboards
- `/msn` - Mission dashboard
Expand Down
14 changes: 14 additions & 0 deletions dashboard/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# MX Server
VITE_TAILNUMBERS='tv-01 tv-02 tv-05 tv-06' # Space delimited
VITE_WS_MX_URI=192.168.0.89
VITE_WS_MX_PORT=8888
VITE_WS_MX_PATH='/mx-dashboard'
VITE_WS_MX_CONTROL_PATH='/mx-controller'
VITE_WS_MX_SORTIE_PATH='/mx-sortie-state'

# MSN Server
VITE_SHOPS='bcd gccs iamd intel freq wx' # Space delimited
VITE_WS_MSN_URI=192.168.0.89
VITE_WS_MSN_PORT=8889
VITE_WS_MSN_PATH='/msn-dashboard'
VITE_WS_MSN_CONTROL_PATH='/msn-controller'
121 changes: 30 additions & 91 deletions dashboard/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
"preview": "vite preview"
},
"dependencies": {
"@chakra-ui/icons": "^2.0.17",
"@chakra-ui/react": "^2.4.4",
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@tanstack/react-router": "^0.0.1-beta.52",
"axios": "^1.2.3",
"framer-motion": "^6.5.1",
"prop-types": "^15.8.1",
"react": "^18.2.0",
Expand Down
Binary file added dashboard/public/f35-canx.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified dashboard/public/f35-flying.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified dashboard/public/f35-landing.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified dashboard/public/f35-takeoff.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions dashboard/serve.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env python

# Inspired by https://gist.github.com/jtangelder/e445e9a7f5e31c220be6
# Python3 http.server for Single Page Application

import urllib.parse
import http.server
import socketserver
import re
from pathlib import Path

HOST = ('0.0.0.0', 80)
pattern = re.compile('.png|.jpg|.jpeg|.js|.css|.ico|.gif|.svg', re.IGNORECASE)

class Handler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
url_parts = urllib.parse.urlparse(self.path)
request_file_path = Path(url_parts.path.strip("/"))

ext = request_file_path.suffix
if not request_file_path.is_file() and not pattern.match(ext):
self.path = 'index.html'

return http.server.SimpleHTTPRequestHandler.do_GET(self)

httpd = socketserver.TCPServer(HOST, Handler)
httpd.serve_forever()
79 changes: 59 additions & 20 deletions dashboard/src/AirTaskingOrderCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
Text,
} from '@chakra-ui/react'

const {VITE_MSN_NUMBER, VITE_MSN_PLATFORM, VITE_MSN_TAKEOFF, VITE_MSN_RETURN, VITE_SHOPS} = import.meta.env
const {VITE_SHOPS} = import.meta.env
const SHOPS = VITE_SHOPS.split(' ')

function MetaSection({label, value}){
Expand All @@ -22,32 +22,53 @@ function MetaSection({label, value}){
)
}

MetaSection.defaultProps = {
value: 'unk'
}

MetaSection.propTypes = {
label: PropTypes.string.isRequired,
value: PropTypes.string.isRequired
value: PropTypes.string
}

function MissionMeta({target}){
function MissionMeta({intel}){
const {
msn_takeoff: msnTakeoff,
msn_return: msnReturn,
msn_platform: msnPlatform,
msn_target: msnTarget
} = intel
return (
<Stack>
<Heading size="md">Mission Data</Heading>
<Divider />
<HStack justifyContent="center" spacing={16}>
<MetaSection label="Takeoff" value={VITE_MSN_TAKEOFF} />
<MetaSection label="Return" value={VITE_MSN_RETURN} />
<MetaSection label="Platform" value={VITE_MSN_PLATFORM} />
<MetaSection label="Target" value={target} />
<HStack justifyContent="center" spacing={8}>
<MetaSection label="Takeoff" value={msnTakeoff} />
<MetaSection label="Return" value={msnReturn} />
<MetaSection label="Platform" value={msnPlatform} />
<MetaSection label="Target" value={msnTarget} />
</HStack>
</Stack>
)
}

MissionMeta.defaultProps = {
target: "unk"
intel: PropTypes.shape({
msn_takeoff: 'unk',
msn_return: 'unk',
msn_platform: 'unk',
msn_target: 'unk',
})
}

MissionMeta.propTypes = {
target: PropTypes.string
intel: PropTypes.shape({
msn_id: PropTypes.string,
msn_takeoff: PropTypes.string,
msn_return: PropTypes.string,
msn_platform: PropTypes.string,
msn_target: PropTypes.string,
})
}

function Status({label, state, delay}){
Expand Down Expand Up @@ -75,9 +96,9 @@ function MissionStatus({states}){
<Stack>
<Heading size="md">Mission Status</Heading>
<Divider />
<HStack justifyContent="center" spacing={6}>
<HStack justifyContent="center" spacing={4}>
{SHOPS.map((shop, idx) => {
const currentState = states[shop] ? states[shop].status : 'unk'
const currentState = states[shop] && states[shop].status ? states[shop].status : 'unk'
const delay = idx * 0.5

return(
Expand All @@ -90,27 +111,45 @@ function MissionStatus({states}){

MissionStatus.propTypes = {
states: PropTypes.shape({
intel: PropTypes.string
intel: PropTypes.shape({
status: PropTypes.string
})
}).isRequired
}

export default function AirTaskingOrderCard({msnData}){
const {target, ...states} = msnData
// The defaultProps get overwritten when an empty object is passed in
// There must be a better pattern for this
const {intel = {}} = msnData
const {msn_id: msnId = "unk"} = intel

return (
<Card px={4} py={2}>
<Stack spacing={6}>
<Heading size="lg">{`Mission ${VITE_MSN_NUMBER}`}</Heading>
<MissionStatus states={states} />
<MissionMeta target={target}/>
<Heading size="lg">{`Mission ${msnId.toUpperCase()}`}</Heading>
<MissionStatus states={msnData} />
<MissionMeta intel={intel}/>
</Stack>
</Card>
)
}

AirTaskingOrderCard.defaultProps = {
msnData: {
intel: {
msn_id: 'unk'
}
}
}

AirTaskingOrderCard.propTypes = {
msnData: PropTypes.shape({
target: PropTypes.string,
intel: PropTypes.shape({})
}).isRequired,
intel: PropTypes.shape({
msn_id: PropTypes.string,
msn_takeoff: PropTypes.string,
msn_return: PropTypes.string,
msn_platform: PropTypes.string,
msn_target: PropTypes.string,
})
})
}
Loading

0 comments on commit 971a602

Please sign in to comment.