/* Copyright (C) 2023-2026 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import { useState, useMemo } from 'react' import { Search } from 'lucide-react' import { useTranslation } from 'react-i18next' import { Button } from '@/components/ui/button' import { Checkbox } from '@/components/ui/checkbox' import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog' import { Input } from '@/components/ui/input' import { ScrollArea } from '@/components/ui/scroll-area' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { ConfirmDialog } from '@/components/confirm-dialog' import { StatusBadge } from '@/components/status-badge' interface UpstreamUpdateDialogProps { open: boolean addModels: string[] removeModels: string[] preferredTab: 'add' | 'remove' confirmLoading: boolean onConfirm: (data: { addModels: string[]; removeModels: string[] }) => void onCancel: () => void } export function UpstreamUpdateDialog(props: UpstreamUpdateDialogProps) { const { t } = useTranslation() const [activeTab, setActiveTab] = useState(props.preferredTab) const [searchAdd, setSearchAdd] = useState('') const [searchRemove, setSearchRemove] = useState('') const [selectedAdd, setSelectedAdd] = useState>( () => new Set(props.addModels) ) const [selectedRemove, setSelectedRemove] = useState>( () => new Set(props.removeModels) ) const [partialConfirmOpen, setPartialConfirmOpen] = useState(false) const filteredAdd = useMemo( () => props.addModels.filter((m) => m.toLowerCase().includes(searchAdd.toLowerCase()) ), [props.addModels, searchAdd] ) const filteredRemove = useMemo( () => props.removeModels.filter((m) => m.toLowerCase().includes(searchRemove.toLowerCase()) ), [props.removeModels, searchRemove] ) const toggleModel = ( model: string, set: Set, setter: (s: Set) => void ) => { const next = new Set(set) if (next.has(model)) next.delete(model) else next.add(model) setter(next) } const toggleAllVisible = ( models: string[], set: Set, setter: (s: Set) => void ) => { const allSelected = models.every((m) => set.has(m)) const next = new Set(set) if (allSelected) { models.forEach((m) => next.delete(m)) } else { models.forEach((m) => next.add(m)) } setter(next) } const handleConfirm = () => { const hasAdd = props.addModels.length > 0 const hasRemove = props.removeModels.length > 0 const selectedAddArr = Array.from(selectedAdd) const selectedRemoveArr = Array.from(selectedRemove) const anyAdd = selectedAddArr.length > 0 const anyRemove = selectedRemoveArr.length > 0 if (hasAdd && hasRemove && (!anyAdd || !anyRemove)) { setPartialConfirmOpen(true) return } props.onConfirm({ addModels: selectedAddArr, removeModels: selectedRemoveArr, }) } return ( <> !v && props.onCancel()}> {t('Upstream Model Updates')}

{t( 'Select models to process. Unselected "add" models will be ignored.' )}

setActiveTab(v as 'add' | 'remove')} > {t('Add Models')} {selectedAdd.size}/{props.addModels.length} {t('Remove Models')} {selectedRemove.size}/{props.removeModels.length}
setSearchAdd(e.target.value)} />
{filteredAdd.length > 0 && (
selectedAdd.has(m))} onCheckedChange={() => toggleAllVisible(filteredAdd, selectedAdd, setSelectedAdd) } /> {t('Select All Visible')}
)} {filteredAdd.length > 0 ? (
{filteredAdd.map((model) => ( ))}
) : (

{props.addModels.length === 0 ? t('No models to add') : t('No matching results')}

)}
setSearchRemove(e.target.value)} />
{filteredRemove.length > 0 && (
selectedRemove.has(m))} onCheckedChange={() => toggleAllVisible( filteredRemove, selectedRemove, setSelectedRemove ) } /> {t('Select All Visible')}
)} {filteredRemove.length > 0 ? (
{filteredRemove.map((model) => ( ))}
) : (

{props.removeModels.length === 0 ? t('No models to remove') : t('No matching results')}

)}
{ setPartialConfirmOpen(false) props.onConfirm({ addModels: Array.from(selectedAdd), removeModels: Array.from(selectedRemove), }) }} /> ) }