index.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. 'use client'
  2. import type { FC } from 'react'
  3. import React, { useEffect } from 'react'
  4. import { useRouter } from 'next/navigation'
  5. import { useTranslation } from 'react-i18next'
  6. import { useContext } from 'use-context-selector'
  7. import Toast from '../../base/toast'
  8. import s from './style.module.css'
  9. import ExploreContext from '@/context/explore-context'
  10. import type { App } from '@/models/explore'
  11. import Category from '@/app/components/explore/category'
  12. import AppCard from '@/app/components/explore/app-card'
  13. import { fetchAppDetail, fetchAppList, installApp } from '@/service/explore'
  14. import { createApp } from '@/service/apps'
  15. import CreateAppModal from '@/app/components/explore/create-app-modal'
  16. import Loading from '@/app/components/base/loading'
  17. import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
  18. const Apps: FC = () => {
  19. const { t } = useTranslation()
  20. const router = useRouter()
  21. const { setControlUpdateInstalledApps, hasEditPermission } = useContext(ExploreContext)
  22. const [currCategory, setCurrCategory] = React.useState('')
  23. const [allList, setAllList] = React.useState<App[]>([])
  24. const [isLoaded, setIsLoaded] = React.useState(false)
  25. const currList = (() => {
  26. if (currCategory === '')
  27. return allList
  28. return allList.filter(item => item.category === currCategory)
  29. })()
  30. const [categories, setCategories] = React.useState([])
  31. useEffect(() => {
  32. (async () => {
  33. const { categories, recommended_apps }: any = await fetchAppList()
  34. setCategories(categories)
  35. setAllList(recommended_apps)
  36. setIsLoaded(true)
  37. })()
  38. }, [])
  39. const handleAddToWorkspace = async (appId: string) => {
  40. await installApp(appId)
  41. Toast.notify({
  42. type: 'success',
  43. message: t('common.api.success'),
  44. })
  45. setControlUpdateInstalledApps(Date.now())
  46. }
  47. const [currApp, setCurrApp] = React.useState<App | null>(null)
  48. const [isShowCreateModal, setIsShowCreateModal] = React.useState(false)
  49. const onCreate = async ({ name, icon, icon_background }: any) => {
  50. const { app_model_config: model_config } = await fetchAppDetail(currApp?.app.id as string)
  51. try {
  52. const app = await createApp({
  53. name,
  54. icon,
  55. icon_background,
  56. mode: currApp?.app.mode as any,
  57. config: model_config,
  58. })
  59. setIsShowCreateModal(false)
  60. Toast.notify({
  61. type: 'success',
  62. message: t('app.newApp.appCreated'),
  63. })
  64. localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
  65. router.push(`/app/${app.id}/overview`)
  66. }
  67. catch (e) {
  68. Toast.notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
  69. }
  70. }
  71. if (!isLoaded) {
  72. return (
  73. <div className='flex h-full items-center'>
  74. <Loading type='area' />
  75. </div>
  76. )
  77. }
  78. return (
  79. <div className='h-full flex flex-col border-l border-gray-200'>
  80. <div className='shrink-0 pt-6 px-12'>
  81. <div className={`mb-1 ${s.textGradient} text-xl font-semibold`}>{t('explore.apps.title')}</div>
  82. <div className='text-gray-500 text-sm'>{t('explore.apps.description')}</div>
  83. </div>
  84. <Category
  85. className='mt-6 px-12'
  86. list={categories}
  87. value={currCategory}
  88. onChange={setCurrCategory}
  89. />
  90. <div
  91. className='flex mt-6 flex-col overflow-auto bg-gray-100 shrink-0 grow'
  92. style={{
  93. maxHeight: 'calc(100vh - 243px)',
  94. }}
  95. >
  96. <nav
  97. className={`${s.appList} grid content-start grid-cols-1 gap-4 px-12 pb-10grow shrink-0`}>
  98. {currList.map(app => (
  99. <AppCard
  100. key={app.app_id}
  101. app={app}
  102. canCreate={hasEditPermission}
  103. onCreate={() => {
  104. setCurrApp(app)
  105. setIsShowCreateModal(true)
  106. }}
  107. onAddToWorkspace={handleAddToWorkspace}
  108. />
  109. ))}
  110. </nav>
  111. </div>
  112. {isShowCreateModal && (
  113. <CreateAppModal
  114. appName={currApp?.app.name || ''}
  115. show={isShowCreateModal}
  116. onConfirm={onCreate}
  117. onHide={() => setIsShowCreateModal(false)}
  118. />
  119. )}
  120. </div>
  121. )
  122. }
  123. export default React.memo(Apps)