fix(ui): allow Control UI chat without node

This commit is contained in:
Peter Steinberger
2026-01-04 16:46:39 +00:00
parent 564cc9359d
commit 266fd748d0
3 changed files with 9 additions and 32 deletions

View File

@@ -183,16 +183,7 @@ export function renderApp(state: AppViewState) {
const presenceCount = state.presenceEntries.length;
const sessionsCount = state.sessionsResult?.count ?? null;
const cronNext = state.cronStatus?.nextWakeAtMs ?? null;
const hasConnectedMobileNode = state.nodes.some((n) => {
if (!Boolean(n.connected)) return false;
const p = typeof n.platform === "string" ? n.platform.trim().toLowerCase() : "";
return p.startsWith("ios") || p.startsWith("ipados") || p.startsWith("android");
});
const chatDisabledReason = !state.connected
? "Disconnected from gateway."
: hasConnectedMobileNode
? null
: "No connected iOS/Android node — Web Chat + Talk are disabled.";
const chatDisabledReason = state.connected ? null : "Disconnected from gateway.";
return html`
<div class="shell">
@@ -398,7 +389,7 @@ export function renderApp(state: AppViewState) {
stream: state.chatStream,
draft: state.chatMessage,
connected: state.connected,
canSend: state.connected && hasConnectedMobileNode,
canSend: state.connected,
disabledReason: chatDisabledReason,
sessions: state.sessionsResult,
onRefresh: () => {

View File

@@ -451,17 +451,6 @@ export class ClawdbotApp extends LitElement {
this.nodesPollInterval = null;
}
private hasConnectedMobileNode() {
return this.nodes.some((n) => {
if (!Boolean(n.connected)) return false;
const p =
typeof n.platform === "string" ? n.platform.trim().toLowerCase() : "";
return (
p.startsWith("ios") || p.startsWith("ipados") || p.startsWith("android")
);
});
}
resetToolStream() {
this.toolStreamById.clear();
this.toolStreamOrder = [];
@@ -765,9 +754,8 @@ export class ClawdbotApp extends LitElement {
async loadCron() {
await Promise.all([loadCronStatus(this), loadCronJobs(this)]);
}
async handleSendChat() {
if (!this.connected || !this.hasConnectedMobileNode()) return;
if (!this.connected) return;
await sendChat(this);
void loadChatHistory(this);
}

View File

@@ -23,13 +23,11 @@ export type ChatProps = {
export function renderChat(props: ChatProps) {
const canInteract = props.connected;
const canCompose = props.canSend && !props.sending;
const canCompose = props.connected && !props.sending;
const sessionOptions = resolveSessionOptions(props.sessionKey, props.sessions);
const composePlaceholder = (() => {
if (!props.connected) return "Connect to the gateway to start chatting…";
if (!props.canSend) return "Connect an iOS/Android node to enable Web Chat + Talk…";
return "Message (⌘↩ to send)";
})();
const composePlaceholder = props.connected
? "Message (⌘↩ to send)"
: "Connect to the gateway to start chatting…";
return html`
<section class="card chat">
@@ -90,7 +88,7 @@ export function renderChat(props: ChatProps) {
<span>Message</span>
<textarea
.value=${props.draft}
?disabled=${!props.canSend}
?disabled=${!props.connected}
@keydown=${(e: KeyboardEvent) => {
if (e.key !== "Enter") return;
if (!e.metaKey && !e.ctrlKey) return;
@@ -105,7 +103,7 @@ export function renderChat(props: ChatProps) {
<div class="row chat-compose__actions">
<button
class="btn primary"
?disabled=${!props.canSend || props.sending}
?disabled=${!props.connected || props.sending}
@click=${props.onSend}
>
${props.sending ? "Sending…" : "Send"}