From 5ddd521a4081a768dfab4e259cadcd8c3b576ffa Mon Sep 17 00:00:00 2001 From: Shambhavi Shinde <156112383+shmbhvi101@users.noreply.github.com> Date: Fri, 22 May 2026 17:06:46 +0530 Subject: [PATCH 1/3] Added debounced server-side GitHub repository search to the Pot Sources --- .../pots/components/PotSourcesPanel.tsx | 257 ++++++++++++------ 1 file changed, 177 insertions(+), 80 deletions(-) diff --git a/app/(main)/pots/components/PotSourcesPanel.tsx b/app/(main)/pots/components/PotSourcesPanel.tsx index 5a222771..9a39d626 100644 --- a/app/(main)/pots/components/PotSourcesPanel.tsx +++ b/app/(main)/pots/components/PotSourcesPanel.tsx @@ -1,9 +1,11 @@ "use client"; -import React, { useCallback, useEffect, useMemo, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import Link from "next/link"; import { + FolderOpen, GitBranch, + Loader2, Pause, Play, Plus, @@ -11,6 +13,7 @@ import { Search, Trash2, Users, + X, } from "lucide-react"; function GithubIcon({ className }: { className?: string }) { @@ -104,6 +107,8 @@ const SOURCE_TYPES: SourceTypeOption[] = [ }, ]; +const GITHUB_REPO_PAGE_SIZE = 20; + function extractRepoIdentity(repo: GithubRepo): { owner: string; repo: string; @@ -199,6 +204,8 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged } const [githubHasMore, setGithubHasMore] = useState(false); const [githubOffset, setGithubOffset] = useState(0); const [githubSearch, setGithubSearch] = useState(""); + const githubSearchDebounceRef = useRef(null); + const githubRequestIdRef = useRef(0); const [attachingRepoKey, setAttachingRepoKey] = useState(null); // Linear picker state @@ -265,11 +272,29 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged } // ---- Picker open/close + per-type bootstrapping -------------------- + const clearGithubSearchDebounce = () => { + if (githubSearchDebounceRef.current) { + clearTimeout(githubSearchDebounceRef.current); + githubSearchDebounceRef.current = null; + } + }; + + const resetGithubPicker = () => { + clearGithubSearchDebounce(); + githubRequestIdRef.current += 1; + setGithubSearch(""); + setGithubRepos([]); + setGithubOffset(0); + setGithubHasMore(false); + setGithubLoading(false); + }; + const openPicker = (typeId: SourceTypeId) => { setPickerType(typeId); setPickerOpen(true); if (typeId === "github_repository") { - void loadGithubPage(true); + resetGithubPicker(); + void loadGithubPage(true, ""); } else if (typeId === "linear_team") { // Auto-select the only Linear integration if there's exactly one. const id = @@ -285,35 +310,78 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged } const closePicker = () => { setPickerOpen(false); setPickerType(null); - setGithubSearch(""); - setGithubRepos([]); - setGithubOffset(0); - setGithubHasMore(false); + resetGithubPicker(); setLinearTeams([]); setLinearIntegrationId(null); }; + const backToTypePicker = () => { + if (pickerType === "github_repository") { + resetGithubPicker(); + } + setPickerType(null); + }; + + useEffect(() => { + return () => { + if (githubSearchDebounceRef.current) { + clearTimeout(githubSearchDebounceRef.current); + } + githubRequestIdRef.current += 1; + }; + }, []); + // ---- GitHub picker ------------------------------------------------- - const loadGithubPage = async (reset: boolean) => { + const loadGithubPage = async (reset: boolean, searchTerm = githubSearch) => { + const requestId = githubRequestIdRef.current + 1; + githubRequestIdRef.current = requestId; + const trimmedSearch = searchTerm.trim().slice(0, 200); setGithubLoading(true); try { const offset = reset ? 0 : githubOffset; const page = await BranchAndRepositoryService.searchUserRepositories({ - search: githubSearch, - limit: 20, + search: trimmedSearch, + limit: GITHUB_REPO_PAGE_SIZE, offset, }); + if (githubRequestIdRef.current !== requestId) return; setGithubRepos((prev) => (reset ? page.repositories : [...prev, ...page.repositories])); setGithubHasMore(page.has_next_page); setGithubOffset(offset + page.repositories.length); } catch { - toast.error("Failed to fetch GitHub repositories"); + if (githubRequestIdRef.current === requestId) { + toast.error("Failed to fetch GitHub repositories"); + } } finally { - setGithubLoading(false); + if (githubRequestIdRef.current === requestId) { + setGithubLoading(false); + } } }; + const searchGithubRepos = (value: string) => { + if (value.length > 200) return; + setGithubSearch(value); + clearGithubSearchDebounce(); + githubRequestIdRef.current += 1; + setGithubLoading(true); + githubSearchDebounceRef.current = setTimeout(() => { + void loadGithubPage(true, value.trim()); + }, 350); + }; + + const searchGithubReposNow = () => { + clearGithubSearchDebounce(); + void loadGithubPage(true, githubSearch.trim()); + }; + + const clearGithubSearch = () => { + clearGithubSearchDebounce(); + setGithubSearch(""); + void loadGithubPage(true, ""); + }; + const handleAttachGithub = async (repo: GithubRepo) => { const identity = extractRepoIdentity(repo); if (!identity) { @@ -628,76 +696,105 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged } ) : pickerType === "github_repository" ? (
-
- - setGithubSearch(e.target.value)} - onKeyDown={(e) => { - if (e.key === "Enter") void loadGithubPage(true); - }} - /> - -
-
- {githubRepos.length === 0 && !githubLoading ? ( -

- No matching repositories. -

- ) : ( - githubRepos.map((repo, idx) => { - const identity = extractRepoIdentity(repo); - if (!identity) return null; - const key = `${identity.owner}/${identity.repo}`; - const alreadyAttached = attachedScopeKeys.has(`gh:${key.toLowerCase()}`); - return ( -
-
-

{key}

- {identity.default_branch ? ( -

- default: {identity.default_branch} -

- ) : null} -
- -
- ); - }) - )} - {githubLoading ? ( -

Loading…

+
+
+ + searchGithubRepos(e.target.value)} + onKeyDown={(e) => { + if (e.key === "Enter") searchGithubReposNow(); + }} + maxLength={200} + className="flex-1 h-8 text-[10px] border-0 focus-visible:ring-0 focus-visible:ring-offset-0 bg-transparent px-0" + /> + {githubSearch.trim() ? ( + + ) : null} +
+
+ {githubLoading ? ( +
+ +

+ {githubSearch.trim() ? "Searching repositories..." : "Loading repositories..."} +

+
+ ) : githubRepos.length === 0 ? ( +
+ +

+ {githubSearch.trim() + ? `No repositories found matching '${githubSearch.trim()}'` + : "No parsed repositories found"} +

+

+ {githubSearch.trim() ? "Try a different search term" : "Parse a repository to get started"} +

+
+ ) : ( +
+ {githubRepos.map((repo, idx) => { + const identity = extractRepoIdentity(repo); + if (!identity) return null; + const key = `${identity.owner}/${identity.repo}`; + const alreadyAttached = attachedScopeKeys.has(`gh:${key.toLowerCase()}`); + return ( +
+
+

{key}

+ {identity.default_branch ? ( +

+ default: {identity.default_branch} +

+ ) : null} +
+ +
+ ); + })} +
+ )} +
+ {githubHasMore ? ( +
+ +
) : null}
- {githubHasMore ? ( -
- -
- ) : null}
) : pickerType === "linear_team" ? (
@@ -769,7 +866,7 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged } {pickerType !== null ? ( - ) : null} From ada0f1d832fdf5f8c46fa428ee4b92b46c787dff Mon Sep 17 00:00:00 2001 From: Shambhavi Shinde <156112383+shmbhvi101@users.noreply.github.com> Date: Mon, 25 May 2026 12:45:20 +0530 Subject: [PATCH 2/3] Added repo pills, Filter out already selected repos, and seleect all button --- .../pots/components/PotSourcesPanel.tsx | 446 ++++++++++++++++-- 1 file changed, 398 insertions(+), 48 deletions(-) diff --git a/app/(main)/pots/components/PotSourcesPanel.tsx b/app/(main)/pots/components/PotSourcesPanel.tsx index 9a39d626..12dd9fb6 100644 --- a/app/(main)/pots/components/PotSourcesPanel.tsx +++ b/app/(main)/pots/components/PotSourcesPanel.tsx @@ -1,6 +1,6 @@ "use client"; -import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; import Link from "next/link"; import { FolderOpen, @@ -41,6 +41,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Badge } from "@/components/ui/badge"; +import { Checkbox } from "@/components/ui/checkbox"; import { Dialog, DialogContent, @@ -108,14 +109,18 @@ const SOURCE_TYPES: SourceTypeOption[] = [ ]; const GITHUB_REPO_PAGE_SIZE = 20; +const GITHUB_PILLS_MAX_HEIGHT_CLASS = "max-h-32"; +const GITHUB_PILLS_EXPANDED_MAX_HEIGHT_CLASS = "max-h-40"; -function extractRepoIdentity(repo: GithubRepo): { +type GithubRepoIdentity = { owner: string; repo: string; default_branch?: string; external_repo_id?: string; remote_url?: string; -} | null { +}; + +function extractRepoIdentity(repo: GithubRepo): GithubRepoIdentity | null { const fullName = repo.full_name; let owner = ""; let name = ""; @@ -138,6 +143,10 @@ function extractRepoIdentity(repo: GithubRepo): { }; } +function githubRepoSelectionKey(identity: GithubRepoIdentity): string { + return `gh:${identity.owner.toLowerCase()}/${identity.repo.toLowerCase()}`; +} + function describeSource(s: PotSource): { title: string; subtitle: string | null; url: string | null; avatarUrl: string | null } { if (s.source_kind === "repository" && s.provider === "github") { const owner = (s.scope.owner as string | undefined) || ""; @@ -206,7 +215,16 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged } const [githubSearch, setGithubSearch] = useState(""); const githubSearchDebounceRef = useRef(null); const githubRequestIdRef = useRef(0); - const [attachingRepoKey, setAttachingRepoKey] = useState(null); + const [selectedGithubRepos, setSelectedGithubRepos] = useState< + Record + >({}); + const [addingGithubRepos, setAddingGithubRepos] = useState(false); + const [selectingAllGithubRepos, setSelectingAllGithubRepos] = useState(false); + const [githubPillsExpanded, setGithubPillsExpanded] = useState(false); + const [githubPillsVisibleCount, setGithubPillsVisibleCount] = useState( + null, + ); + const githubPillsMeasureRef = useRef(null); // Linear picker state const [linearIntegrationId, setLinearIntegrationId] = useState(null); @@ -270,6 +288,167 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged } return set; }, [sources]); + const selectedGithubCount = useMemo( + () => Object.keys(selectedGithubRepos).length, + [selectedGithubRepos], + ); + + const selectedGithubRepoPills = useMemo( + () => + Object.entries(selectedGithubRepos) + .map(([selectionKey, identity]) => ({ + selectionKey, + label: `${identity.owner}/${identity.repo}`, + })) + .sort((a, b) => a.label.localeCompare(b.label)), + [selectedGithubRepos], + ); + + const hiddenGithubPillCount = Math.max( + 0, + selectedGithubRepoPills.length - (githubPillsVisibleCount ?? selectedGithubRepoPills.length), + ); + + const visibleGithubRepoPills = githubPillsExpanded + ? selectedGithubRepoPills + : selectedGithubRepoPills.slice( + 0, + githubPillsVisibleCount ?? selectedGithubRepoPills.length, + ); + + useLayoutEffect(() => { + if (githubPillsExpanded || selectedGithubRepoPills.length === 0) { + setGithubPillsVisibleCount(selectedGithubRepoPills.length); + return; + } + + const container = githubPillsMeasureRef.current; + if (!container) { + setGithubPillsVisibleCount(selectedGithubRepoPills.length); + return; + } + + const pillNodes = container.querySelectorAll("[data-github-pill]"); + const total = pillNodes.length; + if (total === 0) { + setGithubPillsVisibleCount(0); + return; + } + + const maxBottom = container.getBoundingClientRect().bottom; + let visible = total; + for (let i = 0; i < total; i += 1) { + const pillBottom = pillNodes[i].getBoundingClientRect().bottom; + if (pillBottom > maxBottom + 1) { + visible = i; + break; + } + } + + const hidden = total - visible; + if (hidden > 0) { + visible = Math.max(1, visible - 1); + } + + setGithubPillsVisibleCount(visible); + }, [selectedGithubRepoPills, githubPillsExpanded]); + + useEffect(() => { + if (selectedGithubRepoPills.length === 0) { + setGithubPillsExpanded(false); + setGithubPillsVisibleCount(null); + } + }, [selectedGithubRepoPills.length]); + + const selectableGithubRepos = useMemo(() => { + const selectable: Record = {}; + githubRepos.forEach((repo) => { + const identity = extractRepoIdentity(repo); + if (!identity) return; + const selectionKey = githubRepoSelectionKey(identity); + if (attachedScopeKeys.has(selectionKey)) return; + selectable[selectionKey] = identity; + }); + return selectable; + }, [githubRepos, attachedScopeKeys]); + + const selectableGithubCount = Object.keys(selectableGithubRepos).length; + + const allLoadedGithubReposSelected = useMemo(() => { + if (selectableGithubCount === 0) return false; + return Object.keys(selectableGithubRepos).every( + (selectionKey) => selectedGithubRepos[selectionKey], + ); + }, [selectableGithubRepos, selectableGithubCount, selectedGithubRepos]); + + const canDeselectAllGithubRepos = + allLoadedGithubReposSelected && !githubHasMore && selectableGithubCount > 0; + + const displayedGithubRepos = useMemo( + () => + githubRepos.filter((repo) => { + const identity = extractRepoIdentity(repo); + if (!identity) return false; + return !attachedScopeKeys.has(githubRepoSelectionKey(identity)); + }), + [githubRepos, attachedScopeKeys], + ); + + const toggleSelectAllGithubRepos = async () => { + if (selectingAllGithubRepos || addingGithubRepos) return; + + if (canDeselectAllGithubRepos) { + setSelectedGithubRepos((prev) => { + const next = { ...prev }; + Object.keys(selectableGithubRepos).forEach((selectionKey) => { + delete next[selectionKey]; + }); + return next; + }); + return; + } + + if (selectableGithubCount === 0 && !githubHasMore) return; + + setSelectingAllGithubRepos(true); + try { + const trimmedSearch = githubSearch.trim().slice(0, 200); + let offset = 0; + let allRepos: GithubRepo[] = []; + let hasMore = true; + + while (hasMore) { + const page = await BranchAndRepositoryService.searchUserRepositories({ + search: trimmedSearch, + limit: GITHUB_REPO_PAGE_SIZE, + offset, + }); + allRepos = allRepos.concat(page.repositories); + hasMore = page.has_next_page; + offset += page.repositories.length; + if (page.repositories.length === 0) break; + } + + setGithubRepos(allRepos); + setGithubOffset(allRepos.length); + setGithubHasMore(false); + + const selectable: Record = {}; + allRepos.forEach((repo) => { + const identity = extractRepoIdentity(repo); + if (!identity) return; + const selectionKey = githubRepoSelectionKey(identity); + if (attachedScopeKeys.has(selectionKey)) return; + selectable[selectionKey] = identity; + }); + setSelectedGithubRepos(selectable); + } catch { + toast.error("Failed to load all repositories"); + } finally { + setSelectingAllGithubRepos(false); + } + }; + // ---- Picker open/close + per-type bootstrapping -------------------- const clearGithubSearchDebounce = () => { @@ -287,6 +466,11 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged } setGithubOffset(0); setGithubHasMore(false); setGithubLoading(false); + setSelectedGithubRepos({}); + setAddingGithubRepos(false); + setSelectingAllGithubRepos(false); + setGithubPillsExpanded(false); + setGithubPillsVisibleCount(null); }; const openPicker = (typeId: SourceTypeId) => { @@ -382,23 +566,74 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged } void loadGithubPage(true, ""); }; - const handleAttachGithub = async (repo: GithubRepo) => { + const toggleGithubRepoSelection = (repo: GithubRepo) => { const identity = extractRepoIdentity(repo); - if (!identity) { - toast.error("Could not read repository identity."); - return; - } - const key = `${identity.owner}/${identity.repo}`; - setAttachingRepoKey(key); + if (!identity) return; + const selectionKey = githubRepoSelectionKey(identity); + if (attachedScopeKeys.has(selectionKey)) return; + + setSelectedGithubRepos((prev) => { + if (prev[selectionKey]) { + const next = { ...prev }; + delete next[selectionKey]; + return next; + } + return { ...prev, [selectionKey]: identity }; + }); + }; + + const removeSelectedGithubRepo = (selectionKey: string) => { + setSelectedGithubRepos((prev) => { + if (!prev[selectionKey]) return prev; + const next = { ...prev }; + delete next[selectionKey]; + return next; + }); + }; + + const handleAddSelectedGithubRepos = async () => { + const identities = Object.values(selectedGithubRepos); + if (identities.length === 0) return; + + setAddingGithubRepos(true); try { - await PotService.addGithubRepositorySource(potId, identity); - toast.success(`Attached ${key}`); - await refresh(); - onPrimaryRepoChanged(); - } catch (e) { - toast.error(e instanceof Error ? e.message : "Failed to attach repository"); + const results = await Promise.allSettled( + identities.map((identity) => + PotService.addGithubRepositorySource(potId, identity), + ), + ); + const succeeded = results.filter((result) => result.status === "fulfilled").length; + const failed = results.length - succeeded; + + if (succeeded > 0) { + await refresh(); + onPrimaryRepoChanged(); + } + + if (failed === 0) { + toast.success( + succeeded === 1 + ? `Added ${identities[0].owner}/${identities[0].repo}` + : `Added ${succeeded} repositories`, + ); + setSelectedGithubRepos({}); + closePicker(); + } else if (succeeded > 0) { + toast.error(`Added ${succeeded} of ${results.length} repositories. ${failed} failed.`); + setSelectedGithubRepos((prev) => { + const next = { ...prev }; + results.forEach((result, index) => { + if (result.status === "fulfilled") { + delete next[githubRepoSelectionKey(identities[index])]; + } + }); + return next; + }); + } else { + toast.error("Failed to add selected repositories"); + } } finally { - setAttachingRepoKey(null); + setAddingGithubRepos(false); } }; @@ -713,47 +948,162 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged } ) : null} + {selectingAllGithubRepos ? ( + + Selecting... + + ) : !githubLoading && + (selectableGithubCount > 0 || githubHasMore) ? ( + + ) : null}
+ {selectedGithubRepoPills.length > 0 ? ( +
+ {!githubPillsExpanded ? ( +
+ {selectedGithubRepoPills.map(({ selectionKey, label }) => ( + + {label} + + + ))} +
+ ) : null} +
+ {visibleGithubRepoPills.map(({ selectionKey, label }) => ( + + {label} + + + ))} + {!githubPillsExpanded && hiddenGithubPillCount > 0 ? ( + + ) : null} +
+
+ ) : null}
- {githubLoading ? ( + {githubLoading || selectingAllGithubRepos ? (

- {githubSearch.trim() ? "Searching repositories..." : "Loading repositories..."} + {selectingAllGithubRepos + ? "Loading all repositories..." + : githubSearch.trim() + ? "Searching repositories..." + : "Loading repositories..."}

- ) : githubRepos.length === 0 ? ( + ) : displayedGithubRepos.length === 0 ? (

- {githubSearch.trim() - ? `No repositories found matching '${githubSearch.trim()}'` - : "No parsed repositories found"} + {githubRepos.length > 0 + ? "All matching repositories are already attached" + : githubSearch.trim() + ? `No repositories found matching '${githubSearch.trim()}'` + : "No parsed repositories found"}

- {githubSearch.trim() ? "Try a different search term" : "Parse a repository to get started"} + {githubRepos.length > 0 + ? "Try a different search term" + : githubSearch.trim() + ? "Try a different search term" + : "Parse a repository to get started"}

) : (
- {githubRepos.map((repo, idx) => { + {displayedGithubRepos.map((repo, idx) => { const identity = extractRepoIdentity(repo); if (!identity) return null; const key = `${identity.owner}/${identity.repo}`; - const alreadyAttached = attachedScopeKeys.has(`gh:${key.toLowerCase()}`); + const selectionKey = githubRepoSelectionKey(identity); + const isSelected = Boolean(selectedGithubRepos[selectionKey]); return (
{ + if (!addingGithubRepos) { + toggleGithubRepoSelection(repo); + } + }} + onKeyDown={(e) => { + if ( + !addingGithubRepos && + (e.key === "Enter" || e.key === " ") + ) { + e.preventDefault(); + toggleGithubRepoSelection(repo); + } + }} + className={`flex items-center gap-2.5 rounded-lg px-2.5 py-2 transition-colors cursor-pointer ${ + isSelected + ? "bg-zinc-50 border border-zinc-200" + : "hover:bg-zinc-50" + }`} > -
+ toggleGithubRepoSelection(repo)} + onClick={(e) => e.stopPropagation()} + className="h-3.5 w-3.5 shrink-0 flex items-center justify-center rounded-[3px] [&>span]:flex [&>span]:h-full [&>span]:w-full [&>span]:items-center [&>span]:justify-center [&_svg]:h-2.5 [&_svg]:w-2.5" + /> +

{key}

{identity.default_branch ? (

@@ -761,19 +1111,6 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged }

) : null}
-
); })} @@ -785,7 +1122,7 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged } ) : null} - + {pickerType === "github_repository" ? ( + + ) : ( + + )} From eff340235b33bbc3c6d763940e2ce07eafd3c9ac Mon Sep 17 00:00:00 2001 From: Shambhavi Shinde <156112383+shmbhvi101@users.noreply.github.com> Date: Mon, 25 May 2026 12:57:17 +0530 Subject: [PATCH 3/3] capped the pill display --- .../pots/components/PotSourcesPanel.tsx | 71 +++++++------------ 1 file changed, 27 insertions(+), 44 deletions(-) diff --git a/app/(main)/pots/components/PotSourcesPanel.tsx b/app/(main)/pots/components/PotSourcesPanel.tsx index 12dd9fb6..6c8e3404 100644 --- a/app/(main)/pots/components/PotSourcesPanel.tsx +++ b/app/(main)/pots/components/PotSourcesPanel.tsx @@ -110,7 +110,6 @@ const SOURCE_TYPES: SourceTypeOption[] = [ const GITHUB_REPO_PAGE_SIZE = 20; const GITHUB_PILLS_MAX_HEIGHT_CLASS = "max-h-32"; -const GITHUB_PILLS_EXPANDED_MAX_HEIGHT_CLASS = "max-h-40"; type GithubRepoIdentity = { owner: string; @@ -220,7 +219,6 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged } >({}); const [addingGithubRepos, setAddingGithubRepos] = useState(false); const [selectingAllGithubRepos, setSelectingAllGithubRepos] = useState(false); - const [githubPillsExpanded, setGithubPillsExpanded] = useState(false); const [githubPillsVisibleCount, setGithubPillsVisibleCount] = useState( null, ); @@ -309,16 +307,14 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged } selectedGithubRepoPills.length - (githubPillsVisibleCount ?? selectedGithubRepoPills.length), ); - const visibleGithubRepoPills = githubPillsExpanded - ? selectedGithubRepoPills - : selectedGithubRepoPills.slice( - 0, - githubPillsVisibleCount ?? selectedGithubRepoPills.length, - ); + const visibleGithubRepoPills = selectedGithubRepoPills.slice( + 0, + githubPillsVisibleCount ?? selectedGithubRepoPills.length, + ); useLayoutEffect(() => { - if (githubPillsExpanded || selectedGithubRepoPills.length === 0) { - setGithubPillsVisibleCount(selectedGithubRepoPills.length); + if (selectedGithubRepoPills.length === 0) { + setGithubPillsVisibleCount(0); return; } @@ -351,11 +347,10 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged } } setGithubPillsVisibleCount(visible); - }, [selectedGithubRepoPills, githubPillsExpanded]); + }, [selectedGithubRepoPills]); useEffect(() => { if (selectedGithubRepoPills.length === 0) { - setGithubPillsExpanded(false); setGithubPillsVisibleCount(null); } }, [selectedGithubRepoPills.length]); @@ -469,7 +464,6 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged } setSelectedGithubRepos({}); setAddingGithubRepos(false); setSelectingAllGithubRepos(false); - setGithubPillsExpanded(false); setGithubPillsVisibleCount(null); }; @@ -977,30 +971,24 @@ export default function PotSourcesPanel({ potId, isOwner, onPrimaryRepoChanged }
{selectedGithubRepoPills.length > 0 ? (
- {!githubPillsExpanded ? ( -
- {selectedGithubRepoPills.map(({ selectionKey, label }) => ( - - {label} - - - ))} -
- ) : null}
+ {selectedGithubRepoPills.map(({ selectionKey, label }) => ( + + {label} + + + ))} +
+
{visibleGithubRepoPills.map(({ selectionKey, label }) => ( ))} - {!githubPillsExpanded && hiddenGithubPillCount > 0 ? ( - + ) : null}