import { AlertOctagon, AlertTriangle, DownloadCloud, Github, HelpCircle, Trash2 } from 'lucide-react'; import cls from 'classnames'; import { type AddonData } from '~main/types'; import { api } from '~renderer/utils/api'; import TextButton from '~renderer/components/styled/TextButton'; import { ColoredText } from '~renderer/components/styled/ColoredText'; import IconSpinner from '~renderer/components/styled/IconSpinner'; import DialogButton from '~renderer/components/styled/DialogButton'; import { isNotUndef } from '~common/utils'; import CloseButton from '~renderer/components/styled/CloseButton'; import AddonDetail from './AddonDetail'; export type Dependencies = { [folder: string]: 'installed' | 'available' | string; }; export type LocalDependencies = { name: string; optional: boolean; status: 'installed' | 'available' | 'missing' | string; }[]; type Props = Omit & { row: number; dependencies: Dependencies; gitRef?: string; }; const toRepoUrl = (git?: string) => git ? git.replace(/\.git$/, '') : undefined; const AddonListItem = ({ row, dependencies, ...addon }: Props) => { const update = api.addons.update.useMutation(); const remove = api.addons.remove.useMutation(); const openLink = api.general.openLink.useMutation(); const repoUrl = toRepoUrl(addon.git); const localDependencies: LocalDependencies = [ ...(addon.toc?.Dependencies?.split(', ')?.map(d => [d, false] as const) ?? []), ...(addon.toc?.OptionalDeps?.split(', ')?.map(d => [d, true] as const) ?? []) ].map(([d, optional]) => ({ name: d, optional, status: dependencies[d] ?? 'missing' })); const warnings = [ addon.toc && addon.toc?.Interface !== '11200' ? { full: `This addon seems to be made for different game version (${addon.toc?.Interface}) and it may not function correctly`, short: 'Incorrect version' } : undefined, localDependencies.some(d => d.status !== 'installed' && !d.optional) ? { full: `This addon has missing dependencies: ${localDependencies .filter(d => d.status !== 'installed' && !d.optional) .map(d => d.name) .join(', ')}`, short: 'Missing dependencies' } : undefined ].filter(isNotUndef); return (
{addon.status === 'fetching' ? ( ) : ( ( )} > {open => ( )} )}
{addon.toc?.Title ?? addon.folder} {repoUrl && ( openLink.mutateAsync(repoUrl)} className="!p-1 text-blueGray/60 hocus:text-pink" /> )}
{addon.toc?.Notes ?? addon.description ?? ''}
{addon.status === 'downloading' ? ( <>

{addon.progress}

) : addon.status === 'invalid' ? (

{addon.error}

) : warnings.length ? (

{warnings[0].short}

) : (

{addon.status === 'upToDate' ? 'Up to date' : !addon.git ? 'Not versioned' : ''}

)} {addon.status === 'outOfDate' && ( update.mutateAsync({ toUpdate: [addon.folder] })} className="s1 -mx-2 justify-self-end" > Update )} {addon.status === 'available' ? ( update.mutateAsync({ toUpdate: [addon.folder] })} className="text-warmGreen" icon={DownloadCloud} size={18} title="Download" /> ) : ( (

Are you sure?


Are you sure you want to delete {addon.folder}{' '} addon?

This will delete all files in the addon folder.

{ await remove.mutateAsync({ toDelete: [addon.folder] }); close(); }} disabled={remove.isLoading} className="self-end text-red" > Delete
)} > {open => ( )}
)}
); }; export default AddonListItem;