Address PR review comments
This commit is contained in:
parent
f7d769ef18
commit
b6304635e7
11 changed files with 105 additions and 64 deletions
|
|
@ -32,11 +32,6 @@ export interface BrowseFilterAndSortActionSheetProps {
|
|||
/** Checked repository URLs. */
|
||||
checked: string[]
|
||||
setChecked: (urls: string[]) => void
|
||||
/** Available release channels across all listings. */
|
||||
channels: string[]
|
||||
/** Selected release channel. Empty string means default. */
|
||||
channel: string
|
||||
setChannel: (channel: string) => void
|
||||
sort: BrowseSortKey
|
||||
setSort: (sort: BrowseSortKey) => void
|
||||
reverse: boolean
|
||||
|
|
@ -47,9 +42,6 @@ export default function BrowseFilterAndSortActionSheet({
|
|||
repos,
|
||||
checked,
|
||||
setChecked,
|
||||
channels,
|
||||
channel,
|
||||
setChannel,
|
||||
sort,
|
||||
setSort,
|
||||
reverse,
|
||||
|
|
@ -84,19 +76,6 @@ export default function BrowseFilterAndSortActionSheet({
|
|||
)
|
||||
})}
|
||||
</TableRowGroup>
|
||||
<TableRadioGroup
|
||||
title="Release channel"
|
||||
defaultValue={channel}
|
||||
onChange={v => setChannel(v as string)}
|
||||
>
|
||||
<TableRadioRow
|
||||
label="Default (latest / first available)"
|
||||
value=""
|
||||
/>
|
||||
{channels.map(c => (
|
||||
<TableRadioRow key={c} label={c} value={c} />
|
||||
))}
|
||||
</TableRadioGroup>
|
||||
<TableRadioGroup
|
||||
title="Sort by"
|
||||
defaultValue={sort}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,19 @@
|
|||
import { getAssetIdByName } from '@revenge-mod/assets'
|
||||
import { ActionSheetActionCreators } from '@revenge-mod/discord/actions'
|
||||
import { Design } from '@revenge-mod/discord/design'
|
||||
import { useState } from 'react'
|
||||
import { PluginInfo } from './PluginCard'
|
||||
import { IdRow, RepositoryRow } from './PluginOptionsActionSheet'
|
||||
import type { RepoPluginListing } from '@revenge-mod/plugins/_/repositories'
|
||||
|
||||
const { ActionSheet, Button, Stack, TableRowGroup } = Design
|
||||
const {
|
||||
ActionSheet,
|
||||
Button,
|
||||
Stack,
|
||||
TableRowGroup,
|
||||
TableRadioGroup,
|
||||
TableRadioRow,
|
||||
} = Design
|
||||
|
||||
const DownloadIcon = getAssetIdByName('DownloadIcon', 'png')!
|
||||
|
||||
|
|
@ -15,9 +24,11 @@ export interface BrowsePluginActionSheetProps {
|
|||
version: string
|
||||
icon?: string
|
||||
id: string
|
||||
listing: RepoPluginListing
|
||||
channel: string
|
||||
/** Display text for the Repository row, eg. `Name (url)`. */
|
||||
repositoryText: string
|
||||
onInstall: () => void
|
||||
onInstall: (channel?: string, version?: string) => void
|
||||
sheetKey: string
|
||||
}
|
||||
|
||||
|
|
@ -31,17 +42,26 @@ export default function BrowsePluginActionSheet({
|
|||
version,
|
||||
icon,
|
||||
id,
|
||||
listing,
|
||||
channel,
|
||||
repositoryText,
|
||||
onInstall,
|
||||
sheetKey,
|
||||
}: BrowsePluginActionSheetProps) {
|
||||
const [selectedChannel, setSelectedChannel] = useState(channel)
|
||||
const selectedVersion = selectedChannel
|
||||
? (listing.channels[selectedChannel] ?? '')
|
||||
: version
|
||||
|
||||
const channelNames = Object.keys(listing.channels)
|
||||
|
||||
return (
|
||||
<ActionSheet>
|
||||
<Stack spacing={24} style={{ paddingTop: 8 }}>
|
||||
<PluginInfo
|
||||
name={name}
|
||||
author={author}
|
||||
version={version}
|
||||
version={selectedVersion}
|
||||
description={description}
|
||||
icon={icon}
|
||||
actions={
|
||||
|
|
@ -53,11 +73,26 @@ export default function BrowsePluginActionSheet({
|
|||
ActionSheetActionCreators.hideActionSheet(
|
||||
sheetKey,
|
||||
)
|
||||
onInstall()
|
||||
onInstall(selectedChannel, selectedVersion)
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{channelNames.length > 0 && (
|
||||
<TableRadioGroup
|
||||
title="Channel"
|
||||
defaultValue={selectedChannel}
|
||||
onChange={v => setSelectedChannel(v as string)}
|
||||
>
|
||||
{channelNames.map(c => (
|
||||
<TableRadioRow
|
||||
key={c}
|
||||
label={c}
|
||||
value={c}
|
||||
/>
|
||||
))}
|
||||
</TableRadioGroup>
|
||||
)}
|
||||
<TableRowGroup title="Advanced">
|
||||
<IdRow id={id} />
|
||||
<RepositoryRow text={repositoryText} copyable />
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import {
|
|||
useEssentialPluginTooltip,
|
||||
} from './TooltipProvider'
|
||||
import type { AnyPlugin, InternalPluginMeta } from '@revenge-mod/plugins/_'
|
||||
import type { RepoPluginListing } from '@revenge-mod/plugins/_/repositories'
|
||||
|
||||
const { Card, Text, Stack, IconButton, Button, createStyles } = Design
|
||||
|
||||
|
|
@ -262,6 +263,8 @@ export const BrowsePluginCard = memo(function BrowsePluginCard({
|
|||
author,
|
||||
icon,
|
||||
id,
|
||||
listing,
|
||||
channel,
|
||||
repositoryText,
|
||||
onInstall,
|
||||
}: {
|
||||
|
|
@ -271,8 +274,10 @@ export const BrowsePluginCard = memo(function BrowsePluginCard({
|
|||
author: string
|
||||
icon?: string
|
||||
id: string
|
||||
listing: RepoPluginListing
|
||||
channel: string
|
||||
repositoryText: string
|
||||
onInstall: () => void
|
||||
onInstall: (channel?: string, version?: string) => void
|
||||
}) {
|
||||
return (
|
||||
<PluginCard
|
||||
|
|
@ -295,6 +300,8 @@ export const BrowsePluginCard = memo(function BrowsePluginCard({
|
|||
version,
|
||||
icon,
|
||||
id,
|
||||
listing,
|
||||
channel,
|
||||
repositoryText,
|
||||
onInstall,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -121,7 +121,11 @@ export function BrowsePluginMasonryFlashList({
|
|||
onInstall,
|
||||
}: {
|
||||
entries: BrowseEntry[]
|
||||
onInstall: (entry: BrowseEntry) => void
|
||||
onInstall: (
|
||||
entry: BrowseEntry,
|
||||
channel?: string,
|
||||
version?: string,
|
||||
) => void
|
||||
}) {
|
||||
const numColumns = useNumColumns()
|
||||
const resetTooltips = useResetTooltips()
|
||||
|
|
@ -152,8 +156,12 @@ export function BrowsePluginMasonryFlashList({
|
|||
author={listing.author}
|
||||
icon={listing.icon ?? undefined}
|
||||
id={listing.id}
|
||||
listing={listing}
|
||||
channel={entry.channel ?? ''}
|
||||
repositoryText={entry.repositoryText}
|
||||
onInstall={() => onInstall(entry)}
|
||||
onInstall={(channel, version) =>
|
||||
onInstall(entry, channel, version)
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -179,12 +179,11 @@ function AdvancedSection({ plugin }: { plugin: AnyPlugin }) {
|
|||
subLabel={`${name} depends on ${dependencies.length} other plugins`}
|
||||
onPress={() => {
|
||||
ActionSheetActionCreators.openLazy(
|
||||
import('./PluginListActionSheet'),
|
||||
import('./PluginRelationsListActionSheet'),
|
||||
`plugin-deps-${id}`,
|
||||
{
|
||||
title: `Dependencies of ${name}`,
|
||||
plugins: dependencies,
|
||||
sheetKey: `plugin-deps-${id}`,
|
||||
},
|
||||
)
|
||||
}}
|
||||
|
|
@ -197,12 +196,11 @@ function AdvancedSection({ plugin }: { plugin: AnyPlugin }) {
|
|||
subLabel={`${dependents.length} other plugins depend on ${name}`}
|
||||
onPress={() => {
|
||||
ActionSheetActionCreators.openLazy(
|
||||
import('./PluginListActionSheet'),
|
||||
import('./PluginRelationsListActionSheet'),
|
||||
`plugin-dependents-${id}`,
|
||||
{
|
||||
title: `Dependents of ${name}`,
|
||||
plugins: dependents,
|
||||
sheetKey: `plugin-dependents-${id}`,
|
||||
},
|
||||
)
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -4,16 +4,15 @@ import type { AnyPlugin } from '@revenge-mod/plugins/_'
|
|||
|
||||
const { ActionSheet, Stack, TableRow, TableRowGroup } = Design
|
||||
|
||||
export interface PluginListActionSheetProps {
|
||||
export interface PluginRelationsListActionSheetProps {
|
||||
title: string
|
||||
plugins: AnyPlugin[]
|
||||
sheetKey: string
|
||||
}
|
||||
|
||||
export default function PluginListActionSheet({
|
||||
export default function PluginRelationsListActionSheet({
|
||||
title,
|
||||
plugins,
|
||||
}: PluginListActionSheetProps) {
|
||||
}: PluginRelationsListActionSheetProps) {
|
||||
return (
|
||||
<ActionSheet>
|
||||
<Stack spacing={24} style={{ paddingTop: 8 }}>
|
||||
|
|
@ -18,8 +18,7 @@ export default function RepoRemoveConfirmationAlert({
|
|||
<Text variant="text-md/semibold" color="text-default">
|
||||
{repo.name ?? repo.url}
|
||||
</Text>{' '}
|
||||
will be removed. You can restore the default repositories by
|
||||
clearing Plugin Settings data.
|
||||
will be removed.
|
||||
</Text>
|
||||
}
|
||||
actions={
|
||||
|
|
|
|||
|
|
@ -7,14 +7,16 @@ import { noop } from '@revenge-mod/utils/callback'
|
|||
import { api } from '.'
|
||||
import type { Repo, RepoConfigEntry } from '@revenge-mod/plugins/_/repositories'
|
||||
|
||||
export async function addDefaultRepoIfNeeded() {
|
||||
if (!__BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__) return
|
||||
export async function addDefaultRepoIfNeeded(
|
||||
refresh = false,
|
||||
): Promise<boolean> {
|
||||
if (!__BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__) return false
|
||||
|
||||
const repos = await listRepos()
|
||||
if (
|
||||
repos.some(repo => repo.url === __BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__)
|
||||
)
|
||||
return
|
||||
return false
|
||||
|
||||
const userRepos = toConfig(repos.filter(repo => !repo.internal))
|
||||
await setRepos([
|
||||
|
|
@ -24,7 +26,10 @@ export async function addDefaultRepoIfNeeded() {
|
|||
|
||||
await api.jsonStorage.set({ defaultRepoRestored: true }).catch(noop)
|
||||
|
||||
await refreshRepo(__BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__).catch(noop)
|
||||
if (refresh)
|
||||
await refreshRepo(__BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__).catch(noop)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export function toConfig(list: Repo[]): RepoConfigEntry[] {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { FormSwitch } from '@revenge-mod/components'
|
|||
import { styles } from '@revenge-mod/components/_'
|
||||
import Page from '@revenge-mod/components/Page'
|
||||
import TableRowAssetIcon from '@revenge-mod/components/TableRowAssetIcon'
|
||||
import { ToastActionCreators } from '@revenge-mod/discord/actions'
|
||||
import { Design } from '@revenge-mod/discord/design'
|
||||
import { Clipboard } from '@revenge-mod/externals/react-native-clipboard'
|
||||
import { callNativeMethod } from '@revenge-mod/modules/native'
|
||||
|
|
@ -373,11 +374,18 @@ export default function RevengePluginsAdvancedSettingScreen() {
|
|||
<TableRow
|
||||
icon={<TableRowAssetIcon name="GlobeEarthIcon" />}
|
||||
label="Restore default repositories"
|
||||
subLabel="Add the bundled default repository if it's missing"
|
||||
onPress={() => {
|
||||
addDefaultRepoIfNeeded().catch(e =>
|
||||
showErrorToast(messageOf(e)),
|
||||
)
|
||||
onPress={async () => {
|
||||
try {
|
||||
const restored =
|
||||
await addDefaultRepoIfNeeded(true)
|
||||
if (!restored)
|
||||
ToastActionCreators.open({
|
||||
key: 'revenge-default-repo-nothing',
|
||||
content: 'No default repository to restore',
|
||||
})
|
||||
} catch (e) {
|
||||
showErrorToast(messageOf(e))
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</TableRowGroup>
|
||||
|
|
|
|||
|
|
@ -82,18 +82,15 @@ function Screen() {
|
|||
const [excluded, setExcluded] = useState<string[]>([])
|
||||
const [sort, setSort] = useState<BrowseSortKey>('name')
|
||||
const [reverse, setReverse] = useState(false)
|
||||
const [channel, setChannel] = useState('')
|
||||
const [channels, setChannels] = useState<string[]>([])
|
||||
|
||||
const hasFilter = useMemo(
|
||||
() => excluded.length > 0 || sort !== 'name' || reverse || channel !== '',
|
||||
[excluded, sort, reverse, channel],
|
||||
() => excluded.length > 0 || sort !== 'name' || reverse,
|
||||
[excluded, sort, reverse],
|
||||
)
|
||||
|
||||
const load = useCallback(async () => {
|
||||
const repos = await listRepos()
|
||||
const all: BrowseEntry[] = []
|
||||
const allChannels = new Set<string>()
|
||||
|
||||
setInternalRepos(
|
||||
repos.filter(repo => repo.internal).map(repo => repo.url),
|
||||
|
|
@ -111,9 +108,7 @@ function Screen() {
|
|||
|
||||
for (const listing of listings) {
|
||||
const plugin = pList.get(listing.id)
|
||||
for (const c of Object.keys(listing.channels))
|
||||
allChannels.add(c)
|
||||
const displayChannel = displayChannelOf(listing, channel)
|
||||
const displayChannel = displayChannelOf(listing, '')
|
||||
const displayVersion = displayChannel
|
||||
? (listing.channels[displayChannel] ?? '')
|
||||
: ''
|
||||
|
|
@ -143,9 +138,8 @@ function Screen() {
|
|||
),
|
||||
)
|
||||
|
||||
setChannels([...allChannels].sort())
|
||||
setEntries(all)
|
||||
}, [channel, setChannels])
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
// Show cached indexes right away, then refresh everything
|
||||
|
|
@ -167,12 +161,24 @@ function Screen() {
|
|||
}, [load])
|
||||
|
||||
const install = useCallback(
|
||||
async (entry: BrowseEntry) => {
|
||||
async (
|
||||
entry: BrowseEntry,
|
||||
channel?: string,
|
||||
version?: string,
|
||||
) => {
|
||||
const targetChannel = channel || entry.channel
|
||||
const targetVersion =
|
||||
version ||
|
||||
(targetChannel
|
||||
? (entry.listing.channels[targetChannel] ?? '')
|
||||
: '') ||
|
||||
entry.version
|
||||
|
||||
// Pin the displayed version, channel, and repository, so the plan matches the card
|
||||
await runInstallFlow(
|
||||
entry.listing.id,
|
||||
entry.version || undefined,
|
||||
entry.channel,
|
||||
targetVersion || undefined,
|
||||
targetChannel,
|
||||
// Internal repos so external plugins can link against internal plugins as well
|
||||
[...internalRepos, entry.repoUrl],
|
||||
)
|
||||
|
|
@ -239,9 +245,6 @@ function Screen() {
|
|||
.map(repo => repo.url)
|
||||
.filter(url => !urls.includes(url)),
|
||||
),
|
||||
channels,
|
||||
channel,
|
||||
setChannel,
|
||||
sort,
|
||||
setSort,
|
||||
reverse,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import PluginClearDataConfirmationAlert from '../components/PluginClearDataConfi
|
|||
import PluginHasDependenciesAlert from '../components/PluginHasDependenciesAlert'
|
||||
import PluginHasDependentsAlert from '../components/PluginHasDependentsAlert'
|
||||
import PluginMissingDependenciesAlert from '../components/PluginMissingDependenciesAlert'
|
||||
import PluginStatesProvider from '../components/PluginStatesProvider'
|
||||
import PluginStatesProvider from '../components/PluginStateProvider'
|
||||
import PluginUninstallConfirmationAlert from '../components/PluginUninstallConfirmationAlert'
|
||||
import RepoRemoveConfirmationAlert from '../components/RepoRemoveConfirmationAlert'
|
||||
import type { Repo } from '@revenge-mod/plugins/_/repositories'
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue