Skip to content

Commit 7742020

Browse files
kingpanther13claude
andcommitted
feat(settings-ui): install-aware restart copy + danger-styled disable confirm
Two UX gaps spotted while testing the sidecar in Claude Desktop. 1. Post-save banner read "Restart the add-on for changes to take effect" regardless of how the user actually runs ha-mcp. Claude Desktop / Docker / standalone users were told to do something that doesn't exist in their install. The banner text now reads from /api/settings/info and rewrites itself per mode: * is_addon → "Click 'Restart Add-on'" (the button is right there) * is_sidecar → "Fully quit and reopen your MCP client (Claude Desktop: tray icon → Quit, then relaunch; Claude Code: close the terminal session)" * otherwise → "Restart your ha-mcp process (Docker container, systemd service, or however you launch it)" 2. The sidecar's "Stop settings server" button was an accent-blue primary button sitting near the page's routine toggles. A misclick silently writes ~/.ha-mcp/settings_ui_disabled, which then prevents the sidecar from respawning on *every* subsequent Claude Desktop / ha-mcp launch — the only recovery is manual filesystem cleanup. Two mitigations: * Renamed to "Permanently disable settings server" and given a new .danger-btn class (red border + danger-red text on a transparent fill) so the destructive semantic is visible without reading the label. * confirm() now leads with the permanence and spells out the two-step recovery (delete the marker file AND unset HA_MCP_DISABLE_SETTINGS_UI). The old wording read like a soft "stop for now, autostart later" — the new wording reads like a commitment. The new \n sequences in the confirm() prompt go through the JS syntax regression test added in 249bcd1 (test_rendered_script_parses_as_javascript) so any future raw-newline slip-up still fails fast. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 249bcd1 commit 7742020

1 file changed

Lines changed: 60 additions & 11 deletions

File tree

src/ha_mcp/settings_ui.py

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,15 @@ def apply_tool_visibility(
497497
font-size: 0.85rem; flex-shrink: 0; }
498498
.restart-btn:hover { background: var(--accent-hover); }
499499
.restart-btn:disabled { opacity: 0.5; cursor: not-allowed; }
500+
/* Destructive variant — visually distinct from the primary accent
501+
so a glance at the page makes "Disable settings server"
502+
obviously not a routine click. Matches the restart-notice red
503+
family so the danger semantic reads even without label text. */
504+
.danger-btn { padding: 7px 14px; border-radius: 8px;
505+
border: 1px solid #7a1a1a; background: transparent; color: #ff9090;
506+
font-weight: 600; cursor: pointer; font-size: 0.8rem; flex-shrink: 0; }
507+
.danger-btn:hover { background: #2a0e0e; }
508+
.danger-btn:disabled { opacity: 0.5; cursor: not-allowed; }
500509
</style>
501510
</head>
502511
<body>
@@ -514,16 +523,16 @@ def apply_tool_visibility(
514523
and pinning has no extra effect.
515524
</div>
516525
<div class="restart-notice" id="restartNotice">
517-
<span class="restart-notice-text">
518-
⚠ Changes saved. Restart the add-on for them to take effect — disabled
526+
<span class="restart-notice-text" id="restartNoticeText">
527+
⚠ Changes saved. Restart ha-mcp for them to take effect — disabled
519528
tools will be fully removed from the MCP tool list on next startup.
520529
</span>
521530
<button class="restart-btn" id="restartBtn" style="display:none">Restart Add-on</button>
522531
</div>
523532
<div id="sidecarStopRow" style="display:none; margin: 12px 0; text-align: right;">
524-
<button class="restart-btn" id="stopSidecarBtn"
525-
title="Stops this settings UI sidecar process and writes a disable sentinel so it won't respawn on next ha-mcp start. Delete ~/.ha-mcp/settings_ui_disabled to re-enable."
526-
>Stop settings server</button>
533+
<button class="danger-btn" id="stopSidecarBtn"
534+
title="Permanently disables the settings UI: stops this server AND writes ~/.ha-mcp/settings_ui_disabled so it does not respawn on future ha-mcp launches. Delete that file to re-enable."
535+
>Permanently disable settings server</button>
527536
</div>
528537
<div class="summary" id="summary"></div>
529538
<input type="text" class="search" id="search" placeholder="Search tools...">
@@ -595,25 +604,65 @@ def apply_tool_visibility(
595604
// button only when this page is served by the stdio sidecar
596605
// (HTTP modes serve the same HTML but is_sidecar=false there, so
597606
// clicking Stop wouldn't make sense — it would kill the MCP server).
607+
// Also tailor the restart-notice copy to the install mode so the
608+
// user is told exactly what action they need to take ("close and
609+
// reopen Claude Desktop" vs "click Restart Add-on" vs "restart
610+
// your Docker container") instead of a generic "restart the add-on"
611+
// that only matches one of three real deployment surfaces.
598612
try {
599613
const infoResp = await fetch('./api/settings/info');
600614
const info = await infoResp.json();
615+
const noticeEl = document.getElementById('restartNoticeText');
601616
if (info.is_addon) {
602617
document.getElementById('restartBtn').style.display = '';
603-
}
604-
if (info.is_sidecar) {
618+
if (noticeEl) {
619+
noticeEl.textContent =
620+
'⚠ Changes saved. Click "Restart Add-on" for them to take ' +
621+
'effect — disabled tools will be fully removed from the MCP ' +
622+
'tool list on next startup.';
623+
}
624+
} else if (info.is_sidecar) {
625+
if (noticeEl) {
626+
noticeEl.textContent =
627+
'⚠ Changes saved. Fully quit and reopen your MCP client ' +
628+
'(Claude Desktop: right-click the tray icon → Quit, then ' +
629+
'relaunch; Claude Code: close the terminal session) for them ' +
630+
'to take effect. Disabled tools will be fully removed from the ' +
631+
'MCP tool list on next startup.';
632+
}
605633
document.getElementById('sidecarStopRow').style.display = '';
634+
} else if (noticeEl) {
635+
// HTTP / Docker / standalone — no button we can wire to a restart,
636+
// so describe the action in process terms.
637+
noticeEl.textContent =
638+
'⚠ Changes saved. Restart your ha-mcp process (Docker ' +
639+
'container, systemd service, or however you launch it) for them ' +
640+
'to take effect. Disabled tools will be fully removed from the ' +
641+
'MCP tool list on next startup.';
606642
}
607643
} catch (_e) {}
608644
}
609645
610646
async function stopSidecar() {
611647
const btn = document.getElementById('stopSidecarBtn');
648+
// Two-part confirm wording: lead with the *permanence* (this is not a
649+
// routine "stop now, autostart later" — the server will refuse to
650+
// restart on every future ha-mcp launch until the user manually
651+
// intervenes), then spell out the exact re-enable steps. The button
652+
// is right-aligned near the top of a list of toggle controls, so
653+
// accidental clicks are easy; the dialog needs to read like a
654+
// commitment, not a soft prompt.
612655
if (!confirm(
613-
'Stop the settings server?\\n\\n' +
614-
'A "disabled" sentinel file will be written so the server does not ' +
615-
'respawn the next time ha-mcp starts. To re-enable, delete the file ' +
616-
'at ~/.ha-mcp/settings_ui_disabled (or unset HA_MCP_DISABLE_SETTINGS_UI).'
656+
'⚠ PERMANENTLY disable the settings server?\\n\\n' +
657+
'This stops the running server AND writes a disable marker so it ' +
658+
'will NOT respawn on future ha-mcp launches — every restart of ' +
659+
'Claude Desktop / Docker / your MCP host will continue to skip it ' +
660+
'until you manually re-enable.\\n\\n' +
661+
'To restore access later you must:\\n' +
662+
' 1. Delete ~/.ha-mcp/settings_ui_disabled (the marker file), AND\\n' +
663+
' 2. Unset HA_MCP_DISABLE_SETTINGS_UI if that env var was set.\\n\\n' +
664+
'You will lose the in-browser tool-configuration UI until both ' +
665+
'conditions are met. Continue?'
617666
)) return;
618667
btn.disabled = true;
619668
btn.textContent = 'Stopping...';

0 commit comments

Comments
 (0)