Tutorial for extending a workflow
Added tutorial for extending an existing workflow as a plugin. Change-Id: I8e6af24b9d1dfe313e6ee6d43894d87d9c97068 Closes-Bug: #1511593
This commit is contained in:
parent
cda9604792
commit
421cdbce24
|
@ -0,0 +1,202 @@
|
|||
Extending an AngularJS Workflow
|
||||
===============================
|
||||
|
||||
A workflow extends the ``extensibleService``. This means that all workflows
|
||||
inherit properties and methods provided by the ``extensibleService``. Extending
|
||||
a workflow allows you to add your own steps, remove existing steps, and inject
|
||||
custom data handling logic. Refer to inline documentation on what those
|
||||
properties and methods are.
|
||||
|
||||
We highly recommend that you complete the
|
||||
:doc:``plugin tutorial </tutorials/plugin>`` if you have not done so already.
|
||||
If you do not know how to package and install a plugin, the rest of this
|
||||
tutorial will not make sense! In this tutorial, we will examine an existing
|
||||
workflow and how we can extend it as a plugin.
|
||||
|
||||
.. Note ::
|
||||
|
||||
Although this tutorial focuses on extending a workflow, the steps here
|
||||
can easily be adapted to extend any service that inherited the
|
||||
``extensibleService``. Examples of other extensible points include
|
||||
table columns and table actions.
|
||||
|
||||
File Structure
|
||||
--------------
|
||||
|
||||
Remember that the goal of this tutorial is to inject our custom step into an
|
||||
**existing** workflow. All of the files we are interested in reside in the
|
||||
``static`` folder.
|
||||
|
||||
myplugin
|
||||
│
|
||||
├── enabled
|
||||
│ └── _31000_myplugin.py
|
||||
│
|
||||
└── static
|
||||
└── horizon
|
||||
└── app
|
||||
└── core
|
||||
└── images
|
||||
├── plugins
|
||||
│ └── myplugin.module.js
|
||||
│
|
||||
└── steps
|
||||
└── mystep
|
||||
├── mystep.controller.js
|
||||
├── mystep.help.html
|
||||
└── mystep.html
|
||||
|
||||
myplugin.module.js
|
||||
------------------
|
||||
|
||||
This is the entry point into our plugin. We hook into an existing module via the
|
||||
run block which is executed after the module has been initialized. All we need
|
||||
to do is inject it as a dependency and then use the methods provided in the
|
||||
extensible service to override or modify steps. In this example, we are going to
|
||||
prepend our custom step so that it will show up as the first step in the wizard.
|
||||
|
||||
::
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('horizon.app.core.images')
|
||||
.run(myPlugin);
|
||||
|
||||
myPlugin.$inject = [
|
||||
'horizon.app.core.images.basePath',
|
||||
'horizon.app.core.images.workflows.create-volume.service'
|
||||
];
|
||||
|
||||
function myPlugin(basePath, workflow) {
|
||||
var customStep = {
|
||||
id: 'mypluginstep',
|
||||
title: gettext('My Step'),
|
||||
templateUrl: basePath + 'steps/mystep/mystep.html',
|
||||
helpUrl: basePath + 'steps/mystep/mystep.help.html',
|
||||
formName: 'myStepForm'
|
||||
};
|
||||
workflow.prepend(customStep);
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
.. Note ::
|
||||
|
||||
Replace ``horizon.app.core.images.workflows.create-volume.service`` with
|
||||
the workflow you intend to augment.
|
||||
|
||||
mystep.controller.js
|
||||
--------------------
|
||||
|
||||
It is important to note that the scope is the glue between our controllers,
|
||||
this is how we are propagating events from one controller to another. We can
|
||||
propagate events upward using the $emit method and propagate events downward
|
||||
using the $broadcast method.
|
||||
|
||||
Using the $on method, we can listen to events generated within the scope. In
|
||||
this manner, actions we completed in the wizard are visually reflected in the
|
||||
table even though they are two completely different widgets. Similarly, you can
|
||||
share data between steps in your workflow as long as they share the same parent
|
||||
scope.
|
||||
|
||||
In this example, we are listening for events generated by the wizard and the
|
||||
user panel. We also emit a custom event that other controllers can register to
|
||||
when favorite color changes.
|
||||
|
||||
::
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('horizon.app.core.images')
|
||||
.controller('horizon.app.core.images.steps.myStepController',
|
||||
myStepController);
|
||||
|
||||
myStepController.$inject = [
|
||||
'$scope',
|
||||
'horizon.framework.widgets.wizard.events',
|
||||
'horizon.app.core.images.events'
|
||||
];
|
||||
|
||||
function myStepController($scope, wizardEvents, imageEvents) {
|
||||
|
||||
var ctrl = this;
|
||||
ctrl.favoriteColor = 'red';
|
||||
|
||||
///////////////////////////
|
||||
|
||||
$scope.$on(wizardEvents.ON_SWITCH, function(e, args) {
|
||||
console.info('Wizard is switching step!');
|
||||
console.info(args);
|
||||
});
|
||||
|
||||
$scope.$on(wizardEvents.BEFORE_SUBMIT, function() {
|
||||
console.info('About to submit!');
|
||||
});
|
||||
|
||||
$scope.$on(imageEvents.VOLUME_CHANGED, function(event, newVolume) {
|
||||
console.info(newVolume);
|
||||
});
|
||||
|
||||
///////////////////////////
|
||||
|
||||
$scope.$watchCollection(getFavoriteColor, watchFavoriteColor);
|
||||
|
||||
function getFavoriteColor() {
|
||||
return ctrl.favoriteColor;
|
||||
}
|
||||
|
||||
function watchFavoriteColor(newColor, oldColor) {
|
||||
if (newColor != oldColor) {
|
||||
$scope.$emit('mystep.favoriteColor', newColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
mystep.help.html
|
||||
----------------
|
||||
|
||||
In this tutorial, we will leave this file blank. Include additional information
|
||||
here if your step requires it. Otherwise, remove the file and the ``helpUrl``
|
||||
property from your step.
|
||||
|
||||
mystep.html
|
||||
-----------
|
||||
|
||||
This file contains contents you want to display to the user. We will provide a
|
||||
simple example of a step that asks for your favorite color. The most important
|
||||
thing to note here is the reference to our controller via the ``ng-controller``
|
||||
directive. This is essentially the link to our controller.
|
||||
|
||||
::
|
||||
<div ng-controller="horizon.app.core.images.steps.myStepController as ctrl">
|
||||
<h1 translate>Blue Plugin</h1>
|
||||
<div class="content">
|
||||
<div class="subtitle" translate>My custom step</div>
|
||||
<div translate style="margin-bottom:1em;">
|
||||
Place your custom content here!
|
||||
</div>
|
||||
<div class="selected-source clearfix">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<div class="form-group required">
|
||||
<label class="control-label" translate>Favorite color</label>
|
||||
<input type="text" class="form-control"
|
||||
ng-model="ctrl.favoriteColor"
|
||||
placeholder="{$ 'Enter your favorite color'|translate $}">
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- row -->
|
||||
</div><!-- clearfix -->
|
||||
</div><!-- content -->
|
||||
</div><!-- controller -->
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
Now that we have completed our plugin, lets package it and test that it works.
|
||||
If you need a refresher, take a look at the installation section in
|
||||
:doc:`Plugin Tutorial </tutorial/plugin>`.
|
Loading…
Reference in New Issue