Merge branch 'marketplace-admin-api' into suggest-ideas-button
@@ -115,11 +115,58 @@ jobs:
|
||||
run: yarn --frozen-lockfile --ignore-optional
|
||||
|
||||
- name: Run Jest
|
||||
run: yarn test:jest
|
||||
run: yarn test:jest --onlyChanged=${{ github.event_name == 'pull_request' }} --passWithNoTests
|
||||
|
||||
pw_affected_tests:
|
||||
name: Resolve affected Playwright tests
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ code_quality, envs_validation ]
|
||||
if: github.event_name == 'pull_request'
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.11.0
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Cache node_modules
|
||||
uses: actions/cache@v4
|
||||
id: cache-node-modules
|
||||
with:
|
||||
path: |
|
||||
node_modules
|
||||
key: node_modules-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
|
||||
- name: Install dependencies
|
||||
if: steps.cache-node-modules.outputs.cache-hit != 'true'
|
||||
run: yarn --frozen-lockfile --ignore-optional
|
||||
|
||||
- name: Install script dependencies
|
||||
run: cd ./deploy/tools/affected-tests && yarn --frozen-lockfile
|
||||
|
||||
- name: Run script
|
||||
run: yarn test:pw:detect-affected
|
||||
|
||||
- name: Upload result file
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: playwright-affected-tests
|
||||
path: ./playwright/affected-tests.txt
|
||||
retention-days: 3
|
||||
|
||||
pw_tests:
|
||||
name: 'Playwright tests / Project: ${{ matrix.project }}'
|
||||
needs: [ code_quality, envs_validation ]
|
||||
needs: [ code_quality, envs_validation, pw_affected_tests ]
|
||||
if: |
|
||||
always() &&
|
||||
needs.code_quality.result == 'success' &&
|
||||
needs.envs_validation.result == 'success' &&
|
||||
(needs.pw_affected_tests.result == 'success' || needs.pw_affected_tests.result == 'skipped')
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: mcr.microsoft.com/playwright:v1.41.1-focal
|
||||
@@ -156,8 +203,15 @@ jobs:
|
||||
if: steps.cache-node-modules.outputs.cache-hit != 'true'
|
||||
run: yarn --frozen-lockfile --ignore-optional
|
||||
|
||||
- name: Download affected tests list
|
||||
if: ${{ needs.pw_affected_tests.result == 'success' }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: playwright-affected-tests
|
||||
path: ./playwright
|
||||
|
||||
- name: Run PlayWright
|
||||
run: yarn test:pw:ci
|
||||
run: yarn test:pw:ci --affected=${{ github.event_name == 'pull_request' }} --pass-with-no-tests
|
||||
env:
|
||||
HOME: /root
|
||||
PW_PROJECT: ${{ matrix.project }}
|
||||
|
||||
@@ -51,5 +51,6 @@ yarn-error.log*
|
||||
/playwright/.cache/
|
||||
/playwright/.browser/
|
||||
/playwright/envs.js
|
||||
/playwright/affected-tests.txt
|
||||
|
||||
**.dec**
|
||||
@@ -155,6 +155,27 @@
|
||||
"instanceLimit": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"command": "yarn test:pw:detect-affected",
|
||||
"problemMatcher": [],
|
||||
"label": "pw: detect affected",
|
||||
"detail": "detect PW tests affected by changes in current branch",
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared",
|
||||
"focus": true,
|
||||
"close": false,
|
||||
"revealProblems": "onProblem",
|
||||
},
|
||||
"icon": {
|
||||
"color": "terminal.ansiBlue",
|
||||
"id": "diff"
|
||||
},
|
||||
"runOptions": {
|
||||
"instanceLimit": 1
|
||||
},
|
||||
},
|
||||
|
||||
// JEST TESTS
|
||||
{
|
||||
@@ -305,6 +326,7 @@
|
||||
"options": [
|
||||
"",
|
||||
"--update-snapshots",
|
||||
"--update-snapshots --affected",
|
||||
"--ui",
|
||||
],
|
||||
"default": ""
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { Feature } from './types';
|
||||
import { SUPPORTED_AD_BANNER_PROVIDERS } from 'types/client/adProviders';
|
||||
import { SUPPORTED_AD_TEXT_PROVIDERS } from 'types/client/adProviders';
|
||||
import type { AdTextProviders } from 'types/client/adProviders';
|
||||
|
||||
import { getEnvValue } from '../utils';
|
||||
|
||||
const provider: AdTextProviders = (() => {
|
||||
const envValue = getEnvValue('NEXT_PUBLIC_AD_TEXT_PROVIDER') as AdTextProviders;
|
||||
return envValue && SUPPORTED_AD_BANNER_PROVIDERS.includes(envValue) ? envValue : 'coinzilla';
|
||||
return envValue && SUPPORTED_AD_TEXT_PROVIDERS.includes(envValue) ? envValue : 'coinzilla';
|
||||
})();
|
||||
|
||||
const title = 'Text ads';
|
||||
|
||||
@@ -13,7 +13,7 @@ export { default as marketplace } from './marketplace';
|
||||
export { default as mixpanel } from './mixpanel';
|
||||
export { default as nameService } from './nameService';
|
||||
export { default as restApiDocs } from './restApiDocs';
|
||||
export { default as optimisticRollup } from './optimisticRollup';
|
||||
export { default as rollup } from './rollup';
|
||||
export { default as safe } from './safe';
|
||||
export { default as sentry } from './sentry';
|
||||
export { default as sol2uml } from './sol2uml';
|
||||
@@ -23,4 +23,3 @@ export { default as txInterpretation } from './txInterpretation';
|
||||
export { default as userOps } from './userOps';
|
||||
export { default as verifiedTokens } from './verifiedTokens';
|
||||
export { default as web3Wallet } from './web3Wallet';
|
||||
export { default as zkEvmRollup } from './zkEvmRollup';
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import type { Feature } from './types';
|
||||
|
||||
import { getEnvValue } from '../utils';
|
||||
|
||||
const title = 'Rollup (L2) chain';
|
||||
|
||||
const config: Feature<{ L1BaseUrl: string; withdrawalUrl: string }> = (() => {
|
||||
const L1BaseUrl = getEnvValue('NEXT_PUBLIC_L1_BASE_URL');
|
||||
const withdrawalUrl = getEnvValue('NEXT_PUBLIC_OPTIMISTIC_L2_WITHDRAWAL_URL');
|
||||
|
||||
if (
|
||||
getEnvValue('NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK') === 'true' &&
|
||||
L1BaseUrl &&
|
||||
withdrawalUrl
|
||||
) {
|
||||
return Object.freeze({
|
||||
title,
|
||||
isEnabled: true,
|
||||
L1BaseUrl,
|
||||
withdrawalUrl,
|
||||
});
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
title,
|
||||
isEnabled: false,
|
||||
});
|
||||
})();
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { Feature } from './types';
|
||||
import type { RollupType } from 'types/client/rollup';
|
||||
import { ROLLUP_TYPES } from 'types/client/rollup';
|
||||
|
||||
import { getEnvValue } from '../utils';
|
||||
|
||||
const type = (() => {
|
||||
const envValue = getEnvValue('NEXT_PUBLIC_ROLLUP_TYPE');
|
||||
return ROLLUP_TYPES.find((type) => type === envValue);
|
||||
})();
|
||||
|
||||
const L1BaseUrl = getEnvValue('NEXT_PUBLIC_ROLLUP_L1_BASE_URL');
|
||||
const L2WithdrawalUrl = getEnvValue('NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL');
|
||||
|
||||
const title = 'Rollup (L2) chain';
|
||||
|
||||
const config: Feature<{ type: RollupType; L1BaseUrl: string; L2WithdrawalUrl?: string }> = (() => {
|
||||
|
||||
if (type && L1BaseUrl) {
|
||||
return Object.freeze({
|
||||
title,
|
||||
isEnabled: true,
|
||||
type,
|
||||
L1BaseUrl,
|
||||
L2WithdrawalUrl,
|
||||
});
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
title,
|
||||
isEnabled: false,
|
||||
});
|
||||
})();
|
||||
|
||||
export default config;
|
||||
@@ -1,25 +0,0 @@
|
||||
import type { Feature } from './types';
|
||||
|
||||
import { getEnvValue } from '../utils';
|
||||
|
||||
const title = 'ZkEVM rollup (L2) chain';
|
||||
|
||||
const config: Feature<{ L1BaseUrl: string; withdrawalUrl?: string }> = (() => {
|
||||
const L1BaseUrl = getEnvValue('NEXT_PUBLIC_L1_BASE_URL');
|
||||
const isZkEvm = getEnvValue('NEXT_PUBLIC_IS_ZKEVM_L2_NETWORK') === 'true';
|
||||
|
||||
if (isZkEvm && L1BaseUrl) {
|
||||
return Object.freeze({
|
||||
title,
|
||||
isEnabled: true,
|
||||
L1BaseUrl,
|
||||
});
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
title,
|
||||
isEnabled: false,
|
||||
});
|
||||
})();
|
||||
|
||||
export default config;
|
||||
@@ -43,6 +43,7 @@ NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
|
||||
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
|
||||
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com
|
||||
NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout
|
||||
NEXT_PUBLIC_AD_BANNER_PROVIDER=hype
|
||||
|
||||
#meta
|
||||
NEXT_PUBLIC_OG_IMAGE_URL=https://github.com/blockscout/frontend-configs/blob/main/configs/og-images/eth.jpg?raw=true
|
||||
|
||||
@@ -44,8 +44,6 @@ NEXT_PUBLIC_APP_INSTANCE=jest
|
||||
NEXT_PUBLIC_APP_ENV=testing
|
||||
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://localhost:3000/marketplace-config.json
|
||||
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://localhost:3000/marketplace-submit-form
|
||||
NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK=false
|
||||
NEXT_PUBLIC_IS_ZKEVM_L2_NETWORK=false
|
||||
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
|
||||
NEXT_PUBLIC_AUTH_URL=http://localhost:3100
|
||||
NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout
|
||||
|
||||
@@ -47,6 +47,6 @@ NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout
|
||||
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/base-goerli.json
|
||||
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C
|
||||
NEXT_PUBLIC_STATS_API_HOST=https://stats-optimism-goerli.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK=true
|
||||
NEXT_PUBLIC_L1_BASE_URL=https://blockscout-main.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_OPTIMISTIC_L2_WITHDRAWAL_URL=https://app.optimism.io/bridge/withdraw
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=optimistic
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://blockscout-main.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://app.optimism.io/bridge/withdraw
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# Set of ENVs for zkevm (dev only)
|
||||
# https://eth.blockscout.com/
|
||||
|
||||
# app configuration
|
||||
NEXT_PUBLIC_APP_PROTOCOL=http
|
||||
NEXT_PUBLIC_APP_HOST=localhost
|
||||
NEXT_PUBLIC_APP_PORT=3000
|
||||
|
||||
# blockchain parameters
|
||||
NEXT_PUBLIC_NETWORK_NAME='OP Goerli'
|
||||
NEXT_PUBLIC_NETWORK_SHORT_NAME='OP Goerli'
|
||||
NEXT_PUBLIC_NETWORK_ID=420
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
|
||||
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
|
||||
NEXT_PUBLIC_NETWORK_RPC_URL=https://goerli.optimism.io
|
||||
|
||||
# api configuration
|
||||
NEXT_PUBLIC_API_HOST=optimism-goerli.blockscout.com
|
||||
NEXT_PUBLIC_API_PORT=80
|
||||
NEXT_PUBLIC_API_PROTOCOL=http
|
||||
NEXT_PUBLIC_API_BASE_PATH=/
|
||||
|
||||
# ui config
|
||||
## homepage
|
||||
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
|
||||
## sidebar
|
||||
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/polygon-mainnet.json
|
||||
## footer
|
||||
## misc
|
||||
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Etherscan','baseUrl':'https://etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}]
|
||||
# app features
|
||||
NEXT_PUBLIC_APP_INSTANCE=local
|
||||
NEXT_PUBLIC_APP_ENV=development
|
||||
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d
|
||||
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
|
||||
# NEXT_PUBLIC_AUTH_URL=http://localhost:3000
|
||||
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws
|
||||
NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout
|
||||
NEXT_PUBLIC_STATS_API_HOST=https://stats-eth-main.k8s.blockscout.com
|
||||
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
|
||||
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
|
||||
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com
|
||||
# rollup
|
||||
NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK=true
|
||||
NEXT_PUBLIC_OPTIMISTIC_L2_WITHDRAWAL_URL=https://app.optimism.io/bridge/withdraw
|
||||
NEXT_PUBLIC_L1_BASE_URL=https://eth-goerli.blockscout.com/
|
||||
@@ -41,8 +41,6 @@ NEXT_PUBLIC_APP_ENV=testing
|
||||
NEXT_PUBLIC_APP_INSTANCE=pw
|
||||
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://localhost:3000/marketplace-config.json
|
||||
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://localhost:3000/marketplace-submit-form
|
||||
NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK=false
|
||||
NEXT_PUBLIC_IS_ZKEVM_L2_NETWORK=false
|
||||
NEXT_PUBLIC_AD_BANNER_PROVIDER=slise
|
||||
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
|
||||
NEXT_PUBLIC_AUTH_URL=http://localhost:3100
|
||||
|
||||
@@ -47,5 +47,5 @@ NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
|
||||
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
|
||||
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com
|
||||
# rollup
|
||||
NEXT_PUBLIC_IS_ZKEVM_L2_NETWORK=true
|
||||
NEXT_PUBLIC_L1_BASE_URL=https://polygon.blockscout.com
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=zkEvm
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://polygon.blockscout.com
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/node_modules
|
||||
@@ -0,0 +1,206 @@
|
||||
/* eslint-disable no-console */
|
||||
const { execSync } = require('child_process');
|
||||
const dependencyTree = require('dependency-tree');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const ROOT_DIR = path.resolve(__dirname, '../../../');
|
||||
|
||||
const TARGET_FILE = path.resolve(ROOT_DIR, './playwright/affected-tests.txt');
|
||||
|
||||
const NON_EXISTENT_DEPS = [];
|
||||
|
||||
const DIRECTORIES_WITH_TESTS = [
|
||||
path.resolve(ROOT_DIR, './ui'),
|
||||
];
|
||||
|
||||
function getAllPwFilesInDirectory(directory) {
|
||||
const files = fs.readdirSync(directory, { recursive: true });
|
||||
return files
|
||||
.filter((file) => file.endsWith('.pw.tsx'))
|
||||
.map((file) => path.join(directory, file));
|
||||
}
|
||||
|
||||
function getFileDeps(filename, changedNpmModules) {
|
||||
return dependencyTree.toList({
|
||||
filename,
|
||||
directory: ROOT_DIR,
|
||||
filter: (path) => {
|
||||
if (path.indexOf('node_modules') === -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (changedNpmModules.some((module) => path.startsWith(module))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
tsConfig: path.resolve(ROOT_DIR, './tsconfig.json'),
|
||||
nonExistent: NON_EXISTENT_DEPS,
|
||||
});
|
||||
}
|
||||
|
||||
async function getChangedFiles() {
|
||||
const command = process.env.CI ?
|
||||
`git diff --name-only origin/${ process.env.GITHUB_BASE_REF } ${ process.env.GITHUB_SHA } -- ${ ROOT_DIR }` :
|
||||
`git diff --name-only main $(git branch --show-current) -- ${ ROOT_DIR }`;
|
||||
|
||||
console.log('Executing command: ', command);
|
||||
const files = execSync(command)
|
||||
.toString()
|
||||
.trim()
|
||||
.split('\n')
|
||||
.filter(Boolean);
|
||||
|
||||
return files.map((file) => path.join(ROOT_DIR, file));
|
||||
}
|
||||
|
||||
function checkChangesInChakraTheme(changedFiles) {
|
||||
const themeDir = path.resolve(ROOT_DIR, './theme');
|
||||
return changedFiles.some((file) => file.startsWith(themeDir));
|
||||
}
|
||||
|
||||
function checkChangesInSvgSprite(changedFiles) {
|
||||
const iconDir = path.resolve(ROOT_DIR, './icons');
|
||||
const areIconsChanged = changedFiles.some((file) => file.startsWith(iconDir));
|
||||
|
||||
if (!areIconsChanged) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const svgNamesFile = path.resolve(ROOT_DIR, './public/icons/name.d.ts');
|
||||
const areSvgNamesChanged = changedFiles.some((file) => file === svgNamesFile);
|
||||
|
||||
if (!areSvgNamesChanged) {
|
||||
// If only the icons have changed and not the names in the SVG file, we will need to run all tests.
|
||||
// This is because we cannot correctly identify the test files that depend on these changes.
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the icon names have changed, then there should be changes in the components that use them.
|
||||
// Otherwise, typescript would complain about that.
|
||||
return false;
|
||||
}
|
||||
|
||||
function createTargetFile(content) {
|
||||
fs.writeFileSync(TARGET_FILE, content);
|
||||
}
|
||||
|
||||
function getPackageJsonUpdatedProps(packageJsonFile) {
|
||||
const command = process.env.CI ?
|
||||
`git diff --unified=0 origin/${ process.env.GITHUB_BASE_REF } ${ process.env.GITHUB_SHA } -- ${ packageJsonFile }` :
|
||||
`git diff --unified=0 main $(git branch --show-current) -- ${ packageJsonFile }`;
|
||||
|
||||
console.log('Executing command: ', command);
|
||||
const changedLines = execSync(command)
|
||||
.toString()
|
||||
.trim()
|
||||
.split('\n')
|
||||
.filter(Boolean)
|
||||
.filter((line) => line.startsWith('+ ') || line.startsWith('- '));
|
||||
|
||||
const changedProps = [ ...new Set(
|
||||
changedLines
|
||||
.map((line) => line.replaceAll(' ', '').replaceAll('+', '').replaceAll('-', ''))
|
||||
.map((line) => line.split(':')[0].replaceAll('"', '')),
|
||||
) ];
|
||||
|
||||
return changedProps;
|
||||
}
|
||||
|
||||
function getUpdatedNpmModules(changedFiles) {
|
||||
const packageJsonFile = path.resolve(ROOT_DIR, './package.json');
|
||||
|
||||
if (!changedFiles.includes(packageJsonFile)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const packageJsonContent = JSON.parse(fs.readFileSync(packageJsonFile, 'utf-8'));
|
||||
const usedNpmModules = [
|
||||
...Object.keys(packageJsonContent.dependencies || {}),
|
||||
...Object.keys(packageJsonContent.devDependencies || {}),
|
||||
];
|
||||
const updatedProps = getPackageJsonUpdatedProps(packageJsonFile);
|
||||
|
||||
return updatedProps.filter((prop) => usedNpmModules.includes(prop));
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
async function run() {
|
||||
// NOTES:
|
||||
// - The absence of TARGET_FILE implies that all tests should be run.
|
||||
// - The empty TARGET_FILE implies that no tests should be run.
|
||||
|
||||
const start = Date.now();
|
||||
|
||||
fs.unlink(TARGET_FILE, () => {});
|
||||
|
||||
const changedFiles = await getChangedFiles();
|
||||
|
||||
if (!changedFiles.length) {
|
||||
createTargetFile('');
|
||||
console.log('No changed files found. Exiting...');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Changed files in the branch: ', changedFiles);
|
||||
|
||||
if (checkChangesInChakraTheme(changedFiles)) {
|
||||
console.log('Changes in Chakra theme detected. It is advisable to run all test suites. Exiting...');
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkChangesInSvgSprite(changedFiles)) {
|
||||
console.log('There are some changes in the SVG sprite that cannot be linked to a specific component. It is advisable to run all test suites. Exiting...');
|
||||
return;
|
||||
}
|
||||
|
||||
let changedNpmModules = getUpdatedNpmModules(changedFiles);
|
||||
|
||||
if (!changedNpmModules) {
|
||||
console.log('Some error occurred while detecting changed NPM modules. It is advisable to run all test suites. Exiting...');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Changed NPM modules in the branch: ', changedNpmModules);
|
||||
|
||||
changedNpmModules = [
|
||||
...changedNpmModules,
|
||||
...changedNpmModules.map((module) => `@types/${ module }`), // there are some deps that are resolved to .d.ts files
|
||||
].map((module) => path.resolve(ROOT_DIR, `./node_modules/${ module }`));
|
||||
|
||||
const allTestFiles = DIRECTORIES_WITH_TESTS.reduce((acc, dir) => {
|
||||
return acc.concat(getAllPwFilesInDirectory(dir));
|
||||
}, []);
|
||||
|
||||
const isDepChanged = (dep) => changedFiles.includes(dep) || changedNpmModules.some((module) => dep.startsWith(module));
|
||||
|
||||
const testFilesToRun = allTestFiles
|
||||
.map((file) => ({ file, deps: getFileDeps(file, changedNpmModules) }))
|
||||
.filter(({ deps }) => deps.some(isDepChanged));
|
||||
const testFileNamesToRun = testFilesToRun.map(({ file }) => path.relative(ROOT_DIR, file));
|
||||
|
||||
if (!testFileNamesToRun.length) {
|
||||
createTargetFile('');
|
||||
console.log('No tests to run. Exiting...');
|
||||
return;
|
||||
}
|
||||
|
||||
createTargetFile(testFileNamesToRun.join('\n'));
|
||||
|
||||
const end = Date.now();
|
||||
|
||||
const testFilesToRunWithFilteredDeps = testFilesToRun.map(({ file, deps }) => ({
|
||||
file,
|
||||
deps: deps.filter(isDepChanged),
|
||||
}));
|
||||
|
||||
console.log('Total time: ', ((end - start) / 1_000).toLocaleString());
|
||||
console.log('Total test to run: ', testFileNamesToRun.length);
|
||||
console.log('Tests to run with changed deps: ', testFilesToRunWithFilteredDeps);
|
||||
console.log('Non existent deps: ', NON_EXISTENT_DEPS);
|
||||
}
|
||||
|
||||
run();
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "affected-tests",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"author": "Vasilii (tom) Goriunov <[email protected]>",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dependency-tree": "10.0.9"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,716 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@babel/parser@^7.21.8":
|
||||
version "7.23.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.9.tgz#7b903b6149b0f8fa7ad564af646c4c38a77fc44b"
|
||||
integrity sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==
|
||||
|
||||
"@dependents/detective-less@^4.1.0":
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@dependents/detective-less/-/detective-less-4.1.0.tgz#4a979ee7a6a79eb33602862d6a1263e30f98002e"
|
||||
integrity sha512-KrkT6qO5NxqNfy68sBl6CTSoJ4SNDIS5iQArkibhlbGU4LaDukZ3q2HIkh8aUKDio6o4itU4xDR7t82Y2eP1Bg==
|
||||
dependencies:
|
||||
gonzales-pe "^4.3.0"
|
||||
node-source-walk "^6.0.1"
|
||||
|
||||
"@nodelib/[email protected]":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
||||
integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
|
||||
dependencies:
|
||||
"@nodelib/fs.stat" "2.0.5"
|
||||
run-parallel "^1.1.9"
|
||||
|
||||
"@nodelib/[email protected]", "@nodelib/fs.stat@^2.0.2":
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
|
||||
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
||||
|
||||
"@nodelib/fs.walk@^1.2.3":
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
|
||||
integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
|
||||
dependencies:
|
||||
"@nodelib/fs.scandir" "2.1.5"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@typescript-eslint/[email protected]":
|
||||
version "5.62.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f"
|
||||
integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==
|
||||
|
||||
"@typescript-eslint/typescript-estree@^5.59.5":
|
||||
version "5.62.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b"
|
||||
integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "5.62.0"
|
||||
"@typescript-eslint/visitor-keys" "5.62.0"
|
||||
debug "^4.3.4"
|
||||
globby "^11.1.0"
|
||||
is-glob "^4.0.3"
|
||||
semver "^7.3.7"
|
||||
tsutils "^3.21.0"
|
||||
|
||||
"@typescript-eslint/[email protected]":
|
||||
version "5.62.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e"
|
||||
integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "5.62.0"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
app-module-path@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/app-module-path/-/app-module-path-2.2.0.tgz#641aa55dfb7d6a6f0a8141c4b9c0aa50b6c24dd5"
|
||||
integrity sha512-gkco+qxENJV+8vFcDiiFhuoSvRXb2a/QPqpSoWhVz829VNJfOTnELbBmPmNKFxf3xdNnw4DWCkzkDaavcX/1YQ==
|
||||
|
||||
array-union@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
|
||||
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
|
||||
|
||||
ast-module-types@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ast-module-types/-/ast-module-types-5.0.0.tgz#32b2b05c56067ff38e95df66f11d6afd6c9ba16b"
|
||||
integrity sha512-JvqziE0Wc0rXQfma0HZC/aY7URXHFuZV84fJRtP8u+lhp0JYCNd5wJzVXP45t0PH0Mej3ynlzvdyITYIu0G4LQ==
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
braces@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
|
||||
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
|
||||
dependencies:
|
||||
fill-range "^7.0.1"
|
||||
|
||||
color-name@^1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
commander@^10.0.1:
|
||||
version "10.0.1"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06"
|
||||
integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
|
||||
|
||||
[email protected]:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
||||
|
||||
debug@^4.3.4:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
[email protected]:
|
||||
version "10.0.9"
|
||||
resolved "https://registry.yarnpkg.com/dependency-tree/-/dependency-tree-10.0.9.tgz#0c6c0dbeb0c5ec2cf83bf755f30e9cb12e7b4ac7"
|
||||
integrity sha512-dwc59FRIsht+HfnTVM0BCjJaEWxdq2YAvEDy4/Hn6CwS3CBWMtFnL3aZGAkQn3XCYxk/YcTDE4jX2Q7bFTwCjA==
|
||||
dependencies:
|
||||
commander "^10.0.1"
|
||||
filing-cabinet "^4.1.6"
|
||||
precinct "^11.0.5"
|
||||
typescript "^5.0.4"
|
||||
|
||||
detective-amd@^5.0.2:
|
||||
version "5.0.2"
|
||||
resolved "https://registry.yarnpkg.com/detective-amd/-/detective-amd-5.0.2.tgz#579900f301c160efe037a6377ec7e937434b2793"
|
||||
integrity sha512-XFd/VEQ76HSpym80zxM68ieB77unNuoMwopU2TFT/ErUk5n4KvUTwW4beafAVUugrjV48l4BmmR0rh2MglBaiA==
|
||||
dependencies:
|
||||
ast-module-types "^5.0.0"
|
||||
escodegen "^2.0.0"
|
||||
get-amd-module-type "^5.0.1"
|
||||
node-source-walk "^6.0.1"
|
||||
|
||||
detective-cjs@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/detective-cjs/-/detective-cjs-5.0.1.tgz#836ad51c6de4863efc7c419ec243694f760ff8b2"
|
||||
integrity sha512-6nTvAZtpomyz/2pmEmGX1sXNjaqgMplhQkskq2MLrar0ZAIkHMrDhLXkRiK2mvbu9wSWr0V5/IfiTrZqAQMrmQ==
|
||||
dependencies:
|
||||
ast-module-types "^5.0.0"
|
||||
node-source-walk "^6.0.0"
|
||||
|
||||
detective-es6@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/detective-es6/-/detective-es6-4.0.1.tgz#38d5d49a6d966e992ef8f2d9bffcfe861a58a88a"
|
||||
integrity sha512-k3Z5tB4LQ8UVHkuMrFOlvb3GgFWdJ9NqAa2YLUU/jTaWJIm+JJnEh4PsMc+6dfT223Y8ACKOaC0qcj7diIhBKw==
|
||||
dependencies:
|
||||
node-source-walk "^6.0.1"
|
||||
|
||||
detective-postcss@^6.1.3:
|
||||
version "6.1.3"
|
||||
resolved "https://registry.yarnpkg.com/detective-postcss/-/detective-postcss-6.1.3.tgz#51a2d4419327ad85d0af071c7054c79fafca7e73"
|
||||
integrity sha512-7BRVvE5pPEvk2ukUWNQ+H2XOq43xENWbH0LcdCE14mwgTBEAMoAx+Fc1rdp76SmyZ4Sp48HlV7VedUnP6GA1Tw==
|
||||
dependencies:
|
||||
is-url "^1.2.4"
|
||||
postcss "^8.4.23"
|
||||
postcss-values-parser "^6.0.2"
|
||||
|
||||
detective-sass@^5.0.3:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/detective-sass/-/detective-sass-5.0.3.tgz#63e54bc9b32f4bdbd9d5002308f9592a3d3a508f"
|
||||
integrity sha512-YsYT2WuA8YIafp2RVF5CEfGhhyIVdPzlwQgxSjK+TUm3JoHP+Tcorbk3SfG0cNZ7D7+cYWa0ZBcvOaR0O8+LlA==
|
||||
dependencies:
|
||||
gonzales-pe "^4.3.0"
|
||||
node-source-walk "^6.0.1"
|
||||
|
||||
detective-scss@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/detective-scss/-/detective-scss-4.0.3.tgz#79758baa0158f72bfc4481eb7e21cc3b5f1ea6eb"
|
||||
integrity sha512-VYI6cHcD0fLokwqqPFFtDQhhSnlFWvU614J42eY6G0s8c+MBhi9QAWycLwIOGxlmD8I/XvGSOUV1kIDhJ70ZPg==
|
||||
dependencies:
|
||||
gonzales-pe "^4.3.0"
|
||||
node-source-walk "^6.0.1"
|
||||
|
||||
detective-stylus@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/detective-stylus/-/detective-stylus-4.0.0.tgz#ce97b6499becdc291de7b3c11df8c352c1eee46e"
|
||||
integrity sha512-TfPotjhszKLgFBzBhTOxNHDsutIxx9GTWjrL5Wh7Qx/ydxKhwUrlSFeLIn+ZaHPF+h0siVBkAQSuy6CADyTxgQ==
|
||||
|
||||
detective-typescript@^11.1.0:
|
||||
version "11.1.0"
|
||||
resolved "https://registry.yarnpkg.com/detective-typescript/-/detective-typescript-11.1.0.tgz#2deea5364cae1f0d9d3688bc596e662b049438cc"
|
||||
integrity sha512-Mq8egjnW2NSCkzEb/Az15/JnBI/Ryyl6Po0Y+0mABTFvOS6DAyUGRZqz1nyhu4QJmWWe0zaGs/ITIBeWkvCkGw==
|
||||
dependencies:
|
||||
"@typescript-eslint/typescript-estree" "^5.59.5"
|
||||
ast-module-types "^5.0.0"
|
||||
node-source-walk "^6.0.1"
|
||||
typescript "^5.0.4"
|
||||
|
||||
dir-glob@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
|
||||
integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
|
||||
dependencies:
|
||||
path-type "^4.0.0"
|
||||
|
||||
enhanced-resolve@^5.14.1:
|
||||
version "5.15.0"
|
||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35"
|
||||
integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==
|
||||
dependencies:
|
||||
graceful-fs "^4.2.4"
|
||||
tapable "^2.2.0"
|
||||
|
||||
escodegen@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17"
|
||||
integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==
|
||||
dependencies:
|
||||
esprima "^4.0.1"
|
||||
estraverse "^5.2.0"
|
||||
esutils "^2.0.2"
|
||||
optionalDependencies:
|
||||
source-map "~0.6.1"
|
||||
|
||||
eslint-visitor-keys@^3.3.0:
|
||||
version "3.4.3"
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
|
||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||
|
||||
esprima@^4.0.0, esprima@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
|
||||
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
|
||||
|
||||
estraverse@^5.2.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
|
||||
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
||||
|
||||
esutils@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
|
||||
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
|
||||
|
||||
fast-glob@^3.2.9:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
|
||||
integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
|
||||
dependencies:
|
||||
"@nodelib/fs.stat" "^2.0.2"
|
||||
"@nodelib/fs.walk" "^1.2.3"
|
||||
glob-parent "^5.1.2"
|
||||
merge2 "^1.3.0"
|
||||
micromatch "^4.0.4"
|
||||
|
||||
fastq@^1.6.0:
|
||||
version "1.17.0"
|
||||
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.0.tgz#ca5e1a90b5e68f97fc8b61330d5819b82f5fab03"
|
||||
integrity sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==
|
||||
dependencies:
|
||||
reusify "^1.0.4"
|
||||
|
||||
filing-cabinet@^4.1.6:
|
||||
version "4.1.6"
|
||||
resolved "https://registry.yarnpkg.com/filing-cabinet/-/filing-cabinet-4.1.6.tgz#8d6d12cf3a84365bbd94e1cbf07d71c113420dd2"
|
||||
integrity sha512-C+HZbuQTER36sKzGtUhrAPAoK6+/PrrUhYDBQEh3kBRdsyEhkLbp1ML8S0+6e6gCUrUlid+XmubxJrhvL2g/Zw==
|
||||
dependencies:
|
||||
app-module-path "^2.2.0"
|
||||
commander "^10.0.1"
|
||||
enhanced-resolve "^5.14.1"
|
||||
is-relative-path "^1.0.2"
|
||||
module-definition "^5.0.1"
|
||||
module-lookup-amd "^8.0.5"
|
||||
resolve "^1.22.3"
|
||||
resolve-dependency-path "^3.0.2"
|
||||
sass-lookup "^5.0.1"
|
||||
stylus-lookup "^5.0.1"
|
||||
tsconfig-paths "^4.2.0"
|
||||
typescript "^5.0.4"
|
||||
|
||||
fill-range@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
|
||||
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
|
||||
dependencies:
|
||||
to-regex-range "^5.0.1"
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||
|
||||
function-bind@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
|
||||
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
|
||||
|
||||
get-amd-module-type@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/get-amd-module-type/-/get-amd-module-type-5.0.1.tgz#bef38ea3674e1aa1bda9c59c8b0da598582f73f2"
|
||||
integrity sha512-jb65zDeHyDjFR1loOVk0HQGM5WNwoGB8aLWy3LKCieMKol0/ProHkhO2X1JxojuN10vbz1qNn09MJ7tNp7qMzw==
|
||||
dependencies:
|
||||
ast-module-types "^5.0.0"
|
||||
node-source-walk "^6.0.1"
|
||||
|
||||
get-own-enumerable-property-symbols@^3.0.0:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
|
||||
integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==
|
||||
|
||||
glob-parent@^5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
|
||||
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
|
||||
dependencies:
|
||||
is-glob "^4.0.1"
|
||||
|
||||
glob@^7.2.3:
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
|
||||
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.1.1"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
globby@^11.1.0:
|
||||
version "11.1.0"
|
||||
resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
|
||||
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
|
||||
dependencies:
|
||||
array-union "^2.1.0"
|
||||
dir-glob "^3.0.1"
|
||||
fast-glob "^3.2.9"
|
||||
ignore "^5.2.0"
|
||||
merge2 "^1.4.1"
|
||||
slash "^3.0.0"
|
||||
|
||||
gonzales-pe@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.3.0.tgz#fe9dec5f3c557eead09ff868c65826be54d067b3"
|
||||
integrity sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==
|
||||
dependencies:
|
||||
minimist "^1.2.5"
|
||||
|
||||
graceful-fs@^4.2.4:
|
||||
version "4.2.11"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
|
||||
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
||||
|
||||
hasown@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c"
|
||||
integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==
|
||||
dependencies:
|
||||
function-bind "^1.1.2"
|
||||
|
||||
ignore@^5.2.0:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
|
||||
integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||
integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
|
||||
dependencies:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
is-core-module@^2.13.0:
|
||||
version "2.13.1"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384"
|
||||
integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
|
||||
dependencies:
|
||||
hasown "^2.0.0"
|
||||
|
||||
is-extglob@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
|
||||
|
||||
is-glob@^4.0.1, is-glob@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
|
||||
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-number@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
||||
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
||||
|
||||
is-obj@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
|
||||
integrity sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==
|
||||
|
||||
is-regexp@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
|
||||
integrity sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==
|
||||
|
||||
is-relative-path@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-relative-path/-/is-relative-path-1.0.2.tgz#091b46a0d67c1ed0fe85f1f8cfdde006bb251d46"
|
||||
integrity sha512-i1h+y50g+0hRbBD+dbnInl3JlJ702aar58snAeX+MxBAPvzXGej7sYoPMhlnykabt0ZzCJNBEyzMlekuQZN7fA==
|
||||
|
||||
is-url-superb@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-url-superb/-/is-url-superb-4.0.0.tgz#b54d1d2499bb16792748ac967aa3ecb41a33a8c2"
|
||||
integrity sha512-GI+WjezhPPcbM+tqE9LnmsY5qqjwHzTvjJ36wxYX5ujNXefSUJ/T17r5bqDV8yLhcgB59KTPNOc9O9cmHTPWsA==
|
||||
|
||||
is-url@^1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52"
|
||||
integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==
|
||||
|
||||
json5@^2.2.2:
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
|
||||
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
|
||||
|
||||
lru-cache@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
|
||||
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
merge2@^1.3.0, merge2@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
||||
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
||||
|
||||
micromatch@^4.0.4:
|
||||
version "4.0.5"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
|
||||
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
|
||||
dependencies:
|
||||
braces "^3.0.2"
|
||||
picomatch "^2.3.1"
|
||||
|
||||
minimatch@^3.1.1:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimist@^1.2.5, minimist@^1.2.6:
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
|
||||
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
|
||||
|
||||
module-definition@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/module-definition/-/module-definition-5.0.1.tgz#62d1194e5d5ea6176b7dc7730f818f466aefa32f"
|
||||
integrity sha512-kvw3B4G19IXk+BOXnYq/D/VeO9qfHaapMeuS7w7sNUqmGaA6hywdFHMi+VWeR9wUScXM7XjoryTffCZ5B0/8IA==
|
||||
dependencies:
|
||||
ast-module-types "^5.0.0"
|
||||
node-source-walk "^6.0.1"
|
||||
|
||||
module-lookup-amd@^8.0.5:
|
||||
version "8.0.5"
|
||||
resolved "https://registry.yarnpkg.com/module-lookup-amd/-/module-lookup-amd-8.0.5.tgz#aaeea41979105b49339380ca3f7d573db78c32a5"
|
||||
integrity sha512-vc3rYLjDo5Frjox8NZpiyLXsNWJ5BWshztc/5KSOMzpg9k5cHH652YsJ7VKKmtM4SvaxuE9RkrYGhiSjH3Ehow==
|
||||
dependencies:
|
||||
commander "^10.0.1"
|
||||
glob "^7.2.3"
|
||||
requirejs "^2.3.6"
|
||||
requirejs-config-file "^4.0.0"
|
||||
|
||||
[email protected]:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
nanoid@^3.3.7:
|
||||
version "3.3.7"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
|
||||
integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
|
||||
|
||||
node-source-walk@^6.0.0, node-source-walk@^6.0.1, node-source-walk@^6.0.2:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/node-source-walk/-/node-source-walk-6.0.2.tgz#ba81bc4bc0f6f05559b084bea10be84c3f87f211"
|
||||
integrity sha512-jn9vOIK/nfqoFCcpK89/VCVaLg1IHE6UVfDOzvqmANaJ/rWCTEdH8RZ1V278nv2jr36BJdyQXIAavBLXpzdlag==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.21.8"
|
||||
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
path-is-absolute@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
|
||||
|
||||
path-parse@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
||||
|
||||
path-type@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
|
||||
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
||||
|
||||
picocolors@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
||||
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
||||
|
||||
picomatch@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
postcss-values-parser@^6.0.2:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-6.0.2.tgz#636edc5b86c953896f1bb0d7a7a6615df00fb76f"
|
||||
integrity sha512-YLJpK0N1brcNJrs9WatuJFtHaV9q5aAOj+S4DI5S7jgHlRfm0PIbDCAFRYMQD5SHq7Fy6xsDhyutgS0QOAs0qw==
|
||||
dependencies:
|
||||
color-name "^1.1.4"
|
||||
is-url-superb "^4.0.0"
|
||||
quote-unquote "^1.0.0"
|
||||
|
||||
postcss@^8.4.23:
|
||||
version "8.4.33"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.33.tgz#1378e859c9f69bf6f638b990a0212f43e2aaa742"
|
||||
integrity sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==
|
||||
dependencies:
|
||||
nanoid "^3.3.7"
|
||||
picocolors "^1.0.0"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
precinct@^11.0.5:
|
||||
version "11.0.5"
|
||||
resolved "https://registry.yarnpkg.com/precinct/-/precinct-11.0.5.tgz#3e15b3486670806f18addb54b8533e23596399ff"
|
||||
integrity sha512-oHSWLC8cL/0znFhvln26D14KfCQFFn4KOLSw6hmLhd+LQ2SKt9Ljm89but76Pc7flM9Ty1TnXyrA2u16MfRV3w==
|
||||
dependencies:
|
||||
"@dependents/detective-less" "^4.1.0"
|
||||
commander "^10.0.1"
|
||||
detective-amd "^5.0.2"
|
||||
detective-cjs "^5.0.1"
|
||||
detective-es6 "^4.0.1"
|
||||
detective-postcss "^6.1.3"
|
||||
detective-sass "^5.0.3"
|
||||
detective-scss "^4.0.3"
|
||||
detective-stylus "^4.0.0"
|
||||
detective-typescript "^11.1.0"
|
||||
module-definition "^5.0.1"
|
||||
node-source-walk "^6.0.2"
|
||||
|
||||
queue-microtask@^1.2.2:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
||||
|
||||
quote-unquote@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/quote-unquote/-/quote-unquote-1.0.0.tgz#67a9a77148effeaf81a4d428404a710baaac8a0b"
|
||||
integrity sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg==
|
||||
|
||||
requirejs-config-file@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/requirejs-config-file/-/requirejs-config-file-4.0.0.tgz#4244da5dd1f59874038cc1091d078d620abb6ebc"
|
||||
integrity sha512-jnIre8cbWOyvr8a5F2KuqBnY+SDA4NXr/hzEZJG79Mxm2WiFQz2dzhC8ibtPJS7zkmBEl1mxSwp5HhC1W4qpxw==
|
||||
dependencies:
|
||||
esprima "^4.0.0"
|
||||
stringify-object "^3.2.1"
|
||||
|
||||
requirejs@^2.3.6:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9"
|
||||
integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==
|
||||
|
||||
resolve-dependency-path@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/resolve-dependency-path/-/resolve-dependency-path-3.0.2.tgz#012816717bcbe8b846835da11af9d2beb5acef50"
|
||||
integrity sha512-Tz7zfjhLfsvR39ADOSk9us4421J/1ztVBo4rWUkF38hgHK5m0OCZ3NxFVpqHRkjctnwVa15igEUHFJp8MCS7vA==
|
||||
|
||||
resolve@^1.22.3:
|
||||
version "1.22.8"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
|
||||
integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
|
||||
dependencies:
|
||||
is-core-module "^2.13.0"
|
||||
path-parse "^1.0.7"
|
||||
supports-preserve-symlinks-flag "^1.0.0"
|
||||
|
||||
reusify@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
||||
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
|
||||
|
||||
run-parallel@^1.1.9:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
|
||||
integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
|
||||
dependencies:
|
||||
queue-microtask "^1.2.2"
|
||||
|
||||
sass-lookup@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/sass-lookup/-/sass-lookup-5.0.1.tgz#1f01d7ff21e09d8c9dcf8d05b3fca28f2f96e6ed"
|
||||
integrity sha512-t0X5PaizPc2H4+rCwszAqHZRtr4bugo4pgiCvrBFvIX0XFxnr29g77LJcpyj9A0DcKf7gXMLcgvRjsonYI6x4g==
|
||||
dependencies:
|
||||
commander "^10.0.1"
|
||||
|
||||
semver@^7.3.7:
|
||||
version "7.5.4"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
|
||||
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
slash@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
||||
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
||||
|
||||
source-map-js@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||
|
||||
source-map@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
stringify-object@^3.2.1:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629"
|
||||
integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==
|
||||
dependencies:
|
||||
get-own-enumerable-property-symbols "^3.0.0"
|
||||
is-obj "^1.0.1"
|
||||
is-regexp "^1.0.0"
|
||||
|
||||
strip-bom@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
|
||||
integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==
|
||||
|
||||
stylus-lookup@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/stylus-lookup/-/stylus-lookup-5.0.1.tgz#3c4d116c3b1e8e1a8169c0d9cd20e608595560f4"
|
||||
integrity sha512-tLtJEd5AGvnVy4f9UHQMw4bkJJtaAcmo54N+ovQBjDY3DuWyK9Eltxzr5+KG0q4ew6v2EHyuWWNnHeiw/Eo7rQ==
|
||||
dependencies:
|
||||
commander "^10.0.1"
|
||||
|
||||
supports-preserve-symlinks-flag@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
|
||||
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
|
||||
|
||||
tapable@^2.2.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
|
||||
integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
|
||||
|
||||
to-regex-range@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
|
||||
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
|
||||
dependencies:
|
||||
is-number "^7.0.0"
|
||||
|
||||
tsconfig-paths@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c"
|
||||
integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==
|
||||
dependencies:
|
||||
json5 "^2.2.2"
|
||||
minimist "^1.2.6"
|
||||
strip-bom "^3.0.0"
|
||||
|
||||
tslib@^1.8.1:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tsutils@^3.21.0:
|
||||
version "3.21.0"
|
||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
|
||||
integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
|
||||
dependencies:
|
||||
tslib "^1.8.1"
|
||||
|
||||
typescript@^5.0.4:
|
||||
version "5.3.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37"
|
||||
integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
|
||||
|
||||
yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
||||
@@ -15,6 +15,7 @@ import type { ContractCodeIde } from '../../../types/client/contract';
|
||||
import type { MarketplaceAppOverview } from '../../../types/client/marketplace';
|
||||
import { NAVIGATION_LINK_IDS } from '../../../types/client/navigation-items';
|
||||
import type { NavItemExternal, NavigationLinkId } from '../../../types/client/navigation-items';
|
||||
import { ROLLUP_TYPES } from '../../../types/client/rollup';
|
||||
import type { BridgedTokenChain, TokenBridge } from '../../../types/client/token';
|
||||
import { PROVIDERS as TX_INTERPRETATION_PROVIDERS } from '../../../types/client/txInterpretation';
|
||||
import type { WalletType } from '../../../types/client/wallets';
|
||||
@@ -123,23 +124,20 @@ const beaconChainSchema = yup
|
||||
const rollupSchema = yup
|
||||
.object()
|
||||
.shape({
|
||||
NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK: yup.boolean(),
|
||||
NEXT_PUBLIC_OPTIMISTIC_L2_WITHDRAWAL_URL: yup
|
||||
NEXT_PUBLIC_ROLLUP_TYPE: yup.string().oneOf(ROLLUP_TYPES),
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL: yup
|
||||
.string()
|
||||
.when('NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK', {
|
||||
.when('NEXT_PUBLIC_ROLLUP_TYPE', {
|
||||
is: (value: string) => value,
|
||||
then: (schema) => schema.test(urlTest).required(),
|
||||
// eslint-disable-next-line max-len
|
||||
otherwise: (schema) => schema.max(-1, 'NEXT_PUBLIC_OPTIMISTIC_L2_WITHDRAWAL_URL cannot not be used if NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK is not set to "true"'),
|
||||
otherwise: (schema) => schema.max(-1, 'NEXT_PUBLIC_ROLLUP_L1_BASE_URL cannot not be used if NEXT_PUBLIC_ROLLUP_TYPE is not defined'),
|
||||
}),
|
||||
NEXT_PUBLIC_IS_ZKEVM_L2_NETWORK: yup.boolean(),
|
||||
NEXT_PUBLIC_L1_BASE_URL: yup
|
||||
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL: yup
|
||||
.string()
|
||||
.when([ 'NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK', 'NEXT_PUBLIC_IS_ZKEVM_L2_NETWORK' ], {
|
||||
is: (isOptimistic?: boolean, isZk?: boolean) => isOptimistic || isZk,
|
||||
.when('NEXT_PUBLIC_ROLLUP_TYPE', {
|
||||
is: (value: string) => value === 'optimistic',
|
||||
then: (schema) => schema.test(urlTest).required(),
|
||||
// eslint-disable-next-line max-len
|
||||
otherwise: (schema) => schema.max(-1, 'NEXT_PUBLIC_L1_BASE_URL cannot not be used if NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK or NEXT_PUBLIC_IS_ZKEVM_L2_NETWORK is not set to "true"'),
|
||||
otherwise: (schema) => schema.max(-1, 'NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL cannot not be used if NEXT_PUBLIC_ROLLUP_TYPE is not defined'),
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK=true
|
||||
NEXT_PUBLIC_L1_BASE_URL=https://example.com
|
||||
NEXT_PUBLIC_OPTIMISTIC_L2_WITHDRAWAL_URL=https://example.com
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=optimistic
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://example.com
|
||||
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://example.com
|
||||
@@ -192,9 +192,9 @@ frontend:
|
||||
NEXT_PUBLIC_VISUALIZE_API_HOST: https://visualizer-test.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_CONTRACT_INFO_API_HOST: https://contracts-info-test.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST: https://admin-rs-test.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK: "true"
|
||||
NEXT_PUBLIC_L1_BASE_URL: https://eth-goerli.blockscout.com/
|
||||
NEXT_PUBLIC_OPTIMISTIC_L2_WITHDRAWAL_URL: https://app.optimism.io/bridge/withdraw
|
||||
NEXT_PUBLIC_ROLLUP_TYPE: optimistic
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL: https://eth-goerli.blockscout.com/
|
||||
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL: https://app.optimism.io/bridge/withdraw
|
||||
NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62
|
||||
envFromSecret:
|
||||
NEXT_PUBLIC_AUTH0_CLIENT_ID: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_AUTH0_CLIENT_ID
|
||||
|
||||
@@ -66,9 +66,9 @@ frontend:
|
||||
NEXT_PUBLIC_VISUALIZE_API_HOST: https://visualizer-optimism-goerli.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_CONTRACT_INFO_API_HOST: https://contracts-info-test.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST: https://admin-rs-test.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK: "true"
|
||||
NEXT_PUBLIC_OPTIMISTIC_L2_WITHDRAWAL_URL: https://app.optimism.io/bridge/withdraw
|
||||
NEXT_PUBLIC_L1_BASE_URL: https://blockscout-main.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_ROLLUP_TYPE=optimistic
|
||||
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://blockscout-main.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://app.optimism.io/bridge/withdraw
|
||||
NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62
|
||||
NEXT_PUBLIC_USE_NEXT_JS_PROXY: true
|
||||
envFromSecret:
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Deprecated environment variables
|
||||
|
||||
| Variable | Type | Description | Compulsoriness | Default value | Example value | Deprecated in version | Comment |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK | `boolean` | Set to true for optimistic L2 solutions | Required | - | `true` | v1.24.0 | Replaced by NEXT_PUBLIC_ROLLUP_TYPE |
|
||||
| NEXT_PUBLIC_IS_ZKEVM_L2_NETWORK | `boolean` | Set to true for zkevm L2 solutions | Required | - | `true` | v1.24.0 | Replaced by NEXT_PUBLIC_ROLLUP_TYPE |
|
||||
| NEXT_PUBLIC_OPTIMISTIC_L2_WITHDRAWAL_URL | `string` | URL for optimistic L2 -> L1 withdrawals | Required | - | `https://app.optimism.io/bridge/withdraw` | v1.24.0 | Renamed to NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL |
|
||||
| NEXT_PUBLIC_L1_BASE_URL | `string` | Blockscout base URL for L1 network | Required | - | `'http://eth-goerli.blockscout.com'` | v1.24.0 | Renamed to NEXT_PUBLIC_ROLLUP_L1_BASE_URL |
|
||||
@@ -34,8 +34,7 @@ Please be aware that all environment variables prefixed with `NEXT_PUBLIC_` will
|
||||
- [Text ads](ENVS.md#text-ads)
|
||||
- [Beacon chain](ENVS.md#beacon-chain)
|
||||
- [User operations](ENVS.md#user-operations-feature-erc-4337)
|
||||
- [Optimistic rollup (L2) chain](ENVS.md#optimistic-rollup-l2-chain)
|
||||
- [ZkEvm rollup (L2) chain](NVS.md#zkevm-rollup-l2-chain)
|
||||
- [Rollup chain](ENVS.md#rollup-chain)
|
||||
- [Export data to CSV file](ENVS.md#export-data-to-csv-file)
|
||||
- [Google analytics](ENVS.md#google-analytics)
|
||||
- [Mixpanel analytics](ENVS.md#mixpanel-analytics)
|
||||
@@ -332,7 +331,7 @@ This feature is **enabled by default** with the `slise` ads provider. To switch
|
||||
|
||||
| Variable | Type| Description | Compulsoriness | Default value | Example value |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| NEXT_PUBLIC_AD_BANNER_PROVIDER | `slise` \| `adbutler` \| `coinzilla` \| `none` | Ads provider | - | `slise` | `coinzilla` |
|
||||
| NEXT_PUBLIC_AD_BANNER_PROVIDER | `slise` \| `adbutler` \| `coinzilla` \| `hype` \| `none` | Ads provider | - | `slise` | `coinzilla` |
|
||||
| NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP | `{ id: string; width: string; height: string }` | Placement config for desktop Adbutler banner | - | - | `{'id':'123456','width':'728','height':'90'}` |
|
||||
| NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE | `{ id: string; width: number; height: number }` | Placement config for mobile Adbutler banner | - | - | `{'id':'654321','width':'300','height':'100'}` |
|
||||
|
||||
@@ -365,22 +364,13 @@ This feature is **enabled by default** with the `coinzilla` ads provider. To swi
|
||||
|
||||
|
||||
|
||||
### Optimistic rollup (L2) chain
|
||||
### Rollup chain
|
||||
|
||||
| Variable | Type| Description | Compulsoriness | Default value | Example value |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK | `boolean` | Set to true for optimistic L2 solutions | Required | - | `true` |
|
||||
| NEXT_PUBLIC_OPTIMISTIC_L2_WITHDRAWAL_URL | `string` | URL for optimistic L2 -> L1 withdrawals | Required | - | `https://app.optimism.io/bridge/withdraw` |
|
||||
| NEXT_PUBLIC_L1_BASE_URL | `string` | Blockscout base URL for L1 network | Required | - | `'http://eth-goerli.blockscout.com'` |
|
||||
|
||||
|
||||
|
||||
### ZkEvm rollup (L2) chain
|
||||
| Variable | Type| Description | Compulsoriness | Default value | Example value |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| NEXT_PUBLIC_IS_ZKEVM_L2_NETWORK | `boolean` | Set to true for zkevm L2 solutions | Required | - | `true` |
|
||||
| NEXT_PUBLIC_L1_BASE_URL | `string` | Blockscout base URL for L1 network | Required | - | `'http://eth-goerli.blockscout.com'` |
|
||||
|
||||
| NEXT_PUBLIC_ROLLUP_TYPE | `'optimistic' \| 'zkEvm' ` | Rollup chain type | Required | - | `'optimistic'` |
|
||||
| NEXT_PUBLIC_ROLLUP_L1_BASE_URL | `string` | Blockscout base URL for L1 network | Required | - | `'http://eth-goerli.blockscout.com'` |
|
||||
| NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL | `string` | URL for L2 -> L1 withdrawals | - | - | `https://app.optimism.io/bridge/withdraw` |
|
||||
|
||||
|
||||
|
||||
@@ -438,7 +428,8 @@ This feature is **always enabled**, but you can configure its behavior by passin
|
||||
|
||||
| Variable | Type| Description | Compulsoriness | Default value | Example value |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| NEXT_PUBLIC_MARKETPLACE_CONFIG_URL | `string` | URL of configuration file (`.json` format only) which contains list of apps that will be shown on the marketplace page. See [below](#marketplace-app-configuration-properties) list of available properties for an app | Required | - | `https://example.com/marketplace_config.json` |
|
||||
| NEXT_PUBLIC_MARKETPLACE_CONFIG_URL | `string` | URL of configuration file (`.json` format only) which contains list of apps that will be shown on the marketplace page. See [below](#marketplace-app-configuration-properties) list of available properties for an app. Can be replaced with NEXT_PUBLIC_ADMIN_SERVICE_API_HOST | Required | - | `https://example.com/marketplace_config.json` |
|
||||
| NEXT_PUBLIC_ADMIN_SERVICE_API_HOST | `string` | Admin Service API endpoint url. Can be used instead of NEXT_PUBLIC_MARKETPLACE_CONFIG_URL | - | - | `https://admin-rs.services.blockscout.com` |
|
||||
| NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM | `string` | Link to form where authors can submit their dapps to the marketplace | Required | - | `https://airtable.com/shrqUAcjgGJ4jU88C` |
|
||||
| NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM | `string` | Link to form where users can suggest ideas for the marketplace | - | - | `https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form` |
|
||||
| NEXT_PUBLIC_NETWORK_RPC_URL | `string` | See in [Blockchain parameters](ENVS.md#blockchain-parameters) section | Required | - | `https://core.poa.network` |
|
||||
|
||||
@@ -34,7 +34,7 @@ describe('falsy query parameters', () => {
|
||||
|
||||
test('builds URL with array-like query parameters', () => {
|
||||
const url = buildUrl('block', { height_or_hash: '42' }, { includeTx: [ '0x11', '0x22' ], sort: 'asc' });
|
||||
expect(url).toBe('https://localhost:3003/api/v2/blocks/42?includeTx%5B0%5D=0x11&includeTx%5B1%5D=0x22&sort=asc');
|
||||
expect(url).toBe('https://localhost:3003/api/v2/blocks/42?includeTx=0x11%2C0x22&sort=asc');
|
||||
});
|
||||
|
||||
test('builds URL for resource with custom API endpoint', () => {
|
||||
|
||||
@@ -19,13 +19,7 @@ export default function buildUrl<R extends ResourceName>(
|
||||
|
||||
queryParams && Object.entries(queryParams).forEach(([ key, value ]) => {
|
||||
// there are some pagination params that can be null or false for the next page
|
||||
if (value !== undefined && value !== '') {
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((v, i) => url.searchParams.append(`${ key }[${ i }]`, String(v)));
|
||||
} else {
|
||||
url.searchParams.append(key, String(value));
|
||||
}
|
||||
}
|
||||
value !== undefined && value !== '' && url.searchParams.append(key, String(value));
|
||||
});
|
||||
|
||||
return url.toString();
|
||||
|
||||
@@ -47,11 +47,14 @@ import type {
|
||||
} from 'types/api/ens';
|
||||
import type { IndexingStatus } from 'types/api/indexingStatus';
|
||||
import type { InternalTransactionsResponse } from 'types/api/internalTransaction';
|
||||
import type { L2DepositsResponse, L2DepositsItem } from 'types/api/l2Deposits';
|
||||
import type { L2OutputRootsResponse } from 'types/api/l2OutputRoots';
|
||||
import type { L2TxnBatchesResponse } from 'types/api/l2TxnBatches';
|
||||
import type { L2WithdrawalsResponse } from 'types/api/l2Withdrawals';
|
||||
import type { LogsResponseTx, LogsResponseAddress } from 'types/api/log';
|
||||
import type {
|
||||
OptimisticL2DepositsResponse,
|
||||
OptimisticL2DepositsItem,
|
||||
OptimisticL2OutputRootsResponse,
|
||||
OptimisticL2TxnBatchesResponse,
|
||||
OptimisticL2WithdrawalsResponse,
|
||||
} from 'types/api/optimisticL2';
|
||||
import type { RawTracesResponse } from 'types/api/rawTrace';
|
||||
import type { SearchRedirectResult, SearchResult, SearchResultFilters, SearchResultItem } from 'types/api/search';
|
||||
import type { Counters, StatsCharts, StatsChart, HomeStats } from 'types/api/stats';
|
||||
@@ -81,11 +84,15 @@ import type { UserOpsResponse, UserOp, UserOpsFilters, UserOpsAccount } from 'ty
|
||||
import type { VerifiedContractsSorting } from 'types/api/verifiedContracts';
|
||||
import type { VisualizedContract } from 'types/api/visualization';
|
||||
import type { WithdrawalsResponse, WithdrawalsCounters } from 'types/api/withdrawals';
|
||||
import type { ZkEvmL2TxnBatch, ZkEvmL2TxnBatchesItem, ZkEvmL2TxnBatchesResponse, ZkEvmL2TxnBatchTxs } from 'types/api/zkEvmL2TxnBatches';
|
||||
import type { ZkEvmL2TxnBatch, ZkEvmL2TxnBatchesItem, ZkEvmL2TxnBatchesResponse, ZkEvmL2TxnBatchTxs } from 'types/api/zkEvmL2';
|
||||
import type { MarketplaceAppOverview } from 'types/client/marketplace';
|
||||
import type { ArrayElement } from 'types/utils';
|
||||
|
||||
import config from 'configs/app';
|
||||
|
||||
const marketplaceFeature = getFeaturePayload(config.features.marketplace);
|
||||
const marketplaceApi = marketplaceFeature && 'api' in marketplaceFeature ? marketplaceFeature.api : undefined;
|
||||
|
||||
export interface ApiResource {
|
||||
path: ResourcePath;
|
||||
endpoint?: string;
|
||||
@@ -221,6 +228,20 @@ export const RESOURCES = {
|
||||
basePath: getFeaturePayload(config.features.sol2uml)?.api.basePath,
|
||||
},
|
||||
|
||||
// MARKETPLACE
|
||||
marketplace_dapps: {
|
||||
path: '/api/v1/chains/:chainId/marketplace/dapps',
|
||||
pathParams: [ 'chainId' as const ],
|
||||
endpoint: marketplaceApi?.endpoint,
|
||||
basePath: marketplaceApi?.basePath,
|
||||
},
|
||||
marketplace_dapp: {
|
||||
path: '/api/v1/chains/:chainId/marketplace/dapps/:dappId',
|
||||
pathParams: [ 'chainId' as const, 'dappId' as const ],
|
||||
endpoint: marketplaceApi?.endpoint,
|
||||
basePath: marketplaceApi?.basePath,
|
||||
},
|
||||
|
||||
// BLOCKS, TXS
|
||||
blocks: {
|
||||
path: '/api/v2/blocks',
|
||||
@@ -688,7 +709,7 @@ Q extends 'homepage_chart_market' ? ChartMarketResponse :
|
||||
Q extends 'homepage_blocks' ? Array<Block> :
|
||||
Q extends 'homepage_txs' ? Array<Transaction> :
|
||||
Q extends 'homepage_txs_watchlist' ? Array<Transaction> :
|
||||
Q extends 'homepage_deposits' ? Array<L2DepositsItem> :
|
||||
Q extends 'homepage_deposits' ? Array<OptimisticL2DepositsItem> :
|
||||
Q extends 'homepage_zkevm_l2_batches' ? { items: Array<ZkEvmL2TxnBatchesItem> } :
|
||||
Q extends 'homepage_indexing_status' ? IndexingStatus :
|
||||
Q extends 'homepage_zkevm_latest_batch' ? number :
|
||||
@@ -752,10 +773,10 @@ Q extends 'visualize_sol2uml' ? VisualizedContract :
|
||||
Q extends 'contract_verification_config' ? SmartContractVerificationConfig :
|
||||
Q extends 'withdrawals' ? WithdrawalsResponse :
|
||||
Q extends 'withdrawals_counters' ? WithdrawalsCounters :
|
||||
Q extends 'l2_output_roots' ? L2OutputRootsResponse :
|
||||
Q extends 'l2_withdrawals' ? L2WithdrawalsResponse :
|
||||
Q extends 'l2_deposits' ? L2DepositsResponse :
|
||||
Q extends 'l2_txn_batches' ? L2TxnBatchesResponse :
|
||||
Q extends 'l2_output_roots' ? OptimisticL2OutputRootsResponse :
|
||||
Q extends 'l2_withdrawals' ? OptimisticL2WithdrawalsResponse :
|
||||
Q extends 'l2_deposits' ? OptimisticL2DepositsResponse :
|
||||
Q extends 'l2_txn_batches' ? OptimisticL2TxnBatchesResponse :
|
||||
Q extends 'l2_output_roots_count' ? number :
|
||||
Q extends 'l2_withdrawals_count' ? number :
|
||||
Q extends 'l2_deposits_count' ? number :
|
||||
@@ -772,6 +793,8 @@ Q extends 'domains_lookup' ? EnsDomainLookupResponse :
|
||||
Q extends 'user_ops' ? UserOpsResponse :
|
||||
Q extends 'user_op' ? UserOp :
|
||||
Q extends 'user_ops_account' ? UserOpsAccount :
|
||||
Q extends 'marketplace_dapps' ? Array<MarketplaceAppOverview> :
|
||||
Q extends 'marketplace_dapp' ? MarketplaceAppOverview :
|
||||
never;
|
||||
/* eslint-enable @typescript-eslint/indent */
|
||||
|
||||
|
||||
@@ -67,7 +67,9 @@ export default function useNavItems(): ReturnType {
|
||||
isActive: pathname === '/name-domains' || pathname === '/name-domains/[name]',
|
||||
} : null;
|
||||
|
||||
if (config.features.zkEvmRollup.isEnabled) {
|
||||
const rollupFeature = config.features.rollup;
|
||||
|
||||
if (rollupFeature.isEnabled && rollupFeature.type === 'zkEvm') {
|
||||
blockchainNavItems = [
|
||||
[
|
||||
txs,
|
||||
@@ -86,7 +88,7 @@ export default function useNavItems(): ReturnType {
|
||||
ensLookup,
|
||||
].filter(Boolean),
|
||||
];
|
||||
} else if (config.features.optimisticRollup.isEnabled) {
|
||||
} else if (rollupFeature.isEnabled && rollupFeature.type === 'optimistic') {
|
||||
blockchainNavItems = [
|
||||
[
|
||||
txs,
|
||||
|
||||
@@ -5,8 +5,11 @@ import type { Route } from 'nextjs-routes';
|
||||
import generate from './generate';
|
||||
|
||||
export default function update<R extends Route>(route: R, apiData: ApiData<R>) {
|
||||
const { title, description } = generate(route, apiData);
|
||||
const { title, description, opengraph } = generate(route, apiData);
|
||||
|
||||
window.document.title = title;
|
||||
window.document.querySelector('meta[name="description"]')?.setAttribute('content', description);
|
||||
window.document.querySelector('meta[property="og:title"]')?.setAttribute('content', opengraph.title);
|
||||
opengraph.description &&
|
||||
window.document.querySelector('meta[property="og:description"]')?.setAttribute('content', opengraph.description);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
export default function shortenString(string: string | null) {
|
||||
export default function shortenString(string: string | null, charNumber: number | undefined = 8) {
|
||||
if (!string) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (string.length <= 7) {
|
||||
if (string.length <= charNumber) {
|
||||
return string;
|
||||
}
|
||||
|
||||
return string.slice(0, 4) + '...' + string.slice(-4);
|
||||
return string.slice(0, charNumber - 4) + '...' + string.slice(-4);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { SmartContractVerificationResponse } from 'types/api/contract';
|
||||
import type { RawTracesResponse } from 'types/api/rawTrace';
|
||||
import type { TokenTransfer } from 'types/api/tokenTransfer';
|
||||
import type { Transaction } from 'types/api/transaction';
|
||||
import type { NewZkEvmBatchSocketResponse } from 'types/api/zkEvmL2TxnBatches';
|
||||
import type { NewZkEvmBatchSocketResponse } from 'types/api/zkEvmL2';
|
||||
|
||||
export type SocketMessageParams = SocketMessage.NewBlock |
|
||||
SocketMessage.BlocksIndexStatus |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ZkEvmL2TxnBatch } from 'types/api/zkEvmL2TxnBatches';
|
||||
import type { ZkEvmL2TxnBatch } from 'types/api/zkEvmL2';
|
||||
|
||||
export const txnBatchData: ZkEvmL2TxnBatch = {
|
||||
acc_input_hash: '0x4bf88aabe33713b7817266d7860912c58272d808da7397cdc627ca53b296fad3',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ZkEvmL2TxnBatchesResponse } from 'types/api/zkEvmL2TxnBatches';
|
||||
import type { ZkEvmL2TxnBatchesResponse } from 'types/api/zkEvmL2';
|
||||
|
||||
export const txnBatchesData: ZkEvmL2TxnBatchesResponse = {
|
||||
items: [
|
||||
|
||||
@@ -3,30 +3,52 @@ import sha256 from 'crypto-js/sha256';
|
||||
import type CspDev from 'csp-dev';
|
||||
|
||||
import { connectAdbutler, placeAd } from 'ui/shared/ad/adbutlerScript';
|
||||
import { hypeInit } from 'ui/shared/ad/hypeBannerScript';
|
||||
|
||||
export function ad(): CspDev.DirectiveDescriptor {
|
||||
return {
|
||||
'connect-src': [
|
||||
// coinzilla
|
||||
'coinzilla.com',
|
||||
'*.coinzilla.com',
|
||||
'https://request-global.czilladx.com',
|
||||
|
||||
// slise
|
||||
'*.slise.xyz',
|
||||
|
||||
// hype
|
||||
'api.hypelab.com',
|
||||
],
|
||||
'frame-src': [
|
||||
// coinzilla
|
||||
'https://request-global.czilladx.com',
|
||||
],
|
||||
'script-src': [
|
||||
// coinzilla
|
||||
'coinzillatag.com',
|
||||
|
||||
// adbutler
|
||||
'servedbyadbutler.com',
|
||||
`'sha256-${ Base64.stringify(sha256(connectAdbutler)) }'`,
|
||||
`'sha256-${ Base64.stringify(sha256(placeAd ?? '')) }'`,
|
||||
|
||||
// slise
|
||||
'*.slise.xyz',
|
||||
|
||||
//hype
|
||||
`'sha256-${ Base64.stringify(sha256(hypeInit ?? '')) }'`,
|
||||
'https://api.hypelab.com',
|
||||
'd1q98dzwj6s2rb.cloudfront.net',
|
||||
],
|
||||
'img-src': [
|
||||
'servedbyadbutler.com',
|
||||
// coinzilla
|
||||
'cdn.coinzilla.io',
|
||||
|
||||
// adbutler
|
||||
'servedbyadbutler.com',
|
||||
],
|
||||
'font-src': [
|
||||
// coinzilla
|
||||
'https://request-global.czilladx.com',
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { GetServerSideProps } from 'next';
|
||||
|
||||
import config from 'configs/app';
|
||||
const rollupFeature = config.features.rollup;
|
||||
|
||||
export type Props = {
|
||||
cookies: string;
|
||||
@@ -49,7 +50,10 @@ export const verifiedAddresses: GetServerSideProps<Props> = async(context) => {
|
||||
};
|
||||
|
||||
export const withdrawals: GetServerSideProps<Props> = async(context) => {
|
||||
if (!config.features.beaconChain.isEnabled && !config.features.optimisticRollup.isEnabled) {
|
||||
if (
|
||||
!config.features.beaconChain.isEnabled &&
|
||||
!(rollupFeature.isEnabled && rollupFeature.type === 'optimistic')
|
||||
) {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
@@ -59,7 +63,7 @@ export const withdrawals: GetServerSideProps<Props> = async(context) => {
|
||||
};
|
||||
|
||||
export const rollup: GetServerSideProps<Props> = async(context) => {
|
||||
if (!config.features.optimisticRollup.isEnabled && !config.features.zkEvmRollup.isEnabled) {
|
||||
if (!config.features.rollup.isEnabled) {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
@@ -69,7 +73,7 @@ export const rollup: GetServerSideProps<Props> = async(context) => {
|
||||
};
|
||||
|
||||
export const optimisticRollup: GetServerSideProps<Props> = async(context) => {
|
||||
if (!config.features.optimisticRollup.isEnabled) {
|
||||
if (!(rollupFeature.isEnabled && rollupFeature.type === 'optimistic')) {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
@@ -79,7 +83,7 @@ export const optimisticRollup: GetServerSideProps<Props> = async(context) => {
|
||||
};
|
||||
|
||||
export const zkEvmRollup: GetServerSideProps<Props> = async(context) => {
|
||||
if (!config.features.zkEvmRollup.isEnabled) {
|
||||
if (!(rollupFeature.isEnabled && rollupFeature.type === 'zkEvm')) {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
|
||||
@@ -38,9 +38,9 @@ declare module "nextjs-routes" {
|
||||
| StaticRoute<"/login">
|
||||
| DynamicRoute<"/name-domains/[name]", { "name": string }>
|
||||
| StaticRoute<"/name-domains">
|
||||
| StaticRoute<"/output-roots">
|
||||
| DynamicRoute<"/op/[hash]", { "hash": string }>
|
||||
| StaticRoute<"/ops">
|
||||
| StaticRoute<"/output-roots">
|
||||
| StaticRoute<"/search-results">
|
||||
| StaticRoute<"/stats">
|
||||
| DynamicRoute<"/token/[hash]", { "hash": string }>
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"test:pw:local": "export NODE_PATH=$(pwd)/node_modules && yarn test:pw",
|
||||
"test:pw:docker": "docker run --rm --network host -v $(pwd):/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.41.1-focal ./tools/scripts/pw.docker.sh",
|
||||
"test:pw:ci": "yarn test:pw --project=$PW_PROJECT",
|
||||
"test:pw:detect-affected": "node ./deploy/tools/affected-tests/index.js",
|
||||
"test:jest": "jest",
|
||||
"test:jest:watch": "jest --watch",
|
||||
"favicon:generate:dev": "./tools/scripts/favicon-generator.dev.sh"
|
||||
@@ -36,6 +37,7 @@
|
||||
"@emotion/react": "^11.10.4",
|
||||
"@emotion/styled": "^11.10.4",
|
||||
"@growthbook/growthbook-react": "0.21.0",
|
||||
"@hypelab/sdk-react": "^1.0.0",
|
||||
"@metamask/post-message-stream": "^7.0.0",
|
||||
"@metamask/providers": "^10.2.1",
|
||||
"@monaco-editor/react": "^4.4.6",
|
||||
|
||||
@@ -5,12 +5,19 @@ import React from 'react';
|
||||
import PageNextJs from 'nextjs/PageNextJs';
|
||||
|
||||
import config from 'configs/app';
|
||||
const rollupFeature = config.features.rollup;
|
||||
|
||||
const Batches = dynamic(() => {
|
||||
if (config.features.zkEvmRollup.isEnabled) {
|
||||
return import('ui/pages/ZkEvmL2TxnBatches');
|
||||
if (!rollupFeature.isEnabled) {
|
||||
throw new Error('Rollup feature is not enabled.');
|
||||
}
|
||||
|
||||
switch (rollupFeature.type) {
|
||||
case 'zkEvm':
|
||||
return import('ui/pages/ZkEvmL2TxnBatches');
|
||||
case 'optimistic':
|
||||
return import('ui/pages/OptimisticL2TxnBatches');
|
||||
}
|
||||
return import('ui/pages/L2TxnBatches');
|
||||
}, { ssr: false });
|
||||
|
||||
const Page: NextPage = () => {
|
||||
|
||||
@@ -4,7 +4,7 @@ import React from 'react';
|
||||
|
||||
import PageNextJs from 'nextjs/PageNextJs';
|
||||
|
||||
const Deposits = dynamic(() => import('ui/pages/L2Deposits'), { ssr: false });
|
||||
const Deposits = dynamic(() => import('ui/pages/OptimisticL2Deposits'), { ssr: false });
|
||||
|
||||
const Page: NextPage = () => {
|
||||
return (
|
||||
|
||||
@@ -4,7 +4,7 @@ import React from 'react';
|
||||
|
||||
import PageNextJs from 'nextjs/PageNextJs';
|
||||
|
||||
const OutputRoots = dynamic(() => import('ui/pages/L2OutputRoots'), { ssr: false });
|
||||
const OutputRoots = dynamic(() => import('ui/pages/OptimisticL2OutputRoots'), { ssr: false });
|
||||
|
||||
const Page: NextPage = () => {
|
||||
return (
|
||||
|
||||
@@ -5,12 +5,18 @@ import React from 'react';
|
||||
import PageNextJs from 'nextjs/PageNextJs';
|
||||
|
||||
import config from 'configs/app';
|
||||
const rollupFeature = config.features.rollup;
|
||||
const beaconChainFeature = config.features.beaconChain;
|
||||
|
||||
const Withdrawals = dynamic(() => {
|
||||
if (config.features.optimisticRollup.isEnabled) {
|
||||
return import('ui/pages/L2Withdrawals');
|
||||
if (rollupFeature.isEnabled && rollupFeature.type === 'optimistic') {
|
||||
return import('ui/pages/OptimisticL2Withdrawals');
|
||||
}
|
||||
return import('ui/pages/Withdrawals');
|
||||
if (beaconChainFeature.isEnabled) {
|
||||
return import('ui/pages/BeaconChainWithdrawals');
|
||||
}
|
||||
|
||||
throw new Error('Withdrawals feature is not enabled.');
|
||||
}, { ssr: false });
|
||||
|
||||
const Page: NextPage = () => {
|
||||
|
||||
@@ -15,9 +15,9 @@ export const featureEnvs = {
|
||||
{ name: 'NEXT_PUBLIC_HAS_BEACON_CHAIN', value: 'true' },
|
||||
],
|
||||
optimisticRollup: [
|
||||
{ name: 'NEXT_PUBLIC_IS_OPTIMISTIC_L2_NETWORK', value: 'true' },
|
||||
{ name: 'NEXT_PUBLIC_L1_BASE_URL', value: 'https://localhost:3101' },
|
||||
{ name: 'NEXT_PUBLIC_OPTIMISTIC_L2_WITHDRAWAL_URL', value: 'https://localhost:3102' },
|
||||
{ name: 'NEXT_PUBLIC_ROLLUP_TYPE', value: 'optimistic' },
|
||||
{ name: 'NEXT_PUBLIC_ROLLUP_L1_BASE_URL', value: 'https://localhost:3101' },
|
||||
{ name: 'NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL', value: 'https://localhost:3102' },
|
||||
],
|
||||
bridgedTokens: [
|
||||
{
|
||||
@@ -32,9 +32,9 @@ export const featureEnvs = {
|
||||
txInterpretation: [
|
||||
{ name: 'NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER', value: 'blockscout' },
|
||||
],
|
||||
zkRollup: [
|
||||
{ name: 'NEXT_PUBLIC_IS_ZKEVM_L2_NETWORK', value: 'true' },
|
||||
{ name: 'NEXT_PUBLIC_L1_BASE_URL', value: 'https://localhost:3101' },
|
||||
zkEvmRollup: [
|
||||
{ name: 'NEXT_PUBLIC_ROLLUP_TYPE', value: 'zkEvm' },
|
||||
{ name: 'NEXT_PUBLIC_ROLLUP_L1_BASE_URL', value: 'https://localhost:3101' },
|
||||
],
|
||||
userOps: [
|
||||
{ name: 'NEXT_PUBLIC_HAS_USER_OPS', value: 'true' },
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import type { L2DepositsItem } from 'types/api/l2Deposits';
|
||||
import type { L2OutputRootsItem } from 'types/api/l2OutputRoots';
|
||||
import type { L2TxnBatchesItem } from 'types/api/l2TxnBatches';
|
||||
import type { L2WithdrawalsItem } from 'types/api/l2Withdrawals';
|
||||
import type {
|
||||
OptimisticL2DepositsItem,
|
||||
OptimisticL2OutputRootsItem,
|
||||
OptimisticL2TxnBatchesItem,
|
||||
OptimisticL2WithdrawalsItem,
|
||||
} from 'types/api/optimisticL2';
|
||||
|
||||
import { ADDRESS_HASH, ADDRESS_PARAMS } from './addressParams';
|
||||
import { TX_HASH } from './tx';
|
||||
|
||||
export const L2_DEPOSIT_ITEM: L2DepositsItem = {
|
||||
export const L2_DEPOSIT_ITEM: OptimisticL2DepositsItem = {
|
||||
l1_block_number: 9045233,
|
||||
l1_block_timestamp: '2023-05-22T18:00:36.000000Z',
|
||||
l1_tx_hash: TX_HASH,
|
||||
@@ -15,7 +17,7 @@ export const L2_DEPOSIT_ITEM: L2DepositsItem = {
|
||||
l2_tx_hash: TX_HASH,
|
||||
};
|
||||
|
||||
export const L2_WITHDRAWAL_ITEM: L2WithdrawalsItem = {
|
||||
export const L2_WITHDRAWAL_ITEM: OptimisticL2WithdrawalsItem = {
|
||||
challenge_period_end: null,
|
||||
from: ADDRESS_PARAMS,
|
||||
l1_tx_hash: TX_HASH,
|
||||
@@ -26,7 +28,7 @@ export const L2_WITHDRAWAL_ITEM: L2WithdrawalsItem = {
|
||||
status: 'Ready to prove',
|
||||
};
|
||||
|
||||
export const L2_TXN_BATCHES_ITEM: L2TxnBatchesItem = {
|
||||
export const L2_TXN_BATCHES_ITEM: OptimisticL2TxnBatchesItem = {
|
||||
epoch_number: 9103513,
|
||||
l1_timestamp: '2023-06-01T14:46:48.000000Z',
|
||||
l1_tx_hashes: [
|
||||
@@ -36,7 +38,7 @@ export const L2_TXN_BATCHES_ITEM: L2TxnBatchesItem = {
|
||||
tx_count: 9,
|
||||
};
|
||||
|
||||
export const L2_OUTPUT_ROOTS_ITEM: L2OutputRootsItem = {
|
||||
export const L2_OUTPUT_ROOTS_ITEM: OptimisticL2OutputRootsItem = {
|
||||
l1_block_number: 9103684,
|
||||
l1_timestamp: '2023-06-01T15:26:12.000000Z',
|
||||
l1_tx_hash: TX_HASH,
|
||||
|
||||
@@ -53,6 +53,10 @@ export const GET_TRANSACTION_RECEIPT: TransactionReceipt = {
|
||||
|
||||
export const GET_TRANSACTION_CONFIRMATIONS = BigInt(420);
|
||||
|
||||
export const GET_BALANCE = BigInt(42_000_000_000_000);
|
||||
|
||||
export const GET_TRANSACTIONS_COUNT = 42;
|
||||
|
||||
export const GET_BLOCK: GetBlockReturnType<Chain, false, 'latest'> = {
|
||||
baseFeePerGas: BigInt(11),
|
||||
difficulty: BigInt(111),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ZkEvmL2TxnBatch, ZkEvmL2TxnBatchesItem } from 'types/api/zkEvmL2TxnBatches';
|
||||
import type { ZkEvmL2TxnBatch, ZkEvmL2TxnBatchesItem } from 'types/api/zkEvmL2';
|
||||
|
||||
import { TX_HASH } from './tx';
|
||||
|
||||
|
||||
@@ -10,7 +10,73 @@ dotenv \
|
||||
|
||||
yarn svg:build-sprite
|
||||
|
||||
# Check if the "--affected" argument is present in the script args
|
||||
check_affected_flag() {
|
||||
local affected_flag=false
|
||||
|
||||
for arg in "$@"; do
|
||||
if [[ "$arg" = "--affected"* ]]; then
|
||||
# Extract the value after the equals sign
|
||||
is_affected_value=${is_affected_arg#*=}
|
||||
|
||||
if [ "$is_affected_value" != "false" ]; then
|
||||
affected_flag=true
|
||||
fi
|
||||
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
echo "$affected_flag"
|
||||
}
|
||||
|
||||
# Remove the "--affected" argument from the script args
|
||||
filter_arguments() {
|
||||
local args=()
|
||||
|
||||
for arg in "$@"; do
|
||||
if [[ "$arg" != "--affected"* ]]; then
|
||||
args+=("$arg")
|
||||
fi
|
||||
done
|
||||
|
||||
echo "${args[@]}"
|
||||
}
|
||||
|
||||
get_files_to_run() {
|
||||
local is_affected=$1
|
||||
local files_to_run=""
|
||||
|
||||
if [ "$is_affected" = true ]; then
|
||||
affected_tests_file="./playwright/affected-tests.txt"
|
||||
|
||||
if [ -f "$affected_tests_file" ]; then
|
||||
file_content=$(<"$affected_tests_file")
|
||||
files_to_run="${file_content//$'\n'/$' '}"
|
||||
|
||||
if [ -z "$files_to_run" ]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$files_to_run"
|
||||
}
|
||||
|
||||
args=$(filter_arguments "$@")
|
||||
affected_flag=$(check_affected_flag "$@")
|
||||
files_to_run=$(get_files_to_run "$affected_flag")
|
||||
if [ $? -eq 1 ]; then
|
||||
echo "No affected tests found in the file. Exiting..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Running Playwright tests with the following arguments: $args"
|
||||
echo "Affected flag: $affected_flag"
|
||||
echo "Files to run: $files_to_run"
|
||||
|
||||
dotenv \
|
||||
-v NODE_OPTIONS=\"--max-old-space-size=4096\" \
|
||||
-e $config_file \
|
||||
-- playwright test -c playwright-ct.config.ts "$@"
|
||||
-- playwright test -c playwright-ct.config.ts $files_to_run $args
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ export interface Address extends UserTags {
|
||||
export interface AddressCounters {
|
||||
transactions_count: string;
|
||||
token_transfers_count: string;
|
||||
gas_usage_count: string;
|
||||
gas_usage_count: string | null;
|
||||
validations_count: string | null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
export type L2DepositsItem = {
|
||||
l1_block_number: number;
|
||||
l1_tx_hash: string;
|
||||
l1_block_timestamp: string;
|
||||
l1_tx_origin: string;
|
||||
l2_tx_gas_limit: string;
|
||||
l2_tx_hash: string;
|
||||
}
|
||||
|
||||
export type L2DepositsResponse = {
|
||||
items: Array<L2DepositsItem>;
|
||||
next_page_params: {
|
||||
items_count: number;
|
||||
l1_block_number: number;
|
||||
tx_hash: string;
|
||||
};
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
export type L2OutputRootsItem = {
|
||||
l1_block_number: number;
|
||||
l1_timestamp: string;
|
||||
l1_tx_hash: string;
|
||||
l2_block_number: number;
|
||||
l2_output_index: number;
|
||||
output_root: string;
|
||||
}
|
||||
|
||||
export type L2OutputRootsResponse = {
|
||||
items: Array<L2OutputRootsItem>;
|
||||
next_page_params: {
|
||||
index: number;
|
||||
items_count: number;
|
||||
};
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
export type L2TxnBatchesItem = {
|
||||
epoch_number: number;
|
||||
l1_tx_hashes: Array<string>;
|
||||
l1_timestamp: string;
|
||||
l2_block_number: number;
|
||||
tx_count: number;
|
||||
}
|
||||
|
||||
export type L2TxnBatchesResponse = {
|
||||
items: Array<L2TxnBatchesItem>;
|
||||
next_page_params: {
|
||||
block_number: number;
|
||||
items_count: number;
|
||||
};
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import type { AddressParam } from './addressParams';
|
||||
|
||||
export type L2WithdrawalsItem = {
|
||||
'challenge_period_end': string | null;
|
||||
'from': AddressParam | null;
|
||||
'l1_tx_hash': string | null;
|
||||
'l2_timestamp': string | null;
|
||||
'l2_tx_hash': string;
|
||||
'msg_nonce': number;
|
||||
'msg_nonce_version': number;
|
||||
'status': string;
|
||||
}
|
||||
|
||||
export const WITHDRAWAL_STATUSES = [
|
||||
'Waiting for state root',
|
||||
'Ready to prove',
|
||||
'In challenge period',
|
||||
'Ready for relay',
|
||||
'Relayed',
|
||||
] as const;
|
||||
|
||||
export type L2WithdrawalStatus = typeof WITHDRAWAL_STATUSES[number];
|
||||
|
||||
export type L2WithdrawalsResponse = {
|
||||
items: Array<L2WithdrawalsItem>;
|
||||
'next_page_params': {
|
||||
'items_count': number;
|
||||
'nonce': string;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import type { AddressParam } from './addressParams';
|
||||
|
||||
export type OptimisticL2DepositsItem = {
|
||||
l1_block_number: number;
|
||||
l1_tx_hash: string;
|
||||
l1_block_timestamp: string;
|
||||
l1_tx_origin: string;
|
||||
l2_tx_gas_limit: string;
|
||||
l2_tx_hash: string;
|
||||
}
|
||||
|
||||
export type OptimisticL2DepositsResponse = {
|
||||
items: Array<OptimisticL2DepositsItem>;
|
||||
next_page_params: {
|
||||
items_count: number;
|
||||
l1_block_number: number;
|
||||
tx_hash: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type OptimisticL2OutputRootsItem = {
|
||||
l1_block_number: number;
|
||||
l1_timestamp: string;
|
||||
l1_tx_hash: string;
|
||||
l2_block_number: number;
|
||||
l2_output_index: number;
|
||||
output_root: string;
|
||||
}
|
||||
|
||||
export type OptimisticL2OutputRootsResponse = {
|
||||
items: Array<OptimisticL2OutputRootsItem>;
|
||||
next_page_params: {
|
||||
index: number;
|
||||
items_count: number;
|
||||
};
|
||||
}
|
||||
|
||||
export type OptimisticL2TxnBatchesItem = {
|
||||
epoch_number: number;
|
||||
l1_tx_hashes: Array<string>;
|
||||
l1_timestamp: string;
|
||||
l2_block_number: number;
|
||||
tx_count: number;
|
||||
}
|
||||
|
||||
export type OptimisticL2TxnBatchesResponse = {
|
||||
items: Array<OptimisticL2TxnBatchesItem>;
|
||||
next_page_params: {
|
||||
block_number: number;
|
||||
items_count: number;
|
||||
};
|
||||
}
|
||||
|
||||
export type OptimisticL2WithdrawalsItem = {
|
||||
'challenge_period_end': string | null;
|
||||
'from': AddressParam | null;
|
||||
'l1_tx_hash': string | null;
|
||||
'l2_timestamp': string | null;
|
||||
'l2_tx_hash': string;
|
||||
'msg_nonce': number;
|
||||
'msg_nonce_version': number;
|
||||
'status': string;
|
||||
}
|
||||
|
||||
export const WITHDRAWAL_STATUSES = [
|
||||
'Waiting for state root',
|
||||
'Ready to prove',
|
||||
'In challenge period',
|
||||
'Ready for relay',
|
||||
'Relayed',
|
||||
] as const;
|
||||
|
||||
export type OptimisticL2WithdrawalStatus = typeof WITHDRAWAL_STATUSES[number];
|
||||
|
||||
export type OptimisticL2WithdrawalsResponse = {
|
||||
items: Array<OptimisticL2WithdrawalsItem>;
|
||||
'next_page_params': {
|
||||
'items_count': number;
|
||||
'nonce': string;
|
||||
};
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import type { AddressParam } from './addressParams';
|
||||
import type { BlockTransactionsResponse } from './block';
|
||||
import type { DecodedInput } from './decodedInput';
|
||||
import type { Fee } from './fee';
|
||||
import type { L2WithdrawalStatus } from './l2Withdrawals';
|
||||
import type { OptimisticL2WithdrawalStatus } from './optimisticL2';
|
||||
import type { TokenInfo } from './token';
|
||||
import type { TokenTransfer } from './tokenTransfer';
|
||||
import type { TxAction } from './txAction';
|
||||
@@ -17,7 +17,7 @@ type WrappedTransactionFields = 'decoded_input' | 'fee' | 'gas_limit' | 'gas_pri
|
||||
export interface OpWithdrawal {
|
||||
l1_transaction_hash: string;
|
||||
nonce: number;
|
||||
status: L2WithdrawalStatus;
|
||||
status: OptimisticL2WithdrawalStatus;
|
||||
}
|
||||
|
||||
export type Transaction = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ArrayElement } from 'types/utils';
|
||||
|
||||
export const SUPPORTED_AD_BANNER_PROVIDERS = [ 'slise', 'adbutler', 'coinzilla', 'none' ] as const;
|
||||
export const SUPPORTED_AD_BANNER_PROVIDERS = [ 'slise', 'adbutler', 'coinzilla', 'hype', 'none' ] as const;
|
||||
export type AdBannerProviders = ArrayElement<typeof SUPPORTED_AD_BANNER_PROVIDERS>;
|
||||
|
||||
export const SUPPORTED_AD_TEXT_PROVIDERS = [ 'coinzilla', 'none' ] as const;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { ArrayElement } from 'types/utils';
|
||||
|
||||
export const ROLLUP_TYPES = [
|
||||
'optimistic',
|
||||
'zkEvm',
|
||||
] as const;
|
||||
|
||||
export type RollupType = ArrayElement<typeof ROLLUP_TYPES>;
|
||||
@@ -1,11 +1,7 @@
|
||||
import { test, expect } from '@playwright/experimental-ct-react';
|
||||
import type { UseQueryResult } from '@tanstack/react-query';
|
||||
import React from 'react';
|
||||
import type { WindowProvider } from 'wagmi';
|
||||
|
||||
import type { Address } from 'types/api/address';
|
||||
|
||||
import type { ResourceError } from 'lib/api/resources';
|
||||
import * as addressMock from 'mocks/address/address';
|
||||
import * as countersMock from 'mocks/address/counters';
|
||||
import * as tokensMock from 'mocks/address/tokens';
|
||||
@@ -15,6 +11,7 @@ import * as configs from 'playwright/utils/configs';
|
||||
|
||||
import AddressDetails from './AddressDetails';
|
||||
import MockAddressPage from './testUtils/MockAddressPage';
|
||||
import type { AddressQuery } from './utils/useAddressQuery';
|
||||
|
||||
const ADDRESS_HASH = addressMock.hash;
|
||||
const API_URL_ADDRESS = buildApiUrl('address', { hash: ADDRESS_HASH });
|
||||
@@ -40,7 +37,7 @@ test('contract +@mobile', async({ mount, page }) => {
|
||||
|
||||
const component = await mount(
|
||||
<TestApp>
|
||||
<AddressDetails addressQuery={{ data: addressMock.contract } as UseQueryResult<Address, ResourceError>}/>
|
||||
<AddressDetails addressQuery={{ data: addressMock.contract } as AddressQuery}/>
|
||||
</TestApp>,
|
||||
{ hooksConfig },
|
||||
);
|
||||
@@ -82,7 +79,7 @@ test('token', async({ mount, page }) => {
|
||||
const component = await mount(
|
||||
<TestApp>
|
||||
<MockAddressPage>
|
||||
<AddressDetails addressQuery={{ data: addressMock.token } as UseQueryResult<Address, ResourceError>}/>
|
||||
<AddressDetails addressQuery={{ data: addressMock.token } as AddressQuery}/>
|
||||
</MockAddressPage>
|
||||
</TestApp>,
|
||||
{ hooksConfig },
|
||||
@@ -106,7 +103,7 @@ test('validator +@mobile', async({ mount, page }) => {
|
||||
|
||||
const component = await mount(
|
||||
<TestApp>
|
||||
<AddressDetails addressQuery={{ data: addressMock.validator } as UseQueryResult<Address, ResourceError>}/>
|
||||
<AddressDetails addressQuery={{ data: addressMock.validator } as AddressQuery}/>
|
||||
</TestApp>,
|
||||
{ hooksConfig },
|
||||
);
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import { Box, Text, Grid } from '@chakra-ui/react';
|
||||
import type { UseQueryResult } from '@tanstack/react-query';
|
||||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
|
||||
import type { Address as TAddress } from 'types/api/address';
|
||||
|
||||
import type { ResourceError } from 'lib/api/resources';
|
||||
import useApiQuery from 'lib/api/useApiQuery';
|
||||
import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError';
|
||||
import getQueryParamString from 'lib/router/getQueryParamString';
|
||||
import { ADDRESS_COUNTERS } from 'stubs/address';
|
||||
import AddressCounterItem from 'ui/address/details/AddressCounterItem';
|
||||
import ServiceDegradationWarning from 'ui/shared/alerts/ServiceDegradationWarning';
|
||||
import DataFetchAlert from 'ui/shared/DataFetchAlert';
|
||||
import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
|
||||
import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem';
|
||||
@@ -21,9 +16,11 @@ import TxEntity from 'ui/shared/entities/tx/TxEntity';
|
||||
import AddressBalance from './details/AddressBalance';
|
||||
import AddressNameInfo from './details/AddressNameInfo';
|
||||
import TokenSelect from './tokenSelect/TokenSelect';
|
||||
import useAddressCountersQuery from './utils/useAddressCountersQuery';
|
||||
import type { AddressQuery } from './utils/useAddressQuery';
|
||||
|
||||
interface Props {
|
||||
addressQuery: UseQueryResult<TAddress, ResourceError>;
|
||||
addressQuery: AddressQuery;
|
||||
scrollRef?: React.RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
@@ -32,12 +29,9 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => {
|
||||
|
||||
const addressHash = getQueryParamString(router.query.hash);
|
||||
|
||||
const countersQuery = useApiQuery('address_counters', {
|
||||
pathParams: { hash: addressHash },
|
||||
queryOptions: {
|
||||
enabled: Boolean(addressHash) && Boolean(addressQuery.data),
|
||||
placeholderData: ADDRESS_COUNTERS,
|
||||
},
|
||||
const countersQuery = useAddressCountersQuery({
|
||||
hash: addressHash,
|
||||
addressQuery,
|
||||
});
|
||||
|
||||
const handleCounterItemClick = React.useCallback(() => {
|
||||
@@ -47,7 +41,7 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => {
|
||||
}, 500);
|
||||
}, [ scrollRef ]);
|
||||
|
||||
const errorData = React.useMemo(() => ({
|
||||
const error404Data = React.useMemo(() => ({
|
||||
hash: addressHash || '',
|
||||
is_contract: false,
|
||||
implementation_name: null,
|
||||
@@ -76,142 +70,151 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => {
|
||||
return <DataFetchAlert/>;
|
||||
}
|
||||
|
||||
const data = addressQuery.isError ? errorData : addressQuery.data;
|
||||
const data = addressQuery.isError ? error404Data : addressQuery.data;
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Grid
|
||||
columnGap={ 8 }
|
||||
rowGap={{ base: 1, lg: 3 }}
|
||||
templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }} overflow="hidden"
|
||||
>
|
||||
<AddressNameInfo data={ data } isLoading={ addressQuery.isPlaceholderData }/>
|
||||
{ data.is_contract && data.creation_tx_hash && data.creator_address_hash && (
|
||||
<DetailsInfoItem
|
||||
title="Creator"
|
||||
hint="Transaction and address of creation"
|
||||
isLoading={ addressQuery.isPlaceholderData }
|
||||
>
|
||||
<AddressEntity
|
||||
address={{ hash: data.creator_address_hash }}
|
||||
truncation="constant"
|
||||
noIcon
|
||||
/>
|
||||
<Text whiteSpace="pre"> at txn </Text>
|
||||
<TxEntity hash={ data.creation_tx_hash } truncation="constant" noIcon noCopy={ false }/>
|
||||
</DetailsInfoItem>
|
||||
) }
|
||||
{ data.is_contract && data.implementation_address && (
|
||||
<DetailsInfoItem
|
||||
title="Implementation"
|
||||
hint="Implementation address of the proxy contract"
|
||||
columnGap={ 1 }
|
||||
>
|
||||
<AddressEntity
|
||||
address={{ hash: data.implementation_address, name: data.implementation_name, is_contract: true }}
|
||||
isLoading={ addressQuery.isPlaceholderData }
|
||||
noIcon
|
||||
/>
|
||||
</DetailsInfoItem>
|
||||
) }
|
||||
<AddressBalance data={ data } isLoading={ addressQuery.isPlaceholderData }/>
|
||||
{ data.has_tokens && (
|
||||
<DetailsInfoItem
|
||||
title="Tokens"
|
||||
hint="All tokens in the account and total value"
|
||||
alignSelf="center"
|
||||
py={ 0 }
|
||||
>
|
||||
{ addressQuery.data ? <TokenSelect onClick={ handleCounterItemClick }/> : <Box py="6px">0</Box> }
|
||||
</DetailsInfoItem>
|
||||
) }
|
||||
<DetailsInfoItem
|
||||
title="Transactions"
|
||||
hint="Number of transactions related to this address"
|
||||
isLoading={ addressQuery.isPlaceholderData || countersQuery.isPlaceholderData }
|
||||
<>
|
||||
{ addressQuery.isDegradedData && <ServiceDegradationWarning isLoading={ addressQuery.isPlaceholderData } mb={ 6 }/> }
|
||||
<Grid
|
||||
columnGap={ 8 }
|
||||
rowGap={{ base: 1, lg: 3 }}
|
||||
templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }} overflow="hidden"
|
||||
>
|
||||
{ addressQuery.data ? (
|
||||
<AddressCounterItem
|
||||
prop="transactions_count"
|
||||
query={ countersQuery }
|
||||
address={ data.hash }
|
||||
onClick={ handleCounterItemClick }
|
||||
isAddressQueryLoading={ addressQuery.isPlaceholderData }
|
||||
/>
|
||||
) :
|
||||
0 }
|
||||
</DetailsInfoItem>
|
||||
{ data.has_token_transfers && (
|
||||
<AddressNameInfo data={ data } isLoading={ addressQuery.isPlaceholderData }/>
|
||||
{ data.is_contract && data.creation_tx_hash && data.creator_address_hash && (
|
||||
<DetailsInfoItem
|
||||
title="Creator"
|
||||
hint="Transaction and address of creation"
|
||||
isLoading={ addressQuery.isPlaceholderData }
|
||||
>
|
||||
<AddressEntity
|
||||
address={{ hash: data.creator_address_hash }}
|
||||
truncation="constant"
|
||||
noIcon
|
||||
/>
|
||||
<Text whiteSpace="pre"> at txn </Text>
|
||||
<TxEntity hash={ data.creation_tx_hash } truncation="constant" noIcon noCopy={ false }/>
|
||||
</DetailsInfoItem>
|
||||
) }
|
||||
{ data.is_contract && data.implementation_address && (
|
||||
<DetailsInfoItem
|
||||
title="Implementation"
|
||||
hint="Implementation address of the proxy contract"
|
||||
columnGap={ 1 }
|
||||
>
|
||||
<AddressEntity
|
||||
address={{ hash: data.implementation_address, name: data.implementation_name, is_contract: true }}
|
||||
isLoading={ addressQuery.isPlaceholderData }
|
||||
noIcon
|
||||
/>
|
||||
</DetailsInfoItem>
|
||||
) }
|
||||
<AddressBalance data={ data } isLoading={ addressQuery.isPlaceholderData }/>
|
||||
{ data.has_tokens && (
|
||||
<DetailsInfoItem
|
||||
title="Tokens"
|
||||
hint="All tokens in the account and total value"
|
||||
alignSelf="center"
|
||||
py={ 0 }
|
||||
>
|
||||
{ addressQuery.data ? <TokenSelect onClick={ handleCounterItemClick }/> : <Box py="6px">0</Box> }
|
||||
</DetailsInfoItem>
|
||||
) }
|
||||
<DetailsInfoItem
|
||||
title="Transfers"
|
||||
hint="Number of transfers to/from this address"
|
||||
title="Transactions"
|
||||
hint="Number of transactions related to this address"
|
||||
isLoading={ addressQuery.isPlaceholderData || countersQuery.isPlaceholderData }
|
||||
>
|
||||
{ addressQuery.data ? (
|
||||
<AddressCounterItem
|
||||
prop="token_transfers_count"
|
||||
prop="transactions_count"
|
||||
query={ countersQuery }
|
||||
address={ data.hash }
|
||||
onClick={ handleCounterItemClick }
|
||||
isAddressQueryLoading={ addressQuery.isPlaceholderData }
|
||||
isDegradedData={ addressQuery.isDegradedData }
|
||||
/>
|
||||
) :
|
||||
0 }
|
||||
</DetailsInfoItem>
|
||||
) }
|
||||
<DetailsInfoItem
|
||||
title="Gas used"
|
||||
hint="Gas used by the address"
|
||||
isLoading={ addressQuery.isPlaceholderData || countersQuery.isPlaceholderData }
|
||||
>
|
||||
{ addressQuery.data ? (
|
||||
<AddressCounterItem
|
||||
prop="gas_usage_count"
|
||||
query={ countersQuery }
|
||||
address={ data.hash }
|
||||
onClick={ handleCounterItemClick }
|
||||
isAddressQueryLoading={ addressQuery.isPlaceholderData }
|
||||
/>
|
||||
) :
|
||||
0 }
|
||||
</DetailsInfoItem>
|
||||
{ data.has_validated_blocks && (
|
||||
<DetailsInfoItem
|
||||
title="Blocks validated"
|
||||
hint="Number of blocks validated by this validator"
|
||||
isLoading={ addressQuery.isPlaceholderData || countersQuery.isPlaceholderData }
|
||||
>
|
||||
{ addressQuery.data ? (
|
||||
<AddressCounterItem
|
||||
prop="validations_count"
|
||||
query={ countersQuery }
|
||||
address={ data.hash }
|
||||
onClick={ handleCounterItemClick }
|
||||
isAddressQueryLoading={ addressQuery.isPlaceholderData }
|
||||
/>
|
||||
) :
|
||||
0 }
|
||||
</DetailsInfoItem>
|
||||
) }
|
||||
{ data.block_number_balance_updated_at && (
|
||||
<DetailsInfoItem
|
||||
title="Last balance update"
|
||||
hint="Block number in which the address was updated"
|
||||
alignSelf="center"
|
||||
py={{ base: '2px', lg: 1 }}
|
||||
isLoading={ addressQuery.isPlaceholderData }
|
||||
>
|
||||
<BlockEntity
|
||||
number={ data.block_number_balance_updated_at }
|
||||
{ data.has_token_transfers && (
|
||||
<DetailsInfoItem
|
||||
title="Transfers"
|
||||
hint="Number of transfers to/from this address"
|
||||
isLoading={ addressQuery.isPlaceholderData || countersQuery.isPlaceholderData }
|
||||
>
|
||||
{ addressQuery.data ? (
|
||||
<AddressCounterItem
|
||||
prop="token_transfers_count"
|
||||
query={ countersQuery }
|
||||
address={ data.hash }
|
||||
onClick={ handleCounterItemClick }
|
||||
isAddressQueryLoading={ addressQuery.isPlaceholderData }
|
||||
isDegradedData={ addressQuery.isDegradedData }
|
||||
/>
|
||||
) :
|
||||
0 }
|
||||
</DetailsInfoItem>
|
||||
) }
|
||||
{ countersQuery.data?.gas_usage_count && (
|
||||
<DetailsInfoItem
|
||||
title="Gas used"
|
||||
hint="Gas used by the address"
|
||||
isLoading={ addressQuery.isPlaceholderData || countersQuery.isPlaceholderData }
|
||||
>
|
||||
{ addressQuery.data ? (
|
||||
<AddressCounterItem
|
||||
prop="gas_usage_count"
|
||||
query={ countersQuery }
|
||||
address={ data.hash }
|
||||
onClick={ handleCounterItemClick }
|
||||
isAddressQueryLoading={ addressQuery.isPlaceholderData }
|
||||
isDegradedData={ addressQuery.isDegradedData }
|
||||
/>
|
||||
) :
|
||||
0 }
|
||||
</DetailsInfoItem>
|
||||
) }
|
||||
{ data.has_validated_blocks && (
|
||||
<DetailsInfoItem
|
||||
title="Blocks validated"
|
||||
hint="Number of blocks validated by this validator"
|
||||
isLoading={ addressQuery.isPlaceholderData || countersQuery.isPlaceholderData }
|
||||
>
|
||||
{ addressQuery.data ? (
|
||||
<AddressCounterItem
|
||||
prop="validations_count"
|
||||
query={ countersQuery }
|
||||
address={ data.hash }
|
||||
onClick={ handleCounterItemClick }
|
||||
isAddressQueryLoading={ addressQuery.isPlaceholderData }
|
||||
isDegradedData={ addressQuery.isDegradedData }
|
||||
/>
|
||||
) :
|
||||
0 }
|
||||
</DetailsInfoItem>
|
||||
) }
|
||||
{ data.block_number_balance_updated_at && (
|
||||
<DetailsInfoItem
|
||||
title="Last balance update"
|
||||
hint="Block number in which the address was updated"
|
||||
alignSelf="center"
|
||||
py={{ base: '2px', lg: 1 }}
|
||||
isLoading={ addressQuery.isPlaceholderData }
|
||||
/>
|
||||
</DetailsInfoItem>
|
||||
) }
|
||||
<DetailsSponsoredItem isLoading={ addressQuery.isPlaceholderData }/>
|
||||
</Grid>
|
||||
>
|
||||
<BlockEntity
|
||||
number={ data.block_number_balance_updated_at }
|
||||
isLoading={ addressQuery.isPlaceholderData }
|
||||
/>
|
||||
</DetailsInfoItem>
|
||||
) }
|
||||
<DetailsSponsoredItem isLoading={ addressQuery.isPlaceholderData }/>
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ test.describe('socket', () => {
|
||||
},
|
||||
};
|
||||
|
||||
const API_URL_NO_TOKEN = buildApiUrl('address_token_transfers', { hash: CURRENT_ADDRESS });
|
||||
const API_URL_NO_TOKEN = buildApiUrl('address_token_transfers', { hash: CURRENT_ADDRESS }) + '?type=';
|
||||
|
||||
await page.route(API_URL_NO_TOKEN, (route) => route.fulfill({
|
||||
status: 200,
|
||||
@@ -144,7 +144,7 @@ test.describe('socket', () => {
|
||||
},
|
||||
};
|
||||
|
||||
const API_URL_NO_TOKEN = buildApiUrl('address_token_transfers', { hash: CURRENT_ADDRESS });
|
||||
const API_URL_NO_TOKEN = buildApiUrl('address_token_transfers', { hash: CURRENT_ADDRESS }) + '?type=';
|
||||
|
||||
await page.route(API_URL_NO_TOKEN, (route) => route.fulfill({
|
||||
status: 200,
|
||||
|
||||
@@ -13,8 +13,8 @@ import AddressTokens from './AddressTokens';
|
||||
const ADDRESS_HASH = addressMock.withName.hash;
|
||||
const API_URL_ADDRESS = buildApiUrl('address', { hash: ADDRESS_HASH });
|
||||
const API_URL_TOKENS = buildApiUrl('address_tokens', { hash: ADDRESS_HASH });
|
||||
const API_URL_NFT = buildApiUrl('address_nfts', { hash: ADDRESS_HASH });
|
||||
const API_URL_COLLECTIONS = buildApiUrl('address_collections', { hash: ADDRESS_HASH });
|
||||
const API_URL_NFT = buildApiUrl('address_nfts', { hash: ADDRESS_HASH }) + '?type=';
|
||||
const API_URL_COLLECTIONS = buildApiUrl('address_collections', { hash: ADDRESS_HASH }) + '?type=';
|
||||
|
||||
const nextPageParams = {
|
||||
items_count: 50,
|
||||
|
||||
@@ -9,8 +9,8 @@ import ActionBar from 'ui/shared/ActionBar';
|
||||
import DataListDisplay from 'ui/shared/DataListDisplay';
|
||||
import Pagination from 'ui/shared/pagination/Pagination';
|
||||
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
|
||||
import WithdrawalsListItem from 'ui/withdrawals/WithdrawalsListItem';
|
||||
import WithdrawalsTable from 'ui/withdrawals/WithdrawalsTable';
|
||||
import BeaconChainWithdrawalsListItem from 'ui/withdrawals/beaconChain/BeaconChainWithdrawalsListItem';
|
||||
import BeaconChainWithdrawalsTable from 'ui/withdrawals/beaconChain/BeaconChainWithdrawalsTable';
|
||||
|
||||
const AddressWithdrawals = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivElement>}) => {
|
||||
const router = useRouter();
|
||||
@@ -32,7 +32,7 @@ const AddressWithdrawals = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivE
|
||||
<>
|
||||
<Show below="lg" ssr={ false }>
|
||||
{ data.items.map((item, index) => (
|
||||
<WithdrawalsListItem
|
||||
<BeaconChainWithdrawalsListItem
|
||||
key={ item.index + Number(isPlaceholderData ? index : '') }
|
||||
item={ item }
|
||||
view="address"
|
||||
@@ -41,7 +41,7 @@ const AddressWithdrawals = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivE
|
||||
)) }
|
||||
</Show>
|
||||
<Hide below="lg" ssr={ false }>
|
||||
<WithdrawalsTable items={ data.items } view="address" top={ pagination.isVisible ? 80 : 0 } isLoading={ isPlaceholderData }/>
|
||||
<BeaconChainWithdrawalsTable items={ data.items } view="address" top={ pagination.isVisible ? 80 : 0 } isLoading={ isPlaceholderData }/>
|
||||
</Hide>
|
||||
</>
|
||||
) : null ;
|
||||
|
||||
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 54 KiB |
@@ -2,6 +2,7 @@ import { Checkbox, Flex, chakra } from '@chakra-ui/react';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import React from 'react';
|
||||
import { getAddress } from 'viem';
|
||||
|
||||
import type { SmartContractMethodOutput } from 'types/api/contract';
|
||||
|
||||
@@ -50,7 +51,7 @@ const ContractMethodStatic = ({ data }: Props) => {
|
||||
if (typeof data.value === 'string' && data.type === 'address' && data.value) {
|
||||
return (
|
||||
<AddressEntity
|
||||
address={{ hash: data.value }}
|
||||
address={{ hash: getAddress(data.value) }}
|
||||
noIcon
|
||||
/>
|
||||
);
|
||||
|
||||
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
@@ -16,6 +16,7 @@ interface Props {
|
||||
address: string;
|
||||
onClick: () => void;
|
||||
isAddressQueryLoading: boolean;
|
||||
isDegradedData: boolean;
|
||||
}
|
||||
|
||||
const PROP_TO_TAB = {
|
||||
@@ -24,7 +25,7 @@ const PROP_TO_TAB = {
|
||||
validations_count: 'blocks_validated',
|
||||
};
|
||||
|
||||
const AddressCounterItem = ({ prop, query, address, onClick, isAddressQueryLoading }: Props) => {
|
||||
const AddressCounterItem = ({ prop, query, address, onClick, isAddressQueryLoading, isDegradedData }: Props) => {
|
||||
if (query.isPlaceholderData || isAddressQueryLoading) {
|
||||
return <Skeleton h={ 5 } w="80px" borderRadius="full"/>;
|
||||
}
|
||||
@@ -44,6 +45,11 @@ const AddressCounterItem = ({ prop, query, address, onClick, isAddressQueryLoadi
|
||||
if (data === '0') {
|
||||
return <span>0</span>;
|
||||
}
|
||||
|
||||
if (isDegradedData) {
|
||||
return <span>{ Number(data).toLocaleString() }</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<LinkInternal href={ route({ pathname: '/address/[hash]', query: { hash: address, tab: PROP_TO_TAB[prop] } }) } onClick={ onClick }>
|
||||
{ Number(data).toLocaleString() }
|
||||
|
||||
@@ -45,7 +45,7 @@ const TxInternalsListItem = ({
|
||||
hash={ txnHash }
|
||||
isLoading={ isLoading }
|
||||
fontWeight={ 700 }
|
||||
truncation="constant"
|
||||
truncation="constant_long"
|
||||
/>
|
||||
<Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight="400" fontSize="sm">
|
||||
<span>{ dayjs(timestamp).fromNow() }</span>
|
||||
|
||||
@@ -43,6 +43,7 @@ const AddressIntTxsTableItem = ({
|
||||
isLoading={ isLoading }
|
||||
fontWeight={ 700 }
|
||||
noIcon
|
||||
truncation="constant_long"
|
||||
/>
|
||||
{ timestamp && (
|
||||
<Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight="400" fontSize="sm">
|
||||
|
||||
@@ -43,6 +43,7 @@ const ERC20TokensTableItem = ({
|
||||
<AddressEntity
|
||||
address={{ hash: token.address }}
|
||||
isLoading={ isLoading }
|
||||
truncation="constant"
|
||||
noIcon
|
||||
/>
|
||||
<AddressAddToWallet token={ token } ml={ 4 } isLoading={ isLoading } opacity="0"/>
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import type { UseQueryResult } from '@tanstack/react-query';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import type { AddressCounters } from 'types/api/address';
|
||||
|
||||
import type { ResourceError } from 'lib/api/resources';
|
||||
import useApiQuery from 'lib/api/useApiQuery';
|
||||
import { publicClient } from 'lib/web3/client';
|
||||
import { ADDRESS_COUNTERS } from 'stubs/address';
|
||||
import { GET_TRANSACTIONS_COUNT } from 'stubs/RPC';
|
||||
|
||||
import type { AddressQuery } from './useAddressQuery';
|
||||
|
||||
type RpcResponseType = [
|
||||
number | null,
|
||||
];
|
||||
|
||||
export type AddressCountersQuery = UseQueryResult<AddressCounters, ResourceError<{ status: number }>> & {
|
||||
isDegradedData: boolean;
|
||||
};
|
||||
|
||||
interface Params {
|
||||
hash: string;
|
||||
addressQuery: AddressQuery;
|
||||
}
|
||||
|
||||
export default function useAddressQuery({ hash, addressQuery }: Params): AddressCountersQuery {
|
||||
const enabled = Boolean(hash) && !addressQuery.isPlaceholderData;
|
||||
|
||||
const apiQuery = useApiQuery<'address_counters', { status: number }>('address_counters', {
|
||||
pathParams: { hash },
|
||||
queryOptions: {
|
||||
enabled: enabled && !addressQuery.isDegradedData,
|
||||
placeholderData: ADDRESS_COUNTERS,
|
||||
refetchOnMount: false,
|
||||
},
|
||||
});
|
||||
|
||||
const rpcQuery = useQuery<RpcResponseType, unknown, AddressCounters | null>({
|
||||
queryKey: [ 'RPC', 'address_counters', { hash } ],
|
||||
queryFn: async() => {
|
||||
const txCount = publicClient.getTransactionCount({ address: hash as `0x${ string }` }).catch(() => null);
|
||||
|
||||
return Promise.all([
|
||||
txCount,
|
||||
]);
|
||||
},
|
||||
select: (response) => {
|
||||
const [ txCount ] = response;
|
||||
return {
|
||||
transactions_count: txCount?.toString() ?? '0',
|
||||
token_transfers_count: '0',
|
||||
gas_usage_count: null,
|
||||
validations_count: null,
|
||||
};
|
||||
},
|
||||
placeholderData: [ GET_TRANSACTIONS_COUNT ],
|
||||
enabled: enabled && (addressQuery.isDegradedData || apiQuery.isError),
|
||||
retry: false,
|
||||
refetchOnMount: false,
|
||||
});
|
||||
|
||||
const isRpcQuery = Boolean((addressQuery.isDegradedData || apiQuery.isError) && rpcQuery.data);
|
||||
const query = isRpcQuery ? rpcQuery as UseQueryResult<AddressCounters, ResourceError<{ status: number }>> : apiQuery;
|
||||
|
||||
return {
|
||||
...query,
|
||||
isDegradedData: isRpcQuery,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import type { UseQueryResult } from '@tanstack/react-query';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import React from 'react';
|
||||
|
||||
import type { Address } from 'types/api/address';
|
||||
|
||||
import type { ResourceError } from 'lib/api/resources';
|
||||
import useApiQuery from 'lib/api/useApiQuery';
|
||||
import { retry } from 'lib/api/useQueryClientConfig';
|
||||
import { SECOND } from 'lib/consts';
|
||||
import { publicClient } from 'lib/web3/client';
|
||||
import { ADDRESS_INFO } from 'stubs/address';
|
||||
import { GET_BALANCE } from 'stubs/RPC';
|
||||
|
||||
type RpcResponseType = [
|
||||
bigint | null,
|
||||
];
|
||||
|
||||
export type AddressQuery = UseQueryResult<Address, ResourceError<{ status: number }>> & {
|
||||
isDegradedData: boolean;
|
||||
};
|
||||
|
||||
interface Params {
|
||||
hash: string;
|
||||
}
|
||||
|
||||
export default function useAddressQuery({ hash }: Params): AddressQuery {
|
||||
const [ isRefetchEnabled, setRefetchEnabled ] = React.useState(false);
|
||||
|
||||
const apiQuery = useApiQuery<'address', { status: number }>('address', {
|
||||
pathParams: { hash },
|
||||
queryOptions: {
|
||||
enabled: Boolean(hash),
|
||||
placeholderData: ADDRESS_INFO,
|
||||
refetchOnMount: false,
|
||||
retry: (failureCount, error) => {
|
||||
if (isRefetchEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return retry(failureCount, error);
|
||||
},
|
||||
refetchInterval: (): number | false => {
|
||||
return isRefetchEnabled ? 15 * SECOND : false;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const rpcQuery = useQuery<RpcResponseType, unknown, Address | null>({
|
||||
queryKey: [ 'RPC', 'address', { hash } ],
|
||||
queryFn: async() => {
|
||||
if (!publicClient) {
|
||||
throw new Error('No public RPC client');
|
||||
}
|
||||
|
||||
const balance = publicClient.getBalance({ address: hash as `0x${ string }` }).catch(() => null);
|
||||
|
||||
return Promise.all([
|
||||
balance,
|
||||
]);
|
||||
},
|
||||
select: (response) => {
|
||||
const [ balance ] = response;
|
||||
|
||||
if (!balance) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
hash,
|
||||
block_number_balance_updated_at: null,
|
||||
coin_balance: balance.toString(),
|
||||
creator_address_hash: null,
|
||||
creation_tx_hash: null,
|
||||
exchange_rate: null,
|
||||
ens_domain_name: null,
|
||||
has_custom_methods_read: false,
|
||||
has_custom_methods_write: false,
|
||||
has_decompiled_code: false,
|
||||
has_logs: false,
|
||||
has_methods_read: false,
|
||||
has_methods_read_proxy: false,
|
||||
has_methods_write: false,
|
||||
has_methods_write_proxy: false,
|
||||
has_token_transfers: false,
|
||||
has_tokens: false,
|
||||
has_validated_blocks: false,
|
||||
implementation_address: null,
|
||||
implementation_name: null,
|
||||
is_contract: false,
|
||||
is_verified: false,
|
||||
name: null,
|
||||
token: null,
|
||||
watchlist_address_id: null,
|
||||
private_tags: null,
|
||||
public_tags: null,
|
||||
watchlist_names: null,
|
||||
};
|
||||
},
|
||||
placeholderData: [ GET_BALANCE ],
|
||||
enabled: apiQuery.isError || apiQuery.errorUpdateCount > 0,
|
||||
retry: false,
|
||||
refetchOnMount: false,
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
if (apiQuery.isPlaceholderData || !publicClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (apiQuery.isError && apiQuery.errorUpdateCount === 1) {
|
||||
setRefetchEnabled(true);
|
||||
} else if (!apiQuery.isError) {
|
||||
setRefetchEnabled(false);
|
||||
}
|
||||
}, [ apiQuery.errorUpdateCount, apiQuery.isError, apiQuery.isPlaceholderData ]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!rpcQuery.isPlaceholderData && !rpcQuery.data) {
|
||||
setRefetchEnabled(false);
|
||||
}
|
||||
}, [ rpcQuery.data, rpcQuery.isPlaceholderData ]);
|
||||
|
||||
const isRpcQuery = Boolean((apiQuery.isError || apiQuery.isPlaceholderData) && apiQuery.errorUpdateCount > 0 && rpcQuery.data && publicClient);
|
||||
const query = isRpcQuery ? rpcQuery as UseQueryResult<Address, ResourceError<{ status: number }>> : apiQuery;
|
||||
|
||||
return {
|
||||
...query,
|
||||
isDegradedData: isRpcQuery,
|
||||
};
|
||||
}
|
||||
@@ -157,7 +157,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
|
||||
}
|
||||
case 'INVALID_SIGNER_ERROR': {
|
||||
const signer = shortenString(formState.errors.root.message || '');
|
||||
const expectedSigners = [ contractCreator, contractOwner ].filter(Boolean).map(shortenString).join(', ');
|
||||
const expectedSigners = [ contractCreator, contractOwner ].filter(Boolean).map(s => shortenString(s)).join(', ');
|
||||
return (
|
||||
<Box>
|
||||
<span>This address </span>
|
||||
|
||||
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
@@ -35,6 +35,7 @@ const AddressesListItem = ({
|
||||
isLoading={ isLoading }
|
||||
fontWeight={ 700 }
|
||||
mr={ 2 }
|
||||
truncation="constant"
|
||||
/>
|
||||
<Skeleton isLoaded={ !isLoading } fontSize="sm" ml="auto" minW={ 6 } color="text_secondary">
|
||||
<span>{ index }</span>
|
||||
|
||||
@@ -34,7 +34,7 @@ interface Props {
|
||||
query: BlockQuery;
|
||||
}
|
||||
|
||||
const isRollup = config.features.optimisticRollup.isEnabled || config.features.zkEvmRollup.isEnabled;
|
||||
const rollupFeature = config.features.rollup;
|
||||
|
||||
const BlockDetails = ({ query }: Props) => {
|
||||
const [ isExpanded, setIsExpanded ] = React.useState(false);
|
||||
@@ -73,7 +73,7 @@ const BlockDetails = ({ query }: Props) => {
|
||||
const validatorTitle = getNetworkValidatorTitle();
|
||||
|
||||
const rewardBreakDown = (() => {
|
||||
if (isRollup || totalReward.isEqualTo(ZERO) || txFees.isEqualTo(ZERO) || burntFees.isEqualTo(ZERO)) {
|
||||
if (rollupFeature.isEnabled || totalReward.isEqualTo(ZERO) || txFees.isEqualTo(ZERO) || burntFees.isEqualTo(ZERO)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ const BlockDetails = ({ query }: Props) => {
|
||||
})();
|
||||
|
||||
const verificationTitle = (() => {
|
||||
if (config.features.zkEvmRollup.isEnabled) {
|
||||
if (rollupFeature.isEnabled && rollupFeature.type === 'zkEvm') {
|
||||
return 'Sequenced by';
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ const BlockDetails = ({ query }: Props) => {
|
||||
{ /* <Text>{ dayjs.duration(block.minedIn, 'second').humanize(true) }</Text> */ }
|
||||
</DetailsInfoItem>
|
||||
) }
|
||||
{ !isRollup && !totalReward.isEqualTo(ZERO) && !config.UI.views.block.hiddenFields?.total_reward && (
|
||||
{ !rollupFeature.isEnabled && !totalReward.isEqualTo(ZERO) && !config.UI.views.block.hiddenFields?.total_reward && (
|
||||
<DetailsInfoItem
|
||||
title="Block reward"
|
||||
hint={
|
||||
|
||||
@@ -3,8 +3,8 @@ import React from 'react';
|
||||
|
||||
import DataListDisplay from 'ui/shared/DataListDisplay';
|
||||
import type { QueryWithPagesResult } from 'ui/shared/pagination/useQueryWithPages';
|
||||
import WithdrawalsList from 'ui/withdrawals/WithdrawalsList';
|
||||
import WithdrawalsTable from 'ui/withdrawals/WithdrawalsTable';
|
||||
import BeaconChainWithdrawalsList from 'ui/withdrawals/beaconChain/BeaconChainWithdrawalsList';
|
||||
import BeaconChainWithdrawalsTable from 'ui/withdrawals/beaconChain/BeaconChainWithdrawalsTable';
|
||||
|
||||
type Props = {
|
||||
blockWithdrawalsQuery: QueryWithPagesResult<'block_withdrawals'>;
|
||||
@@ -14,14 +14,14 @@ const BlockWithdrawals = ({ blockWithdrawalsQuery }: Props) => {
|
||||
const content = blockWithdrawalsQuery.data?.items ? (
|
||||
<>
|
||||
<Show below="lg" ssr={ false }>
|
||||
<WithdrawalsList
|
||||
<BeaconChainWithdrawalsList
|
||||
items={ blockWithdrawalsQuery.data.items }
|
||||
isLoading={ blockWithdrawalsQuery.isPlaceholderData }
|
||||
view="block"
|
||||
/>
|
||||
</Show>
|
||||
<Hide below="lg" ssr={ false }>
|
||||
<WithdrawalsTable
|
||||
<BeaconChainWithdrawalsTable
|
||||
items={ blockWithdrawalsQuery.data.items }
|
||||
isLoading={ blockWithdrawalsQuery.isPlaceholderData }
|
||||
top={ blockWithdrawalsQuery.pagination.isVisible ? 80 : 0 }
|
||||
|
||||
@@ -28,7 +28,7 @@ interface Props {
|
||||
enableTimeIncrement?: boolean;
|
||||
}
|
||||
|
||||
const isRollup = config.features.optimisticRollup.isEnabled || config.features.zkEvmRollup.isEnabled;
|
||||
const isRollup = config.features.rollup.isEnabled;
|
||||
|
||||
const BlocksListItem = ({ data, isLoading, enableTimeIncrement }: Props) => {
|
||||
const totalReward = getBlockTotalReward(data);
|
||||
@@ -63,6 +63,7 @@ const BlocksListItem = ({ data, isLoading, enableTimeIncrement }: Props) => {
|
||||
<AddressEntity
|
||||
address={ data.miner }
|
||||
isLoading={ isLoading }
|
||||
truncation="constant"
|
||||
/>
|
||||
</Flex>
|
||||
) }
|
||||
|
||||
@@ -28,7 +28,7 @@ const GAS_COL_WEIGHT = 33;
|
||||
const REWARD_COL_WEIGHT = 22;
|
||||
const FEES_COL_WEIGHT = 22;
|
||||
|
||||
const isRollup = config.features.optimisticRollup.isEnabled || config.features.zkEvmRollup.isEnabled;
|
||||
const isRollup = config.features.rollup.isEnabled;
|
||||
|
||||
const BlocksTable = ({ data, isLoading, top, page, showSocketInfo, socketInfoNum, socketInfoAlert }: Props) => {
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ interface Props {
|
||||
enableTimeIncrement?: boolean;
|
||||
}
|
||||
|
||||
const isRollup = config.features.optimisticRollup.isEnabled || config.features.zkEvmRollup.isEnabled;
|
||||
const isRollup = config.features.rollup.isEnabled;
|
||||
|
||||
const BlocksTableItem = ({ data, isLoading, enableTimeIncrement }: Props) => {
|
||||
const totalReward = getBlockTotalReward(data);
|
||||
@@ -70,6 +70,7 @@ const BlocksTableItem = ({ data, isLoading, enableTimeIncrement }: Props) => {
|
||||
<AddressEntity
|
||||
address={ data.miner }
|
||||
isLoading={ isLoading }
|
||||
truncation="constant"
|
||||
/>
|
||||
</Td>
|
||||
) }
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Skeleton } from '@chakra-ui/react';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import React from 'react';
|
||||
|
||||
import type { L2DepositsItem } from 'types/api/l2Deposits';
|
||||
import type { OptimisticL2DepositsItem } from 'types/api/optimisticL2';
|
||||
|
||||
import config from 'configs/app';
|
||||
import dayjs from 'lib/date/dayjs';
|
||||
@@ -12,14 +12,14 @@ import TxEntity from 'ui/shared/entities/tx/TxEntity';
|
||||
import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
|
||||
import ListItemMobileGrid from 'ui/shared/ListItemMobile/ListItemMobileGrid';
|
||||
|
||||
const feature = config.features.optimisticRollup;
|
||||
const rollupFeature = config.features.rollup;
|
||||
|
||||
type Props = { item: L2DepositsItem; isLoading?: boolean };
|
||||
type Props = { item: OptimisticL2DepositsItem; isLoading?: boolean };
|
||||
|
||||
const DepositsListItem = ({ item, isLoading }: Props) => {
|
||||
const OptimisticDepositsListItem = ({ item, isLoading }: Props) => {
|
||||
const timeAgo = dayjs(item.l1_block_timestamp).fromNow();
|
||||
|
||||
if (!feature.isEnabled) {
|
||||
if (!rollupFeature.isEnabled || rollupFeature.type !== 'optimistic') {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ const DepositsListItem = ({ item, isLoading }: Props) => {
|
||||
hash={ item.l2_tx_hash }
|
||||
fontSize="sm"
|
||||
lineHeight={ 5 }
|
||||
truncation="constant_long"
|
||||
/>
|
||||
</ListItemMobileGrid.Value>
|
||||
|
||||
@@ -59,6 +60,7 @@ const DepositsListItem = ({ item, isLoading }: Props) => {
|
||||
hash={ item.l1_tx_hash }
|
||||
fontSize="sm"
|
||||
lineHeight={ 5 }
|
||||
truncation="constant_long"
|
||||
/>
|
||||
</ListItemMobileGrid.Value>
|
||||
|
||||
@@ -68,6 +70,7 @@ const DepositsListItem = ({ item, isLoading }: Props) => {
|
||||
address={{ hash: item.l1_tx_origin, name: '', is_contract: false, is_verified: false, implementation_name: '', ens_domain_name: null }}
|
||||
isLoading={ isLoading }
|
||||
noCopy
|
||||
truncation="constant"
|
||||
/>
|
||||
</ListItemMobileGrid.Value>
|
||||
|
||||
@@ -80,4 +83,4 @@ const DepositsListItem = ({ item, isLoading }: Props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default DepositsListItem;
|
||||
export default OptimisticDepositsListItem;
|
||||
@@ -1,19 +1,19 @@
|
||||
import { Table, Tbody, Th, Tr } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import type { L2DepositsItem } from 'types/api/l2Deposits';
|
||||
import type { OptimisticL2DepositsItem } from 'types/api/optimisticL2';
|
||||
|
||||
import { default as Thead } from 'ui/shared/TheadSticky';
|
||||
|
||||
import DepositsTableItem from './DepositsTableItem';
|
||||
import OptimisticDepositsTableItem from './OptimisticDepositsTableItem';
|
||||
|
||||
type Props = {
|
||||
items: Array<L2DepositsItem>;
|
||||
items: Array<OptimisticL2DepositsItem>;
|
||||
top: number;
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
const DepositsTable = ({ items, top, isLoading }: Props) => {
|
||||
const OptimisticDepositsTable = ({ items, top, isLoading }: Props) => {
|
||||
return (
|
||||
<Table variant="simple" size="sm" style={{ tableLayout: 'auto' }} minW="950px">
|
||||
<Thead top={ top }>
|
||||
@@ -28,11 +28,11 @@ const DepositsTable = ({ items, top, isLoading }: Props) => {
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{ items.map((item, index) => (
|
||||
<DepositsTableItem key={ item.l2_tx_hash + (isLoading ? index : '') } item={ item } isLoading={ isLoading }/>
|
||||
<OptimisticDepositsTableItem key={ item.l2_tx_hash + (isLoading ? index : '') } item={ item } isLoading={ isLoading }/>
|
||||
)) }
|
||||
</Tbody>
|
||||
</Table>
|
||||
);
|
||||
};
|
||||
|
||||
export default DepositsTable;
|
||||
export default OptimisticDepositsTable;
|
||||
@@ -2,7 +2,7 @@ import { Td, Tr, Skeleton } from '@chakra-ui/react';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import React from 'react';
|
||||
|
||||
import type { L2DepositsItem } from 'types/api/l2Deposits';
|
||||
import type { OptimisticL2DepositsItem } from 'types/api/optimisticL2';
|
||||
|
||||
import config from 'configs/app';
|
||||
import dayjs from 'lib/date/dayjs';
|
||||
@@ -11,14 +11,14 @@ import BlockEntityL1 from 'ui/shared/entities/block/BlockEntityL1';
|
||||
import TxEntity from 'ui/shared/entities/tx/TxEntity';
|
||||
import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
|
||||
|
||||
const feature = config.features.optimisticRollup;
|
||||
const rollupFeature = config.features.rollup;
|
||||
|
||||
type Props = { item: L2DepositsItem; isLoading?: boolean };
|
||||
type Props = { item: OptimisticL2DepositsItem; isLoading?: boolean };
|
||||
|
||||
const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
|
||||
const OptimisticDepositsTableItem = ({ item, isLoading }: Props) => {
|
||||
const timeAgo = dayjs(item.l1_block_timestamp).fromNow();
|
||||
|
||||
if (!feature.isEnabled) {
|
||||
if (!rollupFeature.isEnabled || rollupFeature.type !== 'optimistic') {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
|
||||
fontSize="sm"
|
||||
lineHeight={ 5 }
|
||||
fontWeight={ 600 }
|
||||
noIcon
|
||||
/>
|
||||
</Td>
|
||||
<Td verticalAlign="middle">
|
||||
@@ -39,7 +40,8 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
|
||||
hash={ item.l2_tx_hash }
|
||||
fontSize="sm"
|
||||
lineHeight={ 5 }
|
||||
truncation="constant"
|
||||
truncation="constant_long"
|
||||
noIcon
|
||||
/>
|
||||
</Td>
|
||||
<Td verticalAlign="middle" pr={ 12 }>
|
||||
@@ -49,7 +51,8 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
|
||||
<TxEntityL1
|
||||
isLoading={ isLoading }
|
||||
hash={ item.l1_tx_hash }
|
||||
truncation="constant"
|
||||
truncation="constant_long"
|
||||
noIcon
|
||||
fontSize="sm"
|
||||
lineHeight={ 5 }
|
||||
/>
|
||||
@@ -71,4 +74,4 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default WithdrawalsTableItem;
|
||||
export default OptimisticDepositsTableItem;
|
||||
@@ -24,7 +24,7 @@ const LatestBlocks = () => {
|
||||
const isMobile = useIsMobile();
|
||||
// const blocksMaxCount = isMobile ? 2 : 3;
|
||||
let blocksMaxCount: number;
|
||||
if (config.features.optimisticRollup.isEnabled || config.UI.views.block.hiddenFields?.total_reward) {
|
||||
if (config.features.rollup.isEnabled || config.UI.views.block.hiddenFields?.total_reward) {
|
||||
blocksMaxCount = isMobile ? 4 : 5;
|
||||
} else {
|
||||
blocksMaxCount = isMobile ? 2 : 3;
|
||||
|
||||
@@ -59,14 +59,14 @@ const LatestBlocksItem = ({ block, isLoading }: Props) => {
|
||||
<Skeleton isLoaded={ !isLoading }>Txn</Skeleton>
|
||||
<Skeleton isLoaded={ !isLoading } color="text_secondary"><span>{ block.tx_count }</span></Skeleton>
|
||||
|
||||
{ !config.features.optimisticRollup.isEnabled && !config.UI.views.block.hiddenFields?.total_reward && (
|
||||
{ !config.features.rollup.isEnabled && !config.UI.views.block.hiddenFields?.total_reward && (
|
||||
<>
|
||||
<Skeleton isLoaded={ !isLoading }>Reward</Skeleton>
|
||||
<Skeleton isLoaded={ !isLoading } color="text_secondary"><span>{ totalReward.dp(10).toFixed() }</span></Skeleton>
|
||||
</>
|
||||
) }
|
||||
|
||||
{ !config.features.optimisticRollup.isEnabled && !config.UI.views.block.hiddenFields?.miner && (
|
||||
{ !config.features.rollup.isEnabled && !config.UI.views.block.hiddenFields?.miner && (
|
||||
<>
|
||||
<Skeleton isLoaded={ !isLoading } textTransform="capitalize">{ getNetworkValidatorTitle() }</Skeleton>
|
||||
<AddressEntity
|
||||
@@ -74,6 +74,7 @@ const LatestBlocksItem = ({ block, isLoading }: Props) => {
|
||||
isLoading={ isLoading }
|
||||
noIcon
|
||||
noCopy
|
||||
truncation="constant"
|
||||
/>
|
||||
</>
|
||||
) }
|
||||
|
||||