AAAAAAAAAAAAGH

This commit is contained in:
Aquaticholic
2022-02-02 05:37:10 +00:00
parent 285eeb11d4
commit 54b3353a0b
33 changed files with 675 additions and 420 deletions
-6
View File
@@ -1,6 +0,0 @@
{
"prettier.printWidth": 400,
"prettier.semi": false,
"prettier.singleQuote": true
}
+1 -1
View File
@@ -1,3 +1,3 @@
{
"prettier.configPath": "${workspaceFolder}/.prettierrc.json"
"prettier.printWidth": 800
}
+14
View File
@@ -0,0 +1,14 @@
# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file.
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
+8
View File
@@ -0,0 +1,8 @@
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
-----END DH PARAMETERS-----
+28 -6
View File
@@ -1,18 +1,32 @@
version: "3"
services:
scouting-webserver-prod:
container_name: "scouting-webserver-production"
container_name: "production"
restart: unless-stopped
env_file:
- .env
build:
build:
context: ./webserver
dockerfile: ./Dockerfile.prod
expose:
- 80
- 8080
ports:
- "80:80/tcp"
- "8080:8080/tcp"
# - "80:80/tcp"
# - "443:443/tcp"
volumes:
- ./webserver/nginx:/etc/nginx/:ro
ssl-proxy:
image: fsouza/docker-ssl-proxy
ports:
- "80:80"
- "443:443"
environment:
- DOMAIN=10.43.88.1
- TARGET_PORT=8080
- TARGET_HOST=scouting-webserver-prod
- SSL_PORT:443
couchdb:
container_name: "scouting-couchdb"
restart: unless-stopped
@@ -33,4 +47,12 @@ services:
volumes:
- ./couchdb/db.local.ini:/opt/couchdb/etc/local.ini
- ./couchdb/data:/opt/couchdb/data
couch-ssl-proxy:
image: fsouza/docker-ssl-proxy
ports:
- "5985:5985"
environment:
- DOMAIN=10.43.88.1
- TARGET_PORT=5984
- TARGET_HOST=scouting-couchdb
- SSL_PORT:5985
+1
View File
@@ -0,0 +1 @@
docker-compose run certonly --webroot --webroot-path /var/www/certbot/ --dry-run -d scouting.local
+80
View File
@@ -0,0 +1,80 @@
#!/bin/bash
if ! [ -x "$(command -v docker-compose)" ]; then
echo 'Error: docker-compose is not installed.' >&2
exit 1
fi
domains=scouting.local
rsa_key_size=4096
data_path="./data/certbot"
email="" # Adding a valid address is strongly recommended
staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits
if [ -d "$data_path" ]; then
read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision
if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then
exit
fi
fi
if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then
echo "### Downloading recommended TLS parameters ..."
mkdir -p "$data_path/conf"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem"
echo
fi
echo "### Creating dummy certificate for $domains ..."
path="/etc/letsencrypt/live/$domains"
mkdir -p "$data_path/conf/live/$domains"
docker-compose run --rm --entrypoint "\
openssl req -x509 -nodes -newkey rsa:$rsa_key_size -days 1\
-keyout '$path/privkey.pem' \
-out '$path/fullchain.pem' \
-subj '/CN=localhost'" certbot
echo
echo "### Starting nginx ..."
docker-compose up --force-recreate -d nginx
echo
echo "### Deleting dummy certificate for $domains ..."
docker-compose run --rm --entrypoint "\
rm -Rf /etc/letsencrypt/live/$domains && \
rm -Rf /etc/letsencrypt/archive/$domains && \
rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot
echo
echo "### Requesting Let's Encrypt certificate for $domains ..."
#Join $domains to -d args
domain_args=""
for domain in "${domains[@]}"; do
domain_args="$domain_args -d $domain"
done
# Select appropriate email arg
case "$email" in
"") email_arg="--register-unsafely-without-email" ;;
*) email_arg="--email $email" ;;
esac
# Enable staging mode if needed
if [ $staging != "0" ]; then staging_arg="--staging"; fi
docker-compose run --rm --entrypoint "\
certbot certonly --webroot -w /var/www/certbot \
$staging_arg \
$email_arg \
$domain_args \
--rsa-key-size $rsa_key_size \
--agree-tos \
--force-renewal" certbot
echo
echo "### Reloading nginx ..."
docker-compose exec nginx nginx -s reload
+1 -1
View File
@@ -1 +1 @@
docker-compose -f docker-compose.prod.yml up -d --build
docker-compose -f docker-compose.prod.yml up -d --build
+1 -1
View File
@@ -1 +1 @@
docker-compose down
docker-compose down --remove-orphans
+8 -4
View File
@@ -1,9 +1,12 @@
FROM node:16-alpine as build-step
RUN mkdir /app/
RUN mkdir /app/node_modules
RUN chown -R node:node /app/node_modules
#RUN mkdir /app/node_module/.bin
WORKDIR /app/
ENV PATH /app/node_modules/.bin:$PATH
RUN chown -R node:node /app/node_modules
COPY package*.json ./
COPY package.json ./
COPY package-lock.json ./
RUN npm install
COPY . ./
# USER node
@@ -12,6 +15,7 @@ RUN npm run build
FROM nginx:1-alpine
COPY --from=build-step /app/build /usr/share/nginx/html
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx/nginx.conf /etc/nginx/conf.d
EXPOSE 80
# COPY nginx/nginx.conf /etc/nginx/conf.d
EXPOSE 8080
# EXPOSE 443
CMD ["nginx", "-g", "daemon off;"]
+42
View File
@@ -0,0 +1,42 @@
server {
listen 8080;
listen [::]:8080;
; server_name 10.43.88.1;
; server_tokens off;
; location /.well-known/acme-challenge/{
; root /var/www/certbot;
; }
location / {
root /usr/share/nginx/html/;
index index.html index.htm;
try_files $uri $uri/ /index.html;
; return 301 https://$host$request_uri;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
; error_page 500 502 503 504 /50x.html;
; location = /50x.html {
; root /usr/share/nginx/html;
; }
}
; server {
; listen 443 default_server ssl;
; listen [::]:443 ssl;
; server_name 10.43.88.1;
; ssl_certificate /etc/nginx/ssl/live/10.43.88.1/fullchain.pem;
; ssl_certificate_key /etc/nginx/ssl/live/10.43.88.1/privkey.pem;
; include /etc/letsencrypt/options-ssl-nginx.conf;
; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
; location / {
; root /usr/share/nginx/html/;
; index index.html index.htm;
; try_files $uri $uri/ /index.html;
; }
; }
+17 -12
View File
@@ -1,13 +1,18 @@
server {
listen 80;
location / {
root /usr/share/nginx/html/;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
events {
worker_connections 4096; ## Default: 1024
}
http {
server {
listen 8080;
listen [::]:8080;
location / {
root /usr/share/nginx/html/;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
+13 -1
View File
@@ -19,7 +19,19 @@
"react-scripts": "5.0.0",
"web-vitals": "^2.1.3",
"@material-ui/core": "^4.12.3",
"@material-ui/icons": "^4.11.2"
"@material-ui/icons": "^4.11.2",
"workbox-background-sync": "^5.1.4",
"workbox-broadcast-update": "^5.1.4",
"workbox-cacheable-response": "^5.1.4",
"workbox-core": "^5.1.4",
"workbox-expiration": "^5.1.4",
"workbox-google-analytics": "^5.1.4",
"workbox-navigation-preload": "^5.1.4",
"workbox-precaching": "^5.1.4",
"workbox-range-requests": "^5.1.4",
"workbox-routing": "^5.1.4",
"workbox-strategies": "^5.1.4",
"workbox-streams": "^5.1.4"
},
"scripts": {
+3 -2
View File
@@ -1,3 +1,4 @@
.App {
/* height: 100%; */
}
height: 100%;
width: 100%;
}
+11 -17
View File
@@ -16,7 +16,7 @@ import NotFoundPage from "./Pages/NotFoundPage";
import DashboardPage from "./Pages/DashboardPage/DashboardPage";
import WelcomePage from "./Pages/WelcomePage";
import InputPage from "./Pages/InputPage";
import { createMuiTheme, ThemeProvider } from '@material-ui/core'
import { createTheme, ThemeProvider } from '@material-ui/core/styles'
import { Formik, Field, Form } from 'formik';
import { TextField, Button, Grid, FormRow, Checkbox, Radio, FormControlLabel, FormControl, FormLabel, RadioGroup, IconButton, InputAdornment } from "@material-ui/core";
import { AddCircleOutline, RemoveCircleOutline } from "@material-ui/icons";
@@ -25,8 +25,7 @@ import { ProcessedDataBucketProvider } from "./ProcessedDataBucketContext";
function App() {
const darkTheme = createMuiTheme({
const darkTheme = createTheme({
// Theme settings
palette: {
type: "dark",
@@ -35,18 +34,13 @@ function App() {
fontSize: 18
}
});
const styles = {
bigbution: {
}
}
return (
<div className="App">
<ThemeProvider theme={darkTheme}>
<ThemeProvider theme={darkTheme}>
<ProcessedDataBucketProvider>
<DbProvider>
<ProcessedDataBucketProvider>
<Router>
<Navigation />
<Router>
<Navigation />
<div className="App">
<Routes>
<Route path="/" element={<WelcomePage />} />
<Route path="/Dashboard" element={<DashboardPage />} />
@@ -54,11 +48,11 @@ function App() {
<Route path="/404" element={<NotFoundPage />} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
</Router>
</ProcessedDataBucketProvider>
</div>
</Router>
</DbProvider>
</ThemeProvider>
</div>
</ProcessedDataBucketProvider>
</ThemeProvider>
);
}
+4 -12
View File
@@ -14,6 +14,7 @@ export function useRemoteDb() {
}
export function DbProvider({ children }) {
const pdb = React.useContext(ProcessedDataBucketContext);
const [localdb, setLocaldb] = useState(new PouchDB("testdata"));
//used in development server
const [remotedb, setRemotedb] = useState(
@@ -25,25 +26,16 @@ export function DbProvider({ children }) {
},
})
);
console.log(remotedb);
// const [remotedb, setRemotedb] = useState(new PouchDB(window.location.protocol + "//" + window.location.hostname + ":5984/kcmt2021", {skip_setup: true}))
//Login to the Remote Database
// remotedb.logIn('2021', 'Ridgebotics').then(function () {
// console.log("CouchDb Login Successful!");
// }).catch(function (err) {
// console.log("Unable to login to CouchDb!");
// console.log(err);
// });
pdb.updateData(localdb);
localdb
.sync(remotedb, {
live: true,
retry: true,
})
.on("change", function (change) {
const pdb = React.useContext(ProcessedDataBucketContext);
console.log(pdb);
console.log('DB CHANGED');
pdb.updateData(localdb);
})
.on("paused", function (info) { })
.on("active", function (info) { })
+10 -10
View File
@@ -1,13 +1,13 @@
.maxwidth {
display: block;
/* margin-left: auto;
margin-right: auto; */
width: 100%;
text-align: center;
margin: auto;
max-width: fit-content;
/* max-width: 100% */
display: block;
margin-left: auto;
margin-right: auto;
width: 100%;
text-align: center;
margin: auto;
max-width: fit-content;
/* max-width: 100% */
}
.smallfeild {
max-width: 25%;
}
max-width: 25%;
}
+63 -238
View File
@@ -13,6 +13,7 @@ import {
Button,
Grid,
FormRow,
Divider,
Checkbox,
Radio,
FormControlLabel,
@@ -26,9 +27,8 @@ import { AddCircleOutline, RemoveCircleOutline } from "@material-ui/icons";
const InputPage = () => {
const localdb = useLocalDb();
console.log(localdb);
return (
<div class="maxwidth">
<div>
<br />
<Formik
initialValues={{
@@ -39,17 +39,19 @@ const InputPage = () => {
team_abilities_cant: "",
fouls: "0",
fouls_tech: "0",
flips: "0",
flipped: false,
red_cards: "0",
yellow_cards: "0",
disabled: false,
taxi_auto: false,
upper_hub_auto: "0",
lower_hub_auto: "0",
upper_hub: "0",
lower_hub: "0",
upper_hub_teleop: "0",
lower_hub_teleop: "0",
climb_level: "",
alliance: "",
defence: ""
defence: "0",
disabled: false
}}
onSubmit={(values, { setSubmitting, resetForm }) => {
setTimeout(() => {
@@ -82,31 +84,13 @@ const InputPage = () => {
handleSubmit,
isSubmitting,
}) => (
<Form >
<Grid
container
direction="row"
justify="center"
alignItems="flex-start"
spacing={3}>
<Grid container direction="row" justifyContent="center" alignItems="flex-end" spacing={3}>
<Grid item>
{" "}
<Field
type="input"
as={TextField}
name="team_number"
label="Team #"
/>{" "}
<Field type="input" as={TextField} name="team_number" label="Team #" />
</Grid>
<Grid item>
{" "}
<Field
type="input"
as={TextField}
name="match_number"
label="Match Number"
/>{" "}
<Field type="input" as={TextField} name="match_number" label="Match Number" />
</Grid>
<Grid item>
<FormControl component="fieldset">
@@ -114,25 +98,13 @@ const InputPage = () => {
<RadioGroup aria-label="Alliance" name="alliance" row>
<FormControlLabel
control={
<Field
as={Radio}
type="radio"
name="alliance"
value="red"
style={{ fontSize: 50 }}
/>
<Field as={Radio} type="radio" name="alliance" value="red" style={{ fontSize: 50 }} />
}
label="Red"
/>
<FormControlLabel
control={
<Field
as={Radio}
type="radio"
name="alliance"
value="blue"
/>
<Field as={Radio} type="radio" name="alliance" value="blue" />
}
label="Blue"
/>
@@ -140,118 +112,62 @@ const InputPage = () => {
</FormControl>
</Grid>
</Grid>
<div />
<Grid
container
direction="row"
justify="center"
alignItems="flex-start"
spacing={3}>
<Grid container direction="row" justifyContent="center" alignItems="flex-end" spacing={3}>
<Grid item>
<Grid
container
direction="column"
justify="flex-start"
alignItems="center"
spacing={3}>
<Grid container direction="column" justifyContent="flex-end" alignItems="center" spacing={3}>
<Grid item>
<InputNumberField
name="upper_hub_auto"
label="Upper Hub Auto"
/>
<InputNumberField name="upper_hub_auto" label="Upper Hub Auto" />
</Grid>
<Grid item>
<InputNumberField
name="lower_hub_auto"
label="Lower Hub Auto"
/>
<InputNumberField name="lower_hub_auto" label="Lower Hub Auto" />
</Grid>
</Grid>
</Grid>
<Grid item>
{" "}
<Grid
container
direction="column"
justify="flex-start"
alignItems="center"
spacing={3}>
<Grid container direction="column" justifyContent="flex-end" alignItems="center" spacing={3}>
<Grid item>
{" "}
<InputNumberField name="upper_hub" label="Upper Hub" />{" "}
<InputNumberField name="upper_hub_teleop" label="Upper Hub Teleop" />
</Grid>
<Grid item>
{" "}
<InputNumberField name="lower_hub" label="Lower Hub" />{" "}
<InputNumberField name="lower_hub_teleop" label="Lower Hub Teleop" />
</Grid>
</Grid>{" "}
</Grid>
</Grid>
</Grid>
<div />
<Grid
container
direction="row"
justify="center"
alignItems="flex-start"
spacing={3}>
<Grid container direction="row" justifyContent="center" alignItems="flex-end" spacing={3}>
<Grid item>
<FormControl component="fieldset">
<FormLabel component="legend">Climbing</FormLabel>
<RadioGroup aria-label="Climbing" name="climb_level" row>
<FormControlLabel
control={
<Field
as={Radio}
type="radio"
name="climb_level"
value="0"
/>
<Field as={Radio} type="radio" name="climb_level" value="0" />
}
label="None"
/>
<FormControlLabel
control={
<Field
as={Radio}
type="radio"
name="climb_level"
value="1"
/>
<Field as={Radio} type="radio" name="climb_level" value="1" />
}
label="Low"
/>
<FormControlLabel
control={
<Field
as={Radio}
type="radio"
name="climb_level"
value="2"
/>
<Field as={Radio} type="radio" name="climb_level" value="2" />
}
label="Mid"
/>
<FormControlLabel
control={
<Field
as={Radio}
type="radio"
name="climb_level"
value="3"
/>
<Field as={Radio} type="radio" name="climb_level" value="3" />
}
label="High"
/>
<FormControlLabel
control={
<Field
as={Radio}
type="radio"
name="climb_level"
value="4"
/>
<Field as={Radio} type="radio" name="climb_level" value="4" />
}
label="Traversal"
/>
@@ -259,168 +175,77 @@ const InputPage = () => {
</FormControl>
</Grid>
</Grid>
<div />
<Grid
container
direction="row"
justify="center"
alignItems="flex-start"
spacing={3}>
<Grid container direction="row" justifyContent="center" alignItems="flex-end" spacing={3}>
<Grid item>
<Grid
container
direction="column"
justify="flex-start"
alignItems="center"
spacing={3}>
<Grid container direction="column" justifyContent="flex-end" alignItems="center" spacing={3}>
<Grid item>
<InputNumberField name="fouls" label="Fouls" />{" "}
</Grid>{" "}
<InputNumberField name="fouls" label="Fouls" />
</Grid>
<Grid item>
<InputNumberField name="fouls_tech" label="Tech Fouls" />{" "}
</Grid>{" "}
<InputNumberField name="fouls_tech" label="Tech Fouls" />
</Grid>
</Grid>
</Grid>
<Grid item>
<Grid
container
direction="column"
justify="flex-start"
alignItems="center"
spacing={3}>
<Grid container direction="column" justifyContent="flex-end" alignItems="center" spacing={3}>
<Grid item>
<InputNumberField name="red_cards" label="Red Cards" />{" "}
</Grid>{" "}
<Grid item>
<InputNumberField name="yellow_cards" label="Yellow Cards" />{" "}
<InputNumberField name="red_cards" label="Red Cards" />
</Grid>
<Grid item>
{/* <InputNumberField name="disables" label="Disables" />{" "} */}
</Grid>{" "}
<InputNumberField name="yellow_cards" label="Yellow Cards" />
</Grid>
</Grid>
</Grid>
</Grid>
<div />
<Grid
container
direction="row"
justify="center"
alignItems="flex-start"
spacing={3}>
<Grid container direction="row" justifyContent="center" alignItems="flex-end" spacing={3}>
<Grid item>
<FormControl component="fieldset">
<FormLabel component="legend">Defense</FormLabel>
<RadioGroup aria-label="Defense" name="defence" row>
<FormControlLabel
control={
<Field
as={Radio}
type="radio"
name="defence"
value="0"
/>
}
label="N/A"
control={<Field as={Radio} type="radio" name="defence" value="0" />}
label="None"
/>
{/* <Divider orientation="vertical" flexItem middle /> */}
<FormControlLabel
control={
<Field
as={Radio}
type="radio"
name="defence"
value="1"
/>
}
control={<Field as={Radio} type="radio" name="defence" value="1" />}
label="Poor"
/>
<FormControlLabel
control={
<Field
as={Radio}
type="radio"
name="defence"
value="2"
/>
}
control={<Field as={Radio} type="radio" name="defence" value="2" />}
label="Good"
/>
<FormControlLabel
control={
<Field
as={Radio}
type="radio"
name="defence"
value="3"
/>
}
/> <FormControlLabel
control={<Field as={Radio} type="radio" name="defence" value="3" />}
label="Exceptional"
/>
</RadioGroup>
</FormControl>
</Grid>
</Grid>
<div />
<Grid
container
direction="row"
justify="center"
alignItems="flex-start"
spacing={3}>
<Grid item>
{" "}
<Field
type="input"
as={TextField}
multiline
rows={3}
rowsMax={7}
labelWidth={60}
name="team_abilities_well"
label="What they did Well"
/>{" "}
</Grid>
<Grid item>
{" "}
<Field
type="input"
as={TextField}
multiline
rows={3}
rowsMax={7}
labelWidth={60}
name="team_abilities_struggle"
label="What they struggled with"
/>{" "}
</Grid>
<Grid item>
{" "}
<Field
type="input"
as={TextField}
multiline
rows={3}
rowsMax={7}
labelWidth={60}
name="team_abilities_cant"
label="What they can't do"
/>{" "}
<FormControlLabel
control={<Field as={Checkbox} type="checkbox" name="disabled" />}
label="Disabled"
/>
</Grid>
</Grid>
<div />
<Grid
container
direction="row"
justify="center"
alignItems="flex-start"
spacing={3}>
<Grid container direction="row" justifyContent="center" alignItems="flex-end" spacing={3}>
<Grid item>
<Field type="input" as={TextField} multiline rows={3} name="team_abilities_well" label="What they did Well" />
</Grid>
<Grid item>
<Field type="input" as={TextField} multiline rows={3} name="team_abilities_struggle" label="What they struggled with" />
</Grid>
<Grid item>
<Field type="input" as={TextField} multiline rows={3} name="team_abilities_cant" label="What they can't do" />
</Grid>
</Grid>
<div />
<Grid container direction="row" justifyContent="center" alignItems="flex-end" spacing={3}>
<Button type="submit" disabled={isSubmitting}>
{" "}
Submit{" "}
Submit
</Button>
</Grid>
</Form>
+7 -7
View File
@@ -1,12 +1,12 @@
.welcome {
display: block;
/* margin-left: auto;
margin-right: auto; */
width: 100%;
text-align: center;
margin: auto;
display: block;
margin-left: auto;
margin-right: auto;
width: 100%;
text-align: center;
margin: auto;
}
.welcome img {
max-width: 100%;
}
}
+2 -2
View File
@@ -3,9 +3,9 @@ import "./WelcomePage.css";
import "../App.css";
const WelcomePage = () => {
return (
<div class = "welcome">
<div className="welcome">
<h1>Welcome to Ridgebotics Scouting Web Application 2022</h1>
<img src = "/WelcomePageImage.webp"/>
<img src="/WelcomePageImage.webp" />
</div>
)
}
+91 -47
View File
@@ -1,8 +1,13 @@
export class ProcessedDataBucket {
constructor() {
this.teamData = null;
this.matchData = null;
this.teamData = {};
this.matchData = {};
this.updateData = (db) => {
//reset data
this.teamData = {};
this.matchData = {};
console.log(db);
db.allDocs({
include_docs: true,
})
@@ -11,55 +16,94 @@ export class ProcessedDataBucket {
result.rows.forEach((dbentry) => {
let doc = dbentry.doc;
console.log(doc);
//if there's no processed data on a team yet, create a default data entry
if (typeof this.teamData[doc.team_name] === "undefined") {
this.teamData[doc.team_name] = {
team_name: doc.team_name,
alliance: doc.alliance,
games_played: 0,
climbs_none: 0,
climbs_low: 0,
climbs_mid: 0,
climbs_high: 0,
climbs_transverse: 0,
points: 0,
point_average: 0,
num_disables: 0,
disables_average: 0,
num_flips: 0,
flips_average: 0,
fouls: 0,
fouls_average: 0,
fouls_tech: 0,
fouls_tech_average: 0,
};
}
let thisTeamData = this.teamData[doc.team_name];
console.log(thisTeamData);
let new_team_data = {
...thisTeamData,
games_played: thisTeamData.games_played + 1,
num_climbs: thisTeamData.num_climbs + (doc.climb == true ? 1 : 0),
num_disables: thisTeamData.num_disables + (doc.disabled == true ? 1 : 0),
num_flips: thisTeamData.num_flips + (doc.flipped_over == true ? 1 : 0),
fouls: thisTeamData.fouls + parseInt(doc.fouls),
fouls_tech: thisTeamData.fouls_tech + parseInt(doc.fouls_tech),
inner_port: thisTeamData.inner_port + parseInt(doc.inner_port),
outer_port: thisTeamData.outer_port + parseInt(doc.outer_port),
lower_port: thisTeamData.lower_port + parseInt(doc.lower_port),
};
console.log(new_team_data);
// //if there's no processed data on a team yet, create a default data entry
// if (typeof this.teamData[doc.team_number] === "undefined") {
// this.teamData[doc.team_number] = {
// team_number: doc.team_number,
// games_played: 0,
// data_sets: {
// upper_hub_auto: [],
// lower_hub_auto: [],
// upper_hub: [],
// lower_hub: [],
// match_points: []
// },
// climbs_none: 0,
// climbs_low: 0,
// climbs_mid: 0,
// climbs_high: 0,
// climbs_transverse: 0,
// points_average: 0,
// num_disables: 0,
// num_flips: 0,
// fouls: 0,
// fouls_tech: 0,
// red_cards: 0,
// yellow_cards: 0
// };
// }
// //add this game's data to the respective team data:
// let thisTeamData = this.teamData[doc.team_number];
// thisTeamData.games_played++;
// let match_points
// = parseInt(doc.taxi_auto)
// + parseInt(doc.upper_hub_auto) * 4
// + parseInt(doc.lower_hub_auto) * 2
// + parseInt(doc.upper_hub_teleop) * 2
// + parseInt(doc.lower_hub_teleop) * 1
// + (parseInt(doc.climb_level) == 0 ? 4 : 0)
// + (parseInt(doc.climb_level) == 1 ? 6 : 0)
// + (parseInt(doc.climb_level) == 2 ? 10 : 0)
// + (parseInt(doc.climb_level) == 3 ? 15 : 0)
// ;
// //data sets
// thisTeamData.data_sets.upper_hub_auto.push(parseInt(doc.upper_hub_auto));
// thisTeamData.data_sets.lower_hub_auto.push(parseInt(doc.lower_hub_auto));
// thisTeamData.data_sets.upper_hub.push(parseInt(doc.upper_hub));
// thisTeamData.data_sets.lower_hub.push(parseInt(doc.lower_hub));
// thisTeamData.data_sets.match_points.push(match_points);
// //climb data
// switch (parseInt(doc.climb_level)) {
// case 0:
// thisTeamData.climbs_none++;
// break;
// case 1:
// thisTeamData.climbs_low++;
// break;
// case 2:
// thisTeamData.climbs_mid++;
// break;
// case 3:
// thisTeamData.climbs_high++;
// break;
// case 4:
// thisTeamData.climbs_transverse++;
// break;
// default:
// console.error('Invalid Climb Level (how did this even happen lol?): ' + doc.climb_level);
// break;
// }
// //misc data
// thisTeamData.num_disables += doc.disabled ? 1 : 0;
// thisTeamData.num_flips += doc.flipped ? 1 : 0;
// thisTeamData.fouls += parseInt(doc.fouls);
// thisTeamData.fouls_tech += parseInt(doc.fouls_tech);
// thisTeamData.red_cards += parseInt(doc.red_cards);
// thisTeamData.yellow_cards += parseInt(doc.yellow_cards);
// console.log(thisTeamData);
});
})
.catch((err) => {
console.log("Error Fetching Docs from Database!");
console.log(err);
console.log("Error while processing data!");
console.error(err);
});
let datasets = [
{
data: [],
},
];
};
}
}
@@ -1,5 +1,4 @@
import React, { useContext, useState } from "react";
import { useLocalDb } from "./DbContext";
import { ProcessedDataBucket } from "./ProcessedDataBucket.jsx"
export const ProcessedDataBucketContext = React.createContext();
@@ -25,16 +25,15 @@ const InputNumberField = (props) => {
name={props.name}
label={props.label}
InputProps={{
style: { fontSize: 40, "max-width": 300 },
style: { fontSize: 40, "maxWidth": 300 },
startAdornment: (
<InputAdornment position="start">
<IconButton
onClick={() => {
setFieldValue(props.name, Math.max(parseInt(values[props.name]) - 1, 0));
}}
iconStyle={{ width: '48px', height: '48px' }}
style={{ width: '96px', height: '96px', padding: '24px' }}
touch={true}
touch="true"
>
<RemoveCircleOutline style={{ fontSize: 50 }} />
</IconButton>
@@ -46,11 +45,8 @@ const InputNumberField = (props) => {
onClick={() => {
setFieldValue(props.name, Math.max(parseInt(values[props.name]) + 1, 0));
}}
iconStyle={{ width: '100px', height: '100px' }}
style={{ width: '96px', height: '96px', padding: '0' }}
touch={true}
size="large"
touch="true"
>
<AddCircleOutline style={{ fontSize: 50 }} />
</IconButton>
@@ -0,0 +1,8 @@
.Navigation {
position: -webkit-sticky; /*for safari*/
position: sticky;
top: 0;
left: 0;
width: 100%;
z-index: 1;
}
@@ -1,6 +1,7 @@
import React, {Component} from 'react'
import Toolbar from './Toolbar/Toolbar'
import SideDrawer from './Drawer/SideDrawer'
import './Navigation.css'
class Navigation extends Component {
state = {
@@ -15,7 +16,7 @@ class Navigation extends Component {
render() {
return (
<div>
<div className="Navigation">
<Toolbar drawerClickHandler={this.drawerToggleClickHandler} />
<SideDrawer show={this.state.sideDrawerOpen} drawerClickHandler={this.drawerToggleClickHandler}/>
</div>
@@ -1,63 +1,60 @@
.toolbar {
position: sticky;
top: 0px;
left: 0;
width: 100%;
background: #00a65a;
height: 56px
width: 100%;
background: #00a65a;
height: 56px;
}
.toolbar_navigation {
display: flex;
height: 100%;
align-items: center;
padding: 0 1rem;
display: flex;
height: 100%;
align-items: center;
padding: 0 1rem;
}
.toolbar_logo {
margin-left: 0.5rem;
margin-left: 0.5rem;
}
.toolbar_logo a {
color: white;
text-decoration: none;
font-size: 2.0rem;
color: white;
text-decoration: none;
font-size: 2rem;
}
.toolbar_spacer {
flex: 1;
flex: 1;
}
.toolbar_items ul {
list-style: none;
margin: 0;
padding: 0 0;
display: flex;
list-style: none;
margin: 0;
padding: 0 0;
display: flex;
}
.toolbar_items li {
color: white;
background-color: #00000000;
text-decoration: none;
font-size: 1.5rem;
padding: 0 0.6rem;
color: white;
background-color: #00000000;
text-decoration: none;
font-size: 1.5rem;
padding: 0 0.6rem;
}
.toolbar_items a {
color: white;
text-decoration: none;
padding-top: 0.8rem;
padding-bottom: 0.8rem;
color: white;
text-decoration: none;
padding-top: 0.8rem;
padding-bottom: 0.8rem;
}
.toolbar_items a:hover,
.toolbar_items a:active {
color: #ff3b76;
color: #ff3b76;
}
@media (max-width: 768px) {
.toolbar_items {
display: none;
}
}
.toolbar_items {
display: none;
}
}
@@ -10,7 +10,7 @@ const Toolbar = props => {
<header className="toolbar">
<nav className="toolbar_navigation">
<DrawerButton click={props.drawerClickHandler} />
<div className = "toolbar_logo"><Link to="/">Ridgebotics Scouting</Link></div>
<div className = "toolbar_logo"><Link to="/">Ridgebotics Scouting ;)</Link></div>
<div className = "toolbar_spacer" />
<div className = "toolbar_items">
<PagesList />
+9 -8
View File
@@ -1,12 +1,13 @@
body {
background-color: rgb(20, 26, 24);
color: white;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: rgb(20, 26, 24);
color: white;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow-x: hidden;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
}
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
}
+7 -1
View File
@@ -2,7 +2,8 @@ import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
@@ -11,6 +12,11 @@ ReactDOM.render(
document.getElementById("root")
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://cra.link/PWA
serviceWorkerRegistration.register();
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
+72
View File
@@ -0,0 +1,72 @@
/* eslint-disable no-restricted-globals */
// This service worker can be customized!
// See https://developers.google.com/web/tools/workbox/modules
// for the list of available Workbox modules, or add any other
// code you'd like.
// You can also remove this file if you'd prefer not to use a
// service worker, and the Workbox build step will be skipped.
import { clientsClaim } from 'workbox-core';
import { ExpirationPlugin } from 'workbox-expiration';
import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate } from 'workbox-strategies';
clientsClaim();
// Precache all of the assets generated by your build process.
// Their URLs are injected into the manifest variable below.
// This variable must be present somewhere in your service worker file,
// even if you decide not to use precaching. See https://cra.link/PWA
precacheAndRoute(self.__WB_MANIFEST);
// Set up App Shell-style routing, so that all navigation requests
// are fulfilled with your index.html shell. Learn more at
// https://developers.google.com/web/fundamentals/architecture/app-shell
const fileExtensionRegexp = new RegExp('/[^/?]+\\.[^/]+$');
registerRoute(
// Return false to exempt requests from being fulfilled by index.html.
({ request, url }) => {
// If this isn't a navigation, skip.
if (request.mode !== 'navigate') {
return false;
} // If this is a URL that starts with /_, skip.
if (url.pathname.startsWith('/_')) {
return false;
} // If this looks like a URL for a resource, because it contains // a file extension, skip.
if (url.pathname.match(fileExtensionRegexp)) {
return false;
} // Return true to signal that we want to use the handler.
return true;
},
createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html')
);
// An example runtime caching route for requests that aren't handled by the
// precache, in this case same-origin .png requests like those from in public/
registerRoute(
// Add in any other file extensions or routing criteria as needed.
({ url }) => url.origin === self.location.origin && url.pathname.endsWith('.png'), // Customize this strategy as needed, e.g., by changing to CacheFirst.
new StaleWhileRevalidate({
cacheName: 'images',
plugins: [
// Ensure that once this runtime cache reaches a maximum size the
// least-recently used images are removed.
new ExpirationPlugin({ maxEntries: 50 }),
],
})
);
// This allows the web app to trigger skipWaiting via
// registration.waiting.postMessage({type: 'SKIP_WAITING'})
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});
// Any other custom service worker logic can go here.
+137
View File
@@ -0,0 +1,137 @@
// This optional code is used to register a service worker.
// register() is not called by default.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
// To learn more about the benefits of this model and instructions on how to
// opt-in, read https://cra.link/PWA
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.0/8 are considered localhost for IPv4.
window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
);
export function register(config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://cra.link/PWA'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then((registration) => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://cra.link/PWA.'
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch((error) => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl, {
headers: { 'Service-Worker': 'script' },
})
.then((response) => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then((registration) => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log('No internet connection found. App is running in offline mode.');
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready
.then((registration) => {
registration.unregister();
})
.catch((error) => {
console.error(error.message);
});
}
}