Skip to content

Commit 12f3826

Browse files
Jonathan D.A. Jewellclaude
andcommitted
feat: add DevTools integration and icon generation
- Generate extension icons (16/32/48/96/128px) from SVG using ImageMagick - Create DevTools panel with 4 tabs: Active Flags, Performance, Impact Analysis, Console - Add ReScript DevTools module with performance metrics collection - Implement before/after impact recording for flag changes - Add performance metrics: DCL, load complete, FCP, memory usage - Create DevTools entry point (devtools.html + devtools.js) - Update manifest.json with devtools_page - Add console logging and export functionality DevTools panel shows real-time flag impact on page performance. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 99d84db commit 12f3826

14 files changed

Lines changed: 1050 additions & 0 deletions

extension/devtools/devtools.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<!-- SPDX-License-Identifier: PMPL-1.0-or-later -->
3+
<html>
4+
<head>
5+
<meta charset="UTF-8">
6+
</head>
7+
<body>
8+
<script src="devtools.js"></script>
9+
</body>
10+
</html>

extension/devtools/devtools.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-License-Identifier: PMPL-1.0-or-later
2+
// Copyright (C) 2026 Jonathan D.A. Jewell <jonathan.jewell@open.ac.uk>
3+
4+
/**
5+
* FireFlag DevTools Entry Point
6+
*
7+
* Creates the DevTools panel when DevTools is opened.
8+
*/
9+
10+
browser.devtools.panels.create(
11+
"FireFlag",
12+
"../icons/fireflag-32.png",
13+
"devtools/panel.html"
14+
).then((panel) => {
15+
console.log("FireFlag DevTools panel created");
16+
}).catch((error) => {
17+
console.error("Failed to create FireFlag DevTools panel:", error);
18+
});

extension/devtools/panel.css

Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
/* SPDX-License-Identifier: PMPL-1.0-or-later */
2+
3+
:root {
4+
--primary-color: #0060df;
5+
--safe-color: #12bc00;
6+
--experimental-color: #ff9400;
7+
--dangerous-color: #d70022;
8+
--bg-color: #ffffff;
9+
--secondary-bg: #f9f9fa;
10+
--text-color: #0c0c0d;
11+
--border-color: #d7d7db;
12+
--code-bg: #f5f5f5;
13+
}
14+
15+
* {
16+
margin: 0;
17+
padding: 0;
18+
box-sizing: border-box;
19+
}
20+
21+
body {
22+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
23+
font-size: 12px;
24+
color: var(--text-color);
25+
background: var(--bg-color);
26+
overflow: hidden;
27+
}
28+
29+
.devtools-panel {
30+
display: flex;
31+
flex-direction: column;
32+
height: 100vh;
33+
}
34+
35+
.panel-header {
36+
display: flex;
37+
justify-content: space-between;
38+
align-items: center;
39+
padding: 12px 16px;
40+
border-bottom: 1px solid var(--border-color);
41+
background: var(--secondary-bg);
42+
}
43+
44+
.panel-header h1 {
45+
font-size: 14px;
46+
font-weight: 600;
47+
}
48+
49+
.panel-actions {
50+
display: flex;
51+
gap: 8px;
52+
}
53+
54+
.tool-btn {
55+
padding: 6px 12px;
56+
border: 1px solid var(--border-color);
57+
border-radius: 3px;
58+
background: white;
59+
cursor: pointer;
60+
font-size: 11px;
61+
transition: all 0.2s;
62+
}
63+
64+
.tool-btn:hover {
65+
background: var(--secondary-bg);
66+
border-color: var(--primary-color);
67+
}
68+
69+
.panel-tabs {
70+
display: flex;
71+
border-bottom: 1px solid var(--border-color);
72+
background: var(--secondary-bg);
73+
}
74+
75+
.tab-btn {
76+
padding: 10px 20px;
77+
border: none;
78+
background: none;
79+
cursor: pointer;
80+
font-size: 12px;
81+
border-bottom: 2px solid transparent;
82+
transition: all 0.2s;
83+
}
84+
85+
.tab-btn:hover {
86+
background: rgba(0,0,0,0.05);
87+
}
88+
89+
.tab-btn.active {
90+
border-bottom-color: var(--primary-color);
91+
color: var(--primary-color);
92+
}
93+
94+
.tab-content {
95+
display: none;
96+
flex: 1;
97+
overflow-y: auto;
98+
padding: 16px;
99+
}
100+
101+
.tab-content.active {
102+
display: block;
103+
}
104+
105+
.section-header {
106+
display: flex;
107+
justify-content: space-between;
108+
align-items: center;
109+
margin-bottom: 16px;
110+
}
111+
112+
.section-header h2 {
113+
font-size: 14px;
114+
font-weight: 600;
115+
}
116+
117+
.count-badge {
118+
background: var(--primary-color);
119+
color: white;
120+
padding: 2px 8px;
121+
border-radius: 10px;
122+
font-size: 11px;
123+
font-weight: 600;
124+
}
125+
126+
.flags-table {
127+
background: white;
128+
border: 1px solid var(--border-color);
129+
border-radius: 4px;
130+
overflow: hidden;
131+
}
132+
133+
table {
134+
width: 100%;
135+
border-collapse: collapse;
136+
}
137+
138+
th {
139+
background: var(--secondary-bg);
140+
padding: 8px 12px;
141+
text-align: left;
142+
font-weight: 600;
143+
font-size: 11px;
144+
text-transform: uppercase;
145+
border-bottom: 1px solid var(--border-color);
146+
}
147+
148+
td {
149+
padding: 10px 12px;
150+
border-bottom: 1px solid var(--border-color);
151+
font-size: 11px;
152+
}
153+
154+
tr:last-child td {
155+
border-bottom: none;
156+
}
157+
158+
.empty-state {
159+
text-align: center;
160+
color: #737373;
161+
padding: 40px !important;
162+
}
163+
164+
.safety-badge {
165+
padding: 2px 6px;
166+
border-radius: 3px;
167+
font-size: 10px;
168+
font-weight: 600;
169+
text-transform: uppercase;
170+
}
171+
172+
.safety-badge.safe { background: var(--safe-color); color: white; }
173+
.safety-badge.experimental { background: var(--experimental-color); color: white; }
174+
.safety-badge.dangerous { background: var(--dangerous-color); color: white; }
175+
176+
.metrics-grid {
177+
display: grid;
178+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
179+
gap: 12px;
180+
}
181+
182+
.metric-card {
183+
background: white;
184+
border: 1px solid var(--border-color);
185+
border-radius: 4px;
186+
padding: 16px;
187+
display: flex;
188+
flex-direction: column;
189+
gap: 8px;
190+
}
191+
192+
.metric-label {
193+
font-size: 11px;
194+
color: #737373;
195+
text-transform: uppercase;
196+
}
197+
198+
.metric-value {
199+
font-size: 20px;
200+
font-weight: 600;
201+
color: var(--primary-color);
202+
font-family: 'Courier New', monospace;
203+
}
204+
205+
.secondary-btn {
206+
padding: 6px 12px;
207+
background: white;
208+
color: var(--primary-color);
209+
border: 1px solid var(--primary-color);
210+
border-radius: 3px;
211+
cursor: pointer;
212+
font-size: 11px;
213+
font-weight: 600;
214+
}
215+
216+
.secondary-btn:hover {
217+
background: rgba(0, 96, 223, 0.1);
218+
}
219+
220+
.recording-status {
221+
padding: 6px 12px;
222+
background: var(--code-bg);
223+
border-radius: 3px;
224+
font-size: 11px;
225+
font-family: monospace;
226+
}
227+
228+
.recording-status.active {
229+
background: #ffe0e0;
230+
color: var(--dangerous-color);
231+
}
232+
233+
.impact-instructions {
234+
background: var(--secondary-bg);
235+
border: 1px solid var(--border-color);
236+
border-radius: 4px;
237+
padding: 16px;
238+
margin-bottom: 16px;
239+
}
240+
241+
.impact-instructions h3 {
242+
font-size: 12px;
243+
margin-bottom: 12px;
244+
}
245+
246+
.impact-instructions ol {
247+
margin-left: 20px;
248+
line-height: 1.6;
249+
}
250+
251+
.impact-results {
252+
display: flex;
253+
flex-direction: column;
254+
gap: 12px;
255+
}
256+
257+
.impact-item {
258+
background: white;
259+
border: 1px solid var(--border-color);
260+
border-radius: 4px;
261+
padding: 16px;
262+
}
263+
264+
.impact-header {
265+
display: flex;
266+
justify-content: space-between;
267+
align-items: center;
268+
margin-bottom: 12px;
269+
}
270+
271+
.impact-flag {
272+
font-weight: 600;
273+
font-family: monospace;
274+
}
275+
276+
.impact-badge {
277+
padding: 4px 8px;
278+
border-radius: 3px;
279+
font-size: 11px;
280+
font-weight: 600;
281+
}
282+
283+
.impact-badge.improved {
284+
background: var(--safe-color);
285+
color: white;
286+
}
287+
288+
.impact-badge.degraded {
289+
background: var(--dangerous-color);
290+
color: white;
291+
}
292+
293+
.impact-metrics {
294+
display: grid;
295+
grid-template-columns: 1fr 1fr;
296+
gap: 8px;
297+
font-size: 11px;
298+
}
299+
300+
.console-output {
301+
background: var(--code-bg);
302+
border: 1px solid var(--border-color);
303+
border-radius: 4px;
304+
padding: 12px;
305+
font-family: 'Courier New', monospace;
306+
font-size: 11px;
307+
max-height: 400px;
308+
overflow-y: auto;
309+
}
310+
311+
.console-message {
312+
padding: 4px 0;
313+
border-bottom: 1px solid rgba(0,0,0,0.05);
314+
}
315+
316+
.console-message:last-child {
317+
border-bottom: none;
318+
}
319+
320+
.timestamp {
321+
color: #737373;
322+
margin-right: 8px;
323+
}
324+
325+
.console-message.info .message { color: var(--primary-color); }
326+
.console-message.warn .message { color: var(--experimental-color); }
327+
.console-message.error .message { color: var(--dangerous-color); }

0 commit comments

Comments
 (0)