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
47 changes: 47 additions & 0 deletions src/browser/components/WorkspaceHoverPreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from "react";
import { cn } from "@/common/lib/utils";
import { RuntimeBadge } from "./RuntimeBadge";
import { BranchSelector } from "./BranchSelector";
import { WorkspaceLinks } from "./WorkspaceLinks";
import type { RuntimeConfig } from "@/common/types/runtime";

interface WorkspaceHoverPreviewProps {
workspaceId: string;
projectName: string;
workspaceName: string;
namedWorkspacePath: string;
runtimeConfig?: RuntimeConfig;
isWorking: boolean;
className?: string;
}

/**
* Dense workspace info preview for hover cards.
* Shows runtime badge, project name, branch selector, git status, and PR link.
*/
export function WorkspaceHoverPreview({
workspaceId,
projectName,
workspaceName,
namedWorkspacePath,
runtimeConfig,
isWorking,
className,
}: WorkspaceHoverPreviewProps) {
return (
<div className={cn("flex min-w-0 items-center gap-2 text-[11px]", className)}>
<RuntimeBadge
runtimeConfig={runtimeConfig}
isWorking={isWorking}
workspacePath={namedWorkspacePath}
workspaceName={workspaceName}
tooltipSide="bottom"
/>
<span className="min-w-0 truncate font-mono text-[11px]">{projectName}</span>
<div className="flex items-center gap-1">
<BranchSelector workspaceId={workspaceId} workspaceName={workspaceName} />
<WorkspaceLinks workspaceId={workspaceId} />
</div>
</div>
);
}
25 changes: 11 additions & 14 deletions src/browser/components/WorkspaceListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import React, { useState, useEffect } from "react";
import { useDrag } from "react-dnd";
import { getEmptyImage } from "react-dnd-html5-backend";
import { GitStatusIndicator } from "./GitStatusIndicator";
import { RuntimeBadge } from "./RuntimeBadge";

import { WorkspaceHoverPreview } from "./WorkspaceHoverPreview";
import { Tooltip, TooltipTrigger, TooltipContent } from "./ui/tooltip";
import { HoverCard, HoverCardTrigger, HoverCardContent } from "./ui/hover-card";
import { Trash2 } from "lucide-react";
Expand Down Expand Up @@ -442,25 +443,21 @@ function RegularWorkspaceListItemInner(props: WorkspaceListItemProps) {
</span>
</HoverCardTrigger>
<HoverCardContent
// Keep the workspace title hover card on the right to avoid covering the list.
side="right"
align="start"
sideOffset={0}
sideOffset={8}
className="border-separator-light bg-modal-bg w-auto max-w-[420px] px-[10px] py-[6px] text-[11px] shadow-[0_2px_8px_rgba(0,0,0,0.4)]"
onPointerDownOutside={preventHoverCardDismissForRadixPortals}
onFocusOutside={preventHoverCardDismissForRadixPortals}
>
<div className="flex flex-col gap-1">
<div className="flex items-center gap-2">
<RuntimeBadge
runtimeConfig={metadata.runtimeConfig}
workspaceName={metadata.name}
workspacePath={namedWorkspacePath}
/>
<span className="text-foreground font-medium break-words whitespace-normal">
{displayTitle}
</span>
</div>
<WorkspaceHoverPreview
workspaceId={workspaceId}
projectName={projectName}
workspaceName={metadata.name}
namedWorkspacePath={namedWorkspacePath}
runtimeConfig={metadata.runtimeConfig}
isWorking={isWorking}
/>
{!isDisabled && (
<div className="text-muted text-xs">Double-click to edit title</div>
)}
Expand Down
4 changes: 2 additions & 2 deletions src/browser/stories/App.sidebar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -570,8 +570,8 @@ export const WorkspaceTitleHoverCard: AppStory = {
"[data-radix-popper-content-wrapper] .bg-modal-bg"
);
if (!hoverCard) throw new Error("HoverCard not visible");
// Verify it contains the runtime badge and title
within(hoverCard).getByText("Implement new feature with detailed description");
// Verify it contains the project name (WorkspaceHoverPreview content)
within(hoverCard).getByText("hover-demo");
},
{ timeout: 5000 }
);
Expand Down
Loading