fix: AI loop prevention (no tools on last iteration), calendar button first, mail filter in toolbar, AI folder rename query invalidation
Check Cross-Plugin Imports / check (push) Has been cancelled

This commit is contained in:
Agent Zero
2026-07-30 11:33:45 +02:00
parent 124846ae3b
commit acea622a0f
4 changed files with 73 additions and 49 deletions
+6 -1
View File
@@ -1,5 +1,6 @@
import React, { useEffect, useState, useRef, useCallback } from 'react';
import clsx from 'clsx';
import { useQueryClient } from '@tanstack/react-query';
import {
fetchSessions, createSession, deleteSession, updateSession,
fetchFolders, createFolder, deleteFolder, updateFolder,
@@ -261,6 +262,7 @@ export function SessionList({ activeSessionId, onSelectSession, isSidebar, class
const [dragSessionId, setDragSessionId] = useState<string | null>(null);
const [dragFolderId, setDragFolderId] = useState<string | null>(null);
const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);
const queryClient = useQueryClient();
const loadData = async () => {
try {
@@ -287,7 +289,10 @@ export function SessionList({ activeSessionId, onSelectSession, isSidebar, class
if (!newName) return;
try {
if (type === 'session') await updateSession(id, { title: newName });
else await updateFolder(id, { name: newName });
else {
await updateFolder(id, { name: newName });
queryClient.invalidateQueries({ queryKey: ['ai', 'folders'] });
}
loadData();
} catch (e) { setError(e instanceof Error ? e.message : 'Rename failed'); }
};
+25 -25
View File
@@ -327,6 +327,31 @@ export function CalendarPage() {
useEffect(() => {
const items = [
// New appointment — ganz links
{
id: 'new-appointment',
plugin: 'calendar',
label: t('calendar.newAppointment'),
group: 'actions',
onClick: () => {
openWindow({
title: t('calendar.newAppointment'),
type: 'appointment-create',
component: AppointmentEditForm,
componentProps: {
entry: null,
prefillDate: null,
calendars,
defaultCalendarId: activeCalendarId,
onSaved: handleSaved,
onDeleted: handleDeleted,
},
});
},
icon: (
<Plus className="w-3.5 h-3.5" strokeWidth={2} />
),
},
// Navigation group
{
id: 'nav-prev',
@@ -384,31 +409,6 @@ export function CalendarPage() {
onSelect: (value: string) => setViewMode(value as CalendarViewMode),
onClick: () => {},
},
// Actions group
{
id: 'new-appointment',
plugin: 'calendar',
label: t('calendar.newAppointment'),
group: 'actions',
onClick: () => {
openWindow({
title: t('calendar.newAppointment'),
type: 'appointment-create',
component: AppointmentEditForm,
componentProps: {
entry: null,
prefillDate: null,
calendars,
defaultCalendarId: activeCalendarId,
onSaved: handleSaved,
onDeleted: handleDeleted,
},
});
},
icon: (
<Plus className="w-3.5 h-3.5" strokeWidth={2} />
),
},
{
id: 'ics-import',
plugin: 'calendar',
+37 -21
View File
@@ -594,6 +594,43 @@ export function MailPage() {
onSearch: handleSearch,
onClick: () => {},
},
// FilterPanel — SavedFilterBar + TagSelector
{
id: 'filter-panel',
plugin: 'mail',
label: 'Filter',
type: 'custom' as const,
group: 'filter',
customComponent: (
<SavedFilterBar
entityType="mail"
currentFilters={{ search: searchQuery, sortBy, sortOrder, folderId: selectedFolderId }}
onApplyFilter={(criteria) => {
if (criteria.search !== undefined) handleSearch(criteria.search);
if (criteria.sortBy) setSortBy(criteria.sortBy as 'date' | 'from' | 'subject');
if (criteria.sortOrder) setSortOrder(criteria.sortOrder as 'asc' | 'desc');
}}
/>
),
onClick: () => {},
},
{
id: 'tag-filter',
plugin: 'mail',
label: 'Tags',
type: 'custom' as const,
group: 'filter',
customComponent: (
<TagSelector
entityType="file"
entityId={selectedMail?.id ?? ''}
selectedTags={selectedTags}
onChange={setSelectedTags}
placeholder={t('tags.selectPlaceholder', 'Tags filtern...')}
/>
),
onClick: () => {},
},
{
id: 'compose',
plugin: 'mail',
@@ -814,27 +851,6 @@ export function MailPage() {
className="border-r border-secondary-200 bg-white"
data-testid="mail-list-pane"
>
{/* Saved filter bar + tag selector */}
<div className="flex items-center gap-2 px-3 py-2 border-b border-secondary-200 bg-secondary-50 flex-wrap" data-testid="mail-filter-bar">
<SavedFilterBar
entityType="mail"
currentFilters={{ search: searchQuery, sortBy, sortOrder, folderId: selectedFolderId }}
onApplyFilter={(criteria) => {
if (criteria.search !== undefined) handleSearch(criteria.search);
if (criteria.sortBy) setSortBy(criteria.sortBy as 'date' | 'from' | 'subject');
if (criteria.sortOrder) setSortOrder(criteria.sortOrder as 'asc' | 'desc');
}}
/>
<div className="flex-1 min-w-[180px]" data-testid="mail-tag-selector">
<TagSelector
entityType="file"
entityId={selectedMail?.id ?? ''}
selectedTags={selectedTags}
onChange={setSelectedTags}
placeholder={t('tags.selectPlaceholder', 'Tags filtern...')}
/>
</div>
</div>
<MailList
mails={mails}
selectedMailId={selectedMail?.id || null}