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: support new dashboard plugin architecture #3232

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
2131fe0
refactor: use shared dashboard plugin wrapper
edoardo Jun 3, 2024
0d776a5
chore: bump cli-app-scripts and app-runtime dependencies
edoardo Jun 3, 2024
dc26888
chore: use analytics build from d2-ci for testing
edoardo Jul 3, 2024
1a39155
chore: fix dependencies
edoardo Jul 11, 2024
7edef35
chore: run prettier
edoardo Jul 11, 2024
258354c
chore: use latest cli-app-scripts and app-runtime
edoardo Aug 2, 2024
56d3e52
chore: remove old webpack patch
edoardo Aug 7, 2024
2c9733f
chore: update patch for webpack
edoardo Aug 7, 2024
38ecc59
fix: indicate the plugin is for dashboard
edoardo Aug 13, 2024
c80a6ec
Merge remote-tracking branch 'origin/master' into refactor/use-platfo…
edoardo Aug 16, 2024
23591d2
fix: use uppercase for pluginType value
edoardo Aug 16, 2024
0eb0ab7
fix: disable translucent cover, remove unnecessary style
edoardo Aug 19, 2024
4fece4a
Merge remote-tracking branch 'origin/master' into refactor/use-platfo…
edoardo Aug 19, 2024
e904f3b
Merge remote-tracking branch 'origin/master' into refactor/use-platfo…
edoardo Oct 10, 2024
a3eb864
Merge remote-tracking branch 'origin/master' into refactor/use-platfo…
edoardo Oct 30, 2024
f38b20c
chore: use latest analytics build for testing
edoardo Oct 30, 2024
8e8f12b
Merge remote-tracking branch 'origin/master' into refactor/use-platfo…
edoardo Nov 11, 2024
381d4d2
chore: use latest analytics build for testing
edoardo Nov 15, 2024
3487a16
Merge remote-tracking branch 'origin/master' into refactor/use-platfo…
edoardo Nov 15, 2024
64147ae
refactor: remove unnecessary storing of props in local state
edoardo Nov 18, 2024
49fdcd5
Merge branch 'master' into refactor/use-platform-plugin-components
edoardo Nov 18, 2024
78ea2ac
Merge remote-tracking branch 'origin/master' into refactor/use-platfo…
edoardo Dec 4, 2024
5473c4c
Merge branch 'master' into refactor/use-platform-plugin-components
edoardo Dec 6, 2024
b5a8e35
Merge remote-tracking branch 'origin/master' into refactor/use-platfo…
edoardo Dec 11, 2024
1123096
chore: use latest analytics build for testing
edoardo Dec 11, 2024
f7a8eab
chore: update ui dependency
edoardo Dec 16, 2024
197fd7f
chore: use latest analytics build for testing
edoardo Dec 16, 2024
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
4 changes: 2 additions & 2 deletions d2.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const config = {

minDHIS2Version: '2.40',

pluginType: 'DASHBOARD',

pwa: {
enabled: true,
caching: {
Expand All @@ -21,8 +23,6 @@ const config = {

coreApp: true,
dataStoreNamespace: 'DHIS2_MAPS_APP_CORE',

skipPluginLogic: true,
}

module.exports = config
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"start-server-and-test": "^2.0.3"
},
"dependencies": {
"@dhis2/analytics": "^26.8.4",
"@dhis2/analytics": "git+https://github.com/d2-ci/analytics.git#13cd471cc31e0a113fb4323a104f7b4fa70b2353",
"@dhis2/app-runtime": "^3.11.2",
"@dhis2/app-runtime-adapter-d2": "^1.1.0",
"@dhis2/app-service-datastore": "^1.0.0-beta.3",
Expand Down
42 changes: 22 additions & 20 deletions patches/webpack+5.76.2.patch → patches/webpack+5.93.0.patch
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
diff --git a/node_modules/webpack/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js b/node_modules/webpack/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js
index b9947d6..31273c5 100644
index d290c42..a87b524 100644
--- a/node_modules/webpack/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js
+++ b/node_modules/webpack/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js
@@ -88,6 +88,19 @@ class ImportScriptsChunkLoadingRuntimeModule extends RuntimeModule {
? `${RuntimeGlobals.hmrRuntimeStatePrefix}_importScripts`
: undefined;
@@ -92,7 +92,20 @@ class ImportScriptsChunkLoadingRuntimeModule extends RuntimeModule {
const runtimeTemplate = compilation.runtimeTemplate;
const { _withCreateScriptUrl: withCreateScriptUrl } = this;

+ const outputName = this.compilation.getPath(
+ getChunkFilenameTemplate(chunk, this.compilation.outputOptions),
+ {
+ chunk,
+ contentHashType: "javascript"
+ }
+ );
+ const rootOutputDir = JSON.stringify(getUndoPath(
+ outputName,
+ this.compilation.outputOptions.path,
+ true
+ ));
- return Template.asString([
+ const outputName = compilation.getPath(
+ getChunkFilenameTemplate(chunk, compilation.outputOptions),
+ {
+ chunk,
+ contentHashType: "javascript"
+ }
+ );
+ const rootOutputDir = JSON.stringify(getUndoPath(
+ outputName,
+ compilation.outputOptions.path,
+ true
+ ));
+
return Template.asString([
+ return Template.asString([
withBaseURI ? this._generateBaseUri(chunk) : "// no baseURI",
"",
@@ -142,8 +155,8 @@ class ImportScriptsChunkLoadingRuntimeModule extends RuntimeModule {
"// object to store loaded chunks",
@@ -146,8 +159,8 @@ class ImportScriptsChunkLoadingRuntimeModule extends RuntimeModule {
Template.indent(
`importScripts(${
withCreateScriptUrl
Expand All @@ -33,7 +35,7 @@ index b9947d6..31273c5 100644
});`
),
"}"
@@ -183,8 +196,8 @@ class ImportScriptsChunkLoadingRuntimeModule extends RuntimeModule {
@@ -187,8 +200,8 @@ class ImportScriptsChunkLoadingRuntimeModule extends RuntimeModule {
"// start update chunk loading",
`importScripts(${
withCreateScriptUrl
Expand All @@ -44,7 +46,7 @@ index b9947d6..31273c5 100644
});`,
'if(!success) throw new Error("Loading update chunk failed for unknown reason");'
]),
@@ -221,7 +234,7 @@ class ImportScriptsChunkLoadingRuntimeModule extends RuntimeModule {
@@ -225,7 +238,7 @@ class ImportScriptsChunkLoadingRuntimeModule extends RuntimeModule {
RuntimeGlobals.hmrDownloadManifest
} = ${runtimeTemplate.basicFunction("", [
'if (typeof fetch === "undefined") throw new Error("No browser support: need fetch API");',
Expand Down
123 changes: 10 additions & 113 deletions src/PluginWrapper.js
Original file line number Diff line number Diff line change
@@ -1,105 +1,14 @@
import { useCacheableSection, CacheableSection } from '@dhis2/app-runtime'
import { CenteredContent, CircularLoader, Layer } from '@dhis2/ui'
import postRobot from '@krakenjs/post-robot'
import { DashboardPluginWrapper } from '@dhis2/analytics'
import { debounce } from 'lodash/fp'
import PropTypes from 'prop-types'
import React, { useEffect, useLayoutEffect, useState } from 'react'
import { Plugin } from './components/plugin/Plugin.js'
import { getPWAInstallationStatus } from './util/getPWAInstallationStatus.js'
import './locales/index.js'

const LoadingMask = () => {
return (
<Layer>
<CenteredContent>
<CircularLoader />
</CenteredContent>
</Layer>
)
}

const CacheableSectionWrapper = ({
id,
children,
cacheNow,
isParentCached,
}) => {
const { startRecording, isCached, remove } = useCacheableSection(id)

useEffect(() => {
if (cacheNow) {
startRecording({ onError: console.error })
}

// NB: Adding `startRecording` to dependencies causes
// an infinite recording loop as-is (probably need to memoize it)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [cacheNow])

useEffect(() => {
const listener = postRobot.on(
'removeCachedData',
// todo: check domain too; differs based on deployment env though
{ window: window.parent },
() => remove()
)

return () => listener.cancel()
}, [remove])

useEffect(() => {
// Synchronize cache state on load or prop update
// -- a back-up to imperative `removeCachedData`
if (!isParentCached && isCached) {
remove()
}

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isParentCached])

return (
<CacheableSection id={id} loadingMask={LoadingMask}>
{children}
</CacheableSection>
)
}
CacheableSectionWrapper.propTypes = {
cacheNow: PropTypes.bool,
children: PropTypes.node,
id: PropTypes.string,
isParentCached: PropTypes.bool,
}

const sendInstallationStatus = (installationStatus) => {
postRobot.send(window.parent, 'installationStatus', { installationStatus })
}

const PluginWrapper = () => {
const [propsFromParent, setPropsFromParent] = useState()
const PluginWrapper = (props) => {
const [propsFromParent, setPropsFromParent] = useState(props)
const [renderId, setRenderId] = useState(null)

const receivePropsFromParent = (event) => setPropsFromParent(event.data)

useEffect(() => {
postRobot
.send(window.parent, 'getProps')
.then(receivePropsFromParent)
.catch((err) => console.error(err))

// Get & send PWA installation status now, and also prepare to send
// future updates (installing/ready)
getPWAInstallationStatus({
onStateChange: sendInstallationStatus,
}).then(sendInstallationStatus)

// Allow parent to update props
const listener = postRobot.on(
'newProps',
{ window: window.parent /* Todo: check domain */ },
receivePropsFromParent
)

return () => listener.cancel()
}, [])
useEffect(() => setPropsFromParent(props), [props])

useLayoutEffect(() => {
const updateRenderId = debounce(300, () =>
Expand All @@ -113,23 +22,11 @@ const PluginWrapper = () => {
return () => window.removeEventListener('resize', updateRenderId)
}, [])

return propsFromParent ? (
<div
style={{
display: 'flex',
height: '100%',
overflow: 'hidden',
}}
>
<CacheableSectionWrapper
id={propsFromParent.cacheId}
cacheNow={propsFromParent.recordOnNextLoad}
isParentCached={propsFromParent.isParentCached}
>
<Plugin id={renderId} {...propsFromParent} />
</CacheableSectionWrapper>
</div>
) : null
return (
<DashboardPluginWrapper {...propsFromParent}>
{(props) => <Plugin id={renderId} {...props} />}
</DashboardPluginWrapper>
)
}

export default PluginWrapper
6 changes: 3 additions & 3 deletions src/components/app/styles/App.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
}

/* Avoid vertical layer dialog scroll on small screens */
:global(#dhis2-portal-root) aside[role=dialog],
:global(#dhis2-portal-root) aside[role=dialog] > div > div {
max-height: calc(100vh - 64px)
:global(#dhis2-portal-root) aside[role='dialog'],
:global(#dhis2-portal-root) aside[role='dialog'] > div > div {
max-height: calc(100vh - 64px);
}

/* Scrollbar width */
Expand Down
2 changes: 1 addition & 1 deletion src/components/core/LabelDisplayOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
LABEL_TEMPLATE_NAME_AND_VALUE,
LABEL_TEMPLATE_VALUE_ONLY,
} from '../../constants/layers.js'
import { SelectField } from '.'
import SelectField from './SelectField.js'

const getLabelDisplayOptions = () => [
{
Expand Down
2 changes: 1 addition & 1 deletion src/components/core/styles/Checkbox.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
/* This styles the tooltip span containing the svg */
.checkbox span {
margin-left: var(--spacers-dp4);
display:flex;
display: flex;
flex-direction: column;
}
2 changes: 1 addition & 1 deletion src/components/core/styles/IconButton.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
.iconButton.disabled svg {
fill: var(--colors-grey400);
cursor: not-allowed;
color: var(--colors-grey400)
color: var(--colors-grey400);
}

.iconButton:not(.disabled):hover {
Expand Down
2 changes: 1 addition & 1 deletion src/components/datatable/styles/BottomPanel.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
}

.closeIcon svg {
position:absolute;
position: absolute;
top: 50%;
left: 50%;
margin: -8px 0 0 -8px;
Expand Down
2 changes: 1 addition & 1 deletion src/components/download/styles/DownloadMapInfo.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
}

.downloadMapInfo table {
table-layout:fixed;
table-layout: fixed;
}

.downloadMapInfo table td {
Expand Down
3 changes: 1 addition & 2 deletions src/components/download/styles/DownloadMenubar.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
z-index: 1200;
background-color: var(--colors-grey600);
left: 0;
top: 0
top: 0;
}

.downloadModeMenu button {
Expand All @@ -19,4 +19,3 @@
:global(.dhis2-map-downloading .maplibregl-popup-close-button) {
display: none;
}

1 change: 0 additions & 1 deletion src/components/download/styles/LegendLayers.module.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
.legendLayers {
margin-left: 22px;
}

2 changes: 1 addition & 1 deletion src/components/download/styles/OverviewMap.module.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.overviewMap {
margin-top: var(--spacers-dp8);
margin-top: var(--spacers-dp8);
border: 1px solid #ccc;
width: 100%;
height: 260px;
Expand Down
3 changes: 2 additions & 1 deletion src/components/layers/overlays/styles/LayerList.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
.list {
max-width: 684px;
max-height: calc(100vh - 150px);
padding: var(--spacers-dp8) var(--spacers-dp4) var(--spacers-dp8) var(--spacers-dp12);
padding: var(--spacers-dp8) var(--spacers-dp4) var(--spacers-dp8)
var(--spacers-dp12);
overflow-y: auto;
}

Expand Down
8 changes: 1 addition & 7 deletions src/components/map/MapLoadingMask.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import { ComponentCover, CenteredContent, CircularLoader } from '@dhis2/ui'
import cx from 'classnames'
import React from 'react'
import styles from './styles/MapLoadingMask.module.css'

export const loadingMaskClass = 'dhis2-map-loading-mask'

const MapLoadingMask = () => (
<ComponentCover
translucent
className={cx(styles.cover, loadingMaskClass)}
dataTest="map-loading-mask"
>
<ComponentCover className={loadingMaskClass} dataTest="map-loading-mask">
edoardo marked this conversation as resolved.
Show resolved Hide resolved
<CenteredContent>
<CircularLoader />
</CenteredContent>
Expand Down
9 changes: 0 additions & 9 deletions src/components/map/styles/MapLoadingMask.module.css

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/map/styles/MapPosition.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
width: 100%;
position: relative;
overflow: hidden;
flex: auto
flex: auto;
}

.mapContainer.download {
Expand Down
Loading
Loading