From c537590176b2e6aebf278653a87705b3417bcc38 Mon Sep 17 00:00:00 2001 From: Thomas Zemp Date: Fri, 24 Feb 2023 18:57:41 +0100 Subject: [PATCH] fix: add documentation, clean up --- docs/components/Plugin.md | 63 +++++++++++++++++++ runtime/src/index.ts | 2 +- .../src/{PluginSender.tsx => Plugin.tsx} | 2 +- services/plugin/src/index.ts | 2 +- yarn.lock | 44 ------------- 5 files changed, 66 insertions(+), 47 deletions(-) create mode 100644 docs/components/Plugin.md rename services/plugin/src/{PluginSender.tsx => Plugin.tsx} (99%) diff --git a/docs/components/Plugin.md b/docs/components/Plugin.md new file mode 100644 index 00000000..a4ee4dff --- /dev/null +++ b/docs/components/Plugin.md @@ -0,0 +1,63 @@ +# Plugin Component + +A wrapper that creates an iframe for a specified plugin and establishes a two-way communication channel with said plugin, allowing you to pass props (including callbacks between an app and a plugin). Note that the plugin must be built using the app-platform with entryPoints.plugin specified in the d2.config.js file. + +## Basic Usage (Defining a plugin within an app) + +Within an app you can specify a plugin (either by providing its short name `pluginShortName`, or by specifying a URL directly (`pluginSource`). If you have provided `pluginSource`, this will take precedence (Note: lookup logic is TBD? Should we allow a URL only in development mode, for example?). + +```jsx +import { Plugin } from '@dhis2/app-runtime' + +// within the app +const MyApp = () => ( + { + console.error(err) + }} + showAlertsInPlugin={true} + numberToPass={'42'} + callbackToPass={({ name }) => { + console.log(`Hi ${name}!`) + }} + /> +) +``` + +## Basic Usage (Using properties from the parent app) + +You must build your plugin with the app-platform. If you have done this, your entry component will be passed the props from the parent app. From the example above, the properties `numberToPass` and `callbackToPass` will be available in the build plugin (when it is rendered with a component). + +```jsx +// your plugin entry point (the plugin itself) + +const MyPlugin = (propsFromParent) => { + const { numberToPass, callbackToPass: sayHi } = propsFromParent + return ( + <> +

{`The meaning of life is: ${numberToPass}`}

+ + + ) +} +``` + +## Plugin Props (reserved props) + +| Name | Type | Required | Description | +| :--------------------: | :------------: | :---------------------------------------------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **pluginShortName** | _string_ | _required_ if `pluginSource` is not provided | The shortName of the app/plugin you wish to load (matching the result from api/apps). Used to look up the plugin entry point. If this is not provided, `pluginSource` must be provided. `pluginSource` will take precedence if provided. | +| **pluginSource** | _string_ (url) | _required_ if `pluginShortName` is not provided | The URL of the plugin. If this is not provided, `pluginShortName` must be provided. | +| **onError** | _Function_ | _optional_ | Callback function to be called when an error in the plugin triggers an error boundary. You can use this to pass an error back up to the app and create a custom handling/UX if errors occur in the plugin. In general, it is recommended that you use the plugin's built-in error boundaries | +| **showAlertsInPlugin** | _boolean_ | _optional_ | If `true`, any alerts within the plugin (defined with the `useAlert` hook) will be rendered within the iframe. By default, this is `false`. It is recommended, in general, that you do not override this and allow alerts to be hoisted up to the app level | + +## Plugin Props (custom props) + +You can specify pass any other props on the component and these will be passed down to the plugin (provided it was built with app-platform). When props are updated, they will be passed back down to the plugin. This mimics the behaviour of a normal React component, and hence you should provide stable references as needed to prevent rerendering. + +## Extended example + +See these links for an extended example of how component can be used within an [app](https://github.com/tomzemp/workingplugin/blob/plugin-wrapper-in-platform/src/App.js) and consumed within the [plugin](https://github.com/tomzemp/workingplugin/blob/plugin-wrapper-in-platform/src/Plugin.js). diff --git a/runtime/src/index.ts b/runtime/src/index.ts index 37607eb5..aa07c14c 100644 --- a/runtime/src/index.ts +++ b/runtime/src/index.ts @@ -22,6 +22,6 @@ export { clearSensitiveCaches, } from '@dhis2/app-service-offline' -export { PluginSender } from '@dhis2/app-service-plugin' +export { Plugin } from '@dhis2/app-service-plugin' export { Provider } from './Provider' diff --git a/services/plugin/src/PluginSender.tsx b/services/plugin/src/Plugin.tsx similarity index 99% rename from services/plugin/src/PluginSender.tsx rename to services/plugin/src/Plugin.tsx index a72663d2..3fb2f149 100644 --- a/services/plugin/src/PluginSender.tsx +++ b/services/plugin/src/Plugin.tsx @@ -24,7 +24,7 @@ const getPluginEntryPoint = ({ )?.pluginLaunchUrl } -export const PluginSender = ({ +export const Plugin = ({ pluginSource, pluginShortName, ...propsToPass diff --git a/services/plugin/src/index.ts b/services/plugin/src/index.ts index f6913966..2321646e 100644 --- a/services/plugin/src/index.ts +++ b/services/plugin/src/index.ts @@ -1 +1 @@ -export { PluginSender } from './PluginSender' +export { Plugin } from './Plugin' diff --git a/yarn.lock b/yarn.lock index a3b53d94..6d67514d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3810,15 +3810,6 @@ bcryptjs@^2.3.0: resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms= -belter@^1.0.41: - version "1.0.190" - resolved "https://registry.yarnpkg.com/belter/-/belter-1.0.190.tgz#491857550ef240d9c66b56fc637991f5c3089966" - integrity sha512-jz05FHrO+bwitdI6JxV5ESyRdVhTcwMWQ7L4o+q/R4LNJFQrG58sp9EiwsSjhbihhiyYFcmmCMRRagxte6igtw== - dependencies: - cross-domain-safe-weakmap "^1" - cross-domain-utils "^2" - zalgo-promise "^1" - bfj@^7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/bfj/-/bfj-7.0.2.tgz#1988ce76f3add9ac2913fd8ba47aad9e651bfbb2" @@ -5025,20 +5016,6 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-domain-safe-weakmap@^1, cross-domain-safe-weakmap@^1.0.1: - version "1.0.29" - resolved "https://registry.yarnpkg.com/cross-domain-safe-weakmap/-/cross-domain-safe-weakmap-1.0.29.tgz#0847975c27d9e1cc840f24c1745311958df98022" - integrity sha512-VLoUgf2SXnf3+na8NfeUFV59TRZkIJqCIATaMdbhccgtnTlSnHXkyTRwokngEGYdQXx8JbHT9GDYitgR2sdjuA== - dependencies: - cross-domain-utils "^2.0.0" - -cross-domain-utils@^2, cross-domain-utils@^2.0.0: - version "2.0.38" - resolved "https://registry.yarnpkg.com/cross-domain-utils/-/cross-domain-utils-2.0.38.tgz#2eaf321c4dfdb61596805ca4233fde4400cb6377" - integrity sha512-zZfi3+2EIR9l4chrEiXI2xFleyacsJf8YMLR1eJ0Veb5FTMXeJ3DpxDjZkto2FhL/g717WSELqbptNSo85UJDw== - dependencies: - zalgo-promise "^1.0.11" - cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -11531,17 +11508,6 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= -post-robot@^10.0.46: - version "10.0.46" - resolved "https://registry.yarnpkg.com/post-robot/-/post-robot-10.0.46.tgz#39cea5b51033729390fc7c90be3285cd285f0377" - integrity sha512-EgVJiuvI4iRWDZvzObWes0X/n8olWBEJWxlSw79zmhpgkigX8UsVL4VOBhVtoJKwf0Y9qP9g2zOONw1rv80QbA== - dependencies: - belter "^1.0.41" - cross-domain-safe-weakmap "^1.0.1" - cross-domain-utils "^2.0.0" - universal-serialize "^1.0.4" - zalgo-promise "^1.0.3" - postcss-attribute-case-insensitive@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz#d93e46b504589e94ac7277b0463226c68041a880" @@ -15125,11 +15091,6 @@ unique-string@^1.0.0: dependencies: crypto-random-string "^1.0.0" -universal-serialize@^1.0.4: - version "1.0.10" - resolved "https://registry.yarnpkg.com/universal-serialize/-/universal-serialize-1.0.10.tgz#3279bb30f47290ea479f45135620f98fa9d3f3a6" - integrity sha512-FdouA4xSFa0fudk1+z5vLWtxZCoC0Q9lKYV3uUdFl7DttNfolmiw2ASr5ddY+/Yz6Isr68u3IqC9XMSwMP+Pow== - universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -16109,11 +16070,6 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zalgo-promise@^1, zalgo-promise@^1.0.11, zalgo-promise@^1.0.3: - version "1.0.48" - resolved "https://registry.yarnpkg.com/zalgo-promise/-/zalgo-promise-1.0.48.tgz#9e33eef502d5ed9f5a09fc5728c833c3e87afa2e" - integrity sha512-LLHANmdm53+MucY9aOFIggzYtUdkSBFxUsy4glTTQYNyK6B3uCPWTbfiGvSrEvLojw0mSzyFJ1/RRLv+QMNdzQ== - zip-stream@^2.1.2: version "2.1.3" resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-2.1.3.tgz#26cc4bdb93641a8590dd07112e1f77af1758865b"