diff --git a/conf/requirements-latest.pip b/conf/requirements-latest.pip
index b1b7b6774d0dea5ff04d8fbde59e0e3dbf0bbb16..407a971a95ec73e56bf5cca3b08443e34e5192f6 100644
--- a/conf/requirements-latest.pip
+++ b/conf/requirements-latest.pip
@@ -17,6 +17,7 @@ flask-wtf
 flask-script
 flask-sqlalchemy
 flask-debugtoolbar
+flask-jsglue
 geoip2
 rrdtool
 pydgets
diff --git a/conf/requirements.pip b/conf/requirements.pip
index 3f390a6510f93d15dd38a793d4f183aa164cd39b..1b439cee8c89311a17f15448160683ae9b256d97 100644
--- a/conf/requirements.pip
+++ b/conf/requirements.pip
@@ -17,6 +17,7 @@ flask-wtf==0.14.2
 flask-script==2.0.6
 flask-sqlalchemy==2.3.2
 flask-debugtoolbar==0.10.1
+flask-jsglue==0.3.1
 geoip2==2.9.0
 rrdtool==0.1.14
 pydgets==0.9
diff --git a/lib/hawat/app.py b/lib/hawat/app.py
index ea4b0921ace27bfc560eab6c5bb7bb203cc09e30..3648819e4c133fb60b07e760dc8dce910854153e 100644
--- a/lib/hawat/app.py
+++ b/lib/hawat/app.py
@@ -37,6 +37,7 @@ import flask_login
 import flask_principal
 import flask_mail
 import flask_babel
+import flask_jsglue
 
 #
 # Custom modules.
@@ -154,6 +155,7 @@ def _setup_app_core(app):
             hawat_version           = mentat.__version__,
             hawat_bversion          = mentat._buildmeta.__bversion__,  # pylint: disable=locally-disabled,protected-access
             hawat_bversion_full     = mentat._buildmeta.__bversion_full__,  # pylint: disable=locally-disabled,protected-access
+            hawat_current_app       = flask.current_app,
             hawat_current_menu_main = flask.current_app.menu_main,
             hawat_current_menu_auth = flask.current_app.menu_auth,
             hawat_current_menu_anon = flask.current_app.menu_anon,
@@ -177,7 +179,6 @@ def _setup_app_core(app):
         get_datetime_local
             Reference for :py:func:`hawat.app.get_datetime_local`
         """
-
         def get_endpoints_dict():
             """
             Return dictionary of all registered application view endpoints.
@@ -420,6 +421,21 @@ def _setup_app_core(app):
         """
         return flask.render_template('index.html')
 
+    @app.route('/hawat-main.js')
+    def mainjs():  # pylint: disable=locally-disabled,unused-variable
+        """
+        Default route for main application JavaScript file.
+        """
+        return flask.make_response(
+            flask.render_template('hawat-main.js'),
+            200,
+            {'Content-Type': 'text/javascript'}
+        )
+
+    # Initialize JSGlue plugin for using `flask.url_for()` method in JavaScript.
+    jsglue = flask_jsglue.JSGlue()
+    jsglue.init_app(app)
+
     return app
 
 
diff --git a/lib/hawat/base.py b/lib/hawat/base.py
index ada0ec1863b16e8f6bdb8135851d672595085378..6e958e3fa4423203fd439607da65170a28625b03 100644
--- a/lib/hawat/base.py
+++ b/lib/hawat/base.py
@@ -100,7 +100,7 @@ class URLParamsBuilder:
         This class is still proof of concept and work in progress.
     """
     def __init__(self, skeleton = None):
-        self.rules = {}
+        self.rules    = []
         self.skeleton = skeleton or {}
 
     @staticmethod
@@ -116,9 +116,9 @@ class URLParamsBuilder:
         Add new rule to URL parameter builder.
         """
         if as_list:
-            self.rules[key] = self._add_vector
+            self.rules.append([key, self._add_vector, as_list])
         else:
-            self.rules[key] = self._add_scalar
+            self.rules.append([key, self._add_scalar, as_list])
         return self
 
     def get_params(self, value):
@@ -126,8 +126,8 @@ class URLParamsBuilder:
         Get URL parameters as dictionary with filled-in value.
         """
         tmp = copy.deepcopy(self.skeleton)
-        for key, rule in self.rules.items():
-            rule(tmp, key, value)
+        for rule in self.rules:
+            rule[1](tmp, rule[0], value)
         return tmp
 
 
diff --git a/lib/hawat/blueprints/design/static/js/hawat-charts.js b/lib/hawat/blueprints/design/static/js/hawat-charts.js
index 1067118b832442950a5efca9c0aeb56af542416d..3ff79b8dc46ee3da4a2ed12fb332d6481635b01a 100644
--- a/lib/hawat/blueprints/design/static/js/hawat-charts.js
+++ b/lib/hawat/blueprints/design/static/js/hawat-charts.js
@@ -425,8 +425,43 @@ function render_table_timeline_multi(tid, table_columns, table_data, data_stats)
 	return table;
 }
 
+// Render context search action dropdown menu.
+function render_action_dropdown(actions, value) {
+    root_elem = document.createElement('div');
+
+    div_slct = d3.select(root_elem)
+        .style('display', 'inline-block');
+
+    div_dropdown = div_slct.append('div')
+        .attr('class', 'btn-group');
+
+    div_dropdown.append('button')
+        .attr('class', 'btn btn-default btn-xs dropdown-toggle')
+        .attr('type', 'button')
+        .attr('data-toggle', 'dropdown')
+        .attr('aria-haspopup', 'true')
+        .attr('aria-expanded', 'false')
+        .append('span')
+            .attr('class', 'caret');
+
+    ul_elem = div_dropdown.append('ul')
+        .attr('class', 'dropdown-menu dropdown-menu-right')
+
+    actions.forEach(function(action) {
+        try {
+            url = Flask.url_for(action.endpoint, action.params(value));
+            ul_elem.append('li').append('a')
+                .attr('href', url)
+                .html(action.icon + action.title.replace('{name}', value));
+        }
+        catch(err) {}
+    });
+
+    return root_elem;
+}
+
 // Render table for dict-based dataset.
-function render_table_dict(tid, table_columns, table_data, data_stats) {
+function render_table_dict(tid, table_columns, table_data, data_stats, action_list = null) {
     console.log('Rendering table: ' + tid);
 
     var value_formatter = table_value_formatter(
@@ -482,20 +517,37 @@ function render_table_dict(tid, table_columns, table_data, data_stats) {
             });
         })
         .enter()
-        .append('td')
-        //.style('background-color', table_column_color_scale(0))
-        .append('span')
-        .text(function (d, i) {
+        .append('td');
+        //.style('background-color', table_column_color_scale(0));
+
+    bcells.append(function (d, i) {
+            element = document.createElement('span');
+
             // First column contains the name.
             if (i == 0) {
-                return d.value;
+                element.appendChild(
+                    document.createTextNode(
+                        d.value
+                    )
+                );
+                return element;
             }
             // Second column contains the value.
             if (i == 1) {
-                return value_formatter(d.value);
+                element.appendChild(
+                    document.createTextNode(
+                        value_formatter(d.value)
+                    )
+                );
+                return element;
             }
             // Last column contains the percentage.
-            return percent_formatter(d.value);
+            element.appendChild(
+                document.createTextNode(
+                    percent_formatter(d.value)
+                )
+            );
+            return element;
         });
 
     // Insert small circle icon with correct color for given dataset instead of
@@ -505,6 +557,16 @@ function render_table_dict(tid, table_columns, table_data, data_stats) {
         .style('color', table_color_scale())
         .attr('class', 'fas fa-fw fa-circle pull-left');
 
+    if (action_list) {
+        brows.select('td')
+            .filter(function(d, i) {
+                return !(String(d.key).toLowerCase() in {'__unknown__': true, '__rest__': true});
+            })
+            .append(function (d, i) {
+                return render_action_dropdown(action_list, d.key);
+            });
+    }
+
     // Map of aggregation functions for table footer statistical summaries.
     funcmap = {
         'cnt': function(a,b) { return a.length },
diff --git a/lib/hawat/blueprints/design/templates/_layout.html b/lib/hawat/blueprints/design/templates/_layout.html
index 0928389ab491750a0c880fd500555e709d59d866..b05bf1df37098a35ef0bc190e0bb4af2ac7893e4 100644
--- a/lib/hawat/blueprints/design/templates/_layout.html
+++ b/lib/hawat/blueprints/design/templates/_layout.html
@@ -63,6 +63,9 @@
         <script src="{{ url_for('design.static', filename='vendor/globalize/globalize/relative-time.js') }}"></script>
         <script src="{{ url_for('design.static', filename='vendor/globalize/globalize/unit.js') }}"></script>
 
+        <!-- Flask JSGlue plugin -->
+        {{ JSGlue.include() }}
+
         <!-- Moment.js -->
         <script src="{{ url_for('design.static', filename='vendor/moment/js/moment-with-locales.min.js') }}"></script>
 
@@ -166,6 +169,9 @@
 
         </script>
 
+        <!-- Main application library -->
+        <script src="{{ url_for('mainjs') }}"></script>
+
         <!-- Custom libraries -->
         <script src="{{ url_for('design.static', filename='js/hawat-head.js') }}"></script>
         <script src="{{ url_for('design.static', filename='js/hawat-charts.js') }}"></script>
diff --git a/lib/hawat/blueprints/design/templates/_macros_chart.html b/lib/hawat/blueprints/design/templates/_macros_chart.html
index 6a928a839d864190f623fd04d1ee20e611e9d36e..cb55a3ca79c87e9087351cdbf3c4dfee1ac0264a 100644
--- a/lib/hawat/blueprints/design/templates/_macros_chart.html
+++ b/lib/hawat/blueprints/design/templates/_macros_chart.html
@@ -143,9 +143,10 @@
 
     string chart_id: Unique identifier of the chart. This will be used for
         generating all other required unique identifiers.
+    dict cfg_params: Additional chart configuration and customization parameters.
 
 -#}
-{%- macro _snippet_chart_timeline(chart_id) %}
+{%- macro _snippet_chart_timeline(chart_id, cfg_params) %}
                         // Render the timeline chart '{{ chart_id }}'.
                         $(document).ready(function () {
                             render_chart_timeline_multi(
@@ -169,9 +170,10 @@
 
     string chart_id: Unique identifier of the chart. This will be used for
         generating all other required unique identifiers.
+    dict cfg_params: Additional chart configuration and customization parameters.
 
 -#}
-{%- macro _snippet_chart_pie(chart_id) %}
+{%- macro _snippet_chart_pie(chart_id, cfg_params) %}
                         // Render pie chart for dataset '{{ chart_id }}'.
                         $(document).ready(function () {
                             render_chart_pie(
@@ -188,9 +190,10 @@
 
     string chart_id: Unique identifier of the chart. This will be used for
         generating all other required unique identifiers.
+    dict cfg_params: Additional chart configuration and customization parameters.
 
 -#}
-{%- macro _snippet_table_timeline(chart_id) %}
+{%- macro _snippet_table_timeline(chart_id, cfg_params) %}
                         // Render the timeline table '{{ chart_id }}'.
                         $(document).ready(function () {
                             render_table_timeline_multi(
@@ -215,9 +218,10 @@
 
     string chart_id: Unique identifier of the chart. This will be used for
         generating all other required unique identifiers.
+    dict cfg_params: Additional chart configuration and customization parameters.
 
 -#}
-{%- macro _snippet_table_dict(chart_id) %}
+{%- macro _snippet_table_dict(chart_id, cfg_params) %}
                         // Render table for dataset '{{ chart_id }}'.
                         $(document).ready(function () {
                             render_table_dict(
@@ -228,7 +232,8 @@
                                     {'ident': 'share', 'label': '{{ _("Share") }}'},
                                 ],
                                 {{ chart_id }}_dataset,
-                                GLOBAL_TABLE_COLS_STATS
+                                GLOBAL_TABLE_COLS_STATS{%- if 'csag_name' in cfg_params %},
+                                Hawat.get_csag('{{ cfg_params['csag_name'] }}'){%- endif %}
                             );
                         });
 {%- endmacro %}
@@ -240,9 +245,10 @@
 
     string chart_id: Unique identifier of the chart. This will be used for
         generating all other required unique identifiers.
+    dict cfg_params: Additional chart configuration and customization parameters.
 
 -#}
-{%- macro _snippet_ecbks_timeline(chart_id) %}
+{%- macro _snippet_ecbks_timeline(chart_id, cfg_params) %}
                         // Enable necessary event callbacks to appropriate DOM elements.
                         $(document).ready(function () {
                             // Event handler for toggling dataset table.
@@ -310,9 +316,10 @@
 
     string chart_id: Unique identifier of the chart. This will be used for
         generating all other required unique identifiers.
+    dict cfg_params: Additional chart configuration and customization parameters.
 
 -#}
-{%- macro _snippet_ecbks_dict(chart_id) %}
+{%- macro _snippet_ecbks_dict(chart_id, cfg_params) %}
                         // Append necessary event handlers for dataset '{{ chart_id }}'.
                         $(document).ready(function () {
                             // Event handler for downloading chart as SVG.
@@ -380,9 +387,10 @@
         generating identifiers for all required HTML and JS elements.
     string list_keys: List of requested subkeys from which the target dataset will
         be constructed.
+    dict cfg_params: Additional chart configuration and customization parameters.
 
 -#}
-{%- macro render_chart_timeline(full_data, data_var_name, id_prefix, list_keys) %}
+{%- macro render_chart_timeline(full_data, data_var_name, id_prefix, list_keys, cfg_params = {}) %}
 {%- set chart_id = 'chart_timeline_' + id_prefix %}
                     <!------------------------------------------------------------------
                         Dataset visualisation '{{ chart_id }}'
@@ -407,9 +415,9 @@
                             {{ chart_id }}_series
                         );
 
-                        {{ _snippet_chart_timeline(chart_id) }}
-                        {{ _snippet_table_timeline(chart_id) }}
-                        {{ _snippet_ecbks_timeline(chart_id) }}
+                        {{ _snippet_chart_timeline(chart_id, cfg_params) }}
+                        {{ _snippet_table_timeline(chart_id, cfg_params) }}
+                        {{ _snippet_ecbks_timeline(chart_id, cfg_params) }}
                     </script>
 
 {%- endmacro %}
@@ -427,13 +435,14 @@
         generating identifiers for all required HTML and JS elements.
     string dict_key: Name of the subkey in given full_data dictionary structure
         containing data from which to actually generate the TIMELINE chart.
+    dict cfg_params: Additional chart configuration and customization parameters.
 
     This macro expects, that the data structure under dict_key within the full_data
     is going to be a dictionary. In case it does not exist appropriate information
     will be presented to the user instead of the chart.
 
 -#}
-{%- macro render_chart_timeline_dict(full_data, data_var_name, id_prefix, dict_key) %}
+{%- macro render_chart_timeline_dict(full_data, data_var_name, id_prefix, dict_key, cfg_params = {}) %}
 {%- set chart_id = 'chart_timeline_' + id_prefix + '_' + dict_key %}
                     <!------------------------------------------------------------------
                         Dataset visualisation '{{ chart_id }}'
@@ -456,9 +465,9 @@
                             '{{ dict_key }}'
                         );
 
-                        {{ _snippet_chart_timeline(chart_id) }}
-                        {{ _snippet_table_timeline(chart_id) }}
-                        {{ _snippet_ecbks_timeline(chart_id) }}
+                        {{ _snippet_chart_timeline(chart_id, cfg_params) }}
+                        {{ _snippet_table_timeline(chart_id, cfg_params) }}
+                        {{ _snippet_ecbks_timeline(chart_id, cfg_params) }}
                     </script>
 
     {%- else %}
@@ -481,13 +490,14 @@
         generating identifiers for all required HTML and JS elements.
     string dict_key: Name of the subkey in given full_data dictionary structure
         containing data from which to actually generate the PIE chart.
+    dict cfg_params: Additional chart configuration and customization parameters.
 
     This macro expects, that the data structure under dict_key within the full_data
     is going to be a dictionary. In case it does not exist appropriate information
     will be presented to the user instead of the chart.
 
 -#}
-{%- macro render_dataset_pie_dict(full_data, data_var_name, id_prefix, dict_key) %}
+{%- macro render_dataset_pie_dict(full_data, data_var_name, id_prefix, dict_key, cfg_params = {}) %}
 {%- set chart_id = 'chart_pie_' + id_prefix + '_' + dict_key %}
 {%- set chart_data_var = data_var_name + '.' + dict_key %}
                     <!------------------------------------------------------------------
@@ -502,9 +512,9 @@
                         var {{ chart_id }}_dataset = get_dataset_dict(
                             {{ chart_data_var }}
                         );
-                        {{ _snippet_chart_pie(chart_id) }}
-                        {{ _snippet_table_dict(chart_id) }}
-                        {{ _snippet_ecbks_dict(chart_id) }}
+                        {{ _snippet_chart_pie(chart_id, cfg_params) }}
+                        {{ _snippet_table_dict(chart_id, cfg_params) }}
+                        {{ _snippet_ecbks_dict(chart_id, cfg_params) }}
 
                     </script>
 
@@ -529,9 +539,10 @@
         generating identifiers for all required HTML and JS elements.
     string list_keys: List of requested subkeys from which the target dataset will
         be constructed.
+    dict cfg_params: Additional chart configuration and customization parameters.
 
 -#}
-{%- macro render_dataset_pie_list(full_data, data_var_name, id_prefix, list_keys) %}
+{%- macro render_dataset_pie_list(full_data, data_var_name, id_prefix, list_keys, cfg_params = {}) %}
 {%- set chart_id = 'chart_pie_' + id_prefix %}
                     <!------------------------------------------------------------------
                         Dataset visualisation '{{ chart_id }}'
@@ -555,9 +566,9 @@
                             {{ data_var_name }},
                             {{ chart_id }}_series
                         );
-                        {{ _snippet_chart_pie(chart_id) }}
-                        {{ _snippet_table_dict(chart_id) }}
-                        {{ _snippet_ecbks_dict(chart_id) }}
+                        {{ _snippet_chart_pie(chart_id, cfg_params) }}
+                        {{ _snippet_table_dict(chart_id, cfg_params) }}
+                        {{ _snippet_ecbks_dict(chart_id, cfg_params) }}
 
                     </script>
 
@@ -710,7 +721,10 @@
                             statistics,
                             statistics_var_name,
                             id_prefix.replace('-', '_'),
-                            chsection[0]
+                            chsection[0],
+                            {
+                                'csag_name': chsection[0]
+                            }
                         )
                     }}
                 {%- else %}
diff --git a/lib/hawat/const.py b/lib/hawat/const.py
index a9c14c708fab4425299b81fbd04fc044b252b173..596370573b2cfdccea7981bdb5ec5d98fc411fee 100644
--- a/lib/hawat/const.py
+++ b/lib/hawat/const.py
@@ -107,16 +107,16 @@ RESOURCE_BABEL = 'babel'
 #
 # List of all existing Hawat context action search groups.
 #
-HAWAT_CSAG_ABUSE    = 'abuse'
-HAWAT_CSAG_ADDRESS  = 'address'
-HAWAT_CSAG_CATEGORY = 'category'
-HAWAT_CSAG_CLASS    = 'class'
-HAWAT_CSAG_DETECTOR = 'detector'
-HAWAT_CSAG_DETTYPE  = 'detector_type'
-HAWAT_CSAG_HOSTTYPE = 'host_type'
-HAWAT_CSAG_PORT     = 'port'
-HAWAT_CSAG_PROTOCOL = 'protocol'
-HAWAT_CSAG_SEVERITY = 'severity'
+HAWAT_CSAG_ABUSE    = 'abuses'
+HAWAT_CSAG_ADDRESS  = 'ips'
+HAWAT_CSAG_CATEGORY = 'categories'
+HAWAT_CSAG_CLASS    = 'classes'
+HAWAT_CSAG_DETECTOR = 'detectors'
+HAWAT_CSAG_DETTYPE  = 'detector_types'
+HAWAT_CSAG_HOSTTYPE = 'host_types'
+HAWAT_CSAG_PORT     = 'ports'
+HAWAT_CSAG_PROTOCOL = 'protocols'
+HAWAT_CSAG_SEVERITY = 'severities'
 
 FA_ICONS = {
 
diff --git a/lib/hawat/templates/hawat-main.js b/lib/hawat/templates/hawat-main.js
new file mode 100644
index 0000000000000000000000000000000000000000..e7b58255cfee17e4fe8bd9ce294e451334e1aa02
--- /dev/null
+++ b/lib/hawat/templates/hawat-main.js
@@ -0,0 +1,50 @@
+// Global application module.
+var Hawat = (function () {
+
+    function _build_param_builder(skeleton, rules) {
+        //var _skeleton = Object.assign({}, skeleton);
+        var _skeleton = skeleton;
+        var _rules = rules;
+        return function(value) {
+            //var _result = Object.assign({}, _skeleton);
+            var _result = _skeleton;
+            _rules.forEach(function(r) {
+                _result[r[0]] = value;
+            });
+            return _result;
+        }
+    }
+
+    var _csag = {
+{%- for csag_name in hawat_current_app.csag.keys() | sort %}
+        '{{ csag_name }}': [
+    {%- for csag in hawat_current_app.csag[csag_name] %}
+            {
+                'title':    '{{ _(csag.title, name = '{name}') }}',
+                'endpoint': '{{ csag.view.get_view_endpoint() }}',
+                'icon':     '{{ get_icon(csag.view.get_menu_icon()) }}',
+                'params':   _build_param_builder(
+                    {{ csag.params.skeleton | tojson | safe }},
+                    {{ csag.params.rules | tojson | safe }}
+                )
+            }{%- if not loop.last %},{%- endif %}
+    {%- endfor %}
+        ]{%- if not loop.last %},{%- endif %}
+{%- endfor %}
+    };
+
+    return {
+        get_csags: function() {
+            return _csag;
+        },
+
+        get_csag: function(name) {
+            try {
+                return _csag[name];
+            }
+            catch (err) {
+                return null
+            }
+        }
+    };
+})();