Fixes for Release v2.7.0 (#3310)
* fix: correct optional chaining in label-issues-in-release workflow - Updated the filter condition to ensure proper handling of optional chaining for issue labels when label doesn't have a description * add reown to ignored origins of errors in rollbar monitoring * export HintProps * add recipe for Code component and adjust select component props * fix screenshots * fix validator schema for multichain explorer * fix mobile lists in safari * screenshot update * deprecate NEXT_PUBLIC_ROLLUP_L1_BASE_URL env * add support of new Tac operation type * remove recaptcha token from query params * add skin for multichain * update multichain config * fix: og meta tags were not rendered on the server * enable NEXT_PUBLIC_VIEWS_ADDRESS_IDENTICON_TYPE var for multichain * disable e2e test job
@@ -223,7 +223,7 @@ jobs:
|
||||
|
||||
const issues = associatedPullRequests
|
||||
.nodes
|
||||
.filter(({ closingIssuesReferences: { nodes: issues } }) => !issues?.some(({ labels }) => labels?.nodes?.some(({ description }) => description.toLowerCase().startsWith('release'))))
|
||||
.filter(({ closingIssuesReferences: { nodes: issues } }) => !issues?.some(({ labels }) => labels?.nodes?.some(({ description }) => description?.toLowerCase().startsWith('release'))))
|
||||
.map(({ closingIssuesReferences: { nodes: issues } }) => issues.map(({ number }) => number))
|
||||
.flat();
|
||||
|
||||
|
||||
@@ -15,18 +15,20 @@ jobs:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
# publish_image:
|
||||
# image will be published in e2e-tests.yml workflow
|
||||
# name: Publish Docker image
|
||||
# uses: './.github/workflows/publish-image.yml'
|
||||
# secrets: inherit
|
||||
|
||||
e2e_tests:
|
||||
name: Run e2e tests
|
||||
needs: checks
|
||||
uses: "./.github/workflows/e2e-tests.yml"
|
||||
publish_image:
|
||||
name: Publish Docker image
|
||||
uses: './.github/workflows/publish-image.yml'
|
||||
secrets: inherit
|
||||
permissions: write-all
|
||||
with:
|
||||
platforms: linux/amd64
|
||||
|
||||
# e2e_tests:
|
||||
# decided to disable e2e temporarily
|
||||
# name: Run e2e tests
|
||||
# needs: checks
|
||||
# uses: "./.github/workflows/e2e-tests.yml"
|
||||
# secrets: inherit
|
||||
# permissions: write-all
|
||||
|
||||
version:
|
||||
name: Pre-release version info
|
||||
|
||||
@@ -15,15 +15,13 @@ const L2WithdrawalUrl = getEnvValue('NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL');
|
||||
|
||||
const parentChain: ParentChain | undefined = (() => {
|
||||
const envValue = parseEnvJson<ParentChain>(getEnvValue('NEXT_PUBLIC_ROLLUP_PARENT_CHAIN'));
|
||||
const baseUrl = stripTrailingSlash(getEnvValue('NEXT_PUBLIC_ROLLUP_L1_BASE_URL') || '');
|
||||
|
||||
if (!baseUrl && !envValue?.baseUrl) {
|
||||
if (!envValue?.baseUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
...envValue,
|
||||
baseUrl: baseUrl || envValue?.baseUrl || '',
|
||||
baseUrl: stripTrailingSlash(envValue.baseUrl),
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ NEXT_PUBLIC_NETWORK_RPC_URL=https://arbitrum-one.publicnode.com
|
||||
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
|
||||
NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/arbitrum-one.png
|
||||
NEXT_PUBLIC_PUZZLE_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/capyPuzzleBadge
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth.blockscout.com
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://eth.blockscout.com','currency':{'name':'Ether','symbol':'ETH','decimals':18},'isTestnet':false,'id':1,'name':'Ethereum Mainnet','rpcUrls':['https://eth.drpc.org']}
|
||||
NEXT_PUBLIC_ROLLUP_STAGE_INDEX=1
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=arbitrum
|
||||
|
||||
@@ -31,8 +31,8 @@ NEXT_PUBLIC_NETWORK_RPC_URL=https://arbitrum.llamarpc.com
|
||||
NEXT_PUBLIC_NETWORK_SHORT_NAME=Arbitrum Nova
|
||||
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
|
||||
NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/arbitrum-nova.png
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth.blockscout.com
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=arbitrum
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://eth.blockscout.com'}
|
||||
NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout
|
||||
NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true
|
||||
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
|
||||
@@ -44,7 +44,6 @@ NEXT_PUBLIC_NETWORK_RPC_URL=https://sepolia-rollup.arbitrum.io/rpc
|
||||
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
|
||||
NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/arbitrum-sepolia.png
|
||||
NEXT_PUBLIC_PUZZLE_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/capyPuzzleBadge
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth-sepolia.blockscout.com
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://eth-sepolia.blockscout.com','currency':{'name':'Ether','symbol':'ETH','decimals':18},'isTestnet':true,'id':11155111,'name':'Sepolia','rpcUrls':['https://eth-sepolia.public.blastapi.io']}
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=arbitrum
|
||||
NEXT_PUBLIC_STATS_API_BASE_PATH=/stats-service
|
||||
|
||||
@@ -67,7 +67,7 @@ NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
|
||||
NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/base-mainnet.png
|
||||
NEXT_PUBLIC_OTHER_LINKS=[{'url':'https://base.drpc.org?ref=559183','text':'Public RPC'}]
|
||||
NEXT_PUBLIC_PUZZLE_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/capyPuzzleBadge
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth.blockscout.com/
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://eth.blockscout.com'}
|
||||
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://bridge.base.org/withdraw
|
||||
NEXT_PUBLIC_ROLLUP_STAGE_INDEX=1
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=optimistic
|
||||
|
||||
@@ -55,7 +55,7 @@ NEXT_PUBLIC_NETWORK_SHORT_NAME=Mainnet
|
||||
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
|
||||
NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/celo.png
|
||||
NEXT_PUBLIC_PUZZLE_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/capyPuzzleBadge
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth.blockscout.com/
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://eth.blockscout.com'}
|
||||
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://mondo.celo.org/bridge
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=optimistic
|
||||
NEXT_PUBLIC_STATS_API_BASE_PATH=/stats-service
|
||||
|
||||
@@ -46,7 +46,7 @@ NEXT_PUBLIC_OG_DESCRIPTION=Redstone is the home for onchain games, worlds, and o
|
||||
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
|
||||
NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/garnet.png
|
||||
NEXT_PUBLIC_PUZZLE_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/capyPuzzleBadge
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth-holesky.blockscout.com/
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://eth-holesky.blockscout.com'}
|
||||
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://garnet.qry.live/withdraw
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=optimistic
|
||||
NEXT_PUBLIC_STATS_API_BASE_PATH=/stats-service
|
||||
|
||||
@@ -49,7 +49,7 @@ NEXT_PUBLIC_NETWORK_RPC_URL=https://alpha.megaeth.com/rpc
|
||||
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
|
||||
NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/mega-eth.png
|
||||
NEXT_PUBLIC_PUZZLE_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/capyPuzzleBadge
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth.blockscout.com/
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://eth.blockscout.com'}
|
||||
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://www.megaeth.com/
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=optimistic
|
||||
NEXT_PUBLIC_STATS_API_BASE_PATH=/stats-service
|
||||
|
||||
@@ -8,6 +8,16 @@ NEXT_PUBLIC_APP_HOST=localhost
|
||||
NEXT_PUBLIC_APP_PORT=3000
|
||||
NEXT_PUBLIC_APP_ENV=development
|
||||
|
||||
NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/multichain-light.svg
|
||||
NEXT_PUBLIC_NETWORK_ICON_DARK=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/multichain-dark.svg
|
||||
NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-logos/multichain-light.svg
|
||||
NEXT_PUBLIC_NETWORK_LOGO_DARK=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-logos/multichain-dark.svg
|
||||
NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/multichain.png
|
||||
FAVICON_MASTER_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/favicons/multichain.png
|
||||
NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['linear-gradient(89deg,rgba(83,83,211) 50.49%,rgba(155,155,255) 99.38%)'],'text_color':['rgba(225,225,255,1)'],'button':{'_default':{'background':['rgba(16,17,18,1)']},'_hover':{'background':['rgba(74,71,127,1)']}}}
|
||||
NEXT_PUBLIC_COLOR_THEME_OVERRIDES={'bg':{'primary':{'_light':{'value':'rgba(255,255,255,1)'},'_dark':{'value':'rgba(35,43,55,1)'}}},'text':{'primary':{'_light':{'value':'rgba(16,17,18,0.8)'},'_dark':{'value':'rgba(255,255,255,0.8)'}},'secondary':{'_light':{'value':'rgba(113,128,150,1)'},'_dark':{'value':'rgba(160,174,192,1)'}}},'hover':{'_light':{'value':'rgba(155,155,255,1)'},'_dark':{'value':'rgba(155,155,255,1)'}},'selected':{'control':{'text':{'_light':{'value':'rgba(16,17,18,1)'},'_dark':{'value':'rgba(247,250,252,1)'}},'bg':{'_light':{'value':'rgba(16,17,18,0.04)'},'_dark':{'value':'rgba(247,250,252,0.06)'}}},'option':{'bg':{'_light':{'value':'rgba(83,83,211,1)'},'_dark':{'value':'rgba(114,114,233,1)'}}}},'icon':{'primary':{'_light':{'value':'rgba(113,128,150,1)'},'_dark':{'value':'rgba(160,174,192,1)'}},'secondary':{'_light':{'value':'rgba(160,174,192,1)'},'_dark':{'value':'rgba(113,128,150,1)'}}},'button':{'primary':{'_light':{'value':'rgba(83,83,211,1)'},'_dark':{'value':'rgba(114,114,233,1)'},'text':{'_light':{'value':'rgba(255,255,255,0.92)'},'_dark':{'value':'rgba(255,255,255,0.92)'}}}},'link':{'primary':{'_light':{'value':'rgba(83,83,211,1)'},'_dark':{'value':'rgba(114,114,233,1)'}}},'graph':{'line':{'_light':{'value':'rgba(94,87,112,1)'},'_dark':{'value':'rgba(194,190,208,1)'}},'gradient':{'start':{'_light':{'value':'rgba(94,87,112,0.3)'},'_dark':{'value':'rgba(194,190,208,0.3)'}},'stop':{'_light':{'value':'rgba(94,87,112,0)'},'_dark':{'value':'rgba(194,190,208,0)'}}}},'stats':{'bg':{'_light':{'value':'rgba(16,17,18,0.04)'},'_dark':{'value':'rgba(255,255,255,0.06)'}}},'topbar':{'bg':{'_light':{'value':'rgba(16,17,18,0.04)'},'_dark':{'value':'rgba(255,255,255,0.06)'}}},'navigation':{'text':{'selected':{'_light':{'value':'rgba(16,17,18,1)'},'_dark':{'value':'rgba(247,250,252,1)'}}},'bg':{'selected':{'_light':{'value':'rgba(16,17,18,0.04)'},'_dark':{'value':'rgba(255,255,255,0.06)'}}}},'tabs':{'text':{'primary':{'_light':{'value':'rgba(113,128,150,1)'},'_dark':{'value':'rgba(160,174,192,1)'}}}}}
|
||||
|
||||
|
||||
NEXT_PUBLIC_MULTICHAIN_ENABLED=true
|
||||
NEXT_PUBLIC_MULTICHAIN_AGGREGATOR_API_HOST=https://multichain-aggregator.services.blockscout.com
|
||||
NEXT_PUBLIC_MULTICHAIN_CLUSTER=multichain
|
||||
|
||||
@@ -63,7 +63,7 @@ NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
|
||||
NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/optimism-mainnet.png
|
||||
NEXT_PUBLIC_OTHER_LINKS=[{'url':'https://optimism.drpc.org?ref=559183','text':'Public RPC'}]
|
||||
NEXT_PUBLIC_PUZZLE_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/capyPuzzleBadge
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth.blockscout.com/
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://eth.blockscout.com'}
|
||||
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://app.optimism.io/bridge/withdraw
|
||||
NEXT_PUBLIC_ROLLUP_STAGE_INDEX=1
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=optimistic
|
||||
|
||||
@@ -50,7 +50,7 @@ NEXT_PUBLIC_NETWORK_NAME=OP Sepolia
|
||||
NEXT_PUBLIC_NETWORK_RPC_URL=https://sepolia.optimism.io
|
||||
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
|
||||
NEXT_PUBLIC_PUZZLE_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/capyPuzzleBadge
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth-sepolia.blockscout.com/
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://eth-sepolia.blockscout.com'}
|
||||
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://app.optimism.io/bridge/withdraw
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=optimistic
|
||||
NEXT_PUBLIC_STATS_API_BASE_PATH=/stats-service
|
||||
|
||||
@@ -30,7 +30,7 @@ NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=false
|
||||
NEXT_PUBLIC_OTHER_LINKS=[]
|
||||
NEXT_PUBLIC_ROLLUP_DA_CELESTIA_CELENIUM_URL=https://mocha-4.celenium.io/blob
|
||||
NEXT_PUBLIC_ROLLUP_DA_CELESTIA_NAMESPACE=0x00000000000000000000000000000000000000ca1de12a9905be97beaf
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://arbitrum-sepolia.blockscout.com/
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://arbitrum-sepolia.blockscout.com'}
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=arbitrum
|
||||
NEXT_PUBLIC_SEO_ENHANCED_DATA_ENABLED=false
|
||||
NEXT_PUBLIC_VIEWS_ADDRESS_IDENTICON_TYPE=jazzicon
|
||||
|
||||
@@ -39,7 +39,7 @@ NEXT_PUBLIC_NETWORK_RPC_URL=https://sepolia-rpc.scroll.io
|
||||
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
|
||||
NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/scroll-testnet.png
|
||||
NEXT_PUBLIC_PUZZLE_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/capyPuzzleBadge
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth-sepolia.blockscout.com
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://eth-sepolia.blockscout.com'}
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=scroll
|
||||
NEXT_PUBLIC_STATS_API_BASE_PATH=/stats-service
|
||||
NEXT_PUBLIC_STATS_API_HOST=https://scroll-sepolia.blockscout.com
|
||||
|
||||
@@ -56,7 +56,7 @@ NEXT_PUBLIC_NETWORK_SHORT_NAME=Puppynet
|
||||
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
|
||||
NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/shibarium-mainnet.png
|
||||
NEXT_PUBLIC_PUZZLE_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/capyPuzzleBadge
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth.blockscout.com/
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://eth.blockscout.com'}
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=shibarium
|
||||
NEXT_PUBLIC_STATS_API_BASE_PATH=/stats-service
|
||||
NEXT_PUBLIC_STATS_API_HOST=https://www.shibariumscan.io
|
||||
|
||||
@@ -40,7 +40,8 @@ NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-c
|
||||
NEXT_PUBLIC_PUZZLE_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/capyPuzzleBadge
|
||||
NEXT_PUBLIC_STATS_API_BASE_PATH=/stats-service
|
||||
NEXT_PUBLIC_STATS_API_HOST=https://spb.explorer.tac.build
|
||||
NEXT_PUBLIC_TAC_OPERATION_LIFECYCLE_API_HOST=https://tac-spb-operation-lifecycle.k8s.blockscout.com
|
||||
# NEXT_PUBLIC_TAC_OPERATION_LIFECYCLE_API_HOST=https://tac-spb-operation-lifecycle.k8s.blockscout.com
|
||||
NEXT_PUBLIC_TAC_OPERATION_LIFECYCLE_API_HOST=https://tac-spb-operation-lifecycle.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_TAC_TON_EXPLORER_URL=https://testnet.tonviewer.com
|
||||
NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout
|
||||
NEXT_PUBLIC_VIEWS_TOKEN_SCAM_TOGGLE_ENABLED=true
|
||||
|
||||
@@ -39,7 +39,7 @@ NEXT_PUBLIC_NETWORK_NAME=Polygon CDK Stavanger
|
||||
NEXT_PUBLIC_NETWORK_RPC_URL=https://sn2-stavanger-rpc.eu-north-2.gateway.fm
|
||||
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
|
||||
NEXT_PUBLIC_PUZZLE_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/capyPuzzleBadge
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth-sepolia.blockscout.com
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://eth-sepolia.blockscout.com'}
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=zkEvm
|
||||
NEXT_PUBLIC_STATS_API_BASE_PATH=/stats-service
|
||||
NEXT_PUBLIC_STATS_API_HOST=https://polygon-cdk-stavanger.blockscout.com
|
||||
|
||||
@@ -51,7 +51,7 @@ NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
|
||||
NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/zksync.png
|
||||
NEXT_PUBLIC_OTHER_LINKS=[{'url':'https://zksync.drpc.org?ref=559183','text':'Public RPC'}]
|
||||
NEXT_PUBLIC_PUZZLE_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/capyPuzzleBadge
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth.blockscout.com/
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://eth.blockscout.com'}
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=zkSync
|
||||
NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-zksync.safe.global
|
||||
NEXT_PUBLIC_STATS_API_BASE_PATH=/stats-service
|
||||
|
||||
@@ -54,7 +54,7 @@ NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
|
||||
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
|
||||
NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/zora-mainnet.png
|
||||
NEXT_PUBLIC_PUZZLE_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/capyPuzzleBadge
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth.blockscout.com/
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://eth.blockscout.com'}
|
||||
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://bridge.zora.energy
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=optimistic
|
||||
NEXT_PUBLIC_STATS_API_BASE_PATH=/stats-service
|
||||
|
||||
@@ -152,12 +152,7 @@ function getEnvsPlaceholders(filePath: string): Promise<Array<string>> {
|
||||
}
|
||||
|
||||
function printDeprecationWarning(envsMap: Record<string, string>) {
|
||||
if (
|
||||
envsMap.NEXT_PUBLIC_ROLLUP_L1_BASE_URL
|
||||
) {
|
||||
// eslint-disable-next-line max-len
|
||||
console.warn('❗ The NEXT_PUBLIC_ROLLUP_L1_BASE_URL variables are now deprecated and will be removed in the next release. Please migrate to the NEXT_PUBLIC_ROLLUP_PARENT_CHAIN variable.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function checkDeprecatedEnvs(envsMap: Record<string, string>) {
|
||||
|
||||
@@ -13,7 +13,6 @@ import type { AddressProfileAPIConfig } from 'types/client/addressProfileAPIConf
|
||||
import type { GasRefuelProviderConfig } from 'types/client/gasRefuelProviderConfig';
|
||||
import { GAS_UNITS } from 'types/client/gasTracker';
|
||||
import type { GasUnit } from 'types/client/gasTracker';
|
||||
import type { MultichainProviderConfig } from 'types/client/multichainProviderConfig';
|
||||
import { PROVIDERS as TX_INTERPRETATION_PROVIDERS } from 'types/client/txInterpretation';
|
||||
import { VALIDATORS_CHAIN_TYPE } from 'types/client/validators';
|
||||
import type { ValidatorsChainType } from 'types/client/validators';
|
||||
@@ -30,14 +29,6 @@ import * as uiSchemas from './schemas/ui';
|
||||
import * as featuresSchemas from './schemas/features';
|
||||
import servicesSchema from './schemas/services';
|
||||
|
||||
const multichainProviderConfigSchema: yup.ObjectSchema<MultichainProviderConfig> = yup.object({
|
||||
name: yup.string().required(),
|
||||
url_template: yup.string().required(),
|
||||
logo: yup.string().required(),
|
||||
dapp_id: yup.string(),
|
||||
promo: yup.boolean(),
|
||||
});
|
||||
|
||||
const schema = yup
|
||||
.object()
|
||||
.noUnknown(true, (params) => {
|
||||
@@ -79,11 +70,6 @@ const schema = yup
|
||||
NEXT_PUBLIC_SAFE_TX_SERVICE_URL: yup.string().test(urlTest),
|
||||
NEXT_PUBLIC_IS_SUAVE_CHAIN: yup.boolean(),
|
||||
NEXT_PUBLIC_METASUITES_ENABLED: yup.boolean(),
|
||||
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG: yup
|
||||
.array()
|
||||
.transform(replaceQuotes)
|
||||
.json()
|
||||
.of(multichainProviderConfigSchema),
|
||||
NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG: yup
|
||||
.mixed()
|
||||
.test('shape', 'Invalid schema were provided for NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG, it should have name and url template', (data) => {
|
||||
@@ -170,6 +156,7 @@ const schema = yup
|
||||
.concat(featuresSchemas.highlightsConfigSchema)
|
||||
.concat(featuresSchemas.marketplaceSchema)
|
||||
.concat(featuresSchemas.megaEthSchema)
|
||||
.concat(featuresSchemas.multichainButtonSchema)
|
||||
.concat(featuresSchemas.nameServicesSchema)
|
||||
.concat(featuresSchemas.rollupSchema)
|
||||
.concat(featuresSchemas.tacSchema)
|
||||
|
||||
@@ -12,6 +12,7 @@ import * as uiSchemas from './schemas/ui';
|
||||
import * as featuresSchemas from './schemas/features';
|
||||
import servicesSchemas from './schemas/services';
|
||||
import { replaceQuotes } from 'configs/app/utils';
|
||||
import { IDENTICON_TYPES } from 'types/views/address';
|
||||
|
||||
const schema = yup
|
||||
.object()
|
||||
@@ -38,6 +39,10 @@ const schema = yup
|
||||
NEXT_PUBLIC_NETWORK_SHORT_NAME: yup.string(),
|
||||
NEXT_PUBLIC_IS_TESTNET: yup.boolean(),
|
||||
|
||||
// 3. UI views configuration
|
||||
// Some settings that we actually support in multichain mode
|
||||
NEXT_PUBLIC_VIEWS_ADDRESS_IDENTICON_TYPE: yup.string().oneOf(IDENTICON_TYPES),
|
||||
|
||||
// 5. Features configuration
|
||||
// NOTE!: Not all features are supported in multichain mode, and some of them not relevant or enabled per chain basis
|
||||
// Below listed supported features and the features that are enabled by default, so we have to turn them off
|
||||
@@ -63,8 +68,9 @@ const schema = yup
|
||||
.concat(uiSchemas.footerSchema)
|
||||
.concat(uiSchemas.miscSchema)
|
||||
.concat(featuresSchemas.adsSchema)
|
||||
.concat(featuresSchemas.userOpsSchema)
|
||||
.concat(featuresSchemas.defiDropdownSchema)
|
||||
.concat(featuresSchemas.multichainButtonSchema)
|
||||
.concat(featuresSchemas.userOpsSchema)
|
||||
.concat(servicesSchemas);
|
||||
|
||||
export default schema;
|
||||
|
||||
@@ -9,6 +9,7 @@ export * from './defiDropdown';
|
||||
export * from './highlights';
|
||||
export * from './marketplace';
|
||||
export * from './megaEth';
|
||||
export * from './multichainButton';
|
||||
export * from './nameServices';
|
||||
export * from './rollup';
|
||||
export * from './tac';
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { replaceQuotes } from 'configs/app/utils';
|
||||
import { MultichainProviderConfig } from 'types/client/multichainProviderConfig';
|
||||
import * as yup from 'yup';
|
||||
|
||||
const multichainProviderConfigSchema: yup.ObjectSchema<MultichainProviderConfig> = yup.object({
|
||||
name: yup.string().required(),
|
||||
url_template: yup.string().required(),
|
||||
logo: yup.string().required(),
|
||||
dapp_id: yup.string(),
|
||||
promo: yup.boolean(),
|
||||
});
|
||||
|
||||
export const multichainButtonSchema = yup
|
||||
.object()
|
||||
.shape({
|
||||
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG: yup
|
||||
.array()
|
||||
.transform(replaceQuotes)
|
||||
.json()
|
||||
.of(multichainProviderConfigSchema)
|
||||
});
|
||||
@@ -12,46 +12,46 @@ const parentChainCurrencySchema = yup
|
||||
decimals: yup.number().required(),
|
||||
});
|
||||
|
||||
const parentChainSchema = yup
|
||||
.object()
|
||||
.transform(replaceQuotes)
|
||||
.json()
|
||||
.shape({
|
||||
id: yup.number(),
|
||||
name: yup.string(),
|
||||
baseUrl: yup.string().test(urlTest).required(),
|
||||
rpcUrls: yup.array().of(yup.string().test(urlTest)),
|
||||
currency: yup
|
||||
.mixed()
|
||||
.test(
|
||||
'shape',
|
||||
(ctx) => {
|
||||
try {
|
||||
parentChainCurrencySchema.validateSync(ctx.originalValue);
|
||||
throw new Error('Unknown validation error');
|
||||
} catch (error: unknown) {
|
||||
const message = getYupValidationErrorMessage(error);
|
||||
return 'in \"currency\" property ' + (message ? `${ message }` : '');
|
||||
}
|
||||
},
|
||||
(data) => {
|
||||
const isUndefined = data === undefined;
|
||||
return isUndefined || parentChainCurrencySchema.isValidSync(data);
|
||||
},
|
||||
),
|
||||
isTestnet: yup.boolean(),
|
||||
});
|
||||
|
||||
export const rollupSchema = yup
|
||||
.object()
|
||||
.shape({
|
||||
NEXT_PUBLIC_ROLLUP_TYPE: yup.string().oneOf(ROLLUP_TYPES),
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL: yup
|
||||
.string()
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN: yup
|
||||
.object()
|
||||
.when('NEXT_PUBLIC_ROLLUP_TYPE', {
|
||||
is: (value: string) => value,
|
||||
then: (schema) => schema.test(urlTest).required(),
|
||||
otherwise: (schema) => schema.max(-1, 'NEXT_PUBLIC_ROLLUP_L1_BASE_URL cannot not be used if NEXT_PUBLIC_ROLLUP_TYPE is not defined'),
|
||||
then: (schema) => {
|
||||
return schema.transform(replaceQuotes).json().shape({
|
||||
id: yup.number(),
|
||||
name: yup.string(),
|
||||
baseUrl: yup.string().test(urlTest).required(),
|
||||
rpcUrls: yup.array().of(yup.string().test(urlTest)),
|
||||
currency: yup
|
||||
.mixed()
|
||||
.test(
|
||||
'shape',
|
||||
(ctx) => {
|
||||
try {
|
||||
parentChainCurrencySchema.validateSync(ctx.originalValue);
|
||||
throw new Error('Unknown validation error');
|
||||
} catch (error: unknown) {
|
||||
const message = getYupValidationErrorMessage(error);
|
||||
return 'in \"currency\" property ' + (message ? `${ message }` : '');
|
||||
}
|
||||
},
|
||||
(data) => {
|
||||
const isUndefined = data === undefined;
|
||||
return isUndefined || parentChainCurrencySchema.isValidSync(data);
|
||||
},
|
||||
),
|
||||
isTestnet: yup.boolean(),
|
||||
})
|
||||
},
|
||||
otherwise: (schema) => schema.test(
|
||||
'not-exist',
|
||||
'NEXT_PUBLIC_ROLLUP_PARENT_CHAIN cannot not be used if NEXT_PUBLIC_ROLLUP_TYPE is not defined',
|
||||
value => value === undefined,
|
||||
),
|
||||
}),
|
||||
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL: yup
|
||||
.string()
|
||||
@@ -113,34 +113,6 @@ export const rollupSchema = yup
|
||||
value => value === undefined,
|
||||
),
|
||||
}),
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN: yup
|
||||
.mixed()
|
||||
.when('NEXT_PUBLIC_ROLLUP_TYPE', {
|
||||
is: (value: string) => value,
|
||||
then: (schema) => {
|
||||
return schema.test(
|
||||
'shape',
|
||||
(ctx) => {
|
||||
try {
|
||||
parentChainSchema.validateSync(ctx.originalValue);
|
||||
throw new Error('Unknown validation error');
|
||||
} catch (error: unknown) {
|
||||
const message = getYupValidationErrorMessage(error);
|
||||
return 'Invalid schema were provided for NEXT_PUBLIC_ROLLUP_PARENT_CHAIN' + (message ? `: ${ message }` : '');
|
||||
}
|
||||
},
|
||||
(data) => {
|
||||
const isUndefined = data === undefined;
|
||||
return isUndefined || parentChainSchema.isValidSync(data);
|
||||
}
|
||||
)
|
||||
},
|
||||
otherwise: (schema) => schema.test(
|
||||
'not-exist',
|
||||
'NEXT_PUBLIC_ROLLUP_PARENT_CHAIN cannot not be used if NEXT_PUBLIC_ROLLUP_TYPE is not defined',
|
||||
value => value === undefined,
|
||||
),
|
||||
}),
|
||||
NEXT_PUBLIC_ROLLUP_DA_CELESTIA_NAMESPACE: yup
|
||||
.string()
|
||||
.min(60)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=arbitrum
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://example.com
|
||||
NEXT_PUBLIC_ROLLUP_HOMEPAGE_SHOW_LATEST_BLOCKS=true
|
||||
NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://explorer.duckchain.io','currency':{'name':'Quack','symbol':'QUACK','decimals':18},'isTestnet':true,'id':42,'name':'DuckChain','rpcUrls':['https://rpc.duckchain.io']}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ NEXT_PUBLIC_API_DOCS_TABS=[]
|
||||
NEXT_PUBLIC_FEATURED_NETWORKS=http://example.com
|
||||
NEXT_PUBLIC_FOOTER_LINKS=http://example.com
|
||||
NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['linear-gradient(90deg, rgb(232, 52, 53) 0%, rgb(139, 28, 232) 100%)'],'text_color':['rgb(255, 255, 255)']}
|
||||
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
|
||||
NEXT_PUBLIC_NETWORK_ICON=http://example.com
|
||||
NEXT_PUBLIC_NETWORK_ICON_DARK=http://example.com
|
||||
NEXT_PUBLIC_NETWORK_LOGO=http://example.com
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=optimistic
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://example.com
|
||||
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://example.com
|
||||
NEXT_PUBLIC_FAULT_PROOF_ENABLED=true
|
||||
NEXT_PUBLIC_ROLLUP_HOMEPAGE_SHOW_LATEST_BLOCKS=true
|
||||
|
||||
@@ -31,3 +31,4 @@
|
||||
| NEXT_PUBLIC_VIEWS_CONTRACT_LANGUAGE_FILTERS | `Array<'solidity' \| 'vyper' \| 'yul' \| 'scilla' \| 'geas' \| 'stylus_rust'>` | Pass an array of contract languages that will be displayed as options in the filter on the verified contract page. | - | `['solidity','vyper','yul','geas','stylus_rust']` | `['solidity','vyper','yul','scilla']` | v1.37.0+ | v2.6.0+ | Replaced with configuration retrieved from the API. |
|
||||
| NEXT_PUBLIC_SAVE_ON_GAS_ENABLED | `boolean` | Set to "true" to enable the feature | - | - | `true` | v1.35.0+ | v2.7.0+ | Feature is deprecated. |
|
||||
| NEXT_PUBLIC_API_SPEC_URL | `string` | Spec of Blockscout core API to be displayed on the page. | - | `https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml` | `https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml` | v1.0.x+ | v2.7.0+ | The URL is now constructed automatically based on the configuration received from the API. |
|
||||
| NEXT_PUBLIC_ROLLUP_L1_BASE_URL | `string` | Blockscout base URL for parent network. | Required | - | `'http://eth-goerli.blockscout.com'` | v1.24.0+ | v2.7.0+ | Replaced with NEXT_PUBLIC_ROLLUP_PARENT_CHAIN |
|
||||
|
||||
@@ -530,7 +530,7 @@ Ads are enabled by default on all self-hosted instances. If you would like to di
|
||||
| Variable | Type| Description | Compulsoriness | Default value | Example value | Version |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| NEXT_PUBLIC_ROLLUP_TYPE | `'optimistic' \| 'arbitrum' \| 'shibarium' \| 'zkEvm' \| 'zkSync' \| 'scroll'` | Rollup chain type | Required | - | `'optimistic'` | v1.24.0+ |
|
||||
| NEXT_PUBLIC_ROLLUP_L1_BASE_URL | `string` | Blockscout base URL for parent network. **DEPRECATED** _Use `NEXT_PUBLIC_ROLLUP_PARENT_CHAIN` instead_ | Required | - | `'http://eth-goerli.blockscout.com'` | v1.24.0+ |
|
||||
| NEXT_PUBLIC_ROLLUP_PARENT_CHAIN | `ParentChain`, see details [below](#parent-chain-configuration-properties) | Configuration parameters for the parent chain. | Required | - | `{'baseUrl':'https://explorer.duckchain.io'}` | v1.38.0+ |
|
||||
| NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL | `string` | URL for rollup to parent chain withdrawals (Optimistic stack only) | - | - | `https://app.optimism.io/bridge/withdraw` | v1.24.0+ |
|
||||
| NEXT_PUBLIC_ROLLUP_LAYER_NUMBER | `number` | Layer number of the rollup | - | `2` | `3` | v2.7.0+ |
|
||||
| NEXT_PUBLIC_ROLLUP_STAGE_INDEX | `1 \| 2` | Reflects the maturity and decentralization level of the chain based on [L2BEAT's framework](https://medium.com/l2beat/introducing-stages-a-framework-to-evaluate-rollups-maturity-d290bb22befe). The label will be added to the sidebar according to the provided stage index. Not applicable for testnets. | - | - | `1` | v2.1.0+ |
|
||||
@@ -539,7 +539,6 @@ Ads are enabled by default on all self-hosted instances. If you would like to di
|
||||
| NEXT_PUBLIC_INTEROP_ENABLED | `boolean` | Enables "Interop messages" page (Optimistic stack only) | - | `false` | `true` | v1.39.0+ |
|
||||
| NEXT_PUBLIC_ROLLUP_HOMEPAGE_SHOW_LATEST_BLOCKS | `boolean` | Set to `true` to display "Latest blocks" widget instead of "Latest batches" on the home page | - | - | `true` | v1.36.0+ |
|
||||
| NEXT_PUBLIC_ROLLUP_OUTPUT_ROOTS_ENABLED | `boolean` | Enables "Output roots" page (Optimistic stack only) | - | `false` | `true` | v1.37.0+ |
|
||||
| NEXT_PUBLIC_ROLLUP_PARENT_CHAIN | `ParentChain`, see details [below](#parent-chain-configuration-properties) | Configuration parameters for the parent chain. | - | - | `{'baseUrl':'https://explorer.duckchain.io'}` | v1.38.0+ |
|
||||
| NEXT_PUBLIC_ROLLUP_DA_CELESTIA_NAMESPACE | `string` | Hex-string for creating a link to the transaction batch on the [Celenium explorer](https://celenium.io). "0x"-format and 60 symbol length. Available only for Arbitrum roll-ups. | - | - | `0x00000000000000000000000000000000000000ca1de12a9905be97beaf` | v1.38.0+ |
|
||||
| NEXT_PUBLIC_ROLLUP_DA_CELESTIA_CELENIUM_URL | `string` | URL for the Selenium explorer. It is used to create links to the Data Availability Blobs page. The URL should contain the full path without any search parameters related to the blob, as these will be constructed at runtime for each blob separately. Available only for Optimistic or Arbitrum roll-ups. | - | - | `https://mocha.celenium.io/blob` | v2.0.2+ |
|
||||
|
||||
@@ -547,9 +546,9 @@ Ads are enabled by default on all self-hosted instances. If you would like to di
|
||||
|
||||
| Variable | Type| Description | Compulsoriness | Default value | Example value |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| baseUrl | `string` | Base url of the chain explorer. | Required | - | `https://explorer.duckchain.io` |
|
||||
| id | `number` | Chain id, see [https://chainlist.org](https://chainlist.org) for the reference. | - | - | `42` |
|
||||
| name | `string` | Displayed name of the chain. Set to customize parent chain transaction status labels in the UI (e.g., "Sent to <chain-name>"). Currently, this setting is applicable only for Arbitrum-based chains. | - | - | `DuckChain` |
|
||||
| baseUrl | `string` | Base url of the chain explorer. | Required | - | `https://explorer.duckchain.io` |
|
||||
| rpcUrls | `Array<string>` | Chain public RPC server urls, see [https://chainlist.org](https://chainlist.org) for the reference. | - | - | `['https://rpc.duckchain.io']` |
|
||||
| currency | `{ name: string; symbol: string; decimals: number; }` | Chain currency config. | - | - | `{ name: Quack, symbol: QUA, decimals: 18 }` |
|
||||
| isTestnet | `boolean` | Set to true if network is testnet. | - | - | `true` |
|
||||
|
||||
@@ -14,6 +14,8 @@ export function getTacOperationStatus(type: tac.OperationType) {
|
||||
return 'Error';
|
||||
case tac.OperationType.ROLLBACK:
|
||||
return 'Rollback';
|
||||
case tac.OperationType.INSUFFICIENT_FEE:
|
||||
return 'Insufficient fee';
|
||||
case tac.OperationType.PENDING:
|
||||
return 'Pending';
|
||||
default:
|
||||
|
||||
@@ -55,6 +55,7 @@ export const clientConfig: Configuration | undefined = feature.isEnabled ? {
|
||||
const originFileName = getExceptionOriginFileName(item);
|
||||
const IGNORED_ORIGIN_FILE_NAMES_CHUNKS = [
|
||||
'/node_modules/@walletconnect',
|
||||
'/node_modules/@reown',
|
||||
];
|
||||
|
||||
if (originFileName && IGNORED_ORIGIN_FILE_NAMES_CHUNKS.some((chunk) => originFileName.includes(chunk))) {
|
||||
|
||||
@@ -2,7 +2,6 @@ import React from 'react';
|
||||
|
||||
import type { Route } from 'nextjs-routes';
|
||||
import type { Props as PageProps } from 'nextjs/getServerSideProps/handlers';
|
||||
import PageMetadata from 'nextjs/PageMetadata';
|
||||
|
||||
import useAdblockDetect from 'lib/hooks/useAdblockDetect';
|
||||
import useGetCsrfToken from 'lib/hooks/useGetCsrfToken';
|
||||
@@ -27,12 +26,7 @@ const PageNextJs = <Pathname extends Route['pathname']>(props: Props<Pathname>)
|
||||
const isMixPanelInitialized = mixpanel.useInit();
|
||||
mixpanel.useLogPageView(isMixPanelInitialized);
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageMetadata pathname={ props.pathname } query={ props.query } apiData={ props.apiData }/>
|
||||
{ isMounted ? props.children : null }
|
||||
</>
|
||||
);
|
||||
return isMounted ? props.children : null;
|
||||
};
|
||||
|
||||
export default React.memo(PageNextJs);
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
"@blockscout/multichain-aggregator-types": "2.1.2",
|
||||
"@blockscout/points-types": "1.4.0-alpha.1",
|
||||
"@blockscout/stats-types": "2.11.1",
|
||||
"@blockscout/tac-operation-lifecycle-types": "0.0.1-alpha.6",
|
||||
"@blockscout/tac-operation-lifecycle-types": "1.1.0",
|
||||
"@blockscout/visualizer-types": "0.2.0",
|
||||
"@blockscout/zetachain-cctx-types": "^1.0.0-rc.6",
|
||||
"@chakra-ui/react": "3.33.0",
|
||||
|
||||
@@ -8,6 +8,9 @@ import React from 'react';
|
||||
|
||||
import type { NextPageWithLayout } from 'nextjs/types';
|
||||
|
||||
import type { Route } from 'nextjs-routes';
|
||||
import PageMetadata from 'nextjs/PageMetadata';
|
||||
|
||||
import config from 'configs/app';
|
||||
import getSocketUrl from 'lib/api/getSocketUrl';
|
||||
import useQueryClientConfig from 'lib/api/useQueryClientConfig';
|
||||
@@ -57,7 +60,7 @@ If you don't understand what this console is for, close it now and stay safe.`;
|
||||
|
||||
const CONSOLE_SCAM_WARNING_DELAY_MS = 500;
|
||||
|
||||
function MyApp({ Component, pageProps }: AppPropsWithLayout) {
|
||||
function MyApp({ Component, pageProps, router }: AppPropsWithLayout) {
|
||||
|
||||
const growthBook = initGrowthBook(pageProps.uuid);
|
||||
useLoadFeatures(growthBook);
|
||||
@@ -96,34 +99,37 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
|
||||
const socketUrl = !config.features.multichain.isEnabled ? getSocketUrl() : undefined;
|
||||
|
||||
return (
|
||||
<ChakraProvider>
|
||||
<RollbarProvider config={ rollbarConfig }>
|
||||
<AppErrorBoundary
|
||||
{ ...ERROR_SCREEN_STYLES }
|
||||
Container={ AppErrorGlobalContainer }
|
||||
>
|
||||
<QueryClientProvider client={ queryClient }>
|
||||
<Web3Provider>
|
||||
<AppContextProvider pageProps={ pageProps }>
|
||||
<GrowthBookProvider growthbook={ growthBook }>
|
||||
<SocketProvider url={ socketUrl }>
|
||||
<RewardsProvider>
|
||||
<MarketplaceContextProvider>
|
||||
<SettingsContextProvider>
|
||||
{ content }
|
||||
</SettingsContextProvider>
|
||||
</MarketplaceContextProvider>
|
||||
</RewardsProvider>
|
||||
</SocketProvider>
|
||||
</GrowthBookProvider>
|
||||
<ReactQueryDevtools buttonPosition="bottom-left" position="left"/>
|
||||
<GoogleAnalytics/>
|
||||
</AppContextProvider>
|
||||
</Web3Provider>
|
||||
</QueryClientProvider>
|
||||
</AppErrorBoundary>
|
||||
</RollbarProvider>
|
||||
</ChakraProvider>
|
||||
<>
|
||||
<PageMetadata pathname={ router.pathname as Route['pathname'] } query={ pageProps.query } apiData={ pageProps.apiData }/>
|
||||
<ChakraProvider>
|
||||
<RollbarProvider config={ rollbarConfig }>
|
||||
<AppErrorBoundary
|
||||
{ ...ERROR_SCREEN_STYLES }
|
||||
Container={ AppErrorGlobalContainer }
|
||||
>
|
||||
<QueryClientProvider client={ queryClient }>
|
||||
<Web3Provider>
|
||||
<AppContextProvider pageProps={ pageProps }>
|
||||
<GrowthBookProvider growthbook={ growthBook }>
|
||||
<SocketProvider url={ socketUrl }>
|
||||
<RewardsProvider>
|
||||
<MarketplaceContextProvider>
|
||||
<SettingsContextProvider>
|
||||
{ content }
|
||||
</SettingsContextProvider>
|
||||
</MarketplaceContextProvider>
|
||||
</RewardsProvider>
|
||||
</SocketProvider>
|
||||
</GrowthBookProvider>
|
||||
<ReactQueryDevtools buttonPosition="bottom-left" position="left"/>
|
||||
<GoogleAnalytics/>
|
||||
</AppContextProvider>
|
||||
</Web3Provider>
|
||||
</QueryClientProvider>
|
||||
</AppErrorBoundary>
|
||||
</RollbarProvider>
|
||||
</ChakraProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,20 +31,20 @@ export const ENVS_MAP: Record<string, Array<[string, string]>> = {
|
||||
],
|
||||
shibariumRollup: [
|
||||
[ 'NEXT_PUBLIC_ROLLUP_TYPE', 'shibarium' ],
|
||||
[ 'NEXT_PUBLIC_ROLLUP_L1_BASE_URL', 'https://localhost:3101' ],
|
||||
[ 'NEXT_PUBLIC_ROLLUP_PARENT_CHAIN', '{"baseUrl":"https://localhost:3101"}' ],
|
||||
],
|
||||
zkEvmRollup: [
|
||||
[ 'NEXT_PUBLIC_ROLLUP_TYPE', 'zkEvm' ],
|
||||
[ 'NEXT_PUBLIC_ROLLUP_L1_BASE_URL', 'https://localhost:3101' ],
|
||||
[ 'NEXT_PUBLIC_ROLLUP_PARENT_CHAIN', '{"baseUrl":"https://localhost:3101"}' ],
|
||||
],
|
||||
zkSyncRollup: [
|
||||
[ 'NEXT_PUBLIC_ROLLUP_TYPE', 'zkSync' ],
|
||||
[ 'NEXT_PUBLIC_ROLLUP_L1_BASE_URL', 'https://localhost:3101' ],
|
||||
[ 'NEXT_PUBLIC_ROLLUP_PARENT_CHAIN', '{"baseUrl":"https://localhost:3101"}' ],
|
||||
[ 'NEXT_PUBLIC_VIEWS_CONTRACT_EXTRA_VERIFICATION_METHODS', 'none' ],
|
||||
],
|
||||
scrollRollup: [
|
||||
[ 'NEXT_PUBLIC_ROLLUP_TYPE', 'scroll' ],
|
||||
[ 'NEXT_PUBLIC_ROLLUP_L1_BASE_URL', 'https://localhost:3101' ],
|
||||
[ 'NEXT_PUBLIC_ROLLUP_PARENT_CHAIN', '{"baseUrl":"https://localhost:3101"}' ],
|
||||
],
|
||||
bridgedTokens: [
|
||||
[ 'NEXT_PUBLIC_BRIDGED_TOKENS_CHAINS', '[{"id":"1","title":"Ethereum","short_title":"ETH","base_url":"https://eth.blockscout.com/token/"},{"id":"56","title":"Binance Smart Chain","short_title":"BSC","base_url":"https://bscscan.com/token/"},{"id":"99","title":"POA","short_title":"POA","base_url":"https://blockscout.com/poa/core/token/"}]' ],
|
||||
@@ -103,7 +103,7 @@ export const ENVS_MAP: Record<string, Array<[string, string]>> = {
|
||||
],
|
||||
interop: [
|
||||
[ 'NEXT_PUBLIC_ROLLUP_TYPE', 'optimistic' ],
|
||||
[ 'NEXT_PUBLIC_ROLLUP_L1_BASE_URL', 'https://localhost:3101' ],
|
||||
[ 'NEXT_PUBLIC_ROLLUP_PARENT_CHAIN', '{"baseUrl":"https://localhost:3101"}' ],
|
||||
[ 'NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL', 'https://localhost:3102' ],
|
||||
[ 'NEXT_PUBLIC_INTEROP_ENABLED', 'true' ],
|
||||
],
|
||||
|
||||
@@ -16,7 +16,7 @@ export type ViewMode = 'default' | 'compact';
|
||||
|
||||
export interface SelectOption<Value extends string = string> {
|
||||
label: string;
|
||||
renderLabel?: () => React.ReactNode;
|
||||
renderLabel?: (place: 'item' | 'value-text') => React.ReactNode;
|
||||
value: Value;
|
||||
icon?: React.ReactNode;
|
||||
afterElement?: React.ReactNode;
|
||||
@@ -166,7 +166,7 @@ export const SelectValueText = React.forwardRef<
|
||||
WebkitBoxOrient: 'vertical',
|
||||
display: '-webkit-box',
|
||||
}}>
|
||||
{ item.renderLabel ? item.renderLabel() : context.collection.stringifyItem(item) }
|
||||
{ item.renderLabel ? item.renderLabel('value-text') : context.collection.stringifyItem(item) }
|
||||
</span>
|
||||
) }
|
||||
</Flex>
|
||||
@@ -272,7 +272,7 @@ export const Select = React.forwardRef<HTMLDivElement, SelectProps>((props, ref)
|
||||
.map((item: SelectOption) => (
|
||||
<React.Fragment key={ item.value }>
|
||||
<SelectItem item={ item }>
|
||||
{ item.renderLabel ? item.renderLabel() : item.label }
|
||||
{ item.renderLabel ? item.renderLabel('item') : item.label }
|
||||
</SelectItem>
|
||||
{ item.afterElement }
|
||||
</React.Fragment>
|
||||
@@ -292,7 +292,7 @@ export interface SelectAsyncProps extends Omit<SelectProps, 'collection'> {
|
||||
}
|
||||
|
||||
export const SelectAsync = React.forwardRef<HTMLDivElement, SelectAsyncProps>((props, ref) => {
|
||||
const { placeholder, portalled = true, loading, loadOptions, extraControls, onValueChange, errorText, mode, ...rest } = props;
|
||||
const { placeholder, portalled = true, loading, loadOptions, extraControls, onValueChange, errorText, mode, contentHeader, ...rest } = props;
|
||||
|
||||
const [ collection, setCollection ] = React.useState<ListCollection<SelectOption>>(createListCollection<SelectOption>({ items: [] }));
|
||||
const [ inputValue, setInputValue ] = React.useState('');
|
||||
@@ -340,9 +340,10 @@ export const SelectAsync = React.forwardRef<HTMLDivElement, SelectAsyncProps>((p
|
||||
/>
|
||||
{ extraControls }
|
||||
</Box>
|
||||
{ contentHeader }
|
||||
{ collection.items.map((item) => (
|
||||
<SelectItem item={ item } key={ item.value }>
|
||||
{ item.renderLabel ? item.renderLabel() : item.label }
|
||||
{ item.renderLabel ? item.renderLabel('item') : item.label }
|
||||
</SelectItem>
|
||||
)) }
|
||||
</SelectContent>
|
||||
|
||||
@@ -8,14 +8,14 @@ import { IconButton } from '../../chakra/icon-button';
|
||||
import type { TooltipProps } from '../../chakra/tooltip';
|
||||
import { Tooltip } from '../../chakra/tooltip';
|
||||
|
||||
interface Props extends IconButtonProps {
|
||||
export interface HintProps extends IconButtonProps {
|
||||
label: string | React.ReactNode;
|
||||
tooltipProps?: Partial<TooltipProps>;
|
||||
isLoading?: boolean;
|
||||
as?: React.ElementType;
|
||||
}
|
||||
|
||||
export const Hint = React.memo(({ label, tooltipProps, isLoading, boxSize = 5, ...rest }: Props) => {
|
||||
export const Hint = React.memo(({ label, tooltipProps, isLoading, boxSize = 5, ...rest }: HintProps) => {
|
||||
return (
|
||||
<Tooltip
|
||||
content={ label }
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { defineRecipe } from '@chakra-ui/react';
|
||||
|
||||
import { recipe as badgeRecipe } from './badge.recipe';
|
||||
|
||||
const { variants, defaultVariants } = badgeRecipe;
|
||||
|
||||
export const recipe = defineRecipe({
|
||||
className: 'chakra-code',
|
||||
base: {
|
||||
fontFamily: 'mono',
|
||||
alignItems: 'center',
|
||||
display: 'inline-flex',
|
||||
borderRadius: 'l2',
|
||||
},
|
||||
variants,
|
||||
defaultVariants: {
|
||||
...defaultVariants,
|
||||
size: 'sm',
|
||||
},
|
||||
});
|
||||
@@ -5,6 +5,7 @@ import { recipe as button } from './button.recipe';
|
||||
import { recipe as checkbox } from './checkbox.recipe';
|
||||
import { recipe as checkmark } from './checkmark.recipe';
|
||||
import { recipe as closeButton } from './close-button.recipe';
|
||||
import { recipe as code } from './code.recipe';
|
||||
import { recipe as dialog } from './dialog.recipe';
|
||||
import { recipe as drawer } from './drawer.recipe';
|
||||
import { recipe as emptyState } from './empty-state.recipe';
|
||||
@@ -36,6 +37,7 @@ import { recipe as tooltip } from './tooltip.recipe';
|
||||
export const recipes = {
|
||||
badge,
|
||||
button,
|
||||
code,
|
||||
checkmark,
|
||||
closeButton,
|
||||
input,
|
||||
|
||||
@@ -68,6 +68,7 @@ const IGNORED_ENVS = [
|
||||
'NEXT_PUBLIC_VIEWS_CONTRACT_LANGUAGE_FILTERS',
|
||||
|
||||
'NEXT_PUBLIC_API_SPEC_URL',
|
||||
'NEXT_PUBLIC_ROLLUP_L1_BASE_URL',
|
||||
];
|
||||
|
||||
function parseScriptArgs() {
|
||||
|
||||
@@ -25,10 +25,7 @@ const ExportCSV = ({ filters }: Props) => {
|
||||
const [ isLoading, setIsLoading ] = React.useState(false);
|
||||
|
||||
const apiFetchFactory = React.useCallback(async(recaptchaToken?: string) => {
|
||||
const url = buildUrl('general:advanced_filter_csv', undefined, {
|
||||
...filters,
|
||||
recaptcha_response: recaptchaToken,
|
||||
}, undefined, multichainContext?.chain);
|
||||
const url = buildUrl('general:advanced_filter_csv', undefined, filters, undefined, multichainContext?.chain);
|
||||
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
|
||||
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 146 KiB |
@@ -48,7 +48,7 @@ const TokenTransfersCrossChainListItem = ({ data, isLoading, rowGap = 3, current
|
||||
<Time timestamp={ timestamp } format="lll_s"/>
|
||||
</Skeleton>
|
||||
) }
|
||||
<Grid templateColumns="100px 1fr" columnGap={ 2 } rowGap={ rowGap }>
|
||||
<Grid templateColumns="100px minmax(0, 1fr)" columnGap={ 2 } rowGap={ rowGap }>
|
||||
<Skeleton loading={ isLoading }>
|
||||
Source token
|
||||
</Skeleton>
|
||||
|
||||
@@ -66,7 +66,7 @@ const TransactionsCrossChainListItem = ({ data, isLoading, rowGap = 3, currentAd
|
||||
<Time timestamp={ timestamp } format="lll_s"/>
|
||||
</Skeleton>
|
||||
) }
|
||||
<Grid templateColumns="120px 1fr" columnGap={ 2 } rowGap={ rowGap }>
|
||||
<Grid templateColumns="120px minmax(0, 1fr)" columnGap={ 2 } rowGap={ rowGap }>
|
||||
<Skeleton loading={ isLoading }>
|
||||
Source tx
|
||||
</Skeleton>
|
||||
|
||||
@@ -51,7 +51,6 @@ const CsvExportForm = ({ hash, resource, filterType, filterValue, fileNameTempla
|
||||
to_period: exportType !== 'holders' ? dayjs(data.to).toISOString() : null,
|
||||
filter_type: filterType,
|
||||
filter_value: filterValue,
|
||||
recaptcha_response: recaptchaToken,
|
||||
}, undefined, multichainContext?.chain);
|
||||
|
||||
const response = await fetch(url, {
|
||||
|
||||
@@ -98,7 +98,7 @@ const ChainWidget = ({ data, isLoading, metrics }: Props) => {
|
||||
borderColor={{ _light: 'blackAlpha.200', _dark: 'whiteAlpha.200' }}
|
||||
_hover={ !isLoading ? {
|
||||
bgColor: { _light: 'gray.50', _dark: 'whiteAlpha.100' },
|
||||
borderColor: { _light: 'blue.100', _dark: 'blue.700' },
|
||||
borderColor: 'hover',
|
||||
} : undefined }
|
||||
p={ 6 }
|
||||
flexBasis="calc((100% - 3 * 12px) / 4)"
|
||||
|
||||
|
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 179 KiB |
|
Before Width: | Height: | Size: 177 KiB After Width: | Height: | Size: 177 KiB |
@@ -28,26 +28,28 @@ const TacOperationLifecycleAccordionItemContent = ({ isLast, data }: Props) => {
|
||||
</ItemRow>
|
||||
) }
|
||||
|
||||
<ItemRow label="Transactions">
|
||||
<Box
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
rowGap={ 3 }
|
||||
py="6px"
|
||||
width="100%"
|
||||
overflow="hidden"
|
||||
>
|
||||
{
|
||||
data.transactions.map((tx) => {
|
||||
if (tx.type === tac.BlockchainType.TON) {
|
||||
return <TxEntityTon key={ tx.hash } hash={ tx.hash }/>;
|
||||
}
|
||||
{ data.transactions.length > 0 && (
|
||||
<ItemRow label="Transactions">
|
||||
<Box
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
rowGap={ 3 }
|
||||
py="6px"
|
||||
width="100%"
|
||||
overflow="hidden"
|
||||
>
|
||||
{
|
||||
data.transactions.map((tx) => {
|
||||
if (tx.type === tac.BlockchainType.TON) {
|
||||
return <TxEntityTon key={ tx.hash } hash={ tx.hash }/>;
|
||||
}
|
||||
|
||||
return <TxEntity key={ tx.hash } hash={ tx.hash } icon={{ name: 'brands/tac' }}/>;
|
||||
})
|
||||
}
|
||||
</Box>
|
||||
</ItemRow>
|
||||
return <TxEntity key={ tx.hash } hash={ tx.hash } icon={{ name: 'brands/tac' }}/>;
|
||||
})
|
||||
}
|
||||
</Box>
|
||||
</ItemRow>
|
||||
) }
|
||||
|
||||
{ data.note && (
|
||||
<ItemRow label="Note">
|
||||
|
||||
@@ -22,6 +22,7 @@ const TacOperationStatus = ({ status, isLoading, noTooltip }: Props) => {
|
||||
|
||||
switch (status) {
|
||||
case tac.OperationType.ERROR:
|
||||
case tac.OperationType.INSUFFICIENT_FEE:
|
||||
return <StatusTag type="error" text={ text } loading={ isLoading }/>;
|
||||
case tac.OperationType.ROLLBACK:
|
||||
return (
|
||||
|
||||
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |