You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

loaded.tsx 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. 'use client'
  2. import React, { useEffect } from 'react'
  3. import Button from '@/app/components/base/button'
  4. import { type Plugin, type PluginDeclaration, TaskStatus, type UpdateFromGitHubPayload } from '../../../types'
  5. import Card from '../../../card'
  6. import { pluginManifestToCardPluginProps } from '../../utils'
  7. import { useTranslation } from 'react-i18next'
  8. import { updateFromGitHub } from '@/service/plugins'
  9. import { useInstallPackageFromGitHub } from '@/service/use-plugins'
  10. import { RiLoader2Line } from '@remixicon/react'
  11. import { usePluginTaskList } from '@/service/use-plugins'
  12. import checkTaskStatus from '../../base/check-task-status'
  13. import useCheckInstalled from '@/app/components/plugins/install-plugin/hooks/use-check-installed'
  14. import { parseGitHubUrl } from '../../utils'
  15. import Version from '../../base/version'
  16. type LoadedProps = {
  17. updatePayload: UpdateFromGitHubPayload
  18. uniqueIdentifier: string
  19. payload: PluginDeclaration | Plugin
  20. repoUrl: string
  21. selectedVersion: string
  22. selectedPackage: string
  23. onBack: () => void
  24. onStartToInstall?: () => void
  25. onInstalled: (notRefresh?: boolean) => void
  26. onFailed: (message?: string) => void
  27. }
  28. const i18nPrefix = 'plugin.installModal'
  29. const Loaded: React.FC<LoadedProps> = ({
  30. updatePayload,
  31. uniqueIdentifier,
  32. payload,
  33. repoUrl,
  34. selectedVersion,
  35. selectedPackage,
  36. onBack,
  37. onStartToInstall,
  38. onInstalled,
  39. onFailed,
  40. }) => {
  41. const { t } = useTranslation()
  42. const toInstallVersion = payload.version
  43. const pluginId = (payload as Plugin).plugin_id
  44. const { installedInfo, isLoading } = useCheckInstalled({
  45. pluginIds: [pluginId],
  46. enabled: !!pluginId,
  47. })
  48. const installedInfoPayload = installedInfo?.[pluginId]
  49. const installedVersion = installedInfoPayload?.installedVersion
  50. const hasInstalled = !!installedVersion
  51. const [isInstalling, setIsInstalling] = React.useState(false)
  52. const { mutateAsync: installPackageFromGitHub } = useInstallPackageFromGitHub()
  53. const { handleRefetch } = usePluginTaskList(payload.category)
  54. const { check } = checkTaskStatus()
  55. useEffect(() => {
  56. if (hasInstalled && uniqueIdentifier === installedInfoPayload.uniqueIdentifier)
  57. onInstalled()
  58. }, [hasInstalled])
  59. const handleInstall = async () => {
  60. if (isInstalling) return
  61. setIsInstalling(true)
  62. onStartToInstall?.()
  63. try {
  64. const { owner, repo } = parseGitHubUrl(repoUrl)
  65. let taskId
  66. let isInstalled
  67. if (updatePayload) {
  68. const { all_installed, task_id } = await updateFromGitHub(
  69. `${owner}/${repo}`,
  70. selectedVersion,
  71. selectedPackage,
  72. updatePayload.originalPackageInfo.id,
  73. uniqueIdentifier,
  74. )
  75. taskId = task_id
  76. isInstalled = all_installed
  77. }
  78. else {
  79. if (hasInstalled) {
  80. const {
  81. all_installed,
  82. task_id,
  83. } = await updateFromGitHub(
  84. `${owner}/${repo}`,
  85. selectedVersion,
  86. selectedPackage,
  87. installedInfoPayload.uniqueIdentifier,
  88. uniqueIdentifier,
  89. )
  90. taskId = task_id
  91. isInstalled = all_installed
  92. }
  93. else {
  94. const { all_installed, task_id } = await installPackageFromGitHub({
  95. repoUrl: `${owner}/${repo}`,
  96. selectedVersion,
  97. selectedPackage,
  98. uniqueIdentifier,
  99. })
  100. taskId = task_id
  101. isInstalled = all_installed
  102. }
  103. }
  104. if (isInstalled) {
  105. onInstalled()
  106. return
  107. }
  108. handleRefetch()
  109. const { status, error } = await check({
  110. taskId,
  111. pluginUniqueIdentifier: uniqueIdentifier,
  112. })
  113. if (status === TaskStatus.failed) {
  114. onFailed(error)
  115. return
  116. }
  117. onInstalled(true)
  118. }
  119. catch (e) {
  120. if (typeof e === 'string') {
  121. onFailed(e)
  122. return
  123. }
  124. onFailed()
  125. }
  126. finally {
  127. setIsInstalling(false)
  128. }
  129. }
  130. return (
  131. <>
  132. <div className='system-md-regular text-text-secondary'>
  133. <p>{t(`${i18nPrefix}.readyToInstall`)}</p>
  134. </div>
  135. <div className='flex flex-wrap content-start items-start gap-1 self-stretch rounded-2xl bg-background-section-burn p-2'>
  136. <Card
  137. className='w-full'
  138. payload={pluginManifestToCardPluginProps(payload as PluginDeclaration)}
  139. titleLeft={!isLoading && <Version
  140. hasInstalled={hasInstalled}
  141. installedVersion={installedVersion}
  142. toInstallVersion={toInstallVersion}
  143. />}
  144. />
  145. </div>
  146. <div className='mt-4 flex items-center justify-end gap-2 self-stretch'>
  147. {!isInstalling && (
  148. <Button variant='secondary' className='min-w-[72px]' onClick={onBack}>
  149. {t('plugin.installModal.back')}
  150. </Button>
  151. )}
  152. <Button
  153. variant='primary'
  154. className='flex min-w-[72px] space-x-0.5'
  155. onClick={handleInstall}
  156. disabled={isInstalling || isLoading}
  157. >
  158. {isInstalling && <RiLoader2Line className='h-4 w-4 animate-spin-slow' />}
  159. <span>{t(`${i18nPrefix}.${isInstalling ? 'installing' : 'install'}`)}</span>
  160. </Button>
  161. </div>
  162. </>
  163. )
  164. }
  165. export default Loaded