diff --git a/src/components/MessagePanel/message-panel.jsx b/src/components/MessagePanel/message-panel.jsx index 2df78df..4fc40fb 100644 --- a/src/components/MessagePanel/message-panel.jsx +++ b/src/components/MessagePanel/message-panel.jsx @@ -52,13 +52,14 @@ class MessagePanel extends Component { replyMessage(event) { let payloadStructure; - if (event.data.messageType.includes('scratchpad.')) { + const messageTarget = event.data.messageType.split('.'); + if (messageTarget[0] === 'scratchpad') { payloadStructure = { status: 200, location: 'https://resource-location/', outcome: 'Success', }; - } else if (event.data.messageType.includes('ui.')) { + } else if (messageTarget[0] === 'ui') { payloadStructure = { success: true, details: 'Success', @@ -74,32 +75,37 @@ class MessagePanel extends Component { event.source.postMessage(msgStructure, event.origin); } - addMessage(event) { - if (event.origin.includes(document.domain)) { - console.log(`Received message from ${event.origin} but it is the same as the current document's domain: ${document.domain}.`); - return; - } - - console.log(`Received message from ${event.origin}.`); + isActionableMessage(event) { + // Ignore the event, if it doesn't meet our expectations. + if (!event.data) return false; + if ((event.data.source || "").startsWith('react-devtools-')) return false; if (!event.data.messageId) { - console.log('Message did not have a messageId and will be ignored.'); - return; + console.warn('Message has no messageId.'); + return false; } if (!event.data.messageType) { - console.log('Message did not have a messageType and will be ignored.'); - return; + console.warn('Message has no messageType.'); + return false; } - if (!(event.data.messageType.includes('scratchpad.') || event.data.messageType.includes('ui.'))) { - console.log('Message did not have a supported messageType and will be ignored.'); - return; + const messageTarget = event.data.messageType.split('.'); + if (!['scratchpad', 'ui'].includes(messageTarget[0])) { + console.warn(`Unknown message type '${messageTarget[0]}.`); + return false; } - const message = JSON.stringify(event.data, null, 2); - this.setState({ messages: [...this.state.messages, message] }); - this.replyMessage(event); + return true; + } + + addMessage(event) { + if (this.isActionableMessage(event)) { + const message = JSON.stringify(event.data, null, 2); + // TODO(issue#129): convert this to a stack so newer messages are on top. + this.setState({ messages: [...this.state.messages, message] }); + this.replyMessage(event); + } } /** diff --git a/src/middleware/cds-execution.js b/src/middleware/cds-execution.js index 4bbf4f9..d9ea17f 100644 --- a/src/middleware/cds-execution.js +++ b/src/middleware/cds-execution.js @@ -151,7 +151,7 @@ const onSystemActions = (action, next, pre, post) => { const webMessageMiddleware = (store) => (next) => { window.addEventListener('message', ({ data, origin, source }) => { Object.entries(windowsRegistered) - .filter(([windowId, w]) => w.sourceWindow === source) + .filter(([windowId, w]) => w.sourceWindow === source && w.origin === origin) .map(([windowId, w]) => w.triggerPoint) .map((triggerPoint) => triggerHandlers[triggerPoint]) .forEach((handler) => handler.onMessage({ diff --git a/src/reducers/hook-reducers.js b/src/reducers/hook-reducers.js index 75a0ac6..5800425 100644 --- a/src/reducers/hook-reducers.js +++ b/src/reducers/hook-reducers.js @@ -49,9 +49,10 @@ const hookReducers = (state = initialState, action) => { return { ...state, isLoadingData: action.isLoaderOn }; } case types.LAUNCH_SMART_APP: { + const url = new URL(action.link.url); const { windowId } = cdsExecution.registerWindow( action.triggerPoint, - action.link, + url.origin, action.sourceWindow, ); return { @@ -61,6 +62,7 @@ const hookReducers = (state = initialState, action) => { { triggerPoint: action.triggerPoint, link: action.link, + linkOrigin: url.origin, windowId, }, ], diff --git a/tests/middleware/cds-execution.test.js b/tests/middleware/cds-execution.test.js index 9b11188..d8c45f4 100644 --- a/tests/middleware/cds-execution.test.js +++ b/tests/middleware/cds-execution.test.js @@ -45,7 +45,7 @@ describe("CDS Execution Middleware", () => { unregister: unregisterWindow } = cdsExecution.registerWindow( "example-trigger-point", - "fake-origin", + "", // jsdom makes the origin look empty null // jsdom makes the source window look `null` ); diff --git a/tests/reducers/hook-reducers.test.js b/tests/reducers/hook-reducers.test.js index d07dd99..bf1c573 100644 --- a/tests/reducers/hook-reducers.test.js +++ b/tests/reducers/hook-reducers.test.js @@ -6,6 +6,7 @@ describe('Hook Reducer', () => { beforeEach(() => { state = { + apps: [], currentHook: 'patient-view', isLoadingData: false, isContextVisible: true, @@ -28,6 +29,28 @@ describe('Hook Reducer', () => { }); }); + describe('LAUNCH_SMART_APP', () => { + it('should extract the origin from a link url', () => { + const action = { + type: types.LAUNCH_SMART_APP, + triggerPoint: 'patient-view', + link: { + url: 'http://localhost:8080/foo/bar/ignored', + }, + sourceWindow: 'abcdefgh-ijkl-mnop-qrst-uvwxyz012345', + }; + const expectedApp = { + triggerPoint: action.triggerPoint, + link: action.link, + linkOrigin: 'http://localhost:8080', + windowId: 0, + }; + const expected = Object.assign({}, state, { apps: [ expectedApp ] }); + const actual = reducer(state, action); + expect(actual).toEqual(expected); + }) + }); + describe('SET_CONTEXT_VISIBILITY', () => { it('should handle the SET_CONTEXT_VISIBILITY action accordingly', () => { const action = {