Skip to content

Commit

Permalink
Merge 6db33f0 into 640b4c1
Browse files Browse the repository at this point in the history
  • Loading branch information
fredkingham committed Apr 1, 2017
2 parents 640b4c1 + 6db33f0 commit 111b6c3
Show file tree
Hide file tree
Showing 60 changed files with 1,344 additions and 1,541 deletions.
18 changes: 18 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,21 @@
### 0.4

Templates are now compiled on the server so must be referred to with "template" rather than "template_url".

Step template wrappers are no longer a thing.

The episode is compiled onto the pathway as an array.

If a model is a singleton then the client side is given a single item.

Alternatively you can use the SingleModelStep(model=yourModel) in your pathway. this will put the last subrecord of yourModel onto the scope.

The pathway save method now returns a tuple of patient, episode.


If you want to replace the patient/episode you need to pass in a call back


### 0.3 Release

Significant API churn with contextualising and defining Pathways, Steps, et cetera.
Expand Down
86 changes: 22 additions & 64 deletions README.md
Expand Up @@ -3,7 +3,7 @@
The OPAL Pathways plugin provides developers with a highly extensible method of
working with complex forms in [OPAL](https://github.com/openhealthcare/opal).
Typically pathways are forms that allow the user to enter information that spans multiple
`Subrecords` - which can be challengnig with the `Subrecord forms` provided by
`Subrecords` - which can be challenging with the `Subrecord forms` provided by
OPAL itself.

`Pathways` provides Wizards, long multi-model forms, custom validation and much more,
Expand Down Expand Up @@ -51,6 +51,10 @@ this means that OPAL will automatically load any Pathways defined in a python mo
Individual pathways are defined by subclassing a `Pathway` class. You must set at least the display name, and will
often want to also set a slug.

Out of the box, pathways ships with two types of pathways. A page pathway, a whole bunch of model forms on the same page, and a wizard pathway, a bunch of steps where the next step is only revealed after the step before it has been completed.

Let's look at a page pathway definition.

```python
# yourapp/pathways.py
from pathway import pathways
Expand Down Expand Up @@ -100,29 +104,13 @@ class SimplePathway(pathways.Pathway):
)
```

### Viewing The Pathway

This pathway is then available from e.g. `http://localhost:8000/pathway/#/simples/`.

### Steps With Multiple Instances Of Records
Pathways is smart enough to provide a single form step pathway if the model is a model or a pathway that allows a user to edit/add/remove multiple models if its not.

Frequently users need to add multiple instances of a `Subrecord` at the same time - for example when we're recording multiple allergies. Pathways provides a convenient wrapper for this case:

```python
from pathway import pathways
from myapp import models
### Viewing The Pathway

class SimplePathway(pathways.Pathway):
display_name = 'A simple pathway'
slug = 'simples'
steps = (
pathways.MultiSaveStep(model=models.Allergies),
models.Treatment,
models.PastMedicalHistory
)
```
This pathway is then available from e.g. `http://localhost:8000/pathway/#/simples/`.

For full documentation see the Multiple instances documentation below.

## Detailed Topic Guides

Expand Down Expand Up @@ -158,7 +146,13 @@ If you want to add any custom save logic for your step, you can put in a `pre_sa

### Multiple Instances Of Records

Frequently users need to add multiple instances of a `Subrecord` at the same time - for example when we're recording multiple allergies. Pathways provides a convenient wrapper for this case:
If the model is not a singleton, by default it will be show in the form as
a multiple section that allows the user to add one or more models.

This displays to the user a delete button, but by default subrecords are *not*
deleted if they press this. You can change them to be deleted by adding the
delete_others argument


```python
from pathway import pathways
Expand All @@ -168,22 +162,12 @@ class SimplePathway(pathways.Pathway):
display_name = 'A simple pathway'
slug = 'simples'
steps = (
pathways.MultiSaveStep(model=models.Allergies),
pathways.MultiSaveStep(model=models.Allergies, delete_others=True),
models.Treatment,
models.PastMedicalHistory
)
```

By default `MultiSaveStep` won't delete instances of subrecords, it will only edit or create.

If you wish the server to delete any instances of a subrecord that are not passed back (allowing the user a
delete option) then we set the `delete_existing` keyword argument to True. e.g.:

```python
import pathways
pathways.MultiSaveStep(model=models.Allergies, delete_existing=True)
```

In this case, the pathway will delete any existing instances of the given Subrecord Model that are not sent
back to the API in the JSON data.

Expand Down Expand Up @@ -216,6 +200,9 @@ The title and icon are rendered in the header for this step in your pathway, whi
{% include models.Diagnosis.get_form_template %}
```

Note pathways created in this way will not add in the model defaults.


#### Complex Steps With Multiple Instances Per Subrecord

If we need to also save multiple types of the same subrecord e.g. `Treatment` in this step,
Expand Down Expand Up @@ -383,41 +370,12 @@ The Service that is used to instantiate the pathway. This should inherit from th

The name of the class that you're replaceing with the pathway template. You probably shouldn't have to change this.

###### Patway.template_url

###### Patway.template
The name of the pathway template, it must include a div/span with the class .to_append which will be replaced by the wrapped step templates.

###### Patway.modal_template_url

If set, this template will be used if your pathway is opened in a modal. If its not set the template_url attribute will be used.


###### Patway.step_wrapper_template_url

A template that wraps every step when its injected into the pathway. It looks for a tag with .step-template and replaces it with each individual step. Its rendered in angular with the context of the step, so you have access to step.display_name for example.

for example, the below wraps each step in a panel titled with its display name and icon.

```html
<div class="row">
<div class="col-md-8 col-md-push-2">
<div class="panel panel-default">
<div class="panel-heading">
<h3>
<span ng-show="step.icon">
<i class="[[ step.icon ]]"></i>
</span>
[[ step.display_name ]]
</h3>
</div>
<div class="panel-body">
<div class="step-template"></div>
</div>
</div>
</div>
</div>
```
###### Patway.modal_template

If set, this template will be used if your pathway is opened in a modal. If its not set the template attribute will be used.


#### Pathway. _methods_
Expand Down
110 changes: 25 additions & 85 deletions config/karma.conf.js
@@ -1,86 +1,26 @@
module.exports = function(config){

var browsers, basePath, coverageReporter;

if(process.env.TRAVIS){
browsers = ["Firefox"];
basePath = '/home/travis/virtualenv/python2.7/src/opal/opal/static/js';
coverageReporter = {
type: 'lcovonly', // lcov or lcovonly are required for generating lcov.info files
dir: __dirname + '/../coverage/',
};
}
else{
browsers = ['PhantomJS'];
basePath = '../../opal/opal/static/js';
coverageReporter = {
type : 'html',
dir : __dirname + '/../htmlcov/js/'
};
}

var preprocessors = {};
preprocessors[__dirname + '/../pathway/static/js/pathway/**/*.js'] = 'coverage';

config.set({
frameworks: ['jasmine'],
browsers: browsers,
basePath: basePath,

files: [
//JASMINE,
//JASMINE_ADAPTER,
"lib/bower_components/angular/angular.js",
"lib/bower_components/angular-route/angular-route.js",
"lib/bower_components/angular-resource/angular-resource.js",
"lib/bower_components/angular-cookies/angular-cookies.js",
"lib/bower_components/angular-mocks/angular-mocks.js",

'lib/angular-ui-utils-0.1.0/ui-utils.js',
"lib/angulartics-0.17.2/angulartics.min.js",
"lib/angulartics-0.17.2/angulartics-ga.min.js",
"lib/ui-bootstrap-tpls-0.14.3.js",
'lib/ngprogress-lite/ngprogress-lite.js',
'lib/jquery-1.11.3/jquery-1.11.3.js',
'lib/utils/underscore.js',
'lib/utils/showdown.js',
'lib/utils/moment.js',
'lib/bower_components/angular-growl-v2/build/angular-growl.js',
'lib/bower_components/ment.io/dist/mentio.js',
'lib/bower_components/ment.io/dist/templates.js',
'lib/bower_components/angular-ui-select/dist/select.js',
"lib/bower_components/angular-local-storage/dist/angular-local-storage.js",
'opal/utils.js',
'opal/directives.js',
'opal/filters.js',
'opal/services_module.js',
'opal/services/*.js',
'opal/services/flow.js',
'opal/controllers_module.js',
'opal/controllers/*.js',
// 'opal/app.js',

__dirname + '/../pathway/static/js/pathway/**/*.js',

// 'opaltest/*.js',
__dirname + '/../pathway/static/js/pathwaytest/*.js'
// '../../../../elcid/elcid/assets/js/elcidtest/*.js',

],

preprocessors: preprocessors,

reporters: ['progress', 'coverage'],
autoWatch: true,

coverageReporter: coverageReporter,

// Stolen from http://oligofren.wordpress.com/2014/05/27/running-karma-tests-on-browserstack/
browserDisconnectTimeout : 10000, // default 2000
browserDisconnectTolerance : 1, // default 0
browserNoActivityTimeout : 4*60*1000, //default 10000
captureTimeout : 4*60*1000, //default 60000


});
}
var opalPath;
if(process.env.TRAVIS){
python_version = process.env.TRAVIS_PYTHON_VERSION;
opalPath = '/home/travis/virtualenv/python' + python_version + '/src/opal';
}
else{
opalPath = '../../opal';
}
var karmaDefaults = require(opalPath + '/config/karma_defaults.js');
var baseDir = __dirname + '/..';
var coverageFiles = [
__dirname+'/../pathway/static/js/pathway/*.js',
__dirname+'/../pathway/static/js/pathway/controllers/*.js',
__dirname+'/../pathway/static/js/pathway/services/*.js'
];
var includedFiles = [
__dirname+'/../pathway/static/js/pathway/*.js',
__dirname+'/../pathway/static/js/pathway/controllers/*.js',
__dirname+'/../pathway/static/js/pathway/services/*.js',
__dirname+'/../pathway/static/js/pathwaytest/*.js',
];

var defaultConfig = karmaDefaults(includedFiles, baseDir, coverageFiles);
config.set(defaultConfig);
};
10 changes: 8 additions & 2 deletions pathway/api.py
Expand Up @@ -20,10 +20,16 @@ def create(self, request, **kwargs):
episode_id=self.episode_id
)
data = _get_request_data(request)
patient = pathway.save(data, request.user)
patient, episode = pathway.save(data, request.user)
redirect = pathway.redirect_url(patient)

episode_id = None

if episode:
episode_id = episode.id

return _build_json_response({
"episode_id": self.episode_id,
"episode_id": episode_id,
"patient_id": patient.id,
"redirect_url": redirect
})
Expand Down

0 comments on commit 111b6c3

Please sign in to comment.