Skip to content

Commit

Permalink
scout page documented
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryan-Bauroth committed Jun 27, 2024
1 parent 1ac5921 commit 435fe76
Showing 1 changed file with 136 additions and 64 deletions.
200 changes: 136 additions & 64 deletions pages/scout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,54 +12,50 @@ import type { UnwrapRef } from 'vue';
import { loginStateKey } from '~/utils/keys';
import { useEventKey } from '~/composables/useEventKey';
//gets username and scouting database
const {
usernameState,
}: {
usernameState: Ref<UnwrapRef<string>>;
} = inject(loginStateKey)!;
const { scoutingData: db } = databases.locals;
//An enum of tabs on the scout page
enum GameTime {
Autonomous = 'Auto',
Teleoperated = 'Teleop',
Endgame = 'Endgame',
Notes = 'Notes',
}
//The active tab used
let gameTime = ref(GameTime.Autonomous);
//gets current event key
const currentEvent = useEventKey();
watch(currentEvent, value => {
window.localStorage.setItem('currentEvent', value);
});
//gets the blue alliance data for what teams are at the current event and puts them in an array
const { data: tbaEventData, pending: tbaPending } = await useLazyFetch<
Array<any>
>('/api/eventTeams/' + currentEvent.value);
watch(tbaPending, () => {
if (!tbaPending.value && tbaEventData.value != null) {
validTeamNums.value = tbaEventData.value.map(value => value.team_number);
}
});
let validTeamNums = ref<Array<number>>();
/*
START SEASONAL UPDATE AREA
*/
// Selectable options for the Multi-Select component
/*
The following are a bunch of configuration variables used for the 2024 season
Each is labeled with which component in the HTML below it corresponds with
Feel free to delete these when you update this page,
just make sure you understand how they are used in case you wish to use the same custom components we used
*/
//Endgame Multi-Select Component Options
const endgameOptions = [
'None',
'Parked',
'Attempted Onstage',
'Onstage',
'Harmony',
];
const connectedOptions = [1, 2, 2, 3, 3];
let endgameIndex = [1, 0, 0, 0, 0];
//Auto Modal Image
const isOpen = ref(false);
/*
Configuration variables done
*/
//all the data collected on the scout page in the form of ScoutingData, a type found in the utils/databases.ts file
/**
* updateEndgameOptions updates the scoutData variable to match the currently selected option in the endgame multiselect
* @param value the currently selected option
*/
function updateEndgameOptions(value: Array<number>) {
let arr = [];
for (let i = 0; i < value.length; i++) {
if (value[i] == 1) {
arr.push(endgameOptions[i]);
}
}
scoutData.value.endgame.endgame = arr;
if (scoutData.value.endgame.endgame.length < 1) {
scoutData.value.endgame.endgame = [endgameOptions[0]];
}
}
//all the data collected on the scout page in the form of a ScoutingData object,
// you can edit this in the utils/databases.ts file
let scoutData = ref<ScoutingData>({
event: '',
teamNumber: '',
Expand Down Expand Up @@ -105,19 +101,49 @@ let scoutData = ref<ScoutingData>({
},
});
function updateEndgameOptions(value: Array<number>) {
let arr = [];
for (let i = 0; i < value.length; i++) {
if (value[i] == 1) {
arr.push(endgameOptions[i]);
}
}
scoutData.value.endgame.endgame = arr;
if (scoutData.value.endgame.endgame.length < 1) {
scoutData.value.endgame.endgame = [endgameOptions[0]];
}
/*
END SEASON UPDATE AREA
NOTE: you must also update the HTML at the bottom of this page that defines how users will scout matches
to make your work easier we have implemented custom components in the /components directory that you can use just like other HTML objects
*/
//gets username and scouting database
const {
usernameState,
}: {
usernameState: Ref<UnwrapRef<string>>;
} = inject(loginStateKey)!;
const { scoutingData: db } = databases.locals;
//An enum of tabs on the scout page
enum GameTime {
Autonomous = 'Auto',
Teleoperated = 'Teleop',
Endgame = 'Endgame',
Notes = 'Notes',
}
//The active tab used
let gameTime = ref(GameTime.Autonomous);
//gets current event key
const currentEvent = useEventKey();
watch(currentEvent, value => {
window.localStorage.setItem('currentEvent', value);
});
//gets the blue alliance data for what teams are at the current event and puts them in an array
const { data: tbaEventData, pending: tbaPending } = await useLazyFetch<
Array<any>
>('/api/eventTeams/' + currentEvent.value);
watch(tbaPending, () => {
if (!tbaPending.value && tbaEventData.value != null) {
validTeamNums.value = tbaEventData.value.map(value => value.team_number);
}
});
let validTeamNums = ref<Array<number>>();
//a quick function to check if the team and match numbers a user enters are valid
function isValidNum() {
return (
scoutData.value.teamNumber != null &&
Expand All @@ -128,6 +154,10 @@ function isValidNum() {
);
}
/***
The function that submits the data a user inputs to the couchdb database (notice db.post)
also redirects the webpage to the /matches page (notice navigateTo)
*/
async function submit() {
scoutData.value.teamNumber = parseInt(scoutData.value.teamNumber);
scoutData.value.matchNumber = parseInt(scoutData.value.matchNumber);
Expand All @@ -141,13 +171,6 @@ async function submit() {
await navigateTo('/matches');
}
}
const isOpen = ref(false); //prestons way of making the reference image modal open
/* Good-looking square buttons but don't work horizontally why?
<UButton label="Docked & Engaged" style="aspect-ratio : 1 / 1; max-width: 75px; max-height: 75px;" class="m-1.5"/>
<UButton label="Docked" style="aspect-ratio : 1 / 1; max-width: 75px; max-height: 75px;" class="m-1.5"/>
*/
</script>

<template>
Expand All @@ -157,7 +180,12 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
<template #header>
<div style="display: flex">
<div class="flex-0 pr-2">
<UInput v-model="scoutData.teamNumber" placeholder="Team #">
<!-- The input for teamNumber shown in the heading of the page. visit NUXT UI documentaiton to understand UInput and other NUXT elements -->
<UInput
v-model="scoutData.teamNumber"
placeholder="Team #"
>
<!-- shows the red 'not found' text if the team number inputted isnt in the valid teams array -->
<template #trailing>
<span
class="text-red-400 dark:text-red-600 text-xs"
Expand All @@ -172,7 +200,12 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
</UInput>
</div>
<div class="flex-0 pr-2">
<UInput v-model="scoutData.matchNumber" placeholder="Match #">
<!-- the input for the match number -->
<UInput
v-model="scoutData.matchNumber"
placeholder="Match #"
>
<!-- same thing as above, shows an error text if the number is invalid -->
<template #trailing>
<span
class="text-red-400 dark:text-red-600 text-xs"
Expand All @@ -187,10 +220,15 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
</UInput>
</div>
<UFormGroup class="flex-1">
<USelectMenu v-model="currentEvent" :options="eventOptions" />
<!-- select menu between different events -->
<USelectMenu
v-model="currentEvent"
:options="eventOptions"
/>
</UFormGroup>
</div>
<br />
<!-- the tabs for each game period (auto, teleop, endgame, notes) -->
<UButtonGroup class="flex">
<UButton
v-for="gamePeriod of GameTime"
Expand All @@ -204,6 +242,7 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
/>
</UButtonGroup>
</template>
<!-- In this section put all the elements you want to be shown under the autonomous tab -->
<div v-if="gameTime == GameTime.Autonomous">
<div class="flex text-center">
<div class="max-w-24 w-24">
Expand All @@ -215,6 +254,8 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
<h1 class="text-coral-400 font-sans mr-3 mt-1 font-light text-sm">
Scored
</h1>
<!-- (- 0 +) button for scoring that updates the scoutData under the auto tab.
amp is the 2024 game's name for a scoring method -->
<IncrementalButton
class="mb-1 mr-3 mt-1"
v-model="scoutData.auto.amp"
Expand All @@ -223,6 +264,8 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
<h1 class="text-coral-400 font-sans mr-3 mt-1 font-light text-sm">
Missed
</h1>
<!-- we decided it was easiest to separate scoring and missing this year
so this does the same thing as the above incremental button but for missed shots -->
<IncrementalButton
class="mb-0 mr-3 mt-1"
v-model="scoutData.auto.missedAmp"
Expand All @@ -237,6 +280,7 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
<h1 class="text-coral-400 font-sans mr-3 mt-1 font-light text-sm">
Scored
</h1>
<!-- input method for auto and the scoring method 'speaker' for 24' season -->
<IncrementalButton
class="mb-1 mr-3 mt-1"
v-model="scoutData.auto.speakerNA"
Expand All @@ -245,6 +289,7 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
<h1 class="text-coral-400 font-sans mr-3 mt-1 font-light text-sm">
Missed
</h1>
<!-- missed points for speaker -->
<IncrementalButton
class="mb-0 mr-3 mt-1"
v-model="scoutData.auto.missedSpeaker"
Expand All @@ -253,6 +298,7 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
<div>
<br />
<br />
<!-- a true/false button (custom component) -->
<BooleanButton
class="mt-1"
v-model="scoutData.auto.mobility"
Expand All @@ -268,14 +314,22 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
</h1>
</div>
<div>
<!-- a single selection among multiple options custom component.
used for the starting position of the team's robot during auto -->
<SingleSelect
v-model="scoutData.auto.position"
:options="['1', '2', '3', '4']"
/>
<UButton class="ml-1" @click="isOpen = true" label="Reference" />
<!-- a button that opens a reference image for the previous element, a
starting position selector -->
<UButton
class="ml-1"
@click="isOpen = true"
label="Reference"
/>
</div>
</div>

<!-- the popup for the reference image -->
<UModal v-model="isOpen">
<div class="flex flex-auto">
<UButton
Expand All @@ -286,6 +340,8 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
<img src="/public/referenceImage.png" />
</div>
</UModal>

<!-- In this section put all the elements you want to be shown under the teleop tab -->
<div v-if="gameTime == GameTime.Teleoperated">
<div class="flex text-center">
<div class="max-w-24 w-24">
Expand All @@ -297,6 +353,7 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
<h1 class="text-coral-400 font-sans mr-3 mt-1 font-light text-sm">
Scored
</h1>
<!-- same thing as above incremental buttons but for teleop -->
<IncrementalButton
class="mb-1 mr-3 mt-1"
v-model="scoutData.teleop.amp"
Expand Down Expand Up @@ -334,31 +391,39 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
</div>
</div>
</div>
<!-- In this section put all the elements you want for the teleop tab -->
<div v-if="gameTime == GameTime.Endgame">
<div class="flex text-center flex-wrap mb-3">
<div class="max-w-24 w-24">
<h1 class="text-gray-700 dark:text-gray-200 font-sans font-medium">
Trap
</h1>
<!-- a new scoring method, but same idea as above incremental buttons -->
<IncrementalButton
class="mt-1"
v-model="scoutData.endgame.trap"
:max-value="3"
></IncrementalButton>
</div>
</div>
<!-- a multi select custom component. this acts like the single select but allows you to select multiple buttons at a time.
the connection options optional param allows you to configure which options are allowed to be selected with each other
notice the @update: which runs the updateEndgameOptions() function upon each update of the custom component-->
<MultiSelect
:model-value="endgameIndex"
:model-value="[1, 0, 0, 0, 0]"
:options="endgameOptions"
@update:model-value="
value => {
updateEndgameOptions(value);
}
"
:connected-options="connectedOptions"
:connected-options="[1, 2, 2, 3, 3]"
/>
</div>
<!-- In this section put all the elements you want in the notes tab -->
<div v-if="gameTime == GameTime.Notes">
<!-- A UAccordion is a grouping of different dropdowns
in this case, it is used to allow for different categories-->
<UAccordion
open-icon="i-heroicons-plus"
close-icon="i-heroicons-minus"
Expand All @@ -368,7 +433,11 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
{ label: 'Driver', slot: 'driver' },
]"
>
<!-- templates fill the UAccordion's sections -->
<template #defense>
<!-- the PromptedNote custom component takes in an array of questions and how many lines should be expected as output for that question
for example: 'Where did this team play defense?' is the question while '1' is the number of lines expected for that response
it then returns an array of answers to the questions which is updated to the scoutData variable -->
<PromptedNote
v-model="scoutData.notes.promptedNotes[0]"
:questions="[
Expand Down Expand Up @@ -408,6 +477,7 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
</UAccordion>
</div>
<template #footer>
<!-- A general notes area using the NUXT UI UTextarea-->
<UTextarea
v-model="scoutData.notes.notes"
color="yellow"
Expand All @@ -416,6 +486,7 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
<br />
<div class="flex justify-between">
<div>
<!-- a button to cancel -->
<UButton
class="m-1"
color="coral"
Expand All @@ -424,6 +495,7 @@ const isOpen = ref(false); //prestons way of making the reference image modal op
type="reset"
variant="outline"
/>
<!-- a button to submit -->
<UButton
class="m-1"
label="Submit"
Expand Down

0 comments on commit 435fe76

Please sign in to comment.