import { useMutation, useQuery } from "@tanstack/react-query"; import { openUrl } from "@tauri-apps/plugin-opener"; import type { Plugin } from "@yaakapp-internal/models"; import { patchModel, pluginsAtom } from "@yaakapp-internal/models"; import type { PluginVersion } from "@yaakapp-internal/plugins"; import { checkPluginUpdates, installPlugin, searchPlugins, uninstallPlugin, } from "@yaakapp-internal/plugins"; import classNames from "classnames"; import { useAtomValue } from "jotai"; import { useState } from "react"; import { useDebouncedValue } from "../../hooks/useDebouncedValue"; import { useInstallPlugin } from "../../hooks/useInstallPlugin"; import { usePluginInfo } from "../../hooks/usePluginInfo"; import { usePluginsKey, useRefreshPlugins } from "../../hooks/usePlugins"; import { showConfirmDelete } from "../../lib/confirm"; import { minPromiseMillis } from "../../lib/minPromiseMillis"; import { Button } from "../core/Button"; import { Checkbox } from "../core/Checkbox"; import { CountBadge } from "../core/CountBadge"; import { Icon } from "../core/Icon"; import { IconButton } from "../core/IconButton"; import { InlineCode } from "../core/InlineCode"; import { Link } from "../core/Link"; import { LoadingIcon } from "../core/LoadingIcon"; import { PlainInput } from "../core/PlainInput"; import { HStack } from "../core/Stacks"; import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow } from "../core/Table"; import { TabContent, Tabs } from "../core/Tabs/Tabs"; import { EmptyStateText } from "../EmptyStateText"; import { SelectFile } from "../SelectFile"; interface SettingsPluginsProps { defaultSubtab?: string; } export function SettingsPlugins({ defaultSubtab }: SettingsPluginsProps) { const [directory, setDirectory] = useState(null); const plugins = useAtomValue(pluginsAtom); const bundledPlugins = plugins.filter((p) => p.source === "bundled"); const installedPlugins = plugins.filter((p) => p.source !== "bundled"); const createPlugin = useInstallPlugin(); const refreshPlugins = useRefreshPlugins(); return (
, }, { label: "Bundled", value: "bundled", rightSlot: , }, ]} >
setDirectory(filePath)} filePath={directory} /> {directory && ( )} refreshPlugins.mutate()} /> openUrl("https://yaak.app/docs/plugin-development/plugins-quick-start") } />
); } function PluginTableRowForInstalledPlugin({ plugin }: { plugin: Plugin }) { const info = usePluginInfo(plugin.id).data; if (info == null) { return null; } return ( ); } function PluginTableRowForBundledPlugin({ plugin }: { plugin: Plugin }) { const info = usePluginInfo(plugin.id).data; if (info == null) { return null; } return ( ); } function PluginTableRowForRemotePluginVersion({ pluginVersion }: { pluginVersion: PluginVersion }) { const plugin = useAtomValue(pluginsAtom).find((p) => p.id === pluginVersion.id); const pluginInfo = usePluginInfo(plugin?.id ?? null).data; return ( ); } function PluginTableRow({ plugin, name, version, displayName, url, showCheckbox = true, showUninstall = true, }: { plugin: Plugin | null; name: string; version: string; displayName: string; url: string | null; showCheckbox?: boolean; showUninstall?: boolean; }) { const updates = usePluginUpdates(); const latestVersion = updates.data?.plugins.find((u) => u.name === name)?.version; const installPluginMutation = useMutation({ mutationKey: ["install_plugin", name], mutationFn: (name: string) => installPlugin(name, null), }); const uninstall = usePromptUninstall(plugin?.id ?? null, displayName); const refreshPlugins = useRefreshPlugins(); return ( {showCheckbox && ( { if (plugin) { await patchModel(plugin, { enabled }); refreshPlugins.mutate(); } }} /> )} {url ? ( {displayName} ) : ( displayName )} {name} {version} {latestVersion != null && ( {latestVersion} )} {plugin != null && latestVersion != null ? ( ) : plugin == null ? ( ) : null} {showUninstall && uninstall != null && ( )} ); } function PluginSearch() { const [query, setQuery] = useState(""); const debouncedQuery = useDebouncedValue(query); const results = useQuery({ queryKey: ["plugins", debouncedQuery], queryFn: () => searchPlugins(query), }); return (
{results.data == null ? ( ) : (results.data.plugins ?? []).length === 0 ? ( No plugins found ) : ( Display Name Name Version {results.data.plugins.map((p) => ( ))}
)}
); } function InstalledPlugins({ plugins, className }: { plugins: Plugin[]; className?: string }) { return plugins.length === 0 ? (
Plugins extend the functionality of Yaak.
Add your first plugin to get started.
) : ( Display Name Name Version {plugins.map((p) => ( ))}
); } function BundledPlugins({ plugins }: { plugins: Plugin[] }) { return plugins.length === 0 ? (
No bundled plugins found.
) : ( Display Name Name Version {plugins.map((p) => ( ))}
); } function usePromptUninstall(pluginId: string | null, name: string) { const mut = useMutation({ mutationKey: ["uninstall_plugin", pluginId], mutationFn: async () => { if (pluginId == null) return; const confirmed = await showConfirmDelete({ id: `uninstall-plugin-${pluginId}`, title: "Uninstall Plugin", confirmText: "Uninstall", description: ( <> Permanently uninstall {name}? ), }); if (confirmed) { await minPromiseMillis(uninstallPlugin(pluginId), 700); } }, }); return pluginId == null ? null : mut; } function usePluginUpdates() { return useQuery({ queryKey: ["plugin_updates", usePluginsKey()], queryFn: () => checkPluginUpdates(), }); }