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/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.';