Skip to content

Commit

Permalink
feat(multichain-connect-ui): Add UI preparation changes for multichai…
Browse files Browse the repository at this point in the history
…n connection flow (#30164)

## **Description**
This PR updates connection flow to prepare it for multichain
connection/permission/account requests.

[![Open in GitHub
Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/30164?quickstart=1)

## **Related issues**
Fixes: MetaMask/MetaMask-planning#3899

Epic: MetaMask/MetaMask-planning#3660

Design:
https://www.figma.com/design/TVuSsLlBQGypLamTsjN1hG/Connection?node-id=286-3221&p=f&t=FkFfpgICtIpA2WBY-0

## **Notes**
- `AccountListItem` will be updated to handle network icons in this task
here: MetaMask/MetaMask-planning#4056 (when
done, it can be integrated into the connection flow, but for now it's
alright to not have it, since it's not a blocker).

## **Manual testing steps**
1. Go to test-dapp.
2. Request permissions / request to connect.
3. Check UI functionality and designs.
4. Check edge cases.
5. Confirm functionality of the entire flow.

## **Screenshots/Recordings**
### **Before**
![Screenshot 2025-02-11 at 17 26
59](https://github.com/user-attachments/assets/18348f1c-3c12-481f-a346-4ecf05585125)
![Screenshot 2025-02-11 at 17 27
27](https://github.com/user-attachments/assets/fe827d6c-2613-4343-afbf-3d8cd0b4a5c8)
![Screenshot 2025-02-11 at 17 27
57](https://github.com/user-attachments/assets/2152b2fb-c20c-4c61-beb5-ce782040fae3)

### **After**

https://github.com/user-attachments/assets/9e47ac9c-b0de-4e84-ba41-2d72c6d9fe10

#### Regular flows
![Screenshot 2025-02-13 at 20 20
04](https://github.com/user-attachments/assets/889953f8-cbe2-4c33-bf60-649b4d77040c)
![Screenshot 2025-02-13 at 20 20
18](https://github.com/user-attachments/assets/043c5270-be4f-4e41-84ed-53885505a3fe)
![Screenshot 2025-02-13 at 20 20
31](https://github.com/user-attachments/assets/fb32e6f1-f148-4bc7-93d6-ec0f8100b18d)
![Screenshot 2025-02-13 at 20 21
41](https://github.com/user-attachments/assets/991c02e5-5065-407b-922c-c198c285f31f)

#### IP address as a hostname and missing icon handling
![Screenshot 2025-02-13 at 23 19
41](https://github.com/user-attachments/assets/55707212-11e3-4734-a156-741c6ab1baf9)
![Screenshot 2025-02-13 at 23 19
19](https://github.com/user-attachments/assets/87371e18-09ad-4a94-bac6-4883da765d61)
![Screenshot 2025-02-13 at 23 19
59](https://github.com/user-attachments/assets/35aa3456-37e4-4d74-ac36-6b54f5744052)

#### Empty state edge case handling

https://github.com/user-attachments/assets/4ae87104-1e6e-4de3-aa3f-0b2f4b28e1fc

## **Pre-merge author checklist**
- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **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.
  • Loading branch information
david0xd authored Feb 24, 2025
1 parent da8838f commit 32af047
Show file tree
Hide file tree
Showing 17 changed files with 1,068 additions and 335 deletions.
5 changes: 4 additions & 1 deletion app/_locales/en/messages.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion app/_locales/en_GB/messages.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions test/e2e/json-rpc/switchEthereumChain.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@ describe('Switch Ethereum Chain for two dapps', function () {
await driver.clickElement('#connectButton');

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);

const permissionsTab = await driver.findElement(
'[data-testid="permissions-tab"]',
);
await permissionsTab.click();

const editButtons = await driver.findElements('[data-testid="edit"]');

await editButtons[1].click();
Expand Down Expand Up @@ -263,6 +269,12 @@ describe('Switch Ethereum Chain for two dapps', function () {
await driver.clickElement('#connectButton');

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);

const permissionsTab = await driver.findElement(
'[data-testid="permissions-tab"]',
);
await permissionsTab.click();

const editButtons = await driver.findElements('[data-testid="edit"]');

// Click the edit button for networks
Expand Down Expand Up @@ -383,6 +395,11 @@ describe('Switch Ethereum Chain for two dapps', function () {

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);

const permissionsTab = await driver.findElement(
'[data-testid="permissions-tab"]',
);
await permissionsTab.click();

const editButtons = await driver.findElements('[data-testid="edit"]');

// Click the edit button for networks
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ class ConnectAccountConfirmation {
};

private readonly connectAccountConfirmationTitle = {
text: 'Connect with MetaMask',
tag: 'h2',
text: 'Connect this website with MetaMask.',
tag: 'p',
};

constructor(driver: Driver) {
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/page-objects/pages/test-dapp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ class TestDapp {
private readonly connectAccountButton = '#connectButton';

private readonly connectMetaMaskMessage = {
text: 'Connect with MetaMask',
tag: 'h2',
text: 'Connect this website with MetaMask.',
tag: 'p',
};

private readonly connectedAccount = '#accounts';
Expand Down
10 changes: 10 additions & 0 deletions test/e2e/tests/request-queuing/dapp1-switch-dapp2-send.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ describe('Request Queuing Dapp 1, Switch Tx -> Dapp 2 Send Tx', function () {

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);

const permissionsTab = await driver.findElement(
'[data-testid="permissions-tab"]',
);
await permissionsTab.click();

const editButtons = await driver.findElements('[data-testid="edit"]');

await editButtons[1].click();
Expand Down Expand Up @@ -208,6 +213,11 @@ describe('Request Queuing Dapp 1, Switch Tx -> Dapp 2 Send Tx', function () {
await driver.clickElement('#connectButton');

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
const permissionsTab = await driver.findElement(
'[data-testid="permissions-tab"]',
);
await permissionsTab.click();

const editButtons = await driver.findElements('[data-testid="edit"]');

await editButtons[1].click();
Expand Down
6 changes: 6 additions & 0 deletions test/e2e/tests/request-queuing/switchChain-watchAsset.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ describe('Request Queue SwitchChain -> WatchAsset', function () {
await driver.clickElement('#connectButton');

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);

const permissionsTab = await driver.findElement(
'[data-testid="permissions-tab"]',
);
await permissionsTab.click();

const editButtons = await driver.findElements('[data-testid="edit"]');

await editButtons[1].click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ export const SiteCell: React.FC<SiteCellProps> = ({
category: MetaMetricsEventCategory.Navigation,
event: MetaMetricsEventName.ViewPermissionedAccounts,
properties: {
location: 'Connect view, Permissions toast, Permissions (dapp)',
location:
'Connect view (permissions tab), Permissions toast, Permissions (dapp)',
},
});
};
Expand All @@ -112,7 +113,8 @@ export const SiteCell: React.FC<SiteCellProps> = ({
category: MetaMetricsEventCategory.Navigation,
event: MetaMetricsEventName.ViewPermissionedNetworks,
properties: {
location: 'Connect view, Permissions toast, Permissions (dapp)',
location:
'Connect view (permissions tab), Permissions toast, Permissions (dapp)',
},
});
};
Expand Down
1 change: 1 addition & 0 deletions ui/components/ui/tabs/tab/tab.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Tab.propTypes = {
tabIndex: PropTypes.number, // required, but added using React.cloneElement
children: PropTypes.node, // required, but we are not rendering it explicitly
textProps: PropTypes.object, // props to spread to the Text component
width: PropTypes.string,
};

Tab.defaultProps = {
Expand Down
43 changes: 43 additions & 0 deletions ui/helpers/utils/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,49 @@ export const getAvatarFallbackLetter = (subjectName) => {
return subjectName?.match(/[a-z0-9]/iu)?.[0] ?? '?';
};

/**
* Check whether raw origin URL is an IP address.
*
* Note: IPv6 addresses are expected to be wrapped in brackets (e.g. [fe80::1])
* because of how URL formatting works.
*
* @param {string} rawOriginUrl - Raw origin (URL) with protocol that is potentially an IP address
* @returns Boolean, true if the origin is an IP address, false otherwise.
*/
export const isIpAddress = (rawOriginUrl) => {
if (typeof rawOriginUrl === 'string') {
return Boolean(
rawOriginUrl.match(/^(\d{1,3}\.){3}\d{1,3}$|^\[[0-9a-f:]+\]$/iu),
);
}

return false;
};

/**
* Transforms full raw URLs to something that can be used as title.
* Basically, it removes subdomain and protocol prefixes.
*
* Note: For IP address origins, full IP address without protocol will be returned.
*
* @param {string} rawOrigin - Raw origin (URL) with protocol.
* @returns User friendly title extracted from raw URL.
*/
export const transformOriginToTitle = (rawOrigin) => {
try {
const url = new URL(rawOrigin);

if (isIpAddress(url.hostname)) {
return url.hostname;
}

const parts = url.hostname.split('.');
return parts.slice(-2).join('.');
} catch (e) {
return 'Unknown Origin';
}
};

/**
* Get abstracted Snap permissions filtered by weight.
*
Expand Down
50 changes: 50 additions & 0 deletions ui/helpers/utils/util.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1298,4 +1298,54 @@ describe('util', () => {
expect(sortedAccount).toStrictEqual([]);
});
});

describe('isIpAddress', () => {
it('should return true for the IPv4 address', () => {
expect(util.isIpAddress('127.0.0.1')).toBe(true);
});

it('should return true for the IPv6 address', () => {
expect(util.isIpAddress('[fe80::1]')).toBe(true);
});

it('should return true for the invalid IP address', () => {
expect(util.isIpAddress('metamask')).toBe(false);
});

it('should return true for the invalid type of argument', () => {
expect(util.isIpAddress(1024)).toBe(false);
});
});

describe('transformOriginToTitle', () => {
it('should return the correct title for origin with domain', () => {
expect(util.transformOriginToTitle('https://metamask.io')).toBe(
'metamask.io',
);
});

it('should return the correct title for origin with subdomain', () => {
expect(
util.transformOriginToTitle('https://metamask.github.io/test-dapp/'),
).toBe('github.io');
});

it('should return the correct title for localhost', () => {
expect(util.transformOriginToTitle('http://localhost:3000')).toBe(
'localhost',
);
});

it('should return the correct title for IPv4 address', () => {
expect(util.transformOriginToTitle('http://127.0.0.1:3000')).toBe(
'127.0.0.1',
);
});

it('should return the correct title for IPv6 address', () => {
expect(util.transformOriginToTitle('http://[fe80::1]:9011/')).toBe(
'[fe80::1]',
);
});
});
});
Loading

0 comments on commit 32af047

Please sign in to comment.