buzzbandit commited on
Commit
06bde1d
·
verified ·
1 Parent(s): 48d8ce0

add error message banner

Browse files
Files changed (1) hide show
  1. app.py +118 -1
app.py CHANGED
@@ -389,7 +389,124 @@ with gr.Blocks(title="🧳 Torn Foreign Stocks") as iface:
389
  ["tear gas in argentina", "smoke grenade in south africa", "flash grenade in switzerland"], c),
390
  inputs=[capacity_slider], outputs=[result_df, meta_box])
391
 
392
- # --- JS: convert all UTC ISO timestamps to browser's local time ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  gr.HTML("""
394
  <script>
395
  (function () {
 
389
  ["tear gas in argentina", "smoke grenade in south africa", "flash grenade in switzerland"], c),
390
  inputs=[capacity_slider], outputs=[result_df, meta_box])
391
 
392
+
393
+ # --- JS: global error banner (captures JS errors & unhandled promise rejections) ---
394
+ gr.HTML("""
395
+ <script>
396
+ (function () {
397
+ const DEDUP_MS = 10000; // suppress duplicates for 10s
398
+ const errorTimestamps = new Map();
399
+ // Inject minimal styles
400
+ const css = `
401
+ .errban-wrap{position:fixed;inset:auto 0 0 0;top:0;z-index:2147483647;pointer-events:none}
402
+ .errban{pointer-events:auto;margin:8px;border-left:4px solid #ef4444;background:#fee2e2;color:#991b1b;
403
+ box-shadow:0 6px 16px rgba(0,0,0,.15);border-radius:8px;overflow:hidden;font:14px/1.4 system-ui,-apple-system,Segoe UI,Roboto,sans-serif}
404
+ .errban-hd{display:flex;gap:8px;align-items:center;padding:10px 12px}
405
+ .errban-title{font-weight:600;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
406
+ .errban-btn{appearance:none;border:0;background:transparent;color:#7f1d1d;cursor:pointer;padding:6px 8px;border-radius:6px}
407
+ .errban-btn:hover{background:rgba(153,27,27,.1)}
408
+ .errban-body{display:none;border-top:1px dashed rgba(153,27,27,.35);padding:10px 12px;background:#ffe4e6;max-height:40vh;overflow:auto;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;white-space:pre-wrap}
409
+ @media (prefers-color-scheme: dark){
410
+ .errban{background:#2b0f12;color:#ffd7d7;border-left-color:#ff6b6b}
411
+ .errban-body{background:#361317}
412
+ .errban-btn{color:#ffd7d7}
413
+ .errban-btn:hover{background:rgba(255,215,215,.12)}
414
+ }`;
415
+ const style = document.createElement('style');
416
+ style.textContent = css;
417
+ document.head.appendChild(style);
418
+ // Root container
419
+ const root = document.createElement('div');
420
+ root.className = 'errban-wrap';
421
+ document.body.appendChild(root);
422
+ function now() { return Date.now(); }
423
+ function dedup(key) {
424
+ const t = errorTimestamps.get(key) || 0;
425
+ if (now() - t < DEDUP_MS) return true;
426
+ errorTimestamps.set(key, now());
427
+ return false;
428
+ }
429
+ function showBanner(title, details) {
430
+ const key = title + '|' + (details || '');
431
+ if (dedup(key)) return;
432
+ const el = document.createElement('div');
433
+ el.className = 'errban';
434
+ const hd = document.createElement('div');
435
+ hd.className = 'errban-hd';
436
+ const ttl = document.createElement('div');
437
+ ttl.className = 'errban-title';
438
+ ttl.textContent = title;
439
+ const copyBtn = document.createElement('button');
440
+ copyBtn.className = 'errban-btn';
441
+ copyBtn.textContent = 'Copy';
442
+ copyBtn.title = 'Copy error details';
443
+ copyBtn.onclick = async () => {
444
+ try {
445
+ await navigator.clipboard.writeText(details || title);
446
+ copyBtn.textContent = 'Copied!';
447
+ setTimeout(() => (copyBtn.textContent = 'Copy'), 1200);
448
+ } catch {}
449
+ };
450
+ const detBtn = document.createElement('button');
451
+ detBtn.className = 'errban-btn';
452
+ detBtn.textContent = 'Details';
453
+ const body = document.createElement('div');
454
+ body.className = 'errban-body';
455
+ body.textContent = (details || '').trim() || '(no additional details)';
456
+ detBtn.onclick = () => {
457
+ body.style.display = body.style.display === 'block' ? 'none' : 'block';
458
+ };
459
+ const closeBtn = document.createElement('button');
460
+ closeBtn.className = 'errban-btn';
461
+ closeBtn.textContent = 'Dismiss';
462
+ closeBtn.onclick = () => el.remove();
463
+ hd.append(ttl, copyBtn, detBtn, closeBtn);
464
+ el.appendChild(hd);
465
+ el.appendChild(body);
466
+ // Insert newest at top
467
+ root.prepend(el);
468
+ }
469
+ function formatErrorEvent(ev) {
470
+ const parts = [];
471
+ if (ev.message) parts.push(ev.message);
472
+ if (ev.filename) parts.push(`${ev.filename}${ev.lineno ? ':' + ev.lineno : ''}${ev.colno ? ':' + ev.colno : ''}`);
473
+ if (ev.error && ev.error.stack) parts.push(ev.error.stack);
474
+ return {
475
+ title: ev.message || 'Script error',
476
+ details: parts.join('\n')
477
+ };
478
+ }
479
+ function formatRejection(ev) {
480
+ const r = ev.reason;
481
+ let title = 'Unhandled promise rejection';
482
+ let details = '';
483
+ if (r && typeof r === 'object') {
484
+ title = r.message ? `${title}: ${r.message}` : title;
485
+ details = (r.stack || JSON.stringify(r, Object.getOwnPropertyNames(r))).toString();
486
+ } else {
487
+ details = String(r);
488
+ }
489
+ return { title, details };
490
+ }
491
+ // Global listeners
492
+ window.addEventListener('error', (ev) => {
493
+ const { title, details } = formatErrorEvent(ev);
494
+ showBanner(title, details);
495
+ });
496
+ window.addEventListener('unhandledrejection', (ev) => {
497
+ const { title, details } = formatRejection(ev);
498
+ showBanner(title, details);
499
+ });
500
+ // Manual reporting API
501
+ window.reportErrorBanner = function (err, context) {
502
+ const title = context ? `Error: ${context}` : (err && err.message) || 'Error';
503
+ const details = (err && err.stack) ? err.stack : String(err);
504
+ showBanner(title, details);
505
+ };
506
+ })();
507
+ </script>
508
+ """)
509
+ # --- JS: convert all UTC ISO timestamps to browser's local time ---
510
  gr.HTML("""
511
  <script>
512
  (function () {