docs: V2 Content Editors ADR (#72)
This PR adds an overarching ADR for the V2 Content Editors framework, as well as several other, smaller, ADRs related to architectural abstractions.
This commit is contained in:
68
docs/decisions/0003-V2-Content-Editors.rst
Normal file
68
docs/decisions/0003-V2-Content-Editors.rst
Normal file
@@ -0,0 +1,68 @@
|
||||
V2 Content Editors
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
We have created a framework for creating improved editor experiences for existing xblocks. We call these new editors V2 Content Editors.
|
||||
V2 Content Editors replace existing xblock editing experiences using redirection.
|
||||
The V2 Editor framework allows for the easy creation and configuration of new editors through automated boilerplate generation, simple networking and state abstractions, and premade components for basic editing views.
|
||||
|
||||
Decisions
|
||||
------
|
||||
|
||||
I. All V2 content editors shall live in this repository. This choice was made as the existing xblock framework is not amenable to running modern React applications for studio views, and cannot be upgraded to do so without herculanean effort.
|
||||
|
||||
II. These editors will be served to the user as if an overlay on the existing editing experience for a particular xblock. This shall occur by this library's editor comoponent being served from a learning context MFE (Library or Course Authoring).
|
||||
|
||||
III. The Editor component is loaded into a learning context authoring tool (eg. Course or Library Authoring) from this JS library. This component then serves the correct editor type based on the xblock id it is provided.
|
||||
|
||||
IV. Editors for a specific xblock are then provided with the relevant data and metadata of that xblock instance, and their code is run to provide the experience.
|
||||
|
||||
V. The following process was implemented to inject this flow into Studio.
|
||||
|
||||
For entering an editor page: Users click on the "edit xblock" button, are redirected to the course authoring MFE, where they are presented with the relevant editor.
|
||||
|
||||
.. image:: https://user-images.githubusercontent.com/49422820/166940630-51dfc25e-c760-4118-b4dd-ae1fa7fa73b9.png
|
||||
|
||||
For saving content: Once inside the editor, clicking save saves the content to the xblock api and returns the user to the course authoring context.
|
||||
|
||||
.. image:: https://user-images.githubusercontent.com/49422820/166940624-068e8446-0c86-4c24-a2dd-3eb474984f08.png
|
||||
|
||||
For exiting without saving: The user is simply transported back to the course authoring context.
|
||||
|
||||
.. image:: https://user-images.githubusercontent.com/49422820/166940617-80455ade-0a5e-4e61-94b0-b9e2d7a0531e.png
|
||||
|
||||
VI. The library provides prebuilt components and features to accomplish common editor tasks.
|
||||
- The EditorContainer component makes for easy saving, canceling changes, and xblock title editing.
|
||||
- An app-level abstraction for network requests and handling thier states. This is the /Requests layer in the redux store. More information will be contained in ADR 0004 Network Request Layer
|
||||
VII. There are several patterns and principles along which the V2 editors are built. Additional editors are not required to follow these, but it is strongly encouraged. Theses are:
|
||||
- Following the Testing and Implementation ADR.
|
||||
- Generalize components for reuse when possible.
|
||||
- Use Redux for global state management.
|
||||
|
||||
VIII. How to create, configure, and enable a new editor experience will exist in other documentation, but should rely on automated configuration.
|
||||
|
||||
Status
|
||||
------
|
||||
|
||||
Adopted
|
||||
|
||||
Context
|
||||
-------
|
||||
|
||||
We need self-contained xblock editing and configuration experiences. Changing requirements require that that experience be modernized to use Paragon, work across authoring for different learning contexts (course authoring and library authoring), and be flexible, extensible and repeatable.
|
||||
|
||||
Carving experiences out of Studio is an architectural imperative. Editing, as xblocks are discrete pieces of content, can exist in a context independent of the learning context, so having a learning-context agnostic environment for editing makes sense.
|
||||
|
||||
Consequences
|
||||
------------
|
||||
|
||||
This design has several consequences. These consequences are the result of the favoring of incremental changes, which can be iterated upon as other improvements in the openedx ecosystem occur.
|
||||
|
||||
The majority of the impactful consequences have to do with the architectural choice to NOT simply upgrade the capabilities of xblock rendering, and instead serve the new experiences from a separate library. The fallout of these design choices leads to architectural complexity, but also the ability to deliver value in new ways.
|
||||
|
||||
For example, locating the V2 editor in frontend-lib-content-components outside of the xblock code leaves no clear solution for easy open-source extension of V2 editors. This choice, however, also allows us to easily serve library and course contexts and leads to the easier creation of common content react components.
|
||||
|
||||
In addition, this also allows developers to add value to editors, without having to rewrite the course-authoring experience to leverage React. Indeed, even when course authoring moves into an MFE, it will be trivial to place the editor inside the editor.
|
||||
|
||||
This choice, however, is not intended to be final. Instead, this library can become merely a set of tools and common components, and once xblock editor views are Reactified, we can very easily restore the abstraction that all xblock code lives with the xblock. It is in this spirit of providing incremental value that we provided this choice.
|
||||
52
docs/decisions/0004-Network-Request-Layer.rst
Normal file
52
docs/decisions/0004-Network-Request-Layer.rst
Normal file
@@ -0,0 +1,52 @@
|
||||
Network and Requests Layer
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
For V2 Content Editors, we have defined a general abstraction for basic editor actions and content retrieval. This abstraction is twofold: a defined set of general “app” actions for basic editor actions, and a Requests Layer to track the status of ALL network requests.
|
||||
|
||||
This will be a powerful tool to speed up the creation of new editors.
|
||||
|
||||
|
||||
|
||||
Decision
|
||||
------
|
||||
|
||||
The common actions required for any V2 content editor are as follows:
|
||||
Retrieve an xblock
|
||||
Save an xblock to the xblock api in the CMS.
|
||||
Return to your learning context (Studio, Course Authoring, Library Authoring)
|
||||
Obtain content (video, files, images) from the contentstore associated with a learning context.
|
||||
|
||||
We have implemented actions to perform those tasks in src/editors/data/redux/thunkActions/app.js. These actions are decoupled from the code of a specific editor, and are easily portable across editors.
|
||||
|
||||
We have also defined an atomic method to track the lifecycle of a network action. This abstraction applies to these common actions, as well as any actions defined in the data layer of a particular V2 editor.
|
||||
|
||||
The lifecycle of the acquisition of data from network and the updating of the global state with that data is termed to be a "request." The "states" of the lifecycle associated with a request are [inactive, pending, completed, failed]. This lifecycle provides information to the Redux consumer as to the status of their data.
|
||||
|
||||
Each unique request instance is given a key in `src/editors/data/constants/requests`. This key can be queried to ascertain the status of the request using a Redux selector by a consumer of the redux state. This allows for easy conditional rendering. By following this pattern, additional async actions will be easy to write.
|
||||
|
||||
The individual api methods are all defined in `data/services/cms/api`. The goal of the `requests` thunkActions is to first route the appropriate store data to the api request based on how they are being called.
|
||||
|
||||
The actual chain the an example request to save an xblock code is:
|
||||
|
||||
`thunkActions/app:saveBlock` -> `thunkActions/requests:saveBlock` `services/cms/api:saveBlock`
|
||||
|
||||
* The "app" thunk action updates the local block content, and then dispatches the request thunkAction
|
||||
* The "request" thunkAction then loads relevant redux data for the save event and calls the api.saveBlock method, wrapped such that the UI can track the request state
|
||||
* The "api" method provides the specifics for the actual network request, including prop format and url."
|
||||
|
||||
Status
|
||||
------
|
||||
|
||||
Proposed
|
||||
|
||||
Context
|
||||
-------
|
||||
|
||||
In building React Redux applications, asynchronous actions require a set of "Thunk" actions dispatched at relevant points. A common standard around the lifecycle helps prevent the boilerplate for these actions to spiral. In addition, it allows for the faster development of new V2 editors, as developers have easily usable Redux actions to dispatch, as well as Redux selectors to track the status of their requests.
|
||||
|
||||
Consequences
|
||||
------------
|
||||
|
||||
Network-based CRUD actions have a common language of lifecycle, as well as a common pattern to implement, allowing developers to use ready-made requests without issue for common actions, like xblock saving, content store retrieval, and even outside api access. This improves ease of use, as well as readability and uniformity.
|
||||
Reference in New Issue
Block a user