import React, { useState } from 'react';
import {
Box,
Typography,
Card,
Chip,
Button,
Alert,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Snackbar,
} from '@mui/material';
import { CloudDownload as CloudDownloadIcon, Trash2 as DeleteIcon } from 'lucide-react';
import api from '../api';
import { checkpointManagerStyles } from '../theme';
export default function CheckpointManager({ model, onRefresh }) {
const [loadingStates, setLoadingStates] = useState({});
const [error, setError] = useState(null);
const [deleteTarget, setDeleteTarget] = useState(null);
const [toast, setToast] = useState({
open: false,
message: '',
severity: 'success'
});
const handleUnwrapCheckpoint = async (checkpoint) => {
const checkpointId = checkpoint.path;
setLoadingStates(prev => ({ ...prev, [checkpointId]: { unwrapping: true } }));
setError(null);
try {
await api.post('/api/unwrap-model', {
model_config: model.config_path,
ckpt_path: checkpoint.path,
name: `${checkpoint.name}_unwrapped`
});
setError(null);
setToast({
open: true,
message: `Checkpoint "${checkpoint.name}" unwrapped successfully.`,
severity: 'success'
});
onRefresh();
} catch (err) {
setError(`Failed to unwrap ${checkpoint.name}: ${err.response?.data?.error || err.message}`);
} finally {
setLoadingStates(prev => ({ ...prev, [checkpointId]: { unwrapping: false } }));
}
};
const handleDeleteCheckpoint = async () => {
if (!deleteTarget) {
return;
}
const checkpointId = deleteTarget.path;
setLoadingStates(prev => ({ ...prev, [checkpointId]: { deleting: true } }));
setError(null);
try {
await api.post('/api/delete-checkpoint', {
checkpoint_path: deleteTarget.path
});
setToast({
open: true,
message: `Checkpoint "${deleteTarget.name}" deleted successfully.`,
severity: 'success'
});
onRefresh();
} catch (err) {
setError(`Failed to delete ${deleteTarget.name}: ${err.response?.data?.error || err.message}`);
} finally {
setDeleteTarget(null);
setLoadingStates(prev => ({ ...prev, [checkpointId]: { deleting: false } }));
}
};
const closeToast = (_, reason) => {
if (reason === 'clickaway') {
return;
}
setToast(prev => ({ ...prev, open: false }));
};
const checkpoints = model.checkpoints || [];
return (
<>
Checkpoints ({checkpoints.length})
{checkpoints.length === 0 ? (
No checkpoints yet.
) : (
{checkpoints.map((checkpoint, index) => {
const checkpointId = checkpoint.path;
const isUnwrapping = loadingStates[checkpointId]?.unwrapping;
const isDeleting = loadingStates[checkpointId]?.deleting;
const hasUnwrappedVersion = model.unwrapped_models?.some(unwrapped =>
unwrapped.name.includes(checkpoint.name) ||
checkpoint.name.includes(unwrapped.name.replace('_unwrapped', ''))
);
return (
{checkpoint.name}
{hasUnwrappedVersion && (
)}
{checkpoint.size_mb} MB
{!hasUnwrappedVersion && (
}
onClick={() => handleUnwrapCheckpoint(checkpoint)}
disabled={isUnwrapping || isDeleting}
>
{isUnwrapping ? 'Unwrapping...' : 'Unwrap'}
)}
{hasUnwrappedVersion && (
}
onClick={() => setDeleteTarget(checkpoint)}
disabled={isDeleting || isUnwrapping}
>
{isDeleting ? 'Deleting...' : 'Delete'}
)}
);
})}
)}
{error && (
{error}
)}
{toast.message}
>
);
}