fix(projects): Drawer resettet App-Focus nicht mehr (leere Projekte-Ursache) + Zurueck-Button
Kernbug: ProjectsBrowser.load() pushte bei JEDEM Drawer-Oeffnen status.active
in den App-Focus. Im Multi-Threading hat das Brain keinen globalen
active_project-State mehr → status.active ist null → Focus wurde auf Hauptchat
zurueckgesetzt. Folge: nach jedem Drawer-Oeffnen landeten alle Nachrichten im
Hauptchat, Projekte blieben leer.
- ProjectsBrowser: neues Prop currentFocusId (App-Focus = Source-of-Truth).
load() uebernimmt nur noch die Projektliste, kein onActiveChanged(status.active)
mehr. Highlight (✓ FOCUS) folgt currentFocusId.
- ChatScreen: currentFocusId={focusedProjectId} durchgereicht.
- ChatScreen: direkter „← Hauptchat"-Button im Focus-Header (nur im Projekt
sichtbar) — ein Tap statt Drawer→Hauptchat.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,12 @@ interface Props {
|
|||||||
/** Wird gerufen wenn Stefan ein anderes Projekt fokussiert (App-lokale
|
/** Wird gerufen wenn Stefan ein anderes Projekt fokussiert (App-lokale
|
||||||
* UI-Entscheidung, wechselt den Chat-Focus). */
|
* UI-Entscheidung, wechselt den Chat-Focus). */
|
||||||
onActiveChanged?: (project: Project | null) => void;
|
onActiveChanged?: (project: Project | null) => void;
|
||||||
|
/** Der aktuell in der App fokussierte Kontext (App-lokale Source-of-Truth).
|
||||||
|
* Leer = Hauptchat. Steuert das ✓-FOCUS-Highlight. WICHTIG: der Drawer darf
|
||||||
|
* den Focus NICHT aus dem Brain-Status ableiten — im Multi-Threading gibt es
|
||||||
|
* kein globales active_project mehr (status.active ist null), das wuerde den
|
||||||
|
* Focus bei jedem Drawer-Oeffnen auf Hauptchat zuruecksetzen. */
|
||||||
|
currentFocusId?: string;
|
||||||
/** Queue-Status pro Kontext (key "__main__" = Hauptchat, sonst project_id).
|
/** Queue-Status pro Kontext (key "__main__" = Hauptchat, sonst project_id).
|
||||||
* Wenn geliefert: Status-Dot pro Zeile gerendert. */
|
* Wenn geliefert: Status-Dot pro Zeile gerendert. */
|
||||||
queueStatus?: Record<string, { busy: boolean; queue_size: number }>;
|
queueStatus?: Record<string, { busy: boolean; queue_size: number }>;
|
||||||
@@ -51,7 +57,7 @@ function _fmtRel(unixSec: number): string {
|
|||||||
return new Date(unixSec * 1000).toLocaleDateString('de-DE');
|
return new Date(unixSec * 1000).toLocaleDateString('de-DE');
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProjectsBrowser: React.FC<Props> = ({ visible = true, onClose, onActiveChanged, queueStatus }) => {
|
export const ProjectsBrowser: React.FC<Props> = ({ visible = true, onClose, onActiveChanged, currentFocusId, queueStatus }) => {
|
||||||
const _statusDot = (pid: string) => {
|
const _statusDot = (pid: string) => {
|
||||||
const s = queueStatus?.[pid];
|
const s = queueStatus?.[pid];
|
||||||
if (!s) return { color: '#555570', label: '' };
|
if (!s) return { color: '#555570', label: '' };
|
||||||
@@ -80,9 +86,11 @@ export const ProjectsBrowser: React.FC<Props> = ({ visible = true, onClose, onAc
|
|||||||
setLoading(true); setErr(null);
|
setLoading(true); setErr(null);
|
||||||
brainApi.getProjectStatus()
|
brainApi.getProjectStatus()
|
||||||
.then(status => {
|
.then(status => {
|
||||||
|
// NUR die Projektliste + Queue uebernehmen. NICHT status.active in den
|
||||||
|
// App-Focus pushen — im Multi-Threading ist das Brain-active_project
|
||||||
|
// bedeutungslos (null), das wuerde den Focus bei jedem Drawer-Oeffnen
|
||||||
|
// auf Hauptchat zuruecksetzen und alle Nachrichten dort landen lassen.
|
||||||
setProjects(status.projects || []);
|
setProjects(status.projects || []);
|
||||||
setActiveId(status.active_id || '');
|
|
||||||
onActiveChangedRef.current?.(status.active);
|
|
||||||
})
|
})
|
||||||
.catch(e => setErr(String(e?.message || e)))
|
.catch(e => setErr(String(e?.message || e)))
|
||||||
.finally(() => setLoading(false));
|
.finally(() => setLoading(false));
|
||||||
@@ -90,6 +98,10 @@ export const ProjectsBrowser: React.FC<Props> = ({ visible = true, onClose, onAc
|
|||||||
|
|
||||||
useEffect(() => { if (visible) load(); }, [visible, load]);
|
useEffect(() => { if (visible) load(); }, [visible, load]);
|
||||||
|
|
||||||
|
// Highlight („✓ FOCUS") folgt dem App-Focus (Source-of-Truth), nicht dem
|
||||||
|
// Brain. switchTo setzt activeId zusaetzlich sofort fuer Instant-Feedback.
|
||||||
|
useEffect(() => { setActiveId(currentFocusId || ''); }, [currentFocusId]);
|
||||||
|
|
||||||
// Reload bei RVS-Reconnect — sonst zeigt die Liste den Fast-Fail ewig
|
// Reload bei RVS-Reconnect — sonst zeigt die Liste den Fast-Fail ewig
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!visible) return;
|
if (!visible) return;
|
||||||
|
|||||||
@@ -2607,6 +2607,21 @@ const ChatScreen: React.FC = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
<View style={{ width: 8, height: 8, borderRadius: 4, backgroundColor: dot.color }} />
|
<View style={{ width: 8, height: 8, borderRadius: 4, backgroundColor: dot.color }} />
|
||||||
<Text style={{ fontSize: 10, color: '#8888AA' }}>{dot.label}</Text>
|
<Text style={{ fontSize: 10, color: '#8888AA' }}>{dot.label}</Text>
|
||||||
|
{/* Direkter Zurueck-zum-Hauptchat-Button — nur wenn man in einem
|
||||||
|
Projekt ist. Ein Tap statt Drawer→Hauptchat. */}
|
||||||
|
{!isMain && (
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => setFocusedProjectId('')}
|
||||||
|
hitSlop={{top:8,bottom:8,left:8,right:8}}
|
||||||
|
style={{
|
||||||
|
marginLeft: 4, paddingHorizontal: 10, paddingVertical: 4,
|
||||||
|
borderRadius: 12, backgroundColor: 'rgba(255,255,255,0.12)',
|
||||||
|
flexDirection: 'row', alignItems: 'center', gap: 4,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text style={{ color: '#E0E0F0', fontSize: 12, fontWeight: '700' }}>← Hauptchat</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
@@ -2617,6 +2632,7 @@ const ChatScreen: React.FC = () => {
|
|||||||
visible={projectsVisible}
|
visible={projectsVisible}
|
||||||
onClose={() => setProjectsVisible(false)}
|
onClose={() => setProjectsVisible(false)}
|
||||||
onActiveChanged={(p) => setFocusedProjectId(p?.id || '')}
|
onActiveChanged={(p) => setFocusedProjectId(p?.id || '')}
|
||||||
|
currentFocusId={focusedProjectId}
|
||||||
queueStatus={queueStatus}
|
queueStatus={queueStatus}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user