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
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Button } from "@superset/ui/button";
import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip";
import { cn } from "@superset/ui/utils";
import { useEffect, useRef, useState } from "react";
import { HiMiniXMark } from "react-icons/hi2";
import { StatusIndicator } from "renderer/screens/main/components/StatusIndicator";
import type { PaneStatus, Tab } from "renderer/stores/tabs/types";
Expand All @@ -12,6 +13,7 @@ interface GroupItemProps {
status: PaneStatus | null;
onSelect: () => void;
onClose: () => void;
onRename: (newName: string) => void;
}

export function GroupItem({
Expand All @@ -20,33 +22,90 @@ export function GroupItem({
status,
onSelect,
onClose,
onRename,
}: GroupItemProps) {
const displayName = getTabDisplayName(tab);
const [isEditing, setIsEditing] = useState(false);
const [editValue, setEditValue] = useState("");
const inputRef = useRef<HTMLInputElement>(null);
Comment on lines 27 to +30
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Sync editValue with displayName changes when not editing.

The editValue state is initialized once but won't update if the underlying tab prop changes (e.g., if another part of the app renames the tab, or the tab reference changes). When the user double-clicks to edit, they'll see a stale name.

🔎 Proposed fix to synchronize editValue with displayName
 	const displayName = getTabDisplayName(tab);
 	const [isEditing, setIsEditing] = useState(false);
 	const [editValue, setEditValue] = useState(displayName);
 	const inputRef = useRef<HTMLInputElement>(null);
+
+	// Sync editValue when displayName changes and we're not editing
+	useEffect(() => {
+		if (!isEditing) {
+			setEditValue(displayName);
+		}
+	}, [displayName, isEditing]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const displayName = getTabDisplayName(tab);
const [isEditing, setIsEditing] = useState(false);
const [editValue, setEditValue] = useState(displayName);
const inputRef = useRef<HTMLInputElement>(null);
const displayName = getTabDisplayName(tab);
const [isEditing, setIsEditing] = useState(false);
const [editValue, setEditValue] = useState(displayName);
const inputRef = useRef<HTMLInputElement>(null);
// Sync editValue when displayName changes and we're not editing
useEffect(() => {
if (!isEditing) {
setEditValue(displayName);
}
}, [displayName, isEditing]);
🤖 Prompt for AI Agents
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsx
around lines 27 - 30, The editValue state is initialized from
getTabDisplayName(tab) but never updates when the tab prop or displayName
changes; add a useEffect in GroupItem that watches displayName (and optionally
isEditing) and calls setEditValue(displayName) whenever displayName changes
while not editing, so editValue stays in sync with getTabDisplayName(tab) unless
the user is actively editing.


useEffect(() => {
if (isEditing && inputRef.current) {
inputRef.current.focus();
inputRef.current.select();
}
}, [isEditing]);

const startEditing = () => {
setEditValue(displayName);
setIsEditing(true);
};

const handleSave = () => {
const trimmedValue = editValue.trim();
if (trimmedValue && trimmedValue !== displayName) {
onRename(trimmedValue);
}
setIsEditing(false);
};

const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === "Enter") {
e.preventDefault();
handleSave();
} else if (e.key === "Escape") {
e.preventDefault();
setIsEditing(false);
}
};

const tabStyles = cn(
"flex items-center gap-2 transition-all w-full shrink-0 px-3 h-full",
isActive
? "text-foreground bg-border/30"
: "text-muted-foreground/70 hover:text-muted-foreground hover:bg-tertiary/20",
);

return (
<div className="group relative flex items-center shrink-0 h-full border-r border-border">
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
onClick={onSelect}
className={cn(
"flex items-center gap-2 transition-all w-full shrink-0 px-3 h-full",
isActive
? "text-foreground bg-border/30"
: "text-muted-foreground/70 hover:text-muted-foreground hover:bg-tertiary/20",
)}
>
<span className="text-sm whitespace-nowrap overflow-hidden flex-1 text-left">
{displayName}
{isEditing ? (
<div className={tabStyles}>
<input
ref={inputRef}
type="text"
value={editValue}
onChange={(e) => setEditValue(e.target.value)}
onBlur={handleSave}
onKeyDown={handleKeyDown}
maxLength={64}
className="text-sm bg-transparent border-none outline-none flex-1 text-left min-w-0"
/>
</div>
) : (
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
onClick={onSelect}
onDoubleClick={startEditing}
className={tabStyles}
>
<span className="text-sm whitespace-nowrap overflow-hidden flex-1 text-left">
{displayName}
</span>
{status && status !== "idle" && (
<StatusIndicator status={status} />
)}
</button>
</TooltipTrigger>
<TooltipContent side="bottom" sideOffset={4}>
<span>{displayName}</span>
<span className="text-muted-foreground ml-1.5">
Double-click to rename
</span>
{status && status !== "idle" && <StatusIndicator status={status} />}
</button>
</TooltipTrigger>
<TooltipContent side="bottom" sideOffset={4}>
{displayName}
</TooltipContent>
</Tooltip>
</TooltipContent>
</Tooltip>
)}
<Tooltip delayDuration={500}>
<TooltipTrigger asChild>
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ export function GroupStrip() {
removeTab(tabId);
};

const handleRenameGroup = (tabId: string, newName: string) => {
renameTab(tabId, newName);
};

return (
<div className="flex items-center h-10 flex-1 min-w-0">
{tabs.length > 0 && (
Expand All @@ -143,6 +147,7 @@ export function GroupStrip() {
status={tabStatusMap.get(tab.id) ?? null}
onSelect={() => handleSelectGroup(tab.id)}
onClose={() => handleCloseGroup(tab.id)}
onRename={(newName) => handleRenameGroup(tab.id, newName)}
/>
</div>
))}
Expand Down
Loading