{ "info": { "author": "", "author_email": "", "bugtrack_url": null, "classifiers": [], "description": "# Pathways\n\nThe Opal Pathways plugin provides developers with a highly extensible method of\nworking with complex forms in [Opal](https://github.com/openhealthcare/opal).\nTypically pathways are forms that allow the user to enter information that spans multiple\n`Subrecords` - which can be challenging with the `Subrecord forms` provided by\nOpal itself.\n\n`Pathways` provides Wizards, long multi-model forms, custom validation and much more,\nall usable either in full page or modal contexts.\n\nThis plugin is **Alpha** software.\n\nAlthough it aldeady provides significant and useful functionality, it is in active development,\nand delvelopers should anticipate backwards-incompatible API changes as part of minor\n(x.VERSION.x) releases.\n\n[](https://travis-ci.org/openhealthcare/opal-pathway)\n[](https://coveralls.io/github/openhealthcare/opal-pathway)\n\n## Contents\n\n* [Introduction: What is a Pathway?](#introduction-what-is-a-pathway)\n* [Installation](#installation)\n* [Quickstart Guide](#quickstart-guide)\n* [Detailed Topic Guides](#detailed-topic-guides)\n* [Reference Guides](#reference)\n* [Road Map](#road-map)\n* [Modal Pathways](#modal-pathways)\n\n## Introduction: What Is A Pathway?\n\nA pathway is a complex form that we can use in an Opal application. Pathways are comprised of a\ncollection of `Steps`.\n\n`Pathway Steps` are individual sections of that complex form which provide hooks to\ncustomise validation, presentation or behaviour in a granular manner.\n\nThe Pathways plugin ships with two types of pathway, which can be used either on their\nown page, or in an Opal modal:\n\n* Wizard style - e.g. the user has to click next to reveal each subsequent step\n* Single Page - e.g. displaying all the `Pathway Steps` from the start and the user scrolls to the next one\n\n## Installation\n\nClone `git@github.com:openhealthcare/opal-pathway`\n\nRun `python setup.py develop`\n\nAdd `pathway` to `INSTALLED_APPS` in your `settings.py`.\n\n## Quickstart Guide\n\nIn this section we walk you through creating a simple Pathway.\n\n### A First Pathway\n\nPathways are an Opal\n[Discoverable feature](http://opal.openhealthcare.org.uk/docs/guides/discoverable/) -\nthis means that Opal will automatically load any Pathways defined in a python module\nnamed `pathways.py` inside a Django App.\n\nIndividual pathways are defined by subclassing a `Pathway` class. You must set at least the\ndisplay name, and will\noften want to also set a slug.\n\nOut of the box, pathways ships with two types of pathways. A page pathway, a whole bunch of\nmodel forms on the same page, and a wizard pathway, a bunch of steps where the next step is\nonly revealed after the step before it has been completed.\n\nLet's look at a page pathway definition.\n\n```python\n# yourapp/pathways.py\nimport pathway\n\nclass MyPathway(pathway.PagePathway):\n display_name = 'My Awesome Pathway'\n slug = 'awesomest-pathway'\n```\n\n### Taking Our First Steps\n\nA Pathway should have at least one `Step` - a section within the form.\n\n`Steps` are defined on the pathway class using the `Pathway.steps` tuple.\n\n```python\nimport pathway\nfrom myapp import models\n\nclass SimplePathway(pathway.PagePathway):\n display_name = 'A simple pathway'\n steps = (\n pathways.Step(model=models.PastMedicalHistory)\n )\n ```\n\n### Model Steps\n\nA common case is for steps to be simply a single Opal `Subrecord` using the subrecord form template.\n\nIn fact we can simply add Opal `Subrecords` to the `steps` tuple to achieve the same effect.\n\nFor instance, to create a pathway with three steps to record a\npatient's allergies, treatment and past medical history, we could use the following:\n\n```python\nimport pathway\nfrom myapp import models\n\nclass SimplePathway(pathway.PagePathway):\n display_name = 'A simple pathway'\n slug = 'simples'\n steps = (\n models.Allergies,\n models.Treatment,\n models.PastMedicalHistory\n )\n```\n\nPathways 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.\n\n\n### Viewing The Pathway\n\nThis pathway is then available from e.g. `http://localhost:8000/pathway/#/simples`.\n\n\n## Detailed Topic Guides\n\nIn this section we cover Pathway concepts in more detail.\n\n* [Loading data from Existing Episodes](#loading-data-from-existing-episodes)\n* [Customising server side logic](#customising-the-server-side-logic)\n* [Multiple instances of records](#multiple-instances-of-records)\n* [Validation](#validation)\n* [Wizards](#wizards)\n* [Complex steps](#complex-steps)\n* [Success Redirects](#success-redirects)\n\n### Loading Data From Existing Episodes\n\nA URL without a patient id or episode id will create a new patent/episode when\nyou save it.\n\nTo update a particular patient with a new episode, the URL should be:\n`http://localhost:8000/pathway/#/simples/{{ patient_id }}`\n\nTo update a particular episode the URL should be:\n`http://localhost:8000/pathway/#/simples/{{ patient_id }}/{{ episode_id }}`\n\nWhen you load from these urls, your forms will come prepulated with the\nexisting data for that patient/episode.\n\n\n### Customising The Server-side Logic\n\nIf you want to add any custom save logic for your step, you can put in a `pre_save` method. This is passed the full data dictionary that has been received from the client and the patient and episode that the pathways been saved for, if they exist (If you're saving a pathway for a new patient/episode, they won't have been created at this time).\n\n*TODO: How does the data work ? Is the expectation that I alter the data or save a subrecord?*\n\n*TODO: Is there a post-save ?*\n\n*TODO: What if I want to do validation on the server ?*\n\n### Multiple Instances Of Records\n\nIf the model is not a singleton, by default it will be show in the form as\na multiple section that allows the user to add one or more models.\n\nThis displays a delete button for existing subrecords.\n\nBy default, any subrecords that are deleted, or are not included in the data sent back\nto the server are deleted.\n\nIf you don't wish this to happen, pass `delete_others=False` to the `MultiSaveStep`.\n\n\n\n```python\nimport pathway\nfrom myapp import models\n\nclass SimplePathway(pathway.Pathway):\n display_name = 'A simple pathway'\n slug = 'simples'\n steps = (\n pathways.MultiSaveStep(model=models.Allergies, delete_others=True),\n models.Treatment,\n models.PastMedicalHistory\n )\n```\n\nIn this case, the pathway will delete any existing instances of the given Subrecord Model that\nare not sent back to the API in the JSON data.\n\n###\u00a0Complex Steps\n\nIf we want to save multiple types of subrecords at the same step, we can do that by including the\nrelevant form templates in a custom step template.\n\n```python\nimport pathway\nfrom myapp import models\n\nclass SimplePathway(pathway.Pathway):\n display_name = 'A simple pathway'\n slug = 'simples'\n steps = (\n pathways.Step(\n display_name='Demographics and Diagnosis',\n icon='fa fa-clock',\n template='pathways/demographics_and_diagnosis_step.html'\n ),\n )\n```\n\nThe display name and icon are rendered in the header for this step in your pathway, which\nexist outside the scope of the step template itself. Then all we would need is the template\nitself:\n\n```html\n\n{% include models.Demographics.get_form_template %}\n{% include models.Diagnosis.get_form_template %}\n```\n\nNote pathways created in this way will not add in the model defaults.\n\n\n#### Complex step logic\n Pathway steps can be injected with a custom controller. You can do this by declaring an angular step in your controller.\n\n for example\n\n ```python\n steps = (\n Step(\n model=\"NyModel\",\n step_controller=\"FindPatientCtrl\",\n ),\n ```\n\n Your javascript controller should then look something like...\n\n ```js\n angular.module('opal.controllers').controller('FindPatientCtrl',\n function(scope, step, episode) {\n \"use strict\";\n // your custom logic\n });\n ```\n\n The scope passed in comes fully loaded with reference data and meta data.\n It also comes with the scope.editing. This is the dictionary that will\n appear in the form and will be saved back at the end.\n\n The step is the step definition from the server, ie the output of\n step.to_dict.\n\n The episode is the episode in its display state, before its been changed\n into a state that is ready to be displayed in the form.\n\n steps can declare optional `preSave` method on their scope. This is passed\n the editing dictionary which will then be saved and can be altered in place\n if necessary.\n\n\n\n#### Complex Steps With Multiple Instances Per Subrecord\n\nIf we need to also save multiple types of the same subrecord e.g. `Treatment` in this step,\nwe simply use the `multisave` template tag.\n\n```html\n{% load pathways %}\n\n{% include models.Demographics.get_form_template %}\n{% include models.Diagnosis.get_form_template %}\n{% multisave models.Treatment %}\n```\n\nAlternatively you may want to create your own multisave step forms, you can use the multi-save-wrapper for this.\n\n```html\n\n