mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-08 07:17:39 +00:00
feat: add session management (rename, archive, delete)
Implements comprehensive session lifecycle management with user-friendly interactions: Rename: Update session metadata.name via PATCH endpoint with conflict detection Archive: Abort active sessions via DELETE endpoint with validation Delete: Permanently remove inactive sessions with cascade cleanup Backend: - Store.deleteSession() removes session and cascade-deletes messages - SyncEngine.renameSession() with concurrency error handling - SyncEngine.deleteSession() with active session validation - PATCH /sessions/:id for rename, DELETE /sessions/:id for delete Frontend Components: - RenameSessionDialog: Text input with auto-focus and error display - SessionActionMenu: Modal with rename, archive, delete buttons - ConfirmDialog: Reusable confirmation with error feedback - SessionHeader: Menu button (⋮) triggering action menu - SessionList: Long-press detection triggering item actions Interactions: - Long-press on session list items (500ms threshold) opens action menu - Menu button in session header (non-Telegram environments only) - Confirmation dialogs with descriptive warnings for destructive actions - Real-time error display in dialogs on operation failure - Haptic feedback on long-press via usePlatform hook Accessibility: - Keyboard support (Enter/Space) for long-press handler - Focus management in RenameSessionDialog - Proper ARIA labels and semantic HTML
This commit is contained in:
@@ -25,6 +25,8 @@ export function useSessionActions(api: ApiClient | null, sessionId: string | nul
|
||||
switchSession: () => Promise<void>
|
||||
setPermissionMode: (mode: PermissionMode) => Promise<void>
|
||||
setModelMode: (mode: ModelMode) => Promise<void>
|
||||
renameSession: (name: string) => Promise<void>
|
||||
deleteSession: () => Promise<void>
|
||||
isPending: boolean
|
||||
} {
|
||||
const queryClient = useQueryClient()
|
||||
@@ -75,11 +77,38 @@ export function useSessionActions(api: ApiClient | null, sessionId: string | nul
|
||||
onSuccess: () => void invalidateSession(),
|
||||
})
|
||||
|
||||
const renameMutation = useMutation({
|
||||
mutationFn: async (name: string) => {
|
||||
if (!api || !sessionId) {
|
||||
throw new Error('Session unavailable')
|
||||
}
|
||||
await api.renameSession(sessionId, name)
|
||||
},
|
||||
onSuccess: () => void invalidateSession(),
|
||||
})
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
if (!api || !sessionId) {
|
||||
throw new Error('Session unavailable')
|
||||
}
|
||||
await api.deleteSession(sessionId)
|
||||
},
|
||||
onSuccess: async () => {
|
||||
if (!sessionId) return
|
||||
queryClient.removeQueries({ queryKey: queryKeys.session(sessionId) })
|
||||
queryClient.removeQueries({ queryKey: queryKeys.messages(sessionId) })
|
||||
await queryClient.invalidateQueries({ queryKey: queryKeys.sessions })
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
abortSession: abortMutation.mutateAsync,
|
||||
switchSession: switchMutation.mutateAsync,
|
||||
setPermissionMode: permissionMutation.mutateAsync,
|
||||
setModelMode: modelMutation.mutateAsync,
|
||||
isPending: abortMutation.isPending || switchMutation.isPending || permissionMutation.isPending || modelMutation.isPending,
|
||||
renameSession: renameMutation.mutateAsync,
|
||||
deleteSession: deleteMutation.mutateAsync,
|
||||
isPending: abortMutation.isPending || switchMutation.isPending || permissionMutation.isPending || modelMutation.isPending || renameMutation.isPending || deleteMutation.isPending,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user