@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,537 @@
1
+ ---
2
+ /**
3
+ * GitHubUsageCard Component
4
+ *
5
+ * Displays GitHub usage metrics including Actions minutes, storage, and GHAS.
6
+ * Data is fetched from the /api/usage/utilization endpoint's `github` field.
7
+ * This component renders a placeholder initially and is populated via JavaScript.
8
+ */
9
+ ---
10
+
11
+ <div class="github-usage-card" id="github-usage-card" role="region" aria-label="GitHub Usage">
12
+ <div class="card-header">
13
+ <span class="card-icon">
14
+ <!-- GitHub Octicon -->
15
+ <svg viewBox="0 0 16 16" width="20" height="20" fill="currentColor" aria-hidden="true">
16
+ <path
17
+ d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"
18
+ ></path>
19
+ </svg>
20
+ </span>
21
+ <span class="card-label">GitHub</span>
22
+ <span class="plan-badge" id="github-plan-badge">-</span>
23
+ </div>
24
+
25
+ <!-- Loading state -->
26
+ <div id="github-loading" class="github-loading">
27
+ <div class="loading-text">Loading GitHub data...</div>
28
+ </div>
29
+
30
+ <!-- No data state -->
31
+ <div id="github-no-data" class="github-no-data" style="display: none;">
32
+ <div class="no-data-text">No GitHub data collected yet</div>
33
+ <div class="no-data-hint">Data is collected daily at midnight UTC</div>
34
+ </div>
35
+
36
+ <!-- Data content (hidden until populated) -->
37
+ <div id="github-content" class="github-content" style="display: none;">
38
+ <!-- Stale warning -->
39
+ <div id="github-stale-warning" class="stale-warning" style="display: none;">
40
+ ⚠️ Data may be stale (>24h old)
41
+ </div>
42
+
43
+ <!-- Actions Minutes Progress -->
44
+ <div class="metric-section">
45
+ <div class="metric-header">
46
+ <span class="metric-label">Actions Minutes</span>
47
+ <span class="metric-value" id="github-actions-pct">0%</span>
48
+ </div>
49
+ <div class="progress-bar">
50
+ <div class="progress-fill" id="github-actions-progress" style="width: 0%;"></div>
51
+ </div>
52
+ <div class="metric-detail">
53
+ <span id="github-actions-used">0</span>
54
+ <span class="metric-separator">/</span>
55
+ <span id="github-actions-included">50,000</span>
56
+ <span class="metric-unit">mins</span>
57
+ </div>
58
+ </div>
59
+
60
+ <!-- Storage Usage -->
61
+ <div class="metric-section">
62
+ <div class="metric-header">
63
+ <span class="metric-label">Actions Storage</span>
64
+ </div>
65
+ <div class="metric-detail storage-detail">
66
+ <span id="github-storage-used">0</span>
67
+ <span class="metric-unit">GB-hours</span>
68
+ <span class="metric-separator">of</span>
69
+ <span id="github-storage-included">50</span>
70
+ <span class="metric-unit">GB included</span>
71
+ </div>
72
+ </div>
73
+
74
+ <!-- GHAS (if any) -->
75
+ <div id="github-ghas-section" class="metric-section ghas-section" style="display: none;">
76
+ <div class="metric-header">
77
+ <span class="metric-label">Advanced Security</span>
78
+ </div>
79
+ <div class="ghas-details">
80
+ <div class="ghas-item">
81
+ <span class="ghas-label">Code Security:</span>
82
+ <span id="github-ghas-code" class="ghas-value">0</span>
83
+ <span class="ghas-unit">seats</span>
84
+ </div>
85
+ <div class="ghas-item">
86
+ <span class="ghas-label">Secret Protection:</span>
87
+ <span id="github-ghas-secret" class="ghas-value">0</span>
88
+ <span class="ghas-unit">seats</span>
89
+ </div>
90
+ </div>
91
+ </div>
92
+
93
+ <!-- Total Cost -->
94
+ <div class="cost-section">
95
+ <div class="cost-header">
96
+ <span class="cost-label">MTD Cost</span>
97
+ <span class="cost-value" id="github-total-cost">$0.00</span>
98
+ </div>
99
+ </div>
100
+
101
+ <!-- Last Updated -->
102
+ <div class="last-updated">
103
+ <span class="last-updated-label">Last updated:</span>
104
+ <span id="github-last-updated" class="last-updated-value">-</span>
105
+ </div>
106
+ </div>
107
+ </div>
108
+
109
+ <style>
110
+ .github-usage-card {
111
+ background-color: white;
112
+ border: 1px solid #e5e7eb;
113
+ border-radius: 0.5rem;
114
+ padding: 1.25rem;
115
+ transition: all 0.15s ease;
116
+ }
117
+
118
+ .github-usage-card:hover {
119
+ border-color: #d1d5db;
120
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
121
+ }
122
+
123
+ .card-header {
124
+ display: flex;
125
+ align-items: center;
126
+ gap: 0.5rem;
127
+ margin-bottom: 1rem;
128
+ }
129
+
130
+ .card-icon {
131
+ color: #24292f;
132
+ display: flex;
133
+ align-items: center;
134
+ }
135
+
136
+ .card-label {
137
+ font-size: 0.875rem;
138
+ font-weight: 600;
139
+ color: #374151;
140
+ }
141
+
142
+ .plan-badge {
143
+ margin-left: auto;
144
+ font-size: 0.65rem;
145
+ font-weight: 500;
146
+ padding: 0.125rem 0.375rem;
147
+ border-radius: 9999px;
148
+ background-color: #dbeafe;
149
+ color: #1e40af;
150
+ text-transform: uppercase;
151
+ letter-spacing: 0.025em;
152
+ }
153
+
154
+ .github-loading,
155
+ .github-no-data {
156
+ padding: 1rem 0;
157
+ text-align: center;
158
+ }
159
+
160
+ .loading-text {
161
+ font-size: 0.875rem;
162
+ color: #6b7280;
163
+ }
164
+
165
+ .no-data-text {
166
+ font-size: 0.875rem;
167
+ color: #6b7280;
168
+ margin-bottom: 0.25rem;
169
+ }
170
+
171
+ .no-data-hint {
172
+ font-size: 0.75rem;
173
+ color: #9ca3af;
174
+ }
175
+
176
+ .stale-warning {
177
+ background-color: #fef3c7;
178
+ border: 1px solid #f59e0b;
179
+ color: #92400e;
180
+ font-size: 0.75rem;
181
+ padding: 0.375rem 0.5rem;
182
+ border-radius: 0.25rem;
183
+ margin-bottom: 0.75rem;
184
+ }
185
+
186
+ .metric-section {
187
+ margin-bottom: 1rem;
188
+ }
189
+
190
+ .metric-header {
191
+ display: flex;
192
+ justify-content: space-between;
193
+ align-items: center;
194
+ margin-bottom: 0.375rem;
195
+ }
196
+
197
+ .metric-label {
198
+ font-size: 0.75rem;
199
+ font-weight: 500;
200
+ color: #6b7280;
201
+ text-transform: uppercase;
202
+ letter-spacing: 0.025em;
203
+ }
204
+
205
+ .metric-value {
206
+ font-size: 0.875rem;
207
+ font-weight: 600;
208
+ color: #374151;
209
+ }
210
+
211
+ .progress-bar {
212
+ width: 100%;
213
+ height: 0.5rem;
214
+ background-color: #e5e7eb;
215
+ border-radius: 9999px;
216
+ overflow: hidden;
217
+ margin-bottom: 0.375rem;
218
+ }
219
+
220
+ .progress-fill {
221
+ height: 100%;
222
+ background-color: #10b981;
223
+ border-radius: 9999px;
224
+ transition: width 0.3s ease;
225
+ }
226
+
227
+ .progress-fill.warning {
228
+ background-color: #f59e0b;
229
+ }
230
+
231
+ .progress-fill.danger {
232
+ background-color: #ef4444;
233
+ }
234
+
235
+ .metric-detail {
236
+ font-size: 0.75rem;
237
+ color: #6b7280;
238
+ }
239
+
240
+ .metric-separator {
241
+ margin: 0 0.125rem;
242
+ color: #9ca3af;
243
+ }
244
+
245
+ .metric-unit {
246
+ color: #9ca3af;
247
+ margin-left: 0.125rem;
248
+ }
249
+
250
+ .storage-detail {
251
+ margin-top: 0.25rem;
252
+ }
253
+
254
+ .ghas-section {
255
+ padding-top: 0.75rem;
256
+ border-top: 1px solid #f3f4f6;
257
+ }
258
+
259
+ .ghas-details {
260
+ display: flex;
261
+ flex-direction: column;
262
+ gap: 0.25rem;
263
+ }
264
+
265
+ .ghas-item {
266
+ font-size: 0.75rem;
267
+ display: flex;
268
+ gap: 0.25rem;
269
+ align-items: center;
270
+ }
271
+
272
+ .ghas-label {
273
+ color: #6b7280;
274
+ }
275
+
276
+ .ghas-value {
277
+ font-weight: 600;
278
+ color: #374151;
279
+ }
280
+
281
+ .ghas-unit {
282
+ color: #9ca3af;
283
+ }
284
+
285
+ .cost-section {
286
+ padding-top: 0.75rem;
287
+ border-top: 1px solid #f3f4f6;
288
+ margin-top: 0.75rem;
289
+ }
290
+
291
+ .cost-header {
292
+ display: flex;
293
+ justify-content: space-between;
294
+ align-items: center;
295
+ }
296
+
297
+ .cost-label {
298
+ font-size: 0.75rem;
299
+ font-weight: 500;
300
+ color: #6b7280;
301
+ text-transform: uppercase;
302
+ letter-spacing: 0.025em;
303
+ }
304
+
305
+ .cost-value {
306
+ font-size: 1.25rem;
307
+ font-weight: 700;
308
+ color: #1f2937;
309
+ }
310
+
311
+ .last-updated {
312
+ margin-top: 0.75rem;
313
+ padding-top: 0.5rem;
314
+ border-top: 1px solid #f3f4f6;
315
+ font-size: 0.65rem;
316
+ color: #9ca3af;
317
+ }
318
+
319
+ .last-updated-label {
320
+ margin-right: 0.25rem;
321
+ }
322
+
323
+ .last-updated-value {
324
+ color: #6b7280;
325
+ }
326
+
327
+ @media (max-width: 640px) {
328
+ .github-usage-card {
329
+ padding: 1rem;
330
+ }
331
+
332
+ .cost-value {
333
+ font-size: 1rem;
334
+ }
335
+ }
336
+
337
+ /* Dark mode support */
338
+ @media (prefers-color-scheme: dark) {
339
+ .github-usage-card {
340
+ background-color: #1f2937;
341
+ border-color: #374151;
342
+ }
343
+
344
+ .github-usage-card:hover {
345
+ border-color: #4b5563;
346
+ }
347
+
348
+ .card-icon {
349
+ color: #f9fafb;
350
+ }
351
+
352
+ .card-label {
353
+ color: #e5e7eb;
354
+ }
355
+
356
+ .plan-badge {
357
+ background-color: #1e3a5f;
358
+ color: #93c5fd;
359
+ }
360
+
361
+ .loading-text,
362
+ .no-data-text,
363
+ .metric-label,
364
+ .cost-label {
365
+ color: #9ca3af;
366
+ }
367
+
368
+ .metric-value,
369
+ .cost-value {
370
+ color: #f9fafb;
371
+ }
372
+
373
+ .progress-bar {
374
+ background-color: #374151;
375
+ }
376
+
377
+ .metric-detail,
378
+ .ghas-label {
379
+ color: #9ca3af;
380
+ }
381
+
382
+ .ghas-value {
383
+ color: #e5e7eb;
384
+ }
385
+
386
+ .last-updated {
387
+ border-color: #374151;
388
+ }
389
+
390
+ .cost-section,
391
+ .ghas-section {
392
+ border-color: #374151;
393
+ }
394
+ }
395
+ </style>
396
+
397
+ <script>
398
+ /**
399
+ * Update the GitHub Usage Card with data from the utilization API.
400
+ * This function is called from the page's fetchUtilizationData.
401
+ */
402
+ interface GitHubData {
403
+ mtdUsage: {
404
+ actionsMinutes: number;
405
+ actionsMinutesIncluded: number;
406
+ actionsMinutesUsagePct: number;
407
+ actionsStorageGbHours: number;
408
+ actionsStorageGbIncluded: number;
409
+ ghecUserMonths: number;
410
+ ghasCodeSecuritySeats: number;
411
+ ghasSecretProtectionSeats: number;
412
+ totalCost: number;
413
+ };
414
+ plan: {
415
+ name: string;
416
+ filledSeats: number;
417
+ totalSeats: number;
418
+ };
419
+ lastUpdated: string | null;
420
+ isStale: boolean;
421
+ }
422
+
423
+ function formatNumber(num: number): string {
424
+ return num.toLocaleString();
425
+ }
426
+
427
+ function formatCurrency(amount: number): string {
428
+ return `$${amount.toFixed(2)}`;
429
+ }
430
+
431
+ function formatRelativeTime(isoString: string): string {
432
+ const date = new Date(isoString);
433
+ const now = new Date();
434
+ const diffMs = now.getTime() - date.getTime();
435
+ const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
436
+
437
+ if (diffHours < 1) {
438
+ return 'Just now';
439
+ } else if (diffHours < 24) {
440
+ return `${diffHours}h ago`;
441
+ } else {
442
+ const diffDays = Math.floor(diffHours / 24);
443
+ return `${diffDays}d ago`;
444
+ }
445
+ }
446
+
447
+ function updateGitHubCard(data: GitHubData | null): void {
448
+ const loadingEl = document.getElementById('github-loading');
449
+ const noDataEl = document.getElementById('github-no-data');
450
+ const contentEl = document.getElementById('github-content');
451
+
452
+ if (!data) {
453
+ // Show no data state
454
+ if (loadingEl) loadingEl.style.display = 'none';
455
+ if (noDataEl) noDataEl.style.display = 'block';
456
+ if (contentEl) contentEl.style.display = 'none';
457
+ return;
458
+ }
459
+
460
+ // Show content
461
+ if (loadingEl) loadingEl.style.display = 'none';
462
+ if (noDataEl) noDataEl.style.display = 'none';
463
+ if (contentEl) contentEl.style.display = 'block';
464
+
465
+ const { mtdUsage, plan, lastUpdated, isStale } = data;
466
+
467
+ // Update plan badge
468
+ const planBadge = document.getElementById('github-plan-badge');
469
+ if (planBadge) {
470
+ planBadge.textContent = plan.name;
471
+ }
472
+
473
+ // Stale warning
474
+ const staleWarning = document.getElementById('github-stale-warning');
475
+ if (staleWarning) {
476
+ staleWarning.style.display = isStale ? 'block' : 'none';
477
+ }
478
+
479
+ // Actions minutes
480
+ const actionsPct = document.getElementById('github-actions-pct');
481
+ const actionsProgress = document.getElementById('github-actions-progress');
482
+ const actionsUsed = document.getElementById('github-actions-used');
483
+ const actionsIncluded = document.getElementById('github-actions-included');
484
+
485
+ if (actionsPct) actionsPct.textContent = `${mtdUsage.actionsMinutesUsagePct.toFixed(1)}%`;
486
+ if (actionsProgress) {
487
+ const pct = Math.min(mtdUsage.actionsMinutesUsagePct, 100);
488
+ actionsProgress.style.width = `${pct}%`;
489
+ // Color based on usage
490
+ actionsProgress.classList.remove('warning', 'danger');
491
+ if (mtdUsage.actionsMinutesUsagePct >= 90) {
492
+ actionsProgress.classList.add('danger');
493
+ } else if (mtdUsage.actionsMinutesUsagePct >= 70) {
494
+ actionsProgress.classList.add('warning');
495
+ }
496
+ }
497
+ if (actionsUsed) actionsUsed.textContent = formatNumber(mtdUsage.actionsMinutes);
498
+ if (actionsIncluded)
499
+ actionsIncluded.textContent = formatNumber(mtdUsage.actionsMinutesIncluded);
500
+
501
+ // Storage
502
+ const storageUsed = document.getElementById('github-storage-used');
503
+ const storageIncluded = document.getElementById('github-storage-included');
504
+ if (storageUsed) storageUsed.textContent = mtdUsage.actionsStorageGbHours.toFixed(2);
505
+ if (storageIncluded) storageIncluded.textContent = String(mtdUsage.actionsStorageGbIncluded);
506
+
507
+ // GHAS (show only if there's usage)
508
+ const ghasSection = document.getElementById('github-ghas-section');
509
+ const ghasCode = document.getElementById('github-ghas-code');
510
+ const ghasSecret = document.getElementById('github-ghas-secret');
511
+
512
+ const hasGhas = mtdUsage.ghasCodeSecuritySeats > 0 || mtdUsage.ghasSecretProtectionSeats > 0;
513
+ if (ghasSection) {
514
+ ghasSection.style.display = hasGhas ? 'block' : 'none';
515
+ }
516
+ if (ghasCode) ghasCode.textContent = String(mtdUsage.ghasCodeSecuritySeats);
517
+ if (ghasSecret) ghasSecret.textContent = String(mtdUsage.ghasSecretProtectionSeats);
518
+
519
+ // Total cost
520
+ const totalCost = document.getElementById('github-total-cost');
521
+ if (totalCost) totalCost.textContent = formatCurrency(mtdUsage.totalCost);
522
+
523
+ // Last updated
524
+ const lastUpdatedEl = document.getElementById('github-last-updated');
525
+ if (lastUpdatedEl) {
526
+ lastUpdatedEl.textContent = lastUpdated ? formatRelativeTime(lastUpdated) : 'Unknown';
527
+ }
528
+ }
529
+
530
+ // Expose to global scope for the page to call
531
+ declare global {
532
+ interface Window {
533
+ updateGitHubUsageCard: typeof updateGitHubCard;
534
+ }
535
+ }
536
+ window.updateGitHubUsageCard = updateGitHubCard;
537
+ </script>