feat: enhance dataset detail layout with button disable logic based on pipeline status

This commit is contained in:
twwu 2025-05-29 14:06:12 +08:00
parent 6ff6525d1d
commit 9176790adf
9 changed files with 83 additions and 25 deletions

View File

@ -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'))

View File

@ -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>

View File

@ -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 : ''}

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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' />

View File

@ -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 = {