Friday 7 October 2016

Introduction to TACTIC Plugins


TACTIC Plugins are a way of packaging up functionality and distributing them
to other projects or other servers.

The Plugin architecture is very flexible and almost any functionality, large
or small can be packaged in as a plugin.

A TACTIC Plugin can contain:

  1. data
  2. configuration
  3. python class
  4. 4mages and media
  5. css and javascript libraries


At the core of a TACTIC Plugin is a manifest file.  The manifest file tells TACTIC how to load and unload a plugin.  It is an xml file and is placed at the root of the plugin folder.  A simple example of on is as follows:

<manifest>
  <data>
    <code>spt.whatever</code>
    <title>XYZ</title>
  </data>
  <sobject search_type="custom/asset"/>
</manifest>

It declares what data belongs to the plugin.

The above manifest will create a plugin that will export all entries from the "custom/asset" search
type to a file called "custom_asset.spt".  Files with ".spt" extension are TACTIC custom files that are used for importing and exporting data.  The syntax used is exactly the same as Python (a python processor is used to read the data), however they are not self-contained and executable and thus not really considered ".py" files. However, if desired, any python code could be added and it should be processed correctly.

When loading the plugin, the "sobject" will read the corresponding ".spt" file and insert the new sobjects into the database.  On unloading the plugin, the entire table will be removed.  This because the line states that the entire table belongs to the plugin.  This is useful for custom search types, but often it is desireble for the plugin to own a subset of table.  The easiest way to do this is with an expression

<sobject search_type="custom/asset" expression="@SOBJECT(custom/asset['asset_type','image'])"/>

This will export all the sobjects with the column asset_type equal to "image".  This
allows multiple plugins to share data in the same search type.  Care must be taken so
that a given sobject only belongs to a single plugin to avoid conflicts.

To control the output file the data is written to, the "path" attribute can be used.

<sobject search_type="custom/asset" path="config/asset.spt"/>

This file created will be relative to the manifest file.  This can be used to
break up a single table into multiple files, if that is desired.

It is quite common not to wnat all the columns in the exported file.  The
"ignore_columns" attribute can be used to specify columns that are not exported.

<sobject search_type="custom/asset" igonre_columns="id,code,timestamp"/>

The code and id are commonly not exported.   The "id" column is usually auto
generated, so their exact values are not important as long as they are not used
to relate to other table.  This prevents conflicts of ids loaded in from other
plugins.  If the code needs to be exported, it is important to ensure that this
code will be unique enough to be loaded even if data is already filled in that table.

If the definition of a search_type needs to be exported, the "search_type" tag can
be used:

<search_type code="custom/asset"/>

This will save out the entire search_type definition into the ".spt" file.  This makes
it possible for a plugin to own the definition of a search_type allowing a plugin
to define a data model.

With the combination of the <search_type> tag and the <sobject> tag, almost any
configuration data can be stored in a plugin.


When a plugin is loaded, the plugins folder is also accessible from the web server.
This means that images and other files can be put into a plugin and be visible by
a client web broser.

For example:

<img src="/plugins/test_plugin/media/image.png"/>

This would be visible by the following URL:

http://<server>/plugins/test_plugin/media/image.png

This allows the plugin to package up different image files as well as javascript and css files.

This was just a small introduction to TACTIC plugins.  The plugin architecture is flexible enough that almost any TACTIC functionality can be encapsulated in one.





Friday 30 September 2016

Dynamic updates when data changes.

Dynamic updates allow any part of the page to update itself based on change occurring  on the server.


To illustrate, begin with a simple element that display the number of assets in the system.


<div>${asset_count}</div>


In Python, the asset count would be retrieved as follows.


asset_count = server.eval(“@COUNT(example/asset)”)


When the view loads, it would process the asset count on the server side and then fill in the value in HTML.  The problem comes when someone else who is using the system adds another asset after a view has been loaded.  The data displayed is now out of date.  Normally the entire page, or in TACTIC’s case, the widget needs to be reloaded to update the correct value. However, knowing when data has changed presents a challenge.


Dynamic update solves this problem by providing a mechanism to update some part of the content based on some specified updated criteria.


For example, in the widget above, we will add an update through javascript:


<div class=”test_update”>${asset_count)</div>


In python, we would write:


kwargs[‘expr’] = “@COUNT(example/asset)”
asset_count = server.eval(kwargs.get(“expr”))


And in behaviors, we would add:


<behavior class=”test_update” event=”load”>
 var expr = kwargs.expr;
 spt.update.add( bvr.src_el, {
     expression: expr
 } );
</behavior>

This will check the expression periodically to see if the value has changed on the server.  It the value changes, such as a new asset was added, this would be detected and the value of the expression will replace what is inside the “test_update” element.  This is very useful for keeping values up to date on a page without having to refresh.


There is another argument called interval.  Normally, a dynamic update will check every couple of seconds, however, most data this is much too often.  It is possible to slow down the number of checks by setting the interval.


<behavior class=”test_update” event=”load”>
 var expr = kwargs.expr;
 spt.update.add( bvr.src_el, {
     expression: expr,
     Interval: 10,
 } );
</behavior>


This will do a check on the server about every 50 seconds.


If a widget is dependent on the values of a single SObject, then we can add search_key parameter instead and this will detect if any change to a particular SObject has been made.


<behavior class=”test_update” event=”load”>
 var search_key = bvr.kwargs.search_key;
 spt.update.add( bvr.src_el, {
     search_key: search_key,
     expression: “@GET(.status),
 } );
</behavior>


With the addition of a search_key, TACTIC will check if any changes have been made to that SObject.  If so, it will replace the “test_update” widget with the value returned from the corresponding expression.


In order to have more control, it is possible to run some javascript.


<behavior class=”test_update” event=”load”>
 var search_key = bvr.kwargs.search_key;
 spt.update.add( bvr.src_el, {
     search_key: search_key,
     cbjs_action: “spt.panel.refresh(bvr.src_el)”
 } );
</behavior>


This will update refresh the next parent refreshable widget when the corresponding SObject changes.  With a javascript callback, it is possible to do a wide variety of actions.


Finally, it is possible to attach a dynamic behavior purely in Python.


div = DivWdg()
div.add_update( {
   “expression”: expr
} )


This allows a widget that is entirely written using a Python class to make use of dynamic updates.

Dynamic updates provide a powerful and flexible means of update interface elements based on data changes on the server.  With careful judgement about what needs to be updated and how often, data viewed on a page will never be out of date.

Wednesday 28 September 2016

What is a TACTIC Widget?



Widgets are self-contained user interface elements.  In TACTIC, they combine HTML layout and CSS styling with server-side Python processing, client side Javascript behaviors, all encapsulated in a single entity called a widget.


Widgets are a fundamental building block to interfaces in TACTIC. Even the base HTML tags have been mapped to TACTIC Widgets, however, most users will create and combine higher level widgets using pure python classes or, more commonly, they can be created using the TACTIC Custom Layout Editor.


The custom layout editor enables the creation of widgets directly within the TACTIC interface. Very complex enterprise applications can be created using solely this editor without needing to resort to Python class (however, that is always an option, if desired)


There are 5 main components to a TACTIC Widget:

  1. Keyword Arguments
  2. HTML
  3. Styles
  4. Behaviors
  5. Python


Each of these components make up the definition of single widget.  They are form a single interface element. The simplest widget is a pure html element.


<div>Hello</div>


In order to style this element, CSS can be attached to this element.   Because this is HTML, you can add CSS styles directly on the element itself:


<div style=”color: #F00”>Hello</div>


A better method is to separate out the styling of the widget from the structure.   Although, an “id” could be used to relate CSS to this element, it is generally not recommended.  This is because “id” must be unique throughout the entire document.  With widgets as reusable elements that can appear many times in a single interface, it is better to identify an element using “class”.


<div class=”element1”>


And in the styles tab of the Custom Layout Editor, you would add:


.element1 {
   color: #F00;
}


TACTIC Widgets also bind server side processing into the widget.  The python component has a predefined kwargs variable that contains input arguments to the widget.  Thus in the python tab, you could write:


color = kwargs.get(“color”)


And you could use this variable in both the HTML tab and the styles tab.  For example:


.example1 {
   color: ${color};
}


This becomes a configurable widget that can be embedded into another widget using the HTML as follows:


<div>
 <h1>Reference to another widget</h1>
 <element view=”content1” color=”#0B0”/>
</div>


The  would embed the word “Hello” with blue text into this widget.


Finally, you can access the kwargs variable in javascript in the behaviors tab from the implicit bvr variable:


<behavior class=”.element1” event=”click”>
   var color = bvr.kwargs.color;
    alert(color)
</behavior>


Using these together, you can build up more complex reusable widgets.


There are a number of significant advantages of using TACTIC for content delivery, despite the many web platforms out there and many that do a good job of delivering web content.  For those more comfortable with these other platforms, there is a TACTIC javascript standalone API which can be imported into any web framework.  


TACTIC widgets have a very strong encapsulation between the client side code and the server side code.  Data structures are seamless transferred and shared between the two. TACTIC widgets can be loaded asynchronously and do not rely on full page refresh to load content.  This makes TACTIC apps feel smoother because they only update parts of the interface that need updating.  TACTIC also has many built-in widgets that do common widgets that together provide a wide range of tools to handle many enterprise requirements, especially when creating data driven workflow solutions.




Monday 26 September 2016

Keyword arguments (kwargs) in Custom Views


Custom views are a great way to create widgets in TACTIC.   They combine HTML, CSS, server side Python and client Javascript all in a single self contained widget.  All views in TACTIC have a predefined variable named “kwargs” which contain parameters that are passed to the widget from some external source.  The kwargs variable is a simple dictionary of name / value pairs and represent keyword arguments for that widget.  These kwargs can be used to write highly functional general purpose widgets that can be reused.


In a TACTIC using the Custom Layout Editor, it can be assumed that there is always a kwargs variable which can be simply accessed in the Python section of the custom view.


color = kwargs.get(“color”) or “”
search_type = kwargs.get(“search_type”) or “”


These variables can be accessed in the HTML component using the following syntax:


<div class=”top_element” style=”color: ${color}”>
 <element view=”view1” search_type=”${search_type}”/>
</div>


Thus a variable take from the kwargs are passed from python to an HTML, first to set the color style and second, to pass the search_type to another view which will receive as a kwarg as well.


The variables defined in Python are also accessible in the styles section:


.top_element {
   color: ${color};
}


The kwargs variable is also passed along to the behavior section:


<behavior class=”top_element” event=”click”>
   alert( bvr.kwargs.search_key );
</behavior>


This makes the input variables through kwargs available to all parts of a TACTIC widget.  One often used technique is to go fill in the kwargs variable with custom key / value pairs to simplify the communication of data between Python and Javascript


server = TacticServerStub.get()
count = server.eval(“@COUNT(workflow/asset)”)
kwargs.count = count


And in Javascript


<behavior class=”top_element” event=”click”>
   alert(bvr.kwargs.count)
</behavior>


The kwargs value can be a complex data structure as well:


codes = server.eval(“@GET(workflow/asset.code”)
kwargs.codes = codes


And in Javascript


var codes = bvr.kwargs.codes;
for (var i = 0; i < codes.length; i++ ) {
   alert(codes[i]);
}


Put together, this provides a complete communication for transferring data for server side data to the client side, all encapsulated in a single widget.

Saturday 24 September 2016

Delayed loading using load=”async and load=”sequence”


Custom Layout views enable the display of content using a set of widgets.  The custom <element> tag enables TACTIC views to reference other widgets.  A complex page can be broken down into smaller reusable components.


<div>
 <element view=”content.view1” mode=”XYZ”/>
</div>
<div>
 <element view=”content.view2” mode=”XYZ”/>
</div>


Here, a master view can reference two smaller views, each passing in the kwarg “mode” with the value “XYZ” to the referenced view.  When a call is made to draw the overall view, TACTIC will build the entire view with all the reference view on the server and then serve up the entire content to the client.  If “content.view1” or “content.view2” are either large or take up a lot of processing time, the user experience is compromised as they will have to wait for the entire view to be processed before seeing anything on the screen.


To improve the user experience, it is possible to delay the processing of a referenced view.  So for example:


<div>
 <element view=”content.view1” mode=”XYZ”/>
</div>
<div>
 <element view=”content.view2” mode=”XYZ” load=”async”/>
</div>
<div>
 <element view=”content.view3” mode=”XYZ” load=”async”/>
</div>


The server will only process “content.view1” and send that to the client.  Only fter the main view and “content.view” have be been drawn, will the client make asynchronous requests for both “content.view2” and “content.view3” simultaneously.


This has two advantages:
  1. The user experience is improved because content will show up much more quickly as the server only has to process “content.view1”.  The views “content.view2” and “content.view3” are processed after “content.view1” is visible.
  2. The view in its entirety will load much more quickly because “content.view2” and “content.view3” will both be processed simultaneously by the server on two separate processes, making use of load balancing on the server


However, making a lot of heavy simultaneous requests all at once on the server could stress the server.  While desirable to process and receive the content as quickly as possible, it is not always necessary when the content is “below the fold” and falls below the cut-off at the bottom of the page, This problem can be solved with “sequence” loading.


<div>
 <element view=”content.view1” mode=”XYZ”/>
</div>
<div>
 <element view=”content.view2” mode=”XYZ” load=”sequence”/>
</div>
<div>
 <element view=”content.view3” mode=”XYZ” load=”sequence”/>
</div>


This will initially load only “content.view1” with the main view.  Once these are loaded, TACTIC will send a request for “content.view2” and once that is loaded, it will send another request for “content.view3” in sequence.  These views end up being loaded over time in sequence without the user really being aware that the content is missing until they scroll down.

Having control of how and when a page loads content improves the user experience.  Content immediately needed is loaded first and other content can be delayed.  Mixing and matching async loading and sequence loading provides a flexible means of loading heavy content views.

Thursday 22 September 2016

Using "tactic_load" and "tactic_popup" to dynamically load widgets

The TACTIC Custom Layout Editor is a key tool for building enterprise applications in TACTIC.  When building dynamic enterprise applications, dynamically loaded view or a custom widget make for a much better end user experience.  



Dynamic loading can be done with the javascript api function:


spt.panel.load(element, class_name, kwargs);


However, this function requires writing a full behavior with custom javascript code.  Using Javascript is necessary if some logic is required to determine what to load, but often one just needs to load a know widget with known keyword arguments.  This can be very easily achieved using custom html classes.  For example, to a load a view “customers.list”, one could just use the “tactic_load” class:


<div>
<input type=”button tactic_load” view=”customers.list” target=”content” value=”View Customers” />
<div class=”content”/>
</div>


This will create a button with the label “View Customers”.  When clicking, it will dynamically load the view “customers.list” into the “content” element.  This is a very simple way to create a dynamically loaded applications.  It is very useful for creating sidebars or menu items.


Sometimes arguments need to passed to this new view.  This is easily done by adding extra attributes to the html element


<input type=”button tactic_load” view=”customers.list” target=”content” search_type=”workflow/asset” value=”View Customers” />


This will add the “search_type” key with the value “workflow/asset” into the kwargs of the view “customer.list”.  This is very useful for configuring the usage of a widget that is to be loaded.  Even more powerful would be to make the value a variable that is determined in Python.
Similarly, the “tactic_popup” class will open up a popup with the corresponding widget.  This is often used to open up edit or insert widgets or to display some additional information.  

The use of these built-in classes make for a very powerful application building tool.   For a concrete example, this is how the TACTIC Portal loads most of its content.  Since these classes can open up any widget in TACTIC,  one can create complex dynamic applications very quickly.