diff --git a/@xen-orchestra/audit-core/src/specification.ts b/@xen-orchestra/audit-core/src/specification.ts index 9e2e725ea..7df209d0a 100644 --- a/@xen-orchestra/audit-core/src/specification.ts +++ b/@xen-orchestra/audit-core/src/specification.ts @@ -17,10 +17,10 @@ interface Record { } export class AuditCore { - constructor(storage: Storage) { } - public add(subject: any, event: string, data: any): Promise { } - public checkIntegrity(oldest: string, newest: string): Promise { } - public getFrom(newest?: string): AsyncIterator { } - public deleteFrom(newest: string): Promise { } - public deleteRangeAndRewrite(newest: string, oldest: string): Promise { } + constructor(storage: Storage) {} + public add(subject: any, event: string, data: any): Promise {} + public checkIntegrity(oldest: string, newest: string): Promise {} + public getFrom(newest?: string): AsyncIterator {} + public deleteFrom(newest: string): Promise {} + public deleteRangeAndRewrite(newest: string, oldest: string): Promise {} } diff --git a/@xen-orchestra/backups/_lvm.js b/@xen-orchestra/backups/_lvm.js index 0d145844f..7a32f3351 100644 --- a/@xen-orchestra/backups/_lvm.js +++ b/@xen-orchestra/backups/_lvm.js @@ -7,23 +7,25 @@ const { execFile } = require('child_process') const parse = createParser({ keyTransform: key => key.slice(5).toLowerCase(), }) -const makeFunction = command => async (fields, ...args) => { - const info = await fromCallback(execFile, command, [ - '--noheading', - '--nosuffix', - '--nameprefixes', - '--unbuffered', - '--units', - 'b', - '-o', - String(fields), - ...args, - ]) - return info - .trim() - .split(/\r?\n/) - .map(Array.isArray(fields) ? parse : line => parse(line)[fields]) -} +const makeFunction = + command => + async (fields, ...args) => { + const info = await fromCallback(execFile, command, [ + '--noheading', + '--nosuffix', + '--nameprefixes', + '--unbuffered', + '--units', + 'b', + '-o', + String(fields), + ...args, + ]) + return info + .trim() + .split(/\r?\n/) + .map(Array.isArray(fields) ? parse : line => parse(line)[fields]) + } exports.lvs = makeFunction('lvs') exports.pvs = makeFunction('pvs') diff --git a/@xen-orchestra/log/transports/console.js b/@xen-orchestra/log/transports/console.js index 3266e64ba..468fec381 100644 --- a/@xen-orchestra/log/transports/console.js +++ b/@xen-orchestra/log/transports/console.js @@ -20,36 +20,8 @@ if (process.stdout !== undefined && process.stdout.isTTY && process.stderr !== u } const NAMESPACE_COLORS = [ - 196, - 202, - 208, - 214, - 220, - 226, - 190, - 154, - 118, - 82, - 46, - 47, - 48, - 49, - 50, - 51, - 45, - 39, - 33, - 27, - 21, - 57, - 93, - 129, - 165, - 201, - 200, - 199, - 198, - 197, + 196, 202, 208, 214, 220, 226, 190, 154, 118, 82, 46, 47, 48, 49, 50, 51, 45, 39, 33, 27, 21, 57, 93, 129, 165, 201, + 200, 199, 198, 197, ] formatNamespace = namespace => { // https://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/ diff --git a/@xen-orchestra/openflow/src/util/addrress-parser.js b/@xen-orchestra/openflow/src/util/addrress-parser.js index f55c52896..ad6667389 100644 --- a/@xen-orchestra/openflow/src/util/addrress-parser.js +++ b/@xen-orchestra/openflow/src/util/addrress-parser.js @@ -28,9 +28,10 @@ export default { buffer.toString('hex', offset + 5, offset + 6), stringToEth: (string, buffer, offset) => { - const eth = /^([0-9A-Fa-f]{2}):([0-9A-Fa-f]{2}):([0-9A-Fa-f]{2}):([0-9A-Fa-f]{2}):([0-9A-Fa-f]{2}):([0-9A-Fa-f]{2})$/.exec( - string - ) + const eth = + /^([0-9A-Fa-f]{2}):([0-9A-Fa-f]{2}):([0-9A-Fa-f]{2}):([0-9A-Fa-f]{2}):([0-9A-Fa-f]{2}):([0-9A-Fa-f]{2})$/.exec( + string + ) assert(eth !== null) buffer.writeUInt8(parseInt(eth[1], 16), offset) buffer.writeUInt8(parseInt(eth[2], 16), offset + 1) @@ -50,9 +51,10 @@ export default { ), stringToip4: (string, buffer, offset) => { - const ip = /^([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])\.([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])\.([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])\.([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])$/.exec( - string - ) + const ip = + /^([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])\.([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])\.([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])\.([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])$/.exec( + string + ) assert(ip !== null) buffer.writeUInt8(parseInt(ip[1], 10), offset) buffer.writeUInt8(parseInt(ip[2], 10), offset + 1) diff --git a/@xen-orchestra/proxy-cli/src/index.js b/@xen-orchestra/proxy-cli/src/index.js index a212db7f4..d53f1beea 100755 --- a/@xen-orchestra/proxy-cli/src/index.js +++ b/@xen-orchestra/proxy-cli/src/index.js @@ -36,7 +36,14 @@ async function main(argv) { const { hostname = 'localhost', port } = config?.http?.listen?.https ?? {} - const { _: args, file, help, host, raw, token } = getopts(argv, { + const { + _: args, + file, + help, + host, + raw, + token, + } = getopts(argv, { alias: { file: 'f', help: 'h' }, boolean: ['help', 'raw'], default: { diff --git a/@xen-orchestra/proxy/docs/api.md b/@xen-orchestra/proxy/docs/api.md index c43cc40d6..7318a3d7b 100644 --- a/@xen-orchestra/proxy/docs/api.md +++ b/@xen-orchestra/proxy/docs/api.md @@ -93,10 +93,7 @@ declare namespace event { snapshot: Task } - function from(_: { - token: string = '' - timeout?: number - }): { + function from(_: { token: string = ''; timeout?: number }): { events: Event[] token: string } @@ -146,13 +143,13 @@ declare namespace backup { streamLogs: boolean = false }): string - function listPoolMetadataBackups(_: { - remotes: { [id: string]: Remote } - }): { [remoteId: string]: { [poolUuid: string]: object[] } } + function listPoolMetadataBackups(_: { remotes: { [id: string]: Remote } }): { + [remoteId: string]: { [poolUuid: string]: object[] } + } - function listVmBackups(_: { - remotes: { [remoteId: string]: Remote } - }): { [remoteId: string]: { [vmUuid: string]: object[] } } + function listVmBackups(_: { remotes: { [remoteId: string]: Remote } }): { + [remoteId: string]: { [vmUuid: string]: object[] } + } function listXoMetadataBackups(_: { remotes: { [id: string]: Remote } }): { [remoteId: string]: object[] } diff --git a/docs/manage_infrastructure.md b/docs/manage_infrastructure.md index 94b515c74..8b9dcfded 100644 --- a/docs/manage_infrastructure.md +++ b/docs/manage_infrastructure.md @@ -320,6 +320,7 @@ You can learn more about XenServer [resource management on the Citrix Website](h :::tip XCP-ng doesn't limit VMs to 32 vCPU ::: + ### VDI live migration Thanks to Xen Storage Motion, it's easy to move a VM disk from one storage location to another, while the VM is running! This feature can help you migrate from your local storage to a SAN, or just upgrade your SAN without any downtime. @@ -491,10 +492,12 @@ If you are behind a proxy, please update your `xo-server` configuration to add a ::: danger As specified in the [documentation](https://xcp-ng.org/docs/requirements.html#pool-requirements) your pool shouldn't consist of hosts from different CPU vendors. ::: + ::: warning - Even with matching CPU vendors, in the case of different CPU models XCP-ng will scale the pool CPU ability to the CPU having the least instructions. - All the hosts in a pool must run the same XCP-ng version. ::: + ### Creating a pool First you should add your new host to XOA by going to New > Server as described in [the relevant chapter](manage_infrastructure.md#add-a-host). diff --git a/docs/proxy.md b/docs/proxy.md index 98199d37d..11784f72e 100644 --- a/docs/proxy.md +++ b/docs/proxy.md @@ -59,9 +59,11 @@ While creating a standard backup job from your main Xen Orchestra appliance, you Login is disabled by default on proxy appliances. If you need to login for some reason, you need to set a password for the xoa user via the XenStore of the VM. The following is to be ran on your XCP-ng host: + ``` xe vm-param-set uuid= xenstore-data:vm-data/system-account-xoa-password= ``` + Where UUID is the uuid of your proxy VM. Then you need to restart the proxy VM. @@ -74,15 +76,19 @@ First you will need to add a second VIF to your Proxy VM. This can be done in th After adding the VIF you will need to set an IP for the new NIC, for that you will first need to SSH to the VM [as describe before](/proxy.md#enabling-login-to-proxy-appliance). Then set the new IP: + ``` $ xoa network static eth1 ? Static IP for this machine 192.168.100.120 ? Network mask (eg 255.255.255.0) 255.255.255.0 ``` + If you want to set a static address. + ``` $ xoa network dhcp eth1 ``` + If you prefer using DHCP. :::tip As XOA uses the first IP address reported by XAPI to contact the proxy appliance, you may have to switch the network card order if you want your proxy to be connected through a specific IP address. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 3ed0f3b5c..7dafdfa9f 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -19,9 +19,11 @@ XOA uses HVM mode. If your physical host doesn't support virtualization extensio ## Set or recover XOA VM password As no password is set for the xoa system user by default, you will need to set your own. This can be done via the XenStore data of the VM. The following is to be ran on your XCP-ng host: + ``` xe vm-param-set uuid= xenstore-data:vm-data/system-account-xoa-password= ``` + Where UUID is the uuid of your XOA VM. Then you need to restart the VM. diff --git a/packages/xo-acl-resolver/index.js b/packages/xo-acl-resolver/index.js index f056d5d32..cd17ee36c 100644 --- a/packages/xo-acl-resolver/index.js +++ b/packages/xo-acl-resolver/index.js @@ -15,24 +15,28 @@ const authorized = () => true // eslint-disable-line no-unused-vars const forbiddden = () => false // eslint-disable-line no-unused-vars // eslint-disable-next-line no-unused-vars -const and = (...checkers) => (object, permission) => { - for (const checker of checkers) { - if (!checker(object, permission)) { - return false +const and = + (...checkers) => + (object, permission) => { + for (const checker of checkers) { + if (!checker(object, permission)) { + return false + } } + return true } - return true -} // eslint-disable-next-line no-unused-vars -const or = (...checkers) => (object, permission) => { - for (const checker of checkers) { - if (checker(object, permission)) { - return true +const or = + (...checkers) => + (object, permission) => { + for (const checker of checkers) { + if (checker(object, permission)) { + return true + } } + return false } - return false -} // ------------------------------------------------------------------- diff --git a/packages/xo-import-servers-csv/src/index.ts b/packages/xo-import-servers-csv/src/index.ts index e03dae084..1805fea2f 100755 --- a/packages/xo-import-servers-csv/src/index.ts +++ b/packages/xo-import-servers-csv/src/index.ts @@ -7,10 +7,7 @@ import execPromise = require('exec-promise') import through2 = require('through2') import Xo from 'xo-lib' -const parseBoolean = ( - value: string, - defaultValue?: boolean -): boolean | undefined => { +const parseBoolean = (value: string, defaultValue?: boolean): boolean | undefined => { if (value === undefined || value === '') { return defaultValue } @@ -49,30 +46,24 @@ execPromise( const errors: any[] = [] const stream = process.stdin.pipe(csvParser()).pipe( - through2.obj( - ( - { allowUnauthorized, autoConnect, host, label, password, username }, - _, - next - ) => { - console.log('server', host) + through2.obj(({ allowUnauthorized, autoConnect, host, label, password, username }, _, next) => { + console.log('server', host) - xo.call('server.add', { - allowUnauthorized: parseBoolean(allowUnauthorized), - autoConnect: parseBoolean(autoConnect, false), - host, - label, - password, - username, - }).then( - () => next(), - (error: any) => { - errors.push({ host, error }) - return next() - } - ) - } - ) + xo.call('server.add', { + allowUnauthorized: parseBoolean(allowUnauthorized), + autoConnect: parseBoolean(autoConnect, false), + host, + label, + password, + username, + }).then( + () => next(), + (error: any) => { + errors.push({ host, error }) + return next() + } + ) + }) ) await new Promise((resolve, reject) => { diff --git a/packages/xo-server-netbox/src/index.js b/packages/xo-server-netbox/src/index.js index af9099bbc..8cc2ff28a 100644 --- a/packages/xo-server-netbox/src/index.js +++ b/packages/xo-server-netbox/src/index.js @@ -445,18 +445,14 @@ class Netbox { this.#makeRequest('/virtualization/interfaces/', 'DELETE', interfacesToDelete), isEmpty(interfacesToCreateByVif) ? {} - : this.#makeRequest( - '/virtualization/interfaces/', - 'POST', - Object.values(interfacesToCreateByVif) - ).then(interfaces => zipObject(Object.keys(interfacesToCreateByVif), interfaces)), + : this.#makeRequest('/virtualization/interfaces/', 'POST', Object.values(interfacesToCreateByVif)).then( + interfaces => zipObject(Object.keys(interfacesToCreateByVif), interfaces) + ), isEmpty(interfacesToUpdateByVif) ? {} - : this.#makeRequest( - '/virtualization/interfaces/', - 'PATCH', - Object.values(interfacesToUpdateByVif) - ).then(interfaces => zipObject(Object.keys(interfacesToUpdateByVif), interfaces)), + : this.#makeRequest('/virtualization/interfaces/', 'PATCH', Object.values(interfacesToUpdateByVif)).then( + interfaces => zipObject(Object.keys(interfacesToUpdateByVif), interfaces) + ), ]) ) .slice(1) diff --git a/packages/xo-server/src/api/system.mjs b/packages/xo-server/src/api/system.mjs index 6bd017c02..ba945213f 100644 --- a/packages/xo-server/src/api/system.mjs +++ b/packages/xo-server/src/api/system.mjs @@ -24,7 +24,10 @@ getMethodsInfo.permission = null // user does not need to be authenticated // ------------------------------------------------------------------- -export const getServerTimezone = (tz => () => tz)(moment.tz.guess()) +export const getServerTimezone = ( + tz => () => + tz +)(moment.tz.guess()) getServerTimezone.description = 'return the timezone server' // ------------------------------------------------------------------- diff --git a/packages/xo-server/src/glob-matcher.mjs b/packages/xo-server/src/glob-matcher.mjs index 10063fcd3..80a05b6f2 100644 --- a/packages/xo-server/src/glob-matcher.mjs +++ b/packages/xo-server/src/glob-matcher.mjs @@ -8,7 +8,7 @@ export default function globMatcher(patterns, opts) { if (!Array.isArray(patterns)) { if (patterns[0] === '!') { const m = matcher(patterns.slice(1), opts) - return function(string) { + return function (string) { return !m(string) } } else { @@ -32,7 +32,7 @@ export default function globMatcher(patterns, opts) { const nNone = noneMustMatch.length const nAny = anyMustMatch.length - return function(string) { + return function (string) { if (typeof string !== 'string') { return false } diff --git a/packages/xo-server/src/math.mjs b/packages/xo-server/src/math.mjs index 6c3897b48..964133bff 100644 --- a/packages/xo-server/src/math.mjs +++ b/packages/xo-server/src/math.mjs @@ -40,7 +40,9 @@ export const mergeObjects = objects => Object.assign({}, ...objects) // // Ex: crossProduct([ [ { a: 2 }, { b: 3 } ], [ { c: 5 }, { d: 7 } ] ] ) // => [ { a: 2, c: 5 }, { b: 3, c: 5 }, { a: 2, d: 7 }, { b: 3, d: 7 } ] -export const crossProduct = (vectors, mergeFn = mergeObjects) => cb => - combine(vectors)(vector => { - cb(mergeFn(vector)) - }) +export const crossProduct = + (vectors, mergeFn = mergeObjects) => + cb => + combine(vectors)(vector => { + cb(mergeFn(vector)) + }) diff --git a/packages/xo-server/src/xapi/index.mjs b/packages/xo-server/src/xapi/index.mjs index efbb56226..f70c9bc5f 100644 --- a/packages/xo-server/src/xapi/index.mjs +++ b/packages/xo-server/src/xapi/index.mjs @@ -99,13 +99,16 @@ export default class Xapi extends XapiBase { this._snapshotVm = limitConcurrency(vmSnapshotConcurrency)(this._snapshotVm) // Patch getObject to resolve _xapiId property. - this.getObject = (getObject => (...args) => { - let tmp - if ((tmp = args[0]) != null && (tmp = tmp._xapiId) != null) { - args[0] = tmp + this.getObject = ( + getObject => + (...args) => { + let tmp + if ((tmp = args[0]) != null && (tmp = tmp._xapiId) != null) { + args[0] = tmp + } + return getObject.apply(this, args) } - return getObject.apply(this, args) - })(this.getObject) + )(this.getObject) } // Wait for an object to be in a given state. diff --git a/packages/xo-server/src/xo-mixins/ip-pools.mjs b/packages/xo-server/src/xo-mixins/ip-pools.mjs index 9eade80a1..9fe00bda3 100644 --- a/packages/xo-server/src/xo-mixins/ip-pools.mjs +++ b/packages/xo-server/src/xo-mixins/ip-pools.mjs @@ -68,7 +68,9 @@ export default class IpPools { if (await store.has(id)) { await Promise.all( - (await this._app.getAllResourceSets()).map(async set => { + ( + await this._app.getAllResourceSets() + ).map(async set => { await this._app.removeLimitFromResourceSet(`ipPool:${id}`, set.id) return this._app.removeIpPoolFromResourceSet(id, set.id) }) diff --git a/packages/xo-server/src/xo-mixins/resource-sets.mjs b/packages/xo-server/src/xo-mixins/resource-sets.mjs index 4a8e1f5e5..a97593ac1 100644 --- a/packages/xo-server/src/xo-mixins/resource-sets.mjs +++ b/packages/xo-server/src/xo-mixins/resource-sets.mjs @@ -177,7 +177,9 @@ export default class { await Promise.all( difference(set.subjects, subjects).map(async subjectId => Promise.all( - (await this._app.getAclsForSubject(subjectId)).map(async acl => { + ( + await this._app.getAclsForSubject(subjectId) + ).map(async acl => { try { const object = this._app.getObject(acl.object) if ((object.type === 'VM' || object.type === 'VM-snapshot') && object.resourceSet === id) { diff --git a/packages/xo-web/src/common/custom-fields.js b/packages/xo-web/src/common/custom-fields.js index 2d0dccf1e..b5e02b8fa 100644 --- a/packages/xo-web/src/common/custom-fields.js +++ b/packages/xo-web/src/common/custom-fields.js @@ -131,50 +131,56 @@ const CustomFields = decorate([ }), provideState({ effects: { - addCustomField: () => (state, { object: { id } }) => { - const dateTimeUtc = moment.utc() - return form({ - component: CustomFieldModal, - defaultValue: { - date: dateTimeUtc.format(DATE_FORMAT), - isDate: false, - name: '', - text: '', - time: dateTimeUtc.format(TIME_FORMAT), - }, - header: ( - - {_('addCustomField')} - - ), - }).then(params => checkParamsAndCallMethod(addCustomField, id, params)) - }, - removeCustomField: (_, { currentTarget: { dataset } }) => (_, { object: { id } }) => - removeCustomField(id, dataset.name), - setCustomField: (effects, { name, value }) => (state, { object: { id } }) => { - const isDate = PATTERN_DATE_TIME_UTC.test(value) - const dateTimeUtc = isDate ? moment(value).utc() : undefined - return form({ - render: props => , - defaultValue: isDate - ? { - date: dateTimeUtc.format(DATE_FORMAT), - isDate, - name, - time: dateTimeUtc.format(TIME_FORMAT), - } - : { - isDate, - name, - text: value, - }, - header: ( - - {_('editCustomField')} - - ), - }).then(params => checkParamsAndCallMethod(setCustomField, id, params)) - }, + addCustomField: + () => + (state, { object: { id } }) => { + const dateTimeUtc = moment.utc() + return form({ + component: CustomFieldModal, + defaultValue: { + date: dateTimeUtc.format(DATE_FORMAT), + isDate: false, + name: '', + text: '', + time: dateTimeUtc.format(TIME_FORMAT), + }, + header: ( + + {_('addCustomField')} + + ), + }).then(params => checkParamsAndCallMethod(addCustomField, id, params)) + }, + removeCustomField: + (_, { currentTarget: { dataset } }) => + (_, { object: { id } }) => + removeCustomField(id, dataset.name), + setCustomField: + (effects, { name, value }) => + (state, { object: { id } }) => { + const isDate = PATTERN_DATE_TIME_UTC.test(value) + const dateTimeUtc = isDate ? moment(value).utc() : undefined + return form({ + render: props => , + defaultValue: isDate + ? { + date: dateTimeUtc.format(DATE_FORMAT), + isDate, + name, + time: dateTimeUtc.format(TIME_FORMAT), + } + : { + isDate, + name, + text: value, + }, + header: ( + + {_('editCustomField')} + + ), + }).then(params => checkParamsAndCallMethod(setCustomField, id, params)) + }, }, computed: { customFields: (_, { object }) => diff --git a/packages/xo-web/src/common/reaclette-utils.js b/packages/xo-web/src/common/reaclette-utils.js index 9cd27c563..8458ccf31 100644 --- a/packages/xo-web/src/common/reaclette-utils.js +++ b/packages/xo-web/src/common/reaclette-utils.js @@ -4,13 +4,17 @@ export const generateId = () => `i${Math.random().toString(36).slice(2)}` // TODO: remove these functions once the PR: https://github.com/JsCommunity/reaclette/pull/5 has been merged // It only supports native inputs -export const linkState = (_, { target }) => () => ({ - [target.name]: - target.nodeName.toLowerCase() === 'input' && target.type.toLowerCase() === 'checkbox' - ? target.checked - : target.value, -}) +export const linkState = + (_, { target }) => + () => ({ + [target.name]: + target.nodeName.toLowerCase() === 'input' && target.type.toLowerCase() === 'checkbox' + ? target.checked + : target.value, + }) -export const toggleState = (_, { currentTarget: { name } }) => state => ({ - [name]: !state[name], -}) +export const toggleState = + (_, { currentTarget: { name } }) => + state => ({ + [name]: !state[name], + }) diff --git a/packages/xo-web/src/common/render-xo-item.js b/packages/xo-web/src/common/render-xo-item.js index 4206c6431..a56d6f345 100644 --- a/packages/xo-web/src/common/render-xo-item.js +++ b/packages/xo-web/src/common/render-xo-item.js @@ -635,7 +635,10 @@ const renderXoItem = (item, { className, type: xoType, ...props } = {}) => { export { renderXoItem as default } -export const getRenderXoItemOfType = type => (item, options = {}) => renderXoItem(item, { ...options, type }) +export const getRenderXoItemOfType = + type => + (item, options = {}) => + renderXoItem(item, { ...options, type }) const GenericXoItem = connectStore(() => { const getObject = createGetObject() diff --git a/packages/xo-web/src/common/scheduling.js b/packages/xo-web/src/common/scheduling.js index 697027245..66d2ab55f 100644 --- a/packages/xo-web/src/common/scheduling.js +++ b/packages/xo-web/src/common/scheduling.js @@ -193,23 +193,27 @@ class ToggleTd extends Component { const TableSelect = decorate([ provideState({ effects: { - onChange: (_, tdId, add) => (_, { value, onChange, options }) => { - let newValue = [...value] - const index = sortedIndex(newValue, tdId) - if (add) { - newValue[index] !== tdId && newValue.splice(index, 0, tdId) - } else if (newValue[index] === tdId) { - if (newValue.length > 1) { - newValue.splice(index, 1) - } else { - newValue = [options[0][0]] + onChange: + (_, tdId, add) => + (_, { value, onChange, options }) => { + let newValue = [...value] + const index = sortedIndex(newValue, tdId) + if (add) { + newValue[index] !== tdId && newValue.splice(index, 0, tdId) + } else if (newValue[index] === tdId) { + if (newValue.length > 1) { + newValue.splice(index, 1) + } else { + newValue = [options[0][0]] + } } - } - onChange(newValue) - }, - selectAll: () => ({ optionsValues }, { onChange }) => { - onChange(optionsValues) - }, + onChange(newValue) + }, + selectAll: + () => + ({ optionsValues }, { onChange }) => { + onChange(optionsValues) + }, }, computed: { optionsValues: (_, { options }) => flatten(options), @@ -258,15 +262,17 @@ TableSelect.propTypes = { const TimePicker = decorate([ provideState({ effects: { - onChange: (_, value) => ({ optionsValues }, { onChange }) => { - if (Array.isArray(value)) { - value = value.length === optionsValues.length ? '*' : value.join(',') - } else { - value = `*/${value}` - } + onChange: + (_, value) => + ({ optionsValues }, { onChange }) => { + if (Array.isArray(value)) { + value = value.length === optionsValues.length ? '*' : value.join(',') + } else { + value = `*/${value}` + } - onChange(value) - }, + onChange(value) + }, }, computed: { maxStep: ({ optionsValues }) => Math.floor(optionsValues.length / 2), diff --git a/packages/xo-web/src/common/select-objects.js b/packages/xo-web/src/common/select-objects.js index a0c6df884..208b8979a 100644 --- a/packages/xo-web/src/common/select-objects.js +++ b/packages/xo-web/src/common/select-objects.js @@ -524,13 +524,15 @@ export const SelectTag = decorate([ editing: false, }), effects: { - addTag: (effects, newTag) => ({ value }, { multi, onChange }) => { - if (newTag === value || (multi && includes(value, newTag))) { - return - } - const _newTag = { id: newTag, type: 'tag', value: newTag } - onChange(multi ? [...map(value, tag => ({ id: tag, type: 'tag', value: tag })), _newTag] : _newTag) - }, + addTag: + (effects, newTag) => + ({ value }, { multi, onChange }) => { + if (newTag === value || (multi && includes(value, newTag))) { + return + } + const _newTag = { id: newTag, type: 'tag', value: newTag } + onChange(multi ? [...map(value, tag => ({ id: tag, type: 'tag', value: tag })), _newTag] : _newTag) + }, closeEdition: () => ({ editing: false }), toggleState, }, diff --git a/packages/xo-web/src/common/selectors.js b/packages/xo-web/src/common/selectors.js index 86a56af98..e116233e9 100644 --- a/packages/xo-web/src/common/selectors.js +++ b/packages/xo-web/src/common/selectors.js @@ -287,31 +287,33 @@ export const isAdmin = (...args) => { // Common selector creators. // Creates an object selector from an id selector. -export const createGetObject = (idSelector = _getId) => (state, props, useResourceSet) => { - const object = state.objects.all[idSelector(state, props)] - if (!object) { - return - } - - if (useResourceSet) { - return object - } - - const predicate = _getPermissionsPredicate(state) - - if (!predicate) { - if (predicate == null) { - return object // no filtering +export const createGetObject = + (idSelector = _getId) => + (state, props, useResourceSet) => { + const object = state.objects.all[idSelector(state, props)] + if (!object) { + return } - // predicate is false. - return - } + if (useResourceSet) { + return object + } - if (predicate(object)) { - return object + const predicate = _getPermissionsPredicate(state) + + if (!predicate) { + if (predicate == null) { + return object // no filtering + } + + // predicate is false. + return + } + + if (predicate(object)) { + return object + } } -} // Specialized createSort() configured for a given type. export const createSortForType = invoke(() => { @@ -462,9 +464,12 @@ export const createDoesHostNeedRestart = hostSelector => { const patchRequiresReboot = createGetObjectsOfType('patch') .pick(create(hostSelector, host => host.patches)) .find( - create(hostSelector, host => ({ guidance, time, upgrade }) => - time > host.startTime && - (upgrade || some(guidance, action => action === 'restartHost' || action === 'restartXapi')) + create( + hostSelector, + host => + ({ guidance, time, upgrade }) => + time > host.startTime && + (upgrade || some(guidance, action => action === 'restartHost' || action === 'restartXapi')) ) ) diff --git a/packages/xo-web/src/common/sorted-table/index.js b/packages/xo-web/src/common/sorted-table/index.js index 02d34dff4..e124e530b 100644 --- a/packages/xo-web/src/common/sorted-table/index.js +++ b/packages/xo-web/src/common/sorted-table/index.js @@ -140,7 +140,10 @@ const Action = decorate([ computed: { disabled: ({ items }, { disabled, userData }) => typeof disabled === 'function' ? disabled(items, userData) : disabled, - handler: ({ items }, { handler, userData }) => () => handler(items, userData), + handler: + ({ items }, { handler, userData }) => + () => + handler(items, userData), icon: ({ items }, { icon, userData }) => (typeof icon === 'function' ? icon(items, userData) : icon), items: (_, { items, grouped }) => (Array.isArray(items) || !grouped ? items : [items]), label: ({ items }, { label, userData }) => (typeof label === 'function' ? label(items, userData) : label), diff --git a/packages/xo-web/src/common/store/reducer.js b/packages/xo-web/src/common/store/reducer.js index 8b9573573..74c9dd119 100644 --- a/packages/xo-web/src/common/store/reducer.js +++ b/packages/xo-web/src/common/store/reducer.js @@ -7,19 +7,21 @@ import * as actions from './actions' // =================================================================== -const createAsyncHandler = ({ error, next }) => (state, payload, action) => { - if (action.error) { - if (error) { - return error(state, payload, action) +const createAsyncHandler = + ({ error, next }) => + (state, payload, action) => { + if (action.error) { + if (error) { + return error(state, payload, action) + } + } else { + if (next) { + return next(state, payload, action) + } } - } else { - if (next) { - return next(state, payload, action) - } - } - return state -} + return state + } // Action handlers are reducers but bound to a specific action. const combineActionHandlers = invoke( diff --git a/packages/xo-web/src/common/utils.js b/packages/xo-web/src/common/utils.js index 8af20df25..607e62d48 100644 --- a/packages/xo-web/src/common/utils.js +++ b/packages/xo-web/src/common/utils.js @@ -576,18 +576,20 @@ export const downloadLog = ({ log, date, type }) => { // ]) // ) // ``` -export const createCompare = criterias => (...items) => { - let res = 0 - // Array.find to stop when the result is != 0 - criterias.find(fn => { - const [v1, v2] = items.map(item => { - const v = typeof fn === 'string' ? item[fn] : fn(item) - return v === true ? -1 : v === false ? 1 : v +export const createCompare = + criterias => + (...items) => { + let res = 0 + // Array.find to stop when the result is != 0 + criterias.find(fn => { + const [v1, v2] = items.map(item => { + const v = typeof fn === 'string' ? item[fn] : fn(item) + return v === true ? -1 : v === false ? 1 : v + }) + return (res = v1 < v2 ? -1 : v1 > v2 ? 1 : 0) }) - return (res = v1 < v2 ? -1 : v1 > v2 ? 1 : 0) - }) - return res -} + return res + } // =================================================================== diff --git a/packages/xo-web/src/common/xo/index.js b/packages/xo-web/src/common/xo/index.js index 4fbcffd5c..964104dec 100644 --- a/packages/xo-web/src/common/xo/index.js +++ b/packages/xo-web/src/common/xo/index.js @@ -1368,15 +1368,17 @@ export const createVms = (args, nameLabels, cloudConfigs) => body: _('newVmCreateVmsConfirm', { nbVms: nameLabels.length }), }).then(() => Promise.all( - map(nameLabels, ( - name_label, // eslint-disable-line camelcase - i - ) => - _call('vm.create', { - ...args, - name_label, - cloudConfig: get(cloudConfigs, i), - }) + map( + nameLabels, + ( + name_label, // eslint-disable-line camelcase + i + ) => + _call('vm.create', { + ...args, + name_label, + cloudConfig: get(cloudConfigs, i), + }) ) ) ) diff --git a/packages/xo-web/src/common/xo/install-pool-patches-modal/index.js b/packages/xo-web/src/common/xo/install-pool-patches-modal/index.js index 4c79c1ecc..bca35502a 100644 --- a/packages/xo-web/src/common/xo/install-pool-patches-modal/index.js +++ b/packages/xo-web/src/common/xo/install-pool-patches-modal/index.js @@ -25,7 +25,14 @@ import { ejectCd, isSrWritable, setDefaultSr } from 'xo' return { pool: getPool, poolMaster: createGetObject(createSelector(getPool, ({ master }) => master)), - vbds: createGetObjectsOfType('VBD').filter(createSelector(getPool, ({ id }) => vbd => vbd.$pool === id)), + vbds: createGetObjectsOfType('VBD').filter( + createSelector( + getPool, + ({ id }) => + vbd => + vbd.$pool === id + ) + ), } }, { withRef: true } diff --git a/packages/xo-web/src/common/xo/migrate-vm-modal/index.js b/packages/xo-web/src/common/xo/migrate-vm-modal/index.js index 0e3ffe809..cd03947f0 100644 --- a/packages/xo-web/src/common/xo/migrate-vm-modal/index.js +++ b/packages/xo-web/src/common/xo/migrate-vm-modal/index.js @@ -70,7 +70,9 @@ export default class MigrateVmModalBody extends BaseComponent { this._getHostPredicate = createSelector( () => this.props.vm, - ({ $container }) => host => host.id !== $container + ({ $container }) => + host => + host.id !== $container ) this._getSrPredicate = createSelector( diff --git a/packages/xo-web/src/common/xo/multipathing-modal/index.js b/packages/xo-web/src/common/xo/multipathing-modal/index.js index 79c47ffc6..e107e436f 100644 --- a/packages/xo-web/src/common/xo/multipathing-modal/index.js +++ b/packages/xo-web/src/common/xo/multipathing-modal/index.js @@ -11,7 +11,11 @@ import { Sr } from '../../render-xo-item' @connectStore( { srIds: createSelector( - createGetObjectsOfType('PBD').filter((_, { hostIds }) => pbd => hostIds.includes(pbd.host)), + createGetObjectsOfType('PBD').filter( + (_, { hostIds }) => + pbd => + hostIds.includes(pbd.host) + ), pbds => { const srIds = new Set([]) for (const id in pbds) { diff --git a/packages/xo-web/src/common/xo/update-xosan-packs-modal/index.js b/packages/xo-web/src/common/xo/update-xosan-packs-modal/index.js index cf5ed6881..279dd2641 100644 --- a/packages/xo-web/src/common/xo/update-xosan-packs-modal/index.js +++ b/packages/xo-web/src/common/xo/update-xosan-packs-modal/index.js @@ -8,7 +8,11 @@ import { isLatestXosanPackInstalled, connectStore, findLatestPack } from 'utils' @connectStore( { - hosts: createGetObjectsOfType('host').filter((_, { pool }) => host => host.$pool === pool.id), + hosts: createGetObjectsOfType('host').filter( + (_, { pool }) => + host => + host.$pool === pool.id + ), }, { withRef: true } ) diff --git a/packages/xo-web/src/xo-app/backup/file-restore/restore-file-modal.js b/packages/xo-web/src/xo-app/backup/file-restore/restore-file-modal.js index a05bb429f..ab30ed92b 100644 --- a/packages/xo-web/src/xo-app/backup/file-restore/restore-file-modal.js +++ b/packages/xo-web/src/xo-app/backup/file-restore/restore-file-modal.js @@ -264,17 +264,8 @@ export default class RestoreFileModalBody extends Component { render() { const { backups } = this.props - const { - backup, - disk, - partition, - partitions, - path, - scanDiskError, - listFilesError, - scanningFiles, - selectedFiles, - } = this.state + const { backup, disk, partition, partitions, path, scanDiskError, listFilesError, scanningFiles, selectedFiles } = + this.state const noPartitions = isEmpty(partitions) const redundantFiles = this._getRedundantFiles() diff --git a/packages/xo-web/src/xo-app/backup/new/_schedules/index.js b/packages/xo-web/src/xo-app/backup/new/_schedules/index.js index b03ea3946..7a966a3a9 100644 --- a/packages/xo-web/src/xo-app/backup/new/_schedules/index.js +++ b/packages/xo-web/src/xo-app/backup/new/_schedules/index.js @@ -93,65 +93,73 @@ const Schedules = decorate([ delete settings[id] props.handlerSettings(settings) }, - showModal: (effects, { id = generateRandomId(), name, cron, timezone } = DEFAULT_SCHEDULE) => async ( - state, - props - ) => { - const schedule = get(() => props.schedules[id]) - const setting = get(() => props.settings[id]) + showModal: + (effects, { id = generateRandomId(), name, cron, timezone } = DEFAULT_SCHEDULE) => + async (state, props) => { + const schedule = get(() => props.schedules[id]) + const setting = get(() => props.settings[id]) - const { cron: newCron, name: newName, timezone: newTimezone, ...newSetting } = await form({ - defaultValue: setDefaultRetentions({ cron, name, timezone, ...setting }, state.retentions), - render: props => , - header: ( - - {_('schedule')} - - ), - size: 'large', - handler: value => { - if (areRetentionsMissing(value, state.retentions)) { - throw new UserError(_('newScheduleError'), _('retentionNeeded')) - } - return value - }, - }) - - props.handlerSchedules({ - ...props.schedules, - [id]: { - ...schedule, + const { cron: newCron, - id, name: newName, timezone: newTimezone, - }, - }) - props.handlerSettings({ - ...props.settings, - [id]: { - ...setting, - ...newSetting, - }, - }) - }, - toggleScheduleState: (_, id) => (state, { handlerSchedules, schedules }) => { - const schedule = schedules[id] - handlerSchedules({ - ...schedules, - [id]: { - ...schedule, - enabled: !schedule.enabled, - }, - }) - }, + ...newSetting + } = await form({ + defaultValue: setDefaultRetentions({ cron, name, timezone, ...setting }, state.retentions), + render: props => , + header: ( + + {_('schedule')} + + ), + size: 'large', + handler: value => { + if (areRetentionsMissing(value, state.retentions)) { + throw new UserError(_('newScheduleError'), _('retentionNeeded')) + } + return value + }, + }) + + props.handlerSchedules({ + ...props.schedules, + [id]: { + ...schedule, + cron: newCron, + id, + name: newName, + timezone: newTimezone, + }, + }) + props.handlerSettings({ + ...props.settings, + [id]: { + ...setting, + ...newSetting, + }, + }) + }, + toggleScheduleState: + (_, id) => + (state, { handlerSchedules, schedules }) => { + const schedule = schedules[id] + handlerSchedules({ + ...schedules, + [id]: { + ...schedule, + enabled: !schedule.enabled, + }, + }) + }, }, computed: { columns: (_, { retentions }) => [...COLUMNS, ...retentions.map(({ defaultValue, ...props }) => props)], - rowTransform: (_, { settings = {}, retentions }) => schedule => { - schedule = { ...schedule, ...settings[schedule.id] } - return setDefaultRetentions(schedule, retentions) - }, + rowTransform: + (_, { settings = {}, retentions }) => + schedule => { + schedule = { ...schedule, ...settings[schedule.id] } + return setDefaultRetentions(schedule, retentions) + }, }, }), injectState, diff --git a/packages/xo-web/src/xo-app/backup/new/_schedules/new.js b/packages/xo-web/src/xo-app/backup/new/_schedules/new.js index 035b74f12..8d2c787a3 100644 --- a/packages/xo-web/src/xo-app/backup/new/_schedules/new.js +++ b/packages/xo-web/src/xo-app/backup/new/_schedules/new.js @@ -14,23 +14,29 @@ import { areRetentionsMissing } from '.' export default decorate([ provideState({ effects: { - setSchedule: (_, params) => (_, { value, onChange }) => { - onChange({ - ...value, - ...params, - }) - }, - setCronTimezone: ({ setSchedule }, { cronPattern: cron, timezone }) => () => { - setSchedule({ - cron, - timezone, - }) - }, - setName: ({ setSchedule }, { target: { value } }) => () => { - setSchedule({ - name: value.trim() === '' ? null : value, - }) - }, + setSchedule: + (_, params) => + (_, { value, onChange }) => { + onChange({ + ...value, + ...params, + }) + }, + setCronTimezone: + ({ setSchedule }, { cronPattern: cron, timezone }) => + () => { + setSchedule({ + cron, + timezone, + }) + }, + setName: + ({ setSchedule }, { target: { value } }) => + () => { + setSchedule({ + name: value.trim() === '' ? null : value, + }) + }, setRetention({ setSchedule }, value, { name }) { setSchedule({ [name]: value, diff --git a/packages/xo-web/src/xo-app/backup/new/index.js b/packages/xo-web/src/xo-app/backup/new/index.js index 7e7a7d5ac..ce4663767 100644 --- a/packages/xo-web/src/xo-app/backup/new/index.js +++ b/packages/xo-web/src/xo-app/backup/new/index.js @@ -212,11 +212,12 @@ const DeleteOldBackupsFirst = ({ handler, handlerParam, value }) => ( ) const New = decorate([ - New => props => ( - - - - ), + New => props => + ( + + + + ), connectStore(() => ({ hostsById: createGetObjectsOfType('host'), poolsById: createGetObjectsOfType('pool'), @@ -349,14 +350,18 @@ const New = decorate([ vms: state.smartMode ? state.vmsSmartPattern : constructPattern(state.vms), }) }, - toggleMode: (_, { mode }) => state => ({ - ...state, - [mode]: !state[mode], - }), - setCheckboxValue: (_, { target: { checked, name } }) => state => ({ - ...state, - [name]: checked, - }), + toggleMode: + (_, { mode }) => + state => ({ + ...state, + [mode]: !state[mode], + }), + setCheckboxValue: + (_, { target: { checked, name } }) => + state => ({ + ...state, + [name]: checked, + }), toggleScheduleState: (_, id) => state => ({ ...state, schedules: { @@ -367,15 +372,19 @@ const New = decorate([ }, }, }), - setName: (_, { target: { value } }) => state => ({ - ...state, - name: value, - }), - setTargetDeleteFirst: (_, id) => ({ propSettings, settings = propSettings }) => ({ - settings: settings.set(id, { - deleteFirst: !settings.getIn([id, 'deleteFirst']), + setName: + (_, { target: { value } }) => + state => ({ + ...state, + name: value, + }), + setTargetDeleteFirst: + (_, id) => + ({ propSettings, settings = propSettings }) => ({ + settings: settings.set(id, { + deleteFirst: !settings.getIn([id, 'deleteFirst']), + }), }), - }), addRemote: (_, remote) => state => { return { ...state, @@ -403,95 +412,103 @@ const New = decorate([ } }, setVms: (_, vms) => state => ({ ...state, vms }), - updateParams: () => (_, { job, schedules }) => { - const remotes = job.remotes !== undefined ? destructPattern(job.remotes) : [] - const srs = job.srs !== undefined ? destructPattern(job.srs) : [] + updateParams: + () => + (_, { job, schedules }) => { + const remotes = job.remotes !== undefined ? destructPattern(job.remotes) : [] + const srs = job.srs !== undefined ? destructPattern(job.srs) : [] - return { - name: job.name, - smartMode: job.vms.id === undefined, - snapshotMode: some(job.settings, ({ snapshotRetention }) => snapshotRetention > 0), - backupMode: job.mode === 'full' && !isEmpty(remotes), - deltaMode: job.mode === 'delta' && !isEmpty(remotes), - drMode: job.mode === 'full' && !isEmpty(srs), - crMode: job.mode === 'delta' && !isEmpty(srs), - remotes, - srs, - schedules, - ...destructVmsPattern(job.vms), - } - }, - showScheduleModal: ({ saveSchedule }, storedSchedule = DEFAULT_SCHEDULE) => async ( - { copyMode, exportMode, deltaMode, isDelta, propSettings, settings = propSettings, snapshotMode }, - { intl: { formatMessage } } - ) => { - const modes = { copyMode, isDelta, exportMode, snapshotMode } - const schedule = await form({ - defaultValue: storedSchedule, - render: props => ( - - ), - header: ( - - {_('schedule')} - - ), - size: 'large', - handler: value => { - if (!checkRetentions(value, modes)) { - throw new UserError(_('newScheduleError'), _('retentionNeeded')) - } - return value - }, - }) - - saveSchedule({ - ...schedule, - id: storedSchedule.id || generateRandomId(), - }) - }, - deleteSchedule: (_, schedule) => ({ schedules: oldSchedules, propSettings, settings = propSettings }) => { - const id = resolveId(schedule) - const schedules = { ...oldSchedules } - delete schedules[id] - return { - schedules, - settings: settings.delete(id), - } - }, - saveSchedule: ( - _, - { copyRetention, cron, enabled = true, exportRetention, fullInterval, id, name, snapshotRetention, timezone } - ) => ({ propSettings, schedules, settings = propSettings }) => ({ - schedules: { - ...schedules, - [id]: { - ...schedules[id], - cron, - enabled, - id, - name, - timezone, - }, + return { + name: job.name, + smartMode: job.vms.id === undefined, + snapshotMode: some(job.settings, ({ snapshotRetention }) => snapshotRetention > 0), + backupMode: job.mode === 'full' && !isEmpty(remotes), + deltaMode: job.mode === 'delta' && !isEmpty(remotes), + drMode: job.mode === 'full' && !isEmpty(srs), + crMode: job.mode === 'delta' && !isEmpty(srs), + remotes, + srs, + schedules, + ...destructVmsPattern(job.vms), + } }, - settings: settings.set(id, { - copyRetention, - exportRetention, - fullInterval, - snapshotRetention, + showScheduleModal: + ({ saveSchedule }, storedSchedule = DEFAULT_SCHEDULE) => + async ( + { copyMode, exportMode, deltaMode, isDelta, propSettings, settings = propSettings, snapshotMode }, + { intl: { formatMessage } } + ) => { + const modes = { copyMode, isDelta, exportMode, snapshotMode } + const schedule = await form({ + defaultValue: storedSchedule, + render: props => ( + + ), + header: ( + + {_('schedule')} + + ), + size: 'large', + handler: value => { + if (!checkRetentions(value, modes)) { + throw new UserError(_('newScheduleError'), _('retentionNeeded')) + } + return value + }, + }) + + saveSchedule({ + ...schedule, + id: storedSchedule.id || generateRandomId(), + }) + }, + deleteSchedule: + (_, schedule) => + ({ schedules: oldSchedules, propSettings, settings = propSettings }) => { + const id = resolveId(schedule) + const schedules = { ...oldSchedules } + delete schedules[id] + return { + schedules, + settings: settings.delete(id), + } + }, + saveSchedule: + ( + _, + { copyRetention, cron, enabled = true, exportRetention, fullInterval, id, name, snapshotRetention, timezone } + ) => + ({ propSettings, schedules, settings = propSettings }) => ({ + schedules: { + ...schedules, + [id]: { + ...schedules[id], + cron, + enabled, + id, + name, + timezone, + }, + }, + settings: settings.set(id, { + copyRetention, + exportRetention, + fullInterval, + snapshotRetention, + }), }), - }), onVmsPatternChange: (_, _vmsPattern) => ({ _vmsPattern, }), @@ -509,26 +526,32 @@ const New = decorate([ notValues, }, }), - resetJob: ({ updateParams }) => (state, { job }) => { - if (job !== undefined) { - updateParams() - } + resetJob: + ({ updateParams }) => + (state, { job }) => { + if (job !== undefined) { + updateParams() + } - return getInitialState() - }, + return getInitialState() + }, setCompression: (_, compression) => ({ compression }), setProxy(_, id) { this.state._proxyId = id }, - toggleDisplayAdvancedSettings: () => ({ displayAdvancedSettings }) => ({ - _displayAdvancedSettings: !displayAdvancedSettings, - }), - setGlobalSettings: (_, globalSettings) => ({ propSettings, settings = propSettings }) => ({ - settings: settings.update('', setting => ({ - ...setting, - ...globalSettings, - })), - }), + toggleDisplayAdvancedSettings: + () => + ({ displayAdvancedSettings }) => ({ + _displayAdvancedSettings: !displayAdvancedSettings, + }), + setGlobalSettings: + (_, globalSettings) => + ({ propSettings, settings = propSettings }) => ({ + settings: settings.update('', setting => ({ + ...setting, + ...globalSettings, + })), + }), addReportRecipient({ setGlobalSettings }, value) { const { propSettings, settings = propSettings } = this.state const reportRecipients = defined(settings.getIn(['', 'reportRecipients']), []) @@ -545,31 +568,39 @@ const New = decorate([ reportRecipients: (reportRecipients.splice(key, 1), reportRecipients), }) }, - setReportWhen: ({ setGlobalSettings }, { value }) => () => { - setGlobalSettings({ - reportWhen: value, - }) - }, - setConcurrency: ({ setGlobalSettings }, concurrency) => () => { - setGlobalSettings({ - concurrency, - }) - }, - setTimeout: ({ setGlobalSettings }, value) => () => { - setGlobalSettings({ - timeout: value && value * 3600e3, - }) - }, + setReportWhen: + ({ setGlobalSettings }, { value }) => + () => { + setGlobalSettings({ + reportWhen: value, + }) + }, + setConcurrency: + ({ setGlobalSettings }, concurrency) => + () => { + setGlobalSettings({ + concurrency, + }) + }, + setTimeout: + ({ setGlobalSettings }, value) => + () => { + setGlobalSettings({ + timeout: value && value * 3600e3, + }) + }, setFullInterval({ setGlobalSettings }, fullInterval) { setGlobalSettings({ fullInterval, }) }, - setOfflineBackup: ({ setGlobalSettings }, { target: { checked: offlineBackup } }) => () => { - setGlobalSettings({ - offlineBackup, - }) - }, + setOfflineBackup: + ({ setGlobalSettings }, { target: { checked: offlineBackup } }) => + () => { + setGlobalSettings({ + offlineBackup, + }) + }, }, computed: { compressionId: generateId, @@ -618,11 +649,13 @@ const New = decorate([ ...vmsPattern, tags: constructSmartPattern(tags, normalizeTagValues), }), - vmPredicate: ({ isDelta }, { hostsById, poolsById }) => ({ $container }) => - !isDelta || - canDeltaBackup( - get(() => hostsById[$container].version) || get(() => hostsById[poolsById[$container].master].version) - ), + vmPredicate: + ({ isDelta }, { hostsById, poolsById }) => + ({ $container }) => + !isDelta || + canDeltaBackup( + get(() => hostsById[$container].version) || get(() => hostsById[poolsById[$container].master].version) + ), selectedVmIds: state => resolveIds(state.vms), showRetentionWarning: ({ deltaMode, propSettings, settings = propSettings, schedules }) => { if (!deltaMode) { @@ -639,13 +672,18 @@ const New = decorate([ ) ) }, - srPredicate: ({ srs }) => sr => isSrWritable(sr) && !includes(srs, sr.id), - remotePredicate: ({ proxyId, remotes }) => remote => { - if (proxyId === null) { - proxyId = undefined - } - return !remotes.includes(remote.id) && remote.value.proxy === proxyId - }, + srPredicate: + ({ srs }) => + sr => + isSrWritable(sr) && !includes(srs, sr.id), + remotePredicate: + ({ proxyId, remotes }) => + remote => { + if (proxyId === null) { + proxyId = undefined + } + return !remotes.includes(remote.id) && remote.value.proxy === proxyId + }, propSettings: (_, { job }) => Map(get(() => job.settings)).map(setting => defined(setting.copyRetention, setting.exportRetention, setting.snapshotRetention) diff --git a/packages/xo-web/src/xo-app/backup/new/metadata/index.js b/packages/xo-web/src/xo-app/backup/new/metadata/index.js index aacec4e8e..5aaea44a2 100644 --- a/packages/xo-web/src/xo-app/backup/new/metadata/index.js +++ b/packages/xo-web/src/xo-app/backup/new/metadata/index.js @@ -72,11 +72,12 @@ const getInitialState = () => ({ }) export default decorate([ - New => props => ( - - - - ), + New => props => + ( + + + + ), addSubscriptions({ remotes: subscribeRemotes, }), @@ -166,24 +167,30 @@ export default decorate([ setSettings: (_, _settings) => () => ({ _settings, }), - setGlobalSettings: ({ setSettings }, name, value) => ({ settings = {} }) => { - setSettings({ - ...settings, - [GLOBAL_SETTING_KEY]: { - ...settings[GLOBAL_SETTING_KEY], - [name]: value, - }, - }) - }, + setGlobalSettings: + ({ setSettings }, name, value) => + ({ settings = {} }) => { + setSettings({ + ...settings, + [GLOBAL_SETTING_KEY]: { + ...settings[GLOBAL_SETTING_KEY], + [name]: value, + }, + }) + }, setReportWhen({ setGlobalSettings }, { value }) { setGlobalSettings('reportWhen', value) }, - toggleMode: (_, { mode }) => state => ({ - [`_${mode}`]: !state[mode], - }), - addRemote: (_, { id }) => state => ({ - _remotes: [...state.remotes, id], - }), + toggleMode: + (_, { mode }) => + state => ({ + [`_${mode}`]: !state[mode], + }), + addRemote: + (_, { id }) => + state => ({ + _remotes: [...state.remotes, id], + }), deleteRemote: (_, key) => state => { const _remotes = [...state.remotes] _remotes.splice(key, 1) @@ -227,12 +234,14 @@ export default decorate([ }) ), remotes: ({ _remotes }, { job }) => defined(_remotes, () => destructPattern(job.remotes), []), - remotesPredicate: ({ proxyId, remotes }) => remote => { - if (proxyId === null) { - proxyId = undefined - } - return !remotes.includes(remote.id) && remote.value.proxy === proxyId - }, + remotesPredicate: + ({ proxyId, remotes }) => + remote => { + if (proxyId === null) { + proxyId = undefined + } + return !remotes.includes(remote.id) && remote.value.proxy === proxyId + }, isJobInvalid: state => state.missingModes || diff --git a/packages/xo-web/src/xo-app/backup/new/new-schedule.js b/packages/xo-web/src/xo-app/backup/new/new-schedule.js index f477e3450..ce15fcbd0 100644 --- a/packages/xo-web/src/xo-app/backup/new/new-schedule.js +++ b/packages/xo-web/src/xo-app/backup/new/new-schedule.js @@ -20,38 +20,50 @@ const New = decorate([ idInputName: generateId, }, effects: { - setSchedule: (_, params) => (_, { value, onChange }) => { - onChange({ - ...value, - ...params, - }) - }, - setExportRetention: ({ setSchedule }, exportRetention) => () => { - setSchedule({ - exportRetention, - }) - }, - setCopyRetention: ({ setSchedule }, copyRetention) => () => { - setSchedule({ - copyRetention, - }) - }, - setSnapshotRetention: ({ setSchedule }, snapshotRetention) => () => { - setSchedule({ - snapshotRetention, - }) - }, - setCronTimezone: ({ setSchedule }, { cronPattern: cron, timezone }) => () => { - setSchedule({ - cron, - timezone, - }) - }, - setName: ({ setSchedule }, { target: { value } }) => () => { - setSchedule({ - name: value.trim() === '' ? null : value, - }) - }, + setSchedule: + (_, params) => + (_, { value, onChange }) => { + onChange({ + ...value, + ...params, + }) + }, + setExportRetention: + ({ setSchedule }, exportRetention) => + () => { + setSchedule({ + exportRetention, + }) + }, + setCopyRetention: + ({ setSchedule }, copyRetention) => + () => { + setSchedule({ + copyRetention, + }) + }, + setSnapshotRetention: + ({ setSchedule }, snapshotRetention) => + () => { + setSchedule({ + snapshotRetention, + }) + }, + setCronTimezone: + ({ setSchedule }, { cronPattern: cron, timezone }) => + () => { + setSchedule({ + cron, + timezone, + }) + }, + setName: + ({ setSchedule }, { target: { value } }) => + () => { + setSchedule({ + name: value.trim() === '' ? null : value, + }) + }, toggleForceFullBackup({ setSchedule }) { setSchedule({ fullInterval: this.state.forceFullBackup ? undefined : 1, diff --git a/packages/xo-web/src/xo-app/backup/new/schedules.js b/packages/xo-web/src/xo-app/backup/new/schedules.js index 656c534ab..0da2d34ef 100644 --- a/packages/xo-web/src/xo-app/backup/new/schedules.js +++ b/packages/xo-web/src/xo-app/backup/new/schedules.js @@ -39,10 +39,12 @@ export default decorate([ level: 'danger', }, ], - rowTransform: ({ propSettings, settings = propSettings }) => schedule => ({ - ...schedule, - ...settings.get(schedule.id), - }), + rowTransform: + ({ propSettings, settings = propSettings }) => + schedule => ({ + ...schedule, + ...settings.get(schedule.id), + }), schedulesColumns: (state, { effects: { toggleScheduleState } }) => { const columns = [ { diff --git a/packages/xo-web/src/xo-app/backup/new/smart-backup.js b/packages/xo-web/src/xo-app/backup/new/smart-backup.js index 48694554f..374db3c63 100644 --- a/packages/xo-web/src/xo-app/backup/new/smart-backup.js +++ b/packages/xo-web/src/xo-app/backup/new/smart-backup.js @@ -27,28 +27,32 @@ const SmartBackup = decorate([ }), provideState({ effects: { - setPattern: (_, value) => (_, { pattern, onChange }) => { - onChange({ - ...pattern, - ...value, - }) - }, + setPattern: + (_, value) => + (_, { pattern, onChange }) => { + onChange({ + ...pattern, + ...value, + }) + }, setPowerState({ setPattern }, powerState) { setPattern({ power_state: powerState === 'All' ? undefined : powerState, }) }, - setPoolPattern: ({ setPattern }, { values, notValues }) => ({ pools }) => { - setPattern({ - $pool: constructSmartPattern( - { - values: values || pools.values, - notValues: notValues || pools.notValues, - }, - resolveIds - ), - }) - }, + setPoolPattern: + ({ setPattern }, { values, notValues }) => + ({ pools }) => { + setPattern({ + $pool: constructSmartPattern( + { + values: values || pools.values, + notValues: notValues || pools.notValues, + }, + resolveIds + ), + }) + }, setPoolValues({ setPoolPattern }, values) { setPoolPattern({ values }) }, @@ -57,8 +61,10 @@ const SmartBackup = decorate([ }, }, computed: { - poolPredicate: (_, { deltaMode, hosts }) => pool => - !deltaMode || canDeltaBackup(get(() => hosts[pool.master].version)), + poolPredicate: + (_, { deltaMode, hosts }) => + pool => + !deltaMode || canDeltaBackup(get(() => hosts[pool.master].version)), pools: (_, { pattern }) => (pattern.$pool !== undefined ? destructSmartPattern(pattern.$pool) : {}), }, }), diff --git a/packages/xo-web/src/xo-app/dashboard/health/index.js b/packages/xo-web/src/xo-app/dashboard/health/index.js index 226810fe0..0127bcad8 100644 --- a/packages/xo-web/src/xo-app/dashboard/health/index.js +++ b/packages/xo-web/src/xo-app/dashboard/health/index.js @@ -238,21 +238,23 @@ const AttachedVdisTable = decorate([ vdis: createGetObjectsOfType('VDI'), vdiSnapshots: createGetObjectsOfType('VDI-snapshot'), }), - ({ columns, rowTransform }) => ({ pools, srs, vbds, vdis, vdiSnapshots }) => ( - - ), + ({ columns, rowTransform }) => + ({ pools, srs, vbds, vdis, vdiSnapshots }) => + ( + + ), { columns: [ { diff --git a/packages/xo-web/src/xo-app/disk-import/index.js b/packages/xo-web/src/xo-app/disk-import/index.js index b0cfb608e..361729e24 100644 --- a/packages/xo-web/src/xo-app/disk-import/index.js +++ b/packages/xo-web/src/xo-app/disk-import/index.js @@ -71,25 +71,31 @@ const DiskImport = decorate([ ) return { disks: disks.filter(disk => disk !== undefined), loadingDisks: false } }, - import: () => async ({ disks, mapDescriptions, mapNames, sr }) => { - await importDisks( - disks.map(({ id, name, ...disk }) => ({ - ...disk, - name: mapNames[id] || name, - description: mapDescriptions[id], - })), - sr - ) - }, + import: + () => + async ({ disks, mapDescriptions, mapNames, sr }) => { + await importDisks( + disks.map(({ id, name, ...disk }) => ({ + ...disk, + name: mapNames[id] || name, + description: mapDescriptions[id], + })), + sr + ) + }, linkState, - onChangeDescription: (_, { target: { name, value } }) => ({ mapDescriptions }) => { - mapDescriptions[name] = value - return { mapDescriptions } - }, - onChangeName: (_, { target: { name, value } }) => ({ mapNames }) => { - mapNames[name] = value - return { mapNames } - }, + onChangeDescription: + (_, { target: { name, value } }) => + ({ mapDescriptions }) => { + mapDescriptions[name] = value + return { mapDescriptions } + }, + onChangeName: + (_, { target: { name, value } }) => + ({ mapNames }) => { + mapNames[name] = value + return { mapNames } + }, onChangeSr: (_, sr) => ({ sr }), reset: getInitialState, }, diff --git a/packages/xo-web/src/xo-app/home/index.js b/packages/xo-web/src/xo-app/home/index.js index d8c13fe7d..eab15ab99 100644 --- a/packages/xo-web/src/xo-app/home/index.js +++ b/packages/xo-web/src/xo-app/home/index.js @@ -928,14 +928,8 @@ export default class Home extends Component { } = this.state const options = OPTIONS[type] - const { - filters, - mainActions, - otherActions, - showHostsSelector, - showPoolsSelector, - showResourceSetsSelector, - } = options + const { filters, mainActions, otherActions, showHostsSelector, showPoolsSelector, showResourceSetsSelector } = + options return ( diff --git a/packages/xo-web/src/xo-app/host/index.js b/packages/xo-web/src/xo-app/host/index.js index 3265ee7a9..fa70e9f3c 100644 --- a/packages/xo-web/src/xo-app/host/index.js +++ b/packages/xo-web/src/xo-app/host/index.js @@ -53,19 +53,33 @@ const isRunning = host => host && host.power_state === 'Running' const getPool = createGetObject((state, props) => getHost(state, props).$pool) const getVmController = createGetObjectsOfType('VM-controller').find( - createSelector(getHost, ({ id }) => obj => obj.$container === id) + createSelector( + getHost, + ({ id }) => + obj => + obj.$container === id + ) ) const getHostVms = createGetObjectsOfType('VM').filter( - createSelector(getHost, ({ id }) => obj => obj.$container === id) + createSelector( + getHost, + ({ id }) => + obj => + obj.$container === id + ) ) const getNumberOfVms = getHostVms.count() const getLogs = createGetObjectsOfType('message') .filter( - createSelector(getHost, getVmController, (host, controller) => ({ $object }) => - $object === host.id || $object === (controller !== undefined && controller.id) + createSelector( + getHost, + getVmController, + (host, controller) => + ({ $object }) => + $object === host.id || $object === (controller !== undefined && controller.id) ) ) .sort() diff --git a/packages/xo-web/src/xo-app/host/tab-advanced.js b/packages/xo-web/src/xo-app/host/tab-advanced.js index da0e479e5..7569779f5 100644 --- a/packages/xo-web/src/xo-app/host/tab-advanced.js +++ b/packages/xo-web/src/xo-app/host/tab-advanced.js @@ -88,8 +88,10 @@ const SetControlDomainMemory = ({ value, onChange }) => ( const MultipathableSrs = decorate([ connectStore({ - pbds: createGetObjectsOfType('PBD').filter((_, { hostId }) => pbd => - pbd.host === hostId && Boolean(pbd.otherConfig.multipathed) + pbds: createGetObjectsOfType('PBD').filter( + (_, { hostId }) => + pbd => + pbd.host === hostId && Boolean(pbd.otherConfig.multipathed) ), }), ({ pbds }) => diff --git a/packages/xo-web/src/xo-app/hub/recipes/recipe-form.js b/packages/xo-web/src/xo-app/hub/recipes/recipe-form.js index ffefbc10b..70a4a749f 100644 --- a/packages/xo-web/src/xo-app/hub/recipes/recipe-form.js +++ b/packages/xo-web/src/xo-app/hub/recipes/recipe-form.js @@ -44,8 +44,14 @@ export default decorate([ }, }, computed: { - networkPredicate: (_, { value: { pool } }) => network => pool.id === network.$pool, - srPredicate: (_, { value }) => sr => sr.$pool === get(() => value.pool.id) && isSrWritable(sr), + networkPredicate: + (_, { value: { pool } }) => + network => + pool.id === network.$pool, + srPredicate: + (_, { value }) => + sr => + sr.$pool === get(() => value.pool.id) && isSrWritable(sr), }, }), injectState, diff --git a/packages/xo-web/src/xo-app/hub/templates/resource.js b/packages/xo-web/src/xo-app/hub/templates/resource.js index 3b2594eb4..e8aad56eb 100644 --- a/packages/xo-web/src/xo-app/hub/templates/resource.js +++ b/packages/xo-web/src/xo-app/hub/templates/resource.js @@ -47,15 +47,8 @@ export default decorate([ }), effects: { async install() { - const { - id, - name, - namespace, - markHubResourceAsInstalled, - markHubResourceAsInstalling, - templates, - version, - } = this.props + const { id, name, namespace, markHubResourceAsInstalled, markHubResourceAsInstalling, templates, version } = + this.props const { isTemplateInstalled } = this.state const resourceParams = await form({ defaultValue: { @@ -227,10 +220,14 @@ export default decorate([ isTemplateInstalledOnAllPools: ({ installedTemplates }, { pools }) => installedTemplates.length > 0 && pools.every(pool => installedTemplates.find(template => template.$pool === pool.id) !== undefined), - isTemplateInstalled: ({ installedTemplates }) => pool => - installedTemplates.find(template => template.$pool === pool.id) === undefined, - isPoolCreated: ({ installedTemplates }) => pool => - installedTemplates.find(template => template.$pool === pool.id) !== undefined, + isTemplateInstalled: + ({ installedTemplates }) => + pool => + installedTemplates.find(template => template.$pool === pool.id) === undefined, + isPoolCreated: + ({ installedTemplates }) => + pool => + installedTemplates.find(template => template.$pool === pool.id) !== undefined, }, }), injectState, diff --git a/packages/xo-web/src/xo-app/logs/backup-ng/log-alert-body.js b/packages/xo-web/src/xo-app/logs/backup-ng/log-alert-body.js index f8d8f1ccf..0e1b33957 100644 --- a/packages/xo-web/src/xo-app/logs/backup-ng/log-alert-body.js +++ b/packages/xo-web/src/xo-app/logs/backup-ng/log-alert-body.js @@ -307,14 +307,16 @@ export default decorate([ this.state._status = status this.state.page = 1 }, - restartVmJob: (_, params) => async (_, { log: { scheduleId, jobId } }) => { - await runBackupNgJob({ - force: get(() => params.force), - id: jobId, - schedule: scheduleId, - vm: get(() => params.vm), - }) - }, + restartVmJob: + (_, params) => + async (_, { log: { scheduleId, jobId } }) => { + await runBackupNgJob({ + force: get(() => params.force), + id: jobId, + schedule: scheduleId, + vm: get(() => params.vm), + }) + }, }, computed: { log: (_, { log, pools, vms }) => { @@ -361,11 +363,14 @@ export default decorate([ const start = (page - 1) * ITEMS_PER_PAGE return tasksFilteredByStatus.slice(start, start + ITEMS_PER_PAGE) }, - optionRenderer: ({ countByStatus }) => ({ label, value }) => ( - - {_(label)} ({countByStatus[value] || 0}) - - ), + optionRenderer: + ({ countByStatus }) => + ({ label, value }) => + ( + + {_(label)} ({countByStatus[value] || 0}) + + ), countByStatus: ({ preFilteredTasksLogs }) => ({ all: get(() => preFilteredTasksLogs.length), ...countBy(preFilteredTasksLogs, 'status'), diff --git a/packages/xo-web/src/xo-app/logs/backup-ng/log-alert-header.js b/packages/xo-web/src/xo-app/logs/backup-ng/log-alert-header.js index 65e179dd4..79529f56e 100644 --- a/packages/xo-web/src/xo-app/logs/backup-ng/log-alert-header.js +++ b/packages/xo-web/src/xo-app/logs/backup-ng/log-alert-header.js @@ -27,33 +27,37 @@ export default decorate([ })), provideState({ effects: { - _downloadLog: () => ({ formattedLog }, { log }) => - downloadLog({ log: formattedLog, date: log.start, type: 'backup NG' }), - restartFailedVms: (_, params) => async (_, { log: { jobId: id, scheduleId: schedule, tasks, infos } }) => { - let vms - if (tasks !== undefined) { - const scheduledVms = get(() => infos.find(({ message }) => message === 'vms').data.vms) + _downloadLog: + () => + ({ formattedLog }, { log }) => + downloadLog({ log: formattedLog, date: log.start, type: 'backup NG' }), + restartFailedVms: + (_, params) => + async (_, { log: { jobId: id, scheduleId: schedule, tasks, infos } }) => { + let vms + if (tasks !== undefined) { + const scheduledVms = get(() => infos.find(({ message }) => message === 'vms').data.vms) - if (scheduledVms !== undefined) { - vms = new Set(scheduledVms) - tasks.forEach(({ status, data: { id } }) => { - status === 'success' && vms.delete(id) - }) - vms = Array.from(vms) - } else { - vms = [] - tasks.forEach(({ status, data: { id } }) => { - status !== 'success' && vms.push(id) - }) + if (scheduledVms !== undefined) { + vms = new Set(scheduledVms) + tasks.forEach(({ status, data: { id } }) => { + status === 'success' && vms.delete(id) + }) + vms = Array.from(vms) + } else { + vms = [] + tasks.forEach(({ status, data: { id } }) => { + status !== 'success' && vms.push(id) + }) + } } - } - await runBackupNgJob({ - force: get(() => params.force), - id, - schedule, - vms, - }) - }, + await runBackupNgJob({ + force: get(() => params.force), + id, + schedule, + vms, + }) + }, }, computed: { formattedLog: (_, { log }) => JSON.stringify(log, null, 2), diff --git a/packages/xo-web/src/xo-app/new-vm/index.js b/packages/xo-web/src/xo-app/new-vm/index.js index 125c2f5d8..e18bf947f 100644 --- a/packages/xo-web/src/xo-app/new-vm/index.js +++ b/packages/xo-web/src/xo-app/new-vm/index.js @@ -260,7 +260,7 @@ export default class NewVm extends BaseComponent { () => this.props.resourceSets, createSelector( () => this.props.location.query.resourceSet, - resourceSetId => resourceSet => (resourceSet !== undefined ? resourceSetId === resourceSet.id : undefined) + resourceSetId => resourceSet => resourceSet !== undefined ? resourceSetId === resourceSet.id : undefined ) ) @@ -582,7 +582,9 @@ export default class NewVm extends BaseComponent { const { pool } = this.props return pool && pool.id }, - poolId => ({ $pool }) => $pool === poolId + poolId => + ({ $pool }) => + $pool === poolId ) _getIsInResourceSet = createSelector( () => { @@ -592,8 +594,10 @@ export default class NewVm extends BaseComponent { objectsIds => id => includes(objectsIds, id) ) - _getVmPredicate = createSelector(this._getIsInPool, this._getIsInResourceSet, (isInPool, isInResourceSet) => vm => - isInResourceSet(vm.id) || isInPool(vm) + _getVmPredicate = createSelector( + this._getIsInPool, + this._getIsInResourceSet, + (isInPool, isInResourceSet) => vm => isInResourceSet(vm.id) || isInPool(vm) ) _getSrPredicate = createSelector( this._getIsInPool, diff --git a/packages/xo-web/src/xo-app/new/network/index.js b/packages/xo-web/src/xo-app/new/network/index.js index f985c4e44..846fc70c7 100644 --- a/packages/xo-web/src/xo-app/new/network/index.js +++ b/packages/xo-web/src/xo-app/new/network/index.js @@ -102,7 +102,10 @@ const NewNetwork = decorate([ initialize: async () => ({ bondModes: await getBondModes() }), linkState, onChangeMode: (_, bondMode) => ({ bondMode }), - onChangePif: (_, value) => ({ bonded }) => (bonded ? { pifs: value } : { pif: value }), + onChangePif: + (_, value) => + ({ bonded }) => + bonded ? { pifs: value } : { pif: value }, onChangeEncapsulation(_, encapsulation) { return { encapsulation: encapsulation.value } }, @@ -144,16 +147,29 @@ const NewNetwork = decorate([ value: mode, })) : [], - hostPredicate: ({ networks }, { pool }) => host => - host.$pool === pool.id || networks.some(({ pool }) => pool !== undefined && pool.id === host.$pool), - pifPredicate: (_, { pool }) => pif => !pif.isBondSlave && pif.vlan === -1 && pif.$host === (pool && pool.master), - pifPredicateSdnController: (_, { pool }) => pif => canSupportPrivateNetwork(pool, pif), - networkPifPredicate: ({ networks }) => (pif, key) => canSupportPrivateNetwork(networks[key].pool, pif), - networkPoolPredicate: ({ networks }, { pool: rootPool }) => (pool, index) => - pool.id !== rootPool.id && - !networks.some( - ({ pool: networksPool = {} }, networksIndex) => pool.id === networksPool.id && index !== networksIndex - ), + hostPredicate: + ({ networks }, { pool }) => + host => + host.$pool === pool.id || networks.some(({ pool }) => pool !== undefined && pool.id === host.$pool), + pifPredicate: + (_, { pool }) => + pif => + !pif.isBondSlave && pif.vlan === -1 && pif.$host === (pool && pool.master), + pifPredicateSdnController: + (_, { pool }) => + pif => + canSupportPrivateNetwork(pool, pif), + networkPifPredicate: + ({ networks }) => + (pif, key) => + canSupportPrivateNetwork(networks[key].pool, pif), + networkPoolPredicate: + ({ networks }, { pool: rootPool }) => + (pool, index) => + pool.id !== rootPool.id && + !networks.some( + ({ pool: networksPool = {} }, networksIndex) => pool.id === networksPool.id && index !== networksIndex + ), isSdnControllerLoaded: (state, { plugins = [] }) => plugins.some(plugin => plugin.name === 'sdn-controller' && plugin.loaded), }, diff --git a/packages/xo-web/src/xo-app/pool/index.js b/packages/xo-web/src/xo-app/pool/index.js index c7d62b838..cca9e04d9 100644 --- a/packages/xo-web/src/xo-app/pool/index.js +++ b/packages/xo-web/src/xo-app/pool/index.js @@ -35,23 +35,56 @@ import TabPatches from './tab-patches' const getMaster = createGetObject((state, props) => getPool(state, props).master) const getNetworks = createGetObjectsOfType('network') - .filter(createSelector(getPool, ({ id }) => network => network.$pool === id)) + .filter( + createSelector( + getPool, + ({ id }) => + network => + network.$pool === id + ) + ) .sort() const getPifs = createGetObjectsOfType('PIF') - .filter(createSelector(getPool, ({ id }) => pif => pif.$pool === id)) + .filter( + createSelector( + getPool, + ({ id }) => + pif => + pif.$pool === id + ) + ) .sort() const getHosts = createGetObjectsOfType('host') - .filter(createSelector(getPool, ({ id }) => obj => obj.$pool === id)) + .filter( + createSelector( + getPool, + ({ id }) => + obj => + obj.$pool === id + ) + ) .sort() const getPoolSrs = createGetObjectsOfType('SR') - .filter(createSelector(getPool, ({ id }) => sr => sr.$pool === id)) + .filter( + createSelector( + getPool, + ({ id }) => + sr => + sr.$pool === id + ) + ) .sort() const getNumberOfVms = createGetObjectsOfType('VM').count( - createSelector(getPool, ({ id }) => obj => obj.$pool === id) + createSelector( + getPool, + ({ id }) => + obj => + obj.$pool === id + ) ) const getLogs = createGetObjectMessages(getPool) diff --git a/packages/xo-web/src/xo-app/pool/tab-advanced.js b/packages/xo-web/src/xo-app/pool/tab-advanced.js index ef1a0bddf..62a9c3402 100644 --- a/packages/xo-web/src/xo-app/pool/tab-advanced.js +++ b/packages/xo-web/src/xo-app/pool/tab-advanced.js @@ -61,7 +61,12 @@ class PoolMaster extends Component { .sort() return { hosts: getHosts, - hostsByMultipathing: createGroupBy(getHosts, () => ({ multipathing }) => (multipathing ? 'enabled' : 'disabled')), + hostsByMultipathing: createGroupBy( + getHosts, + () => + ({ multipathing }) => + multipathing ? 'enabled' : 'disabled' + ), gpuGroups: createGetObjectsOfType('gpuGroup') .filter((_, { pool }) => ({ $pool: pool.id })) .sort(), diff --git a/packages/xo-web/src/xo-app/proxies/deploy-proxy.js b/packages/xo-web/src/xo-app/proxies/deploy-proxy.js index 287b8774f..17f54e670 100644 --- a/packages/xo-web/src/xo-app/proxies/deploy-proxy.js +++ b/packages/xo-web/src/xo-app/proxies/deploy-proxy.js @@ -79,8 +79,10 @@ const Modal = decorate([ idSelectSr: generateId, isStaticMode: (state, { value }) => value.networkMode === 'static', - srPredicate: (state, { pbds, hosts }) => sr => - isSrWritable(sr) && sr.$PBDs.some(pbd => get(() => hosts[pbds[pbd].host].hvmCapable)), + srPredicate: + (state, { pbds, hosts }) => + sr => + isSrWritable(sr) && sr.$PBDs.some(pbd => get(() => hosts[pbds[pbd].host].hvmCapable)), networkPredicate: (state, { value }) => value.sr && (network => value.sr.$pool === network.$pool), }, }), diff --git a/packages/xo-web/src/xo-app/settings/acls/index.js b/packages/xo-web/src/xo-app/settings/acls/index.js index e8d136c0d..093725f56 100644 --- a/packages/xo-web/src/xo-app/settings/acls/index.js +++ b/packages/xo-web/src/xo-app/settings/acls/index.js @@ -145,7 +145,9 @@ export default class Acls extends Component { _getObjectPredicate = createSelector( () => this.state.typeFilters, () => this.state.someTypeFilters, - (typeFilters, someTypeFilters) => ({ type }) => !someTypeFilters || typeFilters[type] + (typeFilters, someTypeFilters) => + ({ type }) => + !someTypeFilters || typeFilters[type] ) _selectAll = () => { diff --git a/packages/xo-web/src/xo-app/settings/cloud-configs/index.js b/packages/xo-web/src/xo-app/settings/cloud-configs/index.js index 0c5a7ef47..7809ec53b 100644 --- a/packages/xo-web/src/xo-app/settings/cloud-configs/index.js +++ b/packages/xo-web/src/xo-app/settings/cloud-configs/index.js @@ -62,31 +62,39 @@ export default decorate([ provideState({ initialState: () => initialParams, effects: { - setInputValue: (_, { target: { name, value } }) => state => ({ - ...state, - [name]: value, - }), + setInputValue: + (_, { target: { name, value } }) => + state => ({ + ...state, + [name]: value, + }), reset: () => state => ({ ...state, ...initialParams, }), - createCloudConfig: ({ reset }) => async ({ name, template = DEFAULT_CLOUD_CONFIG_TEMPLATE }) => { - await createCloudConfig({ name, template }) - reset() - }, - editCloudConfig: ({ reset }) => async ({ name, template, cloudConfigToEditId }, { cloudConfigs }) => { - const oldCloudConfig = find(cloudConfigs, { id: cloudConfigToEditId }) - if (oldCloudConfig.name !== name || oldCloudConfig.template !== template) { - await editCloudConfig(cloudConfigToEditId, { name, template }) - } - reset() - }, - populateForm: (_, { id, name, template }) => state => ({ - ...state, - name, - cloudConfigToEditId: id, - template, - }), + createCloudConfig: + ({ reset }) => + async ({ name, template = DEFAULT_CLOUD_CONFIG_TEMPLATE }) => { + await createCloudConfig({ name, template }) + reset() + }, + editCloudConfig: + ({ reset }) => + async ({ name, template, cloudConfigToEditId }, { cloudConfigs }) => { + const oldCloudConfig = find(cloudConfigs, { id: cloudConfigToEditId }) + if (oldCloudConfig.name !== name || oldCloudConfig.template !== template) { + await editCloudConfig(cloudConfigToEditId, { name, template }) + } + reset() + }, + populateForm: + (_, { id, name, template }) => + state => ({ + ...state, + name, + cloudConfigToEditId: id, + template, + }), }, computed: { formId: generateId, diff --git a/packages/xo-web/src/xo-app/settings/remotes/remote.js b/packages/xo-web/src/xo-app/settings/remotes/remote.js index f83bb3e43..01b625527 100644 --- a/packages/xo-web/src/xo-app/settings/remotes/remote.js +++ b/packages/xo-web/src/xo-app/settings/remotes/remote.js @@ -51,92 +51,96 @@ export default decorate([ setProxy(_, proxy) { this.state.proxyId = resolveId(proxy) }, - editRemote: ({ reset }) => state => { - const { - remote, - domain = remote.domain || '', - host = remote.host, - name, - options = remote.options || '', - password = remote.password, - port = remote.port, - proxyId = remote.proxy, - type = remote.type, - username = remote.username, - protocol = remote.protocol || 'https', - region = remote.region, - } = state - let { path = remote.path } = state - if (type === 's3') { - const { parsedPath, bucket = parsedPath.split('/')[0], directory = parsedPath.split('/')[1] } = state - path = bucket + '/' + directory - } - return editRemote(remote, { - name, - url: format({ - domain, + editRemote: + ({ reset }) => + state => { + const { + remote, + domain = remote.domain || '', + host = remote.host, + name, + options = remote.options || '', + password = remote.password, + port = remote.port, + proxyId = remote.proxy, + type = remote.type, + username = remote.username, + protocol = remote.protocol || 'https', + region = remote.region, + } = state + let { path = remote.path } = state + if (type === 's3') { + const { parsedPath, bucket = parsedPath.split('/')[0], directory = parsedPath.split('/')[1] } = state + path = bucket + '/' + directory + } + return editRemote(remote, { + name, + url: format({ + domain, + host, + password, + path, + port: port || undefined, + type, + username, + protocol, + region, + }), + options: options !== '' ? options : null, + proxy: proxyId, + }).then(reset) + }, + createRemote: + ({ reset }) => + async (state, { remotes }) => { + if (some(remotes, { name: state.name })) { + return alert( + + {_('remoteTestName')} + , +

{_('remoteTestNameFailure')}

+ ) + } + + const { + domain = 'WORKGROUP', host, + name, + options, password, path, - port: port || undefined, - type, + port, + proxyId, + type = 'nfs', username, - protocol, - region, - }), - options: options !== '' ? options : null, - proxy: proxyId, - }).then(reset) - }, - createRemote: ({ reset }) => async (state, { remotes }) => { - if (some(remotes, { name: state.name })) { - return alert( - - {_('remoteTestName')} - , -

{_('remoteTestNameFailure')}

- ) - } + } = state - const { - domain = 'WORKGROUP', - host, - name, - options, - password, - path, - port, - proxyId, - type = 'nfs', - username, - } = state + const urlParams = { + host, + path, + port, + type, + } + if (type === 's3') { + const { bucket, directory } = state + urlParams.path = bucket + '/' + directory + } + username && (urlParams.username = username) + password && (urlParams.password = password) + domain && (urlParams.domain = domain) - const urlParams = { - host, - path, - port, - type, - } - if (type === 's3') { - const { bucket, directory } = state - urlParams.path = bucket + '/' + directory - } - username && (urlParams.username = username) - password && (urlParams.password = password) - domain && (urlParams.domain = domain) + if (type === 'file') { + await confirm({ + title: _('localRemoteWarningTitle'), + body: _('localRemoteWarningMessage'), + }) + } - if (type === 'file') { - await confirm({ - title: _('localRemoteWarningTitle'), - body: _('localRemoteWarningMessage'), - }) - } - - const url = format(urlParams) - return createRemote(name, url, options !== '' ? options : undefined, proxyId === null ? undefined : proxyId) - .then(reset) - .catch(err => error('Create Remote', err.message || String(err))) - }, + const url = format(urlParams) + return createRemote(name, url, options !== '' ? options : undefined, proxyId === null ? undefined : proxyId) + .then(reset) + .catch(err => error('Create Remote', err.message || String(err))) + }, setSecretKey(_, { target: { value } }) { this.state.password = value }, diff --git a/packages/xo-web/src/xo-app/sr/tab-general.js b/packages/xo-web/src/xo-app/sr/tab-general.js index 506e2347c..8fc3e181f 100644 --- a/packages/xo-web/src/xo-app/sr/tab-general.js +++ b/packages/xo-web/src/xo-app/sr/tab-general.js @@ -210,16 +210,18 @@ export default class TabGeneral extends Component { } ) - _getGenerateLink = createSelector(this._getDiskGroups, diskGroups => ids => - `#/srs/${this.props.sr.id}/disks?s=${encodeURIComponent( - `id:|(${flattenDeep( - map(pick(keyBy(diskGroups, 'id'), ids), ({ id, baseCopies, vdis, snapshots, type }) => - type === 'orphanedSnapshot' ? id : [map(baseCopies, 'id'), map(vdis, 'id'), map(snapshots, 'id')] + _getGenerateLink = createSelector( + this._getDiskGroups, + diskGroups => ids => + `#/srs/${this.props.sr.id}/disks?s=${encodeURIComponent( + `id:|(${flattenDeep( + map(pick(keyBy(diskGroups, 'id'), ids), ({ id, baseCopies, vdis, snapshots, type }) => + type === 'orphanedSnapshot' ? id : [map(baseCopies, 'id'), map(vdis, 'id'), map(snapshots, 'id')] + ) ) - ) - .sort() - .join(' ')})` - )}` + .sort() + .join(' ')})` + )}` ) render() { diff --git a/packages/xo-web/src/xo-app/sr/tab-xosan.js b/packages/xo-web/src/xo-app/sr/tab-xosan.js index c14894abb..ed7174e4c 100644 --- a/packages/xo-web/src/xo-app/sr/tab-xosan.js +++ b/packages/xo-web/src/xo-app/sr/tab-xosan.js @@ -79,7 +79,11 @@ const Field = ({ title, children }) => ( }) class Node extends Component { _replaceBrick = async ({ brick, vm }) => { - const { sr, brickSize, onSameVm = false } = await confirm({ + const { + sr, + brickSize, + onSameVm = false, + } = await confirm({ icon: 'refresh', title: _('xosanReplace'), body: , diff --git a/packages/xo-web/src/xo-app/vm/tab-advanced.js b/packages/xo-web/src/xo-app/vm/tab-advanced.js index 9daa24dbc..fd6af709e 100644 --- a/packages/xo-web/src/xo-app/vm/tab-advanced.js +++ b/packages/xo-web/src/xo-app/vm/tab-advanced.js @@ -87,8 +87,9 @@ const shareVmProxy = vm => shareVm(vm, vm.resourceSet) const getSrs = createGetObjectsOfType('SR').pick(createSelector(getVdis, vdis => uniq(map(vdis, '$SR')))) const getSrsContainers = createSelector(getSrs, srs => uniq(map(srs, '$container'))) - const getAffinityHostPredicate = createSelector(getSrsContainers, containers => host => - every(containers, container => container === host.$pool || container === host.id) + const getAffinityHostPredicate = createSelector( + getSrsContainers, + containers => host => every(containers, container => container === host.$pool || container === host.id) ) return { @@ -275,7 +276,9 @@ class AddAclsModal extends Component { _getPredicate = createSelector( () => this.props.acls, () => this.props.vm, - (acls, object) => ({ id: subject, permission }) => permission !== 'admin' && !some(acls, { object, subject }) + (acls, object) => + ({ id: subject, permission }) => + permission !== 'admin' && !some(acls, { object, subject }) ) render() { @@ -306,25 +309,29 @@ const Acls = decorate([ }), provideState({ effects: { - addAcls: () => (state, { acls, vm }) => - confirm({ - title: _('vmAddAcls'), - body: , - }) - .then(({ action, subjects }) => { - if (action == null || isEmpty(subjects)) { - return error(_('addAclsErrorTitle'), _('addAclsErrorMessage')) - } - - return Promise.all(map(subjects, subject => addAcl({ subject, object: vm, action }))) + addAcls: + () => + (state, { acls, vm }) => + confirm({ + title: _('vmAddAcls'), + body: , }) - .catch(err => err && error(_('addAclsErrorTitle'), err.message || String(err))), - removeAcl: (_, { currentTarget: { dataset } }) => (_, { vm: object }) => - removeAcl({ - action: dataset.action, - object, - subject: dataset.subject, - }), + .then(({ action, subjects }) => { + if (action == null || isEmpty(subjects)) { + return error(_('addAclsErrorTitle'), _('addAclsErrorMessage')) + } + + return Promise.all(map(subjects, subject => addAcl({ subject, object: vm, action }))) + }) + .catch(err => err && error(_('addAclsErrorTitle'), err.message || String(err))), + removeAcl: + (_, { currentTarget: { dataset } }) => + (_, { vm: object }) => + removeAcl({ + action: dataset.action, + object, + subject: dataset.subject, + }), }, computed: { rawAcls: (_, { acls, vm }) => filter(acls, { object: vm }), diff --git a/packages/xo-web/src/xo-app/vm/tab-backups.js b/packages/xo-web/src/xo-app/vm/tab-backups.js index d049daa11..f98a62d27 100644 --- a/packages/xo-web/src/xo-app/vm/tab-backups.js +++ b/packages/xo-web/src/xo-app/vm/tab-backups.js @@ -18,7 +18,10 @@ const BackupTab = decorate([ provideState({ computed: { jobIds: ({ predicate }, { jobs }) => filter(jobs, predicate).map(_ => _.id), - predicate: (_, { vm }) => ({ vms }) => vms !== undefined && createPredicate(omit(vms, 'power_state'))(vm), + predicate: + (_, { vm }) => + ({ vms }) => + vms !== undefined && createPredicate(omit(vms, 'power_state'))(vm), }, }), injectState, diff --git a/packages/xo-web/src/xo-app/vm/tab-disks.js b/packages/xo-web/src/xo-app/vm/tab-disks.js index bd32963ff..16b58a100 100644 --- a/packages/xo-web/src/xo-app/vm/tab-disks.js +++ b/packages/xo-web/src/xo-app/vm/tab-disks.js @@ -565,8 +565,10 @@ export default class TabDisks extends Component { } ) - _getCheckSr = createSelector(this._getRequiredHost, requiredHost => sr => - sr === undefined || isSrShared(sr) || requiredHost === undefined || sr.$container === requiredHost + _getCheckSr = createSelector( + this._getRequiredHost, + requiredHost => sr => + sr === undefined || isSrShared(sr) || requiredHost === undefined || sr.$container === requiredHost ) _getVbds = createSelector( @@ -597,12 +599,14 @@ export default class TabDisks extends Component { ) ) - _getGenerateWarningBeforeMigrate = createSelector(this._getCheckSr, check => sr => - check(sr) ? null : ( - - {_('warningVdiSr')} - - ) + _getGenerateWarningBeforeMigrate = createSelector( + this._getCheckSr, + check => sr => + check(sr) ? null : ( + + {_('warningVdiSr')} + + ) ) actions = [ diff --git a/packages/xo-web/src/xo-app/xoa/licenses/xosan.js b/packages/xo-web/src/xo-app/xoa/licenses/xosan.js index 21f9baf41..34df7f2df 100644 --- a/packages/xo-web/src/xo-app/xoa/licenses/xosan.js +++ b/packages/xo-web/src/xo-app/xoa/licenses/xosan.js @@ -129,9 +129,10 @@ export default class Xosan extends Component { } ) - _getAvailableLicenses = createFilter(() => this.props.xosanLicenses, [ - ({ boundObjectId, expires }) => boundObjectId === undefined && (expires === undefined || expires > Date.now()), - ]) + _getAvailableLicenses = createFilter( + () => this.props.xosanLicenses, + [({ boundObjectId, expires }) => boundObjectId === undefined && (expires === undefined || expires > Date.now())] + ) _getKnownXosans = createSelector( createSelector( diff --git a/packages/xo-web/src/xo-app/xosan/index.js b/packages/xo-web/src/xo-app/xosan/index.js index 0d75c7f25..d8233e29f 100644 --- a/packages/xo-web/src/xo-app/xosan/index.js +++ b/packages/xo-web/src/xo-app/xosan/index.js @@ -237,8 +237,10 @@ const XOSAN_INDIVIDUAL_ACTIONS = [ return hostsNeedRestartByPool }) - const getPoolPredicate = createSelector(getXosanSrs, getHosts, (srs, hosts) => pool => - hosts[pool.master].productBrand !== 'XCP-ng' && every(srs, sr => sr.$pool !== pool.id) + const getPoolPredicate = createSelector( + getXosanSrs, + getHosts, + (srs, hosts) => pool => hosts[pool.master].productBrand !== 'XCP-ng' && every(srs, sr => sr.$pool !== pool.id) ) return {