diff --git a/.github/update.log b/.github/update.log index d2b3b90870..3b3bffbd72 100644 --- a/.github/update.log +++ b/.github/update.log @@ -631,3 +631,4 @@ Update On Thu Apr 25 20:28:01 CEST 2024 Update On Fri Apr 26 20:27:45 CEST 2024 Update On Sat Apr 27 20:27:55 CEST 2024 Update On Sun Apr 28 20:28:07 CEST 2024 +Update On Mon Apr 29 20:27:31 CEST 2024 diff --git a/clash-meta/go.mod b/clash-meta/go.mod index 01d670323b..dad18d9e87 100644 --- a/clash-meta/go.mod +++ b/clash-meta/go.mod @@ -20,7 +20,7 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6 - github.com/metacubex/sing-quic v0.0.0-20240428052223-bf4b8b6c1b22 + github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e github.com/metacubex/sing-shadowsocks v0.2.6 github.com/metacubex/sing-shadowsocks2 v0.2.0 github.com/metacubex/sing-tun v0.2.6 diff --git a/clash-meta/go.sum b/clash-meta/go.sum index c250677cc7..8c4836b2b9 100644 --- a/clash-meta/go.sum +++ b/clash-meta/go.sum @@ -108,8 +108,8 @@ github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6 h1:qqIZ8CjoxV github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6/go.mod h1:uXHODgJFUfUnkkCMWLd5Er6L5QY/LFRZb9LD5jyyhsk= github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764 h1:+czGKoynxYA90YaL3NlCAIJHnlqwoUlLWgmOhdm5ZU8= github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= -github.com/metacubex/sing-quic v0.0.0-20240428052223-bf4b8b6c1b22 h1:LPiTgdUBxOeQqDmHn/W2gDb5W2C+JPWOf/mkRl9nfCM= -github.com/metacubex/sing-quic v0.0.0-20240428052223-bf4b8b6c1b22/go.mod h1:nfqibK+vkBtE6Ch8vYqrFTcaX4BC6TwKqNNl5rORll4= +github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e h1:UW+yfzoLzjEhAoJ6A4mVnov3Aergi7uFM/h7ReNekKI= +github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e/go.mod h1:nfqibK+vkBtE6Ch8vYqrFTcaX4BC6TwKqNNl5rORll4= github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A= diff --git a/clash-nyanpasu/backend/tauri/src/config/nyanpasu/mod.rs b/clash-nyanpasu/backend/tauri/src/config/nyanpasu/mod.rs index 2c3c73f18e..d233eb2fee 100644 --- a/clash-nyanpasu/backend/tauri/src/config/nyanpasu/mod.rs +++ b/clash-nyanpasu/backend/tauri/src/config/nyanpasu/mod.rs @@ -156,7 +156,7 @@ pub struct IVerge { pub verge_mixed_port: Option, /// Check update when app launch - pub disable_auto_check_update: Option, + pub enable_auto_check_update: Option, /// Clash 相关策略 pub clash_strategy: Option, @@ -229,7 +229,7 @@ impl IVerge { page_transition_animation: Some("slide".into()), // auto_log_clean: Some(60 * 24 * 7), // 7 days 自动清理日记 max_log_files: Some(7), // 7 days - disable_auto_check_update: Some(true), + enable_auto_check_update: Some(true), clash_tray_selector: Some(true), ..Self::default() } @@ -258,7 +258,7 @@ impl IVerge { patch!(traffic_graph); patch!(enable_memory_usage); patch!(page_transition_animation); - patch!(disable_auto_check_update); + patch!(enable_auto_check_update); patch!(enable_tun_mode); patch!(enable_service_mode); diff --git a/clash-nyanpasu/frontend/interface/service/types.ts b/clash-nyanpasu/frontend/interface/service/types.ts index 44d7c4d3cd..b79e1ea42e 100644 --- a/clash-nyanpasu/frontend/interface/service/types.ts +++ b/clash-nyanpasu/frontend/interface/service/types.ts @@ -7,7 +7,7 @@ export interface VergeConfig { traffic_graph?: boolean; enable_memory_usage?: boolean; page_transition_animation?: string; - disable_auto_check_update?: boolean; + enable_auto_check_update?: boolean; enable_tun_mode?: boolean; enable_auto_launch?: boolean; enable_service_mode?: boolean; diff --git a/clash-nyanpasu/frontend/nyanpasu/package.json b/clash-nyanpasu/frontend/nyanpasu/package.json index 6af366243e..492e85f7cb 100644 --- a/clash-nyanpasu/frontend/nyanpasu/package.json +++ b/clash-nyanpasu/frontend/nyanpasu/package.json @@ -28,7 +28,7 @@ "axios": "1.6.8", "dayjs": "1.11.11", "framer-motion": "11.1.7", - "i18next": "23.11.2", + "i18next": "23.11.3", "monaco-editor": "0.48.0", "mui-color-input": "2.0.3", "react": "18.3.1", diff --git a/clash-nyanpasu/frontend/nyanpasu/postcss.config.js b/clash-nyanpasu/frontend/nyanpasu/postcss.config.js index bb979c7b40..22b100266a 100644 --- a/clash-nyanpasu/frontend/nyanpasu/postcss.config.js +++ b/clash-nyanpasu/frontend/nyanpasu/postcss.config.js @@ -4,5 +4,6 @@ export default { "postcss-import": {}, "postcss-html": {}, autoprefixer: {}, + tailwindcss: {}, }, }; diff --git a/clash-nyanpasu/frontend/nyanpasu/src/assets/styles/tailwind.css b/clash-nyanpasu/frontend/nyanpasu/src/assets/styles/tailwind.css new file mode 100644 index 0000000000..b5c61c9567 --- /dev/null +++ b/clash-nyanpasu/frontend/nyanpasu/src/assets/styles/tailwind.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-version.module.scss b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-version.module.scss deleted file mode 100644 index 95c98398cc..0000000000 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-version.module.scss +++ /dev/null @@ -1,6 +0,0 @@ -.LogoBox { - svg { - width: 128px; - height: 128px; - } -} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-version.module.scss.d.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-version.module.scss.d.ts deleted file mode 100644 index 30842a9689..0000000000 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-version.module.scss.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare const classNames: { - readonly LogoBox: "LogoBox"; -}; -export default classNames; diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-version.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-version.tsx index ae173f6efa..6e8d6efe33 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-version.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-version.tsx @@ -10,10 +10,9 @@ import { import { BaseCard } from "@nyanpasu/ui"; import { useTranslation } from "react-i18next"; import LogoSvg from "@/assets/image/logo.svg?react"; -import style from "./setting-nyanpasu-version.module.scss"; import { version } from "~/package.json"; -import { LoadingButton } from "@mui/lab"; -import { useState } from "react"; +import LoadingButton from "@mui/lab/LoadingButton"; +import { useEffect, useState } from "react"; import { useLockFn } from "ahooks"; import { checkUpdate } from "@tauri-apps/api/updater"; import { useMessage } from "@/hooks/use-notification"; @@ -77,10 +76,9 @@ export const SettingNyanpasuVersion = () => { display="flex" flexDirection="column" alignItems="center" - className={style.LogoBox} gap={2} > - + {"Clash Nyanpasu~(∠・ω< )⌒☆"}​ @@ -96,11 +94,11 @@ export const SettingNyanpasuVersion = () => { setNyanpasuConfig({ - disable_auto_check_update: - nyanpasuConfig?.disable_auto_check_update, + enable_auto_check_update: + !nyanpasuConfig?.enable_auto_check_update, }) } /> diff --git a/clash-nyanpasu/frontend/nyanpasu/tailwind.config.js b/clash-nyanpasu/frontend/nyanpasu/tailwind.config.js new file mode 100644 index 0000000000..43a0227238 --- /dev/null +++ b/clash-nyanpasu/frontend/nyanpasu/tailwind.config.js @@ -0,0 +1,8 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ["./src/**/*.{tsx,ts}"], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/clash-nyanpasu/frontend/ui/materialYou/components/basePage/style.scss b/clash-nyanpasu/frontend/ui/materialYou/components/basePage/style.scss index ea132bfe2e..38bc1f46e1 100644 --- a/clash-nyanpasu/frontend/ui/materialYou/components/basePage/style.scss +++ b/clash-nyanpasu/frontend/ui/materialYou/components/basePage/style.scss @@ -30,7 +30,7 @@ scrollbar-gutter: stable; .MDYBasePage-content { - width: calc(100% - 28px * 2); + width: 100%; padding: 28px; margin: 0 auto; } @@ -41,7 +41,6 @@ overflow: visible; .MDYBasePage-content { - width: 100%; padding: 0; } } diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json index 3f6aa86f72..f697998069 100644 --- a/clash-nyanpasu/manifest/version.json +++ b/clash-nyanpasu/manifest/version.json @@ -2,7 +2,7 @@ "manifest_version": 1, "latest": { "mihomo": "v1.18.3", - "mihomo_alpha": "alpha-df01582", + "mihomo_alpha": "alpha-89a097f", "clash_rs": "v0.1.16", "clash_premium": "2023-09-05-gdcc8d87" }, @@ -36,5 +36,5 @@ "darwin-x64": "clash-darwin-amd64-n{}.gz" } }, - "updated_at": "2024-04-26T22:20:14.781Z" + "updated_at": "2024-04-28T22:19:19.364Z" } diff --git a/clash-nyanpasu/package.json b/clash-nyanpasu/package.json index 90de13e783..8de902955d 100644 --- a/clash-nyanpasu/package.json +++ b/clash-nyanpasu/package.json @@ -98,6 +98,7 @@ "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-order": "6.0.4", "stylelint-scss": "6.2.1", + "tailwindcss": "3.4.3", "tsx": "4.7.3", "typescript": "5.4.5" }, diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml index 5bd29c062d..9eb1505e64 100644 --- a/clash-nyanpasu/pnpm-lock.yaml +++ b/clash-nyanpasu/pnpm-lock.yaml @@ -123,6 +123,9 @@ importers: stylelint-scss: specifier: 6.2.1 version: 6.2.1(stylelint@16.4.0(typescript@5.4.5)) + tailwindcss: + specifier: 3.4.3 + version: 3.4.3 tsx: specifier: 4.7.3 version: 4.7.3 @@ -202,8 +205,8 @@ importers: specifier: 11.1.7 version: 11.1.7(@emotion/is-prop-valid@1.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) i18next: - specifier: 23.11.2 - version: 23.11.2 + specifier: 23.11.3 + version: 23.11.3 monaco-editor: specifier: 0.48.0 version: 0.48.0 @@ -227,7 +230,7 @@ importers: version: 7.51.3(react@18.3.1) react-i18next: specifier: 14.1.1 - version: 14.1.1(i18next@23.11.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.1.1(i18next@23.11.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-markdown: specifier: 9.0.1 version: 9.0.1(@types/react@18.3.1)(react@18.3.1) @@ -372,6 +375,10 @@ packages: '@adobe/css-tools@4.3.3': resolution: {integrity: sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==} + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -956,20 +963,20 @@ packages: resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} - '@floating-ui/core@1.6.0': - resolution: {integrity: sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==} + '@floating-ui/core@1.6.1': + resolution: {integrity: sha512-42UH54oPZHPdRHdw6BgoBD6cg/eVTmVrFcgeRDM3jbO7uxSoipVcmcIGFcA5jmOHO5apcyvBhkSKES3fQJnu7A==} - '@floating-ui/dom@1.6.3': - resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==} + '@floating-ui/dom@1.6.4': + resolution: {integrity: sha512-0G8R+zOvQsAG1pg2Q99P21jiqxqGBW1iRe/iXHsBRBxnpXKFI8QwbB4x5KmYLggNO5m34IQgOIu9SCRfR/WWiQ==} - '@floating-ui/react-dom@2.0.8': - resolution: {integrity: sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==} + '@floating-ui/react-dom@2.0.9': + resolution: {integrity: sha512-q0umO0+LQK4+p6aGyvzASqKbKOJcAHJ7ycE9CuUvfx3s9zTHWmGJTPOIlM/hmSBfUfg/XfY5YhLBLR/LHwShQQ==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' - '@floating-ui/utils@0.2.1': - resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} + '@floating-ui/utils@0.2.2': + resolution: {integrity: sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==} '@generouted/react-router@1.19.3': resolution: {integrity: sha512-3/Y0j302HnwxyU0KOoCOFSVwJZN4eD73+CVtSaOKUnLbGW1ftP1dT8Eur14PALGvZOVR4gsFrUJFq6a4c/kWvQ==} @@ -989,6 +996,10 @@ packages: '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} @@ -1198,6 +1209,10 @@ packages: '@octokit/types@13.4.1': resolution: {integrity: sha512-Y73oOAzRBAUzR/iRAbGULzpNkX8vaxKCqEtg6K74Ff3w9f5apFnWtE/2nade7dMWWW3bS5Kkd6DJS4HF04xreg==} + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@pkgr/core@0.1.1': resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -1666,10 +1681,16 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -1802,8 +1823,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001613: - resolution: {integrity: sha512-BNjJULJfOONQERivfxte7alLfeLW4QnwHvNW4wEcLEbXfV6VSCYvr+REbf2Sojv8tC1THpjPXBxWgDbq4NtLWg==} + caniuse-lite@1.0.30001614: + resolution: {integrity: sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1888,6 +1909,10 @@ packages: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} @@ -2054,10 +2079,16 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -2093,6 +2124,9 @@ packages: resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + electron-to-chromium@1.4.750: resolution: {integrity: sha512-9ItEpeu15hW5m8jKdriL+BQrgwDTXEL9pn4SkillWFu73ZNNNQ2BKKLS+ZHv2vC9UkNhosAeyfxOf/5OSeTCPA==} @@ -2102,6 +2136,9 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -2399,6 +2436,10 @@ packages: for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + form-data@4.0.0: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} @@ -2491,6 +2532,11 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob@10.3.12: + resolution: {integrity: sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} @@ -2608,8 +2654,8 @@ packages: engines: {node: '>=18'} hasBin: true - i18next@23.11.2: - resolution: {integrity: sha512-qMBm7+qT8jdpmmDw/kQD16VpmkL9BdL+XNAK5MNbNFaf1iQQq35ZbPrSlqmnNPOSUY4m342+c0t0evinF5l7sA==} + i18next@23.11.3: + resolution: {integrity: sha512-Pq/aSKowir7JM0rj+Wa23Kb6KKDUGno/HjG+wRQu0PxoTbpQ4N89MAT0rFGvXmLkRLNMb1BbBOKGozl01dabzg==} iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} @@ -2834,6 +2880,10 @@ packages: iterator.prototype@1.1.2: resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + jiti@1.21.0: resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} hasBin: true @@ -2995,6 +3045,10 @@ packages: lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + lru-cache@10.2.2: + resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} + engines: {node: 14 || >=16.14} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -3153,6 +3207,10 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.0.4: + resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} + engines: {node: '>=16 || 14 >=14.17'} + monaco-editor@0.48.0: resolution: {integrity: sha512-goSDElNqFfw7iDHMg8WDATkfcyeLTNpBHQpO8incK6p5qZt5G/1j41X0xdGzpIkGojGXM+QiRQyLjnfDVvrpwA==} @@ -3179,6 +3237,9 @@ packages: '@types/react': optional: true + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -3243,6 +3304,10 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} @@ -3350,6 +3415,10 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.10.2: + resolution: {integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==} + engines: {node: '>=16 || 14 >=14.17'} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -3374,6 +3443,10 @@ packages: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} @@ -3382,6 +3455,12 @@ packages: resolution: {integrity: sha512-OWgQ9/Pe23MnNJC0PL4uZp8k0EDaUvqpJFSiwFxOLClAhmD7UEisyhO3x5hVsD4xFrjReVTXydlrMes45dJ71w==} engines: {node: ^12 || >=14} + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + postcss-import@16.1.0: resolution: {integrity: sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==} engines: {node: '>=18.0.0'} @@ -3406,6 +3485,18 @@ packages: ts-node: optional: true + postcss-load-config@4.0.2: + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + postcss-media-query-parser@0.2.3: resolution: {integrity: sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==} @@ -3427,6 +3518,12 @@ packages: peerDependencies: postcss: ^8.1.0 + postcss-nested@6.0.1: + resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + postcss-resolve-nested-selector@0.1.1: resolution: {integrity: sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==} @@ -3814,6 +3911,10 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + string-width@7.1.0: resolution: {integrity: sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==} engines: {node: '>=18'} @@ -3912,6 +4013,11 @@ packages: resolution: {integrity: sha512-v3YCf31atbwJQIMtPNX8hcQ+okD4NQaTuKGUWfII8eaqn+3otrbttGL1zSMZAAtiPsBztQnujVBugg/cXFUpyg==} hasBin: true + sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -3947,6 +4053,11 @@ packages: resolution: {integrity: sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==} engines: {node: '>=10.0.0'} + tailwindcss@3.4.3: + resolution: {integrity: sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==} + engines: {node: '>=14.0.0'} + hasBin: true + telegraf@4.16.3: resolution: {integrity: sha512-yjEu2NwkHlXu0OARWoNhJlIjX09dRktiMQFsM678BAH/PEPVwctzL67+tvXqLCRQQvm3SDtki2saGO9hLlz68w==} engines: {node: ^12.20.0 || >=14.13.1} @@ -3959,6 +4070,13 @@ packages: text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} @@ -3985,6 +4103,9 @@ packages: peerDependencies: typescript: '>=4.2.0' + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tsconfck@3.0.3: resolution: {integrity: sha512-4t0noZX9t6GcPTfBAbIbbIU4pfpCwh0ueq3S4O/5qXI1VwK1outmxhe9dOiEWqMz3MW2LKgDTpqWV+37IWuVbA==} engines: {node: ^18 || >=20} @@ -4217,6 +4338,10 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + wrap-ansi@9.0.0: resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} engines: {node: '>=18'} @@ -4281,6 +4406,8 @@ snapshots: '@adobe/css-tools@4.3.3': {} + '@alloc/quick-lru@5.2.0': {} + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.5 @@ -4823,22 +4950,22 @@ snapshots: '@fastify/busboy@2.1.1': {} - '@floating-ui/core@1.6.0': + '@floating-ui/core@1.6.1': dependencies: - '@floating-ui/utils': 0.2.1 + '@floating-ui/utils': 0.2.2 - '@floating-ui/dom@1.6.3': + '@floating-ui/dom@1.6.4': dependencies: - '@floating-ui/core': 1.6.0 - '@floating-ui/utils': 0.2.1 + '@floating-ui/core': 1.6.1 + '@floating-ui/utils': 0.2.2 - '@floating-ui/react-dom@2.0.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@floating-ui/react-dom@2.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@floating-ui/dom': 1.6.3 + '@floating-ui/dom': 1.6.4 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@floating-ui/utils@0.2.1': {} + '@floating-ui/utils@0.2.2': {} '@generouted/react-router@1.19.3(react-router-dom@6.23.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(stylus@0.62.0))': dependencies: @@ -4860,6 +4987,15 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 @@ -4884,7 +5020,7 @@ snapshots: '@mui/base@5.0.0-beta.40(@types/react@18.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.24.4 - '@floating-ui/react-dom': 2.0.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@floating-ui/react-dom': 2.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mui/types': 7.2.14(@types/react@18.3.1) '@mui/utils': 5.15.14(@types/react@18.3.1)(react@18.3.1) '@popperjs/core': 2.11.8 @@ -5079,6 +5215,9 @@ snapshots: dependencies: '@octokit/openapi-types': 22.1.0 + '@pkgjs/parseargs@0.11.0': + optional: true + '@pkgr/core@0.1.1': {} '@popperjs/core@2.11.8': {} @@ -5536,11 +5675,15 @@ snapshots: ansi-styles@6.2.1: {} + any-promise@1.3.0: {} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 + arg@5.0.2: {} + argparse@2.0.1: {} array-buffer-byte-length@1.0.1: @@ -5626,7 +5769,7 @@ snapshots: autoprefixer@10.4.19(postcss@8.4.38): dependencies: browserslist: 4.23.0 - caniuse-lite: 1.0.30001613 + caniuse-lite: 1.0.30001614 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.0.0 @@ -5676,7 +5819,7 @@ snapshots: browserslist@4.23.0: dependencies: - caniuse-lite: 1.0.30001613 + caniuse-lite: 1.0.30001614 electron-to-chromium: 1.4.750 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.23.0) @@ -5710,7 +5853,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001613: {} + caniuse-lite@1.0.30001614: {} ccount@2.0.1: {} @@ -5792,6 +5935,8 @@ snapshots: commander@11.1.0: {} + commander@4.1.1: {} + compare-func@2.0.0: dependencies: array-ify: 1.0.0 @@ -5944,10 +6089,14 @@ snapshots: dependencies: dequal: 2.0.3 + didyoumean@1.2.2: {} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 + dlv@1.1.3: {} + doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -5990,12 +6139,16 @@ snapshots: dotenv@16.4.5: {} + eastasianwidth@0.2.0: {} + electron-to-chromium@1.4.750: {} emoji-regex@10.3.0: {} emoji-regex@8.0.0: {} + emoji-regex@9.2.2: {} + entities@4.5.0: {} env-paths@2.2.1: {} @@ -6443,6 +6596,11 @@ snapshots: dependencies: is-callable: 1.2.7 + foreground-child@3.1.1: + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + form-data@4.0.0: dependencies: asynckit: 0.4.0 @@ -6529,6 +6687,14 @@ snapshots: dependencies: is-glob: 4.0.3 + glob@10.3.12: + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.4 + minipass: 7.0.4 + path-scurry: 1.10.2 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -6668,7 +6834,7 @@ snapshots: husky@9.0.11: {} - i18next@23.11.2: + i18next@23.11.3: dependencies: '@babel/runtime': 7.24.4 @@ -6865,6 +7031,12 @@ snapshots: reflect.getprototypeof: 1.0.6 set-function-name: 2.0.2 + jackspeak@2.3.6: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + jiti@1.21.0: {} js-cookie@2.2.1: {} @@ -7021,6 +7193,8 @@ snapshots: dependencies: tslib: 2.6.2 + lru-cache@10.2.2: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -7299,6 +7473,8 @@ snapshots: minimist@1.2.8: {} + minipass@7.0.4: {} + monaco-editor@0.48.0: {} mri@1.2.0: {} @@ -7318,6 +7494,12 @@ snapshots: optionalDependencies: '@types/react': 18.3.1 + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + nanoid@3.3.7: {} natural-compare@1.4.0: {} @@ -7371,6 +7553,8 @@ snapshots: object-assign@4.1.1: {} + object-hash@3.0.0: {} + object-inspect@1.13.1: {} object-keys@1.1.1: {} @@ -7494,6 +7678,11 @@ snapshots: path-parse@1.0.7: {} + path-scurry@1.10.2: + dependencies: + lru-cache: 10.2.2 + minipass: 7.0.4 + path-type@4.0.0: {} picocolors@1.0.0: {} @@ -7507,6 +7696,8 @@ snapshots: pify@4.0.1: optional: true + pirates@4.0.6: {} + possible-typed-array-names@1.0.0: {} postcss-html@1.6.0: @@ -7516,6 +7707,13 @@ snapshots: postcss: 8.4.38 postcss-safe-parser: 6.0.0(postcss@8.4.38) + postcss-import@15.1.0(postcss@8.4.38): + dependencies: + postcss: 8.4.38 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + postcss-import@16.1.0(postcss@8.4.38): dependencies: postcss: 8.4.38 @@ -7535,6 +7733,13 @@ snapshots: optionalDependencies: postcss: 8.4.38 + postcss-load-config@4.0.2(postcss@8.4.38): + dependencies: + lilconfig: 3.0.0 + yaml: 2.3.4 + optionalDependencies: + postcss: 8.4.38 + postcss-media-query-parser@0.2.3: {} postcss-modules-extract-imports@3.1.0(postcss@8.4.38): @@ -7553,6 +7758,11 @@ snapshots: postcss: 8.4.38 postcss-selector-parser: 6.0.16 + postcss-nested@6.0.1(postcss@8.4.38): + dependencies: + postcss: 8.4.38 + postcss-selector-parser: 6.0.16 + postcss-resolve-nested-selector@0.1.1: {} postcss-safe-parser@6.0.0(postcss@8.4.38): @@ -7636,11 +7846,11 @@ snapshots: dependencies: react: 18.3.1 - react-i18next@14.1.1(i18next@23.11.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-i18next@14.1.1(i18next@23.11.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.24.4 html-parse-stringify: 3.0.1 - i18next: 23.11.2 + i18next: 23.11.3 react: 18.3.1 optionalDependencies: react-dom: 18.3.1(react@18.3.1) @@ -7949,6 +8159,12 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + string-width@7.1.0: dependencies: emoji-regex: 10.3.0 @@ -8107,6 +8323,16 @@ snapshots: transitivePeerDependencies: - supports-color + sucrase@3.35.0: + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + commander: 4.1.1 + glob: 10.3.12 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -8145,6 +8371,33 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 + tailwindcss@3.4.3: + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.0 + lilconfig: 2.1.0 + micromatch: 4.0.5 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.0.0 + postcss: 8.4.38 + postcss-import: 15.1.0(postcss@8.4.38) + postcss-js: 4.0.1(postcss@8.4.38) + postcss-load-config: 4.0.2(postcss@8.4.38) + postcss-nested: 6.0.1(postcss@8.4.38) + postcss-selector-parser: 6.0.16 + resolve: 1.22.8 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + telegraf@4.16.3: dependencies: '@telegraf/types': 7.1.0 @@ -8163,6 +8416,14 @@ snapshots: text-table@0.2.0: {} + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + through@2.3.8: {} to-fast-properties@2.0.0: {} @@ -8181,6 +8442,8 @@ snapshots: dependencies: typescript: 5.4.5 + ts-interface-checker@0.1.13: {} + tsconfck@3.0.3(typescript@5.4.5): optionalDependencies: typescript: 5.4.5 @@ -8470,6 +8733,12 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + wrap-ansi@9.0.0: dependencies: ansi-styles: 6.2.1 diff --git a/clash-verge-rev/.github/ISSUE_TEMPLATE/config.yml b/clash-verge-rev/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..e49cbe6479 --- /dev/null +++ b/clash-verge-rev/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,4 @@ +contact_links: + - name: 讨论交流 / Communication + url: https://t.me/clash_verge_rev + about: 在 Telegram 群组中与其他用户讨论交流 / Communicate with other users in the Telegram group diff --git a/clash-verge-rev/package.json b/clash-verge-rev/package.json index d80cacaa52..d50031dfdb 100644 --- a/clash-verge-rev/package.json +++ b/clash-verge-rev/package.json @@ -33,7 +33,7 @@ "dayjs": "1.11.5", "i18next": "^23.11.2", "lodash-es": "^4.17.21", - "meta-json-schema": "1.18.3-beta", + "meta-json-schema": "1.18.4-beta2", "monaco-editor": "^0.47.0", "monaco-yaml": "^5.1.1", "nanoid": "^5.0.7", diff --git a/clash-verge-rev/pnpm-lock.yaml b/clash-verge-rev/pnpm-lock.yaml index dd1969de0e..05587f2288 100644 --- a/clash-verge-rev/pnpm-lock.yaml +++ b/clash-verge-rev/pnpm-lock.yaml @@ -59,8 +59,8 @@ importers: specifier: ^4.17.21 version: 4.17.21 meta-json-schema: - specifier: 1.18.3-beta - version: 1.18.3-beta + specifier: 1.18.4-beta2 + version: 1.18.4-beta2 monaco-editor: specifier: ^0.47.0 version: 0.47.0 @@ -2435,10 +2435,10 @@ packages: integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==, } - meta-json-schema@1.18.3-beta: + meta-json-schema@1.18.4-beta2: resolution: { - integrity: sha512-7RQvPJVSi0FEg697xUPIM9uTyBIWkcYLnE0CvXChqLQRdLDq0p719ht9TcvDEVMWjwFrFSLVaDsX6IskDxAy0w==, + integrity: sha512-ob3I6wVfkxVursh5TtZfZwYiHLjdWA8fs9H+cp253JTYNYC780qwttQT6qGG9ujUrV9iLYq9Lr/4HlkN+rr5Zg==, } micromark-core-commonmark@2.0.1: @@ -4928,7 +4928,7 @@ snapshots: merge-stream@2.0.0: {} - meta-json-schema@1.18.3-beta: {} + meta-json-schema@1.18.4-beta2: {} micromark-core-commonmark@2.0.1: dependencies: diff --git a/echo/README.md b/echo/README.md index dcb17f3af5..22142054e0 100644 --- a/echo/README.md +++ b/echo/README.md @@ -17,7 +17,7 @@ ehco 现在提供 SaaS(软件即服务)版本!这是一个全托管的解 - tcp/udp relay - tunnel relay (ws/wss/mwss/mtcp) -- proxy server (内嵌了完整班版本的 xray) -- 监控报警 (prometheus/grafana) +- proxy server (内嵌了完整版本的 xray) +- 监控报警 (Prometheus/Grafana) - WebAPI (http://web_host:web_port) - [更多功能请探索文档](https://docs.ehco-relay.cc/) diff --git a/echo/internal/cmgr/cmgr.go b/echo/internal/cmgr/cmgr.go index 4236753803..329402fd90 100644 --- a/echo/internal/cmgr/cmgr.go +++ b/echo/internal/cmgr/cmgr.go @@ -7,6 +7,7 @@ import ( "time" "github.com/Ehco1996/ehco/internal/conn" + "github.com/Ehco1996/ehco/pkg/node_metric" "go.uber.org/zap" ) @@ -36,6 +37,7 @@ type cmgrImpl struct { lock sync.RWMutex cfg *Config l *zap.SugaredLogger + mr node_metric.Reader // k: relay label, v: connection list activeConnectionsMap map[string][]conn.RelayConn @@ -43,12 +45,16 @@ type cmgrImpl struct { } func NewCmgr(cfg *Config) Cmgr { - return &cmgrImpl{ + cmgr := &cmgrImpl{ cfg: cfg, l: zap.S().Named("cmgr"), activeConnectionsMap: make(map[string][]conn.RelayConn), closedConnectionsMap: make(map[string][]conn.RelayConn), } + if cfg.NeedMetrics() { + cmgr.mr = node_metric.NewReader(cfg.MetricsURL) + } + return cmgr } func (cm *cmgrImpl) ListConnections(connType string, page, pageSize int) []conn.RelayConn { @@ -163,7 +169,7 @@ func (cm *cmgrImpl) Start(ctx context.Context, errCH chan error) { cm.l.Info("sync stop") return case <-ticker.C: - if err := cm.syncOnce(); err != nil { + if err := cm.syncOnce(ctx); err != nil { cm.l.Errorf("meet non retry error: %s ,exit now", err) errCH <- err } diff --git a/echo/internal/cmgr/config.go b/echo/internal/cmgr/config.go index aa96e985a8..265ac807cd 100644 --- a/echo/internal/cmgr/config.go +++ b/echo/internal/cmgr/config.go @@ -4,6 +4,7 @@ var DummyConfig = &Config{} type Config struct { SyncURL string `json:"sync_url,omitempty"` + MetricsURL string `json:"metrics_url,omitempty"` SyncInterval int `json:"sync_interval,omitempty"` // in seconds } @@ -11,6 +12,10 @@ func (c *Config) NeedSync() bool { return c.SyncURL != "" } +func (c *Config) NeedMetrics() bool { + return c.MetricsURL != "" +} + func (c *Config) Adjust() { if c.SyncInterval <= 0 { c.SyncInterval = 60 diff --git a/echo/internal/cmgr/metric_sync.go b/echo/internal/cmgr/metric_sync.go index a304f43689..63df84e4c3 100644 --- a/echo/internal/cmgr/metric_sync.go +++ b/echo/internal/cmgr/metric_sync.go @@ -1,11 +1,14 @@ package cmgr import ( + "context" "net/http" "github.com/Ehco1996/ehco/internal/conn" "github.com/Ehco1996/ehco/internal/constant" myhttp "github.com/Ehco1996/ehco/pkg/http" + "github.com/Ehco1996/ehco/pkg/node_metric" + "go.uber.org/zap" ) type StatsPerRule struct { @@ -23,11 +26,12 @@ type VersionInfo struct { } type syncReq struct { - Version VersionInfo `json:"version"` - Stats []StatsPerRule `json:"stats"` + Version VersionInfo `json:"version"` + Node node_metric.NodeMetrics `json:"node"` + Stats []StatsPerRule `json:"stats"` } -func (cm *cmgrImpl) syncOnce() error { +func (cm *cmgrImpl) syncOnce(ctx context.Context) error { cm.l.Infof("sync once total closed connections: %d", cm.countClosedConnection()) // todo: opt lock cm.lock.Lock() @@ -40,6 +44,16 @@ func (cm *cmgrImpl) syncOnce() error { Stats: []StatsPerRule{}, Version: VersionInfo{Version: constant.Version, ShortCommit: shorCommit}, } + + if cm.cfg.NeedMetrics() { + metrics, err := cm.mr.ReadOnce(ctx) + if err != nil { + cm.l.Errorf("read metrics failed: %v", err) + } else { + req.Node = *metrics + } + } + for label, conns := range cm.closedConnectionsMap { s := StatsPerRule{ RelayLabel: label, @@ -59,6 +73,7 @@ func (cm *cmgrImpl) syncOnce() error { cm.closedConnectionsMap = make(map[string][]conn.RelayConn) cm.lock.Unlock() if cm.cfg.NeedSync() { + cm.l.Debug("syncing data to server", zap.Any("data", req)) return myhttp.PostJson(http.DefaultClient, cm.cfg.SyncURL, &req) } else { cm.l.Debugf("remove %d closed connections", len(req.Stats)) diff --git a/echo/internal/config/config.go b/echo/internal/config/config.go index 72735d6576..3752e02ae0 100644 --- a/echo/internal/config/config.go +++ b/echo/internal/config/config.go @@ -149,6 +149,10 @@ func (c *Config) GetMetricURL() string { if c.WebToken != "" { url += fmt.Sprintf("?token=%s", c.WebToken) } + // for basic auth + if c.WebAuthUser != "" && c.WebAuthPass != "" { + url = fmt.Sprintf("http://%s:%s@%s:%d/metrics/", c.WebAuthUser, c.WebAuthPass, c.WebHost, c.WebPort) + } return url } diff --git a/echo/internal/relay/server.go b/echo/internal/relay/server.go index 4bcfb02916..cd677de0bc 100644 --- a/echo/internal/relay/server.go +++ b/echo/internal/relay/server.go @@ -32,6 +32,7 @@ func NewServer(cfg *config.Config) (*Server, error) { cmgrCfg := &cmgr.Config{ SyncURL: cfg.RelaySyncURL, SyncInterval: cfg.RelaySyncInterval, + MetricsURL: cfg.GetMetricURL(), } cmgrCfg.Adjust() s := &Server{ diff --git a/echo/pkg/node_metric/reader.go b/echo/pkg/node_metric/reader.go new file mode 100644 index 0000000000..22cdfac5fd --- /dev/null +++ b/echo/pkg/node_metric/reader.go @@ -0,0 +1,269 @@ +package node_metric + +import ( + "context" + "fmt" + "io" + "net/http" + "strings" + "time" + + dto "github.com/prometheus/client_model/go" + "github.com/prometheus/common/expfmt" +) + +type Reader interface { + ReadOnce(ctx context.Context) (*NodeMetrics, error) +} + +type readerImpl struct { + metricsURL string + httpClient *http.Client + lastMetrics *NodeMetrics +} + +func NewReader(metricsURL string) *readerImpl { + c := &http.Client{Timeout: 30 * time.Second} + return &readerImpl{ + httpClient: c, + metricsURL: metricsURL, + } +} + +func (b *readerImpl) parseCpuInfo(metricMap map[string]*dto.MetricFamily, nm *NodeMetrics) error { + handleMetric := func(metricName string, handleValue func(float64, string)) error { + metric, ok := metricMap[metricName] + if !ok { + return fmt.Errorf("%s not found", metricName) + } + + for _, m := range metric.Metric { + g := m.GetCounter() + mode := "" + for _, label := range m.GetLabel() { + if label.GetName() == "mode" { + mode = label.GetValue() + } + } + handleValue(g.GetValue(), mode) + } + return nil + } + + var ( + totalIdleTime float64 + totalCpuTime float64 + cpuCores int + ) + + err := handleMetric("node_cpu_seconds_total", func(val float64, mode string) { + totalCpuTime += val + if mode == "idle" { + totalIdleTime += val + cpuCores++ + } + }) + if err != nil { + return err + } + + nm.CpuCoreCount = cpuCores + nm.CpuUsagePercent = 100 * (totalCpuTime - totalIdleTime) / totalCpuTime + for _, load := range []string{"1", "5", "15"} { + loadMetricName := fmt.Sprintf("node_load%s", load) + loadMetric, ok := metricMap[loadMetricName] + if !ok { + return fmt.Errorf("%s not found", loadMetricName) + } + for _, m := range loadMetric.Metric { + g := m.GetGauge() + nm.CpuLoadInfo += fmt.Sprintf("%.2f|", g.GetValue()) + } + } + nm.CpuLoadInfo = strings.TrimRight(nm.CpuLoadInfo, "|") + return nil +} + +func (b *readerImpl) parseMemoryInfo(metricMap map[string]*dto.MetricFamily, nm *NodeMetrics) error { + handleMetric := func(metricName string, handleValue func(float64)) error { + metric, ok := metricMap[metricName] + if !ok { + return fmt.Errorf("%s not found", metricName) + } + for _, m := range metric.Metric { + g := m.GetGauge() + handleValue(g.GetValue()) + } + return nil + } + + isMac := false + if _, ok := metricMap["node_memory_total_bytes"]; ok { + isMac = true + } + + if isMac { + err := handleMetric("node_memory_total_bytes", func(val float64) { + nm.MemoryTotalBytes = val + }) + if err != nil { + return err + } + + err = handleMetric("node_memory_active_bytes", func(val float64) { + nm.MemoryUsageBytes += val + }) + if err != nil { + return err + } + + err = handleMetric("node_memory_wired_bytes", func(val float64) { + nm.MemoryUsageBytes += val + }) + if err != nil { + return err + } + } else { + err := handleMetric("node_memory_MemTotal_bytes", func(val float64) { + nm.MemoryTotalBytes = val + }) + if err != nil { + return err + } + + err = handleMetric("node_memory_MemAvailable_bytes", func(val float64) { + nm.MemoryUsageBytes = nm.MemoryTotalBytes - val + }) + if err != nil { + return err + } + } + if nm.MemoryTotalBytes != 0 { + nm.MemoryUsagePercent = 100 * nm.MemoryUsageBytes / nm.MemoryTotalBytes + } + return nil +} + +func (b *readerImpl) parseDiskInfo(metricMap map[string]*dto.MetricFamily, nm *NodeMetrics) error { + handleMetric := func(metricName string, handleValue func(float64)) error { + forMac := false + diskMap := make(map[string]float64) + metric, ok := metricMap[metricName] + if !ok { + return fmt.Errorf("%s not found", metricName) + } + for _, m := range metric.Metric { + g := m.GetGauge() + disk := "" + for _, label := range m.GetLabel() { + if label.GetName() == "device" { + disk = getDiskName(label.GetValue()) + } + if label.GetName() == "fstype" && label.GetValue() == "apfs" { + forMac = true + } + } + diskMap[disk] = g.GetValue() + } + // 对于 macos 的 apfs 文件系统,可能会有多个相同大小的磁盘,这是因为 apfs 磁盘(卷)会共享物理磁盘 + seenVal := map[float64]bool{} + for _, val := range diskMap { + if seenVal[val] && forMac { + continue + } + handleValue(val) + seenVal[val] = true + } + return nil + } + + err := handleMetric("node_filesystem_size_bytes", func(val float64) { + nm.DiskTotalBytes += val + }) + if err != nil { + return err + } + + var availBytes float64 + err = handleMetric("node_filesystem_avail_bytes", func(val float64) { + availBytes += val + }) + if err != nil { + return err + } + nm.DiskUsageBytes = nm.DiskTotalBytes - availBytes + if nm.DiskTotalBytes != 0 { + nm.DiskUsagePercent = 100 * nm.DiskUsageBytes / nm.DiskTotalBytes + } + return nil +} + +func (b *readerImpl) parseNetworkInfo(metricMap map[string]*dto.MetricFamily, nm *NodeMetrics) error { + now := time.Now() + handleMetric := func(metricName string, handleValue func(float64)) error { + metric, ok := metricMap[metricName] + if !ok { + return fmt.Errorf("%s not found", metricName) + } + for _, m := range metric.Metric { + g := m.GetCounter() + handleValue(g.GetValue()) + } + return nil + } + + err := handleMetric("node_network_receive_bytes_total", func(val float64) { + nm.NetworkReceiveBytesTotal += val + }) + if err != nil { + return err + } + + err = handleMetric("node_network_transmit_bytes_total", func(val float64) { + nm.NetworkTransmitBytesTotal += val + }) + if err != nil { + return err + } + + if b.lastMetrics != nil { + passedTime := now.Sub(b.lastMetrics.syncTime).Seconds() + nm.NetworkReceiveBytesRate = (nm.NetworkReceiveBytesTotal - b.lastMetrics.NetworkReceiveBytesTotal) / passedTime + nm.NetworkTransmitBytesRate = (nm.NetworkTransmitBytesTotal - b.lastMetrics.NetworkTransmitBytesTotal) / passedTime + } + return nil +} + +func (b *readerImpl) ReadOnce(ctx context.Context) (*NodeMetrics, error) { + response, err := b.httpClient.Get(b.metricsURL) + if err != nil { + return nil, err + } + defer response.Body.Close() + + body, err := io.ReadAll(response.Body) + if err != nil { + return nil, err + } + var parser expfmt.TextParser + parsed, err := parser.TextToMetricFamilies(strings.NewReader(string(body))) + if err != nil { + return nil, err + } + + nm := &NodeMetrics{syncTime: time.Now()} + if err := b.parseCpuInfo(parsed, nm); err != nil { + return nil, err + } + if err := b.parseMemoryInfo(parsed, nm); err != nil { + return nil, err + } + if err := b.parseDiskInfo(parsed, nm); err != nil { + return nil, err + } + if err := b.parseNetworkInfo(parsed, nm); err != nil { + return nil, err + } + b.lastMetrics = nm + return nm, nil +} diff --git a/echo/pkg/node_metric/types.go b/echo/pkg/node_metric/types.go new file mode 100644 index 0000000000..0846d79904 --- /dev/null +++ b/echo/pkg/node_metric/types.go @@ -0,0 +1,28 @@ +package node_metric + +import "time" + +type NodeMetrics struct { + // cpu + CpuCoreCount int `json:"cpu_core_count"` + CpuLoadInfo string `json:"cpu_load_info"` + CpuUsagePercent float64 `json:"cpu_usage_percent"` + + // memory + MemoryTotalBytes float64 `json:"memory_total_bytes"` + MemoryUsageBytes float64 `json:"memory_usage_bytes"` + MemoryUsagePercent float64 `json:"memory_usage_percent"` + + // disk + DiskTotalBytes float64 `json:"disk_total_bytes"` + DiskUsageBytes float64 `json:"disk_usage_bytes"` + DiskUsagePercent float64 `json:"disk_usage_percent"` + + // network + NetworkReceiveBytesTotal float64 `json:"network_receive_bytes_total"` + NetworkTransmitBytesTotal float64 `json:"network_transmit_bytes_total"` + NetworkReceiveBytesRate float64 `json:"network_receive_bytes_rate"` + NetworkTransmitBytesRate float64 `json:"network_transmit_bytes_rate"` + + syncTime time.Time +} diff --git a/echo/pkg/node_metric/utils.go b/echo/pkg/node_metric/utils.go new file mode 100644 index 0000000000..221efbf5d5 --- /dev/null +++ b/echo/pkg/node_metric/utils.go @@ -0,0 +1,24 @@ +package node_metric + +import "regexp" + +var ( + // parse disk name from device path,such as: + // e.g. /dev/disk1s1 -> disk1 + // e.g. /dev/disk1s2 -> disk1 + // e.g. ntfs://disk1s1 -> disk1 + // e.g. ntfs://disk1s2 -> disk1 + // e.g. /dev/sda1 -> sda + // e.g. /dev/sda2 -> sda + diskNameRegex = regexp.MustCompile(`/dev/disk(\d+)|ntfs://disk(\d+)|/dev/sd[a-zA-Z]`) +) + +func getDiskName(devicePath string) string { + matches := diskNameRegex.FindStringSubmatch(devicePath) + for _, match := range matches { + if match != "" { + return match + } + } + return "" +} diff --git a/filebrowser/frontend/src/components/prompts/UploadFiles.vue b/filebrowser/frontend/src/components/prompts/UploadFiles.vue index 88a0b6078d..48a9e1d4a0 100644 --- a/filebrowser/frontend/src/components/prompts/UploadFiles.vue +++ b/filebrowser/frontend/src/components/prompts/UploadFiles.vue @@ -10,6 +10,12 @@
{{ uploadSpeed.toFixed(2) }} MB/s
{{ formattedETA }} remaining
+
+ {{ getProgressDecimal }}% Completed +
+
+ {{ getTotalProgressBytes }} / {{ getTotalSize }} +