From a7385a58df857ebb29a46d7fbd4265cd02992e23 Mon Sep 17 00:00:00 2001 From: Rosie Val Date: Sun, 9 Aug 2026 00:54:54 -0400 Subject: [PATCH] Add startup update-confirmation alert with plugin details --- lib/plugins/src/_internal/repositories.ts | 4 +- .../components/PluginUpdatesFoundAlert.tsx | 112 ++++++++++++++++++ src/plugins/start/settings.plugins/index.ts | 36 +++++- .../start/settings.plugins/utils/alerts.tsx | 13 +- 4 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 src/plugins/start/settings.plugins/components/PluginUpdatesFoundAlert.tsx diff --git a/lib/plugins/src/_internal/repositories.ts b/lib/plugins/src/_internal/repositories.ts index 6cccf8a..5b24068 100644 --- a/lib/plugins/src/_internal/repositories.ts +++ b/lib/plugins/src/_internal/repositories.ts @@ -160,6 +160,8 @@ export interface RepoUpdate { installed: string available: string channel: string + /** Repository URL this update was found in, added by {@link listAllUpdates}. */ + repo?: string } /** @@ -227,7 +229,7 @@ export async function listAllUpdates(): Promise<{ .map(repo => listUpdates(repo.url).then( result => { - updates.push(...result) + updates.push(...result.map(u => ({ ...u, repo: repo.url }))) }, error => { errors.push({ url: repo.url, error }) diff --git a/src/plugins/start/settings.plugins/components/PluginUpdatesFoundAlert.tsx b/src/plugins/start/settings.plugins/components/PluginUpdatesFoundAlert.tsx new file mode 100644 index 0000000..b5cab95 --- /dev/null +++ b/src/plugins/start/settings.plugins/components/PluginUpdatesFoundAlert.tsx @@ -0,0 +1,112 @@ +import { Design } from '@revenge-mod/discord/design' +import { + listRepoPlugins, + type RepoPluginListing, + type RepoUpdate, +} from '@revenge-mod/plugins/_/repositories' +import { useEffect, useState } from 'react' +import { View } from 'react-native' + +const { AlertModal, AlertActionButton, Text } = Design + +interface UpdateDetail { + id: string + name: string + author: string + installed: string + available: string + channel: string +} + +export default function PluginUpdatesFoundAlert({ + updates, + action, +}: { + updates: RepoUpdate[] + action: () => Promise +}) { + const [details, setDetails] = useState(null) + + useEffect(() => { + const repoMap = new Map() + for (const update of updates) { + const repo = update.repo! + if (!repoMap.has(repo)) repoMap.set(repo, []) + repoMap.get(repo)!.push(update) + } + + const allDetails: UpdateDetail[] = [] + + Promise.all( + [...repoMap.entries()].map(async ([repo, repoUpdates]) => { + let listings: RepoPluginListing[] + try { + listings = await listRepoPlugins(repo) + } catch { + listings = [] + } + + for (const update of repoUpdates) { + const listing = listings.find(l => l.id === update.id) + allDetails.push({ + id: update.id, + name: listing?.name ?? update.id, + author: listing?.author ?? 'Unknown', + installed: update.installed, + available: update.available, + channel: update.channel, + }) + } + }), + ).then(() => setDetails(allDetails)) + }, [updates]) + + return ( + + The following plugins have updates available: + + } + extraContent={ + + {details === null ? ( + Loading... + ) : ( + details.map(detail => ( + + + {detail.name} + + + {detail.installed} → {detail.available} ( + {detail.channel}) + + + by {detail.author} + + + )) + )} + + } + actions={ + <> + + + + } + /> + ) +} diff --git a/src/plugins/start/settings.plugins/index.ts b/src/plugins/start/settings.plugins/index.ts index bf33bfc..420bd40 100644 --- a/src/plugins/start/settings.plugins/index.ts +++ b/src/plugins/start/settings.plugins/index.ts @@ -7,12 +7,15 @@ import { registerInternalPlugin, } from '@revenge-mod/plugins/_' import { + listAllUpdates, refreshAllRepos, updateAllPlugins, } from '@revenge-mod/plugins/_/repositories' import { lookupGeneratedIconComponent } from '@revenge-mod/utils/discord' import pluginSettings from '../settings' +import { showPluginUpdatesFoundAlert } from './utils/alerts' import { addDefaultRepoIfNeeded } from './repos' +import { showErrorToast } from './utils/repos' import type { JsonStorage } from '@revenge-mod/json-storage' import type { PluginApi } from '@revenge-mod/plugins/types' @@ -78,12 +81,37 @@ function autoUpdateService(settings: Storage) { setTimeout(async () => { try { const { errors } = await refreshAllRepos() - await updateAllPlugins() - if (!errors.length) - await api.jsonStorage.set({ - lastUpdateCheck: Date.now(), + if (errors.length) { + ToastActionCreators.open({ + key: 'PLUGIN_UPDATE_CHECK_FAILED', + content: 'Failed to refresh some plugin repositories', + IconComponent: CircleXIconComponent, }) + return + } + + const { updates } = await listAllUpdates() + await api.jsonStorage.set({ lastUpdateCheck: Date.now() }) + + if (!updates.length) return + + showPluginUpdatesFoundAlert(updates, async () => { + const { errors: updateErrors } = await updateAllPlugins() + + if (updateErrors.length) { + showErrorToast( + updateErrors + .map(e => `${e.id}: ${e.error}`) + .join('\n'), + ) + } else { + ToastActionCreators.open({ + key: 'PLUGIN_UPDATES_INSTALLED', + content: 'Plugins will update on the next reload', + }) + } + }) } catch (e) { ToastActionCreators.open({ key: 'PLUGIN_UPDATE_CHECK_FAILED', diff --git a/src/plugins/start/settings.plugins/utils/alerts.tsx b/src/plugins/start/settings.plugins/utils/alerts.tsx index 88aa030..929ec43 100644 --- a/src/plugins/start/settings.plugins/utils/alerts.tsx +++ b/src/plugins/start/settings.plugins/utils/alerts.tsx @@ -13,8 +13,9 @@ import PluginHasDependentsAlert from '../components/PluginHasDependentsAlert' import PluginMissingDependenciesAlert from '../components/PluginMissingDependenciesAlert' import PluginStatesProvider from '../components/PluginStateProvider' import PluginUninstallConfirmationAlert from '../components/PluginUninstallConfirmationAlert' +import PluginUpdatesFoundAlert from '../components/PluginUpdatesFoundAlert' import RepoRemoveConfirmationAlert from '../components/RepoRemoveConfirmationAlert' -import type { Repo } from '@revenge-mod/plugins/_/repositories' +import type { Repo, RepoUpdate } from '@revenge-mod/plugins/_/repositories' import type { AnyPlugin } from '@revenge-mod/plugins/_' export function showPluginClearDataConfirmation( @@ -134,3 +135,13 @@ export function showPluginHasDependentsAlert( , ) } + +export function showPluginUpdatesFoundAlert( + updates: RepoUpdate[], + action: () => Promise, +) { + AlertActionCreators.openAlert( + 'plugin-updates-found', + , + ) +}