| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 | 'use client'import type { FC } from 'react'import React, { useMemo, useState } from 'react'import { useTranslation } from 'react-i18next'import {  PortalToFollowElem,  PortalToFollowElemContent,  PortalToFollowElemTrigger,} from '@/app/components/base/portal-to-follow-elem'import AppTrigger from '@/app/components/plugins/plugin-detail-panel/app-selector/app-trigger'import AppPicker from '@/app/components/plugins/plugin-detail-panel/app-selector/app-picker'import AppInputsPanel from '@/app/components/plugins/plugin-detail-panel/app-selector/app-inputs-panel'import { useAppFullList } from '@/service/use-apps'import type { App } from '@/types/app'import type {  OffsetOptions,  Placement,} from '@floating-ui/react'type Props = {  value?: {    app_id: string    inputs: Record<string, any>    files?: any[]  }  scope?: string  disabled?: boolean  placement?: Placement  offset?: OffsetOptions  onSelect: (app: {    app_id: string    inputs: Record<string, any>    files?: any[]  }) => void  supportAddCustomTool?: boolean}const AppSelector: FC<Props> = ({  value,  scope,  disabled,  placement = 'bottom',  offset = 4,  onSelect,}) => {  const { t } = useTranslation()  const [isShow, onShowChange] = useState(false)  const handleTriggerClick = () => {    if (disabled) return    onShowChange(true)  }  const { data: appList } = useAppFullList()  const currentAppInfo = useMemo(() => {    if (!appList?.data || !value)      return undefined    return appList.data.find(app => app.id === value.app_id)  }, [appList?.data, value])  const [isShowChooseApp, setIsShowChooseApp] = useState(false)  const handleSelectApp = (app: App) => {    const clearValue = app.id !== value?.app_id    const appValue = {      app_id: app.id,      inputs: clearValue ? {} : value?.inputs || {},      files: clearValue ? [] : value?.files || [],    }    onSelect(appValue)    setIsShowChooseApp(false)  }  const handleFormChange = (inputs: Record<string, any>) => {    const newFiles = inputs['#image#']    delete inputs['#image#']    const newValue = {      app_id: value?.app_id || '',      inputs,      files: newFiles ? [newFiles] : value?.files || [],    }    onSelect(newValue)  }  const formattedValue = useMemo(() => {    return {      app_id: value?.app_id || '',      inputs: {        ...value?.inputs,        ...(value?.files?.length ? { '#image#': value.files[0] } : {}),      },    }  }, [value])  return (    <>      <PortalToFollowElem        placement={placement}        offset={offset}        open={isShow}        onOpenChange={onShowChange}      >        <PortalToFollowElemTrigger          className='w-full'          onClick={handleTriggerClick}        >          <AppTrigger            open={isShow}            appDetail={currentAppInfo}          />        </PortalToFollowElemTrigger>        <PortalToFollowElemContent className='z-[1000]'>          <div className="relative min-h-20 w-[389px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-sm">            <div className='flex flex-col gap-1 px-4 py-3'>              <div className='system-sm-semibold flex h-6 items-center text-text-secondary'>{t('app.appSelector.label')}</div>              <AppPicker                placement='bottom'                offset={offset}                trigger={                  <AppTrigger                    open={isShowChooseApp}                    appDetail={currentAppInfo}                  />                }                isShow={isShowChooseApp}                onShowChange={setIsShowChooseApp}                disabled={false}                appList={appList?.data || []}                onSelect={handleSelectApp}                scope={scope || 'all'}              />            </div>            {/* app inputs config panel */}            {currentAppInfo && (              <AppInputsPanel                value={formattedValue}                appDetail={currentAppInfo}                onFormChange={handleFormChange}              />            )}          </div>        </PortalToFollowElemContent>      </PortalToFollowElem>    </>  )}export default React.memo(AppSelector)
 |