diff --git a/.eslintrc.json b/.eslintrc.json index d12b94619..530cfa5e8 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -37,7 +37,7 @@ { "singleQuote": false, "jsxSingleQuote": false, - "trailingComma": "es5", + "trailingComma": "all", "semi": true, "bracketSpacing": true, "arrowParens": "always" diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 8f0a5f4b1..2e3cff9e7 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -96,7 +96,6 @@ jobs: wait-on: "http://localhost:3011" quiet: true env: - REACT_APP_API_ENDPOINT: "https://test-editor-api.raspberrypi.org" PUBLIC_URL: "http://localhost:3011" ASSETS_URL: "http://localhost:3011" REACT_APP_PLAUSIBLE_SOURCE: "" @@ -117,7 +116,6 @@ jobs: assets_url: https://editor-static.raspberrypi.org environment: production prefix: releases - react_app_api_endpoint: https://editor-api.raspberrypi.org react_app_authentication_url: https://auth-v1.raspberrypi.org react_app_base_url: "" react_app_google_tag_manager_id: GTM-5FWFWFJ diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2f2199028..3877c6c7d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -18,10 +18,6 @@ on: required: false default: "https://staging-editor-static.raspberrypi.org" type: string - react_app_api_endpoint: - required: false - default: "https://staging-editor-api.raspberrypi.org" - type: string react_app_authentication_client_id: required: false default: editor-api @@ -132,7 +128,6 @@ jobs: env: PUBLIC_URL: ${{ needs.setup-environment.outputs.public_url }} ASSETS_URL: ${{ needs.setup-environment.outputs.assets_url }} - REACT_APP_API_ENDPOINT: ${{ inputs.react_app_api_endpoint }} REACT_APP_AUTHENTICATION_CLIENT_ID: ${{ inputs.react_app_authentication_client_id }} REACT_APP_AUTHENTICATION_URL: ${{ inputs.react_app_authentication_url }} REACT_APP_BASE_URL: ${{ needs.setup-environment.outputs.react_app_base_url }} diff --git a/cypress.config.mjs b/cypress.config.mjs index 29e8c298e..90d25117d 100644 --- a/cypress.config.mjs +++ b/cypress.config.mjs @@ -23,7 +23,4 @@ export default defineConfig({ openMode: 0, }, }, - env: { - REACT_APP_API_ENDPOINT: process.env.REACT_APP_API_ENDPOINT, - }, }); diff --git a/cypress/e2e/spec-html.cy.js b/cypress/e2e/spec-html.cy.js index 4c2643f8a..0604e265b 100644 --- a/cypress/e2e/spec-html.cy.js +++ b/cypress/e2e/spec-html.cy.js @@ -35,9 +35,7 @@ beforeEach(() => { // intercept request to editor api cy.intercept( "GET", - `${Cypress.env( - "REACT_APP_API_ENDPOINT", - )}/api/projects/blank-html-starter?locale=en`, + "https://test-editor-api.raspberrypi.org/api/projects/blank-html-starter?locale=en", defaultHtmlProject, ); }); diff --git a/src/components/DownloadButton/DownloadButton.jsx b/src/components/DownloadButton/DownloadButton.jsx index b6c81b5f5..eb9c15b8d 100644 --- a/src/components/DownloadButton/DownloadButton.jsx +++ b/src/components/DownloadButton/DownloadButton.jsx @@ -54,8 +54,8 @@ const DownloadButton = (props) => { project.name || t("header.downloadFileNameDefault", { project_type: project.project_type, - }) - )}` + }), + )}`, ); }; diff --git a/src/components/Editor/ImageUploadButton/ImageUploadButton.jsx b/src/components/Editor/ImageUploadButton/ImageUploadButton.jsx index c90202739..ecb3b144d 100644 --- a/src/components/Editor/ImageUploadButton/ImageUploadButton.jsx +++ b/src/components/Editor/ImageUploadButton/ImageUploadButton.jsx @@ -36,7 +36,7 @@ const ImageUploadButton = ({ reactAppApiEndpoint }) => { const dispatch = useDispatch(); const projectType = useSelector((state) => state.editor.project.project_type); const projectIdentifier = useSelector( - (state) => state.editor.project.identifier + (state) => state.editor.project.identifier, ); const projectImages = useSelector((state) => state.editor.project.image_list); const imageNames = projectImages.map((image) => `${image.filename}`); @@ -69,8 +69,8 @@ const ImageUploadButton = ({ reactAppApiEndpoint }) => { } else if (!allowedExtensions[projectType].includes(extension)) { dispatch( setNameError( - `Image names must end in ${allowedExtensionsString(projectType)}.` - ) + `Image names must end in ${allowedExtensionsString(projectType)}.`, + ), ); return false; } else { @@ -82,7 +82,7 @@ const ImageUploadButton = ({ reactAppApiEndpoint }) => { const response = await uploadImages( projectIdentifier, user.access_token, - files + files, ); dispatch(updateImages(response.data.image_list)); closeModal(); diff --git a/src/components/Editor/Runners/PythonRunner/PyodideRunner/PyodideRunner.jsx b/src/components/Editor/Runners/PythonRunner/PyodideRunner/PyodideRunner.jsx index 6d96e4b74..19a6e71a5 100644 --- a/src/components/Editor/Runners/PythonRunner/PyodideRunner/PyodideRunner.jsx +++ b/src/components/Editor/Runners/PythonRunner/PyodideRunner/PyodideRunner.jsx @@ -84,7 +84,7 @@ const PyodideRunner = (props) => { data.line, data.mistake, data.type, - data.info + data.info, ); break; case "handleVisual": @@ -210,8 +210,8 @@ const PyodideRunner = (props) => { projectImages.map(({ filename, url }) => fetch(url) .then((response) => response.arrayBuffer()) - .then((buffer) => writeFile(filename, buffer)) - ) + .then((buffer) => writeFile(filename, buffer)), + ), ); for (const { name, extension, content } of projectCode) { @@ -220,7 +220,7 @@ const PyodideRunner = (props) => { // program is the content of the component with name main and extension py const program = projectCode.find( - (component) => component.name === "main" && component.extension === "py" + (component) => component.name === "main" && component.extension === "py", ).content; if (interruptBuffer.current) { diff --git a/src/components/Editor/Runners/PythonRunner/PythonRunner.jsx b/src/components/Editor/Runners/PythonRunner/PythonRunner.jsx index 52a50a096..01bcf7ca5 100644 --- a/src/components/Editor/Runners/PythonRunner/PythonRunner.jsx +++ b/src/components/Editor/Runners/PythonRunner/PythonRunner.jsx @@ -16,10 +16,10 @@ const SKULPT_ONLY_MODULES = [ const PythonRunner = () => { const project = useSelector((state) => state.editor.project); const codeRunTriggered = useSelector( - (state) => state.editor.codeRunTriggered + (state) => state.editor.codeRunTriggered, ); const senseHatAlwaysEnabled = useSelector( - (state) => state.editor.senseHatAlwaysEnabled + (state) => state.editor.senseHatAlwaysEnabled, ); const [usePyodide, setUsePyodide] = useState(true); const { t } = useTranslation(); @@ -32,7 +32,7 @@ const PythonRunner = () => { const getImports = (code) => { const codeWithoutMultilineStrings = code.replace( /'''[\s\S]*?'''|"""[\s\S]*?"""/gm, - "" + "", ); const importRegex = /(?<=^\s*)(from\s+([a-zA-Z0-9_.]+)(\s+import\s+([a-zA-Z0-9_.]+))?)|(?<=^\s*)(import\s+([a-zA-Z0-9_.]+))/gm; @@ -43,7 +43,7 @@ const PythonRunner = () => { match .split(/from|import/) .filter(Boolean) - .map((s) => s.trim())[0] + .map((s) => s.trim())[0], ) : []; if (code.includes(`# ${t("input.comment.py5")}`)) { @@ -57,7 +57,7 @@ const PythonRunner = () => { try { const imports = getImports(component.content); const hasSkulptOnlyModules = imports.some((name) => - SKULPT_ONLY_MODULES.includes(name) + SKULPT_ONLY_MODULES.includes(name), ); if (hasSkulptOnlyModules || senseHatAlwaysEnabled) { setUsePyodide(false); diff --git a/src/components/Editor/Runners/PythonRunner/SkulptRunner/SkulptRunner.jsx b/src/components/Editor/Runners/PythonRunner/SkulptRunner/SkulptRunner.jsx index f4ad01b31..4e835f4bf 100644 --- a/src/components/Editor/Runners/PythonRunner/SkulptRunner/SkulptRunner.jsx +++ b/src/components/Editor/Runners/PythonRunner/SkulptRunner/SkulptRunner.jsx @@ -57,17 +57,17 @@ const externalLibraries = { const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => { const projectCode = useSelector((state) => state.editor.project.components); const mainComponent = projectCode?.find( - (component) => component.name === "main" && component.extension === "py" + (component) => component.name === "main" && component.extension === "py", ); const projectIdentifier = useSelector( - (state) => state.editor.project.identifier + (state) => state.editor.project.identifier, ); const user = useSelector((state) => state.auth.user); const isSplitView = useSelector((state) => state.editor.isSplitView); const isEmbedded = useSelector((state) => state.editor.isEmbedded); const isOutputOnly = useSelector((state) => state.editor.isOutputOnly); const codeRunTriggered = useSelector( - (state) => state.editor.codeRunTriggered + (state) => state.editor.codeRunTriggered, ); const codeRunStopped = useSelector((state) => state.editor.codeRunStopped); const drawTriggered = useSelector((state) => state.editor.drawTriggered); @@ -190,7 +190,7 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => { .then((code) => { if (!code) { throw new Sk.builtin.ImportError( - "Failed to load remote module" + "Failed to load remote module", ); } externalLibraries[library].code = code; @@ -199,7 +199,7 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => { function mapUrlToPromise(path) { // If the script is already in the DOM don't add it again. const existingScriptElement = document.querySelector( - `script[src="${path}"]` + `script[src="${path}"]`, ); if (!existingScriptElement) { return new Promise(function (resolve, _reject) { @@ -221,11 +221,11 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => { (p, url) => { return p.then(() => mapUrlToPromise(url)); }, - Promise.resolve() + Promise.resolve(), ); // initial } else { promise = Promise.all( - (externalLibraryInfo.dependencies || []).map(mapUrlToPromise) + (externalLibraryInfo.dependencies || []).map(mapUrlToPromise), ); } @@ -235,10 +235,10 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => { }) .catch(function () { throw new Sk.builtin.ImportError( - "Failed to load dependencies required" + "Failed to load dependencies required", ); }); - }) + }), ) ); } @@ -358,7 +358,7 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => { if (prog.includes(`# ${t("input.comment.py5")}`)) { prog = prog.replace( `# ${t("input.comment.py5")}`, - "from py5_imported_mode import *" + "from py5_imported_mode import *", ); if (!prog.match(/(\nrun_sketch)/)) { diff --git a/src/containers/WebComponentLoader.jsx b/src/containers/WebComponentLoader.jsx index e3b8922d4..487142f3a 100644 --- a/src/containers/WebComponentLoader.jsx +++ b/src/containers/WebComponentLoader.jsx @@ -68,19 +68,19 @@ const WebComponentLoader = (props) => { const justLoaded = useSelector((state) => state.editor.justLoaded); const remixLoadFailed = useSelector((state) => state.editor.remixLoadFailed); const hasShownSavePrompt = useSelector( - (state) => state.editor.hasShownSavePrompt + (state) => state.editor.hasShownSavePrompt, ); const saveTriggered = useSelector((state) => state.editor.saveTriggered); const modals = useSelector((state) => state.editor.modals); const errorModalShowing = useSelector( - (state) => state.editor.errorModalShowing + (state) => state.editor.errorModalShowing, ); const newFileModalShowing = useSelector( - (state) => state.editor.newFileModalShowing + (state) => state.editor.newFileModalShowing, ); const renameFileModalShowing = useSelector( - (state) => state.editor.renameFileModalShowing + (state) => state.editor.renameFileModalShowing, ); const [cookies, setCookie] = useCookies(["theme", "fontSize"]); diff --git a/src/hooks/useProject.js b/src/hooks/useProject.js index 0d85300b8..3174735f2 100644 --- a/src/hooks/useProject.js +++ b/src/hooks/useProject.js @@ -26,7 +26,7 @@ export const useProject = ({ ? null : JSON.parse(localStorage.getItem(id || "project")); const [cachedProject, setCachedProject] = useState( - getCachedProject(projectIdentifier) + getCachedProject(projectIdentifier), ); const { i18n } = useTranslation(); const dispatch = useDispatch(); @@ -60,7 +60,7 @@ export const useProject = ({ locale: i18n.language, accessToken, assetsOnly: true, - }) + }), ); return; } @@ -72,7 +72,7 @@ export const useProject = ({ identifier: projectIdentifier, locale: i18n.language, accessToken: accessToken, - }) + }), ); return; } @@ -109,7 +109,7 @@ export const useProject = ({ reactAppApiEndpoint, identifier: projectIdentifier, accessToken: accessToken, - }) + }), ); // Prevents a failure on the initial render (using a ref to avoid triggering a render) @@ -127,7 +127,7 @@ export const useProject = ({ identifier: projectIdentifier, locale: i18n.language, accessToken: accessToken, - }) + }), ); loadDispatched.current = true; @@ -142,7 +142,7 @@ export const useProject = ({ const mainComponent = project.components?.find( (component) => component.name === defaultName && - component.extension === defaultExtension + component.extension === defaultExtension, ) || { name: defaultName, extension: defaultExtension, content: "" }; const otherComponents = @@ -151,7 +151,7 @@ export const useProject = ({ !( component.name === defaultName && component.extension === defaultExtension - ) + ), ) || []; const updatedProject = { diff --git a/src/hooks/useProject.test.js b/src/hooks/useProject.test.js index 0a93fddd7..ed4b88d63 100644 --- a/src/hooks/useProject.test.js +++ b/src/hooks/useProject.test.js @@ -61,11 +61,11 @@ describe("When not embedded", () => { test("If cached project matches identifer uses cached project", () => { localStorage.setItem( cachedProject.identifier, - JSON.stringify(cachedProject) + JSON.stringify(cachedProject), ); renderHook( () => useProject({ projectIdentifier: cachedProject.identifier }), - { wrapper } + { wrapper }, ); expect(setProject).toHaveBeenCalledWith(cachedProject); }); @@ -73,11 +73,11 @@ describe("When not embedded", () => { test("If cached project matches identifer clears cached project", () => { localStorage.setItem( cachedProject.identifier, - JSON.stringify(cachedProject) + JSON.stringify(cachedProject), ); renderHook( () => useProject({ projectIdentifier: cachedProject.identifier }), - { wrapper } + { wrapper }, ); expect(localStorage.getItem("project")).toBeNull(); }); @@ -89,11 +89,11 @@ describe("When not embedded", () => { () => useProject({ projectIdentifier: "my-favourite-project" }), { wrapper, - } + }, ); expect(syncProject).toHaveBeenCalledWith("load"); await waitFor(() => - expect(setProject).not.toHaveBeenCalledWith(cachedProject) + expect(setProject).not.toHaveBeenCalledWith(cachedProject), ); }); @@ -107,7 +107,7 @@ describe("When not embedded", () => { accessToken, reactAppApiEndpoint, }), - { wrapper } + { wrapper }, ); expect(syncProject).toHaveBeenCalledWith("load"); await waitFor(() => @@ -116,7 +116,7 @@ describe("When not embedded", () => { locale: "ja-JP", accessToken, reactAppApiEndpoint, - }) + }), ); }); @@ -131,7 +131,7 @@ describe("When not embedded", () => { loadCache: false, reactAppApiEndpoint, }), - { wrapper } + { wrapper }, ); expect(syncProject).toHaveBeenCalledWith("load"); await waitFor(() => @@ -140,7 +140,7 @@ describe("When not embedded", () => { locale: "ja-JP", accessToken, reactAppApiEndpoint, - }) + }), ); }); @@ -153,7 +153,7 @@ describe("When not embedded", () => { accessToken, reactAppApiEndpoint, }), - { wrapper } + { wrapper }, ); expect(syncProject).toHaveBeenCalledWith("load"); await waitFor(() => @@ -162,7 +162,7 @@ describe("When not embedded", () => { locale: "ja-JP", accessToken, reactAppApiEndpoint, - }) + }), ); }); @@ -172,7 +172,7 @@ describe("When not embedded", () => { () => useProject({ projectIdentifier: "my-favourite-project" }), { wrapper, - } + }, ); expect(syncProject).toHaveBeenCalledWith("load"); await waitFor(() => expect(setProject).not.toHaveBeenCalled()); @@ -188,7 +188,7 @@ describe("When not embedded", () => { isEmbedded: true, isBrowserPreview: true, }), - { wrapper } + { wrapper }, ); expect(setProject).toHaveBeenCalledWith(cachedProject); }); @@ -206,7 +206,7 @@ describe("When not embedded", () => { code, accessToken, }), - { wrapper } + { wrapper }, ); expect(setProject).toHaveBeenCalledWith(expectedProject); }); @@ -221,7 +221,7 @@ describe("When not embedded", () => { loadRemix: true, reactAppApiEndpoint, }), - { wrapper } + { wrapper }, ); expect(syncProject).toHaveBeenCalledWith("loadRemix"); await waitFor(() => @@ -229,7 +229,7 @@ describe("When not embedded", () => { identifier: project1.identifier, accessToken, reactAppApiEndpoint, - }) + }), ); }); @@ -244,7 +244,7 @@ describe("When not embedded", () => { remixLoadFailed: true, reactAppApiEndpoint, }), - { wrapper } + { wrapper }, ); expect(syncProject).toHaveBeenCalledWith("load"); await waitFor(() => @@ -253,7 +253,7 @@ describe("When not embedded", () => { locale: "ja-JP", accessToken, reactAppApiEndpoint, - }) + }), ); }); @@ -266,7 +266,7 @@ describe("When not embedded", () => { accessToken, reactAppApiEndpoint, }), - { wrapper } + { wrapper }, ); expect(syncProject).toHaveBeenCalledWith("load"); await waitFor(() => @@ -276,7 +276,7 @@ describe("When not embedded", () => { accessToken, assetsOnly: true, reactAppApiEndpoint, - }) + }), ); }); @@ -493,7 +493,7 @@ describe("When embedded", () => { isEmbedded: true, reactAppApiEndpoint, }), - { wrapper } + { wrapper }, ); expect(syncProject).toHaveBeenCalledWith("load"); await waitFor(() => @@ -502,7 +502,7 @@ describe("When embedded", () => { locale: "ja-JP", accessToken, reactAppApiEndpoint, - }) + }), ); }); diff --git a/src/redux/EditorSlice.js b/src/redux/EditorSlice.js index b0c95436e..9d113727d 100644 --- a/src/redux/EditorSlice.js +++ b/src/redux/EditorSlice.js @@ -20,7 +20,7 @@ export const syncProject = (actionName) => autosave, assetsOnly, }, - { rejectWithValue } + { rejectWithValue }, ) => { const { createOrUpdateProject, @@ -75,7 +75,7 @@ export const syncProject = (actionName) => return false; } }, - } + }, ); export const loadProjectList = createAsyncThunk( @@ -90,7 +90,7 @@ export const loadProjectList = createAsyncThunk( page, links: parseLinkHeader(response.headers.link), }; - } + }, ); const initialState = { @@ -148,10 +148,10 @@ export const EditorSlice = createSlice({ .map((fileNames) => fileNames.includes(action.payload)) .indexOf(true); const closedFileIndex = state.openFiles[panelIndex].indexOf( - action.payload + action.payload, ); state.openFiles[panelIndex] = state.openFiles[panelIndex].filter( - (fileName) => fileName !== action.payload + (fileName) => fileName !== action.payload, ); if ( state.focussedFileIndices[panelIndex] >= diff --git a/src/redux/EditorSlice.test.js b/src/redux/EditorSlice.test.js index 97444a938..186dac7a8 100644 --- a/src/redux/EditorSlice.test.js +++ b/src/redux/EditorSlice.test.js @@ -47,7 +47,7 @@ test("Action setLoadRemixDisabled sets loadRemixDisabled to true", () => { loadRemixDisabled: true, }; expect(reducer(previousState, setLoadRemixDisabled(true))).toEqual( - expectedState + expectedState, ); }); @@ -59,7 +59,7 @@ test("Action setLoadRemixDisabled sets loadRemixDisabled to false", () => { loadRemixDisabled: false, }; expect(reducer(previousState, setLoadRemixDisabled(false))).toEqual( - expectedState + expectedState, ); }); @@ -93,8 +93,8 @@ test("Action setErrorDetails sets errorDetails to true", () => { expect( reducer( previousState, - setErrorDetails({ type: "Interrupted", message: "Some error message" }) - ) + setErrorDetails({ type: "Interrupted", message: "Some error message" }), + ), ).toEqual(expectedState); }); @@ -122,8 +122,8 @@ test("Showing rename modal sets file state and showing status", () => { expect( reducer( previousState, - showRenameFileModal({ name: "main", ext: ".py", fileKey: 0 }) - ) + showRenameFileModal({ name: "main", ext: ".py", fileKey: 0 }), + ), ).toEqual(expectedState); }); @@ -195,13 +195,13 @@ describe("When project has no identifier", () => { await saveAction(dispatch, () => initialState); expect(mockCreateOrUpdateProject).toHaveBeenCalledWith( project, - access_token + access_token, ); }); test("Successfully creating project triggers fulfilled action", async () => { mockCreateOrUpdateProject.mockImplementationOnce(() => - Promise.resolve({ status: 200 }) + Promise.resolve({ status: 200 }), ); await saveAction(dispatch, () => initialState); expect(dispatch.mock.calls[1][0].type).toBe("editor/saveProject/fulfilled"); @@ -222,8 +222,8 @@ describe("When project has no identifier", () => { expect( reducer( initialState.editor, - saveThunk.fulfilled({ project: returnedProject }) - ) + saveThunk.fulfilled({ project: returnedProject }), + ), ).toEqual(expectedState); }); @@ -282,7 +282,7 @@ describe("When project has an identifier", () => { test("The saveProject/pending action sets saveTriggered to false", async () => { const newState = reducer( initialState.editor, - saveThunk.pending({ project }) + saveThunk.pending({ project }), ); expect(newState.saveTriggered).toBe(false); }); @@ -291,13 +291,13 @@ describe("When project has an identifier", () => { await saveAction(dispatch, () => initialState); expect(mockCreateOrUpdateProject).toHaveBeenCalledWith( project, - access_token + access_token, ); }); test("Successfully updating project triggers fulfilled action", async () => { mockCreateOrUpdateProject.mockImplementationOnce(() => - Promise.resolve({ status: 200 }) + Promise.resolve({ status: 200 }), ); await saveAction(dispatch, () => initialState); expect(dispatch.mock.calls[1][0].type).toBe("editor/saveProject/fulfilled"); @@ -310,14 +310,14 @@ describe("When project has an identifier", () => { }; expect( - reducer(initialState.editor, saveThunk.fulfilled({ project })) + reducer(initialState.editor, saveThunk.fulfilled({ project })), ).toEqual(expectedState); }); test("The remixProject/pending action sets saveTriggered to false", async () => { const newState = reducer( initialState.editor, - remixThunk.pending({ project }) + remixThunk.pending({ project }), ); expect(newState.saveTriggered).toBe(false); }); @@ -329,11 +329,11 @@ describe("When project has an identifier", () => { test("Successfully remixing project triggers fulfilled action", async () => { mockCreateRemix.mockImplementationOnce(() => - Promise.resolve({ status: 200 }) + Promise.resolve({ status: 200 }), ); await remixAction(dispatch, () => initialState); expect(dispatch.mock.calls[1][0].type).toBe( - "editor/remixProject/fulfilled" + "editor/remixProject/fulfilled", ); }); @@ -346,7 +346,7 @@ describe("When project has an identifier", () => { }; expect( - reducer(initialState.editor, remixThunk.fulfilled({ project })) + reducer(initialState.editor, remixThunk.fulfilled({ project })), ).toEqual(expectedState); }); @@ -358,7 +358,7 @@ describe("When project has an identifier", () => { reducer( initialState.editor, - remixThunk.fulfilled({ project: remixedProject }) + remixThunk.fulfilled({ project: remixedProject }), ); expect(localStorage.getItem(project.identifier)).toBeNull(); @@ -393,7 +393,7 @@ describe("When renaming a project from the rename project modal", () => { projectListLoaded: "idle", }; expect( - reducer(initialState.editor, saveThunk.fulfilled({ project })) + reducer(initialState.editor, saveThunk.fulfilled({ project })), ).toEqual(expectedState); }); }); @@ -426,17 +426,17 @@ describe("When deleting a project", () => { await deleteAction(dispatch, () => initialState); expect(mockDeleteProject).toHaveBeenCalledWith( project.identifier, - access_token + access_token, ); }); test("Successfully deleting project triggers fulfilled action", async () => { mockDeleteProject.mockImplementationOnce(() => - Promise.resolve({ status: 200 }) + Promise.resolve({ status: 200 }), ); await deleteAction(dispatch, () => initialState); expect(dispatch.mock.calls[1][0].type).toBe( - "editor/deleteProject/fulfilled" + "editor/deleteProject/fulfilled", ); }); @@ -447,7 +447,7 @@ describe("When deleting a project", () => { projectListLoaded: "idle", }; expect(reducer(initialState.editor, deleteThunk.fulfilled({}))).toEqual( - expectedState + expectedState, ); }); }); @@ -482,8 +482,8 @@ describe("Opening files", () => { expect( reducer( initialState, - setFocussedFileIndex({ panelIndex: 0, fileIndex: 1 }) - ) + setFocussedFileIndex({ panelIndex: 0, fileIndex: 1 }), + ), ).toEqual(expectedState); }); }); @@ -563,8 +563,8 @@ describe("Updating file name", () => { expect( reducer( initialState, - updateComponentName({ key: 0, name: "my_file", extension: "py" }) - ) + updateComponentName({ key: 0, name: "my_file", extension: "py" }), + ), ).toEqual(expectedState); }); @@ -582,8 +582,8 @@ describe("Updating file name", () => { expect( reducer( initialState, - updateComponentName({ key: 1, name: "my_file", extension: "py" }) - ) + updateComponentName({ key: 1, name: "my_file", extension: "py" }), + ), ).toEqual(expectedState); }); }); @@ -619,7 +619,7 @@ describe("Loading a project", () => { expect(mockReadProject).toHaveBeenCalledWith( identifier, locale, - accessToken + accessToken, ); }); }); @@ -641,7 +641,7 @@ describe("Loading a project", () => { expect(mockLoadAssets).toHaveBeenCalledWith( identifier, locale, - accessToken + accessToken, ); }); }); diff --git a/src/redux/reducers/loadProjectReducers.test.js b/src/redux/reducers/loadProjectReducers.test.js index 5ccb388a9..9b1a08b39 100644 --- a/src/redux/reducers/loadProjectReducers.test.js +++ b/src/redux/reducers/loadProjectReducers.test.js @@ -45,7 +45,7 @@ const requestingAProject = function (project, projectFile) { expect(mockReadProject).toHaveBeenCalledWith( "my-project-identifier", "ja-JP", - "my_token" + "my_token", ); }); @@ -80,7 +80,7 @@ const requestingAProject = function (project, projectFile) { loading: "failed", }; expect(reducer(initialState, syncProject("load").fulfilled())).toEqual( - initialState + initialState, ); }); diff --git a/src/utils/apiCallHandler.test.js b/src/utils/apiCallHandler.test.js index e8e8d6d52..f05b2992d 100644 --- a/src/utils/apiCallHandler.test.js +++ b/src/utils/apiCallHandler.test.js @@ -37,14 +37,14 @@ describe("Testing project API calls", () => { ...newProject, }, }, - }) + }), ); const data = await createOrUpdateProject(newProject); expect(axios.post).toHaveBeenCalledWith( `${host}/api/projects`, { project: newProject }, - defaultHeaders + defaultHeaders, ); expect(data).toStrictEqual({ status: 204, @@ -81,7 +81,7 @@ describe("Testing project API calls", () => { project_type: "python", }, }, - authHeaders + authHeaders, ); }); @@ -97,7 +97,7 @@ describe("Testing project API calls", () => { expect(axios.put).toHaveBeenCalledWith( `${host}/api/projects/${project["identifier"]}`, { project: project }, - defaultHeaders + defaultHeaders, ); }); @@ -108,7 +108,7 @@ describe("Testing project API calls", () => { await readProject(projectIdentifier); expect(axios.get).toHaveBeenCalledWith( `${host}/api/projects/${projectIdentifier}`, - defaultHeaders + defaultHeaders, ); }); @@ -120,7 +120,7 @@ describe("Testing project API calls", () => { await readProject(projectIdentifier, locale); expect(axios.get).toHaveBeenCalledWith( `${host}/api/projects/${projectIdentifier}?locale=${locale}`, - defaultHeaders + defaultHeaders, ); }); @@ -131,7 +131,7 @@ describe("Testing project API calls", () => { await readProject(projectIdentifier, null, accessToken); expect(axios.get).toHaveBeenCalledWith( `${host}/api/projects/${projectIdentifier}`, - authHeaders + authHeaders, ); }); @@ -142,7 +142,7 @@ describe("Testing project API calls", () => { await loadAssets(projectIdentifier); expect(axios.get).toHaveBeenCalledWith( `${host}/api/projects/${projectIdentifier}/images`, - defaultHeaders + defaultHeaders, ); }); @@ -154,7 +154,7 @@ describe("Testing project API calls", () => { await loadAssets(projectIdentifier, locale); expect(axios.get).toHaveBeenCalledWith( `${host}/api/projects/${projectIdentifier}/images?locale=${locale}`, - defaultHeaders + defaultHeaders, ); }); @@ -165,7 +165,7 @@ describe("Testing project API calls", () => { await loadAssets(projectIdentifier, null, accessToken); expect(axios.get).toHaveBeenCalledWith( `${host}/api/projects/${projectIdentifier}/images`, - authHeaders + authHeaders, ); }); @@ -173,7 +173,7 @@ describe("Testing project API calls", () => { const projectIdentifier = "my-amazing-project"; const image = new File(["(⌐□_□)"], "image1.png", { type: "image/png" }); axios.post.mockImplementationOnce(() => - Promise.resolve({ status: 200, url: "google.drive.com/image1.png" }) + Promise.resolve({ status: 200, url: "google.drive.com/image1.png" }), ); var formData = new FormData(); @@ -183,7 +183,7 @@ describe("Testing project API calls", () => { expect(axios.post).toHaveBeenCalledWith( `${host}/api/projects/${projectIdentifier}/images`, formData, - { ...authHeaders, "Content-Type": "multipart/form-data" } + { ...authHeaders, "Content-Type": "multipart/form-data" }, ); }); @@ -228,7 +228,7 @@ describe("Testing project errors API calls", () => { { error: error.errorMessage, }, - undefined + undefined, ); }); @@ -246,7 +246,7 @@ describe("Testing project errors API calls", () => { error: error.errorMessage, error_type: error?.errorType, }, - undefined + undefined, ); }); @@ -264,7 +264,7 @@ describe("Testing project errors API calls", () => { error: error.errorMessage, error_type: error?.errorType, }, - undefined + undefined, ); }); }); diff --git a/src/utils/sentry.js b/src/utils/sentry.js index 04c51570c..e9f23505c 100644 --- a/src/utils/sentry.js +++ b/src/utils/sentry.js @@ -21,7 +21,7 @@ Sentry.init({ createRoutesFromChildren, matchRoutes, ), - tracePropagationTargets: [process.env.REACT_APP_API_ENDPOINT, /\//], + tracePropagationTargets: [/\//], }), ], environment: process.env.REACT_APP_SENTRY_ENV, diff --git a/src/utils/userManager.js b/src/utils/userManager.js index 4fb896cc4..210a56764 100644 --- a/src/utils/userManager.js +++ b/src/utils/userManager.js @@ -28,7 +28,7 @@ const UserManager = ({ reactAppAuthenticationUrl }) => { const mgr = createUserManager( userManagerConfig({ reactAppAuthenticationUrl, - }) + }), ); mgr.events.addAccessTokenExpired(() => { diff --git a/src/web-component.html b/src/web-component.html index a607aa1be..8d8b2c72b 100644 --- a/src/web-component.html +++ b/src/web-component.html @@ -43,6 +43,7 @@ // sidebar webComp.setAttribute("with_projectbar", "true"); webComp.setAttribute("with_sidebar", "true"); + webComp.setAttribute("react_app_api_endpoint", "https://test-editor-api.raspberrypi.org"); webComp.setAttribute( "sidebar_options", JSON.stringify([ diff --git a/src/web-component.js b/src/web-component.js index a77fbaecb..9a8006752 100644 --- a/src/web-component.js +++ b/src/web-component.js @@ -173,7 +173,7 @@ class WebComponent extends HTMLElement { - + , ); } }