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

feat: plugin changes for global shell #1373

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ export function usePingQuery(): () => Promise<any> {

// This endpoint doesn't need any extra headers or handling since it's
// public. It doesn't extend the user session. See DHIS2-14531
const ping = useCallback(() => fetch(baseUrl + '/api/ping'), [baseUrl])
const ping = useCallback(
() => fetch(new URL('./api/ping', baseUrl).href),
[baseUrl]
)

return ping
}
130 changes: 78 additions & 52 deletions services/plugin/src/Plugin.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { AlertsManagerContext } from '@dhis2/app-service-alerts'
import { useDataQuery } from '@dhis2/app-service-data'
import postRobot from 'post-robot'
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'
import React, {
ReactEventHandler,
useCallback,
useContext,
useEffect,
useMemo,
useRef,
useState,
} from 'react'
import PluginError from './PluginError'

const appsInfoQuery = {
Expand All @@ -27,10 +35,12 @@ const getPluginEntryPoint = ({
export const Plugin = ({
pluginSource,
pluginShortName,
onLoad,
...propsToPassNonMemoized
}: {
pluginSource?: string
pluginShortName?: string
onLoad?: ReactEventHandler<HTMLIFrameElement>
propsToPass: any
}): JSX.Element => {
const iframeRef = useRef<HTMLIFrameElement>(null)
Expand All @@ -54,14 +64,9 @@ export const Plugin = ({
appShortName: pluginShortName,
})

const [communicationReceived, setCommunicationReceived] =
useState<boolean>(false)
const [prevCommunicationReceived, setPrevCommunicationReceived] =
useState<boolean>(false)

const [inErrorState, setInErrorState] = useState<boolean>(false)
const [pluginHeight, setPluginHeight] = useState<number>(150)
const [pluginWidth, setPluginWidth] = useState<number>(500)
const [pluginHeight, setPluginHeight] = useState<string | number>('150px')
const [pluginWidth, setPluginWidth] = useState<string | number>('500px')

useEffect(() => {
if (height) {
Expand All @@ -84,63 +89,83 @@ export const Plugin = ({
/* eslint-enable react-hooks/exhaustive-deps */
)

useEffect(() => {
setCommunicationReceived(false)
}, [pluginEntryPoint])
const propsFromParentListenerRef = useRef<any>()
const communicationReceivedRef = useRef<boolean>(false)

useEffect(() => {
// if communicationReceived switches from false to true, the props have been sent
const prevCommunication = prevCommunicationReceived
setPrevCommunicationReceived(communicationReceived)
if (prevCommunication === false && communicationReceived === true) {
const setUpCommunication = useCallback(() => {
if (!iframeRef.current) {
return
}

if (iframeRef?.current) {
const iframeProps = {
...memoizedPropsToPass,
alertsAdd,
setPluginHeight,
setPluginWidth,
setInErrorState,
setCommunicationReceived,
}
const iframeProps = {
...memoizedPropsToPass,
alertsAdd,
setPluginHeight,
setPluginWidth,
setInErrorState,
// todo: what does this do? resets state from error component
// seems to work without...
// setCommunicationReceived,
}

// if iframe has not sent initial request, set up a listener
if (!communicationReceived && !inErrorState) {
const listener = postRobot.on(
// if iframe has not sent initial request, set up a listener
if (!communicationReceivedRef.current && !inErrorState) {
// avoid setting up twice
if (!propsFromParentListenerRef.current) {
propsFromParentListenerRef.current = postRobot.on(
'getPropsFromParent',
// listen for messages coming only from the iframe rendered by this component
{ window: iframeRef.current.contentWindow },
(): any => {
setCommunicationReceived(true)
communicationReceivedRef.current = true
return iframeProps
}
)
return () => listener.cancel()
}

// if iframe has sent initial request, send new props
if (
communicationReceived &&
iframeRef.current.contentWindow &&
!inErrorState
) {
postRobot
.send(
iframeRef.current.contentWindow,
'updated',
iframeProps
)
.catch((err) => {
// log postRobot errors, but do not bubble them up
console.error(err)
})
// return clean-up function
return () => {
propsFromParentListenerRef.current.cancel()
propsFromParentListenerRef.current = null
}
}
// prevCommunicationReceived update should not retrigger this hook
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [memoizedPropsToPass, communicationReceived, inErrorState, alertsAdd])

// if iframe has sent initial request, send new props
// (don't do before to avoid sending messages before listeners
// are ready)
if (iframeRef.current.contentWindow && !inErrorState) {
postRobot
.send(iframeRef.current.contentWindow, 'updated', iframeProps)
.catch((err) => {
// log postRobot errors, but do not bubble them up
console.error(err)
})
}
}, [memoizedPropsToPass, inErrorState, alertsAdd])

useEffect(() => {
// return the clean-up function
return setUpCommunication()
}, [setUpCommunication])

const handleLoad = useCallback(
(event) => {
// reset communication received
communicationReceivedRef.current = false
if (propsFromParentListenerRef.current) {
propsFromParentListenerRef.current.cancel()
propsFromParentListenerRef.current = null
}

// Need to set this up again whenever the iframe contentWindow
// changes (e.g. navigations or reloads)
setUpCommunication()

if (onLoad) {
onLoad(event)
}
},
[onLoad, setUpCommunication]
)

if (data && !pluginEntryPoint) {
return (
Expand All @@ -155,8 +180,8 @@ export const Plugin = ({
return (
<div
style={{
height: `${pluginHeight}px`,
width: `${pluginWidth}px`,
height: `${pluginHeight}`,
width: `${pluginWidth}`,
}}
>
<iframe
Expand All @@ -167,6 +192,7 @@ export const Plugin = ({
height: '100%',
border: 'none',
}}
onLoad={handleLoad}
></iframe>
</div>
)
Expand Down
34 changes: 0 additions & 34 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2734,40 +2734,6 @@
"@dhis2/pwa" "10.2.0"
moment "^2.24.0"

"@dhis2/app-runtime@^3.6.1":
version "3.9.0"
resolved "https://registry.yarnpkg.com/@dhis2/app-runtime/-/app-runtime-3.9.0.tgz#c7e295fd0a68fac976a930bc77105206ded0b61a"
integrity sha512-n0S4pbyvK7FnBQFMONGrhR9YYavBQI+mQLHfCX/vtvOyeoioBUNIinuQlGysuLMEkSVaK5OjV40rvTMzdxF2kQ==
dependencies:
"@dhis2/app-service-alerts" "3.9.0"
"@dhis2/app-service-config" "3.9.0"
"@dhis2/app-service-data" "3.9.0"
"@dhis2/app-service-offline" "3.9.0"

"@dhis2/app-service-alerts@3.9.0":
version "3.9.0"
resolved "https://registry.yarnpkg.com/@dhis2/app-service-alerts/-/app-service-alerts-3.9.0.tgz#48d3805676e75ee58104fea4f76cfa779335444e"
integrity sha512-z2eZxm/pxrmFbisbK7/qJKtif2CNWJjaaAH5rfrs5OIajlHy3rO37vSaTQHWv+xWvZFQrs2Op2InxzG0qh5ncA==

"@dhis2/app-service-config@3.9.0":
version "3.9.0"
resolved "https://registry.yarnpkg.com/@dhis2/app-service-config/-/app-service-config-3.9.0.tgz#8dc59d8de246f54057c0c685d5f94b4cbade6f73"
integrity sha512-OuRn2mJGrQQ8QIC+oIVYYpclB4LErRK2wtsuy/cXLfRbeUti1qWIh110rgd1hnTx+BgRCs5s3NWdIQxS4hYGIQ==

"@dhis2/app-service-data@3.9.0":
version "3.9.0"
resolved "https://registry.yarnpkg.com/@dhis2/app-service-data/-/app-service-data-3.9.0.tgz#37f528b5f7f589cbab8dcc7f997c1668bc6566a9"
integrity sha512-/FJgJhL6YGtIVNX5oaNmavkGmimrVHQsS8ueeUO4FvTjYXGlnnN3IuxypQcy/x4yiUyigbPgFJRnbC1J2af2fg==
dependencies:
react-query "^3.13.11"

"@dhis2/app-service-offline@3.9.0":
version "3.9.0"
resolved "https://registry.yarnpkg.com/@dhis2/app-service-offline/-/app-service-offline-3.9.0.tgz#fe4f4a91a1da77554965f6a5fe6f6951d4c467f4"
integrity sha512-0q5zl0vw+a47Ab2qgu6hsZY5ybnH/ea43Vkk4aXYdgcf57xB8ck9DkIcNbc2e1+k9FhvimipxsgTZSbEA/8hJA==
dependencies:
lodash "^4.17.21"

"@dhis2/app-shell@10.2.0":
version "10.2.0"
resolved "https://registry.yarnpkg.com/@dhis2/app-shell/-/app-shell-10.2.0.tgz#2f69aa047dedb6545c75052d8969a80502f0d4a6"
Expand Down
Loading