From 33b41ef5d5ef0cfa67eb5e0a35537b9b21e0f44a Mon Sep 17 00:00:00 2001 From: iliya Date: Tue, 24 Feb 2026 16:10:15 +0200 Subject: [PATCH] feat: enhance folder navigation and team section UI - Implemented synthetic group creation for new folders in `DashboardView`, allowing navigation to projects without existing sessions. - Added `headerExtra` prop to `CollapsibleTeamSection` for inline elements, improving UI flexibility. - Updated `TeamDetailView` to include a notification button for the `claude-notifications-go` plugin, enhancing user experience with desktop notifications. --- .../components/dashboard/DashboardView.tsx | 34 ++++++++++++++++--- .../team/CollapsibleTeamSection.tsx | 4 +++ .../components/team/TeamDetailView.tsx | 20 +++++++++++ 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/renderer/components/dashboard/DashboardView.tsx b/src/renderer/components/dashboard/DashboardView.tsx index 56e8a1fc..d7bbef64 100644 --- a/src/renderer/components/dashboard/DashboardView.tsx +++ b/src/renderer/components/dashboard/DashboardView.tsx @@ -315,11 +315,35 @@ const NewProjectCard = (): React.JSX.Element => { return; } - // Still no match — open the folder in file manager as fallback - const result = await api.openPath(selectedPath, undefined, true); - if (!result.success) { - logger.error('Failed to open folder:', result.error); - } + // Still no match — create a synthetic group for this new folder and navigate to it. + // This allows launching teams in projects that don't have Claude sessions yet. + const encodedId = selectedPath.replace(/[/\\]/g, '-'); + const folderName = selectedPath.split('/').filter(Boolean).pop() ?? selectedPath; + const now = Date.now(); + + const syntheticGroup: RepositoryGroup = { + id: encodedId, + identity: null, + worktrees: [ + { + id: encodedId, + path: selectedPath, + name: folderName, + isMainWorktree: true, + source: 'unknown', + sessions: [], + createdAt: now, + }, + ], + name: folderName, + mostRecentSession: undefined, + totalSessions: 0, + }; + + useStore.setState((state) => ({ + repositoryGroups: [syntheticGroup, ...state.repositoryGroups], + })); + navigateToMatch({ repoId: encodedId, worktreeId: encodedId }); } catch (error) { logger.error('Error selecting folder:', error); } diff --git a/src/renderer/components/team/CollapsibleTeamSection.tsx b/src/renderer/components/team/CollapsibleTeamSection.tsx index ded3ec17..eb8595e9 100644 --- a/src/renderer/components/team/CollapsibleTeamSection.tsx +++ b/src/renderer/components/team/CollapsibleTeamSection.tsx @@ -8,6 +8,8 @@ interface CollapsibleTeamSectionProps { badge?: string | number; /** Secondary badge (e.g. unread count). Shown next to main badge when defined. */ secondaryBadge?: number; + /** Extra element rendered inline after badges (e.g. notification icon). */ + headerExtra?: React.ReactNode; defaultOpen?: boolean; forceOpen?: boolean; action?: React.ReactNode; @@ -18,6 +20,7 @@ export const CollapsibleTeamSection = ({ title, badge, secondaryBadge, + headerExtra, defaultOpen = true, forceOpen, action, @@ -58,6 +61,7 @@ export const CollapsibleTeamSection = ({ {secondaryBadge} new )} + {headerExtra} {action &&
{action}
} diff --git a/src/renderer/components/team/TeamDetailView.tsx b/src/renderer/components/team/TeamDetailView.tsx index b57908cb..fc1f7b05 100644 --- a/src/renderer/components/team/TeamDetailView.tsx +++ b/src/renderer/components/team/TeamDetailView.tsx @@ -18,6 +18,7 @@ import { useStore } from '@renderer/store'; import { buildTaskCountsByOwner } from '@renderer/utils/pathNormalize'; import { toMessageKey } from '@renderer/utils/teamMessageKey'; import { + Bell, CheckCheck, GitBranch, Pencil, @@ -832,6 +833,25 @@ export const TeamDetailView = ({ teamName }: TeamDetailViewProps): React.JSX.Ele secondaryBadge={ filteredMessages.length > 0 && messagesUnreadCount > 0 ? messagesUnreadCount : undefined } + headerExtra={ + + + + + Desktop notifications plugin + + } defaultOpen action={