fix(keep-notes): sidebar chevron, labels sync, batch org errors, perf guards

- Notebooks: chevron visible when expanded (remove overflow clip), functional expand state
- Labels: sync/cleanup by notebookId, reconcile after note move
- Settings: refresh notebooks after cleanup; label dialog routing
- ConnectionsBadge lazy-load; reminder check persistence; i18n keys

Made-with: Cursor
This commit is contained in:
Sepehr Ramezani
2026-04-13 22:07:09 +02:00
parent fa7e166f3e
commit 39671c6472
16 changed files with 469 additions and 303 deletions

View File

@@ -1,6 +1,6 @@
'use client'
import { useState } from 'react'
import { useState, useEffect } from 'react'
import { Button } from './ui/button'
import {
Dialog,
@@ -27,21 +27,24 @@ export function BatchOrganizationDialog({
onOpenChange,
onNotesMoved,
}: BatchOrganizationDialogProps) {
const { t } = useLanguage()
const { t, language } = useLanguage()
const [plan, setPlan] = useState<OrganizationPlan | null>(null)
const [loading, setLoading] = useState(false)
const [applying, setApplying] = useState(false)
const [selectedNotes, setSelectedNotes] = useState<Set<string>>(new Set())
const [fetchError, setFetchError] = useState<string | null>(null)
const fetchOrganizationPlan = async () => {
setLoading(true)
setFetchError(null)
try {
const response = await fetch('/api/ai/batch-organize', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
language: document.documentElement.lang || 'en'
language: language || 'en'
}),
})
@@ -49,32 +52,38 @@ export function BatchOrganizationDialog({
if (data.success && data.data) {
setPlan(data.data)
// Select all notes by default
const allNoteIds = new Set<string>()
data.data.notebooks.forEach((nb: NotebookOrganization) => {
nb.notes.forEach(note => allNoteIds.add(note.noteId))
})
setSelectedNotes(allNoteIds)
} else {
toast.error(data.error || t('ai.batchOrganization.error'))
const msg = data.error || t('ai.batchOrganization.error')
setFetchError(msg)
toast.error(msg)
}
} catch (error) {
console.error('Failed to create organization plan:', error)
toast.error(t('ai.batchOrganization.error'))
const msg = t('ai.batchOrganization.error')
setFetchError(msg)
toast.error(msg)
} finally {
setLoading(false)
}
}
const handleOpenChange = (isOpen: boolean) => {
if (!isOpen) {
// Reset state when closing
useEffect(() => {
if (open) {
fetchOrganizationPlan()
} else {
setPlan(null)
setSelectedNotes(new Set())
} else {
// Fetch plan when opening
fetchOrganizationPlan()
setFetchError(null)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [open])
const handleOpenChange = (isOpen: boolean) => {
onOpenChange(isOpen)
}
@@ -173,6 +182,13 @@ export function BatchOrganizationDialog({
{t('ai.batchOrganization.analyzing')}
</p>
</div>
) : fetchError ? (
<div className="flex flex-col items-center justify-center py-12 gap-4">
<p className="text-sm text-destructive text-center">{fetchError}</p>
<Button variant="outline" onClick={fetchOrganizationPlan}>
{t('general.tryAgain')}
</Button>
</div>
) : plan ? (
<div className="space-y-6 py-4">
{/* Summary */}