Package: tutor-mfe
This plugin makes it possible to easily add micro frontend (MFE) applications on top of an Open edX platform that runs with Tutor. To learn more about MFEs, please check theofficial Open edX documentation.In addition, this plugin comes with a few MFEs which are enabled by default:AuthnAccountCommunicationsCourse AuthoringDiscussionsGradebookLearner DashboardLearningORA GradingProfileInstructions for using each of these MFEs are given below.Installationtutor plugins install mfeUsageTo enable this plugin, run:tutor plugins enable mfe
tutor local launchWhen running the plugin in production, it is recommended that you set up a catch-all CNAME for subdomains at the DNS provider: see theConfiguring DNS Recordssection in the Tutor documentation for more details.  This way, the plugin will work out of the box with no additional configuration.  Which is to say, if yourLMS_HOSTis set tomyopenedx.comthe MFEs this plugin provides will be accessible underapps.myopenedx.comby default.To check what the current value ofMFE_HOSTis actually set to, run:tutor config printvalue MFE_HOSTAuthnThis is a micro-frontend application responsible for the login, registration and password reset functionality.AccountAn MFE to manage account-specific information for every LMS user. Each user’s account page is available athttp(s)://{{MFE_HOST}}/account. For instance, when running locally:https://apps.local.edly.io/account.CommunicationsThe Communications micro-frontend exposes an interface for course teams to communicate with learners.  It achieves this by allowing instructors to send out emails in bulk, either by scheduling them or on demand.Course AuthoringThis MFE is meant for course authors and maintainers. For a given course, it exposes a “Pages & Resources” menu in Studio where one can enable or disable a variety of features, including, for example, the Wiki and Discussions.  Optionally, it allows authors to replace the legacy HTML, Video, and Problem authoring tools with experimental React-based versions, as well as exposing a new proctoring interface that can be enabled if theedx-examsservice is available.DiscussionsThe Discussions MFE updates the previous discussions UI with a new look and better features.GradebookThis instructor-only MFE is for viewing individual and aggregated grade results for a course. To access this MFE, go to a course → Instructor tab → Student Admin → View gradebook. The URL should be:http(s)://{{MFE_HOST}}/gradebook/{{course ID }}. When running locally, the gradebook of the demo course is available at:http://apps.local.edly.io/gradebook/course-v1:edX+DemoX+Demo_CourseLearner DashboardThe Learner Dashboard MFE provides a clean and functional interface to allow learners to view all of their open enrollments, as well as take relevant actions on those enrollments.LearningThe Learning MFE replaces the former courseware, which is the core part of the LMS where students follow courses.ORA GradingWhen enabled, Open Response Assessments (“ORA”) that have a staff grading step will link to this new MFE, either when clicking “Grade Available Responses” from the exercise itself, or via a link in the Instructor Dashboard.  It is meant to streamline the grading process with better previews of submitted content.ProfileEdit and display user-specific profile information. The profile page of every user is visible athttp(s)://{{MFE_HOST}}/profile/u/{{username }}. For instance, when running locally, the profile page of the “admin” user is:http://apps.local.edly.io/profile/u/admin.MFE managementAdding new MFEsWarningAs of Tutor v16 (Palm release) it is no longer possible to add new MFEs by creating*_MFE_APPsettings. Instead, users must implement the approach described here.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 thetutormfe.hooks.MFE_APPSfilter. This configuration should include the name, git repository (and optionally: git branch) and development port. For example:from tutormfe.hooks import MFE_APPS

@MFE_APPS.add()
def _add_my_mfe(mfes):
    mfes["mymfe"] = {
        "repository": "https://github.com/myorg/mymfe",
        "port": 2001,
        "version": "me/my-custom-branch", # optional, will default to the Open edX current tag.
    }
    return mfesThe MFE assets will then be bundled in the “mfe” Docker image whenever it is rebuilt withtutor images build mfe.Assets will be served athttp(s)://{{MFE_HOST}}/mymfe. Developers are free to add extra template patches to their plugins, as usual: for instance LMS setting patches to make sure that the LMS correctly connects to the MFEs.Disabling individual MFEsTo disable an existing MFE, remove the corresponding entry from theMFE_APPSfilter. For instance, to disable some of the MFEs that ship with this plugin:@MFE_APPS.add()
def _remove_some_my_mfe(mfes):
    mfes.pop("account")
    mfes.pop("profile")
    return mfesAdding custom translations to your MFEsThis plugin makes it possible to change existing and add new translation strings to MFEs. Here is how to do it: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” (seesource).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/<appname>/<languagecode>.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.jsonAdd your entries to this file in JSON format, where the key is the string ID and the value is the actual string. For instance:{
  "account.settings.section.account.information": "Information du compte"
}Rebuild the MFE image and restart the MFE with:tutor images build mfe
tutor local start -dYour custom translation strings should now appear in your app.Customising MFEsTo change the MFEs logos from the default to your own logos, override the corresponding settings in the MFEs environment using patchesmfe-lms-production-settingsandmfe-lms-development-settings. For example, using the following plugin:from tutor import hooks

hooks.Filters.ENV_PATCHES.add_items(
    [
        (
            "mfe-lms-development-settings",
            """
    MFE_CONFIG["LOGO_URL"] = "<URL>/logo.svg"
    MFE_CONFIG["LOGO_TRADEMARK_URL"] = "<URL>/logo-trademark.svg"
    MFE_CONFIG["LOGO_WHITE_URL"] = "<URL>/logo-white.svg"
    MFE_CONFIG["FAVICON_URL"] = "<URL>/favicon.ico"
    """
        ),
        (
            "mfe-lms-production-settings",
            """
    MFE_CONFIG["LOGO_URL"] = "<URL>/logo.svg"
    MFE_CONFIG["LOGO_TRADEMARK_URL"] = "<URL>/logo-trademark.svg"
    MFE_CONFIG["LOGO_WHITE_URL"] = "<URL>/logo-white.svg"
    MFE_CONFIG["FAVICON_URL"] = "<URL>/favicon.ico"
    """
        ),
    ]
)If patches are the same in development and production, they can be replaced by a singlemfe-lms-common-settingspatch.To install custom components for the MFEs, such as theheaderandfooter, override the components by adding a patch tomfe-dockerfile-post-npm-installin your plugin:from tutor import hooks

hooks.Filters.ENV_PATCHES.add_item(
    (
        "mfe-dockerfile-post-npm-install",
        """
# npm package
RUN npm install '@edx/frontend-component-header@npm:@edx/frontend-component-header-edx@latest'
# git repository
RUN npm install '@edx/frontend-component-footer@git+https://github.com/edx/frontend-component-footer-edx.git'
"""
    )
)The same applies to installing a custombrandpackage:hooks.Filters.ENV_PATCHES.add_item(
    (
        "mfe-dockerfile-post-npm-install",
        """
RUN npm install '@edx/brand@git+https://github.com/edx/brand-edx.org.git'
"""
    )
)In both cases above, thenpmcommands affect every MFE being built.  If you want have different commands apply to different MFEs, you can add one or more patches tomfe-dockerfile-post-npm-install-*instead.  For instance, you could install one particular version of the header to the Learning MFE by patchingmfe-dockerfile-post-npm-install-learning, and another one to the ORA Grading MFE by patchingmfe-dockerfile-post-npm-install-ora-grading:hooks.Filters.ENV_PATCHES.add_items(
    [
        (
            "mfe-dockerfile-post-npm-install-learning",
            """
    RUN npm install '@edx/frontend-component-header@git+https://github.com/your-repo/frontend-component-header.git#your-branch'
    """
        ),
        (
            "mfe-dockerfile-post-npm-install-ora-grading",
            """
    RUN npm install '@edx/frontend-component-header@git+https://github.com/your-repo/frontend-component-header.git#your-other-branch'
    """
        ),
    ]
)In case you need to run additional instructions just before the build step you can use themfe-dockerfile-pre-npm-buildormfe-dockerfile-pre-npm-build-*patches. For example, you may want to override existing env variables or define new ones.from tutor import hooks

hooks.Filters.ENV_PATCHES.add_items(
    [
        (
            "mfe-dockerfile-pre-npm-build",
            """
ENV ENABLE_NEW_RELIC=true
ENV NEW_RELIC_ACCOUNT_ID="111111"
ENV NEW_RELIC_AGENT_ID="2222222222"
ENV NEW_RELIC_TRUST_KEY="333333"
ENV NEW_RELIC_LICENSE_KEY="4444444444"
ENV NEW_RELIC_APP_ID="5555555555"
"""
        ),
        # Only for the learning MFE
        (
            "mfe-dockerfile-pre-npm-build-learning",
            """ENV CUSTOM_VAR="custom-value"
            """
        ),
    ]
)Installing from a private npm registryIn case you need to install components from a private NPM registry, you can append the--registryoption to your install statement or add anpm config setcommand to the plugin.
In some cases, for example when usingGitLab’s NPM package registry, you might also need to provide a token for your registry, which can be done with an additionalnpm config setcommand as well:from tutor import hooks

hooks.Filters.ENV_PATCHES.add_item(
    (
        "mfe-dockerfile-post-npm-install",
        """
RUN npm config set @foo:registry https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/
RUN npm config set '//gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken' '<your_token>'
RUN npm install '@edx/frontend-component-header@npm:@foo/<your_frontend_component_header_name>@latest'
"""
    )
)MFE developmentTutor makes it possible to run any MFE in development mode. For instance, to run the “profile” MFE:tutor dev start profileThen, accesshttp://apps.local.edly.io:1995/profile/u/YOURUSERNAMEYou can also bind-mount your own fork of an MFE. For example:tutor mounts add /path/to/frontend-app-profile
tutor dev launchWith this change, the “profile-dev” image will be automatically re-built duringlaunch. Your host repository will then be bind-mounted at runtime in the “profile” container. This means that changes you make to the host repository will be automatically picked up and hot-reloaded by your development server.This works for custom MFEs, as well. For example, if you added your own MFE named frontend-app-myapp, then you can bind-mount it like so:tutor mounts add /path/to/frontend-app-myappSimilarly, in production, the “mfe” Docker image will be rebuilt automatically duringtutor local launch.Note: the name of the bind-mount folder needs to match the name of the repository word-for-word. If you’ve forked an MFE repository with a custom name, be sure to change the name back to ensure the bind-mount works properly.UninstallTo disable this plugin run:tutor plugins disable mfeYou will also have to manually remove a few settings:# MFE account
tutor local run lms ./manage.py lms waffle_delete --flags account.redirect_to_microfrontend

# MFE profile
tutor local run lms ./manage.py lms waffle_delete --flags learner_profile.redirect_to_microfrontend
tutor local run lms ./manage.py lms waffle_delete --flags discussions.pages_and_resources_mfe
tutor local run lms ./manage.py lms waffle_delete --flags new_core_editors.use_new_text_editor
tutor local run lms ./manage.py lms waffle_delete --flags new_core_editors.use_new_video_editor
tutor local run lms ./manage.py lms waffle_delete --flags new_core_editors.use_new_problem_editor
tutor local run lms site-configuration unset ENABLE_PROFILE_MICROFRONTEND

# MFE discussions
tutor local run lms ./manage.py lms waffle_delete --flags discussions.enable_discussions_mfe
tutor local run lms ./manage.py lms waffle_delete --flags discussions.enable_learners_tab_in_discussions_mfe
tutor local run lms ./manage.py lms waffle_delete --flags discussions.enable_moderation_reason_codes
tutor local run lms ./manage.py lms waffle_delete --flags discussions.enable_reported_content_email_notifications
tutor local run lms ./manage.py lms waffle_delete --flags discussions.enable_learners_stats

# MFE ora-grading
tutor local run lms ./manage.py lms waffle_delete --flags openresponseassessment.enhanced_staff_graderFinally, restart the platform with:tutor local launchTroubleshootingThis Tutor plugin is maintained by Adolfo Brandes fromtCRIL. Community support is available from the officialOpen edX forum. Do you need help with this plugin? See thetroubleshootingsection from the Tutor documentation.LicenseThis software is licensed under the terms of theGNU Affero General Public License (AGPL).