Commit 2fea665e authored by tom's avatar tom

Merge branch 'main' of github.com:blockscout/frontend

parents fb7f6cfc 1054851c
...@@ -14,11 +14,14 @@ export default function fetchFactory( ...@@ -14,11 +14,14 @@ export default function fetchFactory(
// FIXME migrate to RequestInfo later if needed // FIXME migrate to RequestInfo later if needed
return function fetch(url: string, init?: RequestInit): Promise<Response> { return function fetch(url: string, init?: RequestInit): Promise<Response> {
const csrfToken = _req.headers['x-csrf-token']; const csrfToken = _req.headers['x-csrf-token'];
const authToken = _req.headers['Authorization'];
const headers = { const headers = {
accept: _req.headers['accept'] || 'application/json', accept: _req.headers['accept'] || 'application/json',
'content-type': _req.headers['content-type'] || 'application/json', 'content-type': _req.headers['content-type'] || 'application/json',
cookie: `${ cookies.NAMES.API_TOKEN }=${ _req.cookies[cookies.NAMES.API_TOKEN] }`, cookie: `${ cookies.NAMES.API_TOKEN }=${ _req.cookies[cookies.NAMES.API_TOKEN] }`,
...(csrfToken ? { 'x-csrf-token': String(csrfToken) } : {}), ...(csrfToken ? { 'x-csrf-token': String(csrfToken) } : {}),
...(authToken ? { Authorization: String(authToken) } : {}),
}; };
httpLogger.logger.info({ httpLogger.logger.info({
......
...@@ -65,6 +65,7 @@ export interface ApiResource { ...@@ -65,6 +65,7 @@ export interface ApiResource {
endpoint?: string; endpoint?: string;
basePath?: string; basePath?: string;
pathParams?: Array<string>; pathParams?: Array<string>;
needAuth?: boolean; // for external APIs which require authentication
} }
export const RESOURCES = { export const RESOURCES = {
...@@ -109,6 +110,7 @@ export const RESOURCES = { ...@@ -109,6 +110,7 @@ export const RESOURCES = {
pathParams: [ 'chainId' as const, 'type' as const ], pathParams: [ 'chainId' as const, 'type' as const ],
endpoint: appConfig.contractInfoApi.endpoint, endpoint: appConfig.contractInfoApi.endpoint,
basePath: appConfig.contractInfoApi.basePath, basePath: appConfig.contractInfoApi.basePath,
needAuth: true,
}, },
verified_addresses: { verified_addresses: {
...@@ -116,6 +118,7 @@ export const RESOURCES = { ...@@ -116,6 +118,7 @@ export const RESOURCES = {
pathParams: [ 'chainId' as const ], pathParams: [ 'chainId' as const ],
endpoint: appConfig.contractInfoApi.endpoint, endpoint: appConfig.contractInfoApi.endpoint,
basePath: appConfig.contractInfoApi.basePath, basePath: appConfig.contractInfoApi.basePath,
needAuth: true,
}, },
token_info_applications_config: { token_info_applications_config: {
...@@ -123,6 +126,7 @@ export const RESOURCES = { ...@@ -123,6 +126,7 @@ export const RESOURCES = {
pathParams: [ 'chainId' as const ], pathParams: [ 'chainId' as const ],
endpoint: appConfig.adminServiceApi.endpoint, endpoint: appConfig.adminServiceApi.endpoint,
basePath: appConfig.adminServiceApi.basePath, basePath: appConfig.adminServiceApi.basePath,
needAuth: true,
}, },
token_info_applications: { token_info_applications: {
...@@ -130,6 +134,7 @@ export const RESOURCES = { ...@@ -130,6 +134,7 @@ export const RESOURCES = {
pathParams: [ 'chainId' as const, 'id' as const ], pathParams: [ 'chainId' as const, 'id' as const ],
endpoint: appConfig.adminServiceApi.endpoint, endpoint: appConfig.adminServiceApi.endpoint,
basePath: appConfig.adminServiceApi.basePath, basePath: appConfig.adminServiceApi.basePath,
needAuth: true,
}, },
// STATS // STATS
......
import React from 'react'; import React from 'react';
import isNeedProxy from 'lib/api/isNeedProxy'; import isNeedProxy from 'lib/api/isNeedProxy';
import * as cookies from 'lib/cookies';
import type { Params as FetchParams } from 'lib/hooks/useFetch'; import type { Params as FetchParams } from 'lib/hooks/useFetch';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
...@@ -27,9 +28,10 @@ export default function useApiFetch() { ...@@ -27,9 +28,10 @@ export default function useApiFetch() {
url, url,
{ {
credentials: 'include', credentials: 'include',
...(resource.endpoint && isNeedProxy() ? { ...(resource.endpoint ? {
headers: { headers: {
'x-endpoint': resource.endpoint, ...(isNeedProxy() ? { 'x-endpoint': resource.endpoint } : {}),
...(resource.needAuth ? { Authorization: cookies.get(cookies.NAMES.API_TOKEN) } : {}),
}, },
} : {}), } : {}),
...fetchParams, ...fetchParams,
......
...@@ -167,3 +167,28 @@ l2Test('l2', async({ mount, page }) => { ...@@ -167,3 +167,28 @@ l2Test('l2', async({ mount, page }) => {
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
const mainnetTest = test.extend({
context: contextWithEnvs([
{ name: 'NEXT_PUBLIC_IS_TESTNET', value: 'false' },
// eslint-disable-next-line @typescript-eslint/no-explicit-any
]) as any,
});
mainnetTest('without testnet warning', async({ mount, page }) => {
await page.route(API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify(txMock.l2tx),
}));
const component = await mount(
<TestApp>
<TxDetails/>
</TestApp>,
{ hooksConfig },
);
await insertAdPlaceholder(page);
await expect(component).toHaveScreenshot();
});
...@@ -6,12 +6,12 @@ import { ...@@ -6,12 +6,12 @@ import {
Icon as ChakraIcon, Icon as ChakraIcon,
Link, Link,
Spinner, Spinner,
Tag,
Flex, Flex,
Tooltip, Tooltip,
chakra, chakra,
useColorModeValue, useColorModeValue,
Skeleton, Skeleton,
Alert,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
...@@ -30,6 +30,7 @@ import Address from 'ui/shared/address/Address'; ...@@ -30,6 +30,7 @@ import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon'; import Icon from 'ui/shared/chakra/Icon';
import Tag from 'ui/shared/chakra/Tag';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import CurrencyValue from 'ui/shared/CurrencyValue'; import CurrencyValue from 'ui/shared/CurrencyValue';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
...@@ -120,6 +121,8 @@ const TxDetails = () => { ...@@ -120,6 +121,8 @@ const TxDetails = () => {
); );
return ( return (
<>
{ appConfig.network.isTestnet && <Alert status="warning" mb={ 6 }>This is a { appConfig.network.name } testnet transaction only</Alert> }
<Grid columnGap={ 8 } rowGap={{ base: 3, lg: 3 }} templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }}> <Grid columnGap={ 8 } rowGap={{ base: 3, lg: 3 }} templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }}>
{ socketStatus && ( { socketStatus && (
<GridItem colSpan={{ base: undefined, lg: 2 }} mb={ 2 }> <GridItem colSpan={{ base: undefined, lg: 2 }} mb={ 2 }>
...@@ -141,11 +144,16 @@ const TxDetails = () => { ...@@ -141,11 +144,16 @@ const TxDetails = () => {
{ /* <PrevNext ml={ 7 }/> */ } { /* <PrevNext ml={ 7 }/> */ }
</DetailsInfoItem> </DetailsInfoItem>
<DetailsInfoItem <DetailsInfoItem
title="Status" title="Status and method"
hint="Current transaction state: Success, Failed (Error), or Pending (In Process)" hint="Current transaction state: Success, Failed (Error), or Pending (In Process)"
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
<TxStatus status={ data.status } errorText={ data.status === 'error' ? data.result : undefined } isLoading={ isPlaceholderData }/> <TxStatus status={ data.status } errorText={ data.status === 'error' ? data.result : undefined } isLoading={ isPlaceholderData }/>
{ data.method && (
<Tag colorScheme={ data.method === 'Multicall' ? 'teal' : 'gray' } isLoading={ isPlaceholderData } isTruncated ml={ 3 }>
{ data.method }
</Tag>
) }
</DetailsInfoItem> </DetailsInfoItem>
{ data.revert_reason && ( { data.revert_reason && (
<DetailsInfoItem <DetailsInfoItem
...@@ -269,7 +277,12 @@ const TxDetails = () => { ...@@ -269,7 +277,12 @@ const TxDetails = () => {
hint="Value sent in the native token (and USD) if applicable" hint="Value sent in the native token (and USD) if applicable"
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
<CurrencyValue value={ data.value } currency={ appConfig.network.currency.symbol } exchangeRate={ data.exchange_rate } isLoading={ isPlaceholderData }/> <CurrencyValue
value={ data.value }
currency={ appConfig.network.currency.symbol }
exchangeRate={ data.exchange_rate }
isLoading={ isPlaceholderData }
/>
</DetailsInfoItem> </DetailsInfoItem>
<DetailsInfoItem <DetailsInfoItem
title="Transaction fee" title="Transaction fee"
...@@ -464,6 +477,7 @@ const TxDetails = () => { ...@@ -464,6 +477,7 @@ const TxDetails = () => {
</> </>
) } ) }
</Grid> </Grid>
</>
); );
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment