Skip to content

Commit 92e0966

Browse files
Kiya RoseKiya Rose
authored andcommitted
Half Init (Waiting on bugfix later today
1 parent 09f5903 commit 92e0966

10 files changed

Lines changed: 803 additions & 794 deletions

File tree

frontend/_worker.js

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@ export default {
1616
return new Response(null, { headers: corsHeaders });
1717
}
1818

19+
// Debug endpoint to inspect runtime bindings
20+
if (pathname === '/__bindings') {
21+
const bindings = {
22+
ASSETS_available: !!(env && env.ASSETS && typeof env.ASSETS.fetch === 'function'),
23+
STATUS_KV_bound: !!env.STATUS_KV,
24+
GITHUB_GIST_ID: !!env.GITHUB_GIST_ID,
25+
ISSUES_PAT: !!env.ISSUES_PAT
26+
};
27+
return new Response(JSON.stringify(bindings, null, 2), { headers: { 'Content-Type': 'application/json', ...corsHeaders } });
28+
}
29+
1930
if (pathname === '/api/status') {
2031
const state = await env.STATUS_KV.get('current_state');
2132
return new Response(state || JSON.stringify({ services: {}, incidents: [], maintenance: [], historyByService: {} }), {
@@ -79,38 +90,18 @@ export default {
7990
await saveState(env, state);
8091
return new Response(JSON.stringify({ success: true }), { headers: { 'Content-Type': 'application/json', ...corsHeaders }});
8192
}
82-
83-
if (pathname === '/api/admin/remove_incident') {
84-
// Expect { incidentId: string }
85-
let state = await env.STATUS_KV.get('current_state', 'json') || { services: {}, incidents: [], maintenance: [], historyByService: {} };
86-
if (!state.incidents) state.incidents = [];
87-
88-
const incidentId = String(body.incidentId || '').trim();
89-
if (!incidentId) {
90-
return new Response(JSON.stringify({ success: false, error: 'incidentId is required' }), {
91-
status: 400,
92-
headers: { 'Content-Type': 'application/json', ...corsHeaders }
93-
});
94-
}
95-
96-
const beforeCount = state.incidents.length;
97-
state.incidents = state.incidents.filter((incident) => incident.id !== incidentId);
98-
99-
if (state.incidents.length === beforeCount) {
100-
return new Response(JSON.stringify({ success: false, error: 'Incident not found' }), {
101-
status: 404,
102-
headers: { 'Content-Type': 'application/json', ...corsHeaders }
103-
});
104-
}
105-
106-
await saveState(env, state);
107-
return new Response(JSON.stringify({ success: true }), { headers: { 'Content-Type': 'application/json', ...corsHeaders }});
108-
}
10993
}
11094
}
11195

112-
// Fallback to static assets
113-
return env.ASSETS.fetch(request);
96+
// Fallback to static assets — guard in case ASSETS isn't bound so we don't throw.
97+
if (env && env.ASSETS && typeof env.ASSETS.fetch === 'function') {
98+
return env.ASSETS.fetch(request);
99+
}
100+
101+
// If ASSETS is missing (deployment/config issue), return a small friendly page
102+
// instead of throwing so the admin APIs still work and logs are clearer.
103+
const fallbackHtml = `<!doctype html><html><head><meta charset="utf-8"><title>Static assets unavailable</title></head><body><h1>Static assets unavailable</h1><p>The Worker runtime does not have an <code>ASSETS</code> binding. Check your Pages/Workers configuration.</p><p>Visit <a href="/__bindings">/__bindings</a> to inspect runtime bindings.</p></body></html>`;
104+
return new Response(fallbackHtml, { headers: { 'Content-Type': 'text/html; charset=utf-8' }, status: 500 });
114105
},
115106

116107
async scheduled(event, env, ctx) {

frontend/admin.html

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,6 @@ <h2 class="section-title">Post Incident Update</h2>
7777
<button class="btn" onclick="postIncident()">Post Update</button>
7878
<p id="incident-feedback" class="feedback-message"></p>
7979
</section>
80-
81-
<section class="section-card admin-panel">
82-
<h2 class="section-title">Investigation List</h2>
83-
<p class="admin-panel-description">Remove investigation entries that should no longer appear on the status page.</p>
84-
<div id="admin-incidents-list" class="admin-incident-list">
85-
<p class="loading-text">Loading investigation entries...</p>
86-
</div>
87-
<p id="remove-incident-feedback" class="feedback-message"></p>
88-
</section>
8980
</div>
9081

9182
<footer class="page-footer page-footer-admin">

frontend/css/style.css

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -430,14 +430,6 @@ textarea.form-control {
430430
transform: translateY(-1px);
431431
}
432432

433-
.btn-danger {
434-
background-color: color-mix(in srgb, var(--status-down) 86%, #8a2222);
435-
}
436-
437-
.btn-danger:hover {
438-
background-color: color-mix(in srgb, var(--status-down) 92%, #6f1111);
439-
}
440-
441433
.feedback-message {
442434
margin-top: 0.8rem;
443435
min-height: 1.2rem;
@@ -501,40 +493,6 @@ textarea.form-control {
501493
margin-top: 1.2rem;
502494
}
503495

504-
.admin-incident-list {
505-
display: flex;
506-
flex-direction: column;
507-
gap: 0.6rem;
508-
}
509-
510-
.admin-incident-item {
511-
border: 1px solid var(--border-color);
512-
border-radius: 12px;
513-
padding: 0.75rem;
514-
display: flex;
515-
align-items: center;
516-
justify-content: space-between;
517-
gap: 0.8rem;
518-
background-color: color-mix(in srgb, var(--card-bg) 96%, transparent);
519-
}
520-
521-
.admin-incident-meta {
522-
min-width: 0;
523-
}
524-
525-
.admin-incident-title {
526-
font-size: 0.92rem;
527-
font-weight: 700;
528-
white-space: nowrap;
529-
overflow: hidden;
530-
text-overflow: ellipsis;
531-
}
532-
533-
.admin-incident-subtitle {
534-
font-size: 0.78rem;
535-
color: var(--text-secondary);
536-
}
537-
538496
@media (max-width: 860px) {
539497
.top-hero {
540498
flex-direction: column;
@@ -567,9 +525,4 @@ textarea.form-control {
567525
flex-direction: column;
568526
gap: 0.35rem;
569527
}
570-
571-
.admin-incident-item {
572-
flex-direction: column;
573-
align-items: flex-start;
574-
}
575528
}

frontend/js/admin.js

Lines changed: 4 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
const WORKER_URL = ''; // Relative to the same domain in CF Pages
2-
3-
document.addEventListener('DOMContentLoaded', loadIncidentList);
1+
// During local development (static server on localhost), point API calls to the local Worker.
2+
const WORKER_URL = (typeof window !== 'undefined' && (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'))
3+
? 'http://127.0.0.1:8787'
4+
: '';
45

56
async function updateServiceStatus() {
67
const serviceId = document.getElementById('service-id').value;
@@ -53,7 +54,6 @@ async function postIncident() {
5354
setFeedback(feedback, 'Incident posted successfully!', 'success');
5455
document.getElementById('inc-title').value = '';
5556
document.getElementById('inc-desc').value = '';
56-
await loadIncidentList();
5757
} else {
5858
setFeedback(feedback, `Failed: ${res.statusText}`, 'error');
5959
}
@@ -62,90 +62,6 @@ async function postIncident() {
6262
}
6363
}
6464

65-
async function loadIncidentList() {
66-
const listEl = document.getElementById('admin-incidents-list');
67-
if (!listEl) return;
68-
69-
listEl.innerHTML = '<p class="loading-text">Loading investigation entries...</p>';
70-
71-
try {
72-
const res = await fetch(`${WORKER_URL}/api/status`);
73-
if (!res.ok) {
74-
listEl.innerHTML = '<p class="loading-text">Unable to load entries right now.</p>';
75-
return;
76-
}
77-
78-
const data = await res.json();
79-
const incidents = Array.isArray(data.incidents) ? data.incidents : [];
80-
81-
if (incidents.length === 0) {
82-
listEl.innerHTML = '<p class="loading-text">No entries in the investigation list.</p>';
83-
return;
84-
}
85-
86-
listEl.innerHTML = incidents.map((incident) => {
87-
const createdLabel = incident.createdAt ? new Date(incident.createdAt).toLocaleString() : 'Unknown time';
88-
return `
89-
<article class="admin-incident-item">
90-
<div class="admin-incident-meta">
91-
<p class="admin-incident-title">${escapeHtml(incident.title || 'Untitled')}</p>
92-
<p class="admin-incident-subtitle">${escapeHtml(incident.status || 'Unknown')}${escapeHtml(createdLabel)}</p>
93-
</div>
94-
<button class="btn btn-danger" onclick="removeIncident('${encodeURIComponent(incident.id || '')}')">Remove</button>
95-
</article>
96-
`;
97-
}).join('');
98-
} catch (e) {
99-
listEl.innerHTML = '<p class="loading-text">Unable to load entries right now.</p>';
100-
}
101-
}
102-
103-
async function removeIncident(encodedIncidentId) {
104-
const incidentId = decodeURIComponent(encodedIncidentId || '');
105-
const feedback = document.getElementById('remove-incident-feedback');
106-
if (!incidentId) {
107-
setFeedback(feedback, 'Missing incident ID.', 'error');
108-
return;
109-
}
110-
111-
setFeedback(feedback, '', null);
112-
113-
try {
114-
const res = await fetch(`${WORKER_URL}/api/admin/remove_incident`, {
115-
method: 'POST',
116-
headers: {
117-
'Content-Type': 'application/json'
118-
},
119-
body: JSON.stringify({ incidentId })
120-
});
121-
122-
if (res.ok) {
123-
setFeedback(feedback, 'Investigation entry removed.', 'success');
124-
await loadIncidentList();
125-
} else {
126-
let errorMessage = `Failed: ${res.statusText}`;
127-
try {
128-
const body = await res.json();
129-
if (body?.error) errorMessage = `Failed: ${body.error}`;
130-
} catch {
131-
// keep fallback message
132-
}
133-
setFeedback(feedback, errorMessage, 'error');
134-
}
135-
} catch (e) {
136-
setFeedback(feedback, `Error: ${e.message}`, 'error');
137-
}
138-
}
139-
140-
function escapeHtml(value) {
141-
return String(value)
142-
.replaceAll('&', '&amp;')
143-
.replaceAll('<', '&lt;')
144-
.replaceAll('>', '&gt;')
145-
.replaceAll('"', '&quot;')
146-
.replaceAll("'", '&#39;');
147-
}
148-
14965
function setFeedback(element, message, type) {
15066
element.textContent = message;
15167
element.classList.remove('feedback-success', 'feedback-error');

frontend/js/app.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
const WORKER_URL = ''; // Relative to the same domain in CF Pages
1+
// During local development (static server on localhost), point API calls to the local Worker.
2+
const WORKER_URL = (typeof window !== 'undefined' && (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'))
3+
? 'http://127.0.0.1:8787'
4+
: '';
25
const GIST_URL = 'https://gist.githubusercontent.com/MOCK_USER/MOCK_GIST_ID/raw/status.json'; // TO BE REPLACED
36

47
async function fetchStatus() {

0 commit comments

Comments
 (0)