diff options
11 files changed, 157 insertions, 94 deletions
diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/create/CreateVersionView.jsx b/workflow-designer-ui/src/main/frontend/src/features/version/create/CreateVersionView.jsx index f3a2cccf..23e5db15 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/version/create/CreateVersionView.jsx +++ b/workflow-designer-ui/src/main/frontend/src/features/version/create/CreateVersionView.jsx @@ -60,7 +60,7 @@ class CreateVersionView extends Component { render() { const { closeCreateVersionModal } = this.props; return ( - <form onSubmit={this.handleSubmitForm}> + <form onSubmit={this.handleSubmitForm} autoComplete="off"> <div className="new-version-page custom-modal-wrapper"> <div className="form-custom-modal"> <Select diff --git a/workflow-designer-ui/src/main/frontend/src/features/version/create/__tests__/__snapshots__/CreateVersionView_snapshot-test.js.snap b/workflow-designer-ui/src/main/frontend/src/features/version/create/__tests__/__snapshots__/CreateVersionView_snapshot-test.js.snap index 4f94780d..991ad184 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/version/create/__tests__/__snapshots__/CreateVersionView_snapshot-test.js.snap +++ b/workflow-designer-ui/src/main/frontend/src/features/version/create/__tests__/__snapshots__/CreateVersionView_snapshot-test.js.snap @@ -2,6 +2,7 @@ exports[`Create new version snapshot renders correctly 1`] = ` <form + autoComplete="off" onSubmit={[Function]} > <div diff --git a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/CreateWorkflow.js b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/CreateWorkflow.js index b2a5600b..190677fe 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/CreateWorkflow.js +++ b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/CreateWorkflow.js @@ -27,8 +27,9 @@ import { import { inputChangeAction, submitWorkflowAction, - putNameError + clearValidationError } from 'features/workflow/create/createWorkflowConstants'; +import { clearWorkflowAction } from 'features/workflow/workflowConstants'; function mapStateToProps(state) { return { @@ -44,11 +45,11 @@ function mapDispatchToProps(dispatch) { return { submitWorkflow: payload => { dispatch(submitWorkflowAction(payload)); - dispatch(hideModalAction()); }, closeCreateWorkflowModal: () => dispatch(hideModalAction()), - putNameError: () => dispatch(putNameError()), - workflowInputChange: payload => dispatch(inputChangeAction(payload)) + clearValidationError: () => dispatch(clearValidationError()), + workflowInputChange: payload => dispatch(inputChangeAction(payload)), + clearWorkflow: () => dispatch(clearWorkflowAction) }; } diff --git a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/CreateWorkflowView.jsx b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/CreateWorkflowView.jsx index 5b091322..6aee9f74 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/CreateWorkflowView.jsx +++ b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/CreateWorkflowView.jsx @@ -13,88 +13,89 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; +import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Input, Button } from 'sdc-ui/lib/react'; import { I18n } from 'react-redux-i18n'; import Description from 'shared/components/Description'; -const CreateWorkflowView = props => { - const { - workflowInputChange, - workflowDescription, - workflowName, - submitWorkflow, - closeCreateWorkflowModal, - workflowParams, - history, - errorMessage, - putNameError - } = props; +class CreateWorkflowView extends Component { + static propTypes = { + submitWorkflow: PropTypes.func, + workflowInputChange: PropTypes.func, + workflowDescription: PropTypes.string, + workflowName: PropTypes.string, + closeCreateWorkflowModal: PropTypes.func, + workflowParams: PropTypes.object, + history: PropTypes.object, + errorMessage: PropTypes.string, + clearValidationError: PropTypes.func, + clearWorkflow: PropTypes.func + }; - function handleSubmitForm(e) { - e.preventDefault(); - if (workflowParams.name) { - submitWorkflow({ ...workflowParams, history }); - } else { - putNameError(); - } + componentDidMount() { + const { clearValidationError, clearWorkflow } = this.props; + clearValidationError(); + clearWorkflow(); } + handleSubmitForm = e => { + e.preventDefault(); + const { workflowParams, history, submitWorkflow } = this.props; + submitWorkflow({ ...workflowParams, history }); + }; - return ( - <form onSubmit={handleSubmitForm}> - <div className="new-workflow-page custom-modal-wrapper"> - <div className="form-custom-modal"> - <Input - name="workflowName" - value={workflowName || ''} - type="text" - label={I18n.t('workflow.general.name')} - onChange={val => - workflowInputChange({ - name: val - }) - } - errorMessage={errorMessage} - isRequired - /> - <Description - value={workflowDescription || ''} - label={I18n.t('workflow.general.description')} - onDataChange={workflowInputChange} - /> + render() { + const { + workflowInputChange, + workflowDescription, + workflowName, + closeCreateWorkflowModal, + errorMessage + } = this.props; + return ( + <form onSubmit={this.handleSubmitForm} autoComplete="off"> + <div className="new-workflow-page custom-modal-wrapper"> + <div className="form-custom-modal"> + <Input + name="workflowName" + value={workflowName || ''} + type="text" + label={I18n.t('workflow.general.name')} + onChange={val => + workflowInputChange({ + name: val + }) + } + errorMessage={errorMessage} + isRequired + /> + <Description + value={workflowDescription || ''} + label={I18n.t('workflow.general.description')} + onDataChange={workflowInputChange} + /> + </div> + <div className="modal-action-bar sdc-modal__footer"> + <Button btnType="primary"> + {I18n.t('buttons.createBtn')} + </Button> + <Button + btnType="secondary" + onClick={closeCreateWorkflowModal}> + {I18n.t('buttons.closeBtn')} + </Button> + </div> </div> - <div className="modal-action-bar sdc-modal__footer"> - <Button btnType="primary"> - {I18n.t('buttons.createBtn')} - </Button> - <Button - btnType="secondary" - onClick={closeCreateWorkflowModal}> - {I18n.t('buttons.closeBtn')} - </Button> - </div> - </div> - </form> - ); -}; - -CreateWorkflowView.propTypes = { - submitWorkflow: PropTypes.func, - workflowInputChange: PropTypes.func, - workflowDescription: PropTypes.string, - workflowName: PropTypes.string, - closeCreateWorkflowModal: PropTypes.func, - workflowParams: PropTypes.object, - history: PropTypes.object, - errorMessage: PropTypes.string, - putNameError: PropTypes.func -}; + </form> + ); + } +} CreateWorkflowView.defaultProps = { submitWorkflow: () => {}, workflowInputChange: () => {}, - closeCreateWorkflowModal: () => {} + closeCreateWorkflowModal: () => {}, + clearWorkflow: () => {} }; export default CreateWorkflowView; diff --git a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/CreateWorkflowView_snapshot-test.js b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/CreateWorkflowView_snapshot-test.js index a0d81c71..e34cea96 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/CreateWorkflowView_snapshot-test.js +++ b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/CreateWorkflowView_snapshot-test.js @@ -22,7 +22,14 @@ import CreateWorkflowView from 'features/workflow/create/CreateWorkflowView'; describe('New Workflow View Snapshot', () => { it('renders correctly', () => { - const tree = renderer.create(<CreateWorkflowView />).toJSON(); + const tree = renderer + .create( + <CreateWorkflowView + clearValidationError={() => {}} + clearWorkflow={() => {}} + /> + ) + .toJSON(); expect(tree).toMatchSnapshot(); }); diff --git a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/__snapshots__/CreateWorkflowView_snapshot-test.js.snap b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/__snapshots__/CreateWorkflowView_snapshot-test.js.snap index afd57303..59695f03 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/__snapshots__/CreateWorkflowView_snapshot-test.js.snap +++ b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/__snapshots__/CreateWorkflowView_snapshot-test.js.snap @@ -2,6 +2,7 @@ exports[`New Workflow View Snapshot renders correctly 1`] = ` <form + autoComplete="off" onSubmit={[Function]} > <div diff --git a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/createWorkflowSaga-test.js b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/createWorkflowSaga-test.js index c9782c1b..244a66de 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/createWorkflowSaga-test.js +++ b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/__tests__/createWorkflowSaga-test.js @@ -47,6 +47,12 @@ describe('New workflow saga test', () => { } }; const gen = watchSubmitWorkflow(action); + + /** + * expecting the error message to return as undefined + * from validateNameField method + */ + expect(gen.next().value).toEqual(undefined); expect(gen.next().value).toEqual( call(newWorkflowApi.createNewWorkflow, action.payload) ); diff --git a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/createWorkflowConstants.js b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/createWorkflowConstants.js index fc67605f..de18a1b4 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/createWorkflowConstants.js +++ b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/createWorkflowConstants.js @@ -18,9 +18,13 @@ export const NEW_VERSION = { baseId: null, description: null }; +export const MIN_NAME_LENGTH = 6; +export const MAX_NAME_LENGTH = 40; +export const CHARS_VALIDATION_EXP = /^[\w\s\d]+$/; export const WORKFLOW_INPUT_CHANGE = 'createWorkflow/INPUT_CHANGE'; export const SUBMIT_WORKFLOW = 'createWorkflow/SUBMIT_WORKFLOW'; -export const EMPTY_NAME_ERROR = 'createWorkflow/EMPTY_NAME_ERROR'; +export const VALIDATION_ERROR = 'createWorkflow/VALIDATION_ERROR'; +export const CLEAR_VALIDATION_ERROR = 'createWorkflow/CLEAR_VALIDATION_ERROR'; export const inputChangeAction = payload => ({ type: WORKFLOW_INPUT_CHANGE, @@ -32,6 +36,9 @@ export const submitWorkflowAction = payload => ({ payload }); -export const putNameError = () => ({ - type: EMPTY_NAME_ERROR +export const putValidationError = payload => ({ + type: VALIDATION_ERROR, + payload }); + +export const clearValidationError = () => ({ type: CLEAR_VALIDATION_ERROR }); diff --git a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/createWorkflowSaga.js b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/createWorkflowSaga.js index 7f988002..e918556b 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/workflow/create/createWorkflowSaga.js +++ b/workflow-designer-ui/src/main/frontend/src/features/workflow/create/createWorkflowSaga.js @@ -14,33 +14,66 @@ * limitations under the License. */ import { takeEvery, call, put } from 'redux-saga/effects'; -import { SUBMIT_WORKFLOW } from 'features/workflow/create/createWorkflowConstants'; +import { I18n } from 'react-redux-i18n'; + +import { + SUBMIT_WORKFLOW, + NEW_VERSION, + MAX_NAME_LENGTH, + MIN_NAME_LENGTH, + CHARS_VALIDATION_EXP, + putValidationError +} from 'features/workflow/create/createWorkflowConstants'; import { setWorkflowAction, clearWorkflowAction } from 'features/workflow/workflowConstants'; +import { hideModalAction } from 'shared/modal/modalWrapperActions'; import newWorkflowApi from 'features/workflow/create/createWorkflowApi'; import { genericNetworkErrorAction } from 'wfapp/appConstants'; import { submitVersionAction } from 'features/version/create/createVersionConstants'; -import { NEW_VERSION } from 'features/workflow/create/createWorkflowConstants'; export function* watchSubmitWorkflow(action) { try { - const workflow = yield call( - newWorkflowApi.createNewWorkflow, - action.payload - ); - //Calling to create empty version - const workflowId = workflow.id; - const { history } = action.payload; - yield put(submitVersionAction({ history, workflowId, ...NEW_VERSION })); - yield put(setWorkflowAction(workflow)); + const { name } = action.payload; + const validationError = yield validateNameField(name); + if (validationError) { + yield put(putValidationError(validationError)); + } else { + const workflow = yield call( + newWorkflowApi.createNewWorkflow, + action.payload + ); + //Calling to create empty version + const workflowId = workflow.id; + const { history } = action.payload; + yield put( + submitVersionAction({ history, workflowId, ...NEW_VERSION }) + ); + yield put(setWorkflowAction(workflow)); + yield put(hideModalAction()); + } } catch (error) { yield put(clearWorkflowAction); yield put(genericNetworkErrorAction(error)); } } +export function validateNameField(name) { + let errorMessage; + if (!name) { + errorMessage = I18n.t('workflow.errorMessages.emptyName'); + } else if (!CHARS_VALIDATION_EXP.test(name)) { + errorMessage = I18n.t('workflow.errorMessages.invalidCharacters'); + } else if (name.length < MIN_NAME_LENGTH || name.length > MAX_NAME_LENGTH) { + errorMessage = I18n.t('workflow.errorMessages.nameFieldLength', { + minValue: 6, + maxValue: 40 + }); + } + return errorMessage; +} + export function* watchWorkflow() { yield takeEvery(SUBMIT_WORKFLOW, watchSubmitWorkflow); } diff --git a/workflow-designer-ui/src/main/frontend/src/features/workflow/workflowReducer.js b/workflow-designer-ui/src/main/frontend/src/features/workflow/workflowReducer.js index 3b7e17b4..c0b0557d 100644 --- a/workflow-designer-ui/src/main/frontend/src/features/workflow/workflowReducer.js +++ b/workflow-designer-ui/src/main/frontend/src/features/workflow/workflowReducer.js @@ -14,10 +14,10 @@ * limitations under the License. */ -import { I18n } from 'react-redux-i18n'; import { WORKFLOW_INPUT_CHANGE, - EMPTY_NAME_ERROR + VALIDATION_ERROR, + CLEAR_VALIDATION_ERROR } from 'features/workflow/create/createWorkflowConstants'; import { SET_WORKFLOW, @@ -37,10 +37,15 @@ function workflowReducer(state = {}, action) { return { ...action.payload }; - case EMPTY_NAME_ERROR: + case VALIDATION_ERROR: return { ...state, - error: I18n.t('workflow.errorMessages.emptyName') + error: action.payload + }; + case CLEAR_VALIDATION_ERROR: + return { + ...state, + error: '' }; default: return state; diff --git a/workflow-designer-ui/src/main/frontend/src/i18n/languages.json b/workflow-designer-ui/src/main/frontend/src/i18n/languages.json index 36546452..42f2475e 100644 --- a/workflow-designer-ui/src/main/frontend/src/i18n/languages.json +++ b/workflow-designer-ui/src/main/frontend/src/i18n/languages.json @@ -64,7 +64,8 @@ "errorMessages": { "alreadyExists": "Already exists", "invalidCharacters": "Alphanumeric and underscore only", - "emptyName": "Field is required" + "emptyName": "Field is required", + "nameFieldLength": "Name must be at least %{minValue} characters and no more than %{maxValue} characters" }, "composition": { "bpmnError" : "BPMN.IO Error", |