Skip to content

feat: add instructor dashboard MFE support for canvas and rapid response reports plugins#819

Merged
Anas12091101 merged 17 commits into
mainfrom
anas/instructor-dashboard-mfe-apis
Jul 1, 2026
Merged

feat: add instructor dashboard MFE support for canvas and rapid response reports plugins#819
Anas12091101 merged 17 commits into
mainfrom
anas/instructor-dashboard-mfe-apis

Conversation

@Anas12091101

@Anas12091101 Anas12091101 commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

What are the relevant tickets?

https://github.com/mitodl/hq/issues/11581

Description (What does it do?)

Adds instructor-dashboard MFE (OEP-65 / frontend-base) support to the
ol_openedx_canvas_integration and ol_openedx_rapid_response_reports plugins.

Historically these plugins integrated with the legacy (Django-rendered)
instructor dashboard via PluginContexts (context_api.plugin_context), which
injected tab sections and their data server-side. The new frontend-base
instructor dashboard MFE has no such context, so this PR makes each plugin
expose its tab and data through the supported extension points the MFE consumes:

  • Tab registration via the InstructorDashboardTabsRequested Open edX Filter
    (org.openedx.learning.instructor.dashboard.tabs.requested.v1).
  • Data via small JSON API endpoints the MFE fetches.

The result is self-contained in the plugins — no edx-platform cherry-pick is
required for the MFE
(the cherry-pick remains only for the legacy dashboard).

How tab visibility works

Plugin Tab shown when…
Canvas the course has canvas_id set in Advanced Settings (per-course)
Rapid Responses the plugin is installed on the deployment

Testing

  1. Install both plugins in an LMS running the frontend-base instructor dashboard MFE.
  2. Confirm OPEN_EDX_FILTERS_CONFIG contains both pipeline steps under
    org.openedx.learning.instructor.dashboard.tabs.requested.v1.
  3. Canvas: set {"canvas_id": <id>} in a course's Advanced Settings → the
    Canvas tab appears for that course only. GET .../canvas/api/list_canvas_tasks
    returns {"tasks": [...]}.
  4. Rapid Responses: the Rapid Responses tab appears on any course;
    GET .../instructor/api/rapid_response_runs returns the run list.
  5. Follow the testing instructions in feat: add instructor dashboard overrides to replicate canvas and rapid-response-report plugins behaviour in MFE lehrer#58 to spin up the instructor dashboard MFE.
  6. Confirm tabs do not appear where they shouldn't (Canvas without canvas_id;
    either tab on a deployment without the plugin).
  7. Test the functionality of both plugins

Backward compatibility

  • Legacy instructor dashboard behavior is unchanged (the PluginContexts
    integration remains).
  • New filter registrations merge into existing OPEN_EDX_FILTERS_CONFIG.
  • No edx-platform changes required for the MFE path.

Screenshots (if appropriate):

Screen.Recording.2026-06-19.at.8.41.00.PM.mov

@Anas12091101
Anas12091101 force-pushed the anas/instructor-dashboard-mfe-apis branch from a0fc075 to 340c7ec Compare June 19, 2026 13:50
Anas12091101 and others added 4 commits June 19, 2026 20:56
The frontend-base site projects mount the instructor dashboard routes under
/apps (wrapWithAppsPath), so the LMS-provided tab hrefs must be
/apps/instructor-dashboard/<course>/<tab> to resolve. Update both tab filters
and their tests accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The view lazily imports get_run_data_for_course from rapid_response_xblock,
which is a separate, undeclared plugin. CI installs plugins alphabetically and
cumulatively, so ol_openedx_rapid_response_reports tests run before
rapid_response_xblock is installed, making @patch("rapid_response_xblock.utils...")
fail to import its target. Inject a stub module via sys.modules so the tests
are deterministic regardless of whether the xblock is installed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Anas12091101
Anas12091101 force-pushed the anas/instructor-dashboard-mfe-apis branch from 280e680 to 79a696a Compare June 19, 2026 17:02
@Anas12091101 Anas12091101 changed the title Anas/instructor dashboard mfe apis feat: add instructor dashboard MFE support for canvas and rapid response reports plugins Jun 19, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adds frontend-base instructor dashboard MFE support for the Canvas integration and Rapid Response Reports plugins by registering instructor-dashboard tabs via the InstructorDashboardTabsRequested Open edX Filter and exposing plugin data via lightweight JSON endpoints (while keeping legacy dashboard integration intact).

Changes:

  • Added Open edX Filters pipeline steps to register MFE instructor dashboard tabs for Canvas (course-gated by canvas_id) and Rapid Responses (deployment-gated by plugin install).
  • Added JSON API endpoints consumed by the MFE (list_canvas_tasks, rapid_response_runs) plus associated tests.
  • Updated plugin docs/changelogs and bumped plugin versions.

Reviewed changes

Copilot reviewed 18 out of 19 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/ol_openedx_rapid_response_reports/tests/test_pipeline.py New tests for Rapid Responses tab registration pipeline step.
src/ol_openedx_rapid_response_reports/tests/test_api.py New tests for the Rapid Responses JSON endpoint behavior and permissions.
src/ol_openedx_rapid_response_reports/tests/init.py Test package init (added/updated).
src/ol_openedx_rapid_response_reports/pyproject.toml Version bump and pytest configuration for plugin tests.
src/ol_openedx_rapid_response_reports/ol_openedx_rapid_response_reports/urls.py Exposes rapid_response_runs endpoint under the plugin URL mount.
src/ol_openedx_rapid_response_reports/ol_openedx_rapid_response_reports/settings/common.py Registers the instructor-dashboard tabs filter pipeline step in OPEN_EDX_FILTERS_CONFIG.
src/ol_openedx_rapid_response_reports/ol_openedx_rapid_response_reports/pipeline.py Adds the Rapid Responses instructor dashboard tab pipeline step.
src/ol_openedx_rapid_response_reports/ol_openedx_rapid_response_reports/app.py Wires COMMON settings so filter registration happens when installed.
src/ol_openedx_rapid_response_reports/ol_openedx_rapid_response_reports/api.py Adds list_rapid_response_runs JSON endpoint.
src/ol_openedx_rapid_response_reports/CHANGELOG.rst Documents the new MFE support and endpoint in the release notes.
src/ol_openedx_canvas_integration/tests/test_views.py New tests for the Canvas list_canvas_tasks JSON endpoint.
src/ol_openedx_canvas_integration/tests/test_pipeline.py New tests for Canvas tab registration pipeline step, including failure swallowing.
src/ol_openedx_canvas_integration/README.rst Clarifies cherry-pick requirement applies only to the legacy instructor dashboard.
src/ol_openedx_canvas_integration/pyproject.toml Version bump for the Canvas plugin.
src/ol_openedx_canvas_integration/ol_openedx_canvas_integration/views.py Adds list_canvas_tasks endpoint for MFE task-status polling.
src/ol_openedx_canvas_integration/ol_openedx_canvas_integration/urls.py Routes list_canvas_tasks.
src/ol_openedx_canvas_integration/ol_openedx_canvas_integration/settings/lms/common.py Registers the Canvas tab pipeline step in OPEN_EDX_FILTERS_CONFIG.
src/ol_openedx_canvas_integration/ol_openedx_canvas_integration/pipeline.py Adds the Canvas instructor dashboard tab pipeline step (course-gated).
src/ol_openedx_canvas_integration/CHANGELOG.rst Documents the new MFE support and endpoint in the release notes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +3 to +8
import logging

from django.utils.translation import gettext as _
from openedx_filters import PipelineStep

log = logging.getLogger(__name__)
Comment on lines +207 to +212
for task in tasks_qs:
feature = extract_task_features(task)
# Override the message for Canvas task types with the plugin's formatter
# so the result reads e.g. "N grades and M assignments updated or created".
if task.task_type in CANVAS_TASK_TYPES and task.task_output:
try:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The endpoint does filter to Canvas task types. It calls get_filtered_instructor_tasks (task_helpers.py), whose history query is constrained by task_type__in=CANVAS_TASK_TYPES; the Canvas-specific message override is also gated by CANVAS_TASK_TYPES. The only un-typed rows come from the union with the platforms get_running_instructor_tasks, which is intentional — it mirrors the legacy Canvas "Pending Tasks" view that surfaces any currently-running task. This helper is pre-existing (added in #387) and reused as-is here. If we want strictly Canvas-typed rows even for the running set, I can add a final task_type in CANVAS_TASK_TYPES` filter — happy to do that if you prefer.

@asadali145 asadali145 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is just the code review. Overall looks good. I just have a few minor suggestions.

"Failed to evaluate Canvas instructor tab for course %s", course_key
)

return {"tabs": tabs}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should return all args received in run_filter as a dict at the end, so that if there is any other pipeline step, it gets all the args.

"""

def run_filter(self, tabs, course_key, **kwargs): # noqa: ARG002
try:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we remove this broad try-except to be specific if we need it?

"tab_id": CANVAS_TAB_ID,
"title": _("Canvas"),
"url": (
f"/apps/instructor-dashboard/{course_key}/{CANVAS_TAB_ID}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we use settings INSTRUCTOR_MICROFRONTEND_URL?

"url": (
f"/apps/instructor-dashboard/{course_key}/{CANVAS_TAB_ID}"
),
"sort_order": CANVAS_TAB_SORT_ORDER,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If the idea is to display this at the end of the list, maybe we should generate this using existing sort_orders?

Comment on lines +13 to +14
CANVAS_TAB_ID = "canvas_integration"
CANVAS_TAB_SORT_ORDER = 110

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we move these to constants?

course_id,
):
"""Return JSON list of rapid response runs for the given course."""
from rapid_response_xblock.utils import get_run_data_for_course # noqa: PLC0415

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is a general comment. I don't see rapid_response_xblock as a dependency in pyproject.toml.

Comment on lines +10 to +11
RAPID_RESPONSE_TAB_ID = "rapid_response"
RAPID_RESPONSE_TAB_SORT_ORDER = 120

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please move these to constants.

tabs.append(
{
"tab_id": RAPID_RESPONSE_TAB_ID,
"title": _("Rapid Responses"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same, move this to constants.

"tab_id": RAPID_RESPONSE_TAB_ID,
"title": _("Rapid Responses"),
"url": (
f"/apps/instructor-dashboard/{course_key}/{RAPID_RESPONSE_TAB_ID}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Use the setting.

@@ -0,0 +1,103 @@
"""Tests for the rapid response reports MFE endpoint."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
"""Tests for the rapid response reports MFE endpoint."""
"""Tests for the rapid response reports API"""

# so the result reads e.g. "N grades and M assignments updated or created".
if task.task_type in CANVAS_TASK_TYPES and task.task_output:
try:
feature["task_message"] = get_task_output_formatted_message(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The list_canvas_tasks API endpoint incorrectly includes all running instructor tasks for a course, leaking task information between instructors.
Severity: MEDIUM

Suggested Fix

Modify get_running_instructor_tasks or its usage within get_filtered_instructor_tasks to filter the running tasks by the current user (request.user). This will ensure the API only returns tasks initiated by the user making the request.

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: src/ol_openedx_canvas_integration/ol_openedx_canvas_integration/views.py#L213

Potential issue: The `list_canvas_tasks` API endpoint leaks information about tasks run
by other instructors. The view calls `get_filtered_instructor_tasks`, which combines two
querysets. One is correctly filtered by the current user. The other, from
`get_running_instructor_tasks`, includes all running instructor tasks for the course,
regardless of which user initiated them. As a result, an instructor calling this API may
see details of tasks run by other instructors in the same course, including tasks
unrelated to Canvas.

full page reload.
"""

def run_filter(self, tabs, course_key, **kwargs):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we use the original signature here? I am not sure how it is working as the 2nd arg is user in the original definition.

Suggested change
def run_filter(self, tabs, course_key, **kwargs):
def run_filter(self, tabs, user, course_key):

)

# Return every argument so any subsequent pipeline step gets the full set.
return {"tabs": tabs, "course_key": course_key, **kwargs}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This will change with the definition.

(``createInstructorDashboardCustomApp`` in the shared MFE module).
"""

def run_filter(self, tabs, course_key, **kwargs):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same comments as in canvas plugin.

@Anas12091101
Anas12091101 requested a review from asadali145 June 24, 2026 15:12

@asadali145 asadali145 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM!

@Anas12091101
Anas12091101 merged commit c8aace4 into main Jul 1, 2026
9 checks passed
@Anas12091101
Anas12091101 deleted the anas/instructor-dashboard-mfe-apis branch July 1, 2026 07:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants