Skip to content

[FE] Build the competency-selection tree, Course Search, and gradeable-subsection browse UI for Competency Criteria Associations #670

Description

@thelmick-unicon

Blocked by: #669 (the accessible-courses-by-date endpoint + course outlines) — a TBD contract; wire against it and flag real paths as fill-in-later. The competency tree itself has no new backend dependency — it reuses the existing taxonomy tags list API (a competency is a Tag in a competency taxonomy; that endpoint already returns them).

Repo: frontend-app-authoring. MFE-only. This ticket is #670; the select/deselect-association UI is #672.

Use Case

As a Platform Administrator configuring Competency Criteria associations, I want to select a competency from the taxonomy's competency tree and then search the courses I have access to (filtered by course-run start date), browse a course's sections and gradeable subsections, so that I can find the exact gradeable subsection to attach criteria to without opening each course individually.

Description

Current state

No implementation exists. #623 built only a placeholder Competency Management page (/taxonomy/:taxonomyId/competencies) whose real content is deferred to future tickets; this is one. There is no left-hand competency tree in code yet: #648 designs the shell and that tree, but no implementation ticket builds it, and this is the first ticket that needs a competency actually selected. Studio's existing StudioHome course listing is general and competency-unaware, with no date-range filter and no drill-down into a course's gradeable structure.

Requested change

Build the Manage & Apply Competencies associations workspace: a minimal two-panel layout with a competency-selection tree on the left and the course-browsing panel on the right, driven by the selected competency.

  1. Minimal competency-selection tree (left panel). Render the current taxonomy's competencies as a selectable tree (nested competencies with their codes). Selecting a competency sets the active competency and populates/refreshes the right-hand panel against it. Reuse the existing tag-tree rendering; this is the minimal functional tree, not the finished shell. Expand/collapse polish, switcher styling, empty-state design, and responsive spec are [UXD] Build the UI for Competency Criteria Associations #648's; the Competency ID badge on rows is a separate ticket's. Neither is built here.
  2. Course search with a start-date range filter (right panel). A title search plus a date-range picker, scoped to the selected competency. Use React Date Picker lightly styled with Paragon (Paragon has no native range picker). For MVP the range filters on course-run start date only; make that explicit to the user ("courses whose start date falls between X and Y"). Results come from [BE] Add start-date range filter and outline delivery for accessible courses (Competency Criteria Associations) #669 (paginated accessible courses).
  3. Browse each course's outline. Expanding a course reveals its sections and gradeable subsections (from the course outline — see [BE] Add start-date range filter and outline delivery for accessible courses (Competency Criteria Associations) #669 / CourseIndexView). Sections are navigation; only gradeable subsections are the actionable leaves. For this ticket the subsections are read-only (browse only); making them actionable for association is [Placeholder for FE] Build the select / deselect gradeable-subsection association interactions #672.

Figma Design

Explicitly out of scope

Acceptance Criteria

Frontend ticket.

Scenario: Competency tree lists the taxonomy's competencies
  Given I open the Manage & Apply Competencies page for a competency taxonomy
  Then the left panel shows that taxonomy's competencies as a nested tree

Scenario: Selecting a competency drives the right-hand panel
  Given the competency tree is shown
  When I select a competency
  Then it becomes the active competency
  And the right-hand course-browse panel loads for that competency

Scenario: No competency selected yet
  Given I open the page and have not selected a competency
  Then the right-hand panel prompts me to select a competency
  And no course search runs until one is selected

Scenario: Search courses by title
  Given I have selected a competency and am viewing the course-browse panel
  When I enter a title filter
  Then the course list narrows to accessible courses whose title matches

Scenario: Filter courses by start-date range
  Given I am viewing the panel
  When I set a start and end boundary in the date-range picker
  Then the list shows only courses whose course-run start date falls within that range
  And courses with no start date still appear
  And the UI makes clear the filter is on course start date

Scenario: Default view shows all accessible courses
  Given I have entered no title filter and no date range
  When the panel loads
  Then it shows all courses I have access to

Scenario: Expand a course to browse its gradeable subsections
  Given a course appears in the results
  When I expand it
  Then its sections and gradeable subsections are displayed
  And the course and section rows are navigation only, not selectable as association targets

Scenario: Course search fails
  Given the #669 course-search call fails
  Then an inline error state is shown, distinct from an empty-results state

Scenario: No matching courses
  Given the search/filter matches no accessible course
  Then an empty state is shown

Scenario: Small-screen rendering
  Given I view the page on a small screen
  Then the competency tree, search, date picker, and expand/collapse remain usable

Open Questions

Context

  • Decision: [UXD] Build the UI for Competency Criteria Associations #648 is being reframed as a parent UX-design ticket with implementation children. Because this is the first ticket that needs a competency selected, the minimal tree + selection belongs here rather than deferred to a later ticket.
  • Decision (MVP): the course filter is on course-run start date only; end-date filtering is deferred. React Date Picker (lightly styled with Paragon) fills the gap since Paragon has no native range picker.
  • Decision: criteria are associated only at the gradeable-subsection level; courses and sections are navigation, not association targets.
  • Competency tree data: the taxonomy tags list API already returns a competency taxonomy's tags (already satisfied, no backend work); the MFE data layer already carries them (TagData via useTagListData in src/taxonomy/data/apiHooks.ts, nested by TagTree in src/taxonomy/tag-list/tagTree.ts). No backend or data-layer change for the tree.
  • CourseIndexView (GET /api/contentstore/v1/course_index/{course_id}, openedx-platform): existing full course-outline endpoint (sections→subsections, with graded flag); the likely per-course outline source.
  • Tree-rendering precedents (frontend; none a drop-in): src/taxonomy/tag-list/tagTree.ts (TagTree nests a taxonomy's tags — the competency tree's basis); src/taxonomy/tree-table/ NestedRows/getSubRows (arbitrary-depth recursion, bundled with tag-CRUD context to strip); src/course-outline/OutlineTree.tsx (real 3-level course tree, hardcoded depth and dnd/XBlock-coupled). Reuse TagTree for the competency tree; borrow the recursion pattern for the course outline.
  • Selection-callback precedent: ComponentPickerContext's ComponentSelectedEvent = (c: {usageKey, blockType}) => void, already used for course-structure items via src/course-outline/outline-sidebar/AddSidebar.tsx — the shape to mirror for the ([Placeholder for FE] Build the select / deselect gradeable-subsection association interactions #672-bound) subsection-selected callback.
  • src/generic/datepicker-control/DatepickerControl.jsx (wraps react-datepicker): the single-date picker to compose into a from/to range.
  • [Placeholder for FE] Add Competency Management entry point to taxonomy actions menu #623: the placeholder Competency Management page this workspace lives inside.

Technical Notes

Files to Create

File Purpose
src/taxonomy/competency-management/associations/CompetencyAssociationsPanel.tsx Two-panel container: left competency tree + right course-browse panel; owns the selected-competency state that drives the right panel
src/taxonomy/competency-management/associations/CompetencyTree.tsx Minimal selectable competency tree for the current taxonomy; reuses TagTree/tree-table recursion; emits the selected competency. No ID badge (separate ticket), no CRUD affordances
src/taxonomy/competency-management/course-search/index.ts Public interface exporting the browse panel component
src/taxonomy/competency-management/course-search/CourseSearchBrowse.tsx Search + date-range filter + paginated course list; each row expands to the outline tree; takes the active competency as input
src/taxonomy/competency-management/course-search/CourseOutlineTree.tsx Recursive section→gradeable-subsection renderer; borrows NestedRows' recursion pattern, no TanStack/CRUD context
src/taxonomy/competency-management/*/messages.ts i18n strings
src/taxonomy/competency-management/course-search/data/api.ts getCourseSearchResults(params) (#669), getCourseOutline(courseKey) (CourseIndexView or #669 inline, per decision)
src/taxonomy/competency-management/course-search/data/apiHooks.ts React Query hooks for course search and outline
src/taxonomy/competency-management/course-search/data/queryKeys.ts Query-key factory
src/taxonomy/competency-management/**/*.test.tsx RTL: tree renders + selection drives the panel + no-selection prompt; search, date filter (start-date semantics + null-start inclusion), expand, empty/error states

Files to Modify

File Nature
src/taxonomy/competency-management/index.ts Re-export CompetencyAssociationsPanel alongside CompetencyManagementPage (from #623)
the #623 Competency Management page component Mount CompetencyAssociationsPanel as the page's real content, replacing the placeholder

Implementation Notes

Competency tree (minimal). Reuse useTagListData (src/taxonomy/data/apiHooks.ts), which already returns a taxonomy's tags, and TagTree (src/taxonomy/tag-list/tagTree.ts) to render the current taxonomy's competencies as a nested, selectable tree. The taxonomy id comes from the /taxonomy/:taxonomyId/competencies route (#623). Track the selected competency in CompetencyAssociationsPanel state and pass it (tag id / external_id) to the browse panel as its active competency. Keep it minimal: no ID badge (separate ticket), no create/remove or other CRUD affordances, no switcher/empty-state/responsive polish (#648). Until a selection is made, the right panel shows a "select a competency" prompt and runs no course query.

Course browse. Compose two data sources client-side: #669 for the course list (start-date filter, pagination) and the outline per course (lazily on expand, via CourseIndexView unless #669 returns it inline).

Date filter: compose two DatepickerControl instances into a from/to range bound to #669's start-date parameter; label it as filtering on course start date. Don't send an end-date filter (MVP).

Build CourseOutlineTree as a plain recursive component (borrow NestedRows' childRowsData/depth shape; skip its TanStack table and CRUD context). Filter outline nodes to sections (navigation) and gradeable subsections (the actionable leaves) using the outline's graded flag; don't render unit/component levels. Subsections are read-only here; a gradeable-subsection click exposes a selected-subsection callback ({usageKey, blockType}, mirroring ComponentSelectedEvent) for the #672 select/associate flow to consume — this ticket fires the callback and does nothing else with it.

MFE-only; no ADR. Reuses frontend-app-authoring conventions (React Query, feature-folder, Paragon, defineMessages).

Example Resolution Prompt

In frontend-app-authoring, build the Competency Criteria associations workspace at src/taxonomy/competency-management/. CompetencyAssociationsPanel.tsx: a two-panel layout that owns the selected-competency state. Left panel CompetencyTree.tsx: render the current taxonomy's competencies (taxonomy id from the /taxonomy/:taxonomyId/competencies route, #623) as a minimal selectable nested tree, reusing useTagListData (src/taxonomy/data/apiHooks.ts) and TagTree (src/taxonomy/tag-list/tagTree.ts); selecting a competency sets it active and drives the right panel; no ID badge (a separate ticket), no CRUD, no shell polish (#648). Right panel course-search/CourseSearchBrowse.tsx: until a competency is selected show a prompt and run no query; once selected, a title search + a from/to date-range filter built from two src/generic/datepicker-control/DatepickerControl.jsx instances, bound to #669's course-search endpoint (accessible courses filtered by course-run start date only; label it as such; courses with no start date still appear). Paginated course list; each row expands. On expand, render CourseOutlineTree.tsx: fetch the course outline (via the existing CourseIndexView, GET /api/contentstore/v1/course_index/{course_id}, unless the team has #669 return it inline — confirm), a plain recursive renderer (model on src/taxonomy/tree-table/NestedRows.tsx's recursion, without its TanStack table or TreeTableContext) showing sections (navigation) and gradeable subsections (read-only leaves, filtered by the outline graded flag). A gradeable-subsection click fires an onSubsectionSelected({ usageKey, blockType }) callback (mirror ComponentPickerContext's ComponentSelectedEvent) and does nothing else — the #672 flow consumes it. Mount the panel as the #623 page's real content. Do NOT build any backend endpoint, any course-level or section-level association, a Programs button, or a course-associate button. Tests: tree renders and selection drives the panel, no-selection prompt, title search, start-date filtering incl. null-start inclusion, expand-to-outline, empty and error states, small-screen.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Final Axim Review

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions