Add restart stage to AppUpdateProgress for enhanced update management. Implemented new status handling and UI updates to reflect restart progress, improving user feedback during application updates.
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good

This commit is contained in:
Tom Butcher 2026-06-21 21:57:42 +01:00
parent 65cc2cd8b5
commit 00cde6e8c5

View File

@ -4,6 +4,7 @@ import { Button, Flex, Modal, Progress, Typography, theme } from 'antd'
import CloudIcon from '../../../Icons/CloudIcon' import CloudIcon from '../../../Icons/CloudIcon'
import HostIcon from '../../../Icons/HostIcon' import HostIcon from '../../../Icons/HostIcon'
import ReloadIcon from '../../../Icons/ReloadIcon'
import CheckCircleIcon from '../../../Icons/CheckCircleIcon' import CheckCircleIcon from '../../../Icons/CheckCircleIcon'
import XMarkCircleIcon from '../../../Icons/XMarkCircleIcon' import XMarkCircleIcon from '../../../Icons/XMarkCircleIcon'
@ -45,6 +46,15 @@ const STAGE_CONFIG = {
complete: 'Installed', complete: 'Installed',
error: 'Install failed' error: 'Install failed'
} }
},
restart: {
icon: ReloadIcon,
labels: {
pending: 'Restart',
active: 'Restarting...',
complete: 'Restarted',
error: 'Restart failed'
}
} }
} }
@ -62,20 +72,25 @@ const getDownloadStageStatus = (phase, isError) => {
return 'pending' return 'pending'
} }
const getInstallStageStatus = (phase, isError, message) => { const isInstallComplete = (phase, message) =>
if (isError && ['downloaded', 'installing'].includes(phase)) return 'error'
if (
phase === 'installing' && phase === 'installing' &&
String(message || '') String(message || '')
.toLowerCase() .toLowerCase()
.includes('complete') .includes('complete')
) {
return 'complete' const getInstallStageStatus = (phase, isError, message) => {
} if (isError && ['downloaded', 'installing'].includes(phase)) return 'error'
if (isInstallComplete(phase, message)) return 'complete'
if (phase === 'installing') return 'active' if (phase === 'installing') return 'active'
return 'pending' return 'pending'
} }
const getRestartStageStatus = (phase, isError, message) => {
if (isError && isInstallComplete(phase, message)) return 'error'
if (isInstallComplete(phase, message)) return 'active'
return 'pending'
}
const getProgressStatus = (stageStatus) => { const getProgressStatus = (stageStatus) => {
if (stageStatus === 'error') return 'exception' if (stageStatus === 'error') return 'exception'
if (stageStatus === 'complete') return 'success' if (stageStatus === 'complete') return 'success'
@ -101,25 +116,19 @@ const UpdateStage = ({ stage, status, percent, detail }) => {
: StageIcon : StageIcon
return ( return (
<Flex align='center' gap='middle'> <Flex align='start' gap='middle' style={{ width: '100%' }}>
<StatusIcon style={{ fontSize: 20, color, flexShrink: 0 }} /> <StatusIcon style={{ fontSize: 22, color, flexShrink: 0 }} />
<Flex align='center' gap='small' style={{ flex: 1, minWidth: 0 }}> <Flex align='start' gap='24px' style={{ flex: 1, minWidth: 0 }}>
<Text style={{ flexShrink: 0, minWidth: 96 }}> <Text style={{ flexShrink: 0 }}>{config.labels[resolvedStatus]}</Text>
{config.labels[resolvedStatus]}
</Text>
{showProgress && ( {showProgress && (
<Flex vertical gap={4}> <Flex vertical gap={2} style={{ flex: 1 }}>
<Progress <Progress
percent={resolvedPercent} percent={resolvedPercent}
status={getProgressStatus(resolvedStatus)} status={getProgressStatus(resolvedStatus)}
showInfo={typeof resolvedPercent === 'number'} showInfo={typeof resolvedPercent === 'number'}
style={{ flex: 1, margin: 0 }} style={{ flex: 1, margin: 0 }}
/> />
{detail && ( {detail && <Text type='secondary'>{detail}</Text>}
<Text type='secondary' style={{ marginLeft: 36 }}>
{detail}
</Text>
)}
</Flex> </Flex>
)} )}
</Flex> </Flex>
@ -128,7 +137,7 @@ const UpdateStage = ({ stage, status, percent, detail }) => {
} }
UpdateStage.propTypes = { UpdateStage.propTypes = {
stage: PropTypes.oneOf(['download', 'install']).isRequired, stage: PropTypes.oneOf(['download', 'install', 'restart']).isRequired,
status: PropTypes.oneOf(['pending', 'active', 'complete', 'error']) status: PropTypes.oneOf(['pending', 'active', 'complete', 'error'])
.isRequired, .isRequired,
percent: PropTypes.number, percent: PropTypes.number,
@ -150,6 +159,7 @@ const AppUpdateProgress = ({ progress, update, onClose }) => {
const downloadStatus = getDownloadStageStatus(phase, isError) const downloadStatus = getDownloadStageStatus(phase, isError)
const installStatus = getInstallStageStatus(phase, isError, message) const installStatus = getInstallStageStatus(phase, isError, message)
const restartStatus = getRestartStageStatus(phase, isError, message)
const downloadPercent = const downloadPercent =
downloadStatus === 'active' ? (phase === 'preparing' ? 0 : percent) : null downloadStatus === 'active' ? (phase === 'preparing' ? 0 : percent) : null
@ -163,6 +173,8 @@ const AppUpdateProgress = ({ progress, update, onClose }) => {
const installDetail = installStatus === 'active' ? message : null const installDetail = installStatus === 'active' ? message : null
const restartDetail = restartStatus === 'active' ? message : null
return ( return (
<Flex vertical gap='middle'> <Flex vertical gap='middle'>
<Text> <Text>
@ -185,6 +197,11 @@ const AppUpdateProgress = ({ progress, update, onClose }) => {
percent={installPercent} percent={installPercent}
detail={installDetail} detail={installDetail}
/> />
<UpdateStage
stage='restart'
status={restartStatus}
detail={restartDetail}
/>
</Flex> </Flex>
<Modal <Modal