mirror of https://github.com/langgenius/dify.git
Merge branch 'feat/rag-2' into fix/styling-issue
This commit is contained in:
commit
31edc39686
|
|
@ -20,7 +20,7 @@ depends_on = None
|
|||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('pipeline_built_in_templates',
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuid_generate_v4()'), nullable=False),
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuidv7()'), nullable=False),
|
||||
sa.Column('pipeline_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('name', sa.String(length=255), nullable=False),
|
||||
sa.Column('description', sa.Text(), nullable=False),
|
||||
|
|
@ -35,7 +35,7 @@ def upgrade():
|
|||
sa.PrimaryKeyConstraint('id', name='pipeline_built_in_template_pkey')
|
||||
)
|
||||
op.create_table('pipeline_customized_templates',
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuid_generate_v4()'), nullable=False),
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuidv7()'), nullable=False),
|
||||
sa.Column('tenant_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('pipeline_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('name', sa.String(length=255), nullable=False),
|
||||
|
|
@ -52,7 +52,7 @@ def upgrade():
|
|||
batch_op.create_index('pipeline_customized_template_tenant_idx', ['tenant_id'], unique=False)
|
||||
|
||||
op.create_table('pipelines',
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuid_generate_v4()'), nullable=False),
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuidv7()'), nullable=False),
|
||||
sa.Column('tenant_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('name', sa.String(length=255), nullable=False),
|
||||
sa.Column('description', sa.Text(), server_default=sa.text("''::character varying"), nullable=False),
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ depends_on = None
|
|||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('datasource_oauth_params',
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuid_generate_v4()'), nullable=False),
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuidv7()'), nullable=False),
|
||||
sa.Column('plugin_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('provider', sa.String(length=255), nullable=False),
|
||||
sa.Column('system_credentials', postgresql.JSONB(astext_type=sa.Text()), nullable=False),
|
||||
|
|
@ -28,7 +28,7 @@ def upgrade():
|
|||
sa.UniqueConstraint('plugin_id', 'provider', name='datasource_oauth_config_datasource_id_provider_idx')
|
||||
)
|
||||
op.create_table('datasource_providers',
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuid_generate_v4()'), nullable=False),
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuidv7()'), nullable=False),
|
||||
sa.Column('tenant_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('plugin_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('provider', sa.String(length=255), nullable=False),
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ depends_on = None
|
|||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('document_pipeline_execution_logs',
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuid_generate_v4()'), nullable=False),
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuidv7()'), nullable=False),
|
||||
sa.Column('pipeline_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('document_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('datasource_type', sa.String(length=255), nullable=False),
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ depends_on = None
|
|||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('pipeline_recommended_plugins',
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuid_generate_v4()'), nullable=False),
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuidv7()'), nullable=False),
|
||||
sa.Column('plugin_id', sa.Text(), nullable=False),
|
||||
sa.Column('provider_name', sa.Text(), nullable=False),
|
||||
sa.Column('position', sa.Integer(), nullable=False),
|
||||
|
|
|
|||
|
|
@ -1225,7 +1225,7 @@ class PipelineBuiltInTemplate(Base): # type: ignore[name-defined]
|
|||
__tablename__ = "pipeline_built_in_templates"
|
||||
__table_args__ = (db.PrimaryKeyConstraint("id", name="pipeline_built_in_template_pkey"),)
|
||||
|
||||
id = db.Column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
id = db.Column(StringUUID, server_default=db.text("uuidv7()"))
|
||||
name = db.Column(db.String(255), nullable=False)
|
||||
description = db.Column(db.Text, nullable=False)
|
||||
chunk_structure = db.Column(db.String(255), nullable=False)
|
||||
|
|
@ -1256,7 +1256,7 @@ class PipelineCustomizedTemplate(Base): # type: ignore[name-defined]
|
|||
db.Index("pipeline_customized_template_tenant_idx", "tenant_id"),
|
||||
)
|
||||
|
||||
id = db.Column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
id = db.Column(StringUUID, server_default=db.text("uuidv7()"))
|
||||
tenant_id = db.Column(StringUUID, nullable=False)
|
||||
name = db.Column(db.String(255), nullable=False)
|
||||
description = db.Column(db.Text, nullable=False)
|
||||
|
|
@ -1283,7 +1283,7 @@ class Pipeline(Base): # type: ignore[name-defined]
|
|||
__tablename__ = "pipelines"
|
||||
__table_args__ = (db.PrimaryKeyConstraint("id", name="pipeline_pkey"),)
|
||||
|
||||
id = db.Column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
id = db.Column(StringUUID, server_default=db.text("uuidv7()"))
|
||||
tenant_id: Mapped[str] = db.Column(StringUUID, nullable=False)
|
||||
name = db.Column(db.String(255), nullable=False)
|
||||
description = db.Column(db.Text, nullable=False, server_default=db.text("''::character varying"))
|
||||
|
|
@ -1306,7 +1306,7 @@ class DocumentPipelineExecutionLog(Base):
|
|||
db.Index("document_pipeline_execution_logs_document_id_idx", "document_id"),
|
||||
)
|
||||
|
||||
id = db.Column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
id = db.Column(StringUUID, server_default=db.text("uuidv7()"))
|
||||
pipeline_id = db.Column(StringUUID, nullable=False)
|
||||
document_id = db.Column(StringUUID, nullable=False)
|
||||
datasource_type = db.Column(db.String(255), nullable=False)
|
||||
|
|
@ -1321,7 +1321,7 @@ class PipelineRecommendedPlugin(Base):
|
|||
__tablename__ = "pipeline_recommended_plugins"
|
||||
__table_args__ = (db.PrimaryKeyConstraint("id", name="pipeline_recommended_plugin_pkey"),)
|
||||
|
||||
id = db.Column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
id = db.Column(StringUUID, server_default=db.text("uuidv7()"))
|
||||
plugin_id = db.Column(db.Text, nullable=False)
|
||||
provider_name = db.Column(db.Text, nullable=False)
|
||||
position = db.Column(db.Integer, nullable=False, default=0)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class DatasourceOauthParamConfig(Base): # type: ignore[name-defined]
|
|||
db.UniqueConstraint("plugin_id", "provider", name="datasource_oauth_config_datasource_id_provider_idx"),
|
||||
)
|
||||
|
||||
id = db.Column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
id = db.Column(StringUUID, server_default=db.text("uuidv7()"))
|
||||
plugin_id: Mapped[str] = db.Column(db.String(255), nullable=False)
|
||||
provider: Mapped[str] = db.Column(db.String(255), nullable=False)
|
||||
system_credentials: Mapped[dict] = db.Column(JSONB, nullable=False)
|
||||
|
|
@ -28,7 +28,7 @@ class DatasourceProvider(Base):
|
|||
db.UniqueConstraint("tenant_id", "plugin_id", "provider", "name", name="datasource_provider_unique_name"),
|
||||
db.Index("datasource_provider_auth_type_provider_idx", "tenant_id", "plugin_id", "provider"),
|
||||
)
|
||||
id = db.Column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
id = db.Column(StringUUID, server_default=db.text("uuidv7()"))
|
||||
tenant_id = db.Column(StringUUID, nullable=False)
|
||||
name: Mapped[str] = db.Column(db.String(255), nullable=False)
|
||||
provider: Mapped[str] = db.Column(db.String(255), nullable=False)
|
||||
|
|
@ -50,7 +50,7 @@ class DatasourceOauthTenantParamConfig(Base):
|
|||
db.UniqueConstraint("tenant_id", "plugin_id", "provider", name="datasource_oauth_tenant_config_unique"),
|
||||
)
|
||||
|
||||
id = db.Column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
id = db.Column(StringUUID, server_default=db.text("uuidv7()"))
|
||||
tenant_id = db.Column(StringUUID, nullable=False)
|
||||
provider: Mapped[str] = db.Column(db.String(255), nullable=False)
|
||||
plugin_id: Mapped[str] = db.Column(db.String(255), nullable=False)
|
||||
|
|
|
|||
|
|
@ -148,7 +148,11 @@ const DatasetSidebarDropdown = ({
|
|||
)
|
||||
})}
|
||||
</nav>
|
||||
<ExtraInfo relatedApps={relatedApps} expand documentCount={dataset.document_count} />
|
||||
<ExtraInfo
|
||||
relatedApps={relatedApps}
|
||||
expand
|
||||
documentCount={dataset.document_count}
|
||||
/>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.92578 11.0094C5.92578 10.0174 5.12163 9.21256 4.12956 9.21256C3.13752 9.2126 2.33333 10.0174 2.33333 11.0094C2.33349 12.0014 3.13762 12.8056 4.12956 12.8057C5.12153 12.8057 5.92562 12.0014 5.92578 11.0094ZM13.6667 11.0094C13.6667 10.0174 12.8625 9.2126 11.8704 9.21256C10.8784 9.21256 10.0742 10.0174 10.0742 11.0094C10.0744 12.0014 10.8785 12.8057 11.8704 12.8057C12.8624 12.8056 13.6665 12.0014 13.6667 11.0094ZM9.79622 4.32389C9.79619 3.33186 8.99205 2.52767 8 2.52767C7.00796 2.52767 6.20382 3.33186 6.20378 4.32389C6.20378 5.31596 7.00793 6.12012 8 6.12012C8.99207 6.12012 9.79622 5.31596 9.79622 4.32389ZM11.1296 4.32389C11.1296 5.82351 10.0748 7.07628 8.66667 7.38184V7.9196L9.74284 8.71387C10.3012 8.19607 11.0489 7.87923 11.8704 7.87923C13.5989 7.87927 15 9.28101 15 11.0094C14.9998 12.7377 13.5988 14.139 11.8704 14.139C10.1421 14.139 8.74104 12.7378 8.74089 11.0094C8.74089 10.5837 8.82585 10.1776 8.97982 9.80762L8 9.08366L7.01953 9.80762C7.17356 10.1777 7.25911 10.5836 7.25911 11.0094C7.25896 12.7378 5.85791 14.139 4.12956 14.139C2.40124 14.139 1.00016 12.7377 1 11.0094C1 9.28101 2.40114 7.87927 4.12956 7.87923C4.95094 7.87923 5.69819 8.19627 6.25651 8.71387L7.33333 7.9196V7.38184C5.92523 7.07628 4.87044 5.82351 4.87044 4.32389C4.87048 2.59548 6.27158 1.19434 8 1.19434C9.72843 1.19434 11.1295 2.59548 11.1296 4.32389Z" fill="#354052"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "16",
|
||||
"height": "16",
|
||||
"viewBox": "0 0 16 16",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M5.92578 11.0094C5.92578 10.0174 5.12163 9.21256 4.12956 9.21256C3.13752 9.2126 2.33333 10.0174 2.33333 11.0094C2.33349 12.0014 3.13762 12.8056 4.12956 12.8057C5.12153 12.8057 5.92562 12.0014 5.92578 11.0094ZM13.6667 11.0094C13.6667 10.0174 12.8625 9.2126 11.8704 9.21256C10.8784 9.21256 10.0742 10.0174 10.0742 11.0094C10.0744 12.0014 10.8785 12.8057 11.8704 12.8057C12.8624 12.8056 13.6665 12.0014 13.6667 11.0094ZM9.79622 4.32389C9.79619 3.33186 8.99205 2.52767 8 2.52767C7.00796 2.52767 6.20382 3.33186 6.20378 4.32389C6.20378 5.31596 7.00793 6.12012 8 6.12012C8.99207 6.12012 9.79622 5.31596 9.79622 4.32389ZM11.1296 4.32389C11.1296 5.82351 10.0748 7.07628 8.66667 7.38184V7.9196L9.74284 8.71387C10.3012 8.19607 11.0489 7.87923 11.8704 7.87923C13.5989 7.87927 15 9.28101 15 11.0094C14.9998 12.7377 13.5988 14.139 11.8704 14.139C10.1421 14.139 8.74104 12.7378 8.74089 11.0094C8.74089 10.5837 8.82585 10.1776 8.97982 9.80762L8 9.08366L7.01953 9.80762C7.17356 10.1777 7.25911 10.5836 7.25911 11.0094C7.25896 12.7378 5.85791 14.139 4.12956 14.139C2.40124 14.139 1.00016 12.7377 1 11.0094C1 9.28101 2.40114 7.87927 4.12956 7.87923C4.95094 7.87923 5.69819 8.19627 6.25651 8.71387L7.33333 7.9196V7.38184C5.92523 7.07628 4.87044 5.82351 4.87044 4.32389C4.87048 2.59548 6.27158 1.19434 8 1.19434C9.72843 1.19434 11.1295 2.59548 11.1296 4.32389Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "ApiAggregate"
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './ApiAggregate.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = (
|
||||
{
|
||||
ref,
|
||||
...props
|
||||
}: React.SVGProps<SVGSVGElement> & {
|
||||
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
|
||||
},
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />
|
||||
|
||||
Icon.displayName = 'ApiAggregate'
|
||||
|
||||
export default Icon
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
export { default as AddChunks } from './AddChunks'
|
||||
export { default as ApiAggregate } from './ApiAggregate'
|
||||
export { default as ArrowShape } from './ArrowShape'
|
||||
export { default as Chunk } from './Chunk'
|
||||
export { default as Collapse } from './Collapse'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
import React from 'react'
|
||||
import type { RelatedAppResponse } from '@/models/datasets'
|
||||
import Statistics from './statistics'
|
||||
import ServiceApi from './service-api'
|
||||
import { useDatasetApiBaseUrl } from '@/service/knowledge/use-dataset'
|
||||
import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail'
|
||||
|
||||
type IExtraInfoProps = {
|
||||
relatedApps?: RelatedAppResponse
|
||||
documentCount?: number
|
||||
expand: boolean
|
||||
}
|
||||
|
||||
const ExtraInfo = ({
|
||||
relatedApps,
|
||||
documentCount,
|
||||
expand,
|
||||
}: IExtraInfoProps) => {
|
||||
const apiEnabled = useDatasetDetailContextWithSelector(state => state.dataset?.enable_api)
|
||||
const { data: apiBaseInfo } = useDatasetApiBaseUrl()
|
||||
|
||||
return (
|
||||
<>
|
||||
{expand && (
|
||||
<Statistics
|
||||
expand={expand}
|
||||
documentCount={documentCount}
|
||||
relatedApps={relatedApps}
|
||||
/>
|
||||
)}
|
||||
<ServiceApi
|
||||
expand={expand}
|
||||
apiBaseUrl={apiBaseInfo?.api_base_url ?? ''}
|
||||
apiEnabled={apiEnabled ?? false}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(ExtraInfo)
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
import React, { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { ApiAggregate } from '@/app/components/base/icons/src/vender/knowledge'
|
||||
import Indicator from '@/app/components/header/indicator'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import { useSelector as useAppContextSelector } from '@/context/app-context'
|
||||
import cn from '@/utils/classnames'
|
||||
import CopyFeedback from '@/app/components/base/copy-feedback'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { RiBookOpenLine, RiKey2Line } from '@remixicon/react'
|
||||
import { useDisableDatasetServiceApi, useEnableDatasetServiceApi } from '@/service/knowledge/use-dataset'
|
||||
import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail'
|
||||
import Link from 'next/link'
|
||||
import SecretKeyModal from '@/app/components/develop/secret-key/secret-key-modal'
|
||||
|
||||
type CardProps = {
|
||||
apiEnabled: boolean
|
||||
apiBaseUrl: string
|
||||
}
|
||||
|
||||
const Card = ({
|
||||
apiEnabled,
|
||||
apiBaseUrl,
|
||||
}: CardProps) => {
|
||||
const { t } = useTranslation()
|
||||
const datasetId = useDatasetDetailContextWithSelector(state => state.dataset?.id)
|
||||
const mutateDatasetRes = useDatasetDetailContextWithSelector(state => state.mutateDatasetRes)
|
||||
const { mutateAsync: enableDatasetServiceApi } = useEnableDatasetServiceApi()
|
||||
const { mutateAsync: disableDatasetServiceApi } = useDisableDatasetServiceApi()
|
||||
const [isSecretKeyModalVisible, setIsSecretKeyModalVisible] = useState(false)
|
||||
|
||||
const isCurrentWorkspaceManager = useAppContextSelector(state => state.isCurrentWorkspaceManager)
|
||||
|
||||
const onToggle = useCallback(async (state: boolean) => {
|
||||
let result: 'success' | 'fail'
|
||||
if (state)
|
||||
result = (await enableDatasetServiceApi(datasetId ?? '')).result
|
||||
else
|
||||
result = (await disableDatasetServiceApi(datasetId ?? '')).result
|
||||
if (result === 'success')
|
||||
mutateDatasetRes?.()
|
||||
}, [datasetId, enableDatasetServiceApi, disableDatasetServiceApi])
|
||||
|
||||
const handleOpenSecretKeyModal = useCallback(() => {
|
||||
setIsSecretKeyModalVisible(true)
|
||||
}, [])
|
||||
|
||||
const handleCloseSecretKeyModal = useCallback(() => {
|
||||
setIsSecretKeyModalVisible(false)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className='flex w-[360px] flex-col rounded-xl border border-components-panel-border bg-components-panel-bg shadow-lg shadow-shadow-shadow-1'>
|
||||
<div className='flex flex-col gap-y-3 p-4'>
|
||||
<div className='flex items-center gap-x-3'>
|
||||
<div className='flex grow items-center gap-x-2'>
|
||||
<div className='flex size-6 shrink-0 items-center justify-center rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-brand-blue-brand-500 shadow-md shadow-shadow-shadow-5'>
|
||||
<ApiAggregate className='size-4 text-text-primary-on-surface' />
|
||||
</div>
|
||||
<div className='system-sm-semibold grow truncate text-text-secondary'>
|
||||
{t('dataset.serviceApi.card.title')}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-center gap-x-1'>
|
||||
<Indicator
|
||||
className='shrink-0'
|
||||
color={apiEnabled ? 'green' : 'yellow'}
|
||||
/>
|
||||
<div
|
||||
className={cn(
|
||||
'system-xs-semibold-uppercase',
|
||||
apiEnabled ? 'text-text-success' : 'text-text-warning',
|
||||
)}
|
||||
>
|
||||
{apiEnabled
|
||||
? t('dataset.serviceApi.enabled')
|
||||
: t('dataset.serviceApi.disabled')}
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
defaultValue={apiEnabled}
|
||||
onChange={onToggle}
|
||||
disabled={!isCurrentWorkspaceManager}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex flex-col'>
|
||||
<div className='system-xs-regular leading-6 text-text-tertiary'>
|
||||
{t('dataset.serviceApi.card.endpoint')}
|
||||
</div>
|
||||
<div className='flex h-8 items-center gap-0.5 rounded-lg bg-components-input-bg-normal p-1 pl-2'>
|
||||
<div className='flex h-4 min-w-0 flex-1 items-start justify-start gap-2 px-1'>
|
||||
<div className='system-xs-medium truncate text-text-secondary'>
|
||||
{apiBaseUrl}
|
||||
</div>
|
||||
</div>
|
||||
<CopyFeedback
|
||||
content={apiBaseUrl}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Actions */}
|
||||
<div className='flex gap-x-1 border-t-[0.5px] border-divider-subtle p-4'>
|
||||
<Button
|
||||
variant='ghost'
|
||||
size='small'
|
||||
className='gap-x-px text-text-tertiary'
|
||||
onClick={handleOpenSecretKeyModal}
|
||||
>
|
||||
<RiKey2Line className='size-3.5 shrink-0' />
|
||||
<span className='system-xs-medium px-[3px]'>
|
||||
{t('dataset.serviceApi.card.apiKey')}
|
||||
</span>
|
||||
</Button>
|
||||
<Link
|
||||
href={'https://docs.dify.ai/api-reference/datasets'}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
<Button
|
||||
variant='ghost'
|
||||
size='small'
|
||||
className='gap-x-px text-text-tertiary'
|
||||
>
|
||||
<RiBookOpenLine className='size-3.5 shrink-0' />
|
||||
<span className='system-xs-medium px-[3px]'>
|
||||
{t('dataset.serviceApi.card.apiReference')}
|
||||
</span>
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<SecretKeyModal
|
||||
isShow={isSecretKeyModalVisible}
|
||||
onClose={handleCloseSecretKeyModal}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(Card)
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
import React, { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { ApiAggregate } from '@/app/components/base/icons/src/vender/knowledge'
|
||||
import Indicator from '@/app/components/header/indicator'
|
||||
import cn from '@/utils/classnames'
|
||||
import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
|
||||
import Card from './card'
|
||||
|
||||
type ServiceApiProps = {
|
||||
expand: boolean
|
||||
apiBaseUrl: string
|
||||
apiEnabled: boolean
|
||||
}
|
||||
|
||||
const ServiceApi = ({
|
||||
expand,
|
||||
apiBaseUrl,
|
||||
apiEnabled,
|
||||
}: ServiceApiProps) => {
|
||||
const { t } = useTranslation()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const handleToggle = () => {
|
||||
setOpen(!open)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='p-3 pt-2'>
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
placement='top-start'
|
||||
offset={{
|
||||
mainAxis: 4,
|
||||
crossAxis: -4,
|
||||
}}
|
||||
customContainer={document.body}
|
||||
>
|
||||
<PortalToFollowElemTrigger
|
||||
className='w-full'
|
||||
onClick={handleToggle}
|
||||
>
|
||||
<div className={cn(
|
||||
'relative flex h-8 cursor-pointer items-center gap-2 rounded-lg border border-components-panel-border px-3',
|
||||
!expand && 'w-8 justify-center',
|
||||
open ? 'bg-state-base-hover' : 'hover:bg-state-base-hover',
|
||||
)}>
|
||||
<ApiAggregate className='size-4 shrink-0 text-text-secondary' />
|
||||
{expand && <div className='system-sm-medium grow text-text-secondary'>{t('dataset.serviceApi.title')}</div>}
|
||||
<Indicator
|
||||
className={cn('shrink-0', !expand && 'absolute -right-px -top-px')}
|
||||
color={apiEnabled ? 'green' : 'yellow'}
|
||||
/>
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent>
|
||||
<Card
|
||||
apiEnabled={apiEnabled}
|
||||
apiBaseUrl={apiBaseUrl}
|
||||
/>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(ServiceApi)
|
||||
|
|
@ -1,33 +1,30 @@
|
|||
import React from 'react'
|
||||
import type { RelatedAppResponse } from '@/models/datasets'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Divider from '../base/divider'
|
||||
import Tooltip from '../base/tooltip'
|
||||
import LinkedAppsPanel from '../base/linked-apps-panel'
|
||||
import NoLinkedAppsPanel from './no-linked-apps-panel'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import LinkedAppsPanel from '@/app/components/base/linked-apps-panel'
|
||||
import NoLinkedAppsPanel from '../no-linked-apps-panel'
|
||||
import { RiInformation2Line } from '@remixicon/react'
|
||||
import type { RelatedAppResponse } from '@/models/datasets'
|
||||
|
||||
type IExtraInfoProps = {
|
||||
relatedApps?: RelatedAppResponse
|
||||
documentCount?: number
|
||||
type StatisticsProps = {
|
||||
expand: boolean
|
||||
documentCount?: number
|
||||
relatedApps?: RelatedAppResponse
|
||||
}
|
||||
|
||||
const ExtraInfo = ({
|
||||
relatedApps,
|
||||
documentCount,
|
||||
const Statistics = ({
|
||||
expand,
|
||||
}: IExtraInfoProps) => {
|
||||
documentCount,
|
||||
relatedApps,
|
||||
}: StatisticsProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const hasRelatedApps = relatedApps?.data && relatedApps?.data?.length > 0
|
||||
const relatedAppsTotal = relatedApps?.data?.length || 0
|
||||
|
||||
if (!expand)
|
||||
return null
|
||||
const relatedAppsTotal = relatedApps?.total
|
||||
const hasRelatedApps = relatedApps?.data && relatedApps.data.length > 0
|
||||
|
||||
return (
|
||||
<div className='flex items-center gap-x-0.5 p-2 pb-3'>
|
||||
<div className='flex items-center gap-x-0.5 p-2 pb-0'>
|
||||
<div className='flex grow flex-col px-2 pb-1.5 pt-1'>
|
||||
<div className='system-md-semibold-uppercase text-text-secondary'>
|
||||
{documentCount ?? '--'}
|
||||
|
|
@ -66,4 +63,4 @@ const ExtraInfo = ({
|
|||
)
|
||||
}
|
||||
|
||||
export default React.memo(ExtraInfo)
|
||||
export default React.memo(Statistics)
|
||||
|
|
@ -1,203 +0,0 @@
|
|||
'use client'
|
||||
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiCloseLine, RiListUnordered } from '@remixicon/react'
|
||||
import TemplateEn from './template/template.en.mdx'
|
||||
import TemplateZh from './template/template.zh.mdx'
|
||||
import TemplateJa from './template/template.ja.mdx'
|
||||
import I18n from '@/context/i18n'
|
||||
import { LanguagesSupported } from '@/i18n-config/language'
|
||||
import useTheme from '@/hooks/use-theme'
|
||||
import { Theme } from '@/types/app'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type DocProps = {
|
||||
apiBaseUrl: string
|
||||
}
|
||||
|
||||
const Doc = ({ apiBaseUrl }: DocProps) => {
|
||||
const { locale } = useContext(I18n)
|
||||
const { t } = useTranslation()
|
||||
const [toc, setToc] = useState<Array<{ href: string; text: string }>>([])
|
||||
const [isTocExpanded, setIsTocExpanded] = useState(false)
|
||||
const [activeSection, setActiveSection] = useState<string>('')
|
||||
const { theme } = useTheme()
|
||||
|
||||
// Set initial TOC expanded state based on screen width
|
||||
useEffect(() => {
|
||||
const mediaQuery = window.matchMedia('(min-width: 1280px)')
|
||||
setIsTocExpanded(mediaQuery.matches)
|
||||
}, [])
|
||||
|
||||
// Extract TOC from article content
|
||||
useEffect(() => {
|
||||
const extractTOC = () => {
|
||||
const article = document.querySelector('article')
|
||||
if (article) {
|
||||
const headings = article.querySelectorAll('h2')
|
||||
const tocItems = Array.from(headings).map((heading) => {
|
||||
const anchor = heading.querySelector('a')
|
||||
if (anchor) {
|
||||
return {
|
||||
href: anchor.getAttribute('href') || '',
|
||||
text: anchor.textContent || '',
|
||||
}
|
||||
}
|
||||
return null
|
||||
}).filter((item): item is { href: string; text: string } => item !== null)
|
||||
setToc(tocItems)
|
||||
// Set initial active section
|
||||
if (tocItems.length > 0)
|
||||
setActiveSection(tocItems[0].href.replace('#', ''))
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(extractTOC, 0)
|
||||
}, [locale])
|
||||
|
||||
// Track scroll position for active section highlighting
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
const scrollContainer = document.querySelector('.scroll-container')
|
||||
if (!scrollContainer || toc.length === 0)
|
||||
return
|
||||
|
||||
// Find active section based on scroll position
|
||||
let currentSection = ''
|
||||
toc.forEach((item) => {
|
||||
const targetId = item.href.replace('#', '')
|
||||
const element = document.getElementById(targetId)
|
||||
if (element) {
|
||||
const rect = element.getBoundingClientRect()
|
||||
// Consider section active if its top is above the middle of viewport
|
||||
if (rect.top <= window.innerHeight / 2)
|
||||
currentSection = targetId
|
||||
}
|
||||
})
|
||||
|
||||
if (currentSection && currentSection !== activeSection)
|
||||
setActiveSection(currentSection)
|
||||
}
|
||||
|
||||
const scrollContainer = document.querySelector('.scroll-container')
|
||||
if (scrollContainer) {
|
||||
scrollContainer.addEventListener('scroll', handleScroll)
|
||||
handleScroll() // Initial check
|
||||
return () => scrollContainer.removeEventListener('scroll', handleScroll)
|
||||
}
|
||||
}, [toc, activeSection])
|
||||
|
||||
// Handle TOC item click
|
||||
const handleTocClick = (e: React.MouseEvent<HTMLAnchorElement>, item: { href: string; text: string }) => {
|
||||
e.preventDefault()
|
||||
const targetId = item.href.replace('#', '')
|
||||
const element = document.getElementById(targetId)
|
||||
if (element) {
|
||||
const scrollContainer = document.querySelector('.scroll-container')
|
||||
if (scrollContainer) {
|
||||
const headerOffset = -40
|
||||
const elementTop = element.offsetTop - headerOffset
|
||||
scrollContainer.scrollTo({
|
||||
top: elementTop,
|
||||
behavior: 'smooth',
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Template = useMemo(() => {
|
||||
switch (locale) {
|
||||
case LanguagesSupported[1]:
|
||||
return <TemplateZh apiBaseUrl={apiBaseUrl} />
|
||||
case LanguagesSupported[7]:
|
||||
return <TemplateJa apiBaseUrl={apiBaseUrl} />
|
||||
default:
|
||||
return <TemplateEn apiBaseUrl={apiBaseUrl} />
|
||||
}
|
||||
}, [apiBaseUrl, locale])
|
||||
|
||||
return (
|
||||
<div className='flex'>
|
||||
<div className={`fixed right-20 top-32 z-10 transition-all duration-150 ease-out ${isTocExpanded ? 'w-[280px]' : 'w-11'}`}>
|
||||
{isTocExpanded
|
||||
? (
|
||||
<nav className='toc flex max-h-[calc(100vh-150px)] w-full flex-col overflow-hidden rounded-xl border-[0.5px] border-components-panel-border bg-background-default-hover shadow-xl'>
|
||||
<div className='relative z-10 flex items-center justify-between border-b border-components-panel-border-subtle bg-background-default-hover px-4 py-2.5'>
|
||||
<span className='text-xs font-medium uppercase tracking-wide text-text-tertiary'>
|
||||
{t('appApi.develop.toc')}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => setIsTocExpanded(false)}
|
||||
className='group flex h-6 w-6 items-center justify-center rounded-md transition-colors hover:bg-state-base-hover'
|
||||
aria-label='Close'
|
||||
>
|
||||
<RiCloseLine className='h-3 w-3 text-text-quaternary transition-colors group-hover:text-text-secondary' />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className='from-components-panel-border-subtle/20 pointer-events-none absolute left-0 right-0 top-[41px] z-10 h-2 bg-gradient-to-b to-transparent'></div>
|
||||
<div className='pointer-events-none absolute left-0 right-0 top-[43px] z-10 h-3 bg-gradient-to-b from-background-default-hover to-transparent'></div>
|
||||
|
||||
<div className='relative flex-1 overflow-y-auto px-3 py-3 pt-1'>
|
||||
{toc.length === 0 ? (
|
||||
<div className='px-2 py-8 text-center text-xs text-text-quaternary'>
|
||||
{t('appApi.develop.noContent')}
|
||||
</div>
|
||||
) : (
|
||||
<ul className='space-y-0.5'>
|
||||
{toc.map((item, index) => {
|
||||
const isActive = activeSection === item.href.replace('#', '')
|
||||
return (
|
||||
<li key={index}>
|
||||
<a
|
||||
href={item.href}
|
||||
onClick={e => handleTocClick(e, item)}
|
||||
className={cn(
|
||||
'group relative flex items-center rounded-md px-3 py-2 text-[13px] transition-all duration-200',
|
||||
isActive
|
||||
? 'bg-state-base-hover font-medium text-text-primary'
|
||||
: 'text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
'mr-2 h-1.5 w-1.5 rounded-full transition-all duration-200',
|
||||
isActive
|
||||
? 'scale-100 bg-text-accent'
|
||||
: 'scale-75 bg-components-panel-border',
|
||||
)}
|
||||
/>
|
||||
<span className='flex-1 truncate'>
|
||||
{item.text}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className='pointer-events-none absolute bottom-0 left-0 right-0 z-10 h-4 rounded-b-xl bg-gradient-to-t from-background-default-hover to-transparent'></div>
|
||||
</nav>
|
||||
)
|
||||
: (
|
||||
<button
|
||||
onClick={() => setIsTocExpanded(true)}
|
||||
className='group flex h-11 w-11 items-center justify-center rounded-full border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg transition-all duration-150 hover:bg-background-default-hover hover:shadow-xl'
|
||||
aria-label='Open table of contents'
|
||||
>
|
||||
<RiListUnordered className='h-5 w-5 text-text-tertiary transition-colors group-hover:text-text-secondary' />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<article className={cn('prose-xl prose', theme === Theme.dark && 'prose-invert')}>
|
||||
{Template}
|
||||
</article>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Doc
|
||||
|
|
@ -1,20 +1,15 @@
|
|||
'use client'
|
||||
|
||||
// Libraries
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useBoolean, useDebounceFn } from 'ahooks'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
||||
// Components
|
||||
import ExternalAPIPanel from '../external-api/external-api-panel'
|
||||
import Datasets from './datasets'
|
||||
import DatasetFooter from './dataset-footer'
|
||||
import ApiServer from '../../develop/ApiServer'
|
||||
import Doc from './doc'
|
||||
import SegmentedControl from '@/app/components/base/segmented-control'
|
||||
import { RiBook2Line, RiTerminalBoxLine } from '@remixicon/react'
|
||||
import TagManagementModal from '@/app/components/base/tag-management'
|
||||
import TagFilter from '@/app/components/base/tag-management/filter'
|
||||
import Button from '@/app/components/base/button'
|
||||
|
|
@ -22,11 +17,7 @@ import Input from '@/app/components/base/input'
|
|||
import { ApiConnectionMod } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
import CheckboxWithLabel from '@/app/components/datasets/create/website/base/checkbox-with-label'
|
||||
|
||||
// Services
|
||||
import { fetchDatasetApiBaseUrl } from '@/service/datasets'
|
||||
|
||||
// Hooks
|
||||
import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
|
||||
import { useStore as useTagStore } from '@/app/components/base/tag-management/store'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { useExternalApiPanel } from '@/context/external-api-panel-context'
|
||||
|
|
@ -43,26 +34,6 @@ const List = () => {
|
|||
const [includeAll, { toggle: toggleIncludeAll }] = useBoolean(false)
|
||||
useDocumentTitle(t('dataset.knowledge'))
|
||||
|
||||
const options = useMemo(() => {
|
||||
return [
|
||||
{ value: 'dataset', text: t('dataset.datasets'), Icon: RiBook2Line },
|
||||
...(currentWorkspace.role === 'dataset_operator' ? [] : [{
|
||||
value: 'api', text: t('dataset.datasetsApi'), Icon: RiTerminalBoxLine,
|
||||
}]),
|
||||
]
|
||||
}, [currentWorkspace.role, t])
|
||||
|
||||
const [activeTab, setActiveTab] = useTabSearchParams({
|
||||
defaultTab: 'dataset',
|
||||
})
|
||||
const { data } = useQuery(
|
||||
{
|
||||
queryKey: ['datasetApiBaseInfo'],
|
||||
queryFn: () => fetchDatasetApiBaseUrl('/datasets/api-base-info'),
|
||||
enabled: activeTab !== 'dataset',
|
||||
},
|
||||
)
|
||||
|
||||
const [keywords, setKeywords] = useState('')
|
||||
const [searchKeywords, setSearchKeywords] = useState('')
|
||||
const { run: handleSearch } = useDebounceFn(() => {
|
||||
|
|
@ -89,55 +60,42 @@ const List = () => {
|
|||
|
||||
return (
|
||||
<div className='scroll-container relative flex grow flex-col overflow-y-auto bg-background-body'>
|
||||
<div className='sticky top-0 z-10 flex items-center justify-between gap-x-1 bg-background-body px-12 pb-2 pt-4'>
|
||||
<SegmentedControl
|
||||
value={activeTab}
|
||||
onChange={newActiveTab => setActiveTab(newActiveTab as string)}
|
||||
options={options}
|
||||
size='large'
|
||||
activeClassName='text-text-primary'
|
||||
/>
|
||||
{activeTab === 'dataset' && (
|
||||
<div className='flex items-center justify-center gap-2'>
|
||||
{isCurrentWorkspaceOwner && <CheckboxWithLabel
|
||||
<div className='sticky top-0 z-10 flex items-center justify-end gap-x-1 bg-background-body px-12 pb-2 pt-4'>
|
||||
<div className='flex items-center justify-center gap-2'>
|
||||
{isCurrentWorkspaceOwner && (
|
||||
<CheckboxWithLabel
|
||||
isChecked={includeAll}
|
||||
onChange={toggleIncludeAll}
|
||||
label={t('dataset.allKnowledge')}
|
||||
labelClassName='system-md-regular text-text-secondary'
|
||||
className='mr-2'
|
||||
tooltip={t('dataset.allKnowledgeDescription') as string}
|
||||
/>}
|
||||
<TagFilter type='knowledge' value={tagFilterValue} onChange={handleTagsChange} />
|
||||
<Input
|
||||
showLeftIcon
|
||||
showClearIcon
|
||||
wrapperClassName='w-[200px]'
|
||||
value={keywords}
|
||||
onChange={e => handleKeywordsChange(e.target.value)}
|
||||
onClear={() => handleKeywordsChange('')}
|
||||
/>
|
||||
<div className='h-4 w-[1px] bg-divider-regular' />
|
||||
<Button
|
||||
className='shadows-shadow-xs gap-0.5'
|
||||
onClick={() => setShowExternalApiPanel(true)}
|
||||
>
|
||||
<ApiConnectionMod className='h-4 w-4 text-components-button-secondary-text' />
|
||||
<div className='system-sm-medium flex items-center justify-center gap-1 px-0.5 text-components-button-secondary-text'>{t('dataset.externalAPIPanelTitle')}</div>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{activeTab === 'api' && data && <ApiServer apiBaseUrl={data.api_base_url || ''} />}
|
||||
</div>
|
||||
{activeTab === 'dataset' && (
|
||||
<>
|
||||
<Datasets tags={tagIDs} keywords={searchKeywords} includeAll={includeAll} />
|
||||
{!systemFeatures.branding.enabled && <DatasetFooter />}
|
||||
{showTagManagementModal && (
|
||||
<TagManagementModal type='knowledge' show={showTagManagementModal} />
|
||||
)}
|
||||
</>
|
||||
<TagFilter type='knowledge' value={tagFilterValue} onChange={handleTagsChange} />
|
||||
<Input
|
||||
showLeftIcon
|
||||
showClearIcon
|
||||
wrapperClassName='w-[200px]'
|
||||
value={keywords}
|
||||
onChange={e => handleKeywordsChange(e.target.value)}
|
||||
onClear={() => handleKeywordsChange('')}
|
||||
/>
|
||||
<div className='h-4 w-[1px] bg-divider-regular' />
|
||||
<Button
|
||||
className='shadows-shadow-xs gap-0.5'
|
||||
onClick={() => setShowExternalApiPanel(true)}
|
||||
>
|
||||
<ApiConnectionMod className='h-4 w-4 text-components-button-secondary-text' />
|
||||
<div className='system-sm-medium flex items-center justify-center gap-1 px-0.5 text-components-button-secondary-text'>{t('dataset.externalAPIPanelTitle')}</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<Datasets tags={tagIDs} keywords={searchKeywords} includeAll={includeAll} />
|
||||
{!systemFeatures.branding.enabled && <DatasetFooter />}
|
||||
{showTagManagementModal && (
|
||||
<TagManagementModal type='knowledge' show={showTagManagementModal} />
|
||||
)}
|
||||
{activeTab === 'api' && data && <Doc apiBaseUrl={data.api_base_url || ''} />}
|
||||
|
||||
{showExternalApiPanel && <ExternalAPIPanel onClose={() => setShowExternalApiPanel(false)} />}
|
||||
</div>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -46,14 +46,14 @@ export default function Indicator({
|
|||
className = '',
|
||||
}: IndicatorProps) {
|
||||
return (
|
||||
<div className={classNames(
|
||||
'h-2 w-2 rounded-[3px] border border-solid',
|
||||
BACKGROUND_MAP[color],
|
||||
BORDER_MAP[color],
|
||||
SHADOW_MAP[color],
|
||||
className,
|
||||
)}>
|
||||
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
'h-2 w-2 rounded-[3px] border border-solid',
|
||||
BACKGROUND_MAP[color],
|
||||
BORDER_MAP[color],
|
||||
SHADOW_MAP[color],
|
||||
className,
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import dataSourceDefault from '@/app/components/workflow/nodes/data-source/defau
|
|||
import dataSourceEmptyDefault from '@/app/components/workflow/nodes/data-source-empty/default'
|
||||
import { WORKFLOW_COMMON_NODES } from '@/app/components/workflow/constants/node'
|
||||
import type { AvailableNodesMetaData } from '@/app/components/workflow/hooks-store/store'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
||||
export const useAvailableNodesMetaData = () => {
|
||||
const { t } = useTranslation()
|
||||
|
|
@ -61,7 +62,10 @@ export const useAvailableNodesMetaData = () => {
|
|||
return useMemo(() => {
|
||||
return {
|
||||
nodes: availableNodesMetaData,
|
||||
nodesMap: availableNodesMetaDataMap,
|
||||
nodesMap: {
|
||||
...availableNodesMetaDataMap,
|
||||
[BlockEnum.VariableAssigner]: availableNodesMetaDataMap?.[BlockEnum.VariableAggregator],
|
||||
},
|
||||
}
|
||||
}, [availableNodesMetaData, availableNodesMetaDataMap])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import AnswerDefault from '@/app/components/workflow/nodes/answer/default'
|
|||
import { WORKFLOW_COMMON_NODES } from '@/app/components/workflow/constants/node'
|
||||
import type { AvailableNodesMetaData } from '@/app/components/workflow/hooks-store/store'
|
||||
import { useIsChatMode } from './use-is-chat-mode'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
||||
export const useAvailableNodesMetaData = () => {
|
||||
const { t } = useTranslation()
|
||||
|
|
@ -58,7 +59,10 @@ export const useAvailableNodesMetaData = () => {
|
|||
return useMemo(() => {
|
||||
return {
|
||||
nodes: availableNodesMetaData,
|
||||
nodesMap: availableNodesMetaDataMap,
|
||||
nodesMap: {
|
||||
...availableNodesMetaDataMap,
|
||||
[BlockEnum.VariableAssigner]: availableNodesMetaDataMap?.[BlockEnum.VariableAggregator],
|
||||
},
|
||||
}
|
||||
}, [availableNodesMetaData, availableNodesMetaDataMap])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -226,6 +226,17 @@ const translation = {
|
|||
technicalParameters: 'Technical Parameters',
|
||||
},
|
||||
},
|
||||
serviceApi: {
|
||||
title: 'Service API',
|
||||
enabled: 'In Service',
|
||||
disabled: 'Disabled',
|
||||
card: {
|
||||
title: 'Backend service api',
|
||||
endpoint: 'Service API Endpoint',
|
||||
apiKey: 'API Key',
|
||||
apiReference: 'API Reference',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
|||
|
|
@ -226,6 +226,17 @@ const translation = {
|
|||
technicalParameters: '技术参数',
|
||||
},
|
||||
},
|
||||
serviceApi: {
|
||||
title: '服务 API',
|
||||
enabled: '运行中',
|
||||
disabled: '已停用',
|
||||
card: {
|
||||
title: '后端服务 API',
|
||||
endpoint: 'API 端点',
|
||||
apiKey: 'API 密钥',
|
||||
apiReference: 'API 文档',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ export type DataSet = {
|
|||
pipeline_id?: string
|
||||
is_published?: boolean // Indicates if the pipeline is published
|
||||
runtime_mode: 'rag_pipeline' | 'general'
|
||||
enable_api: boolean
|
||||
}
|
||||
|
||||
export type ExternalAPIItem = {
|
||||
|
|
|
|||
|
|
@ -203,10 +203,6 @@ export const createApikey: Fetcher<CreateApiKeyResponse, { url: string; body: Re
|
|||
return post<CreateApiKeyResponse>(url, body)
|
||||
}
|
||||
|
||||
export const fetchDatasetApiBaseUrl: Fetcher<{ api_base_url: string }, string> = (url) => {
|
||||
return get<{ api_base_url: string }>(url)
|
||||
}
|
||||
|
||||
export const fetchDataSources = () => {
|
||||
return get<CommonResponse>('api-key-auth/data-source')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,10 @@ import type {
|
|||
ProcessRuleResponse,
|
||||
RelatedAppResponse,
|
||||
} from '@/models/datasets'
|
||||
import { get } from '../base'
|
||||
import { get, post } from '../base'
|
||||
import { useInvalid } from '../use-base'
|
||||
import qs from 'qs'
|
||||
import type { CommonResponse } from '@/models/common'
|
||||
|
||||
const NAME_SPACE = 'dataset'
|
||||
|
||||
|
|
@ -75,3 +76,24 @@ export const useProcessRule = (documentId: string) => {
|
|||
queryFn: () => get<ProcessRuleResponse>('/datasets/process-rule', { params: { document_id: documentId } }),
|
||||
})
|
||||
}
|
||||
|
||||
export const useDatasetApiBaseUrl = () => {
|
||||
return useQuery<{ api_base_url: string }>({
|
||||
queryKey: [NAME_SPACE, 'api-base-info'],
|
||||
queryFn: () => get<{ api_base_url: string }>('/datasets/api-base-info'),
|
||||
})
|
||||
}
|
||||
|
||||
export const useEnableDatasetServiceApi = () => {
|
||||
return useMutation({
|
||||
mutationKey: [NAME_SPACE, 'enable-api'],
|
||||
mutationFn: (datasetId: string) => post<CommonResponse>(`/datasets/${datasetId}/enable`),
|
||||
})
|
||||
}
|
||||
|
||||
export const useDisableDatasetServiceApi = () => {
|
||||
return useMutation({
|
||||
mutationKey: [NAME_SPACE, 'disable-api'],
|
||||
mutationFn: (datasetId: string) => post<CommonResponse>(`/datasets/${datasetId}/disable`),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue