Add pit image submission test
Add submission test and add pit images to view tab.
Signed-off-by: Emily Markova <emily.markova@gmail.com>
Change-Id: I01e227f19c0622fcca09186662ab25ab34599045
diff --git a/scouting/BUILD b/scouting/BUILD
index b7e50fa..82f058c 100644
--- a/scouting/BUILD
+++ b/scouting/BUILD
@@ -28,6 +28,8 @@
name = "scouting_test",
data = [
"scouting_test.cy.js",
+ "test_img_1.png",
+ "test_img_2.png",
"//scouting/testing:scouting_test_servers",
],
runner = "scouting_test_runner.js",
diff --git a/scouting/scouting_test.cy.js b/scouting/scouting_test.cy.js
index b1276d9..7d5d75b 100644
--- a/scouting/scouting_test.cy.js
+++ b/scouting/scouting_test.cy.js
@@ -175,6 +175,39 @@
headerShouldBe('1 Init ');
});
+ it('should: allow users to submit pit images.', () => {
+ switchToTab('Pit');
+ headerShouldBe('Pit Scouting');
+ setInputTo('#teamNumber', '971');
+
+ cy.get('#pitImage').selectFile('test_img_1.png');
+
+ clickButton('Submit');
+ headerShouldBe('Pit Scouting');
+ setInputTo('#teamNumber', '971');
+
+ cy.get('#pitImage').selectFile('test_img_2.png');
+
+ clickButton('Submit');
+ headerShouldBe('Pit Scouting');
+
+ switchToTab('View');
+
+ cy.get('[data-bs-toggle="dropdown"]').click();
+ cy.get('[id="pit_images_source_dropdown"]').click();
+ cy.get('table.table tbody th').should('contain', '971');
+ cy.get('img')
+ .first()
+ .should('be.visible')
+ .should('have.attr', 'src')
+ .should('include', 'test_img_1.png');
+ cy.get('img')
+ .last()
+ .should('be.visible')
+ .should('have.attr', 'src')
+ .should('include', 'test_img_2.png');
+ });
+
it('should: let users enter match information manually.', () => {
switchToTab('Entry');
headerShouldBe(' Team Selection ');
diff --git a/scouting/test_img_1.png b/scouting/test_img_1.png
new file mode 100644
index 0000000..d13a4df
--- /dev/null
+++ b/scouting/test_img_1.png
Binary files differ
diff --git a/scouting/test_img_2.png b/scouting/test_img_2.png
new file mode 100644
index 0000000..5f77ef3
--- /dev/null
+++ b/scouting/test_img_2.png
Binary files differ
diff --git a/scouting/webserver/requests/BUILD b/scouting/webserver/requests/BUILD
index a7593e7..7be151e 100644
--- a/scouting/webserver/requests/BUILD
+++ b/scouting/webserver/requests/BUILD
@@ -19,6 +19,8 @@
"//scouting/webserver/requests/messages:request_all_matches_response_go_fbs",
"//scouting/webserver/requests/messages:request_all_notes_go_fbs",
"//scouting/webserver/requests/messages:request_all_notes_response_go_fbs",
+ "//scouting/webserver/requests/messages:request_all_pit_images_go_fbs",
+ "//scouting/webserver/requests/messages:request_all_pit_images_response_go_fbs",
"//scouting/webserver/requests/messages:request_notes_for_team_go_fbs",
"//scouting/webserver/requests/messages:request_notes_for_team_response_go_fbs",
"//scouting/webserver/requests/messages:request_pit_images_go_fbs",
@@ -57,6 +59,8 @@
"//scouting/webserver/requests/messages:request_all_matches_response_go_fbs",
"//scouting/webserver/requests/messages:request_all_notes_go_fbs",
"//scouting/webserver/requests/messages:request_all_notes_response_go_fbs",
+ "//scouting/webserver/requests/messages:request_all_pit_images_go_fbs",
+ "//scouting/webserver/requests/messages:request_all_pit_images_response_go_fbs",
"//scouting/webserver/requests/messages:request_notes_for_team_go_fbs",
"//scouting/webserver/requests/messages:request_pit_images_go_fbs",
"//scouting/webserver/requests/messages:request_pit_images_response_go_fbs",
diff --git a/scouting/webserver/requests/debug/BUILD b/scouting/webserver/requests/debug/BUILD
index 11311d2..1224710 100644
--- a/scouting/webserver/requests/debug/BUILD
+++ b/scouting/webserver/requests/debug/BUILD
@@ -13,6 +13,7 @@
"//scouting/webserver/requests/messages:request_all_driver_rankings_response_go_fbs",
"//scouting/webserver/requests/messages:request_all_matches_response_go_fbs",
"//scouting/webserver/requests/messages:request_all_notes_response_go_fbs",
+ "//scouting/webserver/requests/messages:request_all_pit_images_response_go_fbs",
"//scouting/webserver/requests/messages:request_notes_for_team_response_go_fbs",
"//scouting/webserver/requests/messages:request_pit_images_response_go_fbs",
"//scouting/webserver/requests/messages:request_shift_schedule_response_go_fbs",
diff --git a/scouting/webserver/requests/debug/debug.go b/scouting/webserver/requests/debug/debug.go
index 3e5b4f9..faf4a9d 100644
--- a/scouting/webserver/requests/debug/debug.go
+++ b/scouting/webserver/requests/debug/debug.go
@@ -15,6 +15,7 @@
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes_response"
+ "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_pit_images_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule_response"
@@ -144,6 +145,12 @@
request_pit_images_response.GetRootAsRequestPitImagesResponse)
}
+func RequestAllPitImages(server string, requestBytes []byte) (*request_all_pit_images_response.RequestAllPitImagesResponseT, error) {
+ return sendMessage[request_all_pit_images_response.RequestAllPitImagesResponseT](
+ server+"/requests/request/all_pit_images", requestBytes,
+ request_all_pit_images_response.GetRootAsRequestAllPitImagesResponse)
+}
+
func RequestAllNotes(server string, requestBytes []byte) (*request_all_notes_response.RequestAllNotesResponseT, error) {
return sendMessage[request_all_notes_response.RequestAllNotesResponseT](
server+"/requests/request/all_notes", requestBytes,
diff --git a/scouting/webserver/requests/messages/BUILD b/scouting/webserver/requests/messages/BUILD
index 13fdc45..735caab 100644
--- a/scouting/webserver/requests/messages/BUILD
+++ b/scouting/webserver/requests/messages/BUILD
@@ -19,6 +19,8 @@
"submit_pit_image_response",
"request_pit_images",
"request_pit_images_response",
+ "request_all_pit_images",
+ "request_all_pit_images_response",
"request_shift_schedule",
"request_shift_schedule_response",
"submit_shift_schedule",
diff --git a/scouting/webserver/requests/messages/request_all_pit_images.fbs b/scouting/webserver/requests/messages/request_all_pit_images.fbs
new file mode 100644
index 0000000..df2d085
--- /dev/null
+++ b/scouting/webserver/requests/messages/request_all_pit_images.fbs
@@ -0,0 +1,6 @@
+namespace scouting.webserver.requests;
+
+table RequestAllPitImages {
+}
+
+root_type RequestAllPitImages;
diff --git a/scouting/webserver/requests/messages/request_all_pit_images_response.fbs b/scouting/webserver/requests/messages/request_all_pit_images_response.fbs
new file mode 100644
index 0000000..d5a2abc
--- /dev/null
+++ b/scouting/webserver/requests/messages/request_all_pit_images_response.fbs
@@ -0,0 +1,13 @@
+namespace scouting.webserver.requests;
+
+table PitImage {
+ team_number:string (id:0);
+ check_sum:string (id:1);
+ image_path:string (id:2);
+}
+
+table RequestAllPitImagesResponse {
+ pit_image_list: [PitImage] (id:0);
+}
+
+root_type RequestAllPitImagesResponse;
diff --git a/scouting/webserver/requests/requests.go b/scouting/webserver/requests/requests.go
index af67386..9628c0d 100644
--- a/scouting/webserver/requests/requests.go
+++ b/scouting/webserver/requests/requests.go
@@ -23,6 +23,8 @@
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes_response"
+ "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_pit_images"
+ "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_pit_images_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images"
@@ -57,6 +59,8 @@
type SubmitPitImageResponseT = submit_pit_image_response.SubmitPitImageResponseT
type RequestPitImages = request_pit_images.RequestPitImages
type RequestPitImagesResponseT = request_pit_images_response.RequestPitImagesResponseT
+type RequestAllPitImages = request_all_pit_images.RequestAllPitImages
+type RequestAllPitImagesResponseT = request_all_pit_images_response.RequestAllPitImagesResponseT
type RequestNotesForTeam = request_notes_for_team.RequestNotesForTeam
type RequestNotesForTeamResponseT = request_notes_for_team_response.RequestNotesForTeamResponseT
type RequestShiftSchedule = request_shift_schedule.RequestShiftSchedule
@@ -86,6 +90,7 @@
QueryAllShifts(int) ([]db.Shift, error)
QueryNotes(string) ([]string, error)
QueryPitImages(string) ([]db.RequestedPitImage, error)
+ ReturnPitImages() ([]db.PitImage, error)
AddNotes(db.NotesData) error
AddPitImage(db.PitImage) error
AddDriverRanking(db.DriverRankingData) error
@@ -619,6 +624,42 @@
w.Write(builder.FinishedBytes())
}
+type requestAllPitImagesHandler struct {
+ db Database
+}
+
+func (handler requestAllPitImagesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ requestBytes, err := io.ReadAll(req.Body)
+ if err != nil {
+ respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
+ return
+ }
+
+ _, success := parseRequest(w, requestBytes, "RequestAllPitImages", request_all_pit_images.GetRootAsRequestAllPitImages)
+ if !success {
+ return
+ }
+
+ images, err := handler.db.ReturnPitImages()
+ if err != nil {
+ respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to get pit images: %v", err))
+ return
+ }
+
+ var response RequestAllPitImagesResponseT
+ for _, data := range images {
+ response.PitImageList = append(response.PitImageList, &request_all_pit_images_response.PitImageT{
+ TeamNumber: data.TeamNumber,
+ ImagePath: data.ImagePath,
+ CheckSum: data.CheckSum,
+ })
+ }
+
+ builder := flatbuffers.NewBuilder(1024)
+ builder.Finish((&response).Pack(builder))
+ w.Write(builder.FinishedBytes())
+}
+
type requestPitImagesHandler struct {
db Database
}
@@ -1009,6 +1050,7 @@
scoutingServer.Handle("/requests/submit/submit_notes", submitNoteScoutingHandler{db})
scoutingServer.Handle("/requests/submit/submit_pit_image", submitPitImageScoutingHandler{db})
scoutingServer.Handle("/requests/request/pit_images", requestPitImagesHandler{db})
+ scoutingServer.Handle("/requests/request/all_pit_images", requestAllPitImagesHandler{db})
scoutingServer.Handle("/requests/request/notes_for_team", requestNotesForTeamHandler{db})
scoutingServer.Handle("/requests/submit/shift_schedule", submitShiftScheduleHandler{db})
scoutingServer.Handle("/requests/request/shift_schedule", requestShiftScheduleHandler{db})
diff --git a/scouting/webserver/requests/requests_test.go b/scouting/webserver/requests/requests_test.go
index 0797bc1..d81b659 100644
--- a/scouting/webserver/requests/requests_test.go
+++ b/scouting/webserver/requests/requests_test.go
@@ -16,6 +16,8 @@
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes_response"
+ "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_pit_images"
+ "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_pit_images_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images_response"
@@ -597,6 +599,62 @@
}
}
+func TestRequestAllPitImages(t *testing.T) {
+ db := MockDatabase{
+ images: []db.PitImage{
+ {
+ TeamNumber: "32", ImagePath: "pitimage.jpg",
+ ImageData: []byte{3, 43, 44, 32}, CheckSum: "cdhrj",
+ },
+ {
+ TeamNumber: "231", ImagePath: "232robot.png",
+ ImageData: []byte{64, 54, 54, 21, 76, 32}, CheckSum: "rgre",
+ },
+ {
+ TeamNumber: "90", ImagePath: "abcd.jpg",
+ ImageData: []byte{92, 94, 10, 30, 57, 32, 32}, CheckSum: "erfer",
+ },
+ },
+ }
+
+ scoutingServer := server.NewScoutingServer()
+ HandleRequests(&db, scoutingServer)
+ scoutingServer.Start(8080)
+ defer scoutingServer.Stop()
+
+ builder := flatbuffers.NewBuilder(1024)
+ builder.Finish((&request_all_pit_images.RequestAllPitImagesT{}).Pack(builder))
+
+ response, err := debug.RequestAllPitImages("http://localhost:8080", builder.FinishedBytes())
+ if err != nil {
+ t.Fatal("Failed to request pit images: ", err)
+ }
+
+ expected := request_all_pit_images_response.RequestAllPitImagesResponseT{
+ PitImageList: []*request_all_pit_images_response.PitImageT{
+ {
+ TeamNumber: "32", ImagePath: "pitimage.jpg", CheckSum: "cdhrj",
+ },
+ {
+ TeamNumber: "231", ImagePath: "232robot.png", CheckSum: "rgre",
+ },
+ {
+ TeamNumber: "90", ImagePath: "abcd.jpg", CheckSum: "erfer",
+ },
+ },
+ }
+
+ if len(expected.PitImageList) != len(response.PitImageList) {
+ t.Fatal("Expected ", expected, ", but got ", *response)
+ }
+
+ for i, pit_image := range expected.PitImageList {
+ if !reflect.DeepEqual(*pit_image, *response.PitImageList[i]) {
+ t.Fatal("Expected for pit image", i, ":", *pit_image, ", but got:", *response.PitImageList[i])
+ }
+ }
+}
+
func TestRequestShiftSchedule(t *testing.T) {
db := MockDatabase{
shiftSchedule: []db.Shift{
@@ -1206,6 +1264,10 @@
return database.actions, nil
}
+func (database *MockDatabase) ReturnPitImages() ([]db.PitImage, error) {
+ return database.images, nil
+}
+
func (database *MockDatabase) DeleteFromStats(compLevel_ string, matchNumber_ int32, setNumber_ int32, teamNumber_ string) error {
for i, stat := range database.stats2023 {
if stat.CompLevel == compLevel_ &&
diff --git a/scouting/www/pit_scouting/pit_scouting.component.ts b/scouting/www/pit_scouting/pit_scouting.component.ts
index fe14090..58e7647 100644
--- a/scouting/www/pit_scouting/pit_scouting.component.ts
+++ b/scouting/www/pit_scouting/pit_scouting.component.ts
@@ -1,4 +1,10 @@
-import {Component} from '@angular/core';
+import {
+ Component,
+ ElementRef,
+ QueryList,
+ ViewChild,
+ ViewChildren,
+} from '@angular/core';
import {Builder, ByteBuffer} from 'flatbuffers';
import {ErrorResponse} from '../../webserver/requests/messages/error_response_generated';
import {SubmitPitImage} from '../../webserver/requests/messages/submit_pit_image_generated';
@@ -16,10 +22,11 @@
styleUrls: ['../app/common.css', './pit_scouting.component.css'],
})
export class PitScoutingComponent {
+ @ViewChild('preview') preview: ElementRef<HTMLImageElement>;
section: Section = 'Data';
errorMessage = '';
- teamNumber: string = '971';
+ teamNumber: string = '1';
pitImage: string = '';
async readFile(file): Promise<ArrayBuffer> {
@@ -39,10 +46,19 @@
return new Uint8Array(await this.readFile(selectedFile));
}
+ async setPitImage(event) {
+ const src = URL.createObjectURL(event.target.files[0]);
+ const previewElement = this.preview.nativeElement;
+ previewElement.src = src;
+ previewElement.style.display = 'block';
+ }
+
async submitData() {
const builder = new Builder();
const teamNumber = builder.createString(this.teamNumber);
- const pitImage = builder.createString(this.pitImage.toString());
+ const pitImage = builder.createString(
+ this.pitImage.toString().replace(/^.*[\\\/]/, '')
+ );
const imageData = SubmitPitImage.createImageDataVector(
builder,
await this.getImageData()
@@ -68,8 +84,14 @@
const errorMessage = parsedResponse.errorMessage();
this.errorMessage = `Received ${res.status} ${res.statusText}: "${errorMessage}"`;
+ return;
}
- this.section = 'TeamSelection';
+
+ // Reset Data.
+ this.section = 'Data';
+ this.errorMessage = '';
this.pitImage = '';
+ const previewElement = this.preview.nativeElement;
+ previewElement.src = '';
}
}
diff --git a/scouting/www/pit_scouting/pit_scouting.ng.html b/scouting/www/pit_scouting/pit_scouting.ng.html
index 9e90d2d..94de4f0 100644
--- a/scouting/www/pit_scouting/pit_scouting.ng.html
+++ b/scouting/www/pit_scouting/pit_scouting.ng.html
@@ -5,6 +5,7 @@
<div *ngSwitchCase="'Data'" id="pitImageSelection" class="container-fluid">
<label for="teamNumber">Team Number</label>
<input [(ngModel)]="teamNumber" type="text" id="teamNumber" />
+ <img id="preview" #preview style="max-height: 200px; max-width: 200px" />
<form action="setPitImage()">
<label for="pitImage">Select pit image:</label>
<br />
@@ -12,6 +13,7 @@
id="pitImage"
[(ngModel)]="pitImage"
type="file"
+ (change)="setPitImage($event)"
accept="image/*"
/>
</form>
diff --git a/scouting/www/rpc/BUILD b/scouting/www/rpc/BUILD
index 113c747..ab28581 100644
--- a/scouting/www/rpc/BUILD
+++ b/scouting/www/rpc/BUILD
@@ -19,6 +19,8 @@
"//scouting/webserver/requests/messages:request_all_matches_ts_fbs",
"//scouting/webserver/requests/messages:request_all_notes_response_ts_fbs",
"//scouting/webserver/requests/messages:request_all_notes_ts_fbs",
+ "//scouting/webserver/requests/messages:request_all_pit_images_response_ts_fbs",
+ "//scouting/webserver/requests/messages:request_all_pit_images_ts_fbs",
"@com_github_google_flatbuffers//ts:flatbuffers_ts",
],
)
diff --git a/scouting/www/rpc/view_data_requestor.ts b/scouting/www/rpc/view_data_requestor.ts
index 24d10b6..f1f2b79 100644
--- a/scouting/www/rpc/view_data_requestor.ts
+++ b/scouting/www/rpc/view_data_requestor.ts
@@ -13,6 +13,11 @@
} from '../../webserver/requests/messages/request_all_driver_rankings_response_generated';
import {Request2023DataScouting} from '../../webserver/requests/messages/request_2023_data_scouting_generated';
import {
+ PitImage,
+ RequestAllPitImagesResponse,
+} from '../../webserver/requests/messages/request_all_pit_images_response_generated';
+import {RequestAllPitImages} from '../../webserver/requests/messages/request_all_pit_images_generated';
+import {
Stats2023,
Request2023DataScoutingResponse,
} from '../../webserver/requests/messages/request_2023_data_scouting_response_generated';
@@ -96,4 +101,25 @@
}
return statList;
}
+
+ // Returns all pit image entries from the database.
+ async fetchPitImagesList(): Promise<PitImage[]> {
+ let fbBuffer = await this.fetchFromServer(
+ RequestAllPitImages.startRequestAllPitImages,
+ RequestAllPitImages.endRequestAllPitImages,
+ '/requests/request/all_pit_images'
+ );
+
+ const parsedResponse =
+ RequestAllPitImagesResponse.getRootAsRequestAllPitImagesResponse(
+ fbBuffer
+ );
+
+ // Convert the flatbuffer list into an array. That's more useful.
+ const pitImageList = [];
+ for (let i = 0; i < parsedResponse.pitImageListLength(); i++) {
+ pitImageList.push(parsedResponse.pitImageList(i));
+ }
+ return pitImageList;
+ }
}
diff --git a/scouting/www/view/view.component.css b/scouting/www/view/view.component.css
index e220645..7811d2d 100644
--- a/scouting/www/view/view.component.css
+++ b/scouting/www/view/view.component.css
@@ -1,3 +1,23 @@
* {
padding: 10px;
}
+
+.collapse-border {
+ border-collapse: collapse;
+ border-color: transparent;
+ border-width: 0;
+ overflow: auto;
+}
+
+.align-images {
+ word-wrap: break-word;
+ display: flex;
+ margin: 5px;
+ justify-content: center;
+ align-items: center;
+}
+
+.align-text {
+ text-align: center;
+ vertical-align: middle;
+}
diff --git a/scouting/www/view/view.component.ts b/scouting/www/view/view.component.ts
index 26e816b..64b0680 100644
--- a/scouting/www/view/view.component.ts
+++ b/scouting/www/view/view.component.ts
@@ -9,6 +9,12 @@
Stats2023,
Request2023DataScoutingResponse,
} from '../../webserver/requests/messages/request_2023_data_scouting_response_generated';
+
+import {
+ PitImage,
+ RequestAllPitImagesResponse,
+} from '../../webserver/requests/messages/request_all_pit_images_response_generated';
+
import {
Note,
RequestAllNotesResponse,
@@ -18,7 +24,7 @@
import {ViewDataRequestor} from '../rpc';
-type Source = 'Notes' | 'Stats2023' | 'DriverRanking';
+type Source = 'Notes' | 'Stats2023' | 'PitImages' | 'DriverRanking';
//TODO(Filip): Deduplicate
const COMP_LEVEL_LABELS = {
@@ -56,6 +62,7 @@
// Stores the corresponding data.
noteList: Note[] = [];
driverRankingList: Ranking[] = [];
+ pitImageList: PitImage[][] = [];
statList: Stats2023[] = [];
// Fetch notes on initialization.
@@ -74,13 +81,23 @@
.team()
.localeCompare(a[0].team(), undefined, {numeric: true});
});
+ this.pitImageList.sort(function (a, b) {
+ return b[0]
+ .teamNumber()
+ .localeCompare(a[0].teamNumber(), undefined, {numeric: true});
+ });
this.statList.sort((a, b) => b.matchNumber() - a.matchNumber());
} else {
this.driverRankingList.sort((a, b) => a.matchNumber() - b.matchNumber());
this.noteList.sort(function (a, b) {
- return a[0]
+ return b[0]
.team()
- .localeCompare(b[0].team(), undefined, {numeric: true});
+ .localeCompare(a[0].team(), undefined, {numeric: true});
+ });
+ this.pitImageList.sort(function (a, b) {
+ return a[0]
+ .teamNumber()
+ .localeCompare(b[0].teamNumber(), undefined, {numeric: true});
});
this.statList.sort((a, b) => a.matchNumber() - b.matchNumber());
}
@@ -95,6 +112,7 @@
this.noteList = [];
this.driverRankingList = [];
this.statList = [];
+ this.pitImageList = [];
this.fetchCurrentSource();
}
@@ -109,6 +127,10 @@
this.fetchStats2023();
}
+ case 'PitImages': {
+ this.fetchPitImages();
+ }
+
case 'DriverRanking': {
this.fetchDriverRanking();
}
@@ -211,6 +233,42 @@
}
}
+ // Fetch all pit image data and store in pitImageList.
+ async fetchPitImages() {
+ this.progressMessage = 'Fetching pit image list. Please be patient.';
+ this.errorMessage = '';
+
+ try {
+ const initialPitImageList =
+ await this.viewDataRequestor.fetchPitImagesList();
+ let officialPitImageList = [];
+ // Use iteration to make an array of arrays containing pit image data for individual teams.
+ // Ex. [ [ {971PitImageData} , {971PitImage2Data} ], [ {432PitImageData} ] , [ {213PitImageData} ] ]
+ for (let pitImage of initialPitImageList) {
+ let found = false;
+ for (let arr of officialPitImageList) {
+ if (arr[0].teamNumber() == pitImage.teamNumber()) {
+ arr.push(pitImage);
+ found = true;
+ }
+ }
+ if (!found) {
+ officialPitImageList.push([pitImage]);
+ }
+ }
+ // Sort the arrays based on image file names so their order is predictable.
+ for (let arr of officialPitImageList) {
+ arr.sort((a, b) => (a.imagePath() > b.imagePath() ? 1 : -1));
+ }
+ this.pitImageList = officialPitImageList;
+ this.sortData();
+ this.progressMessage = 'Successfully fetched pit image list.';
+ } catch (e) {
+ this.errorMessage = e;
+ this.progressMessage = '';
+ }
+ }
+
// Fetch all data scouting (stats) data and store in statList.
async fetchStats2023() {
this.progressMessage = 'Fetching stats list. Please be patient.';
diff --git a/scouting/www/view/view.ng.html b/scouting/www/view/view.ng.html
index ee2c62f..239548c 100644
--- a/scouting/www/view/view.ng.html
+++ b/scouting/www/view/view.ng.html
@@ -34,6 +34,16 @@
<a
class="dropdown-item"
href="#"
+ (click)="switchDataSource('PitImages')"
+ id="pit_images_source_dropdown"
+ >
+ PitImages
+ </a>
+ </li>
+ <li>
+ <a
+ class="dropdown-item"
+ href="#"
(click)="switchDataSource('DriverRanking')"
id="driver_ranking_source_dropdown"
>
@@ -123,6 +133,42 @@
</tbody>
</table>
</div>
+ <!-- Pit Images Data Display. -->
+ <div *ngSwitchCase="'PitImages'">
+ <table class="table collapse-border">
+ <thead>
+ <tr>
+ <th scope="col" class="d-flex flex-row">
+ <div class="align-self-center">Team</div>
+ <div class="align-self-center" *ngIf="ascendingSort">
+ <i (click)="sortData()" class="bi bi-caret-up"></i>
+ </div>
+ <div class="align-self-center" *ngIf="!ascendingSort">
+ <i (click)="sortData()" class="bi bi-caret-down"></i>
+ </div>
+ </th>
+ <th scope="col" style="max-width: 200px; max-height: 200px">
+ Image(s)
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let pitImageArr of pitImageList">
+ <th scope="row" class="align-text">
+ {{pitImageArr[0].teamNumber()}}
+ </th>
+ <td style="display: flex">
+ <div *ngFor="let pitImage of pitImageArr" class="align-images">
+ <img
+ src="/sha256/{{ pitImage.checkSum() }}/{{ pitImage.imagePath() }}"
+ style="max-width: 50px; max-height: 50px; padding: 0; margin: 0"
+ />
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
<!-- Driver Ranking Data Display. -->
<div *ngSwitchCase="'DriverRanking'">
<table class="table">