@jatahworx/bhive-toolkits
v9.3.0
Published
Palette toolkits
Downloads
78
Readme
bhive-toolkits
Service Designer
Creating A Node
View
Using GADBAD (Generating Attributes Dom Based on Attribute Def)
This will take care of DOM creation and form validation for the defaults
Define the
attrDef
object for each of thedefaults
object preperty in the ${nodename}.HTML file.Properties of
attrDef
object- attrType: type of the field (each value corresponds to a Jquery widget)
values can be: 'INPUT' | 'TOGGLE_BUTTON' | 'SELECT' | 'TYPED_INPUT' - label: Label text to be used for that field
- options:
options
object expected by the each type of widget (documented below under each widget)
- attrType: type of the field (each value corresponds to a Jquery widget)
Example:TestNode.html
(Refer "nodeDef" topic under Registering NodeType for ht other nodeDef
properties' description)
<script type="text/x-red" data-template-name="TestNode"></script>
<script type="text/javascript">
registerNode({
nodeType: 'TestNode',
nodeDef: {
color: "black",
defaults: {
testdata: {
value: 'Default test data; Changes should reflect back;',
attrDef: { attrType: 'INPUT', options: { placeholder: 'testdata', required: true } }
},
thisisthenewdefault: {
value: 'test you',
attrDef: { attrType: 'INPUT', options: { placeholder: 'thisisthenewdefault' } }
},
anothernewdefault: {
value: 'another test you',
attrDef: { attrType: 'INPUT', options: { placeholder: 'anothernewdefault' } }
},
testinganotherone: {
value: 'testinganotherone',
attrDef: { attrType: 'INPUT', options: { placeholder: 'testinganotherone' } }
},
amqpConfig: {
type: 'amqp-config', value: {}, required: true, options: {},
attrDef: { label: 'AMQP Config' }
},
checkbox: {
value: false,
attrDef: {attrType: 'TOGGLE_BUTTON', options: {label: 'A togglebutton'}}
}
},
.
.
.
// Other properties
}
});
</script>
NOTE
Limitations:
- Editable list is not yet implemented
- switching between fields is not current supported in this. It has to be manually
implemented in "oneditprepare" hook
Codegen
Registering NodeType
nodeType
serviceType: ("client"|"server")
nodeDef: All the function properties' "this" will refer to the current node.
defaults: (object) the editable properties for the node. Each property in "defaults" is an object and can have following properties
- value: initial value for the property
- validate(Regex | function(v, ServiceDesigner)) => boolean: This is used for validation of the property after a node is added to the canvas and after the node is edited. It should return
true
orfalse
- required(boolean): If the field is required fr he node to be valid.
- Example for "defaults" object: (Snippet from the "HttpOut" server node)
defaults: { // input text fields name: { value: '' }, // headers headers: { value: { type: 'bh.input', value: '' } }, // response body responseBody: { value: { type: 'bh.input', value: '' }, validate: function (v) { return this.responseType === 'next' || server.validators.patterns.noblank.test(v.value); } }, httpcode: { value: '', validate: function (v) { return this.responseType === 'next' || server.validators.patterns.noblank.test(v) } }, responseType: { value: '', required: true }, responseMapping: { value: '', }, cookies: { value: [] }, // ports inputs: { value: 1 }, outputs: { value: 0 }, editableListData: { value: { headers: [], } }, cookiesList: { value: {} }, switchStates: { value: { headers: 'Map', cookies: 'Map' } }
inputs: (number) how many inputs the node has, either 0 or 1.
outputs: (number) how many outputs the node has. Can be 0 or more.
color: (string) the background colour to use.
paletteLabel: (string|function) the label to use in the palette.
label: (string|function) the label to use in the workspace.
labelStyle: (string|function) the style to apply to the label.
inputLabels: (string|function) optional label to add on hover to the input port of a node.
outputLabels: (string|function) optional labels to add on hover to the output ports of a node.
icon: (string) the icon to use.
oneditinit: (function) Event that opens the Edit dialog box, which can be used to initialize the input widgets on any of the DOM elements.
Note: node-input-{defaultProperty}, node-input-typed-{defaultProperty} values will get auto-initialized back to the respective input fields throughout this cycle.
Example:
<input id="node-input-name" placeholder="Name" /> ... <input id="node-input-typed-logObject" /> <!-- 'logObject' in id of the input tag matches the default property 'logObject' in the node (ref. to Comment-A) --> ...
registerNode({ nodeType: 'Log', serviceType: 'client', nodeDef: { ... ... defaults: { ... name: {value: ''}, logObject: {value: 'bh.input'}, // Comment-A ... }, oneditinit: function(ServiceDesigner) { ... ... $('node-input-name').inputField(); $('node-input-typed-logObject').typedInput({ types: [ ... ], change: validateForm }) } } })
initdefaults
((SRD: ServiceDesignerObject) => this:DEFAULTS)
:this
in initdefaultscontext
refers to thedefaults
Object of the current node. Repopulate/change thedefaults
Object and return for changing the defaults object dynamically. The first argument is the node object and second is the SRD object. Only works for Editing node, not for config node as the issue for dynamic defaults update only exists there.oneditinit
((SRD: ServiceDesignerObject) => void)
: Called beforeoneditprepare
. To be used to attach dynamic UI widgets.oneditprepare
(function(SD) => void)
: Event that can be used to pick-up the reinitialized values to further do any other operationsonpropertiesvalidated
(function(SD) => void)
: Event called after default required fields are validatedoneditsave
(function(SD) => void)
: called when the edit dialog is okayed.oneditcancel
(function(SD) => void)
: called when the edit dialog is cancelled.oneditresize
(function(SD) => void)
: called when the edit dialog is resized.afteradd
(function(SD) => void)
: Called after a node is added to the set of nodes in the service-designer services.onpropertieschange
(function(oldPropertyValues, ServiceDesigner))
: called after node properties are changed, just after "oneditsave" or when "undo" is performed.afterservicerename
(function(ServiceDesigner))
: called after the node's service is renamed.shape 'circle' for start type nodes or leave blank for the default 'square'.
docsLink
(string | funciton(serviceDesignerType: "client" | "server"): {nodePath: string} | {fullPath: string})
Example:
// As a string docsLink: 'start-node' // As a function #1 - that returns only the nodepath docsLink: function(serviceDesignerType) { return { nodePath: 'start-' + serviceDesignerType + '-node'; } } // As a function #2 - that returns the entire url docsLink: function(serviceDesignerType) { return { fullPath: 'docs.official.website/node-docs/' + serviceDesignerType + '/start-node'; } }
category
(string)
: the palette category the node appears in
Styling Node Attribute Window
- Create a class for the node under 'bhive-ad/src/scss/nodes' folder
- SCSS classes should be nested under the attribute selector -
[servicetype][editing-node-type="NodeType"]
Example: If the nodeType is "HttpRequest" and the servicetype is "server", then the class structure of the "httprequest.scss" file would be,
// This prevents your node style bleeding into other DOM elements.
[server][editing-node-type='HttpRequest'] {
.node-input-field {
width: 100%;
}
input[type='text']:focus {
background: gray;
}
}
- Finally, import the style in styles.scss
Node Dev Utils
SwitchFields (util.service.ts>switchFields()) : Use this function to toggle 2 fields with a switch(button). Current state can also be retrieved which might be used for displaying the correct field when openeing the editor window.
ServiceDesigner.utils.isValidHttpStatusCode(httpStatusCode);
: Returns boolean. Validates against a list of http status codes.A node user can create assignment complex object by creating:
<input id="node-input-a.b.c" />
defaults: { // you will have to provide two defaults // one with the mapping 'a.b.c': { value: '' }, // one as a default a: {value: ''} }
the node will auto populate default property 'a' with whatever value is assigned to 'node-input-a.b.c', and generate a object:
a: { b: { c: '' } }
JQuery Widgets
[1. inputField widget]
options
HTML attrs acknowledged by this widget
- placeholder: Can be a string or "[i18nPrefix]path"
- required
Example
<!-- <placeholder form i18n> -->
<input
type="text"
id="cookies-name"
placeholder="[n-sd]common.label.name"
required
/>
OR
<!-- <plaintext placeholder> -->
<input type="text" id="cookies-name" placeholder="Name" required />
properties:
- wrapperClass:(string) - Add classes to the wrapper div separated by space.
- wrapperAttr:({ [key: string]: any }) - Append attributes to wrapper div. JQuery PlainObject with keys(attr name) and values(attr value)
- inputClassList?:(string) - Space seperated classes.
- placeholderClassList?:(string) - Space seperated classes.
- placeholder?:(string) - Text to show as input field's placeholder.
- attrs?: ({ [key: string]: any }) - JQuery PlainObject with keys(attr name) and values(attr value).
- props?: ({ [key: string]: any }) - JQuery PlainObject with keys(prop name) and values(true/ false).
- value?:(string) - default value for the inputField.
- validateOnCreate?:(boolean) - Wheather validation should run as soon as the widget gets created.
- validatorRegexp?: RegExp; - Regex to validate the input value against.
- errorText?:(string) - Custom error message when the input value fails the test against pattern.
- errorClassList?:(string) - Space seperated classes,
- required?: (boolean) - true if the inputField is required.
- disabled: (boolean)
Dynamically Updatable Options
placeholder
attrs
wrapperAttr
Example
// updating "placeholder" after initialization $('#node-input-name').inputField('option', { placeholder: 'asdasdas' });
Functions:
- validator: (inputValue: string) => {valid: boolean, errorMessage: string} - Function called on 'input' event to the inputElement. It should return validity and associated errorMessage (if invalid).
- updations: (elmData: any, inputValue: string) => any - Miscellaneous updates. Called after the input value validation.
- onError: Function that should be executed if the inputfield value becomes invalid(function).
Public methods:
- show: displays the widget
- hide: hides the widget
- toggle: hides if displayed. else, displays.
- reset: clears the value and clears the data associated with the inputField.
- valid: get the validity of the inputField.
- value(v): Use this to correctly set the value. If 'v' is empty, it returns the current value.
Usage Example:
$('#node-input-name').inputField({
validator: function (v) {
let valid = true;
let msg = '';
if (!SD.validators.patterns.validbh.test(v)) {
valid = false;
msg = 'Name should contain alphanumeric chars';
} else if (
SD.nodes
.workspaceNodes(node.type, node.id, 'name', node.z)
.nodePropsArr.includes(v)
) {
valid = false;
msg =
'Middlewarestart node with the same name exists in this workspace';
}
return {
valid: valid,
errorMessage: msg,
};
},
validateOnCreate: true,
disableDoneIfInvalid: true,
enableDoneIfValid: true,
});
2. selectField widget
Provide a JSON object of the format shown below:
Properties
<select id="node-input-selectFieldname"></select>
To give tooltip for the option, define a property "description".
Example:
{value: 'application/json', displayValue: 'JSON', description: "Select this if the server sends json data"}
optionsgroupData example:
$('#node-input-selectFieldname').selectField({
optionsgroupData: [
{
'group 1': [
{ id: 'opt1', name: 'option1' },
{ id: 'opt2', name: 'option2' },
],
'group 2': [
{ id: 'opt3', name: 'option2' },
{ id: 'opt4', name: 'option3' },
{ id: 'opt5', name: 'option4' },
],
},
],
value: node.encoding,
change: val => {
validateForm();
},
});
3. toggleButton widget
options
Properties
- cssObject: Jquery cssObject - It will be applied on the outermost element of the toggleGroup.
- label: string - Label for the button toggle.
- labelCss: Jquery cssObject for styling the togglebuttn label.
- states: {on: string, off: string} - Name for the 'on' and 'off' states.
- labelId: string - Id applied for the label
- inputId: string - Id applied to the input and used in the label for attributes and it will treated like clicking on the associated input element
- containerId - string: adds th id to the container of the toggle button
Functions
- afterToggle: (checked: boolean) => any - Executed after the button has been toggled (either on or off).
Public Methods
- toggleOn: toggle on the button.
- toggleOff: toggle off the button.
- state: Get the assciated state of the current button position. If no state option was provided, returns
true
orfalse
Usage Example:
<input type="checkbox" id="node-input-useProxyAuth" />
$('#node-input-useProxyAuth').toggleButton({
label: SRD._('httpProxy.label.useProxyAuth'),
labelCss: {
'margin-right': '3em',
},
cssObject: {
'margin-top': '1.5em',
},
// Provide state
states: {
on: 'use',
off: 'donotuse',
},
afterToggle: updateProxyAuth,
});
// Get the current state
const state = $('#node-input-useProxyAuth').toggleButton('state');
// "state" now contains 'use' or 'donotuse' string as per the 'states' options object
4. editableList widget
Official Docs: https://nodered.org/docs/api/ui/editableList/
options
Properties:
- addButton : boolean|string - text for add label, default 'add'
- height : number|'auto'
- sortable : boolean|string - string is the css selector for handle
- connectWith : css selector of other sortables
- removable : boolean - whether to display delete button on items
- scrollOnAdd : boolean - whether to scroll to newly added items
- showAddBtnLabel: boolean - Whether to show the addButton label as its buttonName.
Functions
- resizeItem : function(item) - called to resize individual item
- sortItems : function(items) - when order of items changes
- resize : function - called when list as a whole is resized
- addItem : function(row,index,itemData) - when an item is added
- removeItem : function(itemData) - called when an item is removed
- filter : function(itemData) - called for each item to determine if it should be shown
- sort : function(itemDataA,itemDataB) - called to sort items
- validator: function - called before adding an item to the edtableist. If "false", it is skipped.
Public methods
- addItem(itemData)
- removeItem(itemData)
- width(width)
- height(height)
- items()
- empty()
- filter(filter)
- sort(sort)
- length()
- checkUnique(editableListDataArray)
5. typedInput widget
Official Docs: https://nodered.org/docs/api/ui/typedInput/
options
Properties:
Functions
Public methods
CSS classes for alignemtments
editor-form-row - Should be applied to immediate parent element if there is no error message
editor-form-row-error-msg - Should be applied to immediate parent element if there is error message
editor-form-row-label - Should be applied to every label
editor-form-row-with-sub-ele - Sholud be applied to immediate parent element if there are any sub elements are present
editor-form-row-sub-ele - Should be applied if the element is sub element
Node Codegen
Methods
generateImports()
: Should return an array of library, modules and alias.
/** * @param {{depth: number, pathToUtilsRoot: string, pathToServiceRoot: string}} rootPaths * @returns {{ * library: string, * modules?: [string], * alias?: string, * default? string, * }[]} imports */ generateImports(rootPaths) { return [ { library: 'express-session', alias: 'expressSession', }, { library: '../helper/generic/SessionStore', modules: [ 'TypeormStore' ] }, { library: 'typeorm', modules: [ 'getConnection' ] } ] }
generateSnippet()
: Should return a string which will be generated in the placeholder of the node.updateTemplate(serviceClassTemplate)
: This callback gets the whole service file as string. Manipulate anything and return the file string back for codegen.getErrorTemplate()
: A template to validate your generated code against. Default:
getErrorTemplate() { return ` export class errorCheck { //appendnew_node } `; }
getCallTemplate()
: If your snippet is a function then, it will need a call template.getCallTemplate() { return "bh = await this." + this.functionName + "(bh);" }
Method Variables:
this.viewType
: Name of the supported views.// supported types { COMMON: 'common', SERVER: 'server', CLIENT: 'client', MIDDLEWARE: 'middleware' } // Usage: this.viewType = BaseComponent.viewTypes.SERVER;
this.nodeType
: Name of the supported node type.START: 'start', MIDDLEWARE: 'middleware'
} // Usage: this.nodeType = BaseComponent.nodeTypes.MIDDLEWARE;
Generic style class
- The generic-style.scss file contains the trivial css stylings that can be included for the node template custom styling.
- We can also specify the custom CSS class in the generic-style.scss class which is located in 'src/scss' folder. ```css .padding-left-0 { padding-left: 0 !important; }
.padding-right-0 { padding-right: 0 !important; }
.padding-top-0 { padding-top: 0 !important; }
.padding-bottom-0 { padding-bottom: 0 !important; }
.margin-left-0 { margin-left: 0 !important; }
.margin-right-0 { margin-right: 0 !important; }
.margin-top-0 { margin-top: 0 !important; }
.margin-bottom-0 { margin-bottom: 0 !important; }
.margin-top-1 { margin-top: 1 !important; }
.margin-bottom-1 { margin-bottom: 1em !important; }
.width-100 { width: 100% !important; }
.height-100 { height: 100% !important; }
.diplay-block { display: block !important; }
.display-flex { display: flex !important; }
.vertical-align-top { vertical-align: top !important; }
## Componets Development
### Attribute View Types
- AUTOCOMPLETE
* Example attribute definition using "AUTOCOMPLETE" type:
```javascript
let anAttributesInstance = null;
module.exports = class AnAttribute {
constructor() {
if (!anAttributesInstance) {
anAttributesInstance = this;
this.displayAs = 'anAttr';
this.value = '[anAttr]';
this.type = 'AUTOCOMPLETE';
/*
* Note: "this.values" type is "Array<string> | Array<{value: any, display: string}>"
* and, "display" field should have the name of one of the fields in "value" property
* if the type is Array<{value: any, display: string}>.
*/
this.values = [
{ display: "Left", value: { a: 'adasd', Left: 'asdasd' } },
{ display: "Center", value: { l: "center", Center: "000" } },
{ display: "FuckThis", value: { k: "justify", FuckThis: "Yes" } }
];
}
return fxShowInstance;
}
}
- DROPDOWN
- TOGGLE
- LIST_DIALOG