diff --git a/static/billing-dashboard.html b/static/billing-dashboard.html
index 7dfaae4..7fd54bd 100644
--- a/static/billing-dashboard.html
+++ b/static/billing-dashboard.html
@@ -204,9 +204,7 @@ footer{padding:10px 20px 16px;font-size:11px;color:var(--faint);text-align:cente
-
-
-
+ GCP
🔔 Varsler aktive
@@ -432,7 +430,7 @@ footer{padding:10px 20px 16px;font-size:11px;color:var(--faint);text-align:cente
const API_BASE = '';
let currentBudget = 500;
const REFRESH_MS = 5 * 60 * 1000;
-let currentProvider = localStorage.getItem('costguard_provider') || 'gcp';
+let currentProvider = 'gcp';
const DEMO_SUMMARY = [
{service:'Cloud Run',total_cost:1.82},{service:'Cloud Build',total_cost:0.61},
@@ -444,7 +442,7 @@ const DEMO_FORECAST = {month_to_date_cost:3.00,daily_average_last_7_days:0.13,to
const DEMO_ANOMALIES = [];
let barChart,donutChart,period=30;
-let currentData={gcp: null, aws: null};
+let currentData={gcp: null};
let userProfile = null;
function fmtNOK(v,d=2){
@@ -469,10 +467,11 @@ async function apiFetch(url, options = {}) {
}
function switchProvider(provider) {
- currentProvider = provider;
- localStorage.setItem('costguard_provider', provider);
+ // AWS-støtte er parkert; vi holder oss på GCP
+ currentProvider = 'gcp';
+ localStorage.setItem('costguard_provider', 'gcp');
document.querySelectorAll('#provider-toggle .sel-opt').forEach(btn => {
- btn.classList.toggle('active', btn.dataset.provider === provider);
+ btn.classList.toggle('active', btn.dataset.provider === 'gcp');
});
fetchAll();
}
@@ -562,20 +561,28 @@ async function fetchAll(){
const gcpForecast = apiFetch(API_BASE+'/billing/live');
const gcpAnomalies = apiFetch(API_BASE+'/billing/anomalies');
const gcpHistory = apiFetch(API_BASE+'/billing/history');
-
- const awsSummary = apiFetch(API_BASE+'/billing/aws/summary');
- const awsForecast = apiFetch(API_BASE+'/billing/aws/forecast');
- const [gcpSR, gcpLR, gcpAR, gcpHR, awsSR, awsLR] = await Promise.all([gcpSummary, gcpForecast, gcpAnomalies, gcpHistory, awsSummary, awsForecast]);
+ const [gcpSR, gcpLR, gcpAR, gcpHR] = await Promise.all([gcpSummary, gcpForecast, gcpAnomalies, gcpHistory]);
- if (!gcpSR.ok || !gcpLR.ok || !gcpAR.ok || !gcpHR.ok || !awsSR.ok || !awsLR.ok) {
- throw new Error('HTTP error on one or more endpoints');
+ // GCP summary/forecast/anomalies er kritiske; history er nice-to-have
+ if (!gcpSR.ok || !gcpLR.ok || !gcpAR.ok) {
+ throw new Error('HTTP error on core billing endpoints');
}
- const [gcpS, gcpL, gcpA, gcpH, awsS, awsL] = await Promise.all([gcpSR.json(), gcpLR.json(), gcpAR.json(), gcpHR.json(), awsSR.json(), awsLR.json()]);
+ const [gcpS, gcpL, gcpA] = await Promise.all([gcpSR.json(), gcpLR.json(), gcpAR.json()]);
+
+ let gcpH = { history: [] };
+ if (gcpHR.ok) {
+ try {
+ gcpH = await gcpHR.json();
+ } catch (e) {
+ console.warn('Could not parse history JSON:', e.message);
+ }
+ } else {
+ console.warn('History endpoint returned', gcpHR.status);
+ }
currentData.gcp = { summary: gcpS.summary || [], forecast: gcpL, anomalies: gcpA.anomalies || [], history: gcpH.history || [] };
- currentData.aws = { summary: awsS.summary || [], forecast: awsL, anomalies: [], history: [] };
document.getElementById('err-banner').classList.remove('show');
dot.style.background='var(--ok)';
@@ -583,7 +590,6 @@ async function fetchAll(){
console.warn('API feil, demo-data:',err.message);
if (err.message.includes("Not logged in")) return;
currentData.gcp = { summary: DEMO_SUMMARY, forecast: DEMO_FORECAST, anomalies: DEMO_ANOMALIES, history: [] };
- currentData.aws = { summary: [], forecast: {}, anomalies: [], history: [] };
document.getElementById('err-msg').textContent='API utilgjengelig: '+err.message+' — demo-data vises.';
document.getElementById('err-banner').classList.add('show');
dot.style.background='var(--red)';
@@ -593,43 +599,8 @@ async function fetchAll(){
}
function getVisibleData() {
- if (currentProvider === 'gcp') {
- return currentData.gcp;
- }
- if (currentProvider === 'aws') {
- return currentData.aws;
- }
- if (currentProvider === 'all') {
- if (!currentData.gcp || !currentData.aws) return null;
- const combined = {
- summary: [...(currentData.gcp.summary || []), ...(currentData.aws.summary || [])]
- .reduce((acc, service) => {
- const cost = service.daily_cost ?? service.total_cost ?? service.cost ?? 0;
- const existing = acc.find(s => s.service === service.service);
- if (existing) {
- existing.total_cost = (existing.total_cost || 0) + cost;
- } else {
- acc.push({ ...service, total_cost: cost });
- }
- return acc;
- }, [])
- .sort((a, b) => {
- const costA = a.daily_cost ?? a.total_cost ?? a.cost ?? 0;
- const costB = b.daily_cost ?? b.total_cost ?? b.cost ?? 0;
- return costB - costA;
- }),
- forecast: {
- month_to_date_cost: (currentData.gcp.forecast?.month_to_date_cost || 0) + (currentData.aws.forecast?.month_to_date_cost || 0),
- daily_average_last_7_days: (currentData.gcp.forecast?.daily_average_last_7_days || 0) + (currentData.aws.forecast?.daily_average_last_7_days || 0),
- total_monthly_forecast: (currentData.gcp.forecast?.total_monthly_forecast || 0) + (currentData.aws.forecast?.total_monthly_forecast || 0),
- remaining_days_in_month: currentData.gcp.forecast?.remaining_days_in_month
- },
- anomalies: [...(currentData.gcp.anomalies || []), ...(currentData.aws.anomalies || [])],
- history: currentData.gcp.history
- };
- return combined;
- }
- return null;
+ // AWS er parkert; all visning baseres på GCP-data
+ return currentData.gcp;
}
@@ -640,7 +611,6 @@ function calculateDailyCosts(history) {
const dailyCosts = [];
const labels = [];
- let lastMtd = 0;
for (let i = 0; i < history.length; i++) {
const entry = history[i];
@@ -828,6 +798,7 @@ function exportPDF() {
window.print();
}
+
document.addEventListener('DOMContentLoaded', checkAuth);
if ('serviceWorker' in navigator) {
@@ -846,7 +817,7 @@ if ('serviceWorker' in navigator) {
border: none;
color: var(--muted);
padding: 4px 10px;
- cursor: pointer;
+ cursor: default;
border-radius: 4px;
font-size: 12px;
font-family: var(--font);