mirror of
https://github.com/langgenius/dify.git
synced 2025-10-29 18:03:13 +00:00
Merge branch 'main' into feat/rag-pipeline
This commit is contained in:
commit
c4169f8aa0
@ -2,12 +2,14 @@ from collections.abc import Callable
|
||||
from functools import wraps
|
||||
from typing import Optional
|
||||
|
||||
from flask import request
|
||||
from flask import current_app, request
|
||||
from flask_login import user_logged_in
|
||||
from flask_restful import reqparse
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from extensions.ext_database import db
|
||||
from libs.login import _get_user
|
||||
from models.account import Account, Tenant
|
||||
from models.model import EndUser
|
||||
from services.account_service import AccountService
|
||||
@ -80,7 +82,12 @@ def get_user_tenant(view: Optional[Callable] = None):
|
||||
raise ValueError("tenant not found")
|
||||
|
||||
kwargs["tenant_model"] = tenant_model
|
||||
kwargs["user_model"] = get_user(tenant_id, user_id)
|
||||
|
||||
user = get_user(tenant_id, user_id)
|
||||
kwargs["user_model"] = user
|
||||
|
||||
current_app.login_manager._update_request_context_with_user(user) # type: ignore
|
||||
user_logged_in.send(current_app._get_current_object(), user=_get_user()) # type: ignore
|
||||
|
||||
return view_func(*args, **kwargs)
|
||||
|
||||
|
||||
@ -455,8 +455,6 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline, MessageCycleMan
|
||||
agent_thought: Optional[MessageAgentThought] = (
|
||||
db.session.query(MessageAgentThought).filter(MessageAgentThought.id == event.agent_thought_id).first()
|
||||
)
|
||||
db.session.refresh(agent_thought)
|
||||
db.session.close()
|
||||
|
||||
if agent_thought:
|
||||
return AgentThoughtStreamResponse(
|
||||
|
||||
@ -356,7 +356,9 @@ class AgentNode(ToolNode):
|
||||
|
||||
def _remove_unsupported_model_features_for_old_version(self, model_schema: AIModelEntity) -> AIModelEntity:
|
||||
if model_schema.features:
|
||||
for feature in model_schema.features:
|
||||
if feature.value not in AgentOldVersionModelFeatures:
|
||||
for feature in model_schema.features[:]: # Create a copy to safely modify during iteration
|
||||
try:
|
||||
AgentOldVersionModelFeatures(feature.value) # Try to create enum member from value
|
||||
except ValueError:
|
||||
model_schema.features.remove(feature)
|
||||
return model_schema
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from enum import Enum
|
||||
from enum import Enum, StrEnum
|
||||
from typing import Any, Literal, Union
|
||||
|
||||
from pydantic import BaseModel
|
||||
@ -26,7 +26,7 @@ class ParamsAutoGenerated(Enum):
|
||||
OPEN = 1
|
||||
|
||||
|
||||
class AgentOldVersionModelFeatures(Enum):
|
||||
class AgentOldVersionModelFeatures(StrEnum):
|
||||
"""
|
||||
Enum class for old SDK version llm feature.
|
||||
"""
|
||||
|
||||
@ -235,6 +235,10 @@ class Executor:
|
||||
files[key].append(file_tuple)
|
||||
|
||||
# convert files to list for httpx request
|
||||
# If there are no actual files, we still need to force httpx to use `multipart/form-data`.
|
||||
# This is achieved by inserting a harmless placeholder file that will be ignored by the server.
|
||||
if not files:
|
||||
self.files = [("__multipart_placeholder__", ("", b"", "application/octet-stream"))]
|
||||
if files:
|
||||
self.files = []
|
||||
for key, file_tuples in files.items():
|
||||
@ -373,7 +377,10 @@ class Executor:
|
||||
raw += f"{k}: {v}\r\n"
|
||||
|
||||
body_string = ""
|
||||
if self.files:
|
||||
# Only log actual files if present.
|
||||
# '__multipart_placeholder__' is inserted to force multipart encoding but is not a real file.
|
||||
# This prevents logging meaningless placeholder entries.
|
||||
if self.files and not all(f[0] == "__multipart_placeholder__" for f in self.files):
|
||||
for key, (filename, content, mime_type) in self.files:
|
||||
body_string += f"--{boundary}\r\n"
|
||||
body_string += f'Content-Disposition: form-data; name="{key}"\r\n\r\n'
|
||||
|
||||
@ -149,6 +149,7 @@ dev = [
|
||||
"types-tqdm~=4.67.0",
|
||||
"types-ujson~=5.10.0",
|
||||
"boto3-stubs>=1.38.20",
|
||||
"types-jmespath>=1.0.2.20240106",
|
||||
]
|
||||
|
||||
############################################################
|
||||
|
||||
@ -246,7 +246,9 @@ def test_executor_with_form_data():
|
||||
assert "multipart/form-data" in executor.headers["Content-Type"]
|
||||
assert executor.params == []
|
||||
assert executor.json is None
|
||||
assert executor.files is None
|
||||
# '__multipart_placeholder__' is expected when no file inputs exist,
|
||||
# to ensure the request is treated as multipart/form-data by the backend.
|
||||
assert executor.files == [("__multipart_placeholder__", ("", b"", "application/octet-stream"))]
|
||||
assert executor.content is None
|
||||
|
||||
# Check that the form data is correctly loaded in executor.data
|
||||
|
||||
11
api/uv.lock
generated
11
api/uv.lock
generated
@ -1315,6 +1315,7 @@ dev = [
|
||||
{ name = "types-gevent" },
|
||||
{ name = "types-greenlet" },
|
||||
{ name = "types-html5lib" },
|
||||
{ name = "types-jmespath" },
|
||||
{ name = "types-jsonschema" },
|
||||
{ name = "types-markdown" },
|
||||
{ name = "types-oauthlib" },
|
||||
@ -1486,6 +1487,7 @@ dev = [
|
||||
{ name = "types-gevent", specifier = "~=24.11.0" },
|
||||
{ name = "types-greenlet", specifier = "~=3.1.0" },
|
||||
{ name = "types-html5lib", specifier = "~=1.1.11" },
|
||||
{ name = "types-jmespath", specifier = ">=1.0.2.20240106" },
|
||||
{ name = "types-jsonschema", specifier = "~=4.23.0" },
|
||||
{ name = "types-markdown", specifier = "~=3.7.0" },
|
||||
{ name = "types-oauthlib", specifier = "~=3.2.0" },
|
||||
@ -5726,6 +5728,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/7c/f862b1dc31268ef10fe95b43dcdf216ba21a592fafa2d124445cd6b92e93/types_html5lib-1.1.11.20241018-py3-none-any.whl", hash = "sha256:3f1e064d9ed2c289001ae6392c84c93833abb0816165c6ff0abfc304a779f403", size = 17292 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "types-jmespath"
|
||||
version = "1.0.2.20240106"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1b/e4/1f7414dbca03975f66f1ab1b3f7b3deb7c19b104ef14dd3c99036bbc39b2/types-jmespath-1.0.2.20240106.tar.gz", hash = "sha256:b4a65a116bfc1c700a4fd9d24e2e397f4a431122e0320a77b7f1989a6b5d819e", size = 5071 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/30/3d6443f782601dd88820ba31e7668abfec7e19d685ac7f6fbcfd6ebba519/types_jmespath-1.0.2.20240106-py3-none-any.whl", hash = "sha256:c3e715fcaae9e5f8d74e14328fdedc4f2b3f0e18df17f3e457ae0a18e245bde0", size = 6087 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "types-jsonschema"
|
||||
version = "4.23.0.20241208"
|
||||
|
||||
@ -6,10 +6,12 @@ import Button from '../components/base/button'
|
||||
import Avatar from './avatar'
|
||||
import DifyLogo from '@/app/components/base/logo/dify-logo'
|
||||
import { useCallback } from 'react'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
|
||||
const Header = () => {
|
||||
const { t } = useTranslation()
|
||||
const router = useRouter()
|
||||
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
|
||||
|
||||
const back = useCallback(() => {
|
||||
router.back()
|
||||
@ -19,7 +21,13 @@ const Header = () => {
|
||||
<div className='flex flex-1 items-center justify-between px-4'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<div className='flex cursor-pointer items-center' onClick={back}>
|
||||
<DifyLogo />
|
||||
{systemFeatures.branding.enabled && systemFeatures.branding.login_page_logo
|
||||
? <img
|
||||
src={systemFeatures.branding.login_page_logo}
|
||||
className='block h-[22px] w-auto object-contain'
|
||||
alt='Dify logo'
|
||||
/>
|
||||
: <DifyLogo />}
|
||||
</div>
|
||||
<div className='h-4 w-[1px] origin-center rotate-[11.31deg] bg-divider-regular' />
|
||||
<p className='title-3xl-semi-bold relative mt-[-2px] text-text-primary'>{t('common.account.account')}</p>
|
||||
|
||||
@ -148,10 +148,12 @@ const Sidebar = ({ isPanel }: Props) => {
|
||||
'flex shrink-0 items-center gap-1.5 px-1',
|
||||
)}>
|
||||
<div className='system-2xs-medium-uppercase text-text-tertiary'>{t('share.chat.poweredBy')}</div>
|
||||
{systemFeatures.branding.enabled ? (
|
||||
<img src={systemFeatures.branding.login_page_logo} alt='logo' className='block h-5 w-auto' />
|
||||
) : (
|
||||
<DifyLogo size='small' />)
|
||||
{
|
||||
systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
|
||||
? <img src={systemFeatures.branding.workspace_logo} alt='logo' className='block h-5 w-auto' />
|
||||
: appData?.custom_config?.replace_webapp_logo
|
||||
? <img src={`${appData?.custom_config?.replace_webapp_logo}`} alt='logo' className='block h-5 w-auto' />
|
||||
: <DifyLogo size='small' />
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -13,6 +13,7 @@ import Divider from '@/app/components/base/divider'
|
||||
import ViewFormDropdown from '@/app/components/base/chat/embedded-chatbot/inputs-form/view-form-dropdown'
|
||||
import DifyLogo from '@/app/components/base/logo/dify-logo'
|
||||
import cn from '@/utils/classnames'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
|
||||
export type IHeaderProps = {
|
||||
isMobile?: boolean
|
||||
@ -42,6 +43,7 @@ const Header: FC<IHeaderProps> = ({
|
||||
const [parentOrigin, setParentOrigin] = useState('')
|
||||
const [showToggleExpandButton, setShowToggleExpandButton] = useState(false)
|
||||
const [expanded, setExpanded] = useState(false)
|
||||
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
|
||||
|
||||
const handleMessageReceived = useCallback((event: MessageEvent) => {
|
||||
let currentParentOrigin = parentOrigin
|
||||
@ -85,12 +87,13 @@ const Header: FC<IHeaderProps> = ({
|
||||
'flex shrink-0 items-center gap-1.5 px-2',
|
||||
)}>
|
||||
<div className='system-2xs-medium-uppercase text-text-tertiary'>{t('share.chat.poweredBy')}</div>
|
||||
{appData?.custom_config?.replace_webapp_logo && (
|
||||
<img src={appData?.custom_config?.replace_webapp_logo} alt='logo' className='block h-5 w-auto' />
|
||||
)}
|
||||
{!appData?.custom_config?.replace_webapp_logo && (
|
||||
<DifyLogo size='small' />
|
||||
)}
|
||||
{
|
||||
systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
|
||||
? <img src={systemFeatures.branding.workspace_logo} alt='logo' className='block h-5 w-auto' />
|
||||
: appData?.custom_config?.replace_webapp_logo
|
||||
? <img src={`${appData?.custom_config?.replace_webapp_logo}`} alt='logo' className='block h-5 w-auto' />
|
||||
: <DifyLogo size='small' />
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -22,6 +22,7 @@ import ChatWrapper from '@/app/components/base/chat/embedded-chatbot/chat-wrappe
|
||||
import DifyLogo from '@/app/components/base/logo/dify-logo'
|
||||
import cn from '@/utils/classnames'
|
||||
import useDocumentTitle from '@/hooks/use-document-title'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
|
||||
const Chatbot = () => {
|
||||
const {
|
||||
@ -37,6 +38,7 @@ const Chatbot = () => {
|
||||
themeBuilder,
|
||||
} = useEmbeddedChatbotContext()
|
||||
const { t } = useTranslation()
|
||||
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
|
||||
|
||||
const customConfig = appData?.custom_config
|
||||
const site = appData?.site
|
||||
@ -115,12 +117,13 @@ const Chatbot = () => {
|
||||
'flex shrink-0 items-center gap-1.5 px-2',
|
||||
)}>
|
||||
<div className='system-2xs-medium-uppercase text-text-tertiary'>{t('share.chat.poweredBy')}</div>
|
||||
{appData?.custom_config?.replace_webapp_logo && (
|
||||
<img src={appData?.custom_config?.replace_webapp_logo} alt='logo' className='block h-5 w-auto' />
|
||||
)}
|
||||
{!appData?.custom_config?.replace_webapp_logo && (
|
||||
<DifyLogo size='small' />
|
||||
)}
|
||||
{
|
||||
systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
|
||||
? <img src={systemFeatures.branding.workspace_logo} alt='logo' className='block h-5 w-auto' />
|
||||
: appData?.custom_config?.replace_webapp_logo
|
||||
? <img src={`${appData?.custom_config?.replace_webapp_logo}`} alt='logo' className='block h-5 w-auto' />
|
||||
: <DifyLogo size='small' />
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -3,7 +3,6 @@ import type { FC } from 'react'
|
||||
import classNames from '@/utils/classnames'
|
||||
import useTheme from '@/hooks/use-theme'
|
||||
import { basePath } from '@/utils/var'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
export type LogoStyle = 'default' | 'monochromeWhite'
|
||||
|
||||
export const logoPathMap: Record<LogoStyle, string> = {
|
||||
@ -32,18 +31,12 @@ const DifyLogo: FC<DifyLogoProps> = ({
|
||||
}) => {
|
||||
const { theme } = useTheme()
|
||||
const themedStyle = (theme === 'dark' && style === 'default') ? 'monochromeWhite' : style
|
||||
const { systemFeatures } = useGlobalPublicStore()
|
||||
const hasBrandingLogo = Boolean(systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo)
|
||||
|
||||
let src = `${basePath}${logoPathMap[themedStyle]}`
|
||||
if (hasBrandingLogo)
|
||||
src = systemFeatures.branding.workspace_logo
|
||||
|
||||
return (
|
||||
<img
|
||||
src={src}
|
||||
className={classNames('block object-contain', logoSizeMap[size], hasBrandingLogo && 'w-auto', className)}
|
||||
alt={hasBrandingLogo ? 'Logo' : 'Dify logo'}
|
||||
src={`${basePath}${logoPathMap[themedStyle]}`}
|
||||
className={classNames('block object-contain', logoSizeMap[size], className)}
|
||||
alt='Dify logo'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ const TabSlider: FC<TabSliderProps> = ({
|
||||
const newIndex = options.findIndex(option => option.value === value)
|
||||
setActiveIndex(newIndex)
|
||||
updateSliderStyle(newIndex)
|
||||
}, [value, options, pluginList])
|
||||
}, [value, options, pluginList?.total])
|
||||
|
||||
return (
|
||||
<div className={cn(className, 'relative inline-flex items-center justify-center rounded-[10px] bg-components-segmented-control-bg-normal p-0.5')}>
|
||||
@ -69,13 +69,13 @@ const TabSlider: FC<TabSliderProps> = ({
|
||||
{option.text}
|
||||
{/* if no plugin installed, the badge won't show */}
|
||||
{option.value === 'plugins'
|
||||
&& (pluginList?.plugins.length ?? 0) > 0
|
||||
&& (pluginList?.total ?? 0) > 0
|
||||
&& <Badge
|
||||
size='s'
|
||||
uppercase={true}
|
||||
state={BadgeState.Default}
|
||||
>
|
||||
{pluginList?.plugins.length}
|
||||
{pluginList?.total}
|
||||
</Badge>
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -24,6 +24,7 @@ import {
|
||||
} from '@/service/common'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import cn from '@/utils/classnames'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
|
||||
const ALLOW_FILE_EXTENSIONS = ['svg', 'png']
|
||||
|
||||
@ -39,6 +40,7 @@ const CustomWebAppBrand = () => {
|
||||
const [fileId, setFileId] = useState('')
|
||||
const [imgKey, setImgKey] = useState(Date.now())
|
||||
const [uploadProgress, setUploadProgress] = useState(0)
|
||||
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
|
||||
const isSandbox = enableBilling && plan.type === Plan.sandbox
|
||||
const uploading = uploadProgress > 0 && uploadProgress < 100
|
||||
const webappLogo = currentWorkspace.custom_config?.replace_webapp_logo || ''
|
||||
@ -244,9 +246,12 @@ const CustomWebAppBrand = () => {
|
||||
{!webappBrandRemoved && (
|
||||
<>
|
||||
<div className='system-2xs-medium-uppercase text-text-tertiary'>POWERED BY</div>
|
||||
{webappLogo
|
||||
? <img src={`${webappLogo}?hash=${imgKey}`} alt='logo' className='block h-5 w-auto' />
|
||||
: <DifyLogo size='small' />
|
||||
{
|
||||
systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
|
||||
? <img src={systemFeatures.branding.workspace_logo} alt='logo' className='block h-5 w-auto' />
|
||||
: webappLogo
|
||||
? <img src={`${webappLogo}?hash=${imgKey}`} alt='logo' className='block h-5 w-auto' />
|
||||
: <DifyLogo size='small' />
|
||||
}
|
||||
</>
|
||||
)}
|
||||
@ -303,9 +308,12 @@ const CustomWebAppBrand = () => {
|
||||
{!webappBrandRemoved && (
|
||||
<>
|
||||
<div className='system-2xs-medium-uppercase text-text-tertiary'>POWERED BY</div>
|
||||
{webappLogo
|
||||
? <img src={`${webappLogo}?hash=${imgKey}`} alt='logo' className='block h-5 w-auto' />
|
||||
: <DifyLogo size='small' />
|
||||
{
|
||||
systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
|
||||
? <img src={systemFeatures.branding.workspace_logo} alt='logo' className='block h-5 w-auto' />
|
||||
: webappLogo
|
||||
? <img src={`${webappLogo}?hash=${imgKey}`} alt='logo' className='block h-5 w-auto' />
|
||||
: <DifyLogo size='small' />
|
||||
}
|
||||
</>
|
||||
)}
|
||||
|
||||
@ -9,6 +9,7 @@ import type { LangGeniusVersionResponse } from '@/models/common'
|
||||
import { IS_CE_EDITION } from '@/config'
|
||||
import DifyLogo from '@/app/components/base/logo/dify-logo'
|
||||
import { noop } from 'lodash-es'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
|
||||
type IAccountSettingProps = {
|
||||
langeniusVersionInfo: LangGeniusVersionResponse
|
||||
@ -21,6 +22,7 @@ export default function AccountAbout({
|
||||
}: IAccountSettingProps) {
|
||||
const { t } = useTranslation()
|
||||
const isLatest = langeniusVersionInfo.current_version === langeniusVersionInfo.latest_version
|
||||
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@ -33,7 +35,14 @@ export default function AccountAbout({
|
||||
<RiCloseLine className='h-4 w-4 text-text-tertiary' />
|
||||
</div>
|
||||
<div className='flex flex-col items-center gap-4 py-8'>
|
||||
<DifyLogo size='large' className='mx-auto' />
|
||||
{systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
|
||||
? <img
|
||||
src={systemFeatures.branding.workspace_logo}
|
||||
className='block h-7 w-auto object-contain'
|
||||
alt='logo'
|
||||
/>
|
||||
: <DifyLogo size='large' className='mx-auto' />}
|
||||
|
||||
<div className='text-center text-xs font-normal text-text-tertiary'>Version {langeniusVersionInfo?.current_version}</div>
|
||||
<div className='flex flex-col items-center gap-2 text-center text-xs font-normal text-text-secondary'>
|
||||
<div>© {dayjs().year()} LangGenius, Inc., Contributors.</div>
|
||||
|
||||
@ -21,6 +21,7 @@ import { useModalContext } from '@/context/modal-context'
|
||||
import PlanBadge from './plan-badge'
|
||||
import LicenseNav from './license-env'
|
||||
import { Plan } from '../billing/type'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
|
||||
const navClassName = `
|
||||
flex items-center relative mr-0 sm:mr-3 px-3 h-8 rounded-xl
|
||||
@ -36,6 +37,7 @@ const Header = () => {
|
||||
const [isShowNavMenu, { toggle, setFalse: hideNavMenu }] = useBoolean(false)
|
||||
const { enableBilling, plan } = useProviderContext()
|
||||
const { setShowPricingModal, setShowAccountSettingModal } = useModalContext()
|
||||
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
|
||||
const isFreePlan = plan.type === Plan.sandbox
|
||||
const handlePlanClick = useCallback(() => {
|
||||
if (isFreePlan)
|
||||
@ -61,7 +63,13 @@ const Header = () => {
|
||||
!isMobile
|
||||
&& <div className='flex shrink-0 items-center gap-1.5 self-stretch pl-3'>
|
||||
<Link href="/apps" className='flex h-8 shrink-0 items-center justify-center gap-2 px-0.5'>
|
||||
<DifyLogo />
|
||||
{systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
|
||||
? <img
|
||||
src={systemFeatures.branding.workspace_logo}
|
||||
className='block h-[22px] w-auto object-contain'
|
||||
alt='logo'
|
||||
/>
|
||||
: <DifyLogo />}
|
||||
</Link>
|
||||
<div className='font-light text-divider-deep'>/</div>
|
||||
<div className='flex items-center gap-0.5'>
|
||||
@ -76,7 +84,13 @@ const Header = () => {
|
||||
{isMobile && (
|
||||
<div className='flex'>
|
||||
<Link href="/apps" className='mr-4 flex items-center'>
|
||||
<DifyLogo />
|
||||
{systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
|
||||
? <img
|
||||
src={systemFeatures.branding.workspace_logo}
|
||||
className='block h-[22px] w-auto object-contain'
|
||||
alt='logo'
|
||||
/>
|
||||
: <DifyLogo />}
|
||||
</Link>
|
||||
<div className='font-light text-divider-deep'>/</div>
|
||||
{enableBilling ? <PlanBadge allowHover sandboxAsUpgrade plan={plan.type} onClick={handlePlanClick} /> : <LicenseNav />}
|
||||
|
||||
@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import type { FilterState } from './filter-management'
|
||||
import FilterManagement from './filter-management'
|
||||
import List from './list'
|
||||
import { useInstalledLatestVersion, useInstalledPluginListWithPagination, useInvalidateInstalledPluginList } from '@/service/use-plugins'
|
||||
import { useInstalledLatestVersion, useInstalledPluginList, useInvalidateInstalledPluginList } from '@/service/use-plugins'
|
||||
import PluginDetailPanel from '@/app/components/plugins/plugin-detail-panel'
|
||||
import { usePluginPageContext } from './context'
|
||||
import { useDebounceFn } from 'ahooks'
|
||||
@ -17,7 +17,7 @@ const PluginsPanel = () => {
|
||||
const { t } = useTranslation()
|
||||
const filters = usePluginPageContext(v => v.filters) as FilterState
|
||||
const setFilters = usePluginPageContext(v => v.setFilters)
|
||||
const { data: pluginList, isLoading: isPluginListLoading, isFetching, isLastPage, loadNextPage } = useInstalledPluginListWithPagination()
|
||||
const { data: pluginList, isLoading: isPluginListLoading, isFetching, isLastPage, loadNextPage } = useInstalledPluginList()
|
||||
const { data: installedLatestVersion } = useInstalledLatestVersion(
|
||||
pluginList?.plugins
|
||||
.filter(plugin => plugin.source === PluginSource.marketplace)
|
||||
|
||||
@ -641,11 +641,13 @@ const TextGeneration: FC<IMainProps> = ({
|
||||
!isPC && resultExisted && 'rounded-b-2xl border-b-[0.5px] border-divider-regular',
|
||||
)}>
|
||||
<div className='system-2xs-medium-uppercase text-text-tertiary'>{t('share.chat.poweredBy')}</div>
|
||||
{systemFeatures.branding.enabled ? (
|
||||
<img src={systemFeatures.branding.login_page_logo} alt='logo' className='block h-5 w-auto' />
|
||||
) : (
|
||||
<DifyLogo size='small' />
|
||||
)}
|
||||
{
|
||||
systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
|
||||
? <img src={systemFeatures.branding.workspace_logo} alt='logo' className='block h-5 w-auto' />
|
||||
: customConfig?.replace_webapp_logo
|
||||
? <img src={`${customConfig?.replace_webapp_logo}`} alt='logo' className='block h-5 w-auto' />
|
||||
: <DifyLogo size='small' />
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -105,7 +105,7 @@ const ChangePasswordForm = () => {
|
||||
</div>
|
||||
|
||||
<div className="mx-auto mt-6 w-full">
|
||||
<div className="bg-white">
|
||||
<div>
|
||||
{/* Password */}
|
||||
<div className='mb-5'>
|
||||
<label htmlFor="password" className="system-md-semibold my-2 text-text-secondary">
|
||||
|
||||
@ -7,6 +7,7 @@ import { languages } from '@/i18n/language'
|
||||
import type { Locale } from '@/i18n'
|
||||
import I18n from '@/context/i18n'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
|
||||
// Avoid rendering the logo and theme selector on the server
|
||||
const DifyLogo = dynamic(() => import('@/app/components/base/logo/dify-logo'), {
|
||||
@ -20,10 +21,17 @@ const ThemeSelector = dynamic(() => import('@/app/components/base/theme-selector
|
||||
|
||||
const Header = () => {
|
||||
const { locale, setLocaleOnClient } = useContext(I18n)
|
||||
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
|
||||
|
||||
return (
|
||||
<div className='flex w-full items-center justify-between p-6'>
|
||||
<DifyLogo size='large' />
|
||||
{systemFeatures.branding.enabled && systemFeatures.branding.login_page_logo
|
||||
? <img
|
||||
src={systemFeatures.branding.login_page_logo}
|
||||
className='block h-7 w-auto object-contain'
|
||||
alt='logo'
|
||||
/>
|
||||
: <DifyLogo size='large' />}
|
||||
<div className='flex items-center gap-1'>
|
||||
<Select
|
||||
value={locale}
|
||||
|
||||
@ -645,9 +645,9 @@ const translation = {
|
||||
perPage: '페이지당 항목 수',
|
||||
},
|
||||
theme: {
|
||||
theme: '주제',
|
||||
light: '빛',
|
||||
dark: '어둠',
|
||||
theme: '테마',
|
||||
light: '밝은',
|
||||
dark: '어두운',
|
||||
auto: '시스템',
|
||||
},
|
||||
compliance: {
|
||||
|
||||
@ -301,7 +301,7 @@ const translation = {
|
||||
designDocument: '디자인 문서',
|
||||
productSpecification: '제품 사양서',
|
||||
financialReport: '재무 보고서',
|
||||
marketAnalysis: '시장 분석',
|
||||
marketAnalysis: '마켓 분석',
|
||||
projectPlan: '프로젝트 계획서',
|
||||
teamStructure: '팀 구조',
|
||||
policiesProcedures: '정책 및 절차',
|
||||
|
||||
@ -194,7 +194,7 @@ const translation = {
|
||||
datasetMetadata: {
|
||||
name: '이름',
|
||||
deleteTitle: '삭제 확인',
|
||||
disabled: '장애인',
|
||||
disabled: '사용안함',
|
||||
addMetaData: '메타데이터 추가',
|
||||
values: '{{num}} 값들',
|
||||
namePlaceholder: '메타데이터 이름',
|
||||
|
||||
@ -25,7 +25,7 @@ const translation = {
|
||||
},
|
||||
source: {
|
||||
local: '로컬 패키지 파일',
|
||||
marketplace: '시장',
|
||||
marketplace: '마켓',
|
||||
github: '깃허브',
|
||||
},
|
||||
detailPanel: {
|
||||
@ -197,7 +197,7 @@ const translation = {
|
||||
endpointsEnabled: '{{num}}개의 엔드포인트 집합이 활성화되었습니다.',
|
||||
installFrom: '에서 설치',
|
||||
allCategories: '모든 카테고리',
|
||||
submitPlugin: '제출 플러그인',
|
||||
submitPlugin: '플러그인 제출',
|
||||
findMoreInMarketplace: 'Marketplace에서 더 알아보기',
|
||||
searchCategories: '검색 카테고리',
|
||||
search: '검색',
|
||||
|
||||
@ -200,7 +200,7 @@ const translation = {
|
||||
code: '코드',
|
||||
model: '모델',
|
||||
rerankModel: '재정렬 모델',
|
||||
visionVariable: '시력 변수',
|
||||
visionVariable: '비전 변수',
|
||||
},
|
||||
invalidVariable: '잘못된 변수',
|
||||
rerankModelRequired: 'Rerank Model을 켜기 전에 설정에서 모델이 성공적으로 구성되었는지 확인하십시오.',
|
||||
@ -463,7 +463,7 @@ const translation = {
|
||||
metadata: {
|
||||
options: {
|
||||
disabled: {
|
||||
title: '장애인',
|
||||
title: '사용안함',
|
||||
subTitle: '메타데이터 필터링을 활성화하지 않음',
|
||||
},
|
||||
automatic: {
|
||||
|
||||
@ -10,7 +10,6 @@ import type {
|
||||
GitHubItemAndMarketPlaceDependency,
|
||||
InstallPackageResponse,
|
||||
InstalledLatestVersionResponse,
|
||||
InstalledPluginListResponse,
|
||||
InstalledPluginListWithTotalResponse,
|
||||
PackageDependency,
|
||||
Permissions,
|
||||
@ -67,16 +66,7 @@ export const useCheckInstalled = ({
|
||||
})
|
||||
}
|
||||
|
||||
export const useInstalledPluginList = (disable?: boolean) => {
|
||||
return useQuery<InstalledPluginListResponse>({
|
||||
queryKey: useInstalledPluginListKey,
|
||||
queryFn: () => get<InstalledPluginListResponse>('/workspaces/current/plugin/list'),
|
||||
enabled: !disable,
|
||||
initialData: !disable ? undefined : { plugins: [] },
|
||||
})
|
||||
}
|
||||
|
||||
export const useInstalledPluginListWithPagination = (pageSize = 100) => {
|
||||
export const useInstalledPluginList = (disable?: boolean, pageSize = 100) => {
|
||||
const fetchPlugins = async ({ pageParam = 1 }) => {
|
||||
const response = await get<InstalledPluginListWithTotalResponse>(
|
||||
`/workspaces/current/plugin/list?page=${pageParam}&page_size=${pageSize}`,
|
||||
@ -91,8 +81,10 @@ export const useInstalledPluginListWithPagination = (pageSize = 100) => {
|
||||
hasNextPage,
|
||||
isFetchingNextPage,
|
||||
isLoading,
|
||||
isSuccess,
|
||||
} = useInfiniteQuery({
|
||||
queryKey: ['installed-plugins', pageSize],
|
||||
enabled: !disable,
|
||||
queryKey: useInstalledPluginListKey,
|
||||
queryFn: fetchPlugins,
|
||||
getNextPageParam: (lastPage, pages) => {
|
||||
const totalItems = lastPage.total
|
||||
@ -108,10 +100,12 @@ export const useInstalledPluginListWithPagination = (pageSize = 100) => {
|
||||
})
|
||||
|
||||
const plugins = data?.pages.flatMap(page => page.plugins) ?? []
|
||||
const total = data?.pages[0].total ?? 0
|
||||
|
||||
return {
|
||||
data: {
|
||||
data: disable ? undefined : {
|
||||
plugins,
|
||||
total,
|
||||
},
|
||||
isLastPage: !hasNextPage,
|
||||
loadNextPage: () => {
|
||||
@ -120,6 +114,7 @@ export const useInstalledPluginListWithPagination = (pageSize = 100) => {
|
||||
isLoading,
|
||||
isFetching: isFetchingNextPage,
|
||||
error,
|
||||
isSuccess,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user