chore(xo-web/xoa/update): rewrite (#3620)

This commit is contained in:
Julien Fontanet
2018-10-31 09:46:44 +01:00
committed by GitHub
parent 675763d039
commit 02dddbd662
7 changed files with 454 additions and 465 deletions

View File

@@ -97,7 +97,7 @@
"promise-toolbox": "^0.10.1",
"prop-types": "^15.6.0",
"random-password": "^0.1.2",
"reaclette": "^0.6.0",
"reaclette": "^0.7.0",
"react": "^15.4.1",
"react-addons-shallow-compare": "^15.6.2",
"react-addons-test-utils": "^15.6.2",

View File

@@ -39,14 +39,17 @@ export const updatePermissions = createAction(
export const signedIn = createAction('SIGNED_IN', user => user)
export const signedOut = createAction('SIGNED_OUT')
export const xoaUpdaterState = createAction('XOA_UPDATER_STATE', state => state)
export const xoaTrialState = createAction('XOA_TRIAL_STATE', state => state)
export const xoaUpdaterLog = createAction('XOA_UPDATER_LOG', log => log)
export const xoaRegisterState = createAction(
export const setXoaUpdaterState = createAction(
'XOA_UPDATER_STATE',
state => state
)
export const setXoaTrialState = createAction('XOA_TRIAL_STATE', state => state)
export const setXoaUpdaterLog = createAction('XOA_UPDATER_LOG', log => log)
export const setXoaRegisterState = createAction(
'XOA_REGISTER_STATE',
registration => registration
)
export const xoaConfiguration = createAction(
export const setXoaConfiguration = createAction(
'XOA_CONFIGURATION',
configuration => configuration
)

View File

@@ -136,28 +136,28 @@ export default {
}),
xoaUpdaterState: combineActionHandlers('disconnected', {
[actions.xoaUpdaterState]: (_, state) => state,
[actions.setXoaUpdaterState]: (_, state) => state,
}),
xoaTrialState: combineActionHandlers(
{},
{
[actions.xoaTrialState]: (_, state) => state,
[actions.setXoaTrialState]: (_, state) => state,
}
),
xoaUpdaterLog: combineActionHandlers([], {
[actions.xoaUpdaterLog]: (_, log) => log,
[actions.setXoaUpdaterLog]: (_, log) => log,
}),
xoaRegisterState: combineActionHandlers(
{ state: '?' },
{
[actions.xoaRegisterState]: (_, registration) => registration,
[actions.setXoaRegisterState]: (_, registration) => registration,
}
),
xoaConfiguration: combineActionHandlers(
{ proxyHost: '', proxyPort: '', proxyUser: '' },
{
// defined values for controlled inputs
[actions.xoaConfiguration]: (_, configuration) => {
[actions.setXoaConfiguration]: (_, configuration) => {
delete configuration.password
return configuration
},

View File

@@ -18,6 +18,7 @@ import {
keys,
map,
mapValues,
pick,
replace,
sample,
some,
@@ -69,6 +70,11 @@ export const propsEqual = (o1, o2, props) => {
// ===================================================================
const _normalizeMapStateToProps = mapper => {
// accept a list of entries to extract from the state
if (Array.isArray(mapper)) {
return state => pick(state, mapper)
}
if (isFunction(mapper)) {
const factoryOrMapper = (state, props) => {
const result = mapper(state, props)

View File

@@ -9,11 +9,11 @@ import makeError from 'make-error'
import map from 'lodash/map'
import { EventEmitter } from 'events'
import {
xoaConfiguration,
xoaRegisterState,
xoaTrialState,
xoaUpdaterLog,
xoaUpdaterState,
setXoaConfiguration,
setXoaRegisterState,
setXoaTrialState,
setXoaUpdaterLog,
setXoaUpdaterState,
} from 'store/actions'
// ===================================================================
@@ -406,14 +406,14 @@ export default xoaUpdater
export const connectStore = store => {
forEach(states, state =>
xoaUpdater.on(state, () => store.dispatch(xoaUpdaterState(state)))
xoaUpdater.on(state, () => store.dispatch(setXoaUpdaterState(state)))
)
xoaUpdater.on('trialState', state => store.dispatch(xoaTrialState(state)))
xoaUpdater.on('log', log => store.dispatch(xoaUpdaterLog(log)))
xoaUpdater.on('trialState', state => store.dispatch(setXoaTrialState(state)))
xoaUpdater.on('log', log => store.dispatch(setXoaUpdaterLog(log)))
xoaUpdater.on('registerState', registration =>
store.dispatch(xoaRegisterState(registration))
store.dispatch(setXoaRegisterState(registration))
)
xoaUpdater.on('configuration', configuration =>
store.dispatch(xoaConfiguration(configuration))
store.dispatch(setXoaConfiguration(configuration))
)
}

View File

@@ -2,19 +2,21 @@ import _, { messages } from 'intl'
import ActionButton from 'action-button'
import AnsiUp from 'ansi_up'
import Button from 'button'
import Component from 'base-component'
import decorate from 'apply-decorators'
import defined from '@xen-orchestra/defined'
import Icon from 'icon'
import React from 'react'
import Tooltip from 'tooltip'
import xoaUpdater, { exposeTrial, isTrialRunning } from 'xoa-updater'
import { addSubscriptions, connectStore } from 'utils'
import { assign, includes, isEmpty, map, some } from 'lodash'
import { Card, CardBlock, CardHeader } from 'card'
import { confirm } from 'modal'
import { Container, Row, Col } from 'grid'
import { createSelector } from 'selectors'
import { error } from 'notification'
import { injectIntl } from 'react-intl'
import { injectState, provideState } from 'reaclette'
import { isEmpty, map, pick, some, zipObject } from 'lodash'
import { linkState, toggleState } from 'reaclette-utils'
import { Password } from 'form'
import { serverVersion, subscribeBackupNgJobs, subscribeJobs } from 'xo'
@@ -22,472 +24,450 @@ import pkg from '../../../../package'
const ansiUp = new AnsiUp()
let updateSource
const promptForReload = (source, force) => {
if (force || (updateSource && source !== updateSource)) {
confirm({
title: _('promptUpgradeReloadTitle'),
body: <p>{_('promptUpgradeReloadMessage')}</p>,
}).then(() => window.location.reload())
}
updateSource = source
}
if (+process.env.XOA_PLAN < 5) {
xoaUpdater.start()
let updateSource
const promptForReload = (source, force) => {
if (force || (updateSource && source !== updateSource)) {
confirm({
title: _('promptUpgradeReloadTitle'),
body: <p>{_('promptUpgradeReloadMessage')}</p>,
}).then(() => window.location.reload())
}
updateSource = source
}
xoaUpdater.on('upgradeSuccessful', source => promptForReload(source, !source))
xoaUpdater.on('upToDate', promptForReload)
}
// FIXME: can't translate
const states = {
const LABELS_BY_STATE = {
disconnected: 'Disconnected',
error: 'An error occured',
registerNeeded: 'Registration required',
updating: 'Updating',
upgradeNeeded: 'Upgrade required',
upgrading: 'Upgrading',
upToDate: 'Up to Date',
upgradeNeeded: 'Upgrade required',
registerNeeded: 'Registration required',
error: 'An error occured',
}
const update = () => xoaUpdater.update()
const upgrade = ({ runningJobsExist }) =>
runningJobsExist
? confirm({
title: _('upgradeWarningTitle'),
body: _('upgradeWarningMessage'),
}).then(() => xoaUpdater.upgrade())
: xoaUpdater.upgrade()
const LEVELS_TO_CLASSES = {
info: 'text-info',
success: 'text-success',
warning: 'text-warning',
error: 'text-danger',
}
@addSubscriptions({
backupNgJobs: subscribeBackupNgJobs,
jobs: subscribeJobs,
})
@connectStore(state => {
return {
configuration: state.xoaConfiguration,
log: state.xoaUpdaterLog,
registration: state.xoaRegisterState,
state: state.xoaUpdaterState,
trial: state.xoaTrialState,
}
})
@injectIntl
export default class XoaUpdates extends Component {
// These 3 inputs are "controlled" http://facebook.github.io/react/docs/forms.html#controlled-components
_handleProxyHostChange = event =>
this.setState({ proxyHost: event.target.value || '' })
_handleProxyPortChange = event =>
this.setState({ proxyPort: event.target.value || '' })
_handleProxyUserChange = event =>
this.setState({ proxyUser: event.target.value || '' })
const PROXY_ENTRIES = ['proxyHost', 'proxyPassword', 'proxyPort', 'proxyUser']
const initialProxyState = () => zipObject(PROXY_ENTRIES)
_handleConfigReset = () => {
const { configuration } = this.props
const { proxyPassword } = this.refs
proxyPassword.value = ''
this.setState(configuration)
}
const REGISTRATION_ENTRIES = ['email', 'password']
const initialRegistrationState = () => zipObject(REGISTRATION_ENTRIES)
_register = async () => {
const { email, password } = this.state
const helper = (obj1, obj2, prop) =>
defined(() => obj1[prop], () => obj2[prop], '')
const { registration } = this.props
const alreadyRegistered = registration.state === 'registered'
const Updates = decorate([
addSubscriptions({
backupNgJobs: subscribeBackupNgJobs,
jobs: subscribeJobs,
}),
connectStore([
'xoaConfiguration',
'xoaRegisterState',
'xoaTrialState',
'xoaUpdaterLog',
'xoaUpdaterState',
]),
provideState({
initialState: () => ({
...initialProxyState(),
...initialRegistrationState(),
askRegisterAgain: false,
}),
effects: {
async configure () {
await xoaUpdater.configure(
pick(this.state, [
'proxyHost',
'proxyPassword',
'proxyPort',
'proxyUser',
])
)
return this.effects.resetProxyConfig()
},
initialize () {
return this.effects.update()
},
linkState,
async register () {
const { state } = this
if (alreadyRegistered) {
try {
await confirm({
title: _('alreadyRegisteredModal'),
body: (
<p>
{_('alreadyRegisteredModalText', { email: registration.email })}
</p>
),
})
} catch (error) {
return
}
}
this.setState({ askRegisterAgain: false })
return xoaUpdater
.register(email, password, alreadyRegistered)
.then(() => this.setState({ email: '', password: '' }))
}
_configure = async () => {
const { proxyHost, proxyPort, proxyUser } = this.state
const { proxyPassword } = this.refs
return xoaUpdater
.configure({
proxyHost,
proxyPort,
proxyUser,
proxyPassword: proxyPassword.value,
})
.then(config => {
this.setState({
proxyHost: undefined,
proxyPort: undefined,
proxyUser: undefined,
})
proxyPassword.value = ''
})
}
_trialAllowed = trial => trial.state === 'default' && exposeTrial(trial.trial)
_trialAvailable = trial =>
trial.state === 'default' && isTrialRunning(trial.trial)
_trialConsumed = trial =>
trial.state === 'default' &&
!isTrialRunning(trial.trial) &&
!exposeTrial(trial.trial)
_updaterDown = trial => isEmpty(trial) || trial.state === 'ERROR'
_toggleAskRegisterAgain = () =>
this.setState({ askRegisterAgain: !this.state.askRegisterAgain })
_startTrial = async () => {
try {
await confirm({
title: _('trialReadyModal'),
body: <p>{_('trialReadyModalText')}</p>,
})
return xoaUpdater
.requestTrial()
.then(() => xoaUpdater.update())
.catch(err => error('Request Trial', err.message || String(err)))
} catch (_) {}
}
componentWillMount () {
this.setState({ askRegisterAgain: false })
serverVersion.then(serverVersion => {
this.setState({ serverVersion })
})
update()
}
_getRunningJobsExist = createSelector(
() => this.props.jobs,
() => this.props.backupNgJobs,
(jobs, backupNgJobs) =>
jobs !== undefined &&
backupNgJobs !== undefined &&
some(jobs.concat(backupNgJobs), job => job.runId !== undefined)
)
render () {
const textClasses = {
info: 'text-info',
success: 'text-success',
warning: 'text-warning',
error: 'text-danger',
}
const { log, registration, state, trial } = this.props
let { configuration } = this.props // Configuration from the store
const alreadyRegistered = registration.state === 'registered'
configuration = assign({}, configuration)
const { proxyHost, proxyPort, proxyUser } = this.state // Edited non-saved configuration values override in view
let configEdited = false
proxyHost !== undefined &&
(configuration.proxyHost = proxyHost) &&
(configEdited = true)
proxyPort !== undefined &&
(configuration.proxyPort = proxyPort) &&
(configEdited = true)
proxyUser !== undefined &&
(configuration.proxyUser = proxyUser) &&
(configEdited = true)
const { formatMessage } = this.props.intl
return (
<Container>
<Row>
<Col mediumSize={12}>
<Card>
<CardHeader>
<UpdateTag /> {states[state]}
</CardHeader>
<CardBlock>
const { isRegistered } = state
if (isRegistered) {
try {
await confirm({
title: _('alreadyRegisteredModal'),
body: (
<p>
{_('currentVersion')}{' '}
{`xo-server ${this.state.serverVersion}`} /{' '}
{`xo-web ${pkg.version}`}
{_('alreadyRegisteredModalText', {
email: this.props.registration.email,
})}
</p>
{includes(['error', 'disconnected'], state) && (
<p>
<a href='https://xen-orchestra.com/docs/updater.html#troubleshooting'>
{_('updaterTroubleshootingLink')}
</a>
),
})
} catch (_) {
return
}
}
state.askRegisterAgain = false
const { email, password } = state
await xoaUpdater.register(email, password, isRegistered)
return initialRegistrationState()
},
resetProxyConfig: initialProxyState,
async startTrial () {
try {
await confirm({
title: _('trialReadyModal'),
body: <p>{_('trialReadyModalText')}</p>,
})
} catch (_) {
return
}
try {
await xoaUpdater.requestTrial()
await xoaUpdater.update()
} catch (err) {
error('Request Trial', err.message || String(err))
}
},
toggleState,
update: () => xoaUpdater.update(),
upgrade: () => xoaUpdater.upgrade(),
},
computed: {
areJobsRunning: (_, { jobs, backupNgJobs }) =>
jobs !== undefined &&
backupNgJobs !== undefined &&
some(jobs.concat(backupNgJobs), job => job.runId !== undefined),
isDisconnected: (_, { xoaUpdaterState }) =>
xoaUpdater === 'disconnected' || xoaUpdaterState === 'error',
isProxyConfigEdited: state =>
PROXY_ENTRIES.some(entry => state[entry] !== undefined),
isRegistered: (_, { xoaRegisterState }) =>
xoaRegisterState.state === 'register',
isTrialAllowed: (_, { xoaTrialState }) =>
xoaTrialState.state === 'default' && exposeTrial(xoaTrialState.trial),
isTrialAvailable: (_, { xoaTrialState }) =>
xoaTrialState.state === 'default' &&
isTrialRunning(xoaTrialState.trial),
isTrialConsumed: (_, { xoaTrialState }) =>
xoaTrialState.state === 'default' &&
!isTrialRunning(xoaTrialState.trial) &&
!exposeTrial(xoaTrialState.trial),
isUpdaterDown: (_, { xoaTrialState }) =>
isEmpty(xoaTrialState) || xoaTrialState.state === 'ERROR',
serverVersion: () => serverVersion,
},
}),
injectState,
injectIntl,
({
effects,
intl: { formatMessage },
state,
xoaConfiguration,
xoaRegisterState,
xoaTrialState,
xoaUpdaterLog,
xoaUpdaterState,
}) => (
<Container>
<Row>
<Col mediumSize={12}>
<Card>
<CardHeader>
<UpdateTag /> {LABELS_BY_STATE[xoaUpdaterState]}
</CardHeader>
<CardBlock>
<p>
{_('currentVersion')} {`xo-server ${state.serverVersion}`} /{' '}
{`xo-web ${pkg.version}`}
</p>
{state.isDisconnected && (
<p>
<a href='https://xen-orchestra.com/docs/updater.html#troubleshooting'>
{_('updaterTroubleshootingLink')}
</a>
</p>
)}
<ActionButton
btnStyle='info'
handler={effects.update}
icon='refresh'
>
{_('refresh')}
</ActionButton>{' '}
<ActionButton
btnStyle='success'
data-runningJobsExist={state.areJobsRunning}
disabled={xoaUpdaterState !== 'upgradeNeeded'}
handler={effects.upgrade}
icon='upgrade'
>
{xoaTrialState.state !== 'untrustedTrial'
? _('upgrade')
: _('downgrade')}
</ActionButton>
<hr />
<div>
{map(xoaUpdaterLog, (log, key) => (
<p key={key}>
<span className={LEVELS_TO_CLASSES[log.level]}>
{log.date}
</span>
:{' '}
<span
dangerouslySetInnerHTML={{
__html: ansiUp.ansi_to_html(log.message),
}}
/>
</p>
)}
<ActionButton btnStyle='info' handler={update} icon='refresh'>
{_('refresh')}
</ActionButton>{' '}
<ActionButton
btnStyle='success'
data-runningJobsExist={this._getRunningJobsExist()}
disabled={state !== 'upgradeNeeded'}
handler={upgrade}
icon='upgrade'
>
{trial.state !== 'untrustedTrial'
? _('upgrade')
: _('downgrade')}
</ActionButton>
<hr />
<div>
{map(log, (log, key) => (
<p key={key}>
<span className={textClasses[log.level]}>{log.date}</span>
:{' '}
<span
dangerouslySetInnerHTML={{
__html: ansiUp.ansi_to_html(log.message),
}}
/>
</p>
))}
</div>
</CardBlock>
</Card>
</Col>
</Row>
<Row>
<Col mediumSize={6}>
<Card>
<CardHeader>
{_('proxySettings')} {configEdited ? '*' : ''}
</CardHeader>
<CardBlock>
<form>
<fieldset>
<div className='form-group'>
<input
className='form-control'
placeholder={formatMessage(
messages.proxySettingsHostPlaceHolder
)}
type='text'
value={configuration.proxyHost}
onChange={this._handleProxyHostChange}
/>
</div>{' '}
<div className='form-group'>
<input
className='form-control'
placeholder={formatMessage(
messages.proxySettingsPortPlaceHolder
)}
type='text'
value={configuration.proxyPort}
onChange={this._handleProxyPortChange}
/>
</div>{' '}
<div className='form-group'>
<input
className='form-control'
placeholder={formatMessage(
messages.proxySettingsUsernamePlaceHolder
)}
type='text'
value={configuration.proxyUser}
onChange={this._handleProxyUserChange}
/>
</div>{' '}
<div className='form-group'>
<Password
placeholder={formatMessage(
messages.proxySettingsPasswordPlaceHolder
)}
ref='proxyPassword'
/>
</div>
</fieldset>
<br />
<fieldset>
<ActionButton
icon='save'
btnStyle='primary'
handler={this._configure}
>
{_('saveResourceSet')}
</ActionButton>{' '}
<Button
onClick={this._handleConfigReset}
disabled={!configEdited}
>
{_('resetResourceSet')}
</Button>
</fieldset>
</form>
</CardBlock>
</Card>
</Col>
<Col mediumSize={6}>
<Card>
<CardHeader>{_('registration')}</CardHeader>
<CardBlock>
<strong>{registration.state}</strong>
{registration.email && <span> to {registration.email}</span>}
<span className='text-danger'> {registration.error}</span>
{!alreadyRegistered || this.state.askRegisterAgain ? (
<form id='registrationForm'>
<div className='form-group'>
<input
className='form-control'
onChange={this.linkState('email')}
placeholder={formatMessage(
messages.updateRegistrationEmailPlaceHolder
)}
required
type='text'
/>
</div>{' '}
<div className='form-group'>
<Password
disabled={!this.state.email}
onChange={this.linkState('password')}
placeholder={formatMessage(
messages.updateRegistrationPasswordPlaceHolder
)}
required
/>
</div>{' '}
<ActionButton
form='registrationForm'
icon='success'
btnStyle='primary'
handler={this._register}
>
{_('register')}
</ActionButton>
</form>
) : (
<ActionButton
icon='edit'
btnStyle='primary'
handler={this._toggleAskRegisterAgain}
>
{_('editRegistration')}
</ActionButton>
)}
{+process.env.XOA_PLAN === 1 && (
<div>
<h2>{_('trial')}</h2>
{this._trialAllowed(trial) && (
<div>
{registration.state !== 'registered' && (
<p>{_('trialRegistration')}</p>
)}
{registration.state === 'registered' && (
<ActionButton
btnStyle='success'
handler={this._startTrial}
icon='trial'
>
{_('trialStartButton')}
</ActionButton>
)}
</div>
)}
{this._trialAvailable(trial) && (
<p className='text-success'>
{_('trialAvailableUntil', {
date: new Date(trial.trial.end),
})}
</p>
)}
{this._trialConsumed(trial) && <p>{_('trialConsumed')}</p>}
))}
</div>
</CardBlock>
</Card>
</Col>
</Row>
<Row>
<Col mediumSize={6}>
<Card>
<CardHeader>
{_('proxySettings')} {state.isProxyConfigEdited ? '*' : ''}
</CardHeader>
<CardBlock>
<form>
<fieldset>
<div className='form-group'>
<input
className='form-control'
name='proxyHost'
onChange={effects.linkState}
placeholder={formatMessage(
messages.proxySettingsHostPlaceHolder
)}
value={helper(state, xoaConfiguration, 'proxyHost')}
/>
</div>{' '}
<div className='form-group'>
<input
className='form-control'
name='proxyPort'
onChange={effects.linkState}
placeholder={formatMessage(
messages.proxySettingsPortPlaceHolder
)}
value={helper(state, xoaConfiguration, 'proxyPort')}
/>
</div>{' '}
<div className='form-group'>
<input
className='form-control'
name='proxyUser'
onChange={effects.linkState}
placeholder={formatMessage(
messages.proxySettingsUsernamePlaceHolder
)}
value={helper(state, xoaConfiguration, 'proxyUser')}
/>
</div>{' '}
<div className='form-group'>
<Password
name='proxyPassword'
onChange={effects.linkState}
placeholder={formatMessage(
messages.proxySettingsPasswordPlaceHolder
)}
value={defined(state.proxyPassword, '')}
/>
</div>
)}
{process.env.XOA_PLAN > 1 &&
process.env.XOA_PLAN < 5 && (
</fieldset>
<br />
<fieldset>
<ActionButton
icon='save'
btnStyle='primary'
handler={effects.configure}
>
{_('formSave')}
</ActionButton>{' '}
<Button
onClick={effects.resetProxyConfig}
disabled={!state.isProxyConfigEdited}
>
{_('formReset')}
</Button>
</fieldset>
</form>
</CardBlock>
</Card>
</Col>
<Col mediumSize={6}>
<Card>
<CardHeader>{_('registration')}</CardHeader>
<CardBlock>
<strong>{xoaRegisterState.state}</strong>
{xoaRegisterState.email && (
<span> to {xoaRegisterState.email}</span>
)}
<span className='text-danger'> {xoaRegisterState.error}</span>
{!state.isRegistered || state.askRegisterAgain ? (
<form id='registrationForm'>
<div className='form-group'>
<input
className='form-control'
name='email'
onChange={effects.linkState}
placeholder={formatMessage(
messages.updateRegistrationEmailPlaceHolder
)}
required
value={helper(state, xoaRegisterState, 'email')}
/>
</div>{' '}
<div className='form-group'>
<Password
disabled={state.email === undefined}
name='password'
onChange={effects.linkState}
placeholder={formatMessage(
messages.updateRegistrationPasswordPlaceHolder
)}
required
value={defined(state.password, '')}
/>
</div>{' '}
<ActionButton
form='registrationForm'
icon='success'
btnStyle='primary'
handler={effects.register}
>
{_('register')}
</ActionButton>
</form>
) : (
<ActionButton
btnStyle='primary'
handler={effects.toggleState}
icon='edit'
name='askRegisterAgain'
>
{_('editRegistration')}
</ActionButton>
)}
{+process.env.XOA_PLAN === 1 && (
<div>
<h2>{_('trial')}</h2>
{state.isTrialAllowed && (
<div>
{trial.state === 'trustedTrial' && <p>{trial.message}</p>}
{trial.state === 'untrustedTrial' && (
<p className='text-danger'>{trial.message}</p>
{state.isRegistered ? (
<ActionButton
btnStyle='success'
handler={effects.startTrial}
icon='trial'
>
{_('trialStartButton')}
</ActionButton>
) : (
<p>{_('trialRegistration')}</p>
)}
</div>
)}
{process.env.XOA_PLAN < 5 && (
{state.isTrialAvailable && (
<p className='text-success'>
{_('trialAvailableUntil', {
date: new Date(xoaTrialState.trial.end),
})}
</p>
)}
{state.isTrialConsumed && <p>{_('trialConsumed')}</p>}
</div>
)}
{process.env.XOA_PLAN > 1 &&
process.env.XOA_PLAN < 5 && (
<div>
{this._updaterDown(trial) && (
<p className='text-danger'>{_('trialLocked')}</p>
{xoaTrialState.state === 'trustedTrial' && (
<p>{xoaTrialState.message}</p>
)}
{xoaTrialState.state === 'untrustedTrial' && (
<p className='text-danger'>{xoaTrialState.message}</p>
)}
</div>
)}
</CardBlock>
</Card>
</Col>
</Row>
</Container>
)
}
{process.env.XOA_PLAN < 5 && (
<div>
{state.isUpdaterDown && (
<p className='text-danger'>{_('trialLocked')}</p>
)}
</div>
)}
</CardBlock>
</Card>
</Col>
</Row>
</Container>
),
])
export { Updates as default }
const COMPONENTS_BY_STATE = {
connected: (
<span className='fa-stack'>
<i className='fa fa-circle fa-stack-2x text-warning' />
<i className='fa fa-question fa-stack-1x' />
</span>
),
disconnected: (
<span className='fa-stack'>
<i className='fa fa-circle fa-stack-2x text-danger' />
<i className='fa fa-question fa-stack-1x' />
</span>
),
error: (
<span className='fa-stack'>
<i className='fa fa-circle fa-stack-2x text-danger' />
<i className='fa fa-exclamation fa-stack-1x' />
</span>
),
registerNeeded: <Icon icon='not-registered' className='text-warning' />,
upgradeNeeded: (
<span className='fa-stack'>
<i className='fa fa-circle fa-stack-2x text-success' />
<i className='fa fa-bell fa-stack-1x' />
</span>
),
upToDate: <Icon icon='success' />,
}
const TOOLTIPS_BY_STATE = {
connected: _('waitingUpdateInfo'),
disconnected: _('noUpdateInfo'),
error: _('updaterError'),
registerNeeded: _('registerNeeded'),
upgradeNeeded: _('mustUpgrade'),
upToDate: _('upToDate'),
}
const UpdateAlarm = () => (
<span className='fa-stack'>
<i className='fa fa-circle fa-stack-2x text-danger' />
<i className='fa fa-exclamation fa-stack-1x' />
</span>
)
const UpdateError = () => (
<span className='fa-stack'>
<i className='fa fa-circle fa-stack-2x text-danger' />
<i className='fa fa-question fa-stack-1x' />
</span>
)
const UpdateWarning = () => (
<span className='fa-stack'>
<i className='fa fa-circle fa-stack-2x text-warning' />
<i className='fa fa-question fa-stack-1x' />
</span>
)
const UpdateSuccess = () => <Icon icon='success' />
const UpdateAlert = () => (
<span className='fa-stack'>
<i className='fa fa-circle fa-stack-2x text-success' />
<i className='fa fa-bell fa-stack-1x' />
</span>
)
const RegisterAlarm = () => (
<Icon icon='not-registered' className='text-warning' />
)
export const UpdateTag = connectStore(state => {
return {
configuration: state.xoaConfiguration,
log: state.xoaUpdaterLog,
registration: state.xoaRegisterState,
state: state.xoaUpdaterState,
trial: state.xoaTrialState,
}
})(props => {
const { state } = props
const components = {
disconnected: <UpdateError />,
connected: <UpdateWarning />,
upToDate: <UpdateSuccess />,
upgradeNeeded: <UpdateAlert />,
registerNeeded: <RegisterAlarm />,
error: <UpdateAlarm />,
}
const tooltips = {
disconnected: _('noUpdateInfo'),
connected: _('waitingUpdateInfo'),
upToDate: _('upToDate'),
upgradeNeeded: _('mustUpgrade'),
registerNeeded: _('registerNeeded'),
error: _('updaterError'),
}
return <Tooltip content={tooltips[state]}>{components[state]}</Tooltip>
})
export const UpdateTag = connectStore(state => ({
state: state.xoaUpdaterState,
}))(({ state }) => (
<Tooltip content={TOOLTIPS_BY_STATE[state]}>
{COMPONENTS_BY_STATE[state]}
</Tooltip>
))

View File

@@ -10797,10 +10797,10 @@ rc@^1.1.6, rc@^1.1.7, rc@^1.2.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
reaclette@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/reaclette/-/reaclette-0.6.0.tgz#7f3d84d51c9461dde7d92e445fa48a43d728967c"
integrity sha512-GkUENuI56UTXboaGHIjlVc/FIGeX4GaIaVguKH3kiGJOevDbwicTuZHF/86cpIktNRJY4u2SI8tH+ygJC1v+wg==
reaclette@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/reaclette/-/reaclette-0.7.0.tgz#ff69aacb2c18747630f386f4627771e9fe584d54"
integrity sha512-6mk0s9u9hmLsrSLuOdmzaBazUI8bLbrptiXqe8pqYJiw4Gw1wtMhFkt/Qvu1way8qykq7h54V/TDvAuSzH5AKA==
react-addons-shallow-compare@^15.0.2, react-addons-shallow-compare@^15.6.2:
version "15.6.2"