diff --git a/back/src/adapters/primary/helpers/handleHttpJsonResponseError.ts b/back/src/adapters/primary/helpers/handleHttpJsonResponseError.ts index b681cb0fde..9db73bd6af 100644 --- a/back/src/adapters/primary/helpers/handleHttpJsonResponseError.ts +++ b/back/src/adapters/primary/helpers/handleHttpJsonResponseError.ts @@ -11,10 +11,6 @@ export const handleHttpJsonResponseError = ( if (error instanceof HttpError) { res.status(error.httpCode); - if (error.httpCode === 409) { - return unhandledError(error, req, res); - } - return res.json({ errors: toValidJSONObjectOrString(error) }); } diff --git a/front/.nvmrc b/front/.nvmrc deleted file mode 100644 index 19c7bdba7b..0000000000 --- a/front/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -16 \ No newline at end of file diff --git a/front/package.json b/front/package.json index 0a95f1065e..e34f992d66 100644 --- a/front/package.json +++ b/front/package.json @@ -33,6 +33,7 @@ "@mui/icons-material": "^5.8.0", "@mui/material": "^5.11.8", "@reduxjs/toolkit": "^1.8.1", + "@sentry/browser": "^7.56.0", "@types/jest": "^29.5.2", "@types/node": "^18.13.0", "@types/papaparse": "^5.3.7", diff --git a/front/src/app/main.tsx b/front/src/app/main.tsx index 098ffbb1ec..46b4b4df69 100644 --- a/front/src/app/main.tsx +++ b/front/src/app/main.tsx @@ -2,11 +2,22 @@ import React from "react"; import { createRoot } from "react-dom/client"; import { Provider } from "react-redux"; import { startReactDsfr } from "@codegouvfr/react-dsfr/spa"; +import * as Sentry from "@sentry/browser"; import { App } from "src/app/App"; import { store } from "src/config/dependencies"; +import { ENV } from "src/config/environmentVariables"; import { MetaContent } from "./components/layout/MetaContent"; import { RouteProvider } from "./routes/routes"; +Sentry.init({ + dsn: "https://c2909f1d7f384d17bde3e75e250f2828@sentry.gip-inclusion.cloud-ed.fr/2", + integrations: [new Sentry.BrowserTracing(), new Sentry.Replay()], + environment: ENV.envType, + tracesSampleRate: 0.01, + replaysOnErrorSampleRate: 1.0, + replaysSessionSampleRate: 0, +}); + startReactDsfr({ defaultColorScheme: "light" }); const rootContainer = document.getElementById("root"); diff --git a/front/src/core-logic/storeConfig/catchEpicError.ts b/front/src/core-logic/storeConfig/catchEpicError.ts index 2f784bf936..66b35cbcf3 100644 --- a/front/src/core-logic/storeConfig/catchEpicError.ts +++ b/front/src/core-logic/storeConfig/catchEpicError.ts @@ -1,3 +1,4 @@ +import * as Sentry from "@sentry/browser"; import { catchError, merge, Observable, of } from "rxjs"; export const catchEpicError = @@ -8,4 +9,9 @@ export const catchEpicError = cb: (error: Error) => OutputAction, ) => (inputObs: Observable): Observable => - inputObs.pipe(catchError((error, caught) => merge(of(cb(error)), caught))); + inputObs.pipe( + catchError((error, caught) => { + Sentry.captureException(error); + return merge(of(cb(error)), caught); + }), + ); diff --git a/front/src/core-logic/storeConfig/store.ts b/front/src/core-logic/storeConfig/store.ts index 7efd498096..58c530c060 100644 --- a/front/src/core-logic/storeConfig/store.ts +++ b/front/src/core-logic/storeConfig/store.ts @@ -1,4 +1,5 @@ import { combineReducers, configureStore } from "@reduxjs/toolkit"; +import * as Sentry from "@sentry/browser"; import { combineEpics, createEpicMiddleware, Epic } from "redux-observable"; import { catchError } from "rxjs"; import type { Dependencies } from "src/config/dependencies"; @@ -88,6 +89,7 @@ const rootEpic: Epic = (action$, store$, dependencies) => catchError((error, source) => { //eslint-disable-next-line no-console console.error("combineEpic", error); + Sentry.captureException(error); return source; }), ); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5de83e40e3..1320a7f6ea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -277,6 +277,9 @@ importers: '@reduxjs/toolkit': specifier: ^1.8.1 version: 1.8.1(react-redux@7.2.8)(react@18.2.0) + '@sentry/browser': + specifier: ^7.56.0 + version: 7.56.0 '@types/jest': specifier: ^29.5.2 version: 29.5.2 @@ -5199,6 +5202,59 @@ packages: picomatch: 2.3.1 dev: true + /@sentry-internal/tracing@7.56.0: + resolution: {integrity: sha512-OKI4Pz/O13gng8hT9rNc+gRV3+P7nnk1HnHlV8fgaQydS6DsRxoDL1sHa42tZGbh7K9jqNAP3TC6VjBOsr2tXA==} + engines: {node: '>=8'} + dependencies: + '@sentry/core': 7.56.0 + '@sentry/types': 7.56.0 + '@sentry/utils': 7.56.0 + tslib: 1.14.1 + dev: true + + /@sentry/browser@7.56.0: + resolution: {integrity: sha512-qpyyw+NM/psbNAYMlTCCdWwxHHcogppEQ+Q40jGE4sKP2VRIjjyteJkUcaEMoGpbJXx9puzTWbpzqlQ8r15Now==} + engines: {node: '>=8'} + dependencies: + '@sentry-internal/tracing': 7.56.0 + '@sentry/core': 7.56.0 + '@sentry/replay': 7.56.0 + '@sentry/types': 7.56.0 + '@sentry/utils': 7.56.0 + tslib: 1.14.1 + dev: true + + /@sentry/core@7.56.0: + resolution: {integrity: sha512-Nuyyfh09Yz27kPo74fXHlrdmZeK6zrlJVtxQ6LkwuoaTBcNcesNXVaOtr6gjvUGUmsfriVPP3Jero5LXufV7GQ==} + engines: {node: '>=8'} + dependencies: + '@sentry/types': 7.56.0 + '@sentry/utils': 7.56.0 + tslib: 1.14.1 + dev: true + + /@sentry/replay@7.56.0: + resolution: {integrity: sha512-bvjiJK1+SM/paLapuL+nEJ8CIF1bJqi0nnFyxUIi2L5L6yb2uMwfyT3IQ+kz0cXJsLdb3HN4WMphVjyiU9pFdg==} + engines: {node: '>=12'} + dependencies: + '@sentry/core': 7.56.0 + '@sentry/types': 7.56.0 + '@sentry/utils': 7.56.0 + dev: true + + /@sentry/types@7.56.0: + resolution: {integrity: sha512-5WjhVOQm75ItOytOx2jTx+5yw8/qJ316+g1Di8dS9+kgIi1zniqdMcX00C2yYe3FMUgFB49PegCUYulm9Evapw==} + engines: {node: '>=8'} + dev: true + + /@sentry/utils@7.56.0: + resolution: {integrity: sha512-wgeX7bufxc//TjjSIE+gCMm8hVId7Jzvc+f441bYrWnNZBuzPIDW2BummCcPrKzSYe5GeYZDTZGV8YZGMLGBjw==} + engines: {node: '>=8'} + dependencies: + '@sentry/types': 7.56.0 + tslib: 1.14.1 + dev: true + /@sidvind/better-ajv-errors@2.1.0(ajv@8.12.0): resolution: {integrity: sha512-JuIb009FhHuL9priFBho2kv7QmZOydj0LgYvj+h1t0mMCmhM/YmQNRlJR5wVtBZya6wrVFK5Hi5TIbv5BKEx7w==} engines: {node: '>= 14.0.0'}