Skip to content
PDF

Smart UI Tiles

Smart Pages enables an extended set of pre-built tiles to be available within the Smart View Perspective Manager tile library.

These can be added to perspectives just as any other out-of-the-box tile, and mixed & matched with other standard components.

Widget Library

Available Smart Page Tiles

The following tiles are available in the AnswerModules Module Suite section of the Widget Library:

  • Charts - Used to create data visualization charts
  • Links - Create a "menu" tile including a custom, dynamic list of links and actions
  • Tree - Display a dynamic, lazy-loaded tree structure that can be used to display or access hierarchical data
  • Content Script Node Table - Display an alternative version of the standard Node Browsing Table tile with customizable Content Script data source
  • News - Display a list of expandable, actionable news items
  • Tiles - An advanced version of the original Links Tile that allows for better usage of the screen space
  • Content Script Result - A general-purpose tile that can be used to inject any output generated by a Content Script Data source or a Smart Page

Tile Configuration

Module Suite tiles share some common configuration options, while other options are specific to single tiles.

Common Configuration Options

Common options include:

  • External frame configuration (header, scrolling content, title, icon)
  • Data Source configuration - All Module Suite tiles require a Content Script object that acts as a Data Source
  • Parameter passing - Additional parameters can be passed to the script and will be available in the params variable

Content Script Tile Configuration

  • Icon Configuration - When configuring the tile's icon, two different approaches are possible:

    1. CSS Style Class: Specify a CSS style class to apply to the icon element. This should define the rules needed to apply the desired icon.

    2. Module Suite Icon Set: Specify the name (and color scheme) of the desired icon among the ones available in the Module Suite icon set. See the Icon Reference Cheat Sheet for a full list of options.

  • Dynamic Configuration - Module Suite tiles are designed to dynamically load their configuration from the same data source that supplies their data. This process is initiated by invoking the data source prior to the tile's rendering. To identify requests for configuration-only data, the widgetConfig parameter is used. This parameter signals the data source that it's being called specifically for tile configuration.

    Considerations for Dynamic Configuration

    • Flexibility vs. Initial Load Time: While this feature offers increased flexibility, it does come with the trade-off of additional loading time for the initial data source call.
    • Optimized Data Source Responses: It's advisable to configure the data source in a way that recognizes when it's being called solely for configuration purposes. Implementing strategies such as caching mechanisms or the use of static data can significantly expedite the configuration delivery.

Content Script Data Sources

All Module Suite tiles require a Content Script object that will be executed when the tile content is created. This script acts as a Data Source for the tile, and allows to make its content dynamic.

The data source script receives:

  • params - A map containing all parameters passed from the tile configuration
  • widgetConfig - A boolean parameter indicating if the script is being called for configuration purposes

The script should return data in a format specific to the tile type being used.

Content Script Data Source Configuration

Tile Library Reference

Content Script Tile Chart

The Content Script Tile Chart is a tile who's purpose is to create interactive charts within the Smart View. The data shown in the charts will be provided by a Content Script data source.

Chart tiles leverage two different javascript libraries:

  • Chartist (supported for backward compatibility)
  • Chart.js (suggested)

Depending on the selected chart type, the appropriate configuration has to be provided in JSON format.

Tile Chart

def rand = new Random()

if(params.widgetConfig){

    json(widgetConfig:[
        reloadCommands:["updateChart"],
        html:"""


<small>Move the mouse over the chart for triggering data-reload</small>
<script>
    csui.onReady2([ 
        "csui/lib/jquery", 
        "csui/lib/underscore", 
        "csui/lib/radio"], 
                function(jQ, _, Radio){

                    //Get the page message bus
                    var amChannel  = Radio.channel('ampagenotify');

                    //Get the chart
                    var chart = amChannel.request("ampages:myChart");

                    var canvas = jQ("#myChart");
                    canvas.unbind("click");
                    canvas.on("click", function (evt) {
                        var activePoints = chart.getElementsAtEvent(evt);
                        var vals = _.map(_.pluck(_.filter(chart.legend.legendItems, function(it){ return it.hidden==false}), "text"), function(value){ return value;}).join("|");
                        if(!_.isUndefined(activePoints[0])){
                        var chartData = activePoints[0]['_chart'].config.data;
                        var idx = activePoints[0]['_index'];

                        var label = chartData.labels[idx];
                        var value = chartData.datasets[0].data[idx];     
                        amChannel.trigger("updateChart", [ {name:"where_type", value:label} ]);

                    } else {
                        amChannel.trigger("updateChart", [ {name:"where_type", value:vals} ]);
                    }
                    });


                    canvas.hover(function(){
                        var self = jQ(this);
                        //jQ(".myChartLoader").removeClass("binf-hidden");
                        amChannel.trigger("updateChart", [{name:"filter", value:"first"}]);
                    });
                });
</script>"""
    ])
}else{

    json([

        type:"bar",
        data: 
        [

            labels: ["red", "green"],
            datasets: [

                [
                    label: "My First dataset",
                    backgroundColor: "${AMBWFWidgetsLib.getBehaviour("ambwf","generateRandomHTMLColor", this)(rand)}",
                    borderColor: "${AMBWFWidgetsLib.getBehaviour("ambwf","generateRandomHTMLColor", this)(rand)}",
                    data: [rand.nextInt(100), rand.nextInt(100)],

                ],
                [
                    label: "My Second dataset",
                    borderColor: "${AMBWFWidgetsLib.getBehaviour("ambwf","generateRandomHTMLColor", this)(rand)}",
                    backgroundColor: "${AMBWFWidgetsLib.getBehaviour("ambwf","generateRandomHTMLColor", this)(rand)}",
                    data: [ rand.nextInt(100), rand.nextInt(100)],

                ]
            ]
        ],
        options: [
            maintainAspectRatio: false,
            title: [
                display: true,
                text: 'myChart',
                position: 'left'
            ],
            legend: [
                display: true,
                position: 'top'
            ],
            scales: [
                yAxes: [
                    [
                        ticks: [
                            beginAtZero:true
                        ]
                    ]
                ]
            ]
        ]
    ])
}

Content Script Tile Tiles

The Content Script Tile Tiles is a tile meant to create a customizable list of clickable links and HTML Tiles. The data controlling the links is provided by the backing Content Script data source.

Tile Links

    app = runCS("am_businessCompliance")
    if( params.widgetConfig ){
        json( widgetConfig : [
            reloadCommands : [ "updateTiles" ], // The widget will be refreshed when this command is executed
            html : """
                <link type="text/css" rel="stylesheet" data-csui-required="true" href="${app.config.static.tilesCss}">
                <script>
                csui.onReady2([
                    'csui/lib/jquery',
                    'csui/lib/underscore',
                    'csui/lib/marionette',
                    'csui/lib/radio',
                    'csui/utils/commands',
                    'csui/controls/side.panel/side.panel.view',
                    'csui/controls/tile/behaviors/perfect.scrolling.behavior',
                    'anscontentSmart View/utils/contexts/factories/scriptjsonresult.model.factory'
                    ],
                    function (jQ, _, Marionette, Radio, CommandsRegistry, SidePanelView, PerfectScrollingBehavior, ContentScriptModelFactory) {
                        var ContentView = Marionette.View.extend({
                            constructor: function ContentView(options) {
                                this.widgetConfig = options.widgetConfig || {};
                                this.options = options;
                                Marionette.View.prototype.constructor.apply(this, arguments);
                            },
                            className: 'anscontentSmart View-tile-content-script',
                            render: function () {
                                var source;
                                if (this.model) {
                                    source = this.model.get('cssource');
                                    if (!_.isUndefined(source)) {
                                        var self = this;
                                        csui.require(['csui/lib/jquery'], function (jQ) {
                                            jQ(self.\$el).html(source);
                                        });
                                    }
                                }
                                return this;
                            },
                            className: 'amsui-exp-content-script',
                            behaviors: {
                                PerfectScrolling: {
                                    behaviorClass: PerfectScrollingBehavior,
                                    contentParent: ".am-Smart View",
                                    suppressScrollX: true,
                                    scrollYMarginOffset: 15,
                                    scrollingDisabled: false
                                }
                            }
                        });

                        // Get the page message bus
                        var amChannel = Radio.channel('ampagenotify');
                        amChannel.off("tiles_action");
                        amChannel.on("tiles_action", function (action, param) { //action = panel|1234|My Title|80
                            if( action.startsWith('panel') ){
                                var scriptID   = undefined;
                                var title      = "Action Panel";
                                var panelWidth = 80;
                                var params     = undefined; 
                                if( action.includes("|") ){
                                    var tokens = action.split('|')
                                    if( tokens.length >= 2){
                                        if(jQ.isNumeric( tokens[1] )){ //panel|1234...
                                            scriptID = tokens[1];
                                            params = param;
                                            if( tokens.length >= 3){
                                                if(jQ.isNumeric( tokens[2] )){ //panel|1234|80
                                                    panelWidth = tokens[2];         
                                                }else{ //panel|1234|My Title
                                                    title = _.escape(tokens[2]);
                                                    if( tokens.length >= 4){
                                                        if(jQ.isNumeric( tokens[3] )){ //panel|1234|My Title|80
                                                            panelWidth = tokens[3];
                                                        }
                                                    }
                                                }
                                            }
                                        }else{
                                            //panel|My title...
                                            title = _.escape(tokens[1]);
                                            if( tokens.length >= 3){ 
                                                if(jQ.isNumeric( tokens[2] )){ //panel|My Title|80
                                                    panelWidth = tokens[2];         
                                                }
                                            }
                                        }
                                    }
                                    if( scriptID === undefined ){
                                        scriptID = param;
                                    }
                                } 

                                if( jQ.isNumeric( scriptID ) ){
                                    var context = amChannel.request("ampages:pageContext");
                                    var scriptAttrs = { source: scriptID };
                                    var script = context.getModel(ContentScriptModelFactory, { attributes: scriptAttrs });
                                    if(params != undefined){
                                        script.attributes.parameters = [{ name: "actionParams", value: params }];
                                    }
                                    var slides = [
                                        {
                                            title   : title,
                                            content : new ContentView({ model: script })
                                        }
                                    ];
                                    script.fetch().then(function () {
                                        var dialog = new SidePanelView(_.extend({
                                            sidePanelClassName : "amsui-Smart View-slide-panel-"+panelWidth+"vw",
                                            openFrom           : "right",
                                            slides             : slides
                                        }));

                                        dialog.show();
                                        amChannel.on("tiles_panel:hide", function () {
                                                dialog.hide();
                                        });
                                    });
                                } else {
                                    console.log("Error opening panel - invalid settings.")
                                }
                            };
                        });
                    });
                </script>
                <style>
                .binf-widgets [data-csui-widget_type=tilelinkstiles_content_script] .am-tile-content{
                    padding-right: 15px;
                }
                </style>
                """ ])
    } else {

        json(
            data : [
                styleclass : "myStyleClass",
                rows : [
                    [   // First row
                        styleclass : "",
                        size : 1, // The relative height of this row compared to other rows (default : 1)
                        tiles : [
                            [ // First Tile
                                size       : 1, // The relative size of this tile compared to others in the row (default : 1)
                                styleclass : "",
                                html : """<div class="showcase-tiles-heading"> 
                                        <div class="showcase-tiles-heading-main">Third party due diligence</div>
                                        <div style="font-size: 0.6em;">Process to manage the engagement, monitoring and payment of third parties</div>
                                        </div>
                                        """
                            ]
                        ]
                    ],
                    [   //Empty Row
                        styleclass : "myStyleClass",
                        size : 1, // The relative height of this row compared to other rows (default : 1)
                        tiles : [
                            [ // First Tile
                                size       : 1, // The relative size of this tile compared to others in the row (default : 1)
                                styleclass : "myStyleClass",
                                html : """<div class="showcase-tiles-section"></div>"""
                            ]
                        ]
                    ],
                    [  
                        styleclass : "",
                        size : 1, // The relative height of this row compared to other rows (default : 1)
                        tiles : [
                            [ 
                                size       : 1, // The relative size of this tile compared to others in the row (default : 1)
                                styleclass : "",
                                html : """<div class="showcase-tiles-section" style="text-align: left; padding-left: 18px; font-size: 1em;">
                                            The Business Compliance process has been implemented as a case management application.
                                            It is intended to demonstrate how it is possible to manage a Business Compliance process by 
                                            integrating a Connected Workspace, representing a third party, with a list of tasks for managing the
                                            different steps such as assessment, engagement, monitoring and payment of the above, in accordance with
                                            internal regulatory requirements.
                                        </div>"""
                            ]
                        ]
                    ],
                    [
                        size : 3,
                        tiles : [
                            [   // First Tile
                                size : 1,
                                type : 'red', // Available types: red, green, blue, orange, teal, gold, purple
                                front : [
                                    icon : "${img}anscontentSmart View/app/image/icons/windows10/white/risk_assesment.svg",
                                    body : """3""",
                                    body_text_align : 'right', // left, center, right (default)
                                    body_text_size : 'jumbo', // small (90%), normal (100%), large (200%), jumbo (300%)
                                    title : "Late Tasks"
                                ],
                                back : [
                                    icon : "${img}anscontentSmart View/app/image/icons/windows10/white/task.svg",
                                    title : "Late Tasks",
                                    body_text_align : 'center',
                                    body : """Potuit, iam districtum mucronem in proprium latus inpegit. hocque deformi genere mortis excessit e vita iustissimus 
                                            rector ausus miserabiles casus levare multorum. hinc ille commotus ut iniusta perferens et indigna praefecti 
                                            custodiam protectoribus mandaverat fidis."""
                                ]
                            ],
                            [   // Second Tile
                                size : 1,
                                type : 'green', // Available types: red, green, blue, orange, teal, gold, purple
                                front : [
                                    icon : "${img}anscontentSmart View/app/image/icons/windows10/white/public_private_company.svg",
                                    body : """9""",
                                    body_text_align : 'right', // left, center, right (default)
                                    body_text_size : 'jumbo', // small (90%), normal (100%), large (200%), jumbo (300%)
                                    title : "Active Processes"
                                ],
                                back : [
                                    icon : "${img}anscontentSmart View/app/image/icons/windows10/white/task.svg",
                                    title : "Active Processes",
                                    body_text_align : 'center',
                                    body : """<table class="binf-table binf-table-condensed">
                                                <thead>
                                                    <tr>
                                                        <th>First Col</th>
                                                        <th>Second Col</th>
                                                    </tr>
                                                </thead>
                                                <tbody>
                                                    <tr>
                                                        <td>Some Data</td>
                                                        <td>Other Data</td>
                                                    </tr>
                                                </tbody>
                                            </table>"""
                                ]
                            ],
                        ]
                    ],
                    [
                        size : 3,
                        tiles : [
                            [   
                                size : 1,
                                type : 'teal', // Available types: red, green, blue, orange, teal, gold, purple
                                front : [
                                    icon : "${img}anscontentSmart View/app/image/icons/windows10/white/flag.svg",
                                    body : """254""",
                                    body_text_align : 'right', // left, center, right (default)
                                    body_text_size : 'large', // small (90%), normal (100%), large (200%), jumbo (300%)
                                    title : "Registered Third Parties"
                                ],
                                back : [
                                    icon : "${img}anscontentSmart View/app/image/icons/windows10/white/flag.svg",
                                    title : "Registered Third Parties"
                                ]
                            ],
                            [   
                                size : 1,
                                type : 'orange', // Available types: red, green, blue, orange, teal, gold, purple
                                front : [
                                    icon : "${img}anscontentSmart View/app/image/icons/windows10/white/task.svg",
                                    body : """42""",
                                    body_text_align : 'right', // left, center, right (default)
                                    body_text_size : 'jumbo', // small (90%), normal (100%), large (200%), jumbo (300%)
                                    title : "Open Tasks"
                                ],
                                back : [
                                    icon : "${img}anscontentSmart View/app/image/icons/windows10/white/task.svg",
                                    title : "Open Tasks"
                                ]
                            ],
                        ]
                    ],
                    [   
                        styleclass : "myStyleClass",
                        size : 1, // The relative height of this row compared to other rows (default : 1)
                        tiles : [
                            [ // First Tile
                                size       : 1, // The relative size of this tile compared to others in the row (default : 1)
                                styleclass : "myStyleClass",
                                html : """<div class="showcase-tiles-section"> Actions </div>"""
                            ]
                        ]
                    ],
                    [
                        size : 0,
                        tiles : [ 
                            [
                                size : 12,
                                styleclass : "",
                                command : "tiles", // Custom command
                                action : "panel|Register New Third-Party|60", 
                                params : app.config.pages.caseNew, //The action's parameter
                                newtab : false,
                                type : 'green',
                                front : [
                                    icon : "${app.config.static.resourcesPath}add.svg",
                                    body : "Start Business Compliance Process",
                                ]
                            ]
                        ]
                    ],
                    [
                        size : 0,
                        tiles : [ 
                            [
                                size : 12,
                                styleclass : "",
                                command : "cases", // Custom command
                                action : "z_changeMode", 
                                params : "grid", //The action's parameter
                                newtab : false,
                                type : 'green',
                                front : [
                                    icon : "${img}anscontentSmart View/app/image/icons/windows10/white/report2.svg",
                                    body : "Business Compliance List",
                                    //title : "Analytics"
                                ]
                            ]
                        ]
                    ],
                    [
                        size : 0,
                        tiles : [ 
                            [
                                size : 12,
                                styleclass : "",
                                command : "cases", // Custom command
                                action : "z_changeMode", 
                                params : "stats", //The action's parameter
                                newtab : false,
                                type : 'green',
                                front : [
                                    icon : "${img}anscontentSmart View/app/image/icons/windows10/white/stats_line_chart.svg",
                                    body : "Analytics",
                                    //title : "Analytics"
                                ]
                            ]
                        ]
                    ],
                    [
                        size : 0,
                        tiles : [ 
                            [
                                size : 12,
                                styleclass : "",
                                command : "cases", // Custom command
                                action : "z_changeMode", 
                                params : "kaban", //The action's parameter
                                newtab : false,
                                type : 'green',
                                front : [
                                    icon : "${img}anscontentSmart View/app/image/icons/windows10/white/diversity.svg",
                                    body : "Business Compliance By Status",
                                ]
                            ]
                        ]
                    ],
                    [
                        size : 0,
                        tiles : [ 
                            [
                                size : 12,
                                styleclass : "",
                                command : "cases", // Custom command
                                action : "z_changeMode", 
                                params : "conf", //The action's parameter
                                newtab : false,
                                type : 'green',
                                front : [
                                    icon : "${app.config.static.resourcesPath}settings.svg",
                                    body : "Configuration",
                                ]
                            ]
                        ]
                    ],
                    //Empty
                    [   
                        styleclass : "myStyleClass",
                        size : 1, // The relative height of this row compared to other rows (default : 1)
                        tiles : [
                            [ 
                                size       : 1, // The relative size of this tile compared to others in the row (default : 1)
                                styleclass : "myStyleClass",
                                html : """<div class="showcase-tiles-section"></div>"""
                            ]
                        ]
                    ],
                ]
            ]
        )
    }

The Content Script Tile Links is a tile meant to create a customizable list of clickable links. The data controlling the links is provided by the backing Content Script data source.

Tile Links

    if(params.widgetConfig){

        json(widgetConfig:[
            reloadCommands:["updateLinks"],
            html:"""

    <style>
    div.ans-tile-content-linkstiles{
        background: linear-gradient(180deg, #122c69 0%, #078db3 100% );
        color:#fff;
        height:100%;
    }

    div.ans-tile-content-linkstiles > div.binf-list-group > a:nth-child(2),
    div.ans-tile-content-linkstiles > div.binf-list-group > a:nth-child(6),
    div.ans-tile-content-linkstiles > div.binf-list-group > a:nth-child(10){
        background:#00639b;
        color:#fff;
        border-radius:0px;
    }
    div.ans-tile-content-linkstiles > div.binf-list-group > a:nth-child(3),
    div.ans-tile-content-linkstiles > div.binf-list-group > a:nth-child(7),
    div.ans-tile-content-linkstiles > div.binf-list-group > a:nth-child(11){
        background:#df3324;
        color:#fff;
        border-radius:0px;
    }
    div.ans-tile-content-linkstiles > div.binf-list-group > a:nth-child(4),
    div.ans-tile-content-linkstiles > div.binf-list-group > a:nth-child(8),
    div.ans-tile-content-linkstiles > div.binf-list-group > a:nth-child(12){
        background:#008485;
        color:#fff;
        border-radius:0px;
    }

    </style>
    <div style="padding:20px; background-color:white;margin-bottom:10px;color:#333" >
    Click on the differnt links to see them in action.
    </div>
    <script>
        csui.onReady2([    'csui/lib/underscore',
            'csui/lib/backbone',
            'csui/lib/jquery',
            'csui/lib/radio'], 
            function(_,Backbone, jQ, Radio){
                var amChannel = Radio.channel("ampagenotify");
                amChannel.on("smartPage_action", function(action,param){
                    console.log("GOT Page Action request. Action: "+action+ " parameter: "+param);
                });

            });
    </script>
    """
        ])
    }else{

        retVal = 
            [
                data:[
                    links:[
                        [
                            issection:true,
                            name:"First Section",
                        ],
                        [
                            issection:false,
                            icon:"csui-icon-home",
                            name:"First Link (Navigate)",
                            desc:"More information for this link",

                            url:"#", //If action != null url must be set equal to #
                            action:"navigate", //Will trigger a browse action of the current view
                            params:"2000", //The DataID of the node you wanto to navigate to 

                        ],
                        [
                            issection:false,
                            icon:"icon-tileExpand icon-perspective-open",
                            name:"Duplicate (Action)",

                            url:"#", //If action != null url must be set equal to #
                            action:"notify", //Will trigger the execution of the command below
                            command:"updateLinks", //The action to execute
                            params:"duplicate", //The action's parameter, this value will be passed to the script in a parameter named "tile"

                        ],
                        [
                            issection:false,
                            icon:"icon-socialFavOpen",
                            name:"Notify Smart Page (Page Action)",

                            url:"#", //If action != null url must be set equal to #
                            command:"smartPage", //The SmartPage(s) to notify
                            action:"updatePage",   //The action to execute
                            params:"2000" //The action's parameter

                        ],
                        [
                            issection:false,
                            am_icon:"am_icon_link",
                            am_icon_schema:"am_icon_green",
                            name:"Simple link",

                            url:"http://www.answermodules.com",
                            newtab:true

                        ]

                    ]
                ]
            ]

        if(params.tile == "duplicate"){
            retVal.data.links += retVal.data.links[-5].clone()
            retVal.data.links += retVal.data.links[-5]
            retVal.data.links += retVal.data.links[-5]
            retVal.data.links += retVal.data.links[-5]

            retVal.data.links[-4].name = "Second Section"
        }else if(params.tile == "triple"){
            retVal.data.links += retVal.data.links[-5].clone()
            retVal.data.links += retVal.data.links[-5]
            retVal.data.links += retVal.data.links[-5]
            retVal.data.links += retVal.data.links[-5]

            retVal.data.links[-4].name = "Second Section"

            retVal.data.links += retVal.data.links[-4].clone()
            retVal.data.links += retVal.data.links[-4]
            retVal.data.links += retVal.data.links[-4]
            retVal.data.links += retVal.data.links[-4]

            retVal.data.links[-4].name = "Third Section"
        }

        json(
            retVal
        )


    }

Content Script Tile Tree

The Content Script Tile Tree creates an interactive tree structure with nodes that can be expanded and collapsed. The tree structure uses a Content Script data source for the initial data and for subsequent ajax data load calls.

Tile Tree

    if(params.widgetConfig){
        json( [ id           : 2,
            widgetConfig : [
                tileLayoutClasses  : "", 
                tileContentClasses : "", 
                reloadCommands     : ["updateTree"],
                root               : 2000, 
                plugins            : [ "wholerow" ],
                theme              : [ 'name': 'proton',
                                        'responsive': true ],
                html               : """
    <style>
    div.ans-tile-tree{
    background: linear-gradient(180deg, #122c69 0%, #078db3 100% );
    color:#fff;
    height:calc(100vh - 222px);
    font-size:13px !important;
    }
    .binf-widgets .jstree-proton .jstree-icon.csui-icon-node-task {
    background-image:url('${img}csui/themes/carbonfiber/image/icons/mime_task.svg')
    }
    .binf-widgets .jstree-proton .jstree-icon.mime_pdf{
    background-image:url('${img}csui/themes/carbonfiber/image/icons/mime_pdf.svg')
    }
    .jstree-anchor small{
    font-size:.9em;
    font-style:italic;
    }
    </style>
    <div class="am-form-text-input" style="margin-top: 1px;padding: 5px 0px;">
        <label class=" control-label col-form-label am-form-text-input-label   am-form-label-top" style="padding: 5px;">Filter tree</label>
        <div class="am-form-input-wrap" style="padding: 0 5px;">
            <input id="filter" type="text" placeholder="" class="form-control" style="border-radius: 0px;box-shadow: none;">
        </div>
    </div>

    <script>
        csui.onReady2([    'csui/lib/underscore',
            'csui/lib/backbone',
            'csui/lib/jquery',
            'csui/lib/radio'], 
            function(_,Backbone, jQ, Radio){
                var amChannel = Radio.channel("ampagenotify");
                amChannel.on("printConsole", function(params){
                    console.log("GOT request "+JSON.stringify(params));
                });
                amChannel.on("smartPage_action", function(action,param){
                    console.log("GOT Page Action request. Action: "+action+ " parameter: "+param);
                });
                jQ("#filter").on("blur", function(){
                    amChannel.trigger("updateTree",{'term':jQ(this).val()})
                })  

            });
    </script>"""
            ]
            ] )
        return
    }

    data =

        [
            [

                icon     : "csui-icon cs_vfolder", //mime_folder, cs_folder_root, cs_vfolder, cs_folder_open...
                id       : 1,
                text     : "Roots",
                children :  [
                    [
                        action   : "navigate", //Trigger a Smart View navigation
                        icon     : "csui-icon cs_folder_root", //cs_folder_root, cs_vfolder, cs_folder_open
                        id       : 2000, //The node will be used as the action's parameter
                        text     : "Home",
                        children : false
                    ]

                ],
                state       : [
                    opened    : true
                ] 
            ],
            [

                action   : "printConsole", //Trigger a Tile action
                params   : "3", //This value will be passed to the script in a parameter named 'tile'
                icon     : "csui-icon mime_folder",
                id       : 3,
                text     : "Folder (Lazy Loaded)",
                children : true,
                state       : [
                    opened    : false
                ] 
            ]
        ]


    if(params.uiParentID == "3"){
        data[1].children = [
            [

                icon     : "csui-icon mime_folder",
                id       : 4,
                text     : "Sub Folder",
                children : [
                    [
                        notify   : "smartPage",    //Triggers a Smart Page action noifying the provided page(s) (CSV)
                        action   : "customAction", //The action to execute
                        params   : "2000",         //The action's parameter
                        icon     : "csui-icon mime_pdf",
                        id       : 5,
                        text     : "Notify Smart Page",
                        children : false
                    ],
                    [
                        action   : "printConsole",
                        params   : "2000",
                        icon     : "csui-icon mime_pdf",
                        id       : 6,
                        text     : "Execute Action",
                        children : false
                    ]

                ]
            ]

        ]
    }
    if(params.term){
        data = data.findAll{it.text.startsWith(params.term)}
    }
    json(data)

Content Script Node Table

The Content Script Node Table is an enhancement of the standard Node Table tile. The tile uses a Content Script as data source, allowing to set up any custom business logic to generate the list of nodes to be shown.

Tile Node Table

    def targetSpaceFilter = 2000


    def subtypeFilter = "144".split(",") 

    if(params.widgetConfig){
        json([
        widgetConfig:[
            reloadCommands:[ "updateData" ],
            columnsWithSearch:[ "Owner", "Name" ]
        ]
        ])
        return 
    }

    if(params.page?.contains("_") && params.page_list){
        if(params.page_list[0].contains("_") && !params.page_list?[1]?.contains("_")){
            params.page = params.page_list[1]
        }else if(!params.page_list[0].contains("_") && params.page_list?[1]?.contains("_")){
            params.page = params.page_list[0]
        }
    }

    def paging = [actual_count:0, 
                limit:((params.limit?:"30") as int), 
                page:((params.page?:"1") as int), 
                page_total:0, 
                range_max:0, 
                range_min:0, 
                total_count:0, 
                total_row_count:0, 
                total_source_count:0]

    def pageSize = paging.limit
    def offset = (paging.limit * (paging.page - 1))
    def firstRow = offset + 1
    def lastRow = firstRow + paging.limit

    nodes = []

    def nameFilter = null
    if( params.where_name ){
        nameFilter = "%${params.where_name}%"
    }

    def ownerFilter = null
    if( params.where_owner ){
        ownerFilter = "%${params.where_owner}%"
    }

    def sortingOrderParam     = 'desc'
    def sortingColumnParam     = 'name'

    def sortingOrder     = 'DESC'
    def sortingColumn     = 'DTree.Name'


    if( params.sort && params.sort.contains('_') ){

        def sorting = params.sort.split('_')

        sortingOrderParam     = sorting[0]
        sortingColumnParam     = sorting[1]

        sortingOrder = ( sortingOrderParam == 'asc' ) ? 'ASC' : 'DESC'


        switch( sortingColumnParam?.trim() ){

            case 'name' :
                sortingColumn = 'DTree.Name'
                break

            case 'owner' :
                sortingColumn = 'KUAF.ID'
                break

            default :
                sortingColumn = 'DTree.Name'
                break
        }

    }


    try{


        def queryParams = [targetSpaceFilter as String]
        def queryIndex = 1

        def permExpr = "(exists (select DataID from DTreeACL aclT where aclT.DataID=DTree.DataID and ${users.getRightsStringForSQL("RightID", false)} and See >1 ))"


        sqlCode = """ select DTree.DataID "DID", 
                            DTree.Name "NAME", 
                            COUNT(*) OVER() as "overall_count" 

                        from DTree 
                        LEFT JOIN KUAF ON DTree.UserID = KUAF.ID

                        where DTree.ParentID = %1 """

        if(subtypeFilter.size() == 1){
            sqlCode += " and DTree.SubType = %${++queryIndex} "
            queryParams << (subtypeFilter[0] as long)
        } else if( subtypeFilter.size() > 1 ) {
            sqlCode += " and DTree.SubType IN (${subtypeFilter.join(',')}) "
        }

        if(nameFilter){
            sqlCode += " and DTree.Name LIKE %${++queryIndex} "
            queryParams << (nameFilter as String)
        }

        if(ownerFilter){
            sqlCode += " and (KUAF.Name LIKE %${++queryIndex} OR KUAF.LastName LIKE %${queryIndex} ) "
            queryParams << (ownerFilter as String)
        }

        if(!users.current.canAdministerSystem){
            sqlCode += " and ${permExpr} "
        }

        sqlCode += """
                    ORDER BY ${sortingColumn} ${sortingOrder}
                        OFFSET ${offset} ROWS
                        FETCH NEXT ${pageSize} ROWS ONLY

                    """



        def queryResults

        if(queryParams){
            queryResults =  sql.runSQLFast(sqlCode, true, true, 100, *queryParams).rows
        } else {
            queryResults =  sql.runSQLFast(sqlCode, true, true, 100 ).rows
        }   

        def totalCount = (queryResults) ? queryResults[0].overall_count : 0

        nodes = queryResults?.collect{it.DID as Long}



        paging << [
                actual_count:totalCount, 
                page_total:((totalCount%paging.limit)+1),
                range_min:paging.page*paging.limit-paging.limit+1,
                range_max:(paging.limit*(paging.page+1)-totalCount)>0?(paging.limit*(paging.page+1)-totalCount):paging.limit*(paging.page+1),
                total_count:totalCount, 
                total_row_count:totalCount, 
                total_source_count:totalCount]

    }catch(e){
        log.error("Error loading nodes table data",e)
        printError(e)
    }



    def drawStatusBar = { node ->

        def statusList = ['Draft', 'Under Revision', 'Approved', 'Published']
        def numSteps = statusList.size()
        def currStep = new Random().nextInt(statusList.size())
        def currStepName = statusList[currStep]


        def stepStyle = "height:100%; width:calc(100% / ${numSteps}); float:left; background-color:#F0AD4E; box-sizing:border-box;"

        def stepsHtml = ""

        (currStep + 1).times{
            stepsHtml += """<span style="${stepStyle}"></span>"""
        }


        return """ 
        <div style="text-align:center; font-size:.75em">${currStepName}</div>
        <div style="margin:3px 0; padding:0; height:5px; background-color:#eee;">${stepsHtml}</div>"""
    }



    def slurper = new JsonSlurper()

    def processNode = { node, myNode ->

        /* Add your custom node post-processing here */

        //def myNode = asCSNode(node?.data.properties.id as long)

        node.data.amcsproxy =  [
            columns: [:],
            commands:[] 
        ]

        //Add custom column: node.data.amcsproxy.colums.sample_column = "My custom Value"

            def owner = myNode.createdBy
            def ownerBox = "<span><img src='/otcs/cs.exe/pulse/photos/userphoto/${owner.ID}/2000' style='max-height: 3em; border-radius: 50%; margin-right: 5px; vertical-align: middle;' /> ${owner.displayName}</span>"
            node.data.amcsproxy.columns.owner = ownerBox

        node.data.amcsproxy.columns.comment = myNode.comment 
        node.data.amcsproxy.columns.statusBar = drawStatusBar( myNode ) 

        return node
    }

    results = []

    def fields = JsonOutput.toJson( [
        'actions': [ 'fields': [] ],
        'properties': [ 'fields': [] ],
        'versions': [ 'fields': [] ],
        'amcsproxy': [ 'fields': [] ],
    ])

    //Identifies actions to be displayed for every node
    //Node actions are return together with data request thay may lead to additinal response time
    // [] - docman.getNodesRestV2JSon will not process actions. 
    //      Actions will be processed on a separate call based on the list provided (see returned json object at the end of this script)
    // null - default list of actions will be returned
    // ['open','properties','copy','move','edit'] - sample list of actions
    // To ideal actions processing requires you to assign an empty list (see below) to the nodesActions variable below and pass the list of commands to be retrived
    // using the 'actions' list property of the json object returned by this script (see last line)
    def nodesActions = [] 

    if( nodes.size() > 1 ){
        log.error("Nodes ${nodes}")
        temp = slurper.parseText( docman.getNodesRestV2JSon(nodes, fields, '{"properties":{"fields":["parent_id"]}}', false, false, nodesActions) )
        theNodes = docman.getNodesFastWith(nodes, [], params, false, false, false)
        nodes.each{ node ->

            def jsonNode = temp.find{ it.data.properties.id == node }
            results << processNode(jsonNode, theNodes.find{it.ID == node}  )
        }


    } else if (nodes.size() == 1 ){

        it = slurper.parseText(docman.getNodesRestV2JSon(nodes, fields, '{"properties":{"fields":["parent_id"]}}', false, false, nodesActions))
        processNode(it, docman.getNodeFast(nodes[0])) 

        results = [it]
    }




    def columns = [

        type: [
                key:"type",
                name:"Type",
                type:2,
                type_name:"Integer",
                sort:false
            ]

        ,name: [
                key:"name",
                name:"Name",
                type:-1,
                type_name:"String",
                sort:true,
                align:"left"
            ]

        ,owner: [
                key:"owner",
                name:"Owner",
                type:43200,
                type_name:"String",
                sort:true,
                align:"left"
            ]

        ,statusBar: [
                key:"statusBar",
                name:"Doc. Status",
                type:43200,
                type_name:"String",
                sort:false,
                align:"left"
            ]

        ,comment: [
                key:"comment",
                name:"Comment",
                type:-1,
                type_name:"String",
                sort:false,
                align:"left"
            ]
    ]


    // actions - list of commands defined for all the nodes listed in the page
    // action=[] - will return all possible actions for a node
    json(
        [
        paging:paging,
        columnsWithSearch:[ "name" , "owner" ], 
        results:results, 
        columns:columns, 
        tableColumns:columns,
        widgetConfig:[
            reloadCommands:[ "updateData" ]
        ],
        actions: ['open','properties','copy']
    ]
    )

Content Script Result

The Content Script Result is a general-purpose tile that can be used to inject any output generated by a Content Script Data source or a Smart Page into a SmartUI perspective.

Content Script Result Example

Icon Reference Cheat Sheet

Iconset Color Codes

Module Suite icons are available in the following colors:

Icons Colors

All Icons

A complete list of the currently available icons is shown below:

Icons Reference

Next Steps