This commit is contained in:
seb
2026-10-12 18:10:26 +02:00
parent 15dce3c1cf
commit a0a40b243a
6 changed files with 1065 additions and 698 deletions

View File

@@ -46,6 +46,44 @@ import {
} from '../../colors';
const DEFAULT_DRAWER_WIDTH = 460;
/** Sort by updated_at desc; subagents (started_by set) directly below their parent. */
function sortConversations(list) {
const ts = (c) => new Date(c.updated_at || c.created_at || 0).getTime() || 0;
const byUpdated = (a, b) => ts(b) - ts(a);
const ids = new Set(list.map((c) => c.id));
const children = new Map();
const roots = [];
for (const c of list) {
if (c.started_by != null && ids.has(c.started_by)) {
if (!children.has(c.started_by)) children.set(c.started_by, []);
children.get(c.started_by).push(c);
} else {
roots.push(c);
}
}
const out = [];
const walk = (c, depth) => {
out.push({ conv: c, depth });
(children.get(c.id) || []).sort(byUpdated).forEach((k) => walk(k, depth + 1));
};
roots.sort(byUpdated).forEach((c) => walk(c, 0));
return out;
}
function formatUpdated(value) {
if (!value) return '';
const d = new Date(value);
if (Number.isNaN(d.getTime())) return '';
return d.toLocaleString('de-DE', {
day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit',
});
}
function conversationTitle(c) {
const msg = (c.first_message || '').replace(/\s+/g, ' ').trim();
return msg || '…';
}
const MIN_DRAWER_WIDTH = 320;
export default class ChatDrawer extends PureComponent {
@@ -1085,24 +1123,32 @@ export default class ChatDrawer extends PureComponent {
if (!conv) return '';
return (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, overflow: 'hidden' }}>
<Typography variant="body2" fontWeight={600} noWrap>
#{conv.id}
<Typography variant="body2" fontWeight={600} noWrap sx={{ flexGrow: 1, minWidth: 0 }}>
{conversationTitle(conv)}
</Typography>
<Typography variant="caption" color="text.secondary" noWrap>
{conv.model || 'Standard'}
<Typography variant="caption" color="text.secondary" noWrap sx={{ flexShrink: 0 }}>
{formatUpdated(conv.updated_at)}
</Typography>
</Box>
);
}}
>
{conversations.map((c) => (
<MenuItem key={c.id} value={c.id}>
{sortConversations(conversations).map(({ conv: c, depth }) => (
<MenuItem key={c.id} value={c.id} sx={{ pl: 2 + depth * 2.5 }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, width: '100%', overflow: 'hidden' }}>
<Typography variant="body2" fontWeight={600} noWrap>
#{c.id}
{depth > 0 && (
<Typography variant="caption" color="text.secondary">↳</Typography>
)}
<Typography
variant="body2"
fontWeight={depth > 0 ? 400 : 600}
noWrap
sx={{ flexGrow: 1, minWidth: 0 }}
>
{conversationTitle(c)}
</Typography>
<Typography variant="caption" color="text.secondary" noWrap sx={{ flexGrow: 1 }}>
{c.model || 'Standard'}
<Typography variant="caption" color="text.secondary" noWrap sx={{ flexShrink: 0 }}>
{formatUpdated(c.updated_at)}
</Typography>
</Box>
</MenuItem>