X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=csit.infra.dash%2Fapp%2Fcdash%2Ftrending%2Flayout.py;h=74c39eb8c05da784814d908730fc3b1275a1bdd8;hb=7669ddf94b93df73c339d41b8094bf95a5247775;hp=3a7cd946286a7025cf4eb0e43e689eea307ffa55;hpb=f29a59cc6235e02f38fed3822b26c199da03b239;p=csit.git diff --git a/csit.infra.dash/app/cdash/trending/layout.py b/csit.infra.dash/app/cdash/trending/layout.py index 3a7cd94628..74c39eb8c0 100644 --- a/csit.infra.dash/app/cdash/trending/layout.py +++ b/csit.infra.dash/app/cdash/trending/layout.py @@ -279,15 +279,8 @@ class Layout: ) else: return html.Div( - id="div-main-error", - children=[ - dbc.Alert( - [ - "An Error Occured" - ], - color="danger" - ) - ] + dbc.Alert("An Error Occured", color="danger"), + id="div-main-error" ) def _add_navbar(self): @@ -297,17 +290,15 @@ class Layout: :rtype: dbc.NavbarSimple """ return dbc.NavbarSimple( - id="navbarsimple-main", - children=[ - dbc.NavItem( - dbc.NavLink( - C.TREND_TITLE, - disabled=True, - external_link=True, - href="#" - ) + dbc.NavItem( + dbc.NavLink( + C.TREND_TITLE, + disabled=True, + external_link=True, + href="#" ) - ], + ), + id="navbarsimple-main", brand=C.BRAND, brand_href="/", brand_external_link=True, @@ -321,12 +312,7 @@ class Layout: :returns: Column with the control panel. :rtype: dbc.Col """ - return dbc.Col([ - html.Div( - children=self._add_ctrl_panel(), - className="sticky-top" - ) - ]) + return dbc.Col(html.Div(self._add_ctrl_panel(), className="sticky-top")) def _add_ctrl_panel(self) -> list: """Add control panel. @@ -336,326 +322,232 @@ class Layout: """ return [ dbc.Row( - class_name="g-0 p-1", - children=[ - dbc.InputGroup( - [ - dbc.InputGroupText( - children=show_tooltip( - self._tooltips, - "help-dut", - "DUT" - ) - ), - dbc.Select( - id={"type": "ctrl-dd", "index": "dut"}, - placeholder="Select a Device under Test...", - options=sorted( - [ - {"label": k, "value": k} \ - for k in self._spec_tbs.keys() - ], - key=lambda d: d["label"] - ) + dbc.InputGroup( + [ + dbc.InputGroupText( + show_tooltip(self._tooltips, "help-dut", "DUT") + ), + dbc.Select( + id={"type": "ctrl-dd", "index": "dut"}, + placeholder="Select a Device under Test...", + options=sorted( + [ + {"label": k, "value": k} \ + for k in self._spec_tbs.keys() + ], + key=lambda d: d["label"] ) - ], - size="sm" - ) - ] + ) + ], + size="sm" + ), + class_name="g-0 p-1" ), dbc.Row( - class_name="g-0 p-1", - children=[ - dbc.InputGroup( - [ - dbc.InputGroupText( - children=show_tooltip( - self._tooltips, - "help-infra", - "Infra" - ) - ), - dbc.Select( - id={"type": "ctrl-dd", "index": "phy"}, - placeholder=\ - "Select a Physical Test Bed Topology..." - ) - ], - size="sm" - ) - ] + dbc.InputGroup( + [ + dbc.InputGroupText( + show_tooltip(self._tooltips, "help-infra", "Infra") + ), + dbc.Select( + id={"type": "ctrl-dd", "index": "phy"}, + placeholder="Select a Physical Test Bed Topology..." + ) + ], + size="sm" + ), + class_name="g-0 p-1" ), dbc.Row( - class_name="g-0 p-1", - children=[ - dbc.InputGroup( - [ - dbc.InputGroupText( - children=show_tooltip( - self._tooltips, - "help-area", - "Area" - ) - ), - dbc.Select( - id={"type": "ctrl-dd", "index": "area"}, - placeholder="Select an Area..." - ) - ], - size="sm" - ) - ] + dbc.InputGroup( + [ + dbc.InputGroupText( + show_tooltip(self._tooltips, "help-area", "Area") + ), + dbc.Select( + id={"type": "ctrl-dd", "index": "area"}, + placeholder="Select an Area..." + ) + ], + size="sm" + ), + class_name="g-0 p-1" ), dbc.Row( - class_name="g-0 p-1", - children=[ - dbc.InputGroup( - [ - dbc.InputGroupText( - children=show_tooltip( - self._tooltips, - "help-test", - "Test" - ) - ), - dbc.Select( - id={"type": "ctrl-dd", "index": "test"}, - placeholder="Select a Test..." - ) - ], - size="sm" - ) - ] + dbc.InputGroup( + [ + dbc.InputGroupText( + show_tooltip(self._tooltips, "help-test", "Test") + ), + dbc.Select( + id={"type": "ctrl-dd", "index": "test"}, + placeholder="Select a Test..." + ) + ], + size="sm" + ), + class_name="g-0 p-1" ), dbc.Row( - class_name="g-0 p-1", - children=[ - dbc.InputGroup( - [ - dbc.InputGroupText( - children=show_tooltip( - self._tooltips, - "help-framesize", - "Frame Size" - ) - ), - dbc.Col( - children=[ - dbc.Checklist( - id={ - "type": "ctrl-cl", - "index": "frmsize-all" - }, - options=C.CL_ALL_DISABLED, - inline=True, - class_name="ms-2" - ) - ], - width=2 + dbc.InputGroup( + [ + dbc.InputGroupText(show_tooltip( + self._tooltips, + "help-framesize", + "Frame Size" + )), + dbc.Col( + dbc.Checklist( + id={"type": "ctrl-cl", "index": "frmsize-all"}, + options=C.CL_ALL_DISABLED, + inline=True, + class_name="ms-2" ), - dbc.Col( - children=[ - dbc.Checklist( - id={ - "type": "ctrl-cl", - "index": "frmsize" - }, - inline=True - ) - ] + width=2 + ), + dbc.Col( + dbc.Checklist( + id={"type": "ctrl-cl", "index": "frmsize"}, + inline=True ) - ], - style={"align-items": "center"}, - size="sm" - ) - ] + ) + ], + style={"align-items": "center"}, + size="sm" + ), + class_name="g-0 p-1" ), dbc.Row( - class_name="g-0 p-1", - children=[ - dbc.InputGroup( - [ - dbc.InputGroupText( - children=show_tooltip( - self._tooltips, - "help-cores", - "Number of Cores" - ) - ), - dbc.Col( - children=[ - dbc.Checklist( - id={ - "type": "ctrl-cl", - "index": "core-all" - }, - options=C.CL_ALL_DISABLED, - inline=True, - class_name="ms-2" - ) - ], - width=2 + dbc.InputGroup( + [ + dbc.InputGroupText(show_tooltip( + self._tooltips, + "help-cores", + "Number of Cores" + )), + dbc.Col( + dbc.Checklist( + id={"type": "ctrl-cl", "index": "core-all"}, + options=C.CL_ALL_DISABLED, + inline=True, + class_name="ms-2" ), - dbc.Col( - children=[ - dbc.Checklist( - id={ - "type": "ctrl-cl", - "index": "core" - }, - inline=True - ) - ] + width=2 + ), + dbc.Col( + dbc.Checklist( + id={"type": "ctrl-cl", "index": "core"}, + inline=True ) - ], - style={"align-items": "center"}, - size="sm" - ) - ] + ) + ], + style={"align-items": "center"}, + size="sm" + ), + class_name="g-0 p-1" ), dbc.Row( - class_name="g-0 p-1", - children=[ - dbc.InputGroup( - [ - dbc.InputGroupText( - children=show_tooltip( - self._tooltips, - "help-ttype", - "Test Type" - ) - ), - dbc.Col( - children=[ - dbc.Checklist( - id={ - "type": "ctrl-cl", - "index": "tsttype-all" - }, - options=C.CL_ALL_DISABLED, - inline=True, - class_name="ms-2" - ) - ], - width=2 + dbc.InputGroup( + [ + dbc.InputGroupText(show_tooltip( + self._tooltips, + "help-ttype", + "Test Type" + )), + dbc.Col( + dbc.Checklist( + id={"type": "ctrl-cl", "index": "tsttype-all"}, + options=C.CL_ALL_DISABLED, + inline=True, + class_name="ms-2" ), - dbc.Col( - children=[ - dbc.Checklist( - id={ - "type": "ctrl-cl", - "index": "tsttype" - }, - inline=True - ) - ] + width=2 + ), + dbc.Col( + dbc.Checklist( + id={"type": "ctrl-cl", "index": "tsttype"}, + inline=True ) - ], - style={"align-items": "center"}, - size="sm" - ) - ] + ) + ], + style={"align-items": "center"}, + size="sm" + ), + class_name="g-0 p-1" ), 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.InputGroup( + [ + dbc.InputGroupText(show_tooltip( + self._tooltips, + "help-normalize", + "Normalization" + )), + dbc.Col(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" + ), + class_name="g-0 p-1" ), dbc.Row( - class_name="g-0 p-1", - children=[ - dbc.Button( - id={"type": "ctrl-btn", "index": "add-test"}, - children="Add Selected", - color="info" - ) - ] + dbc.Button( + id={"type": "ctrl-btn", "index": "add-test"}, + children="Add Selected", + color="info" + ), + class_name="g-0 p-1" ), dbc.Row( + dbc.ListGroup( + class_name="overflow-auto p-0", + id="lg-selected", + children=[], + style={"max-height": "20em"}, + flush=True + ), 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": "20em"}, - flush=True - ) - ] ), dbc.Row( + dbc.ButtonGroup([ + dbc.Button( + "Remove Selected", + id={"type": "ctrl-btn", "index": "rm-test"}, + class_name="w-100", + color="info", + disabled=False + ), + dbc.Button( + "Remove All", + id={"type": "ctrl-btn", "index": "rm-test-all"}, + class_name="w-100", + color="info", + disabled=False + ) + ]), id="row-btns-sel-tests", class_name="g-0 p-1", style=C.STYLE_DISABLED, - 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.Stack( - id="row-btns-add-tm", - class_name="g-0 p-1", - style=C.STYLE_DISABLED, - gap=2, - children=[ + [ dbc.Button( + "Add Telemetry Panel", id={"type": "telemetry-btn", "index": "open"}, - children="Telemetry", - color="info" - ), - dbc.Button( - id="plot-btn-url", - children="Show URL", color="info" ), + dbc.Button("Show URL", id="plot-btn-url", color="info"), dbc.Modal( [ dbc.ModalHeader(dbc.ModalTitle("URL")), @@ -666,7 +558,11 @@ class Layout: is_open=False, scrollable=True ) - ] + ], + id="row-btns-add-tm", + class_name="g-0 p-1", + style=C.STYLE_DISABLED, + gap=2 ) ] @@ -697,45 +593,38 @@ class Layout: style=C.STYLE_DISABLED, ) - def _plotting_area_trending( - self, - tests: list, - normalize: bool - ) -> dbc.Col: + @staticmethod + def _plotting_area_trending(graphs: list) -> dbc.Col: """Generate the plotting area with all its content. - :param tests: A list of tests to be displayed in the trending graphs. - :param normalize: If True, the data in graphs is normalized. - :type tests: list - :type normalize: bool + :param graphs: A list of graphs to be displayed in the trending page. + :type graphs: list :returns: A collumn with trending graphs (tput and latency) in tabs. :rtype: dbc.Col """ - if not tests: + if not graphs: return C.PLACEHOLDER - figs = graph_trending(self._data, tests, self._graph_layout, normalize) - - if not figs[0]: + if not graphs[0]: return C.PLACEHOLDER tab_items = [ dbc.Tab( children=dcc.Graph( id={"type": "graph", "index": "tput"}, - figure=figs[0] + figure=graphs[0] ), label="Throughput", tab_id="tab-tput" ) ] - if figs[1]: + if graphs[1]: tab_items.append( dbc.Tab( children=dcc.Graph( id={"type": "graph", "index": "lat"}, - figure=figs[1] + figure=graphs[1] ), label="Latency", tab_id="tab-lat" @@ -743,50 +632,40 @@ class Layout: ) trending = [ - dbc.Row(children=[ + dbc.Row( dbc.Tabs( children=tab_items, id="tabs", active_tab="tab-tput", - ) - ]), + ), + class_name="g-0 p-0" + ), dbc.Row( - [ - dbc.Col([html.Div( - [ - dbc.Button( - id="plot-btn-download", - children="Download Data", - class_name="me-1", - color="info", - style={"padding": "0rem 1rem"} - ), - dcc.Download(id="download-trending-data") - ], - className=\ - "d-grid gap-0 d-md-flex justify-content-md-end" - )]) - ], + html.Div( + [ + dbc.Button( + "Download Data", + id="plot-btn-download", + class_name="me-1", + color="info", + style={"padding": "0rem 1rem"} + ), + dcc.Download(id="download-trending-data") + ], + className="d-grid gap-0 d-md-flex justify-content-md-end" + ), class_name="g-0 p-0" ) ] return dbc.Col( children=[ - dbc.Row( - dbc.Accordion( - children=[ - dbc.AccordionItem( - title="Trending", - children=trending - ) - ], - class_name="g-0 p-1", - start_collapsed=False, - always_open=True, - active_item=["item-0", ] - ), - class_name="g-0 p-0", + dbc.Accordion( + dbc.AccordionItem(trending, title="Trending"), + class_name="g-0 p-1", + start_collapsed=False, + always_open=True, + active_item=["item-0", ] ), dbc.Modal( [ @@ -795,23 +674,26 @@ class Layout: close_button=False ), dbc.Spinner( - dbc.ModalBody(self._get_telemetry_step_1()), + dbc.ModalBody(Layout._get_telemetry_step_1()), delay_show=2 * C.SPINNER_DELAY ), dbc.ModalFooter([ dbc.Button( "Select", id={"type": "telemetry-btn", "index": "select"}, + color="success", disabled=True ), dbc.Button( "Cancel", id={"type": "telemetry-btn", "index": "cancel"}, + color="info", disabled=False ), dbc.Button( - "Remove", - id={"type": "telemetry-btn", "index": "remove"}, + "Remove All", + id={"type": "telemetry-btn", "index": "rm-all"}, + color="danger", disabled=False ) ]) @@ -830,23 +712,26 @@ class Layout: close_button=False ), dbc.Spinner( - dbc.ModalBody(self._get_telemetry_step_2()), + dbc.ModalBody(Layout._get_telemetry_step_2()), delay_show=2 * C.SPINNER_DELAY ), dbc.ModalFooter([ dbc.Button( "Back", id={"type": "telemetry-btn", "index": "back"}, + color="info", disabled=False ), dbc.Button( - "Display Telemetry", + "Add Telemetry Panel", id={"type": "telemetry-btn", "index": "add"}, + color="success", disabled=True ), dbc.Button( "Cancel", id={"type": "telemetry-btn", "index": "cancel"}, + color="info", disabled=False ) ]) @@ -861,37 +746,94 @@ class Layout: ] ) - def _plotting_area_telemetry(self, graphs: list) -> dbc.Col: + @staticmethod + def _plotting_area_telemetry(graphs: list) -> dbc.Col: """Generate the plotting area with telemetry. + + :param graphs: A list of graphs to be displayed in the telemetry page. + :type graphs: list + :returns: A collumn with telemetry trending graphs. + :rtype: dbc.Col """ if not graphs: return C.PLACEHOLDER - acc_items = list() - for graph in graphs: - acc_items.append( + def _plural(iterative): + return "s" if len(iterative) > 1 else str() + + panels = list() + for idx, graph_set in enumerate(graphs): + acc_items = list() + for graph in graph_set[0]: + graph_name = ", ".join(graph[1]) + acc_items.append( + dbc.AccordionItem( + dcc.Graph( + id={"type": "graph-telemetry", "index": graph_name}, + figure=graph[0] + ), + title=(f"Test{_plural(graph[1])}: {graph_name}"), + class_name="g-0 p-0" + ) + ) + panels.append( dbc.AccordionItem( - title=f"Telemetry: {graph[1]}" if graph[1] else "Telemetry", - children=dcc.Graph( - id={"type": "graph-telemetry", "index": graph[1]}, - figure=graph[0] + [ + dbc.Row( + dbc.Accordion( + children=acc_items, + class_name="g-0 p-0", + start_collapsed=True, + always_open=True, + flush=True + ), + class_name="g-0 p-0" + ), + dbc.Row( + html.Div( + [ + dbc.Button( + "Remove", + id={ + "type": "tm-btn-remove", + "index": idx + }, + class_name="me-1", + color="danger", + style={"padding": "0rem 1rem"} + ), + dbc.Button( + "Download Data", + id={ + "type": "tm-btn-download", + "index": idx + }, + class_name="me-1", + color="info", + style={"padding": "0rem 1rem"} + ) + ], + className=\ + "d-grid gap-0 d-md-flex justify-content-md-end" + ), + class_name="g-0 p-0" + ) + ], + class_name="g-0 p-0", + title=( + f"Metric{_plural(graph_set[1])}: ", + ", ".join(graph_set[1]) ) ) ) return dbc.Col( - children=[ - dbc.Row( - dbc.Accordion( - children=acc_items, - class_name="g-0 p-1", - start_collapsed=False, - always_open=True, - active_item=[f"item-{i}" for i in range(len(acc_items))] - ), - class_name="g-0 p-0", - ) - ] + dbc.Accordion( + panels, + class_name="g-0 p-1", + start_collapsed=True, + always_open=True + ) ) @staticmethod @@ -938,30 +880,38 @@ class Layout: """ return [ dbc.Row( + "Add content here.", id={"type": "tm-container", "index": 0}, - class_name="g-0 p-1", - children=["Add content here."] + class_name="g-0 p-1" ), dbc.Row( - class_name="g-0 p-2", - children=[ - dbc.Checkbox( - id={"type": "cb-all-in-one", "index": 0}, - label="All Metrics in one Graph" + [ + dbc.Col( + dbc.Checkbox( + id={"type": "cb-all-in-one", "index": 0}, + label="All Metrics in one Graph" + ), + width=6 ), - ] + dbc.Col( + dbc.Checkbox( + id={"type": "cb-ignore-host", "index": 0}, + label="Ignore Host" + ), + width=6 + ) + ], + class_name="g-0 p-2" ), dbc.Row( - class_name="g-0 p-1", - children=[ - dbc.Textarea( - id={"type": "tm-list-metrics", "index": 0}, - rows=20, - size="sm", - wrap="off", - readonly=True - ) - ] + dbc.Textarea( + id={"type": "tm-list-metrics", "index": 0}, + rows=20, + size="sm", + wrap="off", + readonly=True + ), + class_name="g-0 p-1" ) ] @@ -1014,19 +964,21 @@ class Layout: State("store", "data"), State({"type": "sel-cl", "index": ALL}, "value"), State({"type": "cb-all-in-one", "index": ALL}, "value"), + State({"type": "cb-ignore-host", "index": ALL}, "value"), State({"type": "telemetry-search-out", "index": ALL}, "children"), State({"type": "plot-mod-telemetry", "index": ALL}, "is_open"), State({"type": "telemetry-btn", "index": ALL}, "disabled"), State({"type": "tm-container", "index": ALL}, "children"), State({"type": "tm-list-metrics", "index": ALL}, "value"), + State({"type": "tele-cl", "index": ALL}, "value"), Input("url", "href"), - Input({"type": "tele-cl", "index": ALL}, "value"), Input({"type": "tm-dd", "index": ALL}, "value"), Input("normalize", "value"), Input({"type": "telemetry-search-in", "index": ALL}, "value"), Input({"type": "telemetry-btn", "index": ALL}, "n_clicks"), + Input({"type": "tm-btn-remove", "index": ALL}, "n_clicks"), Input({"type": "ctrl-dd", "index": ALL}, "value"), Input({"type": "ctrl-cl", "index": ALL}, "value"), Input({"type": "ctrl-btn", "index": ALL}, "n_clicks"), @@ -1037,13 +989,14 @@ class Layout: store: dict, lst_sel: list, all_in_one: list, + ignore_host: list, search_out: list, is_open: list, tm_btns_disabled: list, tm_dd: list, list_metrics: list, - href: str, cl_metrics: list, + href: str, tm_dd_in: list, *_ ) -> tuple: @@ -1054,8 +1007,13 @@ class Layout: store = { "control-panel": dict(), "selected-tests": list(), + "trending-graphs": None, "telemetry-data": dict(), "selected-metrics": dict(), + "telemetry-panels": list(), + "telemetry-all-in-one": list(), + "telemetry-ignore-host": list(), + "telemetry-graphs": list(), "url": str() } @@ -1066,6 +1024,9 @@ class Layout: store_sel = store["selected-tests"] tm_data = store["telemetry-data"] tm_user = store["selected-metrics"] + tm_panels = store["telemetry-panels"] + tm_all_in_one = store["telemetry-all-in-one"] + tm_ignore_host = store["telemetry-ignore-host"] plotting_area_telemetry = no_update on_draw = [False, False] # 0 --> trending, 1 --> telemetry @@ -1105,8 +1066,13 @@ class Layout: store_sel = literal_eval(url_params["store_sel"][0]) normalize = literal_eval(url_params["norm"][0]) telemetry = literal_eval(url_params["telemetry"][0]) - all_in_one = literal_eval(url_params["all-in-one"][0]) - except (KeyError, IndexError, AttributeError): + url_p = url_params.get("all-in-one", ["[[None]]"]) + tm_all_in_one = literal_eval(url_p[0]) + url_p = url_params.get("ignore-host", ["[[None]]"]) + tm_ignore_host = literal_eval(url_p[0]) + if not isinstance(telemetry, list): + telemetry = [telemetry, ] + except (KeyError, IndexError, AttributeError, ValueError): pass if store_sel: last_test = store_sel[-1] @@ -1148,16 +1114,19 @@ class Layout: "cl-normalize-val": normalize, "btn-add-dis": False }) + store["trending-graphs"] = None + store["telemetry-graphs"] = list() on_draw[0] = True if telemetry: tm = TelemetryData(store_sel) tm.from_dataframe(self._data) tm_data = tm.to_json() tm.from_json(tm_data) - tm_user["selected_metrics_with_labels"] = telemetry + tm_panels = telemetry on_draw[1] = True elif trigger.type == "normalize": ctrl_panel.set({"cl-normalize-val": trigger.value}) + store["trending-graphs"] = None on_draw[0] = True elif trigger.type == "ctrl-dd": if trigger.idx == "dut": @@ -1295,14 +1264,20 @@ class Layout: f"cl-{param}-val": val_sel, f"cl-{param}-all-val": val_all, }) - if all((ctrl_panel.get("cl-core-val"), + if all((ctrl_panel.get("cl-core-val"), ctrl_panel.get("cl-frmsize-val"), ctrl_panel.get("cl-tsttype-val"), )): ctrl_panel.set({"btn-add-dis": False}) else: ctrl_panel.set({"btn-add-dis": True}) elif trigger.type == "ctrl-btn": - on_draw[0] = True + tm_panels = list() + tm_all_in_one = list() + tm_ignore_host = list() + store["trending-graphs"] = None + store["telemetry-graphs"] = list() + # on_draw[0] = True + on_draw = [True, True] if trigger.idx == "add-test": dut = ctrl_panel.get("dd-dut-val") phy = ctrl_panel.get("dd-phy-val") @@ -1360,10 +1335,10 @@ class Layout: "tele-cl", False), ) is_open = (True, False) - tm_btns_disabled[1], tm_btns_disabled[5] = True, True + tm_btns_disabled[1], tm_btns_disabled[5] = False, True elif trigger.idx == "select": - tm.from_json(tm_data) if any(cl_metrics): + tm.from_json(tm_data) if not tm_user["selected_metrics"]: tm_user["selected_metrics"] = \ tm_user["unique_metrics"] @@ -1381,17 +1356,22 @@ class Layout: tm_btns_disabled[4] = False is_open = (False, True) else: - tm_user = None - is_open = (False, False) + is_open = (True, False) elif trigger.idx == "add": tm.from_json(tm_data) + tm_panels.append(tm_user["selected_metrics_with_labels"]) + tm_all_in_one.append(all_in_one) + tm_ignore_host.append(ignore_host) is_open = (False, False) tm_btns_disabled[1], tm_btns_disabled[5] = True, True on_draw = [True, True] elif trigger.idx == "cancel": is_open = (False, False) tm_btns_disabled[1], tm_btns_disabled[5] = True, True - elif trigger.idx == "remove": + elif trigger.idx == "rm-all": + tm_panels = list() + tm_all_in_one = list() + tm_ignore_host = list() tm_user = None is_open = (False, False) tm_btns_disabled[1], tm_btns_disabled[5] = True, True @@ -1406,12 +1386,6 @@ class Layout: colorize=False ), ) is_open = (True, False) - elif trigger.type == "tele-cl": - if any(cl_metrics): - tm_btns_disabled[1] = False - else: - tm_btns_disabled[1] = True - is_open = (True, False) elif trigger.type == "tm-dd": tm.from_metrics_with_labels( tm_user["unique_metrics_with_labels"] @@ -1441,33 +1415,59 @@ class Layout: tm_btns_disabled[5] = False else: list_metrics[0] = str() + elif trigger.type == "tm-btn-remove": + del tm_panels[trigger.idx] + del tm_all_in_one[trigger.idx] + del tm_ignore_host[trigger.idx] + del store["telemetry-graphs"][trigger.idx] + tm.from_json(tm_data) + on_draw = [True, True] new_url_params = { "store_sel": store_sel, "norm": ctrl_panel.get("cl-normalize-val") } - if tm_user and tm_user.get("selected_metrics_with_labels", None): - new_url_params["telemetry"] = \ - tm_user["selected_metrics_with_labels"] - new_url_params["all-in-one"] = all_in_one + if tm_panels: + new_url_params["telemetry"] = tm_panels + new_url_params["all-in-one"] = tm_all_in_one + new_url_params["ignore-host"] = tm_ignore_host if on_draw[0]: # Trending if store_sel: lg_selected = get_list_group_items(store_sel, "sel-cl") - plotting_area_trending = self._plotting_area_trending( - store_sel, - bool(ctrl_panel.get("cl-normalize-val")) - ) - if on_draw[1]: # Telemetry - plotting_area_telemetry = self._plotting_area_telemetry( - graph_tm_trending( + if store["trending-graphs"]: + graphs = store["trending-graphs"] + else: + graphs = graph_trending( + self._data, + store_sel, + self._graph_layout, + bool(ctrl_panel.get("cl-normalize-val")) + ) + if graphs and graphs[0]: + store["trending-graphs"] = graphs + plotting_area_trending = \ + Layout._plotting_area_trending(graphs) + + # Telemetry + start_idx = len(store["telemetry-graphs"]) + end_idx = len(tm_panels) + if not end_idx: + plotting_area_telemetry = C.PLACEHOLDER + elif on_draw[1] and (end_idx >= start_idx): + for idx in range(start_idx, end_idx): + store["telemetry-graphs"].append(graph_tm_trending( tm.select_tm_trending_data( - tm_user["selected_metrics_with_labels"] + tm_panels[idx], + ignore_host=bool(tm_ignore_host[idx][0]) ), self._graph_layout, - False if not all_in_one else all_in_one[0] + bool(tm_all_in_one[idx][0]) + )) + plotting_area_telemetry = \ + Layout._plotting_area_telemetry( + store["telemetry-graphs"] ) - ) col_plotting_area = C.STYLE_ENABLED row_card_sel_tests = C.STYLE_ENABLED row_btns_sel_tests = C.STYLE_ENABLED @@ -1481,6 +1481,9 @@ class Layout: row_btns_add_tm = C.STYLE_DISABLED lg_selected = no_update store_sel = list() + tm_panels = list() + tm_all_in_one = list() + tm_ignore_host = list() tm_user = None else: plotting_area_trending = no_update @@ -1495,6 +1498,9 @@ class Layout: store["selected-tests"] = store_sel store["telemetry-data"] = tm_data store["selected-metrics"] = tm_user + store["telemetry-panels"] = tm_panels + store["telemetry-all-in-one"] = tm_all_in_one + store["telemetry-ignore-host"] = tm_ignore_host ret_val = [ store, plotting_area_trending, @@ -1720,9 +1726,10 @@ class Layout: Output("download-trending-data", "data"), State("store", "data"), Input("plot-btn-download", "n_clicks"), + Input({"type": "tm-btn-download", "index": ALL}, "n_clicks"), prevent_initial_call=True ) - def _download_trending_data(store: list, _) -> dict: + def _download_data(store: list, *_) -> dict: """Download the data :param store_sel: List of tests selected by user stored in the @@ -1737,12 +1744,30 @@ class Layout: raise PreventUpdate if not store["selected-tests"]: raise PreventUpdate - + df = pd.DataFrame() - for itm in store["selected-tests"]: - sel_data = select_trending_data(self._data, itm) - if sel_data is None: - continue - df = pd.concat([df, sel_data], ignore_index=True, copy=False) + + trigger = Trigger(callback_context.triggered) + if not trigger.value: + raise PreventUpdate + + if trigger.type == "plot-btn-download": + data = list() + for itm in store["selected-tests"]: + sel_data = select_trending_data(self._data, itm) + if sel_data is None: + continue + data.append(sel_data) + df = pd.concat(data, ignore_index=True, copy=False) + file_name = C.TREND_DOWNLOAD_FILE_NAME + elif trigger.type == "tm-btn-download": + tm = TelemetryData(store["selected-tests"]) + tm.from_json(store["telemetry-data"]) + df = tm.select_tm_trending_data( + store["telemetry-panels"][trigger.idx] + ) + file_name = C.TELEMETRY_DOWNLOAD_FILE_NAME + else: + raise PreventUpdate - return dcc.send_data_frame(df.to_csv, C.TREND_DOWNLOAD_FILE_NAME) + return dcc.send_data_frame(df.to_csv, file_name)