diff --git a/.env.example b/.env.example index aff82280b..74edcb9bf 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,2 @@ -REACT_APP_PINATA_API_TOKEN= \ No newline at end of file +REACT_APP_PINATA_API_TOKEN= +REACT_APP_SENTRY_DSN= \ No newline at end of file diff --git a/config-overrides.js b/config-overrides.js index 950cdedfb..bb4b71155 100644 --- a/config-overrides.js +++ b/config-overrides.js @@ -10,6 +10,8 @@ const { } = require('customize-cra') const webpack = require('webpack') +const SentryWebpackPlugin = require('@sentry/webpack-plugin') + module.exports = override( useBabelRc(), addWebpackAlias({ @@ -27,6 +29,19 @@ module.exports = override( Buffer: ['buffer', 'Buffer'], }) ), + addWebpackPlugin( + new SentryWebpackPlugin({ + authToken: process.env.SENTRY_AUTH_TOKEN, + org: process.env.SENTRY_ORG, + project: process.env.SENTRY_PROJECT, + include: './build', + debug: false, + // ignore: ['node_modules', 'webpack.config.js'], + configFile: path.resolve(__dirname, '.sentryclirc'), + validate: true, + release: process.env.VERCEL_GIT_COMMIT_SHA, + }) + ), addWebpackPlugin( new webpack.ProvidePlugin({ process: 'process/browser', diff --git a/package.json b/package.json index a2698bbf0..3511e27e2 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,8 @@ "@juggle/resize-observer": "^3.2.0", "@nivo/core": "^0.73.0", "@nivo/line": "^0.73.0", + "@sentry/react": "^6.16.1", + "@sentry/tracing": "^6.16.1", "assert": "^2.0.0", "bignumber.js": "^9.0.0", "buffer": "^6.0.3", @@ -68,6 +70,7 @@ "@babel/plugin-proposal-class-properties": "^7.16.5", "@babel/preset-env": "^7.16.5", "@babel/preset-react": "^7.16.5", + "@sentry/webpack-plugin": "^1.18.3", "@trivago/prettier-plugin-sort-imports": "^3.1.1", "@types/node": "^16.11.12", "@types/react": "^17.0.37", diff --git a/src/App.tsx b/src/App.tsx index 66da37b04..cd6f71cf1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,17 +1,21 @@ import React from 'react' import { HashRouter } from 'react-router-dom' + import { Main } from '@1hive/1hive-ui' -import GlobalErrorHandler from './GlobalErrorHandler' import MainView from '@components/MainView' -import Routes from './routes/Routes' import WelcomeLoader from '@components/Welcome/WelcomeLoader' +import GlobalErrorHandler from './GlobalErrorHandler' import { GardensProvider } from './providers/Gardens' import { ProfileProvider } from './providers/Profile' import { UserProvider } from './providers/User' import { WalletProvider } from './providers/Wallet' +import Routes from './routes/Routes' +import initializeSentry, { logWithSentry } from './sentry' +initializeSentry() +logWithSentry('Init App.tsx') function App() { return ( diff --git a/src/components/Garden/Preferences/EVMExecutor.js b/src/components/Garden/Preferences/EVMExecutor.js index e579b7d4f..e9e66870c 100644 --- a/src/components/Garden/Preferences/EVMExecutor.js +++ b/src/components/Garden/Preferences/EVMExecutor.js @@ -1,6 +1,8 @@ /* eslint-disable no-unexpected-multiline */ import React, { useCallback, useMemo, useState } from 'react' + import { utils } from 'ethers' + import { Box, Button, @@ -10,16 +12,21 @@ import { Info, TextInput, } from '@1hive/1hive-ui' + import MultiModal from '@components/MultiModal/MultiModal' + import { useConnectedGarden } from '@providers/ConnectedGarden' + import { SHORTENED_APPS_NAMES } from '@utils/app-utils' import { getAppByName } from '@utils/data-utils' + import actions from '@/actions/garden-action-types' import { TERMINAL_EXECUTOR_MESSAGE } from '@/constants' import env from '@/environment' import { useGardenState } from '@/providers/GardenState' import { useWallet } from '@/providers/Wallet' import radspec from '@/radspec' + import CreateDecisionScreens from '../ModalFlows/CreateDecisionScreens/CreateDecisionScreens' const INTERACTION_TYPES = ['Internal', 'External', 'Terminal'] @@ -66,7 +73,7 @@ function EVMExecutor({ evmcrispr }) { return evmcrispr.apps() }, [evmcrispr]) - const shortenedAppsNames = installedApps.map(appName => { + const shortenedAppsNames = installedApps.map((appName) => { const dotIndex = appName.indexOf('.') return ( SHORTENED_APPS_NAMES.get( @@ -87,7 +94,7 @@ function EVMExecutor({ evmcrispr }) { appFunctions = evmcrispr.appMethods(appName) } if (interactionType === EXTERNAL_INDEX && formattedAbi) { - appFunctions = formattedAbi.map(item => { + appFunctions = formattedAbi.map((item) => { if (item.type === 'function' && item.stateMutability !== 'view') { return item.name } @@ -121,7 +128,7 @@ function EVMExecutor({ evmcrispr }) { }) } if (interactionType === EXTERNAL_INDEX && formattedAbi) { - return formattedAbi[selectedFunction].inputs.map(parameter => { + return formattedAbi[selectedFunction].inputs.map((parameter) => { return [parameter.name, parameter.type] }) } @@ -155,7 +162,7 @@ function EVMExecutor({ evmcrispr }) { const handleOnChangeParameters = useCallback((index, event) => { const newValue = event.target.value - setParameters(prevState => { + setParameters((prevState) => { const newArray = [...prevState] newArray[index] = newValue return newArray @@ -224,12 +231,12 @@ function EVMExecutor({ evmcrispr }) { code, ]) - const handleOnContractAddressChange = useCallback(event => { + const handleOnContractAddressChange = useCallback((event) => { const value = event.target.value setExternalContractAddress(value) }, []) - const handleOnAbiChange = useCallback(event => { + const handleOnAbiChange = useCallback((event) => { const value = event.target.value setAbi(value) let iface @@ -238,7 +245,7 @@ function EVMExecutor({ evmcrispr }) { iface = new utils.Interface(value) formattedAbi = iface.format(utils.FormatTypes.json) setFormattedAbi( - JSON.parse(formattedAbi).filter(item => { + JSON.parse(formattedAbi).filter((item) => { if (item.type === 'function' && item.stateMutability !== 'view') { return item.name } @@ -257,7 +264,7 @@ function EVMExecutor({ evmcrispr }) { setCreateDecisionModalVisible(false) }, []) - const handleOnSetCode = useCallback(event => { + const handleOnSetCode = useCallback((event) => { const value = event.target.value setCode(value) }, []) @@ -337,7 +344,7 @@ function EVMExecutor({ evmcrispr }) { return ( handleOnChangeParameters(index, event)} + onChange={(event) => handleOnChangeParameters(index, event)} placeholder={`${parameter[0].toString()} : ${parameter[1].toString()}`} wide css={` diff --git a/src/components/Home.tsx b/src/components/Home.tsx index 59c44b48f..371eb6d0d 100644 --- a/src/components/Home.tsx +++ b/src/components/Home.tsx @@ -1,21 +1,28 @@ import React, { useCallback, useState } from 'react' + import styled from 'styled-components' + import { GU, useToast } from '@1hive/1hive-ui' + import { useGardens } from '@providers/Gardens' +import { useWallet } from '@providers/Wallet' + import { useNodeHeight } from '@hooks/useNodeHeight' + +import { logWithSentry } from '@/sentry' + import GardensFilters from './GardensFilters' import GardensList from './GardensList' import LandingBanner from './LandingBanner' -import { useWallet } from '@providers/Wallet' -import MultiModal from './MultiModal/MultiModal' -import ConnectWalletScreens from './MultiModal/ConnectWallet/ConnectWalletScreens' import Loader from './Loader' +import ConnectWalletScreens from './MultiModal/ConnectWallet/ConnectWalletScreens' +import MultiModal from './MultiModal/MultiModal' import Onboarding from './Onboarding' const DynamicSection = styled.div<{ marginTop: any }>` - margin-top: ${props => props.marginTop}px; + margin-top: ${(props) => props.marginTop}px; padding: 0 ${2 * GU}px; ` @@ -38,10 +45,12 @@ function Home() { return } setOnboardingVisible(true) + logWithSentry('Opened Onboarding') }, [account]) const handleOnboardingClose = useCallback(() => { setOnboardingVisible(false) + logWithSentry('Closed Onboarding') toast('Saved!') }, [toast]) diff --git a/src/components/SingleDatePicker/DatePicker.js b/src/components/SingleDatePicker/DatePicker.js index d1429fa5d..7c27b832f 100644 --- a/src/components/SingleDatePicker/DatePicker.js +++ b/src/components/SingleDatePicker/DatePicker.js @@ -1,8 +1,12 @@ /* eslint-disable no-unexpected-multiline */ import React, { useState } from 'react' + import PropTypes from 'prop-types' -import { eachDayOfInterval, GU } from '@1hive/1hive-ui' + +import { GU, eachDayOfInterval } from '@1hive/1hive-ui' + import { dayjs } from '@utils/date-utils' + import MonthDay from './MonthDay' import { Selector } from './components' @@ -23,7 +27,7 @@ function DatePicker({ const setDate = ({ year, add }) => - event => { + (event) => { setSelectedDate( dayjs(selectedDate) .startOf('month') @@ -36,7 +40,7 @@ function DatePicker({ const selectedDayjs = dayjs(selectedDate || today) - const isSelected = day => { + const isSelected = (day) => { if (initialDate) { return day.isSame(initialDate, 'day') } @@ -82,7 +86,7 @@ function DatePicker({ eachDayOfInterval({ start: selectedDayjs.startOf('week'), end: selectedDayjs.endOf('week'), - }).map(day => { + }).map((day) => { const dayJs = dayjs(day) return ( @@ -94,7 +98,7 @@ function DatePicker({ {eachDayOfInterval({ start: selectedDayjs.startOf('month').startOf('week'), end: selectedDayjs.endOf('month').endOf('week'), - }).map(day => { + }).map((day) => { const dayJs = dayjs(day) return (