-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' of https://github.com/openedx/frontend-app-admi…
…n-portal into mashal-m/react-upgrade-to-v17
- Loading branch information
Showing
195 changed files
with
12,681 additions
and
2,904 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
# App Specific | ||
|
||
# Note: The Algolia APP_ID and SEARCH_API_KEY are secret and must be configured via `.env.private`. | ||
ALGOLIA_APP_ID="" | ||
ALGOLIA_SEARCH_API_KEY="" | ||
|
||
BASE_URL="https://localhost.stage.edx.org:1991" | ||
LICENSE_MANAGER_BASE_URL="https://license-manager.stage.edx.org" | ||
ENTERPRISE_ACCESS_BASE_URL="https://enterprise-access.stage.edx.org" | ||
ENTERPRISE_CATALOG_BASE_URL="https://enterprise-catalog.stage.edx.org" | ||
ENTERPRISE_SUBSIDY_BASE_URL="https://enterprise-subsidy.stage.edx.org" | ||
DISCOVERY_BASE_URL="https://discovery.stage.edx.org" | ||
PLOTLY_SERVER_URL="https://enterprise-dash.edx.org/admin-analytics/" | ||
SEGMENT_KEY="" | ||
NEW_RELIC_AGENT_ID="" | ||
NEW_RELIC_APP_ID="" | ||
ALGOLIA_INDEX_NAME="enterprise_catalog_new" | ||
FEATURE_PROGRAM_TITLES_FACET='true' | ||
FEATURE_LANGUAGE_FACET='true' | ||
FEATURE_CODE_MANAGEMENT='true' | ||
FEATURE_REPORTING_CONFIGURATIONS='true' | ||
FEATURE_ANALYTICS='true' | ||
FEATURE_SUPPORT='true' | ||
FEATURE_SAML_CONFIGURATION='' | ||
FEATURE_CODE_VISIBILITY='true' | ||
FEATURE_EXTERNAL_LMS_CONFIGURATION='' | ||
FEATURE_BULK_ENROLLMENT='true' | ||
FEATURE_FILE_ATTACHMENT='true' | ||
FEATURE_SETTINGS_PAGE='true' | ||
FEATURE_SETTINGS_PAGE_LMS_TAB='true' | ||
FEATURE_SETTINGS_PAGE_APPEARANCE_TAB='true' | ||
FEATURE_LEARNER_CREDIT_MANAGEMENT='true' | ||
FEATURE_CONTENT_HIGHLIGHTS='true' | ||
FEATURE_AUTH0_SELF_SERVICE_INTEGRATION='false' | ||
HOTJAR_DEBUG='' | ||
HOTJAR_APP_ID='' | ||
FEATURE_SSO_SETTINGS_TAB='true' | ||
FEATURE_API_CREDENTIALS_TAB='true' | ||
FEATURE_PENDING_ENROLLMENT_ACTIONS='false' | ||
# maintenance alert | ||
IS_MAINTENANCE_ALERT_ENABLED='' | ||
MAINTENANCE_ALERT_MESSAGE='edX is currently in a brief maintenance window. Functionality involving course enrollments is unavailable at this time, including enrollment and assignment. Please check back shortly to continue the learning journey.' | ||
MAINTENANCE_ALERT_START_TIMESTAMP='' | ||
|
||
# Common | ||
|
||
LMS_BASE_URL="https://courses.stage.edx.org" | ||
STUDIO_BASE_URL="https://studio.stage.edx.org" | ||
DATA_API_BASE_URL="https://analyticsapi.stage.edx.org" | ||
ECOMMERCE_BASE_URL="https://ecommerce.stage.edx.org" | ||
DISCOVERY_API_BASE_URL="https://discovery.stage.edx.org" | ||
PUBLISHER_BASE_URL="https://publisher.stage.edx.org/" | ||
CREDENTIALS_BASE_URL="https://credentials.stage.edx.org" | ||
ENTERPRISE_CATALOG_API_BASE_URL="https://enterprise-catalog.stage.edx.org" | ||
INSIGHTS_BASE_URL="https://stage-insights.edx.org" | ||
LEARNING_BASE_URL="https://learning.stage.edx.org" | ||
LOGIN_URL="https://courses.stage.edx.org/login" | ||
LOGOUT_URL="https://courses.stage.edx.org/logout" | ||
MARKETING_SITE_BASE_URL="https://stage.edx.org" | ||
ORDER_HISTORY_URL="https://orders.stage.edx.org/orders" | ||
ENTERPRISE_MARKETING_URL="https://business.edx.org" | ||
REGISTRAR_API_BASE_URL="https://registrar.stage.edx.org/api" | ||
OPTIMIZELY_PROJECT_ID="1706490390" | ||
ENTERPRISE_LEARNER_PORTAL_HOSTNAME="enterprise.stage.edx.org" | ||
ENTERPRISE_LEARNER_PORTAL_URL="https://enterprise.stage.edx.org" | ||
DEMOGRAPHICS_BASE_URL="https://demographics.stage.edx.org" | ||
EXAMS_BASE_URL="https://edx-exams.stage.edx.org" | ||
ACCOUNT_SETTINGS_URL="https://account.stage.edx.org" | ||
ACCOUNT_PROFILE_URL="https://profile.stage.edx.org" | ||
SUPPORT_URL="https://support.edx.org" | ||
ENTERPRISE_SUPPORT_URL="https://business-support.edx.org/hc/en-us" | ||
ENTERPRISE_SUPPORT_PROGRAM_OPTIMIZATION_URL="https://business.edx.org/hubfs/Onboarding%20and%20Engagement/Onboarding%20Assets/Admin%20Resources/Program%20Optimization.pdf?hsLang=en" | ||
ENTERPRISE_SUPPORT_LEARNER_CREDIT_URL='http://stage.edx.org' | ||
CONTACT_URL="https://courses.stage.edx.org/support/contact_us" | ||
OPEN_SOURCE_URL="https://open.edx.org" | ||
TERMS_OF_SERVICE_URL="https://stage.edx.org/edx-terms-service" | ||
PRIVACY_POLICY_URL="https://stage.edx.org/edx-privacy-policy" | ||
SPANISH_PRIVACY_POLICY_URL="https://stage.edx.org/es/edx-privacy-policy" | ||
SEARCH_CATALOG_URL="https://stage.edx.org/search" | ||
FACEBOOK_URL="https://www.facebook.com/edX" | ||
TWITTER_URL="https://twitter.com/edXOnline" | ||
YOU_TUBE_URL="https://www.youtube.com/user/edxonline" | ||
LINKED_IN_URL="https://www.linkedin.com/school/edx/" | ||
GOOGLE_PLUS_URL="https://plus.google.com/+edXOnline" | ||
REDDIT_URL="https://www.reddit.com/r/edx" | ||
APPLE_APP_STORE_URL="https://itunes.apple.com/us/app/edx/id945480667?mt=8" | ||
GOOGLE_PLAY_URL="https://play.google.com/store/apps/details?id=org.edx.mobile" | ||
ENTERPRISE_SUPPORT_REVOKE_LICENSE_URL="https://business-support.edx.org/hc/en-us/articles/4409008473495" | ||
LANGUAGE_PREFERENCE_COOKIE_NAME="stage-edx-language-preference" | ||
NEW_RELIC_ACCOUNT_ID="" | ||
NEW_RELIC_LICENSE_KEY="" | ||
NEW_RELIC_TRUST_KEY="" | ||
ACCESS_TOKEN_COOKIE_NAME="stage-edx-jwt-cookie-header-payload" | ||
USER_INFO_COOKIE_NAME="stage-edx-user-info" | ||
REFRESH_ACCESS_TOKEN_ENDPOINT="https://courses.stage.edx.org/login_refresh" | ||
CSRF_TOKEN_API_PATH="/csrf/api/v1/token" | ||
SITE_NAME="edX" | ||
FAVICON_URL="https://edx-cdn.org/v3/stage/favicon.ico" | ||
LOGO_TRADEMARK_URL="https://edx-cdn.org/v3/stage/logo-trademark.svg" | ||
LOGO_TRADEMARK_URL_PNG="https://edx-cdn.org/v3/stage/logo-trademark.png" | ||
LOGO_TRADEMARK_URL_SVG="https://edx-cdn.org/v3/stage/logo-trademark.svg" | ||
LOGO_URL="https://edx-cdn.org/v3/stage/logo.svg" | ||
LOGO_URL_PNG="https://edx-cdn.org/v3/stage/logo.png" | ||
LOGO_URL_SVG="https://edx-cdn.org/v3/stage/logo.svg" | ||
LOGO_WHITE_URL="https://edx-cdn.org/v3/stage/logo-white.svg" | ||
LOGO_WHITE_URL_PNG="https://edx-cdn.org/v3/stage/logo-white.png" | ||
LOGO_WHITE_URL_SVG="https://edx-cdn.org/v3/stage/logo-white.svg" | ||
LOGO_POWERED_BY_OPEN_EDX_URL="https://edx-cdn.org/v3/stage/open-edx-tag.png" | ||
LOGO_POWERED_BY_OPEN_EDX_URL_PNG="https://edx-cdn.org/v3/stage/open-edx-tag.png" | ||
LOGO_POWERED_BY_OPEN_EDX_URL_SVG="https://edx-cdn.org/v3/stage/open-edx-tag.svg" | ||
HOTJAR_VERSION=6 | ||
SESSION_COOKIE_DOMAIN=".stage.edx.org" | ||
|
||
# Cookie Policy Banner | ||
COOKIE_POLICY_BANNER_VIEWED_NAME="edx-cookie-policy-viewed" | ||
MARKETING_SITE_NAME="edx.org" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,9 +3,11 @@ | |
![Build Status](https://github.com/openedx/frontend-app-admin-portal/actions/workflows/ci.yml/badge.svg) | ||
![Codecov](https://codecov.io/gh/edx/frontend-app-admin-portal/branch/master/graph/badge.svg) | ||
|
||
## Overview | ||
# Purpose | ||
frontend-app-admin-portal is a frontend that provides branded learning experiences as well as a dashboard for enterprise learning administrators. | ||
|
||
# Getting Started | ||
|
||
## Setting up a dev environment | ||
|
||
### The Short Story | ||
|
@@ -101,3 +103,81 @@ module.exports = { | |
``` | ||
|
||
NB: In order for webpack to properly resolve scss imports locally, you must use a `~` before the import, like so: `@import "~@edx/brand/paragon/fonts";` | ||
|
||
### Running tests | ||
|
||
You can run all tests as follows: | ||
``` | ||
nvm use | ||
npm install | ||
npm run test | ||
``` | ||
|
||
Additionally, you can run a single test file with | ||
``` | ||
npm run test -- ProvisioningFormSubmissionButton.test.jsx | ||
``` | ||
|
||
or run a given test function by appending a `.only` to the test function (or appending `.skip` to do the inverse). | ||
For example: `test.only('your test function', () => {...})`. | ||
|
||
You can use watch mode with tests as follows: | ||
``` | ||
npm run test:watch BudgetDetailPage.test.jsx | ||
# or to skip coverage reporting | ||
npm run test:watch-no-cov BudgetDetailpage.test.jsx | ||
``` | ||
Note the watcher has its own set of commands to help run test functions that match a regex (`t my regex`), etc. | ||
Use the `w` command to get a list of valid watch commands. | ||
|
||
## Getting Help | ||
|
||
If you're having trouble, we have discussion forums at | ||
https://discuss.openedx.org where you can connect with others in the community. | ||
|
||
Our real-time conversations are on Slack. You can request a `Slack | ||
invitation`_, then join our `community Slack workspace`_. Because this is a | ||
frontend repository, the best place to discuss it would be in the `#wg-frontend | ||
channel`_. | ||
|
||
For anything non-trivial, the best path is to open an issue in this repository | ||
with as many details about the issue you are facing as you can provide. | ||
|
||
https://github.com/openedx/frontend-app-admin-portal/issues | ||
|
||
For more information about these options, see the `Getting Help`_ page. | ||
|
||
.. _Slack invitation: https://openedx.org/slack | ||
.. _community Slack workspace: https://openedx.slack.com/ | ||
.. _#wg-frontend channel: https://openedx.slack.com/archives/C04BM6YC7A6 | ||
.. _Getting Help: https://openedx.org/community/connect | ||
|
||
## Contributing | ||
|
||
Contributions are very welcome. Please read `How To Contribute`_ for details. | ||
|
||
.. _How To Contribute: https://openedx.org/r/how-to-contribute | ||
|
||
This project is currently accepting all types of contributions, bug fixes, | ||
security fixes, maintenance work, or new features. However, please make sure | ||
to have a discussion about your new feature idea with the maintainers prior to | ||
beginning development to maximize the chances of your change being accepted. | ||
You can start a conversation by creating a new issue on this repo summarizing | ||
your idea. | ||
|
||
## The Open edX Code of Conduct | ||
|
||
All community members are expected to follow the `Open edX Code of Conduct`_. | ||
|
||
.. _Open edX Code of Conduct: https://openedx.org/code-of-conduct/ | ||
|
||
## License | ||
|
||
The code in this repository is licensed under the AGPLv3 unless otherwise | ||
noted. | ||
|
||
Please see `LICENSE <LICENSE>`_ for details. | ||
|
||
## Reporting Security Issues | ||
|
||
Please do not report security issues in public. Please email [email protected]. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
6. Adopting ``@tanstack/react-query`` for data fetching and client-side caching | ||
============================================================================= | ||
|
||
Status | ||
****** | ||
|
||
Accepted (October 2023) | ||
|
||
Context | ||
******* | ||
|
||
The ``frontend-app-admin-portal`` MFE currently relies on custom state variables when integrating with an API (e.g., managing loading states). As a result, there is generally a fair amount of boilerplate involved with each API integration. Additionally, the current approach does not provide any client-side caching out-of-the-box or any other best-in-class features like automatic query retries, which can lead to heavy reliance on approaches such as React Context or Redux in order to pass data returned by asynchronous API calls throughout the application. | ||
|
||
The existing approach of heavily relying on React Context providers has resulted in many nested context providers that can make it difficult for contributors to understand what data is available to them from which context provider. Additionally, the reliance on context providers means accepting some performance risk that all components nested under a context provider will re-render whenever any value within the context provider changes, which can lead to performance issues if the context provider is wrapping a large number of components if not mitigated with techniques like ``React.memo``, ``useMemo``, or context selectors. | ||
|
||
Decisions | ||
********* | ||
|
||
We will instead rely on ``@tanstack/react-query`` for data fetching and client-side caching. This library provides a number of benefits over the existing approach, including: | ||
|
||
* Using ``@tanstack/react-query`` will allow us to avoid writing a significant amount of boilerplate code that is currently required to integrate with an API. We can rely on the library to handle loading states, error states, and other common API integration concerns. | ||
* Flexible client-side caching, which will allow us to avoid using custom caching logic provided by ``@edx/frontend-platform``, which is not as full-featured. | ||
* A number of other features out-of-the-box, including automatic query retries on failed network requests, which will allow us to avoid writing custom logic to handle these scenarios. | ||
* Using ``@tanstack/react-query`` will allow us to avoid relying on React Context providers to pass data returned by asynchronous API calls throughout the application. Instead, we can rely on the library to handle this for us via custom hooks. For example, calling ``useQuery`` twice within the rendering lifecycle will not result in duplicate API calls. Instead, the library will first make the initial network call and then store its response in a client-side cache. The second call to ``useQuery`` will then return the cached response instead of making a duplicate network call. The cache invalidation is customizable globally for the application or by query. | ||
|
||
|
||
We will adopt query key factories to manage the implementation of query keys such that cache invalidation for independent features (e.g., Learner Credit Management) can be managed with adequate granularity. For example: | ||
|
||
:: | ||
|
||
// Query Key Factory | ||
export const learnerCreditManagementQueryKeys = { | ||
all: ['learner-credit-management'], | ||
budgets: () => [...learnerCreditManagementQueryKeys.all, 'budgets'], | ||
budget: (budgetId) => [...learnerCreditManagementQueryKeys.all, 'budget', budgetId], | ||
budgetActivity: (budgetId) => [...learnerCreditManagementQueryKeys.budget(budgetId), 'activity'], | ||
budgetActivityOverview: (budgetId) => [...learnerCreditManagementQueryKeys.budgetActivity(budgetId), 'overview'], | ||
}; | ||
|
||
By having a query key factory as suggested above, contributors may have a structured way to manage query keys for a given feature. This approach enabled granular control over cache invalidation, query prefetching, etc. Using the above example, one could invalidate the query cache for the entire ``['learner-credit-management']`` feature or opt to only invalidate the query cache for specific individual queries or even groups of queries: | ||
|
||
:: | ||
|
||
// Remove everything related to the learner credit management feature | ||
queryClient.removeQueries({ | ||
queryKey: learnerCreditManagementQueryKeys.all, | ||
}) | ||
|
||
// Invalidate all queries supporting the budget detail page route | ||
queryClient.invalidateQueries({ | ||
queryKey: learnerCreditManagementQueryKeys.budget(budgetId), | ||
}) | ||
|
||
// Invalidate the budget detail page route's activity tab's overview query | ||
queryClient.invalidateQueries({ | ||
queryKey: learnerCreditManagementQueryKeys.budgetActivityOverview(budgetId), | ||
}) | ||
|
||
The recommendation for new asynchronous network calls moving forward is to use ``@tanstack/react-query``. Additionally, it's recommended to incrementally migrate existing network calls to use ``@tanstack/react-query``. This will allow us to avoid a large refactoring effort and instead migrate to the library over time as we touch existing network calls. | ||
|
||
Consequences | ||
************ | ||
|
||
The entire application is wrapped within ``QueryClientProvider``, which contains a default configuration to at least extend the ``staleTime`` to be 20 seconds. This change in default behavior is to enable the use of ``@tanstack/react-query`` as a state manager. Instead of queries becoming instantly stale after success (i.e., ``staleTime: 0``) where network calls would be re-fetched on all window refocuses and component mounts, etc., having a ``staleTime`` of 20 seconds will keep the data fresh for 20 seconds before the query becomes stale, preventing unnecessary API calls (e.g., when calling duplicate ``useQuery`` hooks in the same rendering lifecycle). | ||
|
||
By adopting ``@tanstack/react-query``, by default, queries made with ``useQuery`` will have some automatic background refetching behavior baked in. It's recommended to consider whether any specific queries should override/extend the default options provided by the library. For example, some specific queries may not want the automatic refetches, etc. that are provided by default. | ||
|
||
Alternatives Considered | ||
*********************** | ||
|
||
* In order to enable the same pattern of relying on ``@tanstack/react-query`` as a state manager to avoid additional context providers, it was considered whether we could make heavier use of the client-side caching provided by ``@edx/frontend-platform``. This was decided against as it is not as full-featured as ``@tanstack/react-query`` when it comes to caching alone. Additionally, it does not provide any other features that are provided by ``@tanstack/react-query``, which will enable more efficient API integrations moving forward. |
Oops, something went wrong.