feat: roadmap search shortcut pills (#1815)#1907
Conversation
- Add courseId field to WebsocSearchInputSchema, matching the Anteater API's existing support for querying WebSOC by course ID - Extend getManyOfField's fieldName enum to accept 'courseId' in addition to 'ge', enabling fan-out queries for multiple course IDs Part of #1815
- Add courseIds nuqs array parser and useCourseIds hook for URL-driven planner course search state - Update CourseRenderPane to branch on courseIds: fan out via getManyOfField with fieldName 'courseId', then unionWebsocResponses - Update SearchWithPlanner to write courseIds directly to URL instead of resolving via trpc.course.getMultiple + RightPaneStore - Update PlannerCourseLinkBanner to read courseIds from URL - Remove useQuickSearch's RightPaneStore dependency - Delete RightPaneStore.ts (multiSearchData was its only purpose) - Simplify queryKeys to use courseIds array instead of serialized multiSearchData Part of #1815
- courseIds is now part of courseSearchParamParsers, making it part of formData alongside ge, deptValue, etc. - Remove standalone courseIdsParser, useCourseIds hook, COURSE_IDS_KEY - Update isValidSearch and shouldShowSearchForm to accept courseIds - CourseRenderPane reads formData.courseIds directly - queryKeys simplified — courseIds included in formData serialization - Add courseIds default to DEFAULT_FORM_DATA Part of #1815
Move courseIds default into DEFAULT_ADVANCED_SEARCH_VALUES and add it to ADVANCED_SEARCH_PARAMS and advancedSearchParsers. This categorizes it alongside other non-UI-exposed params like excludeRoadmapCourses. Part of #1815
Split-button pill for quick roadmap search: - Left side: click to search with the active roadmap's courses - Right side: dropdown to pick a different roadmap - Only renders when signed in and roadmaps with courses for the current term are available - Animates in via MUI Grow transition - Dropdown shows all roadmaps, disabled ones labeled with reason Part of #1815
- Remove 'or' text + SearchWithPlanner autocomplete from QuickSearch - Add pill row below FuzzySearch with RoadmapPill as first pill - Delete SearchWithPlanner.tsx entirely - Leave commented slot in pill row for future pills (department, etc.) Part of #1815
- Remove COURSE_SEARCH_PLANNER_KEY constant - Remove plannerSearchParser export - Remove shouldSearchPlannerFromParams() from plannerHelpers - Remove plannerSearchParam from useCourseSearchMode (manual mode no longer gated on planner param absence) - Update ScheduleManagement to rely on hasAdvancedParams (which now covers courseIds) instead of shouldSearchPlannerFromParams Part of #1815
- Bring back 'X is not offered' warnings for courseIds searches by diffing requested courseIds against courseIds returned by WebSOC - Remove the filterTakenCourses WarningAlert - Remove usePlannerStore import from CourseRenderPane Part of #1815
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/antalmanac/src/components/RightPane/CoursePane/CourseRenderPane/CourseRenderPane.tsx">
<violation number="1" location="apps/antalmanac/src/components/RightPane/CoursePane/CourseRenderPane/CourseRenderPane.tsx:93">
P2: `unofferedCourseIds` is mutated inside async `queryFn`, which can leave stale/mismatched warning alerts after failed or out-of-order requests.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| ); | ||
|
|
||
| const returnedIds = new Set(flattenCourses(response).map((c) => c.courseId)); | ||
| setUnofferedCourseIds(formData.courseIds.filter((id) => !returnedIds.has(id))); |
There was a problem hiding this comment.
P2: unofferedCourseIds is mutated inside async queryFn, which can leave stale/mismatched warning alerts after failed or out-of-order requests.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/antalmanac/src/components/RightPane/CoursePane/CourseRenderPane/CourseRenderPane.tsx, line 93:
<comment>`unofferedCourseIds` is mutated inside async `queryFn`, which can leave stale/mismatched warning alerts after failed or out-of-order requests.</comment>
<file context>
@@ -89,7 +88,11 @@ export function CourseRenderPane({ onDismissSearchResults }: CourseRenderPanePro
);
+
+ const returnedIds = new Set(flattenCourses(response).map((c) => c.courseId));
+ setUnofferedCourseIds(formData.courseIds.filter((id) => !returnedIds.has(id)));
} else {
+ setUnofferedCourseIds([]);
</file context>
There was a problem hiding this comment.
1 issue found across 17 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/antalmanac/src/components/RightPane/CoursePane/SearchForm/QuickSearch/RoadmapPill.tsx">
<violation number="1" location="apps/antalmanac/src/components/RightPane/CoursePane/SearchForm/QuickSearch/RoadmapPill.tsx:117">
P2: Roadmaps are enabled by term presence instead of searchable (non-custom) course IDs, so custom-only roadmaps appear selectable but always fail at search time.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
/deploy-shared |
TODO: Remove before merging. Bypasses auth check and injects fake roadmaps (CS Major + GE) covering 2024-2026 so the pill renders without a real planner session.
There was a problem hiding this comment.
2 issues found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/antalmanac/src/components/RightPane/CoursePane/CourseRenderPane/CourseRenderPane.tsx">
<violation number="1" location="apps/antalmanac/src/components/RightPane/CoursePane/CourseRenderPane/CourseRenderPane.tsx:93">
P2: `unofferedCourseIds` is mutated inside async `queryFn`, which can leave stale/mismatched warning alerts after failed or out-of-order requests.</violation>
</file>
<file name="apps/antalmanac/src/components/RightPane/CoursePane/SearchForm/QuickSearch/RoadmapPill.tsx">
<violation number="1" location="apps/antalmanac/src/components/RightPane/CoursePane/SearchForm/QuickSearch/RoadmapPill.tsx:17">
P3: New TODO comment is anonymous; add an owner handle to match repository TODO conventions.
(Based on your team's feedback about naming TODO owners.) [FEEDBACK_USED].</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| import { useCallback, useMemo, useRef, useState } from 'react'; | ||
| import { useShallow } from 'zustand/react/shallow'; | ||
|
|
||
| // TODO: Remove mock data before merging. Hardcoded roadmaps for testing the pill UI. |
There was a problem hiding this comment.
P3: New TODO comment is anonymous; add an owner handle to match repository TODO conventions.
(Based on your team's feedback about naming TODO owners.) .
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/antalmanac/src/components/RightPane/CoursePane/SearchForm/QuickSearch/RoadmapPill.tsx, line 17:
<comment>New TODO comment is anonymous; add an owner handle to match repository TODO conventions.
(Based on your team's feedback about naming TODO owners.) .</comment>
<file context>
@@ -14,6 +14,34 @@ import type { AATerm, Roadmap } from '@packages/antalmanac-types';
import { useCallback, useMemo, useRef, useState } from 'react';
import { useShallow } from 'zustand/react/shallow';
+// TODO: Remove mock data before merging. Hardcoded roadmaps for testing the pill UI.
+const MOCK_ROADMAPS: Roadmap[] = [
+ {
</file context>
- Full pill-radius (9999) on ButtonGroup with inherited radii on children - Menu anchored bottom-left with small gap, rounded paper, subtle shadow - Menu items have slight rounding and horizontal margin Part of #1815
…pills-7722 # Conflicts: # apps/antalmanac/src/components/RightPane/CoursePane/SearchForm/QuickSearch/SearchWithPlanner.tsx # apps/antalmanac/src/lib/plannerHelpers.ts
There was a problem hiding this comment.
2 issues found across 5 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/antalmanac/src/components/RightPane/CoursePane/CourseRenderPane/CourseRenderPane.tsx">
<violation number="1" location="apps/antalmanac/src/components/RightPane/CoursePane/CourseRenderPane/CourseRenderPane.tsx:93">
P2: `unofferedCourseIds` is mutated inside async `queryFn`, which can leave stale/mismatched warning alerts after failed or out-of-order requests.</violation>
</file>
<file name="apps/antalmanac/src/components/RightPane/CoursePane/SearchForm/QuickSearch/RoadmapPill.tsx">
<violation number="1" location="apps/antalmanac/src/components/RightPane/CoursePane/SearchForm/QuickSearch/RoadmapPill.tsx:17">
P3: New TODO comment is anonymous; add an owner handle to match repository TODO conventions.
(Based on your team's feedback about naming TODO owners.) [FEEDBACK_USED].</violation>
<violation number="2" location="apps/antalmanac/src/components/RightPane/CoursePane/SearchForm/QuickSearch/RoadmapPill.tsx:383">
P2: Dropdown visibility is tied to searchable roadmaps only, which hides the roadmap menu when there is one valid roadmap plus additional non-searchable roadmaps.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
|
|
||
| // TODO: Restore sessionIsValid-only gate before merging (drop usingMockRoadmaps bypass). | ||
| const showPill = isSignedIn && !isPlannerLoading && roadmapsForTerm.length > 0; | ||
| const showMenu = roadmapsForTerm.length > 1; |
There was a problem hiding this comment.
P2: Dropdown visibility is tied to searchable roadmaps only, which hides the roadmap menu when there is one valid roadmap plus additional non-searchable roadmaps.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/antalmanac/src/components/RightPane/CoursePane/SearchForm/QuickSearch/RoadmapPill.tsx, line 383:
<comment>Dropdown visibility is tied to searchable roadmaps only, which hides the roadmap menu when there is one valid roadmap plus additional non-searchable roadmaps.</comment>
<file context>
@@ -1,211 +1,486 @@
+
+ // TODO: Restore sessionIsValid-only gate before merging (drop usingMockRoadmaps bypass).
+ const showPill = isSignedIn && !isPlannerLoading && roadmapsForTerm.length > 0;
+ const showMenu = roadmapsForTerm.length > 1;
+
+ useEffect(() => {
</file context>
| const showMenu = roadmapsForTerm.length > 1; | |
| const showMenu = sortedRoadmaps.length > 1; |
|
Looking pretty good so far
|
|
|
/deploy |
Summary
Migrate "Search with Roadmap" from a dedicated autocomplete input to shortcut pills below the quick search input.
Chunk 1 — Schema & Backend:
courseIdfield toWebsocSearchInputSchema, matching the Anteater API's existing support for querying WebSOC by course ID directlygetManyOfField'sfieldNameenum to accept'courseId'in addition to'ge', enabling unified fan-out queriesChunk 2 — URL State & Query Logic:
courseIdsas a nuqs array param insidecourseSearchParamParsersas an advanced search param (not UI-exposed, likeexcludeRoadmapCourses)CourseRenderPanequery logic:formData.courseIds.length > 0takes priority →getManyOfFieldwithfieldName: 'courseId'→unionWebsocResponsesRightPaneStore.tsentirely —multiSearchDatais fully replaced by the URL paramisValidSearchandshouldShowSearchFormto acceptcourseIdsqueryKeys— courseIds included in formData serialization automaticallyChunk 4 — RoadmapPill Component:
RoadmapPillsplit-button: left = search with active roadmap's courses, right = dropdown to pick a different roadmapGrowtransitionChunk 5 — Layout:
SearchWithPlannerautocomplete + "or" divider inQuickSearchwith pill row belowFuzzySearchSearchWithPlanner.tsx(242 lines removed)Chunk 6 — Cleanup:
COURSE_SEARCH_PLANNER_KEY,plannerSearchParser,shouldSearchPlannerFromParams()useCourseSearchMode— no longer gated on planner paramScheduleManagementtab detection useshasAdvancedParams(coverscourseIds)filterTakenCoursesWarningAlert fromCourseRenderPaneTest Plan
tsc --noEmitpasses (only pre-existing errors from missing generated data files)oxlint --deny-warningspasses (0 warnings, 0 errors)vitest run— all 34 tests pass; 4 test suites fail due to pre-existing missingtermData.jsonIssues
Closes #1815