Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to redwood #207

Merged
merged 18 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ instructions, because git commits are used to generate release notes:

<!-- scriv-insert-here -->

<a id='changelog-18.0.0'></a>
## v18.0.0 (2024-06-19)

- 💥[Feature] Upgrade to Redwood (by @hinakhadim)
- [Feature] Enable `atlas pull` on all Micro-frontends. (by @omarithawi)
- 💥[Feature] Use `ATLAS_OPTIONS` for `atlas pull`. This breaks the `i18n-merge.js` custom locale Tutor MFE feature in favor of [OEP-58](https://docs.openedx.org/en/latest/developers/concepts/oep58.html) `atlas pull` options. (by @omarithawi)

<a id='changelog-17.0.1'></a>
## v17.0.1 (2024-03-26)

Expand Down
35 changes: 15 additions & 20 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ Adding new MFEs

- As of Tutor v16 (Palm release) it is no longer possible to add new MFEs by creating ``*_MFE_APP`` settings. Instead, users must implement the approach described below.
- As of Tutor v17 (Quince release) you must make sure that the git URL of your MFE repository ends with ``.git``. Otherwise the plugin build will fail.
- As of Tutor v18 (Redwood release) all MFEs must provide a ``make pull_translations`` command. Otherwise the plugin build will fail. Providing an empty command is enough to bypass this requirement. See the `Custom translations section <#mfe-custom-translations>`_ for more information.

Other MFE developers can take advantage of this plugin to deploy their own MFEs. To declare a new MFE, create a Tutor plugin and add your MFE configuration to the ``tutormfe.hooks.MFE_APPS`` filter. This configuration should include the name, git repository (and optionally: git branch or tag) and development port. For example:

Expand Down Expand Up @@ -163,32 +164,26 @@ To disable an existing MFE, remove the corresponding entry from the ``MFE_APPS``
mfes.pop("profile")
return mfes

Adding custom translations to your MFEs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This plugin makes it possible to change existing and add new translation strings to MFEs. Here is how to do it:

1. Identify the ID of the string you would like to translate. For instance, the ID of the "Account Information" string in the account MFE is "account.settings.section.account.information" (see `source <https://github.com/edx/frontend-app-account/blob/1444831833cad4746b9ed14618a499b425ccc907/src/account-settings/AccountSettingsPage.messages.jsx#L34>`__).
2. Create a folder and i18n file corresponding to your MFE app and language in the Tutor root. This location of this file should be ``/path/to/tutor/env/plugins/mfe/build/mfe/i18n/<app name>/<language code>.json``. For instance, to add French ("fr") translation strings to the account MFE, run::

cd "$(tutor config printroot)/env/plugins/mfe/build/mfe/i18n/"
mkdir account
touch account/fr.json
Using custom translations to your MFEs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

3. Add your entries to this file in JSON format, where the key is the string ID and the value is the actual string. For instance:
.. _mfe-custom-translations:

.. code-block::json
During docker image build, this plugin runs ``make pull_translations`` for each Micro-frontend. This
program is used in the ``Dockerfile`` to pull translations from the `openedx/openedx-translations repository <https://github.com/openedx/openedx-translations>`_ via `openedx-atlas <https://github.com/openedx/openedx-atlas>`_.

{
"account.settings.section.account.information": "Information du compte"
}
The ``make pull_translations`` command passes the ``ATLAS_OPTIONS`` environment variable to the ``atlas pull`` command. This allows specifying a custom repository or branch to pull translations from.

4. Rebuild the MFE image and restart the MFE with::
Translations in the MFE plugin as well as other Tutor plugins can be customized with the following configuration
variables:

tutor images build mfe
tutor local start -d
- ``ATLAS_REVISION`` (default: ``"main"`` on nightly and ``"{{ OPENEDX_COMMON_VERSION }}"`` if a named release is used)
- ``ATLAS_REPOSITORY`` (default: ``"openedx/openedx-translations"``).
- ``ATLAS_OPTIONS`` (default: ``""``) Pass additional arguments to ``atlas pull``. Refer to the `atlas documentations <https://github.com/openedx/openedx-atlas>`_ for more information.

Your custom translation strings should now appear in your app.
The
`Getting and customizing Translations <https://docs.tutor.edly.io/configuration.html#getting-and-customizing-translations>`_
section in the Tutor configuration documentation explains how to do this.

Customising MFEs
~~~~~~~~~~~~~~~~
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ def load_about():
packages=find_packages(exclude=["tests*"]),
include_package_data=True,
python_requires=">=3.8",
install_requires=["tutor>=17.0.0,<18.0.0"],
extras_require={"dev": ["tutor[dev]>=17.0.0,<18.0.0"]},
install_requires=["tutor>=18.0.0,<19.0.0"],
extras_require={"dev": ["tutor[dev]>=18.0.0,<19.0.0"]},
entry_points={"tutor.plugin.v1": ["mfe = tutormfe.plugin"]},
classifiers=[
"Development Status :: 5 - Production/Stable",
Expand Down
2 changes: 1 addition & 1 deletion tutormfe/__about__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "17.0.1"
__version__ = "18.0.0"
1 change: 1 addition & 0 deletions tutormfe/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
the tutor-mfe hooks would be created in the context of some other plugin that imports
them.
"""

from __future__ import annotations

import typing as t
Expand Down
6 changes: 4 additions & 2 deletions tutormfe/patches/openedx-lms-development-settings
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ MFE_CONFIG["ACCOUNT_SETTINGS_URL"] = ACCOUNT_MICROFRONTEND_URL
{% endif %}

{% if get_mfe("course-authoring") %}
MFE_CONFIG["ENABLE_NEW_EDITOR_PAGES"] = True
MFE_CONFIG["ENABLE_PROGRESS_GRAPH_SETTINGS"] = True
MFE_CONFIG["COURSE_AUTHORING_MICROFRONTEND_URL"] = "http://{{ MFE_HOST }}:{{ get_mfe("course-authoring")["port"] }}/course-authoring"
MFE_CONFIG["ENABLE_ASSETS_PAGE"] = "true"
MFE_CONFIG["ENABLE_HOME_PAGE_COURSE_API_V2"] = "true"
MFE_CONFIG["ENABLE_PROGRESS_GRAPH_SETTINGS"] = "true"
MFE_CONFIG["ENABLE_TAGGING_TAXONOMY_PAGES"] = "true"
{% endif %}

{% if get_mfe("discussions") %}
Expand Down
6 changes: 4 additions & 2 deletions tutormfe/patches/openedx-lms-production-settings
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ MFE_CONFIG["ACCOUNT_SETTINGS_URL"] = ACCOUNT_MICROFRONTEND_URL
{% endif %}

{% if get_mfe("course-authoring") %}
MFE_CONFIG["ENABLE_NEW_EDITOR_PAGES"] = True
MFE_CONFIG["ENABLE_PROGRESS_GRAPH_SETTINGS"] = True
MFE_CONFIG["COURSE_AUTHORING_MICROFRONTEND_URL"] = "{% if ENABLE_HTTPS %}https://{% else %}http://{% endif %}{{ MFE_HOST }}/course-authoring"
MFE_CONFIG["ENABLE_ASSETS_PAGE"] = "true"
MFE_CONFIG["ENABLE_HOME_PAGE_COURSE_API_V2"] = "true"
MFE_CONFIG["ENABLE_PROGRESS_GRAPH_SETTINGS"] = "true"
MFE_CONFIG["ENABLE_TAGGING_TAXONOMY_PAGES"] = "true"
{% endif %}

{% if get_mfe("discussions") %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const fs = require('fs');
const baseDevConfig = (
fs.existsSync('./webpack.dev.config.js')
? require('./webpack.dev.config.js')
: require('@edx/frontend-build/config/webpack.dev.config.js')
: require('@openedx/frontend-build/config/webpack.dev.config.js')
);

module.exports = merge(baseDevConfig, {
Expand Down
25 changes: 1 addition & 24 deletions tutormfe/templates/mfe/build/mfe/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,6 @@ RUN mkdir -p /openedx/app /openedx/env
WORKDIR /openedx/app
ENV PATH /openedx/app/node_modules/.bin:${PATH}

######## i18n strings
FROM base AS i18n
COPY ./i18n /openedx/i18n
RUN chmod a+x /openedx/i18n/*.js
RUN echo "copying i18n data" \
{%- for app_name, app in iter_mfes() %}
&& mkdir -p /openedx/i18n/{{ app_name }} \
{%- endfor %}
echo "done."

{% for app_name, app in iter_mfes() %}
####################### {{ app_name }} MFE
######## {{ app_name }} (git)
Expand All @@ -42,14 +32,6 @@ ADD --keep-git-dir=true {{ app["repository"] }}#{{ app.get("version", MFE_COMMON
FROM scratch as {{ app_name }}-src
COPY --from={{ app_name }}-git /openedx/app /

######## {{ app_name }} (i18n)
FROM base AS {{ app_name }}-i18n
COPY --from={{ app_name }}-src / /openedx/app
COPY --from=i18n /openedx/i18n/{{ app_name }} /openedx/i18n/{{ app_name }}
COPY --from=i18n /openedx/i18n/i18n-merge.js /openedx/i18n/i18n-merge.js
RUN stat /openedx/app/src/i18n/messages 2> /dev/null || (echo "missing messages folder" && mkdir -p /openedx/app/src/i18n/messages)
RUN /openedx/i18n/i18n-merge.js /openedx/app/src/i18n/messages /openedx/i18n/{{ app_name }} /openedx/app/src/i18n/messages

######## {{ app_name }} (common)
FROM base AS {{ app_name }}-common
COPY --from={{ app_name }}-src /package.json /openedx/app/package.json
Expand All @@ -65,13 +47,8 @@ RUN --mount=type=cache,target=/root/.npm,sharing=shared npm clean-install --no-a
{{ patch("mfe-dockerfile-post-npm-install") }}
{{ patch("mfe-dockerfile-post-npm-install-{}".format(app_name)) }}
COPY --from={{ app_name }}-src / /openedx/app
COPY --from={{ app_name }}-i18n /openedx/app/src/i18n/messages /openedx/app/src/i18n/messages

# Whenever a new MFE supports Atlas, it should be added to this list.
# When all MFEs support Atlas, this if-statement should be removed.
{% if app_name in ["communications"] %}
RUN make OPENEDX_ATLAS_PULL=true pull_translations
{% endif %}
RUN make OPENEDX_ATLAS_PULL=true ATLAS_OPTIONS="--repository={{ ATLAS_REPOSITORY }} --revision={{ ATLAS_REVISION }} {{ ATLAS_OPTIONS }}" pull_translations

EXPOSE {{ app['port'] }}

Expand Down
47 changes: 0 additions & 47 deletions tutormfe/templates/mfe/build/mfe/i18n/i18n-merge.js

This file was deleted.

42 changes: 38 additions & 4 deletions tutormfe/templates/mfe/tasks/lms/init
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,54 @@ site-configuration unset --domain={{ LMS_HOST }}:8000 ENABLE_PROFILE_MICROFRONTE

{% if is_mfe_enabled("learning") %}
(./manage.py lms waffle_flag --list | grep course_home.course_home_mfe_progress_tab) || ./manage.py lms waffle_flag --create --everyone course_home.course_home_mfe_progress_tab
(./manage.py lms waffle_flag --list | grep courseware.enable_navigation_sidebar) || ./manage.py lms waffle_flag --create --deactivate courseware.enable_navigation_sidebar
(./manage.py lms waffle_flag --list | grep courseware.always_open_auxiliary_sidebar) || ./manage.py lms waffle_flag --create --deactivate courseware.always_open_auxiliary_sidebar
{% else %}
./manage.py lms waffle_delete --flags course_home.course_home_mfe_progress_tab
./manage.py lms waffle_delete --flags courseware.enable_navigation_sidebar
./manage.py lms waffle_delete --flags courseware.always_open_auxiliary_sidebar
{% endif %}

{% if is_mfe_enabled("course-authoring") %}
(./manage.py lms waffle_flag --list | grep contentstore.new_studio_mfe.use_new_advanced_settings_page) || ./manage.py lms waffle_flag --create --everyone contentstore.new_studio_mfe.use_new_advanced_settings_page
(./manage.py lms waffle_flag --list | grep contentstore.new_studio_mfe.use_new_certificates_page) || ./manage.py lms waffle_flag --create --everyone contentstore.new_studio_mfe.use_new_certificates_page
(./manage.py lms waffle_flag --list | grep contentstore.new_studio_mfe.use_new_course_outline_page) || ./manage.py lms waffle_flag --create --everyone contentstore.new_studio_mfe.use_new_course_outline_page
(./manage.py lms waffle_flag --list | grep contentstore.new_studio_mfe.use_new_course_team_page) || ./manage.py lms waffle_flag --create --everyone contentstore.new_studio_mfe.use_new_course_team_page
(./manage.py lms waffle_flag --list | grep contentstore.new_studio_mfe.use_new_custom_pages) || ./manage.py lms waffle_flag --create --everyone contentstore.new_studio_mfe.use_new_custom_pages
(./manage.py lms waffle_flag --list | grep contentstore.new_studio_mfe.use_new_export_page) || ./manage.py lms waffle_flag --create --everyone contentstore.new_studio_mfe.use_new_export_page
(./manage.py lms waffle_flag --list | grep contentstore.new_studio_mfe.use_new_files_uploads_page) || ./manage.py lms waffle_flag --create --everyone contentstore.new_studio_mfe.use_new_files_uploads_page
(./manage.py lms waffle_flag --list | grep contentstore.new_studio_mfe.use_new_grading_page) || ./manage.py lms waffle_flag --create --everyone contentstore.new_studio_mfe.use_new_grading_page
(./manage.py lms waffle_flag --list | grep contentstore.new_studio_mfe.use_new_group_configurations_page) || ./manage.py lms waffle_flag --create --everyone contentstore.new_studio_mfe.use_new_group_configurations_page
(./manage.py lms waffle_flag --list | grep contentstore.new_studio_mfe.use_new_import_page) || ./manage.py lms waffle_flag --create --everyone contentstore.new_studio_mfe.use_new_import_page
(./manage.py lms waffle_flag --list | grep contentstore.new_studio_mfe.use_new_schedule_details_page) || ./manage.py lms waffle_flag --create --everyone contentstore.new_studio_mfe.use_new_schedule_details_page
(./manage.py lms waffle_flag --list | grep contentstore.new_studio_mfe.use_new_textbooks_page) || ./manage.py lms waffle_flag --create --everyone contentstore.new_studio_mfe.use_new_textbooks_page
(./manage.py lms waffle_flag --list | grep contentstore.new_studio_mfe.use_new_updates_page) || ./manage.py lms waffle_flag --create --everyone contentstore.new_studio_mfe.use_new_updates_page
(./manage.py lms waffle_flag --list | grep discussions.pages_and_resources_mfe) || ./manage.py lms waffle_flag --create --everyone discussions.pages_and_resources_mfe
(./manage.py lms waffle_flag --list | grep new_core_editors.use_new_text_editor) || ./manage.py lms waffle_flag --create --deactivate new_core_editors.use_new_text_editor
(./manage.py lms waffle_flag --list | grep new_core_editors.use_new_video_editor) || ./manage.py lms waffle_flag --create --deactivate new_core_editors.use_new_video_editor
(./manage.py lms waffle_flag --list | grep new_core_editors.use_new_problem_editor) || ./manage.py lms waffle_flag --create --deactivate new_core_editors.use_new_problem_editor
(./manage.py lms waffle_flag --list | grep new_core_editors.use_new_problem_editor) || ./manage.py lms waffle_flag --create --everyone new_core_editors.use_new_problem_editor
(./manage.py lms waffle_flag --list | grep new_core_editors.use_new_text_editor) || ./manage.py lms waffle_flag --create --everyone new_core_editors.use_new_text_editor
(./manage.py lms waffle_flag --list | grep new_core_editors.use_new_video_editor) || ./manage.py lms waffle_flag --create --everyone new_core_editors.use_new_video_editor
(./manage.py lms waffle_flag --list | grep new_studio_mfe.use_new_home_page) || ./manage.py lms waffle_flag --create --everyone new_studio_mfe.use_new_home_page
(./manage.py lms waffle_flag --list | grep new_studio_mfe.use_tagging_taxonomy_list_page) || ./manage.py lms waffle_flag --create --everyone new_studio_mfe.use_tagging_taxonomy_list_page
{% else %}
./manage.py lms waffle_delete --flags contentstore.new_studio_mfe.use_new_advanced_settings_page
./manage.py lms waffle_delete --flags contentstore.new_studio_mfe.use_new_certificates_page
./manage.py lms waffle_delete --flags contentstore.new_studio_mfe.use_new_course_outline_page
./manage.py lms waffle_delete --flags contentstore.new_studio_mfe.use_new_course_team_page
./manage.py lms waffle_delete --flags contentstore.new_studio_mfe.use_new_custom_pages
./manage.py lms waffle_delete --flags contentstore.new_studio_mfe.use_new_export_page
./manage.py lms waffle_delete --flags contentstore.new_studio_mfe.use_new_files_uploads_page
./manage.py lms waffle_delete --flags contentstore.new_studio_mfe.use_new_grading_page
./manage.py lms waffle_delete --flags contentstore.new_studio_mfe.use_new_group_configurations_page
./manage.py lms waffle_delete --flags contentstore.new_studio_mfe.use_new_import_page
./manage.py lms waffle_delete --flags contentstore.new_studio_mfe.use_new_schedule_details_page
./manage.py lms waffle_delete --flags contentstore.new_studio_mfe.use_new_textbooks_page
./manage.py lms waffle_delete --flags contentstore.new_studio_mfe.use_new_updates_page
./manage.py lms waffle_delete --flags discussions.pages_and_resources_mfe
./manage.py lms waffle_delete --flags new_core_editors.use_new_problem_editor
./manage.py lms waffle_delete --flags new_core_editors.use_new_text_editor
./manage.py lms waffle_delete --flags new_core_editors.use_new_video_editor
./manage.py lms waffle_delete --flags new_core_editors.use_new_problem_editor
./manage.py lms waffle_delete --flags new_studio_mfe.use_new_home_page
./manage.py lms waffle_delete --flags new_studio_mfe.use_tagging_taxonomy_list_page
{% endif %}

{% if is_mfe_enabled("discussions") %}
Expand Down