import React, { useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' import { useBoolean } from 'ahooks' import { RiBugLine, RiCloseLine, RiHardDrive3Line, RiVerifiedBadgeLine, } from '@remixicon/react' import type { PluginDetail } from '../types' import { PluginSource } from '../types' import Description from '../card/base/description' import Icon from '../card/base/card-icon' import Title from '../card/base/title' import OrgInfo from '../card/base/org-info' import { useGitHubReleases } from '../install-plugin/hooks' import { compareVersion, getLatestVersion } from '@/utils/semver' import OperationDropdown from './operation-dropdown' import PluginInfo from '@/app/components/plugins/plugin-page/plugin-info' import ActionButton from '@/app/components/base/action-button' import Button from '@/app/components/base/button' import Badge from '@/app/components/base/badge' import Confirm from '@/app/components/base/confirm' import Tooltip from '@/app/components/base/tooltip' import Toast from '@/app/components/base/toast' import { BoxSparkleFill } from '@/app/components/base/icons/src/vender/plugin' import { Github } from '@/app/components/base/icons/src/public/common' import { uninstallPlugin } from '@/service/plugins' import { useGetLanguage } from '@/context/i18n' import { useModalContext } from '@/context/modal-context' import UpdateFromMarketplace from '@/app/components/plugins/update-plugin/from-market-place' import { API_PREFIX, MARKETPLACE_URL_PREFIX } from '@/config' import cn from '@/utils/classnames' const i18nPrefix = 'plugin.action' type Props = { detail: PluginDetail onHide: () => void onUpdate: () => void } const DetailHeader = ({ detail, onHide, onUpdate, }: Props) => { const { t } = useTranslation() const locale = useGetLanguage() const { fetchReleases } = useGitHubReleases() const { setShowUpdatePluginModal } = useModalContext() const { installation_id, source, tenant_id, version, latest_unique_identifier, latest_version, meta, } = detail const { author, name, label, description, icon, verified } = detail.declaration const isFromGitHub = source === PluginSource.github const isFromMarketplace = source === PluginSource.marketplace const hasNewVersion = useMemo(() => { if (isFromGitHub) return latest_version !== version if (isFromMarketplace) return !!latest_version && latest_version !== version return false }, [isFromGitHub, isFromMarketplace, latest_version, version]) const [isShowUpdateModal, { setTrue: showUpdateModal, setFalse: hideUpdateModal, }] = useBoolean(false) const handleUpdate = async () => { if (isFromMarketplace) { showUpdateModal() return } try { const fetchedReleases = await fetchReleases(author, name) if (fetchedReleases.length === 0) return const versions = fetchedReleases.map(release => release.tag_name) const latestVersion = getLatestVersion(versions) if (compareVersion(latestVersion, version) === 1) { setShowUpdatePluginModal({ onSaveCallback: () => { onUpdate() }, payload: { type: PluginSource.github, github: { originalPackageInfo: { id: installation_id, repo: meta!.repo, version: meta!.version, package: meta!.package, releases: fetchedReleases, }, }, }, }) } else { Toast.notify({ type: 'info', message: 'No new version available', }) } } catch { Toast.notify({ type: 'error', message: 'Failed to compare versions', }) } } const handleUpdatedFromMarketplace = () => { onUpdate() hideUpdateModal() } const [isShowPluginInfo, { setTrue: showPluginInfo, setFalse: hidePluginInfo, }] = useBoolean(false) const [isShowDeleteConfirm, { setTrue: showDeleteConfirm, setFalse: hideDeleteConfirm, }] = useBoolean(false) const [deleting, { setTrue: showDeleting, setFalse: hideDeleting, }] = useBoolean(false) const handleDelete = useCallback(async () => { showDeleting() const res = await uninstallPlugin(installation_id) hideDeleting() if (res.success) { hideDeleteConfirm() onUpdate() } }, [hideDeleteConfirm, hideDeleting, installation_id, showDeleting, onUpdate]) // #plugin TODO# used in apps // const usedInApps = 3 return (