@dhis2/app-service-offline 3.11.3 → 3.12.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/__tests__/integration.test.js +51 -82
- package/build/cjs/index.js +0 -7
- package/build/cjs/lib/__tests__/cacheable-section-state.test.js +7 -14
- package/build/cjs/lib/__tests__/clear-sensitive-caches.test.js +17 -20
- package/build/cjs/lib/__tests__/network-status.test.js +135 -148
- package/build/cjs/lib/__tests__/offline-provider.test.js +12 -22
- package/build/cjs/lib/__tests__/use-cacheable-section.test.js +87 -98
- package/build/cjs/lib/__tests__/use-online-status-message.test.js +7 -14
- package/build/cjs/lib/cacheable-section-state.js +27 -38
- package/build/cjs/lib/cacheable-section.js +26 -27
- package/build/cjs/lib/clear-sensitive-caches.js +14 -24
- package/build/cjs/lib/dhis2-connection-status/dev-debug-log.js +1 -3
- package/build/cjs/lib/dhis2-connection-status/dhis2-connection-status.js +27 -58
- package/build/cjs/lib/dhis2-connection-status/dhis2-connection-status.test.js +287 -230
- package/build/cjs/lib/dhis2-connection-status/index.js +0 -1
- package/build/cjs/lib/dhis2-connection-status/is-ping-available.js +0 -6
- package/build/cjs/lib/dhis2-connection-status/is-ping-available.test.js +0 -1
- package/build/cjs/lib/dhis2-connection-status/smart-interval.js +35 -49
- package/build/cjs/lib/dhis2-connection-status/use-ping-query.js +4 -5
- package/build/cjs/lib/global-state-service.js +9 -27
- package/build/cjs/lib/network-status.js +10 -13
- package/build/cjs/lib/offline-interface.js +3 -14
- package/build/cjs/lib/offline-provider.js +1 -12
- package/build/cjs/lib/online-status-message.js +5 -17
- package/build/cjs/setupRTL.js +1 -1
- package/build/cjs/utils/__tests__/render-counter.test.js +3 -12
- package/build/cjs/utils/render-counter.js +2 -10
- package/build/cjs/utils/test-mocks.js +13 -18
- package/build/es/__tests__/integration.test.js +51 -74
- package/build/es/index.js +2 -2
- package/build/es/lib/__tests__/cacheable-section-state.test.js +2 -4
- package/build/es/lib/__tests__/clear-sensitive-caches.test.js +19 -16
- package/build/es/lib/__tests__/network-status.test.js +105 -114
- package/build/es/lib/__tests__/offline-provider.test.js +13 -15
- package/build/es/lib/__tests__/use-cacheable-section.test.js +69 -73
- package/build/es/lib/__tests__/use-online-status-message.test.js +2 -3
- package/build/es/lib/cacheable-section-state.js +25 -26
- package/build/es/lib/cacheable-section.js +23 -15
- package/build/es/lib/clear-sensitive-caches.js +13 -21
- package/build/es/lib/dhis2-connection-status/dev-debug-log.js +1 -3
- package/build/es/lib/dhis2-connection-status/dhis2-connection-status.js +26 -37
- package/build/es/lib/dhis2-connection-status/dhis2-connection-status.test.js +223 -159
- package/build/es/lib/dhis2-connection-status/is-ping-available.js +0 -5
- package/build/es/lib/dhis2-connection-status/smart-interval.js +34 -42
- package/build/es/lib/dhis2-connection-status/use-ping-query.js +6 -3
- package/build/es/lib/global-state-service.js +6 -12
- package/build/es/lib/network-status.js +10 -9
- package/build/es/lib/offline-interface.js +0 -3
- package/build/es/lib/offline-provider.js +0 -3
- package/build/es/lib/online-status-message.js +3 -2
- package/build/es/setupRTL.js +1 -1
- package/build/es/utils/__tests__/render-counter.test.js +2 -4
- package/build/es/utils/render-counter.js +1 -3
- package/build/es/utils/test-mocks.js +8 -9
- package/build/types/lib/cacheable-section.d.ts +1 -1
- package/build/types/lib/dhis2-connection-status/dhis2-connection-status.d.ts +1 -1
- package/build/types/lib/network-status.d.ts +1 -1
- package/build/types/lib/online-status-message.d.ts +1 -1
- package/build/types/types.d.ts +1 -1
- package/package.json +4 -4
|
@@ -14,22 +14,17 @@ export function isPingAvailable(serverVersion) {
|
|
|
14
14
|
if (!serverVersion) {
|
|
15
15
|
return false;
|
|
16
16
|
}
|
|
17
|
-
|
|
18
17
|
const {
|
|
19
18
|
minor,
|
|
20
19
|
patch
|
|
21
20
|
} = serverVersion;
|
|
22
|
-
|
|
23
21
|
switch (minor) {
|
|
24
22
|
case 39:
|
|
25
23
|
return patch === undefined || patch >= 2;
|
|
26
|
-
|
|
27
24
|
case 38:
|
|
28
25
|
return patch === undefined || patch >= 4;
|
|
29
|
-
|
|
30
26
|
case 37:
|
|
31
27
|
return patch === undefined || patch >= 10;
|
|
32
|
-
|
|
33
28
|
default:
|
|
34
29
|
return minor >= 40;
|
|
35
30
|
}
|
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
import { devDebugLog } from './dev-debug-log';
|
|
1
|
+
import { devDebugLog } from './dev-debug-log';
|
|
2
2
|
|
|
3
|
+
// Exported for tests
|
|
3
4
|
export const DEFAULT_INITIAL_DELAY_MS = 1000 * 30; // 30 sec
|
|
4
|
-
|
|
5
5
|
export const DEFAULT_MAX_DELAY_MS = 1000 * 60 * 5; // 5 min
|
|
6
|
-
|
|
7
6
|
export const DEFAULT_INCREMENT_FACTOR = 1.5;
|
|
8
|
-
|
|
9
7
|
const throwErrorIfNoCallbackIsProvided = () => {
|
|
10
8
|
throw new Error('Provide a callback');
|
|
11
9
|
};
|
|
12
|
-
|
|
13
10
|
export default function createSmartInterval() {
|
|
14
11
|
let {
|
|
15
12
|
initialDelay = DEFAULT_INITIAL_DELAY_MS,
|
|
@@ -28,8 +25,8 @@ export default function createSmartInterval() {
|
|
|
28
25
|
}, 0),
|
|
29
26
|
standbyCallback: null
|
|
30
27
|
};
|
|
31
|
-
/** Increment delay by the increment factor, up to a max value */
|
|
32
28
|
|
|
29
|
+
/** Increment delay by the increment factor, up to a max value */
|
|
33
30
|
function incrementDelay() {
|
|
34
31
|
const newDelay = Math.min(state.delay * delayIncrementFactor, maxDelay);
|
|
35
32
|
devDebugLog('[SI] incrementing delay', {
|
|
@@ -38,51 +35,51 @@ export default function createSmartInterval() {
|
|
|
38
35
|
});
|
|
39
36
|
state.delay = newDelay;
|
|
40
37
|
}
|
|
41
|
-
|
|
42
38
|
function invokeCallbackAndHandleDelay() {
|
|
43
39
|
// Increment delay before calling callback, so callback can potentially
|
|
44
40
|
// reset the delay to initial before starting the next timeout
|
|
45
41
|
incrementDelay();
|
|
46
42
|
callback();
|
|
47
43
|
}
|
|
48
|
-
|
|
49
44
|
function clearTimeoutAndStart() {
|
|
50
45
|
devDebugLog('[SI] clearing and starting timeout', {
|
|
51
46
|
delay: state.delay
|
|
52
|
-
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Prevent parallel timeouts from occuring
|
|
53
50
|
// (weird note: `if (this.timeout) { clearTimeout(this.timeout) }`
|
|
54
51
|
// does NOT work for some reason)
|
|
52
|
+
clearTimeout(state.timeout);
|
|
55
53
|
|
|
56
|
-
|
|
54
|
+
// A timeout is used instead of an interval for handling slow execution
|
|
57
55
|
// https://developer.mozilla.org/en-US/docs/Web/API/setInterval#ensure_that_execution_duration_is_shorter_than_interval_frequency
|
|
58
|
-
|
|
59
56
|
state.timeout = setTimeout(function callbackAndRestart() {
|
|
60
57
|
if (state.paused) {
|
|
61
|
-
devDebugLog('[SI] entering regular standby');
|
|
58
|
+
devDebugLog('[SI] entering regular standby');
|
|
59
|
+
|
|
60
|
+
// If paused, prepare a 'standby callback' to be invoked when
|
|
62
61
|
// `resume()` is called (see its definition below).
|
|
63
62
|
// The timer will not be started again until the standbyCallback
|
|
64
63
|
// is invoked.
|
|
65
|
-
|
|
66
64
|
state.standbyCallback = () => {
|
|
67
65
|
invokeCallbackAndHandleDelay();
|
|
68
66
|
clearTimeoutAndStart();
|
|
69
67
|
};
|
|
70
|
-
|
|
71
68
|
return;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
invokeCallbackAndHandleDelay(); // and start process over again
|
|
69
|
+
}
|
|
76
70
|
|
|
71
|
+
// Otherwise, invoke callback
|
|
72
|
+
invokeCallbackAndHandleDelay();
|
|
73
|
+
// and start process over again
|
|
77
74
|
clearTimeoutAndStart();
|
|
78
75
|
}, state.delay);
|
|
79
76
|
}
|
|
80
|
-
/** Stop the interval. Used for cleaning up */
|
|
81
|
-
|
|
82
77
|
|
|
78
|
+
/** Stop the interval. Used for cleaning up */
|
|
83
79
|
function clear() {
|
|
84
80
|
clearTimeout(state.timeout);
|
|
85
81
|
}
|
|
82
|
+
|
|
86
83
|
/**
|
|
87
84
|
* Invoke the provided callback immediately and start the timer over.
|
|
88
85
|
* The timeout to the next invocation will not be increased
|
|
@@ -94,8 +91,6 @@ export default function createSmartInterval() {
|
|
|
94
91
|
* elapses while paused, the regular standby is entered, overwriting this
|
|
95
92
|
* partial standby.
|
|
96
93
|
*/
|
|
97
|
-
|
|
98
|
-
|
|
99
94
|
function invokeCallbackImmediately() {
|
|
100
95
|
if (state.paused) {
|
|
101
96
|
if (state.standbyCallback === null) {
|
|
@@ -107,22 +102,22 @@ export default function createSmartInterval() {
|
|
|
107
102
|
// overwrite this callback if the timer elapses, so that the
|
|
108
103
|
// timeout delay gets incremented appropriately.
|
|
109
104
|
devDebugLog('[SI] entering standby without timer increment');
|
|
110
|
-
|
|
111
105
|
state.standbyCallback = () => {
|
|
112
106
|
// Invoke callback and start timer without incrementing
|
|
113
107
|
callback();
|
|
114
108
|
clearTimeoutAndStart();
|
|
115
109
|
};
|
|
116
|
-
}
|
|
117
|
-
|
|
110
|
+
}
|
|
118
111
|
|
|
112
|
+
// Skip rest of execution while paused
|
|
119
113
|
return;
|
|
120
|
-
}
|
|
121
|
-
|
|
114
|
+
}
|
|
122
115
|
|
|
116
|
+
// Invoke callback and start timer without incrementing
|
|
123
117
|
callback();
|
|
124
118
|
clearTimeoutAndStart();
|
|
125
119
|
}
|
|
120
|
+
|
|
126
121
|
/**
|
|
127
122
|
* Sets a 'paused' flag (doesn't yet stop the timer):
|
|
128
123
|
*
|
|
@@ -133,35 +128,35 @@ export default function createSmartInterval() {
|
|
|
133
128
|
*
|
|
134
129
|
* This decreases execution activity while 'paused'
|
|
135
130
|
*/
|
|
136
|
-
|
|
137
|
-
|
|
138
131
|
function pause() {
|
|
139
132
|
devDebugLog('[SI] pausing');
|
|
140
133
|
state.paused = true;
|
|
141
134
|
}
|
|
135
|
+
|
|
142
136
|
/**
|
|
143
137
|
* Removes 'paused' state
|
|
144
138
|
*
|
|
145
139
|
* If the interval is in 'standby', trigger the saved 'standbyCallback',
|
|
146
140
|
* which should start the interval timer again
|
|
147
141
|
*/
|
|
148
|
-
|
|
149
|
-
|
|
150
142
|
function resume() {
|
|
151
143
|
devDebugLog('[SI] resuming', {
|
|
152
144
|
standbyCb: state.standbyCallback
|
|
153
|
-
});
|
|
145
|
+
});
|
|
154
146
|
|
|
155
|
-
|
|
147
|
+
// Clear paused state
|
|
148
|
+
state.paused = false;
|
|
149
|
+
|
|
150
|
+
// If in standby, invoke the saved callback
|
|
156
151
|
// (invokeCallbackImmediately and clearTimeoutAndStart can set a
|
|
157
152
|
// standby callback)
|
|
158
|
-
|
|
159
153
|
if (state.standbyCallback !== null) {
|
|
160
|
-
state.standbyCallback();
|
|
161
|
-
|
|
154
|
+
state.standbyCallback();
|
|
155
|
+
// Remove existing standbyCallback
|
|
162
156
|
state.standbyCallback = null;
|
|
163
157
|
}
|
|
164
158
|
}
|
|
159
|
+
|
|
165
160
|
/**
|
|
166
161
|
* Restart the timer to the next callback invocation, using the current
|
|
167
162
|
* delay
|
|
@@ -169,24 +164,21 @@ export default function createSmartInterval() {
|
|
|
169
164
|
* Expected to be called to delay a ping in response to incidental network
|
|
170
165
|
* traffic, for example
|
|
171
166
|
*/
|
|
172
|
-
|
|
173
|
-
|
|
174
167
|
function snooze() {
|
|
175
168
|
devDebugLog('[SI] snoozing timeout');
|
|
176
169
|
clearTimeoutAndStart();
|
|
177
170
|
}
|
|
171
|
+
|
|
178
172
|
/**
|
|
179
173
|
* Cancels the current timeout and starts a new one with the initial delay
|
|
180
174
|
*/
|
|
181
|
-
|
|
182
|
-
|
|
183
175
|
function reset() {
|
|
184
176
|
devDebugLog('[SI] resetting interval from beginning');
|
|
185
177
|
state.delay = initialDelay;
|
|
186
178
|
clearTimeoutAndStart();
|
|
187
|
-
}
|
|
188
|
-
|
|
179
|
+
}
|
|
189
180
|
|
|
181
|
+
// Start the timer!
|
|
190
182
|
clearTimeoutAndStart();
|
|
191
183
|
return {
|
|
192
184
|
clear,
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { useConfig } from '@dhis2/app-service-config';
|
|
2
|
-
import { useCallback } from 'react';
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
|
|
4
|
+
// This function has a separate file for easier mocking
|
|
3
5
|
|
|
4
6
|
export function usePingQuery() {
|
|
5
7
|
const {
|
|
6
8
|
baseUrl
|
|
7
|
-
} = useConfig();
|
|
8
|
-
// public. It doesn't extend the user session. See DHIS2-14531
|
|
9
|
+
} = useConfig();
|
|
9
10
|
|
|
11
|
+
// This endpoint doesn't need any extra headers or handling since it's
|
|
12
|
+
// public. It doesn't extend the user session. See DHIS2-14531
|
|
10
13
|
const ping = useCallback(() => fetch(baseUrl + '/api/ping'), [baseUrl]);
|
|
11
14
|
return ping;
|
|
12
15
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import isEqual from 'lodash/isEqual';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import React, { useEffect, useCallback, useContext, useState, useMemo } from 'react';
|
|
4
|
-
|
|
5
4
|
// This file creates a redux-like state management service using React context
|
|
6
5
|
// that minimizes unnecessary rerenders that consume the context.
|
|
7
6
|
// See more at https://github.com/amcgee/state-service-poc
|
|
8
|
-
const identity = state => state;
|
|
9
7
|
|
|
8
|
+
const identity = state => state;
|
|
10
9
|
export const createStore = function () {
|
|
11
10
|
let initialState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
12
11
|
const subscriptions = new Set();
|
|
@@ -21,7 +20,6 @@ export const createStore = function () {
|
|
|
21
20
|
},
|
|
22
21
|
mutate: mutation => {
|
|
23
22
|
state = mutation(state);
|
|
24
|
-
|
|
25
23
|
for (const callback of subscriptions) {
|
|
26
24
|
callback(state);
|
|
27
25
|
}
|
|
@@ -29,10 +27,8 @@ export const createStore = function () {
|
|
|
29
27
|
};
|
|
30
28
|
};
|
|
31
29
|
const GlobalStateContext = /*#__PURE__*/React.createContext(createStore());
|
|
32
|
-
|
|
33
30
|
const useGlobalStateStore = () => useContext(GlobalStateContext);
|
|
34
|
-
|
|
35
|
-
export const GlobalStateProvider = (_ref) => {
|
|
31
|
+
export const GlobalStateProvider = _ref => {
|
|
36
32
|
let {
|
|
37
33
|
store,
|
|
38
34
|
children
|
|
@@ -52,21 +48,19 @@ export const useGlobalState = function () {
|
|
|
52
48
|
useEffect(() => {
|
|
53
49
|
// NEW: deep equality check before updating
|
|
54
50
|
const callback = state => {
|
|
55
|
-
const newSelectedState = selector(state);
|
|
56
|
-
|
|
51
|
+
const newSelectedState = selector(state);
|
|
52
|
+
// Use this form to avoid having `selectedState` as a dep in here
|
|
57
53
|
setSelectedState(currentSelectedState => {
|
|
58
54
|
// Second condition handles case where a selected object gets
|
|
59
55
|
// deleted, but state does not update
|
|
60
56
|
if (!isEqual(currentSelectedState, newSelectedState) || currentSelectedState === undefined) {
|
|
61
57
|
return newSelectedState;
|
|
62
58
|
}
|
|
63
|
-
|
|
64
59
|
return currentSelectedState;
|
|
65
60
|
});
|
|
66
61
|
};
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
store.subscribe(callback);
|
|
63
|
+
// Make sure to update state when selector changes
|
|
70
64
|
callback(store.getState());
|
|
71
65
|
return () => store.unsubscribe(callback);
|
|
72
66
|
}, [store, selector]);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import debounce from 'lodash/debounce';
|
|
2
2
|
import { useState, useEffect, useCallback, useMemo } from 'react';
|
|
3
|
-
const lastOnlineKey = 'dhis2.lastOnline';
|
|
3
|
+
const lastOnlineKey = 'dhis2.lastOnline';
|
|
4
|
+
|
|
5
|
+
// TODO: Add option to periodically ping server to check online status.
|
|
4
6
|
// TODO: Add logic to return a variable indicating unstable connection.
|
|
5
7
|
|
|
6
8
|
/**
|
|
@@ -17,30 +19,28 @@ const lastOnlineKey = 'dhis2.lastOnline'; // TODO: Add option to periodically pi
|
|
|
17
19
|
* @param {Number} [options.debounceDelay] - Timeout delay to debounce updates, in ms
|
|
18
20
|
* @returns {Object} `{ online: boolean, offline: boolean, lastOnline: Date | null }`
|
|
19
21
|
*/
|
|
20
|
-
|
|
21
22
|
export function useNetworkStatus() {
|
|
22
23
|
var _options$debounceDela;
|
|
23
|
-
|
|
24
24
|
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
25
25
|
// initialize state to `navigator.onLine` value
|
|
26
|
-
const [online, setOnline] = useState(navigator.onLine);
|
|
26
|
+
const [online, setOnline] = useState(navigator.onLine);
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
29
|
+
const updateState = useCallback(debounce(_ref => {
|
|
29
30
|
let {
|
|
30
31
|
type
|
|
31
32
|
} = _ref;
|
|
32
|
-
|
|
33
33
|
if (type === 'online') {
|
|
34
34
|
setOnline(true);
|
|
35
35
|
} else if (type === 'offline') {
|
|
36
36
|
if (online || !localStorage.getItem(lastOnlineKey)) {
|
|
37
37
|
localStorage.setItem(lastOnlineKey, new Date(Date.now()).toUTCString());
|
|
38
38
|
}
|
|
39
|
-
|
|
40
39
|
setOnline(false);
|
|
41
40
|
}
|
|
42
|
-
}, (_options$debounceDela = options.debounceDelay) !== null && _options$debounceDela !== void 0 ? _options$debounceDela : 1000), [options.debounceDelay]);
|
|
41
|
+
}, (_options$debounceDela = options.debounceDelay) !== null && _options$debounceDela !== void 0 ? _options$debounceDela : 1000), [options.debounceDelay]);
|
|
43
42
|
|
|
43
|
+
// on 'online' or 'offline' events, set state
|
|
44
44
|
useEffect(() => {
|
|
45
45
|
window.addEventListener('online', updateState);
|
|
46
46
|
window.addEventListener('offline', updateState);
|
|
@@ -49,8 +49,9 @@ export function useNetworkStatus() {
|
|
|
49
49
|
window.removeEventListener('online', updateState);
|
|
50
50
|
window.removeEventListener('offline', updateState);
|
|
51
51
|
};
|
|
52
|
-
}, [updateState]);
|
|
52
|
+
}, [updateState]);
|
|
53
53
|
|
|
54
|
+
// Only fetch if `online === false` as local storage is synchronous and disk-based
|
|
54
55
|
const lastOnline = useMemo(() => !online && localStorage.getItem(lastOnlineKey), [online]);
|
|
55
56
|
return {
|
|
56
57
|
online,
|
|
@@ -10,7 +10,6 @@ const noopOfflineInterface = {
|
|
|
10
10
|
removeSection: async () => false
|
|
11
11
|
};
|
|
12
12
|
const OfflineInterfaceContext = /*#__PURE__*/createContext(noopOfflineInterface);
|
|
13
|
-
|
|
14
13
|
/**
|
|
15
14
|
* Receives an OfflineInterface instance as a prop (presumably from the app
|
|
16
15
|
* adapter) and provides it as context for other offline tools.
|
|
@@ -36,10 +35,8 @@ OfflineInterfaceProvider.propTypes = {
|
|
|
36
35
|
};
|
|
37
36
|
export function useOfflineInterface() {
|
|
38
37
|
const offlineInterface = useContext(OfflineInterfaceContext);
|
|
39
|
-
|
|
40
38
|
if (offlineInterface === undefined) {
|
|
41
39
|
throw new Error('Offline interface context not found. If this app is using the app platform, make sure `pwa: { enabled: true }` is in d2.config.js. If this is not a platform app, make sure your app is wrapped with an app-runtime <Provider> or an <OfflineProvider> from app-service-offline.');
|
|
42
40
|
}
|
|
43
|
-
|
|
44
41
|
return offlineInterface;
|
|
45
42
|
}
|
|
@@ -4,20 +4,17 @@ import { CacheableSectionProvider } from './cacheable-section-state';
|
|
|
4
4
|
import { Dhis2ConnectionStatusProvider } from './dhis2-connection-status';
|
|
5
5
|
import { OfflineInterfaceProvider } from './offline-interface';
|
|
6
6
|
import { OnlineStatusMessageProvider } from './online-status-message';
|
|
7
|
-
|
|
8
7
|
/** A context provider for all the relevant offline contexts */
|
|
9
8
|
export function OfflineProvider(_ref) {
|
|
10
9
|
let {
|
|
11
10
|
offlineInterface,
|
|
12
11
|
children
|
|
13
12
|
} = _ref;
|
|
14
|
-
|
|
15
13
|
// If an offline interface is not provided, or if one is provided and PWA
|
|
16
14
|
// is not enabled, skip adding context providers
|
|
17
15
|
if (!offlineInterface || !offlineInterface.pwaEnabled) {
|
|
18
16
|
return /*#__PURE__*/React.createElement(React.Fragment, null, children);
|
|
19
17
|
}
|
|
20
|
-
|
|
21
18
|
return /*#__PURE__*/React.createElement(OfflineInterfaceProvider, {
|
|
22
19
|
offlineInterface: offlineInterface
|
|
23
20
|
}, /*#__PURE__*/React.createElement(Dhis2ConnectionStatusProvider, null, /*#__PURE__*/React.createElement(CacheableSectionProvider, null, /*#__PURE__*/React.createElement(OnlineStatusMessageProvider, null, children))));
|
|
@@ -3,7 +3,7 @@ import React, { useContext, useState } from 'react';
|
|
|
3
3
|
// actually need the value don't have to rerender when the value changes:
|
|
4
4
|
const OnlineStatusMessageValueContext = /*#__PURE__*/React.createContext(undefined);
|
|
5
5
|
const SetOnlineStatusMessageContext = /*#__PURE__*/React.createContext(() => undefined);
|
|
6
|
-
export const OnlineStatusMessageProvider =
|
|
6
|
+
export const OnlineStatusMessageProvider = _ref => {
|
|
7
7
|
let {
|
|
8
8
|
children
|
|
9
9
|
} = _ref;
|
|
@@ -20,8 +20,9 @@ export const useOnlineStatusMessageValue = () => {
|
|
|
20
20
|
};
|
|
21
21
|
export const useSetOnlineStatusMessage = () => {
|
|
22
22
|
return useContext(SetOnlineStatusMessageContext);
|
|
23
|
-
};
|
|
23
|
+
};
|
|
24
24
|
|
|
25
|
+
// combination of both getter and setter (also provides backward compatability)
|
|
25
26
|
export const useOnlineStatusMessage = () => {
|
|
26
27
|
const onlineStatusMessage = useOnlineStatusMessageValue();
|
|
27
28
|
const setOnlineStatusMessage = useSetOnlineStatusMessage();
|
package/build/es/setupRTL.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import '@testing-library/jest-dom
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
@@ -4,9 +4,7 @@ import { RenderCounter, resetRenderCounts } from '../render-counter';
|
|
|
4
4
|
const renderCounts = {};
|
|
5
5
|
export const Rerenderer = () => {
|
|
6
6
|
const [, setState] = React.useState(true);
|
|
7
|
-
|
|
8
7
|
const toggleState = () => setState(prevState => !prevState);
|
|
9
|
-
|
|
10
8
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("button", {
|
|
11
9
|
onClick: toggleState,
|
|
12
10
|
role: "button"
|
|
@@ -19,7 +17,7 @@ afterEach(() => {
|
|
|
19
17
|
resetRenderCounts(renderCounts);
|
|
20
18
|
});
|
|
21
19
|
it('increments the counter when rerendered', () => {
|
|
22
|
-
render(
|
|
20
|
+
render(/*#__PURE__*/React.createElement(Rerenderer, null));
|
|
23
21
|
const {
|
|
24
22
|
getByTestId,
|
|
25
23
|
getByRole
|
|
@@ -35,6 +33,6 @@ it('increments the counter when rerendered', () => {
|
|
|
35
33
|
expect(getByTestId('rc1')).toHaveTextContent('3');
|
|
36
34
|
});
|
|
37
35
|
it('resets the render counter successfully', () => {
|
|
38
|
-
render(
|
|
36
|
+
render(/*#__PURE__*/React.createElement(Rerenderer, null));
|
|
39
37
|
expect(screen.getByTestId('rc1')).toHaveTextContent('1');
|
|
40
38
|
});
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
export const RenderCounter =
|
|
2
|
+
export const RenderCounter = _ref => {
|
|
3
3
|
let {
|
|
4
4
|
id,
|
|
5
5
|
countsObj
|
|
6
6
|
} = _ref;
|
|
7
|
-
|
|
8
7
|
if (!(id in countsObj)) {
|
|
9
8
|
countsObj[id] = 0;
|
|
10
9
|
}
|
|
11
|
-
|
|
12
10
|
return /*#__PURE__*/React.createElement("div", {
|
|
13
11
|
"data-testid": id
|
|
14
12
|
}, ++countsObj[id]);
|
|
@@ -3,18 +3,17 @@ export const successfulRecordingMock = jest.fn().mockImplementation(async functi
|
|
|
3
3
|
onStarted,
|
|
4
4
|
onCompleted
|
|
5
5
|
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
6
|
-
|
|
7
6
|
// in 100ms, call 'onStarted' callback (allows 'pending' state)
|
|
8
7
|
if (onStarted) {
|
|
9
8
|
setTimeout(onStarted, 100);
|
|
10
|
-
}
|
|
11
|
-
|
|
9
|
+
}
|
|
12
10
|
|
|
11
|
+
// in 200ms, call 'onCompleted' callback
|
|
13
12
|
if (onCompleted) {
|
|
14
13
|
setTimeout(onCompleted, 200);
|
|
15
|
-
}
|
|
16
|
-
|
|
14
|
+
}
|
|
17
15
|
|
|
16
|
+
// resolve
|
|
18
17
|
return Promise.resolve();
|
|
19
18
|
});
|
|
20
19
|
export const errorRecordingMock = jest.fn().mockImplementation(function () {
|
|
@@ -22,15 +21,15 @@ export const errorRecordingMock = jest.fn().mockImplementation(function () {
|
|
|
22
21
|
onStarted,
|
|
23
22
|
onError
|
|
24
23
|
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
25
|
-
|
|
26
24
|
// in 100ms, call 'onStarted' callback (allows 'pending' state)
|
|
27
25
|
if (onStarted) {
|
|
28
26
|
setTimeout(onStarted, 100);
|
|
29
|
-
}
|
|
30
|
-
|
|
27
|
+
}
|
|
31
28
|
|
|
32
|
-
|
|
29
|
+
// in 200ms, call 'onError'
|
|
30
|
+
setTimeout(() => onError(new Error('test err')), 200);
|
|
33
31
|
|
|
32
|
+
// resolve to signal successful initiation
|
|
34
33
|
return Promise.resolve();
|
|
35
34
|
});
|
|
36
35
|
export const failedMessageRecordingMock = jest.fn().mockRejectedValue(new Error('Failed message'));
|
|
@@ -7,7 +7,7 @@ interface CacheableSectionStartRecordingOptions {
|
|
|
7
7
|
onCompleted?: () => void;
|
|
8
8
|
onError?: (err: Error) => void;
|
|
9
9
|
}
|
|
10
|
-
export
|
|
10
|
+
export type CacheableSectionStartRecording = (options?: CacheableSectionStartRecordingOptions) => Promise<any>;
|
|
11
11
|
interface CacheableSectionControls {
|
|
12
12
|
recordingState: RecordingState;
|
|
13
13
|
startRecording: CacheableSectionStartRecording;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
|
|
3
|
+
type AppName = string | undefined;
|
|
4
4
|
export declare const getLastConnectedKey: (appName?: AppName) => string;
|
|
5
5
|
export interface Dhis2ConnectionStatus {
|
|
6
6
|
isConnected: boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { ReactElement, ReactNode } from 'react';
|
|
2
|
-
|
|
2
|
+
type SetOnlineStatusMessage = (message: ReactNode) => void;
|
|
3
3
|
export declare const OnlineStatusMessageProvider: ({ children, }: {
|
|
4
4
|
children: ReactNode;
|
|
5
5
|
}) => ReactElement;
|
package/build/types/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dhis2/app-service-offline",
|
|
3
3
|
"description": "A runtime service for online/offline detection and offline caching",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.12.0-alpha.2",
|
|
5
5
|
"main": "./build/cjs/index.js",
|
|
6
6
|
"module": "./build/es/index.js",
|
|
7
7
|
"types": "build/types/index.d.ts",
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"coverage": "yarn test --coverage"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"@dhis2/app-service-config": "3.
|
|
36
|
+
"@dhis2/app-service-config": "3.12.0-alpha.2",
|
|
37
37
|
"prop-types": "^15.7.2",
|
|
38
|
-
"react": "^16.8.6",
|
|
39
|
-
"react-dom": "^16.8.6"
|
|
38
|
+
"react": "^16.8.6 || ^18",
|
|
39
|
+
"react-dom": "^16.8.6 || ^18"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"lodash": "^4.17.21"
|