@littlebearapps/platform-admin-sdk 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/README.md +2 -5
  2. package/dist/templates.d.ts +1 -1
  3. package/dist/templates.js +121 -3
  4. package/package.json +1 -1
  5. package/templates/full/dashboard/src/components/notifications/NotificationDropdown.tsx +130 -0
  6. package/templates/full/dashboard/src/components/notifications/NotificationItem.tsx +264 -0
  7. package/templates/full/dashboard/src/components/patterns/PatternInfoButton.tsx +60 -0
  8. package/templates/full/dashboard/src/components/reports/FeatureUsageReport.tsx +339 -0
  9. package/templates/full/dashboard/src/components/search/SearchResultGroup.tsx +46 -0
  10. package/templates/full/dashboard/src/components/search/SearchResultItem.tsx +212 -0
  11. package/templates/full/dashboard/src/pages/api/patterns/[id]/approve.ts +49 -0
  12. package/templates/full/dashboard/src/pages/api/patterns/[id]/reject.ts +50 -0
  13. package/templates/full/dashboard/src/pages/api/reports/digests/stats.ts +38 -0
  14. package/templates/full/dashboard/src/pages/api/reports/digests.ts +39 -0
  15. package/templates/full/dashboard/src/pages/api/search/reindex/[type].ts +56 -0
  16. package/templates/full/dashboard/src/pages/api/test-reports/[id].ts +102 -0
  17. package/templates/full/dashboard/src/pages/feedback.astro +365 -0
  18. package/templates/full/dashboard/src/pages/kiosk.astro +206 -0
  19. package/templates/full/dashboard/src/pages/map.astro +561 -0
  20. package/templates/full/dashboard/src/pages/revenue.astro +72 -0
  21. package/templates/full/dashboard/src/pages/tests.astro +431 -0
  22. package/templates/full/scripts/ops/audit-cost-anomaly.ts +430 -0
  23. package/templates/full/scripts/ops/verify-account-total.ts +256 -0
  24. package/templates/full/tests/integration/feedback-schema.test.ts +361 -0
  25. package/templates/full/tests/integration/r2-archive.test.ts +108 -0
  26. package/templates/shared/.github/workflows/dependabot-automerge.yml +41 -0
  27. package/templates/shared/.github/workflows/validate-controls.yml +27 -0
  28. package/templates/shared/dashboard/src/components/Breadcrumbs.astro +101 -0
  29. package/templates/shared/dashboard/src/components/EmptyState.astro +46 -0
  30. package/templates/shared/dashboard/src/components/ErrorBoundary.astro +79 -0
  31. package/templates/shared/dashboard/src/components/LoadingSkeleton.astro +105 -0
  32. package/templates/shared/dashboard/src/components/PageShell.astro +72 -0
  33. package/templates/shared/dashboard/src/components/SkipLinks.astro +22 -0
  34. package/templates/shared/dashboard/src/components/Toast.astro +170 -0
  35. package/templates/shared/dashboard/src/components/ToastContainer.astro +156 -0
  36. package/templates/shared/dashboard/src/components/costs/ProviderCostsGrid.tsx +401 -0
  37. package/templates/shared/dashboard/src/components/costs/index.ts +4 -0
  38. package/templates/shared/dashboard/src/components/overview/AlertBanner.tsx +94 -0
  39. package/templates/shared/dashboard/src/components/overview/index.ts +9 -0
  40. package/templates/shared/dashboard/src/components/resources/CostChart.tsx +170 -0
  41. package/templates/shared/dashboard/src/components/resources/ProviderCard.tsx +272 -0
  42. package/templates/shared/dashboard/src/components/resources/ProviderDetail.tsx +293 -0
  43. package/templates/shared/dashboard/src/components/settings/SettingsCard.astro +102 -0
  44. package/templates/shared/dashboard/src/components/usage/AllowanceGauge.astro +170 -0
  45. package/templates/shared/dashboard/src/components/usage/AnomalyAlerts.astro +633 -0
  46. package/templates/shared/dashboard/src/components/usage/BillingCycleCountdown.astro +192 -0
  47. package/templates/shared/dashboard/src/components/usage/BurnRateHero.astro +539 -0
  48. package/templates/shared/dashboard/src/components/usage/CircuitBreakerEventLog.astro +542 -0
  49. package/templates/shared/dashboard/src/components/usage/CircuitBreakerPanel.tsx +292 -0
  50. package/templates/shared/dashboard/src/components/usage/CircuitBreakerStatus.astro +669 -0
  51. package/templates/shared/dashboard/src/components/usage/CompactThresholdBanner.astro +531 -0
  52. package/templates/shared/dashboard/src/components/usage/ComparisonModeSelector.astro +651 -0
  53. package/templates/shared/dashboard/src/components/usage/CostBreakdownChart.astro +381 -0
  54. package/templates/shared/dashboard/src/components/usage/CostBreakdownTable.astro +210 -0
  55. package/templates/shared/dashboard/src/components/usage/CostDataTable.astro +0 -0
  56. package/templates/shared/dashboard/src/components/usage/CostDonutChart.astro +311 -0
  57. package/templates/shared/dashboard/src/components/usage/DailyCostChart.astro +632 -0
  58. package/templates/shared/dashboard/src/components/usage/ExportButton.astro +114 -0
  59. package/templates/shared/dashboard/src/components/usage/FeatureBudgetsTable.astro +872 -0
  60. package/templates/shared/dashboard/src/components/usage/FilterBar.astro +190 -0
  61. package/templates/shared/dashboard/src/components/usage/FilterToggles.astro +175 -0
  62. package/templates/shared/dashboard/src/components/usage/GitHubUsageCard.astro +537 -0
  63. package/templates/shared/dashboard/src/components/usage/OverageCostCard.astro +212 -0
  64. package/templates/shared/dashboard/src/components/usage/PlanUtilizationCard.astro +193 -0
  65. package/templates/shared/dashboard/src/components/usage/ProjectCard.astro +640 -0
  66. package/templates/shared/dashboard/src/components/usage/ProjectCardsGrid.astro +272 -0
  67. package/templates/shared/dashboard/src/components/usage/ResourceSearch.astro +279 -0
  68. package/templates/shared/dashboard/src/components/usage/ServiceUtilizationList.astro +604 -0
  69. package/templates/shared/dashboard/src/components/usage/SparklineCard.astro +399 -0
  70. package/templates/shared/dashboard/src/components/usage/StatsHero.astro +600 -0
  71. package/templates/shared/dashboard/src/components/usage/TableFilters.astro +1033 -0
  72. package/templates/shared/dashboard/src/components/usage/ThresholdAlert.astro +271 -0
  73. package/templates/shared/dashboard/src/components/usage/ThresholdSettings.astro +618 -0
  74. package/templates/shared/dashboard/src/components/usage/TopSpenderCard.astro +170 -0
  75. package/templates/shared/dashboard/src/components/usage/UnifiedResourceTable.astro +1737 -0
  76. package/templates/shared/dashboard/src/components/usage/UsageCard.astro +135 -0
  77. package/templates/shared/dashboard/src/components/usage/UsageHealthBanner.astro +387 -0
  78. package/templates/shared/dashboard/src/components/usage/UtilizationBar.astro +159 -0
  79. package/templates/shared/dashboard/src/components/usage/WorkersBreakdownTable.astro +659 -0
  80. package/templates/shared/dashboard/src/components/usage/daily/CostChart.astro +461 -0
  81. package/templates/shared/dashboard/src/components/usage/daily/CostTable.astro +946 -0
  82. package/templates/shared/dashboard/src/components/usage/daily/DailyOverview.astro +1079 -0
  83. package/templates/shared/dashboard/src/components/usage/design-tokens.ts +187 -0
  84. package/templates/shared/dashboard/src/components/usage/filters/InlineDateRange.astro +285 -0
  85. package/templates/shared/dashboard/src/components/usage/filters/PeriodButtons.astro +157 -0
  86. package/templates/shared/dashboard/src/components/usage/filters/ProjectSelect.astro +284 -0
  87. package/templates/shared/dashboard/src/components/usage/scripts/ai-tab-controller.ts +419 -0
  88. package/templates/shared/dashboard/src/components/usage/scripts/constants.ts +60 -0
  89. package/templates/shared/dashboard/src/components/usage/scripts/formatters.ts +62 -0
  90. package/templates/shared/dashboard/src/components/usage/scripts/overview-controller.ts +1633 -0
  91. package/templates/shared/dashboard/src/components/usage/scripts/resource-table-builder.ts +294 -0
  92. package/templates/shared/dashboard/src/components/usage/scripts/tabs-filters-controller.ts +464 -0
  93. package/templates/shared/dashboard/src/components/usage/state/index.ts +55 -0
  94. package/templates/shared/dashboard/src/components/usage/state/usageActions.ts +439 -0
  95. package/templates/shared/dashboard/src/components/usage/state/usageStore.ts +376 -0
  96. package/templates/shared/dashboard/src/components/usage/types.ts +283 -0
  97. package/templates/shared/dashboard/src/components/usage/usage-colors.ts +292 -0
  98. package/templates/shared/dashboard/src/pages/api/usage/ai-models.ts +235 -0
  99. package/templates/shared/dashboard/src/pages/api/usage/billing-context.ts +296 -0
  100. package/templates/shared/scripts/test-telemetry-flow.ts +464 -0
  101. package/templates/shared/tests/e2e/usage-export.test.ts +784 -0
  102. package/templates/shared/tests/e2e/usage-mobile.test.ts +531 -0
  103. package/templates/standard/dashboard/src/components/errors/PriorityBadge.astro +27 -0
  104. package/templates/standard/dashboard/src/components/infrastructure/HealthchecksStatus.tsx +293 -0
  105. package/templates/standard/dashboard/src/components/infrastructure/InfrastructureTabs.tsx +268 -0
  106. package/templates/standard/dashboard/src/pages/analytics.astro +64 -0
  107. package/templates/standard/dashboard/src/pages/api/infrastructure/alerts.ts +85 -0
  108. package/templates/standard/dashboard/src/pages/api/infrastructure/healthchecks/[id]/flips.ts +110 -0
  109. package/templates/standard/dashboard/src/pages/api/infrastructure/healthchecks.ts +101 -0
  110. package/templates/standard/dashboard/src/pages/api/infrastructure/uptime/[id]/response-times.ts +121 -0
  111. package/templates/standard/dashboard/src/pages/api/infrastructure/uptime.ts +89 -0
  112. package/templates/standard/dashboard/src/pages/api/test/service-auth.ts +178 -0
  113. package/templates/standard/tests/integration/connectors.test.ts +241 -0
  114. package/templates/standard/tests/integration/github-monitor.test.ts +143 -0
  115. package/templates/standard/tests/integration/ingestion.test.ts +211 -0
@@ -0,0 +1,539 @@
1
+ ---
2
+ /**
3
+ * BurnRateHero Component
4
+ *
5
+ * Global "Total Cloudflare Burn Rate" hero section displaying:
6
+ * - Month-to-date (MTD) total spend across all Cloudflare services
7
+ * - Projected Monthly Total based on current velocity
8
+ * - Daily burn rate average
9
+ * - Days remaining in billing period
10
+ *
11
+ * Data is populated via JavaScript after API fetch.
12
+ */
13
+ ---
14
+
15
+ <div class="burn-rate-hero" role="region" aria-label="Cloudflare burn rate summary">
16
+ <!-- Primary Stats Row -->
17
+ <div class="burn-hero-primary">
18
+ <!-- MTD Spend -->
19
+ <div class="burn-stat-block mtd-block">
20
+ <div class="burn-stat-header">
21
+ <span class="burn-stat-label">Month-to-Date Spend</span>
22
+ <span id="burn-mtd-period" class="burn-period-badge">Jan 1-12</span>
23
+ </div>
24
+ <div class="burn-stat-value-row">
25
+ <span id="burn-mtd-value" class="burn-stat-value">$0.00</span>
26
+ <div id="burn-mtd-trend" class="burn-trend" style="display: none;">
27
+ <span id="burn-mtd-arrow" class="trend-arrow"></span>
28
+ <span id="burn-mtd-pct" class="trend-pct"></span>
29
+ </div>
30
+ </div>
31
+ <div class="burn-stat-meta">
32
+ <span id="burn-mtd-vs-last" class="burn-comparison"></span>
33
+ </div>
34
+ </div>
35
+
36
+ <!-- Projected Monthly -->
37
+ <div class="burn-stat-block projected-block">
38
+ <div class="burn-stat-header">
39
+ <span class="burn-stat-label">Projected Monthly Total</span>
40
+ <span class="burn-velocity-badge">Current Velocity</span>
41
+ </div>
42
+ <div class="burn-stat-value-row">
43
+ <span id="burn-projected-value" class="burn-stat-value projected">$0.00</span>
44
+ <div id="burn-projected-confidence" class="confidence-badge" style="display: none;">
45
+ <span id="burn-confidence-label">Medium</span>
46
+ </div>
47
+ </div>
48
+ <div class="burn-stat-meta">
49
+ <span id="burn-projected-note" class="burn-note">Based on 12 days of data</span>
50
+ </div>
51
+ </div>
52
+
53
+ <!-- Daily Rate -->
54
+ <div class="burn-stat-block rate-block">
55
+ <div class="burn-stat-header">
56
+ <span class="burn-stat-label">Daily Burn Rate</span>
57
+ </div>
58
+ <div class="burn-stat-value-row">
59
+ <span id="burn-daily-value" class="burn-stat-value small">$0.00</span>
60
+ <span class="burn-daily-unit">/day</span>
61
+ </div>
62
+ <div class="burn-stat-meta">
63
+ <span id="burn-days-remaining" class="burn-note">19 days remaining</span>
64
+ </div>
65
+ </div>
66
+
67
+ <!-- Quick Status -->
68
+ <div class="burn-stat-block status-block">
69
+ <div class="burn-status-indicator">
70
+ <div id="burn-status-dot" class="status-dot status-green" aria-label="Budget status"></div>
71
+ <div class="status-text">
72
+ <span id="burn-status-label" class="status-label">On Track</span>
73
+ <span id="burn-status-detail" class="status-detail">Under budget</span>
74
+ </div>
75
+ </div>
76
+ </div>
77
+ </div>
78
+
79
+ <!-- Secondary Info Row -->
80
+ <div class="burn-hero-secondary">
81
+ <div class="burn-info-item">
82
+ <span class="info-icon">&#x1F4C5;</span>
83
+ <span id="burn-billing-period" class="info-text">Billing: Jan 1 - Jan 31</span>
84
+ </div>
85
+ <div class="burn-info-item">
86
+ <span class="info-icon">&#x23F0;</span>
87
+ <span id="burn-last-updated" class="info-text">Updated: --</span>
88
+ </div>
89
+ <div class="burn-info-item">
90
+ <span class="info-icon">&#x1F4BE;</span>
91
+ <span id="burn-data-source" class="info-text">Source: D1 Warehouse</span>
92
+ </div>
93
+ </div>
94
+ </div>
95
+
96
+ <style>
97
+ .burn-rate-hero {
98
+ background: linear-gradient(
99
+ 135deg,
100
+ var(--usage-bg-secondary) 0%,
101
+ var(--usage-bg-tertiary) 100%
102
+ );
103
+ border: 2px solid var(--usage-accent-blue);
104
+ border-radius: var(--usage-radius-xl);
105
+ padding: 1.5rem 2rem;
106
+ margin-bottom: 1.5rem;
107
+ position: relative;
108
+ overflow: hidden;
109
+ }
110
+
111
+ .burn-rate-hero::before {
112
+ content: '';
113
+ position: absolute;
114
+ top: 0;
115
+ left: 0;
116
+ right: 0;
117
+ height: 4px;
118
+ background: linear-gradient(
119
+ 90deg,
120
+ var(--usage-accent-blue),
121
+ var(--usage-accent-purple),
122
+ var(--usage-accent-blue)
123
+ );
124
+ background-size: 200% 100%;
125
+ animation: shimmer 3s ease-in-out infinite;
126
+ }
127
+
128
+ @keyframes shimmer {
129
+ 0%,
130
+ 100% {
131
+ background-position: 0% 50%;
132
+ }
133
+ 50% {
134
+ background-position: 100% 50%;
135
+ }
136
+ }
137
+
138
+ .burn-hero-primary {
139
+ display: grid;
140
+ grid-template-columns: 1.5fr 1.5fr 1fr auto;
141
+ gap: 2rem;
142
+ align-items: center;
143
+ }
144
+
145
+ .burn-stat-block {
146
+ display: flex;
147
+ flex-direction: column;
148
+ gap: 0.5rem;
149
+ }
150
+
151
+ .burn-stat-header {
152
+ display: flex;
153
+ align-items: center;
154
+ gap: 0.5rem;
155
+ flex-wrap: wrap;
156
+ }
157
+
158
+ .burn-stat-label {
159
+ font-size: 0.75rem;
160
+ font-weight: 600;
161
+ text-transform: uppercase;
162
+ letter-spacing: 0.05em;
163
+ color: var(--usage-text-secondary);
164
+ }
165
+
166
+ .burn-period-badge,
167
+ .burn-velocity-badge {
168
+ font-size: 0.625rem;
169
+ font-weight: 600;
170
+ text-transform: uppercase;
171
+ padding: 0.125rem 0.375rem;
172
+ border-radius: var(--usage-radius-sm);
173
+ }
174
+
175
+ .burn-period-badge {
176
+ background: var(--usage-accent-blue);
177
+ color: white;
178
+ }
179
+
180
+ .burn-velocity-badge {
181
+ background: var(--usage-accent-purple);
182
+ color: white;
183
+ }
184
+
185
+ .burn-stat-value-row {
186
+ display: flex;
187
+ align-items: baseline;
188
+ gap: 0.5rem;
189
+ }
190
+
191
+ .burn-stat-value {
192
+ font-family: var(--usage-font-mono);
193
+ font-size: 2.25rem;
194
+ font-weight: 700;
195
+ color: var(--usage-text-primary);
196
+ line-height: 1;
197
+ }
198
+
199
+ .burn-stat-value.projected {
200
+ color: var(--usage-accent-purple);
201
+ }
202
+
203
+ .burn-stat-value.small {
204
+ font-size: 1.5rem;
205
+ }
206
+
207
+ .burn-daily-unit {
208
+ font-size: 0.875rem;
209
+ color: var(--usage-text-secondary);
210
+ font-weight: 500;
211
+ }
212
+
213
+ .burn-trend {
214
+ display: flex;
215
+ align-items: center;
216
+ gap: 0.25rem;
217
+ padding: 0.25rem 0.5rem;
218
+ border-radius: var(--usage-radius-md);
219
+ font-size: 0.875rem;
220
+ font-weight: 600;
221
+ }
222
+
223
+ .burn-trend.up {
224
+ background: var(--usage-status-critical-bg);
225
+ color: var(--usage-status-critical);
226
+ }
227
+
228
+ .burn-trend.down {
229
+ background: var(--usage-status-ok-bg);
230
+ color: var(--usage-status-ok);
231
+ }
232
+
233
+ .burn-trend.stable {
234
+ background: var(--usage-bg-tertiary);
235
+ color: var(--usage-text-secondary);
236
+ }
237
+
238
+ .trend-arrow {
239
+ font-size: 0.875rem;
240
+ }
241
+
242
+ .confidence-badge {
243
+ font-size: 0.625rem;
244
+ font-weight: 600;
245
+ text-transform: uppercase;
246
+ padding: 0.125rem 0.375rem;
247
+ border-radius: var(--usage-radius-sm);
248
+ background: var(--usage-bg-tertiary);
249
+ color: var(--usage-text-secondary);
250
+ }
251
+
252
+ .confidence-badge.high {
253
+ background: var(--usage-status-ok-bg);
254
+ color: var(--usage-status-ok);
255
+ }
256
+
257
+ .confidence-badge.medium {
258
+ background: var(--usage-status-warning-bg);
259
+ color: var(--usage-status-warning);
260
+ }
261
+
262
+ .confidence-badge.low {
263
+ background: var(--usage-status-critical-bg);
264
+ color: var(--usage-status-critical);
265
+ }
266
+
267
+ .burn-stat-meta {
268
+ min-height: 1rem;
269
+ }
270
+
271
+ .burn-comparison {
272
+ font-size: 0.75rem;
273
+ color: var(--usage-text-secondary);
274
+ }
275
+
276
+ .burn-note {
277
+ font-size: 0.6875rem;
278
+ color: var(--usage-text-muted);
279
+ }
280
+
281
+ /* Status Block */
282
+ .status-block {
283
+ display: flex;
284
+ align-items: center;
285
+ justify-content: center;
286
+ }
287
+
288
+ .burn-status-indicator {
289
+ display: flex;
290
+ align-items: center;
291
+ gap: 0.75rem;
292
+ padding: 1rem 1.25rem;
293
+ background: var(--usage-bg-primary);
294
+ border: 1px solid var(--usage-border-default);
295
+ border-radius: var(--usage-radius-lg);
296
+ }
297
+
298
+ .status-dot {
299
+ width: 16px;
300
+ height: 16px;
301
+ border-radius: 50%;
302
+ flex-shrink: 0;
303
+ }
304
+
305
+ .status-dot.status-green {
306
+ background: var(--usage-status-ok);
307
+ box-shadow: 0 0 12px var(--usage-status-ok);
308
+ }
309
+
310
+ .status-dot.status-yellow {
311
+ background: var(--usage-status-warning);
312
+ box-shadow: 0 0 12px var(--usage-status-warning);
313
+ }
314
+
315
+ .status-dot.status-red {
316
+ background: var(--usage-status-critical);
317
+ box-shadow: 0 0 12px var(--usage-status-critical);
318
+ }
319
+
320
+ .status-text {
321
+ display: flex;
322
+ flex-direction: column;
323
+ gap: 0.125rem;
324
+ }
325
+
326
+ .status-label {
327
+ font-size: 0.875rem;
328
+ font-weight: 600;
329
+ color: var(--usage-text-primary);
330
+ }
331
+
332
+ .status-detail {
333
+ font-size: 0.6875rem;
334
+ color: var(--usage-text-muted);
335
+ }
336
+
337
+ /* Secondary Info Row */
338
+ .burn-hero-secondary {
339
+ display: flex;
340
+ gap: 1.5rem;
341
+ margin-top: 1rem;
342
+ padding-top: 1rem;
343
+ border-top: 1px solid var(--usage-border-subtle);
344
+ }
345
+
346
+ .burn-info-item {
347
+ display: flex;
348
+ align-items: center;
349
+ gap: 0.375rem;
350
+ }
351
+
352
+ .info-icon {
353
+ font-size: 0.875rem;
354
+ }
355
+
356
+ .info-text {
357
+ font-size: 0.6875rem;
358
+ color: var(--usage-text-muted);
359
+ }
360
+
361
+ /* Responsive */
362
+ @media (max-width: 1024px) {
363
+ .burn-hero-primary {
364
+ grid-template-columns: 1fr 1fr;
365
+ gap: 1.5rem;
366
+ }
367
+
368
+ .status-block {
369
+ grid-column: span 2;
370
+ justify-content: flex-start;
371
+ }
372
+ }
373
+
374
+ @media (max-width: 640px) {
375
+ .burn-rate-hero {
376
+ padding: 1rem;
377
+ }
378
+
379
+ .burn-hero-primary {
380
+ grid-template-columns: 1fr;
381
+ gap: 1rem;
382
+ }
383
+
384
+ .burn-stat-value {
385
+ font-size: 1.75rem;
386
+ }
387
+
388
+ .burn-stat-value.small {
389
+ font-size: 1.25rem;
390
+ }
391
+
392
+ .status-block {
393
+ grid-column: span 1;
394
+ }
395
+
396
+ .burn-hero-secondary {
397
+ flex-wrap: wrap;
398
+ gap: 0.75rem;
399
+ }
400
+ }
401
+ </style>
402
+
403
+ <script>
404
+ /**
405
+ * BurnRateHero JavaScript
406
+ *
407
+ * Updates the burn rate display from API data.
408
+ */
409
+
410
+ interface BurnRateData {
411
+ mtdCost: number;
412
+ mtdStartDate: string;
413
+ mtdEndDate: string;
414
+ projectedMonthlyCost: number;
415
+ dailyBurnRate: number;
416
+ daysIntoMonth: number;
417
+ daysRemaining: number;
418
+ confidence: 'low' | 'medium' | 'high';
419
+ vsLastMonthPct: number | null;
420
+ billingPeriodStart: string;
421
+ billingPeriodEnd: string;
422
+ status: 'green' | 'yellow' | 'red';
423
+ statusLabel: string;
424
+ statusDetail: string;
425
+ dataSource: 'D1 Warehouse' | 'Live API' | 'Cached';
426
+ lastUpdated: string;
427
+ }
428
+
429
+ // Update burn rate hero from API data
430
+ window.updateBurnRateHero = function (data: BurnRateData) {
431
+ // MTD Value
432
+ const mtdValueEl = document.getElementById('burn-mtd-value');
433
+ if (mtdValueEl) {
434
+ mtdValueEl.textContent = `$${data.mtdCost.toFixed(2)}`;
435
+ }
436
+
437
+ // MTD Period badge
438
+ const mtdPeriodEl = document.getElementById('burn-mtd-period');
439
+ if (mtdPeriodEl) {
440
+ const start = new Date(data.mtdStartDate);
441
+ const end = new Date(data.mtdEndDate);
442
+ mtdPeriodEl.textContent = `${start.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}-${end.getDate()}`;
443
+ }
444
+
445
+ // MTD vs Last Month
446
+ const mtdVsLastEl = document.getElementById('burn-mtd-vs-last');
447
+ const mtdTrendEl = document.getElementById('burn-mtd-trend');
448
+ const mtdArrowEl = document.getElementById('burn-mtd-arrow');
449
+ const mtdPctEl = document.getElementById('burn-mtd-pct');
450
+
451
+ if (data.vsLastMonthPct !== null && mtdVsLastEl && mtdTrendEl && mtdArrowEl && mtdPctEl) {
452
+ mtdTrendEl.style.display = 'flex';
453
+ const isUp = data.vsLastMonthPct > 0;
454
+ mtdTrendEl.className =
455
+ 'burn-trend ' + (isUp ? 'up' : data.vsLastMonthPct < 0 ? 'down' : 'stable');
456
+ mtdArrowEl.textContent = isUp ? '↑' : data.vsLastMonthPct < 0 ? '↓' : '→';
457
+ // Cap extreme percentages at 999%
458
+ const absPct = Math.abs(data.vsLastMonthPct);
459
+ mtdPctEl.textContent = absPct > 999 ? '>999%' : `${absPct.toFixed(1)}%`;
460
+ mtdVsLastEl.textContent = `vs last month (same period)`;
461
+ }
462
+
463
+ // Projected Monthly
464
+ const projectedValueEl = document.getElementById('burn-projected-value');
465
+ if (projectedValueEl) {
466
+ projectedValueEl.textContent = `$${data.projectedMonthlyCost.toFixed(2)}`;
467
+ }
468
+
469
+ // Confidence badge
470
+ const confidenceEl = document.getElementById('burn-projected-confidence');
471
+ const confidenceLabelEl = document.getElementById('burn-confidence-label');
472
+ if (confidenceEl && confidenceLabelEl) {
473
+ confidenceEl.style.display = 'inline-flex';
474
+ confidenceEl.className = 'confidence-badge ' + data.confidence;
475
+ confidenceLabelEl.textContent =
476
+ data.confidence.charAt(0).toUpperCase() + data.confidence.slice(1);
477
+ }
478
+
479
+ // Projected note
480
+ const projectedNoteEl = document.getElementById('burn-projected-note');
481
+ if (projectedNoteEl) {
482
+ projectedNoteEl.textContent = `Based on ${data.daysIntoMonth} days of data`;
483
+ }
484
+
485
+ // Daily burn rate
486
+ const dailyValueEl = document.getElementById('burn-daily-value');
487
+ if (dailyValueEl) {
488
+ dailyValueEl.textContent = `$${data.dailyBurnRate.toFixed(2)}`;
489
+ }
490
+
491
+ // Days remaining
492
+ const daysRemainingEl = document.getElementById('burn-days-remaining');
493
+ if (daysRemainingEl) {
494
+ daysRemainingEl.textContent = `${data.daysRemaining} days remaining`;
495
+ }
496
+
497
+ // Status indicator
498
+ const statusDotEl = document.getElementById('burn-status-dot');
499
+ const statusLabelEl = document.getElementById('burn-status-label');
500
+ const statusDetailEl = document.getElementById('burn-status-detail');
501
+
502
+ if (statusDotEl) {
503
+ statusDotEl.className = 'status-dot status-' + data.status;
504
+ }
505
+ if (statusLabelEl) {
506
+ statusLabelEl.textContent = data.statusLabel;
507
+ }
508
+ if (statusDetailEl) {
509
+ statusDetailEl.textContent = data.statusDetail;
510
+ }
511
+
512
+ // Billing period
513
+ const billingPeriodEl = document.getElementById('burn-billing-period');
514
+ if (billingPeriodEl) {
515
+ const start = new Date(data.billingPeriodStart);
516
+ const end = new Date(data.billingPeriodEnd);
517
+ billingPeriodEl.textContent = `Billing: ${start.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} - ${end.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}`;
518
+ }
519
+
520
+ // Last updated
521
+ const lastUpdatedEl = document.getElementById('burn-last-updated');
522
+ if (lastUpdatedEl) {
523
+ lastUpdatedEl.textContent = `Updated: ${data.lastUpdated}`;
524
+ }
525
+
526
+ // Data source
527
+ const dataSourceEl = document.getElementById('burn-data-source');
528
+ if (dataSourceEl) {
529
+ dataSourceEl.textContent = `Source: ${data.dataSource}`;
530
+ }
531
+ };
532
+
533
+ // Type declaration for global window
534
+ declare global {
535
+ interface Window {
536
+ updateBurnRateHero: (data: BurnRateData) => void;
537
+ }
538
+ }
539
+ </script>