From 93a5907ea39420b5165a24af38c247f82ca435cf Mon Sep 17 00:00:00 2001 From: Matt Bertrand Date: Tue, 28 Oct 2025 12:18:44 -0400 Subject: [PATCH 1/6] Don't publish Professional Ed resources with blank run ids (#2637) --- learning_resources/etl/mitpe.py | 17 +++++++----- learning_resources/etl/mitpe_test.py | 39 +++++++++++++++++++--------- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/learning_resources/etl/mitpe.py b/learning_resources/etl/mitpe.py index c25911a1f3..a604fb6ebf 100644 --- a/learning_resources/etl/mitpe.py +++ b/learning_resources/etl/mitpe.py @@ -233,10 +233,13 @@ def _transform_runs(resource_data: dict) -> list[dict]: duration = parse_resource_duration(resource_data.get("duration")) published_runs = [] for run_data in runs_data: + run_id = run_data[0] start = parse_date(run_data[1]) end = parse_date(run_data[2]) enrollment_end = parse_date(run_data[3]) - published = (not end and not enrollment_end) or (now <= (enrollment_end or end)) + published = run_id and ( + (not end and not enrollment_end) or (now <= (enrollment_end or end)) + ) if published: published_runs.append( { @@ -283,8 +286,8 @@ def transform_course(resource_data: dict) -> dict or None: Returns: dict: transformed course data if it has any viable runs """ - runs = _transform_runs(resource_data) - if runs: + published_runs = _transform_runs(resource_data) + if published_runs: return { "readable_id": resource_data["uuid"], "offered_by": copy.deepcopy(OFFERED_BY), @@ -303,7 +306,7 @@ def transform_course(resource_data: dict) -> dict or None: "delivery": transform_delivery(resource_data["learning_format"]), "published": True, "topics": parse_topics(resource_data), - "runs": runs, + "runs": published_runs, "format": [Format.asynchronous.name], "pace": [Pace.instructor_paced.name], "availability": Availability.dated.name, @@ -321,8 +324,8 @@ def transform_program(resource_data: dict) -> dict or None: Returns: dict: transformed program data """ - runs = _transform_runs(resource_data) - if runs: + published_runs = _transform_runs(resource_data) + if published_runs: return { "readable_id": resource_data["uuid"], "offered_by": copy.deepcopy(OFFERED_BY), @@ -343,7 +346,7 @@ def transform_program(resource_data: dict) -> dict or None: "delivery": transform_delivery(resource_data["learning_format"]), "published": True, "topics": parse_topics(resource_data), - "runs": runs, + "runs": published_runs, "format": [Format.asynchronous.name], "pace": [Pace.instructor_paced.name], "availability": Availability.dated.name, diff --git a/learning_resources/etl/mitpe_test.py b/learning_resources/etl/mitpe_test.py index b36322d0c3..6978f3df0b 100644 --- a/learning_resources/etl/mitpe_test.py +++ b/learning_resources/etl/mitpe_test.py @@ -193,6 +193,22 @@ def read_json(file_path): ) +@pytest.fixture +def mitpe_offeror_and_topics(mocker): + """Create the MIT Professional Education offeror and 2 topics""" + offeror = LearningResourceOfferorFactory.create(code="mitpe") + LearningResourceTopicMappingFactory.create( + offeror=offeror, + topic=LearningResourceTopicFactory.create(name="Product Innovation"), + topic_name="Technology Innovation", + ) + LearningResourceTopicMappingFactory.create( + offeror=offeror, + topic=LearningResourceTopicFactory.create(name="Data Science"), + topic_name="Data Science", + ) + + @pytest.mark.parametrize("prof_ed_api_url", ["http://pro_edd_api.com", None]) def test_extract(settings, mock_fetch_data, prof_ed_api_url): """Test extract function""" @@ -213,19 +229,8 @@ def test_extract(settings, mock_fetch_data, prof_ed_api_url): @pytest.mark.django_db -def test_transform(mock_fetch_data): +def test_transform(mock_fetch_data, mitpe_offeror_and_topics): """Test transform function, and effectively most other functions""" - offeror = LearningResourceOfferorFactory.create(code="mitpe") - LearningResourceTopicMappingFactory.create( - offeror=offeror, - topic=LearningResourceTopicFactory.create(name="Product Innovation"), - topic_name="Technology Innovation", - ) - LearningResourceTopicMappingFactory.create( - offeror=offeror, - topic=LearningResourceTopicFactory.create(name="Data Science"), - topic_name="Data Science", - ) extracted = mitpe.extract() assert len(extracted) == 3 courses, programs = mitpe.transform(extracted) @@ -233,3 +238,13 @@ def test_transform(mock_fetch_data): sorted(courses, key=lambda course: course["readable_id"]), EXPECTED_COURSES ) assert_json_equal(programs, EXPECTED_PROGRAMS) + + +@pytest.mark.django_db +def test_transform__course_no_run_ids(mock_fetch_data, mitpe_offeror_and_topics): + """Resources with no run IDs should not be published""" + extracted = mitpe.extract() + assert len(extracted) == 3 + for resource in extracted: + resource["run__readable_id"] = "" + assert mitpe.transform(extracted) == ([], []) From ad2300082b7a9d8dd5d910e272d0db3da56de1c1 Mon Sep 17 00:00:00 2001 From: Chris Chudzicki Date: Tue, 28 Oct 2025 14:21:30 -0400 Subject: [PATCH 2/6] Fix a BannerPage background issue (#2651) * do not double up on url(...) * turn off image opt locally by default --- env/frontend.env | 2 +- .../ol-components/src/components/Banner/Banner.tsx | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/env/frontend.env b/env/frontend.env index 635d73a377..58ae74be6d 100644 --- a/env/frontend.env +++ b/env/frontend.env @@ -1,7 +1,7 @@ NODE_ENV=development PORT=8062 SENTRY_ENV=dev # Re-enable sentry -NEXT_PUBLIC_OPTIMIZE_IMAGES="true" +NEXT_PUBLIC_OPTIMIZE_IMAGES="false" # Environment variables with `NEXT_PUBLIC_` prefix are exposed to the client side NEXT_PUBLIC_ORIGIN=${MITOL_APP_BASE_URL} diff --git a/frontends/ol-components/src/components/Banner/Banner.tsx b/frontends/ol-components/src/components/Banner/Banner.tsx index 6fd84cae5d..559c00f1d7 100644 --- a/frontends/ol-components/src/components/Banner/Banner.tsx +++ b/frontends/ol-components/src/components/Banner/Banner.tsx @@ -11,11 +11,21 @@ const SubHeader = styled(Typography)({ }) type BannerBackgroundProps = { + /** + * Background image src, url(...), or image-set(...). + */ backgroundUrl?: string backgroundSize?: string backgroundDim?: number } +const standardizeBackgroundUrl = (url: string) => { + if (url.startsWith("url(") || url.startsWith("image-set(")) { + return url + } + return url.startsWith("image-set(") ? url : `url('${url}')` +} + /** * This is a full-width banner component that takes a background image URL. */ @@ -26,9 +36,7 @@ const BannerBackground = styled.div( backgroundSize = "cover", backgroundDim = 0, }) => { - const backgroundUrlFn = backgroundUrl.startsWith("image-set(") - ? backgroundUrl - : `url('${backgroundUrl}')` + const backgroundUrlFn = standardizeBackgroundUrl(backgroundUrl) return { backgroundAttachment: "fixed", From a304bcf5e23ab170e37e7af616d227bd429722e5 Mon Sep 17 00:00:00 2001 From: Carey P Gumaer Date: Tue, 28 Oct 2025 14:40:15 -0400 Subject: [PATCH 3/6] use next_start_date when available in learning resource drawer (#2619) * replace earliest start date with next_start_date from the base resource, if available * add some new tests to cover the usage of next_start_date * remove stray test code * only return null if there are no run dates and next_start_date is also unavailable --- .../InfoSection.test.tsx | 54 +++++++++++++++++++ .../LearningResourceExpanded/InfoSection.tsx | 15 +++++- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/frontends/main/src/page-components/LearningResourceExpanded/InfoSection.test.tsx b/frontends/main/src/page-components/LearningResourceExpanded/InfoSection.test.tsx index 06383cfc32..bf1c5645ed 100644 --- a/frontends/main/src/page-components/LearningResourceExpanded/InfoSection.test.tsx +++ b/frontends/main/src/page-components/LearningResourceExpanded/InfoSection.test.tsx @@ -115,6 +115,35 @@ describe("Learning resource info section start date", () => { within(section).getByText(runDate) }) + test("Uses next_start_date when available", () => { + const course = { + ...courses.free.dated, + next_start_date: "2024-03-15T00:00:00Z", + } + renderWithTheme() + + const section = screen.getByTestId("drawer-info-items") + within(section).getByText("Starts:") + within(section).getByText("March 15, 2024") + }) + + test("Falls back to run date when next_start_date is null", () => { + const course = { + ...courses.free.dated, + next_start_date: null, + } + const run = course.runs?.[0] + invariant(run) + const runDate = formatRunDate(run, false) + invariant(runDate) + renderWithTheme() + + const section = screen.getByTestId("drawer-info-items") + within(section).getByText("Starts:") + within(section).getByText(runDate) + expect(within(section).queryByText("March 15, 2024")).toBeNull() + }) + test("As taught in date(s)", () => { const course = courses.free.anytime const run = course.runs?.[0] @@ -151,6 +180,31 @@ describe("Learning resource info section start date", () => { }) }) + test("Multiple run dates with next_start_date uses next_start_date as first date", () => { + const course = { + ...courses.multipleRuns.sameData, + next_start_date: "2024-01-15T00:00:00Z", + } + const sortedDates = course.runs + ?.sort((a, b) => { + if (a?.start_date && b?.start_date) { + return Date.parse(a.start_date) - Date.parse(b.start_date) + } + return 0 + }) + .map((run) => formatRunDate(run, false)) + .filter((date) => date !== null) + + // First date should be next_start_date, second should be original second date + const expectedDateText = `January 15, 2024${SEPARATOR}${sortedDates?.[1]}Show more` + renderWithTheme() + + const section = screen.getByTestId("drawer-info-items") + within(section).getAllByText((_content, node) => { + return node?.textContent === expectedDateText || false + }) + }) + test("If data is different then dates, formats, locations and prices are not shown", () => { const course = courses.multipleRuns.differentData renderWithTheme() diff --git a/frontends/main/src/page-components/LearningResourceExpanded/InfoSection.tsx b/frontends/main/src/page-components/LearningResourceExpanded/InfoSection.tsx index 3b68e7badb..f07ab87a22 100644 --- a/frontends/main/src/page-components/LearningResourceExpanded/InfoSection.tsx +++ b/frontends/main/src/page-components/LearningResourceExpanded/InfoSection.tsx @@ -31,6 +31,7 @@ import { getLearningResourcePrices, showStartAnytime, NoSSR, + formatDate, } from "ol-utilities" import { theme, Link } from "ol-components" import DifferingRunsTable from "./DifferingRunsTable" @@ -179,7 +180,7 @@ const totalRunsWithDates = (resource: LearningResource) => { const RunDates: React.FC<{ resource: LearningResource }> = ({ resource }) => { const [showingMore, setShowingMore] = useState(false) - const sortedDates = resource.runs + let sortedDates = resource.runs ?.sort((a, b) => { if (a?.start_date && b?.start_date) { return Date.parse(a.start_date) - Date.parse(b.start_date) @@ -188,6 +189,18 @@ const RunDates: React.FC<{ resource: LearningResource }> = ({ resource }) => { }) .map((run) => formatRunDate(run, showStartAnytime(resource))) .filter((date) => date !== null) + + const nextStartDate = resource.next_start_date + ? formatDate(resource.next_start_date, "MMMM DD, YYYY") + : null + + if (sortedDates && nextStartDate) { + // Replace the first date with next_start_date + sortedDates = [nextStartDate, ...sortedDates.slice(1)] + } + if (!sortedDates || sortedDates.length === 0) { + return null + } const totalDates = sortedDates?.length || 0 const showMore = totalDates > 2 if (showMore) { From 34a8864df5df912fc9778f4b02e366c7dedbc894 Mon Sep 17 00:00:00 2001 From: Matt Bertrand Date: Tue, 28 Oct 2025 16:25:02 -0400 Subject: [PATCH 4/6] Avoid double slashes in paths (#2652) --- video_shorts/factories.py | 4 ++-- video_shorts/serializers.py | 4 +++- video_shorts/serializers_test.py | 19 +++++++++++-------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/video_shorts/factories.py b/video_shorts/factories.py index 4c0c415df7..eec04dc85f 100644 --- a/video_shorts/factories.py +++ b/video_shorts/factories.py @@ -20,12 +20,12 @@ class VideoShortFactory(DjangoModelFactory): datetime.now(tz=UTC), ) thumbnail_url = factory.LazyAttribute( - lambda obj: f"https://example.com/thumbnails/{obj.youtube_id}.jpg" + lambda obj: f"shorts/{obj.youtube_id}/{obj.youtube_id}.jpg" ) thumbnail_height = FuzzyInteger(360, 720) thumbnail_width = FuzzyInteger(480, 1280) video_url = factory.LazyAttribute( - lambda obj: f"https://example.com/videos/{obj.youtube_id}.mp4" + lambda obj: f"shorts/{obj.youtube_id}/{obj.youtube_id}.mp4" ) class Meta: diff --git a/video_shorts/serializers.py b/video_shorts/serializers.py index 4b9713758b..a020924da0 100644 --- a/video_shorts/serializers.py +++ b/video_shorts/serializers.py @@ -1,5 +1,7 @@ """Serializers for video shorts""" +from urllib.parse import urljoin + from django.conf import settings from rest_framework import serializers @@ -46,7 +48,7 @@ def to_internal_value(self, data): ) # Use relative URLs so they work regardless of domain - base_path = f"/{settings.VIDEO_SHORTS_S3_PREFIX}/{youtube_id}/" + base_path = urljoin(f"/{settings.VIDEO_SHORTS_S3_PREFIX}/", f"{youtube_id}/") transformed_data = { "youtube_id": youtube_id, "title": snippet.get("title"), diff --git a/video_shorts/serializers_test.py b/video_shorts/serializers_test.py index 183d5c5352..6de5a5a28b 100644 --- a/video_shorts/serializers_test.py +++ b/video_shorts/serializers_test.py @@ -22,10 +22,10 @@ def test_video_short_serializer_read(): title="Test Video", description="Test description", published_at=datetime(2024, 1, 15, 12, 0, 0, tzinfo=UTC), - thumbnail_url="https://example.com/thumb.jpg", + thumbnail_url="/shorts/test_123/test_123.jpg", thumbnail_height=360, thumbnail_width=480, - video_url="https://example.com/video.mp4", + video_url="/shorts/test_123/test_123.mp4", ) serializer = VideoShortSerializer(video_short) @@ -41,10 +41,10 @@ def test_video_short_serializer_read(): "title": "Test Video", "description": "Test description", "published_at": "2024-01-15T12:00:00Z", - "thumbnail_url": "https://example.com/thumb.jpg", + "thumbnail_url": "/shorts/test_123/test_123.jpg", "thumbnail_height": 360, "thumbnail_width": 480, - "video_url": "https://example.com/video.mp4", + "video_url": "/shorts/test_123/test_123.mp4", }, ) @@ -56,10 +56,10 @@ def test_video_short_serializer_create(): "title": "Created Video", "description": "Created description", "published_at": "2024-01-15T12:00:00Z", - "thumbnail_url": "https://example.com/created_thumb.jpg", + "thumbnail_url": "/shorts/create_test/create_test.jpg", "thumbnail_height": 720, "thumbnail_width": 1280, - "video_url": "https://example.com/created_video.mp4", + "video_url": "/shorts/create_test/create_test.mp4", } serializer = VideoShortSerializer(data=data) @@ -120,9 +120,12 @@ def test_video_short_serializer_update(): assert_json_equal(result_data, data) -def test_youtube_metadata_serializer(settings, sample_youtube_metadata): +@pytest.mark.parametrize( + "prefix", ["youtube_shorts/", "youtube_shorts", "youtube_shorts//"] +) +def test_youtube_metadata_serializer(settings, sample_youtube_metadata, prefix): """Test YouTubeMetadataSerializer transforms YouTube API data correctly""" - settings.VIDEO_SHORTS_S3_PREFIX = "youtube_shorts" + settings.VIDEO_SHORTS_S3_PREFIX = prefix serializer = YouTubeMetadataSerializer(data=sample_youtube_metadata) assert serializer.is_valid() From 24ab6c03a8ac262dd2fb8026f6764447fd2e8c33 Mon Sep 17 00:00:00 2001 From: Carey P Gumaer Date: Tue, 28 Oct 2025 17:23:44 -0400 Subject: [PATCH 5/6] remove org dashboard feature flag (#2654) * remove organization dashboard feature flags and always display org dashboard related components * remove posthog mocking where applicable --- .../DashboardPage/DashboardLayout.test.tsx | 9 --------- .../DashboardPage/DashboardLayout.tsx | 18 ++++-------------- .../DashboardPage/HomeContent.test.tsx | 1 - .../app-pages/DashboardPage/HomeContent.tsx | 3 +-- .../DashboardPage/OrganizationContent.test.tsx | 7 ------- .../DashboardPage/OrganizationContent.tsx | 7 ------- frontends/main/src/common/feature_flags.ts | 1 - 7 files changed, 5 insertions(+), 41 deletions(-) diff --git a/frontends/main/src/app-pages/DashboardPage/DashboardLayout.test.tsx b/frontends/main/src/app-pages/DashboardPage/DashboardLayout.test.tsx index 13d4eccaf5..9b04084e3e 100644 --- a/frontends/main/src/app-pages/DashboardPage/DashboardLayout.test.tsx +++ b/frontends/main/src/app-pages/DashboardPage/DashboardLayout.test.tsx @@ -21,17 +21,11 @@ import { } from "@/common/urls" import { faker } from "@faker-js/faker/locale/en" import invariant from "tiny-invariant" -import { useFeatureFlagEnabled } from "posthog-js/react" import { OrganizationPage, ContractPage } from "@mitodl/mitxonline-api-axios/v2" jest.mock("posthog-js/react") -const mockedUseFeatureFlagEnabled = jest.mocked(useFeatureFlagEnabled) describe("DashboardLayout", () => { - beforeEach(() => { - mockedUseFeatureFlagEnabled.mockReturnValue(false) - }) - type SetupOptions = { initialUrl?: string organizations?: OrganizationPage[] @@ -68,9 +62,6 @@ describe("DashboardLayout", () => { }) test("Renders the expected tab links and labels", async () => { - // Enable organization dashboard feature flag for this test - mockedUseFeatureFlagEnabled.mockReturnValue(true) - const organizations = [ mitxOnlineFactories.organizations.organization({ slug: "org-test-org", diff --git a/frontends/main/src/app-pages/DashboardPage/DashboardLayout.tsx b/frontends/main/src/app-pages/DashboardPage/DashboardLayout.tsx index a105940280..c6a5ece287 100644 --- a/frontends/main/src/app-pages/DashboardPage/DashboardLayout.tsx +++ b/frontends/main/src/app-pages/DashboardPage/DashboardLayout.tsx @@ -36,8 +36,6 @@ import { import dynamic from "next/dynamic" import { MitxOnlineUser, mitxUserQueries } from "api/mitxonline-hooks/user" import { useUserMe } from "api/hooks/user" -import { useFeatureFlagEnabled } from "posthog-js/react" -import { FeatureFlags } from "@/common/feature_flags" import { contractQueries } from "api/mitxonline-hooks/contracts" import { useQuery } from "@tanstack/react-query" import { ContractPage } from "@mitodl/mitxonline-api-axios/v2" @@ -241,12 +239,11 @@ type TabData = { } } const getTabData = ( - orgsEnabled: boolean = false, user?: MitxOnlineUser, contracts?: ContractPage[], ): TabData[] => { const orgTabs = - orgsEnabled && user && contracts + user && contracts ? user?.b2b_organizations.map((org) => { const orgContracts = contracts?.filter( (contract) => contract.organization === org.id, @@ -317,7 +314,6 @@ const DashboardPage: React.FC<{ }> = ({ children }) => { const pathname = usePathname() const { isLoading: isLoadingUser, data: user } = useUserMe() - const orgsEnabled = useFeatureFlagEnabled(FeatureFlags.OrganizationDashboard) const { data: mitxOnlineUser, isLoading: isLoadingMitxOnlineUser } = useQuery( { ...mitxUserQueries.me(), @@ -330,15 +326,9 @@ const DashboardPage: React.FC<{ const tabData = useMemo( () => isLoadingMitxOnlineUser || isLoadingContracts - ? getTabData(orgsEnabled) - : getTabData(orgsEnabled, mitxOnlineUser, contracts), - [ - isLoadingMitxOnlineUser, - isLoadingContracts, - orgsEnabled, - mitxOnlineUser, - contracts, - ], + ? getTabData() + : getTabData(mitxOnlineUser, contracts), + [isLoadingMitxOnlineUser, isLoadingContracts, mitxOnlineUser, contracts], ) const tabValue = useMemo(() => { diff --git a/frontends/main/src/app-pages/DashboardPage/HomeContent.test.tsx b/frontends/main/src/app-pages/DashboardPage/HomeContent.test.tsx index d07267c2c1..a81e290173 100644 --- a/frontends/main/src/app-pages/DashboardPage/HomeContent.test.tsx +++ b/frontends/main/src/app-pages/DashboardPage/HomeContent.test.tsx @@ -210,7 +210,6 @@ describe("HomeContent", () => { setupAPIs() mockedUseFeatureFlagEnabled.mockImplementation((flag) => { if (flag === "enrollment-dashboard") return enrollmentsEnabled - if (flag === "mitlearn-organization-dashboard") return false // Disable org cards to avoid image issues return false }) diff --git a/frontends/main/src/app-pages/DashboardPage/HomeContent.tsx b/frontends/main/src/app-pages/DashboardPage/HomeContent.tsx index 85bbaa09aa..377d1eb7e9 100644 --- a/frontends/main/src/app-pages/DashboardPage/HomeContent.tsx +++ b/frontends/main/src/app-pages/DashboardPage/HomeContent.tsx @@ -70,7 +70,6 @@ const HomeContent: React.FC = () => { const { isLoading: isLoadingProfile, data: user } = useUserMe() const topics = user?.profile?.preference_search_filters.topic const certification = user?.profile?.preference_search_filters.certification - const showOrgs = useFeatureFlagEnabled(FeatureFlags.OrganizationDashboard) const showEnrollments = useFeatureFlagEnabled( FeatureFlags.EnrollmentDashboard, ) @@ -89,7 +88,7 @@ const HomeContent: React.FC = () => { - {showOrgs ? : null} + {showEnrollments ? : null} false) - describe("OrganizationContent", () => { beforeEach(() => { - mockedUseFeatureFlagEnabled.mockReturnValue(true) setMockResponse.get(urls.enrollment.enrollmentsList(), []) setMockResponse.get(urls.enrollment.enrollmentsListV2(), []) setMockResponse.get(urls.programEnrollments.enrollmentsList(), []) diff --git a/frontends/main/src/app-pages/DashboardPage/OrganizationContent.tsx b/frontends/main/src/app-pages/DashboardPage/OrganizationContent.tsx index 2653118675..2c5d649d7c 100644 --- a/frontends/main/src/app-pages/DashboardPage/OrganizationContent.tsx +++ b/frontends/main/src/app-pages/DashboardPage/OrganizationContent.tsx @@ -3,8 +3,6 @@ import React, { useEffect } from "react" import DOMPurify from "isomorphic-dompurify" import Image from "next/image" -import { useFeatureFlagEnabled } from "posthog-js/react" -import { FeatureFlags } from "@/common/feature_flags" import { useQueries, useQuery } from "@tanstack/react-query" import { programsQueries, @@ -360,9 +358,6 @@ type OrganizationContentInternalProps = { const OrganizationContentInternal: React.FC< OrganizationContentInternalProps > = ({ org }) => { - const isOrgDashboardEnabled = useFeatureFlagEnabled( - FeatureFlags.OrganizationDashboard, - ) const orgId = org.id const contracts = useQuery(contractQueries.contractsList()) const orgContracts = contracts.data?.filter( @@ -379,8 +374,6 @@ const OrganizationContentInternal: React.FC< programCollectionQueries.programCollectionsList({}), ) - if (!isOrgDashboardEnabled) return null - const transformedPrograms = programs.data?.results .filter((program) => program.collections.length === 0) .map((program) => transform.mitxonlineProgram(program)) diff --git a/frontends/main/src/common/feature_flags.ts b/frontends/main/src/common/feature_flags.ts index 39d09ae681..f45b5f5c03 100644 --- a/frontends/main/src/common/feature_flags.ts +++ b/frontends/main/src/common/feature_flags.ts @@ -8,7 +8,6 @@ export enum FeatureFlags { RecommendationBot = "recommendation-bot", HomePageRecommendationBot = "home-page-recommendation-bot", EnrollmentDashboard = "enrollment-dashboard", - OrganizationDashboard = "mitlearn-organization-dashboard", VideoShorts = "video-shorts", ProductPageCourse = "product-page-course", } From 6ec11c44e1f63cf06b5973fb1bc26c6c3cf50cab Mon Sep 17 00:00:00 2001 From: Doof Date: Tue, 28 Oct 2025 21:24:40 +0000 Subject: [PATCH 6/6] Release 0.47.7 --- RELEASE.rst | 9 +++++++++ main/settings.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/RELEASE.rst b/RELEASE.rst index a7db1b8414..d4b02bedc1 100644 --- a/RELEASE.rst +++ b/RELEASE.rst @@ -1,6 +1,15 @@ Release Notes ============= +Version 0.47.7 +-------------- + +- remove org dashboard feature flag (#2654) +- Avoid double slashes in paths (#2652) +- use next_start_date when available in learning resource drawer (#2619) +- Fix a BannerPage background issue (#2651) +- Don't publish Professional Ed resources with blank run ids (#2637) + Version 0.47.5 (Released October 28, 2025) -------------- diff --git a/main/settings.py b/main/settings.py index 2f43462be4..8cd321eeb6 100644 --- a/main/settings.py +++ b/main/settings.py @@ -34,7 +34,7 @@ from main.settings_pluggy import * # noqa: F403 from openapi.settings_spectacular import open_spectacular_settings -VERSION = "0.47.5" +VERSION = "0.47.7" log = logging.getLogger()