'use client' import { Button } from '@langgenius/dify-ui/button' import { Checkbox } from '@langgenius/dify-ui/checkbox' import { Dialog, DialogClose, DialogContent, DialogDescription, DialogTitle, } from '@langgenius/dify-ui/dialog' import { IconButton } from '@langgenius/dify-ui/icon-button' import { Input } from '@langgenius/dify-ui/input' import { Popover, PopoverContent, PopoverTrigger } from '@langgenius/dify-ui/popover' import { Radio, RadioGroup } from '@langgenius/dify-ui/radio-group' import { ScrollArea } from '@langgenius/dify-ui/scroll-area' import { useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { useInfiniteDatasets } from '@/service/knowledge/use-dataset' type Scope = 'all' | 'specific' type SelectedKb = { id: string; name: string } type DatasetScopeDialogProps = { open: boolean isCreating: boolean onOpenChange: (open: boolean) => void // Emits the knowledge-base ids to scope the new key to. An empty array means the // key can access every knowledge base in the workspace (the "all" scope). onConfirm: (datasetIds: string[]) => void } // Scope picker shown when creating a workspace dataset API key. It lets the caller // grant the key access to every knowledge base or to a specific selection, then hands // the chosen ids back to the parent modal, which owns the create mutation. export function DatasetScopeDialog({ open, isCreating, onOpenChange, onConfirm, }: DatasetScopeDialogProps) { const { t } = useTranslation() const [scope, setScope] = useState('all') const [selected, setSelected] = useState([]) const [pickerOpen, setPickerOpen] = useState(false) const [keyword, setKeyword] = useState('') // Selection state resets by remounting: the parent bumps this dialog's `key` each time // it opens, so every open starts from these defaults with no reset-in-effect. const { data: datasetsPages } = useInfiniteDatasets({ keyword }, { enabled: open && pickerOpen }) const datasets = useMemo( () => (datasetsPages?.pages ?? []).flatMap((page) => page.data), [datasetsPages], ) const selectedIds = useMemo(() => new Set(selected.map((kb) => kb.id)), [selected]) const toggleKb = (id: string, name: string) => { setSelected((prev) => prev.some((kb) => kb.id === id) ? prev.filter((kb) => kb.id !== id) : [...prev, { id, name }], ) } const removeKb = (id: string) => setSelected((prev) => prev.filter((kb) => kb.id !== id)) const canCreate = scope === 'all' || selected.length > 0 const handleOpenChange = (nextOpen: boolean) => { if (!nextOpen && isCreating) return onOpenChange(nextOpen) } const handleConfirm = () => { if (!canCreate || isCreating) return onConfirm(scope === 'specific' ? selected.map((kb) => kb.id) : []) } return (
{t(($) => $['apiKeyModal.addTitle'], { ns: 'appApi' })} {t(($) => $['apiKeyModal.addSubtitle'], { ns: 'appApi' })}
$['operation.close'], { ns: 'common' })} size="lg" className="absolute inset-e-6 top-6" disabled={isCreating} > } />
{t(($) => $['apiKeyModal.knowledgeBaseAccess'], { ns: 'appApi' })}
value={scope} onValueChange={setScope}>
{scope === 'specific' && (
{t(($) => $['apiKeyModal.selectedKnowledgeBases'], { ns: 'appApi' })}
{selected.length === 0 ? (
{t(($) => $['apiKeyModal.noKnowledgeBasesSelected'], { ns: 'appApi' })}
) : (
{t(($) => $['apiKeyModal.selectedKnowledgeBasesCount'], { ns: 'appApi', count: selected.length, })}
{selected.map((kb) => (
{kb.name}
))}
)} {t(($) => $['apiKeyModal.addKnowledgeBase'], { ns: 'appApi' })} } /> setKeyword(e.target.value)} placeholder={t(($) => $['apiKeyModal.searchKnowledgeBases'], { ns: 'appApi', })} />
{datasets.map((ds) => ( ))}
)}
) }