chore(web): new lint setup (#30020)

Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
This commit is contained in:
Stephen Zhou
2025-12-23 16:58:55 +08:00
committed by GitHub
parent 9701a2994b
commit f2842da397
3356 changed files with 85046 additions and 81278 deletions

View File

@ -1,17 +1,17 @@
'use client'
import type { FC } from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import {
RiEditLine,
RiFileEditLine,
} from '@remixicon/react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import ActionButton from '@/app/components/base/action-button'
import Tooltip from '@/app/components/base/tooltip'
import { addAnnotation } from '@/service/annotation'
import Toast from '@/app/components/base/toast'
import { useProviderContext } from '@/context/provider-context'
import Tooltip from '@/app/components/base/tooltip'
import { useModalContext } from '@/context/modal-context'
import { useProviderContext } from '@/context/provider-context'
import { addAnnotation } from '@/service/annotation'
type Props = {
appId: string
@ -60,7 +60,7 @@ const AnnotationCtrlButton: FC<Props> = ({
popupContent={t('appDebug.feature.annotation.edit')}
>
<ActionButton onClick={onEdit}>
<RiEditLine className='h-4 w-4' />
<RiEditLine className="h-4 w-4" />
</ActionButton>
</Tooltip>
)}
@ -69,7 +69,7 @@ const AnnotationCtrlButton: FC<Props> = ({
popupContent={t('appDebug.feature.annotation.add')}
>
<ActionButton onClick={handleAdd}>
<RiFileEditLine className='h-4 w-4' />
<RiFileEditLine className="h-4 w-4" />
</ActionButton>
</Tooltip>
)}

View File

@ -1,17 +1,17 @@
'use client'
import type { FC } from 'react'
import type { AnnotationReplyConfig } from '@/models/debug'
import React, { useState } from 'react'
import { useTranslation } from 'react-i18next'
import ScoreSlider from './score-slider'
import { Item } from './config-param'
import Modal from '@/app/components/base/modal'
import Button from '@/app/components/base/button'
import Modal from '@/app/components/base/modal'
import Toast from '@/app/components/base/toast'
import type { AnnotationReplyConfig } from '@/models/debug'
import { ANNOTATION_DEFAULT } from '@/config'
import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
import { ANNOTATION_DEFAULT } from '@/config'
import { Item } from './config-param'
import ScoreSlider from './score-slider'
type Props = {
appId: string
@ -43,15 +43,15 @@ const ConfigParamModal: FC<Props> = ({
const [isLoading, setLoading] = useState(false)
const [embeddingModel, setEmbeddingModel] = useState(oldAnnotationConfig.embedding_model
? {
providerName: oldAnnotationConfig.embedding_model.embedding_provider_name,
modelName: oldAnnotationConfig.embedding_model.embedding_model_name,
}
: (embeddingsDefaultModel
? {
providerName: embeddingsDefaultModel.provider.provider,
modelName: embeddingsDefaultModel.model,
providerName: oldAnnotationConfig.embedding_model.embedding_provider_name,
modelName: oldAnnotationConfig.embedding_model.embedding_model_name,
}
: undefined))
: (embeddingsDefaultModel
? {
providerName: embeddingsDefaultModel.provider.provider,
modelName: embeddingsDefaultModel.model,
}
: undefined))
const onHide = () => {
if (!isLoading)
doHide()
@ -77,19 +77,19 @@ const ConfigParamModal: FC<Props> = ({
<Modal
isShow={isShow}
onClose={onHide}
className='!mt-14 !w-[640px] !max-w-none !p-6'
className="!mt-14 !w-[640px] !max-w-none !p-6"
>
<div className='title-2xl-semi-bold mb-2 text-text-primary'>
<div className="title-2xl-semi-bold mb-2 text-text-primary">
{t(`appAnnotation.initSetup.${isInit ? 'title' : 'configTitle'}`)}
</div>
<div className='mt-6 space-y-3'>
<div className="mt-6 space-y-3">
<Item
title={t('appDebug.feature.annotation.scoreThreshold.title')}
tooltip={t('appDebug.feature.annotation.scoreThreshold.description')}
>
<ScoreSlider
className='mt-1'
className="mt-1"
value={(annotationConfig.score_threshold || ANNOTATION_DEFAULT.score_threshold) * 100}
onChange={(val) => {
setAnnotationConfig({
@ -104,7 +104,7 @@ const ConfigParamModal: FC<Props> = ({
title={t('common.modelProvider.embeddingModel.key')}
tooltip={t('appAnnotation.embeddingModelSwitchTip')}
>
<div className='pt-1'>
<div className="pt-1">
<ModelSelector
defaultModel={embeddingModel && {
provider: embeddingModel.providerName,
@ -122,18 +122,18 @@ const ConfigParamModal: FC<Props> = ({
</Item>
</div>
<div className='mt-6 flex justify-end gap-2'>
<div className="mt-6 flex justify-end gap-2">
<Button onClick={onHide}>{t('common.operation.cancel')}</Button>
<Button
variant='primary'
variant="primary"
onClick={handleSave}
loading={isLoading}
>
<div></div>
<div>{t(`appAnnotation.initSetup.${isInit ? 'confirmBtn' : 'configConfirmBtn'}`)}</div>
</Button >
</div >
</Modal >
</Button>
</div>
</Modal>
)
}
export default React.memo(ConfigParamModal)

View File

@ -3,18 +3,18 @@ import type { FC } from 'react'
import React from 'react'
import Tooltip from '@/app/components/base/tooltip'
export const Item: FC<{ title: string; tooltip: string; children: React.JSX.Element }> = ({
export const Item: FC<{ title: string, tooltip: string, children: React.JSX.Element }> = ({
title,
tooltip,
children,
}) => {
return (
<div>
<div className='mb-1 flex items-center space-x-1'>
<div className='system-sm-semibold py-1 text-text-secondary'>{title}</div>
<div className="mb-1 flex items-center space-x-1">
<div className="system-sm-semibold py-1 text-text-secondary">{title}</div>
<Tooltip
popupContent={
<div className='system-sm-regular max-w-[200px] text-text-secondary'>{tooltip}</div>
<div className="system-sm-regular max-w-[200px] text-text-secondary">{tooltip}</div>
}
/>
</div>

View File

@ -1,18 +1,18 @@
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import type { AnnotationReplyConfig } from '@/models/debug'
import { RiEqualizer2Line, RiExternalLinkLine } from '@remixicon/react'
import { produce } from 'immer'
import { usePathname, useRouter } from 'next/navigation'
import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { usePathname, useRouter } from 'next/navigation'
import { produce } from 'immer'
import { RiEqualizer2Line, RiExternalLinkLine } from '@remixicon/react'
import { MessageFast } from '@/app/components/base/icons/src/vender/features'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import Button from '@/app/components/base/button'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import useAnnotationConfig from '@/app/components/base/features/new-feature-panel/annotation-reply/use-annotation-config'
import ConfigParamModal from '@/app/components/base/features/new-feature-panel/annotation-reply/config-param-modal'
import useAnnotationConfig from '@/app/components/base/features/new-feature-panel/annotation-reply/use-annotation-config'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import { MessageFast } from '@/app/components/base/icons/src/vender/features'
import AnnotationFullModal from '@/app/components/billing/annotation-full/modal'
import { ANNOTATION_DEFAULT } from '@/config'
import type { AnnotationReplyConfig } from '@/models/debug'
type Props = {
disabled?: boolean
@ -77,11 +77,11 @@ const AnnotationReply = ({
return (
<>
<FeatureCard
icon={
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs'>
<MessageFast className='h-4 w-4 text-text-primary-on-surface' />
icon={(
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs">
<MessageFast className="h-4 w-4 text-text-primary-on-surface" />
</div>
}
)}
title={t('appDebug.feature.annotation.title')}
value={!!annotationReply?.enabled}
onChange={state => handleSwitch(state)}
@ -91,33 +91,36 @@ const AnnotationReply = ({
>
<>
{!annotationReply?.enabled && (
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.annotation.description')}</div>
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{t('appDebug.feature.annotation.description')}</div>
)}
{!!annotationReply?.enabled && (
<>
{!isHovering && (
<div className='flex items-center gap-4 pt-0.5'>
<div className=''>
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.annotation.scoreThreshold.title')}</div>
<div className='system-xs-regular text-text-secondary'>{annotationReply.score_threshold || '-'}</div>
<div className="flex items-center gap-4 pt-0.5">
<div className="">
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.feature.annotation.scoreThreshold.title')}</div>
<div className="system-xs-regular text-text-secondary">{annotationReply.score_threshold || '-'}</div>
</div>
<div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
<div className=''>
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('common.modelProvider.embeddingModel.key')}</div>
<div className='system-xs-regular text-text-secondary'>{annotationReply.embedding_model?.embedding_model_name}</div>
<div className="h-[27px] w-px rotate-12 bg-divider-subtle"></div>
<div className="">
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('common.modelProvider.embeddingModel.key')}</div>
<div className="system-xs-regular text-text-secondary">{annotationReply.embedding_model?.embedding_model_name}</div>
</div>
</div>
)}
{isHovering && (
<div className='flex items-center justify-between'>
<Button className='w-[178px]' onClick={() => setIsShowAnnotationConfigInit(true)} disabled={disabled}>
<RiEqualizer2Line className='mr-1 h-4 w-4' />
<div className="flex items-center justify-between">
<Button className="w-[178px]" onClick={() => setIsShowAnnotationConfigInit(true)} disabled={disabled}>
<RiEqualizer2Line className="mr-1 h-4 w-4" />
{t('common.operation.params')}
</Button>
<Button className='w-[178px]' onClick={() => {
router.push(`/app/${appId}/annotations`)
}}>
<RiExternalLinkLine className='mr-1 h-4 w-4' />
<Button
className="w-[178px]"
onClick={() => {
router.push(`/app/${appId}/annotations`)
}}
>
<RiExternalLinkLine className="mr-1 h-4 w-4" />
{t('appDebug.feature.annotation.cacheManagement')}
</Button>
</div>

View File

@ -1,6 +1,6 @@
import ReactSlider from 'react-slider'
import s from './style.module.css'
import { cn } from '@/utils/classnames'
import s from './style.module.css'
type ISliderProps = {
className?: string
@ -13,26 +13,28 @@ type ISliderProps = {
}
const Slider: React.FC<ISliderProps> = ({ className, max, min, step, value, disabled, onChange }) => {
return <ReactSlider
disabled={disabled}
value={isNaN(value) ? 0 : value}
min={min || 0}
max={max || 100}
step={step || 1}
className={cn(className, s.slider)}
thumbClassName={cn(s['slider-thumb'], 'top-[-7px] h-[18px] w-2 cursor-pointer rounded-[36px] border !border-black/8 bg-white shadow-md')}
trackClassName={s['slider-track']}
onChange={onChange}
renderThumb={(props, state) => (
<div {...props}>
<div className='relative h-full w-full'>
<div className='system-sm-semibold absolute left-[50%] top-[-16px] translate-x-[-50%] text-text-primary'>
{(state.valueNow / 100).toFixed(2)}
return (
<ReactSlider
disabled={disabled}
value={isNaN(value) ? 0 : value}
min={min || 0}
max={max || 100}
step={step || 1}
className={cn(className, s.slider)}
thumbClassName={cn(s['slider-thumb'], 'top-[-7px] h-[18px] w-2 cursor-pointer rounded-[36px] border !border-black/8 bg-white shadow-md')}
trackClassName={s['slider-track']}
onChange={onChange}
renderThumb={(props, state) => (
<div {...props}>
<div className="relative h-full w-full">
<div className="system-sm-semibold absolute left-[50%] top-[-16px] translate-x-[-50%] text-text-primary">
{(state.valueNow / 100).toFixed(2)}
</div>
</div>
</div>
</div>
)}
/>
)}
/>
)
}
export default Slider

View File

@ -19,7 +19,7 @@ const ScoreSlider: FC<Props> = ({
return (
<div className={className}>
<div className='mt-[14px] h-px'>
<div className="mt-[14px] h-px">
<Slider
max={100}
min={80}
@ -28,13 +28,13 @@ const ScoreSlider: FC<Props> = ({
onChange={onChange}
/>
</div>
<div className='system-xs-semibold-uppercase mt-[10px] flex items-center justify-between'>
<div className='flex space-x-1 text-util-colors-cyan-cyan-500'>
<div className="system-xs-semibold-uppercase mt-[10px] flex items-center justify-between">
<div className="flex space-x-1 text-util-colors-cyan-cyan-500">
<div>0.8</div>
<div>·</div>
<div>{t('appDebug.feature.annotation.scoreThreshold.easyMatch')}</div>
</div>
<div className='flex space-x-1 text-util-colors-blue-blue-500'>
<div className="flex space-x-1 text-util-colors-blue-blue-500">
<div>1.0</div>
<div>·</div>
<div>{t('appDebug.feature.annotation.scoreThreshold.accurateMatch')}</div>

View File

@ -1,12 +1,12 @@
import React, { useState } from 'react'
import { produce } from 'immer'
import type { AnnotationReplyConfig } from '@/models/debug'
import { queryAnnotationJobStatus, updateAnnotationStatus } from '@/service/annotation'
import type { EmbeddingModelConfig } from '@/app/components/app/annotation/type'
import type { AnnotationReplyConfig } from '@/models/debug'
import { produce } from 'immer'
import React, { useState } from 'react'
import { AnnotationEnableStatus, JobStatus } from '@/app/components/app/annotation/type'
import { sleep } from '@/utils'
import { ANNOTATION_DEFAULT } from '@/config'
import { useProviderContext } from '@/context/provider-context'
import { queryAnnotationJobStatus, updateAnnotationStatus } from '@/service/annotation'
import { sleep } from '@/utils'
type Params = {
appId: string

View File

@ -1,11 +1,11 @@
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import { produce } from 'immer'
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { produce } from 'immer'
import { Citations } from '@/app/components/base/icons/src/vender/features'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import { FeatureEnum } from '@/app/components/base/features/types'
import { Citations } from '@/app/components/base/icons/src/vender/features'
type Props = {
disabled?: boolean
@ -39,11 +39,11 @@ const Citation = ({
return (
<FeatureCard
icon={
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-warning-warning-500 p-1 shadow-xs'>
<Citations className='h-4 w-4 text-text-primary-on-surface' />
icon={(
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-warning-warning-500 p-1 shadow-xs">
<Citations className="h-4 w-4 text-text-primary-on-surface" />
</div>
}
)}
title={t('appDebug.feature.citation.title')}
value={!!features.citation?.enabled}
description={t('appDebug.feature.citation.description')!}

View File

@ -1,16 +1,16 @@
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import type { InputVar } from '@/app/components/workflow/types'
import type { PromptVariable } from '@/models/debug'
import { RiEditLine } from '@remixicon/react'
import { produce } from 'immer'
import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { produce } from 'immer'
import { RiEditLine } from '@remixicon/react'
import { LoveMessage } from '@/app/components/base/icons/src/vender/features'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import Button from '@/app/components/base/button'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import { FeatureEnum } from '@/app/components/base/features/types'
import { LoveMessage } from '@/app/components/base/icons/src/vender/features'
import { useModalContext } from '@/context/modal-context'
import type { PromptVariable } from '@/models/debug'
import type { InputVar } from '@/app/components/workflow/types'
type Props = {
disabled?: boolean
@ -80,11 +80,11 @@ const ConversationOpener = ({
return (
<FeatureCard
icon={
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
<LoveMessage className='h-4 w-4 text-text-primary-on-surface' />
icon={(
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs">
<LoveMessage className="h-4 w-4 text-text-primary-on-surface" />
</div>
}
)}
title={t('appDebug.feature.conversationOpener.title')}
value={!!opening?.enabled}
onChange={state => handleChange(FeatureEnum.opening, state)}
@ -94,18 +94,18 @@ const ConversationOpener = ({
>
<>
{!opening?.enabled && (
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.conversationOpener.description')}</div>
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{t('appDebug.feature.conversationOpener.description')}</div>
)}
{!!opening?.enabled && (
<>
{!isHovering && (
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">
{opening.opening_statement || t('appDebug.openingStatement.placeholder')}
</div>
)}
{isHovering && (
<Button className='w-full' onClick={handleOpenOpeningModal} disabled={disabled}>
<RiEditLine className='mr-1 h-4 w-4' />
<Button className="w-full" onClick={handleOpenOpeningModal} disabled={disabled}>
<RiEditLine className="mr-1 h-4 w-4" />
{t('appDebug.openingStatement.writeOpener')}
</Button>
)}

View File

@ -1,22 +1,21 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import type { OpeningStatement } from '@/app/components/base/features/types'
import type { InputVar } from '@/app/components/workflow/types'
import type { PromptVariable } from '@/models/debug'
import { RiAddLine, RiAsterisk, RiCloseLine, RiDeleteBinLine, RiDraggable } from '@remixicon/react'
import { useBoolean } from 'ahooks'
import { produce } from 'immer'
import { noop } from 'lodash-es'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ReactSortable } from 'react-sortablejs'
import { RiAddLine, RiAsterisk, RiCloseLine, RiDeleteBinLine, RiDraggable } from '@remixicon/react'
import Modal from '@/app/components/base/modal'
import ConfirmAddVar from '@/app/components/app/configuration/config-prompt/confirm-add-var'
import { getInputKeys } from '@/app/components/base/block-input'
import Button from '@/app/components/base/button'
import Divider from '@/app/components/base/divider'
import ConfirmAddVar from '@/app/components/app/configuration/config-prompt/confirm-add-var'
import Modal from '@/app/components/base/modal'
import PromptEditor from '@/app/components/base/prompt-editor'
import type { OpeningStatement } from '@/app/components/base/features/types'
import { getInputKeys } from '@/app/components/base/block-input'
import type { PromptVariable } from '@/models/debug'
import type { InputVar } from '@/app/components/workflow/types'
import { getNewVar } from '@/utils/var'
import { cn } from '@/utils/classnames'
import { noop } from 'lodash-es'
import { checkKeys } from '@/utils/var'
import { checkKeys, getNewVar } from '@/utils/var'
type OpeningSettingModalProps = {
data: OpeningStatement
@ -104,13 +103,17 @@ const OpeningSettingModal = ({
const renderQuestions = () => {
return (
<div>
<div className='flex items-center py-2'>
<div className='flex shrink-0 space-x-0.5 text-xs font-medium leading-[18px] text-text-tertiary'>
<div className='uppercase'>{t('appDebug.openingStatement.openingQuestion')}</div>
<div className="flex items-center py-2">
<div className="flex shrink-0 space-x-0.5 text-xs font-medium leading-[18px] text-text-tertiary">
<div className="uppercase">{t('appDebug.openingStatement.openingQuestion')}</div>
<div>·</div>
<div>{tempSuggestedQuestions.length}/{MAX_QUESTION_NUM}</div>
<div>
{tempSuggestedQuestions.length}
/
{MAX_QUESTION_NUM}
</div>
</div>
<Divider bgStyle='gradient' className='ml-3 h-px w-0 grow' />
<Divider bgStyle="gradient" className="ml-3 h-px w-0 grow" />
</div>
<ReactSortable
className="space-y-1"
@ -121,7 +124,7 @@ const OpeningSettingModal = ({
}
})}
setList={list => setTempSuggestedQuestions(list.map(item => item.name))}
handle='.handle'
handle=".handle"
ghostClass="opacity-50"
animation={150}
>
@ -135,7 +138,7 @@ const OpeningSettingModal = ({
)}
key={index}
>
<RiDraggable className='handle h-4 w-4 cursor-grab text-text-quaternary' />
<RiDraggable className="handle h-4 w-4 cursor-grab text-text-quaternary" />
<input
type="input"
value={question || ''}
@ -149,30 +152,32 @@ const OpeningSettingModal = ({
return item
}))
}}
className={'h-9 w-full grow cursor-pointer overflow-x-auto rounded-lg border-0 bg-transparent pl-1.5 pr-8 text-sm leading-9 text-text-secondary focus:outline-none'}
className="h-9 w-full grow cursor-pointer overflow-x-auto rounded-lg border-0 bg-transparent pl-1.5 pr-8 text-sm leading-9 text-text-secondary focus:outline-none"
onFocus={() => setFocusID(index)}
onBlur={() => setFocusID(null)}
/>
<div
className='absolute right-1.5 top-1/2 block translate-y-[-50%] cursor-pointer rounded-md p-1 text-text-tertiary hover:bg-state-destructive-hover hover:text-text-destructive'
className="absolute right-1.5 top-1/2 block translate-y-[-50%] cursor-pointer rounded-md p-1 text-text-tertiary hover:bg-state-destructive-hover hover:text-text-destructive"
onClick={() => {
setTempSuggestedQuestions(tempSuggestedQuestions.filter((_, i) => index !== i))
}}
onMouseEnter={() => setDeletingID(index)}
onMouseLeave={() => setDeletingID(null)}
>
<RiDeleteBinLine className='h-3.5 w-3.5' />
<RiDeleteBinLine className="h-3.5 w-3.5" />
</div>
</div>
)
})}</ReactSortable>
})}
</ReactSortable>
{tempSuggestedQuestions.length < MAX_QUESTION_NUM && (
<div
onClick={() => { setTempSuggestedQuestions([...tempSuggestedQuestions, '']) }}
className='mt-1 flex h-9 cursor-pointer items-center gap-2 rounded-lg bg-components-button-tertiary-bg px-3 text-components-button-tertiary-text hover:bg-components-button-tertiary-bg-hover'>
<RiAddLine className='h-4 w-4' />
<div className='system-sm-medium text-[13px]'>{t('appDebug.variableConfig.addOption')}</div>
className="mt-1 flex h-9 cursor-pointer items-center gap-2 rounded-lg bg-components-button-tertiary-bg px-3 text-components-button-tertiary-text hover:bg-components-button-tertiary-bg-hover"
>
<RiAddLine className="h-4 w-4" />
<div className="system-sm-medium text-[13px]">{t('appDebug.variableConfig.addOption')}</div>
</div>
)}
</div>
@ -183,17 +188,17 @@ const OpeningSettingModal = ({
<Modal
isShow
onClose={noop}
className='!mt-14 !w-[640px] !max-w-none !bg-components-panel-bg-blur !p-6'
className="!mt-14 !w-[640px] !max-w-none !bg-components-panel-bg-blur !p-6"
>
<div className='mb-6 flex items-center justify-between'>
<div className='title-2xl-semi-bold text-text-primary'>{t('appDebug.feature.conversationOpener.title')}</div>
<div className='cursor-pointer p-1' onClick={onCancel}><RiCloseLine className='h-4 w-4 text-text-tertiary' /></div>
<div className="mb-6 flex items-center justify-between">
<div className="title-2xl-semi-bold text-text-primary">{t('appDebug.feature.conversationOpener.title')}</div>
<div className="cursor-pointer p-1" onClick={onCancel}><RiCloseLine className="h-4 w-4 text-text-tertiary" /></div>
</div>
<div className='mb-8 flex gap-2'>
<div className='mt-1.5 h-8 w-8 shrink-0 rounded-lg border-components-panel-border bg-util-colors-orange-dark-orange-dark-500 p-1.5'>
<RiAsterisk className='h-5 w-5 text-text-primary-on-surface' />
<div className="mb-8 flex gap-2">
<div className="mt-1.5 h-8 w-8 shrink-0 rounded-lg border-components-panel-border bg-util-colors-orange-dark-orange-dark-500 p-1.5">
<RiAsterisk className="h-5 w-5 text-text-primary-on-surface" />
</div>
<div className='grow rounded-2xl border-t border-divider-subtle bg-chat-bubble-bg p-3 shadow-xs'>
<div className="grow rounded-2xl border-t border-divider-subtle bg-chat-bubble-bg p-3 shadow-xs">
<PromptEditor
value={tempValue}
onChange={setTempValue}
@ -217,15 +222,15 @@ const OpeningSettingModal = ({
{renderQuestions()}
</div>
</div>
<div className='flex items-center justify-end'>
<div className="flex items-center justify-end">
<Button
onClick={onCancel}
className='mr-2'
className="mr-2"
>
{t('common.operation.cancel')}
</Button>
<Button
variant='primary'
variant="primary"
onClick={() => handleSave()}
disabled={isSaveDisabled}
>

View File

@ -1,6 +1,6 @@
import { Fragment, useCallback } from 'react'
import type { ReactNode } from 'react'
import { Dialog, DialogPanel, Transition, TransitionChild } from '@headlessui/react'
import { Fragment, useCallback } from 'react'
import { cn } from '@/utils/classnames'
type DialogProps = {
@ -28,7 +28,8 @@ const DialogWrapper = ({
'data-[closed]:opacity-0',
'data-[enter]:opacity-100 data-[enter]:duration-300 data-[enter]:ease-out',
'data-[leave]:opacity-0 data-[leave]:duration-200 data-[leave]:ease-in',
)} />
)}
/>
</TransitionChild>
<div className="fixed inset-0">
@ -41,14 +42,15 @@ const DialogWrapper = ({
'data-[enter]:scale-100 data-[enter]:opacity-100 data-[enter]:duration-300 data-[enter]:ease-out',
'data-[leave]:scale-95 data-[leave]:opacity-0 data-[leave]:duration-200 data-[leave]:ease-in',
className,
)}>
)}
>
{children}
</DialogPanel>
</TransitionChild>
</div>
</div>
</Dialog>
</Transition >
</Transition>
)
}

View File

@ -1,11 +1,11 @@
import { RiApps2AddLine, RiArrowRightLine, RiSparklingFill } from '@remixicon/react'
import React, { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { RiApps2AddLine, RiArrowRightLine, RiSparklingFill } from '@remixicon/react'
import { Citations, ContentModeration, FolderUpload, LoveMessage, MessageFast, Microphone01, TextToAudio, VirtualAssistant } from '@/app/components/base/icons/src/vender/features'
import Button from '@/app/components/base/button'
import Tooltip from '@/app/components/base/tooltip'
import VoiceSettings from '@/app/components/base/features/new-feature-panel/text-to-speech/voice-settings'
import { useFeatures } from '@/app/components/base/features/hooks'
import VoiceSettings from '@/app/components/base/features/new-feature-panel/text-to-speech/voice-settings'
import { Citations, ContentModeration, FolderUpload, LoveMessage, MessageFast, Microphone01, TextToAudio, VirtualAssistant } from '@/app/components/base/icons/src/vender/features'
import Tooltip from '@/app/components/base/tooltip'
import { cn } from '@/utils/classnames'
type Props = {
@ -36,23 +36,23 @@ const FeatureBar = ({
}, [features, isChatMode, showFileUpload])
return (
<div className='m-1 mt-0 -translate-y-2 rounded-b-[10px] border-b border-l border-r border-components-panel-border-subtle bg-util-colors-indigo-indigo-50 px-2.5 py-2 pt-4'>
<div className="m-1 mt-0 -translate-y-2 rounded-b-[10px] border-b border-l border-r border-components-panel-border-subtle bg-util-colors-indigo-indigo-50 px-2.5 py-2 pt-4">
{noFeatureEnabled && (
<div className='flex cursor-pointer items-end gap-1' onClick={() => onFeatureBarClick?.(true)}>
<RiApps2AddLine className='h-3.5 w-3.5 text-text-accent' />
<div className='body-xs-medium text-text-accent'>{t('appDebug.feature.bar.empty')}</div>
<RiArrowRightLine className='h-3.5 w-3.5 text-text-accent' />
<div className="flex cursor-pointer items-end gap-1" onClick={() => onFeatureBarClick?.(true)}>
<RiApps2AddLine className="h-3.5 w-3.5 text-text-accent" />
<div className="body-xs-medium text-text-accent">{t('appDebug.feature.bar.empty')}</div>
<RiArrowRightLine className="h-3.5 w-3.5 text-text-accent" />
</div>
)}
{!noFeatureEnabled && (
<div className='flex items-center gap-2'>
<div className='flex shrink-0 items-center gap-0.5'>
<div className="flex items-center gap-2">
<div className="flex shrink-0 items-center gap-0.5">
{!!features.moreLikeThis?.enabled && (
<Tooltip
popupContent={t('appDebug.feature.moreLikeThis.title')}
>
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
<RiSparklingFill className='h-3.5 w-3.5 text-text-primary-on-surface' />
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs">
<RiSparklingFill className="h-3.5 w-3.5 text-text-primary-on-surface" />
</div>
</Tooltip>
)}
@ -60,8 +60,8 @@ const FeatureBar = ({
<Tooltip
popupContent={t('appDebug.feature.conversationOpener.title')}
>
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
<LoveMessage className='h-3.5 w-3.5 text-text-primary-on-surface' />
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs">
<LoveMessage className="h-3.5 w-3.5 text-text-primary-on-surface" />
</div>
</Tooltip>
)}
@ -69,8 +69,8 @@ const FeatureBar = ({
<Tooltip
popupContent={t('appDebug.feature.moderation.title')}
>
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-text-success p-1 shadow-xs'>
<ContentModeration className='h-3.5 w-3.5 text-text-primary-on-surface' />
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-text-success p-1 shadow-xs">
<ContentModeration className="h-3.5 w-3.5 text-text-primary-on-surface" />
</div>
</Tooltip>
)}
@ -78,8 +78,8 @@ const FeatureBar = ({
<Tooltip
popupContent={t('appDebug.feature.speechToText.title')}
>
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs'>
<Microphone01 className='h-3.5 w-3.5 text-text-primary-on-surface' />
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs">
<Microphone01 className="h-3.5 w-3.5 text-text-primary-on-surface" />
</div>
</Tooltip>
)}
@ -89,7 +89,7 @@ const FeatureBar = ({
popupContent={t('appDebug.feature.textToSpeech.title')}
>
<div className={cn('shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs', !disabled && 'cursor-pointer')}>
<TextToAudio className='h-3.5 w-3.5 text-text-primary-on-surface' />
<TextToAudio className="h-3.5 w-3.5 text-text-primary-on-surface" />
</div>
</Tooltip>
</VoiceSettings>
@ -98,8 +98,8 @@ const FeatureBar = ({
<Tooltip
popupContent={t('appDebug.feature.fileUpload.title')}
>
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-blue-600 p-1 shadow-xs'>
<FolderUpload className='h-3.5 w-3.5 text-text-primary-on-surface' />
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-blue-600 p-1 shadow-xs">
<FolderUpload className="h-3.5 w-3.5 text-text-primary-on-surface" />
</div>
</Tooltip>
)}
@ -107,8 +107,8 @@ const FeatureBar = ({
<Tooltip
popupContent={t('appDebug.feature.suggestedQuestionsAfterAnswer.title')}
>
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
<VirtualAssistant className='h-3.5 w-3.5 text-text-primary-on-surface' />
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs">
<VirtualAssistant className="h-3.5 w-3.5 text-text-primary-on-surface" />
</div>
</Tooltip>
)}
@ -116,8 +116,8 @@ const FeatureBar = ({
<Tooltip
popupContent={t('appDebug.feature.citation.title')}
>
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-warning-warning-500 p-1 shadow-xs'>
<Citations className='h-4 w-4 text-text-primary-on-surface' />
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-warning-warning-500 p-1 shadow-xs">
<Citations className="h-4 w-4 text-text-primary-on-surface" />
</div>
</Tooltip>
)}
@ -125,16 +125,16 @@ const FeatureBar = ({
<Tooltip
popupContent={t('appDebug.feature.annotation.title')}
>
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs'>
<MessageFast className='h-3.5 w-3.5 text-text-primary-on-surface' />
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs">
<MessageFast className="h-3.5 w-3.5 text-text-primary-on-surface" />
</div>
</Tooltip>
)}
</div>
<div className='body-xs-regular grow text-text-tertiary'>{t('appDebug.feature.bar.enableText')}</div>
<Button className='shrink-0' variant='ghost-accent' size='small' onClick={() => onFeatureBarClick?.(true)}>
<div className='mx-1'>{t('appDebug.feature.bar.manage')}</div>
<RiArrowRightLine className='h-3.5 w-3.5 text-text-accent' />
<div className="body-xs-regular grow text-text-tertiary">{t('appDebug.feature.bar.enableText')}</div>
<Button className="shrink-0" variant="ghost-accent" size="small" onClick={() => onFeatureBarClick?.(true)}>
<div className="mx-1">{t('appDebug.feature.bar.manage')}</div>
<RiArrowRightLine className="h-3.5 w-3.5 text-text-accent" />
</Button>
</div>
)}

View File

@ -1,7 +1,7 @@
import React from 'react'
import {
RiQuestionLine,
} from '@remixicon/react'
import React from 'react'
import Switch from '@/app/components/base/switch'
import Tooltip from '@/app/components/base/tooltip'
@ -32,26 +32,26 @@ const FeatureCard = ({
}: Props) => {
return (
<div
className='mb-1 rounded-xl border-l-[0.5px] border-t-[0.5px] border-effects-highlight bg-background-section-burn p-3'
className="mb-1 rounded-xl border-l-[0.5px] border-t-[0.5px] border-effects-highlight bg-background-section-burn p-3"
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
<div className='mb-2 flex items-center gap-2'>
<div className="mb-2 flex items-center gap-2">
{icon}
<div className='system-sm-semibold flex grow items-center text-text-secondary'>
<div className="system-sm-semibold flex grow items-center text-text-secondary">
{title}
{tooltip && (
<Tooltip
popupContent={tooltip}
>
<div className='ml-0.5 p-px'><RiQuestionLine className='h-3.5 w-3.5 text-text-quaternary' /></div>
<div className="ml-0.5 p-px"><RiQuestionLine className="h-3.5 w-3.5 text-text-quaternary" /></div>
</Tooltip>
)}
</div>
<Switch disabled={disabled} className='shrink-0' onChange={state => onChange?.(state)} defaultValue={value} />
<Switch disabled={disabled} className="shrink-0" onChange={state => onChange?.(state)} defaultValue={value} />
</div>
{description && (
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{description}</div>
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{description}</div>
)}
{children}
</div>

View File

@ -1,14 +1,14 @@
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import { RiEqualizer2Line } from '@remixicon/react'
import { produce } from 'immer'
import React, { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { produce } from 'immer'
import { RiEqualizer2Line } from '@remixicon/react'
import { FolderUpload } from '@/app/components/base/icons/src/vender/features'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import SettingModal from '@/app/components/base/features/new-feature-panel/file-upload/setting-modal'
import Button from '@/app/components/base/button'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import SettingModal from '@/app/components/base/features/new-feature-panel/file-upload/setting-modal'
import { FeatureEnum } from '@/app/components/base/features/types'
import { FolderUpload } from '@/app/components/base/icons/src/vender/features'
type Props = {
disabled: boolean
@ -49,11 +49,11 @@ const FileUpload = ({
return (
<FeatureCard
icon={
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-blue-600 p-1 shadow-xs'>
<FolderUpload className='h-4 w-4 text-text-primary-on-surface' />
icon={(
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-blue-600 p-1 shadow-xs">
<FolderUpload className="h-4 w-4 text-text-primary-on-surface" />
</div>
}
)}
title={t('appDebug.feature.fileUpload.title')}
value={file?.enabled}
onChange={state => handleChange(FeatureEnum.file, state)}
@ -63,20 +63,20 @@ const FileUpload = ({
>
<>
{!file?.enabled && (
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.fileUpload.description')}</div>
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{t('appDebug.feature.fileUpload.description')}</div>
)}
{file?.enabled && (
<>
{!isHovering && !modalOpen && (
<div className='flex items-center gap-4 pt-0.5'>
<div className=''>
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.fileUpload.supportedTypes')}</div>
<div className='system-xs-regular text-text-secondary'>{supportedTypes}</div>
<div className="flex items-center gap-4 pt-0.5">
<div className="">
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.feature.fileUpload.supportedTypes')}</div>
<div className="system-xs-regular text-text-secondary">{supportedTypes}</div>
</div>
<div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
<div className=''>
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.fileUpload.numberLimit')}</div>
<div className='system-xs-regular text-text-secondary'>{file?.number_limits}</div>
<div className="h-[27px] w-px rotate-12 bg-divider-subtle"></div>
<div className="">
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.feature.fileUpload.numberLimit')}</div>
<div className="system-xs-regular text-text-secondary">{file?.number_limits}</div>
</div>
</div>
)}
@ -89,8 +89,8 @@ const FileUpload = ({
}}
onChange={onChange}
>
<Button className='w-full' disabled={disabled}>
<RiEqualizer2Line className='mr-1 h-4 w-4' />
<Button className="w-full" disabled={disabled}>
<RiEqualizer2Line className="mr-1 h-4 w-4" />
{t('common.operation.settings')}
</Button>
</SettingModal>

View File

@ -1,14 +1,14 @@
import React, { useCallback, useMemo, useState } from 'react'
import { produce } from 'immer'
import { useTranslation } from 'react-i18next'
import { RiCloseLine } from '@remixicon/react'
import FileUploadSetting from '@/app/components/workflow/nodes/_base/components/file-upload-setting'
import Button from '@/app/components/base/button'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import type { UploadFileSetting } from '@/app/components/workflow/types'
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
import { RiCloseLine } from '@remixicon/react'
import { produce } from 'immer'
import React, { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Button from '@/app/components/base/button'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
import FileUploadSetting from '@/app/components/workflow/nodes/_base/components/file-upload-setting'
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
type SettingContentProps = {
imageUpload?: boolean
@ -56,9 +56,9 @@ const SettingContent = ({
return (
<>
<div className='mb-4 flex items-center justify-between'>
<div className='system-xl-semibold text-text-primary'>{!imageUpload ? t('appDebug.feature.fileUpload.modalTitle') : t('appDebug.feature.imageUpload.modalTitle')}</div>
<div className='cursor-pointer p-1' onClick={onClose}><RiCloseLine className='h-4 w-4 text-text-tertiary'/></div>
<div className="mb-4 flex items-center justify-between">
<div className="system-xl-semibold text-text-primary">{!imageUpload ? t('appDebug.feature.fileUpload.modalTitle') : t('appDebug.feature.imageUpload.modalTitle')}</div>
<div className="cursor-pointer p-1" onClick={onClose}><RiCloseLine className="h-4 w-4 text-text-tertiary" /></div>
</div>
<FileUploadSetting
isMultiple
@ -67,15 +67,15 @@ const SettingContent = ({
payload={tempPayload}
onChange={(p: UploadFileSetting) => setTempPayload(p)}
/>
<div className='mt-4 flex items-center justify-end'>
<div className="mt-4 flex items-center justify-end">
<Button
onClick={onClose}
className='mr-2'
className="mr-2"
>
{t('common.operation.cancel')}
</Button>
<Button
variant='primary'
variant="primary"
onClick={handleChange}
disabled={tempPayload.allowed_file_types.length === 0}
>

View File

@ -1,12 +1,12 @@
'use client'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import { memo } from 'react'
import SettingContent from '@/app/components/base/features/new-feature-panel/file-upload/setting-content'
import {
PortalToFollowElem,
PortalToFollowElemContent,
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import SettingContent from '@/app/components/base/features/new-feature-panel/file-upload/setting-content'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
type FileUploadSettingsProps = {
open: boolean
@ -28,23 +28,24 @@ const FileUploadSettings = ({
<PortalToFollowElem
open={open}
onOpenChange={onOpen}
placement='left'
placement="left"
offset={{
mainAxis: 32,
}}
>
<PortalToFollowElemTrigger className='flex' onClick={() => !disabled && onOpen((open: boolean) => !open)}>
<PortalToFollowElemTrigger className="flex" onClick={() => !disabled && onOpen((open: boolean) => !open)}>
{children}
</PortalToFollowElemTrigger>
<PortalToFollowElemContent style={{ zIndex: 50 }}>
<div className='max-h-[calc(100vh-20px)] w-[360px] overflow-y-auto rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-4 shadow-2xl'>
<div className="max-h-[calc(100vh-20px)] w-[360px] overflow-y-auto rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-4 shadow-2xl">
<SettingContent
imageUpload={imageUpload}
onClose={() => onOpen(false)}
onChange={(v) => {
onChange?.(v)
onOpen(false)
}} />
}}
/>
</div>
</PortalToFollowElemContent>
</PortalToFollowElem>

View File

@ -1,11 +1,11 @@
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import { produce } from 'immer'
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { produce } from 'immer'
import { VirtualAssistant } from '@/app/components/base/icons/src/vender/features'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import { FeatureEnum } from '@/app/components/base/features/types'
import { VirtualAssistant } from '@/app/components/base/icons/src/vender/features'
type Props = {
disabled?: boolean
@ -39,11 +39,11 @@ const FollowUp = ({
return (
<FeatureCard
icon={
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
<VirtualAssistant className='h-4 w-4 text-text-primary-on-surface' />
icon={(
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs">
<VirtualAssistant className="h-4 w-4 text-text-primary-on-surface" />
</div>
}
)}
title={t('appDebug.feature.suggestedQuestionsAfterAnswer.title')}
value={!!features.suggested?.enabled}
description={t('appDebug.feature.suggestedQuestionsAfterAnswer.description')!}

View File

@ -1,13 +1,13 @@
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import { RiEqualizer2Line, RiImage2Fill } from '@remixicon/react'
import { produce } from 'immer'
import React, { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { produce } from 'immer'
import { RiEqualizer2Line, RiImage2Fill } from '@remixicon/react'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import SettingModal from '@/app/components/base/features/new-feature-panel/file-upload/setting-modal'
import Badge from '@/app/components/base/badge'
import Button from '@/app/components/base/button'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import SettingModal from '@/app/components/base/features/new-feature-panel/file-upload/setting-modal'
import { FeatureEnum } from '@/app/components/base/features/types'
type Props = {
@ -49,20 +49,20 @@ const FileUpload = ({
return (
<FeatureCard
icon={
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs'>
<RiImage2Fill className='h-4 w-4 text-text-primary-on-surface' />
icon={(
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs">
<RiImage2Fill className="h-4 w-4 text-text-primary-on-surface" />
</div>
}
title={
<div className='flex items-center'>
)}
title={(
<div className="flex items-center">
{t('appDebug.feature.imageUpload.title')}
<Badge
text='LEGACY'
className='mx-1 shrink-0 border-text-accent-secondary text-text-accent-secondary'
text="LEGACY"
className="mx-1 shrink-0 border-text-accent-secondary text-text-accent-secondary"
/>
</div>
}
)}
value={file?.enabled}
onChange={state => handleChange(FeatureEnum.file, state)}
onMouseEnter={() => setIsHovering(true)}
@ -71,20 +71,20 @@ const FileUpload = ({
>
<>
{!file?.enabled && (
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.imageUpload.description')}</div>
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{t('appDebug.feature.imageUpload.description')}</div>
)}
{file?.enabled && (
<>
{!isHovering && !modalOpen && (
<div className='flex items-center gap-4 pt-0.5'>
<div className=''>
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.imageUpload.supportedTypes')}</div>
<div className='system-xs-regular text-text-secondary'>{supportedTypes}</div>
<div className="flex items-center gap-4 pt-0.5">
<div className="">
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.feature.imageUpload.supportedTypes')}</div>
<div className="system-xs-regular text-text-secondary">{supportedTypes}</div>
</div>
<div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
<div className=''>
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.imageUpload.numberLimit')}</div>
<div className='system-xs-regular text-text-secondary'>{file?.number_limits}</div>
<div className="h-[27px] w-px rotate-12 bg-divider-subtle"></div>
<div className="">
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.feature.imageUpload.numberLimit')}</div>
<div className="system-xs-regular text-text-secondary">{file?.number_limits}</div>
</div>
</div>
)}
@ -98,8 +98,8 @@ const FileUpload = ({
}}
onChange={onChange}
>
<Button className='w-full' disabled={disabled}>
<RiEqualizer2Line className='mr-1 h-4 w-4' />
<Button className="w-full" disabled={disabled}>
<RiEqualizer2Line className="mr-1 h-4 w-4" />
{t('common.operation.settings')}
</Button>
</SettingModal>

View File

@ -1,23 +1,23 @@
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import type { InputVar } from '@/app/components/workflow/types'
import type { PromptVariable } from '@/models/debug'
import { RiCloseLine, RiInformation2Fill } from '@remixicon/react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { RiCloseLine, RiInformation2Fill } from '@remixicon/react'
import DialogWrapper from '@/app/components/base/features/new-feature-panel/dialog-wrapper'
import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import AnnotationReply from '@/app/components/base/features/new-feature-panel/annotation-reply'
import MoreLikeThis from '@/app/components/base/features/new-feature-panel/more-like-this'
import ConversationOpener from '@/app/components/base/features/new-feature-panel/conversation-opener'
import FollowUp from '@/app/components/base/features/new-feature-panel/follow-up'
import SpeechToText from '@/app/components/base/features/new-feature-panel/speech-to-text'
import TextToSpeech from '@/app/components/base/features/new-feature-panel/text-to-speech'
import FileUpload from '@/app/components/base/features/new-feature-panel/file-upload'
import Citation from '@/app/components/base/features/new-feature-panel/citation'
import ConversationOpener from '@/app/components/base/features/new-feature-panel/conversation-opener'
import DialogWrapper from '@/app/components/base/features/new-feature-panel/dialog-wrapper'
import FileUpload from '@/app/components/base/features/new-feature-panel/file-upload'
import FollowUp from '@/app/components/base/features/new-feature-panel/follow-up'
import ImageUpload from '@/app/components/base/features/new-feature-panel/image-upload'
import Moderation from '@/app/components/base/features/new-feature-panel/moderation'
import AnnotationReply from '@/app/components/base/features/new-feature-panel/annotation-reply'
import type { PromptVariable } from '@/models/debug'
import type { InputVar } from '@/app/components/workflow/types'
import MoreLikeThis from '@/app/components/base/features/new-feature-panel/more-like-this'
import SpeechToText from '@/app/components/base/features/new-feature-panel/speech-to-text'
import TextToSpeech from '@/app/components/base/features/new-feature-panel/text-to-speech'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { useDocLink } from '@/context/i18n'
type Props = {
@ -56,31 +56,34 @@ const NewFeaturePanel = ({
onClose={onClose}
inWorkflow={inWorkflow}
>
<div className='flex h-full grow flex-col'>
<div className="flex h-full grow flex-col">
{/* header */}
<div className='flex shrink-0 justify-between p-4 pb-3'>
<div className="flex shrink-0 justify-between p-4 pb-3">
<div>
<div className='system-xl-semibold text-text-primary'>{t('workflow.common.features')}</div>
<div className='body-xs-regular text-text-tertiary'>{t('workflow.common.featuresDescription')}</div>
<div className="system-xl-semibold text-text-primary">{t('workflow.common.features')}</div>
<div className="body-xs-regular text-text-tertiary">{t('workflow.common.featuresDescription')}</div>
</div>
<div className='h-8 w-8 cursor-pointer p-2' onClick={onClose}><RiCloseLine className='h-4 w-4 text-text-tertiary'/></div>
<div className="h-8 w-8 cursor-pointer p-2" onClick={onClose}><RiCloseLine className="h-4 w-4 text-text-tertiary" /></div>
</div>
{/* list */}
<div className='grow basis-0 overflow-y-auto px-4 pb-4'>
<div className="grow basis-0 overflow-y-auto px-4 pb-4">
{showFileUpload && (
<div className='relative mb-1 rounded-xl border border-components-panel-border p-2 shadow-xs'>
<div className='absolute left-0 top-0 h-full w-full rounded-xl opacity-40' style={{ background: 'linear-gradient(92deg, rgba(11, 165, 236, 0.25) 18.12%, rgba(255, 255, 255, 0.00) 167.31%)' }}></div>
<div className='relative flex h-full w-full items-start'>
<div className='mr-0.5 shrink-0 p-0.5'>
<RiInformation2Fill className='h-5 w-5 text-text-accent' />
<div className="relative mb-1 rounded-xl border border-components-panel-border p-2 shadow-xs">
<div className="absolute left-0 top-0 h-full w-full rounded-xl opacity-40" style={{ background: 'linear-gradient(92deg, rgba(11, 165, 236, 0.25) 18.12%, rgba(255, 255, 255, 0.00) 167.31%)' }}></div>
<div className="relative flex h-full w-full items-start">
<div className="mr-0.5 shrink-0 p-0.5">
<RiInformation2Fill className="h-5 w-5 text-text-accent" />
</div>
<div className='system-xs-medium p-1 text-text-primary'>
<div className="system-xs-medium p-1 text-text-primary">
<span>{isChatMode ? t('workflow.common.fileUploadTip') : t('workflow.common.ImageUploadLegacyTip')}</span>
<a
className='text-text-accent'
className="text-text-accent"
href={docLink('/guides/workflow/bulletin')}
target='_blank' rel='noopener noreferrer'
>{t('workflow.common.featuresDocLink')}</a>
target="_blank"
rel="noopener noreferrer"
>
{t('workflow.common.featuresDocLink')}
</a>
</div>
</div>
</div>

View File

@ -1,10 +1,10 @@
import type { FC } from 'react'
import { useContext } from 'use-context-selector'
import type { CodeBasedExtensionForm } from '@/models/common'
import I18n from '@/context/i18n'
import type { ModerationConfig } from '@/models/debug'
import { useContext } from 'use-context-selector'
import { PortalSelect } from '@/app/components/base/select'
import Textarea from '@/app/components/base/textarea'
import type { ModerationConfig } from '@/models/debug'
import I18n from '@/context/i18n'
type FormGenerationProps = {
forms: CodeBasedExtensionForm[]
@ -28,16 +28,16 @@ const FormGeneration: FC<FormGenerationProps> = ({
forms.map((form, index) => (
<div
key={index}
className='py-2'
className="py-2"
>
<div className='flex h-9 items-center text-sm font-medium text-text-primary'>
<div className="flex h-9 items-center text-sm font-medium text-text-primary">
{locale === 'zh-Hans' ? form.label['zh-Hans'] : form.label['en-US']}
</div>
{
form.type === 'text-input' && (
<input
value={value?.[form.variable] || ''}
className='block h-9 w-full appearance-none rounded-lg bg-components-input-bg-normal px-3 text-sm text-text-primary outline-none'
className="block h-9 w-full appearance-none rounded-lg bg-components-input-bg-normal px-3 text-sm text-text-primary outline-none"
placeholder={form.placeholder}
onChange={e => handleFormChange(form.variable, e.target.value)}
/>
@ -45,9 +45,9 @@ const FormGeneration: FC<FormGenerationProps> = ({
}
{
form.type === 'paragraph' && (
<div className='relative'>
<div className="relative">
<Textarea
className='resize-none'
className="resize-none"
value={value?.[form.variable] || ''}
placeholder={form.placeholder}
onChange={e => handleFormChange(form.variable, e.target.value)}
@ -66,7 +66,7 @@ const FormGeneration: FC<FormGenerationProps> = ({
}
})}
onSelect={item => handleFormChange(form.variable, item.value as string)}
popupClassName='w-[576px] !z-[102]'
popupClassName="w-[576px] !z-[102]"
/>
)
}

View File

@ -1,16 +1,16 @@
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import { RiEqualizer2Line } from '@remixicon/react'
import { produce } from 'immer'
import React, { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { produce } from 'immer'
import { useContext } from 'use-context-selector'
import { RiEqualizer2Line } from '@remixicon/react'
import { ContentModeration } from '@/app/components/base/icons/src/vender/features'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import Button from '@/app/components/base/button'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import { FeatureEnum } from '@/app/components/base/features/types'
import { useModalContext } from '@/context/modal-context'
import { ContentModeration } from '@/app/components/base/icons/src/vender/features'
import I18n from '@/context/i18n'
import { useModalContext } from '@/context/modal-context'
import { useCodeBasedExtensions } from '@/service/use-common'
type Props = {
@ -125,11 +125,11 @@ const Moderation = ({
return (
<FeatureCard
icon={
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-text-success p-1 shadow-xs'>
<ContentModeration className='h-4 w-4 text-text-primary-on-surface' />
icon={(
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-text-success p-1 shadow-xs">
<ContentModeration className="h-4 w-4 text-text-primary-on-surface" />
</div>
}
)}
title={t('appDebug.feature.moderation.title')}
value={!!moderation?.enabled}
onChange={state => handleChange(FeatureEnum.moderation, state)}
@ -139,26 +139,26 @@ const Moderation = ({
>
<>
{!moderation?.enabled && (
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.moderation.description')}</div>
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{t('appDebug.feature.moderation.description')}</div>
)}
{!!moderation?.enabled && (
<>
{!isHovering && (
<div className='flex items-center gap-4 pt-0.5'>
<div className=''>
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.moderation.modal.provider.title')}</div>
<div className='system-xs-regular text-text-secondary'>{providerContent}</div>
<div className="flex items-center gap-4 pt-0.5">
<div className="">
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.feature.moderation.modal.provider.title')}</div>
<div className="system-xs-regular text-text-secondary">{providerContent}</div>
</div>
<div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
<div className=''>
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.moderation.contentEnableLabel')}</div>
<div className='system-xs-regular text-text-secondary'>{enableContent}</div>
<div className="h-[27px] w-px rotate-12 bg-divider-subtle"></div>
<div className="">
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.feature.moderation.contentEnableLabel')}</div>
<div className="system-xs-regular text-text-secondary">{enableContent}</div>
</div>
</div>
)}
{isHovering && (
<Button className='w-full' onClick={handleOpenModerationSettingModal} disabled={disabled}>
<RiEqualizer2Line className='mr-1 h-4 w-4' />
<Button className="w-full" onClick={handleOpenModerationSettingModal} disabled={disabled}>
<RiEqualizer2Line className="mr-1 h-4 w-4" />
{t('common.operation.settings')}
</Button>
)}

View File

@ -1,7 +1,7 @@
import type { FC } from 'react'
import type { ModerationContentConfig } from '@/models/debug'
import { useTranslation } from 'react-i18next'
import Switch from '@/app/components/base/switch'
import type { ModerationContentConfig } from '@/models/debug'
type ModerationContentProps = {
title: string
@ -26,18 +26,18 @@ const ModerationContent: FC<ModerationContentProps> = ({
}
return (
<div className='py-2'>
<div className='rounded-lg border border-components-panel-border bg-components-panel-bg'>
<div className='flex h-10 items-center justify-between rounded-lg px-3'>
<div className='shrink-0 text-sm font-medium text-text-primary'>{title}</div>
<div className='flex grow items-center justify-end'>
<div className="py-2">
<div className="rounded-lg border border-components-panel-border bg-components-panel-bg">
<div className="flex h-10 items-center justify-between rounded-lg px-3">
<div className="shrink-0 text-sm font-medium text-text-primary">{title}</div>
<div className="flex grow items-center justify-end">
{
info && (
<div className='mr-2 truncate text-xs text-text-tertiary' title={info}>{info}</div>
<div className="mr-2 truncate text-xs text-text-tertiary" title={info}>{info}</div>
)
}
<Switch
size='l'
size="l"
defaultValue={config.enabled}
onChange={v => handleConfigChange('enabled', v)}
/>
@ -45,20 +45,22 @@ const ModerationContent: FC<ModerationContentProps> = ({
</div>
{
config.enabled && showPreset && (
<div className='rounded-lg bg-components-panel-bg px-3 pb-3 pt-1'>
<div className='flex h-8 items-center justify-between text-[13px] font-medium text-text-secondary'>
<div className="rounded-lg bg-components-panel-bg px-3 pb-3 pt-1">
<div className="flex h-8 items-center justify-between text-[13px] font-medium text-text-secondary">
{t('appDebug.feature.moderation.modal.content.preset')}
<span className='text-xs font-normal text-text-tertiary'>{t('appDebug.feature.moderation.modal.content.supportMarkdown')}</span>
<span className="text-xs font-normal text-text-tertiary">{t('appDebug.feature.moderation.modal.content.supportMarkdown')}</span>
</div>
<div className='relative h-20 rounded-lg bg-components-input-bg-normal px-3 py-2'>
<div className="relative h-20 rounded-lg bg-components-input-bg-normal px-3 py-2">
<textarea
value={config.preset_response || ''}
className='block h-full w-full resize-none appearance-none bg-transparent text-sm text-text-secondary outline-none'
className="block h-full w-full resize-none appearance-none bg-transparent text-sm text-text-secondary outline-none"
placeholder={t('appDebug.feature.moderation.modal.content.placeholder') || ''}
onChange={e => handleConfigChange('preset_response', e.target.value)}
/>
<div className='absolute bottom-2 right-2 flex h-5 items-center rounded-md bg-background-section px-1 text-xs font-medium text-text-quaternary'>
<span>{(config.preset_response || '').length}</span>/<span className='text-text-tertiary'>100</span>
<div className="absolute bottom-2 right-2 flex h-5 items-center rounded-md bg-background-section px-1 text-xs font-medium text-text-quaternary">
<span>{(config.preset_response || '').length}</span>
/
<span className="text-text-tertiary">100</span>
</div>
</div>
</div>

View File

@ -1,28 +1,27 @@
import type { ChangeEvent, FC } from 'react'
import { useState } from 'react'
import { useContext } from 'use-context-selector'
import { useTranslation } from 'react-i18next'
import type { CodeBasedExtensionItem } from '@/models/common'
import type { ModerationConfig, ModerationContentConfig } from '@/models/debug'
import { RiCloseLine } from '@remixicon/react'
import ModerationContent from './moderation-content'
import FormGeneration from './form-generation'
import ApiBasedExtensionSelector from '@/app/components/header/account-setting/api-based-extension-page/selector'
import Modal from '@/app/components/base/modal'
import { noop } from 'lodash-es'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import Button from '@/app/components/base/button'
import Divider from '@/app/components/base/divider'
import { BookOpen01 } from '@/app/components/base/icons/src/vender/line/education'
import type { ModerationConfig, ModerationContentConfig } from '@/models/debug'
import { useToastContext } from '@/app/components/base/toast'
import type { CodeBasedExtensionItem } from '@/models/common'
import I18n from '@/context/i18n'
import { LanguagesSupported } from '@/i18n-config/language'
import { InfoCircle } from '@/app/components/base/icons/src/vender/line/general'
import { useModalContext } from '@/context/modal-context'
import { CustomConfigurationStatusEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { cn } from '@/utils/classnames'
import { noop } from 'lodash-es'
import { useDocLink } from '@/context/i18n'
import Modal from '@/app/components/base/modal'
import { useToastContext } from '@/app/components/base/toast'
import ApiBasedExtensionSelector from '@/app/components/header/account-setting/api-based-extension-page/selector'
import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/constants'
import { CustomConfigurationStatusEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import I18n, { useDocLink } from '@/context/i18n'
import { useModalContext } from '@/context/modal-context'
import { LanguagesSupported } from '@/i18n-config/language'
import { useCodeBasedExtensions, useModelProviders } from '@/service/use-common'
import { cn } from '@/utils/classnames'
import FormGeneration from './form-generation'
import ModerationContent from './moderation-content'
const systemTypes = ['openai_moderation', 'keywords', 'api']
@ -81,12 +80,12 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
...(
codeBasedExtensionList
? codeBasedExtensionList.data.map((item) => {
return {
key: item.name,
name: locale === 'zh-Hans' ? item.label['zh-Hans'] : item.label['en-US'],
form_schema: item.form_schema,
}
})
return {
key: item.name,
name: locale === 'zh-Hans' ? item.label['zh-Hans'] : item.label['en-US'],
form_schema: item.form_schema,
}
})
: []
),
]
@ -237,17 +236,17 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
<Modal
isShow
onClose={noop}
className='!mt-14 !w-[600px] !max-w-none !p-6'
className="!mt-14 !w-[600px] !max-w-none !p-6"
>
<div className='flex items-center justify-between'>
<div className='title-2xl-semi-bold text-text-primary'>{t('appDebug.feature.moderation.modal.title')}</div>
<div className='cursor-pointer p-1' onClick={onCancel}><RiCloseLine className='h-4 w-4 text-text-tertiary' /></div>
<div className="flex items-center justify-between">
<div className="title-2xl-semi-bold text-text-primary">{t('appDebug.feature.moderation.modal.title')}</div>
<div className="cursor-pointer p-1" onClick={onCancel}><RiCloseLine className="h-4 w-4 text-text-tertiary" /></div>
</div>
<div className='py-2'>
<div className='text-sm font-medium leading-9 text-text-primary'>
<div className="py-2">
<div className="text-sm font-medium leading-9 text-text-primary">
{t('appDebug.feature.moderation.modal.provider.title')}
</div>
<div className='grid grid-cols-3 gap-2.5'>
<div className="grid grid-cols-3 gap-2.5">
{
providers.map(provider => (
<div
@ -263,7 +262,9 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
<div className={cn(
'mr-2 h-4 w-4 rounded-full border border-components-radio-border bg-components-radio-bg shadow-xs',
localeData.type === provider.key && 'border-[5px] border-components-radio-border-checked',
)}></div>
)}
>
</div>
{provider.name}
</div>
))
@ -271,15 +272,17 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
</div>
{
!isLoading && !isOpenAIProviderConfigured && localeData.type === 'openai_moderation' && (
<div className='mt-2 flex items-center rounded-lg border border-[#FEF0C7] bg-[#FFFAEB] px-3 py-2'>
<InfoCircle className='mr-1 h-4 w-4 text-[#F79009]' />
<div className='flex items-center text-xs font-medium text-gray-700'>
<div className="mt-2 flex items-center rounded-lg border border-[#FEF0C7] bg-[#FFFAEB] px-3 py-2">
<InfoCircle className="mr-1 h-4 w-4 text-[#F79009]" />
<div className="flex items-center text-xs font-medium text-gray-700">
{t('appDebug.feature.moderation.modal.openaiNotConfig.before')}
<span
className='cursor-pointer text-primary-600'
className="cursor-pointer text-primary-600"
onClick={handleOpenSettingsModal}
>
&nbsp;{t('common.settings.provider')}&nbsp;
&nbsp;
{t('common.settings.provider')}
&nbsp;
</span>
{t('appDebug.feature.moderation.modal.openaiNotConfig.after')}
</div>
@ -289,18 +292,23 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
</div>
{
localeData.type === 'keywords' && (
<div className='py-2'>
<div className='mb-1 text-sm font-medium text-text-primary'>{t('appDebug.feature.moderation.modal.provider.keywords')}</div>
<div className='mb-2 text-xs text-text-tertiary'>{t('appDebug.feature.moderation.modal.keywords.tip')}</div>
<div className='relative h-[88px] rounded-lg bg-components-input-bg-normal px-3 py-2'>
<div className="py-2">
<div className="mb-1 text-sm font-medium text-text-primary">{t('appDebug.feature.moderation.modal.provider.keywords')}</div>
<div className="mb-2 text-xs text-text-tertiary">{t('appDebug.feature.moderation.modal.keywords.tip')}</div>
<div className="relative h-[88px] rounded-lg bg-components-input-bg-normal px-3 py-2">
<textarea
value={localeData.config?.keywords || ''}
onChange={handleDataKeywordsChange}
className='block h-full w-full resize-none appearance-none bg-transparent text-sm text-text-secondary outline-none'
className="block h-full w-full resize-none appearance-none bg-transparent text-sm text-text-secondary outline-none"
placeholder={t('appDebug.feature.moderation.modal.keywords.placeholder') || ''}
/>
<div className='absolute bottom-2 right-2 flex h-5 items-center rounded-md bg-background-section px-1 text-xs font-medium text-text-quaternary'>
<span>{(localeData.config?.keywords || '').split('\n').filter(Boolean).length}</span>/<span className='text-text-tertiary'>100 {t('appDebug.feature.moderation.modal.keywords.line')}</span>
<div className="absolute bottom-2 right-2 flex h-5 items-center rounded-md bg-background-section px-1 text-xs font-medium text-text-quaternary">
<span>{(localeData.config?.keywords || '').split('\n').filter(Boolean).length}</span>
/
<span className="text-text-tertiary">
100
{t('appDebug.feature.moderation.modal.keywords.line')}
</span>
</div>
</div>
</div>
@ -308,15 +316,16 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
}
{
localeData.type === 'api' && (
<div className='py-2'>
<div className='flex h-9 items-center justify-between'>
<div className='text-sm font-medium text-text-primary'>{t('common.apiBasedExtension.selector.title')}</div>
<div className="py-2">
<div className="flex h-9 items-center justify-between">
<div className="text-sm font-medium text-text-primary">{t('common.apiBasedExtension.selector.title')}</div>
<a
href={docLink('/guides/extension/api-based-extension/README')}
target='_blank' rel='noopener noreferrer'
className='group flex items-center text-xs text-text-tertiary hover:text-primary-600'
target="_blank"
rel="noopener noreferrer"
className="group flex items-center text-xs text-text-tertiary hover:text-primary-600"
>
<BookOpen01 className='mr-1 h-3 w-3 text-text-tertiary group-hover:text-primary-600' />
<BookOpen01 className="mr-1 h-3 w-3 text-text-tertiary group-hover:text-primary-600" />
{t('common.apiBasedExtension.link')}
</a>
</div>
@ -338,7 +347,7 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
/>
)
}
<Divider bgStyle='gradient' className='my-3 h-px' />
<Divider bgStyle="gradient" className="my-3 h-px" />
<ModerationContent
title={t('appDebug.feature.moderation.modal.content.input') || ''}
config={localeData.config?.inputs_config || { enabled: false, preset_response: '' }}
@ -353,16 +362,16 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
info={(localeData.type === 'api' && t('appDebug.feature.moderation.modal.content.fromApi')) || ''}
showPreset={localeData.type !== 'api'}
/>
<div className='mb-8 mt-1 text-xs font-medium text-text-tertiary'>{t('appDebug.feature.moderation.modal.content.condition')}</div>
<div className='flex items-center justify-end'>
<div className="mb-8 mt-1 text-xs font-medium text-text-tertiary">{t('appDebug.feature.moderation.modal.content.condition')}</div>
<div className="flex items-center justify-end">
<Button
onClick={onCancel}
className='mr-2'
className="mr-2"
>
{t('common.operation.cancel')}
</Button>
<Button
variant='primary'
variant="primary"
onClick={handleSave}
disabled={localeData.type === 'openai_moderation' && !isOpenAIProviderConfigured}
>

View File

@ -1,10 +1,10 @@
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import { RiSparklingFill } from '@remixicon/react'
import { produce } from 'immer'
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { produce } from 'immer'
import { RiSparklingFill } from '@remixicon/react'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import { FeatureEnum } from '@/app/components/base/features/types'
type Props = {
@ -39,11 +39,11 @@ const MoreLikeThis = ({
return (
<FeatureCard
icon={
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
<RiSparklingFill className='h-4 w-4 text-text-primary-on-surface' />
icon={(
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs">
<RiSparklingFill className="h-4 w-4 text-text-primary-on-surface" />
</div>
}
)}
title={t('appDebug.feature.moreLikeThis.title')}
tooltip={t('appDebug.feature.moreLikeThis.tip')}
value={!!features.moreLikeThis?.enabled}

View File

@ -1,11 +1,11 @@
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import { produce } from 'immer'
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { produce } from 'immer'
import { Microphone01 } from '@/app/components/base/icons/src/vender/features'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import { FeatureEnum } from '@/app/components/base/features/types'
import { Microphone01 } from '@/app/components/base/icons/src/vender/features'
type Props = {
disabled: boolean
@ -39,11 +39,11 @@ const SpeechToText = ({
return (
<FeatureCard
icon={
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs'>
<Microphone01 className='h-4 w-4 text-text-primary-on-surface' />
icon={(
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs">
<Microphone01 className="h-4 w-4 text-text-primary-on-surface" />
</div>
}
)}
title={t('appDebug.feature.speechToText.title')}
value={!!features.speech2text?.enabled}
description={t('appDebug.feature.speechToText.description')!}

View File

@ -1,14 +1,14 @@
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import { RiEqualizer2Line } from '@remixicon/react'
import { produce } from 'immer'
import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { produce } from 'immer'
import { RiEqualizer2Line } from '@remixicon/react'
import { TextToAudio } from '@/app/components/base/icons/src/vender/features'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import Button from '@/app/components/base/button'
import VoiceSettings from '@/app/components/base/features/new-feature-panel/text-to-speech/voice-settings'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import VoiceSettings from '@/app/components/base/features/new-feature-panel/text-to-speech/voice-settings'
import { FeatureEnum } from '@/app/components/base/features/types'
import { TextToAudio } from '@/app/components/base/icons/src/vender/features'
import { languages } from '@/i18n-config/language'
import { TtsAutoPlay } from '@/types/app'
@ -48,11 +48,11 @@ const TextToSpeech = ({
return (
<FeatureCard
icon={
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs'>
<TextToAudio className='h-4 w-4 text-text-primary-on-surface' />
icon={(
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs">
<TextToAudio className="h-4 w-4 text-text-primary-on-surface" />
</div>
}
)}
title={t('appDebug.feature.textToSpeech.title')}
value={!!features.text2speech?.enabled}
onChange={state => handleChange(FeatureEnum.text2speech, state)}
@ -62,32 +62,32 @@ const TextToSpeech = ({
>
<>
{!features.text2speech?.enabled && (
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.textToSpeech.description')}</div>
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{t('appDebug.feature.textToSpeech.description')}</div>
)}
{!!features.text2speech?.enabled && (
<>
{!isHovering && !modalOpen && (
<div className='flex items-center gap-4 pt-0.5'>
<div className=''>
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.voice.voiceSettings.language')}</div>
<div className='system-xs-regular text-text-secondary'>{languageInfo?.name || '-'}</div>
<div className="flex items-center gap-4 pt-0.5">
<div className="">
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.voice.voiceSettings.language')}</div>
<div className="system-xs-regular text-text-secondary">{languageInfo?.name || '-'}</div>
</div>
<div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
<div className=''>
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.voice.voiceSettings.voice')}</div>
<div className='system-xs-regular text-text-secondary'>{features.text2speech?.voice || t('appDebug.voice.defaultDisplay')}</div>
<div className="h-[27px] w-px rotate-12 bg-divider-subtle"></div>
<div className="">
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.voice.voiceSettings.voice')}</div>
<div className="system-xs-regular text-text-secondary">{features.text2speech?.voice || t('appDebug.voice.defaultDisplay')}</div>
</div>
<div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
<div className=''>
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.voice.voiceSettings.autoPlay')}</div>
<div className='system-xs-regular text-text-secondary'>{features.text2speech?.autoPlay === TtsAutoPlay.enabled ? t('appDebug.voice.voiceSettings.autoPlayEnabled') : t('appDebug.voice.voiceSettings.autoPlayDisabled')}</div>
<div className="h-[27px] w-px rotate-12 bg-divider-subtle"></div>
<div className="">
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.voice.voiceSettings.autoPlay')}</div>
<div className="system-xs-regular text-text-secondary">{features.text2speech?.autoPlay === TtsAutoPlay.enabled ? t('appDebug.voice.voiceSettings.autoPlayEnabled') : t('appDebug.voice.voiceSettings.autoPlayDisabled')}</div>
</div>
</div>
)}
{(isHovering || modalOpen) && (
<VoiceSettings open={modalOpen && !disabled} onOpen={setModalOpen} onChange={onChange}>
<Button className='w-full' disabled={disabled}>
<RiEqualizer2Line className='mr-1 h-4 w-4' />
<Button className="w-full" disabled={disabled}>
<RiEqualizer2Line className="mr-1 h-4 w-4" />
{t('appDebug.voice.voiceSettings.title')}
</Button>
</VoiceSettings>

View File

@ -1,21 +1,21 @@
'use client'
import { produce } from 'immer'
import React, { Fragment } from 'react'
import { usePathname } from 'next/navigation'
import { useTranslation } from 'react-i18next'
import { RiCloseLine } from '@remixicon/react'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import type { Item } from '@/app/components/base/select'
import { Listbox, ListboxButton, ListboxOption, ListboxOptions, Transition } from '@headlessui/react'
import { CheckIcon, ChevronDownIcon } from '@heroicons/react/20/solid'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import type { Item } from '@/app/components/base/select'
import Tooltip from '@/app/components/base/tooltip'
import Switch from '@/app/components/base/switch'
import { RiCloseLine } from '@remixicon/react'
import { produce } from 'immer'
import { usePathname } from 'next/navigation'
import React, { Fragment } from 'react'
import { useTranslation } from 'react-i18next'
import AudioBtn from '@/app/components/base/audio-btn'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import Switch from '@/app/components/base/switch'
import Tooltip from '@/app/components/base/tooltip'
import { languages } from '@/i18n-config/language'
import { TtsAutoPlay } from '@/types/app'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import { cn } from '@/utils/classnames'
import { useAppVoices } from '@/service/use-apps'
import { TtsAutoPlay } from '@/types/app'
import { cn } from '@/utils/classnames'
type VoiceParamConfigProps = {
onClose: () => void
@ -64,22 +64,23 @@ const VoiceParamConfig = ({
return (
<>
<div className='mb-4 flex items-center justify-between'>
<div className='system-xl-semibold text-text-primary'>{t('appDebug.voice.voiceSettings.title')}</div>
<div className='cursor-pointer p-1' onClick={onClose}><RiCloseLine className='h-4 w-4 text-text-tertiary' /></div>
<div className="mb-4 flex items-center justify-between">
<div className="system-xl-semibold text-text-primary">{t('appDebug.voice.voiceSettings.title')}</div>
<div className="cursor-pointer p-1" onClick={onClose}><RiCloseLine className="h-4 w-4 text-text-tertiary" /></div>
</div>
<div className='mb-3'>
<div className='system-sm-semibold mb-1 flex items-center py-1 text-text-secondary'>
<div className="mb-3">
<div className="system-sm-semibold mb-1 flex items-center py-1 text-text-secondary">
{t('appDebug.voice.voiceSettings.language')}
<Tooltip
popupContent={
<div className='w-[180px]'>
popupContent={(
<div className="w-[180px]">
{t('appDebug.voice.voiceSettings.resolutionTooltip').split('\n').map(item => (
<div key={item}>{item}
<div key={item}>
{item}
</div>
))}
</div>
}
)}
/>
</div>
<Listbox
@ -90,9 +91,10 @@ const VoiceParamConfig = ({
})
}}
>
<div className='relative h-8'>
<div className="relative h-8">
<ListboxButton
className={'h-full w-full cursor-pointer rounded-lg border-0 bg-components-input-bg-normal py-1.5 pl-3 pr-10 focus-visible:bg-state-base-hover focus-visible:outline-none group-hover:bg-state-base-hover sm:text-sm sm:leading-6'}>
className="h-full w-full cursor-pointer rounded-lg border-0 bg-components-input-bg-normal py-1.5 pl-3 pr-10 focus-visible:bg-state-base-hover focus-visible:outline-none group-hover:bg-state-base-hover sm:text-sm sm:leading-6"
>
<span className={cn('block truncate text-left text-text-secondary', !languageItem?.name && 'text-text-tertiary')}>
{languageItem?.name ? t(`common.voice.language.${languageItem?.value.replace('-', '')}`) : localLanguagePlaceholder}
</span>
@ -111,20 +113,22 @@ const VoiceParamConfig = ({
>
<ListboxOptions
className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md border-[0.5px] border-components-panel-border bg-components-panel-bg px-1 py-1 text-base shadow-lg focus:outline-none sm:text-sm">
className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md border-[0.5px] border-components-panel-border bg-components-panel-bg px-1 py-1 text-base shadow-lg focus:outline-none sm:text-sm"
>
{languages.map((item: Item) => (
<ListboxOption
key={item.value}
className={
'relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover data-[active]:bg-state-base-active'
}
className="relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover data-[active]:bg-state-base-active"
value={item}
disabled={false}
>
{({ /* active, */ selected }) => (
<>
<span
className={cn('block', selected && 'font-normal')}>{t(`common.voice.language.${(item.value).toString().replace('-', '')}`)}</span>
className={cn('block', selected && 'font-normal')}
>
{t(`common.voice.language.${(item.value).toString().replace('-', '')}`)}
</span>
{(selected || item.value === text2speech?.language) && (
<span
className={cn('absolute inset-y-0 right-0 flex items-center pr-4 text-text-secondary')}
@ -141,11 +145,11 @@ const VoiceParamConfig = ({
</div>
</Listbox>
</div>
<div className='mb-3'>
<div className='system-sm-semibold mb-1 py-1 text-text-secondary'>
<div className="mb-3">
<div className="system-sm-semibold mb-1 py-1 text-text-secondary">
{t('appDebug.voice.voiceSettings.voice')}
</div>
<div className='flex items-center gap-1'>
<div className="flex items-center gap-1">
<Listbox
value={voiceItem ?? {}}
disabled={!languageItem}
@ -155,11 +159,15 @@ const VoiceParamConfig = ({
})
}}
>
<div className={'relative h-8 grow'}>
<div className="relative h-8 grow">
<ListboxButton
className={'h-full w-full cursor-pointer rounded-lg border-0 bg-components-input-bg-normal py-1.5 pl-3 pr-10 focus-visible:bg-state-base-hover focus-visible:outline-none group-hover:bg-state-base-hover sm:text-sm sm:leading-6'}>
className="h-full w-full cursor-pointer rounded-lg border-0 bg-components-input-bg-normal py-1.5 pl-3 pr-10 focus-visible:bg-state-base-hover focus-visible:outline-none group-hover:bg-state-base-hover sm:text-sm sm:leading-6"
>
<span
className={cn('block truncate text-left text-text-secondary', !voiceItem?.name && 'text-text-tertiary')}>{voiceItem?.name ?? localVoicePlaceholder}</span>
className={cn('block truncate text-left text-text-secondary', !voiceItem?.name && 'text-text-tertiary')}
>
{voiceItem?.name ?? localVoicePlaceholder}
</span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<ChevronDownIcon
className="h-4 w-4 text-text-tertiary"
@ -175,13 +183,12 @@ const VoiceParamConfig = ({
>
<ListboxOptions
className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md border-[0.5px] border-components-panel-border bg-components-panel-bg px-1 py-1 text-base shadow-lg focus:outline-none sm:text-sm">
className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md border-[0.5px] border-components-panel-border bg-components-panel-bg px-1 py-1 text-base shadow-lg focus:outline-none sm:text-sm"
>
{voiceItems?.map((item: Item) => (
<ListboxOption
key={item.value}
className={
'relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover data-[active]:bg-state-base-active'
}
className="relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover data-[active]:bg-state-base-active"
value={item}
disabled={false}
>
@ -204,7 +211,7 @@ const VoiceParamConfig = ({
</div>
</Listbox>
{languageItem?.example && (
<div className='h-8 shrink-0 rounded-lg bg-components-button-tertiary-bg p-1'>
<div className="h-8 shrink-0 rounded-lg bg-components-button-tertiary-bg p-1">
<AudioBtn
value={languageItem?.example}
isAudition
@ -216,10 +223,11 @@ const VoiceParamConfig = ({
</div>
</div>
<div>
<div className='system-sm-semibold mb-1 py-1 text-text-secondary'>
<div className="system-sm-semibold mb-1 py-1 text-text-secondary">
{t('appDebug.voice.voiceSettings.autoPlay')}
</div>
<Switch className='shrink-0'
<Switch
className="shrink-0"
defaultValue={text2speech?.autoPlay === TtsAutoPlay.enabled}
onChange={(value: boolean) => {
handleChange({

View File

@ -1,12 +1,12 @@
'use client'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import { memo } from 'react'
import ParamConfigContent from '@/app/components/base/features/new-feature-panel/text-to-speech/param-config-content'
import {
PortalToFollowElem,
PortalToFollowElemContent,
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import ParamConfigContent from '@/app/components/base/features/new-feature-panel/text-to-speech/param-config-content'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
type VoiceSettingsProps = {
open: boolean
@ -33,11 +33,11 @@ const VoiceSettings = ({
mainAxis: placementLeft ? 32 : 4,
}}
>
<PortalToFollowElemTrigger className='flex' onClick={() => !disabled && onOpen((open: boolean) => !open)}>
<PortalToFollowElemTrigger className="flex" onClick={() => !disabled && onOpen((open: boolean) => !open)}>
{children}
</PortalToFollowElemTrigger>
<PortalToFollowElemContent style={{ zIndex: 50 }}>
<div className='w-[360px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-4 shadow-2xl'>
<div className="w-[360px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-4 shadow-2xl">
<ParamConfigContent onClose={() => onOpen(false)} onChange={onChange} />
</div>
</PortalToFollowElemContent>