Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yamuna | FBE - 22 | Implementation of form conditions Editor #4

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
42b9414
Sneha | FBE-29 | When a form is edited after publish copy transaltion…
bsneha90TW Mar 26, 2020
1c8a98d
Vinay | FBE - 32 | Add form name in translations page and save the tr…
vinay-ThoughtWorks Mar 30, 2020
e82f368
Sowmika, Alekhya | FBE-70 | Add save button on preview popup
sowmika148 Mar 24, 2020
3795f46
Sowmika, Alekhya | FBE-70 | Use renderWithControls instead of container
sowmika148 Mar 26, 2020
0cd10fc
Sowmika, Alekhya | FBE-70 | Execute formSave event when save button o…
sowmika148 Mar 26, 2020
dbc4ebe
Sowmika, Alekhya | FBE-70 | Handle errors from onFormSave event
sowmika148 Mar 30, 2020
f7878d5
Sowmika, Swetha | FBE-34 | Fix form event getting copied while creati…
swetha1992 Mar 31, 2020
dedec8f
Vinay | FBE - 32 | Add saveFormNameTranslations call on form publish
vinay-ThoughtWorks Mar 31, 2020
2782daa
Vinay | FBE - 32 | Handle form name change
vinay-ThoughtWorks Mar 31, 2020
3a4594e
Vinay | FBE - 66 | Fix form controls scroll in minimum resolution scr…
vinay-ThoughtWorks Apr 1, 2020
200ff3d
Vinay, Swetha | FBE-73 | Support form name translations for bulk impo…
vinay-ThoughtWorks Apr 3, 2020
e624530
Vinay, Swetha | FBE-73 | Fix tests
vinay-ThoughtWorks Apr 3, 2020
ae8ea17
Vinay | FBE - 32 | Display recently saved name even on locale change
vinay-ThoughtWorks Apr 3, 2020
472ad18
Vinay | FBE - 66 | Fix scroll issue with minimal resolution for ubuntu
vinay-ThoughtWorks Apr 6, 2020
3169ab0
Yamuna | FBE - 22 | Add full screen viewer for all form events
Apr 1, 2020
4b882cd
Yamuna | FBE - 22 | Change all controls form viewer Obs dropdown to r…
Apr 1, 2020
a824f8e
Yamuna | FBE - 22 | Move styles to css class
Apr 2, 2020
de38372
Yamuna | FBE - 22 | Add proper spaces in Css file & Remove setState B…
Apr 2, 2020
571a43c
Yamuna | FBE - 22 | Add unit tests for fbe-22 functionality
Apr 6, 2020
efc0b21
Yamuna | FBE - 22 | Css changes to have vertical scroll in form condi…
Apr 6, 2020
5555634
Yamuna | FBE - 22 | Modify code to support code review comments
Apr 7, 2020
03867f0
Yamuna | FBE - 22 | Remove unused code
Apr 7, 2020
177d9a3
Yamuna | FBE - 22 | Add support for reading obscontrol in hierrachy a…
Apr 9, 2020
86075db
Yamuna | FBE - 22 | Add unit test for getObsControlEvents method in F…
Apr 9, 2020
d34d454
Yamuna | FBE - 22 | Resolving conflicts with master
Apr 9, 2020
5038c3f
Yamuna | FBE - 22 | Applying Resolve conflicts with master
Apr 9, 2020
e483288
Revert "Yamuna | FBE - 22 | Applying Resolve conflicts with master"
Apr 9, 2020
f46b2e9
Revert "Yamuna | FBE - 22 | Resolving conflicts with master"
Apr 9, 2020
e4fc8e2
Yamuna | FBE - 22 | Applying Resolve conflicts with master
Apr 9, 2020
dec8b99
Yamuna | FBE-22 | Add tests for unit test coverage
Apr 10, 2020
603aa3a
Yamuna | FBE - 22 | Update unittests to meet coverage percentage
Apr 10, 2020
de772fe
Yamuna | FBE - 22 | Fix line spacing between label and code editor in…
Apr 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/common/apis/formTranslationApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,14 @@ export function translationsFor(formName, formVersion, locale, formUuid) {
export function saveTranslations(translations) {
return httpInterceptor.post(formBuilderConstants.saveTranslationsUrl, translations);
}

export function saveFormNameTranslations(nameTranslations, referenceUuid) {
return httpInterceptor.post(new UrlHelper()
.bahmniSaveFormNameTranslateUrl(referenceUuid), nameTranslations);
}


export function getFormNameTranslations(formName, formUuid) {
return httpInterceptor.get(new UrlHelper()
.bahmniFormNameTranslateUrl(formName, formUuid), 'text');
}
6 changes: 5 additions & 1 deletion src/form-builder/actions/control.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const addSourceMap = (sourceMap) => ({ type: 'ADD_SOURCE_MAP', sourceMap
export const setChangedProperty = (property, id) =>
({ type: 'SET_CHANGED_PROPERTY', property, id });

export const sourceChangedProperty = (source) => ({ type: 'SOURCE_CHANGED', source });
export const sourceChangedProperty = (source, id) => ({ type: 'SOURCE_CHANGED', source, id });

export const dragSourceUpdate = (cell) => ({ type: 'DRAG_SOURCE_CHANGED', cell });

Expand All @@ -35,3 +35,7 @@ export const removeLocaleTranslation =
(locale) => ({ type: 'REMOVE_LOCALE_TRANSLATIONS', locale });

export const clearTranslations = () => ({ type: 'CLEAR_TRANSLATIONS' });

export const formConditionsEventUpdate = (events) => ({ type: 'FORM_CONDITIONS_CHANGED', events });

export const formLoad = (controls) => ({ type: 'FORM_LOAD', controls });
48 changes: 37 additions & 11 deletions src/form-builder/components/FormBuilder.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ import { saveAs } from 'file-saver';
import NotificationContainer from 'common/Notification';
import { remove } from 'lodash';
import Spinner from 'common/Spinner';

import { formEventUpdate, saveEventUpdate } from 'form-builder/actions/control';

export default class FormBuilder extends Component {

constructor() {
super();
constructor(props) {
super(props);
this.state = { showModal: false, selectedForms: [], notification: {}, loading: false };
this.setState = this.setState.bind(this);

Expand All @@ -32,6 +32,7 @@ export default class FormBuilder extends Component {
this.formConceptValidationResults = {};
this.handleSelectedForm = this.handleSelectedForm.bind(this);
this.parseErrorMessage = 'Parse Error While Importing.. Please import a valid form';
this.clearEventEditors();
}

getFormVersion(formName) {
Expand Down Expand Up @@ -88,6 +89,11 @@ export default class FormBuilder extends Component {
return validJsonFiles;
}

clearEventEditors() {
this.props.dispatch(saveEventUpdate(''));
this.props.dispatch(formEventUpdate(''));
}

validateAndLoadZipFile(jsonZip) {
const self = this;
const maxAllowedSize = 5 * 1024 * 1024;
Expand Down Expand Up @@ -221,6 +227,7 @@ export default class FormBuilder extends Component {
const { formJson, translations } = formData;
const formName = formJson.name;
const value = JSON.parse(formJson.resources[0].value);
const nameTranslations = formJson.resources[1] && formJson.resources[1].value;
const form = {
name: formName,
version: '1',
Expand All @@ -239,7 +246,7 @@ export default class FormBuilder extends Component {
});
self.updateImportErrors(fileName, message);
} else {
self.formJSONs.push({ form, value, formName, translations });
self.formJSONs.push({ form, value, formName, translations, nameTranslations });
}
});
}
Expand Down Expand Up @@ -271,15 +278,16 @@ export default class FormBuilder extends Component {
const self = this;
const importFormJsonPromises = [];
formJsons.forEach(formJson => {
const { form, value, formName, translations } = formJson;
importFormJsonPromises.push(self.saveFormJson(form, value, formName, translations));
const { form, value, formName, translations, nameTranslations } = formJson;
importFormJsonPromises.push(self.saveFormJson(form, value, formName, translations,
nameTranslations));
});
Promise.all(importFormJsonPromises)
.then(() => self.hideLoader())
.catch(() => self.hideLoader());
}

saveFormJson(form, value, formName, translations) {
saveFormJson(form, value, formName, translations, nameTranslations) {
const self = this;
const val = value;
return httpInterceptor.post(formBuilderConstants.formUrl, form).then((response) => {
Expand All @@ -292,9 +300,18 @@ export default class FormBuilder extends Component {
value: JSON.stringify(value),
uuid: '',
};
const translationsWithFormUuid = translations.map((eachTranslation) => Object.assign({},
eachTranslation, { formUuid: response.uuid }));
self.props.saveFormResource(formResource, translationsWithFormUuid);
const formNameTranslationsResource = !!nameTranslations && {
form: {
name: formName,
uuid: response.uuid,
},
value: nameTranslations,
uuid: '',
};
const translationsWithFormUuid = translations.map((eachTranslation) =>
Object.assign({}, eachTranslation, { formUuid: response.uuid }));
self.props.saveFormResource(formResource, translationsWithFormUuid,
formNameTranslationsResource);
})
.catch(() => {
const formUuid = self.getFormUuid(formName);
Expand All @@ -312,7 +329,15 @@ export default class FormBuilder extends Component {
value: JSON.stringify(value),
uuid: data.resources[0].uuid,
};
self.props.saveFormResource(formResource, translations);
const formNameTranslationsResource = !!nameTranslations && {
form: {
name: formName,
uuid: formUuid,
},
value: nameTranslations,
uuid: '',
};
self.props.saveFormResource(formResource, translations, formNameTranslationsResource);
});
});
}
Expand Down Expand Up @@ -479,6 +504,7 @@ export default class FormBuilder extends Component {

FormBuilder.propTypes = {
data: PropTypes.array.isRequired,
dispatch: PropTypes.func.isRequired,
match: PropTypes.shape({
path: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
Expand Down
33 changes: 18 additions & 15 deletions src/form-builder/components/FormBuilderContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import sortBy from 'lodash/sortBy';
import formHelper from '../helpers/formHelper';
import { connect } from 'react-redux';
import { setDefaultLocale } from '../actions/control';
import { saveTranslations } from 'common/apis/formTranslationApi';
import { saveFormNameTranslations, saveTranslations } from 'common/apis/formTranslationApi';


export class FormBuilderContainer extends Component {
Expand Down Expand Up @@ -103,21 +103,23 @@ export class FormBuilderContainer extends Component {
}
}

saveTranslations(translations) {
saveTranslations(translations, formNameTranslations) {
const self = this;
self.setMessage('Importing Translations...', commonConstants.responseType.success);
saveTranslations(translations || [])
.then(() => {
self.getFormData();
self.setMessage('Imported Successfully',
commonConstants.responseType.success);
})
.catch(() => {
this.setMessage('Error Importing Translations', commonConstants.responseType.error);
});
const translationsPromises = [saveTranslations(translations || [])];
if (formNameTranslations) {
translationsPromises.push(saveFormNameTranslations(formNameTranslations, null));
}

Promise.all(translationsPromises).then(() => {
self.getFormData();
self.setMessage('Imported Successfully', commonConstants.responseType.success);
}).catch(() => {
this.setMessage('Error Importing Translations', commonConstants.responseType.error);
});
}

saveFormResource(formJson, formTranslations) {
saveFormResource(formJson, formTranslations, formNameTranslationsResource) {
const self = this;
self.setMessage('Importing Form...', commonConstants.responseType.success);
httpInterceptor.post(formBuilderConstants.bahmniFormResourceUrl, formJson)
Expand All @@ -127,7 +129,7 @@ export class FormBuilderContainer extends Component {
formTranslation.version = form.form.version || translation.version;
return formTranslation;
});
self.saveTranslations(updatedTranslations);
self.saveTranslations(updatedTranslations, formNameTranslationsResource);
})
.catch(() => {
this.setMessage('Error Importing Form', commonConstants.responseType.error);
Expand All @@ -143,12 +145,13 @@ export class FormBuilderContainer extends Component {
/>
<FormBuilder
data={this.state.data}
dispatch={this.props.dispatch}
match={this.props.match}
onValidationError={(messages) => this.onValidationError(messages)}
routes={this.props.routes}
saveForm={(formName) => this.saveForm(formName)}
saveFormResource={(formJson, translations) =>
this.saveFormResource(formJson, translations)}
saveFormResource={(formJson, translations, nameTranslations) =>
this.saveFormResource(formJson, translations, nameTranslations)}
/>
</div>
);
Expand Down
51 changes: 51 additions & 0 deletions src/form-builder/components/FormConditionsContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { setChangedProperty } from '../actions/control';

export class FormConditionsContainer extends Component {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where are you using this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.Forgot to delete.Deleted Now


constructor(props) {
super(props);
this.state = { events: {} };
}

componentWillUpdate(newProps) {
const updatedEvents = newProps.formDetails && newProps.formDetails.events;
if (updatedEvents && this.state.events !== updatedEvents) {
this.setState({ events: updatedEvents });
this.props.updateFormEvents(updatedEvents);
}
}

updateProperty() {
const properties = { [this.props.eventProperty]: true, formTitle: this.props.formTitle };
this.props.dispatch(setChangedProperty(properties));
}

render() {
return (
<div className="form-controls-container">
<label>{this.props.label}</label>
<button onClick={() => this.updateProperty()}>
<i aria-hidden="true" className="fa fa-code" />
</button>
</div>
);
}
}

FormConditionsContainer.propTypes = {
dispatch: PropTypes.func,
eventProperty: PropTypes.string,
formDetails: PropTypes.object,
formTitle: PropTypes.string,
label: PropTypes.string,
updateFormEvents: PropTypes.func,
};

const mapStateToProps = (state) => ({
formDetails: state.formDetails,
});

export default connect(mapStateToProps)(FormConditionsContainer);
125 changes: 125 additions & 0 deletions src/form-builder/components/FormConditionsModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { JSHINT } from 'jshint';
import ObsControlScriptEditorModal from 'form-builder/components/ObsControlScriptEditorModal';

window.JSHINT = JSHINT;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this required here? ObsControlScriptEditorModal has it already?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not required. removed here


export default class FormConditionsModal extends Component {
constructor(props) {
super(props);
this.state = { selectedControlEventTitleId: undefined,
selectedControlEventTitleName: undefined, selectedControlScript: undefined };
this.selectedControlOption = undefined;
this.prevSelectedControlOption = undefined;
this.selectedControlTitleId = undefined;
this.selectedControlTitleName = undefined;
this.selectedControlScript = undefined;
this.updateSelectedOption = this.updateSelectedOption.bind(this);
}

updateSelectedOption(element) {
this.prevSelectedControlOption = this.selectedControlOption;
this.selectedControlOption = element.target.value;
const selectedControlEventObj = this.props.controlEvents.find(control =>
control.id === this.selectedControlOption);
const selectedControlScriptObj = selectedControlEventObj ?
selectedControlEventObj.events : undefined;
this.selectedControlTitleId = selectedControlEventObj ? selectedControlEventObj.id : undefined;
this.selectedControlTitleName = selectedControlEventObj ? selectedControlEventObj.name :
undefined;
this.selectedControlScript = selectedControlScriptObj ?
selectedControlScriptObj.onValueChange : undefined;
if (this.selectedControlOption !== this.prevSelectedControlOption) {
this.setState({ selectedControlEventTitleId: this.selectedControlTitleId });
this.setState({ selectedControlEventTitleName: this.selectedControlTitleName });
this.setState({ selectedControlScript: this.selectedControlScript });
}
}

showObsControlScriptEditorModal(controlScript, controlEventTitleId, controlEventTitleName) {
if (controlEventTitleId !== undefined) {
return (<ObsControlScriptEditorModal
close={this.props.close}
script={controlScript}
titleId={controlEventTitleId}
titleName={controlEventTitleName}
updateScript={this.props.updateScript}
/>
);
}
return null;
}
render() {
const obs = this.props.controlEvents !== undefined ? this.props.controlEvents : [];
const ObsWithControlEvents = obs.filter(o => o.events !== undefined);
const obsWithoutControlEvents = obs.filter(o => o.events === undefined);
const formDetailEvents = this.props.formDetails.events ? this.props.formDetails.events
: { onFormInit: undefined, onFormSave: undefined };
return (
<div className="form-conditions-modal-container">
<h2 className="header-title">{this.props.formTitle} - Form Conditions</h2>

<div className="left-panel" >
<br />
{ this.showObsControlScriptEditorModal(formDetailEvents.onFormInit, null,
'Form Event')}
<br />
{ this.showObsControlScriptEditorModal(formDetailEvents.onFormSave, null,
'Save Event')}
<br />
</div>
<div className="right-panel" >
<br />
<div>
<label className="label" >Control Events:</label>
<select className="obs-dropdown" onChange={this.updateSelectedOption}>
<option key="0" value="0" >Select Option</option>)
{obsWithoutControlEvents.map((e) =>
<option key={e.id} value={e.id} >{e.name}</option>)}
</select>
</div>
<span className="line-break-3"></span>
<div>
{
ObsWithControlEvents.map((e) =>
this.showObsControlScriptEditorModal(e.events.onValueChange, e.id, e.name)
)
}
</div>
{
<div> {this.showObsControlScriptEditorModal(this.state.selectedControlScript,
this.state.selectedControlEventTitleId, this.state.selectedControlEventTitleName)}
<span className="line-break-2"></span>
</div>
}
</div>

<div className="button-wrapper" >
<button className="btn" onClick={() => this.props.close()} type="reset">
Cancel
</button>
</div>

</div>
);
}
}

FormConditionsModal.propTypes = {
close: PropTypes.func.isRequired,
controlEvents: PropTypes.array,
formDetails: PropTypes.shape({
events: PropTypes.object,
}),
formTitle: PropTypes.string,
selectedControlEventTitleId: PropTypes.string,
selectedControlEventTitleName: PropTypes.string,
selectedControlScript: PropTypes.string,
updateScript: PropTypes.func.isRequired,
};

FormConditionsModal.defaultProps = {
formDetails: { events: {} },
};

Loading