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.
This commit is contained in:
parent
a30f8ab879
commit
33b41ef5d5
3 changed files with 53 additions and 5 deletions
|
|
@ -315,11 +315,35 @@ const NewProjectCard = (): React.JSX.Element => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Still no match — open the folder in file manager as fallback
|
// Still no match — create a synthetic group for this new folder and navigate to it.
|
||||||
const result = await api.openPath(selectedPath, undefined, true);
|
// This allows launching teams in projects that don't have Claude sessions yet.
|
||||||
if (!result.success) {
|
const encodedId = selectedPath.replace(/[/\\]/g, '-');
|
||||||
logger.error('Failed to open folder:', result.error);
|
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) {
|
} catch (error) {
|
||||||
logger.error('Error selecting folder:', error);
|
logger.error('Error selecting folder:', error);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ interface CollapsibleTeamSectionProps {
|
||||||
badge?: string | number;
|
badge?: string | number;
|
||||||
/** Secondary badge (e.g. unread count). Shown next to main badge when defined. */
|
/** Secondary badge (e.g. unread count). Shown next to main badge when defined. */
|
||||||
secondaryBadge?: number;
|
secondaryBadge?: number;
|
||||||
|
/** Extra element rendered inline after badges (e.g. notification icon). */
|
||||||
|
headerExtra?: React.ReactNode;
|
||||||
defaultOpen?: boolean;
|
defaultOpen?: boolean;
|
||||||
forceOpen?: boolean;
|
forceOpen?: boolean;
|
||||||
action?: React.ReactNode;
|
action?: React.ReactNode;
|
||||||
|
|
@ -18,6 +20,7 @@ export const CollapsibleTeamSection = ({
|
||||||
title,
|
title,
|
||||||
badge,
|
badge,
|
||||||
secondaryBadge,
|
secondaryBadge,
|
||||||
|
headerExtra,
|
||||||
defaultOpen = true,
|
defaultOpen = true,
|
||||||
forceOpen,
|
forceOpen,
|
||||||
action,
|
action,
|
||||||
|
|
@ -58,6 +61,7 @@ export const CollapsibleTeamSection = ({
|
||||||
{secondaryBadge} new
|
{secondaryBadge} new
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
|
{headerExtra}
|
||||||
</div>
|
</div>
|
||||||
{action && <div className="relative z-10 flex shrink-0 items-center">{action}</div>}
|
{action && <div className="relative z-10 flex shrink-0 items-center">{action}</div>}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import { useStore } from '@renderer/store';
|
||||||
import { buildTaskCountsByOwner } from '@renderer/utils/pathNormalize';
|
import { buildTaskCountsByOwner } from '@renderer/utils/pathNormalize';
|
||||||
import { toMessageKey } from '@renderer/utils/teamMessageKey';
|
import { toMessageKey } from '@renderer/utils/teamMessageKey';
|
||||||
import {
|
import {
|
||||||
|
Bell,
|
||||||
CheckCheck,
|
CheckCheck,
|
||||||
GitBranch,
|
GitBranch,
|
||||||
Pencil,
|
Pencil,
|
||||||
|
|
@ -832,6 +833,25 @@ export const TeamDetailView = ({ teamName }: TeamDetailViewProps): React.JSX.Ele
|
||||||
secondaryBadge={
|
secondaryBadge={
|
||||||
filteredMessages.length > 0 && messagesUnreadCount > 0 ? messagesUnreadCount : undefined
|
filteredMessages.length > 0 && messagesUnreadCount > 0 ? messagesUnreadCount : undefined
|
||||||
}
|
}
|
||||||
|
headerExtra={
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="pointer-events-auto rounded p-0.5 text-[var(--color-text-muted)] transition-colors hover:text-[var(--color-text-secondary)]"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
void window.electronAPI.openExternal(
|
||||||
|
'https://github.com/777genius/claude-notifications-go'
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Bell size={12} />
|
||||||
|
</button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="top">Desktop notifications plugin</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
defaultOpen
|
defaultOpen
|
||||||
action={
|
action={
|
||||||
<div className="flex items-center gap-2 pl-2">
|
<div className="flex items-center gap-2 pl-2">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue