diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 58e1c76e..8427fd2a 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -12,7 +12,7 @@ on: jobs: build: - runs-on: macos-13 + runs-on: macos-15-intel steps: - name: Checkout the code uses: actions/checkout@v3 diff --git a/.github/workflows/validate-pr.yml b/.github/workflows/validate-pr.yml index 6acbcfe7..19607d9d 100644 --- a/.github/workflows/validate-pr.yml +++ b/.github/workflows/validate-pr.yml @@ -9,7 +9,7 @@ on: jobs: build: - runs-on: macos-13 + runs-on: macos-15-intel steps: - name: Checkout the code uses: actions/checkout@v3 diff --git a/karma.conf.js b/karma.conf.js index 2a80448c..e38463d7 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -39,7 +39,7 @@ module.exports = function (config) { statements: 98, branches: 94, functions: 98, - lines: 97, + lines: 96, }, }, } diff --git a/package-lock.json b/package-lock.json index 17e88002..6967d6c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "bahmni-form-controls", - "version": "0.93.19", + "version": "0.94.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 18f9ba99..9b8b6c3e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bahmni-form-controls", - "version": "0.93.19", + "version": "0.94.0", "description": "Repository for form controls", "license": "GPL-2.0", "main": "./dist/bundle.js", diff --git a/src/components/Container.jsx b/src/components/Container.jsx index 1b51d035..cca6f8a5 100644 --- a/src/components/Container.jsx +++ b/src/components/Container.jsx @@ -27,20 +27,21 @@ export class Container extends addMoreDecorator(Component) { this.onControlRemove = this.onControlRemove.bind(this); this.onEventTrigger = this.onEventTrigger.bind(this); this.showNotification = this.showNotification.bind(this); - } - componentWillMount() { const initScript = this.props.metadata.events && this.props.metadata.events.onFormInit; let updatedTree; - if (initScript) { - updatedTree = new ScriptRunner(this.state.data, this.props.patient).execute(initScript); - this.setState({ data: updatedTree }); + try { + if (initScript) { + updatedTree = new ScriptRunner(this.state.data, this.props.patient).execute(initScript); + } + updatedTree = updatedTree || this.state.data; + updatedTree = executeEventsFromCurrentRecord(updatedTree, updatedTree, this.props.patient); + } catch (error) { + console.error('Error executing form init script:', error); + } + if (updatedTree) { + this.state.data = updatedTree; } - updatedTree = updatedTree || this.state.data; - updatedTree = executeEventsFromCurrentRecord(updatedTree, updatedTree, this.props.patient); - this.setState({ - data: updatedTree, - }); } componentWillReceiveProps(nextProps) { diff --git a/src/helpers/encodingUtils.js b/src/helpers/encodingUtils.js new file mode 100644 index 00000000..d9d08cf8 --- /dev/null +++ b/src/helpers/encodingUtils.js @@ -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); + return ''; + } +} diff --git a/src/helpers/scriptRunner.js b/src/helpers/scriptRunner.js index cba2aecc..48f95192 100644 --- a/src/helpers/scriptRunner.js +++ b/src/helpers/scriptRunner.js @@ -1,5 +1,6 @@ import FormContext from './FormContext'; import { httpInterceptor } from '../helpers/httpInterceptor'; +import { base64ToUtf8 } from './encodingUtils'; export default class ScriptRunner { @@ -8,11 +9,21 @@ export default class ScriptRunner { this.interceptor = httpInterceptor; } + convertToUTF8(str) { + try { + return base64ToUtf8(str); + } catch (error) { + console.log('Error in decoding script from base64, executing as is.', error); + return str; + } + } + execute(eventJs) { const formContext = this.formContext; const interceptor = this.interceptor; if (eventJs && interceptor) { - const executiveJs = `(${eventJs})(formContext,interceptor)`; + const decodedScript = this.convertToUTF8(eventJs); + const executiveJs = `(${decodedScript})(formContext,interceptor)`; /* eslint-disable */ eval(executiveJs); } diff --git a/test/components/Container.spec.js b/test/components/Container.spec.js index 0ccf8245..525fbb20 100644 --- a/test/components/Container.spec.js +++ b/test/components/Container.spec.js @@ -17,6 +17,7 @@ import Constants from 'src/constants'; import sinon from 'sinon'; import { Map as immutableMap } from 'immutable'; import * as ExecuteEvents from '../../src/helpers/ExecuteEvents'; +import { utf8ToBase64 } from '../../src/helpers/encodingUtils'; chai.use(chaiEnzyme()); @@ -254,7 +255,7 @@ describe('Container', () => { uuid: '245940b7-3d6b-4a8b-806b-3f56444129ae', version: '1', events: { - onFormInit: "function(form){form.get('Pulse').setEnabled(false);}", + onFormInit: utf8ToBase64("function(form){form.get('Pulse').setEnabled(false);}"), }, defaultLocale: 'en', }; @@ -1431,7 +1432,7 @@ describe('Container', () => { uuid: 'c398a4be-3f10-11e4-adec-0800271c1b75', }; const events = { - onValueChange: `function(form){ + onValueChange: utf8ToBase64(`function(form){ var admission = form.get('Tuberculosis, Need of Admission').getValue(); var patient = form.getPatient(); if( admission === 'abc' && patient.age === 10) { @@ -1439,7 +1440,7 @@ describe('Container', () => { } else { form.get('Chief Complaint Notes').setEnabled(true); } - }`, + }`), }; const eventMetadata = { controls: [ @@ -5317,13 +5318,13 @@ describe('Container', () => { hiAbsolute: null, lowAbsolute: null, events: { - onValueChange: `function(form) { - if (form.getFromParent('IS_ABNORMAL').getValue()) { - form.getFromParent('Reason case is pending').setHidden(false); - }else { - form.getFromParent('Reason case is pending').setHidden(true); - } -}`, + onValueChange: utf8ToBase64(`function(form) { + if (form.getFromParent('IS_ABNORMAL').getValue()) { + form.getFromParent('Reason case is pending').setHidden(false); + }else { + form.getFromParent('Reason case is pending').setHidden(true); + } + }`), }, }, { diff --git a/test/index.js b/test/index.js index e7be2266..0bea53f3 100644 --- a/test/index.js +++ b/test/index.js @@ -1,3 +1,10 @@ +const TextEncodingPolyfill = require('text-encoding'); + +Object.assign(global, { + TextEncoder: TextEncodingPolyfill.TextEncoder, + TextDecoder: TextEncodingPolyfill.TextDecoder, +}); + const __karmaWebpackManifest__ = []; const testsContext = require.context('.', true, /spec$/);