From 4e444cf55da89e2d91c5a5efdc73a7c6cd268451 Mon Sep 17 00:00:00 2001 From: Rosie Val Date: Sun, 16 Aug 2026 12:45:24 -0400 Subject: [PATCH] Address review comments on channel switching --- lib/discord/src/types/index.ts | 1 + .../components/PluginOptionsActionSheet.tsx | 216 ++++++++---------- .../start/settings.plugins/utils/repos.tsx | 18 ++ 3 files changed, 117 insertions(+), 118 deletions(-) diff --git a/lib/discord/src/types/index.ts b/lib/discord/src/types/index.ts index 5aa566d..87365ec 100644 --- a/lib/discord/src/types/index.ts +++ b/lib/discord/src/types/index.ts @@ -499,6 +499,7 @@ export namespace DiscordModules { extends TableRowGroupProps { children: ReactNode onChange: (value: T) => void + value?: T defaultValue?: T } diff --git a/src/plugins/start/settings.plugins/components/PluginOptionsActionSheet.tsx b/src/plugins/start/settings.plugins/components/PluginOptionsActionSheet.tsx index a3a4c42..c45b3a5 100644 --- a/src/plugins/start/settings.plugins/components/PluginOptionsActionSheet.tsx +++ b/src/plugins/start/settings.plugins/components/PluginOptionsActionSheet.tsx @@ -25,7 +25,6 @@ import { } from '@revenge-mod/plugins/_' import { listRepoPlugins, - listRepos, refreshRepo, } from '@revenge-mod/plugins/_/repositories' import { PluginStatus } from '@revenge-mod/plugins/constants' @@ -39,7 +38,11 @@ import { showPluginClearDataConfirmation, showPluginUninstallConfirmation, } from '../utils/alerts' -import { messageOf, runInstallFlow, showErrorToast } from '../utils/repos' +import { + messageOf, + runInstallFlowWithInternalRepos, + showErrorToast, +} from '../utils/repos' import { InstalledPluginSwitch, PluginInfo } from './PluginCard' import { usePluginEnabled, usePluginStatus } from './PluginStateProvider' import PluginTooltipsProvider, { @@ -47,7 +50,6 @@ import PluginTooltipsProvider, { usePluginTooltip, } from './TooltipProvider' import type { AnyPlugin } from '@revenge-mod/plugins/_' -import type { RepoPluginListing } from '@revenge-mod/plugins/_/repositories' export interface PluginOptionsActionSheetProps { plugin: AnyPlugin @@ -131,7 +133,8 @@ function PluginOptions({ plugin, sheetKey }: PluginOptionsActionSheetProps) { }} /> - + + ) } @@ -173,92 +176,72 @@ function StatusSection({ plugin }: { plugin: AnyPlugin }) { function ChannelSection({ plugin, - sheetKey, }: { plugin: AnyPlugin - sheetKey: string }) { const meta = getInternalPluginMeta(plugin) const source = meta.source if (isPluginInternal(meta) || !source?.repo) return null - const [listing, setListing] = useState(null) - const [resetKey, setResetKey] = useState(0) + const [channels, setChannels] = useState>({}) + const [selected, setSelected] = useState(source.channel) useEffect(() => { - let cancelled = false - ;(async () => { - try { - const listings = await listRepoPlugins(source.repo) - const found = listings.find(l => l.id === plugin.manifest.id) - if (found && !cancelled) setListing(found) - } catch { - try { - await refreshRepo(source.repo) - const listings = await listRepoPlugins(source.repo) - const found = listings.find(l => l.id === plugin.manifest.id) - if (found && !cancelled) setListing(found) - } catch {} - } - })() - return () => { - cancelled = true - } + listRepoPlugins(source.repo) + .then(listings => { + const listing = listings.find(l => l.id === plugin.manifest.id) + if (listing) setChannels(listing.channels) + }) + .catch(() => + refreshRepo(source.repo) + .then(() => listRepoPlugins(source.repo)) + .then(listings => { + const listing = listings.find( + l => l.id === plugin.manifest.id, + ) + if (listing) setChannels(listing.channels) + }) + .catch(() => {}), + ) }, [source.repo, plugin.manifest.id]) - if (!listing || Object.keys(listing.channels).length === 0) return null + if (Object.keys(channels).length === 0) return null - const handleChange = async (selected: string) => { - if (selected === source.channel) return - - const targetVersion = listing.channels[selected] - if (!targetVersion) return + const handleChange = (value: string) => { + setSelected(value) + const targetVersion = channels[value]! if (targetVersion === plugin.manifest.version) { - setResetKey(k => k + 1) ToastActionCreators.open({ - key: 'REVENGE_PLUGIN_CHANNEL_UP_TO_DATE', - content: 'This channel is already installed', + key: 'REVENGE_PLUGIN_VERSION_ALREADY_INSTALLED', + content: 'This version is already installed', IconComponent: () => , }) return } - const repos = await listRepos() - const internalUrls = repos - .filter(r => r.internal) - .map(r => r.url) - - ActionSheetActionCreators.hideActionSheet(sheetKey) - runInstallFlow( + runInstallFlowWithInternalRepos( plugin.manifest.id, undefined, - selected, - [...internalUrls, source.repo], + value, + source.repo, ) } return ( handleChange(v as string)} > - {Object.keys(listing.channels).map(c => ( + {Object.keys(channels).map(c => ( ))} ) } -function AdvancedSection({ - plugin, - sheetKey, -}: { - plugin: AnyPlugin - sheetKey: string -}) { +function AdvancedSection({ plugin }: { plugin: AnyPlugin }) { const meta = getInternalPluginMeta(plugin) const dependents = getPluginDependents(plugin, true) const dependencies = getPluginDependencies(plugin, false) @@ -266,73 +249,70 @@ function AdvancedSection({ const { id, name } = plugin.manifest return ( - <> - - - - + + + + } + label="Flags" + subLabel={bitFieldToString(PluginFlags, meta.flags)} + /> + {meta.iflags > 0 && ( } - label="Flags" - subLabel={bitFieldToString(PluginFlags, meta.flags)} + label="Internal Flags" + subLabel={bitFieldToString( + InternalPluginFlags, + meta.iflags, + )} /> - {meta.iflags > 0 && ( - } - label="Internal Flags" - subLabel={bitFieldToString( - InternalPluginFlags, - meta.iflags, - )} - /> - )} - {dependencies.length > 0 && ( - } - label="Dependencies" - subLabel={`${name} depends on ${dependencies.length} other plugins`} - onPress={() => { - ActionSheetActionCreators.openLazy( - import('./PluginRelationsListActionSheet'), - `plugin-deps-${id}`, - { - title: `Dependencies of ${name}`, - unsatisfiedTitle: `Unsatisfied dependencies of ${name}`, - unsatisfiedPlugins: - meta.unsatisfiedOptionalDependencies.map( - id => pList.get(id) ?? id, - ), - plugins: dependencies, - dependencyMap: plugin.manifest.dependencies!, - }, - 'stack', - ) - }} - /> - )} - {dependents.length > 0 && ( - } - label="Dependents" - subLabel={`${dependents.length} other plugins depend on ${name}`} - onPress={() => { - ActionSheetActionCreators.openLazy( - import('./PluginRelationsListActionSheet'), - `plugin-dependents-${id}`, - { - title: `Dependents of ${name}`, - plugins: dependents, - }, - 'stack', - ) - }} - /> - )} - - + )} + {dependencies.length > 0 && ( + } + label="Dependencies" + subLabel={`${name} depends on ${dependencies.length} other plugins`} + onPress={() => { + ActionSheetActionCreators.openLazy( + import('./PluginRelationsListActionSheet'), + `plugin-deps-${id}`, + { + title: `Dependencies of ${name}`, + unsatisfiedTitle: `Unsatisfied dependencies of ${name}`, + unsatisfiedPlugins: + meta.unsatisfiedOptionalDependencies.map( + id => pList.get(id) ?? id, + ), + plugins: dependencies, + dependencyMap: plugin.manifest.dependencies!, + }, + 'stack', + ) + }} + /> + )} + {dependents.length > 0 && ( + } + label="Dependents" + subLabel={`${dependents.length} other plugins depend on ${name}`} + onPress={() => { + ActionSheetActionCreators.openLazy( + import('./PluginRelationsListActionSheet'), + `plugin-dependents-${id}`, + { + title: `Dependents of ${name}`, + plugins: dependents, + }, + 'stack', + ) + }} + /> + )} + ) } diff --git a/src/plugins/start/settings.plugins/utils/repos.tsx b/src/plugins/start/settings.plugins/utils/repos.tsx index f470e48..ef4ca28 100644 --- a/src/plugins/start/settings.plugins/utils/repos.tsx +++ b/src/plugins/start/settings.plugins/utils/repos.tsx @@ -170,3 +170,21 @@ export async function runInstallFlow( return false } } + +/** + * Same as {@link runInstallFlow}, but automatically includes every internal repository plus + * the target repository in `filteredRepos`, so repo-installed plugins can be updated in place. + */ +export async function runInstallFlowWithInternalRepos( + id: string, + version?: string, + channel?: string, + repo?: string, +): Promise { + const repos = await listRepos() + const filteredRepos = repos + .filter(r => r.internal) + .map(r => r.url) + if (repo) filteredRepos.push(repo) + return runInstallFlow(id, version, channel, filteredRepos) +}