Skip to content

Commit 1f587b3

Browse files
authored
feat(kernel-ui): Use MetaMask extension's design system (#577)
1 parent cd49ec0 commit 1f587b3

82 files changed

Lines changed: 3043 additions & 2059 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.depcheckrc.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,11 @@ ignores:
3838
- 'simple-git-hooks'
3939
- 'typedoc'
4040
- 'typescript'
41-
- 'typescript-plugin-css-modules'
4241
- '@agoric/internal'
4342
- 'setimmediate'
4443
- '@types/setimmediate'
44+
- 'autoprefixer'
45+
- 'postcss'
4546

4647
# Used by @ocap/nodejs to build the sqlite3 bindings
4748
- 'node-gyp'
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
diff --git a/dist/index.mjs b/dist/index.mjs
2+
index 510e77fc0471abe017279f39c87ecded59c41954..f7517e6b66d010a3ae7143417a36fa2f20c93767 100644
3+
--- a/dist/index.mjs
4+
+++ b/dist/index.mjs
5+
@@ -1,7 +1,7 @@
6+
// src/slot.tsx
7+
import * as React from "react";
8+
import { composeRefs } from "@radix-ui/react-compose-refs";
9+
-import { Fragment as Fragment2, jsx } from "react/jsx-runtime";
10+
+import { Fragment as Fragment2, jsx } from "react/jsx-runtime.js";
11+
// @__NO_SIDE_EFFECTS__
12+
function createSlot(ownerName) {
13+
const SlotClone = /* @__PURE__ */ createSlotClone(ownerName);

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
}
125125
},
126126
"resolutions": {
127-
"cookie": "^0.7.0"
127+
"cookie": "^0.7.0",
128+
"@radix-ui/react-slot@npm:^1.1.0": "patch:@radix-ui/react-slot@npm%3A1.2.3#~/.yarn/patches/@radix-ui-react-slot-npm-1.2.3-6e45e6d89b.patch"
128129
}
129130
}

packages/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"@metamask/kernel-utils": "workspace:^",
4141
"@metamask/logger": "workspace:^",
4242
"@metamask/snaps-utils": "^9.1.0",
43-
"@metamask/utils": "^11.4.0",
43+
"@metamask/utils": "^11.4.2",
4444
"@types/node": "^22.13.1",
4545
"chokidar": "^4.0.1",
4646
"glob": "^11.0.0",

packages/create-package/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"@metamask/eslint-config": "^14.0.0",
5151
"@metamask/eslint-config-nodejs": "^14.0.0",
5252
"@metamask/eslint-config-typescript": "^14.0.0",
53-
"@metamask/utils": "^11.4.0",
53+
"@metamask/utils": "^11.4.2",
5454
"@ocap/test-utils": "workspace:^",
5555
"@ts-bridge/cli": "^0.6.3",
5656
"@ts-bridge/shims": "^0.1.1",

packages/extension/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
"@metamask/logger": "workspace:^",
5252
"@metamask/ocap-kernel": "workspace:^",
5353
"@metamask/streams": "workspace:^",
54-
"@metamask/utils": "^11.4.0",
54+
"@metamask/utils": "^11.4.2",
5555
"react": "^17.0.2",
5656
"react-dom": "^17.0.2",
5757
"ses": "^1.13.0"

packages/extension/test/e2e/control-panel.test.ts

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,6 @@ test.describe('Control Panel', () => {
2323
await extensionContext.close();
2424
});
2525

26-
/**
27-
* Clears the state of the popup page.
28-
*/
29-
async function clearState(): Promise<void> {
30-
await popupPage.locator('[data-testid="clear-logs-button"]').click();
31-
await expect(
32-
popupPage.locator('[data-testid="message-output"]'),
33-
).toContainText('');
34-
await popupPage.click('button:text("Clear All State")');
35-
await expect(
36-
popupPage.locator('[data-testid="message-output"]'),
37-
).toContainText('State cleared');
38-
await expect(
39-
popupPage.locator('[data-testid="subcluster-accordion-s1"]'),
40-
).not.toBeVisible();
41-
}
42-
4326
/**
4427
* Launches a subcluster with the given configuration.
4528
*
@@ -61,17 +44,28 @@ test.describe('Control Panel', () => {
6144
}
6245

6346
test('should load popup with kernel panel', async () => {
64-
await expect(popupPage.locator('h2')).toHaveText('Kernel');
6547
await expect(
66-
popupPage.locator('button:text("Clear All State")'),
48+
popupPage.locator('button:text("Control Panel")'),
6749
).toBeVisible();
6850
await expect(
69-
popupPage.locator('h4:text("Launch New Subcluster")'),
51+
popupPage.locator('[data-testid="subcluster-accordion-s1"]'),
52+
).toBeVisible();
53+
await expect(popupPage.locator('p:text("Message History")')).toBeVisible();
54+
await expect(
55+
popupPage.locator('p:text("Launch New Subcluster")'),
7056
).toBeVisible();
7157
});
7258

7359
test('should launch a new subcluster and vat within it', async () => {
74-
await clearState();
60+
// Clear all state
61+
await popupPage.click('button:text("Clear All State")');
62+
await expect(
63+
popupPage.locator('[data-testid="message-output"]'),
64+
).toContainText('State cleared');
65+
await expect(
66+
popupPage.locator('[data-testid="subcluster-accordion-s1"]'),
67+
).not.toBeVisible();
68+
// Launch a new subcluster
7569
await launchSubcluster(minimalClusterConfig);
7670
const subcluster = popupPage.locator(
7771
'[data-testid="subcluster-accordion-s1"]',
@@ -81,43 +75,49 @@ test.describe('Control Panel', () => {
8175
});
8276
await expect(popupPage.locator('text=1 Vat')).toBeVisible();
8377
// Open the subcluster accordion to view vats
84-
await popupPage.locator('.accordion-header').first().click();
78+
await popupPage.locator('[data-testid="accordion-header"]').click();
8579
const vatTable = popupPage.locator('[data-testid="vat-table"]');
8680
await expect(vatTable).toBeVisible();
8781
await expect(vatTable.locator('tr')).toHaveCount(2);
8882
});
8983

9084
test('should restart a vat within subcluster', async () => {
9185
// Open the subcluster accordion first
92-
await popupPage.locator('.accordion-header').first().click();
86+
await popupPage.locator('[data-testid="accordion-header"]').first().click();
9387
await expect(
94-
popupPage.locator('button:text("Restart")').first(),
88+
popupPage.locator('[data-testid="restart-vat-button"]').first(),
9589
).toBeVisible();
96-
await popupPage.locator('button:text("Restart")').first().click();
90+
await popupPage
91+
.locator('[data-testid="restart-vat-button"]')
92+
.first()
93+
.click();
9794
await expect(
9895
popupPage.locator('[data-testid="message-output"]'),
9996
).toContainText('Restarted vat');
10097
});
10198

10299
test('should terminate a vat within subcluster', async () => {
103100
// Open the subcluster accordion first
104-
await popupPage.locator('.accordion-header').first().click();
101+
await popupPage.locator('[data-testid="accordion-header"]').first().click();
105102
await expect(
106-
popupPage.locator('td button:text("Terminate")').first(),
103+
popupPage.locator('td [data-testid="terminate-vat-button"]').first(),
107104
).toBeVisible();
108-
await popupPage.locator('td button:text("Terminate")').first().click();
105+
await popupPage
106+
.locator('td [data-testid="terminate-vat-button"]')
107+
.first()
108+
.click();
109109
await expect(
110110
popupPage.locator('[data-testid="message-output"]'),
111111
).toContainText('Terminated vat');
112112
});
113113

114114
test('should ping a vat within subcluster', async () => {
115115
// Open the subcluster accordion first
116-
await popupPage.locator('.accordion-header').first().click();
116+
await popupPage.locator('[data-testid="accordion-header"]').first().click();
117117
await expect(
118-
popupPage.locator('td button:text("Ping")').first(),
118+
popupPage.locator('[data-testid="ping-vat-button"]').first(),
119119
).toBeVisible();
120-
await popupPage.locator('td button:text("Ping")').first().click();
120+
await popupPage.locator('[data-testid="ping-vat-button"]').first().click();
121121
await expect(
122122
popupPage.locator('[data-testid="message-output"]'),
123123
).toContainText('"method": "pingVat",');
@@ -128,12 +128,12 @@ test.describe('Control Panel', () => {
128128

129129
test('should terminate a subcluster', async () => {
130130
// Open the subcluster accordion first
131-
await popupPage.locator('.accordion-header').first().click();
131+
await popupPage.locator('[data-testid="accordion-header"]').first().click();
132132
await expect(
133-
popupPage.locator('button:text("Terminate Subcluster")').first(),
133+
popupPage.locator('[data-testid="terminate-subcluster-button"]').first(),
134134
).toBeVisible();
135135
await popupPage
136-
.locator('button:text("Terminate Subcluster")')
136+
.locator('[data-testid="terminate-subcluster-button"]')
137137
.first()
138138
.click();
139139
await expect(
@@ -143,11 +143,14 @@ test.describe('Control Panel', () => {
143143

144144
test('should reload a subcluster', async () => {
145145
// Open the subcluster accordion first
146-
await popupPage.locator('.accordion-header').first().click();
146+
await popupPage.locator('[data-testid="accordion-header"]').first().click();
147147
await expect(
148-
popupPage.locator('button:text("Reload Subcluster")').first(),
148+
popupPage.locator('[data-testid="reload-subcluster-button"]').first(),
149149
).toBeVisible();
150-
await popupPage.locator('button:text("Reload Subcluster")').first().click();
150+
await popupPage
151+
.locator('[data-testid="reload-subcluster-button"]')
152+
.first()
153+
.click();
151154
await expect(
152155
popupPage.locator('[data-testid="message-output"]'),
153156
).toContainText('Reloaded subcluster');
@@ -280,8 +283,11 @@ test.describe('Control Panel', () => {
280283
).toContainText(value);
281284
}
282285
await popupPage.click('button:text("Control Panel")');
283-
await popupPage.locator('.accordion-header').first().click();
284-
await popupPage.locator('td button:text("Terminate")').last().click();
286+
await popupPage.locator('[data-testid="accordion-header"]').first().click();
287+
await popupPage
288+
.locator('[data-testid="terminate-vat-button"]')
289+
.last()
290+
.click();
285291
await expect(
286292
popupPage.locator('[data-testid="message-output"]'),
287293
).toContainText('Terminated vat "v3"');
@@ -329,9 +335,12 @@ test.describe('Control Panel', () => {
329335
popupPage.locator('[data-testid="message-output"]'),
330336
).toContainText('{"key":"kp3.refCount","value":"1"}');
331337
await popupPage.click('button:text("Control Panel")');
332-
await popupPage.locator('.accordion-header').first().click();
338+
await popupPage.locator('[data-testid="accordion-header"]').first().click();
333339
// delete v1
334-
await popupPage.locator('td button:text("Terminate")').first().click();
340+
await popupPage
341+
.locator('[data-testid="terminate-vat-button"]')
342+
.first()
343+
.click();
335344
await expect(
336345
popupPage.locator('[data-testid="message-output"]'),
337346
).toContainText('Terminated vat "v1"');

packages/extension/test/e2e/database-inspector.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ test.describe('Database Inspector', () => {
1414
await expect(
1515
popupPage.locator('[data-testid="subcluster-accordion-s1"]'),
1616
).toBeVisible();
17-
await popupPage.locator('.accordion-header').first().click();
17+
await popupPage.locator('[data-testid="accordion-header"]').first().click();
1818
await expect(popupPage.locator('table tr')).toHaveCount(4); // Header + 3 rows
1919
await popupPage.click('button:text("Database Inspector")');
2020
await expect(popupPage.locator('#root')).toContainText(
@@ -38,18 +38,18 @@ test.describe('Database Inspector', () => {
3838
});
3939

4040
test('should refresh table data', async () => {
41-
await popupPage.click('button:text("Refresh")');
41+
await popupPage.click('[data-testid="refresh-button"]');
4242
const table = popupPage.locator('table');
4343
await expect(table).toBeVisible();
4444
await expect(table).toContainText('nextVatId');
4545
});
4646

4747
test('should execute SQL query and show results', async () => {
4848
await popupPage.fill(
49-
'input[placeholder="Enter SQL query..."]',
49+
'[data-testid="sql-query-input"]',
5050
"SELECT value FROM kv WHERE key = 'nextVatId'",
5151
);
52-
await popupPage.click('button:text("Execute Query")');
52+
await popupPage.click('[data-testid="execute-query-button"]');
5353
const queryResults = popupPage.locator('table');
5454
await expect(queryResults).toBeVisible();
5555
const resultCell = queryResults.locator('td').first();
@@ -58,10 +58,10 @@ test.describe('Database Inspector', () => {
5858

5959
test('should handle invalid SQL queries', async () => {
6060
await popupPage.fill(
61-
'input[placeholder="Enter SQL query..."]',
61+
'[data-testid="sql-query-input"]',
6262
'INVALID SQL QUERY',
6363
);
64-
await popupPage.click('button:text("Execute Query")');
64+
await popupPage.click('[data-testid="execute-query-button"]');
6565
await expect(popupPage.locator('#root')).toContainText(
6666
'Failed to execute query',
6767
);

packages/extension/test/e2e/object-registry.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const sendMessage = async (
1919
.selectOption(target);
2020
await page.locator('input[data-testid="message-method"]').fill(method);
2121
await page.locator('input[data-testid="message-params"]').fill(params);
22-
await page.locator('button:text("Send")').click();
22+
await page.locator('button[data-testid="message-send-button"]').click();
2323
return page.locator('[data-testid="message-response"]');
2424
};
2525

@@ -29,7 +29,7 @@ export const revokeObject = async (
2929
target: string,
3030
): Promise<{ button: Locator; output: Locator }> => {
3131
await page
32-
.locator(`.accordion-header:has(.accordion-title:text("${owner}"))`)
32+
.locator(`[data-testid="accordion-header"]:has(:text("${owner}"))`)
3333
.click();
3434
const button = page.locator(`[data-testid="revoke-button-${target}"]`);
3535
await button.click();

packages/extension/vite.config.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,18 @@ export default defineConfig(({ mode }) => {
109109
},
110110
},
111111
},
112+
// Watch kernel-ui dist folder and trigger rebuilds
113+
{
114+
name: 'watch-kernel-ui',
115+
configureServer(server) {
116+
server.watcher.add(path.resolve(rootDir, 'kernel-ui/dist'));
117+
server.watcher.on('change', (file) => {
118+
if (file.includes('kernel-ui/dist')) {
119+
server.moduleGraph.invalidateAll();
120+
}
121+
});
122+
},
123+
},
112124
// Open the extension in the browser when watching
113125
isWatching && extensionDev({ extensionPath: outDir }),
114126
],

0 commit comments

Comments
 (0)