From 7749e325a217ec2a9e32911d05172bea050e4e3e Mon Sep 17 00:00:00 2001 From: YoVinchen Date: Mon, 24 Nov 2025 22:45:05 +0800 Subject: [PATCH] feat(frontend): add deeplink import event listeners and UI improvements Add event-driven refresh logic for deeplink imports and enhance Skills page filtering capabilities. PromptPanel changes: - Add "prompt-imported" custom event listener - Auto-reload prompts when deeplink import completes - Filter events by app ID to avoid unnecessary refreshes - Clean up event listener on component unmount SkillsPage improvements: - Add installation status filter (all/installed/uninstalled) - Implement Select component for filter dropdown - Combine status filter with existing search functionality - Update filtered skills memo to include both filters - Improve responsive layout for search and filter controls Event flow: 1. DeepLinkImportDialog dispatches "prompt-imported" event 2. PromptPanel listens for event matching its app 3. Panel triggers reload to show newly imported prompt 4. Similar pattern can be used for other non-React-Query resources These improvements enable seamless UI updates after deeplink imports without requiring manual page refresh. --- src/components/prompts/PromptPanel.tsx | 16 +++++++ src/components/skills/SkillsPage.tsx | 65 +++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/components/prompts/PromptPanel.tsx b/src/components/prompts/PromptPanel.tsx index 4b1761a8..12b9b2b9 100644 --- a/src/components/prompts/PromptPanel.tsx +++ b/src/components/prompts/PromptPanel.tsx @@ -43,6 +43,22 @@ const PromptPanel = React.forwardRef( if (open) reload(); }, [open, reload]); + // Listen for prompt import events from deep link + useEffect(() => { + const handlePromptImported = (event: Event) => { + const customEvent = event as CustomEvent; + // Reload if the import is for this app + if (customEvent.detail?.app === appId) { + reload(); + } + }; + + window.addEventListener("prompt-imported", handlePromptImported); + return () => { + window.removeEventListener("prompt-imported", handlePromptImported); + }; + }, [appId, reload]); + const handleAdd = () => { setEditingId(null); setIsFormOpen(true); diff --git a/src/components/skills/SkillsPage.tsx b/src/components/skills/SkillsPage.tsx index 7f936a1e..25f359bb 100644 --- a/src/components/skills/SkillsPage.tsx +++ b/src/components/skills/SkillsPage.tsx @@ -8,6 +8,13 @@ import { import { useTranslation } from "react-i18next"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import { RefreshCw, Search } from "lucide-react"; import { toast } from "sonner"; import { SkillCard } from "./SkillCard"; @@ -32,6 +39,9 @@ export const SkillsPage = forwardRef( const [loading, setLoading] = useState(true); const [repoManagerOpen, setRepoManagerOpen] = useState(false); const [searchQuery, setSearchQuery] = useState(""); + const [filterStatus, setFilterStatus] = useState< + "all" | "installed" | "uninstalled" + >("all"); const loadSkills = async (afterLoad?: (data: Skill[]) => void) => { try { @@ -172,10 +182,16 @@ export const SkillsPage = forwardRef( // 过滤技能列表 const filteredSkills = useMemo(() => { - if (!searchQuery.trim()) return skills; + const byStatus = skills.filter((skill) => { + if (filterStatus === "installed") return skill.installed; + if (filterStatus === "uninstalled") return !skill.installed; + return true; + }); + + if (!searchQuery.trim()) return byStatus; const query = searchQuery.toLowerCase(); - return skills.filter((skill) => { + return byStatus.filter((skill) => { const name = skill.name?.toLowerCase() || ""; const description = skill.description?.toLowerCase() || ""; const directory = skill.directory?.toLowerCase() || ""; @@ -186,7 +202,7 @@ export const SkillsPage = forwardRef( directory.includes(query) ); }); - }, [skills, searchQuery]); + }, [skills, searchQuery, filterStatus]); return (
@@ -218,17 +234,54 @@ export const SkillsPage = forwardRef( ) : ( <> {/* 搜索框 */} -
-
+
+
setSearchQuery(e.target.value)} - className="pl-9" + className="pl-9 pr-3" />
+
+ +
{searchQuery && (

{t("skills.count", { count: filteredSkills.length })}