Skip to content

fix: show the block title only when the learner can see it on the page - #263

Open
zamanafzal wants to merge 1 commit into
mainfrom
zafzal/13643-feedback-visible-title
Open

zamanafzal wants to merge 1 commit into
mainfrom
zafzal/13643-feedback-visible-title

Conversation

@zamanafzal

@zamanafzal zamanafzal commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

What are the relevant tickets?

Part of https://github.com/mitodl/hq/issues/13643

Paired with mitodl/open-edx-plugins#876, which sends the new field.

Description (What does it do?)

The drawer labelled itself with blockDisplayName. For most block types that is a Studio-only authoring note ("Wk3 intro copy - REVISED, do not reuse") that never appears in courseware, so the panel was showing learners an internal label.

  • Reads the new visibleTitle payload field for the subheader instead. The trigger sends it only for block types that actually render their name, so the decision lives with the side that knows the block.
  • blockDisplayName is still POSTed as block_display_name, unchanged — that's how the content team locates the component.
  • With no visible title the subheader names the block type, and an unmapped type now falls back to "this content" rather than echoing the raw slug.
  • Doesn't append a second terminator to a title that already ends a sentence.

The last bullet is outside the ticket's four criteria — it surfaced while testing the first three and is here because it's two lines in the same expression. Say the word if you'd rather it went separately.

Implementation details

FRIENDLY_BLOCK_TYPES previously did FRIENDLY_BLOCK_TYPES[blockType] ?? blockType, which rendered the raw type for anything unmapped — a learner on a custom block would read "about this ol_openedx_chat_xblock block". The lookup now resolves to null when unmapped.

Two things about that lookup are deliberate. The own-key check via hasOwnProperty is needed because a plain object literal returns real values for constructor, __proto__, and toString; without it, blockType: "constructor" would render the Object source text into the question. And both blockType and visibleTitle arrive over a cross-origin postMessage, so the sender controls their type — the typeof checks keep a non-string from throwing on .trim() mid-render, which would blank the panel since the bundle has no error boundary.

FRIENDLY_BLOCK_TYPES gains videoalpha, annotatable, pdf, edx_sga, and staffgradedxblock so it covers every type the trigger's own map can send a title for, plus poll_question — the built-in poll draws its question text rather than its name (its extracted template renders only a JSON config div), so it never sends a title and this wording is the only one it can get. Those blocks land on this wording whenever their title comes through blank, and without the entries they'd read "this content". A test enumerates all 14 of the trigger's types so the two maps can't drift apart silently.

The terminator: an author can write a question into the Studio name, and some types render that name as their heading — the third-party poll puts display_name in an <h3> and keeps the question in a separate field — so a title can arrive as "Which approach did you prefer?" and read "...prefer??".

Screenshots (if appropriate):

Video — title shown. video renders its name as a heading, so the panel reuses the words the learner can already see.

Courseware unit with a video block outlined; panel reads 'What kind of feedback do you have about Lecture 3: Recursion?'

Problem — title shown. Same path for a problem, whose name is the Quiz 1: Base cases heading above the choices.

Problem block headed 'Quiz 1: Base cases' outlined; panel reads 'What kind of feedback do you have about Quiz 1: Base cases?'

Poll (the third-party poll) — title shown, and not double-terminated. The <h3> is display_name and the question is a separate field below it, so an author can put a question in the name. The panel reads "…prefer?", not "…prefer??".

Poll block whose heading is 'WHICH APPROACH DID YOU PREFER?' with a separate question below; panel reads 'What kind of feedback do you have about Which approach did you prefer?'

Survey — title comes from block_name. survey renders block_name as its heading, and that heading is what the panel names — not display_name.

Survey block headed 'END OF WEEK CHECK-IN' outlined; panel reads 'What kind of feedback do you have about End of week check-in?'

Text block — falls back to the block type. This block's Studio name is Wk3 intro copy - REVISED, do not reuse. It appears nowhere on the page and nowhere in the panel, which reads "about this text?". This is the leak the ticket is about. ← AC1

HTML block rendering only its body text, outlined; panel reads 'What kind of feedback do you have about this text?' with no Studio name anywhere

Built-in poll — falls back. poll_question draws its question text rather than its name, so it sends no title and the panel names the type.

Built-in poll block outlined; panel reads 'What kind of feedback do you have about this poll?'

Problem with an empty Studio name — falls back. A mapped type still degrades to block-type wording when the name is blank.

Problem block with no heading, outlined; panel reads 'What kind of feedback do you have about this problem?'

Unmapped type — generic wording. done is in neither map, so the panel says "about this content?" instead of echoing the raw slug.

'Mark as complete' done block outlined; panel reads 'What kind of feedback do you have about this content?'

The two Storybook stories cover the same split without a harness — Slot (block title in subheader) and Slot (block type in subheader).

How can this be tested?

Automated: nvm use 24 && yarn jest src/bundles/FeedbackDrawer — 80 pass. yarn typecheck passes and yarn build:bundles:feedback builds.

The new tests cover the split directly: FeedbackDrawerManager.test.tsx opens the drawer for an html block whose blockDisplayName is "Wk3 intro copy - REVISED, do not reuse" with no visibleTitle, asserts the panel says "about this text?" and that REVISED appears nowhere in the DOM, then submits and asserts the Studio name is still in the POST body. The shared PAYLOAD now uses different values for the two fields, so the subtitle test can only pass by reading visibleTitle. A parity test enumerates all 14 of the trigger's block types so the two maps can't drift apart silently.

Drawer only (no harness) — nvm use 24 && yarn install && yarn start (Storybook on http://localhost:6006), then smoot-design → Feedback → FeedbackDrawer:

  • Slot (block title in subheader) — video with a visible title → "…about Lecture 3: Recursion?"
  • Slot (block type in subheader) — problem with none → "…about this problem?"

Manual — to exercise the full megaphone → drawer loop locally:

  1. Set up a Tutor instance locally and mount frontend-app-learning (run its dev server).
  2. Enable the trigger: install the companion ol_openedx_feedback plugin (open-edx-plugins#876) in the LMS and turn on the ol_openedx_feedback.feedback_enabled CourseWaffleFlag (globally or per course). This branch reads visibleTitle, which only that PR's trigger sends — against the released plugin every block falls back to block-type wording.
  3. Wire the feedback drawer into the Learning MFE's right-sidebar slot (SidebarAIDrawerCoordinator mounts it inline). In .env.development set DEPLOYMENT_NAME='mitxonline' and ENABLE_AI_DRAWER_SLOT='true' (feedback shares AskTIM's sidebar mount).
  4. Build this branch and copy the bundle into the MFE (paths assume the two repos are siblings):
    cd smoot-design && nvm use 24 && yarn install && yarn build:bundles:feedback \
      && mkdir -p ../frontend-app-learning/public/static/smoot-design \
      && cp dist/bundles/feedbackDrawerManager.* ../frontend-app-learning/public/static/smoot-design/
    The MFE loads it from /static/smoot-design/feedbackDrawerManager.es.js (override with FEEDBACK_DRAWER_BUNDLE_PATH).
  5. Author a unit with one block per case — a video or word_cloud with a Studio name, a text/HTML block, and a built-in poll. Give the text block a deliberately author-only name like Wk3 intro copy - REVISED, do not reuse so a leak is obvious.
  6. Open the unit as a signed-in learner and click the 📣 on each block:
    1. Title path — the video / word cloud panel reads What kind of feedback do you have about <the block's title>? ← AC2
    2. Fallback path — the text block reads "…about this text?" and the poll "…about this poll?", with no Studio name anywhere in the panel. ← AC1
    3. Record still carries it — submit from the text block and confirm the mit-learn row still has block_display_name set to the Studio name. ← AC4

Steps 5–6 were run on a Tutor LMS with the paired plugin installed — the screenshots above are that run, one shot per case. drag-and-drop-v2's show_title toggle is covered by unit tests in the paired PR only.

Additional Context

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The implementation meets the privacy requirement with comprehensive coverage; only a minor Storybook documentation mismatch remains.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
What changed in this PR

Updates the feedback drawer to display learner-visible titles while preserving Studio labels for submissions.

Changes:

  • Uses visibleTitle with safe block-type fallbacks.
  • Prevents raw slugs and duplicate punctuation.
  • Expands tests and Storybook coverage.
File Description
FeedbackDrawerManager.tsx Handles the new title field.
FeedbackDrawerManager.test.tsx Tests display/submission separation.
FeedbackDrawer.tsx Adds safe learner-facing wording.
FeedbackDrawer.test.tsx Covers mappings, punctuation, and malformed payloads.
FeedbackDrawer.stories.tsx Updates title and fallback stories.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/bundles/FeedbackDrawer/FeedbackDrawer.stories.tsx Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

The terminator logic still duplicates punctuation for titles ending with punctuated brackets or nested quotes.

Review effort: Balanced
Findings: None

Resolved since last review (1)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Avoid duplicate question marks after closing punctuation

src/​bundles/​FeedbackDrawer/​FeedbackDrawer.tsx:381

The terminator check only permits one trailing quote, so titles whose existing punctuation is followed by a closing bracket or nested quotes still get a second question mark (for example, Recursion (why?) becomes ...why?)?). Treat a sequence of closing punctuation as trailing characters while still allowing Midterm (offline) to receive its question mark.

@zamanafzal zamanafzal added the Needs Review An open Pull Request that is ready for review label Sep 30, 2026
The drawer named the block with the Studio display_name, which for most block
types is an authoring label the learner never sees ("Wk3 intro copy - REVISED,
do not reuse"). It now reads the new `visibleTitle` payload field, which the
LMS trigger sets only for block types that actually draw a title, and names the
block type when there is none.

Alongside that:

- Name more block types, so the fallback reads "this PDF" or "this assignment"
  rather than a raw slug, and never leaks an unmapped slug.
- Treat `subtitle` and `blockType` as untrusted. Both arrive over postMessage
  and this bundle has no error boundary, so a non-string `subtitle` threw
  mid-render and blanked the panel, and `blockType: "constructor"` resolved to
  an Object.prototype member.
- Don't append a second terminator to a title that already ends a sentence.
  poll renders the Studio name as its question, so authors write questions
  there and the subheader read "...which do you prefer??". A trailing period is
  excluded: it's usually numbering ("Ch. 4."), and swallowing the question mark
  left the reaction radiogroup's accessible name a statement.
@zamanafzal
zamanafzal force-pushed the zafzal/13643-feedback-visible-title branch from 3bce2b6 to bce96c4 Compare October 1, 2026 06:24
@arslanashraf7 arslanashraf7 self-assigned this Oct 1, 2026

@arslanashraf7 arslanashraf7 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM 👍

@arslanashraf7 arslanashraf7 added Waiting on Author and removed Needs Review An open Pull Request that is ready for review labels Oct 6, 2026

This branch has not been deployed

No deployments
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