Skip to content

Commit

Permalink
Advanced filter (#1905)
Browse files Browse the repository at this point in the history
* advanced filter start

* advanced filters stage 2

* adv filters stage 3

* fixes

* add test

* eslint fixes

* age filter update

* some fixes and filters tests

* fixes 2

* add csv export

* fixes 3

* add env variable for adv filter

* fix tests

* edit env temporary
  • Loading branch information
isstuev authored Dec 16, 2024
1 parent 476d771 commit 8538b69
Show file tree
Hide file tree
Showing 67 changed files with 2,347 additions and 70 deletions.
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 @@ -1092,6 +1093,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 @@ -1186,7 +1222,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 @@ -1378,6 +1414,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 @@ -1413,6 +1451,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

0 comments on commit 8538b69

Please sign in to comment.