From d6a60b5043c6f7c3dfc45853feb68d0aca5a4a5f Mon Sep 17 00:00:00 2001 From: pmikus Date: Mon, 19 Sep 2022 08:49:01 +0200 Subject: feat(uti): Move directory Signed-off-by: pmikus Change-Id: I7300ecfe756baaf3fbeedb020070f882cfaca445 --- resources/tools/dash/Dockerfile | 12 - .../tools/dash/app/.ebextensions/cron-linux.config | 14 - resources/tools/dash/app/Procfile | 1 - resources/tools/dash/app/app.ini | 19 - resources/tools/dash/app/config.py | 30 - resources/tools/dash/app/pal/__init__.py | 81 - resources/tools/dash/app/pal/data/__init__.py | 12 - resources/tools/dash/app/pal/data/data.py | 351 ----- resources/tools/dash/app/pal/data/data.yaml | 117 -- resources/tools/dash/app/pal/debug.py | 48 - resources/tools/dash/app/pal/news/__init__.py | 12 - resources/tools/dash/app/pal/news/layout.py | 522 ------- resources/tools/dash/app/pal/news/news.py | 46 - resources/tools/dash/app/pal/news/tables.py | 176 --- resources/tools/dash/app/pal/report/__init__.py | 12 - resources/tools/dash/app/pal/report/graphs.py | 275 ---- resources/tools/dash/app/pal/report/layout.py | 1494 ------------------ resources/tools/dash/app/pal/report/layout.yaml | 127 -- resources/tools/dash/app/pal/report/report.py | 48 - resources/tools/dash/app/pal/routes.py | 32 - .../tools/dash/app/pal/static/dist/img/favicon.svg | 348 ----- resources/tools/dash/app/pal/static/img/logo.svg | 348 ----- .../dash/app/pal/static/sass/_bootswatch.scss | 178 --- .../tools/dash/app/pal/static/sass/_variables.scss | 103 -- .../app/pal/static/sass/bootstrap/_accordion.scss | 149 -- .../dash/app/pal/static/sass/bootstrap/_alert.scss | 71 - .../dash/app/pal/static/sass/bootstrap/_badge.scss | 38 - .../app/pal/static/sass/bootstrap/_breadcrumb.scss | 40 - .../pal/static/sass/bootstrap/_button-group.scss | 142 -- .../app/pal/static/sass/bootstrap/_buttons.scss | 201 --- .../dash/app/pal/static/sass/bootstrap/_card.scss | 234 --- .../app/pal/static/sass/bootstrap/_carousel.scss | 229 --- .../dash/app/pal/static/sass/bootstrap/_close.scss | 40 - .../app/pal/static/sass/bootstrap/_containers.scss | 41 - .../app/pal/static/sass/bootstrap/_dropdown.scss | 249 --- .../dash/app/pal/static/sass/bootstrap/_forms.scss | 9 - .../app/pal/static/sass/bootstrap/_functions.scss | 302 ---- .../dash/app/pal/static/sass/bootstrap/_grid.scss | 33 - .../app/pal/static/sass/bootstrap/_helpers.scss | 10 - .../app/pal/static/sass/bootstrap/_images.scss | 42 - .../app/pal/static/sass/bootstrap/_list-group.scss | 192 --- .../dash/app/pal/static/sass/bootstrap/_maps.scss | 54 - .../app/pal/static/sass/bootstrap/_mixins.scss | 43 - .../dash/app/pal/static/sass/bootstrap/_modal.scss | 237 --- .../dash/app/pal/static/sass/bootstrap/_nav.scss | 172 --- .../app/pal/static/sass/bootstrap/_navbar.scss | 278 ---- .../app/pal/static/sass/bootstrap/_offcanvas.scss | 144 -- .../app/pal/static/sass/bootstrap/_pagination.scss | 109 -- .../pal/static/sass/bootstrap/_placeholders.scss | 51 - .../app/pal/static/sass/bootstrap/_popover.scss | 196 --- .../app/pal/static/sass/bootstrap/_progress.scss | 59 - .../app/pal/static/sass/bootstrap/_reboot.scss | 610 -------- .../dash/app/pal/static/sass/bootstrap/_root.scss | 73 - .../app/pal/static/sass/bootstrap/_spinners.scss | 85 - .../app/pal/static/sass/bootstrap/_tables.scss | 164 -- .../app/pal/static/sass/bootstrap/_toasts.scss | 71 - .../app/pal/static/sass/bootstrap/_tooltip.scss | 120 -- .../pal/static/sass/bootstrap/_transitions.scss | 27 - .../dash/app/pal/static/sass/bootstrap/_type.scss | 106 -- .../app/pal/static/sass/bootstrap/_utilities.scss | 647 -------- .../app/pal/static/sass/bootstrap/_variables.scss | 1634 -------------------- .../pal/static/sass/bootstrap/bootstrap-grid.scss | 64 - .../static/sass/bootstrap/bootstrap-reboot.scss | 9 - .../static/sass/bootstrap/bootstrap-utilities.scss | 15 - .../app/pal/static/sass/bootstrap/bootstrap.scss | 51 - .../sass/bootstrap/forms/_floating-labels.scss | 75 - .../static/sass/bootstrap/forms/_form-check.scss | 175 --- .../static/sass/bootstrap/forms/_form-control.scss | 194 --- .../static/sass/bootstrap/forms/_form-range.scss | 91 -- .../static/sass/bootstrap/forms/_form-select.scss | 71 - .../static/sass/bootstrap/forms/_form-text.scss | 11 - .../static/sass/bootstrap/forms/_input-group.scss | 132 -- .../pal/static/sass/bootstrap/forms/_labels.scss | 36 - .../static/sass/bootstrap/forms/_validation.scss | 12 - .../static/sass/bootstrap/helpers/_clearfix.scss | 3 - .../static/sass/bootstrap/helpers/_color-bg.scss | 10 - .../sass/bootstrap/helpers/_colored-links.scss | 12 - .../static/sass/bootstrap/helpers/_position.scss | 36 - .../pal/static/sass/bootstrap/helpers/_ratio.scss | 26 - .../pal/static/sass/bootstrap/helpers/_stacks.scss | 15 - .../sass/bootstrap/helpers/_stretched-link.scss | 15 - .../sass/bootstrap/helpers/_text-truncation.scss | 7 - .../sass/bootstrap/helpers/_visually-hidden.scss | 8 - .../app/pal/static/sass/bootstrap/helpers/_vr.scss | 8 - .../pal/static/sass/bootstrap/mixins/_alert.scss | 15 - .../static/sass/bootstrap/mixins/_backdrop.scss | 14 - .../pal/static/sass/bootstrap/mixins/_banner.scss | 9 - .../sass/bootstrap/mixins/_border-radius.scss | 78 - .../static/sass/bootstrap/mixins/_box-shadow.scss | 18 - .../static/sass/bootstrap/mixins/_breakpoints.scss | 127 -- .../pal/static/sass/bootstrap/mixins/_buttons.scss | 70 - .../pal/static/sass/bootstrap/mixins/_caret.scss | 64 - .../static/sass/bootstrap/mixins/_clearfix.scss | 9 - .../sass/bootstrap/mixins/_color-scheme.scss | 7 - .../static/sass/bootstrap/mixins/_container.scss | 11 - .../static/sass/bootstrap/mixins/_deprecate.scss | 10 - .../pal/static/sass/bootstrap/mixins/_forms.scss | 152 -- .../static/sass/bootstrap/mixins/_gradients.scss | 47 - .../pal/static/sass/bootstrap/mixins/_grid.scss | 151 -- .../pal/static/sass/bootstrap/mixins/_image.scss | 16 - .../static/sass/bootstrap/mixins/_list-group.scss | 24 - .../pal/static/sass/bootstrap/mixins/_lists.scss | 7 - .../static/sass/bootstrap/mixins/_pagination.scss | 10 - .../static/sass/bootstrap/mixins/_reset-text.scss | 17 - .../pal/static/sass/bootstrap/mixins/_resize.scss | 6 - .../sass/bootstrap/mixins/_table-variants.scss | 24 - .../sass/bootstrap/mixins/_text-truncate.scss | 8 - .../static/sass/bootstrap/mixins/_transition.scss | 26 - .../static/sass/bootstrap/mixins/_utilities.scss | 97 -- .../sass/bootstrap/mixins/_visually-hidden.scss | 29 - .../pal/static/sass/bootstrap/utilities/_api.scss | 47 - .../app/pal/static/sass/bootstrap/vendor/_rfs.scss | 354 ----- resources/tools/dash/app/pal/static/sass/lux.scss | 6 - resources/tools/dash/app/pal/stats/__init__.py | 12 - resources/tools/dash/app/pal/stats/graphs.py | 124 -- resources/tools/dash/app/pal/stats/layout.py | 868 ----------- resources/tools/dash/app/pal/stats/layout.yaml | 79 - resources/tools/dash/app/pal/stats/stats.py | 48 - .../dash/app/pal/templates/base_layout.jinja2 | 24 - .../dash/app/pal/templates/index_layout.jinja2 | 34 - .../dash/app/pal/templates/news_layout.jinja2 | 17 - .../dash/app/pal/templates/report_layout.jinja2 | 17 - .../dash/app/pal/templates/stats_layout.jinja2 | 17 - .../dash/app/pal/templates/trending_layout.jinja2 | 17 - resources/tools/dash/app/pal/trending/__init__.py | 12 - resources/tools/dash/app/pal/trending/graphs.py | 408 ----- resources/tools/dash/app/pal/trending/layout.py | 1387 ----------------- resources/tools/dash/app/pal/trending/layout.yaml | 129 -- resources/tools/dash/app/pal/trending/trending.py | 48 - resources/tools/dash/app/pal/utils/__init__.py | 12 - resources/tools/dash/app/pal/utils/constants.py | 315 ---- resources/tools/dash/app/pal/utils/tooltips.yaml | 42 - .../tools/dash/app/pal/utils/url_processing.py | 99 -- resources/tools/dash/app/pal/utils/utils.py | 344 ----- resources/tools/dash/app/requirements.txt | 40 - resources/tools/dash/app/wsgi.py | 21 - resources/tools/dash/docker-compose.yaml | 15 - 137 files changed, 17966 deletions(-) delete mode 100644 resources/tools/dash/Dockerfile delete mode 100644 resources/tools/dash/app/.ebextensions/cron-linux.config delete mode 100644 resources/tools/dash/app/Procfile delete mode 100644 resources/tools/dash/app/app.ini delete mode 100644 resources/tools/dash/app/config.py delete mode 100644 resources/tools/dash/app/pal/__init__.py delete mode 100644 resources/tools/dash/app/pal/data/__init__.py delete mode 100644 resources/tools/dash/app/pal/data/data.py delete mode 100644 resources/tools/dash/app/pal/data/data.yaml delete mode 100644 resources/tools/dash/app/pal/debug.py delete mode 100644 resources/tools/dash/app/pal/news/__init__.py delete mode 100644 resources/tools/dash/app/pal/news/layout.py delete mode 100644 resources/tools/dash/app/pal/news/news.py delete mode 100644 resources/tools/dash/app/pal/news/tables.py delete mode 100644 resources/tools/dash/app/pal/report/__init__.py delete mode 100644 resources/tools/dash/app/pal/report/graphs.py delete mode 100644 resources/tools/dash/app/pal/report/layout.py delete mode 100644 resources/tools/dash/app/pal/report/layout.yaml delete mode 100644 resources/tools/dash/app/pal/report/report.py delete mode 100644 resources/tools/dash/app/pal/routes.py delete mode 100644 resources/tools/dash/app/pal/static/dist/img/favicon.svg delete mode 100644 resources/tools/dash/app/pal/static/img/logo.svg delete mode 100644 resources/tools/dash/app/pal/static/sass/_bootswatch.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/_variables.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_accordion.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_alert.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_badge.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_breadcrumb.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_button-group.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_buttons.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_card.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_carousel.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_close.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_containers.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_dropdown.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_forms.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_functions.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_grid.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_helpers.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_images.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_list-group.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_maps.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_mixins.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_modal.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_nav.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_navbar.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_offcanvas.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_pagination.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_placeholders.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_popover.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_progress.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_reboot.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_root.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_spinners.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_tables.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_toasts.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_tooltip.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_transitions.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_type.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_utilities.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/_variables.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/bootstrap-grid.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/bootstrap-reboot.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/bootstrap-utilities.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/bootstrap.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/forms/_floating-labels.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/forms/_form-check.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/forms/_form-control.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/forms/_form-range.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/forms/_form-select.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/forms/_form-text.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/forms/_input-group.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/forms/_labels.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/forms/_validation.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/helpers/_clearfix.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/helpers/_color-bg.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/helpers/_colored-links.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/helpers/_position.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/helpers/_ratio.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/helpers/_stacks.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/helpers/_stretched-link.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/helpers/_text-truncation.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/helpers/_visually-hidden.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/helpers/_vr.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_alert.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_backdrop.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_banner.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_border-radius.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_box-shadow.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_breakpoints.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_buttons.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_caret.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_clearfix.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_color-scheme.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_container.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_deprecate.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_forms.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_gradients.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_grid.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_image.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_list-group.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_lists.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_pagination.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_reset-text.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_resize.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_table-variants.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_text-truncate.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_transition.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_utilities.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/mixins/_visually-hidden.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/utilities/_api.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/bootstrap/vendor/_rfs.scss delete mode 100644 resources/tools/dash/app/pal/static/sass/lux.scss delete mode 100644 resources/tools/dash/app/pal/stats/__init__.py delete mode 100644 resources/tools/dash/app/pal/stats/graphs.py delete mode 100644 resources/tools/dash/app/pal/stats/layout.py delete mode 100644 resources/tools/dash/app/pal/stats/layout.yaml delete mode 100644 resources/tools/dash/app/pal/stats/stats.py delete mode 100644 resources/tools/dash/app/pal/templates/base_layout.jinja2 delete mode 100644 resources/tools/dash/app/pal/templates/index_layout.jinja2 delete mode 100644 resources/tools/dash/app/pal/templates/news_layout.jinja2 delete mode 100644 resources/tools/dash/app/pal/templates/report_layout.jinja2 delete mode 100644 resources/tools/dash/app/pal/templates/stats_layout.jinja2 delete mode 100644 resources/tools/dash/app/pal/templates/trending_layout.jinja2 delete mode 100644 resources/tools/dash/app/pal/trending/__init__.py delete mode 100644 resources/tools/dash/app/pal/trending/graphs.py delete mode 100644 resources/tools/dash/app/pal/trending/layout.py delete mode 100644 resources/tools/dash/app/pal/trending/layout.yaml delete mode 100644 resources/tools/dash/app/pal/trending/trending.py delete mode 100644 resources/tools/dash/app/pal/utils/__init__.py delete mode 100644 resources/tools/dash/app/pal/utils/constants.py delete mode 100644 resources/tools/dash/app/pal/utils/tooltips.yaml delete mode 100644 resources/tools/dash/app/pal/utils/url_processing.py delete mode 100644 resources/tools/dash/app/pal/utils/utils.py delete mode 100644 resources/tools/dash/app/requirements.txt delete mode 100644 resources/tools/dash/app/wsgi.py delete mode 100644 resources/tools/dash/docker-compose.yaml (limited to 'resources/tools/dash') diff --git a/resources/tools/dash/Dockerfile b/resources/tools/dash/Dockerfile deleted file mode 100644 index ee4ae1edd9..0000000000 --- a/resources/tools/dash/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -ARG PYTHON_VERSION=3.8 -FROM python:${PYTHON_VERSION}-buster - -WORKDIR /app - -COPY ./app/requirements.txt . - -RUN pip3 install -r requirements.txt - -EXPOSE 5000 - -CMD [ "uwsgi", "app.ini" ] \ No newline at end of file diff --git a/resources/tools/dash/app/.ebextensions/cron-linux.config b/resources/tools/dash/app/.ebextensions/cron-linux.config deleted file mode 100644 index ae8c33c814..0000000000 --- a/resources/tools/dash/app/.ebextensions/cron-linux.config +++ /dev/null @@ -1,14 +0,0 @@ -files: - "/etc/cron.d/mycron": - mode: "000644" - owner: root - group: root - content: | - SHELL=/bin/bash - PATH=/sbin:/bin:/usr/sbin:/usr/bin - MAILTO=root - 0 6 * * * root /bin/echo 'c' > /tmp/masterfifo - -commands: - remove_old_cron: - command: "rm -f /etc/cron.d/mycron.bak" \ No newline at end of file diff --git a/resources/tools/dash/app/Procfile b/resources/tools/dash/app/Procfile deleted file mode 100644 index c79d502390..0000000000 --- a/resources/tools/dash/app/Procfile +++ /dev/null @@ -1 +0,0 @@ -uwsgi: uwsgi app.ini diff --git a/resources/tools/dash/app/app.ini b/resources/tools/dash/app/app.ini deleted file mode 100644 index b42f63dc4b..0000000000 --- a/resources/tools/dash/app/app.ini +++ /dev/null @@ -1,19 +0,0 @@ -[uwsgi] -ini = :pal -py-autoreload = 0 - -[pal] -module = wsgi:app -master-fifo = /tmp/masterfifo -lazy = True -lazy-apps = True -touch-chain-reload -listen = 128 - -workers = 2 -plugin = python3 - -master = true -http-socket = :5000 -socket = /tmp/app.sock -chmod-socket = 666 diff --git a/resources/tools/dash/app/config.py b/resources/tools/dash/app/config.py deleted file mode 100644 index 559864bebb..0000000000 --- a/resources/tools/dash/app/config.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2022 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -class Config: - """Flask configuration variables. - """ - # General Config - FLASK_APP = "wsgi.py" - FLASK_ENV = "production" - - # Assets - ASSETS_DEBUG = False - ASSETS_AUTO_BUILD = True - - # Static Assets - STATIC_FOLDER = "static" - TEMPLATES_FOLDER = "templates" - COMPRESSOR_DEBUG = "True" diff --git a/resources/tools/dash/app/pal/__init__.py b/resources/tools/dash/app/pal/__init__.py deleted file mode 100644 index 20023ec157..0000000000 --- a/resources/tools/dash/app/pal/__init__.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (c) 2022 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Initialize Flask app. -""" - -import logging - -from flask import Flask -from flask_assets import Environment, Bundle - -from .utils.constants import Constants as C - - -def init_app(): - """Construct core Flask application with embedded Dash app. - """ - logging.basicConfig( - format=C.LOG_FORMAT, - datefmt=C.LOG_DATE_FORMAT, - level=C.LOG_LEVEL - ) - - logging.info("Application started.") - - app = Flask(__name__, instance_relative_config=False) - app.config.from_object("config.Config") - - with app.app_context(): - # Import parts of our core Flask app. - from . import routes - - assets = Environment() - assets.init_app(app) - - # Compile static assets. - sass_bundle = Bundle( - "sass/lux.scss", - filters="libsass", - output="dist/css/bootstrap.css", - depends="**/*.scss", - extra={ - "rel": "stylesheet" - } - ) - assets.register("sass_all", sass_bundle) - sass_bundle.build() - - # Set the time period for Trending - if C.TIME_PERIOD is None or C.TIME_PERIOD > C.MAX_TIME_PERIOD: - time_period = C.MAX_TIME_PERIOD - else: - time_period = C.TIME_PERIOD - - # Import Dash applications. - from .news.news import init_news - app = init_news(app) - - from .stats.stats import init_stats - app = init_stats(app, time_period=time_period) - - from .trending.trending import init_trending - app = init_trending(app, time_period=time_period) - - from .report.report import init_report - app = init_report(app, releases=C.RELEASES) - - return app - - -app = init_app() diff --git a/resources/tools/dash/app/pal/data/__init__.py b/resources/tools/dash/app/pal/data/__init__.py deleted file mode 100644 index 5692432123..0000000000 --- a/resources/tools/dash/app/pal/data/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2022 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. diff --git a/resources/tools/dash/app/pal/data/data.py b/resources/tools/dash/app/pal/data/data.py deleted file mode 100644 index 77fd113a9c..0000000000 --- a/resources/tools/dash/app/pal/data/data.py +++ /dev/null @@ -1,351 +0,0 @@ -# Copyright (c) 2022 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Prepare data for Plotly Dash applications. -""" - -import logging -import awswrangler as wr - -from yaml import load, FullLoader, YAMLError -from datetime import datetime, timedelta -from time import time -from pytz import UTC -from pandas import DataFrame -from awswrangler.exceptions import EmptyDataFrame, NoFilesFound - - -class Data: - """Gets the data from parquets and stores it for further use by dash - applications. - """ - - def __init__(self, data_spec_file: str, debug: bool=False) -> None: - """Initialize the Data object. - - :param data_spec_file: Path to file specifying the data to be read from - parquets. - :param debug: If True, the debuf information is printed to stdout. - :type data_spec_file: str - :type debug: bool - :raises RuntimeError: if it is not possible to open data_spec_file or it - is not a valid yaml file. - """ - - # Inputs: - self._data_spec_file = data_spec_file - self._debug = debug - - # Specification of data to be read from parquets: - self._data_spec = None - - # Data frame to keep the data: - self._data = None - - # Read from files: - try: - with open(self._data_spec_file, "r") as file_read: - self._data_spec = load(file_read, Loader=FullLoader) - except IOError as err: - raise RuntimeError( - f"Not possible to open the file {self._data_spec_file,}\n{err}" - ) - except YAMLError as err: - raise RuntimeError( - f"An error occurred while parsing the specification file " - f"{self._data_spec_file,}\n" - f"{err}" - ) - - @property - def data(self): - return self._data - - def _get_columns(self, parquet: str) -> list: - """Get the list of columns from the data specification file to be read - from parquets. - - :param parquet: The parquet's name. - :type parquet: str - :raises RuntimeError: if the parquet is not defined in the data - specification file or it does not have any columns specified. - :returns: List of columns. - :rtype: list - """ - - try: - return self._data_spec[parquet]["columns"] - except KeyError as err: - raise RuntimeError( - f"The parquet {parquet} is not defined in the specification " - f"file {self._data_spec_file} or it does not have any columns " - f"specified.\n{err}" - ) - - def _get_path(self, parquet: str) -> str: - """Get the path from the data specification file to be read from - parquets. - - :param parquet: The parquet's name. - :type parquet: str - :raises RuntimeError: if the parquet is not defined in the data - specification file or it does not have the path specified. - :returns: Path. - :rtype: str - """ - - try: - return self._data_spec[parquet]["path"] - except KeyError as err: - raise RuntimeError( - f"The parquet {parquet} is not defined in the specification " - f"file {self._data_spec_file} or it does not have the path " - f"specified.\n{err}" - ) - - def _get_list_of_files(self, - path, - last_modified_begin=None, - last_modified_end=None, - days=None) -> list: - """Get list of interested files stored in S3 compatible storage and - returns it. - - :param path: S3 prefix (accepts Unix shell-style wildcards) - (e.g. s3://bucket/prefix) or list of S3 objects paths - (e.g. [s3://bucket/key0, s3://bucket/key1]). - :param last_modified_begin: Filter the s3 files by the Last modified - date of the object. The filter is applied only after list all s3 - files. - :param last_modified_end: Filter the s3 files by the Last modified date - of the object. The filter is applied only after list all s3 files. - :param days: Number of days to filter. - :type path: Union[str, List[str]] - :type last_modified_begin: datetime, optional - :type last_modified_end: datetime, optional - :type days: integer, optional - :returns: List of file names. - :rtype: List - """ - if days: - last_modified_begin = datetime.now(tz=UTC) - timedelta(days=days) - try: - file_list = wr.s3.list_objects( - path=path, - suffix="parquet", - last_modified_begin=last_modified_begin, - last_modified_end=last_modified_end - ) - if self._debug: - logging.info("\n".join(file_list)) - except NoFilesFound as err: - logging.error(f"No parquets found.\n{err}") - except EmptyDataFrame as err: - logging.error(f"No data.\n{err}") - - return file_list - - def _create_dataframe_from_parquet(self, - path, partition_filter=None, - columns=None, - validate_schema=False, - last_modified_begin=None, - last_modified_end=None, - days=None) -> DataFrame: - """Read parquet stored in S3 compatible storage and returns Pandas - Dataframe. - - :param path: S3 prefix (accepts Unix shell-style wildcards) - (e.g. s3://bucket/prefix) or list of S3 objects paths - (e.g. [s3://bucket/key0, s3://bucket/key1]). - :param partition_filter: Callback Function filters to apply on PARTITION - columns (PUSH-DOWN filter). This function MUST receive a single - argument (Dict[str, str]) where keys are partitions names and values - are partitions values. Partitions values will be always strings - extracted from S3. This function MUST return a bool, True to read - the partition or False to ignore it. Ignored if dataset=False. - :param columns: Names of columns to read from the file(s). - :param validate_schema: Check that individual file schemas are all the - same / compatible. Schemas within a folder prefix should all be the - same. Disable if you have schemas that are different and want to - disable this check. - :param last_modified_begin: Filter the s3 files by the Last modified - date of the object. The filter is applied only after list all s3 - files. - :param last_modified_end: Filter the s3 files by the Last modified date - of the object. The filter is applied only after list all s3 files. - :param days: Number of days to filter. - :type path: Union[str, List[str]] - :type partition_filter: Callable[[Dict[str, str]], bool], optional - :type columns: List[str], optional - :type validate_schema: bool, optional - :type last_modified_begin: datetime, optional - :type last_modified_end: datetime, optional - :type days: integer, optional - :returns: Pandas DataFrame or None if DataFrame cannot be fetched. - :rtype: DataFrame - """ - df = None - start = time() - if days: - last_modified_begin = datetime.now(tz=UTC) - timedelta(days=days) - try: - df = wr.s3.read_parquet( - path=path, - path_suffix="parquet", - ignore_empty=True, - validate_schema=validate_schema, - use_threads=True, - dataset=True, - columns=columns, - partition_filter=partition_filter, - last_modified_begin=last_modified_begin, - last_modified_end=last_modified_end - ) - if self._debug: - df.info(verbose=True, memory_usage='deep') - logging.info( - u"\n" - f"Creation of dataframe {path} took: {time() - start}" - u"\n" - ) - except NoFilesFound as err: - logging.error(f"No parquets found.\n{err}") - except EmptyDataFrame as err: - logging.error(f"No data.\n{err}") - - self._data = df - return df - - def check_datasets(self, days: int=None): - """Read structure from parquet. - - :param days: Number of days back to the past for which the data will be - read. - :type days: int - """ - self._get_list_of_files(path=self._get_path("trending"), days=days) - self._get_list_of_files(path=self._get_path("statistics"), days=days) - - def read_stats(self, days: int=None) -> tuple: - """Read statistics from parquet. - - It reads from: - - Suite Result Analysis (SRA) partition, - - NDRPDR trending partition, - - MRR trending partition. - - :param days: Number of days back to the past for which the data will be - read. - :type days: int - :returns: tuple of pandas DataFrame-s with data read from specified - parquets. - :rtype: tuple of pandas DataFrame-s - """ - - l_stats = lambda part: True if part["stats_type"] == "sra" else False - l_mrr = lambda part: True if part["test_type"] == "mrr" else False - l_ndrpdr = lambda part: True if part["test_type"] == "ndrpdr" else False - - return ( - self._create_dataframe_from_parquet( - path=self._get_path("statistics"), - partition_filter=l_stats, - columns=self._get_columns("statistics"), - days=days - ), - self._create_dataframe_from_parquet( - path=self._get_path("statistics-trending-mrr"), - partition_filter=l_mrr, - columns=self._get_columns("statistics-trending-mrr"), - days=days - ), - self._create_dataframe_from_parquet( - path=self._get_path("statistics-trending-ndrpdr"), - partition_filter=l_ndrpdr, - columns=self._get_columns("statistics-trending-ndrpdr"), - days=days - ) - ) - - def read_trending_mrr(self, days: int=None) -> DataFrame: - """Read MRR data partition from parquet. - - :param days: Number of days back to the past for which the data will be - read. - :type days: int - :returns: Pandas DataFrame with read data. - :rtype: DataFrame - """ - - lambda_f = lambda part: True if part["test_type"] == "mrr" else False - - return self._create_dataframe_from_parquet( - path=self._get_path("trending-mrr"), - partition_filter=lambda_f, - columns=self._get_columns("trending-mrr"), - days=days - ) - - def read_trending_ndrpdr(self, days: int=None) -> DataFrame: - """Read NDRPDR data partition from iterative parquet. - - :param days: Number of days back to the past for which the data will be - read. - :type days: int - :returns: Pandas DataFrame with read data. - :rtype: DataFrame - """ - - lambda_f = lambda part: True if part["test_type"] == "ndrpdr" else False - - return self._create_dataframe_from_parquet( - path=self._get_path("trending-ndrpdr"), - partition_filter=lambda_f, - columns=self._get_columns("trending-ndrpdr"), - days=days - ) - - def read_iterative_mrr(self, release: str) -> DataFrame: - """Read MRR data partition from iterative parquet. - - :param release: The CSIT release from which the data will be read. - :type release: str - :returns: Pandas DataFrame with read data. - :rtype: DataFrame - """ - - lambda_f = lambda part: True if part["test_type"] == "mrr" else False - - return self._create_dataframe_from_parquet( - path=self._get_path("iterative-mrr").format(release=release), - partition_filter=lambda_f, - columns=self._get_columns("iterative-mrr") - ) - - def read_iterative_ndrpdr(self, release: str) -> DataFrame: - """Read NDRPDR data partition from parquet. - - :param release: The CSIT release from which the data will be read. - :type release: str - :returns: Pandas DataFrame with read data. - :rtype: DataFrame - """ - - lambda_f = lambda part: True if part["test_type"] == "ndrpdr" else False - - return self._create_dataframe_from_parquet( - path=self._get_path("iterative-ndrpdr").format(release=release), - partition_filter=lambda_f, - columns=self._get_columns("iterative-ndrpdr") - ) diff --git a/resources/tools/dash/app/pal/data/data.yaml b/resources/tools/dash/app/pal/data/data.yaml deleted file mode 100644 index 396f1b1638..0000000000 --- a/resources/tools/dash/app/pal/data/data.yaml +++ /dev/null @@ -1,117 +0,0 @@ -statistics: - path: s3://fdio-docs-s3-cloudfront-index/csit/parquet/stats - columns: - - job - - build - - start_time - - duration -statistics-trending-ndrpdr: - path: s3://fdio-docs-s3-cloudfront-index/csit/parquet/trending - columns: - - job - - build - - dut_type - - dut_version - - hosts - - start_time - - passed - - test_id - - result_pdr_lower_rate_value - - result_ndr_lower_rate_value -statistics-trending-mrr: - path: s3://fdio-docs-s3-cloudfront-index/csit/parquet/trending - columns: - - job - - build - - dut_type - - dut_version - - hosts - - start_time - - passed - - test_id - - result_receive_rate_rate_avg -trending: - path: s3://fdio-docs-s3-cloudfront-index/csit/parquet/trending - columns: - - job - - build - - start_time -trending-mrr: - path: s3://fdio-docs-s3-cloudfront-index/csit/parquet/trending - columns: - - job - - build - - dut_type - - dut_version - - hosts - - start_time - - passed - - test_id - - version - - result_receive_rate_rate_avg - - result_receive_rate_rate_stdev - - result_receive_rate_rate_unit -trending-ndrpdr: - path: s3://fdio-docs-s3-cloudfront-index/csit/parquet/trending - columns: - - job - - build - - dut_type - - dut_version - - hosts - - start_time - - passed - - test_id - - version - - result_pdr_lower_rate_unit - - result_pdr_lower_rate_value - - result_ndr_lower_rate_unit - - result_ndr_lower_rate_value - - result_latency_reverse_pdr_90_hdrh - - result_latency_reverse_pdr_50_hdrh - - result_latency_reverse_pdr_10_hdrh - - result_latency_reverse_pdr_0_hdrh - - result_latency_forward_pdr_90_hdrh - - result_latency_forward_pdr_50_avg - - result_latency_forward_pdr_50_hdrh - - result_latency_forward_pdr_50_unit - - result_latency_forward_pdr_10_hdrh - - result_latency_forward_pdr_0_hdrh -iterative-mrr: - path: s3://fdio-docs-s3-cloudfront-index/csit/parquet/iterative_{release} - columns: - - job - - build - - dut_type - - dut_version - - hosts - - start_time - - passed - - test_id - - version - - result_receive_rate_rate_avg - - result_receive_rate_rate_stdev - - result_receive_rate_rate_unit - - result_receive_rate_rate_values -iterative-ndrpdr: - path: s3://fdio-docs-s3-cloudfront-index/csit/parquet/iterative_{release} - columns: - - job - - build - - dut_type - - dut_version - - hosts - - start_time - - passed - - test_id - - version - - result_pdr_lower_rate_unit - - result_pdr_lower_rate_value - - result_ndr_lower_rate_unit - - result_ndr_lower_rate_value - - result_latency_forward_pdr_50_avg - - result_latency_forward_pdr_50_unit -# coverage-ndrpdr: -# path: str -# columns: -# - list diff --git a/resources/tools/dash/app/pal/debug.py b/resources/tools/dash/app/pal/debug.py deleted file mode 100644 index 9d46d2a111..0000000000 --- a/resources/tools/dash/app/pal/debug.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2022 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Debug class. Only for internal debugging puproses. -""" - -import logging - -from data.data import Data -from utils.constants import Constants as C - - -logging.basicConfig( - format=u"%(asctime)s: %(levelname)s: %(message)s", - datefmt=u"%Y/%m/%d %H:%M:%S", - level=logging.INFO -) - -# Set the time period for data fetch -if C.TIME_PERIOD is None or C.TIME_PERIOD > C.MAX_TIME_PERIOD: - time_period = C.MAX_TIME_PERIOD -else: - time_period = C.TIME_PERIOD - -#data_mrr = Data( -# data_spec_file=C.DATA_SPEC_FILE, -# debug=True -#).read_trending_mrr(days=time_period) -# -#data_ndrpdr = Data( -# data_spec_file=C.DATA_SPEC_FILE, -# debug=True -#).read_trending_ndrpdr(days=time_period) - -data_list = Data( - data_spec_file=C.DATA_SPEC_FILE, - debug=True -).check_datasets(days=time_period) \ No newline at end of file diff --git a/resources/tools/dash/app/pal/news/__init__.py b/resources/tools/dash/app/pal/news/__init__.py deleted file mode 100644 index 5692432123..0000000000 --- a/resources/tools/dash/app/pal/news/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2022 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. diff --git a/resources/tools/dash/app/pal/news/layout.py b/resources/tools/dash/app/pal/news/layout.py deleted file mode 100644 index cd1618d719..0000000000 --- a/resources/tools/dash/app/pal/news/layout.py +++ /dev/null @@ -1,522 +0,0 @@ -# Copyright (c) 2022 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Plotly Dash HTML layout override. -""" - -import logging -import pandas as pd -import dash_bootstrap_components as dbc - -from flask import Flask -from dash import dcc -from dash import html -from dash import callback_context -from dash import Input, Output -from yaml import load, FullLoader, YAMLError - -from ..data.data import Data -from ..utils.constants import Constants as C -from ..utils.utils import classify_anomalies, show_tooltip, gen_new_url -from ..utils.url_processing import url_decode -from ..data.data import Data -from .tables import table_summary - - -class Layout: - """The layout of the dash app and the callbacks. - """ - - def __init__(self, app: Flask, html_layout_file: str, data_spec_file: str, - tooltip_file: str) -> None: - """Initialization: - - save the input parameters, - - read and pre-process the data, - - prepare data for the control panel, - - read HTML layout file, - - read tooltips from the tooltip file. - - :param app: Flask application running the dash application. - :param html_layout_file: Path and name of the file specifying the HTML - layout of the dash application. - :param data_spec_file: Path and name of the file specifying the data to - be read from parquets for this application. - :param tooltip_file: Path and name of the yaml file specifying the - tooltips. - :type app: Flask - :type html_layout_file: str - :type data_spec_file: str - :type tooltip_file: str - """ - - # Inputs - self._app = app - self._html_layout_file = html_layout_file - self._data_spec_file = data_spec_file - self._tooltip_file = tooltip_file - - # Read the data: - data_stats, data_mrr, data_ndrpdr = Data( - data_spec_file=self._data_spec_file, - debug=True - ).read_stats(days=C.NEWS_TIME_PERIOD) - - df_tst_info = pd.concat([data_mrr, data_ndrpdr], ignore_index=True) - - # Prepare information for the control panel: - self._jobs = sorted(list(df_tst_info["job"].unique())) - d_job_info = { - "job": list(), - "dut": list(), - "ttype": list(), - "cadence": list(), - "tbed": list() - } - for job in self._jobs: - lst_job = job.split("-") - d_job_info["job"].append(job) - d_job_info["dut"].append(lst_job[1]) - d_job_info["ttype"].append(lst_job[3]) - d_job_info["cadence"].append(lst_job[4]) - d_job_info["tbed"].append("-".join(lst_job[-2:])) - self.job_info = pd.DataFrame.from_dict(d_job_info) - - # Pre-process the data: - - def _create_test_name(test: str) -> str: - lst_tst = test.split(".") - suite = lst_tst[-2].replace("2n1l-", "").replace("1n1l-", "").\ - replace("2n-", "") - return f"{suite.split('-')[0]}-{lst_tst[-1]}" - - def _get_rindex(array: list, itm: any) -> int: - return len(array) - 1 - array[::-1].index(itm) - - tst_info = { - "job": list(), - "build": list(), - "start": list(), - "dut_type": list(), - "dut_version": list(), - "hosts": list(), - "failed": list(), - "regressions": list(), - "progressions": list() - } - for job in self._jobs: - # Create lists of failed tests: - df_job = df_tst_info.loc[(df_tst_info["job"] == job)] - last_build = str(max(pd.to_numeric(df_job["build"].unique()))) - df_build = df_job.loc[(df_job["build"] == last_build)] - tst_info["job"].append(job) - tst_info["build"].append(last_build) - tst_info["start"].append(data_stats.loc[ - (data_stats["job"] == job) & - (data_stats["build"] == last_build) - ]["start_time"].iloc[-1].strftime('%Y-%m-%d %H:%M')) - tst_info["dut_type"].append(df_build["dut_type"].iloc[-1]) - tst_info["dut_version"].append(df_build["dut_version"].iloc[-1]) - tst_info["hosts"].append(df_build["hosts"].iloc[-1]) - failed_tests = df_build.loc[(df_build["passed"] == False)]\ - ["test_id"].to_list() - l_failed = list() - try: - for tst in failed_tests: - l_failed.append(_create_test_name(tst)) - except KeyError: - l_failed = list() - tst_info["failed"].append(sorted(l_failed)) - - # Create lists of regressions and progressions: - l_reg = list() - l_prog = list() - - tests = df_job["test_id"].unique() - for test in tests: - tst_data = df_job.loc[df_job["test_id"] == test].sort_values( - by="start_time", ignore_index=True) - x_axis = tst_data["start_time"].tolist() - if "-ndrpdr" in test: - tst_data = tst_data.dropna( - subset=["result_pdr_lower_rate_value", ] - ) - if tst_data.empty: - continue - try: - anomalies, _, _ = classify_anomalies({ - k: v for k, v in zip( - x_axis, - tst_data["result_ndr_lower_rate_value"].tolist() - ) - }) - except ValueError: - continue - if "progression" in anomalies: - l_prog.append(( - _create_test_name(test).replace("-ndrpdr", "-ndr"), - x_axis[_get_rindex(anomalies, "progression")] - )) - if "regression" in anomalies: - l_reg.append(( - _create_test_name(test).replace("-ndrpdr", "-ndr"), - x_axis[_get_rindex(anomalies, "regression")] - )) - try: - anomalies, _, _ = classify_anomalies({ - k: v for k, v in zip( - x_axis, - tst_data["result_pdr_lower_rate_value"].tolist() - ) - }) - except ValueError: - continue - if "progression" in anomalies: - l_prog.append(( - _create_test_name(test).replace("-ndrpdr", "-pdr"), - x_axis[_get_rindex(anomalies, "progression")] - )) - if "regression" in anomalies: - l_reg.append(( - _create_test_name(test).replace("-ndrpdr", "-pdr"), - x_axis[_get_rindex(anomalies, "regression")] - )) - else: # mrr - tst_data = tst_data.dropna( - subset=["result_receive_rate_rate_avg", ] - ) - if tst_data.empty: - continue - try: - anomalies, _, _ = classify_anomalies({ - k: v for k, v in zip( - x_axis, - tst_data["result_receive_rate_rate_avg"].\ - tolist() - ) - }) - except ValueError: - continue - if "progression" in anomalies: - l_prog.append(( - _create_test_name(test), - x_axis[_get_rindex(anomalies, "progression")] - )) - if "regression" in anomalies: - l_reg.append(( - _create_test_name(test), - x_axis[_get_rindex(anomalies, "regression")] - )) - - tst_info["regressions"].append( - sorted(l_reg, key=lambda k: k[1], reverse=True)) - tst_info["progressions"].append( - sorted(l_prog, key=lambda k: k[1], reverse=True)) - - self._data = pd.DataFrame.from_dict(tst_info) - - # Read from files: - self._html_layout = str() - self._tooltips = dict() - - try: - with open(self._html_layout_file, "r") as file_read: - self._html_layout = file_read.read() - except IOError as err: - raise RuntimeError( - f"Not possible to open the file {self._html_layout_file}\n{err}" - ) - - try: - with open(self._tooltip_file, "r") as file_read: - self._tooltips = load(file_read, Loader=FullLoader) - except IOError as err: - logging.warning( - f"Not possible to open the file {self._tooltip_file}\n{err}" - ) - except YAMLError as err: - logging.warning( - f"An error occurred while parsing the specification file " - f"{self._tooltip_file}\n{err}" - ) - - self._default_period = C.NEWS_SHORT - self._default_active = (False, True, False) - self._default_table = \ - table_summary(self._data, self._jobs, self._default_period) - - # Callbacks: - if self._app is not None and hasattr(self, 'callbacks'): - self.callbacks(self._app) - - @property - def html_layout(self) -> dict: - return self._html_layout - - def add_content(self): - """Top level method which generated the web page. - - It generates: - - Store for user input data, - - Navigation bar, - - Main area with control panel and ploting area. - - If no HTML layout is provided, an error message is displayed instead. - - :returns: The HTML div with the whole page. - :rtype: html.Div - """ - - if self.html_layout: - return html.Div( - id="div-main", - className="small", - children=[ - dcc.Location(id="url", refresh=False), - dbc.Row( - id="row-navbar", - class_name="g-0", - children=[ - self._add_navbar(), - ] - ), - dbc.Row( - id="row-main", - class_name="g-0", - children=[ - self._add_ctrl_col(), - self._add_plotting_col(), - ] - ) - ] - ) - else: - return html.Div( - id="div-main-error", - children=[ - dbc.Alert( - [ - "An Error Occured", - ], - color="danger", - ), - ] - ) - - def _add_navbar(self): - """Add nav element with navigation panel. It is placed on the top. - - :returns: Navigation bar. - :rtype: dbc.NavbarSimple - """ - - return dbc.NavbarSimple( - id="navbarsimple-main", - children=[ - dbc.NavItem( - dbc.NavLink( - "Continuous Performance News", - disabled=True, - external_link=True, - href="#" - ) - ) - ], - brand="Dashboard", - brand_href="/", - brand_external_link=True, - class_name="p-2", - fluid=True, - ) - - def _add_ctrl_col(self) -> dbc.Col: - """Add column with control panel. It is placed on the left side. - - :returns: Column with the control panel. - :rtype: dbc.Col - """ - - return dbc.Col( - id="col-controls", - children=[ - self._add_ctrl_panel(), - ], - ) - - def _add_plotting_col(self) -> dbc.Col: - """Add column with tables. It is placed on the right side. - - :returns: Column with tables. - :rtype: dbc.Col - """ - - return dbc.Col( - id="col-plotting-area", - children=[ - dcc.Loading( - children=[ - dbc.Row( # Failed tests - id="row-table", - class_name="g-0 p-2", - children=self._default_table - ), - dbc.Row( - class_name="g-0 p-2", - align="center", - justify="start", - children=[ - dbc.InputGroup( - class_name="me-1", - children=[ - dbc.InputGroupText( - style=C.URL_STYLE, - children=show_tooltip( - self._tooltips, - "help-url", "URL", - "input-url" - ) - ), - dbc.Input( - id="input-url", - readonly=True, - type="url", - style=C.URL_STYLE, - value="" - ) - ] - ) - ] - ) - ] - ) - ], - width=9, - ) - - def _add_ctrl_panel(self) -> dbc.Row: - """Add control panel. - - :returns: Control panel. - :rtype: dbc.Row - """ - return dbc.Row( - id="row-ctrl-panel", - class_name="g-0", - children=[ - dbc.Row( - class_name="g-0 p-2", - children=[ - dbc.Row( - class_name="g-0", - children=[ - dbc.Label( - class_name="g-0", - children=show_tooltip(self._tooltips, - "help-summary-period", "Window") - ), - dbc.Row( - dbc.ButtonGroup( - id="bg-time-period", - class_name="g-0", - children=[ - dbc.Button( - id="period-last", - children="Last Run", - className="me-1", - outline=True, - color="info" - ), - dbc.Button( - id="period-short", - children=\ - f"Last {C.NEWS_SHORT} Runs", - className="me-1", - outline=True, - active=True, - color="info" - ), - dbc.Button( - id="period-long", - children="All Runs", - className="me-1", - outline=True, - color="info" - ) - ] - ) - ) - ] - ) - ] - ) - ] - ) - - def callbacks(self, app): - """Callbacks for the whole application. - - :param app: The application. - :type app: Flask - """ - - @app.callback( - Output("row-table", "children"), - Output("input-url", "value"), - Output("period-last", "active"), - Output("period-short", "active"), - Output("period-long", "active"), - Input("period-last", "n_clicks"), - Input("period-short", "n_clicks"), - Input("period-long", "n_clicks"), - Input("url", "href") - ) - def _update_application(btn_last: int, btn_short: int, btn_long: int, - href: str) -> tuple: - """Update the application when the event is detected. - - :returns: New values for web page elements. - :rtype: tuple - """ - - _, _, _ = btn_last, btn_short, btn_long - - periods = { - "period-last": C.NEWS_LAST, - "period-short": C.NEWS_SHORT, - "period-long": C.NEWS_LONG - } - actives = { - "period-last": (True, False, False), - "period-short": (False, True, False), - "period-long": (False, False, True) - } - - # Parse the url: - parsed_url = url_decode(href) - if parsed_url: - url_params = parsed_url["params"] - else: - url_params = None - - trigger_id = callback_context.triggered[0]["prop_id"].split(".")[0] - if trigger_id == "url" and url_params: - trigger_id = url_params.get("period", list())[0] - - period = periods.get(trigger_id, self._default_period) - active = actives.get(trigger_id, self._default_active) - - ret_val = [ - table_summary(self._data, self._jobs, period), - gen_new_url(parsed_url, {"period": trigger_id}) - ] - ret_val.extend(active) - return ret_val diff --git a/resources/tools/dash/app/pal/news/news.py b/resources/tools/dash/app/pal/news/news.py deleted file mode 100644 index a0d05f1483..0000000000 --- a/resources/tools/dash/app/pal/news/news.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (c) 2022 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Instantiate the News Dash application. -""" -import dash - -from ..utils.constants import Constants as C -from .layout import Layout - - -def init_news(server): - """Create a Plotly Dash dashboard. - - :param server: Flask server. - :type server: Flask - :returns: Dash app server. - :rtype: Dash - """ - - dash_app = dash.Dash( - server=server, - routes_pathname_prefix=C.NEWS_ROUTES_PATHNAME_PREFIX, - external_stylesheets=C.EXTERNAL_STYLESHEETS - ) - - layout = Layout( - app=dash_app, - html_layout_file=C.NEWS_HTML_LAYOUT_FILE, - data_spec_file=C.DATA_SPEC_FILE, - tooltip_file=C.TOOLTIP_FILE, - ) - dash_app.index_string = layout.html_layout - dash_app.layout = layout.add_content() - - return dash_app.server diff --git a/resources/tools/dash/app/pal/news/tables.py b/resources/tools/dash/app/pal/news/tables.py deleted file mode 100644 index 7c0cc66eda..0000000000 --- a/resources/tools/dash/app/pal/news/tables.py +++ /dev/null @@ -1,176 +0,0 @@ -# Copyright (c) 2022 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""The tables with news. -""" - -import pandas as pd -import dash_bootstrap_components as dbc - -from datetime import datetime, timedelta - - -def _table_info(job_data: pd.DataFrame) -> dbc.Table: - """Generates table with info about the job. - - :param job_data: Dataframe with information about the job. - :type job_data: pandas.DataFrame - :returns: Table with job info. - :rtype: dbc.Table - """ - return dbc.Table.from_dataframe( - pd.DataFrame.from_dict( - { - "Job": job_data["job"], - "Last Build": job_data["build"], - "Date": job_data["start"], - "DUT": job_data["dut_type"], - "DUT Version": job_data["dut_version"], - "Hosts": ", ".join(job_data["hosts"].to_list()[0]) - } - ), - bordered=True, - striped=True, - hover=True, - size="sm", - color="info" - ) - - -def _table_failed(job_data: pd.DataFrame, failed: list) -> dbc.Table: - """Generates table with failed tests from the last run of the job. - - :param job_data: Dataframe with information about the job. - :param failed: List of failed tests. - :type job_data: pandas.DataFrame - :type failed: list - :returns: Table with fialed tests. - :rtype: dbc.Table - """ - return dbc.Table.from_dataframe( - pd.DataFrame.from_dict( - { - ( - f"Last Failed Tests on " - f"{job_data['start'].values[0]} ({len(failed)})" - ): failed - } - ), - bordered=True, - striped=True, - hover=True, - size="sm", - color="danger" - ) - - -def _table_gressions(itms: dict, color: str) -> dbc.Table: - """Generates table with regressions. - - :param itms: Dictionary with items (regressions or progressions) and their - last occurence. - :param color: Color of the table. - :type regressions: dict - :type color: str - :returns: The table with regressions. - :rtype: dbc.Table - """ - return dbc.Table.from_dataframe( - pd.DataFrame.from_dict(itms), - bordered=True, - striped=True, - hover=True, - size="sm", - color=color - ) - - -def table_news(data: pd.DataFrame, job: str, period: int) -> list: - """Generates the tables with news: - 1. Falied tests from the last run - 2. Regressions and progressions calculated from the last C.NEWS_TIME_PERIOD - days. - - :param data: Trending data with calculated annomalies to be displayed in the - tables. - :param job: The job name. - :param period: The time period (nr of days from now) taken into account. - :type data: pandas.DataFrame - :type job: str - :type period: int - :returns: List of tables. - :rtype: list - """ - - last_day = datetime.utcnow() - timedelta(days=period) - r_list = list() - job_data = data.loc[(data["job"] == job)] - r_list.append(_table_info(job_data)) - - failed = job_data["failed"].to_list()[0] - if failed: - r_list.append(_table_failed(job_data, failed)) - - title = f"Regressions in the last {period} days" - regressions = {title: list(), "Last Regression": list()} - for itm in job_data["regressions"].to_list()[0]: - if itm[1] < last_day: - break - regressions[title].append(itm[0]) - regressions["Last Regression"].append( - itm[1].strftime('%Y-%m-%d %H:%M')) - if regressions["Last Regression"]: - r_list.append(_table_gressions(regressions, "warning")) - - title = f"Progressions in the last {period} days" - progressions = {title: list(), "Last Progression": list()} - for itm in job_data["progressions"].to_list()[0]: - if itm[1] < last_day: - break - progressions[title].append(itm[0]) - progressions["Last Progression"].append( - itm[1].strftime('%Y-%m-%d %H:%M')) - if progressions["Last Progression"]: - r_list.append(_table_gressions(progressions, "success")) - - return r_list - - -def table_summary(data: pd.DataFrame, jobs: list, period: int) -> list: - """Generates summary (failed tests, regressions and progressions) from the - last week. - - :param data: Trending data with calculated annomalies to be displayed in the - tables. - :param jobs: List of jobs. - :params period: The time period for the summary table. - :type data: pandas.DataFrame - :type job: str - :type period: int - :returns: List of tables. - :rtype: list - """ - - return [ - dbc.Accordion( - children=[ - dbc.AccordionItem( - title=job, - children=table_news(data, job, period) - ) for job in jobs - ], - class_name="gy-2 p-0", - start_collapsed=True, - always_open=True - ) - ] diff --git a/resources/tools/dash/app/pal/report/__init__.py b/resources/tools/dash/app/pal/report/__init__.py deleted file mode 100644 index 5692432123..0000000000 --- a/resources/tools/dash/app/pal/report/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2022 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. diff --git a/resources/tools/dash/app/pal/report/graphs.py b/resources/tools/dash/app/pal/report/graphs.py deleted file mode 100644 index 36f28d09e8..0000000000 --- a/resources/tools/dash/app/pal/report/graphs.py +++ /dev/null @@ -1,275 +0,0 @@ -# Copyright (c) 2022 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -""" - -import re -import plotly.graph_objects as go -import pandas as pd - -from copy import deepcopy - -from ..utils.constants import Constants as C -from ..utils.utils import get_color - - -def get_short_version(version: str, dut_type: str="vpp") -> str: - """Returns the short version of DUT without build number. - - :param version: Original version string. - :param dut_type: DUT type. - :type version: str - :type dut_type: str - :returns: Short verion string. - :rtype: str - """ - - if dut_type in ("trex", "dpdk"): - return version - - s_version = str() - groups = re.search( - pattern=re.compile(r"^(\d{2}).(\d{2})-(rc0|rc1|rc2|release$)"), - string=version - ) - if groups: - try: - s_version = \ - f"{groups.group(1)}.{groups.group(2)}.{groups.group(3)}".\ - replace("release", "rls") - except IndexError: - pass - - return s_version - - -def select_iterative_data(data: pd.DataFrame, itm:dict) -> pd.DataFrame: - """Select the data for graphs and tables from the provided data frame. - - :param data: Data frame with data for graphs and tables. - :param itm: Item (in this case job name) which data will be selected from - the input data frame. - :type data: pandas.DataFrame - :type itm: str - :returns: A data frame with selected data. - :rtype: pandas.DataFrame - """ - - phy = itm["phy"].split("-") - if len(phy) == 4: - topo, arch, nic, drv = phy - if drv == "dpdk": - drv = "" - else: - drv += "-" - drv = drv.replace("_", "-") - else: - return None - - core = str() if itm["dut"] == "trex" else f"{itm['core']}" - ttype = "ndrpdr" if itm["testtype"] in ("ndr", "pdr") else itm["testtype"] - dut_v100 = "none" if itm["dut"] == "trex" else itm["dut"] - dut_v101 = itm["dut"] - - df = data.loc[( - (data["release"] == itm["rls"]) & - ( - ( - (data["version"] == "1.0.0") & - (data["dut_type"].str.lower() == dut_v100) - ) | - ( - (data["version"] == "1.0.1") & - (data["dut_type"].str.lower() == dut_v101) - ) - ) & - (data["test_type"] == ttype) & - (data["passed"] == True) - )] - regex_test = \ - f"^.*[.|-]{nic}.*{itm['framesize']}-{core}-{drv}{itm['test']}-{ttype}$" - df = df[ - (df.job.str.endswith(f"{topo}-{arch}")) & - (df.dut_version.str.contains(itm["dutver"].replace(".r", "-r").\ - replace("rls", "release"))) & - (df.test_id.str.contains(regex_test, regex=True)) - ] - - return df - - -def graph_iterative(data: pd.DataFrame, sel:dict, layout: dict, - normalize: bool) -> tuple: - """Generate the statistical box graph with iterative data (MRR, NDR and PDR, - for PDR also Latencies). - - :param data: Data frame with iterative data. - :param sel: Selected tests. - :param layout: Layout of plot.ly graph. - :param normalize: If True, the data is normalized to CPU frquency - Constants.NORM_FREQUENCY. - :param data: pandas.DataFrame - :param sel: dict - :param layout: dict - :param normalize: bool - :returns: Tuple of graphs - throughput and latency. - :rtype: tuple(plotly.graph_objects.Figure, plotly.graph_objects.Figure) - """ - - fig_tput = None - fig_lat = None - - tput_traces = list() - y_tput_max = 0 - lat_traces = list() - y_lat_max = 0 - x_lat = list() - show_latency = False - show_tput = False - for idx, itm in enumerate(sel): - itm_data = select_iterative_data(data, itm) - if itm_data.empty: - continue - phy = itm["phy"].split("-") - topo_arch = f"{phy[0]}-{phy[1]}" if len(phy) == 4 else str() - norm_factor = (C.NORM_FREQUENCY / C.FREQUENCY[topo_arch]) \ - if normalize else 1.0 - if itm["testtype"] == "mrr": - y_data_raw = itm_data[C.VALUE_ITER[itm["testtype"]]].to_list()[0] - y_data = [(y * norm_factor) for y in y_data_raw] - if len(y_data) > 0: - y_tput_max = \ - max(y_data) if max(y_data) > y_tput_max else y_tput_max - else: - y_data_raw = itm_data[C.VALUE_ITER[itm["testtype"]]].to_list() - y_data = [(y * norm_factor) for y in y_data_raw] - if y_data: - y_tput_max = \ - max(y_data) if max(y_data) > y_tput_max else y_tput_max - nr_of_samples = len(y_data) - tput_kwargs = dict( - y=y_data, - name=( - f"{idx + 1}. " - f"({nr_of_samples:02d} " - f"run{'s' if nr_of_samples > 1 else ''}) " - f"{itm['id']}" - ), - hoverinfo=u"y+name", - boxpoints="all", - jitter=0.3, - marker=dict(color=get_color(idx)) - ) - tput_traces.append(go.Box(**tput_kwargs)) - show_tput = True - - if itm["testtype"] == "pdr": - y_lat_row = itm_data[C.VALUE_ITER["pdr-lat"]].to_list() - y_lat = [(y / norm_factor) for y in y_lat_row] - if y_lat: - y_lat_max = max(y_lat) if max(y_lat) > y_lat_max else y_lat_max - nr_of_samples = len(y_lat) - lat_kwargs = dict( - y=y_lat, - name=( - f"{idx + 1}. " - f"({nr_of_samples:02d} " - f"run{u's' if nr_of_samples > 1 else u''}) " - f"{itm['id']}" - ), - hoverinfo="all", - boxpoints="all", - jitter=0.3, - marker=dict(color=get_color(idx)) - ) - x_lat.append(idx + 1) - lat_traces.append(go.Box(**lat_kwargs)) - show_latency = True - else: - lat_traces.append(go.Box()) - - if show_tput: - pl_tput = deepcopy(layout["plot-throughput"]) - pl_tput["xaxis"]["tickvals"] = [i for i in range(len(sel))] - pl_tput["xaxis"]["ticktext"] = [str(i + 1) for i in range(len(sel))] - if y_tput_max: - pl_tput["yaxis"]["range"] = [0, (int(y_tput_max / 1e6) + 1) * 1e6] - fig_tput = go.Figure(data=tput_traces, layout=pl_tput) - - if show_latency: - pl_lat = deepcopy(layout["plot-latency"]) - pl_lat["xaxis"]["tickvals"] = [i for i in range(len(x_lat))] - pl_lat["xaxis"]["ticktext"] = x_lat - if y_lat_max: - pl_lat["yaxis"]["range"] = [0, (int(y_lat_max / 10) + 1) * 10] - fig_lat = go.Figure(data=lat_traces, layout=pl_lat) - - return fig_tput, fig_lat - - -def table_comparison(data: pd.DataFrame, sel:dict, - normalize: bool) -> pd.DataFrame: - """Generate the comparison table with selected tests. - - :param data: Data frame with iterative data. - :param sel: Selected tests. - :param normalize: If True, the data is normalized to CPU frquency - Constants.NORM_FREQUENCY. - :param data: pandas.DataFrame - :param sel: dict - :param normalize: bool - :returns: Comparison table. - :rtype: pandas.DataFrame - """ - table = pd.DataFrame( - # { - # "Test Case": [ - # "64b-2t1c-avf-eth-l2xcbase-eth-2memif-1dcr", - # "64b-2t1c-avf-eth-l2xcbase-eth-2vhostvr1024-1vm-vppl2xc", - # "64b-2t1c-avf-ethip4udp-ip4base-iacl50sl-10kflows", - # "78b-2t1c-avf-ethip6-ip6scale2m-rnd "], - # "2106.0-8": [ - # "14.45 +- 0.08", - # "9.63 +- 0.05", - # "9.7 +- 0.02", - # "8.95 +- 0.06"], - # "2110.0-8": [ - # "14.45 +- 0.08", - # "9.63 +- 0.05", - # "9.7 +- 0.02", - # "8.95 +- 0.06"], - # "2110.0-9": [ - # "14.45 +- 0.08", - # "9.63 +- 0.05", - # "9.7 +- 0.02", - # "8.95 +- 0.06"], - # "2202.0-9": [ - # "14.45 +- 0.08", - # "9.63 +- 0.05", - # "9.7 +- 0.02", - # "8.95 +- 0.06"], - # "2110.0-9 vs 2110.0-8": [ - # "-0.23 +- 0.62", - # "-1.37 +- 1.3", - # "+0.08 +- 0.2", - # "-2.16 +- 0.83"], - # "2202.0-9 vs 2110.0-9": [ - # "+6.95 +- 0.72", - # "+5.35 +- 1.26", - # "+4.48 +- 1.48", - # "+4.09 +- 0.95"] - # } - ) - - return table diff --git a/resources/tools/dash/app/pal/report/layout.py b/resources/tools/dash/app/pal/report/layout.py deleted file mode 100644 index a556871084..0000000000 --- a/resources/tools/dash/app/pal/report/layout.py +++ /dev/null @@ -1,1494 +0,0 @@ -# Copyright (c) 2022 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Plotly Dash HTML layout override. -""" - -import logging -import pandas as pd -import dash_bootstrap_components as dbc - -from flask import Flask -from dash import dcc -from dash import html -from dash import callback_context, no_update, ALL -from dash import Input, Output, State -from dash.exceptions import PreventUpdate -from yaml import load, FullLoader, YAMLError -from copy import deepcopy -from ast import literal_eval - -from ..utils.constants import Constants as C -from ..utils.utils import show_tooltip, label, sync_checklists, list_tests, \ - gen_new_url, generate_options -from ..utils.url_processing import url_decode -from ..data.data import Data -from .graphs import graph_iterative, table_comparison, get_short_version, \ - select_iterative_data - - -class Layout: - """The layout of the dash app and the callbacks. - """ - - def __init__(self, app: Flask, releases: list, html_layout_file: str, - graph_layout_file: str, data_spec_file: str, tooltip_file: str) -> None: - """Initialization: - - save the input parameters, - - read and pre-process the data, - - prepare data for the control panel, - - read HTML layout file, - - read tooltips from the tooltip file. - - :param app: Flask application running the dash application. - :param releases: Lis of releases to be displayed. - :param html_layout_file: Path and name of the file specifying the HTML - layout of the dash application. - :param graph_layout_file: Path and name of the file with layout of - plot.ly graphs. - :param data_spec_file: Path and name of the file specifying the data to - be read from parquets for this application. - :param tooltip_file: Path and name of the yaml file specifying the - tooltips. - :type app: Flask - :type releases: list - :type html_layout_file: str - :type graph_layout_file: str - :type data_spec_file: str - :type tooltip_file: str - """ - - # Inputs - self._app = app - self.releases = releases - self._html_layout_file = html_layout_file - self._graph_layout_file = graph_layout_file - self._data_spec_file = data_spec_file - self._tooltip_file = tooltip_file - - # Read the data: - self._data = pd.DataFrame() - for rls in releases: - data_mrr = Data(self._data_spec_file, True).\ - read_iterative_mrr(release=rls.replace("csit", "rls")) - data_mrr["release"] = rls - data_ndrpdr = Data(self._data_spec_file, True).\ - read_iterative_ndrpdr(release=rls.replace("csit", "rls")) - data_ndrpdr["release"] = rls - self._data = pd.concat( - [self._data, data_mrr, data_ndrpdr], ignore_index=True) - - # Get structure of tests: - tbs = dict() - cols = ["job", "test_id", "test_type", "dut_version", "release"] - for _, row in self._data[cols].drop_duplicates().iterrows(): - rls = row["release"] - ttype = row["test_type"] - lst_job = row["job"].split("-") - dut = lst_job[1] - d_ver = get_short_version(row["dut_version"], dut) - tbed = "-".join(lst_job[-2:]) - lst_test_id = row["test_id"].split(".") - if dut == "dpdk": - area = "dpdk" - else: - area = "-".join(lst_test_id[3:-2]) - suite = lst_test_id[-2].replace("2n1l-", "").replace("1n1l-", "").\ - replace("2n-", "") - test = lst_test_id[-1] - nic = suite.split("-")[0] - for drv in C.DRIVERS: - if drv in test: - driver = drv.replace("-", "_") - test = test.replace(f"{drv}-", "") - break - else: - driver = "dpdk" - infra = "-".join((tbed, nic, driver)) - lst_test = test.split("-") - framesize = lst_test[0] - core = lst_test[1] if lst_test[1] else "8C" - test = "-".join(lst_test[2: -1]) - - if tbs.get(rls, None) is None: - tbs[rls] = dict() - if tbs[rls].get(dut, None) is None: - tbs[rls][dut] = dict() - if tbs[rls][dut].get(d_ver, None) is None: - tbs[rls][dut][d_ver] = dict() - if tbs[rls][dut][d_ver].get(infra, None) is None: - tbs[rls][dut][d_ver][infra] = dict() - if tbs[rls][dut][d_ver][infra].get(area, None) is None: - tbs[rls][dut][d_ver][infra][area] = dict() - if tbs[rls][dut][d_ver][infra][area].get(test, None) is None: - tbs[rls][dut][d_ver][infra][area][test] = dict() - tbs[rls][dut][d_ver][infra][area][test]["core"] = list() - tbs[rls][dut][d_ver][infra][area][test]["frame-size"] = list() - tbs[rls][dut][d_ver][infra][area][test]["test-type"] = list() - if core.upper() not in \ - tbs[rls][dut][d_ver][infra][area][test]["core"]: - tbs[rls][dut][d_ver][infra][area][test]["core"].append( - core.upper()) - if framesize.upper() not in \ - tbs[rls][dut][d_ver][infra][area][test]["frame-size"]: - tbs[rls][dut][d_ver][infra][area][test]["frame-size"].append( - framesize.upper()) - if ttype == "mrr": - if "MRR" not in \ - tbs[rls][dut][d_ver][infra][area][test]["test-type"]: - tbs[rls][dut][d_ver][infra][area][test]["test-type"].append( - "MRR") - elif ttype == "ndrpdr": - if "NDR" not in \ - tbs[rls][dut][d_ver][infra][area][test]["test-type"]: - tbs[rls][dut][d_ver][infra][area][test]["test-type"].extend( - ("NDR", "PDR", )) - self._spec_tbs = tbs - - # Read from files: - self._html_layout = "" - self._graph_layout = None - self._tooltips = dict() - - try: - with open(self._html_layout_file, "r") as file_read: - self._html_layout = file_read.read() - except IOError as err: - raise RuntimeError( - f"Not possible to open the file {self._html_layout_file}\n{err}" - ) - - try: - with open(self._graph_layout_file, "r") as file_read: - self._graph_layout = load(file_read, Loader=FullLoader) - except IOError as err: - raise RuntimeError( - f"Not possible to open the file {self._graph_layout_file}\n" - f"{err}" - ) - except YAMLError as err: - raise RuntimeError( - f"An error occurred while parsing the specification file " - f"{self._graph_layout_file}\n{err}" - ) - - try: - with open(self._tooltip_file, "r") as file_read: - self._tooltips = load(file_read, Loader=FullLoader) - except IOError as err: - logging.warning( - f"Not possible to open the file {self._tooltip_file}\n{err}" - ) - except YAMLError as err: - logging.warning( - f"An error occurred while parsing the specification file " - f"{self._tooltip_file}\n{err}" - ) - - # Callbacks: - if self._app is not None and hasattr(self, 'callbacks'): - self.callbacks(self._app) - - @property - def html_layout(self): - return self._html_layout - - @property - def spec_tbs(self): - return self._spec_tbs - - @property - def data(self): - return self._data - - @property - def layout(self): - return self._graph_layout - - def add_content(self): - """Top level method which generated the web page. - - It generates: - - Store for user input data, - - Navigation bar, - - Main area with control panel and ploting area. - - If no HTML layout is provided, an error message is displayed instead. - - :returns: The HTML div with the whole page. - :rtype: html.Div - """ - - if self.html_layout and self.spec_tbs: - return html.Div( - id="div-main", - className="small", - children=[ - dbc.Row( - id="row-navbar", - class_name="g-0", - children=[ - self._add_navbar(), - ] - ), - dcc.Loading( - dbc.Offcanvas( - class_name="w-50", - id="offcanvas-metadata", - title="Throughput And Latency", - placement="end", - is_open=False, - children=[ - dbc.Row(id="metadata-tput-lat"), - dbc.Row(id="metadata-hdrh-graph"), - ] - ) - ), - dbc.Row( - id="row-main", - class_name="g-0", - children=[ - dcc.Store(id="selected-tests"), - dcc.Store(id="control-panel"), - dcc.Location(id="url", refresh=False), - self._add_ctrl_col(), - self._add_plotting_col(), - ] - ) - ] - ) - else: - return html.Div( - id="div-main-error", - children=[ - dbc.Alert( - [ - "An Error Occured", - ], - color="danger", - ), - ] - ) - - def _add_navbar(self): - """Add nav element with navigation panel. It is placed on the top. - - :returns: Navigation bar. - :rtype: dbc.NavbarSimple - """ - return dbc.NavbarSimple( - id="navbarsimple-main", - children=[ - dbc.NavItem( - dbc.NavLink( - "Iterative Test Runs", - disabled=True, - external_link=True, - href="#" - ) - ) - ], - brand="Dashboard", - brand_href="/", - brand_external_link=True, - class_name="p-2", - fluid=True, - ) - - def _add_ctrl_col(self) -> dbc.Col: - """Add column with controls. It is placed on the left side. - - :returns: Column with the control panel. - :rtype: dbc.Col - """ - return dbc.Col( - id="col-controls", - children=[ - self._add_ctrl_panel(), - ], - ) - - def _add_plotting_col(self) -> dbc.Col: - """Add column with plots and tables. It is placed on the right side. - - :returns: Column with tables. - :rtype: dbc.Col - """ - return dbc.Col( - id="col-plotting-area", - children=[ - dcc.Loading( - children=[ - dbc.Row( # Graphs - class_name="g-0 p-2", - children=[ - dbc.Col( - dbc.Row( # Throughput - id="row-graph-tput", - class_name="g-0 p-2", - children=[C.PLACEHOLDER, ] - ), - width=6 - ), - dbc.Col( - dbc.Row( # Latency - id="row-graph-lat", - class_name="g-0 p-2", - children=[C.PLACEHOLDER, ] - ), - width=6 - ) - ] - ), - dbc.Row( # Tables - id="row-table", - class_name="g-0 p-2", - children=[C.PLACEHOLDER, ] - ), - dbc.Row( # Download - id="row-btn-download", - class_name="g-0 p-2", - children=[C.PLACEHOLDER, ] - ) - ] - ) - ], - width=9 - ) - - def _add_ctrl_panel(self) -> dbc.Row: - """Add control panel. - - :returns: Control panel. - :rtype: dbc.Row - """ - return dbc.Row( - id="row-ctrl-panel", - class_name="g-0 p-2", - children=[ - dbc.Row( - class_name="g-0", - children=[ - dbc.InputGroup( - [ - dbc.InputGroupText( - children=show_tooltip(self._tooltips, - "help-release", "CSIT Release") - ), - dbc.Select( - id="dd-ctrl-rls", - placeholder=("Select a Release..."), - options=sorted( - [ - {"label": k, "value": k} \ - for k in self.spec_tbs.keys() - ], - key=lambda d: d["label"] - ) - ) - ], - class_name="mb-3", - size="sm", - ), - ] - ), - dbc.Row( - class_name="g-0", - children=[ - dbc.InputGroup( - [ - dbc.InputGroupText( - children=show_tooltip(self._tooltips, - "help-dut", "DUT") - ), - dbc.Select( - id="dd-ctrl-dut", - placeholder=( - "Select a Device under Test..." - ) - ) - ], - class_name="mb-3", - size="sm", - ), - ] - ), - dbc.Row( - class_name="g-0", - children=[ - dbc.InputGroup( - [ - dbc.InputGroupText( - children=show_tooltip(self._tooltips, - "help-dut-ver", "DUT Version") - ), - dbc.Select( - id="dd-ctrl-dutver", - placeholder=( - "Select a Version of " - "Device under Test..." - ) - ) - ], - class_name="mb-3", - size="sm", - ), - ] - ), - dbc.Row( - class_name="g-0", - children=[ - dbc.InputGroup( - [ - dbc.InputGroupText( - children=show_tooltip(self._tooltips, - "help-infra", "Infra") - ), - dbc.Select( - id="dd-ctrl-phy", - placeholder=( - "Select a Physical Test Bed " - "Topology..." - ) - ) - ], - class_name="mb-3", - size="sm", - ), - ] - ), - dbc.Row( - class_name="g-0", - children=[ - dbc.InputGroup( - [ - dbc.InputGroupText( - children=show_tooltip(self._tooltips, - "help-area", "Area") - ), - dbc.Select( - id="dd-ctrl-area", - placeholder="Select an Area...", - disabled=True, - ), - ], - class_name="mb-3", - size="sm", - ), - ] - ), - dbc.Row( - class_name="g-0", - children=[ - dbc.InputGroup( - [ - dbc.InputGroupText( - children=show_tooltip(self._tooltips, - "help-test", "Test") - ), - dbc.Select( - id="dd-ctrl-test", - placeholder="Select a Test...", - disabled=True, - ), - ], - class_name="mb-3", - size="sm", - ), - ] - ), - dbc.Row( - id="row-ctrl-framesize", - class_name="gy-1", - children=[ - dbc.Label( - children=show_tooltip(self._tooltips, - "help-framesize", "Frame Size"), - class_name="p-0" - ), - dbc.Col( - children=[ - dbc.Checklist( - id="cl-ctrl-framesize-all", - options=C.CL_ALL_DISABLED, - inline=True, - switch=False - ), - ], - width=3 - ), - dbc.Col( - children=[ - dbc.Checklist( - id="cl-ctrl-framesize", - inline=True, - switch=False - ) - ] - ) - ] - ), - dbc.Row( - id="row-ctrl-core", - class_name="gy-1", - children=[ - dbc.Label( - children=show_tooltip(self._tooltips, - "help-cores", "Number of Cores"), - class_name="p-0" - ), - dbc.Col( - children=[ - dbc.Checklist( - id="cl-ctrl-core-all", - options=C.CL_ALL_DISABLED, - inline=False, - switch=False - ) - ], - width=3 - ), - dbc.Col( - children=[ - dbc.Checklist( - id="cl-ctrl-core", - inline=True, - switch=False - ) - ] - ) - ] - ), - dbc.Row( - id="row-ctrl-testtype", - class_name="gy-1", - children=[ - dbc.Label( - children=show_tooltip(self._tooltips, - "help-ttype", "Test Type"), - class_name="p-0" - ), - dbc.Col( - children=[ - dbc.Checklist( - id="cl-ctrl-testtype-all", - options=C.CL_ALL_DISABLED, - inline=True, - switch=False - ), - ], - width=3 - ), - dbc.Col( - children=[ - dbc.Checklist( - id="cl-ctrl-testtype", - inline=True, - switch=False - ) - ] - ) - ] - ), - dbc.Row( - id="row-ctrl-normalize", - class_name="gy-1", - children=[ - dbc.Label( - children=show_tooltip(self._tooltips, - "help-normalize", "Normalize"), - class_name="p-0" - ), - dbc.Col( - children=[ - dbc.Checklist( - id="cl-ctrl-normalize", - options=[{ - "value": "normalize", - "label": ( - "Normalize results to CPU" - "frequency 2GHz" - ) - }], - value=[], - inline=True, - switch=False - ), - ] - ) - ] - ), - dbc.Row( - class_name="gy-1 p-0", - children=[ - dbc.ButtonGroup( - [ - dbc.Button( - id="btn-ctrl-add", - children="Add Selected", - class_name="me-1", - color="info" - ) - ] - ) - ] - ), - dbc.Row( - id="row-card-sel-tests", - class_name="gy-1", - style=C.STYLE_DISABLED, - children=[ - dbc.Label( - "Selected tests", - class_name="p-0" - ), - dbc.Checklist( - class_name="overflow-auto", - id="cl-selected", - options=[], - inline=False, - style={"max-height": "20em"}, - ) - ], - ), - dbc.Row( - id="row-btns-sel-tests", - style=C.STYLE_DISABLED, - children=[ - dbc.ButtonGroup( - class_name="gy-2", - children=[ - dbc.Button( - id="btn-sel-remove", - children="Remove Selected", - class_name="w-100 me-1", - color="info", - disabled=False - ), - dbc.Button( - id="btn-sel-remove-all", - children="Remove All", - class_name="w-100 me-1", - color="info", - disabled=False - ), - ] - ) - ] - ), - ] - ) - - class ControlPanel: - """A class representing the control panel. - """ - - def __init__(self, panel: dict) -> None: - """Initialisation of the control pannel by default values. If - particular values are provided (parameter "panel") they are set - afterwards. - - :param panel: Custom values to be set to the control panel. - :param default: Default values to be set to the control panel. - :type panel: dict - :type defaults: dict - """ - - # Defines also the order of keys - self._defaults = { - "dd-rls-value": str(), - "dd-dut-options": list(), - "dd-dut-disabled": True, - "dd-dut-value": str(), - "dd-dutver-options": list(), - "dd-dutver-disabled": True, - "dd-dutver-value": str(), - "dd-phy-options": list(), - "dd-phy-disabled": True, - "dd-phy-value": str(), - "dd-area-options": list(), - "dd-area-disabled": True, - "dd-area-value": str(), - "dd-test-options": list(), - "dd-test-disabled": True, - "dd-test-value": str(), - "cl-core-options": list(), - "cl-core-value": list(), - "cl-core-all-value": list(), - "cl-core-all-options": C.CL_ALL_DISABLED, - "cl-framesize-options": list(), - "cl-framesize-value": list(), - "cl-framesize-all-value": list(), - "cl-framesize-all-options": C.CL_ALL_DISABLED, - "cl-testtype-options": list(), - "cl-testtype-value": list(), - "cl-testtype-all-value": list(), - "cl-testtype-all-options": C.CL_ALL_DISABLED, - "btn-add-disabled": True, - "cl-normalize-value": list(), - "cl-selected-options": list() - } - - self._panel = deepcopy(self._defaults) - if panel: - for key in self._defaults: - self._panel[key] = panel[key] - - @property - def defaults(self) -> dict: - return self._defaults - - @property - def panel(self) -> dict: - return self._panel - - def set(self, kwargs: dict) -> None: - """Set the values of the Control panel. - - :param kwargs: key - value pairs to be set. - :type kwargs: dict - :raises KeyError: If the key in kwargs is not present in the Control - panel. - """ - for key, val in kwargs.items(): - if key in self._panel: - self._panel[key] = val - else: - raise KeyError(f"The key {key} is not defined.") - - def get(self, key: str) -> any: - """Returns the value of a key from the Control panel. - - :param key: The key which value should be returned. - :type key: str - :returns: The value of the key. - :rtype: any - :raises KeyError: If the key in kwargs is not present in the Control - panel. - """ - return self._panel[key] - - def values(self) -> tuple: - """Returns the values from the Control panel as a list. - - :returns: The values from the Control panel. - :rtype: list - """ - return tuple(self._panel.values()) - - def callbacks(self, app): - """Callbacks for the whole application. - - :param app: The application. - :type app: Flask - """ - - def _generate_plotting_area(figs: tuple, table: pd.DataFrame, - url: str) -> tuple: - """Generate the plotting area with all its content. - - :param figs: Figures to be placed in the plotting area. - :param table: A table to be placed in the plotting area bellow the - figures. - :param utl: The URL to be placed in the plotting area bellow the - tables. - :type figs: tuple of plotly.graph_objects.Figure - :type table: pandas.DataFrame - :type url: str - :returns: tuple of elements to be shown in the plotting area. - :rtype: tuple - (dcc.Graph, dcc.Graph, dbc.Table, list(dbc.Col, dbc.Col)) - """ - - (fig_tput, fig_lat) = figs - - row_fig_tput = C.PLACEHOLDER - row_fig_lat = C.PLACEHOLDER - row_table = C.PLACEHOLDER - row_btn_dwnld = C.PLACEHOLDER - - if fig_tput: - row_fig_tput = [ - dcc.Graph( - id={"type": "graph", "index": "tput"}, - figure=fig_tput - ) - ] - row_btn_dwnld = [ - dbc.Col( # Download - width=2, - children=[ - dcc.Loading(children=[ - dbc.Button( - id="btn-download-data", - children=show_tooltip(self._tooltips, - "help-download", "Download Data"), - class_name="me-1", - color="info" - ), - dcc.Download(id="download-data") - ]), - ] - ), - dbc.Col( # Show URL - width=10, - children=[ - dbc.InputGroup( - class_name="me-1", - children=[ - dbc.InputGroupText( - style=C.URL_STYLE, - children=show_tooltip(self._tooltips, - "help-url", "URL", "input-url") - ), - dbc.Input( - id="input-url", - readonly=True, - type="url", - style=C.URL_STYLE, - value=url - ) - ] - ) - ] - ) - ] - if fig_lat: - row_fig_lat = [ - dcc.Graph( - id={"type": "graph", "index": "lat"}, - figure=fig_lat - ) - ] - if not table.empty: - row_table = [ - dbc.Table.from_dataframe( - table, - id={"type": "table", "index": "compare"}, - striped=True, - bordered=True, - hover=True - ) - ] - - return row_fig_tput, row_fig_lat, row_table, row_btn_dwnld - - @app.callback( - Output("control-panel", "data"), # Store - Output("selected-tests", "data"), # Store - Output("row-graph-tput", "children"), - Output("row-graph-lat", "children"), - Output("row-table", "children"), - Output("row-btn-download", "children"), - Output("row-card-sel-tests", "style"), - Output("row-btns-sel-tests", "style"), - Output("dd-ctrl-rls", "value"), - Output("dd-ctrl-dut", "options"), - Output("dd-ctrl-dut", "disabled"), - Output("dd-ctrl-dut", "value"), - Output("dd-ctrl-dutver", "options"), - Output("dd-ctrl-dutver", "disabled"), - Output("dd-ctrl-dutver", "value"), - Output("dd-ctrl-phy", "options"), - Output("dd-ctrl-phy", "disabled"), - Output("dd-ctrl-phy", "value"), - Output("dd-ctrl-area", "options"), - Output("dd-ctrl-area", "disabled"), - Output("dd-ctrl-area", "value"), - Output("dd-ctrl-test", "options"), - Output("dd-ctrl-test", "disabled"), - Output("dd-ctrl-test", "value"), - Output("cl-ctrl-core", "options"), - Output("cl-ctrl-core", "value"), - Output("cl-ctrl-core-all", "value"), - Output("cl-ctrl-core-all", "options"), - Output("cl-ctrl-framesize", "options"), - Output("cl-ctrl-framesize", "value"), - Output("cl-ctrl-framesize-all", "value"), - Output("cl-ctrl-framesize-all", "options"), - Output("cl-ctrl-testtype", "options"), - Output("cl-ctrl-testtype", "value"), - Output("cl-ctrl-testtype-all", "value"), - Output("cl-ctrl-testtype-all", "options"), - Output("btn-ctrl-add", "disabled"), - Output("cl-ctrl-normalize", "value"), - Output("cl-selected", "options"), # User selection - State("control-panel", "data"), # Store - State("selected-tests", "data"), # Store - State("cl-selected", "value"), # User selection - Input("dd-ctrl-rls", "value"), - Input("dd-ctrl-dut", "value"), - Input("dd-ctrl-dutver", "value"), - Input("dd-ctrl-phy", "value"), - Input("dd-ctrl-area", "value"), - Input("dd-ctrl-test", "value"), - Input("cl-ctrl-core", "value"), - Input("cl-ctrl-core-all", "value"), - Input("cl-ctrl-framesize", "value"), - Input("cl-ctrl-framesize-all", "value"), - Input("cl-ctrl-testtype", "value"), - Input("cl-ctrl-testtype-all", "value"), - Input("cl-ctrl-normalize", "value"), - Input("btn-ctrl-add", "n_clicks"), - Input("btn-sel-remove", "n_clicks"), - Input("btn-sel-remove-all", "n_clicks"), - Input("url", "href") - ) - def _update_ctrl_panel(cp_data: dict, store_sel: list, list_sel: list, - dd_rls: str, dd_dut: str, dd_dutver: str, dd_phy: str, dd_area: str, - dd_test: str, cl_core: list, cl_core_all: list, cl_framesize: list, - cl_framesize_all: list, cl_testtype: list, cl_testtype_all: list, - cl_normalize: list, btn_add: int, btn_remove: int, - btn_remove_all: int, href: str) -> tuple: - """Update the application when the event is detected. - - :param cp_data: Current status of the control panel stored in - browser. - :param store_sel: List of tests selected by user stored in the - browser. - :param list_sel: List of tests selected by the user shown in the - checklist. - :param dd_rls: Input - Releases. - :param dd_dut: Input - DUTs. - :param dd_dutver: Input - Version of DUT. - :param dd_phy: Input - topo- arch-nic-driver. - :param dd_area: Input - Tested area. - :param dd_test: Input - Test. - :param cl_core: Input - Number of cores. - :param cl_core_all: Input - All numbers of cores. - :param cl_framesize: Input - Frame sizes. - :param cl_framesize_all: Input - All frame sizes. - :param cl_testtype: Input - Test type (NDR, PDR, MRR). - :param cl_testtype_all: Input - All test types. - :param cl_normalize: Input - Normalize the results. - :param btn_add: Input - Button "Add Selected" tests. - :param btn_remove: Input - Button "Remove selected" tests. - :param btn_remove_all: Input - Button "Remove All" tests. - :param href: Input - The URL provided by the browser. - :type cp_data: dict - :type store_sel: list - :type list_sel: list - :type dd_rls: str - :type dd_dut: str - :type dd_dutver: str - :type dd_phy: str - :type dd_area: str - :type dd_test: str - :type cl_core: list - :type cl_core_all: list - :type cl_framesize: list - :type cl_framesize_all: list - :type cl_testtype: list - :type cl_testtype_all: list - :type cl_normalize: list - :type btn_add: int - :type btn_remove: int - :type btn_remove_all: int - :type href: str - :returns: New values for web page elements. - :rtype: tuple - """ - - ctrl_panel = self.ControlPanel(cp_data) - norm = cl_normalize - - # Parse the url: - parsed_url = url_decode(href) - if parsed_url: - url_params = parsed_url["params"] - else: - url_params = None - - row_fig_tput = no_update - row_fig_lat = no_update - row_table = no_update - row_btn_dwnld = no_update - row_card_sel_tests = no_update - row_btns_sel_tests = no_update - - trigger_id = callback_context.triggered[0]["prop_id"].split(".")[0] - - if trigger_id == "dd-ctrl-rls": - try: - options = \ - generate_options(sorted(self.spec_tbs[dd_rls].keys())) - disabled = False - except KeyError: - options = list() - disabled = True - ctrl_panel.set({ - "dd-rls-value": dd_rls, - "dd-dut-value": str(), - "dd-dut-options": options, - "dd-dut-disabled": disabled, - "dd-dutver-value": str(), - "dd-dutver-options": list(), - "dd-dutver-disabled": True, - "dd-phy-value": str(), - "dd-phy-options": list(), - "dd-phy-disabled": True, - "dd-area-value": str(), - "dd-area-options": list(), - "dd-area-disabled": True, - "dd-test-value": str(), - "dd-test-options": list(), - "dd-test-disabled": True, - "cl-core-options": list(), - "cl-core-value": list(), - "cl-core-all-value": list(), - "cl-core-all-options": C.CL_ALL_DISABLED, - "cl-framesize-options": list(), - "cl-framesize-value": list(), - "cl-framesize-all-value": list(), - "cl-framesize-all-options": C.CL_ALL_DISABLED, - "cl-testtype-options": list(), - "cl-testtype-value": list(), - "cl-testtype-all-value": list(), - "cl-testtype-all-options": C.CL_ALL_DISABLED - }) - elif trigger_id == "dd-ctrl-dut": - try: - rls = ctrl_panel.get("dd-rls-value") - dut = self.spec_tbs[rls][dd_dut] - options = generate_options(sorted(dut.keys())) - disabled = False - except KeyError: - options = list() - disabled = True - ctrl_panel.set({ - "dd-dut-value": dd_dut, - "dd-dutver-value": str(), - "dd-dutver-options": options, - "dd-dutver-disabled": disabled, - "dd-phy-value": str(), - "dd-phy-options": list(), - "dd-phy-disabled": True, - "dd-area-value": str(), - "dd-area-options": list(), - "dd-area-disabled": True, - "dd-test-value": str(), - "dd-test-options": list(), - "dd-test-disabled": True, - "cl-core-options": list(), - "cl-core-value": list(), - "cl-core-all-value": list(), - "cl-core-all-options": C.CL_ALL_DISABLED, - "cl-framesize-options": list(), - "cl-framesize-value": list(), - "cl-framesize-all-value": list(), - "cl-framesize-all-options": C.CL_ALL_DISABLED, - "cl-testtype-options": list(), - "cl-testtype-value": list(), - "cl-testtype-all-value": list(), - "cl-testtype-all-options": C.CL_ALL_DISABLED - }) - elif trigger_id == "dd-ctrl-dutver": - try: - rls = ctrl_panel.get("dd-rls-value") - dut = ctrl_panel.get("dd-dut-value") - dutver = self.spec_tbs[rls][dut][dd_dutver] - options = generate_options(sorted(dutver.keys())) - disabled = False - except KeyError: - options = list() - disabled = True - ctrl_panel.set({ - "dd-dutver-value": dd_dutver, - "dd-phy-value": str(), - "dd-phy-options": options, - "dd-phy-disabled": disabled, - "dd-area-value": str(), - "dd-area-options": list(), - "dd-area-disabled": True, - "dd-test-value": str(), - "dd-test-options": list(), - "dd-test-disabled": True, - "cl-core-options": list(), - "cl-core-value": list(), - "cl-core-all-value": list(), - "cl-core-all-options": C.CL_ALL_DISABLED, - "cl-framesize-options": list(), - "cl-framesize-value": list(), - "cl-framesize-all-value": list(), - "cl-framesize-all-options": C.CL_ALL_DISABLED, - "cl-testtype-options": list(), - "cl-testtype-value": list(), - "cl-testtype-all-value": list(), - "cl-testtype-all-options": C.CL_ALL_DISABLED - }) - elif trigger_id == "dd-ctrl-phy": - try: - rls = ctrl_panel.get("dd-rls-value") - dut = ctrl_panel.get("dd-dut-value") - dutver = ctrl_panel.get("dd-dutver-value") - phy = self.spec_tbs[rls][dut][dutver][dd_phy] - options = [{"label": label(v), "value": v} \ - for v in sorted(phy.keys())] - disabled = False - except KeyError: - options = list() - disabled = True - ctrl_panel.set({ - "dd-phy-value": dd_phy, - "dd-area-value": str(), - "dd-area-options": options, - "dd-area-disabled": disabled, - "dd-test-value": str(), - "dd-test-options": list(), - "dd-test-disabled": True, - "cl-core-options": list(), - "cl-core-value": list(), - "cl-core-all-value": list(), - "cl-core-all-options": C.CL_ALL_DISABLED, - "cl-framesize-options": list(), - "cl-framesize-value": list(), - "cl-framesize-all-value": list(), - "cl-framesize-all-options": C.CL_ALL_DISABLED, - "cl-testtype-options": list(), - "cl-testtype-value": list(), - "cl-testtype-all-value": list(), - "cl-testtype-all-options": C.CL_ALL_DISABLED - }) - elif trigger_id == "dd-ctrl-area": - try: - rls = ctrl_panel.get("dd-rls-value") - dut = ctrl_panel.get("dd-dut-value") - dutver = ctrl_panel.get("dd-dutver-value") - phy = ctrl_panel.get("dd-phy-value") - area = self.spec_tbs[rls][dut][dutver][phy][dd_area] - options = generate_options(sorted(area.keys())) - disabled = False - except KeyError: - options = list() - disabled = True - ctrl_panel.set({ - "dd-area-value": dd_area, - "dd-test-value": str(), - "dd-test-options": options, - "dd-test-disabled": disabled, - "cl-core-options": list(), - "cl-core-value": list(), - "cl-core-all-value": list(), - "cl-core-all-options": C.CL_ALL_DISABLED, - "cl-framesize-options": list(), - "cl-framesize-value": list(), - "cl-framesize-all-value": list(), - "cl-framesize-all-options": C.CL_ALL_DISABLED, - "cl-testtype-options": list(), - "cl-testtype-value": list(), - "cl-testtype-all-value": list(), - "cl-testtype-all-options": C.CL_ALL_DISABLED - }) - elif trigger_id == "dd-ctrl-test": - rls = ctrl_panel.get("dd-rls-value") - dut = ctrl_panel.get("dd-dut-value") - dutver = ctrl_panel.get("dd-dutver-value") - phy = ctrl_panel.get("dd-phy-value") - area = ctrl_panel.get("dd-area-value") - if all((rls, dut, dutver, phy, area, dd_test, )): - test = self.spec_tbs[rls][dut][dutver][phy][area][dd_test] - ctrl_panel.set({ - "dd-test-value": dd_test, - "cl-core-options": \ - generate_options(sorted(test["core"])), - "cl-core-value": list(), - "cl-core-all-value": list(), - "cl-core-all-options": C.CL_ALL_ENABLED, - "cl-framesize-options": \ - generate_options(sorted(test["frame-size"])), - "cl-framesize-value": list(), - "cl-framesize-all-value": list(), - "cl-framesize-all-options": C.CL_ALL_ENABLED, - "cl-testtype-options": \ - generate_options(sorted(test["test-type"])), - "cl-testtype-value": list(), - "cl-testtype-all-value": list(), - "cl-testtype-all-options": C.CL_ALL_ENABLED, - }) - elif trigger_id == "cl-ctrl-core": - val_sel, val_all = sync_checklists( - options=ctrl_panel.get("cl-core-options"), - sel=cl_core, - all=list(), - id="" - ) - ctrl_panel.set({ - "cl-core-value": val_sel, - "cl-core-all-value": val_all, - }) - elif trigger_id == "cl-ctrl-core-all": - val_sel, val_all = sync_checklists( - options = ctrl_panel.get("cl-core-options"), - sel=list(), - all=cl_core_all, - id="all" - ) - ctrl_panel.set({ - "cl-core-value": val_sel, - "cl-core-all-value": val_all, - }) - elif trigger_id == "cl-ctrl-framesize": - val_sel, val_all = sync_checklists( - options = ctrl_panel.get("cl-framesize-options"), - sel=cl_framesize, - all=list(), - id="" - ) - ctrl_panel.set({ - "cl-framesize-value": val_sel, - "cl-framesize-all-value": val_all, - }) - elif trigger_id == "cl-ctrl-framesize-all": - val_sel, val_all = sync_checklists( - options = ctrl_panel.get("cl-framesize-options"), - sel=list(), - all=cl_framesize_all, - id="all" - ) - ctrl_panel.set({ - "cl-framesize-value": val_sel, - "cl-framesize-all-value": val_all, - }) - elif trigger_id == "cl-ctrl-testtype": - val_sel, val_all = sync_checklists( - options = ctrl_panel.get("cl-testtype-options"), - sel=cl_testtype, - all=list(), - id="" - ) - ctrl_panel.set({ - "cl-testtype-value": val_sel, - "cl-testtype-all-value": val_all, - }) - elif trigger_id == "cl-ctrl-testtype-all": - val_sel, val_all = sync_checklists( - options = ctrl_panel.get("cl-testtype-options"), - sel=list(), - all=cl_testtype_all, - id="all" - ) - ctrl_panel.set({ - "cl-testtype-value": val_sel, - "cl-testtype-all-value": val_all, - }) - elif trigger_id == "btn-ctrl-add": - _ = btn_add - rls = ctrl_panel.get("dd-rls-value") - dut = ctrl_panel.get("dd-dut-value") - dutver = ctrl_panel.get("dd-dutver-value") - phy = ctrl_panel.get("dd-phy-value") - area = ctrl_panel.get("dd-area-value") - test = ctrl_panel.get("dd-test-value") - cores = ctrl_panel.get("cl-core-value") - framesizes = ctrl_panel.get("cl-framesize-value") - testtypes = ctrl_panel.get("cl-testtype-value") - # Add selected test to the list of tests in store: - if all((rls, dut, dutver, phy, area, test, cores, framesizes, - testtypes)): - if store_sel is None: - store_sel = list() - for core in cores: - for framesize in framesizes: - for ttype in testtypes: - if dut == "trex": - core = str() - tid = "-".join((rls, dut, dutver, - phy.replace('af_xdp', 'af-xdp'), area, - framesize.lower(), core.lower(), test, - ttype.lower())) - if tid not in [itm["id"] for itm in store_sel]: - store_sel.append({ - "id": tid, - "rls": rls, - "dut": dut, - "dutver": dutver, - "phy": phy, - "area": area, - "test": test, - "framesize": framesize.lower(), - "core": core.lower(), - "testtype": ttype.lower() - }) - store_sel = sorted(store_sel, key=lambda d: d["id"]) - row_card_sel_tests = C.STYLE_ENABLED - row_btns_sel_tests = C.STYLE_ENABLED - if C.CLEAR_ALL_INPUTS: - ctrl_panel.set(ctrl_panel.defaults) - ctrl_panel.set({ - "cl-selected-options": list_tests(store_sel) - }) - elif trigger_id == "btn-sel-remove-all": - _ = btn_remove_all - row_fig_tput = C.PLACEHOLDER - row_fig_lat = C.PLACEHOLDER - row_table = C.PLACEHOLDER - row_btn_dwnld = C.PLACEHOLDER - row_card_sel_tests = C.STYLE_DISABLED - row_btns_sel_tests = C.STYLE_DISABLED - store_sel = list() - ctrl_panel.set({"cl-selected-options": list()}) - elif trigger_id == "btn-sel-remove": - _ = btn_remove - if list_sel: - new_store_sel = list() - for item in store_sel: - if item["id"] not in list_sel: - new_store_sel.append(item) - store_sel = new_store_sel - elif trigger_id == "url": - if url_params: - try: - store_sel = literal_eval(url_params["store_sel"][0]) - norm = literal_eval(url_params["norm"][0]) - except (KeyError, IndexError): - pass - if store_sel: - row_card_sel_tests = C.STYLE_ENABLED - row_btns_sel_tests = C.STYLE_ENABLED - last_test = store_sel[-1] - test = self.spec_tbs[last_test["rls"]]\ - [last_test["dut"]][last_test["dutver"]]\ - [last_test["phy"]][last_test["area"]]\ - [last_test["test"]] - ctrl_panel.set({ - "dd-rls-value": last_test["rls"], - "dd-dut-value": last_test["dut"], - "dd-dut-options": generate_options(sorted( - self.spec_tbs[last_test["rls"]].keys())), - "dd-dut-disabled": False, - "dd-dutver-value": last_test["dutver"], - "dd-dutver-options": generate_options(sorted( - self.spec_tbs[last_test["rls"]]\ - [last_test["dut"]].keys())), - "dd-dutver-disabled": False, - "dd-phy-value": last_test["phy"], - "dd-phy-options": generate_options(sorted( - self.spec_tbs[last_test["rls"]]\ - [last_test["dut"]]\ - [last_test["dutver"]].keys())), - "dd-phy-disabled": False, - "dd-area-value": last_test["area"], - "dd-area-options": [ - {"label": label(v), "value": v} for v in \ - sorted(self.spec_tbs[last_test["rls"]]\ - [last_test["dut"]][last_test["dutver"]]\ - [last_test["phy"]].keys()) - ], - "dd-area-disabled": False, - "dd-test-value": last_test["test"], - "dd-test-options": generate_options(sorted( - self.spec_tbs[last_test["rls"]]\ - [last_test["dut"]][last_test["dutver"]]\ - [last_test["phy"]]\ - [last_test["area"]].keys())), - "dd-test-disabled": False, - "cl-core-options": generate_options(sorted( - test["core"])), - "cl-core-value": [last_test["core"].upper(), ], - "cl-core-all-value": list(), - "cl-core-all-options": C.CL_ALL_ENABLED, - "cl-framesize-options": generate_options( - sorted(test["frame-size"])), - "cl-framesize-value": \ - [last_test["framesize"].upper(), ], - "cl-framesize-all-value": list(), - "cl-framesize-all-options": C.CL_ALL_ENABLED, - "cl-testtype-options": generate_options(sorted( - test["test-type"])), - "cl-testtype-value": \ - [last_test["testtype"].upper(), ], - "cl-testtype-all-value": list(), - "cl-testtype-all-options": C.CL_ALL_ENABLED - }) - - if trigger_id in ("btn-ctrl-add", "url", "btn-sel-remove", - "cl-ctrl-normalize"): - if store_sel: - row_fig_tput, row_fig_lat, row_table, row_btn_dwnld = \ - _generate_plotting_area( - graph_iterative( - self.data, store_sel, self.layout, bool(norm) - ), - table_comparison( - self.data, store_sel, bool(norm) - ), - gen_new_url( - parsed_url, - {"store_sel": store_sel, "norm": norm} - ) - ) - ctrl_panel.set({ - "cl-selected-options": list_tests(store_sel) - }) - else: - row_fig_tput = C.PLACEHOLDER - row_fig_lat = C.PLACEHOLDER - row_table = C.PLACEHOLDER - row_btn_dwnld = C.PLACEHOLDER - row_card_sel_tests = C.STYLE_DISABLED - row_btns_sel_tests = C.STYLE_DISABLED - store_sel = list() - ctrl_panel.set({"cl-selected-options": list()}) - - if ctrl_panel.get("cl-core-value") and \ - ctrl_panel.get("cl-framesize-value") and \ - ctrl_panel.get("cl-testtype-value"): - disabled = False - else: - disabled = True - ctrl_panel.set({ - "btn-add-disabled": disabled, - "cl-normalize-value": norm - }) - - ret_val = [ - ctrl_panel.panel, store_sel, - row_fig_tput, row_fig_lat, row_table, row_btn_dwnld, - row_card_sel_tests, row_btns_sel_tests - ] - ret_val.extend(ctrl_panel.values()) - return ret_val - - @app.callback( - Output("download-data", "data"), - State("selected-tests", "data"), - Input("btn-download-data", "n_clicks"), - prevent_initial_call=True - ) - def _download_data(store_sel, n_clicks): - """Download the data - - :param store_sel: List of tests selected by user stored in the - browser. - :param n_clicks: Number of clicks on the button "Download". - :type store_sel: list - :type n_clicks: int - :returns: dict of data frame content (base64 encoded) and meta data - used by the Download component. - :rtype: dict - """ - - if not n_clicks: - raise PreventUpdate - - if not store_sel: - raise PreventUpdate - - df = pd.DataFrame() - for itm in store_sel: - sel_data = select_iterative_data(self.data, itm) - if sel_data is None: - continue - df = pd.concat([df, sel_data], ignore_index=True) - - return dcc.send_data_frame(df.to_csv, C.REPORT_DOWNLOAD_FILE_NAME) diff --git a/resources/tools/dash/app/pal/report/layout.yaml b/resources/tools/dash/app/pal/report/layout.yaml deleted file mode 100644 index c4ef13bf8b..0000000000 --- a/resources/tools/dash/app/pal/report/layout.yaml +++ /dev/null @@ -1,127 +0,0 @@ -plot-throughput: - xaxis: - title: "Test Cases [Index]" - autorange: True - fixedrange: False - gridcolor: "rgb(230, 230, 230)" - linecolor: "rgb(220, 220, 220)" - linewidth: 1 - showgrid: True - showline: True - showticklabels: True - tickcolor: "rgb(220, 220, 220)" - tickmode: "array" - zeroline: False - yaxis: - title: "Packet Throughput [pps]" - gridcolor: "rgb(230, 230, 230)" - hoverformat: ".3s" - tickformat: ".3s" - linecolor: "rgb(220, 220, 220)" - linewidth: 1 - showgrid: True - showline: True - showticklabels: True - tickcolor: "rgb(220, 220, 220)" - zeroline: False - range: [0, 50] - autosize: False - margin: - t: 50 - b: 0 - l: 80 - r: 20 - showlegend: True - legend: - orientation: "h" - font: - size: 10 - width: 700 - height: 900 - paper_bgcolor: "#fff" - plot_bgcolor: "#fff" - hoverlabel: - namelength: -1 - -plot-latency: - xaxis: - title: "Test Cases [Index]" - autorange: True - fixedrange: False - gridcolor: "rgb(230, 230, 230)" - linecolor: "rgb(220, 220, 220)" - linewidth: 1 - showgrid: True - showline: True - showticklabels: True - tickcolor: "rgb(220, 220, 220)" - tickmode: "array" - zeroline: False - yaxis: - title: "Average Latency at 50% PDR [us]" - gridcolor: "rgb(230, 230, 230)" - hoverformat: ".3s" - tickformat: ".3s" - linecolor: "rgb(220, 220, 220)" - linewidth: 1 - showgrid: True - showline: True - showticklabels: True - tickcolor: "rgb(220, 220, 220)" - zeroline: False - range: [0, 50] - autosize: False - margin: - t: 50 - b: 0 - l: 80 - r: 20 - showlegend: True - legend: - orientation: "h" - font: - size: 10 - width: 700 - height: 900 - paper_bgcolor: "#fff" - plot_bgcolor: "#fff" - hoverlabel: - namelength: -1 - -plot-hdrh-latency: - showlegend: True - legend: - traceorder: "normal" - orientation: "h" - xanchor: "left" - yanchor: "top" - x: 0 - y: -0.25 - bgcolor: "rgba(255, 255, 255, 0)" - bordercolor: "rgba(255, 255, 255, 0)" - xaxis: - type: "log" - title: "Percentile [%]" - autorange: False - fixedrange: True - gridcolor: "rgb(230, 230, 230)" - linecolor: "rgb(220, 220, 220)" - linewidth: 1 - showgrid: True - showline: True - showticklabels: True - tickcolor: "rgb(220, 220, 220)" - tickvals: [1, 2, 1e1, 20, 1e2, 1e3, 1e4, 1e5, 1e6] - ticktext: [0, 50, 90, 95, 99, 99.9, 99.99, 99.999, 99.9999] - yaxis: - title: "One-Way Latency per Direction [us]" - gridcolor: "rgb(230, 230, 230)" - linecolor: "rgb(220, 220, 220)" - linewidth: 1 - showgrid: True - showline: True - showticklabels: True - tickcolor: "rgb(220, 220, 220)" - autosize: True - paper_bgcolor: "white" - plot_bgcolor: "white" diff --git a/resources/tools/dash/app/pal/report/report.py b/resources/tools/dash/app/pal/report/report.py deleted file mode 100644 index e4565731ec..0000000000 --- a/resources/tools/dash/app/pal/report/report.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2022 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Instantiate the Report Dash application. -""" -import dash - -from ..utils.constants import Constants as C -from .layout import Layout - - -def init_report(server, releases): - """Create a Plotly Dash dashboard. - - :param server: Flask server. - :type server: Flask - :returns: Dash app server. - :rtype: Dash - """ - - dash_app = dash.Dash( - server=server, - routes_pathname_prefix=C.REPORT_ROUTES_PATHNAME_PREFIX, - external_stylesheets=C.EXTERNAL_STYLESHEETS - ) - - layout = Layout( - app=dash_app, - releases=releases, - html_layout_file=C.REPORT_HTML_LAYOUT_FILE, - graph_layout_file=C.REPORT_GRAPH_LAYOUT_FILE, - data_spec_file=C.DATA_SPEC_FILE, - tooltip_file=C.TOOLTIP_FILE, - ) - dash_app.index_string = layout.html_layout - dash_app.layout = layout.add_content() - - return dash_app.server diff --git a/resources/tools/dash/app/pal/routes.py b/resources/tools/dash/app/pal/routes.py deleted file mode 100644 index 59af748168..0000000000 --- a/resources/tools/dash/app/pal/routes.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2022 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Routes for parent Flask app. -""" - -from flask import current_app as app -from flask import render_template - -from .utils.constants import Constants as C - - -@app.route(C.APPLICATIN_ROOT) -def home(): - """Landing page. - """ - return render_template( - C.MAIN_HTML_LAYOUT_FILE, - title=C.TITLE, - description=C.DESCRIPTION, - template=C.TEMPLATE - ) diff --git a/resources/tools/dash/app/pal/static/dist/img/favicon.svg b/resources/tools/dash/app/pal/static/dist/img/favicon.svg deleted file mode 100644 index 689757e3fd..0000000000 --- a/resources/tools/dash/app/pal/static/dist/img/favicon.svg +++ /dev/null @@ -1,348 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/resources/tools/dash/app/pal/static/img/logo.svg b/resources/tools/dash/app/pal/static/img/logo.svg deleted file mode 100644 index 689757e3fd..0000000000 --- a/resources/tools/dash/app/pal/static/img/logo.svg +++ /dev/null @@ -1,348 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/resources/tools/dash/app/pal/static/sass/_bootswatch.scss b/resources/tools/dash/app/pal/static/sass/_bootswatch.scss deleted file mode 100644 index 900ccfb3c1..0000000000 --- a/resources/tools/dash/app/pal/static/sass/_bootswatch.scss +++ /dev/null @@ -1,178 +0,0 @@ -// Lux 5.2.1 -// Bootswatch - - -// Variables - -$web-font-path: "https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@400;600&display=swap" !default; -@if $web-font-path { - @import url($web-font-path); -} - -:root { - color-scheme: light; -} - -// Navbar - -.navbar { - font-size: $font-size-sm; - font-weight: 600; - text-transform: uppercase; - - &-nav { - .nav-link { - padding-top: .715rem; - padding-bottom: .715rem; - } - } - - &-brand { - margin-right: 2rem; - } -} - -.bg-light { - border: 1px solid rgba(0, 0, 0, .1); - - &.navbar-fixed-top { - border-width: 0 0 1px; - } - - &.navbar-bottom-top { - border-width: 1px 0 0; - } -} - -.nav-item { - margin-right: 2rem; -} - -// Buttons - -.btn { - font-size: $font-size-sm; - text-transform: uppercase; - - &-sm { - font-size: 10px; - } - - &-warning { - &, - &:hover, - &:not([disabled]):not(.disabled):active, - &:focus { - color: $white; - } - } -} - -.btn-outline-secondary { - color: $gray-600; - border-color: $gray-600; - - &:not([disabled]):not(.disabled):hover, - &:not([disabled]):not(.disabled):focus, - &:not([disabled]):not(.disabled):active { - color: $white; - background-color: $gray-400; - border-color: $gray-400; - } - - &:not([disabled]):not(.disabled):focus { - box-shadow: 0 0 0 .2rem rgba($gray-400, .5); - } -} - -[class*="btn-outline-"] { - border-width: 2px; -} - -.border-secondary { - border: 1px solid $gray-400 !important; -} - -// Typography - -body { - font-weight: 200; - letter-spacing: 1px; -} - -h1, -h2, -h3, -h4, -h5, -h6 { - text-transform: uppercase; - letter-spacing: 3px; -} - -.text-secondary { - color: $body-color !important; -} - -// Tables - -th { - font-size: $font-size-sm; - text-transform: uppercase; -} - -.table { - th, - td { - padding: 1.5rem; - } - - &-sm { - th, - td { - padding: .75rem; - } - } -} - -// Navs - -.dropdown-menu { - font-size: $font-size-sm; - text-transform: none; -} - -// Indicators - -.badge { - padding-top: .28rem; - - &-pill { - border-radius: 10rem; - } - - &.bg-secondary, - &.bg-light { - color: $dark; - } -} - -// Containers - -.list-group-item, -.card { - h1, - h2, - h3, - h4, - h5, - h6, - .h1, - .h2, - .h3, - .h4, - .h5, - .h6 { - color: inherit; - } -} diff --git a/resources/tools/dash/app/pal/static/sass/_variables.scss b/resources/tools/dash/app/pal/static/sass/_variables.scss deleted file mode 100644 index 6bfd6408b7..0000000000 --- a/resources/tools/dash/app/pal/static/sass/_variables.scss +++ /dev/null @@ -1,103 +0,0 @@ -// Lux 5.2.1 -// Bootswatch - -$theme: "lux" !default; - -// -// Color system -// - -$white: #fff !default; -$gray-100: #f8f9fa !default; -$gray-200: #f7f7f9 !default; -$gray-300: #eceeef !default; -$gray-400: #ced4da !default; -$gray-500: #adb5bd !default; -$gray-600: #919aa1 !default; -$gray-700: #55595c !default; -$gray-800: #343a40 !default; -$gray-900: #1a1a1a !default; -$black: #000 !default; - -$blue: #007bff !default; -$indigo: #6610f2 !default; -$purple: #6f42c1 !default; -$pink: #e83e8c !default; -$red: #d9534f !default; -$orange: #fd7e14 !default; -$yellow: #f0ad4e !default; -$green: #4bbf73 !default; -$teal: #20c997 !default; -$cyan: #1f9bcf !default; - -$primary: $gray-900 !default; -$secondary: $white !default; -$success: $green !default; -$info: $cyan !default; -$warning: $yellow !default; -$danger: $red !default; -$light: $white !default; -$dark: $gray-800 !default; - -$min-contrast-ratio: 2.3 !default; - -// Options - -$enable-rounded: false !default; - -// Body - -$body-color: $gray-700 !default; - -// Fonts - -// stylelint-disable-next-line value-keyword-case -$font-family-sans-serif: "Nunito Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default; -$h1-font-size: 2rem !default; -$h2-font-size: 1.75rem !default; -$h3-font-size: 1.5rem !default; -$h4-font-size: 1.25rem !default; -$h5-font-size: 1rem !default; -$h6-font-size: .75rem !default; -$headings-font-weight: 600 !default; -$headings-color: $gray-900 !default; - -// Tables - -$table-border-color: rgba(0, 0, 0, .05) !default; - -// Buttons + Forms - -$input-btn-border-width: 0 !default; - -// Buttons - -$btn-line-height: 1.5rem !default; -$input-btn-padding-y: .75rem !default; -$input-btn-padding-x: 1.5rem !default; -$input-btn-padding-y-sm: .5rem !default; -$input-btn-padding-x-sm: 1rem !default; -$input-btn-padding-y-lg: 2rem !default; -$input-btn-padding-x-lg: 2rem !default; -$btn-font-weight: 600 !default; - -// Forms - -$input-line-height: 1.5 !default; -$input-bg: $gray-200 !default; -$input-disabled-bg: $gray-300 !default; -$input-group-addon-bg: $gray-300 !default; - -// Navbar - -$navbar-padding-y: 1.5rem !default; -$navbar-dark-hover-color: $white !default; -$navbar-light-color: rgba($black, .3) !default; -$navbar-light-hover-color: $gray-900 !default; -$navbar-light-active-color: $gray-900 !default; - -// Pagination - -$pagination-border-color: transparent !default; -$pagination-hover-border-color: $pagination-border-color !default; -$pagination-disabled-border-color: $pagination-border-color !default; diff --git a/resources/tools/dash/app/pal/static/sass/bootstrap/_accordion.scss b/resources/tools/dash/app/pal/static/sass/bootstrap/_accordion.scss deleted file mode 100644 index f09601bab6..0000000000 --- a/resources/tools/dash/app/pal/static/sass/bootstrap/_accordion.scss +++ /dev/null @@ -1,149 +0,0 @@ -// -// Base styles -// - -.accordion { - // scss-docs-start accordion-css-vars - --#{$prefix}accordion-color: #{$accordion-color}; - --#{$prefix}accordion-bg: #{$accordion-bg}; - --#{$prefix}accordion-transition: #{$accordion-transition}; - --#{$prefix}accordion-border-color: #{$accordion-border-color}; - --#{$prefix}accordion-border-width: #{$accordion-border-width}; - --#{$prefix}accordion-border-radius: #{$accordion-border-radius}; - --#{$prefix}accordion-inner-border-radius: #{$accordion-inner-border-radius}; - --#{$prefix}accordion-btn-padding-x: #{$accordion-button-padding-x}; - --#{$prefix}accordion-btn-padding-y: #{$accordion-button-padding-y}; - --#{$prefix}accordion-btn-color: #{$accordion-button-color}; - --#{$prefix}accordion-btn-bg: #{$accordion-button-bg}; - --#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon)}; - --#{$prefix}accordion-btn-icon-width: #{$accordion-icon-width}; - --#{$prefix}accordion-btn-icon-transform: #{$accordion-icon-transform}; - --#{$prefix}accordion-btn-icon-transition: #{$accordion-icon-transition}; - --#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon)}; - --#{$prefix}accordion-btn-focus-border-color: #{$accordion-button-focus-border-color}; - --#{$prefix}accordion-btn-focus-box-shadow: #{$accordion-button-focus-box-shadow}; - --#{$prefix}accordion-body-padding-x: #{$accordion-body-padding-x}; - --#{$prefix}accordion-body-padding-y: #{$accordion-body-padding-y}; - --#{$prefix}accordion-active-color: #{$accordion-button-active-color}; - --#{$prefix}accordion-active-bg: #{$accordion-button-active-bg}; - // scss-docs-end accordion-css-vars -} - -.accordion-button { - position: relative; - display: flex; - align-items: center; - width: 100%; - padding: var(--#{$prefix}accordion-btn-padding-y) var(--#{$prefix}accordion-btn-padding-x); - @include font-size($font-size-base); - color: var(--#{$prefix}accordion-btn-color); - text-align: left; // Reset button style - background-color: var(--#{$prefix}accordion-btn-bg); - border: 0; - @include border-radius(0); - overflow-anchor: none; - @include transition(var(--#{$prefix}accordion-transition)); - - &:not(.collapsed) { - color: var(--#{$prefix}accordion-active-color); - background-color: var(--#{$prefix}accordion-active-bg); - box-shadow: inset 0 calc(-1 * var(--#{$prefix}accordion-border-width)) 0 var(--#{$prefix}accordion-border-color); // stylelint-disable-line function-disallowed-list - - &::after { - background-image: var(--#{$prefix}accordion-btn-active-icon); - transform: var(--#{$prefix}accordion-btn-icon-transform); - } - } - - // Accordion icon - &::after { - flex-shrink: 0; - width: var(--#{$prefix}accordion-btn-icon-width); - height: var(--#{$prefix}accordion-btn-icon-width); - margin-left: auto; - content: ""; - background-image: var(--#{$prefix}accordion-btn-icon); - background-repeat: no-repeat; - background-size: var(--#{$prefix}accordion-btn-icon-width); - @include transition(var(--#{$prefix}accordion-btn-icon-transition)); - } - - &:hover { - z-index: 2; - } - - &:focus { - z-index: 3; - border-color: var(--#{$prefix}accordion-btn-focus-border-color); - outline: 0; - box-shadow: var(--#{$prefix}accordion-btn-focus-box-shadow); - } -} - -.accordion-header { - margin-bottom: 0; -} - -.accordion-item { - color: var(--#{$prefix}accordion-color); - background-color: var(--#{$prefix}accordion-bg); - border: var(--#{$prefix}accordion-border-width) solid var(--#{$prefix}accordion-border-color); - - &:first-of-type { - @include border-top-radius(var(--#{$prefix}accordion-border-radius)); - - .accordion-button { - @include border-top-radius(var(--#{$prefix}accordion-inner-border-radius)); - } - } - - &:not(:first-of-type) { - border-top: 0; - } - - // Only set a border-radius on the last item if the accordion is collapsed - &:last-of-type { - @include border-bottom-radius(var(--#{$prefix}accordion-border-radius)); - - .accordion-button { - &.collapsed { - @include border-bottom-radius(var(--#{$prefix}accordion-inner-border-radius)); - } - } - - .accordion-collapse { - @include border-bottom-radius(var(--#{$prefix}accordion-border-radius)); - } - } -} - -.accordion-body { - padding: var(--#{$prefix}accordion-body-padding-y) var(--#{$prefix}accordion-body-padding-x); -} - - -// Flush accordion items -// -// Remove borders and border-radius to keep accordion items edge-to-edge. - -.accordion-flush { - .accordion-collapse { - border-width: 0; - } - - .accordion-item { - border-right: 0; - border-left: 0; - @include border-radius(0); - - &:first-child { border-top: 0; } - &:last-child { border-bottom: 0; } - - .accordion-button { - &, - &.collapsed { - @include border-radius(0); - } - } - } -} diff --git a/resources/tools/dash/app/pal/static/sass/bootstrap/_alert.scss b/resources/tools/dash/app/pal/static/sass/bootstrap/_alert.scss deleted file mode 100644 index c8bc91b420..0000000000 --- a/resources/tools/dash/app/pal/static/sass/bootstrap/_alert.scss +++ /dev/null @@ -1,71 +0,0 @@ -// -// Base styles -// - -.alert { - // scss-docs-start alert-css-vars - --#{$prefix}alert-bg: transparent; - --#{$prefix}alert-padding-x: #{$alert-padding-x}; - --#{$prefix}alert-padding-y: #{$alert-padding-y}; - --#{$prefix}alert-margin-bottom: #{$alert-margin-bottom}; - --#{$prefix}alert-color: inherit; - --#{$prefix}alert-border-color: transparent; - --#{$prefix}alert-border: #{$alert-border-width} solid var(--#{$prefix}alert-border-color); - --#{$prefix}alert-border-radius: #{$alert-border-radius}; - // scss-docs-end alert-css-vars - - position: relative; - padding: var(--#{$prefix}alert-padding-y) var(--#{$prefix}alert-padding-x); - margin-bottom: var(--#{$prefix}alert-margin-bottom); - color: var(--#{$prefix}alert-color); - background-color: var(--#{$prefix}alert-bg); - border: var(--#{$prefix}alert-border); - @include border-radius(var(--#{$prefix}alert-border-radius)); -} - -// Headings for larger alerts -.alert-heading { - // Specified to prevent conflicts of changing $headings-color - color: inherit; -} - -// Provide class for links that match alerts -.alert-link { - font-weight: $alert-link-font-weight; -} - - -// Dismissible alerts -// -// Expand the right padding and account for the close button's positioning. - -.alert-dismissible { - padding-right: $alert-dismissible-padding-r; - - // Adjust close link position - .btn-close { - position: absolute; - top: 0; - right: 0; - z-index: $stretched-link-z-index + 1; - padding: $alert-padding-y * 1.25 $alert-padding-x; - } -} - - -// scss-docs-start alert-modifiers -// Generate contextual modifier classes for colorizing the alert. - -@each $state, $value in $theme-colors { - $alert-background: shift-color($value, $alert-bg-scale); - $alert-border: shift-color($value, $alert-border-scale); - $alert-color: shift-color($value, $alert-color-scale); - - @if (contrast-ratio($alert-background, $alert-color) < $min-contrast-ratio) { - $alert-color: mix($value, color-contrast($alert-background), abs($alert-color-scale)); - } - .alert-#{$state} { - @include alert-variant($alert-background, $alert-border, $alert-color); - } -} -// scss-docs-end alert-modifiers diff --git a/resources/tools/dash/app/pal/static/sass/bootstrap/_badge.scss b/resources/tools/dash/app/pal/static/sass/bootstrap/_badge.scss deleted file mode 100644 index cc3d269556..0000000000 --- a/resources/tools/dash/app/pal/static/sass/bootstrap/_badge.scss +++ /dev/null @@ -1,38 +0,0 @@ -// Base class -// -// Requires one of the contextual, color modifier classes for `color` and -// `background-color`. - -.badge { - // scss-docs-start badge-css-vars - --#{$prefix}badge-padding-x: #{$badge-padding-x}; - --#{$prefix}badge-padding-y: #{$badge-padding-y}; - @include rfs($badge-font-size, --#{$prefix}badge-font-size); - --#{$prefix}badge-font-weight: #{$badge-font-weight}; - --#{$prefix}badge-color: #{$badge-color}; - --#{$prefix}badge-border-radius: #{$badge-border-radius}; - // scss-docs-end badge-css-vars - - display: inline-block; - padding: var(--#{$prefix}badge-padding-y) var(--#{$prefix}badge-padding-x); - @include font-size(var(--#{$prefix}badge-font-size)); - font-weight: var(--#{$prefix}badge-font-weight); - line-height: 1; - color: var(--#{$prefix}badge-color); - text-align: center; - white-space: nowrap; - vertical-align: baseline; - @include border-radius(var(--#{$prefix}badge-border-radius)); - @include gradient-bg(); - - // Empty badges collapse automatically - &:empty { - display: none; - } -} - -// Quick fix for badges in buttons -.btn .badge { - position: relative; - top: -1px; -} diff --git a/resources/tools/dash/app/pal/static/sass/bootstrap/_breadcrumb.scss b/resources/tools/dash/app/pal/static/sass/bootstrap/_breadcrumb.scss deleted file mode 100644 index b8252ff215..0000000000 --- a/resources/tools/dash/app/pal/static/sass/bootstrap/_breadcrumb.scss +++ /dev/null @@ -1,40 +0,0 @@ -.breadcrumb { - // scss-docs-start breadcrumb-css-vars - --#{$prefix}breadcrumb-padding-x: #{$breadcrumb-padding-x}; - --#{$prefix}breadcrumb-padding-y: #{$breadcrumb-padding-y}; - --#{$prefix}breadcrumb-margin-bottom: #{$breadcrumb-margin-bottom}; - @include rfs($breadcrumb-font-size, --#{$prefix}breadcrumb-font-size); - --#{$prefix}breadcrumb-bg: #{$breadcrumb-bg}; - --#{$prefix}breadcrumb-border-radius: #{$breadcrumb-border-radius}; - --#{$prefix}breadcrumb-divider-color: #{$breadcrumb-divider-color}; - --#{$prefix}breadcrumb-item-padding-x: #{$breadcrumb-item-padding-x}; - --#{$prefix}breadcrumb-item-active-color: #{$breadcrumb-active-color}; - // scss-docs-end breadcrumb-css-vars - - display: flex; - flex-wrap: wrap; - padding: var(--#{$prefix}breadcrumb-padding-y) var(--#{$prefix}breadcrumb-padding-x); - margin-bottom: var(--#{$prefix}breadcrumb-margin-bottom); - @include font-size(var(--#{$prefix}breadcrumb-font-size)); - list-style: none; - background-color: var(--#{$prefix}breadcrumb-bg); - @include border-radius(var(--#{$prefix}breadcrumb-border-radius)); -} - -.breadcrumb-item { - // The separator between breadcrumbs (by default, a forward-slash: "/") - + .breadcrumb-item { - padding-left: var(--#{$prefix}breadcrumb-item-padding-x); - - &::before { - float: left; // Suppress inline spacings and underlining of the separator - padding-right: var(--#{$prefix}breadcrumb-item-padding-x); - color: var(--#{$prefix}breadcrumb-divider-color); - content: var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)) #{"/* rtl:"} var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped)) #{"*/"}; - } - } - - &.active { - color: var(--#{$prefix}breadcrumb-item-active-color); - } -} diff --git a/resources/tools/dash/app/pal/static/sass/bootstrap/_button-group.scss b/resources/tools/dash/app/pal/static/sass/bootstrap/_button-group.scss deleted file mode 100644 index 79b100cbfb..0000000000 --- a/resources/tools/dash/app/pal/static/sass/bootstrap/_button-group.scss +++ /dev/null @@ -1,142 +0,0 @@ -// Make the div behave like a button -.btn-group, -.btn-group-vertical { - position: relative; - display: inline-flex; - vertical-align: middle; // match .btn alignment given font-size hack above - - > .btn { - position: relative; - flex: 1 1 auto; - } - - // Bring the hover, focused, and "active" buttons to the front to overlay - // the borders properly - > .btn-check:checked + .btn, - > .btn-check:focus + .btn, - > .btn:hover, - > .btn:focus, - > .btn:active, - > .btn.active { - z-index: 1; - } -} - -// Optional: Group multiple button groups together for a toolbar -.btn-toolbar { - display: flex; - flex-wrap: wrap; - justify-content: flex-start; - - .input-group { - width: auto; - } -} - -.btn-group { - @include border-radius($btn-border-radius); - - // Prevent double borders when buttons are next to each other - > :not(.btn-check:first-child) + .btn, - > .btn-group:not(:first-child) { - margin-left: -$btn-border-width; - } - - // Reset rounded corners - > .btn:not(:last-child):not(.dropdown-toggle), - > .btn.dropdown-toggle-split:first-child, - > .btn-group:not(:last-child) > .btn { - @include border-end-radius(0); - } - - // The left radius should be 0 if the button is: - // - the "third or more" child - // - the second child and the previous element isn't `.btn-check` (making it the first child visually) - // - part of a btn-group which isn't the first child - > .btn:nth-child(n + 3), - > :not(.btn-check) + .btn, - > .btn-group:not(:first-child) > .btn { - @include border-start-radius(0); - } -} - -// Sizing -// -// Remix the default button sizing classes into new ones for easier manipulation. - -.btn-group-sm > .btn { @extend .btn-sm; } -.btn-group-lg > .btn { @extend .btn-lg; } - - -// -// Split button dropdowns -// - -.dropdown-toggle-split { - padding-right: $btn-padding-x * .75; - padding-left: $btn-padding-x * .75; - - &::after, - .dropup &::after, - .dropend &::after { - margin-left: 0; - } - - .dropstart &::before { - margin-right: 0; - } -} - -.btn-sm + .dropdown-toggle-split { - padding-right: $btn-padding-x-sm * .75; - padding-left: $btn-padding-x-sm * .75; -} - -.btn-lg + .dropdown-toggle-split { - padding-right: $btn-padding-x-lg * .75; - padding-left: $btn-padding-x-lg * .75; -} - - -// The clickable button for toggling the menu -// Set the same inset shadow as the :active state -.btn-group.show .dropdown-toggle { - @include box-shadow($btn-active-box-shadow); - - // Show no shadow for `.btn-link` since it has no other button styles. - &.btn-link { - @include box-shadow(none); - } -} - - -// -// Vertical button groups -// - -.btn-group-vertical { - flex-direction: column; - align-items: flex-start; - justify-content: center; - - > .btn, - > .btn-group { - width: 100%; - } - - > .btn:not(:first-child), - > .btn-group:not(:first-child) { - margin-top: -$btn-border-width; - } - - // Reset rounded corners - > .btn:not(:last-child):not(.dropdown-toggle), - > .btn-group:not(:last-child) > .btn { - @include border-bottom-radius(0); - } - - > .btn ~ .btn, - > .btn-group:not(:first-child) > .btn { - @include border-top-radius(0); - } -} diff --git a/resources/tools/dash/app/pal/static/sass/bootstrap/_buttons.scss b/resources/tools/dash/app/pal/static/sass/bootstrap/_buttons.scss deleted file mode 100644 index c2d0773516..0000000000 --- a/resources/tools/dash/app/pal/static/sass/bootstrap/_buttons.scss +++ /dev/null @@ -1,201 +0,0 @@ -// -// Base styles -// - -.btn { - // scss-docs-start btn-css-vars - --#{$prefix}btn-padding-x: #{$btn-padding-x}; - --#{$prefix}btn-padding-y: #{$btn-padding-y}; - --#{$prefix}btn-font-family: #{$btn-font-family}; - @include rfs($btn-font-size, --#{$prefix}btn-font-size); - --#{$prefix}btn-font-weight: #{$btn-font-weight}; - --#{$prefix}btn-line-height: #{$btn-line-height}; - --#{$prefix}btn-color: #{$body-color}; - --#{$prefix}btn-bg: transparent; - --#{$prefix}btn-border-width: #{$btn-border-width}; - --#{$prefix}btn-border-color: transparent; - --#{$prefix}btn-border-radius: #{$btn-border-radius}; - --#{$prefix}btn-hover-border-color: transparent; - --#{$prefix}btn-box-shadow: #{$btn-box-shadow}; - --#{$prefix}btn-disabled-opacity: #{$btn-disabled-opacity}; - --#{$prefix}btn-focus-box-shadow: 0 0 0 #{$btn-focus-width} rgba(var(--#{$prefix}btn-focus-shadow-rgb), .5); - // scss-docs-end btn-css-vars - - display: inline-block; - padding: var(--#{$prefix}btn-padding-y) var(--#{$prefix}btn-padding-x); - font-family: var(--#{$prefix}btn-font-family); - @include font-size(var(--#{$prefix}btn-font-size)); - font-weight: var(--#{$prefix}btn-font-weight); - line-height: var(--#{$prefix}btn-line-height); - color: var(--#{$prefix}btn-color); - text-align: center; - text-decoration: if($link-decoration == none, null, none); - white-space: $btn-white-space; - vertical-align: middle; - cursor: if($enable-button-pointers, pointer, null); - user-select: none; - border: var(--#{$prefix}btn-border-width) solid var(--#{$prefix}btn-border-color); - @include border-radius(var(--#{$prefix}btn-border-radius)); - @include gradient-bg(var(--#{$prefix}btn-bg)); - @include box-shadow(var(--#{$prefix}btn-box-shadow)); - @include transition($btn-transition); - - :not(.btn-check) + &:hover, - &:first-child:hover { - color: var(--#{$prefix}btn-hover-color); - text-decoration: if($link-hover-decoration == underline, none, null); - background-color: var(--#{$prefix}btn-hover-bg); - border-color: var(--#{$prefix}btn-hover-border-color); - } - - &:focus-visible { - color: var(--#{$prefix}btn-hover-color); - @include gradient-bg(var(--#{$prefix}btn-hover-bg)); - border-color: var(--#{$prefix}btn-hover-border-color); - outline: 0; - // Avoid using mixin so we can pass custom focus shadow properly - @if $enable-shadows { - box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow); - } @else { - box-shadow: var(--#{$prefix}btn-focus-box-shadow); - } - } - - .btn-check:focus-visible + & { - border-color: var(--#{$prefix}btn-hover-border-color); - outline: 0; - // Avoid using mixin so we can pass custom focus shadow properly - @if $enable-shadows { - box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow); - } @else { - box-shadow: var(--#{$prefix}btn-focus-box-shadow); - } - } - - .btn-check:checked + &, - :not(.btn-check) + &:active, - &:first-child:active, - &.active, - &.show { - color: var(--#{$prefix}btn-active-color); - background-color: var(--#{$prefix}btn-active-bg); - // Remove CSS gradients if they're enabled - background-image: if($enable-gradients, none, null); - border-color: var(--#{$prefix}btn-active-border-color); - @include box-shadow(var(--#{$prefix}btn-active-shadow)); - - &:focus-visible { - // Avoid using mixin so we can pass custom focus shadow properly - @if $enable-shadows { - box-shadow: var(--#{$prefix}btn-active-shadow), var(--#{$prefix}btn-focus-box-shadow); - } @else { - box-shadow: var(--#{$prefix}btn-focus-box-shadow); - } - } - } - - &:disabled, - &.disabled, - fieldset:disabled & { - color: var(--#{$prefix}btn-disabled-color); - pointer-events: none; - background-color: var(--#{$prefix}btn-disabled-bg); - background-image: if($enable-gradients, none, null); - border-color: var(--#{$prefix}btn-disabled-border-color); - opacity: var(--#{$prefix}btn-disabled-opacity); - @include box-shadow(none); - } -} - - -// -// Alternate buttons -// - -// scss-docs-start btn-variant-loops -@each $color, $value in $theme-colors { - .btn-#{$color} { - @if $color == "light" { - @include button-variant( - $value, - $value, - $hover-background: shade-color($value, $btn-hover-bg-shade-amount), - $hover-border: shade-color($value, $btn-hover-border-shade-amount), - $active-background: shade-color($value, $btn-active-bg-shade-amount), - $active-border: shade-color($value, $btn-active-border-shade-amount) - ); - } @else if $color == "dark" { - @include button-variant( - $value, - $value, - $hover-background: tint-color($value, $btn-hover-bg-tint-amount), - $hover-border: tint-color($value, $btn-hover-border-tint-amount), - $active-background: tint-color($value, $btn-active-bg-tint-amount), - $active-border: tint-color($value, $btn-active-border-tint-amount) - ); - } @else { - @include button-variant($value, $value); - } - } -} - -@each $color, $value in $theme-colors { - .btn-outline-#{$color} { - @include button-outline-variant($value); - } -} -// scss-docs-end btn-variant-loops - - -// -// Link buttons -// - -// Make a button look and behave like a link -.btn-link { - --#{$prefix}btn-font-weight: #{$font-weight-normal}; - --#{$prefix}btn-color: #{$btn-link-color}; - --#{$prefix}btn-bg: transparent; - --#{$prefix}btn-border-color: transparent; - --#{$prefix}btn-hover-color: #{$btn-link-hover-color}; - --#{$prefix}btn-hover-border-color: transparent; - --#{$prefix}btn-active-color: #{$btn-link-hover-color}; - --#{$prefix}btn-active-border-color: transparent; - --#{$prefix}btn-disabled-color: #{$btn-link-disabled-color}; - --#{$prefix}btn-disabled-border-color: transparent; - --#{$prefix}btn-box-shadow: none; - --#{$prefix}btn-focus-shadow-rgb: #{to-rgb(mix(color-contrast($primary), $primary, 15%))}; - - text-decoration: $link-decoration; - @if $enable-gradients { - background-image: none; - } - - &:hover, - &:focus-visible { - text-decoration: $link-hover-decoration; - } - - &:focus-visible { - color: var(--#{$prefix}btn-color); - } - - &:hover { - color: var(--#{$prefix}btn-hover-color); - } - - // No need for an active state here -} - - -// -// Button Sizes -// - -.btn-lg { - @include button-size($btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-border-radius-lg); -} - -.btn-sm { - @include button-size($btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-border-radius-sm); -} diff --git a/resources/tools/dash/app/pal/static/sass/bootstrap/_card.scss b/resources/tools/dash/app/pal/static/sass/bootstrap/_card.scss deleted file mode 100644 index ce8c02f1f2..0000000000 --- a/resources/tools/dash/app/pal/static/sass/bootstrap/_card.scss +++ /dev/null @@ -1,234 +0,0 @@ -// -// Base styles -// - -.card { - // scss-docs-start card-css-vars - --#{$prefix}card-spacer-y: #{$card-spacer-y}; - --#{$prefix}card-spacer-x: #{$card-spacer-x}; - --#{$prefix}card-title-spacer-y: #{$card-title-spacer-y}; - --#{$prefix}card-border-width: #{$card-border-width}; - --#{$prefix}card-border-color: #{$card-border-color}; - --#{$prefix}card-border-radius: #{$card-border-radius}; - --#{$prefix}card-box-shadow: #{$card-box-shadow}; - --#{$prefix}card-inner-border-radius: #{$card-inner-border-radius}; - --#{$prefix}card-cap-padding-y: #{$card-cap-padding-y}; - --#{$prefix}card-cap-padding-x: #{$card-cap-padding-x}; - --#{$prefix}card-cap-bg: #{$card-cap-bg}; - --#{$prefix}card-cap-color: #{$card-cap-color}; - --#{$prefix}card-height: #{$card-height}; - --#{$prefix}card-color: #{$card-color}; - --#{$prefix}card-bg: #{$card-bg}; - --#{$prefix}card-img-overlay-padding: #{$card-img-overlay-padding}; - --#{$prefix}card-group-margin: #{$card-group-margin}; - // scss-docs-end card-css-vars - - position: relative; - display: flex; - flex-direction: column; - min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106 - height: var(--#{$prefix}card-height); - word-wrap: break-word; - background-color: var(--#{$prefix}card-bg); - background-clip: border-box; - border: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color); - @include border-radius(var(--#{$prefix}card-border-radius)); - @include box-shadow(var(--#{$prefix}card-box-shadow)); - - > hr { - margin-right: 0; - margin-left: 0; - } - - > .list-group { - border-top: inherit; - border-bottom: inherit; - - &:first-child { - border-top-width: 0; - @include border-top-radius(var(--#{$prefix}card-inner-border-radius)); - } - - &:last-child { - border-bottom-width: 0; - @include border-bottom-radius(var(--#{$prefix}card-inner-border-radius)); - } - } - - // Due to specificity of the above selector (`.card > .list-group`), we must - // use a child selector here to prevent double borders. - > .card-header + .list-group, - > .list-group + .card-footer { - border-top: 0; - } -} - -.card-body { - // Enable `flex-grow: 1` for decks and groups so that card blocks take up - // as much space as possible, ensuring footers are aligned to the bottom. - flex: 1 1 auto; - padding: var(--#{$prefix}card-spacer-y) var(--#{$prefix}card-spacer-x); - color: var(--#{$prefix}card-color); -} - -.card-title { - margin-bottom: var(--#{$prefix}card-title-spacer-y); -} - -.card-subtitle { - margin-top: calc(-.5 * var(--#{$prefix}card-title-spacer-y)); // stylelint-disable-line function-disallowed-list - margin-bottom: 0; -} - -.card-text:last-child { - margin-bottom: 0; -} - -.card-link { - &:hover { - text-decoration: if($link-hover-decoration == underline, none, null); - } - - + .card-link { - margin-left: var(--#{$prefix}card-spacer-x); - } -} - -// -// Optional textual caps -// - -.card-header { - padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x); - margin-bottom: 0; // Removes the default margin-bottom of - color: var(--#{$prefix}card-cap-color); - background-color: var(--#{$prefix}card-cap-bg); - border-bottom: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color); - - &:first-child { - @include border-radius(var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius) 0 0); - } -} - -.card-footer { - padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x); - color: var(--#{$prefix}card-cap-color); - background-color: var(--#{$prefix}card-cap-bg); - border-top: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color); - - &:last-child { - @include border-radius(0 0 var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius)); - } -} - - -// -// Header navs -// - -.card-header-tabs { - margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list - margin-bottom: calc(-1 * var(--#{$prefix}card-cap-padding-y)); // stylelint-disable-line function-disallowed-list - margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list - border-bottom: 0; - - .nav-link.active { - background-color: var(--#{$prefix}card-bg); - border-bottom-color: var(--#{$prefix}card-bg); - } -} - -.card-header-pills { - margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list - margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list -} - -// Card image -.card-img-overlay { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - padding: var(--#{$prefix}card-img-overlay-padding); - @include border-radius(var(--#{$prefix}card-inner-border-radius)); -} - -.card-img, -.card-img-top, -.card-img-bottom { - width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch -} - -.card-img, -.card-img-top { - @include border-top-radius(var(--#{$prefix}card-inner-border-radius)); -} - -.card-img, -.card-img-bottom { - @include border-bottom-radius(var(--#{$prefix}card-inner-border-radius)); -} - - -// -// Card groups -// - -.card-group { - // The child selector allows nested `.card` within `.card-group` - // to display properly. - > .card { - margin-bottom: var(--#{$prefix}card-group-margin); - } - - @include media-breakpoint-up(sm) { - display: flex; - flex-flow: row wrap; - // The child selector allows nested `.card` within `.card-group` - // to display properly. - > .card { - // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4 - flex: 1 0 0%; - margin-bottom: 0; - - + .card { - margin-left: 0; - border-left: 0; - } - - // Handle rounded corners - @if $enable-rounded { - &:not(:last-child) { - @include border-end-radius(0); - - .card-img-top, - .card-header { - // stylelint-disable-next-line property-disallowed-list - border-top-right-radius: 0; - } - .card-img-bottom, - .card-footer { - // stylelint-disable-next-line property-disallowed-list - border-bottom-right-radius: 0; - } - } - - &:not(:first-child) { - @include border-start-radius(0); - - .card-img-top, - .card-header { - // stylelint-disable-next-line property-disallowed-list - border-top-left-radius: 0; - } - .card-img-bottom, - .card-footer { - // stylelint-disable-next-line property-disallowed-list - border-bottom-left-radius: 0; - } - } - } - } - } -} diff --git a/resources/tools/dash/app/pal/static/sass/bootstrap/_carousel.scss b/resources/tools/dash/app/pal/static/sass/bootstrap/_carousel.scss deleted file mode 100644 index 3d8fb15a06..0000000000 --- a/resources/tools/dash/app/pal/static/sass/bootstrap/_carousel.scss +++ /dev/null @@ -1,229 +0,0 @@ -// Notes on the classes: -// -// 1. .carousel.pointer-event should ideally be pan-y (to allow for users to scroll vertically) -// even when their scroll action started on a carousel, but for compatibility (with Firefox) -// we're preventing all actions instead -// 2. The .carousel-item-start and .carousel-item-end is used to indicate where -// the active slide is heading. -// 3. .active.carousel-item is the current slide. -// 4. .active.carousel-item-start and .active.carousel-item-end is the current -// slide in its in-transition state. Only one of these occurs at a time. -// 5. .carousel-item-next.carousel-item-start and .carousel-item-prev.carousel-item-end -// is the upcoming slide in transition. - -.carousel { - position: relative; -} - -.carousel.pointer-event { - touch-action: pan-y; -} - -.carousel-inner { - position: relative; - width: 100%; - overflow: hidden; - @include clearfix(); -} - -.carousel-item { - position: relative; - display: none; - float: left; - width: 100%; - margin-right: -100%; - backface-visibility: hidden; - @include transition($carousel-transition); -} - -.carousel-item.active, -.carousel-item-next, -.carousel-item-prev { - display: block; -} - -/* rtl:begin:ignore */ -.carousel-item-next:not(.carousel-item-start), -.active.carousel-item-end { - transform: translateX(100%); -} - -.carousel-item-prev:not(.carousel-item-end), -.active.carousel-item-start { - transform: translateX(-100%); -} - -/* rtl:end:ignore */ - - -// -// Alternate transitions -// - -.carousel-fade { - .carousel-item { - opacity: 0; - transition-property: opacity; - transform: none; - } - - .carousel-item.active, - .carousel-item-next.carousel-item-start, - .carousel-item-prev.carousel-item-end { - z-index: 1; - opacity: 1; - } - - .active.carousel-item-start, - .active.carousel-item-end { - z-index: 0; - opacity: 0; - @include transition(opacity 0s $carousel-transition-duration); - } -} - - -// -// Left/right controls for nav -// - -.carousel-control-prev, -.carousel-control-next { - position: absolute; - top: 0; - bottom: 0; - z-index: 1; - // Use flex for alignment (1-3) - display: flex; // 1. allow flex styles - align-items: center; // 2. vertically center contents - justify-content: center; // 3. horizontally center contents - width: $carousel-control-width; - padding: 0; - color: $carousel-control-color; - text-align: center; - background: none; - border: 0; - opacity: $carousel-control-opacity; - @include transition($carousel-control-transition); - - // Hover/focus state - &:hover, - &:focus { - color: $carousel-control-color; - text-decoration: none; - outline: 0; - opacity: $carousel-control-hover-opacity; - } -} -.carousel-control-prev { - left: 0; - background-image: if($enable-gradients, linear-gradient(90deg, rgba($black, .25), rgba($black, .001)), null); -} -.carousel-control-next { - right: 0; - background-image: if($enable-gradients, linear-gradient(270deg, rgba($black, .25), rgba($black, .001)), null); -} - -// Icons for within -.carousel-control-prev-icon, -.carousel-control-next-icon { - display: inline-block; - width: $carousel-control-icon-width; - height: $carousel-control-icon-width; - background-repeat: no-repeat; - background-position: 50%; - background-size: 100% 100%; -} - -/* rtl:options: { - "autoRename": true, - "stringMap":[ { - "name" : "prev-next", - "search" : "prev", - "replace" : "next" - } ] -} */ -.carousel-control-prev-icon { - background-image: escape-svg($carousel-control-prev-icon-bg); -} -.carousel-control-next-icon { - background-image: escape-svg($carousel-control-next-icon-bg); -} - -// Optional indicator pips/controls -// -// Add a container (such as a list) with the following class and add an item (ideally a focusable control, -// like a button) with data-bs-target for each slide your carousel holds. - -.carousel-indicators { - position: absolute; - right: 0; - bottom: 0; - left: 0; - z-index: 2; - display: flex; - justify-content: center; - padding: 0; - // Use the .carousel-control's width as margin so we don't overlay those - margin-right: $carousel-control-width; - margin-bottom: 1rem; - margin-left: $carousel-control-width; - list-style: none; - - [data-bs-target] { - box-sizing: content-box; - flex: 0 1 auto; - width: $carousel-indicator-width; - height: $carousel-indicator-height; - padding: 0; - margin-right: $carousel-indicator-spacer; - margin-left: $carousel-indicator-spacer; - text-indent: -999px; - cursor: pointer; - background-color: $carousel-indicator-active-bg; - background-clip: padding-box; - border: 0; - // Use transparent borders to increase the hit area by 10px on top and bottom. - border-top: $carousel-indicator-hit-area-height solid transparent; - border-bottom: $carousel-indicator-hit-area-height solid transparent; - opacity: $carousel-indicator-opacity; - @include transition($carousel-indicator-transition); - } - - .active { - opacity: $carousel-indicator-active-opacity; - } -} - - -// Optional captions -// -// - -.carousel-caption { - position: absolute; - right: (100% - $carousel-caption-width) * .5; - bottom: $carousel-caption-spacer; - left: (100% - $carousel-caption-width) * .5; - padding-top: $carousel-caption-padding-y; - padding-bottom: $carousel-caption-padding-y; - color: $carousel-caption-color; - text-align: center; -} - -// Dark mode carousel - -.carousel-dark { - .carousel-control-prev-icon, - .carousel-control-next-icon { - filter: $carousel-dark-control-icon-filter; - } - - .carousel-indicators [data-bs-target] { - background-color: $carousel-dark-indicator-active-bg; - } - - .carousel-caption { - color: $carousel-dark-caption-color; - } -} diff --git a/resources/tools/dash/app/pal/static/sass/bootstrap/_close.scss b/resources/tools/dash/app/pal/static/sass/bootstrap/_close.scss deleted file mode 100644 index a0813de8d3..0000000000 --- a/resources/tools/dash/app/pal/static/sass/bootstrap/_close.scss +++ /dev/null @@ -1,40 +0,0 @@ -// Transparent background and border properties included for button version. -// iOS requires the button element instead of an anchor tag. -// If you want the anchor version, it requires `href="#"`. -// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile - -.btn-close { - box-sizing: content-box; - width: $btn-close-width; - height: $btn-close-height; - padding: $btn-close-padding-y $btn-close-padding-x; - color: $btn-close-color; - background: transparent escape-svg($btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements - border: 0; // for button elements - @include border-radius(); - opacity: $btn-close-opacity; - - // Override 's hover style - &:hover { - color: $btn-close-color; - text-decoration: none; - opacity: $btn-close-hover-opacity; - } - - &:focus { - outline: 0; - box-shadow: $btn-close-focus-shadow; - opacity: $btn-close-focus-opacity; - } - - &:disabled, - &.disabled { - pointer-events: none; - user-select: none; - opacity: $btn-close-disabled-opacity; - } -} - -.btn-close-white { - filter: $btn-close-white-filter; -} diff --git a/resources/tools/dash/app/pal/static/sass/bootstrap/_containers.scss b/resources/tools/dash/app/pal/static/sass/bootstrap/_containers.scss deleted file mode 100644 index 83b31381bf..0000000000 --- a/resources/tools/dash/app/pal/static/sass/bootstrap/_containers.scss +++ /dev/null @@ -1,41 +0,0 @@ -// Container widths -// -// Set the container width, and override it for fixed navbars in media queries. - -@if $enable-container-classes { - // Single container class with breakpoint max-widths - .container, - // 100% wide container at all breakpoints - .container-fluid { - @include make-container(); - } - - // Responsive containers that are 100% wide until a breakpoint - @each $breakpoint, $container-max-width in $container-max-widths { - .container-#{$breakpoint} { - @extend .container-fluid; - } - - @include media-breakpoint-up($breakpoint, $grid-breakpoints) { - %responsive-container-#{$breakpoint} { - max-width: $container-max-width; - } - - // Extend each breakpoint which is smaller or equal to the current breakpoint - $extend-breakpoint: true; - - @each $name, $width in $grid-breakpoints { - @if ($extend-breakpoint) { - .container#{breakpoint-infix($name, $grid-breakpoints)} { - @extend %responsive-container-#{$breakpoint}; - } - - // Once the current breakpoint is reached, stop extending - @if ($breakpoint == $name) { - $extend-breakpoint: false; - } - } - } - } - } -} diff --git a/resources/tools/dash/app/pal/static/sass/bootstrap/_dropdown.scss b/resources/tools/dash/app/pal/static/sass/bootstrap/_dropdown.scss deleted file mode 100644 index 8899d25a0d..0000000000 --- a/resources/tools/dash/app/pal/static/sass/bootstrap/_dropdown.scss +++ /dev/null @@ -1,249 +0,0 @@ -// The dropdown wrapper (`
`) -.dropup, -.dropend, -.dropdown, -.dropstart, -.dropup-center, -.dropdown-center { - position: relative; -} - -.dropdown-toggle { - white-space: nowrap; - - // Generate the caret automatically - @include caret(); -} - -// The dropdown menu -.dropdown-menu { - // scss-docs-start dropdown-css-vars - --#{$prefix}dropdown-zindex: #{$zindex-dropdown}; - --#{$prefix}dropdown-min-width: #{$dropdown-min-width}; - --#{$prefix}dropdown-padding-x: #{$dropdown-padding-x}; - --#{$prefix}dropdown-padding-y: #{$dropdown-padding-y}; - --#{$prefix}dropdown-spacer: #{$dropdown-spacer}; - @include rfs($dropdown-font-size, --#{$prefix}dropdown-font-size); - --#{$prefix}dropdown-color: #{$dropdown-color}; - --#{$prefix}dropdown-bg: #{$dropdown-bg}; - --#{$prefix}dropdown-border-color: #{$dropdown-border-color}; - --#{$prefix}dropdown-border-radius: #{$dropdown-border-radius}; - --#{$prefix}dropdown-border-width: #{$dropdown-border-width}; - --#{$prefix}dropdown-inner-border-radius: #{$dropdown-inner-border-radius}; - --#{$prefix}dropdown-divider-bg: #{$dropdown-divider-bg}; - --#{$prefix}dropdown-divider-margin-y: #{$dropdown-divider-margin-y}; - --#{$prefix}dropdown-box-shadow: #{$dropdown-box-shadow}; - --#{$prefix}dropdown-link-color: #{$dropdown-link-color}; - --#{$prefix}dropdown-link-hover-color: #{$dropdown-link-hover-color}; - --#{$prefix}dropdown-link-hover-bg: #{$dropdown-link-hover-bg}; - --#{$prefix}dropdown-link-active-color: #{$dropdown-link-active-color}; - --#{$prefix}dropdown-link-active-bg: #{$dropdown-link-active-bg}; - --#{$prefix}dropdown-link-disabled-color: #{$dropdown-link-disabled-color}; - --#{$prefix}dropdown-item-padding-x: #{$dropdown-item-padding-x}; - --#{$prefix}dropdown-item-padding-y: #{$dropdown-item-padding-y}; - --#{$prefix}dropdown-header-color: #{$dropdown-header-color}; - --#{$prefix}dropdown-header-padding-x: #{$dropdown-header-padding-x}; - --#{$prefix}dropdown-header-padding-y: #{$dropdown-header-padding-y}; - // scss-docs-end dropdown-css-vars - - position: absolute; - z-index: var(--#{$prefix}dropdown-zindex); - display: none; // none by default, but block on "open" of the menu - min-width: var(--#{$prefix}dropdown-min-width); - padding: var(--#{$prefix}dropdown-padding-y) var(--#{$prefix}dropdown-padding-x); - margin: 0; // Override default margin of ul - @include font-size(var(--#{$prefix}dropdown-font-size)); - color: var(--#{$prefix}dropdown-color); - text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer) - list-style: none; - background-color: var(--#{$prefix}dropdown-bg); - background-clip: padding-box; - border: var(--#{$prefix}dropdown-border-width) solid var(--#{$prefix}dropdown-border-color); - @include border-radius(var(--#{$prefix}dropdown-border-radius)); - @include box-shadow(var(--#{$prefix}dropdown-box-shadow)); - - &[data-bs-popper] { - top: 100%; - left: 0; - margin-top: var(--#{$prefix}dropdown-spacer); - } - - @if $dropdown-padding-y == 0 { - > .dropdown-item:first-child, - > li:first-child .dropdown-item { - @include border-top-radius(var(--#{$prefix}dropdown-inner-border-radius)); - } - > .dropdown-item:last-child, - > li:last-child .dropdown-item { - @include border-bottom-radius(var(--#{$prefix}dropdown-inner-border-radius)); - } - - } -} - -// scss-docs-start responsive-breakpoints -// We deliberately hardcode the `bs-` prefix because we check -// this custom property in JS to determine Popper's positioning - -@each $breakpoint in map-keys($grid-breakpoints) { - @include media-breakpoint-up($breakpoint) { - $infix: breakpoint-infix($breakpoint, $grid-breakpoints); - - .dropdown-menu#{$infix}-start { - --bs-position: start; - - &[data-bs-popper] { - right: auto; - left: 0; - } - } - - .dropdown-menu#{$infix}-end { - --bs-position: end; - - &[data-bs-popper] { - right: 0; - left: auto; - } - } - } -} -// scss-docs-end responsive-breakpoints - -// Allow for dropdowns to go bottom up (aka, dropup-menu) -// Just add .dropup after the standard .dropdown class and you're set. -.dropup { - .dropdown-menu[data-bs-popper] { - top: auto; - bottom: 100%; - margin-top: 0; - margin-bottom: var(--#{$prefix}dropdown-spacer); - } - - .dropdown-toggle { - @include caret(up); - } -} - -.dropend { - .dropdown-menu[data-bs-popper] { - top: 0; - right: auto; - left: 100%; - margin-top: 0; - margin-left: var(--#{$prefix}dropdown-spacer); - } - - .dropdown-toggle { - @include caret(end); - &::after { - vertical-align: 0; - } - } -} - -.dropstart { - .dropdown-menu[data-bs-popper] { - top: 0; - right: 100%; - left: auto; - margin-top: 0; - margin-right: var(--#{$prefix}dropdown-spacer); - } - - .dropdown-toggle { - @include caret(start); - &::before { - vertical-align: 0; - } - } -} - - -// Dividers (basically an `
`) within the dropdown -.dropdown-divider { - height: 0; - margin: var(--#{$prefix}dropdown-divider-margin-y) 0; - overflow: hidden; - border-top: 1px solid var(--#{$prefix}dropdown-divider-bg); - opacity: 1; // Revisit in v6 to de-dupe styles that conflict with
element -} - -// Links, buttons, and more within the dropdown menu -// -// `