UTI: Remove datepicker, unify font sizes
[csit.git] / resources / tools / dash / app / pal / report / layout.py
index 26b9a9f..a556871 100644 (file)
@@ -26,68 +26,46 @@ from dash import Input, Output, State
 from dash.exceptions import PreventUpdate
 from yaml import load, FullLoader, YAMLError
 from copy import deepcopy
 from dash.exceptions import PreventUpdate
 from yaml import load, FullLoader, YAMLError
 from copy import deepcopy
-from json import loads, JSONDecodeError
 from ast import literal_eval
 
 from ast import literal_eval
 
-from pprint import pformat
-
+from ..utils.constants import Constants as C
+from ..utils.utils import show_tooltip, label, sync_checklists, list_tests, \
+    gen_new_url, generate_options
+from ..utils.url_processing import url_decode
 from ..data.data import Data
 from ..data.data import Data
-from ..data.url_processing import url_decode, url_encode
-from .graphs import graph_iterative, table_comparison
+from .graphs import graph_iterative, table_comparison, get_short_version, \
+    select_iterative_data
 
 
 class Layout:
 
 
 class Layout:
+    """The layout of the dash app and the callbacks.
     """
     """
-    """
-
-    # If True, clear all inputs in control panel when button "ADD SELECTED" is
-    # pressed.
-    CLEAR_ALL_INPUTS = False
-
-    STYLE_DISABLED = {"display": "none"}
-    STYLE_ENABLED = {"display": "inherit"}
-
-    CL_ALL_DISABLED = [{
-        "label": "All",
-        "value": "all",
-        "disabled": True
-    }]
-    CL_ALL_ENABLED = [{
-        "label": "All",
-        "value": "all",
-        "disabled": False
-    }]
-
-    PLACEHOLDER = html.Nobr("")
-
-    DRIVERS = ("avf", "af-xdp", "rdma", "dpdk")
-
-    LABELS = {
-        "dpdk": "DPDK",
-        "container_memif": "LXC/DRC Container Memif",
-        "crypto": "IPSec IPv4 Routing",
-        "ip4": "IPv4 Routing",
-        "ip6": "IPv6 Routing",
-        "ip4_tunnels": "IPv4 Tunnels",
-        "l2": "L2 Ethernet Switching",
-        "srv6": "SRv6 Routing",
-        "vm_vhost": "VMs vhost-user",
-        "nfv_density-dcr_memif-chain_ipsec": "CNF Service Chains Routing IPSec",
-        "nfv_density-vm_vhost-chain_dot1qip4vxlan":"VNF Service Chains Tunnels",
-        "nfv_density-vm_vhost-chain": "VNF Service Chains Routing",
-        "nfv_density-dcr_memif-pipeline": "CNF Service Pipelines Routing",
-        "nfv_density-dcr_memif-chain": "CNF Service Chains Routing",
-    }
-
-    URL_STYLE = {
-        "background-color": "#d2ebf5",
-        "border-color": "#bce1f1",
-        "color": "#135d7c"
-    }
 
     def __init__(self, app: Flask, releases: list, html_layout_file: str,
         graph_layout_file: str, data_spec_file: str, tooltip_file: str) -> None:
 
     def __init__(self, app: Flask, releases: list, html_layout_file: str,
         graph_layout_file: str, data_spec_file: str, tooltip_file: str) -> None:
-        """
+        """Initialization:
+        - save the input parameters,
+        - read and pre-process the data,
+        - prepare data for the control panel,
+        - read HTML layout file,
+        - read tooltips from the tooltip file.
+
+        :param app: Flask application running the dash application.
+        :param releases: Lis of releases to be displayed.
+        :param html_layout_file: Path and name of the file specifying the HTML
+            layout of the dash application.
+        :param graph_layout_file: Path and name of the file with layout of
+            plot.ly graphs.
+        :param data_spec_file: Path and name of the file specifying the data to
+            be read from parquets for this application.
+        :param tooltip_file: Path and name of the yaml file specifying the
+            tooltips.
+        :type app: Flask
+        :type releases: list
+        :type html_layout_file: str
+        :type graph_layout_file: str
+        :type data_spec_file: str
+        :type tooltip_file: str
         """
 
         # Inputs
         """
 
         # Inputs
@@ -102,10 +80,10 @@ class Layout:
         self._data = pd.DataFrame()
         for rls in releases:
             data_mrr = Data(self._data_spec_file, True).\
         self._data = pd.DataFrame()
         for rls in releases:
             data_mrr = Data(self._data_spec_file, True).\
-                read_iterative_mrr(release=rls)
+                read_iterative_mrr(release=rls.replace("csit", "rls"))
             data_mrr["release"] = rls
             data_ndrpdr = Data(self._data_spec_file, True).\
             data_mrr["release"] = rls
             data_ndrpdr = Data(self._data_spec_file, True).\
-                read_iterative_ndrpdr(release=rls)
+                read_iterative_ndrpdr(release=rls.replace("csit", "rls"))
             data_ndrpdr["release"] = rls
             self._data = pd.concat(
                 [self._data, data_mrr, data_ndrpdr], ignore_index=True)
             data_ndrpdr["release"] = rls
             self._data = pd.concat(
                 [self._data, data_mrr, data_ndrpdr], ignore_index=True)
@@ -116,9 +94,9 @@ class Layout:
         for _, row in self._data[cols].drop_duplicates().iterrows():
             rls = row["release"]
             ttype = row["test_type"]
         for _, row in self._data[cols].drop_duplicates().iterrows():
             rls = row["release"]
             ttype = row["test_type"]
-            d_ver = row["dut_version"]
             lst_job = row["job"].split("-")
             dut = lst_job[1]
             lst_job = row["job"].split("-")
             dut = lst_job[1]
+            d_ver = get_short_version(row["dut_version"], dut)
             tbed = "-".join(lst_job[-2:])
             lst_test_id = row["test_id"].split(".")
             if dut == "dpdk":
             tbed = "-".join(lst_job[-2:])
             lst_test_id = row["test_id"].split(".")
             if dut == "dpdk":
@@ -129,12 +107,9 @@ class Layout:
                 replace("2n-", "")
             test = lst_test_id[-1]
             nic = suite.split("-")[0]
                 replace("2n-", "")
             test = lst_test_id[-1]
             nic = suite.split("-")[0]
-            for drv in self.DRIVERS:
+            for drv in C.DRIVERS:
                 if drv in test:
                 if drv in test:
-                    if drv == "af-xdp":
-                        driver = "af_xdp"
-                    else:
-                        driver = drv
+                    driver = drv.replace("-", "_")
                     test = test.replace(f"{drv}-", "")
                     break
             else:
                     test = test.replace(f"{drv}-", "")
                     break
             else:
@@ -157,20 +132,27 @@ class Layout:
                 tbs[rls][dut][d_ver][infra][area] = dict()
             if tbs[rls][dut][d_ver][infra][area].get(test, None) is None:
                 tbs[rls][dut][d_ver][infra][area][test] = dict()
                 tbs[rls][dut][d_ver][infra][area] = dict()
             if tbs[rls][dut][d_ver][infra][area].get(test, None) is None:
                 tbs[rls][dut][d_ver][infra][area][test] = dict()
-                tbs_test = tbs[rls][dut][d_ver][infra][area][test]
-                tbs_test["core"] = list()
-                tbs_test["frame-size"] = list()
-                tbs_test["test-type"] = list()
-            if core.upper() not in tbs_test["core"]:
-                tbs_test["core"].append(core.upper())
-            if framesize.upper() not in tbs_test["frame-size"]:
-                tbs_test["frame-size"].append(framesize.upper())
+                tbs[rls][dut][d_ver][infra][area][test]["core"] = list()
+                tbs[rls][dut][d_ver][infra][area][test]["frame-size"] = list()
+                tbs[rls][dut][d_ver][infra][area][test]["test-type"] = list()
+            if core.upper() not in \
+                    tbs[rls][dut][d_ver][infra][area][test]["core"]:
+                tbs[rls][dut][d_ver][infra][area][test]["core"].append(
+                    core.upper())
+            if framesize.upper() not in \
+                        tbs[rls][dut][d_ver][infra][area][test]["frame-size"]:
+                tbs[rls][dut][d_ver][infra][area][test]["frame-size"].append(
+                    framesize.upper())
             if ttype == "mrr":
             if ttype == "mrr":
-                if "MRR" not in tbs_test["test-type"]:
-                    tbs_test["test-type"].append("MRR")
+                if "MRR" not in \
+                        tbs[rls][dut][d_ver][infra][area][test]["test-type"]:
+                    tbs[rls][dut][d_ver][infra][area][test]["test-type"].append(
+                        "MRR")
             elif ttype == "ndrpdr":
             elif ttype == "ndrpdr":
-                if "NDR" not in tbs_test["test-type"]:
-                    tbs_test["test-type"].extend(("NDR", "PDR", ))
+                if "NDR" not in \
+                        tbs[rls][dut][d_ver][infra][area][test]["test-type"]:
+                    tbs[rls][dut][d_ver][infra][area][test]["test-type"].extend(
+                        ("NDR", "PDR", ))
         self._spec_tbs = tbs
 
         # Read from files:
         self._spec_tbs = tbs
 
         # Read from files:
@@ -233,38 +215,24 @@ class Layout:
     def layout(self):
         return self._graph_layout
 
     def layout(self):
         return self._graph_layout
 
-    def label(self, key: str) -> str:
-        return self.LABELS.get(key, key)
+    def add_content(self):
+        """Top level method which generated the web page.
 
 
-    def _show_tooltip(self, id: str, title: str,
-            clipboard_id: str=None) -> list:
-        """
-        """
-        return [
-            dcc.Clipboard(target_id=clipboard_id, title="Copy URL") \
-                if clipboard_id else str(),
-            f"{title} ",
-            dbc.Badge(
-                id=id,
-                children="?",
-                pill=True,
-                color="white",
-                text_color="info",
-                class_name="border ms-1",
-            ),
-            dbc.Tooltip(
-                children=self._tooltips.get(id, str()),
-                target=id,
-                placement="auto"
-            )
-        ]
+        It generates:
+        - Store for user input data,
+        - Navigation bar,
+        - Main area with control panel and ploting area.
 
 
-    def add_content(self):
-        """
+        If no HTML layout is provided, an error message is displayed instead.
+
+        :returns: The HTML div with the whole page.
+        :rtype: html.Div
         """
         """
+
         if self.html_layout and self.spec_tbs:
             return html.Div(
                 id="div-main",
         if self.html_layout and self.spec_tbs:
             return html.Div(
                 id="div-main",
+                className="small",
                 children=[
                     dbc.Row(
                         id="row-navbar",
                 children=[
                     dbc.Row(
                         id="row-navbar",
@@ -314,6 +282,9 @@ class Layout:
 
     def _add_navbar(self):
         """Add nav element with navigation panel. It is placed on the top.
 
     def _add_navbar(self):
         """Add nav element with navigation panel. It is placed on the top.
+
+        :returns: Navigation bar.
+        :rtype: dbc.NavbarSimple
         """
         return dbc.NavbarSimple(
             id="navbarsimple-main",
         """
         return dbc.NavbarSimple(
             id="navbarsimple-main",
@@ -336,6 +307,9 @@ class Layout:
 
     def _add_ctrl_col(self) -> dbc.Col:
         """Add column with controls. It is placed on the left side.
 
     def _add_ctrl_col(self) -> dbc.Col:
         """Add column with controls. It is placed on the left side.
+
+        :returns: Column with the control panel.
+        :rtype: dbc.Col
         """
         return dbc.Col(
             id="col-controls",
         """
         return dbc.Col(
             id="col-controls",
@@ -346,6 +320,9 @@ class Layout:
 
     def _add_plotting_col(self) -> dbc.Col:
         """Add column with plots and tables. It is placed on the right side.
 
     def _add_plotting_col(self) -> dbc.Col:
         """Add column with plots and tables. It is placed on the right side.
+
+        :returns: Column with tables.
+        :rtype: dbc.Col
         """
         return dbc.Col(
             id="col-plotting-area",
         """
         return dbc.Col(
             id="col-plotting-area",
@@ -359,19 +336,15 @@ class Layout:
                                     dbc.Row(  # Throughput
                                         id="row-graph-tput",
                                         class_name="g-0 p-2",
                                     dbc.Row(  # Throughput
                                         id="row-graph-tput",
                                         class_name="g-0 p-2",
-                                        children=[
-                                            self.PLACEHOLDER
-                                        ]
+                                        children=[C.PLACEHOLDER, ]
                                     ),
                                     width=6
                                 ),
                                 dbc.Col(
                                     ),
                                     width=6
                                 ),
                                 dbc.Col(
-                                    dbc.Row(  # TSA
-                                        id="row-graph-tsa",
+                                    dbc.Row(  # Latency
+                                        id="row-graph-lat",
                                         class_name="g-0 p-2",
                                         class_name="g-0 p-2",
-                                        children=[
-                                            self.PLACEHOLDER
-                                        ]
+                                        children=[C.PLACEHOLDER, ]
                                     ),
                                     width=6
                                 )
                                     ),
                                     width=6
                                 )
@@ -380,16 +353,12 @@ class Layout:
                         dbc.Row(  # Tables
                             id="row-table",
                             class_name="g-0 p-2",
                         dbc.Row(  # Tables
                             id="row-table",
                             class_name="g-0 p-2",
-                            children=[
-                                self.PLACEHOLDER
-                            ]
+                            children=[C.PLACEHOLDER, ]
                         ),
                         dbc.Row(  # Download
                             id="row-btn-download",
                             class_name="g-0 p-2",
                         ),
                         dbc.Row(  # Download
                             id="row-btn-download",
                             class_name="g-0 p-2",
-                            children=[
-                                self.PLACEHOLDER
-                            ]
+                            children=[C.PLACEHOLDER, ]
                         )
                     ]
                 )
                         )
                     ]
                 )
@@ -398,7 +367,10 @@ class Layout:
         )
 
     def _add_ctrl_panel(self) -> dbc.Row:
         )
 
     def _add_ctrl_panel(self) -> dbc.Row:
-        """
+        """Add control panel.
+
+        :returns: Control panel.
+        :rtype: dbc.Row
         """
         return dbc.Row(
             id="row-ctrl-panel",
         """
         return dbc.Row(
             id="row-ctrl-panel",
@@ -410,8 +382,8 @@ class Layout:
                         dbc.InputGroup(
                             [
                                 dbc.InputGroupText(
                         dbc.InputGroup(
                             [
                                 dbc.InputGroupText(
-                                    children=self._show_tooltip(
-                                        "help-release", "Release")
+                                    children=show_tooltip(self._tooltips,
+                                        "help-release", "CSIT Release")
                                 ),
                                 dbc.Select(
                                     id="dd-ctrl-rls",
                                 ),
                                 dbc.Select(
                                     id="dd-ctrl-rls",
@@ -436,7 +408,7 @@ class Layout:
                         dbc.InputGroup(
                             [
                                 dbc.InputGroupText(
                         dbc.InputGroup(
                             [
                                 dbc.InputGroupText(
-                                    children=self._show_tooltip(
+                                    children=show_tooltip(self._tooltips,
                                         "help-dut", "DUT")
                                 ),
                                 dbc.Select(
                                         "help-dut", "DUT")
                                 ),
                                 dbc.Select(
@@ -457,7 +429,7 @@ class Layout:
                         dbc.InputGroup(
                             [
                                 dbc.InputGroupText(
                         dbc.InputGroup(
                             [
                                 dbc.InputGroupText(
-                                    children=self._show_tooltip(
+                                    children=show_tooltip(self._tooltips,
                                         "help-dut-ver", "DUT Version")
                                 ),
                                 dbc.Select(
                                         "help-dut-ver", "DUT Version")
                                 ),
                                 dbc.Select(
@@ -479,7 +451,7 @@ class Layout:
                         dbc.InputGroup(
                             [
                                 dbc.InputGroupText(
                         dbc.InputGroup(
                             [
                                 dbc.InputGroupText(
-                                    children=self._show_tooltip(
+                                    children=show_tooltip(self._tooltips,
                                         "help-infra", "Infra")
                                 ),
                                 dbc.Select(
                                         "help-infra", "Infra")
                                 ),
                                 dbc.Select(
@@ -501,7 +473,7 @@ class Layout:
                         dbc.InputGroup(
                             [
                                 dbc.InputGroupText(
                         dbc.InputGroup(
                             [
                                 dbc.InputGroupText(
-                                    children=self._show_tooltip(
+                                    children=show_tooltip(self._tooltips,
                                         "help-area", "Area")
                                 ),
                                 dbc.Select(
                                         "help-area", "Area")
                                 ),
                                 dbc.Select(
@@ -521,7 +493,7 @@ class Layout:
                         dbc.InputGroup(
                             [
                                 dbc.InputGroupText(
                         dbc.InputGroup(
                             [
                                 dbc.InputGroupText(
-                                    children=self._show_tooltip(
+                                    children=show_tooltip(self._tooltips,
                                         "help-test", "Test")
                                 ),
                                 dbc.Select(
                                         "help-test", "Test")
                                 ),
                                 dbc.Select(
@@ -540,7 +512,7 @@ class Layout:
                     class_name="gy-1",
                     children=[
                         dbc.Label(
                     class_name="gy-1",
                     children=[
                         dbc.Label(
-                            children=self._show_tooltip(
+                            children=show_tooltip(self._tooltips,
                                 "help-framesize", "Frame Size"),
                             class_name="p-0"
                         ),
                                 "help-framesize", "Frame Size"),
                             class_name="p-0"
                         ),
@@ -548,7 +520,7 @@ class Layout:
                             children=[
                                 dbc.Checklist(
                                     id="cl-ctrl-framesize-all",
                             children=[
                                 dbc.Checklist(
                                     id="cl-ctrl-framesize-all",
-                                    options=self.CL_ALL_DISABLED,
+                                    options=C.CL_ALL_DISABLED,
                                     inline=True,
                                     switch=False
                                 ),
                                     inline=True,
                                     switch=False
                                 ),
@@ -571,7 +543,7 @@ class Layout:
                     class_name="gy-1",
                     children=[
                         dbc.Label(
                     class_name="gy-1",
                     children=[
                         dbc.Label(
-                            children=self._show_tooltip(
+                            children=show_tooltip(self._tooltips,
                                 "help-cores", "Number of Cores"),
                             class_name="p-0"
                         ),
                                 "help-cores", "Number of Cores"),
                             class_name="p-0"
                         ),
@@ -579,7 +551,7 @@ class Layout:
                             children=[
                                 dbc.Checklist(
                                     id="cl-ctrl-core-all",
                             children=[
                                 dbc.Checklist(
                                     id="cl-ctrl-core-all",
-                                    options=self.CL_ALL_DISABLED,
+                                    options=C.CL_ALL_DISABLED,
                                     inline=False,
                                     switch=False
                                 )
                                     inline=False,
                                     switch=False
                                 )
@@ -602,7 +574,7 @@ class Layout:
                     class_name="gy-1",
                     children=[
                         dbc.Label(
                     class_name="gy-1",
                     children=[
                         dbc.Label(
-                            children=self._show_tooltip(
+                            children=show_tooltip(self._tooltips,
                                 "help-ttype", "Test Type"),
                             class_name="p-0"
                         ),
                                 "help-ttype", "Test Type"),
                             class_name="p-0"
                         ),
@@ -610,7 +582,7 @@ class Layout:
                             children=[
                                 dbc.Checklist(
                                     id="cl-ctrl-testtype-all",
                             children=[
                                 dbc.Checklist(
                                     id="cl-ctrl-testtype-all",
-                                    options=self.CL_ALL_DISABLED,
+                                    options=C.CL_ALL_DISABLED,
                                     inline=True,
                                     switch=False
                                 ),
                                     inline=True,
                                     switch=False
                                 ),
@@ -628,6 +600,34 @@ class Layout:
                         )
                     ]
                 ),
                         )
                     ]
                 ),
+                dbc.Row(
+                    id="row-ctrl-normalize",
+                    class_name="gy-1",
+                    children=[
+                        dbc.Label(
+                            children=show_tooltip(self._tooltips,
+                                "help-normalize", "Normalize"),
+                            class_name="p-0"
+                        ),
+                        dbc.Col(
+                            children=[
+                                dbc.Checklist(
+                                    id="cl-ctrl-normalize",
+                                    options=[{
+                                        "value": "normalize",
+                                        "label": (
+                                            "Normalize results to CPU"
+                                            "frequency 2GHz"
+                                        )
+                                    }],
+                                    value=[],
+                                    inline=True,
+                                    switch=False
+                                ),
+                            ]
+                        )
+                    ]
+                ),
                 dbc.Row(
                     class_name="gy-1 p-0",
                     children=[
                 dbc.Row(
                     class_name="gy-1 p-0",
                     children=[
@@ -639,15 +639,14 @@ class Layout:
                                     class_name="me-1",
                                     color="info"
                                 )
                                     class_name="me-1",
                                     color="info"
                                 )
-                            ],
-                            size="md",
+                            ]
                         )
                     ]
                 ),
                 dbc.Row(
                     id="row-card-sel-tests",
                     class_name="gy-1",
                         )
                     ]
                 ),
                 dbc.Row(
                     id="row-card-sel-tests",
                     class_name="gy-1",
-                    style=self.STYLE_DISABLED,
+                    style=C.STYLE_DISABLED,
                     children=[
                         dbc.Label(
                             "Selected tests",
                     children=[
                         dbc.Label(
                             "Selected tests",
@@ -658,13 +657,13 @@ class Layout:
                             id="cl-selected",
                             options=[],
                             inline=False,
                             id="cl-selected",
                             options=[],
                             inline=False,
-                            style={"max-height": "12em"},
+                            style={"max-height": "20em"},
                         )
                     ],
                 ),
                 dbc.Row(
                     id="row-btns-sel-tests",
                         )
                     ],
                 ),
                 dbc.Row(
                     id="row-btns-sel-tests",
-                    style=self.STYLE_DISABLED,
+                    style=C.STYLE_DISABLED,
                     children=[
                         dbc.ButtonGroup(
                             class_name="gy-2",
                     children=[
                         dbc.ButtonGroup(
                             class_name="gy-2",
@@ -683,8 +682,7 @@ class Layout:
                                     color="info",
                                     disabled=False
                                 ),
                                     color="info",
                                     disabled=False
                                 ),
-                            ],
-                            size="md",
+                            ]
                         )
                     ]
                 ),
                         )
                     ]
                 ),
@@ -692,13 +690,19 @@ class Layout:
         )
 
     class ControlPanel:
         )
 
     class ControlPanel:
-        def __init__(self, panel: dict) -> None:
+        """A class representing the control panel.
+        """
 
 
-            CL_ALL_DISABLED = [{
-                "label": "All",
-                "value": "all",
-                "disabled": True
-            }]
+        def __init__(self, panel: dict) -> None:
+            """Initialisation of the control pannel by default values. If
+            particular values are provided (parameter "panel") they are set
+            afterwards.
+
+            :param panel: Custom values to be set to the control panel.
+            :param default: Default values to be set to the control panel.
+            :type panel: dict
+            :type defaults: dict
+            """
 
             # Defines also the order of keys
             self._defaults = {
 
             # Defines also the order of keys
             self._defaults = {
@@ -721,16 +725,17 @@ class Layout:
                 "cl-core-options": list(),
                 "cl-core-value": list(),
                 "cl-core-all-value": list(),
                 "cl-core-options": list(),
                 "cl-core-value": list(),
                 "cl-core-all-value": list(),
-                "cl-core-all-options": CL_ALL_DISABLED,
+                "cl-core-all-options": C.CL_ALL_DISABLED,
                 "cl-framesize-options": list(),
                 "cl-framesize-value": list(),
                 "cl-framesize-all-value": list(),
                 "cl-framesize-options": list(),
                 "cl-framesize-value": list(),
                 "cl-framesize-all-value": list(),
-                "cl-framesize-all-options": CL_ALL_DISABLED,
+                "cl-framesize-all-options": C.CL_ALL_DISABLED,
                 "cl-testtype-options": list(),
                 "cl-testtype-value": list(),
                 "cl-testtype-all-value": list(),
                 "cl-testtype-options": list(),
                 "cl-testtype-value": list(),
                 "cl-testtype-all-value": list(),
-                "cl-testtype-all-options": CL_ALL_DISABLED,
+                "cl-testtype-all-options": C.CL_ALL_DISABLED,
                 "btn-add-disabled": True,
                 "btn-add-disabled": True,
+                "cl-normalize-value": list(),
                 "cl-selected-options": list()
             }
 
                 "cl-selected-options": list()
             }
 
@@ -748,6 +753,13 @@ class Layout:
             return self._panel
 
         def set(self, kwargs: dict) -> None:
             return self._panel
 
         def set(self, kwargs: dict) -> None:
+            """Set the values of the Control panel.
+
+            :param kwargs: key - value pairs to be set.
+            :type kwargs: dict
+            :raises KeyError: If the key in kwargs is not present in the Control
+                panel.
+            """
             for key, val in kwargs.items():
                 if key in self._panel:
                     self._panel[key] = val
             for key, val in kwargs.items():
                 if key in self._panel:
                     self._panel[key] = val
@@ -755,44 +767,55 @@ class Layout:
                     raise KeyError(f"The key {key} is not defined.")
 
         def get(self, key: str) -> any:
                     raise KeyError(f"The key {key} is not defined.")
 
         def get(self, key: str) -> any:
+            """Returns the value of a key from the Control panel.
+
+            :param key: The key which value should be returned.
+            :type key: str
+            :returns: The value of the key.
+            :rtype: any
+            :raises KeyError: If the key in kwargs is not present in the Control
+                panel.
+            """
             return self._panel[key]
 
         def values(self) -> tuple:
             return self._panel[key]
 
         def values(self) -> tuple:
+            """Returns the values from the Control panel as a list.
+
+            :returns: The values from the Control panel.
+            :rtype: list
+            """
             return tuple(self._panel.values())
 
             return tuple(self._panel.values())
 
-    @staticmethod
-    def _sync_checklists(opt: list, sel: list, all: list, id: str) -> tuple:
-        """
-        """
-        options = {v["value"] for v in opt}
-        if id =="all":
-            sel = list(options) if all else list()
-        else:
-            all = ["all", ] if set(sel) == options else list()
-        return sel, all
+    def callbacks(self, app):
+        """Callbacks for the whole application.
 
 
-    @staticmethod
-    def _list_tests(selection: dict) -> list:
-        """Display selected tests with checkboxes
+        :param app: The application.
+        :type app: Flask
         """
         """
-        if selection:
-            return [{"label": v["id"], "value": v["id"]} for v in selection]
-        else:
-            return list()
-
-    def callbacks(self, app):
 
         def _generate_plotting_area(figs: tuple, table: pd.DataFrame,
                 url: str) -> tuple:
 
         def _generate_plotting_area(figs: tuple, table: pd.DataFrame,
                 url: str) -> tuple:
-            """
+            """Generate the plotting area with all its content.
+
+            :param figs: Figures to be placed in the plotting area.
+            :param table: A table to be placed in the plotting area bellow the
+                figures.
+            :param utl: The URL to be placed in the plotting area bellow the
+                tables.
+            :type figs: tuple of plotly.graph_objects.Figure
+            :type table: pandas.DataFrame
+            :type url: str
+            :returns: tuple of elements to be shown in the plotting area.
+            :rtype: tuple
+                (dcc.Graph, dcc.Graph, dbc.Table, list(dbc.Col, dbc.Col))
             """
 
             """
 
-            (fig_tput, fig_tsa) = figs
+            (fig_tput, fig_lat) = figs
 
 
-            row_fig_tput = self.PLACEHOLDER
-            row_fig_tsa = self.PLACEHOLDER
-            row_table = self.PLACEHOLDER
-            row_btn_dwnld = self.PLACEHOLDER
+            row_fig_tput = C.PLACEHOLDER
+            row_fig_lat = C.PLACEHOLDER
+            row_table = C.PLACEHOLDER
+            row_btn_dwnld = C.PLACEHOLDER
 
             if fig_tput:
                 row_fig_tput = [
 
             if fig_tput:
                 row_fig_tput = [
@@ -808,7 +831,7 @@ class Layout:
                             dcc.Loading(children=[
                                 dbc.Button(
                                     id="btn-download-data",
                             dcc.Loading(children=[
                                 dbc.Button(
                                     id="btn-download-data",
-                                    children=self._show_tooltip(
+                                    children=show_tooltip(self._tooltips,
                                         "help-download", "Download Data"),
                                     class_name="me-1",
                                     color="info"
                                         "help-download", "Download Data"),
                                     class_name="me-1",
                                     color="info"
@@ -824,15 +847,15 @@ class Layout:
                                 class_name="me-1",
                                 children=[
                                     dbc.InputGroupText(
                                 class_name="me-1",
                                 children=[
                                     dbc.InputGroupText(
-                                        style=self.URL_STYLE,
-                                        children=self._show_tooltip(
+                                        style=C.URL_STYLE,
+                                        children=show_tooltip(self._tooltips,
                                             "help-url", "URL", "input-url")
                                     ),
                                     dbc.Input(
                                         id="input-url",
                                         readonly=True,
                                         type="url",
                                             "help-url", "URL", "input-url")
                                     ),
                                     dbc.Input(
                                         id="input-url",
                                         readonly=True,
                                         type="url",
-                                        style=self.URL_STYLE,
+                                        style=C.URL_STYLE,
                                         value=url
                                     )
                                 ]
                                         value=url
                                     )
                                 ]
@@ -840,11 +863,11 @@ class Layout:
                         ]
                     )
                 ]
                         ]
                     )
                 ]
-            if fig_tsa:
-                row_fig_tsa = [
+            if fig_lat:
+                row_fig_lat = [
                     dcc.Graph(
                         id={"type": "graph", "index": "lat"},
                     dcc.Graph(
                         id={"type": "graph", "index": "lat"},
-                        figure=fig_tsa
+                        figure=fig_lat
                     )
                 ]
             if not table.empty:
                     )
                 ]
             if not table.empty:
@@ -858,13 +881,13 @@ class Layout:
                     )
                 ]
 
                     )
                 ]
 
-            return row_fig_tput, row_fig_tsa, row_table, row_btn_dwnld
+            return row_fig_tput, row_fig_lat, row_table, row_btn_dwnld
 
         @app.callback(
             Output("control-panel", "data"),  # Store
             Output("selected-tests", "data"),  # Store
             Output("row-graph-tput", "children"),
 
         @app.callback(
             Output("control-panel", "data"),  # Store
             Output("selected-tests", "data"),  # Store
             Output("row-graph-tput", "children"),
-            Output("row-graph-tsa", "children"),
+            Output("row-graph-lat", "children"),
             Output("row-table", "children"),
             Output("row-btn-download", "children"),
             Output("row-card-sel-tests", "style"),
             Output("row-table", "children"),
             Output("row-btn-download", "children"),
             Output("row-card-sel-tests", "style"),
@@ -898,6 +921,7 @@ class Layout:
             Output("cl-ctrl-testtype-all", "value"),
             Output("cl-ctrl-testtype-all", "options"),
             Output("btn-ctrl-add", "disabled"),
             Output("cl-ctrl-testtype-all", "value"),
             Output("cl-ctrl-testtype-all", "options"),
             Output("btn-ctrl-add", "disabled"),
+            Output("cl-ctrl-normalize", "value"),
             Output("cl-selected", "options"),  # User selection
             State("control-panel", "data"),  # Store
             State("selected-tests", "data"),  # Store
             Output("cl-selected", "options"),  # User selection
             State("control-panel", "data"),  # Store
             State("selected-tests", "data"),  # Store
@@ -914,6 +938,7 @@ class Layout:
             Input("cl-ctrl-framesize-all", "value"),
             Input("cl-ctrl-testtype", "value"),
             Input("cl-ctrl-testtype-all", "value"),
             Input("cl-ctrl-framesize-all", "value"),
             Input("cl-ctrl-testtype", "value"),
             Input("cl-ctrl-testtype-all", "value"),
+            Input("cl-ctrl-normalize", "value"),
             Input("btn-ctrl-add", "n_clicks"),
             Input("btn-sel-remove", "n_clicks"),
             Input("btn-sel-remove-all", "n_clicks"),
             Input("btn-ctrl-add", "n_clicks"),
             Input("btn-sel-remove", "n_clicks"),
             Input("btn-sel-remove-all", "n_clicks"),
@@ -923,34 +948,69 @@ class Layout:
             dd_rls: str, dd_dut: str, dd_dutver: str, dd_phy: str, dd_area: str,
             dd_test: str, cl_core: list, cl_core_all: list, cl_framesize: list,
             cl_framesize_all: list, cl_testtype: list, cl_testtype_all: list,
             dd_rls: str, dd_dut: str, dd_dutver: str, dd_phy: str, dd_area: str,
             dd_test: str, cl_core: list, cl_core_all: list, cl_framesize: list,
             cl_framesize_all: list, cl_testtype: list, cl_testtype_all: list,
-            btn_add: int, btn_remove: int, btn_remove_all: int,
-            href: str) -> tuple:
-            """
+            cl_normalize: list, btn_add: int, btn_remove: int,
+            btn_remove_all: int, href: str) -> tuple:
+            """Update the application when the event is detected.
+
+            :param cp_data: Current status of the control panel stored in
+                browser.
+            :param store_sel: List of tests selected by user stored in the
+                browser.
+            :param list_sel: List of tests selected by the user shown in the
+                checklist.
+            :param dd_rls: Input - Releases.
+            :param dd_dut: Input - DUTs.
+            :param dd_dutver: Input - Version of DUT.
+            :param dd_phy: Input - topo- arch-nic-driver.
+            :param dd_area: Input - Tested area.
+            :param dd_test: Input - Test.
+            :param cl_core: Input - Number of cores.
+            :param cl_core_all: Input - All numbers of cores.
+            :param cl_framesize: Input - Frame sizes.
+            :param cl_framesize_all: Input - All frame sizes.
+            :param cl_testtype: Input - Test type (NDR, PDR, MRR).
+            :param cl_testtype_all: Input - All test types.
+            :param cl_normalize: Input - Normalize the results.
+            :param btn_add: Input - Button "Add Selected" tests.
+            :param btn_remove: Input - Button "Remove selected" tests.
+            :param btn_remove_all: Input - Button "Remove All" tests.
+            :param href: Input - The URL provided by the browser.
+            :type cp_data: dict
+            :type store_sel: list
+            :type list_sel: list
+            :type dd_rls: str
+            :type dd_dut: str
+            :type dd_dutver: str
+            :type dd_phy: str
+            :type dd_area: str
+            :type dd_test: str
+            :type cl_core: list
+            :type cl_core_all: list
+            :type cl_framesize: list
+            :type cl_framesize_all: list
+            :type cl_testtype: list
+            :type cl_testtype_all: list
+            :type cl_normalize: list
+            :type btn_add: int
+            :type btn_remove: int
+            :type btn_remove_all: int
+            :type href: str
+            :returns: New values for web page elements.
+            :rtype: tuple
             """
 
             """
 
-            def _gen_new_url(parsed_url: dict, store_sel: list) -> str:
-
-                if parsed_url:
-                    new_url = url_encode({
-                        "scheme": parsed_url["scheme"],
-                        "netloc": parsed_url["netloc"],
-                        "path": parsed_url["path"],
-                        "params": {
-                            "store_sel": store_sel,
-                        }
-                    })
-                else:
-                    new_url = str()
-                return new_url
-
-
             ctrl_panel = self.ControlPanel(cp_data)
             ctrl_panel = self.ControlPanel(cp_data)
+            norm = cl_normalize
 
             # Parse the url:
             parsed_url = url_decode(href)
 
             # Parse the url:
             parsed_url = url_decode(href)
+            if parsed_url:
+                url_params = parsed_url["params"]
+            else:
+                url_params = None
 
             row_fig_tput = no_update
 
             row_fig_tput = no_update
-            row_fig_tsa = no_update
+            row_fig_lat = no_update
             row_table = no_update
             row_btn_dwnld = no_update
             row_card_sel_tests = no_update
             row_table = no_update
             row_btn_dwnld = no_update
             row_card_sel_tests = no_update
@@ -960,11 +1020,8 @@ class Layout:
 
             if trigger_id == "dd-ctrl-rls":
                 try:
 
             if trigger_id == "dd-ctrl-rls":
                 try:
-                    rls = self.spec_tbs[dd_rls]
-                    options = sorted(
-                        [{"label": v, "value": v} for v in rls.keys()],
-                        key=lambda d: d["label"]
-                    )
+                    options = \
+                        generate_options(sorted(self.spec_tbs[dd_rls].keys()))
                     disabled = False
                 except KeyError:
                     options = list()
                     disabled = False
                 except KeyError:
                     options = list()
@@ -989,24 +1046,21 @@ class Layout:
                     "cl-core-options": list(),
                     "cl-core-value": list(),
                     "cl-core-all-value": list(),
                     "cl-core-options": list(),
                     "cl-core-value": list(),
                     "cl-core-all-value": list(),
-                    "cl-core-all-options": self.CL_ALL_DISABLED,
+                    "cl-core-all-options": C.CL_ALL_DISABLED,
                     "cl-framesize-options": list(),
                     "cl-framesize-value": list(),
                     "cl-framesize-all-value": list(),
                     "cl-framesize-options": list(),
                     "cl-framesize-value": list(),
                     "cl-framesize-all-value": list(),
-                    "cl-framesize-all-options": self.CL_ALL_DISABLED,
+                    "cl-framesize-all-options": C.CL_ALL_DISABLED,
                     "cl-testtype-options": list(),
                     "cl-testtype-value": list(),
                     "cl-testtype-all-value": list(),
                     "cl-testtype-options": list(),
                     "cl-testtype-value": list(),
                     "cl-testtype-all-value": list(),
-                    "cl-testtype-all-options": self.CL_ALL_DISABLED
+                    "cl-testtype-all-options": C.CL_ALL_DISABLED
                 })
                 })
-            if trigger_id == "dd-ctrl-dut":
+            elif trigger_id == "dd-ctrl-dut":
                 try:
                     rls = ctrl_panel.get("dd-rls-value")
                     dut = self.spec_tbs[rls][dd_dut]
                 try:
                     rls = ctrl_panel.get("dd-rls-value")
                     dut = self.spec_tbs[rls][dd_dut]
-                    options = sorted(
-                        [{"label": v, "value": v} for v in dut.keys()],
-                        key=lambda d: d["label"]
-                    )
+                    options = generate_options(sorted(dut.keys()))
                     disabled = False
                 except KeyError:
                     options = list()
                     disabled = False
                 except KeyError:
                     options = list()
@@ -1028,25 +1082,22 @@ class Layout:
                     "cl-core-options": list(),
                     "cl-core-value": list(),
                     "cl-core-all-value": list(),
                     "cl-core-options": list(),
                     "cl-core-value": list(),
                     "cl-core-all-value": list(),
-                    "cl-core-all-options": self.CL_ALL_DISABLED,
+                    "cl-core-all-options": C.CL_ALL_DISABLED,
                     "cl-framesize-options": list(),
                     "cl-framesize-value": list(),
                     "cl-framesize-all-value": list(),
                     "cl-framesize-options": list(),
                     "cl-framesize-value": list(),
                     "cl-framesize-all-value": list(),
-                    "cl-framesize-all-options": self.CL_ALL_DISABLED,
+                    "cl-framesize-all-options": C.CL_ALL_DISABLED,
                     "cl-testtype-options": list(),
                     "cl-testtype-value": list(),
                     "cl-testtype-all-value": list(),
                     "cl-testtype-options": list(),
                     "cl-testtype-value": list(),
                     "cl-testtype-all-value": list(),
-                    "cl-testtype-all-options": self.CL_ALL_DISABLED
+                    "cl-testtype-all-options": C.CL_ALL_DISABLED
                 })
             elif trigger_id == "dd-ctrl-dutver":
                 try:
                     rls = ctrl_panel.get("dd-rls-value")
                     dut = ctrl_panel.get("dd-dut-value")
                     dutver = self.spec_tbs[rls][dut][dd_dutver]
                 })
             elif trigger_id == "dd-ctrl-dutver":
                 try:
                     rls = ctrl_panel.get("dd-rls-value")
                     dut = ctrl_panel.get("dd-dut-value")
                     dutver = self.spec_tbs[rls][dut][dd_dutver]
-                    options = sorted(
-                        [{"label": v, "value": v} for v in dutver.keys()],
-                        key=lambda d: d["label"]
-                    )
+                    options = generate_options(sorted(dutver.keys()))
                     disabled = False
                 except KeyError:
                     options = list()
                     disabled = False
                 except KeyError:
                     options = list()
@@ -1065,15 +1116,15 @@ class Layout:
                     "cl-core-options": list(),
                     "cl-core-value": list(),
                     "cl-core-all-value": list(),
                     "cl-core-options": list(),
                     "cl-core-value": list(),
                     "cl-core-all-value": list(),
-                    "cl-core-all-options": self.CL_ALL_DISABLED,
+                    "cl-core-all-options": C.CL_ALL_DISABLED,
                     "cl-framesize-options": list(),
                     "cl-framesize-value": list(),
                     "cl-framesize-all-value": list(),
                     "cl-framesize-options": list(),
                     "cl-framesize-value": list(),
                     "cl-framesize-all-value": list(),
-                    "cl-framesize-all-options": self.CL_ALL_DISABLED,
+                    "cl-framesize-all-options": C.CL_ALL_DISABLED,
                     "cl-testtype-options": list(),
                     "cl-testtype-value": list(),
                     "cl-testtype-all-value": list(),
                     "cl-testtype-options": list(),
                     "cl-testtype-value": list(),
                     "cl-testtype-all-value": list(),
-                    "cl-testtype-all-options": self.CL_ALL_DISABLED
+                    "cl-testtype-all-options": C.CL_ALL_DISABLED
                 })
             elif trigger_id == "dd-ctrl-phy":
                 try:
                 })
             elif trigger_id == "dd-ctrl-phy":
                 try:
@@ -1081,11 +1132,8 @@ class Layout:
                     dut = ctrl_panel.get("dd-dut-value")
                     dutver = ctrl_panel.get("dd-dutver-value")
                     phy = self.spec_tbs[rls][dut][dutver][dd_phy]
                     dut = ctrl_panel.get("dd-dut-value")
                     dutver = ctrl_panel.get("dd-dutver-value")
                     phy = self.spec_tbs[rls][dut][dutver][dd_phy]
-                    options = sorted(
-                        [{"label": self.label(v), "value": v}
-                            for v in phy.keys()],
-                        key=lambda d: d["label"]
-                    )
+                    options = [{"label": label(v), "value": v} \
+                        for v in sorted(phy.keys())]
                     disabled = False
                 except KeyError:
                     options = list()
                     disabled = False
                 except KeyError:
                     options = list()
@@ -1101,15 +1149,15 @@ class Layout:
                     "cl-core-options": list(),
                     "cl-core-value": list(),
                     "cl-core-all-value": list(),
                     "cl-core-options": list(),
                     "cl-core-value": list(),
                     "cl-core-all-value": list(),
-                    "cl-core-all-options": self.CL_ALL_DISABLED,
+                    "cl-core-all-options": C.CL_ALL_DISABLED,
                     "cl-framesize-options": list(),
                     "cl-framesize-value": list(),
                     "cl-framesize-all-value": list(),
                     "cl-framesize-options": list(),
                     "cl-framesize-value": list(),
                     "cl-framesize-all-value": list(),
-                    "cl-framesize-all-options": self.CL_ALL_DISABLED,
+                    "cl-framesize-all-options": C.CL_ALL_DISABLED,
                     "cl-testtype-options": list(),
                     "cl-testtype-value": list(),
                     "cl-testtype-all-value": list(),
                     "cl-testtype-options": list(),
                     "cl-testtype-value": list(),
                     "cl-testtype-all-value": list(),
-                    "cl-testtype-all-options": self.CL_ALL_DISABLED
+                    "cl-testtype-all-options": C.CL_ALL_DISABLED
                 })
             elif trigger_id == "dd-ctrl-area":
                 try:
                 })
             elif trigger_id == "dd-ctrl-area":
                 try:
@@ -1118,10 +1166,7 @@ class Layout:
                     dutver = ctrl_panel.get("dd-dutver-value")
                     phy = ctrl_panel.get("dd-phy-value")
                     area = self.spec_tbs[rls][dut][dutver][phy][dd_area]
                     dutver = ctrl_panel.get("dd-dutver-value")
                     phy = ctrl_panel.get("dd-phy-value")
                     area = self.spec_tbs[rls][dut][dutver][phy][dd_area]
-                    options = sorted(
-                        [{"label": v, "value": v} for v in area.keys()],
-                        key=lambda d: d["label"]
-                    )
+                    options = generate_options(sorted(area.keys()))
                     disabled = False
                 except KeyError:
                     options = list()
                     disabled = False
                 except KeyError:
                     options = list()
@@ -1134,15 +1179,15 @@ class Layout:
                     "cl-core-options": list(),
                     "cl-core-value": list(),
                     "cl-core-all-value": list(),
                     "cl-core-options": list(),
                     "cl-core-value": list(),
                     "cl-core-all-value": list(),
-                    "cl-core-all-options": self.CL_ALL_DISABLED,
+                    "cl-core-all-options": C.CL_ALL_DISABLED,
                     "cl-framesize-options": list(),
                     "cl-framesize-value": list(),
                     "cl-framesize-all-value": list(),
                     "cl-framesize-options": list(),
                     "cl-framesize-value": list(),
                     "cl-framesize-all-value": list(),
-                    "cl-framesize-all-options": self.CL_ALL_DISABLED,
+                    "cl-framesize-all-options": C.CL_ALL_DISABLED,
                     "cl-testtype-options": list(),
                     "cl-testtype-value": list(),
                     "cl-testtype-all-value": list(),
                     "cl-testtype-options": list(),
                     "cl-testtype-value": list(),
                     "cl-testtype-all-value": list(),
-                    "cl-testtype-all-options": self.CL_ALL_DISABLED
+                    "cl-testtype-all-options": C.CL_ALL_DISABLED
                 })
             elif trigger_id == "dd-ctrl-test":
                 rls = ctrl_panel.get("dd-rls-value")
                 })
             elif trigger_id == "dd-ctrl-test":
                 rls = ctrl_panel.get("dd-rls-value")
@@ -1150,29 +1195,29 @@ class Layout:
                 dutver = ctrl_panel.get("dd-dutver-value")
                 phy = ctrl_panel.get("dd-phy-value")
                 area = ctrl_panel.get("dd-area-value")
                 dutver = ctrl_panel.get("dd-dutver-value")
                 phy = ctrl_panel.get("dd-phy-value")
                 area = ctrl_panel.get("dd-area-value")
-                test = self.spec_tbs[rls][dut][dutver][phy][area][dd_test]
-                if dut and phy and area and dd_test:
+                if all((rls, dut, dutver, phy, area, dd_test, )):
+                    test = self.spec_tbs[rls][dut][dutver][phy][area][dd_test]
                     ctrl_panel.set({
                         "dd-test-value": dd_test,
                     ctrl_panel.set({
                         "dd-test-value": dd_test,
-                        "cl-core-options": [{"label": v, "value": v}
-                            for v in sorted(test["core"])],
+                        "cl-core-options": \
+                            generate_options(sorted(test["core"])),
                         "cl-core-value": list(),
                         "cl-core-all-value": list(),
                         "cl-core-value": list(),
                         "cl-core-all-value": list(),
-                        "cl-core-all-options": self.CL_ALL_ENABLED,
-                        "cl-framesize-options": [{"label": v, "value": v}
-                            for v in sorted(test["frame-size"])],
+                        "cl-core-all-options": C.CL_ALL_ENABLED,
+                        "cl-framesize-options": \
+                            generate_options(sorted(test["frame-size"])),
                         "cl-framesize-value": list(),
                         "cl-framesize-all-value": list(),
                         "cl-framesize-value": list(),
                         "cl-framesize-all-value": list(),
-                        "cl-framesize-all-options": self.CL_ALL_ENABLED,
-                        "cl-testtype-options": [{"label": v, "value": v}
-                            for v in sorted(test["test-type"])],
+                        "cl-framesize-all-options": C.CL_ALL_ENABLED,
+                        "cl-testtype-options": \
+                            generate_options(sorted(test["test-type"])),
                         "cl-testtype-value": list(),
                         "cl-testtype-all-value": list(),
                         "cl-testtype-value": list(),
                         "cl-testtype-all-value": list(),
-                        "cl-testtype-all-options": self.CL_ALL_ENABLED,
+                        "cl-testtype-all-options": C.CL_ALL_ENABLED,
                     })
             elif trigger_id == "cl-ctrl-core":
                     })
             elif trigger_id == "cl-ctrl-core":
-                val_sel, val_all = self._sync_checklists(
-                    opt=ctrl_panel.get("cl-core-options"),
+                val_sel, val_all = sync_checklists(
+                    options=ctrl_panel.get("cl-core-options"),
                     sel=cl_core,
                     all=list(),
                     id=""
                     sel=cl_core,
                     all=list(),
                     id=""
@@ -1182,8 +1227,8 @@ class Layout:
                     "cl-core-all-value": val_all,
                 })
             elif trigger_id == "cl-ctrl-core-all":
                     "cl-core-all-value": val_all,
                 })
             elif trigger_id == "cl-ctrl-core-all":
-                val_sel, val_all = self._sync_checklists(
-                    opt = ctrl_panel.get("cl-core-options"),
+                val_sel, val_all = sync_checklists(
+                    options = ctrl_panel.get("cl-core-options"),
                     sel=list(),
                     all=cl_core_all,
                     id="all"
                     sel=list(),
                     all=cl_core_all,
                     id="all"
@@ -1193,8 +1238,8 @@ class Layout:
                     "cl-core-all-value": val_all,
                 })
             elif trigger_id == "cl-ctrl-framesize":
                     "cl-core-all-value": val_all,
                 })
             elif trigger_id == "cl-ctrl-framesize":
-                val_sel, val_all = self._sync_checklists(
-                    opt = ctrl_panel.get("cl-framesize-options"),
+                val_sel, val_all = sync_checklists(
+                    options = ctrl_panel.get("cl-framesize-options"),
                     sel=cl_framesize,
                     all=list(),
                     id=""
                     sel=cl_framesize,
                     all=list(),
                     id=""
@@ -1204,8 +1249,8 @@ class Layout:
                     "cl-framesize-all-value": val_all,
                 })
             elif trigger_id == "cl-ctrl-framesize-all":
                     "cl-framesize-all-value": val_all,
                 })
             elif trigger_id == "cl-ctrl-framesize-all":
-                val_sel, val_all = self._sync_checklists(
-                    opt = ctrl_panel.get("cl-framesize-options"),
+                val_sel, val_all = sync_checklists(
+                    options = ctrl_panel.get("cl-framesize-options"),
                     sel=list(),
                     all=cl_framesize_all,
                     id="all"
                     sel=list(),
                     all=cl_framesize_all,
                     id="all"
@@ -1215,8 +1260,8 @@ class Layout:
                     "cl-framesize-all-value": val_all,
                 })
             elif trigger_id == "cl-ctrl-testtype":
                     "cl-framesize-all-value": val_all,
                 })
             elif trigger_id == "cl-ctrl-testtype":
-                val_sel, val_all = self._sync_checklists(
-                    opt = ctrl_panel.get("cl-testtype-options"),
+                val_sel, val_all = sync_checklists(
+                    options = ctrl_panel.get("cl-testtype-options"),
                     sel=cl_testtype,
                     all=list(),
                     id=""
                     sel=cl_testtype,
                     all=list(),
                     id=""
@@ -1226,8 +1271,8 @@ class Layout:
                     "cl-testtype-all-value": val_all,
                 })
             elif trigger_id == "cl-ctrl-testtype-all":
                     "cl-testtype-all-value": val_all,
                 })
             elif trigger_id == "cl-ctrl-testtype-all":
-                val_sel, val_all = self._sync_checklists(
-                    opt = ctrl_panel.get("cl-testtype-options"),
+                val_sel, val_all = sync_checklists(
+                    options = ctrl_panel.get("cl-testtype-options"),
                     sel=list(),
                     all=cl_testtype_all,
                     id="all"
                     sel=list(),
                     all=cl_testtype_all,
                     id="all"
@@ -1275,27 +1320,21 @@ class Layout:
                                         "testtype": ttype.lower()
                                     })
                     store_sel = sorted(store_sel, key=lambda d: d["id"])
                                         "testtype": ttype.lower()
                                     })
                     store_sel = sorted(store_sel, key=lambda d: d["id"])
-                    row_card_sel_tests = self.STYLE_ENABLED
-                    row_btns_sel_tests = self.STYLE_ENABLED
-                    if self.CLEAR_ALL_INPUTS:
+                    row_card_sel_tests = C.STYLE_ENABLED
+                    row_btns_sel_tests = C.STYLE_ENABLED
+                    if C.CLEAR_ALL_INPUTS:
                         ctrl_panel.set(ctrl_panel.defaults)
                     ctrl_panel.set({
                         ctrl_panel.set(ctrl_panel.defaults)
                     ctrl_panel.set({
-                        "cl-selected-options": self._list_tests(store_sel)
+                        "cl-selected-options": list_tests(store_sel)
                     })
                     })
-                    row_fig_tput, row_fig_tsa, row_table, row_btn_dwnld = \
-                        _generate_plotting_area(
-                            graph_iterative(self.data, store_sel, self.layout),
-                            table_comparison(self.data, store_sel),
-                            _gen_new_url(parsed_url, store_sel)
-                        )
             elif trigger_id == "btn-sel-remove-all":
                 _ = btn_remove_all
             elif trigger_id == "btn-sel-remove-all":
                 _ = btn_remove_all
-                row_fig_tput = self.PLACEHOLDER
-                row_fig_tsa = self.PLACEHOLDER
-                row_table = self.PLACEHOLDER
-                row_btn_dwnld = self.PLACEHOLDER
-                row_card_sel_tests = self.STYLE_DISABLED
-                row_btns_sel_tests = self.STYLE_DISABLED
+                row_fig_tput = C.PLACEHOLDER
+                row_fig_lat = C.PLACEHOLDER
+                row_table = C.PLACEHOLDER
+                row_btn_dwnld = C.PLACEHOLDER
+                row_card_sel_tests = C.STYLE_DISABLED
+                row_btns_sel_tests = C.STYLE_DISABLED
                 store_sel = list()
                 ctrl_panel.set({"cl-selected-options": list()})
             elif trigger_id == "btn-sel-remove":
                 store_sel = list()
                 ctrl_panel.set({"cl-selected-options": list()})
             elif trigger_id == "btn-sel-remove":
@@ -1306,53 +1345,100 @@ class Layout:
                         if item["id"] not in list_sel:
                             new_store_sel.append(item)
                     store_sel = new_store_sel
                         if item["id"] not in list_sel:
                             new_store_sel.append(item)
                     store_sel = new_store_sel
+            elif trigger_id == "url":
+                if url_params:
+                    try:
+                        store_sel = literal_eval(url_params["store_sel"][0])
+                        norm = literal_eval(url_params["norm"][0])
+                    except (KeyError, IndexError):
+                        pass
+                    if store_sel:
+                        row_card_sel_tests = C.STYLE_ENABLED
+                        row_btns_sel_tests = C.STYLE_ENABLED
+                        last_test = store_sel[-1]
+                        test = self.spec_tbs[last_test["rls"]]\
+                            [last_test["dut"]][last_test["dutver"]]\
+                                [last_test["phy"]][last_test["area"]]\
+                                    [last_test["test"]]
+                        ctrl_panel.set({
+                            "dd-rls-value": last_test["rls"],
+                            "dd-dut-value": last_test["dut"],
+                            "dd-dut-options": generate_options(sorted(
+                                self.spec_tbs[last_test["rls"]].keys())),
+                            "dd-dut-disabled": False,
+                            "dd-dutver-value": last_test["dutver"],
+                            "dd-dutver-options": generate_options(sorted(
+                                self.spec_tbs[last_test["rls"]]\
+                                    [last_test["dut"]].keys())),
+                            "dd-dutver-disabled": False,
+                            "dd-phy-value": last_test["phy"],
+                            "dd-phy-options": generate_options(sorted(
+                                self.spec_tbs[last_test["rls"]]\
+                                    [last_test["dut"]]\
+                                        [last_test["dutver"]].keys())),
+                            "dd-phy-disabled": False,
+                            "dd-area-value": last_test["area"],
+                            "dd-area-options": [
+                                {"label": label(v), "value": v} for v in \
+                                    sorted(self.spec_tbs[last_test["rls"]]\
+                                        [last_test["dut"]][last_test["dutver"]]\
+                                            [last_test["phy"]].keys())
+                            ],
+                            "dd-area-disabled": False,
+                            "dd-test-value": last_test["test"],
+                            "dd-test-options": generate_options(sorted(
+                                self.spec_tbs[last_test["rls"]]\
+                                    [last_test["dut"]][last_test["dutver"]]\
+                                        [last_test["phy"]]\
+                                            [last_test["area"]].keys())),
+                            "dd-test-disabled": False,
+                            "cl-core-options": generate_options(sorted(
+                                test["core"])),
+                            "cl-core-value": [last_test["core"].upper(), ],
+                            "cl-core-all-value": list(),
+                            "cl-core-all-options": C.CL_ALL_ENABLED,
+                            "cl-framesize-options": generate_options(
+                                sorted(test["frame-size"])),
+                            "cl-framesize-value": \
+                                [last_test["framesize"].upper(), ],
+                            "cl-framesize-all-value": list(),
+                            "cl-framesize-all-options": C.CL_ALL_ENABLED,
+                            "cl-testtype-options": generate_options(sorted(
+                                test["test-type"])),
+                            "cl-testtype-value": \
+                                [last_test["testtype"].upper(), ],
+                            "cl-testtype-all-value": list(),
+                            "cl-testtype-all-options": C.CL_ALL_ENABLED
+                        })
+
+            if trigger_id in ("btn-ctrl-add", "url", "btn-sel-remove",
+                    "cl-ctrl-normalize"):
                 if store_sel:
                 if store_sel:
-                    row_fig_tput, row_fig_tsa, row_table, row_btn_dwnld = \
+                    row_fig_tput, row_fig_lat, row_table, row_btn_dwnld = \
                         _generate_plotting_area(
                         _generate_plotting_area(
-                            graph_iterative(self.data, store_sel, self.layout),
-                            table_comparison(self.data, store_sel),
-                            _gen_new_url(parsed_url, store_sel)
+                            graph_iterative(
+                                self.data, store_sel, self.layout, bool(norm)
+                            ),
+                            table_comparison(
+                                self.data, store_sel, bool(norm)
+                            ),
+                            gen_new_url(
+                                parsed_url,
+                                {"store_sel": store_sel, "norm": norm}
+                            )
                         )
                     ctrl_panel.set({
                         )
                     ctrl_panel.set({
-                        "cl-selected-options": self._list_tests(store_sel)
+                        "cl-selected-options": list_tests(store_sel)
                     })
                 else:
                     })
                 else:
-                    row_fig_tput = self.PLACEHOLDER
-                    row_fig_tsa = self.PLACEHOLDER
-                    row_table = self.PLACEHOLDER
-                    row_btn_dwnld = self.PLACEHOLDER
-                    row_card_sel_tests = self.STYLE_DISABLED
-                    row_btns_sel_tests = self.STYLE_DISABLED
+                    row_fig_tput = C.PLACEHOLDER
+                    row_fig_lat = C.PLACEHOLDER
+                    row_table = C.PLACEHOLDER
+                    row_btn_dwnld = C.PLACEHOLDER
+                    row_card_sel_tests = C.STYLE_DISABLED
+                    row_btns_sel_tests = C.STYLE_DISABLED
                     store_sel = list()
                     ctrl_panel.set({"cl-selected-options": list()})
                     store_sel = list()
                     ctrl_panel.set({"cl-selected-options": list()})
-            elif trigger_id == "url":
-                # TODO: Add verification
-                url_params = parsed_url["params"]
-                if url_params:
-                    store_sel = literal_eval(
-                        url_params.get("store_sel", list())[0])
-                    if store_sel:
-                        row_fig_tput, row_fig_tsa, row_table, row_btn_dwnld = \
-                            _generate_plotting_area(
-                                graph_iterative(self.data, store_sel,
-                                    self.layout),
-                                table_comparison(self.data, store_sel),
-                                _gen_new_url(parsed_url, store_sel)
-                            )
-                        row_card_sel_tests = self.STYLE_ENABLED
-                        row_btns_sel_tests = self.STYLE_ENABLED
-                        ctrl_panel.set({
-                            "cl-selected-options": self._list_tests(store_sel)
-                        })
-                    else:
-                        row_fig_tput = self.PLACEHOLDER
-                        row_fig_tsa = self.PLACEHOLDER
-                        row_table = self.PLACEHOLDER
-                        row_btn_dwnld = self.PLACEHOLDER
-                        row_card_sel_tests = self.STYLE_DISABLED
-                        row_btns_sel_tests = self.STYLE_DISABLED
-                        store_sel = list()
-                        ctrl_panel.set({"cl-selected-options": list()})
 
             if ctrl_panel.get("cl-core-value") and \
                     ctrl_panel.get("cl-framesize-value") and \
 
             if ctrl_panel.get("cl-core-value") and \
                     ctrl_panel.get("cl-framesize-value") and \
@@ -1360,108 +1446,49 @@ class Layout:
                 disabled = False
             else:
                 disabled = True
                 disabled = False
             else:
                 disabled = True
-            ctrl_panel.set({"btn-add-disabled": disabled})
+            ctrl_panel.set({
+                "btn-add-disabled": disabled,
+                "cl-normalize-value": norm
+            })
 
             ret_val = [
                 ctrl_panel.panel, store_sel,
 
             ret_val = [
                 ctrl_panel.panel, store_sel,
-                row_fig_tput, row_fig_tsa, row_table, row_btn_dwnld,
+                row_fig_tput, row_fig_lat, row_table, row_btn_dwnld,
                 row_card_sel_tests, row_btns_sel_tests
             ]
             ret_val.extend(ctrl_panel.values())
             return ret_val
 
                 row_card_sel_tests, row_btns_sel_tests
             ]
             ret_val.extend(ctrl_panel.values())
             return ret_val
 
-        # @app.callback(
-        #     Output("metadata-tput-lat", "children"),
-        #     Output("metadata-hdrh-graph", "children"),
-        #     Output("offcanvas-metadata", "is_open"),
-        #     Input({"type": "graph", "index": ALL}, "clickData"),
-        #     prevent_initial_call=True
-        # )
-        # def _show_metadata_from_graphs(graph_data: dict) -> tuple:
-        #     """
-        #     """
-        #     try:
-        #         trigger_id = loads(
-        #             callback_context.triggered[0]["prop_id"].split(".")[0]
-        #         )["index"]
-        #         idx = 0 if trigger_id == "tput" else 1
-        #         graph_data = graph_data[idx]["points"][0]
-        #     except (JSONDecodeError, IndexError, KeyError, ValueError,
-        #             TypeError):
-        #         raise PreventUpdate
-
-        #     metadata = no_update
-        #     graph = list()
-
-        #     children = [
-        #         dbc.ListGroupItem(
-        #             [dbc.Badge(x.split(":")[0]), x.split(": ")[1]]
-        #         ) for x in graph_data.get("text", "").split("<br>")
-        #     ]
-        #     if trigger_id == "tput":
-        #         title = "Throughput"
-        #     elif trigger_id == "lat":
-        #         title = "Latency"
-        #         hdrh_data = graph_data.get("customdata", None)
-        #         if hdrh_data:
-        #             graph = [dbc.Card(
-        #                 class_name="gy-2 p-0",
-        #                 children=[
-        #                     dbc.CardHeader(hdrh_data.pop("name")),
-        #                     dbc.CardBody(children=[
-        #                         dcc.Graph(
-        #                             id="hdrh-latency-graph",
-        #                             figure=graph_hdrh_latency(
-        #                                 hdrh_data, self.layout
-        #                             )
-        #                         )
-        #                     ])
-        #                 ])
-        #             ]
-        #     metadata = [
-        #         dbc.Card(
-        #             class_name="gy-2 p-0",
-        #             children=[
-        #                 dbc.CardHeader(children=[
-        #                     dcc.Clipboard(
-        #                         target_id="tput-lat-metadata",
-        #                         title="Copy",
-        #                         style={"display": "inline-block"}
-        #                     ),
-        #                     title
-        #                 ]),
-        #                 dbc.CardBody(
-        #                     id="tput-lat-metadata",
-        #                     class_name="p-0",
-        #                     children=[dbc.ListGroup(children, flush=True), ]
-        #                 )
-        #             ]
-        #         )
-        #     ]
-
-        #     return metadata, graph, True
-
-        # @app.callback(
-        #     Output("download-data", "data"),
-        #     State("selected-tests", "data"),
-        #     Input("btn-download-data", "n_clicks"),
-        #     prevent_initial_call=True
-        # )
-        # def _download_data(store_sel, n_clicks):
-        #     """
-        #     """
-
-        #     if not n_clicks:
-        #         raise PreventUpdate
-
-        #     if not store_sel:
-        #         raise PreventUpdate
-
-        #     df = pd.DataFrame()
-        #     for itm in store_sel:
-        #         sel_data = select_trending_data(self.data, itm)
-        #         if sel_data is None:
-        #             continue
-        #         df = pd.concat([df, sel_data], ignore_index=True)
-
-        #     return dcc.send_data_frame(df.to_csv, "trending_data.csv")
+        @app.callback(
+            Output("download-data", "data"),
+            State("selected-tests", "data"),
+            Input("btn-download-data", "n_clicks"),
+            prevent_initial_call=True
+        )
+        def _download_data(store_sel, n_clicks):
+            """Download the data
+
+            :param store_sel: List of tests selected by user stored in the
+                browser.
+            :param n_clicks: Number of clicks on the button "Download".
+            :type store_sel: list
+            :type n_clicks: int
+            :returns: dict of data frame content (base64 encoded) and meta data
+                used by the Download component.
+            :rtype: dict
+            """
+
+            if not n_clicks:
+                raise PreventUpdate
+
+            if not store_sel:
+                raise PreventUpdate
+
+            df = pd.DataFrame()
+            for itm in store_sel:
+                sel_data = select_iterative_data(self.data, itm)
+                if sel_data is None:
+                    continue
+                df = pd.concat([df, sel_data], ignore_index=True)
+
+            return dcc.send_data_frame(df.to_csv, C.REPORT_DOWNLOAD_FILE_NAME)