feat(xo-web/metadata-backup): add pool selection for restoration (#6670)
See #6664
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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 =>
|
||||
|
||||
@@ -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 =>
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user