From 4b16341401a20b6d15cebcb244d1f927894f1097 Mon Sep 17 00:00:00 2001 From: zhom <2717306+zhom@users.noreply.github.com> Date: Thu, 14 Aug 2025 22:35:44 +0400 Subject: [PATCH] refactor: integrage rename of profile into row --- src/components/profile-data-table.tsx | 211 ++++++++++++++++---------- 1 file changed, 131 insertions(+), 80 deletions(-) diff --git a/src/components/profile-data-table.tsx b/src/components/profile-data-table.tsx index f14c496..3b0880e 100644 --- a/src/components/profile-data-table.tsx +++ b/src/components/profile-data-table.tsx @@ -25,13 +25,6 @@ import { CommandItem, CommandList, } from "@/components/ui/command"; -import { - Dialog, - DialogContent, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; import { DropdownMenu, DropdownMenuContent, @@ -67,8 +60,9 @@ import { import { trimName } from "@/lib/name-utils"; import { cn } from "@/lib/utils"; import type { BrowserProfile, StoredProxy } from "@/types"; +import { LoadingButton } from "./loading-button"; import { Input } from "./ui/input"; -import { Label } from "./ui/label"; +// Label no longer needed after removing dialog-based renaming import { RippleButton } from "./ui/ripple"; interface ProfilesDataTableProps { @@ -107,6 +101,8 @@ export function ProfilesDataTable({ React.useState(null); const [newProfileName, setNewProfileName] = React.useState(""); const [renameError, setRenameError] = React.useState(null); + const [isRenamingSaving, setIsRenamingSaving] = React.useState(false); + const renameContainerRef = React.useRef(null); const [profileToDelete, setProfileToDelete] = React.useState(null); const [isDeleting, setIsDeleting] = React.useState(false); @@ -265,10 +261,11 @@ export function ProfilesDataTable({ [browserState.isClient, sorting, updateSorting], ); - const handleRename = async () => { + const handleRename = React.useCallback(async () => { if (!profileToRename || !newProfileName.trim()) return; try { + setIsRenamingSaving(true); await onRenameProfile(profileToRename.name, newProfileName.trim()); setProfileToRename(null); setNewProfileName(""); @@ -277,8 +274,31 @@ export function ProfilesDataTable({ setRenameError( error instanceof Error ? error.message : "Failed to rename profile", ); + } finally { + setIsRenamingSaving(false); } - }; + }, [profileToRename, newProfileName, onRenameProfile]); + + // Cancel inline rename on outside click + React.useEffect(() => { + if (!profileToRename) return; + const handleClickOutside = (event: MouseEvent) => { + const target = event.target as Node | null; + if ( + target && + renameContainerRef.current && + !renameContainerRef.current.contains(target) + ) { + setProfileToRename(null); + setNewProfileName(""); + setRenameError(null); + } + }; + document.addEventListener("mousedown", handleClickOutside); + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, [profileToRename]); const handleDelete = async () => { if (!profileToDelete) return; @@ -622,20 +642,103 @@ export function ProfilesDataTable({ enableSorting: true, sortingFn: "alphanumeric", cell: ({ row }) => { + const profile = row.original as BrowserProfile; const rawName: string = row.getValue("name"); const name = getBrowserDisplayName(rawName); + const isEditing = profileToRename?.name === profile.name; - if (name.length < 20) { - return
{name}
; + if (isEditing) { + const isSaveDisabled = + isRenamingSaving || + newProfileName.trim().length === 0 || + newProfileName.trim() === profile.name; + + return ( +
+ { + setNewProfileName(e.target.value); + if (renameError) setRenameError(null); + }} + onKeyDown={(e) => { + if (e.key === "Enter") { + void handleRename(); + } else if (e.key === "Escape") { + setProfileToRename(null); + setNewProfileName(""); + setRenameError(null); + } + }} + className="inline-block w-full" + /> +
+ void handleRename()} + > + Save + +
+
+ ); } + const display = + name.length < 20 ? ( +
{name}
+ ) : ( + + + {trimName(name, 20)} + + {name} + + ); + + const isRunning = + browserState.isClient && runningProfiles.has(profile.name); + const isLaunching = launchingProfiles.has(profile.name); + const isStopping = stoppingProfiles.has(profile.name); + const isBrowserUpdating = isUpdating(profile.browser); + const isDisabled = + isRunning || isLaunching || isStopping || isBrowserUpdating; + return ( - - - {trimName(name, 20)} - - {name} - + ); }, }, @@ -750,7 +853,7 @@ export function ProfilesDataTable({ )} - { - setProfileToRename(profile); - setNewProfileName(profile.name); - }} - disabled={isDisabled} - > - Rename - + {/* Rename removed from menu; inline on name click */} { setProfileToDelete(profile); @@ -917,6 +1012,11 @@ export function ProfilesDataTable({ openProxySelectorFor, proxyOverrides, handleProxySelection, + profileToRename, + newProfileName, + renameError, + isRenamingSaving, + handleRename, ], ); @@ -944,7 +1044,7 @@ export function ProfilesDataTable({ {table.getHeaderGroups().map((headerGroup) => ( - + {headerGroup.headers.map((header) => { return ( @@ -966,10 +1066,10 @@ export function ProfilesDataTable({ {row.getVisibleCells().map((cell) => ( - + {flexRender( cell.column.columnDef.cell, cell.getContext(), @@ -991,55 +1091,6 @@ export function ProfilesDataTable({
- - { - if (!open) { - setProfileToRename(null); - setNewProfileName(""); - setRenameError(null); - } - }} - > - - - Rename Profile - -
-
- - { - setNewProfileName(e.target.value); - }} - className="col-span-3" - /> -
- {renameError && ( -

{renameError}

- )} -
- - { - setProfileToRename(null); - }} - > - Cancel - - void handleRename()}> - Save - - -
-
- setProfileToDelete(null)}