Add basic scouting web page
This patch adds a basic web page. Ishan did the vast majority of the
work here. Future patches will integrate it with the rest of the
scouting web server.
Change-Id: I467bd16caade9c987022600c2b63e9fad20da1a3
Signed-off-by: Philipp Schrader <philipp.schrader@gmail.com>
Signed-off-by: Ishan Katpally <100026402@mvla.net>
Signed-off-by: Alex Perry <alex.perry96@gmail.com>
diff --git a/scouting/scouting_test.ts b/scouting/scouting_test.ts
index bb1c075..9ee9122 100644
--- a/scouting/scouting_test.ts
+++ b/scouting/scouting_test.ts
@@ -14,7 +14,7 @@
}
async getParagraphText() {
- return (await this.waitForElement(element(by.css('h1')))).getText();
+ return (await this.waitForElement(element(by.css('.header')))).getText();
}
}
@@ -27,6 +27,6 @@
it('should display: This is an app.', async () => {
await page.navigateTo();
- expect(await page.getParagraphText()).toEqual('This is an app.');
+ expect(await page.getParagraphText()).toEqual('Auto');
});
});
diff --git a/scouting/www/BUILD b/scouting/www/BUILD
index aa2ad7b..39246d8 100644
--- a/scouting/www/BUILD
+++ b/scouting/www/BUILD
@@ -14,12 +14,14 @@
]),
angular_assets = glob([
"*.ng.html",
+ "*.css",
]),
compiler = "//tools:tsc_wrapped_with_angular",
target_compatible_with = ["@platforms//cpu:x86_64"],
use_angular_plugin = True,
visibility = ["//visibility:public"],
deps = [
+ "//scouting/www/entry",
"@npm//@angular/animations",
"@npm//@angular/common",
"@npm//@angular/core",
diff --git a/scouting/www/app.ng.html b/scouting/www/app.ng.html
index fb9ba26..d7c1b22 100644
--- a/scouting/www/app.ng.html
+++ b/scouting/www/app.ng.html
@@ -1,3 +1,5 @@
-<h1>
- This is an app.
-</h1>
+<!--Progress Bar-->
+<!--<div class="row">
+ <h1 class="text-end">Match {{matchNumber}}, Team {{teamNumber}}</h1>
+</div>-->
+<app-entry></app-entry>
\ No newline at end of file
diff --git a/scouting/www/app.ts b/scouting/www/app.ts
index f6247d3..c9d5ca1 100644
--- a/scouting/www/app.ts
+++ b/scouting/www/app.ts
@@ -5,4 +5,6 @@
templateUrl: './app.ng.html',
})
export class App {
+ matchNumber: number = 1; //placeholder
+ teamNumber: number = 971; //placeholder
}
diff --git a/scouting/www/app_module.ts b/scouting/www/app_module.ts
index 3e34a17..6a6fff0 100644
--- a/scouting/www/app_module.ts
+++ b/scouting/www/app_module.ts
@@ -1,6 +1,7 @@
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
+import {EntryModule} from './entry/entry.module';
import {App} from './app';
@@ -9,6 +10,7 @@
imports: [
BrowserModule,
BrowserAnimationsModule,
+ EntryModule,
],
exports: [App],
bootstrap: [App],
diff --git a/scouting/www/entry/BUILD b/scouting/www/entry/BUILD
new file mode 100644
index 0000000..8f46de7
--- /dev/null
+++ b/scouting/www/entry/BUILD
@@ -0,0 +1,20 @@
+load("@npm//@bazel/typescript:index.bzl", "ts_library")
+
+ts_library(
+ name = "entry",
+ srcs = glob([
+ "*.ts",
+ ]),
+ angular_assets = glob([
+ "*.ng.html",
+ "*.css",
+ ]),
+ compiler = "//tools:tsc_wrapped_with_angular",
+ target_compatible_with = ["@platforms//cpu:x86_64"],
+ use_angular_plugin = True,
+ visibility = ["//visibility:public"],
+ deps = [
+ "@npm//@angular/common",
+ "@npm//@angular/core",
+ ],
+)
diff --git a/scouting/www/entry/entry.component.css b/scouting/www/entry/entry.component.css
new file mode 100644
index 0000000..520b6d2
--- /dev/null
+++ b/scouting/www/entry/entry.component.css
@@ -0,0 +1,8 @@
+* {
+ margin: 10px;
+}
+
+textarea {
+ width: 300px;
+ height: 150px;
+}
\ No newline at end of file
diff --git a/scouting/www/entry/entry.component.ts b/scouting/www/entry/entry.component.ts
new file mode 100644
index 0000000..21bdac4
--- /dev/null
+++ b/scouting/www/entry/entry.component.ts
@@ -0,0 +1,98 @@
+import { Component, OnInit } from '@angular/core';
+
+type Section = 'Auto'|'TeleOp'|'Climb'|'Defense'|'Review and Submit'|'Home'
+type Level = 'Low'|'Medium'|'High'|'Transversal'
+
+@Component({
+ selector: 'app-entry',
+ templateUrl: './entry.ng.html',
+ styleUrls: ['./entry.component.css']
+})
+export class EntryComponent {
+ section: Section = 'Auto'; //placeholder
+ autoUpperShotsMade: number = 0;
+ autoLowerShotsMade: number = 0;
+ autoShotsMissed: number = 0;
+ teleUpperShotsMade: number = 0;
+ teleLowerShotsMade: number = 0;
+ teleShotsMissed: number = 0;
+ defensePlayedOnScore: number = 50;
+ defensePlayedScore: number = 50;
+ level: Level;
+ proper: boolean = false;
+ climbed: boolean = false;
+
+ toggleProper() {
+ this.proper = !this.proper;
+ }
+
+ setLow() {
+ this.level = 'Low';
+ }
+
+ setMedium() {
+ this.level = 'Medium';
+ }
+
+ setHigh() {
+ this.level = 'High';
+ }
+
+ setTransversal() {
+ this.level = 'Transversal';
+ }
+
+ defensePlayedOnSlider(event) {
+ this.defensePlayedOnScore = event.target.value;
+ }
+
+ defensePlayedSlider(event) {
+ this.defensePlayedScore = event.target.value;
+ }
+
+ setClimbedTrue() {
+ this.climbed = true;
+ }
+
+ setClimbedFalse() {
+ this.climbed = false;
+ }
+
+ nextSection() {
+ if (this.section === 'Auto') {
+ this.section = 'TeleOp';
+ } else if (this.section === 'TeleOp') {
+ this.section = 'Climb';
+ } else if (this.section === 'Climb') {
+ this.section = 'Defense';
+ } else if (this.section === 'Defense') {
+ this.section = 'Review and Submit';
+ } else if (this.section === 'Review and Submit') {
+ this.section = 'Home';
+ }
+ }
+
+ adjustAutoUpper(by: number) {
+ this.autoUpperShotsMade = Math.max(0, this.autoUpperShotsMade + by);
+ }
+
+ adjustAutoLower(by: number) {
+ this.autoLowerShotsMade = Math.max(0, this.autoLowerShotsMade + by);
+ }
+
+ adjustAutoMissed(by: number) {
+ this.autoShotsMissed = Math.max(0, this.autoShotsMissed + by);
+ }
+
+ adjustTeleUpper(by: number) {
+ this.teleUpperShotsMade = Math.max(0, this.teleUpperShotsMade + by);
+ }
+
+ adjustTeleLower(by: number) {
+ this.teleLowerShotsMade = Math.max(0, this.teleLowerShotsMade + by);
+ }
+
+ adjustTeleMissed(by: number) {
+ this.teleShotsMissed = Math.max(0, this.teleShotsMissed + by);
+ }
+}
diff --git a/scouting/www/entry/entry.module.ts b/scouting/www/entry/entry.module.ts
new file mode 100644
index 0000000..d454c2e
--- /dev/null
+++ b/scouting/www/entry/entry.module.ts
@@ -0,0 +1,11 @@
+import {NgModule} from '@angular/core';
+import {CommonModule} from '@angular/common';
+import {EntryComponent} from './entry.component';
+
+@NgModule({
+ declarations: [EntryComponent],
+ exports: [EntryComponent],
+ imports: [CommonModule],
+})
+export class EntryModule {
+}
diff --git a/scouting/www/entry/entry.ng.html b/scouting/www/entry/entry.ng.html
new file mode 100644
index 0000000..c20edf9
--- /dev/null
+++ b/scouting/www/entry/entry.ng.html
@@ -0,0 +1,185 @@
+<div class="header">
+ <h2>{{section}}</h2>
+</div>
+
+<ng-container [ngSwitch]="section">
+ <div *ngSwitchCase="'Auto'" id="auto" class="container-fluid">
+ <div class="row">
+ <!--Image here-->
+ <h4>Image</h4>
+ <form>
+ <!--Choice for each ball location-->
+ <input type="radio" name="balls" value="1" id="ball-1"><label for="ball-1">Ball 1</label>
+ <input type="radio" name="balls" value="2" id="ball-2"><label for="ball-2">Ball 2</label><br>
+ <input type="radio" name="balls" value="3" id="ball-3"><label for="ball-3">Ball 3</label>
+ <input type="radio" name="balls" value="4" id="ball-4"><label for="ball-4">Ball 4</label>
+ </form>
+ </div>
+ <div class="row">
+ <!--Image here-->
+ <h4>Image</h4>
+ <form>
+ <input type="radio" name="quadrant" id="first" value="Quadrant 1">
+ <label for="first">Quadrant 1</label>
+ <input type="radio" name="quadrant" id="second" value="Quadrant 2">
+ <label for="second">Quadrant 2</label><br>
+ <input type="radio" name="quadrant" id="third" value="Quadrant 3">
+ <label for="third">Quadrant 3</label>
+ <input type="radio" name="quadrant" id="fourth" value="Quadrant 4">
+ <label for="fourth">Quadrant 4</label>
+ </form>
+ </div>
+ <div class="row justify-content-center">
+ <div class="col-sm">
+ <h4>Upper Shots Made</h4>
+ <button (click)="adjustAutoUpper(1)" class="btn btn-secondary">+</button>
+ <h3>{{autoUpperShotsMade}}</h3>
+ <button (click)="adjustAutoUpper(-1)" class="btn btn-secondary">-</button>
+ </div>
+
+ <div class="col-sm">
+ <h4>Lower Shots Made</h4>
+ <button (click)="adjustAutoLower(1)" class="col-xs btn btn-secondary">+</button>
+ <h3>{{autoLowerShotsMade}}</h3>
+ <button (click)="adjustAutoLower(-1)" class="btn btn-secondary">-</button>
+ </div>
+
+ <div class="col-sm">
+ <h4>Missed Shots</h4>
+ <button (click)="adjustAutoMissed(1)" class="btn btn-secondary">+</button>
+ <h3>{{autoShotsMissed}}</h3>
+ <button (click)="adjustAutoMissed(-1)" class="btn btn-secondary">-</button>
+ </div>
+ </div>
+ <div class="text-right">
+ <button class="btn btn-primary" (click)="nextSection()">Next</button>
+ </div>
+ </div>
+
+ <div *ngSwitchCase="'TeleOp'" id="teleop" class="container-fluid">
+ <div class="row justify-content-center">
+ <div class="col-sm">
+ <h4>Upper Shots Made</h4>
+ <button (click)="adjustTeleUpper(1)" class="btn btn-secondary">+</button>
+ <h3>{{teleUpperShotsMade}}</h3>
+ <button (click)="adjustTeleUpper(-1)" class="btn btn-secondary">-</button>
+ </div>
+
+ <div class="col-sm">
+ <h4>Lower Shots Made</h4>
+ <button (click)="adjustTeleLower(1)" class="btn btn-secondary">+</button>
+ <h3>{{teleLowerShotsMade}}</h3>
+ <button (click)="adjustTeleLower(-1)" class="btn btn-secondary">-</button>
+ </div>
+
+ <div class="col-sm">
+ <h4>Missed Shots</h4>
+ <button (click)="adjustTeleMissed(1)" class="btn btn-secondary">+</button>
+ <h3>{{teleShotsMissed}}</h3>
+ <button (click)="adjustTeleMissed(-1)" class="btn btn-secondary">-</button>
+ </div>
+ </div>
+ <div class="text-right">
+ <button class="btn btn-primary" (click)="nextSection()">Next</button>
+ </div>
+ </div>
+
+ <div *ngSwitchCase="'Climb'" id="climb" class="container-fluid">
+ <div class="row">
+ <form>
+ <input (click)="setClimbedFalse()" type="radio" name="climbing" id="continue"><label for="continue">Kept Shooting</label><br>
+ <input (click)="setClimbedTrue()" type="radio" name="climbing" id="climbed"><label for="climbed">Attempted to Climb</label><br>
+ </form>
+ </div>
+ <div *ngIf="climbed">
+ <h4>Bar Made</h4>
+ <form>
+ <input (click)="setLow()" type="radio" name="level" id="low"><label for="low">Low</label><br>
+ <input (click)="setMedium()" type="radio" name="level" id="medium"><label for="medium">Medium</label><br>
+ <input (click)="setHigh()" type="radio" name="level" id="high"><label for="high">High</label><br>
+ <input (click)="setTransversal()" type="radio" name="level" id="transversal"><label for="transversal">Transversal</label><br>
+ <input (click)="toggleProper()" type="checkbox" id="proper"><label for="proper">~10 seconds to attempt next level?</label>
+ </form>
+ </div>
+ <div class="row">
+ <h4>Comments</h4>
+ <textarea></textarea>
+ </div>
+ <button class="btn btn-primary" (click)="nextSection()">Next</button>
+ </div>
+
+ <div *ngSwitchCase="'Defense'" id="defense" class="container-fluid">
+ <h4 class="text-center">How much defense did other robots play on this robot?</h4>
+
+ <div class="row" style="min-height: 50px">
+ <div class="col">
+ <h6>None</h6>
+ </div>
+
+ <div class="col">
+ <input type="range" min="1" max="100" value="50" (input)="defensePlayedOnSlider($event)">
+ </div>
+
+ <div class="col">
+ <h6>A lot</h6>
+ </div>
+ </div>
+
+ <h6 class="text-center">{{defensePlayedOnScore}}</h6>
+
+ <h4 class="text-center">How much defense did this robot play?</h4>
+
+ <div class="row">
+
+ <div class="col">
+ <h6>None</h6>
+ </div>
+
+ <div class="col">
+ <input type="range" min="1" max="100" value="50" (input)="defensePlayedSlider($event)">
+ </div>
+
+ <div class="col">
+ <h6>A lot</h6>
+ </div>
+ </div>
+ <h6 class="text-center">{{defensePlayedScore}}</h6>
+
+ <button class="btn btn-primary" (click)="nextSection()">Next</button>
+ </div>
+
+ <div *ngSwitchCase="'Review and Submit'" id="review" class="container-fluid">
+ <h4>Auto</h4>
+ <ul>
+ <li>Upper Shots Made: {{autoUpperShotsMade}}</li>
+ <li>Lower Shots Made: {{autoLowerShotsMade}}</li>
+ <li>Missed Shots: {{autoShotsMissed}}</li>
+ </ul>
+
+ <h4>TeleOp</h4>
+ <ul>
+ <li>Upper Shots Made: {{teleUpperShotsMade}}</li>
+ <li>Lower Shots Made: {{teleLowerShotsMade}}</li>
+ <li>Missed Shots {{teleShotsMissed}}</li>
+ </ul>
+
+ <h4>Climb</h4>
+ <ul>
+ <div *ngIf="climbed">
+ <li *ngIf="climbed">Attempted to Climb?: Yes</li>
+ <li>Level: {{level}}</li>
+ <li *ngIf="proper">Proper Attempt: Yes</li>
+ <li *ngIf="!proper">Proper Attempt: No</li>
+ </div>
+ <li *ngIf="!climbed">Attempted to Climb: No</li>
+ </ul>
+
+ <h4>Defense</h4>
+ <ul>
+ <li>Defense Played On Rating: {{defensePlayedOnScore}}</li>
+ <li>Defense Played Raing: {{defensePlayedScore}}</li>
+ </ul>
+
+ <button class="btn btn-primary" (click)="nextSection()">Submit</button>
+ </div>
+</ng-container>
diff --git a/scouting/www/index.html b/scouting/www/index.html
index cbe8770..3a09dfd 100644
--- a/scouting/www/index.html
+++ b/scouting/www/index.html
@@ -1,7 +1,10 @@
+<!DOCTYPE html>
<html>
<head>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
<base href="/">
<script src="./npm/node_modules/zone.js/dist/zone.min.js"></script>
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body>
<my-app></my-app>