diff options
21 files changed, 1486 insertions, 0 deletions
diff --git a/resources/tools/dash/Dockerfile b/resources/tools/dash/Dockerfile new file mode 100644 index 0000000000..cd7eab7772 --- /dev/null +++ b/resources/tools/dash/Dockerfile @@ -0,0 +1,12 @@ +ARG PYTHON_VERSION=3.10 +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/app.ini b/resources/tools/dash/app/app.ini new file mode 100644 index 0000000000..bbf2943193 --- /dev/null +++ b/resources/tools/dash/app/app.ini @@ -0,0 +1,17 @@ +[uwsgi] +ini = :pal + +[pal] +module = wsgi:app + +processes = 2 +threads = 2 +plugin = python3 + +master = true +http-socket = :5000 +socket = /tmp/app.sock +chmod-socket = 666 +vacuum = true + +die-on-term = true
\ No newline at end of file diff --git a/resources/tools/dash/app/config.py b/resources/tools/dash/app/config.py new file mode 100644 index 0000000000..279317b781 --- /dev/null +++ b/resources/tools/dash/app/config.py @@ -0,0 +1,35 @@ +#!/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. + +from os import environ + + +class Config: + """Flask configuration variables.""" + + # General Config + FLASK_APP = environ.get("FLASK_APP") + FLASK_ENV = environ.get("FLASK_ENV") + SECRET_KEY = environ.get("SECRET_KEY") + + # Assets + LESS_BIN = environ.get("LESS_BIN") + ASSETS_DEBUG = environ.get("ASSETS_DEBUG") + LESS_RUN_IN_DEBUG = environ.get("LESS_RUN_IN_DEBUG") + + # Static Assets + STATIC_FOLDER = "static" + TEMPLATES_FOLDER = "templates" + COMPRESSOR_DEBUG = environ.get("COMPRESSOR_DEBUG") diff --git a/resources/tools/dash/app/pal/__init__.py b/resources/tools/dash/app/pal/__init__.py new file mode 100644 index 0000000000..9950defa44 --- /dev/null +++ b/resources/tools/dash/app/pal/__init__.py @@ -0,0 +1,39 @@ +# 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.""" +from flask import Flask +from flask_assets import Environment + + +def init_app(): + """Construct core Flask application with embedded Dash app.""" + app = Flask(__name__, instance_relative_config=False) + app.config.from_object("config.Config") + assets = Environment() + assets.init_app(app) + + with app.app_context(): + # Import parts of our core Flask app. + from . import routes + from .assets import compile_static_assets + + # Import Trending Dash application. + from .trending.dashboard import init_dashboard + + app = init_dashboard(app) + + # Compile static assets. + compile_static_assets(assets) + + return app diff --git a/resources/tools/dash/app/pal/assets.py b/resources/tools/dash/app/pal/assets.py new file mode 100644 index 0000000000..4237707734 --- /dev/null +++ b/resources/tools/dash/app/pal/assets.py @@ -0,0 +1,38 @@ +# 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. + +"""Compile static assets.""" +from flask import current_app as app +from flask_assets import Bundle + + +def compile_static_assets(assets): + """Compile stylesheets if in development mode. + + :param assets: Flask-Assets Environment. + :type assets: Environment + :returns: Compiled stylesheets. + :rtype: Environment + """ + assets.auto_build = True + assets.debug = False + less_bundle = Bundle( + "less/*.less", + filters="less,cssmin", + output="dist/css/styles.css", + extra={"rel": "stylesheet/less"}, + ) + assets.register("less_all", less_bundle) + if app.config["FLASK_ENV"] == "development": + less_bundle.build() + return assets diff --git a/resources/tools/dash/app/pal/routes.py b/resources/tools/dash/app/pal/routes.py new file mode 100644 index 0000000000..16680c4436 --- /dev/null +++ b/resources/tools/dash/app/pal/routes.py @@ -0,0 +1,27 @@ +# 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 + + +@app.route("/") +def home(): + """Landing page.""" + return render_template( + "index.jinja2", + title="FD.io CSIT", + description="Performance Dashboard", + template="home-template" + ) diff --git a/resources/tools/dash/app/pal/static/dist/css/styles.css b/resources/tools/dash/app/pal/static/dist/css/styles.css new file mode 100644 index 0000000000..d77f95a58f --- /dev/null +++ b/resources/tools/dash/app/pal/static/dist/css/styles.css @@ -0,0 +1 @@ +body,html{height:100%!important;margin:0;padding:0;background:#e7ecf7!important;font-family:'Lato',sans-serif}.row .col{padding:0!important}header{position:relative;width:100%;padding:30px 0!important;background:white!important;box-shadow:0 0 5px #bec6cf;font-family:'Lato',sans-serif}header .nav-wrapper{display:flex;align-items:center;justify-content:space-between;width:1000px;max-width:90%;margin:auto}header .nav-wrapper nav{display:flex}header .nav-wrapper .logo{display:inline-block;width:40px}header .nav-wrapper a{color:#70829d;font-size:1em;text-decoration:none;transition:all .3s ease-out}.home-template .container{margin:0!important}.home-template .card{width:800px;max-width:93%;height:fit-content;margin:50px auto;padding:60px;background:white;box-shadow:0 0 5px rgba(65,67,144,0.15);text-align:center}@media(max-width:800px){.home-template .card{max-width:78%;width:unset;padding:40px}}.home-template .card .logo{width:50px;margin:auto}.home-template .card .site-title{margin:10px 0 3px;color:#5f6988;font-family:proxima-nova,sans-serif;font-size:2.3em;line-height:1;text-transform:uppercase}.home-template .card p{margin:0;color:#7f92af;font-size:1.08em}.home-template .card a{color:#79aec8;font-weight:500;text-decoration:none;transition:all .2s ease}.home-template .card .dash-link{display:block;margin-top:30px;font-size:1.1em;font-weight:600}.home-template .card .dash-link:hover{opacity:.7}.home-template .card .dash-link i{margin-left:6px;font-size:.9em}body,html{height:100%!important;padding:0;background:#e7ecf7!important;font-family:'Lato',sans-serif;margin:0}.dash-template h1{display:inline-block;margin:0;font-size:1.5em}.dash-template .logo{width:40px;margin-right:20px}.dash-template .logo:hover{opacity:.7}.dash-template .nav-wrapper a{display:flex;align-items:center}#dash-container{width:1200px;max-width:95%;margin:50px auto 0}.container{margin:90px 30px;color:#182635}#_dash-app-content{max-width:95%!important;margin:90px auto!important;overflow:hidden}nav a{display:flex;align-items:center;justify-content:space-between;color:#59657b;line-height:1;text-decoration:none;transition:all .3s ease-out}nav a:hover{cursor:pointer;opacity:.7}nav a i{margin-right:5px}.dash-spreadsheet-container{max-width:100%;margin:0 auto 20px!important;overflow:hidden;border:0;border-radius:4px;box-shadow:0 0 4px #cdd3e2;font-family:'Lato',sans-serif}.dash-spreadsheet-container *{box-shadow:none!important;font-family:Lato,sans-serif}.dash-spreadsheet-container th,.dash-spreadsheet-container tr{box-shadow:none!important}.dash-spreadsheet-container td:first-of-type,.dash-spreadsheet-container tr:first-of-type{width:55px}.dash-spreadsheet-container td:last-of-type,.dash-spreadsheet-container tr:last-of-type{width:100px}.dash-spreadsheet-container th{padding:25px 12px!important;border-top:0!important;border-right:0!important;border-bottom:1px solid #e5e7eb!important;border-left:0!important;background:white!important;color:#404552}.dash-spreadsheet-container th .column-header--sort{margin-right:7px;transition:all .2s ease-out}.dash-spreadsheet-container th .column-header--sort:hover{color:#9bd2eb!important}.dash-spreadsheet-container th .column-header--sort svg{width:.5em}.dash-spreadsheet-container th .sort{order:2;color:#aeaeae!important;transition:all .3s ease-out}.dash-spreadsheet-container th .sort:hover{text-decoration:none;cursor:pointer;opacity:.7}.dash-spreadsheet-container th>div{display:flex;align-items:center;width:fit-content}.dash-spreadsheet-container th>div span:last-of-type{font-size:.8em;font-weight:600;text-transform:uppercase}.dash-spreadsheet-container td{padding:12px!important;font-size:.95em;text-align:left!important}.dash-spreadsheet-container td:first-of-type,.dash-spreadsheet-container td:last-of-type{max-width:50px!important}.dash-spreadsheet-container td .dash-cell-value{display:block!important;max-width:500px;overflow:hidden!important;font-size:1.2em;font-weight:300;text-align:left;text-overflow:ellipsis;white-space:nowrap;opacity:.8}.dash-spreadsheet-container td[data-dash-column="command"],.dash-spreadsheet-container .column-1{max-width:200px!important}.dash-spreadsheet-container td[data-dash-column="index"]{text-align:center!important}.dash-spreadsheet-container td[data-dash-column="index"] div{text-align:center!important}.dash-spreadsheet-container td[data-dash-column="index"]{color:#939da4;font-size:1.1em;font-weight:500}.dash-spreadsheet-container tr:nth-child(even){background:#f5f8fc!important}table tbody{box-shadow:0 0 7px #bdbdd2!important}table tbody tr{border:0!important}table tbody tr:nth-child(even){background:#e7eefa!important}table tbody tr td{padding:12px 10px!important;overflow:hidden!important;border:0!important;font-size:.65em!important;line-height:1.25!important;text-align:center!important}.dash-spreadsheet-container .dash-spreadsheet-inner td.focused{background-color:rgba(154,212,255,0.2)!important;box-shadow:0 0 4px #cdd3e2}.dash-spreadsheet-container .dash-spreadsheet-inner td .input-cell-value-shadow{width:100%}.dash-spreadsheet-container .dash-spreadsheet-inner td input.dash-cell-value.unfocused{caret-color:#317ed1!important}.dash-spreadsheet-inner .input-active{overflow:visible!important;color:#829ab2;text-align:left!important}.dash-spreadsheet-inner input::placeholder{color:grey}#histogram-graph{margin-bottom:30px;padding-bottom:176px!important;overflow:hidden;border-radius:4px;background:white;box-shadow:0 0 4px #cdd3e2}.main-svg{overflow:visible!important}header .nav-wrapper{width:1200px!important}
\ No newline at end of file diff --git a/resources/tools/dash/app/pal/static/dist/img/favicon.svg b/resources/tools/dash/app/pal/static/dist/img/favicon.svg new file mode 100644 index 0000000000..689757e3fd --- /dev/null +++ b/resources/tools/dash/app/pal/static/dist/img/favicon.svg @@ -0,0 +1,348 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 1000 568.31" style="enable-background:new 0 0 1000 568.31;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#1DCAD3;} + .st1{fill:#36B0C9;} + .st2{fill:#231F20;} + .st3{fill:#FFFFFF;} + .st4{fill:#9164CC;} + .st5{clip-path:url(#SVGID_2_);fill:url(#SVGID_3_);} + .st6{fill:#201747;} + .st7{fill-rule:evenodd;clip-rule:evenodd;fill:#10CFC9;} + .st8{clip-path:url(#SVGID_5_);fill:#231F20;} + .st9{fill-rule:evenodd;clip-rule:evenodd;fill:#231F20;} + .st10{clip-path:url(#SVGID_7_);fill:#FFFFFF;} + .st11{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;} + .st12{fill:#8CCEAF;} + .st13{fill:#008476;} + .st14{fill:#25BCBD;} + .st15{fill:#004D70;} + .st16{fill:#20BBBB;} + .st17{fill:#024D70;} + .st18{fill-rule:evenodd;clip-rule:evenodd;fill:#F58B1F;} + .st19{fill-rule:evenodd;clip-rule:evenodd;fill:#18335B;} + .st20{clip-path:url(#SVGID_9_);} + .st21{clip-path:url(#SVGID_11_);} + .st22{fill:#18335B;} + .st23{fill:#F58B1F;} + .st24{clip-path:url(#SVGID_15_);} + .st25{clip-path:url(#SVGID_17_);} + .st26{clip-path:url(#SVGID_21_);} + .st27{clip-path:url(#SVGID_23_);} + .st28{clip-path:url(#SVGID_27_);} + .st29{clip-path:url(#SVGID_29_);} + .st30{clip-path:url(#SVGID_33_);} + .st31{clip-path:url(#SVGID_35_);} + .st32{clip-path:url(#SVGID_39_);} + .st33{clip-path:url(#SVGID_41_);} + .st34{fill:#416BA9;} + .st35{fill:#73C3D5;} + .st36{opacity:0.8;} + .st37{fill:#3A3A3A;} + .st38{fill:url(#SVGID_44_);} + .st39{fill:none;stroke:#000000;stroke-width:6.3384;} + .st40{fill:none;stroke:#000000;stroke-width:3.1692;} + .st41{fill:#48494B;} + .st42{fill:#C1986C;} + .st43{fill:url(#SVGID_63_);} + .st44{fill:url(#SVGID_64_);} + .st45{fill:url(#SVGID_65_);} + .st46{fill:url(#SVGID_66_);} + .st47{fill:url(#SVGID_67_);} + .st48{fill:#4D4E4E;} + .st49{fill:#27B373;} + .st50{fill:#5DC4CD;} + .st51{fill:#1E8756;} + .st52{fill:#3D1152;} + .st53{fill:#922C48;} + .st54{fill-rule:evenodd;clip-rule:evenodd;fill:#922C48;} + .st55{fill:#404041;} + .st56{fill:#EC1C24;} + .st57{fill:#373A36;} + .st58{fill:#808184;} + .st59{fill:#262261;} + .st60{fill:#6FCBDC;} + .st61{fill:#2F3436;} + .st62{fill:#5F97D0;} + .st63{fill:#132428;} + .st64{fill:#85C041;} + .st65{fill:#677784;} + .st66{fill:url(#SVGID_68_);} + .st67{opacity:0.2;clip-path:url(#SVGID_70_);} + .st68{fill:#FFFEFA;} + .st69{opacity:0.1;} + .st70{fill:url(#SVGID_71_);} + .st71{opacity:0.3;} + .st72{opacity:0.08;} + .st73{opacity:0.1;fill:url(#Wordmark_1_);} + .st74{fill:url(#SVGID_104_);} + .st75{opacity:0.6;fill:url(#SVGID_107_);} + .st76{opacity:0.4;} + .st77{fill:url(#SVGID_110_);} + .st78{opacity:0.6;fill:url(#SVGID_113_);} + .st79{fill:url(#SVGID_116_);} + .st80{opacity:0.6;fill:url(#SVGID_119_);} + .st81{fill:url(#SVGID_122_);} + .st82{opacity:0.6;fill:url(#SVGID_125_);} + .st83{fill:url(#SVGID_128_);} + .st84{opacity:0.6;fill:url(#SVGID_131_);} + .st85{fill:#221F1F;} + .st86{fill:none;} + .st87{fill:#00416B;} + .st88{opacity:0.8;fill:url(#XMLID_323_);} + .st89{fill:#4197CB;} + .st90{fill:#003E52;} + .st91{fill:#3F96B4;} + .st92{fill:#B9DBE5;} + .st93{opacity:0.3;fill:#231F20;} + .st94{opacity:0.3;fill:#FFFFFF;} + .st95{fill:#050013;} + .st96{fill:#E87200;} + .st97{fill:#FCB813;} + .st98{fill:#3D3935;} + .st99{fill:#FFB600;} + .st100{fill:#FCB814;} + .st101{fill:#F48120;} + .st102{fill:#EF4E25;} + .st103{fill:#ED3024;} + .st104{fill:#E0592A;} + .st105{fill:#00ADBB;} + .st106{fill:#00829B;} + .st107{fill:#93D500;} + .st108{fill:#4D5A31;} + .st109{fill:#6BA43A;} + .st110{fill:#424143;} + .st111{fill-rule:evenodd;clip-rule:evenodd;fill:#C7E6B4;} + .st112{fill-rule:evenodd;clip-rule:evenodd;fill:#5A9891;} + .st113{fill-rule:evenodd;clip-rule:evenodd;fill:#127870;} + .st114{fill-rule:evenodd;clip-rule:evenodd;fill:#5CCFD5;} + .st115{fill-rule:evenodd;clip-rule:evenodd;fill:#ACD5CD;} + .st116{fill-rule:evenodd;clip-rule:evenodd;fill:#B5ECC9;} + .st117{fill-rule:evenodd;clip-rule:evenodd;fill:#A1D683;} + .st118{fill-rule:evenodd;clip-rule:evenodd;fill:#DEF0D3;} + .st119{fill-rule:evenodd;clip-rule:evenodd;fill:#91B9B4;} + .st120{fill-rule:evenodd;clip-rule:evenodd;fill:#006860;} + .st121{fill-rule:evenodd;clip-rule:evenodd;fill:#00ADBB;} + .st122{fill-rule:evenodd;clip-rule:evenodd;fill:#B4E7E9;} + .st123{fill-rule:evenodd;clip-rule:evenodd;fill:#007565;} + .st124{fill-rule:evenodd;clip-rule:evenodd;fill:#00CE7C;} + .st125{fill-rule:evenodd;clip-rule:evenodd;fill:#5FD896;} + .st126{fill:#007DA5;} + .st127{fill:#313032;} + .st128{fill:#24272A;} + .st129{fill:#00AFAA;} + .st130{fill:#66C9BA;} + .st131{fill:#0069A7;} + .st132{fill:#002F87;} + .st133{fill:#8BC53F;} + .st134{fill:#1A1A1A;} + .st135{fill:#0095D6;} + .st136{fill:#003F5F;} + .st137{fill:#2D317C;} + .st138{fill:#41BFBF;} + .st139{fill:#293C97;} + .st140{fill:#52C2BD;} + .st141{fill:url(#SVGID_134_);} + .st142{fill:url(#SVGID_135_);} + .st143{fill:url(#SVGID_136_);} + .st144{fill:#0DBEEA;} + .st145{fill:#097EC2;} + .st146{fill:#133C63;} + .st147{fill:#3B91CF;} + .st148{fill:#C8DEE8;} + .st149{fill:#629BBA;} + .st150{fill:#F8BE19;} + .st151{fill:url(#SVGID_137_);} + .st152{fill:url(#SVGID_138_);} + .st153{fill:url(#SVGID_139_);} + .st154{fill:#00233B;} + .st155{fill:url(#SVGID_140_);} + .st156{fill:url(#SVGID_141_);} + .st157{fill:url(#SVGID_142_);} + .st158{fill:url(#SVGID_143_);} + .st159{fill:url(#SVGID_144_);} + .st160{fill:url(#SVGID_145_);} + .st161{fill:url(#SVGID_146_);} + .st162{fill:url(#SVGID_147_);} + .st163{fill:url(#SVGID_148_);} + .st164{fill:url(#SVGID_149_);} + .st165{fill:url(#SVGID_150_);} + .st166{fill:url(#SVGID_151_);} + .st167{fill:url(#SVGID_152_);} + .st168{fill:url(#SVGID_153_);} + .st169{fill:url(#SVGID_154_);} + .st170{fill:url(#SVGID_155_);} + .st171{fill:url(#SVGID_156_);} + .st172{fill:url(#SVGID_157_);} + .st173{fill:url(#SVGID_158_);} + .st174{fill:url(#SVGID_159_);} + .st175{fill:url(#SVGID_160_);} + .st176{fill:url(#SVGID_161_);} + .st177{fill:url(#SVGID_162_);} + .st178{fill:url(#SVGID_163_);} + .st179{fill:url(#SVGID_164_);} + .st180{fill:url(#SVGID_165_);} + .st181{fill:url(#SVGID_166_);} + .st182{fill:url(#SVGID_167_);} + .st183{fill:url(#SVGID_168_);} + .st184{fill:url(#SVGID_169_);} + .st185{fill:url(#SVGID_170_);} + .st186{fill:url(#SVGID_171_);} + .st187{fill:url(#SVGID_172_);} + .st188{fill:url(#SVGID_173_);} + .st189{fill:url(#SVGID_174_);} + .st190{fill:url(#SVGID_175_);} + .st191{fill:url(#SVGID_176_);} + .st192{fill:url(#SVGID_177_);} + .st193{fill:url(#SVGID_178_);} + .st194{fill:#C31230;} + .st195{fill:#807F82;} + .st196{fill-rule:evenodd;clip-rule:evenodd;fill:#C31230;} + .st197{fill-rule:evenodd;clip-rule:evenodd;fill:#807F82;} + .st198{fill:#2D2D2D;} + .st199{display:none;fill:#2D2D2D;} + .st200{fill:#D11F3C;} + .st201{fill:#E42C4C;stroke:#E42C4C;stroke-width:1.0503;stroke-miterlimit:10;} + .st202{display:none;fill:#231F20;} + .st203{display:none;fill:#FFFFFF;} + .st204{fill:#FF7F30;} + .st205{opacity:0.3;fill:#FF7F30;} + .st206{opacity:0.6;fill:#FF7F30;} + .st207{opacity:0.7;fill:#FF7F30;} + .st208{fill:#221C35;} + .st209{fill:#1B98D5;} + .st210{fill:#173963;} + .st211{fill:#009ADE;} + .st212{fill:#003764;} + .st213{fill:#2A7DE1;} + .st214{opacity:0.4;clip-path:url(#XMLID_324_);fill:#221F1F;} + .st215{fill:#002A3A;} + .st216{fill:#0033A1;} + .st217{fill:url(#SVGID_179_);} + .st218{fill:url(#SVGID_180_);} + .st219{fill:url(#SVGID_181_);} + .st220{fill:url(#SVGID_182_);} + .st221{fill:#007EC4;} + .st222{fill-rule:evenodd;clip-rule:evenodd;fill:url(#SVGID_183_);} + .st223{fill-rule:evenodd;clip-rule:evenodd;fill:#E6E7E8;} + .st224{fill:#009345;} + .st225{fill:#BBBCB8;} + .st226{fill:#72C0EB;} + .st227{fill:#939598;} + .st228{fill-rule:evenodd;clip-rule:evenodd;fill:#2CB8EB;} + .st229{fill:#2CB8EB;} + .st230{fill:#81B83A;} + .st231{fill-rule:evenodd;clip-rule:evenodd;fill:#81B83A;} + .st232{enable-background:new ;} + .st233{fill:#FF6F3E;} + .st234{fill:#12143D;} + .st235{fill:url(#SVGID_184_);} + .st236{fill:url(#SVGID_185_);} + .st237{fill:url(#SVGID_186_);} + .st238{fill:url(#SVGID_187_);} + .st239{fill:url(#SVGID_188_);} + .st240{fill:url(#SVGID_189_);} + .st241{fill:url(#SVGID_190_);} + .st242{fill:url(#SVGID_191_);} + .st243{fill:url(#SVGID_192_);} + .st244{fill:#7C51A0;} + .st245{fill:#9F66A9;} + .st246{fill:#9F80B9;} + .st247{fill:url(#SVGID_193_);} + .st248{fill:url(#SVGID_194_);} + .st249{fill:url(#SVGID_195_);} + .st250{fill:url(#SVGID_196_);} + .st251{fill:#2D3136;} + .st252{fill:#76777A;} + .st253{fill:#A7A8A9;} + .st254{fill:#0082CA;} + .st255{fill:#FFB259;} + .st256{fill:#385CAD;} + .st257{fill:#7BA0C4;} + .st258{fill:#EBA900;} + .st259{fill:#929497;} + .st260{opacity:0.7;fill:#FFFFFF;} + .st261{fill:#016BAF;} + .st262{fill:#343432;} + .st263{fill:#6D6E70;} + .st264{fill:#F4B01B;} + .st265{fill:#293271;} + .st266{fill:#A1D33C;} + .st267{fill:#212322;} + .st268{fill:#0047BA;} + .st269{fill:#969CDE;} + .st270{fill:#047BC1;} + .st271{fill:url(#SVGID_197_);} + .st272{fill:url(#SVGID_198_);} + .st273{fill:url(#SVGID_199_);} + .st274{fill:url(#SVGID_200_);} + .st275{fill:url(#SVGID_201_);} + .st276{fill:url(#SVGID_202_);} + .st277{fill:url(#SVGID_203_);} + .st278{fill:#13517C;} + .st279{fill:#0077A6;} + .st280{fill:none;stroke:#231F20;stroke-width:5.9036;stroke-miterlimit:10;} + .st281{fill:#00A94F;} + .st282{fill:none;stroke:#231F20;stroke-width:3.2172;stroke-miterlimit:10;} + .st283{fill:#59595C;} + .st284{opacity:0.349;fill:#F9AE19;} + .st285{opacity:0.349;fill:#E99F22;} + .st286{opacity:0.349;fill:#E47D25;} + .st287{fill:#F9AE19;} + .st288{fill:#E99F22;} + .st289{fill:#F09B20;} + .st290{fill:#E47D25;} + .st291{fill:#E89223;} + .st292{opacity:0.651;fill:#F9AE19;} + .st293{fill:#E68825;} + .st294{opacity:0.651;fill:#E99F22;} + .st295{fill:#EB8D23;} + .st296{opacity:0.7725;fill:#EF9B21;} + .st297{opacity:0.651;fill:#E47D25;} + .st298{opacity:0.7725;fill:#EA9622;} + .st299{fill:url(#SVGID_204_);} + .st300{fill:#55575B;} + .st301{fill:#EE424E;} + .st302{fill:#34424B;} +</style> +<g> + <g> + <path class="st55" d="M772.88,526c9.95,0,15.7,5.53,15.7,15.48c0,10.17-5.75,15.48-15.7,15.48c-9.95,0-15.48-5.31-15.48-15.48 + C757.4,531.53,762.93,526,772.88,526z"/> + <path class="st55" d="M832.94,393.35c8.18,0,13.71,3.32,13.71,12.38c0,9.29-5.53,12.6-13.71,12.6c-8.4,0-14.15-3.32-14.15-12.6 + C818.79,396.67,824.54,393.35,832.94,393.35z M821.22,438.67h22.99V554.3h-22.99V438.67z"/> + <path class="st55" d="M934.56,435.58c36.25,0,61.9,26.09,61.9,61.24c0,34.71-25.65,60.58-61.9,60.58 + c-35.82,0-61.69-25.87-61.69-60.58C872.88,461.67,898.75,435.58,934.56,435.58z M934.56,536.18c23.66,0,39.79-17.03,39.79-39.36 + c0-22.77-16.14-40.02-39.79-40.02c-23.44,0-39.36,17.25-39.36,40.02C895.21,519.15,911.13,536.18,934.56,536.18z"/> + </g> + <g> + <path class="st56" d="M724.15,245.36c-0.97-8.4-17.24-16.23-17.24-16.23c-6.81-4.71-8.03-16.23-7.16-20.6 + c0.87-4.36,15.01-36.66,15.01-36.66c11.52-11.35,31.6-35.44,33.87-48.88c1.07-6.31-3.14-38.93,5.41-49.75 + c5.63-7.12,22.35-15.36,25.84-18.16c3.49-2.79,6.28-11,4.71-14.84c-1.57-3.84-27.41-4.02-27.41-4.02s-2.16-10.79-17.62-11.8 + c-6.05-0.2-10.18,1.3-10.18,1.3c1.78-0.89,4.69-2.18,6.78-3.1c-0.54-3.56-1.89-11.45-3.24-11.72c-1.43-0.29-4.73,5.28-6.27,7.21 + l0.28,3.42l-1.11-2.85l-1.63-4.2l-0.02-0.06h0c-0.64-1.74-1.36-3.37-2.08-3.53c-1.57-0.34-38.06,50.81-42.6,57.44 + c-4.54,6.63-9.25,17.81-33.87,25.49c-17.37,5.42-53.43,6.32-81.13,15.16l0,0c-14.25,1.43-53.29,33.79-83.15,32.62 + c-20.05-0.78-35.61-6.28-39.57-15.25c0,0,4.19,41.32,25.6,43.64c0,0,13.5,2.33,26.53-9.31c0,0-3.72,7.36-8.38,9.5 + c0,0,18.07-4.62,29.06-12.94c3.37-7.06,9.22-17.4,17.46-25.17c0.53-0.52,0.86-0.8,0.86-0.8c-0.29,0.26-0.57,0.53-0.86,0.8 + c-2.65,2.6-10.68,11.48-11.86,24.73c-0.24,2.64-0.21,5.44,0.2,8.41c0,8.9,9.66,20.78,9.66,26.19c0,7.16-16.76,20.25-17.81,23.74 + c-0.58,1.95-2.35,16.91,0.69,29.77h-59.09c-56.8,0-78.68,56.8-78.68,56.8l-24.4,68h-10.52c-8.25,0-14.94,6.69-14.94,14.94 + c0,8.19,6.59,14.81,14.75,14.92l-0.01,0.02h0.2h5.92c8.25,0,14.94,6.69,14.94,14.94c0,8.25-6.69,14.94-14.94,14.94H197.01 + c-8.25,0-14.94,6.69-14.94,14.94c0,8.25,6.69,14.94,14.94,14.94h154.15c8.25,0,14.94,6.69,14.94,14.94 + c0,8.25-6.69,14.94-14.94,14.94h-32.39H146.48h-32.39c-8.25,0-14.94,6.69-14.94,14.94c0,8.25,6.69,14.94,14.94,14.94h183.08 + l-13.71,38.21h113.6l35.67-99.4h1.72c79.83,0,109.91-85.2,109.91-85.2h-81.05l15.29-42.6l88.87,0c56.8,0,83.71-85.2,83.71-85.2 + H539.99c-2.48-4.72-5.03-9.43-5.03-13.01c0-18.5,49.93-30.55,48.36-60.4c-4.08-16.85,2.51-25.92,2.51-25.92 + c-4.2,9.35,0.01,19.79,2.11,24c0.03,0,0.06,0,0.1,0c13.97,0,41.9,15.36,59.18,15.36c11.43,0,20.41-2.37,25.19-3.97 + c0.69-3.96,0.82-14.29-14.36-20.96c0,0,18.37,0.16,18.15,19.52c0,0-2.09,31.42,0.7,54.29c0.55,4.48,1.7,8.11,3.22,11.09h-0.52 + c-13.7,55.08-55.31,85.2-55.31,85.2h60.7l-51.92,142.02l-0.04-0.01H510.67c-56.8,0-85.2,85.2-85.2,85.2H601.9 + c56.8,0,111.69,5.33,144.18-85.2l40.77-113.6C810.25,293.33,776.46,249.98,724.15,245.36z"/> + <path class="st56" d="M56.25,489.25H18.47c-8.25,0-14.94,6.69-14.94,14.94c0,8.25,6.69,14.94,14.94,14.94h37.78 + c8.25,0,14.94-6.69,14.94-14.94C71.19,495.94,64.5,489.25,56.25,489.25z"/> + <path class="st56" d="M171.38,399.61h120.5c8.25,0,14.94-6.69,14.94-14.94c0-8.25-6.69-14.94-14.94-14.94H102.14 + c-8.25,0-14.94,6.69-14.94,14.94c0,8.25,6.69,14.94,14.94,14.94H171.38z"/> + <path class="st56" d="M180.84,339.85h162.85c8.25,0,14.94-6.69,14.94-14.94c0-8.25-6.69-14.94-14.94-14.94H180.84 + c-8.25,0-14.94,6.69-14.94,14.94C165.9,333.17,172.59,339.85,180.84,339.85z"/> + </g> +</g> +</svg> diff --git a/resources/tools/dash/app/pal/static/img/logo.svg b/resources/tools/dash/app/pal/static/img/logo.svg new file mode 100644 index 0000000000..689757e3fd --- /dev/null +++ b/resources/tools/dash/app/pal/static/img/logo.svg @@ -0,0 +1,348 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 1000 568.31" style="enable-background:new 0 0 1000 568.31;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#1DCAD3;} + .st1{fill:#36B0C9;} + .st2{fill:#231F20;} + .st3{fill:#FFFFFF;} + .st4{fill:#9164CC;} + .st5{clip-path:url(#SVGID_2_);fill:url(#SVGID_3_);} + .st6{fill:#201747;} + .st7{fill-rule:evenodd;clip-rule:evenodd;fill:#10CFC9;} + .st8{clip-path:url(#SVGID_5_);fill:#231F20;} + .st9{fill-rule:evenodd;clip-rule:evenodd;fill:#231F20;} + .st10{clip-path:url(#SVGID_7_);fill:#FFFFFF;} + .st11{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;} + .st12{fill:#8CCEAF;} + .st13{fill:#008476;} + .st14{fill:#25BCBD;} + .st15{fill:#004D70;} + .st16{fill:#20BBBB;} + .st17{fill:#024D70;} + .st18{fill-rule:evenodd;clip-rule:evenodd;fill:#F58B1F;} + .st19{fill-rule:evenodd;clip-rule:evenodd;fill:#18335B;} + .st20{clip-path:url(#SVGID_9_);} + .st21{clip-path:url(#SVGID_11_);} + .st22{fill:#18335B;} + .st23{fill:#F58B1F;} + .st24{clip-path:url(#SVGID_15_);} + .st25{clip-path:url(#SVGID_17_);} + .st26{clip-path:url(#SVGID_21_);} + .st27{clip-path:url(#SVGID_23_);} + .st28{clip-path:url(#SVGID_27_);} + .st29{clip-path:url(#SVGID_29_);} + .st30{clip-path:url(#SVGID_33_);} + .st31{clip-path:url(#SVGID_35_);} + .st32{clip-path:url(#SVGID_39_);} + .st33{clip-path:url(#SVGID_41_);} + .st34{fill:#416BA9;} + .st35{fill:#73C3D5;} + .st36{opacity:0.8;} + .st37{fill:#3A3A3A;} + .st38{fill:url(#SVGID_44_);} + .st39{fill:none;stroke:#000000;stroke-width:6.3384;} + .st40{fill:none;stroke:#000000;stroke-width:3.1692;} + .st41{fill:#48494B;} + .st42{fill:#C1986C;} + .st43{fill:url(#SVGID_63_);} + .st44{fill:url(#SVGID_64_);} + .st45{fill:url(#SVGID_65_);} + .st46{fill:url(#SVGID_66_);} + .st47{fill:url(#SVGID_67_);} + .st48{fill:#4D4E4E;} + .st49{fill:#27B373;} + .st50{fill:#5DC4CD;} + .st51{fill:#1E8756;} + .st52{fill:#3D1152;} + .st53{fill:#922C48;} + .st54{fill-rule:evenodd;clip-rule:evenodd;fill:#922C48;} + .st55{fill:#404041;} + .st56{fill:#EC1C24;} + .st57{fill:#373A36;} + .st58{fill:#808184;} + .st59{fill:#262261;} + .st60{fill:#6FCBDC;} + .st61{fill:#2F3436;} + .st62{fill:#5F97D0;} + .st63{fill:#132428;} + .st64{fill:#85C041;} + .st65{fill:#677784;} + .st66{fill:url(#SVGID_68_);} + .st67{opacity:0.2;clip-path:url(#SVGID_70_);} + .st68{fill:#FFFEFA;} + .st69{opacity:0.1;} + .st70{fill:url(#SVGID_71_);} + .st71{opacity:0.3;} + .st72{opacity:0.08;} + .st73{opacity:0.1;fill:url(#Wordmark_1_);} + .st74{fill:url(#SVGID_104_);} + .st75{opacity:0.6;fill:url(#SVGID_107_);} + .st76{opacity:0.4;} + .st77{fill:url(#SVGID_110_);} + .st78{opacity:0.6;fill:url(#SVGID_113_);} + .st79{fill:url(#SVGID_116_);} + .st80{opacity:0.6;fill:url(#SVGID_119_);} + .st81{fill:url(#SVGID_122_);} + .st82{opacity:0.6;fill:url(#SVGID_125_);} + .st83{fill:url(#SVGID_128_);} + .st84{opacity:0.6;fill:url(#SVGID_131_);} + .st85{fill:#221F1F;} + .st86{fill:none;} + .st87{fill:#00416B;} + .st88{opacity:0.8;fill:url(#XMLID_323_);} + .st89{fill:#4197CB;} + .st90{fill:#003E52;} + .st91{fill:#3F96B4;} + .st92{fill:#B9DBE5;} + .st93{opacity:0.3;fill:#231F20;} + .st94{opacity:0.3;fill:#FFFFFF;} + .st95{fill:#050013;} + .st96{fill:#E87200;} + .st97{fill:#FCB813;} + .st98{fill:#3D3935;} + .st99{fill:#FFB600;} + .st100{fill:#FCB814;} + .st101{fill:#F48120;} + .st102{fill:#EF4E25;} + .st103{fill:#ED3024;} + .st104{fill:#E0592A;} + .st105{fill:#00ADBB;} + .st106{fill:#00829B;} + .st107{fill:#93D500;} + .st108{fill:#4D5A31;} + .st109{fill:#6BA43A;} + .st110{fill:#424143;} + .st111{fill-rule:evenodd;clip-rule:evenodd;fill:#C7E6B4;} + .st112{fill-rule:evenodd;clip-rule:evenodd;fill:#5A9891;} + .st113{fill-rule:evenodd;clip-rule:evenodd;fill:#127870;} + .st114{fill-rule:evenodd;clip-rule:evenodd;fill:#5CCFD5;} + .st115{fill-rule:evenodd;clip-rule:evenodd;fill:#ACD5CD;} + .st116{fill-rule:evenodd;clip-rule:evenodd;fill:#B5ECC9;} + .st117{fill-rule:evenodd;clip-rule:evenodd;fill:#A1D683;} + .st118{fill-rule:evenodd;clip-rule:evenodd;fill:#DEF0D3;} + .st119{fill-rule:evenodd;clip-rule:evenodd;fill:#91B9B4;} + .st120{fill-rule:evenodd;clip-rule:evenodd;fill:#006860;} + .st121{fill-rule:evenodd;clip-rule:evenodd;fill:#00ADBB;} + .st122{fill-rule:evenodd;clip-rule:evenodd;fill:#B4E7E9;} + .st123{fill-rule:evenodd;clip-rule:evenodd;fill:#007565;} + .st124{fill-rule:evenodd;clip-rule:evenodd;fill:#00CE7C;} + .st125{fill-rule:evenodd;clip-rule:evenodd;fill:#5FD896;} + .st126{fill:#007DA5;} + .st127{fill:#313032;} + .st128{fill:#24272A;} + .st129{fill:#00AFAA;} + .st130{fill:#66C9BA;} + .st131{fill:#0069A7;} + .st132{fill:#002F87;} + .st133{fill:#8BC53F;} + .st134{fill:#1A1A1A;} + .st135{fill:#0095D6;} + .st136{fill:#003F5F;} + .st137{fill:#2D317C;} + .st138{fill:#41BFBF;} + .st139{fill:#293C97;} + .st140{fill:#52C2BD;} + .st141{fill:url(#SVGID_134_);} + .st142{fill:url(#SVGID_135_);} + .st143{fill:url(#SVGID_136_);} + .st144{fill:#0DBEEA;} + .st145{fill:#097EC2;} + .st146{fill:#133C63;} + .st147{fill:#3B91CF;} + .st148{fill:#C8DEE8;} + .st149{fill:#629BBA;} + .st150{fill:#F8BE19;} + .st151{fill:url(#SVGID_137_);} + .st152{fill:url(#SVGID_138_);} + .st153{fill:url(#SVGID_139_);} + .st154{fill:#00233B;} + .st155{fill:url(#SVGID_140_);} + .st156{fill:url(#SVGID_141_);} + .st157{fill:url(#SVGID_142_);} + .st158{fill:url(#SVGID_143_);} + .st159{fill:url(#SVGID_144_);} + .st160{fill:url(#SVGID_145_);} + .st161{fill:url(#SVGID_146_);} + .st162{fill:url(#SVGID_147_);} + .st163{fill:url(#SVGID_148_);} + .st164{fill:url(#SVGID_149_);} + .st165{fill:url(#SVGID_150_);} + .st166{fill:url(#SVGID_151_);} + .st167{fill:url(#SVGID_152_);} + .st168{fill:url(#SVGID_153_);} + .st169{fill:url(#SVGID_154_);} + .st170{fill:url(#SVGID_155_);} + .st171{fill:url(#SVGID_156_);} + .st172{fill:url(#SVGID_157_);} + .st173{fill:url(#SVGID_158_);} + .st174{fill:url(#SVGID_159_);} + .st175{fill:url(#SVGID_160_);} + .st176{fill:url(#SVGID_161_);} + .st177{fill:url(#SVGID_162_);} + .st178{fill:url(#SVGID_163_);} + .st179{fill:url(#SVGID_164_);} + .st180{fill:url(#SVGID_165_);} + .st181{fill:url(#SVGID_166_);} + .st182{fill:url(#SVGID_167_);} + .st183{fill:url(#SVGID_168_);} + .st184{fill:url(#SVGID_169_);} + .st185{fill:url(#SVGID_170_);} + .st186{fill:url(#SVGID_171_);} + .st187{fill:url(#SVGID_172_);} + .st188{fill:url(#SVGID_173_);} + .st189{fill:url(#SVGID_174_);} + .st190{fill:url(#SVGID_175_);} + .st191{fill:url(#SVGID_176_);} + .st192{fill:url(#SVGID_177_);} + .st193{fill:url(#SVGID_178_);} + .st194{fill:#C31230;} + .st195{fill:#807F82;} + .st196{fill-rule:evenodd;clip-rule:evenodd;fill:#C31230;} + .st197{fill-rule:evenodd;clip-rule:evenodd;fill:#807F82;} + .st198{fill:#2D2D2D;} + .st199{display:none;fill:#2D2D2D;} + .st200{fill:#D11F3C;} + .st201{fill:#E42C4C;stroke:#E42C4C;stroke-width:1.0503;stroke-miterlimit:10;} + .st202{display:none;fill:#231F20;} + .st203{display:none;fill:#FFFFFF;} + .st204{fill:#FF7F30;} + .st205{opacity:0.3;fill:#FF7F30;} + .st206{opacity:0.6;fill:#FF7F30;} + .st207{opacity:0.7;fill:#FF7F30;} + .st208{fill:#221C35;} + .st209{fill:#1B98D5;} + .st210{fill:#173963;} + .st211{fill:#009ADE;} + .st212{fill:#003764;} + .st213{fill:#2A7DE1;} + .st214{opacity:0.4;clip-path:url(#XMLID_324_);fill:#221F1F;} + .st215{fill:#002A3A;} + .st216{fill:#0033A1;} + .st217{fill:url(#SVGID_179_);} + .st218{fill:url(#SVGID_180_);} + .st219{fill:url(#SVGID_181_);} + .st220{fill:url(#SVGID_182_);} + .st221{fill:#007EC4;} + .st222{fill-rule:evenodd;clip-rule:evenodd;fill:url(#SVGID_183_);} + .st223{fill-rule:evenodd;clip-rule:evenodd;fill:#E6E7E8;} + .st224{fill:#009345;} + .st225{fill:#BBBCB8;} + .st226{fill:#72C0EB;} + .st227{fill:#939598;} + .st228{fill-rule:evenodd;clip-rule:evenodd;fill:#2CB8EB;} + .st229{fill:#2CB8EB;} + .st230{fill:#81B83A;} + .st231{fill-rule:evenodd;clip-rule:evenodd;fill:#81B83A;} + .st232{enable-background:new ;} + .st233{fill:#FF6F3E;} + .st234{fill:#12143D;} + .st235{fill:url(#SVGID_184_);} + .st236{fill:url(#SVGID_185_);} + .st237{fill:url(#SVGID_186_);} + .st238{fill:url(#SVGID_187_);} + .st239{fill:url(#SVGID_188_);} + .st240{fill:url(#SVGID_189_);} + .st241{fill:url(#SVGID_190_);} + .st242{fill:url(#SVGID_191_);} + .st243{fill:url(#SVGID_192_);} + .st244{fill:#7C51A0;} + .st245{fill:#9F66A9;} + .st246{fill:#9F80B9;} + .st247{fill:url(#SVGID_193_);} + .st248{fill:url(#SVGID_194_);} + .st249{fill:url(#SVGID_195_);} + .st250{fill:url(#SVGID_196_);} + .st251{fill:#2D3136;} + .st252{fill:#76777A;} + .st253{fill:#A7A8A9;} + .st254{fill:#0082CA;} + .st255{fill:#FFB259;} + .st256{fill:#385CAD;} + .st257{fill:#7BA0C4;} + .st258{fill:#EBA900;} + .st259{fill:#929497;} + .st260{opacity:0.7;fill:#FFFFFF;} + .st261{fill:#016BAF;} + .st262{fill:#343432;} + .st263{fill:#6D6E70;} + .st264{fill:#F4B01B;} + .st265{fill:#293271;} + .st266{fill:#A1D33C;} + .st267{fill:#212322;} + .st268{fill:#0047BA;} + .st269{fill:#969CDE;} + .st270{fill:#047BC1;} + .st271{fill:url(#SVGID_197_);} + .st272{fill:url(#SVGID_198_);} + .st273{fill:url(#SVGID_199_);} + .st274{fill:url(#SVGID_200_);} + .st275{fill:url(#SVGID_201_);} + .st276{fill:url(#SVGID_202_);} + .st277{fill:url(#SVGID_203_);} + .st278{fill:#13517C;} + .st279{fill:#0077A6;} + .st280{fill:none;stroke:#231F20;stroke-width:5.9036;stroke-miterlimit:10;} + .st281{fill:#00A94F;} + .st282{fill:none;stroke:#231F20;stroke-width:3.2172;stroke-miterlimit:10;} + .st283{fill:#59595C;} + .st284{opacity:0.349;fill:#F9AE19;} + .st285{opacity:0.349;fill:#E99F22;} + .st286{opacity:0.349;fill:#E47D25;} + .st287{fill:#F9AE19;} + .st288{fill:#E99F22;} + .st289{fill:#F09B20;} + .st290{fill:#E47D25;} + .st291{fill:#E89223;} + .st292{opacity:0.651;fill:#F9AE19;} + .st293{fill:#E68825;} + .st294{opacity:0.651;fill:#E99F22;} + .st295{fill:#EB8D23;} + .st296{opacity:0.7725;fill:#EF9B21;} + .st297{opacity:0.651;fill:#E47D25;} + .st298{opacity:0.7725;fill:#EA9622;} + .st299{fill:url(#SVGID_204_);} + .st300{fill:#55575B;} + .st301{fill:#EE424E;} + .st302{fill:#34424B;} +</style> +<g> + <g> + <path class="st55" d="M772.88,526c9.95,0,15.7,5.53,15.7,15.48c0,10.17-5.75,15.48-15.7,15.48c-9.95,0-15.48-5.31-15.48-15.48 + C757.4,531.53,762.93,526,772.88,526z"/> + <path class="st55" d="M832.94,393.35c8.18,0,13.71,3.32,13.71,12.38c0,9.29-5.53,12.6-13.71,12.6c-8.4,0-14.15-3.32-14.15-12.6 + C818.79,396.67,824.54,393.35,832.94,393.35z M821.22,438.67h22.99V554.3h-22.99V438.67z"/> + <path class="st55" d="M934.56,435.58c36.25,0,61.9,26.09,61.9,61.24c0,34.71-25.65,60.58-61.9,60.58 + c-35.82,0-61.69-25.87-61.69-60.58C872.88,461.67,898.75,435.58,934.56,435.58z M934.56,536.18c23.66,0,39.79-17.03,39.79-39.36 + c0-22.77-16.14-40.02-39.79-40.02c-23.44,0-39.36,17.25-39.36,40.02C895.21,519.15,911.13,536.18,934.56,536.18z"/> + </g> + <g> + <path class="st56" d="M724.15,245.36c-0.97-8.4-17.24-16.23-17.24-16.23c-6.81-4.71-8.03-16.23-7.16-20.6 + c0.87-4.36,15.01-36.66,15.01-36.66c11.52-11.35,31.6-35.44,33.87-48.88c1.07-6.31-3.14-38.93,5.41-49.75 + c5.63-7.12,22.35-15.36,25.84-18.16c3.49-2.79,6.28-11,4.71-14.84c-1.57-3.84-27.41-4.02-27.41-4.02s-2.16-10.79-17.62-11.8 + c-6.05-0.2-10.18,1.3-10.18,1.3c1.78-0.89,4.69-2.18,6.78-3.1c-0.54-3.56-1.89-11.45-3.24-11.72c-1.43-0.29-4.73,5.28-6.27,7.21 + l0.28,3.42l-1.11-2.85l-1.63-4.2l-0.02-0.06h0c-0.64-1.74-1.36-3.37-2.08-3.53c-1.57-0.34-38.06,50.81-42.6,57.44 + c-4.54,6.63-9.25,17.81-33.87,25.49c-17.37,5.42-53.43,6.32-81.13,15.16l0,0c-14.25,1.43-53.29,33.79-83.15,32.62 + c-20.05-0.78-35.61-6.28-39.57-15.25c0,0,4.19,41.32,25.6,43.64c0,0,13.5,2.33,26.53-9.31c0,0-3.72,7.36-8.38,9.5 + c0,0,18.07-4.62,29.06-12.94c3.37-7.06,9.22-17.4,17.46-25.17c0.53-0.52,0.86-0.8,0.86-0.8c-0.29,0.26-0.57,0.53-0.86,0.8 + c-2.65,2.6-10.68,11.48-11.86,24.73c-0.24,2.64-0.21,5.44,0.2,8.41c0,8.9,9.66,20.78,9.66,26.19c0,7.16-16.76,20.25-17.81,23.74 + c-0.58,1.95-2.35,16.91,0.69,29.77h-59.09c-56.8,0-78.68,56.8-78.68,56.8l-24.4,68h-10.52c-8.25,0-14.94,6.69-14.94,14.94 + c0,8.19,6.59,14.81,14.75,14.92l-0.01,0.02h0.2h5.92c8.25,0,14.94,6.69,14.94,14.94c0,8.25-6.69,14.94-14.94,14.94H197.01 + c-8.25,0-14.94,6.69-14.94,14.94c0,8.25,6.69,14.94,14.94,14.94h154.15c8.25,0,14.94,6.69,14.94,14.94 + c0,8.25-6.69,14.94-14.94,14.94h-32.39H146.48h-32.39c-8.25,0-14.94,6.69-14.94,14.94c0,8.25,6.69,14.94,14.94,14.94h183.08 + l-13.71,38.21h113.6l35.67-99.4h1.72c79.83,0,109.91-85.2,109.91-85.2h-81.05l15.29-42.6l88.87,0c56.8,0,83.71-85.2,83.71-85.2 + H539.99c-2.48-4.72-5.03-9.43-5.03-13.01c0-18.5,49.93-30.55,48.36-60.4c-4.08-16.85,2.51-25.92,2.51-25.92 + c-4.2,9.35,0.01,19.79,2.11,24c0.03,0,0.06,0,0.1,0c13.97,0,41.9,15.36,59.18,15.36c11.43,0,20.41-2.37,25.19-3.97 + c0.69-3.96,0.82-14.29-14.36-20.96c0,0,18.37,0.16,18.15,19.52c0,0-2.09,31.42,0.7,54.29c0.55,4.48,1.7,8.11,3.22,11.09h-0.52 + c-13.7,55.08-55.31,85.2-55.31,85.2h60.7l-51.92,142.02l-0.04-0.01H510.67c-56.8,0-85.2,85.2-85.2,85.2H601.9 + c56.8,0,111.69,5.33,144.18-85.2l40.77-113.6C810.25,293.33,776.46,249.98,724.15,245.36z"/> + <path class="st56" d="M56.25,489.25H18.47c-8.25,0-14.94,6.69-14.94,14.94c0,8.25,6.69,14.94,14.94,14.94h37.78 + c8.25,0,14.94-6.69,14.94-14.94C71.19,495.94,64.5,489.25,56.25,489.25z"/> + <path class="st56" d="M171.38,399.61h120.5c8.25,0,14.94-6.69,14.94-14.94c0-8.25-6.69-14.94-14.94-14.94H102.14 + c-8.25,0-14.94,6.69-14.94,14.94c0,8.25,6.69,14.94,14.94,14.94H171.38z"/> + <path class="st56" d="M180.84,339.85h162.85c8.25,0,14.94-6.69,14.94-14.94c0-8.25-6.69-14.94-14.94-14.94H180.84 + c-8.25,0-14.94,6.69-14.94,14.94C165.9,333.17,172.59,339.85,180.84,339.85z"/> + </g> +</g> +</svg> diff --git a/resources/tools/dash/app/pal/static/less/global.less b/resources/tools/dash/app/pal/static/less/global.less new file mode 100644 index 0000000000..78b7ae4314 --- /dev/null +++ b/resources/tools/dash/app/pal/static/less/global.less @@ -0,0 +1,12 @@ +body, +html { + height: 100% !important; + margin: 0; + padding: 0; + background: #e7ecf7 !important; + font-family: 'Lato', sans-serif; +} + +.row .col { + padding: 0 !important; +} diff --git a/resources/tools/dash/app/pal/static/less/header.less b/resources/tools/dash/app/pal/static/less/header.less new file mode 100644 index 0000000000..49f6769df2 --- /dev/null +++ b/resources/tools/dash/app/pal/static/less/header.less @@ -0,0 +1,33 @@ +header { + position: relative; + width: 100%; + padding: 30px 0 !important; + background: white !important; + box-shadow: 0 0 5px #bec6cf; + font-family: 'Lato', sans-serif; + + .nav-wrapper { + display: flex; + align-items: center; + justify-content: space-between; + width: 1000px; + max-width: 90%; + margin: auto; + + nav { + display: flex; + } + + .logo { + display: inline-block; + width: 40px; + } + + a { + color: #70829d; + font-size: 1em; + text-decoration: none; + transition: all 0.3s ease-out; + } + } +} diff --git a/resources/tools/dash/app/pal/static/less/home.less b/resources/tools/dash/app/pal/static/less/home.less new file mode 100644 index 0000000000..ebd66a2ceb --- /dev/null +++ b/resources/tools/dash/app/pal/static/less/home.less @@ -0,0 +1,64 @@ +.home-template { + .container { + margin: 0 !important; + } + + .card { + width: 800px; + max-width: 93%; + height: fit-content; + margin: 50px auto; + padding: 60px; + background: white; + box-shadow: 0 0 5px rgba(65, 67, 144, 0.15); + text-align: center; + @media (max-width: 800px) { + max-width: 78%; + width: unset; + padding: 40px; + } + + .logo { + width: 50px; + margin: auto; + } + + .site-title { + margin: 10px 0 3px; + color: #5f6988; + font-family: proxima-nova, sans-serif; + font-size: 2.3em; + line-height: 1; + text-transform: uppercase; + } + + p { + margin: 0; + color: #7f92af; + font-size: 1.08em; + } + + a { + color: #79aec8; + font-weight: 500; + text-decoration: none; + transition: all .2s ease; + } + + .dash-link { + display: block; + margin-top: 30px; + font-size: 1.1em; + font-weight: 600; + + &:hover { + opacity: .7; + } + + i { + margin-left: 6px; + font-size: .9em; + } + } + } +} diff --git a/resources/tools/dash/app/pal/static/less/table.less b/resources/tools/dash/app/pal/static/less/table.less new file mode 100644 index 0000000000..40e18e0e64 --- /dev/null +++ b/resources/tools/dash/app/pal/static/less/table.less @@ -0,0 +1,256 @@ +body, +html { + height: 100% !important; + padding: 0; + background: #e7ecf7 !important; + font-family: 'Lato', sans-serif; + margin: 0; +} + +.dash-template { + h1 { + display: inline-block; + margin: 0; + font-size: 1.5em; + } + + .logo { + width: 40px; + margin-right: 20px; + + &:hover { + opacity: .7; + } + } + + .nav-wrapper a { + display: flex; + align-items: center; + } +} + +#dash-container { + width: 1200px; + max-width: 95%; + margin: 50px auto 0; +} + +.container { + margin: 90px 30px; + color: #182635; +} + +#_dash-app-content { + max-width: 95% !important; + margin: 90px auto !important; + overflow: hidden; +} + +nav { + a { + display: flex; + align-items: center; + justify-content: space-between; + color: #59657b; + line-height: 1; + text-decoration: none; + transition: all 0.3s ease-out; + + &:hover { + cursor: pointer; + opacity: 0.7; + } + + i { + margin-right: 5px; + } + } +} + +.dash-spreadsheet-container { + max-width: 100%; + margin: 0 auto 20px !important; + overflow: hidden; + border: 0; + border-radius: 4px; + box-shadow: 0 0 4px #cdd3e2; + font-family: 'Lato', sans-serif; + + * { + box-shadow: none !important; + font-family: Lato, sans-serif; + } + + th, + tr { + box-shadow: none !important; + } + + td:first-of-type, + tr:first-of-type { + width: 55px; + } + + td:last-of-type, + tr:last-of-type { + width: 100px; + } + + th { + padding: 25px 12px !important; + border-top: 0 !important; + border-right: 0 !important; + border-bottom: 1px solid #e5e7eb !important; + border-left: 0 !important; + background: white !important; + color: #404552; + + .column-header--sort { + margin-right: 7px; + transition: all 0.2s ease-out; + + &:hover { + color: #9bd2eb !important; + } + + svg { + width: 0.5em; + } + } + + .sort { + order: 2; + color: #aeaeae !important; + transition: all 0.3s ease-out; + + &:hover { + text-decoration: none; + cursor: pointer; + opacity: 0.7; + } + } + + & > div { + display: flex; + align-items: center; + width: fit-content; + + span:last-of-type { + font-size: 0.8em; + font-weight: 600; + text-transform: uppercase; + } + } + } + + td { + padding: 12px !important; + font-size: .95em; + text-align: left !important; + + &:first-of-type, + &:last-of-type { + max-width: 50px !important; + } + + .dash-cell-value { + display: block !important; + max-width: 500px; + overflow: hidden !important; + font-size: 1.2em; + font-weight: 300; + text-align: left; + text-overflow: ellipsis; + white-space: nowrap; + opacity: .8; + } + } + + td[data-dash-column="command"], + .column-1 { + max-width: 200px !important; + } + + td[data-dash-column="index"] { + text-align: center !important; + + div { + text-align: center !important; + } + } + + td[data-dash-column="index"] { + color: #939da4; + font-size: 1.1em; + font-weight: 500; + } + + tr:nth-child(even) { + background: #f5f8fc !important; + } +} + +table { + tbody { + box-shadow: 0 0 7px #bdbdd2 !important; + + tr { + border: 0 !important; + + &:nth-child(even) { + background: #e7eefa !important; + } + + td { + padding: 12px 10px !important; + overflow: hidden !important; + border: 0 !important; + font-size: 0.65em !important; + line-height: 1.25 !important; + text-align: center !important; + } + } + } +} + +.dash-spreadsheet-container .dash-spreadsheet-inner td.focused { + background-color: rgba(154, 212, 255, 0.2) !important; + box-shadow: 0 0 4px #cdd3e2; +} + +.dash-spreadsheet-container .dash-spreadsheet-inner td .input-cell-value-shadow { + width: 100%; +} + +.dash-spreadsheet-container .dash-spreadsheet-inner td input.dash-cell-value.unfocused { + caret-color: #317ed1 !important; +} + +.dash-spreadsheet-inner .input-active { + overflow: visible !important; + color: #829ab2; + text-align: left !important; +} + +.dash-spreadsheet-inner input { + &::placeholder { + color: grey; + } +} + +#histogram-graph { + margin-bottom: 30px; + padding-bottom: 176px !important; + overflow: hidden; + border-radius: 4px; + background: white; + box-shadow: 0 0 4px #cdd3e2; +} + +.main-svg { + overflow: visible !important; +} + +header .nav-wrapper { + width: 1200px !important; +} diff --git a/resources/tools/dash/app/pal/templates/index.jinja2 b/resources/tools/dash/app/pal/templates/index.jinja2 new file mode 100644 index 0000000000..8ab5c84356 --- /dev/null +++ b/resources/tools/dash/app/pal/templates/index.jinja2 @@ -0,0 +1,13 @@ +{% extends "layout.jinja2" %} + +{% block content %} +<div class="card"> + <img src="{{ url_for('static', filename='img/logo.svg') }}" class="logo" /> + <h1 class="site-title">{{ title }}</h1> + <p class="subtitle">{{ description }}</p> + <a href="/trending/" class="dash-link"> + <span>trending</span> + <i class="fas fa-arrow-right"></i> + </a> +</div> +{% endblock %} diff --git a/resources/tools/dash/app/pal/templates/layout.jinja2 b/resources/tools/dash/app/pal/templates/layout.jinja2 new file mode 100644 index 0000000000..59abba36e3 --- /dev/null +++ b/resources/tools/dash/app/pal/templates/layout.jinja2 @@ -0,0 +1,33 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <title>{{ title }}</title> + <meta property="og:site_name" content="{{ title }}"/> + <meta property="og:type" content="website"/> + <meta property="og:title" content="{{ title }}"/> + <meta property="og:description" content="{{ description }}"/> + <meta property="og:url" content="https://fd.io/"/> + <meta name="HandheldFriendly" content="True" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" /> + <link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet"> + <link rel="stylesheet" href="{{ url_for('static', filename='dist/css/styles.css') }}" /> + <link rel="stylesheet" href="https://use.typekit.net/uqq2lcv.css"> + <link rel="shortcut icon" href="{{ url_for('static', filename='dist/img/favicon.svg') }}" type="image/x-icon" /> + <link + rel="stylesheet" + href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" + integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" + crossorigin="anonymous" + /> +</head> + +<body class="{{template}}"> + <div class="container"> + {% block content %}{% endblock %} + </div> +</body> + +</html> diff --git a/resources/tools/dash/app/pal/trending/dashboard.py b/resources/tools/dash/app/pal/trending/dashboard.py new file mode 100644 index 0000000000..ee5ea5123f --- /dev/null +++ b/resources/tools/dash/app/pal/trending/dashboard.py @@ -0,0 +1,69 @@ +# 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 a Dash app.""" +import dash +from dash import dcc +from dash import html +from dash import dash_table +import numpy as np +import pandas as pd + +from .data import create_dataframe +from .layout import html_layout + + +def init_dashboard(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="/trending/", + external_stylesheets=[ + "/static/dist/css/styles.css", + "https://fonts.googleapis.com/css?family=Lato", + ], + ) + + # Load DataFrame + df = create_dataframe() + + # Custom HTML layout + dash_app.index_string = html_layout + + # Create Layout + dash_app.layout = html.Div( + children=[ + create_data_table(df), + ], + id="dash-container", + ) + return dash_app.server + + +def create_data_table(df): + """Create Dash datatable from Pandas DataFrame.""" + table = dash_table.DataTable( + id="database-table", + columns=[{"name": i, "id": i} for i in df.columns], + data=df.to_dict("records"), + sort_action="native", + sort_mode="native", + page_size=300, + ) + return table diff --git a/resources/tools/dash/app/pal/trending/data.py b/resources/tools/dash/app/pal/trending/data.py new file mode 100644 index 0000000000..06466a9175 --- /dev/null +++ b/resources/tools/dash/app/pal/trending/data.py @@ -0,0 +1,24 @@ +# 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.""" + +import pandas as pd + + +def create_dataframe(): + """Create Pandas DataFrame from local CSV.""" + return pd.read_csv( + "https://s3-docs.fd.io/csit/master/trending/_static/vpp/" + "csit-vpp-perf-mrr-daily-master-2n-zn2-trending.csv" + ) diff --git a/resources/tools/dash/app/pal/trending/layout.py b/resources/tools/dash/app/pal/trending/layout.py new file mode 100644 index 0000000000..1f60aecd83 --- /dev/null +++ b/resources/tools/dash/app/pal/trending/layout.py @@ -0,0 +1,43 @@ +# 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.""" + +html_layout = """ +<!DOCTYPE html> + <html> + <head> + {%metas%} + <title>{%title%}</title> + {%favicon%} + {%css%} + </head> + <body class="dash-template"> + <header> + <div class="nav-wrapper"> + <a href="/"> + <h1>Continuous Performance Trending</h1> + </a> + <nav> + </nav> + </div> + </header> + {%app_entry%} + <footer> + {%config%} + {%scripts%} + {%renderer%} + </footer> + </body> + </html> +""" diff --git a/resources/tools/dash/app/requirements.txt b/resources/tools/dash/app/requirements.txt new file mode 100644 index 0000000000..90e595e81c --- /dev/null +++ b/resources/tools/dash/app/requirements.txt @@ -0,0 +1,35 @@ +attrs==21.2.0 +Brotli==1.0.9 +click==8.0.3 +dash==2.0.0 +dash-core-components==2.0.0 +dash-html-components==2.0.0 +dash-renderer==1.9.1 +dash-table==5.0.0 +Flask==2.0.2 +Flask-Assets==2.0 +Flask-Compress==1.10.1 +future==0.18.2 +intervaltree==3.1.0 +itsdangerous==2.0.1 +Jinja2==3.0.3 +MarkupSafe==2.0.1 +numpy==1.21.4 +packaging==21.3 +pandas==1.3.5 +pip==21.2.4 +plotly==5.4.0 +protobuf==3.19.1 +pyparsing==3.0.6 +python-dateutil==2.8.2 +python-dotenv==0.19.2 +pytz==2022.3 +retrying==1.3.3 +setuptools==57.5.0 +six==1.16.0 +sortedcontainers==2.4.0 +tenacity==8.0.1 +uWSGI==2.0.20 +webassets==2.0 +Werkzeug==2.0.2 +wheel==0.37.0
\ No newline at end of file diff --git a/resources/tools/dash/app/wsgi.py b/resources/tools/dash/app/wsgi.py new file mode 100644 index 0000000000..c2832e29eb --- /dev/null +++ b/resources/tools/dash/app/wsgi.py @@ -0,0 +1,20 @@ +# 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. + +from pal import init_app + +app = init_app() + +if __name__ == "__main__": + # Main entry point. + app.run(host="0.0.0.0") diff --git a/resources/tools/dash/docker-compose.yaml b/resources/tools/dash/docker-compose.yaml new file mode 100644 index 0000000000..335bcdaf94 --- /dev/null +++ b/resources/tools/dash/docker-compose.yaml @@ -0,0 +1,19 @@ +version: "3" +services: + dash: + build: "." + command: "uwsgi app.ini" + environment: + AWS_ACCESS_KEY_ID: "" + AWS_SECRET_ACCESS_KEY: "" + FLASK_APP: "wsgi.py" + FLASK_ENV: "production" + LESS_BIN: "/usr/local/bin/lessc" + ASSETS_DEBUG: "False" + LESS_RUN_IN_DEBUG: "False" + COMPRESSOR_DEBUG: "True" + ports: + - "5000:5000" + volumes: + - "./app/:/app" + working_dir: "/app" |