feat: hierarchical notebook system - trash, selectors, breadcrumb, sidebar tree
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m9s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m9s
- Schema: soft delete with trashedAt on Notebook model - API: PATCH/GET notebooks support trashedAt filtering with cascade - Sidebar: recursive tree rendering with collapse/expand, visual guides, hover actions - HierarchicalNotebookSelector: portal-based dropdown with search, breadcrumbs, dropUp support - AI chat: context selector with Toutes mes notes + notebook selector - Agent detail: flat selects replaced with HierarchicalNotebookSelector - Breadcrumb: notebook path display on home page - Trash view: card grid with countdown, restore/permanent delete - CSS: design tokens (ink, paper, blueprint, concrete, etc.) - Types: parentId, trashedAt added to Notebook interface
This commit is contained in:
@@ -57,6 +57,9 @@ export interface NotebooksContextValue {
|
||||
createNotebookOptimistic: (data: CreateNotebookInput) => Promise<void>
|
||||
updateNotebook: (notebookId: string, data: UpdateNotebookInput) => Promise<void>
|
||||
deleteNotebook: (notebookId: string) => Promise<void>
|
||||
trashNotebook: (notebookId: string) => Promise<void>
|
||||
restoreNotebook: (notebookId: string) => Promise<void>
|
||||
permanentDeleteNotebook: (notebookId: string) => Promise<void>
|
||||
updateNotebookOrderOptimistic: (notebookIds: string[]) => Promise<void>
|
||||
setCurrentNotebook: (notebook: Notebook | null) => void
|
||||
|
||||
@@ -215,6 +218,52 @@ export function NotebooksProvider({ children, initialNotebooks = [] }: Notebooks
|
||||
triggerRefresh()
|
||||
}, [queryClient, triggerNotebooksRefresh, triggerRefresh])
|
||||
|
||||
const trashNotebook = useCallback(async (notebookId: string) => {
|
||||
const response = await fetch(`/api/notebooks/${notebookId}`, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ trashedAt: new Date().toISOString() }),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to trash notebook')
|
||||
}
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.notebooks() })
|
||||
triggerNotebooksRefresh()
|
||||
triggerRefresh()
|
||||
}, [queryClient, triggerNotebooksRefresh, triggerRefresh])
|
||||
|
||||
const restoreNotebook = useCallback(async (notebookId: string) => {
|
||||
const response = await fetch(`/api/notebooks/${notebookId}`, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ trashedAt: null }),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to restore notebook')
|
||||
}
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.notebooks() })
|
||||
triggerNotebooksRefresh()
|
||||
triggerRefresh()
|
||||
}, [queryClient, triggerNotebooksRefresh, triggerRefresh])
|
||||
|
||||
const permanentDeleteNotebook = useCallback(async (notebookId: string) => {
|
||||
const response = await fetch(`/api/notebooks/${notebookId}`, {
|
||||
method: 'DELETE',
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to permanently delete notebook')
|
||||
}
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.notebooks() })
|
||||
triggerNotebooksRefresh()
|
||||
triggerRefresh()
|
||||
}, [queryClient, triggerNotebooksRefresh, triggerRefresh])
|
||||
|
||||
const updateNotebookOrderOptimistic = useCallback(async (notebookIds: string[]) => {
|
||||
const response = await fetch('/api/notebooks/reorder', {
|
||||
method: 'POST',
|
||||
@@ -378,6 +427,9 @@ export function NotebooksProvider({ children, initialNotebooks = [] }: Notebooks
|
||||
createNotebookOptimistic,
|
||||
updateNotebook,
|
||||
deleteNotebook,
|
||||
trashNotebook,
|
||||
restoreNotebook,
|
||||
permanentDeleteNotebook,
|
||||
updateNotebookOrderOptimistic,
|
||||
setCurrentNotebook,
|
||||
createLabel,
|
||||
@@ -403,6 +455,9 @@ export function NotebooksProvider({ children, initialNotebooks = [] }: Notebooks
|
||||
createNotebookOptimistic,
|
||||
updateNotebook,
|
||||
deleteNotebook,
|
||||
trashNotebook,
|
||||
restoreNotebook,
|
||||
permanentDeleteNotebook,
|
||||
updateNotebookOrderOptimistic,
|
||||
createLabel,
|
||||
updateLabel,
|
||||
|
||||
Reference in New Issue
Block a user