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

feat: Token Network Filter UI [Extension] #27884

Open
wants to merge 34 commits into
base: develop
Choose a base branch
from

Conversation

gambinish
Copy link
Contributor

@gambinish gambinish commented Oct 16, 2024

Description

Adds Token network filter controls. Note that this is not fully functional, and is currently blocked by two PRs before it can be fully integrated:

  1. feat: show all tokens for all chains in the token list #27785
  2. fix: should not reset market data after switch network core#4832

In the meantime, this PR is set behind a feature flag FILTER_TOKENS_TOGGLE and can be run as follows:

FILTER_TOKENS_TOGGLE=1 yarn webpack --watch
Alternatively: FILTER_TOKENS_TOGGLE=1 yarn start

Open in GitHub Codespaces

Included in this PR:

  1. Adds new tokenNetworkFilter preference to PreferencesController to manage which chains should be considered when filtering tokens
  2. Adds an action to update this preference by All Networks (no filters) and Current Network { [chainId]: true) } this is meant to be flexible enough to support multiple chains in the future.
  3. Adds filterAssets function in a similar style to sortAssets it should be configuration based, and should be extensible enough to support filtering assets by deeply nested values (NFT traits), and to also support complex filter types (like price ranges).
  4. Dropdown should show the balance for the selected network

Not included in this PR:

  1. Aggregated balance across chains. Blocked by fix: should not reset market data after switch network core#4832 and currently hardcoded to $1000
  2. Token lists will not be filtered in this PR. Blocked by feat: show all tokens for all chains in the token list #27785

Related issues

https://github.com/orgs/MetaMask/projects/85/views/35?pane=issue&itemId=82217837
https://consensyssoftware.atlassian.net/browse/MMASSETS-430

Manual testing steps

Token Filter selection should persist through refresh
Current chain balance should reflect the balance of the current chain
Should visibly match designs: https://www.figma.com/design/aMYisczaJyEsYl1TYdcPUL/Portfolio-View?node-id=5750-47217&node-type=canvas&t=EjOUPnqy7tWZE6sV-0

Screenshots/Recordings

Screen.Recording.2024-10-22.at.10.46.39.AM.mov

Pre-merge author checklist

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Copy link
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@gambinish gambinish changed the title feat: Token Network Filter UI feat: Token Network Filter UI [Extension] Oct 16, 2024
@gambinish
Copy link
Contributor Author

Demo of WIP:

Screen.Recording.2024-10-17.at.7.43.44.AM.mov

@gambinish gambinish marked this pull request as ready for review October 22, 2024 18:04
@gambinish gambinish requested a review from a team as a code owner October 22, 2024 18:04
@gambinish gambinish added team-assets needs-assets-ux-review A shared label between the Assets and UX team to flag PRs ready for consolidated team review. labels Oct 22, 2024
@metamaskbot
Copy link
Collaborator

Builds ready [5b40705]
Page Load Metrics (1979 ± 122 ms)
PlatformPageMetricMin (ms)Max (ms)Average (ms)StandardDeviation (ms)MarginOfError (ms)
ChromeHomefirstPaint29825221765486234
domContentLoaded166626711946255122
load174026761979254122
domInteractive13103502210
backgroundConnect886342412
firstReactRender48118932010
getState46718199
initialActions01000
loadScripts117620871436231111
setupStore1178392612
uiStartup189629062191271130

@metamaskbot
Copy link
Collaborator

Builds ready [f7f09da]
Page Load Metrics (1994 ± 76 ms)
PlatformPageMetricMin (ms)Max (ms)Average (ms)StandardDeviation (ms)MarginOfError (ms)
ChromeHomefirstPaint28624311663662318
domContentLoaded17032248196014972
load17412340199415876
domInteractive14251634924
backgroundConnect9150343215
firstReactRender562951145024
getState597182412
initialActions01000
loadScripts12211709146512460
setupStore1276422512
uiStartup191430222274278134

@metamaskbot
Copy link
Collaborator

Builds ready [c6a408d]
Page Load Metrics (2046 ± 72 ms)
PlatformPageMetricMin (ms)Max (ms)Average (ms)StandardDeviation (ms)MarginOfError (ms)
ChromeHomefirstPaint18322465205314670
domContentLoaded17732410199813766
load18212462204614972
domInteractive27109512010
backgroundConnect8143453818
firstReactRender532051032814
getState661272211
initialActions01000
loadScripts13151874150111856
setupStore1196272311
uiStartup202728542290209100
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 22 Bytes (0.00%)
  • ui: 5.52 KiB (0.07%)
  • common: 359 Bytes (0.00%)

Copy link
Member

@andreahaku andreahaku left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few code optimisation and readability comments :)

</Text>
</Box>
<Box display={Display.Flex}>
{Object.values(allNetworks).map((network, index) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about:

Object.values(allNetworks).slice(0, 5).map(({ chainId }, index) => {
  const networkImageUrl = CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP[chainId as keyof typeof CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP];

  return (
    <AvatarNetwork
      key={chainId}
      name="All"
      src={networkImageUrl ?? undefined}
      // overlap the icons
      style={{
        marginLeft: index === 0 ? 0 : '-20px',
        zIndex: 5 - index,  // Since we're limiting to 5 networks, zIndex is 5 - index
      }}
    />
  );
});

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good callout, addressed here: a2074cd

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here: 836a11b

if (filterCallback && opts) {
switch (filterCallback) {
case 'inclusive':
if (typeof nestedValue === 'string') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if you create helper functions to handle inclusive filter and range filter like:

// Helper function for 'inclusive' filter
function handleInclusiveFilter(nestedValue: unknown, opts: Record<string, boolean>): boolean {
  return typeof nestedValue === 'string'
    ? filterCallbacks.inclusive(nestedValue, opts)
    : false;
}

// Helper function for 'range' filter
function handleRangeFilter(nestedValue: unknown, opts: { min: number; max: number }): boolean {
  return typeof nestedValue === 'number'
    ? filterCallbacks.range(nestedValue, opts)
    : false;
}

so that you can then have something much more readable like:

switch (filterCallback) {
        case 'inclusive':
          return handleInclusiveFilter(nestedValue, opts);
        case 'range':
          return handleRangeFilter(nestedValue, opts);
        default:
          return true;
      }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah you're right this could be cleaner. Rather than adding the additional abstraction, I ended up just cleaning up the code in the switch statement, would you be fine with this?

      switch (filterCallback) {
        case 'inclusive':
          return filterCallbacks.inclusive(
            nestedValue as string,
            opts as Record<string, boolean>,
          );
        case 'range':
          return filterCallbacks.range(
            nestedValue as number,
            opts as { min: number; max: number },
          );
        default:
          return true;
      }

ui/components/app/assets/util/filter.ts Show resolved Hide resolved
ui/components/app/assets/util/filter.ts Outdated Show resolved Hide resolved
@metamaskbot
Copy link
Collaborator

Builds ready [a2074cd]
Page Load Metrics (2146 ± 104 ms)
PlatformPageMetricMin (ms)Max (ms)Average (ms)StandardDeviation (ms)MarginOfError (ms)
ChromeHomefirstPaint32726801963562270
domContentLoaded17662620210620699
load179226802146217104
domInteractive18139522914
backgroundConnect8184374119
firstReactRender532951326230
getState75825189
initialActions01000
loadScripts12892039157518086
setupStore1795392713
uiStartup199730552450288138
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 22 Bytes (0.00%)
  • ui: 5.49 KiB (0.07%)
  • common: 359 Bytes (0.00%)

@metamaskbot
Copy link
Collaborator

Builds ready [441d4cf]
Page Load Metrics (2190 ± 100 ms)
PlatformPageMetricMin (ms)Max (ms)Average (ms)StandardDeviation (ms)MarginOfError (ms)
ChromeHomefirstPaint31224301886664319
domContentLoaded18102688215219895
load185326952190207100
domInteractive318347168
backgroundConnect9127413416
firstReactRender822171173416
getState697302914
initialActions01000
loadScripts13382018159715976
setupStore12101392914
uiStartup205629722470221106
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 22 Bytes (0.00%)
  • ui: 5.5 KiB (0.07%)
  • common: 359 Bytes (0.00%)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-assets-ux-review A shared label between the Assets and UX team to flag PRs ready for consolidated team review. team-assets
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants