Repository navigation
[FE] Build cards displaying Competency Criteria on the Course Progress page #734
Description
User Story
As a learner, when I view the Progress tab of my course, I want to see cards of the competencies and subcompetencies that show which subsections correspond to each competency and what the rule is to demonstrate mastery with these subsections so that I can understand what's required for me to demonstrate mastery.
Description
This ticket builds the foundation of the CBE course progress page, which goes in the ProgressTabCourseCompletionSlot above the default Course completion and Grades cards.
A course can have its content associated with more than one level of the competency taxonomy hierarchy (#666 only blocks a tag and its own ancestor or descendant in the same course; sibling branches of the competency taxonomy hierarchy can be applied in this course at different levels).
Each card's layout will depend on the level of its tags, based on the following cases:
- If a tag with competency criteria in this course is at the topmost level of its taxonomy, then display a card with that tag's name as the heading and the rules and subsections underneath.
- If a tag with competency criteria in this course is right below the topmost level, then display a card with the tag's parent as the heading and the tag (along with any sibling tags that also have criteria in this course) as a child with the rules and subsections underneath it.
- If that parent is itself below the topmost level, then add a breadcrumb above the card heading with each of the parent's ancestors.
- If a tag with competency criteria in this course is also an ancestor, at any depth, of other tags with competency criteria in this course, then that ancestor heads the card, with its own rules and subsections first. Each descendant with criteria appears as a row nested along its path under the heading. The tags on that path that have no criteria of their own appear as rows too, with the target icon like every other tag in the card and nothing of their own underneath, and each row's children are indented beneath it so the hierarchy is visible (example: Ref 1 in the Acceptance Criteria).
- If a tag that heads one card also appears in another card's breadcrumb, the two cards merge into one card headed by the shallower tag. The deeper card's heading becomes a row inside it with the target icon and nothing of its own, and the deeper card's content is indented beneath that row, as in the previous case (example: Ref 2 in the Acceptance Criteria).
Example:
Given the following taxonomy and a course with the indicated criteria associations:
- Critical Thinking
- Analysis (Criteria association here)
- Evaluation
- Inference (Criteria association here)
- Communication (Criteria association here)
- Written Communication
- Oral Communication
- Audience Awareness
- Problem Solving
- Problem Definition
- Root Cause Analysis (Criteria association here)
- Strategy Selection
- Solution Testing
None of these tags is an ancestor or descendant of another, so they can all coexist in this course even though they are at different levels. This course would get three cards:
- A "Communication" card, with Communication's rules and subsections underneath.
- A "Critical Thinking" card, with Analysis and Inference as children. Evaluation isn't shown, because it has no criteria in this course.
- A "Problem Definition" card, with Root Cause Analysis as a child and a "Problem Solving" breadcrumb above the heading.
Note that this course could not also have criteria on Critical Thinking itself, because Critical Thinking is the parent of Analysis and Inference, unless a taxonomy re-import moved tags after the criteria were created.
The tags with competency criteria in this course should have the target icon before them.
Under each of these tags, display this course's bottom-tier groups the way the Competency Management page does: "COMPLETE ANY/ALL OF THE FOLLOWING" per group, then "AT XX% OR BETTER" with the subsections underneath for each set of criteria that share a rule. If there is more than one group, then display an "AND" or "OR" in between them.
Display each taxonomy's name as a heading above its cards.
Because transparency to students is a critical tenet of CBE, subsections the learner can't see still appear, as a placeholder row such as "1 more subsection that isn't visible to you", so the learner knows they count.
If this course has no CompetencyCriteria (if an empty array comes back from #733's endpoint), then display nothing.
Out of Scope (will be implemented in future tickets):
- Sunburst
- Right hand column ([Placeholder - FE] Build a right sidebar (or central) display of top level competencies ("Focus Areas") with their Competency status displayed. #743)
- Displaying grades in the cards
- Displaying competency statuses in the cards
- Expanding a subsection row to show attempts and score feedback
- Rendering the panel in place of the Course completion and Grades cards ([FE] Let the operator choose to replace Course Grade Slot with CBE Progress #839)
Context
- This is the frontend counterpart to [BE] GET Competency Criteria for Course #733.
- Blocked by [BE] GET Competency Criteria for Course #733 and [FE] Render placeholder CBE progress widgets in both learner Progress tab slots #829.
- frontend-app-learning#1905 will move the Learning MFE's plugin slots to frontend-base's
SlotAPI, which may change how this plugin registers.
UX Design
- Figma (happy path): https://www.figma.com/design/VqDdtf3NOsUihle6SNS6Kw/-Course-Level----Student-Progress?node-id=983-3817&t=eJLFBvoAFbCnde7b-4
- Figma (six-level taxonomy): https://www.figma.com/design/VqDdtf3NOsUihle6SNS6Kw/-Course-Level----Student-Progress?node-id=1089-4395&t=eJLFBvoAFbCnde7b-4
- Screenshots:
Acceptance Criteria
These scenarios use the following terms:
- A group is one of the course's bottom-tier groups under a tag. Its group line says whether all or any of the group's subsections are required.
- When every criterion in a group has the same rule, the group line also states that rule's score, for example "COMPLETE ALL OF THE FOLLOWING AT 80% OR BETTER", and the subsections appear directly under the group line.
- When a group's criteria have more than one rule, each rule gets its own rule line under the group line, such as "AT 75% OR BETTER", with the subsections that share that rule under it.
- A subsection hidden from the learner is one that isn't in the learner's course outline: one that only staff can see, one restricted to a content group the learner isn't in, one the author has hidden from the course outline, or one deleted from the course.
- A placeholder row stands in for the subsections under one rule that are hidden from the viewer. It reads "1 more subsection that isn't visible to you", or "N more subsections that aren't visible to you" when there is more than one, and it comes after that rule's named subsections.
Scenario: The panel appears above the Course completion and Grades cards in a course with competency criteria
Given a course with competency criteria on subsections the learner can see
When the learner opens the course's Progress tab
Then the competency criteria panel appears at the top of the main column, above the Course completion and Grades cards
And the panel has no title of its own above its first card or taxonomy heading
And the Course completion card, the Grades card, the grade summary, and the detailed grades table still appear, unchanged
Scenario: A top-level tag with criteria is its own card
Given the course's only competency criteria are on "Communication", a tag at the top level of its taxonomy
When the learner opens the course's Progress tab
Then one card appears, headed "Communication"
And a target icon appears immediately before the heading
And Communication's groups and subsections appear directly under the heading
And no breadcrumb appears above the heading
Scenario: A second-level tag appears in a card headed by its parent
Given "Analysis", "Evaluation", and "Inference" are children of "Critical Thinking", a top-level tag
And the course has competency criteria on "Analysis" and "Inference", and none on "Evaluation"
When the learner opens the course's Progress tab
Then one card appears, headed "Critical Thinking", with no target icon and no breadcrumb
And "Analysis" and "Inference" appear inside that card, each with a target icon immediately before its name and its own groups and subsections under it
And "Evaluation" does not appear
Scenario: A tag two or more levels deep appears under its parent, with the parent's ancestors as a breadcrumb
Given "Root Cause Analysis" is a child of "Problem Definition", which is a child of "Problem Solving", a top-level tag
And the course has competency criteria on "Root Cause Analysis"
When the learner opens the course's Progress tab
Then a card appears, headed "Problem Definition", with no target icon on the heading
And "Problem Solving" appears as a breadcrumb above the heading
And "Root Cause Analysis" appears inside the card, with a target icon and its groups and subsections under it
Scenario: The breadcrumb lists every ancestor in a six-level taxonomy
Given a taxonomy six levels deep, with one tag at each level, named "Level 1" at the top through "Level 6" at the bottom
And the course has competency criteria on "Level 6"
When the learner opens the course's Progress tab
Then a card appears, headed "Level 5"
And the breadcrumb above the heading shows "Level 1", "Level 2", "Level 3", and "Level 4", in that order
And "Level 6" appears inside the card, with a target icon
Scenario: The course in the Description's example shows three cards
Given the taxonomy and the course criteria from the Description's example
When the learner opens the course's Progress tab
Then exactly three cards appear: "Communication", "Critical Thinking", and "Problem Definition"
Scenario: A tag that heads one card and appears in another card's breadcrumb merges the two cards (Ref 2)
Given "Problem Definition" and "Strategy Selection" are children of "Problem Solving", a top-level tag, and "Root Cause Analysis" is a child of "Problem Definition"
And the course has competency criteria on "Strategy Selection" and "Root Cause Analysis", and none on "Problem Solving" or "Problem Definition"
When the learner opens the course's Progress tab
Then one card appears, headed "Problem Solving", with no target icon on the heading and no breadcrumb
And "Strategy Selection" appears inside the card, with a target icon and its groups and subsections under it
And "Problem Definition" appears inside the card as a row with a target icon and no groups or subsections of its own
And "Root Cause Analysis" appears indented under the "Problem Definition" row, with a target icon and its groups and subsections under it
And no card headed "Problem Definition" appears
Scenario: A tag whose parent also has criteria appears under the parent's own requirements
Given "Critical Thinking", a top-level tag, and its child "Analysis" both have criteria in this course, which can happen when a taxonomy is re-imported with a tag moved under a new parent after the criteria were created
When the learner opens the course's Progress tab
Then one card appears, headed "Critical Thinking", with a target icon immediately before the heading
And Critical Thinking's groups and subsections appear directly under the heading, before "Analysis"
And "Analysis" appears inside the same card, with a target icon and its own groups and subsections under it
Scenario: A tag whose ancestor two levels up has criteria appears nested along the path under that ancestor (Ref 1)
Given "Root Cause Analysis" is a child of "Problem Definition", which is a child of "Problem Solving", a top-level tag
And "Problem Solving" and "Root Cause Analysis" both have criteria in this course, and "Problem Definition" has none
When the learner opens the course's Progress tab
Then one card appears, headed "Problem Solving", with a target icon immediately before the heading and no breadcrumb
And Problem Solving's groups and subsections appear directly under the heading, before any row
And "Problem Definition" appears inside the card as a row with a target icon and no groups or subsections of its own
And "Root Cause Analysis" appears indented under the "Problem Definition" row, with a target icon and its groups and subsections under it
And no card headed "Problem Definition" appears
Scenario: A tag that heads its own card isn't repeated in its parent's card
Given "Problem Definition" is a child of "Problem Solving", a top-level tag, and "Root Cause Analysis" is a child of "Problem Definition"
And both "Problem Definition" and "Root Cause Analysis" have criteria in this course
And no other child of "Problem Solving" has criteria in this course
When the learner opens the course's Progress tab
Then a card headed "Problem Definition" appears, with a target icon before the heading and a "Problem Solving" breadcrumb
And Problem Definition's groups and subsections appear directly under that heading, before "Root Cause Analysis"
And Problem Definition's groups and subsections appear nowhere else in the panel
And no card headed "Problem Solving" appears
Scenario Outline: The group line says whether all or any of the group's subsections are required
Given a tag with one group in this course, whose criteria all require 80% or better, and that group <setting>
When the learner opens the course's Progress tab
Then the group line reads "<text>"
Examples:
| setting | text |
| requires all of its criteria | COMPLETE ALL OF THE FOLLOWING AT 80% OR BETTER |
| requires any one of its criteria | COMPLETE ANY OF THE FOLLOWING AT 80% OR BETTER |
| has no combining choice, because it holds a single criterion | COMPLETE ANY OF THE FOLLOWING AT 80% OR BETTER |
Scenario: A group whose criteria have more than one rule shows a rule line for each
Given a group that requires all of its criteria, with "Quiz 1" and "Quiz 2" each requiring 75% or better and "Final Project" requiring 90% or better
When the learner opens the course's Progress tab
Then the group line reads "COMPLETE ALL OF THE FOLLOWING", with no score
And a rule line reading "AT 75% OR BETTER" has "Quiz 1" and "Quiz 2" under it
And a rule line reading "AT 90% OR BETTER" has "Final Project" under it
And no AND or OR appears between the two rule lines
Scenario Outline: The rule states the score the subsections require
Given a group that requires all of its criteria, each of which requires a score <comparison> <threshold>%
When the learner opens the course's Progress tab
Then the group line reads "COMPLETE ALL OF THE FOLLOWING <rule>"
Examples:
| comparison | threshold | rule |
| at or above | 82 | AT 82% OR BETTER |
| at or below | 40 | AT 40% OR LOWER |
| exactly equal to | 100 | AT EXACTLY 100% |
Scenario Outline: A tag's groups in this course are joined by AND or OR
Given a tag with three groups in this course, and the course requires <requirement> of those groups
When the learner opens the course's Progress tab
Then "<word>" appears between the first and second groups, and again between the second and third
And no AND or OR appears before the first group or after the last
Examples:
| requirement | word |
| all | AND |
| any one | OR |
Scenario: A tag with one group in this course shows no AND or OR
Given a tag with exactly one group in this course
And that competency can also be demonstrated through criteria in other courses
When the learner opens the course's Progress tab
Then no AND or OR appears under that tag
Scenario: A course using two taxonomies shows each taxonomy's name above its own cards
Given a course with competency criteria on tags from "Workplace Skills" and from "Accounting Standards"
When the learner opens the course's Progress tab
Then an "Accounting Standards" heading appears first, followed by that taxonomy's cards
And a "Workplace Skills" heading appears after them, followed by that taxonomy's cards
Scenario: A course using one taxonomy still shows that taxonomy's heading
Given a course whose competency criteria all use tags from "Workplace Skills"
When the learner opens the course's Progress tab
Then a "Workplace Skills" heading appears above that taxonomy's cards
Scenario: Tags with the same name in two taxonomies stay separate
Given two taxonomies that each have a top-level tag named "Communication", and the course has criteria on both
When the learner opens the course's Progress tab
Then a "Communication" card appears under each taxonomy's heading
And each card shows only the groups and subsections of its own taxonomy's tag
Scenario: Tag and subsection names appear as plain text
Given a course with competency criteria
When the learner opens the course's Progress tab
Then each tag and subsection appears under the name it has in its taxonomy or in the course
And no tag name, breadcrumb entry, or subsection name is a link
Scenario: A course with no competency criteria shows no panel
Given a course with no competency criteria
When the learner opens the course's Progress tab
Then no card, heading, message, or empty space from the panel appears
And the main column shows the same content it shows on a site without the plugin
Scenario: Nothing from the panel appears while it is loading
Given a course with competency criteria
And the criteria or the course's subsection names are still loading
When the learner opens the course's Progress tab
Then no card, loading indicator, or placeholder from the panel appears
And the Course completion and Grades cards and the rest of the Progress tab appear without waiting for the panel
Scenario: The panel stays hidden when the course's criteria can't be loaded
Given the request for the course's competency criteria fails, for example because the site hasn't deployed that endpoint, the server returns an error, or the request is refused
When the learner opens the course's Progress tab
Then nothing from the panel appears, and no error message is shown to the learner
And the failure is reported to the site's logging service
And the Course completion and Grades cards and the rest of the Progress tab appear as usual
Scenario: The panel stays hidden when the subsection names can't be loaded
Given the course's competency criteria load
And the request for the course outline fails
When the learner opens the course's Progress tab
Then nothing from the panel appears, including any criterion without its subsection's name
And the failure is reported to the site's logging service
And the Course completion and Grades cards and the rest of the Progress tab appear as usual
Scenario: Subsections hidden from the learner appear as a placeholder row
Given a group that requires all of its criteria, each requiring 80% or better, on "Quiz 1", which every learner can see, "Instructor Review", which only staff can see, "Group B Project", which is restricted to a content group the learner isn't in, and "Bonus Case Study", which the author has hidden from the course outline
When the learner opens the course's Progress tab
Then "Quiz 1" appears by name in the group
And a placeholder row reading "3 more subsections that aren't visible to you" appears after it, in the same group
And "Instructor Review", "Group B Project", and "Bonus Case Study" don't appear by name anywhere in the panel
Scenario: A hidden subsection keeps its rule line
Given a group that requires all of its criteria, with "Quiz 1" requiring 75% or better and "Bonus Case Study", which is hidden from the learner, requiring 90% or better
When the learner opens the course's Progress tab
Then the group line reads "COMPLETE ALL OF THE FOLLOWING", with no score
And a rule line reading "AT 75% OR BETTER" has "Quiz 1" under it
And a rule line reading "AT 90% OR BETTER" has a placeholder row reading "1 more subsection that isn't visible to you" under it
Scenario: A group whose subsections are all hidden keeps its place
Given a tag with three groups in this course, joined by AND
And every criterion in the second group is on a subsection hidden from the learner
When the learner opens the course's Progress tab
Then all three groups appear, with AND between the first and second and between the second and third
And the second group shows its group line with only a placeholder row under it
Scenario: A tag whose subsections are all hidden still appears
Given "Analysis" and "Inference" are children of "Critical Thinking", and each has criteria in this course
And every criterion under "Inference" is on a subsection hidden from the learner
When the learner opens the course's Progress tab
Then the "Critical Thinking" card shows "Analysis" with its named subsections
And the card shows "Inference" with its groups and rule lines, each with only a placeholder row under it
Scenario: A course whose subsections are all hidden still shows the panel
Given a course with competency criteria
And every criterion is on a subsection hidden from the learner
When the learner opens the course's Progress tab
Then the panel appears with its taxonomy headings, cards, tags, group lines, and rule lines
And every subsection row in it is a placeholder row
Scenario: A deleted subsection appears as a placeholder row for everyone
Given a criterion on a subsection that has since been deleted from the course
When a learner or a member of course staff opens the course's Progress tab
Then a placeholder row reading "1 more subsection that isn't visible to you" appears in that criterion's place
Scenario: Criteria on subsections that aren't released yet are shown
Given a criterion on "Unit 5 Exam", a subsection whose release date is in the future
When the learner opens the course's Progress tab
Then "Unit 5 Exam" appears by name in its group
Scenario: Course staff viewing a learner's progress see criteria on subsections visible to staff
Given a course with criteria on "Quiz 1", which every learner can see, "Instructor Review", which only staff can see, "Group B Project", which is restricted to content group B, and "Bonus Case Study", which the author has hidden from the course outline
When a member of course staff opens a specific learner's progress page, for example from the instructor dashboard
Then the panel appears on that learner's progress page
And "Quiz 1", "Instructor Review", "Group B Project", and "Bonus Case Study" all appear by name, with no placeholder row
Scenario: Course staff viewing the course as a specific learner see what that learner sees
Given a course with criteria on "Quiz 1", which every learner can see, "Instructor Review", which only staff can see, and "Group B Project", which is restricted to content group B
When a member of course staff views the Progress tab as a specific learner who is in content group A
Then "Quiz 1" appears by name
And a placeholder row reading "2 more subsections that aren't visible to you" appears in place of "Instructor Review" and "Group B Project"
Scenario: A screen reader user hears the panel in the order it appears on screen
Given a course with competency criteria
When a screen reader user moves through the panel
Then they hear each taxonomy heading, breadcrumb, card heading, tag name, group line, AND or OR, rule line, subsection name, and placeholder row in the order it appears on screen
And they can jump between card headings and tag names by moving between headings
And the target icon is announced with a text alternative
Scenario: The panel reflows on a small screen
Given a course with competency criteria
When the learner opens the course's Progress tab at a phone-sized viewport
Then the cards fill the width of the main column and stack one above another
And long tag names, breadcrumbs, group lines, rule lines, and subsection names wrap onto more lines instead of being cut off
And the page doesn't scroll horizontallyTechnical Details
This is a suggested approach, not the source of truth. The User Story, Description, and Acceptance Criteria define what must be true when the work is done.
Summary
The panel makes two requests through a react-query client the plugin owns: #733's criteria for the course and, only when that response has criteria, the learner's course outline from the learning_sequences API, which supplies the subsection names. One pure function joins the two responses, counts criteria on subsections the outline doesn't list into placeholder rows, and returns the cards grouped by taxonomy. The components render that result from plain props and use no slot or fetching APIs, so frontend-app-learning#1905's move to frontend-base's Slot API should only change the registration.
Approach
-
Requests.
src/data/api.jshasgetCourseCompetencyCriteria(courseId), which calls [BE] GET Competency Criteria for Course #733's LMS route, andgetCourseOutline(courseId), which callsGET {LMS_BASE_URL}/api/learning_sequences/v1/course_outline/{courseId}. Both go throughgetAuthenticatedHttpClient().- If [BE] GET Competency Criteria for Course #733 takes the course key as a query parameter, pass it through axios
params, because a literal+in a query string decodes as a space. - Don't run
camelCaseObjectover the outline response.outline.sequencesis keyed by usage key, andcamelCaseObjectwould rewrite those keys.
- If [BE] GET Competency Criteria for Course #733 takes the course key as a query parameter, pass it through axios
-
Outline source. The learning_sequences outline fits this panel for four reasons:
- It keeps unreleased subsections, each with its
effective_start, so a release-date marker needs no extra request if the UX design adds one. - It returns each subsection's plain
title. - For learners, it already removes what they may not know exists: staff-only,
hide_from_toc, content-group, cohort and enrollment-track restricted, and deleted content. The join therefore makes no visibility decision of its own: a criterion whose subsection is missing from the outline becomes part of a placeholder count. - It honors masquerade.
The Course Home Outline API can't be the source. For learners, its
StartDateTransformerdrops subsections that aren't released yet, and it appends "(N Questions)" to graded subsection names. - It keeps unreleased subsections, each with its
-
Query client.
src/data/queryClient.jscreates oneQueryClientlazily on first use, so the package entry point still does no work at import time. Configure it with aQueryCachewhoseonErrorcallslogErrorfrom@edx/frontend-platform/logging, no retry on a 4xx response, andrefetchOnWindowFocus: false. SetstaleTimeexplicitly; its value is the implementer's choice. Every hook passes this client asuseQuery's second argument instead of reading one from React context, because frontend-app-learning's own query client logs every failed query itself, so reading the host's client would log every failure twice. Passing the client explicitly also lets [FE] Let the operator choose to replace Course Grade Slot with CBE Progress #839's wrappers share the cache without putting a provider around the host's stock Course completion and Grades cards. -
Hooks.
src/data/apiHooks.jsexports four things:useCourseCompetencyCriteria(courseId).useCourseOutline(courseId, { enabled }).hasCompetencyCriteria(data), which is true when [BE] GET Competency Criteria for Course #733's criteria array is non-empty.useCompetencyCards(courseId), which runs the transform below insideuseMemo.
Enable the outline query only when
hasCompetencyCriteriais true, so a course without competency criteria costs one request. LeavetargetUserIdout of both query keys, because neither response depends on which learner is being viewed. [FE] Let the operator choose to replace Course Grade Slot with CBE Progress #839's "in place of" option is out of scope; [FE] Let the operator choose to replace Course Grade Slot with CBE Progress #839 reusesuseCourseCompetencyCriteriaandhasCompetencyCriteria. -
Transform.
buildCompetencyCards(criteriaResponse, outline)lives insrc/data/buildCompetencyCards.jsand works in five steps:- Walk
outline.sections, and each section'ssequence_ids, in order. Index each usage key found inoutline.sequenceswith itstitleand its position in the outline. - Mark every criterion whose
object_idisn't in that index as hidden. Hidden criteria are counted, never dropped, and the outline can't say why one is missing, so a deleted subsection counts the same as a hidden one. - The bottom-tier groups are the course-level group's direct children, ordered by
ordering. In each bottom-tier group, group the criteria into rule boxes by effective rule, the same identity [FE] Create & View Competency Criteria #672 gives rule boxes on the Competency Management page, and order the boxes by their lowest criterionid, as [FE] Create & View Competency Criteria #672 does. Order each rule box's visible subsections by outline position, and give the box a hidden count for its placeholder row. [BE] Create CompetencyCriteria #665 creates only three levels of groups, with the bottom tier as the lowest, so how a deeper tree displays is left to [ARCH] Document all acceptable/valid competency criteria combinations that need to be displayed. #731 and [UXD Spike] UX Designs that support all acceptable/valid competency criteria combinations. #732. - Build the cards from each tag's
lineage. A top-level tag heads its own card, and any other tag is a row in the card headed by its parent. When a tag in the response is an ancestor, at any depth, of another tag in the response, the ancestor heads the card and gets the target icon: its own groups go under the heading, ahead of the rows; each descendant with criteria is a row nested along its lineage path below the heading; the tags on that path with no criteria are rows with the target icon, no groups, and their children indented beneath them; and the ancestor is not also a row in its own parent's card. When a card's heading appears in the lineage of another card's heading, merge the deeper card into the shallower one: the deeper heading becomes a path row and its rows nest beneath it, so no tag both heads a card and appears in another card's breadcrumb. Eachlineageentry carries the tag'sidandvalue([BE] GET Competency Criteria for Course #733), ordered from the top of the taxonomy. The breadcrumb is thevalueof each entry in the heading's lineage without the heading. Key cards by the heading's tagid, and carry thatidon the card and each row's tagidon the row, path rows included, so [FE] Display Competency Statuses for Learner in Course #740 can attach competency statuses by tag id. - Group the cards into taxonomy sections, ordered by taxonomy name. Every section gets its taxonomy heading, including when there is only one. Within a section, keep the cards in the order [BE] GET Competency Criteria for Course #733 returns their heading tags, which [BE] GET Competency Criteria for Course #733 guarantees is the same on every request.
Visibility removes nothing, because [BE] GET Competency Criteria for Course #733 already prunes every branch with no criterion, so every layout decision comes straight from [BE] GET Competency Criteria for Course #733's response: which tags head cards, whether a group's single rule sits on the group line, and where an AND/OR separator appears. The test fixtures should cover the Description's example, a tag with criteria alongside its own ancestor, a rule box mixing a profile-based criterion and an override criterion with the same effective rule (the backend normalizes this case away, but the grouping must key on the effective rule, not the profile ID), an unrecognized rule type or
op(the subsection still appears, the line has no threshold, and the rule is logged), a rule box whose subsections are all hidden, a course whose subsections are all hidden, and placeholder counts of one and of several. - Walk
-
Rule text.
formatRuleText(rule, intl)insrc/ruleText.jsmapsgte,lte, andeqto their messages.- Format the threshold with
intl.formatNumber(value, { style: 'percent', maximumFractionDigits: 2 }), which scales the stored 0.0 to 1.0 fraction and absorbs floating-point error. A hand-rolled0.29 * 100gives28.999999999999996. - For an unknown rule type or
op, the function returns null, so that line renders without a threshold, and the transform logs the unknown rule once. - A bottom-tier group's
logic_operatorreads AND as "all", and OR or null as "any". The course-level group's operator appears between bottom-tier groups, with null read as OR, per ADR 0002. - The placeholder row's text is one ICU plural message, so translators control the singular and plural forms.
- Write the strings in
src/messages.jsin sentence case, and uppercase them with Paragon'stext-uppercaseclass, so translators don't receive all-caps source strings.
- Format the threshold with
-
Components.
CompetencyProgressPanelkeeps its name and takes no props. It readscourseIdfromuseProgressRouteParamsand callsuseCompetencyCards. It returns null unless both queries have data and the criteria response is non-empty; that single check covers loading, either request failing, and an empty result.CompetencyCardandCriteriaGroupListtake the transform's output as plain props. The transform needs no try/catch, because the slot's error boundary and [FE] Render placeholder CBE progress widgets in both learner Progress tab slots #829'sSilentErrorFallbackalready contain a render-time throw. -
Packaging and wiring. Add
@tanstack/react-querytopackage.jsonas a peer dependency at"^5", because passing the client asuseQuery's second argument is v5 API. The Learning MFE on master already depends on v5, so the package reuses the host's copy. Both registrations in [FE] Render placeholder CBE progress widgets in both learner Progress tab slots #829'sgetPluginSlotsstay as they are; [FE] Render placeholder CBE progress widgets in both learner Progress tab slots #829's sidebar placeholder remains visible until [Placeholder - FE] Build a right sidebar (or central) display of top level competencies ("Focus Areas") with their Competency status displayed. #743 replaces it.
Files to create and modify
Paths are relative to the root of the plugin repository from #810.
| File | Change |
|---|---|
src/CompetencyProgressPanel.jsx |
modified: the real panel replaces #829's placeholder |
src/CompetencyCard.jsx |
new: breadcrumb, heading, heading's own groups, child rows, nested path rows under an ancestor with criteria |
src/CriteriaGroupList.jsx |
new: bottom-tier groups, separators, rule lines, subsections, placeholder rows |
src/ruleText.js |
new: formatRuleText |
src/messages.js |
new |
src/data/api.js |
new |
src/data/queryClient.js |
new |
src/data/apiHooks.js |
new |
src/data/buildCompetencyCards.js |
new |
package.json |
modified: @tanstack/react-query peer dependency |
Additional context
- ADR 0002 in openedx-core,
docs/openedx_learning/decisions/0002-competency-criteria-model.rst, is the source for the Grade rule payload and thelogic_operatorsemantics. - [FE] Create & View Competency Criteria #672 defines how the Competency Management page derives and orders rule boxes. Its code lives in frontend-app-authoring's
src/taxonomy/competency-management/. - In openedx-platform,
openedx/core/djangoapps/content/learning_sequences/views.py(CourseOutlineView) defines the outline response, andopenedx/core/djangoapps/content/learning_sequences/api/processors/defines what a learner's outline leaves out.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsFinal Axim Review
- StatusShow more project fieldsNo status
Activity
[-][Placeholder - FE] Build collapsable table display of Competency Criteria on the Course Progress page[/-][+][FE] Build cards displaying Competency Criteria on the Course Progress page[/+]thelmick-unicon commentedon Oct 13, 2026
The discussion period for this ticket is now complete, and we appreciate all the feedback. We'll be moving forward with development based on the current ticket pending final Axim sign-off. That said, the conversation doesn't have to stop. If you still have feedback, please continue to add to this ticket. We'll review anything new and determine whether it fits within the current timeline or makes more sense as its own ticket for future work. Thanks again for helping make this better!
@jmakowski1123 This is ready for your final review. Thank you!