feat(xo-web/metadata-backup): add pool selection for restoration (#6670)

See #6664
This commit is contained in:
Gabriel Gunullu
2023-02-27 10:21:49 +01:00
committed by GitHub
parent e6c95a0913
commit 73c0cd6934
4 changed files with 53 additions and 26 deletions

View File

@@ -12,6 +12,7 @@
- [Plugin/auth-oidc] [OpenID Connect](<https://en.wikipedia.org/wiki/OpenID#OpenID_Connect_(OIDC)>) authentication plugin [#6641](https://github.com/vatesfr/xen-orchestra/issues/6641) (PR [#6684](https://github.com/vatesfr/xen-orchestra/issues/6684))
- [REST API] Possibility to start, shutdown, reboot and snapshot VMs
- [Import VM] Ability to import a VM from ESXi (PR [#6663](https://github.com/vatesfr/xen-orchestra/pull/6663))
- [Backup Metadata] Add pool selection to metadata restoration (PR [#6670](https://github.com/vatesfr/xen-orchestra/pull/6670))
### Bug fixes

View File

@@ -2446,9 +2446,10 @@ export const runMetadataBackupJob = params => _call('metadataBackup.runJob', par
export const listMetadataBackups = remotes => _call('metadataBackup.list', { remotes: resolveIds(remotes) })
export const restoreMetadataBackup = backup =>
export const restoreMetadataBackup = data =>
_call('metadataBackup.restore', {
id: resolveId(backup),
id: resolveId(data.backup),
pool: data.pool,
})::tap(subscribeBackupNgLogs.forceRefresh)
export const deleteMetadataBackup = backup =>

View File

@@ -13,7 +13,7 @@ import { error } from 'notification'
import { filter, flatMap, forOwn, reduce } from 'lodash'
import { FormattedDate } from 'react-intl'
import { injectState, provideState } from 'reaclette'
import { noop } from 'utils'
import { noop, resolveId } from 'utils'
import { deleteMetadataBackups, listMetadataBackups, restoreMetadataBackup, subscribeRemotes } from 'xo'
import Logs from '../../logs/restore-metadata'
@@ -32,21 +32,29 @@ const restore = entry =>
}),
body: <RestoreMetadataBackupModalBody backups={entry.backups} type={entry.type} />,
icon: 'restore',
}).then(backup => {
if (backup === undefined) {
}).then(data => {
if (data === undefined) {
error(_('backupRestoreErrorTitle'), _('chooseBackup'))
return
}
return restoreMetadataBackup(backup)
return restoreMetadataBackup({ backup: resolveId(data.backup), pool: resolveId(data.pool) })
}, noop)
const bulkRestore = entries => {
const nMetadataBackups = entries.length
return confirm({
title: _('bulkRestoreMetadataBackupTitle', { nMetadataBackups }),
body: <RestoreMetadataBackupsBulkModalBody nMetadataBackups={nMetadataBackups} />,
body: <RestoreMetadataBackupsBulkModalBody nMetadataBackups={nMetadataBackups} poolMetadataBackups={entries} />,
icon: 'restore',
}).then(latest => Promise.all(entries.map(({ first, last }) => restoreMetadataBackup(latest ? last : first))), noop)
}).then(
data =>
Promise.all(
entries.map(({ first, last, id }) =>
restoreMetadataBackup({ backup: data.latest ? last : first, pool: resolveId(data[id]) })
)
),
noop
)
}
const delete_ = entry =>

View File

@@ -5,9 +5,10 @@ import PropTypes from 'prop-types'
import React from 'react'
import SingleLineRow from 'single-line-row'
import StateButton from 'state-button'
import { Container, Col } from 'grid'
import { Container, Col, Row } from 'grid'
import { FormattedDate } from 'react-intl'
import { Select } from 'form'
import { SelectPool } from 'select-objects'
const restorationWarning = (
<p className='text-warning mt-1'>
@@ -22,7 +23,7 @@ export default class RestoreMetadataBackupModalBody extends Component {
}
get value() {
return this.state.backup
return this.state
}
_optionRenderer = ({ timestamp }) => (
@@ -40,7 +41,7 @@ export default class RestoreMetadataBackupModalBody extends Component {
render() {
return (
<Container>
<SingleLineRow>
<Row>
<Col size={6}>{_('chooseBackup')}</Col>
<Col size={6}>
<Select
@@ -53,7 +54,10 @@ export default class RestoreMetadataBackupModalBody extends Component {
valueKey='id'
/>
</Col>
</SingleLineRow>
</Row>
<Row className='mt-1'>
<SelectPool onChange={this.linkState('pool')} required value={this.state.pool} />
</Row>
{this.props.type !== 'XO' && <SingleLineRow>{restorationWarning}</SingleLineRow>}
</Container>
)
@@ -63,30 +67,43 @@ export default class RestoreMetadataBackupModalBody extends Component {
export class RestoreMetadataBackupsBulkModalBody extends Component {
static propTypes = {
nMetadataBackups: PropTypes.number,
poolMetadataBackups: PropTypes.array,
}
state = { latest: true }
get value() {
return this.state.latest
return this.state
}
render() {
return (
<div>
{_('bulkRestoreMetadataBackupMessage', {
nMetadataBackups: this.props.nMetadataBackups,
oldestOrLatest: (
<StateButton
disabledLabel={_('oldest')}
enabledLabel={_('latest')}
handler={this.toggleState('latest')}
state={this.state.latest}
/>
),
})}
<Container>
<Row>
{_('bulkRestoreMetadataBackupMessage', {
nMetadataBackups: this.props.nMetadataBackups,
oldestOrLatest: (
<StateButton
disabledLabel={_('oldest')}
enabledLabel={_('latest')}
handler={this.toggleState('latest')}
state={this.state.latest}
/>
),
})}
</Row>
{this.props.poolMetadataBackups.map(value => (
<Container key={value.id} className='mt-1'>
<SingleLineRow>
<Col size={6}>{value.first.jobName}</Col>
<Col size={6}>
<SelectPool onChange={this.linkState(value.id)} required value={this.state[value.id]} />
</Col>
</SingleLineRow>
</Container>
))}
{restorationWarning}
</div>
</Container>
)
}
}