From 688bdb7ec5e64814d13514d14a0b74dfba2247db Mon Sep 17 00:00:00 2001 From: Leangseu Kim <83240113+leangseu-edx@users.noreply.github.com> Date: Wed, 17 Apr 2024 09:43:39 -0400 Subject: [PATCH 1/3] chore: add @openedx/frontend-plugin-framework chore: move plugin page setting button to a props chore: split out app setting modal for reusability chore: add implementation of WTC plugin chore: update app setting form chore: implement the plugin form with mock chore: follow the UI design chore: remove translation plugin and move it into frontend-plugin instead --- .gitignore | 3 + example.env.config.jsx | 24 ++ package-lock.json | 292 +++++++++++++----- package.json | 6 +- .../app-settings-modal/AppSettingsModal.jsx | 112 ++----- .../AppSettingsModalBase.jsx | 63 ++++ src/pages-and-resources/pages/PageCard.jsx | 60 ++-- src/pages-and-resources/pages/PageGrid.jsx | 2 + .../pages/PageSettingButton.jsx | 59 ++++ 9 files changed, 418 insertions(+), 203 deletions(-) create mode 100644 example.env.config.jsx create mode 100644 src/pages-and-resources/app-settings-modal/AppSettingsModalBase.jsx create mode 100644 src/pages-and-resources/pages/PageSettingButton.jsx diff --git a/.gitignore b/.gitignore index 02542e96c3..925d1768a4 100755 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,6 @@ temp/babel-plugin-react-intl # Messages .json files fetched by atlas src/i18n/messages/ + +# environment js config +env.config.jsx diff --git a/example.env.config.jsx b/example.env.config.jsx new file mode 100644 index 0000000000..e57c7d7668 --- /dev/null +++ b/example.env.config.jsx @@ -0,0 +1,24 @@ +import WholeCourseTranslation from '@edx/course-app-translation-plugin'; +import { PLUGIN_OPERATIONS, DIRECT_PLUGIN } from '@openedx/frontend-plugin-framework'; + +// Load environment variables from .env file +const config = { + ...process.env, + pluginSlots: { + additional_course_plugin: { + plugins: [ + { + op: PLUGIN_OPERATIONS.Insert, + widget: { + id: 'whole-course-translation-plugin', + type: DIRECT_PLUGIN, + priority: 1, + RenderWidget: WholeCourseTranslation, + }, + }, + ], + }, + }, +}; + +export default config; diff --git a/package-lock.json b/package-lock.json index 062af01e6e..a6d3b3765e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,7 @@ "@openedx-plugins/course-app-teams": "file:plugins/course-apps/teams", "@openedx-plugins/course-app-wiki": "file:plugins/course-apps/wiki", "@openedx-plugins/course-app-xpert_unit_summary": "file:plugins/course-apps/xpert_unit_summary", + "@openedx/frontend-plugin-framework": "^1.1.0", "@openedx/paragon": "^22.2.1", "@reduxjs/toolkit": "1.9.7", "@tanstack/react-query": "4.36.1", @@ -50,10 +51,11 @@ "lodash": "4.17.21", "meilisearch": "^0.38.0", "moment": "2.29.4", - "prop-types": "15.7.2", + "prop-types": "^15.8.1", "react": "17.0.2", "react-datepicker": "^4.13.0", "react-dom": "17.0.2", + "react-error-boundary": "^4.0.13", "react-helmet": "^6.1.0", "react-redux": "7.2.9", "react-responsive": "9.0.2", @@ -2377,16 +2379,6 @@ "react-dom": "^16.9.0 || ^17.0.0" } }, - "node_modules/@edx/frontend-component-ai-translations/node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, "node_modules/@edx/frontend-component-ai-translations/node_modules/react-responsive": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-8.2.0.tgz", @@ -3495,16 +3487,6 @@ "react": ">=16.3" } }, - "node_modules/@fortawesome/react-fontawesome/node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, "node_modules/@fullhuman/postcss-purgecss": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-5.0.0.tgz", @@ -4705,6 +4687,174 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@openedx/frontend-plugin-framework": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@openedx/frontend-plugin-framework/-/frontend-plugin-framework-1.1.0.tgz", + "integrity": "sha512-WT2Up9UR1ctQLeN43iCwEF6BOmU3zxL+s+clDeS4zp/aPue3v5ObTbzRsuJGlFg9gA6lY1C6Yh2+QQ6w2sK2aw==", + "dependencies": { + "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", + "@edx/frontend-component-footer": "13.0.3", + "@edx/frontend-component-header": "5.0.2", + "classnames": "^2.3.2", + "core-js": "3.36.0", + "react-redux": "7.2.9", + "redux": "4.2.1", + "regenerator-runtime": "0.14.1" + }, + "peerDependencies": { + "@edx/frontend-platform": "^7.0.0", + "@openedx/paragon": "^21.0.0 || ^22.0.0", + "prop-types": "^15.8.0", + "react": "^17.0.0", + "react-dom": "^17.0.0", + "react-error-boundary": "^4.0.11" + } + }, + "node_modules/@openedx/frontend-plugin-framework/node_modules/@edx/frontend-component-footer": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/@edx/frontend-component-footer/-/frontend-component-footer-13.0.3.tgz", + "integrity": "sha512-09vX6qC7AcDwG02qhBzKr4x58hpe9FXZrA9ui2cJnsG53pKaNL+wvOSRtDUBNexCf+y/iPg+8RgR+4alkzhZhw==", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "6.5.1", + "@fortawesome/free-brands-svg-icons": "6.5.1", + "@fortawesome/free-regular-svg-icons": "6.5.1", + "@fortawesome/free-solid-svg-icons": "6.5.1", + "@fortawesome/react-fontawesome": "0.2.0", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "@edx/frontend-platform": "^7.0.0", + "@openedx/paragon": ">= 21.11.3 < 23.0.0", + "prop-types": "^15.5.10", + "react": "^16.9.0 || ^17.0.0", + "react-dom": "^16.9.0 || ^17.0.0" + } + }, + "node_modules/@openedx/frontend-plugin-framework/node_modules/@edx/frontend-component-header": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-5.0.2.tgz", + "integrity": "sha512-73fNNc1X/tevb3/hw7+s22T+nPGlW1yXA7zsT9eRzdH7rBxONfp0Jz7yEdeBvTax9a96PaOht45DA6GX9eG4KA==", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "6.5.1", + "@fortawesome/free-brands-svg-icons": "6.5.1", + "@fortawesome/free-regular-svg-icons": "6.5.1", + "@fortawesome/free-solid-svg-icons": "6.5.1", + "@fortawesome/react-fontawesome": "^0.2.0", + "axios-mock-adapter": "1.22.0", + "babel-polyfill": "6.26.0", + "react-responsive": "8.2.0", + "react-transition-group": "4.4.5" + }, + "peerDependencies": { + "@edx/frontend-platform": "^7.0.0", + "@openedx/paragon": ">= 21.5.7 < 23.0.0", + "prop-types": "^15.5.10", + "react": "^16.9.0 || ^17.0.0", + "react-dom": "^16.9.0 || ^17.0.0" + } + }, + "node_modules/@openedx/frontend-plugin-framework/node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz", + "integrity": "sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@openedx/frontend-plugin-framework/node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz", + "integrity": "sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@openedx/frontend-plugin-framework/node_modules/@fortawesome/free-brands-svg-icons": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.5.1.tgz", + "integrity": "sha512-093l7DAkx0aEtBq66Sf19MgoZewv1zeY9/4C7vSKPO4qMwEsW/2VYTUTpBtLwfb9T2R73tXaRDPmE4UqLCYHfg==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@openedx/frontend-plugin-framework/node_modules/@fortawesome/free-regular-svg-icons": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.5.1.tgz", + "integrity": "sha512-m6ShXn+wvqEU69wSP84coxLbNl7sGVZb+Ca+XZq6k30SzuP3X4TfPqtycgUh9ASwlNh5OfQCd8pDIWxl+O+LlQ==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@openedx/frontend-plugin-framework/node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz", + "integrity": "sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@openedx/frontend-plugin-framework/node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, + "node_modules/@openedx/frontend-plugin-framework/node_modules/core-js": { + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.36.0.tgz", + "integrity": "sha512-mt7+TUBbTFg5+GngsAxeKBTl5/VS0guFeJacYge9OmHb+m058UwwIm41SE9T4Den7ClatV57B6TYTuJ0CX1MAw==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/@openedx/frontend-plugin-framework/node_modules/react-responsive": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-8.2.0.tgz", + "integrity": "sha512-iagCqVrw4QSjhxKp3I/YK6+ODkWY6G+YPElvdYKiUUbywwh9Ds0M7r26Fj2/7dWFFbOpcGnJE6uE7aMck8j5Qg==", + "dependencies": { + "hyphenate-style-name": "^1.0.0", + "matchmediaquery": "^0.3.0", + "prop-types": "^15.6.1", + "shallow-equal": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@openedx/frontend-plugin-framework/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/@openedx/frontend-plugin-framework/node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/@openedx/paragon": { "version": "22.2.1", "resolved": "https://registry.npmjs.org/@openedx/paragon/-/paragon-22.2.1.tgz", @@ -4824,16 +4974,6 @@ "node": ">=10" } }, - "node_modules/@openedx/paragon/node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, "node_modules/@openedx/paragon/node_modules/react-responsive": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-8.2.0.tgz", @@ -5386,6 +5526,22 @@ } } }, + "node_modules/@testing-library/react-hooks/node_modules/react-error-boundary": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", + "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, "node_modules/@testing-library/react/node_modules/@testing-library/dom": { "version": "8.20.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", @@ -10062,16 +10218,6 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-react/node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, "node_modules/eslint-plugin-react/node_modules/resolve": { "version": "2.0.0-next.5", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", @@ -17422,13 +17568,13 @@ } }, "node_modules/prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", - "react-is": "^16.8.1" + "react-is": "^16.13.1" } }, "node_modules/prop-types-extra": { @@ -17878,28 +18024,13 @@ "react": ">= 16.8 || 18.0.0" } }, - "node_modules/react-dropzone/node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, "node_modules/react-error-boundary": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", - "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", - "dev": true, + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz", + "integrity": "sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==", "dependencies": { "@babel/runtime": "^7.12.5" }, - "engines": { - "node": ">=10", - "npm": ">=6" - }, "peerDependencies": { "react": ">=16.13.1" } @@ -17996,14 +18127,35 @@ "react": ">=0.14.0" } }, - "node_modules/react-imask/node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "node_modules/react-instantsearch": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/react-instantsearch/-/react-instantsearch-7.7.1.tgz", + "integrity": "sha512-o6nLY4IZWql6m0LYFSKpPKlAZ8zV3fwnwgswGs1okdw2skb3TXB535/mQCQZF39YjrUqBc3thl/YMnEDnKtVaQ==", "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" + "@babel/runtime": "^7.1.2", + "instantsearch-ui-components": "0.4.0", + "instantsearch.js": "4.66.1", + "react-instantsearch-core": "7.7.1" + }, + "peerDependencies": { + "algoliasearch": ">= 3.1 < 5", + "react": ">= 16.8.0 < 19", + "react-dom": ">= 16.8.0 < 19" + } + }, + "node_modules/react-instantsearch-core": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/react-instantsearch-core/-/react-instantsearch-core-7.7.1.tgz", + "integrity": "sha512-OTvf/QtJT5zd+EQW+osjPPFNr7Vo9FAzy/zUxeeP+87IS6tiUpQQEDhgFFYBbvU5+97pYl9YmvGQARakNDHJOw==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "algoliasearch-helper": "3.17.0", + "instantsearch.js": "4.66.1", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "algoliasearch": ">= 3.1 < 5", + "react": ">= 16.8.0 < 19" } }, "node_modules/react-intl": { diff --git a/package.json b/package.json index 75fa7904e0..371b6885bb 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "scripts": { "build": "fedx-scripts webpack", "i18n_extract": "fedx-scripts formatjs extract", - "stylelint": "stylelint \"src/**/*.scss\" \"scss/**/*.scss\" --config .stylelintrc.json", + "stylelint": "stylelint \"plugins/**/*.scss\" \"src/**/*.scss\" \"scss/**/*.scss\" --config .stylelintrc.json", "lint": "npm run stylelint && fedx-scripts eslint --ext .js --ext .jsx .", "lint:fix": "npm run stylelint && fedx-scripts eslint --ext .js --ext .jsx . --fix", "snapshot": "TZ=UTC fedx-scripts jest --updateSnapshot", @@ -64,6 +64,7 @@ "@openedx-plugins/course-app-teams": "file:plugins/course-apps/teams", "@openedx-plugins/course-app-wiki": "file:plugins/course-apps/wiki", "@openedx-plugins/course-app-xpert_unit_summary": "file:plugins/course-apps/xpert_unit_summary", + "@openedx/frontend-plugin-framework": "^1.1.0", "@openedx/paragon": "^22.2.1", "@reduxjs/toolkit": "1.9.7", "@tanstack/react-query": "4.36.1", @@ -77,10 +78,11 @@ "lodash": "4.17.21", "meilisearch": "^0.38.0", "moment": "2.29.4", - "prop-types": "15.7.2", + "prop-types": "^15.8.1", "react": "17.0.2", "react-datepicker": "^4.13.0", "react-dom": "17.0.2", + "react-error-boundary": "^4.0.13", "react-helmet": "^6.1.0", "react-redux": "7.2.9", "react-responsive": "9.0.2", diff --git a/src/pages-and-resources/app-settings-modal/AppSettingsModal.jsx b/src/pages-and-resources/app-settings-modal/AppSettingsModal.jsx index 477b269bb9..276ce4b100 100644 --- a/src/pages-and-resources/app-settings-modal/AppSettingsModal.jsx +++ b/src/pages-and-resources/app-settings-modal/AppSettingsModal.jsx @@ -1,11 +1,9 @@ -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { - ActionRow, Alert, Badge, Form, Hyperlink, - ModalDialog, StatefulButton, TransitionReplace, } from '@openedx/paragon'; @@ -31,81 +29,10 @@ import { updateSavingStatus } from '../data/slice'; import { updateAppStatus } from '../data/thunks'; import AppConfigFormDivider from '../discussions/app-config-form/apps/shared/AppConfigFormDivider'; import { PagesAndResourcesContext } from '../PagesAndResourcesProvider'; +import AppSettingsModalBase from './AppSettingsModalBase'; import messages from './messages'; -const AppSettingsForm = ({ - formikProps, children, showForm, -}) => children && ( - - {showForm ? ( - - {children(formikProps)} - - ) : ( - - )} - -); - -AppSettingsForm.propTypes = { - // Ignore the warning here since we're just passing along the props as-is and the child component should validate - // eslint-disable-next-line react/forbid-prop-types - formikProps: PropTypes.object.isRequired, - showForm: PropTypes.bool.isRequired, - children: PropTypes.func, -}; - -AppSettingsForm.defaultProps = { - children: null, -}; - -const AppSettingsModalBase = ({ - intl, title, onClose, variant, isMobile, children, footer, -}) => ( - - - - {title} - - - - {children} - - - - - {intl.formatMessage(messages.cancel)} - - {footer} - - - -); - -AppSettingsModalBase.propTypes = { - intl: intlShape.isRequired, - title: PropTypes.string.isRequired, - onClose: PropTypes.func.isRequired, - variant: PropTypes.oneOf(['default', 'dark']).isRequired, - isMobile: PropTypes.bool.isRequired, - children: PropTypes.node.isRequired, - footer: PropTypes.node, -}; - -AppSettingsModalBase.defaultProps = { - footer: null, -}; - const AppSettingsModal = ({ - intl, appId, title, children, @@ -121,6 +48,7 @@ const AppSettingsModal = ({ enableReinitialize, hideAppToggle, }) => { + const { formatMessage } = useIntl(); const { courseId } = useContext(PagesAndResourcesContext); const loadingStatus = useSelector(getLoadingStatus); const updateSettingsRequestStatus = useSelector(getSavingStatus); @@ -199,14 +127,12 @@ const AppSettingsModal = ({ onClose={onClose} variant={modalVariant} isMobile={isMobile} - isFullscreenOnMobile - intl={intl} footer={( - {formikProps.errors.enabled?.title || intl.formatMessage(messages.errorSavingTitle)} + {formikProps.errors.enabled?.title || formatMessage(messages.errorSavingTitle)} - {formikProps.errors.enabled?.message || intl.formatMessage(messages.errorSavingMessage)} + {formikProps.errors.enabled?.message || formatMessage(messages.errorSavingMessage)} )} {!hideAppToggle && ( @@ -233,7 +159,7 @@ const AppSettingsModal = ({ {enableAppLabel} {formikProps.values.enabled && ( - {intl.formatMessage(messages.enabled)} + {formatMessage(messages.enabled)} )} @@ -249,9 +175,19 @@ const AppSettingsModal = ({ {bodyChildren} {(formikProps.values.enabled || configureBeforeEnable) && children && } - - {children} - + { + children && ( + + {formikProps.values.enabled || configureBeforeEnable ? ( + + {children(formikProps)} + + ) : ( + + )} + + ) + } )} @@ -260,7 +196,6 @@ const AppSettingsModal = ({ } return ( { + const { formatMessage } = useIntl(); + return ( + + + {title} + + {children} + + + + {formatMessage(messages.cancel)} + + {footer} + + + + ); +}; + +AppSettingsModalBase.defaultProps = { + isOpen: true, +}; + +AppSettingsModalBase.propTypes = { + title: PropTypes.string.isRequired, + onClose: PropTypes.func.isRequired, + variant: PropTypes.oneOf(['default', 'dark']).isRequired, + isMobile: PropTypes.bool.isRequired, + children: PropTypes.node.isRequired, + footer: PropTypes.node, + isOpen: PropTypes.bool, +}; + +AppSettingsModalBase.defaultProps = { + footer: null, +}; + +export default AppSettingsModalBase; diff --git a/src/pages-and-resources/pages/PageCard.jsx b/src/pages-and-resources/pages/PageCard.jsx index 02688b0aec..8ea154c111 100644 --- a/src/pages-and-resources/pages/PageCard.jsx +++ b/src/pages-and-resources/pages/PageCard.jsx @@ -1,15 +1,11 @@ import classNames from 'classnames'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; -import { - Badge, Card, Icon, IconButton, Hyperlink, -} from '@openedx/paragon'; -import { ArrowForward, Settings } from '@openedx/paragon/icons'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Badge, Card } from '@openedx/paragon'; import PropTypes from 'prop-types'; -import React, { useContext } from 'react'; -import { useNavigate } from 'react-router-dom'; +import React from 'react'; import messages from '../messages'; -import { PagesAndResourcesContext } from '../PagesAndResourcesProvider'; import { useIsDesktop } from '../../utils'; +import PageSettingButton from './PageSettingButton'; import './PageCard.scss'; const CoursePageShape = PropTypes.shape({ @@ -19,45 +15,21 @@ const CoursePageShape = PropTypes.shape({ enabled: PropTypes.bool.isRequired, legacyLink: PropTypes.string, allowedOperations: PropTypes.shape({ - enable: PropTypes.bool.isRequired, - configure: PropTypes.bool.isRequired, - }).isRequired, + enable: PropTypes.bool, + configure: PropTypes.bool, + }), }); export { CoursePageShape }; const PageCard = ({ - intl, page, + settingButton, }) => { - const { path: pagesAndResourcesPath } = useContext(PagesAndResourcesContext); + const { formatMessage } = useIntl(); const isDesktop = useIsDesktop(); - const navigate = useNavigate(); - // eslint-disable-next-line react/no-unstable-nested-components - const SettingsButton = () => { - if (page.legacyLink) { - return ( - - - - ); - } - return (page.allowedOperations.configure || page.allowedOperations.enable) && ( - navigate(`${pagesAndResourcesPath}/${page.id}/settings`)} - /> - ); - }; + const SettingButton = settingButton || ; return ( - {intl.formatMessage(messages.enabled)} + {formatMessage(messages.enabled)} )} - actions={
} + actions={
{SettingButton}
} size="sm" /> @@ -85,9 +57,13 @@ const PageCard = ({ ); }; +PageCard.defaultProps = { + settingButton: null, +}; + PageCard.propTypes = { - intl: intlShape.isRequired, page: CoursePageShape.isRequired, + settingButton: PropTypes.node, }; -export default injectIntl(PageCard); +export default PageCard; diff --git a/src/pages-and-resources/pages/PageGrid.jsx b/src/pages-and-resources/pages/PageGrid.jsx index 7191498f49..33c5772efe 100644 --- a/src/pages-and-resources/pages/PageGrid.jsx +++ b/src/pages-and-resources/pages/PageGrid.jsx @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import { injectIntl } from '@edx/frontend-platform/i18n'; import { CardGrid } from '@openedx/paragon'; +import { PluginSlot } from '@openedx/frontend-plugin-framework'; import PageCard, { CoursePageShape } from './PageCard'; const PageGrid = ({ pages }) => ( @@ -15,6 +16,7 @@ const PageGrid = ({ pages }) => ( {pages.map((page) => ( ))} + ); diff --git a/src/pages-and-resources/pages/PageSettingButton.jsx b/src/pages-and-resources/pages/PageSettingButton.jsx new file mode 100644 index 0000000000..931181d802 --- /dev/null +++ b/src/pages-and-resources/pages/PageSettingButton.jsx @@ -0,0 +1,59 @@ +import React, { useContext } from 'react'; +import PropTypes from 'prop-types'; + +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Icon, IconButton, Hyperlink } from '@openedx/paragon'; +import { ArrowForward, Settings } from '@openedx/paragon/icons'; +import { useNavigate } from 'react-router-dom'; +import messages from '../messages'; +import { PagesAndResourcesContext } from '../PagesAndResourcesProvider'; + +const PageSettingButton = ({ + id, + legacyLink, + allowedOperations, +}) => { + const { formatMessage } = useIntl(); + const { path: pagesAndResourcesPath } = useContext(PagesAndResourcesContext); + const navigate = useNavigate(); + + if (legacyLink) { + return ( + + + + ); + } if (!(allowedOperations?.configure || allowedOperations?.enable)) { + return null; + } + return ( + navigate(`${pagesAndResourcesPath}/${id}/settings`)} + /> + ); +}; + +PageSettingButton.defaultProps = { + legacyLink: null, + allowedOperations: null, +}; + +PageSettingButton.propTypes = { + id: PropTypes.string.isRequired, + legacyLink: PropTypes.string, + allowedOperations: PropTypes.shape({ + configure: PropTypes.bool, + enable: PropTypes.bool, + }), +}; + +export default PageSettingButton; From b1cfedd8eabe16b5e3c35d3e9424e5bb8fd27e99 Mon Sep 17 00:00:00 2001 From: Leangseu Kim <83240113+leangseu-edx@users.noreply.github.com> Date: Wed, 17 Apr 2024 09:57:14 -0400 Subject: [PATCH 2/3] chore: add eslint ignore for env.config.jsx --- .eslintignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index 6e1aa5ede1..9c46e7b475 100755 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,6 @@ coverage/* dist/ node_modules/ -jest.config.js \ No newline at end of file +jest.config.js +env.config.jsx +example.env.config.jsx From a88a759d304647ecc8c0704dac69427db782628f Mon Sep 17 00:00:00 2001 From: Leangseu Kim <83240113+leangseu-edx@users.noreply.github.com> Date: Wed, 24 Apr 2024 11:47:30 -0400 Subject: [PATCH 3/3] chore: update package-lock.json --- package-lock.json | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/package-lock.json b/package-lock.json index a6d3b3765e..b3dc197513 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18127,37 +18127,6 @@ "react": ">=0.14.0" } }, - "node_modules/react-instantsearch": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/react-instantsearch/-/react-instantsearch-7.7.1.tgz", - "integrity": "sha512-o6nLY4IZWql6m0LYFSKpPKlAZ8zV3fwnwgswGs1okdw2skb3TXB535/mQCQZF39YjrUqBc3thl/YMnEDnKtVaQ==", - "dependencies": { - "@babel/runtime": "^7.1.2", - "instantsearch-ui-components": "0.4.0", - "instantsearch.js": "4.66.1", - "react-instantsearch-core": "7.7.1" - }, - "peerDependencies": { - "algoliasearch": ">= 3.1 < 5", - "react": ">= 16.8.0 < 19", - "react-dom": ">= 16.8.0 < 19" - } - }, - "node_modules/react-instantsearch-core": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/react-instantsearch-core/-/react-instantsearch-core-7.7.1.tgz", - "integrity": "sha512-OTvf/QtJT5zd+EQW+osjPPFNr7Vo9FAzy/zUxeeP+87IS6tiUpQQEDhgFFYBbvU5+97pYl9YmvGQARakNDHJOw==", - "dependencies": { - "@babel/runtime": "^7.1.2", - "algoliasearch-helper": "3.17.0", - "instantsearch.js": "4.66.1", - "use-sync-external-store": "^1.0.0" - }, - "peerDependencies": { - "algoliasearch": ">= 3.1 < 5", - "react": ">= 16.8.0 < 19" - } - }, "node_modules/react-intl": { "version": "6.6.4", "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.6.4.tgz",