1 # Copyright (c) 2022 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
14 """Plotly Dash HTML layout override.
19 import dash_bootstrap_components as dbc
21 from flask import Flask
24 from dash import callback_context, no_update, ALL
25 from dash import Input, Output, State
26 from dash.exceptions import PreventUpdate
27 from yaml import load, FullLoader, YAMLError
28 from ast import literal_eval
30 from ..utils.constants import Constants as C
31 from ..utils.control_panel import ControlPanel
32 from ..utils.trigger import Trigger
33 from ..utils.utils import show_tooltip, label, sync_checklists, gen_new_url, \
34 generate_options, get_list_group_items
35 from ..utils.url_processing import url_decode
36 from ..data.data import Data
37 from .graphs import graph_iterative, get_short_version, select_iterative_data
40 # Control panel partameters and their default values.
46 "dd-dutver-opt": list(),
47 "dd-dutver-dis": True,
48 "dd-dutver-val": str(),
52 "dd-area-opt": list(),
55 "dd-test-opt": list(),
58 "cl-core-opt": list(),
59 "cl-core-val": list(),
60 "cl-core-all-val": list(),
61 "cl-core-all-opt": C.CL_ALL_DISABLED,
62 "cl-frmsize-opt": list(),
63 "cl-frmsize-val": list(),
64 "cl-frmsize-all-val": list(),
65 "cl-frmsize-all-opt": C.CL_ALL_DISABLED,
66 "cl-tsttype-opt": list(),
67 "cl-tsttype-val": list(),
68 "cl-tsttype-all-val": list(),
69 "cl-tsttype-all-opt": C.CL_ALL_DISABLED,
71 "cl-normalize-val": list()
76 """The layout of the dash app and the callbacks.
79 def __init__(self, app: Flask, releases: list, html_layout_file: str,
80 graph_layout_file: str, data_spec_file: str, tooltip_file: str) -> None:
82 - save the input parameters,
83 - read and pre-process the data,
84 - prepare data for the control panel,
85 - read HTML layout file,
86 - read tooltips from the tooltip file.
88 :param app: Flask application running the dash application.
89 :param releases: Lis of releases to be displayed.
90 :param html_layout_file: Path and name of the file specifying the HTML
91 layout of the dash application.
92 :param graph_layout_file: Path and name of the file with layout of
94 :param data_spec_file: Path and name of the file specifying the data to
95 be read from parquets for this application.
96 :param tooltip_file: Path and name of the yaml file specifying the
100 :type html_layout_file: str
101 :type graph_layout_file: str
102 :type data_spec_file: str
103 :type tooltip_file: str
108 self.releases = releases
109 self._html_layout_file = html_layout_file
110 self._graph_layout_file = graph_layout_file
111 self._data_spec_file = data_spec_file
112 self._tooltip_file = tooltip_file
115 self._data = pd.DataFrame()
117 data_mrr = Data(self._data_spec_file, True).\
118 read_iterative_mrr(release=rls.replace("csit", "rls"))
119 data_mrr["release"] = rls
120 data_ndrpdr = Data(self._data_spec_file, True).\
121 read_iterative_ndrpdr(release=rls.replace("csit", "rls"))
122 data_ndrpdr["release"] = rls
123 self._data = pd.concat(
124 [self._data, data_mrr, data_ndrpdr],
128 # Get structure of tests:
130 cols = ["job", "test_id", "test_type", "dut_version", "release"]
131 for _, row in self._data[cols].drop_duplicates().iterrows():
133 ttype = row["test_type"]
134 lst_job = row["job"].split("-")
136 d_ver = get_short_version(row["dut_version"], dut)
137 tbed = "-".join(lst_job[-2:])
138 lst_test_id = row["test_id"].split(".")
142 area = "-".join(lst_test_id[3:-2])
143 suite = lst_test_id[-2].replace("2n1l-", "").replace("1n1l-", "").\
145 test = lst_test_id[-1]
146 nic = suite.split("-")[0]
147 for drv in C.DRIVERS:
149 driver = drv.replace("-", "_")
150 test = test.replace(f"{drv}-", "")
154 infra = "-".join((tbed, nic, driver))
155 lst_test = test.split("-")
156 framesize = lst_test[0]
157 core = lst_test[1] if lst_test[1] else "8C"
158 test = "-".join(lst_test[2: -1])
160 if tbs.get(rls, None) is None:
162 if tbs[rls].get(dut, None) is None:
163 tbs[rls][dut] = dict()
164 if tbs[rls][dut].get(d_ver, None) is None:
165 tbs[rls][dut][d_ver] = dict()
166 if tbs[rls][dut][d_ver].get(infra, None) is None:
167 tbs[rls][dut][d_ver][infra] = dict()
168 if tbs[rls][dut][d_ver][infra].get(area, None) is None:
169 tbs[rls][dut][d_ver][infra][area] = dict()
170 if tbs[rls][dut][d_ver][infra][area].get(test, None) is None:
171 tbs[rls][dut][d_ver][infra][area][test] = dict()
172 tbs[rls][dut][d_ver][infra][area][test]["core"] = list()
173 tbs[rls][dut][d_ver][infra][area][test]["frame-size"] = list()
174 tbs[rls][dut][d_ver][infra][area][test]["test-type"] = list()
175 if core.upper() not in \
176 tbs[rls][dut][d_ver][infra][area][test]["core"]:
177 tbs[rls][dut][d_ver][infra][area][test]["core"].append(
180 if framesize.upper() not in \
181 tbs[rls][dut][d_ver][infra][area][test]["frame-size"]:
182 tbs[rls][dut][d_ver][infra][area][test]["frame-size"].append(
187 tbs[rls][dut][d_ver][infra][area][test]["test-type"]:
188 tbs[rls][dut][d_ver][infra][area][test]["test-type"].append(
191 elif ttype == "ndrpdr":
193 tbs[rls][dut][d_ver][infra][area][test]["test-type"]:
194 tbs[rls][dut][d_ver][infra][area][test]["test-type"].extend(
200 self._html_layout = str()
201 self._graph_layout = None
202 self._tooltips = dict()
205 with open(self._html_layout_file, "r") as file_read:
206 self._html_layout = file_read.read()
207 except IOError as err:
209 f"Not possible to open the file {self._html_layout_file}\n{err}"
213 with open(self._graph_layout_file, "r") as file_read:
214 self._graph_layout = load(file_read, Loader=FullLoader)
215 except IOError as err:
217 f"Not possible to open the file {self._graph_layout_file}\n"
220 except YAMLError as err:
222 f"An error occurred while parsing the specification file "
223 f"{self._graph_layout_file}\n{err}"
227 with open(self._tooltip_file, "r") as file_read:
228 self._tooltips = load(file_read, Loader=FullLoader)
229 except IOError as err:
231 f"Not possible to open the file {self._tooltip_file}\n{err}"
233 except YAMLError as err:
235 f"An error occurred while parsing the specification file "
236 f"{self._tooltip_file}\n{err}"
240 if self._app is not None and hasattr(self, "callbacks"):
241 self.callbacks(self._app)
244 def html_layout(self):
245 return self._html_layout
247 def add_content(self):
248 """Top level method which generated the web page.
251 - Store for user input data,
253 - Main area with control panel and ploting area.
255 If no HTML layout is provided, an error message is displayed instead.
257 :returns: The HTML div with the whole page.
261 if self.html_layout and self._spec_tbs:
277 dcc.Store(id="store-selected-tests"),
278 dcc.Store(id="store-control-panel"),
279 dcc.Location(id="url", refresh=False),
280 self._add_ctrl_col(),
281 self._add_plotting_col()
299 def _add_navbar(self):
300 """Add nav element with navigation panel. It is placed on the top.
302 :returns: Navigation bar.
303 :rtype: dbc.NavbarSimple
305 return dbc.NavbarSimple(
306 id="navbarsimple-main",
319 brand_external_link=True,
324 def _add_ctrl_col(self) -> dbc.Col:
325 """Add column with controls. It is placed on the left side.
327 :returns: Column with the control panel.
332 children=self._add_ctrl_panel(),
333 className="sticky-top"
337 def _add_plotting_col(self) -> dbc.Col:
338 """Add column with plots. It is placed on the right side.
340 :returns: Column with plots.
344 id="col-plotting-area",
350 class_name="g-0 p-0",
361 def _add_ctrl_panel(self) -> list:
362 """Add control panel.
364 :returns: Control panel.
369 class_name="g-0 p-1",
374 children=show_tooltip(
381 id={"type": "ctrl-dd", "index": "rls"},
382 placeholder="Select a Release...",
385 {"label": k, "value": k} \
386 for k in self._spec_tbs.keys()
388 key=lambda d: d["label"]
397 class_name="g-0 p-1",
402 children=show_tooltip(
409 id={"type": "ctrl-dd", "index": "dut"},
410 placeholder="Select a Device under Test..."
418 class_name="g-0 p-1",
423 children=show_tooltip(
430 id={"type": "ctrl-dd", "index": "dutver"},
432 "Select a Version of Device under Test..."
440 class_name="g-0 p-1",
445 children=show_tooltip(
452 id={"type": "ctrl-dd", "index": "phy"},
454 "Select a Physical Test Bed Topology..."
462 class_name="g-0 p-1",
467 children=show_tooltip(
474 id={"type": "ctrl-dd", "index": "area"},
475 placeholder="Select an Area..."
483 class_name="g-0 p-1",
488 children=show_tooltip(
495 id={"type": "ctrl-dd", "index": "test"},
496 placeholder="Select a Test..."
504 class_name="g-0 p-1",
507 children=show_tooltip(
516 id={"type": "ctrl-cl", "index": "frmsize-all"},
517 options=C.CL_ALL_DISABLED,
520 input_class_name="border-info bg-info"
528 id={"type": "ctrl-cl", "index": "frmsize"},
531 input_class_name="border-info bg-info"
538 class_name="g-0 p-1",
541 children=show_tooltip(
550 id={"type": "ctrl-cl", "index": "core-all"},
551 options=C.CL_ALL_DISABLED,
554 input_class_name="border-info bg-info"
562 id={"type": "ctrl-cl", "index": "core"},
565 input_class_name="border-info bg-info"
572 class_name="g-0 p-1",
575 children=show_tooltip(
584 id={"type": "ctrl-cl", "index": "tsttype-all"},
585 options=C.CL_ALL_DISABLED,
588 input_class_name="border-info bg-info"
596 id={"type": "ctrl-cl", "index": "tsttype"},
599 input_class_name="border-info bg-info"
606 class_name="g-0 p-1",
609 children=show_tooltip(
620 "value": "normalize",
622 "Normalize results to CPU "
629 input_class_name="border-info bg-info"
636 class_name="g-0 p-1",
639 id={"type": "ctrl-btn", "index": "add-test"},
640 children="Add Selected",
646 id="row-card-sel-tests",
647 class_name="g-0 p-1",
648 style=C.STYLE_DISABLED,
651 class_name="overflow-auto p-0",
654 style={"max-height": "14em"},
660 id="row-btns-sel-tests",
661 class_name="g-0 p-1",
662 style=C.STYLE_DISABLED,
667 id={"type": "ctrl-btn", "index": "rm-test"},
668 children="Remove Selected",
674 id={"type": "ctrl-btn", "index": "rm-test-all"},
675 children="Remove All",
686 def _get_plotting_area(
692 """Generate the plotting area with all its content.
694 :param tests: List of tests to be displayed in the graphs.
695 :param normalize: If true, the values in graphs are normalized.
696 :param url: URL to be displayed in the modal window.
698 :type normalize: bool
700 :returns: List of rows with elements to be displayed in the plotting
707 figs = graph_iterative(self._data, tests, self._graph_layout, normalize)
715 id={"type": "graph", "index": "tput"},
718 class_name="g-0 p-1",
727 id={"type": "graph", "index": "lat"},
730 class_name="g-0 p-1",
738 class_name="g-0 p-0",
750 "text-transform": "none",
751 "padding": "0rem 1rem"
756 dbc.ModalHeader(dbc.ModalTitle("URL")),
765 id="plot-btn-download",
766 children="Download Data",
770 "text-transform": "none",
771 "padding": "0rem 1rem"
774 dcc.Download(id="download-iterative-data")
777 "d-grid gap-0 d-md-flex justify-content-md-end"
784 def callbacks(self, app):
785 """Callbacks for the whole application.
787 :param app: The application.
793 Output("store-control-panel", "data"),
794 Output("store-selected-tests", "data"),
795 Output("plotting-area", "children"),
796 Output("row-card-sel-tests", "style"),
797 Output("row-btns-sel-tests", "style"),
798 Output("lg-selected", "children"),
800 Output({"type": "ctrl-dd", "index": "rls"}, "value"),
801 Output({"type": "ctrl-dd", "index": "dut"}, "options"),
802 Output({"type": "ctrl-dd", "index": "dut"}, "disabled"),
803 Output({"type": "ctrl-dd", "index": "dut"}, "value"),
804 Output({"type": "ctrl-dd", "index": "dutver"}, "options"),
805 Output({"type": "ctrl-dd", "index": "dutver"}, "disabled"),
806 Output({"type": "ctrl-dd", "index": "dutver"}, "value"),
807 Output({"type": "ctrl-dd", "index": "phy"}, "options"),
808 Output({"type": "ctrl-dd", "index": "phy"}, "disabled"),
809 Output({"type": "ctrl-dd", "index": "phy"}, "value"),
810 Output({"type": "ctrl-dd", "index": "area"}, "options"),
811 Output({"type": "ctrl-dd", "index": "area"}, "disabled"),
812 Output({"type": "ctrl-dd", "index": "area"}, "value"),
813 Output({"type": "ctrl-dd", "index": "test"}, "options"),
814 Output({"type": "ctrl-dd", "index": "test"}, "disabled"),
815 Output({"type": "ctrl-dd", "index": "test"}, "value"),
816 Output({"type": "ctrl-cl", "index": "core"}, "options"),
817 Output({"type": "ctrl-cl", "index": "core"}, "value"),
818 Output({"type": "ctrl-cl", "index": "core-all"}, "value"),
819 Output({"type": "ctrl-cl", "index": "core-all"}, "options"),
820 Output({"type": "ctrl-cl", "index": "frmsize"}, "options"),
821 Output({"type": "ctrl-cl", "index": "frmsize"}, "value"),
822 Output({"type": "ctrl-cl", "index": "frmsize-all"}, "value"),
823 Output({"type": "ctrl-cl", "index": "frmsize-all"}, "options"),
824 Output({"type": "ctrl-cl", "index": "tsttype"}, "options"),
825 Output({"type": "ctrl-cl", "index": "tsttype"}, "value"),
826 Output({"type": "ctrl-cl", "index": "tsttype-all"}, "value"),
827 Output({"type": "ctrl-cl", "index": "tsttype-all"}, "options"),
828 Output({"type": "ctrl-btn", "index": "add-test"}, "disabled"),
829 Output("normalize", "value")
832 State("store-control-panel", "data"),
833 State("store-selected-tests", "data"),
834 State({"type": "sel-cl", "index": ALL}, "value")
837 Input("url", "href"),
838 Input("normalize", "value"),
840 Input({"type": "ctrl-dd", "index": ALL}, "value"),
841 Input({"type": "ctrl-cl", "index": ALL}, "value"),
842 Input({"type": "ctrl-btn", "index": ALL}, "n_clicks")
845 def _update_application(
853 """Update the application when the event is detected.
856 ctrl_panel = ControlPanel(CP_PARAMS, control_panel)
860 parsed_url = url_decode(href)
862 url_params = parsed_url["params"]
866 plotting_area = no_update
867 row_card_sel_tests = no_update
868 row_btns_sel_tests = no_update
869 lg_selected = no_update
871 trigger = Trigger(callback_context.triggered)
873 if trigger.type == "url" and url_params:
875 store_sel = literal_eval(url_params["store_sel"][0])
876 normalize = literal_eval(url_params["norm"][0])
877 except (KeyError, IndexError):
880 row_card_sel_tests = C.STYLE_ENABLED
881 row_btns_sel_tests = C.STYLE_ENABLED
882 last_test = store_sel[-1]
883 test = self._spec_tbs[last_test["rls"]][last_test["dut"]]\
884 [last_test["dutver"]][last_test["phy"]]\
885 [last_test["area"]][last_test["test"]]
887 "dd-rls-val": last_test["rls"],
888 "dd-dut-val": last_test["dut"],
889 "dd-dut-opt": generate_options(
890 self._spec_tbs[last_test["rls"]].keys()
893 "dd-dutver-val": last_test["dutver"],
894 "dd-dutver-opt": generate_options(
895 self._spec_tbs[last_test["rls"]]\
896 [last_test["dut"]].keys()
898 "dd-dutver-dis": False,
899 "dd-phy-val": last_test["phy"],
900 "dd-phy-opt": generate_options(
901 self._spec_tbs[last_test["rls"]][last_test["dut"]]\
902 [last_test["dutver"]].keys()
905 "dd-area-val": last_test["area"],
907 {"label": label(v), "value": v} for v in \
908 sorted(self._spec_tbs[last_test["rls"]]\
909 [last_test["dut"]][last_test["dutver"]]\
910 [last_test["phy"]].keys())
912 "dd-area-dis": False,
913 "dd-test-val": last_test["test"],
914 "dd-test-opt": generate_options(
915 self._spec_tbs[last_test["rls"]][last_test["dut"]]\
916 [last_test["dutver"]][last_test["phy"]]\
917 [last_test["area"]].keys()
919 "dd-test-dis": False,
920 "cl-core-opt": generate_options(test["core"]),
921 "cl-core-val": [last_test["core"].upper(), ],
922 "cl-core-all-val": list(),
923 "cl-core-all-opt": C.CL_ALL_ENABLED,
924 "cl-frmsize-opt": generate_options(test["frame-size"]),
925 "cl-frmsize-val": [last_test["framesize"].upper(), ],
926 "cl-frmsize-all-val": list(),
927 "cl-frmsize-all-opt": C.CL_ALL_ENABLED,
928 "cl-tsttype-opt": generate_options(test["test-type"]),
929 "cl-tsttype-val": [last_test["testtype"].upper(), ],
930 "cl-tsttype-all-val": list(),
931 "cl-tsttype-all-opt": C.CL_ALL_ENABLED,
932 "cl-normalize-val": normalize,
936 elif trigger.type == "normalize":
937 ctrl_panel.set({"cl-normalize-val": normalize})
939 elif trigger.type == "ctrl-dd":
940 if trigger.idx == "rls":
942 options = generate_options(
943 self._spec_tbs[trigger.value].keys()
950 "dd-rls-val": trigger.value,
952 "dd-dut-opt": options,
953 "dd-dut-dis": disabled,
954 "dd-dutver-val": str(),
955 "dd-dutver-opt": list(),
956 "dd-dutver-dis": True,
958 "dd-phy-opt": list(),
960 "dd-area-val": str(),
961 "dd-area-opt": list(),
963 "dd-test-val": str(),
964 "dd-test-opt": list(),
966 "cl-core-opt": list(),
967 "cl-core-val": list(),
968 "cl-core-all-val": list(),
969 "cl-core-all-opt": C.CL_ALL_DISABLED,
970 "cl-frmsize-opt": list(),
971 "cl-frmsize-val": list(),
972 "cl-frmsize-all-val": list(),
973 "cl-frmsize-all-opt": C.CL_ALL_DISABLED,
974 "cl-tsttype-opt": list(),
975 "cl-tsttype-val": list(),
976 "cl-tsttype-all-val": list(),
977 "cl-tsttype-all-opt": C.CL_ALL_DISABLED,
980 elif trigger.idx == "dut":
982 rls = ctrl_panel.get("dd-rls-val")
983 dut = self._spec_tbs[rls][trigger.value]
984 options = generate_options(dut.keys())
990 "dd-dut-val": trigger.value,
991 "dd-dutver-val": str(),
992 "dd-dutver-opt": options,
993 "dd-dutver-dis": disabled,
995 "dd-phy-opt": list(),
997 "dd-area-val": str(),
998 "dd-area-opt": list(),
1000 "dd-test-val": str(),
1001 "dd-test-opt": list(),
1002 "dd-test-dis": True,
1003 "cl-core-opt": list(),
1004 "cl-core-val": list(),
1005 "cl-core-all-val": list(),
1006 "cl-core-all-opt": C.CL_ALL_DISABLED,
1007 "cl-frmsize-opt": list(),
1008 "cl-frmsize-val": list(),
1009 "cl-frmsize-all-val": list(),
1010 "cl-frmsize-all-opt": C.CL_ALL_DISABLED,
1011 "cl-tsttype-opt": list(),
1012 "cl-tsttype-val": list(),
1013 "cl-tsttype-all-val": list(),
1014 "cl-tsttype-all-opt": C.CL_ALL_DISABLED,
1017 elif trigger.idx == "dutver":
1019 rls = ctrl_panel.get("dd-rls-val")
1020 dut = ctrl_panel.get("dd-dut-val")
1021 dutver = self._spec_tbs[rls][dut][trigger.value]
1022 options = generate_options(dutver.keys())
1028 "dd-dutver-val": trigger.value,
1029 "dd-phy-val": str(),
1030 "dd-phy-opt": options,
1031 "dd-phy-dis": disabled,
1032 "dd-area-val": str(),
1033 "dd-area-opt": list(),
1034 "dd-area-dis": True,
1035 "dd-test-val": str(),
1036 "dd-test-opt": list(),
1037 "dd-test-dis": True,
1038 "cl-core-opt": list(),
1039 "cl-core-val": list(),
1040 "cl-core-all-val": list(),
1041 "cl-core-all-opt": C.CL_ALL_DISABLED,
1042 "cl-frmsize-opt": list(),
1043 "cl-frmsize-val": list(),
1044 "cl-frmsize-all-val": list(),
1045 "cl-frmsize-all-opt": C.CL_ALL_DISABLED,
1046 "cl-tsttype-opt": list(),
1047 "cl-tsttype-val": list(),
1048 "cl-tsttype-all-val": list(),
1049 "cl-tsttype-all-opt": C.CL_ALL_DISABLED,
1052 elif trigger.idx == "phy":
1054 rls = ctrl_panel.get("dd-rls-val")
1055 dut = ctrl_panel.get("dd-dut-val")
1056 dutver = ctrl_panel.get("dd-dutver-val")
1057 phy = self._spec_tbs[rls][dut][dutver][trigger.value]
1058 options = [{"label": label(v), "value": v} \
1059 for v in sorted(phy.keys())]
1065 "dd-phy-val": trigger.value,
1066 "dd-area-val": str(),
1067 "dd-area-opt": options,
1068 "dd-area-dis": disabled,
1069 "dd-test-val": str(),
1070 "dd-test-opt": list(),
1071 "dd-test-dis": True,
1072 "cl-core-opt": list(),
1073 "cl-core-val": list(),
1074 "cl-core-all-val": list(),
1075 "cl-core-all-opt": C.CL_ALL_DISABLED,
1076 "cl-frmsize-opt": list(),
1077 "cl-frmsize-val": list(),
1078 "cl-frmsize-all-val": list(),
1079 "cl-frmsize-all-opt": C.CL_ALL_DISABLED,
1080 "cl-tsttype-opt": list(),
1081 "cl-tsttype-val": list(),
1082 "cl-tsttype-all-val": list(),
1083 "cl-tsttype-all-opt": C.CL_ALL_DISABLED,
1086 elif trigger.idx == "area":
1088 rls = ctrl_panel.get("dd-rls-val")
1089 dut = ctrl_panel.get("dd-dut-val")
1090 dutver = ctrl_panel.get("dd-dutver-val")
1091 phy = ctrl_panel.get("dd-phy-val")
1093 self._spec_tbs[rls][dut][dutver][phy][trigger.value]
1094 options = generate_options(area.keys())
1100 "dd-area-val": trigger.value,
1101 "dd-test-val": str(),
1102 "dd-test-opt": options,
1103 "dd-test-dis": disabled,
1104 "cl-core-opt": list(),
1105 "cl-core-val": list(),
1106 "cl-core-all-val": list(),
1107 "cl-core-all-opt": C.CL_ALL_DISABLED,
1108 "cl-frmsize-opt": list(),
1109 "cl-frmsize-val": list(),
1110 "cl-frmsize-all-val": list(),
1111 "cl-frmsize-all-opt": C.CL_ALL_DISABLED,
1112 "cl-tsttype-opt": list(),
1113 "cl-tsttype-val": list(),
1114 "cl-tsttype-all-val": list(),
1115 "cl-tsttype-all-opt": C.CL_ALL_DISABLED,
1118 elif trigger.idx == "test":
1119 rls = ctrl_panel.get("dd-rls-val")
1120 dut = ctrl_panel.get("dd-dut-val")
1121 dutver = ctrl_panel.get("dd-dutver-val")
1122 phy = ctrl_panel.get("dd-phy-val")
1123 area = ctrl_panel.get("dd-area-val")
1124 if all((rls, dut, dutver, phy, area, trigger.value, )):
1125 test = self._spec_tbs[rls][dut][dutver][phy][area]\
1128 "dd-test-val": trigger.value,
1129 "cl-core-opt": generate_options(test["core"]),
1130 "cl-core-val": list(),
1131 "cl-core-all-val": list(),
1132 "cl-core-all-opt": C.CL_ALL_ENABLED,
1134 generate_options(test["frame-size"]),
1135 "cl-frmsize-val": list(),
1136 "cl-frmsize-all-val": list(),
1137 "cl-frmsize-all-opt": C.CL_ALL_ENABLED,
1139 generate_options(test["test-type"]),
1140 "cl-tsttype-val": list(),
1141 "cl-tsttype-all-val": list(),
1142 "cl-tsttype-all-opt": C.CL_ALL_ENABLED,
1145 elif trigger.type == "ctrl-cl":
1146 param = trigger.idx.split("-")[0]
1147 if "-all" in trigger.idx:
1148 c_sel, c_all, c_id = list(), trigger.value, "all"
1150 c_sel, c_all, c_id = trigger.value, list(), str()
1151 val_sel, val_all = sync_checklists(
1152 options=ctrl_panel.get(f"cl-{param}-opt"),
1158 f"cl-{param}-val": val_sel,
1159 f"cl-{param}-all-val": val_all,
1161 if all((ctrl_panel.get("cl-core-val"),
1162 ctrl_panel.get("cl-frmsize-val"),
1163 ctrl_panel.get("cl-tsttype-val"), )):
1164 ctrl_panel.set({"btn-add-dis": False})
1166 ctrl_panel.set({"btn-add-dis": True})
1167 elif trigger.type == "ctrl-btn":
1169 if trigger.idx == "add-test":
1170 rls = ctrl_panel.get("dd-rls-val")
1171 dut = ctrl_panel.get("dd-dut-val")
1172 dutver = ctrl_panel.get("dd-dutver-val")
1173 phy = ctrl_panel.get("dd-phy-val")
1174 area = ctrl_panel.get("dd-area-val")
1175 test = ctrl_panel.get("dd-test-val")
1176 # Add selected test to the list of tests in store:
1177 if store_sel is None:
1179 for core in ctrl_panel.get("cl-core-val"):
1180 for framesize in ctrl_panel.get("cl-frmsize-val"):
1181 for ttype in ctrl_panel.get("cl-tsttype-val"):
1188 phy.replace("af_xdp", "af-xdp"),
1195 if tid not in [i["id"] for i in store_sel]:
1204 "framesize": framesize.lower(),
1205 "core": core.lower(),
1206 "testtype": ttype.lower()
1208 store_sel = sorted(store_sel, key=lambda d: d["id"])
1209 if C.CLEAR_ALL_INPUTS:
1210 ctrl_panel.set(ctrl_panel.defaults)
1211 elif trigger.idx == "rm-test" and lst_sel:
1212 new_store_sel = list()
1213 for idx, item in enumerate(store_sel):
1214 if not lst_sel[idx]:
1215 new_store_sel.append(item)
1216 store_sel = new_store_sel
1217 elif trigger.idx == "rm-test-all":
1222 lg_selected = get_list_group_items(store_sel)
1223 plotting_area = self._get_plotting_area(
1228 {"store_sel": store_sel, "norm": normalize}
1231 row_card_sel_tests = C.STYLE_ENABLED
1232 row_btns_sel_tests = C.STYLE_ENABLED
1234 plotting_area = C.PLACEHOLDER
1235 row_card_sel_tests = C.STYLE_DISABLED
1236 row_btns_sel_tests = C.STYLE_DISABLED
1247 ret_val.extend(ctrl_panel.values)
1251 Output("plot-mod-url", "is_open"),
1252 [Input("plot-btn-url", "n_clicks")],
1253 [State("plot-mod-url", "is_open")],
1255 def toggle_plot_mod_url(n, is_open):
1256 """Toggle the modal window with url.
1263 Output("download-iterative-data", "data"),
1264 State("store-selected-tests", "data"),
1265 Input("plot-btn-download", "n_clicks"),
1266 prevent_initial_call=True
1268 def _download_trending_data(store_sel, _):
1269 """Download the data
1271 :param store_sel: List of tests selected by user stored in the
1273 :type store_sel: list
1274 :returns: dict of data frame content (base64 encoded) and meta data
1275 used by the Download component.
1283 for itm in store_sel:
1284 sel_data = select_iterative_data(self._data, itm)
1285 if sel_data is None:
1287 df = pd.concat([df, sel_data], ignore_index=True)
1289 return dcc.send_data_frame(df.to_csv, C.REPORT_DOWNLOAD_FILE_NAME)