import { useState } from "react"; import { useSshAuthProviders } from "@/hooks/useSshAuthProviders"; import { useTranslation } from "react-i18next"; import { ArrowUpDown, Check, ExternalLink, Filter, GripVertical, Plus, Search, SlidersHorizontal, X, } from "lucide-react"; import { toast } from "sonner"; import { CredentialList } from "@/sidebar/CredentialList"; import { requestManage } from "@/manage/manage-requests"; import { useCredentialSidebarPreferences } from "@/sidebar/credential-tree/hooks/useCredentialSidebarPreferences"; import { useArrangeLock } from "@/sidebar/use-arrange-lock"; import { CustomizeCredentialsSidebarPanel } from "@/sidebar/CustomizeCredentialsSidebarPanel"; import { Button } from "@/components/button"; import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/dropdown-menu"; import type { CredentialSortKey } from "@/types/credential-sidebar-preferences"; export function CredentialsPanel({ active: _active = true, }: { onEditingChange?: (editing: boolean) => void; active?: boolean; }) { const { t } = useTranslation(); const sshAuthProviders = useSshAuthProviders(); const { preferences: sidebarPrefs, update: updateSidebarPrefs } = useCredentialSidebarPreferences(); const [search, setSearch] = useState(""); const [allTags, setAllTags] = useState([]); const [customizePanelOpen, setCustomizePanelOpen] = useState(false); const sortKey = sidebarPrefs.sort.key; const { arrangeLocked, toggleArrangeLock } = useArrangeLock( "credentialSidebarArrangeLocked", ); const filterState = sidebarPrefs.filters; const filterActive = filterState.type.length > 0 || filterState.tags.length > 0; function handleSortChange(key: CredentialSortKey) { updateSidebarPrefs((prev) => ({ ...prev, sort: { ...prev.sort, key }, })); } function handleArrangeLockToggle() { const unlocking = arrangeLocked; toggleArrangeLock(); // Same reasoning as the hosts panel: reordering only sticks visually // under manual sort, so unlocking switches to it. if (unlocking && sortKey !== "manual") { handleSortChange("manual"); toast.info(t("credentials.arrangeUnlockedSwitchedToManual")); } } function handleFilterToggle( group: K, value: (typeof filterState)[K][number], ) { updateSidebarPrefs((prev) => { const arr = prev.filters[group] as string[]; const next = arr.includes(value as string) ? arr.filter((v) => v !== value) : [...arr, value as string]; return { ...prev, filters: { ...prev.filters, [group]: next }, }; }); } function handleFilterClear() { updateSidebarPrefs((prev) => ({ ...prev, filters: { type: [], tags: [] }, })); } return (
{
setSearch(e.target.value)} placeholder={t("credentials.searchCredentials")} className="flex-1 text-xs bg-transparent outline-none placeholder:text-muted-foreground/50 text-foreground min-w-0" /> {search && ( )}
handleSortChange("default")} className="flex items-center gap-1.5" > {sortKey === "default" ? ( ) : ( )} {t("credentials.sortDefault")} {(["name-asc", "name-desc"] as const).map((key) => ( handleSortChange(key)} className="flex items-center gap-1.5" > {sortKey === key ? ( ) : ( )} {t( `credentials.sort${key === "name-asc" ? "NameAsc" : "NameDesc"}`, )} ))} {(["username-asc", "username-desc"] as const).map((key) => ( handleSortChange(key)} className="flex items-center gap-1.5" > {sortKey === key ? ( ) : ( )} {t( `credentials.sort${key === "username-asc" ? "UsernameAsc" : "UsernameDesc"}`, )} ))} handleSortChange("manual")} className="flex items-center gap-1.5" > {sortKey === "manual" ? ( ) : ( )} {t("credentials.sortManual")} event.preventDefault()} > {t("credentials.arrangeUnlocked")}
{filterActive && ( <> {t("credentials.filterClearAll")} )} {t("credentials.filterTypeGroup")} {sshAuthProviders.providers .filter((option) => option.credentialType) .map((option) => ( handleFilterToggle("type", option.type) } onSelect={(e) => e.preventDefault()} > {t( `credentials.filterType${option.type.charAt(0).toUpperCase() + option.type.slice(1)}`, { defaultValue: t(option.labelKey) }, )} ))} {allTags.length > 0 && ( <> {t("credentials.filterTagsGroup")} {allTags.map((tag) => ( handleFilterToggle("tags", tag) } onSelect={(e) => e.preventDefault()} > {tag} ))} )}
}
); }