mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-07 08:26:10 +00:00
Add success modal for health check responses - Add green info icon next to healthy status badges - Click icon to view full health check response including headers - Show rate limit headers and other response metadata - Store successResponse in health status state - Add showSuccessModal functionality to view JSON response details - Restore ability to inspect successful health check responses
This commit is contained in:
parent
0a855ad728
commit
f892439671
2 changed files with 96 additions and 7 deletions
|
|
@ -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<HealthCheckComponentProps> = ({
|
||||
|
|
@ -31,6 +34,7 @@ const HealthCheckComponent: React.FC<HealthCheckComponentProps> = ({
|
|||
modelData,
|
||||
all_models_on_proxy,
|
||||
getDisplayModelName,
|
||||
setSelectedModelId,
|
||||
}) => {
|
||||
const [modelHealthStatuses, setModelHealthStatuses] = useState<{[key: string]: HealthStatus}>({});
|
||||
const [selectedModelsForHealth, setSelectedModelsForHealth] = useState<string[]>([]);
|
||||
|
|
@ -41,6 +45,11 @@ const HealthCheckComponent: React.FC<HealthCheckComponentProps> = ({
|
|||
cleanedError: string;
|
||||
fullError: string;
|
||||
} | null>(null);
|
||||
const [successModalVisible, setSuccessModalVisible] = useState(false);
|
||||
const [selectedSuccessDetails, setSelectedSuccessDetails] = useState<{
|
||||
modelName: string;
|
||||
response: any;
|
||||
} | null>(null);
|
||||
|
||||
const healthTableRef = useRef<TableInstance<any>>(null);
|
||||
|
||||
|
|
@ -57,9 +66,11 @@ const HealthCheckComponent: React.FC<HealthCheckComponentProps> = ({
|
|||
healthStatusMap[modelName] = {
|
||||
status: 'none',
|
||||
lastCheck: 'None',
|
||||
lastSuccess: 'None',
|
||||
loading: false,
|
||||
error: undefined,
|
||||
fullError: undefined,
|
||||
successResponse: undefined,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
@ -99,9 +110,11 @@ const HealthCheckComponent: React.FC<HealthCheckComponentProps> = ({
|
|||
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<HealthCheckComponentProps> = ({
|
|||
[modelName]: {
|
||||
status: 'healthy',
|
||||
lastCheck: currentTime,
|
||||
loading: false
|
||||
lastSuccess: currentTime,
|
||||
loading: false,
|
||||
successResponse: response
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
|
@ -281,9 +296,11 @@ const HealthCheckComponent: React.FC<HealthCheckComponentProps> = ({
|
|||
[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<HealthCheckComponentProps> = ({
|
|||
[modelName]: {
|
||||
status: 'healthy',
|
||||
lastCheck: currentTime,
|
||||
loading: false
|
||||
lastSuccess: currentTime,
|
||||
loading: false,
|
||||
successResponse: response
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
|
@ -405,9 +424,11 @@ const HealthCheckComponent: React.FC<HealthCheckComponentProps> = ({
|
|||
[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<HealthCheckComponentProps> = ({
|
|||
setSelectedErrorDetails(null);
|
||||
};
|
||||
|
||||
const showSuccessModal = (modelName: string, response: any) => {
|
||||
setSelectedSuccessDetails({
|
||||
modelName,
|
||||
response
|
||||
});
|
||||
setSuccessModalVisible(true);
|
||||
};
|
||||
|
||||
const closeSuccessModal = () => {
|
||||
setSuccessModalVisible(false);
|
||||
setSelectedSuccessDetails(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow">
|
||||
<div className="border-b px-6 py-4">
|
||||
|
|
@ -515,6 +549,8 @@ const HealthCheckComponent: React.FC<HealthCheckComponentProps> = ({
|
|||
getStatusBadge,
|
||||
getDisplayModelName,
|
||||
showErrorModal,
|
||||
showSuccessModal,
|
||||
setSelectedModelId,
|
||||
)}
|
||||
data={modelData.data.map((model: any) => {
|
||||
const modelName = model.model_name;
|
||||
|
|
@ -568,6 +604,39 @@ const HealthCheckComponent: React.FC<HealthCheckComponentProps> = ({
|
|||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
{/* Success Modal */}
|
||||
<Modal
|
||||
title={selectedSuccessDetails ? `Health Check Response - ${selectedSuccessDetails.modelName}` : 'Response Details'}
|
||||
open={successModalVisible}
|
||||
onCancel={closeSuccessModal}
|
||||
footer={[
|
||||
<AntdButton key="close" onClick={closeSuccessModal}>
|
||||
Close
|
||||
</AntdButton>
|
||||
]}
|
||||
width={800}
|
||||
>
|
||||
{selectedSuccessDetails && (
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Text className="font-medium">Status:</Text>
|
||||
<div className="mt-2 p-3 bg-green-50 border border-green-200 rounded-md">
|
||||
<Text className="text-green-800">Health check passed successfully</Text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text className="font-medium">Response Details:</Text>
|
||||
<div className="mt-2 p-3 bg-gray-50 border border-gray-200 rounded-md max-h-96 overflow-y-auto">
|
||||
<pre className="text-sm text-gray-800 whitespace-pre-wrap">
|
||||
{JSON.stringify(selectedSuccessDetails.response, null, 2)}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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<HealthCheckData>[] => [
|
||||
{
|
||||
header: () => (
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={allModelsSelected}
|
||||
indeterminate={selectedModelsForHealth.length > 0 && !allModelsSelected}
|
||||
onChange={(e) => handleSelectAll(e.target.checked)}
|
||||
/>
|
||||
<Checkbox
|
||||
checked={allModelsSelected}
|
||||
indeterminate={selectedModelsForHealth.length > 0 && !allModelsSelected}
|
||||
onChange={(e) => handleSelectAll(e.target.checked)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
/>
|
||||
<span>Model ID</span>
|
||||
</div>
|
||||
),
|
||||
|
|
@ -63,10 +68,12 @@ export const healthCheckColumns = (
|
|||
<Checkbox
|
||||
checked={isSelected}
|
||||
onChange={(e) => handleModelSelection(modelName, e.target.checked)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
/>
|
||||
<Tooltip title={model.model_info.id}>
|
||||
<div
|
||||
className="font-mono text-blue-500 bg-blue-50 hover:bg-blue-100 text-xs font-normal px-2 py-0.5 text-left w-full truncate whitespace-nowrap cursor-pointer max-w-[15ch]"
|
||||
onClick={() => setSelectedModelId && setSelectedModelId(model.model_info.id)}
|
||||
>
|
||||
{model.model_info.id}
|
||||
</div>
|
||||
|
|
@ -131,9 +138,22 @@ export const healthCheckColumns = (
|
|||
);
|
||||
}
|
||||
|
||||
const modelName = model.model_name;
|
||||
const hasSuccessResponse = healthStatus.status === 'healthy' && modelHealthStatuses[modelName]?.successResponse;
|
||||
|
||||
return (
|
||||
<div className="flex items-center space-x-2">
|
||||
{getStatusBadge(healthStatus.status)}
|
||||
{hasSuccessResponse && showSuccessModal && (
|
||||
<Tooltip title="View response details" placement="top">
|
||||
<button
|
||||
onClick={() => showSuccessModal(modelName, modelHealthStatuses[modelName]?.successResponse)}
|
||||
className="p-1 text-green-600 hover:text-green-800 hover:bg-green-50 rounded cursor-pointer transition-colors"
|
||||
>
|
||||
<InformationCircleIcon className="h-4 w-4" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue