feat: tooltip (#7634)

This commit is contained in:
Yi Xiao 2024-08-26 13:00:02 +08:00 committed by GitHub
parent 1ba3d3acd6
commit 3be756eaed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
93 changed files with 640 additions and 758 deletions

View File

@ -10,7 +10,7 @@ import { TracingProvider } from './type'
import ProviderConfigModal from './provider-config-modal' import ProviderConfigModal from './provider-config-modal'
import Indicator from '@/app/components/header/indicator' import Indicator from '@/app/components/header/indicator'
import Switch from '@/app/components/base/switch' import Switch from '@/app/components/base/switch'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
const I18N_PREFIX = 'app.tracing' const I18N_PREFIX = 'app.tracing'
@ -121,12 +121,11 @@ const ConfigPopup: FC<PopupProps> = ({
<> <>
{providerAllNotConfigured {providerAllNotConfigured
? ( ? (
<TooltipPlus <Tooltip
popupContent={t(`${I18N_PREFIX}.disabledTip`)} popupContent={t(`${I18N_PREFIX}.disabledTip`)}
> >
{switchContent} {switchContent}
</Tooltip>
</TooltipPlus>
) )
: switchContent} : switchContent}
</> </>

View File

@ -3,7 +3,7 @@ import { ChevronDoubleDownIcon } from '@heroicons/react/20/solid'
import type { FC } from 'react' import type { FC } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import React, { useCallback } from 'react' import React, { useCallback } from 'react'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
const I18N_PREFIX = 'app.tracing' const I18N_PREFIX = 'app.tracing'
@ -25,9 +25,8 @@ const ToggleFoldBtn: FC<Props> = ({
return ( return (
// text-[0px] to hide spacing between tooltip elements // text-[0px] to hide spacing between tooltip elements
<div className='shrink-0 cursor-pointer text-[0px]' onClick={handleFoldChange}> <div className='shrink-0 cursor-pointer text-[0px]' onClick={handleFoldChange}>
<TooltipPlus <Tooltip
popupContent={t(`${I18N_PREFIX}.${isFold ? 'expand' : 'collapse'}`)} popupContent={t(`${I18N_PREFIX}.${isFold ? 'expand' : 'collapse'}`)}
hideArrow
> >
{isFold && ( {isFold && (
<div className='p-1 rounded-md text-gray-500 hover:text-gray-800 hover:bg-black/5'> <div className='p-1 rounded-md text-gray-500 hover:text-gray-800 hover:bg-black/5'>
@ -39,7 +38,7 @@ const ToggleFoldBtn: FC<Props> = ({
<ChevronDoubleDownIcon className='w-4 h-4 transform rotate-180' /> <ChevronDoubleDownIcon className='w-4 h-4 transform rotate-180' />
</div> </div>
)} )}
</TooltipPlus> </Tooltip>
</div> </div>
) )
} }

View File

@ -4,9 +4,7 @@ import { useContext } from 'use-context-selector'
import { useRouter } from 'next/navigation' import { useRouter } from 'next/navigation'
import { useCallback, useEffect, useState } from 'react' import { useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { import { RiMoreFill } from '@remixicon/react'
RiMoreFill,
} from '@remixicon/react'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import Confirm from '@/app/components/base/confirm' import Confirm from '@/app/components/base/confirm'
import { ToastContext } from '@/app/components/base/toast' import { ToastContext } from '@/app/components/base/toast'
@ -129,10 +127,9 @@ const DatasetCard = ({
<div className={cn('truncate', !dataset.embedding_available && 'opacity-50 hover:opacity-100')} title={dataset.name}>{dataset.name}</div> <div className={cn('truncate', !dataset.embedding_available && 'opacity-50 hover:opacity-100')} title={dataset.name}>{dataset.name}</div>
{!dataset.embedding_available && ( {!dataset.embedding_available && (
<Tooltip <Tooltip
selector={`dataset-tag-${dataset.id}`} popupContent={t('dataset.unavailableTip')}
htmlContent={t('dataset.unavailableTip')}
> >
<span className='shrink-0 inline-flex w-max ml-1 px-1 border boder-gray-200 rounded-md text-gray-500 text-xs font-normal leading-[18px]'>{t('dataset.unavailable')}</span> <span className='shrink-0 inline-flex w-max ml-1 px-1 border border-gray-200 rounded-md text-gray-500 text-xs font-normal leading-[18px]'>{t('dataset.unavailable')}</span>
</Tooltip> </Tooltip>
)} )}
</div> </div>

View File

@ -1,10 +1,6 @@
import React from 'react' import React from 'react'
import {
InformationCircleIcon,
} from '@heroicons/react/24/outline'
import Tooltip from '../base/tooltip'
import AppIcon from '../base/app-icon' import AppIcon from '../base/app-icon'
import { randomString } from '@/utils' import Tooltip from '@/app/components/base/tooltip'
export type IAppBasicProps = { export type IAppBasicProps = {
iconType?: 'app' | 'api' | 'dataset' | 'webapp' | 'notion' iconType?: 'app' | 'api' | 'dataset' | 'webapp' | 'notion'
@ -74,9 +70,17 @@ export default function AppBasic({ icon, icon_background, name, type, hoverTip,
<div className={`flex flex-row items-center text-sm font-semibold text-gray-700 group-hover:text-gray-900 break-all ${textStyle?.main ?? ''}`}> <div className={`flex flex-row items-center text-sm font-semibold text-gray-700 group-hover:text-gray-900 break-all ${textStyle?.main ?? ''}`}>
{name} {name}
{hoverTip {hoverTip
&& <Tooltip content={hoverTip} selector={`a${randomString(16)}`}> && <Tooltip
<InformationCircleIcon className='w-4 h-4 ml-1 text-gray-400' /> popupContent={
</Tooltip>} <div className='w-[240px]'>
{hoverTip}
</div>
}
popupClassName='ml-1'
triggerClassName='w-4 h-4 ml-1'
position='top'
/>
}
</div> </div>
<div className={`text-xs font-normal text-gray-500 group-hover:text-gray-700 break-all ${textStyle?.extra ?? ''}`}>{type}</div> <div className={`text-xs font-normal text-gray-500 group-hover:text-gray-700 break-all ${textStyle?.extra ?? ''}`}>{type}</div>
</div>} </div>}

View File

@ -9,7 +9,6 @@ import produce from 'immer'
import { import {
RiDeleteBinLine, RiDeleteBinLine,
RiErrorWarningFill, RiErrorWarningFill,
RiQuestionLine,
} from '@remixicon/react' } from '@remixicon/react'
import s from './style.module.css' import s from './style.module.css'
import MessageTypeSelector from './message-type-selector' import MessageTypeSelector from './message-type-selector'
@ -174,12 +173,12 @@ const AdvancedPromptInput: FC<Props> = ({
<div className='text-sm font-semibold uppercase text-indigo-800'>{t('appDebug.pageTitle.line1')} <div className='text-sm font-semibold uppercase text-indigo-800'>{t('appDebug.pageTitle.line1')}
</div> </div>
<Tooltip <Tooltip
htmlContent={<div className='w-[180px]'> popupContent={
{t('appDebug.promptTip')} <div className='w-[180px]'>
</div>} {t('appDebug.promptTip')}
selector='config-prompt-tooltip'> </div>
<RiQuestionLine className='w-[14px] h-[14px] text-indigo-400' /> }
</Tooltip> />
</div>)} </div>)}
<div className={cn(s.optionWrap, 'items-center space-x-1')}> <div className={cn(s.optionWrap, 'items-center space-x-1')}>
{canDelete && ( {canDelete && (

View File

@ -3,9 +3,6 @@ import type { FC } from 'react'
import React, { useState } from 'react' import React, { useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useBoolean } from 'ahooks' import { useBoolean } from 'ahooks'
import {
RiQuestionLine,
} from '@remixicon/react'
import produce from 'immer' import produce from 'immer'
import { useContext } from 'use-context-selector' import { useContext } from 'use-context-selector'
import ConfirmAddVar from './confirm-add-var' import ConfirmAddVar from './confirm-add-var'
@ -156,12 +153,12 @@ const Prompt: FC<ISimplePromptInput> = ({
<div className='h2'>{mode !== AppType.completion ? t('appDebug.chatSubTitle') : t('appDebug.completionSubTitle')}</div> <div className='h2'>{mode !== AppType.completion ? t('appDebug.chatSubTitle') : t('appDebug.completionSubTitle')}</div>
{!readonly && ( {!readonly && (
<Tooltip <Tooltip
htmlContent={<div className='w-[180px]'> popupContent={
{t('appDebug.promptTip')} <div className='w-[180px]'>
</div>} {t('appDebug.promptTip')}
selector='config-prompt-tooltip'> </div>
<RiQuestionLine className='w-[14px] h-[14px] text-indigo-400' /> }
</Tooltip> />
)} )}
</div> </div>
<div className='flex items-center'> <div className='flex items-center'>

View File

@ -8,7 +8,6 @@ import { useContext } from 'use-context-selector'
import produce from 'immer' import produce from 'immer'
import { import {
RiDeleteBinLine, RiDeleteBinLine,
RiQuestionLine,
} from '@remixicon/react' } from '@remixicon/react'
import Panel from '../base/feature-panel' import Panel from '../base/feature-panel'
import EditModal from './config-modal' import EditModal from './config-modal'
@ -282,11 +281,13 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
<div className='flex items-center'> <div className='flex items-center'>
<div className='mr-1'>{t('appDebug.variableTitle')}</div> <div className='mr-1'>{t('appDebug.variableTitle')}</div>
{!readonly && ( {!readonly && (
<Tooltip htmlContent={<div className='w-[180px]'> <Tooltip
{t('appDebug.variableTip')} popupContent={
</div>} selector='config-var-tooltip'> <div className='w-[180px]'>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' /> {t('appDebug.variableTip')}
</Tooltip> </div>
}
/>
)} )}
</div> </div>
} }

View File

@ -2,9 +2,6 @@
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import {
RiQuestionLine,
} from '@remixicon/react'
import { useContext } from 'use-context-selector' import { useContext } from 'use-context-selector'
import Panel from '../base/feature-panel' import Panel from '../base/feature-panel'
import ParamConfig from './param-config' import ParamConfig from './param-config'
@ -33,11 +30,13 @@ const ConfigVision: FC = () => {
title={ title={
<div className='flex items-center'> <div className='flex items-center'>
<div className='mr-1'>{t('appDebug.vision.name')}</div> <div className='mr-1'>{t('appDebug.vision.name')}</div>
<Tooltip htmlContent={<div className='w-[180px]' > <Tooltip
{t('appDebug.vision.description')} popupContent={
</div>} selector='config-vision-tooltip'> <div className='w-[180px]' >
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' /> {t('appDebug.vision.description')}
</Tooltip> </div>
}
/>
</div> </div>
} }
headerRight={ headerRight={

View File

@ -3,9 +3,6 @@ import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useContext } from 'use-context-selector' import { useContext } from 'use-context-selector'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import {
RiQuestionLine,
} from '@remixicon/react'
import RadioGroup from './radio-group' import RadioGroup from './radio-group'
import ConfigContext from '@/context/debug-configuration' import ConfigContext from '@/context/debug-configuration'
import { Resolution, TransferMethod } from '@/types/app' import { Resolution, TransferMethod } from '@/types/app'
@ -37,13 +34,15 @@ const ParamConfigContent: FC = () => {
<div> <div>
<div className='mb-2 flex items-center space-x-1'> <div className='mb-2 flex items-center space-x-1'>
<div className='leading-[18px] text-[13px] font-semibold text-gray-800'>{t('appDebug.vision.visionSettings.resolution')}</div> <div className='leading-[18px] text-[13px] font-semibold text-gray-800'>{t('appDebug.vision.visionSettings.resolution')}</div>
<Tooltip htmlContent={<div className='w-[180px]' > <Tooltip
{t('appDebug.vision.visionSettings.resolutionTooltip').split('\n').map(item => ( popupContent={
<div key={item}>{item}</div> <div className='w-[180px]' >
))} {t('appDebug.vision.visionSettings.resolutionTooltip').split('\n').map(item => (
</div>} selector='config-resolution-tooltip'> <div key={item}>{item}</div>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' /> ))}
</Tooltip> </div>
}
/>
</div> </div>
<RadioGroup <RadioGroup
className='space-x-3' className='space-x-3'

View File

@ -3,9 +3,6 @@ import useSWR from 'swr'
import type { FC } from 'react' import type { FC } from 'react'
import { useContext } from 'use-context-selector' import { useContext } from 'use-context-selector'
import React, { Fragment } from 'react' import React, { Fragment } from 'react'
import {
RiQuestionLine,
} from '@remixicon/react'
import { usePathname } from 'next/navigation' import { usePathname } from 'next/navigation'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Listbox, Transition } from '@headlessui/react' import { Listbox, Transition } from '@headlessui/react'
@ -50,13 +47,15 @@ const VoiceParamConfig: FC = () => {
<div className='mb-2 flex items-center space-x-1'> <div className='mb-2 flex items-center space-x-1'>
<div <div
className='leading-[18px] text-[13px] font-semibold text-gray-800'>{t('appDebug.voice.voiceSettings.language')}</div> className='leading-[18px] text-[13px] font-semibold text-gray-800'>{t('appDebug.voice.voiceSettings.language')}</div>
<Tooltip htmlContent={<div className='w-[180px]'> <Tooltip
{t('appDebug.voice.voiceSettings.resolutionTooltip').split('\n').map(item => ( popupContent={
<div key={item}>{item}</div> <div className='w-[180px]'>
))} {t('appDebug.voice.voiceSettings.resolutionTooltip').split('\n').map(item => (
</div>} selector='config-resolution-tooltip'> <div key={item}>{item}</div>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' /> ))}
</Tooltip> </div>
}
/>
</div> </div>
<Listbox <Listbox
value={languageItem} value={languageItem}

View File

@ -1,7 +1,6 @@
'use client' 'use client'
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React from 'react'
import { RiQuestionLine } from '@remixicon/react'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
type Props = { type Props = {
@ -25,14 +24,12 @@ const ItemPanel: FC<Props> = ({
{icon} {icon}
<div className='ml-3 mr-1 leading-6 text-sm font-semibold text-gray-800'>{name}</div> <div className='ml-3 mr-1 leading-6 text-sm font-semibold text-gray-800'>{name}</div>
<Tooltip <Tooltip
htmlContent={ popupContent={
<div className='w-[180px]'> <div className='w-[180px]'>
{description} {description}
</div> </div>
} }
selector={`agent-setting-tooltip-${name}`}
> >
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' />
</Tooltip> </Tooltip>
</div> </div>
<div> <div>

View File

@ -7,13 +7,11 @@ import produce from 'immer'
import { import {
RiDeleteBinLine, RiDeleteBinLine,
RiHammerFill, RiHammerFill,
RiQuestionLine,
} from '@remixicon/react' } from '@remixicon/react'
import { useFormattingChangedDispatcher } from '../../../debug/hooks' import { useFormattingChangedDispatcher } from '../../../debug/hooks'
import SettingBuiltInTool from './setting-built-in-tool' import SettingBuiltInTool from './setting-built-in-tool'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import Panel from '@/app/components/app/configuration/base/feature-panel' import Panel from '@/app/components/app/configuration/base/feature-panel'
import Tooltip from '@/app/components/base/tooltip'
import { InfoCircle } from '@/app/components/base/icons/src/vender/line/general' import { InfoCircle } from '@/app/components/base/icons/src/vender/line/general'
import OperationBtn from '@/app/components/app/configuration/base/operation-btn' import OperationBtn from '@/app/components/app/configuration/base/operation-btn'
import AppIcon from '@/app/components/base/app-icon' import AppIcon from '@/app/components/base/app-icon'
@ -23,7 +21,7 @@ import type { AgentTool } from '@/types/app'
import { type Collection, CollectionType } from '@/app/components/tools/types' import { type Collection, CollectionType } from '@/app/components/tools/types'
import { MAX_TOOLS_NUM } from '@/config' import { MAX_TOOLS_NUM } from '@/config'
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback' import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import { DefaultToolIcon } from '@/app/components/base/icons/src/public/other' import { DefaultToolIcon } from '@/app/components/base/icons/src/public/other'
import AddToolModal from '@/app/components/tools/add-tool-modal' import AddToolModal from '@/app/components/tools/add-tool-modal'
@ -68,11 +66,13 @@ const AgentTools: FC = () => {
title={ title={
<div className='flex items-center'> <div className='flex items-center'>
<div className='mr-1'>{t('appDebug.agent.tools.name')}</div> <div className='mr-1'>{t('appDebug.agent.tools.name')}</div>
<Tooltip htmlContent={<div className='w-[180px]'> <Tooltip
{t('appDebug.agent.tools.description')} popupContent={
</div>} selector='config-tools-tooltip'> <div className='w-[180px]'>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' /> {t('appDebug.agent.tools.description')}
</Tooltip> </div>
}
/>
</div> </div>
} }
headerRight={ headerRight={
@ -119,19 +119,20 @@ const AgentTools: FC = () => {
className={cn((item.isDeleted || item.notAuthor) ? 'line-through opacity-50' : '', 'grow w-0 ml-2 leading-[18px] text-[13px] font-medium text-gray-800 truncate')} className={cn((item.isDeleted || item.notAuthor) ? 'line-through opacity-50' : '', 'grow w-0 ml-2 leading-[18px] text-[13px] font-medium text-gray-800 truncate')}
> >
<span className='text-gray-800 pr-2'>{item.provider_type === CollectionType.builtIn ? item.provider_name : item.tool_label}</span> <span className='text-gray-800 pr-2'>{item.provider_type === CollectionType.builtIn ? item.provider_name : item.tool_label}</span>
<TooltipPlus <Tooltip
popupContent={t('tools.toolNameUsageTip')} popupContent={t('tools.toolNameUsageTip')}
> >
<span className='text-gray-500'>{item.tool_name}</span> <span className='text-gray-500'>{item.tool_name}</span>
</TooltipPlus> </Tooltip>
</div> </div>
</div> </div>
<div className='shrink-0 ml-1 flex items-center'> <div className='shrink-0 ml-1 flex items-center'>
{(item.isDeleted || item.notAuthor) {(item.isDeleted || item.notAuthor)
? ( ? (
<div className='flex items-center'> <div className='flex items-center'>
<TooltipPlus <Tooltip
popupContent={t(`tools.${item.isDeleted ? 'toolRemoved' : 'notAuthorized'}`)} popupContent={t(`tools.${item.isDeleted ? 'toolRemoved' : 'notAuthorized'}`)}
needsDelay
> >
<div className='mr-1 p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => { <div className='mr-1 p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => {
if (item.notAuthor) if (item.notAuthor)
@ -139,7 +140,7 @@ const AgentTools: FC = () => {
}}> }}>
<AlertTriangle className='w-4 h-4 text-[#F79009]' /> <AlertTriangle className='w-4 h-4 text-[#F79009]' />
</div> </div>
</TooltipPlus> </Tooltip>
<div className='p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => { <div className='p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => {
const newModelConfig = produce(modelConfig, (draft) => { const newModelConfig = produce(modelConfig, (draft) => {
@ -155,16 +156,17 @@ const AgentTools: FC = () => {
) )
: ( : (
<div className='hidden group-hover:flex items-center'> <div className='hidden group-hover:flex items-center'>
<TooltipPlus <Tooltip
popupContent={t('tools.setBuiltInTools.infoAndSetting')} popupContent={t('tools.setBuiltInTools.infoAndSetting')}
needsDelay
> >
<div className='mr-1 p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => { <div className='p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => {
setCurrentTool(item) setCurrentTool(item)
setIsShowSettingTool(true) setIsShowSettingTool(true)
}}> }}>
<InfoCircle className='w-4 h-4 text-gray-500' /> <InfoCircle className='w-4 h-4 text-gray-500' />
</div> </div>
</TooltipPlus> </Tooltip>
<div className='p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => { <div className='p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => {
const newModelConfig = produce(modelConfig, (draft) => { const newModelConfig = produce(modelConfig, (draft) => {

View File

@ -39,10 +39,9 @@ const CardItem: FC<ICardItemProps> = ({
<div className={cn('text-[13px] leading-[18px] font-medium text-gray-800 overflow-hidden text-ellipsis whitespace-nowrap', !config.embedding_available && 'opacity-50')}>{config.name}</div> <div className={cn('text-[13px] leading-[18px] font-medium text-gray-800 overflow-hidden text-ellipsis whitespace-nowrap', !config.embedding_available && 'opacity-50')}>{config.name}</div>
{!config.embedding_available && ( {!config.embedding_available && (
<Tooltip <Tooltip
selector={`unavailable-tag-${config.id}`} popupContent={t('dataset.unavailableTip')}
htmlContent={t('dataset.unavailableTip')}
> >
<span className='shrink-0 inline-flex whitespace-nowrap px-1 border boder-gray-200 rounded-md text-gray-500 text-xs font-normal leading-[18px]'>{t('dataset.unavailable')}</span> <span className='shrink-0 inline-flex whitespace-nowrap px-1 border border-gray-200 rounded-md text-gray-500 text-xs font-normal leading-[18px]'>{t('dataset.unavailable')}</span>
</Tooltip> </Tooltip>
)} )}
</div> </div>

View File

@ -2,9 +2,6 @@
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import {
RiQuestionLine,
} from '@remixicon/react'
import type { Props } from './var-picker' import type { Props } from './var-picker'
import VarPicker from './var-picker' import VarPicker from './var-picker'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
@ -24,13 +21,12 @@ const ContextVar: FC<Props> = (props) => {
</div> </div>
<div className='mr-1 text-sm font-medium text-gray-800'>{t('appDebug.feature.dataSet.queryVariable.title')}</div> <div className='mr-1 text-sm font-medium text-gray-800'>{t('appDebug.feature.dataSet.queryVariable.title')}</div>
<Tooltip <Tooltip
htmlContent={<div className='w-[180px]'> popupContent={
{t('appDebug.feature.dataSet.queryVariable.tip')} <div className='w-[180px]'>
</div>} {t('appDebug.feature.dataSet.queryVariable.tip')}
selector='context-var-tooltip' </div>
> }
<RiQuestionLine className='w-3.5 h-3.5 text-gray-400' /> />
</Tooltip>
</div> </div>
<VarPicker {...props} /> <VarPicker {...props} />

View File

@ -5,7 +5,6 @@ import type { FC } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { import {
RiAlertFill, RiAlertFill,
RiQuestionLine,
} from '@remixicon/react' } from '@remixicon/react'
import WeightedScore from './weighted-score' import WeightedScore from './weighted-score'
import TopKItem from '@/app/components/base/param-item/top-k-item' import TopKItem from '@/app/components/base/param-item/top-k-item'
@ -23,7 +22,7 @@ import ModelSelector from '@/app/components/header/account-setting/model-provide
import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks' import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
import type { ModelConfig } from '@/app/components/workflow/types' import type { ModelConfig } from '@/app/components/workflow/types'
import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal' import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import type { import type {
DataSet, DataSet,
@ -173,7 +172,7 @@ const ConfigContent: FC<Props> = ({
title={( title={(
<div className='flex items-center'> <div className='flex items-center'>
{t('appDebug.datasetConfig.retrieveOneWay.title')} {t('appDebug.datasetConfig.retrieveOneWay.title')}
<TooltipPlus <Tooltip
popupContent={( popupContent={(
<div className='w-[320px]'> <div className='w-[320px]'>
{t('dataset.nTo1RetrievalLegacy')} {t('dataset.nTo1RetrievalLegacy')}
@ -181,7 +180,7 @@ const ConfigContent: FC<Props> = ({
)} )}
> >
<div className='ml-1 flex items-center px-[5px] h-[18px] rounded-[5px] border border-text-accent-secondary system-2xs-medium-uppercase text-text-accent-secondary'>legacy</div> <div className='ml-1 flex items-center px-[5px] h-[18px] rounded-[5px] border border-text-accent-secondary system-2xs-medium-uppercase text-text-accent-secondary'>legacy</div>
</TooltipPlus> </Tooltip>
</div> </div>
)} )}
description={t('appDebug.datasetConfig.retrieveOneWay.description')} description={t('appDebug.datasetConfig.retrieveOneWay.description')}
@ -250,12 +249,15 @@ const ConfigContent: FC<Props> = ({
onClick={() => handleRerankModeChange(option.value)} onClick={() => handleRerankModeChange(option.value)}
> >
<div className='truncate'>{option.label}</div> <div className='truncate'>{option.label}</div>
<TooltipPlus <Tooltip
popupContent={<div className='w-[200px]'>{option.tips}</div>} popupContent={
hideArrow <div className='w-[200px]'>
> {option.tips}
<RiQuestionLine className='ml-0.5 w-3.5 h-4.5 text-text-quaternary' /> </div>
</TooltipPlus> }
popupClassName='ml-0.5'
triggerClassName='ml-0.5 w-3.5 h-3.5'
/>
</div> </div>
)) ))
} }
@ -281,9 +283,15 @@ const ConfigContent: FC<Props> = ({
) )
} }
<div className='ml-2 leading-[32px] text-[13px] font-medium text-gray-900'>{t('common.modelProvider.rerankModel.key')}</div> <div className='ml-2 leading-[32px] text-[13px] font-medium text-gray-900'>{t('common.modelProvider.rerankModel.key')}</div>
<TooltipPlus popupContent={<div className="w-[200px]">{t('common.modelProvider.rerankModel.tip')}</div>}> <Tooltip
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-gray-400' /> popupContent={
</TooltipPlus> <div className="w-[200px]">
{t('common.modelProvider.rerankModel.tip')}
</div>
}
popupClassName='ml-0.5'
triggerClassName='ml-0.5 w-3.5 h-3.5'
/>
</div> </div>
<div> <div>
<ModelSelector <ModelSelector
@ -361,11 +369,9 @@ const ConfigContent: FC<Props> = ({
<div className='mt-4'> <div className='mt-4'>
<div className='flex items-center space-x-0.5'> <div className='flex items-center space-x-0.5'>
<div className='leading-[32px] text-[13px] font-medium text-gray-900'>{t('common.modelProvider.systemReasoningModel.key')}</div> <div className='leading-[32px] text-[13px] font-medium text-gray-900'>{t('common.modelProvider.systemReasoningModel.key')}</div>
<TooltipPlus <Tooltip
popupContent={t('common.modelProvider.systemReasoningModel.tip')} popupContent={t('common.modelProvider.systemReasoningModel.tip')}
> />
<RiQuestionLine className='w-3.5 h-4.5 text-gray-400' />
</TooltipPlus>
</div> </div>
<ModelParameterModal <ModelParameterModal
isInWorkflow={isInWorkflow} isInWorkflow={isInWorkflow}

View File

@ -13,7 +13,7 @@ import {
} from '@/app/components/header/account-setting/model-provider-page/declarations' } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useDebugConfigurationContext } from '@/context/debug-configuration' import { useDebugConfigurationContext } from '@/context/debug-configuration'
import { CubeOutline } from '@/app/components/base/icons/src/vender/line/shapes' import { CubeOutline } from '@/app/components/base/icons/src/vender/line/shapes'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback' import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks' import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
@ -111,9 +111,9 @@ const ModelParameterTrigger: FC<ModelParameterTriggerProps> = ({
<RiArrowDownSLine className={`w-3 h-3 ${(currentModel && currentProvider) ? 'text-gray-800' : 'text-primary-600'}`} /> <RiArrowDownSLine className={`w-3 h-3 ${(currentModel && currentProvider) ? 'text-gray-800' : 'text-primary-600'}`} />
{ {
currentModel && currentModel.status !== ModelStatusEnum.active && ( currentModel && currentModel.status !== ModelStatusEnum.active && (
<TooltipPlus popupContent={MODEL_STATUS_TEXT[currentModel.status][language]}> <Tooltip popupContent={MODEL_STATUS_TEXT[currentModel.status][language]}>
<AlertTriangle className='w-4 h-4 text-[#F79009]' /> <AlertTriangle className='w-4 h-4 text-[#F79009]' />
</TooltipPlus> </Tooltip>
) )
} }
</div> </div>

View File

@ -2,9 +2,6 @@
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import {
RiQuestionLine,
} from '@remixicon/react'
import Panel from '@/app/components/app/configuration/base/feature-panel' import Panel from '@/app/components/app/configuration/base/feature-panel'
import SuggestedQuestionsAfterAnswerIcon from '@/app/components/app/configuration/base/icons/suggested-questions-after-answer-icon' import SuggestedQuestionsAfterAnswerIcon from '@/app/components/app/configuration/base/icons/suggested-questions-after-answer-icon'
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
@ -15,13 +12,15 @@ const SuggestedQuestionsAfterAnswer: FC = () => {
return ( return (
<Panel <Panel
title={ title={
<div className='flex items-center gap-2'> <div className='flex items-center gap-1'>
<div>{t('appDebug.feature.suggestedQuestionsAfterAnswer.title')}</div> <div>{t('appDebug.feature.suggestedQuestionsAfterAnswer.title')}</div>
<Tooltip htmlContent={<div className='w-[180px]'> <Tooltip
{t('appDebug.feature.suggestedQuestionsAfterAnswer.description')} popupContent={
</div>} selector='suggestion-question-tooltip'> <div className='w-[180px]'>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' /> {t('appDebug.feature.suggestedQuestionsAfterAnswer.description')}
</Tooltip> </div>
}
/>
</div> </div>
} }
headerIcon={<SuggestedQuestionsAfterAnswerIcon />} headerIcon={<SuggestedQuestionsAfterAnswerIcon />}

View File

@ -16,7 +16,7 @@ import { AppType, ModelModeType } from '@/types/app'
import Select from '@/app/components/base/select' import Select from '@/app/components/base/select'
import { DEFAULT_VALUE_MAX_LEN } from '@/config' import { DEFAULT_VALUE_MAX_LEN } from '@/config'
import Button from '@/app/components/base/button' import Button from '@/app/components/base/button'
import Tooltip from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import TextGenerationImageUploader from '@/app/components/base/image-uploader/text-generation-image-uploader' import TextGenerationImageUploader from '@/app/components/base/image-uploader/text-generation-image-uploader'
import type { VisionFile, VisionSettings } from '@/types/app' import type { VisionFile, VisionSettings } from '@/types/app'
@ -207,6 +207,7 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
{canNotRun {canNotRun
? (<Tooltip ? (<Tooltip
popupContent={t('appDebug.otherError.promptNoBeEmpty')} popupContent={t('appDebug.otherError.promptNoBeEmpty')}
needsDelay
> >
{renderRunButton()} {renderRunButton()}
</Tooltip>) </Tooltip>)

View File

@ -8,7 +8,7 @@ import { MessageCheckRemove, MessageFastPlus } from '@/app/components/base/icons
import { MessageFast } from '@/app/components/base/icons/src/vender/solid/communication' import { MessageFast } from '@/app/components/base/icons/src/vender/solid/communication'
import { Edit04 } from '@/app/components/base/icons/src/vender/line/general' import { Edit04 } from '@/app/components/base/icons/src/vender/line/general'
import RemoveAnnotationConfirmModal from '@/app/components/app/annotation/remove-annotation-confirm-modal' import RemoveAnnotationConfirmModal from '@/app/components/app/annotation/remove-annotation-confirm-modal'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import { addAnnotation, delAnnotation } from '@/service/annotation' import { addAnnotation, delAnnotation } from '@/service/annotation'
import Toast from '@/app/components/base/toast' import Toast from '@/app/components/base/toast'
import { useProviderContext } from '@/context/provider-context' import { useProviderContext } from '@/context/provider-context'
@ -99,8 +99,9 @@ const CacheCtrlBtn: FC<Props> = ({
) )
: answer : answer
? ( ? (
<TooltipPlus <Tooltip
popupContent={t('appDebug.feature.annotation.add') as string} popupContent={t('appDebug.feature.annotation.add')}
needsDelay
> >
<div <div
className='p-1 rounded-md hover:bg-[#EEF4FF] hover:text-[#444CE7] cursor-pointer' className='p-1 rounded-md hover:bg-[#EEF4FF] hover:text-[#444CE7] cursor-pointer'
@ -108,12 +109,13 @@ const CacheCtrlBtn: FC<Props> = ({
> >
<MessageFastPlus className='w-4 h-4' /> <MessageFastPlus className='w-4 h-4' />
</div> </div>
</TooltipPlus> </Tooltip>
) )
: null : null
} }
<TooltipPlus <Tooltip
popupContent={t('appDebug.feature.annotation.edit') as string} popupContent={t('appDebug.feature.annotation.edit')}
needsDelay
> >
<div <div
className='p-1 cursor-pointer rounded-md hover:bg-black/5' className='p-1 cursor-pointer rounded-md hover:bg-black/5'
@ -121,7 +123,7 @@ const CacheCtrlBtn: FC<Props> = ({
> >
<Edit04 className='w-4 h-4' /> <Edit04 className='w-4 h-4' />
</div> </div>
</TooltipPlus> </Tooltip>
</div> </div>
<RemoveAnnotationConfirmModal <RemoveAnnotationConfirmModal

View File

@ -4,13 +4,10 @@ import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector' import { useContext } from 'use-context-selector'
import { usePathname, useRouter } from 'next/navigation' import { usePathname, useRouter } from 'next/navigation'
import {
RiQuestionLine,
} from '@remixicon/react'
import ConfigParamModal from './config-param-modal' import ConfigParamModal from './config-param-modal'
import Panel from '@/app/components/app/configuration/base/feature-panel' import Panel from '@/app/components/app/configuration/base/feature-panel'
import { MessageFast } from '@/app/components/base/icons/src/vender/solid/communication' import { MessageFast } from '@/app/components/base/icons/src/vender/solid/communication'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import { LinkExternal02, Settings04 } from '@/app/components/base/icons/src/vender/line/general' import { LinkExternal02, Settings04 } from '@/app/components/base/icons/src/vender/line/general'
import ConfigContext from '@/context/debug-configuration' import ConfigContext from '@/context/debug-configuration'
import type { EmbeddingModelConfig } from '@/app/components/app/annotation/type' import type { EmbeddingModelConfig } from '@/app/components/app/annotation/type'
@ -31,13 +28,11 @@ export const Item: FC<{ title: string; tooltip: string; children: JSX.Element }>
<div> <div>
<div className='flex items-center space-x-1'> <div className='flex items-center space-x-1'>
<div>{title}</div> <div>{title}</div>
<TooltipPlus <Tooltip
popupContent={ popupContent={
<div className='max-w-[200px] leading-[18px] text-[13px] font-medium text-gray-800'>{tooltip}</div> <div className='max-w-[200px] leading-[18px] text-[13px] font-medium text-gray-800'>{tooltip}</div>
} }
> />
<RiQuestionLine className='w-3.5 h-3.5 text-gray-400' />
</TooltipPlus>
</div> </div>
<div>{children}</div> <div>{children}</div>
</div> </div>

View File

@ -7,11 +7,10 @@ import {
RiAddLine, RiAddLine,
RiArrowDownSLine, RiArrowDownSLine,
RiDeleteBinLine, RiDeleteBinLine,
RiQuestionLine,
} from '@remixicon/react' } from '@remixicon/react'
import ConfigContext from '@/context/debug-configuration' import ConfigContext from '@/context/debug-configuration'
import Switch from '@/app/components/base/switch' import Switch from '@/app/components/base/switch'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import { Tool03 } from '@/app/components/base/icons/src/vender/solid/general' import { Tool03 } from '@/app/components/base/icons/src/vender/solid/general'
import { import {
Settings01, Settings01,
@ -107,9 +106,13 @@ const Tools = () => {
<div className='mr-1 text-sm font-semibold text-gray-800'> <div className='mr-1 text-sm font-semibold text-gray-800'>
{t('appDebug.feature.tools.title')} {t('appDebug.feature.tools.title')}
</div> </div>
<TooltipPlus popupContent={<div className='max-w-[160px]'>{t('appDebug.feature.tools.tips')}</div>}> <Tooltip
<RiQuestionLine className='w-3.5 h-3.5 text-gray-400' /> popupContent={
</TooltipPlus> <div className='max-w-[160px]'>
{t('appDebug.feature.tools.tips')}
</div>
}
/>
</div> </div>
{ {
!expanded && !!externalDataToolsConfig.length && ( !expanded && !!externalDataToolsConfig.length && (
@ -143,7 +146,7 @@ const Tools = () => {
background={item.icon_background} background={item.icon_background}
/> />
<div className='mr-2 text-[13px] font-medium text-gray-800'>{item.label}</div> <div className='mr-2 text-[13px] font-medium text-gray-800'>{item.label}</div>
<TooltipPlus <Tooltip
popupContent={copied ? t('appApi.copied') : `${item.variable}, ${t('appApi.copy')}`} popupContent={copied ? t('appApi.copied') : `${item.variable}, ${t('appApi.copy')}`}
> >
<div <div
@ -155,7 +158,7 @@ const Tools = () => {
> >
{item.variable} {item.variable}
</div> </div>
</TooltipPlus> </Tooltip>
</div> </div>
<div <div
className='hidden group-hover:flex items-center justify-center mr-1 w-6 h-6 hover:bg-black/5 rounded-md cursor-pointer' className='hidden group-hover:flex items-center justify-center mr-1 w-6 h-6 hover:bg-black/5 rounded-md cursor-pointer'

View File

@ -23,7 +23,7 @@ import AppIcon from '@/app/components/base/app-icon'
import AppsFull from '@/app/components/billing/apps-full-in-dialog' import AppsFull from '@/app/components/billing/apps-full-in-dialog'
import { AiText, ChatBot, CuteRobote } from '@/app/components/base/icons/src/vender/solid/communication' import { AiText, ChatBot, CuteRobote } from '@/app/components/base/icons/src/vender/solid/communication'
import { Route } from '@/app/components/base/icons/src/vender/solid/mapsAndTravel' import { Route } from '@/app/components/base/icons/src/vender/solid/mapsAndTravel'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import { NEED_REFRESH_APP_LIST_KEY } from '@/config' import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
import { getRedirection } from '@/utils/app-redirection' import { getRedirection } from '@/utils/app-redirection'
@ -100,8 +100,7 @@ const CreateAppModal = ({ show, onSuccess, onClose }: CreateAppDialogProps) => {
<div className='py-2 px-8'> <div className='py-2 px-8'>
<div className='py-2 text-sm leading-[20px] font-medium text-gray-900'>{t('app.newApp.captionAppType')}</div> <div className='py-2 text-sm leading-[20px] font-medium text-gray-900'>{t('app.newApp.captionAppType')}</div>
<div className='flex'> <div className='flex'>
<TooltipPlus <Tooltip
hideArrow
popupContent={ popupContent={
<div className='max-w-[280px] leading-[18px] text-xs text-gray-700'>{t('app.newApp.chatbotDescription')}</div> <div className='max-w-[280px] leading-[18px] text-xs text-gray-700'>{t('app.newApp.chatbotDescription')}</div>
} }
@ -120,9 +119,8 @@ const CreateAppModal = ({ show, onSuccess, onClose }: CreateAppDialogProps) => {
<ChatBot className='w-6 h-6 text-[#1570EF]' /> <ChatBot className='w-6 h-6 text-[#1570EF]' />
<div className='h-5 text-[13px] font-medium leading-[18px]'>{t('app.types.chatbot')}</div> <div className='h-5 text-[13px] font-medium leading-[18px]'>{t('app.types.chatbot')}</div>
</div> </div>
</TooltipPlus> </Tooltip>
<TooltipPlus <Tooltip
hideArrow
popupContent={ popupContent={
<div className='flex flex-col max-w-[320px] leading-[18px] text-xs'> <div className='flex flex-col max-w-[320px] leading-[18px] text-xs'>
<div className='text-gray-700'>{t('app.newApp.completionDescription')}</div> <div className='text-gray-700'>{t('app.newApp.completionDescription')}</div>
@ -143,9 +141,8 @@ const CreateAppModal = ({ show, onSuccess, onClose }: CreateAppDialogProps) => {
<AiText className='w-6 h-6 text-[#0E9384]' /> <AiText className='w-6 h-6 text-[#0E9384]' />
<div className='h-5 text-[13px] font-medium leading-[18px]'>{t('app.newApp.completeApp')}</div> <div className='h-5 text-[13px] font-medium leading-[18px]'>{t('app.newApp.completeApp')}</div>
</div> </div>
</TooltipPlus> </Tooltip>
<TooltipPlus <Tooltip
hideArrow
popupContent={ popupContent={
<div className='max-w-[280px] leading-[18px] text-xs text-gray-700'>{t('app.newApp.agentDescription')}</div> <div className='max-w-[280px] leading-[18px] text-xs text-gray-700'>{t('app.newApp.agentDescription')}</div>
} }
@ -164,9 +161,8 @@ const CreateAppModal = ({ show, onSuccess, onClose }: CreateAppDialogProps) => {
<CuteRobote className='w-6 h-6 text-indigo-600' /> <CuteRobote className='w-6 h-6 text-indigo-600' />
<div className='h-5 text-[13px] font-medium leading-[18px]'>{t('app.types.agent')}</div> <div className='h-5 text-[13px] font-medium leading-[18px]'>{t('app.types.agent')}</div>
</div> </div>
</TooltipPlus> </Tooltip>
<TooltipPlus <Tooltip
hideArrow
popupContent={ popupContent={
<div className='flex flex-col max-w-[320px] leading-[18px] text-xs'> <div className='flex flex-col max-w-[320px] leading-[18px] text-xs'>
<div className='text-gray-700'>{t('app.newApp.workflowDescription')}</div> <div className='text-gray-700'>{t('app.newApp.workflowDescription')}</div>
@ -188,7 +184,7 @@ const CreateAppModal = ({ show, onSuccess, onClose }: CreateAppDialogProps) => {
<div className='h-5 text-[13px] font-medium leading-[18px]'>{t('app.types.workflow')}</div> <div className='h-5 text-[13px] font-medium leading-[18px]'>{t('app.types.workflow')}</div>
<span className='absolute top-[-3px] right-[-3px] px-1 rounded-[5px] bg-white border border-black/8 text-gray-500 text-[10px] leading-[18px] font-medium'>BETA</span> <span className='absolute top-[-3px] right-[-3px] px-1 rounded-[5px] bg-white border border-black/8 text-gray-500 text-[10px] leading-[18px] font-medium'>BETA</span>
</div> </div>
</TooltipPlus> </Tooltip>
</div> </div>
</div> </div>
{showChatBotType && ( {showChatBotType && (

View File

@ -5,10 +5,9 @@ import useSWR from 'swr'
import { import {
HandThumbDownIcon, HandThumbDownIcon,
HandThumbUpIcon, HandThumbUpIcon,
InformationCircleIcon,
XMarkIcon, XMarkIcon,
} from '@heroicons/react/24/outline' } from '@heroicons/react/24/outline'
import { RiEditFill } from '@remixicon/react' import { RiEditFill, RiQuestionLine } from '@remixicon/react'
import { get } from 'lodash-es' import { get } from 'lodash-es'
import InfiniteScroll from 'react-infinite-scroll-component' import InfiniteScroll from 'react-infinite-scroll-component'
import dayjs from 'dayjs' import dayjs from 'dayjs'
@ -20,7 +19,6 @@ import { useTranslation } from 'react-i18next'
import s from './style.module.css' import s from './style.module.css'
import VarPanel from './var-panel' import VarPanel from './var-panel'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { randomString } from '@/utils'
import type { FeedbackFunc, Feedbacktype, IChatItem, SubmitAnnotationFunc } from '@/app/components/base/chat/chat/type' import type { FeedbackFunc, Feedbacktype, IChatItem, SubmitAnnotationFunc } from '@/app/components/base/chat/chat/type'
import type { Annotation, ChatConversationFullDetailResponse, ChatConversationGeneralDetail, ChatConversationsResponse, ChatMessage, ChatMessagesRequest, CompletionConversationFullDetailResponse, CompletionConversationGeneralDetail, CompletionConversationsResponse, LogAnnotation } from '@/models/log' import type { Annotation, ChatConversationFullDetailResponse, ChatConversationGeneralDetail, ChatConversationsResponse, ChatMessage, ChatMessagesRequest, CompletionConversationFullDetailResponse, CompletionConversationGeneralDetail, CompletionConversationsResponse, LogAnnotation } from '@/models/log'
import type { App } from '@/types/app' import type { App } from '@/types/app'
@ -28,7 +26,6 @@ import Loading from '@/app/components/base/loading'
import Drawer from '@/app/components/base/drawer' import Drawer from '@/app/components/base/drawer'
import Popover from '@/app/components/base/popover' import Popover from '@/app/components/base/popover'
import Chat from '@/app/components/base/chat/chat' import Chat from '@/app/components/base/chat/chat'
import Tooltip from '@/app/components/base/tooltip'
import { ToastContext } from '@/app/components/base/toast' import { ToastContext } from '@/app/components/base/toast'
import { fetchChatConversationDetail, fetchChatMessages, fetchCompletionConversationDetail, updateLogMessageAnnotations, updateLogMessageFeedbacks } from '@/service/log' import { fetchChatConversationDetail, fetchChatMessages, fetchCompletionConversationDetail, updateLogMessageAnnotations, updateLogMessageFeedbacks } from '@/service/log'
import { TONE_LIST } from '@/config' import { TONE_LIST } from '@/config'
@ -42,7 +39,7 @@ import MessageLogModal from '@/app/components/base/message-log-modal'
import { useStore as useAppStore } from '@/app/components/app/store' import { useStore as useAppStore } from '@/app/components/app/store'
import { useAppContext } from '@/context/app-context' import { useAppContext } from '@/context/app-context'
import useTimestamp from '@/hooks/use-timestamp' import useTimestamp from '@/hooks/use-timestamp'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import { CopyIcon } from '@/app/components/base/copy-icon' import { CopyIcon } from '@/app/components/base/copy-icon'
dayjs.extend(utc) dayjs.extend(utc)
@ -346,11 +343,11 @@ function DetailPanel<T extends ChatConversationFullDetailResponse | CompletionCo
<div className='text-gray-500 text-[10px] leading-[14px]'>{isChatMode ? t('appLog.detail.conversationId') : t('appLog.detail.time')}</div> <div className='text-gray-500 text-[10px] leading-[14px]'>{isChatMode ? t('appLog.detail.conversationId') : t('appLog.detail.time')}</div>
{isChatMode && ( {isChatMode && (
<div className='flex items-center text-gray-700 text-[13px] leading-[18px]'> <div className='flex items-center text-gray-700 text-[13px] leading-[18px]'>
<TooltipPlus <Tooltip
hideArrow popupContent={detail.id}
popupContent={detail.id}> >
<div className='max-w-[105px] truncate'>{detail.id}</div> <div className='max-w-[105px] truncate'>{detail.id}</div>
</TooltipPlus> </Tooltip>
<CopyIcon content={detail.id} /> <CopyIcon content={detail.id} />
</div> </div>
)} )}
@ -380,7 +377,7 @@ function DetailPanel<T extends ChatConversationFullDetailResponse | CompletionCo
btnClassName='mr-4 !bg-gray-50 !py-1.5 !px-2.5 border-none font-normal' btnClassName='mr-4 !bg-gray-50 !py-1.5 !px-2.5 border-none font-normal'
btnElement={<> btnElement={<>
<span className='text-[13px]'>{targetTone}</span> <span className='text-[13px]'>{targetTone}</span>
<InformationCircleIcon className='h-4 w-4 text-gray-800 ml-1.5' /> <RiQuestionLine className='h-4 w-4 text-gray-800 ml-1.5' />
</>} </>}
htmlContent={<div className='w-[280px]'> htmlContent={<div className='w-[280px]'>
<div className='flex justify-between py-2 px-4 font-medium text-sm text-gray-700'> <div className='flex justify-between py-2 px-4 font-medium text-sm text-gray-700'>
@ -641,13 +638,12 @@ const ConversationList: FC<IConversationList> = ({ logs, appDetail, onRefresh })
const renderTdValue = (value: string | number | null, isEmptyStyle: boolean, isHighlight = false, annotation?: LogAnnotation) => { const renderTdValue = (value: string | number | null, isEmptyStyle: boolean, isHighlight = false, annotation?: LogAnnotation) => {
return ( return (
<Tooltip <Tooltip
htmlContent={ popupContent={
<span className='text-xs text-gray-500 inline-flex items-center'> <span className='text-xs text-gray-500 inline-flex items-center'>
<RiEditFill className='w-3 h-3 mr-1' />{`${t('appLog.detail.annotationTip', { user: annotation?.account?.name })} ${formatTime(annotation?.created_at || dayjs().unix(), 'MM-DD hh:mm A')}`} <RiEditFill className='w-3 h-3 mr-1' />{`${t('appLog.detail.annotationTip', { user: annotation?.account?.name })} ${formatTime(annotation?.created_at || dayjs().unix(), 'MM-DD hh:mm A')}`}
</span> </span>
} }
className={(isHighlight && !isChatMode) ? '' : '!hidden'} popupClassName={(isHighlight && !isChatMode) ? '' : '!hidden'}
selector={`highlight-${randomString(16)}`}
> >
<div className={cn(isEmptyStyle ? 'text-gray-400' : 'text-gray-700', !isHighlight ? '' : 'bg-orange-100', 'text-sm overflow-hidden text-ellipsis whitespace-nowrap')}> <div className={cn(isEmptyStyle ? 'text-gray-400' : 'text-gray-700', !isHighlight ? '' : 'bg-orange-100', 'text-sm overflow-hidden text-ellipsis whitespace-nowrap')}>
{value || '-'} {value || '-'}

View File

@ -195,8 +195,7 @@ function AppCard({
)} )}
{isApp && isCurrentWorkspaceManager && ( {isApp && isCurrentWorkspaceManager && (
<Tooltip <Tooltip
content={t('appOverview.overview.appInfo.regenerate') || ''} popupContent={t('appOverview.overview.appInfo.regenerate') || ''}
selector={`code-generate-${randomString(8)}`}
> >
<div <div
className="w-8 h-8 ml-0.5 cursor-pointer hover:bg-gray-200 rounded-lg" className="w-8 h-8 ml-0.5 cursor-pointer hover:bg-gray-200 rounded-lg"
@ -227,11 +226,10 @@ function AppCard({
disabled={disabled} disabled={disabled}
> >
<Tooltip <Tooltip
content={ popupContent={
t('appOverview.overview.appInfo.preUseReminder') ?? '' t('appOverview.overview.appInfo.preUseReminder') ?? ''
} }
selector={`op-btn-${randomString(16)}`} popupClassName={disabled ? 'mt-[-8px]' : '!hidden'}
className={disabled ? 'mt-[-8px]' : '!hidden'}
> >
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
<op.opIcon className="h-4 w-4 mr-1.5 stroke-[1.8px]" /> <op.opIcon className="h-4 w-4 mr-1.5 stroke-[1.8px]" />

View File

@ -153,8 +153,7 @@ const Embedded = ({ siteInfo, isShow, onClose, appBaseUrl, accessToken, classNam
</div> </div>
<div className="flex items-center justify-center gap-1 p-2 rounded-lg"> <div className="flex items-center justify-center gap-1 p-2 rounded-lg">
<Tooltip <Tooltip
selector={'code-copy-feedback'} popupContent={(isCopied[option] ? t(`${prefixEmbedded}.copied`) : t(`${prefixEmbedded}.copy`)) || ''}
content={(isCopied[option] ? t(`${prefixEmbedded}.copied`) : t(`${prefixEmbedded}.copy`)) || ''}
> >
<div className="w-8 h-8 rounded-lg cursor-pointer hover:bg-gray-100"> <div className="w-8 h-8 rounded-lg cursor-pointer hover:bg-gray-100">
<div onClick={onClickCopy} className={`w-full h-full ${copyStyle.copyIcon} ${isCopied[option] ? copyStyle.copied : ''}`}></div> <div onClick={onClickCopy} className={`w-full h-full ${copyStyle.copyIcon} ${isCopied[option] ? copyStyle.copied : ''}`}></div>

View File

@ -15,7 +15,7 @@ import type { AppDetailResponse } from '@/models/app'
import type { AppIconType, AppSSO, Language } from '@/types/app' import type { AppIconType, AppSSO, Language } from '@/types/app'
import { useToastContext } from '@/app/components/base/toast' import { useToastContext } from '@/app/components/base/toast'
import { languages } from '@/i18n/language' import { languages } from '@/i18n/language'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import AppContext from '@/context/app-context' import AppContext from '@/context/app-context'
import type { AppIconSelection } from '@/app/components/base/app-icon-picker' import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
import AppIconPicker from '@/app/components/base/app-icon-picker' import AppIconPicker from '@/app/components/base/app-icon-picker'
@ -240,9 +240,15 @@ const SettingsModal: FC<ISettingsModalProps> = ({
<p className='system-xs-medium text-gray-500'>{t(`${prefixSettings}.sso.label`)}</p> <p className='system-xs-medium text-gray-500'>{t(`${prefixSettings}.sso.label`)}</p>
<div className='flex justify-between items-center'> <div className='flex justify-between items-center'>
<div className='font-medium system-sm-semibold flex-grow text-gray-900'>{t(`${prefixSettings}.sso.title`)}</div> <div className='font-medium system-sm-semibold flex-grow text-gray-900'>{t(`${prefixSettings}.sso.title`)}</div>
<TooltipPlus disabled={systemFeatures.sso_enforced_for_web} popupContent={<div className='w-[180px]'>{t(`${prefixSettings}.sso.tooltip`)}</div>}> <Tooltip
disabled={systemFeatures.sso_enforced_for_web}
popupContent={
<div className='w-[180px]'>{t(`${prefixSettings}.sso.tooltip`)}</div>
}
asChild={false}
>
<Switch disabled={!systemFeatures.sso_enforced_for_web} defaultValue={systemFeatures.sso_enforced_for_web && inputInfo.enable_sso} onChange={v => setInputInfo({ ...inputInfo, enable_sso: v })}></Switch> <Switch disabled={!systemFeatures.sso_enforced_for_web} defaultValue={systemFeatures.sso_enforced_for_web && inputInfo.enable_sso} onChange={v => setInputInfo({ ...inputInfo, enable_sso: v })}></Switch>
</TooltipPlus> </Tooltip>
</div> </div>
<p className='body-xs-regular text-gray-500'>{t(`${prefixSettings}.sso.description`)}</p> <p className='body-xs-regular text-gray-500'>{t(`${prefixSettings}.sso.description`)}</p>
</div>} </div>}

View File

@ -83,25 +83,25 @@ const AudioBtn = ({
}[audioState] }[audioState]
return ( return (
<div className={`${(audioState === 'loading' || audioState === 'playing') ? 'mr-1' : className}`}> <div className={`inline-flex items-center justify-center ${(audioState === 'loading' || audioState === 'playing') ? 'mr-1' : className}`}>
<Tooltip <Tooltip
selector={selector.current} popupContent={tooltipContent}
content={tooltipContent}
className='z-10'
> >
<button <button
disabled={audioState === 'loading'} disabled={audioState === 'loading'}
className={`box-border p-0.5 flex items-center justify-center cursor-pointer ${isAudition || '!p-0 rounded-md bg-white'}`} className={`box-border w-6 h-6 flex items-center justify-center cursor-pointer ${isAudition ? 'p-0.5' : 'p-0 rounded-md bg-white'}`}
onClick={handleToggle} onClick={handleToggle}
> >
{audioState === 'loading' {audioState === 'loading'
? ( ? (
<div className='w-6 h-6 rounded-md flex items-center justify-center p-2'> <div className='w-full h-full rounded-md flex items-center justify-center'>
<Loading /> <Loading />
</div> </div>
) )
: ( : (
<div className={`w-6 h-6 rounded-md ${!isAudition ? 'w-4 h-4 hover:bg-gray-50' : 'hover:bg-gray-50'} ${(audioState === 'playing') ? s.pauseIcon : s.playIcon}`}></div> <div className={`w-full h-full rounded-md flex items-center justify-center ${!isAudition ? 'hover:bg-gray-50' : 'hover:bg-gray-50'}`}>
<div className={`w-4 h-4 ${(audioState === 'playing') ? s.pauseIcon : s.playIcon}`}></div>
</div>
)} )}
</button> </button>
</Tooltip> </Tooltip>

View File

@ -17,7 +17,7 @@ import {
ThumbsDown, ThumbsDown,
ThumbsUp, ThumbsUp,
} from '@/app/components/base/icons/src/vender/line/alertsAndFeedback' } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import Log from '@/app/components/base/chat/chat/log' import Log from '@/app/components/base/chat/chat/log'
type OperationProps = { type OperationProps = {
@ -162,28 +162,34 @@ const Operation: FC<OperationProps> = ({
{ {
config?.supportFeedback && !localFeedback?.rating && onFeedback && !isOpeningStatement && ( config?.supportFeedback && !localFeedback?.rating && onFeedback && !isOpeningStatement && (
<div className='hidden group-hover:flex ml-1 shrink-0 items-center px-0.5 bg-white border-[0.5px] border-gray-100 shadow-md text-gray-500 rounded-lg'> <div className='hidden group-hover:flex ml-1 shrink-0 items-center px-0.5 bg-white border-[0.5px] border-gray-100 shadow-md text-gray-500 rounded-lg'>
<TooltipPlus popupContent={t('appDebug.operation.agree')}> <Tooltip
popupContent={t('appDebug.operation.agree')}
>
<div <div
className='flex items-center justify-center mr-0.5 w-6 h-6 rounded-md hover:bg-black/5 hover:text-gray-800 cursor-pointer' className='flex items-center justify-center mr-0.5 w-6 h-6 rounded-md hover:bg-black/5 hover:text-gray-800 cursor-pointer'
onClick={() => handleFeedback('like')} onClick={() => handleFeedback('like')}
> >
<ThumbsUp className='w-4 h-4' /> <ThumbsUp className='w-4 h-4' />
</div> </div>
</TooltipPlus> </Tooltip>
<TooltipPlus popupContent={t('appDebug.operation.disagree')}> <Tooltip
popupContent={t('appDebug.operation.disagree')}
>
<div <div
className='flex items-center justify-center w-6 h-6 rounded-md hover:bg-black/5 hover:text-gray-800 cursor-pointer' className='flex items-center justify-center w-6 h-6 rounded-md hover:bg-black/5 hover:text-gray-800 cursor-pointer'
onClick={() => handleFeedback('dislike')} onClick={() => handleFeedback('dislike')}
> >
<ThumbsDown className='w-4 h-4' /> <ThumbsDown className='w-4 h-4' />
</div> </div>
</TooltipPlus> </Tooltip>
</div> </div>
) )
} }
{ {
config?.supportFeedback && localFeedback?.rating && onFeedback && !isOpeningStatement && ( config?.supportFeedback && localFeedback?.rating && onFeedback && !isOpeningStatement && (
<TooltipPlus popupContent={localFeedback.rating === 'like' ? t('appDebug.operation.cancelAgree') : t('appDebug.operation.cancelDisagree')}> <Tooltip
popupContent={localFeedback.rating === 'like' ? t('appDebug.operation.cancelAgree') : t('appDebug.operation.cancelDisagree')}
>
<div <div
className={` className={`
flex items-center justify-center w-7 h-7 rounded-[10px] border-[2px] border-white cursor-pointer flex items-center justify-center w-7 h-7 rounded-[10px] border-[2px] border-white cursor-pointer
@ -203,7 +209,7 @@ const Operation: FC<OperationProps> = ({
) )
} }
</div> </div>
</TooltipPlus> </Tooltip>
) )
} }
</div> </div>

View File

@ -17,7 +17,7 @@ import { TransferMethod } from '../types'
import { useChatWithHistoryContext } from '../chat-with-history/context' import { useChatWithHistoryContext } from '../chat-with-history/context'
import type { Theme } from '../embedded-chatbot/theme/theme-context' import type { Theme } from '../embedded-chatbot/theme/theme-context'
import { CssTransform } from '../embedded-chatbot/theme/utils' import { CssTransform } from '../embedded-chatbot/theme/utils'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import { ToastContext } from '@/app/components/base/toast' import { ToastContext } from '@/app/components/base/toast'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import VoiceInput from '@/app/components/base/voice-input' import VoiceInput from '@/app/components/base/voice-input'
@ -220,7 +220,7 @@ const ChatInput: FC<ChatInputProps> = ({
{isMobile {isMobile
? sendBtn ? sendBtn
: ( : (
<TooltipPlus <Tooltip
popupContent={ popupContent={
<div> <div>
<div>{t('common.operation.send')} Enter</div> <div>{t('common.operation.send')} Enter</div>
@ -229,7 +229,7 @@ const ChatInput: FC<ChatInputProps> = ({
} }
> >
{sendBtn} {sendBtn}
</TooltipPlus> </Tooltip>
)} )}
</div> </div>
{ {

View File

@ -41,9 +41,7 @@ const Header: FC<IHeaderProps> = ({
</div> </div>
</div> </div>
<Tooltip <Tooltip
selector={'embed-scene-restart-button'} popupContent={t('share.chat.resetChat')}
htmlContent={t('share.chat.resetChat')}
position='top'
> >
<div className='flex cursor-pointer hover:rounded-lg hover:bg-black/5 w-8 h-8 items-center justify-center' onClick={() => { <div className='flex cursor-pointer hover:rounded-lg hover:bg-black/5 w-8 h-8 items-center justify-center' onClick={() => {
onCreateNewChat?.() onCreateNewChat?.()

View File

@ -88,9 +88,7 @@ const Chatbot = () => {
{!isMobile && ( {!isMobile && (
<div className='absolute top-2.5 right-3 z-20'> <div className='absolute top-2.5 right-3 z-20'>
<Tooltip <Tooltip
selector={'embed-scene-restart-button'} popupContent={t('share.chat.resetChat')}
htmlContent={t('share.chat.resetChat')}
position='top'
> >
<div className='p-1.5 bg-white border-[0.5px] border-gray-100 rounded-lg shadow-md cursor-pointer' onClick={handleNewConversation}> <div className='p-1.5 bg-white border-[0.5px] border-gray-100 rounded-lg shadow-md cursor-pointer' onClick={handleNewConversation}>
<RiLoopLeftLine className="h-4 w-4 text-gray-500"/> <RiLoopLeftLine className="h-4 w-4 text-gray-500"/>

View File

@ -1,10 +1,9 @@
'use client' 'use client'
import { useRef, useState } from 'react' import { useState } from 'react'
import { t } from 'i18next' import { t } from 'i18next'
import copy from 'copy-to-clipboard' import copy from 'copy-to-clipboard'
import s from './style.module.css' import s from './style.module.css'
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
import { randomString } from '@/utils'
type ICopyBtnProps = { type ICopyBtnProps = {
value: string value: string
@ -18,14 +17,11 @@ const CopyBtn = ({
isPlain, isPlain,
}: ICopyBtnProps) => { }: ICopyBtnProps) => {
const [isCopied, setIsCopied] = useState(false) const [isCopied, setIsCopied] = useState(false)
const selector = useRef(`copy-tooltip-${randomString(4)}`)
return ( return (
<div className={`${className}`}> <div className={`${className}`}>
<Tooltip <Tooltip
selector={selector.current} popupContent={(isCopied ? t('appApi.copied') : t('appApi.copy'))}
content={(isCopied ? t('appApi.copied') : t('appApi.copy')) as string}
className='z-10'
> >
<div <div
className={'box-border p-0.5 flex items-center justify-center rounded-md bg-white cursor-pointer'} className={'box-border p-0.5 flex items-center justify-center rounded-md bg-white cursor-pointer'}

View File

@ -3,19 +3,17 @@ import React, { useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { debounce } from 'lodash-es' import { debounce } from 'lodash-es'
import copy from 'copy-to-clipboard' import copy from 'copy-to-clipboard'
import Tooltip from '../tooltip'
import TooltipPlus from '../tooltip-plus'
import copyStyle from './style.module.css' import copyStyle from './style.module.css'
import Tooltip from '@/app/components/base/tooltip'
type Props = { type Props = {
content: string content: string
selectorId: string
className?: string className?: string
} }
const prefixEmbedded = 'appOverview.overview.appInfo.embedded' const prefixEmbedded = 'appOverview.overview.appInfo.embedded'
const CopyFeedback = ({ content, selectorId, className }: Props) => { const CopyFeedback = ({ content, className }: Props) => {
const { t } = useTranslation() const { t } = useTranslation()
const [isCopied, setIsCopied] = useState<boolean>(false) const [isCopied, setIsCopied] = useState<boolean>(false)
@ -30,8 +28,7 @@ const CopyFeedback = ({ content, selectorId, className }: Props) => {
return ( return (
<Tooltip <Tooltip
selector={`common-copy-feedback-${selectorId}`} popupContent={
content={
(isCopied (isCopied
? t(`${prefixEmbedded}.copied`) ? t(`${prefixEmbedded}.copied`)
: t(`${prefixEmbedded}.copy`)) || '' : t(`${prefixEmbedded}.copy`)) || ''
@ -41,10 +38,10 @@ const CopyFeedback = ({ content, selectorId, className }: Props) => {
className={`w-8 h-8 cursor-pointer hover:bg-gray-100 rounded-lg ${ className={`w-8 h-8 cursor-pointer hover:bg-gray-100 rounded-lg ${
className ?? '' className ?? ''
}`} }`}
onMouseLeave={onMouseLeave}
> >
<div <div
onClick={onClickCopy} onClick={onClickCopy}
onMouseLeave={onMouseLeave}
className={`w-full h-full ${copyStyle.copyIcon} ${ className={`w-full h-full ${copyStyle.copyIcon} ${
isCopied ? copyStyle.copied : '' isCopied ? copyStyle.copied : ''
}`} }`}
@ -70,7 +67,7 @@ export const CopyFeedbackNew = ({ content, className }: Pick<Props, 'className'
}, 100) }, 100)
return ( return (
<TooltipPlus <Tooltip
popupContent={ popupContent={
(isCopied (isCopied
? t(`${prefixEmbedded}.copied`) ? t(`${prefixEmbedded}.copied`)
@ -81,15 +78,15 @@ export const CopyFeedbackNew = ({ content, className }: Pick<Props, 'className'
className={`w-8 h-8 cursor-pointer hover:bg-gray-100 rounded-lg ${ className={`w-8 h-8 cursor-pointer hover:bg-gray-100 rounded-lg ${
className ?? '' className ?? ''
}`} }`}
onMouseLeave={onMouseLeave}
> >
<div <div
onClick={onClickCopy} onClick={onClickCopy}
onMouseLeave={onMouseLeave}
className={`w-full h-full ${copyStyle.copyIcon} ${ className={`w-full h-full ${copyStyle.copyIcon} ${
isCopied ? copyStyle.copied : '' isCopied ? copyStyle.copied : ''
}`} }`}
></div> ></div>
</div> </div>
</TooltipPlus> </Tooltip>
) )
} }

View File

@ -3,7 +3,7 @@ import React, { useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { debounce } from 'lodash-es' import { debounce } from 'lodash-es'
import copy from 'copy-to-clipboard' import copy from 'copy-to-clipboard'
import TooltipPlus from '../tooltip-plus' import Tooltip from '../tooltip'
import { import {
Clipboard, Clipboard,
ClipboardCheck, ClipboardCheck,
@ -29,7 +29,7 @@ export const CopyIcon = ({ content }: Props) => {
}, 100) }, 100)
return ( return (
<TooltipPlus <Tooltip
popupContent={ popupContent={
(isCopied (isCopied
? t(`${prefixEmbedded}.copied`) ? t(`${prefixEmbedded}.copied`)
@ -46,7 +46,7 @@ export const CopyIcon = ({ content }: Props) => {
) )
} }
</div> </div>
</TooltipPlus> </Tooltip>
) )
} }

View File

@ -2,11 +2,8 @@
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import {
RiQuestionLine,
} from '@remixicon/react'
import { MessageSmileSquare } from '@/app/components/base/icons/src/vender/solid/communication' import { MessageSmileSquare } from '@/app/components/base/icons/src/vender/solid/communication'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
const SuggestedQuestionsAfterAnswer: FC = () => { const SuggestedQuestionsAfterAnswer: FC = () => {
const { t } = useTranslation() const { t } = useTranslation()
@ -18,9 +15,7 @@ const SuggestedQuestionsAfterAnswer: FC = () => {
</div> </div>
<div className='shrink-0 mr-2 flex items-center whitespace-nowrap text-sm text-gray-800 font-semibold'> <div className='shrink-0 mr-2 flex items-center whitespace-nowrap text-sm text-gray-800 font-semibold'>
<div className='mr-2'>{t('appDebug.feature.suggestedQuestionsAfterAnswer.title')}</div> <div className='mr-2'>{t('appDebug.feature.suggestedQuestionsAfterAnswer.title')}</div>
<TooltipPlus popupContent={t('appDebug.feature.suggestedQuestionsAfterAnswer.description')}> <Tooltip popupContent={t('appDebug.feature.suggestedQuestionsAfterAnswer.description')}/>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' />
</TooltipPlus>
</div> </div>
<div className='grow'></div> <div className='grow'></div>
<div className='text-xs text-gray-500'>{t('appDebug.feature.suggestedQuestionsAfterAnswer.resDes')}</div> <div className='text-xs text-gray-500'>{t('appDebug.feature.suggestedQuestionsAfterAnswer.resDes')}</div>

View File

@ -2,9 +2,6 @@
import useSWR from 'swr' import useSWR from 'swr'
import produce from 'immer' import produce from 'immer'
import React, { Fragment } from 'react' import React, { Fragment } from 'react'
import {
RiQuestionLine,
} from '@remixicon/react'
import { usePathname } from 'next/navigation' import { usePathname } from 'next/navigation'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Listbox, Transition } from '@headlessui/react' import { Listbox, Transition } from '@headlessui/react'
@ -74,13 +71,16 @@ const VoiceParamConfig = ({
<div className='mb-2 flex items-center space-x-1'> <div className='mb-2 flex items-center space-x-1'>
<div <div
className='leading-[18px] text-[13px] font-semibold text-gray-800'>{t('appDebug.voice.voiceSettings.language')}</div> className='leading-[18px] text-[13px] font-semibold text-gray-800'>{t('appDebug.voice.voiceSettings.language')}</div>
<Tooltip htmlContent={<div className='w-[180px]'> <Tooltip
{t('appDebug.voice.voiceSettings.resolutionTooltip').split('\n').map(item => ( popupContent={
<div key={item}>{item}</div> <div className='w-[180px]'>
))} {t('appDebug.voice.voiceSettings.resolutionTooltip').split('\n').map(item => (
</div>} selector='config-resolution-tooltip'> <div key={item}>{item}
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400'/> </div>
</Tooltip> ))}
</div>
}
/>
</div> </div>
<Listbox <Listbox
value={languageItem} value={languageItem}

View File

@ -8,7 +8,7 @@ import {
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { RefreshCcw01 } from '@/app/components/base/icons/src/vender/line/arrows' import { RefreshCcw01 } from '@/app/components/base/icons/src/vender/line/arrows'
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback' import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import type { ImageFile } from '@/types/app' import type { ImageFile } from '@/types/app'
import { TransferMethod } from '@/types/app' import { TransferMethod } from '@/types/app'
import ImagePreview from '@/app/components/base/image-uploader/image-preview' import ImagePreview from '@/app/components/base/image-uploader/image-preview'
@ -87,11 +87,11 @@ const ImageList: FC<ImageListProps> = ({
<RiLoader2Line className="animate-spin w-5 h-5 text-white" /> <RiLoader2Line className="animate-spin w-5 h-5 text-white" />
)} )}
{item.progress === -1 && ( {item.progress === -1 && (
<TooltipPlus <Tooltip
popupContent={t('common.imageUploader.pasteImageLinkInvalid')} popupContent={t('common.imageUploader.pasteImageLinkInvalid')}
> >
<AlertTriangle className="w-4 h-4 text-[#DC6803]" /> <AlertTriangle className="w-4 h-4 text-[#DC6803]" />
</TooltipPlus> </Tooltip>
)} )}
</div> </div>
)} )}

View File

@ -1,10 +1,6 @@
'use client' 'use client'
import type { FC } from 'react' import type { FC } from 'react'
import { import Tooltip from '@/app/components/base/tooltip'
RiQuestionLine,
} from '@remixicon/react'
import Tooltip from '@/app/components/base/tooltip-plus'
import Slider from '@/app/components/base/slider' import Slider from '@/app/components/base/slider'
import Switch from '@/app/components/base/switch' import Switch from '@/app/components/base/switch'
@ -40,9 +36,9 @@ const ParamItem: FC<Props> = ({ className, id, name, noTooltip, tip, step = 0.1,
)} )}
<span className="mx-1 text-gray-900 text-[13px] leading-[18px] font-medium">{name}</span> <span className="mx-1 text-gray-900 text-[13px] leading-[18px] font-medium">{name}</span>
{!noTooltip && ( {!noTooltip && (
<Tooltip popupContent={<div className="w-[200px]">{tip}</div>}> <Tooltip
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' /> popupContent={<div className="w-[200px]">{tip}</div>}
</Tooltip> />
)} )}
</div> </div>

View File

@ -25,7 +25,7 @@ import { BubbleX, Env } from '@/app/components/base/icons/src/vender/line/others
import { VarBlockIcon } from '@/app/components/workflow/block-icon' import { VarBlockIcon } from '@/app/components/workflow/block-icon'
import { Line3 } from '@/app/components/base/icons/src/public/common' import { Line3 } from '@/app/components/base/icons/src/public/common'
import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils' import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
type WorkflowVariableBlockComponentProps = { type WorkflowVariableBlockComponentProps = {
nodeKey: string nodeKey: string
@ -113,9 +113,9 @@ const WorkflowVariableBlockComponent = ({
if (!node && !isEnv && !isChatVar) { if (!node && !isEnv && !isChatVar) {
return ( return (
<TooltipPlus popupContent={t('workflow.errorMsg.invalidVariable')}> <Tooltip popupContent={t('workflow.errorMsg.invalidVariable')}>
{Item} {Item}
</TooltipPlus> </Tooltip>
) )
} }

View File

@ -2,8 +2,8 @@
import React, { useEffect, useRef, useState } from 'react' import React, { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import QRCode from 'qrcode.react' import QRCode from 'qrcode.react'
import Tooltip from '../tooltip'
import QrcodeStyle from './style.module.css' import QrcodeStyle from './style.module.css'
import Tooltip from '@/app/components/base/tooltip'
type Props = { type Props = {
content: string content: string
@ -51,8 +51,7 @@ const ShareQRCode = ({ content, selectorId, className }: Props) => {
return ( return (
<Tooltip <Tooltip
selector={`common-qrcode-show-${selectorId}`} popupContent={t(`${prefixEmbedded}`) || ''}
content={t(`${prefixEmbedded}`) || ''}
> >
<div <div
className={`w-8 h-8 cursor-pointer rounded-lg ${className ?? ''}`} className={`w-8 h-8 cursor-pointer rounded-lg ${className ?? ''}`}

View File

@ -1,109 +0,0 @@
'use client'
import type { FC } from 'react'
import React, { useEffect, useRef, useState } from 'react'
import { useBoolean } from 'ahooks'
import type { OffsetOptions, Placement } from '@floating-ui/react'
import cn from '@/utils/classnames'
import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
export type TooltipProps = {
position?: Placement
triggerMethod?: 'hover' | 'click'
disabled?: boolean
popupContent: React.ReactNode
children: React.ReactNode
hideArrow?: boolean
popupClassName?: string
offset?: OffsetOptions
asChild?: boolean
}
const arrow = (
<svg className="absolute text-white h-2 w-full left-0 top-full" x="0px" y="0px" viewBox="0 0 255 255"><polygon className="fill-current" points="0,0 127.5,127.5 255,0"></polygon></svg>
)
const Tooltip: FC<TooltipProps> = ({
position = 'top',
triggerMethod = 'hover',
disabled = false,
popupContent,
children,
hideArrow,
popupClassName,
offset,
asChild,
}) => {
const [open, setOpen] = useState(false)
const [isHoverPopup, {
setTrue: setHoverPopup,
setFalse: setNotHoverPopup,
}] = useBoolean(false)
const isHoverPopupRef = useRef(isHoverPopup)
useEffect(() => {
isHoverPopupRef.current = isHoverPopup
}, [isHoverPopup])
const [isHoverTrigger, {
setTrue: setHoverTrigger,
setFalse: setNotHoverTrigger,
}] = useBoolean(false)
const isHoverTriggerRef = useRef(isHoverTrigger)
useEffect(() => {
isHoverTriggerRef.current = isHoverTrigger
}, [isHoverTrigger])
const handleLeave = (isTrigger: boolean) => {
if (isTrigger)
setNotHoverTrigger()
else
setNotHoverPopup()
// give time to move to the popup
setTimeout(() => {
if (!isHoverPopupRef.current && !isHoverTriggerRef.current)
setOpen(false)
}, 500)
}
return (
<PortalToFollowElem
open={disabled ? false : open}
onOpenChange={setOpen}
placement={position}
offset={offset ?? 10}
>
<PortalToFollowElemTrigger
onClick={() => triggerMethod === 'click' && setOpen(v => !v)}
onMouseEnter={() => {
if (triggerMethod === 'hover') {
setHoverTrigger()
setOpen(true)
}
}}
onMouseLeave={() => triggerMethod === 'hover' && handleLeave(true)}
asChild={asChild}
>
{children}
</PortalToFollowElemTrigger>
<PortalToFollowElemContent
className="z-[9999]"
>
<div
className={cn(
'relative px-3 py-2 text-xs font-normal text-gray-700 bg-white rounded-md shadow-lg',
popupClassName,
)}
onMouseEnter={() => triggerMethod === 'hover' && setHoverPopup()}
onMouseLeave={() => triggerMethod === 'hover' && handleLeave(false)}
>
{popupContent}
{!hideArrow && arrow}
</div>
</PortalToFollowElemContent>
</PortalToFollowElem>
)
}
export default React.memo(Tooltip)

View File

@ -1,52 +1,112 @@
'use client' 'use client'
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React, { useEffect, useRef, useState } from 'react'
import { Tooltip as ReactTooltip } from 'react-tooltip' // fixed version to 5.8.3 https://github.com/ReactTooltip/react-tooltip/issues/972 import { useBoolean } from 'ahooks'
import classNames from '@/utils/classnames' import type { OffsetOptions, Placement } from '@floating-ui/react'
import 'react-tooltip/dist/react-tooltip.css' import { RiQuestionLine } from '@remixicon/react'
import cn from '@/utils/classnames'
type TooltipProps = { import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
selector: string export type TooltipProps = {
content?: string position?: Placement
triggerMethod?: 'hover' | 'click'
triggerClassName?: string
disabled?: boolean disabled?: boolean
htmlContent?: React.ReactNode popupContent?: React.ReactNode
className?: string // This should use !impornant to override the default styles eg: '!bg-white' children?: React.ReactNode
position?: 'top' | 'right' | 'bottom' | 'left' popupClassName?: string
clickable?: boolean offset?: OffsetOptions
children: React.ReactNode needsDelay?: boolean
noArrow?: boolean asChild?: boolean
} }
const Tooltip: FC<TooltipProps> = ({ const Tooltip: FC<TooltipProps> = ({
selector,
content,
disabled,
position = 'top', position = 'top',
triggerMethod = 'hover',
triggerClassName,
disabled = false,
popupContent,
children, children,
htmlContent, popupClassName,
className, offset,
clickable, asChild = true,
noArrow, needsDelay = false,
}) => { }) => {
const [open, setOpen] = useState(false)
const [isHoverPopup, {
setTrue: setHoverPopup,
setFalse: setNotHoverPopup,
}] = useBoolean(false)
const isHoverPopupRef = useRef(isHoverPopup)
useEffect(() => {
isHoverPopupRef.current = isHoverPopup
}, [isHoverPopup])
const [isHoverTrigger, {
setTrue: setHoverTrigger,
setFalse: setNotHoverTrigger,
}] = useBoolean(false)
const isHoverTriggerRef = useRef(isHoverTrigger)
useEffect(() => {
isHoverTriggerRef.current = isHoverTrigger
}, [isHoverTrigger])
const handleLeave = (isTrigger: boolean) => {
if (isTrigger)
setNotHoverTrigger()
else
setNotHoverPopup()
// give time to move to the popup
if (needsDelay) {
setTimeout(() => {
if (!isHoverPopupRef.current && !isHoverTriggerRef.current)
setOpen(false)
}, 500)
}
else {
setOpen(false)
}
}
return ( return (
<div className='tooltip-container'> <PortalToFollowElem
{React.cloneElement(children as React.ReactElement, { open={disabled ? false : open}
'data-tooltip-id': selector, onOpenChange={setOpen}
}) placement={position}
} offset={offset ?? 8}
<ReactTooltip >
id={selector} <PortalToFollowElemTrigger
content={content} onClick={() => triggerMethod === 'click' && setOpen(v => !v)}
className={classNames('!z-[999] !bg-white !text-xs !font-normal !text-gray-700 !shadow-lg !opacity-100', className)} onMouseEnter={() => {
place={position} if (triggerMethod === 'hover') {
clickable={clickable} setHoverTrigger()
isOpen={disabled ? false : undefined} setOpen(true)
noArrow={noArrow} }
}}
onMouseLeave={() => triggerMethod === 'hover' && handleLeave(true)}
asChild={asChild}
> >
{htmlContent && htmlContent} {children || <div className={triggerClassName || 'p-[1px] w-3.5 h-3.5 shrink-0'}><RiQuestionLine className='text-text-quaternary hover:text-text-tertiary w-full h-full' /></div>}
</ReactTooltip> </PortalToFollowElemTrigger>
</div> <PortalToFollowElemContent
className="z-[9999]"
>
{popupContent && (<div
className={cn(
'relative px-3 py-2 text-xs font-normal text-gray-700 bg-white rounded-md shadow-lg break-words',
popupClassName,
)}
onMouseEnter={() => triggerMethod === 'hover' && setHoverPopup()}
onMouseLeave={() => triggerMethod === 'hover' && handleLeave(false)}
>
{popupContent}
</div>)}
</PortalToFollowElemContent>
</PortalToFollowElem>
) )
} }
export default Tooltip export default React.memo(Tooltip)

View File

@ -2,14 +2,11 @@
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import {
RiQuestionLine,
} from '@remixicon/react'
import { useContext } from 'use-context-selector' import { useContext } from 'use-context-selector'
import { Plan } from '../type' import { Plan } from '../type'
import { ALL_PLANS, NUM_INFINITE, contactSalesUrl, contractSales, unAvailable } from '../config' import { ALL_PLANS, NUM_INFINITE, contactSalesUrl, contractSales, unAvailable } from '../config'
import Toast from '../../base/toast' import Toast from '../../base/toast'
import TooltipPlus from '../../base/tooltip-plus' import Tooltip from '../../base/tooltip'
import { PlanRange } from './select-plan-range' import { PlanRange } from './select-plan-range'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { useAppContext } from '@/context/app-context' import { useAppContext } from '@/context/app-context'
@ -30,13 +27,11 @@ const KeyValue = ({ label, value, tooltip }: { label: string; value: string | nu
<div className='flex items-center text-gray-500 space-x-1'> <div className='flex items-center text-gray-500 space-x-1'>
<div>{label}</div> <div>{label}</div>
{tooltip && ( {tooltip && (
<TooltipPlus <Tooltip
popupContent={ popupContent={
<div className='w-[200px]'>{tooltip}</div> <div className='w-[200px]'>{tooltip}</div>
} }
> />
<RiQuestionLine className='w-3 h-3 text-gray-400' />
</TooltipPlus>
)} )}
</div> </div>
<div className='mt-0.5 text-gray-900'>{value}</div> <div className='mt-0.5 text-gray-900'>{value}</div>
@ -136,25 +131,21 @@ const PlanItem: FC<Props> = ({
<div className='mt-3.5 flex items-center space-x-1'> <div className='mt-3.5 flex items-center space-x-1'>
<span>+ </span> <span>+ </span>
<div>{t('billing.plansCommon.supportItems.llmLoadingBalancing')}</div> <div>{t('billing.plansCommon.supportItems.llmLoadingBalancing')}</div>
<TooltipPlus <Tooltip
popupContent={ popupContent={
<div className='w-[200px]'>{t('billing.plansCommon.supportItems.llmLoadingBalancingTooltip')}</div> <div className='w-[200px]'>{t('billing.plansCommon.supportItems.llmLoadingBalancingTooltip')}</div>
} }
> />
<RiQuestionLine className='w-3 h-3 text-gray-400' />
</TooltipPlus>
</div> </div>
<div className='mt-3.5 flex items-center space-x-1'> <div className='mt-3.5 flex items-center space-x-1'>
<div className='flex items-center'> <div className='flex items-center'>
+ +
<div className='mr-0.5'>&nbsp;{t('billing.plansCommon.supportItems.ragAPIRequest')}</div> <div className='mr-0.5'>&nbsp;{t('billing.plansCommon.supportItems.ragAPIRequest')}</div>
<TooltipPlus <Tooltip
popupContent={ popupContent={
<div className='w-[200px]'>{t('billing.plansCommon.ragAPIRequestTooltip')}</div> <div className='w-[200px]'>{t('billing.plansCommon.ragAPIRequestTooltip')}</div>
} }
> />
<RiQuestionLine className='w-3 h-3 text-gray-400' />
</TooltipPlus>
</div> </div>
<div>{comingSoon}</div> <div>{comingSoon}</div>
</div> </div>

View File

@ -9,7 +9,7 @@ import {
ZapFast, ZapFast,
ZapNarrow, ZapNarrow,
} from '@/app/components/base/icons/src/vender/solid/general' } from '@/app/components/base/icons/src/vender/solid/general'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
const PriorityLabel = () => { const PriorityLabel = () => {
const { t } = useTranslation() const { t } = useTranslation()
@ -27,7 +27,7 @@ const PriorityLabel = () => {
}, [plan]) }, [plan])
return ( return (
<TooltipPlus popupContent={ <Tooltip popupContent={
<div> <div>
<div className='mb-1 text-xs font-semibold text-gray-700'>{`${t('billing.plansCommon.documentProcessingPriority')}: ${t(`billing.plansCommon.priority.${priority}`)}`}</div> <div className='mb-1 text-xs font-semibold text-gray-700'>{`${t('billing.plansCommon.documentProcessingPriority')}: ${t(`billing.plansCommon.priority.${priority}`)}`}</div>
{ {
@ -53,7 +53,7 @@ const PriorityLabel = () => {
} }
{t(`billing.plansCommon.priority.${priority}`)} {t(`billing.plansCommon.priority.${priority}`)}
</span> </span>
</TooltipPlus> </Tooltip>
) )
} }

View File

@ -2,7 +2,6 @@
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { InfoCircle } from '../../base/icons/src/vender/line/general'
import ProgressBar from '../progress-bar' import ProgressBar from '../progress-bar'
import { NUM_INFINITE } from '../config' import { NUM_INFINITE } from '../config'
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
@ -48,11 +47,13 @@ const UsageInfo: FC<Props> = ({
<Icon className='w-4 h-4 text-gray-700' /> <Icon className='w-4 h-4 text-gray-700' />
<div className='mx-1 leading-5 text-sm font-medium text-gray-700'>{name}</div> <div className='mx-1 leading-5 text-sm font-medium text-gray-700'>{name}</div>
{tooltip && ( {tooltip && (
<Tooltip htmlContent={<div className='w-[180px]'> <Tooltip
{tooltip} popupContent={
</div>} selector='config-var-tooltip'> <div className='w-[180px]'>
<InfoCircle className='w-[14px] h-[14px] text-gray-400' /> {tooltip}
</Tooltip> </div>
}
/>
)} )}
</div> </div>
<div className='flex items-center leading-[18px] text-[13px] font-normal'> <div className='flex items-center leading-[18px] text-[13px] font-normal'>

View File

@ -2,15 +2,13 @@
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import {
RiQuestionLine,
} from '@remixicon/react'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import TopKItem from '@/app/components/base/param-item/top-k-item' import TopKItem from '@/app/components/base/param-item/top-k-item'
import ScoreThresholdItem from '@/app/components/base/param-item/score-threshold-item' import ScoreThresholdItem from '@/app/components/base/param-item/score-threshold-item'
import { RETRIEVE_METHOD } from '@/types/app' import { RETRIEVE_METHOD } from '@/types/app'
import Switch from '@/app/components/base/switch' import Switch from '@/app/components/base/switch'
import Tooltip from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import type { RetrievalConfig } from '@/types/app' import type { RetrievalConfig } from '@/types/app'
import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector' import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
import { useModelListAndDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks' import { useModelListAndDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
@ -114,9 +112,11 @@ const RetrievalParamConfig: FC<Props> = ({
)} )}
<div className='flex items-center'> <div className='flex items-center'>
<span className='mr-0.5'>{t('common.modelProvider.rerankModel.key')}</span> <span className='mr-0.5'>{t('common.modelProvider.rerankModel.key')}</span>
<Tooltip popupContent={<div className="w-[200px]">{t('common.modelProvider.rerankModel.tip')}</div>}> <Tooltip
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' /> popupContent={
</Tooltip> <div className="w-[200px]">{t('common.modelProvider.rerankModel.tip')}</div>
}
/>
</div> </div>
</div> </div>
<ModelSelector <ModelSelector
@ -191,10 +191,8 @@ const RetrievalParamConfig: FC<Props> = ({
<div className='truncate'>{option.label}</div> <div className='truncate'>{option.label}</div>
<Tooltip <Tooltip
popupContent={<div className='w-[200px]'>{option.tips}</div>} popupContent={<div className='w-[200px]'>{option.tips}</div>}
hideArrow triggerClassName='ml-0.5 w-3.5 h-4.5'
> />
<RiQuestionLine className='ml-0.5 w-3.5 h-4.5 text-text-quaternary' />
</Tooltip>
</div> </div>
)) ))
} }

View File

@ -22,7 +22,7 @@ import { Plan } from '@/app/components/billing/type'
import { ZapFast } from '@/app/components/base/icons/src/vender/solid/general' import { ZapFast } from '@/app/components/base/icons/src/vender/solid/general'
import UpgradeBtn from '@/app/components/billing/upgrade-btn' import UpgradeBtn from '@/app/components/billing/upgrade-btn'
import { useProviderContext } from '@/context/provider-context' import { useProviderContext } from '@/context/provider-context'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import { sleep } from '@/utils' import { sleep } from '@/utils'
type Props = { type Props = {
@ -259,16 +259,18 @@ const EmbeddingProcess: FC<Props> = ({ datasetId, batchId, documents = [], index
<div className={s.percent}>{`${getSourcePercent(indexingStatusDetail)}%`}</div> <div className={s.percent}>{`${getSourcePercent(indexingStatusDetail)}%`}</div>
)} )}
{indexingStatusDetail.indexing_status === 'error' && indexingStatusDetail.error && ( {indexingStatusDetail.indexing_status === 'error' && indexingStatusDetail.error && (
<TooltipPlus popupContent={( <Tooltip
<div className='max-w-[400px]'> popupContent={(
{indexingStatusDetail.error} <div className='max-w-[400px]'>
</div> {indexingStatusDetail.error}
)}> </div>
)}
>
<div className={cn(s.percent, s.error, 'flex items-center')}> <div className={cn(s.percent, s.error, 'flex items-center')}>
Error Error
<RiErrorWarningFill className='ml-1 w-4 h-4' /> <RiErrorWarningFill className='ml-1 w-4 h-4' />
</div> </div>
</TooltipPlus> </Tooltip>
)} )}
{indexingStatusDetail.indexing_status === 'error' && !indexingStatusDetail.error && ( {indexingStatusDetail.indexing_status === 'error' && !indexingStatusDetail.error && (
<div className={cn(s.percent, s.error, 'flex items-center')}> <div className={cn(s.percent, s.error, 'flex items-center')}>

View File

@ -7,7 +7,6 @@ import { XMarkIcon } from '@heroicons/react/20/solid'
import { RocketLaunchIcon } from '@heroicons/react/24/outline' import { RocketLaunchIcon } from '@heroicons/react/24/outline'
import { import {
RiCloseLine, RiCloseLine,
RiQuestionLine,
} from '@remixicon/react' } from '@remixicon/react'
import Link from 'next/link' import Link from 'next/link'
import { groupBy } from 'lodash-es' import { groupBy } from 'lodash-es'
@ -43,7 +42,6 @@ import { IS_CE_EDITION } from '@/config'
import { RETRIEVE_METHOD } from '@/types/app' import { RETRIEVE_METHOD } from '@/types/app'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
import TooltipPlus from '@/app/components/base/tooltip-plus'
import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks' import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { LanguagesSupported } from '@/i18n/language' import { LanguagesSupported } from '@/i18n/language'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
@ -556,7 +554,7 @@ const StepTwo = ({
className='border-[0.5px] !h-8 hover:outline hover:outline-[0.5px] hover:outline-gray-300 text-gray-700 font-medium bg-white shadow-[0px_1px_2px_0px_rgba(16,24,40,0.05)]' className='border-[0.5px] !h-8 hover:outline hover:outline-[0.5px] hover:outline-gray-300 text-gray-700 font-medium bg-white shadow-[0px_1px_2px_0px_rgba(16,24,40,0.05)]'
onClick={setShowPreview} onClick={setShowPreview}
> >
<Tooltip selector='data-preview-toggle'> <Tooltip>
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
<RocketLaunchIcon className="h-4 w-4 mr-1.5 stroke-[1.8px]" /> <RocketLaunchIcon className="h-4 w-4 mr-1.5 stroke-[1.8px]" />
<span className="text-[13px]">{t('datasetCreation.stepTwo.previewTitleButton')}</span> <span className="text-[13px]">{t('datasetCreation.stepTwo.previewTitleButton')}</span>
@ -628,13 +626,13 @@ const StepTwo = ({
<div className='w-full'> <div className='w-full'>
<div className={s.label}> <div className={s.label}>
{t('datasetCreation.stepTwo.overlap')} {t('datasetCreation.stepTwo.overlap')}
<TooltipPlus popupContent={ <Tooltip
<div className='max-w-[200px]'> popupContent={
{t('datasetCreation.stepTwo.overlapTip')} <div className='max-w-[200px]'>
</div> {t('datasetCreation.stepTwo.overlapTip')}
}> </div>
<RiQuestionLine className='ml-1 w-3.5 h-3.5 text-gray-400' /> }
</TooltipPlus> />
</div> </div>
<input <input
type="number" type="number"

View File

@ -1,12 +1,9 @@
'use client' 'use client'
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React from 'react'
import {
RiQuestionLine,
} from '@remixicon/react'
import Input from './input' import Input from './input'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
type Props = { type Props = {
className?: string className?: string
@ -37,11 +34,12 @@ const Field: FC<Props> = ({
<div className={cn(labelClassName, 'flex items-center h-[18px] text-[13px] font-medium text-gray-900')}>{label} </div> <div className={cn(labelClassName, 'flex items-center h-[18px] text-[13px] font-medium text-gray-900')}>{label} </div>
{isRequired && <span className='ml-0.5 text-xs font-semibold text-[#D92D20]'>*</span>} {isRequired && <span className='ml-0.5 text-xs font-semibold text-[#D92D20]'>*</span>}
{tooltip && ( {tooltip && (
<TooltipPlus popupContent={ <Tooltip
<div className='w-[200px]'>{tooltip}</div> popupContent={
}> <div className='w-[200px]'>{tooltip}</div>
<RiQuestionLine className='relative top-[3px] w-3 h-3 ml-1 text-gray-500' /> }
</TooltipPlus> popupClassName='relative top-[3px] w-3 h-3 ml-1'
/>
)} )}
</div> </div>
<Input <Input

View File

@ -102,7 +102,9 @@ const IconButton: FC<{
const metadataMap = useMetadataMap() const metadataMap = useMetadataMap()
return ( return (
<Tooltip content={metadataMap[type].text} selector={`doc-metadata-${type}`}> <Tooltip
popupContent={metadataMap[type].text}
>
<button className={cn(s.iconWrapper, 'group', isChecked ? s.iconCheck : '')}> <button className={cn(s.iconWrapper, 'group', isChecked ? s.iconCheck : '')}>
<TypeIcon <TypeIcon
iconName={metadataMap[type].iconName || ''} iconName={metadataMap[type].iconName || ''}

View File

@ -7,14 +7,12 @@ import { ArrowDownIcon, TrashIcon } from '@heroicons/react/24/outline'
import { pick } from 'lodash-es' import { pick } from 'lodash-es'
import { import {
RiMoreFill, RiMoreFill,
RiQuestionLine,
} from '@remixicon/react' } from '@remixicon/react'
import { useContext } from 'use-context-selector' import { useContext } from 'use-context-selector'
import { useRouter } from 'next/navigation' import { useRouter } from 'next/navigation'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { Edit03 } from '../../base/icons/src/vender/solid/general' import { Edit03 } from '../../base/icons/src/vender/solid/general'
import TooltipPlus from '../../base/tooltip-plus'
import { Globe01 } from '../../base/icons/src/vender/line/mapsAndTravel' import { Globe01 } from '../../base/icons/src/vender/line/mapsAndTravel'
import s from './style.module.css' import s from './style.module.css'
import RenameModal from './rename-modal' import RenameModal from './rename-modal'
@ -94,13 +92,11 @@ export const StatusItem: FC<{
{ {
errorMessage && ( errorMessage && (
<Tooltip <Tooltip
selector='dataset-document-detail-item-status' popupContent={
htmlContent={
<div className='max-w-[260px] break-all'>{errorMessage}</div> <div className='max-w-[260px] break-all'>{errorMessage}</div>
} }
> triggerClassName='ml-1 w-4 h-4'
<RiQuestionLine className='ml-1 w-[14px] h-[14px] text-gray-700' /> />
</Tooltip>
) )
} }
</div> </div>
@ -201,7 +197,11 @@ export const OperationAction: FC<{
{isListScene && embeddingAvailable && ( {isListScene && embeddingAvailable && (
<> <>
{archived {archived
? <Tooltip selector={`list-switch-${id}`} content={t('datasetDocuments.list.action.enableWarning') as string} className='!font-semibold'> ? <Tooltip
popupContent={t('datasetDocuments.list.action.enableWarning')}
popupClassName='!font-semibold'
needsDelay
>
<div> <div>
<Switch defaultValue={false} onChange={() => { }} disabled={true} size='md' /> <Switch defaultValue={false} onChange={() => { }} disabled={true} size='md' />
</div> </div>
@ -221,9 +221,9 @@ export const OperationAction: FC<{
{!archived && enabled ? t('datasetDocuments.list.index.enable') : t('datasetDocuments.list.index.disable')} {!archived && enabled ? t('datasetDocuments.list.index.enable') : t('datasetDocuments.list.index.disable')}
</span> </span>
<Tooltip <Tooltip
selector={`detail-switch-${id}`} popupContent={t('datasetDocuments.list.action.enableWarning')}
content={t('datasetDocuments.list.action.enableWarning') as string} popupClassName='!font-semibold'
className='!font-semibold' needsDelay
disabled={!archived} disabled={!archived}
> >
<div> <div>
@ -426,7 +426,9 @@ const DocumentList: FC<IDocumentListProps> = ({ embeddingAvailable, documents =
} }
</span> </span>
<div className='group-hover:flex hidden'> <div className='group-hover:flex hidden'>
<TooltipPlus popupContent={t('datasetDocuments.list.table.rename')}> <Tooltip
popupContent={t('datasetDocuments.list.table.rename')}
>
<div <div
className='p-1 rounded-md cursor-pointer hover:bg-black/5' className='p-1 rounded-md cursor-pointer hover:bg-black/5'
onClick={(e) => { onClick={(e) => {
@ -436,7 +438,7 @@ const DocumentList: FC<IDocumentListProps> = ({ embeddingAvailable, documents =
> >
<Edit03 className='w-4 h-4 text-gray-500' /> <Edit03 className='w-4 h-4 text-gray-500' />
</div> </div>
</TooltipPlus> </Tooltip>
</div> </div>
</div> </div>

View File

@ -1,9 +1,9 @@
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import Button from '../../base/button' import Button from '../../base/button'
import Tag from '../../base/tag' import Tag from '../../base/tag'
import Tooltip from '../../base/tooltip'
import { getIcon } from '../common/retrieval-method-info' import { getIcon } from '../common/retrieval-method-info'
import s from './style.module.css' import s from './style.module.css'
import Tooltip from '@/app/components/base/tooltip'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import type { HitTestingResponse } from '@/models/datasets' import type { HitTestingResponse } from '@/models/datasets'
import { hitTesting } from '@/service/datasets' import { hitTesting } from '@/service/datasets'
@ -74,8 +74,7 @@ const TextAreaWithButton = ({
{t('datasetHitTesting.input.title')} {t('datasetHitTesting.input.title')}
</span> </span>
<Tooltip <Tooltip
selector={'change-retrieval-method'} popupContent={t('dataset.retrieval.changeRetrievalMethod')}
htmlContent={t('dataset.retrieval.changeRetrievalMethod')}
> >
<div <div
onClick={onClickRetrievalMethod} onClick={onClickRetrievalMethod}
@ -99,8 +98,7 @@ const TextAreaWithButton = ({
{text?.length > 200 {text?.length > 200
? ( ? (
<Tooltip <Tooltip
content={t('datasetHitTesting.input.countWarning') as string} popupContent={t('datasetHitTesting.input.countWarning')}
selector="hit-testing-warning"
> >
<div> <div>
<Tag color="red" className="!text-red-600"> <Tag color="red" className="!text-red-600">

View File

@ -1,9 +1,8 @@
'use client' 'use client'
import React, { useEffect, useRef, useState } from 'react' import React, { useEffect, useState } from 'react'
import copy from 'copy-to-clipboard' import copy from 'copy-to-clipboard'
import { t } from 'i18next' import { t } from 'i18next'
import s from './style.module.css' import s from './style.module.css'
import { randomString } from '@/utils'
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
type IInputCopyProps = { type IInputCopyProps = {
@ -21,8 +20,6 @@ const InputCopy = ({
}: IInputCopyProps) => { }: IInputCopyProps) => {
const [isCopied, setIsCopied] = useState(false) const [isCopied, setIsCopied] = useState(false)
const selector = useRef(`input-tooltip-${randomString(4)}`)
useEffect(() => { useEffect(() => {
if (isCopied) { if (isCopied) {
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
@ -40,22 +37,22 @@ const InputCopy = ({
<div className="flex items-center flex-grow h-5"> <div className="flex items-center flex-grow h-5">
{children} {children}
<div className='flex-grow bg-gray-50 text-[13px] relative h-full'> <div className='flex-grow bg-gray-50 text-[13px] relative h-full'>
<Tooltip <div className='absolute top-0 left-0 w-full pl-2 pr-2 truncate cursor-pointer r-0' onClick={() => {
selector={selector.current} copy(value)
content={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`} setIsCopied(true)
className='z-10' }}>
> <Tooltip
<div className='absolute top-0 left-0 w-full pl-2 pr-2 truncate cursor-pointer r-0' onClick={() => { popupContent={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
copy(value) position='bottom'
setIsCopied(true) >
}}>{value}</div> {value}
</Tooltip> </Tooltip>
</div>
</div> </div>
<div className="flex-shrink-0 h-4 bg-gray-200 border" /> <div className="flex-shrink-0 h-4 bg-gray-200 border" />
<Tooltip <Tooltip
selector={selector.current} popupContent={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
content={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`} position='bottom'
className='z-10'
> >
<div className="px-0.5 flex-shrink-0"> <div className="px-0.5 flex-shrink-0">
<div className={`box-border w-[30px] h-[30px] flex items-center justify-center rounded-lg hover:bg-gray-100 cursor-pointer ${s.copyIcon} ${isCopied ? s.copied : ''}`} onClick={() => { <div className={`box-border w-[30px] h-[30px] flex items-center justify-center rounded-lg hover:bg-gray-100 cursor-pointer ${s.copyIcon} ${isCopied ? s.copied : ''}`} onClick={() => {

View File

@ -118,9 +118,8 @@ const SecretKeyModal = ({
<div className='flex-shrink-0 px-3 truncate w-[200px]'>{api.last_used_at ? formatTime(Number(api.last_used_at), t('appLog.dateTimeFormat') as string) : t('appApi.never')}</div> <div className='flex-shrink-0 px-3 truncate w-[200px]'>{api.last_used_at ? formatTime(Number(api.last_used_at), t('appLog.dateTimeFormat') as string) : t('appApi.never')}</div>
<div className='flex flex-grow px-3'> <div className='flex flex-grow px-3'>
<Tooltip <Tooltip
selector={`key-${api.token}`} popupContent={copyValue === api.token ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
content={copyValue === api.token ? `${t('appApi.copied')}` : `${t('appApi.copy')}`} popupClassName='mr-1'
className='z-10'
> >
<div className={`flex items-center justify-center flex-shrink-0 w-6 h-6 mr-1 rounded-lg cursor-pointer hover:bg-gray-100 ${s.copyIcon} ${copyValue === api.token ? s.copied : ''}`} onClick={() => { <div className={`flex items-center justify-center flex-shrink-0 w-6 h-6 mr-1 rounded-lg cursor-pointer hover:bg-gray-100 ${s.copyIcon} ${copyValue === api.token ? s.copied : ''}`} onClick={() => {
// setIsCopied(true) // setIsCopied(true)

View File

@ -1,5 +1,6 @@
import { CheckCircleIcon } from '@heroicons/react/24/solid' import { CheckCircleIcon } from '@heroicons/react/24/solid'
import { QuestionMarkCircleIcon, XMarkIcon } from '@heroicons/react/24/outline' import { XMarkIcon } from '@heroicons/react/24/outline'
import { RiQuestionLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useMemo } from 'react' import { useMemo } from 'react'
import InvitationLink from './invitation-link' import InvitationLink from './invitation-link'
@ -64,12 +65,11 @@ const InvitedModal = ({
failedInvationResults.map(item => failedInvationResults.map(item =>
<div key={item.email} className='flex justify-center border border-red-300 rounded-md px-1 bg-orange-50'> <div key={item.email} className='flex justify-center border border-red-300 rounded-md px-1 bg-orange-50'>
<Tooltip <Tooltip
selector={`invitation-tag-${item.email}`} popupContent={item.message}
htmlContent={item.message}
> >
<div className='flex justify-center items-center text-sm gap-1'> <div className='flex justify-center items-center text-sm gap-1'>
{item.email} {item.email}
<QuestionMarkCircleIcon className='w-4 h-4 text-red-300' /> <RiQuestionLine className='w-4 h-4 text-red-300' />
</div> </div>
</Tooltip> </Tooltip>
</div>, </div>,

View File

@ -39,18 +39,14 @@ const InvitationLink = ({
<div className="flex items-center flex-grow h-5"> <div className="flex items-center flex-grow h-5">
<div className='flex-grow bg-gray-100 text-[13px] relative h-full'> <div className='flex-grow bg-gray-100 text-[13px] relative h-full'>
<Tooltip <Tooltip
selector={selector.current} popupContent={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
content={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
className='z-10'
> >
<div className='absolute top-0 left-0 w-full pl-2 pr-2 truncate cursor-pointer r-0' onClick={copyHandle}>{value.url}</div> <div className='absolute top-0 left-0 w-full pl-2 pr-2 truncate cursor-pointer r-0' onClick={copyHandle}>{value.url}</div>
</Tooltip> </Tooltip>
</div> </div>
<div className="flex-shrink-0 h-4 bg-gray-200 border" /> <div className="flex-shrink-0 h-4 bg-gray-200 border" />
<Tooltip <Tooltip
selector={selector.current} popupContent={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
content={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
className='z-10'
> >
<div className="px-0.5 flex-shrink-0"> <div className="px-0.5 flex-shrink-0">
<div className={`box-border w-[30px] h-[30px] flex items-center justify-center rounded-lg hover:bg-gray-100 cursor-pointer ${s.copyIcon} ${isCopied ? s.copied : ''}`} onClick={copyHandle}> <div className={`box-border w-[30px] h-[30px] flex items-center justify-center rounded-lg hover:bg-gray-100 cursor-pointer ${s.copyIcon} ${isCopied ? s.copied : ''}`} onClick={copyHandle}>

View File

@ -1,8 +1,6 @@
import { Fragment, useState } from 'react' import { Fragment, useState } from 'react'
import type { FC } from 'react' import type { FC } from 'react'
import { import { RiQuestionLine } from '@remixicon/react'
RiQuestionLine,
} from '@remixicon/react'
import { ValidatingTip } from '../../key-validator/ValidateStatus' import { ValidatingTip } from '../../key-validator/ValidateStatus'
import type { import type {
CredentialFormSchema, CredentialFormSchema,
@ -18,7 +16,7 @@ import { useLanguage } from '../hooks'
import Input from './Input' import Input from './Input'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { SimpleSelect } from '@/app/components/base/select' import { SimpleSelect } from '@/app/components/base/select'
import Tooltip from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import Radio from '@/app/components/base/radio' import Radio from '@/app/components/base/radio'
type FormProps = { type FormProps = {
className?: string className?: string

View File

@ -1,8 +1,5 @@
import type { FC } from 'react' import type { FC } from 'react'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import {
RiQuestionLine,
} from '@remixicon/react'
import type { ModelParameterRule } from '../declarations' import type { ModelParameterRule } from '../declarations'
import { useLanguage } from '../hooks' import { useLanguage } from '../hooks'
import { isNullOrUndefined } from '../utils' import { isNullOrUndefined } from '../utils'
@ -241,18 +238,18 @@ const ParameterItem: FC<ParameterItemProps> = ({
{ {
parameterRule.help && ( parameterRule.help && (
<Tooltip <Tooltip
selector={`model-parameter-rule-${parameterRule.name}`} popupContent={(
htmlContent={(
<div className='w-[200px] whitespace-pre-wrap'>{parameterRule.help[language] || parameterRule.help.en_US}</div> <div className='w-[200px] whitespace-pre-wrap'>{parameterRule.help[language] || parameterRule.help.en_US}</div>
)} )}
> popupClassName='mr-1'
<RiQuestionLine className='mr-1.5 w-3.5 h-3.5 text-gray-400' /> triggerClassName='mr-1 w-4 h-4 shrink-0'
</Tooltip> />
) )
} }
{ {
!parameterRule.required && parameterRule.name !== 'stop' && ( !parameterRule.required && parameterRule.name !== 'stop' && (
<Switch <Switch
className='mr-1'
defaultValue={!isNullOrUndefined(value)} defaultValue={!isNullOrUndefined(value)}
onChange={handleSwitch} onChange={handleSwitch}
size='md' size='md'

View File

@ -14,7 +14,7 @@ import cn from '@/utils/classnames'
import { useProviderContext } from '@/context/provider-context' import { useProviderContext } from '@/context/provider-context'
import { SlidersH } from '@/app/components/base/icons/src/vender/line/mediaAndDevices' import { SlidersH } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback' import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
export type TriggerProps = { export type TriggerProps = {
open?: boolean open?: boolean
@ -90,7 +90,7 @@ const Trigger: FC<TriggerProps> = ({
{ {
disabled disabled
? ( ? (
<TooltipPlus <Tooltip
popupContent={ popupContent={
hasDeprecated hasDeprecated
? t('common.modelProvider.deprecated') ? t('common.modelProvider.deprecated')
@ -100,7 +100,7 @@ const Trigger: FC<TriggerProps> = ({
} }
> >
<AlertTriangle className='w-4 h-4 text-[#F79009]' /> <AlertTriangle className='w-4 h-4 text-[#F79009]' />
</TooltipPlus> </Tooltip>
) )
: ( : (
<SlidersH className={cn(!isInWorkflow ? 'text-indigo-600' : 'text-gray-500', 'shrink-0 w-4 h-4')} /> <SlidersH className={cn(!isInWorkflow ? 'text-indigo-600' : 'text-gray-500', 'shrink-0 w-4 h-4')} />

View File

@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
import ModelIcon from '../model-icon' import ModelIcon from '../model-icon'
import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback' import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
import { useProviderContext } from '@/context/provider-context' import { useProviderContext } from '@/context/provider-context'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
type ModelTriggerProps = { type ModelTriggerProps = {
modelName: string modelName: string
@ -35,9 +35,9 @@ const ModelTrigger: FC<ModelTriggerProps> = ({
{modelName} {modelName}
</div> </div>
<div className='shrink-0 flex items-center justify-center w-4 h-4'> <div className='shrink-0 flex items-center justify-center w-4 h-4'>
<TooltipPlus popupContent={t('common.modelProvider.deprecated')}> <Tooltip popupContent={t('common.modelProvider.deprecated')}>
<AlertTriangle className='w-4 h-4 text-[#F79009]' /> <AlertTriangle className='w-4 h-4 text-[#F79009]' />
</TooltipPlus> </Tooltip>
</div> </div>
</div> </div>
) )

View File

@ -11,7 +11,7 @@ import {
// MagicWand, // MagicWand,
// Robot, // Robot,
} from '@/app/components/base/icons/src/vender/solid/mediaAndDevices' } from '@/app/components/base/icons/src/vender/solid/mediaAndDevices'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
type FeatureIconProps = { type FeatureIconProps = {
feature: ModelFeatureEnum feature: ModelFeatureEnum
@ -25,49 +25,51 @@ const FeatureIcon: FC<FeatureIconProps> = ({
// if (feature === ModelFeatureEnum.agentThought) { // if (feature === ModelFeatureEnum.agentThought) {
// return ( // return (
// <TooltipPlus // <Tooltip
// popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.agentThought })} // popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.agentThought })}
// > // >
// <ModelBadge className={`mr-0.5 !px-0 w-[18px] justify-center text-gray-500 ${className}`}> // <ModelBadge className={`mr-0.5 !px-0 w-[18px] justify-center text-gray-500 ${className}`}>
// <Robot className='w-3 h-3' /> // <Robot className='w-3 h-3' />
// </ModelBadge> // </ModelBadge>
// </TooltipPlus> // </Tooltip>
// ) // )
// } // }
// if (feature === ModelFeatureEnum.toolCall) { // if (feature === ModelFeatureEnum.toolCall) {
// return ( // return (
// <TooltipPlus // <Tooltip
// popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.toolCall })} // popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.toolCall })}
// > // >
// <ModelBadge className={`mr-0.5 !px-0 w-[18px] justify-center text-gray-500 ${className}`}> // <ModelBadge className={`mr-0.5 !px-0 w-[18px] justify-center text-gray-500 ${className}`}>
// <MagicWand className='w-3 h-3' /> // <MagicWand className='w-3 h-3' />
// </ModelBadge> // </ModelBadge>
// </TooltipPlus> // </Tooltip>
// ) // )
// } // }
// if (feature === ModelFeatureEnum.multiToolCall) { // if (feature === ModelFeatureEnum.multiToolCall) {
// return ( // return (
// <TooltipPlus // <Tooltip
// popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.multiToolCall })} // popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.multiToolCall })}
// > // >
// <ModelBadge className={`mr-0.5 !px-0 w-[18px] justify-center text-gray-500 ${className}`}> // <ModelBadge className={`mr-0.5 !px-0 w-[18px] justify-center text-gray-500 ${className}`}>
// <MagicBox className='w-3 h-3' /> // <MagicBox className='w-3 h-3' />
// </ModelBadge> // </ModelBadge>
// </TooltipPlus> // </Tooltip>
// ) // )
// } // }
if (feature === ModelFeatureEnum.vision) { if (feature === ModelFeatureEnum.vision) {
return ( return (
<TooltipPlus <Tooltip
popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.vision })} popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.vision })}
> >
<ModelBadge className={`mr-0.5 !px-0 w-[18px] justify-center text-gray-500 ${className}`}> <div className='inline-block cursor-help'>
<MagicEyes className='w-3 h-3' /> <ModelBadge className={`mr-0.5 !px-0 w-[18px] justify-center text-gray-500 ${className}`}>
</ModelBadge> <MagicEyes className='w-3 h-3' />
</TooltipPlus> </ModelBadge>
</div>
</Tooltip>
) )
} }

View File

@ -12,7 +12,7 @@ import { useLanguage } from '../hooks'
import ModelIcon from '../model-icon' import ModelIcon from '../model-icon'
import ModelName from '../model-name' import ModelName from '../model-name'
import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback' import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
type ModelTriggerProps = { type ModelTriggerProps = {
open: boolean open: boolean
@ -56,9 +56,9 @@ const ModelTrigger: FC<ModelTriggerProps> = ({
{ {
model.status !== ModelStatusEnum.active model.status !== ModelStatusEnum.active
? ( ? (
<TooltipPlus popupContent={MODEL_STATUS_TEXT[model.status][language]}> <Tooltip popupContent={MODEL_STATUS_TEXT[model.status][language]}>
<AlertTriangle className='w-4 h-4 text-[#F79009]' /> <AlertTriangle className='w-4 h-4 text-[#F79009]' />
</TooltipPlus> </Tooltip>
) )
: ( : (
<RiArrowDownSLine <RiArrowDownSLine

View File

@ -70,9 +70,8 @@ const PopupItem: FC<PopupItemProps> = ({
{ {
model.models.map(modelItem => ( model.models.map(modelItem => (
<Tooltip <Tooltip
selector={`${modelItem.model}-${modelItem.status}`}
key={modelItem.model} key={modelItem.model}
content={modelItem.status !== ModelStatusEnum.active ? MODEL_STATUS_TEXT[modelItem.status][language] : undefined} popupContent={modelItem.status !== ModelStatusEnum.active ? MODEL_STATUS_TEXT[modelItem.status][language] : undefined}
position='right' position='right'
> >
<div <div

View File

@ -2,7 +2,7 @@ import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useLatest } from 'ahooks' import { useLatest } from 'ahooks'
import SimplePieChart from '@/app/components/base/simple-pie-chart' import SimplePieChart from '@/app/components/base/simple-pie-chart'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
export type CooldownTimerProps = { export type CooldownTimerProps = {
secondsRemaining?: number secondsRemaining?: number
@ -54,9 +54,9 @@ const CooldownTimer = ({ secondsRemaining, onFinish }: CooldownTimerProps) => {
return displayTime return displayTime
? ( ? (
<TooltipPlus popupContent={t('common.modelProvider.apiKeyRateLimit', { seconds: displayTime })}> <Tooltip popupContent={t('common.modelProvider.apiKeyRateLimit', { seconds: displayTime })}>
<SimplePieChart percentage={Math.round(displayTime / 60 * 100)} className='w-3 h-3' /> <SimplePieChart percentage={Math.round(displayTime / 60 * 100)} className='w-3 h-3' />
</TooltipPlus> </Tooltip>
) )
: null : null
} }

View File

@ -11,7 +11,7 @@ import Button from '@/app/components/base/button'
import { Balance } from '@/app/components/base/icons/src/vender/line/financeAndECommerce' import { Balance } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
import { Settings01 } from '@/app/components/base/icons/src/vender/line/general' import { Settings01 } from '@/app/components/base/icons/src/vender/line/general'
import Switch from '@/app/components/base/switch' import Switch from '@/app/components/base/switch'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import { useProviderContext, useProviderContextSelector } from '@/context/provider-context' import { useProviderContext, useProviderContextSelector } from '@/context/provider-context'
import { disableModel, enableModel } from '@/service/common' import { disableModel, enableModel } from '@/service/common'
import { Plan } from '@/app/components/billing/type' import { Plan } from '@/app/components/billing/type'
@ -99,9 +99,14 @@ const ModelListItem = ({ model, provider, isConfigurable, onConfig, onModifyLoad
{ {
model.deprecated model.deprecated
? ( ? (
<TooltipPlus popupContent={<span className='font-semibold'>{t('common.modelProvider.modelHasBeenDeprecated')}</span>} offset={{ mainAxis: 4 }}> <Tooltip
popupContent={
<span className='font-semibold'>{t('common.modelProvider.modelHasBeenDeprecated')}</span>} offset={{ mainAxis: 4 }
}
needsDelay
>
<Switch defaultValue={false} disabled size='md' /> <Switch defaultValue={false} disabled size='md' />
</TooltipPlus> </Tooltip>
) )
: (isCurrentWorkspaceManager && ( : (isCurrentWorkspaceManager && (
<Switch <Switch

View File

@ -3,13 +3,12 @@ import { useCallback } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { import {
RiDeleteBinLine, RiDeleteBinLine,
RiQuestionLine,
} from '@remixicon/react' } from '@remixicon/react'
import type { ConfigurationMethodEnum, CustomConfigurationModelFixedFields, ModelLoadBalancingConfig, ModelLoadBalancingConfigEntry, ModelProvider } from '../declarations' import type { ConfigurationMethodEnum, CustomConfigurationModelFixedFields, ModelLoadBalancingConfig, ModelLoadBalancingConfigEntry, ModelProvider } from '../declarations'
import Indicator from '../../../indicator' import Indicator from '../../../indicator'
import CooldownTimer from './cooldown-timer' import CooldownTimer from './cooldown-timer'
import classNames from '@/utils/classnames' import classNames from '@/utils/classnames'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import Switch from '@/app/components/base/switch' import Switch from '@/app/components/base/switch'
import { Balance } from '@/app/components/base/icons/src/vender/line/financeAndECommerce' import { Balance } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
import { Edit02, Plus02 } from '@/app/components/base/icons/src/vender/line/general' import { Edit02, Plus02 } from '@/app/components/base/icons/src/vender/line/general'
@ -160,9 +159,11 @@ const ModelLoadBalancingConfigs = ({
<div className='grow'> <div className='grow'>
<div className='flex items-center gap-1 text-sm'> <div className='flex items-center gap-1 text-sm'>
{t('common.modelProvider.loadBalancing')} {t('common.modelProvider.loadBalancing')}
<TooltipPlus popupContent={t('common.modelProvider.loadBalancingInfo')} popupClassName='max-w-[300px]'> <Tooltip
<RiQuestionLine className='w-3 h-3 text-gray-400' /> popupContent={t('common.modelProvider.loadBalancingInfo')}
</TooltipPlus> popupClassName='max-w-[300px]'
triggerClassName='w-3 h-3'
/>
</div> </div>
<div className='text-xs text-gray-500'>{t('common.modelProvider.loadBalancingDescription')}</div> <div className='text-xs text-gray-500'>{t('common.modelProvider.loadBalancingDescription')}</div>
</div> </div>
@ -191,9 +192,9 @@ const ModelLoadBalancingConfigs = ({
<CooldownTimer secondsRemaining={config.ttl} onFinish={() => clearCountdown(index)} /> <CooldownTimer secondsRemaining={config.ttl} onFinish={() => clearCountdown(index)} />
) )
: ( : (
<TooltipPlus popupContent={t('common.modelProvider.apiKeyStatusNormal')}> <Tooltip popupContent={t('common.modelProvider.apiKeyStatusNormal')}>
<Indicator color='green' /> <Indicator color='green' />
</TooltipPlus> </Tooltip>
)} )}
</div> </div>
<div className='text-[13px] mr-1'> <div className='text-[13px] mr-1'>

View File

@ -7,8 +7,7 @@ const PriorityUseTip = () => {
return ( return (
<Tooltip <Tooltip
selector='provider-quota-credential-priority-using' popupContent={t('common.modelProvider.priorityUsing') || ''}
content={t('common.modelProvider.priorityUsing') || ''}
> >
<div className='absolute -right-[5px] -top-[5px] bg-indigo-50 rounded-[5px] border-[0.5px] border-indigo-100 cursor-pointer'> <div className='absolute -right-[5px] -top-[5px] bg-indigo-50 rounded-[5px] border-[0.5px] border-indigo-100 cursor-pointer'>
<ChevronDownDouble className='rotate-180 w-3 h-3 text-indigo-600' /> <ChevronDownDouble className='rotate-180 w-3 h-3 text-indigo-600' />

View File

@ -10,8 +10,7 @@ import {
MODEL_PROVIDER_QUOTA_GET_PAID, MODEL_PROVIDER_QUOTA_GET_PAID,
} from '../utils' } from '../utils'
import PriorityUseTip from './priority-use-tip' import PriorityUseTip from './priority-use-tip'
import { InfoCircle } from '@/app/components/base/icons/src/vender/line/general' import Tooltip from '@/app/components/base/tooltip'
import TooltipPlus from '@/app/components/base/tooltip-plus'
import { formatNumber } from '@/utils/format' import { formatNumber } from '@/utils/format'
type QuotaPanelProps = { type QuotaPanelProps = {
@ -32,13 +31,12 @@ const QuotaPanel: FC<QuotaPanelProps> = ({
<div className='group relative shrink-0 min-w-[112px] px-3 py-2 rounded-lg bg-white/[0.3] border-[0.5px] border-black/5'> <div className='group relative shrink-0 min-w-[112px] px-3 py-2 rounded-lg bg-white/[0.3] border-[0.5px] border-black/5'>
<div className='flex items-center mb-2 h-4 text-xs font-medium text-gray-500'> <div className='flex items-center mb-2 h-4 text-xs font-medium text-gray-500'>
{t('common.modelProvider.quota')} {t('common.modelProvider.quota')}
<TooltipPlus popupContent={ <Tooltip popupContent={
openaiOrAnthropic openaiOrAnthropic
? t('common.modelProvider.card.tip') ? t('common.modelProvider.card.tip')
: t('common.modelProvider.quotaTip') : t('common.modelProvider.quotaTip')
}> }
<InfoCircle className='ml-0.5 w-3 h-3 text-gray-400' /> />
</TooltipPlus>
</div> </div>
{ {
currentQuota && ( currentQuota && (

View File

@ -1,9 +1,6 @@
import type { FC } from 'react' import type { FC } from 'react'
import { useState } from 'react' import { useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import {
RiQuestionLine,
} from '@remixicon/react'
import ModelSelector from '../model-selector' import ModelSelector from '../model-selector'
import { import {
useModelList, useModelList,
@ -146,13 +143,13 @@ const SystemModel: FC<SystemModelSelectorProps> = ({
<div className='flex items-center h-8 text-[13px] font-medium text-gray-900'> <div className='flex items-center h-8 text-[13px] font-medium text-gray-900'>
{t('common.modelProvider.systemReasoningModel.key')} {t('common.modelProvider.systemReasoningModel.key')}
<Tooltip <Tooltip
selector='model-page-system-reasoning-model-tip' popupContent={
htmlContent={ <div className='w-[261px] text-gray-500'>
<div className='w-[261px] text-gray-500'>{t('common.modelProvider.systemReasoningModel.tip')}</div> {t('common.modelProvider.systemReasoningModel.tip')}
</div>
} }
> triggerClassName='ml-0.5'
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-gray-400' /> />
</Tooltip>
</div> </div>
<div> <div>
<ModelSelector <ModelSelector
@ -166,13 +163,14 @@ const SystemModel: FC<SystemModelSelectorProps> = ({
<div className='flex items-center h-8 text-[13px] font-medium text-gray-900'> <div className='flex items-center h-8 text-[13px] font-medium text-gray-900'>
{t('common.modelProvider.embeddingModel.key')} {t('common.modelProvider.embeddingModel.key')}
<Tooltip <Tooltip
selector='model-page-system-embedding-model-tip' popupContent={
htmlContent={ <div className='w-[261px] text-gray-500'>
<div className='w-[261px] text-gray-500'>{t('common.modelProvider.embeddingModel.tip')}</div> {t('common.modelProvider.embeddingModel.tip')}
</div>
} }
> needsDelay={false}
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-gray-400' /> triggerClassName='ml-0.5'
</Tooltip> />
</div> </div>
<div> <div>
<ModelSelector <ModelSelector
@ -186,13 +184,14 @@ const SystemModel: FC<SystemModelSelectorProps> = ({
<div className='flex items-center h-8 text-[13px] font-medium text-gray-900'> <div className='flex items-center h-8 text-[13px] font-medium text-gray-900'>
{t('common.modelProvider.rerankModel.key')} {t('common.modelProvider.rerankModel.key')}
<Tooltip <Tooltip
selector='model-page-system-rerankModel-model-tip' popupContent={
htmlContent={ <div className='w-[261px] text-gray-500'>
<div className='w-[261px] text-gray-500'>{t('common.modelProvider.rerankModel.tip')}</div> {t('common.modelProvider.rerankModel.tip')}
</div>
} }
> needsDelay={false}
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-gray-400' /> triggerClassName='ml-0.5'
</Tooltip> />
</div> </div>
<div> <div>
<ModelSelector <ModelSelector
@ -206,13 +205,14 @@ const SystemModel: FC<SystemModelSelectorProps> = ({
<div className='flex items-center h-8 text-[13px] font-medium text-gray-900'> <div className='flex items-center h-8 text-[13px] font-medium text-gray-900'>
{t('common.modelProvider.speechToTextModel.key')} {t('common.modelProvider.speechToTextModel.key')}
<Tooltip <Tooltip
selector='model-page-system-speechToText-model-tip' popupContent={
htmlContent={ <div className='w-[261px] text-gray-500'>
<div className='w-[261px] text-gray-500'>{t('common.modelProvider.speechToTextModel.tip')}</div> {t('common.modelProvider.speechToTextModel.tip')}
</div>
} }
> needsDelay={false}
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-gray-400' /> triggerClassName='ml-0.5'
</Tooltip> />
</div> </div>
<div> <div>
<ModelSelector <ModelSelector
@ -226,13 +226,13 @@ const SystemModel: FC<SystemModelSelectorProps> = ({
<div className='flex items-center h-8 text-[13px] font-medium text-gray-900'> <div className='flex items-center h-8 text-[13px] font-medium text-gray-900'>
{t('common.modelProvider.ttsModel.key')} {t('common.modelProvider.ttsModel.key')}
<Tooltip <Tooltip
selector='model-page-system-tts-model-tip' popupContent={
htmlContent={ <div className='w-[261px] text-gray-500'>
<div className='w-[261px] text-gray-500'>{t('common.modelProvider.ttsModel.tip')}</div> {t('common.modelProvider.ttsModel.tip')}
</div>
} }
> triggerClassName='ml-0.5'
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-gray-400' /> />
</Tooltip>
</div> </div>
<div> <div>
<ModelSelector <ModelSelector

View File

@ -42,8 +42,7 @@ const Header: FC<IResultHeaderProps> = ({
{showFeedback && feedback.rating && feedback.rating === 'like' && ( {showFeedback && feedback.rating && feedback.rating === 'like' && (
<Tooltip <Tooltip
selector="undo-feedback-like" popupContent="Undo Great Rating"
content="Undo Great Rating"
> >
<div <div
onClick={() => { onClick={() => {
@ -59,8 +58,7 @@ const Header: FC<IResultHeaderProps> = ({
{showFeedback && feedback.rating && feedback.rating === 'dislike' && ( {showFeedback && feedback.rating && feedback.rating === 'dislike' && (
<Tooltip <Tooltip
selector="undo-feedback-dislike" popupContent="Undo Undesirable Response"
content="Undo Undesirable Response"
> >
<div <div
onClick={() => { onClick={() => {
@ -77,8 +75,8 @@ const Header: FC<IResultHeaderProps> = ({
{showFeedback && !feedback.rating && ( {showFeedback && !feedback.rating && (
<div className='flex rounded-lg border border-gray-200 p-[1px] space-x-1'> <div className='flex rounded-lg border border-gray-200 p-[1px] space-x-1'>
<Tooltip <Tooltip
selector="feedback-like" popupContent="Great Rating"
content="Great Rating" needsDelay={false}
> >
<div <div
onClick={() => { onClick={() => {
@ -91,8 +89,8 @@ const Header: FC<IResultHeaderProps> = ({
</div> </div>
</Tooltip> </Tooltip>
<Tooltip <Tooltip
selector="feedback-dislike" popupContent="Undesirable Response"
content="Undesirable Response" needsDelay={false}
> >
<div <div
onClick={() => { onClick={() => {

View File

@ -68,10 +68,9 @@ const Blocks = ({
return ( return (
<Tooltip <Tooltip
key={tool.name} key={tool.name}
selector={`workflow-block-tool-${tool.name}`}
position='bottom' position='bottom'
className='!p-0 !px-3 !py-2.5 !w-[210px] !leading-[18px] !text-xs !text-gray-700 !border-[0.5px] !border-black/5 !bg-transparent !rounded-xl !shadow-lg translate-x-[108px]' popupClassName='!p-0 !px-3 !py-2.5 !w-[210px] !leading-[18px] !text-xs !text-gray-700 !border-[0.5px] !border-black/5 !bg-transparent !rounded-xl !shadow-lg translate-x-[108px]'
htmlContent={( popupContent={(
<div> <div>
<BlockIcon <BlockIcon
size='md' size='md'
@ -91,7 +90,7 @@ const Blocks = ({
)} )}
</div> </div>
)} )}
noArrow needsDelay
> >
<div className='group/item flex items-center w-full pl-3 pr-1 h-8 rounded-lg hover:bg-gray-50 cursor-pointer'> <div className='group/item flex items-center w-full pl-3 pr-1 h-8 rounded-lg hover:bg-gray-50 cursor-pointer'>
<BlockIcon <BlockIcon

View File

@ -2,10 +2,7 @@
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { import Tooltip from '@/app/components/base/tooltip'
RiQuestionLine,
} from '@remixicon/react'
import Tooltip from '../../base/tooltip'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import type { Credential } from '@/app/components/tools/types' import type { Credential } from '@/app/components/tools/types'
import Drawer from '@/app/components/base/drawer-plus' import Drawer from '@/app/components/base/drawer-plus'
@ -112,15 +109,13 @@ const ConfigCredential: FC<Props> = ({
<div className='flex items-center h-8 text-[13px] font-medium text-gray-900'> <div className='flex items-center h-8 text-[13px] font-medium text-gray-900'>
{t('tools.createTool.authMethod.key')} {t('tools.createTool.authMethod.key')}
<Tooltip <Tooltip
selector='model-page-system-reasoning-model-tip' popupContent={
htmlContent={
<div className='w-[261px] text-gray-500'> <div className='w-[261px] text-gray-500'>
{t('tools.createTool.authMethod.keyTooltip')} {t('tools.createTool.authMethod.keyTooltip')}
</div> </div>
} }
> triggerClassName='ml-0.5'
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-gray-400' /> />
</Tooltip>
</div> </div>
<input <input
value={tempCredential.api_key_header} value={tempCredential.api_key_header}

View File

@ -2,9 +2,6 @@
import type { FC } from 'react' import type { FC } from 'react'
import React, { useState } from 'react' import React, { useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import {
RiQuestionLine,
} from '@remixicon/react'
import produce from 'immer' import produce from 'immer'
import type { Emoji, WorkflowToolProviderParameter, WorkflowToolProviderRequest } from '../types' import type { Emoji, WorkflowToolProviderParameter, WorkflowToolProviderRequest } from '../types'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
@ -148,15 +145,12 @@ const WorkflowToolAsModal: FC<Props> = ({
<div className='flex items-center py-2 leading-5 text-sm font-medium text-gray-900'> <div className='flex items-center py-2 leading-5 text-sm font-medium text-gray-900'>
{t('tools.createTool.nameForToolCall')} <span className='ml-1 text-red-500'>*</span> {t('tools.createTool.nameForToolCall')} <span className='ml-1 text-red-500'>*</span>
<Tooltip <Tooltip
htmlContent={ popupContent={
<div className='w-[180px]'> <div className='w-[180px]'>
{t('tools.createTool.nameForToolCallPlaceHolder')} {t('tools.createTool.nameForToolCallPlaceHolder')}
</div> </div>
} }
selector='workflow-tool-modal-tooltip' />
>
<RiQuestionLine className='ml-2 w-[14px] h-[14px] text-gray-400' />
</Tooltip>
</div> </div>
<input <input
type='text' type='text'

View File

@ -67,10 +67,9 @@ const Blocks = ({
list.map(block => ( list.map(block => (
<Tooltip <Tooltip
key={block.type} key={block.type}
selector={`workflow-block-${block.type}`}
position='right' position='right'
className='!p-0 !px-3 !py-2.5 !w-[200px] !leading-[18px] !text-xs !text-gray-700 !border-[0.5px] !border-black/5 !rounded-xl !shadow-lg' popupClassName='!p-0 !px-3 !py-2.5 !w-[200px] !leading-[18px] !text-xs !text-gray-700 !border-[0.5px] !border-black/5 !rounded-xl !shadow-lg'
htmlContent={( popupContent={(
<div> <div>
<BlockIcon <BlockIcon
size='md' size='md'
@ -81,7 +80,6 @@ const Blocks = ({
<div className='text-xs text-gray-700 leading-[18px]'>{nodesExtraData[block.type].about}</div> <div className='text-xs text-gray-700 leading-[18px]'>{nodesExtraData[block.type].about}</div>
</div> </div>
)} )}
noArrow
> >
<div <div
key={block.type} key={block.type}

View File

@ -44,10 +44,9 @@ const Blocks = ({
list.map(tool => ( list.map(tool => (
<Tooltip <Tooltip
key={tool.name} key={tool.name}
selector={`workflow-block-tool-${tool.name}`}
position='right' position='right'
className='!p-0 !px-3 !py-2.5 !w-[200px] !leading-[18px] !text-xs !text-gray-700 !border-[0.5px] !border-black/5 !rounded-xl !shadow-lg' popupClassName='!p-0 !px-3 !py-2.5 !w-[200px] !leading-[18px] !text-xs !text-gray-700 !border-[0.5px] !border-black/5 !rounded-xl !shadow-lg'
htmlContent={( popupContent={(
<div> <div>
<BlockIcon <BlockIcon
size='md' size='md'
@ -59,7 +58,6 @@ const Blocks = ({
<div className='text-xs text-gray-700 leading-[18px]'>{tool.description[language]}</div> <div className='text-xs text-gray-700 leading-[18px]'>{tool.description[language]}</div>
</div> </div>
)} )}
noArrow
> >
<div <div
className='flex items-center px-3 w-full h-8 rounded-lg hover:bg-gray-50 cursor-pointer' className='flex items-center px-3 w-full h-8 rounded-lg hover:bg-gray-50 cursor-pointer'
@ -77,7 +75,7 @@ const Blocks = ({
type={BlockEnum.Tool} type={BlockEnum.Tool}
toolIcon={toolWithProvider.icon} toolIcon={toolWithProvider.icon}
/> />
<div className='text-sm text-gray-900 truncate'>{tool.label[language]}</div> <div className='text-sm text-gray-900 flex-1 min-w-0 truncate'>{tool.label[language]}</div>
</div> </div>
</Tooltip> </Tooltip>
)) ))

View File

@ -24,7 +24,7 @@ import {
PortalToFollowElemContent, PortalToFollowElemContent,
PortalToFollowElemTrigger, PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem' } from '@/app/components/base/portal-to-follow-elem'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import { useStore as useAppStore } from '@/app/components/app/store' import { useStore as useAppStore } from '@/app/components/app/store'
import { import {
ClockPlay, ClockPlay,
@ -100,7 +100,7 @@ const ViewHistory = ({
} }
{ {
!withText && ( !withText && (
<TooltipPlus <Tooltip
popupContent={t('workflow.common.viewRunHistory')} popupContent={t('workflow.common.viewRunHistory')}
> >
<div <div
@ -112,7 +112,7 @@ const ViewHistory = ({
> >
<ClockPlay className={cn('w-4 h-4 group-hover:text-components-button-secondary-accent-text', open ? 'text-components-button-secondary-accent-text' : 'text-components-button-ghost-text')} /> <ClockPlay className={cn('w-4 h-4 group-hover:text-components-button-secondary-accent-text', open ? 'text-components-button-secondary-accent-text' : 'text-components-button-ghost-text')} />
</div> </div>
</TooltipPlus> </Tooltip>
) )
} }
</PortalToFollowElemTrigger> </PortalToFollowElemTrigger>

View File

@ -3,12 +3,11 @@ import type { FC } from 'react'
import React from 'react' import React from 'react'
import { import {
RiArrowDownSLine, RiArrowDownSLine,
RiQuestionLine,
} from '@remixicon/react' } from '@remixicon/react'
import { useBoolean } from 'ahooks' import { useBoolean } from 'ahooks'
import type { DefaultTFuncReturn } from 'i18next' import type { DefaultTFuncReturn } from 'i18next'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
type Props = { type Props = {
className?: string className?: string
@ -40,12 +39,11 @@ const Filed: FC<Props> = ({
<div className='flex items-center h-6'> <div className='flex items-center h-6'>
<div className='system-sm-semibold-uppercase text-text-secondary'>{title}</div> <div className='system-sm-semibold-uppercase text-text-secondary'>{title}</div>
{tooltip && ( {tooltip && (
<TooltipPlus popupContent={ <Tooltip
<div className='w-[120px]'> popupContent={tooltip}
{tooltip} popupClassName='ml-1'
</div>}> triggerClassName='w-4 h-4 ml-1'
<RiQuestionLine className='w-3.5 h-3.5 ml-0.5 text-text-quaternary' /> />
</TooltipPlus>
)} )}
</div> </div>

View File

@ -2,7 +2,7 @@ import { memo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { RiBookOpenLine } from '@remixicon/react' import { RiBookOpenLine } from '@remixicon/react'
import { useNodeHelpLink } from '../hooks/use-node-help-link' import { useNodeHelpLink } from '../hooks/use-node-help-link'
import TooltipPlus from '@/app/components/base/tooltip-plus' import TooltipPlus from '@/app/components/base/tooltip'
import type { BlockEnum } from '@/app/components/workflow/types' import type { BlockEnum } from '@/app/components/workflow/types'
type HelpLinkProps = { type HelpLinkProps = {
@ -15,7 +15,9 @@ const HelpLink = ({
const link = useNodeHelpLink(nodeType) const link = useNodeHelpLink(nodeType)
return ( return (
<TooltipPlus popupContent={t('common.userProfile.helpCenter')}> <TooltipPlus
popupContent={t('common.userProfile.helpCenter')}
>
<a <a
href={link} href={link}
target='_blank' target='_blank'

View File

@ -11,7 +11,7 @@ import type {
import { BlockEnum } from '@/app/components/workflow/types' import { BlockEnum } from '@/app/components/workflow/types'
import PromptEditor from '@/app/components/base/prompt-editor' import PromptEditor from '@/app/components/base/prompt-editor'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
type Props = { type Props = {
instanceId?: string instanceId?: string
@ -109,13 +109,13 @@ const Editor: FC<Props> = ({
{readOnly && <div className='absolute inset-0 z-10'></div>} {readOnly && <div className='absolute inset-0 z-10'></div>}
{isFocus && ( {isFocus && (
<div className={cn('absolute z-10', insertVarTipToLeft ? 'top-1.5 left-[-12px]' : ' top-[-9px] right-1')}> <div className={cn('absolute z-10', insertVarTipToLeft ? 'top-1.5 left-[-12px]' : ' top-[-9px] right-1')}>
<TooltipPlus <Tooltip
popupContent={`${t('workflow.common.insertVarTip')}`} popupContent={`${t('workflow.common.insertVarTip')}`}
> >
<div className='p-0.5 rounded-[5px] shadow-lg cursor-pointer bg-white hover:bg-gray-100 border-[0.5px] border-black/5'> <div className='p-0.5 rounded-[5px] shadow-lg cursor-pointer bg-white hover:bg-gray-100 border-[0.5px] border-black/5'>
<Variable02 className='w-3.5 h-3.5 text-components-button-secondary-accent-text' /> <Variable02 className='w-3.5 h-3.5 text-components-button-secondary-accent-text' />
</div> </div>
</TooltipPlus> </Tooltip>
</div> </div>
)} )}
</> </>

View File

@ -19,7 +19,7 @@ import PanelOperator from './panel-operator'
import { import {
Stop, Stop,
} from '@/app/components/base/icons/src/vender/line/mediaAndDevices' } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
type NodeControlProps = Pick<Node, 'id' | 'data'> type NodeControlProps = Pick<Node, 'id' | 'data'>
const NodeControl: FC<NodeControlProps> = ({ const NodeControl: FC<NodeControlProps> = ({
@ -68,11 +68,12 @@ const NodeControl: FC<NodeControlProps> = ({
data._isSingleRun data._isSingleRun
? <Stop className='w-3 h-3' /> ? <Stop className='w-3 h-3' />
: ( : (
<TooltipPlus <Tooltip
popupContent={t('workflow.panel.runThisStep')} popupContent={t('workflow.panel.runThisStep')}
asChild={false}
> >
<RiPlayLargeLine className='w-3 h-3' /> <RiPlayLargeLine className='w-3 h-3' />
</TooltipPlus> </Tooltip>
) )
} }
</div> </div>

View File

@ -3,9 +3,8 @@ import type { FC } from 'react'
import React, { useCallback } from 'react' import React, { useCallback } from 'react'
import type { VariantProps } from 'class-variance-authority' import type { VariantProps } from 'class-variance-authority'
import { cva } from 'class-variance-authority' import { cva } from 'class-variance-authority'
import { RiQuestionLine } from '@remixicon/react'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
const variants = cva([], { const variants = cva([], {
variants: { variants: {
@ -59,13 +58,15 @@ const OptionCard: FC<Props> = ({
onClick={handleSelect} onClick={handleSelect}
> >
<span>{title}</span> <span>{title}</span>
{tooltip && <TooltipPlus {tooltip
popupContent={<div className='w-[240px]'> && <Tooltip
{tooltip} popupContent={
</div>} <div className='w-[240px]'>
> {tooltip}
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-text-quaternary' /> </div>
</TooltipPlus>} }
/>
}
</div> </div>
) )
} }

View File

@ -31,7 +31,7 @@ import { useEventEmitterContextContext } from '@/context/event-emitter'
import { PROMPT_EDITOR_INSERT_QUICKLY } from '@/app/components/base/prompt-editor/plugins/update-block' import { PROMPT_EDITOR_INSERT_QUICKLY } from '@/app/components/base/prompt-editor/plugins/update-block'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
import ActionButton from '@/app/components/base/action-button' import ActionButton from '@/app/components/base/action-button'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor/editor-support-vars' import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor/editor-support-vars'
import Switch from '@/app/components/base/switch' import Switch from '@/app/components/base/switch'
import { Jinja } from '@/app/components/base/icons/src/vender/workflow' import { Jinja } from '@/app/components/base/icons/src/vender/workflow'
@ -141,14 +141,14 @@ const Editor: FC<Props> = ({
{/* Operations */} {/* Operations */}
<div className='flex items-center space-x-[2px]'> <div className='flex items-center space-x-[2px]'>
{isSupportJinja && ( {isSupportJinja && (
<TooltipPlus <Tooltip
popupContent={ popupContent={
<div> <div>
<div>{t('workflow.common.enableJinja')}</div> <div>{t('workflow.common.enableJinja')}</div>
<a className='text-[#155EEF]' target='_blank' href='https://jinja.palletsprojects.com/en/2.10.x/'>{t('workflow.common.learnMore')}</a> <a className='text-[#155EEF]' target='_blank' href='https://jinja.palletsprojects.com/en/2.10.x/'>{t('workflow.common.learnMore')}</a>
</div> </div>
} }
hideArrow needsDelay
> >
<div className={cn(editionType === EditionType.jinja2 && 'border-black/5 bg-white', 'flex h-[22px] items-center px-1.5 rounded-[5px] border border-transparent hover:border-black/5 space-x-0.5')}> <div className={cn(editionType === EditionType.jinja2 && 'border-black/5 bg-white', 'flex h-[22px] items-center px-1.5 rounded-[5px] border border-transparent hover:border-black/5 space-x-0.5')}>
<Jinja className='w-6 h-3 text-gray-300' /> <Jinja className='w-6 h-3 text-gray-300' />
@ -160,18 +160,17 @@ const Editor: FC<Props> = ({
}} }}
/> />
</div> </div>
</TooltipPlus> </Tooltip>
)} )}
{!readOnly && ( {!readOnly && (
<TooltipPlus <Tooltip
popupContent={`${t('workflow.common.insertVarTip')}`} popupContent={`${t('workflow.common.insertVarTip')}`}
asChild
> >
<ActionButton onClick={handleInsertVariable}> <ActionButton onClick={handleInsertVariable}>
<Variable02 className='w-4 h-4' /> <Variable02 className='w-4 h-4' />
</ActionButton> </ActionButton>
</TooltipPlus> </Tooltip>
)} )}
{showRemove && ( {showRemove && (
<ActionButton onClick={onRemove}> <ActionButton onClick={onRemove}>

View File

@ -35,7 +35,7 @@ import {
useWorkflowHistory, useWorkflowHistory,
} from '@/app/components/workflow/hooks' } from '@/app/components/workflow/hooks'
import { canRunBySingle } from '@/app/components/workflow/utils' import { canRunBySingle } from '@/app/components/workflow/utils'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import type { Node } from '@/app/components/workflow/types' import type { Node } from '@/app/components/workflow/types'
import { useStore as useAppStore } from '@/app/components/app/store' import { useStore as useAppStore } from '@/app/components/app/store'
import { useStore } from '@/app/components/workflow/store' import { useStore } from '@/app/components/workflow/store'
@ -127,8 +127,9 @@ const BasePanel: FC<BasePanelProps> = ({
<div className='shrink-0 flex items-center text-gray-500'> <div className='shrink-0 flex items-center text-gray-500'>
{ {
canRunBySingle(data.type) && !nodesReadOnly && ( canRunBySingle(data.type) && !nodesReadOnly && (
<TooltipPlus <Tooltip
popupContent={t('workflow.panel.runThisStep')} popupContent={t('workflow.panel.runThisStep')}
popupClassName='mr-1'
> >
<div <div
className='flex items-center justify-center mr-1 w-6 h-6 rounded-md hover:bg-black/5 cursor-pointer' className='flex items-center justify-center mr-1 w-6 h-6 rounded-md hover:bg-black/5 cursor-pointer'
@ -139,7 +140,7 @@ const BasePanel: FC<BasePanelProps> = ({
> >
<RiPlayLargeLine className='w-4 h-4 text-text-tertiary' /> <RiPlayLargeLine className='w-4 h-4 text-text-tertiary' />
</div> </div>
</TooltipPlus> </Tooltip>
) )
} }
<HelpLink nodeType={data.type} /> <HelpLink nodeType={data.type} />

View File

@ -29,7 +29,7 @@ import type {
import { import {
BlockEnum, BlockEnum,
} from '@/app/components/workflow/types' } from '@/app/components/workflow/types'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
type AddBlockProps = { type AddBlockProps = {
iterationNodeId: string iterationNodeId: string
@ -99,11 +99,11 @@ const AddBlock = ({
return ( return (
<div className='absolute top-12 left-6 flex items-center h-8 z-10'> <div className='absolute top-12 left-6 flex items-center h-8 z-10'>
<TooltipPlus popupContent={t('workflow.blocks.iteration-start')}> <Tooltip popupContent={t('workflow.blocks.iteration-start')}>
<div className='flex items-center justify-center w-6 h-6 rounded-full border-[0.5px] border-black/[0.02] shadow-md bg-primary-500'> <div className='flex items-center justify-center w-6 h-6 rounded-full border-[0.5px] border-black/[0.02] shadow-md bg-primary-500'>
<IterationStart className='w-4 h-4 text-white' /> <IterationStart className='w-4 h-4 text-white' />
</div> </div>
</TooltipPlus> </Tooltip>
<div className='group/insert relative w-16 h-0.5 bg-gray-300'> <div className='group/insert relative w-16 h-0.5 bg-gray-300'>
{ {
iterationNodeData.startNodeType && ( iterationNodeData.startNodeType && (

View File

@ -3,13 +3,12 @@ import type { FC } from 'react'
import React, { useCallback, useEffect, useState } from 'react' import React, { useCallback, useEffect, useState } from 'react'
import { uniqueId } from 'lodash-es' import { uniqueId } from 'lodash-es'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { RiQuestionLine } from '@remixicon/react'
import type { ModelConfig, PromptItem, Variable } from '../../../types' import type { ModelConfig, PromptItem, Variable } from '../../../types'
import { EditionType } from '../../../types' import { EditionType } from '../../../types'
import { useWorkflowStore } from '../../../store' import { useWorkflowStore } from '../../../store'
import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor' import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor'
import TypeSelector from '@/app/components/workflow/nodes/_base/components/selector' import TypeSelector from '@/app/components/workflow/nodes/_base/components/selector'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import { PromptRole } from '@/models/debug' import { PromptRole } from '@/models/debug'
const i18nPrefix = 'workflow.nodes.llm' const i18nPrefix = 'workflow.nodes.llm'
@ -118,13 +117,12 @@ const ConfigPromptItem: FC<Props> = ({
/> />
)} )}
<TooltipPlus <Tooltip
popupContent={ popupContent={
<div className='max-w-[180px]'>{t(`${i18nPrefix}.roleDescription.${payload.role}`)}</div> <div className='max-w-[180px]'>{t(`${i18nPrefix}.roleDescription.${payload.role}`)}</div>
} }
> triggerClassName='w-4 h-4'
<RiQuestionLine className='w-3.5 h-3.5 text-gray-400' /> />
</TooltipPlus>
</div> </div>
} }
value={payload.edition_type === EditionType.jinja2 ? (payload.jinja2_text || '') : payload.text} value={payload.edition_type === EditionType.jinja2 ? (payload.jinja2_text || '') : payload.text}

View File

@ -1,7 +1,6 @@
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { RiQuestionLine } from '@remixicon/react'
import MemoryConfig from '../_base/components/memory-config' import MemoryConfig from '../_base/components/memory-config'
import VarReferencePicker from '../_base/components/variable/var-reference-picker' import VarReferencePicker from '../_base/components/variable/var-reference-picker'
import useConfig from './use-config' import useConfig from './use-config'
@ -19,7 +18,7 @@ import { InputVarType, type NodePanelProps } from '@/app/components/workflow/typ
import BeforeRunForm from '@/app/components/workflow/nodes/_base/components/before-run-form' import BeforeRunForm from '@/app/components/workflow/nodes/_base/components/before-run-form'
import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form' import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form'
import ResultPanel from '@/app/components/workflow/run/result-panel' import ResultPanel from '@/app/components/workflow/run/result-panel'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor' import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor'
import Switch from '@/app/components/base/switch' import Switch from '@/app/components/base/switch'
const i18nPrefix = 'workflow.nodes.llm' const i18nPrefix = 'workflow.nodes.llm'
@ -206,11 +205,10 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
<div className='flex justify-between items-center h-8 pl-3 pr-2 rounded-lg bg-gray-100'> <div className='flex justify-between items-center h-8 pl-3 pr-2 rounded-lg bg-gray-100'>
<div className='flex items-center space-x-1'> <div className='flex items-center space-x-1'>
<div className='text-xs font-semibold text-gray-700 uppercase'>{t('workflow.nodes.common.memories.title')}</div> <div className='text-xs font-semibold text-gray-700 uppercase'>{t('workflow.nodes.common.memories.title')}</div>
<TooltipPlus <Tooltip
popupContent={t('workflow.nodes.common.memories.tip')} popupContent={t('workflow.nodes.common.memories.tip')}
> triggerClassName='w-4 h-4'
<RiQuestionLine className='w-3.5 h-3.5 text-gray-400' /> />
</TooltipPlus>
</div> </div>
<div className='flex items-center h-[18px] px-1 rounded-[5px] border border-black/8 text-xs font-semibold text-gray-500 uppercase'>{t('workflow.nodes.common.memories.builtIn')}</div> <div className='flex items-center h-[18px] px-1 rounded-[5px] border border-black/8 text-xs font-semibold text-gray-500 uppercase'>{t('workflow.nodes.common.memories.builtIn')}</div>
</div> </div>
@ -219,13 +217,12 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
<Editor <Editor
title={<div className='flex items-center space-x-1'> title={<div className='flex items-center space-x-1'>
<div className='text-xs font-semibold text-gray-700 uppercase'>user</div> <div className='text-xs font-semibold text-gray-700 uppercase'>user</div>
<TooltipPlus <Tooltip
popupContent={ popupContent={
<div className='max-w-[180px]'>{t('workflow.nodes.llm.roleDescription.user')}</div> <div className='max-w-[180px]'>{t('workflow.nodes.llm.roleDescription.user')}</div>
} }
> triggerClassName='w-4 h-4'
<RiQuestionLine className='w-3.5 h-3.5 text-gray-400' /> />
</TooltipPlus>
</div>} </div>}
value={inputs.memory.query_prompt_template || '{{#sys.query#}}'} value={inputs.memory.query_prompt_template || '{{#sys.query#}}'}
onChange={handleSyeQueryChange} onChange={handleSyeQueryChange}

View File

@ -1,9 +1,6 @@
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import {
RiQuestionLine,
} from '@remixicon/react'
import MemoryConfig from '../_base/components/memory-config' import MemoryConfig from '../_base/components/memory-config'
import VarReferencePicker from '../_base/components/variable/var-reference-picker' import VarReferencePicker from '../_base/components/variable/var-reference-picker'
import Editor from '../_base/components/prompt/editor' import Editor from '../_base/components/prompt/editor'
@ -19,7 +16,7 @@ import Split from '@/app/components/workflow/nodes/_base/components/split'
import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal' import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/components/output-vars' import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/components/output-vars'
import { InputVarType, type NodePanelProps } from '@/app/components/workflow/types' import { InputVarType, type NodePanelProps } from '@/app/components/workflow/types'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import BeforeRunForm from '@/app/components/workflow/nodes/_base/components/before-run-form' import BeforeRunForm from '@/app/components/workflow/nodes/_base/components/before-run-form'
import { VarType } from '@/app/components/workflow/types' import { VarType } from '@/app/components/workflow/types'
@ -126,12 +123,14 @@ const Panel: FC<NodePanelProps<ParameterExtractorNodeType>> = ({
title={ title={
<div className='flex items-center space-x-1'> <div className='flex items-center space-x-1'>
<span className='uppercase'>{t(`${i18nPrefix}.instruction`)}</span> <span className='uppercase'>{t(`${i18nPrefix}.instruction`)}</span>
<TooltipPlus popupContent={ <Tooltip
<div className='w-[120px]'> popupContent={
{t(`${i18nPrefix}.instructionTip`)} <div className='w-[120px]'>
</div>}> {t(`${i18nPrefix}.instructionTip`)}
<RiQuestionLine className='w-3.5 h-3.5 ml-0.5 text-gray-400' /> </div>
</TooltipPlus> }
triggerClassName='w-3.5 h-3.5 ml-0.5'
/>
</div> </div>
} }
value={inputs.instruction} value={inputs.instruction}

View File

@ -2,13 +2,10 @@
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import {
RiQuestionLine,
} from '@remixicon/react'
import MemoryConfig from '../../_base/components/memory-config' import MemoryConfig from '../../_base/components/memory-config'
import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor' import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor'
import type { Memory, Node, NodeOutPutVar } from '@/app/components/workflow/types' import type { Memory, Node, NodeOutPutVar } from '@/app/components/workflow/types'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
const i18nPrefix = 'workflow.nodes.questionClassifiers' const i18nPrefix = 'workflow.nodes.questionClassifiers'
type Props = { type Props = {
@ -50,12 +47,14 @@ const AdvancedSetting: FC<Props> = ({
title={ title={
<div className='flex items-center space-x-1'> <div className='flex items-center space-x-1'>
<span className='uppercase'>{t(`${i18nPrefix}.instruction`)}</span> <span className='uppercase'>{t(`${i18nPrefix}.instruction`)}</span>
<TooltipPlus popupContent={ <Tooltip
<div className='w-[120px]'> popupContent={
{t(`${i18nPrefix}.instructionTip`)} <div className='w-[120px]'>
</div>}> {t(`${i18nPrefix}.instructionTip`)}
<RiQuestionLine className='w-3.5 h-3.5 ml-0.5 text-gray-400' /> </div>
</TooltipPlus> }
triggerClassName='w-3.5 h-3.5 ml-0.5'
/>
</div> </div>
} }
value={instruction} value={instruction}

View File

@ -13,7 +13,7 @@ import {
import { useStore } from '../store' import { useStore } from '../store'
import { useCommand } from './hooks' import { useCommand } from './hooks'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
type CommandProps = { type CommandProps = {
type: 'bold' | 'italic' | 'strikethrough' | 'link' | 'bullet' type: 'bold' | 'italic' | 'strikethrough' | 'link' | 'bullet'
@ -60,7 +60,9 @@ const Command = ({
}, [type, t]) }, [type, t])
return ( return (
<TooltipPlus popupContent={tip}> <Tooltip
popupContent={tip}
>
<div <div
className={cn( className={cn(
'flex items-center justify-center w-8 h-8 cursor-pointer rounded-md text-gray-500 hover:text-gray-800 hover:bg-black/5', 'flex items-center justify-center w-8 h-8 cursor-pointer rounded-md text-gray-500 hover:text-gray-800 hover:bg-black/5',
@ -74,7 +76,7 @@ const Command = ({
> >
{icon} {icon}
</div> </div>
</TooltipPlus> </Tooltip>
) )
} }

View File

@ -1,6 +1,6 @@
import { memo } from 'react' import { memo } from 'react'
import ShortcutsName from '../shortcuts-name' import ShortcutsName from '../shortcuts-name'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
type TipPopupProps = { type TipPopupProps = {
title: string title: string
@ -13,9 +13,8 @@ const TipPopup = ({
shortcuts, shortcuts,
}: TipPopupProps) => { }: TipPopupProps) => {
return ( return (
<TooltipPlus <Tooltip
offset={4} offset={4}
hideArrow
popupClassName='!p-0 !bg-gray-25' popupClassName='!p-0 !bg-gray-25'
popupContent={ popupContent={
<div className='flex items-center gap-1 px-2 h-6 text-xs font-medium text-gray-700 rounded-lg border-[0.5px] border-black/5'> <div className='flex items-center gap-1 px-2 h-6 text-xs font-medium text-gray-700 rounded-lg border-[0.5px] border-black/5'>
@ -27,7 +26,7 @@ const TipPopup = ({
} }
> >
{children} {children}
</TooltipPlus> </Tooltip>
) )
} }

View File

@ -18,7 +18,7 @@ import ChatWrapper from './chat-wrapper'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { RefreshCcw01 } from '@/app/components/base/icons/src/vender/line/arrows' import { RefreshCcw01 } from '@/app/components/base/icons/src/vender/line/arrows'
import { BubbleX } from '@/app/components/base/icons/src/vender/line/others' import { BubbleX } from '@/app/components/base/icons/src/vender/line/others'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import ActionButton, { ActionButtonState } from '@/app/components/base/action-button' import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
import { useStore } from '@/app/components/workflow/store' import { useStore } from '@/app/components/workflow/store'
@ -63,31 +63,31 @@ const DebugAndPreview = () => {
<div className='shrink-0 flex items-center justify-between px-4 pt-3 pb-2 text-text-primary system-xl-semibold'> <div className='shrink-0 flex items-center justify-between px-4 pt-3 pb-2 text-text-primary system-xl-semibold'>
<div className='h-8'>{t('workflow.common.debugAndPreview').toLocaleUpperCase()}</div> <div className='h-8'>{t('workflow.common.debugAndPreview').toLocaleUpperCase()}</div>
<div className='flex items-center gap-1'> <div className='flex items-center gap-1'>
<TooltipPlus <Tooltip
popupContent={t('common.operation.refresh')} popupContent={t('common.operation.refresh')}
> >
<ActionButton onClick={() => handleRestartChat()}> <ActionButton onClick={() => handleRestartChat()}>
<RefreshCcw01 className='w-4 h-4' /> <RefreshCcw01 className='w-4 h-4' />
</ActionButton> </ActionButton>
</TooltipPlus> </Tooltip>
{varList.length > 0 && ( {varList.length > 0 && (
<TooltipPlus <Tooltip
popupContent={t('workflow.chatVariable.panelTitle')} popupContent={t('workflow.chatVariable.panelTitle')}
> >
<ActionButton onClick={() => setShowConversationVariableModal(true)}> <ActionButton onClick={() => setShowConversationVariableModal(true)}>
<BubbleX className='w-4 h-4' /> <BubbleX className='w-4 h-4' />
</ActionButton> </ActionButton>
</TooltipPlus> </Tooltip>
)} )}
{variables.length > 0 && ( {variables.length > 0 && (
<div className='relative'> <div className='relative'>
<TooltipPlus <Tooltip
popupContent={t('workflow.panel.userInputField')} popupContent={t('workflow.panel.userInputField')}
> >
<ActionButton state={expanded ? ActionButtonState.Active : undefined} onClick={() => setExpanded(!expanded)}> <ActionButton state={expanded ? ActionButtonState.Active : undefined} onClick={() => setExpanded(!expanded)}>
<RiEqualizer2Line className='w-4 h-4' /> <RiEqualizer2Line className='w-4 h-4' />
</ActionButton> </ActionButton>
</TooltipPlus> </Tooltip>
{expanded && <div className='absolute z-10 bottom-[-17px] right-[5px] w-3 h-3 bg-components-panel-on-panel-item-bg border-l-[0.5px] border-t-[0.5px] border-components-panel-border-subtle rotate-45'/>} {expanded && <div className='absolute z-10 bottom-[-17px] right-[5px] w-3 h-3 bg-components-panel-on-panel-item-bg border-l-[0.5px] border-t-[0.5px] border-components-panel-border-subtle rotate-45'/>}
</div> </div>
)} )}

View File

@ -1,10 +1,10 @@
import React, { useEffect } from 'react' import React, { useEffect } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { v4 as uuid4 } from 'uuid' import { v4 as uuid4 } from 'uuid'
import { RiCloseLine, RiQuestionLine } from '@remixicon/react' import { RiCloseLine } from '@remixicon/react'
import { useContext } from 'use-context-selector' import { useContext } from 'use-context-selector'
import Button from '@/app/components/base/button' import Button from '@/app/components/base/button'
import TooltipPlus from '@/app/components/base/tooltip-plus' import Tooltip from '@/app/components/base/tooltip'
import { ToastContext } from '@/app/components/base/toast' import { ToastContext } from '@/app/components/base/toast'
import { useStore } from '@/app/components/workflow/store' import { useStore } from '@/app/components/workflow/store'
import type { EnvironmentVariable } from '@/app/components/workflow/types' import type { EnvironmentVariable } from '@/app/components/workflow/types'
@ -102,13 +102,14 @@ const VariableModal = ({
type === 'secret' && 'text-text-primary font-medium border-[1.5px] shadow-xs bg-components-option-card-option-selected-bg border-components-option-card-option-selected-border hover:border-components-option-card-option-selected-border', type === 'secret' && 'text-text-primary font-medium border-[1.5px] shadow-xs bg-components-option-card-option-selected-bg border-components-option-card-option-selected-border hover:border-components-option-card-option-selected-border',
)} onClick={() => setType('secret')}> )} onClick={() => setType('secret')}>
<span>Secret</span> <span>Secret</span>
<TooltipPlus popupContent={ <Tooltip
<div className='w-[240px]'> popupContent={
{t('workflow.env.modal.secretTip')} <div className='w-[240px]'>
</div> {t('workflow.env.modal.secretTip')}
}> </div>
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-text-quaternary' /> }
</TooltipPlus> triggerClassName='ml-0.5 w-3.5 h-3.5'
/>
</div> </div>
</div> </div>
</div> </div>

View File

@ -6,8 +6,7 @@ import useSWR from 'swr'
import { useRouter } from 'next/navigation' import { useRouter } from 'next/navigation'
// import { useContext } from 'use-context-selector' // import { useContext } from 'use-context-selector'
import Button from '@/app/components/base/button' import Button from '@/app/components/base/button'
import Tooltip from '@/app/components/base/tooltip/index' import Tooltip from '@/app/components/base/tooltip'
import { SimpleSelect } from '@/app/components/base/select' import { SimpleSelect } from '@/app/components/base/select'
import { timezones } from '@/utils/timezone' import { timezones } from '@/utils/timezone'
import { LanguagesSupported, languages } from '@/i18n/language' import { LanguagesSupported, languages } from '@/i18n/language'
@ -88,9 +87,7 @@ const OneMoreStep = () => {
<label className="my-2 flex items-center justify-between text-sm font-medium text-gray-900"> <label className="my-2 flex items-center justify-between text-sm font-medium text-gray-900">
{t('login.invitationCode')} {t('login.invitationCode')}
<Tooltip <Tooltip
clickable popupContent={
selector='dont-have'
htmlContent={
<div className='w-[256px] text-xs font-medium'> <div className='w-[256px] text-xs font-medium'>
<div className='font-medium'>{t('login.sendUsMail')}</div> <div className='font-medium'>{t('login.sendUsMail')}</div>
<div className='text-xs font-medium cursor-pointer text-primary-600'> <div className='text-xs font-medium cursor-pointer text-primary-600'>
@ -98,6 +95,7 @@ const OneMoreStep = () => {
</div> </div>
</div> </div>
} }
needsDelay
> >
<span className='cursor-pointer text-primary-600'>{t('login.donthave')}</span> <span className='cursor-pointer text-primary-600'>{t('login.donthave')}</span>
</Tooltip> </Tooltip>