Skip to content

Commit

Permalink
Merge branch 'alpha' into LIBS-397/plugin-wrappers-sender
Browse files Browse the repository at this point in the history
  • Loading branch information
tomzemp committed Mar 13, 2023
2 parents c537590 + ce16f9e commit 41124e8
Show file tree
Hide file tree
Showing 43 changed files with 7,997 additions and 5,948 deletions.
40 changes: 40 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Implements [LIBS-XXXX](https://dhis2.atlassian.net/browse/LIBS-XXXX)

---

### Key features

<!-- Remove if not applicable -->

1. _feature_

---

### Description

_text_

---

### Checklist

- [ ] Have written Documentation
- _If not needed, explain why, otherwise remove this bullet point_
- [ ] Has tests coverage
- _If not needed, explain why, otherwise remove this bullet point_

---

### Known issues

<!-- Remove if not applicable -->

- _issue_

---

### Screenshots

<!-- Remove if not applicable -->

_supporting text_
2 changes: 1 addition & 1 deletion .github/workflows/dhis2-deploy-netlify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12.x
node-version: 14.x

- uses: c-hive/gha-yarn-cache@v1
- run: yarn install --frozen-lockfile
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/dhis2-verify-lib.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12.x
node-version: 14.x

- uses: actions/cache@v2
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
Expand All @@ -44,7 +44,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12.x
node-version: 14.x

- uses: actions/cache@v2
id: yarn-cache
Expand All @@ -71,7 +71,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12.x
node-version: 14.x

- uses: actions/cache@v2
id: yarn-cache
Expand All @@ -98,7 +98,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12.x
node-version: 14.x

- uses: actions/cache@v2
id: yarn-cache
Expand All @@ -123,7 +123,7 @@ jobs:
token: ${{env.GH_TOKEN}}
- uses: actions/setup-node@v1
with:
node-version: 12.x
node-version: 14.x

- uses: actions/download-artifact@v2
with:
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# [3.9.0](https://github.com/dhis2/app-runtime/compare/v3.8.0...v3.9.0) (2023-03-02)


### Features

* dhis2 connection status [LIBS-315] ([#1203](https://github.com/dhis2/app-runtime/issues/1203)) ([6a4156e](https://github.com/dhis2/app-runtime/commit/6a4156e26b14c0f838bc02d69d0879826f342277))

# [3.8.0](https://github.com/dhis2/app-runtime/compare/v3.7.0...v3.8.0) (2023-01-19)


### Features

* add hook to adjust for server time [LIBS-396] ([#1308](https://github.com/dhis2/app-runtime/issues/1308)) ([d511303](https://github.com/dhis2/app-runtime/commit/d51130336ce8ada00ef5e79884263c678e252302))

# [3.7.0](https://github.com/dhis2/app-runtime/compare/v3.6.2...v3.7.0) (2022-11-17)


Expand Down
6 changes: 5 additions & 1 deletion docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- [useDataEngine](hooks/useDataEngine)
- [useAlert](hooks/useAlert)
- [useAlerts](hooks/useAlerts)
- [useTimeZoneConversion](hooks/useTimeZoneConversion)
- [**Components**](components/)
- [DataQuery](components/DataQuery)
- [DataMutation](components/DataMutation)
Expand All @@ -22,7 +23,10 @@

- **Advanced**

- [Offline tools](advanced/offline)
- [Offline tools](advanced/offline/)
- [Cacheable Sections](advanced/offline/CacheableSections.md)
- [useDhis2ConnectionStatus](advanced/offline/useDhis2ConnectionStatus.md)
- [useOnlineStatus](advanced/offline/useOnlineStatus.md)
- [Services](advanced/services)
- [Data Engine](advanced/DataEngine)
- [Links](advanced/DataEngineLinks)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,22 @@
# Offline tools
# Cacheable sections

!> **WARNING** These features are considered **experimental** and are **subject to breaking changes outside of the normal release cycle.**
> 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.
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", which are sections of an app that can be individually cached on-demand. The [`useCacheableSection`](#usecacheablesection-api) hook and the [`CacheableSection`](#cacheablesection-api) component provide the controls for the section and the wrapper for the section, respectively. The [`useCachedSections`](#usecachedsections-api) hook returns a list of sections that are stored in the cache and a function that can delete them.
The [`useCacheableSection` hook](#usecacheablesection-api) and the [`CacheableSection` component](#cacheablesection-api) provide the controls for the section and the wrapper for the section, respectively. The [`useCachedSections` hook](#usecachedsections-api) returns a list of sections that are stored in the cache and a function that can delete them.

There is also a [`useOnlineStatus`](#online-status) hook which returns the online or offline status of the client.
These features are supported by an `<OfflineProvider>` component which the app platform provides to the app.

To see a good example of these functions' APIs and their usage, see `SectionWrapper.js` in the [PWA example app](https://github.com/dhis2/app-platform/tree/master/examples/pwa-app/src/components/SectionWrapper.js) in the platform repository.

## Cacheable sections

> 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.
These features are supported by an `<OfflineProvider>` component which the app platform provides to the app.

### How it works
## How it works

Cacheable sections enable sections of an app to be individually cached offline on demand. Using the `CacheableSection` wrapper and the `useCacheableSection` hook, when a user requests a section to be cached for offline use, the section's component tree will rerender, and the app's service worker will listen to all the network traffic for the component to cache it offline. To avoid caching that components' data before a user requests to do so, you can use the [URL filters feature](https://platform.dhis2.nu/#/pwa/pwa?id=opting-in) in `d2.config.js`.

Note that, without using these features, an app using offline caching will cache all the data that is requested by user as they use the app without needing to use cacheable sections.

Keep an eye out for this feature in use in the Dashboards app coming soon!

### Usage
## Usage

Wrap the component to be cached in a `CacheableSection` hook, providing an `id` and `loadingMask` prop. The loading mask should block the screen from interaction, and it will be rendered while the component is in 'recording mode'. Note that the `useCacheableSection` hook _does not need to be used in the same component_ as the `<CacheableSection>`, they just need to use the same `id`. There is an example of this in the file linked below.

Expand Down Expand Up @@ -57,15 +51,15 @@ export function CacheableSectionWrapper({ id }) {
}
```

#### `CacheableSection` API
### `CacheableSection` API

| Prop | Type | Required? | Description |
| ------------- | --------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | Component | Yes | Section that will be cached upon recording |
| `id` | String | Yes | ID of the section to be cached. Should match the ID used in the `useCacheableSection` hook. |
| `loadingMask` | Component | Yes | A UI mask that should block the screen from interaction. While the component is rerendering and recording, this mask will be rendered to block user interaction which may interfere with the recorded data. |

#### `useCacheableSection` API
### `useCacheableSection` API

```jsx
import { useCacheableSections } from '@dhis2/app-runtime'
Expand All @@ -86,7 +80,7 @@ function DemoComponent() {
| `isCached` | Boolean | `true` if this section is in offline storage; Provided for convenience. |
| `recordingState` | String | One of `'default'`, `'pending'`, `'recording'`, or `'error'`. Under the hood, the `CacheableSection` component changes how its children are rendered based on the states. They are returned here in case an app wants to change UI or behavior based on the recording state. |

#### `startRecording` API
### `startRecording` API

The `startRecording` function returned by `useCacheableSection` returns a promise that resolves if 'start recording' signal is sent successfully or rejects if there is an error with the offline interface initiating recording. It accepts an `options` parameter with the following optional properties:

Expand Down Expand Up @@ -123,7 +117,7 @@ function StartRecordingButton({ id }) {
}
```

#### `useCachedSections` API
### `useCachedSections` API

The `useCachedSections` hook returns a list of all the sections that are cached, which can be useful if an app needs to manage that whole list at once. It takes no arguments and it returns an object with the following properties:

Expand All @@ -132,23 +126,3 @@ The `useCachedSections` hook returns a list of all the sections that are cached,
| `cachedSections` | Object | An object of cached sections' statuses, where the keys are the section IDs and the values are objects with a `lastUpdated` property that holds a `Date` object reflecting the time this section was last updated. |
| `removeById` | Function | Receives an `id` parameter and attempts to remove the section with that ID from the offline cache. If successful, updates the cached sections list. Returns a promise that resolves to `true` if that section is successfully removed or `false` if a section with that ID was not found. |
| `syncCachedSections` | Function | Syncs the list of cached sections with the list in IndexedDB. Returns a promise. This is handled by the `removeById` function and is probably not necessary to use in most applications. |

## Online status

The `useOnlineStatus` returns the client's online or offline status. It debounces the 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. In the future, the hook may use periodic server pings to detect online status.
11 changes: 11 additions & 0 deletions docs/advanced/offline/README.md
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.
48 changes: 48 additions & 0 deletions docs/advanced/offline/useDhis2ConnectionStatus.md
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.
21 changes: 21 additions & 0 deletions docs/advanced/offline/useOnlineStatus.md
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.
Loading

0 comments on commit 41124e8

Please sign in to comment.