File indexing completed on 2026-04-25 08:29:11
0001 {% load static %}
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 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
0009 <link rel="stylesheet" href="{% static 'css/style.css' %}">
0010 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism.min.css">
0011 <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
0012 <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-python.min.js"></script>
0013 <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-json.min.js"></script>
0014 <style>
0015 .btn.btn-dark-green {
0016 background-color: #166534; border-color: #166534; color: #fff;
0017 }
0018 .btn.btn-dark-green:hover, .btn.btn-dark-green:focus {
0019 background-color: #14532d; border-color: #14532d; color: #fff;
0020 }
0021 .btn.btn-dark-green:disabled, .btn.btn-dark-green.disabled {
0022 background-color: #6c757d; border-color: #6c757d; color: #e9ecef;
0023 }
0024 #js-error-overlay {
0025 position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
0026 z-index: 100000; max-width: 720px; width: calc(100vw - 2rem);
0027 background: #c9302c; color: #fff; padding: 1.25rem 1.5rem;
0028 border: 3px solid #7a1a18; border-radius: .5rem;
0029 box-shadow: 0 10px 30px rgba(0,0,0,.4);
0030 font-family: -apple-system, "Segoe UI", Roboto, sans-serif;
0031 display: none;
0032 }
0033 #js-error-overlay h3 { margin: 0 0 .5rem; font-size: 1.1rem; }
0034 #js-error-overlay pre {
0035 background: rgba(0,0,0,.25); color: #fff; padding: .5rem .75rem;
0036 border-radius: .25rem; margin: .5rem 0 0; font-size: .8rem;
0037 white-space: pre-wrap; word-break: break-word; max-height: 40vh; overflow: auto;
0038 }
0039 #js-error-overlay .close-btn {
0040 position: absolute; top: .5rem; right: .75rem;
0041 background: transparent; border: none; color: #fff; font-size: 1.5rem;
0042 cursor: pointer; line-height: 1;
0043 }
0044 nav {
0045 display: flex;
0046 align-items: center;
0047 gap: 1em;
0048 }
0049 .nav-spacer {
0050 flex: 1 1 auto;
0051 }
0052 .nav-auth {
0053 display: flex;
0054 gap: 1em;
0055 }
0056 /* Dropdown Button */
0057 .dropbtn {
0058 background-color: inherit;
0059 color: #ADD8E6; /* Light Blue */
0060 text-decoration: none;
0061 padding: 0;
0062 font-size: inherit;
0063 border: none;
0064 cursor: pointer;
0065 }
0066
0067 /* The container <div> - needed to position the dropdown content */
0068 .dropdown {
0069 position: relative;
0070 display: inline-block;
0071 margin-right: 1em;
0072 }
0073
0074 /* Dropdown Content (Hidden by Default) */
0075 .dropdown-content {
0076 display: none;
0077 position: absolute;
0078 background-color: #f9f9f9;
0079 min-width: 160px;
0080 box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
0081 z-index: 1;
0082 }
0083
0084 /* Links inside the dropdown */
0085 .dropdown-content a {
0086 color: black;
0087 padding: 12px 16px;
0088 text-decoration: none;
0089 display: block;
0090 }
0091
0092 /* Change color of dropdown links on hover */
0093 .dropdown-content a:hover {background-color: #f1f1f1}
0094
0095 /* Show the dropdown menu on hover */
0096 .dropdown:hover .dropdown-content {
0097 display: block;
0098 }
0099 /* Nav mode flipper */
0100 .nav-mode { display: none; }
0101 .nav-mode.active { display: contents; }
0102 #mode-label { border-right: 1px solid rgba(255,255,255,.2); padding-right: 12px; margin-right: 4px; }
0103 </style>
0104 </head>
0105 <body>
0106 <div id="js-error-overlay" role="alert">
0107 <button class="close-btn" onclick="document.getElementById('js-error-overlay').style.display='none';">×</button>
0108 <h3>JavaScript error</h3>
0109 <div id="js-error-msg"></div>
0110 <pre id="js-error-detail"></pre>
0111 </div>
0112 <script>
0113 (function() {
0114 function show(title, detail) {
0115 var box = document.getElementById('js-error-overlay');
0116 var msg = document.getElementById('js-error-msg');
0117 var det = document.getElementById('js-error-detail');
0118 if (!box || !msg || !det) return;
0119 msg.textContent = title || 'Error';
0120 det.textContent = detail || '';
0121 box.style.display = 'block';
0122 }
0123 window.addEventListener('error', function(ev) {
0124 var err = ev.error;
0125 var loc = (ev.filename || '') + (ev.lineno ? ':' + ev.lineno + ':' + (ev.colno || 0) : '');
0126 var stack = err && err.stack ? err.stack : '';
0127 show(ev.message || 'Script error', (loc ? loc + '\n\n' : '') + stack);
0128 });
0129 window.addEventListener('unhandledrejection', function(ev) {
0130 var r = ev.reason;
0131 var msg = (r && r.message) ? r.message : String(r);
0132 var stack = (r && r.stack) ? r.stack : '';
0133 show('Unhandled promise rejection: ' + msg, stack);
0134 });
0135 })();
0136 </script>
0137 <nav>
0138 <div class="dropdown" id="mode-flipper">
0139 <button class="dropbtn" id="mode-label" style="font-weight:700;"></button>
0140 <div class="dropdown-content">
0141 <a href="{% url 'monitor_app:prod_hub' %}" id="flip-production" onclick="setNavMode('production');">ePIC Production</a>
0142 <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>
0143 </div>
0144 </div>
0145
0146 {# ── Testbed mode ── #}
0147 <span class="nav-mode nav-testbed">
0148 <div class="dropdown">
0149 <button class="dropbtn">Workflows</button>
0150 <div class="dropdown-content">
0151 <a href="{% url 'monitor_app:workflows_home' %}">Views</a>
0152 <a href="{% url 'monitor_app:workflow_definitions_list' %}">Workflow definitions</a>
0153 <a href="{% url 'monitor_app:workflow_executions_list' %}">Workflow executions</a>
0154 <a href="{% url 'monitor_app:namespaces_list' %}">Namespaces</a>
0155 </div>
0156 </div>
0157 <div class="dropdown">
0158 <button class="dropbtn">Files</button>
0159 <div class="dropdown-content">
0160 <a href="{% url 'monitor_app:stf_files_list' %}">STF Files</a>
0161 <a href="{% url 'monitor_app:fastmon_files_list' %}">STF Samples</a>
0162 <a href="{% url 'monitor_app:tf_slices_list' %}">TF Slices</a>
0163 </div>
0164 </div>
0165 <a href="{% url 'monitor_app:workflow_agents_list' %}">Agents</a>
0166 <a href="{% url 'monitor_app:subscribers_list' %}">Subscribers</a>
0167 <a href="{% url 'monitor_app:workflow_messages' %}">Messages</a>
0168 <a href="{% url 'monitor_app:log_summary' %}">Logs</a>
0169 <a href="{% url 'monitor_app:database_tables_list' %}">Database</a>
0170 <a href="{% url 'monitor_app:persistent_state' %}">State</a>
0171 <div class="dropdown">
0172 <button class="dropbtn">PanDA/Rucio</button>
0173 <div class="dropdown-content">
0174 <a href="{% url 'monitor_app:panda_hub' %}">PanDA/Rucio Hub</a>
0175 <a href="{% url 'monitor_app:panda_activity' %}">Activity</a>
0176 <a href="{% url 'monitor_app:panda_jobs_list' %}">Jobs</a>
0177 <a href="{% url 'monitor_app:panda_tasks_list' %}">Tasks</a>
0178 <a href="{% url 'monitor_app:panda_errors_list' %}">Errors</a>
0179 <a href="{% url 'monitor_app:panda_diagnostics_list' %}">Diagnostics</a>
0180 <a href="{% url 'monitor_app:epic_queues_list' %}">EIC PanDA Queues</a>
0181 <a href="{% url 'monitor_app:panda_database_tables_list' %}">PanDA Database</a>
0182 <a href="{% url 'monitor_app:idds_database_tables_list' %}">iDDS Database</a>
0183 <a href="{% url 'monitor_app:rucio_endpoints_list' %}">Rucio Endpoints</a>
0184 </div>
0185 </div>
0186 </span>
0187
0188 {# ── Production mode ── #}
0189 <span class="nav-mode nav-production">
0190 <a href="{% url 'monitor_app:panda_activity' %}">Activity</a>
0191 <a href="{% url 'monitor_app:panda_jobs_list' %}">Jobs</a>
0192 <a href="{% url 'monitor_app:panda_tasks_list' %}">Tasks</a>
0193 <a href="{% url 'monitor_app:panda_errors_list' %}">Errors</a>
0194 <a href="{% url 'monitor_app:panda_diagnostics_list' %}">Diagnostics</a>
0195 <a href="{% url 'monitor_app:epic_queues_list' %}">Queues</a>
0196 <div class="dropdown">
0197 <button class="dropbtn">PCS</button>
0198 <div class="dropdown-content">
0199 <a href="{% url 'pcs:pcs_hub' %}">PCS Hub</a>
0200 <a href="{% url 'pcs:tag_compose' tag_type='p' %}">Physics Tags</a>
0201 <a href="{% url 'pcs:tag_compose' tag_type='e' %}">EvGen Tags</a>
0202 <a href="{% url 'pcs:tag_compose' tag_type='s' %}">Simu Tags</a>
0203 <a href="{% url 'pcs:tag_compose' tag_type='r' %}">Reco Tags</a>
0204 <a href="{% url 'pcs:datasets_compose' %}">Datasets</a>
0205 <a href="{% url 'pcs:prod_configs_compose' %}">Prod Configs</a>
0206 <a href="{% url 'pcs:prod_task_compose' %}?tab=tasks">Prod Tasks</a>
0207 </div>
0208 </div>
0209 </span>
0210 <span class="nav-spacer"></span>
0211 <a href="{% url 'monitor_app:about' %}">About</a>
0212 <div class="nav-auth">
0213 {% if user.is_authenticated %}
0214 {% if user.is_staff %}
0215 <a href="{% url 'admin:index' %}">Admin</a>
0216 {% endif %}
0217 <a href="{% url 'monitor_app:account' %}">Account</a>
0218 <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>
0219 {% else %}
0220 <a href="{% url 'login' %}">Login</a>
0221 {% endif %}
0222 </div>
0223 </nav>
0224 <main>
0225 {% if messages %}
0226 <div class="w-100" style="background-color: #e9ecef; border-bottom: 1px solid #dee2e6; padding: 20px;">
0227 {% for message in messages %}
0228 <div class="alert alert-{{ message.tags|default:'info' }} mb-0" role="alert" style="border: none; background-color: transparent;">
0229 {% if 'safe' in message.tags %}
0230 {{ message|safe }}
0231 {% else %}
0232 {{ message }}
0233 {% endif %}
0234 </div>
0235 {% endfor %}
0236 </div>
0237 {% endif %}
0238 {% block content %}{% endblock %}
0239 </main>
0240 <script>
0241 function setNavMode(mode) {
0242 localStorage.setItem('navMode', mode);
0243 applyNavMode(mode);
0244 }
0245 function applyNavMode(mode) {
0246 document.querySelectorAll('.nav-mode').forEach(el => el.classList.remove('active'));
0247 const target = document.querySelector('.nav-' + mode);
0248 if (target) target.classList.add('active');
0249 const label = document.getElementById('mode-label');
0250 if (label) label.textContent = mode === 'testbed' ? 'ePIC Testbed' : 'ePIC Production';
0251 const ft = document.getElementById('flip-testbed');
0252 const fp = document.getElementById('flip-production');
0253 if (ft) ft.style.fontWeight = mode === 'testbed' ? '700' : 'normal';
0254 if (fp) fp.style.fontWeight = mode === 'production' ? '700' : 'normal';
0255 }
0256 (function() {
0257 var mode = localStorage.getItem('navMode') || 'production';
0258 applyNavMode(mode);
0259 })();
0260 </script>
0261 </body>
0262 </html>