diff --git a/codec_dashboard.html b/codec_dashboard.html index b5bf9c9..f254347 100644 --- a/codec_dashboard.html +++ b/codec_dashboard.html @@ -744,6 +744,18 @@

MENU

.mcp-auth{display:inline-flex;align-items:center;gap:5px;font-size:11px;color:#d99a33;margin-top:5px} .mcp-auth svg{width:12px;height:12px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round} .mcp-empty{font-size:12.5px;color:var(--text-muted);line-height:1.6;padding:22px 18px;text-align:center;border:1px dashed var(--border);border-radius:10px} + /* Connector state row: sits on its own line under the url so the button + never crowds the auth note (the old inline-styled button did). */ + .mcp-state{display:flex;align-items:center;gap:10px;margin-top:8px;flex-wrap:wrap} + .mcp-btn{font:inherit;font-size:12px;font-weight:600;padding:5px 14px;border-radius:6px; + border:1px solid var(--border);background:var(--surface-3);color:var(--text);cursor:pointer; + transition:border-color .12s,background .12s} + .mcp-btn:hover:not(:disabled){border-color:var(--border-hover)} + .mcp-btn:disabled{opacity:.55;cursor:default} + .mcp-btn-primary{background:var(--accent);border-color:var(--accent);color:#fff} + .mcp-btn-primary:hover:not(:disabled){filter:brightness(1.08)} + .mcp-connected{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;font-weight:600;color:#3fa45b} + .mcp-connected .dot{width:7px;height:7px;border-radius:50%;background:currentColor;flex:none} .mcp-switch{position:relative;display:inline-block;width:44px;height:24px;flex-shrink:0} .mcp-switch input{opacity:0;width:0;height:0} .mcp-slider{position:absolute;cursor:pointer;inset:0;background:var(--surface-3);border:1px solid var(--border);border-radius:24px;transition:.2s} @@ -1078,23 +1090,38 @@

MENU

box.innerHTML = servers.map(function(s) { var checked = s.enabled ? 'checked' : ''; var badge = escHtml((s.transport || 'http').toUpperCase()); - var authNote = ''; - if (s.needs_auth) { - var kind = s.auth === 'api_key' ? 'API key' : (s.auth === 'oauth' ? 'OAuth sign-in' : 'sign-in'); - authNote = '
Needs ' + kind + '
'; - } var note = s.note ? '
' + escHtml(s.note) + '
' : ''; - // OAuth connectors get a "Sign in" button (only when enabled) that opens - // the browser authorize flow — toggling on alone doesn't authenticate. - var signinBtn = (s.enabled && s.needs_auth && s.auth === 'oauth') ? - '' : ''; + var lock = ''; + var nm = escHtml(s.name); + // State machine, in the order a user actually experiences it: + // off → nothing (just the toggle) + // on + needs auth + !conn → why + how to fix it (Sign in) + // on + connected → Connected + a way back out (Disconnect) + // on + no auth needed → Connected (nothing to sign into) + var state = ''; + if (s.enabled && s.needs_auth && !s.connected) { + var kind = s.auth === 'api_key' ? 'API key' : 'OAuth sign-in'; + state = '
' + + '' + lock + 'Needs ' + kind + '' + + (s.auth === 'oauth' + ? '' + : '') + + '
'; + } else if (s.enabled && s.connected) { + state = '
' + + 'Connected' + + (s.auth === 'oauth' + ? '' + : '') + + '
'; + } return '
' + '
' + - '
' + escHtml(s.name) + '' + + '
' + nm + '' + '' + badge + '
' + note + '
' + escHtml(s.url || '') + '
' + - authNote + signinBtn + + state + '
' + '