Tutorial #5. Create custom web interface.


This tutorial describes how to make custom interface for your bot.

By default BAS generates user interface automatically. Default interface requires zero time to create, because it is generated automatically. It is functional and reliable. But this approach has several disadvantages:

  1. Default interface is not customisable. You can't change any its part, for example, change label, color of some element.
  2. All bots looks the same. This item is a consequence of the first point.
  3. Default interface has 2 windows: resource selecting and script state. First one is shown before script starts to let user fill settings on how script will work, second one shows log, result, browser state, etc. Such user interface structure is hardcoded and is not a subject of change.

Custom user interface is much more flexible, here are list of advantages:

  1. Everything is customisable, you can change every button, every label, colors, styles, animations, backgrounds, everything! Only 2 things can't be changed right now - it is windows border generated by OS and tray icon popup menu.
  2. White label your script, users do not need to know that your bot is created with BAS. Total customisation will make it look unique and not recognizable as BAS product.
  3. Custom interface is build with html, javascript and css, and you can use any web framework, snippet or library to build your interface. For example, you can find grid javascript library and visualize database content.
  4. Web interface has rich API, which may interact with BAS script.

Here is how custom interface may look like. You can launch it right inside browser. Custom interface demo.


Custom interface requirements.

Here are a list of requirements to start to work with custom interface:

  • First of all you need to have a project to work with. We will be using SiteVisitor script. It is better if script has a resources, however it is not mandatory to have resources, custom interface can be created even without them.
  • You must download BAS and be a premium user. Premium account is required to create web interface.
  • Your project must be protected. Check this article for instructions.


Getting started with custom interface.

Custom interface is stored in a cloud. Data is stored online because doing so will deliver changes instantly to every user.

To start working with custom interface you need to visit interface page.

Then select script to edit interface like this:



Enable web interface with following link:



Now you have a web interface connected to your script. Note, that you don't need to create interface from scratch. Functional and well looking interface is already generated for you. Later we will change it, but right now lets try to test it and see how it works.

To launch your new interface hit 'Record' button and then input your username and password:



If you don't see 'Web interface' window, then it is probably because your script name inside project doesn't match script name on server. To fix this, hit compile button(Menu → Build → Compile), change the script name and compile.

New window with custom interface uses real values, the resources, that you enter there is processed by BAS as real one, it also displays real log and real script statistic. You can now trace your script or run actions one by one, to see how user interface will respond.

Web page for custom interface contains several settings which are worth mentioning: availability of interface to you only or to all users, debugging interface with browser developer tools, if interface must be started in real or in embedded browser. Check this page for more information:




Editing custom interface basics.

Custom interface consists of two pages: main and login. Login page has only login form and logs about connection process. It is hidden right after login was successful and visible to every user, even not authorized. Whole script functionality is located on main page. Main page is visible to authorized users only. Typically it contains resources selection dialog, where all inputs are located and script dashboard with information about script execution.

We will edit only main page, but same approach may be applied to login page.

To start editing click on 'Edit interface' button:



After that you can see interface which may look a little bit complex, but don't worry, everything will be explained in this manual.

Take a look at a central part, this is custom interface, which was generated automatically. It looks not exactly the same as user will see it, to look at final state, you need to click on preview button:



Now click on 'X' button to close preview(at the right-top corner) and lets make a simplest possible change to user interface that we can do - edit script title. To do that, click on it and input new value, like this:



Another way to change label text is by editing its properties. Click on a label to select it and visit properties tab. It has cog icon and located at top-right corner. Each item inside big central panel is element, different elements has different types. And each element type has some properties. For example, element, that we currently selected has property 'Text', and if we change it on properties panel, changes will be reflected inside user interface:



Right now we made some changes to script interface, but if we try to run it in BAS, we will still see old interface version. To update script interface, we need to click on 'Save changes on server' button:



Now changes are reflected in BAS for you and all your users. But if you select resources and proceed to next page, you will see old title. That is because default interface contains two tabs: 'Resources' and 'Script progress'. We have changed title inside first tab, now we need to change it for the second one. Go to the editor, click on 'Script progress' to switch tab and change title there:



Element with 'Tabs' type used very often inside default interface, and you can easily add new tabs, or change existing.



Changing styles.

Changing element style may be accomplished by using 'Styles' panel. First of all select element by clicking on it, then click on tassel icon in the top right screen corner. This panel works almost in a same way as element properties, except there is more settings for stlye, than properties, so this panel contains several groups. Lets change title color and font size. Corresponding settings are located in 'Typography' group:



There are a lot of styles and describing each one is out of scope of this manual. But one important thing is 'Flex' group. Settings from this group are related to css flexbox layouts. These settings helps to position elements and heavily used for default interface. See how several button may be arranged inside flex container:




Elements hierarchy.

Elements are organized in a tree structure, just like DOM in html. Each element may have single parent and several or none children. You can view element tree in corresponding panel:




Creating new elements.

Last unexamined panel is panel that contains available element list, you can drag element from there and drop it anywhere into interface. Next gif shows how to add link to your website:



Previous video should be self explanatory - we are dragging new element near script title, arrange it to the right, tweak element height and set target url through properties. Only one thing not obvious here, is that link target must be 'New Window'. Because if you open link in current window, it will replace custom interface.


Elements layout.

Is is not recommended to set exact top and left position for element. Much better approach would be to place them in special containers called layouts. Using layouts would give approximately same results for different screen sizes. typical form can hold a list of layouts called '2 Columns' like its shown on a video:




Custom logic.

At this point we examined how to change interface appearance, but what about interface logic? Consider following example, you are adding a button and want to show message when button is clicked. To do that, switch to 'Properties' panel and select 'OnClick' event.



Doing so will create a new event callback and transfer you to the custom interface code editor:



Events are processed with javascript, and you can put any javascript code inside that field, that code will be executed at every button click. Lets put there something like:

alert('Button clicked')

You can see, that screen is spitted into four panels: Html, Javascript, Css and Preview. First three panels holds interface source, they reflect all changes made on previous steps and vice versa all changes here will be saved as properties or style settings on main screen. Notice, that changes inside first 3 tabs are immediately visualized on 'Preview' tab. 'Preview' tab shows final interface look, it includes javascript code, html markup and css styles. So, after adding 'alert' function to 'OnClick' event and clicking on that button, proper message will be displayed. You can return to main interface by clicking on 'X' button at right top corner:



You don't have to add event handler to open code editor again, it is sufficient to click on 'Code' button:



By default javascript panel may use any valid javascript code together with jquery library. Third party libraries may be added, but it will be discussed later. For now, lets write a code that sets input field value when button is clicked. To do that first we need assign meaningful id to field which will be changed, because we need to identify element somehow. It could be done from Html panel or from 'Id' setting:



Finally, lets add a code, which changes value:

$("#LoginField").val("Code updated")

Check jquery documentation for more details about their API.




Adding custom components.

Another interesting library, which is included by default is uikit. It is a framework to build web interfaces. Custom interface uses uikit, so if you will use it too, your changes will look more organic. Lets add uikit's progress bar to our interface. Good place to start will be to look at element documentation. From there we find out, that element markup is following:

<progress class="uk-progress" value="30" max="100"></progress>

And the advantage of using html as a foundation for custom interface is that we could just paste that code into Html panel:



Preview tab is updated immediately, and we have our progress bar now. Another challenge would be change its value every time the button is clicked. To achieve this we need to replace button click handler with following code:

$("#Progress")[0].value += 10



Adding custom components.

Third party libraries may be added to custom interface in any amount. As an example, we are going to add moment.js library, it works with dates. Click on 'Change' button inside Javascript panel header to see the list of included *.js files and add there moment.js, its url is following: https://momentjs.com/downloads/moment.js:



Third party library may also include css or several js scripts.


Updating custom interface from BAS.

BAS is able to send javascript code, which will be executed inside custom interface context. This code may have different purposes, for example, changing element values, switching tabs, showing notifications or even adding new elements. In fact, this javascript code may do almost anything. We are going to create two BAS actions which hides and shows button with specified id.

Open 'User interaction' module and select 'Run javascript in web interface' action to do that, put following code there:

$("#StopScript").show()

and to hide button:

$("#StopScript").hide()

This code shows and hides button with id 'StopScript'. Interface, that was generated by default, contains button with id 'StopScript', which task is to stop script when clicked.




API.

Custom interface provides API which main goal is to interact with BAS.

Each API method may be called from any place inside javascript code. For example, following code will immediately restart script:

Api.Restart()

If you place that code inside button click handler, then click on that button will cause entire script restart.

Restart method will return immediately, but other methods may require time to finish. In that case method will return a Promise object, use 'then' keyword to obtain result:

Api.GetGlobalVariable("TEST").then(function(res){
    console.log(res)
})

Custom interface may receive events from BAS. Events are used to notify interface about number of threads changed, about new log messages or any other script state change. Every time BAS wants to inform interface about something, it sends an event. Custom interface must set an event handler one time on page load, like this:

//Set event handler
Api.SetEventHandler(function(EventType, EventData) {
   //Process log event
   if (EventType == "log") {
      //Obtain log text
      var Text = EventData["text"]

      //Output text to the browser console
      console.log(Text)
   }

})

That handler will be called on every event. You can check examples in default interface implementation.

Here are list of API methods and events grouped by theirs purpose.


User authentication.

These methods are used during user authentication on login page.

Note. By default all page content is hidden, when page is ready, you can show interface by calling

$("body").fadeIn()


Method 'Init'

Api.Init(0)

This code inits API, it should be called once and only on login page. You should not call this method on main page.



Event 'login'

if (EventType == "login") {
    var Username = EventData["username"]
    var Password = EventData["password"]
}

Event with type 'login' is fired when BAS expects user to input login and password to authenticate. When event with type 'login' is received, custom interface should display login form. Event has 2 parameters: 'username' and 'password'. These are values from previous login, custom interface may set them as default values for current login.



Method 'Login'

Api.Login(Username, Password)

Authenticate user. 'Username' and 'Password' must be obtained from user input. This method must be call only after 'login' event is received, if you will call it after script started it will do nothing.

Note. This method is safe - it encrypts data before sending, if you want to re-implement user authentication, you must protect sensitive data by yourself.

Method returns immediately, if authentication has failed, custom interface will receive event with type 'message'. You don't need to process successful authentication, in that case login page will be disposed and main page shown automatically.



Event 'message'

if (EventType == "message") {
    var MessageText = EventData["text"]
}

Event with type 'message' is displayed after unsuccessful authentication. Custom interface should display error message and when user finishes reading it, API method 'MessageAccepted' must be call.



Method 'MessageAccepted'

Api.MessageAccepted()

This method must be call only after 'message' event is received and only after user have read that message.



Event 'show_database_connection'

This event is triggered during database connection, custom interface may show corresponding window. This event has no parameters.



Event 'show_database_connection'

if (EventType == "show_database_log") {
   var Text = EventData["text"]
}

New log message about database connection process. Custom interface may display that message.



Event 'finished_database'

This event is triggered after database connection succeeded. Custom interface may hide database connection window.



Method 'RunWithoutDatabase'

Api.RunWithoutDatabase()

If database connection takes too long, custom interface may call that method and script will be launched without database.



Starting embedded languages

Events 'show_embedded_connection', 'show_embedded_log', 'finished_embedded' and method 'RunWithoutEmbeddedLanguage' works exactly in a same way as corresponding entities for database, the only exception is that they are used during embedded language start process.


Check login page default implementation for user authentication API examples.


Managing script lifetime.

By default interface has 3 states: initial, running, stopped. Initial state requires user to input resources and hit 'Run' button, after that script state is changed to running. User may stop script and it sets script state to stopped, or restart it, which restores state to initial again. Stopped script state is almost same as running, except that interface is not updated anymore, but user can view it in readonly mode. This is how BAS script works by default, but you can change that with a help of custom interface and API. For example, you can inpur resources instead of user and run the script immediately after it starts. Or you can skip stopped state. It is impossible to run several scripts simultaneously with custom interface, but you can achieve same result by splitting functionality inside different threads.


Event 'start'

if (EventType == "start") {
   //Code   
}

Event 'start' is fired when interface state is changed to running. Custom interface may or may not show log panel, browser view, etc.



Event 'stop'

if (EventType == "stop") {
   //Code
}

Event 'stop' is fired when interface state is changed to stopped. It could happen because user stopped it manually, or for some other reason, in any case this event will be fired. Custom interface may show report or disable log or react in any other way.



Event 'restart'

if (EventType == "restart") {
   //Code
}

Script is restarted, it means that resource selection dialog must be shown and user must input all required values again. Interface state is changed to initial. Custom interface should return to the same state as it was in the beginning.




Method 'AcceptResources'

Api.AcceptResources()

This method changes script state from initial to running. If script state is not initial, this method will do nothing. After calling this method, BAS will try to get values for all resources: get filenames selected by user, input number. This process is also customizable. To obtain resource value BAS calls function GetResourceValue with parameter which equals resource name, like this:

GetResourceValue("username")

GetResourceValue must return a string with resource value. This function must be defined and implemented by custom interface. This is very powerful mechanism, which gives full control over script inputs. Lets look at several possible implementations. For example, if script has 2 resources - username and password, GetResourceValue may look like this.

function GetResourceValue(ResourceName)
{
   if(ResourceName == "username")
   {
      //This means, that username is always equal to 'login1'
      return "login1"
   }
   if(ResourceName == "password")
   {
      //This means, that password is always equal to 'pass1'
      return "pass1"
   }
   //Unknown resource name
   return ""
}

Previous implementation makes resource values static and always equals to same strings. Following approach may be used if you want to skip initial script state and proceed to running state immediately. You may use javascript or jquery to get user inputs:

function GetResourceValue(ResourceName)
{
   if(ResourceName == "username")
   {
      //Return value of input with id "username"
      return $("#username").val()
   }
   if(ResourceName == "password")
   {
      //Return value of input with id "password"
      return $("#password").val()
   }
   //Unknown resource name
   return ""
}

Default implementation looks like this:

function GetResourceValue(ResourceName) {
    return GetValue(ResourceName)
}

By default GetResourceValue will get actual user inputs by using GetValue function. You can take a default implementation as a foundation and tweak it, for example:

function GetResourceValue(ResourceName) {
    if(ResourceName == "username")
    {
       //This means, that username is always equal to 'login1'
       return "login1"
    }
    //Default implementation for everything else
    return GetValue(ResourceName)
}

This is a mix of dynamic and static implementation, if “username” resource is queried, then static string is returned, else function returns actual user input.



Method 'Restart'

Api.Restart()

This method changes script state from running to initial. If script state is not running, this method will do nothing.



Method 'Stop'

Api.Stop(true)

This method changes script state from running to stopped. If script state is not running, this method will do nothing. This method has one parameter - IsInstant. If it equals to true, then script execution will be terminated immediately, otherwise BAS will wait until all thread will end and all data will be proceeded. After script will be terminated, custom interface will receive 'stop' event.



Getting logs, reports and other script statistic.

There is a list of different methods and events to gather script statistic and information about how script is executed.


Event 'log'

if (EventType == "log") {
   var LogType = EventData["type"]
   var LogText = EventData["text"]
   var LogActionId = EventData["action_id"]
}

Log event is fired on every new log message. Custom interface is not limited on how it should process it. Log can be appended to text field, shown as notification, or simply ignored. EventData object contains type property with possible values: 'user', 'success', 'fail', 'info'. Here is implementation, which uses uikit notification component:

if (EventType == "log") {

	//Convert message type to notification status
	var Status = "primary"
	if(EventData["type"] == "success")
	{
		Status = "success"
	}else if(EventData["type"] == "user")
	{
		Status = "primary"
	}else if(EventData["type"] == "fail")
	{
		Status = "danger"
	}else if(EventData["type"] == "info")
	{
		Status = "warning"
	}
	//Show notification
	UIkit.notification({
	    message: EventData["text"],
	    status: Status,
	    pos: 'bottom-right',
	    timeout: 5000
	});
}

Result will look like this:


Event 'result'

if (EventType == "result") {
   var TabNumber = EventData["number"]
}

'result' event is fired when new data is added to following tab:

EventData['number'] value is a tab number. A text, which is added to tab is not present in EventData object, but you can download entire result file with 'DownloadResult' method.



Event 'thread_start'

if (EventType == "thread_start") {
   //Code
}

Fired after new thread started. Can be used to display number of threads.



Event 'thread_end'

if (EventType == "thread_end") {
   var IsSuccess = EventData["success"]
}

Fired after new thread finished. Can be used to display number of threads. EventData[“success”] contains boolean which equals true only if thread was successful.



Method 'GetScriptReport'

Api.GetScriptReport().then((ReportText) => {
    //Code
})

'GetScriptReport' obtains script report text:

This method returns Promise, use 'then' keyword to obtain result.



Method 'GetResourcesReport'

Api.GetResourcesReport().then((ReportText) => {
    //Code
})

'GetResourcesReport' obtains resources report text. This method returns Promise, use 'then' keyword to obtain result.



Method 'DownloadLog'

Api.DownloadLog().then((LogFileContent) => {
    //Code
})

'DownloadLog' obtains whole log file content. This method returns Promise, use 'then' keyword to obtain result.



Method 'DownloadResult'

Api.DownloadResult(Index).then((ResultFileContent) => {
    //Code
})

'DownloadResult' obtains result file content. This method returns Promise, use 'then' keyword to obtain result.



Interacting with global variables.

Global variables can be used to interact with BAS main script. With help of global variables you can update settings during script execution, execute BAS functions and get results, send data from script to interface and vice versa.


Method 'GetGlobalVariable'

Api.GetGlobalVariable(GlobalVariableName).then(function(GlobalVariableValue){
   //Code
})

Gets global variable. This method returns Promise, you need to use 'then' keyword to obtain result.



Method 'SetGlobalVariable'

Api.GetGlobalVariable(GlobalVariableName,GlobalVariableValue)

Sets global variable. This method returns Promise, you need to use 'then' keyword to wait until it succeeded.



Updating project settings dynamically.

Global variables may be used to update project settings. Consider following task - we need to make a script that does specified number of clicks and that number may be changed by user dynamically.

We will take click number from global variable CLICK_NUMBER. That variable will be updated from user interface and will be used inside BAS script. We will not include any real functionality inside script, just 2 actions to demonstrate how it work:

You can download project here.

Project interface is based on autogenerated with several changes:

  • All resources inputs are removed.
  • Interface immediately calls Api.AcceptResources() to change state to running.
  • All controls which displays script statistic, browser view are removed, only log panel left.
  • Finally range control is added, to let user select click number:

  • Added code to set global variable on range control value changed:
$("#NumberOfClicks").change(function() {
    var value = $("#NumberOfClicks").val()
    Api.SetGlobalVariable("CLICK_NUMBER", value)
});

You can download custom interface here. Custom interface may be imported on following page:

Final result will look like this:

This mechanism can be used in the other direction - to send data from BAS script to custom interface.



Using global variables to call BAS function.

More complex way to interact with script would be to call BAS function from custom interface. One possible way to accomplish this is to create a global variable, which will hold a function name to run next. Lets call that variable FUNCTION_TO_RUN. That variable could be set from user interface, for example, with button click. BAS script will contain loop which constantly checks that global variable, if it is set, corresponding function is called.

BAS script will hold infinite loop which checks FUNCTION_TO_RUN variable:

You can download project here.

We will take simple user interface from previous result as a foundation and replace “number of clicks” element with 3 buttons: “Call function A”, “Call function B”, “Call function C”:

Of course, you need to set buttons click handlers, so that they will change global variables:

You can download custom interface here.

Final result will look like this:

Even more complex example would to obtain result of that function from another global variable.

Interacting with database.

Custom interface API has comprehensive sets of methods to work with database.


Method 'GetDatabaseStructure'

var Structure = Api.GetDatabaseStructure()

This is very important method. Id returns list of ids for tables, columns, groups. Ids are used to interact with those entities. For example, to delete group, you need to know its id, and this method is the only way to get it.

This method works fast and returns immediately.

Here is return data example:

[
  {
    "columns": [
      {
        "description": "c1",
        "id": 2,
        "name": "c1",
        "type": "string"
      },
      {
        "description": "c2",
        "id": 3,
        "name": "c2",
        "type": "int"
      }
    ],
    "description": "table1",
    "groups": [
      {
        "description": "All data in table",
        "id": "-1",
        "name": "All"
      },
      {
        "description": "Items, which is not present in any group",
        "id": "-2",
        "name": "Not in groups"
      }
    ],
    "id": 1,
    "name": "table1"
  }
]

This method call result is array with a list of tables, each table object has id, list of groups and list of columns.

Here are some snippets:

Obtaining first table id:

Api.GetDatabaseStructure()[0].id

Obtaining table id by name:

Api.GetDatabaseStructure()
   .find(function(table){return table.name == "table1"})
   .id

Use same technique to find columns and groups.



Event 'database_structure_changed'

if (EventType == "database_structure_changed") {
   //Code
}

This event is fired every time database structure is changed. BAS can change columns and tables structure only after restart, but groups can be modified during script run, so this event will be fired each time group id is changed. You can be sure that column ids and names and tables won't be changed during script run. Changing records won't trigger that event.



Method 'ShowDatadaseManager'

Api.ShowDatadaseManager()

Show database manager:



Method 'DatabaseSelect'

Api.DatabaseSelect(Selector, TableId).then(function(RecordList){
   //Code
})

This method executes database query and returns result as a list of records. It returns Promise, use 'then' keyword to get result.

Second parameter is a table identifier, could be obtained with 'GetDatabaseStructure' method.

First parameter is a complex object which specifies database query. Here are several examples.

Select all records from database:

{}

Sort records by column with id 2 in ascending order:

{Sort:{ColumnId: 2, OrderIsAsc: true}}

Get first page with page size 10:

{Page:{PageNumber: 1, PageSize: 10}}

Get records from group with id 5b582547cee1c8c66a85ddd9:

{Groups:{GroupIdList:["5b582547cee1c8c66a85ddd9"]}}

Get records from first page of group with id 5b582547cee1c8c66a85ddd9:

{Page:{PageNumber: 1, PageSize: 10}, Groups:{GroupIdList:["5b582547cee1c8c66a85ddd9"]}}

Select only records, which column with id 2 contains string 'test':

{
   Filter:
   {
      FilterList:
      [
         {
            ColumnId:2,
            Type:"StringContains",
            Data:"test",
         }
      ]
   }
}

Filter may have several types depending on column type:

Filters for strings: StringNotEmpty, StringEmpty, StringContains

Filters for numbers: IntEquals, IntNotEquals, IntGreaterOrEqual, IntGreater, IntLessThan, IntLessThanOrEqual

Filters for booleans: BoolIsTrue, BoolIsFalse

Filters for dates: DateIsLessThan, DateGreaterThan, DateIsSameYear, DateIsSameMonth, DateIsSameDay, DateIsSameHour

Method 'DatabaseSelect' return list with records. Each record is represented with object. Object contains 'id' string and 'data' object with keys equals to column ids and values which equals to actual values for that record. Here is example of returning list:

[
  {
    "data": {
      "2": "test1",
      "3": 1
    },
    "id": "5b5820d2cee1c8c66a85ddd7"
  },
  {
    "data": {
      "2": "test2",
      "3": 2
    },
    "id": "5b5820d8cee1c8c66a85ddd8"
  }
]


Method 'DatabaseInsert'

Api.DatabaseInsert(Groups, Item, TableId).then(function(InsertedRecordId){
   //Code
})

This method executes insert single record into database.

First parameter is group id list, leave it empty if you don't want to assign groups to new record.

Second parameter is an item object with keys equals to column ids and values which equals to actual values for that record.

Third parameter is table id.

Example of usages:

Api.DatabaseInsert(
   [],
   {
      2: "test3",
      3: 3
   }, 
   1)


Method 'DatabaseCount'

Api.DatabaseCount(Selector, TableId).then(function(RecordCount){
   //Code
})

Count number of records matching selector. This method returns Promise, use 'then' keyword to get result. Selector format is the same as in 'DatabaseSelect' method.



Method 'DatabaseUpdate'

Api.DatabaseUpdate(ItemId, Item, TableId).then(function(RecordCount){
   //Code
})

Update existing record.

First parameter must equal to record id, which will be changed.

Second parameter is item object, it has same format as second parameter of 'DatabaseInsert' method.

Third parameter is table id.



Method 'DatabaseDelete'

Api.DatabaseDelete(Items, TableId)

Delete one or several records.

First parameter must equal to list with record ids, which will be deleted.

Second parameter is table id.

Example:

Api.DatabaseDelete(["5b5820d8cee1c8c66a85ddd8"], 1)


Method 'DatabaseInsertGroup'

Api.DatabaseInsertGroup(Group, TableId)

Insert group.

Example:

Api.DatabaseInsertGroup({Name:"GroupName",Description:"Description"}, 1).then(function(InsertedGroupId){
   //Code
})


Method 'DatabaseDeleteGroupNoData'

Api.DatabaseDeleteGroupNoData(GroupId, TableId)

Delete group, don't delete data inside it.



Method 'DatabaseDeleteGroupWithData'

Api.DatabaseDeleteGroupWithData(GroupId, TableId)

Delete group and all its records.



Method 'DatabaseUpdateGroup'

Api.DatabaseUpdateGroup(GroupId, Group, TableId)

Updated group name and description.

Example:

Api.DatabaseUpdateGroup("5b5820d8cee1c8c66a85ddd8",{Name:"NewName",Description:"NewDescription"}, 1)


Method 'DatabaseMoveToGroup'

Api.DatabaseMoveToGroup(Items, GroupId, TableId)

Move records to group. Records are identified by first parameter, this parameter must hold a list with record ids.

Second parameter must contain group id.



Method 'DatabaseCopyToGroup'

Api.DatabaseCopyToGroup(Items, GroupId, TableId)

Copy records to group. Records are identified by first parameter, this parameter must hold a list with record ids.

Second parameter must contain group id.

Solving captcha.

BAS has several captcha solvers. Most of them works automatically, but 'manual' solver requires user to recognize image manually. Therefore custom interface must display captcha and deliver result to BAS.

Event 'captcha'

if (EventType == "captcha") {
   var CaptchaId = EventData["id"]
   var IsCaptchaImage = EventData["is_image"]
   var CaptchaData = EventData["data"]
}

This event is triggered only after manual captcha determination is required.

Custom interface must display that captcha to user and when result is obtained, 'CaptchaSolved' method must be called.

EventData[“id”] contains captcha id, it should be used with 'CaptchaSolved' method to identify for which captcha the result is sent.

EventData[“is_image”] can be true or false. If it equals true, then EventData[“data”] contains base64 encoded image in png format, otherwise EventData[“data”] contains text.

If EventData[“is_image”] equals to false, it means that BAS requires text captcha to solve.



Method 'CaptchaSolved'

Api.CaptchaSolved(CaptchaId,IsSuccess,Text)

Use this method to send catpcha text back to BAS.

First parameter is captcha id obtained from 'captcha' event.

Second parameter is true if user have solved captcha, otherwise false.

Third parameter is captcha text.



Inspecting browser.

API allows to obtain browser cursor position and browser image.

Event 'browser_add'

if (EventType == "browser_add") {
   var BrowserId = EventData["browser_id"]
   var ThreadNumber = EventData["thread_number"]
}

Fired after new browser created. Custom interface must preserve browser id to get browser content later.



Event 'browser_remove'

if (EventType == "browser_remove") {
   var BrowserId = EventData["browser_id"]
   var ThreadNumber = EventData["thread_number"]
}

Fired after browser closed.



Method 'ViewBrowser'

Api.ViewBrowser(BrowserId).then((Res)=>{
   var BrowserWidth = Res["width"]
   var BrowserHeight = Res["height"]
   var X = Res["x"]
   var Y = Res["y"]
   var ImageBase64 = Res["image"]
})

Execute this method to obtain browser width, height, cursor position and browser screenshot as base64 encoded png image.

BrowserId is a first method parameter, it can be obtained from 'browser_add' event.

If custom interface contains img tag with id BrowserScreen, then it can be updated with browser image with following code:

Api.ViewBrowser(BrowserId).then((Res)=>{
   $("#BrowserScreen").attr("src","data:image/png;base64," + Res.image)
})