-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: dhis2 connection status [LIBS-315] (#1203)
* feat: track dhis2 connection status with hook * feat(offline): ping server for status periodically * fix: use better endpoint * chore: add a comment * fix: file extension * test(offline): add custom data provider to tests * fix: fix tests * chore: satisfy types * feat: useProgressiveInterval hook * feat: use smart intervals in connection status (wip) * fix: pinging, back-off, pausing, fn references * fix: pausing correctly * fix: don't start pinging if window isn't focused * chore: remove unused eslint ignore * feat: add 'invokeCallbackImmediately' fn * feat: ping on network status changes * fix: enter standby when network changes while blurred * chore: format * fix: only ping when going offline to save resources * fix: don't increment delay on immediate cb unless regular timer has elapsed * refactor: smart interval as class * fix: use data engine for pings to avoid rerenders; handle fetch errors * refactor: make class properties private again * feat: handle sw-free conditions; simplify logic * chore: remove interval hook * fix: don't check auth * refactor: use shorter isConnected name * feat: add lastConnected value * fix: await callbacks to reset correct intervals * chore: cleanup * fix: update subscription callback name * refactor: rename to NetworkStatus * refactor: rename type to match NetworkStatus * chore: fix import * chore: other renaming clean-up * chore: bump cli-style version * refactor: rename method for clarity * chore: clarify logs * fix: bump cli-app-scripts version for jest v27 * refactor: use ping query for easier testing * ci: use node 14 * fix: accept header on ping requests * fix: check for err.type instead of err.message * chore: add comment to remove clg * test: fix tests for RestAPILink * chore: prep for tests * test: initial test commit (dirty wip) * refactor: use a `start` method on SmartInterval * fix(smart-interval): delay reset after 'partial standby' * refactor: use a function for smartInterval instead of class * chore: remove comment * test: some more testing attempts (dirty) * refactor: don't await callback * test(dhis2-connection-status): tweak test for smart interval * test: delays in ping interval * refactor: only create smartInterval once * test: resetting ping interval * test: standby behavior * test: offline & refocusing behavior * fix: maintain lastConnected when disconnected during startup * test: lastConnected handling * fix: initialize to correct status based on offline interface * chore: comment updates * fix: set lastConnected if not set yet and starting while offline * test: initialization conditions * chore: remove console log * chore: reorganize tests * test: refactor to generalize to any default values * chore: clean up smartInterval tests * chore: ignore eslint warning * test: fix test for offlineInterface effects * test: refactor to improve assertions on `setTimeout` delays * chore: remove console log * fix: clear lastConnected when online * refactor: setting lastConnected on startup * fix: make lastConnected specific to each app * docs: reorganize and update docs * docs: useDhis2ConnectionStatus * refactor: remove unused function * chore: explanatory comments * docs: clarify importance of useDhis2ConnectionStatus * refactor: only use logs when specified in dev env * fix: allow logging in production env for netlify previews * chore: undo changes from old ping endpoint * fix: migrate to new ping endpoint * chore: remove unused data service from offline service * chore: reorganize connection status dir * fix: don't ping on unsupported server versions * fix: choose default timer values --------- Co-authored-by: Hendrik de Graaf <[email protected]>
- Loading branch information
1 parent
ca52210
commit 6a4156e
Showing
36 changed files
with
7,527 additions
and
5,964 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Offline tools | ||
|
||
!> **WARNING** These features are considered **experimental** and are **subject to breaking changes outside of the normal release cycle.** | ||
|
||
The app platform provides some support for PWA features, including a `manifest.json` file for installability and service worker which can provide offline caching. In addition to those features, the app runtime provides support for ["cacheable sections"](advanced/offline/CacheableSections), which are sections of an app that can be individually cached on-demand. The [`useCacheableSection` hook](advanced/offline/CacheableSections#usecacheablesection-api) and the [`CacheableSection` component](advanced/offline/CacheableSections#cacheablesection-api) provide the controls for the section and the wrapper for the section, respectively. The [`useCachedSections` hook](advanced/offline/CacheableSections#usecachedsections-api) returns a list of sections that are stored in the cache and a function that can delete them. | ||
|
||
An important tool for offline-capable apps is the [`useDhis2ConnectionStatus` hook](advanced/offline/useDhis2ConnectionStatus.md), which can be used to determine whether or not the app can connect to the DHIS2 server. There is also a [`useOnlineStatus` hook](advanced/offline/useOnlineStatus.md) which returns whether or not the client is connected to the internet, but `useDhis2ConnectionStatus` is probably the one you want to use. On instances where DHIS2 is deployed locally in an environment without internet, `useOnlineStatus` can cause problems, because it will always return `false` even though the app can communicate with the DHIS2 server and therefore function just fine. `useDhis2ConnectionStatus` was created to address this problem. | ||
|
||
## Examples | ||
|
||
To see some examples of the APIs in use, see the [PWA example app](https://github.com/dhis2/app-platform/tree/master/examples/pwa-app/src/components/) in the platform repository. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# useDhis2ConnectionStatus | ||
|
||
> This feature can only be used when PWA is enabled in `d2.config.js`. See the [App Platform docs](https://platform.dhis2.nu/#/pwa/pwa) for more information. | ||
This hook is used to detect whether or not the app can connect to the DHIS2 server. This can be useful, for example, to make changes in the UI to prevent the user from taking actions that would cause errors while unable to reach the server. | ||
|
||
It's designed to detect server connection because checking just the internet connection can lead to problems on DHIS2 instances that are implemented offline, where features or actions might be blocked because the device is offline, even though the app can connect to the DHIS2 server just fine. In these cases, what matters is whether or not the app can connect to the DHIS2 server. | ||
|
||
```ts | ||
import { useDhis2ConnectionStatus } from '@dhis2/app-runtime' | ||
|
||
const { isConnected, isDisconnected, lastConnected } = | ||
useDhis2ConnectionStatus() | ||
``` | ||
|
||
## API | ||
|
||
| Property | Type | Description | | ||
| ---------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `isConnected` | `boolean` | Represents whether the app can connect to the DHIS2 server | | ||
| `isDisconnected` | `boolean` | The opposite of `isConnected`. Provided as a convenience value | | ||
| `lastConnected` | `Date` | The last time the app was able to connect to the server, or `null` when `isConnected` is true. See more [below](#lastconnected-details) about details of this value | | ||
|
||
### `lastConnected` details | ||
|
||
The value will be persisted locally so it will be consistent across sessions while disconnected. | ||
|
||
Since we can’t actually detect the ‘lastConnected’ value between sessions, the `lastConnected` value is set to “now” if the app starts up while disconnected from the server and can’t find an existing value stored from previous sessions. | ||
|
||
**Tip!** Given the above caveat, this value is most accurately thought of as “Time since starting to work offline”. | ||
|
||
This value can be specific to each app — make sure the ‘appName’ is set in d2.config.js to enable this. Otherwise it will use a value that’s shared between apps. | ||
|
||
## Design | ||
|
||
This hook is a refinement to `useNetworkStatus`, since it will work for implementations where the server is used locally without internet. | ||
|
||
The `isConnected` value is primarily detected by the service worker, which listens to the incidental network traffic of the app and interprets the value from successes and failures of requests. | ||
|
||
During periods when there’s no network traffic from the app, “pings” will be used **conservatively** to see if the server is reachable. There are several measures taken to limit the usage of these pings: | ||
|
||
- While the connection status is stable, the intervals between pings will increase exponentially up to a long interval. | ||
- Any new network traffic from the app will postpone future pings. | ||
- If the app is not focused, no pings will be sent. | ||
|
||
### Supported versions | ||
|
||
The pings are only sent for server versions that support them, meaning patch versions 2.40.0, 2.39.2, 2.38.3, and 2.37.10. and after. For unsupported versions, the hook will still use the incidental network traffic to determind a connections status value. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# useOnlineStatus | ||
|
||
!> This hook only detects whether or not you're connected to the internet, which could be problematic for DHIS2 instances that are hosted locally or offline, where what really matters is whether or not you can communicate with the DHIS2 server. The [`useDhis2ConnectionStatus` hook](advanced/offline/useDhis2ConnectionStatus) is usually better for that reason, and is therefore recommended. | ||
|
||
The `useOnlineStatus` returns whether the client is online or offline. It debounces the returned values by default to prevent rapid changes of any UI elements that depend on the online status. | ||
|
||
```jsx | ||
import { useOnlineStatus } from '@dhis2/app-runtime' | ||
|
||
const { online, offline } = useOnlineStatus(options) | ||
``` | ||
|
||
The `online` and `offline` return values are booleans, and both are provided for convenience. | ||
|
||
The `options` param is an optional object with the following optional properties: | ||
|
||
| Property | Type | Default | Description | | ||
| --------------- | ------ | ------- | ---------------------------------------------------------------------------------------- | | ||
| `debounceDelay` | Number | `1000` | Duration in ms to debounce changing `online` values. Set it to `0` to remove debouncing. | | ||
|
||
Under the hood, the `online` value is initialized to `navigator.onLine`, then the value changes in response to browser `online` and `offline` events. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.