Skip to content

Advertise parent programs on course product pages#3026

Closed
ChristopherChudzicki wants to merge 28 commits intomainfrom
cc/program-bundle-upsell-refined
Closed

Advertise parent programs on course product pages#3026
ChristopherChudzicki wants to merge 28 commits intomainfrom
cc/program-bundle-upsell-refined

Conversation

@ChristopherChudzicki
Copy link
Contributor

@ChristopherChudzicki ChristopherChudzicki commented Mar 9, 2026

What are the relevant tickets?

Closes https://github.com/mitodl/hq/issues/10434

Description (What does it do?)

Program Bundle Upsell: When a course belongs to one or more MITx programs, shows a "Best value" upsell below the course metadata with the program price, required course count, and a "View Program" link.

Unified HTML structure: The info box sidebar uses a single HTML structure with CSS-only responsive behavior instead of separate DOM trees per breakpoint.

InfoBox refactor: Introduced InfoBoxCourse and InfoBoxProgram wrapper components that own the full sidebar card composition (summary + enrollment button + upsell), with shared styled primitives in InfoBoxParts. ProductPageTemplate now takes a single infoBox prop instead of separate sidebar-related props.

Screenshots (if appropriate):

[!NOTE] |
Enrollment likely to be removed from mobile/tablet infobox, but will wait until it has been merged into banner.

desktop tablet mobile

How can this be tested?

Prerequisites:

Now:

  1. Navigate to a course that belongs to a program; if using Option 1, http://open.odl.local:8062/courses/course-v1:MITxT+14.100x is a good candidate. (Note: This course has no available runs, but still displays the program upsell correctly.)
    • Desktop: Sticky sidebar with metadata, enrollment button, bundle upsell ("Best value", course count, bold program title, price, "(19% off)", "View Program")
    • Tablet: Two-column metadata with column-rule divider, horizontal upsell (text left, button right), enrollment button
    • Mobile: Single-column metadata, centered upsell, enrollment button
  • Check a course that is not in any programs; it should have no program upsel.
  • Check no navigation links on course/program page
  • ⚠️ You may notice that the product image only shows on Desktop, not mobile/tablet. This will be resolved as part of https://github.com/mitodl/hq/issues/10435

Additional Context

  • Bundle discount "(19% off)" is a hardcoded value that matches our business pricing rules. Not ideal, but requested.

ChristopherChudzicki and others added 26 commits March 7, 2026 14:21
Reorder the sidebar card so the enroll button appears after the summary
info rows rather than before them, matching the Figma design.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the "Course is part of the following programs" info row with a
ProgramBundleUpsell component that fetches each parent program's details
and shows a bundle pricing card with a "View Program" link, ordered after
the enroll button.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…borders/padding

Replace three separate DOM structures (desktop/tablet/mobile) in the product page
info box with a single HTML structure using CSS grid for responsive layout. Fixes
program bundle upsell border on tablet by resetting bleed margins and adding direct
border; adjusts SummaryRoot padding per breakpoint; adds AskTIM placeholder button.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… AskTIM placeholder

- Split SummaryRoot into SummaryCard (border/shadow wrapper) and
  SummaryContent (padded metadata area) so the bundle upsell can span
  edge-to-edge without negative margins
- Delete unused ProductNavbar.tsx
- Add temporary AskTIM button placeholder using smoot-design Button
- Add TODO comment for hardcoded 1.2x strike price
- Add comment explaining per-program detail fetches

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…psell

- Remove grid-based tablet layout (RightCol, ActionsArea) from template
- Enrollment button desktop-only via DesktopEnrollArea; AskTIM outside card
- SummaryContent is now just a padding wrapper; gap/layout owned by SummaryRows
- SummaryRows: flex-column on desktop/mobile, column-count:2 on tablet
- Bundle upsell: row layout on tablet (text left, button right), skip if no price
- Add separator borders between multiple upsell items

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Sticky position on SummaryCol so AskTIM scrolls with the card
- align-self: flex-start required for sticky in flex parent
- Replace magic top offset with HEADER_HEIGHT constant
- Add column-rule divider between tablet metadata columns

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use avoidCents for bundle price formatting (whole dollars)
- Show required course count in upsell title ("Get all 5 ...")
- Bold program title, normal weight for rest of upsell text
- Replace strikethrough price with static "(19% off)" discount
- Replace "Want a program certificate?" with "Best value"
- Make AskTIM button full width, match Figma shadow opacity
- Adjust bundle spacing to match Figma (8px header gap, 24px item gap)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace DesktopEnrollArea (md-only) with EnrollArea (always visible)
- Tablet enrollment button: max-width 50%, center-aligned
- Update ProgramBundleUpsell tests for new copy ("Best value", course
  count, avoidCents price, "(19% off)") and add no-price test case

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ProgramBundleUpsell waits for all queries to load and filters to
  programs with prices before rendering, preventing an empty "Best
  value" header
- AskTIM button text uses productNoun prop ("course" or "program")
- enrollButton is now a required prop on ProductPageTemplate
- Remove console.log placeholder from AskTIM onClick
- Clean up BundleUpsellContainer border styles per breakpoint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use monthsFromNow() helper so tests don't rot as calendar time passes.
Past dates for "Anytime" logic use negative offsets; ordering tests use
spaced-out future offsets; display-only tests let the factory decide.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ises

Add test verifying the upsell renders nothing when the program detail
fetch fails. Use Promise.withResolvers() to control mock response timing
in both no-price and error tests, replacing the fragile
queryClient.isFetching() polling pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show structured skeleton placeholders (title, price, button) while
program details load, then render real content or unmount if no priced
programs. Tests now verify the full loading→removed lifecycle using
waitForElementToBeRemoved and use distinct prices for multi-program
assertions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace sidebarSummary, enrollButton, programUpsell, summaryTitle, and
productNoun props with a single infoBox prop. CoursePage uses
CourseInfoBox, ProgramPage uses ProgramInfoBox.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rather than silently returning null when all program detail fetches
fail, log a console.warn to aid debugging. Add allowConsoleErrors()
to the error-state test to accommodate jest-fail-on-console.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename CourseInfoBox → InfoBoxCourse, ProgramInfoBox → InfoBoxProgram
for alphabetical grouping with InfoBoxParts. Extract shared styled
components (now InfoBoxCard, InfoBoxContent, InfoBoxEnrollArea,
AskTimButton) into InfoBoxParts so InfoBoxProgram no longer depends
on InfoBoxCourse for shared primitives.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move ProgramBundleUpsell component and all its styled components out
of ProductSummary.tsx into ProgramBundleUpsell.tsx, with tests moved
to ProgramBundleUpsell.test.tsx.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove dedicated InfoBoxCourse and InfoBoxProgram test files — their
coverage is better placed at the page level. Rename section headings
to "Course Information" / "Program Information". Add a CoursePage
test asserting the program bundle upsell renders when the course
belongs to a program.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove redundant fragment wrappers in InfoBoxCourse and InfoBoxProgram
- Use V2ProgramDetail instead of V2Program for RequirementsSection prop type
- Remove no-op `& {}` intersection on CourseCertificateBox
- Clarify bundle upsell smoke test name in CoursePage.test
- Fix misleading `courses` variable name in ProgramPage 404 test
- Batch program detail fetches into single programsList query

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ChristopherChudzicki ChristopherChudzicki added the Needs Review An open Pull Request that is ready for review label Mar 9, 2026
@ChristopherChudzicki ChristopherChudzicki marked this pull request as ready for review March 9, 2026 03:12
ChristopherChudzicki and others added 2 commits March 9, 2026 10:48
On tablet, use flex + justify-end instead of centering the enrollment
button. Also remove unnecessary width: 100% and WideButtonLink wrapper
from enrollment button components.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove "Best value" header, use h5 bold for full title line, and
regroup price + button into BundleUpsellActions so price sits above
the button on tablet (single HTML structure, CSS-only responsive).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link

github-actions bot commented Mar 9, 2026

OpenAPI Changes

Show/hide 175 changes: 53 error, 72 warning, 50 info
175 changes: 53 error, 72 warning, 50 info
error	[response-property-became-optional] at head/openapi/specs/v0.yaml	
	in API GET /api/v0/vector_learning_resources_search/
		the response property 'results/items/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v0.yaml	
	in API GET /api/v0/vector_learning_resources_search/
		the response property 'results/items/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/featured/
		the response property 'results/items/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/featured/
		the response property 'results/items/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/featured/{id}/
		the response property '/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/featured/{id}/
		the response property '/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/
		the response property 'results/items/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/
		the response property 'results/items/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/
		the response property '/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/
		the response property '/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learning_resources/{id}/learning_paths/
		the response property '/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learning_resources/{id}/learning_paths/
		the response property '/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/similar/
		the response property '/items/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/similar/
		the response property '/items/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learning_resources/{id}/userlists/
		the response property '/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learning_resources/{id}/userlists/
		the response property '/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/vector_similar/
		the response property '/items/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/vector_similar/
		the response property '/items/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{learning_resource_id}/items/
		the response property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{learning_resource_id}/items/
		the response property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{learning_resource_id}/items/{id}/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{learning_resource_id}/items/{id}/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources_search/
		the response property 'results/items/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources_search/
		the response property 'results/items/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[request-property-enum-value-removed] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learning_resources_user_subscription/subscribe/
		removed the enum value 'resource_category' of the request property 'aggregations/items/' (media type: application/json)

error	[request-property-enum-value-removed] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learning_resources_user_subscription/subscribe/
		removed the enum value 'resource_category' of the request property 'aggregations/items/' (media type: application/x-www-form-urlencoded)

error	[request-property-enum-value-removed] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learning_resources_user_subscription/subscribe/
		removed the enum value 'resource_category' of the request property 'aggregations/items/' (media type: multipart/form-data)

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learningpaths/{learning_resource_id}/items/
		the response property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learningpaths/{learning_resource_id}/items/
		the response property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learningpaths/{learning_resource_id}/items/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '201'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learningpaths/{learning_resource_id}/items/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '201'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learningpaths/{learning_resource_id}/items/{id}/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learningpaths/{learning_resource_id}/items/{id}/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learningpaths/{learning_resource_id}/items/{id}/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learningpaths/{learning_resource_id}/items/{id}/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/podcasts/{learning_resource_id}/items/
		the response property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/podcasts/{learning_resource_id}/items/
		the response property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/podcasts/{learning_resource_id}/items/{id}/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/podcasts/{learning_resource_id}/items/{id}/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/userlists/{userlist_id}/items/
		the response property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/userlists/{userlist_id}/items/
		the response property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/userlists/{userlist_id}/items/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '201'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/userlists/{userlist_id}/items/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '201'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/userlists/{userlist_id}/items/{id}/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/userlists/{userlist_id}/items/{id}/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/userlists/{userlist_id}/items/{id}/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/userlists/{userlist_id}/items/{id}/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/video_playlists/{learning_resource_id}/items/
		the response property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/video_playlists/{learning_resource_id}/items/
		the response property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/video_playlists/{learning_resource_id}/items/{id}/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/video_playlists/{learning_resource_id}/items/{id}/
		the response property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/videos/
		the response property 'results/items/description' became optional for the status '200'

error	[response-property-became-optional] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/videos/{id}/
		the response property 'description' became optional for the status '200'

warning	[response-optional-property-removed] at head/openapi/specs/v0.yaml	
	in API GET /api/v0/vector_content_files_search/
		removed the optional property 'results/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v0.yaml	
	in API GET /api/v0/vector_learning_resources_search/
		removed the optional property 'results/items/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v0.yaml	
	in API GET /api/v0/vector_learning_resources_search/
		removed the optional property 'results/items/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/content_file_search/
		removed the optional property 'results/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/contentfiles/
		removed the optional property 'results/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/contentfiles/{id}/
		removed the optional property 'direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/courses/{learning_resource_id}/contentfiles/
		removed the optional property 'results/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/courses/{learning_resource_id}/contentfiles/{id}/
		removed the optional property 'direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/featured/
		removed the optional property 'results/items/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/featured/
		removed the optional property 'results/items/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/featured/{id}/
		removed the optional property '/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/featured/{id}/
		removed the optional property '/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/
		removed the optional property 'results/items/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/
		removed the optional property 'results/items/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/
		removed the optional property '/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/
		removed the optional property '/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learning_resources/{id}/learning_paths/
		removed the optional property '/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learning_resources/{id}/learning_paths/
		removed the optional property '/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/similar/
		removed the optional property '/items/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/similar/
		removed the optional property '/items/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learning_resources/{id}/userlists/
		removed the optional property '/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learning_resources/{id}/userlists/
		removed the optional property '/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/vector_similar/
		removed the optional property '/items/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/vector_similar/
		removed the optional property '/items/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{learning_resource_id}/contentfiles/
		removed the optional property 'results/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{learning_resource_id}/contentfiles/{id}/
		removed the optional property 'direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{learning_resource_id}/items/
		removed the optional property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{learning_resource_id}/items/
		removed the optional property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{learning_resource_id}/items/{id}/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{learning_resource_id}/items/{id}/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[request-parameter-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources_search/
		deleted the 'query' request parameter 'resource_category'
		This is a warning because some apps may return an error when receiving a parameter that they do not expect. It is recommended to deprecate the parameter first.

warning	[request-parameter-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources_search/
		deleted the 'query' request parameter 'show_ocw_files'
		This is a warning because some apps may return an error when receiving a parameter that they do not expect. It is recommended to deprecate the parameter first.

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources_search/
		removed the optional property 'results/items/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources_search/
		removed the optional property 'results/items/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[request-parameter-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources_user_subscription/
		deleted the 'query' request parameter 'resource_category'
		This is a warning because some apps may return an error when receiving a parameter that they do not expect. It is recommended to deprecate the parameter first.

warning	[request-parameter-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources_user_subscription/
		deleted the 'query' request parameter 'show_ocw_files'
		This is a warning because some apps may return an error when receiving a parameter that they do not expect. It is recommended to deprecate the parameter first.

warning	[request-parameter-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources_user_subscription/check/
		deleted the 'query' request parameter 'resource_category'
		This is a warning because some apps may return an error when receiving a parameter that they do not expect. It is recommended to deprecate the parameter first.

warning	[request-parameter-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources_user_subscription/check/
		deleted the 'query' request parameter 'show_ocw_files'
		This is a warning because some apps may return an error when receiving a parameter that they do not expect. It is recommended to deprecate the parameter first.

warning	[request-parameter-removed] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learning_resources_user_subscription/subscribe/
		deleted the 'query' request parameter 'resource_category'
		This is a warning because some apps may return an error when receiving a parameter that they do not expect. It is recommended to deprecate the parameter first.

warning	[request-parameter-removed] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learning_resources_user_subscription/subscribe/
		deleted the 'query' request parameter 'show_ocw_files'
		This is a warning because some apps may return an error when receiving a parameter that they do not expect. It is recommended to deprecate the parameter first.

warning	[request-property-removed] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learning_resources_user_subscription/subscribe/
		removed the request property 'resource_category' (media type: application/json)

warning	[request-property-removed] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learning_resources_user_subscription/subscribe/
		removed the request property 'resource_category' (media type: multipart/form-data)

warning	[request-property-removed] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learning_resources_user_subscription/subscribe/
		removed the request property 'resource_category' (media type: application/x-www-form-urlencoded)

warning	[request-property-removed] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learning_resources_user_subscription/subscribe/
		removed the request property 'show_ocw_files' (media type: application/json)

warning	[request-property-removed] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learning_resources_user_subscription/subscribe/
		removed the request property 'show_ocw_files' (media type: application/x-www-form-urlencoded)

warning	[request-property-removed] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learning_resources_user_subscription/subscribe/
		removed the request property 'show_ocw_files' (media type: multipart/form-data)

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learningpaths/{learning_resource_id}/items/
		removed the optional property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learningpaths/{learning_resource_id}/items/
		removed the optional property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learningpaths/{learning_resource_id}/items/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '201' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learningpaths/{learning_resource_id}/items/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '201' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learningpaths/{learning_resource_id}/items/{id}/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learningpaths/{learning_resource_id}/items/{id}/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learningpaths/{learning_resource_id}/items/{id}/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learningpaths/{learning_resource_id}/items/{id}/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/podcasts/{learning_resource_id}/items/
		removed the optional property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/podcasts/{learning_resource_id}/items/
		removed the optional property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/podcasts/{learning_resource_id}/items/{id}/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/podcasts/{learning_resource_id}/items/{id}/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/userlists/{userlist_id}/items/
		removed the optional property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/userlists/{userlist_id}/items/
		removed the optional property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/userlists/{userlist_id}/items/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '201' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/userlists/{userlist_id}/items/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '201' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/userlists/{userlist_id}/items/{id}/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/userlists/{userlist_id}/items/{id}/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/userlists/{userlist_id}/items/{id}/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/userlists/{userlist_id}/items/{id}/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/video_playlists/{learning_resource_id}/items/
		removed the optional property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/video_playlists/{learning_resource_id}/items/
		removed the optional property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/video_playlists/{learning_resource_id}/items/{id}/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/video_playlists/{learning_resource_id}/items/{id}/
		removed the optional property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/videos/
		removed the optional property 'results/items/content_files/items/direct_learning_resource_id' from the response with the '200' status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/videos/{id}/
		removed the optional property 'content_files/items/direct_learning_resource_id' from the response with the '200' status

info	[response-required-property-became-not-read-only] at head/openapi/specs/v0.yaml	
	in API GET /api/v0/vector_learning_resources_search/
		the response required property 'results/items/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v0.yaml	
	in API GET /api/v0/vector_learning_resources_search/
		the response required property 'results/items/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/featured/
		the response required property 'results/items/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/featured/
		the response required property 'results/items/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/featured/{id}/
		the response required property '/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/featured/{id}/
		the response required property '/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/
		the response required property 'results/items/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/
		the response required property 'results/items/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/
		the response required property '/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/
		the response required property '/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learning_resources/{id}/learning_paths/
		the response required property '/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learning_resources/{id}/learning_paths/
		the response required property '/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/similar/
		the response required property '/items/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/similar/
		the response required property '/items/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learning_resources/{id}/userlists/
		the response required property '/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learning_resources/{id}/userlists/
		the response required property '/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/vector_similar/
		the response required property '/items/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{id}/vector_similar/
		the response required property '/items/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{learning_resource_id}/items/
		the response required property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{learning_resource_id}/items/
		the response required property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{learning_resource_id}/items/{id}/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources/{learning_resource_id}/items/{id}/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources_search/
		the response required property 'results/items/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learning_resources_search/
		the response required property 'results/items/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learningpaths/{learning_resource_id}/items/
		the response required property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learningpaths/{learning_resource_id}/items/
		the response required property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learningpaths/{learning_resource_id}/items/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '201'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/learningpaths/{learning_resource_id}/items/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '201'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learningpaths/{learning_resource_id}/items/{id}/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/learningpaths/{learning_resource_id}/items/{id}/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learningpaths/{learning_resource_id}/items/{id}/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/learningpaths/{learning_resource_id}/items/{id}/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/podcasts/{learning_resource_id}/items/
		the response required property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/podcasts/{learning_resource_id}/items/
		the response required property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/podcasts/{learning_resource_id}/items/{id}/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/podcasts/{learning_resource_id}/items/{id}/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/userlists/{userlist_id}/items/
		the response required property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/userlists/{userlist_id}/items/
		the response required property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/userlists/{userlist_id}/items/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '201'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API POST /api/v1/userlists/{userlist_id}/items/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '201'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/userlists/{userlist_id}/items/{id}/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/userlists/{userlist_id}/items/{id}/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/userlists/{userlist_id}/items/{id}/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API PATCH /api/v1/userlists/{userlist_id}/items/{id}/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/video_playlists/{learning_resource_id}/items/
		the response required property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/video_playlists/{learning_resource_id}/items/
		the response required property 'results/items/resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/video_playlists/{learning_resource_id}/items/{id}/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/DocumentResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/video_playlists/{learning_resource_id}/items/{id}/
		the response required property 'resource/allOf[#/components/schemas/LearningResource]/oneOf[#/components/schemas/VideoResource]/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/videos/
		the response required property 'results/items/description' became not read-only for the status '200'

info	[response-required-property-became-not-read-only] at head/openapi/specs/v1.yaml	
	in API GET /api/v1/videos/{id}/
		the response required property 'description' became not read-only for the status '200'


Unexpected changes? Ensure your branch is up-to-date with main (consider rebasing).

Comment on lines 251 to 258
</TopContainer>
</BannerBackground>
<BottomContainer>
{/*
* The summary section is rendered 3 times (desktop, tablet, mobile)
* with different layouts, but only one is visible at a time via CSS.
* A single visually-hidden heading serves all three.
*/}
<VisuallyHidden>
<h2 id={HeadingIds.Summary}>{summaryTitle}</h2>
</VisuallyHidden>
<SidebarCol showAbove="md">
<SummaryRoot as="section" aria-labelledby={HeadingIds.Summary}>
{enrollButton}
{sidebarSummary}
</SummaryRoot>
</SidebarCol>
<SummaryCol>{infoBox}</SummaryCol>
<MainCol>
{navbar}
<Show showBetween={["sm", "md"]}>
<SummaryRoot as="section" aria-labelledby={HeadingIds.Summary}>
{sidebarSummary}
<Stack gap="16px">
<SidebarMedia
videoUrl={videoUrl}
imageSrc={imageSrc}
title={title}
/>
{enrollButton}
</Stack>
</SummaryRoot>
</Show>
<SidebarCol showBelow="sm" alignSelf="center">
<SummaryRoot as="section" aria-labelledby={HeadingIds.Summary}>
<SidebarMedia
videoUrl={videoUrl}
imageSrc={imageSrc}
title={title}
/>
{enrollButton}
{sidebarSummary}
</SummaryRoot>
</SidebarCol>
<SectionsWrapper>{children}</SectionsWrapper>
</MainCol>
</BottomContainer>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The refactored ProductPageTemplate no longer renders the SidebarMedia component on tablet and mobile breakpoints, causing the product video or image to be missing on smaller screens.
Severity: HIGH

Suggested Fix

Re-introduce the rendering of the SidebarMedia component for tablet and mobile breakpoints. This can be achieved by adding back the conditional rendering blocks for these screen sizes, such as using <Show showBetween={["sm", "md"]}> and <SidebarCol showBelow="sm"> to wrap the <SidebarMedia /> component.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: frontends/main/src/app-pages/ProductPages/ProductPageTemplate.tsx#L251-L258

Potential issue: The `SidebarMedia` component, which displays a product's video or
image, is now only rendered on desktop views (`showAbove="md"`). The refactoring removed
the rendering logic for tablet (`showBetween=["sm", "md"]`) and mobile
(`showBelow="sm"`) breakpoints. As a result, the product's associated video or image
will be missing on tablet and mobile devices. This is a functional regression, as the
media was previously displayed across all breakpoints.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is true. The media (image/video) no longer renders on mobile/tablet.

This will be resolved in

@ChristopherChudzicki
Copy link
Contributor Author

Closing in favor of #3029 because github has been "processing updates" for an hour, but a new branch got the updates right away 🤷

Screenshot 2026-03-09 at 12 19 27 PM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs Review An open Pull Request that is ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant