From 5f64372b94010e8e14b3d01177eb585cf0439b22 Mon Sep 17 00:00:00 2001 From: Andreas Weyer Date: Wed, 18 Feb 2026 11:19:58 +0000 Subject: [PATCH] Update profile selector, new rename functionality, display options in alphabetical order --- src/components/profile-selector.tsx | 112 ++++++++++++++++++++++++++-- src/components/settings.tsx | 8 +- src/locales/de.ts | 4 + src/locales/en.ts | 4 + 4 files changed, 116 insertions(+), 12 deletions(-) diff --git a/src/components/profile-selector.tsx b/src/components/profile-selector.tsx index ed4d771..f8c152c 100644 --- a/src/components/profile-selector.tsx +++ b/src/components/profile-selector.tsx @@ -21,7 +21,7 @@ import { SelectValue, } from './ui/select'; import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip'; -import { Save, Trash2, Plus } from 'lucide-react'; +import { Save, Trash2, Plus, Pencil } from 'lucide-react'; import { IconButtonWithTooltip } from './ui/icon-button-with-tooltip'; import { MAX_PROFILES, type ScheduleProfile } from '../constants/defaults'; @@ -32,6 +32,7 @@ interface ProfileSelectorProps { onSwitchProfile: (profileId: string) => void; onSaveProfile: () => void; onSaveProfileAs: (name: string) => string | null; + onRenameProfile: (profileId: string, newName: string) => void; onDeleteProfile: (profileId: string) => boolean; t: (key: string) => string; } @@ -43,20 +44,29 @@ export const ProfileSelector: React.FC = ({ onSwitchProfile, onSaveProfile, onSaveProfileAs, + onRenameProfile, onDeleteProfile, t, }) => { const [newProfileName, setNewProfileName] = useState(''); const [isSaveAsMode, setIsSaveAsMode] = useState(false); + const [isRenameMode, setIsRenameMode] = useState(false); + const [renameName, setRenameName] = useState(''); const activeProfile = profiles.find(p => p.id === activeProfileId); const canDelete = profiles.length > 1; const canCreateNew = profiles.length < MAX_PROFILES; + // Sort profiles alphabetically (case-insensitive) + const sortedProfiles = [...profiles].sort((a, b) => + a.name.toLowerCase().localeCompare(b.name.toLowerCase()) + ); + const handleSelectChange = (value: string) => { if (value === '__new__') { // Enter "save as" mode setIsSaveAsMode(true); + setIsRenameMode(false); setNewProfileName(''); } else { // Confirm before switching if there are unsaved changes @@ -67,6 +77,7 @@ export const ProfileSelector: React.FC = ({ } onSwitchProfile(value); setIsSaveAsMode(false); + setIsRenameMode(false); } }; @@ -114,6 +125,51 @@ export const ProfileSelector: React.FC = ({ } }; + const handleStartRename = () => { + if (activeProfile) { + setIsRenameMode(true); + setIsSaveAsMode(false); + setRenameName(activeProfile.name); + } + }; + + const handleRename = () => { + if (!renameName.trim() || !activeProfile) { + return; + } + + const trimmedName = renameName.trim(); + + // Check if name is unchanged + if (trimmedName === activeProfile.name) { + setIsRenameMode(false); + return; + } + + // Check for duplicate names (excluding current profile) + const isDuplicate = profiles.some( + p => p.id !== activeProfile.id && p.name.toLowerCase() === trimmedName.toLowerCase() + ); + + if (isDuplicate) { + alert(t('profileNameAlreadyExists') || 'A schedule with this name already exists'); + return; + } + + onRenameProfile(activeProfile.id, trimmedName); + setIsRenameMode(false); + setRenameName(''); + }; + + const handleRenameKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter') { + handleRename(); + } else if (e.key === 'Escape') { + setIsRenameMode(false); + setRenameName(''); + } + }; + return ( @@ -135,21 +191,32 @@ export const ProfileSelector: React.FC = ({ onKeyDown={handleKeyDown} placeholder={t('profileSaveAsPlaceholder')} autoFocus - className="h-9 rounded-r-none border-r-0 w-[360px] bg-background" + className="h-9 rounded-r-none border-r-0 w-[288px] bg-background" + /> + ) : isRenameMode ? ( + setRenameName(e.target.value)} + onKeyDown={handleRenameKeyDown} + placeholder={t('profileRenamePlaceholder')} + autoFocus + className="h-9 rounded-r-none border-r-0 w-[288px] bg-background" /> ) : (