Explorar el Código

feat: tooltip (#7634)

tags/0.7.2
Yi Xiao hace 1 año
padre
commit
3be756eaed
No account linked to committer's email address
Se han modificado 93 ficheros con 640 adiciones y 758 borrados
  1. 3
    4
      web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/config-popup.tsx
  2. 3
    4
      web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/toggle-fold-btn.tsx
  3. 3
    6
      web/app/(commonLayout)/datasets/DatasetCard.tsx
  4. 12
    8
      web/app/components/app-sidebar/basic.tsx
  5. 6
    7
      web/app/components/app/configuration/config-prompt/advanced-prompt-input.tsx
  6. 6
    9
      web/app/components/app/configuration/config-prompt/simple-prompt-input.tsx
  7. 7
    6
      web/app/components/app/configuration/config-var/index.tsx
  8. 7
    8
      web/app/components/app/configuration/config-vision/index.tsx
  9. 9
    10
      web/app/components/app/configuration/config-vision/param-config-content.tsx
  10. 9
    10
      web/app/components/app/configuration/config-voice/param-config-content.tsx
  11. 1
    4
      web/app/components/app/configuration/config/agent/agent-setting/item-panel.tsx
  12. 17
    15
      web/app/components/app/configuration/config/agent/agent-tools/index.tsx
  13. 2
    3
      web/app/components/app/configuration/dataset-config/card-item/index.tsx
  14. 6
    10
      web/app/components/app/configuration/dataset-config/context-var/index.tsx
  15. 23
    17
      web/app/components/app/configuration/dataset-config/params-config/config-content.tsx
  16. 3
    3
      web/app/components/app/configuration/debug/debug-with-multiple-model/model-parameter-trigger.tsx
  17. 8
    9
      web/app/components/app/configuration/features/chat-group/suggested-questions-after-answer/index.tsx
  18. 2
    1
      web/app/components/app/configuration/prompt-value-panel/index.tsx
  19. 9
    7
      web/app/components/app/configuration/toolbox/annotation/annotation-ctrl-btn/index.tsx
  20. 3
    8
      web/app/components/app/configuration/toolbox/annotation/config-param.tsx
  21. 10
    7
      web/app/components/app/configuration/tools/index.tsx
  22. 9
    13
      web/app/components/app/create-app-modal/index.tsx
  23. 9
    13
      web/app/components/app/log/list.tsx
  24. 3
    5
      web/app/components/app/overview/appCard.tsx
  25. 1
    2
      web/app/components/app/overview/embedded/index.tsx
  26. 9
    3
      web/app/components/app/overview/settings/index.tsx
  27. 7
    7
      web/app/components/base/audio-btn/index.tsx
  28. 13
    7
      web/app/components/base/chat/chat/answer/operation.tsx
  29. 3
    3
      web/app/components/base/chat/chat/chat-input.tsx
  30. 1
    3
      web/app/components/base/chat/embedded-chatbot/header.tsx
  31. 1
    3
      web/app/components/base/chat/embedded-chatbot/index.tsx
  32. 2
    6
      web/app/components/base/copy-btn/index.tsx
  33. 7
    10
      web/app/components/base/copy-feedback/index.tsx
  34. 3
    3
      web/app/components/base/copy-icon/index.tsx
  35. 2
    7
      web/app/components/base/features/feature-panel/suggested-questions-after-answer/index.tsx
  36. 10
    10
      web/app/components/base/features/feature-panel/text-to-speech/param-config-content.tsx
  37. 3
    3
      web/app/components/base/image-uploader/image-list.tsx
  38. 4
    8
      web/app/components/base/param-item/index.tsx
  39. 3
    3
      web/app/components/base/prompt-editor/plugins/workflow-variable-block/component.tsx
  40. 2
    3
      web/app/components/base/qrcode/index.tsx
  41. 0
    109
      web/app/components/base/tooltip-plus/index.tsx
  42. 98
    38
      web/app/components/base/tooltip/index.tsx
  43. 7
    16
      web/app/components/billing/pricing/plan-item.tsx
  44. 3
    3
      web/app/components/billing/priority-label/index.tsx
  45. 7
    6
      web/app/components/billing/usage-info/index.tsx
  46. 9
    11
      web/app/components/datasets/common/retrieval-param-config/index.tsx
  47. 9
    7
      web/app/components/datasets/create/embedding-process/index.tsx
  48. 8
    10
      web/app/components/datasets/create/step-two/index.tsx
  49. 7
    9
      web/app/components/datasets/create/website/firecrawl/base/field.tsx
  50. 3
    1
      web/app/components/datasets/documents/detail/metadata/index.tsx
  51. 15
    13
      web/app/components/datasets/documents/list.tsx
  52. 3
    5
      web/app/components/datasets/hit-testing/textarea.tsx
  53. 14
    17
      web/app/components/develop/secret-key/input-copy.tsx
  54. 2
    3
      web/app/components/develop/secret-key/secret-key-modal.tsx
  55. 4
    4
      web/app/components/header/account-setting/members-page/invited-modal/index.tsx
  56. 2
    6
      web/app/components/header/account-setting/members-page/invited-modal/invitation-link.tsx
  57. 2
    4
      web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx
  58. 5
    8
      web/app/components/header/account-setting/model-provider-page/model-parameter-modal/parameter-item.tsx
  59. 3
    3
      web/app/components/header/account-setting/model-provider-page/model-parameter-modal/trigger.tsx
  60. 3
    3
      web/app/components/header/account-setting/model-provider-page/model-selector/deprecated-model-trigger.tsx
  61. 14
    12
      web/app/components/header/account-setting/model-provider-page/model-selector/feature-icon.tsx
  62. 3
    3
      web/app/components/header/account-setting/model-provider-page/model-selector/model-trigger.tsx
  63. 1
    2
      web/app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx
  64. 3
    3
      web/app/components/header/account-setting/model-provider-page/provider-added-card/cooldown-timer.tsx
  65. 8
    3
      web/app/components/header/account-setting/model-provider-page/provider-added-card/model-list-item.tsx
  66. 8
    7
      web/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-configs.tsx
  67. 1
    2
      web/app/components/header/account-setting/model-provider-page/provider-added-card/priority-use-tip.tsx
  68. 4
    6
      web/app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.tsx
  69. 33
    33
      web/app/components/header/account-setting/model-provider-page/system-model-selector/index.tsx
  70. 6
    8
      web/app/components/share/text-generation/result/header.tsx
  71. 3
    4
      web/app/components/tools/add-tool-modal/tools.tsx
  72. 4
    9
      web/app/components/tools/edit-custom-collection-modal/config-credentials.tsx
  73. 2
    8
      web/app/components/tools/workflow-tool/index.tsx
  74. 2
    4
      web/app/components/workflow/block-selector/blocks.tsx
  75. 3
    5
      web/app/components/workflow/block-selector/tools.tsx
  76. 3
    3
      web/app/components/workflow/header/view-history.tsx
  77. 6
    8
      web/app/components/workflow/nodes/_base/components/field.tsx
  78. 4
    2
      web/app/components/workflow/nodes/_base/components/help-link.tsx
  79. 3
    3
      web/app/components/workflow/nodes/_base/components/input-support-select-var.tsx
  80. 4
    3
      web/app/components/workflow/nodes/_base/components/node-control.tsx
  81. 10
    9
      web/app/components/workflow/nodes/_base/components/option-card.tsx
  82. 6
    7
      web/app/components/workflow/nodes/_base/components/prompt/editor.tsx
  83. 4
    3
      web/app/components/workflow/nodes/_base/panel.tsx
  84. 3
    3
      web/app/components/workflow/nodes/iteration/add-block.tsx
  85. 4
    6
      web/app/components/workflow/nodes/llm/components/config-prompt-item.tsx
  86. 7
    10
      web/app/components/workflow/nodes/llm/panel.tsx
  87. 9
    10
      web/app/components/workflow/nodes/parameter-extractor/panel.tsx
  88. 9
    10
      web/app/components/workflow/nodes/question-classifier/components/advanced-setting.tsx
  89. 5
    3
      web/app/components/workflow/note-node/note-editor/toolbar/command.tsx
  90. 3
    4
      web/app/components/workflow/operator/tip-popup.tsx
  91. 7
    7
      web/app/components/workflow/panel/debug-and-preview/index.tsx
  92. 10
    9
      web/app/components/workflow/panel/env-panel/variable-modal.tsx
  93. 3
    5
      web/app/signin/oneMoreStep.tsx

+ 3
- 4
web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/config-popup.tsx Ver fichero

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'


<> <>
{providerAllNotConfigured {providerAllNotConfigured
? ( ? (
<TooltipPlus
<Tooltip
popupContent={t(`${I18N_PREFIX}.disabledTip`)} popupContent={t(`${I18N_PREFIX}.disabledTip`)}
> >
{switchContent} {switchContent}

</TooltipPlus>
</Tooltip>
) )
: switchContent} : switchContent}
</> </>

+ 3
- 4
web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/toggle-fold-btn.tsx Ver fichero

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'


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'>
<ChevronDoubleDownIcon className='w-4 h-4 transform rotate-180' /> <ChevronDoubleDownIcon className='w-4 h-4 transform rotate-180' />
</div> </div>
)} )}
</TooltipPlus>
</Tooltip>
</div> </div>
) )
} }

+ 3
- 6
web/app/(commonLayout)/datasets/DatasetCard.tsx Ver fichero

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 {
RiMoreFill,
} from '@remixicon/react'
import { 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'
<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}`}
htmlContent={t('dataset.unavailableTip')}
popupContent={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>

+ 12
- 8
web/app/components/app-sidebar/basic.tsx Ver fichero

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'
<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)}`}>
<InformationCircleIcon className='w-4 h-4 ml-1 text-gray-400' />
</Tooltip>}
&& <Tooltip
popupContent={
<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>}

+ 6
- 7
web/app/components/app/configuration/config-prompt/advanced-prompt-input.tsx Ver fichero

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'
<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]'>
{t('appDebug.promptTip')}
</div>}
selector='config-prompt-tooltip'>
<RiQuestionLine className='w-[14px] h-[14px] text-indigo-400' />
</Tooltip>
popupContent={
<div className='w-[180px]'>
{t('appDebug.promptTip')}
</div>
}
/>
</div>)} </div>)}
<div className={cn(s.optionWrap, 'items-center space-x-1')}> <div className={cn(s.optionWrap, 'items-center space-x-1')}>
{canDelete && ( {canDelete && (

+ 6
- 9
web/app/components/app/configuration/config-prompt/simple-prompt-input.tsx Ver fichero

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'
<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]'>
{t('appDebug.promptTip')}
</div>}
selector='config-prompt-tooltip'>
<RiQuestionLine className='w-[14px] h-[14px] text-indigo-400' />
</Tooltip>
popupContent={
<div className='w-[180px]'>
{t('appDebug.promptTip')}
</div>
}
/>
)} )}
</div> </div>
<div className='flex items-center'> <div className='flex items-center'>

+ 7
- 6
web/app/components/app/configuration/config-var/index.tsx Ver fichero

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'
<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]'>
{t('appDebug.variableTip')}
</div>} selector='config-var-tooltip'>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' />
</Tooltip>
<Tooltip
popupContent={
<div className='w-[180px]'>
{t('appDebug.variableTip')}
</div>
}
/>
)} )}
</div> </div>
} }

+ 7
- 8
web/app/components/app/configuration/config-vision/index.tsx Ver fichero

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'
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]' >
{t('appDebug.vision.description')}
</div>} selector='config-vision-tooltip'>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' />
</Tooltip>
<Tooltip
popupContent={
<div className='w-[180px]' >
{t('appDebug.vision.description')}
</div>
}
/>
</div> </div>
} }
headerRight={ headerRight={

+ 9
- 10
web/app/components/app/configuration/config-vision/param-config-content.tsx Ver fichero

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'
<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]' >
{t('appDebug.vision.visionSettings.resolutionTooltip').split('\n').map(item => (
<div key={item}>{item}</div>
))}
</div>} selector='config-resolution-tooltip'>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' />
</Tooltip>
<Tooltip
popupContent={
<div className='w-[180px]' >
{t('appDebug.vision.visionSettings.resolutionTooltip').split('\n').map(item => (
<div key={item}>{item}</div>
))}
</div>
}
/>
</div> </div>
<RadioGroup <RadioGroup
className='space-x-3' className='space-x-3'

+ 9
- 10
web/app/components/app/configuration/config-voice/param-config-content.tsx Ver fichero

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'
<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]'>
{t('appDebug.voice.voiceSettings.resolutionTooltip').split('\n').map(item => (
<div key={item}>{item}</div>
))}
</div>} selector='config-resolution-tooltip'>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' />
</Tooltip>
<Tooltip
popupContent={
<div className='w-[180px]'>
{t('appDebug.voice.voiceSettings.resolutionTooltip').split('\n').map(item => (
<div key={item}>{item}</div>
))}
</div>
}
/>
</div> </div>
<Listbox <Listbox
value={languageItem} value={languageItem}

+ 1
- 4
web/app/components/app/configuration/config/agent/agent-setting/item-panel.tsx Ver fichero

'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 = {
{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>

+ 17
- 15
web/app/components/app/configuration/config/agent/agent-tools/index.tsx Ver fichero

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'
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'


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]'>
{t('appDebug.agent.tools.description')}
</div>} selector='config-tools-tooltip'>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' />
</Tooltip>
<Tooltip
popupContent={
<div className='w-[180px]'>
{t('appDebug.agent.tools.description')}
</div>
}
/>
</div> </div>
} }
headerRight={ headerRight={
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)
}}> }}>
<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) => {
) )
: ( : (
<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) => {

+ 2
- 3
web/app/components/app/configuration/dataset-config/card-item/index.tsx Ver fichero

<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}`}
htmlContent={t('dataset.unavailableTip')}
popupContent={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>

+ 6
- 10
web/app/components/app/configuration/dataset-config/context-var/index.tsx Ver fichero

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'
</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]'>
{t('appDebug.feature.dataSet.queryVariable.tip')}
</div>}
selector='context-var-tooltip'
>
<RiQuestionLine className='w-3.5 h-3.5 text-gray-400' />
</Tooltip>
popupContent={
<div className='w-[180px]'>
{t('appDebug.feature.dataSet.queryVariable.tip')}
</div>
}
/>
</div> </div>


<VarPicker {...props} /> <VarPicker {...props} />

+ 23
- 17
web/app/components/app/configuration/dataset-config/params-config/config-content.tsx Ver fichero

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'
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,
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')}
)} )}
> >
<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')}
onClick={() => handleRerankModeChange(option.value)} onClick={() => handleRerankModeChange(option.value)}
> >
<div className='truncate'>{option.label}</div> <div className='truncate'>{option.label}</div>
<TooltipPlus
popupContent={<div className='w-[200px]'>{option.tips}</div>}
hideArrow
>
<RiQuestionLine className='ml-0.5 w-3.5 h-4.5 text-text-quaternary' />
</TooltipPlus>
<Tooltip
popupContent={
<div className='w-[200px]'>
{option.tips}
</div>
}
popupClassName='ml-0.5'
triggerClassName='ml-0.5 w-3.5 h-3.5'
/>
</div> </div>
)) ))
} }
) )
} }
<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>}>
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-gray-400' />
</TooltipPlus>
<Tooltip
popupContent={
<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
<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}

+ 3
- 3
web/app/components/app/configuration/debug/debug-with-multiple-model/model-parameter-trigger.tsx Ver fichero

} 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'


<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>

+ 8
- 9
web/app/components/app/configuration/features/chat-group/suggested-questions-after-answer/index.tsx Ver fichero

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'
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]'>
{t('appDebug.feature.suggestedQuestionsAfterAnswer.description')}
</div>} selector='suggestion-question-tooltip'>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' />
</Tooltip>
<Tooltip
popupContent={
<div className='w-[180px]'>
{t('appDebug.feature.suggestedQuestionsAfterAnswer.description')}
</div>
}
/>
</div> </div>
} }
headerIcon={<SuggestedQuestionsAfterAnswerIcon />} headerIcon={<SuggestedQuestionsAfterAnswerIcon />}

+ 2
- 1
web/app/components/app/configuration/prompt-value-panel/index.tsx Ver fichero

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'


{canNotRun {canNotRun
? (<Tooltip ? (<Tooltip
popupContent={t('appDebug.otherError.promptNoBeEmpty')} popupContent={t('appDebug.otherError.promptNoBeEmpty')}
needsDelay
> >
{renderRunButton()} {renderRunButton()}
</Tooltip>) </Tooltip>)

+ 9
- 7
web/app/components/app/configuration/toolbox/annotation/annotation-ctrl-btn/index.tsx Ver fichero

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'
) )
: answer : answer
? ( ? (
<TooltipPlus
popupContent={t('appDebug.feature.annotation.add') as string}
<Tooltip
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'
> >
<MessageFastPlus className='w-4 h-4' /> <MessageFastPlus className='w-4 h-4' />
</div> </div>
</TooltipPlus>
</Tooltip>
) )
: null : null
} }
<TooltipPlus
popupContent={t('appDebug.feature.annotation.edit') as string}
<Tooltip
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'
> >
<Edit04 className='w-4 h-4' /> <Edit04 className='w-4 h-4' />
</div> </div>
</TooltipPlus>
</Tooltip>


</div> </div>
<RemoveAnnotationConfirmModal <RemoveAnnotationConfirmModal

+ 3
- 8
web/app/components/app/configuration/toolbox/annotation/config-param.tsx Ver fichero

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'
<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>

+ 10
- 7
web/app/components/app/configuration/tools/index.tsx Ver fichero

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,
<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>}>
<RiQuestionLine className='w-3.5 h-3.5 text-gray-400' />
</TooltipPlus>
<Tooltip
popupContent={
<div className='max-w-[160px]'>
{t('appDebug.feature.tools.tips')}
</div>
}
/>
</div> </div>
{ {
!expanded && !!externalDataToolsConfig.length && ( !expanded && !!externalDataToolsConfig.length && (
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
> >
{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'

+ 9
- 13
web/app/components/app/create-app-modal/index.tsx Ver fichero

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'


<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
hideArrow
<Tooltip
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>
} }
<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>
<TooltipPlus
hideArrow
</Tooltip>
<Tooltip
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>
<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>
<TooltipPlus
hideArrow
</Tooltip>
<Tooltip
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>
} }
<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>
<TooltipPlus
hideArrow
</Tooltip>
<Tooltip
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>
<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 && (

+ 9
- 13
web/app/components/app/log/list.tsx Ver fichero

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'
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'
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'
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)
<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
hideArrow
popupContent={detail.id}>
<Tooltip
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>
)} )}
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'>
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'}
selector={`highlight-${randomString(16)}`}
popupClassName={(isHighlight && !isChatMode) ? '' : '!hidden'}
> >
<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 || '-'}

+ 3
- 5
web/app/components/app/overview/appCard.tsx Ver fichero

)} )}
{isApp && isCurrentWorkspaceManager && ( {isApp && isCurrentWorkspaceManager && (
<Tooltip <Tooltip
content={t('appOverview.overview.appInfo.regenerate') || ''}
selector={`code-generate-${randomString(8)}`}
popupContent={t('appOverview.overview.appInfo.regenerate') || ''}
> >
<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"
disabled={disabled} disabled={disabled}
> >
<Tooltip <Tooltip
content={
popupContent={
t('appOverview.overview.appInfo.preUseReminder') ?? '' t('appOverview.overview.appInfo.preUseReminder') ?? ''
} }
selector={`op-btn-${randomString(16)}`}
className={disabled ? 'mt-[-8px]' : '!hidden'}
popupClassName={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]" />

+ 1
- 2
web/app/components/app/overview/embedded/index.tsx Ver fichero

</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'}
content={(isCopied[option] ? t(`${prefixEmbedded}.copied`) : t(`${prefixEmbedded}.copy`)) || ''}
popupContent={(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>

+ 9
- 3
web/app/components/app/overview/settings/index.tsx Ver fichero

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'
<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>}

+ 7
- 7
web/app/components/base/audio-btn/index.tsx Ver fichero

}[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}
content={tooltipContent}
className='z-10'
popupContent={tooltipContent}
> >
<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>

+ 13
- 7
web/app/components/base/chat/chat/answer/operation.tsx Ver fichero

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 = {
{ {
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>
<TooltipPlus popupContent={t('appDebug.operation.disagree')}>
</Tooltip>
<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
) )
} }
</div> </div>
</TooltipPlus>
</Tooltip>
) )
} }
</div> </div>

+ 3
- 3
web/app/components/base/chat/chat/chat-input.tsx Ver fichero

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'
{isMobile {isMobile
? sendBtn ? sendBtn
: ( : (
<TooltipPlus
<Tooltip
popupContent={ popupContent={
<div> <div>
<div>{t('common.operation.send')} Enter</div> <div>{t('common.operation.send')} Enter</div>
} }
> >
{sendBtn} {sendBtn}
</TooltipPlus>
</Tooltip>
)} )}
</div> </div>
{ {

+ 1
- 3
web/app/components/base/chat/embedded-chatbot/header.tsx Ver fichero

</div> </div>
</div> </div>
<Tooltip <Tooltip
selector={'embed-scene-restart-button'}
htmlContent={t('share.chat.resetChat')}
position='top'
popupContent={t('share.chat.resetChat')}
> >
<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?.()

+ 1
- 3
web/app/components/base/chat/embedded-chatbot/index.tsx Ver fichero

{!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'}
htmlContent={t('share.chat.resetChat')}
position='top'
popupContent={t('share.chat.resetChat')}
> >
<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"/>

+ 2
- 6
web/app/components/base/copy-btn/index.tsx Ver fichero

'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
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}
content={(isCopied ? t('appApi.copied') : t('appApi.copy')) as string}
className='z-10'
popupContent={(isCopied ? t('appApi.copied') : t('appApi.copy'))}
> >
<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'}

+ 7
- 10
web/app/components/base/copy-feedback/index.tsx Ver fichero

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)




return ( return (
<Tooltip <Tooltip
selector={`common-copy-feedback-${selectorId}`}
content={
popupContent={
(isCopied (isCopied
? t(`${prefixEmbedded}.copied`) ? t(`${prefixEmbedded}.copied`)
: t(`${prefixEmbedded}.copy`)) || '' : t(`${prefixEmbedded}.copy`)) || ''
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 : ''
}`} }`}
}, 100) }, 100)


return ( return (
<TooltipPlus
<Tooltip
popupContent={ popupContent={
(isCopied (isCopied
? t(`${prefixEmbedded}.copied`) ? t(`${prefixEmbedded}.copied`)
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>
) )
} }

+ 3
- 3
web/app/components/base/copy-icon/index.tsx Ver fichero

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,
}, 100) }, 100)


return ( return (
<TooltipPlus
<Tooltip
popupContent={ popupContent={
(isCopied (isCopied
? t(`${prefixEmbedded}.copied`) ? t(`${prefixEmbedded}.copied`)
) )
} }
</div> </div>
</TooltipPlus>
</Tooltip>
) )
} }



+ 2
- 7
web/app/components/base/features/feature-panel/suggested-questions-after-answer/index.tsx Ver fichero

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()
</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')}>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' />
</TooltipPlus>
<Tooltip popupContent={t('appDebug.feature.suggestedQuestionsAfterAnswer.description')}/>
</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>

+ 10
- 10
web/app/components/base/features/feature-panel/text-to-speech/param-config-content.tsx Ver fichero

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'
<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]'>
{t('appDebug.voice.voiceSettings.resolutionTooltip').split('\n').map(item => (
<div key={item}>{item}</div>
))}
</div>} selector='config-resolution-tooltip'>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400'/>
</Tooltip>
<Tooltip
popupContent={
<div className='w-[180px]'>
{t('appDebug.voice.voiceSettings.resolutionTooltip').split('\n').map(item => (
<div key={item}>{item}
</div>
))}
</div>
}
/>
</div> </div>
<Listbox <Listbox
value={languageItem} value={languageItem}

+ 3
- 3
web/app/components/base/image-uploader/image-list.tsx Ver fichero

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'
<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>
)} )}

+ 4
- 8
web/app/components/base/param-item/index.tsx Ver fichero

'use client' 'use client'
import type { FC } from 'react' import type { FC } from 'react'
import {
RiQuestionLine,
} from '@remixicon/react'

import Tooltip from '@/app/components/base/tooltip-plus'
import Tooltip from '@/app/components/base/tooltip'
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'


)} )}
<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>}>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' />
</Tooltip>
<Tooltip
popupContent={<div className="w-[200px]">{tip}</div>}
/>
)} )}


</div> </div>

+ 3
- 3
web/app/components/base/prompt-editor/plugins/workflow-variable-block/component.tsx Ver fichero

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


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>
) )
} }



+ 2
- 3
web/app/components/base/qrcode/index.tsx Ver fichero

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


return ( return (
<Tooltip <Tooltip
selector={`common-qrcode-show-${selectorId}`}
content={t(`${prefixEmbedded}`) || ''}
popupContent={t(`${prefixEmbedded}`) || ''}
> >
<div <div
className={`w-8 h-8 cursor-pointer rounded-lg ${className ?? ''}`} className={`w-8 h-8 cursor-pointer rounded-lg ${className ?? ''}`}

+ 0
- 109
web/app/components/base/tooltip-plus/index.tsx Ver fichero

'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)

+ 98
- 38
web/app/components/base/tooltip/index.tsx Ver fichero

'use client' 'use client'
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react'
import { Tooltip as ReactTooltip } from 'react-tooltip' // fixed version to 5.8.3 https://github.com/ReactTooltip/react-tooltip/issues/972
import classNames from '@/utils/classnames'
import 'react-tooltip/dist/react-tooltip.css'

type TooltipProps = {
selector: string
content?: string
import React, { useEffect, useRef, useState } from 'react'
import { useBoolean } from 'ahooks'
import type { OffsetOptions, Placement } from '@floating-ui/react'
import { RiQuestionLine } from '@remixicon/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'
triggerClassName?: string
disabled?: boolean disabled?: boolean
htmlContent?: React.ReactNode
className?: string // This should use !impornant to override the default styles eg: '!bg-white'
position?: 'top' | 'right' | 'bottom' | 'left'
clickable?: boolean
children: React.ReactNode
noArrow?: boolean
popupContent?: React.ReactNode
children?: React.ReactNode
popupClassName?: string
offset?: OffsetOptions
needsDelay?: 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,
className,
clickable,
noArrow,
popupClassName,
offset,
asChild = true,
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'>
{React.cloneElement(children as React.ReactElement, {
'data-tooltip-id': selector,
})
}
<ReactTooltip
id={selector}
content={content}
className={classNames('!z-[999] !bg-white !text-xs !font-normal !text-gray-700 !shadow-lg !opacity-100', className)}
place={position}
clickable={clickable}
isOpen={disabled ? false : undefined}
noArrow={noArrow}
<PortalToFollowElem
open={disabled ? false : open}
onOpenChange={setOpen}
placement={position}
offset={offset ?? 8}
>
<PortalToFollowElemTrigger
onClick={() => triggerMethod === 'click' && setOpen(v => !v)}
onMouseEnter={() => {
if (triggerMethod === 'hover') {
setHoverTrigger()
setOpen(true)
}
}}
onMouseLeave={() => triggerMethod === 'hover' && handleLeave(true)}
asChild={asChild}
>
{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>}
</PortalToFollowElemTrigger>
<PortalToFollowElemContent
className="z-[9999]"
> >
{htmlContent && htmlContent}
</ReactTooltip>
</div>
{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)

+ 7
- 16
web/app/components/billing/pricing/plan-item.tsx Ver fichero

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'
<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>
<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>

+ 3
- 3
web/app/components/billing/priority-label/index.tsx Ver fichero

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()
}, [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>
{ {
} }
{t(`billing.plansCommon.priority.${priority}`)} {t(`billing.plansCommon.priority.${priority}`)}
</span> </span>
</TooltipPlus>
</Tooltip>
) )
} }



+ 7
- 6
web/app/components/billing/usage-info/index.tsx Ver fichero

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'
<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}
</div>} selector='config-var-tooltip'>
<InfoCircle className='w-[14px] h-[14px] text-gray-400' />
</Tooltip>
<Tooltip
popupContent={
<div className='w-[180px]'>
{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'>

+ 9
- 11
web/app/components/datasets/common/retrieval-param-config/index.tsx Ver fichero

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'
)} )}
<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>}>
<RiQuestionLine className='w-[14px] h-[14px] text-gray-400' />
</Tooltip>
<Tooltip
popupContent={
<div className="w-[200px]">{t('common.modelProvider.rerankModel.tip')}</div>
}
/>
</div> </div>
</div> </div>
<ModelSelector <ModelSelector
<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
>
<RiQuestionLine className='ml-0.5 w-3.5 h-4.5 text-text-quaternary' />
</Tooltip>
triggerClassName='ml-0.5 w-3.5 h-4.5'
/>
</div> </div>
)) ))
} }

+ 9
- 7
web/app/components/datasets/create/embedding-process/index.tsx Ver fichero

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 = {
<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={(
<div className='max-w-[400px]'>
{indexingStatusDetail.error}
</div>
)}>
<Tooltip
popupContent={(
<div className='max-w-[400px]'>
{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')}>

+ 8
- 10
web/app/components/datasets/create/step-two/index.tsx Ver fichero

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'
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'
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>
<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={
<div className='max-w-[200px]'>
{t('datasetCreation.stepTwo.overlapTip')}
</div>
}>
<RiQuestionLine className='ml-1 w-3.5 h-3.5 text-gray-400' />
</TooltipPlus>
<Tooltip
popupContent={
<div className='max-w-[200px]'>
{t('datasetCreation.stepTwo.overlapTip')}
</div>
}
/>
</div> </div>
<input <input
type="number" type="number"

+ 7
- 9
web/app/components/datasets/create/website/firecrawl/base/field.tsx Ver fichero

'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
<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={
<div className='w-[200px]'>{tooltip}</div>
}>
<RiQuestionLine className='relative top-[3px] w-3 h-3 ml-1 text-gray-500' />
</TooltipPlus>
<Tooltip
popupContent={
<div className='w-[200px]'>{tooltip}</div>
}
popupClassName='relative top-[3px] w-3 h-3 ml-1'
/>
)} )}
</div> </div>
<Input <Input

+ 3
- 1
web/app/components/datasets/documents/detail/metadata/index.tsx Ver fichero

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 || ''}

+ 15
- 13
web/app/components/datasets/documents/list.tsx Ver fichero

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'
{ {
errorMessage && ( errorMessage && (
<Tooltip <Tooltip
selector='dataset-document-detail-item-status'
htmlContent={
popupContent={
<div className='max-w-[260px] break-all'>{errorMessage}</div> <div className='max-w-[260px] break-all'>{errorMessage}</div>
} }
>
<RiQuestionLine className='ml-1 w-[14px] h-[14px] text-gray-700' />
</Tooltip>
triggerClassName='ml-1 w-4 h-4'
/>
) )
} }
</div> </div>
{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>
{!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}`}
content={t('datasetDocuments.list.action.enableWarning') as string}
className='!font-semibold'
popupContent={t('datasetDocuments.list.action.enableWarning')}
popupClassName='!font-semibold'
needsDelay
disabled={!archived} disabled={!archived}
> >
<div> <div>
} }
</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) => {
> >
<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>



+ 3
- 5
web/app/components/datasets/hit-testing/textarea.tsx Ver fichero

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'
{t('datasetHitTesting.input.title')} {t('datasetHitTesting.input.title')}
</span> </span>
<Tooltip <Tooltip
selector={'change-retrieval-method'}
htmlContent={t('dataset.retrieval.changeRetrievalMethod')}
popupContent={t('dataset.retrieval.changeRetrievalMethod')}
> >
<div <div
onClick={onClickRetrievalMethod} onClick={onClickRetrievalMethod}
{text?.length > 200 {text?.length > 200
? ( ? (
<Tooltip <Tooltip
content={t('datasetHitTesting.input.countWarning') as string}
selector="hit-testing-warning"
popupContent={t('datasetHitTesting.input.countWarning')}
> >
<div> <div>
<Tag color="red" className="!text-red-600"> <Tag color="red" className="!text-red-600">

+ 14
- 17
web/app/components/develop/secret-key/input-copy.tsx Ver fichero

'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 = {
}: 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(() => {
<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
selector={selector.current}
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={() => {
copy(value)
setIsCopied(true)
}}>{value}</div>
</Tooltip>
<div className='absolute top-0 left-0 w-full pl-2 pr-2 truncate cursor-pointer r-0' onClick={() => {
copy(value)
setIsCopied(true)
}}>
<Tooltip
popupContent={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
position='bottom'
>
{value}
</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}
content={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
className='z-10'
popupContent={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
position='bottom'
> >
<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={() => {

+ 2
- 3
web/app/components/develop/secret-key/secret-key-modal.tsx Ver fichero

<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}`}
content={copyValue === api.token ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
className='z-10'
popupContent={copyValue === api.token ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
popupClassName='mr-1'
> >
<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)

+ 4
- 4
web/app/components/header/account-setting/members-page/invited-modal/index.tsx Ver fichero

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'
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}`}
htmlContent={item.message}
popupContent={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>,

+ 2
- 6
web/app/components/header/account-setting/members-page/invited-modal/invitation-link.tsx Ver fichero

<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}
content={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
className='z-10'
popupContent={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
> >
<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}
content={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
className='z-10'
popupContent={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
> >
<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}>

+ 2
- 4
web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx Ver fichero

import { Fragment, useState } from 'react' import { Fragment, useState } from 'react'
import type { FC } from 'react' import type { FC } from 'react'
import {
RiQuestionLine,
} from '@remixicon/react'
import { RiQuestionLine } from '@remixicon/react'
import { ValidatingTip } from '../../key-validator/ValidateStatus' import { ValidatingTip } from '../../key-validator/ValidateStatus'
import type { import type {
CredentialFormSchema, CredentialFormSchema,
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

+ 5
- 8
web/app/components/header/account-setting/model-provider-page/model-parameter-modal/parameter-item.tsx Ver fichero

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'
{ {
parameterRule.help && ( parameterRule.help && (
<Tooltip <Tooltip
selector={`model-parameter-rule-${parameterRule.name}`}
htmlContent={(
popupContent={(
<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>
)} )}
>
<RiQuestionLine className='mr-1.5 w-3.5 h-3.5 text-gray-400' />
</Tooltip>
popupClassName='mr-1'
triggerClassName='mr-1 w-4 h-4 shrink-0'
/>
) )
} }
{ {
!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'

+ 3
- 3
web/app/components/header/account-setting/model-provider-page/model-parameter-modal/trigger.tsx Ver fichero

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
{ {
disabled disabled
? ( ? (
<TooltipPlus
<Tooltip
popupContent={ popupContent={
hasDeprecated hasDeprecated
? t('common.modelProvider.deprecated') ? t('common.modelProvider.deprecated')
} }
> >
<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')} />

+ 3
- 3
web/app/components/header/account-setting/model-provider-page/model-selector/deprecated-model-trigger.tsx Ver fichero

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
{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>
) )

+ 14
- 12
web/app/components/header/account-setting/model-provider-page/model-selector/feature-icon.tsx Ver fichero

// 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


// 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}`}>
<MagicEyes className='w-3 h-3' />
</ModelBadge>
</TooltipPlus>
<div className='inline-block cursor-help'>
<ModelBadge className={`mr-0.5 !px-0 w-[18px] justify-center text-gray-500 ${className}`}>
<MagicEyes className='w-3 h-3' />
</ModelBadge>
</div>
</Tooltip>
) )
} }



+ 3
- 3
web/app/components/header/account-setting/model-provider-page/model-selector/model-trigger.tsx Ver fichero

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
{ {
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

+ 1
- 2
web/app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx Ver fichero

{ {
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

+ 3
- 3
web/app/components/header/account-setting/model-provider-page/provider-added-card/cooldown-timer.tsx Ver fichero

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


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
} }

+ 8
- 3
web/app/components/header/account-setting/model-provider-page/provider-added-card/model-list-item.tsx Ver fichero

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'
{ {
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

+ 8
- 7
web/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-configs.tsx Ver fichero

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'
<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]'>
<RiQuestionLine className='w-3 h-3 text-gray-400' />
</TooltipPlus>
<Tooltip
popupContent={t('common.modelProvider.loadBalancingInfo')}
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>
<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'>

+ 1
- 2
web/app/components/header/account-setting/model-provider-page/provider-added-card/priority-use-tip.tsx Ver fichero



return ( return (
<Tooltip <Tooltip
selector='provider-quota-credential-priority-using'
content={t('common.modelProvider.priorityUsing') || ''}
popupContent={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' />

+ 4
- 6
web/app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.tsx Ver fichero

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 TooltipPlus from '@/app/components/base/tooltip-plus'
import Tooltip from '@/app/components/base/tooltip'
import { formatNumber } from '@/utils/format' import { formatNumber } from '@/utils/format'


type QuotaPanelProps = { type 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 && (

+ 33
- 33
web/app/components/header/account-setting/model-provider-page/system-model-selector/index.tsx Ver fichero

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,
<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'
htmlContent={
<div className='w-[261px] text-gray-500'>{t('common.modelProvider.systemReasoningModel.tip')}</div>
popupContent={
<div className='w-[261px] text-gray-500'>
{t('common.modelProvider.systemReasoningModel.tip')}
</div>
} }
>
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-gray-400' />
</Tooltip>
triggerClassName='ml-0.5'
/>
</div> </div>
<div> <div>
<ModelSelector <ModelSelector
<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'
htmlContent={
<div className='w-[261px] text-gray-500'>{t('common.modelProvider.embeddingModel.tip')}</div>
popupContent={
<div className='w-[261px] text-gray-500'>
{t('common.modelProvider.embeddingModel.tip')}
</div>
} }
>
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-gray-400' />
</Tooltip>
needsDelay={false}
triggerClassName='ml-0.5'
/>
</div> </div>
<div> <div>
<ModelSelector <ModelSelector
<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'
htmlContent={
<div className='w-[261px] text-gray-500'>{t('common.modelProvider.rerankModel.tip')}</div>
popupContent={
<div className='w-[261px] text-gray-500'>
{t('common.modelProvider.rerankModel.tip')}
</div>
} }
>
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-gray-400' />
</Tooltip>
needsDelay={false}
triggerClassName='ml-0.5'
/>
</div> </div>
<div> <div>
<ModelSelector <ModelSelector
<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'
htmlContent={
<div className='w-[261px] text-gray-500'>{t('common.modelProvider.speechToTextModel.tip')}</div>
popupContent={
<div className='w-[261px] text-gray-500'>
{t('common.modelProvider.speechToTextModel.tip')}
</div>
} }
>
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-gray-400' />
</Tooltip>
needsDelay={false}
triggerClassName='ml-0.5'
/>
</div> </div>
<div> <div>
<ModelSelector <ModelSelector
<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'
htmlContent={
<div className='w-[261px] text-gray-500'>{t('common.modelProvider.ttsModel.tip')}</div>
popupContent={
<div className='w-[261px] text-gray-500'>
{t('common.modelProvider.ttsModel.tip')}
</div>
} }
>
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-gray-400' />
</Tooltip>
triggerClassName='ml-0.5'
/>
</div> </div>
<div> <div>
<ModelSelector <ModelSelector

+ 6
- 8
web/app/components/share/text-generation/result/header.tsx Ver fichero



{showFeedback && feedback.rating && feedback.rating === 'like' && ( {showFeedback && feedback.rating && feedback.rating === 'like' && (
<Tooltip <Tooltip
selector="undo-feedback-like"
content="Undo Great Rating"
popupContent="Undo Great Rating"
> >
<div <div
onClick={() => { onClick={() => {


{showFeedback && feedback.rating && feedback.rating === 'dislike' && ( {showFeedback && feedback.rating && feedback.rating === 'dislike' && (
<Tooltip <Tooltip
selector="undo-feedback-dislike"
content="Undo Undesirable Response"
popupContent="Undo Undesirable Response"
> >
<div <div
onClick={() => { onClick={() => {
{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"
content="Great Rating"
popupContent="Great Rating"
needsDelay={false}
> >
<div <div
onClick={() => { onClick={() => {
</div> </div>
</Tooltip> </Tooltip>
<Tooltip <Tooltip
selector="feedback-dislike"
content="Undesirable Response"
popupContent="Undesirable Response"
needsDelay={false}
> >
<div <div
onClick={() => { onClick={() => {

+ 3
- 4
web/app/components/tools/add-tool-modal/tools.tsx Ver fichero

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]'
htmlContent={(
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]'
popupContent={(
<div> <div>
<BlockIcon <BlockIcon
size='md' size='md'
)} )}
</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

+ 4
- 9
web/app/components/tools/edit-custom-collection-modal/config-credentials.tsx Ver fichero

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 Tooltip from '../../base/tooltip'
import Tooltip from '@/app/components/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'
<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'
htmlContent={
popupContent={
<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>
} }
>
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-gray-400' />
</Tooltip>
triggerClassName='ml-0.5'
/>
</div> </div>
<input <input
value={tempCredential.api_key_header} value={tempCredential.api_key_header}

+ 2
- 8
web/app/components/tools/workflow-tool/index.tsx Ver fichero

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'
<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'

+ 2
- 4
web/app/components/workflow/block-selector/blocks.tsx Ver fichero

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'
htmlContent={(
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'
popupContent={(
<div> <div>
<BlockIcon <BlockIcon
size='md' size='md'
<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}

+ 3
- 5
web/app/components/workflow/block-selector/tools.tsx Ver fichero

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'
htmlContent={(
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'
popupContent={(
<div> <div>
<BlockIcon <BlockIcon
size='md' size='md'
<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'
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>
)) ))

+ 3
- 3
web/app/components/workflow/header/view-history.tsx Ver fichero

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,
} }
{ {
!withText && ( !withText && (
<TooltipPlus
<Tooltip
popupContent={t('workflow.common.viewRunHistory')} popupContent={t('workflow.common.viewRunHistory')}
> >
<div <div
> >
<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>

+ 6
- 8
web/app/components/workflow/nodes/_base/components/field.tsx Ver fichero

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
<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={
<div className='w-[120px]'>
{tooltip}
</div>}>
<RiQuestionLine className='w-3.5 h-3.5 ml-0.5 text-text-quaternary' />
</TooltipPlus>
<Tooltip
popupContent={tooltip}
popupClassName='ml-1'
triggerClassName='w-4 h-4 ml-1'
/>
)} )}


</div> </div>

+ 4
- 2
web/app/components/workflow/nodes/_base/components/help-link.tsx Ver fichero

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 = {
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'

+ 3
- 3
web/app/components/workflow/nodes/_base/components/input-support-select-var.tsx Ver fichero

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
{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>
)} )}
</> </>

+ 4
- 3
web/app/components/workflow/nodes/_base/components/node-control.tsx Ver fichero

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> = ({
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>

+ 10
- 9
web/app/components/workflow/nodes/_base/components/option-card.tsx Ver fichero

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: {
onClick={handleSelect} onClick={handleSelect}
> >
<span>{title}</span> <span>{title}</span>
{tooltip && <TooltipPlus
popupContent={<div className='w-[240px]'>
{tooltip}
</div>}
>
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-text-quaternary' />
</TooltipPlus>}
{tooltip
&& <Tooltip
popupContent={
<div className='w-[240px]'>
{tooltip}
</div>
}
/>
}
</div> </div>
) )
} }

+ 6
- 7
web/app/components/workflow/nodes/_base/components/prompt/editor.tsx Ver fichero

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'
{/* 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' />
}} }}
/> />
</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}>

+ 4
- 3
web/app/components/workflow/nodes/_base/panel.tsx Ver fichero

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'
<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'
> >
<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} />

+ 3
- 3
web/app/components/workflow/nodes/iteration/add-block.tsx Ver fichero

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


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 && (

+ 4
- 6
web/app/components/workflow/nodes/llm/components/config-prompt-item.tsx Ver fichero

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'
/> />
)} )}


<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>
} }
>
<RiQuestionLine className='w-3.5 h-3.5 text-gray-400' />
</TooltipPlus>
triggerClassName='w-4 h-4'
/>
</div> </div>
} }
value={payload.edition_type === EditionType.jinja2 ? (payload.jinja2_text || '') : payload.text} value={payload.edition_type === EditionType.jinja2 ? (payload.jinja2_text || '') : payload.text}

+ 7
- 10
web/app/components/workflow/nodes/llm/panel.tsx Ver fichero

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'
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'
<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')}
>
<RiQuestionLine className='w-3.5 h-3.5 text-gray-400' />
</TooltipPlus>
triggerClassName='w-4 h-4'
/>
</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>
<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>
} }
>
<RiQuestionLine className='w-3.5 h-3.5 text-gray-400' />
</TooltipPlus>
triggerClassName='w-4 h-4'
/>
</div>} </div>}
value={inputs.memory.query_prompt_template || '{{#sys.query#}}'} value={inputs.memory.query_prompt_template || '{{#sys.query#}}'}
onChange={handleSyeQueryChange} onChange={handleSyeQueryChange}

+ 9
- 10
web/app/components/workflow/nodes/parameter-extractor/panel.tsx Ver fichero

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'
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'


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={
<div className='w-[120px]'>
{t(`${i18nPrefix}.instructionTip`)}
</div>}>
<RiQuestionLine className='w-3.5 h-3.5 ml-0.5 text-gray-400' />
</TooltipPlus>
<Tooltip
popupContent={
<div className='w-[120px]'>
{t(`${i18nPrefix}.instructionTip`)}
</div>
}
triggerClassName='w-3.5 h-3.5 ml-0.5'
/>
</div> </div>
} }
value={inputs.instruction} value={inputs.instruction}

+ 9
- 10
web/app/components/workflow/nodes/question-classifier/components/advanced-setting.tsx Ver fichero

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 = {
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={
<div className='w-[120px]'>
{t(`${i18nPrefix}.instructionTip`)}
</div>}>
<RiQuestionLine className='w-3.5 h-3.5 ml-0.5 text-gray-400' />
</TooltipPlus>
<Tooltip
popupContent={
<div className='w-[120px]'>
{t(`${i18nPrefix}.instructionTip`)}
</div>
}
triggerClassName='w-3.5 h-3.5 ml-0.5'
/>
</div> </div>
} }
value={instruction} value={instruction}

+ 5
- 3
web/app/components/workflow/note-node/note-editor/toolbar/command.tsx Ver fichero

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'
}, [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',
> >
{icon} {icon}
</div> </div>
</TooltipPlus>
</Tooltip>
) )
} }



+ 3
- 4
web/app/components/workflow/operator/tip-popup.tsx Ver fichero

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
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'>
} }
> >
{children} {children}
</TooltipPlus>
</Tooltip>
) )
} }



+ 7
- 7
web/app/components/workflow/panel/debug-and-preview/index.tsx Ver fichero

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'


<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>
)} )}

+ 10
- 9
web/app/components/workflow/panel/env-panel/variable-modal.tsx Ver fichero

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'
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={
<div className='w-[240px]'>
{t('workflow.env.modal.secretTip')}
</div>
}>
<RiQuestionLine className='ml-0.5 w-[14px] h-[14px] text-text-quaternary' />
</TooltipPlus>
<Tooltip
popupContent={
<div className='w-[240px]'>
{t('workflow.env.modal.secretTip')}
</div>
}
triggerClassName='ml-0.5 w-3.5 h-3.5'
/>
</div> </div>
</div> </div>
</div> </div>

+ 3
- 5
web/app/signin/oneMoreStep.tsx Ver fichero

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'
<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
selector='dont-have'
htmlContent={
popupContent={
<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'>
</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>

Cargando…
Cancelar
Guardar