Commit 51bc8751 authored by tom goriunov's avatar tom goriunov Committed by GitHub

Metasuites placeholders (#1637)

* placeholders for address and txs

* placeholder for explorer link

* move phalcon link

* change api endpoint for demo

* Fixing upstream header too large

* ready flags and navigation events

* add ENV

---------
Co-authored-by: default avatarNick Zenchik <n.zenchik@gmail.com>
parent d53884c9
...@@ -11,6 +11,7 @@ export { default as googleAnalytics } from './googleAnalytics'; ...@@ -11,6 +11,7 @@ export { default as googleAnalytics } from './googleAnalytics';
export { default as graphqlApiDocs } from './graphqlApiDocs'; export { default as graphqlApiDocs } from './graphqlApiDocs';
export { default as growthBook } from './growthBook'; export { default as growthBook } from './growthBook';
export { default as marketplace } from './marketplace'; export { default as marketplace } from './marketplace';
export { default as metasuites } from './metasuites';
export { default as mixpanel } from './mixpanel'; export { default as mixpanel } from './mixpanel';
export { default as nameService } from './nameService'; export { default as nameService } from './nameService';
export { default as restApiDocs } from './restApiDocs'; export { default as restApiDocs } from './restApiDocs';
......
import type { Feature } from './types';
import { getEnvValue } from '../utils';
const title = 'MetaSuites extension';
const config: Feature<{ isEnabled: true }> = (() => {
if (getEnvValue('NEXT_PUBLIC_METASUITES_ENABLED') === 'true') {
return Object.freeze({
title,
isEnabled: true,
});
}
return Object.freeze({
title,
isEnabled: false,
});
})();
export default config;
...@@ -503,6 +503,7 @@ const schema = yup ...@@ -503,6 +503,7 @@ const schema = yup
NEXT_PUBLIC_SAFE_TX_SERVICE_URL: yup.string().test(urlTest), NEXT_PUBLIC_SAFE_TX_SERVICE_URL: yup.string().test(urlTest),
NEXT_PUBLIC_IS_SUAVE_CHAIN: yup.boolean(), NEXT_PUBLIC_IS_SUAVE_CHAIN: yup.boolean(),
NEXT_PUBLIC_HAS_USER_OPS: yup.boolean(), NEXT_PUBLIC_HAS_USER_OPS: yup.boolean(),
NEXT_PUBLIC_METASUITES_ENABLED: yup.boolean(),
NEXT_PUBLIC_SWAP_BUTTON_URL: yup.string(), NEXT_PUBLIC_SWAP_BUTTON_URL: yup.string(),
NEXT_PUBLIC_VALIDATORS_CHAIN_TYPE: yup.string<ValidatorsChainType>().oneOf(VALIDATORS_CHAIN_TYPE), NEXT_PUBLIC_VALIDATORS_CHAIN_TYPE: yup.string<ValidatorsChainType>().oneOf(VALIDATORS_CHAIN_TYPE),
NEXT_PUBLIC_GAS_TRACKER_ENABLED: yup.boolean(), NEXT_PUBLIC_GAS_TRACKER_ENABLED: yup.boolean(),
......
...@@ -24,6 +24,7 @@ NEXT_PUBLIC_GAS_TRACKER_ENABLED=true ...@@ -24,6 +24,7 @@ NEXT_PUBLIC_GAS_TRACKER_ENABLED=true
NEXT_PUBLIC_GAS_TRACKER_UNITS=['gwei'] NEXT_PUBLIC_GAS_TRACKER_UNITS=['gwei']
NEXT_PUBLIC_IS_TESTNET=true NEXT_PUBLIC_IS_TESTNET=true
NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE='<a href="#">Hello</a>' NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE='<a href="#">Hello</a>'
NEXT_PUBLIC_METASUITES_ENABLED=true
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
......
...@@ -30,10 +30,12 @@ frontend: ...@@ -30,10 +30,12 @@ frontend:
kubernetes.io/ingress.class: internal-and-public kubernetes.io/ingress.class: internal-and-public
nginx.ingress.kubernetes.io/proxy-body-size: 500m nginx.ingress.kubernetes.io/proxy-body-size: 500m
nginx.ingress.kubernetes.io/client-max-body-size: "500M" nginx.ingress.kubernetes.io/client-max-body-size: "500M"
nginx.ingress.kubernetes.io/proxy-buffering: "off" nginx.ingress.kubernetes.io/proxy-buffering: "on"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "15m" nginx.ingress.kubernetes.io/proxy-connect-timeout: "15m"
nginx.ingress.kubernetes.io/proxy-send-timeout: "15m" nginx.ingress.kubernetes.io/proxy-send-timeout: "15m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "15m" nginx.ingress.kubernetes.io/proxy-read-timeout: "15m"
nginx.ingress.kubernetes.io/proxy-buffer-size: "128k"
nginx.ingress.kubernetes.io/proxy-buffers-number: "8"
cert-manager.io/cluster-issuer: "zerossl-prod" cert-manager.io/cluster-issuer: "zerossl-prod"
hostname: review-l2-{{ requiredEnv "GITHUB_REF_NAME_SLUG" }}.k8s-dev.blockscout.com hostname: review-l2-{{ requiredEnv "GITHUB_REF_NAME_SLUG" }}.k8s-dev.blockscout.com
......
...@@ -30,10 +30,12 @@ frontend: ...@@ -30,10 +30,12 @@ frontend:
kubernetes.io/ingress.class: internal-and-public kubernetes.io/ingress.class: internal-and-public
nginx.ingress.kubernetes.io/proxy-body-size: 500m nginx.ingress.kubernetes.io/proxy-body-size: 500m
nginx.ingress.kubernetes.io/client-max-body-size: "500M" nginx.ingress.kubernetes.io/client-max-body-size: "500M"
nginx.ingress.kubernetes.io/proxy-buffering: "off" nginx.ingress.kubernetes.io/proxy-buffering: "on"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "15m" nginx.ingress.kubernetes.io/proxy-connect-timeout: "15m"
nginx.ingress.kubernetes.io/proxy-send-timeout: "15m" nginx.ingress.kubernetes.io/proxy-send-timeout: "15m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "15m" nginx.ingress.kubernetes.io/proxy-read-timeout: "15m"
nginx.ingress.kubernetes.io/proxy-buffer-size: "128k"
nginx.ingress.kubernetes.io/proxy-buffers-number: "8"
cert-manager.io/cluster-issuer: "zerossl-prod" cert-manager.io/cluster-issuer: "zerossl-prod"
hostname: review-{{ requiredEnv "GITHUB_REF_NAME_SLUG" }}.k8s-dev.blockscout.com hostname: review-{{ requiredEnv "GITHUB_REF_NAME_SLUG" }}.k8s-dev.blockscout.com
...@@ -89,4 +91,3 @@ frontend: ...@@ -89,4 +91,3 @@ frontend:
FAVICON_GENERATOR_API_KEY: ref+vault://deployment-values/blockscout/common?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY FAVICON_GENERATOR_API_KEY: ref+vault://deployment-values/blockscout/common?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY
NEXT_PUBLIC_GROWTH_BOOK_CLIENT_KEY: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GROWTH_BOOK_CLIENT_KEY NEXT_PUBLIC_GROWTH_BOOK_CLIENT_KEY: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GROWTH_BOOK_CLIENT_KEY
NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN: ref+vault://deployment-values/blockscout/common?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN: ref+vault://deployment-values/blockscout/common?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN
...@@ -52,6 +52,7 @@ Please be aware that all environment variables prefixed with `NEXT_PUBLIC_` will ...@@ -52,6 +52,7 @@ Please be aware that all environment variables prefixed with `NEXT_PUBLIC_` will
- [Bridged tokens](ENVS.md#bridged-tokens) - [Bridged tokens](ENVS.md#bridged-tokens)
- [Safe{Core} address tags](ENVS.md#safecore-address-tags) - [Safe{Core} address tags](ENVS.md#safecore-address-tags)
- [SUAVE chain](ENVS.md#suave-chain) - [SUAVE chain](ENVS.md#suave-chain)
- [MetaSuites extension](ENVS.md#metasuites-extension)
- [Sentry error monitoring](ENVS.md#sentry-error-monitoring) - [Sentry error monitoring](ENVS.md#sentry-error-monitoring)
- [OpenTelemetry](ENVS.md#opentelemetry) - [OpenTelemetry](ENVS.md#opentelemetry)
- [Swap button](ENVS.md#swap-button) - [Swap button](ENVS.md#swap-button)
...@@ -595,6 +596,16 @@ For blockchains that implement SUAVE architecture additional fields will be show ...@@ -595,6 +596,16 @@ For blockchains that implement SUAVE architecture additional fields will be show
&nbsp; &nbsp;
### MetaSuites extension
Enables [MetaSuites browser extension](https://github.com/blocksecteam/metasuites) to integrate with the app views.
| Variable | Type| Description | Compulsoriness | Default value | Example value |
| --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_METASUITES_ENABLED | `boolean` | Set to true to enable integration | Required | - | `true` |
&nbsp;
### Validators list ### Validators list
The feature enables the Validators page which provides detailed information about the validators of the PoS chains. The feature enables the Validators page which provides detailed information about the validators of the PoS chains.
......
import { usePathname } from 'next/navigation';
import { useRouter } from 'next/router';
import React from 'react';
import config from 'configs/app';
import getQueryParamString from 'lib/router/getQueryParamString';
export default function useNotifyOnNavigation() {
const router = useRouter();
const pathname = usePathname();
const tab = getQueryParamString(router.query.tab);
React.useEffect(() => {
if (config.features.metasuites.isEnabled) {
window.postMessage({ source: 'APP_ROUTER', type: 'PATHNAME_CHANGED' }, window.location.origin);
}
}, [ pathname ]);
React.useEffect(() => {
if (config.features.metasuites.isEnabled) {
window.postMessage({ source: 'APP_ROUTER', type: 'TAB_CHANGED' }, window.location.origin);
}
}, [ tab ]);
}
...@@ -15,6 +15,7 @@ import { ChakraProvider } from 'lib/contexts/chakra'; ...@@ -15,6 +15,7 @@ import { ChakraProvider } from 'lib/contexts/chakra';
import { ScrollDirectionProvider } from 'lib/contexts/scrollDirection'; import { ScrollDirectionProvider } from 'lib/contexts/scrollDirection';
import { growthBook } from 'lib/growthbook/init'; import { growthBook } from 'lib/growthbook/init';
import useLoadFeatures from 'lib/growthbook/useLoadFeatures'; import useLoadFeatures from 'lib/growthbook/useLoadFeatures';
import useNotifyOnNavigation from 'lib/hooks/useNotifyOnNavigation';
import { SocketProvider } from 'lib/socket/context'; import { SocketProvider } from 'lib/socket/context';
import theme from 'theme'; import theme from 'theme';
import AppErrorBoundary from 'ui/shared/AppError/AppErrorBoundary'; import AppErrorBoundary from 'ui/shared/AppError/AppErrorBoundary';
...@@ -44,6 +45,7 @@ const ERROR_SCREEN_STYLES: ChakraProps = { ...@@ -44,6 +45,7 @@ const ERROR_SCREEN_STYLES: ChakraProps = {
function MyApp({ Component, pageProps }: AppPropsWithLayout) { function MyApp({ Component, pageProps }: AppPropsWithLayout) {
useLoadFeatures(); useLoadFeatures();
useNotifyOnNavigation();
const queryClient = useQueryClientConfig(); const queryClient = useQueryClientConfig();
......
...@@ -236,6 +236,7 @@ const AddressPageContent = () => { ...@@ -236,6 +236,7 @@ const AddressPageContent = () => {
secondRow={ titleSecondRow } secondRow={ titleSecondRow }
isLoading={ isLoading } isLoading={ isLoading }
/> />
{ config.features.metasuites.isEnabled && <Box display="none" id="meta-suites__address" data-ready={ !isLoading }/> }
<AddressDetails addressQuery={ addressQuery } scrollRef={ tabsScrollRef }/> <AddressDetails addressQuery={ addressQuery } scrollRef={ tabsScrollRef }/>
{ /* should stay before tabs to scroll up with pagination */ } { /* should stay before tabs to scroll up with pagination */ }
<Box ref={ tabsScrollRef }></Box> <Box ref={ tabsScrollRef }></Box>
......
import { GridItem } from '@chakra-ui/react'; import { GridItem, chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
const DetailsInfoItemDivider = () => { interface Props {
className?: string;
id?: string;
}
const DetailsInfoItemDivider = ({ className, id }: Props) => {
return ( return (
<GridItem <GridItem
id={ id }
className={ className }
colSpan={{ base: undefined, lg: 2 }} colSpan={{ base: undefined, lg: 2 }}
mt={{ base: 2, lg: 3 }} mt={{ base: 2, lg: 3 }}
mb={{ base: 0, lg: 3 }} mb={{ base: 0, lg: 3 }}
...@@ -13,4 +20,4 @@ const DetailsInfoItemDivider = () => { ...@@ -13,4 +20,4 @@ const DetailsInfoItemDivider = () => {
); );
}; };
export default DetailsInfoItemDivider; export default chakra(DetailsInfoItemDivider);
import type { ThemingProps } from '@chakra-ui/react'; import type { ThemingProps } from '@chakra-ui/react';
import { Flex, chakra, useDisclosure, Popover, PopoverTrigger, PopoverContent, PopoverBody } from '@chakra-ui/react'; import { Flex, chakra, useDisclosure, Popover, PopoverTrigger, PopoverContent, PopoverBody, Box } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { UserTags } from 'types/api/addressParams'; import type { UserTags } from 'types/api/addressParams';
import config from 'configs/app';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import Tag from 'ui/shared/chakra/Tag'; import Tag from 'ui/shared/chakra/Tag';
...@@ -36,8 +37,12 @@ const EntityTags = ({ className, data, tagsBefore = [], tagsAfter = [], isLoadin ...@@ -36,8 +37,12 @@ const EntityTags = ({ className, data, tagsBefore = [], tagsAfter = [], isLoadin
] ]
.filter(Boolean); .filter(Boolean);
const metaSuitesPlaceholder = config.features.metasuites.isEnabled ?
<Box display="none" id="meta-suites__address-tag" data-ready={ !isLoading }/> :
null;
if (tags.length === 0 && !contentAfter) { if (tags.length === 0 && !contentAfter) {
return null; return metaSuitesPlaceholder;
} }
const content = (() => { const content = (() => {
...@@ -60,6 +65,7 @@ const EntityTags = ({ className, data, tagsBefore = [], tagsAfter = [], isLoadin ...@@ -60,6 +65,7 @@ const EntityTags = ({ className, data, tagsBefore = [], tagsAfter = [], isLoadin
</Tag> </Tag>
)) ))
} }
{ metaSuitesPlaceholder }
<Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy> <Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy>
<PopoverTrigger> <PopoverTrigger>
<Tag isLoading={ isLoading }onClick={ onToggle }>+{ tags.length - 1 }</Tag> <Tag isLoading={ isLoading }onClick={ onToggle }>+{ tags.length - 1 }</Tag>
...@@ -88,7 +94,9 @@ const EntityTags = ({ className, data, tagsBefore = [], tagsAfter = [], isLoadin ...@@ -88,7 +94,9 @@ const EntityTags = ({ className, data, tagsBefore = [], tagsAfter = [], isLoadin
); );
} }
return tags.map((tag) => ( return (
<>
{ tags.map((tag) => (
<Tag <Tag
key={ tag.label } key={ tag.label }
isLoading={ isLoading } isLoading={ isLoading }
...@@ -99,7 +107,10 @@ const EntityTags = ({ className, data, tagsBefore = [], tagsAfter = [], isLoadin ...@@ -99,7 +107,10 @@ const EntityTags = ({ className, data, tagsBefore = [], tagsAfter = [], isLoadin
> >
{ tag.display_name } { tag.display_name }
</Tag> </Tag>
)); )) }
{ metaSuitesPlaceholder }
</>
);
})(); })();
return ( return (
......
...@@ -2,8 +2,8 @@ import { chakra } from '@chakra-ui/react'; ...@@ -2,8 +2,8 @@ import { chakra } from '@chakra-ui/react';
import type { StyleProps } from '@chakra-ui/styled-system'; import type { StyleProps } from '@chakra-ui/styled-system';
import React from 'react'; import React from 'react';
const TextSeparator = (props: StyleProps) => { const TextSeparator = ({ id, ...props }: StyleProps & { id?: string }) => {
return <chakra.span mx={ 3 } { ...props }>|</chakra.span>; return <chakra.span mx={ 3 } id={ id } { ...props }>|</chakra.span>;
}; };
export default React.memo(TextSeparator); export default React.memo(TextSeparator);
...@@ -109,6 +109,15 @@ const TxInfo = ({ data, isLoading, socketStatus }: Props) => { ...@@ -109,6 +109,15 @@ const TxInfo = ({ data, isLoading, socketStatus }: Props) => {
return ( return (
<Grid columnGap={ 8 } rowGap={{ base: 3, lg: 3 }} templateColumns={{ base: 'minmax(0, 1fr)', lg: 'max-content minmax(728px, auto)' }}> <Grid columnGap={ 8 } rowGap={{ base: 3, lg: 3 }} templateColumns={{ base: 'minmax(0, 1fr)', lg: 'max-content minmax(728px, auto)' }}>
{ config.features.metasuites.isEnabled && (
<>
<Box display="none" id="meta-suites__tx-info-label" data-status={ data.status } data-ready={ !isLoading }/>
<Box display="none" id="meta-suites__tx-info-value"/>
<DetailsInfoItemDivider display="none" id="meta-suites__details-info-item-divider"/>
</>
) }
{ socketStatus && ( { socketStatus && (
<GridItem colSpan={{ base: undefined, lg: 2 }} mb={ 2 }> <GridItem colSpan={{ base: undefined, lg: 2 }} mb={ 2 }>
<TxSocketAlert status={ socketStatus }/> <TxSocketAlert status={ socketStatus }/>
...@@ -125,6 +134,13 @@ const TxInfo = ({ data, isLoading, socketStatus }: Props) => { ...@@ -125,6 +134,13 @@ const TxInfo = ({ data, isLoading, socketStatus }: Props) => {
<HashStringShortenDynamic hash={ data.hash }/> <HashStringShortenDynamic hash={ data.hash }/>
</Skeleton> </Skeleton>
<CopyToClipboard text={ data.hash } isLoading={ isLoading }/> <CopyToClipboard text={ data.hash } isLoading={ isLoading }/>
{ config.features.metasuites.isEnabled && (
<>
<TextSeparator color="gray.500" flexShrink={ 0 } display="none" id="meta-suites__tx-explorer-separator"/>
<Box display="none" flexShrink={ 0 } id="meta-suites__tx-explorer-link"/>
</>
) }
</DetailsInfoItem> </DetailsInfoItem>
<DetailsInfoItem <DetailsInfoItem
title={ rollupFeature.isEnabled && rollupFeature.type === 'zkEvm' ? 'L2 status and method' : 'Status and method' } title={ rollupFeature.isEnabled && rollupFeature.type === 'zkEvm' ? 'L2 status and method' : 'Status and method' }
......
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