blob: f503e2d76ad138226a08bc438b8179ede487e654 [file] [log] [blame]
Filip Kujawa7dd49952022-12-02 12:09:13 -08001import {Component, HostListener} from '@angular/core';
Alex Perrybb901052022-03-23 19:46:15 -07002import {Builder, ByteBuffer} from 'flatbuffers';
3import {ErrorResponse} from 'org_frc971/scouting/webserver/requests/messages/error_response_generated';
4import {RequestNotesForTeam} from 'org_frc971/scouting/webserver/requests/messages/request_notes_for_team_generated';
Philipp Schrader817cce32022-03-26 15:00:00 -07005import {
6 Note as NoteFb,
7 RequestNotesForTeamResponse,
8} from 'org_frc971/scouting/webserver/requests/messages/request_notes_for_team_response_generated';
Alex Perrybb901052022-03-23 19:46:15 -07009import {SubmitNotes} from 'org_frc971/scouting/webserver/requests/messages/submit_notes_generated';
10import {SubmitNotesResponse} from 'org_frc971/scouting/webserver/requests/messages/submit_notes_response_generated';
11
Filip Kujawaf947cb42022-11-21 10:00:30 -080012/*
13For new games, the keywords being used will likely need to be updated.
14To update the keywords complete the following:
15 1) Update the Keywords Interface and KEYWORD_CHECKBOX_LABELS in notes.component.ts
16 The keys of Keywords and KEYWORD_CHECKBOX_LABELS should match.
17 2) In notes.component.ts, update the setTeamNumber() method with the new keywords.
18 3) Add/Edit the new keywords in /scouting/webserver/requests/messages/submit_notes.fbs.
19 4) In notes.component.ts, update the submitData() method with the newKeywords
20 so that it matches the updated flatbuffer
21 5) In db.go, update the NotesData struct and the
22 AddNotes method with the new keywords
23 6) In db_test.go update the TestNotes method so the test uses the keywords
24 7) Update the submitNoteScoutingHandler in requests.go with the new keywords
25 8) Finally, update the corresponding test in requests_test.go (TestSubmitNotes)
26
27 Note: If you change the number of keywords you might need to
28 update how they are displayed in notes.ng.html
29*/
30
31// TeamSelection: Display form to add a team to the teams being scouted.
32// Data: Display the note textbox and keyword selection form
33// for all the teams being scouted.
Philipp Schrader817cce32022-03-26 15:00:00 -070034type Section = 'TeamSelection' | 'Data';
Alex Perrybb901052022-03-23 19:46:15 -070035
Filip Kujawaf947cb42022-11-21 10:00:30 -080036// Every keyword checkbox corresponds to a boolean.
37// If the boolean is True, the checkbox is selected
38// and the note scout saw that the robot being scouted
39// displayed said property (ex. Driving really well -> goodDriving)
40interface Keywords {
41 goodDriving: boolean;
42 badDriving: boolean;
43 sketchyClimb: boolean;
44 solidClimb: boolean;
45 goodDefense: boolean;
46 badDefense: boolean;
Alex Perrybb901052022-03-23 19:46:15 -070047}
48
Filip Kujawaf947cb42022-11-21 10:00:30 -080049interface Input {
50 teamNumber: number;
51 notesData: string;
52 keywordsData: Keywords;
53}
54
55const KEYWORD_CHECKBOX_LABELS = {
56 goodDriving: 'Good Driving',
57 badDriving: 'Bad Driving',
58 solidClimb: 'Solid Climb',
59 sketchyClimb: 'Sketchy Climb',
60 goodDefense: 'Good Defense',
61 badDefense: 'Bad Defense',
62} as const;
63
Alex Perrybb901052022-03-23 19:46:15 -070064@Component({
65 selector: 'frc971-notes',
66 templateUrl: './notes.ng.html',
Philipp Schrader817cce32022-03-26 15:00:00 -070067 styleUrls: ['../common.css', './notes.component.css'],
Alex Perrybb901052022-03-23 19:46:15 -070068})
69export class Notes {
Filip Kujawaf947cb42022-11-21 10:00:30 -080070 // Re-export KEYWORD_CHECKBOX_LABELS so that we can
71 // use it in the checkbox properties.
72 readonly KEYWORD_CHECKBOX_LABELS = KEYWORD_CHECKBOX_LABELS;
73
74 // Necessary in order to iterate the keys of KEYWORD_CHECKBOX_LABELS.
75 Object = Object;
76
Alex Perrybb901052022-03-23 19:46:15 -070077 section: Section = 'TeamSelection';
Alex Perrybb901052022-03-23 19:46:15 -070078
79 errorMessage = '';
Filip Kujawaf947cb42022-11-21 10:00:30 -080080 teamNumberSelection: number = 971;
Alex Perrybb901052022-03-23 19:46:15 -070081
Filip Kujawaf947cb42022-11-21 10:00:30 -080082 // Data inputted by user is stored in this array.
83 // Includes the team number, notes, and keyword selection.
84 newData: Input[] = [];
Alex Perrybb901052022-03-23 19:46:15 -070085
Filip Kujawa7dd49952022-12-02 12:09:13 -080086 // Keyboard shortcuts to switch between text areas.
87 // Listens for Ctrl + number and focuses on the
88 // corresponding textbox.
89 // More Info: https://angular.io/api/core/HostListener
90
91 @HostListener('window:keyup', ['$event'])
92 onEvent(event: KeyboardEvent) {
93 if (event.ctrlKey) {
94 if (event.code.includes('Digit')) {
95 this.handleFocus(event.key);
96 }
97 }
98 }
99
100 handleFocus(digit: string) {
101 let textArea = <HTMLInputElement>(
102 document.getElementById('text-input-' + digit)
103 );
104 if (textArea != null) {
105 textArea.focus();
106 }
107 }
108
Filip Kujawaf947cb42022-11-21 10:00:30 -0800109 setTeamNumber() {
110 let data: Input = {
111 teamNumber: this.teamNumberSelection,
Filip Kujawaba55bb32022-12-02 14:08:32 -0800112 notesData: 'Auto: \nTeleop: \nEngame: ',
Filip Kujawaf947cb42022-11-21 10:00:30 -0800113 keywordsData: {
114 goodDriving: false,
115 badDriving: false,
116 solidClimb: false,
117 sketchyClimb: false,
118 goodDefense: false,
119 badDefense: false,
120 },
121 };
Alex Perrybb901052022-03-23 19:46:15 -0700122
Filip Kujawaf947cb42022-11-21 10:00:30 -0800123 this.newData.push(data);
124 this.section = 'Data';
125 }
Alex Perrybb901052022-03-23 19:46:15 -0700126
Filip Kujawaf947cb42022-11-21 10:00:30 -0800127 removeTeam(index: number) {
128 this.newData.splice(index, 1);
129 if (this.newData.length == 0) {
130 this.section = 'TeamSelection';
Alex Perrybb901052022-03-23 19:46:15 -0700131 } else {
Filip Kujawaf947cb42022-11-21 10:00:30 -0800132 this.section = 'Data';
Alex Perrybb901052022-03-23 19:46:15 -0700133 }
134 }
135
Filip Kujawaf947cb42022-11-21 10:00:30 -0800136 addTeam() {
Philipp Schrader817cce32022-03-26 15:00:00 -0700137 this.section = 'TeamSelection';
Alex Perrybb901052022-03-23 19:46:15 -0700138 }
Philipp Schrader817cce32022-03-26 15:00:00 -0700139
Alex Perrybb901052022-03-23 19:46:15 -0700140 async submitData() {
Filip Kujawaf947cb42022-11-21 10:00:30 -0800141 for (let i = 0; i < this.newData.length; i++) {
142 const builder = new Builder();
143 const dataFb = builder.createString(this.newData[i].notesData);
Filip Kujawaba55bb32022-12-02 14:08:32 -0800144
Filip Kujawaf947cb42022-11-21 10:00:30 -0800145 builder.finish(
146 SubmitNotes.createSubmitNotes(
147 builder,
148 this.newData[i].teamNumber,
149 dataFb,
150 this.newData[i].keywordsData.goodDriving,
151 this.newData[i].keywordsData.badDriving,
152 this.newData[i].keywordsData.sketchyClimb,
153 this.newData[i].keywordsData.solidClimb,
154 this.newData[i].keywordsData.goodDefense,
155 this.newData[i].keywordsData.badDefense
156 )
157 );
Alex Perrybb901052022-03-23 19:46:15 -0700158
Filip Kujawaf947cb42022-11-21 10:00:30 -0800159 const buffer = builder.asUint8Array();
160 const res = await fetch('/requests/submit/submit_notes', {
161 method: 'POST',
162 body: buffer,
163 });
Alex Perrybb901052022-03-23 19:46:15 -0700164
Filip Kujawaf947cb42022-11-21 10:00:30 -0800165 if (!res.ok) {
166 const resBuffer = await res.arrayBuffer();
167 const fbBuffer = new ByteBuffer(new Uint8Array(resBuffer));
168 const parsedResponse = ErrorResponse.getRootAsErrorResponse(fbBuffer);
169 const errorMessage = parsedResponse.errorMessage();
170 this.errorMessage = `Received ${res.status} ${res.statusText}: "${errorMessage}"`;
171 }
Alex Perrybb901052022-03-23 19:46:15 -0700172 }
Filip Kujawaf947cb42022-11-21 10:00:30 -0800173
174 this.newData = [];
175 this.errorMessage = '';
176 this.section = 'TeamSelection';
Alex Perrybb901052022-03-23 19:46:15 -0700177 }
178}