diff --git a/src/common/intl/messages.js b/src/common/intl/messages.js index fdb2fb1fc..302f3671d 100644 --- a/src/common/intl/messages.js +++ b/src/common/intl/messages.js @@ -641,12 +641,22 @@ var messages = { xsTasks: 'Currently, there isn\'t any pending XenServer tasks', // ---- Backup views --- + listRemote: 'List Remote', + simpleBackup: 'simple', delta: 'delta', restoreBackups: 'Restore Backups', noRemotes: 'No remotes', remoteEnabled: 'enabled', remoteError: 'error', - noBackup: 'No backups available', + noBackup: 'No backup available', + backupVmNameColumn: 'VM Name', + backupTagColumn: 'Backup Tag', + lastBackupColumn: 'Last Backup', + availableBackupsColumn: 'Available Backups', + restoreColumn: 'Restore', + restoreTip: 'Restore VM', + importBackupTitle: 'Import VM', + importBackupMessage: 'Starting your backup import', // ----- Modals ----- startVmsModalTitle: 'Start VM{vms, plural, one {} other {s}}', diff --git a/src/common/xo/index.js b/src/common/xo/index.js index 430eba4ab..69a586d10 100644 --- a/src/common/xo/index.js +++ b/src/common/xo/index.js @@ -939,6 +939,8 @@ export const editRemote = (remote, {name, url}) => ( export const listRemote = id => ( call('remote.list', {id})::tap( subscribeRemotes.forceRefresh + )::rethrow( + err => error(_('listRemote'), err.message || String(err)) ) ) diff --git a/src/xo-app/backup/restore/index.js b/src/xo-app/backup/restore/index.js index 828b436db..e2fa38501 100644 --- a/src/xo-app/backup/restore/index.js +++ b/src/xo-app/backup/restore/index.js @@ -1,4 +1,4 @@ -import _ from 'intl' +import _, { messages } from 'intl' import ActionButton from 'action-button' import ActionRowButton from 'action-row-button' import find from 'lodash/find' @@ -17,7 +17,7 @@ import { confirm } from 'modal' import { connectStore } from 'utils' import { Container } from 'grid' import { createGetObjectsOfType } from 'selectors' -import { FormattedDate } from 'react-intl' +import { FormattedDate, injectIntl } from 'react-intl' import { info, error } from 'notification' import { SelectPlainObject, Toggle } from 'form' import { SelectSr } from 'select-objects' @@ -32,7 +32,7 @@ import { const parseDate = date => +moment(date, 'YYYYMMDDTHHmmssZ').format('x') -const isEmptyRemote = remote => !remote.lastVmbackups || !size(remote.lastVmbackups) +const isEmptyRemote = remote => !remote.backupInfoByVm || !size(remote.backupInfoByVm) const backupOptionRenderer = backup => {backup.type === 'delta' && {_('delta')}{' '}} @@ -61,7 +61,7 @@ export default class Restore extends Component { remotes: orderBy(map(rawRemotes, r => { r = {...r} const older = find(remotes, {id: r.id}) - older && older.lastVmbackups && (r.backups = older.lastVmbackups) + older && older.backupInfoByVm && (r.backupInfoByVm = older.backupInfoByVm) return r }), ['name']) }) @@ -69,17 +69,11 @@ export default class Restore extends Component { } _list = async id => { - let files - try { - files = await listRemote(id) - } catch (err) { - error('List Remote', err.message || String(err)) - return - } + const files = await listRemote(id) const { remotes } = this.state const remote = find(remotes, {id}) if (remote) { - const lastVmbackups = {} + const backupInfoByVm = {} forEach(files, file => { let backup const deltaInfo = /^vm_delta_(.*)_([^\/]+)\/([^_]+)_(.*)$/.exec(file) @@ -108,14 +102,18 @@ export default class Restore extends Component { } } } - lastVmbackups[backup.name] || (lastVmbackups[backup.name] = []) - lastVmbackups[backup.name].push(backup) + backupInfoByVm[backup.name] || (backupInfoByVm[backup.name] = []) + backupInfoByVm[backup.name].push(backup) }) - for (let vm in lastVmbackups) { - const bks = lastVmbackups[vm] - lastVmbackups[vm] = reduce(bks, (last, b) => b.date > last.date ? b : last) + for (let vm in backupInfoByVm) { + const bks = backupInfoByVm[vm] + backupInfoByVm[vm] = { + last: reduce(bks, (last, b) => b.date > last.date ? b : last), + simpleCount: reduce(bks, (sum, b) => b.type === 'simple' ? ++sum : sum, 0), + deltaCount: reduce(bks, (sum, b) => b.type === 'delta' ? ++sum : sum, 0) + } } - remote.lastVmbackups = map(lastVmbackups) + remote.backupInfoByVm = map(backupInfoByVm) } this.setState({remotes}) } @@ -138,11 +136,11 @@ export default class Restore extends Component { - {r.lastVmbackups &&
+ {r.backupInfoByVm &&

{isEmptyRemote(r) ? {_('noBackup')} - : + : }
}
@@ -155,7 +153,6 @@ export default class Restore extends Component { const openImportModal = backup => confirm({ title: _('importBackupModalTitle', {name: backup.name}), - // title: `Import a ${backup.name} Backup`, body: }).then(doImport) @@ -183,40 +180,43 @@ const doImport = ({ backup, remoteId, sr, start }) => { const BK_COLUMNS = [ { - name: 'VM name', - itemRenderer: bk => bk.name, - sortCriteria: bk => bk.name + name: _('backupVmNameColumn'), + itemRenderer: info => info.last.name, + sortCriteria: info => info.last.name }, { - name: 'Backup Tag', - itemRenderer: bk => bk.tag, - sortCriteria: bk => bk.tag + name: _('backupTagColumn'), + itemRenderer: info => info.last.tag, + sortCriteria: info => info.last.tag }, { - name: 'Last Backup date', - itemRenderer: bk => , - sortCriteria: bk => bk.date + name: _('lastBackupColumn'), + itemRenderer: info => ({info.last.type}), + sortCriteria: info => info.last.date }, { - name: 'Backup Type', - itemRenderer: bk => bk.type, - sortCriteria: bk => bk.type + name: _('availableBackupsColumn'), + itemRenderer: info => + {!!info.simpleCount && simple {info.simpleCount}} + {' '} + {!!info.deltaCount && simple {info.deltaCount}} + }, { - name: 'Action', - itemRenderer: bk => + name: _('restoreColumn'), + itemRenderer: info => } ] const srWritablePredicate = sr => sr.content_type !== 'iso' -const notifyImportStart = () => info('VM import', 'Starting your backup import') +const notifyImportStart = () => info(_('importBackupTitle'), _('importBackupMessage')) @connectStore(() => ({ writableSrs: createGetObjectsOfType('SR').filter( [ sr => sr.content_type !== 'iso' ] ).sort() }), { withRef: true }) -class ImportModalBody extends Component { +class _ModalBody extends Component { constructor (props) { super(props) this.state = {} @@ -276,9 +276,11 @@ class ImportModalBody extends Component { return

- +
{_('importBackupModalStart')}
} } + +const ImportModalBody = injectIntl(_ModalBody, {withRef: true})