X-Git-Url: https://gerrit.fd.io/r/gitweb?p=csit.git;a=blobdiff_plain;f=resources%2Ftools%2Fdash%2Fapp%2Fpal%2Ftrending%2Flayout.py;h=c21e4b3c2ec034dcc7bc4d0e2bebfe6b7769e304;hp=43a37860083896ca1a7e3a1761e31eba03baf4c3;hb=06d3f7331f9f10d99baa334b1808dfdc9c6fc8be;hpb=d3f16c6ceaa5b475a9c8dc13d21817735e087869 diff --git a/resources/tools/dash/app/pal/trending/layout.py b/resources/tools/dash/app/pal/trending/layout.py index 43a3786008..c21e4b3c2e 100644 --- a/resources/tools/dash/app/pal/trending/layout.py +++ b/resources/tools/dash/app/pal/trending/layout.py @@ -28,8 +28,10 @@ from yaml import load, FullLoader, YAMLError from datetime import datetime, timedelta from copy import deepcopy from json import loads, JSONDecodeError +from ast import literal_eval from ..data.data import Data +from ..data.url_processing import url_decode, url_encode from .graphs import graph_trending, graph_hdrh_latency, \ select_trending_data @@ -38,6 +40,10 @@ class Layout: """ """ + # 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"} @@ -73,7 +79,13 @@ class Layout: "nfv_density-dcr_memif-chain": "CNF Service Chains Routing", } - def __init__(self, app: Flask, html_layout_file: str, spec_file: str, + URL_STYLE = { + "background-color": "#d2ebf5", + "border-color": "#bce1f1", + "color": "#135d7c" + } + + def __init__(self, app: Flask, html_layout_file: str, graph_layout_file: str, data_spec_file: str, tooltip_file: str, time_period: str=None) -> None: """ @@ -82,7 +94,6 @@ class Layout: # Inputs self._app = app self._html_layout_file = html_layout_file - self._spec_file = spec_file self._graph_layout_file = graph_layout_file self._data_spec_file = data_spec_file self._tooltip_file = tooltip_file @@ -233,10 +244,13 @@ class Layout: def label(self, key: str) -> str: return self.LABELS.get(key, key) - def _show_tooltip(self, id: str, title: str) -> list: + 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, @@ -284,12 +298,9 @@ class Layout: id="row-main", class_name="g-0", children=[ - dcc.Store( - id="selected-tests" - ), - dcc.Store( - id="control-panel" - ), + dcc.Store(id="selected-tests"), + dcc.Store(id="control-panel"), + dcc.Location(id="url", refresh=False), self._add_ctrl_col(), self._add_plotting_col(), ] @@ -566,6 +577,34 @@ class Layout: ) ] ), + dbc.Row( + id="row-ctrl-normalize", + class_name="gy-1", + children=[ + dbc.Label( + children=self._show_tooltip( + "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=[ @@ -687,6 +726,7 @@ class Layout: "cl-ctrl-testtype-all-value": list(), "cl-ctrl-testtype-all-options": CL_ALL_DISABLED, "btn-ctrl-add-disabled": True, + "cl-normalize-value": list(), "cl-selected-options": list(), } @@ -736,13 +776,17 @@ class Layout: else: return list() + @staticmethod + def _get_date(s_date: str) -> datetime: + return datetime(int(s_date[0:4]), int(s_date[5:7]), int(s_date[8:10])) + def callbacks(self, app): - def _generate_plotting_arrea(args: tuple) -> tuple: + def _generate_plotting_area(figs: tuple, url: str) -> tuple: """ """ - (fig_tput, fig_lat) = args + (fig_tput, fig_lat) = figs row_fig_tput = self.PLACEHOLDER row_fig_lat = self.PLACEHOLDER @@ -756,16 +800,43 @@ class Layout: ) ] row_btn_dwnld = [ - dcc.Loading(children=[ - dbc.Button( - id="btn-download-data", - children=self._show_tooltip( - "help-download", "Download"), - class_name="me-1", - color="info" - ), - dcc.Download(id="download-data") - ]), + dbc.Col( # Download + width=2, + children=[ + dcc.Loading(children=[ + dbc.Button( + id="btn-download-data", + children=self._show_tooltip( + "help-download", "Download Data"), + class_name="me-1", + color="info" + ), + dcc.Download(id="download-data") + ]), + ] + ), + dbc.Col( # Show URL + width=10, + children=[ + dbc.InputGroup( + class_name="me-1", + children=[ + dbc.InputGroupText( + style=self.URL_STYLE, + children=self._show_tooltip( + "help-url", "URL", "input-url") + ), + dbc.Input( + id="input-url", + readonly=True, + type="url", + style=self.URL_STYLE, + value=url + ) + ] + ) + ] + ) ] if fig_lat: row_fig_lat = [ @@ -808,6 +879,7 @@ class Layout: 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 @@ -822,24 +894,49 @@ class Layout: 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("dpr-period", "start_date"), Input("dpr-period", "end_date"), Input("btn-sel-remove", "n_clicks"), Input("btn-sel-remove-all", "n_clicks"), + Input("url", "href") ) def _update_ctrl_panel(cp_data: dict, store_sel: list, list_sel: list, dd_dut: 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, - d_start: str, d_end: str, btn_remove: int, - btn_remove_all: int) -> tuple: + cl_testtype: list, cl_testtype_all: list, cl_normalize: list, + btn_add: int, d_start: str, d_end: str, btn_remove: int, + btn_remove_all: int, href: str) -> tuple: """ """ - d_start = datetime(int(d_start[0:4]), int(d_start[5:7]), - int(d_start[8:10])) - d_end = datetime(int(d_end[0:4]), int(d_end[5:7]), int(d_end[8:10])) + def _gen_new_url(parsed_url: dict, store_sel: list, + start: datetime, end: datetime) -> 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, + "start": start, + "end": end + } + }) + else: + new_url = str() + return new_url + + + ctrl_panel = self.ControlPanel(cp_data) + + d_start = self._get_date(d_start) + d_end = self._get_date(d_end) + + # Parse the url: + parsed_url = url_decode(href) row_fig_tput = no_update row_fig_lat = no_update @@ -847,17 +944,13 @@ class Layout: row_card_sel_tests = no_update row_btns_sel_tests = no_update - ctrl_panel = self.ControlPanel(cp_data) - trigger_id = callback_context.triggered[0]["prop_id"].split(".")[0] if trigger_id == "dd-ctrl-dut": try: + dut = self.spec_tbs[dd_dut] options = sorted( - [ - {"label": v, "value": v} - for v in self.spec_tbs[dd_dut].keys() - ], + [{"label": v, "value": v}for v in dut.keys()], key=lambda d: d["label"] ) disabled = False @@ -872,6 +965,7 @@ class Layout: "dd-ctrl-area-value": str(), "dd-ctrl-area-options": list(), "dd-ctrl-area-disabled": True, + "dd-ctrl-test-value": str(), "dd-ctrl-test-options": list(), "dd-ctrl-test-disabled": True, "cl-ctrl-core-options": list(), @@ -887,14 +981,13 @@ class Layout: "cl-ctrl-testtype-all-value": list(), "cl-ctrl-testtype-all-options": self.CL_ALL_DISABLED, }) - if trigger_id == "dd-ctrl-phy": + elif trigger_id == "dd-ctrl-phy": try: dut = ctrl_panel.get("dd-ctrl-dut-value") + phy = self.spec_tbs[dut][dd_phy] options = sorted( - [ - {"label": self.label(v), "value": v} - for v in self.spec_tbs[dut][dd_phy].keys() - ], + [{"label": self.label(v), "value": v} + for v in phy.keys()], key=lambda d: d["label"] ) disabled = False @@ -906,6 +999,7 @@ class Layout: "dd-ctrl-area-value": str(), "dd-ctrl-area-options": options, "dd-ctrl-area-disabled": disabled, + "dd-ctrl-test-value": str(), "dd-ctrl-test-options": list(), "dd-ctrl-test-disabled": True, "cl-ctrl-core-options": list(), @@ -925,11 +1019,9 @@ class Layout: try: dut = ctrl_panel.get("dd-ctrl-dut-value") phy = ctrl_panel.get("dd-ctrl-phy-value") + area = self.spec_tbs[dut][phy][dd_area] options = sorted( - [ - {"label": v, "value": v} - for v in self.spec_tbs[dut][phy][dd_area].keys() - ], + [{"label": v, "value": v} for v in area.keys()], key=lambda d: d["label"] ) disabled = False @@ -961,19 +1053,17 @@ class Layout: dut = ctrl_panel.get("dd-ctrl-dut-value") phy = ctrl_panel.get("dd-ctrl-phy-value") area = ctrl_panel.get("dd-ctrl-area-value") - cores = self.spec_tbs[dut][phy][area][dd_test]["core"] - fsizes = self.spec_tbs[dut][phy][area][dd_test]["frame-size"] - ttypes = self.spec_tbs[dut][phy][area][dd_test]["test-type"] + test = self.spec_tbs[dut][phy][area][dd_test] + cores = test["core"] + fsizes = test["frame-size"] + ttypes = test["test-type"] if dut and phy and area and dd_test: - core_opts = [ - {"label": v, "value": v} for v in sorted(cores) - ] - framesize_opts = [ - {"label": v, "value": v} for v in sorted(fsizes) - ] - testtype_opts = [ - {"label": v, "value": v}for v in sorted(ttypes) - ] + core_opts = [{"label": v, "value": v} + for v in sorted(cores)] + framesize_opts = [{"label": v, "value": v} + for v in sorted(fsizes)] + testtype_opts = [{"label": v, "value": v} + for v in sorted(ttypes)] ctrl_panel.set({ "dd-ctrl-test-value": dd_test, "cl-ctrl-core-options": core_opts, @@ -1092,24 +1182,8 @@ class Layout: store_sel = sorted(store_sel, key=lambda d: d["id"]) row_card_sel_tests = self.STYLE_ENABLED row_btns_sel_tests = self.STYLE_ENABLED - ctrl_panel.set(ctrl_panel.defaults) - ctrl_panel.set({ - "cl-selected-options": self._list_tests(store_sel) - }) - row_fig_tput, row_fig_lat, row_btn_dwnld = \ - _generate_plotting_arrea( - graph_trending( - self.data, store_sel, self.layout, d_start, - d_end - ) - ) - elif trigger_id == "dpr-period": - row_fig_tput, row_fig_lat, row_btn_dwnld = \ - _generate_plotting_arrea( - graph_trending( - self.data, store_sel, self.layout, d_start, d_end - ) - ) + if self.CLEAR_ALL_INPUTS: + ctrl_panel.set(ctrl_panel.defaults) elif trigger_id == "btn-sel-remove-all": _ = btn_remove_all row_fig_tput = self.PLACEHOLDER @@ -1118,9 +1192,7 @@ class Layout: row_card_sel_tests = self.STYLE_DISABLED row_btns_sel_tests = self.STYLE_DISABLED store_sel = list() - ctrl_panel.set({ - "cl-selected-options": list() - }) + ctrl_panel.set({"cl-selected-options": list()}) elif trigger_id == "btn-sel-remove": _ = btn_remove if list_sel: @@ -1129,13 +1201,26 @@ class Layout: if item["id"] not in list_sel: new_store_sel.append(item) store_sel = new_store_sel + 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]) + d_start = self._get_date(url_params.get("start", list())[0]) + d_end = self._get_date(url_params.get("end", list())[0]) + if store_sel: + row_card_sel_tests = self.STYLE_ENABLED + row_btns_sel_tests = self.STYLE_ENABLED + + if trigger_id in ("btn-ctrl-add", "url", "dpr-period" + "btn-sel-remove", "cl-ctrl-normalize"): if store_sel: row_fig_tput, row_fig_lat, row_btn_dwnld = \ - _generate_plotting_arrea( - graph_trending( - self.data, store_sel, self.layout, d_start, - d_end - ) + _generate_plotting_area( + graph_trending(self.data, store_sel, self.layout, + d_start, d_end, bool(cl_normalize)), + _gen_new_url(parsed_url, store_sel, d_start, d_end) ) ctrl_panel.set({ "cl-selected-options": self._list_tests(store_sel) @@ -1147,9 +1232,7 @@ class Layout: row_card_sel_tests = self.STYLE_DISABLED row_btns_sel_tests = self.STYLE_DISABLED store_sel = list() - ctrl_panel.set({ - "cl-selected-options": list() - }) + ctrl_panel.set({"cl-selected-options": list()}) if ctrl_panel.get("cl-ctrl-core-value") and \ ctrl_panel.get("cl-ctrl-framesize-value") and \ @@ -1158,7 +1241,8 @@ class Layout: else: disabled = True ctrl_panel.set({ - "btn-ctrl-add-disabled": disabled + "btn-ctrl-add-disabled": disabled, + "cl-normalize-value": cl_normalize }) ret_val = [