Skip to content

Commit a6f9f72

Browse files
Merge branch 'develop' into main
2 parents ffcee89 + 48eb461 commit a6f9f72

File tree

12 files changed

+1561
-1161
lines changed

12 files changed

+1561
-1161
lines changed

package-lock.json

Lines changed: 1168 additions & 1026 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"dhis2-godata-interoperability": "git+ssh://[email protected]/WISCENTD-UPC/dhis2-godata-interoperability.git#develop",
2929
"dotenv": "^8.2.0",
3030
"godata-api-wrapper": "git+ssh://[email protected]/WISCENTD-UPC/godata-api-wrapper.git#develop",
31+
"idb": "^6.0.0",
3132
"lodash": "^4.17.20",
3233
"ramda": "^0.27.1",
3334
"react": "^16",

src/api/Dhis2Actions.js

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
import React, { useEffect, useState } from 'react'
2+
import { deleteDB } from 'idb'
3+
import { useD2 } from '@dhis2/app-runtime-adapter-d2'
4+
import { Button, Card } from '@dhis2/ui-core'
5+
import { Radio, RadioGroup, FormControlLabel, Stepper, Step, StepLabel, StepContent } from '@material-ui/core'
6+
import StorageIcon from '@material-ui/icons/Storage'
7+
import DoneIcon from '@material-ui/icons/Done'
8+
import { mergeAll } from 'ramda'
9+
import _ from 'lodash'
10+
import DHIS2API from 'dhis2-api-wrapper'
11+
import GoDataAPI from 'godata-api-wrapper'
12+
import { copyLocations, fullTransferDHIS2, copyTrackedEntities } from 'dhis2-godata-interoperability'
13+
import '../styles/Actions.css'
14+
import { getFullSteps, getFullStepContent, getSteps, getStepContent } from '../utils/dhis2Labels'
15+
16+
const Dhis2Actions = () => {
17+
const [config, setConfig] = useState({})
18+
const [dhis2, setDhis2] = useState(null)
19+
const [godata, setGoData] = useState(null)
20+
21+
const [full, setFull] = useState(true)
22+
const fullTransferSteps = getFullSteps()
23+
const [activeStep, setActiveStep] = useState(0)
24+
const transferSteps = getSteps()
25+
26+
const [skipped, setSkipped] = useState(new Set())
27+
const [completed, setCompleted] = useState(new Set())
28+
29+
const [done, setDone] = useState(false)
30+
const [messages, setMessages] = useState([])
31+
32+
const { d2 } = useD2()
33+
34+
useEffect(() => {
35+
async function initInstances() {
36+
const generalNamespace = await d2.dataStore.get("dhis-godata-interoperability")
37+
const userNamespace = await d2.currentUser.dataStore.get("dhis-godata-interoperability")
38+
const baseConf = await generalNamespace.get("base-config")
39+
const credConf = await userNamespace.get("cred-config")
40+
const password = await userNamespace.get("password")
41+
credConf.GoDataAPIConfig.credentials.password = password.password
42+
const conf = mergeAll([baseConf, credConf])
43+
setConfig(conf)
44+
setDhis2(new DHIS2API(conf.DHIS2APIConfig))
45+
setGoData(new GoDataAPI(conf.GoDataAPIConfig))
46+
47+
}
48+
if (d2) {
49+
initInstances()
50+
}
51+
}, [d2])
52+
53+
const logAction = (message) => setMessages(prevArray => [...prevArray, { text: message, done: false }])
54+
const logDone = () => setMessages(prevArray => {
55+
const newArray = [...prevArray]
56+
newArray[newArray.length - 1].done = true
57+
return newArray
58+
})
59+
60+
const cleanCache = async () => {
61+
if (indexedDB !== undefined) {
62+
await deleteDB('dhis2tc')
63+
}
64+
}
65+
66+
const handleSkip = () => {
67+
setActiveStep(prev => prev + 1)
68+
setSkipped(prevSkipped => {
69+
const newSkipped = new Set(prevSkipped.values())
70+
const length = full ? fullTransferSteps.length : transferSteps.length
71+
newSkipped.add(activeStep)
72+
if (newSkipped.size + completed.size === length) { setDone(true) }
73+
return newSkipped
74+
})
75+
}
76+
77+
const isStepSkipped = (step) => {
78+
return skipped.has(step)
79+
}
80+
81+
const handleFullNext = () => {
82+
async function action() {
83+
switch(activeStep) {
84+
case 0:
85+
await godata.login()
86+
await fullTransferDHIS2(dhis2, godata, config, { logAction, logDone, cleanCache })()
87+
setDone(true)
88+
break
89+
default: break
90+
}
91+
}
92+
setMessages([])
93+
action()
94+
setActiveStep(prev => prev + 1)
95+
setCompleted(prev => {
96+
const newCompleted = new Set(prev.values())
97+
newCompleted.add(activeStep)
98+
return newCompleted
99+
})
100+
}
101+
const handleNext = () => {
102+
async function action() {
103+
switch(activeStep) {
104+
case 0:
105+
await godata.login()
106+
await copyLocations(dhis2, godata, config, { logAction, logDone, cleanCache })()
107+
break
108+
case 1:
109+
await copyTrackedEntities(dhis2, godata, config, { logAction, logDone })()
110+
setDone(true)
111+
break
112+
default: break
113+
}
114+
}
115+
setMessages([])
116+
action()
117+
setActiveStep(prev => prev + 1)
118+
setCompleted(prev => {
119+
const newCompleted = new Set(prev.values())
120+
newCompleted.add(activeStep)
121+
return newCompleted
122+
})
123+
}
124+
125+
return (
126+
<div className="container">
127+
<div className="card">
128+
<Card className="card" dataTest="dhis2-uicore-card">
129+
<div className="title-icon">
130+
<StorageIcon />
131+
<h3>Import data and metadata to DHIS2</h3>
132+
</div>
133+
<div className="content">
134+
<p className="p">Choose export sequence</p>
135+
<RadioGroup
136+
className="radio-group"
137+
name="fullTransfer"
138+
value={ full }
139+
onChange={ () => setFull(prev => !prev) }
140+
>
141+
<FormControlLabel
142+
value={ true }
143+
control={ <Radio disabled={ activeStep!==0 & !full } className="radio"/> }
144+
label="Full transfer"
145+
/>
146+
<FormControlLabel
147+
value={ false }
148+
control={ <Radio disabled={ activeStep!==0 & full } className="radio"/> }
149+
label="Step-by-step transfer"
150+
/>
151+
</RadioGroup>
152+
{ full &&
153+
<Stepper activeStep={ activeStep } orientation="vertical">
154+
{ fullTransferSteps.map((label, index) => {
155+
const stepProps = {}
156+
if (isStepSkipped(index)) {
157+
stepProps.completed = false
158+
}
159+
return (
160+
<Step key={ label }{...stepProps}>
161+
<StepLabel>{ label }</StepLabel>
162+
<StepContent>
163+
<div className="helper">{ getFullStepContent(index) }</div>
164+
<div className="import">
165+
<Button
166+
dataTest="dhis2-uicore-button"
167+
name="button"
168+
type="button"
169+
onClick={ handleFullNext }
170+
>
171+
Complete
172+
</Button>
173+
<Button
174+
dataTest="dhis2-uicore-button"
175+
name="button"
176+
type="button"
177+
onClick={ handleSkip }
178+
>
179+
Skip
180+
</Button>
181+
</div>
182+
</StepContent>
183+
</Step>
184+
)
185+
})}
186+
</Stepper>
187+
}
188+
{ !full &&
189+
<Stepper activeStep={ activeStep } orientation="vertical">
190+
{ transferSteps.map((label, index) => {
191+
const stepProps = {}
192+
if (isStepSkipped(index)) {
193+
stepProps.completed = false
194+
}
195+
return (
196+
<Step key={ label }{...stepProps} >
197+
<StepLabel>{ label }</StepLabel>
198+
<StepContent>
199+
<div className="helper">{ getStepContent(index) }</div>
200+
<div className="import">
201+
<Button
202+
dataTest="dhis2-uicore-button"
203+
name="button"
204+
type="button"
205+
onClick={ handleNext }
206+
>
207+
Complete
208+
</Button>
209+
<Button
210+
dataTest="dhis2-uicore-button"
211+
name="button"
212+
type="button"
213+
onClick={ handleSkip }
214+
>
215+
Skip
216+
</Button>
217+
</div>
218+
</StepContent>
219+
</Step>
220+
)
221+
})}
222+
</Stepper>
223+
}
224+
</div>
225+
</Card>
226+
<div>
227+
{ messages.map(message => (
228+
<Card className="log">
229+
<div className="title-icon" key={ message }>
230+
<div className="logAction">{ message.text+"..." }</div>
231+
{ message.done && <DoneIcon /> }
232+
</div>
233+
</Card>
234+
))}
235+
236+
</div>
237+
238+
{ done &&
239+
<Card className="log">
240+
<p className="title-icon">
241+
<span className="p">All steps completed - you're finished</span>
242+
</p>
243+
</Card>
244+
}
245+
</div>
246+
</div>
247+
248+
)
249+
}
250+
251+
export default Dhis2Actions

src/api/Actions.js renamed to src/api/GoDataActions.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import { mergeAll } from 'ramda'
88
import _ from 'lodash'
99
import DHIS2API from 'dhis2-api-wrapper'
1010
import GoDataAPI from 'godata-api-wrapper'
11-
import { copyOrganisationUnits, fullTransfer, copyCases, createOutbreaks, copyContacts, copyMetadata } from 'dhis2-godata-interoperability'
11+
import { copyOrganisationUnits, fullTransferGoData, copyCases, createOutbreaks, copyContacts, copyMetadata } from 'dhis2-godata-interoperability'
1212
import '../styles/Actions.css'
13-
import { getFullSteps, getFullStepContent, getSteps, getStepContent } from '../utils/labels'
13+
import { getFullSteps, getFullStepContent, getSteps, getStepContent } from '../utils/goDataLabels'
1414

15-
const Actions = () => {
15+
const GoDataActions = () => {
1616
const [config, setConfig] = useState({})
1717
const [dhis2, setDhis2] = useState(null)
1818
const [godata, setGoData] = useState(null)
@@ -78,7 +78,7 @@ const Actions = () => {
7878
await copyOrganisationUnits(dhis2, godata, config, { logAction, logDone })()
7979
break
8080
case 1:
81-
await fullTransfer(dhis2, godata, config, { logAction, logDone })()//TODO
81+
await fullTransferGoData(dhis2, godata, config, { logAction, logDone })()
8282
setDone(true)
8383
break
8484
default: break
@@ -134,7 +134,7 @@ const Actions = () => {
134134
<Card className="card" dataTest="dhis2-uicore-card">
135135
<div className="title-icon">
136136
<StorageIcon />
137-
<h3>Export data and metadata</h3>
137+
<h3>Export data and metadata to Go.Data</h3>
138138
</div>
139139
<div className="content">
140140
<p className="p">Choose export sequence</p>
@@ -254,4 +254,4 @@ const Actions = () => {
254254
)
255255
}
256256

257-
export default Actions
257+
export default GoDataActions

src/components/FileForm.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState } from 'react'
1+
import React, { useState, useEffect } from 'react'
22
import { AlertBar, Button, Card } from '@dhis2/ui-core'
33
import VpnKeyIcon from '@material-ui/icons/VpnKey'
44
import IconButton from '@material-ui/core/IconButton'
@@ -8,19 +8,37 @@ import i18n from '@dhis2/d2-i18n' //do translations!
88
import { useD2 } from '@dhis2/app-runtime-adapter-d2'
99
import _ from 'lodash'
1010
import '../styles/FileForm.css'
11-
import config from '../utils/config'
11+
import { config } from 'dhis2-godata-interoperability'
1212
import { getBaseUrl } from '../index'
1313

1414

1515
const FileForm = () => {
16-
const [formData, setFormData] = useState(config)
16+
const [formData, setFormData] = useState({
17+
DHIS2APIConfig: config.DHIS2APIConfig,
18+
GoDataAPIConfig: config.GoDataAPIConfig
19+
})
1720
const [isOk, setOk] = useState(true)
1821
const [isUploaded, setUploaded] = useState(false)
1922
const [wrong, setWrong] = useState(false)
2023
const [show1, setShow1] = useState(false)
2124
const [show2, setShow2] = useState(false)
2225

2326
const { d2 } = useD2()
27+
28+
useEffect(() => {
29+
async function initInstances() {
30+
const userNamespace = await d2.currentUser.dataStore.get("dhis-godata-interoperability")
31+
const credConf = await userNamespace.get("cred-config")
32+
const password = await userNamespace.get("password")
33+
credConf.GoDataAPIConfig.credentials.password = password.password
34+
if (credConf != null) {
35+
setFormData(credConf)
36+
}
37+
}
38+
if (d2) {
39+
initInstances()
40+
}
41+
}, [d2])
2442

2543
function onFormSubmit() {
2644

0 commit comments

Comments
 (0)