From 817e28c16c8e774c36e775eb880f1295d3623bf0 Mon Sep 17 00:00:00 2001 From: Conor <905676+conorriches@users.noreply.github.com> Date: Tue, 5 Nov 2024 16:57:24 +0000 Subject: [PATCH] set REACT_APP _API_ENDPOINT and _AUTHENTICATION_URL as props (#1124) ## Issue Closes https://github.com/RaspberryPiFoundation/learner-experience-integration-tests/issues/5 ## Description * Changed how both utils function: * `src/utils/apiCallHandler.js` * `src/utils/userManager.js` * I've considered how best to adapt these helpers - I could have gone with classes or functions, and while I considered changing these to be classes, this would require more verbose invocation throughout the codebase which ended up making code harder to read, whereas the function-based approach means most calls can be left as-is. * `public/index.html` added which provides a handy link to the web-component.html rather than just a directory listing * Removed a load of code that isn't used any more --------- Co-authored-by: Scott Adams <74183390+sra405@users.noreply.github.com> Co-authored-by: create-issue-branch[bot] <53036503+create-issue-branch[bot]@users.noreply.github.com> Co-authored-by: Lois Wells Co-authored-by: Lois Wells <88904316+loiswells97@users.noreply.github.com> --- .env.example | 3 +- .github/workflows/ci-cd.yml | 2 +- CHANGELOG.md | 8 + public/index.html | 4 + src/app/store.js | 5 +- .../DownloadButton/DownloadButton.jsx | 10 +- .../DownloadButton/DownloadButton.test.js | 25 -- .../ImageUploadButton/ImageUploadButton.jsx | 8 +- .../PyodideRunner/PyodideRunner.jsx | 6 +- .../SkulptRunner/SkulptRunner.jsx | 5 +- src/components/Login/LoginButton.jsx | 42 ---- src/components/Login/LoginButton.test.js | 229 ----------------- src/components/Login/LoginMenu.jsx | 45 ---- src/components/Login/LoginMenu.test.js | 94 ------- src/components/Login/LogoutButton.jsx | 33 --- src/components/Login/LogoutButton.test.js | 45 ---- .../ProjectActionsMenu/ProjectActionsMenu.jsx | 51 ---- .../ProjectActionsMenu.test.js | 55 ----- .../Modals/AccessDeniedNoAuthModal.jsx | 76 ------ .../Modals/AccessDeniedNoAuthModal.test.js | 54 ---- .../AccessDeniedNoAuthModalEmbedded.jsx | 31 --- src/components/Modals/DeleteProjectModal.jsx | 72 ------ .../Modals/DeleteProjectModal.test.js | 94 ------- src/components/Modals/LoginToSaveModal.jsx | 62 ----- .../Modals/LoginToSaveModal.test.js | 45 ---- src/components/Modals/NewProjectModal.jsx | 94 ------- src/components/Modals/NewProjectModal.test.js | 117 --------- src/components/ProjectIndex/ProjectIndex.jsx | 110 --------- .../ProjectIndex/ProjectIndex.test.js | 130 ---------- .../ProjectIndex/ProjectIndexPagination.jsx | 53 ---- .../ProjectIndexPagination.test.js | 166 ------------- .../ProjectIndexHeader/ProjectIndexHeader.jsx | 23 -- .../ProjectListItem/ProjectListItem.jsx | 94 ------- .../ProjectListItem/ProjectListItem.test.js | 49 ---- .../ProjectListTable/ProjectListTable.jsx | 45 ---- .../ProjectListTable/ProjectListTable.test.js | 64 ----- src/containers/WebComponentLoader.jsx | 29 ++- src/containers/WebComponentLoader.test.js | 69 ++++++ src/hooks/useProject.js | 5 + src/hooks/useProject.test.js | 33 ++- src/hooks/useProjectPersistence.js | 3 - src/hooks/useProjectPersistence.test.js | 19 -- src/redux/EditorSlice.js | 100 ++------ src/redux/EditorSlice.test.js | 143 +++-------- src/redux/reducers/loadProjectReducers.js | 2 - .../reducers/loadProjectReducers.test.js | 9 +- src/utils/apiCallHandler.js | 230 ++++++++++-------- src/utils/apiCallHandler.test.js | 22 +- src/utils/i18n.js | 41 ---- src/utils/login.js | 32 --- src/utils/sentry.js | 2 +- src/utils/userManager.js | 26 +- src/web-component.js | 37 +-- 53 files changed, 400 insertions(+), 2451 deletions(-) create mode 100644 public/index.html delete mode 100644 src/components/Login/LoginButton.jsx delete mode 100644 src/components/Login/LoginButton.test.js delete mode 100644 src/components/Login/LoginMenu.jsx delete mode 100644 src/components/Login/LoginMenu.test.js delete mode 100644 src/components/Login/LogoutButton.jsx delete mode 100644 src/components/Login/LogoutButton.test.js delete mode 100644 src/components/Menus/ProjectActionsMenu/ProjectActionsMenu.jsx delete mode 100644 src/components/Menus/ProjectActionsMenu/ProjectActionsMenu.test.js delete mode 100644 src/components/Modals/AccessDeniedNoAuthModal.jsx delete mode 100644 src/components/Modals/AccessDeniedNoAuthModal.test.js delete mode 100644 src/components/Modals/AccessDeniedNoAuthModalEmbedded.jsx delete mode 100644 src/components/Modals/DeleteProjectModal.jsx delete mode 100644 src/components/Modals/DeleteProjectModal.test.js delete mode 100644 src/components/Modals/LoginToSaveModal.jsx delete mode 100644 src/components/Modals/LoginToSaveModal.test.js delete mode 100644 src/components/Modals/NewProjectModal.jsx delete mode 100644 src/components/Modals/NewProjectModal.test.js delete mode 100644 src/components/ProjectIndex/ProjectIndex.jsx delete mode 100644 src/components/ProjectIndex/ProjectIndex.test.js delete mode 100644 src/components/ProjectIndex/ProjectIndexPagination.jsx delete mode 100644 src/components/ProjectIndex/ProjectIndexPagination.test.js delete mode 100644 src/components/ProjectIndexHeader/ProjectIndexHeader.jsx delete mode 100644 src/components/ProjectListItem/ProjectListItem.jsx delete mode 100644 src/components/ProjectListItem/ProjectListItem.test.js delete mode 100644 src/components/ProjectListTable/ProjectListTable.jsx delete mode 100644 src/components/ProjectListTable/ProjectListTable.test.js delete mode 100644 src/utils/login.js diff --git a/.env.example b/.env.example index 85d2e38ad..4d4e2433a 100644 --- a/.env.example +++ b/.env.example @@ -1,10 +1,9 @@ REACT_APP_AUTHENTICATION_CLIENT_ID='editor-dev' -REACT_APP_AUTHENTICATION_URL='http://localhost:9001' REACT_APP_SENTRY_DSN='' REACT_APP_SENTRY_ENV='local' PUBLIC_URL='http://localhost:3011' ASSETS_URL='http://localhost:3011' -REACT_APP_API_ENDPOINT='http://localhost:3009' REACT_APP_GOOGLE_TAG_MANAGER_ID='' +REACT_APP_API_ENDPOINT='http://localhost:3009' REACT_APP_PLAUSIBLE_DATA_DOMAIN='' REACT_APP_PLAUSIBLE_SOURCE='' diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 8f0a5f4b1..8b7134c1b 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -61,7 +61,7 @@ jobs: run: yarn run test --coverage --maxWorkers=4 --workerThreads=true --reporters=default --reporters=jest-junit --reporters=jest-github-actions-reporter env: JEST_JUNIT_OUTPUT_DIR: ./coverage/ - + REACT_APP_API_ENDPOINT: http://localhost:3009 - name: Record coverage run: ./.github/workflows/record_coverage env: diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e5aa1e0a..a6e9617b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## Unreleased +## [0.28.8] - 2024-11-04 + +### Changed +- REACT_APP_API_ENDPOINT env var is now only a default for the editor-wc prop, which can be overridden (#1124) + +### Removed +- REACT_APP_AUTHENTICATION_URL env var no longer used and is instead a editor-wc prop (#1124) + ## [0.28.5] - 2024-11-01 diff --git a/public/index.html b/public/index.html new file mode 100644 index 000000000..1dbfdf1f4 --- /dev/null +++ b/public/index.html @@ -0,0 +1,4 @@ +

You may be looking for...

+ diff --git a/src/app/store.js b/src/app/store.js index aa1691a78..ec4e800b2 100644 --- a/src/app/store.js +++ b/src/app/store.js @@ -2,8 +2,11 @@ import { configureStore } from "@reduxjs/toolkit"; import EditorReducer from "../redux/EditorSlice"; import InstructionsReducer from "../redux/InstructionsSlice"; import { reducer, loadUser } from "redux-oidc"; -import userManager from "../utils/userManager"; +import UserManager from "../utils/userManager"; +// TODO - not used but keeping this in preparation for using +// src/components/Editor/ImageUploadButton/ImageUploadButton.jsx +const userManager = UserManager({ reactAppAuthenticationUrl: "TODO" }); const store = configureStore({ reducer: { editor: EditorReducer, diff --git a/src/components/DownloadButton/DownloadButton.jsx b/src/components/DownloadButton/DownloadButton.jsx index 4016ae54c..eb9c15b8d 100644 --- a/src/components/DownloadButton/DownloadButton.jsx +++ b/src/components/DownloadButton/DownloadButton.jsx @@ -4,11 +4,10 @@ import { toSnakeCase } from "js-convert-case"; import JSZip from "jszip"; import JSZipUtils from "jszip-utils"; import { useTranslation } from "react-i18next"; -import { useDispatch, useSelector } from "react-redux"; +import { useSelector } from "react-redux"; import PropTypes from "prop-types"; import DesignSystemButton from "../DesignSystemButton/DesignSystemButton"; -import { closeLoginToSaveModal } from "../../redux/EditorSlice"; const DownloadButton = (props) => { const { @@ -20,10 +19,6 @@ const DownloadButton = (props) => { } = props; const { t } = useTranslation(); const project = useSelector((state) => state.editor.project); - const loginToSaveModalShowing = useSelector( - (state) => state.editor.loginToSaveModalShowing, - ); - const dispatch = useDispatch(); const urlToPromise = (url) => { return new Promise(function (resolve, reject) { @@ -42,9 +37,6 @@ const DownloadButton = (props) => { window.plausible("Download"); } - if (loginToSaveModalShowing) { - dispatch(closeLoginToSaveModal()); - } const zip = new JSZip(); project.components.forEach((file) => { diff --git a/src/components/DownloadButton/DownloadButton.test.js b/src/components/DownloadButton/DownloadButton.test.js index 7c2c50d35..ef9e38253 100644 --- a/src/components/DownloadButton/DownloadButton.test.js +++ b/src/components/DownloadButton/DownloadButton.test.js @@ -6,7 +6,6 @@ import DownloadButton from "./DownloadButton"; import FileSaver from "file-saver"; import JSZip from "jszip"; import JSZipUtils from "jszip-utils"; -import { closeLoginToSaveModal } from "../../redux/EditorSlice"; jest.mock("file-saver"); jest.mock("jszip"); @@ -124,27 +123,3 @@ describe("Downloading project with no name set", () => { ); }); }); - -test("If login to save modal open, closes it when download clicked", () => { - JSZip.mockClear(); - const middlewares = []; - const mockStore = configureStore(middlewares); - const initialState = { - editor: { - project: { - components: [], - image_list: [], - }, - loginToSaveModalShowing: true, - }, - }; - const store = mockStore(initialState); - render( - - {}} /> - , - ); - const downloadButton = screen.queryByText("Download").parentElement; - fireEvent.click(downloadButton); - expect(store.getActions()).toEqual([closeLoginToSaveModal()]); -}); diff --git a/src/components/Editor/ImageUploadButton/ImageUploadButton.jsx b/src/components/Editor/ImageUploadButton/ImageUploadButton.jsx index 11ac2fdf4..ecb3b144d 100644 --- a/src/components/Editor/ImageUploadButton/ImageUploadButton.jsx +++ b/src/components/Editor/ImageUploadButton/ImageUploadButton.jsx @@ -9,7 +9,7 @@ import { updateImages, setNameError } from "../../../redux/EditorSlice"; import Button from "../../Button/Button"; import NameErrorMessage from "../ErrorMessage/NameErrorMessage"; import store from "../../../app/store"; -import { uploadImages } from "../../../utils/apiCallHandler"; +import ApiCallHandler from "../../../utils/apiCallHandler"; const allowedExtensions = { python: ["jpg", "jpeg", "png", "gif"], @@ -30,7 +30,7 @@ const allowedExtensionsString = (projectType) => { } }; -const ImageUploadButton = () => { +const ImageUploadButton = ({ reactAppApiEndpoint }) => { const [modalIsOpen, setIsOpen] = useState(false); const [files, setFiles] = useState([]); const dispatch = useDispatch(); @@ -51,6 +51,10 @@ const ImageUploadButton = () => { setIsOpen(true); }; const saveImages = async () => { + const { uploadImages } = ApiCallHandler({ + reactAppApiEndpoint, + }); + files.every((file) => { const fileName = file.name; const extension = fileName.split(".").slice(1).join(".").toLowerCase(); diff --git a/src/components/Editor/Runners/PythonRunner/PyodideRunner/PyodideRunner.jsx b/src/components/Editor/Runners/PythonRunner/PyodideRunner/PyodideRunner.jsx index 8bb232feb..19a6e71a5 100644 --- a/src/components/Editor/Runners/PythonRunner/PyodideRunner/PyodideRunner.jsx +++ b/src/components/Editor/Runners/PythonRunner/PyodideRunner/PyodideRunner.jsx @@ -12,7 +12,7 @@ import { Tab, Tabs, TabList, TabPanel } from "react-tabs"; import { useMediaQuery } from "react-responsive"; import { MOBILE_MEDIA_QUERY } from "../../../../../utils/mediaQueryBreakpoints"; import ErrorMessage from "../../../ErrorMessage/ErrorMessage"; -import { createError } from "../../../../../utils/apiCallHandler"; +import ApiCallHandler from "../../../../../utils/apiCallHandler"; import VisualOutputPane from "./VisualOutputPane"; import OutputViewToggle from "../OutputViewToggle"; import { SettingsContext } from "../../../../../utils/settings"; @@ -47,6 +47,7 @@ const PyodideRunner = (props) => { const userId = user?.profile?.user; const isSplitView = useSelector((s) => s.editor.isSplitView); const isEmbedded = useSelector((s) => s.editor.isEmbedded); + const reactAppApiEndpoint = useSelector((s) => s.editor.reactAppApiEndpoint); const codeRunTriggered = useSelector((s) => s.editor.codeRunTriggered); const codeRunStopped = useSelector((s) => s.editor.codeRunStopped); const output = useRef(); @@ -180,6 +181,9 @@ const PyodideRunner = (props) => { errorMessage += `:\n${mistake}`; } + const { createError } = ApiCallHandler({ + reactAppApiEndpoint, + }); createError(projectIdentifier, userId, { errorType: type, errorMessage }); } diff --git a/src/components/Editor/Runners/PythonRunner/SkulptRunner/SkulptRunner.jsx b/src/components/Editor/Runners/PythonRunner/SkulptRunner/SkulptRunner.jsx index dc852989c..4e835f4bf 100644 --- a/src/components/Editor/Runners/PythonRunner/SkulptRunner/SkulptRunner.jsx +++ b/src/components/Editor/Runners/PythonRunner/SkulptRunner/SkulptRunner.jsx @@ -15,7 +15,7 @@ import { triggerDraw, } from "../../../../../redux/EditorSlice"; import ErrorMessage from "../../../ErrorMessage/ErrorMessage"; -import { createError } from "../../../../../utils/apiCallHandler"; +import ApiCallHandler from "../../../../../utils/apiCallHandler"; import store from "../../../../../redux/stores/WebComponentStore"; import VisualOutputPane from "../VisualOutputPane"; import OutputViewToggle from "../OutputViewToggle"; @@ -71,6 +71,7 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => { ); const codeRunStopped = useSelector((state) => state.editor.codeRunStopped); const drawTriggered = useSelector((state) => state.editor.drawTriggered); + const reactAppApiEndpoint = useSelector((s) => s.editor.reactAppApiEndpoint); const output = useRef(); const dispatch = useDispatch(); const { t } = useTranslation(); @@ -314,6 +315,8 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => { userId = user.profile?.user; } + const { createError } = ApiCallHandler({ reactAppApiEndpoint }); + errorMessage = `${errorType}: ${errorDescription} on line ${lineNumber} of ${fileName}${ explanation ? `. ${explanation}` : "" }`; diff --git a/src/components/Login/LoginButton.jsx b/src/components/Login/LoginButton.jsx deleted file mode 100644 index c4a703e8b..000000000 --- a/src/components/Login/LoginButton.jsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from "react"; -import { useLocation } from "react-router-dom"; -import { useSelector } from "react-redux"; -import Button from "../Button/Button"; -import { login } from "../../utils/login"; -import PropTypes from "prop-types"; - -const LoginButton = ({ buttonText, className, triggerSave, loginRedirect }) => { - const location = useLocation(); - const project = useSelector((state) => state.editor.project); - const accessDeniedData = useSelector( - (state) => state.editor.modals?.accessDenied || null, - ); - - const onLoginButtonClick = (event) => { - event.preventDefault(); - login({ - project, - location, - triggerSave, - accessDeniedData, - loginRedirect, - }); - }; - - return ( -