mirror of https://github.com/langgenius/dify.git
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 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 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') {
|
||||
|
|
@ -132,15 +154,17 @@ const DatasetDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
|||
href: `/datasets/${datasetId}/documents`,
|
||||
icon: RiFileTextLine,
|
||||
selectedIcon: RiFileTextFill,
|
||||
disabled: isButtonDisabledWithPipeline,
|
||||
}, {
|
||||
name: t('common.datasetMenus.pipeline'),
|
||||
href: `/datasets/${datasetId}/pipeline`,
|
||||
icon: PipelineLine as RemixiconComponentType,
|
||||
selectedIcon: PipelineFill as RemixiconComponentType,
|
||||
disabled: false,
|
||||
}])
|
||||
}
|
||||
return baseNavigation
|
||||
}, [datasetRes?.provider, datasetId, t])
|
||||
}, [t, datasetId, isButtonDisabledWithPipeline, datasetRes?.provider])
|
||||
|
||||
useDocumentTitle(datasetRes?.name || t('common.menus.datasets'))
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export type IAppDetailNavProps = {
|
|||
href: string
|
||||
icon: NavIcon
|
||||
selectedIcon: NavIcon
|
||||
disabled?: boolean
|
||||
}>
|
||||
extraInfo?: (modeState: string) => React.ReactNode
|
||||
}
|
||||
|
|
@ -78,7 +79,14 @@ const AppDetailNav = ({
|
|||
>
|
||||
{navigation.map((item, index) => {
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ import classNames from '@/utils/classnames'
|
|||
import type { RemixiconComponentType } from '@remixicon/react'
|
||||
|
||||
export type NavIcon = React.ComponentType<
|
||||
React.PropsWithoutRef<React.ComponentProps<'svg'>> & {
|
||||
title?: string | undefined
|
||||
titleId?: string | undefined
|
||||
}> | RemixiconComponentType
|
||||
React.PropsWithoutRef<React.ComponentProps<'svg'>> & {
|
||||
title?: string | undefined
|
||||
titleId?: string | undefined
|
||||
}> | RemixiconComponentType
|
||||
|
||||
export type NavLinkProps = {
|
||||
name: string
|
||||
|
|
@ -19,6 +19,7 @@ export type NavLinkProps = {
|
|||
normal: NavIcon
|
||||
}
|
||||
mode?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export default function NavLink({
|
||||
|
|
@ -26,6 +27,7 @@ export default function NavLink({
|
|||
href,
|
||||
iconMap,
|
||||
mode = 'expand',
|
||||
disabled = false,
|
||||
}: NavLinkProps) {
|
||||
const segment = useSelectedLayoutSegment()
|
||||
const formattedSegment = (() => {
|
||||
|
|
@ -39,13 +41,38 @@ export default function NavLink({
|
|||
const isActive = href.toLowerCase().split('/')?.pop() === formattedSegment
|
||||
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 (
|
||||
<Link
|
||||
key={name}
|
||||
href={href}
|
||||
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',
|
||||
'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',
|
||||
)}
|
||||
title={mode === 'collapse' ? name : ''}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import { DatasourceType } from '@/models/pipeline'
|
|||
import { TransferMethod } from '@/types/app'
|
||||
import { useAddDocumentsSteps, useLocalFile, useNotionsPages, useWebsiteCrawl } from './hooks'
|
||||
|
||||
const TestRunPanel = () => {
|
||||
const CreateFormPipeline = () => {
|
||||
const { t } = useTranslation()
|
||||
const plan = useProviderContextSelector(state => state.plan)
|
||||
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 = {
|
||||
chunkStructure: ChunkingMode
|
||||
onChunkStructureChange: (value: ChunkingMode) => void
|
||||
}
|
||||
|
||||
const ChunkStructure = ({
|
||||
chunkStructure,
|
||||
onChunkStructureChange,
|
||||
}: ChunkStructureProps) => {
|
||||
const {
|
||||
options,
|
||||
|
|
@ -27,9 +25,6 @@ const ChunkStructure = ({
|
|||
iconActiveColor={option.iconActiveColor}
|
||||
title={option.title}
|
||||
description={option.description}
|
||||
onClick={() => {
|
||||
onChunkStructureChange(option.id)
|
||||
}}
|
||||
isActive={chunkStructure === option.id}
|
||||
effectColor={option.effectColor}
|
||||
showEffectColor
|
||||
|
|
|
|||
|
|
@ -67,13 +67,12 @@ const Form = () => {
|
|||
const [showAppIconPicker, setShowAppIconPicker] = useState(false)
|
||||
const [description, setDescription] = useState(currentDataset?.description ?? '')
|
||||
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 [scoreThreshold, setScoreThreshold] = useState(currentDataset?.external_retrieval_model.score_threshold ?? 0.5)
|
||||
const [scoreThresholdEnabled, setScoreThresholdEnabled] = useState(currentDataset?.external_retrieval_model.score_threshold_enabled ?? false)
|
||||
const [selectedMemberIDs, setSelectedMemberIDs] = useState<string[]>(currentDataset?.partial_member_list || [])
|
||||
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 [retrievalConfig, setRetrievalConfig] = useState(currentDataset?.retrieval_model_dict as RetrievalConfig)
|
||||
const [embeddingModel, setEmbeddingModel] = useState<DefaultModel>(
|
||||
|
|
@ -164,7 +163,7 @@ const Form = () => {
|
|||
body: {
|
||||
name,
|
||||
icon_info: iconInfo,
|
||||
doc_form: chunkStructure,
|
||||
doc_form: currentDataset?.doc_form,
|
||||
description,
|
||||
permission,
|
||||
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 (
|
||||
<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>
|
||||
{
|
||||
!currentDataset?.doc_form && (
|
||||
currentDataset?.doc_form && (
|
||||
<>
|
||||
<Divider
|
||||
type='horizontal'
|
||||
|
|
@ -294,8 +293,7 @@ const Form = () => {
|
|||
</div>
|
||||
<div className='grow'>
|
||||
<ChunkStructure
|
||||
chunkStructure={chunkStructure!}
|
||||
onChunkStructureChange={setChunkStructure}
|
||||
chunkStructure={currentDataset?.doc_form}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -36,8 +36,11 @@ const Publisher = () => {
|
|||
}}
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={() => handleOpenChange(!open)}>
|
||||
<Button variant='primary'>
|
||||
{t('workflow.common.publish')}
|
||||
<Button
|
||||
className='px-2'
|
||||
variant='primary'
|
||||
>
|
||||
<span className='pl-1'>{t('workflow.common.publish')}</span>
|
||||
<RiArrowDownSLine className='h-4 w-4' />
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ const Popup = () => {
|
|||
className='mb-1 w-full hover:bg-state-accent-hover hover:text-text-accent'
|
||||
variant='tertiary'
|
||||
onClick={goToAddDocuments}
|
||||
disabled={!published}
|
||||
>
|
||||
<div className='flex grow items-center'>
|
||||
<RiPlayCircleLine className='mr-2 h-4 w-4' />
|
||||
|
|
@ -135,6 +136,7 @@ const Popup = () => {
|
|||
<Button
|
||||
className='w-full hover:bg-state-accent-hover hover:text-text-accent'
|
||||
variant='tertiary'
|
||||
disabled={!published}
|
||||
>
|
||||
<div className='flex grow items-center'>
|
||||
<RiTerminalBoxLine className='mr-2 h-4 w-4' />
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ export type DataSet = {
|
|||
doc_metadata?: MetadataInDoc[]
|
||||
keyword_number?: number
|
||||
pipeline_id?: string
|
||||
is_published?: boolean // Indicates if the pipeline is published
|
||||
}
|
||||
|
||||
export type ExternalAPIItem = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue