From 136def6977631036736ad5419afef7063b975f9e Mon Sep 17 00:00:00 2001 From: Richard Solomou Date: Tue, 23 Jun 2026 15:50:03 +0300 Subject: [PATCH] feat(folder-picker): remove a folder from recents Add a hover-revealed remove button to each row in the Recent dropdown, gated behind a confirmation dialog since removeFolder also deletes the repo's tasks and worktrees. Generated-By: PostHog Code Task-Id: efb7b41b-2cde-40ff-8bd0-13fae0932ca1 --- .../features/folder-picker/FolderPicker.tsx | 85 ++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/features/folder-picker/FolderPicker.tsx b/packages/ui/src/features/folder-picker/FolderPicker.tsx index 5077715f81..6c802ee07e 100644 --- a/packages/ui/src/features/folder-picker/FolderPicker.tsx +++ b/packages/ui/src/features/folder-picker/FolderPicker.tsx @@ -4,11 +4,19 @@ import { Folder as FolderIcon, FolderOpen, GitBranch, + X, } from "@phosphor-icons/react"; import { ROOT_LOGGER, type RootLogger } from "@posthog/di/logger"; import { useService } from "@posthog/di/react"; import { useHostTRPCClient } from "@posthog/host-router/react"; import { + AlertDialog, + AlertDialogClose, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, Button, DropdownMenu, DropdownMenuContent, @@ -21,6 +29,7 @@ import { useFolders } from "@posthog/ui/features/folders/useFolders"; import { FIELD_TRIGGER_CLASS } from "@posthog/ui/styles/fieldTrigger"; import { Flex, Text } from "@radix-ui/themes"; import { type RefObject, useState } from "react"; +import { toast } from "sonner"; interface FolderPickerProps { value: string; @@ -43,6 +52,7 @@ export function FolderPicker({ getRecentFolders, getFolderDisplayName, addFolder, + removeFolder, updateLastAccessed, getFolderByPath, } = useFolders(); @@ -52,6 +62,13 @@ export function FolderPicker({ const isField = variant === "field"; const [isOpening, setIsOpening] = useState(false); + const [menuOpen, setMenuOpen] = useState(false); + const [pendingRemoval, setPendingRemoval] = useState<{ + id: string; + name: string; + path: string; + } | null>(null); + const [isRemoving, setIsRemoving] = useState(false); const handleSelect = (path: string) => { onChange(path); @@ -59,6 +76,23 @@ export function FolderPicker({ if (folder) updateLastAccessed(folder.id); }; + const handleConfirmRemoval = async () => { + if (!pendingRemoval) return; + setIsRemoving(true); + try { + await removeFolder(pendingRemoval.id); + if (pendingRemoval.path === value) onChange(""); + setPendingRemoval(null); + } catch (error) { + log.error("Failed to remove folder", { error }); + toast.error("Couldn't remove folder", { + description: error instanceof Error ? error.message : String(error), + }); + } finally { + setIsRemoving(false); + } + }; + const handleOpenFilePicker = async () => { if (isOpening) return; setIsOpening(true); @@ -136,7 +170,7 @@ export function FolderPicker({ } return ( - + handleSelect(folder.path)} + className="group" > {folder.name} + ))} @@ -182,6 +235,36 @@ export function FolderPicker({ Open folder... + + { + if (!open && !isRemoving) setPendingRemoval(null); + }} + > + + + Remove folder + + "{pendingRemoval?.name}" will be removed from PostHog Code, + including all of its tasks and their workspaces. This can't be + undone. + + + + Cancel} + /> + + + + ); }