mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-22 08:38:29 +02:00
Fixed bugs in Plugin settings pane
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
use crate::error::Error::MigrationError;
|
use crate::error::Error::MigrationError;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use include_dir::{include_dir, Dir, DirEntry};
|
use include_dir::{Dir, DirEntry, include_dir};
|
||||||
use log::{debug, info};
|
use log::info;
|
||||||
use r2d2::Pool;
|
use r2d2::Pool;
|
||||||
use r2d2_sqlite::SqliteConnectionManager;
|
use r2d2_sqlite::SqliteConnectionManager;
|
||||||
use rusqlite::{params, OptionalExtension, TransactionBehavior};
|
use rusqlite::{OptionalExtension, TransactionBehavior, params};
|
||||||
use sha2::{Digest, Sha384};
|
use sha2::{Digest, Sha384};
|
||||||
|
|
||||||
static MIGRATIONS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/migrations");
|
static MIGRATIONS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/migrations");
|
||||||
@@ -40,12 +40,18 @@ pub(crate) fn migrate_db(pool: &Pool<SqliteConnectionManager>) -> Result<()> {
|
|||||||
|
|
||||||
// Run each migration in a transaction
|
// Run each migration in a transaction
|
||||||
let mut num_migrations = 0;
|
let mut num_migrations = 0;
|
||||||
|
let mut ran_migrations = 0;
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
num_migrations += 1;
|
num_migrations += 1;
|
||||||
let mut conn = pool.get()?;
|
let mut conn = pool.get()?;
|
||||||
let mut tx = conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
|
let mut tx = conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
|
||||||
match run_migration(entry, &mut tx) {
|
match run_migration(entry, &mut tx) {
|
||||||
Ok(_) => tx.commit()?,
|
Ok(ran) => {
|
||||||
|
if ran {
|
||||||
|
ran_migrations += 1;
|
||||||
|
}
|
||||||
|
tx.commit()?
|
||||||
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"{} failed with {}",
|
"{} failed with {}",
|
||||||
@@ -58,7 +64,11 @@ pub(crate) fn migrate_db(pool: &Pool<SqliteConnectionManager>) -> Result<()> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Finished running {} migrations", num_migrations);
|
if ran_migrations == 0 {
|
||||||
|
info!("No migrations to run out of {}", num_migrations);
|
||||||
|
} else {
|
||||||
|
info!("Ran {}/{} migrations", ran_migrations, num_migrations);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -76,9 +86,7 @@ fn run_migration(migration_path: &DirEntry, tx: &mut rusqlite::Transaction) -> R
|
|||||||
.optional()?;
|
.optional()?;
|
||||||
|
|
||||||
if row.is_some() {
|
if row.is_some() {
|
||||||
debug!("Skipping migration {description}");
|
return Ok(false); // Migration was already run
|
||||||
// Migration was already run
|
|
||||||
return Ok(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let sql =
|
let sql =
|
||||||
|
|||||||
@@ -43,8 +43,10 @@ pub async fn download_plugin_archive<R: Runtime>(
|
|||||||
};
|
};
|
||||||
let resp = yaak_api_client(app_handle)?.get(url.clone()).send().await?;
|
let resp = yaak_api_client(app_handle)?.get(url.clone()).send().await?;
|
||||||
if !resp.status().is_success() {
|
if !resp.status().is_success() {
|
||||||
|
warn!("Failed to download plugin: {name} {version}");
|
||||||
return Err(ApiErr(format!("{} response to {}", resp.status(), url.to_string())));
|
return Err(ApiErr(format!("{} response to {}", resp.status(), url.to_string())));
|
||||||
}
|
}
|
||||||
|
info!("Downloaded plugin: {url}");
|
||||||
Ok(resp)
|
Ok(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ use yaak_models::models::Plugin;
|
|||||||
use yaak_models::query_manager::QueryManagerExt;
|
use yaak_models::query_manager::QueryManagerExt;
|
||||||
use yaak_models::util::UpdateSource;
|
use yaak_models::util::UpdateSource;
|
||||||
|
|
||||||
pub async fn delete_and_uninstall<R: Runtime>(window: &WebviewWindow<R>, plugin_id: &str) -> Result<Plugin> {
|
pub async fn delete_and_uninstall<R: Runtime>(
|
||||||
|
window: &WebviewWindow<R>,
|
||||||
|
plugin_id: &str,
|
||||||
|
) -> Result<Plugin> {
|
||||||
let plugin_manager = window.state::<PluginManager>();
|
let plugin_manager = window.state::<PluginManager>();
|
||||||
let plugin = window.db().delete_plugin_by_id(plugin_id, &UpdateSource::from_window(&window))?;
|
let plugin = window.db().delete_plugin_by_id(plugin_id, &UpdateSource::from_window(&window))?;
|
||||||
plugin_manager.uninstall(&PluginWindowContext::new(&window), plugin.directory.as_str()).await?;
|
plugin_manager.uninstall(&PluginWindowContext::new(&window), plugin.directory.as_str()).await?;
|
||||||
@@ -25,6 +28,7 @@ pub async fn download_and_install<R: Runtime>(
|
|||||||
name: &str,
|
name: &str,
|
||||||
version: Option<String>,
|
version: Option<String>,
|
||||||
) -> Result<PluginVersion> {
|
) -> Result<PluginVersion> {
|
||||||
|
info!("Installing plugin {} {}", name, version.clone().unwrap_or_default());
|
||||||
let plugin_manager = window.state::<PluginManager>();
|
let plugin_manager = window.state::<PluginManager>();
|
||||||
let plugin_version = get_plugin(window.app_handle(), name, version).await?;
|
let plugin_version = get_plugin(window.app_handle(), name, version).await?;
|
||||||
let resp = download_plugin_archive(window.app_handle(), &plugin_version).await?;
|
let resp = download_plugin_archive(window.app_handle(), &plugin_version).await?;
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ impl PluginManager {
|
|||||||
dir: &str,
|
dir: &str,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
info!("Adding plugin by dir {dir}");
|
info!("Adding plugin by dir {dir}");
|
||||||
|
|
||||||
let maybe_tx = self.ws_service.app_to_plugin_events_tx.lock().await;
|
let maybe_tx = self.ws_service.app_to_plugin_events_tx.lock().await;
|
||||||
let tx = match &*maybe_tx {
|
let tx = match &*maybe_tx {
|
||||||
None => return Err(ClientNotInitializedErr),
|
None => return Err(ClientNotInitializedErr),
|
||||||
@@ -233,6 +234,12 @@ impl PluginManager {
|
|||||||
)
|
)
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
let mut plugins = self.plugins.lock().await;
|
||||||
|
|
||||||
|
// Remove the existing plugin (if exists) before adding this one
|
||||||
|
plugins.retain(|p| p.dir != dir);
|
||||||
|
plugins.push(plugin_handle.clone());
|
||||||
|
|
||||||
// Add the new plugin
|
// Add the new plugin
|
||||||
self.plugins.lock().await.push(plugin_handle.clone());
|
self.plugins.lock().await.push(plugin_handle.clone());
|
||||||
|
|
||||||
|
|||||||
@@ -9,17 +9,17 @@ import {
|
|||||||
searchPlugins,
|
searchPlugins,
|
||||||
uninstallPlugin,
|
uninstallPlugin,
|
||||||
} from '@yaakapp-internal/plugins';
|
} from '@yaakapp-internal/plugins';
|
||||||
import type { PluginUpdatesResponse } from '@yaakapp-internal/plugins/bindings/gen_api';
|
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useDebouncedValue } from '../../hooks/useDebouncedValue';
|
import { useDebouncedValue } from '../../hooks/useDebouncedValue';
|
||||||
import { useInstallPlugin } from '../../hooks/useInstallPlugin';
|
import { useInstallPlugin } from '../../hooks/useInstallPlugin';
|
||||||
import { usePluginInfo } from '../../hooks/usePluginInfo';
|
import { usePluginInfo } from '../../hooks/usePluginInfo';
|
||||||
import { useRefreshPlugins } from '../../hooks/usePlugins';
|
import { usePluginsKey, useRefreshPlugins } from '../../hooks/usePlugins';
|
||||||
import { showConfirmDelete } from '../../lib/confirm';
|
import { showConfirmDelete } from '../../lib/confirm';
|
||||||
import { minPromiseMillis } from '../../lib/minPromiseMillis';
|
import { minPromiseMillis } from '../../lib/minPromiseMillis';
|
||||||
import { Button } from '../core/Button';
|
import { Button } from '../core/Button';
|
||||||
import { CountBadge } from '../core/CountBadge';
|
import { CountBadge } from '../core/CountBadge';
|
||||||
|
import { Icon } from '../core/Icon';
|
||||||
import { IconButton } from '../core/IconButton';
|
import { IconButton } from '../core/IconButton';
|
||||||
import { InlineCode } from '../core/InlineCode';
|
import { InlineCode } from '../core/InlineCode';
|
||||||
import { Link } from '../core/Link';
|
import { Link } from '../core/Link';
|
||||||
@@ -57,7 +57,7 @@ export function SettingsPlugins() {
|
|||||||
<TabContent value="search">
|
<TabContent value="search">
|
||||||
<PluginSearch />
|
<PluginSearch />
|
||||||
</TabContent>
|
</TabContent>
|
||||||
<TabContent value="installed">
|
<TabContent value="installed" className="pb-0">
|
||||||
<div className="h-full grid grid-rows-[minmax(0,1fr)_auto]">
|
<div className="h-full grid grid-rows-[minmax(0,1fr)_auto]">
|
||||||
<InstalledPlugins />
|
<InstalledPlugins />
|
||||||
<footer className="grid grid-cols-[minmax(0,1fr)_auto] -mx-4 py-2 px-4 border-t bg-surface-highlight border-border-subtle min-w-0">
|
<footer className="grid grid-cols-[minmax(0,1fr)_auto] -mx-4 py-2 px-4 border-t bg-surface-highlight border-border-subtle min-w-0">
|
||||||
@@ -107,32 +107,64 @@ export function SettingsPlugins() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function PluginTableRow({
|
function PluginTableRowForInstalledPlugin({ plugin }: { plugin: Plugin }) {
|
||||||
plugin,
|
const info = usePluginInfo(plugin.id).data;
|
||||||
updates,
|
if (info == null) {
|
||||||
}: {
|
|
||||||
plugin: Plugin;
|
|
||||||
updates: PluginUpdatesResponse | null;
|
|
||||||
}) {
|
|
||||||
const pluginInfo = usePluginInfo(plugin.id);
|
|
||||||
const latestVersion = updates?.plugins.find((u) => u.name === pluginInfo.data?.name)?.version;
|
|
||||||
const installPluginMutation = useMutation({
|
|
||||||
mutationKey: ['install_plugin', plugin.id],
|
|
||||||
mutationFn: (name: string) => installPlugin(name, null),
|
|
||||||
});
|
|
||||||
|
|
||||||
const displayName = pluginInfo.data?.displayName ?? 'Unknown';
|
|
||||||
const uninstallPluginMutation = usePromptUninstall(plugin.id, displayName);
|
|
||||||
|
|
||||||
if (pluginInfo.isPending) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PluginTableRow
|
||||||
|
plugin={plugin}
|
||||||
|
version={info.version}
|
||||||
|
name={info.name}
|
||||||
|
displayName={info.displayName}
|
||||||
|
url={plugin.url}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function PluginTableRowForRemotePluginVersion({ pluginVersion }: { pluginVersion: PluginVersion }) {
|
||||||
|
const plugin = useAtomValue(pluginsAtom).find((p) => p.id === pluginVersion.id);
|
||||||
|
const pluginInfo = usePluginInfo(plugin?.id ?? null).data;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PluginTableRow
|
||||||
|
plugin={plugin ?? null}
|
||||||
|
version={pluginInfo?.version ?? pluginVersion.version}
|
||||||
|
name={pluginVersion.name}
|
||||||
|
displayName={pluginVersion.displayName}
|
||||||
|
url={pluginVersion.url}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function PluginTableRow({
|
||||||
|
plugin,
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
displayName,
|
||||||
|
url,
|
||||||
|
}: {
|
||||||
|
plugin: Plugin | null;
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
displayName: string;
|
||||||
|
url: string | null;
|
||||||
|
}) {
|
||||||
|
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);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell className="font-semibold">
|
<TableCell className="font-semibold">
|
||||||
{plugin.url ? (
|
{url ? (
|
||||||
<Link noUnderline href={plugin.url}>
|
<Link noUnderline href={url}>
|
||||||
{displayName}
|
{displayName}
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
@@ -140,33 +172,52 @@ function PluginTableRow({
|
|||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<InlineCode>{pluginInfo.data?.version ?? 'n/a'}</InlineCode>
|
<HStack space={1.5}>
|
||||||
|
<InlineCode>{version}</InlineCode>
|
||||||
|
{latestVersion != null && (
|
||||||
|
<InlineCode className="text-success flex items-center gap-1">
|
||||||
|
<Icon icon="arrow_up" size="sm" />
|
||||||
|
{latestVersion}
|
||||||
|
</InlineCode>
|
||||||
|
)}
|
||||||
|
</HStack>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell className="!py-0">
|
||||||
<HStack justifyContent="end">
|
<HStack justifyContent="end" space={1.5}>
|
||||||
{pluginInfo.data && latestVersion != null && (
|
{plugin != null && latestVersion != null ? (
|
||||||
<Button
|
<Button
|
||||||
variant="border"
|
variant="border"
|
||||||
color="success"
|
color="success"
|
||||||
title={`Update to ${latestVersion}`}
|
title={`Update to ${latestVersion}`}
|
||||||
size="xs"
|
size="xs"
|
||||||
isLoading={installPluginMutation.isPending}
|
isLoading={installPluginMutation.isPending}
|
||||||
onClick={() => installPluginMutation.mutate(pluginInfo.data.name)}
|
onClick={() => installPluginMutation.mutate(name)}
|
||||||
>
|
>
|
||||||
Update
|
Update
|
||||||
</Button>
|
</Button>
|
||||||
|
) : plugin == null ? (
|
||||||
|
<Button
|
||||||
|
variant="border"
|
||||||
|
color="primary"
|
||||||
|
title={`Install ${latestVersion}`}
|
||||||
|
size="xs"
|
||||||
|
isLoading={installPluginMutation.isPending}
|
||||||
|
onClick={() => installPluginMutation.mutate(name)}
|
||||||
|
>
|
||||||
|
Install
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
{uninstall != null && (
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
title="Uninstall plugin"
|
||||||
|
variant="border"
|
||||||
|
isLoading={uninstall.isPending}
|
||||||
|
onClick={() => uninstall.mutate()}
|
||||||
|
>
|
||||||
|
Uninstall
|
||||||
|
</Button>
|
||||||
)}
|
)}
|
||||||
<Button
|
|
||||||
size="xs"
|
|
||||||
title="Uninstall plugin"
|
|
||||||
variant="border"
|
|
||||||
isLoading={uninstallPluginMutation.isPending}
|
|
||||||
onClick={async () => {
|
|
||||||
uninstallPluginMutation.mutate();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Uninstall
|
|
||||||
</Button>
|
|
||||||
</HStack>
|
</HStack>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -209,20 +260,8 @@ function PluginSearch() {
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{results.data.plugins.map((plugin) => (
|
{results.data.plugins.map((p) => (
|
||||||
<TableRow key={plugin.id}>
|
<PluginTableRowForRemotePluginVersion key={p.id} pluginVersion={p} />
|
||||||
<TableCell className="font-semibold">
|
|
||||||
<Link noUnderline href={plugin.url}>
|
|
||||||
{plugin.displayName}
|
|
||||||
</Link>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
<InlineCode>{plugin.version}</InlineCode>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="w-[6rem]">
|
|
||||||
<InstallPluginButton pluginVersion={plugin} />
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
@@ -232,41 +271,8 @@ function PluginSearch() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function InstallPluginButton({ pluginVersion }: { pluginVersion: PluginVersion }) {
|
|
||||||
const plugins = useAtomValue(pluginsAtom);
|
|
||||||
const installed = plugins?.some((p) => p.id === pluginVersion.id);
|
|
||||||
const uninstallPluginMutation = usePromptUninstall(pluginVersion.id, pluginVersion.displayName);
|
|
||||||
const installPluginMutation = useMutation({
|
|
||||||
mutationKey: ['install_plugin', pluginVersion.id],
|
|
||||||
mutationFn: (pv: PluginVersion) => installPlugin(pv.name, null),
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
size="xs"
|
|
||||||
variant="border"
|
|
||||||
color={installed ? 'default' : 'primary'}
|
|
||||||
className="ml-auto"
|
|
||||||
isLoading={installPluginMutation.isPending || uninstallPluginMutation.isPending}
|
|
||||||
onClick={async () => {
|
|
||||||
if (installed) {
|
|
||||||
uninstallPluginMutation.mutate();
|
|
||||||
} else {
|
|
||||||
installPluginMutation.mutate(pluginVersion);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{installed ? 'Uninstall' : 'Install'}
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function InstalledPlugins() {
|
function InstalledPlugins() {
|
||||||
const plugins = useAtomValue(pluginsAtom);
|
const plugins = useAtomValue(pluginsAtom);
|
||||||
const updates = useQuery({
|
|
||||||
queryKey: ['plugin_updates'],
|
|
||||||
queryFn: () => checkPluginUpdates(),
|
|
||||||
});
|
|
||||||
|
|
||||||
return plugins.length === 0 ? (
|
return plugins.length === 0 ? (
|
||||||
<div className="pb-4">
|
<div className="pb-4">
|
||||||
@@ -286,18 +292,20 @@ function InstalledPlugins() {
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<tbody className="divide-y divide-surface-highlight">
|
<tbody className="divide-y divide-surface-highlight">
|
||||||
{plugins.map((p) => {
|
{plugins.map((p) => (
|
||||||
return <PluginTableRow key={p.id} plugin={p} updates={updates.data ?? null} />;
|
<PluginTableRowForInstalledPlugin key={p.id} plugin={p} />
|
||||||
})}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</Table>
|
</Table>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function usePromptUninstall(pluginId: string, name: string) {
|
function usePromptUninstall(pluginId: string | null, name: string) {
|
||||||
return useMutation({
|
const mut = useMutation({
|
||||||
mutationKey: ['uninstall_plugin', pluginId],
|
mutationKey: ['uninstall_plugin', pluginId],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
|
if (pluginId == null) return;
|
||||||
|
|
||||||
const confirmed = await showConfirmDelete({
|
const confirmed = await showConfirmDelete({
|
||||||
id: 'uninstall-plugin-' + pluginId,
|
id: 'uninstall-plugin-' + pluginId,
|
||||||
title: 'Uninstall Plugin',
|
title: 'Uninstall Plugin',
|
||||||
@@ -313,4 +321,13 @@ function usePromptUninstall(pluginId: string, name: string) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return pluginId == null ? null : mut;
|
||||||
|
}
|
||||||
|
|
||||||
|
function usePluginUpdates() {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['plugin_updates', usePluginsKey()],
|
||||||
|
queryFn: () => checkPluginUpdates(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ export const TabContent = memo(function TabContent({
|
|||||||
<div
|
<div
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
data-tab={value}
|
data-tab={value}
|
||||||
className={classNames(className, 'tab-content', 'hidden w-full h-full py-2')}
|
className={classNames(className, 'tab-content', 'hidden w-full h-full pt-2')}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,18 +6,21 @@ import { useAtomValue } from 'jotai';
|
|||||||
import { queryClient } from '../lib/queryClient';
|
import { queryClient } from '../lib/queryClient';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
|
|
||||||
function pluginInfoKey(id: string, plugin: Plugin | null) {
|
function pluginInfoKey(id: string | null, plugin: Plugin | null) {
|
||||||
return ['plugin_info', id, plugin?.updatedAt ?? 'n/a'];
|
return ['plugin_info', id ?? 'n/a', plugin?.updatedAt ?? 'n/a'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function usePluginInfo(id: string) {
|
export function usePluginInfo(id: string | null) {
|
||||||
const plugins = useAtomValue(pluginsAtom);
|
const plugins = useAtomValue(pluginsAtom);
|
||||||
// Get the plugin so we can refetch whenever it's updated
|
// Get the plugin so we can refetch whenever it's updated
|
||||||
const plugin = plugins.find((p) => p.id === id);
|
const plugin = plugins.find((p) => p.id === id);
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: pluginInfoKey(id, plugin ?? null),
|
queryKey: pluginInfoKey(id, plugin ?? null),
|
||||||
placeholderData: (prev) => prev, // Keep previous data on refetch
|
placeholderData: (prev) => prev, // Keep previous data on refetch
|
||||||
queryFn: () => invokeCmd<PluginMetadata>('cmd_plugin_info', { id }),
|
queryFn: () => {
|
||||||
|
if (id == null) return null;
|
||||||
|
return invokeCmd<PluginMetadata>('cmd_plugin_info', { id });
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user