Skip to content

Commit acddd79

Browse files
docs: ADR for Visually Configuring Course Components (#36856)
--------- Co-authored-by: Maksim Sokolskiy <[email protected]>
1 parent 51ac947 commit acddd79

4 files changed

Lines changed: 144 additions & 0 deletions
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
Course Component Types Page
2+
###########################
3+
4+
**Status**: Proposed
5+
**Date**: 2025‑06‑02
6+
**Target release**: Verawood
7+
8+
-----
9+
10+
Problem Statement
11+
*****************
12+
13+
Course authors currently enable or disable XBlocks for each course via Advanced Settings → "Advanced modules" and the corresponding JSON configuration fields. This user interface is rather difficult for the average user to navigate: it ties the Studio UI to low‐level block keys that the user must locate in documentation or block code, and it does not display any block metadata (documentation, support level, etc.).
14+
15+
The new **Course Component Types page** (see *Figure 1*) provides a catalog-style interface where authors can browse, search, and enable blocks. To support this page, we must:
16+
17+
* Store canonical metadata for each installed XBlock.
18+
* Store activation for each course.
19+
* Safely transfer the existing configuration.
20+
* Synchronize the functionality of the new block addition flow from the Course Component Types page and the old one through Advanced modules until it is removed.
21+
22+
Architectural diagrams (*Figures 2 and 3*) illustrate the interaction during execution.
23+
24+
25+
Decision
26+
********
27+
28+
Domain Models
29+
=============
30+
31+
.. list-table:: Domain Models
32+
:widths: 25 35 40
33+
:header-rows: 1
34+
35+
* - Model
36+
- Responsibility
37+
- Key Fields
38+
* - **ComponentType**
39+
- Canonical catalog record for an XBlock type. Contains fields for global overrides specified in the subtitle, description, documentation urls block.
40+
- ``title``, ``slug`` (entry‑point name), ``enabled`` *(global default)*, ``support_level`` *(global default)*, ``component_type`` (``common`` | ``advanced`` | ``external``, default=``advanced``), ``created``, ``updated``, ``is_experimental``, ``title`` (optional override), ``subtitle`` (optional override), ``description`` (optional override), ``documentation_url`` (optional override).
41+
* - **CourseComponentType**
42+
- Join between ``ComponentType`` and ``CourseKey`` storing per‑course enablement.
43+
- ``id``, ``course_key``, ``content_block``, ``enabled``, ``created``, ``updated``, ``configurable_fields`` (JSON).
44+
45+
Both models live in the existing app ``common.djangoapps.xblock_django``. A unique constraint ``(course_key, content_block)`` prevents duplicates.
46+
47+
Bootstrap and migration
48+
=======================
49+
50+
* Created json with a list of default component types. (The list of component types and data about them can be viewed here_) (All other component types will be marked as experimental during migration)
51+
* Created a migration that fills in the records in `ComponentType` according to the specified json and creates records for each course in CourseComponentType for the enabled component types.
52+
* Created a migration/management command that scans all types of components added to the Advanced modules list and creates corresponding entries in ComponentType if a component with such a slug exists/is available in entry_points. Creates entries in CourseComponentType according to the enabled component types in courses.
53+
54+
.. _here: https://openedx.atlassian.net/wiki/spaces/COMM/database/4499341322
55+
56+
57+
Runtime APIs
58+
============
59+
60+
.. list-table:: Runtime APIs
61+
:widths: 30 10 60
62+
:header-rows: 1
63+
64+
* - Endpoint
65+
- Method
66+
- Purpose
67+
* - ``/api/course_component_types/v1/<course_id>/``
68+
- GET
69+
- Return **all enabled component types** for a course. Supports ``?component_type=common|advanced|external`` filter.
70+
* - ``/api/course_component_types/v1/<course_id>/``
71+
- POST
72+
- Add a new component type to the course. The request body must contain ``slug`` (entry‑point name). If the component type is enabled globally, it will be enabled for the course. If the component type is not enabled globally, it shouldn't be added to the course.
73+
* - ``/xblock/<usage_key>/<view_name>`` (configurable_fields_info|metadata_info)
74+
- GET
75+
- **XBlock Info Handler** (*Fig. 3*) to return ``metadata``(``title``, ``subtitle``, ``description`` etc.) or data about ``configurable_fields`` like a field name, type, value, help etc.
76+
* - ``/api/course_component_types/v1/<course_id>/<slug>/``
77+
- POST
78+
- Persist author edits to component type specific configuration fields (dynamic schema) and store to ``CourseComponentType`` as JSON.
79+
80+
81+
Serializers source immutable metadata from ``ComponentType``, then layer per‑course overrides from ``CourseComponentType``.
82+
83+
New mixin
84+
=========
85+
86+
* **``StudioConfigurableXBlockMixin``** Adds and lists the configuration fields of the component. These fields are also added to the non_editable_fields of the block so that they cannot be changed from the edit form on the unit page. The list of configuration fields can be overridden in the child classes of the corresponding blocks. The mixin also adds default values for metadata fields such as title, subtitle, description, and documentation links. At the same time, it provides an interface for obtaining the values of these fields, as they can be overwritten by the administrator in BlockConfig (shown in the diagram).
87+
88+
Waffle Flag `...enable_course_component_types_page`
89+
===================================================
90+
91+
.. list-table:: Waffle Flag ``...enable_course_component_types_page``
92+
:header-rows: 1
93+
94+
* - Flag state
95+
- Behaviour
96+
* - **Enabled**
97+
- "Course Component Types" appears under *Content* menu; Course Component Types page is accessible.
98+
* - **Disabled**
99+
- Legacy behaviour intact, Course Component Types page is hidden.
100+
101+
Advanced Modules Field Deprecation
102+
==================================
103+
104+
The "Advanced module list" field is hidden by default as an deprecated field. It is displayed after clicking the "Show deprecated settings" button and is marked as deprecated. The "Advanced module list" field still retains its full functionality but will be removed over time.
105+
106+
107+
Consequences
108+
************
109+
110+
* Every new installed XBlock must be added to the ``ComponentType`` table.
111+
* When a user adds a new component type to the Advanced modules list, a corresponding entry with a link to the course is created in CourseComponentType.
112+
* The "Course Component Types" page is discoverable and provides a better UX for course authors.
113+
* If a component type is not enabled in the "Advanced Modules" list, it will be hidden from the course author on the Studio unit page. They will not be able to add it to the course, but any components of that type that have already been added will continue to work. (This is the same as the current behavior.)
114+
* The new API endpoints allow for dynamic configuration of component types and retrieval of metadata.
115+
* The new mixin allows for easy addition of configuration fields to XBlocks and provides a consistent interface for metadata.
116+
* Many existing component types will be marked as experimental during migration, allowing for a gradual transition to the new system.
117+
* The "Advanced module list" field is deprecated, and its functionality will be removed in the future.
118+
* Many new DB entries will be created during the migration, but this is a one‑time cost.
119+
120+
121+
Rejected Alternatives
122+
*********************
123+
124+
* **Hardcoded list of common blocks**: This would not allow for extensibility or dynamic configuration. To many configuration levels, it would be difficult to maintain and extend.
125+
* **Extend existing XBlockConfiguration model**: The current implementation of XBlockConfiguration and related models(XBlockStudioConfigurationFlag, XBlockStudioConfiguration) has complex logic and rather strange behavior (when adding a block to XBlockStudioConfiguration, all other blocks disappear on the unit page, including standard ones (html, problem, video), and there is no way to enable them separately). Also, since these are fairly old models, such a significant refactoring could cause significant problems with existing data.
126+
* **Ability to change block metadata fields on course level**: There is no need for this level, as it is unlikely that information such as component type name, description, or documentation links will need to be changed from course to course.
127+
128+
References
129+
**********
130+
131+
* **Figure 1** – *Course Component Types page*.
132+
133+
.. image:: images/course_component_types_page_design.png
134+
:alt: Course Component Types page
135+
136+
* **Figure 2** – *Course Component Types API*.
137+
138+
.. image:: images/course_component_types_api_diagram.png
139+
:alt: Course Component Types API
140+
141+
142+
* **Figure 3** – *Interaction diagram of the content block’s sidebar tabs*.
143+
.. image:: images/course_component_types_system_diagram.png
144+
:alt: Interaction diagram of the content block’s sidebar tabs
192 KB
Loading
201 KB
Loading
1.15 MB
Loading

0 commit comments

Comments
 (0)