import React, { useState, useEffect } from 'react'; import { Modal, Stack, Text, Badge, Button, Group, Loader, Center, Divider, Box, Collapse } from '@mantine/core'; import { useTranslation } from 'react-i18next'; import { updateService, UpdateSummary, FullUpdateInfo, MachineInfo } from '@app/services/updateService'; import { Z_INDEX_OVER_CONFIG_MODAL } from '@app/styles/zIndex'; import WarningAmberIcon from '@mui/icons-material/WarningAmber'; import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'; import OpenInNewIcon from '@mui/icons-material/OpenInNew'; import DownloadIcon from '@mui/icons-material/Download'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ExpandLessIcon from '@mui/icons-material/ExpandLess'; interface UpdateModalProps { opened: boolean; onClose: () => void; currentVersion: string; updateSummary: UpdateSummary; machineInfo: MachineInfo; } const UpdateModal: React.FC = ({ opened, onClose, currentVersion, updateSummary, machineInfo, }) => { const { t } = useTranslation(); const [fullUpdateInfo, setFullUpdateInfo] = useState(null); const [loading, setLoading] = useState(true); const [expandedVersions, setExpandedVersions] = useState>(new Set([0])); useEffect(() => { if (opened) { setLoading(true); setExpandedVersions(new Set([0])); updateService.getFullUpdateInfo(currentVersion, machineInfo).then((info) => { setFullUpdateInfo(info); setLoading(false); }); } }, [opened, currentVersion, machineInfo]); const toggleVersion = (index: number) => { setExpandedVersions((prev) => { const newSet = new Set(prev); if (newSet.has(index)) { newSet.delete(index); } else { newSet.add(index); } return newSet; }); }; const getPriorityColor = (priority: string): string => { switch (priority?.toLowerCase()) { case 'urgent': return 'red'; case 'normal': return 'blue'; case 'minor': return 'cyan'; case 'low': return 'gray'; default: return 'gray'; } }; const getPriorityLabel = (priority: string): string => { const key = priority?.toLowerCase(); return t(`update.priority.${key}`, priority || 'Normal'); }; const downloadUrl = updateService.getDownloadUrl(machineInfo); return ( {t('update.modalTitle', 'Update Available')} } centered size="xl" zIndex={Z_INDEX_OVER_CONFIG_MODAL} styles={{ body: { maxHeight: '75vh', overflowY: 'auto', }, }} > {/* Version Summary Section */} {t('update.current', 'Current Version')} {currentVersion} {t('update.priorityLabel', 'Priority')} {getPriorityLabel(updateSummary.max_priority)} {t('update.latest', 'Latest Version')} {updateSummary.latest_version} {updateSummary.latest_stable_version && ( {t('update.latestStable', 'Latest Stable')}: {updateSummary.latest_stable_version} )} {/* Recommended action */} {updateSummary.recommended_action && ( {t('update.recommendedAction', 'Recommended Action')} {updateSummary.recommended_action} )} {/* Breaking changes warning */} {updateSummary.any_breaking && ( {t('update.breakingChangesDetected', 'Breaking Changes Detected')} {t( 'update.breakingChangesMessage', 'Some versions contain breaking changes. Please review the migration guides below before updating.' )} )} {/* Migration guides */} {updateSummary.migration_guides && updateSummary.migration_guides.length > 0 && ( <> {t('update.migrationGuides', 'Migration Guides')} {updateSummary.migration_guides.map((guide, idx) => ( {t('update.version', 'Version')} {guide.version} {guide.notes} ))} )} {/* Version details */} {loading ? (
{t('update.loadingDetailedInfo', 'Loading detailed information...')}
) : fullUpdateInfo && fullUpdateInfo.new_versions && fullUpdateInfo.new_versions.length > 0 ? ( {t('update.availableUpdates', 'Available Updates')} {fullUpdateInfo.new_versions.length} {fullUpdateInfo.new_versions.length === 1 ? 'version' : 'versions'} {fullUpdateInfo.new_versions.map((version, index) => { const isExpanded = expandedVersions.has(index); return ( toggleVersion(index)} > {t('update.version', 'Version')} {version.version} {getPriorityLabel(version.priority)} {isExpanded ? ( ) : ( )} {version.announcement.title} {version.announcement.message} {version.compatibility.breaking_changes && ( {t('update.breakingChanges', 'Breaking Changes')} {version.compatibility.breaking_description || t('update.breakingChangesDefault', 'This version contains breaking changes.')} {version.compatibility.migration_guide_url && ( )} )} ); })} ) : null} {/* Action buttons */} {downloadUrl && ( )}
); }; export default UpdateModal;