mirror of
https://github.com/Team4388/ScoutingApp2022.git
synced 2026-06-08 16:28:04 -06:00
we ball
This commit is contained in:
@@ -16,6 +16,6 @@ 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 8080
|
||||
EXPOSE 80
|
||||
# EXPOSE 443
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
|
||||
types {
|
||||
text/html html htm shtml;
|
||||
text/css css;
|
||||
text/xml xml;
|
||||
image/gif gif;
|
||||
image/jpeg jpeg jpg;
|
||||
application/javascript js;
|
||||
application/atom+xml atom;
|
||||
application/rss+xml rss;
|
||||
|
||||
text/mathml mml;
|
||||
text/plain txt;
|
||||
text/vnd.sun.j2me.app-descriptor jad;
|
||||
text/vnd.wap.wml wml;
|
||||
text/x-component htc;
|
||||
|
||||
image/png png;
|
||||
image/svg+xml svg svgz;
|
||||
image/tiff tif tiff;
|
||||
image/vnd.wap.wbmp wbmp;
|
||||
image/webp webp;
|
||||
image/x-icon ico;
|
||||
image/x-jng jng;
|
||||
image/x-ms-bmp bmp;
|
||||
|
||||
application/font-woff woff;
|
||||
application/java-archive jar war ear;
|
||||
application/json json;
|
||||
application/mac-binhex40 hqx;
|
||||
application/msword doc;
|
||||
application/pdf pdf;
|
||||
application/postscript ps eps ai;
|
||||
application/rtf rtf;
|
||||
application/vnd.apple.mpegurl m3u8;
|
||||
application/vnd.google-earth.kml+xml kml;
|
||||
application/vnd.google-earth.kmz kmz;
|
||||
application/vnd.ms-excel xls;
|
||||
application/vnd.ms-fontobject eot;
|
||||
application/vnd.ms-powerpoint ppt;
|
||||
application/vnd.oasis.opendocument.graphics odg;
|
||||
application/vnd.oasis.opendocument.presentation odp;
|
||||
application/vnd.oasis.opendocument.spreadsheet ods;
|
||||
application/vnd.oasis.opendocument.text odt;
|
||||
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||
pptx;
|
||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
xlsx;
|
||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
docx;
|
||||
application/vnd.wap.wmlc wmlc;
|
||||
application/x-7z-compressed 7z;
|
||||
application/x-cocoa cco;
|
||||
application/x-java-archive-diff jardiff;
|
||||
application/x-java-jnlp-file jnlp;
|
||||
application/x-makeself run;
|
||||
application/x-perl pl pm;
|
||||
application/x-pilot prc pdb;
|
||||
application/x-rar-compressed rar;
|
||||
application/x-redhat-package-manager rpm;
|
||||
application/x-sea sea;
|
||||
application/x-shockwave-flash swf;
|
||||
application/x-stuffit sit;
|
||||
application/x-tcl tcl tk;
|
||||
application/x-x509-ca-cert der pem crt;
|
||||
application/x-xpinstall xpi;
|
||||
application/xhtml+xml xhtml;
|
||||
application/xspf+xml xspf;
|
||||
application/zip zip;
|
||||
|
||||
application/octet-stream bin exe dll;
|
||||
application/octet-stream deb;
|
||||
application/octet-stream dmg;
|
||||
application/octet-stream iso img;
|
||||
application/octet-stream msi msp msm;
|
||||
|
||||
audio/midi mid midi kar;
|
||||
audio/mpeg mp3;
|
||||
audio/ogg ogg;
|
||||
audio/x-m4a m4a;
|
||||
audio/x-realaudio ra;
|
||||
|
||||
video/3gpp 3gpp 3gp;
|
||||
video/mp2t ts;
|
||||
video/mp4 mp4;
|
||||
video/mpeg mpeg mpg;
|
||||
video/quicktime mov;
|
||||
video/webm webm;
|
||||
video/x-flv flv;
|
||||
video/x-m4v m4v;
|
||||
video/x-mng mng;
|
||||
video/x-ms-asf asx asf;
|
||||
video/x-ms-wmv wmv;
|
||||
video/x-msvideo avi;
|
||||
}
|
||||
@@ -2,9 +2,10 @@ events {
|
||||
worker_connections 4096; ## Default: 1024
|
||||
}
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
server {
|
||||
listen 8080;
|
||||
listen [::]:8080;
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
location / {
|
||||
root /usr/share/nginx/html/;
|
||||
index index.html index.htm;
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
"@testing-library/react": "^12.1.2",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"react-apexcharts": "^1.3.9",
|
||||
"ag-grid-community": "^26.2.1",
|
||||
"ag-grid-react": "^26.2.0",
|
||||
"formik": "^2.2.9",
|
||||
"pouchdb": "^7.2.2",
|
||||
"react": "^17.0.2",
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#00a65a" />
|
||||
<meta name="description" content="Ridgebotics Scouting App 2022" />
|
||||
<!-- disable user zooming/scaling on mobile -->
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no">
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
|
||||
@@ -19,11 +19,11 @@ function App() {
|
||||
palette: {
|
||||
mode: "dark",
|
||||
background: {
|
||||
paper: "#101515",
|
||||
paper: "#203030",
|
||||
},
|
||||
text: {
|
||||
// primary: "#edf8f3",
|
||||
// secondary: "#acd3bf",
|
||||
primary: "#edf8f3",
|
||||
secondary: "#acd3bf",
|
||||
},
|
||||
red_alliance: "#ec2e63",
|
||||
blue_alliance: "#2d74eb",
|
||||
|
||||
+69
-23
@@ -1,6 +1,6 @@
|
||||
import PouchDB from "pouchdb";
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import { ProcessedDataBucketContext, useProcessedDataBucket } from "./ProcessedDataBucketContext";
|
||||
import { useProcessedDataBucket } from "./ProcessedDataBucketContext";
|
||||
import { getProcessedDataBucket, updateProcessedDataBucket } from "./ProcessedDataBucket";
|
||||
|
||||
const LocalDbContext = React.createContext();
|
||||
@@ -16,12 +16,11 @@ export function useRemoteDb() {
|
||||
|
||||
export function DbProvider({ children }) {
|
||||
// const pdbCtx = useProcessedDataBucket();
|
||||
const { processedDataBucket, setProcessedDataBucket } = useContext(ProcessedDataBucketContext);
|
||||
const { processedDataBucket, setProcessedDataBucket } = useProcessedDataBucket();
|
||||
// console.log(pdb);
|
||||
const [localdb, setLocaldb] = useState(new PouchDB("testdata"));
|
||||
//used in development server
|
||||
const [localdb, setLocaldb] = useState(new PouchDB("denver_fr"));
|
||||
const [remotedb, setRemotedb] = useState(
|
||||
new PouchDB("http://" + window.location.hostname + ":5984/testdata", {
|
||||
new PouchDB("http://" + window.location.hostname + ":5984/denver_fr", {
|
||||
skip_setup: true,
|
||||
auth: {
|
||||
username: "scouting",
|
||||
@@ -29,25 +28,50 @@ export function DbProvider({ children }) {
|
||||
},
|
||||
})
|
||||
);
|
||||
localdb.replicate
|
||||
.from(remotedb, {
|
||||
live: true,
|
||||
retry: true,
|
||||
})
|
||||
.on("change", (change) => {
|
||||
updateProcessedDataBucket(localdb, setProcessedDataBucket);
|
||||
});
|
||||
// updateProcessedDataBucket(localdb, setProcessedDataBucket);
|
||||
// useEffect(() => {
|
||||
// setDatabaseName("denver_fr", setLocaldb, setRemotedb, setProcessedDataBucket);
|
||||
// });
|
||||
|
||||
useEffect(() => {
|
||||
console.log("TEST");
|
||||
updateProcessedDataBucket(localdb, setProcessedDataBucket);
|
||||
localdb
|
||||
.sync(remotedb, {
|
||||
live: true,
|
||||
retry: true,
|
||||
})
|
||||
.on("change", function (change) {
|
||||
console.log("DB CHANGED");
|
||||
updateProcessedDataBucket(localdb, setProcessedDataBucket);
|
||||
})
|
||||
.on("paused", function (info) {})
|
||||
.on("active", function (info) {})
|
||||
.on("error", function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
}, [localdb, setProcessedDataBucket]);
|
||||
// useEffect(() => {
|
||||
// updateProcessedDataBucket(localdb, setProcessedDataBucket);
|
||||
// localdb
|
||||
// .sync(remotedb, {
|
||||
// live: true,
|
||||
// retry: true,
|
||||
// })
|
||||
// .on("change", function (change) {
|
||||
// console.log("DB CHANGED");
|
||||
// updateProcessedDataBucket(localdb, setProcessedDataBucket);
|
||||
// })
|
||||
// .on("paused", function (info) {
|
||||
// console.log("sync paused");
|
||||
// // console.log(info);
|
||||
// })
|
||||
// .on("active", function (info) {
|
||||
// console.log("sync active");
|
||||
// // console.log(info);
|
||||
// })
|
||||
// .on("denied", function (info) {
|
||||
// console.log("sync denied");
|
||||
// // console.log(info);
|
||||
// })
|
||||
// .on("complete", function (info) {
|
||||
// console.log("sync complete");
|
||||
// // console.log(info);
|
||||
// })
|
||||
// .on("error", function (err) {
|
||||
// console.error(err);
|
||||
// });
|
||||
// }, [localdb, setProcessedDataBucket]);
|
||||
|
||||
return (
|
||||
<LocalDbContext.Provider value={{ localdb, setLocaldb }}>
|
||||
@@ -55,3 +79,25 @@ export function DbProvider({ children }) {
|
||||
</LocalDbContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function setDatabaseName(name, setLocaldb, setRemotedb, setProcessedDataBucket) {
|
||||
let localdb = new PouchDB(name);
|
||||
let remotedb = new PouchDB("http://" + window.location.hostname + ":5984/" + name, {
|
||||
skip_setup: true,
|
||||
auth: {
|
||||
username: "scouting",
|
||||
password: "Ridgebotics",
|
||||
},
|
||||
});
|
||||
localdb.replicate
|
||||
.from(remotedb, {
|
||||
live: true,
|
||||
retry: true,
|
||||
})
|
||||
.on("change", (change) => {
|
||||
updateProcessedDataBucket(localdb, setProcessedDataBucket);
|
||||
});
|
||||
updateProcessedDataBucket(localdb, setProcessedDataBucket);
|
||||
setLocaldb(localdb);
|
||||
setRemotedb(remotedb);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import React from "react";
|
||||
import ComparisonPanel from "./ComparisonPanel";
|
||||
|
||||
const AnalyticsPanel = (props) => {
|
||||
if (props.selectedTeams.length > 0) return <ComparisonPanel selectedTeams={props.selectedTeams} />;
|
||||
return <div />;
|
||||
};
|
||||
|
||||
export default AnalyticsPanel;
|
||||
@@ -0,0 +1,67 @@
|
||||
import React from "react";
|
||||
import { ProcessedDataBucketContext, useProcessedDataBucket } from "../../ProcessedDataBucketContext";
|
||||
import Chart from "react-apexcharts";
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
const ComparativeBoxPlot = (props) => {
|
||||
let { processedDataBucket, setProcessedDataBucket } = useProcessedDataBucket();
|
||||
const getPercentile = (sorted_set, percentile) => {
|
||||
let idx = percentile * sorted_set.length;
|
||||
if (Math.floor(idx) == idx) return sorted_set[idx - 1] / 2 + sorted_set[idx] / 2;
|
||||
else return sorted_set[Math.floor(idx)];
|
||||
};
|
||||
const getFiveNumberSummary = (set) => {
|
||||
set.sort();
|
||||
return [set[0], getPercentile(set, 0.25), getPercentile(set, 0.5), getPercentile(set, 0.75), set[set.length - 1]];
|
||||
};
|
||||
const generateBoxPlotData = (pdb, setName, selectedTeams) => {
|
||||
let data = [];
|
||||
for (const teamNumber of selectedTeams) {
|
||||
//console.log(pdb.teamData[teamNumber].data_sets[setName]);
|
||||
data.push({
|
||||
x: teamNumber,
|
||||
y: getFiveNumberSummary(pdb.teamData[teamNumber].data_sets[setName]),
|
||||
});
|
||||
}
|
||||
return [
|
||||
{
|
||||
type: "boxPlot",
|
||||
data: data,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ width: "350px", height: "220px" }}>
|
||||
<Chart
|
||||
type="boxPlot"
|
||||
options={{
|
||||
chart: {
|
||||
type: "boxPlot",
|
||||
width: 350,
|
||||
},
|
||||
theme: {
|
||||
mode: "dark",
|
||||
},
|
||||
title: {
|
||||
text: props.title,
|
||||
},
|
||||
}}
|
||||
series={generateBoxPlotData(processedDataBucket, props.setName, props.selectedTeams)}
|
||||
/>
|
||||
</Box>
|
||||
/* <Chart
|
||||
options={{
|
||||
chart: {
|
||||
width: 384,
|
||||
type: "pie",
|
||||
},
|
||||
labels: ["None", "Low", "Mid", "High", "Transversal"],
|
||||
}}
|
||||
series={processedDataBucket.teamData[4388].climb_counts}
|
||||
type="pie"
|
||||
width={380}
|
||||
/> */
|
||||
);
|
||||
};
|
||||
export default ComparativeBoxPlot;
|
||||
@@ -0,0 +1,64 @@
|
||||
import React from "react";
|
||||
import { ProcessedDataBucketContext, useProcessedDataBucket } from "../../ProcessedDataBucketContext";
|
||||
import Chart from "react-apexcharts";
|
||||
import { Box } from "@mui/material";
|
||||
import ComparativeBoxPlot from "./ComparativeBoxPlot";
|
||||
|
||||
const ComparisonPanel = (props) => {
|
||||
let { processedDataBucket, setProcessedDataBucket } = useProcessedDataBucket();
|
||||
if (processedDataBucket == null) return <div />;
|
||||
|
||||
//gets the given percentile of a sorted set
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
height: "400px",
|
||||
m: 1,
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
flexDirection: "row",
|
||||
justifyContent: "center",
|
||||
p: 1,
|
||||
gap: 2,
|
||||
}}
|
||||
>
|
||||
<ComparativeBoxPlot setName="total_match_points" title="Total Match Points" selectedTeams={props.selectedTeams} />
|
||||
<ComparativeBoxPlot setName="auto_points" title="Auto Points" selectedTeams={props.selectedTeams} />
|
||||
<ComparativeBoxPlot setName="teleop_hub_points" title="Teleop Hub Points" selectedTeams={props.selectedTeams} />
|
||||
<ComparativeBoxPlot setName="climb_points" title="Climb Points" selectedTeams={props.selectedTeams} />
|
||||
<ComparativeBoxPlot setName="upper_hub_auto" title="Upper Hub Auto" selectedTeams={props.selectedTeams} />
|
||||
<ComparativeBoxPlot setName="lower_hub_auto" title="Lower Hub Auto" selectedTeams={props.selectedTeams} />
|
||||
<ComparativeBoxPlot setName="upper_hub_teleop" title="Upper Hub Teleop" selectedTeams={props.selectedTeams} />
|
||||
<ComparativeBoxPlot setName="lower_hub_teleop" title="Lower Hub Teleop" selectedTeams={props.selectedTeams} />
|
||||
{/* <Box sx={{ width: "300px", height: "200px" }}>
|
||||
<Chart
|
||||
type="boxPlot"
|
||||
options={{
|
||||
chart: {
|
||||
type: "boxPlot",
|
||||
width: 350,
|
||||
},
|
||||
theme: {
|
||||
mode: "dark",
|
||||
},
|
||||
}}
|
||||
series={generateBoxPlotData(processedDataBucket, "upper_hub_auto", props.selectedTeams)}
|
||||
/>
|
||||
</Box> */}
|
||||
{/* <Chart
|
||||
options={{
|
||||
chart: {
|
||||
width: 384,
|
||||
type: "pie",
|
||||
},
|
||||
labels: ["None", "Low", "Mid", "High", "Transversal"],
|
||||
}}
|
||||
series={processedDataBucket.teamData[4388].climb_counts}
|
||||
type="pie"
|
||||
width={380}
|
||||
/> */}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default ComparisonPanel;
|
||||
@@ -1,9 +1,15 @@
|
||||
import React from "react";
|
||||
import React, { useState, useCallback, useRef } from "react";
|
||||
import { useLocalDb } from "../../DbContext";
|
||||
import { ProcessedDataBucketContext, useProcessedDataBucket } from "../../ProcessedDataBucketContext";
|
||||
import Chart from "react-apexcharts";
|
||||
import { DataGrid } from "@mui/x-data-grid";
|
||||
import { Box } from "@mui/material";
|
||||
import AnalyticsPanel from "./AnalyticsPanel";
|
||||
|
||||
//https://ag-grid.com/react-data-grid/
|
||||
import { AgGridReact } from "ag-grid-react";
|
||||
|
||||
import "ag-grid-community/dist/styles/ag-grid.css";
|
||||
import "ag-grid-community/dist/styles/ag-theme-alpine-dark.css";
|
||||
|
||||
const DashboardPage = () => {
|
||||
// <ProcessedDataBucketContext.Consumer>
|
||||
@@ -26,72 +32,90 @@ const DashboardPage = () => {
|
||||
// };
|
||||
// };
|
||||
let { processedDataBucket, setProcessedDataBucket } = useProcessedDataBucket();
|
||||
console.log(processedDataBucket);
|
||||
if (processedDataBucket == null) {
|
||||
return <div />;
|
||||
|
||||
let rowData = [];
|
||||
if (processedDataBucket != null) {
|
||||
//turns the values of the key value pairs in the list into an array
|
||||
let team_data_array = Object.values(processedDataBucket.teamData);
|
||||
// let team_data_array = Array.from(processedDataBucket.teamData);
|
||||
const roundPlaces = (n, d) => Math.round(n * Math.pow(10, d)) / Math.pow(10, d);
|
||||
// team_data_array.forEach((value, index, array) => {
|
||||
for (const property in processedDataBucket.teamData) {
|
||||
let value = processedDataBucket.teamData[property];
|
||||
rowData.push({
|
||||
id: value.team_number,
|
||||
average_auto_points: roundPlaces(value.average_auto_points, 2),
|
||||
average_teleop_hub_points: roundPlaces(value.average_teleop_hub_points, 2),
|
||||
average_climb_points: roundPlaces(value.average_climb_points, 2),
|
||||
average_total_match_points: roundPlaces(value.average_total_match_points, 2),
|
||||
matches_played: value.matches_played,
|
||||
num_disables: value.num_disables,
|
||||
num_flips: value.num_flips,
|
||||
fouls: value.fouls,
|
||||
fouls_tech: value.fouls_tech,
|
||||
red_cards: value.red_cards,
|
||||
yellow_cards: value.yellow_cards,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const [columnDefs] = useState([
|
||||
{ field: "id", headerName: "Team", width: 100, checkboxSelection: true, pinned: "left", sortable: true },
|
||||
{ field: "average_total_match_points", headerName: "Avg Total Pts", width: 120, sortable: true },
|
||||
{ field: "average_auto_points", headerName: "Avg Auto Pts", width: 120, sortable: true },
|
||||
{ field: "average_teleop_hub_points", headerName: "Avg Teleop Hub Pts", width: 160, sortable: true },
|
||||
{ field: "average_climb_points", headerName: "Avg Climb Pts", width: 120, sortable: true },
|
||||
{ field: "yellow_cards", headerName: "Yellow Cards", width: 120, sortable: true },
|
||||
{ field: "red_cards", headerName: "Red Cards", width: 100, sortable: true },
|
||||
{ field: "fouls", headerName: "Fouls", width: 70, sortable: true },
|
||||
{ field: "fouls_tech", headerName: "Tech Fouls", width: 100, sortable: true },
|
||||
{ field: "num_disables", headerName: "Disables", width: 100, sortable: true },
|
||||
{ field: "num_flips", headerName: "Flips", width: 80, sortable: true },
|
||||
{ field: "matches_played", headerName: "Matches", width: 100, sortable: true },
|
||||
{ field: "", headerName: "", width: 150, sortable: true },
|
||||
]);
|
||||
|
||||
const [selectedTeams, setSelectedTeams] = useState([]);
|
||||
|
||||
const gridRef = useRef();
|
||||
|
||||
const onSelectionChanged = useCallback(() => {
|
||||
let selectedRows = gridRef.current.api.getSelectedRows();
|
||||
// var selectedRowsString = "";
|
||||
// var maxToShow = 5;
|
||||
let selectedTeams = [];
|
||||
selectedRows.forEach(function (selectedRow, index) {
|
||||
selectedTeams.push(selectedRow.id);
|
||||
});
|
||||
// if (selectedRows.length > maxToShow) {
|
||||
// var othersCount = selectedRows.length - maxToShow;
|
||||
// selectedRowsString += " and " + othersCount + " other" + (othersCount !== 1 ? "s" : "");
|
||||
// }
|
||||
// document.querySelector("#selectedRows").innerHTML = selectedRowsString;
|
||||
setSelectedTeams(selectedTeams);
|
||||
}, [selectedTeams]);
|
||||
|
||||
// const { processedDataBucket, setProcessedDataBucket } = pdbCtx;
|
||||
// console.log(pdbCtx);
|
||||
|
||||
//format data for the data grid
|
||||
let grid_data = [];
|
||||
//turns the values of the key value pairs in the list into an array
|
||||
console.log(processedDataBucket.teamData);
|
||||
let team_data_array = Object.values(processedDataBucket.teamData);
|
||||
// let team_data_array = Array.from(processedDataBucket.teamData);
|
||||
const roundPlaces = (n, d) => Math.round(n * Math.pow(10, d)) / Math.pow(10, d);
|
||||
// team_data_array.forEach((value, index, array) => {
|
||||
for (const property in processedDataBucket.teamData) {
|
||||
console.log(property);
|
||||
let value = processedDataBucket.teamData[property];
|
||||
console.log(value);
|
||||
grid_data.push({
|
||||
id: value.team_number,
|
||||
average_auto_points: roundPlaces(value.average_auto_points, 2),
|
||||
average_teleop_hub_points: roundPlaces(value.average_teleop_hub_points, 2),
|
||||
average_climb_points: roundPlaces(value.average_climb_points, 2),
|
||||
average_total_match_points: roundPlaces(value.average_total_match_points, 2),
|
||||
});
|
||||
}
|
||||
// });
|
||||
console.log(grid_data);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* <Pie data={makePieChartData(pdb, 4388)} /> */}
|
||||
<Box
|
||||
sx={{
|
||||
height: "600px",
|
||||
height: "400px",
|
||||
m: 2,
|
||||
}}
|
||||
>
|
||||
<DataGrid
|
||||
rows={grid_data}
|
||||
columns={[
|
||||
{ field: "id", headerName: "Team", width: 100 },
|
||||
{ field: "average_total_match_points", headerName: "Avg Total Pts", width: 150 },
|
||||
{ field: "average_auto_points", headerName: "Avg Auto Pts", width: 150 },
|
||||
{ field: "average_teleop_hub_points", headerName: "Avg Teleop Hub Pts", width: 190 },
|
||||
{ field: "average_climb_points", headerName: "Avg Climb Pts", width: 150 },
|
||||
// { field: "matched_played", headerName: "Matches", width: 100 },
|
||||
]}
|
||||
checkboxSelection
|
||||
pageSize={15}
|
||||
rowsPerPageOptions={[15]}
|
||||
/>
|
||||
{/* <h2>{JSON.stringify(selectedTeams)}</h2> */}
|
||||
<div className="ag-theme-alpine-dark" style={{ height: 400, width: "100%" }}>
|
||||
<AgGridReact ref={gridRef} rowData={rowData} columnDefs={columnDefs} rowSelection={"multiple"} rowMultiSelectWithClick={true} onSelectionChanged={onSelectionChanged}></AgGridReact>
|
||||
</div>
|
||||
</Box>
|
||||
{/* <Chart
|
||||
options={{
|
||||
chart: {
|
||||
width: 384,
|
||||
type: "pie",
|
||||
},
|
||||
labels: ["None", "Low", "Mid", "High", "Transversal"],
|
||||
}}
|
||||
series={pdb.teamData[4388].climb_counts}
|
||||
type="pie"
|
||||
width={380}
|
||||
/> */}
|
||||
<AnalyticsPanel selectedTeams={selectedTeams} />
|
||||
</div>
|
||||
);
|
||||
//}}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import React from "react";
|
||||
import { useLocalDb } from "../DbContext";
|
||||
import React, { useCallback } from "react";
|
||||
import { useLocalDb, useRemoteDb } from "../DbContext";
|
||||
import "./InputPage.css";
|
||||
import { Formik, FastField, Form } from "formik";
|
||||
import InputNumberField from "../components/InputNumberField.jsx";
|
||||
import { TextField, Button, Grid, FormRow, Divider, Checkbox, Radio, FormControlLabel, FormControl, FormLabel, RadioGroup, IconButton, InputAdornment, Box } from "@mui/material";
|
||||
import { useProcessedDataBucket } from "../ProcessedDataBucketContext";
|
||||
import { getProcessedDataBucket, updateProcessedDataBucket } from "../ProcessedDataBucket";
|
||||
|
||||
const InputPage = () => {
|
||||
const localdb = useLocalDb();
|
||||
let { localdb, setLocaldb } = useLocalDb();
|
||||
let { remotedb, setRemotedb } = useRemoteDb();
|
||||
const { processedDataBucket, setProcessedDataBucket } = useProcessedDataBucket();
|
||||
|
||||
let panel_sx = {
|
||||
display: "flex",
|
||||
flexDirection: { xs: "column", sm: "row" },
|
||||
@@ -20,6 +25,36 @@ const InputPage = () => {
|
||||
borderRadius: "10px",
|
||||
boxShadow: 7,
|
||||
};
|
||||
|
||||
const onSubmit = useCallback(
|
||||
(values, { setSubmitting, resetForm }) => {
|
||||
// setTimeout(() => {
|
||||
localdb
|
||||
.put({
|
||||
// _id: new Date().toISOString(),
|
||||
_id: "match_" + values.match_number + "_team_" + values.team_number,
|
||||
...values,
|
||||
})
|
||||
.then((result) => {
|
||||
alert("Input Saved Successfully!");
|
||||
console.log(result);
|
||||
console.log(localdb);
|
||||
localdb.replicate.to(remotedb, {
|
||||
live: true,
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Failed To Save Input!");
|
||||
alert(err);
|
||||
});
|
||||
// alert(JSON.stringify(values, null, 2));
|
||||
// resetForm(); //Hah tobad
|
||||
setSubmitting(false);
|
||||
// }, 400);
|
||||
updateProcessedDataBucket(localdb, setProcessedDataBucket);
|
||||
},
|
||||
[localdb, remotedb, setProcessedDataBucket, updateProcessedDataBucket]
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<br />
|
||||
@@ -47,27 +82,7 @@ const InputPage = () => {
|
||||
disabled: false,
|
||||
}}
|
||||
validateOnChange="false"
|
||||
onSubmit={(values, { setSubmitting, resetForm }) => {
|
||||
setTimeout(() => {
|
||||
localdb
|
||||
.put({
|
||||
_id: new Date().toISOString(),
|
||||
...values,
|
||||
})
|
||||
.then((result) => {
|
||||
alert("Input Saved Successfully!");
|
||||
console.log(result);
|
||||
console.log(localdb);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Failed To Save Input!");
|
||||
alert(err);
|
||||
});
|
||||
// alert(JSON.stringify(values, null, 2));
|
||||
// resetForm(); //Hah tobad
|
||||
setSubmitting(false);
|
||||
}, 400);
|
||||
}}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
{({ values, setValues, errors, touched, handleChange, handleBlur, handleSubmit, isSubmitting }) => (
|
||||
<Form>
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
import React from "react";
|
||||
import "./WelcomePage.css";
|
||||
import "../App.css";
|
||||
import DbChooser from "../components/DbChooser";
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
const WelcomePage = () => {
|
||||
return (
|
||||
<div className="welcome">
|
||||
<h1>Welcome to Ridgebotics Scouting Web Application 2022</h1>
|
||||
{/* <img src="/WelcomePageImage.webp" /> */}
|
||||
<img src="/picgoeshard.jpg" />
|
||||
<Box sx={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
|
||||
<h1>Welcome to Ridgebotics Scouting Web Application 2022</h1>
|
||||
{/* <img src="/WelcomePageImage.webp" /> */}
|
||||
{/* <img src="/picgoeshard.jpg" /> */}
|
||||
<DbChooser />
|
||||
</Box>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,16 +8,14 @@ export function updateProcessedDataBucket(db, setProcessedDataBucket) {
|
||||
let teamData = {};
|
||||
let matchData = {};
|
||||
|
||||
// console.log(result);
|
||||
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 teamData[doc.team_number] === "undefined") {
|
||||
teamData[doc.team_number] = {
|
||||
team_number: doc.team_number,
|
||||
matched_played: 0,
|
||||
matches_played: 0,
|
||||
data_sets: {
|
||||
upper_hub_auto: [],
|
||||
lower_hub_auto: [],
|
||||
@@ -44,7 +42,7 @@ export function updateProcessedDataBucket(db, setProcessedDataBucket) {
|
||||
|
||||
//add this game's data to the respective team data:
|
||||
let thisTeamData = teamData[doc.team_number];
|
||||
thisTeamData.matched_played++;
|
||||
thisTeamData.matches_played++;
|
||||
|
||||
let auto_points = (parseInt(doc.taxi_auto) ? 2 : 0) + parseInt(doc.upper_hub_auto) * 4 + parseInt(doc.lower_hub_auto) * 2;
|
||||
let teleop_hub_points = parseInt(doc.upper_hub_teleop) * 2 + parseInt(doc.lower_hub_teleop) * 1;
|
||||
@@ -74,10 +72,10 @@ export function updateProcessedDataBucket(db, setProcessedDataBucket) {
|
||||
//sum of all points in the match points data set for this team
|
||||
//function for getting the sum of an array, use in reduce function of array
|
||||
const sum = (accum, current) => accum + current;
|
||||
thisTeamData.average_auto_points = thisTeamData.data_sets.auto_points.reduce(sum, 0) / thisTeamData.matched_played;
|
||||
thisTeamData.average_teleop_hub_points = thisTeamData.data_sets.teleop_hub_points.reduce(sum, 0) / thisTeamData.matched_played;
|
||||
thisTeamData.average_climb_points = thisTeamData.data_sets.climb_points.reduce(sum, 0) / thisTeamData.matched_played;
|
||||
thisTeamData.average_total_match_points = thisTeamData.data_sets.total_match_points.reduce(sum, 0) / thisTeamData.matched_played;
|
||||
thisTeamData.average_auto_points = thisTeamData.data_sets.auto_points.reduce(sum, 0) / thisTeamData.matches_played;
|
||||
thisTeamData.average_teleop_hub_points = thisTeamData.data_sets.teleop_hub_points.reduce(sum, 0) / thisTeamData.matches_played;
|
||||
thisTeamData.average_climb_points = thisTeamData.data_sets.climb_points.reduce(sum, 0) / thisTeamData.matches_played;
|
||||
thisTeamData.average_total_match_points = thisTeamData.data_sets.total_match_points.reduce(sum, 0) / thisTeamData.matches_played;
|
||||
});
|
||||
setProcessedDataBucket({ teamData: teamData, matchData: matchData });
|
||||
})
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import React, { useCallback } from "react";
|
||||
import { Box, InputLabel, MenuItem, FormControl, Select } from "@mui/material";
|
||||
import { setDatabaseName, useLocalDb, useRemoteDb } from "../DbContext";
|
||||
import { useProcessedDataBucket } from "../ProcessedDataBucketContext";
|
||||
|
||||
const DbChooser = (props) => {
|
||||
const { localdb, setLocaldb } = useLocalDb();
|
||||
const { remotedb, setRemotedb } = useRemoteDb();
|
||||
const { processedDataBucket, setProcessedDataBucket } = useProcessedDataBucket();
|
||||
|
||||
const [dbname, setDbName] = React.useState(localdb.name);
|
||||
|
||||
const handleChange = useCallback((event) => {
|
||||
console.log(event.target.value);
|
||||
// setAge(event.target.value);
|
||||
setDbName(event.target.value);
|
||||
setDatabaseName(event.target.value, setLocaldb, setRemotedb, setProcessedDataBucket);
|
||||
});
|
||||
return (
|
||||
<div>
|
||||
<Box sx={{ width: 400 }}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Database</InputLabel>
|
||||
<Select value={dbname} label="Database Name" onChange={handleChange}>
|
||||
<MenuItem value={"denver_practice"}>Denver Practice Matches</MenuItem>
|
||||
<MenuItem value={"denver_fr"}>Denver For Real</MenuItem>
|
||||
{/* <MenuItem value={"utah_practice"}>Utah Practice Matches</MenuItem>
|
||||
<MenuItem value={"utah_fr"}>Utah For Real</MenuItem> */}
|
||||
<MenuItem value={"testdata"}>Test Data</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Box>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DbChooser;
|
||||
@@ -4,5 +4,5 @@
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
.toolbar_logo a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 2rem;
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.toolbar_spacer {
|
||||
|
||||
@@ -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 <3</Link></div>
|
||||
<div className = "toolbar_logo"><Link to="/">Ridgebotics Scouting 💙</Link></div>
|
||||
<div className = "toolbar_spacer" />
|
||||
<div className = "toolbar_items">
|
||||
<PagesList />
|
||||
|
||||
Reference in New Issue
Block a user