diff --git a/ui/litellm-dashboard/src/components/model_dashboard/HealthCheckComponent.tsx b/ui/litellm-dashboard/src/components/model_dashboard/HealthCheckComponent.tsx index 6444031bc12..d7e35d85c98 100644 --- a/ui/litellm-dashboard/src/components/model_dashboard/HealthCheckComponent.tsx +++ b/ui/litellm-dashboard/src/components/model_dashboard/HealthCheckComponent.tsx @@ -14,9 +14,11 @@ import { Table as TableInstance } from '@tanstack/react-table'; interface HealthStatus { status: string; lastCheck: string; + lastSuccess?: string; loading: boolean; error?: string; fullError?: string; + successResponse?: any; } interface HealthCheckComponentProps { @@ -24,6 +26,7 @@ interface HealthCheckComponentProps { modelData: any; all_models_on_proxy: string[]; getDisplayModelName: (model: any) => string; + setSelectedModelId?: (modelId: string) => void; } const HealthCheckComponent: React.FC = ({ @@ -31,6 +34,7 @@ const HealthCheckComponent: React.FC = ({ modelData, all_models_on_proxy, getDisplayModelName, + setSelectedModelId, }) => { const [modelHealthStatuses, setModelHealthStatuses] = useState<{[key: string]: HealthStatus}>({}); const [selectedModelsForHealth, setSelectedModelsForHealth] = useState([]); @@ -41,6 +45,11 @@ const HealthCheckComponent: React.FC = ({ cleanedError: string; fullError: string; } | null>(null); + const [successModalVisible, setSuccessModalVisible] = useState(false); + const [selectedSuccessDetails, setSelectedSuccessDetails] = useState<{ + modelName: string; + response: any; + } | null>(null); const healthTableRef = useRef>(null); @@ -57,9 +66,11 @@ const HealthCheckComponent: React.FC = ({ healthStatusMap[modelName] = { status: 'none', lastCheck: 'None', + lastSuccess: 'None', loading: false, error: undefined, fullError: undefined, + successResponse: undefined, }; }); @@ -99,9 +110,11 @@ const HealthCheckComponent: React.FC = ({ healthStatusMap[targetModelName] = { status: checkData.status || 'unknown', lastCheck: checkData.checked_at ? new Date(checkData.checked_at).toLocaleString() : 'None', + lastSuccess: checkData.status === 'healthy' ? (checkData.checked_at ? new Date(checkData.checked_at).toLocaleString() : 'None') : 'None', loading: false, error: fullError ? extractMeaningfulError(fullError) : undefined, fullError: fullError, + successResponse: checkData.status === 'healthy' ? checkData : undefined, }; } }); @@ -259,7 +272,9 @@ const HealthCheckComponent: React.FC = ({ [modelName]: { status: 'healthy', lastCheck: currentTime, - loading: false + lastSuccess: currentTime, + loading: false, + successResponse: response } })); } @@ -281,9 +296,11 @@ const HealthCheckComponent: React.FC = ({ [modelName]: { status: checkData.status || prev[modelName]?.status || 'unknown', lastCheck: checkData.checked_at ? new Date(checkData.checked_at).toLocaleString() : prev[modelName]?.lastCheck || 'None', + lastSuccess: checkData.status === 'healthy' ? (checkData.checked_at ? new Date(checkData.checked_at).toLocaleString() : prev[modelName]?.lastSuccess || 'None') : prev[modelName]?.lastSuccess || 'None', loading: false, error: fullError ? extractMeaningfulError(fullError) : prev[modelName]?.error, fullError: fullError || prev[modelName]?.fullError, + successResponse: checkData.status === 'healthy' ? checkData : prev[modelName]?.successResponse, } })); } @@ -359,7 +376,9 @@ const HealthCheckComponent: React.FC = ({ [modelName]: { status: 'healthy', lastCheck: currentTime, - loading: false + lastSuccess: currentTime, + loading: false, + successResponse: response } })); } @@ -405,9 +424,11 @@ const HealthCheckComponent: React.FC = ({ [modelName]: { status: checkData.status || currentStatus?.status || 'unknown', lastCheck: checkData.checked_at ? new Date(checkData.checked_at).toLocaleString() : currentStatus?.lastCheck || 'None', + lastSuccess: checkData.status === 'healthy' ? (checkData.checked_at ? new Date(checkData.checked_at).toLocaleString() : currentStatus?.lastSuccess || 'None') : currentStatus?.lastSuccess || 'None', loading: false, error: fullError ? extractMeaningfulError(fullError) : currentStatus?.error, fullError: fullError || currentStatus?.fullError, + successResponse: checkData.status === 'healthy' ? checkData : currentStatus?.successResponse, } }; }); @@ -467,6 +488,19 @@ const HealthCheckComponent: React.FC = ({ setSelectedErrorDetails(null); }; + const showSuccessModal = (modelName: string, response: any) => { + setSelectedSuccessDetails({ + modelName, + response + }); + setSuccessModalVisible(true); + }; + + const closeSuccessModal = () => { + setSuccessModalVisible(false); + setSelectedSuccessDetails(null); + }; + return (
@@ -515,6 +549,8 @@ const HealthCheckComponent: React.FC = ({ getStatusBadge, getDisplayModelName, showErrorModal, + showSuccessModal, + setSelectedModelId, )} data={modelData.data.map((model: any) => { const modelName = model.model_name; @@ -568,6 +604,39 @@ const HealthCheckComponent: React.FC = ({
)} + + {/* Success Modal */} + + Close + + ]} + width={800} + > + {selectedSuccessDetails && ( +
+
+ Status: +
+ Health check passed successfully +
+
+ +
+ Response Details: +
+
+                  {JSON.stringify(selectedSuccessDetails.response, null, 2)}
+                
+
+
+
+ )} +
); }; diff --git a/ui/litellm-dashboard/src/components/model_dashboard/health_check_columns.tsx b/ui/litellm-dashboard/src/components/model_dashboard/health_check_columns.tsx index eaee6181f5c..e51a5c1c149 100644 --- a/ui/litellm-dashboard/src/components/model_dashboard/health_check_columns.tsx +++ b/ui/litellm-dashboard/src/components/model_dashboard/health_check_columns.tsx @@ -23,9 +23,11 @@ interface HealthCheckData { interface HealthStatus { status: string; lastCheck: string; + lastSuccess?: string; loading: boolean; error?: string; fullError?: string; + successResponse?: any; } export const healthCheckColumns = ( @@ -38,15 +40,18 @@ export const healthCheckColumns = ( getStatusBadge: (status: string) => JSX.Element, getDisplayModelName: (model: any) => string, showErrorModal?: (modelName: string, cleanedError: string, fullError: string) => void, + showSuccessModal?: (modelName: string, response: any) => void, + setSelectedModelId?: (modelId: string) => void, ): ColumnDef[] => [ { header: () => (
- 0 && !allModelsSelected} - onChange={(e) => handleSelectAll(e.target.checked)} - /> + 0 && !allModelsSelected} + onChange={(e) => handleSelectAll(e.target.checked)} + onClick={(e) => e.stopPropagation()} + /> Model ID
), @@ -63,10 +68,12 @@ export const healthCheckColumns = ( handleModelSelection(modelName, e.target.checked)} + onClick={(e) => e.stopPropagation()} />
setSelectedModelId && setSelectedModelId(model.model_info.id)} > {model.model_info.id}
@@ -131,9 +138,22 @@ export const healthCheckColumns = ( ); } + const modelName = model.model_name; + const hasSuccessResponse = healthStatus.status === 'healthy' && modelHealthStatuses[modelName]?.successResponse; + return (
{getStatusBadge(healthStatus.status)} + {hasSuccessResponse && showSuccessModal && ( + + + + )}
); },