Skip to content

Commit 99d84db

Browse files
Jonathan D.A. Jewellclaude
andcommitted
feat: complete UI components and background service worker
- Add popup JavaScript with flag loading, toggle, permission requests - Create sidebar with 4 views: flags, tracking, analytics, export - Implement tracking timeline with before/after snapshots - Add export system (JSON/Markdown/CSV) with custom reports - Build options page with 5 sections: general, tracking, permissions, advanced, about - Create background service worker for message handling and state management - Add settings management with auto-save - Implement permission request flow with granular feedback All three UI components (popup, sidebar, options) now functional. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 51525d9 commit 99d84db

8 files changed

Lines changed: 2117 additions & 0 deletions

File tree

extension/background/background.js

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
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 Background Service Worker
6+
*
7+
* Handles flag modifications and message passing between UI components.
8+
*/
9+
10+
const STORAGE_KEY = 'fireflag_state';
11+
const HISTORY_KEY = 'fireflag_history';
12+
const SETTINGS_KEY = 'fireflag_settings';
13+
14+
// Initialize extension
15+
browser.runtime.onInstalled.addListener(async (details) => {
16+
if (details.reason === 'install') {
17+
console.log('FireFlag installed');
18+
await initializeSettings();
19+
} else if (details.reason === 'update') {
20+
console.log('FireFlag updated to', browser.runtime.getManifest().version);
21+
}
22+
});
23+
24+
// Initialize default settings
25+
async function initializeSettings() {
26+
const defaultSettings = {
27+
autoUpdateDatabase: false,
28+
showModifiedBadge: true,
29+
confirmDangerous: true,
30+
enableTracking: true,
31+
historyLimit: 100,
32+
enableMetrics: false,
33+
devtoolsIntegration: false,
34+
verboseLogging: false
35+
};
36+
37+
await browser.storage.local.set({
38+
[SETTINGS_KEY]: defaultSettings
39+
});
40+
}
41+
42+
// Message handler
43+
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
44+
handleMessage(message).then(sendResponse);
45+
return true; // Keep channel open for async response
46+
});
47+
48+
// Handle messages from UI
49+
async function handleMessage(message) {
50+
try {
51+
switch (message.type) {
52+
case 'SET_FLAG':
53+
return await setFlag(message.key, message.value);
54+
55+
case 'GET_FLAG':
56+
return await getFlag(message.key);
57+
58+
case 'RESET_FLAG':
59+
return await resetFlag(message.key);
60+
61+
case 'GET_SETTINGS':
62+
return await getSettings();
63+
64+
case 'UPDATE_SETTINGS':
65+
return await updateSettings(message.settings);
66+
67+
default:
68+
return { success: false, error: 'Unknown message type' };
69+
}
70+
} catch (error) {
71+
console.error('Message handler error:', error);
72+
return { success: false, error: error.message };
73+
}
74+
}
75+
76+
// Set flag value
77+
async function setFlag(key, value) {
78+
try {
79+
const settings = await getSettings();
80+
const result = await browser.storage.local.get(STORAGE_KEY);
81+
const states = result[STORAGE_KEY] || {};
82+
83+
const beforeValue = states[key]?.value ?? null;
84+
const timestamp = Date.now();
85+
86+
// Update state
87+
states[key] = {
88+
value,
89+
timestamp,
90+
modifiedBy: 'extension'
91+
};
92+
93+
await browser.storage.local.set({ [STORAGE_KEY]: states });
94+
95+
// Track change if enabled
96+
if (settings.enableTracking) {
97+
await trackFlagChange(key, beforeValue, value, timestamp);
98+
}
99+
100+
// Log if verbose
101+
if (settings.verboseLogging) {
102+
console.log(`Flag set: ${key} = ${value}`);
103+
}
104+
105+
return { success: true, key, value };
106+
} catch (error) {
107+
console.error('Failed to set flag:', error);
108+
return { success: false, error: error.message };
109+
}
110+
}
111+
112+
// Get flag value
113+
async function getFlag(key) {
114+
try {
115+
const result = await browser.storage.local.get(STORAGE_KEY);
116+
const states = result[STORAGE_KEY] || {};
117+
118+
return {
119+
success: true,
120+
key,
121+
value: states[key]?.value ?? null,
122+
timestamp: states[key]?.timestamp ?? null
123+
};
124+
} catch (error) {
125+
return { success: false, error: error.message };
126+
}
127+
}
128+
129+
// Reset flag to default
130+
async function resetFlag(key) {
131+
try {
132+
const result = await browser.storage.local.get(STORAGE_KEY);
133+
const states = result[STORAGE_KEY] || {};
134+
135+
delete states[key];
136+
await browser.storage.local.set({ [STORAGE_KEY]: states });
137+
138+
return { success: true, key };
139+
} catch (error) {
140+
return { success: false, error: error.message };
141+
}
142+
}
143+
144+
// Track flag change in history
145+
async function trackFlagChange(key, beforeValue, afterValue, timestamp) {
146+
try {
147+
const result = await browser.storage.local.get([HISTORY_KEY, SETTINGS_KEY]);
148+
const history = result[HISTORY_KEY] || [];
149+
const settings = result[SETTINGS_KEY] || {};
150+
151+
// Add change to history
152+
history.push({
153+
key,
154+
beforeValue,
155+
afterValue,
156+
timestamp,
157+
source: 'extension'
158+
});
159+
160+
// Trim history if needed
161+
const limit = settings.historyLimit || 100;
162+
if (history.length > limit) {
163+
history.splice(0, history.length - limit);
164+
}
165+
166+
await browser.storage.local.set({ [HISTORY_KEY]: history });
167+
} catch (error) {
168+
console.error('Failed to track flag change:', error);
169+
}
170+
}
171+
172+
// Get settings
173+
async function getSettings() {
174+
const result = await browser.storage.local.get(SETTINGS_KEY);
175+
return result[SETTINGS_KEY] || {};
176+
}
177+
178+
// Update settings
179+
async function updateSettings(newSettings) {
180+
try {
181+
const current = await getSettings();
182+
const updated = { ...current, ...newSettings };
183+
184+
await browser.storage.local.set({ [SETTINGS_KEY]: updated });
185+
186+
return { success: true, settings: updated };
187+
} catch (error) {
188+
return { success: false, error: error.message };
189+
}
190+
}
191+
192+
console.log('FireFlag background service worker initialized');

0 commit comments

Comments
 (0)