Add integration with The Blue Alliance API#69
Conversation
b61c79c to
6c7b83f
Compare
|
24c058c to
9f539b3
Compare
26d6904 to
3430408
Compare
1. Prefill match data information for your team prior to the event.
- Before scouting an event, click the new "Prefill Match Data"
button.
- This will fetch all events for the current year for your team based
on the config file and provide you with a dialog to choose which
event to use for match data.
- Once the event is selected, it will fetch and store all matches for
that event into our local storage-backed state.
- If no internet is available, we display an error to the user but no
state is lost.
2. DynamicMatchNumberInput Component:
- Shows a dropdown select menu with all qualification match numbers when match data is available.
- Falls back to a standard number input when no match data is available.
- Maintains all other features of the original NumberInput component.
3. DynamicTeamNumberInput Component:
- Automatically populates based on the selected match number and robot position ("R1", "B2", etc.).
- Shows a dropdown with the correct team number when available.
- Automatically sets the team number value when a valid option is found.
- Falls back to a standard number input when no match data is available or no robot position is selected.
4. Updated ConfigurableInput:
- Special case handling for "matchNumber" and "teamNumber" fields.
- Uses the dynamic input components for these fields.
- Maintains the original components for all other fields.
This implementation:
- Shows a dropdown select input for match number only when there's match data in the state
- Shows a dropdown select input for team number when both match data is available and a match is selected
- Automatically populates the team number based on the robot position from the dropdown
- Preserves existing functionality when no match data is available
- Fails gracefully if the form doesn't have match number or team number inputs
The code is designed to respect the existing patterns and structure of the application while adding the new functionality in a clean, maintainable way.
1. Self-contained functionality: - The MatchDataFetcher now includes its own button and dialog handling - It no longer requires a render prop or children function pattern - No need for external refs or state handling by the parent component 2. Clearer separation of concerns: - Each component is now responsible for its own domain - ConfigSection is responsible for layout and general section functionality - MatchDataFetcher is solely responsible for the TBA data fetching workflow 3. Simplified parent component: - Removed unnecessary state, refs, and effect hooks from ConfigSection - Reduced the number of imports in ConfigSection - Eliminated complex prop-passing and render prop patterns
- Add `TBA-match-number` input type for selecting qualification matches - Add `TBA-team-and-robot` input type for selecting teams with robot positions - Replace dynamic field overrides with proper configurable input types - Teams can now control Blue Alliance integration through JSON config - Remove old DynamicMatchNumberInput and DynamicTeamNumberInput components - Update cmdk dependency to fix missing component issue 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit refines the Blue Alliance integration by renaming components for better clarity and adding extensive documentation to help teams understand and configure the TBA features. The original TeamAndRobotInput has been renamed to TBATeamAndRobotInput to make its purpose immediately clear - it's specifically designed for The Blue Alliance integration, not just any team selection. We also updated all the schema names to use the "tba" prefix consistently throughout the codebase. We encountered an interesting challenge when trying to reuse the existing NumberInput component for fallback scenarios. The NumberInput expects a full ConfigurableInputProps interface including a type field, but our TBA components need to manage their own state and behavior differently. Rather than forcing an awkward integration, we opted to implement clean, focused fallback inputs that maintain the same validation logic but don't try to share code where it doesn't naturally fit. The documentation has been significantly expanded to match the quality and depth of the existing input type documentation. The new TBA section in the README explains both input types, provides complete configuration examples, covers the data formats teams can expect in their QR codes, and includes practical FRC scouting scenarios. We also made sure to link to the detailed API setup guide we created earlier, giving teams a complete picture of how to get started with TBA integration. This approach follows QRScout's philosophy of giving users control - the TBA inputs enhance the experience when match data is available, but gracefully fall back to manual entry when needed. Teams can start using these inputs immediately and add the API integration later when they're ready. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add CONTRIBUTING.md with setup instructions for new developers - Add .env.example template for environment variables - Update .gitignore to track .env.example while ignoring actual .env files
Remove the user-provided API key flow in favor of a shipped API key: - Get API key from VITE_TBA_API_KEY environment variable - Inject API key via GitHub secrets in deploy workflow - Remove TBAApiKeyDialog component and tbaApiKeyStorage utility - Simplify MatchDataFetcher to fetch events directly - Remove validateTBAApiKey function (no longer needed) - Update README to remove API key setup instructions - Delete the-blue-alliance-api-configuration.md guide Users no longer need to configure their own TBA API key.
Add optional chaining to monaco.json.jsonDefaults to handle lazy-loaded JSON language features.
The loading state wasn't working because onEventSelected (an async function) wasn't being awaited, causing setIsLoading(false) to run immediately.
Shows a spinner and 'Loading...' text while fetching events from TBA, and disables the button to prevent duplicate requests.
3430408 to
3723dfa
Compare
The old function unnecessarily stringified and re-parsed the config JSON, validated it (even though it came from state and was already valid), and called setFormData which reset form values. The new setMatchData simply stores match data in state, which is all that was actually needed.
Pass fetchEvents directly to onClick instead of wrapping it in another useCallback that just calls it.
|
This looks really good @luanzeba! I accidentally approved. How do i unapprove? A few questions:
|
Previously, errors like 'No match data available for this event yet' were passed to the parent component's onError callback, which displayed them behind the open dialog. Users couldn't see the error and thought the app was unresponsive. Now handleEventSelected throws errors instead of calling onError, and the dialog catches them and displays them inline with the actual error message.
|
Thanks @tytremblay!
You have to review it again with a different status.
Let me know if you can see this https://drive.google.com/file/d/1yngyo1dCD3IyDDvnJwL60g0vJDplahSF/view?usp=sharing
Yep, that was my mistake. I meant the match data is not available until the first day of competition usually. The events are up way in advance. This is what it looks like if I try to pull match data from a 2026 event.
They're stored in local storage after the initial pull so they only need to pull it once, but I think they'd have to pull it individually in each device. I guess we could store it in the config but I think that'd add a lot of noise there. I showed what it looks like in the demo above too. |
|
@luanzeba yeah, the match data makes sense. They don't generate the matches until all the teams have checked in at the event. |

What this adds
This PR brings Blue Alliance integration to QRScout, letting teams automatically populate match and team data instead of entering everything manually.
Demo
https://drive.google.com/file/d/1yngyo1dCD3IyDDvnJwL60g0vJDplahSF/view?usp=sharing
Key changes
New dialog
Added a "Prefill Match Data" button in the configuration panel.
Once clicked, we use their team number from the JSON config to fetch all this year's events and present them to the user to choose from. Once the user chooses the event, we load all the match information into local storage.
New inputs
We added a couple of new input types for the JSON config:
TBA-match-numberThis input uses the data fetched from The Blue Alliance API to populate a "select" input with all the qualifying matches from the specified event.
TBA-team-and-robotThis input uses the data fetched from The Blue Alliance API to populate a "select" input with all the "team number (robot number)" options for match selected above.
Added docs
README on the new input types
Note
We did not update the default config in this PR. We'll do that in a separate PR after thorough testing that these new inputs are behaving as expected.