From 4cf86fb509d5f4d7c3f9ce3cd8f8121c552cba0d Mon Sep 17 00:00:00 2001 From: Manolis Mandrapilias <70536101+moneymanolis@users.noreply.github.com> Date: Tue, 20 Dec 2022 20:58:43 +0100 Subject: [PATCH] UIUX: Better node selection (#1987) --- cypress/integration/spec_configures_nodes.js | 4 +- .../spec_elm_multi_segwit_wallet.js | 3 +- .../spec_elm_single_segwit_wallet.js | 2 +- requirements.txt | 10 +- .../specter/managers/node_manager.py | 6 + .../specter/server_endpoints/nodes.py | 4 +- .../static/img/radio-button-running-node.svg | 1 + .../static/img/radio-button-selected-node.svg | 1 + src/cryptoadvance/specter/static/styles.css | 18 ++- .../templates/components/bitcoin_svg.jinja | 4 +- .../templates/components/liquid_svg.jinja | 4 +- .../sidebar/components/node_connection.jinja | 28 +--- .../sidebar/components/node_logo.jinja | 10 +- .../components/node_select_popup.jinja | 131 +++++++++++++----- 14 files changed, 144 insertions(+), 82 deletions(-) create mode 100644 src/cryptoadvance/specter/static/img/radio-button-running-node.svg create mode 100644 src/cryptoadvance/specter/static/img/radio-button-selected-node.svg diff --git a/cypress/integration/spec_configures_nodes.js b/cypress/integration/spec_configures_nodes.js index 58cbbe964f..958a9ce47b 100644 --- a/cypress/integration/spec_configures_nodes.js +++ b/cypress/integration/spec_configures_nodes.js @@ -46,7 +46,7 @@ describe('Configuring nodes', () => { cy.viewport(1200,660) cy.visit('/') cy.get('#node-switch-icon').click() - cy.get('#btn_new_node').click() + cy.get('[data-cy="connect-new-node-btn"]').click() cy.get('[href="/nodes/new_node/"]').click() cy.get('#name').clear() cy.get('#name').type("Elements Node") @@ -83,7 +83,7 @@ describe('Configuring nodes', () => { cy.viewport(1200,660) cy.visit('/') cy.get('#node-switch-icon').click() - cy.get('#default-select-node-form > .item > div').click() + cy.contains('Bitcoin Core').click() }) }) \ No newline at end of file diff --git a/cypress/integration/spec_elm_multi_segwit_wallet.js b/cypress/integration/spec_elm_multi_segwit_wallet.js index 5deba9f235..28223aca82 100644 --- a/cypress/integration/spec_elm_multi_segwit_wallet.js +++ b/cypress/integration/spec_elm_multi_segwit_wallet.js @@ -4,8 +4,7 @@ describe('Operating with an Elements multisig wallet', () => { cy.viewport(1200,660) cy.visit('/') cy.get('#node-switch-icon').click() - cy.get('#elements_node-select-node-form > .item > div').click() - cy.get('[value="save"]').click() + cy.contains('Elements Node').click() // Delete wallets if existing cy.deleteWallet("Elm Multi Segwit Wallet") diff --git a/cypress/integration/spec_elm_single_segwit_wallet.js b/cypress/integration/spec_elm_single_segwit_wallet.js index 653b3c873b..8281c2ae92 100644 --- a/cypress/integration/spec_elm_single_segwit_wallet.js +++ b/cypress/integration/spec_elm_single_segwit_wallet.js @@ -3,7 +3,7 @@ describe('Operating with an elements singlesig wallet', () => { cy.viewport(1300,660) cy.visit('/') cy.get('#node-switch-icon').click() - cy.get('#elements_node-select-node-form > .item > div').click() + cy.contains('Elements Node').click() // Delete Wallet if existing cy.deleteWallet("Elm Single Segwit Hot Wallet") diff --git a/requirements.txt b/requirements.txt index 4eb391bc89..b49a0db778 100644 --- a/requirements.txt +++ b/requirements.txt @@ -325,7 +325,7 @@ idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 # via requests -importlib-metadata==4.8.1 \ +importlib_metadata==4.8.1 \ --hash=sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15 \ --hash=sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1 # via -r requirements.in @@ -598,6 +598,10 @@ pytimeparse==1.1.8 \ --hash=sha256:04b7be6cc8bd9f5647a6325444926c3ac34ee6bc7e69da4367ba282f076036bd \ --hash=sha256:e86136477be924d7e670646a98561957e8ca7308d44841e21f5ddea757556a0a # via -r requirements.in +pytz-deprecation-shim==0.1.0.post0 \ + --hash=sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6 \ + --hash=sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d + # via tzlocal pytz==2022.5 \ --hash=sha256:335ab46900b1465e714b4fda4963d87363264eb662aab5e65da039c25f1f5b22 \ --hash=sha256:c4d88f472f54d615e9cd582a5004d1e5f624854a6a27a6211591c251f22a6914 @@ -606,10 +610,6 @@ pytz==2022.5 \ # babel # flask-babel # flask-restful -pytz-deprecation-shim==0.1.0.post0 \ - --hash=sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6 \ - --hash=sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d - # via tzlocal requests==2.26.0 \ --hash=sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24 \ --hash=sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7 diff --git a/src/cryptoadvance/specter/managers/node_manager.py b/src/cryptoadvance/specter/managers/node_manager.py index 718cadb5dc..209933eef0 100644 --- a/src/cryptoadvance/specter/managers/node_manager.py +++ b/src/cryptoadvance/specter/managers/node_manager.py @@ -174,6 +174,12 @@ def get_by_name(self, name: str) -> Node: return node raise SpecterError("Node name %s does not exist!" % name) + def get_name_from_alias(self, alias: str) -> str: + for node in self.nodes.values(): + if node.alias == alias: + return node.name + raise SpecterError("Node alias %s does not exist!" % alias) + def update_bitcoind_version(self, specter, version): stopped_nodes = [] for node in (node for node in self.nodes.values() if not node.external_node): diff --git a/src/cryptoadvance/specter/server_endpoints/nodes.py b/src/cryptoadvance/specter/server_endpoints/nodes.py index febfcf45ed..06dcd3b194 100644 --- a/src/cryptoadvance/specter/server_endpoints/nodes.py +++ b/src/cryptoadvance/specter/server_endpoints/nodes.py @@ -372,5 +372,7 @@ def internal_node_logs(node_alias): @login_required def switch_node(): node_alias = request.form["node_alias"] + node_name = app.specter.node_manager.get_name_from_alias(node_alias) app.specter.update_active_node(node_alias) - return redirect(url_for("nodes_endpoint.node_settings", node_alias=node_alias)) + flash(_(f"Switched to use {node_name} as node.")) + return redirect(url_for("index")) diff --git a/src/cryptoadvance/specter/static/img/radio-button-running-node.svg b/src/cryptoadvance/specter/static/img/radio-button-running-node.svg new file mode 100644 index 0000000000..c2a386b10e --- /dev/null +++ b/src/cryptoadvance/specter/static/img/radio-button-running-node.svg @@ -0,0 +1 @@ +radio-button--checked \ No newline at end of file diff --git a/src/cryptoadvance/specter/static/img/radio-button-selected-node.svg b/src/cryptoadvance/specter/static/img/radio-button-selected-node.svg new file mode 100644 index 0000000000..ad9ff678d8 --- /dev/null +++ b/src/cryptoadvance/specter/static/img/radio-button-selected-node.svg @@ -0,0 +1 @@ +radio-button--checked \ No newline at end of file diff --git a/src/cryptoadvance/specter/static/styles.css b/src/cryptoadvance/specter/static/styles.css index aff6cbdef7..dfe953ff81 100644 --- a/src/cryptoadvance/specter/static/styles.css +++ b/src/cryptoadvance/specter/static/styles.css @@ -277,25 +277,25 @@ a.item:hover{ opacity: 1; } /* disconnected node */ -svg.core .main{ +svg.core { fill: var(--network-color, #79869B); } -svg.core.test .main{ +svg.core.test { fill: var(--test-color); } -svg.core.testnet .main{ +svg.core.testnet { fill: var(--test-color); } -svg.core.main .main{ +svg.core.main { fill: var(--main-color); } -svg.core.mainnet .main{ +svg.core.mainnet { fill: var(--main-color); } -svg.core.regtest .main{ +svg.core.regtest { fill: var(--regtest-color); } -svg.core.signet .main{ +svg.core.signet { fill: var(--signet-color); } small, .small{ @@ -1002,6 +1002,10 @@ table tr:hover .btn.hovering{ filter: invert(100%) sepia(0%) saturate(1%) hue-rotate(304deg) brightness(102%) contrast(101%); } + .svg-gray { + filter: invert(75%) sepia(0%) saturate(1%) hue-rotate(304deg) brightness(102%) contrast(101%); + } + /************** Mobile styles ********************************/ #side-expand{ display: none; diff --git a/src/cryptoadvance/specter/templates/components/bitcoin_svg.jinja b/src/cryptoadvance/specter/templates/components/bitcoin_svg.jinja index e64a35dd73..c7e2247dcb 100644 --- a/src/cryptoadvance/specter/templates/components/bitcoin_svg.jinja +++ b/src/cryptoadvance/specter/templates/components/bitcoin_svg.jinja @@ -4,8 +4,8 @@ - chain: Chain to use to colorize the Bitcoin icon - size: Svg width and height #} -{% macro bitcoin_svg(chain, size) -%} - +{% macro bitcoin_svg(node, size) -%} + diff --git a/src/cryptoadvance/specter/templates/components/liquid_svg.jinja b/src/cryptoadvance/specter/templates/components/liquid_svg.jinja index 9a890d03a7..baa062a2fc 100644 --- a/src/cryptoadvance/specter/templates/components/liquid_svg.jinja +++ b/src/cryptoadvance/specter/templates/components/liquid_svg.jinja @@ -4,8 +4,8 @@ - chain: Chain to use to colorize the Bitcoin icon - size: Svg width and height #} -{% macro liquid_svg(chain, size) -%} - +{% macro liquid_svg(node, size) -%} +
- - {% if specter.is_liquid %} - {% from "components/liquid_svg.jinja" import liquid_svg %} - {{ liquid_svg(specter.info.chain, 40) }} - {% else %} - {% from "components/bitcoin_svg.jinja" import bitcoin_svg %} - {{ bitcoin_svg(specter.info.chain, 40) }} - {% endif %} + {% include node.node_logo_template() %} {% include "includes/sidebar/components/bitcoin_core_info.jinja" %}
- {{ specter.node.name }} + {{ node.name }}
{% if specter.chain %} - {% if specter.bitcoin_core_version != '' %} - v{{ specter.bitcoin_core_version }} - {% endif %} - ({{specter.chain}}): - {% if specter.info["blocks"] %} - {{ specter.info.blocks }} blocks - {% else %} - {{ specter.info.chain }} - {% endif %} + {{node.chain | title}} node {% endif %}
{% else %} - +
- {{ _("No node connection") }} + {{ _("No Bitcoin Core connection") }}
{{ _("Click to configure") }}
diff --git a/src/cryptoadvance/specter/templates/includes/sidebar/components/node_logo.jinja b/src/cryptoadvance/specter/templates/includes/sidebar/components/node_logo.jinja index 94f7289357..f7239eac96 100644 --- a/src/cryptoadvance/specter/templates/includes/sidebar/components/node_logo.jinja +++ b/src/cryptoadvance/specter/templates/includes/sidebar/components/node_logo.jinja @@ -1,7 +1,7 @@ -{% if specter.node.is_liquid %} -{% from "components/liquid_svg.jinja" import liquid_svg %} -{{ liquid_svg(specter.node.chain, 40) }} +{% if node.is_liquid %} + {% from "components/liquid_svg.jinja" import liquid_svg %} + {{ liquid_svg(node.chain, 40) }} {% else %} -{% from "components/bitcoin_svg.jinja" import bitcoin_svg %} -{{ bitcoin_svg(specter.node.chain, 40) }} + {% from "components/bitcoin_svg.jinja" import bitcoin_svg %} + {{ bitcoin_svg(node, 40) }} {% endif %} \ No newline at end of file diff --git a/src/cryptoadvance/specter/templates/includes/sidebar/components/node_select_popup.jinja b/src/cryptoadvance/specter/templates/includes/sidebar/components/node_select_popup.jinja index 3c5db30faf..b015b41fcf 100644 --- a/src/cryptoadvance/specter/templates/includes/sidebar/components/node_select_popup.jinja +++ b/src/cryptoadvance/specter/templates/includes/sidebar/components/node_select_popup.jinja @@ -4,72 +4,135 @@ justify-content: flex-start; flex-grow: 1; width: 100%; - padding: 10px 0; + padding: 10px; display: flex; flex-direction: row; align-items: center; - border-left: 3px solid transparent; + border-left: 3px solid transparent; + width: 275px; + height: 60px; + cursor: pointer; + border: 1px solid transparent; + border-radius: 10px; + } + .node-list-item-selected { + border: 1px solid orange; + border-radius: 10px; + cursor: unset; } .node-list-item>svg { width: 80px; } - .node-list-item.active{ - background: #394659; - } @media (min-width: 600px){ #node_select_popup { width: 350px; } } + .page_overlay_popup { + padding: '1.5em 0'; + text-align: unset; + } + .node-select-popup-container { + flex-direction: column; + align-items: start; + gap: 10px; + } + .selected-icon { + width: 20px + } + .node-logo-unreachable { + margin-right: 15px; + opacity: 0.1; + } + .node-logo-running { + margin-right: 15px; + opacity: 1; + } + .node-description { + display: flex; + flex-direction: column; + } + .node-row { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + } + .node-name { + color: white + } + .node-list-item:hover { + border: 1px dotted orange; + border-radius: 10px; + } + .node-list-item-selected:hover { + cursor: default; + border: 1px solid orange; + border-radius: 10px; + } -