This commit is contained in:
seb
2026-10-04 08:18:36 +02:00
parent f2fce9097b
commit 4edd417dab
19 changed files with 141 additions and 220 deletions

View File

@@ -9,7 +9,6 @@ import MenuItem from '@mui/material/MenuItem';
import Select from '@mui/material/Select';
import FormControl from '@mui/material/FormControl';
import InputLabel from '@mui/material/InputLabel';
import Chip from '@mui/material/Chip';
import CircularProgress from '@mui/material/CircularProgress';
import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
import SendRoundedIcon from '@mui/icons-material/SendRounded';
@@ -231,7 +230,6 @@ export default class ChatDrawer extends PureComponent {
const {
conversations,
selectedConversationId,
sseStatus,
loadingConversations,
} = this.state;
@@ -249,21 +247,8 @@ export default class ChatDrawer extends PureComponent {
}}
>
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.25 }}>
<Box
sx={{
width: 32,
height: 32,
borderRadius: 2,
bgcolor: 'primary.main',
color: 'primary.contrastText',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<AutoAwesomeRoundedIcon sx={{ fontSize: 18 }} />
</Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<AutoAwesomeRoundedIcon sx={{ fontSize: 22, color: 'primary.main' }} />
<Typography variant="subtitle1" fontWeight={700}>
KI-Assistent
</Typography>
@@ -275,80 +260,82 @@ export default class ChatDrawer extends PureComponent {
</Box>
{/* Conversation Selector Bar */}
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<FormControl fullWidth size="small">
<InputLabel id="chat-conversation-label">Konversation</InputLabel>
<Select
labelId="chat-conversation-label"
value={selectedConversationId || ''}
label="Konversation"
onChange={this.handleSelectConversation}
disabled={loadingConversations || conversations.length === 0}
sx={{ borderRadius: 2 }}
renderValue={(selectedId) => {
const conv = conversations.find((c) => c.id === selectedId);
if (!conv) return '';
return (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, overflow: 'hidden' }}>
<Typography variant="body2" fontWeight={600} noWrap>
#{conv.id}
</Typography>
<Typography variant="caption" color="text.secondary" noWrap>
{conv.model || 'Standard'}
</Typography>
</Box>
);
{conversations.length > 0 && (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<FormControl fullWidth size="small">
<InputLabel id="chat-conversation-label">Konversation</InputLabel>
<Select
labelId="chat-conversation-label"
value={selectedConversationId || ''}
label="Konversation"
onChange={this.handleSelectConversation}
disabled={loadingConversations || conversations.length === 0}
sx={{ borderRadius: 2 }}
renderValue={(selectedId) => {
const conv = conversations.find((c) => c.id === selectedId);
if (!conv) return '';
return (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, overflow: 'hidden' }}>
<Typography variant="body2" fontWeight={600} noWrap>
#{conv.id}
</Typography>
<Typography variant="caption" color="text.secondary" noWrap>
{conv.model || 'Standard'}
</Typography>
</Box>
);
}}
>
{conversations.map((c) => (
<MenuItem key={c.id} value={c.id}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, width: '100%', overflow: 'hidden' }}>
<Typography variant="body2" fontWeight={600} noWrap>
#{c.id}
</Typography>
<Typography variant="caption" color="text.secondary" noWrap sx={{ flexGrow: 1 }}>
{c.model || 'Standard'}
</Typography>
</Box>
</MenuItem>
))}
</Select>
</FormControl>
<IconButton
size="small"
color="error"
disabled={!selectedConversationId}
onClick={(e) => this.handleDeleteConversation(e, selectedConversationId)}
aria-label="Konversation löschen"
sx={{
borderRadius: 2,
border: 1,
borderColor: 'divider',
p: 0.9,
flexShrink: 0,
}}
>
{conversations.map((c) => (
<MenuItem key={c.id} value={c.id}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, width: '100%', overflow: 'hidden' }}>
<Typography variant="body2" fontWeight={600} noWrap>
#{c.id}
</Typography>
<Typography variant="caption" color="text.secondary" noWrap sx={{ flexGrow: 1 }}>
{c.model || 'Standard'}
</Typography>
</Box>
</MenuItem>
))}
</Select>
</FormControl>
<DeleteOutlineRoundedIcon fontSize="small" />
</IconButton>
<IconButton
size="small"
color="error"
disabled={!selectedConversationId}
onClick={(e) => this.handleDeleteConversation(e, selectedConversationId)}
aria-label="Konversation löschen"
sx={{
borderRadius: 2,
border: 1,
borderColor: 'divider',
p: 0.9,
flexShrink: 0,
}}
>
<DeleteOutlineRoundedIcon fontSize="small" />
</IconButton>
<IconButton
size="small"
color="primary"
disabled={!selectedConversationId}
onClick={this.handleNewChat}
aria-label="Neuer Chat"
sx={{
borderRadius: 2,
border: 1,
borderColor: 'divider',
p: 0.9,
flexShrink: 0,
}}
>
<AddRoundedIcon fontSize="small" />
</IconButton>
</Box>
<IconButton
size="small"
color="primary"
disabled={!selectedConversationId}
onClick={this.handleNewChat}
aria-label="Neuer Chat"
sx={{
borderRadius: 2,
border: 1,
borderColor: 'divider',
p: 0.9,
flexShrink: 0,
}}
>
<AddRoundedIcon fontSize="small" />
</IconButton>
</Box>
)}
</Box>
);
}
@@ -362,7 +349,6 @@ export default class ChatDrawer extends PureComponent {
messages,
streamingText,
loadingConversations,
loadingMessages,
model,
} = this.state;
@@ -391,20 +377,7 @@ export default class ChatDrawer extends PureComponent {
gap: 2,
}}
>
<Box
sx={{
width: 56,
height: 56,
borderRadius: '50%',
bgcolor: 'primary.light',
color: 'primary.main',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<AutoAwesomeRoundedIcon sx={{ fontSize: 32 }} />
</Box>
<AutoAwesomeRoundedIcon sx={{ fontSize: 44, color: 'primary.main', opacity: 0.85 }} />
<Typography variant="h6" fontWeight={700}>
Willkommen im Chat
</Typography>

View File

@@ -177,14 +177,17 @@ function MessageRow({ msg, showTime = true }) {
bodyLength = textContent.length;
}
let displayText = '';
if (resObj && ('answer' in resObj || 'content' in resObj) && ('tool_call_id' in resObj) && !('status' in resObj)) {
displayText = resObj.answer || resObj.content || '';
} else {
displayText = statusText
const isToolAnswer =
Boolean(resObj) &&
('answer' in resObj || 'content' in resObj) &&
'tool_call_id' in resObj &&
!('status' in resObj);
const displayText = isToolAnswer
? resObj.answer || resObj.content || ''
: statusText
? `${statusText}${bodyLength != null ? ` · ${bodyLength} byte` : ''}`
: (bodyLength != null ? `${bodyLength} byte` : String(textContent));
}
return (
<Box sx={{ display: 'flex', justifyContent: 'flex-start', py: 0.35, px: 2 }}>