diff --git a/.gitignore b/.gitignore index e3ee83b511..277f1a9f4e 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,7 @@ coverage.xml # Kedro *.log + +# Python +.venv/ +mise.toml diff --git a/.stylelintignore b/.stylelintignore index 0012d6b366..c8856b88ee 100644 --- a/.stylelintignore +++ b/.stylelintignore @@ -1,5 +1,4 @@ src/**/*.css src/components/search-list/search-list.scss src/components/sidebar/sidebar.scss -src/components/experiment-tracking/time-series/time-series.scss src/components/node-list/styles/_row-toggle.scss \ No newline at end of file diff --git a/cypress/fixtures/graphql/compareThreeRuns.json b/cypress/fixtures/graphql/compareThreeRuns.json deleted file mode 100644 index aa163beaf6..0000000000 --- a/cypress/fixtures/graphql/compareThreeRuns.json +++ /dev/null @@ -1,3406 +0,0 @@ -{ - "data": { - "runMetadata": [ - { - "id": "2022-12-24T21.05.59.296Z", - "author": "rashida_kanchwala", - "bookmark": false, - "gitBranch": "add-plots-to-demo", - "gitSha": "5f81cb5", - "notes": "Test", - "runCommand": "kedro run", - "title": "2022-12-24T21.05.59.296Z", - "__typename": "Run" - }, - { - "id": "2022-10-05T12.22.35.825Z", - "author": "rashida_kanchwala", - "bookmark": false, - "gitBranch": "add-plots-to-demo", - "gitSha": "9ff5c54", - "notes": "", - "runCommand": "kedro run", - "title": "2022-10-05T12.22.35.825Z", - "__typename": "Run" - }, - { - "id": "2022-09-05T12.27.04.496Z", - "author": "rashida_kanchwala", - "bookmark": false, - "gitBranch": "add-plots-to-demo", - "gitSha": "9ff5c54", - "notes": "", - "runCommand": "kedro run", - "title": "2022-09-05T12.27.04.496Z", - "__typename": "Run" - } - ], - "plots": [ - { - "data": { - "feature_importance_plot.json": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": { - "data": [ - { - "alignmentgroup": "True", - "hovertemplate": "Score=%{marker.color}
Features=%{y}", - "legendgroup": "", - "marker": { - "color": [ - 0.02499999999999991, - 0.12199999999999989, - 0.1299999999999999, - 0.1379999999999999, - 0.14900000000000002, - 0.16399999999999992, - 0.16399999999999992, - 0.30099999999999993, - 0.34799999999999986, - 0.43699999999999983, - 0.5659999999999998, - 0.6200000000000001, - 0.7130000000000001, - 0.82, - 0.94 - ], - "coloraxis": "coloraxis", - "pattern": { - "shape": "" - } - }, - "name": "", - "offsetgroup": "", - "orientation": "h", - "showlegend": false, - "textposition": "auto", - "type": "bar", - "x": [ - 0.02499999999999991, - 0.12199999999999989, - 0.1299999999999999, - 0.1379999999999999, - 0.14900000000000002, - 0.16399999999999992, - 0.16399999999999992, - 0.30099999999999993, - 0.34799999999999986, - 0.43699999999999983, - 0.5659999999999998, - 0.6200000000000001, - 0.7130000000000001, - 0.82, - 0.94 - ], - "xaxis": "x", - "y": [ - "feature_14", - "feature_8", - "feature_12", - "feature_1", - "feature_11", - "feature_3", - "feature_9", - "feature_7", - "feature_10", - "feature_6", - "feature_2", - "feature_5", - "feature_13", - "feature_4", - "feature_0" - ], - "yaxis": "y" - } - ], - "layout": { - "barmode": "relative", - "coloraxis": { - "colorbar": { - "title": { - "text": "Score" - } - }, - "colorscale": [ - [ - 0.0, - "rgb(103,0,31)" - ], - [ - 0.1, - "rgb(178,24,43)" - ], - [ - 0.2, - "rgb(214,96,77)" - ], - [ - 0.3, - "rgb(244,165,130)" - ], - [ - 0.4, - "rgb(253,219,199)" - ], - [ - 0.5, - "rgb(247,247,247)" - ], - [ - 0.6, - "rgb(209,229,240)" - ], - [ - 0.7, - "rgb(146,197,222)" - ], - [ - 0.8, - "rgb(67,147,195)" - ], - [ - 0.9, - "rgb(33,102,172)" - ], - [ - 1.0, - "rgb(5,48,97)" - ] - ] - }, - "legend": { - "tracegroupgap": 0 - }, - "margin": { - "t": 60 - }, - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#2a3f5f" - }, - "error_y": { - "color": "#2a3f5f" - }, - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "baxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "type": "heatmap" - } - ], - "heatmapgl": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "type": "heatmapgl" - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergl" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#EBF0F8" - }, - "line": { - "color": "white" - } - }, - "header": { - "fill": { - "color": "#C8D4E3" - }, - "line": { - "color": "white" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#2a3f5f", - "arrowhead": 0, - "arrowwidth": 1 - }, - "autotypenumbers": "strict", - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ], - "sequential": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#2a3f5f" - }, - "geo": { - "bgcolor": "white", - "lakecolor": "white", - "landcolor": "#E5ECF6", - "showlakes": true, - "showland": true, - "subunitcolor": "white" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "light" - }, - "paper_bgcolor": "white", - "plot_bgcolor": "#E5ECF6", - "polar": { - "angularaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "radialaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "yaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "zaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - } - }, - "shapedefaults": { - "line": { - "color": "#2a3f5f" - } - }, - "ternary": { - "aaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "baxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "caxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "xaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - } - } - }, - "xaxis": { - "anchor": "y", - "domain": [ - 0.0, - 1.0 - ], - "title": { - "text": "Score" - } - }, - "yaxis": { - "anchor": "x", - "domain": [ - 0.0, - 1.0 - ], - "title": { - "text": "Features" - } - } - } - } - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": { - "data": [ - { - "alignmentgroup": "True", - "hovertemplate": "Score=%{marker.color}
Feature=%{y}", - "legendgroup": "", - "marker": { - "color": [ - 0.0, - 0.036, - 0.038, - 0.066, - 0.138, - 0.28, - 0.344, - 0.387, - 0.419, - 0.547, - 0.696, - 0.706, - 0.844, - 0.849, - 0.912 - ], - "coloraxis": "coloraxis", - "pattern": { - "shape": "" - } - }, - "name": "", - "offsetgroup": "", - "orientation": "h", - "showlegend": false, - "textposition": "auto", - "x": [ - 0.0, - 0.036, - 0.038, - 0.066, - 0.138, - 0.28, - 0.344, - 0.387, - 0.419, - 0.547, - 0.696, - 0.706, - 0.844, - 0.849, - 0.912 - ], - "xaxis": "x", - "y": [ - "feature_8", - "feature_0", - "feature_4", - "feature_2", - "feature_12", - "feature_13", - "feature_14", - "feature_3", - "feature_1", - "feature_10", - "feature_7", - "feature_5", - "feature_6", - "feature_9", - "feature_11" - ], - "yaxis": "y", - "type": "bar" - } - ], - "layout": { - "template": { - "data": { - "histogram2dcontour": [ - { - "type": "histogram2dcontour", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "choropleth": [ - { - "type": "choropleth", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - ], - "histogram2d": [ - { - "type": "histogram2d", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "heatmap": [ - { - "type": "heatmap", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "heatmapgl": [ - { - "type": "heatmapgl", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "contourcarpet": [ - { - "type": "contourcarpet", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - ], - "contour": [ - { - "type": "contour", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "surface": [ - { - "type": "surface", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "mesh3d": [ - { - "type": "mesh3d", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - ], - "scatter": [ - { - "fillpattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - }, - "type": "scatter" - } - ], - "parcoords": [ - { - "type": "parcoords", - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scatterpolargl": [ - { - "type": "scatterpolargl", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "bar": [ - { - "error_x": { - "color": "#2a3f5f" - }, - "error_y": { - "color": "#2a3f5f" - }, - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "scattergeo": [ - { - "type": "scattergeo", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scatterpolar": [ - { - "type": "scatterpolar", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "scattergl": [ - { - "type": "scattergl", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scatter3d": [ - { - "type": "scatter3d", - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scattermapbox": [ - { - "type": "scattermapbox", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scatterternary": [ - { - "type": "scatterternary", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scattercarpet": [ - { - "type": "scattercarpet", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "baxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "type": "carpet" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#EBF0F8" - }, - "line": { - "color": "white" - } - }, - "header": { - "fill": { - "color": "#C8D4E3" - }, - "line": { - "color": "white" - } - }, - "type": "table" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ] - }, - "layout": { - "autotypenumbers": "strict", - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#2a3f5f" - }, - "hovermode": "closest", - "hoverlabel": { - "align": "left" - }, - "paper_bgcolor": "white", - "plot_bgcolor": "#E5ECF6", - "polar": { - "bgcolor": "#E5ECF6", - "angularaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "radialaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "ternary": { - "bgcolor": "#E5ECF6", - "aaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "baxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "caxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "sequential": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ] - }, - "xaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "automargin": true, - "zerolinewidth": 2 - }, - "yaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "automargin": true, - "zerolinewidth": 2 - }, - "scene": { - "xaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white", - "gridwidth": 2 - }, - "yaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white", - "gridwidth": 2 - }, - "zaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white", - "gridwidth": 2 - } - }, - "shapedefaults": { - "line": { - "color": "#2a3f5f" - } - }, - "annotationdefaults": { - "arrowcolor": "#2a3f5f", - "arrowhead": 0, - "arrowwidth": 1 - }, - "geo": { - "bgcolor": "white", - "landcolor": "#E5ECF6", - "subunitcolor": "white", - "showland": true, - "showlakes": true, - "lakecolor": "white" - }, - "title": { - "x": 0.05 - }, - "mapbox": { - "style": "light" - } - } - }, - "xaxis": { - "anchor": "y", - "domain": [ - 0.0, - 1.0 - ], - "title": { - "text": "Score" - } - }, - "yaxis": { - "anchor": "x", - "domain": [ - 0.0, - 1.0 - ], - "title": { - "text": "Feature" - } - }, - "coloraxis": { - "colorbar": { - "title": { - "text": "Score" - } - }, - "colorscale": [ - [ - 0.0, - "rgb(103,0,31)" - ], - [ - 0.1, - "rgb(178,24,43)" - ], - [ - 0.2, - "rgb(214,96,77)" - ], - [ - 0.3, - "rgb(244,165,130)" - ], - [ - 0.4, - "rgb(253,219,199)" - ], - [ - 0.5, - "rgb(247,247,247)" - ], - [ - 0.6, - "rgb(209,229,240)" - ], - [ - 0.7, - "rgb(146,197,222)" - ], - [ - 0.8, - "rgb(67,147,195)" - ], - [ - 0.9, - "rgb(33,102,172)" - ], - [ - 1.0, - "rgb(5,48,97)" - ] - ] - }, - "legend": { - "tracegroupgap": 0 - }, - "margin": { - "t": 60 - }, - "barmode": "relative" - } - } - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": { - "data": [ - { - "alignmentgroup": "True", - "hovertemplate": "Score=%{marker.color}
Feature=%{y}", - "legendgroup": "", - "marker": { - "color": [ - 0.188, - 0.201, - 0.365, - 0.389, - 0.393, - 0.457, - 0.527, - 0.553, - 0.661, - 0.74, - 0.776, - 0.777, - 0.84, - 0.918, - 0.941 - ], - "coloraxis": "coloraxis", - "pattern": { - "shape": "" - } - }, - "name": "", - "offsetgroup": "", - "orientation": "h", - "showlegend": false, - "textposition": "auto", - "x": [ - 0.188, - 0.201, - 0.365, - 0.389, - 0.393, - 0.457, - 0.527, - 0.553, - 0.661, - 0.74, - 0.776, - 0.777, - 0.84, - 0.918, - 0.941 - ], - "xaxis": "x", - "y": [ - "feature_4", - "feature_7", - "feature_5", - "feature_3", - "feature_13", - "feature_11", - "feature_14", - "feature_0", - "feature_6", - "feature_1", - "feature_2", - "feature_10", - "feature_12", - "feature_9", - "feature_8" - ], - "yaxis": "y", - "type": "bar" - } - ], - "layout": { - "template": { - "data": { - "histogram2dcontour": [ - { - "type": "histogram2dcontour", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "choropleth": [ - { - "type": "choropleth", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - ], - "histogram2d": [ - { - "type": "histogram2d", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "heatmap": [ - { - "type": "heatmap", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "heatmapgl": [ - { - "type": "heatmapgl", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "contourcarpet": [ - { - "type": "contourcarpet", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - ], - "contour": [ - { - "type": "contour", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "surface": [ - { - "type": "surface", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "mesh3d": [ - { - "type": "mesh3d", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - ], - "scatter": [ - { - "fillpattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - }, - "type": "scatter" - } - ], - "parcoords": [ - { - "type": "parcoords", - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scatterpolargl": [ - { - "type": "scatterpolargl", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "bar": [ - { - "error_x": { - "color": "#2a3f5f" - }, - "error_y": { - "color": "#2a3f5f" - }, - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "scattergeo": [ - { - "type": "scattergeo", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scatterpolar": [ - { - "type": "scatterpolar", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "scattergl": [ - { - "type": "scattergl", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scatter3d": [ - { - "type": "scatter3d", - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scattermapbox": [ - { - "type": "scattermapbox", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scatterternary": [ - { - "type": "scatterternary", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scattercarpet": [ - { - "type": "scattercarpet", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "baxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "type": "carpet" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#EBF0F8" - }, - "line": { - "color": "white" - } - }, - "header": { - "fill": { - "color": "#C8D4E3" - }, - "line": { - "color": "white" - } - }, - "type": "table" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ] - }, - "layout": { - "autotypenumbers": "strict", - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#2a3f5f" - }, - "hovermode": "closest", - "hoverlabel": { - "align": "left" - }, - "paper_bgcolor": "white", - "plot_bgcolor": "#E5ECF6", - "polar": { - "bgcolor": "#E5ECF6", - "angularaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "radialaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "ternary": { - "bgcolor": "#E5ECF6", - "aaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "baxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "caxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "sequential": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ] - }, - "xaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "automargin": true, - "zerolinewidth": 2 - }, - "yaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "automargin": true, - "zerolinewidth": 2 - }, - "scene": { - "xaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white", - "gridwidth": 2 - }, - "yaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white", - "gridwidth": 2 - }, - "zaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white", - "gridwidth": 2 - } - }, - "shapedefaults": { - "line": { - "color": "#2a3f5f" - } - }, - "annotationdefaults": { - "arrowcolor": "#2a3f5f", - "arrowhead": 0, - "arrowwidth": 1 - }, - "geo": { - "bgcolor": "white", - "landcolor": "#E5ECF6", - "subunitcolor": "white", - "showland": true, - "showlakes": true, - "lakecolor": "white" - }, - "title": { - "x": 0.05 - }, - "mapbox": { - "style": "light" - } - } - }, - "xaxis": { - "anchor": "y", - "domain": [ - 0.0, - 1.0 - ], - "title": { - "text": "Score" - } - }, - "yaxis": { - "anchor": "x", - "domain": [ - 0.0, - 1.0 - ], - "title": { - "text": "Feature" - } - }, - "coloraxis": { - "colorbar": { - "title": { - "text": "Score" - } - }, - "colorscale": [ - [ - 0.0, - "rgb(103,0,31)" - ], - [ - 0.1, - "rgb(178,24,43)" - ], - [ - 0.2, - "rgb(214,96,77)" - ], - [ - 0.3, - "rgb(244,165,130)" - ], - [ - 0.4, - "rgb(253,219,199)" - ], - [ - 0.5, - "rgb(247,247,247)" - ], - [ - 0.6, - "rgb(209,229,240)" - ], - [ - 0.7, - "rgb(146,197,222)" - ], - [ - 0.8, - "rgb(67,147,195)" - ], - [ - 0.9, - "rgb(33,102,172)" - ], - [ - 1.0, - "rgb(5,48,97)" - ] - ] - }, - "legend": { - "tracegroupgap": 0 - }, - "margin": { - "t": 60 - }, - "barmode": "relative" - } - } - } - ] - }, - "datasetName": "reporting.feature_importance", - "datasetType": "plotly.json_dataset.JSONDataset", - "runIds": [ - "2022-12-24T21.05.59.296Z", - "2022-10-05T12.22.35.825Z", - "2022-09-05T12.27.04.496Z" - ], - "__typename": "TrackingDataset" - }, - { - "data": { - "confusion_matrix.png": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": "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" - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": "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nS4NcExERIS6d+9e+3OXLl10ySWXqKSkRPv27XOwMgDBwvFbkVmspq477rjD2rNnj1VRUWGtW7fOuvzyyx2vicVyciUmJlp1yc7Odrw2Fovl/PL8+z8AAADAJdgDCAAA4DIEQAAAAJchAAIAALgMARAAAMBlCIAAAAAuQwAEAABwGQIgAACAyxAAATRJdna2cnNza39euXKlMjIymr2OxMREWZalqKioZv9sAGhpCICAobKzs2VZlizLUmVlpT777DM98sgjatWq1Rn93Ouvv16PPPKIrXMJbQDgDL4LGDDYkiVLdPPNNyssLExDhgxRVlaWqqqq9MQTT/idFxoaqqqqqoB85qFDhwJyHQDAmUMHEDBYZWWlioqKtHfvXj3//PNavny5rr322tqxbXp6uvLz87Vz505J0gUXXKDXX39dhw4d0jfffKOFCxeqc+fOtdcLCQnR008/rUOHDungwYN68skn5fF4/D7z+yNgr9erJ554Qnv37lVFRYU+++wzjRs3Tp07d9b7778vSTp8+LAsy1J2drYkyePxKDU1VV988YWOHz+uTz75RDfccIPf5yQlJWnnzp06fvy4VqxYoZ/85Cdn4F8QAMxEAARcpLy8XF6vV5I0cOBA9ejRQ4MGDdLQoUPVunVrLV26VGVlZerfv79+8Ytf6OjRo/r73/+u0NBQSdJ9992nlJQUjRs3Tv369dO5556rESNGnPIzX375ZY0ePVp33XWXLrroIt1+++06evSo9u3bp+uvv16SFBMTow4dOmjy5MmSpLS0NN10002aMGGCevbsqYyMDP3pT39SQkKCpG+D6ptvvqnFixerd+/e+uMf/3hSVxMAcGoWi8Uyb2VnZ1u5ubm1Pw8cONAqLy+3nnrqKSs7O9vav3+/FRoaWvv62LFjre3bt/tdIzQ01Dp27Jg1aNAgS5KVn59v3X///bWvt2rVytq7d6/f56xcudLKyMiwJFkXXnihZVmWNXDgwDprTExMtCzLsqKiomqPeb1e6+jRo1ZcXJzfuX/4wx+sV1991ZJk/e53v7M+/fRTv9dnzpx50rVYLBaLVfdiDyBgsKFDh6qsrEyhoaEKCQnRn//8Zz366KPKysrS1q1b/fb9XXLJJerevbvKysr8rtGmTRt169ZN69evV8eOHbV+/fra16qrq/XRRx+dNAb+Tu/evXXixAmtWrXKds3du3dXRESE3nvvPb/jXq9XH3/8sSTpoosu8qtDkvLy8mx/BgC4HQEQMNjKlSs1ceJE+Xw+FRQUqLq6uva1Y8eO+Z3btm1bbdy4UWPHjj3pOsXFxaf1+eXl5Y1+T9u2bSVJ11xzjfLz8/1eq6ysPK06AAD+CICAwY4dO6bdu3fbOnfTpk0aOXKkDhw4cFIX8DsFBQX6+c9/rjVr1kiSWrVqpdjYWG3atKnO87du3aqQkBAlJibqH//4x0mv+3y+2ut851//+pcqKirUqVMnrV69us7rbt++Xddee63fsbi4uIZ/SQCAJG4CAfBvr776qg4ePKhFixapX79++slPfqLExETNnTtX559/viRp7ty5Sk1N1fDhw9WjRw8999xzOuecc+q95ldffaWcnBy99NJLGj58eO01f/WrX9W+XlNTo6FDh6pdu3aKiIjQ0aNHNWvWLGVkZOimm25S165ddemll+rOO+/UTTfdJEl6/vnndeGFF+qpp55STEyMRo8erZSUlDP9TwQARnF8IyKLxQr8+v5NIHZei46OtubPn28dOHDAKi8vtz7//HPrhRdesCIjIy3p25s+MjIyrMOHD1slJSXWrFmzrPnz59d7E4gkKywszHr66aet/Px8q6Kiwtq1a5eVkpJS+/rDDz9sFRQUWNXV1VZ2dnbt8bvuusvavn27VVlZaRUVFVlLliyx+vfvX/v6NddcY+3atcsqLy+3Vq1aZaWkpHATCIvFYtlcnn//BwAAALgEI2AAAACXIQACAAC4DAEQAADAZQiAAAAALkMABAAAcBkCIAAAgMsQAAEAAFyGAAgAAOAyBEAAAACXIQACAAC4DAEQAADAZQiAAAAALvN/cz2wbupCr8YAAAAASUVORK5CYII=" - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": "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tHnzZknS1VdfHVCHJHm9XtufAQBuRwAEDLZ27VpNmDBBPp9P+/fvV0VFReVrJ0+eDDi3ZcuWysvL02233XbWdQ4dOlSnzy8tLa31e1q2bClJuummm1RYWBjwWnl5eZ3qAAAEIgACBjt58qR27dpl69xNmzZp2LBhOnjw4FldwO/t379f119/vT788ENJUrNmzZSQkKBNmzZVef5nn32m8PBwJScn6/333z/rdZ/PV3md73355ZcqKytTXFycPvjggyqvW1BQoFtuuSXgWK9evWr+JQEAktgEAuA/XnnlFR0+fFhLly5Vnz59dMUVVyg5OVlz5szRpZdeKkmaM2eOpkyZorS0NHXp0kXPPfecWrduXe01//3vfys3N1cvv/yy0tLSKq/561//uvJ1v9+vQYMGqU2bNoqKitKJEyf0zDPPKDs7W3fccYeuvPJK9ejRQ/fcc4/uuOMOSdL8+fN11VVX6emnn1bnzp01YsQIjRo1qqH/EQGAURy/EZHFYgV//XgTiJ3XYmJirIULF1oHDx60SktLrZ07d1ovvPCCFR0dbUnfbfrIzs62vv32W+vIkSPWM888Yy1cuLDaTSCSrMjISGvWrFlWYWGhVVZWZm3fvt0aNWpU5euPPvqotX//fquiosLKycmpPD5p0iSroKDAKi8vt4qLi62VK1daffv2rXz9pptusrZv326VlpZa69evt0aNGsUmEBaLxbK5wv7zfwAAAOASjIABAABchgAIAADgMgRAAAAAlyEAAgAAuAwBEAAAwGUIgAAAAC5DAAQAAHAZAiAAAIDLEAABAABchgAIAADgMgRAAAAAlyEAAgAAuMz/BwrBiw1swOnjAAAAAElFTkSuQmCC" - } - ] - }, - "datasetName": "reporting.confusion_matrix", - "datasetType": "matplotlib.matplotlib_writer.MatplotlibWriter", - "runIds": [ - "2022-12-24T21.05.59.296Z", - "2022-10-05T12.22.35.825Z", - "2022-09-05T12.27.04.496Z" - ], - "__typename": "TrackingDataset" - } - ], - "metrics": [ - { - "data": { - "a2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 3.6 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 8.0 - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": 1.4000000000000001 - } - ], - "b2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 3.1 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 8.3 - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": 6.1000000000000005 - } - ], - "r2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 0.40296896595214116 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 0.40296896595214116 - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": 0.40296896595214116 - } - ] - }, - "datasetName": "train_evaluation.linear_regression.r2_score", - "datasetType": "tracking.metrics_dataset.MetricsDataset", - "runIds": [ - "2022-12-24T21.05.59.296Z", - "2022-10-05T12.22.35.825Z", - "2022-09-05T12.27.04.496Z" - ], - "__typename": "TrackingDataset" - }, - { - "data": { - "a2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 4.1000000000000005 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 0.5 - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": 5.5 - } - ], - "b2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 8.4 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 6.800000000000001 - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": 0.1 - } - ], - "r2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 8.700000000000001 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 8.8 - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": 7.1000000000000005 - } - ] - }, - "datasetName": "train_evaluation.random_forest.r2_score", - "datasetType": "tracking.metrics_dataset.MetricsDataset", - "runIds": [ - "2022-12-24T21.05.59.296Z", - "2022-10-05T12.22.35.825Z", - "2022-09-05T12.27.04.496Z" - ], - "__typename": "TrackingDataset" - } - ], - "JSONData": [ - { - "data": { - "model_type": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": "LinearRegression" - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": "LinearRegression" - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": "LinearRegression" - } - ], - "fit_intercept": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": true - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": true - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": true - } - ], - "normalize": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": false - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": false - } - ], - "copy_X": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": { - "precision": { - "prec1": "BTS", - "prec2": 0.4564, - "prec4": "GHD", - "prec5": 0.34343 - }, - "recall": 0.97154, - "f1_score": 0.984534, - "support": 0.2323 - } - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": { - "precision": 0.6423, - "recall": 0.23154, - "f1_score": 0.54534, - "support": 0.222223 - } - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": true - } - ], - "positive": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": false - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": false - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": false - } - ] - }, - "datasetName": "train_evaluation.linear_regression.experiment_params", - "datasetType": "tracking.json_dataset.JSONDataset", - "runIds": [ - "2022-12-24T21.05.59.296Z", - "2022-10-05T12.22.35.825Z", - "2022-09-05T12.27.04.496Z" - ], - "__typename": "TrackingDataset" - }, - { - "data": { - "model_type": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": "RandomForestRegressor" - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": "RandomForestRegressor" - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": "RandomForestRegressor" - } - ], - "n_estimators": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 100 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 100 - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": 100 - } - ], - "criterion": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": "squared_error" - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": "squared_error" - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": "squared_error" - } - ], - "min_samples_split": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 2 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 2 - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": 2 - } - ], - "min_samples_leaf": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 1 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 1 - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": 1 - } - ], - "min_weight_fraction_leaf": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 0 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 0 - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": 0 - } - ], - "max_features": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": "auto" - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": "auto" - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": "auto" - } - ], - "min_impurity_decrease": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 0 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 0 - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": 0 - } - ], - "bootstrap": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": true - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": true - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": true - } - ], - "oob_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": false - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": false - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": false - } - ], - "verbose": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 0 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 0 - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": 0 - } - ], - "warm_start": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": false - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": false - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": false - } - ], - "ccp_alpha": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 0 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 0 - }, - { - "runId": "2022-09-05T12.27.04.496Z", - "value": 0 - } - ] - }, - "datasetName": "train_evaluation.random_forest.experiment_params", - "datasetType": "tracking.json_dataset.JSONDataset", - "runIds": [ - "2022-12-24T21.05.59.296Z", - "2022-10-05T12.22.35.825Z", - "2022-09-05T12.27.04.496Z" - ], - "__typename": "TrackingDataset" - } - ] - } -} diff --git a/cypress/fixtures/graphql/compareTwoRuns.json b/cypress/fixtures/graphql/compareTwoRuns.json deleted file mode 100644 index 56198ca42e..0000000000 --- a/cypress/fixtures/graphql/compareTwoRuns.json +++ /dev/null @@ -1,2318 +0,0 @@ -{ - "data": { - "runMetadata": [ - { - "id": "2022-12-24T21.05.59.296Z", - "author": "rashida_kanchwala", - "bookmark": false, - "gitBranch": "add-plots-to-demo", - "gitSha": "5f81cb5", - "notes": "Test", - "runCommand": "kedro run", - "title": "2022-12-24T21.05.59.296Z", - "__typename": "Run" - }, - { - "id": "2022-10-05T12.22.35.825Z", - "author": "rashida_kanchwala", - "bookmark": false, - "gitBranch": "add-plots-to-demo", - "gitSha": "9ff5c54", - "notes": "", - "runCommand": "kedro run", - "title": "2022-10-05T12.22.35.825Z", - "__typename": "Run" - } - ], - "plots": [ - { - "data": { - "feature_importance_plot.json": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": { - "data": [ - { - "alignmentgroup": "True", - "hovertemplate": "Score=%{marker.color}
Features=%{y}", - "legendgroup": "", - "marker": { - "color": [ - 0.02499999999999991, - 0.12199999999999989, - 0.1299999999999999, - 0.1379999999999999, - 0.14900000000000002, - 0.16399999999999992, - 0.16399999999999992, - 0.30099999999999993, - 0.34799999999999986, - 0.43699999999999983, - 0.5659999999999998, - 0.6200000000000001, - 0.7130000000000001, - 0.82, - 0.94 - ], - "coloraxis": "coloraxis", - "pattern": { - "shape": "" - } - }, - "name": "", - "offsetgroup": "", - "orientation": "h", - "showlegend": false, - "textposition": "auto", - "type": "bar", - "x": [ - 0.02499999999999991, - 0.12199999999999989, - 0.1299999999999999, - 0.1379999999999999, - 0.14900000000000002, - 0.16399999999999992, - 0.16399999999999992, - 0.30099999999999993, - 0.34799999999999986, - 0.43699999999999983, - 0.5659999999999998, - 0.6200000000000001, - 0.7130000000000001, - 0.82, - 0.94 - ], - "xaxis": "x", - "y": [ - "feature_14", - "feature_8", - "feature_12", - "feature_1", - "feature_11", - "feature_3", - "feature_9", - "feature_7", - "feature_10", - "feature_6", - "feature_2", - "feature_5", - "feature_13", - "feature_4", - "feature_0" - ], - "yaxis": "y" - } - ], - "layout": { - "barmode": "relative", - "coloraxis": { - "colorbar": { - "title": { - "text": "Score" - } - }, - "colorscale": [ - [ - 0.0, - "rgb(103,0,31)" - ], - [ - 0.1, - "rgb(178,24,43)" - ], - [ - 0.2, - "rgb(214,96,77)" - ], - [ - 0.3, - "rgb(244,165,130)" - ], - [ - 0.4, - "rgb(253,219,199)" - ], - [ - 0.5, - "rgb(247,247,247)" - ], - [ - 0.6, - "rgb(209,229,240)" - ], - [ - 0.7, - "rgb(146,197,222)" - ], - [ - 0.8, - "rgb(67,147,195)" - ], - [ - 0.9, - "rgb(33,102,172)" - ], - [ - 1.0, - "rgb(5,48,97)" - ] - ] - }, - "legend": { - "tracegroupgap": 0 - }, - "margin": { - "t": 60 - }, - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#2a3f5f" - }, - "error_y": { - "color": "#2a3f5f" - }, - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "baxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "type": "heatmap" - } - ], - "heatmapgl": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "type": "heatmapgl" - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergl" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#EBF0F8" - }, - "line": { - "color": "white" - } - }, - "header": { - "fill": { - "color": "#C8D4E3" - }, - "line": { - "color": "white" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#2a3f5f", - "arrowhead": 0, - "arrowwidth": 1 - }, - "autotypenumbers": "strict", - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ], - "sequential": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#2a3f5f" - }, - "geo": { - "bgcolor": "white", - "lakecolor": "white", - "landcolor": "#E5ECF6", - "showlakes": true, - "showland": true, - "subunitcolor": "white" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "light" - }, - "paper_bgcolor": "white", - "plot_bgcolor": "#E5ECF6", - "polar": { - "angularaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "radialaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "yaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "zaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - } - }, - "shapedefaults": { - "line": { - "color": "#2a3f5f" - } - }, - "ternary": { - "aaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "baxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "caxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "xaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - } - } - }, - "xaxis": { - "anchor": "y", - "domain": [ - 0.0, - 1.0 - ], - "title": { - "text": "Score" - } - }, - "yaxis": { - "anchor": "x", - "domain": [ - 0.0, - 1.0 - ], - "title": { - "text": "Features" - } - } - } - } - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": { - "data": [ - { - "alignmentgroup": "True", - "hovertemplate": "Score=%{marker.color}
Feature=%{y}", - "legendgroup": "", - "marker": { - "color": [ - 0.0, - 0.036, - 0.038, - 0.066, - 0.138, - 0.28, - 0.344, - 0.387, - 0.419, - 0.547, - 0.696, - 0.706, - 0.844, - 0.849, - 0.912 - ], - "coloraxis": "coloraxis", - "pattern": { - "shape": "" - } - }, - "name": "", - "offsetgroup": "", - "orientation": "h", - "showlegend": false, - "textposition": "auto", - "x": [ - 0.0, - 0.036, - 0.038, - 0.066, - 0.138, - 0.28, - 0.344, - 0.387, - 0.419, - 0.547, - 0.696, - 0.706, - 0.844, - 0.849, - 0.912 - ], - "xaxis": "x", - "y": [ - "feature_8", - "feature_0", - "feature_4", - "feature_2", - "feature_12", - "feature_13", - "feature_14", - "feature_3", - "feature_1", - "feature_10", - "feature_7", - "feature_5", - "feature_6", - "feature_9", - "feature_11" - ], - "yaxis": "y", - "type": "bar" - } - ], - "layout": { - "template": { - "data": { - "histogram2dcontour": [ - { - "type": "histogram2dcontour", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "choropleth": [ - { - "type": "choropleth", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - ], - "histogram2d": [ - { - "type": "histogram2d", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "heatmap": [ - { - "type": "heatmap", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "heatmapgl": [ - { - "type": "heatmapgl", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "contourcarpet": [ - { - "type": "contourcarpet", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - ], - "contour": [ - { - "type": "contour", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "surface": [ - { - "type": "surface", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ] - } - ], - "mesh3d": [ - { - "type": "mesh3d", - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - ], - "scatter": [ - { - "fillpattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - }, - "type": "scatter" - } - ], - "parcoords": [ - { - "type": "parcoords", - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scatterpolargl": [ - { - "type": "scatterpolargl", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "bar": [ - { - "error_x": { - "color": "#2a3f5f" - }, - "error_y": { - "color": "#2a3f5f" - }, - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "scattergeo": [ - { - "type": "scattergeo", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scatterpolar": [ - { - "type": "scatterpolar", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "scattergl": [ - { - "type": "scattergl", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scatter3d": [ - { - "type": "scatter3d", - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scattermapbox": [ - { - "type": "scattermapbox", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scatterternary": [ - { - "type": "scatterternary", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "scattercarpet": [ - { - "type": "scattercarpet", - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - } - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "baxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "type": "carpet" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#EBF0F8" - }, - "line": { - "color": "white" - } - }, - "header": { - "fill": { - "color": "#C8D4E3" - }, - "line": { - "color": "white" - } - }, - "type": "table" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ] - }, - "layout": { - "autotypenumbers": "strict", - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#2a3f5f" - }, - "hovermode": "closest", - "hoverlabel": { - "align": "left" - }, - "paper_bgcolor": "white", - "plot_bgcolor": "#E5ECF6", - "polar": { - "bgcolor": "#E5ECF6", - "angularaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "radialaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "ternary": { - "bgcolor": "#E5ECF6", - "aaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "baxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "caxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "sequential": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0.0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1.0, - "#f0f921" - ] - ], - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ] - }, - "xaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "automargin": true, - "zerolinewidth": 2 - }, - "yaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "automargin": true, - "zerolinewidth": 2 - }, - "scene": { - "xaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white", - "gridwidth": 2 - }, - "yaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white", - "gridwidth": 2 - }, - "zaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white", - "gridwidth": 2 - } - }, - "shapedefaults": { - "line": { - "color": "#2a3f5f" - } - }, - "annotationdefaults": { - "arrowcolor": "#2a3f5f", - "arrowhead": 0, - "arrowwidth": 1 - }, - "geo": { - "bgcolor": "white", - "landcolor": "#E5ECF6", - "subunitcolor": "white", - "showland": true, - "showlakes": true, - "lakecolor": "white" - }, - "title": { - "x": 0.05 - }, - "mapbox": { - "style": "light" - } - } - }, - "xaxis": { - "anchor": "y", - "domain": [ - 0.0, - 1.0 - ], - "title": { - "text": "Score" - } - }, - "yaxis": { - "anchor": "x", - "domain": [ - 0.0, - 1.0 - ], - "title": { - "text": "Feature" - } - }, - "coloraxis": { - "colorbar": { - "title": { - "text": "Score" - } - }, - "colorscale": [ - [ - 0.0, - "rgb(103,0,31)" - ], - [ - 0.1, - "rgb(178,24,43)" - ], - [ - 0.2, - "rgb(214,96,77)" - ], - [ - 0.3, - "rgb(244,165,130)" - ], - [ - 0.4, - "rgb(253,219,199)" - ], - [ - 0.5, - "rgb(247,247,247)" - ], - [ - 0.6, - "rgb(209,229,240)" - ], - [ - 0.7, - "rgb(146,197,222)" - ], - [ - 0.8, - "rgb(67,147,195)" - ], - [ - 0.9, - "rgb(33,102,172)" - ], - [ - 1.0, - "rgb(5,48,97)" - ] - ] - }, - "legend": { - "tracegroupgap": 0 - }, - "margin": { - "t": 60 - }, - "barmode": "relative" - } - } - } - ] - }, - "datasetName": "reporting.feature_importance", - "datasetType": "plotly.json_dataset.JSONDataset", - "runIds": [ - "2022-12-24T21.05.59.296Z", - "2022-10-05T12.22.35.825Z" - ], - "__typename": "TrackingDataset" - }, - { - "data": { - "confusion_matrix.png": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": "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" - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": "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nS4NcExERIS6d+9e+3OXLl10ySWXqKSkRPv27XOwMgDBwvFbkVmspq477rjD2rNnj1VRUWGtW7fOuvzyyx2vicVyciUmJlp1yc7Odrw2Fovl/PL8+z8AAADAJdgDCAAA4DIEQAAAAJchAAIAALgMARAAAMBlCIAAAAAuQwAEAABwGQIgAACAyxAAATRJdna2cnNza39euXKlMjIymr2OxMREWZalqKioZv9sAGhpCICAobKzs2VZlizLUmVlpT777DM98sgjatWq1Rn93Ouvv16PPPKIrXMJbQDgDL4LGDDYkiVLdPPNNyssLExDhgxRVlaWqqqq9MQTT/idFxoaqqqqqoB85qFDhwJyHQDAmUMHEDBYZWWlioqKtHfvXj3//PNavny5rr322tqxbXp6uvLz87Vz505J0gUXXKDXX39dhw4d0jfffKOFCxeqc+fOtdcLCQnR008/rUOHDungwYN68skn5fF4/D7z+yNgr9erJ554Qnv37lVFRYU+++wzjRs3Tp07d9b7778vSTp8+LAsy1J2drYkyePxKDU1VV988YWOHz+uTz75RDfccIPf5yQlJWnnzp06fvy4VqxYoZ/85Cdn4F8QAMxEAARcpLy8XF6vV5I0cOBA9ejRQ4MGDdLQoUPVunVrLV26VGVlZerfv79+8Ytf6OjRo/r73/+u0NBQSdJ9992nlJQUjRs3Tv369dO5556rESNGnPIzX375ZY0ePVp33XWXLrroIt1+++06evSo9u3bp+uvv16SFBMTow4dOmjy5MmSpLS0NN10002aMGGCevbsqYyMDP3pT39SQkKCpG+D6ptvvqnFixerd+/e+uMf/3hSVxMAcGoWi8Uyb2VnZ1u5ubm1Pw8cONAqLy+3nnrqKSs7O9vav3+/FRoaWvv62LFjre3bt/tdIzQ01Dp27Jg1aNAgS5KVn59v3X///bWvt2rVytq7d6/f56xcudLKyMiwJFkXXnihZVmWNXDgwDprTExMtCzLsqKiomqPeb1e6+jRo1ZcXJzfuX/4wx+sV1991ZJk/e53v7M+/fRTv9dnzpx50rVYLBaLVfdiDyBgsKFDh6qsrEyhoaEKCQnRn//8Zz366KPKysrS1q1b/fb9XXLJJerevbvKysr8rtGmTRt169ZN69evV8eOHbV+/fra16qrq/XRRx+dNAb+Tu/evXXixAmtWrXKds3du3dXRESE3nvvPb/jXq9XH3/8sSTpoosu8qtDkvLy8mx/BgC4HQEQMNjKlSs1ceJE+Xw+FRQUqLq6uva1Y8eO+Z3btm1bbdy4UWPHjj3pOsXFxaf1+eXl5Y1+T9u2bSVJ11xzjfLz8/1eq6ysPK06AAD+CICAwY4dO6bdu3fbOnfTpk0aOXKkDhw4cFIX8DsFBQX6+c9/rjVr1kiSWrVqpdjYWG3atKnO87du3aqQkBAlJibqH//4x0mv+3y+2ut851//+pcqKirUqVMnrV69us7rbt++Xddee63fsbi4uIZ/SQCAJG4CAfBvr776qg4ePKhFixapX79++slPfqLExETNnTtX559/viRp7ty5Sk1N1fDhw9WjRw8999xzOuecc+q95ldffaWcnBy99NJLGj58eO01f/WrX9W+XlNTo6FDh6pdu3aKiIjQ0aNHNWvWLGVkZOimm25S165ddemll+rOO+/UTTfdJEl6/vnndeGFF+qpp55STEyMRo8erZSUlDP9TwQARnF8IyKLxQr8+v5NIHZei46OtubPn28dOHDAKi8vtz7//HPrhRdesCIjIy3p25s+MjIyrMOHD1slJSXWrFmzrPnz59d7E4gkKywszHr66aet/Px8q6Kiwtq1a5eVkpJS+/rDDz9sFRQUWNXV1VZ2dnbt8bvuusvavn27VVlZaRUVFVlLliyx+vfvX/v6NddcY+3atcsqLy+3Vq1aZaWkpHATCIvFYtlcnn//BwAAALgEI2AAAACXIQACAAC4DAEQAADAZQiAAAAALkMABAAAcBkCIAAAgMsQAAEAAFyGAAgAAOAyBEAAAACXIQACAAC4DAEQAADAZQiAAAAALvN/cz2wbupCr8YAAAAASUVORK5CYII=" - } - ] - }, - "datasetName": "reporting.confusion_matrix", - "datasetType": "matplotlib.matplotlib_writer.MatplotlibWriter", - "runIds": [ - "2022-12-24T21.05.59.296Z", - "2022-10-05T12.22.35.825Z" - ], - "__typename": "TrackingDataset" - } - ], - "metrics": [ - { - "data": { - "a2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 3.6 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 8.0 - } - ], - "b2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 3.1 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 8.3 - } - ], - "r2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 0.40296896595214116 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 0.40296896595214116 - } - ] - }, - "datasetName": "train_evaluation.linear_regression.r2_score", - "datasetType": "tracking.metrics_dataset.MetricsDataset", - "runIds": [ - "2022-12-24T21.05.59.296Z", - "2022-10-05T12.22.35.825Z" - ], - "__typename": "TrackingDataset" - }, - { - "data": { - "a2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 4.1000000000000005 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 0.5 - } - ], - "b2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 8.4 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 6.800000000000001 - } - ], - "r2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 8.700000000000001 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 8.8 - } - ] - }, - "datasetName": "train_evaluation.random_forest.r2_score", - "datasetType": "tracking.metrics_dataset.MetricsDataset", - "runIds": [ - "2022-12-24T21.05.59.296Z", - "2022-10-05T12.22.35.825Z" - ], - "__typename": "TrackingDataset" - } - ], - "JSONData": [ - { - "data": { - "model_type": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": "LinearRegression" - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": "LinearRegression" - } - ], - "fit_intercept": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": true - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": true - } - ], - "normalize": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": false - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": false - } - ], - "copy_X": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": { - "precision": { - "prec1": "BTS", - "prec2": 0.4564, - "prec4": "GHD", - "prec5": 0.34343 - }, - "recall": 0.97154, - "f1_score": 0.984534, - "support": 0.2323 - } - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": { - "precision": 0.6423, - "recall": 0.23154, - "f1_score": 0.54534, - "support": 0.222223 - } - } - ], - "positive": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": false - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": false - } - ] - }, - "datasetName": "train_evaluation.linear_regression.experiment_params", - "datasetType": "tracking.json_dataset.JSONDataset", - "runIds": [ - "2022-12-24T21.05.59.296Z", - "2022-10-05T12.22.35.825Z" - ], - "__typename": "TrackingDataset" - }, - { - "data": { - "model_type": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": "RandomForestRegressor" - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": "RandomForestRegressor" - } - ], - "n_estimators": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 100 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 100 - } - ], - "criterion": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": "squared_error" - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": "squared_error" - } - ], - "min_samples_split": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 2 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 2 - } - ], - "min_samples_leaf": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 1 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 1 - } - ], - "min_weight_fraction_leaf": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 0 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 0 - } - ], - "max_features": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": "auto" - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": "auto" - } - ], - "min_impurity_decrease": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 0 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 0 - } - ], - "bootstrap": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": true - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": true - } - ], - "oob_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": false - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": false - } - ], - "verbose": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 0 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 0 - } - ], - "warm_start": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": false - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": false - } - ], - "ccp_alpha": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 0 - }, - { - "runId": "2022-10-05T12.22.35.825Z", - "value": 0 - } - ] - }, - "datasetName": "train_evaluation.random_forest.experiment_params", - "datasetType": "tracking.json_dataset.JSONDataset", - "runIds": [ - "2022-12-24T21.05.59.296Z", - "2022-10-05T12.22.35.825Z" - ], - "__typename": "TrackingDataset" - } - ] - } -} diff --git a/cypress/fixtures/graphql/getMetricPlotData.json b/cypress/fixtures/graphql/getMetricPlotData.json deleted file mode 100644 index bae18f9511..0000000000 --- a/cypress/fixtures/graphql/getMetricPlotData.json +++ /dev/null @@ -1,134 +0,0 @@ -{ - "data": { - "runMetricsData": { - "data": { - "metrics": { - "train_evaluation.linear_regression.r_score.a2_score": [ - 3.6, 8.0, 1.4000000000000001, 9.600000000000001, 7.7, 8.9, - 3.8000000000000003, 3.9000000000000004, 2.8000000000000003, - 1.9000000000000001, 7.5, 9.700000000000001, 2.8000000000000003, 2.1, - 1.0, 6.0, 2.1, 8.1, 9.0, 6.6000000000000005, 2.1, 7.9 - ], - "train_evaluation.linear_regression.r2_score.b2_score": [ - 3.1, 8.3, 6.1000000000000005, 9.5, 6.6000000000000005, 3.2, 1.0, - 6.6000000000000005, 1.1, 6.7, 8.5, 0.2, 7.300000000000001, 7.7, 3.6, - 7.1000000000000005, 6.300000000000001, 6.4, 5.1000000000000005, 7.5, - 6.300000000000001, 2.8000000000000003 - ], - "train_evaluation.linear_regression.r2_score.r2_score": [ - 0.40296896595214116, 0.40296896595214116, 0.40296896595214116, - 0.40296896595214116, 0.40296896595214116, 0.40296896595214116, - 0.40296896595214116, 0.40296896595214116, 0.40296896595214116, - 0.40296896595214116, 0.42984606386233715, 0.4298460638623369, - 0.40296896595214116, 0.42984606386233737, 0.42984606386233715, - 0.42984606386233715, 0.42984606386233715, 0.4298460638623375, - 0.4298460638623375, 0.4298460638623375, 0.4298460638623369, - 0.42984606386233715 - ], - "train_evaluation.random_forest.r2_score.a2_score": [ - 4.1000000000000005, 0.5, 5.5, 9.8, 6.800000000000001, - 4.1000000000000005, 1.8, 3.9000000000000004, 8.5, 4.4, 6.2, 4.5, - 1.2000000000000002, 2.8000000000000003, 2.5, 8.4, 7.5, 7.0, 9.9, - 2.6, 5.6000000000000005, 1.6 - ], - "train_evaluation.random_forest.r2_score.b2_score": [ - 8.4, 6.800000000000001, 0.1, 5.4, 8.700000000000001, 1.0, 0.1, - 5.300000000000001, 9.1, 8.1, 1.6, 3.6, 7.800000000000001, - 6.800000000000001, 4.4, 8.4, 9.1, 1.7000000000000002, - 4.800000000000001, 3.5, 5.2, 9.200000000000001 - ], - "train_evaluation.random_forest.r2_score.r2_score": [ - 8.700000000000001, 8.8, 7.1000000000000005, 5.300000000000001, - 5.6000000000000005, 3.3000000000000003, 5.7, 7.4, 9.9, - 0.6000000000000001, 0.6000000000000001, 7.4, 9.200000000000001, 2.7, - 1.5, 1.3, 6.6000000000000005, 0.7000000000000001, - 7.6000000000000005, 6.2, 6.1000000000000005, 1.4000000000000001 - ] - }, - "runs": { - "2022-12-24T21.05.59.296Z": [ - 3.6, 3.1, 0.40296896595214116, 4.1000000000000005, 8.4, - 8.700000000000001 - ], - "2022-10-05T12.22.35.825Z": [ - 8.0, 8.3, 0.40296896595214116, 0.5, 6.800000000000001, 8.8 - ], - "2022-09-05T12.27.04.496Z": [ - 1.4000000000000001, 6.1000000000000005, 0.40296896595214116, 5.5, - 0.1, 7.1000000000000005 - ], - "2022-08-24T21.04.31.605Z": [ - 9.600000000000001, 9.5, 0.40296896595214116, 9.8, 5.4, - 5.300000000000001 - ], - "2022-07-22T13.49.08.764Z": [ - 7.7, 6.6000000000000005, 0.40296896595214116, 6.800000000000001, - 8.700000000000001, 5.6000000000000005 - ], - "2022-07-21T12.54.06.759Z": [ - 8.9, 3.2, 0.40296896595214116, 4.1000000000000005, 1.0, - 3.3000000000000003 - ], - "2022-07-20T15.39.58.437Z": [ - 3.8000000000000003, 1.0, 0.40296896595214116, 1.8, 0.1, 5.7 - ], - "2022-06-22T13.13.06.258Z": [ - 3.9000000000000004, 6.6000000000000005, 0.40296896595214116, - 3.9000000000000004, 5.300000000000001, 7.4 - ], - "2022-06-22T13.06.42.364Z": [ - 2.8000000000000003, 1.1, 0.40296896595214116, 8.5, 9.1, 9.9 - ], - "2022-06-06T18.02.47.732Z": [ - 1.9000000000000001, 6.7, 0.40296896595214116, 4.4, 8.1, - 0.6000000000000001 - ], - "2022-05-16T09.48.12.714Z": [ - 7.5, 8.5, 0.42984606386233715, 6.2, 1.6, 0.6000000000000001 - ], - "2022-05-05T09.47.46.344Z": [ - 9.700000000000001, 0.2, 0.4298460638623369, 4.5, 3.6, 7.4 - ], - "2022-04-24T21.03.25.671Z": [ - 2.8000000000000003, 7.300000000000001, 0.40296896595214116, - 1.2000000000000002, 7.800000000000001, 9.200000000000001 - ], - "2022-04-16T09.47.19.553Z": [ - 2.1, 7.7, 0.42984606386233737, 2.8000000000000003, - 6.800000000000001, 2.7 - ], - "2022-02-16T09.46.53.117Z": [ - 1.0, 3.6, 0.42984606386233715, 2.5, 4.4, 1.5 - ], - "2022-02-01T09.46.21.973Z": [ - 6.0, 7.1000000000000005, 0.42984606386233715, 8.4, 8.4, 1.3 - ], - "2021-12-16T09.45.00.604Z": [ - 2.1, 6.300000000000001, 0.42984606386233715, 7.5, 9.1, - 6.6000000000000005 - ], - "2021-12-16T09.43.54.586Z": [ - 8.1, 6.4, 0.4298460638623375, 7.0, 1.7000000000000002, - 0.7000000000000001 - ], - "2021-11-16T09.45.28.204Z": [ - 9.0, 5.1000000000000005, 0.4298460638623375, 9.9, 4.800000000000001, - 7.6000000000000005 - ], - "2021-09-01T09.45.55.269Z": [ - 6.6000000000000005, 7.5, 0.4298460638623375, 2.6, 3.5, 6.2 - ], - "2021-08-16T09.44.26.749Z": [ - 2.1, 6.300000000000001, 0.4298460638623369, 5.6000000000000005, 5.2, - 6.1000000000000005 - ], - "2021-08-08T09.43.11.320Z": [ - 7.9, 2.8000000000000003, 0.42984606386233715, 1.6, - 9.200000000000001, 1.4000000000000001 - ] - } - }, - "__typename": "MetricPlotDataset" - } - } -} diff --git a/cypress/fixtures/graphql/getRunData.json b/cypress/fixtures/graphql/getRunData.json deleted file mode 100644 index 04c89bedb5..0000000000 --- a/cypress/fixtures/graphql/getRunData.json +++ /dev/null @@ -1,881 +0,0 @@ -{ - "data": { - "runMetadata": [ - { - "id": "2022-12-24T21.05.59.296Z", - "author": "rashida_kanchwala", - "bookmark": false, - "gitBranch": "add-plots-to-demo", - "gitSha": "5f81cb5", - "notes": "", - "runCommand": "kedro run", - "title": "2022-12-24T21.05.59.296Z", - "__typename": "Run" - } - ], - "plots": [ - { - "data": { - "feature_importance_plot.json": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": { - "data": [ - { - "alignmentgroup": "True", - "hovertemplate": "Score=%{marker.color}
Features=%{y}", - "legendgroup": "", - "marker": { - "color": [ - 0.02499999999999991, 0.12199999999999989, - 0.1299999999999999, 0.1379999999999999, - 0.14900000000000002, 0.16399999999999992, - 0.16399999999999992, 0.30099999999999993, - 0.34799999999999986, 0.43699999999999983, - 0.5659999999999998, 0.6200000000000001, - 0.7130000000000001, 0.82, 0.94 - ], - "coloraxis": "coloraxis", - "pattern": { - "shape": "" - } - }, - "name": "", - "offsetgroup": "", - "orientation": "h", - "showlegend": false, - "textposition": "auto", - "type": "bar", - "x": [ - 0.02499999999999991, 0.12199999999999989, - 0.1299999999999999, 0.1379999999999999, - 0.14900000000000002, 0.16399999999999992, - 0.16399999999999992, 0.30099999999999993, - 0.34799999999999986, 0.43699999999999983, - 0.5659999999999998, 0.6200000000000001, - 0.7130000000000001, 0.82, 0.94 - ], - "xaxis": "x", - "y": [ - "feature_14", - "feature_8", - "feature_12", - "feature_1", - "feature_11", - "feature_3", - "feature_9", - "feature_7", - "feature_10", - "feature_6", - "feature_2", - "feature_5", - "feature_13", - "feature_4", - "feature_0" - ], - "yaxis": "y" - } - ], - "layout": { - "barmode": "relative", - "coloraxis": { - "colorbar": { - "title": { - "text": "Score" - } - }, - "colorscale": [ - [0.0, "rgb(103,0,31)"], - [0.1, "rgb(178,24,43)"], - [0.2, "rgb(214,96,77)"], - [0.3, "rgb(244,165,130)"], - [0.4, "rgb(253,219,199)"], - [0.5, "rgb(247,247,247)"], - [0.6, "rgb(209,229,240)"], - [0.7, "rgb(146,197,222)"], - [0.8, "rgb(67,147,195)"], - [0.9, "rgb(33,102,172)"], - [1.0, "rgb(5,48,97)"] - ] - }, - "legend": { - "tracegroupgap": 0 - }, - "margin": { - "t": 60 - }, - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#2a3f5f" - }, - "error_y": { - "color": "#2a3f5f" - }, - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "baxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [0.0, "#0d0887"], - [0.1111111111111111, "#46039f"], - [0.2222222222222222, "#7201a8"], - [0.3333333333333333, "#9c179e"], - [0.4444444444444444, "#bd3786"], - [0.5555555555555556, "#d8576b"], - [0.6666666666666666, "#ed7953"], - [0.7777777777777778, "#fb9f3a"], - [0.8888888888888888, "#fdca26"], - [1.0, "#f0f921"] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [0.0, "#0d0887"], - [0.1111111111111111, "#46039f"], - [0.2222222222222222, "#7201a8"], - [0.3333333333333333, "#9c179e"], - [0.4444444444444444, "#bd3786"], - [0.5555555555555556, "#d8576b"], - [0.6666666666666666, "#ed7953"], - [0.7777777777777778, "#fb9f3a"], - [0.8888888888888888, "#fdca26"], - [1.0, "#f0f921"] - ], - "type": "heatmap" - } - ], - "heatmapgl": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [0.0, "#0d0887"], - [0.1111111111111111, "#46039f"], - [0.2222222222222222, "#7201a8"], - [0.3333333333333333, "#9c179e"], - [0.4444444444444444, "#bd3786"], - [0.5555555555555556, "#d8576b"], - [0.6666666666666666, "#ed7953"], - [0.7777777777777778, "#fb9f3a"], - [0.8888888888888888, "#fdca26"], - [1.0, "#f0f921"] - ], - "type": "heatmapgl" - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [0.0, "#0d0887"], - [0.1111111111111111, "#46039f"], - [0.2222222222222222, "#7201a8"], - [0.3333333333333333, "#9c179e"], - [0.4444444444444444, "#bd3786"], - [0.5555555555555556, "#d8576b"], - [0.6666666666666666, "#ed7953"], - [0.7777777777777778, "#fb9f3a"], - [0.8888888888888888, "#fdca26"], - [1.0, "#f0f921"] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [0.0, "#0d0887"], - [0.1111111111111111, "#46039f"], - [0.2222222222222222, "#7201a8"], - [0.3333333333333333, "#9c179e"], - [0.4444444444444444, "#bd3786"], - [0.5555555555555556, "#d8576b"], - [0.6666666666666666, "#ed7953"], - [0.7777777777777778, "#fb9f3a"], - [0.8888888888888888, "#fdca26"], - [1.0, "#f0f921"] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergl" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [0.0, "#0d0887"], - [0.1111111111111111, "#46039f"], - [0.2222222222222222, "#7201a8"], - [0.3333333333333333, "#9c179e"], - [0.4444444444444444, "#bd3786"], - [0.5555555555555556, "#d8576b"], - [0.6666666666666666, "#ed7953"], - [0.7777777777777778, "#fb9f3a"], - [0.8888888888888888, "#fdca26"], - [1.0, "#f0f921"] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#EBF0F8" - }, - "line": { - "color": "white" - } - }, - "header": { - "fill": { - "color": "#C8D4E3" - }, - "line": { - "color": "white" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#2a3f5f", - "arrowhead": 0, - "arrowwidth": 1 - }, - "autotypenumbers": "strict", - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [0, "#8e0152"], - [0.1, "#c51b7d"], - [0.2, "#de77ae"], - [0.3, "#f1b6da"], - [0.4, "#fde0ef"], - [0.5, "#f7f7f7"], - [0.6, "#e6f5d0"], - [0.7, "#b8e186"], - [0.8, "#7fbc41"], - [0.9, "#4d9221"], - [1, "#276419"] - ], - "sequential": [ - [0.0, "#0d0887"], - [0.1111111111111111, "#46039f"], - [0.2222222222222222, "#7201a8"], - [0.3333333333333333, "#9c179e"], - [0.4444444444444444, "#bd3786"], - [0.5555555555555556, "#d8576b"], - [0.6666666666666666, "#ed7953"], - [0.7777777777777778, "#fb9f3a"], - [0.8888888888888888, "#fdca26"], - [1.0, "#f0f921"] - ], - "sequentialminus": [ - [0.0, "#0d0887"], - [0.1111111111111111, "#46039f"], - [0.2222222222222222, "#7201a8"], - [0.3333333333333333, "#9c179e"], - [0.4444444444444444, "#bd3786"], - [0.5555555555555556, "#d8576b"], - [0.6666666666666666, "#ed7953"], - [0.7777777777777778, "#fb9f3a"], - [0.8888888888888888, "#fdca26"], - [1.0, "#f0f921"] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#2a3f5f" - }, - "geo": { - "bgcolor": "white", - "lakecolor": "white", - "landcolor": "#E5ECF6", - "showlakes": true, - "showland": true, - "subunitcolor": "white" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "light" - }, - "paper_bgcolor": "white", - "plot_bgcolor": "#E5ECF6", - "polar": { - "angularaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "radialaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "yaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "zaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - } - }, - "shapedefaults": { - "line": { - "color": "#2a3f5f" - } - }, - "ternary": { - "aaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "baxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "caxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "xaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - } - } - }, - "xaxis": { - "anchor": "y", - "domain": [0.0, 1.0], - "title": { - "text": "Score" - } - }, - "yaxis": { - "anchor": "x", - "domain": [0.0, 1.0], - "title": { - "text": "Features" - } - } - } - } - } - ] - }, - "datasetName": "reporting.feature_importance", - "datasetType": "plotly.json_dataset.JSONDataset", - "runIds": ["2022-12-24T21.05.59.296Z"], - "__typename": "TrackingDataset" - }, - { - "data": { - "confusion_matrix.png": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": "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" - } - ] - }, - "datasetName": "reporting.confusion_matrix", - "datasetType": "matplotlib.matplotlib_writer.MatplotlibWriter", - "runIds": ["2022-12-24T21.05.59.296Z"], - "__typename": "TrackingDataset" - } - ], - "metrics": [ - { - "data": { - "a2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 3.6 - } - ], - "b2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 3.1 - } - ], - "r2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 0.40296896595214116 - } - ] - }, - "datasetName": "train_evaluation.linear_regression.r2_score", - "datasetType": "tracking.metrics_dataset.MetricsDataset", - "runIds": ["2022-12-24T21.05.59.296Z"], - "__typename": "TrackingDataset" - }, - { - "data": { - "a2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 4.1000000000000005 - } - ], - "b2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 8.4 - } - ], - "r2_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 8.700000000000001 - } - ] - }, - "datasetName": "train_evaluation.random_forest.r2_score", - "datasetType": "tracking.metrics_dataset.MetricsDataset", - "runIds": ["2022-12-24T21.05.59.296Z"], - "__typename": "TrackingDataset" - } - ], - "JSONData": [ - { - "data": { - "model_type": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": "LinearRegression" - } - ], - "fit_intercept": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": true - } - ], - "normalize": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": false - } - ], - "copy_X": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": { - "precision": { - "prec1": "BTS", - "prec2": 0.4564, - "prec4": "GHD", - "prec5": 0.34343 - }, - "recall": 0.97154, - "f1_score": 0.984534, - "support": 0.2323 - } - } - ], - "positive": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": false - } - ] - }, - "datasetName": "train_evaluation.linear_regression.experiment_params", - "datasetType": "tracking.json_dataset.JSONDataset", - "runIds": ["2022-12-24T21.05.59.296Z"], - "__typename": "TrackingDataset" - }, - { - "data": { - "model_type": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": "RandomForestRegressor" - } - ], - "n_estimators": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 100 - } - ], - "criterion": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": "squared_error" - } - ], - "min_samples_split": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 2 - } - ], - "min_samples_leaf": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 1 - } - ], - "min_weight_fraction_leaf": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 0 - } - ], - "max_features": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": "auto" - } - ], - "min_impurity_decrease": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 0 - } - ], - "bootstrap": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": true - } - ], - "oob_score": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": false - } - ], - "verbose": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 0 - } - ], - "warm_start": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": false - } - ], - "ccp_alpha": [ - { - "runId": "2022-12-24T21.05.59.296Z", - "value": 0 - } - ] - }, - "datasetName": "train_evaluation.random_forest.experiment_params", - "datasetType": "tracking.json_dataset.JSONDataset", - "runIds": ["2022-12-24T21.05.59.296Z"], - "__typename": "TrackingDataset" - } - ] - } -} diff --git a/cypress/fixtures/graphql/getRunsList.json b/cypress/fixtures/graphql/getRunsList.json deleted file mode 100644 index b631b578a5..0000000000 --- a/cypress/fixtures/graphql/getRunsList.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "data": { - "runsList": [ - { - "bookmark": false, - "gitSha": "5f81cb5", - "id": "2022-12-24T21.05.59.296Z", - "title": "2022-12-24T21.05.59.296Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "9ff5c54", - "id": "2022-10-05T12.22.35.825Z", - "title": "2022-10-05T12.22.35.825Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "9ff5c54", - "id": "2022-09-05T12.27.04.496Z", - "title": "2022-09-05T12.27.04.496Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "5f81cb5", - "id": "2022-08-24T21.04.31.605Z", - "title": "2022-08-24T21.04.31.605Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "a7b9938f", - "id": "2022-07-22T13.49.08.764Z", - "title": "2022-07-22T13.49.08.764Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "4d678b9", - "id": "2022-07-21T12.54.06.759Z", - "title": "2022-07-21T12.54.06.759Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "637f232", - "id": "2022-07-20T15.39.58.437Z", - "title": "2022-07-20T15.39.58.437Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "f5b3a9b7", - "id": "2022-06-22T13.13.06.258Z", - "title": "2022-06-22T13.13.06.258Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "f5b3a9b7", - "id": "2022-06-22T13.06.42.364Z", - "title": "2022-06-22T13.06.42.364Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "e38c4a67", - "id": "2022-06-06T18.02.47.732Z", - "title": "2022-06-06T18.02.47.732Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "7707b23", - "id": "2022-05-16T09.48.12.714Z", - "title": "2022-05-16T09.48.12.714Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "7707b23", - "id": "2022-05-05T09.47.46.344Z", - "title": "2022-05-05T09.47.46.344Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "5f81cb5", - "id": "2022-04-24T21.03.25.671Z", - "title": "2022-04-24T21.03.25.671Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "7707b23", - "id": "2022-04-16T09.47.19.553Z", - "title": "2022-04-16T09.47.19.553Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "7707b23", - "id": "2022-02-16T09.46.53.117Z", - "title": "2022-02-16T09.46.53.117Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "7707b23", - "id": "2022-02-01T09.46.21.973Z", - "title": "2022-02-01T09.46.21.973Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "7707b23", - "id": "2021-12-16T09.45.00.604Z", - "title": "second edit", - "notes": "My new note text is here", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "7707b23", - "id": "2021-12-16T09.43.54.586Z", - "title": "edited run", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "7707b23", - "id": "2021-11-16T09.45.28.204Z", - "title": "2021-11-16T09.45.28.204Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "7707b23", - "id": "2021-09-01T09.45.55.269Z", - "title": "2021-09-01T09.45.55.269Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "7707b23", - "id": "2021-08-16T09.44.26.749Z", - "title": "2021-08-16T09.44.26.749Z", - "notes": "", - "__typename": "Run" - }, - { - "bookmark": false, - "gitSha": "7707b23", - "id": "2021-08-08T09.43.11.320Z", - "title": "2021-08-08T09.43.11.320Z", - "notes": "", - "__typename": "Run" - } - ] - } -} diff --git a/cypress/fixtures/graphql/updateBookmark.json b/cypress/fixtures/graphql/updateBookmark.json deleted file mode 100644 index 083e820014..0000000000 --- a/cypress/fixtures/graphql/updateBookmark.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "data": { - "updateRunDetails": { - "run": { - "bookmark": true, - "id": "2022-12-24T21.05.59.296Z", - "notes": "mock bookmark update", - "title": "2022-12-24T21.05.59.296Z", - "__typename": "Run" - }, - "__typename": "UpdateRunDetailsSuccess" - } - } -} diff --git a/cypress/fixtures/graphql/updateRunContent.json b/cypress/fixtures/graphql/updateRunContent.json deleted file mode 100644 index 9a357b4d1f..0000000000 --- a/cypress/fixtures/graphql/updateRunContent.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "data": { - "updateRunDetails": { - "run": { - "bookmark": false, - "id": "2022-12-24T21.05.59.296Z", - "notes": "Test", - "title": "2022-12-25T21.05.59.296Z", - "__typename": "Run" - }, - "__typename": "UpdateRunDetailsSuccess" - } - } -} \ No newline at end of file diff --git a/cypress/fixtures/graphql/updateRunNotes.json b/cypress/fixtures/graphql/updateRunNotes.json deleted file mode 100644 index 308250066a..0000000000 --- a/cypress/fixtures/graphql/updateRunNotes.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "data": { - "updateRunDetails": { - "run": { - "bookmark": false, - "id": "2022-12-24T21.05.59.296Z", - "notes": "Test", - "title": "2022-12-24T21.05.59.296Z", - "__typename": "Run" - }, - "__typename": "UpdateRunDetailsSuccess" - } - } -} \ No newline at end of file diff --git a/cypress/fixtures/graphql/updateRunTitle.json b/cypress/fixtures/graphql/updateRunTitle.json deleted file mode 100644 index 87c72bdd83..0000000000 --- a/cypress/fixtures/graphql/updateRunTitle.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "data": { - "updateRunDetails": { - "run": { - "bookmark": false, - "id": "2022-12-24T21.05.59.296Z", - "notes": "", - "title": "2022-12-25T21.05.59.296Z", - "__typename": "Run" - }, - "__typename": "UpdateRunDetailsSuccess" - } - } -} \ No newline at end of file diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 169fc93cc8..d57261b556 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -127,81 +127,15 @@ Cypress.Commands.add('__validateImage__', (downloadedFilename) => { }); }); -/** - * Custom command to validate the downloaded csv - * @param {String} downloadedFilename - * @param {Array} recordToCompare - */ -Cypress.Commands.add( - '__validateCsv__', - (downloadedFilename, recordToCompare) => { - const downloadsFolder = Cypress.config('downloadsFolder'); - - if (!downloadedFilename) { - downloadedFilename = join(downloadsFolder, 'data.csv'); - } - - cy.readFile(`${downloadsFolder}/${downloadedFilename}`, { - timeout: 5000, - }).then((csvContent) => { - const modifiedCsvContent = csvContent.replace(/\\|"/g, ''); - - expect(modifiedCsvContent).to.have.length.gt(50); - - const records = modifiedCsvContent.split('\n'); - - cy.wrap(records[0].trim()).should('eq', recordToCompare.join(',').trim()); - }); - } -); - /** * Custom command to conditionally visit a page based on spec file path */ Cypress.Commands.add('__conditionalVisit__', () => { - const specPath = Cypress.spec.relative; - - if (specPath.includes('experiment-tracking')) { - // Queries - cy.__interceptGql__('getRunsList'); - cy.__interceptGql__('getRunData'); - cy.__interceptGql__('getMetricPlotData'); - - cy.visit('/experiment-tracking'); - - cy.wait(['@getRunsList', '@getRunData', '@getMetricPlotData']); - } else { - cy.visit('/'); - } + cy.visit('/'); }); /** - * Custom command to go into comparison mode and select three runs - */ -Cypress.Commands.add('__comparisonMode__', () => { - // Alias - cy.get('.switch__input').as('compareRunsToggle'); - - // Action - cy.get('@compareRunsToggle').check({ force: true }); - - // Mutation for two run comparison - cy.__interceptGql__('getRunData', 'compareTwoRuns'); - - // Action and wait - cy.get(':nth-child(2) > .runs-list-card__checked').click(); - cy.wait('@compareTwoRuns').its('response.statusCode').should('eq', 200); - - // Mutations for three run comparison - cy.__interceptGql__('getRunData', 'compareThreeRuns'); - - // Action and wait - cy.get(':nth-child(3) > .runs-list-card__checked').click(); - cy.wait('@compareThreeRuns').its('response.statusCode').should('eq', 200); -}); - -/** - * Custom command to fillout and submit the hosting shareable URL form + * Custom command to fill out and submit the hosting shareable URL form */ Cypress.Commands.add( '__setupAndSubmitShareableUrlForm__', @@ -220,14 +154,18 @@ Cypress.Commands.add( cy.get('.pipeline-menu-button--deploy').click(); // Select the first hosting platform from the dropdown - cy.get('.shareable-url-modal [data-test=shareable-url-modal-dropdown-hosting-platform]').click(); + cy.get( + '.shareable-url-modal [data-test=shareable-url-modal-dropdown-hosting-platform]' + ).click(); cy.get('.shareable-url-modal .dropdown__options section div').eq(1).click(); // Fill in the form - cy.get('.shareable-url-modal [data-test="shareable-url-modal-input-bucket-name"]').type(bucketName); - cy.get('.shareable-url-modal [data-test="shareable-url-modal-input-endpoint"]').type( - endpointName - ); + cy.get( + '.shareable-url-modal [data-test="shareable-url-modal-input-bucket-name"]' + ).type(bucketName); + cy.get( + '.shareable-url-modal [data-test="shareable-url-modal-input-endpoint"]' + ).type(endpointName); // Submit the form cy.get('.shareable-url-modal__button-wrapper button') @@ -240,14 +178,15 @@ Cypress.Commands.add( * Custom command to wait for page load before enabling pretty names */ Cypress.Commands.add('__waitForSettingsButton__', () => { - cy.get('[data-test="global-toolbar-settings-btn"]', { timeout: 20000 }).should('be.visible'); + cy.get('[data-test="global-toolbar-settings-btn"]', { + timeout: 20000, + }).should('be.visible'); }); /** * Custom command to enable pretty name */ Cypress.Commands.add('enablePrettyNames', () => { - // Wait for the settings button to be visible cy.__waitForSettingsButton__(); @@ -255,10 +194,12 @@ Cypress.Commands.add('enablePrettyNames', () => { cy.get('[data-test="global-toolbar-settings-btn"]').click(); // Enable the pretty names setting - cy.get('[data-test*="settings-modal-toggle-isPrettyName-"]').check({ force: true }); + cy.get('[data-test*="settings-modal-toggle-isPrettyName-"]').check({ + force: true, + }); // Apply changes and close the settings panel cy.get('[data-test="settings-modal-apply-btn"]').click({ - force: true, - }); + force: true, + }); }); diff --git a/cypress/tests/ui/experiment-tracking/experiment-tracking.cy.js b/cypress/tests/ui/experiment-tracking/experiment-tracking.cy.js deleted file mode 100644 index 53940ff564..0000000000 --- a/cypress/tests/ui/experiment-tracking/experiment-tracking.cy.js +++ /dev/null @@ -1,230 +0,0 @@ -// All E2E Tests Related to experiment tracking goes here. - -import { prettifyName, stripNamespace } from '../../../../src/utils'; - -describe('Experiment Tracking', () => { - describe('Overview', () => { - it('verifies that users can edit the run name, apply changes, and see the changes reflected from the overview page. #TC-43', () => { - const modifiedRunTitleText = '2022-12-25T21.05.59.296Z'; - - // Alias - cy.get('.details-metadata__title').first().as('metadataTitle'); - cy.get('[data-test="run-details-modal-apply-changes"]').as( - 'applyChanges' - ); - - // Assert before action - cy.get('.modal--visible').should('not.exist'); - - // Action - cy.get('@metadataTitle').click(); - - // Assert after action - cy.get('.modal--visible').should('exist'); - - cy.get('.modal--visible').within(() => { - cy.get(':nth-child(2) > .input').as('inputField'); - cy.get('@inputField').clear(); - cy.get('@inputField').type(modifiedRunTitleText); - cy.get('@applyChanges').click(); - }); - - cy.get('.modal--visible').should('not.exist'); - cy.get('.runs-list-card__title') - .first() - .should('have.text', modifiedRunTitleText); - cy.get('@metadataTitle').should('have.text', modifiedRunTitleText); - }); - - it('verifies that users can add notes to the run, apply changes, and see the changes reflected from the overview page. #TC-44', () => { - const modifiedRunNotesText = 'Test'; - - // Alias - cy.get('.details-metadata__notes').as('metadataNotes'); - cy.get('[data-test="run-details-modal-apply-changes"]').as( - 'applyChanges' - ); - - // Assert before action - cy.get('.modal--visible').should('not.exist'); - - // Action - cy.get('@metadataNotes').click(); - - // Assert after action - cy.get('.modal--visible').then(($dialog) => { - cy.wrap($dialog).within(() => { - cy.get(':nth-child(3) > .input').clear(); - cy.get(':nth-child(3) > .input').type(modifiedRunNotesText); - cy.get('@applyChanges').click(); - }); - }); - - cy.get('.modal--visible').should('not.exist'); - cy.get('@metadataNotes').should('have.text', modifiedRunNotesText); - }); - }); - - describe('Metrics', () => { - beforeEach(() => { - // Go into metrics tab - - // Alias - cy.get('.details__tabs > :nth-child(2)').as('metricsTab'); - - // Action - cy.get('@metricsTab').click(); - - // Assert after action - cy.get('@metricsTab').should('have.class', 'tabs__item--active'); - }); - - it('verifies that in comparison mode time-series view, users can select the run(s) and see it in the plot. #TC-45', () => { - // Go into comparison mode and select three runs - cy.__comparisonMode__(); - - const runIds = [0, 1, 2]; - - // Assert for time series plot - cy.get(':nth-child(1) > .chart-types-wrapper__tab').should( - 'have.class', - 'chart-types-wrapper__tab--active' - ); - runIds.map((id) => - cy.get(`.time-series__run-line--selected-${id}`).should('exist') - ); - runIds.map((id) => - cy.get(`.time-series__marker--selected-${id}`).should('exist') - ); - }); - - it('verifies that in comparison mode time-series view, users can select/unselect the metrics apply changes, and see the changes in the plot. #TC-46', () => { - // Go into comparison mode and select three runs - cy.__comparisonMode__(); - - const plotToCheckText = - 'train_evaluation.linear_regression.r_score.a2_score'; - - // Assert before action - cy.get('.time-series__metric-name') - .first() - .invoke('text') - .should((text) => { - expect(text.trim()).to.be.eq(plotToCheckText.trim()); - }); - - // Action - cy.get('.select-dropdown [data-test="experiments-metrics-select-dropdown"]').click(); - cy.get('.dropdown__options > :nth-child(2)').click(); - cy.get('[data-test="experiments-metrics-select-dropdown-apply-btn"]').click(); - - // Assert after action - cy.get('.time-series__metric-name') - .first() - .invoke('text') - .should((text) => { - expect(text.trim()).to.be.not.eq(plotToCheckText.trim()); - }); - }); - - it('verifies that in comparison mode parallel coordinates view, users can select the run(s) and see it in the plot. #TC-47', () => { - // Go into comparison mode and select three runs - cy.__comparisonMode__(); - - const runIds = [0, 1, 2]; - - // Alias - cy.get('.chart-types-wrapper > :nth-child(2)').as('parallelView'); - - // Action - cy.get('@parallelView').click(); - - // Assert for parallel coordinates plot - cy.get('@parallelView').should( - 'have.class', - 'chart-types-wrapper__tab--active' - ); - cy.get('.metric-axis').should('exist'); - cy.get('.run-lines').should('exist'); - runIds.map((id) => - cy.get(`.marker-path--selected-${id}`).should('exist') - ); - }); - - it('verifies that in comparison mode parallel coordinates view, users can select/unselect the metrics apply changes, and see the changes in the plot. #TC-48', () => { - // Go into comparison mode and select three runs - cy.__comparisonMode__(); - - const plotToCheckText = - 'train_evaluation.linear_regression.r_score.a2_score'; - // Alias - cy.get('.chart-types-wrapper > :nth-child(2)').as('parallelView'); - cy.get('@parallelView').click(); - - // Assert before action - cy.get(`.metric-axis`) - .should('have.attr', 'id') - .and('eq', plotToCheckText); - - // Action - cy.get('.select-dropdown [data-test="experiments-metrics-select-dropdown"]').click(); - cy.get('.dropdown__options > :nth-child(2)').click(); - cy.get('[data-test="experiments-metrics-select-dropdown-apply-btn"]').click(); - - // Assert after action - cy.get(`.metric-axis`) - .should('have.attr', 'id') - .and('not.eq', plotToCheckText); - }); - }); - - describe('Plots', () => { - beforeEach(() => { - // Go into Plots tab - - // Alias - cy.get('.details__tabs > :nth-child(3)').as('plotsTab'); - - // Action - cy.get('@plotsTab').click(); - - // Assert after action - cy.get('@plotsTab').should('have.class', 'tabs__item--active'); - - cy.enablePrettyNames(); // Enable pretty names using the custom command - }); - - it('verifies that users can select the metrics name, and it takes them to the metrics in the DAG. #TC-49', () => { - const plotNameText = 'reporting.feature_importance'; - - cy.enablePrettyNames(); - - // Action - cy.get('.accordion__title--hyperlink').first().click(); - - // Assert after action - cy.location('search').should( - 'contain', - `?pid=__default__&sn=${plotNameText}` - ); - cy.__checkForText__( - '.pipeline-node--selected > .pipeline-node__text', - prettifyName(stripNamespace(plotNameText)) - ); - cy.__checkForText__( - '.pipeline-metadata__title', - prettifyName(stripNamespace(plotNameText)) - ); - }); - - it('verifies that in comparison mode in plots tab, users can select the run(s) and see them in the UI. #TC-50', () => { - // Go into comparison mode and select three runs - cy.__comparisonMode__(); - - // Assert - cy.get('.details-dataset__row').should('have.length', 4); - cy.get('.details-dataset__value').should('have.length', 6); - cy.get('.details-dataset__image').should('have.length', 3); - }); - }); -}); diff --git a/cypress/tests/ui/experiment-tracking/menu.cy.js b/cypress/tests/ui/experiment-tracking/menu.cy.js deleted file mode 100644 index 24d1064f86..0000000000 --- a/cypress/tests/ui/experiment-tracking/menu.cy.js +++ /dev/null @@ -1,101 +0,0 @@ -// All E2E Tests Related to Experiment Tracking Menu goes here. - -describe('Experiment Tracking Menu', () => { - it('verifies that users can search for a run. #TC-34', () => { - const searchInput = '2022-09'; - - // Action - cy.get('.search-input__field').type(searchInput); - - // Assert after action - cy.get('.runs-list-card', { timeout: 5000 }) - .should('exist') - .should('have.length', 1); - cy.get('.runs-list-card__title') - .should('exist') - .should('contains.text', searchInput); - }); - - it('verifies that users can bookmark a run. #TC-35', () => { - - // Alias - cy.get('.runs-list__accordion-header > .accordion__title').as( - 'accordionTitle' - ); - - // Assert before action - cy.get('@accordionTitle').should('contains.text', 'All'); - cy.get('@accordionTitle').should('have.length', 1); - cy.get('.runs-list-card__bookmark--solid').should('not.exist'); - - // Action - cy.get('.runs-list-card__bookmark').first().click(); - - // Assert after action - cy.get('@accordionTitle').first().should('contains.text', 'Bookmarked'); - cy.get('@accordionTitle').should('have.length', 2); - cy.get('.runs-list-card__bookmark--solid').should('exist'); - }); - - it('verifies that users can toggle compare runs option. #TC-36', () => { - // Alias - cy.get('.switch__input').as('compareRunsToggle'); - - // Assert before action - cy.get('@compareRunsToggle').should('not.be.checked'); - cy.get('.runs-list-card__checked--comparing').should('not.exist'); - - // Action - cy.get('@compareRunsToggle').check({ force: true }); - - // Assert after action - cy.get('@compareRunsToggle').should('be.checked'); - cy.get('.runs-list-card__checked--comparing').should('exist'); - }); - - it('verifies that in the comparison mode, the users can select upto 3 different runs. #TC-37', () => { - const runsSelectedClass = 'runs-list-card__checked--selected'; - - // Alias - cy.get('.switch__input').as('compareRunsToggle'); - - // Assert before action - cy.get(`.${runsSelectedClass}-first`).should('not.exist'); - cy.get('.details-metadata__run--first-run-comparison-view').should( - 'not.exist' - ); - cy.get('.runs-list-card--disabled').should('not.exist'); - - // Action - cy.get('@compareRunsToggle').check({ force: true }); - - // Assert first action - cy.get(`.${runsSelectedClass}-first`).should('exist'); - - // Mutation for two run comparison - cy.__interceptGql__('getRunData', 'compareTwoRuns'); - - // Action and wait - cy.get(`.${runsSelectedClass}-second`).should('not.exist'); - cy.get(':nth-child(2) > .runs-list-card__checked').click(); - cy.wait('@compareTwoRuns').its('response.statusCode').should('eq', 200); - - // Assert second action - cy.get(`.${runsSelectedClass}-second`).should('exist'); - - // Mutations for three run comparison - cy.__interceptGql__('getRunData', 'compareThreeRuns'); - - // Action and wait - cy.get(`.${runsSelectedClass}-third`).should('not.exist'); - cy.get(':nth-child(3) > .runs-list-card__checked').click(); - cy.wait('@compareThreeRuns').its('response.statusCode').should('eq', 200); - - // Assert third action - cy.get(`.${runsSelectedClass}-third`).should('exist'); - - // Assert after all actions - cy.get('.details-metadata__run--first-run-comparison-view').should('exist'); - cy.get('.runs-list-card--disabled').should('exist'); - }); -}); diff --git a/cypress/tests/ui/experiment-tracking/panel.cy.js b/cypress/tests/ui/experiment-tracking/panel.cy.js deleted file mode 100644 index 89283d77f0..0000000000 --- a/cypress/tests/ui/experiment-tracking/panel.cy.js +++ /dev/null @@ -1,154 +0,0 @@ -// All E2E Tests Related to Experiment Tracking Primary Toolbar goes here. - -describe('Experiment Tracking Primary Toolbar', () => { - it('verifies that users can hide/show the side menu. #TC-38', () => { - // Alias - cy.get('[data-test*="sidebar-experiments-visible-btn-"]').as('btnToggleMenu'); - cy.get('.pipeline-sidebar--visible').as('pipelineSideBar'); - - // Assert before action - cy.__checkForAriaLabel__('@btnToggleMenu', 'Hide menu'); - cy.get('@pipelineSideBar').should('exist'); - - // Action - cy.get('@btnToggleMenu').click(); - - // Assert after action - cy.__checkForAriaLabel__('@btnToggleMenu', 'Show menu'); - cy.get('@pipelineSideBar').should('not.exist'); - }); - - it('verifies that users can bookmark a run using the bookmark button in the options panel. #TC-39', () => { - const runGitShaText = '5f81cb5'; - - // Alias - cy.get('[data-test*="sidebar-experiments-bookmark-btn-"]').as('btnToggleBookmark'); - cy.get('.runs-list__accordion-header > .accordion__title').as( - 'accordionTitle' - ); - - // Assert before action - cy.get('@btnToggleBookmark').should( - 'not.contains.class', - 'pipeline-icon-toolbar__button--active' - ); - cy.get('@accordionTitle').should('have.length', 1); - - // Action - cy.get('@btnToggleBookmark').click(); - - // Assert after action - cy.get('@accordionTitle').first().should('contains.text', 'Bookmarked'); - cy.get('@accordionTitle').should('have.length', 2); - cy.get('@btnToggleBookmark').should( - 'contains.class', - 'pipeline-icon-toolbar__button--active' - ); - cy.get('.runs-list-card__gitsha') - .first() - .should('have.text', runGitShaText); - cy.get( - '.details-metadata__run--wrapper > .details-metadata__run > :nth-child(4)' - ).should('have.text', runGitShaText); - }); - - it('verifies that users can edit the details of a run by using the ‘Edit details’ button in the options panel. #TC-40', () => { - const modifiedRunTitleText = '2022-12-25T21.05.59.296Z'; - const modifiedRunNotesText = 'Test'; - - // Alias - cy.get('[data-test="sidebar-experiments-edit-details"]').as('btnEditRunDetails'); - cy.get('[data-test="run-details-modal-apply-changes"]').as( - 'applyChanges' - ); - - // Assert before action - cy.get('.modal--visible').should('not.exist'); - - // Action - cy.get('@btnEditRunDetails').click(); - - // Assert after action - cy.get('.modal--visible').then(($dialog) => { - cy.wrap($dialog).within(() => { - cy.get('.modal__title').should('have.text', 'Edit run details'); - cy.get( - ':nth-child(2) > .pipeline-settings-modal__header > .pipeline-settings-modal__name' - ).should('have.text', 'Run name'); - cy.get( - ':nth-child(3) > .pipeline-settings-modal__header > .pipeline-settings-modal__name' - ).should('have.text', 'Notes'); - - cy.get(':nth-child(2) > .input').clear(); - cy.get(':nth-child(2) > .input').type(modifiedRunTitleText); - - cy.get(':nth-child(3) > .input').clear(); - cy.get(':nth-child(3) > .input').type(modifiedRunNotesText); - - cy.get('@applyChanges').click(); - }); - }); - - cy.get('.modal--visible').should('not.exist'); - cy.get('.runs-list-card__title') - .first() - .should('have.text', modifiedRunTitleText); - cy.get('.details-metadata__notes').should( - 'have.text', - modifiedRunNotesText - ); - }); - - it('verifies that users can export the selected run data, using the ‘Export run data’ button. #TC-41', () => { - const exportRunTitleText = '2022-12-24T21.05.59.296Z'; - - // Alias - cy.get('[data-test="sidebar-experiments-export-runs"]').as('btnExportRunData'); - cy.get('[data-test="run-export-modal-export-all"]').as('btnExportAll'); - - // Action - cy.get('@btnExportRunData').click(); - - // Assert after action - cy.get('.modal--visible').then(($dialog) => { - cy.wrap($dialog).within(() => { - cy.get('.modal__title').should('have.text', 'Export experiment run'); - cy.get('@btnExportAll').click(); - }); - }); - - cy.get('.modal--visible').should('not.exist'); - cy.__validateCsv__('run-data.csv', ['Title', exportRunTitleText]); - }); - - it('verifies that in the comparison mode, users can disable/enable the metrics changes using the ‘disable/enable show changes’ button. #TC-42', () => { - // Alias - cy.get('.switch__input').as('compareRunsToggle'); - - // Action - cy.get('@compareRunsToggle').check({ force: true }); - - // Assert in comparison mode before selecting multiple runs - cy.get('[data-test*="sidebar-experiments-show-changes-btn-"]').as('btnToggleChange'); - cy.get('@btnToggleChange').should('have.attr', 'disabled'); - - // Mutation for two run comparison - cy.__interceptGql__('getRunData', 'compareTwoRuns'); - - // Action and wait - cy.get(':nth-child(2) > .runs-list-card__checked').click(); - cy.wait('@compareTwoRuns').its('response.statusCode').should('eq', 200); - - // Assert in comparison mode - cy.get('@btnToggleChange').should('not.have.attr', 'disabled'); - cy.get('.details-dataset__deltaValue').should('exist'); - cy.get('.dataset-arrow-icon').should('exist'); - - // Toggle Change - cy.get('@btnToggleChange').click(); - - // Assert after toggle action - cy.get('.details-dataset__deltaValue').should('not.exist'); - cy.get('.dataset-arrow-icon').should('not.exist'); - }); -}); diff --git a/cypress/tests/ui/flowchart/flowchart.cy.js b/cypress/tests/ui/flowchart/flowchart.cy.js index f3f241dcb3..805a042f6c 100644 --- a/cypress/tests/ui/flowchart/flowchart.cy.js +++ b/cypress/tests/ui/flowchart/flowchart.cy.js @@ -173,24 +173,6 @@ describe('Flowchart DAG', () => { ).should('exist'); }); - it('verifies that users can navigate to experiment tracking by clicking on Open in Experiment Tracking button on the metadata panel. #TC-32', () => { - const nodeToClickText = 'R2 Score'; - - // Assert before action - cy.location('pathname').should('not.eq', '/experiment-tracking'); - cy.location('search').should('not.eq', '?view=Metrics'); - - // Action - cy.contains('text', nodeToClickText).click({ force: true }); - cy.get('.pipeline-metadata__link').click(); - - // Assert after action - cy.location('pathname').should('eq', '/experiment-tracking'); - cy.location('search').should('eq', '?view=Metrics'); - cy.get('.details-mainframe').should('exist'); - cy.get('.details__tabs').should('exist'); - }); - it('verifies that users see an error message when there are no nodes/pipelines. #TC-33', () => { // Intercept the network request to mock with a fixture cy.__interceptRest__('/api/main', 'GET', '/mock/emptyDataset.json'); diff --git a/cypress/tests/ui/toolbar/global-toolbar.cy.js b/cypress/tests/ui/toolbar/global-toolbar.cy.js index 64971aa1d7..4b35c12036 100644 --- a/cypress/tests/ui/toolbar/global-toolbar.cy.js +++ b/cypress/tests/ui/toolbar/global-toolbar.cy.js @@ -8,29 +8,6 @@ describe('Global Toolbar', () => { cy.enablePrettyNames(); // Enable pretty names using the custom command }); - it('verifies that users can access the flowchart page through the flowchart icon, when in the experiment tracking view. #TC-1', () => { - cy.visit('/experiment-tracking'); - cy.get('[data-test="global-toolbar-flowchart-btn"]').click(); - cy.location('pathname').should('eq', '/'); - - // should exist - cy.get('.pipeline-wrapper').should('exist'); - - // should not exist - cy.get('.details__tabs').should('not.exist'); - }); - - it('verifies that users can access the experiment tracking page through the experiment tracking button, when in the flowchart view. #TC-2', () => { - cy.get('[data-test="global-toolbar-experiments-btn"]').click(); - cy.location('pathname').should('eq', '/experiment-tracking'); - - // should exist - cy.get('.details__tabs').should('exist'); - - // should not exist - cy.get('.pipeline-wrapper').should('not.exist'); - }); - it('verifies that users can change the theme from light to dark theme, or dark to light theme. #TC-3', () => { // Alias cy.get('[data-test*="global-toolbar-theme-btn-"]').as('toggleTheme'); @@ -69,7 +46,6 @@ describe('Global Toolbar', () => { const prettyNodeNameText = prettifyName( stripNamespace(originalNodeNameText) ); - const nodeNameType = 'plotly' const modularPipelineText = 'reporting'; // Alias @@ -81,14 +57,22 @@ describe('Global Toolbar', () => { cy.get('@isPrettyNameCheckbox').should('be.checked'); // Menu - cy.get(`[data-test="node-list-tree-item--row--${prettifyName(modularPipelineText)}"]`).click(); - cy.get(`[data-test="node-list-tree-item--row--${prettyNodeNameText}"]`).should('exist'); + cy.get( + `[data-test="node-list-tree-item--row--${prettifyName( + modularPipelineText + )}"]` + ).click(); + cy.get( + `[data-test="node-list-tree-item--row--${prettyNodeNameText}"]` + ).should('exist'); // Flowchart cy.get('.pipeline-node__text').should('contain', prettyNodeNameText); // Metadata - cy.get(`[data-test="node-list-tree-item--row--${prettyNodeNameText}"]`).click({ force: true }); + cy.get( + `[data-test="node-list-tree-item--row--${prettyNodeNameText}"]` + ).click({ force: true }); cy.get('.pipeline-metadata__title').should( 'have.text', prettyNodeNameText @@ -106,7 +90,9 @@ describe('Global Toolbar', () => { // Assert after action cy.__waitForPageLoad__(() => { // Menu - cy.get(`[data-test="node-list-tree-item--row--${originalNodeNameText}"]`).should('exist'); + cy.get( + `[data-test="node-list-tree-item--row--${originalNodeNameText}"]` + ).should('exist'); // Flowchart cy.get('.pipeline-node__text').should('contain', originalNodeNameText); @@ -158,20 +144,27 @@ describe('Global Toolbar', () => { const modularPipelineChildNodeText = 'Create Derived Features'; // Alias for better readability - cy.get('[data-test*="sidebar-flowchart-expand-pipeline-btn-"]').as('expandAllPipelinesToggle'); + cy.get('[data-test*="sidebar-flowchart-expand-pipeline-btn-"]').as( + 'expandAllPipelinesToggle' + ); // Assert before action cy.get('@expandAllPipelinesToggle').should('not.be.checked'); - cy.get('.pipeline-node__text').should('not.contain', modularPipelineChildNodeText); + cy.get('.pipeline-node__text').should( + 'not.contain', + modularPipelineChildNodeText + ); cy.get('[role="treeitem"]').should('have.attr', 'aria-expanded', 'false'); // Action - toggling the expand all pipelines directly from the toolbar cy.get('@expandAllPipelinesToggle').click(); // Assert after action - cy.get('[role="treeitem"]') - .should('have.attr', 'aria-expanded', 'true'); - cy.get('.pipeline-node__text').should('contain', modularPipelineChildNodeText); + cy.get('[role="treeitem"]').should('have.attr', 'aria-expanded', 'true'); + cy.get('.pipeline-node__text').should( + 'contain', + modularPipelineChildNodeText + ); }); }); }); diff --git a/package-lock.json b/package-lock.json index 9de9baa9a4..1f27a03a84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "@quantumblack/kedro-viz", - "version": "9.2.0", + "version": "10.1.0", "dependencies": { "@apollo/client": "^3.5.6", "@emotion/react": "^11.10.6", @@ -34816,4 +34816,4 @@ } } } -} \ No newline at end of file +} diff --git a/package.json b/package.json index 6bb5472a34..7aaba69b92 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ }, "proxy": "http://localhost:4142/", "scripts": { - "build": "cross-env GENERATE_SOURCEMAP=false react-scripts build && cp ./build/index.html ./build/404.html", + "build": "cross-env GENERATE_SOURCEMAP=false react-scripts build", "postbuild": "rm -rf build/api", "start": "REACT_APP_DATA_SOURCE=$DATA NODE_OPTIONS=\"--dns-result-order=ipv4first\" npm-run-all -p start:app start:lib", "start:dev": "rm -rf node_modules/.cache && npm start", @@ -172,4 +172,4 @@ "not op_mini all" ], "snyk": true -} \ No newline at end of file +} diff --git a/package/test_requirements.txt b/package/test_requirements.txt index c2ac8e7c78..9d5dbb5c7e 100644 --- a/package/test_requirements.txt +++ b/package/test_requirements.txt @@ -3,12 +3,12 @@ kedro >=0.18.0 kedro-datasets[pandas.ParquetDataset, pandas.CSVDataset, pandas.ExcelDataset, plotly.JSONDataset]>=2.1.0 kedro-telemetry>=0.1.1 # for testing telemetry integration -bandit~=1.7 +bandit~=1.8 behave~=1.2 -boto3~=1.34 +boto3~=1.35 matplotlib~=3.9 mypy~=1.11 -moto~=5.0.9 +moto~=5.0.21 psutil==5.9.6 # same as Kedro for now pytest~=8.3 pytest-asyncio~=0.21 @@ -18,7 +18,7 @@ ruff==0.7.0 sqlalchemy-stubs~=0.4 strawberry-graphql[cli]>=0.99.0, <1.0 trufflehog~=2.2 -httpx~=0.27.0 +httpx~=0.28.0 pathspec>=0.12.1 # mypy diff --git a/src/actions/index.js b/src/actions/index.js index e169c38900..43583214a2 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -326,36 +326,6 @@ export function toggleBookmark(bookmark, runId) { }; } -export const UPDATE_RUN_TITLE = 'UPDATE_RUN_TITLE'; - -/** - * Update Run title - * @param {String} title - * @param {string} runId - */ -export function updateRunTitle(title, runId) { - return { - type: UPDATE_RUN_TITLE, - title, - runId, - }; -} - -export const UPDATE_RUN_NOTES = 'UPDATE_RUN_NOTES'; - -/** - * Update Run Notes - * @param {String} notes - * @param {string} runId - */ -export function updateRunNotes(notes, runId) { - return { - type: UPDATE_RUN_NOTES, - notes, - runId, - }; -} - export const UPDATE_STATE_FROM_OPTIONS = 'UPDATE_STATE_FROM_OPTIONS'; /** diff --git a/src/apollo/config.js b/src/apollo/config.js index 59bbf2bda8..9d95d36c4e 100644 --- a/src/apollo/config.js +++ b/src/apollo/config.js @@ -7,10 +7,9 @@ import { Observable, } from '@apollo/client'; import { onError } from '@apollo/client/link/error'; -import { sanitizedPathname } from '../utils'; import loadJsonData from '../store/load-data'; -const apiBaseUrl = `${sanitizedPathname()}graphql`; +const apiBaseUrl = `/graphql`; // HTTP link for GraphQL API calls const httpLink = new HttpLink({ diff --git a/src/apollo/queries.js b/src/apollo/queries.js index a5676220cc..138d8a3a49 100644 --- a/src/apollo/queries.js +++ b/src/apollo/queries.js @@ -1,61 +1,5 @@ import gql from 'graphql-tag'; -/** query for runsList sidebar */ -export const GET_RUNS = gql` - query getRunsList { - runsList { - gitSha - id - } - } -`; - -/** query for runMetadata and runDataset components */ -export const GET_RUN_DATA = gql` - query getRunData($runIds: [ID!]!, $showDiff: Boolean) { - runMetadata(runIds: $runIds) { - id - author - gitBranch - gitSha - runCommand - } - plots: runTrackingData(runIds: $runIds, showDiff: $showDiff, group: PLOT) { - ...trackingDatasetFields - } - metrics: runTrackingData( - runIds: $runIds - showDiff: $showDiff - group: METRIC - ) { - ...trackingDatasetFields - } - JSONData: runTrackingData( - runIds: $runIds - showDiff: $showDiff - group: JSON - ) { - ...trackingDatasetFields - } - } - - fragment trackingDatasetFields on TrackingDataset { - data - datasetName - datasetType - runIds - } -`; - -/** query for runMetricsData */ -export const GET_METRIC_PLOT_DATA = gql` - query getMetricPlotData($limit: Int) { - runMetricsData(limit: $limit) { - data - } - } -`; - /** query for obtaining installed and latest Kedro-Viz versions */ export const GET_VERSIONS = gql` query getVersion { diff --git a/src/components/app/app.scss b/src/components/app/app.scss index bd53527605..7968fa1624 100644 --- a/src/components/app/app.scss +++ b/src/components/app/app.scss @@ -25,24 +25,6 @@ --color-base-20: #{colors.$grey-300}; --color-black-10: #{colors.$white-200}; --color-border-line: #{colors.$white-500}; - - // Experiment tracking colors below - --color-exp-tracking-bg: #{colors.$white-0}; - --color-exp-tracking-metadata: #{colors.$white-0}; - --color-exp-tracking-datasets: #{colors.$white-100}; - --color-metrics-plot-text: #{colors.$grey-200}; - --color-metrics-plot-text-bold: #{colors.$black-900}; - --color-metrics-plot-axis-ends: #{colors.$grey-800}; - --color-metrics-plot-parallel-coords-line: #{colors.$white-200}; - --color-metrics-plot-parallel-coords-line-hover: #{colors.$black-0}; - --color-metrics-plot-parallel-coords-axis-hover: #{colors.$grey-800}; - --color-metrics-plot-tooltip-value: #{colors.$white-0}; - --color-metrics-plot-tooltip-label: #{colors.$grey-300}; - --color-metrics-plot-time-series-metric-line: #{colors.$grey-200}; - --color-metrics-plot-time-series-axis: #{colors.$grey-300}; - --color-metrics-plot-time-series-run-line: #{colors.$grey-100}; - --color-metrics-plot-time-series-run-line-hovered: #{colors.$black-0}; - --color-metrics-plot-time-series-dotted-line: #{colors.$grey-600}; } .kui-theme--dark { @@ -67,24 +49,6 @@ --color-run-list-hover: #{colors.$slate-0}; --color-base-20: #{colors.$grey-800}; --color-black-10: #{colors.$slate-700}; - - // Experiment tracking colors below - --color-exp-tracking-bg: #{colors.$slate-900}; - --color-exp-tracking-metadata: #{colors.$slate-800}; - --color-exp-tracking-datasets: #{colors.$black-850}; - --color-metrics-plot-text: #{colors.$grey-900}; - --color-metrics-plot-text-bold: #{colors.$white-0}; - --color-metrics-plot-axis-ends: #{colors.$grey-300}; - --color-metrics-plot-parallel-coords-line: #{colors.$slate-300}; - --color-metrics-plot-parallel-coords-line-hover: #{colors.$grey-400}; - --color-metrics-plot-parallel-coords-axis-hover: #{colors.$white-900}; - --color-metrics-plot-tooltip-value: #{colors.$black-900}; - --color-metrics-plot-tooltip-label: #{colors.$black-500}; - --color-metrics-plot-time-series-metric-line: #{colors.$grey-700}; - --color-metrics-plot-time-series-axis: #{colors.$grey-900}; - --color-metrics-plot-time-series-run-line: #{colors.$slate-200}; - --color-metrics-plot-time-series-run-line-hovered: #{colors.$white-0}; - --color-metrics-plot-time-series-dotted-line: #{colors.$grey-500}; } .kedro { diff --git a/src/components/experiment-tracking/accordion/accordion.js b/src/components/experiment-tracking/accordion/accordion.js deleted file mode 100644 index 5da2b56410..0000000000 --- a/src/components/experiment-tracking/accordion/accordion.js +++ /dev/null @@ -1,132 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { generatePath, useLocation } from 'react-router-dom'; -import classnames from 'classnames'; -import { routes } from '../../../config'; -import { saveLocalStorage } from '../../../store/helpers'; -import { localStorageFlowchartLink } from '../../../config'; - -import './accordion.scss'; - -/** - * A collapsable container component. - * @param {Object} children React children - * @param {String|null} className A top-level class name for the component. - * @param {String} heading Text to display on the top-level. - * @param {String|null} headingClassName A class name for the accordion header. - * @param {String|null} headingDetail Text to display on the top-level. - * @param {Boolean} isCollapsed Control to collapse or expand the content. - * @param {Boolean} isHyperlink Whether the button has an anchor link to a different page or not - * @param {String|null} layout A secondary text string for additional context - * @param {String|null} linkTitle A tag defines the title of the element - * @param {Function} onCallback Fire a function on click from a parent. - * @param {String} size Set the header font size. - */ -const Accordion = ({ - children, - className = null, - heading = '', - headingClassName = null, - headingDetail = null, - isCollapsed = false, - isHyperlink = false, - layout = 'right', - linkTitle = null, - onCallback, - size = 'small', -}) => { - const [collapsed, setCollapsed] = useState(isCollapsed); - const [flowchartUrl, setFlowchartUrl] = useState(null); - const { pathname, search } = useLocation(); - - useEffect(() => { - setCollapsed(isCollapsed); - }, [isCollapsed]); - - useEffect(() => { - if (heading.length > 0) { - const url = generatePath(routes.flowchart.selectedName, { - pipelineId: '__default__', - fullName: heading, - }); - - setFlowchartUrl(url); - } - }, [heading]); - - const onClick = () => { - setCollapsed(!collapsed); - onCallback && onCallback(); - }; - - const onLinkToFlowChart = () => { - saveLocalStorage(localStorageFlowchartLink, { - fromURL: pathname + search, - showGoBackBtn: true, - }); - }; - - return ( -
-
- {layout === 'left' && ( -
-
- {children} -
-
- ); -}; - -export default Accordion; diff --git a/src/components/experiment-tracking/accordion/accordion.scss b/src/components/experiment-tracking/accordion/accordion.scss deleted file mode 100644 index 639bfdbd6a..0000000000 --- a/src/components/experiment-tracking/accordion/accordion.scss +++ /dev/null @@ -1,111 +0,0 @@ -@use '../../../styles/variables' as colors; - -$toggle-icon-padding: 0.3em; -$toggle-height: 2.2em + $toggle-icon-padding * 2; -$toggle-width: 1.15em; - -// Standard layout - -.accordion__heading { - align-items: center; - display: flex; - justify-content: space-between; - - &--hide { - visibility: hidden; - } -} - -.accordion__title { - font-size: 1.2em; - font-weight: 600; - - &--medium { - cursor: pointer; - font-size: 1.3em; - font-weight: 600; - text-decoration: underline; - text-underline-offset: 5px; - - &:hover { - font-weight: 700; - } - } - - &--large { - font-size: 1.6em; - } -} - -.accordion__title--hyperlink { - color: var(--color-default-alt); - - &:visited { - color: var(--color-default-alt); - text-decoration: none; - } -} - -.accordion__title__detail { - font-weight: normal; - margin-left: 8px; -} - -.accordion__toggle { - background: none; - border-radius: 50%; - border: none; - box-shadow: none; - color: var(--color-default-alt); - cursor: pointer; - font-family: inherit; - font-size: inherit; - height: $toggle-height; - line-height: 1em; - padding: 0; - text-align: center; - transition: transform ease 0.1s; - width: $toggle-width; - - &:focus { - outline: none; - - [data-whatintent='keyboard'] & { - box-shadow: 0 0 0 3px colors.$blue-300 inset; - } - } - - &::before { - content: 'â–¾'; - font-size: 1.8em; - opacity: 0.55; - } - - &:hover::before { - opacity: 1; - } - - &--alt { - transform: rotate(90deg); - } -} - -.accordion__content--hide { - display: none; -} - -// Layout with left-side toggle - -.accordion--left .accordion__heading { - justify-content: flex-start; -} - -.accordion--left .accordion__title { - margin-left: 0.7em; -} - -.accordion--left .accordion__toggle { - &--alt { - transform: rotate(-90deg); - } -} diff --git a/src/components/experiment-tracking/accordion/accordion.test.js b/src/components/experiment-tracking/accordion/accordion.test.js deleted file mode 100644 index 2b75179cb8..0000000000 --- a/src/components/experiment-tracking/accordion/accordion.test.js +++ /dev/null @@ -1,85 +0,0 @@ -import React from 'react'; -import Accordion from '.'; -import Adapter from '@cfaester/enzyme-adapter-react-18'; -import { configure, mount, shallow } from 'enzyme'; - -configure({ adapter: new Adapter() }); - -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useLocation: () => ({ - pathname: 'localhost:3000/', - }), -})); - -describe('Accordion', () => { - it('renders without crashing', () => { - const wrapper = shallow( - -
1
-
2
-
- ); - - expect(wrapper.find('.accordion').length).toBe(1); - expect(wrapper.find('.accordion__title').length).toBe(1); - expect(wrapper.find('.child').length).toBe(2); - }); - - it('renders the toggle button on the left', () => { - const wrapper = shallow( - -
1
-
2
-
- ); - - expect( - wrapper.find( - '.accordion__heading > .accordion__toggle + .accordion__title' - ).length - ).toBe(1); - }); - - it('renders the toggle button on the right', () => { - const wrapper = shallow( - -
1
-
2
-
- ); - - expect( - wrapper.find( - '.accordion__heading > .accordion__title + .accordion__toggle' - ).length - ).toBe(1); - }); - - it('handles collapsing the accordion with a prop', () => { - const wrapper = shallow( - -
1
-
2
-
- ); - - expect(wrapper.find('.accordion__content--hide').length).toBe(1); - }); - - it('handles collapse button click event', () => { - const setCollapsed = jest.fn(); - const wrapper = mount( - -
1
-
2
-
- ); - const onClick = jest.spyOn(React, 'useState'); - - onClick.mockImplementation((collapsed) => [collapsed, setCollapsed]); - wrapper.find('.accordion__toggle').simulate('click'); - expect(setCollapsed).toBeTruthy(); - expect(wrapper.find('.accordion__content--hide').length).toBe(1); - }); -}); diff --git a/src/components/experiment-tracking/accordion/index.js b/src/components/experiment-tracking/accordion/index.js deleted file mode 100644 index 2a5070a113..0000000000 --- a/src/components/experiment-tracking/accordion/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import Accordion from './accordion'; - -export default Accordion; diff --git a/src/components/experiment-tracking/details/details.js b/src/components/experiment-tracking/details/details.js deleted file mode 100644 index 1794db0304..0000000000 --- a/src/components/experiment-tracking/details/details.js +++ /dev/null @@ -1,208 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import classnames from 'classnames'; -import { ButtonTimeoutContextProvider } from '../../../utils/button-timeout-context'; -import { SingleRunDatasetLoader } from '../run-dataset/run-dataset-loader'; -import { SingleRunMetadataLoader } from '../run-metadata/run-metadata-loader'; -import MetricsPlots from '../metrics-plots'; -import RunDataset from '../run-dataset'; -import RunDetailsModal from '../run-details-modal'; -import RunExportModal from '../run-export-modal'; -import RunMetadata from '../run-metadata'; -import RunPlotsModal from '../run-plots-modal'; -import { tabLabels } from '../../../config'; - -import './details.scss'; - -const Details = ({ - activeTab, - enableComparisonView, - enableShowChanges, - isKedroDatasetsCompatible, - isRunDataLoading, - newRunAdded, - onRunSelection, - pinnedRun, - runDataError, - runMetadata, - runTrackingData, - selectedRunIds, - setActiveTab, - setIsDisplayingMetrics, - setPinnedRun, - setShowRunDetailsModal, - setShowRunExportModal, - setShowRunPlotsModal, - showRunDetailsModal, - showRunExportModal, - showRunPlotsModal, - sidebarVisible, - theme, -}) => { - const [runMetadataToEdit, setRunMetadataToEdit] = useState(null); - const [runDatasetToShow, setRunDatasetToShow] = useState({}); - const [showSingleRunLoader, setShowSingleRunLoader] = useState(false); - const [showRunLoader, setRunLoader] = useState(false); - - // Delay showing loader for 0.2s so it has enough time to load the data first - useEffect(() => { - // For single run - if (isRunDataLoading && !enableComparisonView) { - const showSingleRunLoaderTimer = setTimeout(() => { - setShowSingleRunLoader(true); - }, 200); - - return () => clearTimeout(showSingleRunLoaderTimer); - } else { - setShowSingleRunLoader(false); - } - - // For multiple runs when the comparison mode is active - if (isRunDataLoading && newRunAdded) { - const showRunLoaderTimer = setTimeout(() => { - setRunLoader(true); - }, 200); - - return () => clearTimeout(showRunLoaderTimer); - } else { - setRunLoader(false); - } - }, [isRunDataLoading, newRunAdded, enableComparisonView]); - - useEffect(() => { - if (runMetadata && !enableComparisonView) { - const metadata = runMetadata.find((run) => run.id === selectedRunIds[0]); - - setRunMetadataToEdit(metadata); - } - }, [enableComparisonView, runMetadata, selectedRunIds]); - - useEffect(() => { - if (activeTab === 'Metrics') { - setIsDisplayingMetrics(true); - } else { - setIsDisplayingMetrics(false); - } - }, [activeTab, setIsDisplayingMetrics]); - - const kedroDatasetsCompatibilityMessage = () => { - return !isKedroDatasetsCompatible ? ( -
-

- Kedro-Viz Experiment Tracking is only supported with kedro-datasets - version 2.1.0 and above. Please update kedro-datasets in order to use - this feature. -

-
- ) : null; - }; - - const isSingleRun = runMetadata?.length === 1 ? true : false; - - if (runDataError) { - return null; - } - - if (showSingleRunLoader) { - return ( -
- - -
- ); - } - - return ( - <> - - - - - -
-
- {tabLabels.map((tab) => { - return ( -
setActiveTab(tab)} - > - {tab} -
- ); - })} -
- {activeTab === 'Metrics' ? ( - <> - {kedroDatasetsCompatibilityMessage()} - - - ) : ( - <> - {kedroDatasetsCompatibilityMessage()} - - - - )} -
- - ); -}; - -export default Details; diff --git a/src/components/experiment-tracking/details/details.scss b/src/components/experiment-tracking/details/details.scss deleted file mode 100644 index c686455c01..0000000000 --- a/src/components/experiment-tracking/details/details.scss +++ /dev/null @@ -1,74 +0,0 @@ -@use '../../../styles/variables' as variables; - -.kui-theme--light { - --color-compatibility-message--bg: #{variables.$black-300}; - --color-compatibility-message: #{variables.$white-0}; -} - -.kui-theme--dark { - --color-compatibility-message--bg: #{variables.$black-400}; - --color-compatibility-message: #{variables.$white-500}; -} - -.details-mainframe { - background-color: var(--color-exp-tracking-bg); - bottom: 0; - display: flex; - flex-direction: column; - height: 100%; - justify-content: flex-start; - left: #{variables.$global-toolbar-width}; - overflow-y: scroll; - position: absolute; - top: 0; - transform: translateX(variables.$sidebar-width-closed); - transition: transform 0.4s ease, width ease 0.4s; - width: calc( - ( - 100% - #{variables.$sidebar-width-closed} - #{variables.$global-toolbar-width} - ) - ); - - @media (min-width: variables.$sidebar-width-breakpoint) { - &--sidebar-visible { - width: calc( - ( - 100% - #{variables.$sidebar-width-open} - #{variables.$global-toolbar-width} - ) - ); - transform: translateX(variables.$sidebar-width-open); - } - } -} - -.details__tabs { - background-color: var(--color-exp-tracking-bg); - display: flex; - left: 0; - position: sticky; -} - -.tabs__item { - background-color: var(--color-sidebar-background); - cursor: pointer; - font-size: 0.875rem; - padding: 15px 0 13px; - text-align: center; - width: 200px; - - &--active { - background-color: var(--color-exp-tracking-bg); - } -} - -.kedroDatasetsCompatible { - padding: 1em 0 0 2em; - - p { - background-color: var(--color-compatibility-message--bg); - color: var(--color-compatibility-message); - font-size: 14px; - padding: 5px 15px; - width: fit-content; - } -} diff --git a/src/components/experiment-tracking/details/index.js b/src/components/experiment-tracking/details/index.js deleted file mode 100644 index ecf2a5656c..0000000000 --- a/src/components/experiment-tracking/details/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import Details from './details'; - -export default Details; diff --git a/src/components/experiment-tracking/experiment-primary-toolbar/experiment-primary-toolbar.js b/src/components/experiment-tracking/experiment-primary-toolbar/experiment-primary-toolbar.js deleted file mode 100644 index 8d63fca4c8..0000000000 --- a/src/components/experiment-tracking/experiment-primary-toolbar/experiment-primary-toolbar.js +++ /dev/null @@ -1,122 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import IconButton from '../../ui/icon-button'; -import PencilIcon from '../../icons/pencil'; -import BookmarkIcon from '../../icons/bookmark'; -import ExportIcon from '../../icons/export'; -import BookmarkStrokeIcon from '../../icons/bookmark-stroke'; -import PrimaryToolbar from '../../primary-toolbar'; -import ShowChangesIcon from '../../icons/show-changes'; -import { toggleBookmark } from '../../../actions'; - -import { - SlideFromLeftToRight, - SlideFromRightToLeft, -} from './sliding-animation'; - -const duration = 300; - -export const ExperimentPrimaryToolbar = ({ - displaySidebar, - enableComparisonView, - enableShowChanges, - selectedRunData, - setEnableShowChanges, - setSidebarVisible, - showChangesIconDisabled, - showRunDetailsModal, - sidebarVisible, - setShowRunExportModal, - onToggleBookmark, - runsMetadata, -}) => { - const bookmark = runsMetadata[selectedRunData?.id]?.bookmark; - - const toggleBookmark = () => { - onToggleBookmark(!bookmark, selectedRunData?.id); - }; - - return ( - - - {enableComparisonView && ( - <> - setEnableShowChanges(!enableShowChanges)} - /> - setShowRunExportModal(true)} - /> - - )} - - - {!enableComparisonView && ( - <> - toggleBookmark()} - /> - showRunDetailsModal(true)} - /> - setShowRunExportModal(true)} - /> - - )} - - - ); -}; - -export const mapStateToProps = (state) => ({ - runsMetadata: state.runsMetadata, -}); - -export const mapDispatchToProps = (dispatch) => ({ - onToggleBookmark: (bookmark, runId) => { - dispatch(toggleBookmark(bookmark, runId)); - }, -}); - -export default connect( - mapStateToProps, - mapDispatchToProps -)(ExperimentPrimaryToolbar); diff --git a/src/components/experiment-tracking/experiment-primary-toolbar/index.js b/src/components/experiment-tracking/experiment-primary-toolbar/index.js deleted file mode 100644 index 23e1394038..0000000000 --- a/src/components/experiment-tracking/experiment-primary-toolbar/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import ExperimentPrimaryToolbar from './experiment-primary-toolbar'; - -export default ExperimentPrimaryToolbar; diff --git a/src/components/experiment-tracking/experiment-primary-toolbar/sliding-animation.js b/src/components/experiment-tracking/experiment-primary-toolbar/sliding-animation.js deleted file mode 100644 index a998b0611f..0000000000 --- a/src/components/experiment-tracking/experiment-primary-toolbar/sliding-animation.js +++ /dev/null @@ -1,92 +0,0 @@ -import React from 'react'; -import { Transition } from 'react-transition-group'; - -const directions = { - leftToRight: { - entering: { - transform: 'translateX(0)', - visibility: 'visible', - opacity: '1', - }, - entered: { - transform: 'translateX(0)', - visibility: 'visible', - opacity: '1', - }, - exiting: { - transform: 'translateX(-34%)', - visibility: 'hidden', - opacity: '0', - }, - exited: { - transform: 'translateX(-34%)', - visibility: 'hidden', - opacity: '0', - }, - }, - rightToLeft: { - entering: { - transform: 'translateX(0)', - visibility: 'visible', - opacity: '1', - }, - entered: { - transform: 'translateX(0)', - visibility: 'visible', - opacity: '1', - }, - exiting: { - transform: 'translateX(34%)', - visibility: 'hidden', - opacity: '0', - }, - exited: { - transform: 'translateX(34%)', - visibility: 'hidden', - opacity: '0', - }, - }, -}; - -export const Animation = ({ children, direction, duration, state }) => { - const defaultStyle = { - transition: `transform 0.3s ease-out, opacity 0.1s linear`, - }; - - return ( - - {(state) => ( -
- {children} -
- )} -
- ); -}; - -export const SlideFromLeftToRight = ({ state, duration, children }) => { - return ( - - ); -}; - -export const SlideFromRightToLeft = ({ state, duration, children }) => { - return ( - - ); -}; diff --git a/src/components/experiment-tracking/metrics-plots/index.js b/src/components/experiment-tracking/metrics-plots/index.js deleted file mode 100644 index 5bc6886748..0000000000 --- a/src/components/experiment-tracking/metrics-plots/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import MetricsPlots from './metrics-plots'; - -export default MetricsPlots; diff --git a/src/components/experiment-tracking/metrics-plots/metrics-plots.js b/src/components/experiment-tracking/metrics-plots/metrics-plots.js deleted file mode 100644 index 2ddf299993..0000000000 --- a/src/components/experiment-tracking/metrics-plots/metrics-plots.js +++ /dev/null @@ -1,197 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import classnames from 'classnames'; -import { TimeSeries } from '../time-series/time-series.js'; - -import { ParallelCoordinates } from '../parallel-coordinates/parallel-coordinates.js'; -import ExperimentWarning from '../../experiment-warning'; -import { GET_METRIC_PLOT_DATA } from '../../../apollo/queries'; -import { useApolloQuery } from '../../../apollo/utils'; -import SelectDropdown from '../select-dropdown'; -import { saveLocalStorage, loadLocalStorage } from '../../../store/helpers'; -import { metricLimit, localStorageMetricsSelect } from '../../../config'; -import { - removeChildFromObject, - removeElementsFromObjectValues, -} from '../../../utils/object-utils'; - -import './metrics-plots.scss'; - -const tabLabels = ['Time-series', 'Parallel coordinates']; - -const getSelectedDataFromDropdown = ( - runMetricsData, - localRunMetricsData, - selectedMetrics -) => { - const metricsKeys = - runMetricsData?.data && Object.keys(runMetricsData?.data.metrics); - const originalMetricsData = - runMetricsData?.data && runMetricsData?.data.metrics; - const originalRunsData = runMetricsData?.data && runMetricsData?.data.runs; - - const toBeRemoved = {}; - - metricsKeys.map((metric, index) => { - if (selectedMetrics.indexOf(metric) === -1) { - toBeRemoved[metric] = index; - } - return toBeRemoved; - }); - - const updatedMetrics = removeChildFromObject( - originalMetricsData, - Object.keys(toBeRemoved) - ); - const updatedRuns = removeElementsFromObjectValues( - originalRunsData, - Object.values(toBeRemoved) - ); - - return { - ...localRunMetricsData, - metrics: updatedMetrics, - runs: updatedRuns, - }; -}; - -const MetricsPlots = ({ selectedRunIds, sidebarVisible }) => { - const [activeTab, setActiveTab] = useState(tabLabels[0]); - const [chartHeight, setChartHeight] = useState(0); - const [parCoordsWidth, setParCoordsWidth] = useState(0); - const [timeSeriesWidth, setTimeSeriesWidth] = useState(0); - const [containerWidth, setContainerWidth] = useState('auto'); - const [localRunMetricsData, setLocalRunMetricsData] = useState({}); - const [selectedDropdownValues, setSelectedDropdownValues] = useState(0); - - const { data: { runMetricsData = [] } = [] } = useApolloQuery( - GET_METRIC_PLOT_DATA, - { - variables: { limit: metricLimit }, - } - ); - - const metrics = - runMetricsData?.data && Object.keys(runMetricsData?.data.metrics); - const numberOfMetrics = metrics ? metrics.length : 0; - - useEffect(() => { - if (runMetricsData?.data) { - const selectMetricsValues = loadLocalStorage(localStorageMetricsSelect); - // We want to check the localStorage everytime the component re-loads - // if value stored in localStorage - // we can update the localRunMetricsData with the selected values from localStorage - if (Object.keys(selectMetricsValues).length > 0) { - setSelectedDropdownValues(selectMetricsValues[0]); - - const updatedRunData = getSelectedDataFromDropdown( - runMetricsData, - localRunMetricsData, - selectMetricsValues[0] - ); - setLocalRunMetricsData(updatedRunData); - } - // If value doesn't exist in localStorage yet - // then we need to create it first - else { - const metricsKeys = Object.keys(runMetricsData.data.metrics); - - setSelectedDropdownValues(metricsKeys); - setLocalRunMetricsData(runMetricsData.data); - } - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [runMetricsData]); - - const onSelectedDropdownChanged = (selectedValues) => { - const updatedRunData = getSelectedDataFromDropdown( - runMetricsData, - localRunMetricsData, - selectedValues - ); - setLocalRunMetricsData(updatedRunData); - saveLocalStorage(localStorageMetricsSelect, [selectedValues]); - setSelectedDropdownValues(selectedValues); - }; - - useEffect(() => { - if (numberOfMetrics > 0) { - if (numberOfMetrics > 5 && activeTab === tabLabels[1]) { - setContainerWidth(numberOfMetrics * 200); - setParCoordsWidth(numberOfMetrics * 200); - } else { - setContainerWidth('auto'); - setParCoordsWidth( - document.querySelector('.metrics-plots-wrapper__charts').clientWidth - ); - } - } - }, [activeTab, numberOfMetrics]); - - useEffect(() => { - setTimeSeriesWidth( - document.querySelector('.metrics-plots-wrapper__charts').clientWidth - ); - setChartHeight( - document.querySelector('.metrics-plots-wrapper__charts').clientHeight - ); - }, []); - - return ( -
-
-
- {tabLabels.map((tab) => { - return ( -
setActiveTab(tab)} - > - {tab} -
- ); - })} -
- -
- -
- {selectedDropdownValues.length === 0 && ( - - )} - {Object.keys(localRunMetricsData).length > 0 ? ( - activeTab === tabLabels[0] ? ( - - ) : ( - - ) - ) : null} -
-
- ); -}; - -export default MetricsPlots; diff --git a/src/components/experiment-tracking/metrics-plots/metrics-plots.scss b/src/components/experiment-tracking/metrics-plots/metrics-plots.scss deleted file mode 100644 index 5cd6fbc995..0000000000 --- a/src/components/experiment-tracking/metrics-plots/metrics-plots.scss +++ /dev/null @@ -1,50 +0,0 @@ -@use '../../../styles/variables' as variables; - -.metrics-plots-wrapper { - height: 100%; - overflow-x: scroll; - overflow-y: hidden; - padding: 5em 0 0 9em; - width: 100%; -} - -.metrics-plots-wrapper__header { - display: flex; - justify-content: space-between; - - .dropdown { - margin-right: 30px; - } -} - -.metrics-plots-wrapper__charts-empty { - font-size: 13px; -} - -.chart-types-wrapper { - border-bottom: 1px solid rgb(255 255 255 / 10%); - display: flex; - width: 236px; - - &__tab { - cursor: pointer; - font-size: 1.4em; - padding-bottom: 0.7em; - - &:first-of-type { - margin-right: 16px; - } - } - - &__tab--active { - border-bottom: 2px solid var(--color-default-alt); - } -} - -.metrics-plots-wrapper__charts { - display: flex; - flex-flow: column; - height: 100%; - margin-top: 30px; - overflow: scroll; -} diff --git a/src/components/experiment-tracking/mock-data.js b/src/components/experiment-tracking/mock-data.js deleted file mode 100644 index 4c14a5db66..0000000000 --- a/src/components/experiment-tracking/mock-data.js +++ /dev/null @@ -1,31 +0,0 @@ -export const data = { - metrics: { - 'Dataset1.Metrics1': [1, 3, 4.5, 2.4, 3.3, 5.3, 1.3, 6.5, 3.4], - 'Dataset1.Metrics2': [2, 1.5, 5.1, 5.5, 1.5, 3.5, 5.5, 2.5, 4.5], - 'Dataset1.Metrics3': [3, 1.3, 6.6, 6.6, 5.6, 5.6, 2.6, 1.6, 4.6], - 'Dataset2.Metrics4': [4, 2.9, 7.7, 3.5, 2.4, 2.4, 3.4, 6.4, 1.4], - 'Dataset2.Metrics5': [5, 6, 1, 2.1, 1.6, 5.6, 4.6, 2.6, 6.6], - 'Dataset2.Metrics6': [4, 2.9, 7.7, 3.5, 2.4, 2.4, 3.4, 6.4, 1.4], - 'Dataset1.Metrics7': [1, 3, 4.5, 2.4, 3.3, 5.3, 1.3, 6.5, 3.4], - 'Dataset1.Metrics8': [3, 1.3, 6.6, 6.6, 5.6, 5.6, 2.6, 1.6, 4.6], - 'Dataset2.Metrics9': [5, 6, 1, 2.1, 1.6, 5.6, 4.6, 2.6, 6.6], - }, - runs: { - '2022-09-05T12.27.04.496Z': [1, 2, 3, 4, 5], - '2022-10-05T12.22.35.825Z': [3, 1.5, 1.3, 2.9, 6], - '2022-12-24T21.05.59.296Z': [4.5, 5.1, 6.6, 7.7, 1], - '2022-08-24T21.04.31.605Z': [2.4, 5.5, 6.6, 3.5, 2.1], - '2022-08-24T21.03.25.671Z': [3.3, 1.5, 5.6, 2.4, 1.6], - '2022-07-22T13.49.08.764Z': [5.3, 3.5, 5.6, 2.4, 5.6], - '2022-07-21T12.54.06.759Z': [1.3, 5.5, 2.6, 3.4, 4.6], - '2022-07-20T15.39.58.437Z': [6.5, 2.5, 1.6, 6.4, 2.6], - '2022-06-22T13.13.06.258Z': [3.4, 4.5, 4.6, 1.4, 6.6], - }, -}; - -export const oneSelectedRun = ['2022-09-05T12.27.04.496Z']; -export const selectedRuns = [ - '2022-09-05T12.27.04.496Z', - '2022-10-05T12.22.35.825Z', - '2022-12-24T21.05.59.296Z', -]; diff --git a/src/components/experiment-tracking/parallel-coordinates/parallel-coordinates.js b/src/components/experiment-tracking/parallel-coordinates/parallel-coordinates.js deleted file mode 100644 index b03a99d0db..0000000000 --- a/src/components/experiment-tracking/parallel-coordinates/parallel-coordinates.js +++ /dev/null @@ -1,389 +0,0 @@ -import React, { useContext, useState, useEffect, useMemo } from 'react'; -import classnames from 'classnames'; -import * as d3 from 'd3'; -import { HoverStateContext } from '../utils/hover-state-context'; -import { v4 as uuidv4 } from 'uuid'; -import { - ExperimentTrackingTooltip, - tooltipDefaultProps, -} from '../tooltip/tooltip'; -import { getTooltipPosition } from '../tooltip/get-tooltip-position'; -import { formatTimestamp } from '../../../utils/date-utils'; - -import './parallel-coordinates.scss'; - -export const getUniqueValues = (values) => { - return values - .filter((value, i, self) => self.indexOf(value) === i) - .filter((value) => value !== null) - .sort((a, b) => a - b); -}; - -const paddingTopBottom = 38; -const paddingLeftRight = 80; -const axisGapBuffer = 3; -const selectedMarkerRotate = [45, 0, 0]; - -const yAxis = {}; -const yScales = {}; - -export const ParallelCoordinates = ({ - chartHeight, - chartWidth, - metricsData, - selectedRuns, - sidebarVisible, -}) => { - const [hoveredMetricLabel, setHoveredMetricLabel] = useState(null); - const [showTooltip, setShowTooltip] = useState(tooltipDefaultProps); - - const { hoveredElementId, setHoveredElementId } = - useContext(HoverStateContext); - - const selectedMarkerShape = [ - d3.symbolSquare, - d3.symbolCircle, - d3.symbolTriangle, - ]; - - const graph = Object.entries(metricsData.metrics); - const graphKeys = useMemo( - () => Object.keys(metricsData.metrics), - [metricsData.metrics] - ); - - const data = Object.entries(metricsData.runs); - const selectedData = data - .filter(([key]) => selectedRuns.includes(key)) - .sort((a, b) => { - // We need to sort the selected data to match the order of selectedRuns. - // If we didn't, the highlighted runs would switch colors unnecessarily. - return selectedRuns.indexOf(a[0]) - selectedRuns.indexOf(b[0]); - }); - - const hoveredValues = hoveredElementId && metricsData.runs[hoveredElementId]; - - const xScale = d3 - .scalePoint() - .domain(graphKeys) - .range([paddingLeftRight, chartWidth - paddingLeftRight]); - - // For each metric, draw a y-scale - graph.forEach(([key, value]) => { - yScales[key] = d3 - .scaleLinear() - .domain([d3.min(value), d3.max(value)]) - .range([ - chartHeight - paddingTopBottom * 2.15, - paddingTopBottom + paddingTopBottom / axisGapBuffer, - ]); - }); - - Object.entries(yScales).forEach(([key, value]) => { - yAxis[key] = d3.axisLeft(value).ticks(0).tickSizeOuter(0); - }); - - const lineGenerator = d3.line().defined(function (d) { - return d !== null; - }); - - const linePath = function (d) { - const points = d.map((x, i) => { - if (x !== null) { - return [xScale(graphKeys[i]), yScales[graphKeys[i]](x)]; - } else { - return null; - } - }); - - return lineGenerator(points); - }; - - const handleMouseOverMetric = (e, key) => { - const runsCount = graph.find((each) => each[0] === key)[1].length; - const { x, y, direction } = getTooltipPosition(e, sidebarVisible); - - setHoveredMetricLabel(key); - - setShowTooltip({ - content: { - label1: 'Metric name', - value1: key, - label2: 'Run count', - value2: runsCount, - }, - direction, - position: { x, y }, - visible: true, - }); - }; - - const handleMouseOutMetric = () => { - setHoveredMetricLabel(null); - setShowTooltip(tooltipDefaultProps); - }; - - const handleMouseOverLine = (e, key) => { - setHoveredElementId(key); - - if (e) { - const parsedDate = new Date(formatTimestamp(key)); - const { x, y, direction } = getTooltipPosition(e, sidebarVisible); - - setShowTooltip({ - content: { - label1: 'Run name', - value1: key, - label2: 'Date', - value2: parsedDate.toLocaleDateString('default', { - day: 'numeric', - month: 'long', - year: 'numeric', - }), - }, - direction, - position: { x, y }, - visible: true, - }); - } - }; - - const handleMouseOutLine = () => { - setHoveredElementId(null); - setShowTooltip(tooltipDefaultProps); - }; - - useEffect(() => { - d3.select(`.run-line[id="${hoveredElementId}"]`).raise(); - }, [hoveredElementId]); - - useEffect(() => { - d3.select(`.metric-axis[id="${hoveredMetricLabel}"]`).raise(); - d3.selectAll(`.selected-runs`).raise(); - d3.selectAll(`.selected-runs > path`).raise(); - }, [hoveredMetricLabel]); - - return ( -
- - - - {graphKeys.map((metricName) => { - const getYAxis = (ref) => { - d3.select(ref).call(yAxis[metricName]).attr('id', metricName); - }; - - return ( - - handleMouseOverMetric(e, metricName)} - textAnchor="middle" - y={paddingTopBottom / 2} - > - {metricName.length > 20 - ? '...' + metricName.slice(-20) - : metricName} - - - ); - })} - - - {data.map(([runId, value], i) => { - return ( - handleMouseOverLine(e, runId)} - /> - ); - })} - - - {graph.map(([metricName, values], metricIndex) => { - // To avoid rendering a tick more than once - const uniqueValues = getUniqueValues(values); - - return ( - - {uniqueValues.map((value) => { - // To ensure the hoveredValues are highlighted once per axis - const highlightedValue = - hoveredValues && - hoveredValues.find( - (value, index) => index === metricIndex && value - ); - - const xScaleTickValue = isNaN(xScale(metricName)) - ? 0 - : xScale(metricName); - - const yScaleTickValue = isNaN(yScales[metricName](value)) - ? 0 - : yScales[metricName](value); - - return ( - - {value?.toFixed(3)} - - ); - })} - - ); - })} - - {graph.map(([metricName, values], metricIndex) => { - const sortedValues = getUniqueValues(values); - - return ( - - {sortedValues.map((value) => { - // To ensure the hoveredValues are highlighted once per axis - const highlightedValue = - hoveredValues && - hoveredValues.find( - (value, index) => index === metricIndex && value - ); - - const xScaleMetricName = isNaN(xScale(metricName)) - ? 0 - : xScale(metricName); - - const yScaleMetricName = isNaN(yScales[metricName](value)) - ? 0 - : yScales[metricName](value); - - if (value) { - return ( - - ); - } else { - return null; - } - })} - - ); - })} - - - {selectedData.map(([id, value], i) => ( - - ))} - - {selectedData.map(([, values], i) => - values.map((value, index) => { - const transformX = xScale(graphKeys[index]); - const transformY = yScales[graphKeys[index]](value); - const rotate = selectedMarkerRotate[i]; - const xScaleGraphKey = isNaN(xScale(graphKeys[index])) - ? 0 - : xScale(graphKeys[index]); - - const yScaleGraphKey = isNaN(yScales[graphKeys[index]](value)) - ? 0 - : yScales[graphKeys[index]](value); - - return ( - - - - {value?.toFixed(3)} - - - ); - }) - )} - - -
- ); -}; diff --git a/src/components/experiment-tracking/parallel-coordinates/parallel-coordinates.scss b/src/components/experiment-tracking/parallel-coordinates/parallel-coordinates.scss deleted file mode 100644 index f5b4611c86..0000000000 --- a/src/components/experiment-tracking/parallel-coordinates/parallel-coordinates.scss +++ /dev/null @@ -1,121 +0,0 @@ -@use '../../../styles/variables' as colors; - -.parallel-coordinates { - flex: 1 1 auto; - font-family: sans-serif; - margin: 0 4em 0 0; -} - -.parallel-coordinates .text { - font-size: 12px; - font-weight: 400; -} - -.run-line { - cursor: pointer; - stroke: var(--color-metrics-plot-parallel-coords-line); - - &--hovered { - stroke: var(--color-metrics-plot-parallel-coords-line-hover); - } - - &--selected-first { - stroke: colors.$purple-300; - } - - &--selected-second { - stroke: colors.$yellow-300; - } - - &--selected-third { - stroke: colors.$green-300; - } -} - -.marker-path { - &--selected-0 { - stroke: colors.$purple-300; - } - - &--selected-1 { - stroke: colors.$yellow-300; - } - - &--selected-2 { - stroke: colors.$green-300; - } -} - -g.run-lines path { - fill: none; - stroke-linecap: 'round'; -} - -g.highlight path { - fill: none; -} - -g.selected-runs path { - fill: none; -} - -.headers { - fill: var(--color-metrics-plot-text-bold); - font-size: 14px; - font-weight: 400; -} - -// y-Axis -.domain { - stroke: var(--color-metrics-plot-text); -} - -// Start/end tick-values -.tick-values > .text:first-of-type, -.tick-values > .text:last-of-type { - fill: var(--color-metrics-plot-axis-ends); -} - -.tick-values .text { - fill: var(--color-metrics-plot-text); - font-size: 12px; -} - -.tick-lines .line { - stroke: var(--color-metrics-plot-text); - - &--hovered { - stroke: colors.$grey-400; - } -} - -// Selected runs -.selected-runs .text { - fill: var(--color-metrics-plot-text-bold); - font-weight: 600; -} - -// Hovered Y-axis -.metric-axis--hovered { - .domain { - stroke: colors.$grey-400; - stroke-width: 1px; - } - - .headers { - cursor: pointer; - fill: var(--color-metrics-plot-text-bold); - } -} - -// Hovered run -.tick-values .text--hovered { - fill: var(--color-metrics-plot-parallel-coords-axis-hover) !important; -} - -.metric-axis--faded, -.run-line--faded, -.text--faded, -.line--faded { - opacity: 0.55; -} diff --git a/src/components/experiment-tracking/parallel-coordinates/parallel-coordinates.test.js b/src/components/experiment-tracking/parallel-coordinates/parallel-coordinates.test.js deleted file mode 100644 index 86aee880b9..0000000000 --- a/src/components/experiment-tracking/parallel-coordinates/parallel-coordinates.test.js +++ /dev/null @@ -1,261 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; - -import { HoverStateContext } from '../utils/hover-state-context'; -import { ParallelCoordinates, getUniqueValues } from './parallel-coordinates'; -import { data, oneSelectedRun, selectedRuns } from '../mock-data'; -import { metricLimit } from '../../../config'; - -const hoveredRunIndex = 4; -const hoverMetricIndex = 1; - -const mockDefaultContextValue = { - hoveredElementId: null, - setHoveredElementId: jest.fn(), -}; - -const mockHoveredContextValue = { - hoveredElementId: Object.keys(data.runs)[hoveredRunIndex], - setHoveredElementId: jest.fn(), -}; - -describe('Parallel Coordinates renders correctly with D3', () => { - let wrapper; - - beforeEach(() => { - wrapper = mount( - - - - ); - }); - - it('renders without crashing', () => { - const svg = wrapper.find('div').find('svg'); - - expect(svg.length).toEqual(1); - }); - - it('render the correct number of metric-axis from the data', () => { - const metricAxises = wrapper.find('div').find('svg').find('.metric-axis'); - - const graphKeys = Object.keys(data.metrics); - - expect(metricAxises.length).toEqual(graphKeys.length); - }); - - it('run-lines should be limited to less than metricLimit, even if its more than 10 from the data', () => { - const runLine = wrapper.find('.run-line'); - - expect(runLine.length).toBeLessThan(metricLimit); - }); - - it('text from the tick-values should be displayed in ascending order', () => { - const tickValues = wrapper.find('div').find('svg').find('.tick-values'); - - const text = tickValues.map((value) => value.text()); - // Since the text is in the format of ['1.0001.3002.4003.0003.3003.4004.5005.3006.500'] - // we need to remove the extra '00' in the middle - const textValues = text.map((each) => each.split('00')); - - // Then ensure all are number, and the last character 00 should also be removed - const formattedTextValues = textValues.map((array) => { - array.splice(-1); - return array.map((each) => Number(each)); - }); - - const graphData = Object.entries(data.metrics); - - graphData.forEach(([metricName, values], metricIndex) => { - const uniqueValues = getUniqueValues(values); - - formattedTextValues.forEach((text, index) => { - if (index === metricIndex) { - expect(text).toEqual(uniqueValues); - } - }); - }); - }); -}); - -describe('Parallel Coordinates" interactions', () => { - let wrapper; - - beforeEach(() => { - wrapper = mount( - - - - ); - }); - - it('shows tooltip when hovering over a run line', () => { - wrapper - .find('div') - .find('svg') - .find('.run-line') - .at(hoveredRunIndex) - .simulate('mouseover'); - - const tooltip = wrapper.find('div').find('.tooltip'); - - expect(tooltip.hasClass('tooltip--show')).toBe(true); - }); - - it('tick-values are only highlighted once per axis when hovering over a run line', () => { - const highLightedValues = wrapper - .find('div') - .find('svg') - .find('.tick-values') - .find('.text--hovered'); - - const highlightedText = highLightedValues.map((value) => value.text()); - const graphData = Object.entries(data.metrics); - - highlightedText.forEach((text, index) => { - graphData.forEach(([metricName, values], metricIndex) => { - if (index === metricIndex) { - // each values from metrics should include a highlightedText - expect(values.includes(Number(text))).toBe(true); - } - }); - }); - }); - - it('applies "run-line--hovered" to the run line when hovering over', () => { - const runLine = wrapper - .find('div') - .find('svg') - .find('.run-line') - .at(hoveredRunIndex); - - expect(runLine.hasClass('run-line--hovered')).toBe(true); - }); - - it('applies "run-line--faded" to all the run lines that are not included in the hovered modes', () => { - const runLines = wrapper.find('div').find('svg').find('.run-line'); - - runLines.forEach((run, index) => { - expect(run.hasClass('run-line--faded')).toEqual( - index !== hoveredRunIndex - ); - }); - }); - - it('applies "text--hovered" to the tick values when hovering over', () => { - const textValues = wrapper - .find('div') - .find('svg') - .find('.tick-values') - .find('.text') - .at(hoveredRunIndex); - - expect(textValues.hasClass('text--hovered')).toBe(true); - }); - - it('applies "text--faded" to all the tick values that are not included in the hovered modes', () => {}); - - it('applies "line--hovered" to the tick lines when hovering over', () => { - const textValues = wrapper - .find('div') - .find('svg') - .find('.tick-lines') - .find('.line') - .at(hoveredRunIndex); - - expect(textValues.hasClass('line--hovered')).toBe(true); - }); - - it('applies "line--faded" to all the tick lines that are not included in the hovered modes', () => {}); - - it('applies "metric-axis--hovered" to the metric-axis when hovering over', () => { - wrapper - .find('div') - .find('svg') - .find('.metric-axis') - .find('text') - .at(hoverMetricIndex) - .simulate('mouseover'); - - const metricAxis = wrapper - .find('div') - .find('svg') - .find('.metric-axis') - .at(hoverMetricIndex); - - expect(metricAxis.hasClass('metric-axis--hovered')).toBe(true); - }); - - it('applies "metric-axis--faded" to all the metric-axis that are not included in the hovered modes', () => { - wrapper - .find('div') - .find('svg') - .find('.metric-axis') - .find('text') - .at(hoverMetricIndex) - .simulate('mouseover'); - - const otherMetricsAxis = wrapper - .find('div') - .find('svg') - .find('.metric-axis'); - - otherMetricsAxis.forEach((metric, index) => { - expect(metric.hasClass('metric-axis--faded')).toEqual( - index !== hoverMetricIndex - ); - }); - }); - - it('in single run, applies "run-line--selected-first" class to "line" when selecting a new run', () => { - const runKeys = Object.keys(data.runs); - - const oneSelectedRunWrapper = mount( - - - - ) - .find('div') - .find('svg') - .find('.selected-runs') - .find('path') - .at(runKeys.indexOf(oneSelectedRun[0])); - - expect(oneSelectedRunWrapper.length).toEqual(1); - expect(oneSelectedRunWrapper.hasClass('run-line--selected-first')).toBe( - true - ); - }); - - it('in comparison mode, applies classnames accordingly to "line"', () => { - const runKeys = Object.keys(data.runs); - - const selectedRunsWrapper = mount( - - - - ) - .find('div') - .find('svg') - .find('.selected-runs') - .find('path'); - - expect( - selectedRunsWrapper - .at(runKeys.indexOf(selectedRuns[0])) - .hasClass('run-line--selected-first') - ).toBe(true); - - expect( - selectedRunsWrapper - .at(runKeys.indexOf(selectedRuns[1])) - .hasClass('run-line--selected-second') - ).toBe(true); - - expect( - selectedRunsWrapper - .at(runKeys.indexOf(selectedRuns[2])) - .hasClass('run-line--selected-third') - ).toBe(true); - }); -}); diff --git a/src/components/experiment-tracking/run-dataset/index.js b/src/components/experiment-tracking/run-dataset/index.js deleted file mode 100644 index 748155f66a..0000000000 --- a/src/components/experiment-tracking/run-dataset/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import RunDataset from './run-dataset'; - -export default RunDataset; diff --git a/src/components/experiment-tracking/run-dataset/run-dataset-loader.js b/src/components/experiment-tracking/run-dataset/run-dataset-loader.js deleted file mode 100644 index bd0cd4d237..0000000000 --- a/src/components/experiment-tracking/run-dataset/run-dataset-loader.js +++ /dev/null @@ -1,89 +0,0 @@ -import React from 'react'; -import ContentLoader from 'react-content-loader'; -import { - experimentTrackingLazyLoadingColours, - experimentTrackingLazyLoadingGap, -} from '../../../config'; - -import './run-dataset.scss'; - -const GAP = experimentTrackingLazyLoadingGap; - -const SubCatLoader = ({ y }) => ( - <> - - - -); - -const TitleLoader = ({ y }) => ( - <> - - - - - -); - -const DetailsLoader = ({ x, y }) => { - return ( - <> - - - - - ); -}; - -export const SingleRunDatasetLoader = ({ theme }) => ( -
- - - - - - - - - - - - -
-); - -export const DatasetLoader = ({ x, y, length, theme }) => { - return ( - - - - ); -}; diff --git a/src/components/experiment-tracking/run-dataset/run-dataset.js b/src/components/experiment-tracking/run-dataset/run-dataset.js deleted file mode 100644 index 2e9cbbd9b7..0000000000 --- a/src/components/experiment-tracking/run-dataset/run-dataset.js +++ /dev/null @@ -1,426 +0,0 @@ -import React, { useMemo } from 'react'; -import classnames from 'classnames'; -import Accordion from '../accordion'; -import PinArrowIcon from '../../icons/pin-arrow'; -import PlotlyChart from '../../plotly-chart'; -import { sanitizeValue } from '../../../utils/experiment-tracking-utils'; -import { TransitionGroup, CSSTransition } from 'react-transition-group'; -import { DatasetLoader } from './run-dataset-loader'; -import JSONObject from '../../json-object'; - -import getShortType from '../../../utils/short-type'; -import './run-dataset.scss'; -import '../run-metadata/animation.scss'; - -const determinePinIcon = (data, pinValue, pinnedRun) => { - if (data.runId !== pinnedRun && typeof data.value === 'number') { - if (data.value > pinValue) { - return 'upArrow'; - } - if (data.value < pinValue) { - return 'downArrow'; - } - } - return null; -}; - -const determinePinDelta = (data, pinValue, pinnedRun) => { - if ( - data.runId !== pinnedRun && - typeof data.value === 'number' && - data.value !== pinValue - ) { - const delta = data.value - pinValue; - const deltaPercentage = Math.round((delta / Math.abs(pinValue)) * 100); - - return delta.toFixed(1) + ' (' + deltaPercentage + '%)'; - } - - return null; -}; - -const resolveRunDataWithPin = (runData, pinnedRun) => { - const pinValue = runData.filter((data) => data.runId === pinnedRun)[0]?.value; - - if (typeof pinValue === 'number') { - return runData.map((data) => ({ - pinIcon: determinePinIcon(data, pinValue, pinnedRun), - pinDelta: determinePinDelta(data, pinValue, pinnedRun), - ...data, - })); - } - - return runData; -}; - -/** - * Display the dataset of the experiment tracking run. - * @param {String} props.activeTab The selected tab (Overview || Plots). - * @param {Boolean} enableComparisonView Whether or not the enableComparisonView is on. - * @param {Boolean} props.enableShowChanges Are changes enabled or not. - * @param {Boolean} props.isSingleRun Indication to display a single run. - * @param {String} props.pinnedRun ID of the pinned run. - * @param {Boolean} props.showLoader Whether to show the loading component. - * @param {Object} props.trackingData The experiment tracking run data. - * @param {String} props.theme The currently-selected light or dark theme. - */ -const RunDataset = ({ - activeTab, - enableComparisonView, - enableShowChanges, - isSingleRun, - pinnedRun, - selectedRunIds, - setRunDatasetToShow, - setShowRunPlotsModal, - showLoader, - trackingData, - theme, -}) => { - const clonedTrackingData = useMemo( - () => structuredClone(trackingData), - [trackingData] - ); - - if (!clonedTrackingData) { - return null; - } - - return ( -
- {Object.keys(clonedTrackingData) - .filter((group) => { - if (activeTab === 'Plots' && group === activeTab) { - return true; - } - - if (activeTab !== 'Plots' && group !== 'Plots') { - return true; - } - - return false; - }) - .map((group) => { - return ( - - {clonedTrackingData[group].length === 0 && ( -
- - No data to display. Try selecting a different run. - - - {selectedRunIds.map((id, index) => { - return ( - - - No data to display. Try selecting a different run. - - - ); - })} - -
- )} - {clonedTrackingData[group].map((dataset) => { - const { data, datasetType, datasetName, runIds } = dataset; - - return ( - - {Object.keys(data) - .sort((a, b) => { - return a.localeCompare(b); - }) - .map((key, rowIndex) => { - const updatedDatasetValues = fillEmptyMetrics( - dataset.data[key], - runIds - ); - const runDataWithPin = resolveRunDataWithPin( - updatedDatasetValues, - pinnedRun - ); - - return buildDatasetDataMarkup( - key, - runDataWithPin, - datasetType, - rowIndex, - isSingleRun, - enableComparisonView, - enableShowChanges, - setRunDatasetToShow, - setShowRunPlotsModal, - showLoader, - theme - ); - })} - - ); - })} -
- ); - })} -
- ); -}; - -/** - * Build the necessary markup used to display the run dataset. - * @param {String} datasetKey The row label of the data. - * @param {Array} datasetValues A single dataset array from a run. - * @param {Number} rowIndex The array index of the dataset data. - * @param {Boolean} isSingleRun Whether or not this is a single run. - * @param {Boolean} enableShowChanges Are changes enabled or not. - * @param {Boolean} enableComparisonView Whether or not the enableComparisonView is on. - * @param {Function} setRunDatasetToShow Callback function to show runDataset. - * @param {Function} setShowRunPlotsModal Callback function to show RunPlot modal. - */ -function buildDatasetDataMarkup( - datasetKey, - datasetValues, - datasetType, - rowIndex, - isSingleRun, - enableComparisonView, - enableShowChanges, - setRunDatasetToShow, - setShowRunPlotsModal, - showLoader, - theme -) { - const isPlotlyDataset = getShortType(datasetType) === 'plotly'; - const isImageDataset = getShortType(datasetType) === 'image'; - const isJSONTrackingDataset = getShortType(datasetType) === 'JSONTracking'; - const isMetricsTrackingDataset = - getShortType(datasetType) === 'metricsTracking'; - const isTrackingDataset = isJSONTrackingDataset || isMetricsTrackingDataset; - - const onExpandVizClick = () => { - setShowRunPlotsModal(true); - setRunDatasetToShow({ datasetKey, datasetType, datasetValues }); - }; - - return ( - - {rowIndex === 0 ? ( -
- Name - - {datasetValues.map((data, index) => ( - - - Value - - - ))} - - {showLoader && ( - - )} -
- ) : null} -
- {datasetKey} - - {datasetValues.map((run, index) => { - const isSinglePinnedRun = datasetValues.length === 1; - const isJSONObject = run.value && typeof run.value === 'object'; - - return ( - - - {isTrackingDataset && !isJSONObject && ( - <> - {sanitizeValue(run.value)} - {enableShowChanges && } - {enableShowChanges && ( - - {run.pinDelta} - - )} - - )} - {isJSONTrackingDataset && isJSONObject && ( - - )} - - {isPlotlyDataset && - (run.value ? ( -
- -
- ) : ( - fillEmptyPlots() - ))} - - {isImageDataset && - (run.value ? ( -
- Matplotlib rendering -
- ) : ( - fillEmptyPlots() - ))} -
-
- ); - })} -
- {showLoader && ( - - )} -
-
- ); -} - -/** - * Fill in missing run metrics if they don't match the number of runIds. - * @param {Array} datasetValues Array of objects for a metric, e.g. r2_score. - * @param {Array} runIds Array of strings of runIds. - * @returns Array of objects, the length of which matches the length - * of the runIds. - */ -function fillEmptyMetrics(datasetValues, runIds) { - if (datasetValues.length === runIds.length) { - return datasetValues; - } - - const metrics = []; - - runIds.forEach((id) => { - const foundIdIndex = datasetValues.findIndex((item) => { - return item.runId === id; - }); - - // We didn't find a metric with this runId, so add a placeholder. - if (foundIdIndex === -1) { - metrics.push({ runId: id, value: null }); - } else { - metrics.push(datasetValues[foundIdIndex]); - } - }); - - return metrics; -} - -function fillEmptyPlots() { - return
No plot available
; -} - -export default RunDataset; diff --git a/src/components/experiment-tracking/run-dataset/run-dataset.scss b/src/components/experiment-tracking/run-dataset/run-dataset.scss deleted file mode 100644 index 7715cae6f0..0000000000 --- a/src/components/experiment-tracking/run-dataset/run-dataset.scss +++ /dev/null @@ -1,146 +0,0 @@ -@use '../../../styles/variables' as variables; - -.details-dataset { - background-color: var(--color-exp-tracking-datasets); - display: flex; - flex-direction: column; - flex-shrink: 0; - min-width: 100%; - padding: 5em 0 0 9em; - width: max-content; - - &--not-overview { - background-color: var(--color-exp-tracking-bg); - padding: 0.5em 0 0 9em; - } -} - -.details-metadata__title-detail--plots { - padding: 1px 0 1rem; -} - -.details-dataset__accordion { - margin-bottom: 36px; - width: 100%; -} - -.details-dataset__accordion-header { - margin-bottom: 16px; - - &--hidden { - display: none; - } -} - -.details-dataset__row { - display: flex; - font-size: 1.4em; -} - -.details-dataset__name-header, -.details-dataset__value-header { - color: var(--color-text-faded); - font-size: 13px; -} - -.details-dataset__label, -.details-dataset__value, -.details-dataset__value-header { - margin-bottom: 8px; -} - -.details-dataset__label, -.details-dataset__name-header { - display: block; - flex-shrink: 0; - width: variables.$run-width; -} - -.details-dataset__value, -.details-dataset__value-header { - display: flex; - flex-shrink: 0; - min-height: 20px; - width: variables.$run-width; - word-break: break-all; -} - -.details-dataset__accordion-wrapper-comparison-view { - .details-dataset__label, - .details-dataset__name-header, - .details-dataset__value, - .details-dataset__value-header { - width: variables.$run-width-comparison-view; - } -} - -.dataset-arrow-icon { - fill: variables.$blue-300; - height: 1.7em; - margin-left: 1em; - width: 1.7em; -} - -.details-dataset__visualization-wrapper, -.details-dataset__image-container { - cursor: pointer; - opacity: 1; - transition: 0.2s opacity ease; - - &:hover { - opacity: 0.85; - } -} - -.details-dataset__image-container { - height: auto; -} - -.details-dataset__image { - max-width: 250px; - width: 100%; -} - -.details-dataset__empty-plot { - align-items: center; - background-color: var(--color-bg-1); - border: 1px solid var(--color-bg-5); - display: flex; - height: 188px; - justify-content: center; - width: 250px; -} - -.details-dataset__transition-group-wrapper { - display: flex; -} - -.details-dataset__transition-group-wrapper .details-dataset__value { - &:first-of-type { - margin-right: 3.5em; - } - - &:nth-of-type(2) { - margin-right: 8.5em; - } -} - -// to ensure the value header is aligned with its value -.details-dataset__transition-group-wrapper .details-dataset__value-header { - &:nth-of-type(1) { - margin-right: 3.8em; - } - - &:nth-of-type(2) { - margin-right: 9.2em; - } -} - -.details-dataset__deltaValue { - color: variables.$blue-300; - margin-left: 0.5em; -} - -.details-dataset__value--comparison-view { - min-height: 1.7em; -} diff --git a/src/components/experiment-tracking/run-dataset/run-dataset.test.js b/src/components/experiment-tracking/run-dataset/run-dataset.test.js deleted file mode 100644 index 54e56d5850..0000000000 --- a/src/components/experiment-tracking/run-dataset/run-dataset.test.js +++ /dev/null @@ -1,294 +0,0 @@ -import React from 'react'; -import RunDataset from '.'; -import { runs, trackingData } from '../../experiment-wrapper/mock-data'; -import JSONObject from '../../json-object'; -import { shallow, mount } from 'enzyme'; -import 'core-js/stable/structured-clone'; - -const booleanTrackingData = { - JSONData: [ - { - datasetName: 'train_evaluation.hyperparams_linear_regression', - datasetType: 'tracking.json_dataset.JSONDataset', - data: { - classWeight: [{ runId: 'My Favorite Sprint', value: false }], - }, - runIds: ['My Favorite Sprint'], - }, - ], -}; - -const objectTrackingData = { - JSONData: [ - { - datasetName: 'train_evaluation.hyperparams_linear_regression', - datasetType: 'tracking.json_dataset.JSONDataset', - data: { - classWeight: [{ runId: 'My Favorite Sprint', value: { a: true } }], - }, - runIds: ['My Favorite Sprint'], - }, - ], -}; - -const comparisonTrackingData = { - metrics: [ - { - datasetName: 'train_evaluation.r2_score_linear_regression', - datasetType: 'tracking.metrics_dataset.MetricsDataset', - data: { - classWeight: [ - { runId: 'My Favorite Sprint', value: 12 }, - { runId: 'My second Favorite Sprint', value: 13 }, - ], - }, - runIds: ['My Favorite Sprint', 'My second Favorite Sprint'], - }, - ], -}; - -const jsonTrackingData = { - json: [ - { - datasetName: 'train_evaluation.r2_score_linear_regression', - datasetType: 'tracking.json_dataset.JSONDataset', - data: { - classWeight: [ - { - runId: 'My Favorite Sprint', - value: { - precision: 1, - accuracy: { - acc1: 1, - acc2: 2, - }, - }, - }, - { - runId: 'My second Favorite Sprint', - value: { - precision: 4.5, - accuracy: { - acc1: 3.1, - acc2: 2.5, - }, - }, - }, - ], - }, - runIds: ['My Favorite Sprint', 'My second Favorite Sprint'], - }, - ], -}; - -const showDiffTrackingData = { - metrics: [ - { - datasetName: 'train_evaluation.r2_score_linear_regression', - datasetType: 'tracking.metrics_dataset.MetricsDataset', - data: { - classWeight: [ - { runId: 'My Favorite Sprint', value: 12 }, - { runId: 'My second Favorite Sprint', value: 13 }, - ], - r2Score: [{ runId: 'My second Favorite Sprint', value: 0.2342356 }], - }, - runIds: ['My Favorite Sprint', 'My second Favorite Sprint'], - }, - ], -}; - -const matplotlibTrackingData = { - metrics: [ - { - datasetName: 'matplotlib', - datasetType: 'matplotlib.matplotlib_writer.MatplotlibWriter', - data: { - 'matplot_lib_single_plot.png': [ - { - runId: 'My Favorite Sprint', - value: 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', - }, - ], - }, - runIds: ['My Favorite Sprint'], - }, - ], -}; - -const emptyMatplotlibTrackingData = { - metrics: [ - { - datasetName: 'matplotlib', - datasetType: 'matplotlib.matplotlib_writer.MatplotlibWriter', - data: { - 'matplot_lib_single_plot.png': [ - { - runId: 'My Favorite Sprint', - value: null, - }, - ], - }, - runIds: ['My Favorite Sprint'], - }, - ], -}; - -const plotlyTrackingData = { - metrics: [ - { - datasetName: 'plotly', - datasetType: 'plotly.plotly_dataset.PlotlyDataset', - data: { - plotlyVisualization: [ - { - runId: 'My Favorite Sprint', - value: { - data: [], - layout: {}, - }, - }, - ], - }, - runIds: ['My Favorite Sprint'], - }, - ], -}; - -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useLocation: () => ({ - pathname: 'localhost:3000/', - }), -})); - -describe('RunDataset', () => { - it('renders without crashing', () => { - const wrapper = shallow( - - ); - - expect(wrapper.find('.details-dataset').length).toBe(1); - expect(wrapper.find('.details-dataset__accordion-wrapper').length).toBe(1); - }); - - it('contains "comparison-view" classname when the comparison view is enabled', () => { - const wrapper = shallow( - - ); - - expect( - wrapper.find('.details-dataset__accordion-wrapper-comparison-view').length - ).toBe(1); - }); - - it('renders a boolean value as a string', () => { - const wrapper = mount(); - - expect(wrapper.find('.details-dataset__value').text()).toBe('false'); - }); - - it('renders a boolean value as a string', () => { - const wrapper = mount(); - - const datasetValue = wrapper.find('.details-dataset__value').text(); - - expect(typeof datasetValue).toBe('string'); - }); - - it('renders the comparison arrow when showChanges is on', () => { - const wrapper = mount( - - ); - - expect(wrapper.find('.dataset-arrow-icon').length).toBe(1); - }); - - it('renders the comparison delta value when showChanges is on', () => { - const wrapper = mount( - - ); - - expect(wrapper.find('.details-dataset__deltaValue').at(1).text()).toBe( - '1.0 (8%)' - ); - }); - - it('renders a cell with a - value for runs with different metrics', () => { - const wrapper = mount( - - ); - - expect(wrapper.find('.details-dataset__value').at(2).text()).toBe('-'); - }); - - it('renders a matplotlib image and container', () => { - const wrapper = mount( - - ); - - expect(wrapper.find('.details-dataset__image-container').length).toBe(1); - expect(wrapper.find('.details-dataset__image').length).toBe(1); - }); - - it('renders a empty plot placeholder', () => { - const wrapper = mount( - - ); - - expect(wrapper.find('.details-dataset__value').length).toBe(1); - expect(wrapper.find('.details-dataset__empty-plot').length).toBe(1); - }); - - it('renders a plotly chart container', () => { - const wrapper = shallow( - - ); - - expect(wrapper.find('.details-dataset__visualization-wrapper').length).toBe( - 1 - ); - }); - - it('renders a react-json-view component when the run value is a nested json', () => { - const wrapper = shallow( - - ); - - expect(wrapper.containsMatchingElement()).toEqual(true); - }); -}); diff --git a/src/components/experiment-tracking/run-details-modal/index.js b/src/components/experiment-tracking/run-details-modal/index.js deleted file mode 100644 index 52494d3e74..0000000000 --- a/src/components/experiment-tracking/run-details-modal/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import RunDetailsModal from './run-details-modal'; - -export default RunDetailsModal; diff --git a/src/components/experiment-tracking/run-details-modal/run-details-modal.js b/src/components/experiment-tracking/run-details-modal/run-details-modal.js deleted file mode 100644 index ba56c8a380..0000000000 --- a/src/components/experiment-tracking/run-details-modal/run-details-modal.js +++ /dev/null @@ -1,146 +0,0 @@ -import React, { useEffect, useState, useContext } from 'react'; -import { connect } from 'react-redux'; -import { updateRunTitle, updateRunNotes } from '../../../actions'; - -import { ButtonTimeoutContext } from '../../../utils/button-timeout-context'; - -import Button from '../../ui/button'; -import Modal from '../../ui/modal'; -import Input from '../../ui/input'; - -import '../../settings-modal/settings-modal.scss'; -import './run-details-modal.scss'; - -const RunDetailsModal = ({ - runMetadataToEdit, - setShowRunDetailsModal, - theme, - visible, - runsMetadata, - onUpdateRunTitle, - onUpdateRunNotes, -}) => { - const [valuesToUpdate, setValuesToUpdate] = useState({}); - const { - handleClick, - hasNotInteracted, - isSuccessful, - setHasNotInteracted, - setIsSuccessful, - showModal, - } = useContext(ButtonTimeoutContext); - - const onApplyChanges = () => { - onUpdateRunTitle(valuesToUpdate.title, runMetadataToEdit.id); - onUpdateRunNotes(valuesToUpdate.notes, runMetadataToEdit.id); - - handleClick(); - setIsSuccessful(true); - }; - - const onChange = (key, value) => { - setValuesToUpdate( - Object.assign({}, valuesToUpdate, { - [key]: value, - }) - ); - setHasNotInteracted(false); - }; - - const onCloseModal = () => { - if (runMetadataToEdit?.id) { - const { notes = '', title = runMetadataToEdit.id } = - runsMetadata[runMetadataToEdit.id] || {}; - setValuesToUpdate({ notes, title }); - } - setShowRunDetailsModal(false); - }; - - // only if the component is visible first, then apply isSuccessful to show or hide modal - useEffect(() => { - if (visible && isSuccessful) { - setShowRunDetailsModal(showModal); - } - }, [showModal, setShowRunDetailsModal, isSuccessful, visible]); - - useEffect(() => { - if (runMetadataToEdit?.id) { - const { notes = '', title = runMetadataToEdit.id } = - runsMetadata[runMetadataToEdit.id] || {}; - setValuesToUpdate({ notes, title }); - } - }, [runMetadataToEdit, runsMetadata]); - - return ( -
- -
-
-
Run name
-
- onChange('title', value)} - resetValueTrigger={visible} - type="textarea" - size="large" - /> -
-
-
-
Notes
-
- onChange('notes', value)} - placeholder="Add here" - resetValueTrigger={visible} - type="textarea" - size="small" - /> -
-
- - -
-
-
- ); -}; - -export const mapStateToProps = (state) => ({ - runsMetadata: state.runsMetadata, -}); - -export const mapDispatchToProps = (dispatch) => ({ - onUpdateRunTitle: (title, runId) => { - dispatch(updateRunTitle(title, runId)); - }, - onUpdateRunNotes: (notes, runId) => { - dispatch(updateRunNotes(notes, runId)); - }, -}); - -export default connect(mapStateToProps, mapDispatchToProps)(RunDetailsModal); diff --git a/src/components/experiment-tracking/run-details-modal/run-details-modal.scss b/src/components/experiment-tracking/run-details-modal/run-details-modal.scss deleted file mode 100644 index c43b8b4dae..0000000000 --- a/src/components/experiment-tracking/run-details-modal/run-details-modal.scss +++ /dev/null @@ -1,32 +0,0 @@ -.pipeline-settings-modal--experiment-tracking .pipeline-settings-modal__name { - margin-top: 0; -} - -.run-details-modal-button-wrapper { - align-items: baseline; - display: flex; - justify-content: flex-end; - width: 100%; - - .button:first-of-type { - margin-right: 20px; - } -} - -.run-details-modal-error-wrapper { - font-size: 15px; - text-align: right; - width: 100%; -} - -.version-reminder-and-run-details-button-wrapper { - align-items: baseline; - display: flex; - justify-content: space-between; - width: 100%; - margin-top: 50px; - - .button:first-of-type { - margin-right: 20px; - } -} diff --git a/src/components/experiment-tracking/run-details-modal/run-details-modal.test.js b/src/components/experiment-tracking/run-details-modal/run-details-modal.test.js deleted file mode 100644 index e11f09b632..0000000000 --- a/src/components/experiment-tracking/run-details-modal/run-details-modal.test.js +++ /dev/null @@ -1,75 +0,0 @@ -import React from 'react'; -import RunDetailsModal from './index'; -import Adapter from '@cfaester/enzyme-adapter-react-18'; -import { configure } from 'enzyme'; -import { waitFor } from '@testing-library/react'; -import { ButtonTimeoutContext } from '../../../utils/button-timeout-context'; -import { setup } from '../../../utils/state.mock'; - -configure({ adapter: new Adapter() }); - -const mockValue = { - handleClick: jest.fn(), - hasNotInteracted: true, - isSuccessful: false, - setHasNotInteracted: jest.fn(), - setIsSuccessful: jest.fn(), - showModal: false, -}; - -// Tests - -describe('RunDetailsModal', () => { - it('renders without crashing', () => { - const wrapper = setup.mount( - - - - ); - - expect( - wrapper.find('.pipeline-settings-modal--experiment-tracking').length - ).toBe(1); - }); - - it('renders with a disabled primary button', () => { - const wrapper = setup.mount( - - - - ); - - const primaryButton = wrapper - .render() - .find( - '.pipeline-settings-modal--experiment-tracking .button__btn.button__btn--primary' - ); - - waitFor(() => expect(primaryButton).toBeDisabled()); - }); - - it('modal closes when cancel button is clicked', () => { - const setVisible = jest.fn(); - const wrapper = setup.mount( - - setVisible(true)} /> - - ); - const onClick = jest.spyOn(React, 'useState'); - const closeButton = wrapper.find( - '.pipeline-settings-modal--experiment-tracking .button__btn.button__btn--secondary' - ); - - onClick.mockImplementation((visible) => [visible, setVisible]); - - waitFor(() => { - closeButton.simulate('click'); - }); - - expect( - wrapper.find( - '.pipeline-settings-modal--experiment-tracking .kui-modal--visible' - ).length - ).toBe(0); - }); -}); diff --git a/src/components/experiment-tracking/run-export-modal/index.js b/src/components/experiment-tracking/run-export-modal/index.js deleted file mode 100644 index 64c6bf90bf..0000000000 --- a/src/components/experiment-tracking/run-export-modal/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import RunExportModal from './run-export-modal'; - -export default RunExportModal; diff --git a/src/components/experiment-tracking/run-export-modal/run-export-modal.js b/src/components/experiment-tracking/run-export-modal/run-export-modal.js deleted file mode 100644 index 0c54664537..0000000000 --- a/src/components/experiment-tracking/run-export-modal/run-export-modal.js +++ /dev/null @@ -1,102 +0,0 @@ -import React, { useState, useCallback, useContext, useEffect } from 'react'; -import { flushSync } from 'react-dom'; -import { connect } from 'react-redux'; -import { CSVLink } from 'react-csv'; - -import { constructExportData } from '../../../utils/experiment-tracking-utils'; -import { ButtonTimeoutContext } from '../../../utils/button-timeout-context'; - -import Button from '../../ui/button'; -import Modal from '../../ui/modal'; - -import './run-export-modal.scss'; - -const RunExportModal = ({ - runMetadata, - runTrackingData, - setShowRunExportModal, - theme, - visible, - runsMetadata, -}) => { - const [exportData, setExportData] = useState([]); - const { isSuccessful, showModal, handleClick } = - useContext(ButtonTimeoutContext); - - const updateExportData = useCallback(() => { - const mergedRunsMetadata = runMetadata?.map((run) => { - return { - ...run, - ...{ - title: runsMetadata[run.id]?.title || run.id, - notes: runsMetadata[run.id]?.notes || '', - }, - }; - }); - - // Require to opt-out of automatic batching in React 18 - flushSync(() => { - setExportData(constructExportData(mergedRunsMetadata, runTrackingData)); - handleClick(); - }); - }, [runMetadata, runTrackingData, handleClick, runsMetadata]); - - // only if the component is visible first, then apply isSuccessful to show or hide modal - useEffect(() => { - if (visible && isSuccessful) { - setShowRunExportModal(showModal); - } - }, [showModal, setShowRunExportModal, isSuccessful, visible]); - - return ( -
- setShowRunExportModal(false)} - theme={theme} - title="Export experiment run" - visible={visible} - > -
- - - - -
-
-
- ); -}; - -export const mapStateToProps = (state) => ({ - runsMetadata: state.runsMetadata, -}); - -export default connect(mapStateToProps)(RunExportModal); diff --git a/src/components/experiment-tracking/run-export-modal/run-export-modal.scss b/src/components/experiment-tracking/run-export-modal/run-export-modal.scss deleted file mode 100644 index cc08c5e6d9..0000000000 --- a/src/components/experiment-tracking/run-export-modal/run-export-modal.scss +++ /dev/null @@ -1,32 +0,0 @@ -@use '../../../styles/variables' as variables; - -.pipeline-run-export-modal--experiment-tracking .modal__title { - text-align: left; - margin-left: 30px; -} - -.run-export-modal-button-wrapper { - display: flex; - justify-content: space-around; - width: 100%; -} - -// set fix width for export button for when the text is shorter, eg "Done" -.pipeline-run-export-modal--experiment-tracking .button__btn--primary { - margin: 0; - - // to remove focus styling on the button as the style is directly from the CSVLink button - &:focus { - outline: none; - box-shadow: none; - } -} - -.run-export-modal-export-button:focus { - box-shadow: 0 0 0 7px variables.$blue-300; - outline: none; -} - -.run-export-modal-export-button--success:focus-visible { - outline: none; -} diff --git a/src/components/experiment-tracking/run-export-modal/run-export-modal.test.js b/src/components/experiment-tracking/run-export-modal/run-export-modal.test.js deleted file mode 100644 index a03993e21a..0000000000 --- a/src/components/experiment-tracking/run-export-modal/run-export-modal.test.js +++ /dev/null @@ -1,118 +0,0 @@ -import React from 'react'; -import configureMockStore from 'redux-mock-store'; -import RunExportModal from './index'; -import Adapter from '@cfaester/enzyme-adapter-react-18'; -import { configure } from 'enzyme'; -import { render, screen } from '@testing-library/react'; -import { ButtonTimeoutContext } from '../../../utils/button-timeout-context'; -import { setup } from '../../../utils/state.mock'; -import { runs } from '../../experiment-wrapper/mock-data'; - -// to help find text which is made by multiple HTML elements -// eg:
Hello world
-const findTextWithTags = (textMatch) => { - return screen.findByText((content, node) => { - const hasText = (node) => node.textContent === textMatch; - const nodeHasText = hasText(node); - const childrenDontHaveText = Array.from(node?.children || []).every( - (child) => !hasText(child) - ); - return nodeHasText && childrenDontHaveText; - }); -}; - -const mockValue = { - handleClick: jest.fn(), - isSuccessful: false, - setIsSuccessful: jest.fn(), - showModal: false, -}; -configure({ adapter: new Adapter() }); -const mockStore = configureMockStore(); - -describe('RunExportModal', () => { - let store; - beforeEach(() => { - const initialState = { - runsMetadata: { [runs[0].id]: runs[0], [runs[1].id]: runs[1] }, - }; - - store = mockStore(initialState); - }); - - it('renders the component without crashing', () => { - const wrapper = setup.mount( - - - - ); - - expect( - wrapper.find('.pipeline-run-export-modal--experiment-tracking').length - ).toBe(1); - }); - - it('modal closes when cancel button is clicked', () => { - const setVisible = jest.fn(); - const wrapper = setup.mount( - - setVisible(true)} - /> - - ); - const onClick = jest.spyOn(React, 'useState'); - const closeButton = wrapper.find( - '.pipeline-run-export-modal--experiment-tracking .button__btn--secondary' - ); - - onClick.mockImplementation((visible) => [visible, setVisible]); - - closeButton.simulate('click'); - - expect( - wrapper.find( - '.pipeline-run-export-modal--experiment-tracking .kui-modal--visible' - ).length - ).toBe(0); - }); - - it('Text is updated to "Done ✅" when the "Export all and close" is clicked, and modal is closed', () => { - const setVisible = jest.fn(); - const wrapper = setup.mount( - - setVisible(true)} - /> - - ); - - // original text should be "Export all and close" - const { getByText } = render( - - - - ); - expect(getByText(/Export all and close/i)).toBeVisible(); - - const onClick = jest.spyOn(React, 'useState'); - const exportAllAndCloseBtn = wrapper.find( - '.pipeline-run-export-modal--experiment-tracking .button__btn--primary' - ); - - onClick.mockImplementation((visible) => [visible, setVisible]); - exportAllAndCloseBtn.simulate('click'); - - // expect the text to be changed first - expect(findTextWithTags('Done ✅ ')).toBeTruthy(); - - // then the modal is closed - expect( - wrapper.find( - '.pipeline-run-export-modal--experiment-tracking .kui-modal--visible' - ).length - ).toBe(0); - }); -}); diff --git a/src/components/experiment-tracking/run-metadata/animation.scss b/src/components/experiment-tracking/run-metadata/animation.scss deleted file mode 100644 index 2a15af6832..0000000000 --- a/src/components/experiment-tracking/run-metadata/animation.scss +++ /dev/null @@ -1,76 +0,0 @@ -$animation-timing: 0.3s; - -// Animation for the first run when switching the comparison view. -.details-dataset__value, -.details-dataset__value-header, -.details-metadata__run { - transform: translateX(0%); - transition: transform $animation-timing ease-out; -} - -.details-dataset__value-header--comparison-view, -.details-dataset__value--comparison-view, -.details-metadata__run--first-run-comparison-view { - transform: translateX(-25%); - transition: transform $animation-timing ease-out; -} - -// To transition the metadata and dataset panel to the left -// when switch to comparison view. -.details-dataset__accordion-wrapper-comparison-view, -.details-metadata__table-comparison-view { - transform: translateX(-4em); - transition: transform $animation-timing ease-out; -} - -.details-metadata__labels .details-metadata__title { - opacity: 1; - transform: translateX(0); - transition: opacity 0.1s ease-in-out; -} - -.details-metadata__labels-comparison-view .details-metadata__title { - opacity: 0; - pointer-events: none; - transform: translateX(-25%); - transition: opacity 0.1s ease-in-out, transform 1s ease-in-out; -} - -.details-metadata__run--first-run .details-metadata__title { - opacity: 0; -} - -.details-metadata__run--first-run-comparison-view .details-metadata__title { - opacity: 1; - transition: opacity $animation-timing linear; -} - -// Animation for other run when selected or deselected. -// Needed to use react-cssTransition to animate when the run isn't in the DOM anymore. -.details-metadata__run-animation-enter, -.details-dataset__value-animation-enter { - opacity: 0; - transform: translateX(40%); - transition: transform $animation-timing ease-out, - opacity $animation-timing linear; -} - -.details-metadata__run-animation-enter-active, -.details-dataset__value-animation-enter-active { - opacity: 1; - transform: translateX(0); - transition: transform $animation-timing ease-out, - opacity $animation-timing linear; -} - -.details-metadata__run-animation-exit, -.details-dataset__value-animation-exit { - opacity: 1; - transition: opacity $animation-timing linear; -} - -.details-metadata__run-animation-exit-active, -.details-dataset__value-animation-exit-active { - opacity: 0; - transition: opacity $animation-timing linear; -} diff --git a/src/components/experiment-tracking/run-metadata/index.js b/src/components/experiment-tracking/run-metadata/index.js deleted file mode 100644 index c722d16e44..0000000000 --- a/src/components/experiment-tracking/run-metadata/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import RunMetadata from './run-metadata'; - -export default RunMetadata; diff --git a/src/components/experiment-tracking/run-metadata/run-metadata-loader.js b/src/components/experiment-tracking/run-metadata/run-metadata-loader.js deleted file mode 100644 index 181e39cf64..0000000000 --- a/src/components/experiment-tracking/run-metadata/run-metadata-loader.js +++ /dev/null @@ -1,87 +0,0 @@ -import React from 'react'; -import ContentLoader from 'react-content-loader'; -import { - experimentTrackingLazyLoadingColours, - experimentTrackingLazyLoadingGap, -} from '../../../config'; - -import './run-metadata.scss'; - -const GAP = experimentTrackingLazyLoadingGap; - -const TitleLoader = () => ( - <> - - - - - - - - -); - -const DetailsLoader = ({ x }) => ( - <> - - - - - - - - -); - -export const SingleRunMetadataLoader = ({ theme }) => ( -
- - - - -
-); - -export const MetaDataLoader = ({ length, theme }) => { - const x = length > 1 ? 75 : 0; - - return ( - - - - - - - - - - ); -}; diff --git a/src/components/experiment-tracking/run-metadata/run-metadata.js b/src/components/experiment-tracking/run-metadata/run-metadata.js deleted file mode 100644 index b88bed77c6..0000000000 --- a/src/components/experiment-tracking/run-metadata/run-metadata.js +++ /dev/null @@ -1,326 +0,0 @@ -import React, { useCallback, useState } from 'react'; -import { connect } from 'react-redux'; -import classnames from 'classnames'; -import { useOutsideClick } from '../../../utils/hooks'; -import { toHumanReadableTime } from '../../../utils/date-utils'; -import CloseIcon from '../../icons/close'; -import IconButton from '../../ui/icon-button'; -import KebabIcon from '../../icons/kebab'; -import SelectedPin from '../../icons/selected-pin'; -import UnSelectedPin from '../../icons/un-selected-pin'; -import { TransitionGroup, CSSTransition } from 'react-transition-group'; -import { MetaDataLoader } from './run-metadata-loader'; -import { toggleBookmark } from '../../../actions'; -import { RUN_NOTES, RUN_TITLE } from '../../../config'; - -import './run-metadata.scss'; -import './animation.scss'; - -// Return a '-' character if the value is empty or null -const sanitiseEmptyValue = (value) => { - return value === '' || value === null ? '-' : value; -}; - -const HiddenMenu = ({ runsMetadata, runId, onToggleBookmark }) => { - const [isVisible, setIsVisible] = useState(false); - const { bookmark = false } = runsMetadata[runId] || {}; - - const handleClickOutside = useCallback(() => { - setIsVisible(false); - }, []); - - const menuRef = useOutsideClick(handleClickOutside); - - const toggleBookmark = () => { - onToggleBookmark(!bookmark, runId); - - // Close the menu when the bookmark is toggled. - setIsVisible(false); - }; - - return ( -
setIsVisible(!isVisible)} - ref={menuRef} - > -
-
{ - toggleBookmark(); - e.stopPropagation(); - }} - > - {bookmark ? 'Unbookmark' : 'Bookmark'} -
-
- -
- ); -}; - -const RunMetadata = ({ - activeTab, - enableComparisonView, - enableShowChanges = false, - isSingleRun, - onRunSelection, - pinnedRun, - runs = [], - setPinnedRun, - setRunMetadataToEdit, - setShowRunDetailsModal, - showLoader, - theme, - runsMetadata, - onToggleBookmark, -}) => { - let initialState = {}; - for (let i = 0; i < runs.length; i++) { - initialState[i] = false; - } - - const [toggleNotes, setToggleNotes] = useState(initialState); - - const onToggleNoteExpand = (index) => { - setToggleNotes({ ...toggleNotes, [index]: !toggleNotes[index] }); - }; - - const onTitleOrNoteClick = (id) => { - const metadata = runs.find((run) => run.id === id); - - setRunMetadataToEdit(metadata); - setShowRunDetailsModal(true); - }; - - const getNotesByRunId = (runId) => { - if (runsMetadata[runId]) { - return runsMetadata[runId][RUN_NOTES] || ''; - } - - return ''; - }; - - const getTitleByRunId = (runId) => { - if (runsMetadata[runId]) { - return runsMetadata[runId][RUN_TITLE] || runId; - } - - return runId; - }; - - // Initialize title and notes for each run - const runsWithMetadata = runs.map((run) => ({ - ...run, - title: getTitleByRunId(run.id), - notes: getNotesByRunId(run.id), - })); - - return ( -
- - {runsWithMetadata.map((run, i) => ( - - {i === 0 ? ( - - - - {activeTab !== 'Plots' ? ( - <> - - - - - - - - ) : null} - - - ) : null} - - ))} - - {runsWithMetadata.map((run, i) => { - const humanReadableTime = toHumanReadableTime(run.id); - - return ( - - - - {activeTab !== 'Plots' ? ( - <> - - - - - - - - ) : null} - - - ); - })} - - {showLoader && } -
- onTitleOrNoteClick(run.id)} - title={sanitiseEmptyValue(run.title)} - > - {sanitiseEmptyValue(run.title)} - - - Created By - - Creation Date - Git SHA - Git Branch - - Run Command - Notes
-
- onTitleOrNoteClick(run.id)} - title={sanitiseEmptyValue(run.title)} - > - {sanitiseEmptyValue(run.title)} - -
    - {!isSingleRun ? ( - <> - setPinnedRun(run.id)} - visible={enableShowChanges} - /> - onRunSelection(run.id)} - /> - - ) : null} - -
-
- {sanitiseEmptyValue(run.author)} - {`${humanReadableTime} (${sanitiseEmptyValue( - run.id - )})`} - {sanitiseEmptyValue(run.gitSha)} - - {sanitiseEmptyValue(run.gitBranch)} - - {sanitiseEmptyValue(run.runCommand)} - -

onTitleOrNoteClick(run.id)} - style={toggleNotes[i] ? { display: 'block' } : null} - > - {run.notes !== '' ? run.notes : '- Add notes here'} -

- {run.notes.length > 100 ? ( - - ) : null} -
-
- ); -}; - -export const mapStateToProps = (state) => ({ - runsMetadata: state.runsMetadata, -}); - -export const mapDispatchToProps = (dispatch) => ({ - onToggleBookmark: (bookmark, runId) => { - dispatch(toggleBookmark(bookmark, runId)); - }, -}); - -export default connect(mapStateToProps, mapDispatchToProps)(RunMetadata); diff --git a/src/components/experiment-tracking/run-metadata/run-metadata.scss b/src/components/experiment-tracking/run-metadata/run-metadata.scss deleted file mode 100644 index 01e564840e..0000000000 --- a/src/components/experiment-tracking/run-metadata/run-metadata.scss +++ /dev/null @@ -1,240 +0,0 @@ -@use '../../../styles/extends'; -@use '../../../styles/variables' as variables; - -.details-metadata { - background-color: var(--color-exp-tracking-metadata); - display: flex; - flex-shrink: 0; - min-height: 350px; - min-width: 100%; - padding: 5em 0 0 9em; - - &--not-overview { - background-color: var(--color-exp-tracking-bg); - min-height: auto; - } -} - -.details-metadata__buttons { - display: flex; - list-style: none; - margin: -2px 0 0; - padding: 0; - - li, - .hidden-menu-wrapper { - margin-right: 5px; - position: relative; - - &:last-of-type:not(.hidden-menu-wrapper) { - margin-right: 0; - } - } - - .pipeline-icon-toolbar__button { - height: 24px; - width: 24px; - } - - svg { - height: 25px; - width: 25px; - } -} - -.details-metadata__buttons--selected-pin svg { - fill: variables.$blue-300; -} - -// a single run when it's not in comparison mode -.details-metadata__run { - flex-shrink: 0; - margin-right: 12em; - max-width: variables.$run-width; -} - -.details-metadata__labels, -.details-metadata__labels-comparison-view, -.details-metadata__run--first-run-comparison-view { - margin-right: 0; -} - -.details-metadata__labels { - width: variables.$run-width; -} - -.details-metadata__labels-comparison-view { - width: variables.$run-width-comparison-view; -} - -.details-metadata__run td { - font-size: 1.4em; - padding-bottom: 16px; - vertical-align: top; - word-wrap: break-word; // For breaking potential long text, such as as git branch, title, etc. -} - -// a single run when comparison view is on -.details-metadata__run--first-run-comparison-view { - .details-metadata__table-label, - .details-metadata__table-value { - width: variables.$run-width-comparison-view; - } -} - -.details-metadata__run--first-run-comparison-view td { - &:first-of-type { - width: 100%; - } - - &:last-of-type { - width: 100%; - } -} - -.details-metadata__table tr { - display: flex; - flex-direction: column; - width: variables.$run-width; -} - -.details-metadata__table-comparison-view tr { - display: flex; - flex-direction: column; - width: variables.$run-width-comparison-view; -} - -.details-metadata__run--wrapper { - display: flex; -} - -.details-metadata__run--wrapper tr { - &:first-of-type { - margin-right: 5em; - } - - &:last-of-type { - margin-right: 0; - } -} - -// animation for the title of the baseline when comparison mode is on -.details-metadata__title { - align-items: center; - display: flex; - justify-content: space-between; -} - -.details-metadata__title--empty { - width: 365px; -} - -.details-metadata__table { - display: flex; - border-collapse: collapse; - flex-shrink: 0; - width: 100%; - margin-left: -1px; // For exact alignment with content below. -} - -.details-metadata__title-detail { - cursor: pointer; - font-size: 20px; - font-weight: 600; - overflow: hidden; - text-decoration-color: transparent; - text-overflow: ellipsis; - transition: text-decoration-color 0.2s ease; - white-space: nowrap; - - &:hover { - text-decoration: underline; - text-decoration-color: var(--color-text); - } -} - -.details-metadata__indicator { - margin-right: 1em; - - &--selected-first { - @extend %runs-list-card--selected-first; - - border-style: solid; - flex-shrink: 0; - } - - &--selected-second { - @extend %runs-list-card--selected-second; - - border-style: solid; - flex-shrink: 0; - } - - &--selected-third { - @extend %runs-list-card--selected-third; - - flex-shrink: 0; - } -} - -.details-metadata__title .pipeline-toolbar__label { - font-size: 1em; -} - -.details-metadata__notes { - -webkit-box-orient: vertical; - -webkit-line-clamp: 2; - cursor: pointer; - display: -webkit-box; - margin: 0; - overflow: hidden; - text-overflow: ellipsis; - text-decoration-color: transparent; - transition: text-decoration-color 0.2s ease; - - &:hover { - text-decoration: underline; - text-decoration-color: var(--color-text); - } -} - -.details-metadata__show-more.kedro { - background-color: unset; - border: none; - color: var(--color-text-faded); - cursor: pointer; - font-size: 14px; - margin: 2px 0 0; - padding: 0; -} - -.hidden-menu { - background: variables.$white-200; - opacity: 0; - pointer-events: none; - position: absolute; - right: 0; - top: 0; - transition: opacity 0.1s ease, top 0.2s ease; - width: 120px; - - &--visible { - opacity: 1; - pointer-events: all; - top: 30px; - } -} - -.hidden-menu__item { - color: variables.$black-800; - cursor: pointer; - padding: 6px 0 6px 20px; - - &:hover { - background: variables.$white-0; - } -} - -.details-metadata__run-lazy-loader { - max-height: 300px; -} diff --git a/src/components/experiment-tracking/run-metadata/run-metadata.test.js b/src/components/experiment-tracking/run-metadata/run-metadata.test.js deleted file mode 100644 index 0c504a1316..0000000000 --- a/src/components/experiment-tracking/run-metadata/run-metadata.test.js +++ /dev/null @@ -1,98 +0,0 @@ -import React from 'react'; -import configureMockStore from 'redux-mock-store'; -import RunMetadata from '.'; -import { runs } from '../../experiment-wrapper/mock-data'; -import Adapter from '@cfaester/enzyme-adapter-react-18'; -import { configure, mount } from 'enzyme'; -import { setup } from '../../../utils/state.mock'; - -configure({ adapter: new Adapter() }); -const mockStore = configureMockStore(); - -describe('RunMetadata', () => { - it('renders without crashing', () => { - const wrapper = setup.mount( - - ); - - expect(wrapper.find('.details-metadata').length).toBe(1); - expect(wrapper.find('.details-metadata__run').length).toBe(4); - }); - - it('renders a first run for when theres a single run', () => { - const wrapper = setup.mount( - - ); - - expect(wrapper.find('.details-metadata').length).toBe(1); - expect(wrapper.find('.details-metadata__run--first-run').length).toBe(1); - }); - - it('contains "-comparison-view" classname for when the comparison mode is enabled', () => { - const wrapper = setup.mount( - - ); - - expect( - wrapper.find('.details-metadata__table-comparison-view').length - ).toBe(1); - }); - - it('shows a "--first-run" for the first run when comparison mode is on', () => { - const wrapper = setup.mount( - - ); - expect(wrapper.find('.details-metadata__run--first-run').length).toBe(1); - expect( - wrapper.find('.details-metadata__run--first-run-comparison-view').length - ).toBe(1); - }); - - let wrapper, store; - - beforeEach(() => { - const initialState = { - runsMetadata: { [runs[0].id]: runs[0], [runs[1].id]: runs[1] }, - }; - - store = mockStore(initialState); - - wrapper = mount( - - ); - }); - - it('handles show more/less button click event', () => { - const setToggleNotes = jest.fn(); - const onClick = jest.spyOn(React, 'useState'); - onClick.mockImplementation((toggleNotes) => [toggleNotes, setToggleNotes]); - - expect(wrapper.find('.details-metadata__show-more').text()).toMatch( - 'Show more' - ); - - wrapper.find('.details-metadata__show-more').simulate('click'); - expect(setToggleNotes).toBeTruthy(); - expect(wrapper.find('.details-metadata__show-more').text()).toMatch( - 'Show less' - ); - - wrapper.find('.details-metadata__show-more').simulate('click'); - expect(setToggleNotes).toBeTruthy(); - expect(wrapper.find('.details-metadata__show-more').text()).toMatch( - 'Show more' - ); - }); - - it('enables the pin button when show changes is enabled ', () => { - expect(wrapper.find('.pipeline-menu-button__pin').length).toEqual(2); - }); -}); diff --git a/src/components/experiment-tracking/run-plots-modal/index.js b/src/components/experiment-tracking/run-plots-modal/index.js deleted file mode 100644 index bd6c902492..0000000000 --- a/src/components/experiment-tracking/run-plots-modal/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import RunPlotsModal from './run-plots-modal'; - -export default RunPlotsModal; diff --git a/src/components/experiment-tracking/run-plots-modal/run-plots-modal.js b/src/components/experiment-tracking/run-plots-modal/run-plots-modal.js deleted file mode 100644 index a7a0d38f0a..0000000000 --- a/src/components/experiment-tracking/run-plots-modal/run-plots-modal.js +++ /dev/null @@ -1,130 +0,0 @@ -import React, { useEffect } from 'react'; -import PlotlyChart from '../../plotly-chart'; -import BackWideIcon from '../../icons/back-wide'; -import NodeIcon from '../../icons/node-icon'; -import getShortType from '../../../utils/short-type'; -import { toHumanReadableTime } from '../../../utils/date-utils'; -import classNames from 'classnames'; -import './run-plots-modal.scss'; - -const RunPlotsModal = ({ runDatasetToShow, visible, setShowRunPlotsModal }) => { - const { datasetKey, datasetType, datasetValues } = runDatasetToShow; - const runDataWithPlotData = datasetValues?.filter(({ value }) => value); - const numDatasets = runDataWithPlotData?.length; - const plotView = - numDatasets === 3 - ? 'threeCharts' - : numDatasets === 2 - ? 'twoCharts' - : 'oneChart'; - const isPlotly = getShortType(datasetType) === 'plotly'; - const isImage = getShortType(datasetType) === 'image'; - const nodeTypeIcon = getShortType(datasetType); - - const handleKeyDown = (event) => { - if (event.keyCode === 27) { - setShowRunPlotsModal(false); - } - }; - - useEffect(() => { - if (visible) { - window.addEventListener('keydown', handleKeyDown); - } - - return () => window.removeEventListener('keydown', handleKeyDown); - }); - - if (!visible) { - return null; - } - - return ( -
-
- -
- - {datasetKey} -
-
-
- {isPlotly && - runDataWithPlotData.map((data) => { - return ( - data.value && ( -
- -
- - {data.runId} - - - {toHumanReadableTime(data.runId)} - -
-
- ) - ); - })} - {isImage && - runDataWithPlotData.map((data) => { - return ( -
- Matplotlib rendering -
- - {data.runId} - - - {toHumanReadableTime(data.runId)} - -
-
- ); - })} -
-
- ); -}; - -export default RunPlotsModal; diff --git a/src/components/experiment-tracking/run-plots-modal/run-plots-modal.scss b/src/components/experiment-tracking/run-plots-modal/run-plots-modal.scss deleted file mode 100644 index 23bf4ff5e1..0000000000 --- a/src/components/experiment-tracking/run-plots-modal/run-plots-modal.scss +++ /dev/null @@ -1,169 +0,0 @@ -@use '../../../styles/extends'; -@use '../../../styles/variables' as variables; - -.kui-theme--light { - --color-bg-plot: #{variables.$white-0}; -} - -.kui-theme--dark { - --color-bg-plot: #{variables.$slate-600}; -} - -.pipeline-run-plots-modal { - align-items: center; - background-color: var(--color-bg-plot); - inset: 0 0 0 variables.$global-toolbar-width; - display: flex; - flex-direction: column; - overflow-y: scroll; - position: absolute; - z-index: variables.$zindex-plot-modal;; -} - -.pipeline-run-plots-modal__top { - align-items: center; - display: flex; - flex-direction: row; - min-width: 100%; - padding: 4.5em 0 1.5em; -} - -.pipeline-run-plots-modal__header { - display: flex; - margin: 0 auto; - padding: 0 32px; -} - -.pipeline-run-plots-modal__icon { - display: inline-block; - fill: var(--color-text); - height: 2.8em; - margin: 0 10px 0 0; - width: 2.9em; -} - -.pipeline-run-plots-modal__title { - font-size: 1.8em; - margin-top: 1px; -} - -.pipeline-run-plots-modal__back { - @extend %button; - - align-items: center; - display: flex; - margin: 0 -139px 0 58px; - padding: 6px 0; - position: relative; -} - -.pipeline-run-plots-modal__content { - align-items: center; - display: flex; - margin: auto; - width: calc(100% - 116px); - - &--oneChart { - justify-content: center; - } - - &--twoCharts { - justify-content: space-between; - } - - &--plotly { - height: calc(100% - 66px - 6em); - margin: 3em auto; - } -} - -.pipeline-run-plots-modal__back-text { - font-size: 1.6em; -} - -.pipeline-run-plots-modal__back-icon { - fill: var(--color-text); - height: 1.4em; - margin: 0 12px 0 0; - width: 3.6em; -} - -// This is the wrapper element for Matplotlib images. -.pipeline-run-plots__image-wrapper { - margin-bottom: 3em; - margin-top: 3em; - - &--oneChart { - display: flex; - flex-direction: column; - justify-content: center; - margin: 0; - width: 815px; - } - - &--twoCharts { - display: flex; - flex-direction: column; - width: 50%; - - &:nth-of-type(2) { - margin-left: 58px; - } - } - - &--threeCharts { - display: flex; - flex-direction: column; - width: 33.33%; - - &:nth-of-type(2), - &:nth-of-type(3) { - margin-left: 35px; - } - } - - .pipeline-run-plots__image--oneChart, - .pipeline-run-plots__image--twoCharts, - .pipeline-run-plots__image--threeCharts { - padding-bottom: 24px; - width: 100%; - } -} - -// This is the wrapper element for Plotly charts. -.pipeline-run-plots__plot-wrapper { - display: flex; - flex-direction: column; - - &--oneChart { - height: 100%; - justify-content: center; - width: 100%; - } - - &--twoCharts { - width: 50%; - - &:nth-of-type(2) { - margin-left: 47px; - } - } - - &--threeCharts { - width: 33.333%; - - &:nth-of-type(2), - &:nth-of-type(3) { - margin-left: 25px; - } - } -} - -.pipeline-run-plots-image-text-timestamp { - font-size: 1.6em; - padding-right: 1.6em; -} - -.pipeline-run-plots-image-text-relative_timestamp { - font-size: 1.3em; -} diff --git a/src/components/experiment-tracking/run-plots-modal/run-plots-modal.test.js b/src/components/experiment-tracking/run-plots-modal/run-plots-modal.test.js deleted file mode 100644 index 980478da98..0000000000 --- a/src/components/experiment-tracking/run-plots-modal/run-plots-modal.test.js +++ /dev/null @@ -1,187 +0,0 @@ -import React from 'react'; -import RunPlotsModal from './run-plots-modal'; -import { setup } from '../../../utils/state.mock'; - -function generateTestData(numberOfRuns = 2, dataType = 'plotly') { - return { - datasetKey: - dataType === 'matplotlib' ? 'matplotlib_plot.png' : 'plotly chart', - datasetType: - dataType === 'matplotlib' - ? 'matplotlib.matplotlib_writer.MatplotlibWriter' - : 'plotly.plotly_dataset.PlotlyDataset', - datasetValues: [...Array(numberOfRuns).keys()].map((run) => { - if (dataType === 'matplotlib') { - return { - runId: `2022-07-0${run + 1}T12.54.06.759Z`, - value: 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', - }; - } else { - return { - runId: `2022-07-0${run + 1}T12.54.06.759Z`, - value: { - data: [ - { - x: [1, 2, 3], - y: [2, 6, 3], - type: 'scatter', - mode: 'lines+markers', - marker: { color: 'red' }, - }, - { type: 'bar', x: [1, 2, 3], y: [2, 5, 3] }, - ], - layout: { width: 320, height: 240, title: 'A Fancy Plot' }, - }, - }; - } - }), - }; -} - -describe('Run Plots Modal', () => { - const setShowRunPlotsModal = jest.fn(); - - it('renders without crashing', () => { - const wrapper = setup.mount( - - ); - - expect(wrapper.find('.pipeline-run-plots-modal').length).toBe(1); - expect(wrapper.find('.pipeline-run-plots-modal__title').length).toBe(1); - expect(wrapper.find('.pipeline-run-plots-modal__title').text()).toBe( - 'matplotlib_plot.png' - ); - expect( - wrapper.find('.pipeline-run-plots-modal__content--oneChart').length - ).toBe(1); - expect(wrapper.find('.pipeline-run-plots__image--oneChart').length).toBe(1); - expect( - wrapper.find('.pipeline-run-plots-image-text-relative_timestamp').length - ).toBe(1); - expect( - wrapper.find('.pipeline-run-plots-image-text-timestamp').length - ).toBe(1); - }); - - it('renders two Matplotlib images with timestamps and human readable times', () => { - const wrapper = setup.mount( - - ); - - expect(wrapper.find('.pipeline-run-plots-modal').length).toBe(1); - expect(wrapper.find('.pipeline-run-plots-modal__title').length).toBe(1); - expect(wrapper.find('.pipeline-run-plots-modal__title').text()).toBe( - 'matplotlib_plot.png' - ); - expect( - wrapper.find('.pipeline-run-plots-modal__content--twoCharts').length - ).toBe(1); - expect(wrapper.find('.pipeline-run-plots__image--twoCharts').length).toBe( - 2 - ); - expect( - wrapper.find('.pipeline-run-plots-image-text-relative_timestamp').length - ).toBe(2); - expect( - wrapper.find('.pipeline-run-plots-image-text-timestamp').length - ).toBe(2); - }); - - it('renders three Matplotlib images with timestamps and human readable times', () => { - const wrapper = setup.mount( - - ); - - expect(wrapper.find('.pipeline-run-plots-modal').length).toBe(1); - expect(wrapper.find('.pipeline-run-plots-modal__title').length).toBe(1); - expect(wrapper.find('.pipeline-run-plots-modal__title').text()).toBe( - 'matplotlib_plot.png' - ); - expect( - wrapper.find('.pipeline-run-plots-modal__content--threeCharts').length - ).toBe(1); - expect(wrapper.find('.pipeline-run-plots__image--threeCharts').length).toBe( - 3 - ); - expect( - wrapper.find('.pipeline-run-plots-image-text-relative_timestamp').length - ).toBe(3); - expect( - wrapper.find('.pipeline-run-plots-image-text-timestamp').length - ).toBe(3); - }); - - it('renders two Plotly charts with timestamps and human readable times', () => { - const wrapper = setup.mount( - - ); - - expect(wrapper.find('.pipeline-run-plots-modal').length).toBe(1); - expect(wrapper.find('.pipeline-run-plots-modal__title').length).toBe(1); - expect(wrapper.find('.pipeline-run-plots-modal__title').text()).toBe( - 'plotly chart' - ); - expect( - wrapper.find('.pipeline-run-plots-modal__content--twoCharts').length - ).toBe(1); - expect( - wrapper.find('.pipeline-run-plots-modal__content--plotly').length - ).toBe(1); - expect( - wrapper.find('.pipeline-run-plots__plot-wrapper--twoCharts').length - ).toBe(2); - expect( - wrapper.find('.pipeline-run-plots-image-text-relative_timestamp').length - ).toBe(2); - expect( - wrapper.find('.pipeline-run-plots-image-text-timestamp').length - ).toBe(2); - }); - - it('renders three Plotly charts with timestamps and human readable times', () => { - const wrapper = setup.mount( - - ); - - expect(wrapper.find('.pipeline-run-plots-modal').length).toBe(1); - expect(wrapper.find('.pipeline-run-plots-modal__title').length).toBe(1); - expect(wrapper.find('.pipeline-run-plots-modal__title').text()).toBe( - 'plotly chart' - ); - expect( - wrapper.find('.pipeline-run-plots-modal__content--threeCharts').length - ).toBe(1); - expect( - wrapper.find('.pipeline-run-plots-modal__content--plotly').length - ).toBe(1); - expect( - wrapper.find('.pipeline-run-plots__plot-wrapper--threeCharts').length - ).toBe(3); - expect( - wrapper.find('.pipeline-run-plots-image-text-relative_timestamp').length - ).toBe(3); - expect( - wrapper.find('.pipeline-run-plots-image-text-timestamp').length - ).toBe(3); - }); -}); diff --git a/src/components/experiment-tracking/runs-list-card/index.js b/src/components/experiment-tracking/runs-list-card/index.js deleted file mode 100644 index c0633d66e0..0000000000 --- a/src/components/experiment-tracking/runs-list-card/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import RunsListCard from './runs-list-card'; - -export default RunsListCard; diff --git a/src/components/experiment-tracking/runs-list-card/runs-list-card.js b/src/components/experiment-tracking/runs-list-card/runs-list-card.js deleted file mode 100644 index 3f32f37917..0000000000 --- a/src/components/experiment-tracking/runs-list-card/runs-list-card.js +++ /dev/null @@ -1,139 +0,0 @@ -import React, { useEffect, useState, useContext } from 'react'; -import { connect } from 'react-redux'; -import classnames from 'classnames'; -import { - getHighlightedText, - textMatchesSearch, -} from '../../../utils/search-utils'; -import { toHumanReadableTime } from '../../../utils/date-utils'; -import BookmarkIcon from '../../icons/bookmark'; -import BookmarkStrokeIcon from '../../icons/bookmark-stroke'; -import { HoverStateContext } from '../utils/hover-state-context'; -import { toggleBookmark } from '../../../actions'; - -import './runs-list-card.scss'; - -/** - * Display a card showing run info from an experiment - * @param {Object} data High-level data from the run (id, etc.) - */ -const RunsListCard = ({ - data, - disableRunSelection = false, - enableComparisonView = false, - onRunSelection, - selectedRunIds = [], - searchValue, - selectedIndex, - runsMetadata, - onToggleBookmark, -}) => { - const { id, gitSha } = data; - const { notes = '', title = id, bookmark = false } = runsMetadata[id] || {}; - const [active, setActive] = useState(false); - const humanReadableTime = toHumanReadableTime(id); - - const { setHoveredElementId, hoveredElementId } = - useContext(HoverStateContext); - - const isMatchSearchValue = (text) => - searchValue ? textMatchesSearch(text, searchValue) : false; - - const displayValue = (value) => - isMatchSearchValue(value) ? getHighlightedText(value, searchValue) : value; - - const isSearchValueInNotes = isMatchSearchValue(notes); - - const onRunsListCardClick = (id, e) => { - /** - * If we click the bookmark icon or the path HTML element within the SVG, - * then update the bookmark boolean. If we didn't check for the path, the - * user could hit a dead zone, and nothing would happen. - */ - if ( - e.target.classList.contains('runs-list-card__bookmark') || - e.target.tagName === 'path' - ) { - onToggleBookmark(!bookmark, id); - return; - } - - onRunSelection(id); - }; - - useEffect(() => { - setActive(selectedRunIds.includes(id)); - }, [id, selectedRunIds]); - - return ( -
onRunsListCardClick(id, e)} - onMouseOver={() => setHoveredElementId(id)} - onMouseLeave={() => setHoveredElementId(null)} - > - {enableComparisonView && ( -
- )} -
-
- -
-
{humanReadableTime}
- {isSearchValueInNotes && ( -
${displayValue(notes)}`, - }} - /> - )} -
- {bookmark ? ( - - ) : ( - - )} -
- ); -}; - -export const mapStateToProps = (state) => ({ - runsMetadata: state.runsMetadata, -}); - -export const mapDispatchToProps = (dispatch) => ({ - onToggleBookmark: (bookmark, runId) => { - dispatch(toggleBookmark(bookmark, runId)); - }, -}); - -export default connect(mapStateToProps, mapDispatchToProps)(RunsListCard); diff --git a/src/components/experiment-tracking/runs-list-card/runs-list-card.scss b/src/components/experiment-tracking/runs-list-card/runs-list-card.scss deleted file mode 100644 index 7c3d67cb61..0000000000 --- a/src/components/experiment-tracking/runs-list-card/runs-list-card.scss +++ /dev/null @@ -1,116 +0,0 @@ -@use '../../../styles/extends'; -@use '../../../styles/variables' as colors; - -.kui-theme--light { - --color-run-list-highlight: #{colors.$blue-300}; - --color-run-list-bookmark: #{colors.$black-800}; -} - -.kui-theme--dark { - --color-run-list-highlight: #{colors.$blue-300}; - --color-run-list-bookmark: #{colors.$white-600}; -} - -.runs-list-card { - align-items: flex-start; - background: var(--color-bg-3); - border-bottom: 1px solid var(--color-run-list-divider); - display: flex; - padding: 1.6em 2.8em 2em 3em; - - &--active { - background: var(--color-run-list-hover); - box-shadow: -1px 0 0 inset colors.$blue-300; - } - - &--disabled { - opacity: 0.5; - pointer-events: none; - } -} - -.runs-list-card--hovered { - background: var(--color-run-list-hover); - cursor: pointer; - - .runs-list-card__bookmark--stroke { - opacity: 1; - } -} - -.runs-list-card__title { - font-size: 1.6em; - line-height: 1.5; - - b { - color: var(--color-run-list-highlight); - font-weight: normal; - } -} - -.runs-list-card__gitsha { - color: var(--color-text-faded); - font-size: 1.3em; - margin: 4px 0 12px; - - b { - color: var(--color-run-list-highlight); - font-weight: normal; - } -} - -.runs-list-card__timestamp { - font-size: 1.3em; -} - -.runs-list-card__notes { - font-size: 1.3em; - padding-top: 24px; - - b { - color: var(--color-run-list-highlight); - font-weight: normal; - } -} - -.runs-list-card__checked { - @extend %runs-list-card--default; - - &--comparing { - fill: var(--color-base-20); - } - - &--active { - fill: colors.$blue-300; - } - - &--selected-first { - @extend %runs-list-card--selected-first; - } - - &--selected-second { - @extend %runs-list-card--selected-second; - } - - &--selected-third { - @extend %runs-list-card--selected-third; - } -} - -.runs-list-card__bookmark { - fill: var(--color-run-list-bookmark); - height: 24px; - margin-left: auto; - opacity: 1; - transition: fill 300ms ease; - width: 24px; - - &:hover { - fill: var(--color-default-alt); - } - - &--stroke { - opacity: 0; - transition: fill 300ms ease; - } -} diff --git a/src/components/experiment-tracking/runs-list-card/runs-list-card.test.js b/src/components/experiment-tracking/runs-list-card/runs-list-card.test.js deleted file mode 100644 index 7df68abf21..0000000000 --- a/src/components/experiment-tracking/runs-list-card/runs-list-card.test.js +++ /dev/null @@ -1,164 +0,0 @@ -import React from 'react'; -import configureMockStore from 'redux-mock-store'; -import RunsListCard from '.'; -import Adapter from '@cfaester/enzyme-adapter-react-18'; -import { configure, mount } from 'enzyme'; -import { HoverStateContext } from '../utils/hover-state-context'; -import { setup } from '../../../utils/state.mock'; -import { runs } from '../../experiment-wrapper/mock-data'; - -configure({ adapter: new Adapter() }); -const mockStore = configureMockStore(); - -const setHoveredElementId = jest.fn(); - -// Setup - -const randomRunId = '2021-10-15T02:24:00.000Z'; -const randomRun = { - id: randomRunId, -}; - -const selectedRunIds = [randomRunId]; - -const savedRun = { - id: '2021-09-08T10:55:36.810Z', -}; - -const nonActiveRun = { - id: '2021-10-15T02:28:00.000Z', -}; - -const mockContextValue = { - setHoveredElementId, - hoveredElementId: ['2021-10-25T02:30:00.000Z'], -}; - -// Tests - -describe('RunsListCard', () => { - it('renders without crashing', () => { - const wrapper = setup.mount( - - - - ); - - expect(wrapper.find('.runs-list-card').length).toBe(1); - expect(wrapper.find('.runs-list-card__title').length).toBe(1); - }); - - it('renders with a bookmark icon', () => { - const wrapper = setup.mount( - - - - ); - - expect(wrapper.find('.runs-list-card__bookmark').length).toBe(2); - }); - - it('does not render with check icon for single view', () => { - const wrapper = setup.mount( - - - - ); - - expect(wrapper.find('.runs-list-card__checked').length).toBe(0); - }); - - it('renders with an unchecked check icon for comparison view', () => { - const wrapper = setup.mount( - - - - ); - - expect(wrapper.find('.runs-list-card__checked--comparing').length).toBe(1); - }); - - it('renders with an inactive bookmark icon', () => { - const wrapper = setup.mount( - - - - ); - - expect(wrapper.find('.runs-list-card__bookmark--stroke').length).toBe(2); - }); - - let store; - beforeEach(() => { - const initialState = { - runsMetadata: { [runs[0].id]: runs[0], [runs[1].id]: runs[1] }, - }; - - store = mockStore(initialState); - }); - - it('renders with an active bookmark icon', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find('.runs-list-card__bookmark--solid').length).toBe(2); - }); - - it('calls a function on click and adds an active class', () => { - const setActive = jest.fn(); - - const wrapper = setup.mount( - - setActive(randomRunId)} - selectedRunIds={selectedRunIds} - store={store} - /> - - ); - const onClick = jest.spyOn(React, 'useState'); - - onClick.mockImplementation((active) => [active, setActive]); - const div = wrapper.find('div').first(); - div.simulate('click'); - - expect(setActive).toBeTruthy(); - expect(wrapper.find('.runs-list-card--active').length).toBe(1); - }); - - it('displays the notes in the runs card when notes matches search value', () => { - const wrapper = setup.mount( - - - - ); - - expect(wrapper.find('.runs-list-card__notes').length).toBe(1); - }); -}); diff --git a/src/components/experiment-tracking/runs-list/index.js b/src/components/experiment-tracking/runs-list/index.js deleted file mode 100644 index ce125c2aa0..0000000000 --- a/src/components/experiment-tracking/runs-list/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import RunsList from './runs-list'; - -export default RunsList; diff --git a/src/components/experiment-tracking/runs-list/runs-list.js b/src/components/experiment-tracking/runs-list/runs-list.js deleted file mode 100644 index 812582f8bb..0000000000 --- a/src/components/experiment-tracking/runs-list/runs-list.js +++ /dev/null @@ -1,130 +0,0 @@ -import React, { useState } from 'react'; -import { connect } from 'react-redux'; -import debounce from 'lodash/debounce'; -import { textMatchesSearch } from '../../../utils/search-utils'; -import SearchList from '../../search-list'; -import Switch from '../../ui/switch'; -import Accordion from '../accordion'; -import RunsListCard from '../runs-list-card'; -import { metricLimit } from '../../../config'; - -import './runs-list.scss'; - -/** - * Return only the runs that match the search text - * @param {Object} runData original set of runs - * @param {String} searchValue Search term - * @return {Object} Grouped nodes - */ -const getFilteredRunList = (runData, searchValue, runsMetadata) => { - // filter the runs that matches the runId - const filteredRuns = runData?.filter( - (run) => - textMatchesSearch(runsMetadata[run.id]?.title || run.id, searchValue) || - textMatchesSearch(runsMetadata[run.id]?.notes || '', searchValue) || - textMatchesSearch(run.gitSha, searchValue) - ); - - return filteredRuns; -}; - -const RunsList = ({ - disableRunSelection, - enableComparisonView, - isDisplayingMetrics, - onRunSelection, - onToggleComparisonView, - runData, - selectedRunIds, - runsMetadata, -}) => { - const [searchValue, updateSearchValue] = useState(''); - - const condensedRunsList = isDisplayingMetrics - ? runData.slice(0, metricLimit) - : runData; - const filteredRunList = getFilteredRunList( - condensedRunsList, - searchValue, - runsMetadata - ); - - const bookmarkedRuns = filteredRunList.filter( - (run) => runsMetadata[run.id] && runsMetadata[run.id].bookmark === true - ); - const unbookmarkedRuns = filteredRunList.filter( - (run) => !runsMetadata[run.id] || !runsMetadata[run.id].bookmark - ); - - return ( - <> -
-
- -
-
- - Compare runs (max. 3) - - -
-
- {bookmarkedRuns.length > 0 ? ( - -
- {bookmarkedRuns.map((data) => ( - - ))} -
-
- ) : null} - {unbookmarkedRuns.length > 0 ? ( - -
- {unbookmarkedRuns.map((data) => ( - - ))} -
-
- ) : null} - - ); -}; - -export const mapStateToProps = (state) => ({ - runsMetadata: state.runsMetadata, -}); - -export default connect(mapStateToProps)(RunsList); diff --git a/src/components/experiment-tracking/runs-list/runs-list.scss b/src/components/experiment-tracking/runs-list/runs-list.scss deleted file mode 100644 index 9b0327e908..0000000000 --- a/src/components/experiment-tracking/runs-list/runs-list.scss +++ /dev/null @@ -1,48 +0,0 @@ -@use '../../../styles/variables' as variables; - -.kui-theme--light { - --header-border-bottom: #{variables.$white-300}; -} - -.kui-theme--dark { - --header-border-bottom: none; -} - -.runs-list-top-wrapper { - position: sticky; - top: 0; - z-index: variables.$zindex-sticky-elements; -} - -.search-bar-wrapper { - background: var(--color-bg-2); - padding-top: 24px; - position: sticky; - top: 0; - z-index: variables.$zindex-sticky-elements; -} - -.runs-list__wrapper { - width: 100%; -} - -.runs-list__accordion-header { - background-color: var(--color-bg-2); - border-bottom: 1px solid var(--header-border-bottom); - padding: 0.8em 3.5em 0.8em 3em; -} - -.compare-switch-wrapper { - align-items: baseline; - background: var(--color-bg-2); - display: flex; - justify-content: space-between; - padding: 3.5em 3.5em 1.2em 3em; - position: sticky; - top: 64px; - z-index: variables.$zindex-sticky-elements; -} - -.compare-switch-wrapper__text { - font-size: 14px; -} diff --git a/src/components/experiment-tracking/runs-list/runs-list.test.js b/src/components/experiment-tracking/runs-list/runs-list.test.js deleted file mode 100644 index e2ec977375..0000000000 --- a/src/components/experiment-tracking/runs-list/runs-list.test.js +++ /dev/null @@ -1,94 +0,0 @@ -import React from 'react'; -import configureMockStore from 'redux-mock-store'; -import RunsList from '.'; -import { ApolloProvider } from '@apollo/client'; -import { client } from '../../../apollo/config'; -import { setup } from '../../../utils/state.mock'; -import { HoverStateContext } from '../utils/hover-state-context'; -import { runs } from '../../experiment-wrapper/mock-data'; - -const runDataList = [ - { - id: new Date('October 15, 2021 03:24:00').toISOString(), - }, - { - id: new Date('October 15, 2021 03:26:00').toISOString(), - }, - { - id: new Date('October 15, 2021 03:29:00').toISOString(), - }, - { - id: new Date('October 15, 2021 03:32:00').toISOString(), - }, -]; - -const mockStore = configureMockStore(); -const setHoveredElementId = jest.fn(); -const mockContextValue = { - setHoveredElementId, - hoveredElementId: [new Date('October 15, 2021 03:35:00').toISOString()], -}; - -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useLocation: () => ({ - pathname: 'localhost:3000/', - }), -})); - -describe('RunsListCard', () => { - let store; - beforeEach(() => { - const initialState = { - runsMetadata: { [runs[0].id]: runs[0], [runs[1].id]: runs[1] }, - }; - - store = mockStore(initialState); - }); - - it('renders without crashing', () => { - const wrapper = setup.mount( - - - - ); - - expect(wrapper.find('.runs-list__wrapper').length).toBe(1); - }); - - it('renders the search bar', () => { - const wrapper = setup.mount( - - - - ); - - expect(wrapper.find('.search-bar-wrapper').length).toBe(1); - }); - - it('displays the right search amount of cards for the search', () => { - const stateSetter = jest.fn(); - jest - .spyOn(React, 'useState') - //Simulate that searchValue state value - .mockImplementation((stateValue) => [(stateValue = 'run'), stateSetter]); - - const wrapper = setup.mount( - - - - - - ); - - expect(wrapper.find('.runs-list-card').length).toBe(4); - }); -}); diff --git a/src/components/experiment-tracking/select-dropdown/index.js b/src/components/experiment-tracking/select-dropdown/index.js deleted file mode 100644 index 2671a69e50..0000000000 --- a/src/components/experiment-tracking/select-dropdown/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import SelectDropdown from './select-dropdown'; - -export default SelectDropdown; diff --git a/src/components/experiment-tracking/select-dropdown/select-dropdown.js b/src/components/experiment-tracking/select-dropdown/select-dropdown.js deleted file mode 100644 index d56822be57..0000000000 --- a/src/components/experiment-tracking/select-dropdown/select-dropdown.js +++ /dev/null @@ -1,87 +0,0 @@ -import React, { useState, useEffect, useCallback } from 'react'; - -import Dropdown from '../../ui/dropdown'; - -import './select-dropdown.scss'; - -const CheckboxOption = ({ text, selectedValues, onChange }) => { - return ( - - ); -}; - -const SelectDropdown = ({ - dropdownValues, - onChange, - selectedDropdownValues, -}) => { - const [selected, setSelected] = useState(selectedDropdownValues); - const [haveSelectedValues, setHaveSelectedValues] = useState(false); - - useEffect(() => { - if (selectedDropdownValues) { - setSelected(selectedDropdownValues); - } - }, [selectedDropdownValues]); - - const onSelectedHandler = useCallback( - (value) => { - setHaveSelectedValues(true); - - if (selected.includes(value)) { - setSelected(selected.filter((each) => each !== value)); - } else { - setSelected([...selected, value]); - } - }, - [selected] - ); - - return ( -
- { - setSelected(selectedDropdownValues); - setHaveSelectedValues(false); - }} - showCancelApplyBtns - onApplyAndClose={() => { - onChange(selected); - setHaveSelectedValues(false); - }} - onCancel={() => { - setSelected(selectedDropdownValues); - setHaveSelectedValues(false); - }} - haveSelectedValues={haveSelectedValues} - defaultText={`Metrics ${selected ? selected.length : 0}/${ - dropdownValues ? dropdownValues.length : 0 - }`} - dataTest={'experiments-metrics-select-dropdown'} - > -
Metrics
- {dropdownValues && - dropdownValues.map((text, i) => ( - - ))} -
-
- ); -}; - -export default SelectDropdown; diff --git a/src/components/experiment-tracking/select-dropdown/select-dropdown.scss b/src/components/experiment-tracking/select-dropdown/select-dropdown.scss deleted file mode 100644 index 949ae8d4a2..0000000000 --- a/src/components/experiment-tracking/select-dropdown/select-dropdown.scss +++ /dev/null @@ -1,74 +0,0 @@ -@use '../../../styles/variables' as variables; - -.kui-theme--light { - --select-dropdown-bg-hover: #{variables.$white-600}; - --select-dropdown-bg: #{variables.$grey-100}; -} - -.kui-theme--dark { - --select-dropdown-bg-hover: #{variables.$slate-500}; - --select-dropdown-bg: #{variables.$slate-700}; -} - -.select-dropdown { - // apply scroll - section { - height: 479px; - overflow: hidden; - } - - .dropdown__label { - background: var(--select-dropdown-bg); - } - - // overide the fix height and width option from the Dropdown component - .dropdown__options { - box-shadow: none; - max-height: 479px; - right: 0; - width: 284px; - } -} - -.select-dropdown__title { - font-size: 16px; - font-weight: 600; - margin: 28px 28px 32px 24px; - opacity: 0.55; -} - -.select-dropdown__checkbox { - align-items: center; - cursor: pointer; - display: flex; - height: 32px; - justify-content: space-between; - padding: 0 24px; - position: relative; - - .select-dropdown__checkbox-text { - font-size: 14px; - line-height: 20px; - max-width: 80%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } -} - -.select-dropdown__checkbox:hover { - background: var(--select-dropdown-bg-hover); -} - -input[type='checkbox'] { - appearance: none; - border: 2px solid #737373; - cursor: pointer; - height: 8px; - width: 8px; -} - -input[type='checkbox']:checked { - background: variables.$blue-300; - border-color: variables.$blue-300; -} diff --git a/src/components/experiment-tracking/select-dropdown/select-dropdown.test.js b/src/components/experiment-tracking/select-dropdown/select-dropdown.test.js deleted file mode 100644 index 95033c9a51..0000000000 --- a/src/components/experiment-tracking/select-dropdown/select-dropdown.test.js +++ /dev/null @@ -1,52 +0,0 @@ -import React from 'react'; -import sinon from 'sinon'; -import { shallow, mount } from 'enzyme'; -import SelectDropdown from '.'; - -const mockData = { - dropdownValues: [1, 2, 3, 4, 5], - onChange: sinon.spy(() => {}), - selectedDropdownValues: [1, 2, 3], -}; - -describe('SelectDropdown', () => { - it('renders without crashing', () => { - const wrapper = shallow( - - ); - - expect(wrapper.find('.select-dropdown').length).toBe(1); - }); - - it('renders the correct amount of checkbox', () => { - const wrapper = mount( - - ); - - expect(wrapper.find('.select-dropdown__checkbox').length).toBe( - mockData.dropdownValues.length - ); - }); - - it('renders the correct text', () => { - const wrapper = mount( - - ); - - expect(wrapper.find('.dropdown__label').text()).toEqual( - `Metrics ${mockData.selectedDropdownValues.length}/${mockData.dropdownValues.length}` - ); - }); -}); diff --git a/src/components/experiment-tracking/time-series/index.js b/src/components/experiment-tracking/time-series/index.js deleted file mode 100644 index 1e813850e0..0000000000 --- a/src/components/experiment-tracking/time-series/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import TimeSeries from './time-series'; - -export default TimeSeries; diff --git a/src/components/experiment-tracking/time-series/time-series.js b/src/components/experiment-tracking/time-series/time-series.js deleted file mode 100644 index cb0d044b13..0000000000 --- a/src/components/experiment-tracking/time-series/time-series.js +++ /dev/null @@ -1,391 +0,0 @@ -import React, { useContext, useEffect, useState } from 'react'; -import classnames from 'classnames'; -import { formatTimestamp } from '../../../utils/date-utils'; -import { usePrevious } from '../../../utils/hooks'; -import { HoverStateContext } from '../utils/hover-state-context'; -import { - ExperimentTrackingTooltip, - tooltipDefaultProps, -} from '../tooltip/tooltip'; -import { getTooltipPosition } from '../tooltip/get-tooltip-position'; -import * as d3 from 'd3'; - -import './time-series.scss'; - -export const getSelectedOrderedData = (runData, selectedRuns) => { - return runData - .filter(([key, _]) => selectedRuns.includes(key)) - .sort((a, b) => { - // We need to sort the selected data to match the order of selectedRuns. - // If we didn't, the highlighted runs would switch colors unnecessarily. - return selectedRuns.indexOf(a[0]) - selectedRuns.indexOf(b[0]); - }) - .map(([key, value], i) => [new Date(formatTimestamp(key)), value]); -}; - -const chartBuffer = 0.02; -const height = 150; -const margin = { top: 20, right: 10, bottom: 80, left: 35 }; -const yScales = {}; - -export const TimeSeries = ({ - chartWidth, - metricsData, - selectedRuns, - sidebarVisible, -}) => { - const previouslySelectedRuns = usePrevious(selectedRuns); - const [showTooltip, setShowTooltip] = useState(tooltipDefaultProps); - const [rangeSelection, setRangeSelection] = useState(undefined); - - const { hoveredElementId, setHoveredElementId } = - useContext(HoverStateContext); - - const defaultChartWidth = isNaN(chartWidth) ? 100 : chartWidth; - - const selectedMarkerRotate = [45, 0, 0]; - const selectedMarkerShape = [ - d3.symbolSquare, - d3.symbolCircle, - d3.symbolTriangle, - ]; - - const hoveredElementDate = - hoveredElementId && new Date(formatTimestamp(hoveredElementId)); - - const hoveredValues = hoveredElementId && metricsData.runs[hoveredElementId]; - - const metricKeys = Object.keys(metricsData.metrics); - const metricData = Object.entries(metricsData.metrics); - const runKeys = Object.keys(metricsData.runs); - const runData = Object.entries(metricsData.runs); - - const parsedData = runData.map(([key, value]) => [ - new Date(formatTimestamp(key)), - value, - ]); - const parsedDates = parsedData.map(([key, _]) => key); - - const diffDays = parseInt( - (d3.max(parsedDates) - d3.min(parsedDates)) / (1000 * 60 * 60 * 24), - 10 - ); - const minDate = new Date(d3.min(parsedDates)); - minDate.setDate(minDate.getDate() - diffDays * chartBuffer); - const maxDate = new Date(d3.max(parsedDates)); - maxDate.setDate(maxDate.getDate() + diffDays * chartBuffer); - - const selectedData = runData - .filter(([key, _]) => selectedRuns.includes(key)) - .map(([key, value], i) => [new Date(formatTimestamp(key)), value]); - - metricData.map( - ([_, value], i) => - (yScales[i] = d3 - .scaleLinear() - .domain([ - Math.min(...value) - Math.min(...value) * chartBuffer, - Math.max(...value) + Math.max(...value) * chartBuffer, - ]) - .range([height, 0])) - ); - - const xScale = d3 - .scaleTime() - .domain([minDate, maxDate]) - .range([0, defaultChartWidth]); - - if (rangeSelection) { - xScale.domain(rangeSelection); - } - - const handleMouseOverLine = (e, key) => { - setHoveredElementId(key); - - if (e) { - const parsedDate = new Date(formatTimestamp(key)); - const { x, y, direction } = getTooltipPosition(e, sidebarVisible); - - setShowTooltip({ - content: { - label1: 'Run name', - value1: key, - label2: 'Date', - value2: parsedDate.toLocaleDateString('default', { - day: 'numeric', - month: 'long', - year: 'numeric', - }), - }, - direction, - position: { x, y }, - visible: true, - }); - } - }; - - const handleMouseOutLine = () => { - setHoveredElementId(null); - setShowTooltip(tooltipDefaultProps); - }; - - useEffect(() => { - d3.selectAll(`line[id="${hoveredElementId}"]`).raise(); - }, [hoveredElementId]); - - if (previouslySelectedRuns !== selectedRuns) { - if (rangeSelection) { - setRangeSelection(undefined); - } - } - - return ( -
- - {metricKeys.map((metricName, metricIndex) => { - const metricValues = Object.values(metricsData.metrics)[metricIndex]; - - const getXAxis = (ref) => { - if (rangeSelection) { - d3.select(ref) - .transition() - .duration(1000) - .call(d3.axisBottom(xScale).tickSizeOuter(0)); - } else { - d3.select(ref).call(d3.axisBottom(xScale).tickSizeOuter(0)); - } - }; - - const getYAxis = (ref) => { - d3.select(ref).call( - d3 - .axisLeft(yScales[metricIndex]) - .tickSizeOuter(0) - .tickFormat((x) => `${x.toFixed(2)}`) - ); - }; - - const lineGenerator = d3.line().defined(function (d) { - return d !== null; - }); - - const linePath = (data) => { - let points = data.map((x, i) => { - if (x !== null) { - return [xScale(parsedDates[i]), yScales[metricIndex](x)]; - } else { - return null; - } - }); - - return lineGenerator(points); - }; - - const trendLinePath = (data) => { - let points = data.map(([key, value]) => { - if (value !== null) { - return [xScale(key), yScales[metricIndex](value[metricIndex])]; - } else { - return null; - } - }); - return d3.line()(points); - }; - - const brush = d3 - .brushX() - .extent([ - [0, 0], - [defaultChartWidth, height], - ]) - .on('end', (e) => { - if (e.selection) { - const indexSelection = e.selection.map(xScale.invert); - setRangeSelection(indexSelection); - d3.selectAll('.time-series__brush').call(brush.move, null); - } - }); - - d3.selectAll('.time-series__brush').call(brush); - - const resetXScale = () => setRangeSelection(undefined); - - return ( - -
{metricName}
- - - - - - - - - - - - - - - - - - - - - - value - - - - - - {parsedData.map(([key, _], index) => ( - 1, - })} - id={runKeys[index]} - key={key + index} - x1={xScale(key)} - y1={0} - x2={xScale(key)} - y2={height} - onMouseOver={(e) => - handleMouseOverLine(e, runKeys[index]) - } - onMouseLeave={handleMouseOutLine} - /> - ))} - - - {hoveredValues && ( - - {hoveredValues.map((value, index) => { - if (metricIndex === index) { - return ( - - - - - - {value?.toFixed(3)} - - - - ); - } else { - return null; - } - })} - ; - - )} - - 1, - })} - clipPath="url(#clip)" - > - - - - - {getSelectedOrderedData(runData, selectedRuns).map( - ([key, value], index) => ( - - - - {value[metricIndex]?.toFixed(3)} - - - - ) - )} - - - - - - - -
- ); - })} -
- ); -}; diff --git a/src/components/experiment-tracking/time-series/time-series.scss b/src/components/experiment-tracking/time-series/time-series.scss deleted file mode 100644 index cf8b0d8600..0000000000 --- a/src/components/experiment-tracking/time-series/time-series.scss +++ /dev/null @@ -1,131 +0,0 @@ -@use '../../../styles/variables' as colors; - -.time-series { - flex: 1 1 auto; - font-family: Inter, sans-serif; - margin: 0 4em 0 0; - - > svg:last-of-type { - margin-bottom: 5em; - } -} - -.time-series .text { - font-size: 12px; -} - -.time-series__metric-name { - font-size: 1.4em; - color: var(--color-metrics-plot-text-bold); - line-height: 20px; -} - -.time-series__axis-label { - fill: var(--color-metrics-plot-axis-ends); - font-size: 12px; - transform: rotate(-90deg); -} - -.time-series__metric-line { - fill: none; - stroke: var(--color-metrics-plot-time-series-metric-line); - - &--blend { - stroke-opacity: 0.4; - } -} - -.time-series__run-line { - cursor: pointer; - stroke: var(--color-metrics-plot-time-series-run-line); - - &--hovered { - stroke: var(--color-metrics-plot-time-series-run-line-hovered); - } - - &--blend { - stroke-opacity: 0.55; - } - - &--selected-0 { - stroke: colors.$purple-300; - } - - &--selected-1 { - stroke: colors.$yellow-300; - } - - &--selected-2 { - stroke: colors.$green-300; - } -} - -.time-series__marker { - &--selected-0 { - fill: transparent; - stroke: colors.$purple-300; - } - - &--selected-1 { - fill: transparent; - stroke: colors.$yellow-0; - } - - &--selected-2 { - fill: transparent; - stroke: colors.$green-0; - } -} - -.time-series { - .tick text { - fill: var(--color-metrics-plot-axis-ends); - font-size: 12px; - } - - .tick line { - stroke: var(--color-metrics-plot-time-series-axis); - } -} - -.time-series__metric-axis .tick, -.time-series__metric-axis-dual .tick { - opacity: 0; -} - -.time-series__metric-axis { - .tick:nth-last-child(2) { - opacity: 1; - } - - .tick:nth-child(3) { - opacity: 1; - } -} - -.time-series__trend-line { - stroke: var(--color-metrics-plot-time-series-dotted-line); - stroke-dasharray: 4; - fill: none; -} - -.time-series__hovered-line { - stroke: var(--color-metrics-plot-time-series-dotted-line); - stroke-dasharray: 4; -} - -.time-series__tick-line { - stroke: var(--color-metrics-plot-time-series-run-line-hovered); -} - -.time-series__tick-text { - fill: var(--color-metrics-plot-axis-ends); - font-size: 12px; - text-anchor: end; - transform: translate(-10px, -4px); -} - -.time-series__brush .selection { - fill: colors.$ocean-600; - fill-opacity: 0.4; -} diff --git a/src/components/experiment-tracking/time-series/time-series.test.js b/src/components/experiment-tracking/time-series/time-series.test.js deleted file mode 100644 index ad352e8190..0000000000 --- a/src/components/experiment-tracking/time-series/time-series.test.js +++ /dev/null @@ -1,210 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; - -import { getSelectedOrderedData, TimeSeries } from './time-series'; -import { HoverStateContext } from '../utils/hover-state-context'; -import { formatTimestamp } from '../../../utils/date-utils'; -import { data, selectedRuns, oneSelectedRun } from '../mock-data'; - -const metricsKeys = Object.keys(data.metrics); - -const runKeys = Object.keys(data.runs); -const runData = Object.entries(data.runs); - -const hoveredElement = 0; - -describe('TimeSeries', () => { - const mockContextValue = { - hoveredElementId: runKeys[hoveredElement], - setHoveredElementId: jest.fn(), - }; - - const wrapper = mount( - - - - ); - - it('renders without crashing', () => { - expect(wrapper.find('.time-series').length).toBe(1); - }); - - it('constructs an svg for each metric from the data', () => { - const svg = wrapper.find('.time-series').find('svg'); - expect(svg.length).toBe(metricsKeys.length); - }); - - it('show tooltip onHover - runLine', () => { - wrapper - .find('.time-series__run-lines') - .find('line') - .at(hoveredElement) - .simulate('mouseover'); - - const tooltip = wrapper.find('.time-series').find('.tooltip'); - expect(tooltip.hasClass('tooltip--show')).toBe(true); - }); -}); - -describe('TimeSeries with multiple selected runs and hovered run', () => { - const mockContextValue = { - hoveredElementId: runKeys[hoveredElement], - setHoveredElementId: jest.fn(), - }; - - const wrapper = mount( - - - - ) - .find('.time-series') - .find('svg') - .find('g'); - - it('draw X, Y and dual axes for each metric chart', () => { - const xAxis = wrapper.find('.time-series__runs-axis'); - expect(xAxis.length).toBe(metricsKeys.length); - - const yAxis = wrapper.find('.time-series__metric-axis'); - expect(yAxis.length).toBe(metricsKeys.length); - - const dualAxis = wrapper.find('.time-series__metric-axis-dual'); - expect(dualAxis.length).toBe(metricsKeys.length); - }); - - it('draw metricLine for each metric', () => { - const metricLine = wrapper.find('.time-series__metric-line'); - expect(metricLine.length).toBe(metricsKeys.length); - }); - - it('draw runLines for each metric', () => { - const runLines = wrapper - .find('.time-series__run-lines') - .find('.time-series__run-line'); - expect(runLines.length).toBe(runData.length * metricsKeys.length); - }); - - it('applies "time-series__run-line--hovered" class to the correct runLine on mouseover', () => { - const runLine = wrapper - .find('.time-series__run-lines') - .find('line') - .at(hoveredElement); - - runData.forEach((_, index) => { - if (hoveredElement === index) { - expect( - runLine.at(index).hasClass('time-series__run-line--hovered') - ).toBe(true); - } - }); - }); - - it('selected group is returend in the correct order', () => { - const selectedGroupLine = wrapper - .find('.time-series__selected-group') - .find('line'); - - getSelectedOrderedData(runData, selectedRuns).forEach(([key, _], index) => { - const parsedSelectedDate = new Date(formatTimestamp(selectedRuns[index])); - - if (parsedSelectedDate.getTime() === key.getTime()) { - expect( - selectedGroupLine - .at(index) - .hasClass(`time-series__run-line--selected-${index}`) - ).toBe(true); - } - }); - }); - - it('on double click reset to default zoom scale', () => { - const setRangeSelection = jest.fn(); - const brushContainer = wrapper.find('.time-series__brush').at(0); - const onDbClick = jest.spyOn(React, 'useState'); - - onDbClick.mockImplementation((rangeSelection) => [ - rangeSelection, - setRangeSelection, - ]); - brushContainer.simulate('dblclick'); - - expect(setRangeSelection).toBeTruthy(); - expect(brushContainer.length).toBe(1); - }); -}); - -describe('TimeSeries with only one selected run and no hovered run', () => { - const mockContextValue = { - hoveredElementId: null, - setHoveredElementId: jest.fn(), - }; - - const wrapper = mount( - - - - ) - .find('.time-series') - .find('svg') - .find('g'); - - it('Class "time-series__run-line--blend" is not applied when there is only one selected run and no hovered element', () => { - const runLine = wrapper.find('.time-series__run-lines').find('line'); - - runData.forEach((_, index) => { - expect(runLine.at(index).hasClass('time-series__run-line--blend')).toBe( - false - ); - }); - }); - - it('Class "time-series__metric-line--blend" is not applied when there is only one selected run and no hovered element', () => { - const metricLine = wrapper.find('.time-series__metric-line'); - - metricsKeys.forEach((_, index) => { - expect( - metricLine.at(index).hasClass('time-series__metric-line--blend') - ).toBe(false); - }); - }); -}); - -describe('TimeSeries with only one selected run and hovered run', () => { - const mockContextValue = { - hoveredElementId: runKeys[hoveredElement], - setHoveredElementId: jest.fn(), - }; - - const wrapper = mount( - - - - ) - .find('.time-series') - .find('svg') - .find('g'); - - it('Class "time-series__run-line--blend" is applied when there is only one selected run and hovered element', () => { - const runLine = wrapper.find('.time-series__run-lines').find('line'); - - runData.forEach((_, index) => { - if (hoveredElement === index) { - expect(runLine.at(index).hasClass('time-series__run-line--blend')).toBe( - true - ); - } - }); - }); - - it('Class "time-series__metric-line--blend" is applied when there is only one selected run and hovered element', () => { - const metricLine = wrapper.find('.time-series__metric-line'); - - metricsKeys.forEach((_, index) => { - if (hoveredElement === index) { - expect( - metricLine.at(index).hasClass('time-series__metric-line--blend') - ).toBe(true); - } - }); - }); -}); diff --git a/src/components/experiment-tracking/tooltip/get-tooltip-position.js b/src/components/experiment-tracking/tooltip/get-tooltip-position.js deleted file mode 100644 index b8fd735815..0000000000 --- a/src/components/experiment-tracking/tooltip/get-tooltip-position.js +++ /dev/null @@ -1,24 +0,0 @@ -import { sidebarWidth } from '../../../config'; - -const tooltipMaxWidth = 300; -const tooltipLeftGap = 85; -const tooltipRightGap = 70; -const tooltipTopGap = 150; - -export const getTooltipPosition = (e, sidebarVisible) => { - const xCoordsAdjustment = sidebarVisible ? 0 : sidebarWidth.pipelineUI; - const y = e.clientY - tooltipTopGap; - let x, direction; - - if (window.innerWidth - e.clientX > tooltipMaxWidth) { - x = e.clientX - sidebarWidth.open - tooltipRightGap; - direction = 'right'; - } else { - x = e.clientX - sidebarWidth.open - sidebarWidth.open / 2 - tooltipLeftGap; - direction = 'left'; - } - - x = x + xCoordsAdjustment; - - return { x, y, direction }; -}; diff --git a/src/components/experiment-tracking/tooltip/tooltip.js b/src/components/experiment-tracking/tooltip/tooltip.js deleted file mode 100644 index 1dc314f7bc..0000000000 --- a/src/components/experiment-tracking/tooltip/tooltip.js +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; -import classnames from 'classnames'; - -import './tooltip.scss'; - -export const tooltipDefaultProps = { - content: { label1: '', value1: '', label2: '', value2: '' }, - direction: 'right', - position: { x: -500, y: -500 }, - visible: false, -}; - -export const ExperimentTrackingTooltip = ({ - content = tooltipDefaultProps.content, - direction = tooltipDefaultProps.direction, - position = tooltipDefaultProps.position, - visible = tooltipDefaultProps.visible, -}) => { - return ( -
- -

{`${content?.label1}:`}

-

{content?.value1}

- -
-

{`${content?.label2}:`}

-

{content?.value2}

-
- ); -}; diff --git a/src/components/experiment-tracking/tooltip/tooltip.scss b/src/components/experiment-tracking/tooltip/tooltip.scss deleted file mode 100644 index 2224aa7637..0000000000 --- a/src/components/experiment-tracking/tooltip/tooltip.scss +++ /dev/null @@ -1,98 +0,0 @@ -@use '../../../styles/variables' as colors; - -@mixin fade-in($waitTime) { - animation: wait #{$waitTime}, fade-in 500ms #{$waitTime}; -} - -@keyframes wait { - 0% { - opacity: 0; - } - - 100% { - opacity: 0; - } -} - -@keyframes fade-in { - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -} - -$triangle-size: 10px; - -.tooltip { - background: var(--color-bg-alt); - display: flex; - flex-direction: column; - opacity: 0; - padding: 10px 30px 10px 10px; - position: absolute; -} - -.tooltip--show { - @include fade-in('700ms'); - - animation-fill-mode: forwards; -} - -.tooltip-arrow { - display: inline-block; - height: 0; - left: 1px; - margin-right: 1.6em; - margin-top: -1.2em; - position: absolute; - top: 22px; - white-space: nowrap; - width: 0; -} - -.tooltip-arrow--right { - &::before { - border-left: $triangle-size solid transparent; - border-top: $triangle-size solid var(--color-bg-alt); - content: ''; - height: 0; - left: -$triangle-size + 0.5; - position: absolute; - top: calc(50% - #{$triangle-size}); - width: 0; - } -} - -.tooltip-arrow--left { - &::before { - border-right: $triangle-size solid transparent; - border-top: $triangle-size solid var(--color-bg-alt); - content: ''; - height: 0; - position: absolute; - right: -225.5px; - top: calc(50% - #{$triangle-size}); - width: 0; - } -} - -.tooltip-label, -.tooltip-value { - font-size: 12px; - font-weight: 400; - margin: 0; - overflow: hidden; - overflow-wrap: break-word; - width: 180px; -} - -.tooltip-label { - color: var(--color-metrics-plot-tooltip-label); -} - -.tooltip-value { - color: var(--color-metrics-plot-tooltip-value); -} diff --git a/src/components/experiment-tracking/utils/hover-state-context.js b/src/components/experiment-tracking/utils/hover-state-context.js deleted file mode 100644 index dbf8a324da..0000000000 --- a/src/components/experiment-tracking/utils/hover-state-context.js +++ /dev/null @@ -1,22 +0,0 @@ -import React, { createContext, useState } from 'react'; - -export const HoverStateContext = createContext(null); - -/** - * Provides a way to manage state for hovered elements between - * RunListCard and metrics plots components - */ -export const HoverStateContextProvider = ({ children }) => { - const [hoveredElementId, setHoveredElementId] = useState(null); - - return ( - - {children} - - ); -}; diff --git a/src/components/experiment-warning/experiment-warning.js b/src/components/experiment-warning/experiment-warning.js deleted file mode 100644 index 603b345853..0000000000 --- a/src/components/experiment-warning/experiment-warning.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; - -import './experiment-warning.scss'; - -const ExperimentWarning = ({ title, subTitle }) => ( -
-

{title}

-

{subTitle}

-
-); - -export default ExperimentWarning; diff --git a/src/components/experiment-warning/experiment-warning.scss b/src/components/experiment-warning/experiment-warning.scss deleted file mode 100644 index 8729cf31ae..0000000000 --- a/src/components/experiment-warning/experiment-warning.scss +++ /dev/null @@ -1,24 +0,0 @@ -.experiment-warning__wrapper { - align-items: center; - display: flex; - flex-direction: column; - height: 70%; - justify-content: center; - width: 85%; - font-size: 16px; -} - -.experiment-warning__title { - font-size: 2.5em; - font-weight: 400; - line-height: 1.75em; - margin: 0; - margin-bottom: 10px; -} - -.experiment-warning__subtitle { - font-size: 1em; - font-weight: 400; - line-height: 1.25em; - margin: 0; -} diff --git a/src/components/experiment-warning/index.js b/src/components/experiment-warning/index.js deleted file mode 100644 index af3e7a79e0..0000000000 --- a/src/components/experiment-warning/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import ExperimentWarning from './experiment-warning'; - -export default ExperimentWarning; diff --git a/src/components/experiment-wrapper/experiment-wrapper.js b/src/components/experiment-wrapper/experiment-wrapper.js deleted file mode 100644 index ce1195e7c1..0000000000 --- a/src/components/experiment-wrapper/experiment-wrapper.js +++ /dev/null @@ -1,450 +0,0 @@ -import React, { useEffect, useState, useCallback } from 'react'; -import { useLocation } from 'react-router-dom'; -import { Transition } from 'react-transition-group'; -import { useApolloQuery } from '../../apollo/utils'; -import { connect } from 'react-redux'; -import { GET_RUNS, GET_RUN_DATA } from '../../apollo/queries'; -import Button from '../ui/button'; -import Details from '../experiment-tracking/details'; -import Sidebar from '../sidebar'; -import { HoverStateContextProvider } from '../experiment-tracking/utils/hover-state-context'; -import { useGeneratePathnameForExperimentTracking } from '../../utils/hooks/use-generate-pathname'; -import { - errorMessages, - linkToFlowchartInitialVal, - localStorageFlowchartLink, - params, - tabLabels, - PACKAGE_KEDRO_DATASETS, -} from '../../config'; -import { findMatchedPath } from '../../utils/match-path'; -import { fetchMetadata } from '../../utils'; -import { saveLocalStorage, loadLocalStorage } from '../../store/helpers'; - -import './experiment-wrapper.scss'; - -const MAX_NUMBER_COMPARISONS = 2; // 0-based, so three. - -const defaultStyle = { - opacity: 0, - transition: `opacity .5s ease-in-out`, -}; - -const transitionStyles = { - entering: { opacity: 1 }, - entered: { opacity: 1 }, - exiting: { opacity: 0 }, - exited: { opacity: 0 }, -}; - -const ExperimentWrapper = ({ theme, runsMetadata }) => { - const [disableRunSelection, setDisableRunSelection] = useState(false); - const [enableShowChanges, setEnableShowChanges] = useState(true); - const [isSidebarVisible, setIsSidebarVisible] = useState(true); - const [pinnedRun, setPinnedRun] = useState(); - const [selectedRunData, setSelectedRunData] = useState(null); - const [showRunDetailsModal, setShowRunDetailsModal] = useState(false); - const [showRunExportModal, setShowRunExportModal] = useState(false); - const [showRunPlotsModal, setShowRunPlotsModal] = useState(false); - const [newRunAdded, setNewRunAdded] = useState(false); - const [isDisplayingMetrics, setIsDisplayingMetrics] = useState(false); - - const [enableComparisonView, setEnableComparisonView] = useState(false); - const [selectedRunIds, setSelectedRunIds] = useState([]); - const [activeTab, setActiveTab] = useState(tabLabels[0]); - const [errorMessage, setErrorMessage] = useState({}); - const [invalidUrl, setInvalidUrl] = useState(false); - const [usedNavigationBtn, setUsedNavigationBtn] = useState(false); - const [isKedroDatasetsCompatible, setIsKedroDatasetsCompatible] = - useState(false); - - const { pathname, search } = useLocation(); - const searchParams = new URLSearchParams(search); - - const { - matchedExperimentTrackingMainPage, - matchedSelectedView, - matchedSelectedRuns, - } = findMatchedPath(pathname, search); - - const { toExperimentTrackingPath, toSelectedRunsPath } = - useGeneratePathnameForExperimentTracking(); - - // Fetch all runs. - const { data, loading } = useApolloQuery(GET_RUNS); - - // Fetch all data for selected runs. - const { - data: { runMetadata = [], plots = [], metrics = [], JSONData = [] } = [], - error: runDataError, - loading: isRunDataLoading, - } = useApolloQuery(GET_RUN_DATA, { - skip: selectedRunIds.length === 0, - variables: { runIds: selectedRunIds, showDiff: true }, - }); - - let runTrackingData = {}; - - if (plots.length > 0) { - runTrackingData['Plots'] = plots; - } else { - runTrackingData['Plots'] = []; - } - - if (metrics.length > 0) { - runTrackingData['Metrics'] = metrics; - } - - if (JSONData.length > 0) { - runTrackingData['JSON Data'] = JSONData; - } - - const onRunSelection = (id) => { - if (enableComparisonView) { - if (selectedRunIds.includes(id)) { - if (selectedRunIds.length === 1) { - return; - } - const selectedIds = selectedRunIds.filter((run) => run !== id); - - setSelectedRunIds(selectedIds); - toSelectedRunsPath(selectedIds, activeTab, enableComparisonView); - - setNewRunAdded(false); - } else { - setSelectedRunIds([...selectedRunIds, id]); - setNewRunAdded(true); - toSelectedRunsPath( - [...selectedRunIds, id], - activeTab, - enableComparisonView - ); - } - } else { - if (selectedRunIds.includes(id)) { - return; - } else { - setSelectedRunIds([id]); - toSelectedRunsPath([id], activeTab, enableComparisonView); - } - } - }; - - const onToggleComparisonView = () => { - setEnableComparisonView(!enableComparisonView); - - if (selectedRunIds.length === 1) { - toSelectedRunsPath( - selectedRunIds.slice(0, 1), - activeTab, - !enableComparisonView - ); - } - - if (enableComparisonView && selectedRunIds.length > 1) { - setSelectedRunIds(selectedRunIds.slice(0, 1)); - toSelectedRunsPath( - selectedRunIds.slice(0, 1), - activeTab, - !enableComparisonView - ); - } - }; - - const onTabChangeHandler = (tab) => { - setActiveTab(tab); - toSelectedRunsPath(selectedRunIds, tab, enableComparisonView); - }; - - const redirectToSelectedRuns = () => { - const runIds = searchParams.get(params.run).split(','); - const allRunIds = data?.runsList.map((run) => run.id); - const notFoundIds = runIds.find((id) => !allRunIds?.includes(id)); - - if (notFoundIds) { - setErrorMessage(errorMessages.runIds); - setInvalidUrl(true); - } else { - const isComparison = - runIds.length > 1 - ? true - : searchParams.get(params.comparisonMode) === 'true'; - - setSelectedRunIds(runIds); - setEnableComparisonView(isComparison); - if (tabLabels.includes(searchParams.get(params.view))) { - setActiveTab(searchParams.get(params.view)); - } - } - }; - - const redirectToSelectedView = () => { - const latestRun = data.runsList.map((run) => run.id).slice(0, 1); - - setSelectedRunIds(latestRun); - setEnableComparisonView(false); - if (tabLabels.includes(searchParams.get(params.view))) { - setActiveTab(searchParams.get(params.view)); - } - }; - - const handlePopState = useCallback(() => { - setUsedNavigationBtn((usedNavigationBtn) => !usedNavigationBtn); - }, []); - - useEffect(() => { - async function checkPackageCompatibility() { - try { - const request = await fetchMetadata(); - const response = await request.json(); - - if (request.ok) { - const packageCompatibilityInfo = response.package_compatibilities; - const kedroDatasetsPackage = packageCompatibilityInfo.find( - (pckg) => pckg.package_name === PACKAGE_KEDRO_DATASETS - ); - setIsKedroDatasetsCompatible(kedroDatasetsPackage.is_compatible); - } - } catch (error) { - console.error('metadata fetch error: ', error); - } - } - - checkPackageCompatibility(); - }, []); - - useEffect(() => { - const showGoBackBtnFromStorage = loadLocalStorage( - localStorageFlowchartLink - ).showGoBackBtn; - - if (showGoBackBtnFromStorage) { - saveLocalStorage(localStorageFlowchartLink, linkToFlowchartInitialVal); - } - - window.addEventListener('popstate', handlePopState); - - return () => { - window.removeEventListener('popstate', handlePopState); - }; - }, [handlePopState]); - - useEffect(() => { - if (data) { - /** - * To display a generic error message when the URL is not matched any path at all - */ - if ( - !matchedExperimentTrackingMainPage && - !matchedSelectedRuns && - !matchedSelectedView - ) { - setErrorMessage(errorMessages.experimentTracking); - setInvalidUrl(true); - } - - if (matchedSelectedRuns) { - redirectToSelectedRuns(); - } - - /** - * This is for when there's only view= is defined in the URL, without any run_ids - * it should re-direct to the latest run - */ - if (matchedSelectedView) { - redirectToSelectedView(); - } - } - - if (usedNavigationBtn) { - setUsedNavigationBtn(false); - } - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [data, usedNavigationBtn]); - - useEffect(() => { - if (selectedRunIds.length > MAX_NUMBER_COMPARISONS) { - setDisableRunSelection(true); - } else { - setDisableRunSelection(false); - } - }, [selectedRunIds]); - - useEffect(() => { - /** - * If we return runs and aren't in comparison view, set a single selected - * run data object for use in the ExperimentPrimaryToolbar component. - */ - - if (data?.runsList.length > 0 && !enableComparisonView) { - const singleSelectedRunData = data.runsList.filter((run) => { - return run.id === selectedRunIds[0]; - })[0]; - - setSelectedRunData(singleSelectedRunData); - } - }, [data, enableComparisonView, selectedRunIds]); - - useEffect(() => { - if ( - matchedExperimentTrackingMainPage && - data?.runsList.length > 0 && - selectedRunIds.length === 0 - ) { - /** - * If we return to default main page and don't yet have a selected run, set the first one - * as the default, with precedence given to runs that are bookmarked. - */ - const bookmarkedRuns = data.runsList.filter((run) => { - return runsMetadata[run.id]?.bookmark === true; - }); - - if (bookmarkedRuns.length > 0) { - setSelectedRunIds(bookmarkedRuns.map((run) => run.id).slice(0, 1)); - } else { - setSelectedRunIds(data.runsList.map((run) => run.id).slice(0, 1)); - } - } - }, [data, selectedRunIds, matchedExperimentTrackingMainPage, runsMetadata]); - - useEffect(() => { - if ( - typeof pinnedRun === 'undefined' || - !selectedRunIds.includes(pinnedRun) - ) { - // Assign the first selected run as the first pinned run. - setPinnedRun(selectedRunIds[0]); - } - }, [selectedRunIds, pinnedRun]); - - if (loading) { - return ( -
-

Loading...

-
- ); - } - - if (invalidUrl) { - return ( -
-

- Oops, this URL isn't valid -

-

{`${errorMessage}.`}

- -
- ); - } else { - return ( - <> - - {data?.runsList.length > 0 ? ( - <> - - 0} timeout={300}> - {(state) => ( -
- {selectedRunIds.length > 0 ? ( -
1 - } - isKedroDatasetsCompatible={isKedroDatasetsCompatible} - isRunDataLoading={isRunDataLoading} - newRunAdded={newRunAdded} - onRunSelection={onRunSelection} - pinnedRun={pinnedRun} - runDataError={runDataError} - runMetadata={runMetadata} - runTrackingData={runTrackingData} - selectedRunIds={selectedRunIds} - setActiveTab={onTabChangeHandler} - setIsDisplayingMetrics={setIsDisplayingMetrics} - setPinnedRun={setPinnedRun} - setShowRunDetailsModal={setShowRunDetailsModal} - setShowRunExportModal={setShowRunExportModal} - setShowRunPlotsModal={setShowRunPlotsModal} - showRunDetailsModal={showRunDetailsModal} - showRunExportModal={showRunExportModal} - showRunPlotsModal={showRunPlotsModal} - sidebarVisible={isSidebarVisible} - theme={theme} - /> - ) : null} -
- )} -
- - ) : ( - - {(state) => ( -
-

- You don't have any experiments -

-

- Kedro can help you manage your experiments. Learn more how - you can enable experiment tracking in your projects from our - docs.{' '} -

- - - -
- )} -
- )} -
- - ); - } -}; - -export const mapStateToProps = (state) => ({ - theme: state.theme, - runsMetadata: state.runsMetadata, -}); - -export default connect(mapStateToProps)(ExperimentWrapper); diff --git a/src/components/experiment-wrapper/experiment-wrapper.scss b/src/components/experiment-wrapper/experiment-wrapper.scss deleted file mode 100644 index dcc7685a00..0000000000 --- a/src/components/experiment-wrapper/experiment-wrapper.scss +++ /dev/null @@ -1,35 +0,0 @@ -@use '../../styles/variables' as variables; - -.experiment-wrapper { - align-items: center; - display: flex; - flex-direction: column; - height: 100%; - justify-content: center; - margin-left: variables.$global-toolbar-width; - opacity: 0; -} - -.experiment-wrapper__header { - font-size: 40px; - font-weight: 300; - letter-spacing: -0.3px; - margin: 0 0 16px; -} - -.experiment-wrapper__text { - font-size: 16px; - font-weight: normal; - line-height: 1.25; - margin: 0 0 40px; - max-width: 520px; - text-align: center; -} - -.experiment-wrapper__error { - align-items: center; - display: flex; - flex-direction: column; - height: 100%; - justify-content: center; -} diff --git a/src/components/experiment-wrapper/index.js b/src/components/experiment-wrapper/index.js deleted file mode 100644 index b4af8d4162..0000000000 --- a/src/components/experiment-wrapper/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import ExperimentWrapper from './experiment-wrapper'; - -export default ExperimentWrapper; diff --git a/src/components/experiment-wrapper/mock-data.js b/src/components/experiment-wrapper/mock-data.js deleted file mode 100644 index 00cbb0b41a..0000000000 --- a/src/components/experiment-wrapper/mock-data.js +++ /dev/null @@ -1,100 +0,0 @@ -export const runs = [ - { - author: 'Luke Skywalker', - bookmark: true, - id: '2021-09-08T10:55:36.810Z', - gitSha: 'ad60192', - gitBranch: 'feature/new-feature', - runCommand: 'kedro run --pipeline my_pipeline', - notes: - 'But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful.', - title: 'My Favorite Sprint', - }, - { - author: 'Leia Organa', - bookmark: false, - id: '2021-09-07T11:36:24.560Z', - gitSha: 'bt60142', - gitBranch: 'feature/new-feature', - runCommand: 'kedro run --pipeline my_pipeline', - notes: - 'On the other hand, we denounce with righteous indignation and dislike men who are so beguiled.', - title: 'Another favorite sprint', - }, - { - author: 'Obi-wan Kenobi', - bookmark: false, - id: '2021-09-04T04:36:24.560Z', - gitSha: 'tz24689', - gitBranch: 'feature/new-feature', - runCommand: 'kedro run --pipeline my_pipeline', - notes: - 'On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment', - title: 'Slick test this one', - }, -]; - -export const trackingData = { - json: [ - { - datasetName: 'Data Analysis', - data: { - classWeight: [ - { runId: 'My Favorite Sprint', value: 23 }, - { runId: 'Another favorite sprint', value: 21 }, - { runId: 'Slick test this one', value: 21 }, - ], - bootstrap: [ - { runId: 'My Favorite Sprint', value: 0.8 }, - { runId: 'Another favorite sprint', value: 0.5 }, - { runId: 'Slick test this one', value: 1 }, - ], - }, - runIds: [ - 'My Favorite Sprint', - 'Another favorite sprint', - 'Slick test this one', - ], - }, - { - datasetName: 'Shopper Spend Raw', - data: { - maxFeatures: [ - { runId: 'My Favorite Sprint', value: 'auto' }, - { runId: 'Another favorite sprint', value: 'min' }, - { runId: 'Slick test this one', value: 'max' }, - ], - minSamplesLeaf: [ - { runId: 'My Favorite Sprint', value: 12564 }, - { runId: 'Another favorite sprint', value: 34524 }, - { runId: 'Slick test this one', value: 23987 }, - ], - }, - runIds: [ - 'My Favorite Sprint', - 'Another favorite sprint', - 'Slick test this one', - ], - }, - { - datasetName: 'Classical Analysis', - data: { - AU_SSID_NULLS: [ - { runId: 'My Favorite Sprint', value: 54.3 }, - { runId: 'Another favorite sprint', value: 55.1 }, - { runId: 'Slick test this one', value: 54.7 }, - ], - AR_ARM_NULLS: [ - { runId: 'My Favorite Sprint', value: 123 }, - { runId: 'Another favorite sprint', value: 345 }, - { runId: 'Slick test this one', value: 456 }, - ], - }, - runIds: [ - 'My Favorite Sprint', - 'Another favorite sprint', - 'Slick test this one', - ], - }, - ], -}; diff --git a/src/components/feature-hints/feature-hints-content.js b/src/components/feature-hints/feature-hints-content.js index 6015ebf52f..c077d1957b 100644 --- a/src/components/feature-hints/feature-hints-content.js +++ b/src/components/feature-hints/feature-hints-content.js @@ -25,16 +25,6 @@ export const featureHintsContent = [ image: 'data:image/jpeg;base64,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', }, - { - title: 'Experiment tracking', - description: - 'Experiment tracking is the process of saving all the metadata related to an experiment each time you run it. It enables you to compare different runs of a machine-learning model as part of the experimentation process.', - learnMoreLink: - 'https://docs.kedro.org/projects/kedro-viz/en/stable/experiment_tracking.html', - elementId: '#experiment-tracking-nav-button', - image: - 'data:image/jpeg;base64,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', - }, { title: 'Filters and tags', description: diff --git a/src/components/flowchart-wrapper/flowchart-wrapper.js b/src/components/flowchart-wrapper/flowchart-wrapper.js index f6f5bfc167..f09470a6a4 100644 --- a/src/components/flowchart-wrapper/flowchart-wrapper.js +++ b/src/components/flowchart-wrapper/flowchart-wrapper.js @@ -1,5 +1,5 @@ import React, { useState, useEffect, useCallback, useRef } from 'react'; -import { useHistory, useLocation } from 'react-router-dom'; +import { useLocation } from 'react-router-dom'; import { connect } from 'react-redux'; import classnames from 'classnames'; import { isLoading } from '../../selectors/loading'; @@ -24,13 +24,9 @@ import MetaData from '../metadata'; import MetadataModal from '../metadata-modal'; import ShareableUrlMetadata from '../shareable-url-modal/shareable-url-metadata'; import Sidebar from '../sidebar'; -import Button from '../ui/button'; -import CircleProgressBar from '../ui/circle-progress-bar'; import { loadLocalStorage, saveLocalStorage } from '../../store/helpers'; import { errorMessages, - linkToFlowchartInitialVal, - localStorageFlowchartLink, localStorageName, localStorageBannerStatus, params, @@ -54,7 +50,6 @@ export const FlowChartWrapper = ({ displaySidebar, graph, loading, - metadataVisible, modularPipelinesTree, nodes, onToggleFocusMode, @@ -72,7 +67,6 @@ export const FlowChartWrapper = ({ displayExportBtn, displayBanner, }) => { - const history = useHistory(); const { pathname, search } = useLocation(); const searchParams = new URLSearchParams(search); const { toSetQueryParam } = useGeneratePathname(); @@ -81,10 +75,6 @@ export const FlowChartWrapper = ({ const [isInvalidUrl, setIsInvalidUrl] = useState(false); const [usedNavigationBtn, setUsedNavigationBtn] = useState(false); - const [counter, setCounter] = useState(60); - const [goBackToExperimentTracking, setGoBackToExperimentTracking] = - useState(false); - const graphRef = useRef(null); const { @@ -232,10 +222,6 @@ export const FlowChartWrapper = ({ }; }, [handlePopState]); - useEffect(() => { - setGoBackToExperimentTracking(loadLocalStorage(localStorageFlowchartLink)); - }, []); - /** * To handle redirecting to a different location via the URL (e.g. selectedNode, * focusNode, etc.) we only need to call the matchPath actions when: @@ -280,37 +266,6 @@ export const FlowChartWrapper = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [graph, usedNavigationBtn, isInvalidUrl]); - const resetLinkingToFlowchartLocalStorage = useCallback(() => { - saveLocalStorage(localStorageFlowchartLink, linkToFlowchartInitialVal); - - setGoBackToExperimentTracking(linkToFlowchartInitialVal); - }, []); - - useEffect(() => { - if (goBackToExperimentTracking?.showGoBackBtn) { - const timer = - counter > 0 && setInterval(() => setCounter(counter - 1), 1000); - - if (counter === 0) { - resetLinkingToFlowchartLocalStorage(); - } - - return () => clearInterval(timer); - } - }, [ - counter, - goBackToExperimentTracking?.showGoBackBtn, - resetLinkingToFlowchartLocalStorage, - ]); - - const onGoBackToExperimentTrackingHandler = () => { - const url = goBackToExperimentTracking.fromURL; - - history.push(url); - - resetLinkingToFlowchartLocalStorage(); - }; - const handleBannerClose = (bannerKey) => { saveLocalStorage(localStorageBannerStatus, { [bannerKey]: false }); }; @@ -355,21 +310,6 @@ export const FlowChartWrapper = ({
-
- -
- + - {isRunningLocally() ? ( - - - - ) : null}
    { ); - expect(wrapper.find('.pipeline-icon-toolbar__button').length).toBe(6); + expect(wrapper.find('.pipeline-icon-toolbar__button').length).toBe(5); }); const functionCalls = [ diff --git a/src/components/icons/experiments.js b/src/components/icons/experiments.js deleted file mode 100644 index 938b28ccf1..0000000000 --- a/src/components/icons/experiments.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; - -const ExperimentsIcon = ({ className }) => ( - - - -); - -export default ExperimentsIcon; diff --git a/src/components/metadata/metadata.js b/src/components/metadata/metadata.js index 5b0ed7080f..48eeecfc64 100644 --- a/src/components/metadata/metadata.js +++ b/src/components/metadata/metadata.js @@ -19,14 +19,10 @@ import { import { toggleNodeClicked } from '../../actions/nodes'; import { toggleCode, togglePlotModal } from '../../actions'; import getShortType from '../../utils/short-type'; -import { - useGeneratePathname, - useGeneratePathnameForExperimentTracking, -} from '../../utils/hooks/use-generate-pathname'; +import { useGeneratePathname } from '../../utils/hooks/use-generate-pathname'; import './styles/metadata.scss'; import MetaDataStats from './metadata-stats'; -import { isRunningLocally } from '../../utils'; /** * Shows node meta data @@ -43,8 +39,6 @@ const MetaData = ({ showDatasetPreviews, }) => { const { toSelectedPipeline } = useGeneratePathname(); - const { toExperimentTrackingPath, toMetricsViewPath } = - useGeneratePathnameForExperimentTracking(); // Hide code panel when selected metadata changes useEffect(() => onToggleCode(false), [metadata, onToggleCode]); @@ -321,23 +315,6 @@ const MetaData = ({ )} - {isRunningLocally() - ? hasTrackingData && ( - - ) - : null} {hasTablePreview && ( <>
    diff --git a/src/components/metadata/metadata.test.js b/src/components/metadata/metadata.test.js index 849d8cc3e4..5147b9918e 100644 --- a/src/components/metadata/metadata.test.js +++ b/src/components/metadata/metadata.test.js @@ -425,13 +425,6 @@ describe('MetaData', () => { expect.stringContaining('3 items') ); }); - it('shows the experiment link', () => { - const wrapper = mount({ - nodeId: modelInputDatasetNodeId, - mockMetadata: nodeMetricsData, - }); - expect(wrapper.find('.pipeline-metadata__link').length).toBe(1); - }); }); describe('JSON dataset nodes', () => { @@ -445,13 +438,6 @@ describe('MetaData', () => { expect.stringContaining('3 items') ); }); - it('shows the experiment link', () => { - const wrapper = mount({ - nodeId: modelInputDatasetNodeId, - mockMetadata: nodeJSONData, - }); - expect(wrapper.find('.pipeline-metadata__link').length).toBe(1); - }); }); describe('Plot nodes', () => { diff --git a/src/components/primary-toolbar/primary-toolbar.js b/src/components/primary-toolbar/primary-toolbar.js index a286d7eeaa..b66af19f7d 100644 --- a/src/components/primary-toolbar/primary-toolbar.js +++ b/src/components/primary-toolbar/primary-toolbar.js @@ -6,7 +6,7 @@ import MenuIcon from '../icons/menu'; import './primary-toolbar.scss'; /** - * Toolbar to house buttons that controls display options for the main panel (flowchart, experiment details, etc) + * Toolbar to house buttons that controls display options for the main panel (flowchart, etc) * @param {JSX} children The content to be rendered within the toolbar * @param {Function} onToggleSidebar Handle toggling of sidebar collapsable view * @param {Boolean} visible Handle display of tooltip text in relation to collapsable view diff --git a/src/components/shareable-url-modal/shareable-url-metadata.js b/src/components/shareable-url-modal/shareable-url-metadata.js index 0397364941..21ae2d5ba4 100644 --- a/src/components/shareable-url-modal/shareable-url-metadata.js +++ b/src/components/shareable-url-modal/shareable-url-metadata.js @@ -1,5 +1,4 @@ import { useEffect, useState } from 'react'; -import { sanitizedPathname } from '../../utils'; const ShareableUrlMetadata = () => { const [metadata, setMetadata] = useState(null); @@ -7,15 +6,12 @@ const ShareableUrlMetadata = () => { useEffect(() => { async function fetchData() { try { - const request = await fetch( - `${sanitizedPathname()}api/deploy-viz-metadata`, - { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - } - ); + const request = await fetch(`/api/deploy-viz-metadata`, { + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + }); const response = await request.json(); if (request.ok) { diff --git a/src/components/sidebar/sidebar.js b/src/components/sidebar/sidebar.js index 73b6fbcc14..f38438c4b8 100644 --- a/src/components/sidebar/sidebar.js +++ b/src/components/sidebar/sidebar.js @@ -1,13 +1,11 @@ import React, { useState } from 'react'; import { connect } from 'react-redux'; import classnames from 'classnames'; -import ExperimentPrimaryToolbar from '../experiment-tracking/experiment-primary-toolbar'; import FlowchartPrimaryToolbar from '../flowchart-primary-toolbar'; import MiniMap from '../minimap'; import MiniMapToolbar from '../minimap-toolbar'; import NodesPanel from '../nodes-panel'; import PipelineList from '../pipeline-list'; -import RunsList from '../experiment-tracking/runs-list'; import './sidebar.scss'; @@ -15,90 +13,29 @@ import './sidebar.scss'; * Main app container. Handles showing/hiding the sidebar nav, and theme classes. * @param {Boolean} props.visible Whether the sidebar is open/closed */ -export const Sidebar = ({ - disableRunSelection, - displayGlobalNavigation, - displaySidebar, - enableComparisonView, - enableShowChanges, - isDisplayingMetrics = false, - isExperimentView = false, - onRunSelection, - onToggleComparisonView, - runMetadata, - runsListData, - runTrackingData, - selectedRunData, - selectedRunIds, - setEnableShowChanges, - setSidebarVisible, - showRunDetailsModal, - sidebarVisible, - visible, - setShowRunExportModal, -}) => { +export const Sidebar = ({ displayGlobalNavigation, visible }) => { const [pipelineIsOpen, togglePipeline] = useState(false); - if (isExperimentView) { - return ( - <> -
    -
    - -
    - + return ( + <> +
    +
    + +
    - - ); - } else { - return ( - <> -
    -
    - - -
    - - -
    - - ); - } + + +
    + + ); }; const mapStateToProps = (state) => ({ diff --git a/src/components/sidebar/sidebar.scss b/src/components/sidebar/sidebar.scss index 2575bcb166..8973075730 100644 --- a/src/components/sidebar/sidebar.scss +++ b/src/components/sidebar/sidebar.scss @@ -61,10 +61,6 @@ visibility: visible; transition: visibility 0s; } - - &--experiment-tracking { - overflow-y: scroll; - } } .pipeline-toolbar { diff --git a/src/components/wrapper/wrapper.js b/src/components/wrapper/wrapper.js index 37f289fe0f..f37d7927f5 100644 --- a/src/components/wrapper/wrapper.js +++ b/src/components/wrapper/wrapper.js @@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react'; import { connect } from 'react-redux'; import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'; import classnames from 'classnames'; -import { isRunningLocally, sanitizedPathname } from '../../utils'; +import { isRunningLocally } from '../../utils'; import { useApolloQuery } from '../../apollo/utils'; import { client } from '../../apollo/config'; import { GraphQLProvider } from '../provider/provider'; @@ -11,7 +11,6 @@ import { GET_VERSIONS } from '../../apollo/queries'; import FeatureHints from '../feature-hints'; import GlobalToolbar from '../global-toolbar'; import FlowChartWrapper from '../flowchart-wrapper'; -import ExperimentWrapper from '../experiment-wrapper'; import SettingsModal from '../settings-modal'; import UpdateReminder from '../update-reminder'; import ShareableUrlModal from '../shareable-url-modal'; @@ -60,13 +59,10 @@ export const Wrapper = ({ displayGlobalNavigation, theme }) => { /> )} - + - - - ) : ( diff --git a/src/config.js b/src/config.js index 492eb466ec..aca85079bc 100644 --- a/src/config.js +++ b/src/config.js @@ -1,9 +1,6 @@ -import { sanitizedPathname } from './utils'; - export const localStorageName = 'KedroViz'; export const localStorageFlowchartLink = 'KedroViz-link-to-flowchart'; export const localStorageMetricsSelect = 'KedroViz-metrics-chart-select'; -export const localStorageRunsMetadata = 'KedroViz-runs-metadata'; export const localStorageShareableUrl = 'KedroViz-shareable-url'; export const localStorageFeedbackSeen = 'KedroViz-feedback-seen'; export const localStorageBannerStatus = 'KedroViz-banners'; @@ -38,24 +35,6 @@ export const codeSidebarWidth = { // The exact fixed height of a row as measured by getBoundingClientRect() export const nodeListRowHeight = 32; -// These colours variables come from styles/variables -const slate600 = '#0e222d'; -const slate200 = '#21333e'; - -const grey200 = '#d5d8da'; -const grey100 = '#eaebed'; - -export const experimentTrackingLazyLoadingColours = { - backgroundLightTheme: grey200, - foregroundLightTheme: grey100, - backgroundDarkTheme: slate600, - foregroundDarkTheme: slate200, -}; - -export const metricLimit = 50; - -export const experimentTrackingLazyLoadingGap = 38; - export const chartMinWidthScale = 0.25; // Determine the number of nodes and edges in pipeline to trigger size warning @@ -131,20 +110,14 @@ export const params = { }; const activePipeline = `${params.pipeline}=:pipelineId`; -const pathname = sanitizedPathname(); export const routes = { flowchart: { - main: pathname, - focusedNode: `${pathname}?${activePipeline}&${params.focused}=:id`, - selectedNode: `${pathname}?${activePipeline}&${params.selected}=:id`, - selectedName: `${pathname}?${activePipeline}&${params.selectedName}=:fullName`, - selectedPipeline: `${pathname}?${activePipeline}`, - }, - experimentTracking: { - main: `${pathname}experiment-tracking`, - selectedView: `${pathname}experiment-tracking?${params.view}=:view`, - selectedRuns: `${pathname}experiment-tracking?${params.run}=:ids&${params.view}=:view&${params.comparisonMode}=:isComparison`, + main: '/', + focusedNode: `/?${activePipeline}&${params.focused}=:id`, + selectedNode: `/?${activePipeline}&${params.selected}=:id`, + selectedName: `/?${activePipeline}&${params.selectedName}=:fullName`, + selectedPipeline: `/?${activePipeline}`, }, }; @@ -152,8 +125,6 @@ export const errorMessages = { node: 'Please check the value of "selected_id"/"sid" or "selected_name"/"sn" in the URL', modularPipeline: 'Please check the value of "focused_id"/"fid" in the URL', pipeline: 'Please check the value of "pipeline_id"/"pid" in the URL', - experimentTracking: `Please check the spelling of "run_ids" or "view" or "comparison" in the URL. It may be a typo 😇`, - runIds: `Please check the value of "run_ids" in the URL. Perhaps you've deleted the entity 🙈 or it may be a typo 😇`, }; export const datasetStatLabels = ['rows', 'columns', 'file_size']; @@ -185,9 +156,6 @@ export const inputKeyToStateKeyMap = { endpoint: 'hasEndpoint', }; -export const RUN_TITLE = 'title'; -export const RUN_NOTES = 'notes'; - export const PACKAGE_FSSPEC = 'fsspec'; export const PACKAGE_KEDRO_DATASETS = 'kedro-datasets'; diff --git a/src/reducers/index.js b/src/reducers/index.js index 79af193f24..4af8356df6 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -1,5 +1,4 @@ import { combineReducers } from 'redux'; -import runsMetadata from './runs-metadata'; import flags from './flags'; import graph from './graph'; import layer from './layers'; @@ -84,7 +83,6 @@ const combinedReducer = combineReducers({ tag, modularPipeline, visible, - runsMetadata, showBanner: bannerReducer, // These props don't have any actions associated with them display: createReducer(null), diff --git a/src/reducers/runs-metadata.js b/src/reducers/runs-metadata.js deleted file mode 100644 index 2440779459..0000000000 --- a/src/reducers/runs-metadata.js +++ /dev/null @@ -1,39 +0,0 @@ -import { - TOGGLE_BOOKMARK, - UPDATE_RUN_TITLE, - UPDATE_RUN_NOTES, -} from '../actions'; - -function runsMetadataReducer(runsMetadataState = {}, action) { - switch (action.type) { - case TOGGLE_BOOKMARK: { - return Object.assign({}, runsMetadataState, { - [action.runId]: { - ...runsMetadataState[action.runId], - bookmark: action.bookmark, - }, - }); - } - case UPDATE_RUN_TITLE: { - return Object.assign({}, runsMetadataState, { - [action.runId]: { - ...runsMetadataState[action.runId], - title: action.title, - }, - }); - } - case UPDATE_RUN_NOTES: { - return Object.assign({}, runsMetadataState, { - [action.runId]: { - ...runsMetadataState[action.runId], - notes: action.notes, - }, - }); - } - - default: - return runsMetadataState; - } -} - -export default runsMetadataReducer; diff --git a/src/store/initial-state.js b/src/store/initial-state.js index 60f2423310..1fa9eae3db 100644 --- a/src/store/initial-state.js +++ b/src/store/initial-state.js @@ -7,7 +7,6 @@ import { settings, sidebarWidth, localStorageName, - localStorageRunsMetadata, params, BANNER_KEYS, } from '../config'; @@ -62,7 +61,6 @@ export const createInitialState = () => ({ reFocus: true, }, zoom: {}, - runsMetadata: {}, }); export const parseUrlParameters = () => { @@ -167,19 +165,14 @@ const applyUrlParametersToNonPipelineState = (state, urlParams) => { */ export const mergeLocalStorage = (state) => { const localStorageState = loadLocalStorage(localStorageName); - const localStorageRunsMetadataState = loadLocalStorage( - localStorageRunsMetadata - ); + Object.keys(localStorageState).forEach((key) => { if (!(key in state)) { delete localStorageState[key]; } }); - const allLocalStorageState = { - ...localStorageState, - ...{ runsMetadata: localStorageRunsMetadataState }, - }; - return deepmerge(state, allLocalStorageState); + + return deepmerge(state, localStorageState); }; /** diff --git a/src/store/store.js b/src/store/store.js index 8013c2f8e5..8a70c9e807 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -5,7 +5,7 @@ import reducer from '../reducers'; import { getGraphInput } from '../selectors/layout'; import { calculateGraph } from '../actions/graph'; import { saveLocalStorage, pruneFalseyKeys } from './helpers'; -import { localStorageName, localStorageRunsMetadata } from '../config'; +import { localStorageName } from '../config'; import createCallbackMiddleware from './middleware'; /** @@ -62,9 +62,6 @@ const saveStateToLocalStorage = (state) => { flags: state.flags, expandAllPipelines: state.expandAllPipelines, }); - - // Store Run's metadata to localstorage - saveLocalStorage(localStorageRunsMetadata, state.runsMetadata); }; /** diff --git a/src/utils/experiment-tracking-utils.js b/src/utils/experiment-tracking-utils.js deleted file mode 100644 index 617cf11409..0000000000 --- a/src/utils/experiment-tracking-utils.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Take a value and return a meaningful value for display on experiment tracking tables - * @param {value} value The value to be sanitized - * @returns A sanitized value - */ -export const sanitizeValue = (value) => { - if (value === '' || value === null || value === undefined) { - return '-'; - } else if (typeof value === 'object' || typeof value === 'boolean') { - return JSON.stringify(value); - } - - return value; -}; - -/** - * Takes a set of run metadata and run tracking data to construct the array object for csv export - * @param {Array} runMetadata The set of runMetadata - * @param {Array} runTrackingData The set of runTrackingData - * @returns An array formatted for CSV export - */ -export const constructExportData = (runMetadata, runTrackingData) => { - let csvData = []; - - if (runMetadata && runTrackingData) { - // Obtain runMetadata - const runTitle = runMetadata?.map((run) => sanitizeValue(run.title)); - const createdBy = runMetadata?.map((run) => sanitizeValue(run.author)); - const gitSha = runMetadata?.map((run) => sanitizeValue(run.gitSha)); - const gitBranch = runMetadata?.map((run) => sanitizeValue(run.gitBranch)); - const runCommand = runMetadata?.map((run) => sanitizeValue(run.runCommand)); - const notes = runMetadata?.map((run) => sanitizeValue(run.notes)); - - csvData.push( - ['Title', ...runTitle], - ['Created By', ...createdBy], - ['Git SHA', ...gitSha], - ['Git Branch', ...gitBranch], - ['Run Command', ...runCommand], - ['Notes', ...notes] - ); - - // Create empty line between metadata fields and tracking data fields. - csvData.push([]); - - buildCSVRows('Metrics'); - buildCSVRows('JSON Data'); - - function buildCSVRows(section) { - runTrackingData[section].forEach((trackingDataset) => { - const { datasetName, data } = trackingDataset; - const dataKeyNames = Object.keys(data).sort((a, b) => { - return a.localeCompare(b); - }); - - csvData.push([datasetName]); - - dataKeyNames.forEach((key) => { - let keyData = [key]; - - data[key].forEach((dataField) => keyData.push(dataField.value)); - csvData.push(keyData); - }); - - csvData.push([]); - }); - } - } - - return csvData; -}; - -/** - * Take a the runMetadata list to generate a meaningful file name for csv export - * @param {Array} runMetadata The set of runMetadata to be exported - * @returns A string to be used as the file name - */ -export const generateCSVFileName = (runMetadata) => { - let filename = 'rundata'; - - runMetadata?.forEach((run) => (filename += `-${run.id}`)); - filename += '.csv'; - - return filename; -}; diff --git a/src/utils/hooks/use-generate-pathname.js b/src/utils/hooks/use-generate-pathname.js index a70fd14ecf..06468154b5 100644 --- a/src/utils/hooks/use-generate-pathname.js +++ b/src/utils/hooks/use-generate-pathname.js @@ -1,9 +1,8 @@ import { useCallback } from 'react'; -import { useHistory, generatePath } from 'react-router-dom'; +import { useHistory } from 'react-router-dom'; import { localStorageName, params, - routes, defaultQueryParams, NODE_TYPES, } from '../../config'; @@ -134,39 +133,3 @@ export const useGeneratePathname = () => { toUpdateUrlParamsOnFilter, }; }; - -export const useGeneratePathnameForExperimentTracking = () => { - const history = useHistory(); - - const toExperimentTrackingPath = useCallback(() => { - const url = generatePath(routes.experimentTracking.main); - - history.push(url); - }, [history]); - - const toMetricsViewPath = useCallback(() => { - const url = generatePath(routes.experimentTracking.selectedView, { - view: 'Metrics', - }); - history.push(url); - }, [history]); - - const toSelectedRunsPath = useCallback( - (ids, view, isComparison) => { - const url = generatePath(routes.experimentTracking.selectedRuns, { - ids: ids.length === 1 ? ids[0] : ids.toString(), - view, - isComparison, - }); - - history.push(url); - }, - [history] - ); - - return { - toExperimentTrackingPath, - toMetricsViewPath, - toSelectedRunsPath, - }; -}; diff --git a/src/utils/index.js b/src/utils/index.js index 83804e0a6c..7da4d70706 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -206,22 +206,6 @@ export const isRunningLocally = () => { return itemFound; }; -/** - * Sanitized pathname with experiment-tracking string and check if path containing trailing slash - * @returns {string} Sanitized pathname - */ -export const sanitizedPathname = () => { - const { pathname } = window.location; - const sanitizedPathname = replaceMatches(pathname, { - 'experiment-tracking': '', - }); - const pathnameWithTrailingSlash = sanitizedPathname.endsWith('/') - ? sanitizedPathname - : `${sanitizedPathname}/`; // the `pathname` will have a trailing slash if it didn't initially - - return pathnameWithTrailingSlash; -}; - /** * Fetches viz metadata from the server. * @returns {Promise} A promise that resolves the fetched viz metadata. diff --git a/src/utils/match-path.js b/src/utils/match-path.js index 58a707437c..e1cc879314 100644 --- a/src/utils/match-path.js +++ b/src/utils/match-path.js @@ -23,29 +23,11 @@ export const findMatchedPath = (pathname, search) => { const matchedSelectedNodeName = () => hasQueryParam(params.selectedName); const matchedFocusedNode = () => hasQueryParam(params.focused); - const matchedExperimentTrackingMainPage = matchPath(pathname + search, { - exact: true, - path: [routes.experimentTracking.main], - }); - - const matchedSelectedView = matchPath(pathname + search, { - exact: true, - path: [routes.experimentTracking.selectedView], - }); - - const matchedSelectedRuns = matchPath(pathname + search, { - exact: true, - path: [routes.experimentTracking.selectedRuns], - }); - return { matchedFlowchartMainPage, matchedSelectedPipeline, matchedSelectedNodeId, matchedSelectedNodeName, matchedFocusedNode, - matchedExperimentTrackingMainPage, - matchedSelectedView, - matchedSelectedRuns, }; }; diff --git a/src/utils/object-utils.js b/src/utils/object-utils.js index 8efdaab066..159cbe1610 100644 --- a/src/utils/object-utils.js +++ b/src/utils/object-utils.js @@ -1,29 +1,3 @@ -export const removeChildFromObject = (originalObj, itemsToRemove) => { - let updatedObj = { ...originalObj }; - itemsToRemove.map((each) => { - const { [each]: unused, ...rest } = updatedObj; - - return (updatedObj = { ...rest }); - }); - - return updatedObj; -}; - -export const removeElementsFromObjectValues = (obj, itemsToRemove) => { - let updatedObj = {}; - - for (const [key, value] of Object.entries(obj)) { - let newVal = [...value]; - newVal = newVal.filter(function (_, index) { - return itemsToRemove.indexOf(index) === -1; - }); - - updatedObj[key] = newVal; - } - - return updatedObj; -}; - // Returns the key of the given value in the object. export const getKeyByValue = (object, value) => { return Object.keys(object).find((key) => object[key] === value); diff --git a/src/utils/object-utils.test.js b/src/utils/object-utils.test.js index 00ad189980..dc55a4bb74 100644 --- a/src/utils/object-utils.test.js +++ b/src/utils/object-utils.test.js @@ -1,55 +1,4 @@ -import { - removeChildFromObject, - removeElementsFromObjectValues, - getKeyByValue, - getKeysByValue, -} from './object-utils'; -import { data } from '../components/experiment-tracking/mock-data'; - -const mockToBeRemovedValues = { - 'Dataset1.Metrics1': 0, - 'Dataset1.Metrics2': 1, - 'Dataset1.Metrics3': 2, -}; - -test('return expected metrics which should not have the first 3 metrics keys "Dataset1.Metrics1", "Dataset1.Metrics2", and "Dataset1.Metrics3"', () => { - const expected = { - 'Dataset2.Metrics4': [4, 2.9, 7.7, 3.5, 2.4, 2.4, 3.4, 6.4, 1.4], - 'Dataset2.Metrics5': [5, 6, 1, 2.1, 1.6, 5.6, 4.6, 2.6, 6.6], - 'Dataset2.Metrics6': [4, 2.9, 7.7, 3.5, 2.4, 2.4, 3.4, 6.4, 1.4], - 'Dataset1.Metrics7': [1, 3, 4.5, 2.4, 3.3, 5.3, 1.3, 6.5, 3.4], - 'Dataset1.Metrics8': [3, 1.3, 6.6, 6.6, 5.6, 5.6, 2.6, 1.6, 4.6], - 'Dataset2.Metrics9': [5, 6, 1, 2.1, 1.6, 5.6, 4.6, 2.6, 6.6], - }; - - const received = removeChildFromObject( - data.metrics, - Object.keys(mockToBeRemovedValues) - ); - - expect(received).toStrictEqual(expected); -}); - -test('return expected runs which should not have the first 3 values', () => { - const expected = { - '2022-09-05T12.27.04.496Z': [4, 5], - '2022-10-05T12.22.35.825Z': [2.9, 6], - '2022-12-24T21.05.59.296Z': [7.7, 1], - '2022-08-24T21.04.31.605Z': [3.5, 2.1], - '2022-08-24T21.03.25.671Z': [2.4, 1.6], - '2022-07-22T13.49.08.764Z': [2.4, 5.6], - '2022-07-21T12.54.06.759Z': [3.4, 4.6], - '2022-07-20T15.39.58.437Z': [6.4, 2.6], - '2022-06-22T13.13.06.258Z': [1.4, 6.6], - }; - - const received = removeElementsFromObjectValues( - data.runs, - Object.values(mockToBeRemovedValues) - ); - - expect(received).toStrictEqual(expected); -}); +import { getKeyByValue, getKeysByValue } from './object-utils'; test('return the correct key for the value', () => { const mockObject = {