Merge "Improvements for the ClusterActionsPanel component"
This commit is contained in:
commit
385fea48f1
@ -4478,6 +4478,7 @@ input[type=range] {
|
||||
margin-bottom: @dashboard-offset;
|
||||
}
|
||||
.task-alerts {
|
||||
padding: 0;
|
||||
.invalid {
|
||||
.font-semibold;
|
||||
font-size: @base-font-size - 1;
|
||||
@ -4513,15 +4514,31 @@ input[type=range] {
|
||||
}
|
||||
}
|
||||
&.actions-panel {
|
||||
.no-nodes {
|
||||
color: @gray;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
.action-description {
|
||||
padding-right: 0;
|
||||
p:last-child {
|
||||
padding-bottom: @dashboard-offset;
|
||||
}
|
||||
}
|
||||
.nav {
|
||||
.dropdown {
|
||||
margin-right: 0;
|
||||
li.deployment-modes-label {
|
||||
text-align: right;
|
||||
.deployment-modes-label {
|
||||
color: @gray;
|
||||
padding: 7px 0 0;
|
||||
cursor: default;
|
||||
margin-right: @dashboard-offset;
|
||||
}
|
||||
.dropdown-toggle {
|
||||
padding: 0;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
||||
.dropdown-menu {
|
||||
right: 0;
|
||||
left: auto;
|
||||
min-width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,8 +121,8 @@ define([
|
||||
1000,
|
||||
'Provision VMs action appears on the Dashboard'
|
||||
)
|
||||
.clickByCssSelector('.actions-panel .nav button.dropdown-toggle')
|
||||
.clickByCssSelector('.actions-panel .nav .dropdown-menu li.deploy button')
|
||||
.clickByCssSelector('.actions-panel .dropdown button.dropdown-toggle')
|
||||
.clickByCssSelector('.actions-panel .dropdown .dropdown-menu li.deploy button')
|
||||
.then(function() {
|
||||
return dashboardPage.discardChanges();
|
||||
});
|
||||
@ -262,8 +262,8 @@ define([
|
||||
total,
|
||||
'The number of Pending Addition nodes in statistics is correct'
|
||||
)
|
||||
.clickByCssSelector('.actions-panel .nav button.dropdown-toggle')
|
||||
.clickByCssSelector('.actions-panel .nav .dropdown-menu li.deploy button')
|
||||
.clickByCssSelector('.actions-panel .dropdown button.dropdown-toggle')
|
||||
.clickByCssSelector('.actions-panel .dropdown .dropdown-menu li.deploy button')
|
||||
.then(function() {
|
||||
return dashboardPage.discardChanges();
|
||||
});
|
||||
|
@ -71,8 +71,8 @@ define([
|
||||
'Provision nodes': function() {
|
||||
this.timeout = 100000;
|
||||
return this.remote
|
||||
.clickByCssSelector('.actions-panel .nav button.dropdown-toggle')
|
||||
.clickByCssSelector('.actions-panel .nav .dropdown-menu li.provision button')
|
||||
.clickByCssSelector('.actions-panel .dropdown button.dropdown-toggle')
|
||||
.clickByCssSelector('.actions-panel .dropdown .dropdown-menu li.provision button')
|
||||
.assertElementContainsText(
|
||||
'.btn-provision',
|
||||
'Provision 1 Node',
|
||||
@ -123,8 +123,8 @@ define([
|
||||
.then(function() {
|
||||
return clusterPage.goToTab('Dashboard');
|
||||
})
|
||||
.clickByCssSelector('.actions-panel .nav button.dropdown-toggle')
|
||||
.clickByCssSelector('.actions-panel .nav .dropdown-menu li.provision button')
|
||||
.clickByCssSelector('.actions-panel .dropdown button.dropdown-toggle')
|
||||
.clickByCssSelector('.actions-panel .dropdown .dropdown-menu li.provision button')
|
||||
.clickByCssSelector('.changes-list .dropdown-toggle')
|
||||
.clickByCssSelector('.changes-list .btn-select-nodes')
|
||||
.then(function() {
|
||||
@ -205,11 +205,11 @@ define([
|
||||
'Deploy nodes': function() {
|
||||
this.timeout = 100000;
|
||||
return this.remote
|
||||
.clickByCssSelector('.actions-panel .nav button.dropdown-toggle')
|
||||
.clickByCssSelector('.actions-panel .nav .dropdown-menu li.deployment button')
|
||||
.clickByCssSelector('.actions-panel .dropdown button.dropdown-toggle')
|
||||
.clickByCssSelector('.actions-panel .dropdown .dropdown-menu li.deployment button')
|
||||
.assertElementDisabled('.btn-deploy-nodes', 'There are no provisioned nodes to deploy')
|
||||
.clickByCssSelector('.actions-panel .nav button.dropdown-toggle')
|
||||
.clickByCssSelector('.actions-panel .nav .dropdown-menu li.provision button')
|
||||
.clickByCssSelector('.actions-panel .dropdown button.dropdown-toggle')
|
||||
.clickByCssSelector('.actions-panel .dropdown .dropdown-menu li.provision button')
|
||||
.clickByCssSelector('.btn-provision')
|
||||
.then(function() {
|
||||
return modal.waitToOpen();
|
||||
@ -222,8 +222,8 @@ define([
|
||||
})
|
||||
.assertElementAppears('div.deploy-process div.progress', 2000, 'Provisioning started')
|
||||
.assertElementDisappears('div.deploy-process div.progress', 5000, 'Provisioning finished')
|
||||
.clickByCssSelector('.actions-panel .nav button.dropdown-toggle')
|
||||
.clickByCssSelector('.actions-panel .nav .dropdown-menu li.deployment button')
|
||||
.clickByCssSelector('.actions-panel .dropdown button.dropdown-toggle')
|
||||
.clickByCssSelector('.actions-panel .dropdown .dropdown-menu li.deployment button')
|
||||
.assertElementContainsText('.btn-deploy-nodes', 'Deploy 1 Node', '1 node to be deployed')
|
||||
.clickByCssSelector('.btn-deploy-nodes')
|
||||
.then(function() {
|
||||
|
@ -627,8 +627,6 @@
|
||||
"new_environment_welcome": "Welcome to the New OpenStack Environment!",
|
||||
"add_nodes": "Add nodes to the OpenStack Environment.",
|
||||
"deployment_of_environment_cannot_be_started": "Deployment cannot be started due to invalid environment configuration. Please review and address the warnings below before proceeding and see the",
|
||||
"provisioning_cannot_be_started": "Provisioning of nodes cannot be started due to invalid environment configuration. Please review and address the warnings below before proceeding",
|
||||
"deployment_of_nodes_cannot_be_started": "Deployment of nodes cannot be started due to invalid environment configuration. Please review and address the warnings below before proceeding",
|
||||
"stop": "Stop",
|
||||
"healthcheck": "To view the OpenStack health check status go to ",
|
||||
"healthcheck_tab": "Healthcheck tab",
|
||||
@ -666,22 +664,22 @@
|
||||
"tls_not_enabled": "TLS is not enabled. It is highly recommended to enable and configure TLS.",
|
||||
"tls_for_horizon_not_enabled": "TLS is not enabled for Horizon public endpoint. It is highly recommended to enable and configure TLS for Horizon.",
|
||||
"tls_for_services_not_enabled": "TLS is not enabled for OpenStack public endpoints. It is highly recommended to enable and configure TLS.",
|
||||
"offline_nodes": "__count__ node is offline.",
|
||||
"offline_nodes_plural": "__count__ nodes are offline.",
|
||||
"offline_nodes": "__count__ node is offline",
|
||||
"offline_nodes_plural": "__count__ nodes are offline",
|
||||
"unprovisioned_virt_nodes": "1 __role__ node is not provisioned.",
|
||||
"unprovisioned_virt_nodes_plural": "Some __role__ nodes are not provisioned.",
|
||||
"deployment_mode": "Deployment Mode",
|
||||
"actions": {
|
||||
"deploy": {
|
||||
"title": "Regular deployment",
|
||||
"title": "Provisioning + Deployment",
|
||||
"button_title_all_nodes": "Deploy Changes"
|
||||
},
|
||||
"provision": {
|
||||
"title": "Advanced provisioning",
|
||||
"description": "Provisioning installs an operating system on nodes.",
|
||||
"title": "Provisioning only",
|
||||
"description": "\"Provisioning only\" installs the previously selected operating system __os__ on the nodes, but does not deploy OpenStack services.\nTo deploy OpenStack services after provisioning has been completed, select \"Deployment only\" from the Deployment Mode dropdown. To complete provisioning and deployment at the same time, select \"Provisioning + Deployment\" from the Deployment Mode dropdown.",
|
||||
"nodes_to_provision": "__count__ node is discovered",
|
||||
"nodes_to_provision_plural": "__count__ nodes are discovered",
|
||||
"no_nodes_to_provision": "No online discovered nodes to provision.",
|
||||
"no_nodes": "Nodes must be assigned a role in order to be provisioned. Please use the \"Add Nodes\" button to add roles to available discovered nodes before proceeding.\nPlease select \"Deployment only\" or \"Provisioning + Deployment\" from the Deployment Mode dropdown to continue with already provisioned nodes.",
|
||||
"button_title_all_nodes": "Provision __count__ Node",
|
||||
"button_title_all_nodes_plural": "Provision __count__ Nodes",
|
||||
"button_title_some_nodes": "Provision __selected__ of __count__ Nodes",
|
||||
@ -689,11 +687,11 @@
|
||||
"choose_nodes": "Choose nodes for provisioning"
|
||||
},
|
||||
"deployment": {
|
||||
"title": "Advanced deployment",
|
||||
"description": "Deploys OpenStack on nodes.",
|
||||
"title": "Deployment only",
|
||||
"description": "\"Advanced deployment\" deploys OpenStack services on nodes which have the operating system already provisioned.\nTo complete provisioning and deployment at the same time, select \"Provisioning + Deployment\" from the Deployment Mode dropdown.",
|
||||
"nodes_to_deploy": "__count__ node is provisioned",
|
||||
"nodes_to_deploy_plural": "__count__ nodes are provisioned",
|
||||
"no_nodes_to_deploy": "No online provisioned nodes to deploy.",
|
||||
"no_nodes": "Nodes can only be deployed using the \"Deployment only\" feature if they have been provisioned with an operating system.\nPlease select \"Provisioning only\" or \"Provisioning + Deployment\" from the Deployment Mode dropdown to continue.",
|
||||
"button_title_all_nodes": "Deploy __count__ Node",
|
||||
"button_title_all_nodes_plural": "Deploy __count__ Nodes",
|
||||
"button_title_some_nodes": "Deploy __selected__ of __count__ Nodes",
|
||||
|
@ -348,12 +348,6 @@ var ClusterActionsPanel = React.createClass({
|
||||
);
|
||||
},
|
||||
validations(action) {
|
||||
var checkForOfflineNodes = function(nodes) {
|
||||
var offlineNodes = _.filter(nodes, (node) => !node.get('online'));
|
||||
if (offlineNodes.length) {
|
||||
return i18n(ns + 'offline_nodes', {count: offlineNodes.length});
|
||||
}
|
||||
};
|
||||
switch (action) {
|
||||
case 'deploy':
|
||||
return [
|
||||
@ -373,10 +367,14 @@ var ClusterActionsPanel = React.createClass({
|
||||
};
|
||||
}
|
||||
},
|
||||
// check for offline nodes
|
||||
function(cluster) {
|
||||
return {
|
||||
blocker: [checkForOfflineNodes(cluster.get('nodes').models)]
|
||||
};
|
||||
var offlineNodes = cluster.get('nodes').where({online: false});
|
||||
if (offlineNodes.length) {
|
||||
return {
|
||||
blocker: [i18n(ns + 'offline_nodes', {count: offlineNodes.length})]
|
||||
};
|
||||
}
|
||||
},
|
||||
// check if TLS settings are not configured
|
||||
function(cluster) {
|
||||
@ -494,46 +492,16 @@ var ClusterActionsPanel = React.createClass({
|
||||
}
|
||||
}
|
||||
];
|
||||
case 'provision':
|
||||
return [
|
||||
function(cluster) {
|
||||
return {
|
||||
error: [checkForOfflineNodes(
|
||||
cluster.get('nodes').filter((node) => node.isProvisioningPossible())
|
||||
)]
|
||||
};
|
||||
}
|
||||
];
|
||||
case 'deployment':
|
||||
return [
|
||||
function(cluster) {
|
||||
return {
|
||||
error: [checkForOfflineNodes(
|
||||
cluster.get('nodes').filter((node) => node.isDeploymentPossible())
|
||||
)]
|
||||
};
|
||||
}
|
||||
];
|
||||
case 'spawn_vms':
|
||||
return [
|
||||
function(cluster) {
|
||||
return {
|
||||
blocker: [checkForOfflineNodes(
|
||||
cluster.get('nodes').filter(
|
||||
(node) => node.hasRole('virt') && node.isProvisioningPossible()
|
||||
)
|
||||
)]
|
||||
};
|
||||
}
|
||||
];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
},
|
||||
renderNodesAmount(nodes, dictKey) {
|
||||
renderNodesNumber(nodes, dictKey, showDeleteButton = false) {
|
||||
if (!nodes.length) return null;
|
||||
return (
|
||||
<li className='changes-item'>
|
||||
{i18n(ns + dictKey, {count: nodes.length})}
|
||||
{_.all(nodes, (node) => node.get('pending_addition') || node.get('pending_deletion')) &&
|
||||
{showDeleteButton &&
|
||||
<button
|
||||
className='btn btn-link btn-discard-changes'
|
||||
onClick={() => DiscardNodeChangesDialog.show({cluster: this.props.cluster, nodes})}
|
||||
@ -573,22 +541,25 @@ var ClusterActionsPanel = React.createClass({
|
||||
var action = this.state.currentAction;
|
||||
var actionNs = ns + 'actions.' + action + '.';
|
||||
|
||||
var nodes = this.props.cluster.get('nodes');
|
||||
var {cluster} = this.props;
|
||||
var nodes = {
|
||||
provision: new models.Nodes(
|
||||
cluster.get('nodes').filter((node) => node.isProvisioningPossible())
|
||||
),
|
||||
deployment: new models.Nodes(
|
||||
cluster.get('nodes').filter((node) => node.isDeploymentPossible())
|
||||
),
|
||||
spawn_vms: new models.Nodes(
|
||||
cluster.get('nodes').filter(
|
||||
(node) => node.hasRole('virt') && node.get('status') === 'discover'
|
||||
)
|
||||
),
|
||||
deploy: cluster.get('nodes')
|
||||
}[action];
|
||||
var offlineNodes = nodes.where({online: false});
|
||||
|
||||
var alerts = this.validate(action);
|
||||
var blockerDescriptions = {
|
||||
provision: <InstructionElement
|
||||
description='provisioning_cannot_be_started'
|
||||
isAlert
|
||||
/>,
|
||||
deployment: <InstructionElement
|
||||
description='deployment_of_nodes_cannot_be_started'
|
||||
isAlert
|
||||
/>,
|
||||
spawn_vms: <InstructionElement
|
||||
description='provisioning_cannot_be_started'
|
||||
isAlert
|
||||
/>,
|
||||
deploy: <InstructionElement
|
||||
description='deployment_of_environment_cannot_be_started'
|
||||
isAlert
|
||||
@ -601,135 +572,144 @@ var ClusterActionsPanel = React.createClass({
|
||||
};
|
||||
|
||||
var actionButtonProps = {
|
||||
cluster: this.props.cluster,
|
||||
ns: actionNs,
|
||||
disabled: !this.isActionAvailable(action)
|
||||
disabled: !this.isActionAvailable(action),
|
||||
nodes,
|
||||
cluster
|
||||
};
|
||||
|
||||
var actionControls;
|
||||
switch (action) {
|
||||
case 'deploy':
|
||||
actionControls = (
|
||||
<div className='col-xs-3 changes-list' key={action}>
|
||||
{nodes.hasChanges() &&
|
||||
<ul>
|
||||
{this.renderNodesAmount(nodes.where({pending_addition: true}), 'added_node')}
|
||||
{this.renderNodesAmount(
|
||||
nodes.where({status: 'provisioned', pending_deletion: false}),
|
||||
'provisioned_node'
|
||||
)}
|
||||
{this.renderNodesAmount(nodes.where({pending_deletion: true}), 'deleted_node')}
|
||||
</ul>
|
||||
actionControls = [
|
||||
nodes.hasChanges() &&
|
||||
<ul key='node-changes'>
|
||||
{this.renderNodesNumber(nodes.where({pending_addition: true}), 'added_node', true)}
|
||||
{this.renderNodesNumber(
|
||||
nodes.where({pending_deletion: false, status: 'provisioned'}),
|
||||
'provisioned_node'
|
||||
)}
|
||||
{this.renderNodesNumber(nodes.where({pending_deletion: true}), 'deleted_node', true)}
|
||||
</ul>,
|
||||
<ClusterActionButton
|
||||
{...actionButtonProps}
|
||||
key='action-button'
|
||||
nodes={nodes}
|
||||
className='deploy-btn'
|
||||
iconClassName='deploy-icon'
|
||||
warning={
|
||||
_.isEmpty(alerts.blocker) &&
|
||||
(!_.isEmpty(alerts.error) || !_.isEmpty(alerts.warning))
|
||||
}
|
||||
<ClusterActionButton
|
||||
{...actionButtonProps}
|
||||
nodes={nodes.models}
|
||||
className='deploy-btn'
|
||||
iconClassName='deploy-icon'
|
||||
warning={
|
||||
_.isEmpty(alerts.blocker) &&
|
||||
(!_.isEmpty(alerts.error) || !_.isEmpty(alerts.warning))
|
||||
}
|
||||
dialog={DeployClusterDialog}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
dialog={DeployClusterDialog}
|
||||
/>
|
||||
];
|
||||
break;
|
||||
case 'provision':
|
||||
var nodesToProvision = nodes.filter((node) => node.isProvisioningPossible());
|
||||
actionControls = [
|
||||
!!nodesToProvision.length &&
|
||||
<div className='action-description' key='action-description'>
|
||||
{i18n(actionNs + 'description')}
|
||||
</div>,
|
||||
<div className='col-xs-3 changes-list' key={action}>
|
||||
<ul>
|
||||
!!nodes.length &&
|
||||
<ul key='node-changes'>
|
||||
<li>
|
||||
{i18n(
|
||||
actionNs +
|
||||
(nodesToProvision.length ? 'nodes_to_provision' : 'no_nodes_to_provision'),
|
||||
{count: nodesToProvision.length}
|
||||
)}
|
||||
{i18n(actionNs + 'nodes_to_provision', {count: nodes.length})}
|
||||
</li>
|
||||
</ul>
|
||||
<ClusterActionButton
|
||||
{...actionButtonProps}
|
||||
nodes={nodesToProvision}
|
||||
className='btn-provision'
|
||||
dialog={ProvisionNodesDialog}
|
||||
canSelectNodes
|
||||
/>
|
||||
</div>
|
||||
{!!offlineNodes.length &&
|
||||
<li>
|
||||
{i18n(ns + 'offline_nodes', {count: offlineNodes.length})}
|
||||
</li>
|
||||
}
|
||||
</ul>,
|
||||
<ClusterActionButton
|
||||
{...actionButtonProps}
|
||||
key='action-button'
|
||||
className='btn-provision'
|
||||
dialog={ProvisionNodesDialog}
|
||||
canSelectNodes
|
||||
/>
|
||||
];
|
||||
break;
|
||||
case 'deployment':
|
||||
var nodesToDeploy = nodes.filter((node) => node.isDeploymentPossible());
|
||||
actionControls = [
|
||||
!!nodesToDeploy.length &&
|
||||
<div className='action-description' key='action-description'>
|
||||
{i18n(actionNs + 'description')}
|
||||
</div>,
|
||||
<div className='col-xs-3 changes-list' key={action}>
|
||||
<ul>
|
||||
!!nodes.length &&
|
||||
<ul key='node-changes'>
|
||||
<li>
|
||||
{i18n(
|
||||
actionNs + (nodesToDeploy.length ? 'nodes_to_deploy' : 'no_nodes_to_deploy'),
|
||||
{count: nodesToDeploy.length}
|
||||
)}
|
||||
{i18n(actionNs + 'nodes_to_deploy', {count: nodes.length})}
|
||||
</li>
|
||||
</ul>
|
||||
<ClusterActionButton
|
||||
{...actionButtonProps}
|
||||
nodes={nodesToDeploy}
|
||||
className='btn-deploy-nodes'
|
||||
dialog={DeployNodesDialog}
|
||||
canSelectNodes
|
||||
/>
|
||||
</div>
|
||||
{!!offlineNodes.length &&
|
||||
<li>
|
||||
{i18n(ns + 'offline_nodes', {count: offlineNodes.length})}
|
||||
</li>
|
||||
}
|
||||
</ul>,
|
||||
<ClusterActionButton
|
||||
{...actionButtonProps}
|
||||
key='action-button'
|
||||
className='btn-deploy-nodes'
|
||||
dialog={DeployNodesDialog}
|
||||
canSelectNodes
|
||||
/>
|
||||
];
|
||||
break;
|
||||
case 'spawn_vms':
|
||||
var vmsToProvision = nodes.filter(
|
||||
(node) => node.hasRole('virt') && node.get('status') === 'discover'
|
||||
);
|
||||
actionControls = (
|
||||
<div className='col-xs-3 changes-list' key={action}>
|
||||
<ul>
|
||||
actionControls = [
|
||||
<ul key='node-changes'>
|
||||
<li>
|
||||
{i18n(
|
||||
actionNs + 'nodes_to_provision',
|
||||
{
|
||||
count: nodes.length,
|
||||
role: cluster.get('roles').find({name: 'virt'}).get('label')
|
||||
}
|
||||
)}
|
||||
</li>
|
||||
{!!offlineNodes.length &&
|
||||
<li>
|
||||
{i18n(
|
||||
actionNs + 'nodes_to_provision',
|
||||
{
|
||||
count: vmsToProvision.length,
|
||||
role: this.props.cluster.get('roles').find({name: 'virt'}).get('label')
|
||||
}
|
||||
)}
|
||||
{i18n(ns + 'offline_nodes', {count: offlineNodes.length})}
|
||||
</li>
|
||||
</ul>
|
||||
<ClusterActionButton
|
||||
{...actionButtonProps}
|
||||
nodes={vmsToProvision}
|
||||
className='btn-provision-vms'
|
||||
dialog={ProvisionVMsDialog}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
</ul>,
|
||||
<ClusterActionButton
|
||||
{...actionButtonProps}
|
||||
key='action-button'
|
||||
className='btn-provision-vms'
|
||||
dialog={ProvisionVMsDialog}
|
||||
/>
|
||||
];
|
||||
break;
|
||||
default:
|
||||
actionControls = null;
|
||||
}
|
||||
return (
|
||||
<div className='dashboard-block actions-panel clearfix'>
|
||||
{this.renderActionsDropdown()}
|
||||
{actionControls}
|
||||
<div className='col-xs-9 task-alerts'>
|
||||
{_.map(['blocker', 'error', 'warning'],
|
||||
(severity) => <WarningsBlock
|
||||
key={severity}
|
||||
severity={severity}
|
||||
blockersDescription={blockerDescriptions[action]}
|
||||
alerts={alerts[severity]}
|
||||
/>
|
||||
)}
|
||||
<div className='dashboard-block actions-panel row'>
|
||||
<div className='col-xs-8' key={action}>
|
||||
<div className='row'>
|
||||
<div className='col-xs-12 action-description'>
|
||||
{utils.renderMultilineText(i18n(
|
||||
actionNs + (nodes.length ? 'description' : 'no_nodes'),
|
||||
{
|
||||
defaultValue: '',
|
||||
os: cluster.get('release').get('operating_system')
|
||||
}
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className='row'>
|
||||
<div className='col-xs-4 changes-list'>
|
||||
{actionControls}
|
||||
</div>
|
||||
<div className='col-xs-8 task-alerts'>
|
||||
{_.map(['blocker', 'error', 'warning'],
|
||||
(severity) => <WarningsBlock
|
||||
key={severity}
|
||||
severity={severity}
|
||||
blockersDescription={blockerDescriptions[action]}
|
||||
alerts={alerts[severity]}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='col-xs-4 action-dropdown'>
|
||||
{this.renderActionsDropdown()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@ -739,30 +719,28 @@ var ClusterActionsPanel = React.createClass({
|
||||
if (!this.isActionAvailable('spawn_vms')) actions = _.without(actions, 'spawn_vms');
|
||||
|
||||
return (
|
||||
<ul className='nav navbar-nav navbar-right'>
|
||||
<li className='deployment-modes-label'>
|
||||
<div className='dropdown'>
|
||||
<span className='deployment-modes-label'>
|
||||
{i18n(ns + 'deployment_mode')}:
|
||||
</li>
|
||||
<li className='dropdown'>
|
||||
<button className='btn btn-link dropdown-toggle' data-toggle='dropdown'>
|
||||
{i18n(
|
||||
ns + 'actions.' + this.state.currentAction + '.title'
|
||||
)} <span className='caret'></span>
|
||||
</button>
|
||||
<ul className='dropdown-menu'>
|
||||
{_.map(actions,
|
||||
(action) => <li key={action} className={action}>
|
||||
<button
|
||||
className='btn btn-link'
|
||||
onClick={() => this.toggleAction(action)}
|
||||
>
|
||||
{i18n(ns + 'actions.' + action + '.title')}
|
||||
</button>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<button className='btn btn-link dropdown-toggle' data-toggle='dropdown'>
|
||||
{i18n(
|
||||
ns + 'actions.' + this.state.currentAction + '.title'
|
||||
)} <span className='caret'></span>
|
||||
</button>
|
||||
<ul className='dropdown-menu'>
|
||||
{_.map(actions,
|
||||
(action) => <li key={action} className={action}>
|
||||
<button
|
||||
className='btn btn-link'
|
||||
onClick={() => this.toggleAction(action)}
|
||||
>
|
||||
{i18n(ns + 'actions.' + action + '.title')}
|
||||
</button>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
render() {
|
||||
@ -790,7 +768,7 @@ var ClusterActionsPanel = React.createClass({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return <div className='row'>{this.renderActions()}</div>;
|
||||
return <div>{this.renderActions()}</div>;
|
||||
}
|
||||
});
|
||||
|
||||
@ -798,7 +776,7 @@ var ClusterActionButton = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
// offline nodes should not be selected for the task
|
||||
selectedNodeIds: _.pluck(_.filter(this.props.nodes, (node) => node.get('online')), 'id')
|
||||
selectedNodeIds: _.pluck(this.props.nodes.where({online: true}), 'id')
|
||||
};
|
||||
},
|
||||
getDefaultProps() {
|
||||
@ -809,8 +787,7 @@ var ClusterActionButton = React.createClass({
|
||||
};
|
||||
},
|
||||
showSelectNodesDialog() {
|
||||
var {cluster} = this.props;
|
||||
var nodes = new models.Nodes(this.props.nodes);
|
||||
var {nodes, cluster} = this.props;
|
||||
nodes.fetch = function(options) {
|
||||
return this.constructor.__super__.fetch.call(this,
|
||||
_.extend({data: {cluster_id: cluster.id}}, options));
|
||||
|
Loading…
Reference in New Issue
Block a user