Skip to content

[FE] Explain archived competency rules in the Courses & Content panel #841

Open

Description

@thelmick-unicon

User Story

As a course author, I need to know which courses' rules for a competency were archived, in order to understand why I can't add new Competency Criteria associations for that course.

Description

This ticket updates the Courses & Content panel so that when a course's course-level group for the selected competency is archived, expanding that course shows a sentence explaining the situation instead of displaying the course's sections and gradeable subsections. This should work like the "This course has no gradeable subsections." text that already appears in an expanded course row. The list of archived courses comes from the archived_course_keys field that #840 adds to #681's response.

Context

UX Design

Image Image Image

Acceptance Criteria

Scenario: Expanding an archived course shows the archived-rules message instead of its outline
  Given I have selected a competency
  And course run X's course-level group for that competency is archived
  When I expand course run X in the Courses & Content panel
  Then in place of its sections and gradeable subsections, the row shows the archived-rules
    message: "This course's rules for this competency were archived, so no new competency
    criteria associations can be added. This applies only to this course run. Learners'
    recorded progress is kept."
  When I collapse course run X and expand it again
  Then the row shows the archived-rules message again

Scenario: An archived course stays in the course list and can be found by search
  Given course run X's course-level group for the selected competency is archived
  When I view the page of the Courses & Content panel's course list that course run X falls on,
    with no search term or date range applied
  Then course run X is listed there with its expand control, like any other course
  When I search for course run X's title
  Then course run X is among the results
  And expanding it shows the archived-rules message

Scenario: An archived course on another page of the course list shows the message there
  Given course run X's course-level group for the selected competency is archived
  And course run X is listed on a different page of the Courses & Content panel's course list
    than the one I am viewing
  When I move to the page that lists course run X and expand it
  Then the row shows the archived-rules message in place of its outline

Scenario: A course with an active course-level group shows its normal outline, even with archived Rule Groups or criteria under it
  Given course run Y's course-level group for the selected competency is active
  And some of its Rule Groups or criteria for that competency are archived
  When I expand course run Y
  Then its sections and gradeable subsections are shown as usual
  And the archived-rules message is not shown

Scenario: The message follows the selected competency
  Given course run X's course-level group is archived for competency A
  And course run X's course-level group for competency B is not archived
  When I select competency B and expand course run X
  Then its sections and gradeable subsections are shown as usual
  When I select competency A and expand course run X
  Then the row shows the archived-rules message

Scenario: Another run of the same course is unaffected
  Given course run X1's course-level group for the selected competency is archived
  And course run X2 is another run of the same course whose course-level group for that
    competency is not archived
  When I expand course run X2
  Then its sections and gradeable subsections are shown as usual

Scenario Outline: The archived-rules message replaces every other state of the course's content
  Given course run X's course-level group for the selected competency is archived
  And <other state>
  When I expand course run X
  Then the row shows only the archived-rules message in place of its outline

  Examples:
    | other state                                                                             |
    | a competency above or below the selected one already has an association in course run X |
    | I can see course run X but do not have write access to it                               |
    | course run X has no gradeable subsections                                               |
    | course run X's outline cannot be loaded                                                 |

Scenario Outline: While the associations panel's data is loading, an expanded course shows a loading indicator
  Given the associations panel's data has not finished loading, because <reason>
  When I expand a course run
  Then the row shows a loading indicator in place of its outline, with no control for adding an association
  When the associations panel's data finishes loading
  Then without a page reload, the row shows the archived-rules message if that course run's course-level group is archived, and its sections and gradeable subsections otherwise

  Examples:
    | reason                                                  |
    | I just selected the competency                          |
    | I moved to another page of the course list or searched  |

Scenario: If the associations panel's data fails to load, an expanded course shows its outline with no controls for adding an association
  Given the associations panel's data failed to load
  When I expand a course run
  Then its sections and gradeable subsections are shown
  And no subsection offers a control for adding an association

Scenario: A delete that archives a course's rules switches its expanded row without a reload
  Given learners have recorded progress against the selected competency's rules in course run X
  And course run X is expanded in the Courses & Content panel, showing its outline
  When I delete everything course run X has for this competency, whether by deleting its
    course section, its last Rule Group, its last Rule Box, or its last association in the
    Competency Criteria Associations panel, or by removing its last association from its chip
    in course run X's own outline in the Courses & Content panel
  Then without a page reload, course run X's expanded row shows the archived-rules message in
    place of its outline
  And any other expanded course already showing the archived-rules message keeps showing it
    throughout, with no loading indicator in between

Scenario: A delete that removes a course's rules outright leaves its outline in place
  Given no learner has recorded progress against the selected competency's rules in course run X
  And course run X is expanded in the Courses & Content panel, showing its outline
  When I delete everything course run X has for this competency
  Then course run X's expanded row keeps showing its outline
  And the archived-rules message is not shown

Scenario: Keyboard focus moves to the message when the control I was on is replaced
  Given learners have recorded progress against the selected competency's rules in course run X
  And course run X is expanded, and I have used only the keyboard to reach the chip for its last association in its outline
  When I remove that association from the chip
  Then course run X's row shows the archived-rules message in place of its outline
  And keyboard focus moves to the message, so a screen reader reads it

Scenario: The message is not announced when my keyboard focus is elsewhere
  Given course run X is expanded, and keyboard focus is outside course run X's row
  When a delete replaces course run X's outline with the archived-rules message
  Then keyboard focus stays where it was
  And the message is not announced by a screen reader
Technical 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 archived list that #840 adds to #681's response is read from the #681 query that #672's provider already runs, and is exposed as isCourseArchived(courseId) next to canEditCourse. An expanded CourseRow for an archived course renders the new message instead of mounting CourseOutlineSubtree, so the outline is never fetched. Until that query has data, an expanded row shows a loading indicator. If the query failed, the row shows its outline without the controls for adding an association.

Approach

  1. Add archivedCourseKeys: string[] to [BE] GET Competency Criteria & Groups #681's response type in data/types.ts. camelCaseObject changes only the key, so each value matches a course.courseKey as it is.
  2. Add isCourseArchived(courseId) to the CompetencyAssociationsContext value next to canEditCourse. Back it with a Set memoized from data?.archivedCourseKeys ?? [] on the provider's existing useCompetencyCriteriaGroups query, and have the context's no-op default return false. Because the value rides on that query, it needs no new request and adds no invalidation to [FE] Delete Competency Course & Rule Groups #709, [FE] Manage & Apply Competencies: delete a Competency Criteria Association #710, or [FE] Delete a Competency Rule Box #833: the refetch those deletes already make is what switches a newly archived course. Reading ?? [] also means an MFE running against a backend without [BE] Add Archived Course Keys to GET Competency Criteria & Groups Endpoint #840 treats every course as not archived.
  3. Also add associationsStatus to the context value: ready whenever the query has data, even if a later background refetch failed; otherwise error if the query failed, and loading if it hasn't finished. Because ready follows data alone, the refetch after a delete never shows the loading indicator, and a row already showing the message keeps it through that refetch. The list a row reads during a refetch can be stale, but only by leaving out a course archived since it loaded, because a course-level group can't be unarchived.
  4. In course-search/CourseRow.tsx, when the row is expanded:
    • While associationsStatus is loading, render a Paragon Spinner instead of mounting CourseOutlineSubtree.
    • When isCourseArchived(course.courseKey) is true, render a new archivedCourseRulesMessage from course-search/messages.ts instead of mounting CourseOutlineSubtree. Use the same markup as noGradedSubsectionsMessage, with no live region. Not mounting the subtree skips the outline fetch, because the subtree's own mount is its fetch gate. It also makes the message replace [FE] Manage & Apply Competencies: disable dominance-ineligible content before selection #797's disabled content and the permission-gated controls, which all live inside the outline.
    • Otherwise mount CourseOutlineSubtree. The subsection select control [FE] Create & View Competency Criteria #672 adds to the outline is offered only when associationsStatus is ready, in addition to its existing canEditCourse check.
  5. When the row switches from the outline to the message and keyboard focus was inside the outline, move focus to the message, which needs tabIndex={-1}. Otherwise leave focus alone. Record whether focus is inside the outline on the row's container while the outline is shown, because once the focused control is removed the browser has already moved focus to the page body.
  6. Test two edge cases:

Out of scope:

Files to create and modify

File Change
src/taxonomy/competency-management/data/types.ts (path provisional) modified: add archivedCourseKeys
src/taxonomy/competency-management/CompetencyAssociationsContext.tsx (path provisional) modified: add isCourseArchived and associationsStatus
src/taxonomy/competency-management/course-search/CourseRow.tsx modified: render the loading indicator or the message in place of CourseOutlineSubtree, and move keyboard focus to the message
the subsection select control #672 adds to the outline modified: offered only when associationsStatus is ready
src/taxonomy/competency-management/course-search/messages.ts modified: add archivedCourseRulesMessage

Additional context

Activity

  1. thelmick-unicon commented on Oct 13, 2026

    @thelmick-unicon
    Author

    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!

  2. illiphilli commented on Oct 13, 2026

    @illiphilli

    @thelmick-unicon @tbain the designs for this ticket are ready.

    Figma (CBE Stories, section 7, third row): A1 · Archived message · A2 · Loading · A3 · Load failed

    A1 · Expanding an archived course

    The message replaces the outline, using the AC's copy word for word. It uses the same markup as "This course has no gradeable subsections." (<div className="small">), so it needs no new styling. The course stays in the list and in search, and only its expanded row changes.

    A2 · While the associations data loads

    <LoadingSpinner size="sm" /> replaces the outline, with no add controls. After a remove, the refetch doesn't show the spinner: the row switches straight from the outline to the message.

    A3 · If the associations data fails to load

    The outline shows, but no subsection offers the control for adding an association.

    Accessibility

    • If the control I was on is removed (for example, the last chip in this course's outline), focus moves to the message, which has tabIndex={-1}. A screen reader then reads it.
    • If my focus was elsewhere, it stays there and nothing is announced. There's no live region, which matches the AC.

    In Figma, these are new variants of the Course component (Archived, Loading, Outline only), so Dev Mode shows each state directly.

    Image Image Image
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions