Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 50 additions & 3 deletions web-app/src/containers/LeftPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link, useRouterState } from '@tanstack/react-router'
import { Link, useRouterState, useNavigate } from '@tanstack/react-router'
import { useLeftPanel } from '@/hooks/useLeftPanel'
import { cn } from '@/lib/utils'
import {
Expand Down Expand Up @@ -58,6 +58,9 @@
route: route.project,
isEnabled: true,
},
]

const secondaryMenus = [
{
title: 'common:assistants',
icon: IconClipboardSmile,
Expand All @@ -82,6 +85,7 @@
const open = useLeftPanel((state) => state.open)
const setLeftPanel = useLeftPanel((state) => state.setLeftPanel)
const { t } = useTranslation()
const navigate = useNavigate()
const [searchTerm, setSearchTerm] = useState('')
const { isAuthenticated } = useAuth()

Expand All @@ -98,10 +102,10 @@
// Use click outside hook for panel with debugging
useClickOutside(
() => {
if (isSmallScreen && open) {
setLeftPanel(false)
}
},

Check warning on line 108 in web-app/src/containers/LeftPanel.tsx

View workflow job for this annotation

GitHub Actions / coverage-check

105-108 lines are not covered with tests
null,
[
panelRef.current,
Expand All @@ -113,28 +117,28 @@
// Auto-collapse panel only when window is resized
useEffect(() => {
const handleResize = () => {
const currentIsSmallScreen = window.innerWidth <= 768

Check warning on line 120 in web-app/src/containers/LeftPanel.tsx

View workflow job for this annotation

GitHub Actions / coverage-check

120 line is not covered with tests

// Skip on initial mount
if (isInitialMountRef.current) {
isInitialMountRef.current = false
prevScreenSizeRef.current = currentIsSmallScreen
return
}

Check warning on line 127 in web-app/src/containers/LeftPanel.tsx

View workflow job for this annotation

GitHub Actions / coverage-check

123-127 lines are not covered with tests

// Only trigger if the screen size actually changed
if (
prevScreenSizeRef.current !== null &&
prevScreenSizeRef.current !== currentIsSmallScreen
) {
if (currentIsSmallScreen && open) {
setLeftPanel(false)
} else if (!open) {
setLeftPanel(true)
}
prevScreenSizeRef.current = currentIsSmallScreen
}
}

Check warning on line 141 in web-app/src/containers/LeftPanel.tsx

View workflow job for this annotation

GitHub Actions / coverage-check

130-141 lines are not covered with tests

// Add resize listener
window.addEventListener('resize', handleResize)
Expand Down Expand Up @@ -180,9 +184,9 @@

const filteredProjects = useMemo(() => {
if (!searchTerm) return folders
return folders.filter((folder) =>
folder.name.toLowerCase().includes(searchTerm.toLowerCase())
)

Check warning on line 189 in web-app/src/containers/LeftPanel.tsx

View workflow job for this annotation

GitHub Actions / coverage-check

187-189 lines are not covered with tests
}, [folders, searchTerm])

// Memoize categorized threads based on filteredThreads
Expand All @@ -196,32 +200,37 @@

// Project handlers
const handleProjectDelete = (id: string) => {
setDeletingProjectId(id)
setDeleteProjectConfirmOpen(true)
}

Check warning on line 205 in web-app/src/containers/LeftPanel.tsx

View workflow job for this annotation

GitHub Actions / coverage-check

203-205 lines are not covered with tests

const confirmProjectDelete = () => {
if (deletingProjectId) {
deleteFolder(deletingProjectId)
setDeleteProjectConfirmOpen(false)
setDeletingProjectId(null)
}
}

Check warning on line 213 in web-app/src/containers/LeftPanel.tsx

View workflow job for this annotation

GitHub Actions / coverage-check

208-213 lines are not covered with tests

const handleProjectSave = (name: string) => {
if (editingProjectKey) {
updateFolder(editingProjectKey, name)
} else {
addFolder(name)
const newProject = addFolder(name)

Check warning on line 219 in web-app/src/containers/LeftPanel.tsx

View workflow job for this annotation

GitHub Actions / coverage-check

216-219 lines are not covered with tests
// Navigate to the newly created project
navigate({
to: '/project/$projectId',
params: { projectId: newProject.id },
})
}
setProjectDialogOpen(false)
setEditingProjectKey(null)
}

Check warning on line 228 in web-app/src/containers/LeftPanel.tsx

View workflow job for this annotation

GitHub Actions / coverage-check

221-228 lines are not covered with tests

// Disable body scroll when panel is open on small screens
useEffect(() => {
if (isSmallScreen && open) {
document.body.style.overflow = 'hidden'

Check warning on line 233 in web-app/src/containers/LeftPanel.tsx

View workflow job for this annotation

GitHub Actions / coverage-check

233 line is not covered with tests
} else {
document.body.style.overflow = ''
}
Expand Down Expand Up @@ -487,7 +496,7 @@
)}

<div className="flex flex-col h-full overflow-y-scroll w-[calc(100%+6px)]">
<div className="flex flex-col w-full h-full overflow-y-auto overflow-x-hidden">
<div className="flex flex-col w-full h-full overflow-y-auto overflow-x-hidden mb-3">
<div className="h-full w-full overflow-y-auto">
{favoritedThreads.length > 0 && (
<>
Expand Down Expand Up @@ -607,6 +616,44 @@
</div>
</div>
</div>

{secondaryMenus.map((menu) => {
if (!menu.isEnabled) {
return null
}

// Regular menu items must have route and icon
if (!menu.route || !menu.icon) return null

const isActive = (() => {
// Settings routes
if (menu.route.includes(route.settings.index)) {
return currentPath.includes(route.settings.index)
}

// Default exact match for other routes
return currentPath === menu.route
})()
return (
<Link
key={menu.title}
to={menu.route}
onClick={() => isSmallScreen && setLeftPanel(false)}
data-test-id={`menu-${menu.title}`}
activeOptions={{ exact: true }}
className={cn(
'flex items-center gap-1.5 cursor-pointer hover:bg-left-panel-fg/10 py-1 px-1 rounded',
isActive && 'bg-left-panel-fg/10'
)}
>
<menu.icon size={18} className="text-left-panel-fg/70" />
<span className="font-medium text-left-panel-fg/90">
{t(menu.title)}
</span>
</Link>
)
})}

{PlatformFeatures[PlatformFeature.AUTHENTICATION] && (
<div className="space-y-1 shrink-0 py-1">
<div>
Expand Down
5 changes: 4 additions & 1 deletion web-app/src/containers/ThreadList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,10 @@ const SortableItem = memo(
<DropdownMenuTrigger asChild>
<IconDots
size={14}
className="text-left-panel-fg/60 shrink-0 cursor-pointer px-0.5 -mr-1 data-[state=open]:bg-left-panel-fg/10 rounded group-hover/thread-list:data-[state=closed]:size-5 size-5 data-[state=closed]:size-0"
className={cn(
'text-left-panel-fg/60 shrink-0 cursor-pointer px-0.5 -mr-1 data-[state=open]:bg-left-panel-fg/10 rounded group-hover/thread-list:data-[state=closed]:size-5 size-5 data-[state=closed]:size-0',
variant === 'project' && 'text-main-view-fg/60'
)}
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
Expand Down
3 changes: 2 additions & 1 deletion web-app/src/hooks/useThreadManagement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type ThreadFolder = {
type ThreadManagementState = {
folders: ThreadFolder[]
setFolders: (folders: ThreadFolder[]) => void
addFolder: (name: string) => void
addFolder: (name: string) => ThreadFolder
updateFolder: (id: string, name: string) => void
deleteFolder: (id: string) => void
getFolderById: (id: string) => ThreadFolder | undefined
Expand All @@ -37,6 +37,7 @@ export const useThreadManagement = create<ThreadManagementState>()(
set((state) => ({
folders: [...state.folders, newFolder],
}))
return newFolder
},

updateFolder: (id, name) => {
Expand Down
10 changes: 8 additions & 2 deletions web-app/src/routes/project/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createFileRoute } from '@tanstack/react-router'
import { createFileRoute, useNavigate } from '@tanstack/react-router'
import { useState, useMemo } from 'react'

import { useThreadManagement } from '@/hooks/useThreadManagement'
Expand Down Expand Up @@ -31,6 +31,7 @@ function Project() {

function ProjectContent() {
const { t } = useTranslation()
const navigate = useNavigate()
const { folders, addFolder, updateFolder, deleteFolder, getFolderById } =
useThreadManagement()
const threads = useThreads((state) => state.threads)
Expand Down Expand Up @@ -59,7 +60,12 @@ function ProjectContent() {
if (editingKey) {
updateFolder(editingKey, name)
} else {
addFolder(name)
const newProject = addFolder(name)
// Navigate to the newly created project
navigate({
to: '/project/$projectId',
params: { projectId: newProject.id },
})
}
setOpen(false)
setEditingKey(null)
Expand Down
Loading