Merge branch 'main' into feat/rag-pipeline

pull/21398/head
twwu 1 year ago
commit e04ae927b6

@ -245,6 +245,13 @@ class Workflow(Base):
@property @property
def tool_published(self) -> bool: def tool_published(self) -> bool:
"""
DEPRECATED: This property is not accurate for determining if a workflow is published as a tool.
It only checks if there's a WorkflowToolProvider for the app, not if this specific workflow version
is the one being used by the tool.
For accurate checking, use a direct query with tenant_id, app_id, and version.
"""
from models.tools import WorkflowToolProvider from models.tools import WorkflowToolProvider
return ( return (

@ -28,6 +28,7 @@ from extensions.ext_database import db
from models.account import Account from models.account import Account
from models.enums import CreatedByRole from models.enums import CreatedByRole
from models.model import App, AppMode from models.model import App, AppMode
from models.tools import WorkflowToolProvider
from models.workflow import ( from models.workflow import (
Workflow, Workflow,
WorkflowNodeExecution, WorkflowNodeExecution,
@ -523,8 +524,19 @@ class WorkflowService:
# Cannot delete a workflow that's currently in use by an app # Cannot delete a workflow that's currently in use by an app
raise WorkflowInUseError(f"Cannot delete workflow that is currently in use by app '{app.name}'") raise WorkflowInUseError(f"Cannot delete workflow that is currently in use by app '{app.name}'")
# Check if this workflow is published as a tool # Don't use workflow.tool_published as it's not accurate for specific workflow versions
if workflow.tool_published: # Check if there's a tool provider using this specific workflow version
tool_provider = (
session.query(WorkflowToolProvider)
.filter(
WorkflowToolProvider.tenant_id == workflow.tenant_id,
WorkflowToolProvider.app_id == workflow.app_id,
WorkflowToolProvider.version == workflow.version,
)
.first()
)
if tool_provider:
# Cannot delete a workflow that's published as a tool # Cannot delete a workflow that's published as a tool
raise WorkflowInUseError("Cannot delete workflow that is published as a tool") raise WorkflowInUseError("Cannot delete workflow that is published as a tool")

@ -40,6 +40,10 @@ def workflow_setup():
def test_delete_workflow_success(workflow_setup): def test_delete_workflow_success(workflow_setup):
# Setup mocks # Setup mocks
# Mock the tool provider query to return None (not published as a tool)
workflow_setup["session"].query.return_value.filter.return_value.first.return_value = None
workflow_setup["session"].scalar = MagicMock( workflow_setup["session"].scalar = MagicMock(
side_effect=[workflow_setup["workflow"], None] side_effect=[workflow_setup["workflow"], None]
) # Return workflow first, then None for app ) # Return workflow first, then None for app
@ -97,7 +101,12 @@ def test_delete_workflow_in_use_by_app_error(workflow_setup):
def test_delete_workflow_published_as_tool_error(workflow_setup): def test_delete_workflow_published_as_tool_error(workflow_setup):
# Setup mocks # Setup mocks
workflow_setup["workflow"].tool_published = True from models.tools import WorkflowToolProvider
# Mock the tool provider query
mock_tool_provider = MagicMock(spec=WorkflowToolProvider)
workflow_setup["session"].query.return_value.filter.return_value.first.return_value = mock_tool_provider
workflow_setup["session"].scalar = MagicMock( workflow_setup["session"].scalar = MagicMock(
side_effect=[workflow_setup["workflow"], None] side_effect=[workflow_setup["workflow"], None]
) # Return workflow first, then None for app ) # Return workflow first, then None for app

@ -163,7 +163,7 @@ const SettingBuiltInTool: FC<Props> = ({
footer={null} footer={null}
mask={false} mask={false}
positionCenter={false} positionCenter={false}
panelClassname={cn('mb-2 mr-2 mt-[64px] !w-[420px] !max-w-[420px] justify-start rounded-2xl border-[0.5px] border-components-panel-border !bg-components-panel-bg !p-0 shadow-xl')} panelClassName={cn('mb-2 mr-2 mt-[64px] !w-[420px] !max-w-[420px] justify-start rounded-2xl border-[0.5px] border-components-panel-border !bg-components-panel-bg !p-0 shadow-xl')}
> >
<> <>
{isLoading && <Loading type='app' />} {isLoading && <Loading type='app' />}

@ -97,7 +97,7 @@ const Item: FC<ItemProps> = ({
<RiDeleteBinLine className='h-4 w-4' /> <RiDeleteBinLine className='h-4 w-4' />
</div> </div>
</div> </div>
<Drawer isOpen={showSettingsModal} onClose={() => setShowSettingsModal(false)} footer={null} mask={isMobile} panelClassname='mt-16 mx-2 sm:mr-2 mb-3 !p-0 !max-w-[640px] rounded-xl'> <Drawer isOpen={showSettingsModal} onClose={() => setShowSettingsModal(false)} footer={null} mask={isMobile} panelClassName='mt-16 mx-2 sm:mr-2 mb-3 !p-0 !max-w-[640px] rounded-xl'>
<SettingsModal <SettingsModal
currentDataset={config} currentDataset={config}
onCancel={() => setShowSettingsModal(false)} onCancel={() => setShowSettingsModal(false)}

@ -743,7 +743,7 @@ const ConversationList: FC<IConversationList> = ({ logs, appDetail, onRefresh })
onClose={onCloseDrawer} onClose={onCloseDrawer}
mask={isMobile} mask={isMobile}
footer={null} footer={null}
panelClassname='mt-16 mx-2 sm:mr-2 mb-4 !p-0 !max-w-[640px] rounded-xl bg-components-panel-bg' panelClassName='mt-16 mx-2 sm:mr-2 mb-4 !p-0 !max-w-[640px] rounded-xl bg-components-panel-bg'
> >
<DrawerContext.Provider value={{ <DrawerContext.Provider value={{
onClose: onCloseDrawer, onClose: onCloseDrawer,

@ -134,7 +134,7 @@ const WorkflowAppLogList: FC<ILogs> = ({ logs, appDetail, onRefresh }) => {
onClose={onCloseDrawer} onClose={onCloseDrawer}
mask={isMobile} mask={isMobile}
footer={null} footer={null}
panelClassname='mt-16 mx-2 sm:mr-2 mb-3 !p-0 !max-w-[600px] rounded-xl border border-components-panel-border' panelClassName='mt-16 mx-2 sm:mr-2 mb-3 !p-0 !max-w-[600px] rounded-xl border border-components-panel-border'
> >
<DetailPanel onClose={onCloseDrawer} runID={currentLog?.workflow_run.id || ''} /> <DetailPanel onClose={onCloseDrawer} runID={currentLog?.workflow_run.id || ''} />
</Drawer> </Drawer>

@ -9,6 +9,8 @@ import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
type Props = { type Props = {
isShow: boolean isShow: boolean
onHide: () => void onHide: () => void
dialogClassName?: string
dialogBackdropClassName?: string
panelClassName?: string panelClassName?: string
maxWidthClassName?: string maxWidthClassName?: string
contentClassName?: string contentClassName?: string
@ -26,6 +28,8 @@ type Props = {
const DrawerPlus: FC<Props> = ({ const DrawerPlus: FC<Props> = ({
isShow, isShow,
onHide, onHide,
dialogClassName = '',
dialogBackdropClassName = '',
panelClassName = '', panelClassName = '',
maxWidthClassName = '!max-w-[640px]', maxWidthClassName = '!max-w-[640px]',
height = 'calc(100vh - 72px)', height = 'calc(100vh - 72px)',
@ -55,7 +59,9 @@ const DrawerPlus: FC<Props> = ({
footer={null} footer={null}
mask={isMobile || isShowMask} mask={isMobile || isShowMask}
positionCenter={positionCenter} positionCenter={positionCenter}
panelClassname={cn('mx-2 mb-3 mt-16 rounded-xl !p-0 sm:mr-2', panelClassName, maxWidthClassName)} dialogClassName={dialogClassName}
dialogBackdropClassName={dialogBackdropClassName}
panelClassName={cn('mx-2 mb-3 mt-16 rounded-xl !p-0 sm:mr-2', panelClassName, maxWidthClassName)}
> >
<div <div
className={cn(contentClassName, 'flex w-full flex-col rounded-xl border-[0.5px] border-divider-subtle bg-components-panel-bg shadow-xl')} className={cn(contentClassName, 'flex w-full flex-col rounded-xl border-[0.5px] border-divider-subtle bg-components-panel-bg shadow-xl')}

@ -8,7 +8,9 @@ import cn from '@/utils/classnames'
export type IDrawerProps = { export type IDrawerProps = {
title?: string title?: string
description?: string description?: string
panelClassname?: string dialogClassName?: string
dialogBackdropClassName?: string
panelClassName?: string
children: React.ReactNode children: React.ReactNode
footer?: React.ReactNode footer?: React.ReactNode
mask?: boolean mask?: boolean
@ -25,7 +27,9 @@ export type IDrawerProps = {
export default function Drawer({ export default function Drawer({
title = '', title = '',
description = '', description = '',
panelClassname = '', dialogClassName = '',
dialogBackdropClassName = '',
panelClassName = '',
children, children,
footer, footer,
mask = true, mask = true,
@ -44,17 +48,17 @@ export default function Drawer({
unmount={unmount} unmount={unmount}
open={isOpen} open={isOpen}
onClose={() => !clickOutsideNotOpen && onClose()} onClose={() => !clickOutsideNotOpen && onClose()}
className="fixed inset-0 z-[80] overflow-y-auto" className={cn('fixed inset-0 z-[30] overflow-y-auto', dialogClassName)}
> >
<div className={cn('flex h-screen w-screen justify-end', positionCenter && '!justify-center')}> <div className={cn('flex h-screen w-screen justify-end', positionCenter && '!justify-center')}>
{/* mask */} {/* mask */}
<DialogBackdrop <DialogBackdrop
className={cn('fixed inset-0 z-[90]', mask && 'bg-black bg-opacity-30')} className={cn('fixed inset-0 z-[40]', mask && 'bg-black/30', dialogBackdropClassName)}
onClick={() => { onClick={() => {
!clickOutsideNotOpen && onClose() !clickOutsideNotOpen && onClose()
}} }}
/> />
<div className={cn('relative z-[100] flex w-full max-w-sm flex-col justify-between overflow-hidden bg-components-panel-bg p-6 text-left align-middle shadow-xl', panelClassname)}> <div className={cn('relative z-[50] flex w-full max-w-sm flex-col justify-between overflow-hidden bg-components-panel-bg p-6 text-left align-middle shadow-xl', panelClassName)}>
<> <>
<div className='flex justify-between'> <div className='flex justify-between'>
{title && <DialogTitle {title && <DialogTitle

@ -252,7 +252,7 @@ const Img = ({ src }: any) => {
return <div className="markdown-img-wrapper"><ImageGallery srcs={[src]} /></div> return <div className="markdown-img-wrapper"><ImageGallery srcs={[src]} /></div>
} }
const Link = ({ node, ...props }: any) => { const Link = ({ node, children, ...props }: any) => {
if (node.properties?.href && node.properties.href?.toString().startsWith('abbr')) { if (node.properties?.href && node.properties.href?.toString().startsWith('abbr')) {
// eslint-disable-next-line react-hooks/rules-of-hooks // eslint-disable-next-line react-hooks/rules-of-hooks
const { onSend } = useChatContext() const { onSend } = useChatContext()
@ -261,7 +261,7 @@ const Link = ({ node, ...props }: any) => {
return <abbr className="cursor-pointer underline !decoration-primary-700 decoration-dashed" onClick={() => onSend?.(hidden_text)} title={node.children[0]?.value}>{node.children[0]?.value}</abbr> return <abbr className="cursor-pointer underline !decoration-primary-700 decoration-dashed" onClick={() => onSend?.(hidden_text)} title={node.children[0]?.value}>{node.children[0]?.value}</abbr>
} }
else { else {
return <a {...props} target="_blank" className="cursor-pointer underline !decoration-primary-700 decoration-dashed">{node.children[0] ? node.children[0]?.value : 'Download'}</a> return <a {...props} target="_blank" className="cursor-pointer underline !decoration-primary-700 decoration-dashed">{children || 'Download'}</a>
} }
} }

@ -20,7 +20,7 @@ const FullScreenDrawer: FC<IFullScreenDrawerProps> = ({
<Drawer <Drawer
isOpen={isOpen} isOpen={isOpen}
onClose={onClose} onClose={onClose}
panelClassname={classNames('!p-0 bg-components-panel-bg', panelClassName={classNames('!p-0 bg-components-panel-bg',
fullScreen fullScreen
? '!max-w-full !w-full' ? '!max-w-full !w-full'
: 'mt-16 mr-2 mb-2 !max-w-[560px] !w-[560px] border-[0.5px] border-components-panel-border rounded-xl', : 'mt-16 mr-2 mb-2 !max-w-[560px] !w-[560px] border-[0.5px] border-components-panel-border rounded-xl',

@ -277,7 +277,7 @@ const DocumentDetail: FC<Props> = ({ datasetId, documentId }) => {
} }
</div> </div>
} }
<FloatRightContainer showClose isOpen={showMetadata} onClose={() => setShowMetadata(false)} isMobile={isMobile} panelClassname='!justify-start' footer={null}> <FloatRightContainer showClose isOpen={showMetadata} onClose={() => setShowMetadata(false)} isMobile={isMobile} panelClassName='!justify-start' footer={null}>
<Metadata <Metadata
className='mr-2 mt-3' className='mr-2 mt-3'
datasetId={datasetId} datasetId={datasetId}

@ -29,6 +29,8 @@ import { useChildSegmentListKey, useSegmentListKey } from '@/service/knowledge/u
import useEditDocumentMetadata from '../metadata/hooks/use-edit-dataset-metadata' import useEditDocumentMetadata from '../metadata/hooks/use-edit-dataset-metadata'
import DatasetMetadataDrawer from '../metadata/metadata-dataset/dataset-metadata-drawer' import DatasetMetadataDrawer from '../metadata/metadata-dataset/dataset-metadata-drawer'
import StatusWithAction from '../common/document-status-with-action/status-with-action' import StatusWithAction from '../common/document-status-with-action/status-with-action'
import { LanguagesSupported } from '@/i18n/language'
import { getLocaleOnClient } from '@/i18n'
const FolderPlusIcon = ({ className }: React.SVGProps<SVGElement>) => { const FolderPlusIcon = ({ className }: React.SVGProps<SVGElement>) => {
return <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}> return <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}>
@ -98,7 +100,7 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
const isDataSourceWeb = dataset?.data_source_type === DataSourceType.WEB const isDataSourceWeb = dataset?.data_source_type === DataSourceType.WEB
const isDataSourceFile = dataset?.data_source_type === DataSourceType.FILE const isDataSourceFile = dataset?.data_source_type === DataSourceType.FILE
const embeddingAvailable = !!dataset?.embedding_available const embeddingAvailable = !!dataset?.embedding_available
const locale = getLocaleOnClient()
const debouncedSearchValue = useDebounce(searchValue, { wait: 500 }) const debouncedSearchValue = useDebounce(searchValue, { wait: 500 })
const { data: documentsRes, isFetching: isListLoading } = useDocumentList({ const { data: documentsRes, isFetching: isListLoading } = useDocumentList({
@ -260,7 +262,12 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
<a <a
className='flex items-center text-text-accent' className='flex items-center text-text-accent'
target='_blank' target='_blank'
href='https://docs.dify.ai/guides/knowledge-base/integrate-knowledge-within-application'> href={
locale === LanguagesSupported[1]
? 'https://docs.dify.ai/v/zh-hans/guides/knowledge-base/integrate-knowledge-within-application'
: 'https://docs.dify.ai/guides/knowledge-base/integrate-knowledge-within-application'
}
>
<span>{t('datasetDocuments.list.learnMore')}</span> <span>{t('datasetDocuments.list.learnMore')}</span>
<RiExternalLinkLine className='h-3 w-3' /> <RiExternalLinkLine className='h-3 w-3' />
</a> </a>

@ -176,7 +176,7 @@ const HitTestingPage: FC<Props> = ({ datasetId }: Props) => {
<RecordsEmpty /> <RecordsEmpty />
)} )}
</div> </div>
<FloatRightContainer panelClassname='!justify-start !overflow-y-auto' showClose isMobile={isMobile} isOpen={isShowRightPanel} onClose={hideRightPanel} footer={null}> <FloatRightContainer panelClassName='!justify-start !overflow-y-auto' showClose isMobile={isMobile} isOpen={isShowRightPanel} onClose={hideRightPanel} footer={null}>
<div className='flex flex-col pt-3'> <div className='flex flex-col pt-3'>
{/* {renderHitResults(generalResultData)} */} {/* {renderHitResults(generalResultData)} */}
{submitLoading {submitLoading
@ -197,7 +197,7 @@ const HitTestingPage: FC<Props> = ({ datasetId }: Props) => {
} }
</div> </div>
</FloatRightContainer> </FloatRightContainer>
<Drawer unmount={true} isOpen={isShowModifyRetrievalModal} onClose={() => setIsShowModifyRetrievalModal(false)} footer={null} mask={isMobile} panelClassname='mt-16 mx-2 sm:mr-2 mb-3 !p-0 !max-w-[640px] rounded-xl'> <Drawer unmount={true} isOpen={isShowModifyRetrievalModal} onClose={() => setIsShowModifyRetrievalModal(false)} footer={null} mask={isMobile} panelClassName='mt-16 mx-2 sm:mr-2 mb-3 !p-0 !max-w-[640px] rounded-xl'>
<ModifyRetrievalModal <ModifyRetrievalModal
indexMethod={currentDataset?.indexing_technique || ''} indexMethod={currentDataset?.indexing_technique || ''}
value={retrievalConfig} value={retrievalConfig}

@ -173,7 +173,7 @@ const DatasetMetadataDrawer: FC<Props> = ({
showClose showClose
title={t('dataset.metadata.metadata')} title={t('dataset.metadata.metadata')}
footer={null} footer={null}
panelClassname='px-4 block !max-w-[420px] my-2 rounded-l-2xl' panelClassName='px-4 block !max-w-[420px] my-2 rounded-l-2xl'
> >
<div className='h-full overflow-y-auto'> <div className='h-full overflow-y-auto'>
<div className='system-sm-regular text-text-tertiary'>{t(`${i18nPrefix}.description`)}</div> <div className='system-sm-regular text-text-tertiary'>{t(`${i18nPrefix}.description`)}</div>

@ -32,7 +32,9 @@ const ListWithCollection = ({
return ( return (
<> <>
{ {
marketplaceCollections.map(collection => ( marketplaceCollections.filter((collection) => {
return marketplaceCollectionPluginsMap[collection.name]?.length
}).map(collection => (
<div <div
key={collection.name} key={collection.name}
className='py-3' className='py-3'

@ -46,7 +46,7 @@ const EndpointModal: FC<Props> = ({
footer={null} footer={null}
mask mask
positionCenter={false} positionCenter={false}
panelClassname={cn('mb-2 mr-2 mt-[64px] !w-[420px] !max-w-[420px] justify-start rounded-2xl border-[0.5px] border-components-panel-border !bg-components-panel-bg !p-0 shadow-xl')} panelClassName={cn('mb-2 mr-2 mt-[64px] !w-[420px] !max-w-[420px] justify-start rounded-2xl border-[0.5px] border-components-panel-border !bg-components-panel-bg !p-0 shadow-xl')}
> >
<> <>
<div className='p-4 pb-2'> <div className='p-4 pb-2'>

@ -38,7 +38,7 @@ const PluginDetailPanel: FC<Props> = ({
footer={null} footer={null}
mask={false} mask={false}
positionCenter={false} positionCenter={false}
panelClassname={cn('mb-2 mr-2 mt-[64px] !w-[420px] !max-w-[420px] justify-start rounded-2xl border-[0.5px] border-components-panel-border !bg-components-panel-bg !p-0 shadow-xl')} panelClassName={cn('mb-2 mr-2 mt-[64px] !w-[420px] !max-w-[420px] justify-start rounded-2xl border-[0.5px] border-components-panel-border !bg-components-panel-bg !p-0 shadow-xl')}
> >
{detail && ( {detail && (
<> <>

@ -78,7 +78,7 @@ const StrategyDetail: FC<Props> = ({
footer={null} footer={null}
mask={false} mask={false}
positionCenter={false} positionCenter={false}
panelClassname={cn('mb-2 mr-2 mt-[64px] !w-[420px] !max-w-[420px] justify-start rounded-2xl border-[0.5px] border-components-panel-border !bg-components-panel-bg !p-0 shadow-xl')} panelClassName={cn('mb-2 mr-2 mt-[64px] !w-[420px] !max-w-[420px] justify-start rounded-2xl border-[0.5px] border-components-panel-border !bg-components-panel-bg !p-0 shadow-xl')}
> >
<> <>
{/* header */} {/* header */}

@ -178,7 +178,7 @@ const AddToolModal: FC<Props> = ({
clickOutsideNotOpen clickOutsideNotOpen
onClose={onHide} onClose={onHide}
footer={null} footer={null}
panelClassname={cn('mx-2 mb-3 mt-16 rounded-xl !p-0 sm:mr-2', 'mt-2 !w-[640px]', '!max-w-[640px]')} panelClassName={cn('mx-2 mb-3 mt-16 rounded-xl !p-0 sm:mr-2', 'mt-2 !w-[640px]', '!max-w-[640px]')}
> >
<div <div
className='flex w-full rounded-xl border-[0.5px] border-gray-200 bg-white shadow-xl' className='flex w-full rounded-xl border-[0.5px] border-gray-200 bg-white shadow-xl'

@ -52,7 +52,9 @@ const ConfigCredential: FC<Props> = ({
positionCenter={positionCenter} positionCenter={positionCenter}
onHide={onHide} onHide={onHide}
title={t('tools.createTool.authMethod.title')!} title={t('tools.createTool.authMethod.title')!}
panelClassName='mt-2 !w-[520px] h-fit' dialogClassName='z-[60]'
dialogBackdropClassName='z-[70]'
panelClassName='mt-2 !w-[520px] h-fit z-[80]'
maxWidthClassName='!max-w-[520px]' maxWidthClassName='!max-w-[520px]'
height={'fit-content'} height={'fit-content'}
headerClassName='!border-b-divider-regular' headerClassName='!border-b-divider-regular'

@ -234,7 +234,7 @@ const ProviderDetail = ({
footer={null} footer={null}
mask={false} mask={false}
positionCenter={false} positionCenter={false}
panelClassname={cn('mb-2 mr-2 mt-[64px] !w-[420px] !max-w-[420px] justify-start rounded-2xl border-[0.5px] border-components-panel-border !bg-components-panel-bg !p-0 shadow-xl')} panelClassName={cn('mb-2 mr-2 mt-[64px] !w-[420px] !max-w-[420px] justify-start rounded-2xl border-[0.5px] border-components-panel-border !bg-components-panel-bg !p-0 shadow-xl')}
> >
<div className='p-4'> <div className='p-4'>
<div className='mb-3 flex'> <div className='mb-3 flex'>

@ -111,7 +111,7 @@ const DatasetItem: FC<Props> = ({
} }
{isShowSettingsModal && ( {isShowSettingsModal && (
<Drawer isOpen={isShowSettingsModal} onClose={hideSettingsModal} footer={null} mask={isMobile} panelClassname='mt-16 mx-2 sm:mr-2 mb-3 !p-0 !max-w-[640px] rounded-xl'> <Drawer isOpen={isShowSettingsModal} onClose={hideSettingsModal} footer={null} mask={isMobile} panelClassName='mt-16 mx-2 sm:mr-2 mb-3 !p-0 !max-w-[640px] rounded-xl'>
<SettingsModal <SettingsModal
currentDataset={payload} currentDataset={payload}
onCancel={hideSettingsModal} onCancel={hideSettingsModal}

@ -123,7 +123,7 @@ const ChatVariableModal = ({
case ChatVarType.Number: case ChatVarType.Number:
return value || 0 return value || 0
case ChatVarType.Object: case ChatVarType.Object:
return formatValueFromObject(objectValue) return editInJSON ? value : formatValueFromObject(objectValue)
case ChatVarType.ArrayString: case ChatVarType.ArrayString:
case ChatVarType.ArrayNumber: case ChatVarType.ArrayNumber:
case ChatVarType.ArrayObject: case ChatVarType.ArrayObject:

Loading…
Cancel
Save