Merge branch 'marketplace-admin-api' into suggest-ideas-button

This commit is contained in:
Max Alekseenko
2024-02-13 15:00:01 +01:00
266 changed files with 2611 additions and 788 deletions
+57 -3
View File
@@ -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 }}
+1
View File
@@ -51,5 +51,6 @@ yarn-error.log*
/playwright/.cache/
/playwright/.browser/
/playwright/envs.js
/playwright/affected-tests.txt
**.dec**
+22
View File
@@ -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": ""
+2 -2
View File
@@ -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';
+1 -2
View File
@@ -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';
-30
View File
@@ -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;
+35
View File
@@ -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;
-25
View File
@@ -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;
+1
View File
@@ -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
-2
View File
@@ -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
+3 -3
View File
@@ -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
+48
View File
@@ -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/
-2
View File
@@ -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
+2 -2
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
/node_modules
+206
View File
@@ -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();
+10
View File
@@ -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"
}
}
+716
View File
@@ -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==
+9 -11
View File
@@ -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'),
}),
});
+3 -3
View File
@@ -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
+3 -3
View File
@@ -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
+3 -3
View File
@@ -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:
+8
View File
@@ -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 |
+8 -17
View File
@@ -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
&nbsp;
### 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'` |
&nbsp;
### 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` |
&nbsp;
@@ -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` |
+1 -1
View File
@@ -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', () => {
+1 -7
View File
@@ -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();
+33 -10
View File
@@ -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 */
+4 -2
View File
@@ -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,
+4 -1
View File
@@ -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);
}
+3 -3
View File
@@ -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);
}
+1 -1
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
import type { ZkEvmL2TxnBatchesResponse } from 'types/api/zkEvmL2TxnBatches';
import type { ZkEvmL2TxnBatchesResponse } from 'types/api/zkEvmL2';
export const txnBatchesData: ZkEvmL2TxnBatchesResponse = {
items: [
+23 -1
View File
@@ -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',
],
};
+8 -4
View File
@@ -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,
};
+1 -1
View File
@@ -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 }>
+2
View File
@@ -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",
+10 -3
View File
@@ -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 = () => {
+1 -1
View File
@@ -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 (
+1 -1
View File
@@ -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 (
+9 -3
View File
@@ -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 = () => {
+6 -6
View File
@@ -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' },
+10 -8
View File
@@ -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,
+4
View File
@@ -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 -1
View File
@@ -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';
+67 -1
View File
@@ -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
+1 -1
View File
@@ -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;
}
-17
View File
@@ -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;
};
}
-16
View File
@@ -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;
};
}
-15
View File
@@ -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;
};
}
-30
View File
@@ -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;
};
}
+81
View File
@@ -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 -2
View File
@@ -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 -1
View File
@@ -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;
+8
View File
@@ -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>;
+4 -7
View File
@@ -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 },
);
+132 -129
View File
@@ -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>
</>
);
};
+2 -2
View File
@@ -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,
+2 -2
View File
@@ -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,
+4 -4
View File
@@ -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 ;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

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
/>
);
Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

+7 -1
View File
@@ -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,
};
}
+131
View File
@@ -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>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 73 KiB

+1
View File
@@ -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>
+4 -4
View File
@@ -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={
+4 -4
View File
@@ -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 }
+2 -1
View File
@@ -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>
) }
+1 -1
View File
@@ -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) => {
+2 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+3 -2
View File
@@ -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"
/>
</>
) }

Some files were not shown because too many files have changed in this diff Show More