Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

From the pervious discussion of extending OpenLMIS to allow multiple suppliers and workflows related to requisition splitting — we have identified multiple requirements that the UI could support. This document outlines these additional requirements, and attempts to prioritize them in terms of level of effort required to implement these requirements.CSS Styles

Table of Contents

CSS and SASS

...

There should be no special method of removing or explicitly overriding CSS — an implementer should simply use more specific CSS rules to change styles. All This means that CSS styles in OpenLMIS should strive to be as 'general (shallow' (unspecific) as possible (and avoid the !important statement) so that its reasonable to override overriding a style can be done by simply creating a new CSS style. Some basic rules for doing are:

  • avoid the !important statement
  • use child selectors >
  • make mark-up semantic and class free (ie avoid divs)

All colors, absolute spacing, and browser breakpoints should be implemented using SASS variables, so that the overall UI look and feel can be changed by creating a different *.variables.scss file that will overwrite the initial declarations in OpenLMIS.

...

Creating new screens (easy & done)

Goal: Add new functionality to the OpenLMIS-UI

Examples:

  • Add new top-level functionality to OpenLMIS
  • Add configuration page to administration section
  • Add tab to requisition view page

The infrastructure to create new administration screens already exists - meaning an administrative user can navigate to a new screen , that is custom defined in a UI docker container. When the custom UI is included into a UI image, it will be published.module.

Enabling features:

  • UI-Router: Allows for addition of screens with a unique URL
  • NavigationService: Allows UI-Router definitions to expose their menu items into existing navigation frameworks
Code Block
// Consider adding a view to see requisitions on a map
angular.module('custom-module').config(function($stateProvider){
  $stateProvider.state('requisitions.map', {
    url: '/map',
    showInNavigation: true,
    controller: 'MyCustomMapController',
    templateUrl: 'map/page.html'
  });
});

Replacing an existing screen (could be easy & not

...

done)

Goal: Change Add content and functionality to an existing screen

Examples:

  • An implementation needs to replace the homepage with an interactive dashboard
  • A footer needs to be customized (less complicated than previous option)

Options:

Build Process Option - configure the build process so that files on a similar path overwrite eachother before the UI build command is run (this would mean creating a large temporary directory). The nice thing is that if you wanted to replace the home page template, all you would have to do it place a file at `src/home/page.html` (for example). The work involved here would be defined in the NodeJS dev tools, which are shared across all repositories.

UI-Router Solution - Rewrite a UI-Router route to use the newly created view template or controller. The implementation of this in AngularJS would require a run statement to make the switch, because you would need to wait for the original state to be registeredProblem: Not clear how errors would be handled.

Code Block
angular.module('custom-module').run(function($state){
  var state = $state.get('home'); // get the current home page state
  state.view.templateUrl = 'new_tempalte.html';
  // gotta figure out how to change this...
});


// Alternatively just change $StateProvider's fallback page

Define two states with the same name, and add a property that is called "override" - worth testing what happens when there are two states with the same name

...


Custom UI-Router 'Override' -
 Allow implementers to register a route with the property 'override,' which we would recognize in UI-Router and then use the last route with a specific name if the state has the property override. This would allow us to use the error handling framework already developed in UI-Router.

Appending form elements into existing screens w/o forking (hard)

...

  • The v2 configure facility screen, which contains fieldsets of various different types, one could imagine adding a form or fieldset into the group
  • Requisition form actions, where an implementer might need to add a button

Image Added

Options:

Ideal Solution:

Angular Template Blocks - There is a project to add block/extend templating from templates like Jinja2 (Django/Python), Jade, or Handlebars. This library hasn't gotten much attention, and the code might turn to spaghetti quick as it relies on 'templates' to drive the extension. An ideal solution would leave very generic markup.

^ We could also use an HTML preprocessor to inject HTML templates together at build time (ie use jade blocks, to allow for templates to be overwritten) — and use a run statement to replace the template in the $templateCache. The HTML author would have to know what context they are building into. 

Create a dynamic template provider - Since we are already heavily using UI-Router, and ideal solution would be to allow developers inject content into ui-views depending on the state and specify priority order (and maybe other magic to keep it all organized). I have not found a pre-built solution for this — but the resulting code might look like: Develop an Extendable Service


Create an abstraction service where new UI elements could register HTML templates to. This service would work much like UI-Router and allow a person to add a template and controller to the current scope. We could generically apply this code to:

  • Any UI-Router route (if user specifies a specific view)
  • Any form element with a unique ID
  • Any element with a directive and unique ID (ie  <div extendable="foo.bar.1" />)


Code Block
angular.module('custom-module').run(function($rootScope){
  $rootScope.$on('view:requisition.actions', function(templateList, scope, additionalArguments){
    // check scope variables, and do things
    templateList.push('custom-module/template.html');
  }
});


// if we wrap this implementation into a service/factory
angular.module('custom-module').run(function(uiViewExtender){
  uiViewExtender.add(
    'requisitions.requisition', // view name, could take patterns eventually maybe
    'form-actions', // view name to replace
    'custom-module/template.html', // template to add
    10 // priority of where to load (default would be 10, maybe)
    );
  }
});

Extend `<form>` with ngTransclude - Like the two above selections, this would require a custom directive (as I can't find something that does this), but allow a user to inject elements before/after a form by registering items with the form's id element. It would make sense to extend a form element with events for onSubmit, to allow developers to link controller actions and other things to scope variables.

Using a unique idea would be a good approach — extention service stores all the HTML files/templates — there could also be a replace flag

"Extendable directive" – <div extendable="foo.bar.1" />

Targeted Directives - It also might be possible to completely replace an individual `<input />` or `<select />` element – but the difficulty would be being able to consistently target an individual element, and being able to assume that all form element actually support this ability. Issues of rending priority could also hamper development if two elements are changing the same input.

...

Extending Business Logic

We would want to add Javascript events so new logic can be injected in various places, the problem is there are no natural places to inject this behavior, and implementers would need to define specific places for injection.

  • Where would add the logic for a button injected by a template?
  • Change how stock on hand is calculated (document this)
  • Are there easy extension points for service (adding new functionality and replacing the original provider — think angular.merge/extend)

...

  • An implementation requires that products are searched by color
    See earlier note about extending a view, or extending a form element. The real trick here will be having a form submit event correctly pass the data through to the OpenLMIS server endpoint.

Replacing result template

...

There is a need to add table columns. The good news here is that if columns are added in the RequisitionService (backend) they will be displayed in the full-supply product view with no effort as that screen is already template driven.New table cell functionality


...

SIL/SELV UI Changes to OpenLMIS (from Pawel)

...