From 5ed09cc05d3ed62fc3f2a4bddf28210ad5e085b2 Mon Sep 17 00:00:00 2001 From: shaw-baobao <1175745159@qq.com> Date: Sun, 1 Feb 2026 20:10:14 +0800 Subject: [PATCH] Validate Open in targets before selection --- src/features/app/components/OpenAppMenu.tsx | 38 ++++++++-- .../messages/hooks/useFileLinkOpener.ts | 33 +++++++-- .../settings/components/SettingsView.tsx | 72 ++++++++++++++++++- src/styles/settings.css | 18 +++++ 4 files changed, 148 insertions(+), 13 deletions(-) diff --git a/src/features/app/components/OpenAppMenu.tsx b/src/features/app/components/OpenAppMenu.tsx index d2dced15..06d54f02 100644 --- a/src/features/app/components/OpenAppMenu.tsx +++ b/src/features/app/components/OpenAppMenu.tsx @@ -121,6 +121,20 @@ export function OpenAppMenu({ }; }, [openMenuOpen]); + const resolveAppName = (target: OpenTarget) => + (target.target.appName ?? "").trim(); + const resolveCommand = (target: OpenTarget) => + (target.target.command ?? "").trim(); + const canOpenTarget = (target: OpenTarget) => { + if (target.target.kind === "finder") { + return true; + } + if (target.target.kind === "command") { + return Boolean(resolveCommand(target)); + } + return Boolean(resolveAppName(target)); + }; + const openWithTarget = async (target: OpenTarget) => { try { if (target.target.kind === "finder") { @@ -128,16 +142,17 @@ export function OpenAppMenu({ return; } if (target.target.kind === "command") { - if (!target.target.command) { + const command = resolveCommand(target); + if (!command) { return; } await openWorkspaceIn(path, { - command: target.target.command, + command, args: target.target.args, }); return; } - const appName = target.target.appName || target.label; + const appName = resolveAppName(target); if (!appName) { return; } @@ -151,19 +166,29 @@ export function OpenAppMenu({ }; const handleOpen = async () => { - if (!selectedOpenTarget) { + if (!selectedOpenTarget || !canOpenTarget(selectedOpenTarget)) { return; } await openWithTarget(selectedOpenTarget); }; const handleSelectOpenTarget = async (target: OpenTarget) => { + if (!canOpenTarget(target)) { + return; + } onSelectOpenAppId(target.id); window.localStorage.setItem(OPEN_APP_STORAGE_KEY, target.id); setOpenMenuOpen(false); await openWithTarget(target); }; + const selectedCanOpen = canOpenTarget(selectedOpenTarget); + const openLabel = selectedCanOpen + ? `Open in ${selectedOpenTarget.label}` + : selectedOpenTarget.target.kind === "command" + ? "Set command in Settings" + : "Set app name in Settings"; + return (
@@ -171,9 +196,10 @@ export function OpenAppMenu({ type="button" className="ghost main-header-action open-app-action" onClick={handleOpen} + disabled={!selectedCanOpen} data-tauri-drag-region="false" aria-label={`Open in ${selectedOpenTarget.label}`} - title={`Open in ${selectedOpenTarget.label}`} + title={openLabel} > {resolvedOpenTargets.map((target) => ( + // Keep entries visible but disable ones missing required config.