Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New App Shell #13

Merged
merged 38 commits into from
Oct 2, 2020
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
deca610
Generate the HTML
FlorianRappl Sep 21, 2020
b9ce931
Bringing elementary packages to the core
FlorianRappl Sep 22, 2020
c7831ae
Prepared for exposing packages as shared deps
FlorianRappl Sep 22, 2020
edaa6f3
Merge branch 'feature/app-shell' of github.com:openmrs/openmrs-esm-co…
FlorianRappl Sep 22, 2020
09b0548
Realigned and improved
FlorianRappl Sep 22, 2020
757b6cd
Use default import map and favicon
FlorianRappl Sep 23, 2020
84595eb
Bring api and error-handling to core
FlorianRappl Sep 23, 2020
8e9c180
Enhanced FHIR
FlorianRappl Sep 23, 2020
fd21133
Incldued fihr typings
FlorianRappl Sep 23, 2020
03bdee0
Renamed to config
FlorianRappl Sep 29, 2020
30bd466
Merge branch 'master' of github.com:openmrs/esm-core into feature/app…
FlorianRappl Sep 29, 2020
5fa5d99
Renamed module-config to config
FlorianRappl Sep 29, 2020
4b7979c
Improved sync
FlorianRappl Sep 29, 2020
56c3fdb
Finished debugging
FlorianRappl Sep 30, 2020
0ac488c
Enhanced local settings
FlorianRappl Sep 30, 2020
26da6ec
Refinement
FlorianRappl Sep 30, 2020
ca8c008
Alignment
FlorianRappl Sep 30, 2020
423320a
Final alignment of basis
FlorianRappl Sep 30, 2020
8c89689
Merge branch 'master' of github.com:openmrs/esm-core into feature/app…
FlorianRappl Sep 30, 2020
a4e29ea
Merged with latest changes
FlorianRappl Sep 30, 2020
5cc5f1d
Prettified
FlorianRappl Oct 1, 2020
a6b98f0
Prepare for openmrs run command
FlorianRappl Oct 1, 2020
7d38e73
Changed version number
FlorianRappl Oct 1, 2020
ecd2d07
Reordered deps
FlorianRappl Oct 1, 2020
6c525fc
Removed prepublishOnly script
FlorianRappl Oct 1, 2020
1da919a
Updated dep version
FlorianRappl Oct 1, 2020
eeb254d
Rewired postcss
FlorianRappl Oct 1, 2020
6b1ed3f
Improved webpack
FlorianRappl Oct 1, 2020
597cb5c
Use submodule for running
FlorianRappl Oct 1, 2020
8ca75b8
Adjusted for deployment; only need to publish app shell
FlorianRappl Oct 1, 2020
281f323
Added backend parameter
FlorianRappl Oct 1, 2020
008e9b5
Updated with importmap flag
FlorianRappl Oct 1, 2020
c055f66
Changed to better i18n backend see #14
FlorianRappl Oct 1, 2020
3479899
Review comments
FlorianRappl Oct 1, 2020
83d3c38
Review comments
FlorianRappl Oct 1, 2020
27bd5e5
Merge branch 'master' of github.com:openmrs/esm-core into feature/app…
FlorianRappl Oct 1, 2020
9194829
Warn if importmap seems wrong
FlorianRappl Oct 1, 2020
4843475
Prettified
FlorianRappl Oct 1, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,5 @@ dist
*.iml
.idea/

docs/
docs/
storybook-static
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
dist/
README.md
docs/
docs/
packages/esm-styleguide/src/buttons-and-links/buttons-and-links.stories.html
brandones marked this conversation as resolved.
Show resolved Hide resolved
19 changes: 5 additions & 14 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ script:
- npx lerna bootstrap
- npx lerna run lint
- npx lerna run test
- npx lerna run build
- npx lerna run typescript
- npx lerna run build
- echo "Folder name in Digital Ocean Spaces - $TRAVIS_COMMIT"
- mkdir -p dist/@openmrs/esm-module-config/$TRAVIS_COMMIT
- mv packages/esm-config/dist/*.* dist/@openmrs/esm-module-config/$TRAVIS_COMMIT/
- mkdir -p dist/@openmrs/esm-extension-manager/$TRAVIS_COMMIT
- mv packages/esm-extension-manager/dist/*.* dist/@openmrs/esm-extension-manager/$TRAVIS_COMMIT/
- mkdir -p dist/@openmrs/esm-app-shell/$TRAVIS_COMMIT
- mkdir -p dist/@openmrs/esm-app-shell/latest
- cp packages/esm-app-shell/dist/*.* dist/@openmrs/esm-app-shell/$TRAVIS_COMMIT/
- cp packages/esm-app-shell/dist/*.* dist/@openmrs/esm-app-shell/latest/
deploy:
provider: s3
access_key_id: "$DIGITAL_OCEAN_SPACES_KEY_ID"
Expand All @@ -24,12 +24,3 @@ deploy:
acl: public_read
on:
branch: master
after_deploy:
- echo "Updating import map to point to new version of @openmrs/esm-extension-manager"
- statuscode=$(curl --output /dev/null --write-out %{http_code} -u $DEPLOYER_USERNAME:$DEPLOYER_PASSWORD -d '{ "service":"@openmrs/esm-extension-manager","url":"https://spa-modules.nyc3.digitaloceanspaces.com/@openmrs/esm-extension-manager/'$TRAVIS_COMMIT'/openmrs-esm-extension-manager.js" }' -X PATCH $DEPLOYER_HOST/services\?env=prod -H "Accept:application/json" -H "Content-Type:application/json")
- echo "Deployment Status Code (esm-extension-manager) --> ${statuscode}"
- if [ "$statuscode" -ne 200 ]; then travis_terminate "$statuscode"; fi
- echo "Updating import map to point to new version of @openmrs/esm-module-config"
- statuscode=$(curl --output /dev/null --write-out %{http_code} -u $DEPLOYER_USERNAME:$DEPLOYER_PASSWORD -d '{ "service":"@openmrs/esm-module-config","url":"https://spa-modules.nyc3.digitaloceanspaces.com/@openmrs/esm-module-config/'$TRAVIS_COMMIT'/openmrs-esm-module-config.js" }' -X PATCH $DEPLOYER_HOST/services\?env=prod -H "Accept:application/json" -H "Content-Type:application/json")
- echo "Deployment Status Code (esm-config) --> ${statuscode}"
- if [ "$statuscode" -ne 200 ]; then travis_terminate "$statuscode"; fi
43 changes: 35 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,46 @@
# OpenMRS Frontend Core

This is a [Lerna](https://lerna.js.org/) project containing the core
packages for the OpenMRS Frontend. These packages handle the
"cross-cutting concerns" described in the
[Domain Decomposition](https://wiki.openmrs.org/display/projects/MFE+Domain+Decomposition)
document.
This is a [Lerna](https://lerna.js.org/) project containing the core packages for the OpenMRS Frontend. These packages handle the "cross-cutting concerns" described in the [Domain Decomposition](https://wiki.openmrs.org/display/projects/MFE+Domain+Decomposition) document.

- [@openmrs/esm-api](packages/esm-api)
- [@openmrs/esm-app-shell](packages/esm-app-shell)
- [@openmrs/esm-config](packages/esm-config)
- [@openmrs/esm-error-handling](packages/esm-error-handling)
- [@openmrs/esm-extension-manager](packages/esm-extension-manager)
- [@openmrs/esm-styleguide](packages/esm-styleguide)

## Getting Started

To install and setup the repository just use the following command:

```sh
npx lerna bootstrap
```

For working with the app shell you don't need to have the repository cloned. You can also just use the `run-openmrs` directly.

```sh
npx run-openmrs
```
npm install -g lerna
npm install
lerna bootstrap

This is a command line utility for running (or building) the app shell in isolation. In particular, it deals with everything that touches the development, distribution, and deployment of an app shell.

## Possibilities

The new architecture offers a couple of interesting possibilities. We go into them one by one.

### Proxying OpenMRS Backends

We can now proxy *any* backend. For instance, using the backend of the demo instance we just run:

```sh
npx run-openmrs debug --backend https://demo.openmrs.org/
```

There are a couple of interesting public instances:

```sh
https://qa-refapp.openmrs.org/
https://demo.openmrs.org/
https://openmrs-spa.org/
```
21 changes: 17 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@
"private": true,
"husky": {
"hooks": {
"pre-commit": "pretty-quick --staged && concurrently -n lint,test,typescript 'lerna run lint' 'lerna run test' 'lerna run typescript'"
"pre-commit": "pretty-quick --staged && lerna run lint && lerna run test && lerna run typescript"
}
},
"workspaces": [
"packages/*"
],
"scripts": {
"run:shell": "lerna run watch --scope @openmrs/esm-app-shell --stream",
"run:omrs": "run-openmrs",
"verify": "lerna run lint && lerna run test && lerna run typescript",
"prettier": "prettier 'packages/**/src/**/*' --write"
},
"devDependencies": {
"@types/jest": "^26.0.10",
"@babel/core": "^7.11.4",
"@babel/preset-env": "^7.11.0",
"@babel/preset-react": "^7.10.4",
Expand All @@ -22,23 +24,34 @@
"@testing-library/jest-dom": "^5.11.0",
"@testing-library/react": "^10.4.3",
"@testing-library/user-event": "^12.0.11",
"@types/jest": "^26.0.10",
"autoprefixer": "^9.6.1",
"browserslist-config-openmrs": "^1.0.1",
"babel-eslint": "^11.0.0-beta.2",
"babel-jest": "^26.3.0",
"babel-loader": "^8.1.0",
"clean-webpack-plugin": "^3.0.0",
"concurrently": "^5.3.0",
"eslint": "^7.7.0",
"copy-webpack-plugin": "6.1.1",
"css-loader": "^3.2.0",
"cssnano": "^4.1.10",
"ejs": "^2.6.2",
"eslint": "^7.10.0",
"eslint-config-prettier": "^6.11.0",
"eslint-config-ts-react-important-stuff": "^3.0.0",
"eslint-plugin-prettier": "^3.1.4",
"file-loader": "^4.2.0",
"fork-ts-checker-webpack-plugin": "^5.1.0",
"html-webpack-plugin": "^4.5.0",
"husky": "^4.2.5",
"jest": "^26.4.2",
"jest-cli": "^26.4.2",
"lerna": "^3.20.2",
"mini-css-extract-plugin": "^0.8.0",
"postcss-loader": "^4.0.2",
"prettier": "^2.0.5",
"pretty-quick": "^3.0.0",
"raw-loader": "^3.1.0",
"style-loader": "^1.0.0",
"ts-loader": "^8.0.3",
"typescript": "^4.0.2",
"webpack": "^4.44.1",
Expand Down
7 changes: 7 additions & 0 deletions packages/esm-api/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-typescript",
"@babel/preset-react"
]
}
28 changes: 28 additions & 0 deletions packages/esm-api/.travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
language: node_js
node_js:
- node
script:
- npm run lint
- npm test
- npm run typescript
- npm run build
- echo "Folder name in Digital Ocean Spaces - $TRAVIS_COMMIT"
- mkdir -p dist/@openmrs/esm-api/$TRAVIS_COMMIT
- mv dist/*.* dist/@openmrs/esm-api/$TRAVIS_COMMIT/
deploy:
provider: s3
access_key_id: "$DIGITAL_OCEAN_SPACES_KEY_ID"
secret_access_key: "$DIGITAL_OCEAN_SPACES_ACCESS_KEY"
bucket: "$DIGITAL_OCEAN_SPACES_BUCKET"
endpoint: "$DIGITAL_OCEAN_SPACES_ENDPOINT"
cache-control: "max-age=31536000"
local_dir: dist
skip_cleanup: true
acl: public_read
on:
branch: master
after_deploy:
- echo "Updating import map to point to new version of @openmrs/esm-api"
- statuscode=$(curl --output /dev/null --write-out %{http_code} -u $DEPLOYER_USERNAME:$DEPLOYER_PASSWORD -d '{ "service":"@openmrs/esm-api","url":"https://spa-modules.nyc3.digitaloceanspaces.com/@openmrs/esm-api/'$TRAVIS_COMMIT'/openmrs-esm-api.js" }' -X PATCH $DEPLOYER_HOST/services\?env=prod -H "Accept:application/json" -H "Content-Type:application/json")
- echo "Deployment Status Code --> ${statuscode}"
- if [ "$statuscode" -ne 200 ]; then travis_terminate "$statuscode"; fi
144 changes: 144 additions & 0 deletions packages/esm-api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# openmrs-esm-api
[![Build Status](https://travis-ci.org/openmrs/openmrs-esm-api.svg?branch=master)](https://travis-ci.org/openmrs/openmrs-esm-api)

An [OpenMRS Microfrontend](https://wiki.openmrs.org/display/projects/Frontend+-+SPA+and+Microfrontends).

## What is this?

openmrs-esm-api is an [in-browser javascript module](https://github.com/openmrs/openmrs-rfc-frontend/blob/master/text/0002-modules.md) that exports functions that interact with the OpenMRS API.

## How do I use it?

```js
import { openmrsFetch, openmrsObservableFetch, getCurrentUser, fhir } from '@openmrs/esm-api';
openmrsFetch('/ws/rest/v1/session').then(response => {
console.log(response.data.authenticated)
}
```

## Contributing / Development

[Instructions for local development](https://wiki.openmrs.org/display/projects/Setup+local+development+environment+for+OpenMRS+SPA)

## API

The following functions are exported from the @openmrs/esm-api module:

## openmrsFetch(url, init): Promise

The openmrsFetch function is a wrapper around the [browser's built-in fetch function](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch), with extra handling for OpenMRS-specific API behaviors, such as request headers, authentication, authorization, and the API urls.

##### Arguments

1. url (required): A string url to make the request to. Note that the openmrs base url (by default "/openmrs") will be automatically prepended to the URL, so there is no need to include it.
2. init (optional): A [fetch init object](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Syntax). Note that the `body` property does not need to be JSON.stringify()'ed because openmrsFetch will do that for you.

##### Return value

A [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) that resolves with a [Response object](https://developer.mozilla.org/en-US/docs/Web/API/Response). Note that the openmrs version of the Response object has already downloaded the HTTP response body as json, and has an additional `data` property with the HTTP response json as a javascript object.

### Example

```js
import { openmrsFetch } from '@openmrs/esm-api'
const abortController = new AbortController();
openmrsFetch('/ws/rest/v1/session', {signal: abortController.signal})
.then(response => {
console.log(response.data.authenticated)
})
.catch(err => {
console.error(err.status);
})
abortController.abort();
openmrsFetch('/ws/rest/v1/session', {
method: 'POST',
body: {
username: 'hi',
password: 'there',
}
})
```

### Cancellation

To cancel a network request, use an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort). It is best practice to cancel your network requests when the user navigates away from a page while the request is pending request, to free up memory and network resources and to prevent race conditions.

## openmrsObservableFetch(url, init): Observable

The openmrsObservableFetch function is a wrapper around openmrsFetch that returns an [Observable](https://rxjs-dev.firebaseapp.com/guide/observable) instead of a promise. It exists in case using an Observable is preferred or more convenient than a promise.

##### Arguments

The arguments to openmrsObservableFetch are exactly the same as the arguments to openmrsFetch.

##### Return value

An Observable that produces exactly one Response object. The response object is exactly the same as for openmrsFetch.

### Example

```js
import { openmrsObservableFetch } from '@openmrs/esm-api'
const subscription = openmrsObservableFetch('/ws/rest/v1/session').subscribe(
response => console.log(response.data),
err => {throw err},
() => console.log('finished')
)
subscription.unsubscribe()
```

### Cancellation

To cancel the network request, simply call `subscription.unsubscribe();`

## fhir

The `fhir` object is [an instance of fhir.js](https://github.com/FHIR/fhir.js) that can be used to call FHIR-compliant OpenMRS APIs. See [the docs for fhir.js](https://github.com/FHIR/fhir.js) for more info and example usage.

## getCurrentUser(): Observable

The getCurrentUser function returns an observable that produces **zero or more values, over time**. It will produce zero values by default if the user is not logged in. And it will provide a first value when the logged in user is fetched from the server. Subsequent values will be produced whenever the user object is updated.

###### Arguments

1. options (optional): An object with includeAuthStatus boolean property that defaults to false. When includeAuthStatus is set to true, the entire response object from the API will be provided. When includeAuthStatus is set to false, only the user property of the response object will be provided.

###### Return value

An Observable that produces zero or more values (as described above). The values produced will be a user object (if includeAuthStatus is set to false) or an object with a session and authenticated property (if includeAuthStatus is set to true).

### Example

```js
import { getCurrentUser } from '@openmrs/esm-api'
const subscription = getCurrentUser().subscribe(
user => console.log(user)
)
subscription.unsubscribe()
getCurrentUser({includeAuthStatus: true}).subscribe(
data => console.log(data.authenticated)
)
```

### Be sure to unsubscribe when your component unmounts

Otherwise your code will continue getting updates to the user object even after the UI component is gone from the screen. This is a memory leak and source of bugs.

## refetchCurrentUser(): Observable

The refetchCurrentUser function causes a network request to redownload the user. All subscribers to the current user will be notified of the new users once the new version of the user object is downloaded.

###### Arguments

None

###### Return value

An observable exactly the same as if you had called `getCurrentUser()`.

#### Example

```js
import { refetchCurrentUser } from '@openmrs/esm-api'
refetchCurrentUser()
```
2 changes: 2 additions & 0 deletions packages/esm-api/__mocks__/openmrs-esm-error-handling.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export function createErrorHandler() {}
export function reportError() {}
5 changes: 5 additions & 0 deletions packages/esm-api/__mocks__/openmrs-esm-module-config.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const defineConfigSchema = jest.fn();

export const getConfig = jest
.fn()
.mockResolvedValue({ redirectAuthFailure: { enabled: false } });
1 change: 1 addition & 0 deletions packages/esm-api/__mocks__/single-spa.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const navigateToUrl = jest.fn();
13 changes: 13 additions & 0 deletions packages/esm-api/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = {
transform: {
"^.+\\.tsx?$": "babel-jest",
},
moduleNameMapper: {
"lodash-es": "lodash",
"@openmrs/esm-error-handling":
"<rootDir>/__mocks__/openmrs-esm-error-handling.mock.ts",
"@openmrs/esm-config":
"<rootDir>/__mocks__/openmrs-esm-module-config.mock.ts",
"single-spa": "<rootDir>/__mocks__/single-spa.mock.ts",
},
};
Loading