personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

support: interactive diagnostics UI in help & guidance tab

Replace the static CLI-only diagnostics card with an interactive
button that calls GET /app/support/api/diagnostics and renders
results inline using progressive disclosure (details/summary).

+181 -1
+181 -1
apps/support/workspace.html
··· 275 275 font-size: 0.9rem; 276 276 } 277 277 .support-announcements h4 { margin: 0 0 0.25rem 0; font-size: 0.9rem; } 278 + 279 + /* Diagnostics */ 280 + .support-diagnostics-desc { 281 + margin: 0 0 0.75rem 0; 282 + font-size: 0.9rem; 283 + color: var(--muted, #595959); 284 + } 285 + .support-diagnostics-loading { 286 + display: none; 287 + font-size: 0.85rem; 288 + color: var(--muted, #595959); 289 + margin-top: 0.75rem; 290 + animation: support-diagnostics-pulse 1.5s ease-in-out infinite; 291 + } 292 + @keyframes support-diagnostics-pulse { 293 + 0%, 100% { opacity: 1; } 294 + 50% { opacity: 0.4; } 295 + } 296 + .support-diagnostics-results { 297 + display: none; 298 + margin-top: 0.75rem; 299 + } 300 + .support-diagnostics-summary { 301 + font-size: 0.9rem; 302 + font-weight: 500; 303 + margin-bottom: 0.75rem; 304 + } 305 + .support-diagnostics-section { 306 + border: 1px solid var(--border, #e0e0e0); 307 + border-radius: 6px; 308 + margin-bottom: 0.5rem; 309 + } 310 + .support-diagnostics-section summary { 311 + padding: 0.5rem 0.75rem; 312 + cursor: pointer; 313 + font-size: 0.85rem; 314 + font-weight: 500; 315 + } 316 + .support-diagnostics-section .support-diagnostics-body { 317 + padding: 0.25rem 0.75rem 0.5rem; 318 + font-size: 0.85rem; 319 + } 320 + .support-diagnostics-row { 321 + display: flex; 322 + justify-content: space-between; 323 + padding: 0.2rem 0; 324 + gap: 1rem; 325 + } 326 + .support-diagnostics-row .support-diagnostics-label { 327 + color: var(--muted, #595959); 328 + } 329 + .support-diagnostics-dot { 330 + display: inline-block; 331 + width: 8px; 332 + height: 8px; 333 + border-radius: 50%; 334 + margin-right: 0.35rem; 335 + vertical-align: middle; 336 + } 337 + .support-diagnostics-dot.support-diagnostics-running { background: #2e7d32; } 338 + .support-diagnostics-dot.support-diagnostics-stopped { background: #c62828; } 339 + .support-diagnostics-dot.support-diagnostics-unknown { background: #9e9e9e; } 340 + .support-diagnostics-error { 341 + display: none; 342 + font-size: 0.85rem; 343 + color: #c62828; 344 + margin-top: 0.75rem; 345 + } 278 346 </style> 279 347 280 348 <div class="workspace-content" id="support-root"> ··· 330 398 </div> 331 399 <div class="support-help-card"> 332 400 <h3>🩺 run diagnostics</h3> 333 - <p>Run <code>sol call support diagnose</code> to check your system health locally — no data is sent anywhere.</p> 401 + <p class="support-diagnostics-desc">Check your system health locally — no data is sent anywhere.</p> 402 + <button class="support-btn" id="diagnostics-btn" onclick="window._supportRunDiagnostics()">run diagnostics</button> 403 + <div class="support-diagnostics-loading" id="diagnostics-loading">running diagnostics…</div> 404 + <div class="support-diagnostics-error" id="diagnostics-error"></div> 405 + <div class="support-diagnostics-results" id="diagnostics-results"></div> 334 406 </div> 335 407 <div class="support-help-card"> 336 408 <h3>📢 announcements</h3> ··· 806 878 if (s < 86400) return Math.floor(s / 3600) + 'h ago'; 807 879 return Math.floor(s / 86400) + 'd ago'; 808 880 } 881 + 882 + // Diagnostics 883 + function runDiagnostics() { 884 + const btn = document.getElementById('diagnostics-btn'); 885 + const loading = document.getElementById('diagnostics-loading'); 886 + const results = document.getElementById('diagnostics-results'); 887 + const errorEl = document.getElementById('diagnostics-error'); 888 + 889 + btn.disabled = true; 890 + results.style.display = 'none'; 891 + results.innerHTML = ''; 892 + errorEl.style.display = 'none'; 893 + errorEl.innerHTML = ''; 894 + loading.style.display = ''; 895 + 896 + fetch('/app/support/api/diagnostics') 897 + .then(function(r) { 898 + if (!r.ok) throw new Error('HTTP ' + r.status); 899 + return r.json(); 900 + }) 901 + .then(function(data) { 902 + loading.style.display = 'none'; 903 + renderDiagnostics(data, results); 904 + results.style.display = ''; 905 + btn.disabled = false; 906 + }) 907 + .catch(function(err) { 908 + loading.style.display = 'none'; 909 + errorEl.innerHTML = esc('Could not run diagnostics: ' + err.message) + 910 + '<br><span style="color:var(--muted,#595959);">Try the CLI instead: <code>sol call support diagnose</code></span>'; 911 + errorEl.style.display = ''; 912 + btn.disabled = false; 913 + }); 914 + } 915 + 916 + function renderDiagnostics(data, container) { 917 + var html = ''; 918 + 919 + // Summary line 920 + var services = data.services || {}; 921 + var serviceNames = Object.keys(services); 922 + var runningCount = serviceNames.filter(function(k) { return services[k] === 'running'; }).length; 923 + var errorCount = (data.recent_errors || []).length; 924 + html += '<div class="support-diagnostics-summary">' + 925 + esc(runningCount + ' of ' + serviceNames.length + ' services running') + 926 + (errorCount > 0 ? ', ' + esc(errorCount + ' recent error' + (errorCount !== 1 ? 's' : '')) : ', no recent errors') + 927 + '</div>'; 928 + 929 + // Version + Platform section 930 + var versionPlatformRows = ''; 931 + if (data.version) { 932 + versionPlatformRows += '<div class="support-diagnostics-row"><span class="support-diagnostics-label">version</span><span>' + esc(String(data.version)) + '</span></div>'; 933 + } 934 + if (data.platform) { 935 + var p = data.platform; 936 + if (p.system) versionPlatformRows += '<div class="support-diagnostics-row"><span class="support-diagnostics-label">system</span><span>' + esc(String(p.system)) + ' ' + esc(String(p.release || '')) + '</span></div>'; 937 + if (p.machine) versionPlatformRows += '<div class="support-diagnostics-row"><span class="support-diagnostics-label">machine</span><span>' + esc(String(p.machine)) + '</span></div>'; 938 + if (p.python) versionPlatformRows += '<div class="support-diagnostics-row"><span class="support-diagnostics-label">python</span><span>' + esc(String(p.python)) + '</span></div>'; 939 + } 940 + if (versionPlatformRows) { 941 + html += '<details class="support-diagnostics-section"><summary>version &amp; platform</summary>' + 942 + '<div class="support-diagnostics-body">' + versionPlatformRows + '</div></details>'; 943 + } 944 + 945 + // Services section 946 + if (serviceNames.length > 0) { 947 + var svcRows = ''; 948 + serviceNames.forEach(function(name) { 949 + var status = services[name] || 'unknown'; 950 + var dotClass = status === 'running' ? 'support-diagnostics-running' : status === 'stopped' ? 'support-diagnostics-stopped' : 'support-diagnostics-unknown'; 951 + svcRows += '<div class="support-diagnostics-row"><span class="support-diagnostics-label">' + esc(String(name)) + '</span>' + 952 + '<span><span class="support-diagnostics-dot ' + dotClass + '"></span>' + esc(String(status)) + '</span></div>'; 953 + }); 954 + html += '<details class="support-diagnostics-section"><summary>services</summary>' + 955 + '<div class="support-diagnostics-body">' + svcRows + '</div></details>'; 956 + } 957 + 958 + // Recent errors section 959 + if (data.recent_errors && data.recent_errors.length > 0) { 960 + var errRows = ''; 961 + data.recent_errors.forEach(function(e) { 962 + errRows += '<div style="padding:0.2rem 0;"><strong>' + esc(String(e.service || 'unknown')) + '</strong>: ' + 963 + esc(String(e.message || '')) + '</div>'; 964 + }); 965 + html += '<details class="support-diagnostics-section" open><summary>recent errors (' + esc(String(data.recent_errors.length)) + ')</summary>' + 966 + '<div class="support-diagnostics-body">' + errRows + '</div></details>'; 967 + } 968 + 969 + // Config section 970 + if (data.config && Object.keys(data.config).length > 0) { 971 + var cfgRows = ''; 972 + Object.keys(data.config).forEach(function(key) { 973 + cfgRows += '<div class="support-diagnostics-row"><span class="support-diagnostics-label">' + esc(String(key)) + '</span>' + 974 + '<span>' + esc(String(data.config[key])) + '</span></div>'; 975 + }); 976 + html += '<details class="support-diagnostics-section"><summary>config</summary>' + 977 + '<div class="support-diagnostics-body">' + cfgRows + '</div></details>'; 978 + } 979 + 980 + // If nothing rendered beyond summary 981 + if (!versionPlatformRows && serviceNames.length === 0 && (!data.recent_errors || data.recent_errors.length === 0) && (!data.config || Object.keys(data.config).length === 0)) { 982 + html += '<div style="font-size:0.85rem;color:var(--muted,#595959);">No diagnostic data available.</div>'; 983 + } 984 + 985 + container.innerHTML = html; 986 + } 987 + 988 + window._supportRunDiagnostics = runDiagnostics; 809 989 810 990 // Init 811 991 loadTickets();