mirror of
https://github.com/langgenius/dify.git
synced 2026-04-29 04:26:30 +08:00
feat: enhance dataset detail layout with button disable logic based on pipeline status
This commit is contained in:
parent
6ff6525d1d
commit
9176790adf
@ -120,10 +120,32 @@ const DatasetDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
|||||||
|
|
||||||
const { data: relatedApps } = useDatasetRelatedApps(datasetId)
|
const { data: relatedApps } = useDatasetRelatedApps(datasetId)
|
||||||
|
|
||||||
|
const isButtonDisabledWithPipeline = useMemo(() => {
|
||||||
|
if (!datasetRes)
|
||||||
|
return true
|
||||||
|
if (datasetRes.provider === 'external')
|
||||||
|
return false
|
||||||
|
if (!datasetRes.pipeline_id)
|
||||||
|
return false
|
||||||
|
return !datasetRes.is_published
|
||||||
|
}, [datasetRes])
|
||||||
|
|
||||||
const navigation = useMemo(() => {
|
const navigation = useMemo(() => {
|
||||||
const baseNavigation = [
|
const baseNavigation = [
|
||||||
{ name: t('common.datasetMenus.hitTesting'), href: `/datasets/${datasetId}/hitTesting`, icon: RiFocus2Line, selectedIcon: RiFocus2Fill },
|
{
|
||||||
{ name: t('common.datasetMenus.settings'), href: `/datasets/${datasetId}/settings`, icon: RiEqualizer2Line, selectedIcon: RiEqualizer2Fill },
|
name: t('common.datasetMenus.hitTesting'),
|
||||||
|
href: `/datasets/${datasetId}/hitTesting`,
|
||||||
|
icon: RiFocus2Line,
|
||||||
|
selectedIcon: RiFocus2Fill,
|
||||||
|
disabled: isButtonDisabledWithPipeline,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: t('common.datasetMenus.settings'),
|
||||||
|
href: `/datasets/${datasetId}/settings`,
|
||||||
|
icon: RiEqualizer2Line,
|
||||||
|
selectedIcon: RiEqualizer2Fill,
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
if (datasetRes?.provider !== 'external') {
|
if (datasetRes?.provider !== 'external') {
|
||||||
@ -132,15 +154,17 @@ const DatasetDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
|||||||
href: `/datasets/${datasetId}/documents`,
|
href: `/datasets/${datasetId}/documents`,
|
||||||
icon: RiFileTextLine,
|
icon: RiFileTextLine,
|
||||||
selectedIcon: RiFileTextFill,
|
selectedIcon: RiFileTextFill,
|
||||||
|
disabled: isButtonDisabledWithPipeline,
|
||||||
}, {
|
}, {
|
||||||
name: t('common.datasetMenus.pipeline'),
|
name: t('common.datasetMenus.pipeline'),
|
||||||
href: `/datasets/${datasetId}/pipeline`,
|
href: `/datasets/${datasetId}/pipeline`,
|
||||||
icon: PipelineLine as RemixiconComponentType,
|
icon: PipelineLine as RemixiconComponentType,
|
||||||
selectedIcon: PipelineFill as RemixiconComponentType,
|
selectedIcon: PipelineFill as RemixiconComponentType,
|
||||||
|
disabled: false,
|
||||||
}])
|
}])
|
||||||
}
|
}
|
||||||
return baseNavigation
|
return baseNavigation
|
||||||
}, [datasetRes?.provider, datasetId, t])
|
}, [t, datasetId, isButtonDisabledWithPipeline, datasetRes?.provider])
|
||||||
|
|
||||||
useDocumentTitle(datasetRes?.name || t('common.menus.datasets'))
|
useDocumentTitle(datasetRes?.name || t('common.menus.datasets'))
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ export type IAppDetailNavProps = {
|
|||||||
href: string
|
href: string
|
||||||
icon: NavIcon
|
icon: NavIcon
|
||||||
selectedIcon: NavIcon
|
selectedIcon: NavIcon
|
||||||
|
disabled?: boolean
|
||||||
}>
|
}>
|
||||||
extraInfo?: (modeState: string) => React.ReactNode
|
extraInfo?: (modeState: string) => React.ReactNode
|
||||||
}
|
}
|
||||||
@ -78,7 +79,14 @@ const AppDetailNav = ({
|
|||||||
>
|
>
|
||||||
{navigation.map((item, index) => {
|
{navigation.map((item, index) => {
|
||||||
return (
|
return (
|
||||||
<NavLink key={index} mode={appSidebarExpand} iconMap={{ selected: item.selectedIcon, normal: item.icon }} name={item.name} href={item.href} />
|
<NavLink
|
||||||
|
key={index}
|
||||||
|
mode={appSidebarExpand}
|
||||||
|
iconMap={{ selected: item.selectedIcon, normal: item.icon }}
|
||||||
|
name={item.name}
|
||||||
|
href={item.href}
|
||||||
|
disabled={!!item.disabled}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@ -6,10 +6,10 @@ import classNames from '@/utils/classnames'
|
|||||||
import type { RemixiconComponentType } from '@remixicon/react'
|
import type { RemixiconComponentType } from '@remixicon/react'
|
||||||
|
|
||||||
export type NavIcon = React.ComponentType<
|
export type NavIcon = React.ComponentType<
|
||||||
React.PropsWithoutRef<React.ComponentProps<'svg'>> & {
|
React.PropsWithoutRef<React.ComponentProps<'svg'>> & {
|
||||||
title?: string | undefined
|
title?: string | undefined
|
||||||
titleId?: string | undefined
|
titleId?: string | undefined
|
||||||
}> | RemixiconComponentType
|
}> | RemixiconComponentType
|
||||||
|
|
||||||
export type NavLinkProps = {
|
export type NavLinkProps = {
|
||||||
name: string
|
name: string
|
||||||
@ -19,6 +19,7 @@ export type NavLinkProps = {
|
|||||||
normal: NavIcon
|
normal: NavIcon
|
||||||
}
|
}
|
||||||
mode?: string
|
mode?: string
|
||||||
|
disabled?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function NavLink({
|
export default function NavLink({
|
||||||
@ -26,6 +27,7 @@ export default function NavLink({
|
|||||||
href,
|
href,
|
||||||
iconMap,
|
iconMap,
|
||||||
mode = 'expand',
|
mode = 'expand',
|
||||||
|
disabled = false,
|
||||||
}: NavLinkProps) {
|
}: NavLinkProps) {
|
||||||
const segment = useSelectedLayoutSegment()
|
const segment = useSelectedLayoutSegment()
|
||||||
const formattedSegment = (() => {
|
const formattedSegment = (() => {
|
||||||
@ -39,13 +41,38 @@ export default function NavLink({
|
|||||||
const isActive = href.toLowerCase().split('/')?.pop() === formattedSegment
|
const isActive = href.toLowerCase().split('/')?.pop() === formattedSegment
|
||||||
const NavIcon = isActive ? iconMap.selected : iconMap.normal
|
const NavIcon = isActive ? iconMap.selected : iconMap.normal
|
||||||
|
|
||||||
|
if (disabled) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={name}
|
||||||
|
type='button'
|
||||||
|
disabled
|
||||||
|
className={classNames(
|
||||||
|
'opacity-30 text-components-menu-item-text hover:bg-state-base-hover group flex items-center h-9 rounded-md py-2 system-sm-medium cursor-not-allowed',
|
||||||
|
mode === 'expand' ? 'px-3' : 'px-2.5',
|
||||||
|
)}
|
||||||
|
title={mode === 'collapse' ? name : ''}
|
||||||
|
aria-disabled
|
||||||
|
>
|
||||||
|
<NavIcon
|
||||||
|
className={classNames(
|
||||||
|
'h-4 w-4 flex-shrink-0',
|
||||||
|
mode === 'expand' ? 'mr-2' : 'mr-0',
|
||||||
|
)}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
{mode === 'expand' && name}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
key={name}
|
key={name}
|
||||||
href={href}
|
href={href}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
isActive ? 'bg-state-accent-active text-text-accent font-semibold' : 'text-components-menu-item-text hover:bg-state-base-hover hover:text-components-menu-item-text-hover',
|
isActive ? 'bg-state-accent-active text-text-accent font-semibold' : 'text-components-menu-item-text hover:bg-state-base-hover hover:text-components-menu-item-text-hover',
|
||||||
'group flex items-center h-9 rounded-md py-2 text-sm font-normal',
|
'group flex items-center h-9 rounded-md py-2 system-sm-medium',
|
||||||
mode === 'expand' ? 'px-3' : 'px-2.5',
|
mode === 'expand' ? 'px-3' : 'px-2.5',
|
||||||
)}
|
)}
|
||||||
title={mode === 'collapse' ? name : ''}
|
title={mode === 'collapse' ? name : ''}
|
||||||
|
|||||||
@ -27,7 +27,7 @@ import { DatasourceType } from '@/models/pipeline'
|
|||||||
import { TransferMethod } from '@/types/app'
|
import { TransferMethod } from '@/types/app'
|
||||||
import { useAddDocumentsSteps, useLocalFile, useNotionsPages, useWebsiteCrawl } from './hooks'
|
import { useAddDocumentsSteps, useLocalFile, useNotionsPages, useWebsiteCrawl } from './hooks'
|
||||||
|
|
||||||
const TestRunPanel = () => {
|
const CreateFormPipeline = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const plan = useProviderContextSelector(state => state.plan)
|
const plan = useProviderContextSelector(state => state.plan)
|
||||||
const enableBilling = useProviderContextSelector(state => state.enableBilling)
|
const enableBilling = useProviderContextSelector(state => state.enableBilling)
|
||||||
@ -348,4 +348,4 @@ const TestRunPanel = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TestRunPanel
|
export default CreateFormPipeline
|
||||||
|
|||||||
@ -5,12 +5,10 @@ import OptionCard from '../option-card'
|
|||||||
|
|
||||||
type ChunkStructureProps = {
|
type ChunkStructureProps = {
|
||||||
chunkStructure: ChunkingMode
|
chunkStructure: ChunkingMode
|
||||||
onChunkStructureChange: (value: ChunkingMode) => void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChunkStructure = ({
|
const ChunkStructure = ({
|
||||||
chunkStructure,
|
chunkStructure,
|
||||||
onChunkStructureChange,
|
|
||||||
}: ChunkStructureProps) => {
|
}: ChunkStructureProps) => {
|
||||||
const {
|
const {
|
||||||
options,
|
options,
|
||||||
@ -27,9 +25,6 @@ const ChunkStructure = ({
|
|||||||
iconActiveColor={option.iconActiveColor}
|
iconActiveColor={option.iconActiveColor}
|
||||||
title={option.title}
|
title={option.title}
|
||||||
description={option.description}
|
description={option.description}
|
||||||
onClick={() => {
|
|
||||||
onChunkStructureChange(option.id)
|
|
||||||
}}
|
|
||||||
isActive={chunkStructure === option.id}
|
isActive={chunkStructure === option.id}
|
||||||
effectColor={option.effectColor}
|
effectColor={option.effectColor}
|
||||||
showEffectColor
|
showEffectColor
|
||||||
|
|||||||
@ -67,13 +67,12 @@ const Form = () => {
|
|||||||
const [showAppIconPicker, setShowAppIconPicker] = useState(false)
|
const [showAppIconPicker, setShowAppIconPicker] = useState(false)
|
||||||
const [description, setDescription] = useState(currentDataset?.description ?? '')
|
const [description, setDescription] = useState(currentDataset?.description ?? '')
|
||||||
const [permission, setPermission] = useState(currentDataset?.permission)
|
const [permission, setPermission] = useState(currentDataset?.permission)
|
||||||
const [chunkStructure, setChunkStructure] = useState(currentDataset?.doc_form ?? ChunkingMode.text)
|
|
||||||
const [topK, setTopK] = useState(currentDataset?.external_retrieval_model.top_k ?? 2)
|
const [topK, setTopK] = useState(currentDataset?.external_retrieval_model.top_k ?? 2)
|
||||||
const [scoreThreshold, setScoreThreshold] = useState(currentDataset?.external_retrieval_model.score_threshold ?? 0.5)
|
const [scoreThreshold, setScoreThreshold] = useState(currentDataset?.external_retrieval_model.score_threshold ?? 0.5)
|
||||||
const [scoreThresholdEnabled, setScoreThresholdEnabled] = useState(currentDataset?.external_retrieval_model.score_threshold_enabled ?? false)
|
const [scoreThresholdEnabled, setScoreThresholdEnabled] = useState(currentDataset?.external_retrieval_model.score_threshold_enabled ?? false)
|
||||||
const [selectedMemberIDs, setSelectedMemberIDs] = useState<string[]>(currentDataset?.partial_member_list || [])
|
const [selectedMemberIDs, setSelectedMemberIDs] = useState<string[]>(currentDataset?.partial_member_list || [])
|
||||||
const [memberList, setMemberList] = useState<Member[]>([])
|
const [memberList, setMemberList] = useState<Member[]>([])
|
||||||
const [indexMethod, setIndexMethod] = useState(currentDataset?.indexing_technique ?? IndexingType.QUALIFIED)
|
const [indexMethod, setIndexMethod] = useState(currentDataset?.indexing_technique)
|
||||||
const [keywordNumber, setKeywordNumber] = useState(currentDataset?.keyword_number ?? 10)
|
const [keywordNumber, setKeywordNumber] = useState(currentDataset?.keyword_number ?? 10)
|
||||||
const [retrievalConfig, setRetrievalConfig] = useState(currentDataset?.retrieval_model_dict as RetrievalConfig)
|
const [retrievalConfig, setRetrievalConfig] = useState(currentDataset?.retrieval_model_dict as RetrievalConfig)
|
||||||
const [embeddingModel, setEmbeddingModel] = useState<DefaultModel>(
|
const [embeddingModel, setEmbeddingModel] = useState<DefaultModel>(
|
||||||
@ -164,7 +163,7 @@ const Form = () => {
|
|||||||
body: {
|
body: {
|
||||||
name,
|
name,
|
||||||
icon_info: iconInfo,
|
icon_info: iconInfo,
|
||||||
doc_form: chunkStructure,
|
doc_form: currentDataset?.doc_form,
|
||||||
description,
|
description,
|
||||||
permission,
|
permission,
|
||||||
indexing_technique: indexMethod,
|
indexing_technique: indexMethod,
|
||||||
@ -209,7 +208,7 @@ const Form = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isShowIndexMethod = chunkStructure !== ChunkingMode.parentChild && currentDataset && currentDataset.indexing_technique
|
const isShowIndexMethod = currentDataset && currentDataset.doc_form !== ChunkingMode.parentChild && currentDataset.indexing_technique && indexMethod
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex w-full flex-col gap-y-4 px-20 py-8 sm:w-[960px]'>
|
<div className='flex w-full flex-col gap-y-4 px-20 py-8 sm:w-[960px]'>
|
||||||
@ -268,7 +267,7 @@ const Form = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
!currentDataset?.doc_form && (
|
currentDataset?.doc_form && (
|
||||||
<>
|
<>
|
||||||
<Divider
|
<Divider
|
||||||
type='horizontal'
|
type='horizontal'
|
||||||
@ -294,8 +293,7 @@ const Form = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className='grow'>
|
<div className='grow'>
|
||||||
<ChunkStructure
|
<ChunkStructure
|
||||||
chunkStructure={chunkStructure!}
|
chunkStructure={currentDataset?.doc_form}
|
||||||
onChunkStructureChange={setChunkStructure}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -36,8 +36,11 @@ const Publisher = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PortalToFollowElemTrigger onClick={() => handleOpenChange(!open)}>
|
<PortalToFollowElemTrigger onClick={() => handleOpenChange(!open)}>
|
||||||
<Button variant='primary'>
|
<Button
|
||||||
{t('workflow.common.publish')}
|
className='px-2'
|
||||||
|
variant='primary'
|
||||||
|
>
|
||||||
|
<span className='pl-1'>{t('workflow.common.publish')}</span>
|
||||||
<RiArrowDownSLine className='h-4 w-4' />
|
<RiArrowDownSLine className='h-4 w-4' />
|
||||||
</Button>
|
</Button>
|
||||||
</PortalToFollowElemTrigger>
|
</PortalToFollowElemTrigger>
|
||||||
|
|||||||
@ -125,6 +125,7 @@ const Popup = () => {
|
|||||||
className='mb-1 w-full hover:bg-state-accent-hover hover:text-text-accent'
|
className='mb-1 w-full hover:bg-state-accent-hover hover:text-text-accent'
|
||||||
variant='tertiary'
|
variant='tertiary'
|
||||||
onClick={goToAddDocuments}
|
onClick={goToAddDocuments}
|
||||||
|
disabled={!published}
|
||||||
>
|
>
|
||||||
<div className='flex grow items-center'>
|
<div className='flex grow items-center'>
|
||||||
<RiPlayCircleLine className='mr-2 h-4 w-4' />
|
<RiPlayCircleLine className='mr-2 h-4 w-4' />
|
||||||
@ -135,6 +136,7 @@ const Popup = () => {
|
|||||||
<Button
|
<Button
|
||||||
className='w-full hover:bg-state-accent-hover hover:text-text-accent'
|
className='w-full hover:bg-state-accent-hover hover:text-text-accent'
|
||||||
variant='tertiary'
|
variant='tertiary'
|
||||||
|
disabled={!published}
|
||||||
>
|
>
|
||||||
<div className='flex grow items-center'>
|
<div className='flex grow items-center'>
|
||||||
<RiTerminalBoxLine className='mr-2 h-4 w-4' />
|
<RiTerminalBoxLine className='mr-2 h-4 w-4' />
|
||||||
|
|||||||
@ -81,6 +81,7 @@ export type DataSet = {
|
|||||||
doc_metadata?: MetadataInDoc[]
|
doc_metadata?: MetadataInDoc[]
|
||||||
keyword_number?: number
|
keyword_number?: number
|
||||||
pipeline_id?: string
|
pipeline_id?: string
|
||||||
|
is_published?: boolean // Indicates if the pipeline is published
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ExternalAPIItem = {
|
export type ExternalAPIItem = {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user