Skip to content

Conversation

gumaerc
Copy link
Contributor

@gumaerc gumaerc commented Sep 19, 2025

What are the relevant tickets?

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

Description (What does it do?)

This PR fixes a bug with the ordering of courses within programs and program collections. The courses API endpoint in mitxonline does not respect the order that you pass ID's in when making a query for the detail of multiple courses. The courses end up being ordered alphabetically in a non-lexicographical manner. This PR does re-ordering on the frontend of the results so that the order matches the order of the ID's in the courses array on the program API response. The querying of the courses in a program collection has also been optimized to only use one query for all the first courses in each program in the collection, rather than making one query per collection.

How can this be tested?

In order to test this, you need a basic installation of mitxonline up and running with example data in it. You may be able to skip one or more steps if you have already done them:

  • Ensure you have local hosts redirects for the following domains, replacing the example IP with your local IP address (Google how to get this if unsure, mine is 192.168.1.50)
192.168.1.50 open.odl.local
192.168.1.50 api.open.odl.local
192.168.1.50 kc.ol.local
192.168.1.50 mitxonline.odl.local
CELERY_TASK_ALWAYS_EAGER=True
DJANGO_LOG_LEVEL=INFO
LOG_LEVEL=INFO
SENTRY_LOG_LEVEL=ERROR
MAILGUN_KEY=fake
MAILGUN_URL=
MAILGUN_RECIPIENT_OVERRIDE=
MAILGUN_SENDER_DOMAIN=.odl.local
SECRET_KEY=
STATUS_TOKEN=
UWSGI_THREADS=5
SENTRY_DSN=
MITX_ONLINE_BASE_URL=http://open.odl.local:8065/mitxonline
MITX_ONLINE_ADMIN_CLIENT_ID=refine-local-client-id
MITX_ONLINE_ADMIN_BASE_URL=http://mitxonline.odl.local:8016
POSTHOG_PROJECT_API_KEY=
POSTHOG_API_HOST=https://app.posthog.com/
HUBSPOT_HOME_PAGE_FORM_GUID=
HUBSPOT_PORTAL_ID=
APISIX_PORT=9080

# APISIX/Keycloak settings
APISIX_LOGOUT_URL=http://api.open.odl.local:8065/logout/
APISIX_SESSION_SECRET_KEY=supertopsecret1234
KC_SPI_THEME_WELCOME_THEME=scim
KC_SPI_REALM_RESTAPI_EXTENSION_SCIM_LICENSE_KEY=
KEYCLOAK_BASE_URL=http://kc.ol.local:8066
KEYCLOAK_CLIENT_ID=apisix
# This is not a secret. This is for the Keycloak container, only for local use.
KEYCLOAK_CLIENT_SECRET=HckCZXToXfaetbBx0Fo3xbjnC468oMi4 # pragma: allowlist-secret
KEYCLOAK_DISCOVERY_URL=http://kc.ol.local:8066/realms/ol-local/.well-known/openid-configuration
KEYCLOAK_REALM_NAME=ol-local
KEYCLOAK_SCOPES="openid profile ol-profile"
KEYCLOAK_SVC_KEYSTORE_PASSWORD=supertopsecret1234
KEYCLOAK_SVC_HOSTNAME=kc.ol.local
KEYCLOAK_SVC_ADMIN=admin
KEYCLOAK_SVC_ADMIN_PASSWORD=admin
AUTHORIZATION_URL=http://kc.ol.local:8066/realms/ol-local/protocol/openid-connect/auth
ACCESS_TOKEN_URL=http://kc.ol.local:8066/realms/ol-local/protocol/openid-connect/token
OIDC_ENDPOINT=http://kc.ol.local:8066/realms/ol-local
SOCIAL_AUTH_OL_OIDC_OIDC_ENDPOINT=http://kc.ol.local:8066/realms/ol-local
SOCIAL_AUTH_OL_OIDC_KEY=apisix
# This is not a secret. This is for the Keycloak container, only for local use.
SOCIAL_AUTH_OL_OIDC_SECRET=HckCZXToXfaetbBx0Fo3xbjnC468oMi4 # pragma: allowlist-secret
USERINFO_URL=http://kc.ol.local:8066/realms/ol-local/protocol/openid-connect/userinfo
MITOL_APIGATEWAY_DISABLE_MIDDLEWARE=False

FEATURE_IGNORE_EDX_FAILURES=True
OPENEDX_API_CLIENT_ID=fake
OPENEDX_API_CLIENT_SECRET=fake
OPENEDX_SERVICE_WORKER_API_TOKEN=fake

CSRF_COOKIE_DOMAIN=.odl.local
CORS_ALLOWED_ORIGINS=http://mitxonline.odl.local:8065, http://open.odl.local:8062, http://api.open.odl.local:8065
CSRF_TRUSTED_ORIGINS=http://mitxonline.odl.local:8065, http://open.odl.local:8062, http://api.open.odl.local:8065
  • Spin up mitxonline with docker compose up --build -d
  • Promote the admin user with docker compose exec web ./manage.py promote_user promote --superuser --email admin@odl.local
  • Populate test course data with docker compose exec web ./manage.py populate_course_data
  • Generate docs with pants docs ::
  • In dist/sphinx/index.html, read the section on generating a B2B organization / contract and create one, adding all 10 of the test courses
  • In Django admin, create a Program and add all of the courses to the program that are included in your B2B org, making sure to mark the program as "live"
  • Create a few more programs with 1 or 2 courses from the test courses
  • Navigate to Wagtail at http://mitxonline.odl.local:8065/cms
  • Browse to Home Page -> Program Collections
  • Create a new program collection
  • Add the extra programs you created above
  • Make sure you have a personal Posthog project configured and have the API key at the ready
  • Before we spin up mit-learn, we need to set some env variables:
.env
...
MITX_ONLINE_UPSTREAM=mitxonline.odl.local:8013
MITX_ONLINE_DOMAIN=mitxonline.odl.local
MITX_ONLINE_BASE_URL=http://mitxonline.odl.local:8065
POSTHOG_ENABLED=True
CSRF_COOKIE_DOMAIN=.odl.local

shared.local.env
POSTHOG_PROJECT_API_KEY=YOUR_API_KEY_HERE
POSTHOG_PROJECT_ID=YOUR_PROJECT_ID_HERE
POSTHOG_TIMEOUT_MS=1500
  • In your Posthog project, enable the enrollment-dashboard and mitlearn-organization-dashboard feature flags for all users
  • Spin up MIT Learn
  • Go to the org dashboard for the org you created
  • Ensure that Case 10 is displayed at the bottom of the list on the first program you created, and not at the top
  • Ensure that the first course for each program is displayed in the correct order in the program collection

… program, because the API does not respect this order
@gumaerc gumaerc added the Needs Review An open Pull Request that is ready for review label Sep 19, 2025
Copy link
Contributor

@ChristopherChudzicki ChristopherChudzicki left a comment

Choose a reason for hiding this comment

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

👍

Comment on lines +184 to +187
const rawCourses =
courses.data?.results.sort((a, b) => {
return firstCourseIds.indexOf(a.id) - firstCourseIds.indexOf(b.id)
}) ?? []
Copy link
Contributor

Choose a reason for hiding this comment

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

As far as I can tell, program collections have no ordering of the associated programs.

So if the UAI vertical modules on prod look correct, great, but I don't think that's guaranteed by anything, is it?

I.e., there's (currently) no way in wagtail / mitxonline admin to set the order of these programs, is there?

Screenshot 2025-09-19 at 1 09 02 PM

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 a good point. I suppose it would preserve whatever ordering is passed back from the API though, nonetheless.

Comment on lines 134 to 136
queries: programIds.map((programId) => ({
...programsQueries.programsList({ id: programId, org_id: orgId }),
queryKey: [
...programsQueries.programsList({ id: programId, org_id: orgId })
.queryKey,
],
})),
Copy link
Contributor

Choose a reason for hiding this comment

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

This can just be

    queries: programIds.map((programId) =>
      programsQueries.programsList({ id: programId, org_id: orgId }),
    )

useProgramCollectionCourses(collection.programIds, orgId)
const firstCourseIds = programsWithCourses
.map((p) => p?.program.courseIds[0])
.filter((id): id is number => id !== undefined)
Copy link
Contributor

Choose a reason for hiding this comment

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

This is another example of something TS ^5.5 will catch automatically, no need for the id is number part.

Inferred Type Predicates

@gumaerc gumaerc merged commit 415b0d5 into main Sep 19, 2025
13 checks passed
@gumaerc gumaerc deleted the cg/fix-program-ordering-again branch September 19, 2025 18:52
@odlbot odlbot mentioned this pull request Sep 19, 2025
7 tasks
rhysyngsun pushed a commit that referenced this pull request Sep 19, 2025
…collections (#2523)

* Sort program / program collection courses by the order of id's on the program, because the API does not respect this order

* remove unnecessary spread

* remove unnecessary expansion
rhysyngsun pushed a commit that referenced this pull request Sep 19, 2025
…collections (#2523)

* Sort program / program collection courses by the order of id's on the program, because the API does not respect this order

* remove unnecessary spread

* remove unnecessary expansion
rhysyngsun pushed a commit that referenced this pull request Sep 22, 2025
…collections (#2523)

* Sort program / program collection courses by the order of id's on the program, because the API does not respect this order

* remove unnecessary spread

* remove unnecessary expansion
@odlbot odlbot mentioned this pull request Sep 22, 2025
5 tasks
shanbady added a commit that referenced this pull request Sep 23, 2025
* Release 0.43.1

* Release date for 0.43.1

* canvas: citation urls for html content (#2521)

* updates to support urls for non-file items

* adding canvas type

* working urls for assignments and pages

* adding title to contentfile and test for urls

* update test

* titles for embedded pages

* fix non-lexicographical ordering in org dashboard programs / program collections (#2523)

* Sort program / program collection courses by the order of id's on the program, because the API does not respect this order

* remove unnecessary spread

* remove unnecessary expansion

* removing special cased sloan page scraper

---------

Co-authored-by: Doof <mitx-devops@mit.edu>
Co-authored-by: Carey P Gumaer <gumaerc@mit.edu>
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.

2 participants