Skip to content

Commit 92d2b57

Browse files
committed
feat: add Update Environment MCP App
### Description Adds the Update Environment MCP App, allowing users to switch projects and directories from the UI. ### Scenarios Tested - Verified build and file changes.
1 parent 0b1be78 commit 92d2b57

3 files changed

Lines changed: 482 additions & 0 deletions

File tree

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Update Firebase Environment</title>
7+
<link rel="preconnect" href="https://fonts.googleapis.com" />
8+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet" />
10+
<style>
11+
:root {
12+
--primary-color: #ffca28; /* Firebase Yellow */
13+
--primary-hover: #ffb300;
14+
--bg-glass: rgba(30, 30, 30, 0.7);
15+
--text-main: #ffffff;
16+
--text-sub: #b0b0b0;
17+
--border-color: rgba(255, 255, 255, 0.1);
18+
--transition-speed: 0.2s;
19+
--accent-blue: #1976d2;
20+
}
21+
22+
body {
23+
font-family: 'Inter', sans-serif;
24+
background-color: #121212;
25+
color: var(--text-main);
26+
margin: 0;
27+
padding: 24px;
28+
display: flex;
29+
flex-direction: column;
30+
align-items: center;
31+
justify-content: flex-start;
32+
min-height: 100vh;
33+
box-sizing: border-box;
34+
}
35+
36+
.container {
37+
width: 100%;
38+
max-width: 500px;
39+
background: var(--bg-glass);
40+
backdrop-filter: blur(12px);
41+
-webkit-backdrop-filter: blur(12px);
42+
border: 1px solid var(--border-color);
43+
border-radius: 16px;
44+
padding: 32px;
45+
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
46+
display: flex;
47+
flex-direction: column;
48+
gap: 24px;
49+
}
50+
51+
.header {
52+
display: flex;
53+
flex-direction: column;
54+
gap: 8px;
55+
text-align: center;
56+
}
57+
58+
h1 {
59+
font-size: 24px;
60+
font-weight: 600;
61+
margin: 0;
62+
background: linear-gradient(135deg, #ffca28 0%, #ff8f00 100%);
63+
-webkit-background-clip: text;
64+
-webkit-text-fill-color: transparent;
65+
}
66+
67+
p.subtitle {
68+
font-size: 14px;
69+
color: var(--text-sub);
70+
margin: 0;
71+
}
72+
73+
.search-box {
74+
position: relative;
75+
display: flex;
76+
flex-direction: column;
77+
gap: 8px;
78+
}
79+
80+
label {
81+
font-size: 12px;
82+
font-weight: 500;
83+
color: var(--text-sub);
84+
text-transform: uppercase;
85+
letter-spacing: 0.5px;
86+
}
87+
88+
input[type="text"] {
89+
background: rgba(255, 255, 255, 0.05);
90+
border: 1px solid var(--border-color);
91+
border-radius: 8px;
92+
padding: 12px 16px;
93+
color: var(--text-main);
94+
font-size: 14px;
95+
transition: border-color var(--transition-speed);
96+
width: 100%;
97+
box-sizing: border-box;
98+
}
99+
100+
input[type="text"]:focus {
101+
outline: none;
102+
border-color: var(--primary-color);
103+
background: rgba(255, 255, 255, 0.08);
104+
}
105+
106+
.dropdown-container {
107+
position: relative;
108+
width: 100%;
109+
}
110+
111+
.dropdown-list {
112+
background: #1e1e1e;
113+
border: 1px solid var(--border-color);
114+
border-radius: 8px;
115+
max-height: 250px;
116+
overflow-y: auto;
117+
display: flex;
118+
flex-direction: column;
119+
width: 100%;
120+
box-sizing: border-box;
121+
margin-top: 4px;
122+
}
123+
124+
.dropdown-item {
125+
padding: 12px 16px;
126+
cursor: pointer;
127+
transition: background-color var(--transition-speed);
128+
display: flex;
129+
flex-direction: column;
130+
gap: 4px;
131+
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
132+
}
133+
134+
.dropdown-item:last-child {
135+
border-bottom: none;
136+
}
137+
138+
.dropdown-item:hover, .dropdown-item.selected {
139+
background: rgba(255, 255, 255, 0.1);
140+
}
141+
142+
.dropdown-item.selected {
143+
border-left: 3px solid var(--primary-color);
144+
}
145+
146+
.item-name {
147+
font-size: 14px;
148+
font-weight: 500;
149+
}
150+
151+
.item-id {
152+
font-size: 12px;
153+
color: var(--text-sub);
154+
}
155+
156+
.actions {
157+
display: flex;
158+
flex-direction: column;
159+
gap: 12px;
160+
}
161+
162+
button {
163+
background: linear-gradient(135deg, #ffca28 0%, #ff9100 100%);
164+
color: #000000;
165+
border: none;
166+
border-radius: 12px;
167+
padding: 14px;
168+
font-size: 16px;
169+
font-weight: 600;
170+
cursor: pointer;
171+
transition: transform 0.1s ease, box-shadow 0.2s ease;
172+
box-shadow: 0 4px 12px rgba(255, 179, 0, 0.3);
173+
}
174+
175+
button:hover {
176+
transform: translateY(-2px);
177+
box-shadow: 0 6px 16px rgba(255, 179, 0, 0.4);
178+
}
179+
180+
button:active {
181+
transform: translateY(0);
182+
}
183+
184+
button:disabled {
185+
background: #4a4a4a;
186+
color: #888888;
187+
cursor: not-allowed;
188+
transform: none;
189+
box-shadow: none;
190+
}
191+
192+
#status-box {
193+
padding: 12px;
194+
border-radius: 8px;
195+
font-size: 14px;
196+
display: none;
197+
animation: fadeIn 0.3s ease;
198+
}
199+
200+
@keyframes fadeIn {
201+
from { opacity: 0; transform: translateY(-10px); }
202+
to { opacity: 1; transform: translateY(0); }
203+
}
204+
205+
.status.success {
206+
display: block;
207+
background: rgba(76, 175, 80, 0.15);
208+
border: 1px solid #4caf50;
209+
color: #4caf50;
210+
}
211+
212+
.status.error {
213+
display: block;
214+
background: rgba(244, 67, 54, 0.15);
215+
border: 1px solid #f44336;
216+
color: #f44336;
217+
}
218+
219+
.status.info {
220+
display: block;
221+
background: rgba(33, 150, 243, 0.15);
222+
border: 1px solid #2196f3;
223+
color: #2196f3;
224+
}
225+
226+
/* Custom Scrollbar */
227+
.dropdown-list::-webkit-scrollbar {
228+
width: 8px;
229+
}
230+
.dropdown-list::-webkit-scrollbar-track {
231+
background: rgba(0, 0, 0, 0.1);
232+
}
233+
.dropdown-list::-webkit-scrollbar-thumb {
234+
background: rgba(255, 255, 255, 0.2);
235+
border-radius: 4px;
236+
}
237+
.dropdown-list::-webkit-scrollbar-thumb:hover {
238+
background: rgba(255, 255, 255, 0.4);
239+
}
240+
.current-env-box {
241+
background: rgba(255, 255, 255, 0.05);
242+
border: 1px solid rgba(255, 255, 255, 0.1);
243+
border-radius: var(--border-radius-md, 8px);
244+
padding: 16px;
245+
margin-bottom: 24px;
246+
text-align: left;
247+
}
248+
.current-env-box h3 {
249+
margin-top: 0;
250+
margin-bottom: 8px;
251+
font-size: var(--font-text-md-size, 14px);
252+
color: var(--color-text-secondary, #a1a1aa);
253+
}
254+
.current-env-box p {
255+
margin: 4px 0;
256+
font-size: var(--font-text-sm-size, 13px);
257+
}
258+
.current-env-box span {
259+
font-weight: bold;
260+
color: var(--color-text, #ffffff);
261+
}
262+
</style>
263+
</head>
264+
<body>
265+
<div class="container">
266+
<div class="header">
267+
<h1>Choose a Firebase Project</h1>
268+
<p class="subtitle">Select an active Firebase project for your workspace.</p>
269+
</div>
270+
271+
<div id="current-env" class="current-env-box">
272+
<h3>Current Context</h3>
273+
<p>Project ID: <span id="env-project-id">-</span></p>
274+
<p>User: <span id="env-user">-</span></p>
275+
</div>
276+
277+
<div class="search-box">
278+
<label for="search-input">Search Projects</label>
279+
<input type="text" id="search-input" placeholder="Type to filter projects..." />
280+
</div>
281+
282+
<div class="dropdown-container">
283+
<label>Available Projects</label>
284+
<div id="project-list" class="dropdown-list">
285+
<!-- Items will be injected here -->
286+
<div class="dropdown-item" style="cursor: default;">
287+
<div class="item-name">Loading projects...</div>
288+
</div>
289+
</div>
290+
</div>
291+
292+
<div class="actions">
293+
<button id="submit-btn" disabled>Set Active Project</button>
294+
<div id="status-box"></div>
295+
</div>
296+
</div>
297+
<script type="module" src="mcp-app.ts"></script>
298+
</body>
299+
</html>

0 commit comments

Comments
 (0)