/* 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 { useCallback, useEffect, useState } from 'react' import { useQueryClient } from '@tanstack/react-query' import { getRouteApi, useNavigate } from '@tanstack/react-router' import { Plus } from 'lucide-react' import { useTranslation } from 'react-i18next' import { Button } from '@/components/ui/button' import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs' import { SectionPageLayout } from '@/components/layout' import { listDeployments } from './api' import { DeploymentAccessGuard } from './components/deployment-access-guard' import { DeploymentsTable } from './components/deployments-table' import { CreateDeploymentDrawer } from './components/dialogs/create-deployment-drawer' import { ModelsDialogs } from './components/models-dialogs' import { ModelsPrimaryButtons } from './components/models-primary-buttons' import { ModelsProvider, useModels } from './components/models-provider' import { ModelsTable } from './components/models-table' import { useModelDeploymentSettings } from './hooks/use-model-deployment-settings' import { deploymentsQueryKeys } from './lib' import { type ModelsSectionId, MODELS_DEFAULT_SECTION, MODELS_SECTION_IDS, } from './section-registry' const route = getRouteApi('/_authenticated/models/$section') const SECTION_META: Record< ModelsSectionId, { titleKey: string; descriptionKey: string } > = { metadata: { titleKey: 'Metadata', descriptionKey: 'Manage model metadata and configuration', }, deployments: { titleKey: 'Deployments', descriptionKey: 'Manage model deployments', }, } function ModelsContent() { const { t } = useTranslation() const navigate = useNavigate() const queryClient = useQueryClient() const { tabCategory, setTabCategory } = useModels() const params = route.useParams() const activeSection = (params.section ?? MODELS_DEFAULT_SECTION) as ModelsSectionId // Deployment create dialog state const [createDeploymentOpen, setCreateDeploymentOpen] = useState(false) // keep context state in sync (for components that rely on it) useEffect(() => { if (tabCategory !== activeSection) { setTabCategory(activeSection) } }, [activeSection, setTabCategory, tabCategory]) const { loading: deploymentLoading, loadingPhase, isIoNetEnabled, connectionLoading, connectionOk, connectionError, testConnection, refresh: refreshDeploymentSettings, } = useModelDeploymentSettings() // Ensure settings are fresh when switching to deployments section useEffect(() => { if (activeSection === 'deployments') { refreshDeploymentSettings() } }, [activeSection, refreshDeploymentSettings]) // Prefetch deployments list while connection check is in progress // This allows the data to be ready as soon as the guard passes useEffect(() => { if ( activeSection === 'deployments' && isIoNetEnabled && loadingPhase === 'connection' ) { const defaultParams = { p: 1, page_size: 10 } queryClient.prefetchQuery({ queryKey: deploymentsQueryKeys.list(defaultParams), queryFn: () => listDeployments(defaultParams), staleTime: 30 * 1000, // 30 seconds }) } }, [activeSection, isIoNetEnabled, loadingPhase, queryClient]) const handleSectionChange = useCallback( (section: string) => { void navigate({ to: '/models/$section', params: { section: section as ModelsSectionId }, }) }, [navigate] ) const meta = SECTION_META[activeSection] ?? SECTION_META.metadata return ( <> {t(meta.titleKey)} {t(meta.descriptionKey)} {activeSection === 'metadata' ? ( ) : ( )}
{MODELS_SECTION_IDS.map((section) => ( {t(SECTION_META[section].titleKey)} ))} {activeSection === 'metadata' ? ( ) : ( )}
) } export function Models() { return ( ) }