Stable Diffusion: clickable pod-status dot in the chat bar (copy of the settings indicator; click toggles warmup/shutdown)
| @@ -1461,6 +1461,7 @@ const RUNPOD_PING_MS = 60000; | |||
| 1461 | 1461 | ||
| 1462 | let runpodStatusTimer = null; | 1462 | let runpodStatusTimer = null; |
| 1463 | let runpodPingTimer = null; | 1463 | let runpodPingTimer = null; |
| 1464 | let runpodLastPhase = 'red'; | ||
| 1464 | 1465 | ||
| 1465 | function getRunpodLazyUrl() { | 1466 | function getRunpodLazyUrl() { |
| 1466 | return String(extension_settings.sd.runpod_lazy_url ?? '').trim().replace(/\/$/, ''); | 1467 | return String(extension_settings.sd.runpod_lazy_url ?? '').trim().replace(/\/$/, ''); |
| @@ -1477,8 +1478,12 @@ function renderRunpodStatus(status) { | |||
| 1477 | return; | 1478 | return; |
| 1478 | } | 1479 | } |
| 1479 | const phase = status?.state ?? 'red'; | 1480 | const phase = status?.state ?? 'red'; |
| 1480 | dot.classList.remove('sd_runpod_red', 'sd_runpod_orange', 'sd_runpod_green'); | 1481 | runpodLastPhase = phase; |
| 1481 | dot.classList.add(`sd_runpod_${['red', 'orange', 'green'].includes(phase) ? phase : 'red'}`); | 1482 | const phaseClass = `sd_runpod_${['red', 'orange', 'green'].includes(phase) ? phase : 'red'}`; |
| 1483 | for (const el of [dot, document.getElementById('sd_runpod_bar_dot')].filter(Boolean)) { | ||
| 1484 | el.classList.remove('sd_runpod_red', 'sd_runpod_orange', 'sd_runpod_green'); | ||
| 1485 | el.classList.add(phaseClass); | ||
| 1486 | } | ||
| 1482 | const openLink = document.getElementById('sd_runpod_open'); | 1487 | const openLink = document.getElementById('sd_runpod_open'); |
| 1483 | if (openLink) { | 1488 | if (openLink) { |
| 1484 | const showLink = phase === 'green' && status?.url; | 1489 | const showLink = phase === 'green' && status?.url; |
| @@ -1497,9 +1502,32 @@ function renderRunpodStatus(status) { | |||
| 1497 | } else { | 1502 | } else { |
| 1498 | text.textContent = 'off'; | 1503 | text.textContent = 'off'; |
| 1499 | } | 1504 | } |
| 1505 | const barDot = document.getElementById('sd_runpod_bar_dot'); | ||
| 1506 | if (barDot) { | ||
| 1507 | barDot.title = `RunPod pod: ${text.textContent} — click to ${phase === 'red' ? 'warm up' : 'shut down'}`; | ||
| 1508 | } | ||
| 1500 | return phase; | 1509 | return phase; |
| 1501 | } | 1510 | } |
| 1502 | 1511 | ||
| 1512 | /** Adds the clickable pod-status dot to the chat bar (next to other extension icons). */ | ||
| 1513 | function ensureRunpodBarDot() { | ||
| 1514 | if (document.getElementById('sd_runpod_bar_dot')) { | ||
| 1515 | return; | ||
| 1516 | } | ||
| 1517 | const anchor = document.getElementById('leftSendForm'); | ||
| 1518 | if (!anchor) { | ||
| 1519 | return; | ||
| 1520 | } | ||
| 1521 | const dot = document.createElement('div'); | ||
| 1522 | dot.id = 'sd_runpod_bar_dot'; | ||
| 1523 | dot.classList.add('sd_runpod_bar_dot', 'sd_runpod_red', 'interactable'); | ||
| 1524 | dot.title = 'RunPod pod'; | ||
| 1525 | dot.tabIndex = 0; | ||
| 1526 | dot.addEventListener('click', () => runpodControl(runpodLastPhase === 'red' ? 'warmup' : 'shutdown')); | ||
| 1527 | anchor.appendChild(dot); | ||
| 1528 | dot.style.display = getRunpodLazyUrl() ? '' : 'none'; | ||
| 1529 | } | ||
| 1530 | |||
| 1503 | async function pollRunpodStatus() { | 1531 | async function pollRunpodStatus() { |
| 1504 | const url = getRunpodLazyUrl(); | 1532 | const url = getRunpodLazyUrl(); |
| 1505 | if (!url) { | 1533 | if (!url) { |
| @@ -1547,6 +1575,11 @@ function runpodKeepalive() { | |||
| 1547 | function setupRunpodLoops() { | 1575 | function setupRunpodLoops() { |
| 1548 | clearTimeout(runpodStatusTimer); | 1576 | clearTimeout(runpodStatusTimer); |
| 1549 | clearInterval(runpodPingTimer); | 1577 | clearInterval(runpodPingTimer); |
| 1578 | ensureRunpodBarDot(); | ||
| 1579 | const barDot = document.getElementById('sd_runpod_bar_dot'); | ||
| 1580 | if (barDot) { | ||
| 1581 | barDot.style.display = getRunpodLazyUrl() ? '' : 'none'; | ||
| 1582 | } | ||
| 1550 | if (!getRunpodLazyUrl()) { | 1583 | if (!getRunpodLazyUrl()) { |
| 1551 | renderRunpodStatus(null); | 1584 | renderRunpodStatus(null); |
| 1552 | return; | 1585 | return; |
| @@ -127,3 +127,13 @@ | |||
| 127 | .sd_runpod_dot.sd_runpod_red { background: #d9534f; } | 127 | .sd_runpod_dot.sd_runpod_red { background: #d9534f; } |
| 128 | .sd_runpod_dot.sd_runpod_orange { background: #f0ad4e; } | 128 | .sd_runpod_dot.sd_runpod_orange { background: #f0ad4e; } |
| 129 | .sd_runpod_dot.sd_runpod_green { background: #5cb85c; } | 129 | .sd_runpod_dot.sd_runpod_green { background: #5cb85c; } |
| 130 | |||
| 131 | #sd_runpod_bar_dot { | ||
| 132 | width: 14px; | ||
| 133 | height: 14px; | ||
| 134 | border-radius: 50%; | ||
| 135 | align-self: center; | ||
| 136 | cursor: pointer; | ||
| 137 | margin: 0 4px; | ||
| 138 | flex-shrink: 0; | ||
| 139 | } | ||