Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Merge "Refactor Register nodes dialog to use redux-form"
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuul authored and openstack-gerrit committed Dec 4, 2017
2 parents 38d2946 + 2268b05 commit 3099c34
Show file tree
Hide file tree
Showing 32 changed files with 1,376 additions and 1,284 deletions.
12 changes: 8 additions & 4 deletions .babelrc
@@ -1,9 +1,13 @@
{
"presets": ["es2015", "stage-0", "react"],
"plugins": [
["react-intl", {
"messagesDir": "./i18n/extracted-messages/",
"enforceDescriptions": false
}]
[
"react-intl",
{
"messagesDir": "./i18n/extracted-messages/",
"enforceDescriptions": false,
"moduleSourceName": "./redux-form-validators"
}
]
]
}
7 changes: 7 additions & 0 deletions releasenotes/notes/nodesRegistration-fc446cccf7b871a8.yaml
@@ -0,0 +1,7 @@
---
features:
- |
Nodes Registration form has been streamlined. After the nodes registration
form is submitted, nodes are confirmed valid and registration begins. At
this point registration form is closed and remaining registration process is
tracked in Nodes listing view.
55 changes: 19 additions & 36 deletions src/__tests__/actions/RegisterNodesActions.tests.js
Expand Up @@ -16,41 +16,31 @@

import shortid from 'shortid';
import { Map } from 'immutable';

import { InitialPlanState, Plan } from '../../js/immutableRecords/plans';
import MistralApiService from '../../js/services/MistralApiService';
import mockHistory from '../mocks/history';
import { mockStore } from './utils';
import RegisterNodesActions from '../../js/actions/RegisterNodesActions';
import NodesActions from '../../js/actions/NodesActions';
import NotificationActions from '../../js/actions/NotificationActions';
import { IronicNode } from '../../js/immutableRecords/nodes';
import ValidationsActions from '../../js/actions/ValidationsActions';
import RegisterNodesActions from '../../js/actions/RegisterNodesActions';

describe('Asynchronous Register Nodes Action', () => {
describe('startNodesRegistration Action', () => {
const store = mockStore({});
const nodesToRegister = Map({
1: new IronicNode({
uuid: 1
})
});
const nodesToRegister = [
{
name: 'node1',
pm_addr: '192.168.10.10',
pm_user: 'admin',
pm_password: 'pass'
}
];

beforeEach(() => {
MistralApiService.runWorkflow = jest
.fn()
.mockReturnValue(() => Promise.resolve({ state: 'RUNNING' }));
});

it('dispatches actions', () => {
return store
.dispatch(RegisterNodesActions.startNodesRegistration(nodesToRegister))
.then(() => {
expect(MistralApiService.runWorkflow).toHaveBeenCalled();
expect(store.getActions()).toEqual([
RegisterNodesActions.startNodesRegistrationPending(nodesToRegister),
RegisterNodesActions.startNodesRegistrationSuccess()
]);
});
it('dispatches nodesRegistrationPending', () => {
store.dispatch(
RegisterNodesActions.startNodesRegistration(nodesToRegister)
);
expect(store.getActions()).toEqual([
RegisterNodesActions.nodesRegistrationPending()
]);
});
});

Expand Down Expand Up @@ -103,10 +93,7 @@ describe('nodesRegistrationFinished', () => {
};

store.dispatch(
RegisterNodesActions.nodesRegistrationFinished(
messagePayload,
mockHistory
)
RegisterNodesActions.nodesRegistrationFinished(messagePayload)
);
expect(NodesActions.fetchNodes).toHaveBeenCalled();
expect(store.getActions()).toEqual([
Expand Down Expand Up @@ -161,13 +148,9 @@ describe('nodesRegistrationFinished', () => {
];

store.dispatch(
RegisterNodesActions.nodesRegistrationFinished(
messagePayload,
mockHistory
)
RegisterNodesActions.nodesRegistrationFinished(messagePayload)
);
expect(NodesActions.fetchNodes).toHaveBeenCalled();
expect(mockHistory.push).toHaveBeenCalledWith('/nodes/register');
expect(store.getActions()).toEqual([
NodesActions.addNodes(normalizedRegisteredNodes),
RegisterNodesActions.nodesRegistrationFailed(errors)
Expand Down
82 changes: 0 additions & 82 deletions src/__tests__/selectors/registerNodes.tests.js

This file was deleted.

89 changes: 11 additions & 78 deletions src/js/actions/RegisterNodesActions.js
Expand Up @@ -19,14 +19,11 @@ import { normalize, arrayOf } from 'normalizr';
import { Map } from 'immutable';

import { getCurrentPlanName } from '../selectors/plans';
import { handleErrors } from './ErrorActions';
import RegisterNodesConstants from '../constants/RegisterNodesConstants';
import MistralApiService from '../services/MistralApiService';
import NotificationActions from './NotificationActions';
import NodesActions from './NodesActions';
import { nodeSchema } from '../normalizrSchemas/nodes';
import ValidationsActions from './ValidationsActions';
import MistralConstants from '../constants/MistralConstants';

const messages = defineMessages({
registrationNotificationTitle: {
Expand All @@ -40,82 +37,26 @@ const messages = defineMessages({
});

export default {
addNode(node) {
return {
type: RegisterNodesConstants.ADD_NODE,
payload: node
};
},

selectNode(id) {
return {
type: RegisterNodesConstants.SELECT_NODE,
payload: id
};
},

removeNode(id) {
return {
type: RegisterNodesConstants.REMOVE_NODE,
payload: id
};
},

updateNode(node) {
return {
type: RegisterNodesConstants.UPDATE_NODE,
payload: node
};
},

startNodesRegistration(nodes) {
return (dispatch, getState) => {
dispatch(this.startNodesRegistrationPending(nodes));
return dispatch(
MistralApiService.runWorkflow(
MistralConstants.BAREMETAL_REGISTER_OR_UPDATE,
{
nodes_json: nodes.toList().toJS(),
kernel_name: 'bm-deploy-kernel',
ramdisk_name: 'bm-deploy-ramdisk'
}
)
)
.then(response => {
dispatch(this.startNodesRegistrationSuccess());
})
.catch(error => {
dispatch(handleErrors(error, 'Nodes registration failed', false));
dispatch(
this.startNodesRegistrationFailed([
{ title: 'Nodes registration failed', message: error.message }
])
);
});
};
},

startNodesRegistrationPending(nodes) {
return {
type: RegisterNodesConstants.START_NODES_REGISTRATION_PENDING,
payload: nodes
// TODO(jtomasek): Once we are able to generate UUIDs for nodes,
// add nodes to the list and add operation using startNodesOperation action.
// Remove registerNodesReducer and track the progress on each node.
// Introduce separate reducer for tracking operations: nodeOperationsById
// dispatch(NodesActions.addNodes(nodes.map(node => new Node(node))));
// dispatch(startOperation(nodes.map(node => node.uuid), 'register'))
// addNodes(nodesToRegister.map(node => new Node))
dispatch(this.nodesRegistrationPending());
};
},

startNodesRegistrationSuccess() {
nodesRegistrationPending() {
return {
type: RegisterNodesConstants.START_NODES_REGISTRATION_SUCCESS
type: RegisterNodesConstants.NODES_REGISTRATION_PENDING
};
},

startNodesRegistrationFailed(errors) {
return {
type: RegisterNodesConstants.START_NODES_REGISTRATION_FAILED,
payload: errors
};
},

nodesRegistrationFinished(messagePayload, history) {
nodesRegistrationFinished(messagePayload) {
return (dispatch, getState, { getIntl }) => {
const { formatMessage } = getIntl(getState());
const registeredNodes =
Expand Down Expand Up @@ -143,7 +84,6 @@ export default {
})
);
dispatch(this.nodesRegistrationSuccess());
history.push('/nodes');
break;
}
case 'FAILED': {
Expand All @@ -155,7 +95,6 @@ export default {
.map(m => m.result)
}
];
history.push('/nodes/register');
// TODO(jtomasek): repopulate nodes registration form with failed nodes provided by message
dispatch(this.nodesRegistrationFailed(errors));
break;
Expand All @@ -180,11 +119,5 @@ export default {
failedNodes: failedNodes
}
};
},

cancelNodesRegistration() {
return {
type: RegisterNodesConstants.CANCEL_NODES_REGISTRATION
};
}
};
13 changes: 12 additions & 1 deletion src/js/components/nodes/Nodes.js
Expand Up @@ -31,7 +31,7 @@ import NodesListForm from './NodesListView/NodesListForm';
import NodesListView from './NodesListView/NodesListView';
import NodesToolbar from './NodesToolbar/NodesToolbar';
import NodesTableView from './NodesTableView';
import RegisterNodesDialog from './RegisterNodesDialog';
import RegisterNodesDialog from './registerNodes/RegisterNodesDialog';

const messages = defineMessages({
loadingNodes: {
Expand All @@ -46,6 +46,10 @@ const messages = defineMessages({
id: 'Nodes.registerNodes',
defaultMessage: 'Register Nodes'
},
registeringNodes: {
id: 'Nodes.registeringNodes',
defaultMessage: 'Registering Nodes...'
},
nodes: {
id: 'Nodes.nodes',
defaultMessage: 'Nodes'
Expand Down Expand Up @@ -111,6 +115,11 @@ class Nodes extends React.Component {
height={80}
>
<NodesToolbar />
<Loader
loaded={!this.props.isRegistering}
content={this.props.intl.formatMessage(messages.registeringNodes)}
height={80}
/>
{this.renderContentView()}
</Loader>
<Route path="/nodes/register" component={RegisterNodesDialog} />
Expand All @@ -125,6 +134,7 @@ Nodes.propTypes = {
fetchNodes: PropTypes.func.isRequired,
fetchingNodes: PropTypes.bool.isRequired,
intl: PropTypes.object.isRequired,
isRegistering: PropTypes.bool.isRequired,
nodes: ImmutablePropTypes.map.isRequired,
nodesInProgress: ImmutablePropTypes.set.isRequired,
nodesLoaded: PropTypes.bool.isRequired
Expand All @@ -135,6 +145,7 @@ const mapStateToProps = state => ({
'contentView',
'list'
),
isRegistering: state.registerNodes.get('isRegistering'),
fetchingNodes: state.nodes.get('isFetching'),
nodes: getFilteredNodes(state),
nodesInProgress: nodesInProgress(state),
Expand Down

0 comments on commit 3099c34

Please sign in to comment.