From f7d36e82ef0d0bdd33ffc7c663329f6144c8f734 Mon Sep 17 00:00:00 2001 From: Adrian Bonpin Date: Sun, 28 Jun 2026 17:59:05 +0800 Subject: [PATCH] feat(plugin): add verify config and copy launch option buttons --- .../src/components/settings-panel.tsx | 99 ++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/plugins/decky-vault/src/components/settings-panel.tsx b/plugins/decky-vault/src/components/settings-panel.tsx index 08ee14b..efad310 100644 --- a/plugins/decky-vault/src/components/settings-panel.tsx +++ b/plugins/decky-vault/src/components/settings-panel.tsx @@ -14,10 +14,12 @@ import { FaCog, FaFileExport, FaFileImport, + FaCopy, + FaSearch, } from "react-icons/fa" import type { PluginSettings } from "../lib/store" import { KNOWN_HARDWARE_SLUGS } from "@deckyvault/shared" -import { testApiKey, checkMangohud, writeMangohudConfig, exportConfig, importConfig } from "../lib/api" +import { testApiKey, checkMangohud, writeMangohudConfig, getMangohudConfig, exportConfig, importConfig } from "../lib/api" interface SettingsPanelProps { settings: PluginSettings @@ -46,6 +48,12 @@ export default function SettingsPanel({ }>({ checked: false, installed: false, path: "", version: "" }) const [configWritten, setConfigWritten] = useState(false) const [configStatus, setConfigStatus] = useState<{ message: string; isError: boolean } | null>(null) + const [configVerified, setConfigVerified] = useState<{ + checked: boolean + valid: boolean + message: string + }>({ checked: false, valid: false, message: "" }) + const [copiedLaunchOpt, setCopiedLaunchOpt] = useState(false) async function handleTestKey() { if (!settings.apiKey) { @@ -80,6 +88,62 @@ export default function SettingsPanel({ setConfigWritten(result.success) } + async function handleVerifyConfig() { + const result = await getMangohudConfig() + if (!result.exists) { + setConfigVerified({ + checked: true, + valid: false, + message: "No MangoHud config found. Write one first.", + }) + return + } + const content = result.content + const hasOutputFolder = content.includes("output_folder=/tmp") + const hasOutputFile = content.includes("output_file=deckyvault-mangohud.log") + const hasFps = content.includes("fps") + const hasFrameTiming = content.includes("frame_timing") + const hasGpuPower = content.includes("gpu_power") + + if (hasOutputFolder && hasOutputFile && hasFps) { + setConfigVerified({ + checked: true, + valid: true, + message: "Config looks good — logging to /tmp/deckyvault-mangohud.log", + }) + } else { + const missing: string[] = [] + if (!hasOutputFolder) missing.push("output_folder=/tmp") + if (!hasOutputFile) missing.push("output_file=deckyvault-mangohud.log") + if (!hasFps) missing.push("fps") + if (!hasFrameTiming) missing.push("frame_timing") + if (!hasGpuPower) missing.push("gpu_power") + setConfigVerified({ + checked: true, + valid: false, + message: `Missing: ${missing.join(", ")}. Write config again.`, + }) + } + } + + async function handleCopyLaunchOption() { + try { + await navigator.clipboard.writeText("mangohud %command%") + setCopiedLaunchOpt(true) + setTimeout(() => setCopiedLaunchOpt(false), 2000) + } catch { + // Fallback + const ta = document.createElement("textarea") + ta.value = "mangohud %command%" + document.body.appendChild(ta) + ta.select() + document.execCommand("copy") + document.body.removeChild(ta) + setCopiedLaunchOpt(true) + setTimeout(() => setCopiedLaunchOpt(false), 2000) + } + } + async function handleExportConfig() { setConfigStatus(null) const result = await exportConfig(settings) @@ -256,6 +320,39 @@ export default function SettingsPanel({ + + +
+ + Verify Config +
+
+
+ + {configVerified.checked && ( + +
+ {configVerified.valid ? : } {configVerified.message} +
+
+ )} + + + +
+ + {copiedLaunchOpt ? "Copied!" : "Copy Launch Option"} +
+
+
+ {configWritten && (