@jatahworx/bhive-toolkits

Palette toolkits

Stats

StarsIssuesVersionUpdatedCreatedSize
@jatahworx/bhive-toolkits
8.0.02 months ago4 years agoMinified + gzip package size for @jatahworx/bhive-toolkits in KB

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 the defaults 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)

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 or false
      • 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 initdefaults context refers to the defaults Object of the current node. Repopulate/change the defaults 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 before oneditprepare. 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 operations

    • onpropertiesvalidated (function(SD) => void): Event called after default required fields are validated

    • oneditsave (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 or false

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

If you find any bugs or have a feature request, please open an issue on github!

The npm package download data comes from npm's download counts api and package details come from npms.io.