Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions RELEASE.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
Release Notes
=============

Version 0.179.1
---------------

- chore(deps): update dependency js-yaml to v4 (#3238)
- fix: mobile nav update (#3490)
- fix(deps): update dependency mitol-django-olposthog to v2025 (#3506)
- fix(deps): update dependency django-redis to v5.4.0 (#3511)
- fix(deps): update dependency mitol-django-common to v2025 (#3488)
- fix(deps): update dependency django-ipware to v7 (#3515)
- fix(deps): update dependency jsdom to v26 (#3456)

Version 0.179.0 (Released June 02, 2025)
---------------

Expand Down
2 changes: 1 addition & 1 deletion mitxpro/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from mitxpro.celery_utils import OffsettingSchedule
from mitxpro.sentry import init_sentry

VERSION = "0.179.0"
VERSION = "0.179.1"

env.reset()

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"hls.js": "^1.0.0",
"isomorphic-fetch": "^2.2.1",
"jquery": "^3.5.1",
"jsdom": "^16.2.2",
"jsdom": "^26.0.0",
"lodash": "^4.17.21",
"mini-css-extract-plugin": "^0.12.0",
"minimist": "^1.2.6",
Expand Down Expand Up @@ -144,7 +144,7 @@
},
"resolutions": {
"cheerio": "1.0.0-rc.12",
"js-yaml": "^3.13.1",
"js-yaml": "^4.0.0",
"kind-of": "6.0.3",
"minimist": "1.2.8",
"merge": "^2.1.1",
Expand Down
66 changes: 45 additions & 21 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ django = "4.2.21"
django-anymail = { version = "13.0", extras = ["mailgun"] }
django-filter = "^23.4"
django-hijack = "3.7.2"
django-ipware = "3.0.7"
django-ipware = "7.0.1"
django-oauth-toolkit = "1.7.1"
django-redis = "5.0.0"
django-redis = "5.4.0"
django-robots = "6.1"
django-silk = "^5.0.3"
django-storages = "1.14.6"
Expand All @@ -37,12 +37,12 @@ google-auth = "1.35.0"
hubspot-api-client = "^6.1.0"
ipython = "^9.0.0"
mitol-django-authentication = "2023.12.19"
mitol-django-common = "2023.12.19"
mitol-django-common = "2025.5.23"
mitol-django-digital-credentials = "2023.12.19"
mitol-django-hubspot-api = { version = "2023.12.19", extras = [] }
mitol-django-mail = "2025.3.17"
mitol-django-oauth-toolkit-extensions = "2023.12.19.1"
mitol-django-olposthog = "^2024.5.14"
mitol-django-olposthog = "^2025.0.0"
newrelic = "^8.4.0"
pdftotext = "^3.0.0"
psycopg2 = "2.9.10"
Expand Down
30 changes: 19 additions & 11 deletions static/js/babelhook.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,25 @@ function copyProps(src, target) {
});
}

global.window = window;
global.document = window.document;
// Proxy window.location assignments to use jsdom.reconfigure()
// instead of direct assignment, which is no longer allowed in v26
const windowProxy = new Proxy(window, {
set: function (target, prop, value) {
if (prop === "location") {
let url = value;
if (!url.startsWith("http")) {
url = `http://fake${url}`;
}
jsdom.reconfigure({ url });
return true;
}

return Reflect.set(target, prop, value);
},
});
Comment on lines +28 to +43

Choose a reason for hiding this comment

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

medium

This proxy for window.location is a good solution to handle the breaking change in jsdom v26 regarding direct assignment. It correctly intercepts assignments and uses jsdom.reconfigure.


global.window = windowProxy;
global.document = windowProxy.document;
global.navigator = {
userAgent: "node.js",
};
Expand All @@ -38,13 +55,4 @@ global.cancelAnimationFrame = function (id) {
};
copyProps(window, global);

Object.defineProperty(window, "location", {
set: (value) => {
if (!value.startsWith("http")) {
value = `http://fake${value}`;
}
jsdom.reconfigure({ url: value });
},
});

require("@babel/register")(babelSharedLoader.options);
63 changes: 42 additions & 21 deletions static/js/components/CatalogMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,49 @@ import type { CourseTopic } from "../flow/courseTypes";

type Props = {
courseTopics: Array<CourseTopic>,
isMobile?: boolean,
};

const CatalogMenu = ({ courseTopics }: Props) => {
const CatalogMenu = ({ courseTopics, isMobile = false }: Props) => {
const renderMenuItems = () => (
<>
<a
className={
isMobile ? "mobile-catalog-item all-topics" : "dropdown-item bold"
}
href="/catalog/"
aria-label="All Topics"
>
All Topics
</a>
{courseTopics?.map((courseTopic, index) => (
<a
className={isMobile ? "mobile-catalog-item" : "dropdown-item"}
key={index}
href={`/catalog/?topic=${encodeURIComponent(courseTopic.name)}`}
aria-label={courseTopic.name}
>
{courseTopic.name} ({courseTopic.course_count || 0})
</a>
))}
</>
);

if (isMobile) {
return (
<div className="mobile-drawer-section">
<a
className="mobile-drawer-heading"
href="/catalog/"
aria-label="Courses"
>
Courses
</a>
<div className="mobile-catalog-menu">{renderMenuItems()}</div>
</div>
);
}
Comment on lines +12 to +50

Choose a reason for hiding this comment

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

medium

Refactoring the menu item rendering into a separate function renderMenuItems is a good approach to avoid code duplication between the mobile and desktop views. The conditional rendering based on the isMobile prop is clear.


return (
<div className="catalog-menu dropdown">
<a
Expand All @@ -20,7 +60,6 @@ const CatalogMenu = ({ courseTopics }: Props) => {
aria-label="courses"
href="#"
role="button"
data-bs-toggle="dropdown"
onKeyDown={(e) => {
if (e.key === " ") {
e.preventDefault();
Expand All @@ -31,25 +70,7 @@ const CatalogMenu = ({ courseTopics }: Props) => {
Courses
</a>
<ul className="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a
className="dropdown-item bold"
href="/catalog/"
aria-label="All Topics"
>
All Topics
</a>
{courseTopics
? courseTopics.map((courseTopic, index) => (
<a
className="dropdown-item"
key={index}
href={`/catalog/?topic=${encodeURIComponent(courseTopic.name)}`}
aria-label={courseTopic.name}
>
{courseTopic.name} ({courseTopic.course_count})
</a>
))
: null}
{renderMenuItems()}
<div className="dropdown-divider" />
<a
className="dropdown-item bold"
Expand Down
36 changes: 36 additions & 0 deletions static/js/components/CatalogMenu_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,40 @@ describe("CatalogMenu component", () => {
"/catalog/?active-tab=programs-tab",
);
});

describe("when isMobile is true", () => {
it("renders mobile-drawer-section instead of dropdown", () => {
const wrapper = shallow(
<CatalogMenu courseTopics={courseTopics} isMobile={true} />,
);

assert.isTrue(wrapper.find(".mobile-drawer-section").exists());
assert.isFalse(wrapper.find(".catalog-menu.dropdown").exists());
});

it("renders course topics with mobile-specific classes", () => {
const wrapper = shallow(
<CatalogMenu courseTopics={courseTopics} isMobile={true} />,
);

const allTopicsLink = wrapper.find(".mobile-catalog-item.all-topics");
assert.isTrue(allTopicsLink.exists());
assert.equal(allTopicsLink.text(), "All Topics");

const topicLinks = wrapper
.find(".mobile-catalog-item")
.not(".all-topics");
assert.equal(topicLinks.length, courseTopics.length);
});

it("does not render dropdown elements when in mobile mode", () => {
const wrapper = shallow(
<CatalogMenu courseTopics={courseTopics} isMobile={true} />,
);

assert.isFalse(wrapper.find(".dropdown-toggle").exists());
assert.isFalse(wrapper.find(".dropdown-menu").exists());
assert.isFalse(wrapper.find(".dropdown-divider").exists());
});
});
});
Loading
Loading