-# Copyright (c) 2023 Cisco and/or its affiliates.
+# Copyright (c) 2024 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
"""Plotly Dash HTML layout override.
"""
+
import logging
import pandas as pd
import dash_bootstrap_components as dbc
from ..utils.control_panel import ControlPanel
from ..utils.trigger import Trigger
from ..utils.utils import show_tooltip, label, sync_checklists, gen_new_url, \
- generate_options, get_list_group_items
+ generate_options, get_list_group_items, navbar_report, \
+ show_iterative_graph_data
from ..utils.url_processing import url_decode
-from ..data.data import Data
from .graphs import graph_iterative, select_iterative_data
"""The layout of the dash app and the callbacks.
"""
- 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,
+ data_iterative: pd.DataFrame,
+ html_layout_file: str,
+ graph_layout_file: str,
+ tooltip_file: str
+ ) -> None:
"""Initialization:
- save the input parameters,
- read and pre-process the data,
- 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
self._app = app
- self.releases = releases
self._html_layout_file = html_layout_file
self._graph_layout_file = graph_layout_file
- self._data_spec_file = data_spec_file
self._tooltip_file = tooltip_file
-
- # Read the data:
- self._data = pd.DataFrame()
- for rls in releases:
- data_mrr = Data(self._data_spec_file, True).\
- read_iterative_mrr(release=rls)
- data_mrr["release"] = rls
- data_ndrpdr = Data(self._data_spec_file, True).\
- read_iterative_ndrpdr(release=rls)
- data_ndrpdr["release"] = rls
- self._data = pd.concat(
- [self._data, data_mrr, data_ndrpdr],
- ignore_index=True
- )
+ self._data = data_iterative
# Get structure of tests:
tbs = dict()
- cols = ["job", "test_id", "test_type", "dut_version", "release"]
+ cols = [
+ "job", "test_id", "test_type", "dut_version", "tg_type", "release"
+ ]
for _, row in self._data[cols].drop_duplicates().iterrows():
rls = row["release"]
- ttype = row["test_type"]
lst_job = row["job"].split("-")
dut = lst_job[1]
d_ver = row["dut_version"]
if dut == "dpdk":
area = "dpdk"
else:
- area = "-".join(lst_test_id[3:-2])
+ area = ".".join(lst_test_id[3:-2])
suite = lst_test_id[-2].replace("2n1l-", "").replace("1n1l-", "").\
replace("2n-", "")
test = lst_test_id[-1]
tbs[rls][dut] = dict()
if tbs[rls][dut].get(d_ver, None) is None:
tbs[rls][dut][d_ver] = dict()
- if tbs[rls][dut][d_ver].get(infra, None) is None:
- tbs[rls][dut][d_ver][infra] = dict()
- if tbs[rls][dut][d_ver][infra].get(area, None) is None:
- 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][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 "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":
- 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", )
- )
+ if tbs[rls][dut][d_ver].get(area, None) is None:
+ tbs[rls][dut][d_ver][area] = dict()
+ if tbs[rls][dut][d_ver][area].get(test, None) is None:
+ tbs[rls][dut][d_ver][area][test] = dict()
+ if tbs[rls][dut][d_ver][area][test].get(infra, None) is None:
+ tbs[rls][dut][d_ver][area][test][infra] = {
+ "core": list(),
+ "frame-size": list(),
+ "test-type": list()
+ }
+ tst_params = tbs[rls][dut][d_ver][area][test][infra]
+ if core.upper() not in tst_params["core"]:
+ tst_params["core"].append(core.upper())
+ if framesize.upper() not in tst_params["frame-size"]:
+ tst_params["frame-size"].append(framesize.upper())
+ if row["test_type"] == "ndrpdr":
+ if "NDR" not in tst_params["test-type"]:
+ tst_params["test-type"].extend(("NDR", "PDR", ))
+ elif row["test_type"] == "hoststack" and \
+ row["tg_type"] in ("iperf", "vpp"):
+ if "BPS" not in tst_params["test-type"]:
+ tst_params["test-type"].append("BPS")
+ elif row["test_type"] == "hoststack" and row["tg_type"] == "ab":
+ if "CPS" not in tst_params["test-type"]:
+ tst_params["test-type"].extend(("CPS", "RPS"))
+ else: # MRR, SOAK
+ if row["test_type"].upper() not in tst_params["test-type"]:
+ tst_params["test-type"].append(row["test_type"].upper())
self._spec_tbs = tbs
# Read from files:
dbc.Row(
id="row-navbar",
class_name="g-0",
- children=[
- self._add_navbar()
- ]
+ children=[navbar_report((True, False, False, False)), ]
),
dbc.Row(
id="row-main",
self._add_ctrl_col(),
self._add_plotting_col()
]
+ ),
+ dbc.Spinner(
+ dbc.Offcanvas(
+ class_name="w-50",
+ id="offcanvas-metadata",
+ title="Throughput And Latency",
+ placement="end",
+ is_open=False,
+ children=[
+ dbc.Row(id="metadata-tput-lat"),
+ dbc.Row(id="metadata-hdrh-graph")
+ ]
+ ),
+ delay_show=C.SPINNER_DELAY
+ ),
+ dbc.Offcanvas(
+ class_name="w-75",
+ id="offcanvas-documentation",
+ title="Documentation",
+ placement="end",
+ is_open=False,
+ children=html.Iframe(
+ src=C.URL_DOC_REL_NOTES,
+ width="100%",
+ height="100%"
+ )
)
]
)
]
)
- 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",
- children=[
- dbc.NavItem(
- dbc.NavLink(
- C.REPORT_TITLE,
- disabled=True,
- external_link=True,
- href="#"
- )
- )
- ],
- brand=C.BRAND,
- brand_href="/",
- brand_external_link=True,
- class_name="p-2",
- fluid=True
- )
-
def _add_ctrl_col(self) -> dbc.Col:
"""Add column with controls. It is placed on the left side.
return dbc.Col(
id="col-plotting-area",
children=[
- dcc.Loading(
+ dbc.Spinner(
children=[
dbc.Row(
id="plotting-area",
:returns: Control panel.
:rtype: list
"""
- return [
+ test_selection = [
dbc.Row(
class_name="g-0 p-1",
children=[
dbc.InputGroup(
[
- dbc.InputGroupText(
- children=show_tooltip(
- self._tooltips,
- "help-release",
- "CSIT Release"
- )
- ),
+ dbc.InputGroupText(show_tooltip(
+ self._tooltips,
+ "help-release",
+ "CSIT Release"
+ )),
dbc.Select(
id={"type": "ctrl-dd", "index": "rls"},
placeholder="Select a Release...",
children=[
dbc.InputGroup(
[
- dbc.InputGroupText(
- children=show_tooltip(
- self._tooltips,
- "help-dut",
- "DUT"
- )
- ),
+ dbc.InputGroupText(show_tooltip(
+ self._tooltips,
+ "help-dut",
+ "DUT"
+ )),
dbc.Select(
id={"type": "ctrl-dd", "index": "dut"},
placeholder="Select a Device under Test..."
children=[
dbc.InputGroup(
[
- dbc.InputGroupText(
- children=show_tooltip(
- self._tooltips,
- "help-dut-ver",
- "DUT Version"
- )
- ),
+ dbc.InputGroupText(show_tooltip(
+ self._tooltips,
+ "help-dut-ver",
+ "DUT Version"
+ )),
dbc.Select(
id={"type": "ctrl-dd", "index": "dutver"},
placeholder=\
children=[
dbc.InputGroup(
[
- dbc.InputGroupText(
- children=show_tooltip(
- self._tooltips,
- "help-infra",
- "Infra"
- )
- ),
+ dbc.InputGroupText(show_tooltip(
+ self._tooltips,
+ "help-area",
+ "Area"
+ )),
dbc.Select(
- id={"type": "ctrl-dd", "index": "phy"},
- placeholder=\
- "Select a Physical Test Bed Topology..."
+ id={"type": "ctrl-dd", "index": "area"},
+ placeholder="Select an Area..."
)
],
size="sm"
children=[
dbc.InputGroup(
[
- dbc.InputGroupText(
- children=show_tooltip(
- self._tooltips,
- "help-area",
- "Area"
- )
- ),
+ dbc.InputGroupText(show_tooltip(
+ self._tooltips,
+ "help-test",
+ "Test"
+ )),
dbc.Select(
- id={"type": "ctrl-dd", "index": "area"},
- placeholder="Select an Area..."
+ id={"type": "ctrl-dd", "index": "test"},
+ placeholder="Select a Test..."
)
],
size="sm"
children=[
dbc.InputGroup(
[
- dbc.InputGroupText(
- children=show_tooltip(
- self._tooltips,
- "help-test",
- "Test"
- )
- ),
+ dbc.InputGroupText(show_tooltip(
+ self._tooltips,
+ "help-infra",
+ "Infra"
+ )),
dbc.Select(
- id={"type": "ctrl-dd", "index": "test"},
- placeholder="Select a Test..."
+ id={"type": "ctrl-dd", "index": "phy"},
+ placeholder=\
+ "Select a Physical Test Bed Topology..."
)
],
size="sm"
dbc.Row(
class_name="g-0 p-1",
children=[
- dbc.InputGroup(
- [
- dbc.InputGroupText(
- children=show_tooltip(
- self._tooltips,
- "help-normalize",
- "Normalization"
- )
- ),
- dbc.Col(
- children=[
- dbc.Checklist(
- id="normalize",
- options=[{
- "value": "normalize",
- "label": (
- "Normalize to CPU frequency "
- "2GHz"
- )
- }],
- value=[],
- inline=True,
- class_name="ms-2"
- )
- ]
- )
- ],
- style={"align-items": "center"},
- size="sm"
+ dbc.Button(
+ id={"type": "ctrl-btn", "index": "add-test"},
+ children="Add Selected",
+ color="info",
+ class_name="p-1"
)
]
- ),
+ )
+ ]
+ processing = [
dbc.Row(
class_name="g-0 p-1",
children=[
- dbc.Button(
- id={"type": "ctrl-btn", "index": "add-test"},
- children="Add Selected",
- color="info"
+ dbc.Checklist(
+ id="normalize",
+ options=[{
+ "value": "normalize",
+ "label": "Normalize to 2GHz CPU frequency"
+ }],
+ value=[],
+ inline=True,
+ class_name="ms-2"
)
]
- ),
+ )
+ ]
+ test_list = [
dbc.Row(
id="row-card-sel-tests",
class_name="g-0 p-1",
- style=C.STYLE_DISABLED,
children=[
dbc.ListGroup(
class_name="overflow-auto p-0",
id="lg-selected",
children=[],
- style={"max-height": "14em"},
+ style={"max-height": "20em"},
flush=True
)
]
),
- dbc.Row(
+ dbc.Stack(
id="row-btns-sel-tests",
class_name="g-0 p-1",
- style=C.STYLE_DISABLED,
+ gap=2,
children=[
- dbc.ButtonGroup(
- children=[
- dbc.Button(
- id={"type": "ctrl-btn", "index": "rm-test"},
- children="Remove Selected",
- class_name="w-100",
- color="info",
- disabled=False
- ),
- dbc.Button(
- id={"type": "ctrl-btn", "index": "rm-test-all"},
- children="Remove All",
- class_name="w-100",
- color="info",
- disabled=False
- )
- ]
- )
+ dbc.ButtonGroup(children=[
+ dbc.Button(
+ id={"type": "ctrl-btn", "index": "rm-test"},
+ children="Remove Selected",
+ class_name="w-100 p-1",
+ color="info",
+ disabled=False
+ ),
+ dbc.Button(
+ id={"type": "ctrl-btn", "index": "rm-test-all"},
+ children="Remove All",
+ class_name="w-100 p-1",
+ color="info",
+ disabled=False
+ )
+ ]),
+ dbc.ButtonGroup(children=[
+ dbc.Button(
+ id="plot-btn-url",
+ children="Show URL",
+ class_name="w-100 p-1",
+ color="info",
+ disabled=False
+ ),
+ dbc.Button(
+ id="plot-btn-download",
+ children="Download Data",
+ class_name="w-100 p-1",
+ color="info",
+ disabled=False
+ )
+ ])
]
)
]
+ return [
+ dbc.Row(
+ dbc.Card(
+ [
+ dbc.CardHeader(
+ html.H5("Test Selection")
+ ),
+ dbc.CardBody(
+ children=test_selection,
+ class_name="g-0 p-0"
+ )
+ ],
+ color="secondary",
+ outline=True
+ ),
+ class_name="g-0 p-1"
+ ),
+ dbc.Row(
+ dbc.Card(
+ [
+ dbc.CardHeader(
+ html.H5("Data Manipulations")
+ ),
+ dbc.CardBody(
+ children=processing,
+ class_name="g-0 p-0"
+ )
+ ],
+ color="secondary",
+ outline=True
+ ),
+ class_name="g-0 p-1"
+ ),
+ dbc.Row(
+ dbc.Card(
+ [
+ dbc.CardHeader(
+ html.H5("Selected Tests")
+ ),
+ dbc.CardBody(
+ children=test_list,
+ class_name="g-0 p-0"
+ )
+ ],
+ color="secondary",
+ outline=True
+ ),
+ id = "row-selected-tests",
+ class_name="g-0 p-1",
+ style=C.STYLE_DISABLED,
+ )
+ ]
+
def _get_plotting_area(
self,
tests: list,
if not tests:
return C.PLACEHOLDER
- figs = graph_iterative(self._data, tests, self._graph_layout, normalize)
+ graphs = \
+ graph_iterative(self._data, tests, self._graph_layout, normalize)
- if not figs[0]:
+ if not graphs[0]:
return C.PLACEHOLDER
-
- row_items = [
- dbc.Col(
+
+ tab_items = [
+ dbc.Tab(
children=dcc.Graph(
id={"type": "graph", "index": "tput"},
- figure=figs[0]
+ figure=graphs[0]
),
- class_name="g-0 p-1",
- width=6
+ label="Throughput",
+ tab_id="tab-tput"
)
]
- if figs[1]:
- row_items.append(
- dbc.Col(
+ if graphs[1]:
+ tab_items.append(
+ dbc.Tab(
+ children=dcc.Graph(
+ id={"type": "graph", "index": "bandwidth"},
+ figure=graphs[1]
+ ),
+ label="Bandwidth",
+ tab_id="tab-bandwidth"
+ )
+ )
+
+ if graphs[2]:
+ tab_items.append(
+ dbc.Tab(
children=dcc.Graph(
id={"type": "graph", "index": "lat"},
- figure=figs[1]
+ figure=graphs[2]
),
- class_name="g-0 p-1",
- width=6
+ label="Latency",
+ tab_id="tab-lat"
)
)
return [
dbc.Row(
- children=row_items,
- class_name="g-0 p-0",
+ dbc.Tabs(
+ children=tab_items,
+ id="tabs",
+ active_tab="tab-tput",
+ ),
+ class_name="g-0 p-0"
),
- dbc.Row(
+ dbc.Modal(
[
- dbc.Col([html.Div(
- [
- dbc.Button(
- id="plot-btn-url",
- children="Show URL",
- class_name="me-1",
- color="info",
- style={
- "text-transform": "none",
- "padding": "0rem 1rem"
- }
- ),
- dbc.Modal(
- [
- dbc.ModalHeader(dbc.ModalTitle("URL")),
- dbc.ModalBody(url)
- ],
- id="plot-mod-url",
- size="xl",
- is_open=False,
- scrollable=True
- ),
- dbc.Button(
- id="plot-btn-download",
- children="Download Data",
- class_name="me-1",
- color="info",
- style={
- "text-transform": "none",
- "padding": "0rem 1rem"
- }
- ),
- dcc.Download(id="download-iterative-data")
- ],
- className=\
- "d-grid gap-0 d-md-flex justify-content-md-end"
- )])
+ dbc.ModalHeader(dbc.ModalTitle("URL")),
+ dbc.ModalBody(url)
],
- class_name="g-0 p-0"
- )
+ id="plot-mod-url",
+ size="xl",
+ is_open=False,
+ scrollable=True
+ ),
+ dcc.Download(id="download-iterative-data")
]
def callbacks(self, app):
Output("store-control-panel", "data"),
Output("store-selected-tests", "data"),
Output("plotting-area", "children"),
- Output("row-card-sel-tests", "style"),
- Output("row-btns-sel-tests", "style"),
+ Output("row-selected-tests", "style"),
Output("lg-selected", "children"),
Output({"type": "ctrl-dd", "index": "rls"}, "value"),
url_params = None
plotting_area = no_update
- row_card_sel_tests = no_update
- row_btns_sel_tests = no_update
+ row_sel_tests = no_update
lg_selected = no_update
trigger = Trigger(callback_context.triggered)
try:
store_sel = literal_eval(url_params["store_sel"][0])
normalize = literal_eval(url_params["norm"][0])
- except (KeyError, IndexError):
+ except (KeyError, IndexError, AttributeError):
pass
if store_sel:
- row_card_sel_tests = C.STYLE_ENABLED
- row_btns_sel_tests = C.STYLE_ENABLED
+ row_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"]]
+ [last_test["dutver"]][last_test["area"]]\
+ [last_test["test"]][last_test["phy"]]
ctrl_panel.set({
"dd-rls-val": last_test["rls"],
"dd-dut-val": last_test["dut"],
[last_test["dut"]].keys()
),
"dd-dutver-dis": False,
- "dd-phy-val": last_test["phy"],
- "dd-phy-opt": generate_options(
- self._spec_tbs[last_test["rls"]][last_test["dut"]]\
- [last_test["dutver"]].keys()
- ),
- "dd-phy-dis": False,
"dd-area-val": last_test["area"],
"dd-area-opt": [
{"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())
+ [last_test["dut"]]\
+ [last_test["dutver"]].keys())
],
"dd-area-dis": False,
"dd-test-val": last_test["test"],
"dd-test-opt": generate_options(
self._spec_tbs[last_test["rls"]][last_test["dut"]]\
- [last_test["dutver"]][last_test["phy"]]\
- [last_test["area"]].keys()
+ [last_test["dutver"]][last_test["area"]].keys()
),
"dd-test-dis": False,
+ "dd-phy-val": last_test["phy"],
+ "dd-phy-opt": generate_options(
+ self._spec_tbs[last_test["rls"]][last_test["dut"]]\
+ [last_test["dutver"]][last_test["area"]]\
+ [last_test["test"]].keys()
+ ),
+ "dd-phy-dis": False,
"cl-core-opt": generate_options(test["core"]),
"cl-core-val": [last_test["core"].upper(), ],
"cl-core-all-val": list(),
rls = ctrl_panel.get("dd-rls-val")
dut = ctrl_panel.get("dd-dut-val")
dutver = self._spec_tbs[rls][dut][trigger.value]
- options = generate_options(dutver.keys())
+ options = [{"label": label(v), "value": v} \
+ for v in sorted(dutver.keys())]
disabled = False
except KeyError:
options = list()
disabled = True
ctrl_panel.set({
"dd-dutver-val": trigger.value,
- "dd-phy-val": str(),
- "dd-phy-opt": options,
- "dd-phy-dis": disabled,
"dd-area-val": str(),
- "dd-area-opt": list(),
- "dd-area-dis": True,
+ "dd-area-opt": options,
+ "dd-area-dis": disabled,
"dd-test-val": str(),
"dd-test-opt": list(),
"dd-test-dis": True,
+ "dd-phy-val": str(),
+ "dd-phy-opt": list(),
+ "dd-phy-dis": True,
"cl-core-opt": list(),
"cl-core-val": list(),
"cl-core-all-val": list(),
"cl-tsttype-all-opt": C.CL_ALL_DISABLED,
"btn-add-dis": True
})
- elif trigger.idx == "phy":
+ elif trigger.idx == "area":
try:
rls = ctrl_panel.get("dd-rls-val")
dut = ctrl_panel.get("dd-dut-val")
dutver = ctrl_panel.get("dd-dutver-val")
- phy = self._spec_tbs[rls][dut][dutver][trigger.value]
- options = [{"label": label(v), "value": v} \
- for v in sorted(phy.keys())]
+ area = self._spec_tbs[rls][dut][dutver][trigger.value]
+ options = generate_options(area.keys())
disabled = False
except KeyError:
options = list()
disabled = True
ctrl_panel.set({
- "dd-phy-val": trigger.value,
- "dd-area-val": str(),
- "dd-area-opt": options,
- "dd-area-dis": disabled,
+ "dd-area-val": trigger.value,
"dd-test-val": str(),
- "dd-test-opt": list(),
- "dd-test-dis": True,
+ "dd-test-opt": options,
+ "dd-test-dis": disabled,
+ "dd-phy-val": str(),
+ "dd-phy-opt": list(),
+ "dd-phy-dis": True,
"cl-core-opt": list(),
"cl-core-val": list(),
"cl-core-all-val": list(),
"cl-tsttype-all-opt": C.CL_ALL_DISABLED,
"btn-add-dis": True
})
- elif trigger.idx == "area":
+ elif trigger.idx == "test":
try:
rls = ctrl_panel.get("dd-rls-val")
dut = ctrl_panel.get("dd-dut-val")
dutver = ctrl_panel.get("dd-dutver-val")
- phy = ctrl_panel.get("dd-phy-val")
- area = \
- self._spec_tbs[rls][dut][dutver][phy][trigger.value]
- options = generate_options(area.keys())
+ area = ctrl_panel.get("dd-area-val")
+ test = self._spec_tbs[rls][dut][dutver][area]\
+ [trigger.value]
+ options = generate_options(test.keys())
disabled = False
except KeyError:
options = list()
disabled = True
ctrl_panel.set({
- "dd-area-val": trigger.value,
- "dd-test-val": str(),
- "dd-test-opt": options,
- "dd-test-dis": disabled,
+ "dd-test-val": trigger.value,
+ "dd-phy-val": str(),
+ "dd-phy-opt": options,
+ "dd-phy-dis": disabled,
"cl-core-opt": list(),
"cl-core-val": list(),
"cl-core-all-val": list(),
"cl-tsttype-all-opt": C.CL_ALL_DISABLED,
"btn-add-dis": True
})
- elif trigger.idx == "test":
+ elif trigger.idx == "phy":
rls = ctrl_panel.get("dd-rls-val")
dut = ctrl_panel.get("dd-dut-val")
dutver = ctrl_panel.get("dd-dutver-val")
- phy = ctrl_panel.get("dd-phy-val")
area = ctrl_panel.get("dd-area-val")
- if all((rls, dut, dutver, phy, area, trigger.value, )):
- test = self._spec_tbs[rls][dut][dutver][phy][area]\
+ test = ctrl_panel.get("dd-test-val")
+ if all((rls, dut, dutver, area, test, trigger.value, )):
+ phy = self._spec_tbs[rls][dut][dutver][area][test]\
[trigger.value]
ctrl_panel.set({
- "dd-test-val": trigger.value,
- "cl-core-opt": generate_options(test["core"]),
+ "dd-phy-val": trigger.value,
+ "cl-core-opt": generate_options(phy["core"]),
"cl-core-val": list(),
"cl-core-all-val": list(),
"cl-core-all-opt": C.CL_ALL_ENABLED,
"cl-frmsize-opt": \
- generate_options(test["frame-size"]),
+ generate_options(phy["frame-size"]),
"cl-frmsize-val": list(),
"cl-frmsize-all-val": list(),
"cl-frmsize-all-opt": C.CL_ALL_ENABLED,
"cl-tsttype-opt": \
- generate_options(test["test-type"]),
+ generate_options(phy["test-type"]),
"cl-tsttype-val": list(),
"cl-tsttype-all-val": list(),
"cl-tsttype-all-opt": C.CL_ALL_ENABLED,
if on_draw:
if store_sel:
- lg_selected = get_list_group_items(store_sel)
+ lg_selected = get_list_group_items(
+ store_sel, "sel-cl", add_index=True
+ )
plotting_area = self._get_plotting_area(
store_sel,
bool(normalize),
{"store_sel": store_sel, "norm": normalize}
)
)
- row_card_sel_tests = C.STYLE_ENABLED
- row_btns_sel_tests = C.STYLE_ENABLED
+ row_sel_tests = C.STYLE_ENABLED
else:
plotting_area = C.PLACEHOLDER
- row_card_sel_tests = C.STYLE_DISABLED
- row_btns_sel_tests = C.STYLE_DISABLED
+ row_sel_tests = C.STYLE_DISABLED
store_sel = list()
ret_val = [
ctrl_panel.panel,
store_sel,
plotting_area,
- row_card_sel_tests,
- row_btns_sel_tests,
+ row_sel_tests,
lg_selected
]
ret_val.extend(ctrl_panel.values)
@app.callback(
Output("plot-mod-url", "is_open"),
- [Input("plot-btn-url", "n_clicks")],
- [State("plot-mod-url", "is_open")],
+ Output("plot-btn-url", "n_clicks"),
+ Input("plot-btn-url", "n_clicks"),
+ State("plot-mod-url", "is_open")
)
def toggle_plot_mod_url(n, is_open):
"""Toggle the modal window with url.
"""
if n:
- return not is_open
- return is_open
+ return not is_open, 0
+ return is_open, 0
@app.callback(
Output("download-iterative-data", "data"),
Input("plot-btn-download", "n_clicks"),
prevent_initial_call=True
)
- def _download_trending_data(store_sel, _):
+ def _download_iterative_data(store_sel, _):
"""Download the data
:param store_sel: List of tests selected by user stored in the
df = pd.concat([df, sel_data], ignore_index=True)
return dcc.send_data_frame(df.to_csv, C.REPORT_DOWNLOAD_FILE_NAME)
+
+ @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:
+ """Generates the data for the offcanvas displayed when a particular
+ point in a graph is clicked on.
+
+ :param graph_data: The data from the clicked point in the graph.
+ :type graph_data: dict
+ :returns: The data to be displayed on the offcanvas and the
+ information to show the offcanvas.
+ :rtype: tuple(list, list, bool)
+ """
+
+ trigger = Trigger(callback_context.triggered)
+ if not trigger.value:
+ raise PreventUpdate
+
+ return show_iterative_graph_data(
+ trigger, graph_data, self._graph_layout)
+
+ @app.callback(
+ Output("offcanvas-documentation", "is_open"),
+ Input("btn-documentation", "n_clicks"),
+ State("offcanvas-documentation", "is_open")
+ )
+ def toggle_offcanvas_documentation(n_clicks, is_open):
+ if n_clicks:
+ return not is_open
+ return is_open