Refactor: naming, type safety, consistency across panel system

- AppToolbar: rename togglePanel→toggleDropdown to avoid collision with
  debug panel toggle from usePanels
- ChatPane: computed()→toRef() for props passed to composables (consistent)
- ChatPane: add console.warn on session history fetch failure
- DebugColumn: skip object spread when no new panels resolved (perf)
- AgentsView: remove unused wsSwitchAgent, annotate disabled picker

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nico 2026-04-02 20:21:20 +02:00
parent e948caf132
commit 4607a73d67
4 changed files with 24 additions and 20 deletions

View File

@ -1,7 +1,7 @@
<template>
<div v-if="isLoggedIn" class="app-toolbar">
<!-- Connection pill -->
<button class="toolbar-pill" :class="{ active: connActive }" @click="togglePanel('conn')" :title="connLabel || 'Connection'">
<button class="toolbar-pill" :class="{ active: connActive }" @click="toggleDropdown('conn')" :title="connLabel || 'Connection'">
<WifiIcon class="w-4 h-4" />
<span v-if="connLabel" class="toolbar-pill-label">{{ connLabel }}</span>
</button>
@ -57,7 +57,7 @@
v-if="takeoverToken"
class="toolbar-pill"
:class="{ active: captureActive }"
@click="togglePanel('takeover')"
@click="toggleDropdown('takeover')"
title="Takeover"
>
<SignalIcon class="w-4 h-4" />
@ -69,10 +69,10 @@
</button>
<!-- Panels (dropdown from toolbar) -->
<div v-if="openPanel" class="toolbar-panel-backdrop" @click="openPanel = null" />
<div v-if="openDropdown" class="toolbar-panel-backdrop" @click="openDropdown = null" />
<!-- Connection panel -->
<div v-if="openPanel === 'conn'" class="toolbar-panel" style="right: auto; left: 0;">
<div v-if="openDropdown === 'conn'" class="toolbar-panel" style="right: auto; left: 0;">
<div class="toolbar-panel-header">Connection</div>
<div class="toolbar-panel-row"><span>HTTP</span><span>{{ chatStore.connectionState }}</span></div>
<div class="toolbar-panel-row"><span>Channel</span><span>{{ chatStore.channelState }}</span></div>
@ -81,7 +81,7 @@
</div>
<!-- Takeover panel -->
<div v-if="openPanel === 'takeover'" class="toolbar-panel" style="right: 0;">
<div v-if="openDropdown === 'takeover'" class="toolbar-panel" style="right: 0;">
<div class="toolbar-panel-header">Takeover</div>
<div class="toolbar-panel-token" @click="copyToken" :title="tokenCopied ? 'Copied!' : 'Click to copy'">
<code>{{ takeoverToken }}</code>
@ -164,7 +164,7 @@ function copyToken() {
function revokeAndClose() {
takeover.revoke();
openPanel.value = null;
openDropdown.value = null;
}
// Version
@ -181,11 +181,11 @@ function copyVersionDetails() {
setTimeout(() => { versionCopied.value = false; }, 2000);
}
// Panel toggle
const openPanel = ref<'conn' | 'takeover' | null>(null);
// Toolbar dropdown (conn/takeover panels distinct from debug panel toggles)
const openDropdown = ref<'conn' | 'takeover' | null>(null);
function togglePanel(panel: 'conn' | 'takeover') {
openPanel.value = openPanel.value === panel ? null : panel;
function toggleDropdown(panel: 'conn' | 'takeover') {
openDropdown.value = openDropdown.value === panel ? null : panel;
}
</script>

View File

@ -259,7 +259,7 @@ async function fetchPreviousSession(loadMore = false) {
}
prevSkip.value = skip + newSessions.length;
prevHasMore.value = data.hasMore ?? false;
} catch { /* silently fail */ }
} catch (err) { console.warn('[chat] session history fetch failed:', err); }
finally { prevLoading.value = false; }
}
@ -288,8 +288,8 @@ const visibleCount = ref(VISIBLE_PAGE);
const { groupedVisibleMsgs, hasMore, loadMore, getFormattedAgentName } = useMessageGrouping(
computed(() => chatStore.messages),
visibleCount,
computed(() => props.selectedAgent),
computed(() => props.allAgents),
toRef(props, 'selectedAgent'),
toRef(props, 'allAgents'),
toRef(chatStore, 'sessionKey'),
);
@ -421,7 +421,7 @@ function onConfirmNew() {
}
const { inputEl, isShaking, autoGrow, triggerShake } = useInputAutogrow(input);
const { isAgentRunning } = useAgentDisplay(computed(() => props.selectedAgent), computed(() => props.defaultAgent), computed(() => props.allAgents));
const { isAgentRunning } = useAgentDisplay(toRef(props, 'selectedAgent'), toRef(props, 'defaultAgent'), toRef(props, 'allAgents'));
// Attachments
const { attachments, addFiles, removeAttachment, clearAttachments, toPayload, hasAttachments } = useAttachments();

View File

@ -39,13 +39,16 @@ const { openSidePanels, closePanel } = usePanels();
const resolvedComponents = shallowRef<Record<string, Component>>({});
watch(openSidePanels, (panels) => {
const current = { ...resolvedComponents.value };
const current = resolvedComponents.value;
let changed = false;
const updates = { ...current };
for (const panel of panels) {
if (!current[panel.id]) {
current[panel.id] = defineAsyncComponent(panel.component);
if (!updates[panel.id]) {
updates[panel.id] = defineAsyncComponent(panel.component);
changed = true;
}
}
resolvedComponents.value = current;
if (changed) resolvedComponents.value = updates;
}, { immediate: true });
function panelProps(id: PanelId): Record<string, any> {

View File

@ -83,11 +83,12 @@ const agentsRoute = useRoute();
const { isChatOpen, isWorkspaceOpen, hasDebugColumn } = usePanels();
// Auth + agents
const { connected, send: wsSend, switchAgent: wsSwitchAgent } = ws;
const { connected, send: wsSend } = ws;
const { isLoggedIn } = auth;
const { selectedAgent, selectedMode, filteredAgents, defaultAgent, allAgents } = agents;
// Agent picker
// Agent picker disabled for now (auto-select default agent)
// TODO: re-enable when multi-agent UX is designed
const showPicker = computed(() => false);
const SEGMENTS = ['personal', 'common', 'private', 'public'] as const;
const agentSegments = computed(() =>