diff --git a/.github/workflows/electron.yaml b/.github/workflows/electron.yaml index 4d453bf5e..1a57c24f0 100644 --- a/.github/workflows/electron.yaml +++ b/.github/workflows/electron.yaml @@ -155,19 +155,19 @@ jobs: shell: bash - name: Download ubuntu binary from build into dist - uses: actions/download-artifact@master + uses: actions/download-artifact@e9ef242655d12993efdcda9058dee2db83a2cb9b with: name: app-ubuntu-latest path: dist if: ${{ !contains(github.event.head_commit.message, '[NOCI]') }} - name: Download windows binary from build into dist - uses: actions/download-artifact@master + uses: actions/download-artifact@e9ef242655d12993efdcda9058dee2db83a2cb9b with: name: app-windows-latest path: dist if: ${{ !contains(github.event.head_commit.message, '[NOCI]') }} - name: Download macos binary from build into dist - uses: actions/download-artifact@master + uses: actions/download-artifact@e9ef242655d12993efdcda9058dee2db83a2cb9b with: name: app-macos-latest path: dist diff --git a/.vscode/settings.json b/.vscode/settings.json index b3a6dcc53..2f68a7f88 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,5 +14,8 @@ "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode" }, - "vue3snippets.enable-compile-vue-file-on-did-save-code": true + "editor.autoIndent": "none", + "vue3snippets.enable-compile-vue-file-on-did-save-code": true, + "javascript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": false, + "typescript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": false } diff --git a/controls/roles/update-changes/molecule/202/converge.yml b/controls/roles/update-changes/molecule/202/converge.yml new file mode 100644 index 000000000..3f84cb4a2 --- /dev/null +++ b/controls/roles/update-changes/molecule/202/converge.yml @@ -0,0 +1,10 @@ +--- +- name: Converge + hosts: all + vars_files: + - ../../../../defaults/stereum_defaults.yaml + + tasks: + - name: "Include update-changes" + include_role: + name: "update-changes" diff --git a/controls/roles/update-changes/molecule/202/molecule.yml b/controls/roles/update-changes/molecule/202/molecule.yml new file mode 100644 index 000000000..92ae4ff03 --- /dev/null +++ b/controls/roles/update-changes/molecule/202/molecule.yml @@ -0,0 +1,27 @@ +--- +#dependency: +# name: galaxy +driver: + name: docker +platforms: + - name: "update-changes--2.0.2--ubuntu-23.04" + image: ubuntu:lunar + # - name: "configure-updates--default--centos-8" + # image: geerlingguy/docker-centos8-ansible +provisioner: + name: ansible + env: + ANSIBLE_PIPELINING: "True" +lint: | + set -e + yamllint . + ansible-lint . +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - idempotence + - verify + - destroy diff --git a/controls/roles/update-changes/molecule/202/playbook.yml b/controls/roles/update-changes/molecule/202/playbook.yml new file mode 100644 index 000000000..710c596cf --- /dev/null +++ b/controls/roles/update-changes/molecule/202/playbook.yml @@ -0,0 +1,7 @@ +--- +- name: Converge + hosts: all + tasks: + - name: "Include update-changes" + include_role: + name: "update-changes" diff --git a/controls/roles/update-changes/molecule/202/prepare.yml b/controls/roles/update-changes/molecule/202/prepare.yml new file mode 100644 index 000000000..4ce4067f2 --- /dev/null +++ b/controls/roles/update-changes/molecule/202/prepare.yml @@ -0,0 +1,116 @@ +--- +- name: Prepare + hosts: all + tasks: + - name: Make sure Stereum's config path exists + file: + path: "/etc/stereum/services" + state: directory + owner: "root" + group: "root" + mode: 0644 + become: yes + + - name: Create Erigon service config + copy: + dest: "/etc/stereum/services/c3c822b5-5b0c-b779-8a04-fae3563ccfa1.yaml" + owner: "root" + group: "root" + mode: 0644 + content: | + service: ErigonService + id: c3c822b5-5b0c-b779-8a04-fae3563ccfa1 + configVersion: 1 + command: + - erigon + - --chain=holesky + - --datadir=/opt/data/erigon + - --authrpc.addr=0.0.0.0 + - --authrpc.vhosts=* + - --authrpc.port=8551 + - --authrpc.jwtsecret=/engine.jwt + - --rpc.returndata.limit=1000000 + - --ws + - --http + - --http.vhosts=* + - --http.corsdomain=* + - --http.addr=0.0.0.0 + - --http.port=8545 + - --http.api=engine,net,eth,web3 + - --metrics + - --metrics.addr=0.0.0.0 + - --metrics.port=6060 + - --db.pagesize=16K + - --db.size.limit=4TB + - --prune=htc + entrypoint: [] + env: {} + image: thorax/erigon:v2.54.0 + ports: + - 0.0.0.0:30303:30303/tcp + - 0.0.0.0:30303:30303/udp + - 127.0.0.1:8545:8545/tcp + - 127.0.0.1:8546:8546/tcp + volumes: + - /opt/stereum/erigon-c3c822b5-5b0c-b779-8a04-fae3563ccfa1/data:/opt/data/erigon + - /opt/stereum/erigon-c3c822b5-5b0c-b779-8a04-fae3563ccfa1/engine.jwt:/engine.jwt + user: root + autoupdate: true + network: holesky + dependencies: + executionClients: [] + consensusClients: [] + mevboost: [] + become: yes + + - name: Create Erigon service config + copy: + dest: "/etc/stereum/services/da69776a-2468-4e2d-b3fb-7a6dfd9eabf1.yaml" + owner: "root" + group: "root" + mode: 0644 + content: | + service: ErigonService + id: da69776a-2468-4e2d-b3fb-7a6dfd9eabf1 + configVersion: 1 + command: + - erigon + - --chain=holesky + - --datadir=/opt/data/erigon + - --authrpc.addr=0.0.0.0 + - --authrpc.vhosts=* + - --authrpc.port=8551 + - --authrpc.jwtsecret=/engine.jwt + - --rpc.returndata.limit=1000000 + - --ws + - --http + - --http.vhosts=* + - --http.corsdomain=* + - --http.addr=0.0.0.0 + - --http.port=8545 + - --http.api=engine,net,eth,web3 + - --metrics + - --metrics.addr=0.0.0.0 + - --metrics.port=6060 + - --db.pagesize=16K + - --prune=htc + entrypoint: [] + env: {} + image: thorax/erigon:v2.54.0 + ports: + - 0.0.0.0:30303:30303/tcp + - 0.0.0.0:30303:30303/udp + - 127.0.0.1:8545:8545/tcp + - 127.0.0.1:8546:8546/tcp + volumes: + - /opt/stereum/erigon-da69776a-2468-4e2d-b3fb-7a6dfd9eabf1/data:/opt/data/erigon + - /opt/stereum/erigon-da69776a-2468-4e2d-b3fb-7a6dfd9eabf1/engine.jwt:/engine.jwt + user: root + autoupdate: true + network: holesky + dependencies: + executionClients: [] + consensusClients: [] + mevboost: [] + become: yes +# EOF diff --git a/controls/roles/update-changes/molecule/202/verify.yml b/controls/roles/update-changes/molecule/202/verify.yml new file mode 100644 index 000000000..9d3604fa0 --- /dev/null +++ b/controls/roles/update-changes/molecule/202/verify.yml @@ -0,0 +1,35 @@ +--- +- name: Verify + hosts: all + gather_facts: false + tasks: + # Erigon + - name: Read ErigonService file 1 + slurp: + src: "/etc/stereum/services/c3c822b5-5b0c-b779-8a04-fae3563ccfa1.yaml" + register: erigon_service_configuration1_raw + + # Erigon + - name: Read ErigonService file 2 + slurp: + src: "/etc/stereum/services/da69776a-2468-4e2d-b3fb-7a6dfd9eabf1.yaml" + register: erigon_service_configuration2_raw + + - name: Parse ErigonService configurations + set_fact: + erigon_service_configuration1: "{{ erigon_service_configuration1_raw['content'] | b64decode | from_yaml }}" + erigon_service_configuration2: "{{ erigon_service_configuration2_raw['content'] | b64decode | from_yaml }}" + + - debug: + msg: "{{ erigon_service_configuration1 }}" + + - debug: + msg: "{{ erigon_service_configuration2 }}" + + - assert: + that: + - erigon_service_configuration1.command | select('match', '--db.size.limit.*') | length == 1 + - erigon_service_configuration2.command | select('match', '--db.size.limit.*') | length == 1 + - erigon_service_configuration1.command | select('match', '--db.size.limit=4TB') | length == 1 + - erigon_service_configuration2.command | select('match', '--db.size.limit.8TB') | length == 1 +# EOF diff --git a/controls/roles/update-changes/tasks/2.0.2/erigon_dbTag.yaml b/controls/roles/update-changes/tasks/2.0.2/erigon_dbTag.yaml new file mode 100644 index 000000000..b61ca15af --- /dev/null +++ b/controls/roles/update-changes/tasks/2.0.2/erigon_dbTag.yaml @@ -0,0 +1,19 @@ +--- +- name: Read service file + slurp: + src: "{{ item.path }}" + register: service_configuration_raw + +- name: Parse service's configuration + set_fact: + service_configuration: "{{ service_configuration_raw['content'] | b64decode | from_yaml }}" + service_configuration_text: "{{ service_configuration_raw['content'] | b64decode }}" + +- name: Add DB Tag to Erigon + lineinfile: + path: "{{ item.path }}" + insertafter: "- erigon" + line: "{{ service_configuration_text | split('\n') | select('match', '^\\s*- --datadir.*') | first | split('-') | first }}- --db.size.limit=8TB" + when: + - service_configuration.service == "ErigonService" + - service_configuration.command | select('match', '--db.size.limit.*') | length == 0 diff --git a/controls/roles/update-changes/tasks/2.0.2/updates-202.yaml b/controls/roles/update-changes/tasks/2.0.2/updates-202.yaml new file mode 100644 index 000000000..b1ec10acd --- /dev/null +++ b/controls/roles/update-changes/tasks/2.0.2/updates-202.yaml @@ -0,0 +1,9 @@ +--- +- name: Find service configs + find: + paths: "/etc/stereum/services" + register: service_config_files + +- name: Include Erigon DB Tag + include_tasks: erigon_dbTag.yaml + loop: "{{ service_config_files.files }}" diff --git a/controls/roles/update-changes/tasks/main.yml b/controls/roles/update-changes/tasks/main.yml index 0b094f5de..5b11e7a6d 100644 --- a/controls/roles/update-changes/tasks/main.yml +++ b/controls/roles/update-changes/tasks/main.yml @@ -2,4 +2,8 @@ - name: Include RC23 Update Scripts include_tasks: "2.0-rc23/updates-20-rc23.yaml" ignore_errors: yes + +- name: Include 2.0.2 Update Scripts + include_tasks: "2.0.2/updates-202.yaml" + ignore_errors: yes # EOF diff --git a/launcher/package.json b/launcher/package.json index 2219071f6..a677e4fc3 100755 --- a/launcher/package.json +++ b/launcher/package.json @@ -1,6 +1,6 @@ { "name": "stereum-launcher", - "version": "2.0.2", + "version": "2.0.3", "private": true, "description": "Stereum Ethereum Node Setup Launcher", "author": "stereum.net", @@ -18,7 +18,7 @@ "test-coverage": "jest --coverage", "watch:css": "npx tailwindcss -i ./src/main.css -o ./public/output.css --watch", "lint:fix": "eslint --ext .js,.vue --ignore-path ../.gitignore --fix src", - "max": "concurrently \"npm:electron:serve\" \"npm:watch:css\"", + "stereum": "concurrently \"npm:electron:serve\" \"npm:watch:css\"", "format": "prettier . --write" }, "dependencies": { @@ -44,6 +44,7 @@ "pinia": "^2.0.33", "qrcode": "^1.5.1", "ssh2": "^1.1.0", + "uuid": "^9.0.1", "vue": "^3.2.33", "vue-i18n": "9.2.2", "vue-router": "^4.0.15", @@ -88,5 +89,4 @@ "type": "git", "url": "git@github.com:stereum-dev/ethereum-node.git" } -} - +} \ No newline at end of file diff --git a/launcher/public/animation/confirm-changes/modify.gif b/launcher/public/animation/confirm-changes/modify.gif new file mode 100644 index 000000000..19ac703dc Binary files /dev/null and b/launcher/public/animation/confirm-changes/modify.gif differ diff --git a/launcher/public/img/icon/the-staking/alice.gif b/launcher/public/animation/staking/alice.gif similarity index 100% rename from launcher/public/img/icon/the-staking/alice.gif rename to launcher/public/animation/staking/alice.gif diff --git a/launcher/public/img/icon/manage-node-icons/backtonode.png b/launcher/public/img/icon/manage-node-icons/backtonode.png new file mode 100644 index 000000000..dbc689843 Binary files /dev/null and b/launcher/public/img/icon/manage-node-icons/backtonode.png differ diff --git a/launcher/public/img/icon/node-icons/copied.png b/launcher/public/img/icon/node-icons/copied.png new file mode 100755 index 000000000..0e78da73a Binary files /dev/null and b/launcher/public/img/icon/node-icons/copied.png differ diff --git a/launcher/public/img/icon/node-icons/resync.png b/launcher/public/img/icon/node-icons/resync.png index 1ad44fae4..32783d85c 100644 Binary files a/launcher/public/img/icon/node-icons/resync.png and b/launcher/public/img/icon/node-icons/resync.png differ diff --git a/launcher/public/img/icon/service-icons/ssv.gif b/launcher/public/img/icon/service-icons/ssv.gif new file mode 100644 index 000000000..470991be3 Binary files /dev/null and b/launcher/public/img/icon/service-icons/ssv.gif differ diff --git a/launcher/public/img/icon/the-staking/Fehlender_validatorenclient.svg b/launcher/public/img/icon/the-staking/Fehlender_validatorenclient.svg deleted file mode 100755 index 5e554315f..000000000 --- a/launcher/public/img/icon/the-staking/Fehlender_validatorenclient.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/launcher/public/img/icon/the-staking/RemoveGroup.png b/launcher/public/img/icon/the-staking/RemoveGroup.png new file mode 100644 index 000000000..1cc788cb5 Binary files /dev/null and b/launcher/public/img/icon/the-staking/RemoveGroup.png differ diff --git a/launcher/public/img/icon/the-staking/backtolist.png b/launcher/public/img/icon/the-staking/backtolist.png new file mode 100644 index 000000000..5bd0b4dd1 Binary files /dev/null and b/launcher/public/img/icon/the-staking/backtolist.png differ diff --git a/launcher/public/img/icon/the-staking/cancel.png b/launcher/public/img/icon/the-staking/cancel.png new file mode 100755 index 000000000..6dea4dbc8 Binary files /dev/null and b/launcher/public/img/icon/the-staking/cancel.png differ diff --git a/launcher/public/img/icon/the-staking/check.png b/launcher/public/img/icon/the-staking/check.png new file mode 100755 index 000000000..d02542a21 Binary files /dev/null and b/launcher/public/img/icon/the-staking/check.png differ diff --git a/launcher/public/img/icon/the-staking/display-name.png b/launcher/public/img/icon/the-staking/display-name.png new file mode 100644 index 000000000..08fdb41af Binary files /dev/null and b/launcher/public/img/icon/the-staking/display-name.png differ diff --git a/launcher/public/img/icon/the-staking/filter.png b/launcher/public/img/icon/the-staking/filter.png new file mode 100644 index 000000000..7393e6296 Binary files /dev/null and b/launcher/public/img/icon/the-staking/filter.png differ diff --git a/launcher/public/img/icon/the-staking/group.png b/launcher/public/img/icon/the-staking/group.png new file mode 100644 index 000000000..489466bb7 Binary files /dev/null and b/launcher/public/img/icon/the-staking/group.png differ diff --git a/launcher/public/img/icon/the-staking/hide.png b/launcher/public/img/icon/the-staking/hide.png new file mode 100644 index 000000000..7dc15ce04 Binary files /dev/null and b/launcher/public/img/icon/the-staking/hide.png differ diff --git a/launcher/public/img/icon/the-staking/invisible.png b/launcher/public/img/icon/the-staking/invisible.png new file mode 100755 index 000000000..abf8bc4cc Binary files /dev/null and b/launcher/public/img/icon/the-staking/invisible.png differ diff --git a/launcher/public/img/icon/the-staking/key-sign.png b/launcher/public/img/icon/the-staking/key-sign.png new file mode 100644 index 000000000..d5f11a001 Binary files /dev/null and b/launcher/public/img/icon/the-staking/key-sign.png differ diff --git a/launcher/public/img/icon/the-staking/keyIcon.png b/launcher/public/img/icon/the-staking/keyIcon.png index ccdeac061..73479e504 100755 Binary files a/launcher/public/img/icon/the-staking/keyIcon.png and b/launcher/public/img/icon/the-staking/keyIcon.png differ diff --git a/launcher/public/img/icon/the-staking/list1.png b/launcher/public/img/icon/the-staking/list1.png new file mode 100755 index 000000000..389add0cc Binary files /dev/null and b/launcher/public/img/icon/the-staking/list1.png differ diff --git a/launcher/public/img/icon/the-staking/list2.png b/launcher/public/img/icon/the-staking/list2.png new file mode 100755 index 000000000..0ad677e10 Binary files /dev/null and b/launcher/public/img/icon/the-staking/list2.png differ diff --git a/launcher/public/img/icon/the-staking/open-group.png b/launcher/public/img/icon/the-staking/open-group.png new file mode 100644 index 000000000..af330636b Binary files /dev/null and b/launcher/public/img/icon/the-staking/open-group.png differ diff --git a/launcher/public/img/icon/the-staking/remove-group.png b/launcher/public/img/icon/the-staking/remove-group.png new file mode 100644 index 000000000..1f8e86964 Binary files /dev/null and b/launcher/public/img/icon/the-staking/remove-group.png differ diff --git a/launcher/public/img/icon/the-staking/rename-group.png b/launcher/public/img/icon/the-staking/rename-group.png new file mode 100644 index 000000000..9016eab8d Binary files /dev/null and b/launcher/public/img/icon/the-staking/rename-group.png differ diff --git a/launcher/public/img/icon/the-staking/reset.png b/launcher/public/img/icon/the-staking/reset.png new file mode 100644 index 000000000..15ac39812 Binary files /dev/null and b/launcher/public/img/icon/the-staking/reset.png differ diff --git a/launcher/public/img/icon/the-staking/search.png b/launcher/public/img/icon/the-staking/search.png new file mode 100755 index 000000000..e4f1aa50e Binary files /dev/null and b/launcher/public/img/icon/the-staking/search.png differ diff --git a/launcher/public/img/icon/the-staking/select-key.png b/launcher/public/img/icon/the-staking/select-key.png new file mode 100644 index 000000000..d5f11a001 Binary files /dev/null and b/launcher/public/img/icon/the-staking/select-key.png differ diff --git a/launcher/public/img/icon/the-staking/staking-disabled.png b/launcher/public/img/icon/the-staking/staking-disabled.png new file mode 100644 index 000000000..2f520fc9a Binary files /dev/null and b/launcher/public/img/icon/the-staking/staking-disabled.png differ diff --git a/launcher/public/img/icon/the-staking/ungroup.png b/launcher/public/img/icon/the-staking/ungroup.png new file mode 100644 index 000000000..1b5162400 Binary files /dev/null and b/launcher/public/img/icon/the-staking/ungroup.png differ diff --git a/launcher/public/img/icon/the-staking/validator-import.gif b/launcher/public/img/icon/the-staking/validator-import.gif deleted file mode 100755 index ab988f8a2..000000000 Binary files a/launcher/public/img/icon/the-staking/validator-import.gif and /dev/null differ diff --git a/launcher/public/img/icon/the-staking/visible.png b/launcher/public/img/icon/the-staking/visible.png new file mode 100755 index 000000000..dd528ce5f Binary files /dev/null and b/launcher/public/img/icon/the-staking/visible.png differ diff --git a/launcher/public/output.css b/launcher/public/output.css index 06224de64..8c32f502c 100755 --- a/launcher/public/output.css +++ b/launcher/public/output.css @@ -1,7 +1,7 @@ @import url("https://fonts.googleapis.com/css2?family=Noto+Sans:wght@100;200;300;400;500;600;700;800;900&display=swap"); /* -! tailwindcss v3.3.5 | MIT License | https://tailwindcss.com +! tailwindcss v3.4.0 | MIT License | https://tailwindcss.com */ /* @@ -35,9 +35,11 @@ 4. Use the user's configured `sans` font-family by default. 5. Use the user's configured `sans` font-feature-settings by default. 6. Use the user's configured `sans` font-variation-settings by default. +7. Disable tap highlights on iOS */ -html { +html, +:host { line-height: 1.5; /* 1 */ -webkit-text-size-adjust: 100%; @@ -47,13 +49,15 @@ html { -o-tab-size: 4; tab-size: 4; /* 3 */ - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */ -webkit-font-feature-settings: normal; font-feature-settings: normal; /* 5 */ font-variation-settings: normal; /* 6 */ + -webkit-tap-highlight-color: transparent; + /* 7 */ } /* @@ -125,8 +129,10 @@ strong { } /* -1. Use the user's configured `mono` font family by default. -2. Correct the odd `em` font sizing in all browsers. +1. Use the user's configured `mono` font-family by default. +2. Use the user's configured `mono` font-feature-settings by default. +3. Use the user's configured `mono` font-variation-settings by default. +4. Correct the odd `em` font sizing in all browsers. */ code, @@ -135,8 +141,13 @@ samp, pre { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */ - font-size: 1em; + -webkit-font-feature-settings: normal; + font-feature-settings: normal; /* 2 */ + font-variation-settings: normal; + /* 3 */ + font-size: 1em; + /* 4 */ } /* @@ -706,6 +717,10 @@ video { position: relative; } +.sticky{ + position: sticky; +} + .inset-0{ inset: 0px; } @@ -765,6 +780,10 @@ video { top: -0.5rem; } +.-top-\[90px\]{ + top: -90px; +} + .bottom-1{ bottom: 0.25rem; } @@ -801,6 +820,10 @@ video { left: 0.25rem; } +.left-14{ + left: 3.5rem; +} + .left-\[100px\]{ left: 100px; } @@ -813,6 +836,10 @@ video { left: 40%; } +.left-\[920px\]{ + left: 920px; +} + .right-0{ right: 0px; } @@ -885,10 +912,6 @@ video { top: 5rem; } -.top-7{ - top: 1.75rem; -} - .top-\[-18px\]{ top: -18px; } @@ -897,38 +920,6 @@ video { top: -2px; } -.left-2{ - left: 0.5rem; -} - -.left-4{ - left: 1rem; -} - -.-top-4{ - top: -1rem; -} - -.left-6{ - left: 1.5rem; -} - -.left-10{ - left: 2.5rem; -} - -.-top-5{ - top: -1.25rem; -} - -.right-6{ - right: 1.5rem; -} - -.left-12{ - left: 3rem; -} - .z-0{ z-index: 0; } @@ -1009,10 +1000,22 @@ video { grid-column-start: 12; } +.col-start-13{ + grid-column-start: 13; +} + +.col-start-15{ + grid-column-start: 15; +} + .col-start-17{ grid-column-start: 17; } +.col-start-18{ + grid-column-start: 18; +} + .col-start-2{ grid-column-start: 2; } @@ -1025,6 +1028,14 @@ video { grid-column-start: 21; } +.col-start-23{ + grid-column-start: 23; +} + +.col-start-24{ + grid-column-start: 24; +} + .col-start-3{ grid-column-start: 3; } @@ -1069,10 +1080,18 @@ video { grid-column-end: 13; } +.col-end-15{ + grid-column-end: 15; +} + .col-end-17{ grid-column-end: 17; } +.col-end-18{ + grid-column-end: 18; +} + .col-end-2{ grid-column-end: 2; } @@ -1121,6 +1140,10 @@ video { grid-column-end: 8; } +.col-end-9{ + grid-column-end: 9; +} + .row-span-1{ grid-row: span 1 / span 1; } @@ -1153,6 +1176,10 @@ video { grid-row-start: 1; } +.row-start-10{ + grid-row-start: 10; +} + .row-start-11{ grid-row-start: 11; } @@ -1185,14 +1212,14 @@ video { grid-row-start: 7; } -.row-start-8{ - grid-row-start: 8; -} - .row-start-9{ grid-row-start: 9; } +.row-end-10{ + grid-row-end: 10; +} + .row-end-11{ grid-row-end: 11; } @@ -1221,22 +1248,18 @@ video { grid-row-end: 5; } -.row-end-7{ - grid-row-end: 7; +.row-end-6{ + grid-row-end: 6; } -.row-end-8{ - grid-row-end: 8; +.row-end-7{ + grid-row-end: 7; } .row-end-9{ grid-row-end: 9; } -.row-end-10{ - grid-row-end: 10; -} - .-m-1{ margin: -0.25rem; } @@ -1250,6 +1273,11 @@ video { margin-right: 0.25rem; } +.mx-2{ + margin-left: 0.5rem; + margin-right: 0.5rem; +} + .mx-20{ margin-left: 5rem; margin-right: 5rem; @@ -1270,14 +1298,14 @@ video { margin-bottom: auto; } -.-mt-1{ - margin-top: -0.25rem; -} - .mb-2{ margin-bottom: 0.5rem; } +.mb-\[1px\]{ + margin-bottom: 1px; +} + .ml-1{ margin-left: 0.25rem; } @@ -1294,6 +1322,10 @@ video { margin-left: 1rem; } +.ml-5{ + margin-left: 1.25rem; +} + .ml-\[25px\]{ margin-left: 25px; } @@ -1439,6 +1471,14 @@ video { height: 5rem; } +.h-24{ + height: 6rem; +} + +.h-28{ + height: 7rem; +} + .h-3{ height: 0.75rem; } @@ -1585,20 +1625,20 @@ video { height: 100vh; } -.h-1\/2{ - height: 50%; +.max-h-28{ + max-height: 7rem; } -.h-\[400px\]{ - height: 400px; +.max-h-36{ + max-height: 9rem; } -.max-h-60{ - max-height: 15rem; +.max-h-6{ + max-height: 1.5rem; } -.max-h-7{ - max-height: 1.75rem; +.max-h-60{ + max-height: 15rem; } .max-h-\[100px\]{ @@ -1609,6 +1649,10 @@ video { max-height: 110px; } +.max-h-\[144px\]{ + max-height: 144px; +} + .max-h-\[150px\]{ max-height: 150px; } @@ -1621,18 +1665,34 @@ video { max-height: 170px; } +.max-h-\[185px\]{ + max-height: 185px; +} + .max-h-\[200px\]{ max-height: 200px; } -.max-h-\[30px\]{ - max-height: 30px; +.max-h-\[28px\]{ + max-height: 28px; } .max-h-\[320px\]{ max-height: 320px; } +.max-h-\[32px\]{ + max-height: 32px; +} + +.max-h-\[35px\]{ + max-height: 35px; +} + +.max-h-\[409px\]{ + max-height: 409px; +} + .max-h-\[40px\]{ max-height: 40px; } @@ -1645,6 +1705,10 @@ video { max-height: 430px; } +.max-h-\[489px\]{ + max-height: 489px; +} + .max-h-\[503px\]{ max-height: 503px; } @@ -1661,6 +1725,18 @@ video { max-height: 100%; } +.max-h-12{ + max-height: 3rem; +} + +.min-h-11{ + min-height: 2.75rem; +} + +.min-h-\[100px\]{ + min-height: 100px; +} + .min-h-\[18px\]{ min-height: 18px; } @@ -1749,6 +1825,10 @@ video { width: 60%; } +.w-36{ + width: 9rem; +} + .w-4{ width: 1rem; } @@ -1789,10 +1869,18 @@ video { width: 2rem; } +.w-80{ + width: 20rem; +} + .w-9{ width: 2.25rem; } +.w-9\/12{ + width: 75%; +} + .w-\[110px\]{ width: 110px; } @@ -1809,12 +1897,12 @@ video { width: 155px; } -.w-\[15px\]{ - width: 15px; +.w-\[156px\]{ + width: 156px; } -.w-\[160px\]{ - width: 160px; +.w-\[15px\]{ + width: 15px; } .w-\[178px\]{ @@ -2141,6 +2229,10 @@ video { grid-template-rows: repeat(1, minmax(0, 1fr)); } +.grid-rows-10{ + grid-template-rows: repeat(10, minmax(0, 1fr)); +} + .grid-rows-12{ grid-template-rows: repeat(12 , minmax(0,1fr)); } @@ -2253,6 +2345,18 @@ video { gap: 1.25rem; } +.gap-x-2{ + -webkit-column-gap: 0.5rem; + -moz-column-gap: 0.5rem; + column-gap: 0.5rem; +} + +.gap-x-8{ + -webkit-column-gap: 2rem; + -moz-column-gap: 2rem; + column-gap: 2rem; +} + .gap-y-1{ row-gap: 0.25rem; } @@ -2390,6 +2494,10 @@ video { overflow: hidden; } +.overflow-x-auto{ + overflow-x: auto; +} + .overflow-y-auto{ overflow-y: auto; } @@ -2428,10 +2536,22 @@ video { white-space: pre; } +.whitespace-pre-wrap{ + white-space: pre-wrap; +} + +.text-nowrap{ + text-wrap: nowrap; +} + .break-words{ overflow-wrap: break-word; } +.break-all{ + word-break: break-all; +} + .rounded{ border-radius: 0.25rem; } @@ -2474,6 +2594,11 @@ video { border-bottom-left-radius: 0.375rem; } +.rounded-b-sm{ + border-bottom-right-radius: 0.125rem; + border-bottom-left-radius: 0.125rem; +} + .rounded-l-full{ border-top-left-radius: 9999px; border-bottom-left-radius: 9999px; @@ -2489,9 +2614,9 @@ video { border-bottom-right-radius: 9999px; } -.rounded-t-2xl{ - border-top-left-radius: 1rem; - border-top-right-radius: 1rem; +.rounded-r-md{ + border-top-right-radius: 0.375rem; + border-bottom-right-radius: 0.375rem; } .rounded-t-\[5px\]{ @@ -2570,6 +2695,10 @@ video { border-right-width: 2px; } +.border-s-4{ + border-inline-start-width: 4px; +} + .border-t-2{ border-top-width: 2px; } @@ -2582,6 +2711,11 @@ video { border-style: none; } +.border-\[\#171D22\]{ + --tw-border-opacity: 1; + border-color: rgb(23 29 34 / var(--tw-border-opacity)); +} + .border-\[\#1c3634\]{ --tw-border-opacity: 1; border-color: rgb(28 54 52 / var(--tw-border-opacity)); @@ -2602,6 +2736,16 @@ video { border-color: rgb(51 102 102 / var(--tw-border-opacity)); } +.border-\[\#3e4347\]{ + --tw-border-opacity: 1; + border-color: rgb(62 67 71 / var(--tw-border-opacity)); +} + +.border-\[\#6c7e78\]{ + --tw-border-opacity: 1; + border-color: rgb(108 126 120 / var(--tw-border-opacity)); +} + .border-blue-100{ --tw-border-opacity: 1; border-color: rgb(219 234 254 / var(--tw-border-opacity)); @@ -2622,11 +2766,21 @@ video { border-color: rgb(59 130 246 / var(--tw-border-opacity)); } +.border-gray-100{ + --tw-border-opacity: 1; + border-color: rgb(243 244 246 / var(--tw-border-opacity)); +} + .border-gray-200{ --tw-border-opacity: 1; border-color: rgb(229 231 235 / var(--tw-border-opacity)); } +.border-gray-300{ + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity)); +} + .border-gray-400{ --tw-border-opacity: 1; border-color: rgb(156 163 175 / var(--tw-border-opacity)); @@ -2662,6 +2816,11 @@ video { border-color: rgb(249 115 22 / var(--tw-border-opacity)); } +.border-red-400{ + --tw-border-opacity: 1; + border-color: rgb(248 113 113 / var(--tw-border-opacity)); +} + .border-red-500{ --tw-border-opacity: 1; border-color: rgb(239 68 68 / var(--tw-border-opacity)); @@ -2701,16 +2860,6 @@ video { border-color: rgb(255 255 255 / var(--tw-border-opacity)); } -.border-gray-50{ - --tw-border-opacity: 1; - border-color: rgb(249 250 251 / var(--tw-border-opacity)); -} - -.border-gray-100{ - --tw-border-opacity: 1; - border-color: rgb(243 244 246 / var(--tw-border-opacity)); -} - .border-l-gray-200{ --tw-border-opacity: 1; border-left-color: rgb(229 231 235 / var(--tw-border-opacity)); @@ -2725,6 +2874,16 @@ video { border-right-color: transparent; } +.bg-\[\#0d0d0e\]{ + --tw-bg-opacity: 1; + background-color: rgb(13 13 14 / var(--tw-bg-opacity)); +} + +.bg-\[\#111213\]{ + --tw-bg-opacity: 1; + background-color: rgb(17 18 19 / var(--tw-bg-opacity)); +} + .bg-\[\#111315\]{ --tw-bg-opacity: 1; background-color: rgb(17 19 21 / var(--tw-bg-opacity)); @@ -2755,6 +2914,11 @@ video { background-color: rgb(21 26 30 / var(--tw-bg-opacity)); } +.bg-\[\#171D22\]{ + --tw-bg-opacity: 1; + background-color: rgb(23 29 34 / var(--tw-bg-opacity)); +} + .bg-\[\#171a1b\]{ --tw-bg-opacity: 1; background-color: rgb(23 26 27 / var(--tw-bg-opacity)); @@ -2765,6 +2929,11 @@ video { background-color: rgb(23 26 28 / var(--tw-bg-opacity)); } +.bg-\[\#17A2B8\]{ + --tw-bg-opacity: 1; + background-color: rgb(23 162 184 / var(--tw-bg-opacity)); +} + .bg-\[\#191b1e\]{ --tw-bg-opacity: 1; background-color: rgb(25 27 30 / var(--tw-bg-opacity)); @@ -2790,6 +2959,11 @@ video { background-color: rgb(27 28 28 / var(--tw-bg-opacity)); } +.bg-\[\#1b1d1f\]{ + --tw-bg-opacity: 1; + background-color: rgb(27 29 31 / var(--tw-bg-opacity)); +} + .bg-\[\#1c1d1d\]{ --tw-bg-opacity: 1; background-color: rgb(28 29 29 / var(--tw-bg-opacity)); @@ -2810,6 +2984,11 @@ video { background-color: rgb(31 33 35 / var(--tw-bg-opacity)); } +.bg-\[\#202123\]{ + --tw-bg-opacity: 1; + background-color: rgb(32 33 35 / var(--tw-bg-opacity)); +} + .bg-\[\#212629\]{ --tw-bg-opacity: 1; background-color: rgb(33 38 41 / var(--tw-bg-opacity)); @@ -2820,6 +2999,11 @@ video { background-color: rgb(33 39 44 / var(--tw-bg-opacity)); } +.bg-\[\#222526\]{ + --tw-bg-opacity: 1; + background-color: rgb(34 37 38 / var(--tw-bg-opacity)); +} + .bg-\[\#224141\]{ --tw-bg-opacity: 1; background-color: rgb(34 65 65 / var(--tw-bg-opacity)); @@ -2830,16 +3014,31 @@ video { background-color: rgb(35 39 44 / var(--tw-bg-opacity)); } +.bg-\[\#242628\]{ + --tw-bg-opacity: 1; + background-color: rgb(36 38 40 / var(--tw-bg-opacity)); +} + .bg-\[\#243d36\]{ --tw-bg-opacity: 1; background-color: rgb(36 61 54 / var(--tw-bg-opacity)); } +.bg-\[\#252525\]{ + --tw-bg-opacity: 1; + background-color: rgb(37 37 37 / var(--tw-bg-opacity)); +} + .bg-\[\#262626\]{ --tw-bg-opacity: 1; background-color: rgb(38 38 38 / var(--tw-bg-opacity)); } +.bg-\[\#263238\]{ + --tw-bg-opacity: 1; + background-color: rgb(38 50 56 / var(--tw-bg-opacity)); +} + .bg-\[\#264744\]{ --tw-bg-opacity: 1; background-color: rgb(38 71 68 / var(--tw-bg-opacity)); @@ -2875,6 +3074,11 @@ video { background-color: rgb(48 92 89 / var(--tw-bg-opacity)); } +.bg-\[\#313539\]{ + --tw-bg-opacity: 1; + background-color: rgb(49 53 57 / var(--tw-bg-opacity)); +} + .bg-\[\#32363A\]{ --tw-bg-opacity: 1; background-color: rgb(50 54 58 / var(--tw-bg-opacity)); @@ -2905,6 +3109,11 @@ video { background-color: rgb(51 102 102 / var(--tw-bg-opacity)); } +.bg-\[\#343434\]{ + --tw-bg-opacity: 1; + background-color: rgb(52 52 52 / var(--tw-bg-opacity)); +} + .bg-\[\#38504e\]{ --tw-bg-opacity: 1; background-color: rgb(56 80 78 / var(--tw-bg-opacity)); @@ -2925,6 +3134,16 @@ video { background-color: rgb(61 68 73 / var(--tw-bg-opacity)); } +.bg-\[\#3e4347\]{ + --tw-bg-opacity: 1; + background-color: rgb(62 67 71 / var(--tw-bg-opacity)); +} + +.bg-\[\#4D56CB\]{ + --tw-bg-opacity: 1; + background-color: rgb(77 86 203 / var(--tw-bg-opacity)); +} + .bg-\[\#4d7575\]{ --tw-bg-opacity: 1; background-color: rgb(77 117 117 / var(--tw-bg-opacity)); @@ -2940,9 +3159,9 @@ video { background-color: rgb(83 114 99 / var(--tw-bg-opacity)); } -.bg-\[\#5a6168\]{ +.bg-\[\#578f84\]{ --tw-bg-opacity: 1; - background-color: rgb(90 97 104 / var(--tw-bg-opacity)); + background-color: rgb(87 143 132 / var(--tw-bg-opacity)); } .bg-\[\#609879\]{ @@ -2950,6 +3169,36 @@ video { background-color: rgb(96 152 121 / var(--tw-bg-opacity)); } +.bg-\[\#a7aeb5\]{ + --tw-bg-opacity: 1; + background-color: rgb(167 174 181 / var(--tw-bg-opacity)); +} + +.bg-\[\#a846b8\]{ + --tw-bg-opacity: 1; + background-color: rgb(168 70 184 / var(--tw-bg-opacity)); +} + +.bg-\[\#bcc0c2\]{ + --tw-bg-opacity: 1; + background-color: rgb(188 192 194 / var(--tw-bg-opacity)); +} + +.bg-\[\#caced1\]{ + --tw-bg-opacity: 1; + background-color: rgb(202 206 209 / var(--tw-bg-opacity)); +} + +.bg-\[\#e8ebeb\]{ + --tw-bg-opacity: 1; + background-color: rgb(232 235 235 / var(--tw-bg-opacity)); +} + +.bg-amber-400{ + --tw-bg-opacity: 1; + background-color: rgb(251 191 36 / var(--tw-bg-opacity)); +} + .bg-black{ --tw-bg-opacity: 1; background-color: rgb(0 0 0 / var(--tw-bg-opacity)); @@ -2960,9 +3209,9 @@ video { background-color: rgb(96 165 250 / var(--tw-bg-opacity)); } -.bg-blue-600{ +.bg-blue-500{ --tw-bg-opacity: 1; - background-color: rgb(37 99 235 / var(--tw-bg-opacity)); + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); } .bg-cyan-300{ @@ -3015,14 +3264,14 @@ video { background-color: rgb(17 24 39 / var(--tw-bg-opacity)); } -.bg-green-500{ +.bg-green-400{ --tw-bg-opacity: 1; - background-color: rgb(34 197 94 / var(--tw-bg-opacity)); + background-color: rgb(74 222 128 / var(--tw-bg-opacity)); } -.bg-green-600{ +.bg-green-500{ --tw-bg-opacity: 1; - background-color: rgb(22 163 74 / var(--tw-bg-opacity)); + background-color: rgb(34 197 94 / var(--tw-bg-opacity)); } .bg-green-700{ @@ -3040,9 +3289,9 @@ video { background-color: rgb(249 115 22 / var(--tw-bg-opacity)); } -.bg-red-400{ +.bg-red-100{ --tw-bg-opacity: 1; - background-color: rgb(248 113 113 / var(--tw-bg-opacity)); + background-color: rgb(254 226 226 / var(--tw-bg-opacity)); } .bg-red-500{ @@ -3065,6 +3314,11 @@ video { background-color: rgb(153 27 27 / var(--tw-bg-opacity)); } +.bg-slate-200{ + --tw-bg-opacity: 1; + background-color: rgb(226 232 240 / var(--tw-bg-opacity)); +} + .bg-slate-300{ --tw-bg-opacity: 1; background-color: rgb(203 213 225 / var(--tw-bg-opacity)); @@ -3185,6 +3439,10 @@ video { padding: 1.25rem; } +.p-8{ + padding: 2rem; +} + .p-\[1px\]{ padding: 1px; } @@ -3193,10 +3451,6 @@ video { padding: 2px; } -.p-8{ - padding: 2rem; -} - .px-1{ padding-left: 0.25rem; padding-right: 0.25rem; @@ -3232,6 +3486,11 @@ video { padding-right: 2rem; } +.px-\[1px\]{ + padding-left: 1px; + padding-right: 1px; +} + .px-\[2px\]{ padding-left: 2px; padding-right: 2px; @@ -3257,6 +3516,11 @@ video { padding-bottom: 1rem; } +.py-\[2px\]{ + padding-top: 2px; + padding-bottom: 2px; +} + .pb-1{ padding-bottom: 0.25rem; } @@ -3277,6 +3541,14 @@ video { padding-left: 0.5rem; } +.pl-4{ + padding-left: 1rem; +} + +.pr-0{ + padding-right: 0px; +} + .pr-2{ padding-right: 0.5rem; } @@ -3325,11 +3597,19 @@ video { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; } +.font-sans{ + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; +} + .text-2xl{ font-size: 1.5rem; line-height: 2rem; } +.text-2xs{ + font-size: 10px; +} + .text-\[10px\]{ font-size: 10px; } @@ -3358,10 +3638,6 @@ video { font-size: 26px; } -.text-\[6px\]{ - font-size: 6px; -} - .text-\[8px\]{ font-size: 8px; } @@ -3427,11 +3703,26 @@ video { color: rgb(20 23 26 / var(--tw-text-opacity)); } +.text-\[\#333333\]{ + --tw-text-opacity: 1; + color: rgb(51 51 51 / var(--tw-text-opacity)); +} + .text-\[\#4B878D\]{ --tw-text-opacity: 1; color: rgb(75 135 141 / var(--tw-text-opacity)); } +.text-\[\#dee3e3\]{ + --tw-text-opacity: 1; + color: rgb(222 227 227 / var(--tw-text-opacity)); +} + +.text-\[\#ffffff\]{ + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + .text-amber-300{ --tw-text-opacity: 1; color: rgb(252 211 77 / var(--tw-text-opacity)); @@ -3457,6 +3748,11 @@ video { color: rgb(96 165 250 / var(--tw-text-opacity)); } +.text-cyan-400{ + --tw-text-opacity: 1; + color: rgb(34 211 238 / var(--tw-text-opacity)); +} + .text-cyan-500{ --tw-text-opacity: 1; color: rgb(6 182 212 / var(--tw-text-opacity)); @@ -3557,6 +3853,11 @@ video { color: rgb(153 27 27 / var(--tw-text-opacity)); } +.text-teal-400{ + --tw-text-opacity: 1; + color: rgb(45 212 191 / var(--tw-text-opacity)); +} + .text-teal-500{ --tw-text-opacity: 1; color: rgb(20 184 166 / var(--tw-text-opacity)); @@ -3587,6 +3888,26 @@ video { color: rgb(234 179 8 / var(--tw-text-opacity)); } +.placeholder-gray-400\/70::-webkit-input-placeholder{ + color: rgb(156 163 175 / 0.7); +} + +.placeholder-gray-400\/70::-moz-placeholder{ + color: rgb(156 163 175 / 0.7); +} + +.placeholder-gray-400\/70:-ms-input-placeholder{ + color: rgb(156 163 175 / 0.7); +} + +.placeholder-gray-400\/70::-ms-input-placeholder{ + color: rgb(156 163 175 / 0.7); +} + +.placeholder-gray-400\/70::placeholder{ + color: rgb(156 163 175 / 0.7); +} + .placeholder-gray-500::-webkit-input-placeholder{ --tw-placeholder-opacity: 1; color: rgb(107 114 128 / var(--tw-placeholder-opacity)); @@ -3612,6 +3933,31 @@ video { color: rgb(107 114 128 / var(--tw-placeholder-opacity)); } +.placeholder-red-500::-webkit-input-placeholder{ + --tw-placeholder-opacity: 1; + color: rgb(239 68 68 / var(--tw-placeholder-opacity)); +} + +.placeholder-red-500::-moz-placeholder{ + --tw-placeholder-opacity: 1; + color: rgb(239 68 68 / var(--tw-placeholder-opacity)); +} + +.placeholder-red-500:-ms-input-placeholder{ + --tw-placeholder-opacity: 1; + color: rgb(239 68 68 / var(--tw-placeholder-opacity)); +} + +.placeholder-red-500::-ms-input-placeholder{ + --tw-placeholder-opacity: 1; + color: rgb(239 68 68 / var(--tw-placeholder-opacity)); +} + +.placeholder-red-500::placeholder{ + --tw-placeholder-opacity: 1; + color: rgb(239 68 68 / var(--tw-placeholder-opacity)); +} + .opacity-0{ opacity: 0; } @@ -3700,6 +4046,11 @@ video { --tw-shadow: var(--tw-shadow-colored); } +.shadow-\[\#111010\]{ + --tw-shadow-color: #111010; + --tw-shadow: var(--tw-shadow-colored); +} + .shadow-\[\#141516\]{ --tw-shadow-color: #141516; --tw-shadow: var(--tw-shadow-colored); @@ -3710,6 +4061,11 @@ video { --tw-shadow: var(--tw-shadow-colored); } +.shadow-\[\#191a1b\]{ + --tw-shadow-color: #191a1b; + --tw-shadow: var(--tw-shadow-colored); +} + .shadow-\[\#1b1b1b\]{ --tw-shadow-color: #1b1b1b; --tw-shadow: var(--tw-shadow-colored); @@ -3725,6 +4081,11 @@ video { --tw-shadow: var(--tw-shadow-colored); } +.shadow-\[\#242c29\]{ + --tw-shadow-color: #242c29; + --tw-shadow: var(--tw-shadow-colored); +} + .shadow-\[\#252525\]{ --tw-shadow-color: #252525; --tw-shadow: var(--tw-shadow-colored); @@ -3784,12 +4145,6 @@ video { --tw-ring-opacity: 0.05; } -.blur{ - --tw-blur: blur(8px); - -webkit-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} - .grayscale{ --tw-grayscale: grayscale(100%); -webkit-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); @@ -3973,6 +4328,31 @@ html body { background-color: rgb(31, 31, 31); } +.placeholder\:text-gray-400::-webkit-input-placeholder{ + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); +} + +.placeholder\:text-gray-400::-moz-placeholder{ + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); +} + +.placeholder\:text-gray-400:-ms-input-placeholder{ + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); +} + +.placeholder\:text-gray-400::-ms-input-placeholder{ + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); +} + +.placeholder\:text-gray-400::placeholder{ + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); +} + .placeholder\:text-gray-500::-webkit-input-placeholder{ --tw-text-opacity: 1; color: rgb(107 114 128 / var(--tw-text-opacity)); @@ -4154,6 +4534,11 @@ html body { border-width: 1px; } +.hover\:border-\[\#3f4851\]:hover{ + --tw-border-opacity: 1; + border-color: rgb(63 72 81 / var(--tw-border-opacity)); +} + .hover\:border-blue-400:hover{ --tw-border-opacity: 1; border-color: rgb(96 165 250 / var(--tw-border-opacity)); @@ -4189,6 +4574,11 @@ html body { border-color: rgb(13 148 136 / var(--tw-border-opacity)); } +.hover\:bg-\[\#212325\]:hover{ + --tw-bg-opacity: 1; + background-color: rgb(33 35 37 / var(--tw-bg-opacity)); +} + .hover\:bg-\[\#224141\]:hover{ --tw-bg-opacity: 1; background-color: rgb(34 65 65 / var(--tw-bg-opacity)); @@ -4199,6 +4589,11 @@ html body { background-color: rgb(35 39 42 / var(--tw-bg-opacity)); } +.hover\:bg-\[\#234545\]:hover{ + --tw-bg-opacity: 1; + background-color: rgb(35 69 69 / var(--tw-bg-opacity)); +} + .hover\:bg-\[\#243535\]:hover{ --tw-bg-opacity: 1; background-color: rgb(36 53 53 / var(--tw-bg-opacity)); @@ -4264,11 +4659,6 @@ html body { background-color: rgb(59 130 246 / var(--tw-bg-opacity)); } -.hover\:bg-blue-600:hover{ - --tw-bg-opacity: 1; - background-color: rgb(37 99 235 / var(--tw-bg-opacity)); -} - .hover\:bg-cyan-600:hover{ --tw-bg-opacity: 1; background-color: rgb(8 145 178 / var(--tw-bg-opacity)); @@ -4279,11 +4669,6 @@ html body { background-color: rgb(243 244 246 / var(--tw-bg-opacity)); } -.hover\:bg-gray-300:hover{ - --tw-bg-opacity: 1; - background-color: rgb(209 213 219 / var(--tw-bg-opacity)); -} - .hover\:bg-gray-500:hover{ --tw-bg-opacity: 1; background-color: rgb(107 114 128 / var(--tw-bg-opacity)); @@ -4299,11 +4684,6 @@ html body { background-color: rgb(55 65 81 / var(--tw-bg-opacity)); } -.hover\:bg-green-500:hover{ - --tw-bg-opacity: 1; - background-color: rgb(34 197 94 / var(--tw-bg-opacity)); -} - .hover\:bg-green-600:hover{ --tw-bg-opacity: 1; background-color: rgb(22 163 74 / var(--tw-bg-opacity)); @@ -4319,6 +4699,11 @@ html body { background-color: rgb(185 28 28 / var(--tw-bg-opacity)); } +.hover\:bg-slate-300:hover{ + --tw-bg-opacity: 1; + background-color: rgb(203 213 225 / var(--tw-bg-opacity)); +} + .hover\:bg-slate-400:hover{ --tw-bg-opacity: 1; background-color: rgb(148 163 184 / var(--tw-bg-opacity)); @@ -4334,14 +4719,13 @@ html body { background-color: rgb(17 94 89 / var(--tw-bg-opacity)); } -.hover\:text-gray-300:hover{ - --tw-text-opacity: 1; - color: rgb(209 213 219 / var(--tw-text-opacity)); +.hover\:bg-opacity-10:hover{ + --tw-bg-opacity: 0.1; } -.hover\:text-gray-800:hover{ +.hover\:text-gray-300:hover{ --tw-text-opacity: 1; - color: rgb(31 41 55 / var(--tw-text-opacity)); + color: rgb(209 213 219 / var(--tw-text-opacity)); } .hover\:shadow-lg:hover{ @@ -4370,6 +4754,11 @@ html body { --tw-shadow: var(--tw-shadow-colored); } +.hover\:shadow-\[\#101214\]:hover{ + --tw-shadow-color: #101214; + --tw-shadow: var(--tw-shadow-colored); +} + .hover\:shadow-\[\#1a1b1b\]:hover{ --tw-shadow-color: #1a1b1b; --tw-shadow: var(--tw-shadow-colored); @@ -4481,6 +4870,28 @@ html body { box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +@media (min-width: 640px){ + .sm\:gap-x-5{ + -webkit-column-gap: 1.25rem; + -moz-column-gap: 1.25rem; + column-gap: 1.25rem; + } +} + +@media (min-width: 768px){ + .md\:mb-0{ + margin-bottom: 0px; + } +} + +:is(:where([dir="rtl"]) .rtl\:left-0){ + left: 0px; +} + +:is(:where([dir="rtl"]) .rtl\:right-auto){ + right: auto; +} + @media (prefers-color-scheme: dark){ .dark\:text-gray-300{ --tw-text-opacity: 1; @@ -4503,20 +4914,6 @@ html body { } } -@media (min-width: 640px){ - .sm\:gap-x-5{ - -webkit-column-gap: 1.25rem; - -moz-column-gap: 1.25rem; - column-gap: 1.25rem; - } -} - -@media (min-width: 768px){ - .md\:mb-0{ - margin-bottom: 0px; - } -} - .\[\&\:checked_\+_span_svg\[data-checked-icon\]\]\:block:checked + span svg[data-checked-icon]{ display: block; } diff --git a/launcher/src/backend/Monitoring.js b/launcher/src/backend/Monitoring.js index 26e307260..c4be9a3da 100755 --- a/launcher/src/backend/Monitoring.js +++ b/launcher/src/backend/Monitoring.js @@ -426,11 +426,11 @@ export class Monitoring { var query = rpc_method.trim().indexOf("{") < 0 ? JSON.stringify({ - jsonrpc: "2.0", - method: rpc_method.trim(), - params: rpc_params, - id: 1, - }) + jsonrpc: "2.0", + method: rpc_method.trim(), + params: rpc_params, + id: 1, + }) : rpc_method; // Define default response @@ -1631,6 +1631,9 @@ export class Monitoring { // Get storage status of all services async getStorageStatus(live = false) { + // Define services that should be ignored and NOT queried at all + const ignoreServices = ["PrometheusNodeExporterService"]; + // By default return cached data (if available) if (!live) { if ( @@ -1662,6 +1665,9 @@ export class Monitoring { if (typeof svc !== "object" || !svc.hasOwnProperty("service") || !svc.hasOwnProperty("config")) { continue; } + if (ignoreServices.includes(svc.service)) { + continue; + } if (Array.isArray(svc.config.volumes) && svc.config.volumes.length) { const strVolumes = '"' + svc.config.volumes.flatMap(({ destinationPath }) => destinationPath).join('" "') + '"'; sshcommands.push({ @@ -1716,6 +1722,7 @@ export class Monitoring { let svc = index in sshcommands ? sshcommands[index].svc : false; if (svc) { // Prometheus NE does not store data but using "/" as volume, see #1095 + // Likely not queried at all if defined in ignoreServices (see above) if (svc.service === "PrometheusNodeExporterService") { //val = 0; // Solution A: Show 0 B as value for Prometheus NE return; // Solution B: Do not show Prometheus NE at all in the storage list @@ -1740,6 +1747,82 @@ export class Monitoring { }; } + // Get attestation rewards for given validators and epoch + async getAttestationRewards(validators) { + try { + // Get local beacon port from first available consensus client + const beaconResult = await this.findBeaconPort(); + if (beaconResult.code) { + throw new Error("error: could not get balancestatus due to missing beacon port (" + beaconResult.info + ")"); + } + const baseURL = `http://127.0.0.1:${beaconResult.data.port}`; + + // Get latest finalized epoch + const finalizedResult = await this.queryBeaconApi(baseURL, "/eth/v1/beacon/states/head/finality_checkpoints"); + const finalizedEpoch = finalizedResult.data.api_reponse.data.finalized.epoch; + + + // Get attestation rewards for given validators + const attestationResult = await this.queryBeaconApi(baseURL, "/eth/v1/beacon/rewards/attestations/" + finalizedEpoch, validators, "POST") + const rewardsPerValidator = attestationResult.data.api_reponse.data.total_rewards.map(data => { return { ...data, total_rewards: parseInt(data.head) + parseInt(data.source) + parseInt(data.target) + parseInt(data.inactivity) } }); + + return { finalized_epoch: finalizedEpoch, rewards: rewardsPerValidator }; + } catch (error) { + log.error("Getting Attestation Rewards Failed:\n" + error); + return { + code: error.code ? error.code : 1, + info: error.message ? error.message : error.info, + data: error.data ? error.data : JSON.stringify(error), + }; + } + } + + // Get block rewards for given slot (count them together for whole epoch in frontend) + async getBlockRewards(slot) { + try { + // Get local beacon port from first available consensus client + const beaconResult = await this.findBeaconPort(); + if (beaconResult.code) { + throw new Error("error: could not get balancestatus due to missing beacon port (" + beaconResult.info + ")"); + } + const baseURL = `http://127.0.0.1:${beaconResult.data.port}`; + + // Get attestation rewards for given validators + const blockResult = await this.queryBeaconApi(baseURL, "/eth/v1/beacon/rewards/blocks/" + slot) + return blockResult.data.api_reponse.data; + } catch (error) { + log.error("Getting Block Rewards Failed:\n" + error); + return { + code: error.code ? error.code : 1, + info: error.message ? error.message : error.info, + data: error.data ? error.data : JSON.stringify(error), + }; + } + } + + // Get Sync Committee for given validators and slot (count them together for whole epoch in frontend) + async getSyncCommitteeRewards(validators, slot) { + try { + // Get local beacon port from first available consensus client + const beaconResult = await this.findBeaconPort(); + if (beaconResult.code) { + throw new Error("error: could not get balancestatus due to missing beacon port (" + beaconResult.info + ")"); + } + const baseURL = `http://127.0.0.1:${beaconResult.data.port}`; + + // Get attestation rewards for given validators + const blockResult = await this.queryBeaconApi(baseURL, "/eth/v1/beacon/rewards/sync_committee/" + slot, validators, "POST") + return blockResult.data.api_httpcode == 200 ? blockResult.data.api_reponse.data : []; + } catch (error) { + log.error("Getting Block Rewards Failed:\n" + error); + return { + code: error.code ? error.code : 1, + info: error.message ? error.message : error.info, + data: error.data ? error.data : JSON.stringify(error), + }; + } + } + // Get balance status async getBalanceStatus() { // Get local beacon port from first available consensus client @@ -2507,8 +2590,8 @@ export class Monitoring { const addr_type = Array.isArray(addr) ? "arr" : typeof addr === "string" && ["public", "local"].includes(addr) - ? "str" - : "invalid"; + ? "str" + : "invalid"; addr = addr_type == "str" ? addr.toLowerCase().trim() : addr; if (addr_type == "invalid") { return { @@ -2596,7 +2679,7 @@ export class Monitoring { for (let i = 0; i < serviceInfos.length; i++) { const hashDependencies = serviceInfos[i].config.dependencies.consensusClients.length || - serviceInfos[i].config.dependencies.executionClients.length + serviceInfos[i].config.dependencies.executionClients.length ? "yes" : "no"; easyInfos.push({ @@ -2827,144 +2910,87 @@ rm -rf diskoutput return serviceInfos; } - async getValidatorStats(validatorPublicKey) { + async getCurrentEpochandSlot() { try { - const verbose = true; - const proposer = false; - - const beaconStatus = await this.getBeaconStatus(); - const beaconAPIPort = beaconStatus.data[0].beacon.destinationPort; - - const baseURL = `http://localhost:${beaconAPIPort}`; - - const validatorRes = await this.queryBeaconApi( - baseURL, - `/eth/v1/beacon/states/head/validators/${validatorPublicKey}`, - undefined, - "GET" - ); - log.debug(validatorRes); - - const validators_arr = [validatorRes.data.api_reponse.data.index]; - - const beaconAPICmdGenesisTime = `curl -s -X GET '${baseURL}/eth/v1/beacon/genesis' -H 'accept: application/json'`; - const genesisResShell = await this.nodeConnection.sshService.exec(beaconAPICmdGenesisTime); - - const beaconAPICmdSpec = `curl -s -X GET '${baseURL}/eth/v1/config/spec' -H 'accept: application/json'`; - const specRes = await this.nodeConnection.sshService.exec(beaconAPICmdSpec); + // Get local beacon port from first available consensus client + const beaconResult = await this.findBeaconPort(); + if (beaconResult.code) { + throw new Error("error: could not get balancestatus due to missing beacon port (" + beaconResult.info + ")"); + } + const baseURL = `http://127.0.0.1:${beaconResult.data.port}`; - const { SLOTS_PER_EPOCH: slotsPerEpoch, SECONDS_PER_SLOT: secondsPerSlot } = JSON.parse(specRes.stdout).data; + let genesisRes = await this.queryBeaconApi(baseURL, "/eth/v1/beacon/genesis", [], "GET"); + let specRes = await this.queryBeaconApi(baseURL, "/eth/v1/config/spec", [], "GET"); + if (genesisRes.code || specRes.code) { + throw new Error(`Couldn't get genesis or spec:\n${genesisRes.info}\n${specRes.info}`); + } - let output = {}; + const { SLOTS_PER_EPOCH: slotsPerEpoch, SECONDS_PER_SLOT: secondsPerSlot } = specRes.data.api_reponse.data; + const { genesis_time } = genesisRes.data.api_reponse.data; - const { genesis_time } = JSON.parse(genesisResShell.stdout).data; const current_time = Math.floor(Date.now() / 1000); const slot_time = secondsPerSlot; - const slot_timeout = slot_time - ((current_time - genesis_time) % slot_time); + const current_slot = Math.floor((current_time - genesis_time) / slot_time); const current_epoch = Math.floor(current_slot / slotsPerEpoch); - output = { currentEpoch: current_epoch, currentSlot: current_slot }; - - const res = await this.queryBeaconApi( - baseURL, - `/eth/v1/validator/duties/attester/${Math.trunc(current_epoch)}`, - validators_arr, - "POST", - { - "Content-Type": "application/json", - } - ); - - const res_p = await this.queryBeaconApi( - baseURL, - `/eth/v1/validator/duties/proposer/${Math.trunc(current_epoch)}`, - null, - "GET", - { - "Content-Type": "application/json", - } - ); - - let current_prop = 0; - let next_att_slot = 0; - let next_prop_slot = 0; - - const attestationDuties = JSON.stringify(res.data.api_reponse); - const proposerDuties = JSON.stringify(res_p.data.api_reponse); - - // Handle attestation duties - let vidx = attestationDuties.match(/.*"validator_index":"?(\d+)"?.*/)[1]; - let slot = attestationDuties.match(/.*"slot":"?(\d+)"?.*/)[1]; - if (vidx !== undefined && slot !== undefined) { - if (vidx.match(/^[-]?\d+$/) !== null) { - if (verbose === true) { - let duty_eta = (slot - current_slot - 1) * slot_time + slot_timeout; - let eta_str = ""; - if (duty_eta > 0) { - eta_str = " ETA: " + duty_eta + " sec"; - } else if (duty_eta > 0 - slot_time) { - eta_str = " ETA: now!"; - } - let slot_idx = slot % slotsPerEpoch; - output = { ...output, validator: vidx, attestationSlot: slot, idx: slot_idx, ETA: eta_str }; - } - if (slot > current_slot) { - if (slot < next_att_slot || next_att_slot === 0) { - next_att_slot = slot; - } - } - } - } - - // Handle proposer duties - vidx = proposerDuties.match(/.*"validator_index":"?(\d+)"?.*/)[1]; - slot = proposerDuties.match(/.*"slot":"?(\d+)"?.*/)[1]; - if (vidx !== undefined && slot !== undefined) { - if (vidx.match(/^[-]?\d+$/) !== null && validators_arr.includes(vidx) === true) { - if (verbose === true) { - let duty_eta = (slot - current_slot - 1) * slot_time + slot_timeout; - let eta_str = ""; - if (duty_eta >= 0) { - eta_str = " ETA: " + duty_eta + " sec"; - } else if (duty_eta > 0 - slot_time) { - eta_str = " ETA: now!"; - } - let slot_idx = slot % slotsPerEpoch; - output = { ...output, validator: vidx, attestationSlot: slot, idx: slot_idx, ETA: eta_str }; - } - if (slot > current_slot) { - if (slot < next_prop_slot || next_prop_slot === 0) { - next_prop_slot = slot; - } - } else if (slot === current_slot) { - current_prop = vidx; - } - } - } + return { current_epoch, current_slot, secondsPerSlot, slotsPerEpoch }; + } catch (error) { + log.error("Getting Epoch and Slot Failed:\n" + error); + return { + code: error.code ? error.code : 1, + info: error.message ? error.message : error.info, + data: error.data ? error.data : JSON.stringify(error), + }; + } + } - if (proposer === true) { - output = { ...output, nextAttSlot: next_att_slot, nextPropSlot: next_prop_slot }; + // Fetches the validator duties (proposer and sync) for the given validator indices + // Returns an array of validator duties (proposer and sync) for the given validator indices + // validatorIndices: array of validator indices + async getValidatorDuties(validatorIndices) { + try { + if (!Array.isArray(validatorIndices)) { + throw new Error("Invalid Argument: validatorIndices must be an Array"); } - let next_duty_slot; - if (next_prop_slot > 0 && next_prop_slot < next_att_slot) { - next_duty_slot = next_prop_slot; - } else { - next_duty_slot = next_att_slot; + // Get local beacon port from first available consensus client + const beaconResult = await this.findBeaconPort(); + if (beaconResult.code) { + throw new Error("error: could not get balancestatus due to missing beacon port (" + beaconResult.info + ")"); } + const baseURL = `http://127.0.0.1:${beaconResult.data.port}`; - if (next_duty_slot > 0) { - const remaining_slots = next_duty_slot - current_slot - 1; - - const remaining_time = remaining_slots * slot_time + slot_timeout; + const { current_epoch, current_slot } = await this.getCurrentEpochandSlot(); - output = { ...output, remainingSlots: remaining_slots, remainingTime: remaining_time }; - } + let proposerDutiesRes = await this.queryBeaconApi( + baseURL, + "/eth/v1/validator/duties/proposer/" + current_epoch, + [], + "GET" + ); + let syncDutiesRes = await this.queryBeaconApi( + baseURL, + "/eth/v1/validator/duties/sync/" + current_epoch, + validatorIndices, + "POST" + ); - return { ...output, currentProp: current_prop, slotsPerEpoch }; + return { + proposerDuties: proposerDutiesRes.data.api_reponse.data.filter((d) => + validatorIndices.some((i) => i === d.validator_index) + ), // filter out duties for validators that are not in the validatorIndices (imported vals) array + syncDuties: syncDutiesRes.data.api_reponse.data, + currentEpoch: current_epoch, + currentSlot: current_slot, + }; } catch (error) { - return { error: true, message: "An error occurred in getValidatorStats" }; + log.error("Getting Validator Duties Failed:\n" + error); + return { + code: error.code ? error.code : 1, + info: error.message ? error.message : JSON.stringify(error), + data: error, + }; } } @@ -3003,7 +3029,7 @@ rm -rf diskoutput validatorBalances = queryResult.map((key, id) => { return { id: id, - index: key.index, + validatorindex: key.index, balance: key.balance, status: key.validator.slashed === "true" ? "slashed" : key.status.replace(/_.*/, ""), pubkey: key.validator.pubkey, @@ -3056,7 +3082,7 @@ rm -rf diskoutput let currentEpoch = Math.floor(currentSlot / epochLength); let currentJustifiedEpoch = parseInt(JSON.parse(beaconAPIEpochRunCmd.stdout).data.current_justified.epoch); let previousJustifiedEpoch = parseInt(JSON.parse(beaconAPIEpochRunCmd.stdout).data.previous_justified.epoch); - let finalizedEpoch = parseInt(JSON.parse(beaconAPIEpochRunCmd.stdout).data.finalized.epoch); + let finalizedEpoch = parseInt(JSON.parse(beaconAPIEpochRunCmd.stdout).data.finalized.epoch) - 1; // because beacon-API sends previousJustifiedEpoch = finalizedEpoch // create return data currentEpochSlotStatus = { @@ -3149,7 +3175,7 @@ rm -rf diskoutput } } - async exitValidatorAccount(pubkey, password, serviceID) { + async exitValidatorAccount(pubkey, serviceID) { const beaconStatus = await this.getBeaconStatus(); try { if (beaconStatus.code === 0) { @@ -3158,25 +3184,26 @@ rm -rf diskoutput if (!Array.isArray(pubkey)) { pubkey = [pubkey]; } - const results = []; + let results = []; for (let i = 0; i < pubkey.length; i++) { const ref = StringUtils.createRandomString(); // Create a random string to identify the task this.nodeConnection.taskManager.otherTasksHandler(ref, `Exit Account ${pubkey[i].substring(0, 6)}..`); try { - const result = await this.validatorAccountManager.getExitValidatorMessage(pubkey[i], password, serviceID); - if (SSHService.checkExecError(result) && result.stderr) throw SSHService.extractExecError(result); - log.info(result); - - const exitMsg = JSON.stringify(JSON.parse(result.stdout).data); - const exitCommand = `docker run --rm --network=stereum curlimages/curl curl 'http://stereum-${serviceId}:${beaconAPIPort}/eth/v1/beacon/pool/voluntary_exits' -H 'accept: */*' -H 'Content-Type: application/json' -d '${exitMsg}'`; + const result = await this.validatorAccountManager.getExitValidatorMessage(pubkey[i], serviceID); + if (result.data === undefined) { + throw result; + } + const exitMsg = result.data; + const exitCommand = `docker run --rm --network=stereum curlimages/curl curl 'http://stereum-${serviceId}:${beaconAPIPort}/eth/v1/beacon/pool/voluntary_exits' -H 'accept: */*' -H 'Content-Type: application/json' -d '${JSON.stringify( + exitMsg + )}' -i -s`; const runExitCommand = await this.nodeConnection.sshService.exec(exitCommand); - if (SSHService.checkExecError(runExitCommand) && runExitCommand.stderr) - throw SSHService.extractExecError(runExitCommand); + log.info(runExitCommand); - // if (!runExitCommand.stdout.includes("validator_index")) { // find out "successful msg" and put instead of !!!! - // throw "Undexpected Error: " + runExitCommand.stdout; - // } + //Error handling + if (SSHService.checkExecError(runExitCommand) && runExitCommand.stderr) + throw SSHService.extractExecError(runExitCommand); // Push successful task this.nodeConnection.taskManager.otherTasksHandler(ref, `Exiting Account`, true, runExitCommand.stdout); @@ -3184,7 +3211,17 @@ rm -rf diskoutput // add pubkey into the runExitCommands' result; runExitCommand["pubkey"] = `${pubkey[i]}`; - results.push(runExitCommand); + + // Extract the JSON payload from the stdout + const jsonStartIndex = runExitCommand.stdout.indexOf("{"); + const jsonEndIndex = runExitCommand.stdout.lastIndexOf("}"); + const stdoutJson = runExitCommand.stdout.substring(jsonStartIndex, jsonEndIndex + 1); + + results.push({ + pubkey: runExitCommand.pubkey, + code: JSON.parse(stdoutJson).code, + msg: JSON.parse(stdoutJson).message, + }); } catch (error) { this.nodeConnection.taskManager.otherTasksHandler( ref, diff --git a/launcher/src/backend/OneClickInstall.js b/launcher/src/backend/OneClickInstall.js index 9d68efa7a..dcf1877f4 100755 --- a/launcher/src/backend/OneClickInstall.js +++ b/launcher/src/backend/OneClickInstall.js @@ -246,7 +246,7 @@ export class OneClickInstall { //archvie by default break; case "ErigonService": - //archive by default + this.executionClient.command = this.executionClient.command.filter(c => !c.includes("--prune")); break; case "BesuService": this.executionClient.command[this.executionClient.command.findIndex((c) => c.includes("--sync-mode=X_SNAP"))] = "--sync-mode=FULL"; diff --git a/launcher/src/backend/ValidatorAccountManager.js b/launcher/src/backend/ValidatorAccountManager.js index da3a98298..5290ee84e 100755 --- a/launcher/src/backend/ValidatorAccountManager.js +++ b/launcher/src/backend/ValidatorAccountManager.js @@ -19,8 +19,6 @@ export class ValidatorAccountManager { this.nodeConnection = nodeConnection; this.serviceManager = serviceManager; this.batches = []; - this.callCount = 0; - this.storedKeys = []; } createBatch(files, password, slashingDB, chunkSize = 100) { @@ -49,7 +47,7 @@ export class ValidatorAccountManager { pubkeys = files; } else { this.batches = []; - this.createBatch(files, password, slashingDB, client.service === "Web3SignerService" ? 20 : 100); + this.createBatch(files, password, slashingDB, isRemote ? 20 : 100); pubkeys = this.batches.map((b) => b.keystores.map((c) => JSON.parse(c).pubkey)).flat(); } @@ -61,11 +59,9 @@ export class ValidatorAccountManager { let latestEpochsResponse = await axios.get( networks[client.network].dataEndpoint + "/validator/" + pubkey + "/attestations" ); - if ( - latestEpochsResponse.status === 200 && - latestEpochsResponse.data.data.length > 0 && - latestEpochsResponse.data.status !== /ERROR:*/ - ) { + + if (latestEpochsResponse.status === 200 && latestEpochsResponse.data.data.length > 0) { + for (let i = 0; i < 2; i++) { if (latestEpochsResponse.data.data[i].status === 1 && isActiveRunning.indexOf(pubkey) === -1) { isActiveRunning.push(pubkey); @@ -237,7 +233,7 @@ export class ValidatorAccountManager { } } - async listValidators(serviceID, numRunningValidatorService) { + async listValidators(serviceID) { const ref = StringUtils.createRandomString(); this.nodeConnection.taskManager.otherTasksHandler(ref, `Listing Keys`); try { @@ -258,7 +254,7 @@ export class ValidatorAccountManager { this.nodeConnection.taskManager.otherTasksHandler(ref, `Get Keys`, true, result.stdout); if (!data.data) data.data = []; - await this.storeKeys(data.data, numRunningValidatorService); + this.writeKeys(data.data.map((key) => key.validating_pubkey)); this.nodeConnection.taskManager.otherTasksHandler(ref, `Write Keys to keys.yaml`, true); this.nodeConnection.taskManager.otherTasksHandler(ref); @@ -319,7 +315,8 @@ export class ValidatorAccountManager { if (!apiToken) apiToken = await this.getApiToken(service); let command = [ "docker run --rm --network=stereum curlimages/curl", - `curl ${service.service.includes("Teku") ? "--insecure https" : "http"}://stereum-${service.id}:${validatorPorts[service.service] + `curl ${service.service.includes("Teku") ? "--insecure https" : "http"}://stereum-${service.id}:${ + validatorPorts[service.service] }${path}`, `-X ${method.toUpperCase()}`, `-H 'Content-Type: application/json'`, @@ -429,7 +426,6 @@ export class ValidatorAccountManager { //Push successful task this.nodeConnection.taskManager.otherTasksHandler(ref, `Set Fee Recipient`, true, result.stdout); this.nodeConnection.taskManager.otherTasksHandler(ref); - return data; } catch (err) { this.nodeConnection.taskManager.otherTasksHandler( @@ -463,7 +459,6 @@ export class ValidatorAccountManager { //Push successful task this.nodeConnection.taskManager.otherTasksHandler(ref, `Delete Fee Recipient`, true, result.stdout); this.nodeConnection.taskManager.otherTasksHandler(ref); - return data; } catch (err) { this.nodeConnection.taskManager.otherTasksHandler( @@ -534,58 +529,35 @@ export class ValidatorAccountManager { } } - async storeKeys(data, numRunningValidatorService) { - this.callCount++; - if (this.callCount % numRunningValidatorService !== 0 && !isNaN(this.callCount % numRunningValidatorService)) { - this.storedKeys.push(...data.map((k) => k.validating_pubkey)); - } else if (this.callCount % numRunningValidatorService === 0) { - this.storedKeys.push(...data.map((k) => k.validating_pubkey)); - await this.writeKeys(this.storedKeys); - this.storedKeys = []; - this.callCount = 0; - } else if (data.length === 0) { - await this.writeKeys(data); - this.callCount = 0; + async writeKeys(keys) { + //get current keys in yaml file + let currentKeys = await this.readKeys(); + if (!currentKeys) { + currentKeys = {}; } - } - async writeKeys(keys) { - let obj = keys; + //if the argument is an array of keys, add them to the current keys if they don't exist if (Array.isArray(keys)) { - const existing = await this.readKeys(); - if (existing) { - obj = existing; - if (Object.keys(existing).length !== 0) { - Object.keys(existing).forEach((key) => { - obj = !keys.includes(key) ? {} : obj; - }); - } - keys.forEach((key) => { - if (existing[key]) { - if (typeof existing[key] === "string") { - obj[key] = { - keyName: existing[key], - groupName: "", - groupID: null, - }; - } else { - obj[key] = existing[key]; - } - } else { - obj[key] = { - keyName: "", - groupName: "", - groupID: null, - }; - } - }); - } else { - obj = {}; + keys.forEach((key) => { + if (!currentKeys[key]) + currentKeys[key] = { keyName: "", groupName: "", groupID: null, validatorClientID: null }; + }); + await this.nodeConnection.sshService.exec( + "echo -e " + StringUtils.escapeStringForShell(YAML.stringify(currentKeys)) + " > /etc/stereum/keys.yaml" + ); + + //if the argument is an object of keys, overwrite the current keys + } else if (keys) { + if (!keys.overwrite) { + keys = { ...currentKeys, ...keys }; } + delete keys.overwrite; + await this.nodeConnection.sshService.exec( + "echo -e " + StringUtils.escapeStringForShell(YAML.stringify(keys)) + " > /etc/stereum/keys.yaml" + ); + } else { + log.error("INVALID ARGUMENT: keys must be an array or an object"); } - await this.nodeConnection.sshService.exec( - "echo -e " + StringUtils.escapeStringForShell(YAML.stringify(obj)) + " > /etc/stereum/keys.yaml" - ); } async readKeys() { @@ -658,25 +630,28 @@ export class ValidatorAccountManager { return result.stdout.trim(); } - async getExitValidatorMessage(pubkey, password, serviceID) { + async getExitValidatorMessage(pubkey, serviceID) { const ref = StringUtils.createRandomString(); //Create a random string to identify the task this.nodeConnection.taskManager.otherTasksHandler(ref, `Exit msg for ${pubkey.substring(0, 6)}..`); try { let service = await this.nodeConnection.readServiceConfiguration(serviceID); - let data = []; - const result = await this.keymanagerAPI(service, "POST", `/eth/v1/validator/${pubkey}/voluntary_exit`, data); + const result = await this.keymanagerAPI(service, "POST", `/eth/v1/validator/${pubkey}/voluntary_exit`, []); if (SSHService.checkExecError(result) && result.stderr) throw SSHService.extractExecError(result); - log.info(result); - if (!result.stdout.includes("validator_index")) { - throw "Undexpected Error: " + result.stdout; + log.info(result); + const data = JSON.parse(result.stdout); + if (data.data === undefined) { + if (data.code === undefined || data.message === undefined) { + throw "Undexpected Error: " + result; + } + throw data.code + " " + data.message; } //Push successful task - this.nodeConnection.taskManager.otherTasksHandler(ref, `Get signed voluntary exit message`, true, result.stdout); + this.nodeConnection.taskManager.otherTasksHandler(ref, `Get signed voluntary exit message`, true, data); this.nodeConnection.taskManager.otherTasksHandler(ref); - return result; + return data; } catch (error) { this.nodeConnection.taskManager.otherTasksHandler( ref, @@ -690,7 +665,6 @@ export class ValidatorAccountManager { } } - formatImportResult(pubkeys, data) { let imported = 0; let duplicate = 0; diff --git a/launcher/src/backend/ethereum-services/ErigonService.js b/launcher/src/backend/ethereum-services/ErigonService.js index b6001f2e1..8f75e1d49 100755 --- a/launcher/src/backend/ethereum-services/ErigonService.js +++ b/launcher/src/backend/ethereum-services/ErigonService.js @@ -28,7 +28,7 @@ export class ErigonService extends NodeService { `--authrpc.vhosts=*`, `--authrpc.port=8551`, `--authrpc.jwtsecret=/engine.jwt`, - `--prune=default`, + '--rpc.returndata.limit=1000000', `--ws`, `--http`, `--http.vhosts=*`, @@ -39,6 +39,8 @@ export class ErigonService extends NodeService { `--metrics`, `--metrics.addr=0.0.0.0`, `--metrics.port=6060`, + '--db.pagesize=16K', + '--db.size.limit=8TB', ], // command [], // entrypoint null, // env @@ -50,6 +52,27 @@ export class ErigonService extends NodeService { // consensusClients ); + switch (network) { + case "mainnet": + service.command.push("--prune=htc", "--prune.r.before=11052984"); + break; + case "goerli": + service.command.push("--prune=htc", "--prune.r.before=4367322"); + break; + case "sepolia": + service.command.push("--prune=htc", "--prune.r.before=1273020"); + break; + case "holesky": + service.command.push("--prune=htc"); + break; + case "gnosis": + service.command.push("--prune=htc", "--prune.r.before=19469077"); + break; + default: + service.command.push("--prune=htc"); + break; + } + return service; } diff --git a/launcher/src/background.js b/launcher/src/background.js index a990e610a..ac57684c2 100755 --- a/launcher/src/background.js +++ b/launcher/src/background.js @@ -240,7 +240,7 @@ ipcMain.handle("deleteValidators", async (event, args) => { }); ipcMain.handle("listValidators", async (event, args) => { - return await validatorAccountManager.listValidators(args.serviceID, args.numRunningValidatorService); + return await validatorAccountManager.listValidators(args); }); ipcMain.handle("listServices", async () => { @@ -423,7 +423,7 @@ ipcMain.handle("checkActiveValidators", async (event, args) => { }); ipcMain.handle("exitValidatorAccount", async (event, args) => { - return await monitoring.exitValidatorAccount(args.pubkey, args.password, args.serviceID); + return await monitoring.exitValidatorAccount(args.pubkey, args.serviceID); }); ipcMain.handle("exportConfig", async () => { @@ -494,6 +494,26 @@ ipcMain.handle("dumpDockerLogs", async () => { return await nodeConnection.dumpDockerLogs(); }); +ipcMain.handle("getCurrentEpochandSlot", async () => { + return await monitoring.getCurrentEpochandSlot(); +}); + +ipcMain.handle("getValidatorDuties", async (event, args) => { + return await monitoring.getValidatorDuties(args); +}); + +ipcMain.handle("getAttestationRewards", async (event, args) => { + return await monitoring.getAttestationRewards(args); +}); + +ipcMain.handle("getBlockRewards", async (event, args) => { + return await monitoring.getBlockRewards(args); +}); + +ipcMain.handle("getSyncCommitteeRewards", async (event, args) => { + return await monitoring.getSyncCommitteeRewards(args.validators, args.slot); +}); + // Scheme must be registered before the app is ready protocol.registerSchemesAsPrivileged([{ scheme: "app", privileges: { secure: true, standard: true } }]); diff --git a/launcher/src/components/UI/TheCarousel/components/TheCarousel.vue b/launcher/src/components/UI/TheCarousel/components/TheCarousel.vue index 4b4656bc0..dd3180169 100644 --- a/launcher/src/components/UI/TheCarousel/components/TheCarousel.vue +++ b/launcher/src/components/UI/TheCarousel/components/TheCarousel.vue @@ -209,40 +209,8 @@ const linkPicker = async (item) => { }; const setSelectedLinks = () => { - - if (configNetwork.value.id === 1 || currentNetwork.value.id === 1) { - - selectedLinks.value = installStore.mainnet; - } else if (configNetwork.value.id === 2 || currentNetwork.value.id === 2) { - selectedLinks.value = installStore.georli; - } else if (currentNetwork.value.id === 3 || currentNetwork.value.id === 3) { - selectedLinks.value = installStore.sepolia; - } else if (configNetwork.value.id === 4 || currentNetwork.value.id === 4) { - selectedLinks.value = installStore.gnosis; - } else if (configNetwork.value.id === 5 || currentNetwork.value.id === 5) { - selectedLinks.value = installStore.holesky; - } + selectedLinks.value = installStore[manageStore.currentNetwork.network]; }; - -// const setSelectedLinks = () => { -// switch (configNetwork.value.id) { -// case 1: -// selectedLinks.value = installStore.mainnet; -// break; - -// case 2: -// selectedLinks.value = installStore.georli; -// break; -// case 3: -// selectedLinks.value = installStore.sepolia; -// break; -// case 4: -// selectedLinks.value = installStore.gnosis; -// break; -// default: -// break; -// } -// }; diff --git a/launcher/src/components/UI/edit-page/components/drawer/DrawerFilter.vue b/launcher/src/components/UI/edit-page/components/drawer/DrawerFilter.vue index 7ca7c04c0..b2965d079 100644 --- a/launcher/src/components/UI/edit-page/components/drawer/DrawerFilter.vue +++ b/launcher/src/components/UI/edit-page/components/drawer/DrawerFilter.vue @@ -80,7 +80,8 @@ const getFilterbyNetwork = () => { case "sepolia": return (item) => item.service != "SSVNetworkService" && archFilter(item.service); case "gnosis": - return (item) => /(Lighthouse|Teku|Nethermind|Grafana|Prometheus)/.test(item.service) && archFilter(item.service); + return (item) => + /(Lighthouse|Teku|Nethermind|Erigon|Grafana|Prometheus)/.test(item.service) && archFilter(item.service); default: return (item) => item.service != "SSVNetworkService" && archFilter(item.service); } diff --git a/launcher/src/components/UI/edit-page/components/edit/ConfigDetails.vue b/launcher/src/components/UI/edit-page/components/edit/ConfigDetails.vue index 6964973f5..9af4b9048 100644 --- a/launcher/src/components/UI/edit-page/components/edit/ConfigDetails.vue +++ b/launcher/src/components/UI/edit-page/components/edit/ConfigDetails.vue @@ -1,7 +1,5 @@ diff --git a/launcher/src/components/UI/edit-page/components/modals/MevboostRelays.vue b/launcher/src/components/UI/edit-page/components/modals/MevboostRelays.vue index ceec0a091..e04b55eb1 100644 --- a/launcher/src/components/UI/edit-page/components/modals/MevboostRelays.vue +++ b/launcher/src/components/UI/edit-page/components/modals/MevboostRelays.vue @@ -1,7 +1,7 @@ + diff --git a/launcher/src/components/UI/node-header/SecurityButton.vue b/launcher/src/components/UI/node-header/SecurityButton.vue index 13bba25f0..ab1874571 100644 --- a/launcher/src/components/UI/node-header/SecurityButton.vue +++ b/launcher/src/components/UI/node-header/SecurityButton.vue @@ -2,7 +2,7 @@
@@ -40,13 +40,23 @@ export default { serverAccessManagement: "serverAccessManagement", }), checkTheRouter() { - if (this.$route.fullPath !== "/login") { + if (this.$route.fullPath !== "/login" || this.$route.fullPath !== "/oneClick/play") { return true; } else { return false; } }, }, + + watch: { + securityButtonHandler() { + if (this.$route.fullPath === "/login" || this.$route.fullPath === "/oneClick/play") { + return; + } else { + this.$emit("accessSwitch"); + } + }, + }, }; diff --git a/launcher/src/components/UI/node-header/ServiceLinks.vue b/launcher/src/components/UI/node-header/ServiceLinks.vue index f7333cdad..59c93c466 100755 --- a/launcher/src/components/UI/node-header/ServiceLinks.vue +++ b/launcher/src/components/UI/node-header/ServiceLinks.vue @@ -88,8 +88,9 @@ export default { } else if (serviceName == "FlashbotsMevBoostService") { this.showMevboostWindow = true; } else if (serviceName == "CharonService") { - this.showObolCharonWindow = true; - console.log("ObolCharonService"); + return; + // this.showObolCharonWindow = true; + // console.log("ObolCharonService"); } else { return; } diff --git a/launcher/src/components/UI/node-manage/SidebarManage.vue b/launcher/src/components/UI/node-manage/SidebarManage.vue index 453c9b097..ab1b424a5 100755 --- a/launcher/src/components/UI/node-manage/SidebarManage.vue +++ b/launcher/src/components/UI/node-manage/SidebarManage.vue @@ -114,7 +114,8 @@ export default { return (item) => item.service != "SSVNetworkService" && this.archFilter(item.service); case "gnosis": return (item) => - /(Lighthouse|Teku|Nethermind|Grafana|Prometheus)/.test(item.service) && this.archFilter(item.service); + /(Lighthouse|Teku|Nethermind|Erigon|Grafana|Prometheus)/.test(item.service) && + this.archFilter(item.service); default: return (item) => item.service != "SSVNetworkService" && this.archFilter(item.service); } diff --git a/launcher/src/components/UI/node-page/NodeScreen.vue b/launcher/src/components/UI/node-page/NodeScreen.vue index aad51aa1c..bbc8b0b9a 100755 --- a/launcher/src/components/UI/node-page/NodeScreen.vue +++ b/launcher/src/components/UI/node-page/NodeScreen.vue @@ -6,11 +6,11 @@
- +
- +
@@ -25,6 +25,12 @@
+
@@ -35,6 +41,7 @@ import SidebarSection from "./sections/SidebarSection"; import NodeSection from "./sections/NodeSection.vue"; import ServiceSection from "./sections/ServiceSection.vue"; import AlertSection from "./sections/AlertSection.vue"; +import LogsSection from "./sections/LogsSection.vue"; import { ref, onMounted, onUnmounted, watchEffect } from "vue"; import ExpertWindow from "./sections/ExpertWindow.vue"; import { useNodeStore } from "@/store/theNode"; @@ -46,9 +53,12 @@ import { useRefreshNodeStats } from "../../../composables/monitoring"; import { useListKeys } from "../../../composables/validators"; import { useRouter } from "vue-router"; import { useFooter } from "@/store/theFooter"; +import { saveAs } from "file-saver"; const expertModeClient = ref(null); const isExpertModeOpen = ref(false); +const isLogsPageActive = ref(false); + // const chckTutorial = "/img/icon/round-icon.png"; // const returnStatus = "/img/icon/round-icon.png"; @@ -74,6 +84,15 @@ watchEffect(() => { } }); +watchEffect(() => { + if (headerStore.openModalFromNodeAlert) { + nodeStore.isLineHidden = true; + expertModeClient.value = headerStore.selectedValidatorFromNodeAlert; + expertModeClient.value.expertOptionsModal = true; + isExpertModeOpen.value = true; + } +}); + //Lifecycle Hooks onMounted(() => { updateConnectionStats(); @@ -149,6 +168,29 @@ const updateNodeStats = async () => { const closeExpertMode = () => { isExpertModeOpen.value = false; nodeStore.isLineHidden = false; + headerStore.openModalFromNodeAlert = false; + headerStore.selectedValidatorFromNodeAlert = null; +}; +// ********** LOGS ********** + +const exportLogs = async () => { + const data = nodeStore.serviceLogs.slice(-150).reverse(); + const fileName = nodeStore.clientToLogs.name; + + const lineByLine = data.map((line, index) => `#${data.length - index}: ${line}`).join("\n\n"); + + const blob = new Blob([lineByLine], { type: "text/plain;charset=utf-8" }); + saveAs(blob, fileName); +}; + +const openLogPage = (item) => { + nodeStore.clientToLogs = item; + isLogsPageActive.value = true; +}; + +const closeLogPage = () => { + nodeStore.clientToLogs = null; + isLogsPageActive.value = false; }; + + + + + + + + + + diff --git a/launcher/src/components/UI/node-page/components/modals/CustomModal.vue b/launcher/src/components/UI/node-page/components/modals/CustomModal.vue index 31ff38ca4..e04a44d9e 100644 --- a/launcher/src/components/UI/node-page/components/modals/CustomModal.vue +++ b/launcher/src/components/UI/node-page/components/modals/CustomModal.vue @@ -59,16 +59,17 @@ const emitConfirmAction = () => { emit("confirmAction"); }; -defineProps({ - icon: String, - altText: String, - mainTitle: String, - messageText: String, - confirmText: String, - confirmBtn: Boolean, - clickOutsideText: String, - bgColor: String, - btnColor: String, - iconSize: String, -}); +const { icon, altText, mainTitle, messageText, confirmText, clickOutsideText, bgColor, btnColor, iconSize } = + defineProps({ + icon: String, + altText: String, + mainTitle: String, + messageText: String, + confirmText: String, + confirmBtn: Boolean, + clickOutsideText: String, + bgColor: String, + btnColor: String, + iconSize: String, + }); diff --git a/launcher/src/components/UI/node-page/components/modals/ResyncModal.vue b/launcher/src/components/UI/node-page/components/modals/ResyncModal.vue index 85939d343..177a968ad 100755 --- a/launcher/src/components/UI/node-page/components/modals/ResyncModal.vue +++ b/launcher/src/components/UI/node-page/components/modals/ResyncModal.vue @@ -219,22 +219,7 @@ const linkPicker = (item) => { btnActive.value = true; }; const setSelectedLinks = () => { - switch (nodeManageStore.currentNetwork.id) { - case 1: - selectedLinks.value = clickInstallStore.mainnet; - break; - case 2: - selectedLinks.value = clickInstallStore.georli; - break; - case 3: - selectedLinks.value = clickInstallStore.sepolia; - break; - case 4: - selectedLinks.value = clickInstallStore.gnosis; - break; - default: - break; - } + selectedLinks.value = clickInstallStore[nodeManageStore.currentNetwork.network]; }; diff --git a/launcher/src/components/UI/node-page/components/node/NodeBody.vue b/launcher/src/components/UI/node-page/components/node/NodeBody.vue index c225a3d67..bc2521bab 100755 --- a/launcher/src/components/UI/node-page/components/node/NodeBody.vue +++ b/launcher/src/components/UI/node-page/components/node/NodeBody.vue @@ -14,7 +14,7 @@ import { mapState, map } from 'pinia';
{ nodeStore.lines = []; }; -const openLogsPage = (item) => { - itemToLogs.value = item; - isPluginLogPageActive.value = true; +const openLog = (item) => { + emit("openLog", item); }; const closePluginLogsPage = () => { diff --git a/launcher/src/components/UI/node-page/components/service/ServiceBody.vue b/launcher/src/components/UI/node-page/components/service/ServiceBody.vue index 6a924b713..84d60f4ee 100755 --- a/launcher/src/components/UI/node-page/components/service/ServiceBody.vue +++ b/launcher/src/components/UI/node-page/components/service/ServiceBody.vue @@ -3,18 +3,19 @@ class="w-full h-[430px] rounded-md border border-gray-600 bg-[#151618] relative hover:scroll-auto overflow-y-auto" >
Services
- -
@@ -37,13 +36,9 @@ import { useStateHandler, useRestartService } from "@/composables/services"; import { useServices } from "@/store/services"; import ServiceLayout from "./ServiceLayout.vue"; import ServiceButtons from "./ServiceButtons.vue"; -import PluginLogs from "../../sections/PluginLogs.vue"; -import { computed, ref } from "vue"; - -const emit = defineEmits(["openExpert"]); +import { computed } from "vue"; -const isPluginLogPageActive = ref(false); -const itemToLogs = ref({}); +const emit = defineEmits(["openExpert", "openLogs"]); const serviceStore = useServices(); @@ -62,12 +57,7 @@ const openDocs = (item) => { }; const openLogs = (item) => { - isPluginLogPageActive.value = true; - itemToLogs.value = item; -}; - -const closeLogs = () => { - isPluginLogPageActive.value = false; + emit("openLogs", item); }; diff --git a/launcher/src/components/UI/one-click/components/sync/SyncCarousel.vue b/launcher/src/components/UI/one-click/components/sync/SyncCarousel.vue index a56d2c748..1191821c9 100644 --- a/launcher/src/components/UI/one-click/components/sync/SyncCarousel.vue +++ b/launcher/src/components/UI/one-click/components/sync/SyncCarousel.vue @@ -85,7 +85,7 @@
  • { }; const setSelectedLinks = () => { - switch (manageStore.currentNetwork?.id) { - case 1: - selectedLinks.value = installStore.mainnet; - break; - case 2: - selectedLinks.value = installStore.georli; - break; - case 3: - selectedLinks.value = installStore.sepolia; - break; - case 4: - selectedLinks.value = installStore.gnosis; - break; - default: - break; - } + + const networkLinks = { + 1: installStore.mainnet, + 2: installStore.goerli, + 3: installStore.sepolia, + 4: installStore.gnosis, + 5: installStore.holesky, + }; + + selectedLinks.value = networkLinks[manageStore.currentNetwork?.id] || []; + }; diff --git a/launcher/src/components/UI/services-modal/MevboostModal.vue b/launcher/src/components/UI/services-modal/MevboostModal.vue index 07087f8cd..3cf3d49d9 100755 --- a/launcher/src/components/UI/services-modal/MevboostModal.vue +++ b/launcher/src/components/UI/services-modal/MevboostModal.vue @@ -120,16 +120,40 @@ export default { this.installedServices.forEach((item) => { if (item.name === "Flashbots Mev Boost") this.mevService = item; }); + this.isMevAvailable = true; - ControlService.getServiceConfig(this.mevService.config.serviceID).then((service) => { - let relayURLs = service.entrypoint[service.entrypoint.findIndex((e) => e === "-relays") + 1].split(","); - relayURLs.forEach((relay) => { - let relayData = this.relaysList.find((r) => r[this.currentNetwork.network.toLowerCase()] === relay); - if (relayData) this.checkedRelays.push(relayData); - }); - this.serviceConfig = service; - }); + + if (this.mevService && this.mevService.config && this.mevService.config.serviceID) { + ControlService.getServiceConfig(this.mevService.config.serviceID) + .then((service) => { + if (service && service.entrypoint) { + const relayEntryPointIndex = service.entrypoint.findIndex((e) => e === "-relays"); + if (relayEntryPointIndex !== -1 && relayEntryPointIndex + 1 < service.entrypoint.length) { + const relayURLs = service.entrypoint[relayEntryPointIndex + 1].split(","); + relayURLs.forEach((relay) => { + let relayData = this.relaysList.find((r) => r[this.currentNetwork.network.toLowerCase()] === relay); + if (relayData) this.checkedRelays.push(relayData); + }); + } else { + console.error("Invalid or missing -relays entry in service entrypoint"); + // Handle the error or add appropriate fallback logic. + } + this.serviceConfig = service; + } else { + console.error("Invalid service or missing entrypoint"); + // Handle the error or add appropriate fallback logic. + } + }) + .catch((error) => { + console.error("Error fetching service config:", error); + // Handle the error or add appropriate fallback logic. + }); + } else { + console.error("Invalid or missing service or serviceID in config"); + // Handle the error or add appropriate fallback logic. + } }, + openBrowser() { let url = "https://boost.flashbots.net/"; window.open(url, "_blank"); diff --git a/launcher/src/components/UI/services-modal/ObolModal.vue b/launcher/src/components/UI/services-modal/ObolModal.vue index 1be20847b..e2715bc69 100644 --- a/launcher/src/components/UI/services-modal/ObolModal.vue +++ b/launcher/src/components/UI/services-modal/ObolModal.vue @@ -18,19 +18,18 @@
    -
    - {{ !headerStore.continueForExistENR ? "CREATE NEW ENR" : "OPEN OBOL LAUNCHPAD" }} - {{ + -
    -
    -
    - {{ !headerStore.continueForExistENR ? "GENERATE" : "OPEN IN BROWSER" }} -
    -
    + ? 'Generate a new ENR to use to create or join an existing cluster' + : 'Create/join an Obol Cluster solo or with a group using the Distributed Validator Launchpad.' + }`" + :btn-name="`${!headerStore.continueForExistENR ? 'GENERATE' : 'OPEN IN BROWSER'}`" + :btn-bg-color="`#192d31`" + :btn-name-color="`#2fe4ab`" + @confirmPluginClick="topBlock" + />
    @@ -44,40 +43,38 @@
    -
    - {{ !headerStore.continueForExistENR ? "CREATE NEW ENR" : "OPEN OBOL LAUNCHPAD" }} - {{ + -
    -
    -
    - ENR -
    -
    REMOVE
    -
    + ? 'Generate a new ENR to use to create or join an existing cluster' + : 'Create/join an Obol Cluster solo or with a group using the Distributed Validator Launchpad.' + }`" + :btn-name="`COPY`" + :second-btn-name="`REMOVE`" + :btn-bg-color="`#494949`" + :second-btn-bg-color="`#eb5353`" + :btn-name-color="`#dbdbdb`" + img-url="/img/icon/service-icons/copy1.png" + @confirmPluginClick="copyHandler" + @secBtnPluginClick="removeHandler" + />
    -
    -
    - {{ headerStore.depositFile ? "BACKUP DEPOSIT FILE" : "START THE DKG" }} - {{ - headerStore.depositFile - ? "Export your backup deposit file from the server to back it up" - : "When all ENRs are signed, you will be presented with a command. All Node Operators have to run this command at the same time!" - }} - -
    -
    -
    - {{ headerStore.depositFile ? "SAVE" : "START" }} -
    -
    -
    +
    PASTE THE URL @@ -98,6 +95,7 @@ import { useNodeHeader } from "@/store/nodeHeader"; import EnrGenerator from "./EnrGenerator.vue"; import { ref, onMounted } from "vue"; +import ConfirmBox from "./plugin/ConfirmBox.vue"; const obolSharonService = ref({}); const importedENR = ref(""); @@ -311,28 +309,7 @@ onMounted(() => { align-items: center; margin-bottom: 2%; } -.browserBox .title { - width: 70%; - height: 100%; - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: flex-start; -} -.title span:first-child { - color: #dbdbdb; - font-size: 0.9rem; - font-weight: 600; - margin-left: 10px; - margin-top: 5px; -} -.title span:last-child { - color: #dbdbdb; - font-size: 0.65rem; - font-weight: 400; - margin-left: 10px; - margin-top: 10px; -} + .browserBox_import { width: 100%; height: 100%; @@ -400,46 +377,4 @@ onMounted(() => { background-color: #1a2e32e6; box-shadow: 1px 1px 10px 1px #171717 inset; } - -.browserBox .btn-box { - width: 30%; - height: 100%; - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: flex-end; -} -.browserBox .btn { - width: 90%; - height: 35%; - - margin-right: 10px; - background-color: #192d31; - text-decoration: none; - border-radius: 50px; - display: flex; - justify-content: center; - align-items: center; - cursor: pointer; - color: #2fe4ab; - font-size: 0.9rem; - font-weight: 600; - text-transform: uppercase; - transition-duration: all 200ms; -} -.browserBox .btn:first-child { - margin-top: 15px; -} -.browserBox .btn:not(:first-child) { - margin-top: 5px; -} -.btn:hover { - transition-duration: 100ms; - background-color: rgba(26, 46, 50, 0.6); -} -.btn:active { - transition-duration: 100ms; - background-color: #1a2e32e6; - box-shadow: 1px 1px 10px 1px #171717 inset; -} diff --git a/launcher/src/components/UI/services-modal/PrometheusModal.vue b/launcher/src/components/UI/services-modal/PrometheusModal.vue index d7a1857bf..f33a62418 100755 --- a/launcher/src/components/UI/services-modal/PrometheusModal.vue +++ b/launcher/src/components/UI/services-modal/PrometheusModal.vue @@ -16,22 +16,26 @@
    -
    - {{ $t("serviceModals.localApp") }} - {{ $t("serviceModals.localAppText") }} -
    - +
    @@ -179,63 +187,6 @@ export default { display: flex; justify-content: space-between; align-items: center; -} -.browserBox .title { - width: 50%; - height: 100%; - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: flex-start; -} -.title span:first-child { - color: #dbdbdb; - font-size: 0.9rem; - font-weight: 600; - margin-left: 10px; - margin-top: 5px; -} -.title span:last-child { - color: #dbdbdb; - font-size: 0.65rem; - font-weight: 400; - margin-left: 10px; - margin-top: 10px; -} - -.browserBox .btn-box { - width: 50%; - height: 100%; - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: flex-end; -} -.browserBox .btn { - width: 50%; - height: 35%; - margin-top: 15px; - margin-right: 10px; - background-color: #f37625; - text-decoration: none; - border-radius: 50px; - display: flex; - justify-content: center; - align-items: center; - cursor: pointer; - color: #e1e1e1; - font-size: 0.7rem; - font-weight: 600; - text-transform: uppercase; - transition-duration: all 200ms; -} -.btn:hover { - transition-duration: 100ms; - background-color: rgb(179, 72, 0); -} -.btn:active { - box-shadow: 1px 1px 10px 1px #171717 inset; - transition-duration: 100ms; - background-color: rgb(179, 72, 0); + margin-bottom: 2%; } diff --git a/launcher/src/components/UI/services-modal/SsvModal.vue b/launcher/src/components/UI/services-modal/SsvModal.vue index 1dae4ed7c..186f9ea7c 100755 --- a/launcher/src/components/UI/services-modal/SsvModal.vue +++ b/launcher/src/components/UI/services-modal/SsvModal.vue @@ -51,53 +51,157 @@ -
    -
    - spinner + + + + +
    diff --git a/launcher/src/components/UI/services-modal/plugin/ConfirmBox.vue b/launcher/src/components/UI/services-modal/plugin/ConfirmBox.vue new file mode 100644 index 000000000..81c2add0f --- /dev/null +++ b/launcher/src/components/UI/services-modal/plugin/ConfirmBox.vue @@ -0,0 +1,173 @@ + + + + + diff --git a/launcher/src/components/UI/services-modal/plugin/ImportBox.vue b/launcher/src/components/UI/services-modal/plugin/ImportBox.vue new file mode 100644 index 000000000..3f833961b --- /dev/null +++ b/launcher/src/components/UI/services-modal/plugin/ImportBox.vue @@ -0,0 +1,165 @@ + + + + + diff --git a/launcher/src/components/UI/services-modal/plugin/PasswordBox.vue b/launcher/src/components/UI/services-modal/plugin/PasswordBox.vue new file mode 100644 index 000000000..a0387bc6f --- /dev/null +++ b/launcher/src/components/UI/services-modal/plugin/PasswordBox.vue @@ -0,0 +1,194 @@ + + + + + diff --git a/launcher/src/components/UI/staking-page/StakingScreen.vue b/launcher/src/components/UI/staking-page/StakingScreen.vue new file mode 100644 index 000000000..a8cb25de3 --- /dev/null +++ b/launcher/src/components/UI/staking-page/StakingScreen.vue @@ -0,0 +1,719 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/list/GroupList.vue b/launcher/src/components/UI/staking-page/components/list/GroupList.vue new file mode 100644 index 000000000..4fa00e85c --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/GroupList.vue @@ -0,0 +1,33 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/list/ListBody.vue b/launcher/src/components/UI/staking-page/components/list/ListBody.vue new file mode 100644 index 000000000..ada75ae04 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/ListBody.vue @@ -0,0 +1,241 @@ +import { ref, computed, watchEffect, watch, onMounted, onUnmounted } from 'vue'; + + + + diff --git a/launcher/src/components/UI/staking-page/components/list/ListHeader.vue b/launcher/src/components/UI/staking-page/components/list/ListHeader.vue new file mode 100644 index 000000000..69a64c87f --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/ListHeader.vue @@ -0,0 +1,84 @@ + + + diff --git a/launcher/src/components/UI/staking-page/components/list/ListPanels.vue b/launcher/src/components/UI/staking-page/components/list/ListPanels.vue new file mode 100644 index 000000000..97d40f253 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/ListPanels.vue @@ -0,0 +1,164 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/list/RemoteList.vue b/launcher/src/components/UI/staking-page/components/list/RemoteList.vue new file mode 100644 index 000000000..49d20326e --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/RemoteList.vue @@ -0,0 +1,70 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/list/panels/FeePanel.vue b/launcher/src/components/UI/staking-page/components/list/panels/FeePanel.vue new file mode 100644 index 000000000..918d53c2c --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/panels/FeePanel.vue @@ -0,0 +1,107 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/list/panels/GraffitiPanel.vue b/launcher/src/components/UI/staking-page/components/list/panels/GraffitiPanel.vue new file mode 100644 index 000000000..4db1527f8 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/panels/GraffitiPanel.vue @@ -0,0 +1,101 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/list/panels/GroupingPanel.vue b/launcher/src/components/UI/staking-page/components/list/panels/GroupingPanel.vue new file mode 100644 index 000000000..de8373dce --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/panels/GroupingPanel.vue @@ -0,0 +1,112 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/list/panels/InsertPanel.vue b/launcher/src/components/UI/staking-page/components/list/panels/InsertPanel.vue new file mode 100644 index 000000000..dd460cfda --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/panels/InsertPanel.vue @@ -0,0 +1,42 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/list/panels/ManualRemote.vue b/launcher/src/components/UI/staking-page/components/list/panels/ManualRemote.vue new file mode 100644 index 000000000..42650424e --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/panels/ManualRemote.vue @@ -0,0 +1,66 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/list/panels/PasswordPanel.vue b/launcher/src/components/UI/staking-page/components/list/panels/PasswordPanel.vue new file mode 100644 index 000000000..92d0b13b5 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/panels/PasswordPanel.vue @@ -0,0 +1,68 @@ + + + diff --git a/launcher/src/components/UI/staking-page/components/list/panels/RemotePanel.vue b/launcher/src/components/UI/staking-page/components/list/panels/RemotePanel.vue new file mode 100644 index 000000000..f7a858d8a --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/panels/RemotePanel.vue @@ -0,0 +1,72 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/list/panels/RenameKey.vue b/launcher/src/components/UI/staking-page/components/list/panels/RenameKey.vue new file mode 100644 index 000000000..b09fb544a --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/panels/RenameKey.vue @@ -0,0 +1,123 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/list/panels/SearchPanel.vue b/launcher/src/components/UI/staking-page/components/list/panels/SearchPanel.vue new file mode 100644 index 000000000..5cb0c07d7 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/panels/SearchPanel.vue @@ -0,0 +1,35 @@ + + + diff --git a/launcher/src/components/UI/staking-page/components/list/panels/ValidatorPanel.vue b/launcher/src/components/UI/staking-page/components/list/panels/ValidatorPanel.vue new file mode 100644 index 000000000..e35efaea7 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/panels/ValidatorPanel.vue @@ -0,0 +1,32 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/list/rows/GroupRow.vue b/launcher/src/components/UI/staking-page/components/list/rows/GroupRow.vue new file mode 100644 index 000000000..c8faf3b37 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/rows/GroupRow.vue @@ -0,0 +1,107 @@ +import { useStakingStore } from '@/store/theStaking'; + + + diff --git a/launcher/src/components/UI/staking-page/components/list/rows/KeyRow.vue b/launcher/src/components/UI/staking-page/components/list/rows/KeyRow.vue new file mode 100644 index 000000000..8ddc2861e --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/rows/KeyRow.vue @@ -0,0 +1,233 @@ +import { computed } from 'vue'; + + + + diff --git a/launcher/src/components/UI/staking-page/components/list/rows/PreviewKey.vue b/launcher/src/components/UI/staking-page/components/list/rows/PreviewKey.vue new file mode 100644 index 000000000..d64f1551f --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/rows/PreviewKey.vue @@ -0,0 +1,47 @@ +import { computed, ref } from 'vue'; + + + diff --git a/launcher/src/components/UI/staking-page/components/list/rows/RemoteRow.vue b/launcher/src/components/UI/staking-page/components/list/rows/RemoteRow.vue new file mode 100644 index 000000000..42adebc10 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/rows/RemoteRow.vue @@ -0,0 +1,25 @@ +import { computed, ref } from 'vue'; + + + diff --git a/launcher/src/components/UI/staking-page/components/list/rows/SkeletonRow.vue b/launcher/src/components/UI/staking-page/components/list/rows/SkeletonRow.vue new file mode 100644 index 000000000..272a9aceb --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/list/rows/SkeletonRow.vue @@ -0,0 +1,44 @@ +import { computed } from 'vue'; + + diff --git a/launcher/src/components/UI/staking-page/components/management/ClientCommands.vue b/launcher/src/components/UI/staking-page/components/management/ClientCommands.vue new file mode 100644 index 000000000..b5b628f95 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/ClientCommands.vue @@ -0,0 +1,29 @@ + + + diff --git a/launcher/src/components/UI/staking-page/components/management/EpochDuty.vue b/launcher/src/components/UI/staking-page/components/management/EpochDuty.vue new file mode 100644 index 000000000..41350dcd3 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/EpochDuty.vue @@ -0,0 +1,68 @@ +import { ref } from 'vue'; + + diff --git a/launcher/src/components/UI/staking-page/components/management/ValidatorRewards.vue b/launcher/src/components/UI/staking-page/components/management/ValidatorRewards.vue new file mode 100644 index 000000000..112863eeb --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/ValidatorRewards.vue @@ -0,0 +1,20 @@ + + + diff --git a/launcher/src/components/UI/staking-page/components/management/components/client-commands/ButtonBox.vue b/launcher/src/components/UI/staking-page/components/management/components/client-commands/ButtonBox.vue new file mode 100644 index 000000000..89df39eaf --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/components/client-commands/ButtonBox.vue @@ -0,0 +1,57 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/management/components/client-commands/ButtonRow.vue b/launcher/src/components/UI/staking-page/components/management/components/client-commands/ButtonRow.vue new file mode 100644 index 000000000..a9f32fd6d --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/components/client-commands/ButtonRow.vue @@ -0,0 +1,60 @@ +import { ref } from 'vue'; import { useStakingStore } from '@/store/theStaking'; + + + diff --git a/launcher/src/components/UI/staking-page/components/management/components/client-commands/ValidatorState.vue b/launcher/src/components/UI/staking-page/components/management/components/client-commands/ValidatorState.vue new file mode 100644 index 000000000..874936dd8 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/components/client-commands/ValidatorState.vue @@ -0,0 +1,82 @@ + + + diff --git a/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/BlockEpoch.vue b/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/BlockEpoch.vue new file mode 100644 index 000000000..527b5c4fe --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/BlockEpoch.vue @@ -0,0 +1,23 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/CommitteeEpoch.vue b/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/CommitteeEpoch.vue new file mode 100644 index 000000000..c97243890 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/CommitteeEpoch.vue @@ -0,0 +1,23 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/DutyBody.vue b/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/DutyBody.vue new file mode 100644 index 000000000..4b40f7099 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/DutyBody.vue @@ -0,0 +1,20 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/DutyFooter.vue b/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/DutyFooter.vue new file mode 100644 index 000000000..df2515608 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/DutyFooter.vue @@ -0,0 +1,15 @@ + + + diff --git a/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/DutyHeader.vue b/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/DutyHeader.vue new file mode 100644 index 000000000..60729fc26 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/DutyHeader.vue @@ -0,0 +1,27 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/TheEpoch.vue b/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/TheEpoch.vue new file mode 100644 index 000000000..c18174c7c --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/components/epoch-duty/TheEpoch.vue @@ -0,0 +1,23 @@ +import { computed } from 'vue'; + + diff --git a/launcher/src/components/UI/staking-page/components/management/components/val-rewards/AttestationReward.vue b/launcher/src/components/UI/staking-page/components/management/components/val-rewards/AttestationReward.vue new file mode 100644 index 000000000..7c5f066b0 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/components/val-rewards/AttestationReward.vue @@ -0,0 +1,52 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/management/components/val-rewards/BlockReward.vue b/launcher/src/components/UI/staking-page/components/management/components/val-rewards/BlockReward.vue new file mode 100644 index 000000000..3f9deb598 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/components/val-rewards/BlockReward.vue @@ -0,0 +1,49 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/management/components/val-rewards/CommitteeReward.vue b/launcher/src/components/UI/staking-page/components/management/components/val-rewards/CommitteeReward.vue new file mode 100644 index 000000000..954564890 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/components/val-rewards/CommitteeReward.vue @@ -0,0 +1,53 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/management/components/val-rewards/EpochSlot.vue b/launcher/src/components/UI/staking-page/components/management/components/val-rewards/EpochSlot.vue new file mode 100644 index 000000000..3fa088c68 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/components/val-rewards/EpochSlot.vue @@ -0,0 +1,31 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/management/components/val-rewards/TotalBalance.vue b/launcher/src/components/UI/staking-page/components/management/components/val-rewards/TotalBalance.vue new file mode 100644 index 000000000..884785c2b --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/management/components/val-rewards/TotalBalance.vue @@ -0,0 +1,40 @@ + + + diff --git a/launcher/src/components/UI/staking-page/components/modals/ImportRemote.vue b/launcher/src/components/UI/staking-page/components/modals/ImportRemote.vue new file mode 100644 index 000000000..e1b6cf7e3 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/modals/ImportRemote.vue @@ -0,0 +1,97 @@ + + + diff --git a/launcher/src/components/UI/staking-page/components/modals/ImportValidator.vue b/launcher/src/components/UI/staking-page/components/modals/ImportValidator.vue new file mode 100644 index 000000000..ac2f8c30e --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/modals/ImportValidator.vue @@ -0,0 +1,258 @@ + + + diff --git a/launcher/src/components/UI/staking-page/components/modals/RemoveGroup.vue b/launcher/src/components/UI/staking-page/components/modals/RemoveGroup.vue new file mode 100644 index 000000000..710192767 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/modals/RemoveGroup.vue @@ -0,0 +1,52 @@ + + + diff --git a/launcher/src/components/UI/staking-page/components/modals/RemoveValidators.vue b/launcher/src/components/UI/staking-page/components/modals/RemoveValidators.vue new file mode 100644 index 000000000..8a612702d --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/modals/RemoveValidators.vue @@ -0,0 +1,150 @@ + + + diff --git a/launcher/src/components/UI/staking-page/components/modals/RiskWarning.vue b/launcher/src/components/UI/staking-page/components/modals/RiskWarning.vue new file mode 100644 index 000000000..1a3e88fc0 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/modals/RiskWarning.vue @@ -0,0 +1,56 @@ + + diff --git a/launcher/src/components/UI/staking-page/components/modals/SlashingDBModal.vue b/launcher/src/components/UI/staking-page/components/modals/SlashingDBModal.vue new file mode 100644 index 000000000..f83fd1f15 --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/modals/SlashingDBModal.vue @@ -0,0 +1,5 @@ + diff --git a/launcher/src/components/UI/staking-page/components/modals/StakingCustomModal.vue b/launcher/src/components/UI/staking-page/components/modals/StakingCustomModal.vue new file mode 100644 index 000000000..a0a5eb54b --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/modals/StakingCustomModal.vue @@ -0,0 +1,195 @@ +import { useNodeManage } from '@/store/nodeManage'; import { computed } from 'vue'; + + + + diff --git a/launcher/src/components/UI/staking-page/components/modals/WithdrawMultiple.vue b/launcher/src/components/UI/staking-page/components/modals/WithdrawMultiple.vue new file mode 100644 index 000000000..a44350e2d --- /dev/null +++ b/launcher/src/components/UI/staking-page/components/modals/WithdrawMultiple.vue @@ -0,0 +1,187 @@ + + + diff --git a/launcher/src/components/UI/staking-page/sections/DisabledSection.vue b/launcher/src/components/UI/staking-page/sections/DisabledSection.vue new file mode 100644 index 000000000..6070e9e9a --- /dev/null +++ b/launcher/src/components/UI/staking-page/sections/DisabledSection.vue @@ -0,0 +1,38 @@ + + + diff --git a/launcher/src/components/UI/staking-page/sections/ListSection.vue b/launcher/src/components/UI/staking-page/sections/ListSection.vue new file mode 100644 index 000000000..15938e729 --- /dev/null +++ b/launcher/src/components/UI/staking-page/sections/ListSection.vue @@ -0,0 +1,126 @@ + + diff --git a/launcher/src/components/UI/staking-page/sections/ManagementSection.vue b/launcher/src/components/UI/staking-page/sections/ManagementSection.vue new file mode 100644 index 000000000..a19e81dd9 --- /dev/null +++ b/launcher/src/components/UI/staking-page/sections/ManagementSection.vue @@ -0,0 +1,31 @@ + + + diff --git a/launcher/src/components/UI/staking-page/sections/SidebarSection.vue b/launcher/src/components/UI/staking-page/sections/SidebarSection.vue new file mode 100644 index 000000000..7b0f8b658 --- /dev/null +++ b/launcher/src/components/UI/staking-page/sections/SidebarSection.vue @@ -0,0 +1,93 @@ + + diff --git a/launcher/src/components/UI/task-manager/SubTasks.vue b/launcher/src/components/UI/task-manager/SubTasks.vue index 847bc0832..e9fee3601 100755 --- a/launcher/src/components/UI/task-manager/SubTasks.vue +++ b/launcher/src/components/UI/task-manager/SubTasks.vue @@ -63,7 +63,8 @@ export default { props: { subTasks: { type: Array, - required: true, + required: false, + default: () => [], }, }, data() { diff --git a/launcher/src/components/UI/the-control/ControlAlert.vue b/launcher/src/components/UI/the-control/ControlAlert.vue index b818d1832..714ae3704 100755 --- a/launcher/src/components/UI/the-control/ControlAlert.vue +++ b/launcher/src/components/UI/the-control/ControlAlert.vue @@ -102,13 +102,6 @@ > {{ validator.name }} vc
    -
    import ControlService from "@/store/ControlService"; -import TheExpert from "../the-node/TheExpert.vue"; + import { useControlStore } from "@/store/theControl"; import { mapWritableState } from "pinia"; import { useNodeHeader } from "@/store/nodeHeader"; import { useServices } from "@/store/services"; import { useFooter } from "@/store/theFooter"; export default { - components: { - TheExpert, - }, data() { return { storageWarning: false, diff --git a/launcher/src/components/UI/the-control/ControlScreen.vue b/launcher/src/components/UI/the-control/ControlScreen.vue index 0bfcfeffb..facf8cee4 100644 --- a/launcher/src/components/UI/the-control/ControlScreen.vue +++ b/launcher/src/components/UI/the-control/ControlScreen.vue @@ -96,7 +96,7 @@
    -
    +
    diff --git a/launcher/src/components/UI/the-control/DiskSpeed.vue b/launcher/src/components/UI/the-control/DiskSpeed.vue index 20188a611..87b4eae04 100755 --- a/launcher/src/components/UI/the-control/DiskSpeed.vue +++ b/launcher/src/components/UI/the-control/DiskSpeed.vue @@ -8,20 +8,54 @@ {{ $t("controlPage.disk") }}
    -
    +
    {{ $t("controlPage.write") }}
    - {{ convertWriteValueToMb }} Mb + {{ convertWriteValueToMb }} + {{ + controlStore.writeValue / 1024 < 1 && controlStore.writeValue / 1024 > 0 + ? "KB" + : "MB" + }}
    -
    +
    {{ $t("controlPage.read") }}
    - {{ convertReadValueToMb }} Mb + {{ convertReadValueToMb }} + {{ + controlStore.readValue / 1024 < 1 && controlStore.writeValue / 1024 > 0 + ? "KB" + : "MB" + }}
    @@ -32,18 +66,26 @@ diff --git a/launcher/src/components/UI/the-node/ResyncSeparateServices.vue b/launcher/src/components/UI/the-node/ResyncSeparateServices.vue index fc1976764..91134361d 100755 --- a/launcher/src/components/UI/the-node/ResyncSeparateServices.vue +++ b/launcher/src/components/UI/the-node/ResyncSeparateServices.vue @@ -2,7 +2,9 @@
    -
    +
    + +
    {{ $t("resyncSeparateService.message") }} @@ -62,8 +64,12 @@
    -
    {{ selectedItem }}
    -
    {{ selectedItem }}
    +
    + {{ selectedItem }} +
    +
    + {{ selectedItem }} +
    Internet
    @@ -136,7 +142,7 @@ export default { ...mapWritableState(useClickInstall, { syncType: "syncType", mainnet: "mainnet", - georli: "georli", + goerli: "goerli", sepolia: "sepolia", gnosis: "gnosis", }), @@ -207,7 +213,7 @@ export default { this.selectedLinks = this.mainnet; break; case 2: - this.selectedLinks = this.georli; + this.selectedLinks = this.goerli; break; case 3: this.selectedLinks = this.sepolia; @@ -215,6 +221,9 @@ export default { case 4: this.selectedLinks = this.gnosis; break; + case 5: + this.selectedLinks = this.holesky; + break; default: break; } diff --git a/launcher/src/components/base/BaseLayout.vue b/launcher/src/components/base/BaseLayout.vue index 202b1a596..9fd24f64e 100755 --- a/launcher/src/components/base/BaseLayout.vue +++ b/launcher/src/components/base/BaseLayout.vue @@ -1,6 +1,6 @@ diff --git a/launcher/src/store/ControlService.js b/launcher/src/store/ControlService.js index a2694a0e1..878cca987 100755 --- a/launcher/src/store/ControlService.js +++ b/launcher/src/store/ControlService.js @@ -206,11 +206,8 @@ class ControlService extends EventEmitter { return await this.promiseIpc.send("deleteValidators", args); } - async listValidators(serviceID, numRunningValidatorService) { - return await this.promiseIpc.send("listValidators", { - serviceID: serviceID, - numRunningValidatorService: numRunningValidatorService, - }); + async listValidators(args) { + return await this.promiseIpc.send("listValidators", args); } async listServices() { @@ -407,7 +404,6 @@ class ControlService extends EventEmitter { async exitValidatorAccount(args) { return await this.promiseIpc.send("exitValidatorAccount", { pubkey: args.pubkey, - password: args.password, serviceID: args.serviceID, }); } @@ -462,6 +458,24 @@ class ControlService extends EventEmitter { async dumpDockerLogs() { return await this.promiseIpc.send("dumpDockerLogs"); } + async getCurrentEpochandSlot() { + return await this.promiseIpc.send("getCurrentEpochandSlot"); + } + async getValidatorDuties(args) { + return await this.promiseIpc.send("getValidatorDuties", args); + } + + async getAttestationRewards(args) { + return await this.promiseIpc.send("getAttestationRewards", args); + } + + async getBlockRewards(args) { + return await this.promiseIpc.send("getBlockRewards", args); + } + + async getSyncCommitteeRewards(validators, slot) { + return await this.promiseIpc.send("getSyncCommitteeRewards", { validators, slot }); + } } if (!instance) { instance = new ControlService(window.electron); diff --git a/launcher/src/store/clickInstallation.js b/launcher/src/store/clickInstallation.js index 6e77605bd..d81207b52 100755 --- a/launcher/src/store/clickInstallation.js +++ b/launcher/src/store/clickInstallation.js @@ -3,9 +3,9 @@ import { defineStore } from "pinia"; export const useClickInstall = defineStore("clickInstallation", { state: () => { return { + startServicesAfterInstall: false, isConfigButtonEnbabled: false, installMonitoring: false, - startServicesAfterInstall: true, relayURL: "", checkPointSync: "", currentSlide: 0, @@ -186,7 +186,7 @@ export const useClickInstall = defineStore("clickInstallation", { url: "https://beaconstate.info/", }, ], - georli: [ + goerli: [ { id: 1, name: "Sigma Prime", @@ -289,12 +289,6 @@ export const useClickInstall = defineStore("clickInstallation", { icon: "/img/icon/service-icons/ef-devops.png", url: "https://checkpoint-sync.holesky.ethpandaops.io", }, - { - id: 4, - name: "Flashbots", - icon: "/img/icon/click-installation/flashbot-icon.png", - url: "https://boost-relay-holesky.flashbots.net/", - }, ], }; }, diff --git a/launcher/src/store/nodeHeader.js b/launcher/src/store/nodeHeader.js index 2f7670147..81f0b4362 100755 --- a/launcher/src/store/nodeHeader.js +++ b/launcher/src/store/nodeHeader.js @@ -2,6 +2,10 @@ import { defineStore } from "pinia"; export const useNodeHeader = defineStore("nodeHeader", { state: () => { return { + importBoxModel: "", + passwordBoxModel: "", + selectedValidatorFromNodeAlert: {}, + openModalFromNodeAlert: false, depositFile: false, enrIsGenerating: true, generatedENR: "", diff --git a/launcher/src/store/nodeManage.js b/launcher/src/store/nodeManage.js index 470f384f1..0a384c3bd 100755 --- a/launcher/src/store/nodeManage.js +++ b/launcher/src/store/nodeManage.js @@ -31,6 +31,8 @@ export const useNodeManage = defineStore("nodeManage", { "https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@boost-relay-goerli.flashbots.net", sepolia: "https://0x845bd072b7cd566f02faeb0a4033ce9399e42839ced64e8b2adcfc859ed1e8e1a5a293336a49feac6d9a5edb779be53a@boost-relay-sepolia.flashbots.net", + holesky: + "https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@boost-relay-holesky.flashbots.net", id: 1, isSelected: false, isRemoved: false, @@ -189,7 +191,7 @@ export const useNodeManage = defineStore("nodeManage", { icon: "/img/icon/click-installation/testnet-icon.png", currencyIcon: "/img/icon/control/goETH_Currency_Symbol.png", dataEndpoint: "https://sepolia.beaconcha.in/api/v1", - support: ["staking", "mev boost", "stereum on arm"], + support: ["staking", "mev boost", "stereum on arm", "archive"], }, { id: 4, @@ -198,7 +200,7 @@ export const useNodeManage = defineStore("nodeManage", { icon: "/img/icon/click-installation/gnosis_mainnet_icon.png", currencyIcon: "/img/icon/control/gno_currency_symbol.png", dataEndpoint: "https://beacon.gnosischain.com/api/v1", - support: ["staking", "stereum on arm"], + support: ["staking", "stereum on arm", "archive"], }, { id: 5, @@ -207,7 +209,7 @@ export const useNodeManage = defineStore("nodeManage", { icon: "/img/icon/click-installation/testnet-icon.png", currencyIcon: "/img/icon/control/goETH_Currency_Symbol.png", dataEndpoint: "https://holesky.beaconcha.in/api/v1", - support: ["staking", "ssv.network", "stereum on arm", "mev boost"], + support: ["staking", "ssv.network", "stereum on arm", "mev boost", "archive", "obol"], }, ], currentNetwork: {}, diff --git a/launcher/src/store/theNode.js b/launcher/src/store/theNode.js index 7daee5166..aa1aa142b 100755 --- a/launcher/src/store/theNode.js +++ b/launcher/src/store/theNode.js @@ -10,6 +10,9 @@ export const useNodeStore = defineStore("theNode", { lineThree: null, infoAlarm: true, runNodePowerModal: false, + clientToLogs: null, + logs: [], + searchLogs: "", serviceLogs: [], consensusItems: [], executionItems: [], diff --git a/launcher/src/store/theStaking.js b/launcher/src/store/theStaking.js index 274543e9c..8f2a34728 100755 --- a/launcher/src/store/theStaking.js +++ b/launcher/src/store/theStaking.js @@ -3,6 +3,69 @@ import { defineStore } from "pinia"; export const useStakingStore = defineStore("theStaking", { state: () => { return { + currentEpoch: 0, + currentSlot: 0, + secondsPerSlot: null, + slotsPerEpoch: null, + // ***** Staking List + selectedServiceToFilter: null, + filteredKeys: null, + searchedKeys: [], + activePanel: "insert", + searchContent: "", + isOverDropZone: false, + inputWrongKey: false, + isPreviewListActive: false, + importEnteredPassword: null, + importKeyMessage: "", + checkActiveValidatorsResponse: [], + previewKeys: [], + keyNumbers: 0, + //***** End Staking List + + // ***** Staking Modals ***** + activeModal: null, + // ***** End Staking Modals ***** + + // ***** Staking Groups ***** + mode: "create", + groupName: null, + currentGroup: null, + isGroupListActive: false, + isGroupingAllowed: false, + validatorKeyGroups: [], + filteredGroups: [], + selectedGroup: null, + selectedValidatorKeys: [], + // ***** End Staking Groups ***** + + // ***** Staking Remote Keys ***** + isRemoteListActive: false, + previewRemoteKeys: [], // Remote Keys List to display + remoteKeys: [], // Remote Keys List + remoteUrl: "", + remoteResponse: null, + remoteResponseMessage: null, + + // ***** End Staking Remote Keys ***** + + // ***** Validator Keys ***** + isPubkeyVisible: false, + removeResponse: [], + removeKeys: [], + pickedSlashing: "no", + slashingDB: "", // Slashing DB + selectedKeyToRemove: null, + selectKeyToRename: null, + selectKeyForFee: null, + validatorDisplayName: "", + enteredFeeRecipientAddress: "", + feeRecepientAddress: "", + // ***** End Validator Keys ***** + selectedSingleKeyToWithdraw: null, + withdrawAndExitResponse: null, + withdrawIsChecked: false, + exitMultiValidatorKeys: false, doppelgangerStatus: true, selectedIcon: "", @@ -18,9 +81,6 @@ export const useStakingStore = defineStore("theStaking", { insertKeyBoxActive: true, enterPasswordBox: false, importRemoteKeysActive: false, - exitChainForMultiValidatorsActive: false, - removeForMultiValidatorsActive: false, - grafitiForMultiValidatorsActive: false, display: true, isDragOver: false, keyFiles: [], @@ -31,5 +91,18 @@ export const useStakingStore = defineStore("theStaking", { keyCounter: 0, }; }, - actions: {}, + actions: { + setActivePanel(panelName) { + this.activePanel = panelName; + }, + setActiveModal(modalName) { + this.activeModal = modalName; + }, + setMode(mode) { + this.mode = mode; + }, + setValidatorName(newName) { + this.validatorDisplayName = newName; + }, + }, }); diff --git a/launcher/tailwind.config.js b/launcher/tailwind.config.js index aab927cfc..1a09aba39 100755 --- a/launcher/tailwind.config.js +++ b/launcher/tailwind.config.js @@ -5,6 +5,9 @@ module.exports = { backgroundImage: { drop: "url('/img/icon/manage-node-icons/drag.png')", }, + fontSize: { + "2xs": "10px", + }, gridTemplateRows: { 7: "repeat(7 , minmax(0,1fr))", 8: "repeat(8 , minmax(0,1fr))",