Wizard: User Guide

Introduction to ZOAPIIO Wizard

Application Wizard is a super-fast and convenient way to build fully functional custom business applications for your ZOAPIIO Instance. The wizard takes as input a JSON file. There is also a convenient graphical editor to create it in case you do not want to use a text editor.

The Wizard creates the underlying database and the server APIs to manage the data. comes bundled with a Visualization application that renders this Wizard generated application.

  1. Describe your application, database entities/relationships, presentation, access controls, workflows, and dashboard widgets etc.
  2. Optionally, add customization in terms of custom UI controls, server APIs, UI pages, handlers, and help files.
  3. Let the wizard build and configure your entire application.
  4. Deploy the generated application to your instance.
  5. Launch the visualization app url, point it to the generated application and start using it right away.
The application can be safely regenerated after changes to database entities - existing data in database is preserved. You can construct your application incrementally - simply edit-deploy-run - right from your favorite browser!

Anatomy of the Wizard Config

Let us begin the tour with a minimal example - kind of the customary "Hello World". The example below is minimal to the extent that is necessary to demonstrate the core features.

In the listings below, hover over the Highlighted Text to see explanatory tips.

The Configuration

This is the master application configuration that by itself is sufficient for the entire server for visualization to be generated. It contains database, presentation, and behavioral attributes of the application. The visualization app has a fixed navigation structure and look & feel. The generated application plugs in the pages, data, and controls in the app.

The business specific customization - both server and client side - can be provided from outside as additional files which are incorporated into the main application. Let us start by looking at the configuration file first.

Basicdemo.js

{
   "_comment": [
      "1. Basic Demo App to explain core features."
   ],
   "application": {
      "name": "Basicdemo",
      "title": "Basic Demo App",
      "themes": [
         {
            "name": "default"
            ,"type": "dark"
            ,"title": "Default (Dark)"
         },{
            "name": "theme-a"
            ,"type": "light"
            ,"title": "Alternate (Light)"
         }
      ],
      "userroles": ["super", "management", "operator"],
      "defaultrole": "super",
      "entities": [
         {
            "name": "setting", "label": "Settings"
	    ,"menu": "Setting"
	    ,"properties": [
            ]
	    ,"data": "setting"
	    ,"menuicon": "cogs"
            ,"icon": "cog"
            ,"tip": "Organization Settings"
            ,"access": { "full": ["management", "super"] }
            ,"classification": { "open": "WWR-R-" }
         },{
            "name": "assettype", "label": "Asset Type"
            ,"menu": "Assets"
            ,"properties": [
               {
                  "name": "Category"
                  ,"label": "Asset Category"
                  ,"type": "easyselect:Asset,Resource,Inventory,Consumable,Spare"
                  ,"validation": "required", "cached": true
               },{
                  "name": "Description"
                  ,"label": "Comments"
                  ,"type": "string"
                  ,"validation": ""}
            ]
            ,"menuicon": "toolbox"
            ,"icon": "chevron-circle-right"
            ,"tip": "Asset type definition"
            ,"access": { "full": ["management", "super"] }
            ,"classification": { "open": "WWRR--" }
	    ,"dependents": [
               {
		  "name": "asset"
		  ,"property": "AssetTypeId"
               }
            ]
         },{
            "name": "assetsubtype", "label": "Asset Sub-type"
            ,"menu": "Assets"
            ,"properties": [
               {
                  "name": "Category"
                  ,"label": "Asset Category"
                  ,"type": "select:Asset,Resource,Inventory,Consumable,Spare"
                  ,"validation": "required", "cached": true
               },{"name": "AssetTypeId,AssetTypeName"
                  ,"label": "Asset Type"
                  ,"type": "entity:assettype"
                  ,"validation": "required"
                  ,"cached": true
		  ,"filter": "Category"
               },{
                  "name": "Description"
                  ,"label": "Comments"
                  ,"type": "string"
                  ,"validation": ""}
            ]
            ,"icon": "chevron-circle-down"
            ,"tip": "Asset sub-type definition"
            ,"access": { "full": ["management", "super"] }
            ,"classification": { "open": "WWRR--" }
            ,"dependents": [
               {
                  "name": "asset"
                  ,"property": "AssetSubtypeId"}
            ]
         },{
            "name": "asset", "label": "Asset"
            ,"menu": "Assets"
            ,"properties": [
               {"name": "Category"
                  ,"label": "Asset Category"
                  ,"type": "select:Asset,Resource,Inventory,Consumable,Spare"
                  ,"validation": "required", "cached": true
	       },{"name": "AssetTypeId,AssetTypeName"
                  ,"label": "Asset Type"
		  ,"type": "entity:assettype"
                  ,"validation": "required", "cached": true
		  ,"filter": "Category"
               },{"name": "AssetSubtypeId,AssetSubtypeName"
                  ,"label": "Asset Sub-type"
                  ,"type": "entity:assetsubtype"
                  ,"validation": "required"
		  ,"filter": "assettype"
               },{"name": "Ownership"
                  ,"label": "Ownership"
                  ,"type": "easyselect:Owned,Rented"
                  ,"validation": "required"
               },{"name": "SerialNo,AssetCode"
                  ,"label": "Serial Number"
                  ,"labels": ",Code"
		  ,"type": "multiple"
		  ,"types": "string,string"
                  ,"validation": ""
               },{"name": "POName,POFile"
                  ,"label": "Purchase Order"
		  ,"type": "file"
                  ,"validation": ""
               },{"name": "ServiceDue"
                  ,"label": "Service Due"
		  ,"type": "custom:BDServiceDue"
                  ,"validation": ""
               },{"name": "Description"
                  ,"label": "Description"
                  ,"type": "text"
                  ,"validation": ""
               }
            ]
            ,"icon": "tools"
            ,"tip": "An Asset"
            ,"access": { "full": ["management", "super"] }
	    ,"RESTaccess": true
            ,"classification": { "open": "WWRR--" }
	    ,"handler": { "aftersave": "ROUTINE.AfterAssetSave" }
	    ,"children": [
               {
                  "name": "servicelog"
                  ,"label": "Service Log"
		  ,"properties": [
                     {"name": "DateServiced"
                        ,"label": "Date of Service"
                        ,"type": "date"
                        ,"default": "today"
                        ,"validation": "required"
                     },{"name": "Description"
                        ,"label": "Service Comments"
                        ,"type": "string"
                        ,"validation": ""
                     }
                  ]
               }
            ]
         },{
            "name": "report", "label": "Asset Report"
	    ,"data": "report"
            ,"menu": "Assets"
	    ,"properties": [
               {"name": "AssetTypeId,AssetTypeName"
                  ,"label": "Asset Type"
                  ,"type": "entity:assettype"
                  ,"validation": "required"
               }
            ]
            ,"icon": "boxes"
            ,"tip": "The asset report"
	    ,"editor": "BDAssetReport"
            ,"access": { "full": ["management", "super"] }
            ,"classification": { "open": "------" }
         },{
            "name": "user", "label": "Users"
            ,"menu": "User"
            ,"properties": [
            ]
	    ,"data": "user"
            ,"menuicon": "user-ninja"
            ,"icon": "user"
	    ,"bootuser": "Username=admin,Password=nopassword,Name=Administrator"
            ,"access": { "full": ["management", "super"] }
            ,"classification": { "open": "WWWWRR" }
         },{
            "name": "usergroup", "label": "Teams"
            ,"menu": "User"
            ,"properties": [
            ]
	    ,"data": "usergroup", "icon": "users"
            ,"access": { "full": ["management", "super"] }
            ,"classification": { "open": "WWWWRR" }
         },{
            "name": "b2cuser", "label": "Customer"
            ,"menu": "User"
            ,"properties": [
            ]
	    ,"data": "b2cuser"
            ,"icon": "user-circle"
            ,"access": { "full": ["management", "super"] }
            ,"classification": { "open": "WWWWRR" }
            ,"handler": {
               "beforeregister": "ROUTINE.BeforeRegister"
               ,"afterregister": "ROUTINE.AfterRegister"
            }
         }
      ],
      "customization": {
         "scripts": [
            {
               "name": "misc"
               ,"file": "Basicdemo_misc.js"
            }
         ],
         "helpfiles": [
            {
               "name": "basic"
               ,"title": "Essential User Guide"
               ,"file": "Basicdemo_help.html"
            }
         ],
         "handlers": [
            {
               "name": "custhandler"
               ,"file": "Basicdemo_custom.webc"
            }
         ]
      }
   }
}
	

Server-Side Customization

The server-side programming in ZOAPIIO is done using the WebIDE designer (Refer to the ZOAPIIO Web-IDE: User Guide for full details). You will notice that the program below is not very readable, but do not worry because you will be using the graphical WebIDE editor to create this.
  1. In the config file, we indicated the presence of the server customization in the application definition. So the Wizard will be expecting this file.
  2. When generating the application, leave blank when asked for the file.
  3. After the application is generated, modify it and add your custom additions - Services, Routines, Methods, even changes to the schema.
  4. Then from the WebIDE menu select "File -> Save Custom Changes". This will download the file containing only the changes you have made.
  5. When you must generate the application again, simply provide the custom changes file and these will be automatically added to the project after the generation is complete.
  6. You can, of course, repeat the same cycle multiple time. Edit the project any number of times and then save the custom changes. Remember to include the latest saved changes every time you generate.

Basicdemo_custom.js

<PRMLCONFIG CONFIG="RRML">
<ROUTINE NAME="AfterAssetSave">
  <BIZ-RULE OPCODE="Comment" P1="Generate the AssetCode if blank."/>
  <BIZ-RULE OPCODE="Return" CONDITION="/_IN/AssetCode > """/>
  <BIZ-RULE OPCODE="Compute" P1="/_IN/AssetCode = /_IN@__GenerateAssetCode"/>
</ROUTINE>

<METHOD NAME="GenerateAssetCode">
private String GenerateAssetCode(Node in, Node out) {
	String type=get(in, "AssetTypeName");
	String serial=get(in, "SerialNo");
	while (type.length()<2) type+="X";
	return type.substring(0,2)+serial;
}
</METHOD>
</PRMLCONFIG>
	

Client-Side Customization

Basicdemo_misc.js

// Asset Report
function BDAssetReport (divid, params, form) {
	this.divid=divid;
	this.form=form;
	this.params=params;
	this.data=null;
	//
	this.voptsrq=this.form.getProperty('voptsrq', 'env');
	this.vdatarq=this.form.getProperty('vdatarq', 'env');
	this.assettypeid=params.AssetTypeId;
	// Fetch the data from the server.
	this.getData();
}
// Class methods to implement the report.
BDAssetReport.prototype.getData = function() {
	var qry='vapp/getdata/asset+servicelog/_';
	var reqobj={}, req={}; reqobj['asset']={};
	reqobj['asset']['AssetTypeId'] = this.assettypeid;
	req[this.vdatarq]=reqobj;
	req[this.voptsrq]=[
		{'name': 'LIMIT', 'value': 100000}
	];
	this.form.getProperty([qry, req], 'query', [this.renderReport, this]);
}
BDAssetReport.prototype.renderReport = function(data) {
	this.data=data;
	var assets=data.asset||[];
	var servicelog=data.servicelog||[];
	var tabledata=[];
	var columns=[
		{'title': 'Asset Name'},
		{'title': 'Asset Type'},
		{'title': 'Ownership'},
		{'title': 'Last Service'}
	];
	for (var i in assets) {
		var d=assets[i];
		var assetid=d.Id;
		var lastservice='';
		for (var j in servicelog) {
			if (servicelog[j].ParentId == d.Id && servicelog[j].DateServiced > lastservice)
				lastservice=servicelog[j].DateServiced;
		}
		var item=[d.Name, d.AssetTypeName, d.Ownership, lastservice];
		tabledata.push(item);
	}
	var html='';
	html+='<div id="'+this.divid+'_g" style="width: 100%"></div>';
	html+='<table id="'+this.divid+'_dt" class="display compact"></table>';
	$('#'+this.divid).html(html);

	var buttons=[ 'copy', 'excel', 'pdf', 'csv', 'print' ];
	$('#'+this.divid+'_dt').DataTable({
		dom: 'Bfrtip'
		,buttons: buttons
        	,data: tabledata
        	,columns: columns
		,order: []
	});
}

// JS Class for custom Control Property - ServiceDue.
function BDServiceDue (div, names, form) {
	this.div=div;
	this.form=form;
	this.vdatarq=this.form.getProperty('vdatarq', 'env');
	this.assetid=form.getProperty('Id');
	this.render();
	this.updateValue();
}
BDServiceDue.prototype.updateValue = function() {
	// If this is an attached asset, get its availability from the host asset.
	var qry='vapp/getdata/servicelog/'+this.assetid;
	var reqobj={}, req={};
	req[this.vdatarq]=reqobj;
	var that=this;
	this.form.getProperty([qry, req], 'query', function(data) {
		var slogs=data.servicelog||[];
		var lastservice='';
		for (var i in slogs) {
			if (lastservice < slogs[i].DateServiced) lastservice=slogs[i].DateServiced;
		}
		var html='';
		html+='<span>'+lastservice+'</span>';
		$(this.div).html(html);
	});
}
BDServiceDue.prototype.render = function() {
	var html='';
	html+='<table width=100%></table>';
	$(this.div).html(html);
}
BDServiceDue.prototype.get = function(valonly) {
	if (valonly) return '';
	return [''];		// Not saved, only displayed.
}
BDServiceDue.prototype.handleFormChange = function(name) {
}
	

User Help File

Basicdemo_help.html

<!-- Single page help file. -->
<style>
body { font-family: Helvetica; color: #555; font-size: 16px; }
.content { padding: 2px 315px 0 7px; }
.title { font-size: 25px; font-family: Helvetica; color: #18335e; }
h1 { font-size: 22px; color: #222; font-family: Arial; }
h2 { font-size: 18px; color: #333; font-family: Helvetica; }
h3 { font-size: 17px; color: #555; font-family: Arial; text-decoration: underline; }
</style>

<div class="content">
<p class="title">Basic Demo App: User Guide.</p>

<h1>Introduction to Basic Demo</h1>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean hendrerit eros convallis,
consectetur dui vel, vestibulum velit. Vivamus eget odio ex. Proin ut nulla nunc. Sed felis mi, porttitor
et dolor id, aliquam blandit felis. Cras vulputate non massa sed sollicitudin. Aliquam rutrum augue in
nulla dictum, in rhoncus est tristique. Donec at purus et risus lobortis mollis nec eget arcu. Sed tempus
velit at porttitor convallis. Quisque aliquam, turpis in auctor tincidunt, leo massa ornare nibh, nec
tempus dolor ex id sapien. Aenean mollis sapien vel magna ultrices pellentesque. Aenean eu nisl dapibus,
sodales enim sed, efficitur nisl.</p>

</div>
	

Running the Wizard

In the last section, we saw how to create the configuration file for the Wizard. It is advisable to build most of your basic application first and then incrementally add the customization as necessary.

A medium sized application with limited customization can be created in under a week.

Create a folder on your desktop, where you will save the configuration files. When you save something from the WebIDE designer, it will always be saved in your Downloads folder. You will need to manually move it to your project folder. Login to the Designer and follow the Menu File > New Project > App Wizard. The Wizard page will appear.

  1. If you have a Wizard configuration file saved from an earlier run, or you manually created the configuration, choose the file and click on "Load from File".
  2. The JSON code will be displayed in the box below for reference only - you are not required to edit it directly.
  3. To edit the configuration, click on "Visual Editor" to open the visual editor. However, you may find that using a text editor to edit the configuration is more convenient.
  4. Navigate the intuitive Visual Editor and create your application definition.
  5. Always locally save the configuration JSON, because it cannot be retrieved from the server. To save the JSON file locally, use "Save to File" button.
  6. How much of visual editing and manual editing you want to use if up to your preferences.
  7. Once ready, click on the "Continue" button. The wizard input will be validated and if all is well, you will go to the next page, where you can select the "customization" files that are a part of your application. Click "Continue".
  8. The application will be generated.
  9. Deploy the generated application to your instance.

Running your Application

The visualization app is available as a part of your instance. You can launch it on your generated application using the URL-

{Your Instance URL}/vapp/index.html?{Your App name}

You can create multiple Wizard applications and use them as independent applications.

  1. It is advised that you use the bootuser feature to automatically create the first user in the database.
  2. If you have created the boot user, login using the credentials and start using the application.
  3. If you have not used the boot user, then at the time of application launch, it will give you an opportunity to create the first user from the app itself.
  4. Create user accounts for other users who will be using the app.

You are all set. This completes our "Getting Started" part of the guide.

Using your learning so far, you should be able to create Wizard configuration files, simple customizations, generate, deploy and start using fully functional enterprise apps. At the end of this guide, there are some screen-shots to give you an idea of what your finished app will look like.

In the following sections we will go through more details and nuances that almost all real-world applications require - such as workflow control, access control, documents & attachments, dashboards etc.

Regenerating the Application

You can safely regenerate the Wizard application, after making changes to the configuration.

  1. If you have made any changes to the entity declarations, the tables would be regenerated without loss of data".
  2. If you have not made any change to the entity declarations or server handlers, and only making change to a supporting customization file, then you should not regenerate the application.
  3. Before clicking on "Continue", change "Update Artifacts Only" to Yes. The designer will only update the artifacts, without regenerating the entire application.

The Generated Application

This section is for advanced users only. If you do not plan to significantly customize the application, you can skip this section - or read it for academic interest.

Let us look at the generated application. You do not need to know most of these things, but you might require familiarity with the APIs that drive the visualization app. For instance,

  1. You may use these APIs while building customization in your app. You will notice that in our example app above, we used one of these APIs (getdata) to fetch data from the server.
  2. You may want other applications to integrate with your app using these APIs.

While calling the API from a custom front-end component (report, or control), the access rights of the logged-in user are used. For inbound integration with another application, explicit authentication must be performed before calling the services. See Integrating other Applications.

The Request/Response Object

Reproduced below are some snippets from the data schema - The hierarchical data structures that the APIs use to communicate. The REQUEST node is the abstraction of the HTTP request - GET as well as POST - for the service APIs. What you see below is not the full structure - you will notice the elements with DATATYPE names like "TYP:..." - this refers to a detailed reusable structure declared elsewhere.


  <REQUEST>
    <HTTP-HEADER NAME="Authorization"/>
    <HTTP-HEADER NAME="User-Agent"/>
    <TAG NAME="VAPP_voptsRQ" DUPLICATES="true">
      <TAG NAME="name" DATATYPE="STRING" ISKEY="true"/>
      <TAG NAME="value" DATATYPE="STRING"/>
    </TAG>
    <TAG NAME="VAPP_vechoRQ">
      <TAG NAME="ContentType" DATATYPE="STRING"/>
      <TAG NAME="FileName" DATATYPE="STRING"/>
      <TAG NAME="B64Data" DATATYPE="STRING"/>
    </TAG>
    <TAG NAME="VAPP_vanyRS">
      <TAG NAME="*ANY" DATATYPE="" DESCRIPTION="No Structure"/>
    </TAG>
    <TAG NAME="VAPP_vautoRQ">
      <TAG NAME="ColumnName" DATATYPE="STRING"/>
      <TAG NAME="EntityName" DATATYPE="STRING"/>
      <TAG NAME="ValuePrefix" DATATYPE="STRING"/>
    </TAG>
    <TAG NAME="VAPP_vloginRQ" DATATYPE="TYP:VAPP_vloginType"/>
    <TAG NAME="VAPP_vdataRQ" DATATYPE="TYP:VAPP_vdataType"/>
    <TAG NAME="VAPP_vwidgetRQ" DATATYPE="TYP:VAPP_vwidgetType"/>
    <TAG NAME="VAPP_vpushRQ" DATATYPE="TYP:VAPP_vpushType"/>
    <TAG NAME="VAPP_vprocletRQ" DATATYPE="TYP:VAPP_vprocletType"/>
  </REQUEST>
	

This is the Response message structures used by the APIs. Again, this is not the complete structure.


  <TAG NAME="Response">
    <TAG NAME="Status" DATATYPE="STRING" DUPLICATES="true"/>
    <TAG NAME="TimeStamp" DATATYPE="DATETIME"/>
    <TAG NAME="VAPP_vdataRS" DATATYPE="TYP:VAPP_vdataType"/>
    <TAG NAME="VAPP_vprocletRS" DATATYPE="TYP:VAPP_vprocletType"/>
    <TAG NAME="VAPP_vwidgetRS" DATATYPE="TYP:VAPP_vwidgetType"/>
    <TAG NAME="VAPP_vfileRS" DATATYPE="STRING"/>
    <TAG NAME="VAPP_vechoRS" DATATYPE="STRING"/>
    <TAG NAME="VAPP_vautoRS">
      <TAG NAME="result" DATATYPE="STRING" DESCRIPTION="Result Values" DUPLICATES="true">
        <TAG NAME="Value" DATATYPE="STRING"/>
        <TAG NAME="Count" DATATYPE="NUMBER"/>
      </TAG>
    </TAG>
    <TAG NAME="VAPP_vloginRS" DATATYPE="EXT:Basicdemo_userType">
      <TAG NAME="B2C" DATATYPE="TYP:Basicdemo_b2cuserType"/>
    </TAG>
    <TAG NAME="VAPP_vconfigRS">
      <TAG NAME="config" DUPLICATES="true">
        <TAG NAME="Name" DATATYPE="STRING"/>
        <TAG NAME="RecType" DATATYPE="STRING"/>
        <TAG NAME="Type" DATATYPE="STRING"/>
        <TAG NAME="Data" DATATYPE="STRING"/>
      </TAG>
    </TAG>
  </TAG>
	

Reproduced below is a section of the TYPES node. The declarations under TYPES represent the definition only - not the actual data. These structures are referenced in the schema using the TYP:... notation.


  <TYPES>
    <TAG NAME="VAPP_vdataType">
      <TAG NAME="Dashboards" DUPLICATES="true">
        <TAG NAME="Id" DATATYPE="NUMBER"/>
        <TAG NAME="Name" DATATYPE="STRING"/>
        <TAG NAME="Type" DATATYPE="STRING"/>
        <TAG NAME="Owner" DATATYPE="STRING"/>
        <TAG NAME="OwnerGroup" DATATYPE="STRING"/>
        <TAG NAME="Classification" DATATYPE="STRING"/>
        <TAG NAME="Access" DATATYPE="STRING"/>
        <TAG NAME="Data" DATATYPE="STRING"/>
        <TAG NAME="Description" DATATYPE="STRING"/>
      </TAG>
      <TAG NAME="Polygons" DUPLICATES="true">
        <TAG NAME="Id" DATATYPE="NUMBER"/>
        <TAG NAME="Name" DATATYPE="STRING"/>
        <TAG NAME="Owner" DATATYPE="STRING"/>
        <TAG NAME="OwnerGroup" DATATYPE="STRING"/>
        <TAG NAME="Classification" DATATYPE="STRING"/>
        <TAG NAME="Access" DATATYPE="STRING"/>
        <TAG NAME="Data" DATATYPE="STRING"/>
        <TAG NAME="Description" DATATYPE="STRING"/>
      </TAG>
      <TAG NAME="MessageSummary" DUPLICATES="true">
        <TAG NAME="Username" DATATYPE="STRING"/>
        <TAG NAME="UnreadCount" DATATYPE="NUMBER"/>
      </TAG>
      <TAG NAME="setting" DATATYPE="TYP:Basicdemo_settingType" DUPLICATES="true"/>
      <TAG NAME="assettype" DATATYPE="TYP:Basicdemo_assettypeType" DUPLICATES="true"/>
      <TAG NAME="asset" DATATYPE="TYP:Basicdemo_assetType" DUPLICATES="true"/>
      <TAG NAME="servicelog" DATATYPE="TYP:Basicdemo_servicelogType" DUPLICATES="true"/>
      <TAG NAME="report" DATATYPE="TYP:Basicdemo_reportType" DUPLICATES="true"/>
      <TAG NAME="user" DATATYPE="TYP:Basicdemo_userType" DUPLICATES="true"/>
      <TAG NAME="usergroup" DATATYPE="TYP:Basicdemo_usergroupType" DUPLICATES="true"/>
      <TAG NAME="b2cuser" DATATYPE="TYP:Basicdemo_b2cuserType" DUPLICATES="true"/>
      <TAG NAME="userdevice" DATATYPE="TYP:Basicdemo_userdeviceType" DUPLICATES="true"/>
      <TAG NAME="pushmessage" DATATYPE="TYP:Basicdemo_pushmessageType" DUPLICATES="true"/>
      <TAG NAME="message" DATATYPE="TYP:Basicdemo_messageType" DUPLICATES="true"/>
      <TAG NAME="workflow" DATATYPE="TYP:Basicdemo_workflowType" DUPLICATES="true"/>
      <TAG NAME="notification" DATATYPE="TYP:VAPP_vnotificationType"/>
    </TAG>
    <TAG NAME="Basicdemo_assetType">
      <TAG NAME="Id" DATATYPE="NUMBER" ISKEY="true"/>
      <TAG NAME="ParentId" DATATYPE="NUMBER"/>
      <TAG NAME="Name" DATATYPE="STRING"/>
      <TAG NAME="Owner" DATATYPE="STRING"/>
      <TAG NAME="OwnerGroup" DATATYPE="STRING"/>
      <TAG NAME="Classification" DATATYPE="STRING"/>
      <TAG NAME="Access" DATATYPE="STRING"/>
      <TAG NAME="Deleted" DATATYPE="NUMBER"/>
      <TAG NAME="UpdatedBy" DATATYPE="STRING"/>
      <TAG NAME="UpdatedAt" DATATYPE="DATETIME"/>
      <TAG NAME="AssetTypeId" DATATYPE="NUMBER"/>
      <TAG NAME="AssetTypeName" DATATYPE="STRING"/>
      <TAG NAME="Ownership" DATATYPE="STRING"/>
      <TAG NAME="SerialNo" DATATYPE="STRING"/>
      <TAG NAME="AssetCode" DATATYPE="STRING"/>
      <TAG NAME="POName" DATATYPE="STRING"/>
      <TAG NAME="POFile" DATATYPE="STRING"/>
      <TAG NAME="ServiceDue" DATATYPE="STRING"/>
      <TAG NAME="Description" DATATYPE="STRING"/>
      <TAG NAME="workflow" DATATYPE="TYP:Basicdemo_workflowType" DUPLICATES="true"/>
    </TAG>
  </TYPES>
	

Service APIs

The two most important services used in customization and integration are the services that allow you to query and update the entity data - getdata and setdata. gethistory, and dumpfile are also useful and deal with fetching data.

getdata

This service API allows you to retrieve data using a non-trivial query structure.

  1. You can query data for a single entity (parent or child) or an entity along with one or more of its child entities.
  2. You can provide detailed filters for each of the entities in the query.
  3. There is a separate options object that can be passed to control what data and how much data should be retrieved.
  4. You can optionally fetch workflow information (history/status) with each entity.

The API is accessed at the following url

{Instance URL}/wc/{Wizard Project Name}/vapp/getdata/{P1}/{P2}/[P3]

URL Component Description
{Instance URL} This is the base URL of your ZOAPIIO instance. If the instance is hosted on ZOAPIIO cloud, you can get this from the control panel. If you are using on-premise hosting, your system administrator would know the base URL.

wc This prefix is mandatory for all ZOAPIIO HTTP services, to distinguish it from other types of services (SOAP, GRAPHQL, etc.) supported by ZOAPIIO.

{Wizard Project Name} This is your project name - in the case of our example this is Basicdemo. You can create multiple projects in the same instance, and this makes sure there is no conflict between the services of different applications.

vapp This path component is added by the Wizard to suggest that this is a service used by the visualization app.

getdata The name of the service itself.

{P1} The first path parameter to the service is the name(s) of the entity to be fetched.
  1. To fetch records from a single entity, just put the name.
  2. To additionally fetch the details of the entity's child entities append the child's name separated by a '+'.
E.g. asset, assettype, asset+servicelog.

{P2}

The second path parameter is the ParentId filter. For root level entities, this is always 0 and for child entities, this is the Id value of the parent.

A wildcard value of '_' (underscore) can be used if no filtering on ParentId is required.


[P3] The third, last and optional path parameter is the Id value if the entity record. This is a convenient way to fetch all data for an entity record, when its Id value is known. Filters are ignored when Id is present.
The getdata API.

Filter criteria and options are sent to the query as POST data in JSON format. An example of getdata query is-

POST http:.../wc/Basicdemo/vapp/getdata/asset+servicelog/_
{
	"vdataRQ": {
		"asset": {
			"SerialNo": "ABC%"
		},
		"servicelog": {
			"DateServiced": "2022-12-01,2022-12-31"
		},
	},
	"voptsRQ": [
		{ "name": "FETCH", "value": "SUMMARY" },
		{ "name": "LIMIT", "value": 500 }
	]
}
	
The above query will search and return up to 500 asset records - summary properties only - with SerialNo starting with ABC. Additionally for each of these assets, if there is a servicelog record for service in Dec 2022, those records will also be returned.

Following are the rules for specifying the filter selection-

  1. If the Id value is present in the URL (Path parameter 3), then filter selection is not applied - only the record with the given Id will be returned.
  2. If one or more child entities are a part of the query, filter can be specified for each entity separately - as in example above.
  3. When fetching parent-child entity records together, the parent selection is run first, and the child selection is only applied to the child entities of the matching parents.
Property Type Filter Value
string, text The value can use '%' as the wildcard.

integer, decimal, date, datetime Two integer/decimal/date/datetime values representing the range must be provided separated by a comma. If you want to search for a fixed value, repeat the same value as both ends of the range. If a single value is provided, it implies a range with the given value as the lower end and no upper end. If the first value is blank, that implies range with no lower end. Examples-
  • 2,10: range 2 to 10 both inclusive.
  • 2,: Range 2 to infinity
  • 2: Range 2 to infinity
  • ,100: Range negative infinity to 100 inclusive.

decimalrange, daterange When searching for a property declared as a range - two names will be there - the search should use the first name and specify a single value. The search will look for entity records where the value given is within the range.

hashtag hashtag is a datatype supported by the Wizard. The input for the hashtag consists of multiple space separated words, each acting as a tag, which can be independently used in the search. The search value is a list of words separated by spaces and will search all entity records, which has all the tags given in the list.

entity The entity search works like the integer search (see above). Two integer values representing the Id of the target entity should be provided (separated by comma).
getdata API filters.

List of options-

Query Option Description
FETCH You can control the level of detail fetched using this option. Values - SUMMARY, FULL (default). Summary only fetches the basic properties - Name, Id and other properties flagged as "cached". (Also see LIGHT below)

LIMIT This is used to set a limit to the number of records that will be fetched. The default is 100. If multiple entity records are being fetched, this applies only to the primary entity only (first in the list).

LIGHT A true/false value option. If set to true, any 'file' type properties in the entity are not fetched. Usually, the file objects are large in size, and it is advised to always use option and if required, fetch the file object separately.

SINCE The value is a date value (yyyy-mm-dd) and only entity records modified on or after that date are fetched.

WORKFLOW Possible values - ASSIGNMENT. If specified, along with each entity record, its workflow assignment status is also returned.

INCLUDE This option provides an even finer control of which properties will be fetched. You can provide a comma separated list of property names, which you want returned with the result.

EXCLUDE This option also controls which properties to return. The property names mentioned in the value list are excluded from the response.
getdata API options.

setdata

This service API allows you to add or update entity data.

  1. The record level permissions are checked before allowing the update. See Access Control.
  2. The Meta properties - Id, ParentId, UpdatedBy, and UpdatedAt cannot be updated.
  3. The Meta properties - Owner, OwnerGroup, Classification, and Access can be updated if your current access credentials allow you to update Privileged properties of the entity record. Caution is advised when updating these properties, because they will affect the access rights to the updated record and your own account may lose access to the record.
  4. When updating a record, only the values present in the data are updated. This allows you to update only specified properties.
  5. Multiple entity records of different entity types can be updated in the same API call.
  6. If Id is present and is non-zero, it implies an update. If the entity record with that Id is not present, the update fails. After update, the updated record is returned.
  7. If Id is not present or is zero, it implies an add. The data is added, and the newly created record is returned.

The API is accessed at the following url

{Instance URL}/wc/{Wizard Project Name}/vapp/setdata

The path components are same as that for getdata. This API does not have any path parameters.

The data to be added/updated is sent to the query as POST data in JSON format. An example of setdata query is-

POST http:.../wc/Basicdemo/vapp/setdata
{
	"vdataRQ": {
		"asset": {
			"Id": 19,
			"SerialNo": "ABC0123"
		}
	}
}
	
The above query will update the SerialNo property of the asset with Id 19.

When creating a new entity record of a child entity, you must specify the ParentId property, unless you are also creating the parent entity in the same API call.

gethistory

This service API allows you to retrieve history of changes to an entity record.

  1. The generated app automatically maintains the history of changes to all records.
  2. To retrieve the history, you must know the Id of the entity record. You can get it by querying the database using getdata.

The API is accessed at the following url

{Instance URL}/wc/{Wizard Project Name}/vapp/gethistory/{Entity Name}/{Record Id}

The query can be called using GET or POST without any post data.

dumpfile

This service API allows you to retrieve just the contents of a 'file' property from an entity record. This is used to retrieve the contents of a file property as viewable raw binary output. The value of 'file' properties returned by getdata are in a Base64 encoded form. This API gets the raw decoded file.

The API is accessed at the following url

{Instance URL}/wc/{Wizard Project Name}/vapp/gethistory/{Entity Name}/{Record Id}/{Property Name}/[thumbnail]
  1. The {Property Name} path parameter must refer to a file property. File properties have multiple names - use the first name from the list.
  2. If the file (attachment) property refers to an image, additional path parameter 4 can be set as "thumbnail", to retrieve a thumbnail version of the image.

The query can be called using GET or POST without any post data.

Integrating other Applications

The Wizard generated application is Web-API driven. This makes it very easy for an external application to get comprehensive access to its database. The APIs detailed above can be called by any external application.

Authentication

The external application must, of course, first authenticate itself before calling the APIs. Popular OAuth2 protocol is used for authenticating external applications. If you are unfamiliar with this protocol, please refer to public resources about OAuth.

  1. The authentication is performed against the Users created in the visualization app. The same userid and password are used that are used for app login.
  2. Every API call must carry an Authorization header so that the system can establish the identity of the originator of the call.
  3. There are two types of authorization headers - Basic and Bearer.
  4. In Basic authorization type, the Username and Password information is coded into a single string and sent. ZOAPIIO authentication API (below) must be called using the Basic authorization.
  5. If authentication is successful, the call will return a bearer token. The bearer token must be passed as the identity proof with every other ZOAPIIO API call.

The Authentication API is-

{Instance URL}/wc/{Wizard Project Name}/vapp/authenticate

The API is called using GET or POST. Basic OAuth authorization header (with username and password) must be sent with this call. No other information needs to be passed. If successfully authenticated, the following response will be returned.


{
	"SESSIONID": "",
	"SESSIONOWNER": "",
	"INSTANCEID": "39d539e8-000001",
	"RESPONSE": {
		"Status": [
			"OK",
			"{The OAuth Token String...}"
		]
	}
}
	

The application must parse this response and extract the OAuth Token. This token should be passed as Authorization header with subsequent calls.

REST interface to your data

REST is a standard protocol for adding, updating, fetching, and deleting entity records in the target application. The actual operation is controlled by the HTTP request type POST, PUT, GET, and DELETE. At times, certain applications use REST to interact with other applications. ZOAPIIO supports REST based access to its contents.

REST must be explicitly enabled in the master configuration file for entities that require REST access. This is done by setting the "RESTaccess" property of the entity to true. Then the entity data can be accessed using REST over the following API-

{Instance URL}/wc/{Wizard Project Name}/vapp/rest/{Entity Name}

For details about REST, please refer to public resources.

Access Control

The wizard application supports access control at two levels-

  1. Access to entity pages.
  2. Access to entity data.
The two access levels are independent. The page access is implemented in the UI and the data access is implemented in the server APIs. For example, if an entity page is restricted to "read-only", the UI will disallow any updates. This does not restrict access to the entity data using API, which is separately controlled and managed.

Page Access

The page access is controlled through the user role mechanism. This allows you to configure the app such that each user type (role) sees a different UI. The access property of the entity in the wizard configuration controls this - a sample is given below. There are three access types-

  1. full: The user has full access to the page.
  2. readonly: The update operations are disabled and the user cannot make changes to or delete the entity records.
  3. demo: This is a special access type, which works like 'full' access except that the Save operation does not actually update the database.

"access": {
	"full": ["operator", "manager"],
	"readonly": ["audit"],
	"demo": ["demo"]
}
	
  1. If 'access' specification is omitted, all users are granted full access.
  2. If 'access' specification is present, at least one role should be given full access. Otherwise, all users are granted full access.
  3. readonly, and demo access specification is only consulted if at least one user role has full access.

Data Access

Access to entity data is controlled using an access tag associated with each entity record. Each entity record has a Owner (user) and a Group Owner (usergroup). For the purpose of record level access, each user attempting to access it is considered to be of one of the following categories:

  1. Owner
  2. Owner Group Member
  3. Group Manager
  4. Other

Data inside an entity record is itself divided into two access categories.

  1. Ordinary data items
  2. Privileged data items

The record level access is controlled as follows:

  1. A unit of access is a single character, one of (-, R, W, or D), representing none, read, write and delete access. Delete access implies Write access and Write access implies Read access.
  2. For each category of user above, there is a two-character code - one for regular properties and another for privileged properties. So WR indicates write access to general properties but only read access to privileged properties.
  3. The access to a record is controlled by an eight-character code - two characters for each of the user categories above in that order. So, the access control code would look something like 'DD WR WW R-'

Classification is a simpler way of defining the access code. In the wizard configuration, you define short names for access controls that you would like to use. E.g., you could say "open" represents "WWWWWWWW" (unrestricted), and "private" represents "WW------" (fully restricted). You can have other such access classes representing other intermediate settings, depending upon your requirements to control access. At the time of creating a record, the user can pick a classification, thus setting its access level.

The "Access" column in the entity table stores the access code and the "Classification" column stores the codified access tag. Usually, only one of them is present, but if Access is present, it overrides the Classification value.

The visualization app allows you to create users, assign roles, create user groups and add users/managers to them. The app also allows you to edit the access setting for each entity record.

Managing Attachments

Attachments and file data (documents, images etc.) are an important part of any application. has elaborate support for storing and managing file data. ZOAPIIO also supports full text indexing of the document contents. This is a very powerful feature that allows you to search for entities based on the contents of the attached documents.

ZOAPIIO also has a built-in OCR and PDF to text conversion tools. These can be accessed through custom code. Please refer to WebIDE programming guide for details.

File data is defined in the Wizard configuration as a regular entity property to be saved in a multitude of configurations.

  1. In database as a column (optionally compressed)
  2. In a local file on disk
  3. In an AWS S3 bucket

How the attachments are handled and saved is controlled through the name, type, and validation attributes of the entity property.

  1. The type attribute must be set to 'file'.
  2. The file type is a complex property and requires multiple names (comma separated).
  3. Minimum two (maximum three) names should be there - one for the file name and the other for the file data.
  4. If the name attribute contains two names, the file data is stored in the table itself.
  5. If there is a third name, then that is assumed to be a pointer (see format below) to an external storage where the data will be stored. Presently, local file and AWS S3 are supported - in future, support for other destinations may be added.
  6. When using external storage, Wizard app uses a default mechanism for storing the data as files on disk. The default mechanism can be overridden to change the folder structure or to store it on AWS S3. When overriding the default mechanism, you must use the 'beforesave' handler mechanism of customization and provide a custom target pointer.
  7. In validation (comma separated list), using 'image' implies that the attachment is an image.
  8. In validation, flagging 'document' implies that the attachment is a document. (PDF, DOCX, HTML or TXT). See 'Special Handling' for documents below.

'file' Location Pointer

The structure of the file location pointer is-

{Storage ID}:{File Path}

{Storage ID} can be 'local' or the name of a storage target configured for your ZOAPIIO instance. Using a storage location other that local, requires pre-configuration on the server. If you plan to use custom storage destinations in your app, please contact your administrator to create an AWS S3 (or any other supported type) on the server. Access to external targets require credential configuration, which is a system administrator task.

'local' implies local file storage and does not require any pre-configuration on the server.

{File Path} looks like a regular file path - it must start with a '/', although it will be created under a folder on your Instance. It can contain names with characters that are acceptable as filename characters on Linux OS. It can contain '/' (slash) as path separators and finally you can include a placeholder string '${Id}' which is always substituted with the Id of the entity record.

When using external storage, no action is needed from your end if you want the files to be stored on disk as default folder structure. The default mechanism is sufficient for most cases. However, if you want to override it, you can do so through the 'beforesave' event handler for the entity.

'document' Special Handling

If a file type entity property is flagged as document (via validation attribute), the wizard automatically extracts the raw text from the document (PDF, HTML, TXT, or DOCX) and adds it as an additional column in the table. This new column name is created by appending 'Text' to the first name in the names list.

The raw text is also fully indexed, allowing you to search for entities using words appearing inside the documents. The text in this 'Text' column can be retrieved and used using the APIs like a normal entity property.

Filtering & Cascading

The visualization app will allow you to create, query and edit data. The form is automatically generated from the configuration you have provided. The form content and behavior can be tailored to some extent. For example, you can have conditional properties - let us say there is a selection field with 'Others' as an option. If this is selected, you may want to capture additional details. This can be implemented using the 'condition' attribute (See Reference Guide in the end).

Another situation that occurs sometimes, is when a group of fields are related to each other and the selection cascades through them. For instance, in our example - for an Asset Category, there are Asset types, and for each Asset type, there are Asset Sub-types.

When entering/searching Asset details, Category, then Asset Type, and then Asset Sub-type will cascade. Meaning, when the Category is picked, the list of Asset Types will be shortened, and when the Asset Type is picked, the sub-type list is shortened.

This cascading can be achieved using the 'filter' attribute in entity property definition.

  1. The value of the filter can be a property name (like Category in our example) or an entity name (like assettype in our example).
  2. When using filtering on a selection field, use 'select:..' data type instead of 'easyselect:..' type.
  3. The name of the property should be same in both entities participating in cascading.
  4. See the example at the top of this guide.

Workflow

entity records are workflow enabled. You need to declare the workflow definition with the entity. See Reference Guide at the end for details.

Widgets and Dashboards

Data visualization (or dashboards), is a primary use case of the applications. It allows you to combine inputs from multiple sources (Web-APIs) and visualize them in a variety of widgets. The dashboards are created by the users of the application, but you must define the type and nature of the widgets that your application will have.

See Reference Guide for details.

Customization

Invariably, you would want the wizard generated application to have application specific business processing incorporated. You can provide custom code to modify the server as well as front-end application functionality.

Customization is meant for advanced users and requires knowledge of programming - primarily JavaScript. If you are not an experienced programmer yourself, you can perhaps approach a colleague to help you or get help from one of the several freelancing public services.

Each of the customization modules below require you to provide the program in a separate file from your local desktop. When you initiate the application generation, you will be prompted for all the files referenced here.

Helpfiles

You can add HTML help files to your application for the users.

Property Description
name A Unique name for the helpfile.

title A short title - will be shown in the UI.

file The name of the file (.html extension) having the help content
Helpfile properties.

The helpfile should be prepared in a standard format that is used by . The help should be a single file (although you can have multiple help files in your application), the styles should be declared in the same file. It is difficult to use images in the help file because you will have to use "data:" URL, which tend to become large strings, even for small images.

  1. There should be no html, or body tag, these are automatically inserted.
  2. There should be no JavaScript, the script to generate the TOC is automatically inserted.
  3. The opening div should have the class=content set.
  4. Use h1 and h2 tags to define headings, these elements are used to create TOC.

The helpfile template is-


<style>
    <!-- Your styles -->
</style>

<div class="content">
    <!-- Help (HTML) content -->
    <H1>Heading</H1>
    <H2>Sub-Heading</H2>
    <p>Help Content</p>
</div>
	

Scripts

The scripts are used to provide custom logic for-

  1. Custom UI controls: You may want to have a custom editing control for some properties. With the property, you should specify the name of the JavaScript class, and provide the code here.
  2. Reports: For 'report' entity types, you need to provide a JavaScript class that will render the report.
  3. Custompages: For custom pages, you need to provide a JavaScript class that will render the page.
  4. Child data editing: For custom implementation of child data editing, you need to provide a JavaScript class that handle the editing.

application UI uses jQuery JavaScript library, and You should use the same to manage the user page.

Property Description
name A Unique name for the script. You can create separate script files for different functions you are providing, or you can put everything in a single script file.

file The name of the file (.js extension) having the JavaScript program (class definitions)
Script properties.

Interacting with UI/Server

Your JavaScript program can interact with the page (and server) by calling the following methods on the 'form' object, which is received in the constructor.

Function 'form' method Description
Get the value of a field on the page getProperty(fieldname) Should also be called to get the initial value of the fields being rendered.

Execute an ajax query getProperty([url, reqobj], 'query', [this.handler, this, parameter]) The query URL can be one of the Wizard generated APIs, or a custom query provided by you.

  • url - the URL,
  • reqobj - the object which is passed as POST data,
  • 'query' - fixed string to be passed literally,
  • this.handler - a method you should implement in the class to receive the result,
  • this - Current object reference, should always be this,
  • parameter - a parameter to pass to the handler. The handler will receive two parameters - the retrieved data and the parameter provided here.

Get the list of entities from UI cache getProperty(entityname, 'entity')
  • entityname - the name of the entity,
  • 'entity' - fixed string to be passed literally.

Get current user info getProperty(null, 'login')
  • null - ignored,
  • 'login' - fixed string to be passed literally.

Get page environment getProperty(envname, 'env')
  • envname - the name of the environment setting (vappprefix, voptsrq, vdatarq, instanceid, projectid)
  • 'env' - fixed string to be passed literally.

Render a report as an interactive table jQuery plug-in DataTable When rendering a report as a table, you can use DataTable jQuery plug-in. It is loaded in the UI page. See documentation at datatables.net

Interact with UI page.

Custom UI Controls

You must provide a JavaScript class with the following structure-


// The class declaration (constructor).
function {ClassName} (div, names, form) {
	// 'div' is the jQuery handle for the div element, in which the control should be rendered.
	// 'names' is the value you specified for the control (it can be multiple names separated by comma).
	// 'form' is the object reference to the UI page. You use it to interact with the UI (See above).
}
// This method declaration should be present. It is called by the form, whenever an input field on the page
// changes. The control can update itself in response to changes to other elements.
{ClassName}.prototype.handleFormChange = function(name) {
	// 'name' is the name of the field (Entity property) that has changed.
	// Update the control, if required.
}
// This method declaration should be present. It is called by the form to obtain the control's value before
// the save operation. You should return the value of the Entity property.
{ClassName}.prototype.get = function(valonly) {
	// 'valonly' is a boolean - if true, only return if the current input is valid. Return '' if OK,
	// or return the error message to be shown to the user.
	// If 'valonly' is false, return the value of the control. The return value should be an array
	// containing as many values as there are input fields in the control (names) and should be the
	// same datatype as declared in the Entity Property.
}
	

Reports

For report rendering, you must provide a JavaScript class in the following structure-


// The class declaration (constructor).
function {ClassName} (divid, params, form) {
	// 'divid' is the id of the div element, in which the report should be rendered.
	// 'params' is an object containing the current selection when the report is invoked (The report entity).
	// 'form' is the object reference to the UI page. You use it to interact with the UI (See above).
}
	

Custom pages

You must provide a JavaScript class with the following structure-


// The class declaration (constructor).
function {ClassName} (form, divid, param) {
	// 'form' is the object reference to the UI page. You use it to interact with the UI (See above).
	// 'divid' is the id of the div element, in which the report should be rendered.
	// 'param' is the parameter passed in the URL, while invoking the custompage. Generally when sending
	//	the URL to external user, you will include these parameters in the URL.
}
	

Child data editor

The data in child entities may, sometimes, be related in a way that cannot be expressed by a generic Add/Edit/Delete list interface. ZOAPIIO allows you to provide a custom editor for editing the data in the child entity. Provide a JavaScript class with the following structure and specify its name in the 'editor' attribute of the 'children' node along with the window size. E.g. {ClassName}:1000x400.


function {ClassName} (form, div, data, owner) {
	// 'form' is the object reference to the UI page. You use it to interact with the UI (See above).
	// 'div' is either the Id or the jQuery reference to the editor window.
	// 'data' is the current records in the child entity.
	// 'owner' is the handle to an object, where the edited data should be returned.
	//
	// This class should implement the full UI for the editor including the "Save" and "Cancel" buttons.
	//
	this.div=div;
	this.data=data;
	this.owner=owner;
	// Convert the div reference from Id to jQuery handle.
	if (typeof div=='string') this.div=$('#'+div);

	...
	...
	// When editing is over and the user does Save.
	this.owner.editorCallback(this.data);
}
	

Handlers

Property Description
name A Unique name for the handler file. Usually, you can have all your handler programs in the same file, but not necessary.

file The name of the file (.webc extension) having the server program ( programming language).
Handler properties.

The handler programs are server components, which can be added to your application at generation time. You should write these components using the Web-IDE, save them on your desktop and provide it here. This is in XML format and can also be manually edited by experienced users.

You can include ROUTINE, METHOD, VARIABLES, DATABASE-QUERY and other TAG declarations in the file. See the Web-IDE documentation for details. The format is-


<PRMLCONFIG CONFIG="RRML">
<VARIABLES>
	<TAG ...>
</VARIABLES>
<DATABASE-QUERY .....>
	<TAG ...>
	<QUERY-PARAMETER ..>
</DATABASE-QUERY>
<ROUTINE NAME="RoutineName">
	<BIZ-RULE ...>
</ROUTINE>
<METHOD NAME="MethodName">
private String MethodName(Node in, Node out) {
	// Java code..
	return SomeStringVal;
}
</METHOD>
</PRMLCONFIG>
	

Custompages

The application generated by the Wizard is meant to be a business application and will be used within your organization. It is not meant to be an end-user web application. For an end-user web or mobile application - see Apps. You can also, of course, build a completely custom web or mobile application and integrate it with the server.

Custompage is used to create a page in your application, which can be exposed to an external user to accept some input. The simple use case for this is where you want your customer or supplier to provide some solicited input or feedback. When using the custompage, the rest of the UI is ineffective and only the custompage is displayed.

Property Description
name A Unique name for the custompage.

file The name of the file (.js extension) having the program.

editor The name of the JavaScript class declared in the program and will render the page.
Custompage properties.

Properties

server provides you abstraction for Application properties. These properties are stored on the server in a database table and your programs can define and access them. You can update the Application property table directly using the DB Assistant tool. However, the Wizard allows you to populate these properties conveniently at generation time. The properties you define here are accessible to your custom server APIs as Properties abstraction. See the Web-API documentation for details.

Property Description
name A Unique name for the property.

value The value of the property.
Application properties.

Screen Shots

Screen Shots

Reference Guide

Summary

Legend: Array value
Object Description
application The complete description of your application.
themes The visualization app has two pre-defined themes (dark/light). You should define here the themes you want to be available in your app. At least one theme must be defined. If you define both themes, then the one defined first is the default.
entities An entity refers to a database table and necessary UI pages to manage it. Define all the entities here.
access This defines entity page level access control in your app.
classification Classification is used in entity data level access control. It defines codified access tags for entity records.
RESTaccess A true/false value to tell the wizard if REST access API should be generated for this entity.
handler There are server-side events associated with entity record lifecycle. This allows you to configure custom handlers for these events.
properties The properties (or fields or columns) of the entity table. Note that the Wizard adds some properties of its own.
children If the entity has any child entities, define them here.
properties The properties of the child entity.
dependents Define entities which are related to this entity through a foreign key relationship.
workflow If the entity has a workflow associated with it, define it here.
steps The steps in the workflow.
customization Grouping of all customization elements (front-end and back-end) for your app.
scripts The JavaScript files that contain external custom code.
helpfiles The single-page HTML help files for the app.
handlers The ZOAPIIO program files that contain external server-side custom code. Multiple handlers can be put in the same file.
custompages You can add fully custom pages to the app. Define them here.
properties ZOAPIIO apps have an application property-set concept. It is stored on the server and can be accessed by server-side code. If you want to create some application properties at generation stage, you can put them here.
widgets Widgets are building blocks of a dashboard. ZOAPIIO allows users to create and save custom dashboard layouts by combining these widgets. The widgets, their definition and behaviour should be provided here.
selection The selection parameters in the widget.
output Definition of the widget output.
query A database query that will fetch the data for the widget.
result Definition of the widget result.
options Options for the widget result.
dashboards Normally, the users will create their own dashboards from the visualization app. However, you can add some dashboards to the generated app which are accessible to all users in the basic app itself.
widgets Widgets that are a part of the dashboard.
The Wizard config structure.

application

Property Description
name Unique name for the application. The name is important, it will be prefixed to the table names and embedded inside API names to ensure that the different applications you are building do not interfere with each other. Pick a short name, about 5-6 characters, starting with a letter and without spaces or special characters.

title A short phrase describing the application.

userroles A short phrase describing the application.

defaultrole Your application will use User Roles to control access to pages and entities. When you launch your application for the first time, it allows you to add the first user from the home page. This is the role that will be assigned to the application boot user. Provide the name of the most powerful role in your application here because you will use this to create other users.
'application' properties.

themes

Property Description
name The name is fixed and you should choose one from the list - default (dark), or theme-a (alternate light theme).

type The UI engine needs to know if this theme is dark or light. Choose the one applicable to the selected name. Choosing a different value may result in sub-optimal rendering of the UI.

title A short title of your choice - this is displayed in the UI.
'themes' properties.

entities

Property Description
name The name of the entity. This will be used as the database table name (with application name as the prefix). Have a short, yet descriptive name, without any special characters or spaces. It is advised to use all lowercase name for consistency.

label A short phrase describing the entity. This name will appear in the UI, so make it meaningful and keep it short.

menu The application UI will group entities under menus. Provide the name of the menu under which the entity should appear. Keep the menu name short and meaningful. Same menu name can be assigned to more than one entities - they will all appear under that menu.

icon An icon can be specified with the entity. Font Awesome icon set version 5.15 (free) is used for the icons. Enter the name of the icon from the set (E.g. anchor).

menuicon This icon is displayed against the Menu entry where the entity is grouped. The menuicon needs to be specified with only one (any) entity under a menu group. The specification is same as that for the icon attribute (FA 5.15 icon set).

data This property is important, and it tells the wizard what type of data will be stored in the entity. When creating the database table, some columns are automatically added. This property will have an effect on the columns that will be added. This property can be blank.
  1. person: The entity represents a person.
  2. thing: The entity represents a thing or a place.
  3. user: The entity represents the application(b2b) user - users within the organization who are added to the system manually. Only one entity can have this data setting.
  4. usergroup: The entity represents the application user groups (teams). Only one entity can have this data setting.
  5. b2cuser: The entity represents a subcsriber(b2c) user - subscribers can register/subscribe through the web/mobile app and add themselves to the system (See ZOAPIIO app development guide). Only one entity can have this data setting.
  6. setting: The entity will be used to store the application settings. A setting entity is special because only one entity record can be created. Only one entity can have this data setting.
  7. noname: The entity represents something which has no name. I.e. the name column(s) will not be added. Because the Name column is automatically added in most cases, this is useful to explicitly inhibit that.
  8. transaction: The entity represents data which is created and maintained manually (custom APIs). It is not shown on the UI and no extra columns are added.
  9. report: The entity represents an on-line report. No database table is generated, and you should provide a customization module to process and display the report.

bootuser This property is only applicable for the entity with data=user. You can provide here the details of a user that would be automatically created at the time of first generate of the application. You can use this to login to the application and create other users. The boot user gets the same role that is defined as the default role for the application. The format is-
"Username=XXX,Password=XXX,Name=XXX"

tip This can be a larger description of the entity extending up to a sentence. It is shown to the user as mouseover tip.

editor This is required if the 'data' value is set to 'report'. It is the name of a JavaScript class, that will be invoked to process and render the report. The JavaScript code should be separately provided - see Customization.

indexes An array of strings - this allows you to create indexes on the table that will be created during generation. Each string in the array represents a different index and each index is a comma separated list of property (column) names in the index. E.g. "Name, Age".

fetchsummary This is a true/false value. Usually, when the visualization app loads, it fetches a summary (Id, Name, etc.) of all entity records. This is done for optimization but can become a burden if the number of records is large. If you expect the number of records in the entity to be larger than, say 2000, set this to false.

fetchlimit When the visualization app lists the records of an entity, it fetches a maximum of 100 records. If you want this to be set to a higher value, you can do so here.
'entities' properties.

access

'access' attribute controls page level access to the entity. It has no effect on data access. Access Control for details.

Property Description
name The name is fixed and you should choose one from the list.

full A list of strings - userroles with full access page.

readonly A list of strings - userroles with read only access page.

demo A list of strings - userroles with demo access page.
'access' properties.

classification

Classification allows you to define readable names that map to an access code, which itself control entity data access. The user it not restricted to using these names, they can specify their own access control code. This is for convenience only. Depending upon the sensitive attached to the data in the entity, you may define classifications like "open", "restricted", "private" etc. and the user can simply pick one value instead of entering detailed access rights for each placeholder in the code. Access Control for details.

For example { "open": "WWWWWWRR", "private": "WWR-R-R-" }.

handler

The wizard would generate APIs to access the entity data. Handlers allow you to specify custom processing for major access control points. The handler program stubs are in programming language. The program stubs should be provided as an external file - see Customization.

The values for the handlers are provided as "METHOD.<name>" or "ROUTINE.<name>", naming the method or routine to execute at that control point.

Property Description
beforesave Custom program stub (server) to execute before saving the record. This stub can reject the save operation or update the data in the record. The database table Node is passed as the first parameter to the routine/method. To reject the save operation set node /VARIABLES/ACCESS/CANWRITE to "NOK".

aftersave Custom program stub (server) to execute just before saving the record. In this stub, you have the opportunity to modify the record after all system processing has been performed. You cannot reject the save operation from this handler.

afterdbsave Custom program stub (server) to execute after saving the record. In this stub, you cannot reject the save operation and changes to the record have no effect. Typically used to make other dependent changes, sending user notifications, or making API calls to other applications notifying the change.

beforesearch Custom program stub (server) to execute before search on the entity. You can modify the SQL command right before the search is fired. The Database table node is passed as the first parameter. The program can access _WHERE field from the Table node and alter it, if required.

beforelist Custom program stub (server) to execute before listing a record. You can reject access to the record and modify record properties. The database Node is passed as the first parameter. To reject list access to the record, set /VARIABLES/ACCESS/CANREAD to "NOK".

beforeregister Custom program stub (server) to execute when a new Subscriber (b2cuser) is trying to register. You can carry out additional validations and reject the effort. If the registration is to be rejected, assign the error message to the Data Path "/Response/Status[2]".

afterregister Custom program stub (server) to execute after a new Subscriber (b2cuser) has registered register. In the handler, you can update any dependent values, trigger workflow or issue alerts.
'handler' properties.

properties

A property declared for an entity can be a simple property or a complex property, determined by its type. This means that the property may result in the generation of one or more columns in the table. Each property on the UI is rendered on a single row. For instance, type 'country' is a complex property and results in two table columns - Country code, and Country name.

Where a complex property is involved, you must provide more than one names for property - the number of names must match the count that the property type expects. The names are input as comma separated values - E.g. CountryCode,CountryName. Furthermore, you can create a complex property (multiple columns but rendered on the same UI row), by using the type 'multiple'. This is used to group related properties to simplify the look of the UI page. It is advised to have not more than three properties in a group for clean rendering.

Property Description
name Unique name(s) for the property. Multiple names, if applicable, are input as comma separated names without any spaces. Each name must not contain spaces or special characters - the only characters permitted are letters (both upper and lowercase), digits and underscore (_). The name cannot start with an underscore.

privileged A boolean value to indicate if this is a privileged property. Privileged properties have additional access controls. This allows you to take properties that contain sensitive information to be applied additional protection. See Classification above.

label A short user readable name for the property. There will be only one label, even if there are multiple names. Also see labels below.

type The type of the property.
  1. string : Simple string field.
  2. text : Simple text field.
  3. ftext : Simple formatted text (HTML) field.
  4. password : Simple password field.
  5. integer : Simple integer field.
  6. decimal : Simple decimal field.
  7. amount : Simple amount field (decimal with currency).
  8. time : Simple time field.
  9. date : Simple date field.
  10. datetime : Simple date with time field.
  11. dow : Simple date of week field.
  12. timezone : Simple timezone field.
  13. hashtag : Simple string field with special processing attached to it. Hashtag fields are enabled for searching as tags. The input valuee is space separated list of tags.
  14. country : Complex (Code,Name) field representing Country.
  15. timerange : Complex (From,To) field for time range.
  16. decimalrange : Complex (From,To) field for decimal range.
  17. amountrange : Complex (From,To) field for amount range.
  18. geolocation : Complex (Latitude,Longitude) for geo location.
  19. daterange : Complex (From,To) field for date range.
  20. temperature : Complex (Value,Unit) field for temperature.
  21. file : Complex (FileName,FileData) for documents.
  22. thing : Complex (Name,Picture) for an object.
  23. person : Complex (Title,FirstName,LastName,Picture) for a person.
  24. multiple : Complex property with arbitrary number of values.
  25. select: : String field with fixed list of options.
  26. easyselect: : Same as select: but rendered as checkboxes.
  27. combo: : String field with combo (select but ability to enter any value) input.
  28. entity: : Complex (Id,Name) reference to another entity record.
  29. collection: : Simple (JSON) field to capture a collection of other entity records.
  30. custom: : A user defined field. It can have any number of names, the custom control should handle all fields collectively. See Customization
Property types that end with a colon ':', require a subtype to be entered - see below.

subtype A subtype must be entered when the type name ends with a colon ':', as follows
  1. select: : Comma separate list of select options.
  2. easyselect: : Same as select: above.
  3. combo: : Same as select: above.
  4. entity: : Name of the entity, to be used in reference.
  5. collection: : Name of the entity, to be used for collection.
  6. custom: : The name of the JavaScript class to render the property on UI. The custom JavaScript should be provided as a separate file. See Customization

validation The input validations applicable for the property. Validations implicit from the property type are automatically applied. Additional multiple validations can be specified as comma separated list.
  1. required : A value must be provided for the property.
  2. simple : A input must be a simple string (Only letters, digits, and @._- are permitted).
  3. email : A input must be a valid email address.
  4. phone : A input must be a valid phone number.
  5. url : A input must be a valid URL.
  6. match : For type 'password' property, the input values must match (when setting a password).
  7. single : For type 'dow' fields, only a single day of week can be selected.
  8. readonly : The value cannot changed.
  9. addonly : The value can only be added (I.e. changed when it is blank).
  10. document : For type 'file' property, the attachment should be a document (pdf, html, docx, or text). There are additional implications when this validator is used - see the section on Managing Attachments
  11. compressed : For type 'file' property, the data should be stored with compression.
  12. encrypted : For type 'string' property, the data should be stored with encryption.
  13. image : For type 'file' property, the attachment should be an image (png, gif, or jpg).
  14. username : The input value should be unique (should not already exist as a username).
  15. regex[...] : The input value should match the given pattern.

default The default value for the property. For date fields, shortcut 'today' and for time fields, shortcut 'now' can be used.

searchdefault The default value for the property when invoking the search. The default listing produced on the 'List' command will use this default. You can, of course, change it on the search page and search again.

condition This is used to conditionally display a property on the page. If specified, it should be a JavaScript expression evaluating to a boolean value. It can reference other properties on the page by prefixing it with an @. E.g., "@Status=='incomplete' would show this property only if the Status property on the same form is equal to 'incomplete'.

filter The filter attribute is used to implement cascaded fields. See Filtering and Cascading

types The comma separated names of simple types of each field in the property. Applicable where the type is 'multiple' or 'custom:'

labels A comma separate list of field labels, if the type is 'multiple'. For 'multiple' type fields, the label should be for the property as a whole and labels should be short values for each field in the property

cached This is a boolean true/false value that defaults to false. The Visualization app upon loading, fetches selected properties of all entities (unless explicitly disabled using - 'fetchsummary' property). This allows the UI to have quick access to key details - the local cache is updated when an entity record is saved.

The contents of the cache can be accessed programmatically in the client side custom code. Setting the 'cached' attribute to true would cause this entity property to be fetched with initial load.
Entity 'properties' properties.

children

Property Description
name The name of the child entity. Same as for 'entities'

label Same as for 'entities'.

editor The visualization app provides a simple Add/Edit/Delete interface to manage data in the child entity. However, your application may require that all records in the child entity be edited together through a custom UI. If this is the case, provide the name of a JavaScript class, which will be invoked to edit the child entity records. The JavaScript code should be separately provided - see Child data editor.

The value of this attribute can be optionally followed by a window size specification for the editor window, in the format - {ClassName}:{width in px}x{height in px}

fetchlimit Same as for 'entities'.
'children' properties.

properties

The specification for properties for child entities is same as that of root entities, with some constraints.

  1. Data type 'multiple' cannot be used.
  2. Property 'data' is not applicable.
  3. Property 'condition' has no effect. I.e. conditional rendering is not provided.

dependents

Another relationship between entities that can be represented in the Wizard is one-to-many relationship. This is different from parent-child because a child entity has only one parent. To represent a dependent entity, define that entity normally and then add a record here.

Property Description
name The name of the related entity.

property This is the property (field) in the related entity that links to the Id field of this entity and establishes the relationship.


label A meaningful label for the relationship, or leave blank if you do not believe in putting labels on relationships.


workflow Value true/false - if true, it tells the app to display the workflow information, when the listing the dependent entity records.

'dependent' properties.

workflow

Workflow is a list of steps that should be performed on the records of an entity.

steps

Property Description
name The name of the workflow step.

attributes A list of attributes that define the nature of the step. The following attributes can be used in the list. For teamspec and userspec, the JavaScript expression can refer to user and team properties by prefixing it with '@'. E.g. "@UserRole=='somerole'".
  • approval: This is an approval task.
  • ticket: This is a ticket (help desk) task.
  • task: This is a regular task.
  • all: This task can be performed by anyone.
  • supervisor: This task can be performed by a supervisor (assigned as manager).
  • team[teamspec]: This task can be performed by a member of a team meeting the spec - the spec is a JavaScript expression evaluating to a boolean value.
  • user[userspec]: This task can be performed by a user meeting the user spec - the spec is a JavaScript expression evaluating to a boolean value.

prereq A list of workflow steps which are prerequisites for this step.
'steps' properties.

scripts

Property Description
name The name of the script - give a short meaningful name.

title Give a short title for the script.

file When running the wizard, you must select a file using the Explorer - the wizard, by itself, cannot read your files. Provide here the name of the file (.js extension), which you will supply. The file name acts as a validation so that you do not accidently load a different file.
'scripts' properties.

helpfiles

Property Description
name The name of the helpfile - give a short meaningful name.

title Give a short title for the helpfile.

file Same as in 'scripts' above, except the file extension should be .html.
'helpfiles' properties.

handlers

Property Description
name The name of the handler - give a short meaningful name.

title Give a short title for the handler.

file Same as in 'scripts' above, except the file extension should be .webc.
'handlers' properties.

custompages

Property Description
name The name of the custompage - give a short meaningful name.

title Give a short title for the custompage.

file Same as in 'scripts' above, except the file extension should be .js.
'custompages' properties.

properties

Property Description
name The name of the application property.

value The value of the application property.
Application 'properties' properties.

widgets

Property Description
name The name of the widget.

label A short label for the widget

type See widget types below.
Widget basic properties.

visualization app supports a rich collection of widgets compiled from an analysis of several real-life dashboards. The widgets can be textual or graphical, or sometimes even a combination. The following widget types are supported-

Widget Types

Type Seq Description
PieChart 1 Pie charts are quite common and require no description. pie charts support sub-groups of items, effectively letting you represent what would normally take multiple Pie Charts. Suppose you want to represent the break-up of employees by designation and gender in the same pie-chart, you can create two groups "designation" and "gender" and then plot it in the same chart.
2 The pie chart expects a single row of data with the following fields in the input - group, name, value (See Result below).

LineChart 1 Line Charts are also very common and it will plot each item in the data row on the line chart. The result specification should have exactly one value of type 'string' and one or more 'number' values.

Status 1 Status charts are used to represent the status of an object or activity. The status chart can optionally have a progress indicator or a history.
2 The status chart expects a single row of data with the following fields in the output (See result) - reading (the value), units, statuscolor (E.g. red, green, etc..), label1, label2 (up to two labels describing the context of the status), progress (a number between 0 and 100), history (a comma separated values indicating last few values for this indicator for easy visualization by the user).

TimeSince 1 Time since charts are used to represent the time elapsed since an event - normally used for depicting events that you do not want to occur, E.g. accidents.
2 This chart expects a single row of data with the following fields in the output (See result) - days, hours, minutes, seconds.

Gauge 1 Gauge charts are used to represent one or more values on a odometer type gauge - such as CPU utilization on a server or production efficiency etc.
2 The Gauge chart expects one or more rows (but given the rendering limitation, usually very few) of data with the following fields in the output (See result) - name, value.
3 The Gauge chart can also be passed the range option in the widget data consisting of 5 numbers in ascending order indicating the values range to be shown on the meter. E.g., a setting of "0,40,60,80,100" would mean: 0-40 is white color, 40-60 is green (OK), 60-80 is yellow (Warn) and 80-100 is red (Error).

TextLog 1 TextLog charts are used to represent a log of events or notifications.
2 The Gauge chart expects one or more rows of data with the following fields in the output (See result) - ts (timestamp), msg (the notification).

Pivot 1 Pivot (pivot table) is the most versatile chart and can be used to depict data in a variety of formats.
Widget types in Visualization app.

selection

Selection allows you to attach filters to widgets, allowing the user to control the widget in the dashboard.

Property Description
name The short name of the selection. The value selected for this filter will be accessible in your Widget query (DB SQL) by this name.

label A short label for the selection

values Comma separated list of values, if this is a drop-down. Special values #period can be used to specify a period selection (last week, last month etc.). Special value #longperiod can be used for selection over a long period (last quarter, last year etc.)

type dynamic or fixed. A fixed selection is set at the time of creating the widget in the dashboard and cannot be changed when viewing the dashboard. A dynamic selection can be changed when viewing the dashboard.

render select/multiselect/dropdown/checkbox/radio/date - how to render the selection control.

multiple true/false - whether multiple values can be selected.

default The default value for the selection.
Selection properties.

query

The data for the widget is sourced from a database query (SQL), which you must provide. Database programming skills are required. If you are not skilled in writing SQL queries, take the help of a colleague.

  1. You can reference the entities as tables in the query by prefixing them with '@'. E.g., "Select column from @myentity"" implies selection from the table corresponding to the "myentity". The SQL can reference multiple entities using SQL JOIN them in the same way.
  2. You can reference the values of the widget selection filters by prefixing the name with '#'. E.g., #PROP refers to the value of selection with name PROP.
  3. When using the filter selection values do not use the comparison operator - it is automatically added depending upon the type of the selection value. So instead of "Where ColX = #PROP", say "Where ColX #PROP". The Wizard with use either '=' or 'In' SQL operator depending upon whether the value is a string or a list.

result

Here you describe the data contained in the query output.

Property Description
name The name of the field.

label A short label for the field

type string or number - this is important. See Widget Types above.

data The data value. It can be a fixed string or '@' followed by the name of a column output from the query.
Result properties.

options

Additional options can be passed to control the rendering out the widget.

Property Description
name The name of the option.

value The value of the option.
Option properties.

dashboards

This defines canned dashboards in the application - this is an advanced subject and you can come back to it after you have tried creating some dashboards from the visualization app UI.

Property Description
name The name of the dashboard.

owner The Username from the app users designated as the owner of the dashboard. This value can be populated after the users have been added to the visualization app. To update the config after the application had been generated and deployed - use the "Update Artifacts" option. See Regenerating the Application.

This attribute and 'ownergroup' and 'access' below together determine who all can see the dashboard.


ownergroup Same as the owner, except for the Owner group.

classification Not applicable - leave it blank.

access An eight character access control code for the dashboard. See Access Control

description A brief description.
'dashboards' properties.

widgets

The widgets in the canned dashboard.

Property Description
name This must be the name of the widget as given in the Widget definition.

title A short title.

x This attribute and the y, w, h below together determine the location and space occupied by the widget. The dashboard area is divided into a 6x6 grid. x,y must be numbers between 0 and 5 representing the x,y coordinates of the starting block. w,h must be numbers between 1 and 6 representing the width and height in number of blocks respectively.

y See x above.

w See x above.

h See x above.
'widgets' (under dashboards) properties.

Screen shots

The wizard designer

The Application Wizard view.

The generated application

Sample Screen from the generated app.