@dhis2/app-service-offline 3.11.3 → 3.12.0-alpha.1
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
|
@@ -8,20 +8,15 @@ exports.createCacheableSectionStore = createCacheableSectionStore;
|
|
|
8
8
|
exports.useCachedSection = useCachedSection;
|
|
9
9
|
exports.useCachedSections = useCachedSections;
|
|
10
10
|
exports.useRecordingState = useRecordingState;
|
|
11
|
-
|
|
12
11
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
13
|
-
|
|
14
12
|
var _react = _interopRequireWildcard(require("react"));
|
|
15
|
-
|
|
16
13
|
var _globalStateService = require("./global-state-service");
|
|
17
|
-
|
|
18
14
|
var _offlineInterface = require("./offline-interface");
|
|
19
|
-
|
|
20
|
-
function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
16
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
17
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
18
|
+
// Functions in here use the global state service to manage cacheable section
|
|
19
|
+
// state in a performant way
|
|
25
20
|
|
|
26
21
|
/**
|
|
27
22
|
* Helper that transforms an array of cached section objects from the IndexedDB
|
|
@@ -36,19 +31,19 @@ function getSectionsById(sectionsArray) {
|
|
|
36
31
|
sectionId,
|
|
37
32
|
lastUpdated
|
|
38
33
|
} = _ref;
|
|
39
|
-
return {
|
|
34
|
+
return {
|
|
35
|
+
...result,
|
|
40
36
|
[sectionId]: {
|
|
41
37
|
lastUpdated
|
|
42
38
|
}
|
|
43
39
|
};
|
|
44
40
|
}, {});
|
|
45
41
|
}
|
|
42
|
+
|
|
46
43
|
/**
|
|
47
44
|
* Create a store for Cacheable Section state.
|
|
48
45
|
* Expected to be used in app adapter
|
|
49
46
|
*/
|
|
50
|
-
|
|
51
|
-
|
|
52
47
|
function createCacheableSectionStore() {
|
|
53
48
|
const initialState = {
|
|
54
49
|
recordingStates: {},
|
|
@@ -56,41 +51,39 @@ function createCacheableSectionStore() {
|
|
|
56
51
|
};
|
|
57
52
|
return (0, _globalStateService.createStore)(initialState);
|
|
58
53
|
}
|
|
54
|
+
|
|
59
55
|
/**
|
|
60
56
|
* Helper hook that returns a value that will persist between renders but makes
|
|
61
57
|
* sure to only set its initial state once.
|
|
62
58
|
* See https://gist.github.com/amcgee/42bb2fa6d5f79e607f00e6dccc733482
|
|
63
59
|
*/
|
|
64
|
-
|
|
65
|
-
|
|
66
60
|
function useConst(factory) {
|
|
67
61
|
const ref = _react.default.useRef(null);
|
|
68
|
-
|
|
69
62
|
if (ref.current === null) {
|
|
70
63
|
ref.current = factory();
|
|
71
64
|
}
|
|
72
|
-
|
|
73
65
|
return ref.current;
|
|
74
66
|
}
|
|
67
|
+
|
|
75
68
|
/**
|
|
76
69
|
* Provides context for a global state context which will track cached
|
|
77
70
|
* sections' status and cacheable sections' recording states, which will
|
|
78
71
|
* determine how that component will render. The provider will be a part of
|
|
79
72
|
* the OfflineProvider.
|
|
80
73
|
*/
|
|
81
|
-
|
|
82
|
-
|
|
83
74
|
function CacheableSectionProvider(_ref2) {
|
|
84
75
|
let {
|
|
85
76
|
children
|
|
86
77
|
} = _ref2;
|
|
87
78
|
const offlineInterface = (0, _offlineInterface.useOfflineInterface)();
|
|
88
|
-
const store = useConst(createCacheableSectionStore);
|
|
79
|
+
const store = useConst(createCacheableSectionStore);
|
|
89
80
|
|
|
81
|
+
// On load, get sections and add to store
|
|
90
82
|
(0, _react.useEffect)(() => {
|
|
91
83
|
if (offlineInterface) {
|
|
92
84
|
offlineInterface.getCachedSections().then(sections => {
|
|
93
|
-
store.mutate(state => ({
|
|
85
|
+
store.mutate(state => ({
|
|
86
|
+
...state,
|
|
94
87
|
cachedSections: getSectionsById(sections)
|
|
95
88
|
}));
|
|
96
89
|
});
|
|
@@ -100,11 +93,9 @@ function CacheableSectionProvider(_ref2) {
|
|
|
100
93
|
store: store
|
|
101
94
|
}, children);
|
|
102
95
|
}
|
|
103
|
-
|
|
104
96
|
CacheableSectionProvider.propTypes = {
|
|
105
97
|
children: _propTypes.default.node
|
|
106
98
|
};
|
|
107
|
-
|
|
108
99
|
/**
|
|
109
100
|
* Uses an optimized global state to manage 'recording state' values without
|
|
110
101
|
* unnecessarily rerendering all consuming components
|
|
@@ -115,17 +106,21 @@ CacheableSectionProvider.propTypes = {
|
|
|
115
106
|
function useRecordingState(id) {
|
|
116
107
|
const recordingStateSelector = (0, _react.useCallback)(state => state.recordingStates[id], [id]);
|
|
117
108
|
const [recordingState] = (0, _globalStateService.useGlobalState)(recordingStateSelector);
|
|
118
|
-
const setRecordingStateMutationCreator = (0, _react.useCallback)(newState => state => ({
|
|
119
|
-
|
|
109
|
+
const setRecordingStateMutationCreator = (0, _react.useCallback)(newState => state => ({
|
|
110
|
+
...state,
|
|
111
|
+
recordingStates: {
|
|
112
|
+
...state.recordingStates,
|
|
120
113
|
[id]: newState
|
|
121
114
|
}
|
|
122
115
|
}), [id]);
|
|
123
116
|
const setRecordingState = (0, _globalStateService.useGlobalStateMutation)(setRecordingStateMutationCreator);
|
|
124
117
|
const removeRecordingStateMutationCreator = (0, _react.useCallback)(() => state => {
|
|
125
|
-
const recordingStates = {
|
|
118
|
+
const recordingStates = {
|
|
119
|
+
...state.recordingStates
|
|
126
120
|
};
|
|
127
121
|
delete recordingStates[id];
|
|
128
|
-
return {
|
|
122
|
+
return {
|
|
123
|
+
...state,
|
|
129
124
|
recordingStates
|
|
130
125
|
};
|
|
131
126
|
}, [id]);
|
|
@@ -136,17 +131,17 @@ function useRecordingState(id) {
|
|
|
136
131
|
removeRecordingState
|
|
137
132
|
}), [recordingState, setRecordingState, removeRecordingState]);
|
|
138
133
|
}
|
|
134
|
+
|
|
139
135
|
/**
|
|
140
136
|
* Returns a function that syncs cached sections in the global state
|
|
141
137
|
* with IndexedDB, so that IndexedDB is the single source of truth
|
|
142
138
|
*
|
|
143
139
|
* @returns {Function} syncCachedSections
|
|
144
140
|
*/
|
|
145
|
-
|
|
146
|
-
|
|
147
141
|
function useSyncCachedSections() {
|
|
148
142
|
const offlineInterface = (0, _offlineInterface.useOfflineInterface)();
|
|
149
|
-
const setCachedSectionsMutationCreator = (0, _react.useCallback)(cachedSections => state => ({
|
|
143
|
+
const setCachedSectionsMutationCreator = (0, _react.useCallback)(cachedSections => state => ({
|
|
144
|
+
...state,
|
|
150
145
|
cachedSections
|
|
151
146
|
}), []);
|
|
152
147
|
const setCachedSections = (0, _globalStateService.useGlobalStateMutation)(setCachedSectionsMutationCreator);
|
|
@@ -155,7 +150,6 @@ function useSyncCachedSections() {
|
|
|
155
150
|
setCachedSections(getSectionsById(sections));
|
|
156
151
|
}, [offlineInterface, setCachedSections]);
|
|
157
152
|
}
|
|
158
|
-
|
|
159
153
|
/**
|
|
160
154
|
* Uses global state to manage an object of cached sections' statuses
|
|
161
155
|
*
|
|
@@ -165,6 +159,7 @@ function useCachedSections() {
|
|
|
165
159
|
const [cachedSections] = (0, _globalStateService.useGlobalState)(state => state.cachedSections);
|
|
166
160
|
const syncCachedSections = useSyncCachedSections();
|
|
167
161
|
const offlineInterface = (0, _offlineInterface.useOfflineInterface)();
|
|
162
|
+
|
|
168
163
|
/**
|
|
169
164
|
* Uses offline interface to remove a section from IndexedDB and Cache
|
|
170
165
|
* Storage.
|
|
@@ -172,14 +167,11 @@ function useCachedSections() {
|
|
|
172
167
|
* Returns a promise that resolves to `true` if a section is found and
|
|
173
168
|
* deleted, or `false` if asection with the specified ID does not exist.
|
|
174
169
|
*/
|
|
175
|
-
|
|
176
170
|
const removeById = (0, _react.useCallback)(async id => {
|
|
177
171
|
const success = await offlineInterface.removeSection(id);
|
|
178
|
-
|
|
179
172
|
if (success) {
|
|
180
173
|
await syncCachedSections();
|
|
181
174
|
}
|
|
182
|
-
|
|
183
175
|
return success;
|
|
184
176
|
}, [offlineInterface, syncCachedSections]);
|
|
185
177
|
return (0, _react.useMemo)(() => ({
|
|
@@ -188,7 +180,6 @@ function useCachedSections() {
|
|
|
188
180
|
syncCachedSections
|
|
189
181
|
}), [cachedSections, removeById, syncCachedSections]);
|
|
190
182
|
}
|
|
191
|
-
|
|
192
183
|
/**
|
|
193
184
|
* Uses global state to manage the cached status of just one section, which
|
|
194
185
|
* prevents unnecessary rerenders of consuming components
|
|
@@ -201,6 +192,7 @@ function useCachedSection(id) {
|
|
|
201
192
|
const syncCachedSections = useSyncCachedSections();
|
|
202
193
|
const offlineInterface = (0, _offlineInterface.useOfflineInterface)();
|
|
203
194
|
const lastUpdated = status && status.lastUpdated;
|
|
195
|
+
|
|
204
196
|
/**
|
|
205
197
|
* Uses offline interface to remove a section from IndexedDB and Cache
|
|
206
198
|
* Storage.
|
|
@@ -208,14 +200,11 @@ function useCachedSection(id) {
|
|
|
208
200
|
* Returns `true` if a section is found and deleted, or `false` if a
|
|
209
201
|
* section with the specified ID does not exist.
|
|
210
202
|
*/
|
|
211
|
-
|
|
212
203
|
const remove = (0, _react.useCallback)(async () => {
|
|
213
204
|
const success = await offlineInterface.removeSection(id);
|
|
214
|
-
|
|
215
205
|
if (success) {
|
|
216
206
|
await syncCachedSections();
|
|
217
207
|
}
|
|
218
|
-
|
|
219
208
|
return success;
|
|
220
209
|
}, [offlineInterface, id, syncCachedSections]);
|
|
221
210
|
return (0, _react.useMemo)(() => ({
|
|
@@ -5,28 +5,20 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.CacheableSection = CacheableSection;
|
|
7
7
|
exports.useCacheableSection = useCacheableSection;
|
|
8
|
-
|
|
9
8
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
10
|
-
|
|
11
9
|
var _react = _interopRequireWildcard(require("react"));
|
|
12
|
-
|
|
10
|
+
var _reactDom = require("react-dom");
|
|
13
11
|
var _cacheableSectionState = require("./cacheable-section-state");
|
|
14
|
-
|
|
15
12
|
var _offlineInterface = require("./offline-interface");
|
|
16
|
-
|
|
17
|
-
function
|
|
18
|
-
|
|
19
|
-
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
20
|
-
|
|
21
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
22
|
-
|
|
13
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
14
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
15
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
23
16
|
const recordingStates = {
|
|
24
17
|
default: 'default',
|
|
25
18
|
pending: 'pending',
|
|
26
19
|
recording: 'recording',
|
|
27
20
|
error: 'error'
|
|
28
21
|
};
|
|
29
|
-
|
|
30
22
|
/**
|
|
31
23
|
* Returns the main controls for a cacheable section and manages recording
|
|
32
24
|
* state, which affects the render state of the CacheableSection component.
|
|
@@ -53,9 +45,8 @@ function useCacheableSection(id) {
|
|
|
53
45
|
// On mount, add recording state for this ID to context if needed
|
|
54
46
|
if (!recordingState) {
|
|
55
47
|
setRecordingState(recordingStates.default);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
}
|
|
49
|
+
// On unnmount, remove recording state if not recording
|
|
59
50
|
return () => {
|
|
60
51
|
if (recordingState && recordingState !== recordingStates.recording && recordingState !== recordingStates.pending) {
|
|
61
52
|
removeRecordingState();
|
|
@@ -88,21 +79,30 @@ function useCacheableSection(id) {
|
|
|
88
79
|
sectionId: id,
|
|
89
80
|
recordingTimeoutDelay,
|
|
90
81
|
onStarted: () => {
|
|
91
|
-
|
|
82
|
+
// Flush this state update synchronously so that the
|
|
83
|
+
// right recordingState is set before any other callbacks
|
|
84
|
+
(0, _reactDom.flushSync)(() => {
|
|
85
|
+
onRecordingStarted();
|
|
86
|
+
});
|
|
92
87
|
onStarted && onStarted();
|
|
93
88
|
},
|
|
94
89
|
onCompleted: () => {
|
|
95
|
-
|
|
90
|
+
(0, _reactDom.flushSync)(() => {
|
|
91
|
+
onRecordingCompleted();
|
|
92
|
+
});
|
|
96
93
|
onCompleted && onCompleted();
|
|
97
94
|
},
|
|
98
95
|
onError: error => {
|
|
99
|
-
|
|
96
|
+
(0, _reactDom.flushSync)(() => {
|
|
97
|
+
onRecordingError(error);
|
|
98
|
+
});
|
|
100
99
|
onError && onError(error);
|
|
101
100
|
}
|
|
102
101
|
}).then(() => setRecordingState(recordingStates.pending));
|
|
103
|
-
}, [id, offlineInterface, onRecordingCompleted, onRecordingError, onRecordingStarted, setRecordingState]);
|
|
104
|
-
// but provided through this hook for convenience
|
|
102
|
+
}, [id, offlineInterface, onRecordingCompleted, onRecordingError, onRecordingStarted, setRecordingState]);
|
|
105
103
|
|
|
104
|
+
// isCached, lastUpdated, remove: _could_ be accessed by useCachedSection,
|
|
105
|
+
// but provided through this hook for convenience
|
|
106
106
|
return (0, _react.useMemo)(() => ({
|
|
107
107
|
recordingState,
|
|
108
108
|
startRecording,
|
|
@@ -111,7 +111,6 @@ function useCacheableSection(id) {
|
|
|
111
111
|
remove
|
|
112
112
|
}), [recordingState, startRecording, lastUpdated, isCached, remove]);
|
|
113
113
|
}
|
|
114
|
-
|
|
115
114
|
/**
|
|
116
115
|
* Used to wrap the relevant component to be recorded and saved offline.
|
|
117
116
|
* Depending on the recording state of the section, this wrapper will
|
|
@@ -132,21 +131,21 @@ function CacheableSection(_ref) {
|
|
|
132
131
|
// Accesses recording state that useCacheableSection controls
|
|
133
132
|
const {
|
|
134
133
|
recordingState
|
|
135
|
-
} = (0, _cacheableSectionState.useRecordingState)(id);
|
|
134
|
+
} = (0, _cacheableSectionState.useRecordingState)(id);
|
|
135
|
+
|
|
136
|
+
// The following causes the component to reload in the event of a recording
|
|
136
137
|
// error; the state will be cleared next time recording moves to pending.
|
|
137
138
|
// It fixes a component getting stuck while rendered without data after
|
|
138
139
|
// failing a recording while offline.
|
|
139
140
|
// Errors can be handled in the `onError` callback to `startRecording`.
|
|
140
|
-
|
|
141
141
|
if (recordingState === recordingStates.error) {
|
|
142
142
|
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, children);
|
|
143
|
-
}
|
|
144
|
-
// rerender after successful recording
|
|
145
|
-
|
|
143
|
+
}
|
|
146
144
|
|
|
145
|
+
// Handling rendering with the following conditions prevents an unncessary
|
|
146
|
+
// rerender after successful recording
|
|
147
147
|
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, recordingState === recordingStates.recording && loadingMask, recordingState !== recordingStates.pending && children);
|
|
148
148
|
}
|
|
149
|
-
|
|
150
149
|
CacheableSection.propTypes = {
|
|
151
150
|
id: _propTypes.default.string.isRequired,
|
|
152
151
|
children: _propTypes.default.node,
|
|
@@ -6,14 +6,12 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.SECTIONS_STORE = exports.SECTIONS_DB = void 0;
|
|
7
7
|
exports.clearSensitiveCaches = clearSensitiveCaches;
|
|
8
8
|
// IndexedDB names; should be the same as in @dhis2/pwa
|
|
9
|
-
const SECTIONS_DB = 'sections-db';
|
|
10
|
-
exports.
|
|
11
|
-
const SECTIONS_STORE = 'sections-store'; // Non-sensitive caches that can be kept:
|
|
9
|
+
const SECTIONS_DB = exports.SECTIONS_DB = 'sections-db';
|
|
10
|
+
const SECTIONS_STORE = exports.SECTIONS_STORE = 'sections-store';
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
// Non-sensitive caches that can be kept:
|
|
14
13
|
const KEEPABLE_CACHES = [/^workbox-precache/ // precached static assets
|
|
15
14
|
];
|
|
16
|
-
|
|
17
15
|
/*
|
|
18
16
|
* Clears the 'sections-db' IndexedDB if it exists. Designed to avoid opening
|
|
19
17
|
* a new DB if it doesn't exist yet. Firefox can't check if 'sections-db'
|
|
@@ -28,10 +26,8 @@ const clearDB = async dbName => {
|
|
|
28
26
|
// and offline interface will handle discrepancies in PWA apps.
|
|
29
27
|
return;
|
|
30
28
|
}
|
|
31
|
-
|
|
32
29
|
const dbs = await window.indexedDB.databases();
|
|
33
|
-
|
|
34
|
-
if (!dbs.some((_ref) => {
|
|
30
|
+
if (!dbs.some(_ref => {
|
|
35
31
|
let {
|
|
36
32
|
name
|
|
37
33
|
} = _ref;
|
|
@@ -40,57 +36,51 @@ const clearDB = async dbName => {
|
|
|
40
36
|
// Sections-db is not created; nothing to do here
|
|
41
37
|
return;
|
|
42
38
|
}
|
|
43
|
-
|
|
44
39
|
return new Promise((resolve, reject) => {
|
|
45
40
|
// IndexedDB fun:
|
|
46
41
|
const openDBRequest = indexedDB.open(dbName);
|
|
47
|
-
|
|
48
42
|
openDBRequest.onsuccess = e => {
|
|
49
43
|
const db = e.target.result;
|
|
50
|
-
const tx = db.transaction(SECTIONS_STORE, 'readwrite');
|
|
51
|
-
|
|
44
|
+
const tx = db.transaction(SECTIONS_STORE, 'readwrite');
|
|
45
|
+
// When the transaction completes is when the operation is done:
|
|
52
46
|
tx.oncomplete = () => resolve();
|
|
53
|
-
|
|
54
47
|
tx.onerror = e => reject(e.target.error);
|
|
55
|
-
|
|
56
48
|
const os = tx.objectStore(SECTIONS_STORE);
|
|
57
49
|
const clearReq = os.clear();
|
|
58
|
-
|
|
59
50
|
clearReq.onerror = e => reject(e.target.error);
|
|
60
51
|
};
|
|
61
|
-
|
|
62
52
|
openDBRequest.onerror = e => {
|
|
63
53
|
reject(e.target.error);
|
|
64
54
|
};
|
|
65
55
|
});
|
|
66
56
|
};
|
|
57
|
+
|
|
67
58
|
/**
|
|
68
59
|
* Used to clear caches and 'sections-db' IndexedDB when a user logs out or a
|
|
69
60
|
* different user logs in to prevent someone from accessing a different user's
|
|
70
61
|
* caches. Should be able to be used in a non-PWA app.
|
|
71
62
|
*/
|
|
72
|
-
|
|
73
|
-
|
|
74
63
|
async function clearSensitiveCaches() {
|
|
75
64
|
let dbName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : SECTIONS_DB;
|
|
76
65
|
console.debug('Clearing sensitive caches');
|
|
77
|
-
let cacheKeys;
|
|
78
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage
|
|
66
|
+
let cacheKeys;
|
|
79
67
|
|
|
68
|
+
// caches.keys can fail in insecure contexts, see:
|
|
69
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage
|
|
80
70
|
try {
|
|
81
71
|
cacheKeys = await caches.keys();
|
|
82
72
|
} catch (e) {
|
|
83
73
|
// Return false since no caches have been cleared
|
|
84
74
|
return false;
|
|
85
75
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
clearDB(dbName).then(() => false),
|
|
76
|
+
return Promise.all([
|
|
77
|
+
// (Resolves to 'false' because this can't detect if anything was deleted):
|
|
78
|
+
clearDB(dbName).then(() => false),
|
|
79
|
+
// Remove caches if not in keepable list
|
|
89
80
|
...cacheKeys.map(key => {
|
|
90
81
|
if (!KEEPABLE_CACHES.some(pattern => pattern.test(key))) {
|
|
91
82
|
return caches.delete(key);
|
|
92
83
|
}
|
|
93
|
-
|
|
94
84
|
return false;
|
|
95
85
|
})]).then(responses => {
|
|
96
86
|
// Return true if any caches have been cleared
|
|
@@ -5,10 +5,10 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.devDebugLog = devDebugLog;
|
|
7
7
|
const shouldLog = localStorage.getItem('dhis2.debugConnectionStatus');
|
|
8
|
-
|
|
9
8
|
if (shouldLog) {
|
|
10
9
|
console.log('Logging for dhis2ConnectionStatus is enabled. Remove the `dhis2.debugConnectionStatus` item in localStorage to disable logging.');
|
|
11
10
|
}
|
|
11
|
+
|
|
12
12
|
/**
|
|
13
13
|
* This can be used to log info if the `dhis2.debugConnectionStatus` value
|
|
14
14
|
* in localStorage is set to a truthy value during development.
|
|
@@ -17,8 +17,6 @@ if (shouldLog) {
|
|
|
17
17
|
* The behavior of the connection status can be quite hard to inspect without
|
|
18
18
|
* logs, but the logs are quite chatty and should be omitted normally.
|
|
19
19
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
20
|
function devDebugLog() {
|
|
23
21
|
if (shouldLog) {
|
|
24
22
|
console.log(...arguments);
|