Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Advanced filter #1905

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions configs/app/features/advancedFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { Feature } from './types';

import { getEnvValue } from '../utils';

const isDisabled = getEnvValue('NEXT_PUBLIC_ADVANCED_FILTER_ENABLED') === 'false';

const title = 'Advanced filter';

const config: Feature<{}> = (() => {
if (!isDisabled) {
return Object.freeze({
title,
isEnabled: true,
});
}

return Object.freeze({
title,
isEnabled: false,
});
})();

export default config;
1 change: 1 addition & 0 deletions configs/app/features/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default as advancedFilter } from './advancedFilter';
export { default as account } from './account';
export { default as addressVerification } from './addressVerification';
export { default as addressMetadata } from './addressMetadata';
Expand Down
2 changes: 1 addition & 1 deletion configs/envs/.env.eth_sepolia
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP={ "id": "632019", "width": "728", "height
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE={ "id": "632018", "width": "320", "height": "100" }
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/
NEXT_PUBLIC_API_HOST=eth-sepolia.blockscout.com
NEXT_PUBLIC_API_HOST=eth-sepolia.k8s-dev.blockscout.com
NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
NEXT_PUBLIC_CONTRACT_CODE_IDES=[{'title':'Remix IDE','url':'https://remix.ethereum.org/?address={hash}&blockscout={domain}','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}]
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
Expand Down
1 change: 1 addition & 0 deletions deploy/tools/envs-validator/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,7 @@ const schema = yup
NEXT_PUBLIC_GAS_TRACKER_ENABLED: yup.boolean(),
NEXT_PUBLIC_GAS_TRACKER_UNITS: yup.array().transform(replaceQuotes).json().of(yup.string<GasUnit>().oneOf(GAS_UNITS)),
NEXT_PUBLIC_DATA_AVAILABILITY_ENABLED: yup.boolean(),
NEXT_PUBLIC_ADVANCED_FILTER_ENABLED: yup.boolean(),
NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS: yup
.array()
.transform(replaceQuotes)
Expand Down
11 changes: 11 additions & 0 deletions docs/ENVS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Please be aware that all environment variables prefixed with `NEXT_PUBLIC_` will
- [App features](ENVS.md#app-features)
- [My account](ENVS.md#my-account)
- [Gas tracker](ENVS.md#gas-tracker)
- [Advanced filter](ENVS.md#advanced-filter)
- [Address verification](ENVS.md#address-verification-in-my-account) in "My account"
- [Blockchain interaction](ENVS.md#blockchain-interaction-writing-to-contract-etc) (writing to contract, etc.)
- [Banner ads](ENVS.md#banner-ads)
Expand Down Expand Up @@ -367,6 +368,16 @@ This feature is **enabled by default**. To switch it off pass `NEXT_PUBLIC_GAS_T

&nbsp;

### Advanced filter

This feature is **enabled by default**. To switch it off pass `NEXT_PUBLIC_ADVANCED_FILTER_ENABLED=false`.

| Variable | Type| Description | Compulsoriness | Default value | Example value | Version |
| --- | --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_ADVANCED_FILTER_ENABLED | `boolean` | Set to true to enable "Advanced filter" page in the app | Required | `true` | `false` | v1.37.0+ |

&nbsp;

### Address verification in "My account"

*Note* all ENV variables required for [My account](ENVS.md#my-account) feature should be passed alongside the following ones:
Expand Down
6 changes: 6 additions & 0 deletions icons/columns.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 40 additions & 1 deletion lib/api/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import type {
} from 'types/api/address';
import type { AddressesResponse, AddressesMetadataSearchResult, AddressesMetadataSearchFilters } from 'types/api/addresses';
import type { AddressMetadataInfo, PublicTagTypesResponse } from 'types/api/addressMetadata';
import type { AdvancedFilterParams, AdvancedFilterResponse, AdvancedFilterMethodsResponse } from 'types/api/advancedFilter';
import type {
ArbitrumL2MessagesResponse,
ArbitrumL2TxnBatch,
Expand Down Expand Up @@ -1089,6 +1090,41 @@ export const RESOURCES = {
pathParams: [ 'hash' as const ],
},

// ADVANCED FILTER
advanced_filter: {
path: '/api/v2/advanced-filters',
filterFields: [
'tx_types' as const,
'methods' as const,
'methods_names' as const /* frontend only */,
'age_from' as const,
'age_to' as const,
'age' as const /* frontend only */,
'from_address_hashes_to_include' as const,
'from_address_hashes_to_exclude' as const,
'to_address_hashes_to_include' as const,
'to_address_hashes_to_exclude' as const,
'address_relation' as const,
'amount_from' as const,
'amount_to' as const,
'token_contract_address_hashes_to_include' as const,
'token_contract_symbols_to_include' as const /* frontend only */,
'token_contract_address_hashes_to_exclude' as const,
'token_contract_symbols_to_exclude' as const /* frontend only */,
'block_number' as const,
'transaction_index' as const,
'internal_transaction_index' as const,
'token_transfer_index' as const,
],
},
advanced_filter_methods: {
path: '/api/v2/advanced-filters/methods',
filterFields: [ 'q' as const ],
},
advanced_filter_csv: {
path: '/api/v2/advanced-filters/csv',
},

// CONFIGS
config_backend_version: {
path: '/api/v2/config/backend-version',
Expand Down Expand Up @@ -1183,7 +1219,7 @@ export type PaginatedResources = 'blocks' | 'block_txs' | 'block_election_reward
'watchlist' | 'private_tags_address' | 'private_tags_tx' |
'domains_lookup' | 'addresses_lookup' | 'user_ops' | 'validators_stability' | 'validators_blackfort' | 'noves_address_history' |
'token_transfers_all' | 'scroll_l2_txn_batches' | 'scroll_l2_txn_batch_txs' | 'scroll_l2_txn_batch_blocks' |
'scroll_l2_deposits' | 'scroll_l2_withdrawals';
'scroll_l2_deposits' | 'scroll_l2_withdrawals' | 'advanced_filter';

export type PaginatedResponse<Q extends PaginatedResources> = ResourcePayload<Q>;

Expand Down Expand Up @@ -1375,6 +1411,8 @@ Q extends 'scroll_l2_deposits' ? ScrollL2MessagesResponse :
Q extends 'scroll_l2_deposits_count' ? number :
Q extends 'scroll_l2_withdrawals' ? ScrollL2MessagesResponse :
Q extends 'scroll_l2_withdrawals_count' ? number :
Q extends 'advanced_filter' ? AdvancedFilterResponse :
Q extends 'advanced_filter_methods' ? AdvancedFilterMethodsResponse :
never;
/* eslint-enable @stylistic/indent */

Expand Down Expand Up @@ -1410,6 +1448,7 @@ Q extends 'validators_stability' ? ValidatorsStabilityFilters :
Q extends 'address_mud_tables' ? AddressMudTablesFilter :
Q extends 'address_mud_records' ? AddressMudRecordsFilter :
Q extends 'token_transfers_all' ? TokenTransferFilters :
Q extends 'advanced_filter' ? AdvancedFilterParams :
never;
/* eslint-enable @stylistic/indent */

Expand Down
14 changes: 5 additions & 9 deletions lib/getFilterValuesFromQuery.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import getValuesArrayFromQuery from './getValuesArrayFromQuery';

export default function getFilterValue<FilterType>(filterValues: ReadonlyArray<FilterType>, val: string | Array<string> | undefined) {
if (val === undefined) {
return;
}
const valArray = getValuesArrayFromQuery(val);

const valArray = [];
if (typeof val === 'string') {
valArray.push(...val.split(','));
}
if (Array.isArray(val)) {
val.forEach(el => valArray.push(...el.split(',')));
if (!valArray) {
return;
}

return valArray.filter(el => filterValues.includes(el as unknown as FilterType)) as unknown as Array<FilterType>;
Expand Down
18 changes: 18 additions & 0 deletions lib/getValuesArrayFromQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default function getValuesArrayFromQuery(val: string | Array<string> | undefined) {
if (val === undefined) {
return;
}

const valArray = [];
if (typeof val === 'string') {
valArray.push(...val.split(','));
}
if (Array.isArray(val)) {
if (!val.length) {
return;
}
val.forEach(el => valArray.push(...el.split(',')));
}

return valArray;
}
1 change: 1 addition & 0 deletions lib/metadata/getPageOgType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const OG_TYPE_DICT: Record<Route['pathname'], OGPageType> = {
'/gas-tracker': 'Root page',
'/mud-worlds': 'Root page',
'/token-transfers': 'Root page',
'/advanced-filter': 'Root page',

// service routes, added only to make typescript happy
'/login': 'Regular page',
Expand Down
1 change: 1 addition & 0 deletions lib/metadata/templates/description.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const TEMPLATE_MAP: Record<Route['pathname'], string> = {
'/gas-tracker': 'Explore real-time %network_title% gas fees with Blockscout\'s advanced gas fee tracker. Get accurate %network_gwei% estimates and track transaction costs live.',
'/mud-worlds': DEFAULT_TEMPLATE,
'/token-transfers': DEFAULT_TEMPLATE,
'/advanced-filter': DEFAULT_TEMPLATE,

// service routes, added only to make typescript happy
'/login': DEFAULT_TEMPLATE,
Expand Down
1 change: 1 addition & 0 deletions lib/metadata/templates/title.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const TEMPLATE_MAP: Record<Route['pathname'], string> = {
'/gas-tracker': 'Track %network_name% gas fees in %network_gwei%',
'/mud-worlds': '%network_name% MUD worlds list',
'/token-transfers': '%network_name% token transfers',
'/advanced-filter': '%network_name% advanced filter',

// service routes, added only to make typescript happy
'/login': '%network_name% login',
Expand Down
1 change: 1 addition & 0 deletions lib/mixpanel/getPageType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const PAGE_TYPE_DICT: Record<Route['pathname'], string> = {
'/gas-tracker': 'Gas tracker',
'/mud-worlds': 'MUD worlds',
'/token-transfers': 'Token transfers',
'/advanced-filter': 'Advanced filter',

// service routes, added only to make typescript happy
'/login': 'Login',
Expand Down
124 changes: 124 additions & 0 deletions mocks/advancedFilter/advancedFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import type { AdvancedFilterResponse } from 'types/api/advancedFilter';

export const baseResponse: AdvancedFilterResponse = {
items: [
{
timestamp: '2024-12-06T12:38:59.000000Z',
total: null,
type: 'coin_transfer',
value: '0',
hash: '0x35e5793d3da98d8e8e3944e40fa15028806502b53a2319501c6acdb8c83ed4bc',
from: {
ens_domain_name: null,
hash: '0xC1b634853Cb333D3aD8663715b08f41A3Aec47cc',
implementations: [],
is_contract: false,
is_verified: false,
metadata: null,
name: null,
private_tags: [],
public_tags: [],
watchlist_names: [],
},
token: null,
to: {
ens_domain_name: null,
hash: '0x1c479675ad559DC151F6Ec7ed3FbF8ceE79582B6',
implementations: [
{
address: '0x31DA64D19Cd31A19CD09F4070366Fe2144792cf7',
name: 'SequencerInbox',
},
],
is_contract: true,
is_verified: true,
metadata: null,
name: 'TransparentUpgradeableProxy',
private_tags: [],
public_tags: [],
watchlist_names: [],
},
method: 'addSequencerL2BatchFromBlobs',
fee: '2657475294553624',
},
{
timestamp: '2024-12-06T12:38:59.000000Z',
total: null,
type: 'coin_transfer',
value: '1328910000000000',
hash: '0x0d7a6c1e91540f767bc4d48bbcf2aa3fa22c93d0d8a60fb34bd7f0ecec5565b0',
from: {
ens_domain_name: null,
hash: '0x9BDc51980d3b81a0fBd031d0F0E39e9E1aFCB294',
implementations: [],
is_contract: false,
is_verified: false,
metadata: null,
name: null,
private_tags: [],
public_tags: [],
watchlist_names: [],
},
token: null,
to: {
ens_domain_name: null,
hash: '0xFe4cda7cc3603bdB9447cAd4A6550290AFeF6b38',
implementations: [],
is_contract: false,
is_verified: false,
metadata: null,
name: null,
private_tags: [],
public_tags: [],
watchlist_names: [],
},
method: null,
fee: '279416150328000',
},
{
timestamp: '2024-12-06T12:38:59.000000Z',
total: null,
type: 'coin_transfer',
value: '0',
hash: '0x925bb2b7bf0b7a37ba4012bd718015cae29fa44e7846a7563c01f11ef99461e2',
from: {
ens_domain_name: null,
hash: '0x807Db16fd01766EE8A7040B6d32F4169c0A0Bf47',
implementations: [],
is_contract: false,
is_verified: false,
metadata: null,
name: null,
private_tags: [],
public_tags: [],
watchlist_names: [],
},
token: null,
to: {
ens_domain_name: null,
hash: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0',
implementations: [],
is_contract: true,
is_verified: true,
metadata: null,
name: 'WstETH',
private_tags: [],
public_tags: [],
watchlist_names: [],
},
method: 'approve',
fee: '620080096879104',
},
],
next_page_params: {
block_number: 5867485,
internal_transaction_index: null,
token_transfer_index: null,
transaction_index: 208,
items_count: 50,
},
search_params: {
tokens: {},
methods: {},
},
};
10 changes: 10 additions & 0 deletions nextjs/getServerSideProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,16 @@ export const gasTracker: GetServerSideProps<Props> = async(context) => {
return base(context);
};

export const advancedFilter: GetServerSideProps<Props> = async(context) => {
if (!config.features.advancedFilter.isEnabled) {
return {
notFound: true,
};
}

return base(context);
};

export const dataAvailability: GetServerSideProps<Props> = async(context) => {
if (!config.features.dataAvailability.isEnabled) {
return {
Expand Down
1 change: 1 addition & 0 deletions nextjs/nextjs-routes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ declare module "nextjs-routes" {
| DynamicRoute<"/accounts/label/[slug]", { "slug": string }>
| DynamicRoute<"/address/[hash]/contract-verification", { "hash": string }>
| DynamicRoute<"/address/[hash]", { "hash": string }>
| StaticRoute<"/advanced-filter">
| StaticRoute<"/api/config">
| StaticRoute<"/api/csrf">
| StaticRoute<"/api/healthz">
Expand Down
18 changes: 18 additions & 0 deletions pages/advanced-filter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { NextPage } from 'next';
import React from 'react';

import PageNextJs from 'nextjs/PageNextJs';

import AdvancedFilter from 'ui/pages/AdvancedFilter';

const Page: NextPage = () => {
return (
<PageNextJs pathname="/advanced-filter">
<AdvancedFilter/>
</PageNextJs>
);
};

export default Page;

export { advancedFilter as getServerSideProps } from 'nextjs/getServerSideProps';
Loading
Loading