├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── rfc-template.md └── text ├── 0001-single-page-applications.md ├── 0002-modules.md ├── 0003-browser-support.md ├── 0004-import-maps.md ├── 0005-migrating-from-jsps-gsps.md ├── 0008-styleguide.md ├── 0010-design-libraries.md ├── 0012-styleguide-javascript-components.md ├── 0013-api-calls-and-fhir.md ├── 0014-configuration.md ├── 0015-usability-testing.md ├── 0019-issue-tracking-and-documentation.md ├── 0020-contributing-guidelines.md ├── 0021-versioning-releases.md ├── 0022-versions.md ├── 0023-readme.md ├── 0026-activation-distribution.md ├── 0027-extensions.md ├── 0028-data-updates.md ├── 0030-link-system.md └── 0031-version-tracking.md /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenMRS Frontend RFC 2 | The OpenMRS Frontend RFC (Request for Comments) is a git repository where the technologies and processes that apply to all 3 | new OpenMRS distributions are explained. 4 | 5 | ## Purpose 6 | 1. Provide a way to enact change in the OpenMRS frontend. 7 | 2. Clarify what things we are aligned on across all of OpenMRS, so that everything else can be decided by the individual modules and distributions. 8 | 9 | ## What this isn't 10 | 1. An infringement on the autonomy of distribution maintainers. The idea is that if we're aligned on the few important things, we can be autonomous on everything else. 11 | 2. Something oppressively prescriptive. 12 | 3. A technical review process where people get feedback on difficult problems they're facing. Although important, the RFC is not how 13 | technical reviews happen. 14 | 4. A list of technical debt initiatives. This RFC explains the decisions we've made as a group for frontend, but doesn't track the progress of those decisions. 15 | 16 | ## Signs that this is working 17 | 1. The content is up-to-date and people care about it. 18 | 2. Things are removed when no longer relevant or correct. 19 | 3. We change the process when it's annoying or doesn't work well. 20 | 4. Ideas have a safe place to develop before being criticized. 21 | 22 | ## Signs that this isn't working 23 | 1. This blocks people from getting stuff done. 24 | 2. Ivory tower gatekeeping. 25 | 3. Changes are discouraged instead of encouraged. 26 | 4. "Well that's just the way it is." 27 | 5. The process is heavy, bureaucratic, or long. 28 | 6. Some *other* process is being used to achieve the same thing. 29 | 30 | ## What to do if the RFC isn't working 31 | Propose a change to the process! 32 | 33 | ## Process for change 34 | **Anyone** can propose a change. 35 | 36 | 37 | 38 | ### Step 1 - Idea 39 | During the idea phase, we should encourage instead of critique. A person can use the OpenMRS slack workspace, IRC, or Talk forum 40 | to discuss, clarify, and foster an idea. We should examine with an open mind the pros and cons, options, and implementation. 41 | 42 | Another part of the idea phase is asking the question "Should this be autonomous to the distributions or enforced consistently in all distributions?" 43 | 44 | ### Step 2 - Proposal 45 | A proposal is a pull request to this git repository. The proposal should follow the [RFC template](/rfc-template.md). 46 | Here, an idea is debated and discussed by anyone who wants to participate. 47 | Reviewers can make comments asking for changes or they can challenge the basis of the proposal. 48 | 49 | If a pull request becomes stale (not updated or talked about after a fewish weeks), close it. 50 | 51 | ### Step 3 - Approval 52 | Once the author and reviewers have commented and the discussion and proposal have stabilized, the proposal will be merged or closed. 53 | Approval must be given by three members of the "microfrontends squad" (as defined below) must indicate on the PR that they approve. 54 | 55 | Current members of the microfrontends squad are [listed on the GitHub members page](https://github.com/orgs/openmrs/teams/microfrontends-squad/members). More infos are also available [in the OpenMRS wiki](https://wiki.openmrs.org/display/projects/Frontend+-+SPA+and+Microfrontends). 56 | 57 | Other groups who'd like to participate in the microfrontends squad can contact the squad on the [Slack channel #microfrontend](https://slack.openmrs.org/). 58 | 59 | ### Step 4 - Implementation 60 | Once a proposal is merged, it is now part of the RFC. This means that we intend to implement what is described in the RFC. The changes or additions to 61 | the RFC apply to the whole frontend and we should make whatever changes are needed to our code, processes, and organization. 62 | -------------------------------------------------------------------------------- /rfc-template.md: -------------------------------------------------------------------------------- 1 | # Project title 2 | - Start Date: YYYY/MM/DD 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/1 4 | 5 | ## Decision, including impact on distributions 6 | Example: 7 | All distributions and modules should use the @open-mrs/auth module for authenticating requests to the backend REST API. 8 | 9 | Example: 10 | Each distribution can choose its own CSS libraries for the modules they maintain. 11 | 12 | ## Definition 13 | Define terms here and explain what the "how does this apply to distributions" decision means. 14 | 15 | ## Reason for decision 16 | - Bullet points that explain things. 17 | - It's good to link to things, too, if there are relevant things. 18 | 19 | ## Alternatives 20 | Explaining the alternatives gives nuance to the decision and shows we considered more than one option. 21 | 22 | ## Common practices (not enforced) 23 | - A chance to give some comments on popular practices used for OpenMRS and its distributions. 24 | - A chance to opine on some things related to this. -------------------------------------------------------------------------------- /text/0001-single-page-applications.md: -------------------------------------------------------------------------------- 1 | # Single Page Applications 2 | - Start Date: 2019/04/23 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/1 4 | 5 | ## Decision, including impact on distributions 6 | Core OpenMRS frontend modules will be implemented within a master single page application. Distributions are encouraged 7 | to add modules to the master single page application. Older OpenMRS modules implemented with JSPs and GSPs are not addressed in this 8 | proposal, but will be covered in another one. 9 | 10 | The code for the master single page application is hosted at https://github.com/openmrs/openmrs-module-spa. 11 | 12 | ## Definition 13 | A [single page application (SPA)](https://en.wikipedia.org/wiki/Single-page_application) is a frontend application that does not 14 | reload the page when the user navigates. This is accomplished by having only one full html file, using the 15 | [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API), and by making 16 | [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) or [AJAX](https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX) requests 17 | to retrieve data from the backend. 18 | 19 | ## Reason for decision 20 | - SPAs are the industry standard for large web apps. 21 | - SPAs are often faster for users that visit many pages within an app. You pay an upfront performance cost with the initial load time, in order to avoid 22 | subsequent page reloads. 23 | - A shared SPA sets up OpenMRS for a cohesive codebase and UX. 24 | - The tooling and developer experience for SPAs is preferred over server rendered pages. 25 | 26 | ## Alternatives 27 | One alternative to SPAs is server rendered HTML files for each frontend route. This means that the page reloads whenever the user navigates. 28 | Server rendered HTML pages can be implemented with technologies such as JSPs, GSPs, and a variety of other tools. They are often better for 29 | Search Engine Optimization (SEO) and can rely on native browser form submission instead of Fetch/AJAX to communicate with the backend. Server 30 | rendered HTML files often have faster initial load times than SPAs, because the browser can create DOM elements without waiting on client-side 31 | javascript. Additionally, server rendered pages often require far less frontend javascript code to work properly. 32 | 33 | Another alternative is to have multiple SPAs instead of one SPA. See 34 | [this discussion](https://github.com/openmrs/openmrs-rfc-frontend/pull/1#discussion_r279612852) for some discussion of pros and cons for it. 35 | An advantage of multiple SPAs is that it does not require trying to get multiple 36 | separate apps working within a single page, nor multiple frameworks coexisting within a single page. Additionally, sometimes a page reload 37 | can help free memory from a runaway browser tab. The main disadvantage of multiple SPAs is that there is a page reload between the pages, 38 | and that frequent page reloads exacerbate the downsides of SPAs. Additionally, it is harder to guarantee that shared code between SPAs 39 | is always exactly the same and up-to-date, since each HTML file can include whichever libraries it wants to. 40 | 41 | ## Common practices (not enforced) 42 | - [Configure your backend server](https://blog.pshrmn.com/entry/single-page-applications-and-the-server/) to interoperate with SPAs. 43 | - Use a frontend router library (such as [react-router](https://reacttraining.com/react-router/), [@angular/router](https://angular.io/guide/router), 44 | and [vue-router](https://router.vuejs.org/)) to help you implement your single page application. These libraries take care of changing frontend urls 45 | without reloading the page. -------------------------------------------------------------------------------- /text/0002-modules.md: -------------------------------------------------------------------------------- 1 | # Modules 2 | - Start Date: 2019/04/29 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/2 4 | 5 | ## Decision, including impact on distributions 6 | In-browser Javascript modules are the OpenMRS mechanism for adding functionality and creating frontend code for distributions. 7 | Since modules are not yet fully supported in all browsers, OpenMRS uses SystemJS as its in-browser module loader. 8 | 9 | ## Definition 10 | A [javascript module](https://www.sitepoint.com/understanding-es6-modules/) is a new kind of javascript file that 11 | can [import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) and 12 | [export](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export) data and logic from other modules. 13 | Variables within a module are not global-by-default and are not accessible to other javascript code unless explicitly 14 | exported. 15 | 16 | Javascript modules are also known as ECMAScript modules, ES modules, ESM, ES2015 modules, or ES6 modules. 17 | 18 | An in-browser javascript module is a javascript module that is downloaded in the browser. This is different from 19 | build-time modules, which are compiled down so that they know longer use `import` or `export` by the time they 20 | are executed in the browser. Most major frameworks (React, Vue, Angular, etc) always use build-time modules, but do not 21 | always use in-browser modules. At OpenMRS, we use both. 22 | 23 | In-browser javascript modules are downloaded with one network request per module. Build-time modules are compiled away such 24 | that there is only one network request for a whole group (bundle) of build-time modules. 25 | 26 | [Basic browser support for modules](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export#Browser_compatibility) 27 | started in Chrome 61, Firefox 60, Edge 16, and Safari 10.1. There are advanced module features, such as import maps, that are not yet 28 | supported in any browser. Internet Explorer does not have any support for modules. 29 | 30 | A [module loader](https://www.jvandemo.com/a-10-minute-primer-to-javascript-modules-module-formats-module-loaders-and-module-bundlers/) is 31 | a javascript library that allows you to use modules in a browser that does not support them. This makes it possible for us to use both basic and advanced 32 | module features in all browsers. 33 | 34 | [SystemJS](https://github.com/systemjs/systemjs) is a minimalistic module loader that 35 | [polyfills](https://en.wikipedia.org/wiki/Polyfill_(programming)) modules so that you can use them in older browsers. 36 | When browsers fully support modules, the browser will be able to do what SystemJS is currently doing for us. 37 | 38 | ## Reason for decision 39 | - Modules are a built-in programming language feature that allows us to easily extend the OpenMRS frontend. 40 | - Modules allow distribution implementors and maintainers to extend OpenMRS functionality via a browser spec, instead of something 41 | OpenMRS-specific. This means that the process for extending OpenMRS is better understood and more approachable for frontend developers. 42 | - Modules create better [separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns), since dependencies 43 | between modules are explicit and do not rely on global variables. 44 | - Modules can be lazy loaded, or not loaded at all. This allows OpenMRS distributions to choose which modules they wish 45 | to include in their code. 46 | 47 | ## Alternatives 48 | Instead of using both in-browser modules and build-time modules, we could use build-time modules exclusively. This would 49 | simplify some things, but would mean that all frontend code would have to go through a single build process, which would be 50 | very difficult to get working when supporting multiple frameworks and codebases. 51 | 52 | Another alternative is to use neither in-browser modules nor build-time modules. This is how much Javascript code is still 53 | written, including all existing OpenMRS JSPs and GSPs. Not using modules makes it a lot more difficult to build an extensible frontend, 54 | since you ultimately must rely on load-order and global variables for code to interact with each other. 55 | Dependencies between global variables are not explicit and harder to manage. 56 | 57 | ## Common practices (not enforced) 58 | - Use build-time modules liberally, to better organize your code. 59 | - Create only one in-browser module for all your application's components, instead of one in-browser module for each component. -------------------------------------------------------------------------------- /text/0003-browser-support.md: -------------------------------------------------------------------------------- 1 | # Browser support 2 | - Start Date: 2019/04/26 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/3 4 | 5 | ## Decision, including impact on distributions 6 | Core OpenMRS frontend code supports the following browsers: 7 | - Last 2 Safari major versions 8 | - Last 3 Edge major versions 9 | - Last 5 Chrome major versions 10 | - Last 3 Firefox major versions 11 | - Last 3 Opera major versions 12 | 13 | The following browsers are not supported: 14 | - Internet Explorer 15 | 16 | Distributions may choose which browsers they support, including to drop support for browsers that they do not care about. 17 | 18 | ## Definition 19 | Supporting a browser means ensuring that the javascript code meets the syntax implemented by that browser and does not use any 20 | DOM or javascript functionality that does not exist or is not implemented in that browser. 21 | 22 | Accomplishing this can be done with one of more of the following strategies: 23 | - Only write code that works all the supported browsers. 24 | - Write code that is not supported by all browsers, but compile it to older forms of javascript. The most popular options for doing 25 | this are [babel](https://babeljs.io/) and [typescript](https://www.typescriptlang.org/). 26 | - Use [polyfills](https://en.wikipedia.org/wiki/Polyfill_(programming)) to enhance older browsers such that they support some 27 | of the modern javascript features. 28 | 29 | At OpenMRS, we employ all three strategies, relying most heavily on compilation via Babel. The [@babel/preset-env](https://babeljs.io/docs/en/babel-preset-env) 30 | npm package allows you to choose which browsers you want to support and then will automatically make sure that your modern fancy code works 31 | in those browsers. It does this by using the [browserslist](https://github.com/browserslist/browserslist) and [compat-table](https://github.com/kangax/compat-table) 32 | npm packages. 33 | 34 | ## Reason for decision 35 | - Not supporting older browers greatly enhances the frontend developer's ability to quickly build quality functionality. 36 | - Not supporting older browsers allows us to have smaller javascript bundles, which means less code to download and execute in the browser. 37 | - OpenMRS is usually used by people who can be instructed by modern browsers. 38 | 39 | ## Alternatives 40 | We could either not define which browsers we support, or we could support older browsers. The former means we wouldn't be certain whether a browser-specific 41 | error is OpenMRS' fault or not, and the latter would remove all of the advantages listed in the "Reasons for decision" section. 42 | 43 | ## Common practices (not enforced) 44 | - Use [Babel](https://babeljs.io/) and @babel/preset-env to compile your code to be compatible with older browsers. 45 | - [Configure @babel/preset-env](https://babeljs.io/docs/en/babel-preset-env#browserslist-integration) to only target browsers that are supported by OpenMRS. -------------------------------------------------------------------------------- /text/0004-import-maps.md: -------------------------------------------------------------------------------- 1 | # Import maps 2 | - Start Date: 2019/05/01 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/4 4 | 5 | ## Decision, including impact on distributions 6 | Within the [OpenMRS master single page application](/text/0001-single-page-applications.md), we use import maps to control which url each 7 | of the [in-browser javascript modules](/text/0002-modules.md) should be downloaded from. Since import maps are not supported by all browsers yet, 8 | we use SystemJS to polyfill import maps. 9 | 10 | All in-browser OpenMRS core modules and their URLs are defined in an import map. Distributions are encouraged to add their in-browser modules to an import map, too. 11 | 12 | ## Definition 13 | An [import map](https://github.com/WICG/import-maps) is a browser specification for controlling the url to download in-browser javascript modules from. At the 14 | time of this writing, import maps are currently a proposal that has not yet been voted on by major browsers and standards bodies. However, Chrome has already 15 | implemented import maps behind a developer feature flag. The [WICG](https://wicg.github.io/admin/charter.html) is the organization backing and proposing import 16 | maps, with Domenic Denicola being the chief author of the proposal. 17 | 18 | To use browser import maps, you add a ` 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | ``` 37 | 38 | Because import maps are not implemented in browsers yet, we use [SystemJS](https://github.com/systemjs/systemjs) as a polyfill for import maps. 39 | The syntax for SystemJS import maps is slightly different than the specification: 40 | 41 | ```html 42 | 43 | 44 | 51 | 52 | 53 | 60 | 61 | 62 | 63 | 64 | ``` 65 | 66 | You may also specify a download url for the import map itself: 67 | ```html 68 | 69 | ``` 70 | 71 | ## Reason for decision 72 | - [In-browser modules](/text/0002-modules.md) are a key part of OpenMRS architecture, and being able to name them is important for our code to be easily understood. 73 | - Instead of building a home-grown solution for controlling the URLs for javascript modules, we prefer to use a browser specification. 74 | 75 | ## Alternatives 76 | - We could not use in-browser modules. 77 | - We could build a homegrown solution for controlling the download url for in-browser modules. 78 | - We could only rely on the fully qualified url for all in-browser modules, instead of naming them. 79 | 80 | ## Common practices (not enforced) 81 | - **Do not** add your build-time modules to the import map. 82 | - **Always** add all of your in-browser modules to the import map. -------------------------------------------------------------------------------- /text/0005-migrating-from-jsps-gsps.md: -------------------------------------------------------------------------------- 1 | # Migrating from JSPs and GSPs 2 | - Start Date: 2019/05/10 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/5 4 | 5 | ## Decision, including impact on distributions 6 | Existing server rendered pages, including JSPs, GSPs, 7 | [the reference application](https://github.com/openmrs/openmrs-module-referenceapplication), and 8 | [legacyui](https://github.com/openmrs/openmrs-module-legacyui) will be migrated away from, with 9 | the following migration path: 10 | 11 | 1) Tomcat will be configured to return an HTTP 200 status and the [OpenMRS SPA](/text/0001-single-page-applications.md) 12 | HTML content for any incoming requests that do not have a corresponding JSP, GSP, or servlet. 13 | 2) Distributions that use server rendered JSPs/GSPs will link to the OpenMRS SPA for any functionality within the 14 | SPA that they want to use. Navigation to the SPA is a full page reload. 15 | 3) Distributions will configure/modify the OpenMRS SPA so that it links back to JSPs/GSPs for the functionality 16 | that is not yet in the SPA. Navigation to the server rendered pages will also be a full page reload. 17 | 4) When enough functionality exists within the SPA to justify a switch, distributions will switch their 18 | landing/home pages to the SPA, making it the default UI that links to server rendered pages as needed. 19 | 5) Over time, distributions will remove JSPs/GSPs in favor of reusing or building their own functionality 20 | within the SPA. The process of doing so will take time, but can be done piecemeal by changing one 21 | nav link at a time, within the JSPs/GSPs and SPA. Migrating a single server rendered page is done by 22 | changing links to that page so that users are redirected to the SPA instead of the server rendered page. 23 | 6) If, after much migration effort and time, a distribution removes all of their server rendered pages, 24 | they will turn off JSPs/GSPs in favor of only using functionality within the SPA. 25 | 26 | ## Definition 27 | Migration refers to, over time, no longer using JSPs and GSPs in favor of the OpenMRS SPA. 28 | 29 | A server rendered page is an HTML file that is generated by a server for a specific URL. 30 | 31 | An SPA is a single page application, as [defined here](/text/0001-single-page-applications.md). 32 | 33 | [JSP](https://en.wikipedia.org/wiki/JavaServer_Pages) and [GSP](https://gsp.grails.org/latest/guide/index.html) are 34 | ways of building server rendered pages within a [Tomcat](https://en.wikipedia.org/wiki/Apache_Tomcat) server (in our case, 35 | [openmrs-core](https://github.com/openmrs/openmrs-core/) is our Tomcat server). 36 | 37 | A full page reload is when the user clicks on a link and the browser unloads the current page, asking the server to send new HTML. 38 | 39 | ## Reason for decision 40 | - See [An Amazing Future for OpenMRS](https://talk.openmrs.org/t/an-amazing-future-for-openmrs/22328/1) for some thoughts from Burke 41 | on moving away from JSPs/GSPs. 42 | - See [reasons for a single page application](/text/0001-single-page-applications.md#reason-for-decision). 43 | 44 | ## Alternatives 45 | OpenMRS and its distributions could remain implemented in JSPs and GSPs, even though they are older technologies. 46 | 47 | Distributions could do what they have done in the past and implement an SPA of their own that does not use server 48 | rendering technologies. However, that is what happened in that past that resulted each distribution re-implementing 49 | all of the core functionality of an EMR, without being able to share their code. 50 | 51 | ## Common practices (not enforced) 52 | - Treat your JSPs and GSPs as "maintenance-only" mode. When substantial changes are to be made to a JSP or GSP, consider 53 | doing a piecemeal rewrite of just that page into the OpenMRS SPA. 54 | - Try to reach Step 4 (as described above) as soon as possible, since that represents a shift in where user and developer 55 | attention is focused. -------------------------------------------------------------------------------- /text/0008-styleguide.md: -------------------------------------------------------------------------------- 1 | # Styleguide 2 | - Start Date: 2019/06/08 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/8 4 | 5 | ## Decision, including impact on distributions 6 | The OpenMRS styleguide is an [in-browser javascript module](/text/0002-modules.md) that helps OpenMRS UI 7 | look and feel consistent, intentionally designed, and user-friendly. It is the foundation for accessibility 8 | at OpenMRS, providing proper color contrast, font sizing, keyboard usability, screen reader usability, 9 | and more. 10 | 11 | The styleguide is not in charge of any routes, and as such it is not a 12 | [single-spa application](https://single-spa.js.org/docs/building-applications.html). Instead, it is an 13 | [in-browser module](/text/0002-modules.md) that is listed in the [import map](/text/0004-import-maps.md). 14 | 15 | A styleguide documentation website is maintained to show developers how to use the styleguide. The code for the 16 | documentation site is hosted on Github and automatically updated whenever a pull request is merged to master. 17 | 18 | The styleguide should be used by all OpenMRS modules and by all distribution code. 19 | 20 | ## Definition 21 | A styleguide consists of [css classes](https://developer.mozilla.org/en-US/docs/Web/CSS/Class_selectors), 22 | [css custom properties (css variables)](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties), 23 | and [javascript components](/text/0009-styleguide-components.md). These three things create the foundation for 24 | building a UI that has a consistent user experience. 25 | 26 | Global css custom properties are defined with the `openmrs` prefix: 27 | 28 | ```css 29 | /* Example usage of styleguide css variables */ 30 | .a-custom-class-not-in-styleguide { 31 | background-color: var(--openmrs-brand-color); 32 | } 33 | ``` 34 | 35 | Global css classes are named with the `openmrs` prefix, so that it is easy to determine which classes originate from the styleguide: 36 | 37 | ```html 38 | 39 |
40 | ``` 41 | 42 | Javascript components for the styleguide are a big topic, and as such they are discussed in their own RFC proposal: 43 | [Styleguide Components RFC](/text/0012-styleguide-components.md). 44 | 45 | ## Reason for decision 46 | - User experience matters. For many users, the user experience determines whether a web app feels fast, modern, and simple. 47 | A consistent look and feel is the foundation for a good user experience, and the OpenMRS styleguide is a big part of that. 48 | - Developers should not have to re-invent the wheel when creating buttons, tooltips, form elements, etc. A shared styleguide is the 49 | mechanism for this. 50 | - The styleguide is fundamental to sharing code between distributions. It is the most highly reused code in all of OpenMRS frontend. 51 | - Having a single-sourced, shared styleguide allows designers and developers to "change once, see it everywhere." 52 | 53 | ## Alternatives 54 | OpenMRS could choose not to have a styleguide. This has some obvious downsides as explained above, but is truly a simple option that remains 55 | flexible. Doing so calls on the distribution authors to come up with their own look and feel. 56 | 57 | OpenMRS could port [the old OpenMRS styleguide](https://demo.openmrs.org/openmrs/uicommons/styleGuide.page) into the new SPA and microfrontends. 58 | This would potentially provide an easier migration path for people using the old styleguide to switch their server rendered code to 59 | client rendered within the SPA. However, the old styleguide is not very well known and not used much or at all by many of the large distributions. 60 | Starting from scratch gives us a clean slate to make intentional and good decisions, for both the UX design and software development. 61 | 62 | The OpenMRS styleguide could be a custom build of an existing design library, such as Material, SemanticUI, and others. 63 | Using such a existing design library is discussed in [the Design Libraries RFC Proposal](/text/0010-design-libraries.md). 64 | 65 | The OpenMRS styleguide could not expose any global in-browser css custom properties (css variables). Instead, it could require all users of 66 | the styleguide to rely solely on css classes, or require all frontend code to use a css compiler such as SASS or LESS. Doing so doesn't make 67 | a ton of sense for OpenMRS, since all [OpenMRS supported browsers](/text/0003-browser-support.md) support css custom properties. See 68 | the [MDN compatibility table](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties#Browser_compatibility) 69 | for more information. 70 | 71 | The OpenMRS styleguide could not expose any global css classes, but rely entirely on javascript components. Doing so would give the maintainers 72 | of the styleguide more control over the user experience. However, it also complicates the styleguide code substantially, and raises the barrier 73 | to entry for using the styleguide. CSS classes are ubiquitous to all frontend code, whereas javascript components often take some time to 74 | set up and get going in everyone's framework and build process. 75 | 76 | The OpenMRS styleguide could not expose javascript components, but only css. This option would ensure the highest level of compatibility 77 | with javascript frameworks and codebases, since javascript components are much harder than css to use in all situations. See 78 | [the styleguide components proposal](/text/0007-styleguide.components.md) for more discussion about this. 79 | 80 | ## Common practices (not enforced) 81 | - Use existing styleguide css and components whenever possible during feature development. 82 | - Do not add too many things to the styleguide that become dead over time. Prefer a small set of things that are actively maintained 83 | and heavily used. For example, a Button component is small enough that it can be easily maintained and heavily used, 84 | whereas a searchable, sortable, paginated, filterable Table component is likely too hard to make fully customizable in a way 85 | that is maintainable and actually usable by everyone. 86 | - When writing code for the styleguide, focus on making it as reusable as possible. The things that are the most reusable are 87 | things that make few assumptions, don't often have breaking changes, have a small API surface, and do not have to be 88 | altered in order to customize them. 89 | - Do not put all shared components into the styleguide. The styleguide should consist of building blocks for UIs, not entire 90 | features or large components. For example, a Vitals widget is not a good candidate for being in the styleguide, since it 91 | is a feature instead of a UX building block. -------------------------------------------------------------------------------- /text/0010-design-libraries.md: -------------------------------------------------------------------------------- 1 | # The Styleguide and Design Libraries 2 | - Start Date: 2019/06/08 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/10 4 | 5 | ## Decision, including impact on distributions 6 | The [OpenMRS styleguide](/text/0008-styleguide.md) does not use a third party design library's code (such as Twitter Bootstrap, 7 | Material, Semantic UI). Instead, the styleguide is built from scratch in collaboration with UX designers in the OpenMRS community. 8 | UX principles and design elements are liberally borrowed from other design systems and libraries, but the code for the 9 | OpenMRS styleguide is written by the OpenMRS community. 10 | 11 | The decision to embrace one or multiple design libraries for non-code resources will be made separately. 12 | 13 | Distributions should use the OpenMRS styleguide as the primary source of making a consistent user experience, look and feel, 14 | layout, and base-level components. In addition to the OpenMRS styleguide, distributions may use design libraries if they prefer to. 15 | However, it is not necessary (nor encouraged) to do so. 16 | 17 | ## Definition 18 | A design library is a third-party javascript library that provides pre-written css and javascript components. Design libraries 19 | are installed into code and are often used by the frontend community for base-level components (such as buttons, form elements, 20 | and tooltips). 21 | 22 | At the time of this writing, [Material UI](https://material-ui.com/) (from Google), [Twitter Bootstrap](https://getbootstrap.com/), 23 | and [Semantic UI](https://semantic-ui.com/) are a few of the popular design libraries. 24 | 25 | A custom build of a design library is a customized version of such a library. Customizations often include things like custom 26 | css class naming, additional css class definitions, and custom branding variables. Design libraries often provide a 27 | well-supported way to create a custom build of their library. Organizations can use custom builds instead of the generic version 28 | of the library to make the design library their own. 29 | 30 | ## Reason for decision 31 | - Upgrading design libraries is often very difficult because breaking changes span across an organization's entire 32 | frontend codebase. Many organizations get stuck on a particular version of a design library and end up having to 33 | rewrite much of their code to be able to upgrade or switch to a different design library. 34 | - Maintaining our own styleguide enables UX designers in the OpenMRS community. When using a third-party design 35 | library, developers often tell a designer "well that's just not possible" or "that's not how does it." 36 | In other words, many design decisions are made by the third party library, and not by designers within the OpenMRS ecosystem. 37 | - Backwards compatibility is especially important for the styleguide, since it is shared by everything else. It is 38 | difficult to not get stuck on an old version of a design library when upgrading it impacts all frontend code at once. 39 | Backwards compatibility is easier to achieve when (1) you have control over the code that needs to be backwards compatible, 40 | and (2) you have a minimal API surface (which in this case, means having fewer css classes and javascript components). 41 | This is easier to accomplish if we maintain our own. See [this github thread](https://github.com/openmrs/openmrs-rfc-frontend/pull/10#discussion_r292105076) 42 | for more discussion. 43 | - Because of trying to be useful to all organizations in the world, design libraries are often big and bloated. They 44 | include many features that are unnecessary or even damaging to a user experience when used inappropriately. It is 45 | difficult for feature developers to know which parts of the design library to use or not. 46 | - Implementing our own styleguide is not intractably difficult. It is something that perhaps the majority of large 47 | organizations do. Implementation of a styleguide can be iterative and incremental. Not everything needs to be 48 | decided upfront or implemented all at once. It is better to start with something effective and simple than 49 | comprehensive. 50 | - Bug fixing a design library is harder than bug fixing OpenMRS code. 51 | 52 | ## Alternatives 53 | The alternative is to use a design library such as Material Design or similar. 54 | 55 | ## Common practices (not enforced) 56 | - Distribution code should use the OpenMRS styleguide as much as possible, and should consider not bringing in a design library. 57 | - OpenMRS developers should contribute to the OpenMRS styleguide when they find bugs or missing features in it. Doing so fosters 58 | the health and usability of the styleguide by all distributions. -------------------------------------------------------------------------------- /text/0012-styleguide-javascript-components.md: -------------------------------------------------------------------------------- 1 | # Styleguide javascript components 2 | - Start Date: 2019/07/24 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/12 4 | - Previous, defunct RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/9 5 | 6 | ## Decision, including impact on distributions 7 | The [OpenMRS styleguide](/text/0008-styleguide.md) provides a CSS-first API to be used by all 8 | frontend code at OpenMRS. For the few elements for which JavaScript components are required (e.g. multiselect), 9 | the Styleguide will provide framework-specific components in React, Vue, Angular, and/or other frameworks. 10 | 11 | ## Definition 12 | "Javascript component" refers to javascript code that encapsulates the logic for creating and updating 13 | DOM elements and css styles. Components can be reused and composed, but are usually specific to a particular framework. 14 | 15 | "Framework agnosticism" refers to implementing the styleguide such that it can be used by many or all frameworks. This means 16 | that React, Angular, Vue, Svelte, Elm, etc. all can use the component. 17 | 18 | ["Global CSS classes"](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class) are the way to apply css styles 19 | to a dom element. All UI frameworks (React, Vue, Angular, etc) are able to apply global css classes to their dom elements, which 20 | means that by using global css classes we achieve "framework agnosticism." 21 | 22 | ## Reason for decision 23 | - It would be difficult and extremely time consuming to refactor all extant distributions to any one framework. Framework agnosticism allows 24 | distributions to use the styleguide now instead of waiting for a big rewrite of their code. 25 | - Re-implementing all styleguide components in each framework would be very time consuming and error prone. Organizations who do this 26 | often suffer from the different implementations not being equivalent, which erodes the user experience. Therefore, OpenMRS will not 27 | expect all global css classes to have a javascript wrapper component in each of the popular javascript frameworks. If the component exists, 28 | that's great, but the CSS is the Styleguide API and the thing to rely on. 29 | - By not betting entirely on the future of any single framework, we are more likely to avoid full rewrites while being able to do 30 | incremental rewrites. Web components in the styleguide provide a clear path for migrating a module from one framework to another. 31 | Experimentation in new technologies and frameworks is practical only if the experiments don't have to re-implement the entire styleguide 32 | just to get going. 33 | - Web components or other framework agnostic javascript components are 34 | [very difficult to implement well](https://medium.com/canopy-tax/one-companys-relationship-with-custom-elements-d360baf3b253) and 35 | have [some major drawbacks](https://dev.to/richharris/why-i-don-t-use-web-components-2cia). Implementing simple components, such as 36 | a styleguide button, can become [quite complicated](https://twitter.com/Joelbdenning/status/1149822754016780288?s=20) when done with web components. 37 | 38 | ## Alternatives 39 | OpenMRS could implement all of its styleguide components multiple times -- once for each javascript framework that is in use by distributions. 40 | As described above, organizations who have done this in the past have eroded the consistency of their user experience. Often only one of the 41 | framework implementations is fully featured. And minor differences in the different framework implementations result in a noticeable 42 | erosion of the user experience. 43 | 44 | OpenMRS could choose a single framework for its styleguide javascript components and require all modules to be written in that framework. 45 | This would greatly simplify the implementation of the components, and the interop with those components within the framework. Code across all 46 | distributions that is not written in that framework would be either thrown away or unable to participate in the consistent UX provided by 47 | the styleguide. 48 | 49 | OpenMRS could choose a single framework for its styleguide javascript components and rely on adapter libraries (such as ngReact) to allow for other 50 | frameworks to interoperate with the styleguide components. 51 | 52 | OpenMRS could use [single-spa parcels](https://single-spa.js.org/docs/parcels-overview.html) as the mechanism for framework agnostic components. 53 | This would allow for many of the same benefits as using web components, including full framework agnosticism. However, it is nonstandard, less 54 | understood than web components, and always requires a wrapper DOM element. 55 | 56 | OpenMRS could choose not to expose javascript components in the styleguide, but rely entirely on css to accomplish everything in the styleguide. 57 | 58 | ## Common practices (not enforced) 59 | - When the styleguide's global css class is sufficient to achieve what you need, do not wrap the css functionality in a javascript component. 60 | - If an organization has found use in implementing a framework-specific javascript component that wraps the styleguide's css, consider 61 | contributing back to the styleguide by creating a pull request that adds that javascript component to the styleguide. 62 | - For styleguide elements that really would be much nicer with a javascript component wrapping the css (selects, multiselects), implement 63 | framework-specific components into the styleguide. 64 | - Have styleguide documentation focus on learning the styleguide's global css classes. -------------------------------------------------------------------------------- /text/0013-api-calls-and-fhir.md: -------------------------------------------------------------------------------- 1 | # API Calls and FHIR 2 | - Start Date: 2019/07/02 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/13 4 | 5 | ## Decision, including impact on distributions 6 | All API calls from the browser to the server go through the `@openmrs/api` javascript 7 | module. 8 | 9 | The `@openmrs/api` provides the following: 10 | - `authenticatedFetch` 11 | - `fhir` 12 | - `getCurrentPatient`, and a few similar `getCurrent...` functions for shared data. 13 | 14 | Whenever a FHIR backend API is available, it should be used. When no such FHIR api exists, 15 | the OpenMRS-specific APIs will be used. 16 | 17 | ## Definition 18 | - `fhir` refers to the [official fhir.js npm package](https://github.com/FHIR/fhir.js/). [FHIR itself](https://www.hl7.org/fhir/overview.html) 19 | is an acronym that refers to the industry standard API specification for healthcare data. At the time of this writing, the OpenMRS 20 | backend largely offers only non-FHIR APIs for the frontend to use. 21 | - Within a browser, an API call is an HTTP request to the server. This can be done with either 22 | [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) or 23 | [XMLHttpRequest XHR](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). 24 | Fetch is preferred when possible, since it is newer and easier to work with (uses Promises). 25 | - Authentication of an API call is accomplished through a [`Cookie` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) 26 | or other [HTTP headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers). The `@openmrs/api` wrapper for fetch 27 | adds any needed headers and handles server responses that indicate the user is not logged in. 28 | - `getCurrentPatient` and other `getCurrent...` functions are provided to share data between disparate microfrontends that 29 | need the same data at the same time. They use the frontend route to identify the current patientUuid and then maintain a cache 30 | for the shared object. The cache is busted whenever the url changes such that the patientUuid is no longer in the frontend url. 31 | 32 | ## Reason for decision 33 | ### `authenticatedFetch` 34 | 35 | Maintaining an OpenMRS-specific wrapper around `window.fetch()` allows us to make a single code change when 36 | improving or fixing authentication and other API behavior. 37 | 38 | ### `fhir` 39 | 40 | FHIR is the industry standard for healthcare data. The more that OpenMRS uses FHIR, the more interoperable and 41 | accessible it is to researchers and software systems. 42 | 43 | The `fhir` variable exported by `@openmrs/api` is [documented here](https://github.com/FHIR/fhir.js/#native-adapter-npm-install-fhirjs). 44 | It is a pre-configured fhirjs instance that uses `authenticatedFetch` under the hood. When FHIR apis are available, 45 | `fhir` should be used instead of `authenticatedFetch`. 46 | 47 | ### `getCurrentPatient` 48 | 49 | Pages within the patient chart need a shared model of the patient object in order to avoid duplicate network requests 50 | to get the patient object. 51 | 52 | Providing a route-based cache of the patient object is a way to avoid duplicate network requests without coupling 53 | components and microfrontends together. 54 | 55 | ## Alternatives 56 | 57 | ### `fhir` 58 | 59 | Instead of using fhirjs, we could use [Smart on FHIR's client-js](https://github.com/smart-on-fhir/client-js). Smart on FHIR 60 | is a [FHIR Profile](https://www.hl7.org/fhir/profiling.html) and set of software tools funded by the United States that offers 61 | a regional FHIR profile for North America. [From the Smart on FHIR website](http://docs.smarthealthit.org/profiles/): 62 | 63 | > To support apps that run unmodified across different health IT systems, we need a set of “ground rules” that define which data fields are required vs. optional, and which coding systems should be used in a given context. The FHIR specification leaves many of these decisions open to downstream implementers, to ensure that FHIR can work with a variety of use cases. But for a viable app platform, we need more. 64 | > 65 | > As much as possible we want to avoid inventing these “ground rules” ourselves. In the United States, SMART has adopted the profiles outlined in the Argonaut Implementation Guide. Similarly, communities in other regions should work together to define a standard set of profiles that are appropriate for the terminology systems commonly used in their area. 66 | 67 | Since the OpenMRS backend FHIR implementation is not specific to the United States nor the Smart on FHIR profile, fhirjs was chosen instead 68 | of Smart on FHIR's client-js. 69 | 70 | ## Common practices (not enforced) 71 | - Whenever possible, use the `fhir` variable to make network requests. 72 | - Do not add `getCurrent...` functions to avoid all possible duplicate API requests. In a complicated frontend that is configurable 73 | and extensible, it is impractical to prevent all network request duplication. 74 | - `authenticatedFetch` must be completely compatible with any valid call to `window.fetch()` 75 | - Do not use [`axios`](https://github.com/axios/axios), [`Angular HTTP client`](https://angular.io/guide/http), or other API call 76 | libraries without first configuring them to call `authenticatedFetch` for all network requests. -------------------------------------------------------------------------------- /text/0014-configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | - Start Date: 2019/09/09 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/14 4 | 5 | ## Definitions 6 | 7 | **Config files** allow implementers to customize the behavior of microfrontends 8 | by providing static files. Common formats include JSON, YAML, and HCL. 9 | 10 | A **config schema** is the set of expectations that a microfrontend has of 11 | implementation-provided config files. It says how the config file must be 12 | structured, what keys it must have, and constrains what types of values are allowed. 13 | 14 | A **config library** is a code module that allows developers to define config 15 | schemas, and loads config files in accordance with that schema. It may also 16 | provide other tooling related to configuration. 17 | 18 | 19 | ## Decision 20 | 21 | Microfrontend developers should use the official OpenMRS MF Config Library. 22 | The Config Library should be a JavaScript module that 23 | * Provides an API for modules to define a config schema 24 | * Provides an API for modules to access config values 25 | * Provides an API for implementations to provide config files 26 | * Validates config files in non-production environments 27 | * Generates documentation for config schemas 28 | * Provides an API for an implementation’s esm-root-config to specify a config file or a hierarchy of config files 29 | * Provides a UI for viewing the resultant configuration, and which configuration values come from which files, and providing temporary overrides (similar to how Single-SPA allows Import Map overrides) 30 | 31 | The config library should require that each configuration element has a default value. 32 | 33 | The specifics of what these APIs should look like are the topic of a [separate RFC](https://docs.google.com/document/d/1Srazq1xfZSmIE7TfyMNKAriPgV2olEMJ68CirYpbgME/edit). 34 | 35 | 36 | ## Reason for Decision 37 | 38 | For having a config library 39 | * **Configuration as a first-class citizen**. We should do everything we can to encourage developers to make their modules configurable rather than producing implementation-specific modules. Providing a standard mechanism to do so will help. 40 | * **Good error messages for bad configs**. A config library allows defining constraints on the acceptable config values. This allows the application to fail fast with good error messages. Good error messages are essential because we expect non-dev implementers to be doing configuration. We should not expect configurers to be able to debug code. 41 | * **Generate config documentation**. It’s hard to keep docs complete and up to date. It would be much easier if nicely-formatted documentation could be generated from the schema. 42 | * **Enforce conventions**. The config library can enforce certain conventions about, for example, config namespacing or acceptable ways to reference concepts. 43 | * **Validation during config-writing, speed in production**. The config library can execute complex and potentially expensive validation while the implementer is working on the configuration. In production, validation can be turned off to reduce load time. 44 | * **Possible future support for other config file types**. While SystemJS provides native support for JSON import, it would be great to allow implementers to write config files that are less verbose, easier to work with, and support comments. Good candidates include HCL and YAML. 45 | 46 | For having defaults for all values 47 | * Eliminate boilerplate. 48 | 49 | For supporting hierarchical configuration 50 | * Many organizations have multiple implementations with many similarities and a few differences. They should not be forced to manage config files for each of their implementations separately. 51 | 52 | For having the config library handle hierarchies and provide the UI config tool 53 | * Configuration hierarchies quickly get messy. 54 | 55 | 56 | ## Alternatives 57 | 58 | **Developers handle configuration how they like**. Probably almost everyone 59 | that makes their microfrontend configurable will do so using the native JSON 60 | import mechanism. Their users will probably face incomprehensible runtime 61 | errors when bad configuration values are provided. 62 | 63 | **Provide tooling, but not a runtime module, for working with configuration**. 64 | It could do all of the things that the config library would do, but wouldn’t 65 | actually be bundled into the application. Microfrontend developers would 66 | interact with config files through the native JSON import mechanism. 67 | Developers would probably not actually use this tooling, since it wouldn’t be 68 | meaningfully integrated into their application. It would reduce config 69 | validation and documentation to “best practices” which would likely often be ignored. 70 | 71 | ## Common practices (not enforced) 72 | 73 | Wherever possible, developers should be encouraged to make things configurable 74 | rather than writing implementation-specific code. Emphasis on configurability 75 | will allow more collaboration, which will yield a higher-quality product. 76 | -------------------------------------------------------------------------------- /text/0015-usability-testing.md: -------------------------------------------------------------------------------- 1 | ## Usability Testing 2 | - Start Date: 2019/09/10 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/15 4 | 5 | ## Definitions 6 | **Usability Studies / Usability Testing** involves watching users interact with a prototype or tool. This is a type of qualitative user testing. 7 | 8 | **Qualitative User Testing** is based on observations of a small group of participants. The goal is to identify frequently recurrent, major problems, with the user interface and improve these. 9 | 10 | ## Decision 11 | **Prospective Design, Usability Testing** 12 | - Whenever feasible and practical, prospective user interface designs for OpenMRS should undergo usability testing. 13 | - Aim for 3 to 5 test users per design. 14 | - Develop a streamlined process that makes it easy for OpenMRS Implementations to conduct usability testing. This process will evolve, but may involve: 15 | -- Production of prototype 16 | -- Develop tasks for user tests to perform 17 | -- Embed the tasks into a usability interview. 18 | -- Video record user testing so that it can be shared asynchronously with design team members to review 19 | -- Improve designs and perform subsequent usability tests 20 | 21 | - When the design team lead believes the designs are ready, they can be suggested for software production. 22 | 23 | ## Reason for Decision 24 | **Background on task-based user testing** 25 | - Qualitative usability testing is likely the simplest form of user testing to start with for validating OpenMRS prototypes prior to production. It is described in more detail: 26 | 27 | **Task Scenarios Usability Testing** 28 | - https://www.nngroup.com/articles/task-scenarios-usability-testing/ 29 | - Startup Lab workshop: User Research, Quick 'n' Dirty (Michael Margolis, Google Ventures, 2013) https://library.gv.com/user-research-quick-and-dirty-1fcfa54c91c4#.3la09k9x8 30 | 31 | **Usability Interview** 32 | - The Usability Interview format that can be replicated across a variety of OpenMRS implementations asynchronously will evolve with time. It is reasonable to base it on existing Usability Interview styles, such as these proposed ones by Michael Margolis 33 | - See Startup Lab Workshop video above 34 | - Michael Margolis & Google Ventures proposes 5 Act Usability Interview https://library.gv.com/sprint-week-friday-7f66b4194137#.8e10zsect 35 | 36 | **Why 5 is the magic number of users:** 37 | - We need at least 3 users and no more than 5 for each usability study. 38 | - Steve Krung recommends user testing with at least three participants (see book: Don’t make Me Think, Rocket Surgery Made Easy) 39 | - Jakob Nielsen recommends testing with no more than 5 users https://www.nngroup.com/articles/why-you-only-need-to-test-with-5-users/ 40 | 41 | 42 | ## Alternatives 43 | **No user testing** this may be faster to move designs into the software development stage, but is high risk for requiring revision later on. 44 | 45 | **Quantitative User Testing** is based on observations from a larger group of participants. Example: card sorting, tree testing, a/b testing. The goal is to identify quantitatively which design is optimal and preferred. These methods are valuable but generally more labour intensive. This is a different type of user testing that that of qualitative testing proposed in this RFP. 46 | 47 | **Focus Groups** are distinctly different from user testing. Focus groups ask users what they may like to see or do. User testing involves watching users actually use something. Focus groups are not useful for the testing phase of UX work. They also have limited in the Discovery phase value https://medium.com/mule-design/focus-groups-are-worthless-7d30891e58f1 48 | 49 | **Accessibility Evaluation** is testing a design for accessibility across different user abilities. This is the subject of a different RFC. 50 | 51 | ## Common practices (not enforced) 52 | 53 | **Production Code, Usability Testing** 54 | - Where possible, hopefully once a month, perform usability testing of the production codebase. 55 | - Aim for a three-hour session with 3 to 5 users per session. 56 | - Aim for all designers, developers, project managers, and team members to watch these usability tests live together via Zoom so that they can share ideas and observations with each other in real-time. 57 | - Compile the results of these usability tests into a single page document that will inform critical updates and improvements needed in the software. 58 | -------------------------------------------------------------------------------- /text/0019-issue-tracking-and-documentation.md: -------------------------------------------------------------------------------- 1 | # Issue tracking and documentation 2 | - Start Date: 2019/11/15 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/119 4 | 5 | ## Decision, including impact on distributions 6 | For frontend projects within OpenMRS, the following software tools are used for issue tracking: 7 | 8 | - [Github issues](https://help.github.com/en/github/managing-your-work-on-github/about-issues) are enabled and used for general bug reports and questions from the open source community to the repositories' maintainers. 9 | - [OpenMRS JIRA](https://issues.openmrs.org/secure/Dashboard.jspa) is used for coordinating feature development, UX designs/feedback, and QA within the Microfrontends squad. 10 | 11 | For frontend projects within OpenMRS, the following software tools are used for documentation: 12 | - [Github readmes](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-readmes) with [markdown files](https://guides.github.com/features/mastering-markdown/) are used to document installation, usage, and API documentation for projects. 13 | - [OpenMRS wiki](https://wiki.openmrs.org/) is used for in-depth explanations of concepts, tutorials, and examples. 14 | 15 | ## Definition 16 | See the links above for definitions of Github Issues, OpenMRS JIRA, Github readmes, markdown, and OpenMRS wiki. 17 | 18 | ## Reason for decision 19 | - Github issues are the worldwide standard for communication between open source maintainers and their users. They are the most accessible and well understood way for people to talk with the maintainers of open source projects. For many open source users, a Github project without an issue queue is offputting and confusing. Maintainers may not always have time to properly or promptly address issues in large projects. However, maintainers should invite collaborators to become maintainers to help spread the workload. Github issues shine when they are used to discuss bugs and small-to-medium sized feature requests. 20 | - OpenMRS JIRA is a valuable tool for coordinating a project from its beginning to end. It is best used to coordinate projects that span multiple github repos and involve people from multiple technical disciplines. User experience designers, QA engineers, product managers, and project managers are able to coordinate their work with developers via sprint planning, kanban boards, and JIRA workflows. JIRA is not ideal for discussion with the broader open source community because it requires creating a separate login from a developer's Github accounts and is clunkier/slower than Github issues. Additionally, it is not nearly as easy or clear to a new user where and how to create a bug report in JIRA as compared to a Github issue. It is not the worldwide standard for communication between open source maintainers and the users of the open source. 21 | - Github readmes and markdown are the worldwide standard for documenting open source projects in both Github and Gitlab. Github readmes are automatically shown to visitors of a Github project which increases it's visiblity over the OpenMRS wiki. Putting documentation into markdown files within the same repo as the code is advantageous because pull requests can simultanously update the project's API and it's documentation. Additionally, git version control for Readmes is superior to that of Atlassian's wiki product. Since readmes are the very first thing that developers see when they visit a project, they should explain basic installation and usage, along with some details about the API for the project. Markdown is advantageous because it is readable and writable as a plain text file, allowing for users to pick which text editor they wish to use when writing it. In-depth tutorials and examples are not well suited for a Readme, since they often require multiple files and more content than can be quickly viewed in a Readme. 22 | - OpenMRS wiki contains a wealth of information and is currently the main source of documentation for the OpenMRS community. It should contain explanation of concepts, in-depth tutorials, and community-provided information that is helpful for distributions and implementing partners when setting up OpenMRS. It is not well suited for API documentation for code projects, since code samples are a pain to write in it and markdown support is an add-on instead of a primary feature. OpenMRS wiki contains links to Github, as appropriate, for those looking for the information contained in Github readmes. 23 | 24 | ## Alternatives 25 | Up until this RFC was proposed, the OpenMRS community did not use Github issues, readmes, or markdown in any capacity. This discourages collaboration from the open source community and is less accessible to those who are approaching OpenMRS for the first time. When Github issues are turned off, it gives the user of the software the impression that there is no one maintaining it and little hope of making it better. The communication gap between those who maintain the software and those who use the software is widened. 26 | 27 | The extremely popular open source project [Babel](https://babeljs.io/blog/) is an example of why using Github is the best way to go to encourage contribution. They tried to push people to a separate issue tracking system for a while but eventually came back to Github because of the friction it caused. 28 | 29 | ## Common practices (not enforced) 30 | - Add CI and other badges to your Github readmes 31 | - Add installation instructions (`npm install --save @openmrs/esm-login`) to your readme. 32 | - Add basic usage examples that are fully self contained and actually work. 33 | - Add API documentation that explains how the user can import the project and use its functions and data. 34 | - Link from Github readme to relevant wiki pages, and from wiki pages to the Github readme. -------------------------------------------------------------------------------- /text/0020-contributing-guidelines.md: -------------------------------------------------------------------------------- 1 | # Contributing guidelines 2 | - Start Date: 2019/11/15 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/20 4 | 5 | ## Decision, including impact on distributions 6 | For frontend projects within OpenMRS, the following are used to instruct contributors on how to make a pull request. 7 | 8 | - [Github contributing.md files](https://help.github.com/en/github/building-a-strong-community/setting-guidelines-for-repository-contributors#adding-a-contributing-file) 9 | - [Github pull_request_template.md files](https://help.github.com/en/github/building-a-strong-community/creating-a-pull-request-template-for-your-repository) 10 | - [The OpenMRS code of conduct](https://wiki.openmrs.org/display/docs/Code+of+Conduct) 11 | - [The OpenMRS MPL-2.0 + Health care disclaimer software license](https://wiki.openmrs.org/display/RES/OpenMRS+License+FAQ) 12 | 13 | The [OpenMRS Pull Request Tips](https://wiki.openmrs.org/display/docs/Pull+Request+Tips) are recommended. 14 | 15 | [Github squash and merge](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-request-merges#squash-and-merge-your-pull-request-commits) is enabled for all frontend projects. 16 | 17 | For frontend projects within OpenMRS, the following guidelines apply: 18 | - Not all PRs have to link to a JIRA ticket. 19 | - Pull requests are allowed (and encouraged) to contain more than one commit. Those commits are squashed when merged into the master branch. 20 | - Any pull request template within the repo should be followed. 21 | 22 | ## Definition 23 | In this PR, contribution refers to people creating pull requests to Github repos. Other terms in the definition section have been linked to above. 24 | 25 | ## Reason for decision 26 | - Github contributing.md and pull_request_template.md markdown files are the worldwide standard for open source software. They may link to a separate guide, but should be present. 27 | - The OpenMRS code of conduct helps provide a safe environment for people within the OpenMRS community. 28 | - The OpenMRS MPL-2.0 + Health care disclaimer software license protects the freedom of the open source software while also protecting OpenMRS from lawsuits. 29 | - The OpenMRS pull request tips are a community maintained set of good practices. 30 | - Github squash and merge creates the most easily read and understood commit history on the master branch. 31 | - Enforcing that every PR links to a JIRA ticket discourages contribution by increasing barrier to entry. First, you have to create a JIRA account. Then you have to create an issue in the right project. Then you have to self assign it. Then you have to link to it. Then you have to close it. Linking to JIRA is appropriate and helpful when you are working on a ticket. However, not every code change is described by a JIRA ticket. See #19 for more details on the role of JIRA. 32 | - Enforcing that every PR has only one commit increases the barrier to entry while destroying git history. It makes it harder for the reviewer to see incremental progress in a PR. Due to Github's squash and merge feature, it is not required for the master branch in order to have a clean commit history. 33 | 34 | ## Alternatives 35 | The OpenMRS community up already adopts much of what is in this PR. The new aspects of it are using Github squash and merge, not enforcing that all PRs are associated with a JIRA ticket, and allowing for multiple commits in a single PR. These new aspects only apply to frontend code. 36 | 37 | ## Common practices (not enforced) 38 | - Do not increase the scope of a PR after it has been reviewed. 39 | - Encourage feedback as both an author and reviewer. 40 | - Do not close a PR and recreate a new one with the same code. 41 | - Encourage as many contributors to engage in deep and meaningful contribution. 42 | - Be sensitive to the varying experience levels of OpenMRS contributors. 43 | - Avoid gatekeeping, which includes over-emphasizing to contributors how they're failing to follow the correct process. 44 | - Encourage code ownership, including reviewing changes to the code and projects you've contributed to. 45 | - Provide detailed and helpful feedback to reviewers, including using [Github's suggestion feature](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/incorporating-feedback-in-your-pull-request) to help the contributor know how to make the needed changes. 46 | - Your first PR to a codebase should be small. Get a feel for what the reviewer expects before submitting a PR with a large amount of code in it. -------------------------------------------------------------------------------- /text/0021-versioning-releases.md: -------------------------------------------------------------------------------- 1 | # Releasing and Versioning of Openmrs SingleSpa Apps 2 | - Start Date: 2020/01/21 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/1 4 | 5 | ## Definition 6 | OpenMRS: refers to the openmrs community. 7 | 8 | Micro-Frontends Squad: refers to the OpenMRS Community members responsible for creating and maintaining OpenMRS SPAs, under the OpenMRS Micro-Frontends Project. 9 | 10 | OpenMRS SPA: refers to an OpenMRS Micro-Frontend app. An example is openmrs-esm-patient-chart. See https://github.com/openmrs/openmrs-esm-patient-chart 11 | 12 | CDN: Content Distribution Network such as jsdelivr. See https://www.jsdelivr.com/ 13 | 14 | MAJOR Version: version where there are incompatible API or configuration API changes, or major UI changes that are enabled by default 15 | 16 | MINOR Version: version when you add functionality in a backwards compatible manner 17 | 18 | PATCH Version: version when you make backwards compatible bug fixes 19 | 20 | ## Decision 21 | OpenMRS SPA applications should have releases that are versioned so that each implementor/distribution can decide when to upgrade to a certain version, containing features that the implementor/distribution needs. 22 | 23 | The releases should have a maintenance branch for bug fixes and patches so that implementors running a particular version of an app can benefit from recent bug fixes. 24 | 25 | There will be maintenance release branches for both Major and Minor releases, as the motivation for this is to allow implementors/distributions control on when to start using a certain feature, that could be in a certain minor or major release. 26 | 27 | Development will always occur on the master branch with selected changes within master backported to release branches as needed. Making changes directly to a release branch and forward-porting those changes to master is discouraged and should only happen – if ever – in extreme circumstances. 28 | 29 | An implementor or distribution that requires a certain maintenance branch, either for a minor or major release is free to create it, by branching from the release-tagged commit. 30 | 31 | The OpenMRS Microfrontend Squad will not maintain release branches. Implementers or organizations who wish to maintain release branches may do so. They 32 | should be granted write access to the GitHub repo hosting the ESM of interest. 33 | 34 | Releases should be tagged, and the artifacts distributed via a CDN maintained by OpenMRS Community, so that implementors have stable resources to choose from. 35 | 36 | Tagged releases should be distributed via NPM as well, to support development environments and implementations relying on Packmap tool (see https://github.com/openmrs/packmap) for deployment in an offline site. 37 | 38 | ## Reason for decision 39 | - OpenMRS implementors and various distributions will want to decide on when features are added to their various distributions, achieved through versioning of releases. 40 | - Implementors would like to contribute bug fixes and benefit from the bug fixes without necessary upgrading their major/minor versions of OpenMRS SPAs. This is done through patch releases, that are only possible through use of release branching. 41 | - For implementors relying on the internet to access their OpenMRS application, distribution via CDN is desirable, as it brings web-app assets for application closer to the client accessing it. 42 | - Distributions via NPM is desirable as it allows developers to benefit from 'typings' when coding, and for the Packmap tool to be able to create the Openmrs SPA Module artifact for use with offline sites. 43 | 44 | ## Alternatives 45 | Each implementor/distribution to have a fork of the OpenMRS SPAs that they are using, for the purposes of releasing ONLY. This is a less desirable approach as it encourage implementors/contributors/distributions to diverge, weakening the OpenMRS Community in the process. 46 | 47 | ## Common practices (not enforced) 48 | -------------------------------------------------------------------------------- /text/0022-versions.md: -------------------------------------------------------------------------------- 1 | # Contributing guidelines 2 | - Start Date: 2020/02/06 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/22 4 | 5 | ## Decision, including impact on distributions 6 | OpenMRS frontend ESMs should be versioned according to 7 | [Semantic Versioning](https://semver.org/), with the following modification 8 | to the definition of a major version: 9 | 10 | A **Major** version is one in which **any** of the following have taken place 11 | - Backward-incompatible changes have been made to the API, if the ESM exposes an API 12 | - Backward-incompatible changes have been made to the Configuration API, 13 | such that upgrading might cause a previously valid configuration to be invalid 14 | - A functional and substantive UI change has been introduced and that change is 15 | present in the default configuration 16 | - A backend module dependency has been introduced or upgraded across a minor version 17 | 18 | The key ideas here are that 19 | 20 | - The configuration schema is an API, which versioning should respect 21 | - Major UI changes are added as a condition for major versioning 22 | - ESM versions should be sensitive to backend module requirements 23 | 24 | Apart from the differences made explicit in this RFC, SemVer should be followed. 25 | 26 | ## Definitions 27 | 28 | The decision, here, is the definitions. 29 | 30 | As a note, the 31 | [OpenMRS Versioning Conventions](https://wiki.openmrs.org/display/docs/Versioning) 32 | provide guidelines for versioning OpenMRS Modules. However, they do not 33 | usefully apply to ESMs. 34 | 35 | ## Reason for decision 36 | 37 | OpenMRS frontend ESMs do not, for the most part, center their APIs. Rather, 38 | they are built with a focus on UI features. For most of them, the 39 | [Configuration Schema](https://github.com/openmrs/openmrs-rfc-frontend/blob/master/text/0014-configuration.md) 40 | is the most-used API. Due to these considerations, some extension of 41 | SemVer is warranted, in order to provide adequate guidance for versioning 42 | frontend ESMs. 43 | 44 | Additionally, implementers should expect to be able to upgrade ESMs across minor 45 | versions without having to worry about backend module dependencies changing. 46 | 47 | ## Alternatives 48 | 49 | - Version strictly according to the public APIs (and potentially the configuration schemas) 50 | of ESMs, but not backend module dependencies or UI changes. This would be more true 51 | to the text of SemVer. 52 | - Invent some other versioning rationale. 53 | - Abolish versions. Nothing but master and its irregular branches and forks. Has 54 | the potential to make life solitary, poor, nasty, brutish, and short. 55 | 56 | ## Common practices (not enforced) 57 | 58 | - When introducing a major new feature or UI change that is toggled in configuration, consider 59 | first releasing a minor version that has the feature disabled by default, 60 | and then enabling it by default in the next major version. 61 | -------------------------------------------------------------------------------- /text/0023-readme.md: -------------------------------------------------------------------------------- 1 | # Module Documentation 2 | - Start Date: 2020/04/17 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/23 4 | 5 | ## Decision, including impact on distributions 6 | OpenMRS ESMs will maintain documentation of their features, APIs, 7 | configuration schema, and compatibility concerns in their README. 8 | 9 | The OpenMRS Wiki page 10 | [List of frontend modules](https://wiki.openmrs.org/pages/viewpage.action?pageId=224527568) 11 | will link to the GitHub repository of the ESM. The 12 | OpenMRS Wiki will not have individual pages for each ESM. 13 | 14 | Documentation that is not specific to any particular ESM, such as 15 | tutorials, getting started docs, design documents, and conceptual 16 | explanations, should continue to be produced and maintained in the 17 | OpenMRS Wiki. 18 | 19 | ## Definition 20 | An ESM's **README** is a [Markdown](https://en.wikipedia.org/wiki/Markdown) file 21 | `README.md` file kept at the package level, 22 | which is also the base repository level. When one navigates to the ESM's repository on GitHub, 23 | the README is displayed on the page. 24 | 25 | The [OpenMRS Wiki](https://wiki.openmrs.org/) is, sure enough, the wiki for OpenMRS. 26 | It contains all documentation related to OpenMRS backend modules, from the perspectives 27 | of users, implementers, and developers. 28 | 29 | The things documentation should explain, at a minimum, are 30 | - **Brief description at the top**: In as few words as possible, what does the module do? 31 | - **Features**: What are all the important things the module does? Explain it to someone 32 | who has never seen it. Feel free to use screenshots. 33 | - **Configuration schema**: What config keys can be provided? What do they do? What 34 | constraints must provided values meet? 35 | - **APIs**: If the module exposes any functions or components, these *must* be documented. 36 | - **Compatibility notes (if applicable)**: Are there parts of the OpenMRS Microfrontends 37 | ecosystem with which the module is incompatible? Is this Microfrontend a replacement for 38 | another? 39 | 40 | ## Reason for decision 41 | Keeping documentation in the repository's README is standard for open-source projects. 42 | The common exception is for projects requiring multi-page documentation, which 43 | calls for systems like Wikis or ReadTheDocs. Individual ESMs will generally not be so complex. 44 | 45 | Documentation updates can be included in the PR and code review process. 46 | This helps keep documentation in sync with the code it describes. 47 | 48 | Unlike the wiki, Markdown is pleasant to use and behaves predictably. 49 | It is easy to include code in Markdown, both inline and in blocks. 50 | 51 | Tools are available to keep the README up to date with certain aspects of 52 | code, such as APIs and configuration schemas. 53 | 54 | ## Alternatives 55 | - Stay on the Wiki 56 | - Move to ReadTheDocs or some other documentation platform 57 | - Don't document anything, anywhere 58 | 59 | ## Common practices (not enforced) 60 | - Consider using [openmrs-config-cli](https://github.com/openmrs/openmrs-config-cli) 61 | to automatically generate documentation for configuration schemas. 62 | - Consider using a tool like 63 | [documentationjs](https://github.com/documentationjs/documentation), 64 | [jsdoc-to-markdown](https://github.com/jsdoc2md/jsdoc-to-markdown/wiki/How-to-document-TypeScript), 65 | or [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) 66 | with [concat-md](https://www.npmjs.com/package/concat-md) 67 | to generate API documentation. 68 | - Do include UI screenshots. 69 | -------------------------------------------------------------------------------- /text/0026-activation-distribution.md: -------------------------------------------------------------------------------- 1 | # Project title 2 | - Start Date: 2020/04/27 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/26 4 | 5 | ## Decision, including impact on distributions 6 | OpenMRS Microfrontends will have their own default activator functions. 7 | Microfrontends will be identified as such by their names being suffixed with `-app`. 8 | Microfrontends' will provide activator and lifecycle functions in their exports according 9 | to a specific microfrontend interface, defined in this RFC. The interface bundle will be 10 | dynamically split from the main application bundle via a dynamic import in the lifecycle function. 11 | The app shell will load the app shell config if available. The app shell will register all 12 | microfrontends in the import map with Single SPA, and start the application. 13 | 14 | The existing concept of a "root config" will be superseded by the initial script, 15 | which is optionally configurable by a new kind of "root config." 16 | 17 | In order to implement this change, we will need to 18 | 19 | 1. Add index.ts entrypoint files to each microfrontend that satisfy the 20 | microfrontend interface (exporting lifecycle and activate). 21 | 2. Change the initial script to behave as described. 22 | 3. Migrate all existing root configs to the new structure. This will generally 23 | just mean removing the calls to registerApplication and exporting those 24 | activators that are different from the defaults. 25 | 26 | ## Definition 27 | An **activation function** is a JavaScript function that is used by the Single 28 | SPA library to determine if and when a microfrontend should be activated. 29 | 30 | The **activation of a microfrontend** describes when the lifecycle of an app 31 | should begin. 32 | 33 | The **lifecycle** of an app determines what to do technically for booting, 34 | mounting, updating, and unmounting an application in the DOM of the currently 35 | presented website. 36 | 37 | The **DOM** refers to the API responsible for the object representation of a 38 | website in the browser. 39 | 40 | An **app shell** refers to the index.html page that includes required libraries 41 | and the *initial script*. 42 | 43 | The **initial script** is the script which identifies microfrontends in the import map, 44 | loads them, loads the *root config*, and registers microfrontends with the Single SPA 45 | application. It sets up important globals and imports the important global modules. 46 | 47 | The new **root config** replaces the old concept of a [root config][1]. An 48 | optional element of the import map, named `root-config`, which can 49 | be used to (1) provide module configs to `@openmrs/esm-module-config`, (2) 50 | override module activator functions, and (3) do any other pre-app-launch setup 51 | wanted by the actual implemention. It does not register 52 | microfrontends with the Single SPA framework. 53 | 54 | The **microfrontend interface** is the interface that the *initial script* expects microfrontends 55 | to satisfy. Microfrontends are ESMs whose names are suffixed with `-app`. The interface 56 | consists of a single function, `setupOpenMRS`: 57 | 58 | ```ts 59 | interface SetupOpenMRS { 60 | (): { 61 | lifecycle: LifeCycles | (() => Promise | Splat>>); 62 | activate(location: Location): boolean; 63 | }; 64 | } 65 | ``` 66 | 67 | The evaluation of the exports of the modules from the importmaps can be done in 68 | the initial script of the app shell. 69 | 70 | The process to migrate from a centralized module containing all activity 71 | functions to a distributed introduces a new `index.ts` in the microfrontends. 72 | 73 | The `index.ts` may be as simple as follows: 74 | 75 | ```js 76 | // set the public path to be able to retrieve side bundles 77 | import "./set-public-path"; 78 | // get useful helpers for the activity functions from the loaded root-config 79 | import { routePrefix } from '@openmrs/esm-root-config'; 80 | 81 | export function setupOpenMRS() { 82 | return { 83 | lifecycle: () => import('./openmrs-esm-home'), 84 | activate: location => routePrefix("home", location), 85 | }; 86 | } 87 | 88 | // export other dependencies to be used, e.g., by the dev tooling 89 | export { backendDependencies } from "./openmrs-backend-dependencies"; 90 | ``` 91 | 92 | ## Reason for decision 93 | - Enhance possibility of distributing the microfrontends 94 | - Make it possible to create self-containing microfrontends 95 | - Allow an easy packaging model for OpenMRS distributions 96 | - Use existing standards instead of creating new ones 97 | - Cooperate with existing architecture 98 | - Improve developer experience 99 | 100 | ## Alternatives 101 | There are three main alternatives that can be seen: 102 | 103 | 1. Switching away from Single SPA to microfrontend frameworks that support the 104 | notion of distributed microfrontends. 105 | 2. Keeping the original notion of a single file that has the ultimate knowledge 106 | (with all the drawbacks and complexity for distribution). 107 | 3. Using a service to get the information via an API call. Besides the original 108 | importmap the service call would be made later. Downside is that such a call 109 | can never transport functions, thus standard activation functions such as a URL 110 | detection may need to be defined upfront. 111 | 112 | ## Common practices (not enforced) 113 | - Dependency on `@openmrs/esm-root-config` for helper functions 114 | - Predefined helpers to simplify existing tasks 115 | 116 | [1]: https://wiki.openmrs.org/display/projects/openmrs-esm-root-config 117 | -------------------------------------------------------------------------------- /text/0027-extensions.md: -------------------------------------------------------------------------------- 1 | # Project title 2 | - Start Date: 2020/08/20 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/27 4 | 5 | ## Decision, including impact on distributions 6 | 7 | We'll use an extension system that supports 8 | 1. discovery—that components know where to "plug themselves in" to the UI 9 | 2. configurability—that implementers can use config files to change which 10 | components are plugged in where 11 | 12 | We'll build an UI in a new module `@openmrs/esm-implementer-tools` 13 | for managing that configuration, which will assist implementers 14 | in changing the config to add, remove, or reorder extensions. 15 | 16 | ## Definition 17 | 18 | An **Extension** is a component with a unique *name* and a *type*. 19 | 20 | An **Extension Slot** is a place in the DOM where extensions can be attached. 21 | It has a unique *name* and a *type*. 22 | 23 | The **names** of extensions and extension slots should be different. 24 | Extensions can be attached to extension slots by referring to each of their 25 | names. This can be done in code or in configuration. 26 | 27 | An **Extension ID** uniquely identifies an extension *within a specific extension slot*. 28 | By default, if an extension is only attached to an extension point once, 29 | the extension ID is the extension name. 30 | 31 | Extensions and extension slots refer to the same small set of **types**. 32 | These types are merely suggestions. They are used by the extension autocomplete UI 33 | to suggest extensions that are likely to make sense in that context. 34 | 35 | Extensions and Extension Slots are coordinated via the **Extension Manager**. 36 | 37 | The **lifecycle methods** are functions called `bootstrap`, `mount`, `unmount`, and 38 | optionally `update`. 39 | See the [Single-SPA docs](https://single-spa.js.org/docs/parcels-overview/). In Typescript 40 | terms we will say 41 | 42 | ```jsx 43 | interface Lifecycle { 44 | bootstrap: () => void, 45 | mount: () => void, 46 | unmount: () => void, 47 | update?: () => void 48 | } 49 | ``` 50 | 51 | Please see 52 | [these slides](https://docs.google.com/presentation/d/1GmogTn-YSc_TBAvRyakeaBT-7IYsvvUvzZum21LAIOg/edit#slide=id.g1f88252dc4_0_162) 53 | where many of the below concepts are introduced visually. 54 | 55 | ## API Proposal 56 | 57 | Pages are registered in the `setupOpenMRS` function of a module. The `pages` 58 | key should accept an array of objects with the following properties: 59 | - route: equivalent to current `activate` parameter 60 | - load: a function that, when called, returns an object with the lifecycle methods 61 | 62 | Extensions are registered in the `setupOpenMRS` function of a module. The `extensions` 63 | key should accept an array of objects with the following properties: 64 | - name: the unique name of the extension 65 | - load: a function that, when called, returns an object with the lifecycle methods 66 | - type: [optional] the autocomplete type of the extension 67 | - slot: [optional] the name of a slot to attach to 68 | - slots: [optional] an array of slots to attach to 69 | 70 | ```javascript 71 | function setupOpenMRS() { 72 | return { 73 | pages: [ 74 | { route: "login", 75 | load: () => import("./openmrs-esm-login") } 76 | ], 77 | extensions: [ 78 | { name: "locationPicker", 79 | type: "setting", 80 | slot: " 81 | load: () => import("./location-picker") } 82 | ] 83 | }; 84 | } 85 | ``` 86 | 87 | Extension Slots can be registered in React using the component `ExtensionSlot` 88 | (and its optional child, `Extension`) 89 | 90 | ```jsx 91 | 92 | 93 | // or to add custom render logic 94 | 95 | 96 |
97 | 98 |
99 |
100 | ``` 101 | 102 | These wrap two framework-agnostic functions, 103 | 104 | ```javascript 105 | getExtensionNamesForExtensionSlot(extensionSlotName: string): string[] 106 | // and 107 | renderExtension( 108 | bindSite: HTMLElement, 109 | extensionSlotName: string, 110 | extensionName: string, 111 | renderFunction: (lifecycle: Lifecycle) => Lifecycle 112 | ): CancelLoading 113 | ``` 114 | 115 | Where `renderFunction` must both accept and return an object with the lifecycle methods. 116 | 117 | Extensions can be associated with extension slots programmatically by calling `attach` 118 | 119 | ```javascript 120 | attach(extensionSlotName: string, extensionName: string): void 121 | ``` 122 | 123 | This can take place anywhere, but will usually be either on the extension slot side, 124 | or on the extension side where `setupOpenMRS` is defined. 125 | 126 | If the same extension is attached to the same extension slot multiple times, 127 | the `extensionName` must be made unique by suffixing it with `#[idSuffix]`, 128 | where `[idSuffix]` is an identifier of the developer's choosing—preferably 129 | one that is descriptive and human-friendly. So 130 | `notesWidget#hivNotes` would be a valid value for `extensionName`. 131 | 132 | `extensionConfig` overrides the config which the extension receives at that extension 133 | slot. 134 | 135 | Tangentially to all this, we have a new React component 136 | ``, 137 | which renders only when the UI Editor is on, and which, when clicked, sends 138 | the user to the specified config path in the Configuration tab of the dev tools. 139 | 140 | ```jsx 141 | 142 | ``` 143 | 144 | This uses a framework-agnostic function `goToEditConfig(configPath)`. 145 | 146 | ### Configuration 147 | 148 | Every module that has extension slots implicitly supports configuration of the form 149 | 150 | ```js 151 | { 152 | [moduleName]: { 153 | "extensionSlots": { 154 | [extensionSlotName]: { 155 | "add": // Array, array of extension IDs 156 | "remove": // Array, array of extension IDs 157 | "order": // Array, array of extension IDs 158 | "configure": { 159 | [extensionId]: // object 160 | } 161 | } 162 | } 163 | } 164 | } 165 | ``` 166 | 167 | So the four keys for each extension slot are `add`, `remove`, `order`, and `configure`. 168 | All are optional. The extension system does not require configuration to work. 169 | 170 | `remove` causes and extension which was programmatically `attach`ed to an 171 | extension slot not to appear. 172 | 173 | `order` changes the order in which extensions appear. The default is the order in 174 | which they were `attach`ed, with `add`ed extensions at the end. 175 | 176 | `configure` allows overriding the `config` object passed to `attach`ed extensions. 177 | The object passed to `configure[extensionId]` should 178 | satisfy the config schema that the extension's module 179 | defines. Extensions can obtain their configuration using a new function 180 | `getExtensionConfig`, or using the usual React hook, `useConfig`. 181 | 182 | #### Configuration sources 183 | 184 | The precedence of configuration sources will be (lowest first): 185 | - objects provided using the `provide` API 186 | - a file provided via the import map as `config-file` 187 | - JSON in LocalStorage `openmrsTemporaryConfig`, which implementer-tools uses to store 188 | changes made through the interface 189 | 190 | ## Interface 191 | 192 | The implementer tools should be based on the devtools UI Configuration tab. It 193 | should have a toggle called "UI Editor". When turned on, the user should see: 194 | - A little red X in the bottom-right corner of each extension, which adds its ID 195 | to the "remove" array in the config for that extension slot. 196 | - A little green + in the bottom-right corner of each extension slot, which 197 | opens a new object in the "add" array in the config for that extension slot. 198 | - A little blue pencil icon wherever there is a `ConfigEditButton`. 199 | - A thick grey border at the bottom of each extension which allows the user to drag 200 | and drop the extension within the extension slot, which causes the "order" 201 | array in the config for that extension slot to update. 202 | - A tooltip (or similar) indicating the extension ID when hovering an extension 203 | - A tooltip (or similar) indicating the extension slot name when hovering an extension slot 204 | 205 | The configuration shown in the Configuration tab, which at present is just 206 | JSON, should be interactive. Specifically, clicking any value should open 207 | an input box allowing the user to change that value, setting the LocalStorage config JSON. 208 | 209 | Next to the "UI Editor" button there should be a "Save to server" button, a 210 | "Download" button, and a "Reset" button. 211 | - The "Save to server" button saves to `config.json` all config values which are not any 212 | of: defaults, from `provide`d configs, or from the import map `config-file`. 213 | - The "Download" button allows the user to download the LocalStorage config JSON. 214 | - The "Reset" button clears the LocalStorage config JSON. 215 | 216 | ## Implementation Notes 217 | 218 | ### Extension Manager 219 | 220 | The extension manager is the package 221 | [@openmrs/esm-extensions](https://github.com/openmrs/openmrs-esm-core/tree/master/packages/esm-extensions) 222 | in 223 | [openmrs-esm-core](https://github.com/openmrs/openmrs-esm-core). 224 | 225 | The `` component 226 | [should be a](https://reactjs.org/docs/render-props.html#be-careful-when-using-render-props-with-reactpurecomponent) 227 | `React.Component`. As in the 228 | [current implementation](https://github.com/openmrs/openmrs-esm-api/blob/4132f1b25b2044c86fe9fe7ea3c876c9abe214fe/src/shared-api-objects/extension-slot-react.component.tsx#L22), 229 | it should simply call `renderOpenmrsExtension`. However, it should render its 230 | children once for each extension that will be attached. It should provide one 231 | `ref` for each extension to attach to, and that ref should be located at the 232 | `Extension` child of `ExtensionSlot`. 233 | 234 | The following two are equivalent: 235 | 236 | ```jsx 237 | 238 | ``` 239 | 240 | and 241 | 242 | ```jsx 243 | 244 | 245 | 246 | ``` 247 | 248 | When "UI Editor" is enabled, the extension slot should render the `+` and `X` buttons 249 | for adding and removing extensions, as well as the tooltips. 250 | 251 | The API should also include a function `getExtensionNamesForType(type: string): string[]`, which 252 | allows the implementer tools to provide suggestions when `add`ing an extension to an extension 253 | point. 254 | 255 | ## Config 256 | 257 | `@openmrs/esm-config` will need a few more internal functions. "Internal" here 258 | means *used only within openmrs-esm-core* and 259 | *not documented in the esm-config README*. 260 | 261 | #### getExtensionConfig 262 | 263 | `getExtensionConfig(extensionSlotName, extensionId)` should return the configuration 264 | that is expected by the extension according to the config schema defined in its 265 | module. Its values take the following precedence (lowest first): 266 | 267 | - values under the extension-defining module's top-level key 268 | - values under the extension slot -defining module's top-level key, via 269 | `extensions[extensionSlotName].configure[extensionId]` 270 | 271 | Framework-specific wrapper functions should be written. In React, `useConfig` will 272 | return the extension config when used in an extension. 273 | 274 | #### getExtensionSlotConfig 275 | 276 | `getExtensionSlotConfig(extensionSlotName)` should return the configuration at 277 | `[moduleName].extensions.[extensionSlotName]`. It should be used exclusively by 278 | the extension manager to make decisions about how extensions should be rendered 279 | into extension slots. 280 | 281 | #### getImplementerToolsConfig 282 | 283 | Change from `getDevtoolsConfig`. 284 | 285 | #### getTemporaryConfig 286 | 287 | Returns whatever is in the LocalStorage temporary config. 288 | 289 | #### setTemporaryConfigValue 290 | 291 | `setTemporaryConfigValue(path, value)` should update the value in LocalStorage. 292 | Ideally it should cause the relevant component to re-render. 293 | 294 | #### unsetTemporaryConfigValue 295 | 296 | `unsetTemporaryConfigValue(path)`, the counterpart to `setTemporaryConfigValue`. 297 | 298 | #### clearTemporaryConfig 299 | 300 | Used by the Implementer Tools "Reset" button. 301 | 302 | #### getConfig 303 | 304 | The existing function should be modified to *exclude* the special `extensions` key. 305 | 306 | #### validateConfigSchema 307 | 308 | The existing module-config-internal function should be modified to complain if a 309 | developer attempts to provide a schema with `extensions` as a top-level key. The 310 | `extensions` key is special and implicit. 311 | -------------------------------------------------------------------------------- /text/0028-data-updates.md: -------------------------------------------------------------------------------- 1 | # Proposal: User Should Experience Up-To-Date Patient Information (via React-SWR) 2 | - Start Date: 2021/08/18 3 | 4 | ## Decision, including impact on distributions 5 | 6 | *Users need* an experience that makes 3.0 feel like it quickly updates with the most 7 | current information about their patients. 8 | 9 | *Currently*, if a user adds data about a patient (e.g. adds an allergy, a new condition, 10 | etc), the user must manually refresh in order to see their change. Refreshes are 11 | expensive and make for a bad UX. 12 | 13 | ## Definition 14 | - SWR: Stale While Revalidate. A data fetching and caching pattern. See [technical description](https://datatracker.ietf.org/doc/html/rfc5861#section-3). 15 | - React-SWR: A React library for data fetching using SWR. The library is now called "SWR" but 16 | for clarity it will be referred to as React-SWR in this document. 17 | 18 | ### Background 19 | 20 | In [this video/squad call on July 22, 2021](https://iu.mediaspace.kaltura.com/media/t/1_3fu8nt7g?st=642), 21 | [Dennis Kigen](https://github.com/denniskigen) demonstrated using React-SWR to perceptibly reduce 22 | load times for many parts of the page. See the [code](https://github.com/openmrs/openmrs-esm-patient-chart/commit/4563425a859b8fd65f5546fccb941afda7546bd8). 23 | 24 | Using SWR, cached data is immediately loaded, while simultaneously checking for any updates. 25 | 26 | This has two main implications for user experience: 27 | - If a component loads and requests data that has already been cached, it immediately displays 28 | the cached data before making a new request to check for updates. 29 | - If a component is displaying data using SWR, and a request is made elsewhere on the page that 30 | would cause that data to change, the component makes a new request to receive the refreshed 31 | data. 32 | 33 | For example, if a user is looking at a condition list and adds a new condition in a form, the list 34 | will update automatically with the new condition. 35 | 36 | > This RFC was proposed in August of 2021. We have since proceeded to adopt React-SWR across 37 | > the codebase. This RFC has been re-written for clarity in August 2022. It should be adopted 38 | > as a matter of recording what has actually happened. 39 | 40 | ### Caveats 41 | 42 | 1. Vercel, the developers of React-SWR, do not seem interested in making React-SWR support 43 | frameworks other than React. This means that microfrontends not written using React will 44 | not share the same cache as those written using React. 45 | 2. Will require design for "this content is stale/being updated" for clarity. 46 | 47 | ## Reason for decision 48 | - Users from >3 organizations have complained about the current user experience of 49 | updating widgets. See this [related ticket](https://issues.openmrs.org/browse/MF-725). 50 | - Other teams are creating work-arounds by forcing individual widgets to self-update 51 | (see _Alternatives_ section below) 52 | - We are already behaving as a React-first project. React is used for all widget development. 53 | The only exception is Ampath Forms, which is built in Angular. 54 | 55 | ## Alternatives 56 | 1. Add code to individual widgets to force those individual widgets to self-update after a change. 57 | This is already taking place in the absence of a global solution, for example in 58 | UCSF's [HIV Testing Services Encounter widget](https://github.com/UCSF-IGHS/openmrs-esm-ohri/blob/226f7b3075fd88861179c0e9675fb1efd5b932f5/src/hts/encounters-list/hts-overview-list.component.tsx#L40). 59 | 1. Implement a framework-agnostic SWR library based on RxJS. OpenMRS could maintain its own 60 | library which has the same API as React-SWR, but with the addition of APIs supporting 61 | other frameworks as they become necessary. The basics of it would probably be quite easy 62 | to implement on top of RxJS. However, React-SWR has many [features](https://github.com/vercel/swr#readme) 63 | which, if implemented, would add considerably to the complexity of the library. It is 64 | questionable whether OpenMRS has the engineering capacity to support such a library. 65 | 1. Create more explicit caching, such as is used with `useSession` and `useCurrentPatient`. 66 | This is cautioned against in [RFC 13](https://github.com/openmrs/openmrs-rfc-frontend/blob/master/text/0013-api-calls-and-fhir.md). 67 | There are simply too many different kinds of calls for this to be practical. 68 | 1. Create a global data store that caches all data according to the entities represented by that data, 69 | rather than caching by request. This is the approach that was taken for OWAs with 70 | [openmrs-react-components](https://github.com/openmrs/openmrs-react-components/). The result was 71 | unmaintainable. To create a robust architecture for doing this would be a very impressive feat 72 | of engineering, far beyond what would be required for a simple custom SWR implementation. 73 | 1. Use the offline system for data caching. All components need to declare their resources in order 74 | to be offline-ready anyway. Once their resources are declared, the data can be cached. However, 75 | in order for cached data to appear immediately, we would still have to implement a custom SWR 76 | system on top of the Service Worker cache. It also doesn't help at all with getting data to 77 | automatically update when new data is available. 78 | 1. Use a different fetching library with cache support. Propose one. 79 | -------------------------------------------------------------------------------- /text/0030-link-system.md: -------------------------------------------------------------------------------- 1 | # Link System 2 | - Start Date: 2021/10/21 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/30 4 | 5 | ## Decision, including impact on distributions 6 | 7 | We will extend the extension system to have support specific to links. 8 | 9 | We will allow a new property of the `setupOpenMRS` return object, called `links`. 10 | It will be an array of objects which contain 11 | - `id`: Identifies the link 12 | - `label`: The text that should appear on the link 13 | - `to` (optional): The target path or URL. Can include `${variables}` which will be interpolated from 14 | `openmrsBase`, `openmrsSpaBase`, or the extension props 15 | - `onClick` (optional): A click handler. Receives extension props as its second argument 16 | - `menu` or `menus` (optional): Names of menus to attach the link to 17 | - `offline`, `online`, and `meta` (optional): As in extensions. 18 | 19 | ```ts 20 | function setupOpenMRS() { 21 | return { 22 | pages: [], 23 | extensions: [], 24 | links: [{ 25 | id: "Patient list link", 26 | label: () => t("patientList", "Patient List"), 27 | to: "${openmrsSpaBase}/patient-list", 28 | onClick: (e) => { console.log("Clicked button " + e.button); } 29 | menu: 'App menu', 30 | }] 31 | } 32 | } 33 | ``` 34 | 35 | We will define a new React component, `Menu` (along with 36 | framework-independent functions that would support it). `Menu` would 37 | work exactly like `ExtensionSlot`, but only for Links. 38 | 39 | ```ts 40 | function Menu(props: { name: string, state?: object }); 41 | ``` 42 | 43 | We will extend the configuration system so that every Menu supports 44 | the same configuration options as ExtensionSlots. 45 | 46 | The `configure` value will support only the key `openInNewTab`. 47 | `openInNewTab` will default to `true` for external links, `false` otherwise. 48 | When `true`, it will add `target="_blank"` to the link. If the link is an 49 | external link, it will also add `rel="noopener noreferrer"`. 50 | 51 | Menu configuration will also support one additional key, `links`, which would 52 | allow an implementer to add arbitrary links to the Menu: 53 | 54 | ```json 55 | { 56 | "@openmrs/esm-primary-navigation-app": { 57 | "menus": { 58 | "App menu": { 59 | "add": ["Patient list link"], 60 | "remove": ["Provider management link"], 61 | "order": ["Home page link", "Patient list link"], 62 | "links": [{ 63 | "label": "Home", 64 | "to": "${openmrsSpaBase}/home" 65 | }], 66 | "configure": { 67 | "Patient list link": { 68 | "openInNewTab": true 69 | } 70 | } 71 | } 72 | } 73 | } 74 | } 75 | ``` 76 | 77 | For links created using `links`, the link label is the ID. 78 | 79 | ## Reason for decision 80 | 81 | - We have a proliferation of trivial "link" extensions, which all share 82 | approximately the same simple structure. 83 | - Link styling should be left up to the slot/menu. This enforces that 84 | links are not bringing their own CSS classes. 85 | - We already have an extension system wiring things together, so this 86 | won't add much complexity to it. 87 | - All menu-like UI elements should be configurable. At present, developers 88 | add configurability to menus in various ad-hoc ways, or they leave the 89 | menu unconfigurable. 90 | 91 | ## Alternatives 92 | 93 | - Continue making link extensions and solving the configurability problem 94 | each time. 95 | - To solve the configurability problem, you could create a feature in 96 | a module (or a new module) where you can create new 97 | link-like extensions via the config schema. In the config, give it a 98 | label, a target, and a slot (or slots) to attach to, and it will create 99 | the link as an extension and attach it to that slot. This solves the 100 | configurability problem for menu-like slots. It does not, however, 101 | create a common abstraction for defining link-like extensions in code. 102 | It also would be defining new extensions based on the config, which 103 | would create interdependency between config and extensions in the load 104 | process. This may have consequences for performance. 105 | - To create a common abstraction for defining link-like extensions in code, 106 | you could simply define a generic link-like extension generator in 107 | esm-framework, which produces the expected type of extension. 108 | - Another solution to solve the configurability problem would be to create 109 | some abstraction for use at the slot level, which both generates part of a 110 | config schema, and wraps the slot. This would probably not be very elegant, 111 | and config schema generation is a kind of abstraction and complexity that 112 | we have not yet broached. 113 | 114 | ## Common practices (not enforced) 115 | 116 | In the patient chart and the offline tools, we create pages and links together 117 | as extensions. The link is the extension component, and the page is created 118 | using the extension meta. In this paradigm, those extensions would use the 119 | `createLinkExtension` function to create their link components, and would 120 | otherwise be unaffected. 121 | -------------------------------------------------------------------------------- /text/0031-version-tracking.md: -------------------------------------------------------------------------------- 1 | # Version Tracking for Releases 2 | - Start Date: 2021/11/02 3 | - RFC PR: https://github.com/openmrs/openmrs-rfc-frontend/pull/31 4 | 5 | ## Decision, including impact on distributions 6 | 7 | ### Versioning rules 8 | 9 | The versioning rules in [RFC-22](https://github.com/openmrs/openmrs-rfc-frontend/blob/master/text/0022-versions.md) 10 | will be reinstated for all frontend modules. 11 | This does not include the framework, which will follow SemVer strictly. 12 | 13 | However, frontend modules that are part of Lerna monorepos will be versioned 14 | together, in Lerna [Fixed/Locked mode](https://github.com/lerna/lerna#fixedlocked-mode-default). 15 | For example, `@openmrs/esm-login-app` and `@openmrs/esm-primary-navigation-app`, 16 | which are both part of [openmrs-esm-core](https://github.com/openmrs/openmrs-esm-core), 17 | will always remain on the same version. The larger version jump takes precedence; 18 | e.g. if at release time, `@openmrs/esm-login-app` has only had patch changes and 19 | `@openmrs/esm-primary-navigation-app` has had a minor change, they both will be 20 | incremented by a minor version. 21 | 22 | ### Version tracking 23 | 24 | Commits to main/master must comply with thef 25 | [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) 26 | specification. Usage of `fix`, `feat`, and `!` 27 | (corresponding to patch, minor, and major version increments), however, must follow 28 | [RFC-22](https://github.com/openmrs/openmrs-rfc-frontend/blob/master/text/0022-versions.md). 29 | 30 | Types other than `fix`, and `feat` are allowed. Alone they are considered equivalent 31 | to patch changes; with a `!` they indicate a major/breaking change. Types other than 32 | `feat` cannot indicate a minor change. 33 | Otherwise, other types are 34 | not regulated by this decision. Repository maintainers should adopt or limit 35 | them according to what seems useful. 36 | 37 | Commits to main/master should happen using squash, per 38 | [RFC-20](https://github.com/openmrs/openmrs-rfc-frontend/blob/master/text/0020-contributing-guidelines.md). 39 | Because of this, the commit to main/master has its message set when the PR is merged. 40 | Therefore, the title of the PR, which becomes the first line of the message, should 41 | be in Conventional Commits format. 42 | 43 | In the case of a breaking change, the PR author should include a 44 | `BREAKING CHANGE` description in the commit messages or in the PR description. 45 | The person merging the PR is responsible for making sure that `BREAKING CHANGE` 46 | description makes it into the squashed commit message. 47 | 48 | Use of the `scope` portion of the Conventional Commits format is encouraged but 49 | not required for Lerna repositories using Fixed/Locked mode versioning. See 50 | below, "Independent package version tracking." 51 | 52 | #### Examples 53 | 54 | ``` 55 | refactor: Wrap all Context usages in custom hooks 56 | ``` 57 | 58 | would have no impact on the next release version (same as `patch`). 59 | 60 | ``` 61 | feat(login): Automatically search for login locations while typing 62 | ``` 63 | 64 | would imply that the next release of packages in `openmrs-esm-core` should increment 65 | by a minor version. 66 | 67 | ``` 68 | feat!: Add a new menu bar to the top of the patient chart 69 | 70 | BREAKING CHANGE: This introduces a major UI change which is visible by default. 71 | ``` 72 | 73 | would imply that the next release of packages in `openmrs-esm-patient-chart` 74 | should increment by a major version. 75 | 76 | ### Indpendent package version tracking 77 | 78 | If in the future it is decided that the packages in a Lerna monorepo should be 79 | versioned independently of one another, using Lerna 80 | [Independent mode](https://github.com/lerna/lerna#independent-mode), commit messages 81 | (and therefore PR titles) must use the `scope` portion of the 82 | [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) format to 83 | specify which packages are affected by the PR. 84 | 85 | Packages should be listed, alphabetically and comma-separated, 86 | within the corresponding type. Omitting `esm-` and `-app` is encouraged. 87 | If a PR includes multiple types of changes 88 | to multiple packages, these should be separated by a space. Multiple types 89 | should be listed in the order breaking-`feat`-`fix`. Use of `*` or other 90 | means of specifying multiple packages is allowed; scope identifiers are not 91 | intended to be machine readable. They must only be understandable to a 92 | person doing the release without any knowledge of the specifics of that PR. 93 | 94 | #### Examples 95 | ``` 96 | feat!(primary-navigation) feat(login, implementer-tools): O3-999: A big change in esm-core 97 | ``` 98 | 99 | ``` 100 | fix(patient-* except patient-chart): A patch change to all the patient chart apps 101 | ``` 102 | 103 | ``` 104 | feat(apps): O3-999: A minor change to the apps in openmrs-esm-core 105 | ``` 106 | 107 | ### Release notes 108 | 109 | A release should include release notes that list the changes which are 110 | included. Breaking changes, if present, should be highlighted. 111 | 112 | ## Definition 113 | - "Patch," "minor," and "major" are defined in [RFC-22](https://github.com/openmrs/openmrs-rfc-frontend/blob/master/text/0022-versions.md). 114 | - `fix`, `feat`, and `!` are defined in [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). 115 | - Releaser: a person releasing a new version of a package. 116 | 117 | ## Reason for decision 118 | - Now that there are production usages of Frontend 3.x, we need to make sure 119 | we don't break them. Versioning will enable users of Frontend 3.x to have 120 | clear expectations about what they are deploying. 121 | [RFC-22](https://github.com/openmrs/openmrs-rfc-frontend/blob/master/text/0022-versions.md) 122 | provides a clear specification for versioning frontend modules. 123 | - It's hard to keep track of all the changes that happen between releases. 124 | If commits are in Conventional Commit format, a releaser 125 | only has to look at the list of commits or PRs since the last release 126 | in order to determine the correct version increment. These can be 127 | obtained through the GitHub UI or using a tool like 128 | [github-changelog-generator](https://github.com/github-changelog-generator/github-changelog-generator) (which is also useful for producing release 129 | notes). 130 | - If Lerna repos are changed to use Independent versioning, it will be 131 | nearly impossible to keep track of what changes apply to which packages 132 | unless scope messages are used. 133 | 134 | ## Alternatives 135 | - Continue using [Sentimental Versioning](http://sentimentalversioning.org/). 136 | This reuslts in breaking changes being introduced in patch versions, which 137 | results in implementers using exact version specifiers (e.g. `1.2.3`), which 138 | results in their implementations never receiving fixes and updates which they 139 | might otherwise like to have. 140 | - Use tools like [Commitizen](https://commitizen-tools.github.io/commitizen/) 141 | or [commitlint](https://github.com/conventional-changelog/commitlint) to 142 | ensure that every commit meets the Conventional Commits specification. This 143 | would substantially increase the overhead of committing. Developers should 144 | be encouraged to 145 | [commit early and often](https://sethrobertson.github.io/GitBestPractices/#commit), as the old adage goes. 146 | - Attempt to switch back to RFC-22 versioning, but without any rules about 147 | PR/commit titles. This would be difficult for releasers. 148 | 149 | ## Common practices (not enforced) 150 | - Repositories should use a GitHub Action like 151 | [Pull Request Title Checker](https://github.com/marketplace/actions/pr-title-checker) to automate checking that the pull request title 152 | meets the specifications of this RFC. 153 | - A releaser can use 154 | [github-changelog-generator](https://github.com/github-changelog-generator/github-changelog-generator) to produce release notes. The tool produces 155 | a `CHANGELOG.md` file; the relevant section can be copy-pasted into the 156 | release notes box on GitHub, and notes about breaking changes can be 157 | appended manually. 158 | - Reviewers should be familiar with RFC-22 versioning and should help 159 | set PR titles appropriately. Pull request authors are not expected 160 | to be familiar with RFC-22 versioning. 161 | --------------------------------------------------------------------------------