Fix consistent-return warnings
Closes-Bug: #1626059 Change-Id: I442f70e7550be4fdd8549095b01f2762fd8bb841
This commit is contained in:
parent
bdcffb1c2f
commit
dc54e2ec96
|
@ -3,7 +3,6 @@
|
|||
extends: openstack
|
||||
rules:
|
||||
# disabled rules from openstack config
|
||||
consistent-return: 1 # we have lots of incosistent returns which need to be fixed
|
||||
no-extra-parens: 0 # extra parens are preferred with JSX
|
||||
no-warning-comments: 0 # we're ok with FIXMEs
|
||||
no-process-env: 0 # we use it in a few places and are ok with it
|
||||
|
|
|
@ -351,6 +351,7 @@ gulp.task('build', 'Build the project.', function(cb) {
|
|||
} else if (!config.watch) {
|
||||
return cb();
|
||||
}
|
||||
return null;
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ class Router extends Backbone.Router {
|
|||
this.navigate('', {trigger: true});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
return !preventRouting;
|
||||
|
|
|
@ -37,9 +37,8 @@ export function dispatcherMixin(events, callback) {
|
|||
|
||||
export var unsavedChangesMixin = {
|
||||
onBeforeunloadEvent() {
|
||||
if (this.hasChanges()) {
|
||||
return _.result(this, 'getStayMessage') || i18n('dialog.dismiss_settings.default_message');
|
||||
}
|
||||
return this.hasChanges() &&
|
||||
(_.result(this, 'getStayMessage') || i18n('dialog.dismiss_settings.default_message'));
|
||||
},
|
||||
componentWillMount() {
|
||||
this.eventName = _.uniqueId('unsavedchanges');
|
||||
|
@ -85,6 +84,7 @@ export function pollingMixin(updateInterval, delayedStart) {
|
|||
this.stopPolling();
|
||||
return this.fetchData().then(this.scheduleDataFetch, this.scheduleDataFetch);
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
stopPolling() {
|
||||
if (this.activeTimeout) clearTimeout(this.activeTimeout);
|
||||
|
|
|
@ -184,11 +184,9 @@ var restrictionMixin = models.restrictionMixin = {
|
|||
var label = this.get('label');
|
||||
|
||||
var checkOneLimit = (obj, limitType) => {
|
||||
var limitValue, comparator;
|
||||
if (_.isUndefined(obj[limitType])) return null;
|
||||
|
||||
if (_.isUndefined(obj[limitType])) {
|
||||
return null;
|
||||
}
|
||||
var limitValue, comparator;
|
||||
switch (limitType) {
|
||||
case 'min':
|
||||
comparator = checkLimitIsReached ? (a, b) => a < b : (a, b) => a <= b;
|
||||
|
@ -204,36 +202,26 @@ var restrictionMixin = models.restrictionMixin = {
|
|||
// limitValues with overrides having priority
|
||||
limitValues[limitType] = limitValue;
|
||||
checkedLimitTypes[limitType] = true;
|
||||
if (comparator(count, limitValue)) {
|
||||
return {
|
||||
type: limitType,
|
||||
value: limitValue,
|
||||
message: obj.message || i18n('common.role_limits.' + limitType,
|
||||
{limitValue: limitValue, count: count, roleName: label})
|
||||
};
|
||||
}
|
||||
return comparator(count, limitValue) && {
|
||||
type: limitType,
|
||||
value: limitValue,
|
||||
message: obj.message ||
|
||||
i18n('common.role_limits.' + limitType, {limitValue, count, roleName: label})
|
||||
};
|
||||
};
|
||||
|
||||
// Check the overridden limit types
|
||||
messages = _.chain(overrides)
|
||||
.map((override) => {
|
||||
var exp = evaluateExpressionHelper(override.condition, models);
|
||||
|
||||
if (exp) {
|
||||
return _.map(limitTypes, _.partial(checkOneLimit, override));
|
||||
}
|
||||
return exp && _.map(limitTypes, _.partial(checkOneLimit, override));
|
||||
})
|
||||
.flatten()
|
||||
.compact()
|
||||
.value();
|
||||
// Now check the global, not-overridden limit types
|
||||
messages = messages.concat(_.chain(limitTypes)
|
||||
.map((limitType) => {
|
||||
if (checkedLimitTypes[limitType]) {
|
||||
return null;
|
||||
}
|
||||
return checkOneLimit(limitValues, limitType);
|
||||
})
|
||||
.map((limitType) => !checkedLimitTypes[limitType] && checkOneLimit(limitValues, limitType))
|
||||
.flatten()
|
||||
.compact()
|
||||
.value()
|
||||
|
@ -249,17 +237,13 @@ var restrictionMixin = models.restrictionMixin = {
|
|||
.filter({type: limitType})
|
||||
.sortBy('value')
|
||||
.value();
|
||||
if (limitType !== 'max') {
|
||||
message = message.reverse();
|
||||
}
|
||||
if (message[0]) {
|
||||
return message[0].message;
|
||||
}
|
||||
if (limitType !== 'max') message = message.reverse();
|
||||
return (message[0] || {}).message;
|
||||
});
|
||||
messages = _.compact(messages).join(' ');
|
||||
|
||||
return {
|
||||
count: count,
|
||||
count,
|
||||
limits: limitValues,
|
||||
message: messages,
|
||||
valid: !messages
|
||||
|
@ -1467,10 +1451,10 @@ models.NetworkConfiguration = BaseModel.extend(cacheMixin).extend({
|
|||
},
|
||||
validateNameServers(nameservers) {
|
||||
var errors = _.map(nameservers,
|
||||
(nameserver) => !utils.validateIP(nameserver) ?
|
||||
i18n('cluster_page.network_tab.validation.invalid_nameserver') : null
|
||||
(nameserver) => !utils.validateIP(nameserver) &&
|
||||
i18n('cluster_page.network_tab.validation.invalid_nameserver')
|
||||
);
|
||||
if (_.compact(errors).length) return {dns_nameservers: errors};
|
||||
return _.compact(errors).length ? {dns_nameservers: errors} : null;
|
||||
},
|
||||
validate(attrs, options = {}) {
|
||||
var networkingParameters = attrs.networking_parameters;
|
||||
|
@ -1666,24 +1650,11 @@ class ComponentPattern {
|
|||
this.hasWildcard = _.includes(this.parts, '*');
|
||||
}
|
||||
match(componentName) {
|
||||
if (!this.hasWildcard) {
|
||||
return this.pattern === componentName;
|
||||
}
|
||||
if (!this.hasWildcard) return this.pattern === componentName;
|
||||
|
||||
var componentParts = componentName.split(':');
|
||||
if (componentParts.length < this.parts.length) {
|
||||
return false;
|
||||
}
|
||||
var matched = true;
|
||||
_.each(this.parts, (part, index) => {
|
||||
if (part !== '*') {
|
||||
if (part !== componentParts[index]) {
|
||||
matched = false;
|
||||
return matched;
|
||||
}
|
||||
}
|
||||
});
|
||||
return matched;
|
||||
return componentParts.length >= this.parts.length &&
|
||||
_.every(this.parts, (part, index) => part === '*' || part === componentParts[index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,13 +48,11 @@ class ClusterPage {
|
|||
.then(() => this.modal.waitToOpen())
|
||||
.then(() => this.modal.clickFooterButton('Delete'))
|
||||
.findAllByCssSelector('.confirmation-form input[type=text]')
|
||||
.then((confirmInputs) => {
|
||||
if (confirmInputs.length) {
|
||||
return confirmInputs[0]
|
||||
.type(clusterName)
|
||||
.then(() => this.modal.clickFooterButton('Delete'));
|
||||
}
|
||||
})
|
||||
.then((confirmInputs) => !confirmInputs.length ||
|
||||
confirmInputs[0]
|
||||
.type(clusterName)
|
||||
.then(() => this.modal.clickFooterButton('Delete'))
|
||||
)
|
||||
.end()
|
||||
.then(() => this.modal.waitToClose())
|
||||
.waitForCssSelector('.clusters-page', 2000)
|
||||
|
@ -81,6 +79,7 @@ class ClusterPage {
|
|||
assignRoles.splice(index, 1);
|
||||
return !assignRoles.length;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
false
|
||||
)
|
||||
|
@ -109,13 +108,11 @@ class ClusterPage {
|
|||
.then(() => this.modal.checkTitle('Reset Environment'))
|
||||
.then(() => this.modal.clickFooterButton('Reset'))
|
||||
.findAllByCssSelector('.confirmation-form input[type=text]')
|
||||
.then((confirmationInputs) => {
|
||||
if (confirmationInputs.length) {
|
||||
return confirmationInputs[0]
|
||||
.type(clusterName)
|
||||
.then(() => this.modal.clickFooterButton('Reset'));
|
||||
}
|
||||
})
|
||||
.then((confirmationInputs) => !confirmationInputs.length ||
|
||||
confirmationInputs[0]
|
||||
.type(clusterName)
|
||||
.then(() => this.modal.clickFooterButton('Reset'))
|
||||
)
|
||||
.end()
|
||||
.then(() => this.modal.waitToClose())
|
||||
.waitForElementDeletion('div.progress-bar', 30000);
|
||||
|
|
|
@ -92,9 +92,7 @@ class CommonMethods {
|
|||
.clickByCssSelector('.btn-add-nodes')
|
||||
.waitForElementDeletion('.btn-add-nodes', 3000)
|
||||
.waitForCssSelector('.node', 3000)
|
||||
.then(() => {
|
||||
if (nodeNameFilter) return this.clusterPage.searchForNode(nodeNameFilter);
|
||||
})
|
||||
.then(() => !nodeNameFilter || this.clusterPage.searchForNode(nodeNameFilter))
|
||||
.then(() => this.clusterPage.checkNodeRoles(nodesRoles))
|
||||
.then(() => this.clusterPage.checkNodes(nodesAmount, nodeStatus))
|
||||
.clickByCssSelector('.btn-apply')
|
||||
|
|
|
@ -29,11 +29,7 @@ class LoginPage {
|
|||
.setFindTimeout(500)
|
||||
.setWindowSize(1280, 1024)
|
||||
.getCurrentUrl()
|
||||
.then((url) => {
|
||||
if (url !== Helpers.serverUrl + '/#login') {
|
||||
return this.logout();
|
||||
}
|
||||
})
|
||||
.then((url) => url === Helpers.serverUrl + '/#login' || this.logout())
|
||||
.setInputValue('[name=username]', username)
|
||||
.setInputValue('[name=password]', password)
|
||||
.clickByCssSelector('.login-btn');
|
||||
|
@ -42,14 +38,12 @@ class LoginPage {
|
|||
logout() {
|
||||
return this.remote
|
||||
.getCurrentUrl()
|
||||
.then((url) => {
|
||||
if (url.indexOf(Helpers.serverUrl) !== 0) {
|
||||
return this.remote
|
||||
.get(Helpers.serverUrl + '/#logout')
|
||||
.findByClassName('login-btn')
|
||||
.then(() => true);
|
||||
}
|
||||
})
|
||||
.then((url) => url.indexOf(Helpers.serverUrl) === 0 ||
|
||||
this.remote
|
||||
.get(Helpers.serverUrl + '/#logout')
|
||||
.findByClassName('login-btn')
|
||||
.then(() => true)
|
||||
)
|
||||
.clickByCssSelector('li.user-icon')
|
||||
.clickByCssSelector('.user-popover button.btn-logout')
|
||||
.findByCssSelector('.login-btn')
|
||||
|
|
|
@ -55,9 +55,7 @@ registerSuite(() => {
|
|||
.findByCssSelector('.btn-revert-changes')
|
||||
.then(
|
||||
(element) => element.isEnabled()
|
||||
.then((isEnabled) => {
|
||||
if (isEnabled) return element.click();
|
||||
})
|
||||
.then((isEnabled) => !isEnabled || element.click())
|
||||
)
|
||||
.end();
|
||||
},
|
||||
|
|
|
@ -47,7 +47,7 @@ var utils = {
|
|||
options.cluster.get('nodes').getByIds(ids),
|
||||
{fetchOptions: {cluster_id: options.cluster.id}}
|
||||
);
|
||||
if (nodes.length === ids.length) return nodes;
|
||||
return nodes.length === ids.length ? nodes : null;
|
||||
},
|
||||
renderMultilineText(text) {
|
||||
if (!text) return null;
|
||||
|
|
|
@ -219,16 +219,12 @@ var DashboardLinks = React.createClass({
|
|||
<div className='row'>
|
||||
<div className='dashboard-block links-block clearfix'>
|
||||
<div className='col-xs-12'>
|
||||
{links.map((link, index) => {
|
||||
if (index % 2 === 0) {
|
||||
return (
|
||||
<div className='row' key={link.url}>
|
||||
{this.renderLink(link)}
|
||||
{index + 1 < links.length && this.renderLink(links[index + 1])}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
})}
|
||||
{links.map((link, index) => index % 2 === 0 && (
|
||||
<div className='row' key={link.url}>
|
||||
{this.renderLink(link)}
|
||||
{index + 1 < links.length && this.renderLink(links[index + 1])}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -503,77 +499,71 @@ var ClusterActionsPanel = React.createClass({
|
|||
case 'deploy':
|
||||
return [
|
||||
// check for unprovisioned virt nodes
|
||||
function(cluster) {
|
||||
if (virtNodes.length) {
|
||||
return {
|
||||
blocker: [
|
||||
i18n(ns + 'unprovisioned_virt_nodes', {
|
||||
role: cluster.get('roles').find({name: 'virt'}).get('label'),
|
||||
count: virtNodes.length
|
||||
})
|
||||
]
|
||||
};
|
||||
}
|
||||
(cluster) => virtNodes.length && {
|
||||
blocker: [
|
||||
i18n(ns + 'unprovisioned_virt_nodes', {
|
||||
role: cluster.get('roles').find({name: 'virt'}).get('label'),
|
||||
count: virtNodes.length
|
||||
})
|
||||
]
|
||||
},
|
||||
// check for offline nodes
|
||||
function(cluster) {
|
||||
(cluster) => {
|
||||
var offlineNodes = cluster.get('nodes').filter({online: false});
|
||||
if (offlineNodes.length) {
|
||||
return {
|
||||
blocker: [i18n(ns + 'offline_nodes', {count: offlineNodes.length})]
|
||||
};
|
||||
}
|
||||
return offlineNodes.length && {
|
||||
blocker: [i18n(ns + 'offline_nodes', {count: offlineNodes.length})]
|
||||
};
|
||||
},
|
||||
// check if TLS settings are not configured
|
||||
function(cluster) {
|
||||
(cluster) => {
|
||||
var settings = cluster.get('settings');
|
||||
if (!settings.get('public_ssl')) return false;
|
||||
if (
|
||||
!settings.get('public_ssl.horizon.value') &&
|
||||
!settings.get('public_ssl.services.value')
|
||||
) {
|
||||
return {warning: [i18n(ns + 'tls_not_enabled')]};
|
||||
}
|
||||
if (!settings.get('public_ssl.horizon.value')) {
|
||||
return {warning: [i18n(ns + 'tls_for_horizon_not_enabled')]};
|
||||
}
|
||||
if (!settings.get('public_ssl.services.value')) {
|
||||
return {warning: [i18n(ns + 'tls_for_services_not_enabled')]};
|
||||
if (settings.get('public_ssl')) {
|
||||
if (
|
||||
!settings.get('public_ssl.horizon.value') &&
|
||||
!settings.get('public_ssl.services.value')
|
||||
) {
|
||||
return {warning: [i18n(ns + 'tls_not_enabled')]};
|
||||
}
|
||||
if (!settings.get('public_ssl.horizon.value')) {
|
||||
return {warning: [i18n(ns + 'tls_for_horizon_not_enabled')]};
|
||||
}
|
||||
if (!settings.get('public_ssl.services.value')) {
|
||||
return {warning: [i18n(ns + 'tls_for_services_not_enabled')]};
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
// check if deployment failed
|
||||
function(cluster) {
|
||||
return cluster.needsRedeployment() && {
|
||||
error: [
|
||||
<div
|
||||
key='unsuccessful_deploy'
|
||||
className='instruction'>
|
||||
{i18n(ns + 'unsuccessful_deploy')}
|
||||
</div>
|
||||
(cluster) => cluster.needsRedeployment() && {
|
||||
error: [
|
||||
<div
|
||||
key='unsuccessful_deploy'
|
||||
className='instruction'>
|
||||
{i18n(ns + 'unsuccessful_deploy')}
|
||||
</div>
|
||||
]
|
||||
},
|
||||
// check VCenter settings
|
||||
(cluster) => {
|
||||
if (!cluster.get('settings').get('common.use_vcenter.value')) return false;
|
||||
var vcenter = cluster.get('vcenter');
|
||||
vcenter.setModels(_.extend({
|
||||
current_vcenter: vcenter.get('availability_zones').at(0),
|
||||
glance: vcenter.get('glance')
|
||||
}, configModels));
|
||||
return !vcenter.isValid() && {
|
||||
blocker: [
|
||||
<span key='vcenter'>{i18n('vmware.has_errors') + ' '}
|
||||
<Link to={'/cluster/' + cluster.id + '/vmware'}>
|
||||
{i18n('vmware.tab_name')}
|
||||
</Link>
|
||||
</span>
|
||||
]
|
||||
};
|
||||
},
|
||||
// check VCenter settings
|
||||
function(cluster) {
|
||||
if (cluster.get('settings').get('common.use_vcenter.value')) {
|
||||
var vcenter = cluster.get('vcenter');
|
||||
vcenter.setModels(_.extend({
|
||||
current_vcenter: vcenter.get('availability_zones').at(0),
|
||||
glance: vcenter.get('glance')
|
||||
}, configModels));
|
||||
return !vcenter.isValid() && {
|
||||
blocker: [
|
||||
<span key='vcenter'>{i18n('vmware.has_errors') + ' '}
|
||||
<Link to={'/cluster/' + cluster.id + '/vmware'}>
|
||||
{i18n('vmware.tab_name')}
|
||||
</Link>
|
||||
</span>
|
||||
]
|
||||
};
|
||||
}
|
||||
},
|
||||
// check cluster settings
|
||||
function(cluster) {
|
||||
(cluster) => {
|
||||
var settings = cluster.get('settings');
|
||||
settings.isValid({models: configModels});
|
||||
if (_.isNull(settings.validationError)) return {};
|
||||
|
@ -592,27 +582,29 @@ var ClusterActionsPanel = React.createClass({
|
|||
return areOpenStackSettingsValid || areNetworkSettingsValid;
|
||||
});
|
||||
|
||||
return {blocker: [
|
||||
!areOpenStackSettingsValid &&
|
||||
<span key='invalid_settings'>
|
||||
{i18n(ns + 'invalid_settings')}
|
||||
{' ' + i18n(ns + 'get_more_info') + ' '}
|
||||
<Link to={'/cluster/' + cluster.id + '/settings'}>
|
||||
{i18n(ns + 'settings_link')}
|
||||
</Link>.
|
||||
</span>,
|
||||
!areNetworkSettingsValid &&
|
||||
<span key='invalid_network_settings'>
|
||||
{i18n(ns + 'invalid_network_settings')}
|
||||
{' ' + i18n(ns + 'get_more_info') + ' '}
|
||||
<Link to={'/cluster/' + cluster.id + '/network/network_settings'}>
|
||||
{i18n(ns + 'network_settings_link')}
|
||||
</Link>.
|
||||
</span>
|
||||
]};
|
||||
return {
|
||||
blocker: [
|
||||
!areOpenStackSettingsValid &&
|
||||
<span key='invalid_settings'>
|
||||
{i18n(ns + 'invalid_settings')}
|
||||
{' ' + i18n(ns + 'get_more_info') + ' '}
|
||||
<Link to={'/cluster/' + cluster.id + '/settings'}>
|
||||
{i18n(ns + 'settings_link')}
|
||||
</Link>.
|
||||
</span>,
|
||||
!areNetworkSettingsValid &&
|
||||
<span key='invalid_network_settings'>
|
||||
{i18n(ns + 'invalid_network_settings')}
|
||||
{' ' + i18n(ns + 'get_more_info') + ' '}
|
||||
<Link to={'/cluster/' + cluster.id + '/network/network_settings'}>
|
||||
{i18n(ns + 'network_settings_link')}
|
||||
</Link>.
|
||||
</span>
|
||||
]
|
||||
};
|
||||
},
|
||||
// check node amount restrictions according to their roles
|
||||
function(cluster) {
|
||||
(cluster) => {
|
||||
var roleModels = cluster.get('roles');
|
||||
var validRoleModels = roleModels.filter(
|
||||
(role) => !role.checkRestrictions(configModels).result
|
||||
|
@ -638,9 +630,9 @@ var ClusterActionsPanel = React.createClass({
|
|||
};
|
||||
},
|
||||
// check cluster network configuration
|
||||
function(cluster) {
|
||||
(cluster) => {
|
||||
// network verification is not supported in multi-rack environment
|
||||
if (cluster.get('nodeNetworkGroups').length > 1) return null;
|
||||
if (cluster.get('nodeNetworkGroups').length > 1) return false;
|
||||
|
||||
var task = cluster.task('verify_networks');
|
||||
var makeComponent = (text, isError) => {
|
||||
|
@ -665,6 +657,7 @@ var ClusterActionsPanel = React.createClass({
|
|||
if (task.match({active: true})) {
|
||||
return makeComponent(i18n(ns + 'verification_in_progress'));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
];
|
||||
default:
|
||||
|
|
|
@ -59,7 +59,7 @@ HistoryTab = React.createClass({
|
|||
},
|
||||
loadScreenData(transactionId) {
|
||||
transactionId = transactionId || this.props.activeTransactionId;
|
||||
if (_.isNull(transactionId)) return;
|
||||
if (_.isNull(transactionId)) return Promise.resolve();
|
||||
|
||||
return DeploymentHistoryScreen
|
||||
.fetchData(transactionId)
|
||||
|
|
|
@ -238,11 +238,9 @@ var LogFilterBar = React.createClass({
|
|||
this.setState(data);
|
||||
},
|
||||
getLocalSources() {
|
||||
return this.state.sources.map((source) => {
|
||||
if (!source.get('remote')) {
|
||||
return <option value={source.id} key={source.id}>{source.get('name')}</option>;
|
||||
}
|
||||
});
|
||||
return this.state.sources.map((source) => !source.get('remote') &&
|
||||
<option value={source.id} key={source.id}>{source.get('name')}</option>
|
||||
);
|
||||
},
|
||||
getRemoteSources() {
|
||||
var options = {};
|
||||
|
|
|
@ -1575,12 +1575,11 @@ var NetworkSettings = React.createClass({
|
|||
.map(
|
||||
(sectionName) => {
|
||||
var section = settings.get(sectionName);
|
||||
var settingsToDisplay = _.compact(_.map(section, (setting, settingName) => {
|
||||
if (
|
||||
(section.metadata.group || setting.group === 'network') &&
|
||||
settings.isSettingVisible(setting, settingName, this.props.configModels)
|
||||
) return settingName;
|
||||
}));
|
||||
var settingsToDisplay = _.compact(_.map(section, (setting, settingName) =>
|
||||
(section.metadata.group || setting.group === 'network') &&
|
||||
settings.isSettingVisible(setting, settingName, this.props.configModels) &&
|
||||
settingName
|
||||
));
|
||||
if (_.isEmpty(settingsToDisplay) && !settings.isPlugin(section)) return null;
|
||||
return <SettingSection
|
||||
{... _.pick(
|
||||
|
|
|
@ -45,14 +45,11 @@ var EditNodeDisksScreen = React.createClass({
|
|||
node.disks = new models.Disks();
|
||||
return node.disks.fetch({url: _.result(node, 'url') + '/disks'});
|
||||
}).concat(volumes.fetch()))
|
||||
.then(() => {
|
||||
var disks = new models.Disks(_.cloneDeep(nodes.at(0).disks.toJSON()), {parse: true});
|
||||
return {
|
||||
disks: disks,
|
||||
nodes: nodes,
|
||||
volumes: volumes
|
||||
};
|
||||
});
|
||||
.then(() => ({
|
||||
disks: new models.Disks(_.cloneDeep(nodes.at(0).disks.toJSON()), {parse: true}),
|
||||
nodes,
|
||||
volumes
|
||||
}));
|
||||
}
|
||||
},
|
||||
getInitialState() {
|
||||
|
|
|
@ -484,21 +484,24 @@ var EditNodeInterfacesScreen = React.createClass({
|
|||
},
|
||||
mergeLimitations(limitation1, limitation2) {
|
||||
return _.mergeWith(limitation1, limitation2, (value1, value2, interfaceProperty) => {
|
||||
var result;
|
||||
switch (interfaceProperty) {
|
||||
case 'mtu':
|
||||
case 'offloading_modes':
|
||||
// Offloading modes are presumed to be calculated intersection
|
||||
return {equal: true, shown: true};
|
||||
result = {equal: true, shown: true};
|
||||
break;
|
||||
case 'dpdk':
|
||||
if (_.isUndefined(value1) || _.isUndefined(value2)) break;
|
||||
|
||||
// Both interfaces should support DPDK in order bond to support it either
|
||||
var equal = true;
|
||||
var shown = value1.shown && value2.shown;
|
||||
return {equal: equal, shown: shown};
|
||||
if (!_.isUndefined(value1) && !_.isUndefined(value2)) {
|
||||
// Both interfaces should support DPDK in order bond to support it either
|
||||
result = {equal: true, shown: value1.shown && value2.shown};
|
||||
}
|
||||
break;
|
||||
case 'sriov':
|
||||
return {equal: true, shown: false};
|
||||
result = {equal: true, shown: false};
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
},
|
||||
unbondInterfaces() {
|
||||
|
@ -783,34 +786,32 @@ var EditNodeInterfacesScreen = React.createClass({
|
|||
var ifcName = ifc.get('name');
|
||||
var limitations = this.state.limitations[ifc.isBond() ? ifcName : ifc.id];
|
||||
|
||||
if (!_.includes(slaveInterfaceNames, ifcName)) {
|
||||
return (
|
||||
<NodeInterfaceDropTarget
|
||||
{... _.pick(this.props, 'cluster', 'nodes', 'interfaces', 'configModels')}
|
||||
key={'interface-' + ifcName}
|
||||
interface={ifc}
|
||||
limitations={limitations}
|
||||
nodesInterfaces={nodesInterfaces[index]}
|
||||
hasChanges={
|
||||
!_.isEqual(
|
||||
_.find(initialInterfaces, {name: ifcName}),
|
||||
_.omit(ifc.toJSON(), 'state')
|
||||
)
|
||||
}
|
||||
locked={locked}
|
||||
configurationTemplateExists={configurationTemplateExists}
|
||||
errors={interfacesErrors[ifcName]}
|
||||
validate={this.validate}
|
||||
removeInterfaceFromBond={this.removeInterfaceFromBond}
|
||||
bondingProperties={bondingConfig.properties}
|
||||
availableBondingTypes={availableBondingTypes[ifcName]}
|
||||
getAvailableBondingTypes={this.getAvailableBondingTypes}
|
||||
interfaceSpeeds={interfaceSpeeds[index]}
|
||||
interfaceNames={interfaceNames[index]}
|
||||
viewMode={viewMode}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return !_.includes(slaveInterfaceNames, ifcName) && (
|
||||
<NodeInterfaceDropTarget
|
||||
{... _.pick(this.props, 'cluster', 'nodes', 'interfaces', 'configModels')}
|
||||
key={'interface-' + ifcName}
|
||||
interface={ifc}
|
||||
limitations={limitations}
|
||||
nodesInterfaces={nodesInterfaces[index]}
|
||||
hasChanges={
|
||||
!_.isEqual(
|
||||
_.find(initialInterfaces, {name: ifcName}),
|
||||
_.omit(ifc.toJSON(), 'state')
|
||||
)
|
||||
}
|
||||
locked={locked}
|
||||
configurationTemplateExists={configurationTemplateExists}
|
||||
errors={interfacesErrors[ifcName]}
|
||||
validate={this.validate}
|
||||
removeInterfaceFromBond={this.removeInterfaceFromBond}
|
||||
bondingProperties={bondingConfig.properties}
|
||||
availableBondingTypes={availableBondingTypes[ifcName]}
|
||||
getAvailableBondingTypes={this.getAvailableBondingTypes}
|
||||
interfaceSpeeds={interfaceSpeeds[index]}
|
||||
interfaceNames={interfaceNames[index]}
|
||||
viewMode={viewMode}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className='col-xs-12 page-buttons content-elements'>
|
||||
|
@ -1383,7 +1384,7 @@ var NodeInterfaceAttributes = React.createClass({
|
|||
excerpt.push((added > 1 ? ',' : '') + mode.name + ' ' + states[mode.state]);
|
||||
}
|
||||
// show no more than two modes in the button
|
||||
if (added === 2) return false;
|
||||
return added <= 2;
|
||||
}
|
||||
);
|
||||
if (added < ifcModes.length) excerpt.push(', ...');
|
||||
|
@ -1439,58 +1440,60 @@ var NodeInterfaceAttributes = React.createClass({
|
|||
</button>
|
||||
</span>
|
||||
{_.map(ifcProperties, (propertyValue, propertyName) => {
|
||||
var {equal, shown} = _.get(
|
||||
limitations, propertyName,
|
||||
{equal: true, shown: true}
|
||||
);
|
||||
var {equal, shown} = _.get(limitations, propertyName, {equal: true, shown: true});
|
||||
var propertyShown = (!equal && isMassConfiguration && !isBond) || (equal && shown);
|
||||
|
||||
if (_.isPlainObject(propertyValue) && !propertyShown) return null;
|
||||
if (
|
||||
_.isPlainObject(propertyValue) && !propertyShown ||
|
||||
!_.includes(renderableIfcProperties, propertyName)
|
||||
) return null;
|
||||
|
||||
if (_.includes(renderableIfcProperties, propertyName)) {
|
||||
var classes = {
|
||||
'text-danger': _.has(errors, propertyName),
|
||||
'property-item-container': true,
|
||||
[propertyName]: true,
|
||||
active: !collapsed && activeInterfaceSectionName === propertyName,
|
||||
forbidden: !equal
|
||||
};
|
||||
var commonButtonProps = {
|
||||
className: 'btn btn-link property-item',
|
||||
onClick: () => this.switchActiveSubtab(propertyName)
|
||||
};
|
||||
//@TODO (morale): create some common component out of this
|
||||
switch (propertyName) {
|
||||
case 'sriov':
|
||||
case 'dpdk':
|
||||
return (
|
||||
<span key={propertyName} className={utils.classNames(classes)}>
|
||||
{!equal && this.renderLockTooltip(propertyName)}
|
||||
{i18n(ns + propertyName) + ':'}
|
||||
<button {...commonButtonProps} disabled={!equal}>
|
||||
{equal ?
|
||||
propertyValue.enabled ?
|
||||
i18n('common.enabled')
|
||||
:
|
||||
i18n('common.disabled')
|
||||
:
|
||||
i18n(ns + 'different_availability')
|
||||
}
|
||||
</button>
|
||||
</span>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<span key={propertyName} className={utils.classNames(classes)}>
|
||||
{!equal && this.renderLockTooltip(propertyName)}
|
||||
{i18n(ns + propertyName) + ':'}
|
||||
<button {...commonButtonProps} disabled={!equal}>
|
||||
{propertyValue || i18n(ns + propertyName + '_placeholder')}
|
||||
</button>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
var result;
|
||||
var classes = {
|
||||
'text-danger': _.has(errors, propertyName),
|
||||
'property-item-container': true,
|
||||
[propertyName]: true,
|
||||
active: !collapsed && activeInterfaceSectionName === propertyName,
|
||||
forbidden: !equal
|
||||
};
|
||||
var commonButtonProps = {
|
||||
className: 'btn btn-link property-item',
|
||||
onClick: () => this.switchActiveSubtab(propertyName)
|
||||
};
|
||||
//@TODO (morale): create some common component out of this
|
||||
switch (propertyName) {
|
||||
case 'sriov':
|
||||
case 'dpdk':
|
||||
result = (
|
||||
<span key={propertyName} className={utils.classNames(classes)}>
|
||||
{!equal && this.renderLockTooltip(propertyName)}
|
||||
{i18n(ns + propertyName) + ':'}
|
||||
<button {...commonButtonProps} disabled={!equal}>
|
||||
{equal ?
|
||||
propertyValue.enabled ?
|
||||
i18n('common.enabled')
|
||||
:
|
||||
i18n('common.disabled')
|
||||
:
|
||||
i18n(ns + 'different_availability')
|
||||
}
|
||||
</button>
|
||||
</span>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
result = (
|
||||
<span key={propertyName} className={utils.classNames(classes)}>
|
||||
{!equal && this.renderLockTooltip(propertyName)}
|
||||
{i18n(ns + propertyName) + ':'}
|
||||
<button {...commonButtonProps} disabled={!equal}>
|
||||
{propertyValue || i18n(ns + propertyName + '_placeholder')}
|
||||
</button>
|
||||
</span>
|
||||
);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
@ -1540,6 +1543,8 @@ var NodeInterfaceAttributes = React.createClass({
|
|||
return this.renderSRIOV(errors);
|
||||
case 'dpdk':
|
||||
return this.renderDPDK(errors);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
renderSRIOV(errors) {
|
||||
|
|
|
@ -1929,11 +1929,9 @@ NodeList = React.createClass({
|
|||
var groups = _.toPairs(_.groupBy(this.props.nodes, groupingMethod));
|
||||
|
||||
// sort nodes in a group by name, mac or ip or by id (default)
|
||||
var formattedSorters = _.compact(_.map(this.props.activeSorters, (sorter) => {
|
||||
if (_.includes(uniqValueSorters, sorter.name)) {
|
||||
return {attr: sorter.name, desc: sorter.order === 'desc'};
|
||||
}
|
||||
}));
|
||||
var formattedSorters = _.compact(_.map(this.props.activeSorters, ({name, order}) =>
|
||||
_.includes(uniqValueSorters, name) && {attr: name, desc: order === 'desc'}
|
||||
));
|
||||
_.each(groups, (group) => {
|
||||
group[1].sort((node1, node2) => utils.multiSort(
|
||||
node1, node2,
|
||||
|
|
|
@ -90,27 +90,23 @@ var SettingSection = React.createClass({
|
|||
return result;
|
||||
},
|
||||
checkDependentRoles(sectionName, settingName) {
|
||||
if (!this.props.allocatedRoles || !this.props.allocatedRoles.length) return [];
|
||||
var {settings, allocatedRoles, cluster, configModels, getValueAttribute} = this.props;
|
||||
if (!_.size(allocatedRoles)) return [];
|
||||
var path = utils.makePath(sectionName, settingName);
|
||||
var setting = this.props.settings.get(path);
|
||||
var setting = settings.get(path);
|
||||
if (!this.areCalculationsPossible(setting)) return [];
|
||||
var valueAttribute = this.props.getValueAttribute(settingName);
|
||||
var valueAttribute = getValueAttribute(settingName);
|
||||
var valuesToCheck = this.getValuesToCheck(setting, valueAttribute);
|
||||
var pathToCheck = utils.makePath(path, valueAttribute);
|
||||
var roles = this.props.cluster.get('roles');
|
||||
return _.compact(this.props.allocatedRoles.map((roleName) => {
|
||||
var roles = cluster.get('roles');
|
||||
return _.compact(allocatedRoles.map((roleName) => {
|
||||
var role = roles.find({name: roleName});
|
||||
if (_.some(role.get('restrictions'), (restriction) => {
|
||||
return _.some(role.get('restrictions'), (restriction) => {
|
||||
restriction = utils.expandRestriction(restriction);
|
||||
if (_.includes(restriction.condition, 'settings:' + path) &&
|
||||
!(new Expression(
|
||||
restriction.condition,
|
||||
this.props.configModels,
|
||||
restriction
|
||||
).evaluate())) {
|
||||
return this.checkValues(valuesToCheck, pathToCheck, setting[valueAttribute], restriction);
|
||||
}
|
||||
})) return role.get('label');
|
||||
return _.includes(restriction.condition, 'settings:' + path) &&
|
||||
!(new Expression(restriction.condition, configModels, restriction).evaluate()) &&
|
||||
this.checkValues(valuesToCheck, pathToCheck, setting[valueAttribute], restriction);
|
||||
}) && role.get('label');
|
||||
}));
|
||||
},
|
||||
checkDependentSettings(sectionName, settingName) {
|
||||
|
@ -157,9 +153,9 @@ var SettingSection = React.createClass({
|
|||
this.checkValues,
|
||||
valuesToCheck, pathToCheck, currentSetting[valueAttribute]
|
||||
);
|
||||
return _.compact(_.map(dependentRestrictions, (restrictions, label) => {
|
||||
if (_.some(restrictions, checkValues)) return label;
|
||||
}));
|
||||
return _.compact(_.map(dependentRestrictions,
|
||||
(restrictions, label) => _.some(restrictions, checkValues) && label
|
||||
));
|
||||
}
|
||||
return [];
|
||||
},
|
||||
|
@ -215,12 +211,11 @@ var SettingSection = React.createClass({
|
|||
var values = _.chain(_.cloneDeep(setting.values))
|
||||
.map((value) => {
|
||||
var processedValueRestrictions = this.props.checkRestrictions('disable', value);
|
||||
if (!this.props.checkRestrictions('hide', value).result) {
|
||||
value.disabled = isSettingDisabled || processedValueRestrictions.result;
|
||||
value.checked = value.data === setting.value;
|
||||
value.tooltipText = showSettingWarning && processedValueRestrictions.message;
|
||||
return value;
|
||||
}
|
||||
if (this.props.checkRestrictions('hide', value).result) return null;
|
||||
value.disabled = isSettingDisabled || processedValueRestrictions.result;
|
||||
value.checked = value.data === setting.value;
|
||||
value.tooltipText = showSettingWarning && processedValueRestrictions.message;
|
||||
return value;
|
||||
})
|
||||
.compact()
|
||||
.value();
|
||||
|
|
|
@ -264,15 +264,14 @@ var SettingsTab = React.createClass({
|
|||
|
||||
_.each(settingGroups, (settingGroup) => {
|
||||
var calculatedGroup = settings.sanitizeGroup(settingGroup);
|
||||
var pickedSettings = _.compact(_.map(section, (setting, settingName) => {
|
||||
if (
|
||||
settings.isSettingVisible(setting, settingName, this.state.configModels) &&
|
||||
settings.sanitizeGroup(setting.group) === calculatedGroup
|
||||
) return settingName;
|
||||
}));
|
||||
var hasErrors = _.some(pickedSettings, (settingName) => {
|
||||
return (settings.validationError || {})[utils.makePath(sectionName, settingName)];
|
||||
});
|
||||
var pickedSettings = _.compact(_.map(section, (setting, settingName) =>
|
||||
settings.isSettingVisible(setting, settingName, this.state.configModels) &&
|
||||
settings.sanitizeGroup(setting.group) === calculatedGroup &&
|
||||
settingName
|
||||
));
|
||||
var hasErrors = _.some(pickedSettings, (settingName) =>
|
||||
(settings.validationError || {})[utils.makePath(sectionName, settingName)]
|
||||
);
|
||||
if (!_.isEmpty(pickedSettings)) {
|
||||
groupedSettings[calculatedGroup][sectionName] = {
|
||||
settings: pickedSettings,
|
||||
|
@ -308,11 +307,10 @@ var SettingsTab = React.createClass({
|
|||
<div className={'col-xs-10 forms-box ' + groupName} key={groupName}>
|
||||
{_.map(sortedSections, (sectionName) => {
|
||||
var settingsToDisplay = selectedGroup[sectionName].settings ||
|
||||
_.compact(_.map(settings.get(sectionName), (setting, settingName) => {
|
||||
if (settings.isSettingVisible(setting, settingName, this.state.configModels)) {
|
||||
return settingName;
|
||||
}
|
||||
}));
|
||||
_.compact(_.map(settings.get(sectionName), (setting, settingName) =>
|
||||
settings.isSettingVisible(setting, settingName, this.state.configModels) &&
|
||||
settingName
|
||||
));
|
||||
return <SettingSection
|
||||
{... _.pick(this.state, 'initialAttributes', 'settingsForChecks', 'configModels')}
|
||||
key={sectionName}
|
||||
|
|
|
@ -125,12 +125,10 @@ export var Input = React.createClass({
|
|||
},
|
||||
onChange() {
|
||||
var {onChange, name, type} = this.props;
|
||||
if (onChange) {
|
||||
var input = this.getInputDOMNode();
|
||||
var value = type === 'checkbox' ? input.checked : input.value;
|
||||
if (type === 'number') value = parseInt(value, 10);
|
||||
return onChange(name, value);
|
||||
}
|
||||
var input = this.getInputDOMNode();
|
||||
var value = type === 'checkbox' ? input.checked : input.value;
|
||||
if (type === 'number') value = parseInt(value, 10);
|
||||
return onChange(name, value);
|
||||
},
|
||||
handleFocus(e) {
|
||||
e.target.select();
|
||||
|
@ -191,10 +189,10 @@ export var Input = React.createClass({
|
|||
className: utils.classNames({
|
||||
'form-control': type !== 'range',
|
||||
[inputClassName]: inputClassName
|
||||
}),
|
||||
onChange: debounce ? this.debouncedChange : this.onChange
|
||||
})
|
||||
}
|
||||
);
|
||||
if (this.props.onChange) props.onChange = debounce ? this.debouncedChange : this.onChange;
|
||||
|
||||
if (_.has(props, 'value')) {
|
||||
props.value = _.isNull(value) || _.isUndefined(value) ? '' : value;
|
||||
|
|
|
@ -261,7 +261,7 @@ customControls.text_list = customControls.textarea_list = React.createClass({
|
|||
value[index] = input.value;
|
||||
break;
|
||||
}
|
||||
if (this.props.onChange) return this.props.onChange(this.props.name, value);
|
||||
if (this.props.onChange) this.props.onChange(this.props.name, value);
|
||||
},
|
||||
debouncedFieldChange: _.debounce(function(index) {
|
||||
return this.changeField(index);
|
||||
|
|
|
@ -391,33 +391,33 @@ export var DiscardClusterChangesDialog = React.createClass({
|
|||
);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
var nodes = new models.Nodes(this.props.nodes.map((node) => {
|
||||
if (node.get('pending_deletion')) {
|
||||
return {
|
||||
id: node.id,
|
||||
pending_deletion: false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var nodes = new models.Nodes(this.props.nodes.map((node) => {
|
||||
if (node.get('pending_deletion')) {
|
||||
return {
|
||||
id: node.id,
|
||||
cluster_id: null,
|
||||
pending_addition: false,
|
||||
pending_roles: []
|
||||
pending_deletion: false
|
||||
};
|
||||
}));
|
||||
Backbone.sync('update', nodes)
|
||||
.then(() => cluster.get('nodes').fetch())
|
||||
.then(
|
||||
() => {
|
||||
dispatcher
|
||||
.trigger('updateNodeStats networkConfigurationUpdated labelsConfigurationUpdated');
|
||||
this.resolveResult();
|
||||
this.close();
|
||||
},
|
||||
(response) => this.showError(response, i18n(ns + 'cant_discard'))
|
||||
);
|
||||
}
|
||||
}
|
||||
return {
|
||||
id: node.id,
|
||||
cluster_id: null,
|
||||
pending_addition: false,
|
||||
pending_roles: []
|
||||
};
|
||||
}));
|
||||
return Backbone.sync('update', nodes)
|
||||
.then(() => cluster.get('nodes').fetch())
|
||||
.then(
|
||||
() => {
|
||||
dispatcher
|
||||
.trigger('updateNodeStats networkConfigurationUpdated labelsConfigurationUpdated');
|
||||
this.resolveResult();
|
||||
this.close();
|
||||
},
|
||||
(response) => this.showError(response, i18n(ns + 'cant_discard'))
|
||||
);
|
||||
},
|
||||
renderBody() {
|
||||
var {nodes, changeName, ns} = this.props;
|
||||
|
@ -1319,9 +1319,11 @@ export var ShowNodeInfoDialog = React.createClass({
|
|||
}),
|
||||
default: () => ''
|
||||
};
|
||||
var summary;
|
||||
try {
|
||||
return (summaryFormatters[group] || summaryFormatters.default)();
|
||||
summary = (summaryFormatters[group] || summaryFormatters.default)();
|
||||
} catch (ignore) {}
|
||||
return summary;
|
||||
},
|
||||
showPropertyName(propertyName) {
|
||||
return String(propertyName).replace(/_/g, ' ');
|
||||
|
@ -1639,11 +1641,9 @@ export var ShowNodeInfoDialog = React.createClass({
|
|||
(sectionName) => {
|
||||
var metadata = nodeAttributes.get(utils.makePath(sectionName, 'metadata'));
|
||||
var settingsToDisplay = _.compact(_.map(nodeAttributes.attributes[sectionName],
|
||||
(setting, settingName) => {
|
||||
if (nodeAttributes.isSettingVisible(setting, settingName, configModels)) {
|
||||
return settingName;
|
||||
}
|
||||
}));
|
||||
(setting, settingName) =>
|
||||
nodeAttributes.isSettingVisible(setting, settingName, configModels) && settingName
|
||||
));
|
||||
return (
|
||||
<SettingSection
|
||||
{... {sectionName, settingsToDisplay, cluster, configModels}}
|
||||
|
@ -1766,17 +1766,13 @@ export var ShowNodeInfoDialog = React.createClass({
|
|||
return (
|
||||
<div className='nested-object' key={'entry_' + groupIndex + entryIndex}>
|
||||
{_.map(utils.sortEntryProperties(entry, sortOrder[group]),
|
||||
(propertyName) => {
|
||||
if (
|
||||
!_.isPlainObject(entry[propertyName]) &&
|
||||
!_.isArray(entry[propertyName])
|
||||
) {
|
||||
return this.renderNodeInfo(
|
||||
propertyName,
|
||||
this.showPropertyValue(group, propertyName, entry[propertyName])
|
||||
);
|
||||
}
|
||||
}
|
||||
(propertyName) =>
|
||||
!_.isPlainObject(entry[propertyName]) &&
|
||||
!_.isArray(entry[propertyName]) &&
|
||||
this.renderNodeInfo(
|
||||
propertyName,
|
||||
this.showPropertyValue(group, propertyName, entry[propertyName])
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -1785,18 +1781,15 @@ export var ShowNodeInfoDialog = React.createClass({
|
|||
}
|
||||
{_.isPlainObject(groupEntries) &&
|
||||
<div>
|
||||
{_.map(groupEntries, (propertyValue, propertyName) => {
|
||||
if (
|
||||
!_.isPlainObject(propertyValue) &&
|
||||
!_.isArray(propertyValue) &&
|
||||
!_.isNumber(propertyName)
|
||||
) {
|
||||
return this.renderNodeInfo(
|
||||
propertyName,
|
||||
this.showPropertyValue(group, propertyName, propertyValue)
|
||||
);
|
||||
}
|
||||
})}
|
||||
{_.map(groupEntries, (propertyValue, propertyName) =>
|
||||
!_.isPlainObject(propertyValue) &&
|
||||
!_.isArray(propertyValue) &&
|
||||
!_.isNumber(propertyName) &&
|
||||
this.renderNodeInfo(
|
||||
propertyName,
|
||||
this.showPropertyValue(group, propertyName, propertyValue)
|
||||
)
|
||||
)}
|
||||
{!_.isEmpty(subEntries) &&
|
||||
<div>
|
||||
{_.map(subEntries, (subentry, subentrysIndex) => {
|
||||
|
@ -2183,7 +2176,7 @@ export var ChangePasswordDialog = React.createClass({
|
|||
}
|
||||
if (e.key === ' ') {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
},
|
||||
handleChange(clearError, name, value) {
|
||||
|
|
|
@ -113,16 +113,14 @@ var PluginsPage = React.createClass({
|
|||
</div>
|
||||
{_.map(this.props.details, (attribute) => {
|
||||
var data = this.processPluginData(plugin, attribute);
|
||||
if (data.length) {
|
||||
return (
|
||||
<div className='row' key={attribute}>
|
||||
<div className='col-xs-2 detail-title text-right'>
|
||||
{i18n('plugins_page.' + attribute)}:
|
||||
</div>
|
||||
<div className='col-xs-10'>{data}</div>
|
||||
return !!data.length && (
|
||||
<div className='row' key={attribute}>
|
||||
<div className='col-xs-2 detail-title text-right'>
|
||||
{i18n('plugins_page.' + attribute)}:
|
||||
</div>
|
||||
);
|
||||
}
|
||||
<div className='col-xs-10'>{data}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue