This change addresses the warnings and errors that are displayed when the docs are built, including: * Add reference to previously unreferenced workflow_extend in index file * Remove reference to a _static directory that doesn't exist * Fix formatting issues within the workflow_extend document Comments in the bug report discuss the need for warnings to be treated as errors, but this does not seem to be possible using the setup.py build_sphinx command. Change-Id: Iccccb9d104df9847ecd8a52aa73a7aa450bb5f34 Partial-Bug: #1411719
6.5 KiB
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 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.
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);
.$inject = [
myPlugin'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'
;
}.prepend(customStep);
workflow
}
; })()
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)
.$inject = [
myStepController'$scope',
'horizon.framework.widgets.wizard.events',
'horizon.app.core.images.events'
;
]
function myStepController($scope, wizardEvents, imageEvents) {
var ctrl = this;
.favoriteColor = 'red';
ctrl
///////////////////////////
.$on(wizardEvents.ON_SWITCH, function(e, args) {
$scopeconsole.info('Wizard is switching step!');
console.info(args);
;
})
.$on(wizardEvents.BEFORE_SUBMIT, function() {
$scopeconsole.info('About to submit!');
;
})
.$on(imageEvents.VOLUME_CHANGED, function(event, newVolume) {
$scopeconsole.info(newVolume);
;
})
///////////////////////////
.$watchCollection(getFavoriteColor, watchFavoriteColor);
$scope
function getFavoriteColor() {
return ctrl.favoriteColor;
}
function watchFavoriteColor(newColor, oldColor) {
if (newColor != oldColor) {
.$emit('mystep.favoriteColor', newColor);
$scope
}
}
}
; })()
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 Plugin Tutorial </tutorials/plugin>
.