@simple-ui/workflow
v1.2.2
Published
Workflow is a utility to model logic-driven, state-based, user-driven workflows
Downloads
2
Readme
Workflow
@simple-ui/workflow
Workflow is a utility to model logic-driven, state-based workflows. Workflow is used to define a series of steps where step progression can change dynamically. One sequence of work exists as an exterior index for the end-user (in the interface) and an interior index to control a more complex process workflow. A Workflow is an object which encapsulates all logic related to a set of steps and so provides helper methods to query the state of the workflow, to support easy interface control for templates.
Install
Install with npm.
npm install --save @simple-ui/workflow
Install with bower.
bower install --save @simple-ui/workflow
Lodash Dependency
This library requires a small set of lodash. Use lodash-modularize to limit how much of lodash is included in your project.
Quick Usage
import Workflow from "@simple-ui/workflow"
var workflow = Workflow(['one', 'two', 'three']);
// many is* methods to control interface state
assert(workflow.current() === 'one');
assert(workflow.isBeforeLast() === true);
// next will return the next value and advance the internal index
assert(workflow.index === 0);
assert(workflow.next() === 'two');
assert(workflow.index === 1);
Usage
Workflow Scenarios
The following example(s) demonstrate the power of a Workflow and usefulness of managing two indices.
Form Validation
Every page/view within a multi-part form should have a validation method.
var workflow = Workflow({
'step1': {
// NOTE 'step1' is not valid, so the rule will keep the Workflow at index 0
isValid: function() { return false; },
content: {}
},
'step2': {
isValid: function() { return true; },
content: {}
}
});
// Rule: if the current view is not valid, assign the workflow to the current workflow
workflow.reflow().rule(function(requestedIndex, requestedItem) {
if (!this.current().isValid()) {
return this.index;
}
});
workflow.next(); // same as workflow.index = 1 (or any other index)
workflow.index === 0; // the valid method at index 0, prevents progression
User Permission
A Workflow can be used to construct the steps presented to an end-user.
var workflow = Workflow({
'step1': {
isPermitted: true,
content: {}
},
'step2': {
isPermitted: false,
content: {}
},
'step3': {
isPermitted: true,
content: {}
}
});
// Rule: Scan to next/previous permitted item
workflow.reflow().rule(function(requestedIndex) {
return this.scanIndex(function(scanIndex, scanItem) {
return scanItem.isPermitted;
}, (requestedIndex < this.index) ? -1 : 1);
});
workflow.next();
workflow.next();
workflow.index === 2; // it scanned to the next permitted item and not beyond
workflow.previous();
workflow.previous();
workflow.index === 0; // it scanned to the previous permitted item and not beyond
Isolated Parts
A Workflow may be initialized with multiple sets of reflow objects each defining progression rules. It is useful when providing a Workflow to a component that needs to swap progression rules based on application modes.
var workflow = Workflow([1, 2, 3, 4, 5, 6, 7, 8, 9]);
// Apply a reflow with no rules, normal +1 rules for next() apply
workflow.reflow('normal-progression');
workflow.first();
workflow.next();
workflow.next();
// Apply a reflow with skipping odd
workflow.reflow('skip-odd').rule(function(requestIndex) {
return (requestIndex % 2 === 0)
? requestIndex
: requestIndex + 1;
});
workflow.reflowWith('skip-odd');
workflow.first();
workflow.next();
workflow.next();
// Apply a reflow object directly
workflow.reflowWith(workflow.reflow().rule(function(requestIndex) {
return requestIndex + 1;
}));
Workflow API
Initialize a Workflow
A Workflow can progress over the following types:
integer
which is converted to an array[0, 1, 2, 3, ..., <integer>]
array
object
assert((Workflow(3)).size() === 3);
assert((Workflow([2, 3, 4])).size() === 3);
assert((Workflow({ '3':4, '5':4, '1':2 })).size() === 3);
The Workflow object also doubles as a factory for itself.
var workflow = Workflow();
var workflow = Workflow.create();
Moving through a Workflow
A Workflow keeps track of an internal index. By default a Workflow maps it's index directly to the underlying source. With an array Workflow, if index = 2
, the current()
you return the item at index 2.
var workflow = Workflow([2, 3, 4]);
workflow.firstIndex() === 0; // always 0
workflow.lastIndex() === 2; // last index of an array of 3
workflow.index === 0; // defaults to 0
workflow.isFirst() === true; // index is at 0 which is first
workflow.isLast() === false; // index is at 0 which is not the last
workflow.isAfterFirst() === false // index is at first, so it cannot be after it
workflow.isBeforeLast() === true // index is less than lastIndex()
These methods are most useful in a template, this example uses an imaginary templating language.
<section class="wizard">
{{ customViewAtIndex(workflow.index) }}
<button *-show="workflow.isAfterFirst()">Previous</button>
<button *-show="workflow.isBeforeLast()"
*-click="workflow.next()">
Next
</button>
</section>
A Workflow bounds the index.
var workflow = Workflow([2, 3, 4]);
workflow.index = 1;
workflow.index === 1;
// assign an index under the first index, so we set to first
workflow.index = -3;
workflow.index === 0;
// assign an index over the last index, so we set to last
workflow.index = 6;
workflow.index === 2;
// assign a non-numerical index, leave the index at the same location
workflow.index = 'as';
workflow.index === 2;
Workflows of Objects
The object stored at the index can be retrieved too.
var workflow = Workflow(['two', 'three', 'four']);
workflow.current() === 'two'; // defaults to 'two'
workflow.peekFirst() === 'two'; // always the first object
workflow.peekLast() === 'four'; // always the last object
Workflow Size
The size of the object being progressed over.
var workflow = Workflow([2, 3, 4]);
workflow.length === 3;
workflow.size() === 3;
License
MIT © mwjaworski
This software is released under the MIT license:
Copyright (c) 2017 mwjaworski [email protected]
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.))