Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ module.exports = function (config) {
check: {
global: {
statements: 91.0,
branches: 89.0,
branches: 88.0,
functions: 91.0,
lines: 85.0,
},
Expand Down
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "implementer-interface",
"version": "1.1.1",
"version": "1.2.0",
"description": "App for implementer interfaces like form builder, reports, etc.",
"license": "GPL-2.0",
"main": "index.js",
Expand All @@ -11,7 +11,7 @@
"scripts": {
"preinstall": "node -e \"if(process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('You must use Yarn to install, not NPM')\"",
"clean": "rimraf dist/*",
"upgrade-form-control": "yarn upgrade bahmni-form-controls@0.93",
"upgrade-form-control": "yarn upgrade bahmni-form-controls@0.94.0",
"copy": "copyfiles -f ./index.html ./dist",
"build": "yarn run copy && webpack",
"build-dev": "yarn run copy && webpack --config webpack.dev.config.js",
Expand Down Expand Up @@ -81,11 +81,13 @@
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.9.0",
"babel-preset-react": "^6.11.1",
"bahmni-form-controls": "^0.93.17",
"bahmni-form-controls": "^0.94.0",
"classnames": "^2.2.5",
"codemirror": "^5.51.0",
"core-js": "^2.4.1",
"enzyme-adapter-react-16": "^1.15.2",
"file-saver": "^2.0.2",
"js-beautify": "^1.10.3",
"jshint": "^2.11.0",
"jsonpath": "^0.2.11",
"jszip": "^3.2.1",
Expand All @@ -98,11 +100,9 @@
"react-file-reader": "^1.0.2",
"react-redux": "^7.2.0",
"react-router-dom": "^4.3.1",
"reactjs-popup": "^1.5.0",
"redux": "^4.0.5",
"whatwg-fetch": "^1.0.0",
"js-beautify": "^1.10.3",
"enzyme-adapter-react-16": "^1.15.2",
"reactjs-popup": "^1.5.0"
"whatwg-fetch": "^1.0.0"
},
"resolutions": {
"**/**/lodash": "^4.17.12",
Expand Down
28 changes: 28 additions & 0 deletions src/common/utils/encodingUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export function utf8ToBase64(str) {
if (str === undefined || str === null || str === '') {
return '';
}
const encoder = new TextEncoder();
const data = encoder.encode(str);

const binaryString = String.fromCharCode.apply(null, data);
return btoa(binaryString);
}

export function base64ToUtf8(b64) {
if (b64 === undefined || b64 === null || b64 === '') {
return '';
}
try {
const binaryString = atob(b64);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
const decoder = new TextDecoder();
return decoder.decode(bytes);
} catch (e) {
console.error('Error decoding base64 string:', e);

Check warning on line 25 in src/common/utils/encodingUtils.js

View workflow job for this annotation

GitHub Actions / Build & Package

Unexpected console statement
return '';
}
}
2 changes: 2 additions & 0 deletions src/form-builder/actions/control.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@
export const formLoad = (controls) => ({ type: 'FORM_LOAD', controls });

export const deleteControl = (controlIds) => ({ type: 'DELETE_CONTROL', controlIds });

export const formDefVersionUpdate = (version) => ({ type: 'FORM_DEFINITION_VERSION_UPDATE', version });

Check warning on line 46 in src/form-builder/actions/control.js

View workflow job for this annotation

GitHub Actions / Build & Package

Line 46 exceeds the maximum line length of 100
13 changes: 12 additions & 1 deletion src/form-builder/components/FormConditionsModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import ObsControlScriptEditorModal from 'form-builder/components/ObsControlScrip
import _ from 'lodash';
import NotificationContainer from 'common/Notification';
import { commonConstants } from 'common/constants';
import { base64ToUtf8 } from 'common/utils/encodingUtils';

export default class FormConditionsModal extends Component {
constructor(props) {
Expand All @@ -15,6 +16,7 @@ export default class FormConditionsModal extends Component {
this.addToMap = this.addToMap.bind(this);
this.removeFromMap = this.removeFromMap.bind(this);
this.removeControlEvent = this.removeControlEvent.bind(this);
this.formDefVersion = props.formDefVersion || 1.0;
props.controlEvents.forEach(control => {
this[`${control.id}_ref`] = React.createRef();
});
Expand Down Expand Up @@ -92,14 +94,22 @@ export default class FormConditionsModal extends Component {
this.addToMap('controlsWithoutEvents', control);
}

decodeEventScript(controlScript) {
if (this.formDefVersion < 2.0) {
return controlScript;
}
return base64ToUtf8(controlScript);
}

showObsControlScriptEditorModal(controlScript, controlEventTitleId,
controlEventTitleName, editorRef, hasError) {
const eventScript = (controlEventTitleId == undefined && controlEventTitleName == undefined) ? '' : this.decodeEventScript(controlScript);
return (<ObsControlScriptEditorModal
close={this.props.close}
hasError={hasError}
key={`${controlEventTitleName}_${controlEventTitleId}`}
removeControlEvent={this.removeControlEvent}
script={controlScript}
script={eventScript}
textAreaRef={editorRef}
titleId={controlEventTitleId}
titleName={controlEventTitleName}
Expand Down Expand Up @@ -228,6 +238,7 @@ FormConditionsModal.propTypes = {
}),
formTitle: PropTypes.string,
updateAllScripts: PropTypes.func.isRequired,
formDefVersion: PropTypes.number,
};

FormConditionsModal.defaultProps = {
Expand Down
45 changes: 31 additions & 14 deletions src/form-builder/components/FormDetail.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Popup from 'reactjs-popup';
import FormConditionsModal from 'form-builder/components/FormConditionsModal';
import { commonConstants } from 'common/constants';
import NotificationContainer from 'common/Notification';
import { base64ToUtf8, utf8ToBase64 } from 'common/utils/encodingUtils';


export default class FormDetail extends Component {
Expand Down Expand Up @@ -83,27 +84,42 @@ export default class FormDetail extends Component {
throw e;
}
}

getScript(property, formDetails, controlEvents, selectedControlId, formDefinitionVersion) {
const definitionVersion = formDefinitionVersion || 1.0;
const isControlEvent = property.controlEvent;
if (isControlEvent) {
const selectedFormControlEvent = controlEvents
.find(control => control.id === selectedControlId);
const controlEventScript = selectedFormControlEvent && selectedFormControlEvent.events
&& selectedFormControlEvent.events.onValueChange;
if (controlEventScript == undefined) {
return '';
}
return definitionVersion > 1.0 ? base64ToUtf8(controlEventScript) : controlEventScript;
}
if (property.formSaveEvent === undefined && property.formInitEvent === undefined) {
return '';
}
const isSaveEvent = property.formSaveEvent;
const formEventScript = formDetails.events && (isSaveEvent ? formDetails.events.onFormSave
: formDetails.events.onFormInit);
if (formEventScript == undefined) {
return '';
}
return definitionVersion > 1.0 ? base64ToUtf8(formEventScript) : formEventScript;
}

render() {
const { formData, defaultLocale, formControlEvents } = this.props;
if (formData) {
const { name, uuid, id, version, published, editable } = this.props.formData;
const formResourceControls = FormHelper.getFormResourceControls(this.props.formData);
const formDefVersion = this.props.formDetails && this.props.formDetails.formDefVersion;
const idGenerator = this.getIdGenerator(formResourceControls);
const getScript = (property, formDetails, selectedControlId) => {
const isControlEvent = property.controlEvent;
if (isControlEvent) {
const selectedFormControlEvent = formControlEvents
.find(control => control.id === selectedControlId);
return selectedFormControlEvent && selectedFormControlEvent.events
&& selectedFormControlEvent.events.onValueChange;
}
const isSaveEvent = property.formSaveEvent;
return formDetails.events && (isSaveEvent ? formDetails.events.onFormSave
: formDetails.events.onFormInit);
};
const FormEventEditorContent = (props) => {
const script = props.property ? getScript(props.property,
props.formDetails, props.selectedControlId) : '';
const script = props.property ? this.getScript(props.property,
props.formDetails, formControlEvents, props.selectedControlId, formDefVersion) : '';
const showEditor = props.property && (props.property.formInitEvent
|| props.property.formSaveEvent || props.property.formConditionsEvent
|| props.property.controlEvent || props.property.formPrivilegesEventUpdate);
Expand All @@ -123,6 +139,7 @@ export default class FormDetail extends Component {
formDetails={props.formDetails}
formTitle={this.formTitle(name, version, published, editable)}
updateAllScripts={props.updateAllScripts}
formDefVersion={formDefVersion}
/>
</Popup>
}
Expand Down
9 changes: 8 additions & 1 deletion src/form-builder/components/FormDetailContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
removeSourceMap,
formLoad,
setChangedProperty,
formDefVersionUpdate,
} from 'form-builder/actions/control';
import NotificationContainer from 'common/Notification';
import Spinner from 'common/Spinner';
Expand Down Expand Up @@ -55,6 +56,7 @@ export class FormDetailContainer extends Component {
referenceFormUuid: undefined,
formPreviewJson: undefined,
formPrivileges: [],
formDefinitionVersion: undefined,
};
this.setState = this.setState.bind(this);
this.setErrorMessage = this.setErrorMessage.bind(this);
Expand All @@ -77,7 +79,7 @@ export class FormDetailContainer extends Component {

componentDidMount() {
const params =
'v=custom:(id,uuid,name,version,published,auditInfo,' +
'v=custom:(id,uuid,build,name,version,published,auditInfo,' +
'resources:(value,dataType,uuid))';
httpInterceptor
.get(
Expand All @@ -86,6 +88,7 @@ export class FormDetailContainer extends Component {
.then((data) => {
const parsedFormValue =
data.resources.length > 0 ? JSON.parse(data.resources[0].value) : {};
const formDefVersion = parsedFormValue.formDefVersion || 1.0;
this.setState({
formData: data,
httpReceived: true,
Expand All @@ -97,9 +100,11 @@ export class FormDetailContainer extends Component {
// eslint-disable-next-line eqeqeq
referenceFormUuid: data.version == 1 ?
data.uuid : parsedFormValue.referenceFormUuid,
formDefinitionVersion: formDefVersion,
});
this._getFormPrivilegesFromDB(data.id, data.version);
const formControlsArray = formHelper.getObsControlEvents(parsedFormValue);
this.props.dispatch(formDefVersionUpdate(formDefVersion));
this.props.dispatch(formLoad(formControlsArray));
})
.catch((error) => {
Expand Down Expand Up @@ -147,6 +152,8 @@ export class FormDetailContainer extends Component {
throw new Exception(emptySectionOrTable);
}
formJson.events = this.state.formEvents;
const formDefVersion = (this.props.formDetails && this.props.formDetails.formDefVersion) || this.state.formDefinitionVersion;
formJson.formDefVersion = formDefVersion;
const formName = this.state.formData ? this.state.formData.name : 'FormName';
const formUuid = this.state.formData ? this.state.formData.uuid : undefined;
const formResourceUuid = this.state.formData && this.state.formData.resources.length > 0 ?
Expand Down
33 changes: 27 additions & 6 deletions src/form-builder/components/FormEventEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ import {
formLoad,
saveEventUpdate,
sourceChangedProperty,
formDefVersionUpdate,
} from 'form-builder/actions/control';
import { setChangedProperty, formConditionsEventUpdate } from 'form-builder/actions/control';
import { formBuilderConstants } from 'form-builder/constants';
import { utf8ToBase64 } from 'common/utils/encodingUtils';
export const FormEventEditor = (props) => {
const { property, formDetails, formControlEvents,
updateAllScripts, selectedControlId } = props;
Expand Down Expand Up @@ -54,6 +57,23 @@ const mapStateToProps = (state) => ({
&& state.controlDetails.selectedControl.id,
});

function encodeControlScipts(controlScripts) {
if (!controlScripts) {
return [];
}
return controlScripts.map(control => {
if (control.events) {
const encodedEvents = {};
Object.keys(control.events).forEach(eventKey => {
encodedEvents[eventKey] = utf8ToBase64(control.events[eventKey]);
});
const _ctrl = Object.assign({}, control, { events: encodedEvents });
return _ctrl;
}
return control;
});
}

const mapDispatchToProps = (dispatch) => ({
closeEventEditor: (selectedControlId) => {
dispatch(setChangedProperty({ formInitEvent: false }));
Expand All @@ -63,20 +83,21 @@ const mapDispatchToProps = (dispatch) => ({
},
updateScript: (script, property, selectedControlId) => {
if (property.formSaveEvent) {
dispatch(saveEventUpdate(script));
dispatch(saveEventUpdate(utf8ToBase64(script)));
} else if (property.formInitEvent) {
dispatch(formEventUpdate(script));
dispatch(formEventUpdate(utf8ToBase64(script)));
} else if (property.formConditionsEvent) {
dispatch(formConditionsEventUpdate(script));
dispatch(formConditionsEventUpdate(utf8ToBase64(script)));
}
if (property.controlEvent) {
dispatch(sourceChangedProperty(script, selectedControlId));
}
},
updateAllScripts: ({ controlScripts, formSaveEventScript, formInitEventScript }) => {
dispatch(saveEventUpdate(formSaveEventScript));
dispatch(formEventUpdate(formInitEventScript));
dispatch(formLoad(controlScripts));
dispatch(saveEventUpdate(utf8ToBase64(formSaveEventScript)));
dispatch(formEventUpdate(utf8ToBase64(formInitEventScript)));
dispatch(formLoad(encodeControlScipts(controlScripts)));
dispatch(formDefVersionUpdate(formBuilderConstants.formDefinitionVersion));
},
});
export default connect(mapStateToProps, mapDispatchToProps)(FormEventEditor);
1 change: 1 addition & 0 deletions src/form-builder/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ export const formBuilderConstants = {
jsonToPdfConvertionUrl: '/openmrs/ws/rest/v1/bahmniie/form/jsonToPdf',
pdfDownloadUrl: '/openmrs/ws/rest/v1/bahmniie/form/download/',
dataLimit: 9999,
formDefinitionVersion: 2.0,
};
17 changes: 17 additions & 0 deletions src/form-builder/helpers/formHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,21 @@ export default class FormHelper {
}
return obsControlEvents;
}

static getFormDefinitionVersion(formData) {
if (formData) {
const { resources } = formData;
const formResources = filter(resources,
(resource) => resource.dataType === formBuilderConstants.formResourceDataType);
const valueAsString = get(formResources, ['0', 'value']);
if (valueAsString) {
const formDefVersion = JSON.parse(valueAsString).formDefVersion;
if (formDefVersion !== undefined) {
return formDefVersion;
}
}
}
return 1.0;
}

}
2 changes: 2 additions & 0 deletions src/form-builder/reducers/formDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const formDetails = (store = {}, action) => {
});
case 'SET_DEFAULT_LOCALE':
return Object.assign({}, store, { defaultLocale: action.locale });
case 'FORM_DEFINITION_VERSION_UPDATE':
return Object.assign({}, store, { formDefVersion: action.version });
default:
return store;
}
Expand Down
Loading
Loading