Fix sorting of settings

_.sortBy works improperly when returning array as a sorter.
Numbers are sorted as strings in this case.

Closes-Bug: #1644461

Change-Id: I7642ae2af6b847bd7c3217700f6866c2aef307c9
This commit is contained in:
Julia Aranovich 2016-12-05 11:38:03 +03:00
parent fcf4afcc39
commit 6c1c688e37
6 changed files with 84 additions and 69 deletions

View File

@ -951,6 +951,10 @@ models.Settings = BaseModel
}
});
this.isValid({models});
},
sortAttributes({weight: weight1, label: label1}, {weight: weight2, label: label2}) {
if (weight1 !== weight2) return weight1 - weight2;
return utils.natsort(label1, label2);
}
});

View File

@ -1569,47 +1569,49 @@ var NetworkSettings = React.createClass({
return (
<div className='forms-box network'>
{
_.chain(settings.attributes)
.keys()
.filter(
(sectionName) => {
var section = settings.get(sectionName);
return (section.metadata.group === 'network' ||
_.some(section, {group: 'network'})) &&
!this.checkRestrictions('hide', section.metadata).result;
}
_.chain(
_.keys(settings.attributes).sort(
(sectionName1, sectionName2) => settings.sortAttributes(
settings.get(sectionName1 + '.metadata'),
settings.get(sectionName2 + '.metadata')
)
)
.sortBy((sectionName) => {
var {weight, label} = settings.get(sectionName + '.metadata');
return [weight, label];
})
.map(
(sectionName) => {
var section = settings.get(sectionName);
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(
this.props,
'cluster', 'initialAttributes', 'settingsForChecks', 'configModels'
)}
key={sectionName}
sectionName={sectionName}
settingsToDisplay={settingsToDisplay}
onChange={_.partial(this.onChange, sectionName)}
allocatedRoles={allocatedRoles}
settings={settings}
getValueAttribute={settings.getValueAttribute}
locked={locked}
checkRestrictions={this.checkRestrictions}
/>;
}
)
.value()
)
.filter(
(sectionName) => {
var section = settings.get(sectionName);
return (section.metadata.group === 'network' ||
_.some(section, {group: 'network'})) &&
!this.checkRestrictions('hide', section.metadata).result;
}
)
.map(
(sectionName) => {
var section = settings.get(sectionName);
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(
this.props,
'cluster', 'initialAttributes', 'settingsForChecks', 'configModels'
)}
key={sectionName}
sectionName={sectionName}
settingsToDisplay={settingsToDisplay}
onChange={_.partial(this.onChange, sectionName)}
allocatedRoles={allocatedRoles}
settings={settings}
getValueAttribute={settings.getValueAttribute}
locked={locked}
checkRestrictions={this.checkRestrictions}
/>;
}
)
.value()
}
</div>
);

View File

@ -1206,11 +1206,13 @@ var NodeInterface = React.createClass({
attributes.get(utils.makePath(sectionName, 'metadata'))
).result
)
.sortBy((sectionName) => {
var {weight, label} = attributes.get(sectionName + '.metadata');
return [weight, label];
})
.value();
.value()
.sort(
(sectionName1, sectionName2) => attributes.sortAttributes(
attributes.get(sectionName1 + '.metadata'),
attributes.get(sectionName2 + '.metadata')
)
);
var bondingPossible = !!availableBondingTypes.length && !configurationTemplateExists && !locked;
var networkErrors = (_.flatten((errors || {}).networks || [])).join(', ');
@ -1565,19 +1567,19 @@ var NodeInterfaceAttributes = React.createClass({
// the following code provides the following suggestion:
// first setting in NIC's attribute section should be a checkbox
// that reflects enableness of the section on the particular NIC
var name = _.chain(_.keys(attributes.get(sectionName)))
.sortBy((settingName) => {
var {weight, label} = attributes.get(utils.makePath(sectionName, settingName));
return [weight, label];
})
.find(
(settingName) => attributes.isSettingVisible(
attributes.get(utils.makePath(sectionName, settingName)),
settingName,
configModels
var name = _.find(
_.keys(attributes.get(sectionName)).sort(
(settingName1, settingName2) => attributes.sortAttributes(
attributes.get(utils.makePath(sectionName, settingName1)),
attributes.get(utils.makePath(sectionName, settingName2))
)
),
(settingName) => attributes.isSettingVisible(
attributes.get(utils.makePath(sectionName, settingName)),
settingName,
configModels
)
.value();
);
var value = attributes.get(utils.makePath(sectionName, name, 'value'));
if (_.isBoolean(value)) {

View File

@ -269,10 +269,12 @@ var SettingSection = React.createClass({
var isPluginWithLegacyTasksLocked = isPlugin && metadata.contains_legacy_tasks &&
!settings.get('common.propagate_task_deploy.value');
var sortedSettings = _.sortBy(settingsToDisplay, (settingName) => {
var {weight, label} = section[settingName];
return [weight, label];
});
var sortedSettings = settingsToDisplay.sort(
(settingName1, settingName2) => settings.sortAttributes(
section[settingName1],
section[settingName2]
)
);
var processedGroupRestrictions = this.processRestrictions(metadata);
var processedGroupDependencies = this.checkDependencies(sectionName, 'metadata');
var isGroupDisabled = locked ||

View File

@ -304,10 +304,12 @@ var SettingsTab = React.createClass({
{_.map(groupedSettings, (selectedGroup, groupName) => {
if (groupName !== activeSettingsSectionName) return null;
var sortedSections = _.sortBy(_.keys(selectedGroup), (sectionName) => {
var {weight, label} = settings.get(sectionName + '.metadata');
return [weight, label];
});
var sortedSections = _.keys(selectedGroup).sort(
(sectionName1, sectionName2) => settings.sortAttributes(
settings.get(sectionName1 + '.metadata'),
settings.get(sectionName2 + '.metadata')
)
);
return (
<div className={'col-xs-10 forms-box ' + groupName} key={groupName}>
{_.map(sortedSections, (sectionName) => {

View File

@ -1678,7 +1678,14 @@ export var ShowNodeInfoDialog = React.createClass({
var isLocked = !node.get('pending_addition') || actionInProgress;
var attributes = _.chain(_.keys(nodeAttributes.attributes))
var attributes = _.chain(
_.keys(nodeAttributes.attributes).sort(
(sectionName1, sectionName2) => nodeAttributes.sortAttributes(
nodeAttributes.get(sectionName1 + '.metadata'),
nodeAttributes.get(sectionName2 + '.metadata')
)
)
)
.filter(
(sectionName) => !nodeAttributes.checkRestrictions(
configModels,
@ -1686,10 +1693,6 @@ export var ShowNodeInfoDialog = React.createClass({
nodeAttributes.get(sectionName).metadata
).result
)
.sortBy((sectionName) => {
var {weight, label} = nodeAttributes.get(sectionName + '.metadata');
return [weight, label];
})
.map(
(sectionName) => {
var metadata = nodeAttributes.get(utils.makePath(sectionName, 'metadata'));