'use client' import React, { useState } from 'react' import Modal from '@/app/components/base/modal' import Button from '@/app/components/base/button' import type { Item } from '@/app/components/base/select' import { PortalSelect } from '@/app/components/base/select' import type { GitHubRepoReleaseResponse } from '@/app/components/plugins/types' import { installPackageFromGitHub } from '@/service/plugins' import Toast from '@/app/components/base/toast' type InstallFromGitHubProps = { onClose: () => void } type InstallStep = 'url' | 'version' | 'package' | 'installed' type GitHubUrlInfo = { isValid: boolean owner?: string repo?: string } const InstallFromGitHub: React.FC = ({ onClose }) => { const [step, setStep] = useState('url') const [repoUrl, setRepoUrl] = useState('') const [selectedVersion, setSelectedVersion] = useState('') const [selectedPackage, setSelectedPackage] = useState('') const [releases, setReleases] = useState([]) const versions: Item[] = releases.map(release => ({ value: release.tag_name, name: release.tag_name, })) const packages: Item[] = selectedVersion ? (releases .find(release => release.tag_name === selectedVersion) ?.assets.map(asset => ({ value: asset.browser_download_url, name: asset.name, })) || []) : [] const parseGitHubUrl = (url: string): GitHubUrlInfo => { const githubUrlRegex = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/?$/ const match = url.match(githubUrlRegex) if (match) { return { isValid: true, owner: match[1], repo: match[2], } } return { isValid: false } } const handleInstall = async () => { try { const response = await installPackageFromGitHub({ repo: repoUrl, version: selectedVersion, package: selectedPackage }) if (response.plugin_unique_identifier) { setStep('installed') console.log('Package installed:') } else { console.error('Failed to install package:') } } catch (error) { console.error('Error installing package:') } } const handleNext = async () => { switch (step) { case 'url': { const { isValid, owner, repo } = parseGitHubUrl(repoUrl) if (!isValid || !owner || !repo) { Toast.notify({ type: 'error', message: 'Invalid GitHub URL. Please enter a valid URL in the format: https://github.com/owner/repo', }) break } try { const res = await fetch(`https://api.github.com/repos/${owner}/${repo}/releases`) if (!res.ok) throw new Error('Failed to fetch releases') const data = await res.json() const formattedReleases = data.map((release: any) => ({ tag_name: release.tag_name, assets: release.assets.map((asset: any) => ({ browser_download_url: asset.browser_download_url, id: asset.id, name: asset.name, })), })) setReleases(formattedReleases) setStep('version') } catch (error) { Toast.notify({ type: 'error', message: 'Failed to fetch repository release', }) } break } case 'version': setStep('package') break case 'package': handleInstall() break } } const isInputValid = () => { switch (step) { case 'url': return !!repoUrl.trim() case 'version': return !!selectedVersion case 'package': return !!selectedPackage default: return true } } const InfoRow = ({ label, value }: { label: string; value: string }) => (
{label}
{value}
) return (
Install plugin from GitHub
{step !== 'installed' && 'Please make sure that you only install plugins from a trusted source.'}
{step === 'url' && ( <> setRepoUrl(e.target.value)} // TODO: needs to verify the url className='flex items-center self-stretch rounded-lg border border-components-input-border-active bg-components-input-bg-active shadows-shadow-xs p-2 gap-[2px] flex-grow overflow-hidden text-components-input-text-filled text-ellipsis system-sm-regular' placeholder='Please enter GitHub repo URL' /> )} {step === 'version' && ( <> setSelectedVersion(item.value as string)} items={versions} placeholder="Please select a version" popupClassName='w-[432px] z-[1001]' /> )} {step === 'package' && ( <> setSelectedPackage(item.value as string)} items={packages} placeholder="Please select a package" popupClassName='w-[432px] z-[1001]' /> )} {step === 'installed' && ( <>
The plugin has been installed successfully.
{[ { label: 'Repository', value: repoUrl }, { label: 'Version', value: selectedVersion }, { label: 'Package', value: selectedPackage }, ].map(({ label, value }) => ( ))}
)}
{step === 'installed' ? ( ) : ( <> )}
) } export default InstallFromGitHub