Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-06-26 08:40:26

0001 {% load static tz %}
0002 <!DOCTYPE html>
0003 <html lang="en">
0004 <head>
0005     <meta charset="UTF-8">
0006     <meta name="viewport" content="width=device-width, initial-scale=1.0">
0007     <title>{% block title %}SWF Monitor{% endblock %}</title>
0008     <script>
0009     (function() {
0010         var mode = 'production';
0011         try {
0012             mode = localStorage.getItem('navMode') || 'production';
0013         } catch (e) {}
0014         if (mode !== 'testbed') mode = 'production';
0015         document.documentElement.setAttribute('data-nav-mode', mode);
0016     })();
0017     </script>
0018     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
0019     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
0020     <link rel="stylesheet" href="{% static 'css/style.css' %}">
0021     <link rel="stylesheet" href="{% static 'css/state-colors.css' %}">
0022     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism.min.css">
0023     <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
0024     <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-python.min.js"></script>
0025     <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-json.min.js"></script>
0026     <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
0027     <style>
0028       body {
0029         margin: 0;
0030         padding: 0;
0031       }
0032       main {
0033         padding: 0.65rem 1rem 1rem;
0034         position: relative;
0035       }
0036       main > .container,
0037       main > .container-fluid {
0038         margin-top: 0 !important;
0039       }
0040       main > h1,
0041       main > h2,
0042       main > .container > h1,
0043       main > .container > h2,
0044       main > .container-fluid > h1,
0045       main > .container-fluid > h2,
0046       main > .container > div.mb-3 > h1,
0047       main > .container > div.mb-3 > h2,
0048       main > .container > div.mb-4 > div > h1,
0049       main > .container > div.mb-4 > div > h2,
0050       main > .container > .d-flex h1,
0051       main > .container > .d-flex h2,
0052       main > .container-fluid > div.mb-3 > h1,
0053       main > .container-fluid > div.mb-3 > h2,
0054       main > .container-fluid > div.mb-4 > div > h1,
0055       main > .container-fluid > div.mb-4 > div > h2,
0056       main > .container-fluid > .d-flex h1,
0057       main > .container-fluid > .d-flex h2 {
0058         font-size: 1.7rem;
0059         line-height: 1.2;
0060         margin-top: 0 !important;
0061       }
0062       main > h1,
0063       main > h2,
0064       main > .container > h1,
0065       main > .container > h2,
0066       main > .container-fluid > h1,
0067       main > .container-fluid > h2,
0068       main > .container > div.mb-3 > h1,
0069       main > .container > div.mb-3 > h2,
0070       main > .container > div.mb-4 > div > h1,
0071       main > .container > div.mb-4 > div > h2,
0072       main > .container-fluid > div.mb-3 > h1,
0073       main > .container-fluid > div.mb-3 > h2,
0074       main > .container-fluid > div.mb-4 > div > h1,
0075       main > .container-fluid > div.mb-4 > div > h2 {
0076         margin-bottom: 0.2rem !important;
0077       }
0078       main > .container > .d-flex h1,
0079       main > .container > .d-flex h2,
0080       main > .container-fluid > .d-flex h1,
0081       main > .container-fluid > .d-flex h2 {
0082         margin-bottom: 0 !important;
0083       }
0084       .btn.btn-dark-green {
0085         background-color: #166534; border-color: #166534; color: #fff;
0086       }
0087       .btn.btn-dark-green:hover, .btn.btn-dark-green:focus {
0088         background-color: #14532d; border-color: #14532d; color: #fff;
0089       }
0090       .btn.btn-dark-green:disabled, .btn.btn-dark-green.disabled {
0091         background-color: #6c757d; border-color: #6c757d; color: #e9ecef;
0092       }
0093       #js-error-overlay {
0094         position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
0095         z-index: 100000; max-width: 720px; width: calc(100vw - 2rem);
0096         background: #c9302c; color: #fff; padding: 1.25rem 1.5rem;
0097         border: 3px solid #7a1a18; border-radius: .5rem;
0098         box-shadow: 0 10px 30px rgba(0,0,0,.4);
0099         font-family: -apple-system, "Segoe UI", Roboto, sans-serif;
0100         display: none;
0101       }
0102       #js-error-overlay h3 { margin: 0 0 .5rem; font-size: 1.1rem; }
0103       #js-error-overlay pre {
0104         background: rgba(0,0,0,.25); color: #fff; padding: .5rem .75rem;
0105         border-radius: .25rem; margin: .5rem 0 0; font-size: .8rem;
0106         white-space: pre-wrap; word-break: break-word; max-height: 40vh; overflow: auto;
0107       }
0108       #js-error-overlay .close-btn {
0109         position: absolute; top: .5rem; right: .75rem;
0110         background: transparent; border: none; color: #fff; font-size: 1.5rem;
0111         cursor: pointer; line-height: 1;
0112       }
0113       nav {
0114         display: flex;
0115         align-items: center;
0116         gap: .8em;
0117       }
0118       .sticky-header {
0119         position: sticky;
0120         top: 0;
0121         z-index: 1030;
0122       }
0123       .nav-spacer {
0124         flex: 1 1 auto;
0125       }
0126       .nav-auth {
0127         display: flex;
0128         gap: .8em;
0129       }
0130       .main-time-info {
0131         color: #667085;
0132         float: right;
0133         font-size: .75rem;
0134         margin: -.25rem 0 .25rem 1rem;
0135         white-space: nowrap;
0136       }
0137       nav a {
0138         color: #ADD8E6;
0139       }
0140       nav a.nav-active {
0141         text-shadow: 0 0 .65px currentColor, 0 0 .65px currentColor;
0142       }
0143       /* Dropdown Button */
0144       .dropbtn {
0145         background-color: inherit;
0146         color: #8fc7e8;
0147         text-decoration: none;
0148         padding: 0;
0149         font-size: inherit;
0150         border: none;
0151         cursor: pointer;
0152       }
0153       .dropbtn.nav-active {
0154         text-shadow: 0 0 .65px currentColor, 0 0 .65px currentColor;
0155       }
0156 
0157       /* The container <div> - needed to position the dropdown content */
0158       .dropdown {
0159         position: relative;
0160         display: inline-block;
0161         margin-right: .35em;
0162       }
0163 
0164       /* Dropdown Content (Hidden by Default) */
0165       .dropdown-content {
0166         display: none;
0167         position: absolute;
0168         background-color: #f9f9f9;
0169         min-width: 160px;
0170         box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
0171         z-index: 1;
0172       }
0173 
0174       /* Links inside the dropdown */
0175       .dropdown-content a {
0176         color: black;
0177         padding: 12px 16px;
0178         text-decoration: none;
0179         display: block;
0180       }
0181       .dropdown-content a.nav-active {
0182         background-color: #e9ecef;
0183       }
0184 
0185       /* Change color of dropdown links on hover */
0186       .dropdown-content a:hover {background-color: #f1f1f1}
0187 
0188       /* Show the dropdown menu on hover */
0189       .dropdown:hover .dropdown-content {
0190         display: block;
0191       }
0192       /* Nav mode flipper */
0193       .nav-mode { display: none; }
0194       .nav-mode.active { display: contents; }
0195       html[data-nav-mode="production"] .nav-production,
0196       html[data-nav-mode="testbed"] .nav-testbed { display: contents; }
0197       #mode-label {
0198         border-right: 1px solid rgba(255,255,255,.2);
0199         color: #fff;
0200         padding-right: 12px;
0201         margin-right: 4px;
0202       }
0203       #mode-label .mode-title { display: none; }
0204       html[data-nav-mode="production"] #mode-label .mode-title-production,
0205       html[data-nav-mode="testbed"] #mode-label .mode-title-testbed { display: inline; }
0206       .nav-label {
0207         color: #fff;
0208         font-weight: 700;
0209       }
0210       .nav-panda-label {
0211         margin-left: 1.5em;
0212       }
0213       .nav-system-error { color: #ff8174 !important; font-weight: 700; }
0214       /* One-click copy icon for IDs — see swf_fmt.copy_btn template tag */
0215       .copy-btn {
0216         background: none; border: none; color: #6c757d; cursor: pointer;
0217         padding: 0 .25rem; font-size: .85em; line-height: 1; vertical-align: baseline;
0218       }
0219       .copy-btn:hover { color: #0d6efd; }
0220       .copy-btn.copied { color: #198754; }
0221     </style>
0222 </head>
0223 <body>
0224     <div id="js-error-overlay" role="alert">
0225         <button class="close-btn" onclick="document.getElementById('js-error-overlay').style.display='none';">&times;</button>
0226         <h3>JavaScript error</h3>
0227         <div id="js-error-msg"></div>
0228         <pre id="js-error-detail"></pre>
0229     </div>
0230     <script>
0231     (function() {
0232         function show(title, detail) {
0233             var box = document.getElementById('js-error-overlay');
0234             var msg = document.getElementById('js-error-msg');
0235             var det = document.getElementById('js-error-detail');
0236             if (!box || !msg || !det) return;
0237             msg.textContent = title || 'Error';
0238             det.textContent = detail || '';
0239             box.style.display = 'block';
0240         }
0241         window.addEventListener('error', function(ev) {
0242             var err = ev.error;
0243             var loc = (ev.filename || '') + (ev.lineno ? ':' + ev.lineno + ':' + (ev.colno || 0) : '');
0244             var stack = err && err.stack ? err.stack : '';
0245             show(ev.message || 'Script error', (loc ? loc + '\n\n' : '') + stack);
0246         });
0247         window.addEventListener('unhandledrejection', function(ev) {
0248             var r = ev.reason;
0249             var msg = (r && r.message) ? r.message : String(r);
0250             var stack = (r && r.stack) ? r.stack : '';
0251             show('Unhandled promise rejection: ' + msg, stack);
0252         });
0253     })();
0254     // One-click copy-to-clipboard handler for .copy-btn buttons rendered by
0255     // the copy_btn template tag (swf_fmt). Swaps the icon to a checkmark for
0256     // 1s on success so the user sees the click landed.
0257     document.addEventListener('click', function(ev) {
0258         var btn = ev.target.closest('.copy-btn');
0259         if (!btn) return;
0260         ev.preventDefault();
0261         var text = btn.getAttribute('data-copy') || '';
0262         if (!text || !navigator.clipboard) return;
0263         navigator.clipboard.writeText(text).then(function() {
0264             var icon = btn.querySelector('i');
0265             if (!icon) return;
0266             var prev = icon.className;
0267             icon.className = 'bi bi-clipboard-check';
0268             btn.classList.add('copied');
0269             setTimeout(function() {
0270                 icon.className = prev;
0271                 btn.classList.remove('copied');
0272             }, 1000);
0273         });
0274     });
0275     // Near-zero-latency tooltips via Bootstrap 5 for elements with title=.
0276     // Scoped to state-filled cells and the copy button so we don't spin up
0277     // a tooltip for every cell on every page. show delay 50ms, hide 0ms.
0278     document.addEventListener('DOMContentLoaded', function() {
0279         if (!window.bootstrap || !bootstrap.Tooltip) return;
0280         function init(root) {
0281             root.querySelectorAll(
0282                 'td[title]:not([data-bs-tooltip-init]), .copy-btn[title]:not([data-bs-tooltip-init])'
0283             ).forEach(function(el) {
0284                 if (!el.getAttribute('title')) return;
0285                 el.setAttribute('data-bs-tooltip-init', '1');
0286                 new bootstrap.Tooltip(el, {delay: {show: 50, hide: 0}});
0287             });
0288         }
0289         init(document);
0290         // DataTables redraws replace rows; re-init after each draw.
0291         if (window.jQuery) {
0292             jQuery(document).on('draw.dt', function(_, settings) {
0293                 init(settings.nTable || document);
0294             });
0295         }
0296     });
0297     </script>
0298     <div class="sticky-header">
0299     <nav>
0300         <div class="dropdown" id="mode-flipper">
0301             <button class="dropbtn" id="mode-label">
0302                 <span class="mode-title mode-title-production">epicprod</span>
0303                 <span class="mode-title mode-title-testbed">ePIC Testbed</span>
0304             </button>
0305             <div class="dropdown-content">
0306                 <a href="{% url 'monitor_app:prod_hub' %}" id="flip-production" onclick="setNavMode('production');">epicprod - ePIC Production</a>
0307                 <a href="{% if is_tunnel %}https://pandaserver02.sdcc.bnl.gov/swf-monitor/testbed/{% else %}{% url 'monitor_app:testbed_hub' %}{% endif %}" id="flip-testbed" onclick="setNavMode('testbed');">ePIC Testbed</a>
0308             </div>
0309         </div>
0310 
0311         {# ── Testbed mode ── #}
0312         <span class="nav-mode nav-testbed">
0313         <div class="dropdown" id="system-status-dropdown">
0314             <button class="dropbtn{% if active_nav.workflows %} nav-active{% endif %}">Workflows</button>
0315             <div class="dropdown-content">
0316                 <a href="{% url 'monitor_app:workflows_home' %}" class="{% if active_nav.workflows %}nav-active{% endif %}">Views</a>
0317                 <a href="{% url 'monitor_app:workflow_definitions_list' %}" class="{% if active_nav.workflows %}nav-active{% endif %}">Workflow definitions</a>
0318                 <a href="{% url 'monitor_app:workflow_executions_list' %}" class="{% if active_nav.workflows %}nav-active{% endif %}">Workflow executions</a>
0319                 <a href="{% url 'monitor_app:namespaces_list' %}" class="{% if active_nav.workflows %}nav-active{% endif %}">Namespaces</a>
0320             </div>
0321         </div>
0322         <div class="dropdown">
0323             <button class="dropbtn{% if active_nav.files %} nav-active{% endif %}">Files</button>
0324             <div class="dropdown-content">
0325                 <a href="{% url 'monitor_app:stf_files_list' %}" class="{% if active_nav.files %}nav-active{% endif %}">STF Files</a>
0326                 <a href="{% url 'monitor_app:fastmon_files_list' %}" class="{% if active_nav.files %}nav-active{% endif %}">STF Samples</a>
0327                 <a href="{% url 'monitor_app:tf_slices_list' %}" class="{% if active_nav.files %}nav-active{% endif %}">TF Slices</a>
0328             </div>
0329         </div>
0330         <a href="{% url 'monitor_app:workflow_agents_list' %}" class="{% if active_nav.agents %}nav-active{% endif %}">Agents</a>
0331         <a href="{% url 'monitor_app:subscribers_list' %}" class="{% if active_nav.subscribers %}nav-active{% endif %}">Subscribers</a>
0332         <a href="{% url 'monitor_app:workflow_messages' %}" class="{% if active_nav.messages %}nav-active{% endif %}">Messages</a>
0333         <a href="{% url 'monitor_app:log_summary' %}" class="{% if active_nav.logs %}nav-active{% endif %}">Logs</a>
0334         <a href="{% url 'monitor_app:database_tables_list' %}" class="{% if active_nav.database %}nav-active{% endif %}">Database</a>
0335         <a href="{% url 'monitor_app:persistent_state' %}" class="{% if active_nav.state %}nav-active{% endif %}">State</a>
0336         <div class="dropdown">
0337             <button class="dropbtn{% if active_nav.panda_rucio %} nav-active{% endif %}">PanDA/Rucio</button>
0338             <div class="dropdown-content">
0339                 <a href="{% url 'monitor_app:panda_hub' %}" class="{% if active_nav.panda_hub %}nav-active{% endif %}">PanDA/Rucio Hub</a>
0340                 <a href="{% url 'monitor_app:panda_activity' %}" class="{% if active_nav.panda_activity %}nav-active{% endif %}">Activity</a>
0341                 <a href="{% url 'monitor_app:panda_jobs_list' %}" class="{% if active_nav.panda_jobs %}nav-active{% endif %}">Jobs</a>
0342                 <a href="{% url 'monitor_app:panda_tasks_list' %}" class="{% if active_nav.panda_tasks %}nav-active{% endif %}">Tasks</a>
0343                 <a href="{% url 'monitor_app:panda_errors_list' %}" class="{% if active_nav.panda_errors %}nav-active{% endif %}">Errors</a>
0344                 <a href="{% url 'monitor_app:panda_diagnostics_list' %}" class="{% if active_nav.panda_diagnostics %}nav-active{% endif %}">Diagnostics</a>
0345                 <a href="{% url 'monitor_app:epic_queues_list' %}" class="{% if active_nav.panda_queues %}nav-active{% endif %}">EIC PanDA Queues</a>
0346                 <a href="{% url 'monitor_app:panda_database_tables_list' %}" class="{% if active_nav.panda_database %}nav-active{% endif %}">PanDA Database</a>
0347                 <a href="{% url 'monitor_app:idds_database_tables_list' %}" class="{% if active_nav.idds_database %}nav-active{% endif %}">iDDS Database</a>
0348                 <a href="{% url 'monitor_app:rucio_endpoints_list' %}" class="{% if active_nav.rucio_endpoints %}nav-active{% endif %}">Rucio Endpoints</a>
0349             </div>
0350         </div>
0351         </span>
0352 
0353         {# ── Production mode ── #}
0354         <span class="nav-mode nav-production">
0355         <a href="{% url 'pcs:questionnaires_list' %}" class="{% if active_nav.requests %}nav-active{% endif %}">Requests</a>
0356         <div class="dropdown">
0357             <button class="dropbtn{% if active_nav.pcs %} nav-active{% endif %}">PCS</button>
0358             <div class="dropdown-content">
0359                 <a href="{% url 'pcs:pcs_hub' %}" class="{% if active_nav.pcs_hub %}nav-active{% endif %}">PCS Hub</a>
0360                 <a href="{% url 'pcs:physics_categories_list' %}" class="{% if active_nav.pcs_categories %}nav-active{% endif %}">Physics Categories</a>
0361                 <a href="{% url 'pcs:tag_compose' tag_type='p' %}" class="{% if active_nav.pcs_physics_tags %}nav-active{% endif %}">Physics Tags</a>
0362                 <a href="{% url 'pcs:tag_compose' tag_type='e' %}" class="{% if active_nav.pcs_evgen_tags %}nav-active{% endif %}">EvGen Tags</a>
0363                 <a href="{% url 'pcs:tag_compose' tag_type='s' %}" class="{% if active_nav.pcs_simu_tags %}nav-active{% endif %}">Simu Tags</a>
0364                 <a href="{% url 'pcs:tag_compose' tag_type='r' %}" class="{% if active_nav.pcs_reco_tags %}nav-active{% endif %}">Reco Tags</a>
0365                 <a href="{% url 'pcs:tag_compose' tag_type='k' %}" class="{% if active_nav.pcs_background_tags %}nav-active{% endif %}">Background Tags</a>
0366                 <a href="{% url 'pcs:datasets_compose' %}" class="{% if active_nav.pcs_datasets %}nav-active{% endif %}">Datasets</a>
0367                 <a href="{% url 'pcs:prod_configs_compose' %}" class="{% if active_nav.pcs_configs %}nav-active{% endif %}">Prod Configs</a>
0368                 <a href="{% url 'pcs:prod_task_compose' %}?tab=tasks" class="{% if active_nav.pcs_tasks %}nav-active{% endif %}">Prod Tasks</a>
0369             </div>
0370         </div>
0371         <a href="{% url 'pcs:pcs_catalog' %}" class="{% if active_nav.campaigns %}nav-active{% endif %}">Campaigns</a>
0372         <strong class="nav-label nav-panda-label">PanDA</strong>
0373         <a href="{% url 'monitor_app:panda_activity' %}" class="{% if active_nav.panda_activity %}nav-active{% endif %}">Activity</a>
0374         <a href="{% url 'monitor_app:panda_tasks_list' %}" class="{% if active_nav.panda_tasks %}nav-active{% endif %}">Tasks</a>
0375         <a href="{% url 'monitor_app:panda_jobs_list' %}" class="{% if active_nav.panda_jobs %}nav-active{% endif %}">Jobs</a>
0376         <a href="{% url 'monitor_app:panda_errors_list' %}" class="{% if active_nav.panda_errors %}nav-active{% endif %}">Errors</a>
0377         <a href="{% url 'monitor_app:panda_diagnostics_list' %}" class="{% if active_nav.panda_diagnostics %}nav-active{% endif %}">Diagnostics</a>
0378         <a href="{% url 'monitor_app:epic_queues_list' %}" class="{% if active_nav.panda_queues %}nav-active{% endif %}">Queues</a>
0379         <a href="{% url 'monitor_app:alarms_dashboard' %}" class="{% if active_nav.alarms %}nav-active{% endif %}">Alarms</a>
0380         </span>
0381         <span class="nav-spacer"></span>
0382         <div class="dropdown">
0383             <button class="dropbtn{% if system_status_overall == 'error' %} nav-system-error{% endif %}{% if active_nav.system or active_nav.about %} nav-active{% endif %}"
0384                     id="system-status-nav-link"
0385                     data-system-status="{{ system_status_overall|default:'unknown' }}"
0386                     data-system-status-url="{% url 'monitor_app:system_status_json' %}"
0387                     {% if system_status_latest_checked_at %}data-system-checked-at="{{ system_status_latest_checked_at|date:'c' }}"{% endif %}
0388                     title="{{ system_status_reason|default:'' }}">System</button>
0389             <div class="dropdown-content">
0390                 <a href="{% url 'monitor_app:system_status' %}"
0391                    id="system-status-dropdown-link"
0392                    class="{% if system_status_overall == 'error' %}nav-system-error{% endif %}{% if active_nav.system %} nav-active{% endif %}">System Status</a>
0393                 {% if user.is_authenticated and user.is_staff %}
0394                     <a href="{% url 'admin:index' %}">Admin</a>
0395                 {% endif %}
0396                 <a href="{% url 'monitor_app:about' %}" class="{% if active_nav.about %}nav-active{% endif %}">About</a>
0397             </div>
0398         </div>
0399         <div class="nav-auth">
0400             {% if user.is_authenticated %}
0401                 <a href="{% url 'monitor_app:account' %}" class="{% if active_nav.account %}nav-active{% endif %}">Account</a>
0402                 <form method="post" action="{% url 'logout' %}" style="display:inline;margin:0;">{% csrf_token %}<button type="submit" style="background:none;border:none;color:inherit;cursor:pointer;padding:0;font:inherit;">Logout</button></form>
0403             {% else %}
0404                 <a href="{% url 'login' %}">Login</a>
0405             {% endif %}
0406         </div>
0407     </nav>
0408     </div>
0409     <main>
0410         {% timezone "America/New_York" %}
0411         <div class="main-time-info">Built at {% now "Ymd H:i:s" %} {% now "T" %}</div>
0412         {% endtimezone %}
0413         {% if messages %}
0414             {% for message in messages %}
0415                 <div class="alert alert-{{ message.tags|default:'info' }} alert-dismissible fade show w-100 mb-0 rounded-0" role="alert"
0416                      style="background-color: #e9ecef; border: none; border-bottom: 1px solid #dee2e6; padding: 20px;">
0417                     {% if 'safe' in message.tags %}
0418                         {{ message|safe }}
0419                     {% else %}
0420                         {{ message }}
0421                     {% endif %}
0422                     <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
0423                 </div>
0424             {% endfor %}
0425         {% endif %}
0426         {% block content %}{% endblock %}
0427     </main>
0428 <script>
0429 function setNavMode(mode) {
0430     localStorage.setItem('navMode', mode);
0431     applyNavMode(mode);
0432 }
0433 function applyNavMode(mode) {
0434     if (mode !== 'testbed') mode = 'production';
0435     document.documentElement.setAttribute('data-nav-mode', mode);
0436     const ft = document.getElementById('flip-testbed');
0437     const fp = document.getElementById('flip-production');
0438     if (ft) ft.classList.toggle('nav-active', mode === 'testbed');
0439     if (fp) fp.classList.toggle('nav-active', mode === 'production');
0440 }
0441 (function() {
0442     var mode = localStorage.getItem('navMode') || 'production';
0443     applyNavMode(mode);
0444 })();
0445 (function() {
0446     const staleAfterSeconds = 15 * 60;
0447     const dropdown = document.getElementById('system-status-dropdown');
0448     const link = document.getElementById('system-status-nav-link');
0449     if (!link) return;
0450     const dropdownLink = document.getElementById('system-status-dropdown-link');
0451     const statusUrl = link.getAttribute('data-system-status-url');
0452     function refreshSystemNav() {
0453         const status = link.getAttribute('data-system-status') || 'unknown';
0454         const checkedAt = link.getAttribute('data-system-checked-at');
0455         let stale = false;
0456         if (checkedAt) {
0457             const ts = Date.parse(checkedAt);
0458             if (!Number.isNaN(ts)) {
0459                 stale = (Date.now() - ts) / 1000 > staleAfterSeconds;
0460             }
0461         }
0462         const showError = status === 'error' || stale;
0463         link.classList.toggle('nav-system-error', showError);
0464         if (dropdownLink) dropdownLink.classList.toggle('nav-system-error', showError);
0465         if (stale) {
0466             link.title = 'System status is stale by more than 15 minutes.';
0467         }
0468     }
0469     function pollSystemStatus() {
0470         if (!statusUrl || !window.fetch) return;
0471         fetch(statusUrl, {
0472             cache: 'no-store',
0473             credentials: 'same-origin',
0474             headers: {'Accept': 'application/json'}
0475         }).then(function(resp) {
0476             if (!resp.ok) throw new Error('HTTP ' + resp.status);
0477             return resp.json();
0478         }).then(function(data) {
0479             link.setAttribute('data-system-status', data.overall_status || 'unknown');
0480             if (data.latest_checked_at) {
0481                 link.setAttribute('data-system-checked-at', data.latest_checked_at);
0482             }
0483             link.title = data.overall_reason || '';
0484             refreshSystemNav();
0485         }).catch(function() {
0486             refreshSystemNav();
0487         });
0488     }
0489     refreshSystemNav();
0490     pollSystemStatus();
0491     if (dropdown) {
0492         dropdown.addEventListener('mouseenter', pollSystemStatus);
0493         dropdown.addEventListener('focusin', pollSystemStatus);
0494     }
0495     setInterval(refreshSystemNav, 10000);
0496     setInterval(pollSystemStatus, 60000);
0497 })();
0498 </script>
0499 </body>
0500 </html>